From b7224c0a99342ef8b608ea3f334307a5e5462c81 Mon Sep 17 00:00:00 2001 From: Karen Langford Date: Thu, 11 Aug 2011 15:31:25 +0200 Subject: [PATCH 001/288] Raise version number after cloning 5.1.59 --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index 0e336c5522b..e56a18540b5 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.59], [], [mysql]) +AC_INIT([MySQL Server], [5.1.60], [], [mysql]) AC_CONFIG_SRCDIR([sql/mysqld.cc]) AC_CANONICAL_SYSTEM From 5a7e0127e5b17eb16ede1c09cf1dbc66006547bc Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Fri, 12 Aug 2011 14:22:16 +0300 Subject: [PATCH 002/288] bumped up the version to 5.5.18 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index d9f537cb915..7bac52ecdfb 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ MYSQL_VERSION_MAJOR=5 MYSQL_VERSION_MINOR=5 -MYSQL_VERSION_PATCH=16 +MYSQL_VERSION_PATCH=18 MYSQL_VERSION_EXTRA= From 4d0784eeba8a7017beff553b27a05fc18e17540f Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Fri, 12 Aug 2011 15:04:05 +0300 Subject: [PATCH 003/288] Bug #12818542: PAM: ADDING PASSWORD FOR AN ACCOUNT DISABLES PAM AUTHENTICATION SETTINGS SET PASSWORD code on a account with plugin authentication was errorneously resetting the in-memory plugin pointer for the user back to native password plugin despite the fact that it was sending a warning that the command has no immediate effect. Fixed by not updating the user's plugin if it's already set to a non default value. Note that the bug affected only the in-memory cache of the user definitions. Any restart of the server will fix the problem. Also the salt and the password has are still stored into the user tables (just as it's documented now). Test case added. One old test case result updated to have the correct value. --- mysql-test/r/plugin_auth.result | 22 +++++++++++++++++++++- mysql-test/t/plugin_auth.test | 31 +++++++++++++++++++++++++++++++ sql/sql_acl.cc | 10 +++++----- 3 files changed, 57 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/plugin_auth.result b/mysql-test/r/plugin_auth.result index 327ba2969e9..64bc870a7fa 100644 --- a/mysql-test/r/plugin_auth.result +++ b/mysql-test/r/plugin_auth.result @@ -44,7 +44,7 @@ ERROR 28000: Access denied for user 'plug'@'localhost' (using password: YES) ## test correct default plugin select USER(),CURRENT_USER(); USER() CURRENT_USER() -plug@localhost plug@% +plug@localhost plug_dest@% ## test no_auto_create_user sql mode with plugin users SET @@sql_mode=no_auto_create_user; GRANT INSERT ON TEST.* TO grant_user IDENTIFIED WITH 'test_plugin_server'; @@ -462,4 +462,24 @@ CREATE USER bug12610784@localhost; SET PASSWORD FOR bug12610784@localhost = PASSWORD('secret'); ERROR 28000: Access denied for user 'bug12610784'@'localhost' (using password: NO) DROP USER bug12610784@localhost; +# +# Bug #12818542: PAM: ADDING PASSWORD FOR AN ACCOUNT DISABLES PAM +# AUTHENTICATION SETTINGS +# +CREATE USER bug12818542@localhost +IDENTIFIED WITH 'test_plugin_server' AS 'bug12818542_dest'; +CREATE USER bug12818542_dest@localhost +IDENTIFIED BY 'bug12818542_dest_passwd'; +GRANT PROXY ON bug12818542_dest@localhost TO bug12818542@localhost; +SELECT USER(),CURRENT_USER(); +USER() CURRENT_USER() +bug12818542@localhost bug12818542_dest@localhost +SET PASSWORD = PASSWORD('bruhaha'); +Warnings: +Note 1699 SET PASSWORD has no significance for users authenticating via plugins +SELECT USER(),CURRENT_USER(); +USER() CURRENT_USER() +bug12818542@localhost bug12818542_dest@localhost +DROP USER bug12818542@localhost; +DROP USER bug12818542_dest@localhost; End of 5.5 tests diff --git a/mysql-test/t/plugin_auth.test b/mysql-test/t/plugin_auth.test index 0dc3068de61..f169360cf2e 100644 --- a/mysql-test/t/plugin_auth.test +++ b/mysql-test/t/plugin_auth.test @@ -540,4 +540,35 @@ connection default; disconnect b12610784; DROP USER bug12610784@localhost; + +--echo # +--echo # Bug #12818542: PAM: ADDING PASSWORD FOR AN ACCOUNT DISABLES PAM +--echo # AUTHENTICATION SETTINGS +--echo # + +CREATE USER bug12818542@localhost + IDENTIFIED WITH 'test_plugin_server' AS 'bug12818542_dest'; +CREATE USER bug12818542_dest@localhost + IDENTIFIED BY 'bug12818542_dest_passwd'; +GRANT PROXY ON bug12818542_dest@localhost TO bug12818542@localhost; + +connect(bug12818542_con,localhost,bug12818542,bug12818542_dest); +connection bug12818542_con; +SELECT USER(),CURRENT_USER(); + +SET PASSWORD = PASSWORD('bruhaha'); + +connection default; +disconnect bug12818542_con; + +connect(bug12818542_con2,localhost,bug12818542,bug12818542_dest); +connection bug12818542_con2; +SELECT USER(),CURRENT_USER(); + +connection default; +disconnect bug12818542_con2; + +DROP USER bug12818542@localhost; +DROP USER bug12818542_dest@localhost; + --echo End of 5.5 tests diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index f4d217c85ff..06a67edda36 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1881,17 +1881,17 @@ bool change_password(THD *thd, const char *host, const char *user, goto end; } + /* update loaded acl entry: */ + set_user_salt(acl_user, new_password, new_password_len); + if (my_strcasecmp(system_charset_info, acl_user->plugin.str, native_password_plugin_name.str) && my_strcasecmp(system_charset_info, acl_user->plugin.str, old_password_plugin_name.str)) - { push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_SET_PASSWORD_AUTH_PLUGIN, ER(ER_SET_PASSWORD_AUTH_PLUGIN)); - } - /* update loaded acl entry: */ - set_user_salt(acl_user, new_password, new_password_len); - set_user_plugin(acl_user, new_password_len); + else + set_user_plugin(acl_user, new_password_len); if (update_user_table(thd, table, acl_user->host.hostname ? acl_user->host.hostname : "", From 0d6a4b081340ab38b5e29ba319a69b78504e2bfa Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Fri, 12 Aug 2011 15:14:31 +0300 Subject: [PATCH 004/288] Bug #11765565: 58548: 5.5.X NEEDS TO LINK TO THE CORESERVICES FRAMEWORK FOR SOME PLUGINS TO WORK Some dynamically loadable plugins on the Mac may need functions from the CoreServices framework. Unfortunately the only place where this can be initialized is the main executable. Thus to allow plugins to use functions from that framework the mysqld binary needs to link to the framework. --- sql/CMakeLists.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index f95cc359439..fb86d1ce60f 100644 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -100,6 +100,14 @@ ENDIF() MYSQL_ADD_EXECUTABLE(mysqld ${MYSQLD_SOURCE} DESTINATION ${INSTALL_SBINDIR} COMPONENT Server) +IF(APPLE) + # Add CoreServices framework since some dloadable plugins may need it + FIND_LIBRARY(CORESERVICES NAMES CoreServices) + IF(CORESERVICES) + TARGET_LINK_LIBRARIES(mysqld ${CORESERVICES}) + ENDIF() +ENDIF() + IF(NOT WITHOUT_DYNAMIC_PLUGINS) SET_TARGET_PROPERTIES(mysqld PROPERTIES ENABLE_EXPORTS TRUE) GET_TARGET_PROPERTY(mysqld_link_flags mysqld LINK_FLAGS) From 644db664462a52bae2237635c1d44401a5b1ec60 Mon Sep 17 00:00:00 2001 From: Dmitry Shulga Date: Sat, 13 Aug 2011 13:34:00 +0700 Subject: [PATCH 005/288] Fixed Bug#12621017 - CRASH IF A SP VARIABLE IS USED IN THE LIMIT CLAUSE OF A SET STATEMENT. Server built with debug asserts, without debug crashes if a user tries to run a stored procedure that constains query with subquery that include either LIMIT or LIMIT OFFSET clauses. The problem was that Item::fix_fields() was not called for the items representing LIMIT or OFFSET clauses. The solution is to call Item::fix_fields() right before evaluation in st_select_lex_unit::set_limit(). mysql-test/r/sp.result: Added testcase result for bug#12621017. Updated testcase result for bug 11918. mysql-test/t/sp.test: Added testcase for bug#12621017. Addressed review comments for Bug 11918 (added tests for use LIMIT at stored function). sql/item.h: Addressed review comments for Bug 11918. sql/share/errmsg-utf8.txt: Addressed review comments for Bug 11918. sql/sp_head.cc: Addressed review comments for Bug 11918. sql/sql_lex.cc: Added call fix_fields() for item just before its evaluation. sql/sql_yacc.yy: Addressed review comments for Bug 11918. --- mysql-test/r/sp.result | 150 ++++++++++++++++++++++++++++++++++-- mysql-test/t/sp.test | 156 +++++++++++++++++++++++++++++++++++++- sql/item.h | 2 +- sql/share/errmsg-utf8.txt | 2 +- sql/sp_head.cc | 6 +- sql/sql_lex.cc | 59 +++++++++++++- sql/sql_yacc.yy | 3 +- 7 files changed, 364 insertions(+), 14 deletions(-) diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 104ddd3353b..1644c764431 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -7437,17 +7437,17 @@ ERROR 42000: Undeclared variable: a # Try to use data types not allowed in LIMIT # create procedure p1(p1 date, p2 date) select * from t1 limit p1, p2; -ERROR HY000: A variable of a non-integer type in LIMIT clause +ERROR HY000: A variable of a non-integer based type in LIMIT clause create procedure p1(p1 integer, p2 float) select * from t1 limit p1, p2; -ERROR HY000: A variable of a non-integer type in LIMIT clause +ERROR HY000: A variable of a non-integer based type in LIMIT clause create procedure p1(p1 integer, p2 char(1)) select * from t1 limit p1, p2; -ERROR HY000: A variable of a non-integer type in LIMIT clause +ERROR HY000: A variable of a non-integer based type in LIMIT clause create procedure p1(p1 varchar(5), p2 char(1)) select * from t1 limit p1, p2; -ERROR HY000: A variable of a non-integer type in LIMIT clause +ERROR HY000: A variable of a non-integer based type in LIMIT clause create procedure p1(p1 decimal, p2 decimal) select * from t1 limit p1, p2; -ERROR HY000: A variable of a non-integer type in LIMIT clause +ERROR HY000: A variable of a non-integer based type in LIMIT clause create procedure p1(p1 double, p2 double) select * from t1 limit p1, p2; -ERROR HY000: A variable of a non-integer type in LIMIT clause +ERROR HY000: A variable of a non-integer based type in LIMIT clause # # Finally, test the valid case. # @@ -7483,9 +7483,117 @@ call p1(3, 2); c1 4 5 +# Try to create a function that +# refers to non-existing variables. +create function f1(p1 integer, p2 integer) +returns int +begin +declare a int; +set a = (select count(*) from t1 limit a, b); +return a; +end| +ERROR 42000: Undeclared variable: b +create function f1() +returns int +begin +declare a, b, c int; +set a = (select count(*) from t1 limit b, c); +return a; +end| +# How do we handle NULL limit values? +select f1(); +f1() +NULL +drop function f1; +# +# Try to use data types not allowed in LIMIT +# +create function f1(p1 date, p2 date) +returns int +begin +declare a int; +set a = (select count(*) from t1 limit p1, p2); +return a; +end| +ERROR HY000: A variable of a non-integer based type in LIMIT clause +create function f1(p1 integer, p2 float) +returns int +begin +declare a int; +set a = (select count(*) from t1 limit p1, p2); +return a; +end| +ERROR HY000: A variable of a non-integer based type in LIMIT clause +create function f1(p1 integer, p2 char(1)) +returns int +begin +declare a int; +set a = (select count(*) from t1 limit p1, p2); +return a; +end| +ERROR HY000: A variable of a non-integer based type in LIMIT clause +create function f1(p1 varchar(5), p2 char(1)) +returns int +begin +declare a int; +set a = (select count(*) from t1 limit p1, p2); +return a; +end| +ERROR HY000: A variable of a non-integer based type in LIMIT clause +create function f1(p1 decimal, p2 decimal) +returns int +begin +declare a int; +set a = (select count(*) from t1 limit p1, p2); +return a; +end| +ERROR HY000: A variable of a non-integer based type in LIMIT clause +create function f1(p1 double, p2 double) +returns int +begin +declare a int; +set a = (select count(*) from t1 limit p1, p2); +return a; +end| +ERROR HY000: A variable of a non-integer based type in LIMIT clause +# +# Finally, test the valid case. +# +create function f1(p1 integer, p2 integer) +returns int +begin +declare count int; +set count= (select count(*) from (select * from t1 limit p1, p2) t_1); +return count; +end| +select f1(0, 0); +f1(0, 0) +0 +select f1(0, -1); +f1(0, -1) +5 +select f1(-1, 0); +f1(-1, 0) +0 +select f1(-1, -1); +f1(-1, -1) +0 +select f1(0, 1); +f1(0, 1) +1 +select f1(1, 0); +f1(1, 0) +0 +select f1(1, 5); +f1(1, 5) +4 +select f1(3, 2); +f1(3, 2) +2 # Cleanup drop table t1; drop procedure p1; +drop function f1; # # BUG#11766234: 59299: ASSERT (TABLE_REF->TABLE || TABLE_REF->VIEW) # FAILS IN SET_FIELD_ITERATOR @@ -7606,4 +7714,34 @@ b DROP TABLE t1; DROP PROCEDURE p1; +# +# Bug#12621017 - Crash if a sp variable is used in the +# limit clause of a set statement +# +DROP TABLE IF EXISTS t1; +DROP PROCEDURE IF EXISTS p1; +DROP PROCEDURE IF EXISTS p2; +CREATE TABLE t1 (c1 INT); +INSERT INTO t1 VALUES (1); +CREATE PROCEDURE p1() +BEGIN +DECLARE foo, cnt INT UNSIGNED DEFAULT 1; +SET foo = (SELECT MIN(c1) FROM t1 LIMIT cnt); +END| +CREATE PROCEDURE p2() +BEGIN +DECLARE iLimit INT; +DECLARE iVal INT; +DECLARE cur1 CURSOR FOR +SELECT c1 FROM t1 +LIMIT iLimit; +SET iLimit=1; +OPEN cur1; +FETCH cur1 INTO iVal; +END| +CALL p1(); +CALL p2(); +DROP PROCEDURE p1; +DROP PROCEDURE p2; +DROP TABLE t1; # End of 5.5 test diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 07b8c065be4..3f6c50a9095 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -8755,11 +8755,117 @@ call p1(1, 0); call p1(1, 5); call p1(3, 2); +delimiter |; +--echo # Try to create a function that +--echo # refers to non-existing variables. +--error ER_SP_UNDECLARED_VAR +create function f1(p1 integer, p2 integer) + returns int +begin + declare a int; + set a = (select count(*) from t1 limit a, b); + return a; +end| + +create function f1() + returns int +begin + declare a, b, c int; + set a = (select count(*) from t1 limit b, c); + return a; +end| + +delimiter ;| +--echo # How do we handle NULL limit values? +select f1(); + +drop function f1; + +delimiter |; +--echo # +--echo # Try to use data types not allowed in LIMIT +--echo # +--error ER_WRONG_SPVAR_TYPE_IN_LIMIT +create function f1(p1 date, p2 date) + returns int +begin + declare a int; + set a = (select count(*) from t1 limit p1, p2); + return a; +end| + +--error ER_WRONG_SPVAR_TYPE_IN_LIMIT +create function f1(p1 integer, p2 float) + returns int +begin + declare a int; + set a = (select count(*) from t1 limit p1, p2); + return a; +end| + +--error ER_WRONG_SPVAR_TYPE_IN_LIMIT +create function f1(p1 integer, p2 char(1)) + returns int +begin + declare a int; + set a = (select count(*) from t1 limit p1, p2); + return a; +end| + +--error ER_WRONG_SPVAR_TYPE_IN_LIMIT +create function f1(p1 varchar(5), p2 char(1)) + returns int +begin + declare a int; + set a = (select count(*) from t1 limit p1, p2); + return a; +end| + +--error ER_WRONG_SPVAR_TYPE_IN_LIMIT +create function f1(p1 decimal, p2 decimal) + returns int +begin + declare a int; + set a = (select count(*) from t1 limit p1, p2); + return a; +end| + +--error ER_WRONG_SPVAR_TYPE_IN_LIMIT +create function f1(p1 double, p2 double) + returns int +begin + declare a int; + set a = (select count(*) from t1 limit p1, p2); + return a; +end| + +--echo # +--echo # Finally, test the valid case. +--echo # + +create function f1(p1 integer, p2 integer) +returns int +begin + declare count int; + set count= (select count(*) from (select * from t1 limit p1, p2) t_1); + return count; +end| + +delimiter ;| + +select f1(0, 0); +select f1(0, -1); +select f1(-1, 0); +select f1(-1, -1); +select f1(0, 1); +select f1(1, 0); +select f1(1, 5); +select f1(3, 2); --echo # Cleanup drop table t1; drop procedure p1; - +drop function f1; --echo # --echo # BUG#11766234: 59299: ASSERT (TABLE_REF->TABLE || TABLE_REF->VIEW) @@ -8881,4 +8987,52 @@ DROP TABLE t1; DROP PROCEDURE p1; --echo +--echo # +--echo # Bug#12621017 - Crash if a sp variable is used in the +--echo # limit clause of a set statement +--echo # + +--disable_warnings +DROP TABLE IF EXISTS t1; +DROP PROCEDURE IF EXISTS p1; +DROP PROCEDURE IF EXISTS p2; +--enable_warnings + +CREATE TABLE t1 (c1 INT); +INSERT INTO t1 VALUES (1); + +delimiter |; + +CREATE PROCEDURE p1() +BEGIN + DECLARE foo, cnt INT UNSIGNED DEFAULT 1; + SET foo = (SELECT MIN(c1) FROM t1 LIMIT cnt); +END| + +CREATE PROCEDURE p2() +BEGIN + +DECLARE iLimit INT; +DECLARE iVal INT; + +DECLARE cur1 CURSOR FOR + SELECT c1 FROM t1 + LIMIT iLimit; + +SET iLimit=1; + +OPEN cur1; +FETCH cur1 INTO iVal; + +END| + +delimiter ;| + +CALL p1(); +CALL p2(); + +DROP PROCEDURE p1; +DROP PROCEDURE p2; +DROP TABLE t1; + --echo # End of 5.5 test diff --git a/sql/item.h b/sql/item.h index 46916346ebe..3fa0f4bb50b 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1371,7 +1371,7 @@ class Item_splocal :public Item_sp_variable, enum_field_types m_field_type; public: /* - Is this variable a parameter in LIMIT clause. + If this variable is a parameter in LIMIT clause. Used only during NAME_CONST substitution, to not append NAME_CONST to the resulting query and thus not break the slave. diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index b8f46f090ab..fd943c4f4d8 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -6329,7 +6329,7 @@ ER_DATA_OUT_OF_RANGE 22003 eng "%s value is out of range in '%s'" ER_WRONG_SPVAR_TYPE_IN_LIMIT - eng "A variable of a non-integer type in LIMIT clause" + eng "A variable of a non-integer based type in LIMIT clause" ER_BINLOG_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE eng "Mixing self-logging and non-self-logging engines in a statement is unsafe." diff --git a/sql/sp_head.cc b/sql/sp_head.cc index ce713504a38..eb0eb8edc60 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1005,6 +1005,8 @@ subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str) if ((*splocal)->limit_clause_param) { res|= qbuf.append_ulonglong((*splocal)->val_uint()); + if (res) + break; continue; } @@ -1029,8 +1031,8 @@ subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str) thd->query_name_consts++; } - res|= qbuf.append(cur + prev_pos, query_str->length - prev_pos); - if (res) + if (res || + qbuf.append(cur + prev_pos, query_str->length - prev_pos)) DBUG_RETURN(TRUE); /* diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 3e6052d3561..f22f459e93e 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -2599,7 +2599,47 @@ void st_select_lex_unit::set_limit(st_select_lex *sl) ulonglong val; DBUG_ASSERT(! thd->stmt_arena->is_stmt_prepare()); - val= sl->select_limit ? sl->select_limit->val_uint() : HA_POS_ERROR; + if (sl->select_limit) + { + Item *item = sl->select_limit; + /* + fix_fields() has not been called for sl->select_limit. That's due to the + historical reasons -- this item could be only of type Item_int, and + Item_int does not require fix_fields(). Thus, fix_fields() was never + called for sl->select_limit. + + Some time ago, Item_splocal was also allowed for LIMIT / OFFSET clauses. + However, the fix_fields() behavior was not updated, which led to a crash + in some cases. + + There is no single place where to call fix_fields() for LIMIT / OFFSET + items during the fix-fields-phase. Thus, for the sake of readability, + it was decided to do it here, on the evaluation phase (which is a + violation of design, but we chose the lesser of two evils). + + We can call fix_fields() here, because sl->select_limit can be of two + types only: Item_int and Item_splocal. Item_int::fix_fields() is trivial, + and Item_splocal::fix_fields() (or rather Item_sp_variable::fix_fields()) + has the following specific: + 1) it does not affect other items; + 2) it does not fail. + + Nevertheless DBUG_ASSERT was added to catch future changes in + fix_fields() implementation. Also added runtime check against a result + of fix_fields() in order to handle error condition in non-debug build. + */ + bool fix_fields_successful= true; + if (!item->fixed) + { + fix_fields_successful= !item->fix_fields(thd, NULL); + + DBUG_ASSERT(fix_fields_successful); + } + val= fix_fields_successful ? item->val_uint() : HA_POS_ERROR; + } + else + val= HA_POS_ERROR; + select_limit_val= (ha_rows)val; #ifndef BIG_TABLES /* @@ -2609,7 +2649,22 @@ void st_select_lex_unit::set_limit(st_select_lex *sl) if (val != (ulonglong)select_limit_val) select_limit_val= HA_POS_ERROR; #endif - val= sl->offset_limit ? sl->offset_limit->val_uint() : ULL(0); + if (sl->offset_limit) + { + Item *item = sl->offset_limit; + // see comment for sl->select_limit branch. + bool fix_fields_successful= true; + if (!item->fixed) + { + fix_fields_successful= !item->fix_fields(thd, NULL); + + DBUG_ASSERT(fix_fields_successful); + } + val= fix_fields_successful ? item->val_uint() : HA_POS_ERROR; + } + else + val= ULL(0); + offset_limit_cnt= (ha_rows)val; #ifndef BIG_TABLES /* Check for truncation. */ diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 6fe9626b11d..3d30dbe614f 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -9961,7 +9961,8 @@ limit_option: } splocal->limit_clause_param= TRUE; $$= splocal; - } | param_marker + } + | param_marker { ((Item_param *) $1)->limit_clause_param= TRUE; } From 138df47b4988aa59ddf3be74710c1537240b1ccc Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Wed, 17 Aug 2011 13:13:44 +0300 Subject: [PATCH 006/288] changed the old @sun.com address of security trees. --- .bzr-mysql/default.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.bzr-mysql/default.conf b/.bzr-mysql/default.conf index 4b2affc1529..3e92b5454d7 100644 --- a/.bzr-mysql/default.conf +++ b/.bzr-mysql/default.conf @@ -1,4 +1,4 @@ [MYSQL] -post_commit_to = "dbg_mysql_security@sun.com" -post_push_to = "dbg_mysql_security@sun.com" +post_commit_to = "MYSQL_COMMITS_SECURITY_WW@ORACLE.COM" +post_push_to = "MYSQL_COMMITS_SECURITY_WW@ORACLE.COM" tree_name = "mysql-5.0-security" From 4da845ec489edb5156be248b117c0dfdfd48f058 Mon Sep 17 00:00:00 2001 From: Tor Didriksen Date: Fri, 19 Aug 2011 09:06:50 +0200 Subject: [PATCH 007/288] Backport from trunk of: Bug#12532830 - SIGFPE OR ASSERTION (PRECISION <= ((9 * 9) - 8*2)) && (DEC <= 30) --- mysql-test/r/func_if.result | 14 ++++++ .../suite/innodb/r/innodb_bug54044.result | 11 ++++- .../suite/innodb/t/innodb_bug54044.test | 14 ++++-- mysql-test/t/func_if.test | 12 +++++ sql/field.cc | 3 +- sql/item_cmpfunc.cc | 46 +++++++++++-------- sql/item_cmpfunc.h | 2 + 7 files changed, 77 insertions(+), 25 deletions(-) diff --git a/mysql-test/r/func_if.result b/mysql-test/r/func_if.result index c70589a27b7..7946d8f328c 100644 --- a/mysql-test/r/func_if.result +++ b/mysql-test/r/func_if.result @@ -196,3 +196,17 @@ c NULL 0 DROP TABLE t1; +# +# Bug#12532830 +# SIGFPE OR ASSERTION (PRECISION <= ((9 * 9) - 8*2)) && (DEC <= 30) +# +select +sum(distinct(if('a', +(select adddate(elt(convert(9999999999999999999999999999999999999,decimal(64,0)),count(*)), +interval 1 day)) +, .1))) as foo; +foo +0.1 +Warnings: +Warning 1292 Truncated incorrect DOUBLE value: 'a' +Warning 1292 Truncated incorrect DOUBLE value: 'a' diff --git a/mysql-test/suite/innodb/r/innodb_bug54044.result b/mysql-test/suite/innodb/r/innodb_bug54044.result index 90ab812f2ae..350c500cb9b 100644 --- a/mysql-test/suite/innodb/r/innodb_bug54044.result +++ b/mysql-test/suite/innodb/r/innodb_bug54044.result @@ -1,3 +1,12 @@ CREATE TEMPORARY TABLE table_54044 ENGINE = INNODB AS SELECT IF(NULL IS NOT NULL, NULL, NULL); -ERROR HY000: Can't create table 'test.table_54044' (errno: -1) +SHOW CREATE TABLE table_54044; +Table Create Table +table_54044 CREATE TEMPORARY TABLE `table_54044` ( + `IF(NULL IS NOT NULL, NULL, NULL)` binary(0) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +DROP TABLE table_54044; +CREATE TABLE tmp ENGINE = INNODB AS SELECT COALESCE(NULL, NULL, NULL); +ERROR HY000: Can't create table 'test.tmp' (errno: -1) +CREATE TABLE tmp ENGINE = INNODB AS SELECT GREATEST(NULL, NULL); +ERROR HY000: Can't create table 'test.tmp' (errno: -1) diff --git a/mysql-test/suite/innodb/t/innodb_bug54044.test b/mysql-test/suite/innodb/t/innodb_bug54044.test index a6722ed6399..0bbd7da0065 100644 --- a/mysql-test/suite/innodb/t/innodb_bug54044.test +++ b/mysql-test/suite/innodb/t/innodb_bug54044.test @@ -3,9 +3,17 @@ --source include/have_innodb.inc -# This 'create table' operation should fail because of -# using NULL datatype ---error ER_CANT_CREATE_TABLE +# This 'create table' operation no longer uses the NULL datatype. + CREATE TEMPORARY TABLE table_54044 ENGINE = INNODB AS SELECT IF(NULL IS NOT NULL, NULL, NULL); +SHOW CREATE TABLE table_54044; +DROP TABLE table_54044; +# These 'create table' operations should fail because of +# using NULL datatype + +--error ER_CANT_CREATE_TABLE +CREATE TABLE tmp ENGINE = INNODB AS SELECT COALESCE(NULL, NULL, NULL); +--error ER_CANT_CREATE_TABLE +CREATE TABLE tmp ENGINE = INNODB AS SELECT GREATEST(NULL, NULL); diff --git a/mysql-test/t/func_if.test b/mysql-test/t/func_if.test index 91f70bb98d7..41115a2da30 100644 --- a/mysql-test/t/func_if.test +++ b/mysql-test/t/func_if.test @@ -177,3 +177,15 @@ INSERT INTO t1 VALUES (NULL, 0), (NULL, 1); SELECT IF(b, (SELECT a FROM t1 LIMIT 1), b) c FROM t1 GROUP BY c; DROP TABLE t1; + +--echo # +--echo # Bug#12532830 +--echo # SIGFPE OR ASSERTION (PRECISION <= ((9 * 9) - 8*2)) && (DEC <= 30) +--echo # + +let $nines= 9999999999999999999999999999999999999; +eval select +sum(distinct(if('a', + (select adddate(elt(convert($nines,decimal(64,0)),count(*)), + interval 1 day)) + , .1))) as foo; diff --git a/sql/field.cc b/sql/field.cc index e1a24e82718..ef66c1ba9bb 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -9159,8 +9159,9 @@ void Create_field::init_for_tmp_table(enum_field_types sql_type_arg, pack_flag= FIELDFLAG_INTERVAL; break; - case MYSQL_TYPE_DECIMAL: case MYSQL_TYPE_NEWDECIMAL: + DBUG_ASSERT(decimals_arg <= DECIMAL_MAX_SCALE); + case MYSQL_TYPE_DECIMAL: case MYSQL_TYPE_FLOAT: case MYSQL_TYPE_DOUBLE: pack_flag= FIELDFLAG_NUMBER | diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index e28221109d9..f30b6adcb93 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -2625,37 +2625,43 @@ Item_func_if::fix_fields(THD *thd, Item **ref) } +void Item_func_if::cache_type_info(Item *source) +{ + collation.set(source->collation); + cached_field_type= source->field_type(); + cached_result_type= source->result_type(); + decimals= source->decimals; + max_length= source->max_length; + maybe_null= source->maybe_null; + unsigned_flag= source->unsigned_flag; +} + + void Item_func_if::fix_length_and_dec() { - maybe_null=args[1]->maybe_null || args[2]->maybe_null; - decimals= max(args[1]->decimals, args[2]->decimals); - unsigned_flag=args[1]->unsigned_flag && args[2]->unsigned_flag; - - enum Item_result arg1_type=args[1]->result_type(); - enum Item_result arg2_type=args[2]->result_type(); - bool null1=args[1]->const_item() && args[1]->null_value; - bool null2=args[2]->const_item() && args[2]->null_value; - - if (null1) + // Let IF(cond, expr, NULL) and IF(cond, NULL, expr) inherit type from expr. + if (args[1]->type() == NULL_ITEM) { - cached_result_type= arg2_type; - collation.set(args[2]->collation); - cached_field_type= args[2]->field_type(); - max_length= args[2]->max_length; + cache_type_info(args[2]); + maybe_null= true; + // If both arguments are NULL, make resulting type BINARY(0). + if (args[2]->type() == NULL_ITEM) + cached_field_type= MYSQL_TYPE_STRING; return; } - - if (null2) + if (args[2]->type() == NULL_ITEM) { - cached_result_type= arg1_type; - collation.set(args[1]->collation); - cached_field_type= args[1]->field_type(); - max_length= args[1]->max_length; + cache_type_info(args[1]); + maybe_null= true; return; } agg_result_type(&cached_result_type, args + 1, 2); + maybe_null= args[1]->maybe_null || args[2]->maybe_null; + decimals= max(args[1]->decimals, args[2]->decimals); + unsigned_flag=args[1]->unsigned_flag && args[2]->unsigned_flag; + if (cached_result_type == STRING_RESULT) { if (agg_arg_charsets_for_string_result(collation, args + 1, 2)) diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index b6928d63ea0..a735f01fb39 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -750,6 +750,8 @@ public: void fix_length_and_dec(); uint decimal_precision() const; const char *func_name() const { return "if"; } +private: + void cache_type_info(Item *source); }; From 0fca2269425df6a1e2224bb3185a76d3a2608fbf Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Tue, 23 Aug 2011 15:13:17 +0200 Subject: [PATCH 008/288] Bug#11766879/Bug#60106: DIFF BETWEEN # OF INDEXES IN MYSQL VS INNODB, PARTITONING, ON INDEX CREATE If the first partition succeeded in adding a index, but a successive partition failed, then the first partition had still the new index. The fix reverts the added indexes from previous partitions on failure. --- mysql-test/r/partition_innodb_plugin.result | 22 +++++++++++++++++ mysql-test/t/partition_innodb_plugin.test | 27 +++++++++++++++++++-- sql/ha_partition.cc | 20 ++++++++++++++- 3 files changed, 66 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/partition_innodb_plugin.result b/mysql-test/r/partition_innodb_plugin.result index f6b5ce84338..081b7b94e1f 100644 --- a/mysql-test/r/partition_innodb_plugin.result +++ b/mysql-test/r/partition_innodb_plugin.result @@ -1,3 +1,25 @@ +# +# Bug#11766879/Bug#60106: DIFF BETWEEN # OF INDEXES IN MYSQL VS INNODB, +# PARTITONING, ON INDEX CREATE +# +CREATE TABLE t1 ( +id bigint NOT NULL AUTO_INCREMENT, +time date, +id2 bigint not null, +PRIMARY KEY (id,time) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 +/*!50100 PARTITION BY RANGE(TO_DAYS(time)) +(PARTITION p10 VALUES LESS THAN (734708) ENGINE = InnoDB, +PARTITION p20 VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */; +INSERT INTO t1 (time,id2) VALUES ('2011-07-24',1); +INSERT INTO t1 (time,id2) VALUES ('2011-07-25',1); +INSERT INTO t1 (time,id2) VALUES ('2011-07-25',1); +CREATE UNIQUE INDEX uk_time_id2 on t1(time,id2); +ERROR 23000: Duplicate entry '2011-07-25-1' for key 'uk_time_id2' +SELECT COUNT(*) FROM t1; +COUNT(*) +3 +DROP TABLE t1; call mtr.add_suppression("nnoDB: Error: table `test`.`t1` .* Partition.* InnoDB internal"); # # Bug#55091: Server crashes on ADD PARTITION after a failed attempt diff --git a/mysql-test/t/partition_innodb_plugin.test b/mysql-test/t/partition_innodb_plugin.test index 626e5d19b99..efcf5c282a7 100644 --- a/mysql-test/t/partition_innodb_plugin.test +++ b/mysql-test/t/partition_innodb_plugin.test @@ -1,10 +1,33 @@ --source include/have_partition.inc --source include/have_innodb_plugin.inc -# Remove the line below when bug#53307 is solved. ---source include/not_valgrind.inc let $MYSQLD_DATADIR= `SELECT @@datadir`; +--echo # +--echo # Bug#11766879/Bug#60106: DIFF BETWEEN # OF INDEXES IN MYSQL VS INNODB, +--echo # PARTITONING, ON INDEX CREATE +--echo # +CREATE TABLE t1 ( + id bigint NOT NULL AUTO_INCREMENT, + time date, + id2 bigint not null, + PRIMARY KEY (id,time) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 +/*!50100 PARTITION BY RANGE(TO_DAYS(time)) +(PARTITION p10 VALUES LESS THAN (734708) ENGINE = InnoDB, + PARTITION p20 VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */; + +INSERT INTO t1 (time,id2) VALUES ('2011-07-24',1); +INSERT INTO t1 (time,id2) VALUES ('2011-07-25',1); +INSERT INTO t1 (time,id2) VALUES ('2011-07-25',1); + +--error ER_DUP_ENTRY +CREATE UNIQUE INDEX uk_time_id2 on t1(time,id2); + +SELECT COUNT(*) FROM t1; + +DROP TABLE t1; + call mtr.add_suppression("nnoDB: Error: table `test`.`t1` .* Partition.* InnoDB internal"); --echo # --echo # Bug#55091: Server crashes on ADD PARTITION after a failed attempt diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index cd5d7f201a7..7c7cf5a4302 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -6490,7 +6490,25 @@ int ha_partition::add_index(TABLE *table_arg, KEY *key_info, uint num_of_keys) */ for (file= m_file; *file; file++) if ((ret= (*file)->add_index(table_arg, key_info, num_of_keys))) - break; + goto err; + return ret; +err: + if (file > m_file) + { + uint *key_numbers= (uint*) ha_thd()->alloc(sizeof(uint) * num_of_keys); + KEY *old_key_info= table_arg->key_info; + uint i; + /* Use the newly added key_info as table->key_info to remove them. */ + for (i= 0; i < num_of_keys; i++) + key_numbers[i]= i; + table_arg->key_info= key_info; + while (--file >= m_file) + { + (void) (*file)->prepare_drop_index(table_arg, key_numbers, num_of_keys); + (void) (*file)->final_drop_index(table_arg); + } + table_arg->key_info= old_key_info; + } return ret; } From 884df0871d0453624504b9b8dc485a859911f2e7 Mon Sep 17 00:00:00 2001 From: Kristofer Pettersson Date: Tue, 23 Aug 2011 16:20:21 +0200 Subject: [PATCH 009/288] Bug10064164 Clean up of the protocol to avoid ambiguities The client-server protocol has left some room for interpretation which this patch fixes by introducing byte counters and enforced logic for SSL handshakes. --- sql/sql_acl.cc | 145 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 105 insertions(+), 40 deletions(-) diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 06a67edda36..d3f03d40d22 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -520,23 +520,9 @@ static uchar* acl_entry_get_key(acl_entry *entry, size_t *length, #define ACL_KEY_LENGTH (IP_ADDR_STRLEN + 1 + NAME_LEN + \ 1 + USERNAME_LENGTH + 1) -#if defined(HAVE_OPENSSL) -/* - Without SSL the handshake consists of one packet. This packet - has both client capabilities and scrambled password. - With SSL the handshake might consist of two packets. If the first - packet (client capabilities) has CLIENT_SSL flag set, we have to - switch to SSL and read the second packet. The scrambled password - is in the second packet and client_capabilities field will be ignored. - Maybe it is better to accept flags other than CLIENT_SSL from the - second packet? -*/ -#define SSL_HANDSHAKE_SIZE 2 -#define NORMAL_HANDSHAKE_SIZE 6 -#define MIN_HANDSHAKE_SIZE 2 -#else -#define MIN_HANDSHAKE_SIZE 6 -#endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */ +/** Size of the header fields of an authentication packet. */ +#define AUTH_PACKET_HEADER_SIZE_PROTO_41 32 +#define AUTH_PACKET_HEADER_SIZE_PROTO_40 5 static DYNAMIC_ARRAY acl_hosts, acl_users, acl_dbs, acl_proxy_users; static MEM_ROOT mem, memex; @@ -8552,37 +8538,92 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio, #ifndef EMBEDDED_LIBRARY NET *net= mpvio->net; char *end; - + bool packet_has_required_size= false; DBUG_ASSERT(mpvio->status == MPVIO_EXT::FAILURE); - if (pkt_len < MIN_HANDSHAKE_SIZE) - return packet_error; - if (mpvio->connect_errors) reset_host_errors(mpvio->ip); - ulong client_capabilities= uint2korr(net->read_pos); - if (client_capabilities & CLIENT_PROTOCOL_41) + uint charset_code= 0; + end= (char *)net->read_pos; + /* + In order to safely scan a head for '\0' string terminators + we must keep track of how many bytes remain in the allocated + buffer or we might read past the end of the buffer. + */ + size_t bytes_remaining_in_packet= pkt_len; + + /* + Peek ahead on the client capability packet and determine which version of + the protocol should be used. + */ + if (bytes_remaining_in_packet < 2) + return packet_error; + + mpvio->client_capabilities= uint2korr(end); + + /* + JConnector only sends server capabilities before starting SSL + negotiation. The below code is patch for this. + */ + if (bytes_remaining_in_packet == 4 && + mpvio->client_capabilities & CLIENT_SSL) { - client_capabilities|= ((ulong) uint2korr(net->read_pos + 2)) << 16; - mpvio->max_client_packet_length= uint4korr(net->read_pos + 4); - DBUG_PRINT("info", ("client_character_set: %d", (uint) net->read_pos[8])); - if (mpvio->charset_adapter->init_client_charset((uint) net->read_pos[8])) + mpvio->client_capabilities= uint4korr(end); + mpvio->max_client_packet_length= 0xfffff; + charset_code= default_charset_info->number; + if (mpvio->charset_adapter->init_client_charset(charset_code)) return packet_error; - end= (char*) net->read_pos + 32; + goto skip_to_ssl; + } + + if (mpvio->client_capabilities & CLIENT_PROTOCOL_41) + packet_has_required_size= bytes_remaining_in_packet >= + AUTH_PACKET_HEADER_SIZE_PROTO_41; + else + packet_has_required_size= bytes_remaining_in_packet >= + AUTH_PACKET_HEADER_SIZE_PROTO_40; + + if (!packet_has_required_size) + return packet_error; + + if (mpvio->client_capabilities & CLIENT_PROTOCOL_41) + { + mpvio->client_capabilities= uint4korr(end); + mpvio->max_client_packet_length= uint4korr(end + 4); + charset_code= (uint)(uchar)*(end + 8); + /* + Skip 23 remaining filler bytes which have no particular meaning. + */ + end+= AUTH_PACKET_HEADER_SIZE_PROTO_41; + bytes_remaining_in_packet-= AUTH_PACKET_HEADER_SIZE_PROTO_41; } else { - mpvio->max_client_packet_length= uint3korr(net->read_pos + 2); - end= (char*) net->read_pos + 5; + mpvio->client_capabilities= uint2korr(end); + mpvio->max_client_packet_length= uint3korr(end + 2); + end+= AUTH_PACKET_HEADER_SIZE_PROTO_40; + bytes_remaining_in_packet-= AUTH_PACKET_HEADER_SIZE_PROTO_40; + /** + Old clients didn't have their own charset. Instead the assumption + was that they used what ever the server used. + */ + charset_code= default_charset_info->number; } - /* Disable those bits which are not supported by the client. */ - mpvio->client_capabilities&= client_capabilities; - + DBUG_PRINT("info", ("client_character_set: %u", charset_code)); + if (mpvio->charset_adapter->init_client_charset(charset_code)) + return packet_error; #if defined(HAVE_OPENSSL) DBUG_PRINT("info", ("client capabilities: %lu", mpvio->client_capabilities)); + + /* + If client requested SSL then we must stop parsing, try to switch to SSL, + and wait for the client to send a new handshake packet. + The client isn't expected to send any more bytes until SSL is initialized. + */ +skip_to_ssl: if (mpvio->client_capabilities & CLIENT_SSL) { unsigned long errptr; @@ -8599,18 +8640,42 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio, } DBUG_PRINT("info", ("Reading user information over SSL layer")); - pkt_len= my_net_read(net); - if (pkt_len == packet_error || pkt_len < NORMAL_HANDSHAKE_SIZE) + if ((pkt_len= my_net_read(net)) == packet_error) { DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)", pkt_len)); return packet_error; } - } -#endif + /* + A new packet was read and the statistics reflecting the remaining bytes + in the packet must be updated. + */ + bytes_remaining_in_packet= pkt_len; - if (end > (char *)net->read_pos + pkt_len) - return packet_error; + /* + After the SSL handshake is performed the client resends the handshake + packet but because of legacy reasons we chose not to parse the packet + fields a second time and instead only assert the length of the packet. + */ + if (mpvio->client_capabilities & CLIENT_PROTOCOL_41) + { + packet_has_required_size= bytes_remaining_in_packet >= + AUTH_PACKET_HEADER_SIZE_PROTO_41; + end= (char *)net->read_pos + AUTH_PACKET_HEADER_SIZE_PROTO_41; + bytes_remaining_in_packet -= AUTH_PACKET_HEADER_SIZE_PROTO_41; + } + else + { + packet_has_required_size= bytes_remaining_in_packet >= + AUTH_PACKET_HEADER_SIZE_PROTO_40; + end= (char *)net->read_pos + AUTH_PACKET_HEADER_SIZE_PROTO_40; + bytes_remaining_in_packet -= AUTH_PACKET_HEADER_SIZE_PROTO_40; + } + + if (!packet_has_required_size) + return packet_error; + } +#endif /* HAVE_OPENSSL */ if ((mpvio->client_capabilities & CLIENT_TRANSACTIONS) && opt_using_transactions) @@ -8634,7 +8699,7 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio, we must keep track of how many bytes remain in the allocated buffer or we might read past the end of the buffer. */ - size_t bytes_remaining_in_packet= pkt_len - (end - (char *)net->read_pos); + bytes_remaining_in_packet= pkt_len - (end - (char *)net->read_pos); size_t user_len; char *user= get_string(&end, &bytes_remaining_in_packet, &user_len); From 3603b28da4911bc97c84c30a6ae4da6417ebf94e Mon Sep 17 00:00:00 2001 From: Tor Didriksen Date: Wed, 24 Aug 2011 09:18:50 +0200 Subject: [PATCH 010/288] Bug#10064164 post-push fix: build break unless #defined HAVE_OPENSSL --- sql/sql_acl.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index d3f03d40d22..aaf8ed26966 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -8615,6 +8615,7 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio, if (mpvio->charset_adapter->init_client_charset(charset_code)) return packet_error; +skip_to_ssl: #if defined(HAVE_OPENSSL) DBUG_PRINT("info", ("client capabilities: %lu", mpvio->client_capabilities)); @@ -8623,7 +8624,6 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio, and wait for the client to send a new handshake packet. The client isn't expected to send any more bytes until SSL is initialized. */ -skip_to_ssl: if (mpvio->client_capabilities & CLIENT_SSL) { unsigned long errptr; From 39175b922504c8e459040657e48c89ea14256683 Mon Sep 17 00:00:00 2001 From: Kristofer Pettersson Date: Tue, 6 Sep 2011 09:42:14 +0200 Subject: [PATCH 011/288] Bug11764310 - 57132: CONV FUNCTION CRASHES, NEGATIVE ARGUMENT TO MEMCPY Failure to check the return state of a longlong2str() call caused a crash. This could happen if a user executed the sql function CONV() with certain parameters. The patch fixes the issue by checking that the returned pointer isn't NULL. --- mysql-test/r/func_str.result | 6 ++++++ mysql-test/t/func_str.test | 5 +++++ sql/item_strfunc.cc | 10 ++++++---- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index 81fe2413725..5a582f08829 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -2784,6 +2784,12 @@ SELECT * FROM t1; format(123,2,'no_NO') 123,00 DROP TABLE t1; +# +# Bug#11764310 conv function crashes, negative argument to memcpy +# +SELECT CONV(1,-2147483648,-2147483648); +CONV(1,-2147483648,-2147483648) + # # End of 5.5 tests # diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index 9a9a8110a74..076c64e3ee1 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -1436,6 +1436,11 @@ SHOW CREATE TABLE t1; SELECT * FROM t1; DROP TABLE t1; +--echo # +--echo # Bug#11764310 conv function crashes, negative argument to memcpy +--echo # +SELECT CONV(1,-2147483648,-2147483648); + --echo # --echo # End of 5.5 tests --echo # diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 55087879b98..c6e9384bc5e 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -2952,8 +2952,8 @@ String *Item_func_conv::val_str(String *str) from_base, &endptr, &err); } - ptr= longlong2str(dec, ans, to_base); - if (str->copy(ans, (uint32) (ptr-ans), default_charset())) + if (!(ptr= longlong2str(dec, ans, to_base)) || + str->copy(ans, (uint32) (ptr - ans), default_charset())) return make_empty_result(); return str; } @@ -3113,8 +3113,10 @@ String *Item_func_hex::val_str_ascii(String *str) if ((null_value= args[0]->null_value)) return 0; - ptr= longlong2str(dec,ans,16); - if (str->copy(ans,(uint32) (ptr-ans), &my_charset_numeric)) + + if (!(ptr= longlong2str(dec, ans, 16)) || + str->copy(ans,(uint32) (ptr - ans), + &my_charset_numeric)) return make_empty_result(); // End of memory return str; } From d1a80e6ad7ce5909301c4fa1549bcedefc4f89cd Mon Sep 17 00:00:00 2001 From: Jimmy Yang Date: Wed, 7 Sep 2011 21:42:14 -0700 Subject: [PATCH 012/288] Fix Bug #12885783 - BLOCK LOADING TABLE WITH LARGE COLLATION NUMBER FROM 5.6 SERVER rb://747 approved by Marko --- storage/innobase/dict/dict0load.c | 40 ++++++++++++++++++++-- storage/innobase/handler/ha_innodb.cc | 11 +++--- storage/innobase/include/data0type.h | 9 +++++ storage/innobase/include/data0type.ic | 6 ++-- storage/innodb_plugin/ChangeLog | 7 ++++ storage/innodb_plugin/dict/dict0load.c | 40 ++++++++++++++++++++-- storage/innodb_plugin/handler/ha_innodb.cc | 7 ++-- storage/innodb_plugin/include/data0type.h | 9 +++++ storage/innodb_plugin/include/data0type.ic | 2 +- 9 files changed, 114 insertions(+), 17 deletions(-) diff --git a/storage/innobase/dict/dict0load.c b/storage/innobase/dict/dict0load.c index 7e820cfb08d..4b5087e6e22 100644 --- a/storage/innobase/dict/dict0load.c +++ b/storage/innobase/dict/dict0load.c @@ -25,6 +25,7 @@ Created 4/24/1996 Heikki Tuuri #include "rem0cmp.h" #include "srv0start.h" #include "srv0srv.h" +#include "db0err.h" /******************************************************************** Returns TRUE if index's i'th column's name is 'name' .*/ @@ -329,7 +330,7 @@ loop: /************************************************************************ Loads definitions for table columns. */ static -void +ulint dict_load_columns( /*==============*/ dict_table_t* table, /* in: table */ @@ -350,6 +351,7 @@ dict_load_columns( ulint col_len; ulint i; mtr_t mtr; + ulint err = DB_SUCCESS; ut_ad(mutex_own(&(dict_sys->mutex))); @@ -397,6 +399,30 @@ dict_load_columns( field = rec_get_nth_field_old(rec, 6, &len); prtype = mach_read_from_4(field); + /* We can rely on dtype_get_charset_coll() to check + charset collation number exceed limit, since it comes + with a smaller mask. We have to do the check explicitly + here */ + if (((prtype >> 16) & LARGE_CHAR_COLL_PRTYPE_MASK) + > MAX_CHAR_COLL_NUM) { + fprintf(stderr, "InnoDB: Error: load column" + " '%s' for table '%s' failed.\n" + "InnoDB: column '%s' has a charset" + " collation number of %lu, exceeds" + " maximum value %lu supported\n", + name, name, table->name, + (ulong) ((prtype >> 16) + & LARGE_CHAR_COLL_PRTYPE_MASK), + (ulong) MAX_CHAR_COLL_NUM); + err = DB_CORRUPTION; + + /* If the force recovery flag is not set, it will + stop loading and exit */ + if (!srv_force_recovery) { + goto func_exit; + } + } + if (dtype_get_charset_coll(prtype) == 0 && dtype_is_string_type(mtype)) { /* The table was created with < 4.1.2. */ @@ -428,8 +454,11 @@ dict_load_columns( btr_pcur_move_to_next_user_rec(&pcur, &mtr); } +func_exit: btr_pcur_close(&pcur); mtr_commit(&mtr); + + return(err); } /************************************************************************ @@ -899,7 +928,12 @@ err_exit: btr_pcur_close(&pcur); mtr_commit(&mtr); - dict_load_columns(table, heap); + err = dict_load_columns(table, heap); + + if (err != DB_SUCCESS && !srv_force_recovery) { + table = NULL; + goto func_exit; + } dict_table_add_to_cache(table, heap); @@ -961,6 +995,8 @@ err_exit: mutex_exit(&dict_foreign_err_mutex); } #endif /* 0 */ + +func_exit: mem_heap_free(heap); return(table); diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index dfe13ccbbfe..64f6b5da414 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -5336,13 +5336,14 @@ create_table_def( charset_no = (ulint)field->charset()->number; - ut_a(charset_no < 256); /* in data0type.h we assume - that the number fits in one - byte */ + /* in data0type.h we assume + that the number fits in one byte */ + ut_a(charset_no <= MAX_CHAR_COLL_NUM); } - ut_a(field->type() < 256); /* we assume in dtype_form_prtype() - that this fits in one byte */ + /* we assume in dtype_form_prtype() that this fits in + one byte */ + ut_a(field->type() <= MAX_CHAR_COLL_NUM); col_len = field->pack_length(); /* The MySQL pack length contains 1 or 2 bytes length field diff --git a/storage/innobase/include/data0type.h b/storage/innobase/include/data0type.h index e5e9c5076be..5b1628bb56c 100644 --- a/storage/innobase/include/data0type.h +++ b/storage/innobase/include/data0type.h @@ -149,6 +149,15 @@ SQL null*/ store the charset-collation number; one byte is left unused, though */ #define DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE 6 +/* We support 8 bits (up to 255) collation number until 5.6.3, in which +the collation number is extended to 32767 */ +#define MAX_CHAR_COLL_NUM 255 + +/* Mask to get the large charset-collation number in PRTYPE +This is used to mainly block loading tables with large charset-collation +value with database from 5.6 */ +#define LARGE_CHAR_COLL_PRTYPE_MASK 0xFFFFUL + /************************************************************************* Gets the MySQL type code from a dtype. */ UNIV_INLINE diff --git a/storage/innobase/include/data0type.ic b/storage/innobase/include/data0type.ic index ad0f95755d2..9135f2afa61 100644 --- a/storage/innobase/include/data0type.ic +++ b/storage/innobase/include/data0type.ic @@ -272,7 +272,7 @@ dtype_new_store_for_order_and_null_size( mach_write_to_2(buf + 2, len & 0xFFFFUL); - ut_ad(dtype_get_charset_coll(type->prtype) < 256); + ut_ad(dtype_get_charset_coll(type->prtype) <= MAX_CHAR_COLL_NUM); mach_write_to_2(buf + 4, dtype_get_charset_coll(type->prtype)); if (type->prtype & DATA_NOT_NULL) { @@ -339,12 +339,10 @@ dtype_new_read_for_order_and_null_size( type->len = mach_read_from_2(buf + 2); - mach_read_from_2(buf + 4); - charset_coll = mach_read_from_2(buf + 4) & 0x7fff; if (dtype_is_string_type(type->mtype)) { - ut_a(charset_coll < 256); + ut_a(charset_coll <= MAX_CHAR_COLL_NUM); if (charset_coll == 0) { /* This insert buffer record was inserted with MySQL diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index a29aaf2077e..2e66a987745 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,3 +1,10 @@ +2011-09-08 The InnoDB Team + + * dict/dict0load.c, handler/ha_innodb.cc, include/data0type.h + include/data0type.ic: + Fix Bug##12885783 - BLOCK LOADING TABLE WITH LARGE COLLATION + NUMBER FROM 5.6 SERVER + 2011-09-06 The InnoDB Team * buf/buf0buddy.c: diff --git a/storage/innodb_plugin/dict/dict0load.c b/storage/innodb_plugin/dict/dict0load.c index 7a0b6edcb08..1bbced84091 100644 --- a/storage/innodb_plugin/dict/dict0load.c +++ b/storage/innodb_plugin/dict/dict0load.c @@ -40,6 +40,7 @@ Created 4/24/1996 Heikki Tuuri #include "rem0cmp.h" #include "srv0start.h" #include "srv0srv.h" +#include "db0err.h" /****************************************************************//** Compare the name of an index column. @@ -449,7 +450,7 @@ loop: /********************************************************************//** Loads definitions for table columns. */ static -void +enum db_err dict_load_columns( /*==============*/ dict_table_t* table, /*!< in: table */ @@ -470,6 +471,7 @@ dict_load_columns( ulint col_len; ulint i; mtr_t mtr; + enum db_err err = DB_SUCCESS; ut_ad(mutex_own(&(dict_sys->mutex))); @@ -517,6 +519,30 @@ dict_load_columns( field = rec_get_nth_field_old(rec, 6, &len); prtype = mach_read_from_4(field); + /* We can rely on dtype_get_charset_coll() to check + charset collation number exceed limit, since it comes + with a smaller mask. We have to do the check explicitly + here */ + if (((prtype >> 16) & LARGE_CHAR_COLL_PRTYPE_MASK) + > MAX_CHAR_COLL_NUM) { + fprintf(stderr, "InnoDB: Error: load column" + " '%s' for table '%s' failed.\n" + "InnoDB: column '%s' has a charset" + " collation number of %lu, exceeds" + " maximum value %lu supported\n", + name, name, table->name, + (ulong) ((prtype >> 16) + & LARGE_CHAR_COLL_PRTYPE_MASK), + (ulong) MAX_CHAR_COLL_NUM); + err = DB_CORRUPTION; + + /* If the force recovery flag is not set, it will + stop loading and exit */ + if (!srv_force_recovery) { + goto func_exit; + } + } + if (dtype_get_charset_coll(prtype) == 0 && dtype_is_string_type(mtype)) { /* The table was created with < 4.1.2. */ @@ -548,8 +574,11 @@ dict_load_columns( btr_pcur_move_to_next_user_rec(&pcur, &mtr); } +func_exit: btr_pcur_close(&pcur); mtr_commit(&mtr); + + return(err); } /********************************************************************//** @@ -1044,7 +1073,12 @@ err_exit: btr_pcur_close(&pcur); mtr_commit(&mtr); - dict_load_columns(table, heap); + err = dict_load_columns(table, heap); + + if (err != DB_SUCCESS && !srv_force_recovery) { + table = NULL; + goto func_exit; + } dict_table_add_to_cache(table, heap); @@ -1106,6 +1140,8 @@ err_exit: mutex_exit(&dict_foreign_err_mutex); } #endif /* 0 */ + +func_exit: mem_heap_free(heap); return(table); diff --git a/storage/innodb_plugin/handler/ha_innodb.cc b/storage/innodb_plugin/handler/ha_innodb.cc index 609299efce5..e7c5cbdedae 100644 --- a/storage/innodb_plugin/handler/ha_innodb.cc +++ b/storage/innodb_plugin/handler/ha_innodb.cc @@ -6086,7 +6086,7 @@ create_table_def( charset_no = (ulint)field->charset()->number; - if (UNIV_UNLIKELY(charset_no >= 256)) { + if (UNIV_UNLIKELY(charset_no > MAX_CHAR_COLL_NUM)) { /* in data0type.h we assume that the number fits in one byte in prtype */ push_warning_printf( @@ -6101,8 +6101,9 @@ create_table_def( } } - ut_a(field->type() < 256); /* we assume in dtype_form_prtype() - that this fits in one byte */ + /* we assume in dtype_form_prtype() that this fits in + one byte */ + ut_a(field->type() <= MAX_CHAR_COLL_NUM); col_len = field->pack_length(); /* The MySQL pack length contains 1 or 2 bytes length field diff --git a/storage/innodb_plugin/include/data0type.h b/storage/innodb_plugin/include/data0type.h index a73bed3a9f5..87699e8ab5d 100644 --- a/storage/innodb_plugin/include/data0type.h +++ b/storage/innodb_plugin/include/data0type.h @@ -168,6 +168,15 @@ SQL null*/ store the charset-collation number; one byte is left unused, though */ #define DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE 6 +/* We support 8 bits (up to 255) collation number until 5.6.3, in which +the collation number is extended to 32767 */ +#define MAX_CHAR_COLL_NUM 255 + +/* Mask to get the large charset-collation number in PRTYPE +This is used to mainly block loading tables with large charset-collation +value with database from 5.6 */ +#define LARGE_CHAR_COLL_PRTYPE_MASK 0xFFFFUL + #ifndef UNIV_HOTBACKUP /*********************************************************************//** Gets the MySQL type code from a dtype. diff --git a/storage/innodb_plugin/include/data0type.ic b/storage/innodb_plugin/include/data0type.ic index 2bf67a941bd..44b6cf273e5 100644 --- a/storage/innodb_plugin/include/data0type.ic +++ b/storage/innodb_plugin/include/data0type.ic @@ -306,7 +306,7 @@ dtype_new_store_for_order_and_null_size( mach_write_to_2(buf + 2, len & 0xFFFFUL); - ut_ad(dtype_get_charset_coll(type->prtype) < 256); + ut_ad(dtype_get_charset_coll(type->prtype) <= MAX_CHAR_COLL_NUM); mach_write_to_2(buf + 4, dtype_get_charset_coll(type->prtype)); if (type->prtype & DATA_NOT_NULL) { From e9d23b5a89241ccd290ad3da43e7947f7e161222 Mon Sep 17 00:00:00 2001 From: Kristofer Pettersson Date: Thu, 15 Sep 2011 10:01:15 +0200 Subject: [PATCH 013/288] Bug#11764310 - 57132: CONV FUNCTION CRASHES, NEGATIVE ARGUMENT TO MEMCPY Amendment to previous patch: Failure in CONV() should return NULL instead of empty set. When compiled on Windows or Solaris the function Item_func_conv::val_str() doesn't fail on longlong2str() but finds an earlier exit path based on the attributes of the arguments. This exit path returns NULL on failure and as a consequence the original patch caused different test results depending on the OS used. --- mysql-test/r/func_str.result | 2 +- sql/item_strfunc.cc | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index 5a582f08829..d3757f799ce 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -2789,7 +2789,7 @@ DROP TABLE t1; # SELECT CONV(1,-2147483648,-2147483648); CONV(1,-2147483648,-2147483648) - +NULL # # End of 5.5 tests # diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index c6e9384bc5e..a0fdb3cf811 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -2954,7 +2954,10 @@ String *Item_func_conv::val_str(String *str) if (!(ptr= longlong2str(dec, ans, to_base)) || str->copy(ans, (uint32) (ptr - ans), default_charset())) - return make_empty_result(); + { + null_value= 1; + return NULL; + } return str; } From ab761db8d5c4d59229c94687abf5030130a168b2 Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Thu, 15 Sep 2011 20:49:39 +0200 Subject: [PATCH 014/288] Bug#12696518: MEMORY LEAKS IN HA_PARTITION (VALGRIND TESTS ON TRUNK) (also 5.5+ solution for bug#11766879/bug#60106) The valgrind warning was due to an unused 'new handler_add_index(...)' which was never freed. The error handling did not work (fails as in bug#11766879) and the implementation was not as transparant as it could, therefore I made it a bit simpler and more transparant to the underlying handlers. This way it follows the api better and the error handling works and is also now tested. Also added a debug test to verify the error handling. Improved according to Jon Olavs review: Added class ha_partition_add_index. Also added base class Sql_alloc to handler_add_index. Update 3. --- mysql-test/r/partition_innodb_plugin.result | 34 +++ .../parts/r/partition_debug_innodb.result | 71 ++++++ .../suite/parts/t/partition_debug_innodb.test | 35 +++ mysql-test/t/partition_innodb_plugin.test | 27 +++ sql/ha_partition.cc | 206 ++++++++++++++---- sql/handler.h | 6 +- 6 files changed, 331 insertions(+), 48 deletions(-) diff --git a/mysql-test/r/partition_innodb_plugin.result b/mysql-test/r/partition_innodb_plugin.result index aa0944e96b5..f30dbd20119 100644 --- a/mysql-test/r/partition_innodb_plugin.result +++ b/mysql-test/r/partition_innodb_plugin.result @@ -1,3 +1,37 @@ +# +# Bug#11766879/Bug#60106: DIFF BETWEEN # OF INDEXES IN MYSQL VS INNODB, +# PARTITONING, ON INDEX CREATE +# Bug#12696518: MEMORY LEAKS IN HA_PARTITION (VALGRIND TESTS ON TRUNK) +# +CREATE TABLE t1 ( +id bigint NOT NULL AUTO_INCREMENT, +time date, +id2 bigint not null, +PRIMARY KEY (id,time) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 +/*!50100 PARTITION BY RANGE(TO_DAYS(time)) +(PARTITION p10 VALUES LESS THAN (734708) ENGINE = InnoDB, +PARTITION p20 VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */; +INSERT INTO t1 (time,id2) VALUES ('2011-07-24',1); +INSERT INTO t1 (time,id2) VALUES ('2011-07-25',1); +INSERT INTO t1 (time,id2) VALUES ('2011-07-25',1); +CREATE UNIQUE INDEX uk_time_id2 on t1(time,id2); +ERROR 23000: Duplicate entry '2011-07-25-1' for key 'uk_time_id2' +SELECT COUNT(*) FROM t1; +COUNT(*) +3 +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `time` date NOT NULL DEFAULT '0000-00-00', + `id2` bigint(20) NOT NULL, + PRIMARY KEY (`id`,`time`) +) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 +/*!50100 PARTITION BY RANGE (TO_DAYS(time)) +(PARTITION p10 VALUES LESS THAN (734708) ENGINE = InnoDB, + PARTITION p20 VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */ +DROP TABLE t1; call mtr.add_suppression("nnoDB: Error: table `test`.`t1` .* Partition.* InnoDB internal"); # # Bug#55091: Server crashes on ADD PARTITION after a failed attempt diff --git a/mysql-test/suite/parts/r/partition_debug_innodb.result b/mysql-test/suite/parts/r/partition_debug_innodb.result index 49d863bca8e..bae4faf434e 100644 --- a/mysql-test/suite/parts/r/partition_debug_innodb.result +++ b/mysql-test/suite/parts/r/partition_debug_innodb.result @@ -1,4 +1,75 @@ DROP TABLE IF EXISTS t1; +# +# Bug#12696518/Bug#11766879/60106:DIFF BETWEEN # OF INDEXES IN MYSQL +# VS INNODB, PARTITONING, ON INDEX CREATE +# +CREATE TABLE t1 +(a INT PRIMARY KEY, +b VARCHAR(64)) +ENGINE = InnoDB +PARTITION BY HASH (a) PARTITIONS 3; +INSERT INTO t1 VALUES (0, 'first row'), (1, 'second row'), (2, 'Third row'); +INSERT INTO t1 VALUES (3, 'row id 3'), (4, '4 row'), (5, 'row5'); +INSERT INTO t1 VALUES (6, 'X 6 row'), (7, 'Seventh row'), (8, 'Last row'); +ALTER TABLE t1 ADD INDEX new_b_index (b); +ALTER TABLE t1 DROP INDEX new_b_index; +SET SESSION debug= "+d,ha_partition_fail_final_add_index"; +ALTER TABLE t1 ADD INDEX (b); +ERROR HY000: Table has no partition for value 0 +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + `b` varchar(64) DEFAULT NULL, + PRIMARY KEY (`a`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY HASH (a) +PARTITIONS 3 */ +SELECT * FROM t1; +a b +0 first row +1 second row +2 Third row +3 row id 3 +4 4 row +5 row5 +6 X 6 row +7 Seventh row +8 Last row +FLUSH TABLES; +CREATE INDEX new_index ON t1 (b); +ERROR HY000: Table has no partition for value 0 +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + `b` varchar(64) DEFAULT NULL, + PRIMARY KEY (`a`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY HASH (a) +PARTITIONS 3 */ +SELECT * FROM t1; +a b +0 first row +1 second row +2 Third row +3 row id 3 +4 4 row +5 row5 +6 X 6 row +7 Seventh row +8 Last row +SET SESSION debug= "-d,ha_partition_fail_final_add_index"; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + `b` varchar(64) DEFAULT NULL, + PRIMARY KEY (`a`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY HASH (a) +PARTITIONS 3 */ +DROP TABLE t1; call mtr.add_suppression("InnoDB: Warning: allocated tablespace .*, old maximum was"); call mtr.add_suppression("InnoDB: Error: table .* does not exist in the InnoDB internal"); call mtr.add_suppression("InnoDB: Warning: MySQL is trying to drop table "); diff --git a/mysql-test/suite/parts/t/partition_debug_innodb.test b/mysql-test/suite/parts/t/partition_debug_innodb.test index c5d8df33213..b546f6d73f8 100644 --- a/mysql-test/suite/parts/t/partition_debug_innodb.test +++ b/mysql-test/suite/parts/t/partition_debug_innodb.test @@ -12,6 +12,41 @@ DROP TABLE IF EXISTS t1; --let $DATADIR= `SELECT @@datadir;` +--echo # +--echo # Bug#12696518/Bug#11766879/60106:DIFF BETWEEN # OF INDEXES IN MYSQL +--echo # VS INNODB, PARTITONING, ON INDEX CREATE +--echo # +CREATE TABLE t1 +(a INT PRIMARY KEY, + b VARCHAR(64)) +ENGINE = InnoDB +PARTITION BY HASH (a) PARTITIONS 3; +INSERT INTO t1 VALUES (0, 'first row'), (1, 'second row'), (2, 'Third row'); +INSERT INTO t1 VALUES (3, 'row id 3'), (4, '4 row'), (5, 'row5'); +INSERT INTO t1 VALUES (6, 'X 6 row'), (7, 'Seventh row'), (8, 'Last row'); + +ALTER TABLE t1 ADD INDEX new_b_index (b); +ALTER TABLE t1 DROP INDEX new_b_index; + +SET SESSION debug= "+d,ha_partition_fail_final_add_index"; + +--error ER_NO_PARTITION_FOR_GIVEN_VALUE +ALTER TABLE t1 ADD INDEX (b); +SHOW CREATE TABLE t1; +--sorted_result +SELECT * FROM t1; + +FLUSH TABLES; +--error ER_NO_PARTITION_FOR_GIVEN_VALUE +CREATE INDEX new_index ON t1 (b); +SHOW CREATE TABLE t1; +--sorted_result +SELECT * FROM t1; + +SET SESSION debug= "-d,ha_partition_fail_final_add_index"; +SHOW CREATE TABLE t1; +DROP TABLE t1; + # Checking with #innodb what this is... call mtr.add_suppression("InnoDB: Warning: allocated tablespace .*, old maximum was"); # If there is a crash or failure between the ddl_log is written and the diff --git a/mysql-test/t/partition_innodb_plugin.test b/mysql-test/t/partition_innodb_plugin.test index e8b73687177..ee428e0662f 100644 --- a/mysql-test/t/partition_innodb_plugin.test +++ b/mysql-test/t/partition_innodb_plugin.test @@ -3,6 +3,33 @@ let $MYSQLD_DATADIR= `SELECT @@datadir`; +--echo # +--echo # Bug#11766879/Bug#60106: DIFF BETWEEN # OF INDEXES IN MYSQL VS INNODB, +--echo # PARTITONING, ON INDEX CREATE +--echo # Bug#12696518: MEMORY LEAKS IN HA_PARTITION (VALGRIND TESTS ON TRUNK) +--echo # +CREATE TABLE t1 ( + id bigint NOT NULL AUTO_INCREMENT, + time date, + id2 bigint not null, + PRIMARY KEY (id,time) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 +/*!50100 PARTITION BY RANGE(TO_DAYS(time)) +(PARTITION p10 VALUES LESS THAN (734708) ENGINE = InnoDB, + PARTITION p20 VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */; + +INSERT INTO t1 (time,id2) VALUES ('2011-07-24',1); +INSERT INTO t1 (time,id2) VALUES ('2011-07-25',1); +INSERT INTO t1 (time,id2) VALUES ('2011-07-25',1); + +--error ER_DUP_ENTRY +CREATE UNIQUE INDEX uk_time_id2 on t1(time,id2); + +SELECT COUNT(*) FROM t1; +SHOW CREATE TABLE t1; + +DROP TABLE t1; + call mtr.add_suppression("nnoDB: Error: table `test`.`t1` .* Partition.* InnoDB internal"); --echo # --echo # Bug#55091: Server crashes on ADD PARTITION after a failed attempt diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 9e22553ef0e..7afe148dd17 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -6663,49 +6663,81 @@ bool ha_partition::check_if_incompatible_data(HA_CREATE_INFO *create_info, /** - Support of in-place add/drop index + Helper class for [final_]add_index, see handler.h */ + +class ha_partition_add_index : public handler_add_index +{ +public: + handler_add_index **add_array; + ha_partition_add_index(TABLE* table_arg, KEY* key_info_arg, + uint num_of_keys_arg) + : handler_add_index(table_arg, key_info_arg, num_of_keys_arg) + {} + ~ha_partition_add_index() {} +}; + + +/** + Support of in-place add/drop index + + @param table_arg Table to add index to + @param key_info Struct over the new keys to add + @param num_of_keys Number of keys to add + @param[out] add Data to be submitted with final_add_index + + @return Operation status + @retval 0 Success + @retval != 0 Failure (error code returned, and all operations rollbacked) +*/ + int ha_partition::add_index(TABLE *table_arg, KEY *key_info, uint num_of_keys, handler_add_index **add) { - handler **file; + uint i; int ret= 0; + THD *thd= ha_thd(); + ha_partition_add_index *part_add_index; DBUG_ENTER("ha_partition::add_index"); - *add= new handler_add_index(table, key_info, num_of_keys); /* There has already been a check in fix_partition_func in mysql_alter_table before this call, which checks for unique/primary key violations of the partitioning function. So no need for extra check here. */ - for (file= m_file; *file; file++) + + /* + This will be freed at the end of the statement. + And destroyed at final_add_index. (Sql_alloc does not free in delete). + */ + part_add_index= new (thd->mem_root) + ha_partition_add_index(table_arg, key_info, num_of_keys); + if (!part_add_index) + DBUG_RETURN(HA_ERR_OUT_OF_MEM); + part_add_index->add_array= (handler_add_index **) + thd->alloc(sizeof(void *) * m_tot_parts); + if (!part_add_index->add_array) { - handler_add_index *add_index; - if ((ret= (*file)->add_index(table_arg, key_info, num_of_keys, &add_index))) - goto err; - if ((ret= (*file)->final_add_index(add_index, true))) + delete part_add_index; + DBUG_RETURN(HA_ERR_OUT_OF_MEM); + } + + for (i= 0; i < m_tot_parts; i++) + { + if ((ret= m_file[i]->add_index(table_arg, key_info, num_of_keys, + &part_add_index->add_array[i]))) goto err; } + *add= part_add_index; DBUG_RETURN(ret); err: - if (file > m_file) + /* Rollback all prepared partitions. i - 1 .. 0 */ + while (i) { - uint *key_numbers= (uint*) ha_thd()->alloc(sizeof(uint) * num_of_keys); - uint old_num_of_keys= table_arg->s->keys; - uint i; - /* The newly created keys have the last id's */ - for (i= 0; i < num_of_keys; i++) - key_numbers[i]= i + old_num_of_keys; - if (!table_arg->key_info) - table_arg->key_info= key_info; - while (--file >= m_file) - { - (void) (*file)->prepare_drop_index(table_arg, key_numbers, num_of_keys); - (void) (*file)->final_drop_index(table_arg); - } - if (table_arg->key_info == key_info) - table_arg->key_info= NULL; + i--; + (void) m_file[i]->final_add_index(part_add_index->add_array[i], false); } + delete part_add_index; DBUG_RETURN(ret); } @@ -6713,37 +6745,119 @@ err: /** Second phase of in-place add index. + @param add Info from add_index + @param commit Should we commit or rollback the add_index operation + + @return Operation status + @retval 0 Success + @retval != 0 Failure (error code returned) + @note If commit is false, index changes are rolled back by dropping the added indexes. If commit is true, nothing is done as the indexes were already made active in ::add_index() - */ +*/ int ha_partition::final_add_index(handler_add_index *add, bool commit) { + ha_partition_add_index *part_add_index; + uint i; + int ret= 0; + DBUG_ENTER("ha_partition::final_add_index"); - // Rollback by dropping indexes. - if (!commit) + + if (!add) { - TABLE *table_arg= add->table; - uint num_of_keys= add->num_of_keys; - handler **file; - uint *key_numbers= (uint*) ha_thd()->alloc(sizeof(uint) * num_of_keys); - uint old_num_of_keys= table_arg->s->keys; - uint i; - /* The newly created keys have the last id's */ - for (i= 0; i < num_of_keys; i++) - key_numbers[i]= i + old_num_of_keys; - if (!table_arg->key_info) - table_arg->key_info= add->key_info; - for (file= m_file; *file; file++) - { - (void) (*file)->prepare_drop_index(table_arg, key_numbers, num_of_keys); - (void) (*file)->final_drop_index(table_arg); - } - if (table_arg->key_info == add->key_info) - table_arg->key_info= NULL; + DBUG_ASSERT(!commit); + DBUG_RETURN(0); } - DBUG_RETURN(0); + part_add_index= static_cast(add); + + for (i= 0; i < m_tot_parts; i++) + { + if ((ret= m_file[i]->final_add_index(part_add_index->add_array[i], commit))) + goto err; + DBUG_EXECUTE_IF("ha_partition_fail_final_add_index", { + /* Simulate a failure by rollback the second partition */ + if (m_tot_parts > 1) + { + i++; + m_file[i]->final_add_index(part_add_index->add_array[i], false); + /* Set an error that is specific to ha_partition. */ + ret= HA_ERR_NO_PARTITION_FOUND; + goto err; + } + }); + } + delete part_add_index; + DBUG_RETURN(ret); +err: + uint j; + uint *key_numbers= NULL; + KEY *old_key_info= NULL; + uint num_of_keys= 0; + int error; + + /* How could this happen? Needed to create a covering test case :) */ + DBUG_ASSERT(ret == HA_ERR_NO_PARTITION_FOUND); + + if (i > 0) + { + num_of_keys= part_add_index->num_of_keys; + key_numbers= (uint*) ha_thd()->alloc(sizeof(uint) * num_of_keys); + if (!key_numbers) + { + sql_print_error("Failed with error handling of adding index:\n" + "committing index failed, and when trying to revert " + "already committed partitions we failed allocating\n" + "memory for the index for table '%s'", + table_share->table_name.str); + DBUG_RETURN(HA_ERR_OUT_OF_MEM); + } + old_key_info= table->key_info; + /* + Use the newly added key_info as table->key_info to remove them. + Note that this requires the subhandlers to use name lookup of the + index. They must use given table->key_info[key_number], they cannot + use their local view of the keys, since table->key_info only include + the indexes to be removed here. + */ + for (j= 0; j < num_of_keys; j++) + key_numbers[j]= j; + table->key_info= part_add_index->key_info; + } + + for (j= 0; j < m_tot_parts; j++) + { + if (j < i) + { + /* Remove the newly added index */ + error= m_file[j]->prepare_drop_index(table, key_numbers, num_of_keys); + if (error || m_file[j]->final_drop_index(table)) + { + sql_print_error("Failed with error handling of adding index:\n" + "committing index failed, and when trying to revert " + "already committed partitions we failed removing\n" + "the index for table '%s' partition nr %d", + table_share->table_name.str, j); + } + } + else if (j > i) + { + /* Rollback non finished partitions */ + if (m_file[j]->final_add_index(part_add_index->add_array[j], false)) + { + /* How could this happen? */ + sql_print_error("Failed with error handling of adding index:\n" + "Rollback of add_index failed for table\n" + "'%s' partition nr %d", + table_share->table_name.str, j); + } + } + } + if (i > 0) + table->key_info= old_key_info; + delete part_add_index; + DBUG_RETURN(ret); } int ha_partition::prepare_drop_index(TABLE *table_arg, uint *key_num, diff --git a/sql/handler.h b/sql/handler.h index d1222cb56a6..cbdfc231ed5 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1163,10 +1163,12 @@ uint calculate_key_len(TABLE *, uint, const uchar *, key_part_map); /** Index creation context. - Created by handler::add_index() and freed by handler::final_add_index(). + Created by handler::add_index() and destroyed by handler::final_add_index(). + And finally freed at the end of the statement. + (Sql_alloc does not free in delete). */ -class handler_add_index +class handler_add_index : public Sql_alloc { public: /* Table where the indexes are added */ From 1922d65fd8881836b57ac925596dac4cb753e29b Mon Sep 17 00:00:00 2001 From: Alexander Nozdrin Date: Thu, 22 Sep 2011 18:31:16 +0400 Subject: [PATCH 015/288] Fix for Bug#13001491: MYSQL_REFRESH CRASHES WHEN STORED ROUTINES ARE RUN CONCURRENTLY. The main problem was that lex_start() was forgotten to be called before processing COM_REFRESH. Another problem discovered was that if failures to flush the error log were not properly handled, which resulted in the server crash. The user-visible effect of these problems were: - if COM_REFRESH command was sent after SQL-queries of some sort, the server would crash. - if COM_REFRESH was requested with REFRESH_LOG only, and the error log failed to flush, the server would crash. The error log fails to flush when it points to unavailable file (for example, due to restricted permissions). The fixes are: - call lex_start() in the beginning of COM_REFRESH; - handle failures to flush the error log properly, i.e. raise ER_UNKNOWN_ERROR. sql/sql_parse.cc: Fix for Bug#13001491: MYSQL_REFRESH CRASHES WHEN STORED ROUTINES ARE RUN CONCURRENTLY. tests/mysql_client_test.c: A test case for Bug#13001491: MYSQL_REFRESH CRASHES WHEN STORED ROUTINES ARE RUN CONCURRENTLY. --- sql/sql_parse.cc | 44 ++++++++++++++++++--- tests/mysql_client_test.c | 80 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+), 5 deletions(-) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 2eeabc2f0c1..b5864fef19d 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1491,6 +1491,14 @@ bool dispatch_command(enum enum_server_command command, THD *thd, case COM_REFRESH: { int not_used; + + /* + Initialize thd->lex since it's used in many base functions, such as + open_tables(). Otherwise, it remains unitialized and may cause crash + during execution of COM_REFRESH. + */ + lex_start(thd); + status_var_increment(thd->status_var.com_stat[SQLCOM_FLUSH]); ulong options= (ulong) (uchar) packet[0]; if (check_global_access(thd,RELOAD_ACL)) @@ -6986,7 +6994,14 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, if (ha_flush_logs(NULL)) result=1; if (flush_error_log()) - result=1; + { + /* + When flush_error_log() failed, my_error() has not been called. + So, we have to do it here to keep the protocol. + */ + my_error(ER_UNKNOWN_ERROR, MYF(0)); + result= 1; + } } #ifdef HAVE_QUERY_CACHE if (options & REFRESH_QUERY_CACHE_FREE) @@ -7035,7 +7050,13 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, return 1; // Killed if (close_cached_tables(thd, tables, FALSE, (options & REFRESH_FAST) ? FALSE : TRUE, TRUE)) - result= 1; + { + /* + NOTE: my_error() has been already called by reopen_tables() within + close_cached_tables(). + */ + result= 1; + } if (make_global_read_lock_block_commit(thd)) // Killed { @@ -7048,7 +7069,13 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, { if (close_cached_tables(thd, tables, FALSE, (options & REFRESH_FAST) ? FALSE : TRUE, FALSE)) + { + /* + NOTE: my_error() has been already called by reopen_tables() within + close_cached_tables(). + */ result= 1; + } } my_dbopt_cleanup(); } @@ -7065,7 +7092,8 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, tmp_write_to_binlog= 0; if (reset_master(thd)) { - result=1; + /* NOTE: my_error() has been already called by reset_master(). */ + result= 1; } } #endif @@ -7073,7 +7101,10 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, if (options & REFRESH_DES_KEY_FILE) { if (des_key_file && load_des_key_file(des_key_file)) - result= 1; + { + /* NOTE: my_error() has been already called by load_des_key_file(). */ + result= 1; + } } #endif #ifdef HAVE_REPLICATION @@ -7082,7 +7113,10 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, tmp_write_to_binlog= 0; pthread_mutex_lock(&LOCK_active_mi); if (reset_slave(thd, active_mi)) - result=1; + { + /* NOTE: my_error() has been already called by reset_slave(). */ + result= 1; + } pthread_mutex_unlock(&LOCK_active_mi); } #endif diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 5880e734d32..2472a0b6df6 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -18513,6 +18513,85 @@ static void test_bug56976() DBUG_VOID_RETURN; } +/* + Bug#13001491: MYSQL_REFRESH CRASHES WHEN STORED ROUTINES ARE RUN CONCURRENTLY. +*/ +static void test_bug13001491() +{ + int rc; + char query[MAX_TEST_QUERY_LENGTH]; + MYSQL *c; + + myheader("test_bug13001491"); + + snprintf(query, MAX_TEST_QUERY_LENGTH, + "GRANT ALL PRIVILEGES ON *.* TO mysqltest_u1@%s", + opt_host ? opt_host : "'localhost'"); + + rc= mysql_query(mysql, query); + myquery(rc); + + snprintf(query, MAX_TEST_QUERY_LENGTH, + "GRANT RELOAD ON *.* TO mysqltest_u1@%s", + opt_host ? opt_host : "'localhost'"); + + rc= mysql_query(mysql, query); + myquery(rc); + + c= mysql_client_init(NULL); + + DIE_UNLESS(mysql_real_connect(c, opt_host, "mysqltest_u1", NULL, + current_db, opt_port, opt_unix_socket, + CLIENT_MULTI_STATEMENTS | + CLIENT_MULTI_RESULTS)); + + rc= mysql_query(c, "DROP PROCEDURE IF EXISTS p1"); + myquery(rc); + + rc= mysql_query(c, + "CREATE PROCEDURE p1() " + "BEGIN " + " DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END; " + " SELECT COUNT(*) " + " FROM INFORMATION_SCHEMA.PROCESSLIST " + " GROUP BY user " + " ORDER BY NULL " + " INTO @a; " + "END"); + myquery(rc); + + rc= mysql_query(c, "CALL p1()"); + myquery(rc); + + mysql_free_result(mysql_store_result(c)); + + /* Check that mysql_refresh() succeeds without REFRESH_LOG. */ + rc= mysql_refresh(c, REFRESH_GRANT | + REFRESH_TABLES | REFRESH_HOSTS | + REFRESH_STATUS | REFRESH_THREADS); + myquery(rc); + + /* + Check that mysql_refresh(REFRESH_LOG) does not crash the server even if it + fails. mysql_refresh(REFRESH_LOG) fails when error log points to unavailable + location. + */ + mysql_refresh(c, REFRESH_LOG); + + rc= mysql_query(c, "DROP PROCEDURE p1"); + myquery(rc); + + mysql_close(c); + c= NULL; + + snprintf(query, MAX_TEST_QUERY_LENGTH, + "DROP USER mysqltest_u1@%s", + opt_host ? opt_host : "'localhost'"); + + rc= mysql_query(mysql, query); + myquery(rc); +} + /* Read and parse arguments and MySQL options from my.cnf @@ -18842,6 +18921,7 @@ static struct my_tests_st my_tests[]= { { "test_bug47485", test_bug47485 }, { "test_bug58036", test_bug58036 }, { "test_bug56976", test_bug56976 }, + { "test_bug13001491", test_bug13001491 }, { 0, 0 } }; From deba087af08a53dad962c551fcbd6cf0c0cc5180 Mon Sep 17 00:00:00 2001 From: Joerg Bruehe Date: Wed, 28 Sep 2011 11:43:16 +0200 Subject: [PATCH 016/288] Fix the spec file: Files must not be mentioned twice in a "%files" list. --- support-files/mysql.spec.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index 1442e1b96bd..009d38fde65 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -1002,7 +1002,6 @@ echo "=====" >> $STATUS_HISTORY %doc %attr(644, root, man) %{_mandir}/man1/replace.1* %doc %attr(644, root, man) %{_mandir}/man1/resolve_stack_dump.1* %doc %attr(644, root, man) %{_mandir}/man1/resolveip.1* -%doc %attr(644, root, man) %{_mandir}/man1/mysql_plugin.1* %ghost %config(noreplace,missingok) %{_sysconfdir}/my.cnf @@ -1020,7 +1019,6 @@ echo "=====" >> $STATUS_HISTORY %attr(755, root, root) %{_bindir}/mysql_setpermission %attr(755, root, root) %{_bindir}/mysql_tzinfo_to_sql %attr(755, root, root) %{_bindir}/mysql_upgrade -%attr(755, root, root) %{_bindir}/mysql_plugin %attr(755, root, root) %{_bindir}/mysql_zap %attr(755, root, root) %{_bindir}/mysqlbug %attr(755, root, root) %{_bindir}/mysqld_multi @@ -1131,6 +1129,11 @@ echo "=====" >> $STATUS_HISTORY # merging BK trees) ############################################################################## %changelog +* Wed Sep 28 2011 Joerg Bruehe + +- Fix duplicate mentioning of "mysql_plugin" and its manual page, + it is better to keep alphabetic order in the files list (merging!). + * Tue Sep 13 2011 Jonathan Perkin - Add support for Oracle Linux 6 and Red Hat Enterprise Linux 6. Due to From 8932ae216674f08880a6f914b9651262037175be Mon Sep 17 00:00:00 2001 From: Tatjana Azundris Nuernberg Date: Thu, 29 Sep 2011 10:47:11 +0100 Subject: [PATCH 017/288] Bug#11765687 (MySQL58677): No privilege on table / view, but can know #rows / underlying table's name 1 - If a user had SHOW VIEW and SELECT privileges on a view and this view was referencing another view, EXPLAIN SELECT on the outer view (that the user had privileges on) could reveal the structure of the underlying "inner" view as well as the number of rows in the underlying tables, even if the user had privileges on none of these referenced objects. This happened because we used DEFINER's UID ("SUID") not just for the view given in EXPLAIN, but also when checking privileges on the underlying views (where we should use the UID of the EXPLAIN's INVOKER instead). We no longer run the EXPLAIN SUID (with DEFINER's privileges). This prevents a possible exploit and makes permissions more orthogonal. 2 - EXPLAIN SELECT would reveal a view's structure even if the user did not have SHOW VIEW privileges for that view, as long as they had SELECT privilege on the underlying tables. Instead of requiring both SHOW VIEW privilege on a view and SELECT privilege on all underlying tables, we were checking for presence of either of them. We now explicitly require SHOW VIEW and SELECT privileges on the view we run EXPLAIN SELECT on, as well as all its underlying views. We also require SELECT on all relevant tables. mysql-test/r/view_grant.result: add extensive tests to illustrate desired behavior and prevent regressions (as always). mysql-test/t/view_grant.test: add extensive tests to illustrate desired behavior and prevent regressions (as always). sql/sql_view.cc: We no longer run the EXPLAIN SUID (with DEFINER's privileges). To achieve this, we use a temporary, SUID-less TABLE_LIST for the views while checking privileges. --- mysql-test/r/view_grant.result | 224 +++++++++++++++++++- mysql-test/t/view_grant.test | 368 ++++++++++++++++++++++++++++++++- sql/sql_view.cc | 34 ++- 3 files changed, 608 insertions(+), 18 deletions(-) diff --git a/mysql-test/r/view_grant.result b/mysql-test/r/view_grant.result index e7a50451cec..1febb54fbf4 100644 --- a/mysql-test/r/view_grant.result +++ b/mysql-test/r/view_grant.result @@ -64,10 +64,12 @@ create view mysqltest.v1 (c,d) as select a+1,b+1 from mysqltest.t1; create algorithm=temptable view mysqltest.v2 (c,d) as select a+1,b+1 from mysqltest.t1; create view mysqltest.v3 (c,d) as select a+1,b+1 from mysqltest.t2; create algorithm=temptable view mysqltest.v4 (c,d) as select a+1,b+1 from mysqltest.t2; +create view mysqltest.v5 (c,d) as select a+1,b+1 from mysqltest.t1; grant select on mysqltest.v1 to mysqltest_1@localhost; grant select on mysqltest.v2 to mysqltest_1@localhost; grant select on mysqltest.v3 to mysqltest_1@localhost; grant select on mysqltest.v4 to mysqltest_1@localhost; +grant show view on mysqltest.v5 to mysqltest_1@localhost; select c from mysqltest.v1; c select c from mysqltest.v2; @@ -76,6 +78,8 @@ select c from mysqltest.v3; c select c from mysqltest.v4; c +select c from mysqltest.v5; +ERROR 42000: SELECT command denied to user 'mysqltest_1'@'localhost' for table 'v5' show columns from mysqltest.v1; Field Type Null Key Default Extra c bigint(12) YES NULL @@ -100,16 +104,25 @@ explain select c from mysqltest.v4; ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table show create view mysqltest.v4; ERROR 42000: SHOW VIEW command denied to user 'mysqltest_1'@'localhost' for table 'v4' +explain select c from mysqltest.v5; +ERROR 42000: SELECT command denied to user 'mysqltest_1'@'localhost' for table 'v5' +show create view mysqltest.v5; +View Create View +v5 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest`.`v5` AS select (`mysqltest`.`t1`.`a` + 1) AS `c`,(`mysqltest`.`t1`.`b` + 1) AS `d` from `mysqltest`.`t1` +explain select c from mysqltest.v1; +ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table +show create view mysqltest.v1; +ERROR 42000: SHOW VIEW command denied to user 'mysqltest_1'@'localhost' for table 'v1' +grant show view on mysqltest.v1 to mysqltest_1@localhost; grant select on mysqltest.t1 to mysqltest_1@localhost; explain select c from mysqltest.v1; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 system NULL NULL NULL NULL 0 const row not found show create view mysqltest.v1; -ERROR 42000: SHOW VIEW command denied to user 'mysqltest_1'@'localhost' for table 'v1' +View Create View +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest`.`v1` AS select (`mysqltest`.`t1`.`a` + 1) AS `c`,(`mysqltest`.`t1`.`b` + 1) AS `d` from `mysqltest`.`t1` explain select c from mysqltest.v2; -id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY system NULL NULL NULL NULL 0 const row not found -2 DERIVED NULL NULL NULL NULL NULL NULL NULL no matching row in const table +ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table show create view mysqltest.v2; ERROR 42000: SHOW VIEW command denied to user 'mysqltest_1'@'localhost' for table 'v2' explain select c from mysqltest.v3; @@ -120,6 +133,11 @@ explain select c from mysqltest.v4; ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table show create view mysqltest.v4; ERROR 42000: SHOW VIEW command denied to user 'mysqltest_1'@'localhost' for table 'v4' +explain select c from mysqltest.v5; +ERROR 42000: SELECT command denied to user 'mysqltest_1'@'localhost' for table 'v5' +show create view mysqltest.v5; +View Create View +v5 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest`.`v5` AS select (`mysqltest`.`t1`.`a` + 1) AS `c`,(`mysqltest`.`t1`.`b` + 1) AS `d` from `mysqltest`.`t1` grant show view on mysqltest.* to mysqltest_1@localhost; explain select c from mysqltest.v1; id select_type table type possible_keys key key_len ref rows Extra @@ -135,15 +153,12 @@ show create view mysqltest.v2; View Create View v2 CREATE ALGORITHM=TEMPTABLE DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest`.`v2` AS select (`mysqltest`.`t1`.`a` + 1) AS `c`,(`mysqltest`.`t1`.`b` + 1) AS `d` from `mysqltest`.`t1` explain select c from mysqltest.v3; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 system NULL NULL NULL NULL 0 const row not found +ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table show create view mysqltest.v3; View Create View v3 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest`.`v3` AS select (`mysqltest`.`t2`.`a` + 1) AS `c`,(`mysqltest`.`t2`.`b` + 1) AS `d` from `mysqltest`.`t2` explain select c from mysqltest.v4; -id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY system NULL NULL NULL NULL 0 const row not found -2 DERIVED NULL NULL NULL NULL NULL NULL NULL no matching row in const table +ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table show create view mysqltest.v4; View Create View v4 CREATE ALGORITHM=TEMPTABLE DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest`.`v4` AS select (`mysqltest`.`t2`.`a` + 1) AS `c`,(`mysqltest`.`t2`.`b` + 1) AS `d` from `mysqltest`.`t2` @@ -945,4 +960,195 @@ DROP USER foo; DROP VIEW db1.v1; DROP TABLE db1.t1; DROP DATABASE db1; +Bug #11765687/#58677: +No privilege on table/view, but can know #rows / underlying table's name +create database mysqltest1; +create table mysqltest1.t1 (i int); +create table mysqltest1.t2 (j int); +create table mysqltest1.t3 (k int, secret int); +create user alice@localhost; +create user bob@localhost; +create user cecil@localhost; +create user dan@localhost; +create user eugene@localhost; +create user fiona@localhost; +create user greg@localhost; +create user han@localhost; +create user inga@localhost; +create user jamie@localhost; +create user karl@localhost; +create user lena@localhost; +create user mhairi@localhost; +create user noam@localhost; +create user olga@localhost; +create user pjotr@localhost; +create user quintessa@localhost; +grant all privileges on mysqltest1.* to alice@localhost with grant option; +... as alice +create view v1 as select * from t1; +create view v2 as select * from v1, t2; +create view v3 as select k from t3; +grant select on mysqltest1.v1 to bob@localhost; +grant show view on mysqltest1.v1 to cecil@localhost; +grant select, show view on mysqltest1.v1 to dan@localhost; +grant select on mysqltest1.t1 to dan@localhost; +grant select on mysqltest1.* to eugene@localhost; +grant select, show view on mysqltest1.v2 to fiona@localhost; +grant select, show view on mysqltest1.v2 to greg@localhost; +grant show view on mysqltest1.v1 to greg@localhost; +grant select(k) on mysqltest1.t3 to han@localhost; +grant select, show view on mysqltest1.v3 to han@localhost; +grant select on mysqltest1.t1 to inga@localhost; +grant select on mysqltest1.t2 to inga@localhost; +grant select on mysqltest1.v1 to inga@localhost; +grant select, show view on mysqltest1.v2 to inga@localhost; +grant select on mysqltest1.t1 to jamie@localhost; +grant select on mysqltest1.t2 to jamie@localhost; +grant show view on mysqltest1.v1 to jamie@localhost; +grant select, show view on mysqltest1.v2 to jamie@localhost; +grant select on mysqltest1.t1 to karl@localhost; +grant select on mysqltest1.t2 to karl@localhost; +grant select, show view on mysqltest1.v1 to karl@localhost; +grant select on mysqltest1.v2 to karl@localhost; +grant select on mysqltest1.t1 to lena@localhost; +grant select on mysqltest1.t2 to lena@localhost; +grant select, show view on mysqltest1.v1 to lena@localhost; +grant show view on mysqltest1.v2 to lena@localhost; +grant select on mysqltest1.t1 to mhairi@localhost; +grant select on mysqltest1.t2 to mhairi@localhost; +grant select, show view on mysqltest1.v1 to mhairi@localhost; +grant select, show view on mysqltest1.v2 to mhairi@localhost; +grant select on mysqltest1.t1 to noam@localhost; +grant select, show view on mysqltest1.v1 to noam@localhost; +grant select, show view on mysqltest1.v2 to noam@localhost; +grant select on mysqltest1.t2 to olga@localhost; +grant select, show view on mysqltest1.v1 to olga@localhost; +grant select, show view on mysqltest1.v2 to olga@localhost; +grant select on mysqltest1.t1 to pjotr@localhost; +grant select on mysqltest1.t2 to pjotr@localhost; +grant select, show view on mysqltest1.v2 to pjotr@localhost; +grant select, show view on mysqltest1.v1 to quintessa@localhost; +... as bob +select * from v1; +i +explain select * from v1; +ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table +... as cecil +select * from v1; +ERROR 42000: SELECT command denied to user 'cecil'@'localhost' for table 'v1' +explain select * from v1; +ERROR 42000: SELECT command denied to user 'cecil'@'localhost' for table 'v1' +... as dan +select * from v1; +i +explain select * from v1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 system NULL NULL NULL NULL 0 const row not found +... as eugene +select * from v1; +i +explain select * from v1; +ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table +... as fiona +select * from v2; +i j +show create view v2; +View Create View +v2 CREATE ALGORITHM=UNDEFINED DEFINER=`alice`@`localhost` SQL SECURITY DEFINER VIEW `v2` AS select `v1`.`i` AS `i`,`t2`.`j` AS `j` from (`v1` join `t2`) +explain select * from t1; +ERROR 42000: SELECT command denied to user 'fiona'@'localhost' for table 't1' +explain select * from v1; +ERROR 42000: SELECT command denied to user 'fiona'@'localhost' for table 'v1' +explain select * from t2; +ERROR 42000: SELECT command denied to user 'fiona'@'localhost' for table 't2' +explain select * from v2; +ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table +... as greg +select * from v2; +i j +explain select * from v1; +ERROR 42000: SELECT command denied to user 'greg'@'localhost' for table 'v1' +explain select * from v2; +ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table +... as han +select * from t3; +ERROR 42000: SELECT command denied to user 'han'@'localhost' for table 't3' +explain select * from t3; +ERROR 42000: SELECT command denied to user 'han'@'localhost' for table 't3' +select k from t3; +k +explain select k from t3; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t3 system NULL NULL NULL NULL 0 const row not found +select * from v3; +k +explain select * from v3; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t3 system NULL NULL NULL NULL 0 const row not found +... as inga +select * from v2; +i j +explain select * from v2; +ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table +... as jamie +select * from v2; +i j +explain select * from v2; +ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table +... as karl +select * from v2; +i j +explain select * from v2; +ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table +... as lena +select * from v2; +ERROR 42000: SELECT command denied to user 'lena'@'localhost' for table 'v2' +explain select * from v2; +ERROR 42000: SELECT command denied to user 'lena'@'localhost' for table 'v2' +... as mhairi +select * from v2; +i j +explain select * from v2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 system NULL NULL NULL NULL 0 const row not found +1 SIMPLE t2 system NULL NULL NULL NULL 0 const row not found +... as noam +select * from v2; +i j +explain select * from v2; +ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table +... as olga +select * from v2; +i j +explain select * from v2; +ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table +... as pjotr +select * from v2; +i j +explain select * from v2; +ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table +... as quintessa +select * from v1; +i +explain select * from v1; +ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table +... as root again at last: clean-up time! +drop user alice@localhost; +drop user bob@localhost; +drop user cecil@localhost; +drop user dan@localhost; +drop user eugene@localhost; +drop user fiona@localhost; +drop user greg@localhost; +drop user han@localhost; +drop user inga@localhost; +drop user jamie@localhost; +drop user karl@localhost; +drop user lena@localhost; +drop user mhairi@localhost; +drop user noam@localhost; +drop user olga@localhost; +drop user pjotr@localhost; +drop user quintessa@localhost; +drop database mysqltest1; End of 5.0 tests. diff --git a/mysql-test/t/view_grant.test b/mysql-test/t/view_grant.test index ff17cde5184..f06f0d58c8a 100644 --- a/mysql-test/t/view_grant.test +++ b/mysql-test/t/view_grant.test @@ -121,21 +121,26 @@ create view mysqltest.v1 (c,d) as select a+1,b+1 from mysqltest.t1; create algorithm=temptable view mysqltest.v2 (c,d) as select a+1,b+1 from mysqltest.t1; create view mysqltest.v3 (c,d) as select a+1,b+1 from mysqltest.t2; create algorithm=temptable view mysqltest.v4 (c,d) as select a+1,b+1 from mysqltest.t2; +# v5: SHOW VIEW, but no SELECT +create view mysqltest.v5 (c,d) as select a+1,b+1 from mysqltest.t1; grant select on mysqltest.v1 to mysqltest_1@localhost; grant select on mysqltest.v2 to mysqltest_1@localhost; grant select on mysqltest.v3 to mysqltest_1@localhost; grant select on mysqltest.v4 to mysqltest_1@localhost; +grant show view on mysqltest.v5 to mysqltest_1@localhost; connection user1; -# all selects works +# all SELECTs works, except v5 which lacks SELECT privs select c from mysqltest.v1; select c from mysqltest.v2; select c from mysqltest.v3; select c from mysqltest.v4; +--error ER_TABLEACCESS_DENIED_ERROR +select c from mysqltest.v5; # test of show coluns show columns from mysqltest.v1; show columns from mysqltest.v2; -# but explain/show do not +# explain/show fail --error ER_VIEW_NO_EXPLAIN explain select c from mysqltest.v1; --error ER_TABLEACCESS_DENIED_ERROR @@ -152,15 +157,26 @@ show create view mysqltest.v3; explain select c from mysqltest.v4; --error ER_TABLEACCESS_DENIED_ERROR show create view mysqltest.v4; +--error ER_TABLEACCESS_DENIED_ERROR +explain select c from mysqltest.v5; +show create view mysqltest.v5; -# allow to see one of underlying table -connection root; -grant select on mysqltest.t1 to mysqltest_1@localhost; -connection user1; -# EXPLAIN of view on above table works +# missing SELECT on underlying t1, no SHOW VIEW on v1 either. +--error ER_VIEW_NO_EXPLAIN explain select c from mysqltest.v1; +# missing SHOW VIEW --error ER_TABLEACCESS_DENIED_ERROR show create view mysqltest.v1; +# allow to see one of underlying table +connection root; +grant show view on mysqltest.v1 to mysqltest_1@localhost; +grant select on mysqltest.t1 to mysqltest_1@localhost; +connection user1; +# EXPLAIN works +explain select c from mysqltest.v1; +show create view mysqltest.v1; +# missing SHOW VIEW +--error ER_VIEW_NO_EXPLAIN explain select c from mysqltest.v2; --error ER_TABLEACCESS_DENIED_ERROR show create view mysqltest.v2; @@ -173,6 +189,11 @@ show create view mysqltest.v3; explain select c from mysqltest.v4; --error ER_TABLEACCESS_DENIED_ERROR show create view mysqltest.v4; +# we have SHOW VIEW on v5, and SELECT on t1 -- not enough +--error ER_TABLEACCESS_DENIED_ERROR +explain select c from mysqltest.v5; +# we can SHOW CREATE VIEW though +show create view mysqltest.v5; # allow to see any view in mysqltest database connection root; @@ -182,8 +203,12 @@ explain select c from mysqltest.v1; show create view mysqltest.v1; explain select c from mysqltest.v2; show create view mysqltest.v2; +# have SHOW VIEW | SELECT on v3, but no SELECT on t2 +--error ER_VIEW_NO_EXPLAIN explain select c from mysqltest.v3; show create view mysqltest.v3; +# have SHOW VIEW | SELECT on v4, but no SELECT on t2 +--error ER_VIEW_NO_EXPLAIN explain select c from mysqltest.v4; show create view mysqltest.v4; @@ -1232,7 +1257,336 @@ DROP TABLE db1.t1; DROP DATABASE db1; connection default; + + +--echo Bug #11765687/#58677: +--echo No privilege on table/view, but can know #rows / underlying table's name + +# As a root-like user +connect (root,localhost,root,,test); +connection root; + +create database mysqltest1; +create table mysqltest1.t1 (i int); +create table mysqltest1.t2 (j int); +create table mysqltest1.t3 (k int, secret int); + +create user alice@localhost; +create user bob@localhost; +create user cecil@localhost; +create user dan@localhost; +create user eugene@localhost; +create user fiona@localhost; +create user greg@localhost; +create user han@localhost; +create user inga@localhost; +create user jamie@localhost; +create user karl@localhost; +create user lena@localhost; +create user mhairi@localhost; +create user noam@localhost; +create user olga@localhost; +create user pjotr@localhost; +create user quintessa@localhost; + +grant all privileges on mysqltest1.* to alice@localhost with grant option; + +# +--echo ... as alice +connect (test11765687,localhost,alice,,mysqltest1); +connection test11765687; + +create view v1 as select * from t1; +create view v2 as select * from v1, t2; +create view v3 as select k from t3; + +grant select on mysqltest1.v1 to bob@localhost; + +grant show view on mysqltest1.v1 to cecil@localhost; + +grant select, show view on mysqltest1.v1 to dan@localhost; +grant select on mysqltest1.t1 to dan@localhost; + +grant select on mysqltest1.* to eugene@localhost; + +grant select, show view on mysqltest1.v2 to fiona@localhost; + +grant select, show view on mysqltest1.v2 to greg@localhost; +grant show view on mysqltest1.v1 to greg@localhost; + +grant select(k) on mysqltest1.t3 to han@localhost; +grant select, show view on mysqltest1.v3 to han@localhost; + +grant select on mysqltest1.t1 to inga@localhost; +grant select on mysqltest1.t2 to inga@localhost; +grant select on mysqltest1.v1 to inga@localhost; +grant select, show view on mysqltest1.v2 to inga@localhost; + +grant select on mysqltest1.t1 to jamie@localhost; +grant select on mysqltest1.t2 to jamie@localhost; +grant show view on mysqltest1.v1 to jamie@localhost; +grant select, show view on mysqltest1.v2 to jamie@localhost; + +grant select on mysqltest1.t1 to karl@localhost; +grant select on mysqltest1.t2 to karl@localhost; +grant select, show view on mysqltest1.v1 to karl@localhost; +grant select on mysqltest1.v2 to karl@localhost; + +grant select on mysqltest1.t1 to lena@localhost; +grant select on mysqltest1.t2 to lena@localhost; +grant select, show view on mysqltest1.v1 to lena@localhost; +grant show view on mysqltest1.v2 to lena@localhost; + +grant select on mysqltest1.t1 to mhairi@localhost; +grant select on mysqltest1.t2 to mhairi@localhost; +grant select, show view on mysqltest1.v1 to mhairi@localhost; +grant select, show view on mysqltest1.v2 to mhairi@localhost; + +grant select on mysqltest1.t1 to noam@localhost; +grant select, show view on mysqltest1.v1 to noam@localhost; +grant select, show view on mysqltest1.v2 to noam@localhost; + +grant select on mysqltest1.t2 to olga@localhost; +grant select, show view on mysqltest1.v1 to olga@localhost; +grant select, show view on mysqltest1.v2 to olga@localhost; + +grant select on mysqltest1.t1 to pjotr@localhost; +grant select on mysqltest1.t2 to pjotr@localhost; +grant select, show view on mysqltest1.v2 to pjotr@localhost; + +grant select, show view on mysqltest1.v1 to quintessa@localhost; + +disconnect test11765687; + +# +--echo ... as bob +connect (test11765687,localhost,bob,,mysqltest1); +connection test11765687; + +select * from v1; # Should succeed. +--error ER_VIEW_NO_EXPLAIN +explain select * from v1; # fail, no SHOW_VIEW + +disconnect test11765687; + +# +--echo ... as cecil +connect (test11765687,localhost,cecil,,mysqltest1); +connection test11765687; + +--error ER_TABLEACCESS_DENIED_ERROR +select * from v1; # fail, no SELECT +--error ER_TABLEACCESS_DENIED_ERROR +explain select * from v1; # fail, no SELECT + +disconnect test11765687; + +# +--echo ... as dan +connect (test11765687,localhost,dan,,mysqltest1); +connection test11765687; + +select * from v1; # Should succeed. +explain select * from v1; # Should succeed. + +disconnect test11765687; + +# +--echo ... as eugene +connect (test11765687,localhost,eugene,,mysqltest1); +connection test11765687; + +select * from v1; # Should succeed. +--error ER_VIEW_NO_EXPLAIN +explain select * from v1; # fail, no SHOW_VIEW + +disconnect test11765687; + +# +--echo ... as fiona +connect (test11765687,localhost,fiona,,mysqltest1); +connection test11765687; + +select * from v2; # Should succeed. +show create view v2; # Should succeed, but... +--error ER_TABLEACCESS_DENIED_ERROR +explain select * from t1; # fail, shouldn't see t1! +--error ER_TABLEACCESS_DENIED_ERROR +# err msg must give view name, no table names!! +explain select * from v1; # fail, have no privs on v1! +--error ER_TABLEACCESS_DENIED_ERROR +explain select * from t2; # fail, have no privs on t2! +--error ER_VIEW_NO_EXPLAIN +explain select * from v2; # fail, shouldn't see t2! + +disconnect test11765687; + +# +--echo ... as greg +connect (test11765687,localhost,greg,,mysqltest1); +connection test11765687; + +select * from v2; # Should succeed. +--error ER_TABLEACCESS_DENIED_ERROR +explain select * from v1; # fail; no SELECT on v1! +--error ER_VIEW_NO_EXPLAIN +explain select * from v2; # fail; no SELECT on v1! + +disconnect test11765687; + +# +--echo ... as han +connect (test11765687,localhost,han,,mysqltest1); +connection test11765687; + +--error ER_TABLEACCESS_DENIED_ERROR +select * from t3; # don't have privs on all columns, +--error ER_TABLEACCESS_DENIED_ERROR +explain select * from t3; # so EXPLAIN on "forbidden" columns should fail. +select k from t3; # but we do have SELECT on column k though, +explain select k from t3; # so EXPLAIN just on k should work, +select * from v3; # and so should SELECT on view only using allowed columns +explain select * from v3; # as should the associated EXPLAIN + +disconnect test11765687; + +# +--echo ... as inga +connect (test11765687,localhost,inga,,mysqltest1); +connection test11765687; + +select * from v2; +# has sel/show on v2, sel on t1/t2, only sel v1 +# fail: lacks show on v1 +--error ER_VIEW_NO_EXPLAIN +explain select * from v2; +disconnect test11765687; + +# +--echo ... as jamie +connect (test11765687,localhost,jamie,,mysqltest1); +connection test11765687; + +select * from v2; +# has sel/show on v2, sel on t1/t2, only show v1 +# fail: lacks sel on v1 +--error ER_VIEW_NO_EXPLAIN +explain select * from v2; +disconnect test11765687; + +# +--echo ... as karl +connect (test11765687,localhost,karl,,mysqltest1); +connection test11765687; + +select * from v2; +# has sel only on v2, sel on t1/t2, sel/show v1 +# fail: lacks show on v2 +--error ER_VIEW_NO_EXPLAIN +explain select * from v2; +disconnect test11765687; + +# +--echo ... as lena + +connect (test11765687,localhost,lena,,mysqltest1); +connection test11765687; +--error ER_TABLEACCESS_DENIED_ERROR +select * from v2; +# has show only on v2, sel on t1/t2, sel/show v1 +# fail: lacks sel on v2 +--error ER_TABLEACCESS_DENIED_ERROR +explain select * from v2; +disconnect test11765687; + +# +--echo ... as mhairi +connect (test11765687,localhost,mhairi,,mysqltest1); +connection test11765687; + +select * from v2; +# has sel/show on v2, sel on t1/t2, sel/show v1 +explain select * from v2; +disconnect test11765687; + +# +--echo ... as noam +connect (test11765687,localhost,noam,,mysqltest1); +connection test11765687; + +select * from v2; +# has sel/show on v2, sel only on t1, sel/show v1 (no sel on t2!) +--error ER_VIEW_NO_EXPLAIN +explain select * from v2; +disconnect test11765687; + +# +--echo ... as olga +connect (test11765687,localhost,olga,,mysqltest1); +connection test11765687; + +select * from v2; +# has sel/show on v2, sel only on t2, sel/show v1 (no sel on t1!) +--error ER_VIEW_NO_EXPLAIN +explain select * from v2; +disconnect test11765687; + +# +--echo ... as pjotr +connect (test11765687,localhost,pjotr,,mysqltest1); +connection test11765687; + +select * from v2; +# has sel/show on v2, sel only on t2, nothing on v1 +# fail: lacks show on v1 +--error ER_VIEW_NO_EXPLAIN +explain select * from v2; +disconnect test11765687; + +# +--echo ... as quintessa +connect (test11765687,localhost,quintessa,,mysqltest1); +connection test11765687; + +select * from v1; # Should succeed. +--error ER_VIEW_NO_EXPLAIN +explain select * from v1; # fail: lacks select on t1 + +disconnect test11765687; + +# cleanup + +# +--echo ... as root again at last: clean-up time! +connection root; + +drop user alice@localhost; +drop user bob@localhost; +drop user cecil@localhost; +drop user dan@localhost; +drop user eugene@localhost; +drop user fiona@localhost; +drop user greg@localhost; +drop user han@localhost; +drop user inga@localhost; +drop user jamie@localhost; +drop user karl@localhost; +drop user lena@localhost; +drop user mhairi@localhost; +drop user noam@localhost; +drop user olga@localhost; +drop user pjotr@localhost; +drop user quintessa@localhost; + +drop database mysqltest1; + +disconnect root; + +connection default; + --echo End of 5.0 tests. + + # Wait till we reached the initial number of concurrent sessions --source include/wait_until_count_sessions.inc diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 07580663f24..c318f79eec1 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -1148,8 +1148,38 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table, if (!table->prelocking_placeholder && (old_lex->sql_command == SQLCOM_SELECT && old_lex->describe)) { - if (check_table_access(thd, SELECT_ACL, view_tables, 1) && - check_table_access(thd, SHOW_VIEW_ACL, table, 1)) + /* + The user we run EXPLAIN as (either the connected user who issued + the EXPLAIN statement, or the definer of a SUID stored routine + which contains the EXPLAIN) should have both SHOW_VIEW_ACL and + SELECT_ACL on the view being opened as well as on all underlying + views since EXPLAIN will disclose their structure. This user also + should have SELECT_ACL on all underlying tables of the view since + this EXPLAIN will disclose information about the number of rows in it. + + To perform this privilege check we create auxiliary TABLE_LIST object + for the view in order a) to avoid trashing "table->grant" member for + original table list element, which contents can be important at later + stage for column-level privilege checking b) get TABLE_LIST object + with "security_ctx" member set to 0, i.e. forcing check_table_access() + to use active user's security context. + + There is no need for creating similar copies of table list elements + for underlying tables since they are just have been constructed and + thus have TABLE_LIST::security_ctx == 0 and fresh TABLE_LIST::grant + member. + + Finally at this point making sure we have SHOW_VIEW_ACL on the views + will suffice as we implicitly require SELECT_ACL anyway. + */ + + TABLE_LIST view; + bzero((char *)&view, sizeof(TABLE_LIST)); + view.db= table->db; + view.table_name= table->table_name; + + if (check_table_access(thd, SELECT_ACL, view_tables, 1) || + check_table_access(thd, SHOW_VIEW_ACL, &view, 1)) { my_message(ER_VIEW_NO_EXPLAIN, ER(ER_VIEW_NO_EXPLAIN), MYF(0)); goto err; From fdfea7a8180ef5d97d61038bcec75fed6f892fbc Mon Sep 17 00:00:00 2001 From: Joerg Bruehe Date: Fri, 30 Sep 2011 13:27:29 +0200 Subject: [PATCH 018/288] Transferring a change from main 5.5 into the 5.5.17 build: | revision-id: rafal.somla@oracle.com-20110929150216-jl3y54s54w04y2vu | parent: marko.makela@oracle.com-20110929123146-03lcg1vixncyviyn | committer: Rafal Somla | branch nick: bug12982926 | timestamp: Thu 2011-09-29 17:02:16 +0200 | message: | Bug#12982926 CLIENT CAN OVERRIDE ZERO-LENGTH-ALLOCATE BUFFER | | Changes in client plugin needed for testing the issue (test instrumentation). --- libmysql/authentication_win/handshake_client.cc | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/libmysql/authentication_win/handshake_client.cc b/libmysql/authentication_win/handshake_client.cc index 565726651cb..02e5483da29 100644 --- a/libmysql/authentication_win/handshake_client.cc +++ b/libmysql/authentication_win/handshake_client.cc @@ -161,6 +161,21 @@ int Handshake_client::write_packet(Blob &data) keep all the data. */ unsigned block_count= data.len()/512 + ((data.len() % 512) ? 1 : 0); + +#if !defined(DBUG_OFF) && defined(WINAUTH_USE_DBUG_LIB) + + /* + For testing purposes, use wrong block count to see how server + handles this. + */ + DBUG_EXECUTE_IF("winauth_first_packet_test",{ + block_count= data.len() == 601 ? 0 : + data.len() == 602 ? 1 : + block_count; + }); + +#endif + DBUG_ASSERT(block_count < (unsigned)0x100); saved_byte= data[254]; data[254] = block_count; From 3fb8fe5eb27356c147ac39ae18de3d3e682918b8 Mon Sep 17 00:00:00 2001 From: Joerg Bruehe Date: Fri, 30 Sep 2011 13:37:22 +0200 Subject: [PATCH 019/288] Transferring a change from main 5.5 into the 5.5.17 build: | revision-id: inaam.rana@oracle.com-20110930110219-vnpaqghj9hm0grds | parent: rohit.kalhans@oracle.com-20110930094635-hjhrv55tg6z6pz7y | committer: Inaam Rana | branch nick: mysql-5.5 | timestamp: Fri 2011-09-30 07:02:19 -0400 | message: | Revert original fix for Bug 12612184 and the follow up fix for | Bug 12704861. | | Bug 12704861 fix was revno: 3504.1.1 (rb://693) | Bug 12612184 fix was revno: 3445.1.10 (rb://678) --- storage/innobase/btr/btr0btr.c | 272 ++++---------------------- storage/innobase/btr/btr0cur.c | 140 ++++--------- storage/innobase/buf/buf0buf.c | 25 +++ storage/innobase/fsp/fsp0fsp.c | 234 +++++++++------------- storage/innobase/include/btr0btr.h | 49 +---- storage/innobase/include/btr0cur.h | 44 ++--- storage/innobase/include/btr0cur.ic | 4 +- storage/innobase/include/buf0buf.h | 36 +--- storage/innobase/include/buf0buf.ic | 17 +- storage/innobase/include/fsp0fsp.h | 30 ++- storage/innobase/include/mtr0mtr.h | 15 +- storage/innobase/include/mtr0mtr.ic | 8 +- storage/innobase/include/page0cur.ic | 5 +- storage/innobase/include/page0page.h | 39 +--- storage/innobase/include/page0page.ic | 32 +-- storage/innobase/include/rem0rec.h | 4 +- storage/innobase/include/rem0rec.ic | 4 +- storage/innobase/include/sync0rw.ic | 10 +- storage/innobase/include/sync0sync.h | 6 +- storage/innobase/include/univ.i | 5 +- storage/innobase/mtr/mtr0mtr.c | 7 +- storage/innobase/page/page0cur.c | 17 +- storage/innobase/page/page0page.c | 52 ++--- storage/innobase/row/row0ins.c | 61 +----- storage/innobase/row/row0row.c | 28 +-- storage/innobase/row/row0upd.c | 40 ++-- storage/innobase/row/row0vers.c | 16 +- storage/innobase/sync/sync0rw.c | 4 +- storage/innobase/sync/sync0sync.c | 12 +- storage/innobase/trx/trx0rec.c | 4 +- storage/innobase/trx/trx0undo.c | 4 +- 31 files changed, 366 insertions(+), 858 deletions(-) diff --git a/storage/innobase/btr/btr0btr.c b/storage/innobase/btr/btr0btr.c index 6a6f0025fa5..b476167af29 100644 --- a/storage/innobase/btr/btr0btr.c +++ b/storage/innobase/btr/btr0btr.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1994, 2010, Innobase Oy. 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 @@ -906,29 +906,28 @@ btr_page_alloc_for_ibuf( /**************************************************************//** Allocates a new file page to be used in an index tree. NOTE: we assume that the caller has made the reservation for free extents! -@return allocated page number, FIL_NULL if out of space */ -static __attribute__((nonnull(1,5), warn_unused_result)) -ulint -btr_page_alloc_low( -/*===============*/ +@return new allocated block, x-latched; NULL if out of space */ +UNIV_INTERN +buf_block_t* +btr_page_alloc( +/*===========*/ dict_index_t* index, /*!< in: index */ ulint hint_page_no, /*!< in: hint of a good page */ byte file_direction, /*!< in: direction where a possible page split is made */ ulint level, /*!< in: level where the page is placed in the tree */ - mtr_t* mtr, /*!< in/out: mini-transaction - for the allocation */ - mtr_t* init_mtr) /*!< in/out: mini-transaction - in which the page should be - initialized (may be the same - as mtr), or NULL if it should - not be initialized (the page - at hint was previously freed - in mtr) */ + mtr_t* mtr) /*!< in: mtr */ { fseg_header_t* seg_header; page_t* root; + buf_block_t* new_block; + ulint new_page_no; + + if (dict_index_is_ibuf(index)) { + + return(btr_page_alloc_for_ibuf(index, mtr)); + } root = btr_root_get(index, mtr); @@ -942,42 +941,8 @@ btr_page_alloc_low( reservation for free extents, and thus we know that a page can be allocated: */ - return(fseg_alloc_free_page_general( - seg_header, hint_page_no, file_direction, - TRUE, mtr, init_mtr)); -} - -/**************************************************************//** -Allocates a new file page to be used in an index tree. NOTE: we assume -that the caller has made the reservation for free extents! -@return new allocated block, x-latched; NULL if out of space */ -UNIV_INTERN -buf_block_t* -btr_page_alloc( -/*===========*/ - dict_index_t* index, /*!< in: index */ - ulint hint_page_no, /*!< in: hint of a good page */ - byte file_direction, /*!< in: direction where a possible - page split is made */ - ulint level, /*!< in: level where the page is placed - in the tree */ - mtr_t* mtr, /*!< in/out: mini-transaction - for the allocation */ - mtr_t* init_mtr) /*!< in/out: mini-transaction - for x-latching and initializing - the page */ -{ - buf_block_t* new_block; - ulint new_page_no; - - if (dict_index_is_ibuf(index)) { - - return(btr_page_alloc_for_ibuf(index, mtr)); - } - - new_page_no = btr_page_alloc_low( - index, hint_page_no, file_direction, level, mtr, init_mtr); - + new_page_no = fseg_alloc_free_page_general(seg_header, hint_page_no, + file_direction, TRUE, mtr); if (new_page_no == FIL_NULL) { return(NULL); @@ -985,16 +950,9 @@ btr_page_alloc( new_block = buf_page_get(dict_index_get_space(index), dict_table_zip_size(index->table), - new_page_no, RW_X_LATCH, init_mtr); + new_page_no, RW_X_LATCH, mtr); buf_block_dbg_add_level(new_block, SYNC_TREE_NODE_NEW); - if (mtr->freed_clust_leaf) { - mtr_memo_release(mtr, new_block, MTR_MEMO_FREE_CLUST_LEAF); - ut_ad(!mtr_memo_contains(mtr, new_block, - MTR_MEMO_FREE_CLUST_LEAF)); - } - - ut_ad(btr_freed_leaves_validate(mtr)); return(new_block); } @@ -1107,15 +1065,6 @@ btr_page_free_low( fseg_free_page(seg_header, buf_block_get_space(block), buf_block_get_page_no(block), mtr); - - /* The page was marked free in the allocation bitmap, but it - should remain buffer-fixed until mtr_commit(mtr) or until it - is explicitly freed from the mini-transaction. */ - ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); - /* TODO: Discard any operations on the page from the redo log - and remove the block from the flush list and the buffer pool. - This would free up buffer pool earlier and reduce writes to - both the tablespace and the redo log. */ } /**************************************************************//** @@ -1129,140 +1078,13 @@ btr_page_free( buf_block_t* block, /*!< in: block to be freed, x-latched */ mtr_t* mtr) /*!< in: mtr */ { - const page_t* page = buf_block_get_frame(block); - ulint level = btr_page_get_level(page, mtr); + ulint level; + + level = btr_page_get_level(buf_block_get_frame(block), mtr); - ut_ad(fil_page_get_type(block->frame) == FIL_PAGE_INDEX); btr_page_free_low(index, block, level, mtr); - - /* The handling of MTR_MEMO_FREE_CLUST_LEAF assumes this. */ - ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); - - if (level == 0 && dict_index_is_clust(index)) { - /* We may have to call btr_mark_freed_leaves() to - temporarily mark the block nonfree for invoking - btr_store_big_rec_extern_fields_func() after an - update. Remember that the block was freed. */ - mtr->freed_clust_leaf = TRUE; - mtr_memo_push(mtr, block, MTR_MEMO_FREE_CLUST_LEAF); - } - - ut_ad(btr_freed_leaves_validate(mtr)); } -/**************************************************************//** -Marks all MTR_MEMO_FREE_CLUST_LEAF pages nonfree or free. -For invoking btr_store_big_rec_extern_fields() after an update, -we must temporarily mark freed clustered index pages allocated, so -that off-page columns will not be allocated from them. Between the -btr_store_big_rec_extern_fields() and mtr_commit() we have to -mark the pages free again, so that no pages will be leaked. */ -UNIV_INTERN -void -btr_mark_freed_leaves( -/*==================*/ - dict_index_t* index, /*!< in/out: clustered index */ - mtr_t* mtr, /*!< in/out: mini-transaction */ - ibool nonfree)/*!< in: TRUE=mark nonfree, FALSE=mark freed */ -{ - /* This is loosely based on mtr_memo_release(). */ - - ulint offset; - - ut_ad(dict_index_is_clust(index)); - ut_ad(mtr->magic_n == MTR_MAGIC_N); - ut_ad(mtr->state == MTR_ACTIVE); - - if (!mtr->freed_clust_leaf) { - return; - } - - offset = dyn_array_get_data_size(&mtr->memo); - - while (offset > 0) { - mtr_memo_slot_t* slot; - buf_block_t* block; - - offset -= sizeof *slot; - - slot = dyn_array_get_element(&mtr->memo, offset); - - if (slot->type != MTR_MEMO_FREE_CLUST_LEAF) { - continue; - } - - /* Because btr_page_alloc() does invoke - mtr_memo_release on MTR_MEMO_FREE_CLUST_LEAF, all - blocks tagged with MTR_MEMO_FREE_CLUST_LEAF in the - memo must still be clustered index leaf tree pages. */ - block = slot->object; - ut_a(buf_block_get_space(block) - == dict_index_get_space(index)); - ut_a(fil_page_get_type(buf_block_get_frame(block)) - == FIL_PAGE_INDEX); - ut_a(page_is_leaf(buf_block_get_frame(block))); - - if (nonfree) { - /* Allocate the same page again. */ - ulint page_no; - page_no = btr_page_alloc_low( - index, buf_block_get_page_no(block), - FSP_NO_DIR, 0, mtr, NULL); - ut_a(page_no == buf_block_get_page_no(block)); - } else { - /* Assert that the page is allocated and free it. */ - btr_page_free_low(index, block, 0, mtr); - } - } - - ut_ad(btr_freed_leaves_validate(mtr)); -} - -#ifdef UNIV_DEBUG -/**************************************************************//** -Validates all pages marked MTR_MEMO_FREE_CLUST_LEAF. -@see btr_mark_freed_leaves() -@return TRUE */ -UNIV_INTERN -ibool -btr_freed_leaves_validate( -/*======================*/ - mtr_t* mtr) /*!< in: mini-transaction */ -{ - ulint offset; - - ut_ad(mtr->magic_n == MTR_MAGIC_N); - ut_ad(mtr->state == MTR_ACTIVE); - - offset = dyn_array_get_data_size(&mtr->memo); - - while (offset > 0) { - const mtr_memo_slot_t* slot; - const buf_block_t* block; - - offset -= sizeof *slot; - - slot = dyn_array_get_element(&mtr->memo, offset); - - if (slot->type != MTR_MEMO_FREE_CLUST_LEAF) { - continue; - } - - ut_a(mtr->freed_clust_leaf); - /* Because btr_page_alloc() does invoke - mtr_memo_release on MTR_MEMO_FREE_CLUST_LEAF, all - blocks tagged with MTR_MEMO_FREE_CLUST_LEAF in the - memo must still be clustered index leaf tree pages. */ - block = slot->object; - ut_a(fil_page_get_type(buf_block_get_frame(block)) - == FIL_PAGE_INDEX); - ut_a(page_is_leaf(buf_block_get_frame(block))); - } - - return(TRUE); -} -#endif /* UNIV_DEBUG */ - /**************************************************************//** Sets the child node file address in a node pointer. */ UNIV_INLINE @@ -1987,7 +1809,7 @@ btr_root_raise_and_insert( level = btr_page_get_level(root, mtr); - new_block = btr_page_alloc(index, 0, FSP_NO_DIR, level, mtr, mtr); + new_block = btr_page_alloc(index, 0, FSP_NO_DIR, level, mtr); new_page = buf_block_get_frame(new_block); new_page_zip = buf_block_get_page_zip(new_block); ut_a(!new_page_zip == !root_page_zip); @@ -2458,7 +2280,7 @@ btr_attach_half_pages( /*==================*/ dict_index_t* index, /*!< in: the index tree */ buf_block_t* block, /*!< in/out: page to be split */ - const rec_t* split_rec, /*!< in: first record on upper + rec_t* split_rec, /*!< in: first record on upper half page */ buf_block_t* new_block, /*!< in/out: the new half page */ ulint direction, /*!< in: FSP_UP or FSP_DOWN */ @@ -2723,7 +2545,7 @@ func_start: /* 2. Allocate a new page to the index */ new_block = btr_page_alloc(cursor->index, hint_page_no, direction, - btr_page_get_level(page, mtr), mtr, mtr); + btr_page_get_level(page, mtr), mtr); new_page = buf_block_get_frame(new_block); new_page_zip = buf_block_get_page_zip(new_block); btr_page_create(new_block, new_page_zip, cursor->index, @@ -3173,16 +2995,15 @@ btr_node_ptr_delete( ut_a(err == DB_SUCCESS); if (!compressed) { - btr_cur_compress_if_useful(&cursor, FALSE, mtr); + btr_cur_compress_if_useful(&cursor, mtr); } } /*************************************************************//** If page is the only on its level, this function moves its records to the -father page, thus reducing the tree height. -@return father block */ +father page, thus reducing the tree height. */ static -buf_block_t* +void btr_lift_page_up( /*=============*/ dict_index_t* index, /*!< in: index tree */ @@ -3299,8 +3120,6 @@ btr_lift_page_up( } ut_ad(page_validate(father_page, index)); ut_ad(btr_check_node_ptr(index, father_block, mtr)); - - return(father_block); } /*************************************************************//** @@ -3317,13 +3136,11 @@ UNIV_INTERN ibool btr_compress( /*=========*/ - btr_cur_t* cursor, /*!< in/out: cursor on the page to merge - or lift; the page must not be empty: - when deleting records, use btr_discard_page() - if the page would become empty */ - ibool adjust, /*!< in: TRUE if should adjust the - cursor position even if compression occurs */ - mtr_t* mtr) /*!< in/out: mini-transaction */ + btr_cur_t* cursor, /*!< in: cursor on the page to merge or lift; + the page must not be empty: in record delete + use btr_discard_page if the page would become + empty */ + mtr_t* mtr) /*!< in: mtr */ { dict_index_t* index; ulint space; @@ -3341,14 +3158,12 @@ btr_compress( ulint* offsets; ulint data_size; ulint n_recs; - ulint nth_rec = 0; /* remove bogus warning */ ulint max_ins_size; ulint max_ins_size_reorg; block = btr_cur_get_block(cursor); page = btr_cur_get_page(cursor); index = btr_cur_get_index(cursor); - ut_a((ibool) !!page_is_comp(page) == dict_table_is_comp(index->table)); ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index), @@ -3369,10 +3184,6 @@ btr_compress( offsets = btr_page_get_father_block(NULL, heap, index, block, mtr, &father_cursor); - if (adjust) { - nth_rec = page_rec_get_n_recs_before(btr_cur_get_rec(cursor)); - } - /* Decide the page to which we try to merge and which will inherit the locks */ @@ -3399,9 +3210,9 @@ btr_compress( } else { /* The page is the only one on the level, lift the records to the father */ - - merge_block = btr_lift_page_up(index, block, mtr); - goto func_exit; + btr_lift_page_up(index, block, mtr); + mem_heap_free(heap); + return(TRUE); } n_recs = page_get_n_recs(page); @@ -3483,10 +3294,6 @@ err_exit: btr_node_ptr_delete(index, block, mtr); lock_update_merge_left(merge_block, orig_pred, block); - - if (adjust) { - nth_rec += page_rec_get_n_recs_before(orig_pred); - } } else { rec_t* orig_succ; #ifdef UNIV_BTR_DEBUG @@ -3551,6 +3358,7 @@ err_exit: } btr_blob_dbg_remove(page, index, "btr_compress"); + mem_heap_free(heap); if (!dict_index_is_clust(index) && page_is_leaf(merge_page)) { /* Update the free bits of the B-tree page in the @@ -3602,16 +3410,6 @@ err_exit: btr_page_free(index, block, mtr); ut_ad(btr_check_node_ptr(index, merge_block, mtr)); -func_exit: - mem_heap_free(heap); - - if (adjust) { - btr_cur_position( - index, - page_rec_get_nth(merge_block->frame, nth_rec), - merge_block, cursor); - } - return(TRUE); } diff --git a/storage/innobase/btr/btr0cur.c b/storage/innobase/btr/btr0cur.c index 3021bb71929..f63ca20ef24 100644 --- a/storage/innobase/btr/btr0cur.c +++ b/storage/innobase/btr/btr0cur.c @@ -1985,6 +1985,7 @@ btr_cur_optimistic_update( ulint old_rec_size; dtuple_t* new_entry; roll_ptr_t roll_ptr; + trx_t* trx; mem_heap_t* heap; ulint i; ulint n_ext; @@ -2001,10 +2002,9 @@ btr_cur_optimistic_update( heap = mem_heap_create(1024); offsets = rec_get_offsets(rec, index, NULL, ULINT_UNDEFINED, &heap); -#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG - ut_a(!rec_offs_any_null_extern(rec, offsets) - || trx_is_recv(thr_get_trx(thr))); -#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ +#ifdef UNIV_BLOB_NULL_DEBUG + ut_a(!rec_offs_any_null_extern(rec, offsets)); +#endif /* UNIV_BLOB_NULL_DEBUG */ #ifdef UNIV_DEBUG if (btr_cur_print_record_ops && thr) { @@ -2127,11 +2127,13 @@ any_extern: page_cur_move_to_prev(page_cursor); + trx = thr_get_trx(thr); + if (!(flags & BTR_KEEP_SYS_FLAG)) { row_upd_index_entry_sys_field(new_entry, index, DATA_ROLL_PTR, roll_ptr); row_upd_index_entry_sys_field(new_entry, index, DATA_TRX_ID, - thr_get_trx(thr)->id); + trx->id); } /* There are no externally stored columns in new_entry */ @@ -2217,9 +2219,7 @@ btr_cur_pessimistic_update( /*=======================*/ ulint flags, /*!< in: undo logging, locking, and rollback flags */ - btr_cur_t* cursor, /*!< in/out: cursor on the record to update; - cursor may become invalid if *big_rec == NULL - || !(flags & BTR_KEEP_POS_FLAG) */ + btr_cur_t* cursor, /*!< in: cursor on the record to update */ mem_heap_t** heap, /*!< in/out: pointer to memory heap, or NULL */ big_rec_t** big_rec,/*!< out: big rec vector whose fields have to be stored externally by the caller, or NULL */ @@ -2358,7 +2358,7 @@ btr_cur_pessimistic_update( record to be inserted: we have to remember which fields were such */ ut_ad(!page_is_comp(page) || !rec_get_node_ptr_flag(rec)); - ut_ad(rec_offs_validate(rec, index, offsets)); + offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, heap); n_ext += btr_push_update_extern_fields(new_entry, update, *heap); if (UNIV_LIKELY_NULL(page_zip)) { @@ -2381,10 +2381,6 @@ make_external: err = DB_TOO_BIG_RECORD; goto return_after_reservations; } - - ut_ad(page_is_leaf(page)); - ut_ad(dict_index_is_clust(index)); - ut_ad(flags & BTR_KEEP_POS_FLAG); } /* Store state of explicit locks on rec on the page infimum record, @@ -2412,8 +2408,6 @@ make_external: rec = btr_cur_insert_if_possible(cursor, new_entry, n_ext, mtr); if (rec) { - page_cursor->rec = rec; - lock_rec_restore_from_page_infimum(btr_cur_get_block(cursor), rec, block); @@ -2427,10 +2421,7 @@ make_external: rec, index, offsets, mtr); } - btr_cur_compress_if_useful( - cursor, - big_rec_vec != NULL && (flags & BTR_KEEP_POS_FLAG), - mtr); + btr_cur_compress_if_useful(cursor, mtr); if (page_zip && !dict_index_is_clust(index) && page_is_leaf(page)) { @@ -2450,21 +2441,6 @@ make_external: } } - if (big_rec_vec) { - ut_ad(page_is_leaf(page)); - ut_ad(dict_index_is_clust(index)); - ut_ad(flags & BTR_KEEP_POS_FLAG); - - /* btr_page_split_and_insert() in - btr_cur_pessimistic_insert() invokes - mtr_memo_release(mtr, index->lock, MTR_MEMO_X_LOCK). - We must keep the index->lock when we created a - big_rec, so that row_upd_clust_rec() can store the - big_rec in the same mini-transaction. */ - - mtr_x_lock(dict_index_get_lock(index), mtr); - } - /* Was the record to be updated positioned as the first user record on its page? */ was_first = page_cur_is_before_first(page_cursor); @@ -2480,7 +2456,6 @@ make_external: ut_a(rec); ut_a(err == DB_SUCCESS); ut_a(dummy_big_rec == NULL); - page_cursor->rec = rec; if (dict_index_is_sec_or_ibuf(index)) { /* Update PAGE_MAX_TRX_ID in the index page header. @@ -2915,12 +2890,10 @@ UNIV_INTERN ibool btr_cur_compress_if_useful( /*=======================*/ - btr_cur_t* cursor, /*!< in/out: cursor on the page to compress; - cursor does not stay valid if !adjust and - compression occurs */ - ibool adjust, /*!< in: TRUE if should adjust the - cursor position even if compression occurs */ - mtr_t* mtr) /*!< in/out: mini-transaction */ + btr_cur_t* cursor, /*!< in: cursor on the page to compress; + cursor does not stay valid if compression + occurs */ + mtr_t* mtr) /*!< in: mtr */ { ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(btr_cur_get_index(cursor)), @@ -2929,7 +2902,7 @@ btr_cur_compress_if_useful( MTR_MEMO_PAGE_X_FIX)); return(btr_cur_compress_recommendation(cursor, mtr) - && btr_compress(cursor, adjust, mtr)); + && btr_compress(cursor, mtr)); } /*******************************************************//** @@ -3171,7 +3144,7 @@ return_after_reservations: mem_heap_free(heap); if (ret == FALSE) { - ret = btr_cur_compress_if_useful(cursor, FALSE, mtr); + ret = btr_cur_compress_if_useful(cursor, mtr); } if (n_extents > 0) { @@ -4160,9 +4133,6 @@ btr_store_big_rec_extern_fields_func( the "external storage" flags in offsets will not correspond to rec when this function returns */ - const big_rec_t*big_rec_vec, /*!< in: vector containing fields - to be stored externally */ - #ifdef UNIV_DEBUG mtr_t* local_mtr, /*!< in: mtr containing the latch to rec and to the tree */ @@ -4171,11 +4141,9 @@ btr_store_big_rec_extern_fields_func( ibool update_in_place,/*! in: TRUE if the record is updated in place (not delete+insert) */ #endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ - mtr_t* alloc_mtr) /*!< in/out: in an insert, NULL; - in an update, local_mtr for - allocating BLOB pages and - updating BLOB pointers; alloc_mtr - must not have freed any leaf pages */ + const big_rec_t*big_rec_vec) /*!< in: vector containing fields + to be stored externally */ + { ulint rec_page_no; byte* field_ref; @@ -4194,9 +4162,6 @@ btr_store_big_rec_extern_fields_func( ut_ad(rec_offs_validate(rec, index, offsets)); ut_ad(rec_offs_any_extern(offsets)); - ut_ad(local_mtr); - ut_ad(!alloc_mtr || alloc_mtr == local_mtr); - ut_ad(!update_in_place || alloc_mtr); ut_ad(mtr_memo_contains(local_mtr, dict_index_get_lock(index), MTR_MEMO_X_LOCK)); ut_ad(mtr_memo_contains(local_mtr, rec_block, MTR_MEMO_PAGE_X_FIX)); @@ -4212,25 +4177,6 @@ btr_store_big_rec_extern_fields_func( rec_page_no = buf_block_get_page_no(rec_block); ut_a(fil_page_get_type(page_align(rec)) == FIL_PAGE_INDEX); - if (alloc_mtr) { - /* Because alloc_mtr will be committed after - mtr, it is possible that the tablespace has been - extended when the B-tree record was updated or - inserted, or it will be extended while allocating - pages for big_rec. - - TODO: In mtr (not alloc_mtr), write a redo log record - about extending the tablespace to its current size, - and remember the current size. Whenever the tablespace - grows as pages are allocated, write further redo log - records to mtr. (Currently tablespace extension is not - covered by the redo log. If it were, the record would - only be written to alloc_mtr, which is committed after - mtr.) */ - } else { - alloc_mtr = &mtr; - } - if (UNIV_LIKELY_NULL(page_zip)) { int err; @@ -4307,7 +4253,7 @@ btr_store_big_rec_extern_fields_func( } block = btr_page_alloc(index, hint_page_no, - FSP_NO_DIR, 0, alloc_mtr, &mtr); + FSP_NO_DIR, 0, &mtr); if (UNIV_UNLIKELY(block == NULL)) { mtr_commit(&mtr); @@ -4434,15 +4380,11 @@ btr_store_big_rec_extern_fields_func( goto next_zip_page; } - if (alloc_mtr == &mtr) { - rec_block = buf_page_get( - space_id, zip_size, - rec_page_no, - RW_X_LATCH, &mtr); - buf_block_dbg_add_level( - rec_block, - SYNC_NO_ORDER_CHECK); - } + rec_block = buf_page_get(space_id, zip_size, + rec_page_no, + RW_X_LATCH, &mtr); + buf_block_dbg_add_level(rec_block, + SYNC_NO_ORDER_CHECK); if (err == Z_STREAM_END) { mach_write_to_4(field_ref @@ -4476,8 +4418,7 @@ btr_store_big_rec_extern_fields_func( page_zip_write_blob_ptr( page_zip, rec, index, offsets, - big_rec_vec->fields[i].field_no, - alloc_mtr); + big_rec_vec->fields[i].field_no, &mtr); next_zip_page: prev_page_no = page_no; @@ -4522,23 +4463,19 @@ next_zip_page: extern_len -= store_len; - if (alloc_mtr == &mtr) { - rec_block = buf_page_get( - space_id, zip_size, - rec_page_no, - RW_X_LATCH, &mtr); - buf_block_dbg_add_level( - rec_block, - SYNC_NO_ORDER_CHECK); - } + rec_block = buf_page_get(space_id, zip_size, + rec_page_no, + RW_X_LATCH, &mtr); + buf_block_dbg_add_level(rec_block, + SYNC_NO_ORDER_CHECK); mlog_write_ulint(field_ref + BTR_EXTERN_LEN, 0, - MLOG_4BYTES, alloc_mtr); + MLOG_4BYTES, &mtr); mlog_write_ulint(field_ref + BTR_EXTERN_LEN + 4, big_rec_vec->fields[i].len - extern_len, - MLOG_4BYTES, alloc_mtr); + MLOG_4BYTES, &mtr); if (prev_page_no == FIL_NULL) { btr_blob_dbg_add_blob( @@ -4548,19 +4485,18 @@ next_zip_page: mlog_write_ulint(field_ref + BTR_EXTERN_SPACE_ID, - space_id, MLOG_4BYTES, - alloc_mtr); + space_id, + MLOG_4BYTES, &mtr); mlog_write_ulint(field_ref + BTR_EXTERN_PAGE_NO, - page_no, MLOG_4BYTES, - alloc_mtr); + page_no, + MLOG_4BYTES, &mtr); mlog_write_ulint(field_ref + BTR_EXTERN_OFFSET, FIL_PAGE_DATA, - MLOG_4BYTES, - alloc_mtr); + MLOG_4BYTES, &mtr); } prev_page_no = page_no; diff --git a/storage/innobase/buf/buf0buf.c b/storage/innobase/buf/buf0buf.c index e0b9e979970..33b4cd40215 100644 --- a/storage/innobase/buf/buf0buf.c +++ b/storage/innobase/buf/buf0buf.c @@ -1715,6 +1715,31 @@ buf_page_set_accessed_make_young( } } +/********************************************************************//** +Resets the check_index_page_at_flush field of a page if found in the buffer +pool. */ +UNIV_INTERN +void +buf_reset_check_index_page_at_flush( +/*================================*/ + ulint space, /*!< in: space id */ + ulint offset) /*!< in: page number */ +{ + buf_block_t* block; + buf_pool_t* buf_pool = buf_pool_get(space, offset); + + buf_pool_mutex_enter(buf_pool); + + block = (buf_block_t*) buf_page_hash_get(buf_pool, space, offset); + + if (block && buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE) { + ut_ad(!buf_pool_watch_is_sentinel(buf_pool, &block->page)); + block->check_index_page_at_flush = FALSE; + } + + buf_pool_mutex_exit(buf_pool); +} + /********************************************************************//** 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 diff --git a/storage/innobase/fsp/fsp0fsp.c b/storage/innobase/fsp/fsp0fsp.c index 96d29e8ae32..3f09732a676 100644 --- a/storage/innobase/fsp/fsp0fsp.c +++ b/storage/innobase/fsp/fsp0fsp.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2010, Innobase Oy. 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 @@ -311,9 +311,8 @@ fsp_fill_free_list( descriptor page and ibuf bitmap page; then we do not allocate more extents */ ulint space, /*!< in: space */ - fsp_header_t* header, /*!< in/out: space header */ - mtr_t* mtr) /*!< in/out: mini-transaction */ - UNIV_COLD __attribute__((nonnull)); + fsp_header_t* header, /*!< in: space header */ + mtr_t* mtr); /*!< in: mtr */ /**********************************************************************//** Allocates a single free page from a segment. This function implements the intelligent allocation strategy which tries to minimize file space @@ -326,20 +325,14 @@ fseg_alloc_free_page_low( ulint space, /*!< in: space */ ulint zip_size,/*!< in: compressed page size in bytes or 0 for uncompressed pages */ - fseg_inode_t* seg_inode, /*!< in/out: segment inode */ + fseg_inode_t* seg_inode, /*!< in: segment inode */ ulint hint, /*!< in: hint of which page would be desirable */ byte direction, /*!< in: if the new page is needed because of an index page split, and records are inserted there in order, into which direction they go alphabetically: FSP_DOWN, FSP_UP, FSP_NO_DIR */ - mtr_t* mtr, /*!< in/out: mini-transaction */ - mtr_t* init_mtr)/*!< in/out: mini-transaction in which the - page should be initialized - (may be the same as mtr), or NULL if it - should not be initialized (the page at hint - was previously freed in mtr) */ - __attribute__((warn_unused_result, nonnull(3,6))); + mtr_t* mtr); /*!< in: mtr handle */ #endif /* !UNIV_HOTBACKUP */ /**********************************************************************//** @@ -707,18 +700,17 @@ list, if not free limit == space size. This adding is necessary to make the descriptor defined, as they are uninitialized above the free limit. @return pointer to the extent descriptor, NULL if the page does not exist in the space or if the offset exceeds the free limit */ -UNIV_INLINE __attribute__((nonnull, warn_unused_result)) +UNIV_INLINE xdes_t* xdes_get_descriptor_with_space_hdr( /*===============================*/ - fsp_header_t* sp_header, /*!< in/out: space header, x-latched - in mtr */ - ulint space, /*!< in: space id */ - ulint offset, /*!< in: page offset; if equal - to the free limit, we try to - add new extents to the space - free list */ - mtr_t* mtr) /*!< in/out: mini-transaction */ + fsp_header_t* sp_header,/*!< in/out: space header, x-latched */ + ulint space, /*!< in: space id */ + ulint offset, /*!< in: page offset; + if equal to the free limit, + we try to add new extents to + the space free list */ + mtr_t* mtr) /*!< in: mtr handle */ { ulint limit; ulint size; @@ -726,9 +718,11 @@ xdes_get_descriptor_with_space_hdr( ulint descr_page_no; page_t* descr_page; + ut_ad(mtr); ut_ad(mtr_memo_contains(mtr, fil_space_get_latch(space, NULL), MTR_MEMO_X_LOCK)); - ut_ad(mtr_memo_contains_page(mtr, sp_header, MTR_MEMO_PAGE_X_FIX)); + ut_ad(mtr_memo_contains_page(mtr, sp_header, MTR_MEMO_PAGE_S_FIX) + || mtr_memo_contains_page(mtr, sp_header, MTR_MEMO_PAGE_X_FIX)); ut_ad(page_offset(sp_header) == FSP_HEADER_OFFSET); /* Read free limit and space size */ limit = mach_read_from_4(sp_header + FSP_FREE_LIMIT); @@ -778,7 +772,7 @@ is necessary to make the descriptor defined, as they are uninitialized above the free limit. @return pointer to the extent descriptor, NULL if the page does not exist in the space or if the offset exceeds the free limit */ -static __attribute__((nonnull, warn_unused_result)) +static xdes_t* xdes_get_descriptor( /*================*/ @@ -787,7 +781,7 @@ xdes_get_descriptor( or 0 for uncompressed pages */ ulint offset, /*!< in: page offset; if equal to the free limit, we try to add new extents to the space free list */ - mtr_t* mtr) /*!< in/out: mini-transaction */ + mtr_t* mtr) /*!< in: mtr handle */ { buf_block_t* block; fsp_header_t* sp_header; @@ -1165,14 +1159,14 @@ fsp_header_get_tablespace_size(void) Tries to extend a single-table tablespace so that a page would fit in the data file. @return TRUE if success */ -static UNIV_COLD __attribute__((nonnull, warn_unused_result)) +static ibool fsp_try_extend_data_file_with_pages( /*================================*/ ulint space, /*!< in: space */ ulint page_no, /*!< in: page number */ - fsp_header_t* header, /*!< in/out: space header */ - mtr_t* mtr) /*!< in/out: mini-transaction */ + fsp_header_t* header, /*!< in: space header */ + mtr_t* mtr) /*!< in: mtr */ { ibool success; ulint actual_size; @@ -1197,7 +1191,7 @@ fsp_try_extend_data_file_with_pages( /***********************************************************************//** Tries to extend the last data file of a tablespace if it is auto-extending. @return FALSE if not auto-extending */ -static UNIV_COLD __attribute__((nonnull)) +static ibool fsp_try_extend_data_file( /*=====================*/ @@ -1207,8 +1201,8 @@ fsp_try_extend_data_file( the actual file size rounded down to megabyte */ ulint space, /*!< in: space */ - fsp_header_t* header, /*!< in/out: space header */ - mtr_t* mtr) /*!< in/out: mini-transaction */ + fsp_header_t* header, /*!< in: space header */ + mtr_t* mtr) /*!< in: mtr */ { ulint size; ulint zip_size; @@ -1344,7 +1338,7 @@ fsp_fill_free_list( then we do not allocate more extents */ ulint space, /*!< in: space */ fsp_header_t* header, /*!< in/out: space header */ - mtr_t* mtr) /*!< in/out: mini-transaction */ + mtr_t* mtr) /*!< in: mtr */ { ulint limit; ulint size; @@ -1542,47 +1536,10 @@ fsp_alloc_free_extent( return(descr); } -/**********************************************************************//** -Allocates a single free page from a space. */ -static __attribute__((nonnull)) -void -fsp_alloc_from_free_frag( -/*=====================*/ - fsp_header_t* header, /*!< in/out: tablespace header */ - xdes_t* descr, /*!< in/out: extent descriptor */ - ulint bit, /*!< in: slot to allocate in the extent */ - mtr_t* mtr) /*!< in/out: mini-transaction */ -{ - ulint frag_n_used; - - ut_ad(xdes_get_state(descr, mtr) == XDES_FREE_FRAG); - ut_a(xdes_get_bit(descr, XDES_FREE_BIT, bit, mtr)); - xdes_set_bit(descr, XDES_FREE_BIT, bit, FALSE, mtr); - - /* Update the FRAG_N_USED field */ - frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES, - mtr); - frag_n_used++; - mlog_write_ulint(header + FSP_FRAG_N_USED, frag_n_used, MLOG_4BYTES, - mtr); - if (xdes_is_full(descr, mtr)) { - /* The fragment is full: move it to another list */ - flst_remove(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE, - mtr); - xdes_set_state(descr, XDES_FULL_FRAG, mtr); - - flst_add_last(header + FSP_FULL_FRAG, descr + XDES_FLST_NODE, - mtr); - mlog_write_ulint(header + FSP_FRAG_N_USED, - frag_n_used - FSP_EXTENT_SIZE, MLOG_4BYTES, - mtr); - } -} - /**********************************************************************//** Allocates a single free page from a space. The page is marked as used. @return the page offset, FIL_NULL if no page could be allocated */ -static __attribute__((nonnull, warn_unused_result)) +static ulint fsp_alloc_free_page( /*================*/ @@ -1590,22 +1547,19 @@ fsp_alloc_free_page( ulint zip_size,/*!< in: compressed page size in bytes or 0 for uncompressed pages */ ulint hint, /*!< in: hint of which page would be desirable */ - mtr_t* mtr, /*!< in/out: mini-transaction */ - mtr_t* init_mtr)/*!< in/out: mini-transaction in which the - page should be initialized - (may be the same as mtr) */ + mtr_t* mtr) /*!< in: mtr handle */ { fsp_header_t* header; fil_addr_t first; xdes_t* descr; buf_block_t* block; ulint free; + ulint frag_n_used; ulint page_no; ulint space_size; ibool success; ut_ad(mtr); - ut_ad(init_mtr); header = fsp_get_space_header(space, zip_size, mtr); @@ -1687,19 +1641,38 @@ fsp_alloc_free_page( } } - fsp_alloc_from_free_frag(header, descr, free, mtr); + xdes_set_bit(descr, XDES_FREE_BIT, free, FALSE, mtr); + + /* Update the FRAG_N_USED field */ + frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES, + mtr); + frag_n_used++; + mlog_write_ulint(header + FSP_FRAG_N_USED, frag_n_used, MLOG_4BYTES, + mtr); + if (xdes_is_full(descr, mtr)) { + /* The fragment is full: move it to another list */ + flst_remove(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE, + mtr); + xdes_set_state(descr, XDES_FULL_FRAG, mtr); + + flst_add_last(header + FSP_FULL_FRAG, descr + XDES_FLST_NODE, + mtr); + mlog_write_ulint(header + FSP_FRAG_N_USED, + frag_n_used - FSP_EXTENT_SIZE, MLOG_4BYTES, + mtr); + } /* Initialize the allocated page to the buffer pool, so that it can be obtained immediately with buf_page_get without need for a disk read. */ - buf_page_create(space, page_no, zip_size, init_mtr); + buf_page_create(space, page_no, zip_size, mtr); - block = buf_page_get(space, zip_size, page_no, RW_X_LATCH, init_mtr); + block = buf_page_get(space, zip_size, page_no, RW_X_LATCH, mtr); buf_block_dbg_add_level(block, SYNC_FSP_PAGE); /* Prior contents of the page should be ignored */ - fsp_init_file_page(block, init_mtr); + fsp_init_file_page(block, mtr); return(page_no); } @@ -1935,7 +1908,7 @@ fsp_alloc_seg_inode_page( zip_size = dict_table_flags_to_zip_size( mach_read_from_4(FSP_SPACE_FLAGS + space_header)); - page_no = fsp_alloc_free_page(space, zip_size, 0, mtr, mtr); + page_no = fsp_alloc_free_page(space, zip_size, 0, mtr); if (page_no == FIL_NULL) { @@ -2347,7 +2320,7 @@ fseg_create_general( if (page == 0) { page = fseg_alloc_free_page_low(space, zip_size, - inode, 0, FSP_UP, mtr, mtr); + inode, 0, FSP_UP, mtr); if (page == FIL_NULL) { @@ -2596,19 +2569,14 @@ fseg_alloc_free_page_low( ulint space, /*!< in: space */ ulint zip_size,/*!< in: compressed page size in bytes or 0 for uncompressed pages */ - fseg_inode_t* seg_inode, /*!< in/out: segment inode */ + fseg_inode_t* seg_inode, /*!< in: segment inode */ ulint hint, /*!< in: hint of which page would be desirable */ byte direction, /*!< in: if the new page is needed because of an index page split, and records are inserted there in order, into which direction they go alphabetically: FSP_DOWN, FSP_UP, FSP_NO_DIR */ - mtr_t* mtr, /*!< in/out: mini-transaction */ - mtr_t* init_mtr)/*!< in/out: mini-transaction in which the - page should be initialized - (may be the same as mtr), or NULL if it - should not be initialized (the page at hint - was previously freed in mtr) */ + mtr_t* mtr) /*!< in: mtr handle */ { fsp_header_t* space_header; ulint space_size; @@ -2619,6 +2587,7 @@ fseg_alloc_free_page_low( ulint ret_page; /*!< the allocated page offset, FIL_NULL if could not be allocated */ xdes_t* ret_descr; /*!< the extent of the allocated page */ + ibool frag_page_allocated = FALSE; ibool success; ulint n; @@ -2640,8 +2609,6 @@ fseg_alloc_free_page_low( if (descr == NULL) { /* Hint outside space or too high above free limit: reset hint */ - ut_a(init_mtr); - /* The file space header page is always allocated. */ hint = 0; descr = xdes_get_descriptor(space, zip_size, hint, mtr); } @@ -2652,20 +2619,15 @@ fseg_alloc_free_page_low( && mach_read_from_8(descr + XDES_ID) == seg_id && (xdes_get_bit(descr, XDES_FREE_BIT, hint % FSP_EXTENT_SIZE, mtr) == TRUE)) { -take_hinted_page: + /* 1. We can take the hinted page =================================*/ ret_descr = descr; ret_page = hint; - /* Skip the check for extending the tablespace. If the - page hint were not within the size of the tablespace, - we would have got (descr == NULL) above and reset the hint. */ - goto got_hinted_page; /*-----------------------------------------------------------*/ - } else if (xdes_get_state(descr, mtr) == XDES_FREE - && (!init_mtr - || ((reserved - used < reserved / FSEG_FILLFACTOR) - && used >= FSEG_FRAG_LIMIT))) { + } else if ((xdes_get_state(descr, mtr) == XDES_FREE) + && ((reserved - used) < reserved / FSEG_FILLFACTOR) + && (used >= FSEG_FRAG_LIMIT)) { /* 2. We allocate the free extent from space and can take ========================================================= @@ -2683,20 +2645,8 @@ take_hinted_page: /* Try to fill the segment free list */ fseg_fill_free_list(seg_inode, space, zip_size, hint + FSP_EXTENT_SIZE, mtr); - goto take_hinted_page; - /*-----------------------------------------------------------*/ - } else if (!init_mtr) { - ut_a(xdes_get_state(descr, mtr) == XDES_FREE_FRAG); - fsp_alloc_from_free_frag(space_header, descr, - hint % FSP_EXTENT_SIZE, mtr); ret_page = hint; - ret_descr = NULL; - - /* Put the page in the fragment page array of the segment */ - n = fseg_find_free_frag_page_slot(seg_inode, mtr); - ut_a(n != FIL_NULL); - fseg_set_nth_frag_page_no(seg_inode, n, ret_page, mtr); - goto got_hinted_page; + /*-----------------------------------------------------------*/ } else if ((direction != FSP_NO_DIR) && ((reserved - used) < reserved / FSEG_FILLFACTOR) && (used >= FSEG_FRAG_LIMIT) @@ -2755,10 +2705,11 @@ take_hinted_page: } else if (used < FSEG_FRAG_LIMIT) { /* 6. We allocate an individual page from the space ===================================================*/ - ret_page = fsp_alloc_free_page(space, zip_size, hint, - mtr, init_mtr); + ret_page = fsp_alloc_free_page(space, zip_size, hint, mtr); ret_descr = NULL; + frag_page_allocated = TRUE; + if (ret_page != FIL_NULL) { /* Put the page in the fragment page array of the segment */ @@ -2768,10 +2719,6 @@ take_hinted_page: fseg_set_nth_frag_page_no(seg_inode, n, ret_page, mtr); } - - /* fsp_alloc_free_page() invoked fsp_init_file_page() - already. */ - return(ret_page); /*-----------------------------------------------------------*/ } else { /* 7. We allocate a new extent and take its first page @@ -2819,34 +2766,26 @@ take_hinted_page: } } -got_hinted_page: - { + if (!frag_page_allocated) { /* Initialize the allocated page to buffer pool, so that it can be obtained immediately with buf_page_get without need for a disk read */ buf_block_t* block; ulint zip_size = dict_table_flags_to_zip_size( mach_read_from_4(FSP_SPACE_FLAGS + space_header)); - mtr_t* block_mtr = init_mtr ? init_mtr : mtr; - block = buf_page_create(space, ret_page, zip_size, block_mtr); + block = buf_page_create(space, ret_page, zip_size, mtr); buf_block_dbg_add_level(block, SYNC_FSP_PAGE); if (UNIV_UNLIKELY(block != buf_page_get(space, zip_size, ret_page, RW_X_LATCH, - block_mtr))) { + mtr))) { ut_error; } - if (init_mtr) { - /* The prior contents of the page should be ignored */ - fsp_init_file_page(block, init_mtr); - } - } + /* The prior contents of the page should be ignored */ + fsp_init_file_page(block, mtr); - /* ret_descr == NULL if the block was allocated from free_frag - (XDES_FREE_FRAG) */ - if (ret_descr != NULL) { /* At this point we know the extent and the page offset. The extent is still in the appropriate list (FSEG_NOT_FULL or FSEG_FREE), and the page is not yet marked as used. */ @@ -2859,6 +2798,8 @@ got_hinted_page: fseg_mark_page_used(seg_inode, space, zip_size, ret_page, mtr); } + buf_reset_check_index_page_at_flush(space, ret_page); + return(ret_page); } @@ -2871,7 +2812,7 @@ UNIV_INTERN ulint fseg_alloc_free_page_general( /*=========================*/ - fseg_header_t* seg_header,/*!< in/out: segment header */ + fseg_header_t* seg_header,/*!< in: segment header */ ulint hint, /*!< in: hint of which page would be desirable */ byte direction,/*!< in: if the new page is needed because of an index page split, and records are @@ -2883,11 +2824,7 @@ fseg_alloc_free_page_general( with fsp_reserve_free_extents, then there is no need to do the check for this individual page */ - mtr_t* mtr, /*!< in/out: mini-transaction handle */ - mtr_t* init_mtr)/*!< in/out: mtr or another mini-transaction - in which the page should be initialized, - or NULL if this is a "fake allocation" of - a page that was previously freed in mtr */ + mtr_t* mtr) /*!< in: mtr handle */ { fseg_inode_t* inode; ulint space; @@ -2929,8 +2866,7 @@ fseg_alloc_free_page_general( } page_no = fseg_alloc_free_page_low(space, zip_size, - inode, hint, direction, - mtr, init_mtr); + inode, hint, direction, mtr); if (!has_done_reservation) { fil_space_release_free_extents(space, n_reserved); } @@ -2938,6 +2874,28 @@ fseg_alloc_free_page_general( return(page_no); } +/**********************************************************************//** +Allocates a single free page from a segment. This function implements +the intelligent allocation strategy which tries to minimize file space +fragmentation. +@return allocated page offset, FIL_NULL if no page could be allocated */ +UNIV_INTERN +ulint +fseg_alloc_free_page( +/*=================*/ + fseg_header_t* seg_header,/*!< in: segment header */ + ulint hint, /*!< in: hint of which page would be desirable */ + byte direction,/*!< in: if the new page is needed because + of an index page split, and records are + inserted there in order, into which + direction they go alphabetically: FSP_DOWN, + FSP_UP, FSP_NO_DIR */ + mtr_t* mtr) /*!< in: mtr handle */ +{ + return(fseg_alloc_free_page_general(seg_header, hint, direction, + FALSE, mtr)); +} + /**********************************************************************//** Checks that we have at least 2 frag pages free in the first extent of a single-table tablespace, and they are also physically initialized to the data diff --git a/storage/innobase/include/btr0btr.h b/storage/innobase/include/btr0btr.h index 3dfd98ceb08..71e772388a0 100644 --- a/storage/innobase/include/btr0btr.h +++ b/storage/innobase/include/btr0btr.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1994, 2010, Innobase Oy. 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 @@ -499,14 +499,11 @@ UNIV_INTERN ibool btr_compress( /*=========*/ - btr_cur_t* cursor, /*!< in/out: cursor on the page to merge - or lift; the page must not be empty: - when deleting records, use btr_discard_page() - if the page would become empty */ - ibool adjust, /*!< in: TRUE if should adjust the - cursor position even if compression occurs */ - mtr_t* mtr) /*!< in/out: mini-transaction */ - __attribute__((nonnull)); + btr_cur_t* cursor, /*!< in: cursor on the page to merge or lift; + the page must not be empty: in record delete + use btr_discard_page if the page would become + empty */ + mtr_t* mtr); /*!< in: mtr */ /*************************************************************//** Discards a page from a B-tree. This is used to remove the last record from a B-tree page: the whole page must be removed at the same time. This cannot @@ -568,12 +565,7 @@ btr_page_alloc( page split is made */ ulint level, /*!< in: level where the page is placed in the tree */ - mtr_t* mtr, /*!< in/out: mini-transaction - for the allocation */ - mtr_t* init_mtr) /*!< in/out: mini-transaction - for x-latching and initializing - the page */ - __attribute__((nonnull, warn_unused_result)); + mtr_t* mtr); /*!< in: mtr */ /**************************************************************//** Frees a file page used in an index tree. NOTE: cannot free field external storage pages because the page must contain info on its level. */ @@ -596,33 +588,6 @@ btr_page_free_low( buf_block_t* block, /*!< in: block to be freed, x-latched */ ulint level, /*!< in: page level */ mtr_t* mtr); /*!< in: mtr */ -/**************************************************************//** -Marks all MTR_MEMO_FREE_CLUST_LEAF pages nonfree or free. -For invoking btr_store_big_rec_extern_fields() after an update, -we must temporarily mark freed clustered index pages allocated, so -that off-page columns will not be allocated from them. Between the -btr_store_big_rec_extern_fields() and mtr_commit() we have to -mark the pages free again, so that no pages will be leaked. */ -UNIV_INTERN -void -btr_mark_freed_leaves( -/*==================*/ - dict_index_t* index, /*!< in/out: clustered index */ - mtr_t* mtr, /*!< in/out: mini-transaction */ - ibool nonfree)/*!< in: TRUE=mark nonfree, FALSE=mark freed */ - UNIV_COLD __attribute__((nonnull)); -#ifdef UNIV_DEBUG -/**************************************************************//** -Validates all pages marked MTR_MEMO_FREE_CLUST_LEAF. -@see btr_mark_freed_leaves() -@return TRUE */ -UNIV_INTERN -ibool -btr_freed_leaves_validate( -/*======================*/ - mtr_t* mtr) /*!< in: mini-transaction */ - __attribute__((nonnull, warn_unused_result)); -#endif /* UNIV_DEBUG */ #ifdef UNIV_BTR_PRINT /*************************************************************//** Prints size info of a B-tree. */ diff --git a/storage/innobase/include/btr0cur.h b/storage/innobase/include/btr0cur.h index 26ed766dbd4..be918439f59 100644 --- a/storage/innobase/include/btr0cur.h +++ b/storage/innobase/include/btr0cur.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1994, 2010, Innobase Oy. 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 @@ -36,9 +36,6 @@ Created 10/16/1994 Heikki Tuuri #define BTR_NO_LOCKING_FLAG 2 /* do no record lock checking */ #define BTR_KEEP_SYS_FLAG 4 /* sys fields will be found from the update vector or inserted entry */ -#define BTR_KEEP_POS_FLAG 8 /* btr_cur_pessimistic_update() - must keep cursor position when - moving columns to big_rec */ #ifndef UNIV_HOTBACKUP #include "que0types.h" @@ -313,9 +310,7 @@ btr_cur_pessimistic_update( /*=======================*/ ulint flags, /*!< in: undo logging, locking, and rollback flags */ - btr_cur_t* cursor, /*!< in/out: cursor on the record to update; - cursor may become invalid if *big_rec == NULL - || !(flags & BTR_KEEP_POS_FLAG) */ + btr_cur_t* cursor, /*!< in: cursor on the record to update */ mem_heap_t** heap, /*!< in/out: pointer to memory heap, or NULL */ big_rec_t** big_rec,/*!< out: big rec vector whose fields have to be stored externally by the caller, or NULL */ @@ -369,13 +364,10 @@ UNIV_INTERN ibool btr_cur_compress_if_useful( /*=======================*/ - btr_cur_t* cursor, /*!< in/out: cursor on the page to compress; + btr_cur_t* cursor, /*!< in: cursor on the page to compress; cursor does not stay valid if compression occurs */ - ibool adjust, /*!< in: TRUE if should adjust the - cursor position even if compression occurs */ - mtr_t* mtr) /*!< in/out: mini-transaction */ - __attribute__((nonnull)); + mtr_t* mtr); /*!< in: mtr */ /*******************************************************//** Removes the record on which the tree cursor is positioned. It is assumed that the mtr has an x-latch on the page where the cursor is positioned, @@ -518,8 +510,6 @@ btr_store_big_rec_extern_fields_func( the "external storage" flags in offsets will not correspond to rec when this function returns */ - const big_rec_t*big_rec_vec, /*!< in: vector containing fields - to be stored externally */ #ifdef UNIV_DEBUG mtr_t* local_mtr, /*!< in: mtr containing the latch to rec and to the tree */ @@ -528,12 +518,9 @@ btr_store_big_rec_extern_fields_func( ibool update_in_place,/*! in: TRUE if the record is updated in place (not delete+insert) */ #endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ - mtr_t* alloc_mtr) /*!< in/out: in an insert, NULL; - in an update, local_mtr for - allocating BLOB pages and - updating BLOB pointers; alloc_mtr - must not have freed any leaf pages */ - __attribute__((nonnull(1,2,3,4,5), warn_unused_result)); + const big_rec_t*big_rec_vec) /*!< in: vector containing fields + to be stored externally */ + __attribute__((nonnull)); /** Stores the fields in big_rec_vec to the tablespace and puts pointers to them in rec. The extern flags in rec will have to be set beforehand. @@ -542,22 +529,21 @@ file segment of the index tree. @param index in: clustered index; MUST be X-latched by mtr @param b in/out: block containing rec; MUST be X-latched by mtr @param rec in/out: clustered index record -@param offs in: rec_get_offsets(rec, index); +@param offsets in: rec_get_offsets(rec, index); the "external storage" flags in offsets will not be adjusted -@param big in: vector containing fields to be stored externally @param mtr in: mini-transaction that holds x-latch on index and b @param upd in: TRUE if the record is updated in place (not delete+insert) -@param rmtr in/out: in updates, the mini-transaction that holds rec +@param big in: vector containing fields to be stored externally @return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */ #ifdef UNIV_DEBUG -# define btr_store_big_rec_extern_fields(index,b,rec,offs,big,mtr,upd,rmtr) \ - btr_store_big_rec_extern_fields_func(index,b,rec,offs,big,mtr,upd,rmtr) +# define btr_store_big_rec_extern_fields(index,b,rec,offsets,mtr,upd,big) \ + btr_store_big_rec_extern_fields_func(index,b,rec,offsets,mtr,upd,big) #elif defined UNIV_BLOB_LIGHT_DEBUG -# define btr_store_big_rec_extern_fields(index,b,rec,offs,big,mtr,upd,rmtr) \ - btr_store_big_rec_extern_fields_func(index,b,rec,offs,big,upd,rmtr) +# define btr_store_big_rec_extern_fields(index,b,rec,offsets,mtr,upd,big) \ + btr_store_big_rec_extern_fields_func(index,b,rec,offsets,upd,big) #else -# define btr_store_big_rec_extern_fields(index,b,rec,offs,big,mtr,upd,rmtr) \ - btr_store_big_rec_extern_fields_func(index,b,rec,offs,big,rmtr) +# define btr_store_big_rec_extern_fields(index,b,rec,offsets,mtr,upd,big) \ + btr_store_big_rec_extern_fields_func(index,b,rec,offsets,big) #endif /*******************************************************************//** diff --git a/storage/innobase/include/btr0cur.ic b/storage/innobase/include/btr0cur.ic index c833b3e8572..280583f6ccf 100644 --- a/storage/innobase/include/btr0cur.ic +++ b/storage/innobase/include/btr0cur.ic @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1994, 2009, Innobase Oy. 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 @@ -139,7 +139,7 @@ btr_cur_compress_recommendation( btr_cur_t* cursor, /*!< in: btr cursor */ mtr_t* mtr) /*!< in: mtr */ { - const page_t* page; + page_t* page; ut_ad(mtr_memo_contains(mtr, btr_cur_get_block(cursor), MTR_MEMO_PAGE_X_FIX)); diff --git a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h index 03b80fce2e8..ccebb69a4fe 100644 --- a/storage/innobase/include/buf0buf.h +++ b/storage/innobase/include/buf0buf.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2010, Innobase Oy. 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 @@ -491,6 +491,15 @@ buf_page_peek( /*==========*/ ulint space, /*!< in: space id */ ulint offset);/*!< in: page number */ +/********************************************************************//** +Resets the check_index_page_at_flush field of a page if found in the buffer +pool. */ +UNIV_INTERN +void +buf_reset_check_index_page_at_flush( +/*================================*/ + ulint space, /*!< in: space id */ + ulint offset);/*!< in: page number */ #if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG /********************************************************************//** Sets file_page_was_freed TRUE if the page is found in the buffer pool. @@ -600,31 +609,6 @@ buf_block_get_modify_clock( #else /* !UNIV_HOTBACKUP */ # define buf_block_modify_clock_inc(block) ((void) 0) #endif /* !UNIV_HOTBACKUP */ -/*******************************************************************//** -Increments the bufferfix count. */ -UNIV_INLINE -void -buf_block_buf_fix_inc_func( -/*=======================*/ -#ifdef UNIV_SYNC_DEBUG - const char* file, /*!< in: file name */ - ulint line, /*!< in: line */ -#endif /* UNIV_SYNC_DEBUG */ - buf_block_t* block) /*!< in/out: block to bufferfix */ - __attribute__((nonnull)); -#ifdef UNIV_SYNC_DEBUG -/** Increments the bufferfix count. -@param b in/out: block to bufferfix -@param f in: file name where requested -@param l in: line number where requested */ -# define buf_block_buf_fix_inc(b,f,l) buf_block_buf_fix_inc_func(f,l,b) -#else /* UNIV_SYNC_DEBUG */ -/** Increments the bufferfix count. -@param b in/out: block to bufferfix -@param f in: file name where requested -@param l in: line number where requested */ -# define buf_block_buf_fix_inc(b,f,l) buf_block_buf_fix_inc_func(b) -#endif /* UNIV_SYNC_DEBUG */ /********************************************************************//** Calculates a page checksum which is stored to the page when it is written to a file. Note that we must be careful to calculate the same value diff --git a/storage/innobase/include/buf0buf.ic b/storage/innobase/include/buf0buf.ic index 0e80ce55e57..b65b5133c15 100644 --- a/storage/innobase/include/buf0buf.ic +++ b/storage/innobase/include/buf0buf.ic @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved. Copyright (c) 2008, Google Inc. Portions of this file contain modifications contributed and copyrighted by @@ -944,6 +944,19 @@ buf_block_buf_fix_inc_func( block->page.buf_fix_count++; } +#ifdef UNIV_SYNC_DEBUG +/** Increments the bufferfix count. +@param b in/out: block to bufferfix +@param f in: file name where requested +@param l in: line number where requested */ +# define buf_block_buf_fix_inc(b,f,l) buf_block_buf_fix_inc_func(f,l,b) +#else /* UNIV_SYNC_DEBUG */ +/** Increments the bufferfix count. +@param b in/out: block to bufferfix +@param f in: file name where requested +@param l in: line number where requested */ +# define buf_block_buf_fix_inc(b,f,l) buf_block_buf_fix_inc_func(b) +#endif /* UNIV_SYNC_DEBUG */ /*******************************************************************//** Decrements the bufferfix count. */ @@ -1194,7 +1207,7 @@ buf_block_dbg_add_level( where we have acquired latch */ ulint level) /*!< in: latching order level */ { - sync_thread_add_level(&block->lock, level, FALSE); + sync_thread_add_level(&block->lock, level); } #endif /* UNIV_SYNC_DEBUG */ /********************************************************************//** diff --git a/storage/innobase/include/fsp0fsp.h b/storage/innobase/include/fsp0fsp.h index 2221380c9a2..7abd3914eda 100644 --- a/storage/innobase/include/fsp0fsp.h +++ b/storage/innobase/include/fsp0fsp.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2009, Innobase Oy. 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 @@ -176,18 +176,19 @@ fseg_n_reserved_pages( Allocates a single free page from a segment. This function implements the intelligent allocation strategy which tries to minimize file space fragmentation. -@param[in/out] seg_header segment header -@param[in] hint hint of which page would be desirable -@param[in] direction if the new page is needed because +@return the allocated page offset FIL_NULL if no page could be allocated */ +UNIV_INTERN +ulint +fseg_alloc_free_page( +/*=================*/ + fseg_header_t* seg_header, /*!< in: segment header */ + ulint hint, /*!< in: hint of which page would be desirable */ + byte direction, /*!< in: if the new page is needed because of an index page split, and records are inserted there in order, into which direction they go alphabetically: FSP_DOWN, - FSP_UP, FSP_NO_DIR -@param[in/out] mtr mini-transaction -@return the allocated page offset FIL_NULL if no page could be allocated */ -#define fseg_alloc_free_page(seg_header, hint, direction, mtr) \ - fseg_alloc_free_page_general(seg_header, hint, direction, \ - FALSE, mtr, mtr) + FSP_UP, FSP_NO_DIR */ + mtr_t* mtr); /*!< in: mtr handle */ /**********************************************************************//** Allocates a single free page from a segment. This function implements the intelligent allocation strategy which tries to minimize file space @@ -197,7 +198,7 @@ UNIV_INTERN ulint fseg_alloc_free_page_general( /*=========================*/ - fseg_header_t* seg_header,/*!< in/out: segment header */ + fseg_header_t* seg_header,/*!< in: segment header */ ulint hint, /*!< in: hint of which page would be desirable */ byte direction,/*!< in: if the new page is needed because of an index page split, and records are @@ -209,12 +210,7 @@ fseg_alloc_free_page_general( with fsp_reserve_free_extents, then there is no need to do the check for this individual page */ - mtr_t* mtr, /*!< in/out: mini-transaction */ - mtr_t* init_mtr)/*!< in/out: mtr or another mini-transaction - in which the page should be initialized, - or NULL if this is a "fake allocation" of - a page that was previously freed in mtr */ - __attribute__((warn_unused_result, nonnull(1,5))); + mtr_t* mtr); /*!< in: mtr handle */ /**********************************************************************//** Reserves free pages from a tablespace. All mini-transactions which may use several pages from the tablespace should call this function beforehand diff --git a/storage/innobase/include/mtr0mtr.h b/storage/innobase/include/mtr0mtr.h index 185a0953231..7f608546cc2 100644 --- a/storage/innobase/include/mtr0mtr.h +++ b/storage/innobase/include/mtr0mtr.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2009, Innobase Oy. 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 @@ -53,8 +53,6 @@ first 3 values must be RW_S_LATCH, RW_X_LATCH, RW_NO_LATCH */ #define MTR_MEMO_MODIFY 54 #define MTR_MEMO_S_LOCK 55 #define MTR_MEMO_X_LOCK 56 -/** The mini-transaction freed a clustered index leaf page. */ -#define MTR_MEMO_FREE_CLUST_LEAF 57 /** @name Log item types The log items are declared 'byte' so that the compiler can warn if val @@ -370,14 +368,11 @@ struct mtr_struct{ #endif dyn_array_t memo; /*!< memo stack for locks etc. */ dyn_array_t log; /*!< mini-transaction log */ - unsigned inside_ibuf:1; + ibool inside_ibuf; /*!< TRUE if inside ibuf changes */ - unsigned modifications:1; - /*!< TRUE if the mini-transaction - modified buffer pool pages */ - unsigned freed_clust_leaf:1; - /*!< TRUE if MTR_MEMO_FREE_CLUST_LEAF - was logged in the mini-transaction */ + ibool modifications; + /* TRUE if the mtr made modifications to + buffer pool pages */ ulint n_log_recs; /* count of how many page initial log records have been written to the mtr log */ diff --git a/storage/innobase/include/mtr0mtr.ic b/storage/innobase/include/mtr0mtr.ic index 3541f359338..1db4a4bd735 100644 --- a/storage/innobase/include/mtr0mtr.ic +++ b/storage/innobase/include/mtr0mtr.ic @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2010, Innobase Oy. 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 @@ -43,9 +43,8 @@ mtr_start( dyn_array_create(&(mtr->log)); mtr->log_mode = MTR_LOG_ALL; - mtr->inside_ibuf = FALSE; mtr->modifications = FALSE; - mtr->freed_clust_leaf = FALSE; + mtr->inside_ibuf = FALSE; mtr->n_log_recs = 0; ut_d(mtr->state = MTR_ACTIVE); @@ -67,8 +66,7 @@ mtr_memo_push( ut_ad(object); ut_ad(type >= MTR_MEMO_PAGE_S_FIX); - ut_ad(type <= MTR_MEMO_FREE_CLUST_LEAF); - ut_ad(type != MTR_MEMO_FREE_CLUST_LEAF || mtr->freed_clust_leaf); + ut_ad(type <= MTR_MEMO_X_LOCK); ut_ad(mtr); ut_ad(mtr->magic_n == MTR_MAGIC_N); ut_ad(mtr->state == MTR_ACTIVE); diff --git a/storage/innobase/include/page0cur.ic b/storage/innobase/include/page0cur.ic index 81474fa35f5..3520677dfb3 100644 --- a/storage/innobase/include/page0cur.ic +++ b/storage/innobase/include/page0cur.ic @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1994, 2009, Innobase Oy. 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 @@ -27,8 +27,6 @@ Created 10/4/1994 Heikki Tuuri #include "buf0types.h" #ifdef UNIV_DEBUG -# include "rem0cmp.h" - /*********************************************************//** Gets pointer to the page frame where the cursor is positioned. @return page */ @@ -270,7 +268,6 @@ page_cur_tuple_insert( index, rec, offsets, mtr); } - ut_ad(!rec || !cmp_dtuple_rec(tuple, rec, offsets)); mem_heap_free(heap); return(rec); } diff --git a/storage/innobase/include/page0page.h b/storage/innobase/include/page0page.h index ad1445b3935..6a82e820312 100644 --- a/storage/innobase/include/page0page.h +++ b/storage/innobase/include/page0page.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1994, 2009, Innobase Oy. 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 @@ -281,42 +281,16 @@ page_get_supremum_offset( const page_t* page); /*!< in: page which must have record(s) */ #define page_get_infimum_rec(page) ((page) + page_get_infimum_offset(page)) #define page_get_supremum_rec(page) ((page) + page_get_supremum_offset(page)) - /************************************************************//** -Returns the nth record of the record list. -This is the inverse function of page_rec_get_n_recs_before(). -@return nth record */ -UNIV_INTERN -const rec_t* -page_rec_get_nth_const( -/*===================*/ - const page_t* page, /*!< in: page */ - ulint nth) /*!< in: nth record */ - __attribute__((nonnull, warn_unused_result)); -/************************************************************//** -Returns the nth record of the record list. -This is the inverse function of page_rec_get_n_recs_before(). -@return nth record */ -UNIV_INLINE -rec_t* -page_rec_get_nth( -/*=============*/ - page_t* page, /*< in: page */ - ulint nth) /*!< in: nth record */ - __attribute__((nonnull, warn_unused_result)); - -#ifndef UNIV_HOTBACKUP -/************************************************************//** -Returns the middle record of the records on the page. If there is an -even number of records in the list, returns the first record of the -upper half-list. +Returns the middle record of record list. If there are an even number +of records in the list, returns the first record of upper half-list. @return middle record */ -UNIV_INLINE +UNIV_INTERN rec_t* page_get_middle_rec( /*================*/ - page_t* page) /*!< in: page */ - __attribute__((nonnull, warn_unused_result)); + page_t* page); /*!< in: page */ +#ifndef UNIV_HOTBACKUP /*************************************************************//** Compares a data tuple to a physical record. Differs from the function cmp_dtuple_rec_with_match in the way that the record must reside on an @@ -371,7 +345,6 @@ page_get_n_recs( /***************************************************************//** Returns the number of records before the given record in chain. The number includes infimum and supremum records. -This is the inverse function of page_rec_get_nth(). @return number of records */ UNIV_INTERN ulint diff --git a/storage/innobase/include/page0page.ic b/storage/innobase/include/page0page.ic index c1a0ce73982..115cee64f8b 100644 --- a/storage/innobase/include/page0page.ic +++ b/storage/innobase/include/page0page.ic @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1994, 2009, Innobase Oy. 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 @@ -419,37 +419,7 @@ page_rec_is_infimum( return(page_rec_is_infimum_low(page_offset(rec))); } -/************************************************************//** -Returns the nth record of the record list. -This is the inverse function of page_rec_get_n_recs_before(). -@return nth record */ -UNIV_INLINE -rec_t* -page_rec_get_nth( -/*=============*/ - page_t* page, /*!< in: page */ - ulint nth) /*!< in: nth record */ -{ - return((rec_t*) page_rec_get_nth_const(page, nth)); -} - #ifndef UNIV_HOTBACKUP -/************************************************************//** -Returns the middle record of the records on the page. If there is an -even number of records in the list, returns the first record of the -upper half-list. -@return middle record */ -UNIV_INLINE -rec_t* -page_get_middle_rec( -/*================*/ - page_t* page) /*!< in: page */ -{ - ulint middle = (page_get_n_recs(page) + PAGE_HEAP_NO_USER_LOW) / 2; - - return(page_rec_get_nth(page, middle)); -} - /*************************************************************//** Compares a data tuple to a physical record. Differs from the function cmp_dtuple_rec_with_match in the way that the record must reside on an diff --git a/storage/innobase/include/rem0rec.h b/storage/innobase/include/rem0rec.h index 46914d13c7f..10b74d18c13 100644 --- a/storage/innobase/include/rem0rec.h +++ b/storage/innobase/include/rem0rec.h @@ -480,7 +480,7 @@ ulint rec_offs_any_extern( /*================*/ const ulint* offsets);/*!< in: array returned by rec_get_offsets() */ -#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG +#ifdef UNIV_BLOB_NULL_DEBUG /******************************************************//** Determine if the offsets are for a record containing null BLOB pointers. @return first field containing a null BLOB pointer, or NULL if none found */ @@ -491,7 +491,7 @@ rec_offs_any_null_extern( const rec_t* rec, /*!< in: record */ const ulint* offsets) /*!< in: rec_get_offsets(rec) */ __attribute__((nonnull, warn_unused_result)); -#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ +#endif /* UNIV_BLOB_NULL_DEBUG */ /******************************************************//** Returns nonzero if the extern bit is set in nth field of rec. @return nonzero if externally stored */ diff --git a/storage/innobase/include/rem0rec.ic b/storage/innobase/include/rem0rec.ic index ebda6105bf1..dc8ed515c30 100644 --- a/storage/innobase/include/rem0rec.ic +++ b/storage/innobase/include/rem0rec.ic @@ -1088,7 +1088,7 @@ rec_offs_any_extern( return(UNIV_UNLIKELY(*rec_offs_base(offsets) & REC_OFFS_EXTERNAL)); } -#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG +#ifdef UNIV_BLOB_NULL_DEBUG /******************************************************//** Determine if the offsets are for a record containing null BLOB pointers. @return first field containing a null BLOB pointer, or NULL if none found */ @@ -1124,7 +1124,7 @@ rec_offs_any_null_extern( return(NULL); } -#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ +#endif /* UNIV_BLOB_NULL_DEBUG */ /******************************************************//** Returns nonzero if the extern bit is set in nth field of rec. diff --git a/storage/innobase/include/sync0rw.ic b/storage/innobase/include/sync0rw.ic index 5d15677ccce..2ffd9fdafb5 100644 --- a/storage/innobase/include/sync0rw.ic +++ b/storage/innobase/include/sync0rw.ic @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. Copyright (c) 2008, Google Inc. Portions of this file contain modifications contributed and copyrighted by @@ -603,16 +603,16 @@ rw_lock_x_unlock_direct( ut_ad((lock->lock_word % X_LOCK_DECR) == 0); +#ifdef UNIV_SYNC_DEBUG + rw_lock_remove_debug_info(lock, 0, RW_LOCK_EX); +#endif + if (lock->lock_word == 0) { lock->recursive = FALSE; UNIV_MEM_INVALID(&lock->writer_thread, sizeof lock->writer_thread); } -#ifdef UNIV_SYNC_DEBUG - rw_lock_remove_debug_info(lock, 0, RW_LOCK_EX); -#endif - lock->lock_word += X_LOCK_DECR; ut_ad(!lock->waiters); diff --git a/storage/innobase/include/sync0sync.h b/storage/innobase/include/sync0sync.h index f6b8897522f..d9dea0aa63d 100644 --- a/storage/innobase/include/sync0sync.h +++ b/storage/innobase/include/sync0sync.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2011, Innobase Oy. All Rights Reserved. Copyright (c) 2008, Google Inc. Portions of this file contain modifications contributed and copyrighted by @@ -400,10 +400,8 @@ void sync_thread_add_level( /*==================*/ void* latch, /*!< in: pointer to a mutex or an rw-lock */ - ulint level, /*!< in: level in the latching order; if + ulint level); /*!< in: level in the latching order; if SYNC_LEVEL_VARYING, nothing is done */ - ibool relock) /*!< in: TRUE if re-entering an x-lock */ - __attribute__((nonnull)); /******************************************************************//** Removes a latch from the thread level array if it is found there. @return TRUE if found in the array; it is no error if the latch is diff --git a/storage/innobase/include/univ.i b/storage/innobase/include/univ.i index cb175c2c234..e86cd4402bf 100644 --- a/storage/innobase/include/univ.i +++ b/storage/innobase/include/univ.i @@ -1,7 +1,8 @@ /***************************************************************************** -Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1994, 2010, Innobase Oy. All Rights Reserved. Copyright (c) 2008, Google Inc. +Copyright (c) 2009, Sun Microsystems, Inc. Portions of this file contain modifications contributed and copyrighted by Google, Inc. Those modifications are gratefully acknowledged and are described @@ -185,6 +186,8 @@ command. Not tested on Windows. */ debugging without UNIV_DEBUG */ #define UNIV_BLOB_LIGHT_DEBUG /* Enable off-page column debugging without UNIV_DEBUG */ +#define UNIV_BLOB_NULL_DEBUG /* Enable deep off-page + column debugging */ #define UNIV_DEBUG /* Enable ut_ad() assertions and disable UNIV_INLINE */ #define UNIV_DEBUG_LOCK_VALIDATE /* Enable diff --git a/storage/innobase/mtr/mtr0mtr.c b/storage/innobase/mtr/mtr0mtr.c index fde87cb3cd3..08234609ff0 100644 --- a/storage/innobase/mtr/mtr0mtr.c +++ b/storage/innobase/mtr/mtr0mtr.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2009, Innobase Oy. 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 @@ -64,11 +64,12 @@ mtr_memo_slot_release( buf_page_release((buf_block_t*)object, type); } else if (type == MTR_MEMO_S_LOCK) { rw_lock_s_unlock((rw_lock_t*)object); +#ifdef UNIV_DEBUG } else if (type != MTR_MEMO_X_LOCK) { - ut_ad(type == MTR_MEMO_MODIFY - || type == MTR_MEMO_FREE_CLUST_LEAF); + ut_ad(type == MTR_MEMO_MODIFY); ut_ad(mtr_memo_contains(mtr, object, MTR_MEMO_PAGE_X_FIX)); +#endif /* UNIV_DEBUG */ } else { rw_lock_x_unlock((rw_lock_t*)object); } diff --git a/storage/innobase/page/page0cur.c b/storage/innobase/page/page0cur.c index b8c492328e8..936762b986a 100644 --- a/storage/innobase/page/page0cur.c +++ b/storage/innobase/page/page0cur.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1994, 2009, Innobase Oy. 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 @@ -1180,15 +1180,14 @@ page_cur_insert_rec_zip_reorg( /* Before trying to reorganize the page, store the number of preceding records on the page. */ pos = page_rec_get_n_recs_before(rec); - ut_ad(pos > 0); if (page_zip_reorganize(block, index, mtr)) { /* The page was reorganized: Find rec by seeking to pos, and update *current_rec. */ - if (pos > 1) { - rec = page_rec_get_nth(page, pos - 1); - } else { - rec = page + PAGE_NEW_INFIMUM; + rec = page + PAGE_NEW_INFIMUM; + + while (--pos) { + rec = page + rec_get_next_offs(rec, TRUE); } *current_rec = rec; @@ -1284,12 +1283,6 @@ page_cur_insert_rec_zip( insert_rec = page_cur_insert_rec_zip_reorg( current_rec, block, index, insert_rec, page, page_zip, mtr); -#ifdef UNIV_DEBUG - if (insert_rec) { - rec_offs_make_valid( - insert_rec, index, offsets); - } -#endif /* UNIV_DEBUG */ } return(insert_rec); diff --git a/storage/innobase/page/page0page.c b/storage/innobase/page/page0page.c index 1c74a1d5cab..6064d028ae1 100644 --- a/storage/innobase/page/page0page.c +++ b/storage/innobase/page/page0page.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1994, 2010, Innobase Oy. 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 @@ -1465,54 +1465,55 @@ page_dir_balance_slot( } } +#ifndef UNIV_HOTBACKUP /************************************************************//** -Returns the nth record of the record list. -This is the inverse function of page_rec_get_n_recs_before(). -@return nth record */ +Returns the middle record of the record list. If there are an even number +of records in the list, returns the first record of the upper half-list. +@return middle record */ UNIV_INTERN -const rec_t* -page_rec_get_nth_const( -/*===================*/ - const page_t* page, /*!< in: page */ - ulint nth) /*!< in: nth record */ +rec_t* +page_get_middle_rec( +/*================*/ + page_t* page) /*!< in: page */ { - const page_dir_slot_t* slot; + page_dir_slot_t* slot; + ulint middle; ulint i; ulint n_owned; - const rec_t* rec; + ulint count; + rec_t* rec; - ut_ad(nth < UNIV_PAGE_SIZE / (REC_N_NEW_EXTRA_BYTES + 1)); + /* This many records we must leave behind */ + middle = (page_get_n_recs(page) + PAGE_HEAP_NO_USER_LOW) / 2; + + count = 0; for (i = 0;; i++) { slot = page_dir_get_nth_slot(page, i); n_owned = page_dir_slot_get_n_owned(slot); - if (n_owned > nth) { + if (count + n_owned > middle) { break; } else { - nth -= n_owned; + count += n_owned; } } ut_ad(i > 0); slot = page_dir_get_nth_slot(page, i - 1); - rec = page_dir_slot_get_rec(slot); + rec = (rec_t*) page_dir_slot_get_rec(slot); + rec = page_rec_get_next(rec); - if (page_is_comp(page)) { - do { - rec = page_rec_get_next_low(rec, TRUE); - ut_ad(rec); - } while (nth--); - } else { - do { - rec = page_rec_get_next_low(rec, FALSE); - ut_ad(rec); - } while (nth--); + /* There are now count records behind rec */ + + for (i = 0; i < middle - count; i++) { + rec = page_rec_get_next(rec); } return(rec); } +#endif /* !UNIV_HOTBACKUP */ /***************************************************************//** Returns the number of records before the given record in chain. @@ -1574,7 +1575,6 @@ page_rec_get_n_recs_before( n--; ut_ad(n >= 0); - ut_ad(n < UNIV_PAGE_SIZE / (REC_N_NEW_EXTRA_BYTES + 1)); return((ulint) n); } diff --git a/storage/innobase/row/row0ins.c b/storage/innobase/row/row0ins.c index 5f10a763fc4..2925feb2904 100644 --- a/storage/innobase/row/row0ins.c +++ b/storage/innobase/row/row0ins.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1996, 2010, Innobase Oy. 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 @@ -348,9 +348,9 @@ row_ins_clust_index_entry_by_modify( return(DB_LOCK_TABLE_FULL); } - err = btr_cur_pessimistic_update( - BTR_KEEP_POS_FLAG, cursor, heap, big_rec, update, - 0, thr, mtr); + err = btr_cur_pessimistic_update(0, cursor, + heap, big_rec, update, + 0, thr, mtr); } return(err); @@ -1976,7 +1976,6 @@ row_ins_index_entry_low( ulint modify = 0; /* remove warning */ rec_t* insert_rec; rec_t* rec; - ulint* offsets; ulint err; ulint n_unique; big_rec_t* big_rec = NULL; @@ -2084,51 +2083,6 @@ row_ins_index_entry_low( err = row_ins_clust_index_entry_by_modify( mode, &cursor, &heap, &big_rec, entry, thr, &mtr); - - if (big_rec) { - ut_a(err == DB_SUCCESS); - /* Write out the externally stored - columns, but allocate the pages and - write the pointers using the - mini-transaction of the record update. - If any pages were freed in the update, - temporarily mark them allocated so - that off-page columns will not - overwrite them. We must do this, - because we will write the redo log for - the BLOB writes before writing the - redo log for the record update. Thus, - redo log application at crash recovery - will see BLOBs being written to free pages. */ - - btr_mark_freed_leaves(index, &mtr, TRUE); - - rec = btr_cur_get_rec(&cursor); - offsets = rec_get_offsets( - rec, index, NULL, - ULINT_UNDEFINED, &heap); - - err = btr_store_big_rec_extern_fields( - index, btr_cur_get_block(&cursor), - rec, offsets, big_rec, &mtr, - FALSE, &mtr); - /* If writing big_rec fails (for - example, because of DB_OUT_OF_FILE_SPACE), - the record will be corrupted. Even if - we did not update any externally - stored columns, our update could cause - the record to grow so that a - non-updated column was selected for - external storage. This non-update - would not have been written to the - undo log, and thus the record cannot - be rolled back. */ - ut_a(err == DB_SUCCESS); - /* Free the pages again - in order to avoid a leak. */ - btr_mark_freed_leaves(index, &mtr, FALSE); - goto stored_big_rec; - } } else { ut_ad(!n_ext); err = row_ins_sec_index_entry_by_modify( @@ -2157,6 +2111,8 @@ function_exit: mtr_commit(&mtr); if (UNIV_LIKELY_NULL(big_rec)) { + rec_t* rec; + ulint* offsets; mtr_start(&mtr); btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE, @@ -2168,9 +2124,8 @@ function_exit: err = btr_store_big_rec_extern_fields( index, btr_cur_get_block(&cursor), - rec, offsets, big_rec, &mtr, FALSE, NULL); + rec, offsets, &mtr, FALSE, big_rec); -stored_big_rec: if (modify) { dtuple_big_rec_free(big_rec); } else { @@ -2443,7 +2398,7 @@ row_ins( node->index = dict_table_get_next_index(node->index); node->entry = UT_LIST_GET_NEXT(tuple_list, node->entry); - /* Skip corrupted secondary index and its entry */ + /* Skip corrupted secondar index and its entry */ while (node->index && dict_index_is_corrupted(node->index)) { node->index = dict_table_get_next_index(node->index); diff --git a/storage/innobase/row/row0row.c b/storage/innobase/row/row0row.c index 8892c8dc289..20fd475343e 100644 --- a/storage/innobase/row/row0row.c +++ b/storage/innobase/row/row0row.c @@ -233,7 +233,6 @@ row_build( ut_ad(index && rec && heap); ut_ad(dict_index_is_clust(index)); - ut_ad(!mutex_own(&kernel_mutex)); if (!offsets) { offsets = rec_get_offsets(rec, index, offsets_, @@ -242,22 +241,13 @@ row_build( ut_ad(rec_offs_validate(rec, index, offsets)); } -#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG - if (rec_offs_any_null_extern(rec, offsets)) { - /* This condition can occur during crash recovery - before trx_rollback_active() has completed execution. - - This condition is possible if the server crashed - during an insert or update-by-delete-and-insert before - btr_store_big_rec_extern_fields() did mtr_commit() all - BLOB pointers to the freshly inserted clustered index - record. */ - ut_a(trx_assert_recovered( - row_get_rec_trx_id(rec, index, offsets))); - ut_a(trx_undo_roll_ptr_is_insert( - row_get_rec_roll_ptr(rec, index, offsets))); - } -#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ +#if 0 && defined UNIV_BLOB_NULL_DEBUG + /* This one can fail in trx_rollback_active() if + the server crashed during an insert before the + btr_store_big_rec_extern_fields() did mtr_commit() + all BLOB pointers to the clustered index record. */ + ut_a(!rec_offs_any_null_extern(rec, offsets)); +#endif /* 0 && UNIV_BLOB_NULL_DEBUG */ if (type != ROW_COPY_POINTERS) { /* Take a copy of rec to heap */ @@ -442,10 +432,10 @@ row_rec_to_index_entry( rec = rec_copy(buf, rec, offsets); /* Avoid a debug assertion in rec_offs_validate(). */ rec_offs_make_valid(rec, index, offsets); -#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG +#ifdef UNIV_BLOB_NULL_DEBUG } else { ut_a(!rec_offs_any_null_extern(rec, offsets)); -#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ +#endif /* UNIV_BLOB_NULL_DEBUG */ } entry = row_rec_to_index_entry_low(rec, index, offsets, n_ext, heap); diff --git a/storage/innobase/row/row0upd.c b/storage/innobase/row/row0upd.c index 2401fc88553..765233c8dab 100644 --- a/storage/innobase/row/row0upd.c +++ b/storage/innobase/row/row0upd.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1996, 2010, Innobase Oy. 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 @@ -1999,46 +1999,28 @@ row_upd_clust_rec( ut_ad(!rec_get_deleted_flag(btr_pcur_get_rec(pcur), dict_table_is_comp(index->table))); - err = btr_cur_pessimistic_update( - BTR_NO_LOCKING_FLAG | BTR_KEEP_POS_FLAG, btr_cur, - &heap, &big_rec, node->update, node->cmpl_info, thr, mtr); - if (big_rec) { + err = btr_cur_pessimistic_update(BTR_NO_LOCKING_FLAG, btr_cur, + &heap, &big_rec, node->update, + node->cmpl_info, thr, mtr); + mtr_commit(mtr); + + if (err == DB_SUCCESS && big_rec) { ulint offsets_[REC_OFFS_NORMAL_SIZE]; rec_t* rec; rec_offs_init(offsets_); - ut_a(err == DB_SUCCESS); - /* Write out the externally stored columns, but - allocate the pages and write the pointers using the - mini-transaction of the record update. If any pages - were freed in the update, temporarily mark them - allocated so that off-page columns will not overwrite - them. We must do this, because we write the redo log - for the BLOB writes before writing the redo log for - the record update. */ + mtr_start(mtr); - btr_mark_freed_leaves(index, mtr, TRUE); + ut_a(btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, mtr)); rec = btr_cur_get_rec(btr_cur); err = btr_store_big_rec_extern_fields( index, btr_cur_get_block(btr_cur), rec, rec_get_offsets(rec, index, offsets_, ULINT_UNDEFINED, &heap), - big_rec, mtr, TRUE, mtr); - /* If writing big_rec fails (for example, because of - DB_OUT_OF_FILE_SPACE), the record will be corrupted. - Even if we did not update any externally stored - columns, our update could cause the record to grow so - that a non-updated column was selected for external - storage. This non-update would not have been written - to the undo log, and thus the record cannot be rolled - back. */ - ut_a(err == DB_SUCCESS); - /* Free the pages again in order to avoid a leak. */ - btr_mark_freed_leaves(index, mtr, FALSE); + mtr, TRUE, big_rec); + mtr_commit(mtr); } - mtr_commit(mtr); - if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); } diff --git a/storage/innobase/row/row0vers.c b/storage/innobase/row/row0vers.c index abd065ce1ff..5fd7d082194 100644 --- a/storage/innobase/row/row0vers.c +++ b/storage/innobase/row/row0vers.c @@ -550,10 +550,10 @@ row_vers_build_for_consistent_read( /* The view already sees this version: we can copy it to in_heap and return */ -#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG +#ifdef UNIV_BLOB_NULL_DEBUG ut_a(!rec_offs_any_null_extern( version, *offsets)); -#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ +#endif /* UNIV_BLOB_NULL_DEBUG */ buf = mem_heap_alloc(in_heap, rec_offs_size(*offsets)); @@ -588,9 +588,9 @@ row_vers_build_for_consistent_read( *offsets = rec_get_offsets(prev_version, index, *offsets, ULINT_UNDEFINED, offset_heap); -#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG +#ifdef UNIV_BLOB_NULL_DEBUG ut_a(!rec_offs_any_null_extern(prev_version, *offsets)); -#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ +#endif /* UNIV_BLOB_NULL_DEBUG */ trx_id = row_get_rec_trx_id(prev_version, index, *offsets); @@ -691,9 +691,9 @@ row_vers_build_for_semi_consistent_read( /* We found a version that belongs to a committed transaction: return it. */ -#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG +#ifdef UNIV_BLOB_NULL_DEBUG ut_a(!rec_offs_any_null_extern(version, *offsets)); -#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ +#endif /* UNIV_BLOB_NULL_DEBUG */ if (rec == version) { *old_vers = rec; @@ -752,9 +752,9 @@ row_vers_build_for_semi_consistent_read( version = prev_version; *offsets = rec_get_offsets(version, index, *offsets, ULINT_UNDEFINED, offset_heap); -#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG +#ifdef UNIV_BLOB_NULL_DEBUG ut_a(!rec_offs_any_null_extern(version, *offsets)); -#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ +#endif /* UNIV_BLOB_NULL_DEBUG */ }/* for (;;) */ if (heap) { diff --git a/storage/innobase/sync/sync0rw.c b/storage/innobase/sync/sync0rw.c index 5b72e0afdf4..397d505df50 100644 --- a/storage/innobase/sync/sync0rw.c +++ b/storage/innobase/sync/sync0rw.c @@ -782,9 +782,7 @@ rw_lock_add_debug_info( rw_lock_debug_mutex_exit(); if ((pass == 0) && (lock_type != RW_LOCK_WAIT_EX)) { - sync_thread_add_level(lock, lock->level, - lock_type == RW_LOCK_EX - && lock->lock_word < 0); + sync_thread_add_level(lock, lock->level); } } diff --git a/storage/innobase/sync/sync0sync.c b/storage/innobase/sync/sync0sync.c index af6e3f0e275..8ea57b8655c 100644 --- a/storage/innobase/sync/sync0sync.c +++ b/storage/innobase/sync/sync0sync.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2011, Innobase Oy. All Rights Reserved. Copyright (c) 2008, Google Inc. Portions of this file contain modifications contributed and copyrighted by @@ -690,7 +690,7 @@ mutex_set_debug_info( ut_ad(mutex); ut_ad(file_name); - sync_thread_add_level(mutex, mutex->level, FALSE); + sync_thread_add_level(mutex, mutex->level); mutex->file_name = file_name; mutex->line = line; @@ -1133,9 +1133,8 @@ void sync_thread_add_level( /*==================*/ void* latch, /*!< in: pointer to a mutex or an rw-lock */ - ulint level, /*!< in: level in the latching order; if + ulint level) /*!< in: level in the latching order; if SYNC_LEVEL_VARYING, nothing is done */ - ibool relock) /*!< in: TRUE if re-entering an x-lock */ { ulint i; sync_level_t* slot; @@ -1186,10 +1185,6 @@ sync_thread_add_level( array = thread_slot->levels; - if (relock) { - goto levels_ok; - } - /* NOTE that there is a problem with _NODE and _LEAF levels: if the B-tree height changes, then a leaf can change to an internal node or the other way around. We do not know at present if this can cause @@ -1366,7 +1361,6 @@ sync_thread_add_level( ut_error; } -levels_ok: if (array->next_free == ULINT_UNDEFINED) { ut_a(array->n_elems < array->max_elems); diff --git a/storage/innobase/trx/trx0rec.c b/storage/innobase/trx/trx0rec.c index ad209110e60..0bf41780fcc 100644 --- a/storage/innobase/trx/trx0rec.c +++ b/storage/innobase/trx/trx0rec.c @@ -1621,9 +1621,9 @@ trx_undo_prev_version_build( return(DB_ERROR); } -# if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG +# ifdef UNIV_BLOB_NULL_DEBUG ut_a(!rec_offs_any_null_extern(rec, offsets)); -# endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ +# endif /* UNIV_BLOB_NULL_DEBUG */ if (row_upd_changes_field_size_or_external(index, offsets, update)) { ulint n_ext; diff --git a/storage/innobase/trx/trx0undo.c b/storage/innobase/trx/trx0undo.c index 805fdcee242..dae0637f72c 100644 --- a/storage/innobase/trx/trx0undo.c +++ b/storage/innobase/trx/trx0undo.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1996, 2009, Innobase Oy. 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 @@ -918,7 +918,7 @@ trx_undo_add_page( page_no = fseg_alloc_free_page_general(header_page + TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER, undo->top_page_no + 1, FSP_UP, - TRUE, mtr, mtr); + TRUE, mtr); fil_space_release_free_extents(undo->space, n_reserved); From 4e26afa01b3c711772e4bd33ae75ac13d6c0ae20 Mon Sep 17 00:00:00 2001 From: Joerg Bruehe Date: Tue, 4 Oct 2011 12:28:30 +0200 Subject: [PATCH 020/288] Exclude NDB man pages from a source tarball, these sources don't have any current NDB. man/CMakeLists.txt: This will need to be modified as soon as NDB is added to the 5.5 sources, then the man page exclusion should be controlled by the build option also governing NDB use. --- man/CMakeLists.txt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/man/CMakeLists.txt b/man/CMakeLists.txt index 135d66634e4..4987a5bee61 100644 --- a/man/CMakeLists.txt +++ b/man/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2006, 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 @@ -16,15 +16,23 @@ # Copy man pages FILE(GLOB MAN1_FILES *.1) FILE(GLOB MAN1_EXCLUDE make_win_bin_dist.1) +FILE(GLOB MAN1_NDB ndb*.1) FILE(GLOB MAN8_FILES *.8) +FILE(GLOB MAN8_NDB ndb*.8) IF(MAN1_FILES) IF(MAN1_EXCLUDE) LIST(REMOVE_ITEM MAN1_FILES ${MAN1_EXCLUDE}) ENDIF() + IF(MAN1_NDB) + LIST(REMOVE_ITEM MAN1_FILES ${MAN1_NDB}) + ENDIF() INSTALL(FILES ${MAN1_FILES} DESTINATION ${INSTALL_MANDIR}/man1 COMPONENT ManPages) ENDIF() IF(MAN8_FILES) + IF(MAN8_NDB) + LIST(REMOVE_ITEM MAN8_FILES ${MAN8_NDB}) + ENDIF() INSTALL(FILES ${MAN8_FILES} DESTINATION ${INSTALL_MANDIR}/man8 COMPONENT ManPages) ENDIF() From d740f9e603378c2ba9bbfacd111f6fe9c6728b78 Mon Sep 17 00:00:00 2001 From: Tatjana Azundris Nuernberg Date: Thu, 6 Oct 2011 11:23:46 +0100 Subject: [PATCH 021/288] additional clean-up for 11765687 --- sql/sql_view.cc | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/sql/sql_view.cc b/sql/sql_view.cc index c318f79eec1..3ae35e5cfe0 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -1164,22 +1164,23 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table, with "security_ctx" member set to 0, i.e. forcing check_table_access() to use active user's security context. - There is no need for creating similar copies of table list elements - for underlying tables since they are just have been constructed and - thus have TABLE_LIST::security_ctx == 0 and fresh TABLE_LIST::grant - member. + There is no need for creating similar copies of TABLE_LIST elements + for underlying tables since they just have been constructed and thus + have TABLE_LIST::security_ctx == 0 and fresh TABLE_LIST::grant member. Finally at this point making sure we have SHOW_VIEW_ACL on the views will suffice as we implicitly require SELECT_ACL anyway. */ - TABLE_LIST view; - bzero((char *)&view, sizeof(TABLE_LIST)); - view.db= table->db; - view.table_name= table->table_name; + TABLE_LIST view_no_suid; + bzero(static_cast(&view_no_suid), sizeof(TABLE_LIST)); + view_no_suid.db= table->db; + view_no_suid.table_name= table->table_name; + + DBUG_ASSERT(view_tables == NULL || view_tables->security_ctx == NULL); if (check_table_access(thd, SELECT_ACL, view_tables, 1) || - check_table_access(thd, SHOW_VIEW_ACL, &view, 1)) + check_table_access(thd, SHOW_VIEW_ACL, &view_no_suid, 1)) { my_message(ER_VIEW_NO_EXPLAIN, ER(ER_VIEW_NO_EXPLAIN), MYF(0)); goto err; From f36e854ac6ce19e7018addbb8701796006a27134 Mon Sep 17 00:00:00 2001 From: Magne Mahre Date: Fri, 7 Oct 2011 14:08:31 +0200 Subject: [PATCH 022/288] BUG#12589870 CRASHES WITH MULTIQUERY PACKET + USE + QUERY CACHE A buffer large enough to hold the query _plus_ some additional data is allocated before parsing is started. The additional data is used by the query cache, and consists of the name of the current database and a set of flags. When a packet containing multiple SQL statements is sent to the server and one of the statements changes the current database (a "USE " statement), and the name of the new current database is longer than of the previous, there is not enough space in the buffer for the new name, and we write out over the buffer boundary. The fix adds an extra field to store the number of bytes allocated to the database name in the buffer. If the current database name changes, and the new name is longer than the previous one, we refuse to cache the query. --- sql/sp_head.cc | 12 +++++++++++- sql/sql_cache.cc | 33 ++++++++++++++++++++++++++++----- sql/sql_parse.cc | 21 +++++++++++++++++++-- 3 files changed, 58 insertions(+), 8 deletions(-) diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 95a7eda0540..70ffb0a36ab 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1029,12 +1029,22 @@ subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str) /* Allocate additional space at the end of the new query string for the query_cache_send_result_to_client function. + + The query buffer layout is: + buffer :== + The input statement(s) + '\0' Terminating null char + Length of following current database name (size_t) + Name of current database + Flags struct */ - buf_len= qbuf.length() + thd->db_length + 1 + QUERY_CACHE_FLAGS_SIZE + 1; + buf_len= qbuf.length() + 1 + sizeof(size_t) + thd->db_length + + QUERY_CACHE_FLAGS_SIZE + 1; if ((pbuf= (char *) alloc_root(thd->mem_root, buf_len))) { memcpy(pbuf, qbuf.ptr(), qbuf.length()); pbuf[qbuf.length()]= 0; + *(size_t *)(pbuf+qbuf.length()+1)= thd->db_length; } else DBUG_RETURN(TRUE); diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index b791428eef0..4800fdedbe5 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -1241,8 +1241,8 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d", /* Key is query + database + flag */ if (thd->db_length) { - memcpy(thd->query() + thd->query_length() + 1, thd->db, - thd->db_length); + memcpy(thd->query() + thd->query_length() + 1 + sizeof(size_t), + thd->db, thd->db_length); DBUG_PRINT("qcache", ("database: %s length: %u", thd->db, (unsigned) thd->db_length)); } @@ -1251,7 +1251,7 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d", DBUG_PRINT("qcache", ("No active database")); } tot_length= thd->query_length() + thd->db_length + 1 + - QUERY_CACHE_FLAGS_SIZE; + sizeof(size_t) + QUERY_CACHE_FLAGS_SIZE; /* We should only copy structure (don't use it location directly) because of alignment issue @@ -1462,7 +1462,28 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) goto err; } } + { + /* + We have allocated buffer space (in alloc_query) to hold the + SQL statement(s) + the current database name + a flags struct. + If the database name has changed during execution, which might + happen if there are multiple statements, we need to make + sure the new current database has a name with the same length + as the previous one. + */ + size_t *db_len= (size_t *) (sql + query_length + 1); + if (thd->db_length != *db_len) + { + /* + We should probably reallocate the buffer in this case, + but for now we just leave it uncached + */ + DBUG_PRINT("qcache", + ("Current database has changed since start of query")); + goto err; + } + } /* Try to obtain an exclusive lock on the query cache. If the cache is disabled or if a full cache flush is in progress, the attempt to @@ -1484,10 +1505,12 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) Query_cache_block *query_block; - tot_length= query_length + thd->db_length + 1 + QUERY_CACHE_FLAGS_SIZE; + tot_length= query_length + 1 + sizeof(size_t) + + thd->db_length + QUERY_CACHE_FLAGS_SIZE; + if (thd->db_length) { - memcpy(sql+query_length+1, thd->db, thd->db_length); + memcpy(sql + query_length + 1 + sizeof(size_t), thd->db, thd->db_length); DBUG_PRINT("qcache", ("database: '%s' length: %u", thd->db, (unsigned)thd->db_length)); } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index b5864fef19d..55509a31f77 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1912,13 +1912,30 @@ bool alloc_query(THD *thd, const char *packet, uint packet_length) pos--; packet_length--; } - /* We must allocate some extra memory for query cache */ + /* We must allocate some extra memory for query cache + + The query buffer layout is: + buffer :== + The input statement(s) + '\0' Terminating null char (1 byte) + Length of following current database name (size_t) + Name of current database + Flags struct + */ if (! (query= (char*) thd->memdup_w_gap(packet, packet_length, - 1 + thd->db_length + + 1 + sizeof(size_t) + thd->db_length + QUERY_CACHE_FLAGS_SIZE))) return TRUE; query[packet_length]= '\0'; + /* + Space to hold the name of the current database is allocated. We + also store this length, in case current database is changed during + execution. We might need to reallocate the 'query' buffer + */ + size_t *len = (size_t *) (query + packet_length + 1); + *len= thd->db_length; + thd->set_query(query, packet_length); /* Reclaim some memory */ From 22fdbd40d4daae0ba7fed2edc04348f1026c7951 Mon Sep 17 00:00:00 2001 From: Joerg Bruehe Date: Mon, 10 Oct 2011 14:03:29 +0200 Subject: [PATCH 023/288] Test "file_contents" failed in non-community RPMs on SuSE because the search pattern for the "INFO_*" files was not general enough: Fixed. --- mysql-test/t/file_contents.test | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mysql-test/t/file_contents.test b/mysql-test/t/file_contents.test index 33cd65fb2b4..965f6c3b363 100644 --- a/mysql-test/t/file_contents.test +++ b/mysql-test/t/file_contents.test @@ -15,9 +15,9 @@ if ($dir_bin =~ m|/usr/|) { # RPM package $dir_docs = $dir_bin; $dir_docs =~ s|/lib|/share/doc|; - if(-d "$dir_docs/packages/MySQL-server") { - # SuSE - $dir_docs = "$dir_docs/packages/MySQL-server"; + if(-d "$dir_docs/packages") { + # SuSE: "packages/" in the documentation path + $dir_docs = glob "$dir_docs/packages/MySQL-server*"; } else { # RedHat: version number in directory name $dir_docs = glob "$dir_docs/MySQL-server*"; @@ -25,9 +25,9 @@ if ($dir_bin =~ m|/usr/|) { } elsif ($dir_bin =~ m|/usr$|) { # RPM build during development $dir_docs = "$dir_bin/share/doc"; - if(-d "$dir_docs/packages/MySQL-server") { - # SuSE - $dir_docs = "$dir_docs/packages/MySQL-server"; + if(-d "$dir_docs/packages") { + # SuSE: "packages/" in the documentation path + $dir_docs = glob "$dir_docs/packages/MySQL-server*"; } else { # RedHat: version number in directory name $dir_docs = glob "$dir_docs/MySQL-server*"; From 73db2a1504188611c3348e1bd55d181aea6ab533 Mon Sep 17 00:00:00 2001 From: Vinay Fisrekar Date: Wed, 12 Oct 2011 10:10:52 +0530 Subject: [PATCH 024/288] bug#11766457 - adjusting/modifying the the tests as tests were failing if system time zone is set differently. --- mysql-test/suite/engines/funcs/r/de_calendar_range.result | 2 ++ .../in_calendar_2_unique_constraints_duplicate_update.result | 2 ++ .../r/in_calendar_pk_constraint_duplicate_update.result | 2 ++ .../engines/funcs/r/in_calendar_pk_constraint_error.result | 2 ++ .../engines/funcs/r/in_calendar_pk_constraint_ignore.result | 2 ++ .../r/in_calendar_unique_constraint_duplicate_update.result | 2 ++ .../funcs/r/in_calendar_unique_constraint_error.result | 2 ++ .../funcs/r/in_calendar_unique_constraint_ignore.result | 2 ++ ...ulticolumn_calendar_pk_constraint_duplicate_update.result | 2 ++ .../r/in_multicolumn_calendar_pk_constraint_error.result | 2 ++ .../r/in_multicolumn_calendar_pk_constraint_ignore.result | 2 ++ ...column_calendar_unique_constraint_duplicate_update.result | 2 ++ .../r/in_multicolumn_calendar_unique_constraint_error.result | 2 ++ .../in_multicolumn_calendar_unique_constraint_ignore.result | 2 ++ ..._multicolumn_number_pk_constraint_duplicate_update.result | 2 ++ mysql-test/suite/engines/funcs/r/up_calendar_range.result | 2 ++ mysql-test/suite/engines/funcs/t/de_calendar_range.test | 5 ++++- .../t/in_calendar_2_unique_constraints_duplicate_update.test | 4 ++++ .../funcs/t/in_calendar_pk_constraint_duplicate_update.test | 5 ++++- .../engines/funcs/t/in_calendar_pk_constraint_error.test | 5 ++++- .../engines/funcs/t/in_calendar_pk_constraint_ignore.test | 4 ++++ .../t/in_calendar_unique_constraint_duplicate_update.test | 5 ++++- .../engines/funcs/t/in_calendar_unique_constraint_error.test | 5 ++++- .../funcs/t/in_calendar_unique_constraint_ignore.test | 5 ++++- ..._multicolumn_calendar_pk_constraint_duplicate_update.test | 4 ++++ .../funcs/t/in_multicolumn_calendar_pk_constraint_error.test | 5 ++++- .../t/in_multicolumn_calendar_pk_constraint_ignore.test | 5 ++++- ...ticolumn_calendar_unique_constraint_duplicate_update.test | 5 ++++- .../t/in_multicolumn_calendar_unique_constraint_error.test | 5 ++++- .../t/in_multicolumn_calendar_unique_constraint_ignore.test | 4 ++++ ...in_multicolumn_number_pk_constraint_duplicate_update.test | 4 ++++ mysql-test/suite/engines/funcs/t/up_calendar_range.test | 5 ++++- 32 files changed, 96 insertions(+), 11 deletions(-) diff --git a/mysql-test/suite/engines/funcs/r/de_calendar_range.result b/mysql-test/suite/engines/funcs/r/de_calendar_range.result index 904b14c06b5..07543e0c8c4 100644 --- a/mysql-test/suite/engines/funcs/r/de_calendar_range.result +++ b/mysql-test/suite/engines/funcs/r/de_calendar_range.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1,t2,t3; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL PRIMARY KEY); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1) VALUES(NOW()); @@ -89,3 +90,4 @@ c1 2007-02-16 12:10:34 2007-02-17 13:10:34 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/r/in_calendar_2_unique_constraints_duplicate_update.result b/mysql-test/suite/engines/funcs/r/in_calendar_2_unique_constraints_duplicate_update.result index 7479cf3ea0b..9c56e23574d 100644 --- a/mysql-test/suite/engines/funcs/r/in_calendar_2_unique_constraints_duplicate_update.result +++ b/mysql-test/suite/engines/funcs/r/in_calendar_2_unique_constraints_duplicate_update.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL, c2 DATE NULL, c3 DATE NULL, PRIMARY KEY(c1), UNIQUE(c2)); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),ADDTIME(NOW(),'4 04:01:01'),NOW()); @@ -128,3 +129,4 @@ c1 c2 c3 2003 2001 2000 2004 2000 2000 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/r/in_calendar_pk_constraint_duplicate_update.result b/mysql-test/suite/engines/funcs/r/in_calendar_pk_constraint_duplicate_update.result index 763e9f564c6..47355681eae 100644 --- a/mysql-test/suite/engines/funcs/r/in_calendar_pk_constraint_duplicate_update.result +++ b/mysql-test/suite/engines/funcs/r/in_calendar_pk_constraint_duplicate_update.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL PRIMARY KEY); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1) VALUES(NOW()); @@ -82,3 +83,4 @@ c1 2000 2011 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/r/in_calendar_pk_constraint_error.result b/mysql-test/suite/engines/funcs/r/in_calendar_pk_constraint_error.result index 3f2b1546995..f8bff355901 100644 --- a/mysql-test/suite/engines/funcs/r/in_calendar_pk_constraint_error.result +++ b/mysql-test/suite/engines/funcs/r/in_calendar_pk_constraint_error.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL PRIMARY KEY); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1) VALUES(NOW()); @@ -87,3 +88,4 @@ c1 1999 2000 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/r/in_calendar_pk_constraint_ignore.result b/mysql-test/suite/engines/funcs/r/in_calendar_pk_constraint_ignore.result index 3f2b1546995..f8bff355901 100644 --- a/mysql-test/suite/engines/funcs/r/in_calendar_pk_constraint_ignore.result +++ b/mysql-test/suite/engines/funcs/r/in_calendar_pk_constraint_ignore.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL PRIMARY KEY); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1) VALUES(NOW()); @@ -87,3 +88,4 @@ c1 1999 2000 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/r/in_calendar_unique_constraint_duplicate_update.result b/mysql-test/suite/engines/funcs/r/in_calendar_unique_constraint_duplicate_update.result index 154c44426bc..5c4307158fa 100644 --- a/mysql-test/suite/engines/funcs/r/in_calendar_unique_constraint_duplicate_update.result +++ b/mysql-test/suite/engines/funcs/r/in_calendar_unique_constraint_duplicate_update.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NULL UNIQUE); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1) VALUES(NOW()); @@ -82,3 +83,4 @@ c1 2000 2011 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/r/in_calendar_unique_constraint_error.result b/mysql-test/suite/engines/funcs/r/in_calendar_unique_constraint_error.result index 6c395c5f6b9..9f6a205530c 100644 --- a/mysql-test/suite/engines/funcs/r/in_calendar_unique_constraint_error.result +++ b/mysql-test/suite/engines/funcs/r/in_calendar_unique_constraint_error.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NULL UNIQUE); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1) VALUES(NOW()); @@ -87,3 +88,4 @@ c1 1999 2000 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/r/in_calendar_unique_constraint_ignore.result b/mysql-test/suite/engines/funcs/r/in_calendar_unique_constraint_ignore.result index 58802aab0b2..5469527b762 100644 --- a/mysql-test/suite/engines/funcs/r/in_calendar_unique_constraint_ignore.result +++ b/mysql-test/suite/engines/funcs/r/in_calendar_unique_constraint_ignore.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NULL UNIQUE); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1) VALUES(NOW()); @@ -81,3 +82,4 @@ c1 1999 2000 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_pk_constraint_duplicate_update.result b/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_pk_constraint_duplicate_update.result index f2cafdfce52..d7dfc9d794c 100644 --- a/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_pk_constraint_duplicate_update.result +++ b/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_pk_constraint_duplicate_update.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL, c2 DATE NOT NULL, c3 DATE NOT NULL, PRIMARY KEY(c1,c2,c3)); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),NOW(),NOW()); @@ -144,3 +145,4 @@ c1 c2 c3 2011 2011 2000 2011 2011 2011 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_pk_constraint_error.result b/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_pk_constraint_error.result index b630d3f519f..d71af8d6375 100644 --- a/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_pk_constraint_error.result +++ b/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_pk_constraint_error.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL, c2 DATE NOT NULL, c3 DATE NOT NULL, PRIMARY KEY(c1,c2,c3)); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),NOW(),NOW()); @@ -147,3 +148,4 @@ c1 c2 c3 1999 2000 1999 2000 1999 1999 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_pk_constraint_ignore.result b/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_pk_constraint_ignore.result index b630d3f519f..d71af8d6375 100644 --- a/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_pk_constraint_ignore.result +++ b/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_pk_constraint_ignore.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL, c2 DATE NOT NULL, c3 DATE NOT NULL, PRIMARY KEY(c1,c2,c3)); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),NOW(),NOW()); @@ -147,3 +148,4 @@ c1 c2 c3 1999 2000 1999 2000 1999 1999 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_unique_constraint_duplicate_update.result b/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_unique_constraint_duplicate_update.result index 3b40a2f57ab..edad4bb218d 100644 --- a/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_unique_constraint_duplicate_update.result +++ b/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_unique_constraint_duplicate_update.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NULL, c2 DATE NULL, c3 DATE NULL, UNIQUE(c1,c2,c3)); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),NOW(),NOW()); @@ -144,3 +145,4 @@ c1 c2 c3 2011 2011 2000 2011 2011 2011 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_unique_constraint_error.result b/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_unique_constraint_error.result index 84f626d3347..4d7cadac70c 100644 --- a/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_unique_constraint_error.result +++ b/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_unique_constraint_error.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NULL, c2 DATE NULL, c3 DATE NULL, UNIQUE(c1,c2,c3)); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),NOW(),NOW()); @@ -147,3 +148,4 @@ c1 c2 c3 1999 2000 1999 2000 1999 1999 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_unique_constraint_ignore.result b/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_unique_constraint_ignore.result index f34b39ec1b4..31f7db1dc9a 100644 --- a/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_unique_constraint_ignore.result +++ b/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_unique_constraint_ignore.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NULL, c2 DATE NULL, c3 DATE NULL, UNIQUE(c1,c2,c3)); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),NOW(),NOW()); @@ -139,3 +140,4 @@ c1 c2 c3 1999 2000 1999 2000 1999 1999 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/r/in_multicolumn_number_pk_constraint_duplicate_update.result b/mysql-test/suite/engines/funcs/r/in_multicolumn_number_pk_constraint_duplicate_update.result index f2cafdfce52..d7dfc9d794c 100644 --- a/mysql-test/suite/engines/funcs/r/in_multicolumn_number_pk_constraint_duplicate_update.result +++ b/mysql-test/suite/engines/funcs/r/in_multicolumn_number_pk_constraint_duplicate_update.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL, c2 DATE NOT NULL, c3 DATE NOT NULL, PRIMARY KEY(c1,c2,c3)); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),NOW(),NOW()); @@ -144,3 +145,4 @@ c1 c2 c3 2011 2011 2000 2011 2011 2011 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/r/up_calendar_range.result b/mysql-test/suite/engines/funcs/r/up_calendar_range.result index 7185fc3c6ee..dbd6e2cf8a6 100644 --- a/mysql-test/suite/engines/funcs/r/up_calendar_range.result +++ b/mysql-test/suite/engines/funcs/r/up_calendar_range.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1,t2,t3; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1) VALUES(NOW()); @@ -104,3 +105,4 @@ c1 2007-02-13 09:09:33 2007-02-14 10:10:34 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/de_calendar_range.test b/mysql-test/suite/engines/funcs/t/de_calendar_range.test index c1e191fdd97..6e3f1915e9a 100644 --- a/mysql-test/suite/engines/funcs/t/de_calendar_range.test +++ b/mysql-test/suite/engines/funcs/t/de_calendar_range.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1,t2,t3; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL PRIMARY KEY); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1) VALUES(NOW()); @@ -45,4 +47,5 @@ SELECT * FROM t1 ORDER BY c1; DELETE FROM t1 WHERE c1 <= ADDTIME(NOW(),'2 02:01:01'); SELECT * FROM t1 ORDER BY c1; DROP TABLE t1; - +# Restore timezone to default +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/in_calendar_2_unique_constraints_duplicate_update.test b/mysql-test/suite/engines/funcs/t/in_calendar_2_unique_constraints_duplicate_update.test index 8c6f960b60d..5ae519abdc8 100644 --- a/mysql-test/suite/engines/funcs/t/in_calendar_2_unique_constraints_duplicate_update.test +++ b/mysql-test/suite/engines/funcs/t/in_calendar_2_unique_constraints_duplicate_update.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL, c2 DATE NULL, c3 DATE NULL, PRIMARY KEY(c1), UNIQUE(c2)); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),ADDTIME(NOW(),'4 04:01:01'),NOW()); @@ -70,4 +72,6 @@ INSERT INTO t1 (c1,c2,c3) VALUES(2000,2000,2000) ON DUPLICATE KEY UPDATE c3=2011 --sorted_result SELECT * FROM t1; DROP TABLE t1; +# Restore timezone to default +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/in_calendar_pk_constraint_duplicate_update.test b/mysql-test/suite/engines/funcs/t/in_calendar_pk_constraint_duplicate_update.test index 65c7c34f907..fdfb6edb139 100644 --- a/mysql-test/suite/engines/funcs/t/in_calendar_pk_constraint_duplicate_update.test +++ b/mysql-test/suite/engines/funcs/t/in_calendar_pk_constraint_duplicate_update.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL PRIMARY KEY); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1) VALUES(NOW()); @@ -61,4 +63,5 @@ INSERT INTO t1 (c1) VALUES(1999) ON DUPLICATE KEY UPDATE c1=2011; --sorted_result SELECT * FROM t1; DROP TABLE t1; - +# Restore timezone to default +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/in_calendar_pk_constraint_error.test b/mysql-test/suite/engines/funcs/t/in_calendar_pk_constraint_error.test index 36a8ef3a0a7..f65c705031b 100644 --- a/mysql-test/suite/engines/funcs/t/in_calendar_pk_constraint_error.test +++ b/mysql-test/suite/engines/funcs/t/in_calendar_pk_constraint_error.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL PRIMARY KEY); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1) VALUES(NOW()); @@ -61,4 +63,5 @@ INSERT INTO t1 (c1) VALUES(2000); INSERT INTO t1 (c1) VALUES(1999); SELECT * FROM t1; DROP TABLE t1; - +# Restore timezone to default +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/in_calendar_pk_constraint_ignore.test b/mysql-test/suite/engines/funcs/t/in_calendar_pk_constraint_ignore.test index 36a8ef3a0a7..bac71b99a97 100644 --- a/mysql-test/suite/engines/funcs/t/in_calendar_pk_constraint_ignore.test +++ b/mysql-test/suite/engines/funcs/t/in_calendar_pk_constraint_ignore.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL PRIMARY KEY); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1) VALUES(NOW()); @@ -61,4 +63,6 @@ INSERT INTO t1 (c1) VALUES(2000); INSERT INTO t1 (c1) VALUES(1999); SELECT * FROM t1; DROP TABLE t1; +# Restore timezone to default +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/in_calendar_unique_constraint_duplicate_update.test b/mysql-test/suite/engines/funcs/t/in_calendar_unique_constraint_duplicate_update.test index 20da85f5b66..e6235e77603 100644 --- a/mysql-test/suite/engines/funcs/t/in_calendar_unique_constraint_duplicate_update.test +++ b/mysql-test/suite/engines/funcs/t/in_calendar_unique_constraint_duplicate_update.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NULL UNIQUE); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1) VALUES(NOW()); @@ -61,4 +63,5 @@ INSERT INTO t1 (c1) VALUES(1999) ON DUPLICATE KEY UPDATE c1=2011; --sorted_result SELECT * FROM t1; DROP TABLE t1; - +# Restore timezone to default +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/in_calendar_unique_constraint_error.test b/mysql-test/suite/engines/funcs/t/in_calendar_unique_constraint_error.test index 73b8c3d0775..f9d101d8327 100644 --- a/mysql-test/suite/engines/funcs/t/in_calendar_unique_constraint_error.test +++ b/mysql-test/suite/engines/funcs/t/in_calendar_unique_constraint_error.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NULL UNIQUE); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1) VALUES(NOW()); @@ -61,4 +63,5 @@ INSERT INTO t1 (c1) VALUES(2000); INSERT INTO t1 (c1) VALUES(1999); SELECT * FROM t1; DROP TABLE t1; - +# Restore timezone to default +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/in_calendar_unique_constraint_ignore.test b/mysql-test/suite/engines/funcs/t/in_calendar_unique_constraint_ignore.test index 91e4f8faef9..a4e96a7ccc3 100644 --- a/mysql-test/suite/engines/funcs/t/in_calendar_unique_constraint_ignore.test +++ b/mysql-test/suite/engines/funcs/t/in_calendar_unique_constraint_ignore.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NULL UNIQUE); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1) VALUES(NOW()); @@ -53,4 +55,5 @@ INSERT INTO t1 (c1) VALUES(2000); INSERT IGNORE INTO t1 (c1) VALUES(1999); SELECT * FROM t1; DROP TABLE t1; - +#restore timezone to default +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_pk_constraint_duplicate_update.test b/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_pk_constraint_duplicate_update.test index a7648a55128..12307232d64 100644 --- a/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_pk_constraint_duplicate_update.test +++ b/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_pk_constraint_duplicate_update.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL, c2 DATE NOT NULL, c3 DATE NOT NULL, PRIMARY KEY(c1,c2,c3)); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),NOW(),NOW()); @@ -85,4 +87,6 @@ INSERT INTO t1 (c1,c2,c3) VALUES(1999,1999,2000) ON DUPLICATE KEY UPDATE c1=2011 --sorted_result SELECT * FROM t1; DROP TABLE t1; +# Restore timezone to default +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_pk_constraint_error.test b/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_pk_constraint_error.test index 9678ddd716b..8d994cb3d7a 100644 --- a/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_pk_constraint_error.test +++ b/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_pk_constraint_error.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL, c2 DATE NOT NULL, c3 DATE NOT NULL, PRIMARY KEY(c1,c2,c3)); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),NOW(),NOW()); @@ -93,4 +95,5 @@ INSERT INTO t1 (c1,c2,c3) VALUES(1999,1999,1999); INSERT INTO t1 (c1,c2,c3) VALUES(1999,1999,2000); SELECT * FROM t1; DROP TABLE t1; - +# Restore timezone to default +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_pk_constraint_ignore.test b/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_pk_constraint_ignore.test index 9678ddd716b..8d994cb3d7a 100644 --- a/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_pk_constraint_ignore.test +++ b/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_pk_constraint_ignore.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL, c2 DATE NOT NULL, c3 DATE NOT NULL, PRIMARY KEY(c1,c2,c3)); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),NOW(),NOW()); @@ -93,4 +95,5 @@ INSERT INTO t1 (c1,c2,c3) VALUES(1999,1999,1999); INSERT INTO t1 (c1,c2,c3) VALUES(1999,1999,2000); SELECT * FROM t1; DROP TABLE t1; - +# Restore timezone to default +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_unique_constraint_duplicate_update.test b/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_unique_constraint_duplicate_update.test index 13575722c1f..3d455bcb5d8 100644 --- a/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_unique_constraint_duplicate_update.test +++ b/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_unique_constraint_duplicate_update.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NULL, c2 DATE NULL, c3 DATE NULL, UNIQUE(c1,c2,c3)); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),NOW(),NOW()); @@ -85,4 +87,5 @@ INSERT INTO t1 (c1,c2,c3) VALUES(1999,1999,2000) ON DUPLICATE KEY UPDATE c1=2011 --sorted_result SELECT * FROM t1; DROP TABLE t1; - +# Restore timezone to default +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_unique_constraint_error.test b/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_unique_constraint_error.test index 916b0c527eb..9cbafd3b8d0 100644 --- a/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_unique_constraint_error.test +++ b/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_unique_constraint_error.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NULL, c2 DATE NULL, c3 DATE NULL, UNIQUE(c1,c2,c3)); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),NOW(),NOW()); @@ -93,4 +95,5 @@ INSERT INTO t1 (c1,c2,c3) VALUES(1999,1999,1999); INSERT INTO t1 (c1,c2,c3) VALUES(1999,1999,2000); SELECT * FROM t1; DROP TABLE t1; - +# Restore timezone to default +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_unique_constraint_ignore.test b/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_unique_constraint_ignore.test index b43ff52abe3..e313f29edfb 100644 --- a/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_unique_constraint_ignore.test +++ b/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_unique_constraint_ignore.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NULL, c2 DATE NULL, c3 DATE NULL, UNIQUE(c1,c2,c3)); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),NOW(),NOW()); @@ -85,4 +87,6 @@ INSERT IGNORE INTO t1 (c1,c2,c3) VALUES(1999,1999,2000); --sorted_result SELECT * FROM t1; DROP TABLE t1; +# Restore timezone to default +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/in_multicolumn_number_pk_constraint_duplicate_update.test b/mysql-test/suite/engines/funcs/t/in_multicolumn_number_pk_constraint_duplicate_update.test index 71848c1ac38..df4a194a2cf 100644 --- a/mysql-test/suite/engines/funcs/t/in_multicolumn_number_pk_constraint_duplicate_update.test +++ b/mysql-test/suite/engines/funcs/t/in_multicolumn_number_pk_constraint_duplicate_update.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL, c2 DATE NOT NULL, c3 DATE NOT NULL, PRIMARY KEY(c1,c2,c3)); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),NOW(),NOW()); @@ -93,4 +95,6 @@ INSERT INTO t1 (c1,c2,c3) VALUES(1999,1999,2000) ON DUPLICATE KEY UPDATE c1=2011 --sorted_result SELECT * FROM t1; DROP TABLE t1; +# Restore timezone to default +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/up_calendar_range.test b/mysql-test/suite/engines/funcs/t/up_calendar_range.test index 9c88d52f826..d4aca03199d 100644 --- a/mysql-test/suite/engines/funcs/t/up_calendar_range.test +++ b/mysql-test/suite/engines/funcs/t/up_calendar_range.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1,t2,t3; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1) VALUES(NOW()); @@ -53,4 +55,5 @@ UPDATE t1 SET c1 = NOW() WHERE c1 >= ADDTIME(NOW(),'2 02:01:01'); --sorted_result SELECT * FROM t1 ORDER BY c1; DROP TABLE t1; - +# Restore timezone to default +SET TIME_ZONE= @@global.time_zone; From 6d59064948fa916667a7cc885ecdc4df3b8fb871 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 12 Oct 2011 09:00:49 +0300 Subject: [PATCH 025/288] Bug#13006367 62487: innodb takes 3 minutes to clean up the adaptive hash index at shutdown btr_search_disable(): Just drop the entire adaptive hash index, without dropping every record separately. buf_pool_clear_hash_index(): Renamed and simplified from buf_pool_drop_hash_index(). Set block->index = NULL for every block in the buffer pool. Do not release the btr_search_latch. The caller will have to adjust other data structures. Remove block->is_hashed. It is redundant, should be always equal to block->index != NULL. Remove btr_search_fully_disabled, btr_search_enabled_mutex, and SYNC_SEARCH_SYS_CONF. We drop the AHI in one pass, without releasing the btr_search_latch in between. Replace void* with const rec_t* and add assertions on btr_search_latch and btr_search_enabled to ha0ha.h, ha0ha.ic, ha0ha.c. page_set_max_trx_id(): Ignore the adaptive hash index. I forgot to push this in rb:750. btr0sea.c: Always after acquiring btr_search_latch, check for block->index==NULL or !btr_search_enabled. We can now set block->index=NULL while only holding btr_search_latch in exclusive mode. Always acquire btr_search_latch before reading block->index, except in shortcuts when testing for block->index == NULL. ha_clear(), ha_search(): Unused function, remove. buf_page_peek_if_search_hashed(): Remove. This function may avoid latching a page at the cost of doing a duplicate buf_pool->page_hash lookup. rb:775 approved by Inaam Rana --- storage/innodb_plugin/ChangeLog | 10 + storage/innodb_plugin/btr/btr0cur.c | 2 +- storage/innodb_plugin/btr/btr0sea.c | 254 ++++++++++++--------- storage/innodb_plugin/buf/buf0buf.c | 119 ++-------- storage/innodb_plugin/buf/buf0lru.c | 6 +- storage/innodb_plugin/ha/ha0ha.c | 69 ++---- storage/innodb_plugin/handler/ha_innodb.cc | 1 - storage/innodb_plugin/ibuf/ibuf0ibuf.c | 2 +- storage/innodb_plugin/include/btr0sea.h | 34 +-- storage/innodb_plugin/include/btr0types.h | 25 +- storage/innodb_plugin/include/buf0buf.h | 44 ++-- storage/innodb_plugin/include/ha0ha.h | 23 +- storage/innodb_plugin/include/ha0ha.ic | 54 ++--- storage/innodb_plugin/include/row0upd.ic | 1 - storage/innodb_plugin/include/sync0sync.h | 1 - storage/innodb_plugin/page/page0page.c | 12 - storage/innodb_plugin/sync/sync0sync.c | 1 - 17 files changed, 272 insertions(+), 386 deletions(-) diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index cdf8e8351a8..b560f69daea 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,3 +1,13 @@ +2011-10-12 The InnoDB Team + + * btr/btr0cur.c, btr/btr0sea.c, buf/buf0buf.c, buf/buf0lru.c, + ha/ha0ha.c, handler/ha_innodb.cc, ibuf/ibuf0ibuf.c, include/btr0sea.h, + include/btr0types.h, include/buf0buf.h, include/ha0ha.h, + include/ha0ha.ic, include/row0upd.ic, include/sync0sync.h, + page/page0page.c, sync/sync0sync.c: + Fix Bug#13006367 62487: innodb takes 3 minutes to clean up + the adaptive hash index at shutdown + 2011-10-04 The InnoDB Team * include/sync0rw.h, sync/sync0rw.c: diff --git a/storage/innodb_plugin/btr/btr0cur.c b/storage/innodb_plugin/btr/btr0cur.c index 4baa21d7c71..5fe16ff1215 100644 --- a/storage/innodb_plugin/btr/btr0cur.c +++ b/storage/innodb_plugin/btr/btr0cur.c @@ -1777,7 +1777,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 diff --git a/storage/innodb_plugin/btr/btr0sea.c b/storage/innodb_plugin/btr/btr0sea.c index 88442b7d4f0..3dd30cbc0f3 100644 --- a/storage/innodb_plugin/btr/btr0sea.c +++ b/storage/innodb_plugin/btr/btr0sea.c @@ -44,12 +44,8 @@ Created 2/17/1996 Heikki Tuuri #include "ha0ha.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; - -/** Mutex protecting btr_search_enabled */ -static mutex_t btr_search_enabled_mutex; /** A dummy variable to fool the compiler */ UNIV_INTERN ulint btr_search_this_is_zero = 0; @@ -169,7 +165,6 @@ btr_search_sys_create( btr_search_latch_temp = mem_alloc(sizeof(rw_lock_t)); rw_lock_create(&btr_search_latch, SYNC_SEARCH_SYS); - mutex_create(&btr_search_enabled_mutex, SYNC_SEARCH_SYS_CONF); btr_search_sys = mem_alloc(sizeof(btr_search_sys_t)); @@ -199,27 +194,37 @@ void btr_search_disable(void) /*====================*/ { - mutex_enter(&btr_search_enabled_mutex); + dict_table_t* table; + + mutex_enter(&dict_sys->mutex); rw_lock_x_lock(&btr_search_latch); - /* 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. */ + hash_table_clear(btr_search_sys->hash_index); + mem_heap_empty(btr_search_sys->hash_index->heap); rw_lock_x_unlock(&btr_search_latch); - mutex_exit(&btr_search_enabled_mutex); } /********************************************************************//** @@ -229,14 +234,11 @@ void btr_search_enable(void) /*====================*/ { - mutex_enter(&btr_search_enabled_mutex); rw_lock_x_lock(&btr_search_latch); btr_search_enabled = TRUE; - btr_search_fully_disabled = FALSE; rw_lock_x_unlock(&btr_search_latch); - mutex_exit(&btr_search_enabled_mutex); } /*****************************************************************//** @@ -459,7 +461,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)) { @@ -488,7 +490,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) @@ -520,9 +522,9 @@ btr_search_update_hash_ref( buf_block_t* block, /*!< in: buffer block where cursor positioned */ btr_cur_t* cursor) /*!< in: cursor */ { - ulint fold; - rec_t* rec; - dulint index_id; + dict_index_t* index; + ulint fold; + const rec_t* rec; ut_ad(cursor->flag == BTR_CUR_HASH_FAIL); #ifdef UNIV_SYNC_DEBUG @@ -533,13 +535,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) @@ -556,12 +560,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); } @@ -824,7 +827,7 @@ btr_search_guess_on_hash( mtr_t* mtr) /*!< in: mtr */ { buf_block_t* block; - rec_t* rec; + const rec_t* rec; ulint fold; dulint index_id; #ifdef notdefined @@ -910,7 +913,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 */ @@ -1041,15 +1044,16 @@ btr_search_drop_page_hash_index( retry: rw_lock_s_lock(&btr_search_latch); - page = block->frame; + index = block->index; - if (UNIV_LIKELY(!block->is_hashed)) { + if (UNIV_LIKELY(!index)) { rw_lock_s_unlock(&btr_search_latch); return; } + ut_a(!dict_index_is_ibuf(index)); table = btr_search_sys->hash_index; #ifdef UNIV_SYNC_DEBUG @@ -1060,8 +1064,6 @@ retry: n_fields = block->curr_n_fields; n_bytes = block->curr_n_bytes; - index = block->index; - ut_a(!dict_index_is_ibuf(index)); /* NOTE: The fields of block must not be accessed after releasing btr_search_latch, as the index page might only @@ -1071,6 +1073,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 @@ -1119,7 +1122,7 @@ next_rec: rw_lock_x_lock(&btr_search_latch); - if (UNIV_UNLIKELY(!block->is_hashed)) { + if (UNIV_UNLIKELY(!block->index)) { /* Someone else has meanwhile dropped the hash index */ goto cleanup; @@ -1147,9 +1150,8 @@ next_rec: ut_a(index->search_info->ref_count > 0); index->search_info->ref_count--; - block->is_hashed = FALSE; block->index = NULL; - + cleanup: #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG if (UNIV_UNLIKELY(block->n_pointers)) { @@ -1175,8 +1177,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( @@ -1189,28 +1191,19 @@ 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); @@ -1242,7 +1235,6 @@ btr_search_build_page_hash_index( rec_t* next_rec; ulint fold; ulint next_fold; - dulint index_id; ulint n_cached; ulint n_recs; ulint* folds; @@ -1256,9 +1248,6 @@ btr_search_build_page_hash_index( ut_ad(index); ut_a(!dict_index_is_ibuf(index)); - table = btr_search_sys->hash_index; - page = buf_block_get_frame(block); - #ifdef UNIV_SYNC_DEBUG ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_EX)); ut_ad(rw_lock_own(&(block->lock), RW_LOCK_SHARED) @@ -1267,9 +1256,17 @@ btr_search_build_page_hash_index( rw_lock_s_lock(&btr_search_latch); - if (block->is_hashed && ((block->curr_n_fields != n_fields) - || (block->curr_n_bytes != n_bytes) - || (block->curr_left_side != left_side))) { + if (!btr_search_enabled) { + rw_lock_s_unlock(&btr_search_latch); + return; + } + + table = btr_search_sys->hash_index; + page = buf_block_get_frame(block); + + 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_latch); @@ -1306,7 +1303,7 @@ btr_search_build_page_hash_index( n_cached = 0; - index_id = btr_page_get_index_id(page); + ut_a(UT_DULINT_EQ(index->id, btr_page_get_index_id(page))); rec = page_rec_get_next(page_get_infimum_rec(page)); @@ -1321,7 +1318,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) { @@ -1348,7 +1345,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 */ @@ -1373,13 +1370,13 @@ btr_search_build_page_hash_index( rw_lock_x_lock(&btr_search_latch); - 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; } @@ -1388,11 +1385,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; @@ -1440,14 +1436,15 @@ 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_latch); - 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_latch); @@ -1456,7 +1453,7 @@ btr_search_move_or_delete_hash_entries( return; } - if (block->is_hashed) { + if (block->index) { n_fields = block->curr_n_fields; n_bytes = block->curr_n_bytes; @@ -1493,42 +1490,48 @@ btr_search_update_hash_on_delete( { hash_table_t* table; buf_block_t* block; - rec_t* rec; + const rec_t* rec; ulint fold; - dulint 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_sys->hash_index; - 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_latch); - 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_latch); } @@ -1546,6 +1549,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); @@ -1556,16 +1560,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_latch); + 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) @@ -1576,6 +1589,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_latch); } else { rw_lock_x_unlock(&btr_search_latch); @@ -1597,10 +1611,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; - dulint index_id; ulint fold; ulint ins_fold; ulint next_fold = 0; /* remove warning (??? bug ???) */ @@ -1625,15 +1639,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; @@ -1642,21 +1656,21 @@ 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) { @@ -1664,6 +1678,10 @@ btr_search_update_hash_on_insert( locked = TRUE; + if (!btr_search_enabled) { + goto function_exit; + } + ha_insert_for_fold(table, ins_fold, block, ins_rec); } @@ -1677,6 +1695,10 @@ btr_search_update_hash_on_insert( rw_lock_x_lock(&btr_search_latch); locked = TRUE; + + if (!btr_search_enabled) { + goto function_exit; + } } if (!left_side) { @@ -1695,6 +1717,10 @@ check_next_rec: rw_lock_x_lock(&btr_search_latch); locked = TRUE; + + if (!btr_search_enabled) { + goto function_exit; + } } ha_insert_for_fold(table, ins_fold, block, ins_rec); @@ -1710,6 +1736,10 @@ check_next_rec: rw_lock_x_lock(&btr_search_latch); locked = TRUE; + + if (!btr_search_enabled) { + goto function_exit; + } } if (!left_side) { @@ -1717,7 +1747,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 { @@ -1821,7 +1851,7 @@ btr_search_validate(void) + (block->curr_n_bytes > 0), &heap); - if (!block->is_hashed || node->fold + if (!block->index || node->fold != rec_fold((rec_t*)(node->data), offsets, block->curr_n_fields, @@ -1856,10 +1886,10 @@ btr_search_validate(void) rec_print_new(stderr, (rec_t*)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/storage/innodb_plugin/buf/buf0buf.c b/storage/innodb_plugin/buf/buf0buf.c index 47300627acc..7d03f08f61f 100644 --- a/storage/innodb_plugin/buf/buf0buf.c +++ b/storage/innodb_plugin/buf/buf0buf.c @@ -962,86 +962,42 @@ buf_pool_free(void) } /********************************************************************//** -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; + buf_chunk_t* chunks = buf_pool->chunks; + buf_chunk_t* chunk = chunks + buf_pool->n_chunks; #ifdef UNIV_SYNC_DEBUG ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EX)); #endif /* UNIV_SYNC_DEBUG */ ut_ad(!btr_search_enabled); - do { - buf_chunk_t* chunks = buf_pool->chunks; - buf_chunk_t* chunk = chunks + buf_pool->n_chunks; + while (--chunk >= chunks) { + buf_block_t* block = chunk->blocks; + ulint i = chunk->size; - released_search_latch = FALSE; + for (; i--; block++) { + dict_index_t* index = block->index; - while (--chunk >= chunks) { - buf_block_t* block = chunk->blocks; - ulint i = chunk->size; + /* We can set block->index = NULL + when we have an x-latch on btr_search_latch; + see the comment in buf0buf.h */ - for (; 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 (buf_block_get_state(block) - != BUF_BLOCK_FILE_PAGE - || !block->is_hashed) { - continue; - } - - /* To follow the latching order, we - have to release btr_search_latch - before acquiring block->latch. */ - rw_lock_x_unlock(&btr_search_latch); - /* 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); - - rw_lock_x_unlock(&block->lock); - - rw_lock_x_lock(&btr_search_latch); - - ut_ad(!btr_search_enabled); + 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); + } } /********************************************************************//** @@ -1174,36 +1130,6 @@ buf_page_set_accessed_make_young( } } -/********************************************************************//** -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_mutex_enter(); - - block = (buf_block_t*) buf_page_hash_get(space, offset); - - if (!block || buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE) { - is_hashed = FALSE; - } else { - is_hashed = block->is_hashed; - } - - buf_pool_mutex_exit(); - - 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. @@ -1408,7 +1334,6 @@ buf_block_init_low( block->index = NULL; block->n_hash_helps = 0; - block->is_hashed = FALSE; block->n_fields = 1; block->n_bytes = 0; block->left_side = TRUE; diff --git a/storage/innodb_plugin/buf/buf0lru.c b/storage/innodb_plugin/buf/buf0lru.c index ad6feef5f2f..5124787eba1 100644 --- a/storage/innodb_plugin/buf/buf0lru.c +++ b/storage/innodb_plugin/buf/buf0lru.c @@ -272,7 +272,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) { @@ -407,7 +407,7 @@ scan_again: 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) { + } else if (((buf_block_t*) bpage)->index) { ulint page_no; ulint zip_size; @@ -419,7 +419,7 @@ scan_again: mutex_exit(block_mutex); /* Note that the following call will acquire - an S-latch on the page */ + and release an X-latch on the page. */ btr_search_drop_page_hash_when_freed( id, zip_size, page_no); diff --git a/storage/innodb_plugin/ha/ha0ha.c b/storage/innodb_plugin/ha/ha0ha.c index 7f11917de0a..65046138275 100644 --- a/storage/innodb_plugin/ha/ha0ha.c +++ b/storage/innodb_plugin/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,40 +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 - 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 @@ -140,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; @@ -153,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(&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); @@ -173,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; @@ -186,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)); @@ -250,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) { @@ -272,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; @@ -286,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); @@ -322,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/storage/innodb_plugin/handler/ha_innodb.cc b/storage/innodb_plugin/handler/ha_innodb.cc index aec0e77768c..fc1193e55bb 100644 --- a/storage/innodb_plugin/handler/ha_innodb.cc +++ b/storage/innodb_plugin/handler/ha_innodb.cc @@ -2304,7 +2304,6 @@ innobase_change_buffering_inited_ok: /* Get the current high water mark format. */ innobase_file_format_check = (char*) trx_sys_file_format_max_get(); - btr_search_fully_disabled = (!btr_search_enabled); DBUG_RETURN(FALSE); error: DBUG_RETURN(TRUE); diff --git a/storage/innodb_plugin/ibuf/ibuf0ibuf.c b/storage/innodb_plugin/ibuf/ibuf0ibuf.c index e4d8f79a944..a22de3b0e70 100644 --- a/storage/innodb_plugin/ibuf/ibuf0ibuf.c +++ b/storage/innodb_plugin/ibuf/ibuf0ibuf.c @@ -2971,7 +2971,7 @@ ibuf_insert_to_index_page( ut_ad(ibuf_inside()); 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/storage/innodb_plugin/include/btr0sea.h b/storage/innodb_plugin/include/btr0sea.h index 6493689a969..1f920471f7d 100644 --- a/storage/innodb_plugin/include/btr0sea.h +++ b/storage/innodb_plugin/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 @@ -141,8 +141,8 @@ btr_search_drop_page_hash_index( for which we know that block->buf_fix_count == 0 */ /********************************************************************//** -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( @@ -192,16 +192,6 @@ btr_search_validate(void); # define btr_search_validate() TRUE #endif /* defined UNIV_AHI_DEBUG || defined UNIV_DEBUG */ -/** Flag: has the search system been enabled? -Protected by btr_search_latch and btr_search_enabled_mutex. */ -extern char btr_search_enabled; - -/** 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 @@ -270,24 +260,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; - -/** 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/storage/innodb_plugin/include/btr0types.h b/storage/innodb_plugin/include/btr0types.h index 07c06fb18d7..5adc858b931 100644 --- a/storage/innodb_plugin/include/btr0types.h +++ b/storage/innodb_plugin/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,28 @@ 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; + +/** 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; + #ifdef UNIV_BLOB_DEBUG # include "buf0types.h" /** An index->blobs entry for keeping track of off-page column references */ diff --git a/storage/innodb_plugin/include/buf0buf.h b/storage/innodb_plugin/include/buf0buf.h index 557bc17d311..e7fe3901ad4 100644 --- a/storage/innodb_plugin/include/buf0buf.h +++ b/storage/innodb_plugin/include/buf0buf.h @@ -120,13 +120,11 @@ buf_pool_free(void); /*===============*/ /********************************************************************//** -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 @@ -440,17 +438,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 */ @@ -1267,13 +1254,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. */ /* @{ */ @@ -1282,20 +1272,20 @@ struct buf_block_struct{ pointers in the adaptive hash index pointing to this frame */ #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ - 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. */ + 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. */ /* @} */ # ifdef UNIV_SYNC_DEBUG /** @name Debug fields */ diff --git a/storage/innodb_plugin/include/ha0ha.h b/storage/innodb_plugin/include/ha0ha.h index 3299000bf3c..8bba564d153 100644 --- a/storage/innodb_plugin/include/ha0ha.h +++ b/storage/innodb_plugin/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/storage/innodb_plugin/include/ha0ha.ic b/storage/innodb_plugin/include/ha0ha.ic index 734403c4cd9..5656e9b7eba 100644 --- a/storage/innodb_plugin/include/ha0ha.ic +++ b/storage/innodb_plugin/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/storage/innodb_plugin/include/row0upd.ic b/storage/innodb_plugin/include/row0upd.ic index 11db82f64da..10646241125 100644 --- a/storage/innodb_plugin/include/row0upd.ic +++ b/storage/innodb_plugin/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/storage/innodb_plugin/include/sync0sync.h b/storage/innodb_plugin/include/sync0sync.h index f2013c202c1..63bad29a9c8 100644 --- a/storage/innodb_plugin/include/sync0sync.h +++ b/storage/innodb_plugin/include/sync0sync.h @@ -481,7 +481,6 @@ or row lock! */ #define SYNC_LOG 170 #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/storage/innodb_plugin/page/page0page.c b/storage/innodb_plugin/page/page0page.c index a284b1480a3..1b9470acbbc 100644 --- a/storage/innodb_plugin/page/page0page.c +++ b/storage/innodb_plugin/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_latch); - } - 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_latch); - } -#endif /* !UNIV_HOTBACKUP */ } /************************************************************//** diff --git a/storage/innodb_plugin/sync/sync0sync.c b/storage/innodb_plugin/sync/sync0sync.c index 3640e204525..3e66aaafef2 100644 --- a/storage/innodb_plugin/sync/sync0sync.c +++ b/storage/innodb_plugin/sync/sync0sync.c @@ -1160,7 +1160,6 @@ sync_thread_add_level( case SYNC_DOUBLEWRITE: case SYNC_BUF_POOL: case SYNC_SEARCH_SYS: - case SYNC_SEARCH_SYS_CONF: case SYNC_TRX_LOCK_HEAP: case SYNC_KERNEL: case SYNC_IBUF_BITMAP_MUTEX: From bd4785a6b71f794fcc82b6c52761015e497498ce Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Wed, 12 Oct 2011 17:41:25 +0400 Subject: [PATCH 026/288] Bug#11750518 41090: ORDER BY TRUNCATES GROUP_CONCAT RESULT When temporary tables is used for result sorting result field for gconcat function is created using group_concat_max_len size. It leads to result truncation when character_set_results is multi-byte character set due to insufficient tmp table field size. The fix is to increase temporary table field size for gconcat. Method make_string_field() is overloaded for Item_func_group_concat class and uses max_characters * collation.collation->mbmaxlen size for result field. max_characters is maximum number of characters what can fit into max_length size. mysql-test/r/ctype_utf16.result: test result mysql-test/r/ctype_utf32.result: test result mysql-test/r/ctype_utf8.result: test result mysql-test/t/ctype_utf16.test: test case mysql-test/t/ctype_utf32.test: test case mysql-test/t/ctype_utf8.test: test case sql/item.h: make Item::make_string_field() virtual sql/item_sum.cc: added Item_func_group_concat::make_string_field(TABLE *table) method which uses max_characters * collation.collation->mbmaxlen size for result item. max_characters is maximum number of characters what can fit into max_length size. sql/item_sum.h: added Item_func_group_concat::make_string_field(TABLE *table) method --- mysql-test/r/ctype_utf16.result | 14 ++++++++++++++ mysql-test/r/ctype_utf32.result | 14 ++++++++++++++ mysql-test/r/ctype_utf8.result | 16 +++++++++++++++- mysql-test/t/ctype_utf16.test | 14 ++++++++++++++ mysql-test/t/ctype_utf32.test | 13 +++++++++++++ mysql-test/t/ctype_utf8.test | 12 ++++++++++++ sql/item.h | 2 +- sql/item_sum.cc | 25 +++++++++++++++++++++++++ sql/item_sum.h | 1 + 9 files changed, 109 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/ctype_utf16.result b/mysql-test/r/ctype_utf16.result index dfffd8142de..42897ca580f 100644 --- a/mysql-test/r/ctype_utf16.result +++ b/mysql-test/r/ctype_utf16.result @@ -1126,5 +1126,19 @@ NULL Warnings: Warning 1301 Result of repeat() was larger than max_allowed_packet (1048576) - truncated # +# Bug#11750518 41090: ORDER BY TRUNCATES GROUP_CONCAT RESULT +# +SET NAMES utf8, @@character_set_connection=utf16; +SELECT id, CHAR_LENGTH(GROUP_CONCAT(body)) AS l +FROM (SELECT 'a' AS id, REPEAT('foo bar', 100) AS body +UNION ALL +SELECT 'a' AS id, REPEAT('bla bla', 100) AS body) t1 +GROUP BY id +ORDER BY l DESC; +id l +a 512 +Warnings: +Warning 1260 Row 1 was cut by GROUP_CONCAT() +# # End of 5.5 tests # diff --git a/mysql-test/r/ctype_utf32.result b/mysql-test/r/ctype_utf32.result index d749383d249..2433f2426a4 100644 --- a/mysql-test/r/ctype_utf32.result +++ b/mysql-test/r/ctype_utf32.result @@ -1167,5 +1167,19 @@ CASE s1 WHEN 'a' THEN 'b' ELSE 'c' END b DROP TABLE t1; # +# Bug#11750518 41090: ORDER BY TRUNCATES GROUP_CONCAT RESULT +# +SET NAMES utf8, @@character_set_connection=utf32; +SELECT id, CHAR_LENGTH(GROUP_CONCAT(body)) AS l +FROM (SELECT 'a' AS id, REPEAT('foo bar', 100) AS body +UNION ALL +SELECT 'a' AS id, REPEAT('bla bla', 100) AS body) t1 +GROUP BY id +ORDER BY l DESC; +id l +a 256 +Warnings: +Warning 1260 Row 1 was cut by GROUP_CONCAT() +# # End of 5.5 tests # diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index cfbf6cee3a2..8237f174514 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -2788,7 +2788,7 @@ create table t1 as select group_concat(1,2,3) as c1; show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `c1` varchar(342) CHARACTER SET utf8 DEFAULT NULL + `c1` text CHARACTER SET utf8 ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; create table t1 as select 1 as c1 union select 'a'; @@ -5010,5 +5010,19 @@ id select_type table type possible_keys key key_len ref rows filtered Extra Warnings: Note 1003 select 'abcdÁÂÃÄÅ' AS `abcdÁÂÃÄÅ`,_latin1'abcd\xC3\x81\xC3\x82\xC3\x83\xC3\x84\xC3\x85' AS `abcdÁÂÃÄÅ`,_utf8'abcd\xC3\x81\xC3\x82\xC3\x83\xC3\x84\xC3\x85' AS `abcdÁÂÃÄÅ` # +# Bug#11750518 41090: ORDER BY TRUNCATES GROUP_CONCAT RESULT +# +SET NAMES utf8; +SELECT id, CHAR_LENGTH(GROUP_CONCAT(body)) AS l +FROM (SELECT 'a' AS id, REPEAT('foo bar', 100) AS body +UNION ALL +SELECT 'a' AS id, REPEAT('bla bla', 100) AS body) t1 +GROUP BY id +ORDER BY l DESC; +id l +a 1024 +Warnings: +Warning 1260 Row 2 was cut by GROUP_CONCAT() +# # End of 5.5 tests # diff --git a/mysql-test/t/ctype_utf16.test b/mysql-test/t/ctype_utf16.test index 4ac47a4ac53..ca6802d96dc 100644 --- a/mysql-test/t/ctype_utf16.test +++ b/mysql-test/t/ctype_utf16.test @@ -762,6 +762,20 @@ DROP TABLE t1; SELECT space(date_add(101, INTERVAL CHAR('1' USING utf16) hour_second)); + +--echo # +--echo # Bug#11750518 41090: ORDER BY TRUNCATES GROUP_CONCAT RESULT +--echo # + +SET NAMES utf8, @@character_set_connection=utf16; +SELECT id, CHAR_LENGTH(GROUP_CONCAT(body)) AS l +FROM (SELECT 'a' AS id, REPEAT('foo bar', 100) AS body +UNION ALL +SELECT 'a' AS id, REPEAT('bla bla', 100) AS body) t1 +GROUP BY id +ORDER BY l DESC; + + # ## TODO: add tests for all engines # diff --git a/mysql-test/t/ctype_utf32.test b/mysql-test/t/ctype_utf32.test index 10d365572bf..c36e623541a 100644 --- a/mysql-test/t/ctype_utf32.test +++ b/mysql-test/t/ctype_utf32.test @@ -840,6 +840,19 @@ INSERT INTO t1 VALUES ('a'); SELECT CASE s1 WHEN 'a' THEN 'b' ELSE 'c' END FROM t1; DROP TABLE t1; +--echo # +--echo # Bug#11750518 41090: ORDER BY TRUNCATES GROUP_CONCAT RESULT +--echo # + +SET NAMES utf8, @@character_set_connection=utf32; +SELECT id, CHAR_LENGTH(GROUP_CONCAT(body)) AS l +FROM (SELECT 'a' AS id, REPEAT('foo bar', 100) AS body +UNION ALL +SELECT 'a' AS id, REPEAT('bla bla', 100) AS body) t1 +GROUP BY id +ORDER BY l DESC; + + --echo # --echo # End of 5.5 tests --echo # diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test index a519a417192..8254f99249f 100644 --- a/mysql-test/t/ctype_utf8.test +++ b/mysql-test/t/ctype_utf8.test @@ -1561,6 +1561,18 @@ EXPLAIN EXTENDED SELECT 'abcdÁÂÃÄÅ', _latin1'abcdÁÂÃÄÅ', _utf8'abcdÁ SET NAMES utf8; EXPLAIN EXTENDED SELECT 'abcdÁÂÃÄÅ', _latin1'abcdÁÂÃÄÅ', _utf8'abcdÁÂÃÄÅ'; +--echo # +--echo # Bug#11750518 41090: ORDER BY TRUNCATES GROUP_CONCAT RESULT +--echo # + +SET NAMES utf8; +SELECT id, CHAR_LENGTH(GROUP_CONCAT(body)) AS l +FROM (SELECT 'a' AS id, REPEAT('foo bar', 100) AS body +UNION ALL +SELECT 'a' AS id, REPEAT('bla bla', 100) AS body) t1 +GROUP BY id +ORDER BY l DESC; + --echo # --echo # End of 5.5 tests --echo # diff --git a/sql/item.h b/sql/item.h index 46916346ebe..5a40aaf2a93 100644 --- a/sql/item.h +++ b/sql/item.h @@ -592,7 +592,7 @@ public: void init_make_field(Send_field *tmp_field,enum enum_field_types type); virtual void cleanup(); virtual void make_field(Send_field *field); - Field *make_string_field(TABLE *table); + virtual Field *make_string_field(TABLE *table); virtual bool fix_fields(THD *, Item **); /* should be used in case where we are sure that we do not need diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 161c8c8eacf..d9e634f8c16 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -3128,6 +3128,31 @@ void Item_func_group_concat::cleanup() } +Field *Item_func_group_concat::make_string_field(TABLE *table) +{ + Field *field; + DBUG_ASSERT(collation.collation); + /* + max_characters is maximum number of characters + what can fit into max_length size. It's necessary + to use field size what allows to store group_concat + result without truncation. For this purpose we use + max_characters * CS->mbmaxlen. + */ + const uint32 max_characters= max_length / collation.collation->mbminlen; + if (max_characters > CONVERT_IF_BIGGER_TO_BLOB) + field= new Field_blob(max_characters * collation.collation->mbmaxlen, + maybe_null, name, collation.collation, TRUE); + else + field= new Field_varstring(max_characters * collation.collation->mbmaxlen, + maybe_null, name, table->s, collation.collation); + + if (field) + field->init(table); + return field; +} + + Item *Item_func_group_concat::copy_or_same(THD* thd) { return new (thd->mem_root) Item_func_group_concat(thd, this); diff --git a/sql/item_sum.h b/sql/item_sum.h index c303385c535..a0b54b0ec8a 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -1411,6 +1411,7 @@ public: enum Sumfunctype sum_func () const {return GROUP_CONCAT_FUNC;} const char *func_name() const { return "group_concat"; } virtual Item_result result_type () const { return STRING_RESULT; } + virtual Field *make_string_field(TABLE *table); enum_field_types field_type() const { if (max_length/collation.collation->mbmaxlen > CONVERT_IF_BIGGER_TO_BLOB ) From d96c25a79013eae662d1c0f5f43782126b24e696 Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Fri, 14 Oct 2011 01:03:25 +0530 Subject: [PATCH 027/288] WL#5945 : Improve libedit library Updated libedit library. --- cmd-line-utils/libedit/Makefile.am | 17 +- cmd-line-utils/libedit/README | 12 +- cmd-line-utils/libedit/chared.c | 289 ++--- cmd-line-utils/libedit/chared.h | 50 +- cmd-line-utils/libedit/chartype.c | 364 ++++++ cmd-line-utils/libedit/chartype.h | 252 ++++ cmd-line-utils/libedit/common.c | 252 ++-- cmd-line-utils/libedit/config.h | 3 + cmd-line-utils/libedit/el.c | 238 ++-- cmd-line-utils/libedit/el.h | 53 +- .../libedit/{el_term.h => el_terminal.h} | 72 +- cmd-line-utils/libedit/eln.c | 364 ++++++ cmd-line-utils/libedit/emacs.c | 161 +-- cmd-line-utils/libedit/filecomplete.c | 231 ++-- cmd-line-utils/libedit/filecomplete.h | 6 +- cmd-line-utils/libedit/hist.c | 77 +- cmd-line-utils/libedit/hist.h | 29 +- cmd-line-utils/libedit/histedit.h | 147 ++- cmd-line-utils/libedit/history.c | 486 +++++--- cmd-line-utils/libedit/historyn.c | 5 + cmd-line-utils/libedit/{key.c => keymacro.c} | 422 ++++--- cmd-line-utils/libedit/{key.h => keymacro.h} | 57 +- cmd-line-utils/libedit/makelist.sh | 25 +- cmd-line-utils/libedit/map.c | 215 ++-- cmd-line-utils/libedit/map.h | 16 +- cmd-line-utils/libedit/np/strlcat.c | 1 + cmd-line-utils/libedit/np/strlcpy.c | 2 + cmd-line-utils/libedit/np/unvis.c | 437 +++++-- cmd-line-utils/libedit/np/vis.c | 312 ++++- cmd-line-utils/libedit/np/vis.h | 50 +- cmd-line-utils/libedit/np/wcsdup.c | 43 + cmd-line-utils/libedit/parse.c | 124 +- cmd-line-utils/libedit/parse.h | 10 +- cmd-line-utils/libedit/prompt.c | 83 +- cmd-line-utils/libedit/prompt.h | 14 +- cmd-line-utils/libedit/read.c | 265 +++-- cmd-line-utils/libedit/read.h | 4 +- cmd-line-utils/libedit/readline.c | 719 ++++++++---- cmd-line-utils/libedit/readline/readline.h | 28 +- cmd-line-utils/libedit/refresh.c | 472 ++++---- cmd-line-utils/libedit/refresh.h | 4 +- cmd-line-utils/libedit/search.c | 160 +-- cmd-line-utils/libedit/search.h | 14 +- cmd-line-utils/libedit/sig.c | 86 +- cmd-line-utils/libedit/sig.h | 10 +- cmd-line-utils/libedit/sys.h | 51 +- cmd-line-utils/libedit/{term.c => terminal.c} | 1030 ++++++++--------- cmd-line-utils/libedit/tokenizer.c | 111 +- cmd-line-utils/libedit/tokenizern.c | 5 + cmd-line-utils/libedit/tty.c | 136 ++- cmd-line-utils/libedit/tty.h | 7 +- cmd-line-utils/libedit/vi.c | 358 +++--- 52 files changed, 5379 insertions(+), 3000 deletions(-) create mode 100644 cmd-line-utils/libedit/chartype.c create mode 100644 cmd-line-utils/libedit/chartype.h rename cmd-line-utils/libedit/{el_term.h => el_terminal.h} (65%) create mode 100644 cmd-line-utils/libedit/eln.c create mode 100644 cmd-line-utils/libedit/historyn.c rename cmd-line-utils/libedit/{key.c => keymacro.c} (55%) rename cmd-line-utils/libedit/{key.h => keymacro.h} (60%) create mode 100644 cmd-line-utils/libedit/np/wcsdup.c rename cmd-line-utils/libedit/{term.c => terminal.c} (56%) create mode 100644 cmd-line-utils/libedit/tokenizern.c diff --git a/cmd-line-utils/libedit/Makefile.am b/cmd-line-utils/libedit/Makefile.am index ddafa4aab44..87ca8b591bb 100644 --- a/cmd-line-utils/libedit/Makefile.am +++ b/cmd-line-utils/libedit/Makefile.am @@ -7,19 +7,19 @@ INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include noinst_LIBRARIES = libedit.a -libedit_a_SOURCES = chared.c el.c history.c map.c prompt.c readline.c \ - search.c tokenizer.c vi.c common.c emacs.c \ - hist.c key.c parse.c read.c refresh.c sig.c term.c \ +libedit_a_SOURCES = chared.c el.c eln.c history.c historyn.c map.c prompt.c readline.c \ + search.c tokenizer.c tokenizern.c vi.c common.c emacs.c \ + hist.c keymacro.c parse.c read.c refresh.c sig.c terminal.c \ tty.c help.c fcns.c filecomplete.c \ np/unvis.c np/strlcpy.c np/vis.c np/strlcat.c \ - np/fgetln.c + np/fgetln.c np/wcsdup.c libedit_a_LIBADD = @LIBEDIT_LOBJECTS@ libedit_a_DEPENDENCIES = @LIBEDIT_LOBJECTS@ pkginclude_HEADERS = readline/readline.h -noinst_HEADERS = chared.h el.h el_term.h histedit.h key.h parse.h refresh.h sig.h \ +noinst_HEADERS = chared.h el.h el_terminal.h histedit.h keymacro.h parse.h refresh.h sig.h \ sys.h config.h hist.h map.h prompt.h read.h \ search.h tty.h filecomplete.h np/vis.h @@ -70,22 +70,25 @@ fcns.c: ${AHDR} fcns.h makelist chared.o: vi.h emacs.h common.h help.h fcns.h el.o: vi.h emacs.h common.h help.h fcns.h +eln.o: vi.h emacs.h common.h help.h fcns.h history.o: vi.h emacs.h common.h help.h fcns.h +historyn.o: vi.h emacs.h common.h help.h fcns.h map.o: vi.h emacs.h common.h help.h fcns.h prompt.o: vi.h emacs.h common.h help.h fcns.h readline.o: vi.h emacs.h common.h help.h fcns.h search.o: vi.h emacs.h common.h help.h fcns.h tokenizer.o: vi.h emacs.h common.h help.h fcns.h +tokenizern.o: vi.h emacs.h common.h help.h fcns.h vi.o: vi.h emacs.h common.h help.h fcns.h common.o: vi.h emacs.h common.h help.h fcns.h emacs.o: vi.h emacs.h common.h help.h fcns.h hist.o: vi.h emacs.h common.h help.h fcns.h -key.o: vi.h emacs.h common.h help.h fcns.h +keymacro.o: vi.h emacs.h common.h help.h fcns.h parse.o: vi.h emacs.h common.h help.h fcns.h read.o: vi.h emacs.h common.h help.h fcns.h refresh.o: vi.h emacs.h common.h help.h fcns.h sig.o: vi.h emacs.h common.h help.h fcns.h -term.o: vi.h emacs.h common.h help.h fcns.h +terminal.o: vi.h emacs.h common.h help.h fcns.h tty.o: vi.h emacs.h common.h help.h fcns.h help.o: vi.h emacs.h common.h help.h fcns.h fcns.o: vi.h emacs.h common.h help.h fcns.h diff --git a/cmd-line-utils/libedit/README b/cmd-line-utils/libedit/README index 0b698a6150d..28041766a2e 100644 --- a/cmd-line-utils/libedit/README +++ b/cmd-line-utils/libedit/README @@ -2,7 +2,7 @@ An approximate method to merge from upstream is: # Fetch latest from upstream (we also include some compat stuff) $ CVS_RSH=ssh; export CVS_RSH - $ CVSROOT="anoncvs@stripped:/cvsroot" + $ CVSROOT="anoncvs@anoncvs.netbsd.org:/cvsroot" $ cvs co -d libedit -P src/lib/libedit $ mkdir libedit/np $ for f in src/common/lib/libc/string/strlcat.c \ @@ -24,13 +24,13 @@ An approximate method to merge from upstream is: # Rename files to match our naming $ mv makelist makelist.sh - $ mv term.h el_term.h + $ mv terminal.h el_terminal.h # Remove NetBSD-specific bits $ for file in $(find . -type f) > do > cp ${file} ${file}.orig - > sed -e 's/#include "term.h"/#include "el_term.h"/g' \ + > sed -e 's/#include "terminal.h"/#include "el_terminal.h"/g' \ > -e 's/sig_handler/el_sig_handler/g' \ > -e 's/isprint/el_isprint/g' \ > -e '/^__RCSID/d' \ @@ -42,9 +42,9 @@ then merge remaining bits by hand. All MySQL-specific changes should be marked with XXXMYSQL to make them easier to identify and merge. To generate a 'clean' diff against upstream you can use the above commands but use - cvs co -D "2009/02/06 20:09:00" [..] + cvs co -D "2011/10/04 15:27:04" [..] to fetch the baseline of most recent merge. -Please feed any fixes to Jonathan Perkin who will endeavour -to merge them upstream and keep diffs minimal. +Please feed any fixes to Jonathan Perkin who will +endeavour to merge them upstream and keep diffs minimal. diff --git a/cmd-line-utils/libedit/chared.c b/cmd-line-utils/libedit/chared.c index e4823db7147..aba30086b9f 100644 --- a/cmd-line-utils/libedit/chared.c +++ b/cmd-line-utils/libedit/chared.c @@ -1,4 +1,4 @@ -/* $NetBSD: chared.c,v 1.26 2009/02/06 12:45:25 sketch Exp $ */ +/* $NetBSD: chared.c,v 1.35 2011/08/16 16:25:15 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -59,13 +59,13 @@ cv_undo(EditLine *el) { c_undo_t *vu = &el->el_chared.c_undo; c_redo_t *r = &el->el_chared.c_redo; - unsigned int size; + size_t size; /* Save entire line for undo */ - size = el->el_line.lastchar - el->el_line.buffer; - vu->len = size; - vu->cursor = el->el_line.cursor - el->el_line.buffer; - memcpy(vu->buf, el->el_line.buffer, size); + size = (size_t)(el->el_line.lastchar - el->el_line.buffer); + vu->len = (ssize_t)size; + vu->cursor = (int)(el->el_line.cursor - el->el_line.buffer); + (void)memcpy(vu->buf, el->el_line.buffer, size * sizeof(*vu->buf)); /* save command info for redo */ r->count = el->el_state.doingarg ? el->el_state.argument : 0; @@ -79,11 +79,11 @@ cv_undo(EditLine *el) * Save yank/delete data for paste */ protected void -cv_yank(EditLine *el, const char *ptr, int size) +cv_yank(EditLine *el, const Char *ptr, int size) { c_kill_t *k = &el->el_chared.c_kill; - memcpy(k->buf, ptr, size +0u); + (void)memcpy(k->buf, ptr, (size_t)size * sizeof(*k->buf)); k->last = k->buf + size; } @@ -94,10 +94,10 @@ cv_yank(EditLine *el, const char *ptr, int size) protected void c_insert(EditLine *el, int num) { - char *cp; + Char *cp; if (el->el_line.lastchar + num >= el->el_line.limit) { - if (!ch_enlargebufs(el, num +0u)) + if (!ch_enlargebufs(el, (size_t)num)) return; /* can't go past end of buffer */ } @@ -118,7 +118,7 @@ c_delafter(EditLine *el, int num) { if (el->el_line.cursor + num > el->el_line.lastchar) - num = el->el_line.lastchar - el->el_line.cursor; + num = (int)(el->el_line.lastchar - el->el_line.cursor); if (el->el_map.current != el->el_map.emacs) { cv_undo(el); @@ -126,7 +126,7 @@ c_delafter(EditLine *el, int num) } if (num > 0) { - char *cp; + Char *cp; for (cp = el->el_line.cursor; cp <= el->el_line.lastchar; cp++) *cp = cp[num]; @@ -142,7 +142,7 @@ c_delafter(EditLine *el, int num) protected void c_delafter1(EditLine *el) { - char *cp; + Char *cp; for (cp = el->el_line.cursor; cp <= el->el_line.lastchar; cp++) *cp = cp[1]; @@ -159,7 +159,7 @@ c_delbefore(EditLine *el, int num) { if (el->el_line.cursor - num < el->el_line.buffer) - num = el->el_line.cursor - el->el_line.buffer; + num = (int)(el->el_line.cursor - el->el_line.buffer); if (el->el_map.current != el->el_map.emacs) { cv_undo(el); @@ -167,7 +167,7 @@ c_delbefore(EditLine *el, int num) } if (num > 0) { - char *cp; + Char *cp; for (cp = el->el_line.cursor - num; cp <= el->el_line.lastchar; @@ -185,7 +185,7 @@ c_delbefore(EditLine *el, int num) protected void c_delbefore1(EditLine *el) { - char *cp; + Char *cp; for (cp = el->el_line.cursor - 1; cp <= el->el_line.lastchar; cp++) *cp = cp[1]; @@ -198,9 +198,9 @@ c_delbefore1(EditLine *el) * Return if p is part of a word according to emacs */ protected int -ce__isword(int p) +ce__isword(Int p) { - return (isalnum(p) || strchr("*?_-.[]~=", p) != NULL); + return Isalnum(p || Strchr(STR("*?_-.[]~="), p) != NULL); } @@ -208,11 +208,11 @@ ce__isword(int p) * Return if p is part of a word according to vi */ protected int -cv__isword(int p) +cv__isword(Int p) { - if (isalnum(p) || p == '_') + if (Isalnum(p) || p == '_') return 1; - if (isgraph(p)) + if (Isgraph(p)) return 2; return 0; } @@ -222,24 +222,24 @@ cv__isword(int p) * Return if p is part of a big word according to vi */ protected int -cv__isWord(int p) +cv__isWord(Int p) { - return (!isspace(p)); + return !Isspace(p); } /* c__prev_word(): * Find the previous word */ -protected char * -c__prev_word(char *p, char *low, int n, int (*wtest)(int)) +protected Char * +c__prev_word(Char *p, Char *low, int n, int (*wtest)(Int)) { p--; while (n--) { - while ((p >= low) && !(*wtest)((unsigned char) *p)) + while ((p >= low) && !(*wtest)(*p)) p--; - while ((p >= low) && (*wtest)((unsigned char) *p)) + while ((p >= low) && (*wtest)(*p)) p--; } @@ -248,117 +248,83 @@ c__prev_word(char *p, char *low, int n, int (*wtest)(int)) if (p < low) p = low; /* cp now points where we want it */ - return (p); + return p; } /* c__next_word(): * Find the next word */ -protected char * -c__next_word(char *p, char *high, int n, int (*wtest)(int)) +protected Char * +c__next_word(Char *p, Char *high, int n, int (*wtest)(Int)) { while (n--) { - while ((p < high) && !(*wtest)((unsigned char) *p)) + while ((p < high) && !(*wtest)(*p)) p++; - while ((p < high) && (*wtest)((unsigned char) *p)) + while ((p < high) && (*wtest)(*p)) p++; } if (p > high) p = high; /* p now points where we want it */ - return (p); + return p; } /* cv_next_word(): * Find the next word vi style */ -protected char * -cv_next_word(EditLine *el, char *p, char *high, int n, int (*wtest)(int)) +protected Char * +cv_next_word(EditLine *el, Char *p, Char *high, int n, int (*wtest)(Int)) { int test; while (n--) { - test = (*wtest)((unsigned char) *p); - while ((p < high) && (*wtest)((unsigned char) *p) == test) + test = (*wtest)(*p); + while ((p < high) && (*wtest)(*p) == test) p++; /* * vi historically deletes with cw only the word preserving the * trailing whitespace! This is not what 'w' does.. */ if (n || el->el_chared.c_vcmd.action != (DELETE|INSERT)) - while ((p < high) && isspace((unsigned char) *p)) + while ((p < high) && Isspace(*p)) p++; } /* p now points where we want it */ if (p > high) - return (high); + return high; else - return (p); + return p; } /* cv_prev_word(): * Find the previous word vi style */ -protected char * -cv_prev_word(char *p, char *low, int n, int (*wtest)(int)) +protected Char * +cv_prev_word(Char *p, Char *low, int n, int (*wtest)(Int)) { int test; p--; while (n--) { - while ((p > low) && isspace((unsigned char) *p)) + while ((p > low) && Isspace(*p)) p--; - test = (*wtest)((unsigned char) *p); - while ((p >= low) && (*wtest)((unsigned char) *p) == test) + test = (*wtest)(*p); + while ((p >= low) && (*wtest)(*p) == test) p--; } p++; /* p now points where we want it */ if (p < low) - return (low); + return low; else - return (p); + return p; } -#ifdef notdef -/* c__number(): - * Ignore character p points to, return number appearing after that. - * A '$' by itself means a big number; "$-" is for negative; '^' means 1. - * Return p pointing to last char used. - */ -protected char * -c__number( - char *p, /* character position */ - int *num, /* Return value */ - int dval) /* dval is the number to subtract from like $-3 */ -{ - int i; - int sign = 1; - - if (*++p == '^') { - *num = 1; - return (p); - } - if (*p == '$') { - if (*++p != '-') { - *num = 0x7fffffff; /* Handle $ */ - return (--p); - } - sign = -1; /* Handle $- */ - ++p; - } - for (i = 0; isdigit((unsigned char) *p); i = 10 * i + *p++ - '0') - continue; - *num = (sign < 0 ? dval - i : i); - return (--p); -} -#endif - /* cv_delfini(): * Finish vi delete action */ @@ -375,7 +341,7 @@ cv_delfini(EditLine *el) /* sanity */ return; - size = el->el_line.cursor - el->el_chared.c_vcmd.pos; + size = (int)(el->el_line.cursor - el->el_chared.c_vcmd.pos); if (size == 0) size = 1; el->el_line.cursor = el->el_chared.c_vcmd.pos; @@ -397,48 +363,26 @@ cv_delfini(EditLine *el) } -#ifdef notdef -/* ce__endword(): - * Go to the end of this word according to emacs - */ -protected char * -ce__endword(char *p, char *high, int n) -{ - p++; - - while (n--) { - while ((p < high) && isspace((unsigned char) *p)) - p++; - while ((p < high) && !isspace((unsigned char) *p)) - p++; - } - - p--; - return (p); -} -#endif - - /* cv__endword(): * Go to the end of this word according to vi */ -protected char * -cv__endword(char *p, char *high, int n, int (*wtest)(int)) +protected Char * +cv__endword(Char *p, Char *high, int n, int (*wtest)(Int)) { int test; p++; while (n--) { - while ((p < high) && isspace((unsigned char) *p)) + while ((p < high) && Isspace(*p)) p++; - test = (*wtest)((unsigned char) *p); - while ((p < high) && (*wtest)((unsigned char) *p) == test) + test = (*wtest)(*p); + while ((p < high) && (*wtest)(*p) == test) p++; } p--; - return (p); + return p; } /* ch_init(): @@ -449,24 +393,29 @@ ch_init(EditLine *el) { c_macro_t *ma = &el->el_chared.c_macro; - el->el_line.buffer = (char *) el_malloc(EL_BUFSIZ); + el->el_line.buffer = el_malloc(EL_BUFSIZ * + sizeof(*el->el_line.buffer)); if (el->el_line.buffer == NULL) - return (-1); + return -1; - (void) memset(el->el_line.buffer, 0, EL_BUFSIZ); + (void) memset(el->el_line.buffer, 0, EL_BUFSIZ * + sizeof(*el->el_line.buffer)); el->el_line.cursor = el->el_line.buffer; el->el_line.lastchar = el->el_line.buffer; el->el_line.limit = &el->el_line.buffer[EL_BUFSIZ - EL_LEAVE]; - el->el_chared.c_undo.buf = (char *) el_malloc(EL_BUFSIZ); + el->el_chared.c_undo.buf = el_malloc(EL_BUFSIZ * + sizeof(*el->el_chared.c_undo.buf)); if (el->el_chared.c_undo.buf == NULL) - return (-1); - (void) memset(el->el_chared.c_undo.buf, 0, EL_BUFSIZ); + return -1; + (void) memset(el->el_chared.c_undo.buf, 0, EL_BUFSIZ * + sizeof(*el->el_chared.c_undo.buf)); el->el_chared.c_undo.len = -1; el->el_chared.c_undo.cursor = 0; - el->el_chared.c_redo.buf = (char *) el_malloc(EL_BUFSIZ); + el->el_chared.c_redo.buf = el_malloc(EL_BUFSIZ * + sizeof(*el->el_chared.c_redo.buf)); if (el->el_chared.c_redo.buf == NULL) - return (-1); + return -1; el->el_chared.c_redo.pos = el->el_chared.c_redo.buf; el->el_chared.c_redo.lim = el->el_chared.c_redo.buf + EL_BUFSIZ; el->el_chared.c_redo.cmd = ED_UNASSIGNED; @@ -474,12 +423,16 @@ ch_init(EditLine *el) el->el_chared.c_vcmd.action = NOP; el->el_chared.c_vcmd.pos = el->el_line.buffer; - el->el_chared.c_kill.buf = (char *) el_malloc(EL_BUFSIZ); + el->el_chared.c_kill.buf = el_malloc(EL_BUFSIZ * + sizeof(*el->el_chared.c_kill.buf)); if (el->el_chared.c_kill.buf == NULL) - return (-1); - (void) memset(el->el_chared.c_kill.buf, 0, EL_BUFSIZ); + return -1; + (void) memset(el->el_chared.c_kill.buf, 0, EL_BUFSIZ * + sizeof(*el->el_chared.c_kill.buf)); el->el_chared.c_kill.mark = el->el_line.buffer; el->el_chared.c_kill.last = el->el_chared.c_kill.buf; + el->el_chared.c_resizefun = NULL; + el->el_chared.c_resizearg = NULL; el->el_map.current = el->el_map.key; @@ -491,10 +444,10 @@ ch_init(EditLine *el) ma->level = -1; ma->offset = 0; - ma->macro = (char **) el_malloc(EL_MAXMACRO * sizeof(char *)); + ma->macro = el_malloc(EL_MAXMACRO * sizeof(*ma->macro)); if (ma->macro == NULL) - return (-1); - return (0); + return -1; + return 0; } /* ch_reset(): @@ -529,12 +482,11 @@ ch_reset(EditLine *el, int mclear) } private void -ch__clearmacro(el) - EditLine *el; +ch__clearmacro(EditLine *el) { c_macro_t *ma = &el->el_chared.c_macro; while (ma->level >= 0) - el_free((ptr_t)ma->macro[ma->level--]); + el_free(ma->macro[ma->level--]); } /* ch_enlargebufs(): @@ -542,14 +494,12 @@ ch__clearmacro(el) * Returns 1 if successful, 0 if not. */ protected int -ch_enlargebufs(el, addlen) - EditLine *el; - size_t addlen; +ch_enlargebufs(EditLine *el, size_t addlen) { size_t sz, newsz; - char *newbuffer, *oldbuf, *oldkbuf; + Char *newbuffer, *oldbuf, *oldkbuf; - sz = el->el_line.limit - el->el_line.buffer + EL_LEAVE; + sz = (size_t)(el->el_line.limit - el->el_line.buffer + EL_LEAVE); newsz = sz * 2; /* * If newly required length is longer than current buffer, we need @@ -563,12 +513,12 @@ ch_enlargebufs(el, addlen) /* * Reallocate line buffer. */ - newbuffer = el_realloc(el->el_line.buffer, newsz); + newbuffer = el_realloc(el->el_line.buffer, newsz * sizeof(*newbuffer)); if (!newbuffer) return 0; /* zero the newly added memory, leave old data in */ - (void) memset(&newbuffer[sz], 0, newsz - sz); + (void) memset(&newbuffer[sz], 0, (newsz - sz) * sizeof(*newbuffer)); oldbuf = el->el_line.buffer; @@ -581,12 +531,13 @@ ch_enlargebufs(el, addlen) /* * Reallocate kill buffer. */ - newbuffer = el_realloc(el->el_chared.c_kill.buf, newsz); + newbuffer = el_realloc(el->el_chared.c_kill.buf, newsz * + sizeof(*newbuffer)); if (!newbuffer) return 0; /* zero the newly added memory, leave old data in */ - (void) memset(&newbuffer[sz], 0, newsz - sz); + (void) memset(&newbuffer[sz], 0, (newsz - sz) * sizeof(*newbuffer)); oldkbuf = el->el_chared.c_kill.buf; @@ -599,15 +550,17 @@ ch_enlargebufs(el, addlen) /* * Reallocate undo buffer. */ - newbuffer = el_realloc(el->el_chared.c_undo.buf, newsz); + newbuffer = el_realloc(el->el_chared.c_undo.buf, + newsz * sizeof(*newbuffer)); if (!newbuffer) return 0; /* zero the newly added memory, leave old data in */ - (void) memset(&newbuffer[sz], 0, newsz - sz); + (void) memset(&newbuffer[sz], 0, (newsz - sz) * sizeof(*newbuffer)); el->el_chared.c_undo.buf = newbuffer; - newbuffer = el_realloc(el->el_chared.c_redo.buf, newsz); + newbuffer = el_realloc(el->el_chared.c_redo.buf, + newsz * sizeof(*newbuffer)); if (!newbuffer) return 0; el->el_chared.c_redo.pos = newbuffer + @@ -621,6 +574,8 @@ ch_enlargebufs(el, addlen) /* Safe to set enlarged buffer size */ el->el_line.limit = &el->el_line.buffer[newsz - EL_LEAVE]; + if (el->el_chared.c_resizefun) + (*el->el_chared.c_resizefun)(el, el->el_chared.c_resizearg); return 1; } @@ -630,20 +585,20 @@ ch_enlargebufs(el, addlen) protected void ch_end(EditLine *el) { - el_free((ptr_t) el->el_line.buffer); + el_free(el->el_line.buffer); el->el_line.buffer = NULL; el->el_line.limit = NULL; - el_free((ptr_t) el->el_chared.c_undo.buf); + el_free(el->el_chared.c_undo.buf); el->el_chared.c_undo.buf = NULL; - el_free((ptr_t) el->el_chared.c_redo.buf); + el_free(el->el_chared.c_redo.buf); el->el_chared.c_redo.buf = NULL; el->el_chared.c_redo.pos = NULL; el->el_chared.c_redo.lim = NULL; el->el_chared.c_redo.cmd = ED_UNASSIGNED; - el_free((ptr_t) el->el_chared.c_kill.buf); + el_free(el->el_chared.c_kill.buf); el->el_chared.c_kill.buf = NULL; ch_reset(el, 1); - el_free((ptr_t) el->el_chared.c_macro.macro); + el_free(el->el_chared.c_macro.macro); el->el_chared.c_macro.macro = NULL; } @@ -652,21 +607,21 @@ ch_end(EditLine *el) * Insert string at cursorI */ public int -el_insertstr(EditLine *el, const char *s) +FUN(el,insertstr)(EditLine *el, const Char *s) { size_t len; - if ((len = strlen(s)) == 0) - return (-1); + if ((len = Strlen(s)) == 0) + return -1; if (el->el_line.lastchar + len >= el->el_line.limit) { if (!ch_enlargebufs(el, len)) - return (-1); + return -1; } c_insert(el, (int)len); while (*s) *el->el_line.cursor++ = *s++; - return (0); + return 0; } @@ -692,15 +647,15 @@ el_deletestr(EditLine *el, int n) * Get a string */ protected int -c_gets(EditLine *el, char *buf, const char *prompt) +c_gets(EditLine *el, Char *buf, const Char *prompt) { - char ch; - int len; - char *cp = el->el_line.buffer; + Char ch; + ssize_t len; + Char *cp = el->el_line.buffer; if (prompt) { - len = strlen(prompt); - memcpy(cp, prompt, len + 0u); + len = (ssize_t)Strlen(prompt); + (void)memcpy(cp, prompt, (size_t)len * sizeof(*cp)); cp += len; } len = 0; @@ -711,7 +666,7 @@ c_gets(EditLine *el, char *buf, const char *prompt) el->el_line.lastchar = cp + 1; re_refresh(el); - if (el_getc(el, &ch) != 1) { + if (FUN(el,getc)(el, &ch) != 1) { ed_end_of_file(el, 0); len = -1; break; @@ -721,7 +676,7 @@ c_gets(EditLine *el, char *buf, const char *prompt) case 0010: /* Delete and backspace */ case 0177: - if (len <= 0) { + if (len == 0) { len = -1; break; } @@ -735,8 +690,8 @@ c_gets(EditLine *el, char *buf, const char *prompt) break; default: - if (len >= EL_BUFSIZ - 16) - term_beep(el); + if (len >= (ssize_t)(EL_BUFSIZ - 16)) + terminal_beep(el); else { buf[len++] = ch; *cp++ = ch; @@ -749,7 +704,7 @@ c_gets(EditLine *el, char *buf, const char *prompt) el->el_line.buffer[0] = '\0'; el->el_line.lastchar = el->el_line.buffer; el->el_line.cursor = el->el_line.buffer; - return len; + return (int)len; } @@ -759,18 +714,26 @@ c_gets(EditLine *el, char *buf, const char *prompt) protected int c_hpos(EditLine *el) { - char *ptr; + Char *ptr; /* * Find how many characters till the beginning of this line. */ if (el->el_line.cursor == el->el_line.buffer) - return (0); + return 0; else { for (ptr = el->el_line.cursor - 1; ptr >= el->el_line.buffer && *ptr != '\n'; ptr--) continue; - return (el->el_line.cursor - ptr - 1); + return (int)(el->el_line.cursor - ptr - 1); } } + +protected int +ch_resizefun(EditLine *el, el_zfunc_t f, void *a) +{ + el->el_chared.c_resizefun = f; + el->el_chared.c_resizearg = a; + return 0; +} diff --git a/cmd-line-utils/libedit/chared.h b/cmd-line-utils/libedit/chared.h index fa8f5a58d83..176475ac8f0 100644 --- a/cmd-line-utils/libedit/chared.h +++ b/cmd-line-utils/libedit/chared.h @@ -1,4 +1,4 @@ -/* $NetBSD: chared.h,v 1.17 2006/03/06 21:11:56 christos Exp $ */ +/* $NetBSD: chared.h,v 1.21 2010/08/28 15:44:59 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -63,25 +63,25 @@ typedef struct c_macro_t { int level; int offset; - char **macro; + Char **macro; } c_macro_t; /* * Undo information for vi - no undo in emacs (yet) */ typedef struct c_undo_t { - int len; /* length of saved line */ + ssize_t len; /* length of saved line */ int cursor; /* position of saved cursor */ - char *buf; /* full saved text */ + Char *buf; /* full saved text */ } c_undo_t; /* redo for vi */ typedef struct c_redo_t { - char *buf; /* redo insert key sequence */ - char *pos; - char *lim; + Char *buf; /* redo insert key sequence */ + Char *pos; + Char *lim; el_action_t cmd; /* command to redo */ - char ch; /* char that invoked it */ + Char ch; /* char that invoked it */ int count; int action; /* from cv_action() */ } c_redo_t; @@ -91,18 +91,20 @@ typedef struct c_redo_t { */ typedef struct c_vcmd_t { int action; - char *pos; + Char *pos; } c_vcmd_t; /* * Kill buffer for emacs */ typedef struct c_kill_t { - char *buf; - char *last; - char *mark; + Char *buf; + Char *last; + Char *mark; } c_kill_t; +typedef void (*el_zfunc_t)(EditLine *, void *); + /* * Note that we use both data structures because the user can bind * commands from both editors! @@ -113,13 +115,14 @@ typedef struct el_chared_t { c_redo_t c_redo; c_vcmd_t c_vcmd; c_macro_t c_macro; + el_zfunc_t c_resizefun; + void * c_resizearg; } el_chared_t; #define STRQQ "\"\"" #define isglob(a) (strchr("*[]?", (a)) != NULL) -#define isword(a) (el_isprint(a)) #define NOP 0x00 #define DELETE 0x01 @@ -140,27 +143,28 @@ typedef struct el_chared_t { #include "fcns.h" -protected int cv__isword(int); -protected int cv__isWord(int); +protected int cv__isword(Int); +protected int cv__isWord(Int); protected void cv_delfini(EditLine *); -protected char *cv__endword(char *, char *, int, int (*)(int)); -protected int ce__isword(int); +protected Char *cv__endword(Char *, Char *, int, int (*)(Int)); +protected int ce__isword(Int); protected void cv_undo(EditLine *); -protected void cv_yank(EditLine *, const char *, int); -protected char *cv_next_word(EditLine*, char *, char *, int, int (*)(int)); -protected char *cv_prev_word(char *, char *, int, int (*)(int)); -protected char *c__next_word(char *, char *, int, int (*)(int)); -protected char *c__prev_word(char *, char *, int, int (*)(int)); +protected void cv_yank(EditLine *, const Char *, int); +protected Char *cv_next_word(EditLine*, Char *, Char *, int, int (*)(Int)); +protected Char *cv_prev_word(Char *, Char *, int, int (*)(Int)); +protected Char *c__next_word(Char *, Char *, int, int (*)(Int)); +protected Char *c__prev_word(Char *, Char *, int, int (*)(Int)); protected void c_insert(EditLine *, int); protected void c_delbefore(EditLine *, int); protected void c_delbefore1(EditLine *); protected void c_delafter(EditLine *, int); protected void c_delafter1(EditLine *); -protected int c_gets(EditLine *, char *, const char *); +protected int c_gets(EditLine *, Char *, const Char *); protected int c_hpos(EditLine *); protected int ch_init(EditLine *); protected void ch_reset(EditLine *, int); +protected int ch_resizefun(EditLine *, el_zfunc_t, void *); protected int ch_enlargebufs(EditLine *, size_t); protected void ch_end(EditLine *); diff --git a/cmd-line-utils/libedit/chartype.c b/cmd-line-utils/libedit/chartype.c new file mode 100644 index 00000000000..3d66c48c36e --- /dev/null +++ b/cmd-line-utils/libedit/chartype.c @@ -0,0 +1,364 @@ +/* $NetBSD: chartype.c,v 1.10 2011/08/16 16:25:15 christos Exp $ */ + +/*- + * Copyright (c) 2009 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * chartype.c: character classification and meta information + */ +#include "config.h" +#if !defined(lint) && !defined(SCCSID) +#endif /* not lint && not SCCSID */ +#include "el.h" +#include + +#define CT_BUFSIZ ((size_t)1024) + +#ifdef WIDECHAR +protected void +ct_conv_buff_resize(ct_buffer_t *conv, size_t mincsize, size_t minwsize) +{ + void *p; + if (mincsize > conv->csize) { + conv->csize = mincsize; + p = el_realloc(conv->cbuff, conv->csize * sizeof(*conv->cbuff)); + if (p == NULL) { + conv->csize = 0; + el_free(conv->cbuff); + conv->cbuff = NULL; + } else + conv->cbuff = p; + } + + if (minwsize > conv->wsize) { + conv->wsize = minwsize; + p = el_realloc(conv->wbuff, conv->wsize * sizeof(*conv->wbuff)); + if (p == NULL) { + conv->wsize = 0; + el_free(conv->wbuff); + conv->wbuff = NULL; + } else + conv->wbuff = p; + } +} + + +public char * +ct_encode_string(const Char *s, ct_buffer_t *conv) +{ + char *dst; + ssize_t used = 0; + mbstate_t state; + + memset(&state, 0, sizeof(mbstate_t)); + + if (!s) + return NULL; + if (!conv->cbuff) + ct_conv_buff_resize(conv, CT_BUFSIZ, (size_t)0); + if (!conv->cbuff) + return NULL; + + dst = conv->cbuff; + while (*s) { + used = (ssize_t)(conv->csize - (size_t)(dst - conv->cbuff)); + if (used < 5) { + used = dst - conv->cbuff; + ct_conv_buff_resize(conv, conv->csize + CT_BUFSIZ, + (size_t)0); + if (!conv->cbuff) + return NULL; + dst = conv->cbuff + used; + } + used = ct_encode_char(dst, (size_t)5, *s, &state); + if (used == -1) /* failed to encode, need more buffer space */ + abort(); + ++s; + dst += used; + } + *dst = '\0'; + return conv->cbuff; +} + +public Char * +ct_decode_string(const char *s, ct_buffer_t *conv) +{ + size_t len = 0; + + if (!s) + return NULL; + if (!conv->wbuff) + ct_conv_buff_resize(conv, (size_t)0, CT_BUFSIZ); + if (!conv->wbuff) + return NULL; + + len = ct_mbstowcs(NULL, s, (size_t)0); + if (len == (size_t)-1) + return NULL; + if (len > conv->wsize) + ct_conv_buff_resize(conv, (size_t)0, len + 1); + if (!conv->wbuff) + return NULL; + ct_mbstowcs(conv->wbuff, s, conv->wsize); + return conv->wbuff; +} + + +protected Char ** +ct_decode_argv(int argc, const char *argv[], ct_buffer_t *conv) +{ + size_t bufspace; + int i; + Char *p; + Char **wargv; + ssize_t bytes; + mbstate_t state; + + /* Make sure we have enough space in the conversion buffer to store all + * the argv strings. */ + for (i = 0, bufspace = 0; i < argc; ++i) + bufspace += argv[i] ? strlen(argv[i]) + 1 : 0; + ct_conv_buff_resize(conv, (size_t)0, bufspace); + if (!conv->wsize) + return NULL; + + wargv = el_malloc((size_t)argc * sizeof(*wargv)); + + for (i = 0, p = conv->wbuff; i < argc; ++i) { + if (!argv[i]) { /* don't pass null pointers to mbsrtowcs */ + wargv[i] = NULL; + continue; + } else { + wargv[i] = p; + memset(&state, 0, sizeof(mbstate_t)); + bytes = (ssize_t)mbsrtowcs(p, argv + i, bufspace, &state); + } + if (bytes == -1) { + el_free(wargv); + return NULL; + } else + bytes++; /* include '\0' in the count */ + bufspace -= (size_t)bytes; + p += bytes; + } + + return wargv; +} + + +protected size_t +ct_enc_width(Char c) +{ + /* UTF-8 encoding specific values */ + if (c < 0x80) + return 1; + else if (c < 0x0800) + return 2; + else if (c < 0x10000) + return 3; + else if (c < 0x110000) + return 4; + else + return 0; /* not a valid codepoint */ +} + +protected ssize_t +ct_encode_char(char *dst, size_t len, Char c, mbstate_t *state) +{ + ssize_t l = 0; + + if (len < ct_enc_width(c)) + return -1; + + l = wcrtomb(dst, c, state); + + if (l < 0) { + memset (state, 0, sizeof (mbstate_t)); + l = 0; + } + return l; +} +#endif + +protected const Char * +ct_visual_string(const Char *s) +{ + static Char *buff = NULL; + static size_t buffsize = 0; + void *p; + Char *dst; + ssize_t used = 0; + + if (!s) + return NULL; + if (!buff) { + buffsize = CT_BUFSIZ; + buff = el_malloc(buffsize * sizeof(*buff)); + } + dst = buff; + while (*s) { + used = ct_visual_char(dst, buffsize - (size_t)(dst - buff), *s); + if (used == -1) { /* failed to encode, need more buffer space */ + used = dst - buff; + buffsize += CT_BUFSIZ; + p = el_realloc(buff, buffsize * sizeof(*buff)); + if (p == NULL) + goto out; + buff = p; + dst = buff + used; + /* don't increment s here - we want to retry it! */ + } + else + ++s; + dst += used; + } + if (dst >= (buff + buffsize)) { /* sigh */ + buffsize += 1; + p = el_realloc(buff, buffsize * sizeof(*buff)); + if (p == NULL) + goto out; + buff = p; + dst = buff + buffsize - 1; + } + *dst = 0; + return buff; +out: + el_free(buff); + buffsize = 0; + return NULL; +} + +#ifdef WIDECHAR +int wcwidth(wchar_t wc); // Signature. +#endif + +protected int +ct_visual_width(Char c) +{ + int t = ct_chr_class(c); + switch (t) { + case CHTYPE_ASCIICTL: + return 2; /* ^@ ^? etc. */ + case CHTYPE_TAB: + return 1; /* Hmm, this really need to be handled outside! */ + case CHTYPE_NL: + return 0; /* Should this be 1 instead? */ +#ifdef WIDECHAR + case CHTYPE_PRINT: + return wcwidth(c); + case CHTYPE_NONPRINT: + if (c > 0xffff) /* prefer standard 4-byte display over 5-byte */ + return 8; /* \U+12345 */ + else + return 7; /* \U+1234 */ +#else + case CHTYPE_PRINT: + return 1; + case CHTYPE_NONPRINT: + return 4; /* \123 */ +#endif + default: + return 0; /* should not happen */ + } +} + + +protected ssize_t +ct_visual_char(Char *dst, size_t len, Char c) +{ + int t = ct_chr_class(c); + switch (t) { + case CHTYPE_TAB: + case CHTYPE_NL: + case CHTYPE_ASCIICTL: + if (len < 2) + return -1; /* insufficient space */ + *dst++ = '^'; + if (c == '\177') + *dst = '?'; /* DEL -> ^? */ + else + *dst = c | 0100; /* uncontrolify it */ + return 2; + case CHTYPE_PRINT: + if (len < 1) + return -1; /* insufficient space */ + *dst = c; + return 1; + case CHTYPE_NONPRINT: + /* we only use single-width glyphs for display, + * so this is right */ + if ((ssize_t)len < ct_visual_width(c)) + return -1; /* insufficient space */ +#ifdef WIDECHAR + *dst++ = '\\'; + *dst++ = 'U'; + *dst++ = '+'; +#define tohexdigit(v) "0123456789ABCDEF"[v] + if (c > 0xffff) /* prefer standard 4-byte display over 5-byte */ + *dst++ = tohexdigit(((unsigned int) c >> 16) & 0xf); + *dst++ = tohexdigit(((unsigned int) c >> 12) & 0xf); + *dst++ = tohexdigit(((unsigned int) c >> 8) & 0xf); + *dst++ = tohexdigit(((unsigned int) c >> 4) & 0xf); + *dst = tohexdigit(((unsigned int) c ) & 0xf); + return c > 0xffff ? 8 : 7; +#else + *dst++ = '\\'; +#define tooctaldigit(v) ((v) + '0') + *dst++ = tooctaldigit(((unsigned int) c >> 6) & 0x7); + *dst++ = tooctaldigit(((unsigned int) c >> 3) & 0x7); + *dst++ = tooctaldigit(((unsigned int) c ) & 0x7); +#endif + /*FALLTHROUGH*/ + /* these two should be handled outside this function */ + default: /* we should never hit the default */ + return 0; + } +} + + + + +protected int +ct_chr_class(Char c) +{ + if (c == '\t') + return CHTYPE_TAB; + else if (c == '\n') + return CHTYPE_NL; + else if (IsASCII(c) && Iscntrl(c)) + return CHTYPE_ASCIICTL; + else if (Isprint(c)) + return CHTYPE_PRINT; + else + return CHTYPE_NONPRINT; +} diff --git a/cmd-line-utils/libedit/chartype.h b/cmd-line-utils/libedit/chartype.h new file mode 100644 index 00000000000..678d13683be --- /dev/null +++ b/cmd-line-utils/libedit/chartype.h @@ -0,0 +1,252 @@ +/* $NetBSD: chartype.h,v 1.8 2011/07/29 23:44:44 christos Exp $ */ + +/*- + * Copyright (c) 2009 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _h_chartype_f +#define _h_chartype_f + + + +#ifdef WIDECHAR + +/* Ideally we should also test the value of the define to see if it + * supports non-BMP code points without requiring UTF-16, but nothing + * seems to actually advertise this properly, despite Unicode 3.1 having + * been around since 2001... */ + +/* XXXMYSQL : Added FreeBSD to bypass this check. + TODO : Verify if FreeBSD stores ISO 10646 in wchar_t. */ +#if !defined(__NetBSD__) && !defined(__sun) \ + && !(defined(__APPLE__) && defined(__MACH__)) \ + && !defined(__FreeBSD__) +#ifndef __STDC_ISO_10646__ +/* In many places it is assumed that the first 127 code points are ASCII + * compatible, so ensure wchar_t indeed does ISO 10646 and not some other + * funky encoding that could break us in weird and wonderful ways. */ + #error wchar_t must store ISO 10646 characters +#endif +#endif + +/* Oh for a with char32_t and __STDC_UTF_32__ in it... + * ref: ISO/IEC DTR 19769 + */ +#if WCHAR_MAX < INT32_MAX +#warning Build environment does not support non-BMP characters +#endif + +#ifndef HAVE_WCSDUP +wchar_t *wcsdup(const wchar_t *s); +#endif + +#define ct_wctomb wctomb +#define ct_wctomb_reset wctomb(0,0) +#define ct_wcstombs wcstombs +#define ct_mbstowcs mbstowcs + +#define Char wchar_t +#define Int wint_t +#define FUN(prefix,rest) prefix ## _w ## rest +#define FUNW(type) type ## _w +#define TYPE(type) type ## W +#define FSTR "%ls" +#define STR(x) L ## x +#define UC(c) c +#define Isalpha(x) iswalpha(x) +#define Isalnum(x) iswalnum(x) +#define Isgraph(x) iswgraph(x) +#define Isspace(x) iswspace(x) +#define Isdigit(x) iswdigit(x) +#define Iscntrl(x) iswcntrl(x) +#define Isprint(x) iswprint(x) + +#define Isupper(x) iswupper(x) +#define Islower(x) iswlower(x) +#define Toupper(x) towupper(x) +#define Tolower(x) towlower(x) + +#define IsASCII(x) (x < 0x100) + +#define Strlen(x) wcslen(x) +#define Strchr(s,c) wcschr(s,c) +#define Strrchr(s,c) wcsrchr(s,c) +#define Strstr(s,v) wcsstr(s,v) +#define Strdup(x) wcsdup(x) +#define Strcpy(d,s) wcscpy(d,s) +#define Strncpy(d,s,n) wcsncpy(d,s,n) +#define Strncat(d,s,n) wcsncat(d,s,n) + +#define Strcmp(s,v) wcscmp(s,v) +#define Strncmp(s,v,n) wcsncmp(s,v,n) +#define Strcspn(s,r) wcscspn(s,r) + +#define Strtol(p,e,b) wcstol(p,e,b) + +#define Width(c) wcwidth(c) + +#else /* NARROW */ + +#define ct_mbtowc error +#define ct_mbtowc_reset +#define ct_wctomb error +#define ct_wctomb_reset +#define ct_wcstombs(a, b, c) (strncpy(a, b, c), strlen(a)) +#define ct_mbstowcs(a, b, c) (strncpy(a, b, c), strlen(a)) + +#define Char char +#define Int int +#define FUN(prefix,rest) prefix ## _ ## rest +#define FUNW(type) type +#define TYPE(type) type +#define FSTR "%s" +#define STR(x) x +#define UC(c) (unsigned char)(c) + +#define Isalpha(x) isalpha((unsigned char)x) +#define Isalnum(x) isalnum((unsigned char)x) +#define Isgraph(x) isgraph((unsigned char)x) +#define Isspace(x) isspace((unsigned char)x) +#define Isdigit(x) isdigit((unsigned char)x) +#define Iscntrl(x) iscntrl((unsigned char)x) +#define Isprint(x) isprint((unsigned char)x) + +#define Isupper(x) isupper((unsigned char)x) +#define Islower(x) islower((unsigned char)x) +#define Toupper(x) toupper((unsigned char)x) +#define Tolower(x) tolower((unsigned char)x) + +#define IsASCII(x) isascii((unsigned char)x) + +#define Strlen(x) strlen(x) +#define Strchr(s,c) strchr(s,c) +#define Strrchr(s,c) strrchr(s,c) +#define Strstr(s,v) strstr(s,v) +#define Strdup(x) strdup(x) +#define Strcpy(d,s) strcpy(d,s) +#define Strncpy(d,s,n) strncpy(d,s,n) +#define Strncat(d,s,n) strncat(d,s,n) + +#define Strcmp(s,v) strcmp(s,v) +#define Strncmp(s,v,n) strncmp(s,v,n) +#define Strcspn(s,r) strcspn(s,r) + +#define Strtol(p,e,b) strtol(p,e,b) + +#define Width(c) 1 + +#endif + + +#ifdef WIDECHAR +/* + * Conversion buffer + */ +typedef struct ct_buffer_t { + char *cbuff; + size_t csize; + Char *wbuff; + size_t wsize; +} ct_buffer_t; + +#define ct_encode_string __ct_encode_string +/* Encode a wide-character string and return the UTF-8 encoded result. */ +public char *ct_encode_string(const Char *, ct_buffer_t *); + +#define ct_decode_string __ct_decode_string +/* Decode a (multi)?byte string and return the wide-character string result. */ +public Char *ct_decode_string(const char *, ct_buffer_t *); + +/* Decode a (multi)?byte argv string array. + * The pointer returned must be free()d when done. */ +protected Char **ct_decode_argv(int, const char *[], ct_buffer_t *); + +/* Resizes the conversion buffer(s) if needed. */ +protected void ct_conv_buff_resize(ct_buffer_t *, size_t, size_t); +protected ssize_t ct_encode_char(char *, size_t, Char, mbstate_t *); +protected size_t ct_enc_width(Char); + +#define ct_free_argv(s) el_free(s) + +#else +#define ct_encode_string(s, b) (s) +#define ct_decode_string(s, b) (s) +#define ct_decode_argv(l, s, b) (s) +#define ct_conv_buff_resize(b, os, ns) +#define ct_encode_char(d, l, s, ps) (*d = s, 1) +#define ct_free_argv(s) +#endif + +#ifndef NARROWCHAR +/* Encode a characted into the destination buffer, provided there is sufficent + * buffer space available. Returns the number of bytes used up (zero if the + * character cannot be encoded, -1 if there was not enough space available). */ + +/* The maximum buffer size to hold the most unwieldly visual representation, + * in this case \U+nnnnn. */ +#define VISUAL_WIDTH_MAX ((size_t)8) + +/* The terminal is thought of in terms of X columns by Y lines. In the cases + * where a wide character takes up more than one column, the adjacent + * occupied column entries will contain this faux character. */ +#define MB_FILL_CHAR ((Char)-1) + +/* Visual width of character c, taking into account ^? , \0177 and \U+nnnnn + * style visual expansions. */ +protected int ct_visual_width(Char); + +/* Turn the given character into the appropriate visual format, matching + * the width given by ct_visual_width(). Returns the number of characters used + * up, or -1 if insufficient space. Buffer length is in count of Char's. */ +protected ssize_t ct_visual_char(Char *, size_t, Char); + +/* Convert the given string into visual format, using the ct_visual_char() + * function. Uses a static buffer, so not threadsafe. */ +protected const Char *ct_visual_string(const Char *); + + +/* printable character, use ct_visual_width() to find out display width */ +#define CHTYPE_PRINT ( 0) +/* control character found inside the ASCII portion of the charset */ +#define CHTYPE_ASCIICTL (-1) +/* a \t */ +#define CHTYPE_TAB (-2) +/* a \n */ +#define CHTYPE_NL (-3) +/* non-printable character */ +#define CHTYPE_NONPRINT (-4) +/* classification of character c, as one of the above defines */ +protected int ct_chr_class(Char c); +#endif + + +#endif /* _chartype_f */ diff --git a/cmd-line-utils/libedit/common.c b/cmd-line-utils/libedit/common.c index ba5890fa606..c0512061e6f 100644 --- a/cmd-line-utils/libedit/common.c +++ b/cmd-line-utils/libedit/common.c @@ -1,4 +1,4 @@ -/* $NetBSD: common.c,v 1.21 2008/09/30 08:37:42 aymeric Exp $ */ +/* $NetBSD: common.c,v 1.28 2011/07/29 20:58:07 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -51,12 +51,12 @@ static char sccsid[] = "@(#)common.c 8.1 (Berkeley) 6/4/93"; */ protected el_action_t /*ARGSUSED*/ -ed_end_of_file(EditLine *el, int c __attribute__((__unused__))) +ed_end_of_file(EditLine *el, Int c __attribute__((__unused__))) { re_goto_bottom(el); *el->el_line.lastchar = '\0'; - return (CC_EOF); + return CC_EOF; } @@ -65,12 +65,12 @@ ed_end_of_file(EditLine *el, int c __attribute__((__unused__))) * Insert a character [bound to all insert keys] */ protected el_action_t -ed_insert(EditLine *el, int c) +ed_insert(EditLine *el, Int c) { int count = el->el_state.argument; if (c == '\0') - return (CC_ERROR); + return CC_ERROR; if (el->el_line.lastchar + el->el_state.argument >= el->el_line.limit) { @@ -98,7 +98,7 @@ ed_insert(EditLine *el, int c) if (el->el_state.inputmode == MODE_REPLACE_1) return vi_command_mode(el, 0); - return (CC_NORM); + return CC_NORM; } @@ -108,12 +108,12 @@ ed_insert(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -ed_delete_prev_word(EditLine *el, int c __attribute__((__unused__))) +ed_delete_prev_word(EditLine *el, Int c __attribute__((__unused__))) { - char *cp, *p, *kp; + Char *cp, *p, *kp; if (el->el_line.cursor == el->el_line.buffer) - return (CC_ERROR); + return CC_ERROR; cp = c__prev_word(el->el_line.cursor, el->el_line.buffer, el->el_state.argument, ce__isword); @@ -122,11 +122,11 @@ ed_delete_prev_word(EditLine *el, int c __attribute__((__unused__))) *kp++ = *p; el->el_chared.c_kill.last = kp; - c_delbefore(el, el->el_line.cursor - cp); /* delete before dot */ + c_delbefore(el, (int)(el->el_line.cursor - cp));/* delete before dot */ el->el_line.cursor = cp; if (el->el_line.cursor < el->el_line.buffer) el->el_line.cursor = el->el_line.buffer; /* bounds check */ - return (CC_REFRESH); + return CC_REFRESH; } @@ -136,9 +136,9 @@ ed_delete_prev_word(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -ed_delete_next_char(EditLine *el, int c __attribute__((__unused__))) +ed_delete_next_char(EditLine *el, Int c __attribute__((__unused__))) { -#ifdef notdef /* XXX */ +#ifdef DEBUG_EDIT #define EL el->el_line (void) fprintf(el->el_errlfile, "\nD(b: %x(%s) c: %x(%s) last: %x(%s) limit: %x(%s)\n", @@ -151,24 +151,24 @@ ed_delete_next_char(EditLine *el, int c __attribute__((__unused__))) if (el->el_line.cursor == el->el_line.buffer) { /* if I'm also at the beginning */ #ifdef KSHVI - return (CC_ERROR); + return CC_ERROR; #else /* then do an EOF */ - term_writechar(el, c); - return (CC_EOF); + terminal_writec(el, c); + return CC_EOF; #endif } else { #ifdef KSHVI el->el_line.cursor--; #else - return (CC_ERROR); + return CC_ERROR; #endif } } else { if (el->el_line.cursor != el->el_line.buffer) el->el_line.cursor--; else - return (CC_ERROR); + return CC_ERROR; } } c_delafter(el, el->el_state.argument); /* delete after dot */ @@ -176,7 +176,7 @@ ed_delete_next_char(EditLine *el, int c __attribute__((__unused__))) el->el_line.cursor > el->el_line.buffer) /* bounds check */ el->el_line.cursor = el->el_line.lastchar - 1; - return (CC_REFRESH); + return CC_REFRESH; } @@ -186,9 +186,9 @@ ed_delete_next_char(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -ed_kill_line(EditLine *el, int c __attribute__((__unused__))) +ed_kill_line(EditLine *el, Int c __attribute__((__unused__))) { - char *kp, *cp; + Char *kp, *cp; cp = el->el_line.cursor; kp = el->el_chared.c_kill.buf; @@ -197,7 +197,7 @@ ed_kill_line(EditLine *el, int c __attribute__((__unused__))) el->el_chared.c_kill.last = kp; /* zap! -- delete to end */ el->el_line.lastchar = el->el_line.cursor; - return (CC_REFRESH); + return CC_REFRESH; } @@ -207,20 +207,20 @@ ed_kill_line(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -ed_move_to_end(EditLine *el, int c __attribute__((__unused__))) +ed_move_to_end(EditLine *el, Int c __attribute__((__unused__))) { el->el_line.cursor = el->el_line.lastchar; if (el->el_map.type == MAP_VI) { if (el->el_chared.c_vcmd.action != NOP) { cv_delfini(el); - return (CC_REFRESH); + return CC_REFRESH; } #ifdef VI_MOVE el->el_line.cursor--; #endif } - return (CC_CURSOR); + return CC_CURSOR; } @@ -230,21 +230,21 @@ ed_move_to_end(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -ed_move_to_beg(EditLine *el, int c __attribute__((__unused__))) +ed_move_to_beg(EditLine *el, Int c __attribute__((__unused__))) { el->el_line.cursor = el->el_line.buffer; if (el->el_map.type == MAP_VI) { /* We want FIRST non space character */ - while (isspace((unsigned char) *el->el_line.cursor)) + while (Isspace(*el->el_line.cursor)) el->el_line.cursor++; if (el->el_chared.c_vcmd.action != NOP) { cv_delfini(el); - return (CC_REFRESH); + return CC_REFRESH; } } - return (CC_CURSOR); + return CC_CURSOR; } @@ -253,12 +253,12 @@ ed_move_to_beg(EditLine *el, int c __attribute__((__unused__))) * [^T] [^T] */ protected el_action_t -ed_transpose_chars(EditLine *el, int c) +ed_transpose_chars(EditLine *el, Int c) { if (el->el_line.cursor < el->el_line.lastchar) { if (el->el_line.lastchar <= &el->el_line.buffer[1]) - return (CC_ERROR); + return CC_ERROR; else el->el_line.cursor++; } @@ -267,9 +267,9 @@ ed_transpose_chars(EditLine *el, int c) c = el->el_line.cursor[-2]; el->el_line.cursor[-2] = el->el_line.cursor[-1]; el->el_line.cursor[-1] = c; - return (CC_REFRESH); + return CC_REFRESH; } else - return (CC_ERROR); + return CC_ERROR; } @@ -279,15 +279,15 @@ ed_transpose_chars(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -ed_next_char(EditLine *el, int c __attribute__((__unused__))) +ed_next_char(EditLine *el, Int c __attribute__((__unused__))) { - char *lim = el->el_line.lastchar; + Char *lim = el->el_line.lastchar; if (el->el_line.cursor >= lim || (el->el_line.cursor == lim - 1 && el->el_map.type == MAP_VI && el->el_chared.c_vcmd.action == NOP)) - return (CC_ERROR); + return CC_ERROR; el->el_line.cursor += el->el_state.argument; if (el->el_line.cursor > lim) @@ -296,9 +296,9 @@ ed_next_char(EditLine *el, int c __attribute__((__unused__))) if (el->el_map.type == MAP_VI) if (el->el_chared.c_vcmd.action != NOP) { cv_delfini(el); - return (CC_REFRESH); + return CC_REFRESH; } - return (CC_CURSOR); + return CC_CURSOR; } @@ -308,11 +308,11 @@ ed_next_char(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -ed_prev_word(EditLine *el, int c __attribute__((__unused__))) +ed_prev_word(EditLine *el, Int c __attribute__((__unused__))) { if (el->el_line.cursor == el->el_line.buffer) - return (CC_ERROR); + return CC_ERROR; el->el_line.cursor = c__prev_word(el->el_line.cursor, el->el_line.buffer, @@ -322,9 +322,9 @@ ed_prev_word(EditLine *el, int c __attribute__((__unused__))) if (el->el_map.type == MAP_VI) if (el->el_chared.c_vcmd.action != NOP) { cv_delfini(el); - return (CC_REFRESH); + return CC_REFRESH; } - return (CC_CURSOR); + return CC_CURSOR; } @@ -334,7 +334,7 @@ ed_prev_word(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -ed_prev_char(EditLine *el, int c __attribute__((__unused__))) +ed_prev_char(EditLine *el, Int c __attribute__((__unused__))) { if (el->el_line.cursor > el->el_line.buffer) { @@ -345,11 +345,11 @@ ed_prev_char(EditLine *el, int c __attribute__((__unused__))) if (el->el_map.type == MAP_VI) if (el->el_chared.c_vcmd.action != NOP) { cv_delfini(el); - return (CC_REFRESH); + return CC_REFRESH; } - return (CC_CURSOR); + return CC_CURSOR; } else - return (CC_ERROR); + return CC_ERROR; } @@ -358,19 +358,19 @@ ed_prev_char(EditLine *el, int c __attribute__((__unused__))) * [^V] [^V] */ protected el_action_t -ed_quoted_insert(EditLine *el, int c) +ed_quoted_insert(EditLine *el, Int c) { int num; - char tc; + Char tc; tty_quotemode(el); - num = el_getc(el, &tc); - c = (unsigned char) tc; + num = FUN(el,getc)(el, &tc); + c = tc; tty_noquotemode(el); if (num == 1) - return (ed_insert(el, c)); + return ed_insert(el, c); else - return (ed_end_of_file(el, 0)); + return ed_end_of_file(el, 0); } @@ -378,11 +378,11 @@ ed_quoted_insert(EditLine *el, int c) * Adds to argument or enters a digit */ protected el_action_t -ed_digit(EditLine *el, int c) +ed_digit(EditLine *el, Int c) { - if (!isdigit(c)) - return (CC_ERROR); + if (!Isdigit(c)) + return CC_ERROR; if (el->el_state.doingarg) { /* if doing an arg, add this in... */ @@ -390,11 +390,11 @@ ed_digit(EditLine *el, int c) el->el_state.argument = c - '0'; else { if (el->el_state.argument > 1000000) - return (CC_ERROR); + return CC_ERROR; el->el_state.argument = (el->el_state.argument * 10) + (c - '0'); } - return (CC_ARGHACK); + return CC_ARGHACK; } return ed_insert(el, c); @@ -406,22 +406,22 @@ ed_digit(EditLine *el, int c) * For ESC-n */ protected el_action_t -ed_argument_digit(EditLine *el, int c) +ed_argument_digit(EditLine *el, Int c) { - if (!isdigit(c)) - return (CC_ERROR); + if (!Isdigit(c)) + return CC_ERROR; if (el->el_state.doingarg) { if (el->el_state.argument > 1000000) - return (CC_ERROR); + return CC_ERROR; el->el_state.argument = (el->el_state.argument * 10) + (c - '0'); } else { /* else starting an argument */ el->el_state.argument = c - '0'; el->el_state.doingarg = 1; } - return (CC_ARGHACK); + return CC_ARGHACK; } @@ -432,10 +432,10 @@ ed_argument_digit(EditLine *el, int c) protected el_action_t /*ARGSUSED*/ ed_unassigned(EditLine *el __attribute__((__unused__)), - int c __attribute__((__unused__))) + Int c __attribute__((__unused__))) { - return (CC_ERROR); + return CC_ERROR; } @@ -450,10 +450,10 @@ ed_unassigned(EditLine *el __attribute__((__unused__)), protected el_action_t /*ARGSUSED*/ ed_tty_sigint(EditLine *el __attribute__((__unused__)), - int c __attribute__((__unused__))) + Int c __attribute__((__unused__))) { - return (CC_NORM); + return CC_NORM; } @@ -464,10 +464,10 @@ ed_tty_sigint(EditLine *el __attribute__((__unused__)), protected el_action_t /*ARGSUSED*/ ed_tty_dsusp(EditLine *el __attribute__((__unused__)), - int c __attribute__((__unused__))) + Int c __attribute__((__unused__))) { - return (CC_NORM); + return CC_NORM; } @@ -478,10 +478,10 @@ ed_tty_dsusp(EditLine *el __attribute__((__unused__)), protected el_action_t /*ARGSUSED*/ ed_tty_flush_output(EditLine *el __attribute__((__unused__)), - int c __attribute__((__unused__))) + Int c __attribute__((__unused__))) { - return (CC_NORM); + return CC_NORM; } @@ -492,10 +492,10 @@ ed_tty_flush_output(EditLine *el __attribute__((__unused__)), protected el_action_t /*ARGSUSED*/ ed_tty_sigquit(EditLine *el __attribute__((__unused__)), - int c __attribute__((__unused__))) + Int c __attribute__((__unused__))) { - return (CC_NORM); + return CC_NORM; } @@ -506,10 +506,10 @@ ed_tty_sigquit(EditLine *el __attribute__((__unused__)), protected el_action_t /*ARGSUSED*/ ed_tty_sigtstp(EditLine *el __attribute__((__unused__)), - int c __attribute__((__unused__))) + Int c __attribute__((__unused__))) { - return (CC_NORM); + return CC_NORM; } @@ -520,10 +520,10 @@ ed_tty_sigtstp(EditLine *el __attribute__((__unused__)), protected el_action_t /*ARGSUSED*/ ed_tty_stop_output(EditLine *el __attribute__((__unused__)), - int c __attribute__((__unused__))) + Int c __attribute__((__unused__))) { - return (CC_NORM); + return CC_NORM; } @@ -534,10 +534,10 @@ ed_tty_stop_output(EditLine *el __attribute__((__unused__)), protected el_action_t /*ARGSUSED*/ ed_tty_start_output(EditLine *el __attribute__((__unused__)), - int c __attribute__((__unused__))) + Int c __attribute__((__unused__))) { - return (CC_NORM); + return CC_NORM; } @@ -547,13 +547,13 @@ ed_tty_start_output(EditLine *el __attribute__((__unused__)), */ protected el_action_t /*ARGSUSED*/ -ed_newline(EditLine *el, int c __attribute__((__unused__))) +ed_newline(EditLine *el, Int c __attribute__((__unused__))) { re_goto_bottom(el); *el->el_line.lastchar++ = '\n'; *el->el_line.lastchar = '\0'; - return (CC_NEWLINE); + return CC_NEWLINE; } @@ -563,17 +563,17 @@ ed_newline(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -ed_delete_prev_char(EditLine *el, int c __attribute__((__unused__))) +ed_delete_prev_char(EditLine *el, Int c __attribute__((__unused__))) { if (el->el_line.cursor <= el->el_line.buffer) - return (CC_ERROR); + return CC_ERROR; c_delbefore(el, el->el_state.argument); el->el_line.cursor -= el->el_state.argument; if (el->el_line.cursor < el->el_line.buffer) el->el_line.cursor = el->el_line.buffer; - return (CC_REFRESH); + return CC_REFRESH; } @@ -583,12 +583,12 @@ ed_delete_prev_char(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -ed_clear_screen(EditLine *el, int c __attribute__((__unused__))) +ed_clear_screen(EditLine *el, Int c __attribute__((__unused__))) { - term_clear_screen(el); /* clear the whole real screen */ + terminal_clear_screen(el); /* clear the whole real screen */ re_clear_display(el); /* reset everything */ - return (CC_REFRESH); + return CC_REFRESH; } @@ -599,10 +599,10 @@ ed_clear_screen(EditLine *el, int c __attribute__((__unused__))) protected el_action_t /*ARGSUSED*/ ed_redisplay(EditLine *el __attribute__((__unused__)), - int c __attribute__((__unused__))) + Int c __attribute__((__unused__))) { - return (CC_REDISPLAY); + return CC_REDISPLAY; } @@ -612,11 +612,11 @@ ed_redisplay(EditLine *el __attribute__((__unused__)), */ protected el_action_t /*ARGSUSED*/ -ed_start_over(EditLine *el, int c __attribute__((__unused__))) +ed_start_over(EditLine *el, Int c __attribute__((__unused__))) { ch_reset(el, 0); - return (CC_REFRESH); + return CC_REFRESH; } @@ -627,10 +627,10 @@ ed_start_over(EditLine *el, int c __attribute__((__unused__))) protected el_action_t /*ARGSUSED*/ ed_sequence_lead_in(EditLine *el __attribute__((__unused__)), - int c __attribute__((__unused__))) + Int c __attribute__((__unused__))) { - return (CC_NORM); + return CC_NORM; } @@ -640,7 +640,7 @@ ed_sequence_lead_in(EditLine *el __attribute__((__unused__)), */ protected el_action_t /*ARGSUSED*/ -ed_prev_history(EditLine *el, int c __attribute__((__unused__))) +ed_prev_history(EditLine *el, Int c __attribute__((__unused__))) { char beep = 0; int sv_event = el->el_history.eventno; @@ -650,7 +650,7 @@ ed_prev_history(EditLine *el, int c __attribute__((__unused__))) if (el->el_history.eventno == 0) { /* save the current buffer * away */ - (void) strncpy(el->el_history.buf, el->el_line.buffer, + (void) Strncpy(el->el_history.buf, el->el_line.buffer, EL_BUFSIZ); el->el_history.last = el->el_history.buf + (el->el_line.lastchar - el->el_line.buffer); @@ -660,7 +660,7 @@ ed_prev_history(EditLine *el, int c __attribute__((__unused__))) if (hist_get(el) == CC_ERROR) { if (el->el_map.type == MAP_VI) { el->el_history.eventno = sv_event; - return CC_ERROR; + } beep = 1; /* el->el_history.eventno was fixed by first call */ @@ -678,7 +678,7 @@ ed_prev_history(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -ed_next_history(EditLine *el, int c __attribute__((__unused__))) +ed_next_history(EditLine *el, Int c __attribute__((__unused__))) { el_action_t beep = CC_REFRESH, rval; @@ -705,9 +705,9 @@ ed_next_history(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -ed_search_prev_history(EditLine *el, int c __attribute__((__unused__))) +ed_search_prev_history(EditLine *el, Int c __attribute__((__unused__))) { - const char *hp; + const Char *hp; int h; bool_t found = 0; @@ -720,20 +720,20 @@ ed_search_prev_history(EditLine *el, int c __attribute__((__unused__))) "e_prev_search_hist(): eventno < 0;\n"); #endif el->el_history.eventno = 0; - return (CC_ERROR); + return CC_ERROR; } if (el->el_history.eventno == 0) { - (void) strncpy(el->el_history.buf, el->el_line.buffer, + (void) Strncpy(el->el_history.buf, el->el_line.buffer, EL_BUFSIZ); el->el_history.last = el->el_history.buf + (el->el_line.lastchar - el->el_line.buffer); } if (el->el_history.ref == NULL) - return (CC_ERROR); + return CC_ERROR; hp = HIST_FIRST(el); if (hp == NULL) - return (CC_ERROR); + return CC_ERROR; c_setpat(el); /* Set search pattern !! */ @@ -744,7 +744,7 @@ ed_search_prev_history(EditLine *el, int c __attribute__((__unused__))) #ifdef SDEBUG (void) fprintf(el->el_errfile, "Comparing with \"%s\"\n", hp); #endif - if ((strncmp(hp, el->el_line.buffer, (size_t) + if ((Strncmp(hp, el->el_line.buffer, (size_t) (el->el_line.lastchar - el->el_line.buffer)) || hp[el->el_line.lastchar - el->el_line.buffer]) && c_hmatch(el, hp)) { @@ -759,11 +759,11 @@ ed_search_prev_history(EditLine *el, int c __attribute__((__unused__))) #ifdef SDEBUG (void) fprintf(el->el_errfile, "not found\n"); #endif - return (CC_ERROR); + return CC_ERROR; } el->el_history.eventno = h; - return (hist_get(el)); + return hist_get(el); } @@ -773,9 +773,9 @@ ed_search_prev_history(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -ed_search_next_history(EditLine *el, int c __attribute__((__unused__))) +ed_search_next_history(EditLine *el, Int c __attribute__((__unused__))) { - const char *hp; + const Char *hp; int h; bool_t found = 0; @@ -784,14 +784,14 @@ ed_search_next_history(EditLine *el, int c __attribute__((__unused__))) *el->el_line.lastchar = '\0'; /* just in case */ if (el->el_history.eventno == 0) - return (CC_ERROR); + return CC_ERROR; if (el->el_history.ref == NULL) - return (CC_ERROR); + return CC_ERROR; hp = HIST_FIRST(el); if (hp == NULL) - return (CC_ERROR); + return CC_ERROR; c_setpat(el); /* Set search pattern !! */ @@ -799,7 +799,7 @@ ed_search_next_history(EditLine *el, int c __attribute__((__unused__))) #ifdef SDEBUG (void) fprintf(el->el_errfile, "Comparing with \"%s\"\n", hp); #endif - if ((strncmp(hp, el->el_line.buffer, (size_t) + if ((Strncmp(hp, el->el_line.buffer, (size_t) (el->el_line.lastchar - el->el_line.buffer)) || hp[el->el_line.lastchar - el->el_line.buffer]) && c_hmatch(el, hp)) @@ -812,12 +812,12 @@ ed_search_next_history(EditLine *el, int c __attribute__((__unused__))) #ifdef SDEBUG (void) fprintf(el->el_errfile, "not found\n"); #endif - return (CC_ERROR); + return CC_ERROR; } } el->el_history.eventno = found; - return (hist_get(el)); + return hist_get(el); } @@ -827,9 +827,9 @@ ed_search_next_history(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -ed_prev_line(EditLine *el, int c __attribute__((__unused__))) +ed_prev_line(EditLine *el, Int c __attribute__((__unused__))) { - char *ptr; + Char *ptr; int nchars = c_hpos(el); /* @@ -843,7 +843,7 @@ ed_prev_line(EditLine *el, int c __attribute__((__unused__))) break; if (el->el_state.argument > 0) - return (CC_ERROR); + return CC_ERROR; /* * Move to the beginning of the line @@ -860,7 +860,7 @@ ed_prev_line(EditLine *el, int c __attribute__((__unused__))) continue; el->el_line.cursor = ptr; - return (CC_CURSOR); + return CC_CURSOR; } @@ -870,9 +870,9 @@ ed_prev_line(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -ed_next_line(EditLine *el, int c __attribute__((__unused__))) +ed_next_line(EditLine *el, Int c __attribute__((__unused__))) { - char *ptr; + Char *ptr; int nchars = c_hpos(el); /* @@ -883,7 +883,7 @@ ed_next_line(EditLine *el, int c __attribute__((__unused__))) break; if (el->el_state.argument > 0) - return (CC_ERROR); + return CC_ERROR; /* * Move to the character requested @@ -894,7 +894,7 @@ ed_next_line(EditLine *el, int c __attribute__((__unused__))) continue; el->el_line.cursor = ptr; - return (CC_CURSOR); + return CC_CURSOR; } @@ -904,16 +904,16 @@ ed_next_line(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -ed_command(EditLine *el, int c __attribute__((__unused__))) +ed_command(EditLine *el, Int c __attribute__((__unused__))) { - char tmpbuf[EL_BUFSIZ]; + Char tmpbuf[EL_BUFSIZ]; int tmplen; - tmplen = c_gets(el, tmpbuf, "\n: "); - term__putc(el, '\n'); + tmplen = c_gets(el, tmpbuf, STR("\n: ")); + terminal__putc(el, '\n'); if (tmplen < 0 || (tmpbuf[tmplen] = 0, parse_line(el, tmpbuf)) == -1) - term_beep(el); + terminal_beep(el); el->el_map.current = el->el_map.key; re_clear_display(el); diff --git a/cmd-line-utils/libedit/config.h b/cmd-line-utils/libedit/config.h index 2c3989ee316..c06d5e28a0a 100644 --- a/cmd-line-utils/libedit/config.h +++ b/cmd-line-utils/libedit/config.h @@ -1,2 +1,5 @@ #include "my_config.h" #include "sys.h" +#ifndef NARROW_WRAPPER +#define WIDECHAR +#endif diff --git a/cmd-line-utils/libedit/el.c b/cmd-line-utils/libedit/el.c index c7f8386773d..c7f4f81ec93 100644 --- a/cmd-line-utils/libedit/el.c +++ b/cmd-line-utils/libedit/el.c @@ -1,4 +1,4 @@ -/* $NetBSD: el.c,v 1.47 2009/01/18 12:17:24 lukem Exp $ */ +/* $NetBSD: el.c,v 1.68 2011/07/29 15:16:33 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -48,6 +48,9 @@ static char sccsid[] = "@(#)el.c 8.2 (Berkeley) 1/3/94"; #include #include #include +#include +#include +#include #include "el.h" /* el_init(): @@ -56,11 +59,10 @@ static char sccsid[] = "@(#)el.c 8.2 (Berkeley) 1/3/94"; public EditLine * el_init(const char *prog, FILE *fin, FILE *fout, FILE *ferr) { - - EditLine *el = (EditLine *) el_malloc(sizeof(EditLine)); + EditLine *el = el_malloc(sizeof(*el)); if (el == NULL) - return (NULL); + return NULL; memset(el, 0, sizeof(EditLine)); @@ -69,8 +71,11 @@ el_init(const char *prog, FILE *fin, FILE *fout, FILE *ferr) el->el_errfile = ferr; el->el_infd = fileno(fin); + el->el_outfd = fileno(fout); + el->el_errfd = fileno(ferr); - if ((el->el_prog = el_strdup(prog)) == NULL) { + el->el_prog = Strdup(ct_decode_string(prog, &el->el_scratch)); + if (el->el_prog == NULL) { el_free(el); return NULL; } @@ -79,13 +84,18 @@ el_init(const char *prog, FILE *fin, FILE *fout, FILE *ferr) * Initialize all the modules. Order is important!!! */ el->el_flags = 0; +#ifdef WIDECHAR + setlocale(LC_CTYPE, NULL); + if (MB_CUR_MAX > 1) + el->el_flags |= CHARSET_IS_MULTIBYTE; +#endif - if (term_init(el) == -1) { + if (terminal_init(el) == -1) { el_free(el->el_prog); el_free(el); return NULL; } - (void) key_init(el); + (void) keymacro_init(el); (void) map_init(el); if (tty_init(el) == -1) el->el_flags |= NO_TTY; @@ -96,7 +106,7 @@ el_init(const char *prog, FILE *fin, FILE *fout, FILE *ferr) (void) sig_init(el); (void) read_init(el); - return (el); + return el; } @@ -112,8 +122,8 @@ el_end(EditLine *el) el_reset(el); - term_end(el); - key_end(el); + terminal_end(el); + keymacro_end(el); map_end(el); tty_end(el); ch_end(el); @@ -122,8 +132,14 @@ el_end(EditLine *el) prompt_end(el); sig_end(el); - el_free((ptr_t) el->el_prog); - el_free((ptr_t) el); + el_free(el->el_prog); +#ifdef WIDECHAR + el_free(el->el_scratch.cbuff); + el_free(el->el_scratch.wbuff); + el_free(el->el_lgcyconv.cbuff); + el_free(el->el_lgcyconv.wbuff); +#endif + el_free(el); } @@ -143,27 +159,46 @@ el_reset(EditLine *el) * set the editline parameters */ public int -el_set(EditLine *el, int op, ...) +FUN(el,set)(EditLine *el, int op, ...) { va_list ap; int rv = 0; if (el == NULL) - return (-1); + return -1; va_start(ap, op); switch (op) { case EL_PROMPT: - case EL_RPROMPT: - rv = prompt_set(el, va_arg(ap, el_pfunc_t), op); + case EL_RPROMPT: { + el_pfunc_t p = va_arg(ap, el_pfunc_t); + + rv = prompt_set(el, p, 0, op, 1); break; + } + + case EL_RESIZE: { + el_zfunc_t p = va_arg(ap, el_zfunc_t); + void *arg = va_arg(ap, void *); + rv = ch_resizefun(el, p, arg); + break; + } + + case EL_PROMPT_ESC: + case EL_RPROMPT_ESC: { + el_pfunc_t p = va_arg(ap, el_pfunc_t); + int c = va_arg(ap, int); + + rv = prompt_set(el, p, c, op, 1); + break; + } case EL_TERMINAL: - rv = term_set(el, va_arg(ap, char *)); + rv = terminal_set(el, va_arg(ap, char *)); break; case EL_EDITOR: - rv = map_set_editor(el, va_arg(ap, char *)); + rv = map_set_editor(el, va_arg(ap, Char *)); break; case EL_SIGNAL: @@ -176,40 +211,39 @@ el_set(EditLine *el, int op, ...) case EL_BIND: case EL_TELLTC: case EL_SETTC: - case EL_GETTC: case EL_ECHOTC: case EL_SETTY: { - const char *argv[20]; + const Char *argv[20]; int i; for (i = 1; i < 20; i++) - if ((argv[i] = va_arg(ap, char *)) == NULL) + if ((argv[i] = va_arg(ap, Char *)) == NULL) break; switch (op) { case EL_BIND: - argv[0] = "bind"; + argv[0] = STR("bind"); rv = map_bind(el, i, argv); break; case EL_TELLTC: - argv[0] = "telltc"; - rv = term_telltc(el, i, argv); + argv[0] = STR("telltc"); + rv = terminal_telltc(el, i, argv); break; case EL_SETTC: - argv[0] = "settc"; - rv = term_settc(el, i, argv); + argv[0] = STR("settc"); + rv = terminal_settc(el, i, argv); break; case EL_ECHOTC: - argv[0] = "echotc"; - rv = term_echotc(el, i, argv); + argv[0] = STR("echotc"); + rv = terminal_echotc(el, i, argv); break; case EL_SETTY: - argv[0] = "setty"; + argv[0] = STR("setty"); rv = tty_stty(el, i, argv); break; @@ -223,8 +257,8 @@ el_set(EditLine *el, int op, ...) case EL_ADDFN: { - char *name = va_arg(ap, char *); - char *help = va_arg(ap, char *); + Char *name = va_arg(ap, Char *); + Char *help = va_arg(ap, Char *); el_func_t func = va_arg(ap, el_func_t); rv = map_addfunc(el, name, help, func); @@ -234,9 +268,11 @@ el_set(EditLine *el, int op, ...) case EL_HIST: { hist_fun_t func = va_arg(ap, hist_fun_t); - ptr_t ptr = va_arg(ap, char *); + void *ptr = va_arg(ap, void *); rv = hist_set(el, func, ptr); + if (!(el->el_flags & CHARSET_IS_MULTIBYTE)) + el->el_flags &= ~NARROW_HISTORY; break; } @@ -252,6 +288,7 @@ el_set(EditLine *el, int op, ...) { el_rfunc_t rc = va_arg(ap, el_rfunc_t); rv = el_read_setfn(el, rc); + el->el_flags &= ~NARROW_READ; break; } @@ -296,9 +333,11 @@ el_set(EditLine *el, int op, ...) break; case 1: el->el_outfile = fp; + el->el_outfd = fileno(fp); break; case 2: el->el_errfile = fp; + el->el_errfd = fileno(fp); break; default: rv = -1; @@ -310,7 +349,7 @@ el_set(EditLine *el, int op, ...) case EL_REFRESH: re_clear_display(el); re_refresh(el); - term__flush(el); + terminal__flush(el); break; default: @@ -319,7 +358,7 @@ el_set(EditLine *el, int op, ...) } va_end(ap); - return (rv); + return rv; } @@ -327,7 +366,7 @@ el_set(EditLine *el, int op, ...) * retrieve the editline parameters */ public int -el_get(EditLine *el, int op, ...) +FUN(el,get)(EditLine *el, int op, ...) { va_list ap; int rv; @@ -339,12 +378,22 @@ el_get(EditLine *el, int op, ...) switch (op) { case EL_PROMPT: - case EL_RPROMPT: - rv = prompt_get(el, va_arg(ap, el_pfunc_t *), op); + case EL_RPROMPT: { + el_pfunc_t *p = va_arg(ap, el_pfunc_t *); + rv = prompt_get(el, p, 0, op); break; + } + case EL_PROMPT_ESC: + case EL_RPROMPT_ESC: { + el_pfunc_t *p = va_arg(ap, el_pfunc_t *); + Char *c = va_arg(ap, Char *); + + rv = prompt_get(el, p, c, op); + break; + } case EL_EDITOR: - rv = map_get_editor(el, va_arg(ap, const char **)); + rv = map_get_editor(el, va_arg(ap, const Char **)); break; case EL_SIGNAL: @@ -358,7 +407,7 @@ el_get(EditLine *el, int op, ...) break; case EL_TERMINAL: - term_get(el, va_arg(ap, const char **)); + terminal_get(el, va_arg(ap, const char **)); rv = 0; break; @@ -375,7 +424,7 @@ el_get(EditLine *el, int op, ...) switch (op) { case EL_GETTC: argv[0] = name; - rv = term_gettc(el, i, argv); + rv = terminal_gettc(el, i, argv); break; default: @@ -386,26 +435,6 @@ el_get(EditLine *el, int op, ...) break; } -#if 0 /* XXX */ - case EL_ADDFN: - { - char *name = va_arg(ap, char *); - char *help = va_arg(ap, char *); - el_func_t func = va_arg(ap, el_func_t); - - rv = map_addfunc(el, name, help, func); - break; - } - - case EL_HIST: - { - hist_fun_t func = va_arg(ap, hist_fun_t); - ptr_t ptr = va_arg(ap, char *); - rv = hist_set(el, func, ptr); - } - break; -#endif /* XXX */ - case EL_GETCFN: *va_arg(ap, el_rfunc_t *) = el_read_getfn(el); rv = 0; @@ -451,18 +480,18 @@ el_get(EditLine *el, int op, ...) } va_end(ap); - return (rv); + return rv; } /* el_line(): * Return editing info */ -public const LineInfo * -el_line(EditLine *el) +public const TYPE(LineInfo) * +FUN(el,line)(EditLine *el) { - return (const LineInfo *) (void *) &el->el_line; + return (const TYPE(LineInfo) *)(void *)&el->el_line; } @@ -475,6 +504,9 @@ el_source(EditLine *el, const char *fname) FILE *fp; size_t len; char *ptr; + char *path = NULL; + const Char *dptr; + int error = 0; fp = NULL; if (fname == NULL) { @@ -486,25 +518,21 @@ el_source(EditLine *el, const char *fname) #if (defined(HAVE_ISSETUGID) || defined(HAVE_IDENTITY_FUNCS)) static const char elpath[] = "/.editrc"; + size_t plen = sizeof(elpath); /* XXXMYSQL: Portability fix (for which platforms?) */ -#ifdef MAXPATHLEN - char path[MAXPATHLEN]; -#else - char path[4096]; -#endif #ifdef HAVE_ISSETUGID if (issetugid()) - return (-1); + return -1; #elif defined(HAVE_IDENTITY_FUNCS) if (getuid() != geteuid() || getgid() != getegid()) return (-1); #endif if ((ptr = getenv("HOME")) == NULL) - return (-1); - if (strlcpy(path, ptr, sizeof(path)) >= sizeof(path)) - return (-1); - if (strlcat(path, elpath, sizeof(path)) >= sizeof(path)) - return (-1); + return -1; + plen += strlen(ptr); + if ((path = el_malloc(plen * sizeof(*path))) == NULL) + return -1; + (void)snprintf(path, plen, "%s%s", ptr, elpath); fname = path; #else /* @@ -513,26 +541,37 @@ el_source(EditLine *el, const char *fname) * to keep from inadvertently opening up the user to a * security hole. */ - return (-1); + return -1; #endif } if (fp == NULL) fp = fopen(fname, "r"); - if (fp == NULL) - return (-1); - - while ((ptr = fgetln(fp, &len)) != NULL) { - if (len > 0 && ptr[len - 1] == '\n') - --len; - ptr[len] = '\0'; - if (parse_line(el, ptr) == -1) { - (void) fclose(fp); - return (-1); - } + if (fp == NULL) { + el_free(path); + return -1; } + while ((ptr = fgetln(fp, &len)) != NULL) { + if (*ptr == '\n') + continue; /* Empty line. */ + dptr = ct_decode_string(ptr, &el->el_scratch); + if (!dptr) + continue; + if (len > 0 && dptr[len - 1] == '\n') + --len; + + /* loop until first non-space char or EOL */ + while (*dptr != '\0' && Isspace(*dptr)) + dptr++; + if (*dptr == '#') + continue; /* ignore, this is a comment line */ + if ((error = parse_line(el, dptr)) == -1) + break; + } + + el_free(path); (void) fclose(fp); - return (0); + return error; } @@ -550,8 +589,8 @@ el_resize(EditLine *el) (void) sigprocmask(SIG_BLOCK, &nset, &oset); /* get the correct window size */ - if (term_get_size(el, &lins, &cols)) - term_change_size(el, lins, cols); + if (terminal_get_size(el, &lins, &cols)) + terminal_change_size(el, lins, cols); (void) sigprocmask(SIG_SETMASK, &oset, NULL); } @@ -564,7 +603,7 @@ public void el_beep(EditLine *el) { - term_beep(el); + terminal_beep(el); } @@ -573,24 +612,25 @@ el_beep(EditLine *el) */ protected int /*ARGSUSED*/ -el_editmode(EditLine *el, int argc, const char **argv) +el_editmode(EditLine *el, int argc, const Char **argv) { - const char *how; + const Char *how; if (argv == NULL || argc != 2 || argv[1] == NULL) - return (-1); + return -1; how = argv[1]; - if (strcmp(how, "on") == 0) { + if (Strcmp(how, STR("on")) == 0) { el->el_flags &= ~EDIT_DISABLED; tty_rawmode(el); - } else if (strcmp(how, "off") == 0) { + } else if (Strcmp(how, STR("off")) == 0) { tty_cookedmode(el); el->el_flags |= EDIT_DISABLED; } else { - (void) fprintf(el->el_errfile, "edit: Bad value `%s'.\n", how); - return (-1); + (void) fprintf(el->el_errfile, "edit: Bad value `" FSTR "'.\n", + how); + return -1; } - return (0); + return 0; } diff --git a/cmd-line-utils/libedit/el.h b/cmd-line-utils/libedit/el.h index 05d88ad88ba..403a44aa806 100644 --- a/cmd-line-utils/libedit/el.h +++ b/cmd-line-utils/libedit/el.h @@ -1,4 +1,4 @@ -/* $NetBSD: el.h,v 1.17 2006/12/15 22:13:33 christos Exp $ */ +/* $NetBSD: el.h,v 1.25 2011/07/29 23:44:44 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -46,15 +46,21 @@ #define VIDEFAULT #define ANCHOR +#include "histedit.h" +#include "chartype.h" #include #include -#define EL_BUFSIZ 1024 /* Maximum line size */ +#define EL_BUFSIZ ((size_t)4096) /* Maximum line size */ -#define HANDLE_SIGNALS 0x01 -#define NO_TTY 0x02 -#define EDIT_DISABLED 0x04 -#define UNBUFFERED 0x08 +#define HANDLE_SIGNALS 0x01 +#define NO_TTY 0x02 +#define EDIT_DISABLED 0x04 +#define UNBUFFERED 0x08 +#define CHARSET_IS_MULTIBYTE 0x10 +#define IGNORE_EXTCHARS 0x20 /* Ignore characters read > 0xff */ +#define NARROW_HISTORY 0x40 +#define NARROW_READ 0x80 typedef int bool_t; /* True or not */ @@ -66,10 +72,10 @@ typedef struct coord_t { /* Position on the screen */ } coord_t; typedef struct el_line_t { - char *buffer; /* Input line */ - char *cursor; /* Cursor position */ - char *lastchar; /* Last character */ - const char *limit; /* Max position */ + Char *buffer; /* Input line */ + Char *cursor; /* Cursor position */ + Char *lastchar; /* Last character */ + const Char *limit; /* Max position */ } el_line_t; /* @@ -82,21 +88,20 @@ typedef struct el_state_t { int metanext; /* Is the next char a meta char */ el_action_t lastcmd; /* Previous command */ el_action_t thiscmd; /* this command */ - char thisch; /* char that generated it */ + Char thisch; /* char that generated it */ } el_state_t; /* * Until we come up with something better... */ -#define el_strdup(a) strdup(a) #define el_malloc(a) malloc(a) #define el_realloc(a,b) realloc(a, b) #define el_free(a) free(a) #include "tty.h" #include "prompt.h" -#include "key.h" -#include "el_term.h" +#include "keymacro.h" +#include "el_terminal.h" #include "refresh.h" #include "chared.h" #include "common.h" @@ -109,33 +114,41 @@ typedef struct el_state_t { #include "read.h" struct editline { - char *el_prog; /* the program name */ + Char *el_prog; /* the program name */ FILE *el_infile; /* Stdio stuff */ FILE *el_outfile; /* Stdio stuff */ FILE *el_errfile; /* Stdio stuff */ int el_infd; /* Input file descriptor */ + int el_outfd; /* Output file descriptor */ + int el_errfd; /* Error file descriptor */ int el_flags; /* Various flags. */ + int el_errno; /* Local copy of errno */ coord_t el_cursor; /* Cursor location */ - char **el_display; /* Real screen image = what is there */ - char **el_vdisplay; /* Virtual screen image = what we see */ + Char **el_display; /* Real screen image = what is there */ + Char **el_vdisplay; /* Virtual screen image = what we see */ void *el_data; /* Client data */ el_line_t el_line; /* The current line information */ el_state_t el_state; /* Current editor state */ - el_term_t el_term; /* Terminal dependent stuff */ + el_terminal_t el_terminal; /* Terminal dependent stuff */ el_tty_t el_tty; /* Tty dependent stuff */ el_refresh_t el_refresh; /* Refresh stuff */ el_prompt_t el_prompt; /* Prompt stuff */ el_prompt_t el_rprompt; /* Prompt stuff */ el_chared_t el_chared; /* Characted editor stuff */ el_map_t el_map; /* Key mapping stuff */ - el_key_t el_key; /* Key binding stuff */ + el_keymacro_t el_keymacro; /* Key binding stuff */ el_history_t el_history; /* History stuff */ el_search_t el_search; /* Search stuff */ el_signal_t el_signal; /* Signal handling stuff */ el_read_t el_read; /* Character reading stuff */ +#ifdef WIDECHAR + ct_buffer_t el_scratch; /* Scratch conversion buffer */ + ct_buffer_t el_lgcyconv; /* Buffer for legacy wrappers */ + LineInfo el_lgcylinfo; /* Legacy LineInfo buffer */ +#endif }; -protected int el_editmode(EditLine *, int, const char **); +protected int el_editmode(EditLine *, int, const Char **); /* XXXMYSQL: Bug#23097 mysql can't insert korean on mysql prompt. */ #define el_isprint(x) ((unsigned char) (x) < 0x80 ? isprint(x) : 1) diff --git a/cmd-line-utils/libedit/el_term.h b/cmd-line-utils/libedit/el_terminal.h similarity index 65% rename from cmd-line-utils/libedit/el_term.h rename to cmd-line-utils/libedit/el_terminal.h index 0e7ddd555f4..807c651783e 100644 --- a/cmd-line-utils/libedit/el_term.h +++ b/cmd-line-utils/libedit/el_terminal.h @@ -1,4 +1,4 @@ -/* $NetBSD: term.h,v 1.19 2008/09/10 15:45:37 christos Exp $ */ +/* $NetBSD: terminal.h,v 1.3 2011/07/29 23:44:45 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -37,17 +37,17 @@ /* * el.term.h: Termcap header */ -#ifndef _h_el_term -#define _h_el_term +#ifndef _h_el_terminal +#define _h_el_terminal #include "histedit.h" typedef struct { /* Symbolic function key bindings */ - const char *name; /* name of the key */ + const Char *name; /* name of the key */ int key; /* Index in termcap table */ - key_value_t fun; /* Function bound to it */ + keymacro_value_t fun; /* Function bound to it */ int type; /* Type of function */ -} fkey_t; +} funckey_t; typedef struct { const char *t_name; /* the terminal name */ @@ -63,12 +63,12 @@ typedef struct { #define TERM_HAS_AUTO_MARGINS 0x080 /* Has auto margins */ #define TERM_HAS_MAGIC_MARGINS 0x100 /* Has magic margins */ char *t_buf; /* Termcap buffer */ - int t_loc; /* location used */ + size_t t_loc; /* location used */ char **t_str; /* termcap strings */ int *t_val; /* termcap values */ char *t_cap; /* Termcap buffer */ - fkey_t *t_fkey; /* Array of keys */ -} el_term_t; + funckey_t *t_fkey; /* Array of keys */ +} el_terminal_t; /* * fKey indexes @@ -81,36 +81,36 @@ typedef struct { #define A_K_EN 5 #define A_K_NKEYS 6 -protected void term_move_to_line(EditLine *, int); -protected void term_move_to_char(EditLine *, int); -protected void term_clear_EOL(EditLine *, int); -protected void term_overwrite(EditLine *, const char *, int); -protected void term_insertwrite(EditLine *, char *, int); -protected void term_deletechars(EditLine *, int); -protected void term_clear_screen(EditLine *); -protected void term_beep(EditLine *); -protected int term_change_size(EditLine *, int, int); -protected int term_get_size(EditLine *, int *, int *); -protected int term_init(EditLine *); -protected void term_bind_arrow(EditLine *); -protected void term_print_arrow(EditLine *, const char *); -protected int term_clear_arrow(EditLine *, const char *); -protected int term_set_arrow(EditLine *, const char *, key_value_t *, int); -protected void term_end(EditLine *); -protected void term_get(EditLine *, const char **); -protected int term_set(EditLine *, const char *); -protected int term_settc(EditLine *, int, const char **); -protected int term_gettc(EditLine *, int, char **); -protected int term_telltc(EditLine *, int, const char **); -protected int term_echotc(EditLine *, int, const char **); -protected void term_writec(EditLine *, int); -protected int term__putc(EditLine *, int); -protected void term__flush(EditLine *); +protected void terminal_move_to_line(EditLine *, int); +protected void terminal_move_to_char(EditLine *, int); +protected void terminal_clear_EOL(EditLine *, int); +protected void terminal_overwrite(EditLine *, const Char *, size_t); +protected void terminal_insertwrite(EditLine *, Char *, int); +protected void terminal_deletechars(EditLine *, int); +protected void terminal_clear_screen(EditLine *); +protected void terminal_beep(EditLine *); +protected int terminal_change_size(EditLine *, int, int); +protected int terminal_get_size(EditLine *, int *, int *); +protected int terminal_init(EditLine *); +protected void terminal_bind_arrow(EditLine *); +protected void terminal_print_arrow(EditLine *, const Char *); +protected int terminal_clear_arrow(EditLine *, const Char *); +protected int terminal_set_arrow(EditLine *, const Char *, keymacro_value_t *, int); +protected void terminal_end(EditLine *); +protected void terminal_get(EditLine *, const char **); +protected int terminal_set(EditLine *, const char *); +protected int terminal_settc(EditLine *, int, const Char **); +protected int terminal_gettc(EditLine *, int, char **); +protected int terminal_telltc(EditLine *, int, const Char **); +protected int terminal_echotc(EditLine *, int, const Char **); +protected void terminal_writec(EditLine *, Int); +protected int terminal__putc(EditLine *, Int); +protected void terminal__flush(EditLine *); /* * Easy access macros */ -#define EL_FLAGS (el)->el_term.t_flags +#define EL_FLAGS (el)->el_terminal.t_flags #define EL_CAN_INSERT (EL_FLAGS & TERM_CAN_INSERT) #define EL_CAN_DELETE (EL_FLAGS & TERM_CAN_DELETE) @@ -122,4 +122,4 @@ protected void term__flush(EditLine *); #define EL_HAS_AUTO_MARGINS (EL_FLAGS & TERM_HAS_AUTO_MARGINS) #define EL_HAS_MAGIC_MARGINS (EL_FLAGS & TERM_HAS_MAGIC_MARGINS) -#endif /* _h_el_term */ +#endif /* _h_el_terminal */ diff --git a/cmd-line-utils/libedit/eln.c b/cmd-line-utils/libedit/eln.c new file mode 100644 index 00000000000..4b9f16c38f3 --- /dev/null +++ b/cmd-line-utils/libedit/eln.c @@ -0,0 +1,364 @@ +/* $NetBSD: eln.c,v 1.13 2011/08/16 16:25:15 christos Exp $ */ + +/*- + * Copyright (c) 2009 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "config.h" +#if !defined(lint) && !defined(SCCSID) +#endif /* not lint && not SCCSID */ + +#include "histedit.h" +#include "el.h" +#include "read.h" +#include +#include +#include + +public int +el_getc(EditLine *el, char *cp) +{ + int num_read; + wchar_t wc = 0; + + num_read = el_wgetc (el, &wc); + + if (num_read > 0) + *cp = (char)wc; + return num_read; +} + + +public void +el_push(EditLine *el, const char *str) +{ + /* Using multibyte->wide string decoding works fine under single-byte + * character sets too, and Does The Right Thing. */ + el_wpush(el, ct_decode_string(str, &el->el_lgcyconv)); +} + + +public const char * +el_gets(EditLine *el, int *nread) +{ + const wchar_t *tmp; + + tmp = el_wgets(el, nread); + return ct_encode_string(tmp, &el->el_lgcyconv); +} + + +public int +el_parse(EditLine *el, int argc, const char *argv[]) +{ + int ret; + const wchar_t **wargv; + + wargv = (const wchar_t **) + ct_decode_argv(argc, argv, &el->el_lgcyconv); + if (!wargv) + return -1; + ret = el_wparse(el, argc, wargv); + ct_free_argv(wargv); + + return ret; +} + + +public int +el_set(EditLine *el, int op, ...) +{ + va_list ap; + int ret; + + if (!el) + return -1; + va_start(ap, op); + + switch (op) { + case EL_PROMPT: /* el_pfunc_t */ + case EL_RPROMPT: { + el_pfunc_t p = va_arg(ap, el_pfunc_t); + ret = prompt_set(el, p, 0, op, 0); + break; + } + + case EL_RESIZE: { + el_zfunc_t p = va_arg(ap, el_zfunc_t); + void *arg = va_arg(ap, void *); + ret = ch_resizefun(el, p, arg); + break; + } + + case EL_TERMINAL: /* const char * */ + ret = el_wset(el, op, va_arg(ap, char *)); + break; + + case EL_EDITOR: /* const wchar_t * */ + ret = el_wset(el, op, ct_decode_string(va_arg(ap, char *), + &el->el_lgcyconv)); + break; + + case EL_SIGNAL: /* int */ + case EL_EDITMODE: + case EL_UNBUFFERED: + case EL_PREP_TERM: + ret = el_wset(el, op, va_arg(ap, int)); + break; + + case EL_BIND: /* const char * list -> const wchar_t * list */ + case EL_TELLTC: + case EL_SETTC: + case EL_ECHOTC: + case EL_SETTY: { + const char *argv[20]; + int i; + const wchar_t **wargv; + for (i = 1; i < (int)__arraycount(argv); ++i) + if ((argv[i] = va_arg(ap, char *)) == NULL) + break; + argv[0] = NULL; + wargv = (const wchar_t **) + ct_decode_argv(i, argv, &el->el_lgcyconv); + if (!wargv) { + ret = -1; + goto out; + } + /* + * AFAIK we can't portably pass through our new wargv to + * el_wset(), so we have to reimplement the body of + * el_wset() for these ops. + */ + switch (op) { + case EL_BIND: + wargv[0] = STR("bind"); + ret = map_bind(el, i, wargv); + break; + case EL_TELLTC: + wargv[0] = STR("telltc"); + ret = terminal_telltc(el, i, wargv); + break; + case EL_SETTC: + wargv[0] = STR("settc"); + ret = terminal_settc(el, i, wargv); + break; + case EL_ECHOTC: + wargv[0] = STR("echotc"); + ret = terminal_echotc(el, i, wargv); + break; + case EL_SETTY: + wargv[0] = STR("setty"); + ret = tty_stty(el, i, wargv); + break; + default: + ret = -1; + } + ct_free_argv(wargv); + break; + } + + /* XXX: do we need to change el_func_t too? */ + case EL_ADDFN: { /* const char *, const char *, el_func_t */ + const char *args[2]; + el_func_t func; + wchar_t **wargv; + + args[0] = va_arg(ap, const char *); + args[1] = va_arg(ap, const char *); + func = va_arg(ap, el_func_t); + + wargv = ct_decode_argv(2, args, &el->el_lgcyconv); + if (!wargv) { + ret = -1; + goto out; + } + // XXX: The two strdup's leak + ret = map_addfunc(el, Strdup(wargv[0]), Strdup(wargv[1]), + func); + ct_free_argv(wargv); + break; + } + case EL_HIST: { /* hist_fun_t, const char * */ + hist_fun_t fun = va_arg(ap, hist_fun_t); + void *ptr = va_arg(ap, void *); + ret = hist_set(el, fun, ptr); + el->el_flags |= NARROW_HISTORY; + break; + } + /* XXX: do we need to change el_rfunc_t? */ + case EL_GETCFN: /* el_rfunc_t */ + ret = el_wset(el, op, va_arg(ap, el_rfunc_t)); + el->el_flags |= NARROW_READ; + break; + case EL_CLIENTDATA: /* void * */ + ret = el_wset(el, op, va_arg(ap, void *)); + break; + case EL_SETFP: { /* int, FILE * */ + int what = va_arg(ap, int); + FILE *fp = va_arg(ap, FILE *); + ret = el_wset(el, op, what, fp); + break; + } + case EL_PROMPT_ESC: /* el_pfunc_t, char */ + case EL_RPROMPT_ESC: { + el_pfunc_t p = va_arg(ap, el_pfunc_t); + char c = (char)va_arg(ap, int); + ret = prompt_set(el, p, c, op, 0); + break; + } + default: + ret = -1; + break; + } + +out: + va_end(ap); + return ret; +} + + +public int +el_get(EditLine *el, int op, ...) +{ + va_list ap; + int ret; + + if (!el) + return -1; + + va_start(ap, op); + + switch (op) { + case EL_PROMPT: /* el_pfunc_t * */ + case EL_RPROMPT: { + el_pfunc_t *p = va_arg(ap, el_pfunc_t *); + ret = prompt_get(el, p, 0, op); + break; + } + + case EL_PROMPT_ESC: /* el_pfunc_t *, char **/ + case EL_RPROMPT_ESC: { + el_pfunc_t *p = va_arg(ap, el_pfunc_t *); + char *c = va_arg(ap, char *); + wchar_t wc = 0; + ret = prompt_get(el, p, &wc, op); + *c = (char)wc; + break; + } + + case EL_EDITOR: { + const char **p = va_arg(ap, const char **); + const wchar_t *pw; + ret = el_wget(el, op, &pw); + *p = ct_encode_string(pw, &el->el_lgcyconv); + if (!el->el_lgcyconv.csize) + ret = -1; + break; + } + + case EL_TERMINAL: /* const char ** */ + ret = el_wget(el, op, va_arg(ap, const char **)); + break; + + case EL_SIGNAL: /* int * */ + case EL_EDITMODE: + case EL_UNBUFFERED: + case EL_PREP_TERM: + ret = el_wget(el, op, va_arg(ap, int *)); + break; + + case EL_GETTC: { + char *argv[20]; + static char gettc[] = "gettc"; + int i; + for (i = 1; i < (int)__arraycount(argv); ++i) + if ((argv[i] = va_arg(ap, char *)) == NULL) + break; + argv[0] = gettc; + ret = terminal_gettc(el, i, argv); + break; + } + + /* XXX: do we need to change el_rfunc_t? */ + case EL_GETCFN: /* el_rfunc_t */ + ret = el_wget(el, op, va_arg(ap, el_rfunc_t *)); + break; + + case EL_CLIENTDATA: /* void ** */ + ret = el_wget(el, op, va_arg(ap, void **)); + break; + + case EL_GETFP: { /* int, FILE ** */ + int what = va_arg(ap, int); + FILE **fpp = va_arg(ap, FILE **); + ret = el_wget(el, op, what, fpp); + break; + } + + default: + ret = -1; + break; + } + + va_end(ap); + return ret; +} + + +const LineInfo * +el_line(EditLine *el) +{ + const LineInfoW *winfo = el_wline(el); + LineInfo *info = &el->el_lgcylinfo; + size_t offset; + const Char *p; + + info->buffer = ct_encode_string(winfo->buffer, &el->el_lgcyconv); + + offset = 0; + for (p = winfo->buffer; p < winfo->cursor; p++) + offset += ct_enc_width(*p); + info->cursor = info->buffer + offset; + + offset = 0; + for (p = winfo->buffer; p < winfo->lastchar; p++) + offset += ct_enc_width(*p); + info->lastchar = info->buffer + offset; + + return info; +} + + +int +el_insertstr(EditLine *el, const char *str) +{ + return el_winsertstr(el, ct_decode_string(str, &el->el_lgcyconv)); +} diff --git a/cmd-line-utils/libedit/emacs.c b/cmd-line-utils/libedit/emacs.c index 135bd75f566..554d3970485 100644 --- a/cmd-line-utils/libedit/emacs.c +++ b/cmd-line-utils/libedit/emacs.c @@ -1,4 +1,4 @@ -/* $NetBSD: emacs.c,v 1.21 2006/03/06 21:11:56 christos Exp $ */ +/* $NetBSD: emacs.c,v 1.25 2011/07/29 15:16:33 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -51,22 +51,22 @@ static char sccsid[] = "@(#)emacs.c 8.1 (Berkeley) 6/4/93"; */ protected el_action_t /*ARGSUSED*/ -em_delete_or_list(EditLine *el, int c) +em_delete_or_list(EditLine *el, Int c) { if (el->el_line.cursor == el->el_line.lastchar) { /* if I'm at the end */ if (el->el_line.cursor == el->el_line.buffer) { /* and the beginning */ - term_writec(el, c); /* then do an EOF */ - return (CC_EOF); + terminal_writec(el, c); /* then do an EOF */ + return CC_EOF; } else { /* * Here we could list completions, but it is an * error right now */ - term_beep(el); - return (CC_ERROR); + terminal_beep(el); + return CC_ERROR; } } else { if (el->el_state.doingarg) @@ -76,7 +76,7 @@ em_delete_or_list(EditLine *el, int c) if (el->el_line.cursor > el->el_line.lastchar) el->el_line.cursor = el->el_line.lastchar; /* bounds check */ - return (CC_REFRESH); + return CC_REFRESH; } } @@ -87,12 +87,12 @@ em_delete_or_list(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -em_delete_next_word(EditLine *el, int c __attribute__((__unused__))) +em_delete_next_word(EditLine *el, Int c __attribute__((__unused__))) { - char *cp, *p, *kp; + Char *cp, *p, *kp; if (el->el_line.cursor == el->el_line.lastchar) - return (CC_ERROR); + return CC_ERROR; cp = c__next_word(el->el_line.cursor, el->el_line.lastchar, el->el_state.argument, ce__isword); @@ -102,11 +102,11 @@ em_delete_next_word(EditLine *el, int c __attribute__((__unused__))) *kp++ = *p; el->el_chared.c_kill.last = kp; - c_delafter(el, cp - el->el_line.cursor); /* delete after dot */ + c_delafter(el, (int)(cp - el->el_line.cursor)); /* delete after dot */ if (el->el_line.cursor > el->el_line.lastchar) el->el_line.cursor = el->el_line.lastchar; /* bounds check */ - return (CC_REFRESH); + return CC_REFRESH; } @@ -116,23 +116,24 @@ em_delete_next_word(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -em_yank(EditLine *el, int c __attribute__((__unused__))) +em_yank(EditLine *el, Int c __attribute__((__unused__))) { - char *kp, *cp; + Char *kp, *cp; if (el->el_chared.c_kill.last == el->el_chared.c_kill.buf) - return (CC_NORM); + return CC_NORM; if (el->el_line.lastchar + (el->el_chared.c_kill.last - el->el_chared.c_kill.buf) >= el->el_line.limit) - return (CC_ERROR); + return CC_ERROR; el->el_chared.c_kill.mark = el->el_line.cursor; cp = el->el_line.cursor; /* open the space, */ - c_insert(el, el->el_chared.c_kill.last - el->el_chared.c_kill.buf); + c_insert(el, + (int)(el->el_chared.c_kill.last - el->el_chared.c_kill.buf)); /* copy the chars */ for (kp = el->el_chared.c_kill.buf; kp < el->el_chared.c_kill.last; kp++) *cp++ = *kp; @@ -141,7 +142,7 @@ em_yank(EditLine *el, int c __attribute__((__unused__))) if (el->el_state.argument == 1) el->el_line.cursor = cp; - return (CC_REFRESH); + return CC_REFRESH; } @@ -151,9 +152,9 @@ em_yank(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -em_kill_line(EditLine *el, int c __attribute__((__unused__))) +em_kill_line(EditLine *el, Int c __attribute__((__unused__))) { - char *kp, *cp; + Char *kp, *cp; cp = el->el_line.buffer; kp = el->el_chared.c_kill.buf; @@ -163,7 +164,7 @@ em_kill_line(EditLine *el, int c __attribute__((__unused__))) /* zap! -- delete all of it */ el->el_line.lastchar = el->el_line.buffer; el->el_line.cursor = el->el_line.buffer; - return (CC_REFRESH); + return CC_REFRESH; } @@ -173,12 +174,12 @@ em_kill_line(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -em_kill_region(EditLine *el, int c __attribute__((__unused__))) +em_kill_region(EditLine *el, Int c __attribute__((__unused__))) { - char *kp, *cp; + Char *kp, *cp; if (!el->el_chared.c_kill.mark) - return (CC_ERROR); + return CC_ERROR; if (el->el_chared.c_kill.mark > el->el_line.cursor) { cp = el->el_line.cursor; @@ -186,17 +187,17 @@ em_kill_region(EditLine *el, int c __attribute__((__unused__))) while (cp < el->el_chared.c_kill.mark) *kp++ = *cp++; /* copy it */ el->el_chared.c_kill.last = kp; - c_delafter(el, cp - el->el_line.cursor); + c_delafter(el, (int)(cp - el->el_line.cursor)); } else { /* mark is before cursor */ cp = el->el_chared.c_kill.mark; kp = el->el_chared.c_kill.buf; while (cp < el->el_line.cursor) *kp++ = *cp++; /* copy it */ el->el_chared.c_kill.last = kp; - c_delbefore(el, cp - el->el_chared.c_kill.mark); + c_delbefore(el, (int)(cp - el->el_chared.c_kill.mark)); el->el_line.cursor = el->el_chared.c_kill.mark; } - return (CC_REFRESH); + return CC_REFRESH; } @@ -206,12 +207,12 @@ em_kill_region(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -em_copy_region(EditLine *el, int c __attribute__((__unused__))) +em_copy_region(EditLine *el, Int c __attribute__((__unused__))) { - char *kp, *cp; + Char *kp, *cp; if (!el->el_chared.c_kill.mark) - return (CC_ERROR); + return CC_ERROR; if (el->el_chared.c_kill.mark > el->el_line.cursor) { cp = el->el_line.cursor; @@ -226,7 +227,7 @@ em_copy_region(EditLine *el, int c __attribute__((__unused__))) *kp++ = *cp++; /* copy it */ el->el_chared.c_kill.last = kp; } - return (CC_NORM); + return CC_NORM; } @@ -235,7 +236,7 @@ em_copy_region(EditLine *el, int c __attribute__((__unused__))) * Gosling emacs transpose chars [^T] */ protected el_action_t -em_gosmacs_transpose(EditLine *el, int c) +em_gosmacs_transpose(EditLine *el, Int c) { if (el->el_line.cursor > &el->el_line.buffer[1]) { @@ -243,9 +244,9 @@ em_gosmacs_transpose(EditLine *el, int c) c = el->el_line.cursor[-2]; el->el_line.cursor[-2] = el->el_line.cursor[-1]; el->el_line.cursor[-1] = c; - return (CC_REFRESH); + return CC_REFRESH; } else - return (CC_ERROR); + return CC_ERROR; } @@ -255,10 +256,10 @@ em_gosmacs_transpose(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -em_next_word(EditLine *el, int c __attribute__((__unused__))) +em_next_word(EditLine *el, Int c __attribute__((__unused__))) { if (el->el_line.cursor == el->el_line.lastchar) - return (CC_ERROR); + return CC_ERROR; el->el_line.cursor = c__next_word(el->el_line.cursor, el->el_line.lastchar, @@ -268,9 +269,9 @@ em_next_word(EditLine *el, int c __attribute__((__unused__))) if (el->el_map.type == MAP_VI) if (el->el_chared.c_vcmd.action != NOP) { cv_delfini(el); - return (CC_REFRESH); + return CC_REFRESH; } - return (CC_CURSOR); + return CC_CURSOR; } @@ -280,21 +281,21 @@ em_next_word(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -em_upper_case(EditLine *el, int c __attribute__((__unused__))) +em_upper_case(EditLine *el, Int c __attribute__((__unused__))) { - char *cp, *ep; + Char *cp, *ep; ep = c__next_word(el->el_line.cursor, el->el_line.lastchar, el->el_state.argument, ce__isword); for (cp = el->el_line.cursor; cp < ep; cp++) - if (islower((unsigned char)*cp)) - *cp = toupper((unsigned char)*cp); + if (Islower(*cp)) + *cp = Toupper(*cp); el->el_line.cursor = ep; if (el->el_line.cursor > el->el_line.lastchar) el->el_line.cursor = el->el_line.lastchar; - return (CC_REFRESH); + return CC_REFRESH; } @@ -304,29 +305,29 @@ em_upper_case(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -em_capitol_case(EditLine *el, int c __attribute__((__unused__))) +em_capitol_case(EditLine *el, Int c __attribute__((__unused__))) { - char *cp, *ep; + Char *cp, *ep; ep = c__next_word(el->el_line.cursor, el->el_line.lastchar, el->el_state.argument, ce__isword); for (cp = el->el_line.cursor; cp < ep; cp++) { - if (isalpha((unsigned char)*cp)) { - if (islower((unsigned char)*cp)) - *cp = toupper((unsigned char)*cp); + if (Isalpha(*cp)) { + if (Islower(*cp)) + *cp = Toupper(*cp); cp++; break; } } for (; cp < ep; cp++) - if (isupper((unsigned char)*cp)) - *cp = tolower((unsigned char)*cp); + if (Isupper(*cp)) + *cp = Tolower(*cp); el->el_line.cursor = ep; if (el->el_line.cursor > el->el_line.lastchar) el->el_line.cursor = el->el_line.lastchar; - return (CC_REFRESH); + return CC_REFRESH; } @@ -336,21 +337,21 @@ em_capitol_case(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -em_lower_case(EditLine *el, int c __attribute__((__unused__))) +em_lower_case(EditLine *el, Int c __attribute__((__unused__))) { - char *cp, *ep; + Char *cp, *ep; ep = c__next_word(el->el_line.cursor, el->el_line.lastchar, el->el_state.argument, ce__isword); for (cp = el->el_line.cursor; cp < ep; cp++) - if (isupper((unsigned char)*cp)) - *cp = tolower((unsigned char)*cp); + if (Isupper(*cp)) + *cp = Tolower(*cp); el->el_line.cursor = ep; if (el->el_line.cursor > el->el_line.lastchar) el->el_line.cursor = el->el_line.lastchar; - return (CC_REFRESH); + return CC_REFRESH; } @@ -360,11 +361,11 @@ em_lower_case(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -em_set_mark(EditLine *el, int c __attribute__((__unused__))) +em_set_mark(EditLine *el, Int c __attribute__((__unused__))) { el->el_chared.c_kill.mark = el->el_line.cursor; - return (CC_NORM); + return CC_NORM; } @@ -374,14 +375,14 @@ em_set_mark(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -em_exchange_mark(EditLine *el, int c __attribute__((__unused__))) +em_exchange_mark(EditLine *el, Int c __attribute__((__unused__))) { - char *cp; + Char *cp; cp = el->el_line.cursor; el->el_line.cursor = el->el_chared.c_kill.mark; el->el_chared.c_kill.mark = cp; - return (CC_CURSOR); + return CC_CURSOR; } @@ -391,14 +392,14 @@ em_exchange_mark(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -em_universal_argument(EditLine *el, int c __attribute__((__unused__))) +em_universal_argument(EditLine *el, Int c __attribute__((__unused__))) { /* multiply current argument by 4 */ if (el->el_state.argument > 1000000) - return (CC_ERROR); + return CC_ERROR; el->el_state.doingarg = 1; el->el_state.argument *= 4; - return (CC_ARGHACK); + return CC_ARGHACK; } @@ -408,11 +409,11 @@ em_universal_argument(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -em_meta_next(EditLine *el, int c __attribute__((__unused__))) +em_meta_next(EditLine *el, Int c __attribute__((__unused__))) { el->el_state.metanext = 1; - return (CC_ARGHACK); + return CC_ARGHACK; } @@ -421,12 +422,12 @@ em_meta_next(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -em_toggle_overwrite(EditLine *el, int c __attribute__((__unused__))) +em_toggle_overwrite(EditLine *el, Int c __attribute__((__unused__))) { el->el_state.inputmode = (el->el_state.inputmode == MODE_INSERT) ? MODE_REPLACE : MODE_INSERT; - return (CC_NORM); + return CC_NORM; } @@ -435,25 +436,25 @@ em_toggle_overwrite(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -em_copy_prev_word(EditLine *el, int c __attribute__((__unused__))) +em_copy_prev_word(EditLine *el, Int c __attribute__((__unused__))) { - char *cp, *oldc, *dp; + Char *cp, *oldc, *dp; if (el->el_line.cursor == el->el_line.buffer) - return (CC_ERROR); + return CC_ERROR; oldc = el->el_line.cursor; /* does a bounds check */ cp = c__prev_word(el->el_line.cursor, el->el_line.buffer, el->el_state.argument, ce__isword); - c_insert(el, oldc - cp); + c_insert(el, (int)(oldc - cp)); for (dp = oldc; cp < oldc && dp < el->el_line.lastchar; cp++) *dp++ = *cp; el->el_line.cursor = dp;/* put cursor at end */ - return (CC_REFRESH); + return CC_REFRESH; } @@ -462,11 +463,11 @@ em_copy_prev_word(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -em_inc_search_next(EditLine *el, int c __attribute__((__unused__))) +em_inc_search_next(EditLine *el, Int c __attribute__((__unused__))) { el->el_search.patlen = 0; - return (ce_inc_search(el, ED_SEARCH_NEXT_HISTORY)); + return ce_inc_search(el, ED_SEARCH_NEXT_HISTORY); } @@ -475,11 +476,11 @@ em_inc_search_next(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -em_inc_search_prev(EditLine *el, int c __attribute__((__unused__))) +em_inc_search_prev(EditLine *el, Int c __attribute__((__unused__))) { el->el_search.patlen = 0; - return (ce_inc_search(el, ED_SEARCH_PREV_HISTORY)); + return ce_inc_search(el, ED_SEARCH_PREV_HISTORY); } @@ -489,11 +490,11 @@ em_inc_search_prev(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -em_delete_prev_char(EditLine *el, int c __attribute__((__unused__))) +em_delete_prev_char(EditLine *el, Int c __attribute__((__unused__))) { if (el->el_line.cursor <= el->el_line.buffer) - return (CC_ERROR); + return CC_ERROR; if (el->el_state.doingarg) c_delbefore(el, el->el_state.argument); @@ -502,5 +503,5 @@ em_delete_prev_char(EditLine *el, int c __attribute__((__unused__))) el->el_line.cursor -= el->el_state.argument; if (el->el_line.cursor < el->el_line.buffer) el->el_line.cursor = el->el_line.buffer; - return (CC_REFRESH); + return CC_REFRESH; } diff --git a/cmd-line-utils/libedit/filecomplete.c b/cmd-line-utils/libedit/filecomplete.c index 05bd10e9f9e..b67b54510bf 100644 --- a/cmd-line-utils/libedit/filecomplete.c +++ b/cmd-line-utils/libedit/filecomplete.c @@ -1,4 +1,4 @@ -/* $NetBSD: filecomplete.c,v 1.13 2009/01/26 17:32:41 apb Exp $ */ +/* $NetBSD: filecomplete.c,v 1.31 2011/09/16 16:13:16 plunky Exp $ */ /*- * Copyright (c) 1997 The NetBSD Foundation, Inc. @@ -78,8 +78,8 @@ extern char *alloca (); #include "histedit.h" #include "filecomplete.h" -static char break_chars[] = { ' ', '\t', '\n', '"', '\\', '\'', '`', '@', '$', - '>', '<', '=', ';', '|', '&', '{', '(', '\0' }; +static const Char break_chars[] = { ' ', '\t', '\n', '"', '\\', '\'', '`', '@', + '$', '>', '<', '=', ';', '|', '&', '{', '(', '\0' }; /********************************/ @@ -95,12 +95,16 @@ static char break_chars[] = { ' ', '\t', '\n', '"', '\\', '\'', '`', '@', '$', char * fn_tilde_expand(const char *txt) { +#if defined(HAVE_GETPW_R_POSIX) || defined(HAVE_GETPW_R_DRAFT) + struct passwd pwres; + char pwbuf[1024]; +#endif struct passwd *pass; char *temp; size_t len = 0; if (txt[0] != '~') - return (strdup(txt)); + return strdup(txt); temp = strchr(txt + 1, '/'); if (temp == NULL) { @@ -108,33 +112,49 @@ fn_tilde_expand(const char *txt) if (temp == NULL) return NULL; } else { - len = temp - txt + 1; /* text until string after slash */ - temp = malloc(len); + /* text until string after slash */ + len = (size_t)(temp - txt + 1); + temp = el_malloc(len * sizeof(*temp)); if (temp == NULL) return NULL; (void)strncpy(temp, txt + 1, len - 2); temp[len - 2] = '\0'; } - /* XXXMYSQL: use non-_r functions for now */ if (temp[0] == 0) { +#ifdef HAVE_GETPW_R_POSIX + if (getpwuid_r(getuid(), &pwres, pwbuf, sizeof(pwbuf), + &pass) != 0) + pass = NULL; +#elif HAVE_GETPW_R_DRAFT + pass = getpwuid_r(getuid(), &pwres, pwbuf, sizeof(pwbuf)); +#else pass = getpwuid(getuid()); +#endif } else { +#ifdef HAVE_GETPW_R_POSIX + if (getpwnam_r(temp, &pwres, pwbuf, sizeof(pwbuf), &pass) != 0) + pass = NULL; +#elif HAVE_GETPW_R_DRAFT + pass = getpwnam_r(temp, &pwres, pwbuf, sizeof(pwbuf)); +#else pass = getpwnam(temp); +#endif } - free(temp); /* value no more needed */ + el_free(temp); /* value no more needed */ if (pass == NULL) - return (strdup(txt)); + return strdup(txt); /* update pointer txt to point at string immedially following */ /* first slash */ txt += len; - temp = malloc(strlen(pass->pw_dir) + 1 + strlen(txt) + 1); + len = strlen(pass->pw_dir) + 1 + strlen(txt) + 1; + temp = el_malloc(len * sizeof(*temp)); if (temp == NULL) return NULL; - (void)sprintf(temp, "%s/%s", pass->pw_dir, txt); + (void)snprintf(temp, len, "%s/%s", pass->pw_dir, txt); - return (temp); + return temp; } @@ -160,23 +180,29 @@ fn_filename_completion_function(const char *text, int state) if (temp) { char *nptr; temp++; - nptr = realloc(filename, strlen(temp) + 1); + nptr = el_realloc(filename, (strlen(temp) + 1) * + sizeof(*nptr)); if (nptr == NULL) { - free(filename); + el_free(filename); + filename = NULL; return NULL; } filename = nptr; (void)strcpy(filename, temp); - len = temp - text; /* including last slash */ - nptr = realloc(dirname, len + 1); + len = (size_t)(temp - text); /* including last slash */ + + nptr = el_realloc(dirname, (len + 1) * + sizeof(*nptr)); if (nptr == NULL) { - free(filename); + el_free(dirname); + dirname = NULL; return NULL; } dirname = nptr; (void)strncpy(dirname, text, len); dirname[len] = '\0'; } else { + el_free(filename); if (*text == 0) filename = NULL; else { @@ -184,6 +210,7 @@ fn_filename_completion_function(const char *text, int state) if (filename == NULL) return NULL; } + el_free(dirname); dirname = NULL; } @@ -193,12 +220,14 @@ fn_filename_completion_function(const char *text, int state) } /* support for ``~user'' syntax */ - free(dirpath); - if (dirname == NULL && (dirname = strdup("./")) == NULL) - return NULL; - - if (*dirname == '~') + el_free(dirpath); + dirpath = NULL; + if (dirname == NULL) { + if ((dirname = strdup("")) == NULL) + return NULL; + dirpath = strdup("./"); + } else if (*dirname == '~') dirpath = fn_tilde_expand(dirname); else dirpath = strdup(dirname); @@ -208,7 +237,7 @@ fn_filename_completion_function(const char *text, int state) dir = opendir(dirpath); if (!dir) - return (NULL); /* cannot open the directory */ + return NULL; /* cannot open the directory */ /* will be used in cycle */ filename_len = filename ? strlen(filename) : 0; @@ -243,17 +272,18 @@ fn_filename_completion_function(const char *text, int state) len = strlen(entry->d_name); #endif - temp = malloc(strlen(dirname) + len + 1); + len = strlen(dirname) + len + 1; + temp = el_malloc(len * sizeof(*temp)); if (temp == NULL) return NULL; - (void)sprintf(temp, "%s%s", dirname, entry->d_name); + (void)snprintf(temp, len, "%s%s", dirname, entry->d_name); } else { (void)closedir(dir); dir = NULL; temp = NULL; } - return (temp); + return temp; } @@ -270,7 +300,7 @@ append_char_function(const char *name) rs = "/"; out: if (expname) - free(expname); + el_free(expname); return rs; } /* @@ -293,10 +323,10 @@ completion_matches(const char *text, char *(*genfunc)(const char *, int)) char **nmatch_list; while (matches + 3 >= match_list_len) match_list_len <<= 1; - nmatch_list = realloc(match_list, - match_list_len * sizeof(char *)); + nmatch_list = el_realloc(match_list, + match_list_len * sizeof(*nmatch_list)); if (nmatch_list == NULL) { - free(match_list); + el_free(match_list); return NULL; } match_list = nmatch_list; @@ -319,9 +349,9 @@ completion_matches(const char *text, char *(*genfunc)(const char *, int)) max_equal = i; } - retstr = malloc(max_equal + 1); + retstr = el_malloc((max_equal + 1) * sizeof(*retstr)); if (retstr == NULL) { - free(match_list); + el_free(match_list); return NULL; } (void)strncpy(retstr, match_list[1], max_equal); @@ -329,9 +359,9 @@ completion_matches(const char *text, char *(*genfunc)(const char *, int)) match_list[0] = retstr; /* add NULL as last pointer to the array */ - match_list[matches + 1] = (char *) NULL; + match_list[matches + 1] = NULL; - return (match_list); + return match_list; } /* @@ -348,37 +378,47 @@ _fn_qsort_string_compare(const void *i1, const void *i2) /* * Display list of strings in columnar format on readline's output stream. - * 'matches' is list of strings, 'len' is number of strings in 'matches', - * 'max' is maximum length of string in 'matches'. + * 'matches' is list of strings, 'num' is number of strings in 'matches', + * 'width' is maximum length of string in 'matches'. + * + * matches[0] is not one of the match strings, but it is counted in + * num, so the strings are matches[1] *through* matches[num-1]. */ void -fn_display_match_list (EditLine *el, char **matches, int len, int max) +fn_display_match_list (EditLine *el, char **matches, size_t num, size_t width) { - int i, idx, limit, count; - int screenwidth = el->el_term.t_size.h; + size_t line, lines, col, cols, thisguy; + int screenwidth = el->el_terminal.t_size.h; + + /* Ignore matches[0]. Avoid 1-based array logic below. */ + matches++; + num--; /* - * Find out how many entries can be put on one line, count - * with two spaces between strings. + * Find out how many entries can be put on one line; count + * with one space between strings the same way it's printed. */ - limit = screenwidth / (max + 2); - if (limit == 0) - limit = 1; + cols = (size_t)screenwidth / (width + 1); + if (cols == 0) + cols = 1; - /* how many lines of output */ - count = len / limit; - if (count * limit < len) - count++; + /* how many lines of output, rounded up */ + lines = (num + cols - 1) / cols; - /* Sort the items if they are not already sorted. */ - qsort(&matches[1], (size_t)(len - 1), sizeof(char *), - _fn_qsort_string_compare); + /* Sort the items. */ + qsort(matches, num, sizeof(char *), _fn_qsort_string_compare); - idx = 1; - for(; count > 0; count--) { - for(i = 0; i < limit && matches[idx]; i++, idx++) - (void)fprintf(el->el_outfile, "%-*s ", max, - matches[idx]); + /* + * On the ith line print elements i, i+lines, i+lines*2, etc. + */ + for (line = 0; line < lines; line++) { + for (col = 0; col < cols; col++) { + thisguy = line + col * lines; + if (thisguy >= num) + break; + (void)fprintf(el->el_outfile, "%s%-*s", + col == 0 ? "" : " ", (int)width, matches[thisguy]); + } (void)fprintf(el->el_outfile, "\n"); } } @@ -399,13 +439,14 @@ int fn_complete(EditLine *el, char *(*complet_func)(const char *, int), char **(*attempted_completion_function)(const char *, int, int), - const char *word_break, const char *special_prefixes, - const char *(*app_func)(const char *), int query_items, + const Char *word_break, const Char *special_prefixes, + const char *(*app_func)(const char *), size_t query_items, int *completion_type, int *over, int *point, int *end) { - const LineInfo *li; - char *temp, **matches; - const char *ctemp; + const TYPE(LineInfo) *li; + Char *temp; + char **matches; + const Char *ctemp; size_t len; int what_to_do = '\t'; int retval = CC_NORM; @@ -423,45 +464,47 @@ fn_complete(EditLine *el, app_func = append_char_function; /* We now look backwards for the start of a filename/variable word */ - li = el_line(el); - ctemp = (const char *) li->cursor; + li = FUN(el,line)(el); + ctemp = li->cursor; while (ctemp > li->buffer - && !strchr(word_break, ctemp[-1]) - && (!special_prefixes || !strchr(special_prefixes, ctemp[-1]) ) ) + && !Strchr(word_break, ctemp[-1]) + && (!special_prefixes || !Strchr(special_prefixes, ctemp[-1]) ) ) ctemp--; - len = li->cursor - ctemp; + len = (size_t)(li->cursor - ctemp); #if defined(__SSP__) || defined(__SSP_ALL__) - temp = malloc(len + 1); + temp = el_malloc((len + 1) * sizeof(*temp)); #else - temp = alloca(len + 1); + temp = alloca((len + 1) * sizeof(*temp)); #endif - (void)strncpy(temp, ctemp, len); + (void)Strncpy(temp, ctemp, len); temp[len] = '\0'; /* these can be used by function called in completion_matches() */ /* or (*attempted_completion_function)() */ if (point != 0) - *point = li->cursor - li->buffer; + *point = (int)(li->cursor - li->buffer); if (end != NULL) - *end = li->lastchar - li->buffer; + *end = (int)(li->lastchar - li->buffer); if (attempted_completion_function) { - int cur_off = li->cursor - li->buffer; - matches = (*attempted_completion_function) (temp, - (int)(cur_off - len), cur_off); + int cur_off = (int)(li->cursor - li->buffer); + matches = (*attempted_completion_function)( + ct_encode_string(temp, &el->el_scratch), + cur_off - (int)len, cur_off); } else matches = 0; if (!attempted_completion_function || (over != NULL && !*over && !matches)) - matches = completion_matches(temp, complet_func); + matches = completion_matches( + ct_encode_string(temp, &el->el_scratch), complet_func); if (over != NULL) *over = 0; if (matches) { int i; - int matches_num, maxlen, match_len, match_display=1; + size_t matches_num, maxlen, match_len, match_display=1; retval = CC_REFRESH; /* @@ -470,7 +513,8 @@ fn_complete(EditLine *el, */ if (matches[0][0] != '\0') { el_deletestr(el, (int) len); - el_insertstr(el, matches[0]); + FUN(el,insertstr)(el, + ct_decode_string(matches[0], &el->el_scratch)); } if (what_to_do == '?') @@ -482,7 +526,9 @@ fn_complete(EditLine *el, * it, unless we do filename completion and the * object is a directory. */ - el_insertstr(el, (*app_func)(matches[0])); + FUN(el,insertstr)(el, + ct_decode_string((*app_func)(matches[0]), + &el->el_scratch)); } else if (what_to_do == '!') { display_matches: /* @@ -490,12 +536,13 @@ fn_complete(EditLine *el, * matches. */ - for(i=1, maxlen=0; matches[i]; i++) { + for(i = 1, maxlen = 0; matches[i]; i++) { match_len = strlen(matches[i]); if (match_len > maxlen) maxlen = match_len; } - matches_num = i - 1; + /* matches[1] through matches[i-1] are available */ + matches_num = (size_t)(i - 1); /* newline to get on next line from command line */ (void)fprintf(el->el_outfile, "\n"); @@ -506,7 +553,7 @@ fn_complete(EditLine *el, */ if (matches_num > query_items) { (void)fprintf(el->el_outfile, - "Display all %d possibilities? (y or n) ", + "Display all %zu possibilities? (y or n) ", matches_num); (void)fflush(el->el_outfile); if (getc(stdin) != 'y') @@ -514,9 +561,17 @@ fn_complete(EditLine *el, (void)fprintf(el->el_outfile, "\n"); } - if (match_display) - fn_display_match_list(el, matches, matches_num, - maxlen); + if (match_display) { + /* + * Interface of this function requires the + * strings be matches[1..num-1] for compat. + * We have matches_num strings not counting + * the prefix in matches[0], so we need to + * add 1 to matches_num for the call. + */ + fn_display_match_list(el, matches, + matches_num+1, maxlen); + } retval = CC_REDISPLAY; } else if (matches[0][0]) { /* @@ -534,12 +589,12 @@ fn_complete(EditLine *el, /* free elements of array and the array itself */ for (i = 0; matches[i]; i++) - free(matches[i]); - free(matches); + el_free(matches[i]); + el_free(matches); matches = NULL; } #if defined(__SSP__) || defined(__SSP_ALL__) - free(temp); + el_free(temp); #endif return retval; } @@ -552,6 +607,6 @@ unsigned char _el_fn_complete(EditLine *el, int ch __attribute__((__unused__))) { return (unsigned char)fn_complete(el, NULL, NULL, - break_chars, NULL, NULL, 100, + break_chars, NULL, NULL, (size_t)100, NULL, NULL, NULL, NULL); } diff --git a/cmd-line-utils/libedit/filecomplete.h b/cmd-line-utils/libedit/filecomplete.h index 12e0c6f14b0..971e6e05939 100644 --- a/cmd-line-utils/libedit/filecomplete.h +++ b/cmd-line-utils/libedit/filecomplete.h @@ -1,4 +1,4 @@ -/* $NetBSD: filecomplete.h,v 1.6 2008/04/29 06:53:01 martin Exp $ */ +/* $NetBSD: filecomplete.h,v 1.9 2009/12/30 22:37:40 christos Exp $ */ /*- * Copyright (c) 1997 The NetBSD Foundation, Inc. @@ -34,10 +34,10 @@ int fn_complete(EditLine *, char *(*)(const char *, int), char **(*)(const char *, int, int), - const char *, const char *, const char *(*)(const char *), int, + const Char *, const Char *, const char *(*)(const char *), size_t, int *, int *, int *, int *); -void fn_display_match_list(EditLine *, char **, int, int); +void fn_display_match_list(EditLine *, char **, size_t, size_t); char *fn_tilde_expand(const char *); char *fn_filename_completion_function(const char *, int); diff --git a/cmd-line-utils/libedit/hist.c b/cmd-line-utils/libedit/hist.c index c0b23ee6641..d24f5e7ff53 100644 --- a/cmd-line-utils/libedit/hist.c +++ b/cmd-line-utils/libedit/hist.c @@ -1,4 +1,4 @@ -/* $NetBSD: hist.c,v 1.15 2003/11/01 23:36:39 christos Exp $ */ +/* $NetBSD: hist.c,v 1.20 2011/07/29 15:16:33 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -55,12 +55,12 @@ hist_init(EditLine *el) el->el_history.fun = NULL; el->el_history.ref = NULL; - el->el_history.buf = (char *) el_malloc(EL_BUFSIZ); + el->el_history.buf = el_malloc(EL_BUFSIZ * sizeof(*el->el_history.buf)); el->el_history.sz = EL_BUFSIZ; if (el->el_history.buf == NULL) - return (-1); + return -1; el->el_history.last = el->el_history.buf; - return (0); + return 0; } @@ -71,7 +71,7 @@ protected void hist_end(EditLine *el) { - el_free((ptr_t) el->el_history.buf); + el_free(el->el_history.buf); el->el_history.buf = NULL; } @@ -80,12 +80,12 @@ hist_end(EditLine *el) * Set new history interface */ protected int -hist_set(EditLine *el, hist_fun_t fun, ptr_t ptr) +hist_set(EditLine *el, hist_fun_t fun, void *ptr) { el->el_history.ref = ptr; el->el_history.fun = fun; - return (0); + return 0; } @@ -96,11 +96,11 @@ hist_set(EditLine *el, hist_fun_t fun, ptr_t ptr) protected el_action_t hist_get(EditLine *el) { - const char *hp; + const Char *hp; int h; if (el->el_history.eventno == 0) { /* if really the current line */ - (void) strncpy(el->el_line.buffer, el->el_history.buf, + (void) Strncpy(el->el_line.buffer, el->el_history.buf, el->el_history.sz); el->el_line.lastchar = el->el_line.buffer + (el->el_history.last - el->el_history.buf); @@ -112,24 +112,25 @@ hist_get(EditLine *el) #endif /* KSHVI */ el->el_line.cursor = el->el_line.lastchar; - return (CC_REFRESH); + return CC_REFRESH; } if (el->el_history.ref == NULL) - return (CC_ERROR); + return CC_ERROR; hp = HIST_FIRST(el); if (hp == NULL) - return (CC_ERROR); + return CC_ERROR; for (h = 1; h < el->el_history.eventno; h++) if ((hp = HIST_NEXT(el)) == NULL) { el->el_history.eventno = h; - return (CC_ERROR); + return CC_ERROR; } - (void) strlcpy(el->el_line.buffer, hp, + (void) Strncpy(el->el_line.buffer, hp, (size_t)(el->el_line.limit - el->el_line.buffer)); - el->el_line.lastchar = el->el_line.buffer + strlen(el->el_line.buffer); + el->el_line.buffer[el->el_line.limit - el->el_line.buffer - 1] = '\0'; + el->el_line.lastchar = el->el_line.buffer + Strlen(el->el_line.buffer); if (el->el_line.lastchar > el->el_line.buffer && el->el_line.lastchar[-1] == '\n') @@ -144,7 +145,7 @@ hist_get(EditLine *el) #endif /* KSHVI */ el->el_line.cursor = el->el_line.lastchar; - return (CC_REFRESH); + return CC_REFRESH; } @@ -152,34 +153,34 @@ hist_get(EditLine *el) * process a history command */ protected int -hist_command(EditLine *el, int argc, const char **argv) +hist_command(EditLine *el, int argc, const Char **argv) { - const char *str; + const Char *str; int num; - HistEvent ev; + TYPE(HistEvent) ev; if (el->el_history.ref == NULL) - return (-1); + return -1; - if (argc == 1 || strcmp(argv[1], "list") == 0) { + if (argc == 1 || Strcmp(argv[1], STR("list")) == 0) { /* List history entries */ for (str = HIST_LAST(el); str != NULL; str = HIST_PREV(el)) (void) fprintf(el->el_outfile, "%d %s", - el->el_history.ev.num, str); - return (0); + el->el_history.ev.num, ct_encode_string(str, &el->el_scratch)); + return 0; } if (argc != 3) - return (-1); + return -1; - num = (int)strtol(argv[2], NULL, 0); + num = (int)Strtol(argv[2], NULL, 0); - if (strcmp(argv[1], "size") == 0) - return history(el->el_history.ref, &ev, H_SETSIZE, num); + if (Strcmp(argv[1], STR("size")) == 0) + return FUNW(history)(el->el_history.ref, &ev, H_SETSIZE, num); - if (strcmp(argv[1], "unique") == 0) - return history(el->el_history.ref, &ev, H_SETUNIQUE, num); + if (Strcmp(argv[1], STR("unique")) == 0) + return FUNW(history)(el->el_history.ref, &ev, H_SETUNIQUE, num); return -1; } @@ -192,13 +193,13 @@ protected int /*ARGSUSED*/ hist_enlargebuf(EditLine *el, size_t oldsz, size_t newsz) { - char *newbuf; + Char *newbuf; - newbuf = realloc(el->el_history.buf, newsz); + newbuf = el_realloc(el->el_history.buf, newsz * sizeof(*newbuf)); if (!newbuf) return 0; - (void) memset(&newbuf[oldsz], '\0', newsz - oldsz); + (void) memset(&newbuf[oldsz], '\0', (newsz - oldsz) * sizeof(*newbuf)); el->el_history.last = newbuf + (el->el_history.last - el->el_history.buf); @@ -207,3 +208,15 @@ hist_enlargebuf(EditLine *el, size_t oldsz, size_t newsz) return 1; } + +#ifdef WIDECHAR +protected wchar_t * +hist_convert(EditLine *el, int fn, void *arg) +{ + HistEventW ev; + if ((*(el)->el_history.fun)((el)->el_history.ref, &ev, fn, arg) == -1) + return NULL; + return ct_decode_string((const char *)(const void *)ev.str, + &el->el_scratch); +} +#endif diff --git a/cmd-line-utils/libedit/hist.h b/cmd-line-utils/libedit/hist.h index 46e14634adf..a63be499dbd 100644 --- a/cmd-line-utils/libedit/hist.h +++ b/cmd-line-utils/libedit/hist.h @@ -1,4 +1,4 @@ -/* $NetBSD: hist.h,v 1.10 2003/08/07 16:44:31 agc Exp $ */ +/* $NetBSD: hist.h,v 1.13 2011/07/28 20:50:55 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -42,21 +42,29 @@ #include "histedit.h" -typedef int (*hist_fun_t)(ptr_t, HistEvent *, int, ...); +typedef int (*hist_fun_t)(void *, TYPE(HistEvent) *, int, ...); typedef struct el_history_t { - char *buf; /* The history buffer */ + Char *buf; /* The history buffer */ size_t sz; /* Size of history buffer */ - char *last; /* The last character */ + Char *last; /* The last character */ int eventno; /* Event we are looking for */ - ptr_t ref; /* Argument for history fcns */ + void * ref; /* Argument for history fcns */ hist_fun_t fun; /* Event access */ - HistEvent ev; /* Event cookie */ + TYPE(HistEvent) ev; /* Event cookie */ } el_history_t; -#define HIST_FUN(el, fn, arg) \ +#define HIST_FUN_INTERNAL(el, fn, arg) \ ((((*(el)->el_history.fun) ((el)->el_history.ref, &(el)->el_history.ev, \ fn, arg)) == -1) ? NULL : (el)->el_history.ev.str) +#ifdef WIDECHAR +#define HIST_FUN(el, fn, arg) \ + (((el)->el_flags & NARROW_HISTORY) ? hist_convert(el, fn, arg) : \ + HIST_FUN_INTERNAL(el, fn, arg)) +#else +#define HIST_FUN(el, fn, arg) HIST_FUN_INTERNAL(el, fn, arg) +#endif + #define HIST_NEXT(el) HIST_FUN(el, H_NEXT, NULL) #define HIST_FIRST(el) HIST_FUN(el, H_FIRST, NULL) @@ -69,8 +77,11 @@ typedef struct el_history_t { protected int hist_init(EditLine *); protected void hist_end(EditLine *); protected el_action_t hist_get(EditLine *); -protected int hist_set(EditLine *, hist_fun_t, ptr_t); -protected int hist_command(EditLine *, int, const char **); +protected int hist_set(EditLine *, hist_fun_t, void *); +protected int hist_command(EditLine *, int, const Char **); protected int hist_enlargebuf(EditLine *, size_t, size_t); +#ifdef WIDECHAR +protected wchar_t *hist_convert(EditLine *, int, void *); +#endif #endif /* _h_el_hist */ diff --git a/cmd-line-utils/libedit/histedit.h b/cmd-line-utils/libedit/histedit.h index 37823141c06..b066593cefd 100644 --- a/cmd-line-utils/libedit/histedit.h +++ b/cmd-line-utils/libedit/histedit.h @@ -1,4 +1,4 @@ -/* $NetBSD: histedit.h,v 1.35 2009/02/05 19:15:44 christos Exp $ */ +/* $NetBSD: histedit.h,v 1.48 2011/07/28 20:50:55 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -43,6 +43,8 @@ #define LIBEDIT_MAJOR 2 #define LIBEDIT_MINOR 11 +#include + #include #include @@ -114,29 +116,46 @@ unsigned char _el_fn_complete(EditLine *, int); /* * el_set/el_get parameters + * + * When using el_wset/el_wget (as opposed to el_set/el_get): + * Char is wchar_t, otherwise it is char. + * prompt_func is el_wpfunc_t, otherwise it is el_pfunc_t . + + * Prompt function prototypes are: + * typedef char *(*el_pfunct_t) (EditLine *); + * typedef wchar_t *(*el_wpfunct_t) (EditLine *); + * + * For operations that support set or set/get, the argument types listed are for + * the "set" operation. For "get", each listed type must be a pointer. + * E.g. EL_EDITMODE takes an int when set, but an int* when get. + * + * Operations that only support "get" have the correct argument types listed. */ -#define EL_PROMPT 0 /* , el_pfunc_t); */ -#define EL_TERMINAL 1 /* , const char *); */ -#define EL_EDITOR 2 /* , const char *); */ -#define EL_SIGNAL 3 /* , int); */ -#define EL_BIND 4 /* , const char *, ..., NULL); */ -#define EL_TELLTC 5 /* , const char *, ..., NULL); */ -#define EL_SETTC 6 /* , const char *, ..., NULL); */ -#define EL_ECHOTC 7 /* , const char *, ..., NULL); */ -#define EL_SETTY 8 /* , const char *, ..., NULL); */ -#define EL_ADDFN 9 /* , const char *, const char * */ - /* , el_func_t); */ -#define EL_HIST 10 /* , hist_fun_t, const char *); */ -#define EL_EDITMODE 11 /* , int); */ -#define EL_RPROMPT 12 /* , el_pfunc_t); */ -#define EL_GETCFN 13 /* , el_rfunc_t); */ -#define EL_CLIENTDATA 14 /* , void *); */ -#define EL_UNBUFFERED 15 /* , int); */ -#define EL_PREP_TERM 16 /* , int); */ -#define EL_GETTC 17 /* , const char *, ..., NULL); */ -#define EL_GETFP 18 /* , int, FILE **); */ -#define EL_SETFP 19 /* , int, FILE *); */ -#define EL_REFRESH 20 /* , void); */ +#define EL_PROMPT 0 /* , prompt_func); set/get */ +#define EL_TERMINAL 1 /* , const char *); set/get */ +#define EL_EDITOR 2 /* , const Char *); set/get */ +#define EL_SIGNAL 3 /* , int); set/get */ +#define EL_BIND 4 /* , const Char *, ..., NULL); set */ +#define EL_TELLTC 5 /* , const Char *, ..., NULL); set */ +#define EL_SETTC 6 /* , const Char *, ..., NULL); set */ +#define EL_ECHOTC 7 /* , const Char *, ..., NULL); set */ +#define EL_SETTY 8 /* , const Char *, ..., NULL); set */ +#define EL_ADDFN 9 /* , const Char *, const Char, set */ + /* el_func_t); */ +#define EL_HIST 10 /* , hist_fun_t, const void *); set */ +#define EL_EDITMODE 11 /* , int); set/get */ +#define EL_RPROMPT 12 /* , prompt_func); set/get */ +#define EL_GETCFN 13 /* , el_rfunc_t); set/get */ +#define EL_CLIENTDATA 14 /* , void *); set/get */ +#define EL_UNBUFFERED 15 /* , int); set/get */ +#define EL_PREP_TERM 16 /* , int); set */ +#define EL_GETTC 17 /* , const Char *, ..., NULL); get */ +#define EL_GETFP 18 /* , int, FILE **); get */ +#define EL_SETFP 19 /* , int, FILE *); set */ +#define EL_REFRESH 20 /* , void); set */ +#define EL_PROMPT_ESC 21 /* , prompt_func, Char); set/get */ +#define EL_RPROMPT_ESC 22 /* , prompt_func, Char); set/get */ +#define EL_RESIZE 23 /* , el_zfunc_t, void *); set */ #define EL_BUILTIN_GETCFN (NULL) @@ -188,12 +207,12 @@ int history(History *, HistEvent *, int, ...); #define H_NEXT 6 /* , void); */ #define H_CURR 8 /* , const int); */ #define H_SET 7 /* , int); */ -#define H_ADD 9 /* , const char *); */ -#define H_ENTER 10 /* , const char *); */ -#define H_APPEND 11 /* , const char *); */ +#define H_ADD 9 /* , const wchar_t *); */ +#define H_ENTER 10 /* , const wchar_t *); */ +#define H_APPEND 11 /* , const wchar_t *); */ #define H_END 12 /* , void); */ -#define H_NEXT_STR 13 /* , const char *); */ -#define H_PREV_STR 14 /* , const char *); */ +#define H_NEXT_STR 13 /* , const wchar_t *); */ +#define H_PREV_STR 14 /* , const wchar_t *); */ #define H_NEXT_EVENT 15 /* , const int); */ #define H_PREV_EVENT 16 /* , const int); */ #define H_LOAD 17 /* , const char *); */ @@ -202,6 +221,10 @@ int history(History *, HistEvent *, int, ...); #define H_SETUNIQUE 20 /* , int); */ #define H_GETUNIQUE 21 /* , void); */ #define H_DEL 22 /* , int); */ +#define H_NEXT_EVDATA 23 /* , const int, histdata_t *); */ +#define H_DELDATA 24 /* , int, histdata_t *);*/ +#define H_REPLACE 25 /* , const char *, histdata_t); */ + /* @@ -221,6 +244,74 @@ int tok_line(Tokenizer *, const LineInfo *, int tok_str(Tokenizer *, const char *, int *, const char ***); +/* + * Begin Wide Character Support + */ +#ifdef __linux__ +/* Apparently we need _GNU_SOURCE defined to get access to wcsdup on Linux */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#endif + +#include +#include + +/* + * Wide character versions + */ + +/* + * ==== Editing ==== + */ +typedef struct lineinfow { + const wchar_t *buffer; + const wchar_t *cursor; + const wchar_t *lastchar; +} LineInfoW; + +const wchar_t *el_wgets(EditLine *, int *); +int el_wgetc(EditLine *, wchar_t *); +void el_wpush(EditLine *, const wchar_t *); + +int el_wparse(EditLine *, int, const wchar_t **); + +int el_wset(EditLine *, int, ...); +int el_wget(EditLine *, int, ...); + +const LineInfoW *el_wline(EditLine *); +int el_winsertstr(EditLine *, const wchar_t *); +#define el_wdeletestr el_deletestr + +/* + * ==== History ==== + */ +typedef struct histeventW { + int num; + const wchar_t *str; +} HistEventW; + +typedef struct historyW HistoryW; + +HistoryW * history_winit(void); +void history_wend(HistoryW *); + +int history_w(HistoryW *, HistEventW *, int, ...); + +/* + * ==== Tokenization ==== + */ +typedef struct tokenizerW TokenizerW; + +/* Wide character tokenizer support */ +TokenizerW *tok_winit(const wchar_t *); +void tok_wend(TokenizerW *); +void tok_wreset(TokenizerW *); +int tok_wline(TokenizerW *, const LineInfoW *, + int *, const wchar_t ***, int *, int *); +int tok_wstr(TokenizerW *, const wchar_t *, + int *, const wchar_t ***); + #ifdef __cplusplus } #endif diff --git a/cmd-line-utils/libedit/history.c b/cmd-line-utils/libedit/history.c index 3080dd231f6..6d2176c258b 100644 --- a/cmd-line-utils/libedit/history.c +++ b/cmd-line-utils/libedit/history.c @@ -1,4 +1,4 @@ -/* $NetBSD: history.c,v 1.33 2009/02/06 14:40:32 sketch Exp $ */ +/* $NetBSD: history.c,v 1.45 2011/07/29 23:44:44 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -41,7 +41,7 @@ static char sccsid[] = "@(#)history.c 8.1 (Berkeley) 6/4/93"; #endif /* not lint && not SCCSID */ /* - * hist.c: History access functions + * hist.c: TYPE(History) access functions */ #include #include @@ -56,14 +56,15 @@ static char sccsid[] = "@(#)history.c 8.1 (Berkeley) 6/4/93"; static const char hist_cookie[] = "_HiStOrY_V2_\n"; #include "histedit.h" +#include "chartype.h" -typedef int (*history_gfun_t)(ptr_t, HistEvent *); -typedef int (*history_efun_t)(ptr_t, HistEvent *, const char *); -typedef void (*history_vfun_t)(ptr_t, HistEvent *); -typedef int (*history_sfun_t)(ptr_t, HistEvent *, const int); +typedef int (*history_gfun_t)(void *, TYPE(HistEvent) *); +typedef int (*history_efun_t)(void *, TYPE(HistEvent) *, const Char *); +typedef void (*history_vfun_t)(void *, TYPE(HistEvent) *); +typedef int (*history_sfun_t)(void *, TYPE(HistEvent) *, const int); -struct history { - ptr_t h_ref; /* Argument for history fcns */ +struct TYPE(history) { + void *h_ref; /* Argument for history fcns */ int h_ent; /* Last entry point for history */ history_gfun_t h_first; /* Get the first element */ history_gfun_t h_next; /* Get the next element */ @@ -88,29 +89,29 @@ struct history { #define HADD(h, ev, str) (*(h)->h_add)((h)->h_ref, ev, str) #define HDEL(h, ev, n) (*(h)->h_del)((h)->h_ref, ev, n) -#define h_strdup(a) strdup(a) +#define h_strdup(a) Strdup(a) #define h_malloc(a) malloc(a) #define h_realloc(a, b) realloc((a), (b)) #define h_free(a) free(a) typedef struct { int num; - char *str; + Char *str; } HistEventPrivate; -private int history_setsize(History *, HistEvent *, int); -private int history_getsize(History *, HistEvent *); -private int history_setunique(History *, HistEvent *, int); -private int history_getunique(History *, HistEvent *); -private int history_set_fun(History *, History *); -private int history_load(History *, const char *); -private int history_save(History *, const char *); -private int history_prev_event(History *, HistEvent *, int); -private int history_next_event(History *, HistEvent *, int); -private int history_next_string(History *, HistEvent *, const char *); -private int history_prev_string(History *, HistEvent *, const char *); +private int history_setsize(TYPE(History) *, TYPE(HistEvent) *, int); +private int history_getsize(TYPE(History) *, TYPE(HistEvent) *); +private int history_setunique(TYPE(History) *, TYPE(HistEvent) *, int); +private int history_getunique(TYPE(History) *, TYPE(HistEvent) *); +private int history_set_fun(TYPE(History) *, TYPE(History) *); +private int history_load(TYPE(History) *, const char *); +private int history_save(TYPE(History) *, const char *); +private int history_prev_event(TYPE(History) *, TYPE(HistEvent) *, int); +private int history_next_event(TYPE(History) *, TYPE(HistEvent) *, int); +private int history_next_string(TYPE(History) *, TYPE(HistEvent) *, const Char *); +private int history_prev_string(TYPE(History) *, TYPE(HistEvent) *, const Char *); /***********************************************************************/ @@ -119,7 +120,8 @@ private int history_prev_string(History *, HistEvent *, const char *); * Builtin- history implementation */ typedef struct hentry_t { - HistEvent ev; /* What we return */ + TYPE(HistEvent) ev; /* What we return */ + void *data; /* data */ struct hentry_t *next; /* Next entry */ struct hentry_t *prev; /* Previous entry */ } hentry_t; @@ -130,24 +132,27 @@ typedef struct history_t { int max; /* Maximum number of events */ int cur; /* Current number of events */ int eventid; /* For generation of unique event id */ - int flags; /* History flags */ + int flags; /* TYPE(History) flags */ #define H_UNIQUE 1 /* Store only unique elements */ } history_t; -private int history_def_next(ptr_t, HistEvent *); -private int history_def_first(ptr_t, HistEvent *); -private int history_def_prev(ptr_t, HistEvent *); -private int history_def_last(ptr_t, HistEvent *); -private int history_def_curr(ptr_t, HistEvent *); -private int history_def_set(ptr_t, HistEvent *, const int); -private void history_def_clear(ptr_t, HistEvent *); -private int history_def_enter(ptr_t, HistEvent *, const char *); -private int history_def_add(ptr_t, HistEvent *, const char *); -private int history_def_del(ptr_t, HistEvent *, const int); +private int history_def_next(void *, TYPE(HistEvent) *); +private int history_def_first(void *, TYPE(HistEvent) *); +private int history_def_prev(void *, TYPE(HistEvent) *); +private int history_def_last(void *, TYPE(HistEvent) *); +private int history_def_curr(void *, TYPE(HistEvent) *); +private int history_def_set(void *, TYPE(HistEvent) *, const int); +private void history_def_clear(void *, TYPE(HistEvent) *); +private int history_def_enter(void *, TYPE(HistEvent) *, const Char *); +private int history_def_add(void *, TYPE(HistEvent) *, const Char *); +private int history_def_del(void *, TYPE(HistEvent) *, const int); -private int history_def_init(ptr_t *, HistEvent *, int); -private int history_def_insert(history_t *, HistEvent *, const char *); -private void history_def_delete(history_t *, HistEvent *, hentry_t *); +private int history_def_init(void **, TYPE(HistEvent) *, int); +private int history_def_insert(history_t *, TYPE(HistEvent) *, const Char *); +private void history_def_delete(history_t *, TYPE(HistEvent) *, hentry_t *); + +private int history_deldata_nth(history_t *, TYPE(HistEvent) *, int, void **); +private int history_set_nth(void *, TYPE(HistEvent) *, int); #define history_def_setsize(p, num)(void) (((history_t *)p)->max = (num)) #define history_def_getsize(p) (((history_t *)p)->cur) @@ -165,23 +170,23 @@ private void history_def_delete(history_t *, HistEvent *, hentry_t *); } /* error messages */ -static const char *const he_errlist[] = { - "OK", - "unknown error", - "malloc() failed", - "first event not found", - "last event not found", - "empty list", - "no next event", - "no previous event", - "current event is invalid", - "event not found", - "can't read history from file", - "can't write history", - "required parameter(s) not supplied", - "history size negative", - "function not allowed with other history-functions-set the default", - "bad parameters" +static const Char *const he_errlist[] = { + STR("OK"), + STR("unknown error"), + STR("malloc() failed"), + STR("first event not found"), + STR("last event not found"), + STR("empty list"), + STR("no next event"), + STR("no previous event"), + STR("current event is invalid"), + STR("event not found"), + STR("can't read history from file"), + STR("can't write history"), + STR("required parameter(s) not supplied"), + STR("history size negative"), + STR("function not allowed with other history-functions-set the default"), + STR("bad parameters") }; /* error codes */ #define _HE_OK 0 @@ -205,7 +210,7 @@ static const char *const he_errlist[] = { * Default function to return the first event in the history. */ private int -history_def_first(ptr_t p, HistEvent *ev) +history_def_first(void *p, TYPE(HistEvent) *ev) { history_t *h = (history_t *) p; @@ -214,10 +219,10 @@ history_def_first(ptr_t p, HistEvent *ev) *ev = h->cursor->ev; else { he_seterrev(ev, _HE_FIRST_NOTFOUND); - return (-1); + return -1; } - return (0); + return 0; } @@ -225,7 +230,7 @@ history_def_first(ptr_t p, HistEvent *ev) * Default function to return the last event in the history. */ private int -history_def_last(ptr_t p, HistEvent *ev) +history_def_last(void *p, TYPE(HistEvent) *ev) { history_t *h = (history_t *) p; @@ -234,10 +239,10 @@ history_def_last(ptr_t p, HistEvent *ev) *ev = h->cursor->ev; else { he_seterrev(ev, _HE_LAST_NOTFOUND); - return (-1); + return -1; } - return (0); + return 0; } @@ -245,24 +250,24 @@ history_def_last(ptr_t p, HistEvent *ev) * Default function to return the next event in the history. */ private int -history_def_next(ptr_t p, HistEvent *ev) +history_def_next(void *p, TYPE(HistEvent) *ev) { history_t *h = (history_t *) p; if (h->cursor == &h->list) { he_seterrev(ev, _HE_EMPTY_LIST); - return (-1); + return -1; } if (h->cursor->next == &h->list) { he_seterrev(ev, _HE_END_REACHED); - return (-1); + return -1; } h->cursor = h->cursor->next; *ev = h->cursor->ev; - return (0); + return 0; } @@ -270,25 +275,25 @@ history_def_next(ptr_t p, HistEvent *ev) * Default function to return the previous event in the history. */ private int -history_def_prev(ptr_t p, HistEvent *ev) +history_def_prev(void *p, TYPE(HistEvent) *ev) { history_t *h = (history_t *) p; if (h->cursor == &h->list) { he_seterrev(ev, (h->cur > 0) ? _HE_END_REACHED : _HE_EMPTY_LIST); - return (-1); + return -1; } if (h->cursor->prev == &h->list) { he_seterrev(ev, _HE_START_REACHED); - return (-1); + return -1; } h->cursor = h->cursor->prev; *ev = h->cursor->ev; - return (0); + return 0; } @@ -296,7 +301,7 @@ history_def_prev(ptr_t p, HistEvent *ev) * Default function to return the current event in the history. */ private int -history_def_curr(ptr_t p, HistEvent *ev) +history_def_curr(void *p, TYPE(HistEvent) *ev) { history_t *h = (history_t *) p; @@ -305,10 +310,10 @@ history_def_curr(ptr_t p, HistEvent *ev) else { he_seterrev(ev, (h->cur > 0) ? _HE_CURR_INVALID : _HE_EMPTY_LIST); - return (-1); + return -1; } - return (0); + return 0; } @@ -317,13 +322,13 @@ history_def_curr(ptr_t p, HistEvent *ev) * given one. */ private int -history_def_set(ptr_t p, HistEvent *ev, const int n) +history_def_set(void *p, TYPE(HistEvent) *ev, const int n) { history_t *h = (history_t *) p; if (h->cur == 0) { he_seterrev(ev, _HE_EMPTY_LIST); - return (-1); + return -1; } if (h->cursor == &h->list || h->cursor->ev.num != n) { for (h->cursor = h->list.next; h->cursor != &h->list; @@ -333,9 +338,34 @@ history_def_set(ptr_t p, HistEvent *ev, const int n) } if (h->cursor == &h->list) { he_seterrev(ev, _HE_NOT_FOUND); - return (-1); + return -1; } - return (0); + return 0; +} + + +/* history_set_nth(): + * Default function to set the current event in the history to the + * n-th one. + */ +private int +history_set_nth(void *p, TYPE(HistEvent) *ev, int n) +{ + history_t *h = (history_t *) p; + + if (h->cur == 0) { + he_seterrev(ev, _HE_EMPTY_LIST); + return -1; + } + for (h->cursor = h->list.prev; h->cursor != &h->list; + h->cursor = h->cursor->prev) + if (n-- <= 0) + break; + if (h->cursor == &h->list) { + he_seterrev(ev, _HE_NOT_FOUND); + return -1; + } + return 0; } @@ -343,27 +373,46 @@ history_def_set(ptr_t p, HistEvent *ev, const int n) * Append string to element */ private int -history_def_add(ptr_t p, HistEvent *ev, const char *str) +history_def_add(void *p, TYPE(HistEvent) *ev, const Char *str) { history_t *h = (history_t *) p; size_t len; - char *s; + Char *s; HistEventPrivate *evp = (void *)&h->cursor->ev; if (h->cursor == &h->list) - return (history_def_enter(p, ev, str)); - len = strlen(evp->str) + strlen(str) + 1; - s = (char *) h_malloc(len); + return history_def_enter(p, ev, str); + len = Strlen(evp->str) + Strlen(str) + 1; + s = h_malloc(len * sizeof(*s)); if (s == NULL) { he_seterrev(ev, _HE_MALLOC_FAILED); - return (-1); + return -1; } - (void) strlcpy(s, h->cursor->ev.str, len); - (void) strlcat(s, str, len); - h_free((ptr_t)evp->str); + (void) Strncpy(s, h->cursor->ev.str, len); + s[len - 1] = '\0'; + (void) Strncat(s, str, len - Strlen(s) - 1); + h_free(evp->str); evp->str = s; *ev = h->cursor->ev; - return (0); + return 0; +} + + +private int +history_deldata_nth(history_t *h, TYPE(HistEvent) *ev, + int num, void **data) +{ + if (history_set_nth(h, ev, num) != 0) + return -1; + /* magic value to skip delete (just set to n-th history) */ + if (data == (void **)-1) + return 0; + ev->str = Strdup(h->cursor->ev.str); + ev->num = h->cursor->ev.num; + if (data) + *data = h->cursor->data; + history_def_delete(h, ev, h->cursor); + return 0; } @@ -372,16 +421,16 @@ history_def_add(ptr_t p, HistEvent *ev, const char *str) */ /* ARGSUSED */ private int -history_def_del(ptr_t p, HistEvent *ev __attribute__((__unused__)), +history_def_del(void *p, TYPE(HistEvent) *ev __attribute__((__unused__)), const int num) { history_t *h = (history_t *) p; if (history_def_set(h, ev, num) != 0) - return (-1); - ev->str = strdup(h->cursor->ev.str); + return -1; + ev->str = Strdup(h->cursor->ev.str); ev->num = h->cursor->ev.num; history_def_delete(h, ev, h->cursor); - return (0); + return 0; } @@ -391,16 +440,19 @@ history_def_del(ptr_t p, HistEvent *ev __attribute__((__unused__)), /* ARGSUSED */ private void history_def_delete(history_t *h, - HistEvent *ev __attribute__((__unused__)), hentry_t *hp) + TYPE(HistEvent) *ev __attribute__((__unused__)), hentry_t *hp) { HistEventPrivate *evp = (void *)&hp->ev; if (hp == &h->list) abort(); - if (h->cursor == hp) + if (h->cursor == hp) { h->cursor = hp->prev; + if (h->cursor == &h->list) + h->cursor = hp->next; + } hp->prev->next = hp->next; hp->next->prev = hp->prev; - h_free((ptr_t) evp->str); + h_free(evp->str); h_free(hp); h->cur--; } @@ -410,28 +462,31 @@ history_def_delete(history_t *h, * Insert element with string str in the h list */ private int -history_def_insert(history_t *h, HistEvent *ev, const char *str) +history_def_insert(history_t *h, TYPE(HistEvent) *ev, const Char *str) { + hentry_t *c; - h->cursor = (hentry_t *) h_malloc(sizeof(hentry_t)); - if (h->cursor == NULL) + c = h_malloc(sizeof(*c)); + if (c == NULL) goto oomem; - if ((h->cursor->ev.str = h_strdup(str)) == NULL) { - h_free((ptr_t)h->cursor); + if ((c->ev.str = h_strdup(str)) == NULL) { + h_free(c); goto oomem; } - h->cursor->ev.num = ++h->eventid; - h->cursor->next = h->list.next; - h->cursor->prev = &h->list; - h->list.next->prev = h->cursor; - h->list.next = h->cursor; + c->data = NULL; + c->ev.num = ++h->eventid; + c->next = h->list.next; + c->prev = &h->list; + h->list.next->prev = c; + h->list.next = c; h->cur++; + h->cursor = c; - *ev = h->cursor->ev; - return (0); + *ev = c->ev; + return 0; oomem: he_seterrev(ev, _HE_MALLOC_FAILED); - return (-1); + return -1; } @@ -439,16 +494,16 @@ oomem: * Default function to enter an item in the history */ private int -history_def_enter(ptr_t p, HistEvent *ev, const char *str) +history_def_enter(void *p, TYPE(HistEvent) *ev, const Char *str) { history_t *h = (history_t *) p; if ((h->flags & H_UNIQUE) != 0 && h->list.next != &h->list && - strcmp(h->list.next->ev.str, str) == 0) - return (0); + Strcmp(h->list.next->ev.str, str) == 0) + return 0; if (history_def_insert(h, ev, str) == -1) - return (-1); /* error, keep error message */ + return -1; /* error, keep error message */ /* * Always keep at least one entry. @@ -457,7 +512,7 @@ history_def_enter(ptr_t p, HistEvent *ev, const char *str) while (h->cur > h->max && h->cur > 0) history_def_delete(h, ev, h->list.prev); - return (1); + return 1; } @@ -466,9 +521,9 @@ history_def_enter(ptr_t p, HistEvent *ev, const char *str) */ /* ARGSUSED */ private int -history_def_init(ptr_t *p, HistEvent *ev __attribute__((__unused__)), int n) +history_def_init(void **p, TYPE(HistEvent) *ev __attribute__((__unused__)), int n) { - history_t *h = (history_t *) h_malloc(sizeof(history_t)); + history_t *h = (history_t *) h_malloc(sizeof(*h)); if (h == NULL) return -1; @@ -482,7 +537,7 @@ history_def_init(ptr_t *p, HistEvent *ev __attribute__((__unused__)), int n) h->list.ev.num = 0; h->cursor = &h->list; h->flags = 0; - *p = (ptr_t) h; + *p = h; return 0; } @@ -491,12 +546,13 @@ history_def_init(ptr_t *p, HistEvent *ev __attribute__((__unused__)), int n) * Default history cleanup function */ private void -history_def_clear(ptr_t p, HistEvent *ev) +history_def_clear(void *p, TYPE(HistEvent) *ev) { history_t *h = (history_t *) p; while (h->list.prev != &h->list) history_def_delete(h, ev, h->list.prev); + h->cursor = &h->list; h->eventid = 0; h->cur = 0; } @@ -509,16 +565,16 @@ history_def_clear(ptr_t p, HistEvent *ev) /* history_init(): * Initialization function. */ -public History * -history_init(void) +public TYPE(History) * +FUN(history,init)(void) { - HistEvent ev; - History *h = (History *) h_malloc(sizeof(History)); + TYPE(HistEvent) ev; + TYPE(History) *h = (TYPE(History) *) h_malloc(sizeof(*h)); if (h == NULL) return NULL; if (history_def_init(&h->h_ref, &ev, 0) == -1) { - h_free((ptr_t)h); + h_free(h); return NULL; } h->h_ent = -1; @@ -533,7 +589,7 @@ history_init(void) h->h_add = history_def_add; h->h_del = history_def_del; - return (h); + return h; } @@ -541,9 +597,9 @@ history_init(void) * clean up history; */ public void -history_end(History *h) +FUN(history,end)(TYPE(History) *h) { - HistEvent ev; + TYPE(HistEvent) ev; if (h->h_next == history_def_next) history_def_clear(h->h_ref, &ev); @@ -557,19 +613,19 @@ history_end(History *h) * Set history number of events */ private int -history_setsize(History *h, HistEvent *ev, int num) +history_setsize(TYPE(History) *h, TYPE(HistEvent) *ev, int num) { if (h->h_next != history_def_next) { he_seterrev(ev, _HE_NOT_ALLOWED); - return (-1); + return -1; } if (num < 0) { he_seterrev(ev, _HE_BAD_PARAM); - return (-1); + return -1; } history_def_setsize(h->h_ref, num); - return (0); + return 0; } @@ -577,18 +633,18 @@ history_setsize(History *h, HistEvent *ev, int num) * Get number of events currently in history */ private int -history_getsize(History *h, HistEvent *ev) +history_getsize(TYPE(History) *h, TYPE(HistEvent) *ev) { if (h->h_next != history_def_next) { he_seterrev(ev, _HE_NOT_ALLOWED); - return (-1); + return -1; } ev->num = history_def_getsize(h->h_ref); if (ev->num < -1) { he_seterrev(ev, _HE_SIZE_NEGATIVE); - return (-1); + return -1; } - return (0); + return 0; } @@ -596,15 +652,15 @@ history_getsize(History *h, HistEvent *ev) * Set if adjacent equal events should not be entered in history. */ private int -history_setunique(History *h, HistEvent *ev, int uni) +history_setunique(TYPE(History) *h, TYPE(HistEvent) *ev, int uni) { if (h->h_next != history_def_next) { he_seterrev(ev, _HE_NOT_ALLOWED); - return (-1); + return -1; } history_def_setunique(h->h_ref, uni); - return (0); + return 0; } @@ -612,14 +668,14 @@ history_setunique(History *h, HistEvent *ev, int uni) * Get if adjacent equal events should not be entered in history. */ private int -history_getunique(History *h, HistEvent *ev) +history_getunique(TYPE(History) *h, TYPE(HistEvent) *ev) { if (h->h_next != history_def_next) { he_seterrev(ev, _HE_NOT_ALLOWED); - return (-1); + return -1; } ev->num = history_def_getunique(h->h_ref); - return (0); + return 0; } @@ -627,9 +683,9 @@ history_getunique(History *h, HistEvent *ev) * Set history functions */ private int -history_set_fun(History *h, History *nh) +history_set_fun(TYPE(History) *h, TYPE(History) *nh) { - HistEvent ev; + TYPE(HistEvent) ev; if (nh->h_first == NULL || nh->h_next == NULL || nh->h_last == NULL || nh->h_prev == NULL || nh->h_curr == NULL || nh->h_set == NULL || @@ -648,7 +704,7 @@ history_set_fun(History *h, History *nh) h->h_add = history_def_add; h->h_del = history_def_del; } - return (-1); + return -1; } if (h->h_next == history_def_next) history_def_clear(h->h_ref, &ev); @@ -665,25 +721,28 @@ history_set_fun(History *h, History *nh) h->h_add = nh->h_add; h->h_del = nh->h_del; - return (0); + return 0; } /* history_load(): - * History load function + * TYPE(History) load function */ private int -history_load(History *h, const char *fname) +history_load(TYPE(History) *h, const char *fname) { FILE *fp; char *line; size_t sz, max_size; char *ptr; int i = -1; - HistEvent ev; + TYPE(HistEvent) ev; +#ifdef WIDECHAR + static ct_buffer_t conv; +#endif if ((fp = fopen(fname, "r")) == NULL) - return (i); + return i; if ((line = fgetln(fp, &sz)) == NULL) goto done; @@ -691,7 +750,7 @@ history_load(History *h, const char *fname) if (strncmp(line, hist_cookie, sz) != 0) goto done; - ptr = h_malloc(max_size = 1024); + ptr = h_malloc((max_size = 1024) * sizeof(*ptr)); if (ptr == NULL) goto done; for (i = 0; (line = fgetln(fp, &sz)) != NULL; i++) { @@ -704,8 +763,8 @@ history_load(History *h, const char *fname) if (max_size < sz) { char *nptr; - max_size = (sz + 1024) & ~1023; - nptr = h_realloc(ptr, max_size); + max_size = (sz + 1024) & (size_t)~1023; + nptr = h_realloc(ptr, max_size * sizeof(*ptr)); if (nptr == NULL) { i = -1; goto oomem; @@ -714,63 +773,68 @@ history_load(History *h, const char *fname) } (void) strunvis(ptr, line); line[sz] = c; - if (HENTER(h, &ev, ptr) == -1) { + if (HENTER(h, &ev, ct_decode_string(ptr, &conv)) == -1) { i = -1; goto oomem; } } oomem: - h_free((ptr_t)ptr); + h_free(ptr); done: (void) fclose(fp); - return (i); + return i; } /* history_save(): - * History save function + * TYPE(History) save function */ private int -history_save(History *h, const char *fname) +history_save(TYPE(History) *h, const char *fname) { FILE *fp; - HistEvent ev; + TYPE(HistEvent) ev; int i = -1, retval; size_t len, max_size; char *ptr; + const char *str; +#ifdef WIDECHAR + static ct_buffer_t conv; +#endif if ((fp = fopen(fname, "w")) == NULL) - return (-1); + return -1; if (fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1) goto done; if (fputs(hist_cookie, fp) == EOF) goto done; - ptr = h_malloc(max_size = 1024); + ptr = h_malloc((max_size = 1024) * sizeof(*ptr)); if (ptr == NULL) goto done; for (i = 0, retval = HLAST(h, &ev); retval != -1; retval = HPREV(h, &ev), i++) { - len = strlen(ev.str) * 4; + str = ct_encode_string(ev.str, &conv); + len = strlen(str) * 4; if (len >= max_size) { char *nptr; - max_size = (len + 1024) & ~1023; - nptr = h_realloc(ptr, max_size); + max_size = (len + 1024) & (size_t)~1023; + nptr = h_realloc(ptr, max_size * sizeof(*ptr)); if (nptr == NULL) { i = -1; goto oomem; } ptr = nptr; } - (void) strvis(ptr, ev.str, VIS_WHITE); + (void) strvis(ptr, str, VIS_WHITE); (void) fprintf(fp, "%s\n", ptr); } oomem: - h_free((ptr_t)ptr); + h_free(ptr); done: (void) fclose(fp); - return (i); + return i; } @@ -778,16 +842,33 @@ done: * Find the previous event, with number given */ private int -history_prev_event(History *h, HistEvent *ev, int num) +history_prev_event(TYPE(History) *h, TYPE(HistEvent) *ev, int num) { int retval; for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev)) if (ev->num == num) - return (0); + return 0; he_seterrev(ev, _HE_NOT_FOUND); - return (-1); + return -1; +} + + +private int +history_next_evdata(TYPE(History) *h, TYPE(HistEvent) *ev, int num, void **d) +{ + int retval; + + for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev)) + if (ev->num == num) { + if (d) + *d = ((history_t *)h->h_ref)->cursor->data; + return 0; + } + + he_seterrev(ev, _HE_NOT_FOUND); + return -1; } @@ -795,16 +876,16 @@ history_prev_event(History *h, HistEvent *ev, int num) * Find the next event, with number given */ private int -history_next_event(History *h, HistEvent *ev, int num) +history_next_event(TYPE(History) *h, TYPE(HistEvent) *ev, int num) { int retval; for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev)) if (ev->num == num) - return (0); + return 0; he_seterrev(ev, _HE_NOT_FOUND); - return (-1); + return -1; } @@ -812,17 +893,17 @@ history_next_event(History *h, HistEvent *ev, int num) * Find the previous event beginning with string */ private int -history_prev_string(History *h, HistEvent *ev, const char *str) +history_prev_string(TYPE(History) *h, TYPE(HistEvent) *ev, const Char *str) { - size_t len = strlen(str); + size_t len = Strlen(str); int retval; for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev)) - if (strncmp(str, ev->str, len) == 0) - return (0); + if (Strncmp(str, ev->str, len) == 0) + return 0; he_seterrev(ev, _HE_NOT_FOUND); - return (-1); + return -1; } @@ -830,17 +911,17 @@ history_prev_string(History *h, HistEvent *ev, const char *str) * Find the next event beginning with string */ private int -history_next_string(History *h, HistEvent *ev, const char *str) +history_next_string(TYPE(History) *h, TYPE(HistEvent) *ev, const Char *str) { - size_t len = strlen(str); + size_t len = Strlen(str); int retval; for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev)) - if (strncmp(str, ev->str, len) == 0) - return (0); + if (Strncmp(str, ev->str, len) == 0) + return 0; he_seterrev(ev, _HE_NOT_FOUND); - return (-1); + return -1; } @@ -848,10 +929,10 @@ history_next_string(History *h, HistEvent *ev, const char *str) * User interface to history functions. */ int -history(History *h, HistEvent *ev, int fun, ...) +FUNW(history)(TYPE(History) *h, TYPE(HistEvent) *ev, int fun, ...) { va_list va; - const char *str; + const Char *str; int retval; va_start(va, fun); @@ -876,7 +957,7 @@ history(History *h, HistEvent *ev, int fun, ...) break; case H_ADD: - str = va_arg(va, const char *); + str = va_arg(va, const Char *); retval = HADD(h, ev, str); break; @@ -885,13 +966,13 @@ history(History *h, HistEvent *ev, int fun, ...) break; case H_ENTER: - str = va_arg(va, const char *); + str = va_arg(va, const Char *); if ((retval = HENTER(h, ev, str)) != -1) h->h_ent = ev->num; break; case H_APPEND: - str = va_arg(va, const char *); + str = va_arg(va, const Char *); if ((retval = HSET(h, ev, h->h_ent)) != -1) retval = HADD(h, ev, str); break; @@ -946,18 +1027,18 @@ history(History *h, HistEvent *ev, int fun, ...) break; case H_PREV_STR: - retval = history_prev_string(h, ev, va_arg(va, const char *)); + retval = history_prev_string(h, ev, va_arg(va, const Char *)); break; case H_NEXT_STR: - retval = history_next_string(h, ev, va_arg(va, const char *)); + retval = history_next_string(h, ev, va_arg(va, const Char *)); break; case H_FUNC: { - History hf; + TYPE(History) hf; - hf.h_ref = va_arg(va, ptr_t); + hf.h_ref = va_arg(va, void *); h->h_ent = -1; hf.h_first = va_arg(va, history_gfun_t); hf.h_next = va_arg(va, history_gfun_t); @@ -976,15 +1057,46 @@ history(History *h, HistEvent *ev, int fun, ...) } case H_END: - history_end(h); + FUN(history,end)(h); retval = 0; break; + case H_NEXT_EVDATA: + { + int num = va_arg(va, int); + void **d = va_arg(va, void **); + retval = history_next_evdata(h, ev, num, d); + break; + } + + case H_DELDATA: + { + int num = va_arg(va, int); + void **d = va_arg(va, void **); + retval = history_deldata_nth((history_t *)h->h_ref, ev, num, d); + break; + } + + case H_REPLACE: /* only use after H_NEXT_EVDATA */ + { + const Char *line = va_arg(va, const Char *); + void *d = va_arg(va, void *); + const Char *s; + if(!line || !(s = Strdup(line))) { + retval = -1; + break; + } + ((history_t *)h->h_ref)->cursor->ev.str = s; + ((history_t *)h->h_ref)->cursor->data = d; + retval = 0; + break; + } + default: retval = -1; he_seterrev(ev, _HE_UNKNOWN); break; } va_end(va); - return (retval); + return retval; } diff --git a/cmd-line-utils/libedit/historyn.c b/cmd-line-utils/libedit/historyn.c new file mode 100644 index 00000000000..99871ea2075 --- /dev/null +++ b/cmd-line-utils/libedit/historyn.c @@ -0,0 +1,5 @@ +#define NARROW_WRAPPER +#include "config.h" +#undef WIDECHAR +#define NARROWCHAR +#include "./history.c" diff --git a/cmd-line-utils/libedit/key.c b/cmd-line-utils/libedit/keymacro.c similarity index 55% rename from cmd-line-utils/libedit/key.c rename to cmd-line-utils/libedit/keymacro.c index cda02816861..8df60e85d6c 100644 --- a/cmd-line-utils/libedit/key.c +++ b/cmd-line-utils/libedit/keymacro.c @@ -1,4 +1,4 @@ -/* $NetBSD: key.c,v 1.19 2006/03/23 20:22:51 christos Exp $ */ +/* $NetBSD: keymacro.c,v 1.7 2011/08/16 16:25:15 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -41,20 +41,21 @@ static char sccsid[] = "@(#)key.c 8.1 (Berkeley) 6/4/93"; #endif /* not lint && not SCCSID */ /* - * key.c: This module contains the procedures for maintaining - * the extended-key map. + * keymacro.c: This module contains the procedures for maintaining + * the extended-key map. * * An extended-key (key) is a sequence of keystrokes introduced * with a sequence introducer and consisting of an arbitrary - * number of characters. This module maintains a map (the el->el_key.map) + * number of characters. This module maintains a map (the + * el->el_keymacro.map) * to convert these extended-key sequences into input strs * (XK_STR), editor functions (XK_CMD), or unix commands (XK_EXE). * * Warning: * If key is a substr of some other keys, then the longer * keys are lost!! That is, if the keys "abcd" and "abcef" - * are in el->el_key.map, adding the key "abc" will cause the first two - * definitions to be lost. + * are in el->el_keymacro.map, adding the key "abc" will cause + * the first two definitions to be lost. * * Restrictions: * ------------- @@ -67,102 +68,104 @@ static char sccsid[] = "@(#)key.c 8.1 (Berkeley) 6/4/93"; #include "el.h" /* - * The Nodes of the el->el_key.map. The el->el_key.map is a linked list - * of these node elements + * The Nodes of the el->el_keymacro.map. The el->el_keymacro.map is a + * linked list of these node elements */ -struct key_node_t { - char ch; /* single character of key */ - int type; /* node type */ - key_value_t val; /* command code or pointer to str, */ +struct keymacro_node_t { + Char ch; /* single character of key */ + int type; /* node type */ + keymacro_value_t val; /* command code or pointer to str, */ /* if this is a leaf */ - struct key_node_t *next; /* ptr to next char of this key */ - struct key_node_t *sibling; /* ptr to another key with same prefix*/ + struct keymacro_node_t *next; /* ptr to next char of this key */ + struct keymacro_node_t *sibling;/* ptr to another key with same prefix*/ }; -private int node_trav(EditLine *, key_node_t *, char *, - key_value_t *); -private int node__try(EditLine *, key_node_t *, const char *, - key_value_t *, int); -private key_node_t *node__get(int); -private void node__free(key_node_t *); -private void node__put(EditLine *, key_node_t *); -private int node__delete(EditLine *, key_node_t **, const char *); -private int node_lookup(EditLine *, const char *, key_node_t *, - int); -private int node_enum(EditLine *, key_node_t *, int); +private int node_trav(EditLine *, keymacro_node_t *, Char *, + keymacro_value_t *); +private int node__try(EditLine *, keymacro_node_t *, const Char *, + keymacro_value_t *, int); +private keymacro_node_t *node__get(Int); +private void node__free(keymacro_node_t *); +private void node__put(EditLine *, keymacro_node_t *); +private int node__delete(EditLine *, keymacro_node_t **, + const Char *); +private int node_lookup(EditLine *, const Char *, + keymacro_node_t *, size_t); +private int node_enum(EditLine *, keymacro_node_t *, size_t); #define KEY_BUFSIZ EL_BUFSIZ -/* key_init(): +/* keymacro_init(): * Initialize the key maps */ protected int -key_init(EditLine *el) +keymacro_init(EditLine *el) { - el->el_key.buf = (char *) el_malloc(KEY_BUFSIZ); - if (el->el_key.buf == NULL) - return (-1); - el->el_key.map = NULL; - key_reset(el); - return (0); + el->el_keymacro.buf = el_malloc(KEY_BUFSIZ * + sizeof(*el->el_keymacro.buf)); + if (el->el_keymacro.buf == NULL) + return -1; + el->el_keymacro.map = NULL; + keymacro_reset(el); + return 0; } -/* key_end(): +/* keymacro_end(): * Free the key maps */ protected void -key_end(EditLine *el) +keymacro_end(EditLine *el) { - el_free((ptr_t) el->el_key.buf); - el->el_key.buf = NULL; - node__free(el->el_key.map); + el_free(el->el_keymacro.buf); + el->el_keymacro.buf = NULL; + node__free(el->el_keymacro.map); } -/* key_map_cmd(): +/* keymacro_map_cmd(): * Associate cmd with a key value */ -protected key_value_t * -key_map_cmd(EditLine *el, int cmd) +protected keymacro_value_t * +keymacro_map_cmd(EditLine *el, int cmd) { - el->el_key.val.cmd = (el_action_t) cmd; - return (&el->el_key.val); + el->el_keymacro.val.cmd = (el_action_t) cmd; + return &el->el_keymacro.val; } -/* key_map_str(): +/* keymacro_map_str(): * Associate str with a key value */ -protected key_value_t * -key_map_str(EditLine *el, char *str) +protected keymacro_value_t * +keymacro_map_str(EditLine *el, Char *str) { - el->el_key.val.str = str; - return (&el->el_key.val); + el->el_keymacro.val.str = str; + return &el->el_keymacro.val; } -/* key_reset(): - * Takes all nodes on el->el_key.map and puts them on free list. Then - * initializes el->el_key.map with arrow keys +/* keymacro_reset(): + * Takes all nodes on el->el_keymacro.map and puts them on free list. + * Then initializes el->el_keymacro.map with arrow keys * [Always bind the ansi arrow keys?] */ protected void -key_reset(EditLine *el) +keymacro_reset(EditLine *el) { - node__put(el, el->el_key.map); - el->el_key.map = NULL; + node__put(el, el->el_keymacro.map); + el->el_keymacro.map = NULL; return; } -/* key_get(): - * Calls the recursive function with entry point el->el_key.map +/* keymacro_get(): + * Calls the recursive function with entry point el->el_keymacro.map * Looks up *ch in map and then reads characters until a * complete match is found or a mismatch occurs. Returns the * type of the match found (XK_STR, XK_CMD, or XK_EXE). @@ -170,98 +173,101 @@ key_reset(EditLine *el) * The last character read is returned in *ch. */ protected int -key_get(EditLine *el, char *ch, key_value_t *val) +keymacro_get(EditLine *el, Char *ch, keymacro_value_t *val) { - return (node_trav(el, el->el_key.map, ch, val)); + return node_trav(el, el->el_keymacro.map, ch, val); } -/* key_add(): - * Adds key to the el->el_key.map and associates the value in val with it. - * If key is already is in el->el_key.map, the new code is applied to the - * existing key. Ntype specifies if code is a command, an - * out str or a unix command. +/* keymacro_add(): + * Adds key to the el->el_keymacro.map and associates the value in + * val with it. If key is already is in el->el_keymacro.map, the new + * code is applied to the existing key. Ntype specifies if code is a + * command, an out str or a unix command. */ protected void -key_add(EditLine *el, const char *key, key_value_t *val, int ntype) +keymacro_add(EditLine *el, const Char *key, keymacro_value_t *val, int ntype) { if (key[0] == '\0') { (void) fprintf(el->el_errfile, - "key_add: Null extended-key not allowed.\n"); + "keymacro_add: Null extended-key not allowed.\n"); return; } if (ntype == XK_CMD && val->cmd == ED_SEQUENCE_LEAD_IN) { (void) fprintf(el->el_errfile, - "key_add: sequence-lead-in command not allowed\n"); + "keymacro_add: sequence-lead-in command not allowed\n"); return; } - if (el->el_key.map == NULL) + if (el->el_keymacro.map == NULL) /* tree is initially empty. Set up new node to match key[0] */ - el->el_key.map = node__get(key[0]); + el->el_keymacro.map = node__get(key[0]); /* it is properly initialized */ - /* Now recurse through el->el_key.map */ - (void) node__try(el, el->el_key.map, key, val, ntype); + /* Now recurse through el->el_keymacro.map */ + (void) node__try(el, el->el_keymacro.map, key, val, ntype); return; } -/* key_clear(): +/* keymacro_clear(): * */ protected void -key_clear(EditLine *el, el_action_t *map, const char *in) +keymacro_clear(EditLine *el, el_action_t *map, const Char *in) { - +#ifdef WIDECHAR + if (*in > N_KEYS) /* can't be in the map */ + return; +#endif if ((map[(unsigned char)*in] == ED_SEQUENCE_LEAD_IN) && ((map == el->el_map.key && el->el_map.alt[(unsigned char)*in] != ED_SEQUENCE_LEAD_IN) || (map == el->el_map.alt && el->el_map.key[(unsigned char)*in] != ED_SEQUENCE_LEAD_IN))) - (void) key_delete(el, in); + (void) keymacro_delete(el, in); } -/* key_delete(): +/* keymacro_delete(): * Delete the key and all longer keys staring with key, if * they exists. */ protected int -key_delete(EditLine *el, const char *key) +keymacro_delete(EditLine *el, const Char *key) { if (key[0] == '\0') { (void) fprintf(el->el_errfile, - "key_delete: Null extended-key not allowed.\n"); - return (-1); + "keymacro_delete: Null extended-key not allowed.\n"); + return -1; } - if (el->el_key.map == NULL) - return (0); + if (el->el_keymacro.map == NULL) + return 0; - (void) node__delete(el, &el->el_key.map, key); - return (0); + (void) node__delete(el, &el->el_keymacro.map, key); + return 0; } -/* key_print(): +/* keymacro_print(): * Print the binding associated with key key. - * Print entire el->el_key.map if null + * Print entire el->el_keymacro.map if null */ protected void -key_print(EditLine *el, const char *key) +keymacro_print(EditLine *el, const Char *key) { - /* do nothing if el->el_key.map is empty and null key specified */ - if (el->el_key.map == NULL && *key == 0) + /* do nothing if el->el_keymacro.map is empty and null key specified */ + if (el->el_keymacro.map == NULL && *key == 0) return; - el->el_key.buf[0] = '"'; - if (node_lookup(el, key, el->el_key.map, 1) <= -1) + el->el_keymacro.buf[0] = '"'; + if (node_lookup(el, key, el->el_keymacro.map, (size_t)1) <= -1) /* key is not bound */ - (void) fprintf(el->el_errfile, "Unbound extended key \"%s\"\n", - key); + (void) fprintf(el->el_errfile, "Unbound extended key \"" FSTR + "\"\n", key); return; } @@ -271,34 +277,34 @@ key_print(EditLine *el, const char *key) * found. May read in more characters. */ private int -node_trav(EditLine *el, key_node_t *ptr, char *ch, key_value_t *val) +node_trav(EditLine *el, keymacro_node_t *ptr, Char *ch, keymacro_value_t *val) { if (ptr->ch == *ch) { /* match found */ if (ptr->next) { /* key not complete so get next char */ - if (el_getc(el, ch) != 1) { /* if EOF or error */ + if (FUN(el,getc)(el, ch) != 1) {/* if EOF or error */ val->cmd = ED_END_OF_FILE; - return (XK_CMD); + return XK_CMD; /* PWP: Pretend we just read an end-of-file */ } - return (node_trav(el, ptr->next, ch, val)); + return node_trav(el, ptr->next, ch, val); } else { *val = ptr->val; if (ptr->type != XK_CMD) *ch = '\0'; - return (ptr->type); + return ptr->type; } } else { /* no match found here */ if (ptr->sibling) { /* try next sibling */ - return (node_trav(el, ptr->sibling, ch, val)); + return node_trav(el, ptr->sibling, ch, val); } else { /* no next sibling -- mismatch */ val->str = NULL; - return (XK_STR); + return XK_STR; } } } @@ -308,11 +314,12 @@ node_trav(EditLine *el, key_node_t *ptr, char *ch, key_value_t *val) * Find a node that matches *str or allocate a new one */ private int -node__try(EditLine *el, key_node_t *ptr, const char *str, key_value_t *val, int ntype) +node__try(EditLine *el, keymacro_node_t *ptr, const Char *str, + keymacro_value_t *val, int ntype) { if (ptr->ch != *str) { - key_node_t *xm; + keymacro_node_t *xm; for (xm = ptr; xm->sibling != NULL; xm = xm->sibling) if (xm->sibling->ch == *str) @@ -335,7 +342,7 @@ node__try(EditLine *el, key_node_t *ptr, const char *str, key_value_t *val, int case XK_STR: case XK_EXE: if (ptr->val.str) - el_free((ptr_t) ptr->val.str); + el_free(ptr->val.str); break; default: EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", @@ -349,7 +356,7 @@ node__try(EditLine *el, key_node_t *ptr, const char *str, key_value_t *val, int break; case XK_STR: case XK_EXE: - if ((ptr->val.str = el_strdup(val->str)) == NULL) + if ((ptr->val.str = Strdup(val->str)) == NULL) return -1; break; default: @@ -362,7 +369,7 @@ node__try(EditLine *el, key_node_t *ptr, const char *str, key_value_t *val, int ptr->next = node__get(*str); /* setup new node */ (void) node__try(el, ptr->next, str, val, ntype); } - return (0); + return 0; } @@ -370,21 +377,21 @@ node__try(EditLine *el, key_node_t *ptr, const char *str, key_value_t *val, int * Delete node that matches str */ private int -node__delete(EditLine *el, key_node_t **inptr, const char *str) +node__delete(EditLine *el, keymacro_node_t **inptr, const Char *str) { - key_node_t *ptr; - key_node_t *prev_ptr = NULL; + keymacro_node_t *ptr; + keymacro_node_t *prev_ptr = NULL; ptr = *inptr; if (ptr->ch != *str) { - key_node_t *xm; + keymacro_node_t *xm; for (xm = ptr; xm->sibling != NULL; xm = xm->sibling) if (xm->sibling->ch == *str) break; if (xm->sibling == NULL) - return (0); + return 0; prev_ptr = xm; ptr = xm->sibling; } @@ -396,20 +403,20 @@ node__delete(EditLine *el, key_node_t **inptr, const char *str) prev_ptr->sibling = ptr->sibling; ptr->sibling = NULL; node__put(el, ptr); - return (1); + return 1; } else if (ptr->next != NULL && node__delete(el, &ptr->next, str) == 1) { if (ptr->next != NULL) - return (0); + return 0; if (prev_ptr == NULL) *inptr = ptr->sibling; else prev_ptr->sibling = ptr->sibling; ptr->sibling = NULL; node__put(el, ptr); - return (1); + return 1; } else { - return (0); + return 0; } } @@ -418,7 +425,7 @@ node__delete(EditLine *el, key_node_t **inptr, const char *str) * Puts a tree of nodes onto free list using free(3). */ private void -node__put(EditLine *el, key_node_t *ptr) +node__put(EditLine *el, keymacro_node_t *ptr) { if (ptr == NULL) return; @@ -436,25 +443,25 @@ node__put(EditLine *el, key_node_t *ptr) case XK_EXE: case XK_STR: if (ptr->val.str != NULL) - el_free((ptr_t) ptr->val.str); + el_free(ptr->val.str); break; default: EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", ptr->type)); break; } - el_free((ptr_t) ptr); + el_free(ptr); } /* node__get(): - * Returns pointer to a key_node_t for ch. + * Returns pointer to a keymacro_node_t for ch. */ -private key_node_t * -node__get(int ch) +private keymacro_node_t * +node__get(Int ch) { - key_node_t *ptr; + keymacro_node_t *ptr; - ptr = (key_node_t *) el_malloc((size_t) sizeof(key_node_t)); + ptr = el_malloc(sizeof(*ptr)); if (ptr == NULL) return NULL; ptr->ch = ch; @@ -462,17 +469,17 @@ node__get(int ch) ptr->val.str = NULL; ptr->next = NULL; ptr->sibling = NULL; - return (ptr); + return ptr; } private void -node__free(key_node_t *k) +node__free(keymacro_node_t *k) { if (k == NULL) return; node__free(k->sibling); node__free(k->next); - el_free((ptr_t) k); + el_free(k); } /* node_lookup(): @@ -480,37 +487,40 @@ node__free(key_node_t *k) * Print if last node */ private int -node_lookup(EditLine *el, const char *str, key_node_t *ptr, int cnt) +node_lookup(EditLine *el, const Char *str, keymacro_node_t *ptr, size_t cnt) { - int ncnt; + ssize_t used; if (ptr == NULL) - return (-1); /* cannot have null ptr */ + return -1; /* cannot have null ptr */ - if (*str == 0) { + if (!str || *str == 0) { /* no more chars in str. node_enum from here. */ (void) node_enum(el, ptr, cnt); - return (0); + return 0; } else { - /* If match put this char into el->el_key.buf. Recurse */ + /* If match put this char into el->el_keymacro.buf. Recurse */ if (ptr->ch == *str) { /* match found */ - ncnt = key__decode_char(el->el_key.buf, KEY_BUFSIZ, cnt, - (unsigned char) ptr->ch); + used = ct_visual_char(el->el_keymacro.buf + cnt, + KEY_BUFSIZ - cnt, ptr->ch); + if (used == -1) + return -1; /* ran out of buffer space */ if (ptr->next != NULL) /* not yet at leaf */ return (node_lookup(el, str + 1, ptr->next, - ncnt + 1)); + (size_t)used + cnt)); else { /* next node is null so key should be complete */ if (str[1] == 0) { - el->el_key.buf[ncnt + 1] = '"'; - el->el_key.buf[ncnt + 2] = '\0'; - key_kprint(el, el->el_key.buf, + size_t px = cnt + (size_t)used; + el->el_keymacro.buf[px] = '"'; + el->el_keymacro.buf[px + 1] = '\0'; + keymacro_kprint(el, el->el_keymacro.buf, &ptr->val, ptr->type); - return (0); + return 0; } else - return (-1); + return -1; /* mismatch -- str still has chars */ } } else { @@ -519,7 +529,7 @@ node_lookup(EditLine *el, const char *str, key_node_t *ptr, int cnt) return (node_lookup(el, str, ptr->sibling, cnt)); else - return (-1); + return -1; } } } @@ -529,68 +539,76 @@ node_lookup(EditLine *el, const char *str, key_node_t *ptr, int cnt) * Traverse the node printing the characters it is bound in buffer */ private int -node_enum(EditLine *el, key_node_t *ptr, int cnt) +node_enum(EditLine *el, keymacro_node_t *ptr, size_t cnt) { - int ncnt; + ssize_t used; if (cnt >= KEY_BUFSIZ - 5) { /* buffer too small */ - el->el_key.buf[++cnt] = '"'; - el->el_key.buf[++cnt] = '\0'; + el->el_keymacro.buf[++cnt] = '"'; + el->el_keymacro.buf[++cnt] = '\0'; (void) fprintf(el->el_errfile, "Some extended keys too long for internal print buffer"); - (void) fprintf(el->el_errfile, " \"%s...\"\n", el->el_key.buf); - return (0); + (void) fprintf(el->el_errfile, " \"" FSTR "...\"\n", + el->el_keymacro.buf); + return 0; } if (ptr == NULL) { #ifdef DEBUG_EDIT (void) fprintf(el->el_errfile, "node_enum: BUG!! Null ptr passed\n!"); #endif - return (-1); + return -1; } /* put this char at end of str */ - ncnt = key__decode_char(el->el_key.buf, KEY_BUFSIZ, cnt, - (unsigned char)ptr->ch); + used = ct_visual_char(el->el_keymacro.buf + cnt, KEY_BUFSIZ - cnt, + ptr->ch); if (ptr->next == NULL) { /* print this key and function */ - el->el_key.buf[ncnt + 1] = '"'; - el->el_key.buf[ncnt + 2] = '\0'; - key_kprint(el, el->el_key.buf, &ptr->val, ptr->type); + el->el_keymacro.buf[cnt + (size_t)used ] = '"'; + el->el_keymacro.buf[cnt + (size_t)used + 1] = '\0'; + keymacro_kprint(el, el->el_keymacro.buf, &ptr->val, ptr->type); } else - (void) node_enum(el, ptr->next, ncnt + 1); + (void) node_enum(el, ptr->next, cnt + (size_t)used); /* go to sibling if there is one */ if (ptr->sibling) (void) node_enum(el, ptr->sibling, cnt); - return (0); + return 0; } -/* key_kprint(): +/* keymacro_kprint(): * Print the specified key and its associated * function specified by val */ protected void -key_kprint(EditLine *el, const char *key, key_value_t *val, int ntype) +keymacro_kprint(EditLine *el, const Char *key, keymacro_value_t *val, int ntype) { el_bindings_t *fp; char unparsbuf[EL_BUFSIZ]; static const char fmt[] = "%-15s-> %s\n"; + mbstate_t state; + memset(&state, 0, sizeof(mbstate_t)); if (val != NULL) switch (ntype) { case XK_STR: case XK_EXE: - (void) key__decode_str(val->str, unparsbuf, + (void) keymacro__decode_str(val->str, unparsbuf, sizeof(unparsbuf), ntype == XK_STR ? "\"\"" : "[]"); - (void) fprintf(el->el_outfile, fmt, key, unparsbuf); + (void) fprintf(el->el_outfile, fmt, + ct_encode_string(key, &el->el_scratch), unparsbuf); break; case XK_CMD: for (fp = el->el_map.help; fp->name; fp++) if (val->cmd == fp->func) { + memset(&state, 0, sizeof(mbstate_t)); + wcsrtombs(unparsbuf, (const wchar_t **) &fp->name, + sizeof(unparsbuf), &state); + unparsbuf[sizeof(unparsbuf) -1] = '\0'; (void) fprintf(el->el_outfile, fmt, - key, fp->name); + ct_encode_string(key, &el->el_scratch), unparsbuf); break; } #ifdef DEBUG_KEY @@ -605,7 +623,8 @@ key_kprint(EditLine *el, const char *key, key_value_t *val, int ntype) break; } else - (void) fprintf(el->el_outfile, fmt, key, "no input"); + (void) fprintf(el->el_outfile, fmt, ct_encode_string(key, + &el->el_scratch), "no input"); } @@ -614,53 +633,17 @@ key_kprint(EditLine *el, const char *key, key_value_t *val, int ntype) *b++ = c; \ else \ b++ -/* key__decode_char(): - * Put a printable form of char in buf. - */ -protected int -key__decode_char(char *buf, int cnt, int off, int ch) -{ - char *sb = buf + off; - char *eb = buf + cnt; - char *b = sb; - if (ch == 0) { - ADDC('^'); - ADDC('@'); - return b - sb; - } - if (iscntrl(ch)) { - ADDC('^'); - if (ch == '\177') - ADDC('?'); - else - ADDC(ch | 0100); - } else if (ch == '^') { - ADDC('\\'); - ADDC('^'); - } else if (ch == '\\') { - ADDC('\\'); - ADDC('\\'); - } else if (ch == ' ' || (el_isprint(ch) && !isspace(ch))) { - ADDC(ch); - } else { - ADDC('\\'); - ADDC((((unsigned int) ch >> 6) & 7) + '0'); - ADDC((((unsigned int) ch >> 3) & 7) + '0'); - ADDC((ch & 7) + '0'); - } - return b - sb; -} - - -/* key__decode_str(): +/* keymacro__decode_str(): * Make a printable version of the ey */ -protected int -key__decode_str(const char *str, char *buf, int len, const char *sep) +protected size_t +keymacro__decode_str(const Char *str, char *buf, size_t len, const char *sep) { char *b = buf, *eb = b + len; - const char *p; + const Char *p; + mbstate_t state; + memset(&state, 0, sizeof(mbstate_t)); b = buf; if (sep[0] != '\0') { ADDC(sep[0]); @@ -668,38 +651,27 @@ key__decode_str(const char *str, char *buf, int len, const char *sep) if (*str == '\0') { ADDC('^'); ADDC('@'); - if (sep[0] != '\0' && sep[1] != '\0') { - ADDC(sep[1]); - } - goto done; + goto add_endsep; } for (p = str; *p != 0; p++) { - if (iscntrl((unsigned char) *p)) { - ADDC('^'); - if (*p == '\177') { - ADDC('?'); - } else { - ADDC(*p | 0100); - } - } else if (*p == '^' || *p == '\\') { - ADDC('\\'); - ADDC(*p); - } else if (*p == ' ' || (el_isprint((unsigned char) *p) && - !isspace((unsigned char) *p))) { - ADDC(*p); - } else { - ADDC('\\'); - ADDC((((unsigned int) *p >> 6) & 7) + '0'); - ADDC((((unsigned int) *p >> 3) & 7) + '0'); - ADDC((*p & 7) + '0'); + Char dbuf[VISUAL_WIDTH_MAX]; + Char *p2 = dbuf; + ssize_t l = ct_visual_char(dbuf, VISUAL_WIDTH_MAX, *p); + while (l-- > 0) { + ssize_t n = ct_encode_char(b, (size_t)(eb - b), *p2++, + &state); + if (n == -1) /* ran out of space */ + goto add_endsep; + else + b += n; } } +add_endsep: if (sep[0] != '\0' && sep[1] != '\0') { ADDC(sep[1]); } -done: ADDC('\0'); - if (b - buf >= len) + if ((size_t)(b - buf) >= len) buf[len - 1] = '\0'; - return b - buf; + return (size_t)(b - buf); } diff --git a/cmd-line-utils/libedit/key.h b/cmd-line-utils/libedit/keymacro.h similarity index 60% rename from cmd-line-utils/libedit/key.h rename to cmd-line-utils/libedit/keymacro.h index 9c6844e6d99..2445de5a5bc 100644 --- a/cmd-line-utils/libedit/key.h +++ b/cmd-line-utils/libedit/keymacro.h @@ -1,4 +1,4 @@ -/* $NetBSD: key.h,v 1.10 2006/03/23 20:22:51 christos Exp $ */ +/* $NetBSD: keymacro.h,v 1.2 2011/07/28 03:44:36 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -35,47 +35,42 @@ */ /* - * el.key.h: Key macro header + * el.keymacro.h: Key macro header */ -#ifndef _h_el_key -#define _h_el_key +#ifndef _h_el_keymacro +#define _h_el_keymacro -typedef union key_value_t { +typedef union keymacro_value_t { el_action_t cmd; /* If it is a command the # */ - char *str; /* If it is a string... */ -} key_value_t; + Char *str; /* If it is a string... */ +} keymacro_value_t; -typedef struct key_node_t key_node_t; +typedef struct keymacro_node_t keymacro_node_t; -typedef struct el_key_t { - char *buf; /* Key print buffer */ - key_node_t *map; /* Key map */ - key_value_t val; /* Local conversion buffer */ -} el_key_t; +typedef struct el_keymacromacro_t { + Char *buf; /* Key print buffer */ + keymacro_node_t *map; /* Key map */ + keymacro_value_t val; /* Local conversion buffer */ +} el_keymacro_t; #define XK_CMD 0 #define XK_STR 1 #define XK_NOD 2 #define XK_EXE 3 -#undef key_end -#undef key_clear -#undef key_print - -protected int key_init(EditLine *); -protected void key_end(EditLine *); -protected key_value_t *key_map_cmd(EditLine *, int); -protected key_value_t *key_map_str(EditLine *, char *); -protected void key_reset(EditLine *); -protected int key_get(EditLine *, char *, key_value_t *); -protected void key_add(EditLine *, const char *, key_value_t *, int); -protected void key_clear(EditLine *, el_action_t *, const char *); -protected int key_delete(EditLine *, const char *); -protected void key_print(EditLine *, const char *); -protected void key_kprint(EditLine *, const char *, key_value_t *, +protected int keymacro_init(EditLine *); +protected void keymacro_end(EditLine *); +protected keymacro_value_t *keymacro_map_cmd(EditLine *, int); +protected keymacro_value_t *keymacro_map_str(EditLine *, Char *); +protected void keymacro_reset(EditLine *); +protected int keymacro_get(EditLine *, Char *, keymacro_value_t *); +protected void keymacro_add(EditLine *, const Char *, keymacro_value_t *, int); +protected void keymacro_clear(EditLine *, el_action_t *, const Char *); +protected int keymacro_delete(EditLine *, const Char *); +protected void keymacro_print(EditLine *, const Char *); +protected void keymacro_kprint(EditLine *, const Char *, keymacro_value_t *, int); -protected int key__decode_str(const char *, char *, int, +protected size_t keymacro__decode_str(const Char *, char *, size_t, const char *); -protected int key__decode_char(char *, int, int, int); -#endif /* _h_el_key */ +#endif /* _h_el_keymacro */ diff --git a/cmd-line-utils/libedit/makelist.sh b/cmd-line-utils/libedit/makelist.sh index 5d25b4776c9..b1a28c32370 100644 --- a/cmd-line-utils/libedit/makelist.sh +++ b/cmd-line-utils/libedit/makelist.sh @@ -1,5 +1,5 @@ #!/bin/sh - -# $NetBSD: makelist,v 1.11 2005/10/22 16:45:03 christos Exp $ +# $NetBSD: makelist,v 1.16 2010/04/18 21:17:05 christos Exp $ # # Copyright (c) 1992, 1993 # The Regents of the University of California. All rights reserved. @@ -36,7 +36,7 @@ # makelist.sh: Automatically generate header files... AWK=@AWK@ -USAGE="Usage: $0 -h|-e|-fc|-fh|-bc|-bh|-m " +USAGE="Usage: $0 -n|-h|-e|-fc|-fh|-bc|-bh|-m " if [ "x$1" = "x" ] then @@ -53,6 +53,14 @@ case $FLAG in # generate foo.h file from foo.c # +-n) + cat << _EOF +#undef WIDECHAR +#define NARROWCHAR +#include "${FILES}" +_EOF + ;; + -h) set - `echo $FILES | sed -e 's/\\./_/g'` hdr="_h_`basename $1`" @@ -70,7 +78,7 @@ case $FLAG in # XXX: need a space between name and prototype so that -fc and -fh # parsing is much easier # - printf("protected el_action_t\t%s (EditLine *, int);\n", name); + printf("protected el_action_t\t%s (EditLine *, Int);\n", name); } } END { @@ -85,6 +93,7 @@ case $FLAG in BEGIN { printf("/* Automatically generated file, do not edit */\n"); printf("#include \"config.h\"\n#include \"el.h\"\n"); + printf("#include \"chartype.h\"\n"); printf("private const struct el_bindings_t el_func_help[] = {\n"); low = "abcdefghijklmnopqrstuvwxyz_"; high = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_"; @@ -106,18 +115,18 @@ case $FLAG in fname = fname s; } - printf(" { %-30.30s %-30.30s\n","\"" fname "\",", uname ","); + printf(" { %-30.30s %-30.30s\n","STR(\"" fname "\"),", uname ","); ok = 1; } } /^ \*/ { if (ok) { - printf(" \""); + printf(" STR(\""); for (i = 2; i < NF; i++) printf("%s ", $i); - # XXXMYSQL: support CRLF + # XXXMYSQL: support CRLF sub("\r", "", $i); - printf("%s\" },\n", $i); + printf("%s\") },\n", $i); ok = 0; } } @@ -157,7 +166,7 @@ case $FLAG in END { printf("#define\t%-30.30s\t%3d\n", "EL_NUM_FCNS", count); - printf("typedef el_action_t (*el_func_t)(EditLine *, int);"); + printf("typedef el_action_t (*el_func_t)(EditLine *, Int);"); printf("\nprotected const el_func_t* func__get(void);\n"); printf("#endif /* _h_fcns_c */\n"); }' diff --git a/cmd-line-utils/libedit/map.c b/cmd-line-utils/libedit/map.c index 693b56c82ba..946bc185437 100644 --- a/cmd-line-utils/libedit/map.c +++ b/cmd-line-utils/libedit/map.c @@ -1,4 +1,4 @@ -/* $NetBSD: map.c,v 1.24 2006/04/09 01:36:51 christos Exp $ */ +/* $NetBSD: map.c,v 1.30 2011/08/16 16:25:15 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -46,10 +46,8 @@ static char sccsid[] = "@(#)map.c 8.1 (Berkeley) 6/4/93"; #include #include "el.h" -#define N_KEYS 256 - -private void map_print_key(EditLine *, el_action_t *, const char *); -private void map_print_some_keys(EditLine *, el_action_t *, int, int); +private void map_print_key(EditLine *, el_action_t *, const Char *); +private void map_print_some_keys(EditLine *, el_action_t *, Int, Int); private void map_print_all_keys(EditLine *); private void map_init_nls(EditLine *); private void map_init_meta(EditLine *); @@ -904,26 +902,25 @@ map_init(EditLine *el) EL_ABORT((el->errfile, "Vi insert map incorrect\n")); #endif - el->el_map.alt = (el_action_t *)el_malloc(sizeof(el_action_t) * N_KEYS); + el->el_map.alt = el_malloc(sizeof(*el->el_map.alt) * N_KEYS); if (el->el_map.alt == NULL) - return (-1); - el->el_map.key = (el_action_t *)el_malloc(sizeof(el_action_t) * N_KEYS); + return -1; + el->el_map.key = el_malloc(sizeof(*el->el_map.key) * N_KEYS); if (el->el_map.key == NULL) - return (-1); + return -1; el->el_map.emacs = el_map_emacs; el->el_map.vic = el_map_vi_command; el->el_map.vii = el_map_vi_insert; - el->el_map.help = (el_bindings_t *) el_malloc(sizeof(el_bindings_t) * - EL_NUM_FCNS); + el->el_map.help = el_malloc(sizeof(*el->el_map.help) * EL_NUM_FCNS); if (el->el_map.help == NULL) - return (-1); + return -1; (void) memcpy(el->el_map.help, help__get(), - sizeof(el_bindings_t) * EL_NUM_FCNS); - el->el_map.func = (el_func_t *)el_malloc(sizeof(el_func_t) * - EL_NUM_FCNS); + sizeof(*el->el_map.help) * EL_NUM_FCNS); + el->el_map.func = el_malloc(sizeof(*el->el_map.func) * EL_NUM_FCNS); if (el->el_map.func == NULL) - return (-1); - memcpy(el->el_map.func, func__get(), sizeof(el_func_t) * EL_NUM_FCNS); + return -1; + memcpy(el->el_map.func, func__get(), sizeof(*el->el_map.func) + * EL_NUM_FCNS); el->el_map.nfunc = EL_NUM_FCNS; #ifdef VIDEFAULT @@ -931,7 +928,7 @@ map_init(EditLine *el) #else map_init_emacs(el); #endif /* VIDEFAULT */ - return (0); + return 0; } @@ -942,16 +939,16 @@ protected void map_end(EditLine *el) { - el_free((ptr_t) el->el_map.alt); + el_free(el->el_map.alt); el->el_map.alt = NULL; - el_free((ptr_t) el->el_map.key); + el_free(el->el_map.key); el->el_map.key = NULL; el->el_map.emacs = NULL; el->el_map.vic = NULL; el->el_map.vii = NULL; - el_free((ptr_t) el->el_map.help); + el_free(el->el_map.help); el->el_map.help = NULL; - el_free((ptr_t) el->el_map.func); + el_free(el->el_map.func); el->el_map.func = NULL; } @@ -967,7 +964,7 @@ map_init_nls(EditLine *el) el_action_t *map = el->el_map.key; for (i = 0200; i <= 0377; i++) - if (el_isprint(i)) + if (Isprint(i)) map[i] = ED_INSERT; } @@ -978,7 +975,7 @@ map_init_nls(EditLine *el) private void map_init_meta(EditLine *el) { - char buf[3]; + Char buf[3]; int i; el_action_t *map = el->el_map.key; el_action_t *alt = el->el_map.alt; @@ -996,7 +993,7 @@ map_init_meta(EditLine *el) } else map = alt; } - buf[0] = (char) i; + buf[0] = (Char) i; buf[2] = 0; for (i = 0200; i <= 0377; i++) switch (map[i]) { @@ -1006,7 +1003,7 @@ map_init_meta(EditLine *el) break; default: buf[1] = i & 0177; - key_add(el, buf, key_map_cmd(el, (int) map[i]), XK_CMD); + keymacro_add(el, buf, keymacro_map_cmd(el, (int) map[i]), XK_CMD); break; } map[(int) buf[0]] = ED_SEQUENCE_LEAD_IN; @@ -1028,7 +1025,7 @@ map_init_vi(EditLine *el) el->el_map.type = MAP_VI; el->el_map.current = el->el_map.key; - key_reset(el); + keymacro_reset(el); for (i = 0; i < N_KEYS; i++) { key[i] = vii[i]; @@ -1039,7 +1036,7 @@ map_init_vi(EditLine *el) map_init_nls(el); tty_bind_char(el, 1); - term_bind_arrow(el); + terminal_bind_arrow(el); } @@ -1050,14 +1047,14 @@ protected void map_init_emacs(EditLine *el) { int i; - char buf[3]; + Char buf[3]; el_action_t *key = el->el_map.key; el_action_t *alt = el->el_map.alt; const el_action_t *emacs = el->el_map.emacs; el->el_map.type = MAP_EMACS; el->el_map.current = el->el_map.key; - key_reset(el); + keymacro_reset(el); for (i = 0; i < N_KEYS; i++) { key[i] = emacs[i]; @@ -1070,10 +1067,10 @@ map_init_emacs(EditLine *el) buf[0] = CONTROL('X'); buf[1] = CONTROL('X'); buf[2] = 0; - key_add(el, buf, key_map_cmd(el, EM_EXCHANGE_MARK), XK_CMD); + keymacro_add(el, buf, keymacro_map_cmd(el, EM_EXCHANGE_MARK), XK_CMD); tty_bind_char(el, 1); - term_bind_arrow(el); + terminal_bind_arrow(el); } @@ -1081,18 +1078,18 @@ map_init_emacs(EditLine *el) * Set the editor */ protected int -map_set_editor(EditLine *el, char *editor) +map_set_editor(EditLine *el, Char *editor) { - if (strcmp(editor, "emacs") == 0) { + if (Strcmp(editor, STR("emacs")) == 0) { map_init_emacs(el); - return (0); + return 0; } - if (strcmp(editor, "vi") == 0) { + if (Strcmp(editor, STR("vi")) == 0) { map_init_vi(el); - return (0); + return 0; } - return (-1); + return -1; } @@ -1100,20 +1097,20 @@ map_set_editor(EditLine *el, char *editor) * Retrieve the editor */ protected int -map_get_editor(EditLine *el, const char **editor) +map_get_editor(EditLine *el, const Char **editor) { if (editor == NULL) - return (-1); + return -1; switch (el->el_map.type) { case MAP_EMACS: - *editor = "emacs"; - return (0); + *editor = STR("emacs"); + return 0; case MAP_VI: - *editor = "vi"; - return (0); + *editor = STR("vi"); + return 0; } - return (-1); + return -1; } @@ -1121,22 +1118,22 @@ map_get_editor(EditLine *el, const char **editor) * Print the function description for 1 key */ private void -map_print_key(EditLine *el, el_action_t *map, const char *in) +map_print_key(EditLine *el, el_action_t *map, const Char *in) { char outbuf[EL_BUFSIZ]; el_bindings_t *bp, *ep; if (in[0] == '\0' || in[1] == '\0') { - (void) key__decode_str(in, outbuf, sizeof(outbuf), ""); + (void) keymacro__decode_str(in, outbuf, sizeof(outbuf), ""); ep = &el->el_map.help[el->el_map.nfunc]; for (bp = el->el_map.help; bp < ep; bp++) if (bp->func == map[(unsigned char) *in]) { (void) fprintf(el->el_outfile, - "%s\t->\t%s\n", outbuf, bp->name); + "%s\t->\t" FSTR "\n", outbuf, bp->name); return; } } else - key_print(el, in); + keymacro_print(el, in); } @@ -1144,10 +1141,10 @@ map_print_key(EditLine *el, el_action_t *map, const char *in) * Print keys from first to last */ private void -map_print_some_keys(EditLine *el, el_action_t *map, int first, int last) +map_print_some_keys(EditLine *el, el_action_t *map, Int first, Int last) { el_bindings_t *bp, *ep; - char firstbuf[2], lastbuf[2]; + Char firstbuf[2], lastbuf[2]; char unparsbuf[EL_BUFSIZ], extrabuf[EL_BUFSIZ]; firstbuf[0] = first; @@ -1156,7 +1153,7 @@ map_print_some_keys(EditLine *el, el_action_t *map, int first, int last) lastbuf[1] = 0; if (map[first] == ED_UNASSIGNED) { if (first == last) { - (void) key__decode_str(firstbuf, unparsbuf, + (void) keymacro__decode_str(firstbuf, unparsbuf, sizeof(unparsbuf), STRQQ); (void) fprintf(el->el_outfile, "%-15s-> is undefined\n", unparsbuf); @@ -1167,17 +1164,17 @@ map_print_some_keys(EditLine *el, el_action_t *map, int first, int last) for (bp = el->el_map.help; bp < ep; bp++) { if (bp->func == map[first]) { if (first == last) { - (void) key__decode_str(firstbuf, unparsbuf, + (void) keymacro__decode_str(firstbuf, unparsbuf, sizeof(unparsbuf), STRQQ); - (void) fprintf(el->el_outfile, "%-15s-> %s\n", + (void) fprintf(el->el_outfile, "%-15s-> " FSTR "\n", unparsbuf, bp->name); } else { - (void) key__decode_str(firstbuf, unparsbuf, + (void) keymacro__decode_str(firstbuf, unparsbuf, sizeof(unparsbuf), STRQQ); - (void) key__decode_str(lastbuf, extrabuf, + (void) keymacro__decode_str(lastbuf, extrabuf, sizeof(extrabuf), STRQQ); (void) fprintf(el->el_outfile, - "%-4s to %-7s-> %s\n", + "%-4s to %-7s-> " FSTR "\n", unparsbuf, extrabuf, bp->name); } return; @@ -1185,14 +1182,14 @@ map_print_some_keys(EditLine *el, el_action_t *map, int first, int last) } #ifdef MAP_DEBUG if (map == el->el_map.key) { - (void) key__decode_str(firstbuf, unparsbuf, + (void) keymacro__decode_str(firstbuf, unparsbuf, sizeof(unparsbuf), STRQQ); (void) fprintf(el->el_outfile, "BUG!!! %s isn't bound to anything.\n", unparsbuf); (void) fprintf(el->el_outfile, "el->el_map.key[%d] == %d\n", first, el->el_map.key[first]); } else { - (void) key__decode_str(firstbuf, unparsbuf, + (void) keymacro__decode_str(firstbuf, unparsbuf, sizeof(unparsbuf), STRQQ); (void) fprintf(el->el_outfile, "BUG!!! %s isn't bound to anything.\n", unparsbuf); @@ -1233,9 +1230,9 @@ map_print_all_keys(EditLine *el) map_print_some_keys(el, el->el_map.alt, prev, i - 1); (void) fprintf(el->el_outfile, "Multi-character bindings\n"); - key_print(el, ""); + keymacro_print(el, STR("")); (void) fprintf(el->el_outfile, "Arrow key bindings\n"); - term_print_arrow(el, ""); + terminal_print_arrow(el, STR("")); } @@ -1243,21 +1240,21 @@ map_print_all_keys(EditLine *el) * Add/remove/change bindings */ protected int -map_bind(EditLine *el, int argc, const char **argv) +map_bind(EditLine *el, int argc, const Char **argv) { el_action_t *map; int ntype, rem; - const char *p; - char inbuf[EL_BUFSIZ]; - char outbuf[EL_BUFSIZ]; - const char *in = NULL; - char *out = NULL; + const Char *p; + Char inbuf[EL_BUFSIZ]; + Char outbuf[EL_BUFSIZ]; + const Char *in = NULL; + Char *out = NULL; el_bindings_t *bp, *ep; int cmd; int key; if (argv == NULL) - return (-1); + return -1; map = el->el_map.key; ntype = XK_CMD; @@ -1287,22 +1284,22 @@ map_bind(EditLine *el, int argc, const char **argv) case 'v': map_init_vi(el); - return (0); + return 0; case 'e': map_init_emacs(el); - return (0); + return 0; case 'l': ep = &el->el_map.help[el->el_map.nfunc]; for (bp = el->el_map.help; bp < ep; bp++) (void) fprintf(el->el_outfile, - "%s\n\t%s\n", + "" FSTR "\n\t" FSTR "\n", bp->name, bp->description); - return (0); + return 0; default: (void) fprintf(el->el_errfile, - "%s: Invalid switch `%c'.\n", + "" FSTR ": Invalid switch `%c'.\n", argv[0], p[1]); } else @@ -1310,40 +1307,40 @@ map_bind(EditLine *el, int argc, const char **argv) if (argv[argc] == NULL) { map_print_all_keys(el); - return (0); + return 0; } if (key) in = argv[argc++]; else if ((in = parse__string(inbuf, argv[argc++])) == NULL) { (void) fprintf(el->el_errfile, - "%s: Invalid \\ or ^ in instring.\n", + "" FSTR ": Invalid \\ or ^ in instring.\n", argv[0]); - return (-1); + return -1; } if (rem) { if (key) { - (void) term_clear_arrow(el, in); - return (-1); + (void) terminal_clear_arrow(el, in); + return -1; } if (in[1]) - (void) key_delete(el, in); + (void) keymacro_delete(el, in); else if (map[(unsigned char) *in] == ED_SEQUENCE_LEAD_IN) - (void) key_delete(el, in); + (void) keymacro_delete(el, in); else map[(unsigned char) *in] = ED_UNASSIGNED; - return (0); + return 0; } if (argv[argc] == NULL) { if (key) - term_print_arrow(el, in); + terminal_print_arrow(el, in); else map_print_key(el, map, in); - return (0); + return 0; } #ifdef notyet if (argv[argc + 1] != NULL) { - bindkey_usage(); - return (-1); + bindkeymacro_usage(); + return -1; } #endif @@ -1352,31 +1349,32 @@ map_bind(EditLine *el, int argc, const char **argv) case XK_EXE: if ((out = parse__string(outbuf, argv[argc])) == NULL) { (void) fprintf(el->el_errfile, - "%s: Invalid \\ or ^ in outstring.\n", argv[0]); - return (-1); + "" FSTR ": Invalid \\ or ^ in outstring.\n", argv[0]); + return -1; } if (key) - term_set_arrow(el, in, key_map_str(el, out), ntype); + terminal_set_arrow(el, in, keymacro_map_str(el, out), ntype); else - key_add(el, in, key_map_str(el, out), ntype); + keymacro_add(el, in, keymacro_map_str(el, out), ntype); map[(unsigned char) *in] = ED_SEQUENCE_LEAD_IN; break; case XK_CMD: if ((cmd = parse_cmd(el, argv[argc])) == -1) { (void) fprintf(el->el_errfile, - "%s: Invalid command `%s'.\n", argv[0], argv[argc]); - return (-1); + "" FSTR ": Invalid command `" FSTR "'.\n", + argv[0], argv[argc]); + return -1; } if (key) - term_set_arrow(el, in, key_map_str(el, out), ntype); + terminal_set_arrow(el, in, keymacro_map_str(el, out), ntype); else { if (in[1]) { - key_add(el, in, key_map_cmd(el, cmd), ntype); + keymacro_add(el, in, keymacro_map_cmd(el, cmd), ntype); map[(unsigned char) *in] = ED_SEQUENCE_LEAD_IN; } else { - key_clear(el, map, in); - map[(unsigned char) *in] = cmd; + keymacro_clear(el, map, in); + map[(unsigned char) *in] = (el_action_t)cmd; } } break; @@ -1385,7 +1383,7 @@ map_bind(EditLine *el, int argc, const char **argv) EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", ntype)); break; } - return (0); + return 0; } @@ -1393,29 +1391,30 @@ map_bind(EditLine *el, int argc, const char **argv) * add a user defined function */ protected int -map_addfunc(EditLine *el, const char *name, const char *help, el_func_t func) +map_addfunc(EditLine *el, const Char *name, const Char *help, el_func_t func) { void *p; - int nf = el->el_map.nfunc + 1; + size_t nf = (size_t)el->el_map.nfunc + 1; if (name == NULL || help == NULL || func == NULL) - return (-1); + return -1; - if ((p = el_realloc(el->el_map.func, nf * sizeof(el_func_t))) == NULL) - return (-1); - el->el_map.func = (el_func_t *) p; - if ((p = el_realloc(el->el_map.help, nf * sizeof(el_bindings_t))) + if ((p = el_realloc(el->el_map.func, nf * + sizeof(*el->el_map.func))) == NULL) + return -1; + el->el_map.func = p; + if ((p = el_realloc(el->el_map.help, nf * sizeof(*el->el_map.help))) == NULL) - return (-1); - el->el_map.help = (el_bindings_t *) p; + return -1; + el->el_map.help = p; - nf = el->el_map.nfunc; + nf = (size_t)el->el_map.nfunc; el->el_map.func[nf] = func; el->el_map.help[nf].name = name; - el->el_map.help[nf].func = nf; + el->el_map.help[nf].func = (int)nf; el->el_map.help[nf].description = help; el->el_map.nfunc++; - return (0); + return 0; } diff --git a/cmd-line-utils/libedit/map.h b/cmd-line-utils/libedit/map.h index 3b08f48be7a..8e0c7e4eaa1 100644 --- a/cmd-line-utils/libedit/map.h +++ b/cmd-line-utils/libedit/map.h @@ -1,4 +1,4 @@ -/* $NetBSD: map.h,v 1.8 2003/08/07 16:44:32 agc Exp $ */ +/* $NetBSD: map.h,v 1.9 2009/12/30 22:37:40 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -41,9 +41,9 @@ #define _h_el_map typedef struct el_bindings_t { /* for the "bind" shell command */ - const char *name; /* function name for bind command */ + const Char *name; /* function name for bind command */ int func; /* function numeric value */ - const char *description; /* description of function */ + const Char *description; /* description of function */ } el_bindings_t; @@ -63,13 +63,15 @@ typedef struct el_map_t { #define MAP_EMACS 0 #define MAP_VI 1 -protected int map_bind(EditLine *, int, const char **); +#define N_KEYS 256 + +protected int map_bind(EditLine *, int, const Char **); protected int map_init(EditLine *); protected void map_end(EditLine *); protected void map_init_vi(EditLine *); protected void map_init_emacs(EditLine *); -protected int map_set_editor(EditLine *, char *); -protected int map_get_editor(EditLine *, const char **); -protected int map_addfunc(EditLine *, const char *, const char *, el_func_t); +protected int map_set_editor(EditLine *, Char *); +protected int map_get_editor(EditLine *, const Char **); +protected int map_addfunc(EditLine *, const Char *, const Char *, el_func_t); #endif /* _h_el_map */ diff --git a/cmd-line-utils/libedit/np/strlcat.c b/cmd-line-utils/libedit/np/strlcat.c index 4e2897d8f35..c2ecc3d9b4f 100644 --- a/cmd-line-utils/libedit/np/strlcat.c +++ b/cmd-line-utils/libedit/np/strlcat.c @@ -24,6 +24,7 @@ #include "config.h" #endif +#include #if defined(LIBC_SCCS) && !defined(lint) #endif /* LIBC_SCCS and not lint */ diff --git a/cmd-line-utils/libedit/np/strlcpy.c b/cmd-line-utils/libedit/np/strlcpy.c index 092a9757c0f..533dbee70d4 100644 --- a/cmd-line-utils/libedit/np/strlcpy.c +++ b/cmd-line-utils/libedit/np/strlcpy.c @@ -23,6 +23,8 @@ #else #include "config.h" #endif + +#include #if defined(LIBC_SCCS) && !defined(lint) #endif /* LIBC_SCCS and not lint */ diff --git a/cmd-line-utils/libedit/np/unvis.c b/cmd-line-utils/libedit/np/unvis.c index 3c37c231ceb..3fc9fe1c9ed 100644 --- a/cmd-line-utils/libedit/np/unvis.c +++ b/cmd-line-utils/libedit/np/unvis.c @@ -1,4 +1,4 @@ -/* $NetBSD: unvis.c,v 1.28 2005/09/13 01:44:09 christos Exp $ */ +/* $NetBSD: unvis.c,v 1.36 2011/03/18 09:07:20 martin Exp $ */ /*- * Copyright (c) 1989, 1993 @@ -31,6 +31,7 @@ #include "config.h" +#include #if defined(LIBC_SCCS) && !defined(lint) #if 0 static char sccsid[] = "@(#)unvis.c 8.1 (Berkeley) 6/4/93"; @@ -38,11 +39,18 @@ static char sccsid[] = "@(#)unvis.c 8.1 (Berkeley) 6/4/93"; #endif #endif /* LIBC_SCCS and not lint */ +/* XXXMYSQL : Make compiler happy. */ +#ifdef _LIBC +#include "namespace.h" +#endif + #include #include #include +#include #include +#include #ifdef HAVE_VIS_H #include #else @@ -50,7 +58,7 @@ static char sccsid[] = "@(#)unvis.c 8.1 (Berkeley) 6/4/93"; #endif #ifdef __weak_alias -__weak_alias(strunvis,_strunvis) +__weak_alias(strnunvisx,_strnunvisx) #endif #if !HAVE_VIS @@ -64,143 +72,276 @@ __weak_alias(strunvis,_strunvis) #define S_CTRL 4 /* control char started (^) */ #define S_OCTAL2 5 /* octal digit 2 */ #define S_OCTAL3 6 /* octal digit 3 */ -#define S_HEX1 7 /* hex digit */ -#define S_HEX2 8 /* hex digit 2 */ +#define S_HEX1 7 /* http hex digit */ +#define S_HEX2 8 /* http hex digit 2 */ +#define S_MIME1 9 /* mime hex digit 1 */ +#define S_MIME2 10 /* mime hex digit 2 */ +#define S_EATCRNL 11 /* mime eating CRNL */ +#define S_AMP 12 /* seen & */ +#define S_NUMBER 13 /* collecting number */ +#define S_STRING 14 /* collecting string */ #define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7') #define xtod(c) (isdigit(c) ? (c - '0') : ((tolower(c) - 'a') + 10)) +#define XTOD(c) (isdigit(c) ? (c - '0') : ((c - 'A') + 10)) + +/* + * RFC 1866 + */ +static const struct nv { + const char *name; + uint8_t value; +} nv[] = { + { "AElig", 198 }, /* capital AE diphthong (ligature) */ + { "Aacute", 193 }, /* capital A, acute accent */ + { "Acirc", 194 }, /* capital A, circumflex accent */ + { "Agrave", 192 }, /* capital A, grave accent */ + { "Aring", 197 }, /* capital A, ring */ + { "Atilde", 195 }, /* capital A, tilde */ + { "Auml", 196 }, /* capital A, dieresis or umlaut mark */ + { "Ccedil", 199 }, /* capital C, cedilla */ + { "ETH", 208 }, /* capital Eth, Icelandic */ + { "Eacute", 201 }, /* capital E, acute accent */ + { "Ecirc", 202 }, /* capital E, circumflex accent */ + { "Egrave", 200 }, /* capital E, grave accent */ + { "Euml", 203 }, /* capital E, dieresis or umlaut mark */ + { "Iacute", 205 }, /* capital I, acute accent */ + { "Icirc", 206 }, /* capital I, circumflex accent */ + { "Igrave", 204 }, /* capital I, grave accent */ + { "Iuml", 207 }, /* capital I, dieresis or umlaut mark */ + { "Ntilde", 209 }, /* capital N, tilde */ + { "Oacute", 211 }, /* capital O, acute accent */ + { "Ocirc", 212 }, /* capital O, circumflex accent */ + { "Ograve", 210 }, /* capital O, grave accent */ + { "Oslash", 216 }, /* capital O, slash */ + { "Otilde", 213 }, /* capital O, tilde */ + { "Ouml", 214 }, /* capital O, dieresis or umlaut mark */ + { "THORN", 222 }, /* capital THORN, Icelandic */ + { "Uacute", 218 }, /* capital U, acute accent */ + { "Ucirc", 219 }, /* capital U, circumflex accent */ + { "Ugrave", 217 }, /* capital U, grave accent */ + { "Uuml", 220 }, /* capital U, dieresis or umlaut mark */ + { "Yacute", 221 }, /* capital Y, acute accent */ + { "aacute", 225 }, /* small a, acute accent */ + { "acirc", 226 }, /* small a, circumflex accent */ + { "acute", 180 }, /* acute accent */ + { "aelig", 230 }, /* small ae diphthong (ligature) */ + { "agrave", 224 }, /* small a, grave accent */ + { "amp", 38 }, /* ampersand */ + { "aring", 229 }, /* small a, ring */ + { "atilde", 227 }, /* small a, tilde */ + { "auml", 228 }, /* small a, dieresis or umlaut mark */ + { "brvbar", 166 }, /* broken (vertical) bar */ + { "ccedil", 231 }, /* small c, cedilla */ + { "cedil", 184 }, /* cedilla */ + { "cent", 162 }, /* cent sign */ + { "copy", 169 }, /* copyright sign */ + { "curren", 164 }, /* general currency sign */ + { "deg", 176 }, /* degree sign */ + { "divide", 247 }, /* divide sign */ + { "eacute", 233 }, /* small e, acute accent */ + { "ecirc", 234 }, /* small e, circumflex accent */ + { "egrave", 232 }, /* small e, grave accent */ + { "eth", 240 }, /* small eth, Icelandic */ + { "euml", 235 }, /* small e, dieresis or umlaut mark */ + { "frac12", 189 }, /* fraction one-half */ + { "frac14", 188 }, /* fraction one-quarter */ + { "frac34", 190 }, /* fraction three-quarters */ + { "gt", 62 }, /* greater than */ + { "iacute", 237 }, /* small i, acute accent */ + { "icirc", 238 }, /* small i, circumflex accent */ + { "iexcl", 161 }, /* inverted exclamation mark */ + { "igrave", 236 }, /* small i, grave accent */ + { "iquest", 191 }, /* inverted question mark */ + { "iuml", 239 }, /* small i, dieresis or umlaut mark */ + { "laquo", 171 }, /* angle quotation mark, left */ + { "lt", 60 }, /* less than */ + { "macr", 175 }, /* macron */ + { "micro", 181 }, /* micro sign */ + { "middot", 183 }, /* middle dot */ + { "nbsp", 160 }, /* no-break space */ + { "not", 172 }, /* not sign */ + { "ntilde", 241 }, /* small n, tilde */ + { "oacute", 243 }, /* small o, acute accent */ + { "ocirc", 244 }, /* small o, circumflex accent */ + { "ograve", 242 }, /* small o, grave accent */ + { "ordf", 170 }, /* ordinal indicator, feminine */ + { "ordm", 186 }, /* ordinal indicator, masculine */ + { "oslash", 248 }, /* small o, slash */ + { "otilde", 245 }, /* small o, tilde */ + { "ouml", 246 }, /* small o, dieresis or umlaut mark */ + { "para", 182 }, /* pilcrow (paragraph sign) */ + { "plusmn", 177 }, /* plus-or-minus sign */ + { "pound", 163 }, /* pound sterling sign */ + { "quot", 34 }, /* double quote */ + { "raquo", 187 }, /* angle quotation mark, right */ + { "reg", 174 }, /* registered sign */ + { "sect", 167 }, /* section sign */ + { "shy", 173 }, /* soft hyphen */ + { "sup1", 185 }, /* superscript one */ + { "sup2", 178 }, /* superscript two */ + { "sup3", 179 }, /* superscript three */ + { "szlig", 223 }, /* small sharp s, German (sz ligature) */ + { "thorn", 254 }, /* small thorn, Icelandic */ + { "times", 215 }, /* multiply sign */ + { "uacute", 250 }, /* small u, acute accent */ + { "ucirc", 251 }, /* small u, circumflex accent */ + { "ugrave", 249 }, /* small u, grave accent */ + { "uml", 168 }, /* umlaut (dieresis) */ + { "uuml", 252 }, /* small u, dieresis or umlaut mark */ + { "yacute", 253 }, /* small y, acute accent */ + { "yen", 165 }, /* yen sign */ + { "yuml", 255 }, /* small y, dieresis or umlaut mark */ +}; /* * unvis - decode characters previously encoded by vis */ int -unvis(cp, c, astate, flag) - char *cp; - int c; - int *astate, flag; +unvis(char *cp, int c, int *astate, int flag) { unsigned char uc = (unsigned char)c; + unsigned char st, ia, is, lc; + +/* + * Bottom 8 bits of astate hold the state machine state. + * Top 8 bits hold the current character in the http 1866 nv string decoding + */ +#define GS(a) ((a) & 0xff) +#define SS(a, b) (((uint32_t)(a) << 24) | (b)) +#define GI(a) ((uint32_t)(a) >> 24) _DIAGASSERT(cp != NULL); _DIAGASSERT(astate != NULL); + st = GS(*astate); if (flag & UNVIS_END) { - if (*astate == S_OCTAL2 || *astate == S_OCTAL3 - || *astate == S_HEX2) { - *astate = S_GROUND; - return (UNVIS_VALID); + switch (st) { + case S_OCTAL2: + case S_OCTAL3: + case S_HEX2: + *astate = SS(0, S_GROUND); + return UNVIS_VALID; + case S_GROUND: + return UNVIS_NOCHAR; + default: + return UNVIS_SYNBAD; } - return (*astate == S_GROUND ? UNVIS_NOCHAR : UNVIS_SYNBAD); } - switch (*astate) { + switch (st) { case S_GROUND: *cp = 0; - if (c == '\\') { - *astate = S_START; - return (0); + if ((flag & VIS_NOESCAPE) == 0 && c == '\\') { + *astate = SS(0, S_START); + return UNVIS_NOCHAR; } - if ((flag & VIS_HTTPSTYLE) && c == '%') { - *astate = S_HEX1; - return (0); + if ((flag & VIS_HTTP1808) && c == '%') { + *astate = SS(0, S_HEX1); + return UNVIS_NOCHAR; + } + if ((flag & VIS_HTTP1866) && c == '&') { + *astate = SS(0, S_AMP); + return UNVIS_NOCHAR; + } + if ((flag & VIS_MIMESTYLE) && c == '=') { + *astate = SS(0, S_MIME1); + return UNVIS_NOCHAR; } *cp = c; - return (UNVIS_VALID); + return UNVIS_VALID; case S_START: switch(c) { case '\\': *cp = c; - *astate = S_GROUND; - return (UNVIS_VALID); + *astate = SS(0, S_GROUND); + return UNVIS_VALID; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': *cp = (c - '0'); - *astate = S_OCTAL2; - return (0); + *astate = SS(0, S_OCTAL2); + return UNVIS_NOCHAR; case 'M': *cp = (char)0200; - *astate = S_META; - return (0); + *astate = SS(0, S_META); + return UNVIS_NOCHAR; case '^': - *astate = S_CTRL; - return (0); + *astate = SS(0, S_CTRL); + return UNVIS_NOCHAR; case 'n': *cp = '\n'; - *astate = S_GROUND; - return (UNVIS_VALID); + *astate = SS(0, S_GROUND); + return UNVIS_VALID; case 'r': *cp = '\r'; - *astate = S_GROUND; - return (UNVIS_VALID); + *astate = SS(0, S_GROUND); + return UNVIS_VALID; case 'b': *cp = '\b'; - *astate = S_GROUND; - return (UNVIS_VALID); + *astate = SS(0, S_GROUND); + return UNVIS_VALID; case 'a': *cp = '\007'; - *astate = S_GROUND; - return (UNVIS_VALID); + *astate = SS(0, S_GROUND); + return UNVIS_VALID; case 'v': *cp = '\v'; - *astate = S_GROUND; - return (UNVIS_VALID); + *astate = SS(0, S_GROUND); + return UNVIS_VALID; case 't': *cp = '\t'; - *astate = S_GROUND; - return (UNVIS_VALID); + *astate = SS(0, S_GROUND); + return UNVIS_VALID; case 'f': *cp = '\f'; - *astate = S_GROUND; - return (UNVIS_VALID); + *astate = SS(0, S_GROUND); + return UNVIS_VALID; case 's': *cp = ' '; - *astate = S_GROUND; - return (UNVIS_VALID); + *astate = SS(0, S_GROUND); + return UNVIS_VALID; case 'E': *cp = '\033'; - *astate = S_GROUND; - return (UNVIS_VALID); + *astate = SS(0, S_GROUND); + return UNVIS_VALID; case '\n': /* * hidden newline */ - *astate = S_GROUND; - return (UNVIS_NOCHAR); + *astate = SS(0, S_GROUND); + return UNVIS_NOCHAR; case '$': /* * hidden marker */ - *astate = S_GROUND; - return (UNVIS_NOCHAR); + *astate = SS(0, S_GROUND); + return UNVIS_NOCHAR; } - *astate = S_GROUND; - return (UNVIS_SYNBAD); + goto bad; case S_META: if (c == '-') - *astate = S_META1; + *astate = SS(0, S_META1); else if (c == '^') - *astate = S_CTRL; - else { - *astate = S_GROUND; - return (UNVIS_SYNBAD); - } - return (0); + *astate = SS(0, S_CTRL); + else + goto bad; + return UNVIS_NOCHAR; case S_META1: - *astate = S_GROUND; + *astate = SS(0, S_GROUND); *cp |= c; - return (UNVIS_VALID); + return UNVIS_VALID; case S_CTRL: if (c == '?') *cp |= 0177; else *cp |= c & 037; - *astate = S_GROUND; - return (UNVIS_VALID); + *astate = SS(0, S_GROUND); + return UNVIS_VALID; case S_OCTAL2: /* second possible octal digit */ if (isoctal(uc)) { @@ -208,102 +349,206 @@ unvis(cp, c, astate, flag) * yes - and maybe a third */ *cp = (*cp << 3) + (c - '0'); - *astate = S_OCTAL3; - return (0); + *astate = SS(0, S_OCTAL3); + return UNVIS_NOCHAR; } /* * no - done with current sequence, push back passed char */ - *astate = S_GROUND; - return (UNVIS_VALIDPUSH); + *astate = SS(0, S_GROUND); + return UNVIS_VALIDPUSH; case S_OCTAL3: /* third possible octal digit */ - *astate = S_GROUND; + *astate = SS(0, S_GROUND); if (isoctal(uc)) { *cp = (*cp << 3) + (c - '0'); - return (UNVIS_VALID); + return UNVIS_VALID; } /* * we were done, push back passed char */ - return (UNVIS_VALIDPUSH); + return UNVIS_VALIDPUSH; case S_HEX1: if (isxdigit(uc)) { *cp = xtod(uc); - *astate = S_HEX2; - return (0); + *astate = SS(0, S_HEX2); + return UNVIS_NOCHAR; } /* * no - done with current sequence, push back passed char */ - *astate = S_GROUND; - return (UNVIS_VALIDPUSH); + *astate = SS(0, S_GROUND); + return UNVIS_VALIDPUSH; case S_HEX2: *astate = S_GROUND; if (isxdigit(uc)) { *cp = xtod(uc) | (*cp << 4); - return (UNVIS_VALID); + return UNVIS_VALID; } - return (UNVIS_VALIDPUSH); + return UNVIS_VALIDPUSH; + + case S_MIME1: + if (uc == '\n' || uc == '\r') { + *astate = SS(0, S_EATCRNL); + return UNVIS_NOCHAR; + } + if (isxdigit(uc) && (isdigit(uc) || isupper(uc))) { + *cp = XTOD(uc); + *astate = SS(0, S_MIME2); + return UNVIS_NOCHAR; + } + goto bad; + + case S_MIME2: + if (isxdigit(uc) && (isdigit(uc) || isupper(uc))) { + *astate = SS(0, S_GROUND); + *cp = XTOD(uc) | (*cp << 4); + return UNVIS_VALID; + } + goto bad; + + case S_EATCRNL: + switch (uc) { + case '\r': + case '\n': + return UNVIS_NOCHAR; + case '=': + *astate = SS(0, S_MIME1); + return UNVIS_NOCHAR; + default: + *cp = uc; + *astate = SS(0, S_GROUND); + return UNVIS_VALID; + } + + case S_AMP: + *cp = 0; + if (uc == '#') { + *astate = SS(0, S_NUMBER); + return UNVIS_NOCHAR; + } + *astate = SS(0, S_STRING); + /*FALLTHROUGH*/ + + case S_STRING: + ia = *cp; /* index in the array */ + is = GI(*astate); /* index in the string */ + lc = is == 0 ? 0 : nv[ia].name[is - 1]; /* last character */ + + if (uc == ';') + uc = '\0'; + + for (; ia < __arraycount(nv); ia++) { + if (is != 0 && nv[ia].name[is - 1] != lc) + goto bad; + if (nv[ia].name[is] == uc) + break; + } + + if (ia == __arraycount(nv)) + goto bad; + + if (uc != 0) { + *cp = ia; + *astate = SS(is + 1, S_STRING); + return UNVIS_NOCHAR; + } + + *cp = nv[ia].value; + *astate = SS(0, S_GROUND); + return UNVIS_VALID; + + case S_NUMBER: + if (uc == ';') + return UNVIS_VALID; + if (!isdigit(uc)) + goto bad; + *cp += (*cp * 10) + uc - '0'; + return UNVIS_NOCHAR; default: + bad: /* * decoder in unknown state - (probably uninitialized) */ - *astate = S_GROUND; - return (UNVIS_SYNBAD); + *astate = SS(0, S_GROUND); + return UNVIS_SYNBAD; } } /* - * strunvis - decode src into dst + * strnunvisx - decode src into dst * * Number of chars decoded into dst is returned, -1 on error. * Dst is null terminated. */ int -strunvisx(dst, src, flag) - char *dst; - const char *src; - int flag; +strnunvisx(char *dst, size_t dlen, const char *src, int flag) { char c; - char *start = dst; + char t, *start = dst; int state = 0; _DIAGASSERT(src != NULL); _DIAGASSERT(dst != NULL); +#define CHECKSPACE() \ + do { \ + if (dlen-- == 0) { \ + errno = ENOSPC; \ + return -1; \ + } \ + } while (/*CONSTCOND*/0) while ((c = *src++) != '\0') { again: - switch (unvis(dst, c, &state, flag)) { + switch (unvis(&t, c, &state, flag)) { case UNVIS_VALID: - dst++; + CHECKSPACE(); + *dst++ = t; break; case UNVIS_VALIDPUSH: - dst++; + CHECKSPACE(); + *dst++ = t; goto again; case 0: case UNVIS_NOCHAR: break; + case UNVIS_SYNBAD: + errno = EINVAL; + return -1; default: - return (-1); + _DIAGASSERT(0); + errno = EINVAL; + return -1; } } - if (unvis(dst, c, &state, UNVIS_END) == UNVIS_VALID) - dst++; + if (unvis(&t, c, &state, UNVIS_END) == UNVIS_VALID) { + CHECKSPACE(); + *dst++ = t; + } + CHECKSPACE(); *dst = '\0'; - return (dst - start); + return (int)(dst - start); } int -strunvis(dst, src) - char *dst; - const char *src; +strunvisx(char *dst, const char *src, int flag) { - return strunvisx(dst, src, 0); + return strnunvisx(dst, (size_t)~0, src, flag); +} + +int +strunvis(char *dst, const char *src) +{ + return strnunvisx(dst, (size_t)~0, src, 0); +} + +int +strnunvis(char *dst, size_t dlen, const char *src) +{ + return strnunvisx(dst, dlen, src, 0); } #endif diff --git a/cmd-line-utils/libedit/np/vis.c b/cmd-line-utils/libedit/np/vis.c index 2a746274681..d18eb38e287 100644 --- a/cmd-line-utils/libedit/np/vis.c +++ b/cmd-line-utils/libedit/np/vis.c @@ -1,4 +1,4 @@ -/* $NetBSD: vis.c,v 1.38 2008/09/04 09:41:44 lukem Exp $ */ +/* $NetBSD: vis.c,v 1.44 2011/03/12 19:52:48 christos Exp $ */ /*- * Copyright (c) 1989, 1993 @@ -57,9 +57,15 @@ #include "config.h" +#include #if defined(LIBC_SCCS) && !defined(lint) #endif /* LIBC_SCCS and not lint */ +/* XXXMYSQL : Make compiler happy. */ +#ifdef _LIBC +#include "namespace.h" +#endif + #include #include @@ -68,15 +74,11 @@ #else #include "np/vis.h" #endif +#include #include #ifdef __weak_alias -__weak_alias(strsvis,_strsvis) -__weak_alias(strsvisx,_strsvisx) -__weak_alias(strvis,_strvis) __weak_alias(strvisx,_strvisx) -__weak_alias(svis,_svis) -__weak_alias(vis,_vis) #endif #if !HAVE_VIS || !HAVE_SVIS @@ -85,7 +87,7 @@ __weak_alias(vis,_vis) #include #include -static char *do_svis(char *, int, int, int, const char *); +static char *do_svis(char *, size_t *, int, int, int, const char *); #undef BELL #define BELL '\a' @@ -94,6 +96,7 @@ static char *do_svis(char *, int, int, int, const char *); #define iswhite(c) (c == ' ' || c == '\t' || c == '\n') #define issafe(c) (c == '\b' || c == BELL || c == '\r') #define xtoa(c) "0123456789abcdef"[c] +#define XTOA(c) "0123456789ABCDEF"[c] #define MAXEXTRAS 5 @@ -120,14 +123,54 @@ do { \ * This is do_hvis, for HTTP style (RFC 1808) */ static char * -do_hvis(char *dst, int c, int flag, int nextc, const char *extra) +do_hvis(char *dst, size_t *dlen, int c, int flag, int nextc, const char *extra) { - if (!isascii(c) || !isalnum(c) || strchr("$-_.+!*'(),", c) != NULL) { + + if ((isascii(c) && isalnum(c)) + /* safe */ + || c == '$' || c == '-' || c == '_' || c == '.' || c == '+' + /* extra */ + || c == '!' || c == '*' || c == '\'' || c == '(' || c == ')' + || c == ',') { + dst = do_svis(dst, dlen, c, flag, nextc, extra); + } else { + if (dlen) { + if (*dlen < 3) + return NULL; + *dlen -= 3; + } *dst++ = '%'; *dst++ = xtoa(((unsigned int)c >> 4) & 0xf); *dst++ = xtoa((unsigned int)c & 0xf); + } + + return dst; +} + +/* + * This is do_mvis, for Quoted-Printable MIME (RFC 2045) + * NB: No handling of long lines or CRLF. + */ +static char * +do_mvis(char *dst, size_t *dlen, int c, int flag, int nextc, const char *extra) +{ + if ((c != '\n') && + /* Space at the end of the line */ + ((isspace(c) && (nextc == '\r' || nextc == '\n')) || + /* Out of range */ + (!isspace(c) && (c < 33 || (c > 60 && c < 62) || c > 126)) || + /* Specific char to be escaped */ + strchr("#$@[\\]^`{|}~", c) != NULL)) { + if (dlen) { + if (*dlen < 3) + return NULL; + *dlen -= 3; + } + *dst++ = '='; + *dst++ = XTOA(((unsigned int)c >> 4) & 0xf); + *dst++ = XTOA((unsigned int)c & 0xf); } else { - dst = do_svis(dst, c, flag, nextc, extra); + dst = do_svis(dst, dlen, c, flag, nextc, extra); } return dst; } @@ -142,16 +185,28 @@ do_hvis(char *dst, int c, int flag, int nextc, const char *extra) * backslash-protected. */ static char * -do_svis(char *dst, int c, int flag, int nextc, const char *extra) +do_svis(char *dst, size_t *dlen, int c, int flag, int nextc, const char *extra) { int isextra; + size_t odlen = dlen ? *dlen : 0; + isextra = strchr(extra, c) != NULL; +#define HAVE(x) \ + do { \ + if (dlen) { \ + if (*dlen < (x)) \ + goto out; \ + *dlen -= (x); \ + } \ + } while (/*CONSTCOND*/0) if (!isextra && isascii(c) && (isgraph(c) || iswhite(c) || ((flag & VIS_SAFE) && issafe(c)))) { + HAVE(1); *dst++ = c; return dst; } if (flag & VIS_CSTYLE) { + HAVE(2); switch (c) { case '\n': *dst++ = '\\'; *dst++ = 'n'; @@ -180,6 +235,7 @@ do_svis(char *dst, int c, int flag, int nextc, const char *extra) case '\0': *dst++ = '\\'; *dst++ = '0'; if (isoctal(nextc)) { + HAVE(2); *dst++ = '0'; *dst++ = '0'; } @@ -189,57 +245,104 @@ do_svis(char *dst, int c, int flag, int nextc, const char *extra) *dst++ = '\\'; *dst++ = c; return dst; } + if (dlen) + *dlen = odlen; } } if (isextra || ((c & 0177) == ' ') || (flag & VIS_OCTAL)) { + HAVE(4); *dst++ = '\\'; *dst++ = (u_char)(((u_int32_t)(u_char)c >> 6) & 03) + '0'; *dst++ = (u_char)(((u_int32_t)(u_char)c >> 3) & 07) + '0'; *dst++ = (c & 07) + '0'; } else { - if ((flag & VIS_NOSLASH) == 0) *dst++ = '\\'; + if ((flag & VIS_NOSLASH) == 0) { + HAVE(1); + *dst++ = '\\'; + } + if (c & 0200) { + HAVE(1); c &= 0177; *dst++ = 'M'; } + if (iscntrl(c)) { + HAVE(2); *dst++ = '^'; if (c == 0177) *dst++ = '?'; else *dst++ = c + '@'; } else { + HAVE(2); *dst++ = '-'; *dst++ = c; } } return dst; +out: + *dlen = odlen; + return NULL; } +typedef char *(*visfun_t)(char *, size_t *, int, int, int, const char *); /* - * svis - visually encode characters, also encoding the characters + * Return the appropriate encoding function depending on the flags given. + */ +static visfun_t +getvisfun(int flag) +{ + if (flag & VIS_HTTPSTYLE) + return do_hvis; + if (flag & VIS_MIMESTYLE) + return do_mvis; + return do_svis; +} + +/* + * isnvis - visually encode characters, also encoding the characters * pointed to by `extra' */ -char * -svis(char *dst, int c, int flag, int nextc, const char *extra) +static char * +isnvis(char *dst, size_t *dlen, int c, int flag, int nextc, const char *extra) { char *nextra = NULL; + visfun_t f; _DIAGASSERT(dst != NULL); _DIAGASSERT(extra != NULL); MAKEEXTRALIST(flag, nextra, extra); if (!nextra) { + if (dlen && *dlen == 0) { + errno = ENOSPC; + return NULL; + } *dst = '\0'; /* can't create nextra, return "" */ return dst; } - if (flag & VIS_HTTPSTYLE) - dst = do_hvis(dst, c, flag, nextc, nextra); - else - dst = do_svis(dst, c, flag, nextc, nextra); + f = getvisfun(flag); + dst = (*f)(dst, dlen, c, flag, nextc, nextra); free(nextra); + if (dst == NULL || (dlen && *dlen == 0)) { + errno = ENOSPC; + return NULL; + } *dst = '\0'; return dst; } +char * +svis(char *dst, int c, int flag, int nextc, const char *extra) +{ + return isnvis(dst, NULL, c, flag, nextc, extra); +} + +char * +snvis(char *dst, size_t dlen, int c, int flag, int nextc, const char *extra) +{ + return isnvis(dst, &dlen, c, flag, nextc, extra); +} + /* * strsvis, strsvisx - visually encode characters from src into dst @@ -256,13 +359,14 @@ svis(char *dst, int c, int flag, int nextc, const char *extra) * Strsvisx encodes exactly len bytes from src into dst. * This is useful for encoding a block of data. */ -int -strsvis(char *dst, const char *csrc, int flag, const char *extra) +static int +istrsnvis(char *dst, size_t *dlen, const char *csrc, int flag, const char *extra) { int c; char *start; char *nextra = NULL; const unsigned char *src = (const unsigned char *)csrc; + visfun_t f; _DIAGASSERT(dst != NULL); _DIAGASSERT(src != NULL); @@ -272,52 +376,87 @@ strsvis(char *dst, const char *csrc, int flag, const char *extra) *dst = '\0'; /* can't create nextra, return "" */ return 0; } - if (flag & VIS_HTTPSTYLE) { - for (start = dst; (c = *src++) != '\0'; /* empty */) - dst = do_hvis(dst, c, flag, *src, nextra); - } else { - for (start = dst; (c = *src++) != '\0'; /* empty */) - dst = do_svis(dst, c, flag, *src, nextra); + f = getvisfun(flag); + for (start = dst; (c = *src++) != '\0'; /* empty */) { + dst = (*f)(dst, dlen, c, flag, *src, nextra); + if (dst == NULL) { + errno = ENOSPC; + return -1; + } } free(nextra); + if (dlen && *dlen == 0) { + errno = ENOSPC; + return -1; + } *dst = '\0'; - return (dst - start); + return (int)(dst - start); } +int +strsvis(char *dst, const char *csrc, int flag, const char *extra) +{ + return istrsnvis(dst, NULL, csrc, flag, extra); +} int -strsvisx(char *dst, const char *csrc, size_t len, int flag, const char *extra) +strsnvis(char *dst, size_t dlen, const char *csrc, int flag, const char *extra) +{ + return istrsnvis(dst, &dlen, csrc, flag, extra); +} + +static int +istrsnvisx(char *dst, size_t *dlen, const char *csrc, size_t len, int flag, + const char *extra) { unsigned char c; char *start; char *nextra = NULL; const unsigned char *src = (const unsigned char *)csrc; + visfun_t f; _DIAGASSERT(dst != NULL); _DIAGASSERT(src != NULL); _DIAGASSERT(extra != NULL); MAKEEXTRALIST(flag, nextra, extra); if (! nextra) { + if (dlen && *dlen == 0) { + errno = ENOSPC; + return -1; + } *dst = '\0'; /* can't create nextra, return "" */ return 0; } - if (flag & VIS_HTTPSTYLE) { - for (start = dst; len > 0; len--) { - c = *src++; - dst = do_hvis(dst, c, flag, - len > 1 ? *src : '\0', nextra); - } - } else { - for (start = dst; len > 0; len--) { - c = *src++; - dst = do_svis(dst, c, flag, - len > 1 ? *src : '\0', nextra); + f = getvisfun(flag); + for (start = dst; len > 0; len--) { + c = *src++; + dst = (*f)(dst, dlen, c, flag, len > 1 ? *src : '\0', nextra); + if (dst == NULL) { + errno = ENOSPC; + return -1; } } free(nextra); + if (dlen && *dlen == 0) { + errno = ENOSPC; + return -1; + } *dst = '\0'; - return (dst - start); + return (int)(dst - start); +} + +int +strsvisx(char *dst, const char *csrc, size_t len, int flag, const char *extra) +{ + return istrsnvisx(dst, NULL, csrc, len, flag, extra); +} + +int +strsnvisx(char *dst, size_t dlen, const char *csrc, size_t len, int flag, + const char *extra) +{ + return istrsnvisx(dst, &dlen, csrc, len, flag, extra); } #endif @@ -325,28 +464,47 @@ strsvisx(char *dst, const char *csrc, size_t len, int flag, const char *extra) /* * vis - visually encode characters */ -char * -vis(char *dst, int c, int flag, int nextc) +static char * +invis(char *dst, size_t *dlen, int c, int flag, int nextc) { char *extra = NULL; unsigned char uc = (unsigned char)c; + visfun_t f; _DIAGASSERT(dst != NULL); MAKEEXTRALIST(flag, extra, ""); if (! extra) { + if (dlen && *dlen == 0) { + errno = ENOSPC; + return NULL; + } *dst = '\0'; /* can't create extra, return "" */ return dst; } - if (flag & VIS_HTTPSTYLE) - dst = do_hvis(dst, uc, flag, nextc, extra); - else - dst = do_svis(dst, uc, flag, nextc, extra); + f = getvisfun(flag); + dst = (*f)(dst, dlen, uc, flag, nextc, extra); free(extra); + if (dst == NULL || (dlen && *dlen == 0)) { + errno = ENOSPC; + return NULL; + } *dst = '\0'; return dst; } +char * +vis(char *dst, int c, int flag, int nextc) +{ + return invis(dst, NULL, c, flag, nextc); +} + +char * +nvis(char *dst, size_t dlen, int c, int flag, int nextc) +{ + return invis(dst, &dlen, c, flag, nextc); +} + /* * strvis, strvisx - visually encode characters from src into dst @@ -358,36 +516,68 @@ vis(char *dst, int c, int flag, int nextc) * Strvisx encodes exactly len bytes from src into dst. * This is useful for encoding a block of data. */ -int -strvis(char *dst, const char *src, int flag) +static int +istrnvis(char *dst, size_t *dlen, const char *src, int flag) { char *extra = NULL; int rv; MAKEEXTRALIST(flag, extra, ""); if (!extra) { + if (dlen && *dlen == 0) { + errno = ENOSPC; + return -1; + } *dst = '\0'; /* can't create extra, return "" */ return 0; } - rv = strsvis(dst, src, flag, extra); + rv = istrsnvis(dst, dlen, src, flag, extra); free(extra); return rv; } +int +strvis(char *dst, const char *src, int flag) +{ + return istrnvis(dst, NULL, src, flag); +} + +int +strnvis(char *dst, size_t dlen, const char *src, int flag) +{ + return istrnvis(dst, &dlen, src, flag); +} + +static int +istrnvisx(char *dst, size_t *dlen, const char *src, size_t len, int flag) +{ + char *extra = NULL; + int rv; + + MAKEEXTRALIST(flag, extra, ""); + if (!extra) { + if (dlen && *dlen == 0) { + errno = ENOSPC; + return -1; + } + *dst = '\0'; /* can't create extra, return "" */ + return 0; + } + rv = istrsnvisx(dst, dlen, src, len, flag, extra); + free(extra); + return rv; +} int strvisx(char *dst, const char *src, size_t len, int flag) { - char *extra = NULL; - int rv; - - MAKEEXTRALIST(flag, extra, ""); - if (!extra) { - *dst = '\0'; /* can't create extra, return "" */ - return 0; - } - rv = strsvisx(dst, src, len, flag, extra); - free(extra); - return rv; + return istrnvisx(dst, NULL, src, len, flag); } + +int +strnvisx(char *dst, size_t dlen, const char *src, size_t len, int flag) +{ + return istrnvisx(dst, &dlen, src, len, flag); +} + #endif diff --git a/cmd-line-utils/libedit/np/vis.h b/cmd-line-utils/libedit/np/vis.h index 11f5b740e2d..324e961cd4c 100644 --- a/cmd-line-utils/libedit/np/vis.h +++ b/cmd-line-utils/libedit/np/vis.h @@ -1,4 +1,4 @@ -/* $NetBSD: vis.h,v 1.16 2005/09/13 01:44:32 christos Exp $ */ +/* $NetBSD: vis.h,v 1.19 2011/03/12 19:52:45 christos Exp $ */ /*- * Copyright (c) 1990, 1993 @@ -39,24 +39,29 @@ /* * to select alternate encoding format */ -#define VIS_OCTAL 0x01 /* use octal \ddd format */ -#define VIS_CSTYLE 0x02 /* use \[nrft0..] where appropiate */ +#define VIS_OCTAL 0x001 /* use octal \ddd format */ +#define VIS_CSTYLE 0x002 /* use \[nrft0..] where appropiate */ /* * to alter set of characters encoded (default is to encode all * non-graphic except space, tab, and newline). */ -#define VIS_SP 0x04 /* also encode space */ -#define VIS_TAB 0x08 /* also encode tab */ -#define VIS_NL 0x10 /* also encode newline */ +#define VIS_SP 0x004 /* also encode space */ +#define VIS_TAB 0x008 /* also encode tab */ +#define VIS_NL 0x010 /* also encode newline */ #define VIS_WHITE (VIS_SP | VIS_TAB | VIS_NL) -#define VIS_SAFE 0x20 /* only encode "unsafe" characters */ +#define VIS_SAFE 0x020 /* only encode "unsafe" characters */ /* * other */ -#define VIS_NOSLASH 0x40 /* inhibit printing '\' */ -#define VIS_HTTPSTYLE 0x80 /* http-style escape % HEX HEX */ +#define VIS_NOSLASH 0x040 /* inhibit printing '\' */ +#define VIS_HTTP1808 0x080 /* http-style escape % hex hex */ +#define VIS_HTTPSTYLE 0x080 /* http-style escape % hex hex */ +#define VIS_MIMESTYLE 0x100 /* mime-style escape = HEX HEX */ +#define VIS_HTTP1866 0x200 /* http-style &#num; or &string; */ +#define VIS_NOESCAPE 0x400 /* don't decode `\' */ +#define _VIS_END 0x800 /* for unvis */ /* * unvis return codes @@ -70,18 +75,41 @@ /* * unvis flags */ -#define UNVIS_END 1 /* no more characters */ +#define UNVIS_END _VIS_END /* no more characters */ +#include +/* XXXMYSQL */ +#ifndef __RENAME +#define __RENAME(x) +#endif __BEGIN_DECLS char *vis(char *, int, int, int); +char *nvis(char *, size_t, int, int, int); + char *svis(char *, int, int, int, const char *); +char *snvis(char *, size_t, int, int, int, const char *); + int strvis(char *, const char *, int); +int strnvis(char *, size_t, const char *, int); + int strsvis(char *, const char *, int, const char *); +int strsnvis(char *, size_t, const char *, int, const char *); + int strvisx(char *, const char *, size_t, int); +int strnvisx(char *, size_t, const char *, size_t, int); + int strsvisx(char *, const char *, size_t, int, const char *); +int strsnvisx(char *, size_t, const char *, size_t, int, const char *); + int strunvis(char *, const char *); +int strnunvis(char *, size_t, const char *); + int strunvisx(char *, const char *, int); -int unvis(char *, int, int *, int); +int strnunvisx(char *, size_t, const char *, int); + +#ifndef __LIBC12_SOURCE__ +int unvis(char *, int, int *, int) __RENAME(__unvis50); +#endif __END_DECLS #endif /* !_VIS_H_ */ diff --git a/cmd-line-utils/libedit/np/wcsdup.c b/cmd-line-utils/libedit/np/wcsdup.c new file mode 100644 index 00000000000..2a77375e0b7 --- /dev/null +++ b/cmd-line-utils/libedit/np/wcsdup.c @@ -0,0 +1,43 @@ +/* $NetBSD: wcsdup.c,v 1.3 2008/05/26 13:17:48 haad Exp $ */ + +/* + * Copyright (C) 2006 Aleksey Cheusov + * + * This material is provided "as is", with absolutely no warranty expressed + * or implied. Any use is at your own risk. + * + * Permission to use or copy this software for any purpose is hereby granted + * without fee. Permission to modify the code and to distribute modified + * code is also granted without any restrictions. + */ + +#ifndef HAVE_WCSDUP + +#include "config.h" + +#if defined(LIBC_SCCS) && !defined(lint) +__RCSID("$NetBSD: wcsdup.c,v 1.3 2008/05/26 13:17:48 haad Exp $"); +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include + +wchar_t * +wcsdup(const wchar_t *str) +{ + wchar_t *copy; + size_t len; + + _DIAGASSERT(str != NULL); + + len = wcslen(str) + 1; + copy = malloc(len * sizeof (wchar_t)); + + if (!copy) + return NULL; + + return wmemcpy(copy, str, len); +} + +#endif diff --git a/cmd-line-utils/libedit/parse.c b/cmd-line-utils/libedit/parse.c index 5bdefb5a0e4..b14e4ae7165 100644 --- a/cmd-line-utils/libedit/parse.c +++ b/cmd-line-utils/libedit/parse.c @@ -1,4 +1,4 @@ -/* $NetBSD: parse.c,v 1.22 2005/05/29 04:58:15 lukem Exp $ */ +/* $NetBSD: parse.c,v 1.26 2011/08/16 16:25:15 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -57,17 +57,17 @@ static char sccsid[] = "@(#)parse.c 8.1 (Berkeley) 6/4/93"; #include private const struct { - const char *name; - int (*func)(EditLine *, int, const char **); + const Char *name; + int (*func)(EditLine *, int, const Char **); } cmds[] = { - { "bind", map_bind }, - { "echotc", term_echotc }, - { "edit", el_editmode }, - { "history", hist_command }, - { "telltc", term_telltc }, - { "settc", term_settc }, - { "setty", tty_stty }, - { NULL, NULL } + { STR("bind"), map_bind }, + { STR("echotc"), terminal_echotc }, + { STR("edit"), el_editmode }, + { STR("history"), hist_command }, + { STR("telltc"), terminal_telltc }, + { STR("settc"), terminal_settc }, + { STR("setty"), tty_stty }, + { NULL, NULL } }; @@ -75,17 +75,17 @@ private const struct { * Parse a line and dispatch it */ protected int -parse_line(EditLine *el, const char *line) +parse_line(EditLine *el, const Char *line) { - const char **argv; + const Char **argv; int argc; - Tokenizer *tok; + TYPE(Tokenizer) *tok; - tok = tok_init(NULL); - tok_str(tok, line, &argc, &argv); - argc = el_parse(el, argc, argv); - tok_end(tok); - return (argc); + tok = FUN(tok,init)(NULL); + FUN(tok,str)(tok, line, &argc, &argv); + argc = FUN(el,parse)(el, argc, argv); + FUN(tok,end)(tok); + return argc; } @@ -93,57 +93,57 @@ parse_line(EditLine *el, const char *line) * Command dispatcher */ public int -el_parse(EditLine *el, int argc, const char *argv[]) +FUN(el,parse)(EditLine *el, int argc, const Char *argv[]) { - const char *ptr; + const Char *ptr; int i; if (argc < 1) - return (-1); - ptr = strchr(argv[0], ':'); + return -1; + ptr = Strchr(argv[0], ':'); if (ptr != NULL) { - char *tprog; + Char *tprog; size_t l; if (ptr == argv[0]) - return (0); - l = ptr - argv[0] - 1; - tprog = (char *) el_malloc(l + 1); + return 0; + l = (size_t)(ptr - argv[0] - 1); + tprog = el_malloc((l + 1) * sizeof(*tprog)); if (tprog == NULL) - return (0); - (void) strncpy(tprog, argv[0], l); + return 0; + (void) Strncpy(tprog, argv[0], l); tprog[l] = '\0'; ptr++; - l = el_match(el->el_prog, tprog); + l = (size_t)el_match(el->el_prog, tprog); el_free(tprog); if (!l) - return (0); + return 0; } else ptr = argv[0]; for (i = 0; cmds[i].name != NULL; i++) - if (strcmp(cmds[i].name, ptr) == 0) { + if (Strcmp(cmds[i].name, ptr) == 0) { i = (*cmds[i].func) (el, argc, argv); - return (-i); + return -i; } - return (-1); + return -1; } /* parse__escape(): - * Parse a string of the form ^ \ \ and return + * Parse a string of the form ^ \ \ \U+xxxx and return * the appropriate character or -1 if the escape is not valid */ protected int -parse__escape(const char **ptr) +parse__escape(const Char **ptr) { - const char *p; - int c; + const Char *p; + Int c; p = *ptr; if (p[1] == 0) - return (-1); + return -1; if (*p == '\\') { p++; @@ -172,6 +172,28 @@ parse__escape(const char **ptr) case 'e': c = '\033'; /* Escape */ break; + case 'U': /* Unicode \U+xxxx or \U+xxxxx format */ + { + int i; + const Char hex[] = STR("0123456789ABCDEF"); + const Char *h; + ++p; + if (*p++ != '+') + return -1; + c = 0; + for (i = 0; i < 5; ++i) { + h = Strchr(hex, *p++); + if (!h && i < 4) + return -1; + else if (h) + c = (c << 4) | ((int)(h - hex)); + else + --p; + } + if (c > 0x10FFFF) /* outside valid character range */ + return -1; + break; + } case '0': case '1': case '2': @@ -191,8 +213,8 @@ parse__escape(const char **ptr) } c = (c << 3) | (ch - '0'); } - if ((c & 0xffffff00) != 0) - return (-1); + if ((c & (wint_t)0xffffff00) != (wint_t)0) + return -1; --p; break; } @@ -206,28 +228,28 @@ parse__escape(const char **ptr) } else c = *p; *ptr = ++p; - return (c); + return c; } /* parse__string(): * Parse the escapes from in and put the raw string out */ -protected char * -parse__string(char *out, const char *in) +protected Char * +parse__string(Char *out, const Char *in) { - char *rv = out; + Char *rv = out; int n; for (;;) switch (*in) { case '\0': *out = '\0'; - return (rv); + return rv; case '\\': case '^': if ((n = parse__escape(&in)) == -1) - return (NULL); + return NULL; *out++ = n; break; @@ -251,12 +273,12 @@ parse__string(char *out, const char *in) * or -1 if one is not found */ protected int -parse_cmd(EditLine *el, const char *cmd) +parse_cmd(EditLine *el, const Char *cmd) { el_bindings_t *b; for (b = el->el_map.help; b->name != NULL; b++) - if (strcmp(b->name, cmd) == 0) - return (b->func); - return (-1); + if (Strcmp(b->name, cmd) == 0) + return b->func; + return -1; } diff --git a/cmd-line-utils/libedit/parse.h b/cmd-line-utils/libedit/parse.h index 58dced1aeaa..ec04051bc27 100644 --- a/cmd-line-utils/libedit/parse.h +++ b/cmd-line-utils/libedit/parse.h @@ -1,4 +1,4 @@ -/* $NetBSD: parse.h,v 1.6 2005/05/29 04:58:15 lukem Exp $ */ +/* $NetBSD: parse.h,v 1.7 2009/12/30 22:37:40 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -40,9 +40,9 @@ #ifndef _h_el_parse #define _h_el_parse -protected int parse_line(EditLine *, const char *); -protected int parse__escape(const char **); -protected char *parse__string(char *, const char *); -protected int parse_cmd(EditLine *, const char *); +protected int parse_line(EditLine *, const Char *); +protected int parse__escape(const Char **); +protected Char *parse__string(Char *, const Char *); +protected int parse_cmd(EditLine *, const Char *); #endif /* _h_el_parse */ diff --git a/cmd-line-utils/libedit/prompt.c b/cmd-line-utils/libedit/prompt.c index 982943afd30..3f8d73303ec 100644 --- a/cmd-line-utils/libedit/prompt.c +++ b/cmd-line-utils/libedit/prompt.c @@ -1,4 +1,4 @@ -/* $NetBSD: prompt.c,v 1.11 2003/08/07 16:44:32 agc Exp $ */ +/* $NetBSD: prompt.c,v 1.20 2011/07/29 15:16:33 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -46,54 +46,66 @@ static char sccsid[] = "@(#)prompt.c 8.1 (Berkeley) 6/4/93"; #include #include "el.h" -private char *prompt_default(EditLine *); -private char *prompt_default_r(EditLine *); +private Char *prompt_default(EditLine *); +private Char *prompt_default_r(EditLine *); /* prompt_default(): * Just a default prompt, in case the user did not provide one */ -private char * +private Char * /*ARGSUSED*/ prompt_default(EditLine *el __attribute__((__unused__))) { - static char a[3] = {'?', ' ', '\0'}; + static Char a[3] = {'?', ' ', '\0'}; - return (a); + return a; } /* prompt_default_r(): * Just a default rprompt, in case the user did not provide one */ -private char * +private Char * /*ARGSUSED*/ prompt_default_r(EditLine *el __attribute__((__unused__))) { - static char a[1] = {'\0'}; + static Char a[1] = {'\0'}; - return (a); + return a; } /* prompt_print(): * Print the prompt and update the prompt position. - * We use an array of integers in case we want to pass - * literal escape sequences in the prompt and we want a - * bit to flag them */ protected void prompt_print(EditLine *el, int op) { el_prompt_t *elp; - char *p; + Char *p; + int ignore = 0; if (op == EL_PROMPT) elp = &el->el_prompt; else elp = &el->el_rprompt; - p = (elp->p_func) (el); - while (*p) - re_putc(el, *p++, 1); + + if (elp->p_wide) + p = (*elp->p_func)(el); + else + p = ct_decode_string((char *)(void *)(*elp->p_func)(el), + &el->el_scratch); + + for (; *p; p++) { + if (elp->p_ignore == *p) { + ignore = !ignore; + continue; + } + if (ignore) + terminal__putc(el, *p); + else + re_putc(el, *p, 1); + } elp->p_pos.v = el->el_refresh.r_cursor.v; elp->p_pos.h = el->el_refresh.r_cursor.h; @@ -110,10 +122,12 @@ prompt_init(EditLine *el) el->el_prompt.p_func = prompt_default; el->el_prompt.p_pos.v = 0; el->el_prompt.p_pos.h = 0; + el->el_prompt.p_ignore = '\0'; el->el_rprompt.p_func = prompt_default_r; el->el_rprompt.p_pos.v = 0; el->el_rprompt.p_pos.h = 0; - return (0); + el->el_rprompt.p_ignore = '\0'; + return 0; } @@ -131,24 +145,31 @@ prompt_end(EditLine *el __attribute__((__unused__))) * Install a prompt printing function */ protected int -prompt_set(EditLine *el, el_pfunc_t prf, int op) +prompt_set(EditLine *el, el_pfunc_t prf, Char c, int op, int wide) { el_prompt_t *p; - if (op == EL_PROMPT) + if (op == EL_PROMPT || op == EL_PROMPT_ESC) p = &el->el_prompt; else p = &el->el_rprompt; + if (prf == NULL) { - if (op == EL_PROMPT) + if (op == EL_PROMPT || op == EL_PROMPT_ESC) p->p_func = prompt_default; else p->p_func = prompt_default_r; - } else + } else { p->p_func = prf; + } + + p->p_ignore = c; + p->p_pos.v = 0; p->p_pos.h = 0; - return (0); + p->p_wide = wide; + + return 0; } @@ -156,14 +177,22 @@ prompt_set(EditLine *el, el_pfunc_t prf, int op) * Retrieve the prompt printing function */ protected int -prompt_get(EditLine *el, el_pfunc_t *prf, int op) +prompt_get(EditLine *el, el_pfunc_t *prf, Char *c, int op) { + el_prompt_t *p; if (prf == NULL) - return (-1); + return -1; + if (op == EL_PROMPT) - *prf = el->el_prompt.p_func; + p = &el->el_prompt; else - *prf = el->el_rprompt.p_func; - return (0); + p = &el->el_rprompt; + + if (prf) + *prf = p->p_func; + if (c) + *c = p->p_ignore; + + return 0; } diff --git a/cmd-line-utils/libedit/prompt.h b/cmd-line-utils/libedit/prompt.h index d18110861f8..af63b82b684 100644 --- a/cmd-line-utils/libedit/prompt.h +++ b/cmd-line-utils/libedit/prompt.h @@ -1,4 +1,4 @@ -/* $NetBSD: prompt.h,v 1.6 2003/08/07 16:44:32 agc Exp $ */ +/* $NetBSD: prompt.h,v 1.10 2009/12/30 22:37:40 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -42,16 +42,18 @@ #include "histedit.h" -typedef char * (*el_pfunc_t)(EditLine*); +typedef Char *(*el_pfunc_t)(EditLine *); typedef struct el_prompt_t { - el_pfunc_t p_func; /* Function to return the prompt */ - coord_t p_pos; /* position in the line after prompt */ + el_pfunc_t p_func; /* Function to return the prompt */ + coord_t p_pos; /* position in the line after prompt */ + Char p_ignore; /* character to start/end literal */ + int p_wide; } el_prompt_t; protected void prompt_print(EditLine *, int); -protected int prompt_set(EditLine *, el_pfunc_t, int); -protected int prompt_get(EditLine *, el_pfunc_t *, int); +protected int prompt_set(EditLine *, el_pfunc_t, Char, int, int); +protected int prompt_get(EditLine *, el_pfunc_t *, Char *, int); protected int prompt_init(EditLine *); protected void prompt_end(EditLine *); diff --git a/cmd-line-utils/libedit/read.c b/cmd-line-utils/libedit/read.c index ac768142e79..48bf4efd59b 100644 --- a/cmd-line-utils/libedit/read.c +++ b/cmd-line-utils/libedit/read.c @@ -1,4 +1,4 @@ -/* $NetBSD: read.c,v 1.43 2009/02/05 19:15:44 christos Exp $ */ +/* $NetBSD: read.c,v 1.67 2011/08/16 16:25:15 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -48,14 +48,15 @@ static char sccsid[] = "@(#)read.c 8.1 (Berkeley) 6/4/93"; #include #include #include +#include #include "el.h" -#define OKCMD -1 +#define OKCMD -1 /* must be -1! */ private int read__fixio(int, int); private int read_preread(EditLine *); -private int read_char(EditLine *, char *); -private int read_getcmd(EditLine *, el_action_t *, char *); +private int read_char(EditLine *, Char *); +private int read_getcmd(EditLine *, el_action_t *, Char *); private void read_pop(c_macro_t *); /* read_init(): @@ -89,7 +90,7 @@ el_read_setfn(EditLine *el, el_rfunc_t rc) protected el_rfunc_t el_read_getfn(EditLine *el) { - return (el->el_read.read_char == read_char) ? + return el->el_read.read_char == read_char ? EL_BUILTIN_GETCFN : el->el_read.read_char; } @@ -131,7 +132,7 @@ read__fixio(int fd __attribute__((__unused__)), int e) #ifdef EWOULDBLOCK case EWOULDBLOCK: #ifndef TRY_AGAIN -#define TRY_AGAIN +#define TRY_AGAIN #endif #endif /* EWOULDBLOCK */ @@ -139,7 +140,7 @@ read__fixio(int fd __attribute__((__unused__)), int e) #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN case EAGAIN: #ifndef TRY_AGAIN -#define TRY_AGAIN +#define TRY_AGAIN #endif #endif /* EWOULDBLOCK && EWOULDBLOCK != EAGAIN */ #endif /* POSIX && EAGAIN */ @@ -148,10 +149,10 @@ read__fixio(int fd __attribute__((__unused__)), int e) #ifdef TRY_AGAIN #if defined(F_SETFL) && defined(O_NDELAY) if ((e = fcntl(fd, F_GETFL, 0)) == -1) - return (-1); + return -1; if (fcntl(fd, F_SETFL, e & ~O_NDELAY) == -1) - return (-1); + return -1; else e = 1; #endif /* F_SETFL && O_NDELAY */ @@ -160,21 +161,21 @@ read__fixio(int fd __attribute__((__unused__)), int e) { int zero = 0; - if (ioctl(fd, FIONBIO, (ioctl_t) & zero) == -1) - return (-1); + if (ioctl(fd, FIONBIO, &zero) == -1) + return -1; else e = 1; } #endif /* FIONBIO */ #endif /* TRY_AGAIN */ - return (e ? 0 : -1); + return e ? 0 : -1; case EINTR: - return (0); + return 0; default: - return (-1); + return -1; } } @@ -188,10 +189,13 @@ read_preread(EditLine *el) int chrs = 0; if (el->el_tty.t_mode == ED_IO) - return (0); + return 0; +#ifndef WIDECHAR +/* FIONREAD attempts to buffer up multiple bytes, and to make that work + * properly with partial wide/UTF-8 characters would need some careful work. */ #ifdef FIONREAD - (void) ioctl(el->el_infd, FIONREAD, (ioctl_t) & chrs); + (void) ioctl(el->el_infd, FIONREAD, &chrs); if (chrs > 0) { char buf[EL_BUFSIZ]; @@ -203,8 +207,8 @@ read_preread(EditLine *el) } } #endif /* FIONREAD */ - - return (chrs > 0); +#endif + return chrs > 0; } @@ -212,33 +216,37 @@ read_preread(EditLine *el) * Push a macro */ public void -el_push(EditLine *el, const char *str) +FUN(el,push)(EditLine *el, const Char *str) { c_macro_t *ma = &el->el_chared.c_macro; if (str != NULL && ma->level + 1 < EL_MAXMACRO) { ma->level++; - if ((ma->macro[ma->level] = el_strdup(str)) != NULL) + if ((ma->macro[ma->level] = Strdup(str)) != NULL) return; ma->level--; } - term_beep(el); - term__flush(el); + terminal_beep(el); + terminal__flush(el); } /* read_getcmd(): * Return next command from the input stream. + * Character values > 255 are not looked up in the map, but inserted. */ private int -read_getcmd(EditLine *el, el_action_t *cmdnum, char *ch) +read_getcmd(EditLine *el, el_action_t *cmdnum, Char *ch) { el_action_t cmd; int num; + el->el_errno = 0; do { - if ((num = el_getc(el, ch)) != 1) /* if EOF or error */ - return (num); + if ((num = FUN(el,getc)(el, ch)) != 1) {/* if EOF or error */ + el->el_errno = num == 0 ? 0 : errno; + return num; + } #ifdef KANJI if ((*ch & 0200)) { @@ -252,15 +260,20 @@ read_getcmd(EditLine *el, el_action_t *cmdnum, char *ch) el->el_state.metanext = 0; *ch |= 0200; } - cmd = el->el_map.current[(unsigned char) *ch]; +#ifdef WIDECHAR + if (*ch >= N_KEYS) + cmd = ED_INSERT; + else +#endif + cmd = el->el_map.current[(unsigned char) *ch]; if (cmd == ED_SEQUENCE_LEAD_IN) { - key_value_t val; - switch (key_get(el, ch, &val)) { + keymacro_value_t val; + switch (keymacro_get(el, ch, &val)) { case XK_CMD: cmd = val.cmd; break; case XK_STR: - el_push(el, val.str); + FUN(el,push)(el, val.str); break; #ifdef notyet case XK_EXE: @@ -277,28 +290,82 @@ read_getcmd(EditLine *el, el_action_t *cmdnum, char *ch) el->el_map.current = el->el_map.key; } while (cmd == ED_SEQUENCE_LEAD_IN); *cmdnum = cmd; - return (OKCMD); + return OKCMD; } - /* read_char(): * Read a character from the tty. */ private int -read_char(EditLine *el, char *cp) +read_char(EditLine *el, Char *cp) { - int num_read; + ssize_t num_read; int tried = 0; + char cbuf[MB_LEN_MAX]; + size_t cbp = 0; + int bytes = 0; - while ((num_read = read(el->el_infd, cp, 1)) == -1) +#ifdef WIDECHAR +static mbstate_t state, temp_state; +memset(&state, 0, sizeof(mbstate_t)); +#endif + + again: + el->el_signal->sig_no = 0; + while ((num_read = read(el->el_infd, cbuf + cbp, (size_t)1)) == -1) { + switch (el->el_signal->sig_no) { + case SIGCONT: + FUN(el,set)(el, EL_REFRESH); + /*FALLTHROUGH*/ + case SIGWINCH: + sig_set(el); + goto again; + default: + break; + } if (!tried && read__fixio(el->el_infd, errno) == 0) tried = 1; else { *cp = '\0'; - return (-1); + return -1; } + } - return (num_read); +#ifdef WIDECHAR + ++cbp; + if (cbp > MB_CUR_MAX) { /* "shouldn't happen" */ + *cp = '\0'; + return (-1); + } + + temp_state= state; + + if ((bytes = mbrtowc(cp, cbuf, cbp, &state)) == -2) + { + /* Incomplete sequence, restore the state and scan more bytes. */ + state= temp_state; + goto again; + } + else if (bytes == -1) + { + /* Invalid sequence, reset the state and continue. */ + cbp= 0; + memset(&state, 0, sizeof(mbstate_t)); + goto again; + } + /* We successfully read one single or multi-byte character */ +#else + *cp = (unsigned char)cbuf[0]; +#endif + +#if 0 + if ((el->el_flags & IGNORE_EXTCHARS) && bytes > 1) { + cbp = 0; /* skip this character */ + goto again; + } +#endif + + return (int)num_read; } /* read_pop(): @@ -310,8 +377,9 @@ read_pop(c_macro_t *ma) int i; el_free(ma->macro[0]); - for (i = ma->level--; i > 0; i--) - ma->macro[i - 1] = ma->macro[i]; + for (i = 0; i < ma->level; i++) + ma->macro[i] = ma->macro[i + 1]; + ma->level--; ma->offset = 0; } @@ -319,12 +387,12 @@ read_pop(c_macro_t *ma) * Read a character */ public int -el_getc(EditLine *el, char *cp) +FUN(el,getc)(EditLine *el, Char *cp) { int num_read; c_macro_t *ma = &el->el_chared.c_macro; - term__flush(el); + terminal__flush(el); for (;;) { if (ma->level < 0) { if (!read_preread(el)) @@ -339,30 +407,34 @@ el_getc(EditLine *el, char *cp) continue; } - *cp = ma->macro[0][ma->offset++] & 0377; + *cp = ma->macro[0][ma->offset++]; if (ma->macro[0][ma->offset] == '\0') { /* Needed for QuoteMode On */ read_pop(ma); } - return (1); + return 1; } #ifdef DEBUG_READ (void) fprintf(el->el_errfile, "Turning raw mode on\n"); #endif /* DEBUG_READ */ if (tty_rawmode(el) < 0)/* make sure the tty is set up correctly */ - return (0); + return 0; #ifdef DEBUG_READ (void) fprintf(el->el_errfile, "Reading a character\n"); #endif /* DEBUG_READ */ num_read = (*el->el_read.read_char)(el, cp); +#ifdef WIDECHAR + if (el->el_flags & NARROW_READ) + *cp = *(char *)(void *)cp; +#endif #ifdef DEBUG_READ (void) fprintf(el->el_errfile, "Got it %c\n", *cp); #endif /* DEBUG_READ */ - return (num_read); + return num_read; } protected void @@ -383,7 +455,7 @@ read_prepare(EditLine *el) re_refresh(el); /* print the prompt */ if (el->el_flags & UNBUFFERED) - term__flush(el); + terminal__flush(el); } protected void @@ -395,27 +467,32 @@ read_finish(EditLine *el) sig_clr(el); } -public const char * -el_gets(EditLine *el, int *nread) +public const Char * +FUN(el,gets)(EditLine *el, int *nread) { int retval; el_action_t cmdnum = 0; int num; /* how many chars we have read at NL */ - char ch; + Char ch, *cp; int crlf = 0; + int nrb; #ifdef FIONREAD c_macro_t *ma = &el->el_chared.c_macro; #endif /* FIONREAD */ + if (nread == NULL) + nread = &nrb; + *nread = 0; + if (el->el_flags & NO_TTY) { - char *cp = el->el_line.buffer; size_t idx; - while ((*el->el_read.read_char)(el, cp) == 1) { + cp = el->el_line.buffer; + while ((num = (*el->el_read.read_char)(el, cp)) == 1) { /* make sure there is space for next character */ if (cp + 1 >= el->el_line.limit) { - idx = (cp - el->el_line.buffer); - if (!ch_enlargebufs(el, 2)) + idx = (size_t)(cp - el->el_line.buffer); + if (!ch_enlargebufs(el, (size_t)2)) break; cp = &el->el_line.buffer[idx]; } @@ -425,12 +502,13 @@ el_gets(EditLine *el, int *nread) if (cp[-1] == '\r' || cp[-1] == '\n') break; } + if (num == -1) { + if (errno == EINTR) + cp = el->el_line.buffer; + el->el_errno = errno; + } - el->el_line.cursor = el->el_line.lastchar = cp; - *cp = '\0'; - if (nread) - *nread = el->el_line.cursor - el->el_line.buffer; - return (el->el_line.buffer); + goto noedit; } @@ -438,12 +516,12 @@ el_gets(EditLine *el, int *nread) if (el->el_tty.t_mode == EX_IO && ma->level < 0) { long chrs = 0; - (void) ioctl(el->el_infd, FIONREAD, (ioctl_t) & chrs); + (void) ioctl(el->el_infd, FIONREAD, &chrs); if (chrs == 0) { if (tty_rawmode(el) < 0) { - if (nread) - *nread = 0; - return (NULL); + errno = 0; + *nread = 0; + return NULL; } } } @@ -453,25 +531,23 @@ el_gets(EditLine *el, int *nread) read_prepare(el); if (el->el_flags & EDIT_DISABLED) { - char *cp; size_t idx; + if ((el->el_flags & UNBUFFERED) == 0) cp = el->el_line.buffer; else cp = el->el_line.lastchar; - term__flush(el); + terminal__flush(el); - while ((*el->el_read.read_char)(el, cp) == 1) { + while ((num = (*el->el_read.read_char)(el, cp)) == 1) { /* make sure there is space next character */ if (cp + 1 >= el->el_line.limit) { - idx = (cp - el->el_line.buffer); - if (!ch_enlargebufs(el, 2)) + idx = (size_t)(cp - el->el_line.buffer); + if (!ch_enlargebufs(el, (size_t)2)) break; cp = &el->el_line.buffer[idx]; } - if (*cp == 4) /* ought to be stty eof */ - break; cp++; crlf = cp[-1] == '\r' || cp[-1] == '\n'; if (el->el_flags & UNBUFFERED) @@ -480,11 +556,13 @@ el_gets(EditLine *el, int *nread) break; } - el->el_line.cursor = el->el_line.lastchar = cp; - *cp = '\0'; - if (nread) - *nread = el->el_line.cursor - el->el_line.buffer; - return (el->el_line.buffer); + if (num == -1) { + if (errno == EINTR) + cp = el->el_line.buffer; + el->el_errno = errno; + } + + goto noedit; } for (num = OKCMD; num == OKCMD;) { /* while still editing this @@ -500,6 +578,12 @@ el_gets(EditLine *el, int *nread) #endif /* DEBUG_READ */ break; } + if (el->el_errno == EINTR) { + el->el_line.buffer[0] = '\0'; + el->el_line.lastchar = + el->el_line.cursor = el->el_line.buffer; + break; + } if ((unsigned int)cmdnum >= (unsigned int)el->el_map.nfunc) { /* BUG CHECK command */ #ifdef DEBUG_EDIT (void) fprintf(el->el_errfile, @@ -530,7 +614,7 @@ el_gets(EditLine *el, int *nread) el->el_chared.c_redo.pos < el->el_chared.c_redo.lim) { if (cmdnum == VI_DELETE_PREV_CHAR && el->el_chared.c_redo.pos != el->el_chared.c_redo.buf - && el_isprint((unsigned char)el->el_chared.c_redo.pos[-1])) + && Isprint(el->el_chared.c_redo.pos[-1])) el->el_chared.c_redo.pos--; else *el->el_chared.c_redo.pos++ = ch; @@ -561,7 +645,7 @@ el_gets(EditLine *el, int *nread) case CC_REFRESH_BEEP: re_refresh(el); - term_beep(el); + terminal_beep(el); break; case CC_NORM: /* normal char */ @@ -582,7 +666,7 @@ el_gets(EditLine *el, int *nread) break; case CC_NEWLINE: /* normal end of line */ - num = el->el_line.lastchar - el->el_line.buffer; + num = (int)(el->el_line.lastchar - el->el_line.buffer); break; case CC_FATAL: /* fatal error, reset to known state */ @@ -593,7 +677,7 @@ el_gets(EditLine *el, int *nread) /* put (real) cursor in a known place */ re_clear_display(el); /* reset the display stuff */ ch_reset(el, 1); /* reset the input pointers */ - re_refresh(el); /* print the prompt again */ + re_refresh(el); /* print the prompt again */ break; case CC_ERROR: @@ -602,8 +686,8 @@ el_gets(EditLine *el, int *nread) (void) fprintf(el->el_errfile, "*** editor ERROR ***\r\n\n"); #endif /* DEBUG_READ */ - term_beep(el); - term__flush(el); + terminal_beep(el); + terminal__flush(el); break; } el->el_state.argument = 1; @@ -613,15 +697,26 @@ el_gets(EditLine *el, int *nread) break; } - term__flush(el); /* flush any buffered output */ + terminal__flush(el); /* flush any buffered output */ /* make sure the tty is set up correctly */ if ((el->el_flags & UNBUFFERED) == 0) { read_finish(el); - if (nread) - *nread = num; + *nread = num != -1 ? num : 0; } else { - if (nread) - *nread = el->el_line.lastchar - el->el_line.buffer; + *nread = (int)(el->el_line.lastchar - el->el_line.buffer); } - return (num ? el->el_line.buffer : NULL); + goto done; +noedit: + el->el_line.cursor = el->el_line.lastchar = cp; + *cp = '\0'; + *nread = (int)(el->el_line.cursor - el->el_line.buffer); +done: + if (*nread == 0) { + if (num == -1) { + *nread = -1; + errno = el->el_errno; + } + return NULL; + } else + return el->el_line.buffer; } diff --git a/cmd-line-utils/libedit/read.h b/cmd-line-utils/libedit/read.h index bd8d4c1f5bb..852606a9c17 100644 --- a/cmd-line-utils/libedit/read.h +++ b/cmd-line-utils/libedit/read.h @@ -1,4 +1,4 @@ -/* $NetBSD: read.h,v 1.6 2008/04/29 06:53:01 martin Exp $ */ +/* $NetBSD: read.h,v 1.7 2009/12/30 22:37:40 christos Exp $ */ /*- * Copyright (c) 2001 The NetBSD Foundation, Inc. @@ -35,7 +35,7 @@ #ifndef _h_el_read #define _h_el_read -typedef int (*el_rfunc_t)(EditLine *, char *); +typedef int (*el_rfunc_t)(EditLine *, Char *); typedef struct el_read_t { el_rfunc_t read_char; /* Function to read a character */ diff --git a/cmd-line-utils/libedit/readline.c b/cmd-line-utils/libedit/readline.c index 0318ab409b3..eaf26d4c497 100644 --- a/cmd-line-utils/libedit/readline.c +++ b/cmd-line-utils/libedit/readline.c @@ -1,4 +1,4 @@ -/* $NetBSD: readline.c,v 1.78 2009/02/05 19:15:26 christos Exp $ */ +/* $NetBSD: readline.c,v 1.99 2011/08/16 16:25:15 christos Exp $ */ /*- * Copyright (c) 1997 The NetBSD Foundation, Inc. @@ -69,6 +69,7 @@ void rl_deprep_terminal(void); /* readline compatibility stuff - look at readline sources/documentation */ /* to see what these variables mean */ const char *rl_library_version = "EditLine wrapper"; +int rl_readline_version = RL_READLINE_VERSION; static char empty[] = { '\0' }; static char expand_chars[] = { ' ', '\t', '\n', '=', '(', '\0' }; static char break_chars[] = { ' ', '\t', '\n', '"', '\\', '\'', '`', '@', '$', @@ -117,6 +118,7 @@ Function *rl_startup_hook = NULL; VFunction *rl_completion_display_matches_hook = NULL; VFunction *rl_prep_term_function = (VFunction *)rl_prep_terminal; VFunction *rl_deprep_term_function = (VFunction *)rl_deprep_terminal; +KEYMAP_ENTRY_ARRAY emacs_meta_keymap; /* * The current prompt string. @@ -174,7 +176,7 @@ static char * _get_prompt(EditLine *el __attribute__((__unused__))) { rl_already_prompted = 1; - return (rl_prompt); + return rl_prompt; } @@ -188,12 +190,12 @@ _move_history(int op) static HIST_ENTRY rl_he; if (history(h, &ev, op) != 0) - return (HIST_ENTRY *) NULL; + return NULL; rl_he.line = ev.str; rl_he.data = NULL; - return (&rl_he); + return &rl_he; } @@ -209,10 +211,34 @@ _getc_function(EditLine *el __attribute__((__unused__)), char *c) i = (*rl_getc_function)(NULL); if (i == -1) return 0; - *c = i; + *c = (char)i; return 1; } +static void +_resize_fun(EditLine *el, void *a) +{ + const LineInfo *li; + char **ap = a; + + li = el_line(el); + /* a cheesy way to get rid of const cast. */ + *ap = memchr(li->buffer, *li->buffer, (size_t)1); +} + +static const char * +_default_history_file(void) +{ + struct passwd *p; + static char path[PATH_MAX]; + + if (*path) + return path; + if ((p = getpwuid(getuid())) == NULL) + return NULL; + (void)snprintf(path, sizeof(path), "%s/.history", p->pw_dir); + return path; +} /* * READLINE compatibility stuff @@ -224,14 +250,22 @@ _getc_function(EditLine *el __attribute__((__unused__)), char *c) int rl_set_prompt(const char *prompt) { + char *p; + if (!prompt) prompt = ""; if (rl_prompt != NULL && strcmp(rl_prompt, prompt) == 0) return 0; if (rl_prompt) - free(rl_prompt); + el_free(rl_prompt); rl_prompt = strdup(prompt); - return rl_prompt == NULL ? -1 : 0; + if (rl_prompt == NULL) + return -1; + + while ((p = strchr(rl_prompt, RL_PROMPT_END_IGNORE)) != NULL) + *p = RL_PROMPT_START_IGNORE; + + return 0; } /* @@ -241,7 +275,6 @@ int rl_initialize(void) { HistEvent ev; - const LineInfo *li; int editmode = 1; struct termios t; @@ -268,13 +301,16 @@ rl_initialize(void) h = history_init(); if (!e || !h) - return (-1); + return -1; history(h, &ev, H_SETSIZE, INT_MAX); /* unlimited */ history_length = 0; max_input_history = INT_MAX; el_set(e, EL_HIST, history, h); + /* Setup resize function */ + el_set(e, EL_RESIZE, _resize_fun, &rl_line_buffer); + /* setup getc function if valid */ if (rl_getc_function) el_set(e, EL_GETCFN, _getc_function); @@ -285,7 +321,7 @@ rl_initialize(void) el_end(e); return -1; } - el_set(e, EL_PROMPT, _get_prompt); + el_set(e, EL_PROMPT, _get_prompt, RL_PROMPT_START_IGNORE); el_set(e, EL_SIGNAL, rl_catch_signals); /* set default mode to "emacs"-style and read setting afterwards */ @@ -312,7 +348,38 @@ rl_initialize(void) "ReadLine compatible suspend function", _el_rl_tstp); el_set(e, EL_BIND, "^Z", "rl_tstp", NULL); - + + /* + * Set some readline compatible key-bindings. + */ + el_set(e, EL_BIND, "^R", "em-inc-search-prev", NULL); + + /* + * Allow the use of Home/End keys. + */ + el_set(e, EL_BIND, "\\e[1~", "ed-move-to-beg", NULL); + el_set(e, EL_BIND, "\\e[4~", "ed-move-to-end", NULL); + el_set(e, EL_BIND, "\\e[7~", "ed-move-to-beg", NULL); + el_set(e, EL_BIND, "\\e[8~", "ed-move-to-end", NULL); + el_set(e, EL_BIND, "\\e[H", "ed-move-to-beg", NULL); + el_set(e, EL_BIND, "\\e[F", "ed-move-to-end", NULL); + + /* + * Allow the use of the Delete/Insert keys. + */ + el_set(e, EL_BIND, "\\e[3~", "ed-delete-next-char", NULL); + el_set(e, EL_BIND, "\\e[2~", "ed-quoted-insert", NULL); + + /* + * Ctrl-left-arrow and Ctrl-right-arrow for word moving. + */ + el_set(e, EL_BIND, "\\e[1;5C", "em-next-word", NULL); + el_set(e, EL_BIND, "\\e[1;5D", "ed-prev-word", NULL); + el_set(e, EL_BIND, "\\e[5C", "em-next-word", NULL); + el_set(e, EL_BIND, "\\e[5D", "ed-prev-word", NULL); + el_set(e, EL_BIND, "\\e\\e[C", "em-next-word", NULL); + el_set(e, EL_BIND, "\\e\\e[D", "ed-prev-word", NULL); + /* read settings from configuration file */ el_source(e, NULL); @@ -320,15 +387,13 @@ rl_initialize(void) * Unfortunately, some applications really do use rl_point * and rl_line_buffer directly. */ - li = el_line(e); - /* a cheesy way to get rid of const cast. */ - rl_line_buffer = memchr(li->buffer, *li->buffer, 1); + _resize_fun(e, &rl_line_buffer); _rl_update_pos(); if (rl_startup_hook) (*rl_startup_hook)(NULL, 0); - return (0); + return 0; } @@ -437,7 +502,7 @@ _rl_compat_sub(const char *str, const char *what, const char *with, } else s++; } - r = result = malloc(len + 1); + r = result = el_malloc((len + 1) * sizeof(*r)); if (result == NULL) return NULL; s = str; @@ -448,13 +513,13 @@ _rl_compat_sub(const char *str, const char *what, const char *with, s += what_len; if (!globally) { (void)strcpy(r, s); - return(result); + return result; } } else *r++ = *s++; } *r = '\0'; - return(result); + return result; } static char *last_search_pat; /* last !?pat[?] search pattern */ @@ -471,14 +536,14 @@ get_history_event(const char *cmd, int *cindex, int qchar) idx = *cindex; if (cmd[idx++] != history_expansion_char) - return(NULL); + return NULL; /* find out which event to take */ if (cmd[idx] == history_expansion_char || cmd[idx] == '\0') { if (history(h, &ev, H_FIRST) != 0) - return(NULL); + return NULL; *cindex = cmd[idx]? (idx + 1):idx; - return(ev.str); + return ev.str; } sign = 0; if (cmd[idx] == '-') { @@ -498,10 +563,10 @@ get_history_event(const char *cmd, int *cindex, int qchar) num = history_length - num + 1; if (!(rl_he = history_get(num))) - return(NULL); + return NULL; *cindex = idx; - return(rl_he->line); + return rl_he->line; } sub = 0; if (cmd[idx] == '?') { @@ -519,15 +584,15 @@ get_history_event(const char *cmd, int *cindex, int qchar) break; idx++; } - len = idx - begin; + len = (size_t)idx - (size_t)begin; if (sub && cmd[idx] == '?') idx++; if (sub && len == 0 && last_search_pat && *last_search_pat) pat = last_search_pat; else if (len == 0) - return(NULL); + return NULL; else { - if ((pat = malloc(len + 1)) == NULL) + if ((pat = el_malloc((len + 1) * sizeof(*pat))) == NULL) return NULL; (void)strncpy(pat, cmd + begin, len); pat[len] = '\0'; @@ -535,15 +600,15 @@ get_history_event(const char *cmd, int *cindex, int qchar) if (history(h, &ev, H_CURR) != 0) { if (pat != last_search_pat) - free(pat); - return (NULL); + el_free(pat); + return NULL; } num = ev.num; if (sub) { if (pat != last_search_pat) { if (last_search_pat) - free(last_search_pat); + el_free(last_search_pat); last_search_pat = pat; } ret = history_search(pat, -1); @@ -555,21 +620,21 @@ get_history_event(const char *cmd, int *cindex, int qchar) history(h, &ev, H_FIRST); (void)fprintf(rl_outstream, "%s: Event not found\n", pat); if (pat != last_search_pat) - free(pat); - return(NULL); + el_free(pat); + return NULL; } if (sub && len) { if (last_search_match && last_search_match != pat) - free(last_search_match); + el_free(last_search_match); last_search_match = pat; } if (pat != last_search_pat) - free(pat); + el_free(pat); if (history(h, &ev, H_CURR) != 0) - return(NULL); + return NULL; *cindex = idx; rptr = ev.str; @@ -621,7 +686,8 @@ _history_expand_command(const char *command, size_t offs, size_t cmdlen, } else { if (command[offs + 1] == '#') { /* use command so far */ - if ((aptr = malloc(offs + 1)) == NULL) + if ((aptr = el_malloc((offs + 1) * sizeof(*aptr))) + == NULL) return -1; (void)strncpy(aptr, command, offs); aptr[offs] = '\0'; @@ -632,17 +698,19 @@ _history_expand_command(const char *command, size_t offs, size_t cmdlen, qchar = (offs > 0 && command[offs - 1] == '"')? '"':0; ptr = get_history_event(command + offs, &idx, qchar); } - has_mods = command[offs + idx] == ':'; + has_mods = command[offs + (size_t)idx] == ':'; } if (ptr == NULL && aptr == NULL) - return(-1); + return -1; if (!has_mods) { - *result = strdup(aptr? aptr : ptr); + *result = strdup(aptr ? aptr : ptr); if (aptr) - free(aptr); - return(1); + el_free(aptr); + if (*result == NULL) + return -1; + return 1; } cmd = command + offs + idx + 1; @@ -687,18 +755,18 @@ _history_expand_command(const char *command, size_t offs, size_t cmdlen, (void)fprintf(rl_outstream, "%s: Bad word specifier", command + offs + idx); if (aptr) - free(aptr); - return(-1); + el_free(aptr); + return -1; } } else tmp = strdup(aptr? aptr:ptr); if (aptr) - free(aptr); + el_free(aptr); if (*cmd == '\0' || ((size_t)(cmd - (command + offs)) >= cmdlen)) { *result = tmp; - return(1); + return 1; } for (; *cmd; cmd++) { @@ -710,7 +778,7 @@ _history_expand_command(const char *command, size_t offs, size_t cmdlen, } else if (*cmd == 't') { /* remove leading path */ if ((aptr = strrchr(tmp, '/')) != NULL) { aptr = strdup(aptr + 1); - free(tmp); + el_free(tmp); tmp = aptr; } } else if (*cmd == 'r') { /* remove trailing suffix */ @@ -719,7 +787,7 @@ _history_expand_command(const char *command, size_t offs, size_t cmdlen, } else if (*cmd == 'e') { /* remove all but suffix */ if ((aptr = strrchr(tmp, '.')) != NULL) { aptr = strdup(aptr); - free(tmp); + el_free(tmp); tmp = aptr; } } else if (*cmd == 'p') /* print only */ @@ -736,10 +804,10 @@ _history_expand_command(const char *command, size_t offs, size_t cmdlen, else if (*cmd == 's') { delim = *(++cmd), cmd++; size = 16; - what = realloc(from, size); + what = el_realloc(from, size * sizeof(*what)); if (what == NULL) { - free(from); - free(tmp); + el_free(from); + el_free(tmp); return 0; } len = 0; @@ -748,11 +816,12 @@ _history_expand_command(const char *command, size_t offs, size_t cmdlen, cmd++; if (len >= size) { char *nwhat; - nwhat = realloc(what, - (size <<= 1)); + nwhat = el_realloc(what, + (size <<= 1) * + sizeof(*nwhat)); if (nwhat == NULL) { - free(what); - free(tmp); + el_free(what); + el_free(tmp); return 0; } what = nwhat; @@ -762,17 +831,17 @@ _history_expand_command(const char *command, size_t offs, size_t cmdlen, what[len] = '\0'; from = what; if (*what == '\0') { - free(what); + el_free(what); if (search) { from = strdup(search); if (from == NULL) { - free(tmp); + el_free(tmp); return 0; } } else { from = NULL; - free(tmp); - return (-1); + el_free(tmp); + return -1; } } cmd++; /* shift after delim */ @@ -780,10 +849,10 @@ _history_expand_command(const char *command, size_t offs, size_t cmdlen, continue; size = 16; - with = realloc(to, size); + with = el_realloc(to, size * sizeof(*with)); if (with == NULL) { - free(to); - free(tmp); + el_free(to); + el_free(tmp); return -1; } len = 0; @@ -792,10 +861,11 @@ _history_expand_command(const char *command, size_t offs, size_t cmdlen, if (len + from_len + 1 >= size) { char *nwith; size += from_len + 1; - nwith = realloc(with, size); + nwith = el_realloc(with, + size * sizeof(*nwith)); if (nwith == NULL) { - free(with); - free(tmp); + el_free(with); + el_free(tmp); return -1; } with = nwith; @@ -818,14 +888,14 @@ _history_expand_command(const char *command, size_t offs, size_t cmdlen, aptr = _rl_compat_sub(tmp, from, to, g_on); if (aptr) { - free(tmp); + el_free(tmp); tmp = aptr; } g_on = 0; } } *result = tmp; - return (p_on? 2:1); + return p_on? 2:1; } @@ -844,13 +914,13 @@ history_expand(char *str, char **output) if (history_expansion_char == 0) { *output = strdup(str); - return(0); + return 0; } *output = NULL; if (str[0] == history_subst_char) { /* ^foo^foo2^ is equivalent to !!:s^foo^foo2^ */ - *output = malloc(strlen(str) + 4 + 1); + *output = el_malloc((strlen(str) + 4 + 1) * sizeof(*output)); if (*output == NULL) return 0; (*output)[0] = (*output)[1] = history_expansion_char; @@ -867,11 +937,12 @@ history_expand(char *str, char **output) #define ADD_STRING(what, len, fr) \ { \ if (idx + len + 1 > size) { \ - char *nresult = realloc(result, (size += len + 1));\ + char *nresult = el_realloc(result, \ + (size += len + 1) * sizeof(*nresult)); \ if (nresult == NULL) { \ - free(*output); \ + el_free(*output); \ if (/*CONSTCOND*/fr) \ - free(tmp); \ + el_free(tmp); \ return 0; \ } \ result = nresult; \ @@ -938,7 +1009,7 @@ loop: ADD_STRING(tmp, len, 1); } if (tmp) { - free(tmp); + el_free(tmp); tmp = NULL; } i = j; @@ -955,10 +1026,10 @@ loop: ret = -1; #endif } - free(*output); + el_free(*output); *output = result; - return (ret); + return ret; } /* @@ -968,40 +1039,39 @@ char * history_arg_extract(int start, int end, const char *str) { size_t i, len, max; - char **arr, *result; + char **arr, *result = NULL; arr = history_tokenize(str); if (!arr) - return(NULL); - if (arr && *arr == NULL) { - free(arr); - return(NULL); - } + return NULL; + if (arr && *arr == NULL) + goto out; for (max = 0; arr[max]; max++) continue; max--; if (start == '$') - start = max; + start = (int)max; if (end == '$') - end = max; + end = (int)max; if (end < 0) - end = max + end + 1; + end = (int)max + end + 1; if (start < 0) start = end; - if (start < 0 || end < 0 || (size_t)start > max || (size_t)end > max || start > end) - return(NULL); + if (start < 0 || end < 0 || (size_t)start > max || + (size_t)end > max || start > end) + goto out; - for (i = start, len = 0; i <= (size_t)end; i++) + for (i = (size_t)start, len = 0; i <= (size_t)end; i++) len += strlen(arr[i]) + 1; len++; - result = malloc(len); + result = el_malloc(len * sizeof(*result)); if (result == NULL) - return NULL; + goto out; - for (i = start, len = 0; i <= (size_t)end; i++) { + for (i = (size_t)start, len = 0; i <= (size_t)end; i++) { (void)strcpy(result + len, arr[i]); len += strlen(arr[i]); if (i < (size_t)end) @@ -1009,11 +1079,12 @@ history_arg_extract(int start, int end, const char *str) } result[len] = '\0'; +out: for (i = 0; arr[i]; i++) - free(arr[i]); - free(arr); + el_free(arr[i]); + el_free(arr); - return(result); + return result; } /* @@ -1050,19 +1121,19 @@ history_tokenize(const char *str) if (idx + 2 >= size) { char **nresult; size <<= 1; - nresult = realloc(result, size * sizeof(char *)); + nresult = el_realloc(result, (size_t)size * sizeof(*nresult)); if (nresult == NULL) { - free(result); + el_free(result); return NULL; } result = nresult; } - len = i - start; - temp = malloc(len + 1); + len = (size_t)i - (size_t)start; + temp = el_malloc((size_t)(len + 1) * sizeof(*temp)); if (temp == NULL) { for (i = 0; i < idx; i++) - free(result[i]); - free(result); + el_free(result[i]); + el_free(result); return NULL; } (void)strncpy(temp, &str[start], len); @@ -1072,7 +1143,7 @@ history_tokenize(const char *str) if (str[i]) i++; } - return (result); + return result; } @@ -1104,7 +1175,7 @@ unstifle_history(void) history(h, &ev, H_SETSIZE, INT_MAX); omax = max_input_history; max_input_history = INT_MAX; - return (omax); /* some value _must_ be returned */ + return omax; /* some value _must_ be returned */ } @@ -1113,7 +1184,146 @@ history_is_stifled(void) { /* cannot return true answer */ - return (max_input_history != INT_MAX); + return max_input_history != INT_MAX; +} + +static const char _history_tmp_template[] = "/tmp/.historyXXXXXX"; + +int +history_truncate_file (const char *filename, int nlines) +{ + int ret = 0; + FILE *fp, *tp; + char template[sizeof(_history_tmp_template)]; + char buf[4096]; + int fd; + char *cp; + off_t off; + int count = 0; + ssize_t left = 0; + + if (filename == NULL && (filename = _default_history_file()) == NULL) + return errno; + if ((fp = fopen(filename, "r+")) == NULL) + return errno; + strcpy(template, _history_tmp_template); + if ((fd = mkstemp(template)) == -1) { + ret = errno; + goto out1; + } + + if ((tp = fdopen(fd, "r+")) == NULL) { + close(fd); + ret = errno; + goto out2; + } + + for(;;) { + if (fread(buf, sizeof(buf), (size_t)1, fp) != 1) { + if (ferror(fp)) { + ret = errno; + break; + } + if (fseeko(fp, (off_t)sizeof(buf) * count, SEEK_SET) == + (off_t)-1) { + ret = errno; + break; + } + left = (ssize_t)fread(buf, (size_t)1, sizeof(buf), fp); + if (ferror(fp)) { + ret = errno; + break; + } + if (left == 0) { + count--; + left = sizeof(buf); + } else if (fwrite(buf, (size_t)left, (size_t)1, tp) + != 1) { + ret = errno; + break; + } + fflush(tp); + break; + } + if (fwrite(buf, sizeof(buf), (size_t)1, tp) != 1) { + ret = errno; + break; + } + count++; + } + if (ret) + goto out3; + cp = buf + left - 1; + if(*cp != '\n') + cp++; + for(;;) { + while (--cp >= buf) { + if (*cp == '\n') { + if (--nlines == 0) { + if (++cp >= buf + sizeof(buf)) { + count++; + cp = buf; + } + break; + } + } + } + if (nlines <= 0 || count == 0) + break; + count--; + if (fseeko(tp, (off_t)sizeof(buf) * count, SEEK_SET) < 0) { + ret = errno; + break; + } + if (fread(buf, sizeof(buf), (size_t)1, tp) != 1) { + if (ferror(tp)) { + ret = errno; + break; + } + ret = EAGAIN; + break; + } + cp = buf + sizeof(buf); + } + + if (ret || nlines > 0) + goto out3; + + if (fseeko(fp, (off_t)0, SEEK_SET) == (off_t)-1) { + ret = errno; + goto out3; + } + + if (fseeko(tp, (off_t)sizeof(buf) * count + (cp - buf), SEEK_SET) == + (off_t)-1) { + ret = errno; + goto out3; + } + + for(;;) { + if ((left = (ssize_t)fread(buf, (size_t)1, sizeof(buf), tp)) == 0) { + if (ferror(fp)) + ret = errno; + break; + } + if (fwrite(buf, (size_t)left, (size_t)1, fp) != 1) { + ret = errno; + break; + } + } + fflush(fp); + if((off = ftello(fp)) > 0) { + if (ftruncate(fileno(fp), off) == -1) + ret = errno; + } +out3: + fclose(tp); +out2: + unlink(template); +out1: + fclose(fp); + + return ret; } @@ -1127,7 +1337,10 @@ read_history(const char *filename) if (h == NULL || e == NULL) rl_initialize(); - return (history(h, &ev, H_LOAD, filename) == -1); + if (filename == NULL && (filename = _default_history_file()) == NULL) + return errno; + return history(h, &ev, H_LOAD, filename) == -1 ? + (errno ? errno : EINVAL) : 0; } @@ -1141,7 +1354,10 @@ write_history(const char *filename) if (h == NULL || e == NULL) rl_initialize(); - return (history(h, &ev, H_SAVE, filename) == -1); + if (filename == NULL && (filename = _default_history_file()) == NULL) + return errno; + return history(h, &ev, H_SAVE, filename) == -1 ? + (errno ? errno : EINVAL) : 0; } @@ -1162,24 +1378,23 @@ history_get(int num) /* save current position */ if (history(h, &ev, H_CURR) != 0) - return (NULL); + return NULL; curr_num = ev.num; - /* start from most recent */ - if (history(h, &ev, H_FIRST) != 0) - return (NULL); /* error */ + /* start from the oldest */ + if (history(h, &ev, H_LAST) != 0) + return NULL; /* error */ - /* look backwards for event matching specified offset */ - if (history(h, &ev, H_NEXT_EVENT, num + 1)) - return (NULL); + /* look forwards for event matching specified offset */ + if (history(h, &ev, H_NEXT_EVDATA, num, &she.data)) + return NULL; she.line = ev.str; - she.data = NULL; /* restore pointer to where it was */ (void)history(h, &ev, H_SET, curr_num); - return (&she); + return &she; } @@ -1198,7 +1413,7 @@ add_history(const char *line) if (history(h, &ev, H_GETSIZE) == 0) history_length = ev.num; - return (!(history_length > 0)); /* return 0 if all is okay */ + return !(history_length > 0); /* return 0 if all is okay */ } @@ -1208,25 +1423,74 @@ add_history(const char *line) HIST_ENTRY * remove_history(int num) { - HIST_ENTRY *she; + HIST_ENTRY *he; HistEvent ev; if (h == NULL || e == NULL) rl_initialize(); - if (history(h, &ev, H_DEL, num) != 0) + if ((he = el_malloc(sizeof(*he))) == NULL) return NULL; - if ((she = malloc(sizeof(*she))) == NULL) + if (history(h, &ev, H_DELDATA, num, &he->data) != 0) { + el_free(he); return NULL; + } - she->line = ev.str; - she->data = NULL; + he->line = ev.str; + if (history(h, &ev, H_GETSIZE) == 0) + history_length = ev.num; - return she; + return he; } +/* + * replace the line and data of the num-th entry + */ +HIST_ENTRY * +replace_history_entry(int num, const char *line, histdata_t data) +{ + HIST_ENTRY *he; + HistEvent ev; + int curr_num; + + if (h == NULL || e == NULL) + rl_initialize(); + + /* save current position */ + if (history(h, &ev, H_CURR) != 0) + return NULL; + curr_num = ev.num; + + /* start from the oldest */ + if (history(h, &ev, H_LAST) != 0) + return NULL; /* error */ + + if ((he = el_malloc(sizeof(*he))) == NULL) + return NULL; + + /* look forwards for event matching specified offset */ + if (history(h, &ev, H_NEXT_EVDATA, num, &he->data)) + goto out; + + he->line = strdup(ev.str); + if (he->line == NULL) + goto out; + + if (history(h, &ev, H_REPLACE, line, data)) + goto out; + + /* restore pointer to where it was */ + if (history(h, &ev, H_SET, curr_num)) + goto out; + + return he; +out: + el_free(he); + return NULL; +} + /* * clear the history list - delete all entries */ @@ -1235,7 +1499,8 @@ clear_history(void) { HistEvent ev; - history(h, &ev, H_CLEAR); + (void)history(h, &ev, H_CLEAR); + history_length = 0; } @@ -1249,15 +1514,15 @@ where_history(void) int curr_num, off; if (history(h, &ev, H_CURR) != 0) - return (0); + return 0; curr_num = ev.num; - history(h, &ev, H_FIRST); + (void)history(h, &ev, H_FIRST); off = 1; while (ev.num != curr_num && history(h, &ev, H_NEXT) == 0) off++; - return (off); + return off; } @@ -1268,7 +1533,7 @@ HIST_ENTRY * current_history(void) { - return (_move_history(H_CURR)); + return _move_history(H_CURR); } @@ -1279,22 +1544,23 @@ int history_total_bytes(void) { HistEvent ev; - int curr_num, size; + int curr_num; + size_t size; if (history(h, &ev, H_CURR) != 0) - return (-1); + return -1; curr_num = ev.num; - history(h, &ev, H_FIRST); + (void)history(h, &ev, H_FIRST); size = 0; do - size += strlen(ev.str); + size += strlen(ev.str) * sizeof(*ev.str); while (history(h, &ev, H_NEXT) == 0); /* get to the same position as before */ history(h, &ev, H_PREV_EVENT, curr_num); - return (size); + return (int)size; } @@ -1307,17 +1573,21 @@ history_set_pos(int pos) HistEvent ev; int curr_num; - if (pos > history_length || pos < 0) - return (-1); + if (pos >= history_length || pos < 0) + return -1; - history(h, &ev, H_CURR); + (void)history(h, &ev, H_CURR); curr_num = ev.num; - if (history(h, &ev, H_SET, pos)) { - history(h, &ev, H_SET, curr_num); - return(-1); + /* + * use H_DELDATA to set to nth history (without delete) by passing + * (void **)-1 + */ + if (history(h, &ev, H_DELDATA, pos, (void **)-1)) { + (void)history(h, &ev, H_SET, curr_num); + return -1; } - return (0); + return 0; } @@ -1328,7 +1598,7 @@ HIST_ENTRY * previous_history(void) { - return (_move_history(H_PREV)); + return _move_history(H_PREV); } @@ -1339,7 +1609,7 @@ HIST_ENTRY * next_history(void) { - return (_move_history(H_NEXT)); + return _move_history(H_NEXT); } @@ -1354,17 +1624,17 @@ history_search(const char *str, int direction) int curr_num; if (history(h, &ev, H_CURR) != 0) - return (-1); + return -1; curr_num = ev.num; for (;;) { if ((strp = strstr(ev.str, str)) != NULL) - return (int) (strp - ev.str); + return (int)(strp - ev.str); if (history(h, &ev, direction < 0 ? H_NEXT:H_PREV) != 0) break; } - history(h, &ev, H_SET, curr_num); - return (-1); + (void)history(h, &ev, H_SET, curr_num); + return -1; } @@ -1376,7 +1646,8 @@ history_search_prefix(const char *str, int direction) { HistEvent ev; - return (history(h, &ev, direction < 0? H_PREV_STR:H_NEXT_STR, str)); + return (history(h, &ev, direction < 0 ? + H_PREV_STR : H_NEXT_STR, str)); } @@ -1396,24 +1667,24 @@ history_search_pos(const char *str, pos = (pos > 0) ? 1 : -1; if (history(h, &ev, H_CURR) != 0) - return (-1); + return -1; curr_num = ev.num; if (history_set_pos(off) != 0 || history(h, &ev, H_CURR) != 0) - return (-1); - + return -1; for (;;) { if (strstr(ev.str, str)) - return (off); + return off; if (history(h, &ev, (pos < 0) ? H_PREV : H_NEXT) != 0) break; } /* set "current" pointer back to previous state */ - history(h, &ev, (pos < 0) ? H_NEXT_EVENT : H_PREV_EVENT, curr_num); + (void)history(h, &ev, + pos < 0 ? H_NEXT_EVENT : H_PREV_EVENT, curr_num); - return (-1); + return -1; } @@ -1436,16 +1707,20 @@ filename_completion_function(const char *name, int state) * a completion generator for usernames; returns _first_ username * which starts with supplied text * text contains a partial username preceded by random character - * (usually '~'); state is ignored + * (usually '~'); state resets search from start (??? should we do that anyway) * it's callers responsibility to free returned value */ char * username_completion_function(const char *text, int state) { - struct passwd *pwd; +#if defined(HAVE_GETPW_R_POSIX) || defined(HAVE_GETPW_R_DRAFT) + struct passwd pwres; + char pwbuf[1024]; +#endif + struct passwd *pass = NULL; if (text[0] == '\0') - return (NULL); + return NULL; if (*text == '~') text++; @@ -1453,15 +1728,21 @@ username_completion_function(const char *text, int state) if (state == 0) setpwent(); - /* XXXMYSQL: just use non-_r functions for now */ - while ((pwd = getpwent()) && text[0] == pwd->pw_name[0] - && strcmp(text, pwd->pw_name) == 0); + while ( +#if defined(HAVE_GETPW_R_POSIX) || defined(HAVE_GETPW_R_DRAFT) + getpwent_r(&pwres, pwbuf, sizeof(pwbuf), &pass) == 0 && pass != NULL +#else + (pass = getpwent()) != NULL +#endif + && text[0] == pass->pw_name[0] + && strcmp(text, pass->pw_name) == 0) + continue; - if (pwd == NULL) { + if (pass == NULL) { endpwent(); - return (NULL); + return NULL; } - return (strdup(pwd->pw_name)); + return strdup(pass->pw_name); } @@ -1485,7 +1766,7 @@ void rl_display_match_list(char **matches, int len, int max) { - fn_display_match_list(e, matches, len, max); + fn_display_match_list(e, matches, (size_t)len, (size_t)max); } static const char * @@ -1494,7 +1775,7 @@ _rl_completion_append_character_function(const char *dummy __attribute__((__unused__))) { static char buf[2]; - buf[0] = rl_completion_append_character; + buf[0] = (char)rl_completion_append_character; buf[1] = '\0'; return buf; } @@ -1507,6 +1788,10 @@ _rl_completion_append_character_function(const char *dummy int rl_complete(int ignore __attribute__((__unused__)), int invoking_key) { +#ifdef WIDECHAR + static ct_buffer_t wbreak_conv, sprefix_conv; +#endif + if (h == NULL || e == NULL) rl_initialize(); @@ -1515,17 +1800,21 @@ rl_complete(int ignore __attribute__((__unused__)), int invoking_key) arr[0] = (char)invoking_key; arr[1] = '\0'; el_insertstr(e, arr); - return (CC_REFRESH); + return CC_REFRESH; } /* Just look at how many global variables modify this operation! */ return fn_complete(e, (CPFunction *)rl_completion_entry_function, rl_attempted_completion_function, - rl_basic_word_break_characters, rl_special_prefixes, - _rl_completion_append_character_function, rl_completion_query_items, + ct_decode_string(rl_basic_word_break_characters, &wbreak_conv), + ct_decode_string(rl_special_prefixes, &sprefix_conv), + _rl_completion_append_character_function, + (size_t)rl_completion_query_items, &rl_completion_type, &rl_attempted_completion_over, &rl_point, &rl_end); + + } @@ -1544,7 +1833,7 @@ _el_rl_complete(EditLine *el __attribute__((__unused__)), int ch) * bind key c to readline-type function func */ int -rl_bind_key(int c, int func(int, int)) +rl_bind_key(int c, rl_command_func_t *func) { int retval = -1; @@ -1556,7 +1845,7 @@ rl_bind_key(int c, int func(int, int)) e->el_map.key[c] = ED_INSERT; retval = 0; } - return (retval); + return retval; } @@ -1572,7 +1861,7 @@ rl_read_key(void) if (e == NULL || h == NULL) rl_initialize(); - return (el_getc(e, fooarr)); + return el_getc(e, fooarr); } @@ -1602,19 +1891,33 @@ rl_insert(int count, int c) rl_initialize(); /* XXX - int -> char conversion can lose on multichars */ - arr[0] = c; + arr[0] = (char)c; arr[1] = '\0'; for (; count > 0; count--) el_push(e, arr); - return (0); + return 0; +} + +int +rl_insert_text(const char *text) +{ + if (!text || *text == 0) + return 0; + + if (h == NULL || e == NULL) + rl_initialize(); + + if (el_insertstr(e, text) < 0) + return 0; + return (int)strlen(text); } /*ARGSUSED*/ int rl_newline(int count __attribute__((__unused__)), - int c __attribute__((__unused__))) + int c __attribute__((__unused__))) { /* * Readline-4.0 appears to ignore the args. @@ -1675,7 +1978,7 @@ rl_callback_read_char() } else wbuf = NULL; (*(void (*)(const char *))rl_linefunc)(wbuf); - el_set(e, EL_UNBUFFERED, 1); + //el_set(e, EL_UNBUFFERED, 1); } } @@ -1701,7 +2004,7 @@ void rl_redisplay(void) { char a[2]; - a[0] = e->el_tty.t_c[TS_IO][C_REPRINT]; + a[0] = (char)e->el_tty.t_c[TS_IO][C_REPRINT]; a[1] = '\0'; el_push(e, a); } @@ -1710,7 +2013,7 @@ int rl_get_previous_history(int count, int key) { char a[2]; - a[0] = key; + a[0] = (char)key; a[1] = '\0'; while (count--) el_push(e, a); @@ -1733,7 +2036,7 @@ rl_deprep_terminal(void) int rl_read_init_file(const char *s) { - return(el_source(e, s)); + return el_source(e, s); } int @@ -1747,7 +2050,7 @@ rl_parse_and_bind(const char *line) tok_str(tok, line, &argc, &argv); argc = el_parse(e, argc, argv); tok_end(tok); - return (argc ? 1 : 0); + return argc ? 1 : 0; } int @@ -1757,7 +2060,7 @@ rl_variable_bind(const char *var, const char *value) * The proper return value is undocument, but this is what the * readline source seems to do. */ - return ((el_set(e, EL_BIND, "", var, value) == -1) ? 1 : 0); + return el_set(e, EL_BIND, "", var, value) == -1 ? 1 : 0; } void @@ -1765,7 +2068,7 @@ rl_stuff_char(int c) { char buf[2]; - buf[0] = c; + buf[0] = (char)c; buf[1] = '\0'; el_insertstr(e, buf); } @@ -1773,7 +2076,8 @@ rl_stuff_char(int c) static int _rl_event_read_char(EditLine *el, char *cp) { - int n, num_read = 0; + int n; + ssize_t num_read = 0; *cp = '\0'; while (rl_event_hook) { @@ -1782,23 +2086,23 @@ _rl_event_read_char(EditLine *el, char *cp) #if defined(FIONREAD) if (ioctl(el->el_infd, FIONREAD, &n) < 0) - return(-1); + return -1; if (n) - num_read = read(el->el_infd, cp, 1); + num_read = read(el->el_infd, cp, (size_t)1); else num_read = 0; #elif defined(F_SETFL) && defined(O_NDELAY) if ((n = fcntl(el->el_infd, F_GETFL, 0)) < 0) - return(-1); + return -1; if (fcntl(el->el_infd, F_SETFL, n|O_NDELAY) < 0) - return(-1); + return -1; num_read = read(el->el_infd, cp, 1); if (fcntl(el->el_infd, F_SETFL, n)) - return(-1); + return -1; #else /* not non-blocking, but what you gonna do? */ num_read = read(el->el_infd, cp, 1); - return(-1); + return -1; #endif if (num_read < 0 && errno == EAGAIN) @@ -1809,7 +2113,7 @@ _rl_event_read_char(EditLine *el, char *cp) } if (!rl_event_hook) el_set(el, EL_GETCFN, EL_BUILTIN_GETCFN); - return(num_read); + return (int)num_read; } static void @@ -1817,8 +2121,8 @@ _rl_update_pos(void) { const LineInfo *li = el_line(e); - rl_point = li->cursor - li->buffer; - rl_end = li->lastchar - li->buffer; + rl_point = (int)(li->cursor - li->buffer); + rl_end = (int)(li->lastchar - li->buffer); } void @@ -1848,18 +2152,18 @@ rl_completion_matches(const char *str, rl_compentry_func_t *fun) len = 1; max = 10; - if ((list = malloc(max * sizeof(*list))) == NULL) + if ((list = el_malloc(max * sizeof(*list))) == NULL) return NULL; while ((match = (*fun)(str, (int)(len - 1))) != NULL) { + list[len++] = match; if (len == max) { char **nl; max += 10; - if ((nl = realloc(list, max * sizeof(*nl))) == NULL) + if ((nl = el_realloc(list, max * sizeof(*nl))) == NULL) goto out; list = nl; } - list[len++] = match; } if (len == 1) goto out; @@ -1883,7 +2187,7 @@ rl_completion_matches(const char *str, rl_compentry_func_t *fun) if ((list[0] = strdup(str)) == NULL) goto out; } else { - if ((list[0] = malloc(min + 1)) == NULL) + if ((list[0] = el_malloc((min + 1) * sizeof(*list[0]))) == NULL) goto out; (void)memcpy(list[0], list[1], min); list[0][min] = '\0'; @@ -1891,7 +2195,7 @@ rl_completion_matches(const char *str, rl_compentry_func_t *fun) return list; out: - free(list); + el_free(list); return NULL; } @@ -1921,10 +2225,21 @@ _rl_qsort_string_compare(char **s1, char **s2) return strcoll(*s1, *s2); } +HISTORY_STATE * +history_get_history_state(void) +{ + HISTORY_STATE *hs; + + if ((hs = el_malloc(sizeof(*hs))) == NULL) + return NULL; + hs->length = history_length; + return hs; +} + int /*ARGSUSED*/ rl_kill_text(int from __attribute__((__unused__)), - int to __attribute__((__unused__))) + int to __attribute__((__unused__))) { return 0; } @@ -1950,9 +2265,9 @@ rl_set_keymap(Keymap k __attribute__((__unused__))) int /*ARGSUSED*/ rl_generic_bind(int type __attribute__((__unused__)), - const char * keyseq __attribute__((__unused__)), - const char * data __attribute__((__unused__)), - Keymap k __attribute__((__unused__))) + const char * keyseq __attribute__((__unused__)), + const char * data __attribute__((__unused__)), + Keymap k __attribute__((__unused__))) { return 0; } @@ -1960,8 +2275,20 @@ rl_generic_bind(int type __attribute__((__unused__)), int /*ARGSUSED*/ rl_bind_key_in_map(int key __attribute__((__unused__)), - Function *fun __attribute__((__unused__)), - Keymap k __attribute__((__unused__))) + rl_command_func_t *fun __attribute__((__unused__)), + Keymap k __attribute__((__unused__))) +{ + return 0; +} + +/* unsupported, but needed by python */ +void +rl_cleanup_after_signal(void) +{ +} + +int +rl_on_new_line(void) { return 0; } diff --git a/cmd-line-utils/libedit/readline/readline.h b/cmd-line-utils/libedit/readline/readline.h index 0e300faed89..d9efe3e01a8 100644 --- a/cmd-line-utils/libedit/readline/readline.h +++ b/cmd-line-utils/libedit/readline/readline.h @@ -1,4 +1,4 @@ -/* $NetBSD: readline.h,v 1.24 2009/02/05 19:15:26 christos Exp $ */ +/* $NetBSD: readline.h,v 1.32 2010/09/16 20:08:52 christos Exp $ */ /*- * Copyright (c) 1997 The NetBSD Foundation, Inc. @@ -32,6 +32,7 @@ #define _READLINE_H_ #include +#include /* list of readline stuff supported by editline library's readline wrapper */ @@ -42,10 +43,18 @@ typedef void VCPFunction(char *); typedef char *CPFunction(const char *, int); typedef char **CPPFunction(const char *, int, int); typedef char *rl_compentry_func_t(const char *, int); +typedef int rl_command_func_t(int, int); + +/* only supports length */ +typedef struct { + int length; +} HISTORY_STATE; + +typedef void *histdata_t; typedef struct _hist_entry { const char *line; - const char *data; + histdata_t data; } HIST_ENTRY; typedef struct _keymap_entry { @@ -79,12 +88,16 @@ typedef KEYMAP_ENTRY *Keymap; #define RUBOUT 0x7f #define ABORT_CHAR CTRL('G') +#define RL_READLINE_VERSION 0x0402 +#define RL_PROMPT_START_IGNORE '\1' +#define RL_PROMPT_END_IGNORE '\2' /* global variables used by readline enabled applications */ #ifdef __cplusplus extern "C" { #endif extern const char *rl_library_version; +extern int rl_readline_version; extern char *rl_readline_name; extern FILE *rl_instream; extern FILE *rl_outstream; @@ -138,6 +151,7 @@ int where_history(void); HIST_ENTRY *current_history(void); HIST_ENTRY *history_get(int); HIST_ENTRY *remove_history(int); +HIST_ENTRY *replace_history_entry(int, const char *, histdata_t); int history_total_bytes(void); int history_set_pos(int); HIST_ENTRY *previous_history(void); @@ -147,6 +161,7 @@ int history_search_prefix(const char *, int); int history_search_pos(const char *, int, int); int read_history(const char *); int write_history(const char *); +int history_truncate_file (const char *, int); int history_expand(char *, char **); char **history_tokenize(const char *); const char *get_history_event(const char *, int *, int); @@ -161,8 +176,9 @@ char **completion_matches(const char *, CPFunction *); void rl_display_match_list(char **, int, int); int rl_insert(int, int); +int rl_insert_text(const char *); void rl_reset_terminal(const char *); -int rl_bind_key(int, int (*)(int, int)); +int rl_bind_key(int, rl_command_func_t *); int rl_newline(int, int); void rl_callback_read_char(void); void rl_callback_handler_install(const char *, VCPFunction *); @@ -176,6 +192,7 @@ int rl_parse_and_bind(const char *); int rl_variable_bind(const char *, const char *); void rl_stuff_char(int); int rl_add_defun(const char *, Function *, int); +HISTORY_STATE *history_get_history_state(void); void rl_get_screen_size(int *, int *); void rl_set_screen_size(int, int); char *rl_filename_completion_function (const char *, int); @@ -184,6 +201,7 @@ int _rl_qsort_string_compare(char **, char **); char **rl_completion_matches(const char *, rl_compentry_func_t *); void rl_forced_update_display(void); int rl_set_prompt(const char *); +int rl_on_new_line(void); /* * The following are not implemented @@ -193,7 +211,9 @@ Keymap rl_get_keymap(void); void rl_set_keymap(Keymap); Keymap rl_make_bare_keymap(void); int rl_generic_bind(int, const char *, const char *, Keymap); -int rl_bind_key_in_map(int, Function *, Keymap); +int rl_bind_key_in_map(int, rl_command_func_t *, Keymap); +void rl_cleanup_after_signal(void); +void rl_free_line_state(void); #ifdef __cplusplus } #endif diff --git a/cmd-line-utils/libedit/refresh.c b/cmd-line-utils/libedit/refresh.c index 5edd1fe78fc..a144059f700 100644 --- a/cmd-line-utils/libedit/refresh.c +++ b/cmd-line-utils/libedit/refresh.c @@ -1,4 +1,4 @@ -/* $NetBSD: refresh.c,v 1.28 2008/09/10 15:45:37 christos Exp $ */ +/* $NetBSD: refresh.c,v 1.37 2011/07/29 23:44:45 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -40,6 +40,8 @@ static char sccsid[] = "@(#)refresh.c 8.1 (Berkeley) 6/4/93"; #endif #endif /* not lint && not SCCSID */ +#include "chartype.c" /* XXXMYSQL */ + /* * refresh.c: Lower level screen refreshing functions */ @@ -50,14 +52,15 @@ static char sccsid[] = "@(#)refresh.c 8.1 (Berkeley) 6/4/93"; #include "el.h" -private void re_addc(EditLine *, int); -private void re_update_line(EditLine *, char *, char *, int); -private void re_insert (EditLine *, char *, int, int, char *, int); -private void re_delete(EditLine *, char *, int, int, int); -private void re_fastputc(EditLine *, int); +private void re_nextline(EditLine *); +private void re_addc(EditLine *, Int); +private void re_update_line(EditLine *, Char *, Char *, int); +private void re_insert (EditLine *, Char *, int, int, Char *, int); +private void re_delete(EditLine *, Char *, int, int, int); +private void re_fastputc(EditLine *, Int); private void re_clear_eol(EditLine *, int, int, int); -private void re__strncopy(char *, char *, size_t); -private void re__copy_and_pad(char *, const char *, size_t); +private void re__strncopy(Char *, Char *, size_t); +private void re__copy_and_pad(Char *, const Char *, size_t); #ifdef DEBUG_REFRESH private void re_printstr(EditLine *, const char *, char *, char *); @@ -87,45 +90,70 @@ re_printstr(EditLine *el, const char *str, char *f, char *t) #define ELRE_DEBUG(a, b) #endif +/* re_nextline(): + * Move to the next line or scroll + */ +private void +re_nextline(EditLine *el) +{ + el->el_refresh.r_cursor.h = 0; /* reset it. */ + + /* + * If we would overflow (input is longer than terminal size), + * emulate scroll by dropping first line and shuffling the rest. + * We do this via pointer shuffling - it's safe in this case + * and we avoid memcpy(). + */ + if (el->el_refresh.r_cursor.v + 1 >= el->el_terminal.t_size.v) { + int i, lins = el->el_terminal.t_size.v; + Char *firstline = el->el_vdisplay[0]; + + for(i = 1; i < lins; i++) + el->el_vdisplay[i - 1] = el->el_vdisplay[i]; + + firstline[0] = '\0'; /* empty the string */ + el->el_vdisplay[i - 1] = firstline; + } else + el->el_refresh.r_cursor.v++; + + ELRE_ASSERT(el->el_refresh.r_cursor.v >= el->el_terminal.t_size.v, + (__F, "\r\nre_putc: overflow! r_cursor.v == %d > %d\r\n", + el->el_refresh.r_cursor.v, el->el_terminal.t_size.v), + abort()); +} /* re_addc(): * Draw c, expanding tabs, control chars etc. */ private void -re_addc(EditLine *el, int c) +re_addc(EditLine *el, Int c) { - - if (el_isprint(c)) { - re_putc(el, c, 1); - return; - } - if (c == '\n') { /* expand the newline */ - int oldv = el->el_refresh.r_cursor.v; - re_putc(el, '\0', 0); /* assure end of line */ - if (oldv == el->el_refresh.r_cursor.v) { /* XXX */ - el->el_refresh.r_cursor.h = 0; /* reset cursor pos */ - el->el_refresh.r_cursor.v++; - } - return; - } - if (c == '\t') { /* expand the tab */ + switch (ct_chr_class((Char)c)) { + case CHTYPE_TAB: /* expand the tab */ for (;;) { re_putc(el, ' ', 1); if ((el->el_refresh.r_cursor.h & 07) == 0) break; /* go until tab stop */ } - } else if (iscntrl(c)) { - re_putc(el, '^', 1); - if (c == '\177') - re_putc(el, '?', 1); - else - /* uncontrolify it; works only for iso8859-1 like sets */ - re_putc(el, (c | 0100), 1); - } else { - re_putc(el, '\\', 1); - re_putc(el, (int) ((((unsigned int) c >> 6) & 07) + '0'), 1); - re_putc(el, (int) ((((unsigned int) c >> 3) & 07) + '0'), 1); - re_putc(el, (c & 07) + '0', 1); + break; + case CHTYPE_NL: { + int oldv = el->el_refresh.r_cursor.v; + re_putc(el, '\0', 0); /* assure end of line */ + if (oldv == el->el_refresh.r_cursor.v) /* XXX */ + re_nextline(el); + break; + } + case CHTYPE_PRINT: + re_putc(el, c, 1); + break; + default: { + Char visbuf[VISUAL_WIDTH_MAX]; + ssize_t i, n = + ct_visual_char(visbuf, VISUAL_WIDTH_MAX, (Char)c); + for (i = 0; n-- > 0; ++i) + re_putc(el, visbuf[i], 1); + break; + } } } @@ -134,43 +162,31 @@ re_addc(EditLine *el, int c) * Draw the character given */ protected void -re_putc(EditLine *el, int c, int shift) +re_putc(EditLine *el, Int c, int shift) { + int i, w = Width(c); + ELRE_DEBUG(1, (__F, "printing %5x '%c'\r\n", c, c)); - ELRE_DEBUG(1, (__F, "printing %3.3o '%c'\r\n", c, c)); + while (shift && (el->el_refresh.r_cursor.h + w > el->el_terminal.t_size.h)) + re_putc(el, ' ', 1); + + el->el_vdisplay[el->el_refresh.r_cursor.v] + [el->el_refresh.r_cursor.h] = c; + /* assumes !shift is only used for single-column chars */ + i = w; + while (--i > 0) + el->el_vdisplay[el->el_refresh.r_cursor.v] + [el->el_refresh.r_cursor.h + i] = MB_FILL_CHAR; - el->el_vdisplay[el->el_refresh.r_cursor.v][el->el_refresh.r_cursor.h] = c; if (!shift) return; - el->el_refresh.r_cursor.h++; /* advance to next place */ - if (el->el_refresh.r_cursor.h >= el->el_term.t_size.h) { - el->el_vdisplay[el->el_refresh.r_cursor.v][el->el_term.t_size.h] = '\0'; + el->el_refresh.r_cursor.h += w; /* advance to next place */ + if (el->el_refresh.r_cursor.h >= el->el_terminal.t_size.h) { /* assure end of line */ - el->el_refresh.r_cursor.h = 0; /* reset it. */ - - /* - * If we would overflow (input is longer than terminal size), - * emulate scroll by dropping first line and shuffling the rest. - * We do this via pointer shuffling - it's safe in this case - * and we avoid memcpy(). - */ - if (el->el_refresh.r_cursor.v + 1 >= el->el_term.t_size.v) { - int i, lins = el->el_term.t_size.v; - char *firstline = el->el_vdisplay[0]; - - for(i=1; i < lins; i++) - el->el_vdisplay[i-1] = el->el_vdisplay[i]; - - firstline[0] = '\0'; /* empty the string */ - el->el_vdisplay[i-1] = firstline; - } else - el->el_refresh.r_cursor.v++; - - ELRE_ASSERT(el->el_refresh.r_cursor.v >= el->el_term.t_size.v, - (__F, "\r\nre_putc: overflow! r_cursor.v == %d > %d\r\n", - el->el_refresh.r_cursor.v, el->el_term.t_size.v), - abort()); + el->el_vdisplay[el->el_refresh.r_cursor.v][el->el_terminal.t_size.h] + = '\0'; + re_nextline(el); } } @@ -185,7 +201,7 @@ protected void re_refresh(EditLine *el) { int i, rhdiff; - char *cp, *st; + Char *cp, *st; coord_t cur; #ifdef notyet size_t termsz; @@ -220,7 +236,7 @@ re_refresh(EditLine *el) /* draw the current input buffer */ #if notyet - termsz = el->el_term.t_size.h * el->el_term.t_size.v; + termsz = el->el_terminal.t_size.h * el->el_terminal.t_size.v; if (el->el_line.lastchar - el->el_line.buffer > termsz) { /* * If line is longer than terminal, process only part @@ -229,26 +245,33 @@ re_refresh(EditLine *el) size_t rem = (el->el_line.lastchar-el->el_line.buffer)%termsz; st = el->el_line.lastchar - rem - - (termsz - (((rem / el->el_term.t_size.v) - 1) - * el->el_term.t_size.v)); + - (termsz - (((rem / el->el_terminal.t_size.v) - 1) + * el->el_terminal.t_size.v)); } else #endif st = el->el_line.buffer; for (cp = st; cp < el->el_line.lastchar; cp++) { if (cp == el->el_line.cursor) { + int w = Width(*cp); /* save for later */ cur.h = el->el_refresh.r_cursor.h; cur.v = el->el_refresh.r_cursor.v; + /* handle being at a linebroken doublewidth char */ + if (w > 1 && el->el_refresh.r_cursor.h + w > + el->el_terminal.t_size.h) { + cur.h = 0; + cur.v++; + } } - re_addc(el, (unsigned char) *cp); + re_addc(el, *cp); } if (cur.h == -1) { /* if I haven't been set yet, I'm at the end */ cur.h = el->el_refresh.r_cursor.h; cur.v = el->el_refresh.r_cursor.v; } - rhdiff = el->el_term.t_size.h - el->el_refresh.r_cursor.h - + rhdiff = el->el_terminal.t_size.h - el->el_refresh.r_cursor.h - el->el_rprompt.p_pos.h; if (el->el_rprompt.p_pos.h && !el->el_rprompt.p_pos.v && !el->el_refresh.r_cursor.v && rhdiff > 1) { @@ -271,8 +294,8 @@ re_refresh(EditLine *el) ELRE_DEBUG(1, (__F, "term.h=%d vcur.h=%d vcur.v=%d vdisplay[0]=\r\n:%80.80s:\r\n", - el->el_term.t_size.h, el->el_refresh.r_cursor.h, - el->el_refresh.r_cursor.v, el->el_vdisplay[0])); + el->el_terminal.t_size.h, el->el_refresh.r_cursor.h, + el->el_refresh.r_cursor.v, ct_encode_string(el->el_vdisplay[0]))); ELRE_DEBUG(1, (__F, "updating %d lines.\r\n", el->el_refresh.r_newcv)); for (i = 0; i <= el->el_refresh.r_newcv; i++) { @@ -287,7 +310,7 @@ re_refresh(EditLine *el) * leftover stuff. */ re__copy_and_pad(el->el_display[i], el->el_vdisplay[i], - (size_t) el->el_term.t_size.h); + (size_t) el->el_terminal.t_size.h); } ELRE_DEBUG(1, (__F, "\r\nel->el_refresh.r_cursor.v=%d,el->el_refresh.r_oldcv=%d i=%d\r\n", @@ -295,11 +318,12 @@ re_refresh(EditLine *el) if (el->el_refresh.r_oldcv > el->el_refresh.r_newcv) for (; i <= el->el_refresh.r_oldcv; i++) { - term_move_to_line(el, i); - term_move_to_char(el, 0); - term_clear_EOL(el, (int) strlen(el->el_display[i])); + terminal_move_to_line(el, i); + terminal_move_to_char(el, 0); + /* This Strlen should be safe even with MB_FILL_CHARs */ + terminal_clear_EOL(el, (int) Strlen(el->el_display[i])); #ifdef DEBUG_REFRESH - term_overwrite(el, "C\b", 2); + terminal_overwrite(el, "C\b", (size_t)2); #endif /* DEBUG_REFRESH */ el->el_display[i][0] = '\0'; } @@ -309,8 +333,8 @@ re_refresh(EditLine *el) "\r\ncursor.h = %d, cursor.v = %d, cur.h = %d, cur.v = %d\r\n", el->el_refresh.r_cursor.h, el->el_refresh.r_cursor.v, cur.h, cur.v)); - term_move_to_line(el, cur.v); /* go to where the cursor is */ - term_move_to_char(el, cur.h); + terminal_move_to_line(el, cur.v); /* go to where the cursor is */ + terminal_move_to_char(el, cur.h); } @@ -321,10 +345,10 @@ protected void re_goto_bottom(EditLine *el) { - term_move_to_line(el, el->el_refresh.r_oldcv); - term__putc(el, '\n'); + terminal_move_to_line(el, el->el_refresh.r_oldcv); + terminal__putc(el, '\n'); re_clear_display(el); - term__flush(el); + terminal__flush(el); } @@ -335,9 +359,9 @@ re_goto_bottom(EditLine *el) private void /*ARGSUSED*/ re_insert(EditLine *el __attribute__((__unused__)), - char *d, int dat, int dlen, char *s, int num) + Char *d, int dat, int dlen, Char *s, int num) { - char *a, *b; + Char *a, *b; if (num <= 0) return; @@ -346,8 +370,8 @@ re_insert(EditLine *el __attribute__((__unused__)), ELRE_DEBUG(1, (__F, "re_insert() starting: %d at %d max %d, d == \"%s\"\n", - num, dat, dlen, d)); - ELRE_DEBUG(1, (__F, "s == \"%s\"\n", s)); + num, dat, dlen, ct_encode_string(d))); + ELRE_DEBUG(1, (__F, "s == \"%s\"\n", ct_encode_string(s))); /* open up the space for num chars */ if (num > 0) { @@ -357,19 +381,24 @@ re_insert(EditLine *el __attribute__((__unused__)), *b-- = *a--; d[dlen] = '\0'; /* just in case */ } + ELRE_DEBUG(1, (__F, "re_insert() after insert: %d at %d max %d, d == \"%s\"\n", - num, dat, dlen, d)); - ELRE_DEBUG(1, (__F, "s == \"%s\"\n", s)); + num, dat, dlen, ct_encode_string(d))); + ELRE_DEBUG(1, (__F, "s == \"%s\"\n", ct_encode_string(s))); /* copy the characters */ for (a = d + dat; (a < d + dlen) && (num > 0); num--) *a++ = *s++; +#ifdef notyet + /* ct_encode_string() uses a static buffer, so we can't conveniently + * encode both d & s here */ ELRE_DEBUG(1, (__F, "re_insert() after copy: %d at %d max %d, %s == \"%s\"\n", num, dat, dlen, d, s)); ELRE_DEBUG(1, (__F, "s == \"%s\"\n", s)); +#endif } @@ -379,9 +408,9 @@ re_insert(EditLine *el __attribute__((__unused__)), private void /*ARGSUSED*/ re_delete(EditLine *el __attribute__((__unused__)), - char *d, int dat, int dlen, int num) + Char *d, int dat, int dlen, int num) { - char *a, *b; + Char *a, *b; if (num <= 0) return; @@ -391,7 +420,7 @@ re_delete(EditLine *el __attribute__((__unused__)), } ELRE_DEBUG(1, (__F, "re_delete() starting: %d at %d max %d, d == \"%s\"\n", - num, dat, dlen, d)); + num, dat, dlen, ct_encode_string(d))); /* open up the space for num chars */ if (num > 0) { @@ -403,7 +432,7 @@ re_delete(EditLine *el __attribute__((__unused__)), } ELRE_DEBUG(1, (__F, "re_delete() after delete: %d at %d max %d, d == \"%s\"\n", - num, dat, dlen, d)); + num, dat, dlen, ct_encode_string(d))); } @@ -411,7 +440,7 @@ re_delete(EditLine *el __attribute__((__unused__)), * Like strncpy without padding. */ private void -re__strncopy(char *a, char *b, size_t n) +re__strncopy(Char *a, Char *b, size_t n) { while (n-- && *b) @@ -422,7 +451,7 @@ re__strncopy(char *a, char *b, size_t n) * Find the number of characters we need to clear till the end of line * in order to make sure that we have cleared the previous contents of * the line. fx and sx is the number of characters inserted or deleted - * int the first or second diff, diff is the difference between the + * in the first or second diff, diff is the difference between the * number of characters between the new and old line. */ private void @@ -442,7 +471,7 @@ re_clear_eol(EditLine *el, int fx, int sx, int diff) diff = sx; ELRE_DEBUG(1, (__F, "re_clear_eol %d\n", diff)); - term_clear_EOL(el, diff); + terminal_clear_EOL(el, diff); } /***************************************************************** @@ -470,12 +499,13 @@ new: eddie> Oh, my little buggy says to me, as lurgid as #define MIN_END_KEEP 4 private void -re_update_line(EditLine *el, char *old, char *new, int i) +re_update_line(EditLine *el, Char *old, Char *new, int i) { - char *o, *n, *p, c; - char *ofd, *ols, *oe, *nfd, *nls, *ne; - char *osb, *ose, *nsb, *nse; + Char *o, *n, *p, c; + Char *ofd, *ols, *oe, *nfd, *nls, *ne; + Char *osb, *ose, *nsb, *nse; int fx, sx; + size_t len; /* * find first diff @@ -602,12 +632,12 @@ re_update_line(EditLine *el, char *old, char *new, int i) * fx is the number of characters we need to insert/delete: in the * beginning to bring the two same begins together */ - fx = (nsb - nfd) - (osb - ofd); + fx = (int)((nsb - nfd) - (osb - ofd)); /* * sx is the number of characters we need to insert/delete: in the * end to bring the two same last parts together */ - sx = (nls - nse) - (ols - ose); + sx = (int)((nls - nse) - (ols - ose)); if (!EL_CAN_INSERT) { if (fx > 0) { @@ -656,8 +686,8 @@ re_update_line(EditLine *el, char *old, char *new, int i) /* * Now that we are done with pragmatics we recompute fx, sx */ - fx = (nsb - nfd) - (osb - ofd); - sx = (nls - nse) - (ols - ose); + fx = (int)((nsb - nfd) - (osb - ofd)); + sx = (int)((nls - nse) - (ols - ose)); ELRE_DEBUG(1, (__F, "fx %d, sx %d\n", fx, sx)); ELRE_DEBUG(1, (__F, "ofd %d, osb %d, ose %d, ols %d, oe %d\n", @@ -688,7 +718,7 @@ re_update_line(EditLine *el, char *old, char *new, int i) * don't have to change the line, we don't move to it. el_cursor.h to * first diff char */ - term_move_to_line(el, i); + terminal_move_to_line(el, i); /* * at this point we have something like this: @@ -712,7 +742,7 @@ re_update_line(EditLine *el, char *old, char *new, int i) * if we have a net insert on the first difference, AND inserting the * net amount ((nsb-nfd) - (osb-ofd)) won't push the last useful * character (which is ne if nls != ne, otherwise is nse) off the edge - * of the screen (el->el_term.t_size.h) else we do the deletes first + * of the screen (el->el_terminal.t_size.h) else we do the deletes first * so that we keep everything we need to. */ @@ -734,13 +764,13 @@ re_update_line(EditLine *el, char *old, char *new, int i) * No insert or delete */ if ((nsb != nfd) && fx > 0 && - ((p - old) + fx <= el->el_term.t_size.h)) { + ((p - old) + fx <= el->el_terminal.t_size.h)) { ELRE_DEBUG(1, (__F, "first diff insert at %d...\r\n", nfd - new)); /* * Move to the first char to insert, where the first diff is. */ - term_move_to_char(el, nfd - new); + terminal_move_to_char(el, (int)(nfd - new)); /* * Check if we have stuff to keep at end */ @@ -752,21 +782,22 @@ re_update_line(EditLine *el, char *old, char *new, int i) if (fx > 0) { ELRE_DEBUG(!EL_CAN_INSERT, (__F, "ERROR: cannot insert in early first diff\n")); - term_insertwrite(el, nfd, fx); - re_insert(el, old, ofd - old, - el->el_term.t_size.h, nfd, fx); + terminal_insertwrite(el, nfd, fx); + re_insert(el, old, (int)(ofd - old), + el->el_terminal.t_size.h, nfd, fx); } /* * write (nsb-nfd) - fx chars of new starting at * (nfd + fx) */ - term_overwrite(el, nfd + fx, (nsb - nfd) - fx); - re__strncopy(ofd + fx, nfd + fx, - (size_t) ((nsb - nfd) - fx)); + len = (size_t) ((nsb - nfd) - fx); + terminal_overwrite(el, (nfd + fx), len); + re__strncopy(ofd + fx, nfd + fx, len); } else { ELRE_DEBUG(1, (__F, "without anything to save\r\n")); - term_overwrite(el, nfd, (nsb - nfd)); - re__strncopy(ofd, nfd, (size_t) (nsb - nfd)); + len = (size_t)(nsb - nfd); + terminal_overwrite(el, nfd, len); + re__strncopy(ofd, nfd, len); /* * Done */ @@ -778,7 +809,7 @@ re_update_line(EditLine *el, char *old, char *new, int i) /* * move to the first char to delete where the first diff is */ - term_move_to_char(el, ofd - old); + terminal_move_to_char(el, (int)(ofd - old)); /* * Check if we have stuff to save */ @@ -791,15 +822,16 @@ re_update_line(EditLine *el, char *old, char *new, int i) if (fx < 0) { ELRE_DEBUG(!EL_CAN_DELETE, (__F, "ERROR: cannot delete in first diff\n")); - term_deletechars(el, -fx); - re_delete(el, old, ofd - old, - el->el_term.t_size.h, -fx); + terminal_deletechars(el, -fx); + re_delete(el, old, (int)(ofd - old), + el->el_terminal.t_size.h, -fx); } /* * write (nsb-nfd) chars of new starting at nfd */ - term_overwrite(el, nfd, (nsb - nfd)); - re__strncopy(ofd, nfd, (size_t) (nsb - nfd)); + len = (size_t) (nsb - nfd); + terminal_overwrite(el, nfd, len); + re__strncopy(ofd, nfd, len); } else { ELRE_DEBUG(1, (__F, @@ -807,8 +839,9 @@ re_update_line(EditLine *el, char *old, char *new, int i) /* * write (nsb-nfd) chars of new starting at nfd */ - term_overwrite(el, nfd, (nsb - nfd)); - re_clear_eol(el, fx, sx, (oe - old) - (ne - new)); + terminal_overwrite(el, nfd, (size_t)(nsb - nfd)); + re_clear_eol(el, fx, sx, + (int)((oe - old) - (ne - new))); /* * Done */ @@ -817,7 +850,7 @@ re_update_line(EditLine *el, char *old, char *new, int i) } else fx = 0; - if (sx < 0 && (ose - old) + fx < el->el_term.t_size.h) { + if (sx < 0 && (ose - old) + fx < el->el_terminal.t_size.h) { ELRE_DEBUG(1, (__F, "second diff delete at %d...\r\n", (ose - old) + fx)); /* @@ -827,7 +860,7 @@ re_update_line(EditLine *el, char *old, char *new, int i) * fx is the number of characters inserted (+) or deleted (-) */ - term_move_to_char(el, (ose - old) + fx); + terminal_move_to_char(el, (int)((ose - old) + fx)); /* * Check if we have stuff to save */ @@ -839,17 +872,18 @@ re_update_line(EditLine *el, char *old, char *new, int i) if (sx < 0) { ELRE_DEBUG(!EL_CAN_DELETE, (__F, "ERROR: cannot delete in second diff\n")); - term_deletechars(el, -sx); + terminal_deletechars(el, -sx); } /* * write (nls-nse) chars of new starting at nse */ - term_overwrite(el, nse, (nls - nse)); + terminal_overwrite(el, nse, (size_t)(nls - nse)); } else { ELRE_DEBUG(1, (__F, "but with nothing left to save\r\n")); - term_overwrite(el, nse, (nls - nse)); - re_clear_eol(el, fx, sx, (oe - old) - (ne - new)); + terminal_overwrite(el, nse, (size_t)(nls - nse)); + re_clear_eol(el, fx, sx, + (int)((oe - old) - (ne - new))); } } /* @@ -859,7 +893,7 @@ re_update_line(EditLine *el, char *old, char *new, int i) ELRE_DEBUG(1, (__F, "late first diff insert at %d...\r\n", nfd - new)); - term_move_to_char(el, nfd - new); + terminal_move_to_char(el, (int)(nfd - new)); /* * Check if we have stuff to keep at the end */ @@ -870,28 +904,29 @@ re_update_line(EditLine *el, char *old, char *new, int i) * to zero above as a flag saying that we hadn't done * an early first insert. */ - fx = (nsb - nfd) - (osb - ofd); + fx = (int)((nsb - nfd) - (osb - ofd)); if (fx > 0) { /* * insert fx chars of new starting at nfd */ ELRE_DEBUG(!EL_CAN_INSERT, (__F, "ERROR: cannot insert in late first diff\n")); - term_insertwrite(el, nfd, fx); - re_insert(el, old, ofd - old, - el->el_term.t_size.h, nfd, fx); + terminal_insertwrite(el, nfd, fx); + re_insert(el, old, (int)(ofd - old), + el->el_terminal.t_size.h, nfd, fx); } /* * write (nsb-nfd) - fx chars of new starting at * (nfd + fx) */ - term_overwrite(el, nfd + fx, (nsb - nfd) - fx); - re__strncopy(ofd + fx, nfd + fx, - (size_t) ((nsb - nfd) - fx)); + len = (size_t) ((nsb - nfd) - fx); + terminal_overwrite(el, (nfd + fx), len); + re__strncopy(ofd + fx, nfd + fx, len); } else { ELRE_DEBUG(1, (__F, "without anything to save\r\n")); - term_overwrite(el, nfd, (nsb - nfd)); - re__strncopy(ofd, nfd, (size_t) (nsb - nfd)); + len = (size_t) (nsb - nfd); + terminal_overwrite(el, nfd, len); + re__strncopy(ofd, nfd, len); } } /* @@ -899,24 +934,25 @@ re_update_line(EditLine *el, char *old, char *new, int i) */ if (sx >= 0) { ELRE_DEBUG(1, (__F, - "second diff insert at %d...\r\n", nse - new)); - term_move_to_char(el, nse - new); + "second diff insert at %d...\r\n", (int)(nse - new))); + terminal_move_to_char(el, (int)(nse - new)); if (ols != oe) { ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n")); if (sx > 0) { /* insert sx chars of new starting at nse */ ELRE_DEBUG(!EL_CAN_INSERT, (__F, "ERROR: cannot insert in second diff\n")); - term_insertwrite(el, nse, sx); + terminal_insertwrite(el, nse, sx); } /* * write (nls-nse) - sx chars of new starting at * (nse + sx) */ - term_overwrite(el, nse + sx, (nls - nse) - sx); + terminal_overwrite(el, (nse + sx), + (size_t)((nls - nse) - sx)); } else { ELRE_DEBUG(1, (__F, "without anything to save\r\n")); - term_overwrite(el, nse, (nls - nse)); + terminal_overwrite(el, nse, (size_t)(nls - nse)); /* * No need to do a clear-to-end here because we were @@ -933,7 +969,7 @@ re_update_line(EditLine *el, char *old, char *new, int i) * Copy string and pad with spaces */ private void -re__copy_and_pad(char *dst, const char *src, size_t width) +re__copy_and_pad(Char *dst, const Char *src, size_t width) { size_t i; @@ -956,8 +992,8 @@ re__copy_and_pad(char *dst, const char *src, size_t width) protected void re_refresh_cursor(EditLine *el) { - char *cp, c; - int h, v, th; + Char *cp; + int h, v, th, w; if (el->el_line.cursor >= el->el_line.lastchar) { if (el->el_map.current == el->el_map.alt @@ -970,47 +1006,46 @@ re_refresh_cursor(EditLine *el) /* first we must find where the cursor is... */ h = el->el_prompt.p_pos.h; v = el->el_prompt.p_pos.v; - th = el->el_term.t_size.h; /* optimize for speed */ + th = el->el_terminal.t_size.h; /* optimize for speed */ /* do input buffer to el->el_line.cursor */ for (cp = el->el_line.buffer; cp < el->el_line.cursor; cp++) { - c = *cp; - h++; /* all chars at least this long */ - - if (c == '\n') {/* handle newline in data part too */ + switch (ct_chr_class(*cp)) { + case CHTYPE_NL: /* handle newline in data part too */ h = 0; v++; - } else { - if (c == '\t') { /* if a tab, to next tab stop */ - while (h & 07) { - h++; - } - } else if (iscntrl((unsigned char) c)) { - /* if control char */ - h++; - if (h > th) { /* if overflow, compensate */ - h = 1; - v++; - } - } else if (!el_isprint((unsigned char) c)) { - h += 3; - if (h > th) { /* if overflow, compensate */ - h = h - th; - v++; - } + break; + case CHTYPE_TAB: /* if a tab, to next tab stop */ + while (++h & 07) + continue; + break; + default: + w = Width(*cp); + if (w > 1 && h + w > th) { /* won't fit on line */ + h = 0; + v++; } - } + h += ct_visual_width(*cp); + break; + } if (h >= th) { /* check, extra long tabs picked up here also */ - h = 0; + h -= th; v++; } } + /* if we have a next character, and it's a doublewidth one, we need to + * check whether we need to linebreak for it to fit */ + if (cp < el->el_line.lastchar && (w = Width(*cp)) > 1) + if (h + w > th) { + h = 0; + v++; + } /* now go there */ - term_move_to_line(el, v); - term_move_to_char(el, h); - term__flush(el); + terminal_move_to_line(el, v); + terminal_move_to_char(el, h); + terminal__flush(el); } @@ -1018,12 +1053,19 @@ re_refresh_cursor(EditLine *el) * Add a character fast. */ private void -re_fastputc(EditLine *el, int c) +re_fastputc(EditLine *el, Int c) { + int w = Width((Char)c); + while (w > 1 && el->el_cursor.h + w > el->el_terminal.t_size.h) + re_fastputc(el, ' '); - term__putc(el, c); + terminal__putc(el, c); el->el_display[el->el_cursor.v][el->el_cursor.h++] = c; - if (el->el_cursor.h >= el->el_term.t_size.h) { + while (--w > 0) + el->el_display[el->el_cursor.v][el->el_cursor.h++] + = MB_FILL_CHAR; + + if (el->el_cursor.h >= el->el_terminal.t_size.h) { /* if we must overflow */ el->el_cursor.h = 0; @@ -1033,27 +1075,27 @@ re_fastputc(EditLine *el, int c) * We do this via pointer shuffling - it's safe in this case * and we avoid memcpy(). */ - if (el->el_cursor.v + 1 >= el->el_term.t_size.v) { - int i, lins = el->el_term.t_size.v; - char *firstline = el->el_display[0]; + if (el->el_cursor.v + 1 >= el->el_terminal.t_size.v) { + int i, lins = el->el_terminal.t_size.v; + Char *firstline = el->el_display[0]; - for(i=1; i < lins; i++) - el->el_display[i-1] = el->el_display[i]; + for(i = 1; i < lins; i++) + el->el_display[i - 1] = el->el_display[i]; - re__copy_and_pad(firstline, "", 0); - el->el_display[i-1] = firstline; + re__copy_and_pad(firstline, STR(""), (size_t)0); + el->el_display[i - 1] = firstline; } else { el->el_cursor.v++; el->el_refresh.r_oldcv++; } if (EL_HAS_AUTO_MARGINS) { if (EL_HAS_MAGIC_MARGINS) { - term__putc(el, ' '); - term__putc(el, '\b'); + terminal__putc(el, ' '); + terminal__putc(el, '\b'); } } else { - term__putc(el, '\r'); - term__putc(el, '\n'); + terminal__putc(el, '\r'); + terminal__putc(el, '\n'); } } } @@ -1066,7 +1108,7 @@ re_fastputc(EditLine *el, int c) protected void re_fastaddc(EditLine *el) { - char c; + Char c; int rhdiff; c = el->el_line.cursor[-1]; @@ -1075,25 +1117,30 @@ re_fastaddc(EditLine *el) re_refresh(el); /* too hard to handle */ return; } - rhdiff = el->el_term.t_size.h - el->el_cursor.h - + rhdiff = el->el_terminal.t_size.h - el->el_cursor.h - el->el_rprompt.p_pos.h; if (el->el_rprompt.p_pos.h && rhdiff < 3) { re_refresh(el); /* clear out rprompt if less than 1 char gap */ return; } /* else (only do at end of line, no TAB) */ - if (iscntrl((unsigned char) c)) { /* if control char, do caret */ - char mc = (c == '\177') ? '?' : (c | 0100); - re_fastputc(el, '^'); - re_fastputc(el, mc); - } else if (el_isprint((unsigned char) c)) { /* normal char */ + switch (ct_chr_class(c)) { + case CHTYPE_TAB: /* already handled, should never happen here */ + break; + case CHTYPE_NL: + case CHTYPE_PRINT: re_fastputc(el, c); - } else { - re_fastputc(el, '\\'); - re_fastputc(el, (int)(((((unsigned int)c) >> 6) & 3) + '0')); - re_fastputc(el, (int)(((((unsigned int)c) >> 3) & 7) + '0')); - re_fastputc(el, (c & 7) + '0'); + break; + case CHTYPE_ASCIICTL: + case CHTYPE_NONPRINT: { + Char visbuf[VISUAL_WIDTH_MAX]; + ssize_t i, n = + ct_visual_char(visbuf, VISUAL_WIDTH_MAX, (Char)c); + for (i = 0; n-- > 0; ++i) + re_fastputc(el, visbuf[i]); + break; } - term__flush(el); + } + terminal__flush(el); } @@ -1107,7 +1154,7 @@ re_clear_display(EditLine *el) el->el_cursor.v = 0; el->el_cursor.h = 0; - for (i = 0; i < el->el_term.t_size.v; i++) + for (i = 0; i < el->el_terminal.t_size.v; i++) el->el_display[i][0] = '\0'; el->el_refresh.r_oldcv = 0; } @@ -1122,17 +1169,16 @@ re_clear_lines(EditLine *el) if (EL_CAN_CEOL) { int i; - term_move_to_char(el, 0); - for (i = 0; i <= el->el_refresh.r_oldcv; i++) { + for (i = el->el_refresh.r_oldcv; i >= 0; i--) { /* for each line on the screen */ - term_move_to_line(el, i); - term_clear_EOL(el, el->el_term.t_size.h); + terminal_move_to_line(el, i); + terminal_move_to_char(el, 0); + terminal_clear_EOL(el, el->el_terminal.t_size.h); } - term_move_to_line(el, 0); } else { - term_move_to_line(el, el->el_refresh.r_oldcv); + terminal_move_to_line(el, el->el_refresh.r_oldcv); /* go to last line */ - term__putc(el, '\r'); /* go to BOL */ - term__putc(el, '\n'); /* go to new line */ + terminal__putc(el, '\r'); /* go to BOL */ + terminal__putc(el, '\n'); /* go to new line */ } } diff --git a/cmd-line-utils/libedit/refresh.h b/cmd-line-utils/libedit/refresh.h index dd2bd02094b..f80be463545 100644 --- a/cmd-line-utils/libedit/refresh.h +++ b/cmd-line-utils/libedit/refresh.h @@ -1,4 +1,4 @@ -/* $NetBSD: refresh.h,v 1.5 2003/08/07 16:44:33 agc Exp $ */ +/* $NetBSD: refresh.h,v 1.6 2009/12/30 22:37:40 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -48,7 +48,7 @@ typedef struct { int r_newcv; } el_refresh_t; -protected void re_putc(EditLine *, int, int); +protected void re_putc(EditLine *, Int, int); protected void re_clear_lines(EditLine *); protected void re_clear_display(EditLine *); protected void re_refresh(EditLine *); diff --git a/cmd-line-utils/libedit/search.c b/cmd-line-utils/libedit/search.c index df50c7e7370..2324cc94d76 100644 --- a/cmd-line-utils/libedit/search.c +++ b/cmd-line-utils/libedit/search.c @@ -1,4 +1,4 @@ -/* $NetBSD: search.c,v 1.20 2004/11/04 01:16:03 christos Exp $ */ +/* $NetBSD: search.c,v 1.30 2011/10/04 15:27:04 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -65,15 +65,16 @@ protected int search_init(EditLine *el) { - el->el_search.patbuf = (char *) el_malloc(EL_BUFSIZ); + el->el_search.patbuf = el_malloc(EL_BUFSIZ * + sizeof(*el->el_search.patbuf)); if (el->el_search.patbuf == NULL) - return (-1); + return -1; el->el_search.patlen = 0; el->el_search.patdir = -1; el->el_search.chacha = '\0'; el->el_search.chadir = CHAR_FWD; el->el_search.chatflg = 0; - return (0); + return 0; } @@ -84,7 +85,7 @@ protected void search_end(EditLine *el) { - el_free((ptr_t) el->el_search.patbuf); + el_free(el->el_search.patbuf); el->el_search.patbuf = NULL; } @@ -105,8 +106,11 @@ regerror(const char *msg) * Return if string matches pattern */ protected int -el_match(const char *str, const char *pat) +el_match(const Char *str, const Char *pat) { +#ifdef WIDECHAR + static ct_buffer_t conv; +#endif #if defined (REGEX) regex_t re; int rv; @@ -118,30 +122,31 @@ el_match(const char *str, const char *pat) extern int re_exec(const char *); #endif - if (strstr(str, pat) != NULL) - return (1); + if (Strstr(str, pat) != 0) + return 1; #if defined(REGEX) - if (regcomp(&re, pat, 0) == 0) { - rv = regexec(&re, str, 0, NULL, 0) == 0; + if (regcomp(&re, ct_encode_string(pat, &conv), 0) == 0) { + rv = regexec(&re, ct_encode_string(str, &conv), (size_t)0, NULL, + 0) == 0; regfree(&re); } else { rv = 0; } - return (rv); + return rv; #elif defined(REGEXP) - if ((re = regcomp(pat)) != NULL) { - rv = regexec(re, str); - free((ptr_t) re); + if ((re = regcomp(ct_encode_string(pat, &conv))) != NULL) { + rv = regexec(re, ct_encode_string(str, &conv)); + el_free(re); } else { rv = 0; } - return (rv); + return rv; #else - if (re_comp(pat) != NULL) - return (0); + if (re_comp(ct_encode_string(pat, &conv)) != NULL) + return 0; else - return (re_exec(str) == 1); + return re_exec(ct_encode_string(str, &conv) == 1); #endif } @@ -150,14 +155,14 @@ el_match(const char *str, const char *pat) * return True if the pattern matches the prefix */ protected int -c_hmatch(EditLine *el, const char *str) +c_hmatch(EditLine *el, const Char *str) { #ifdef SDEBUG (void) fprintf(el->el_errfile, "match `%s' with `%s'\n", el->el_search.patbuf, str); #endif /* SDEBUG */ - return (el_match(str, el->el_search.patbuf)); + return el_match(str, el->el_search.patbuf); } @@ -169,15 +174,16 @@ c_setpat(EditLine *el) { if (el->el_state.lastcmd != ED_SEARCH_PREV_HISTORY && el->el_state.lastcmd != ED_SEARCH_NEXT_HISTORY) { - el->el_search.patlen = EL_CURSOR(el) - el->el_line.buffer; + el->el_search.patlen = + (size_t)(EL_CURSOR(el) - el->el_line.buffer); if (el->el_search.patlen >= EL_BUFSIZ) el->el_search.patlen = EL_BUFSIZ - 1; if (el->el_search.patlen != 0) { - (void) strncpy(el->el_search.patbuf, el->el_line.buffer, + (void) Strncpy(el->el_search.patbuf, el->el_line.buffer, el->el_search.patlen); el->el_search.patbuf[el->el_search.patlen] = '\0'; } else - el->el_search.patlen = strlen(el->el_search.patbuf); + el->el_search.patlen = Strlen(el->el_search.patbuf); } #ifdef SDEBUG (void) fprintf(el->el_errfile, "\neventno = %d\n", @@ -198,23 +204,24 @@ c_setpat(EditLine *el) protected el_action_t ce_inc_search(EditLine *el, int dir) { - static const char STRfwd[] = {'f', 'w', 'd', '\0'}, + static const Char STRfwd[] = {'f', 'w', 'd', '\0'}, STRbck[] = {'b', 'c', 'k', '\0'}; - static char pchar = ':';/* ':' = normal, '?' = failed */ - static char endcmd[2] = {'\0', '\0'}; - char ch, *ocursor = el->el_line.cursor, oldpchar = pchar; - const char *cp; + static Char pchar = ':';/* ':' = normal, '?' = failed */ + static Char endcmd[2] = {'\0', '\0'}; + Char ch, *ocursor = el->el_line.cursor, oldpchar = pchar; + const Char *cp; el_action_t ret = CC_NORM; int ohisteventno = el->el_history.eventno; - int oldpatlen = el->el_search.patlen; + size_t oldpatlen = el->el_search.patlen; int newdir = dir; int done, redo; - if (el->el_line.lastchar + sizeof(STRfwd) / sizeof(char) + 2 + + if (el->el_line.lastchar + sizeof(STRfwd) / + sizeof(*el->el_line.lastchar) + 2 + el->el_search.patlen >= el->el_line.limit) - return (CC_ERROR); + return CC_ERROR; for (;;) { @@ -241,14 +248,14 @@ ce_inc_search(EditLine *el, int dir) *el->el_line.lastchar = '\0'; re_refresh(el); - if (el_getc(el, &ch) != 1) - return (ed_end_of_file(el, 0)); + if (FUN(el,getc)(el, &ch) != 1) + return ed_end_of_file(el, 0); switch (el->el_map.current[(unsigned char) ch]) { case ED_INSERT: case ED_DIGIT: if (el->el_search.patlen >= EL_BUFSIZ - LEN) - term_beep(el); + terminal_beep(el); else { el->el_search.patbuf[el->el_search.patlen++] = ch; @@ -273,7 +280,7 @@ ce_inc_search(EditLine *el, int dir) if (el->el_search.patlen > LEN) done++; else - term_beep(el); + terminal_beep(el); break; default: @@ -297,7 +304,7 @@ ce_inc_search(EditLine *el, int dir) *el->el_line.cursor != '\n') { if (el->el_search.patlen >= EL_BUFSIZ - LEN) { - term_beep(el); + terminal_beep(el); break; } el->el_search.patbuf[el->el_search.patlen++] = @@ -310,14 +317,14 @@ ce_inc_search(EditLine *el, int dir) re_refresh(el); break; } else if (isglob(*cp)) { - term_beep(el); + terminal_beep(el); break; } break; default: /* Terminate and execute cmd */ endcmd[0] = ch; - el_push(el, endcmd); + FUN(el,push)(el, endcmd); /* FALLTHROUGH */ case 0033: /* ESC: Terminate */ @@ -379,9 +386,10 @@ ce_inc_search(EditLine *el, int dir) /* avoid c_setpat */ el->el_state.lastcmd = (el_action_t) newdir; - ret = newdir == ED_SEARCH_PREV_HISTORY ? + ret = (el_action_t) + (newdir == ED_SEARCH_PREV_HISTORY ? ed_search_prev_history(el, 0) : - ed_search_next_history(el, 0); + ed_search_next_history(el, 0)); if (ret != CC_ERROR) { el->el_line.cursor = newdir == ED_SEARCH_PREV_HISTORY ? @@ -395,13 +403,13 @@ ce_inc_search(EditLine *el, int dir) el->el_search.patbuf[el->el_search.patlen] = '\0'; if (ret == CC_ERROR) { - term_beep(el); + terminal_beep(el); if (el->el_history.eventno != ohisteventno) { el->el_history.eventno = ohisteventno; if (hist_get(el) == CC_ERROR) - return (CC_ERROR); + return CC_ERROR; } el->el_line.cursor = ocursor; pchar = '?'; @@ -426,14 +434,14 @@ ce_inc_search(EditLine *el, int dir) if (el->el_history.eventno != ohisteventno) { el->el_history.eventno = ohisteventno; if (hist_get(el) == CC_ERROR) - return (CC_ERROR); + return CC_ERROR; } el->el_line.cursor = ocursor; if (ret == CC_ERROR) re_refresh(el); } if (done || ret != CC_NORM) - return (ret); + return ret; } } @@ -444,9 +452,9 @@ ce_inc_search(EditLine *el, int dir) protected el_action_t cv_search(EditLine *el, int dir) { - char ch; - char tmpbuf[EL_BUFSIZ]; - int tmplen; + Char ch; + Char tmpbuf[EL_BUFSIZ]; + ssize_t tmplen; #ifdef ANCHOR tmpbuf[0] = '.'; @@ -457,7 +465,7 @@ cv_search(EditLine *el, int dir) el->el_search.patdir = dir; tmplen = c_gets(el, &tmpbuf[LEN], - dir == ED_SEARCH_PREV_HISTORY ? "\n/" : "\n?" ); + dir == ED_SEARCH_PREV_HISTORY ? STR("\n/") : STR("\n?") ); if (tmplen == -1) return CC_REFRESH; @@ -471,16 +479,16 @@ cv_search(EditLine *el, int dir) */ if (el->el_search.patlen == 0) { re_refresh(el); - return (CC_ERROR); + return CC_ERROR; } #ifdef ANCHOR if (el->el_search.patbuf[0] != '.' && el->el_search.patbuf[0] != '*') { - (void) strncpy(tmpbuf, el->el_search.patbuf, - sizeof(tmpbuf) - 1); + (void) Strncpy(tmpbuf, el->el_search.patbuf, + sizeof(tmpbuf) / sizeof(*tmpbuf) - 1); el->el_search.patbuf[0] = '.'; el->el_search.patbuf[1] = '*'; - (void) strncpy(&el->el_search.patbuf[2], tmpbuf, + (void) Strncpy(&el->el_search.patbuf[2], tmpbuf, EL_BUFSIZ - 3); el->el_search.patlen++; el->el_search.patbuf[el->el_search.patlen++] = '.'; @@ -494,21 +502,21 @@ cv_search(EditLine *el, int dir) tmpbuf[tmplen++] = '*'; #endif tmpbuf[tmplen] = '\0'; - (void) strncpy(el->el_search.patbuf, tmpbuf, EL_BUFSIZ - 1); - el->el_search.patlen = tmplen; + (void) Strncpy(el->el_search.patbuf, tmpbuf, EL_BUFSIZ - 1); + el->el_search.patlen = (size_t)tmplen; } el->el_state.lastcmd = (el_action_t) dir; /* avoid c_setpat */ el->el_line.cursor = el->el_line.lastchar = el->el_line.buffer; if ((dir == ED_SEARCH_PREV_HISTORY ? ed_search_prev_history(el, 0) : ed_search_next_history(el, 0)) == CC_ERROR) { re_refresh(el); - return (CC_ERROR); + return CC_ERROR; } if (ch == 0033) { re_refresh(el); return ed_newline(el, 0); } - return (CC_REFRESH); + return CC_REFRESH; } @@ -518,9 +526,9 @@ cv_search(EditLine *el, int dir) protected el_action_t ce_search_line(EditLine *el, int dir) { - char *cp = el->el_line.cursor; - char *pattern = el->el_search.patbuf; - char oc, *ocp; + Char *cp = el->el_line.cursor; + Char *pattern = el->el_search.patbuf; + Char oc, *ocp; #ifdef ANCHOR ocp = &pattern[1]; oc = *ocp; @@ -535,21 +543,21 @@ ce_search_line(EditLine *el, int dir) if (el_match(cp, ocp)) { *ocp = oc; el->el_line.cursor = cp; - return (CC_NORM); + return CC_NORM; } } *ocp = oc; - return (CC_ERROR); + return CC_ERROR; } else { for (; *cp != '\0' && cp < el->el_line.limit; cp++) { if (el_match(cp, ocp)) { *ocp = oc; el->el_line.cursor = cp; - return (CC_NORM); + return CC_NORM; } } *ocp = oc; - return (CC_ERROR); + return CC_ERROR; } } @@ -558,12 +566,12 @@ ce_search_line(EditLine *el, int dir) * Vi repeat search */ protected el_action_t -cv_repeat_srch(EditLine *el, int c) +cv_repeat_srch(EditLine *el, Int c) { #ifdef SDEBUG (void) fprintf(el->el_errfile, "dir %d patlen %d patbuf %s\n", - c, el->el_search.patlen, el->el_search.patbuf); + c, el->el_search.patlen, ct_encode_string(el->el_search.patbuf)); #endif el->el_state.lastcmd = (el_action_t) c; /* Hack to stop c_setpat */ @@ -571,11 +579,11 @@ cv_repeat_srch(EditLine *el, int c) switch (c) { case ED_SEARCH_NEXT_HISTORY: - return (ed_search_next_history(el, 0)); + return ed_search_next_history(el, 0); case ED_SEARCH_PREV_HISTORY: - return (ed_search_prev_history(el, 0)); + return ed_search_prev_history(el, 0); default: - return (CC_ERROR); + return CC_ERROR; } } @@ -584,16 +592,16 @@ cv_repeat_srch(EditLine *el, int c) * Vi character search */ protected el_action_t -cv_csearch(EditLine *el, int direction, int ch, int count, int tflag) +cv_csearch(EditLine *el, int direction, Int ch, int count, int tflag) { - char *cp; + Char *cp; if (ch == 0) return CC_ERROR; - if (ch == -1) { - char c; - if (el_getc(el, &c) != 1) + if (ch == (Int)-1) { + Char c; + if (FUN(el,getc)(el, &c) != 1) return ed_end_of_file(el, 0); ch = c; } @@ -601,18 +609,18 @@ cv_csearch(EditLine *el, int direction, int ch, int count, int tflag) /* Save for ';' and ',' commands */ el->el_search.chacha = ch; el->el_search.chadir = direction; - el->el_search.chatflg = tflag; + el->el_search.chatflg = (char)tflag; cp = el->el_line.cursor; while (count--) { - if (*cp == ch) + if ((Int)*cp == ch) cp += direction; for (;;cp += direction) { if (cp >= el->el_line.lastchar) return CC_ERROR; if (cp < el->el_line.buffer) return CC_ERROR; - if (*cp == ch) + if ((Int)*cp == ch) break; } } diff --git a/cmd-line-utils/libedit/search.h b/cmd-line-utils/libedit/search.h index 2aa8f985013..d9f27e56185 100644 --- a/cmd-line-utils/libedit/search.h +++ b/cmd-line-utils/libedit/search.h @@ -1,4 +1,4 @@ -/* $NetBSD: search.h,v 1.8 2003/10/18 23:27:36 christos Exp $ */ +/* $NetBSD: search.h,v 1.9 2009/12/30 22:37:40 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -43,24 +43,24 @@ #include "histedit.h" typedef struct el_search_t { - char *patbuf; /* The pattern buffer */ + Char *patbuf; /* The pattern buffer */ size_t patlen; /* Length of the pattern buffer */ int patdir; /* Direction of the last search */ int chadir; /* Character search direction */ - char chacha; /* Character we are looking for */ + Char chacha; /* Character we are looking for */ char chatflg; /* 0 if f, 1 if t */ } el_search_t; -protected int el_match(const char *, const char *); +protected int el_match(const Char *, const Char *); protected int search_init(EditLine *); protected void search_end(EditLine *); -protected int c_hmatch(EditLine *, const char *); +protected int c_hmatch(EditLine *, const Char *); protected void c_setpat(EditLine *); protected el_action_t ce_inc_search(EditLine *, int); protected el_action_t cv_search(EditLine *, int); protected el_action_t ce_search_line(EditLine *, int); -protected el_action_t cv_repeat_srch(EditLine *, int); -protected el_action_t cv_csearch(EditLine *, int, int, int, int); +protected el_action_t cv_repeat_srch(EditLine *, Int); +protected el_action_t cv_csearch(EditLine *, int, Int, int, int); #endif /* _h_el_search */ diff --git a/cmd-line-utils/libedit/sig.c b/cmd-line-utils/libedit/sig.c index 5307ee6ec60..986ad5792e2 100644 --- a/cmd-line-utils/libedit/sig.c +++ b/cmd-line-utils/libedit/sig.c @@ -1,4 +1,4 @@ -/* $NetBSD: sig.c,v 1.12 2008/09/10 15:45:37 christos Exp $ */ +/* $NetBSD: sig.c,v 1.17 2011/07/28 20:50:55 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -57,15 +57,15 @@ private const int sighdl[] = { - 1 }; -private void el_sig_handler(int); +private void sig_handler(int); -/* el_sig_handler(): +/* sig_handler(): * This is the handler called for all signals * XXX: we cannot pass any data so we just store the old editline * state in a private variable */ private void -el_sig_handler(int signo) +sig_handler(int signo) { int i; sigset_t nset, oset; @@ -74,12 +74,14 @@ el_sig_handler(int signo) (void) sigaddset(&nset, signo); (void) sigprocmask(SIG_BLOCK, &nset, &oset); + sel->el_signal->sig_no = signo; + switch (signo) { case SIGCONT: tty_rawmode(sel); if (ed_redisplay(sel, 0) == CC_REFRESH) re_refresh(sel); - term__flush(sel); + terminal__flush(sel); break; case SIGWINCH: @@ -95,7 +97,10 @@ el_sig_handler(int signo) if (signo == sighdl[i]) break; - (void) signal(signo, sel->el_signal[i]); + (void) sigaction(signo, &sel->el_signal->sig_action[i], NULL); + sel->el_signal->sig_action[i].sa_handler = SIG_ERR; + sel->el_signal->sig_action[i].sa_flags = 0; + sigemptyset(&sel->el_signal->sig_action[i].sa_mask); (void) sigprocmask(SIG_SETMASK, &oset, NULL); (void) kill(0, signo); } @@ -107,26 +112,29 @@ el_sig_handler(int signo) protected int sig_init(EditLine *el) { - int i; - sigset_t nset, oset; + size_t i; + sigset_t *nset, oset; - (void) sigemptyset(&nset); -#define _DO(a) (void) sigaddset(&nset, a); + el->el_signal = el_malloc(sizeof(*el->el_signal)); + if (el->el_signal == NULL) + return -1; + + nset = &el->el_signal->sig_set; + (void) sigemptyset(nset); +#define _DO(a) (void) sigaddset(nset, a); ALLSIGS #undef _DO - (void) sigprocmask(SIG_BLOCK, &nset, &oset); + (void) sigprocmask(SIG_BLOCK, nset, &oset); -#define SIGSIZE (sizeof(sighdl) / sizeof(sighdl[0]) * sizeof(el_signalhandler_t)) - - el->el_signal = (el_signalhandler_t *) el_malloc(SIGSIZE); - if (el->el_signal == NULL) - return (-1); - for (i = 0; sighdl[i] != -1; i++) - el->el_signal[i] = SIG_ERR; + for (i = 0; sighdl[i] != -1; i++) { + el->el_signal->sig_action[i].sa_handler = SIG_ERR; + el->el_signal->sig_action[i].sa_flags = 0; + sigemptyset(&el->el_signal->sig_action[i].sa_mask); + } (void) sigprocmask(SIG_SETMASK, &oset, NULL); - return (0); + return 0; } @@ -137,7 +145,7 @@ protected void sig_end(EditLine *el) { - el_free((ptr_t) el->el_signal); + el_free(el->el_signal); el->el_signal = NULL; } @@ -148,20 +156,21 @@ sig_end(EditLine *el) protected void sig_set(EditLine *el) { - int i; - sigset_t nset, oset; + size_t i; + sigset_t oset; + struct sigaction osa, nsa; - (void) sigemptyset(&nset); -#define _DO(a) (void) sigaddset(&nset, a); - ALLSIGS -#undef _DO - (void) sigprocmask(SIG_BLOCK, &nset, &oset); + nsa.sa_handler = sig_handler; + nsa.sa_flags = 0; + sigemptyset(&nsa.sa_mask); + + (void) sigprocmask(SIG_BLOCK, &el->el_signal->sig_set, &oset); for (i = 0; sighdl[i] != -1; i++) { - el_signalhandler_t s; /* This could happen if we get interrupted */ - if ((s = signal(sighdl[i], el_sig_handler)) != el_sig_handler) - el->el_signal[i] = s; + if (sigaction(sighdl[i], &nsa, &osa) != -1 && + osa.sa_handler != sig_handler) + el->el_signal->sig_action[i] = osa; } sel = el; (void) sigprocmask(SIG_SETMASK, &oset, NULL); @@ -174,20 +183,17 @@ sig_set(EditLine *el) protected void sig_clr(EditLine *el) { - int i; - sigset_t nset, oset; + size_t i; + sigset_t oset; - (void) sigemptyset(&nset); -#define _DO(a) (void) sigaddset(&nset, a); - ALLSIGS -#undef _DO - (void) sigprocmask(SIG_BLOCK, &nset, &oset); + (void) sigprocmask(SIG_BLOCK, &el->el_signal->sig_set, &oset); for (i = 0; sighdl[i] != -1; i++) - if (el->el_signal[i] != SIG_ERR) - (void) signal(sighdl[i], el->el_signal[i]); + if (el->el_signal->sig_action[i].sa_handler != SIG_ERR) + (void)sigaction(sighdl[i], + &el->el_signal->sig_action[i], NULL); sel = NULL; /* we are going to die if the handler is * called */ - (void) sigprocmask(SIG_SETMASK, &oset, NULL); + (void)sigprocmask(SIG_SETMASK, &oset, NULL); } diff --git a/cmd-line-utils/libedit/sig.h b/cmd-line-utils/libedit/sig.h index 2bd3c516d46..c957cfdf5a7 100644 --- a/cmd-line-utils/libedit/sig.h +++ b/cmd-line-utils/libedit/sig.h @@ -1,4 +1,4 @@ -/* $NetBSD: sig.h,v 1.6 2008/07/12 15:27:14 christos Exp $ */ +/* $NetBSD: sig.h,v 1.8 2009/02/19 15:20:22 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -56,9 +56,13 @@ _DO(SIGTERM) \ _DO(SIGCONT) \ _DO(SIGWINCH) +#define ALLSIGSNO 7 -typedef void (*el_signalhandler_t)(int); -typedef el_signalhandler_t *el_signal_t; +typedef struct { + struct sigaction sig_action[ALLSIGSNO]; + sigset_t sig_set; + volatile sig_atomic_t sig_no; +} *el_signal_t; protected void sig_end(EditLine*); protected int sig_init(EditLine*); diff --git a/cmd-line-utils/libedit/sys.h b/cmd-line-utils/libedit/sys.h index a0369affbb0..2731fb5f30e 100644 --- a/cmd-line-utils/libedit/sys.h +++ b/cmd-line-utils/libedit/sys.h @@ -1,4 +1,4 @@ -/* $NetBSD: sys.h,v 1.9 2004/01/17 17:57:40 christos Exp $ */ +/* $NetBSD: sys.h,v 1.17 2011/09/28 14:08:04 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -48,14 +48,6 @@ # define __attribute__(A) #endif -#ifndef _DIAGASSERT -# define _DIAGASSERT(x) -#endif - -#ifndef SIZE_T_MAX -# define SIZE_T_MAX UINT_MAX -#endif - #ifndef __BEGIN_DECLS # ifdef __cplusplus # define __BEGIN_DECLS extern "C" { @@ -79,18 +71,8 @@ /* When we want to hide everything */ #endif -#ifndef HAVE_U_INT32_T -typedef unsigned int u_int32_t; -#endif - -#ifndef _PTR_T -# define _PTR_T -typedef void *ptr_t; -#endif - -#ifndef _IOCTL_T -# define _IOCTL_T -typedef void *ioctl_t; +#ifndef __arraycount +# define __arraycount(a) (sizeof(a) / sizeof(*(a))) #endif #include @@ -110,10 +92,31 @@ size_t strlcpy(char *dst, const char *src, size_t size); char *fgetln(FILE *fp, size_t *len); #endif +#ifndef HAVE_WCSDUP +#include +wchar_t *wcsdup(const wchar_t *); +#endif + +#ifndef _DIAGASSERT +#define _DIAGASSERT(x) +#endif + +#ifndef __RCSID +#define __RCSID(x) +#endif + +#ifndef HAVE_U_INT32_T +typedef unsigned int u_int32_t; +#endif + +#ifndef SIZE_T_MAX +#define SIZE_T_MAX ((size_t)-1) +#endif + #define REGEX /* Use POSIX.2 regular expression functions */ #undef REGEXP /* Use UNIX V8 regular expression functions */ -#ifdef __SunOS +#if defined(__sun) extern int tgetent(char *, const char *); extern int tgetflag(char *); extern int tgetnum(char *); @@ -162,8 +165,8 @@ extern void perror(const char *); # define strerror(e) sys_errlist[e] # endif # ifdef SABER -extern ptr_t memcpy(ptr_t, const ptr_t, size_t); -extern ptr_t memset(ptr_t, int, size_t); +extern void * memcpy(void *, const void *, size_t); +extern void * memset(void *, int, size_t); # endif extern char *fgetline(FILE *, int *); #endif diff --git a/cmd-line-utils/libedit/term.c b/cmd-line-utils/libedit/terminal.c similarity index 56% rename from cmd-line-utils/libedit/term.c rename to cmd-line-utils/libedit/terminal.c index 2f1aefa7117..ae91d9afe92 100644 --- a/cmd-line-utils/libedit/term.c +++ b/cmd-line-utils/libedit/terminal.c @@ -1,4 +1,4 @@ -/* $NetBSD: term.c,v 1.48 2009/02/06 20:08:13 sketch Exp $ */ +/* $NetBSD: terminal.c,v 1.10 2011/10/04 15:27:04 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -41,15 +41,16 @@ static char sccsid[] = "@(#)term.c 8.2 (Berkeley) 4/30/95"; #endif /* not lint && not SCCSID */ /* - * term.c: Editor/termcap-curses interface - * We have to declare a static variable here, since the - * termcap putchar routine does not take an argument! + * terminal.c: Editor/termcap-curses interface + * We have to declare a static variable here, since the + * termcap putchar routine does not take an argument! */ #include #include #include #include #include +#include #if 0 /* TODO: do we need this */ #ifdef HAVE_TERMCAP_H #include @@ -57,14 +58,15 @@ static char sccsid[] = "@(#)term.c 8.2 (Berkeley) 4/30/95"; #endif #ifdef HAVE_CURSES_H #include -#endif -#ifdef HAVE_NCURSES_H +#elif HAVE_NCURSES_H #include #endif -/* Don't use Solaris's term.h. */ -#if (defined(HAVE_TERM_H) && !defined(__SunOS)) + +/* Solaris's term.h does horrid things. */ +#if defined(HAVE_TERM_H) && !defined(__sun) #include #endif + #include #include @@ -76,89 +78,17 @@ static char sccsid[] = "@(#)term.c 8.2 (Berkeley) 4/30/95"; /* * IMPORTANT NOTE: these routines are allowed to look at the current screen - * and the current possition assuming that it is correct. If this is not + * and the current position assuming that it is correct. If this is not * true, then the update will be WRONG! This is (should be) a valid * assumption... */ -#define TC_BUFSIZE 2048 +#define TC_BUFSIZE ((size_t)2048) -#define GoodStr(a) (el->el_term.t_str[a] != NULL && \ - el->el_term.t_str[a][0] != '\0') -#define Str(a) el->el_term.t_str[a] -#define Val(a) el->el_term.t_val[a] - -#ifdef notdef -private const struct { - const char *b_name; - int b_rate; -} baud_rate[] = { -#ifdef B0 - { "0", B0 }, -#endif -#ifdef B50 - { "50", B50 }, -#endif -#ifdef B75 - { "75", B75 }, -#endif -#ifdef B110 - { "110", B110 }, -#endif -#ifdef B134 - { "134", B134 }, -#endif -#ifdef B150 - { "150", B150 }, -#endif -#ifdef B200 - { "200", B200 }, -#endif -#ifdef B300 - { "300", B300 }, -#endif -#ifdef B600 - { "600", B600 }, -#endif -#ifdef B900 - { "900", B900 }, -#endif -#ifdef B1200 - { "1200", B1200 }, -#endif -#ifdef B1800 - { "1800", B1800 }, -#endif -#ifdef B2400 - { "2400", B2400 }, -#endif -#ifdef B3600 - { "3600", B3600 }, -#endif -#ifdef B4800 - { "4800", B4800 }, -#endif -#ifdef B7200 - { "7200", B7200 }, -#endif -#ifdef B9600 - { "9600", B9600 }, -#endif -#ifdef EXTA - { "19200", EXTA }, -#endif -#ifdef B19200 - { "19200", B19200 }, -#endif -#ifdef EXTB - { "38400", EXTB }, -#endif -#ifdef B38400 - { "38400", B38400 }, -#endif - { NULL, 0 } -}; -#endif +#define GoodStr(a) (el->el_terminal.t_str[a] != NULL && \ + el->el_terminal.t_str[a][0] != '\0') +#define Str(a) el->el_terminal.t_str[a] +#define Val(a) el->el_terminal.t_val[a] private const struct termcapstr { const char *name; @@ -269,27 +199,28 @@ private const struct termcapval { }; /* do two or more of the attributes use me */ -private void term_setflags(EditLine *); -private int term_rebuffer_display(EditLine *); -private void term_free_display(EditLine *); -private int term_alloc_display(EditLine *); -private void term_alloc(EditLine *, const struct termcapstr *, const char *); -private void term_init_arrow(EditLine *); -private void term_reset_arrow(EditLine *); -private int term_putc(int); -private void term_tputs(EditLine *, const char *, int); +private void terminal_setflags(EditLine *); +private int terminal_rebuffer_display(EditLine *); +private void terminal_free_display(EditLine *); +private int terminal_alloc_display(EditLine *); +private void terminal_alloc(EditLine *, const struct termcapstr *, + const char *); +private void terminal_init_arrow(EditLine *); +private void terminal_reset_arrow(EditLine *); +private int terminal_putc(int); +private void terminal_tputs(EditLine *, const char *, int); #ifdef _REENTRANT -private pthread_mutex_t term_mutex = PTHREAD_MUTEX_INITIALIZER; +private pthread_mutex_t terminal_mutex = PTHREAD_MUTEX_INITIALIZER; #endif -private FILE *term_outfile = NULL; +private FILE *terminal_outfile = NULL; -/* term_setflags(): +/* terminal_setflags(): * Set the terminal capability flags */ private void -term_setflags(EditLine *el) +terminal_setflags(EditLine *el) { EL_FLAGS = 0; if (el->el_tty.t_tabs) @@ -330,67 +261,74 @@ term_setflags(EditLine *el) #endif /* DEBUG_SCREEN */ } -/* term_init(): +/* terminal_init(): * Initialize the terminal stuff */ protected int -term_init(EditLine *el) +terminal_init(EditLine *el) { - el->el_term.t_buf = (char *) el_malloc(TC_BUFSIZE); - if (el->el_term.t_buf == NULL) - return (-1); - el->el_term.t_cap = (char *) el_malloc(TC_BUFSIZE); - if (el->el_term.t_cap == NULL) - return (-1); - el->el_term.t_fkey = (fkey_t *) el_malloc(A_K_NKEYS * sizeof(fkey_t)); - if (el->el_term.t_fkey == NULL) - return (-1); - el->el_term.t_loc = 0; - el->el_term.t_str = (char **) el_malloc(T_str * sizeof(char *)); - if (el->el_term.t_str == NULL) - return (-1); - (void) memset(el->el_term.t_str, 0, T_str * sizeof(char *)); - el->el_term.t_val = (int *) el_malloc(T_val * sizeof(int)); - if (el->el_term.t_val == NULL) - return (-1); - (void) memset(el->el_term.t_val, 0, T_val * sizeof(int)); - (void) term_set(el, NULL); - term_init_arrow(el); - return (0); + el->el_terminal.t_buf = el_malloc(TC_BUFSIZE * + sizeof(*el->el_terminal.t_buf)); + if (el->el_terminal.t_buf == NULL) + return -1; + el->el_terminal.t_cap = el_malloc(TC_BUFSIZE * + sizeof(*el->el_terminal.t_cap)); + if (el->el_terminal.t_cap == NULL) + return -1; + el->el_terminal.t_fkey = el_malloc(A_K_NKEYS * + sizeof(*el->el_terminal.t_fkey)); + if (el->el_terminal.t_fkey == NULL) + return -1; + el->el_terminal.t_loc = 0; + el->el_terminal.t_str = el_malloc(T_str * + sizeof(*el->el_terminal.t_str)); + if (el->el_terminal.t_str == NULL) + return -1; + (void) memset(el->el_terminal.t_str, 0, T_str * + sizeof(*el->el_terminal.t_str)); + el->el_terminal.t_val = el_malloc(T_val * + sizeof(*el->el_terminal.t_val)); + if (el->el_terminal.t_val == NULL) + return -1; + (void) memset(el->el_terminal.t_val, 0, T_val * + sizeof(*el->el_terminal.t_val)); + (void) terminal_set(el, NULL); + terminal_init_arrow(el); + return 0; } -/* term_end(): +/* terminal_end(): * Clean up the terminal stuff */ protected void -term_end(EditLine *el) +terminal_end(EditLine *el) { - el_free((ptr_t) el->el_term.t_buf); - el->el_term.t_buf = NULL; - el_free((ptr_t) el->el_term.t_cap); - el->el_term.t_cap = NULL; - el->el_term.t_loc = 0; - el_free((ptr_t) el->el_term.t_str); - el->el_term.t_str = NULL; - el_free((ptr_t) el->el_term.t_val); - el->el_term.t_val = NULL; - el_free((ptr_t) el->el_term.t_fkey); - el->el_term.t_fkey = NULL; - term_free_display(el); + el_free(el->el_terminal.t_buf); + el->el_terminal.t_buf = NULL; + el_free(el->el_terminal.t_cap); + el->el_terminal.t_cap = NULL; + el->el_terminal.t_loc = 0; + el_free(el->el_terminal.t_str); + el->el_terminal.t_str = NULL; + el_free(el->el_terminal.t_val); + el->el_terminal.t_val = NULL; + el_free(el->el_terminal.t_fkey); + el->el_terminal.t_fkey = NULL; + terminal_free_display(el); } -/* term_alloc(): +/* terminal_alloc(): * Maintain a string pool for termcap strings */ private void -term_alloc(EditLine *el, const struct termcapstr *t, const char *cap) +terminal_alloc(EditLine *el, const struct termcapstr *t, const char *cap) { char termbuf[TC_BUFSIZE]; - int tlen, clen; - char **tlist = el->el_term.t_str; + size_t tlen, clen; + char **tlist = el->el_terminal.t_str; char **tmp, **str = &tlist[t - tstr]; if (cap == NULL || *cap == '\0') { @@ -412,11 +350,11 @@ term_alloc(EditLine *el, const struct termcapstr *t, const char *cap) /* * New string is longer; see if we have enough space to append */ - if (el->el_term.t_loc + 3 < TC_BUFSIZE) { + if (el->el_terminal.t_loc + 3 < TC_BUFSIZE) { /* XXX strcpy is safe */ - (void) strcpy(*str = &el->el_term.t_buf[el->el_term.t_loc], - cap); - el->el_term.t_loc += clen + 1; /* one for \0 */ + (void) strcpy(*str = &el->el_terminal.t_buf[ + el->el_terminal.t_loc], cap); + el->el_terminal.t_loc += clen + 1; /* one for \0 */ return; } /* @@ -432,124 +370,126 @@ term_alloc(EditLine *el, const struct termcapstr *t, const char *cap) continue; termbuf[tlen++] = '\0'; } - memcpy(el->el_term.t_buf, termbuf, TC_BUFSIZE); - el->el_term.t_loc = tlen; - if (el->el_term.t_loc + 3 >= TC_BUFSIZE) { + memcpy(el->el_terminal.t_buf, termbuf, TC_BUFSIZE); + el->el_terminal.t_loc = tlen; + if (el->el_terminal.t_loc + 3 >= TC_BUFSIZE) { (void) fprintf(el->el_errfile, "Out of termcap string space.\n"); return; } /* XXX strcpy is safe */ - (void) strcpy(*str = &el->el_term.t_buf[el->el_term.t_loc], cap); - el->el_term.t_loc += clen + 1; /* one for \0 */ + (void) strcpy(*str = &el->el_terminal.t_buf[el->el_terminal.t_loc], + cap); + el->el_terminal.t_loc += (size_t)clen + 1; /* one for \0 */ return; } -/* term_rebuffer_display(): +/* terminal_rebuffer_display(): * Rebuffer the display after the screen changed size */ private int -term_rebuffer_display(EditLine *el) +terminal_rebuffer_display(EditLine *el) { - coord_t *c = &el->el_term.t_size; + coord_t *c = &el->el_terminal.t_size; - term_free_display(el); + terminal_free_display(el); c->h = Val(T_co); c->v = Val(T_li); - if (term_alloc_display(el) == -1) - return (-1); - return (0); + if (terminal_alloc_display(el) == -1) + return -1; + return 0; } -/* term_alloc_display(): +/* terminal_alloc_display(): * Allocate a new display. */ private int -term_alloc_display(EditLine *el) +terminal_alloc_display(EditLine *el) { int i; - char **b; - coord_t *c = &el->el_term.t_size; + Char **b; + coord_t *c = &el->el_terminal.t_size; - b = (char **) el_malloc((size_t) (sizeof(char *) * (c->v + 1))); + b = el_malloc(sizeof(*b) * (size_t)(c->v + 1)); if (b == NULL) - return (-1); + return -1; for (i = 0; i < c->v; i++) { - b[i] = (char *) el_malloc((size_t) (sizeof(char) * (c->h + 1))); + b[i] = el_malloc(sizeof(**b) * (size_t)(c->h + 1)); if (b[i] == NULL) { while (--i >= 0) - el_free((ptr_t) b[i]); - el_free((ptr_t) b); - return (-1); + el_free(b[i]); + el_free(b); + return -1; } } b[c->v] = NULL; el->el_display = b; - b = (char **) el_malloc((size_t) (sizeof(char *) * (c->v + 1))); + b = el_malloc(sizeof(*b) * (size_t)(c->v + 1)); if (b == NULL) - return (-1); + return -1; for (i = 0; i < c->v; i++) { - b[i] = (char *) el_malloc((size_t) (sizeof(char) * (c->h + 1))); + b[i] = el_malloc(sizeof(**b) * (size_t)(c->h + 1)); if (b[i] == NULL) { while (--i >= 0) - el_free((ptr_t) b[i]); - el_free((ptr_t) b); - return (-1); + el_free(b[i]); + el_free(b); + return -1; } } b[c->v] = NULL; el->el_vdisplay = b; - return (0); + return 0; } -/* term_free_display(): +/* terminal_free_display(): * Free the display buffers */ private void -term_free_display(EditLine *el) +terminal_free_display(EditLine *el) { - char **b; - char **bufp; + Char **b; + Char **bufp; b = el->el_display; el->el_display = NULL; if (b != NULL) { for (bufp = b; *bufp != NULL; bufp++) - el_free((ptr_t) * bufp); - el_free((ptr_t) b); + el_free(*bufp); + el_free(b); } b = el->el_vdisplay; el->el_vdisplay = NULL; if (b != NULL) { for (bufp = b; *bufp != NULL; bufp++) - el_free((ptr_t) * bufp); - el_free((ptr_t) b); + el_free(*bufp); + el_free(b); } } -/* term_move_to_line(): +/* terminal_move_to_line(): * move to line (first line == 0) * as efficiently as possible */ protected void -term_move_to_line(EditLine *el, int where) +terminal_move_to_line(EditLine *el, int where) { int del; if (where == el->el_cursor.v) return; - if (where > el->el_term.t_size.v) { + if (where > el->el_terminal.t_size.v) { #ifdef DEBUG_SCREEN (void) fprintf(el->el_errfile, - "term_move_to_line: where is ridiculous: %d\r\n", where); + "terminal_move_to_line: where is ridiculous: %d\r\n", + where); #endif /* DEBUG_SCREEN */ return; } @@ -557,21 +497,31 @@ term_move_to_line(EditLine *el, int where) while (del > 0) { if (EL_HAS_AUTO_MARGINS && el->el_display[el->el_cursor.v][0] != '\0') { + size_t h = (size_t) + (el->el_terminal.t_size.h - 1); +#ifdef WIDECHAR + for (; h > 0 && + el->el_display[el->el_cursor.v][h] == + MB_FILL_CHAR; + h--) + continue; +#endif /* move without newline */ - term_move_to_char(el, el->el_term.t_size.h - 1); - term_overwrite(el, - &el->el_display[el->el_cursor.v][el->el_cursor.h], - 1); + terminal_move_to_char(el, (int)h); + terminal_overwrite(el, &el->el_display + [el->el_cursor.v][el->el_cursor.h], + (size_t)(el->el_terminal.t_size.h - + el->el_cursor.h)); /* updates Cursor */ del--; } else { if ((del > 1) && GoodStr(T_DO)) { - term_tputs(el, tgoto(Str(T_DO), del, + terminal_tputs(el, tgoto(Str(T_DO), del, del), del); del = 0; } else { for (; del > 0; del--) - term__putc(el, '\n'); + terminal__putc(el, '\n'); /* because the \n will become \r\n */ el->el_cursor.h = 0; } @@ -579,22 +529,22 @@ term_move_to_line(EditLine *el, int where) } } else { /* del < 0 */ if (GoodStr(T_UP) && (-del > 1 || !GoodStr(T_up))) - term_tputs(el, tgoto(Str(T_UP), -del, -del), -del); + terminal_tputs(el, tgoto(Str(T_UP), -del, -del), -del); else { if (GoodStr(T_up)) for (; del < 0; del++) - term_tputs(el, Str(T_up), 1); + terminal_tputs(el, Str(T_up), 1); } } el->el_cursor.v = where;/* now where is here */ } -/* term_move_to_char(): +/* terminal_move_to_char(): * Move to the character position specified */ protected void -term_move_to_char(EditLine *el, int where) +terminal_move_to_char(EditLine *el, int where) { int del, i; @@ -602,15 +552,16 @@ mc_again: if (where == el->el_cursor.h) return; - if (where > el->el_term.t_size.h) { + if (where > el->el_terminal.t_size.h) { #ifdef DEBUG_SCREEN (void) fprintf(el->el_errfile, - "term_move_to_char: where is riduculous: %d\r\n", where); + "terminal_move_to_char: where is riduculous: %d\r\n", + where); #endif /* DEBUG_SCREEN */ return; } if (!where) { /* if where is first column */ - term__putc(el, '\r'); /* do a CR */ + terminal__putc(el, '\r'); /* do a CR */ el->el_cursor.h = 0; return; } @@ -618,24 +569,32 @@ mc_again: if ((del < -4 || del > 4) && GoodStr(T_ch)) /* go there directly */ - term_tputs(el, tgoto(Str(T_ch), where, where), where); + terminal_tputs(el, tgoto(Str(T_ch), where, where), where); else { if (del > 0) { /* moving forward */ if ((del > 4) && GoodStr(T_RI)) - term_tputs(el, tgoto(Str(T_RI), del, del), del); + terminal_tputs(el, tgoto(Str(T_RI), del, del), + del); else { /* if I can do tabs, use them */ if (EL_CAN_TAB) { if ((el->el_cursor.h & 0370) != - (where & 0370)) { + (where & ~0x7) +#ifdef WIDECHAR + && (el->el_display[ + el->el_cursor.v][where & 0370] != + MB_FILL_CHAR) +#endif + ) { /* if not within tab stop */ for (i = (el->el_cursor.h & 0370); - i < (where & 0370); + i < (where & ~0x7); i += 8) - term__putc(el, '\t'); + terminal__putc(el, + '\t'); /* then tab over */ - el->el_cursor.h = where & 0370; + el->el_cursor.h = where & ~0x7; } } /* @@ -643,17 +602,17 @@ mc_again: * chars, so we do. */ /* - * NOTE THAT term_overwrite() WILL CHANGE + * NOTE THAT terminal_overwrite() WILL CHANGE * el->el_cursor.h!!! */ - term_overwrite(el, - &el->el_display[el->el_cursor.v][el->el_cursor.h], - where - el->el_cursor.h); + terminal_overwrite(el, &el->el_display[ + el->el_cursor.v][el->el_cursor.h], + (size_t)(where - el->el_cursor.h)); } } else { /* del < 0 := moving backward */ if ((-del > 4) && GoodStr(T_LE)) - term_tputs(el, tgoto(Str(T_LE), -del, -del), + terminal_tputs(el, tgoto(Str(T_LE), -del, -del), -del); else { /* can't go directly there */ /* @@ -665,66 +624,88 @@ mc_again: (((unsigned int) where >> 3) + (where & 07))) : (-del > where)) { - term__putc(el, '\r'); /* do a CR */ + terminal__putc(el, '\r');/* do a CR */ el->el_cursor.h = 0; goto mc_again; /* and try again */ } for (i = 0; i < -del; i++) - term__putc(el, '\b'); + terminal__putc(el, '\b'); } } } el->el_cursor.h = where; /* now where is here */ } +#ifdef WIDECHAR +int wcwidth(wchar_t); // Signature. +#endif -/* term_overwrite(): +/* terminal_overwrite(): * Overstrike num characters + * Assumes MB_FILL_CHARs are present to keep the column count correct */ protected void -term_overwrite(EditLine *el, const char *cp, int n) +terminal_overwrite(EditLine *el, const Char *cp, size_t n) { - if (n <= 0) - return; /* catch bugs */ +#ifdef WIDECHAR + int width; +#endif - if (n > el->el_term.t_size.h) { + if (n == 0) + return; + + if (n > (size_t)el->el_terminal.t_size.h) { #ifdef DEBUG_SCREEN (void) fprintf(el->el_errfile, - "term_overwrite: n is riduculous: %d\r\n", n); + "terminal_overwrite: n is riduculous: %d\r\n", n); #endif /* DEBUG_SCREEN */ return; } - do { - term__putc(el, *cp++); - el->el_cursor.h++; - } while (--n); - if (el->el_cursor.h >= el->el_term.t_size.h) { /* wrap? */ + do { +#ifdef WIDECHAR + width = wcwidth(*cp); /* Returns -1 for faux character. */ + if (width != -1) + el->el_cursor.h += width; +#else + el->el_cursor.h++; +#endif + /* terminal__putc() ignores any MB_FILL_CHARs */ + terminal__putc(el, *cp++); + } while (--n); + + if (el->el_cursor.h >= el->el_terminal.t_size.h) { /* wrap? */ if (EL_HAS_AUTO_MARGINS) { /* yes */ el->el_cursor.h = 0; el->el_cursor.v++; if (EL_HAS_MAGIC_MARGINS) { /* force the wrap to avoid the "magic" * situation */ - char c; - if ((c = el->el_display[el->el_cursor.v][el->el_cursor.h]) - != '\0') - term_overwrite(el, &c, 1); - else - term__putc(el, ' '); - el->el_cursor.h = 1; + Char c; + if ((c = el->el_display[el->el_cursor.v] + [el->el_cursor.h]) != '\0') { + terminal_overwrite(el, &c, (size_t)1); +#ifdef WIDECHAR + while (el->el_display[el->el_cursor.v] + [el->el_cursor.h] == MB_FILL_CHAR) + el->el_cursor.h++; +#endif + } else { + terminal__putc(el, ' '); + el->el_cursor.h = 1; + } } } else /* no wrap, but cursor stays on screen */ - el->el_cursor.h = el->el_term.t_size.h; + el->el_cursor.h = el->el_terminal.t_size.h - 1; } } -/* term_deletechars(): +/* terminal_deletechars(): * Delete num characters */ protected void -term_deletechars(EditLine *el, int num) +terminal_deletechars(EditLine *el, int num) { if (num <= 0) return; @@ -735,37 +716,38 @@ term_deletechars(EditLine *el, int num) #endif /* DEBUG_EDIT */ return; } - if (num > el->el_term.t_size.h) { + if (num > el->el_terminal.t_size.h) { #ifdef DEBUG_SCREEN (void) fprintf(el->el_errfile, - "term_deletechars: num is riduculous: %d\r\n", num); + "terminal_deletechars: num is riduculous: %d\r\n", num); #endif /* DEBUG_SCREEN */ return; } if (GoodStr(T_DC)) /* if I have multiple delete */ if ((num > 1) || !GoodStr(T_dc)) { /* if dc would be more * expen. */ - term_tputs(el, tgoto(Str(T_DC), num, num), num); + terminal_tputs(el, tgoto(Str(T_DC), num, num), num); return; } if (GoodStr(T_dm)) /* if I have delete mode */ - term_tputs(el, Str(T_dm), 1); + terminal_tputs(el, Str(T_dm), 1); if (GoodStr(T_dc)) /* else do one at a time */ while (num--) - term_tputs(el, Str(T_dc), 1); + terminal_tputs(el, Str(T_dc), 1); if (GoodStr(T_ed)) /* if I have delete mode */ - term_tputs(el, Str(T_ed), 1); + terminal_tputs(el, Str(T_ed), 1); } -/* term_insertwrite(): +/* terminal_insertwrite(): * Puts terminal in insert character mode or inserts num * characters in the line + * Assumes MB_FILL_CHARs are present to keep column count correct */ protected void -term_insertwrite(EditLine *el, char *cp, int num) +terminal_insertwrite(EditLine *el, Char *cp, int num) { if (num <= 0) return; @@ -775,7 +757,7 @@ term_insertwrite(EditLine *el, char *cp, int num) #endif /* DEBUG_EDIT */ return; } - if (num > el->el_term.t_size.h) { + if (num > el->el_terminal.t_size.h) { #ifdef DEBUG_SCREEN (void) fprintf(el->el_errfile, "StartInsert: num is riduculous: %d\r\n", num); @@ -785,120 +767,106 @@ term_insertwrite(EditLine *el, char *cp, int num) if (GoodStr(T_IC)) /* if I have multiple insert */ if ((num > 1) || !GoodStr(T_ic)) { /* if ic would be more expensive */ - term_tputs(el, tgoto(Str(T_IC), num, num), num); - term_overwrite(el, cp, num); + terminal_tputs(el, tgoto(Str(T_IC), num, num), num); + terminal_overwrite(el, cp, (size_t)num); /* this updates el_cursor.h */ return; } if (GoodStr(T_im) && GoodStr(T_ei)) { /* if I have insert mode */ - term_tputs(el, Str(T_im), 1); + terminal_tputs(el, Str(T_im), 1); el->el_cursor.h += num; do - term__putc(el, *cp++); + terminal__putc(el, *cp++); while (--num); if (GoodStr(T_ip)) /* have to make num chars insert */ - term_tputs(el, Str(T_ip), 1); + terminal_tputs(el, Str(T_ip), 1); - term_tputs(el, Str(T_ei), 1); + terminal_tputs(el, Str(T_ei), 1); return; } do { if (GoodStr(T_ic)) /* have to make num chars insert */ - term_tputs(el, Str(T_ic), 1); + terminal_tputs(el, Str(T_ic), 1); - term__putc(el, *cp++); + terminal__putc(el, *cp++); el->el_cursor.h++; if (GoodStr(T_ip)) /* have to make num chars insert */ - term_tputs(el, Str(T_ip), 1); + terminal_tputs(el, Str(T_ip), 1); /* pad the inserted char */ } while (--num); } -/* term_clear_EOL(): +/* terminal_clear_EOL(): * clear to end of line. There are num characters to clear */ protected void -term_clear_EOL(EditLine *el, int num) +terminal_clear_EOL(EditLine *el, int num) { int i; if (EL_CAN_CEOL && GoodStr(T_ce)) - term_tputs(el, Str(T_ce), 1); + terminal_tputs(el, Str(T_ce), 1); else { for (i = 0; i < num; i++) - term__putc(el, ' '); + terminal__putc(el, ' '); el->el_cursor.h += num; /* have written num spaces */ } } -/* term_clear_screen(): +/* terminal_clear_screen(): * Clear the screen */ protected void -term_clear_screen(EditLine *el) +terminal_clear_screen(EditLine *el) { /* clear the whole screen and home */ if (GoodStr(T_cl)) /* send the clear screen code */ - term_tputs(el, Str(T_cl), Val(T_li)); + terminal_tputs(el, Str(T_cl), Val(T_li)); else if (GoodStr(T_ho) && GoodStr(T_cd)) { - term_tputs(el, Str(T_ho), Val(T_li)); /* home */ + terminal_tputs(el, Str(T_ho), Val(T_li)); /* home */ /* clear to bottom of screen */ - term_tputs(el, Str(T_cd), Val(T_li)); + terminal_tputs(el, Str(T_cd), Val(T_li)); } else { - term__putc(el, '\r'); - term__putc(el, '\n'); + terminal__putc(el, '\r'); + terminal__putc(el, '\n'); } } -/* term_beep(): +/* terminal_beep(): * Beep the way the terminal wants us */ protected void -term_beep(EditLine *el) +terminal_beep(EditLine *el) { if (GoodStr(T_bl)) /* what termcap says we should use */ - term_tputs(el, Str(T_bl), 1); + terminal_tputs(el, Str(T_bl), 1); else - term__putc(el, '\007'); /* an ASCII bell; ^G */ + terminal__putc(el, '\007'); /* an ASCII bell; ^G */ } -#ifdef notdef -/* term_clear_to_bottom(): - * Clear to the bottom of the screen - */ -protected void -term_clear_to_bottom(EditLine *el) -{ - if (GoodStr(T_cd)) - term_tputs(el, Str(T_cd), Val(T_li)); - else if (GoodStr(T_ce)) - term_tputs(el, Str(T_ce), Val(T_li)); -} -#endif - protected void -term_get(EditLine *el, const char **term) +terminal_get(EditLine *el, const char **term) { - *term = el->el_term.t_name; + *term = el->el_terminal.t_name; } -/* term_set(): +/* terminal_set(): * Read in the terminal capabilities from the requested terminal */ protected int -term_set(EditLine *el, const char *term) +terminal_set(EditLine *el, const char *term) { int i; char buf[TC_BUFSIZE]; @@ -923,9 +891,9 @@ term_set(EditLine *el, const char *term) if (strcmp(term, "emacs") == 0) el->el_flags |= EDIT_DISABLED; - memset(el->el_term.t_cap, 0, TC_BUFSIZE); + memset(el->el_terminal.t_cap, 0, TC_BUFSIZE); - i = tgetent(el->el_term.t_cap, term); + i = tgetent(el->el_terminal.t_cap, term); if (i <= 0) { if (i == -1) @@ -940,7 +908,7 @@ term_set(EditLine *el, const char *term) Val(T_pt) = Val(T_km) = Val(T_li) = 0; Val(T_xt) = Val(T_MT); for (t = tstr; t->name != NULL; t++) - term_alloc(el, t, NULL); + terminal_alloc(el, t, NULL); } else { /* auto/magic margins */ Val(T_am) = tgetflag("am"); @@ -956,7 +924,7 @@ term_set(EditLine *el, const char *term) Val(T_li) = tgetnum("li"); for (t = tstr; t->name != NULL; t++) { /* XXX: some systems' tgetstr needs non const */ - term_alloc(el, t, tgetstr(strchr(t->name, *t->name), + terminal_alloc(el, t, tgetstr(strchr(t->name, *t->name), &area)); } } @@ -966,28 +934,28 @@ term_set(EditLine *el, const char *term) if (Val(T_li) < 1) Val(T_li) = 24; - el->el_term.t_size.v = Val(T_co); - el->el_term.t_size.h = Val(T_li); + el->el_terminal.t_size.v = Val(T_co); + el->el_terminal.t_size.h = Val(T_li); - term_setflags(el); + terminal_setflags(el); /* get the correct window size */ - (void) term_get_size(el, &lins, &cols); - if (term_change_size(el, lins, cols) == -1) - return (-1); + (void) terminal_get_size(el, &lins, &cols); + if (terminal_change_size(el, lins, cols) == -1) + return -1; (void) sigprocmask(SIG_SETMASK, &oset, NULL); - term_bind_arrow(el); - el->el_term.t_name = term; - return (i <= 0 ? -1 : 0); + terminal_bind_arrow(el); + el->el_terminal.t_name = term; + return i <= 0 ? -1 : 0; } -/* term_get_size(): +/* terminal_get_size(): * Return the new window size in lines and cols, and * true if the size was changed. */ protected int -term_get_size(EditLine *el, int *lins, int *cols) +terminal_get_size(EditLine *el, int *lins, int *cols) { *cols = Val(T_co); @@ -996,7 +964,7 @@ term_get_size(EditLine *el, int *lins, int *cols) #ifdef TIOCGWINSZ { struct winsize ws; - if (ioctl(el->el_infd, TIOCGWINSZ, (ioctl_t) & ws) != -1) { + if (ioctl(el->el_infd, TIOCGWINSZ, &ws) != -1) { if (ws.ws_col) *cols = ws.ws_col; if (ws.ws_row) @@ -1007,7 +975,7 @@ term_get_size(EditLine *el, int *lins, int *cols) #ifdef TIOCGSIZE { struct ttysize ts; - if (ioctl(el->el_infd, TIOCGSIZE, (ioctl_t) & ts) != -1) { + if (ioctl(el->el_infd, TIOCGSIZE, &ts) != -1) { if (ts.ts_cols) *cols = ts.ts_cols; if (ts.ts_lines) @@ -1015,15 +983,15 @@ term_get_size(EditLine *el, int *lins, int *cols) } } #endif - return (Val(T_co) != *cols || Val(T_li) != *lins); + return Val(T_co) != *cols || Val(T_li) != *lins; } -/* term_change_size(): +/* terminal_change_size(): * Change the size of the terminal */ protected int -term_change_size(EditLine *el, int lins, int cols) +terminal_change_size(EditLine *el, int lins, int cols) { /* * Just in case @@ -1032,283 +1000,301 @@ term_change_size(EditLine *el, int lins, int cols) Val(T_li) = (lins < 1) ? 24 : lins; /* re-make display buffers */ - if (term_rebuffer_display(el) == -1) - return (-1); + if (terminal_rebuffer_display(el) == -1) + return -1; re_clear_display(el); - return (0); + return 0; } -/* term_init_arrow(): +/* terminal_init_arrow(): * Initialize the arrow key bindings from termcap */ private void -term_init_arrow(EditLine *el) +terminal_init_arrow(EditLine *el) { - fkey_t *arrow = el->el_term.t_fkey; + funckey_t *arrow = el->el_terminal.t_fkey; - arrow[A_K_DN].name = "down"; + arrow[A_K_DN].name = STR("down"); arrow[A_K_DN].key = T_kd; arrow[A_K_DN].fun.cmd = ED_NEXT_HISTORY; arrow[A_K_DN].type = XK_CMD; - arrow[A_K_UP].name = "up"; + arrow[A_K_UP].name = STR("up"); arrow[A_K_UP].key = T_ku; arrow[A_K_UP].fun.cmd = ED_PREV_HISTORY; arrow[A_K_UP].type = XK_CMD; - arrow[A_K_LT].name = "left"; + arrow[A_K_LT].name = STR("left"); arrow[A_K_LT].key = T_kl; arrow[A_K_LT].fun.cmd = ED_PREV_CHAR; arrow[A_K_LT].type = XK_CMD; - arrow[A_K_RT].name = "right"; + arrow[A_K_RT].name = STR("right"); arrow[A_K_RT].key = T_kr; arrow[A_K_RT].fun.cmd = ED_NEXT_CHAR; arrow[A_K_RT].type = XK_CMD; - arrow[A_K_HO].name = "home"; + arrow[A_K_HO].name = STR("home"); arrow[A_K_HO].key = T_kh; arrow[A_K_HO].fun.cmd = ED_MOVE_TO_BEG; arrow[A_K_HO].type = XK_CMD; - arrow[A_K_EN].name = "end"; + arrow[A_K_EN].name = STR("end"); arrow[A_K_EN].key = T_at7; arrow[A_K_EN].fun.cmd = ED_MOVE_TO_END; arrow[A_K_EN].type = XK_CMD; } -/* term_reset_arrow(): +/* terminal_reset_arrow(): * Reset arrow key bindings */ private void -term_reset_arrow(EditLine *el) +terminal_reset_arrow(EditLine *el) { - fkey_t *arrow = el->el_term.t_fkey; - static const char strA[] = {033, '[', 'A', '\0'}; - static const char strB[] = {033, '[', 'B', '\0'}; - static const char strC[] = {033, '[', 'C', '\0'}; - static const char strD[] = {033, '[', 'D', '\0'}; - static const char strH[] = {033, '[', 'H', '\0'}; - static const char strF[] = {033, '[', 'F', '\0'}; - static const char stOA[] = {033, 'O', 'A', '\0'}; - static const char stOB[] = {033, 'O', 'B', '\0'}; - static const char stOC[] = {033, 'O', 'C', '\0'}; - static const char stOD[] = {033, 'O', 'D', '\0'}; - static const char stOH[] = {033, 'O', 'H', '\0'}; - static const char stOF[] = {033, 'O', 'F', '\0'}; + funckey_t *arrow = el->el_terminal.t_fkey; + static const Char strA[] = {033, '[', 'A', '\0'}; + static const Char strB[] = {033, '[', 'B', '\0'}; + static const Char strC[] = {033, '[', 'C', '\0'}; + static const Char strD[] = {033, '[', 'D', '\0'}; + static const Char strH[] = {033, '[', 'H', '\0'}; + static const Char strF[] = {033, '[', 'F', '\0'}; + static const Char stOA[] = {033, 'O', 'A', '\0'}; + static const Char stOB[] = {033, 'O', 'B', '\0'}; + static const Char stOC[] = {033, 'O', 'C', '\0'}; + static const Char stOD[] = {033, 'O', 'D', '\0'}; + static const Char stOH[] = {033, 'O', 'H', '\0'}; + static const Char stOF[] = {033, 'O', 'F', '\0'}; - key_add(el, strA, &arrow[A_K_UP].fun, arrow[A_K_UP].type); - key_add(el, strB, &arrow[A_K_DN].fun, arrow[A_K_DN].type); - key_add(el, strC, &arrow[A_K_RT].fun, arrow[A_K_RT].type); - key_add(el, strD, &arrow[A_K_LT].fun, arrow[A_K_LT].type); - key_add(el, strH, &arrow[A_K_HO].fun, arrow[A_K_HO].type); - key_add(el, strF, &arrow[A_K_EN].fun, arrow[A_K_EN].type); - key_add(el, stOA, &arrow[A_K_UP].fun, arrow[A_K_UP].type); - key_add(el, stOB, &arrow[A_K_DN].fun, arrow[A_K_DN].type); - key_add(el, stOC, &arrow[A_K_RT].fun, arrow[A_K_RT].type); - key_add(el, stOD, &arrow[A_K_LT].fun, arrow[A_K_LT].type); - key_add(el, stOH, &arrow[A_K_HO].fun, arrow[A_K_HO].type); - key_add(el, stOF, &arrow[A_K_EN].fun, arrow[A_K_EN].type); + keymacro_add(el, strA, &arrow[A_K_UP].fun, arrow[A_K_UP].type); + keymacro_add(el, strB, &arrow[A_K_DN].fun, arrow[A_K_DN].type); + keymacro_add(el, strC, &arrow[A_K_RT].fun, arrow[A_K_RT].type); + keymacro_add(el, strD, &arrow[A_K_LT].fun, arrow[A_K_LT].type); + keymacro_add(el, strH, &arrow[A_K_HO].fun, arrow[A_K_HO].type); + keymacro_add(el, strF, &arrow[A_K_EN].fun, arrow[A_K_EN].type); + keymacro_add(el, stOA, &arrow[A_K_UP].fun, arrow[A_K_UP].type); + keymacro_add(el, stOB, &arrow[A_K_DN].fun, arrow[A_K_DN].type); + keymacro_add(el, stOC, &arrow[A_K_RT].fun, arrow[A_K_RT].type); + keymacro_add(el, stOD, &arrow[A_K_LT].fun, arrow[A_K_LT].type); + keymacro_add(el, stOH, &arrow[A_K_HO].fun, arrow[A_K_HO].type); + keymacro_add(el, stOF, &arrow[A_K_EN].fun, arrow[A_K_EN].type); - if (el->el_map.type == MAP_VI) { - key_add(el, &strA[1], &arrow[A_K_UP].fun, arrow[A_K_UP].type); - key_add(el, &strB[1], &arrow[A_K_DN].fun, arrow[A_K_DN].type); - key_add(el, &strC[1], &arrow[A_K_RT].fun, arrow[A_K_RT].type); - key_add(el, &strD[1], &arrow[A_K_LT].fun, arrow[A_K_LT].type); - key_add(el, &strH[1], &arrow[A_K_HO].fun, arrow[A_K_HO].type); - key_add(el, &strF[1], &arrow[A_K_EN].fun, arrow[A_K_EN].type); - key_add(el, &stOA[1], &arrow[A_K_UP].fun, arrow[A_K_UP].type); - key_add(el, &stOB[1], &arrow[A_K_DN].fun, arrow[A_K_DN].type); - key_add(el, &stOC[1], &arrow[A_K_RT].fun, arrow[A_K_RT].type); - key_add(el, &stOD[1], &arrow[A_K_LT].fun, arrow[A_K_LT].type); - key_add(el, &stOH[1], &arrow[A_K_HO].fun, arrow[A_K_HO].type); - key_add(el, &stOF[1], &arrow[A_K_EN].fun, arrow[A_K_EN].type); - } + if (el->el_map.type != MAP_VI) + return; + keymacro_add(el, &strA[1], &arrow[A_K_UP].fun, arrow[A_K_UP].type); + keymacro_add(el, &strB[1], &arrow[A_K_DN].fun, arrow[A_K_DN].type); + keymacro_add(el, &strC[1], &arrow[A_K_RT].fun, arrow[A_K_RT].type); + keymacro_add(el, &strD[1], &arrow[A_K_LT].fun, arrow[A_K_LT].type); + keymacro_add(el, &strH[1], &arrow[A_K_HO].fun, arrow[A_K_HO].type); + keymacro_add(el, &strF[1], &arrow[A_K_EN].fun, arrow[A_K_EN].type); + keymacro_add(el, &stOA[1], &arrow[A_K_UP].fun, arrow[A_K_UP].type); + keymacro_add(el, &stOB[1], &arrow[A_K_DN].fun, arrow[A_K_DN].type); + keymacro_add(el, &stOC[1], &arrow[A_K_RT].fun, arrow[A_K_RT].type); + keymacro_add(el, &stOD[1], &arrow[A_K_LT].fun, arrow[A_K_LT].type); + keymacro_add(el, &stOH[1], &arrow[A_K_HO].fun, arrow[A_K_HO].type); + keymacro_add(el, &stOF[1], &arrow[A_K_EN].fun, arrow[A_K_EN].type); } -/* term_set_arrow(): +/* terminal_set_arrow(): * Set an arrow key binding */ protected int -term_set_arrow(EditLine *el, const char *name, key_value_t *fun, int type) +terminal_set_arrow(EditLine *el, const Char *name, keymacro_value_t *fun, + int type) { - fkey_t *arrow = el->el_term.t_fkey; + funckey_t *arrow = el->el_terminal.t_fkey; int i; for (i = 0; i < A_K_NKEYS; i++) - if (strcmp(name, arrow[i].name) == 0) { + if (Strcmp(name, arrow[i].name) == 0) { arrow[i].fun = *fun; arrow[i].type = type; - return (0); + return 0; } - return (-1); + return -1; } -/* term_clear_arrow(): +/* terminal_clear_arrow(): * Clear an arrow key binding */ protected int -term_clear_arrow(EditLine *el, const char *name) +terminal_clear_arrow(EditLine *el, const Char *name) { - fkey_t *arrow = el->el_term.t_fkey; + funckey_t *arrow = el->el_terminal.t_fkey; int i; for (i = 0; i < A_K_NKEYS; i++) - if (strcmp(name, arrow[i].name) == 0) { + if (Strcmp(name, arrow[i].name) == 0) { arrow[i].type = XK_NOD; - return (0); + return 0; } - return (-1); + return -1; } -/* term_print_arrow(): +/* terminal_print_arrow(): * Print the arrow key bindings */ protected void -term_print_arrow(EditLine *el, const char *name) +terminal_print_arrow(EditLine *el, const Char *name) { int i; - fkey_t *arrow = el->el_term.t_fkey; + funckey_t *arrow = el->el_terminal.t_fkey; for (i = 0; i < A_K_NKEYS; i++) - if (*name == '\0' || strcmp(name, arrow[i].name) == 0) + if (*name == '\0' || Strcmp(name, arrow[i].name) == 0) if (arrow[i].type != XK_NOD) - key_kprint(el, arrow[i].name, &arrow[i].fun, - arrow[i].type); + keymacro_kprint(el, arrow[i].name, + &arrow[i].fun, arrow[i].type); } -/* term_bind_arrow(): +/* terminal_bind_arrow(): * Bind the arrow keys */ protected void -term_bind_arrow(EditLine *el) +terminal_bind_arrow(EditLine *el) { el_action_t *map; const el_action_t *dmap; int i, j; char *p; - fkey_t *arrow = el->el_term.t_fkey; + funckey_t *arrow = el->el_terminal.t_fkey; /* Check if the components needed are initialized */ - if (el->el_term.t_buf == NULL || el->el_map.key == NULL) + if (el->el_terminal.t_buf == NULL || el->el_map.key == NULL) return; map = el->el_map.type == MAP_VI ? el->el_map.alt : el->el_map.key; dmap = el->el_map.type == MAP_VI ? el->el_map.vic : el->el_map.emacs; - term_reset_arrow(el); + terminal_reset_arrow(el); for (i = 0; i < A_K_NKEYS; i++) { - p = el->el_term.t_str[arrow[i].key]; - if (p && *p) { - j = (unsigned char) *p; - /* - * Assign the arrow keys only if: - * - * 1. They are multi-character arrow keys and the user - * has not re-assigned the leading character, or - * has re-assigned the leading character to be - * ED_SEQUENCE_LEAD_IN - * 2. They are single arrow keys pointing to an - * unassigned key. - */ - if (arrow[i].type == XK_NOD) - key_clear(el, map, p); - else { - if (p[1] && (dmap[j] == map[j] || - map[j] == ED_SEQUENCE_LEAD_IN)) { - key_add(el, p, &arrow[i].fun, + Char wt_str[VISUAL_WIDTH_MAX]; + Char *px; + size_t n; + + p = el->el_terminal.t_str[arrow[i].key]; + if (!p || !*p) + continue; + for (n = 0; n < VISUAL_WIDTH_MAX && p[n]; ++n) + wt_str[n] = p[n]; + while (n < VISUAL_WIDTH_MAX) + wt_str[n++] = '\0'; + px = wt_str; + j = (unsigned char) *p; + /* + * Assign the arrow keys only if: + * + * 1. They are multi-character arrow keys and the user + * has not re-assigned the leading character, or + * has re-assigned the leading character to be + * ED_SEQUENCE_LEAD_IN + * 2. They are single arrow keys pointing to an + * unassigned key. + */ + if (arrow[i].type == XK_NOD) + keymacro_clear(el, map, px); + else { + if (p[1] && (dmap[j] == map[j] || + map[j] == ED_SEQUENCE_LEAD_IN)) { + keymacro_add(el, px, &arrow[i].fun, + arrow[i].type); + map[j] = ED_SEQUENCE_LEAD_IN; + } else if (map[j] == ED_UNASSIGNED) { + keymacro_clear(el, map, px); + if (arrow[i].type == XK_CMD) + map[j] = arrow[i].fun.cmd; + else + keymacro_add(el, px, &arrow[i].fun, arrow[i].type); - map[j] = ED_SEQUENCE_LEAD_IN; - } else if (map[j] == ED_UNASSIGNED) { - key_clear(el, map, p); - if (arrow[i].type == XK_CMD) - map[j] = arrow[i].fun.cmd; - else - key_add(el, p, &arrow[i].fun, - arrow[i].type); - } } } } } -/* term_putc(): +/* terminal_putc(): * Add a character */ private int -term_putc(int c) +terminal_putc(int c) { - - if (term_outfile == NULL) + if (terminal_outfile == NULL) return -1; - return fputc(c, term_outfile); + return fputc(c, terminal_outfile); } private void -term_tputs(EditLine *el, const char *cap, int affcnt) +terminal_tputs(EditLine *el, const char *cap, int affcnt) { #ifdef _REENTRANT - pthread_mutex_lock(&term_mutex); + pthread_mutex_lock(&terminal_mutex); #endif - term_outfile = el->el_outfile; - (void)tputs(cap, affcnt, term_putc); + terminal_outfile = el->el_outfile; + (void)tputs(cap, affcnt, terminal_putc); #ifdef _REENTRANT - pthread_mutex_unlock(&term_mutex); + pthread_mutex_unlock(&terminal_mutex); #endif } -/* term__putc(): +/* terminal__putc(): * Add a character */ protected int -term__putc(EditLine *el, int c) +terminal__putc(EditLine *el, Int c) { + char buf[MB_LEN_MAX +1]; + ssize_t i; + mbstate_t state; - return fputc(c, el->el_outfile); + memset(&state, 0, sizeof(mbstate_t)); + if (c == (Int)MB_FILL_CHAR) + return 0; + i = ct_encode_char(buf, (size_t)MB_CUR_MAX, c, &state); + if (i <= 0) + return (int)i; + buf[i] = '\0'; + return fputs(buf, el->el_outfile); } -/* term__flush(): +/* terminal__flush(): * Flush output */ protected void -term__flush(EditLine *el) +terminal__flush(EditLine *el) { (void) fflush(el->el_outfile); } -/* term_writec(): +/* terminal_writec(): * Write the given character out, in a human readable form */ protected void -term_writec(EditLine *el, int c) +terminal_writec(EditLine *el, Int c) { - char buf[8]; - int cnt = key__decode_char(buf, sizeof(buf), 0, c); - buf[cnt] = '\0'; - term_overwrite(el, buf, cnt); - term__flush(el); + Char visbuf[VISUAL_WIDTH_MAX +1]; + ssize_t vcnt = ct_visual_char(visbuf, VISUAL_WIDTH_MAX, c); + visbuf[vcnt] = '\0'; + terminal_overwrite(el, visbuf, (size_t)vcnt); + terminal__flush(el); } -/* term_telltc(): +/* terminal_telltc(): * Print the current termcap characteristics */ protected int /*ARGSUSED*/ -term_telltc(EditLine *el, int argc __attribute__((__unused__)), - const char **argv __attribute__((__unused__))) +terminal_telltc(EditLine *el, int argc __attribute__((__unused__)), + const Char **argv __attribute__((__unused__))) { const struct termcapstr *t; char **ts; - char upbuf[EL_BUFSIZ]; (void) fprintf(el->el_outfile, "\n\tYour terminal has the\n"); (void) fprintf(el->el_outfile, "\tfollowing characteristics:\n\n"); @@ -1324,39 +1310,42 @@ term_telltc(EditLine *el, int argc __attribute__((__unused__)), (void) fprintf(el->el_outfile, "\tIt %s magic margins\n", EL_HAS_MAGIC_MARGINS ? "has" : "does not have"); - for (t = tstr, ts = el->el_term.t_str; t->name != NULL; t++, ts++) { + for (t = tstr, ts = el->el_terminal.t_str; t->name != NULL; t++, ts++) { const char *ub; if (*ts && **ts) { - (void) key__decode_str(*ts, upbuf, sizeof(upbuf), ""); - ub = upbuf; + ub = ct_encode_string(ct_visual_string( + ct_decode_string(*ts, &el->el_scratch)), + &el->el_scratch); } else { - ub = "(empty)"; + ub = "(empty)"; } (void) fprintf(el->el_outfile, "\t%25s (%s) == %s\n", t->long_name, t->name, ub); } (void) fputc('\n', el->el_outfile); - return (0); + return 0; } -/* term_settc(): +/* terminal_settc(): * Change the current terminal characteristics */ protected int /*ARGSUSED*/ -term_settc(EditLine *el, int argc __attribute__((__unused__)), - const char **argv) +terminal_settc(EditLine *el, int argc __attribute__((__unused__)), + const Char **argv) { const struct termcapstr *ts; const struct termcapval *tv; - const char *what, *how; + char what[8], how[8]; if (argv == NULL || argv[1] == NULL || argv[2] == NULL) return -1; - what = argv[1]; - how = argv[2]; + strncpy(what, ct_encode_string(argv[1], &el->el_scratch), sizeof(what)); + what[sizeof(what) - 1] = '\0'; + strncpy(how, ct_encode_string(argv[2], &el->el_scratch), sizeof(how)); + how[sizeof(how) - 1] = '\0'; /* * Do the strings first @@ -1366,8 +1355,8 @@ term_settc(EditLine *el, int argc __attribute__((__unused__)), break; if (ts->name != NULL) { - term_alloc(el, ts, how); - term_setflags(el); + terminal_alloc(el, ts, how); + terminal_setflags(el); return 0; } /* @@ -1383,16 +1372,16 @@ term_settc(EditLine *el, int argc __attribute__((__unused__)), if (tv == &tval[T_pt] || tv == &tval[T_km] || tv == &tval[T_am] || tv == &tval[T_xn]) { if (strcmp(how, "yes") == 0) - el->el_term.t_val[tv - tval] = 1; + el->el_terminal.t_val[tv - tval] = 1; else if (strcmp(how, "no") == 0) - el->el_term.t_val[tv - tval] = 0; + el->el_terminal.t_val[tv - tval] = 0; else { (void) fprintf(el->el_errfile, - "%s: Bad value `%s'.\n", argv[0], how); + "" FSTR ": Bad value `%s'.\n", argv[0], how); return -1; } - term_setflags(el); - if (term_change_size(el, Val(T_li), Val(T_co)) == -1) + terminal_setflags(el); + if (terminal_change_size(el, Val(T_li), Val(T_co)) == -1) return -1; return 0; } else { @@ -1402,14 +1391,14 @@ term_settc(EditLine *el, int argc __attribute__((__unused__)), i = strtol(how, &ep, 10); if (*ep != '\0') { (void) fprintf(el->el_errfile, - "%s: Bad value `%s'.\n", argv[0], how); + "" FSTR ": Bad value `%s'.\n", argv[0], how); return -1; } - el->el_term.t_val[tv - tval] = (int) i; - el->el_term.t_size.v = Val(T_co); - el->el_term.t_size.h = Val(T_li); + el->el_terminal.t_val[tv - tval] = (int) i; + el->el_terminal.t_size.v = Val(T_co); + el->el_terminal.t_size.h = Val(T_li); if (tv == &tval[T_co] || tv == &tval[T_li]) - if (term_change_size(el, Val(T_li), Val(T_co)) + if (terminal_change_size(el, Val(T_li), Val(T_co)) == -1) return -1; return 0; @@ -1417,12 +1406,12 @@ term_settc(EditLine *el, int argc __attribute__((__unused__)), } -/* term_gettc(): +/* terminal_gettc(): * Get the current terminal characteristics */ protected int /*ARGSUSED*/ -term_gettc(EditLine *el, int argc __attribute__((__unused__)), char **argv) +terminal_gettc(EditLine *el, int argc __attribute__((__unused__)), char **argv) { const struct termcapstr *ts; const struct termcapval *tv; @@ -1430,7 +1419,7 @@ term_gettc(EditLine *el, int argc __attribute__((__unused__)), char **argv) void *how; if (argv == NULL || argv[1] == NULL || argv[2] == NULL) - return (-1); + return -1; what = argv[1]; how = argv[2]; @@ -1443,7 +1432,7 @@ term_gettc(EditLine *el, int argc __attribute__((__unused__)), char **argv) break; if (ts->name != NULL) { - *(char **)how = el->el_term.t_str[ts - tstr]; + *(char **)how = el->el_terminal.t_str[ts - tstr]; return 0; } /* @@ -1460,26 +1449,27 @@ term_gettc(EditLine *el, int argc __attribute__((__unused__)), char **argv) tv == &tval[T_am] || tv == &tval[T_xn]) { static char yes[] = "yes"; static char no[] = "no"; - if (el->el_term.t_val[tv - tval]) + if (el->el_terminal.t_val[tv - tval]) *(char **)how = yes; else *(char **)how = no; return 0; } else { - *(int *)how = el->el_term.t_val[tv - tval]; + *(int *)how = el->el_terminal.t_val[tv - tval]; return 0; } } -/* term_echotc(): +/* terminal_echotc(): * Print the termcap string out with variable substitution */ protected int /*ARGSUSED*/ -term_echotc(EditLine *el, int argc __attribute__((__unused__)), - const char **argv) +terminal_echotc(EditLine *el, int argc __attribute__((__unused__)), + const Char **argv) { - char *cap, *scap, *ep; + char *cap, *scap; + Char *ep; int arg_need, arg_cols, arg_rows; int verbose = 0, silent = 0; char *area; @@ -1491,7 +1481,7 @@ term_echotc(EditLine *el, int argc __attribute__((__unused__)), area = buf; if (argv == NULL || argv[1] == NULL) - return (-1); + return -1; argv++; if (argv[0][0] == '-') { @@ -1509,62 +1499,52 @@ term_echotc(EditLine *el, int argc __attribute__((__unused__)), argv++; } if (!*argv || *argv[0] == '\0') - return (0); - if (strcmp(*argv, "tabs") == 0) { + return 0; + if (Strcmp(*argv, STR("tabs")) == 0) { (void) fprintf(el->el_outfile, fmts, EL_CAN_TAB ? "yes" : "no"); - return (0); - } else if (strcmp(*argv, "meta") == 0) { + return 0; + } else if (Strcmp(*argv, STR("meta")) == 0) { (void) fprintf(el->el_outfile, fmts, Val(T_km) ? "yes" : "no"); - return (0); - } else if (strcmp(*argv, "xn") == 0) { + return 0; + } else if (Strcmp(*argv, STR("xn")) == 0) { (void) fprintf(el->el_outfile, fmts, EL_HAS_MAGIC_MARGINS ? "yes" : "no"); - return (0); - } else if (strcmp(*argv, "am") == 0) { + return 0; + } else if (Strcmp(*argv, STR("am")) == 0) { (void) fprintf(el->el_outfile, fmts, EL_HAS_AUTO_MARGINS ? "yes" : "no"); - return (0); - } else if (strcmp(*argv, "baud") == 0) { -#ifdef notdef - int i; - - for (i = 0; baud_rate[i].b_name != NULL; i++) - if (el->el_tty.t_speed == baud_rate[i].b_rate) { - (void) fprintf(el->el_outfile, fmts, - baud_rate[i].b_name); - return (0); - } - (void) fprintf(el->el_outfile, fmtd, 0); -#else + return 0; + } else if (Strcmp(*argv, STR("baud")) == 0) { (void) fprintf(el->el_outfile, fmtd, (int)el->el_tty.t_speed); -#endif - return (0); - } else if (strcmp(*argv, "rows") == 0 || strcmp(*argv, "lines") == 0) { + return 0; + } else if (Strcmp(*argv, STR("rows")) == 0 || + Strcmp(*argv, STR("lines")) == 0) { (void) fprintf(el->el_outfile, fmtd, Val(T_li)); - return (0); - } else if (strcmp(*argv, "cols") == 0) { + return 0; + } else if (Strcmp(*argv, STR("cols")) == 0) { (void) fprintf(el->el_outfile, fmtd, Val(T_co)); - return (0); + return 0; } /* * Try to use our local definition first */ scap = NULL; for (t = tstr; t->name != NULL; t++) - if (strcmp(t->name, *argv) == 0) { - scap = el->el_term.t_str[t - tstr]; + if (strcmp(t->name, + ct_encode_string(*argv, &el->el_scratch)) == 0) { + scap = el->el_terminal.t_str[t - tstr]; break; } if (t->name == NULL) { /* XXX: some systems' tgetstr needs non const */ - scap = tgetstr(strchr(*argv, **argv), &area); + scap = tgetstr(ct_encode_string(*argv, &el->el_scratch), &area); } if (!scap || scap[0] == '\0') { if (!silent) (void) fprintf(el->el_errfile, - "echotc: Termcap parameter `%s' not found.\n", + "echotc: Termcap parameter `" FSTR "' not found.\n", *argv); - return (-1); + return -1; } /* * Count home many values we need for this capability. @@ -1605,11 +1585,11 @@ term_echotc(EditLine *el, int argc __attribute__((__unused__)), if (*argv && *argv[0]) { if (!silent) (void) fprintf(el->el_errfile, - "echotc: Warning: Extra argument `%s'.\n", + "echotc: Warning: Extra argument `" FSTR "'.\n", *argv); - return (-1); + return -1; } - term_tputs(el, scap, 1); + terminal_tputs(el, scap, 1); break; case 1: argv++; @@ -1617,27 +1597,27 @@ term_echotc(EditLine *el, int argc __attribute__((__unused__)), if (!silent) (void) fprintf(el->el_errfile, "echotc: Warning: Missing argument.\n"); - return (-1); + return -1; } arg_cols = 0; - i = strtol(*argv, &ep, 10); + i = Strtol(*argv, &ep, 10); if (*ep != '\0' || i < 0) { if (!silent) (void) fprintf(el->el_errfile, - "echotc: Bad value `%s' for rows.\n", + "echotc: Bad value `" FSTR "' for rows.\n", *argv); - return (-1); + return -1; } arg_rows = (int) i; argv++; if (*argv && *argv[0]) { if (!silent) (void) fprintf(el->el_errfile, - "echotc: Warning: Extra argument `%s'.\n", - *argv); - return (-1); + "echotc: Warning: Extra argument `" FSTR + "'.\n", *argv); + return -1; } - term_tputs(el, tgoto(scap, arg_cols, arg_rows), 1); + terminal_tputs(el, tgoto(scap, arg_cols, arg_rows), 1); break; default: /* This is wrong, but I will ignore it... */ @@ -1652,15 +1632,15 @@ term_echotc(EditLine *el, int argc __attribute__((__unused__)), if (!silent) (void) fprintf(el->el_errfile, "echotc: Warning: Missing argument.\n"); - return (-1); + return -1; } - i = strtol(*argv, &ep, 10); + i = Strtol(*argv, &ep, 10); if (*ep != '\0' || i < 0) { if (!silent) (void) fprintf(el->el_errfile, - "echotc: Bad value `%s' for cols.\n", + "echotc: Bad value `" FSTR "' for cols.\n", *argv); - return (-1); + return -1; } arg_cols = (int) i; argv++; @@ -1668,33 +1648,33 @@ term_echotc(EditLine *el, int argc __attribute__((__unused__)), if (!silent) (void) fprintf(el->el_errfile, "echotc: Warning: Missing argument.\n"); - return (-1); + return -1; } - i = strtol(*argv, &ep, 10); + i = Strtol(*argv, &ep, 10); if (*ep != '\0' || i < 0) { if (!silent) (void) fprintf(el->el_errfile, - "echotc: Bad value `%s' for rows.\n", + "echotc: Bad value `" FSTR "' for rows.\n", *argv); - return (-1); + return -1; } arg_rows = (int) i; if (*ep != '\0') { if (!silent) (void) fprintf(el->el_errfile, - "echotc: Bad value `%s'.\n", *argv); - return (-1); + "echotc: Bad value `" FSTR "'.\n", *argv); + return -1; } argv++; if (*argv && *argv[0]) { if (!silent) (void) fprintf(el->el_errfile, - "echotc: Warning: Extra argument `%s'.\n", - *argv); - return (-1); + "echotc: Warning: Extra argument `" FSTR + "'.\n", *argv); + return -1; } - term_tputs(el, tgoto(scap, arg_cols, arg_rows), arg_rows); + terminal_tputs(el, tgoto(scap, arg_cols, arg_rows), arg_rows); break; } - return (0); + return 0; } diff --git a/cmd-line-utils/libedit/tokenizer.c b/cmd-line-utils/libedit/tokenizer.c index 5161cdd0a22..7267164e9b6 100644 --- a/cmd-line-utils/libedit/tokenizer.c +++ b/cmd-line-utils/libedit/tokenizer.c @@ -1,4 +1,4 @@ -/* $NetBSD: tokenizer.c,v 1.14 2003/12/05 13:37:48 lukem Exp $ */ +/* $NetBSD: tokenizer.c,v 1.19 2011/07/28 20:50:55 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -40,51 +40,53 @@ static char sccsid[] = "@(#)tokenizer.c 8.1 (Berkeley) 6/4/93"; #endif #endif /* not lint && not SCCSID */ +/* We build this file twice, once as NARROW, once as WIDE. */ /* * tokenize.c: Bourne shell like tokenizer */ #include #include #include "histedit.h" +#include "chartype.h" typedef enum { Q_none, Q_single, Q_double, Q_one, Q_doubleone } quote_t; -#define IFS "\t \n" - #define TOK_KEEP 1 #define TOK_EAT 2 #define WINCR 20 #define AINCR 10 -#define tok_strdup(a) strdup(a) +#define IFS STR("\t \n") + #define tok_malloc(a) malloc(a) #define tok_free(a) free(a) #define tok_realloc(a, b) realloc(a, b) +#define tok_strdup(a) Strdup(a) -struct tokenizer { - char *ifs; /* In field separator */ +struct TYPE(tokenizer) { + Char *ifs; /* In field separator */ int argc, amax; /* Current and maximum number of args */ - char **argv; /* Argument list */ - char *wptr, *wmax; /* Space and limit on the word buffer */ - char *wstart; /* Beginning of next word */ - char *wspace; /* Space of word buffer */ + Char **argv; /* Argument list */ + Char *wptr, *wmax; /* Space and limit on the word buffer */ + Char *wstart; /* Beginning of next word */ + Char *wspace; /* Space of word buffer */ quote_t quote; /* Quoting state */ int flags; /* flags; */ }; -private void tok_finish(Tokenizer *); +private void FUN(tok,finish)(TYPE(Tokenizer) *); -/* tok_finish(): +/* FUN(tok,finish)(): * Finish a word in the tokenizer. */ private void -tok_finish(Tokenizer *tok) +FUN(tok,finish)(TYPE(Tokenizer) *tok) { *tok->wptr = '\0'; @@ -97,35 +99,35 @@ tok_finish(Tokenizer *tok) } -/* tok_init(): +/* FUN(tok,init)(): * Initialize the tokenizer */ -public Tokenizer * -tok_init(const char *ifs) +public TYPE(Tokenizer) * +FUN(tok,init)(const Char *ifs) { - Tokenizer *tok = (Tokenizer *) tok_malloc(sizeof(Tokenizer)); + TYPE(Tokenizer) *tok = tok_malloc(sizeof(*tok)); if (tok == NULL) return NULL; tok->ifs = tok_strdup(ifs ? ifs : IFS); if (tok->ifs == NULL) { - tok_free((ptr_t)tok); + tok_free(tok); return NULL; } tok->argc = 0; tok->amax = AINCR; - tok->argv = (char **) tok_malloc(sizeof(char *) * tok->amax); + tok->argv = tok_malloc(sizeof(*tok->argv) * tok->amax); if (tok->argv == NULL) { - tok_free((ptr_t)tok->ifs); - tok_free((ptr_t)tok); + tok_free(tok->ifs); + tok_free(tok); return NULL; } tok->argv[0] = NULL; - tok->wspace = (char *) tok_malloc(WINCR); + tok->wspace = tok_malloc(WINCR * sizeof(*tok->wspace)); if (tok->wspace == NULL) { - tok_free((ptr_t)tok->argv); - tok_free((ptr_t)tok->ifs); - tok_free((ptr_t)tok); + tok_free(tok->argv); + tok_free(tok->ifs); + tok_free(tok); return NULL; } tok->wmax = tok->wspace + WINCR; @@ -138,11 +140,11 @@ tok_init(const char *ifs) } -/* tok_reset(): +/* FUN(tok,reset)(): * Reset the tokenizer */ public void -tok_reset(Tokenizer *tok) +FUN(tok,reset)(TYPE(Tokenizer) *tok) { tok->argc = 0; @@ -153,25 +155,25 @@ tok_reset(Tokenizer *tok) } -/* tok_end(): +/* FUN(tok,end)(): * Clean up */ public void -tok_end(Tokenizer *tok) +FUN(tok,end)(TYPE(Tokenizer) *tok) { - tok_free((ptr_t) tok->ifs); - tok_free((ptr_t) tok->wspace); - tok_free((ptr_t) tok->argv); - tok_free((ptr_t) tok); + tok_free(tok->ifs); + tok_free(tok->wspace); + tok_free(tok->argv); + tok_free(tok); } -/* tok_line(): +/* FUN(tok,line)(): * Bourne shell (sh(1)) like tokenizing * Arguments: - * tok current tokenizer state (setup with tok_init()) + * tok current tokenizer state (setup with FUN(tok,init)()) * line line to parse * Returns: * -1 Internal error @@ -186,20 +188,20 @@ tok_end(Tokenizer *tok) * cursorv if !NULL, offset in argv[cursorc] of cursor */ public int -tok_line(Tokenizer *tok, const LineInfo *line, - int *argc, const char ***argv, int *cursorc, int *cursoro) +FUN(tok,line)(TYPE(Tokenizer) *tok, const TYPE(LineInfo) *line, + int *argc, const Char ***argv, int *cursorc, int *cursoro) { - const char *ptr; + const Char *ptr; int cc, co; cc = co = -1; ptr = line->buffer; for (ptr = line->buffer; ;ptr++) { if (ptr >= line->lastchar) - ptr = ""; + ptr = STR(""); if (ptr == line->cursor) { cc = tok->argc; - co = tok->wptr - tok->wstart; + co = (int)(tok->wptr - tok->wstart); } switch (*ptr) { case '\'': @@ -357,8 +359,8 @@ tok_line(Tokenizer *tok, const LineInfo *line, tok->flags &= ~TOK_EAT; switch (tok->quote) { case Q_none: - if (strchr(tok->ifs, *ptr) != NULL) - tok_finish(tok); + if (Strchr(tok->ifs, *ptr) != NULL) + FUN(tok,finish)(tok); else *tok->wptr++ = *ptr; break; @@ -389,7 +391,8 @@ tok_line(Tokenizer *tok, const LineInfo *line, if (tok->wptr >= tok->wmax - 4) { size_t size = tok->wmax - tok->wspace + WINCR; - char *s = (char *) tok_realloc(tok->wspace, size); + Char *s = tok_realloc(tok->wspace, + size * sizeof(*s)); if (s == NULL) return (-1); @@ -406,10 +409,9 @@ tok_line(Tokenizer *tok, const LineInfo *line, tok->wmax = s + size; } if (tok->argc >= tok->amax - 4) { - char **p; + Char **p; tok->amax += AINCR; - p = (char **) tok_realloc(tok->argv, - tok->amax * sizeof(char *)); + p = tok_realloc(tok->argv, tok->amax * sizeof(*p)); if (p == NULL) return (-1); tok->argv = p; @@ -418,29 +420,30 @@ tok_line(Tokenizer *tok, const LineInfo *line, tok_line_outok: if (cc == -1 && co == -1) { cc = tok->argc; - co = tok->wptr - tok->wstart; + co = (int)(tok->wptr - tok->wstart); } if (cursorc != NULL) *cursorc = cc; if (cursoro != NULL) *cursoro = co; - tok_finish(tok); - *argv = (const char **)tok->argv; + FUN(tok,finish)(tok); + *argv = (const Char **)tok->argv; *argc = tok->argc; return (0); } -/* tok_str(): +/* FUN(tok,str)(): * Simpler version of tok_line, taking a NUL terminated line * and splitting into words, ignoring cursor state. */ public int -tok_str(Tokenizer *tok, const char *line, int *argc, const char ***argv) +FUN(tok,str)(TYPE(Tokenizer) *tok, const Char *line, int *argc, + const Char ***argv) { - LineInfo li; + TYPE(LineInfo) li; memset(&li, 0, sizeof(li)); li.buffer = line; - li.cursor = li.lastchar = strchr(line, '\0'); - return (tok_line(tok, &li, argc, argv, NULL, NULL)); + li.cursor = li.lastchar = Strchr(line, '\0'); + return (FUN(tok,line)(tok, &li, argc, argv, NULL, NULL)); } diff --git a/cmd-line-utils/libedit/tokenizern.c b/cmd-line-utils/libedit/tokenizern.c new file mode 100644 index 00000000000..92376e066f1 --- /dev/null +++ b/cmd-line-utils/libedit/tokenizern.c @@ -0,0 +1,5 @@ +#define NARROW_WRAPPER +#include "config.h" +#undef WIDECHAR +#define NARROWCHAR +#include "./tokenizer.c" diff --git a/cmd-line-utils/libedit/tty.c b/cmd-line-utils/libedit/tty.c index 3706905fc79..46624a87077 100644 --- a/cmd-line-utils/libedit/tty.c +++ b/cmd-line-utils/libedit/tty.c @@ -1,4 +1,4 @@ -/* $NetBSD: tty.c,v 1.28 2009/02/06 19:53:23 sketch Exp $ */ +/* $NetBSD: tty.c,v 1.41 2011/10/04 15:27:04 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -45,8 +45,10 @@ static char sccsid[] = "@(#)tty.c 8.1 (Berkeley) 6/4/93"; */ #include #include -#include "tty.h" +#include /* for isatty */ +#include /* for ffs */ #include "el.h" +#include "tty.h" typedef struct ttymodes_t { const char *m_name; @@ -55,7 +57,7 @@ typedef struct ttymodes_t { } ttymodes_t; typedef struct ttymap_t { - int nch, och; /* Internal and termio rep of chars */ + Int nch, och; /* Internal and termio rep of chars */ el_action_t bind[3]; /* emacs, vi, and vi-cmd */ } ttymap_t; @@ -151,7 +153,7 @@ private const ttymap_t tty_map[] = { {C_LNEXT, VLNEXT, {ED_QUOTED_INSERT, ED_QUOTED_INSERT, ED_UNASSIGNED}}, #endif /* VLNEXT */ - {-1, -1, + {(Int)-1, (Int)-1, {ED_UNASSIGNED, ED_UNASSIGNED, ED_UNASSIGNED}} }; @@ -492,14 +494,21 @@ tty_setup(EditLine *el) int rst = 1; if (el->el_flags & EDIT_DISABLED) - return (0); + return 0; + if (!isatty(el->el_outfd)) { +#ifdef DEBUG_TTY + (void) fprintf(el->el_errfile, + "tty_setup: isatty: %s\n", strerror(errno)); +#endif /* DEBUG_TTY */ + return -1; + } if (tty_getty(el, &el->el_tty.t_ed) == -1) { #ifdef DEBUG_TTY (void) fprintf(el->el_errfile, "tty_setup: tty_getty: %s\n", strerror(errno)); #endif /* DEBUG_TTY */ - return (-1); + return -1; } el->el_tty.t_ts = el->el_tty.t_ex = el->el_tty.t_ed; @@ -549,13 +558,9 @@ tty_setup(EditLine *el) "tty_setup: tty_setty: %s\n", strerror(errno)); #endif /* DEBUG_TTY */ - return (-1); + return -1; } } -#ifdef notdef - else - tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]); -#endif el->el_tty.t_ed.c_iflag &= ~el->el_tty.t_t[ED_IO][MD_INP].t_clrmask; el->el_tty.t_ed.c_iflag |= el->el_tty.t_t[ED_IO][MD_INP].t_setmask; @@ -571,7 +576,7 @@ tty_setup(EditLine *el) tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]); tty_bind_char(el, 1); - return (0); + return 0; } protected int @@ -582,7 +587,7 @@ tty_init(EditLine *el) el->el_tty.t_vdisable = _POSIX_VDISABLE; (void) memcpy(el->el_tty.t_t, ttyperm, sizeof(ttyperm_t)); (void) memcpy(el->el_tty.t_c, ttychar, sizeof(ttychar_t)); - return (tty_setup(el)); + return tty_setup(el); } @@ -608,7 +613,7 @@ tty__getspeed(struct termios *td) if ((spd = cfgetispeed(td)) == 0) spd = cfgetospeed(td); - return (spd); + return spd; } /* tty__getspeed(): @@ -892,7 +897,7 @@ tty_bind_char(EditLine *el, int force) unsigned char *t_n = el->el_tty.t_c[ED_IO]; unsigned char *t_o = el->el_tty.t_ed.c_cc; - unsigned char new[2], old[2]; + Char new[2], old[2]; const ttymap_t *tp; el_action_t *map, *alt; const el_action_t *dmap, *dalt; @@ -908,22 +913,22 @@ tty_bind_char(EditLine *el, int force) dalt = NULL; } - for (tp = tty_map; tp->nch != -1; tp++) { + for (tp = tty_map; tp->nch != (Int)-1; tp++) { new[0] = t_n[tp->nch]; old[0] = t_o[tp->och]; if (new[0] == old[0] && !force) continue; /* Put the old default binding back, and set the new binding */ - key_clear(el, map, (char *)old); - map[old[0]] = dmap[old[0]]; - key_clear(el, map, (char *)new); + keymacro_clear(el, map, old); + map[UC(old[0])] = dmap[UC(old[0])]; + keymacro_clear(el, map, new); /* MAP_VI == 1, MAP_EMACS == 0... */ - map[new[0]] = tp->bind[el->el_map.type]; + map[UC(new[0])] = tp->bind[el->el_map.type]; if (dalt) { - key_clear(el, alt, (char *)old); - alt[old[0]] = dalt[old[0]]; - key_clear(el, alt, (char *)new); - alt[new[0]] = tp->bind[el->el_map.type + 1]; + keymacro_clear(el, alt, old); + alt[UC(old[0])] = dalt[UC(old[0])]; + keymacro_clear(el, alt, new); + alt[UC(new[0])] = tp->bind[el->el_map.type + 1]; } } } @@ -937,21 +942,21 @@ tty_rawmode(EditLine *el) { if (el->el_tty.t_mode == ED_IO || el->el_tty.t_mode == QU_IO) - return (0); + return 0; if (el->el_flags & EDIT_DISABLED) - return (0); + return 0; if (tty_getty(el, &el->el_tty.t_ts) == -1) { #ifdef DEBUG_TTY (void) fprintf(el->el_errfile, "tty_rawmode: tty_getty: %s\n", strerror(errno)); #endif /* DEBUG_TTY */ - return (-1); + return -1; } /* * We always keep up with the eight bit setting and the speed of the - * tty. But only we only believe changes that are made to cooked mode! + * tty. But we only believe changes that are made to cooked mode! */ el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ts); el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ts); @@ -1077,10 +1082,10 @@ tty_rawmode(EditLine *el) (void) fprintf(el->el_errfile, "tty_rawmode: tty_setty: %s\n", strerror(errno)); #endif /* DEBUG_TTY */ - return (-1); + return -1; } el->el_tty.t_mode = ED_IO; - return (0); + return 0; } @@ -1092,10 +1097,10 @@ tty_cookedmode(EditLine *el) { /* set tty in normal setup */ if (el->el_tty.t_mode == EX_IO) - return (0); + return 0; if (el->el_flags & EDIT_DISABLED) - return (0); + return 0; if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ex) == -1) { #ifdef DEBUG_TTY @@ -1103,10 +1108,10 @@ tty_cookedmode(EditLine *el) "tty_cookedmode: tty_setty: %s\n", strerror(errno)); #endif /* DEBUG_TTY */ - return (-1); + return -1; } el->el_tty.t_mode = EX_IO; - return (0); + return 0; } @@ -1117,7 +1122,7 @@ protected int tty_quotemode(EditLine *el) { if (el->el_tty.t_mode == QU_IO) - return (0); + return 0; el->el_tty.t_qu = el->el_tty.t_ed; @@ -1138,10 +1143,10 @@ tty_quotemode(EditLine *el) (void) fprintf(el->el_errfile, "QuoteModeOn: tty_setty: %s\n", strerror(errno)); #endif /* DEBUG_TTY */ - return (-1); + return -1; } el->el_tty.t_mode = QU_IO; - return (0); + return 0; } @@ -1153,16 +1158,16 @@ tty_noquotemode(EditLine *el) { if (el->el_tty.t_mode != QU_IO) - return (0); + return 0; if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ed) == -1) { #ifdef DEBUG_TTY (void) fprintf(el->el_errfile, "QuoteModeOff: tty_setty: %s\n", strerror(errno)); #endif /* DEBUG_TTY */ - return (-1); + return -1; } el->el_tty.t_mode = ED_IO; - return (0); + return 0; } @@ -1171,19 +1176,20 @@ tty_noquotemode(EditLine *el) */ protected int /*ARGSUSED*/ -tty_stty(EditLine *el, int argc __attribute__((__unused__)), const char **argv) +tty_stty(EditLine *el, int argc __attribute__((__unused__)), const Char **argv) { const ttymodes_t *m; char x; int aflag = 0; - const char *s, *d; - const char *name; + const Char *s, *d; + char name[EL_BUFSIZ]; struct termios *tios = &el->el_tty.t_ex; int z = EX_IO; if (argv == NULL) - return (-1); - name = *argv++; + return -1; + strncpy(name, ct_encode_string(*argv++, &el->el_scratch), sizeof(name)); + name[sizeof(name) - 1] = '\0'; while (argv && *argv && argv[0][0] == '-' && argv[0][2] == '\0') switch (argv[0][1]) { @@ -1210,12 +1216,12 @@ tty_stty(EditLine *el, int argc __attribute__((__unused__)), const char **argv) (void) fprintf(el->el_errfile, "%s: Unknown switch `%c'.\n", name, argv[0][1]); - return (-1); + return -1; } if (!argv || !*argv) { int i = -1; - int len = 0, st = 0, cu; + size_t len = 0, st = 0, cu; for (m = ttymodes; m->m_name; m++) { if (m->m_type != i) { (void) fprintf(el->el_outfile, "%s%s", @@ -1228,8 +1234,9 @@ tty_stty(EditLine *el, int argc __attribute__((__unused__)), const char **argv) if (i != -1) { x = (el->el_tty.t_t[z][i].t_setmask & m->m_value) ? '+' : '\0'; - x = (el->el_tty.t_t[z][i].t_clrmask & m->m_value) - ? '-' : x; + + if (el->el_tty.t_t[z][i].t_clrmask & m->m_value) + x = '-'; } else { x = '\0'; } @@ -1238,9 +1245,9 @@ tty_stty(EditLine *el, int argc __attribute__((__unused__)), const char **argv) cu = strlen(m->m_name) + (x != '\0') + 1; - if (len + cu >= el->el_term.t_size.h) { + if (len + cu >= (size_t)el->el_terminal.t_size.h) { (void) fprintf(el->el_outfile, "\n%*s", - st, ""); + (int)st, ""); len = st + cu; } else len += cu; @@ -1254,40 +1261,41 @@ tty_stty(EditLine *el, int argc __attribute__((__unused__)), const char **argv) } } (void) fprintf(el->el_outfile, "\n"); - return (0); + return 0; } while (argv && (s = *argv++)) { - const char *p; + const Char *p; switch (*s) { case '+': case '-': - x = *s++; + x = (char)*s++; break; default: x = '\0'; break; } d = s; - p = strchr(s, '='); + p = Strchr(s, '='); for (m = ttymodes; m->m_name; m++) - if ((p ? strncmp(m->m_name, d, (size_t)(p - d)) : - strcmp(m->m_name, d)) == 0 && + if ((p ? strncmp(m->m_name, ct_encode_string(d, &el->el_scratch), (size_t)(p - d)) : + strcmp(m->m_name, ct_encode_string(d, &el->el_scratch))) == 0 && (p == NULL || m->m_type == MD_CHAR)) break; if (!m->m_name) { (void) fprintf(el->el_errfile, - "%s: Invalid argument `%s'.\n", name, d); - return (-1); + "%s: Invalid argument `" FSTR "'.\n", name, d); + return -1; } if (p) { int c = ffs((int)m->m_value); - int v = *++p ? parse__escape((const char **) &p) : + int v = *++p ? parse__escape(&p) : el->el_tty.t_vdisable; - assert(c-- != 0); + assert(c != 0); + c--; c = tty__getcharindex(c); assert(c != -1); - tios->c_cc[c] = v; + tios->c_cc[c] = (cc_t)v; continue; } switch (x) { @@ -1312,11 +1320,11 @@ tty_stty(EditLine *el, int argc __attribute__((__unused__)), const char **argv) (void) fprintf(el->el_errfile, "tty_stty: tty_setty: %s\n", strerror(errno)); #endif /* DEBUG_TTY */ - return (-1); + return -1; } } - return (0); + return 0; } diff --git a/cmd-line-utils/libedit/tty.h b/cmd-line-utils/libedit/tty.h index 10e9b98c953..04485eb83ad 100644 --- a/cmd-line-utils/libedit/tty.h +++ b/cmd-line-utils/libedit/tty.h @@ -1,4 +1,4 @@ -/* $NetBSD: tty.h,v 1.11 2005/06/01 11:37:52 lukem Exp $ */ +/* $NetBSD: tty.h,v 1.13 2011/08/16 16:25:15 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -40,6 +40,7 @@ #ifndef _h_el_tty #define _h_el_tty +#include "sys.h" #include "histedit.h" #include #include @@ -430,7 +431,7 @@ #define C_MIN 23 #define C_TIME 24 #define C_NCC 25 -#define C_SH(A) (1 << (A)) +#define C_SH(A) ((unsigned int)(1 << (A))) /* * Terminal dependend data structures @@ -458,7 +459,7 @@ typedef unsigned char ttychar_t[NN_IO][C_NCC]; protected int tty_init(EditLine *); protected void tty_end(EditLine *); -protected int tty_stty(EditLine *, int, const char **); +protected int tty_stty(EditLine *, int, const Char **); protected int tty_rawmode(EditLine *); protected int tty_cookedmode(EditLine *); protected int tty_quotemode(EditLine *); diff --git a/cmd-line-utils/libedit/vi.c b/cmd-line-utils/libedit/vi.c index beffc7b40b5..9a4b97a977e 100644 --- a/cmd-line-utils/libedit/vi.c +++ b/cmd-line-utils/libedit/vi.c @@ -1,4 +1,4 @@ -/* $NetBSD: vi.c,v 1.28 2009/02/06 13:14:37 sketch Exp $ */ +/* $NetBSD: vi.c,v 1.41 2011/10/04 15:27:04 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -35,6 +35,7 @@ #include "config.h" #include #include +#include #include #if !defined(lint) && !defined(SCCSID) @@ -49,25 +50,25 @@ static char sccsid[] = "@(#)vi.c 8.1 (Berkeley) 6/4/93"; */ #include "el.h" -private el_action_t cv_action(EditLine *, int); -private el_action_t cv_paste(EditLine *, int); +private el_action_t cv_action(EditLine *, Int); +private el_action_t cv_paste(EditLine *, Int); /* cv_action(): * Handle vi actions. */ private el_action_t -cv_action(EditLine *el, int c) +cv_action(EditLine *el, Int c) { if (el->el_chared.c_vcmd.action != NOP) { /* 'cc', 'dd' and (possibly) friends */ - if (c != el->el_chared.c_vcmd.action) + if (c != (Int)el->el_chared.c_vcmd.action) return CC_ERROR; if (!(c & YANK)) cv_undo(el); cv_yank(el, el->el_line.buffer, - el->el_line.lastchar - el->el_line.buffer); + (int)(el->el_line.lastchar - el->el_line.buffer)); el->el_chared.c_vcmd.action = NOP; el->el_chared.c_vcmd.pos = 0; if (!(c & YANK)) { @@ -77,26 +78,26 @@ cv_action(EditLine *el, int c) if (c & INSERT) el->el_map.current = el->el_map.key; - return (CC_REFRESH); + return CC_REFRESH; } el->el_chared.c_vcmd.pos = el->el_line.cursor; el->el_chared.c_vcmd.action = c; - return (CC_ARGHACK); + return CC_ARGHACK; } /* cv_paste(): * Paste previous deletion before or after the cursor */ private el_action_t -cv_paste(EditLine *el, int c) +cv_paste(EditLine *el, Int c) { c_kill_t *k = &el->el_chared.c_kill; - int len = k->last - k->buf; + size_t len = (size_t)(k->last - k->buf); if (k->buf == NULL || len == 0) - return (CC_ERROR); + return CC_ERROR; #ifdef DEBUG_PASTE - (void) fprintf(el->el_errfile, "Paste: \"%.*s\"\n", len, k->buf); + (void) fprintf(el->el_errfile, "Paste: \"%.*s\"\n", (int)len, k->buf); #endif cv_undo(el); @@ -104,12 +105,13 @@ cv_paste(EditLine *el, int c) if (!c && el->el_line.cursor < el->el_line.lastchar) el->el_line.cursor++; - c_insert(el, len); + c_insert(el, (int)len); if (el->el_line.cursor + len > el->el_line.lastchar) - return (CC_ERROR); - (void) memcpy(el->el_line.cursor, k->buf, len +0u); + return CC_ERROR; + (void) memcpy(el->el_line.cursor, k->buf, len * + sizeof(*el->el_line.cursor)); - return (CC_REFRESH); + return CC_REFRESH; } @@ -119,10 +121,10 @@ cv_paste(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -vi_paste_next(EditLine *el, int c __attribute__((__unused__))) +vi_paste_next(EditLine *el, Int c __attribute__((__unused__))) { - return (cv_paste(el, 0)); + return cv_paste(el, 0); } @@ -132,10 +134,10 @@ vi_paste_next(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -vi_paste_prev(EditLine *el, int c __attribute__((__unused__))) +vi_paste_prev(EditLine *el, Int c __attribute__((__unused__))) { - return (cv_paste(el, 1)); + return cv_paste(el, 1); } @@ -145,11 +147,11 @@ vi_paste_prev(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -vi_prev_big_word(EditLine *el, int c __attribute__((__unused__))) +vi_prev_big_word(EditLine *el, Int c __attribute__((__unused__))) { if (el->el_line.cursor == el->el_line.buffer) - return (CC_ERROR); + return CC_ERROR; el->el_line.cursor = cv_prev_word(el->el_line.cursor, el->el_line.buffer, @@ -158,9 +160,9 @@ vi_prev_big_word(EditLine *el, int c __attribute__((__unused__))) if (el->el_chared.c_vcmd.action != NOP) { cv_delfini(el); - return (CC_REFRESH); + return CC_REFRESH; } - return (CC_CURSOR); + return CC_CURSOR; } @@ -170,11 +172,11 @@ vi_prev_big_word(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -vi_prev_word(EditLine *el, int c __attribute__((__unused__))) +vi_prev_word(EditLine *el, Int c __attribute__((__unused__))) { if (el->el_line.cursor == el->el_line.buffer) - return (CC_ERROR); + return CC_ERROR; el->el_line.cursor = cv_prev_word(el->el_line.cursor, el->el_line.buffer, @@ -183,9 +185,9 @@ vi_prev_word(EditLine *el, int c __attribute__((__unused__))) if (el->el_chared.c_vcmd.action != NOP) { cv_delfini(el); - return (CC_REFRESH); + return CC_REFRESH; } - return (CC_CURSOR); + return CC_CURSOR; } @@ -195,11 +197,11 @@ vi_prev_word(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -vi_next_big_word(EditLine *el, int c __attribute__((__unused__))) +vi_next_big_word(EditLine *el, Int c __attribute__((__unused__))) { if (el->el_line.cursor >= el->el_line.lastchar - 1) - return (CC_ERROR); + return CC_ERROR; el->el_line.cursor = cv_next_word(el, el->el_line.cursor, el->el_line.lastchar, el->el_state.argument, cv__isWord); @@ -207,9 +209,9 @@ vi_next_big_word(EditLine *el, int c __attribute__((__unused__))) if (el->el_map.type == MAP_VI) if (el->el_chared.c_vcmd.action != NOP) { cv_delfini(el); - return (CC_REFRESH); + return CC_REFRESH; } - return (CC_CURSOR); + return CC_CURSOR; } @@ -219,11 +221,11 @@ vi_next_big_word(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -vi_next_word(EditLine *el, int c __attribute__((__unused__))) +vi_next_word(EditLine *el, Int c __attribute__((__unused__))) { if (el->el_line.cursor >= el->el_line.lastchar - 1) - return (CC_ERROR); + return CC_ERROR; el->el_line.cursor = cv_next_word(el, el->el_line.cursor, el->el_line.lastchar, el->el_state.argument, cv__isword); @@ -231,9 +233,9 @@ vi_next_word(EditLine *el, int c __attribute__((__unused__))) if (el->el_map.type == MAP_VI) if (el->el_chared.c_vcmd.action != NOP) { cv_delfini(el); - return (CC_REFRESH); + return CC_REFRESH; } - return (CC_CURSOR); + return CC_CURSOR; } @@ -242,20 +244,20 @@ vi_next_word(EditLine *el, int c __attribute__((__unused__))) * [~] */ protected el_action_t -vi_change_case(EditLine *el, int c) +vi_change_case(EditLine *el, Int c) { int i; if (el->el_line.cursor >= el->el_line.lastchar) - return (CC_ERROR); + return CC_ERROR; cv_undo(el); for (i = 0; i < el->el_state.argument; i++) { - c = *(unsigned char *)el->el_line.cursor; - if (isupper(c)) - *el->el_line.cursor = tolower(c); - else if (islower(c)) - *el->el_line.cursor = toupper(c); + c = *el->el_line.cursor; + if (Isupper(c)) + *el->el_line.cursor = Tolower(c); + else if (Islower(c)) + *el->el_line.cursor = Toupper(c); if (++el->el_line.cursor >= el->el_line.lastchar) { el->el_line.cursor--; @@ -274,14 +276,14 @@ vi_change_case(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -vi_change_meta(EditLine *el, int c __attribute__((__unused__))) +vi_change_meta(EditLine *el, Int c __attribute__((__unused__))) { /* * Delete with insert == change: first we delete and then we leave in * insert mode. */ - return (cv_action(el, DELETE | INSERT)); + return cv_action(el, DELETE | INSERT); } @@ -291,13 +293,13 @@ vi_change_meta(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -vi_insert_at_bol(EditLine *el, int c __attribute__((__unused__))) +vi_insert_at_bol(EditLine *el, Int c __attribute__((__unused__))) { el->el_line.cursor = el->el_line.buffer; cv_undo(el); el->el_map.current = el->el_map.key; - return (CC_CURSOR); + return CC_CURSOR; } @@ -307,7 +309,7 @@ vi_insert_at_bol(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -vi_replace_char(EditLine *el, int c __attribute__((__unused__))) +vi_replace_char(EditLine *el, Int c __attribute__((__unused__))) { if (el->el_line.cursor >= el->el_line.lastchar) @@ -316,7 +318,7 @@ vi_replace_char(EditLine *el, int c __attribute__((__unused__))) el->el_map.current = el->el_map.key; el->el_state.inputmode = MODE_REPLACE_1; cv_undo(el); - return (CC_ARGHACK); + return CC_ARGHACK; } @@ -326,13 +328,13 @@ vi_replace_char(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -vi_replace_mode(EditLine *el, int c __attribute__((__unused__))) +vi_replace_mode(EditLine *el, Int c __attribute__((__unused__))) { el->el_map.current = el->el_map.key; el->el_state.inputmode = MODE_REPLACE; cv_undo(el); - return (CC_NORM); + return CC_NORM; } @@ -342,12 +344,12 @@ vi_replace_mode(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -vi_substitute_char(EditLine *el, int c __attribute__((__unused__))) +vi_substitute_char(EditLine *el, Int c __attribute__((__unused__))) { c_delafter(el, el->el_state.argument); el->el_map.current = el->el_map.key; - return (CC_REFRESH); + return CC_REFRESH; } @@ -357,15 +359,15 @@ vi_substitute_char(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -vi_substitute_line(EditLine *el, int c __attribute__((__unused__))) +vi_substitute_line(EditLine *el, Int c __attribute__((__unused__))) { cv_undo(el); cv_yank(el, el->el_line.buffer, - el->el_line.lastchar - el->el_line.buffer); + (int)(el->el_line.lastchar - el->el_line.buffer)); (void) em_kill_line(el, 0); el->el_map.current = el->el_map.key; - return (CC_REFRESH); + return CC_REFRESH; } @@ -375,15 +377,15 @@ vi_substitute_line(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -vi_change_to_eol(EditLine *el, int c __attribute__((__unused__))) +vi_change_to_eol(EditLine *el, Int c __attribute__((__unused__))) { cv_undo(el); cv_yank(el, el->el_line.cursor, - el->el_line.lastchar - el->el_line.cursor); + (int)(el->el_line.lastchar - el->el_line.cursor)); (void) ed_kill_line(el, 0); el->el_map.current = el->el_map.key; - return (CC_REFRESH); + return CC_REFRESH; } @@ -393,12 +395,12 @@ vi_change_to_eol(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -vi_insert(EditLine *el, int c __attribute__((__unused__))) +vi_insert(EditLine *el, Int c __attribute__((__unused__))) { el->el_map.current = el->el_map.key; cv_undo(el); - return (CC_NORM); + return CC_NORM; } @@ -408,7 +410,7 @@ vi_insert(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -vi_add(EditLine *el, int c __attribute__((__unused__))) +vi_add(EditLine *el, Int c __attribute__((__unused__))) { int ret; @@ -423,7 +425,7 @@ vi_add(EditLine *el, int c __attribute__((__unused__))) cv_undo(el); - return (ret); + return (el_action_t)ret; } @@ -433,13 +435,13 @@ vi_add(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -vi_add_at_eol(EditLine *el, int c __attribute__((__unused__))) +vi_add_at_eol(EditLine *el, Int c __attribute__((__unused__))) { el->el_map.current = el->el_map.key; el->el_line.cursor = el->el_line.lastchar; cv_undo(el); - return (CC_CURSOR); + return CC_CURSOR; } @@ -449,10 +451,10 @@ vi_add_at_eol(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -vi_delete_meta(EditLine *el, int c __attribute__((__unused__))) +vi_delete_meta(EditLine *el, Int c __attribute__((__unused__))) { - return (cv_action(el, DELETE)); + return cv_action(el, DELETE); } @@ -462,11 +464,11 @@ vi_delete_meta(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -vi_end_big_word(EditLine *el, int c __attribute__((__unused__))) +vi_end_big_word(EditLine *el, Int c __attribute__((__unused__))) { if (el->el_line.cursor == el->el_line.lastchar) - return (CC_ERROR); + return CC_ERROR; el->el_line.cursor = cv__endword(el->el_line.cursor, el->el_line.lastchar, el->el_state.argument, cv__isWord); @@ -474,9 +476,9 @@ vi_end_big_word(EditLine *el, int c __attribute__((__unused__))) if (el->el_chared.c_vcmd.action != NOP) { el->el_line.cursor++; cv_delfini(el); - return (CC_REFRESH); + return CC_REFRESH; } - return (CC_CURSOR); + return CC_CURSOR; } @@ -486,11 +488,11 @@ vi_end_big_word(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -vi_end_word(EditLine *el, int c __attribute__((__unused__))) +vi_end_word(EditLine *el, Int c __attribute__((__unused__))) { if (el->el_line.cursor == el->el_line.lastchar) - return (CC_ERROR); + return CC_ERROR; el->el_line.cursor = cv__endword(el->el_line.cursor, el->el_line.lastchar, el->el_state.argument, cv__isword); @@ -498,9 +500,9 @@ vi_end_word(EditLine *el, int c __attribute__((__unused__))) if (el->el_chared.c_vcmd.action != NOP) { el->el_line.cursor++; cv_delfini(el); - return (CC_REFRESH); + return CC_REFRESH; } - return (CC_CURSOR); + return CC_CURSOR; } @@ -510,7 +512,7 @@ vi_end_word(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -vi_undo(EditLine *el, int c __attribute__((__unused__))) +vi_undo(EditLine *el, Int c __attribute__((__unused__))) { c_undo_t un = el->el_chared.c_undo; @@ -520,13 +522,14 @@ vi_undo(EditLine *el, int c __attribute__((__unused__))) /* switch line buffer and undo buffer */ el->el_chared.c_undo.buf = el->el_line.buffer; el->el_chared.c_undo.len = el->el_line.lastchar - el->el_line.buffer; - el->el_chared.c_undo.cursor = el->el_line.cursor - el->el_line.buffer; + el->el_chared.c_undo.cursor = + (int)(el->el_line.cursor - el->el_line.buffer); el->el_line.limit = un.buf + (el->el_line.limit - el->el_line.buffer); el->el_line.buffer = un.buf; el->el_line.cursor = un.buf + un.cursor; el->el_line.lastchar = un.buf + un.len; - return (CC_REFRESH); + return CC_REFRESH; } @@ -536,7 +539,7 @@ vi_undo(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -vi_command_mode(EditLine *el, int c __attribute__((__unused__))) +vi_command_mode(EditLine *el, Int c __attribute__((__unused__))) { /* [Esc] cancels pending action */ @@ -551,7 +554,7 @@ vi_command_mode(EditLine *el, int c __attribute__((__unused__))) if (el->el_line.cursor > el->el_line.buffer) el->el_line.cursor--; #endif - return (CC_CURSOR); + return CC_CURSOR; } @@ -560,7 +563,7 @@ vi_command_mode(EditLine *el, int c __attribute__((__unused__))) * [0] */ protected el_action_t -vi_zero(EditLine *el, int c) +vi_zero(EditLine *el, Int c) { if (el->el_state.doingarg) @@ -569,9 +572,9 @@ vi_zero(EditLine *el, int c) el->el_line.cursor = el->el_line.buffer; if (el->el_chared.c_vcmd.action != NOP) { cv_delfini(el); - return (CC_REFRESH); + return CC_REFRESH; } - return (CC_CURSOR); + return CC_CURSOR; } @@ -581,15 +584,15 @@ vi_zero(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -vi_delete_prev_char(EditLine *el, int c __attribute__((__unused__))) +vi_delete_prev_char(EditLine *el, Int c __attribute__((__unused__))) { if (el->el_line.cursor <= el->el_line.buffer) - return (CC_ERROR); + return CC_ERROR; c_delbefore1(el); el->el_line.cursor--; - return (CC_REFRESH); + return CC_REFRESH; } @@ -599,32 +602,32 @@ vi_delete_prev_char(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -vi_list_or_eof(EditLine *el, int c) +vi_list_or_eof(EditLine *el, Int c) { if (el->el_line.cursor == el->el_line.lastchar) { if (el->el_line.cursor == el->el_line.buffer) { - term_writec(el, c); /* then do a EOF */ - return (CC_EOF); + terminal_writec(el, c); /* then do a EOF */ + return CC_EOF; } else { /* * Here we could list completions, but it is an * error right now */ - term_beep(el); - return (CC_ERROR); + terminal_beep(el); + return CC_ERROR; } } else { #ifdef notyet re_goto_bottom(el); *el->el_line.lastchar = '\0'; /* just in case */ - return (CC_LIST_CHOICES); + return CC_LIST_CHOICES; #else /* * Just complain for now. */ - term_beep(el); - return (CC_ERROR); + terminal_beep(el); + return CC_ERROR; #endif } } @@ -636,18 +639,18 @@ vi_list_or_eof(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -vi_kill_line_prev(EditLine *el, int c __attribute__((__unused__))) +vi_kill_line_prev(EditLine *el, Int c __attribute__((__unused__))) { - char *kp, *cp; + Char *kp, *cp; cp = el->el_line.buffer; kp = el->el_chared.c_kill.buf; while (cp < el->el_line.cursor) *kp++ = *cp++; /* copy it */ el->el_chared.c_kill.last = kp; - c_delbefore(el, el->el_line.cursor - el->el_line.buffer); + c_delbefore(el, (int)(el->el_line.cursor - el->el_line.buffer)); el->el_line.cursor = el->el_line.buffer; /* zap! */ - return (CC_REFRESH); + return CC_REFRESH; } @@ -657,10 +660,10 @@ vi_kill_line_prev(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -vi_search_prev(EditLine *el, int c __attribute__((__unused__))) +vi_search_prev(EditLine *el, Int c __attribute__((__unused__))) { - return (cv_search(el, ED_SEARCH_PREV_HISTORY)); + return cv_search(el, ED_SEARCH_PREV_HISTORY); } @@ -670,10 +673,10 @@ vi_search_prev(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -vi_search_next(EditLine *el, int c __attribute__((__unused__))) +vi_search_next(EditLine *el, Int c __attribute__((__unused__))) { - return (cv_search(el, ED_SEARCH_NEXT_HISTORY)); + return cv_search(el, ED_SEARCH_NEXT_HISTORY); } @@ -683,13 +686,13 @@ vi_search_next(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -vi_repeat_search_next(EditLine *el, int c __attribute__((__unused__))) +vi_repeat_search_next(EditLine *el, Int c __attribute__((__unused__))) { if (el->el_search.patlen == 0) - return (CC_ERROR); + return CC_ERROR; else - return (cv_repeat_srch(el, el->el_search.patdir)); + return cv_repeat_srch(el, el->el_search.patdir); } @@ -699,11 +702,11 @@ vi_repeat_search_next(EditLine *el, int c __attribute__((__unused__))) */ /*ARGSUSED*/ protected el_action_t -vi_repeat_search_prev(EditLine *el, int c __attribute__((__unused__))) +vi_repeat_search_prev(EditLine *el, Int c __attribute__((__unused__))) { if (el->el_search.patlen == 0) - return (CC_ERROR); + return CC_ERROR; else return (cv_repeat_srch(el, el->el_search.patdir == ED_SEARCH_PREV_HISTORY ? @@ -717,7 +720,7 @@ vi_repeat_search_prev(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -vi_next_char(EditLine *el, int c __attribute__((__unused__))) +vi_next_char(EditLine *el, Int c __attribute__((__unused__))) { return cv_csearch(el, CHAR_FWD, -1, el->el_state.argument, 0); } @@ -729,7 +732,7 @@ vi_next_char(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -vi_prev_char(EditLine *el, int c __attribute__((__unused__))) +vi_prev_char(EditLine *el, Int c __attribute__((__unused__))) { return cv_csearch(el, CHAR_BACK, -1, el->el_state.argument, 0); } @@ -741,7 +744,7 @@ vi_prev_char(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -vi_to_next_char(EditLine *el, int c __attribute__((__unused__))) +vi_to_next_char(EditLine *el, Int c __attribute__((__unused__))) { return cv_csearch(el, CHAR_FWD, -1, el->el_state.argument, 1); } @@ -753,7 +756,7 @@ vi_to_next_char(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -vi_to_prev_char(EditLine *el, int c __attribute__((__unused__))) +vi_to_prev_char(EditLine *el, Int c __attribute__((__unused__))) { return cv_csearch(el, CHAR_BACK, -1, el->el_state.argument, 1); } @@ -765,7 +768,7 @@ vi_to_prev_char(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -vi_repeat_next_char(EditLine *el, int c __attribute__((__unused__))) +vi_repeat_next_char(EditLine *el, Int c __attribute__((__unused__))) { return cv_csearch(el, el->el_search.chadir, el->el_search.chacha, @@ -779,7 +782,7 @@ vi_repeat_next_char(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -vi_repeat_prev_char(EditLine *el, int c __attribute__((__unused__))) +vi_repeat_prev_char(EditLine *el, Int c __attribute__((__unused__))) { el_action_t r; int dir = el->el_search.chadir; @@ -797,20 +800,20 @@ vi_repeat_prev_char(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -vi_match(EditLine *el, int c __attribute__((__unused__))) +vi_match(EditLine *el, Int c __attribute__((__unused__))) { - const char match_chars[] = "()[]{}"; - char *cp; - int delta, i, count; - char o_ch, c_ch; + const Char match_chars[] = STR("()[]{}"); + Char *cp; + size_t delta, i, count; + Char o_ch, c_ch; *el->el_line.lastchar = '\0'; /* just in case */ - i = strcspn(el->el_line.cursor, match_chars); + i = Strcspn(el->el_line.cursor, match_chars); o_ch = el->el_line.cursor[i]; if (o_ch == 0) return CC_ERROR; - delta = strchr(match_chars, o_ch) - match_chars; + delta = (size_t)(Strchr(match_chars, o_ch) - match_chars); c_ch = match_chars[delta ^ 1]; count = 1; delta = 1 - (delta & 1) * 2; @@ -833,9 +836,9 @@ vi_match(EditLine *el, int c __attribute__((__unused__))) if (delta > 0) el->el_line.cursor++; cv_delfini(el); - return (CC_REFRESH); + return CC_REFRESH; } - return (CC_CURSOR); + return CC_CURSOR; } /* vi_undo_line(): @@ -844,7 +847,7 @@ vi_match(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -vi_undo_line(EditLine *el, int c __attribute__((__unused__))) +vi_undo_line(EditLine *el, Int c __attribute__((__unused__))) { cv_undo(el); @@ -858,7 +861,7 @@ vi_undo_line(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -vi_to_column(EditLine *el, int c __attribute__((__unused__))) +vi_to_column(EditLine *el, Int c __attribute__((__unused__))) { el->el_line.cursor = el->el_line.buffer; @@ -872,11 +875,11 @@ vi_to_column(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -vi_yank_end(EditLine *el, int c __attribute__((__unused__))) +vi_yank_end(EditLine *el, Int c __attribute__((__unused__))) { cv_yank(el, el->el_line.cursor, - el->el_line.lastchar - el->el_line.cursor); + (int)(el->el_line.lastchar - el->el_line.cursor)); return CC_REFRESH; } @@ -886,7 +889,7 @@ vi_yank_end(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -vi_yank(EditLine *el, int c __attribute__((__unused__))) +vi_yank(EditLine *el, Int c __attribute__((__unused__))) { return cv_action(el, YANK); @@ -898,7 +901,7 @@ vi_yank(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -vi_comment_out(EditLine *el, int c __attribute__((__unused__))) +vi_comment_out(EditLine *el, Int c __attribute__((__unused__))) { el->el_line.cursor = el->el_line.buffer; @@ -915,18 +918,19 @@ vi_comment_out(EditLine *el, int c __attribute__((__unused__))) * this is against historical precedent... */ #if defined(__weak_reference) && !defined(__FreeBSD__) -extern char *get_alias_text(const char *) __weak_reference(get_alias_text); +__weakref_visible char *my_get_alias_text(const char *) + __weak_reference(get_alias_text); #endif protected el_action_t /*ARGSUSED*/ vi_alias(EditLine *el __attribute__((__unused__)), - int c __attribute__((__unused__))) + Int c __attribute__((__unused__))) { #if defined(__weak_reference) && !defined(__FreeBSD__) char alias_name[3]; char *alias_text; - if (get_alias_text == 0) { + if (my_get_alias_text == 0) { return CC_ERROR; } @@ -935,9 +939,9 @@ vi_alias(EditLine *el __attribute__((__unused__)), if (el_getc(el, &alias_name[1]) != 1) return CC_ERROR; - alias_text = get_alias_text(alias_name); + alias_text = my_get_alias_text(alias_name); if (alias_text != NULL) - el_push(el, alias_text); + FUN(el,push)(el, ct_decode_string(alias_text, &el->el_scratch)); return CC_NORM; #else return CC_ERROR; @@ -950,14 +954,14 @@ vi_alias(EditLine *el __attribute__((__unused__)), */ protected el_action_t /*ARGSUSED*/ -vi_to_history_line(EditLine *el, int c __attribute__((__unused__))) +vi_to_history_line(EditLine *el, Int c __attribute__((__unused__))) { int sv_event_no = el->el_history.eventno; el_action_t rval; if (el->el_history.eventno == 0) { - (void) strncpy(el->el_history.buf, el->el_line.buffer, + (void) Strncpy(el->el_history.buf, el->el_line.buffer, EL_BUFSIZ); el->el_history.last = el->el_history.buf + (el->el_line.lastchar - el->el_line.buffer); @@ -995,14 +999,19 @@ vi_to_history_line(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -vi_histedit(EditLine *el, int c __attribute__((__unused__))) +vi_histedit(EditLine *el, Int c __attribute__((__unused__))) { int fd; pid_t pid; - int st; + ssize_t st; + int status; char tempfile[] = "/tmp/histedit.XXXXXXXXXX"; char *cp; + size_t len; + Char *line; + mbstate_t state; + memset(&state, 0, sizeof(mbstate_t)); if (el->el_state.doingarg) { if (vi_to_history_line(el, 0) == CC_ERROR) return CC_ERROR; @@ -1011,16 +1020,35 @@ vi_histedit(EditLine *el, int c __attribute__((__unused__))) fd = mkstemp(tempfile); if (fd < 0) return CC_ERROR; - cp = el->el_line.buffer; - if (write(fd, cp, el->el_line.lastchar - cp +0u) == -1) + len = (size_t)(el->el_line.lastchar - el->el_line.buffer); +#define TMP_BUFSIZ (EL_BUFSIZ * MB_LEN_MAX) + cp = el_malloc(TMP_BUFSIZ * sizeof(*cp)); + if (cp == NULL) { + unlink(tempfile); + close(fd); + return CC_ERROR; + } + line = el_malloc(len * sizeof(*line)); + if (line == NULL) { + el_free(cp); + return CC_ERROR; + } + Strncpy(line, el->el_line.buffer, len); + line[len] = '\0'; + wcsrtombs(cp, (const wchar_t **) &line, TMP_BUFSIZ - 1, &state); + cp[TMP_BUFSIZ - 1] = '\0'; + len = strlen(cp); + if (write(fd, cp, len) == -1) goto error; - if (write(fd, "\n", 1) == -1) + if (write(fd, "\n", (size_t)1) == -1) goto error; pid = fork(); switch (pid) { case -1: close(fd); unlink(tempfile); + el_free(cp); + el_free(line); return CC_ERROR; case 0: close(fd); @@ -1028,14 +1056,25 @@ vi_histedit(EditLine *el, int c __attribute__((__unused__))) exit(0); /*NOTREACHED*/ default: - while (waitpid(pid, &st, 0) != pid) + while (waitpid(pid, &status, 0) != pid) continue; - lseek(fd, 0ll, SEEK_SET); - st = read(fd, cp, el->el_line.limit - cp +0u); - if (st > 0 && cp[st - 1] == '\n') - st--; - el->el_line.cursor = cp; - el->el_line.lastchar = cp + st; + lseek(fd, (off_t)0, SEEK_SET); + st = read(fd, cp, TMP_BUFSIZ); + if (st > 0) { + len = (size_t)(el->el_line.lastchar - + el->el_line.buffer); + memset(&state, 0, sizeof(mbstate_t)); + len = mbsrtowcs(el->el_line.buffer, + (const char**) &cp, len, &state); + if (len > 0 && el->el_line.buffer[len -1] == '\n') + --len; + } + else + len = 0; + el->el_line.cursor = el->el_line.buffer; + el->el_line.lastchar = el->el_line.buffer + len; + el_free(cp); + el_free(line); break; } @@ -1059,34 +1098,35 @@ error: */ protected el_action_t /*ARGSUSED*/ -vi_history_word(EditLine *el, int c __attribute__((__unused__))) +vi_history_word(EditLine *el, Int c __attribute__((__unused__))) { - const char *wp = HIST_FIRST(el); - const char *wep, *wsp; + const Char *wp = HIST_FIRST(el); + const Char *wep, *wsp; int len; - char *cp; - const char *lim; + Char *cp; + const Char *lim; if (wp == NULL) return CC_ERROR; wep = wsp = 0; do { - while (isspace((unsigned char)*wp)) + while (Isspace(*wp)) wp++; if (*wp == 0) break; wsp = wp; - while (*wp && !isspace((unsigned char)*wp)) + while (*wp && !Isspace(*wp)) wp++; wep = wp; - } while ((!el->el_state.doingarg || --el->el_state.argument > 0) && *wp != 0); + } while ((!el->el_state.doingarg || --el->el_state.argument > 0) + && *wp != 0); if (wsp == 0 || (el->el_state.doingarg && el->el_state.argument != 0)) return CC_ERROR; cv_undo(el); - len = wep - wsp; + len = (int)(wep - wsp); if (el->el_line.cursor < el->el_line.lastchar) el->el_line.cursor++; c_insert(el, len + 1); @@ -1108,7 +1148,7 @@ vi_history_word(EditLine *el, int c __attribute__((__unused__))) */ protected el_action_t /*ARGSUSED*/ -vi_redo(EditLine *el, int c __attribute__((__unused__))) +vi_redo(EditLine *el, Int c __attribute__((__unused__))) { c_redo_t *r = &el->el_chared.c_redo; @@ -1124,10 +1164,10 @@ vi_redo(EditLine *el, int c __attribute__((__unused__))) /* sanity */ r->pos = r->lim - 1; r->pos[0] = 0; - el_push(el, r->buf); + FUN(el,push)(el, r->buf); } el->el_state.thiscmd = r->cmd; el->el_state.thisch = r->ch; - return (*el->el_map.func[r->cmd])(el, r->ch); + return (*el->el_map.func[r->cmd])(el, r->ch); } From a6145f4b62bd264ad32d2dade98eda0cc6de0dba Mon Sep 17 00:00:00 2001 From: Tor Didriksen Date: Fri, 14 Oct 2011 10:09:53 +0200 Subject: [PATCH 028/288] Bug#12563865 ROUNDED,TMP_BUF,DECIMAL_VALUE STACK CORRUPTION IN ALL VERSIONS >=5.0 Buffer over-run on all platforms, crash on windows, wrong result on other platforms, when rounding numbers which start with 999999999 and have precision = 9 or 18 or 27 or 36 ... mysql-test/r/type_newdecimal.result: New test cases. mysql-test/t/type_newdecimal.test: New test cases. sql/my_decimal.h: Add sanity checking code, to catch buffer over/under-run. strings/decimal.c: The original initialization of intg1 (add 1 if buf[0] == DIG_MAX) will set p1 to point outside the buffer, and the loop to copy the original value while (buf0 < p0) *(--p1) = *(--p0); will overwrite memory outside the my_decimal object. --- mysql-test/r/type_newdecimal.result | 44 +++++++++++++++++++++++++++++ mysql-test/t/type_newdecimal.test | 21 ++++++++++++++ sql/my_decimal.h | 30 ++++++++++++++++++++ strings/decimal.c | 21 ++++++++------ 4 files changed, 108 insertions(+), 8 deletions(-) diff --git a/mysql-test/r/type_newdecimal.result b/mysql-test/r/type_newdecimal.result index 90b6f524692..43caaa2239b 100644 --- a/mysql-test/r/type_newdecimal.result +++ b/mysql-test/r/type_newdecimal.result @@ -1539,4 +1539,48 @@ select * from t1; 5.05 / 0.014 360.714286 DROP TABLE t1; +# +# Bug#12563865 +# ROUNDED,TMP_BUF,DECIMAL_VALUE STACK CORRUPTION IN ALL VERSIONS >=5.0 +# +SELECT substring(('M') FROM (999999999999999999999999999999999999999999999999999999999999999999999999999999999)) AS foo; +foo + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +SELECT min(999999999999999999999999999999999999999999999999999999999999999999999999999999999) AS foo; +foo +999999999999999999999999999999999999999999999999999999999999999999999999999999999 +SELECT multipolygonfromtext(('4294967294.1'),(999999999999999999999999999999999999999999999999999999999999999999999999999999999)) AS foo; +foo +NULL +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +SELECT convert((999999999999999999999999999999999999999999999999999999999999999999999999999999999), decimal(30,30)) AS foo; +foo +0.999999999999999999999999999999 +Warnings: +Error 1264 Out of range value adjusted for column 'foo' at row 1 +SELECT bit_xor(999999999999999999999999999999999999999999999999999999999999999999999999999999999) AS foo; +foo +9223372036854775807 +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +SELECT -(999999999999999999999999999999999999999999999999999999999999999999999999999999999) AS foo; +foo +-999999999999999999999999999999999999999999999999999999999999999999999999999999999 +SELECT date_sub((999999999999999999999999999999999999999999999999999999999999999999999999999999999), +interval ((SELECT date_add((0x77500000), +interval ('Oml') second))) +day_minute) +AS foo; +foo +NULL +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect datetime value: '9223372036854775807' +SELECT truncate(999999999999999999999999999999999999999999999999999999999999999999999999999999999, 28) AS foo; +foo +999999999999999999999999999999999999999999999999999999999999999999999999999999999 End of 5.0 tests diff --git a/mysql-test/t/type_newdecimal.test b/mysql-test/t/type_newdecimal.test index a5331582df6..a55951caf63 100644 --- a/mysql-test/t/type_newdecimal.test +++ b/mysql-test/t/type_newdecimal.test @@ -1235,4 +1235,25 @@ show create table t1; select * from t1; DROP TABLE t1; +--echo # +--echo # Bug#12563865 +--echo # ROUNDED,TMP_BUF,DECIMAL_VALUE STACK CORRUPTION IN ALL VERSIONS >=5.0 +--echo # + +let $nine_81= +999999999999999999999999999999999999999999999999999999999999999999999999999999999; + +eval SELECT substring(('M') FROM ($nine_81)) AS foo; +eval SELECT min($nine_81) AS foo; +eval SELECT multipolygonfromtext(('4294967294.1'),($nine_81)) AS foo; +eval SELECT convert(($nine_81), decimal(30,30)) AS foo; +eval SELECT bit_xor($nine_81) AS foo; +eval SELECT -($nine_81) AS foo; +eval SELECT date_sub(($nine_81), + interval ((SELECT date_add((0x77500000), + interval ('Oml') second))) + day_minute) +AS foo; +eval SELECT truncate($nine_81, 28) AS foo; + --echo End of 5.0 tests diff --git a/sql/my_decimal.h b/sql/my_decimal.h index 6a0d05921ec..ee023438f20 100644 --- a/sql/my_decimal.h +++ b/sql/my_decimal.h @@ -86,12 +86,31 @@ inline int my_decimal_int_part(uint precision, uint decimals) class my_decimal :public decimal_t { + /* + Several of the routines in strings/decimal.c have had buffer + overrun/underrun problems. These are *not* caught by valgrind. + To catch them, we allocate dummy fields around the buffer, + and test that their values do not change. + */ +#if !defined(DBUG_OFF) + int foo1; +#endif + decimal_digit_t buffer[DECIMAL_BUFF_LENGTH]; +#if !defined(DBUG_OFF) + int foo2; + static const int test_value= 123; +#endif + public: void init() { +#if !defined(DBUG_OFF) + foo1= test_value; + foo2= test_value; +#endif len= DECIMAL_BUFF_LENGTH; buf= buffer; #if !defined (HAVE_purify) && !defined(DBUG_OFF) @@ -104,6 +123,17 @@ public: { init(); } + ~my_decimal() + { + sanity_check(); + } + + void sanity_check() + { + DBUG_ASSERT(foo1 == test_value); + DBUG_ASSERT(foo2 == test_value); + } + void fix_buffer_pointer() { buf= buffer; } bool sign() const { return decimal_t::sign; } diff --git a/strings/decimal.c b/strings/decimal.c index 1498aec15a1..87faff9b4cd 100644 --- a/strings/decimal.c +++ b/strings/decimal.c @@ -1480,9 +1480,8 @@ decimal_round(decimal_t *from, decimal_t *to, int scale, { int frac0=scale>0 ? ROUND_UP(scale) : scale/DIG_PER_DEC1, frac1=ROUND_UP(from->frac), UNINIT_VAR(round_digit), - intg0=ROUND_UP(from->intg), error=E_DEC_OK, len=to->len, - intg1=ROUND_UP(from->intg + - (((intg0 + frac0)>0) && (from->buf[0] == DIG_MAX))); + intg0=ROUND_UP(from->intg), error=E_DEC_OK, len=to->len; + dec1 *buf0=from->buf, *buf1=to->buf, x, y, carry=0; int first_dig; @@ -1497,6 +1496,12 @@ decimal_round(decimal_t *from, decimal_t *to, int scale, default: DBUG_ASSERT(0); } + /* + For my_decimal we always use len == DECIMAL_BUFF_LENGTH == 9 + For internal testing here (ifdef MAIN) we always use len == 100/4 + */ + DBUG_ASSERT(from->len == to->len); + if (unlikely(frac0+intg0 > len)) { frac0=len-intg0; @@ -1510,17 +1515,17 @@ decimal_round(decimal_t *from, decimal_t *to, int scale, return E_DEC_OK; } - if (to != from || intg1>intg0) + if (to != from) { dec1 *p0= buf0+intg0+max(frac1, frac0); - dec1 *p1= buf1+intg1+max(frac1, frac0); + dec1 *p1= buf1+intg0+max(frac1, frac0); + + DBUG_ASSERT(p0 - buf0 <= len); + DBUG_ASSERT(p1 - buf1 <= len); while (buf0 < p0) *(--p1) = *(--p0); - if (unlikely(intg1 > intg0)) - to->buf[0]= 0; - intg0= intg1; buf0=to->buf; buf1=to->buf; to->sign=from->sign; From 7b4ebc16c391c5933072cd45e3d5ee4553c915d8 Mon Sep 17 00:00:00 2001 From: Alfranio Correia Date: Fri, 14 Oct 2011 14:24:15 +0100 Subject: [PATCH 029/288] Introduced this code to make the gcc 4.6.1 compiler happy. When warnings are converted to errors, the compiler complains about the fact that binlog_can_be_corrupted is defined but never used. We need to check if this is a dead code or if someone removed any code by mistake. --- sql/sql_repl.cc | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index a37e8700e4f..80fef42434c 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -720,6 +720,19 @@ impossible position"; else if (event_type == STOP_EVENT) binlog_can_be_corrupted= FALSE; + /* + Introduced this code to make the gcc 4.6.1 compiler happy. When + warnings are converted to errors, the compiler complains about + the fact that binlog_can_be_corrupted is defined but never used. + + We need to check if this is a dead code or if someone removed any + code by mistake. + + /Alfranio + */ + if (binlog_can_be_corrupted) + sql_print_information("The binlog may be corrupted."); + pos = my_b_tell(&log); if (RUN_HOOK(binlog_transmit, before_send_event, (thd, flags, packet, log_file_name, pos))) From d1846e3b95c0bf75e0648e44136933e07f85f9fa Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 17 Oct 2011 15:30:28 -0400 Subject: [PATCH 030/288] BUG#12968815: mysql_plugin : disable requires plugin name but doesn't use it This patch corrects a defect in the building of the DELETE commands for disabling a plugin whereby only the original plugin data was deleted. If there were other plugins, the delete did not remove the rows. The code has been changed to remove all rows from the mysql.plugin table that were inserted when the plugin was loaded. The test has also been changed to correctly identify if all rows have been deleted. --- client/mysql_plugin.c | 2 +- mysql-test/r/mysql_plugin.result | 16 +++++++++++++--- mysql-test/t/mysql_plugin.test | 14 +++++++++++--- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/client/mysql_plugin.c b/client/mysql_plugin.c index 825c962c486..dd5c02931c9 100644 --- a/client/mysql_plugin.c +++ b/client/mysql_plugin.c @@ -1081,7 +1081,7 @@ static int build_bootstrap_file(char *operation, char *bootstrap) else { fprintf(file, - "DELETE FROM mysql.plugin WHERE name = '%s';", plugin_data.name); + "DELETE FROM mysql.plugin WHERE dl = '%s';", plugin_data.so_name); if (opt_verbose) { printf("# Disabling %s...\n", plugin_data.name); diff --git a/mysql-test/r/mysql_plugin.result b/mysql-test/r/mysql_plugin.result index 949f3748236..93567e28c3d 100644 --- a/mysql-test/r/mysql_plugin.result +++ b/mysql-test/r/mysql_plugin.result @@ -1,24 +1,34 @@ # # Ensure the plugin isn't loaded. # -SELECT * FROM mysql.plugin WHERE name = 'daemon_example' ORDER BY name; +SELECT * FROM mysql.plugin WHERE dl like 'libdaemon%' ORDER BY name; name dl # # Enable the plugin... # # +# Simulate loading a plugin libary with multiple entry points. +# This will test the DISABLE to ensure all rows are removed. +# +INSERT INTO mysql.plugin VALUES ('wicky', 'libdaemon_example.so'); +INSERT INTO mysql.plugin VALUES ('wacky', 'libdaemon_example.so'); +INSERT INTO mysql.plugin VALUES ('wonky', 'libdaemon_example.so'); +# # Ensure the plugin is now loaded. # -SELECT * FROM mysql.plugin WHERE name = 'daemon_example' ORDER BY name; +SELECT * FROM mysql.plugin WHERE dl like 'libdaemon%' ORDER BY name; name dl daemon_example libdaemon_example.so +wacky libdaemon_example.so +wicky libdaemon_example.so +wonky libdaemon_example.so # # Disable the plugin... # # # Ensure the plugin isn't loaded. # -SELECT * FROM mysql.plugin WHERE name = 'daemon_example' ORDER BY name; +SELECT * FROM mysql.plugin WHERE dl like 'libdaemon%' ORDER BY name; name dl # # Attempt to load non-existant plugin diff --git a/mysql-test/t/mysql_plugin.test b/mysql-test/t/mysql_plugin.test index b7fbe377e31..897e22ddd62 100644 --- a/mysql-test/t/mysql_plugin.test +++ b/mysql-test/t/mysql_plugin.test @@ -105,7 +105,7 @@ let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN --datadir=$MYSQLD_DATADIR --basedir=$MYSQLD --echo # --echo # Ensure the plugin isn't loaded. --echo # -SELECT * FROM mysql.plugin WHERE name = 'daemon_example' ORDER BY name; +SELECT * FROM mysql.plugin WHERE dl like 'libdaemon%' ORDER BY name; --echo # --echo # Enable the plugin... @@ -138,11 +138,19 @@ EOF --enable_reconnect --source include/wait_until_connected_again.inc +--echo # +--echo # Simulate loading a plugin libary with multiple entry points. +--echo # This will test the DISABLE to ensure all rows are removed. +--echo # +eval INSERT INTO mysql.plugin VALUES ('wicky', '$DAEMONEXAMPLE'); +eval INSERT INTO mysql.plugin VALUES ('wacky', '$DAEMONEXAMPLE'); +eval INSERT INTO mysql.plugin VALUES ('wonky', '$DAEMONEXAMPLE'); + --echo # --echo # Ensure the plugin is now loaded. --echo # --replace_regex /\.dll/.so/ -SELECT * FROM mysql.plugin WHERE name = 'daemon_example' ORDER BY name; +SELECT * FROM mysql.plugin WHERE dl like 'libdaemon%' ORDER BY name; --echo # --echo # Disable the plugin... @@ -173,7 +181,7 @@ EOF --echo # --echo # Ensure the plugin isn't loaded. --echo # -SELECT * FROM mysql.plugin WHERE name = 'daemon_example' ORDER BY name; +SELECT * FROM mysql.plugin WHERE dl like 'libdaemon%' ORDER BY name; # # Stop the server for error conditions From 3c869a521ae17900fd60d67e5804f4a51cdec7cc Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 17 Oct 2011 15:33:54 -0400 Subject: [PATCH 031/288] BUG#12968567: mysql_plugin : incorrect return from bootstrap failure This patch corrects a defect whereby the bootstrap_server() method was returning 0 instead of the error code generated. The code has been changed to return the correct value returned from the bootstrap command. --- client/mysql_plugin.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/client/mysql_plugin.c b/client/mysql_plugin.c index dd5c02931c9..55f5ea0827e 100644 --- a/client/mysql_plugin.c +++ b/client/mysql_plugin.c @@ -1160,7 +1160,6 @@ static int bootstrap_server(char *server_path, char *bootstrap_file) { char bootstrap_cmd[FN_REFLEN]; int error= 0; - int ret= 0; #ifdef __WIN__ char *format_str= 0; @@ -1196,7 +1195,7 @@ static int bootstrap_server(char *server_path, char *bootstrap_file) if (error) fprintf(stderr, "ERROR: Unexpected result from bootstrap. Error code: %d.\n", - ret); + error); return error; } From fd955448c86018539e1e46a7390273dff11f0291 Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Tue, 18 Oct 2011 22:47:32 +0530 Subject: [PATCH 032/288] Bug#13102538 : COMPILE ERROR ON SOLARIS WHEN COMPILING WITH LIBEDIT Libedit won't build on platforms that do not provide "sys/cdefs.h". Removed the inclusion of cdefs.h from all files other that sys.h, which includes this file only when the header is found while configuring. --- cmd-line-utils/libedit/np/strlcat.c | 1 - cmd-line-utils/libedit/np/strlcpy.c | 1 - cmd-line-utils/libedit/np/unvis.c | 1 - cmd-line-utils/libedit/np/vis.c | 1 - cmd-line-utils/libedit/np/vis.h | 1 - 5 files changed, 5 deletions(-) diff --git a/cmd-line-utils/libedit/np/strlcat.c b/cmd-line-utils/libedit/np/strlcat.c index c2ecc3d9b4f..4e2897d8f35 100644 --- a/cmd-line-utils/libedit/np/strlcat.c +++ b/cmd-line-utils/libedit/np/strlcat.c @@ -24,7 +24,6 @@ #include "config.h" #endif -#include #if defined(LIBC_SCCS) && !defined(lint) #endif /* LIBC_SCCS and not lint */ diff --git a/cmd-line-utils/libedit/np/strlcpy.c b/cmd-line-utils/libedit/np/strlcpy.c index 533dbee70d4..ccbe6812dfc 100644 --- a/cmd-line-utils/libedit/np/strlcpy.c +++ b/cmd-line-utils/libedit/np/strlcpy.c @@ -24,7 +24,6 @@ #include "config.h" #endif -#include #if defined(LIBC_SCCS) && !defined(lint) #endif /* LIBC_SCCS and not lint */ diff --git a/cmd-line-utils/libedit/np/unvis.c b/cmd-line-utils/libedit/np/unvis.c index 3fc9fe1c9ed..4c523608c27 100644 --- a/cmd-line-utils/libedit/np/unvis.c +++ b/cmd-line-utils/libedit/np/unvis.c @@ -31,7 +31,6 @@ #include "config.h" -#include #if defined(LIBC_SCCS) && !defined(lint) #if 0 static char sccsid[] = "@(#)unvis.c 8.1 (Berkeley) 6/4/93"; diff --git a/cmd-line-utils/libedit/np/vis.c b/cmd-line-utils/libedit/np/vis.c index d18eb38e287..6c75438c352 100644 --- a/cmd-line-utils/libedit/np/vis.c +++ b/cmd-line-utils/libedit/np/vis.c @@ -57,7 +57,6 @@ #include "config.h" -#include #if defined(LIBC_SCCS) && !defined(lint) #endif /* LIBC_SCCS and not lint */ diff --git a/cmd-line-utils/libedit/np/vis.h b/cmd-line-utils/libedit/np/vis.h index 324e961cd4c..54a76e9108f 100644 --- a/cmd-line-utils/libedit/np/vis.h +++ b/cmd-line-utils/libedit/np/vis.h @@ -76,7 +76,6 @@ * unvis flags */ #define UNVIS_END _VIS_END /* no more characters */ -#include /* XXXMYSQL */ #ifndef __RENAME #define __RENAME(x) From 8444b6a1149aad457f8d584e0d410c3be9cd4336 Mon Sep 17 00:00:00 2001 From: Tatjana Azundris Nuernberg Date: Wed, 19 Oct 2011 03:21:31 +0100 Subject: [PATCH 033/288] Bug12589870 post-merge fixes for Sparc64 and friends sql/sp_head.cc: alignment-safe copy sql/sql_cache.cc: alignment-safe copy sql/sql_parse.cc: alignment-safe copy --- sql/sp_head.cc | 2 +- sql/sql_cache.cc | 5 +++-- sql/sql_parse.cc | 6 ++++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 70ffb0a36ab..8bea0be0f56 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1044,7 +1044,7 @@ subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str) { memcpy(pbuf, qbuf.ptr(), qbuf.length()); pbuf[qbuf.length()]= 0; - *(size_t *)(pbuf+qbuf.length()+1)= thd->db_length; + memcpy(pbuf+qbuf.length()+1, (char *) &thd->db_length, sizeof(size_t)); } else DBUG_RETURN(TRUE); diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 4800fdedbe5..8a6d4bf9802 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -1471,8 +1471,9 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) sure the new current database has a name with the same length as the previous one. */ - size_t *db_len= (size_t *) (sql + query_length + 1); - if (thd->db_length != *db_len) + size_t db_len; + memcpy((char *) &db_len, (sql + query_length + 1), sizeof(size_t)); + if (thd->db_length != db_len) { /* We should probably reallocate the buffer in this case, diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index a88cc2fa8e5..989c3e0f42f 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -492,6 +492,8 @@ static void handle_bootstrap_impl(THD *thd) query= (char *) thd->memdup_w_gap(buff, length + 1, thd->db_length + 1 + QUERY_CACHE_FLAGS_SIZE); + size_t db_len= 0; + memcpy(query + length + 1, (char *) &db_len, sizeof(size_t)); thd->set_query(query, length); DBUG_PRINT("query",("%-.4096s", thd->query())); #if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) @@ -1933,8 +1935,8 @@ bool alloc_query(THD *thd, const char *packet, uint packet_length) also store this length, in case current database is changed during execution. We might need to reallocate the 'query' buffer */ - size_t *len = (size_t *) (query + packet_length + 1); - *len= thd->db_length; + char *len_pos = (query + packet_length + 1); + memcpy(len_pos, (char *) &thd->db_length, sizeof(size_t)); thd->set_query(query, packet_length); From 434dd8635e3517869be37ee61bcaae1f1694aba1 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 19 Oct 2011 12:53:52 +0530 Subject: [PATCH 034/288] Bug #11754855 46528: NEED A WAY TO PASS A VARIABLE TO MTR COMMANDS modified function do_get_error in mysqltest.cc to handle multiple variable passed added test case to mysqltest.test to verify handling to multiple errors passed --- client/mysqltest.cc | 14 +++++++++++++- mysql-test/r/mysqltest.result | 11 +++++++++++ mysql-test/t/mysqltest.test | 25 +++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/client/mysqltest.cc b/client/mysqltest.cc index 915c6e4d495..f0184e5297b 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -4839,6 +4839,7 @@ void do_get_errcodes(struct st_command *command) struct st_match_err *to= saved_expected_errors.err; char *p= command->first_argument; uint count= 0; + char *next; DBUG_ENTER("do_get_errcodes"); @@ -4858,6 +4859,17 @@ void do_get_errcodes(struct st_command *command) while (*end && *end != ',' && *end != ' ') end++; + next=end; + + /* code to handle variables passed to mysqltest */ + if( *p == '$') + { + const char* fin; + VAR *var = var_get(p,&fin,0,0); + p=var->str_val; + end=p+var->str_val_len; + } + if (*p == 'S') { char *to_ptr= to->code.sqlstate; @@ -4932,7 +4944,7 @@ void do_get_errcodes(struct st_command *command) die("Too many errorcodes specified"); /* Set pointer to the end of the last error code */ - p= end; + p= next; /* Find next ',' */ while (*p && *p != ',') diff --git a/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result index 003388be2cf..a0456c65f53 100644 --- a/mysql-test/r/mysqltest.result +++ b/mysql-test/r/mysqltest.result @@ -662,6 +662,17 @@ a D 1 1 1 4 drop table t1; +create table t2 ( a char(10)); +garbage; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'garbage' at line 1 +garbage; +Got one of the listed errors +garbage; +Got one of the listed errors +insert into t1 values ("Abcd"); +Got one of the listed errors +garbage; +drop table t2; create table t1 ( f1 char(10)); insert into t1 values ("Abcd"); select * from t1; diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test index a363038dee3..11ab79458d7 100644 --- a/mysql-test/t/mysqltest.test +++ b/mysql-test/t/mysqltest.test @@ -2065,6 +2065,31 @@ insert into t1 values (2,4); select * from t1; drop table t1; +#------------------------------------------------------------------------- +# BUG #11754855 : Passing variable to --error +#------------------------------------------------------------------------- +create table t2 ( a char(10)); +let $errno1=0; +let $errno2=ER_PARSE_ERROR; +let $errno3=ER_NO_SUCH_TABLE; +--error $errno2 +garbage; + +--error $errno2,$errno3 +garbage; + +--error $errno2,ER_NO_SUCH_TABLE +garbage; + +--error ER_NO_SUCH_TABLE,$errno2 +insert into t1 values ("Abcd"); + +--error $errno1,ER_PARSE_ERROR +garbage; + +drop table t2; + + # ---------------------------------------------------------------------------- # Tests of send # ---------------------------------------------------------------------------- From 14dff92d58569657c126bc8cc8755d0341581ea4 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Wed, 19 Oct 2011 13:36:57 +0200 Subject: [PATCH 035/288] Remove copyright header from parser_stack.test --- mysql-test/t/parser_stack.test | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/mysql-test/t/parser_stack.test b/mysql-test/t/parser_stack.test index e58459044f0..f8291ce8766 100644 --- a/mysql-test/t/parser_stack.test +++ b/mysql-test/t/parser_stack.test @@ -1,18 +1,3 @@ -# Copyright (c) 2008 MySQL AB -# -# 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 Foundation; version 2 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - # # These tests are designed to cause an internal parser stack overflow, # and trigger my_yyoverflow(). From a405d30e93096175618f28ada9e0e8cb5f94b914 Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Wed, 19 Oct 2011 16:07:14 +0400 Subject: [PATCH 036/288] Bug#12540545 61101: ASSERTION FAILURE IN THREAD 1256741184 IN FILE /BUILDDIR/BUILD/BUILD/MYSQ The assertion in innodb is triggered in this way: 1. mysql server does lookup on the primary key with full key, innodb decides to not store cursor position because "any index_next/prev call will return EOF anyway" 2. server asks innodb to return any next record in the index and the assertion is triggered because no cursor position is stored. It happens when a unique search (match_mode=ROW_SEL_EXACT) in the clustered index is performed. InnoDB has never stored the cursor position after a unique key lookup in the clustered index because storing the position is an expensive operation. The bug was introduced by WL3220 'Loose index scan for aggregate functions'. The fix is to disallow loose index scan optimization for AGG_FUNC(DISTINCT ...) if GROUP_MIN_MAX quick select uses clustered key. mysql-test/r/group_min_max_innodb.result: test case mysql-test/t/group_min_max_innodb.test: test case sql/opt_range.cc: disallow loose index scan optimization for AGG_FUNC(DISTINCT ...) if GROUP_MIN_MAX quick select uses clustered key. --- mysql-test/r/group_min_max_innodb.result | 24 ++++++++++++++++++++++++ mysql-test/t/group_min_max_innodb.test | 20 ++++++++++++++++++++ sql/opt_range.cc | 12 ++++++++++++ 3 files changed, 56 insertions(+) diff --git a/mysql-test/r/group_min_max_innodb.result b/mysql-test/r/group_min_max_innodb.result index 6607e1babf6..0e7841e979d 100644 --- a/mysql-test/r/group_min_max_innodb.result +++ b/mysql-test/r/group_min_max_innodb.result @@ -94,3 +94,27 @@ pk drop view v1; drop table t1; End of 5.1 tests +# +# Bug#12540545 61101: ASSERTION FAILURE IN THREAD 1256741184 IN +# FILE /BUILDDIR/BUILD/BUILD/MYSQ +# +CREATE TABLE t1 (a CHAR(1), b CHAR(1), PRIMARY KEY (a,b)) ENGINE=InnoDB; +INSERT INTO t1 VALUES ('a', 'b'), ('c', 'd'); +EXPLAIN SELECT COUNT(DISTINCT a) FROM t1 WHERE b = 'b'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL PRIMARY 2 NULL 2 Using where; Using index +SELECT COUNT(DISTINCT a) FROM t1 WHERE b = 'b'; +COUNT(DISTINCT a) +1 +DROP TABLE t1; +CREATE TABLE t1 (a CHAR(1) NOT NULL, b CHAR(1) NOT NULL, UNIQUE KEY (a,b)) +ENGINE=InnoDB; +INSERT INTO t1 VALUES ('a', 'b'), ('c', 'd'); +EXPLAIN SELECT COUNT(DISTINCT a) FROM t1 WHERE b = 'b'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL a 2 NULL 2 Using where; Using index +SELECT COUNT(DISTINCT a) FROM t1 WHERE b = 'b'; +COUNT(DISTINCT a) +1 +DROP TABLE t1; +End of 5.5 tests diff --git a/mysql-test/t/group_min_max_innodb.test b/mysql-test/t/group_min_max_innodb.test index 643b4f7d55e..7038eb2ff47 100644 --- a/mysql-test/t/group_min_max_innodb.test +++ b/mysql-test/t/group_min_max_innodb.test @@ -117,3 +117,23 @@ drop view v1; drop table t1; --echo End of 5.1 tests + +--echo # +--echo # Bug#12540545 61101: ASSERTION FAILURE IN THREAD 1256741184 IN +--echo # FILE /BUILDDIR/BUILD/BUILD/MYSQ +--echo # + +CREATE TABLE t1 (a CHAR(1), b CHAR(1), PRIMARY KEY (a,b)) ENGINE=InnoDB; +INSERT INTO t1 VALUES ('a', 'b'), ('c', 'd'); +EXPLAIN SELECT COUNT(DISTINCT a) FROM t1 WHERE b = 'b'; +SELECT COUNT(DISTINCT a) FROM t1 WHERE b = 'b'; +DROP TABLE t1; + +CREATE TABLE t1 (a CHAR(1) NOT NULL, b CHAR(1) NOT NULL, UNIQUE KEY (a,b)) +ENGINE=InnoDB; +INSERT INTO t1 VALUES ('a', 'b'), ('c', 'd'); +EXPLAIN SELECT COUNT(DISTINCT a) FROM t1 WHERE b = 'b'; +SELECT COUNT(DISTINCT a) FROM t1 WHERE b = 'b'; +DROP TABLE t1; + +--echo End of 5.5 tests diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 730024f4389..8a6607cf343 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -9318,6 +9318,11 @@ cost_group_min_max(TABLE* table, KEY *index_info, uint used_key_parts, except MIN and MAX. For queries with DISTINCT, aggregate functions are allowed. SA5. The select list in DISTINCT queries should not contain expressions. + SA6. Clustered index can not be used by GROUP_MIN_MAX quick select + for AGG_FUNC(DISTINCT ...) optimization because cursor position is + never stored after a unique key lookup in the clustered index and + furhter index_next/prev calls can not be used. So loose index scan + optimization can not be used in this case. GA1. If Q has a GROUP BY clause, then GA is a prefix of I. That is, if G_i = A_j => i = j. GA2. If Q has a DISTINCT clause, then there is a permutation of SA that @@ -9804,6 +9809,13 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree, double read_time) Field::itMBR : Field::itRAW)) DBUG_RETURN(NULL); + /* + Check (SA6) if clustered key is used + */ + if (is_agg_distinct && index == table->s->primary_key && + table->file->primary_key_is_clustered()) + DBUG_RETURN(NULL); + /* The query passes all tests, so construct a new TRP object. */ read_plan= new (param->mem_root) TRP_GROUP_MIN_MAX(have_min, have_max, is_agg_distinct, From de8c70e70b3fd335e1d34a5635fc4357adb43d95 Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Thu, 20 Oct 2011 15:03:22 +0400 Subject: [PATCH 037/288] BUG#11757032 - 49030: OPTIMIZE TABLE BREAKS MYISAM TABLE WHEN USING MYISAM_USE_MMAP ON WINDOWS When OPTIMIZE/REPAIR TABLE is switching to new data file, old data file is removed while memory mapping is still active. With 5.1 implementation of nt_share_delete() it is not permitted to remove mmaped file. This fix disables memory mapping for mi_repair() operations. mysql-test/r/myisam.result: A test case for BUG#11757032. mysql-test/t/myisam.test: A test case for BUG#11757032. storage/myisam/ha_myisam.cc: mi_repair*() functions family use file I/O even if memory mapping is available. Since mixing mmap I/O and file I/O may cause various artifacts, memory mapping must be disabled. storage/myisam/mi_delete_all.c: Clean-up: do not attempt to remap file after truncate, since there is nothing to map. --- mysql-test/r/myisam.result | 24 ++++++++++++++++++++++++ mysql-test/t/myisam.test | 18 ++++++++++++++++++ storage/myisam/ha_myisam.cc | 16 ++++++++++++++++ storage/myisam/mi_delete_all.c | 5 ----- 4 files changed, 58 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result index 433fc7c16a7..620c1f8b4b6 100644 --- a/mysql-test/r/myisam.result +++ b/mysql-test/r/myisam.result @@ -2412,4 +2412,28 @@ CARDINALITY DROP TABLE t1; SET myisam_sort_buffer_size=@@global.myisam_sort_buffer_size; SET myisam_repair_threads=@@global.myisam_repair_threads; +# +# BUG#11757032 - 49030: OPTIMIZE TABLE BREAKS MYISAM TABLE WHEN +# USING MYISAM_USE_MMAP ON WINDOWS +# +SET GLOBAL myisam_use_mmap=1; +CREATE TABLE t1(a INT); +INSERT INTO t1 VALUES(1),(2); +DELETE FROM t1 WHERE a=1; +FLUSH TABLE t1; +LOCK TABLE t1 WRITE; +OPTIMIZE TABLE t1; +Table Op Msg_type Msg_text +test.t1 optimize status OK +INSERT INTO t1 VALUES(3); +UNLOCK TABLES; +SELECT * FROM t1; +a +2 +3 +CHECK TABLE t1; +Table Op Msg_type Msg_text +test.t1 check status OK +DROP TABLE t1; +SET GLOBAL myisam_use_mmap=default; End of 5.1 tests diff --git a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test index 4abd7dd2b1b..5340ddcaa48 100644 --- a/mysql-test/t/myisam.test +++ b/mysql-test/t/myisam.test @@ -1645,4 +1645,22 @@ DROP TABLE t1; SET myisam_sort_buffer_size=@@global.myisam_sort_buffer_size; SET myisam_repair_threads=@@global.myisam_repair_threads; +--echo # +--echo # BUG#11757032 - 49030: OPTIMIZE TABLE BREAKS MYISAM TABLE WHEN +--echo # USING MYISAM_USE_MMAP ON WINDOWS +--echo # +SET GLOBAL myisam_use_mmap=1; +CREATE TABLE t1(a INT); +INSERT INTO t1 VALUES(1),(2); +DELETE FROM t1 WHERE a=1; +FLUSH TABLE t1; +LOCK TABLE t1 WRITE; +OPTIMIZE TABLE t1; +INSERT INTO t1 VALUES(3); +UNLOCK TABLES; +SELECT * FROM t1; +CHECK TABLE t1; +DROP TABLE t1; +SET GLOBAL myisam_use_mmap=default; + --echo End of 5.1 tests diff --git a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc index 881102433d8..173dc356778 100644 --- a/storage/myisam/ha_myisam.cc +++ b/storage/myisam/ha_myisam.cc @@ -1135,6 +1135,18 @@ int ha_myisam::repair(THD *thd, MI_CHECK ¶m, bool do_optimize) mi_get_mask_all_keys_active(share->base.keys) : share->state.key_map); uint testflag=param.testflag; +#ifdef HAVE_MMAP + bool remap= test(share->file_map); + /* + mi_repair*() functions family use file I/O even if memory + mapping is available. + + Since mixing mmap I/O and file I/O may cause various artifacts, + memory mapping must be disabled. + */ + if (remap) + mi_munmap_file(file); +#endif if (mi_test_if_sort_rep(file,file->state->records,key_map,0) && (local_testflag & T_REP_BY_SORT)) { @@ -1166,6 +1178,10 @@ int ha_myisam::repair(THD *thd, MI_CHECK ¶m, bool do_optimize) error= mi_repair(¶m, file, fixed_name, param.testflag & T_QUICK); } +#ifdef HAVE_MMAP + if (remap) + mi_dynmap_file(file, file->state->data_file_length); +#endif param.testflag=testflag; optimize_done=1; } diff --git a/storage/myisam/mi_delete_all.c b/storage/myisam/mi_delete_all.c index 6ba542c112f..126359a0864 100644 --- a/storage/myisam/mi_delete_all.c +++ b/storage/myisam/mi_delete_all.c @@ -63,11 +63,6 @@ int mi_delete_all_rows(MI_INFO *info) my_chsize(share->kfile, share->base.keystart, 0, MYF(MY_WME)) ) goto err; VOID(_mi_writeinfo(info,WRITEINFO_UPDATE_KEYFILE)); -#ifdef HAVE_MMAP - /* Map again */ - if (share->file_map) - mi_dynmap_file(info, (my_off_t) 0); -#endif allow_break(); /* Allow SIGHUP & SIGINT */ DBUG_RETURN(0); From ca881510f21b9b0787079ec478d563cf52d38264 Mon Sep 17 00:00:00 2001 From: Alexander Nozdrin Date: Thu, 20 Oct 2011 18:06:41 +0400 Subject: [PATCH 038/288] Fix Windows-build failure: use my_snprintf() instead of snprintf(). --- tests/mysql_client_test.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 2472a0b6df6..f553eb530ae 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -18524,14 +18524,14 @@ static void test_bug13001491() myheader("test_bug13001491"); - snprintf(query, MAX_TEST_QUERY_LENGTH, + my_snprintf(query, MAX_TEST_QUERY_LENGTH, "GRANT ALL PRIVILEGES ON *.* TO mysqltest_u1@%s", opt_host ? opt_host : "'localhost'"); rc= mysql_query(mysql, query); myquery(rc); - snprintf(query, MAX_TEST_QUERY_LENGTH, + my_snprintf(query, MAX_TEST_QUERY_LENGTH, "GRANT RELOAD ON *.* TO mysqltest_u1@%s", opt_host ? opt_host : "'localhost'"); @@ -18584,7 +18584,7 @@ static void test_bug13001491() mysql_close(c); c= NULL; - snprintf(query, MAX_TEST_QUERY_LENGTH, + my_snprintf(query, MAX_TEST_QUERY_LENGTH, "DROP USER mysqltest_u1@%s", opt_host ? opt_host : "'localhost'"); From 8a0be8a541a1fd79bce33fc5157e8c7ff613c185 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 21 Oct 2011 06:32:16 +0300 Subject: [PATCH 039/288] Bug#13116045 Compilation failure using GCC 4.6.1 in btr/btr0cur.c btr_record_not_null_field_in_rec(): Remove the parameter rec. Use rec_offs_nth_sql_null() instead of rec_get_nth_field(). rb:788 approved by Jimmy Yang --- storage/innobase/btr/btr0cur.c | 18 +++++------------- storage/innodb_plugin/ChangeLog | 5 +++++ storage/innodb_plugin/btr/btr0cur.c | 18 +++++------------- 3 files changed, 15 insertions(+), 26 deletions(-) diff --git a/storage/innobase/btr/btr0cur.c b/storage/innobase/btr/btr0cur.c index a1dda8edf69..37bb3188785 100644 --- a/storage/innobase/btr/btr0cur.c +++ b/storage/innobase/btr/btr0cur.c @@ -2864,7 +2864,6 @@ static void btr_record_not_null_field_in_rec( /*=============================*/ - rec_t* rec, /* in: physical record */ ulint n_unique, /* in: dict_index_get_n_unique(index), number of columns uniquely determine an index entry */ @@ -2883,17 +2882,11 @@ btr_record_not_null_field_in_rec( } for (i = 0; i < n_unique; i++) { - ulint rec_len; - byte* field; - - field = rec_get_nth_field(rec, 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]++; } } @@ -2988,7 +2981,7 @@ btr_estimate_number_of_different_key_vals( if (n_not_null) { btr_record_not_null_field_in_rec( - rec, n_cols, offsets_rec, n_not_null); + n_cols, offsets_rec, n_not_null); } } @@ -3023,8 +3016,7 @@ btr_estimate_number_of_different_key_vals( if (n_not_null) { btr_record_not_null_field_in_rec( - next_rec, n_cols, offsets_next_rec, - n_not_null); + n_cols, offsets_next_rec, n_not_null); } total_external_size diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index b560f69daea..68f60c37f1f 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,3 +1,8 @@ +2011-10-20 The InnoDB Team + + * btr/brt0cur.c: + Fix Bug#13116045 Compilation failure using GCC 4.6.1 in btr/btr0cur.c + 2011-10-12 The InnoDB Team * btr/btr0cur.c, btr/btr0sea.c, buf/buf0buf.c, buf/buf0lru.c, diff --git a/storage/innodb_plugin/btr/btr0cur.c b/storage/innodb_plugin/btr/btr0cur.c index 5fe16ff1215..1e603a6fc81 100644 --- a/storage/innodb_plugin/btr/btr0cur.c +++ b/storage/innodb_plugin/btr/btr0cur.c @@ -3261,7 +3261,6 @@ static void btr_record_not_null_field_in_rec( /*=============================*/ - rec_t* rec, /*!< in: physical record */ ulint n_unique, /*!< in: dict_index_get_n_unique(index), number of columns uniquely determine an index entry */ @@ -3280,17 +3279,11 @@ btr_record_not_null_field_in_rec( } for (i = 0; i < n_unique; i++) { - ulint rec_len; - byte* field; - - field = rec_get_nth_field(rec, 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]++; } } @@ -3398,7 +3391,7 @@ btr_estimate_number_of_different_key_vals( if (n_not_null) { btr_record_not_null_field_in_rec( - rec, n_cols, offsets_rec, n_not_null); + n_cols, offsets_rec, n_not_null); } } @@ -3433,8 +3426,7 @@ btr_estimate_number_of_different_key_vals( if (n_not_null) { btr_record_not_null_field_in_rec( - next_rec, n_cols, offsets_next_rec, - n_not_null); + n_cols, offsets_next_rec, n_not_null); } total_external_size From 3e250dc83f263b3a541f1e780c2382f5e21897d2 Mon Sep 17 00:00:00 2001 From: Ashish Agarwal Date: Fri, 21 Oct 2011 16:19:58 +0530 Subject: [PATCH 040/288] bug#11758979 - 51252: ARCHIVE TABLES STILL FAIL UNDER STRESS TESTS: CRASH, CORRUPTION, 4G MEMOR Issue: Valgrind errors due to checksum and optimize query angaist archive tables with null columns. Table record buffer was not initialized. Solution: Initialize the record buffer. --- mysql-test/r/archive.result | 19 +++++++++++++++++++ mysql-test/t/archive.test | 15 +++++++++++++++ storage/archive/ha_archive.cc | 12 ++++++++++++ 3 files changed, 46 insertions(+) diff --git a/mysql-test/r/archive.result b/mysql-test/r/archive.result index aacaff30898..3ffefd2aedb 100644 --- a/mysql-test/r/archive.result +++ b/mysql-test/r/archive.result @@ -12823,3 +12823,22 @@ a b c d e f -1 b c d e 1 DROP TABLE t1; SET sort_buffer_size=DEFAULT; +# +# BUG#11758979 - 51252: ARCHIVE TABLES STILL FAIL UNDER STRESS +# TESTS: CRASH, CORRUPTION, 4G MEMOR +# (to be executed with valgrind) +CREATE TABLE t1(a BLOB, b VARCHAR(200)) ENGINE=ARCHIVE; +INSERT INTO t1 VALUES(NULL, ''); +FLUSH TABLE t1; +# we need this select to workaround BUG#11764364 +SELECT * FROM t1; +a b +NULL +CHECKSUM TABLE t1 EXTENDED; +Table Checksum +test.t1 286155052 +FLUSH TABLE t1; +OPTIMIZE TABLE t1; +Table Op Msg_type Msg_text +test.t1 optimize status OK +DROP TABLE t1; diff --git a/mysql-test/t/archive.test b/mysql-test/t/archive.test index 4686b3ca1dc..3c18152ccc6 100644 --- a/mysql-test/t/archive.test +++ b/mysql-test/t/archive.test @@ -1745,3 +1745,18 @@ INSERT INTO t1 SELECT t1.* FROM t1,t1 t2,t1 t3,t1 t4,t1 t5,t1 t6; SELECT * FROM t1 ORDER BY f LIMIT 1; DROP TABLE t1; SET sort_buffer_size=DEFAULT; + + +--echo # +--echo # BUG#11758979 - 51252: ARCHIVE TABLES STILL FAIL UNDER STRESS +--echo # TESTS: CRASH, CORRUPTION, 4G MEMOR +--echo # (to be executed with valgrind) +CREATE TABLE t1(a BLOB, b VARCHAR(200)) ENGINE=ARCHIVE; +INSERT INTO t1 VALUES(NULL, ''); +FLUSH TABLE t1; +--echo # we need this select to workaround BUG#11764364 +SELECT * FROM t1; +CHECKSUM TABLE t1 EXTENDED; +FLUSH TABLE t1; +OPTIMIZE TABLE t1; +DROP TABLE t1; diff --git a/storage/archive/ha_archive.cc b/storage/archive/ha_archive.cc index 345c1b6835f..b6947688768 100644 --- a/storage/archive/ha_archive.cc +++ b/storage/archive/ha_archive.cc @@ -819,6 +819,7 @@ uint32 ha_archive::max_row_length(const uchar *buf) ptr != end ; ptr++) { + if (!table->field[*ptr]->is_null()) length += 2 + ((Field_blob*)table->field[*ptr])->get_length(); } @@ -1178,6 +1179,17 @@ int ha_archive::unpack_row(azio_stream *file_to_read, uchar *record) /* Copy null bits */ const uchar *ptr= record_buffer->buffer; + /* + Field::unpack() is not called when field is NULL. For VARCHAR + Field::unpack() only unpacks as much bytes as occupied by field + value. In these cases respective memory area on record buffer is + not initialized. + + These uninitialized areas may be accessed by CHECKSUM TABLE or + by optimizer using temporary table (BUG#12997905). We may remove + this memset() when they're fixed. + */ + memset(record, 0, table->s->reclength); memcpy(record, ptr, table->s->null_bytes); ptr+= table->s->null_bytes; for (Field **field=table->field ; *field ; field++) From 62a40350b162a73a20a0d66b7efebd470b520c2b Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Fri, 21 Oct 2011 18:10:12 +0530 Subject: [PATCH 041/288] Bug#13106585 PUSH FOR "WL#5945 : IMPROVE LIBEDIT LIBRARY" BREAKS SOURCE RELEASE BUILD Some of the required files were not getting copied while performing 'make dist' and hence the build failed for the created distribution source. Added the missing files to Makefile.am. --- cmd-line-utils/libedit/Makefile.am | 9 +++++---- cmd-line-utils/libedit/chartype.c | 3 --- cmd-line-utils/libedit/histedit.h | 9 --------- cmd-line-utils/libedit/refresh.c | 2 -- cmd-line-utils/libedit/sys.h | 15 ++++++++++++++- cmd-line-utils/libedit/terminal.c | 3 --- 6 files changed, 19 insertions(+), 22 deletions(-) diff --git a/cmd-line-utils/libedit/Makefile.am b/cmd-line-utils/libedit/Makefile.am index 87ca8b591bb..b68eca7f44a 100644 --- a/cmd-line-utils/libedit/Makefile.am +++ b/cmd-line-utils/libedit/Makefile.am @@ -7,8 +7,8 @@ INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include noinst_LIBRARIES = libedit.a -libedit_a_SOURCES = chared.c el.c eln.c history.c historyn.c map.c prompt.c readline.c \ - search.c tokenizer.c tokenizern.c vi.c common.c emacs.c \ +libedit_a_SOURCES = chared.c el.c eln.c history.c historyn.c map.c prompt.c chartype.c \ + readline.c search.c tokenizer.c tokenizern.c vi.c common.c emacs.c \ hist.c keymacro.c parse.c read.c refresh.c sig.c terminal.c \ tty.c help.c fcns.c filecomplete.c \ np/unvis.c np/strlcpy.c np/vis.c np/strlcat.c \ @@ -19,8 +19,8 @@ libedit_a_DEPENDENCIES = @LIBEDIT_LOBJECTS@ pkginclude_HEADERS = readline/readline.h -noinst_HEADERS = chared.h el.h el_terminal.h histedit.h keymacro.h parse.h refresh.h sig.h \ - sys.h config.h hist.h map.h prompt.h read.h \ +noinst_HEADERS = chared.h chartype.h el.h el_terminal.h histedit.h keymacro.h parse.h \ + refresh.h sig.h sys.h config.h hist.h map.h prompt.h read.h \ search.h tty.h filecomplete.h np/vis.h EXTRA_DIST = makelist.sh @@ -74,6 +74,7 @@ eln.o: vi.h emacs.h common.h help.h fcns.h history.o: vi.h emacs.h common.h help.h fcns.h historyn.o: vi.h emacs.h common.h help.h fcns.h map.o: vi.h emacs.h common.h help.h fcns.h +chartype.o: vi.h emacs.h common.h help.h fcns.h prompt.o: vi.h emacs.h common.h help.h fcns.h readline.o: vi.h emacs.h common.h help.h fcns.h search.o: vi.h emacs.h common.h help.h fcns.h diff --git a/cmd-line-utils/libedit/chartype.c b/cmd-line-utils/libedit/chartype.c index 3d66c48c36e..b70aebeec46 100644 --- a/cmd-line-utils/libedit/chartype.c +++ b/cmd-line-utils/libedit/chartype.c @@ -258,9 +258,6 @@ out: return NULL; } -#ifdef WIDECHAR -int wcwidth(wchar_t wc); // Signature. -#endif protected int ct_visual_width(Char c) diff --git a/cmd-line-utils/libedit/histedit.h b/cmd-line-utils/libedit/histedit.h index b066593cefd..9f2b245f851 100644 --- a/cmd-line-utils/libedit/histedit.h +++ b/cmd-line-utils/libedit/histedit.h @@ -247,15 +247,6 @@ int tok_str(Tokenizer *, const char *, /* * Begin Wide Character Support */ -#ifdef __linux__ -/* Apparently we need _GNU_SOURCE defined to get access to wcsdup on Linux */ -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif -#endif - -#include -#include /* * Wide character versions diff --git a/cmd-line-utils/libedit/refresh.c b/cmd-line-utils/libedit/refresh.c index a144059f700..64057eaabfe 100644 --- a/cmd-line-utils/libedit/refresh.c +++ b/cmd-line-utils/libedit/refresh.c @@ -40,8 +40,6 @@ static char sccsid[] = "@(#)refresh.c 8.1 (Berkeley) 6/4/93"; #endif #endif /* not lint && not SCCSID */ -#include "chartype.c" /* XXXMYSQL */ - /* * refresh.c: Lower level screen refreshing functions */ diff --git a/cmd-line-utils/libedit/sys.h b/cmd-line-utils/libedit/sys.h index 2731fb5f30e..33638d1565b 100644 --- a/cmd-line-utils/libedit/sys.h +++ b/cmd-line-utils/libedit/sys.h @@ -92,8 +92,21 @@ size_t strlcpy(char *dst, const char *src, size_t size); char *fgetln(FILE *fp, size_t *len); #endif -#ifndef HAVE_WCSDUP +#ifdef __linux__ +/* Apparently we need _GNU_SOURCE defined to get access to wcsdup on Linux */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#endif + +#ifndef __USE_XOPEN +#define __USE_XOPEN +#endif + #include +#include + +#ifndef HAVE_WCSDUP wchar_t *wcsdup(const wchar_t *); #endif diff --git a/cmd-line-utils/libedit/terminal.c b/cmd-line-utils/libedit/terminal.c index ae91d9afe92..8cfbeac7c52 100644 --- a/cmd-line-utils/libedit/terminal.c +++ b/cmd-line-utils/libedit/terminal.c @@ -636,9 +636,6 @@ mc_again: el->el_cursor.h = where; /* now where is here */ } -#ifdef WIDECHAR -int wcwidth(wchar_t); // Signature. -#endif /* terminal_overwrite(): * Overstrike num characters From a656ff83c822f79806aaaf71d2aca98529db23f9 Mon Sep 17 00:00:00 2001 From: Dmitry Lenev Date: Sun, 23 Oct 2011 09:37:35 +0400 Subject: [PATCH 042/288] Fix for bug #13116518 - "OPEN_TABLES() SHOULD NOT ALLOCATE AND FREE NEW_FRM_MEM WITHOUT NEEDING TO". During the process of opening tables for a statement, we allocated memory which was used only during view loading even in cases when the statement didn't use any views. Such an unnecessary allocation (and corresponding freeing) might have caused significant performance overhead in some workloads. For example, it caused up to 15% slowdown in a simple stored routine calculating Fibonacci's numbers. This memory was pre-allocated as part of "new_frm_mem" MEM_ROOT initialization at the beginning of open_tables(). This patch addresses this issue by turning off memory pre-allocation during initialization for this MEM_ROOT. Now, memory on this root will be allocated only at the point when the first .FRM for a view is opened. The patch doesn't contain a test case since it is hard to test the performance improvements or the absence of memory allocation in our test framework. --- sql/sql_base.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 644796ea337..e0472e2c9b5 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -4810,10 +4810,11 @@ bool open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags, } /* - temporary mem_root for new .frm parsing. - TODO: variables for size + Initialize temporary MEM_ROOT for new .FRM parsing. Do not allocate + anything yet, to avoid penalty for statements which don't use views + and thus new .FRM format. */ - init_sql_alloc(&new_frm_mem, 8024, 8024); + init_sql_alloc(&new_frm_mem, 8024, 0); thd->current_tablenr= 0; restart: From f66002f8eb5747e95721790b30a5e02be6ca6929 Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Mon, 24 Oct 2011 13:35:28 +0530 Subject: [PATCH 043/288] WL#5945 - Improve libedit library Fixed a misplaced parenthesis, injected due to syncing from libedit CVS head. --- cmd-line-utils/libedit/README | 2 +- cmd-line-utils/libedit/chared.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd-line-utils/libedit/README b/cmd-line-utils/libedit/README index 28041766a2e..c4bc1554b03 100644 --- a/cmd-line-utils/libedit/README +++ b/cmd-line-utils/libedit/README @@ -42,7 +42,7 @@ then merge remaining bits by hand. All MySQL-specific changes should be marked with XXXMYSQL to make them easier to identify and merge. To generate a 'clean' diff against upstream you can use the above commands but use - cvs co -D "2011/10/04 15:27:04" [..] + cvs co -D "2011/10/23 17:37:55" [..] to fetch the baseline of most recent merge. diff --git a/cmd-line-utils/libedit/chared.c b/cmd-line-utils/libedit/chared.c index aba30086b9f..647a5afe439 100644 --- a/cmd-line-utils/libedit/chared.c +++ b/cmd-line-utils/libedit/chared.c @@ -1,4 +1,4 @@ -/* $NetBSD: chared.c,v 1.35 2011/08/16 16:25:15 christos Exp $ */ +/* $NetBSD: chared.c,v 1.36 2011/10/23 17:37:55 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -200,7 +200,7 @@ c_delbefore1(EditLine *el) protected int ce__isword(Int p) { - return Isalnum(p || Strchr(STR("*?_-.[]~="), p) != NULL); + return Isalnum(p) || Strchr(STR("*?_-.[]~="), p) != NULL; } From dce337406ea07b4581bf724133d5262fddd365f3 Mon Sep 17 00:00:00 2001 From: Vasil Dimov Date: Tue, 25 Oct 2011 16:46:38 +0300 Subject: [PATCH 044/288] Fix Bug#12661768 UPDATE IGNORE CRASHES SERVER IF TABLE IS INNODB AND IT IS PARENT FOR OTHER ONE Do not try to lookup key_nr'th key in 'table' because there may not be such a key there. key_nr is the number of the key in the _child_ table name, not in the parent table. Instead just print the fields of the record that are covered by the first key defined on the parent table. This bug gets a better fix in MySQL 5.6, which is too risky for 5.1 and 5.5. Approved by: Jon Olav Hauglid (via IM) --- .../suite/innodb/r/innodb_bug12661768.result | 2 + .../suite/innodb/t/innodb_bug12661768.test | 50 +++++++++++++++++++ sql/handler.cc | 8 ++- 3 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 mysql-test/suite/innodb/r/innodb_bug12661768.result create mode 100644 mysql-test/suite/innodb/t/innodb_bug12661768.test diff --git a/mysql-test/suite/innodb/r/innodb_bug12661768.result b/mysql-test/suite/innodb/r/innodb_bug12661768.result new file mode 100644 index 00000000000..1f2401ddd47 --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_bug12661768.result @@ -0,0 +1,2 @@ +SET SESSION foreign_key_checks=0; +ERROR 23000: Upholding foreign key constraints for table 'bug12661768_1', entry '3-bbb', key 2 would lead to a duplicate entry diff --git a/mysql-test/suite/innodb/t/innodb_bug12661768.test b/mysql-test/suite/innodb/t/innodb_bug12661768.test new file mode 100644 index 00000000000..01549a7e9e9 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_bug12661768.test @@ -0,0 +1,50 @@ +# +# Bug#12661768 UPDATE IGNORE CRASHES SERVER IF TABLE IS INNODB AND IT IS +# PARENT FOR OTHER ONE +# + +-- source include/have_innodb.inc + +SET SESSION foreign_key_checks=0; + +# only interested that the "UPDATE IGNORE" at the end does not crash the server + +-- disable_query_log +-- disable_result_log + +SET NAMES utf8; + +-- let $t1_name = bug12661768_1 +-- let $t2_name = bug12661768_2 +-- let $fk_name = ab_on_2 +-- let $key_str = 'bbb' + +eval DROP TABLE IF EXISTS `$t2_name`, `$t1_name`; + +eval CREATE TABLE `$t1_name` ( + a INT, + b VARCHAR(512), + PRIMARY KEY (a, b) +) ENGINE=INNODB; + +eval CREATE TABLE `$t2_name` ( + id INT, + a INT, + b VARCHAR(512), + PRIMARY KEY (id), + UNIQUE KEY `$fk_name` (a, b), + FOREIGN KEY (a, b) REFERENCES `$t1_name` (a, b) + ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=INNODB; + +eval INSERT INTO `$t1_name` VALUES (1, $key_str); +eval INSERT INTO `$t2_name` VALUES (100, 1, $key_str), (101, 3, $key_str); + +SET SESSION foreign_key_checks=1; + +-- enable_result_log + +-- error ER_FOREIGN_DUPLICATE_KEY +eval UPDATE IGNORE `$t1_name` SET a = 3; + +eval DROP TABLE `$t2_name`, `$t1_name`; diff --git a/sql/handler.cc b/sql/handler.cc index 82f5f2ee841..895e7cc4df0 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -2692,7 +2692,13 @@ void handler::print_error(int error, myf errflag) char key[MAX_KEY_LENGTH]; String str(key,sizeof(key),system_charset_info); /* Table is opened and defined at this point */ - key_unpack(&str,table,(uint) key_nr); + key_unpack(&str,table,0 /* Use 0 instead of key_nr because key_nr + is a key number in the child FK table, not in our 'table'. See + Bug#12661768 UPDATE IGNORE CRASHES SERVER IF TABLE IS INNODB + AND IT IS PARENT FOR OTHER ONE + This bug gets a better fix in MySQL 5.6, but it is too risky + to get that in 5.1 and 5.5 (extending the handler interface + and adding new error message codes */); max_length= (MYSQL_ERRMSG_SIZE- (uint) strlen(ER(ER_FOREIGN_DUPLICATE_KEY))); if (str.length() >= max_length) From 013ba71dfdd6f9d49730c1a918d1d089976faefd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 25 Oct 2011 17:33:38 +0300 Subject: [PATCH 045/288] Bug#13002783 PARTIALLY UNINITIALIZED CASCADE UPDATE VECTOR In the ON UPDATE CASCADE clause of FOREIGN KEY constraints, the calculated update vector was not fully initialized. This bug was introduced in the InnoDB Plugin when implementing support for ROW_FORMAT=DYNAMIC. Additionally, the data type information was not initialized, but apparently it has never been needed in this case. Nevertheless, it is not good programming practice to pass uninitialized values around. calc_row_difference(): Declare the update field uninitialized in Valgrind. Copy the data type information as well, except when the field is SQL NULL. In the built-in InnoDB, initialize ufield->extern_storage = FALSE (an initialization bug that had gone unnoticed this far). The InnoDB Plugin and later have this flag to dfield_t and have always initialized it properly. row_ins_cascade_calc_update_vec(): Reduce the scope of some pointers. Initialize orig_len. (This caused the bug in InnoDB Plugin and later.) row_ins_foreign_check_on_constraint(): Simplify a condition. Declare the update vector uninitialized. rb:771 approved by Jimmy Yang --- mysql-test/suite/innodb/r/innodb.result | 16 +++++++++++++++- mysql-test/suite/innodb/t/innodb.test | 18 ++++++++++++++++++ mysql-test/suite/innodb_plugin/r/innodb.result | 16 +++++++++++++++- mysql-test/suite/innodb_plugin/t/innodb.test | 18 ++++++++++++++++++ storage/innobase/handler/ha_innodb.cc | 10 +++++++--- storage/innobase/row/row0ins.c | 15 ++++++++------- storage/innodb_plugin/ChangeLog | 7 ++++++- storage/innodb_plugin/handler/ha_innodb.cc | 9 +++++---- storage/innodb_plugin/row/row0ins.c | 17 ++++++++++------- 9 files changed, 102 insertions(+), 24 deletions(-) diff --git a/mysql-test/suite/innodb/r/innodb.result b/mysql-test/suite/innodb/r/innodb.result index c6f6f352743..edf3c7d2753 100644 --- a/mysql-test/suite/innodb/r/innodb.result +++ b/mysql-test/suite/innodb/r/innodb.result @@ -1293,6 +1293,20 @@ ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fail update t3 set t3.id=7 where t1.id =1 and t2.id = t1.id and t3.id = t2.id; ERROR 42S22: Unknown column 't1.id' in 'where clause' drop table t3,t2,t1; +CREATE TABLE t1 ( +c1 VARCHAR(8), c2 VARCHAR(8), +PRIMARY KEY (c1, c2) +) ENGINE=InnoDB; +CREATE TABLE t2 ( +c0 INT PRIMARY KEY, +c1 VARCHAR(8) UNIQUE, +FOREIGN KEY (c1) REFERENCES t1 (c1) ON UPDATE CASCADE +) ENGINE=InnoDB; +INSERT INTO t1 VALUES ('old', 'somevalu'), ('other', 'anyvalue'); +INSERT INTO t2 VALUES (10, 'old'), (20, 'other'); +UPDATE t1 SET c1 = 'other' WHERE c1 = 'old'; +ERROR 23000: Upholding foreign key constraints for table 't1', entry '', key 2 would lead to a duplicate entry +DROP TABLE t2,t1; create table t1( id int primary key, pid int, @@ -1671,7 +1685,7 @@ variable_value - @innodb_rows_deleted_orig 71 SELECT variable_value - @innodb_rows_inserted_orig FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_rows_inserted'; variable_value - @innodb_rows_inserted_orig -1063 +1067 SELECT variable_value - @innodb_rows_updated_orig FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_rows_updated'; variable_value - @innodb_rows_updated_orig 865 diff --git a/mysql-test/suite/innodb/t/innodb.test b/mysql-test/suite/innodb/t/innodb.test index 480183b9e2d..ef050390b48 100644 --- a/mysql-test/suite/innodb/t/innodb.test +++ b/mysql-test/suite/innodb/t/innodb.test @@ -1021,6 +1021,24 @@ update t1,t2,t3 set t3.id=5, t2.id=6, t1.id=7 where t1.id =1 and t2.id = t1.id update t3 set t3.id=7 where t1.id =1 and t2.id = t1.id and t3.id = t2.id; drop table t3,t2,t1; +# test ON UPDATE CASCADE +CREATE TABLE t1 ( + c1 VARCHAR(8), c2 VARCHAR(8), + PRIMARY KEY (c1, c2) +) ENGINE=InnoDB; + +CREATE TABLE t2 ( + c0 INT PRIMARY KEY, + c1 VARCHAR(8) UNIQUE, + FOREIGN KEY (c1) REFERENCES t1 (c1) ON UPDATE CASCADE +) ENGINE=InnoDB; + +INSERT INTO t1 VALUES ('old', 'somevalu'), ('other', 'anyvalue'); +INSERT INTO t2 VALUES (10, 'old'), (20, 'other'); +-- error ER_FOREIGN_DUPLICATE_KEY +UPDATE t1 SET c1 = 'other' WHERE c1 = 'old'; +DROP TABLE t2,t1; + # # test for recursion depth limit # diff --git a/mysql-test/suite/innodb_plugin/r/innodb.result b/mysql-test/suite/innodb_plugin/r/innodb.result index d3f7a0b9fff..a550b9702bb 100644 --- a/mysql-test/suite/innodb_plugin/r/innodb.result +++ b/mysql-test/suite/innodb_plugin/r/innodb.result @@ -1301,6 +1301,20 @@ ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fail update t3 set t3.id=7 where t1.id =1 and t2.id = t1.id and t3.id = t2.id; ERROR 42S22: Unknown column 't1.id' in 'where clause' drop table t3,t2,t1; +CREATE TABLE t1 ( +c1 VARCHAR(8), c2 VARCHAR(8), +PRIMARY KEY (c1, c2) +) ENGINE=InnoDB; +CREATE TABLE t2 ( +c0 INT PRIMARY KEY, +c1 VARCHAR(8) UNIQUE, +FOREIGN KEY (c1) REFERENCES t1 (c1) ON UPDATE CASCADE +) ENGINE=InnoDB; +INSERT INTO t1 VALUES ('old', 'somevalu'), ('other', 'anyvalue'); +INSERT INTO t2 VALUES (10, 'old'), (20, 'other'); +UPDATE t1 SET c1 = 'other' WHERE c1 = 'old'; +ERROR 23000: Upholding foreign key constraints for table 't1', entry '', key 2 would lead to a duplicate entry +DROP TABLE t2,t1; create table t1( id int primary key, pid int, @@ -1679,7 +1693,7 @@ variable_value - @innodb_rows_deleted_orig 71 SELECT variable_value - @innodb_rows_inserted_orig FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_rows_inserted'; variable_value - @innodb_rows_inserted_orig -1067 +1071 SELECT variable_value - @innodb_rows_updated_orig FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_rows_updated'; variable_value - @innodb_rows_updated_orig 866 diff --git a/mysql-test/suite/innodb_plugin/t/innodb.test b/mysql-test/suite/innodb_plugin/t/innodb.test index cfc2277d501..1480492cf2a 100644 --- a/mysql-test/suite/innodb_plugin/t/innodb.test +++ b/mysql-test/suite/innodb_plugin/t/innodb.test @@ -1040,6 +1040,24 @@ update t1,t2,t3 set t3.id=5, t2.id=6, t1.id=7 where t1.id =1 and t2.id = t1.id update t3 set t3.id=7 where t1.id =1 and t2.id = t1.id and t3.id = t2.id; drop table t3,t2,t1; +# test ON UPDATE CASCADE +CREATE TABLE t1 ( + c1 VARCHAR(8), c2 VARCHAR(8), + PRIMARY KEY (c1, c2) +) ENGINE=InnoDB; + +CREATE TABLE t2 ( + c0 INT PRIMARY KEY, + c1 VARCHAR(8) UNIQUE, + FOREIGN KEY (c1) REFERENCES t1 (c1) ON UPDATE CASCADE +) ENGINE=InnoDB; + +INSERT INTO t1 VALUES ('old', 'somevalu'), ('other', 'anyvalue'); +INSERT INTO t2 VALUES (10, 'old'), (20, 'other'); +-- error ER_FOREIGN_DUPLICATE_KEY +UPDATE t1 SET c1 = 'other' WHERE c1 = 'old'; +DROP TABLE t2,t1; + # # test for recursion depth limit # diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 2d230e1c297..44b9a7fba36 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -4264,14 +4264,16 @@ 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_noninline(prebuilt->table->cols + i, - &dfield.type); - if (n_len != UNIV_SQL_NULL) { + dict_col_copy_type_noninline( + prebuilt->table->cols + i, + &dfield.type); + buf = row_mysql_store_col_in_innobase_format( &dfield, (byte*)buf, @@ -4282,11 +4284,13 @@ calc_row_difference( prebuilt->table)); ufield->new_val.data = dfield.data; ufield->new_val.len = dfield.len; + ufield->new_val.type = dfield.type; } else { ufield->new_val.data = NULL; ufield->new_val.len = UNIV_SQL_NULL; } + ufield->extern_storage = FALSE; ufield->exp = NULL; ufield->field_no = dict_col_get_clust_pos_noninline( &prebuilt->table->cols[i], clust_index); diff --git a/storage/innobase/row/row0ins.c b/storage/innobase/row/row0ins.c index 6366beb6b47..f6e6c81534b 100644 --- a/storage/innobase/row/row0ins.c +++ b/storage/innobase/row/row0ins.c @@ -425,11 +425,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; @@ -465,12 +463,14 @@ 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; + upd_field_t* ufield; col = dict_index_get_nth_col(index, i); @@ -975,10 +975,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 */ @@ -987,6 +986,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++) { (update->fields + i)->field_no diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index 68f60c37f1f..4e6e2be615a 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,6 +1,11 @@ +2011-10-25 The InnoDB Team + + * handler/ha_innodb.cc, row/row0ins.c: + Fix Bug#13002783 PARTIALLY UNINITIALIZED CASCADE UPDATE VECTOR + 2011-10-20 The InnoDB Team - * btr/brt0cur.c: + * btr/btr0cur.c: Fix Bug#13116045 Compilation failure using GCC 4.6.1 in btr/btr0cur.c 2011-10-12 The InnoDB Team diff --git a/storage/innodb_plugin/handler/ha_innodb.cc b/storage/innodb_plugin/handler/ha_innodb.cc index fc1193e55bb..566c54e0175 100644 --- a/storage/innodb_plugin/handler/ha_innodb.cc +++ b/storage/innodb_plugin/handler/ha_innodb.cc @@ -4971,14 +4971,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, @@ -4986,7 +4987,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); } diff --git a/storage/innodb_plugin/row/row0ins.c b/storage/innodb_plugin/row/row0ins.c index 0f158cdc706..cd135e8ba8f 100644 --- a/storage/innodb_plugin/row/row0ins.c +++ b/storage/innodb_plugin/row/row0ins.c @@ -434,11 +434,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; @@ -474,13 +472,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); @@ -493,6 +493,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; @@ -993,10 +995,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 */ @@ -1005,6 +1006,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]; From e8d793f8709ce2beab3cff6a184e0c959f44e6b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 25 Oct 2011 17:58:34 +0300 Subject: [PATCH 046/288] Fix results after Bug#12661768 fix. --- mysql-test/suite/innodb_plugin/r/innodb.result | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/suite/innodb_plugin/r/innodb.result b/mysql-test/suite/innodb_plugin/r/innodb.result index a550b9702bb..cdb61f3ba98 100644 --- a/mysql-test/suite/innodb_plugin/r/innodb.result +++ b/mysql-test/suite/innodb_plugin/r/innodb.result @@ -1313,7 +1313,7 @@ FOREIGN KEY (c1) REFERENCES t1 (c1) ON UPDATE CASCADE INSERT INTO t1 VALUES ('old', 'somevalu'), ('other', 'anyvalue'); INSERT INTO t2 VALUES (10, 'old'), (20, 'other'); UPDATE t1 SET c1 = 'other' WHERE c1 = 'old'; -ERROR 23000: Upholding foreign key constraints for table 't1', entry '', key 2 would lead to a duplicate entry +ERROR 23000: Upholding foreign key constraints for table 't1', entry 'other-somevalu', key 2 would lead to a duplicate entry DROP TABLE t2,t1; create table t1( id int primary key, From 86c72a3fad6fdd0868d47168c306b873b3aed7cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 26 Oct 2011 09:34:32 +0300 Subject: [PATCH 047/288] Fix results after Bug#12661768 fix. --- mysql-test/suite/innodb/r/innodb.result | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/suite/innodb/r/innodb.result b/mysql-test/suite/innodb/r/innodb.result index edf3c7d2753..ad140cc59be 100644 --- a/mysql-test/suite/innodb/r/innodb.result +++ b/mysql-test/suite/innodb/r/innodb.result @@ -1305,7 +1305,7 @@ FOREIGN KEY (c1) REFERENCES t1 (c1) ON UPDATE CASCADE INSERT INTO t1 VALUES ('old', 'somevalu'), ('other', 'anyvalue'); INSERT INTO t2 VALUES (10, 'old'), (20, 'other'); UPDATE t1 SET c1 = 'other' WHERE c1 = 'old'; -ERROR 23000: Upholding foreign key constraints for table 't1', entry '', key 2 would lead to a duplicate entry +ERROR 23000: Upholding foreign key constraints for table 't1', entry 'other-somevalu', key 2 would lead to a duplicate entry DROP TABLE t2,t1; create table t1( id int primary key, From 5cd2cb0c4f6f63d44f9d130d4f2e1f11b5d4064e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 26 Oct 2011 09:38:28 +0300 Subject: [PATCH 048/288] Copy and adapt innodb_misc1.test from innodb to innodb_plugin. --- .../suite/innodb_plugin/r/innodb_misc1.result | 882 ++++++++++++ .../innodb_plugin/t/innodb_misc1-master.opt | 1 + .../suite/innodb_plugin/t/innodb_misc1.test | 1178 +++++++++++++++++ 3 files changed, 2061 insertions(+) create mode 100644 mysql-test/suite/innodb_plugin/r/innodb_misc1.result create mode 100644 mysql-test/suite/innodb_plugin/t/innodb_misc1-master.opt create mode 100644 mysql-test/suite/innodb_plugin/t/innodb_misc1.test diff --git a/mysql-test/suite/innodb_plugin/r/innodb_misc1.result b/mysql-test/suite/innodb_plugin/r/innodb_misc1.result new file mode 100644 index 00000000000..5b1774c6e99 --- /dev/null +++ b/mysql-test/suite/innodb_plugin/r/innodb_misc1.result @@ -0,0 +1,882 @@ +drop table if exists t1,t2,t3,t4; +drop database if exists mysqltest; +create table t1 (v varchar(16384)) engine=innodb; +drop table t1; +create table t1 (a char(1), b char(1), key(a, b)) engine=innodb; +insert into t1 values ('8', '6'), ('4', '7'); +select min(a) from t1; +min(a) +4 +select min(b) from t1 where a='8'; +min(b) +6 +drop table t1; +CREATE TABLE t1 ( `a` int(11) NOT NULL auto_increment, `b` int(11) default NULL,PRIMARY KEY (`a`),UNIQUE KEY `b` (`b`)) ENGINE=innodb; +insert into t1 (b) values (1); +replace into t1 (b) values (2), (1), (3); +select * from t1; +a b +3 1 +2 2 +4 3 +truncate table t1; +insert into t1 (b) values (1); +replace into t1 (b) values (2); +replace into t1 (b) values (1); +replace into t1 (b) values (3); +select * from t1; +a b +3 1 +2 2 +4 3 +drop table t1; +create table t1 (rowid int not null auto_increment, val int not null,primary +key (rowid), unique(val)) engine=innodb; +replace into t1 (val) values ('1'),('2'); +replace into t1 (val) values ('1'),('2'); +insert into t1 (val) values ('1'),('2'); +ERROR 23000: Duplicate entry '1' for key 'val' +select * from t1; +rowid val +3 1 +4 2 +drop table t1; +create table t1 (a int not null auto_increment primary key, val int) engine=InnoDB; +insert into t1 (val) values (1); +update t1 set a=2 where a=1; +insert into t1 (val) values (1); +ERROR 23000: Duplicate entry '2' for key 'PRIMARY' +select * from t1; +a val +2 1 +drop table t1; +CREATE TABLE t1 (GRADE DECIMAL(4) NOT NULL, PRIMARY KEY (GRADE)) ENGINE=INNODB; +INSERT INTO t1 (GRADE) VALUES (151),(252),(343); +SELECT GRADE FROM t1 WHERE GRADE > 160 AND GRADE < 300; +GRADE +252 +SELECT GRADE FROM t1 WHERE GRADE= 151; +GRADE +151 +DROP TABLE t1; +create table t1 (f1 varchar(10), f2 varchar(10), primary key (f1,f2)) engine=innodb; +create table t2 (f3 varchar(10), f4 varchar(10), key (f4)) engine=innodb; +insert into t2 values ('aa','cc'); +insert into t1 values ('aa','bb'),('aa','cc'); +delete t1 from t1,t2 where f1=f3 and f4='cc'; +select * from t1; +f1 f2 +drop table t1,t2; +CREATE TABLE t1 ( +id INTEGER NOT NULL AUTO_INCREMENT, PRIMARY KEY (id) +) ENGINE=InnoDB; +CREATE TABLE t2 ( +id INTEGER NOT NULL, +FOREIGN KEY (id) REFERENCES t1 (id) +) ENGINE=InnoDB; +INSERT INTO t1 (id) VALUES (NULL); +SELECT * FROM t1; +id +1 +TRUNCATE t1; +INSERT INTO t1 (id) VALUES (NULL); +SELECT * FROM t1; +id +1 +DELETE FROM t1; +TRUNCATE t1; +INSERT INTO t1 (id) VALUES (NULL); +SELECT * FROM t1; +id +1 +DROP TABLE t2, t1; +CREATE TABLE t1 +( +id INT PRIMARY KEY +) ENGINE=InnoDB; +CREATE TEMPORARY TABLE t2 +( +id INT NOT NULL PRIMARY KEY, +b INT, +FOREIGN KEY (b) REFERENCES test.t1(id) +) ENGINE=InnoDB; +Got one of the listed errors +DROP TABLE t1; +create table t1 (col1 varchar(2000), index (col1(767))) +character set = latin1 engine = innodb; +create table t2 (col1 char(255), index (col1)) +character set = latin1 engine = innodb; +create table t3 (col1 binary(255), index (col1)) +character set = latin1 engine = innodb; +create table t4 (col1 varchar(767), index (col1)) +character set = latin1 engine = innodb; +create table t5 (col1 varchar(767) primary key) +character set = latin1 engine = innodb; +create table t6 (col1 varbinary(767) primary key) +character set = latin1 engine = innodb; +create table t7 (col1 text, index(col1(767))) +character set = latin1 engine = innodb; +create table t8 (col1 blob, index(col1(767))) +character set = latin1 engine = innodb; +create table t9 (col1 varchar(512), col2 varchar(512), index(col1, col2)) +character set = latin1 engine = innodb; +show create table t9; +Table Create Table +t9 CREATE TABLE `t9` ( + `col1` varchar(512) DEFAULT NULL, + `col2` varchar(512) DEFAULT NULL, + KEY `col1` (`col1`,`col2`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +drop table t1, t2, t3, t4, t5, t6, t7, t8, t9; +create table t1 (col1 varchar(768), index(col1)) +character set = latin1 engine = innodb; +Warnings: +Warning 1071 Specified key was too long; max key length is 767 bytes +create table t2 (col1 varbinary(768), index(col1)) +character set = latin1 engine = innodb; +Warnings: +Warning 1071 Specified key was too long; max key length is 767 bytes +create table t3 (col1 text, index(col1(768))) +character set = latin1 engine = innodb; +Warnings: +Warning 1071 Specified key was too long; max key length is 767 bytes +create table t4 (col1 blob, index(col1(768))) +character set = latin1 engine = innodb; +Warnings: +Warning 1071 Specified key was too long; max key length is 767 bytes +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `col1` varchar(768) DEFAULT NULL, + KEY `col1` (`col1`(767)) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +drop table t1, t2, t3, t4; +create table t1 (col1 varchar(768) primary key) +character set = latin1 engine = innodb; +ERROR 42000: Specified key was too long; max key length is 767 bytes +create table t2 (col1 varbinary(768) primary key) +character set = latin1 engine = innodb; +ERROR 42000: Specified key was too long; max key length is 767 bytes +create table t3 (col1 text, primary key(col1(768))) +character set = latin1 engine = innodb; +ERROR 42000: Specified key was too long; max key length is 767 bytes +create table t4 (col1 blob, primary key(col1(768))) +character set = latin1 engine = innodb; +ERROR 42000: Specified key was too long; max key length is 767 bytes +CREATE TABLE t1 +( +id INT PRIMARY KEY +) ENGINE=InnoDB; +CREATE TABLE t2 +( +v INT, +CONSTRAINT c1 FOREIGN KEY (v) REFERENCES t1(id) +) ENGINE=InnoDB; +INSERT INTO t2 VALUES(2); +ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `c1` FOREIGN KEY (`v`) REFERENCES `t1` (`id`)) +INSERT INTO t1 VALUES(1); +INSERT INTO t2 VALUES(1); +DELETE FROM t1 WHERE id = 1; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `c1` FOREIGN KEY (`v`) REFERENCES `t1` (`id`)) +DROP TABLE t1; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails +SET FOREIGN_KEY_CHECKS=0; +DROP TABLE t1; +SET FOREIGN_KEY_CHECKS=1; +INSERT INTO t2 VALUES(3); +ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `c1` FOREIGN KEY (`v`) REFERENCES `t1` (`id`)) +DROP TABLE t2; +create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1; +insert into t1 values (1),(2); +set autocommit=0; +checksum table t1; +Table Checksum +test.t1 1531596814 +insert into t1 values(3); +checksum table t1; +Table Checksum +test.t1 1531596814 +commit; +checksum table t1; +Table Checksum +test.t1 2050879373 +commit; +drop table t1; +create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1; +insert into t1 values (1),(2); +set autocommit=1; +checksum table t1; +Table Checksum +test.t1 1531596814 +set autocommit=1; +insert into t1 values(3); +checksum table t1; +Table Checksum +test.t1 2050879373 +drop table t1; +set foreign_key_checks=0; +create table t2 (a int primary key, b int, foreign key (b) references t1(a)) engine = innodb; +create table t1(a char(10) primary key, b varchar(20)) engine = innodb; +ERROR HY000: Can't create table 'test.t1' (errno: 150) +set foreign_key_checks=1; +drop table t2; +set foreign_key_checks=0; +create table t1(a varchar(10) primary key) engine = innodb DEFAULT CHARSET=latin1; +create table t2 (a varchar(10), foreign key (a) references t1(a)) engine = innodb DEFAULT CHARSET=utf8; +ERROR HY000: Can't create table 'test.t2' (errno: 150) +set foreign_key_checks=1; +drop table t1; +set foreign_key_checks=0; +create table t2 (a varchar(10), foreign key (a) references t1(a)) engine = innodb; +create table t1(a varchar(10) primary key) engine = innodb; +alter table t1 modify column a int; +Got one of the listed errors +set foreign_key_checks=1; +drop table t2,t1; +set foreign_key_checks=0; +create table t2 (a varchar(10), foreign key (a) references t1(a)) engine = innodb DEFAULT CHARSET=latin1; +create table t1(a varchar(10) primary key) engine = innodb DEFAULT CHARSET=latin1; +alter table t1 convert to character set utf8; +set foreign_key_checks=1; +drop table t2,t1; +set foreign_key_checks=0; +create table t2 (a varchar(10), foreign key (a) references t1(a)) engine = innodb DEFAULT CHARSET=latin1; +create table t3(a varchar(10) primary key) engine = innodb DEFAULT CHARSET=utf8; +rename table t3 to t1; +ERROR HY000: Error on rename of './test/t3' to './test/t1' (errno: 150) +set foreign_key_checks=1; +drop table t2,t3; +create table t1(a int primary key) row_format=redundant engine=innodb; +create table t2(a int primary key,constraint foreign key(a)references t1(a)) row_format=compact engine=innodb; +create table t3(a int primary key) row_format=compact engine=innodb; +create table t4(a int primary key,constraint foreign key(a)references t3(a)) row_format=redundant engine=innodb; +insert into t1 values(1); +insert into t3 values(1); +insert into t2 values(2); +ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`)) +insert into t4 values(2); +ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t4`, CONSTRAINT `t4_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t3` (`a`)) +insert into t2 values(1); +insert into t4 values(1); +update t1 set a=2; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`)) +update t2 set a=2; +ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`)) +update t3 set a=2; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t4`, CONSTRAINT `t4_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t3` (`a`)) +update t4 set a=2; +ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t4`, CONSTRAINT `t4_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t3` (`a`)) +truncate t1; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`)) +truncate t3; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t4`, CONSTRAINT `t4_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t3` (`a`)) +truncate t2; +truncate t4; +truncate t1; +truncate t3; +drop table t4,t3,t2,t1; +create table t1 (a varchar(255) character set utf8, +b varchar(255) character set utf8, +c varchar(255) character set utf8, +d varchar(255) character set utf8, +key (a,b,c,d)) engine=innodb; +drop table t1; +create table t1 (a varchar(255) character set utf8, +b varchar(255) character set utf8, +c varchar(255) character set utf8, +d varchar(255) character set utf8, +e varchar(255) character set utf8, +key (a,b,c,d,e)) engine=innodb; +ERROR 42000: Specified key was too long; max key length is 3072 bytes +create table t1 (s1 varbinary(2),primary key (s1)) engine=innodb; +create table t2 (s1 binary(2),primary key (s1)) engine=innodb; +create table t3 (s1 varchar(2) binary,primary key (s1)) engine=innodb; +create table t4 (s1 char(2) binary,primary key (s1)) engine=innodb; +insert into t1 values (0x41),(0x4120),(0x4100); +insert into t2 values (0x41),(0x4120),(0x4100); +ERROR 23000: Duplicate entry 'A' for key 'PRIMARY' +insert into t2 values (0x41),(0x4120); +insert into t3 values (0x41),(0x4120),(0x4100); +ERROR 23000: Duplicate entry 'A ' for key 'PRIMARY' +insert into t3 values (0x41),(0x4100); +insert into t4 values (0x41),(0x4120),(0x4100); +ERROR 23000: Duplicate entry 'A' for key 'PRIMARY' +insert into t4 values (0x41),(0x4100); +select hex(s1) from t1; +hex(s1) +41 +4100 +4120 +select hex(s1) from t2; +hex(s1) +4100 +4120 +select hex(s1) from t3; +hex(s1) +4100 +41 +select hex(s1) from t4; +hex(s1) +4100 +41 +drop table t1,t2,t3,t4; +create table t1 (a int primary key,s1 varbinary(3) not null unique) engine=innodb; +create table t2 (s1 binary(2) not null, constraint c foreign key(s1) references t1(s1) on update cascade) engine=innodb; +insert into t1 values(1,0x4100),(2,0x41),(3,0x4120),(4,0x42); +insert into t2 values(0x42); +ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE) +insert into t2 values(0x41); +select hex(s1) from t2; +hex(s1) +4100 +update t1 set s1=0x123456 where a=2; +select hex(s1) from t2; +hex(s1) +4100 +update t1 set s1=0x12 where a=1; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE) +update t1 set s1=0x12345678 where a=1; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE) +update t1 set s1=0x123457 where a=1; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE) +update t1 set s1=0x1220 where a=1; +select hex(s1) from t2; +hex(s1) +1220 +update t1 set s1=0x1200 where a=1; +select hex(s1) from t2; +hex(s1) +1200 +update t1 set s1=0x4200 where a=1; +select hex(s1) from t2; +hex(s1) +4200 +delete from t1 where a=1; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE) +delete from t1 where a=2; +update t2 set s1=0x4120; +delete from t1; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE) +delete from t1 where a!=3; +select a,hex(s1) from t1; +a hex(s1) +3 4120 +select hex(s1) from t2; +hex(s1) +4120 +drop table t2,t1; +create table t1 (a int primary key,s1 varchar(2) binary not null unique) engine=innodb; +create table t2 (s1 char(2) binary not null, constraint c foreign key(s1) references t1(s1) on update cascade) engine=innodb; +insert into t1 values(1,0x4100),(2,0x41); +insert into t2 values(0x41); +select hex(s1) from t2; +hex(s1) +41 +update t1 set s1=0x1234 where a=1; +select hex(s1) from t2; +hex(s1) +41 +update t1 set s1=0x12 where a=2; +select hex(s1) from t2; +hex(s1) +12 +delete from t1 where a=1; +delete from t1 where a=2; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE) +select a,hex(s1) from t1; +a hex(s1) +2 12 +select hex(s1) from t2; +hex(s1) +12 +drop table t2,t1; +CREATE TABLE t1(a INT, PRIMARY KEY(a)) ENGINE=InnoDB; +CREATE TABLE t2(a INT) ENGINE=InnoDB; +ALTER TABLE t2 ADD FOREIGN KEY (a) REFERENCES t1(a); +ALTER TABLE t2 DROP FOREIGN KEY t2_ibfk_1; +ALTER TABLE t2 ADD CONSTRAINT t2_ibfk_0 FOREIGN KEY (a) REFERENCES t1(a); +ALTER TABLE t2 DROP FOREIGN KEY t2_ibfk_0; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` int(11) DEFAULT NULL, + KEY `t2_ibfk_0` (`a`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +DROP TABLE t2,t1; +create table t1(a int not null, b int, c int, d int, primary key(a)) engine=innodb; +insert into t1(a) values (1),(2),(3); +commit; +set autocommit = 0; +update t1 set b = 5 where a = 2; +create trigger t1t before insert on t1 for each row begin set NEW.b = NEW.a * 10 + 5, NEW.c = NEW.a / 10; end | +set autocommit = 0; +insert into t1(a) values (10),(20),(30),(40),(50),(60),(70),(80),(90),(100), +(11),(21),(31),(41),(51),(61),(71),(81),(91),(101), +(12),(22),(32),(42),(52),(62),(72),(82),(92),(102), +(13),(23),(33),(43),(53),(63),(73),(83),(93),(103), +(14),(24),(34),(44),(54),(64),(74),(84),(94),(104); +commit; +commit; +drop trigger t1t; +drop table t1; +create table t1(a int not null, b int, c int, d int, primary key(a)) engine=innodb; +create table t2(a int not null, b int, c int, d int, primary key(a)) engine=innodb; +create table t3(a int not null, b int, c int, d int, primary key(a)) engine=innodb; +create table t4(a int not null, b int, c int, d int, primary key(a)) engine=innodb; +create table t5(a int not null, b int, c int, d int, primary key(a)) engine=innodb; +insert into t1(a) values (1),(2),(3); +insert into t2(a) values (1),(2),(3); +insert into t3(a) values (1),(2),(3); +insert into t4(a) values (1),(2),(3); +insert into t3(a) values (5),(7),(8); +insert into t4(a) values (5),(7),(8); +insert into t5(a) values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12); +create trigger t1t before insert on t1 for each row begin +INSERT INTO t2 SET a = NEW.a; +end | +create trigger t2t before insert on t2 for each row begin +DELETE FROM t3 WHERE a = NEW.a; +end | +create trigger t3t before delete on t3 for each row begin +UPDATE t4 SET b = b + 1 WHERE a = OLD.a; +end | +create trigger t4t before update on t4 for each row begin +UPDATE t5 SET b = b + 1 where a = NEW.a; +end | +commit; +set autocommit = 0; +update t1 set b = b + 5 where a = 1; +update t2 set b = b + 5 where a = 1; +update t3 set b = b + 5 where a = 1; +update t4 set b = b + 5 where a = 1; +insert into t5(a) values(20); +set autocommit = 0; +insert into t1(a) values(7); +insert into t2(a) values(8); +delete from t2 where a = 3; +update t4 set b = b + 1 where a = 3; +commit; +drop trigger t1t; +drop trigger t2t; +drop trigger t3t; +drop trigger t4t; +drop table t1, t2, t3, t4, t5; +CREATE TABLE t1 ( +field1 varchar(8) NOT NULL DEFAULT '', +field2 varchar(8) NOT NULL DEFAULT '', +PRIMARY KEY (field1, field2) +) ENGINE=InnoDB; +CREATE TABLE t2 ( +field1 varchar(8) NOT NULL DEFAULT '' PRIMARY KEY, +FOREIGN KEY (field1) REFERENCES t1 (field1) +ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB; +INSERT INTO t1 VALUES ('old', 'somevalu'); +INSERT INTO t1 VALUES ('other', 'anyvalue'); +INSERT INTO t2 VALUES ('old'); +INSERT INTO t2 VALUES ('other'); +UPDATE t1 SET field1 = 'other' WHERE field2 = 'somevalu'; +ERROR 23000: Upholding foreign key constraints for table 't1', entry 'other-somevalu', key 1 would lead to a duplicate entry +DROP TABLE t2; +DROP TABLE t1; +create table t1 ( +c1 bigint not null, +c2 bigint not null, +primary key (c1), +unique key (c2) +) engine=innodb; +create table t2 ( +c1 bigint not null, +primary key (c1) +) engine=innodb; +alter table t1 add constraint c2_fk foreign key (c2) +references t2(c1) on delete cascade; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` bigint(20) NOT NULL, + `c2` bigint(20) NOT NULL, + PRIMARY KEY (`c1`), + UNIQUE KEY `c2` (`c2`), + CONSTRAINT `c2_fk` FOREIGN KEY (`c2`) REFERENCES `t2` (`c1`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +alter table t1 drop foreign key c2_fk; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` bigint(20) NOT NULL, + `c2` bigint(20) NOT NULL, + PRIMARY KEY (`c1`), + UNIQUE KEY `c2` (`c2`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +drop table t1, t2; +create table t1(a date) engine=innodb; +create table t2(a date, key(a)) engine=innodb; +insert into t1 values('2005-10-01'); +insert into t2 values('2005-10-01'); +select * from t1, t2 +where t2.a between t1.a - interval 2 day and t1.a + interval 2 day; +a a +2005-10-01 2005-10-01 +drop table t1, t2; +create table t1 (id int not null, f_id int not null, f int not null, +primary key(f_id, id)) engine=innodb; +create table t2 (id int not null,s_id int not null,s varchar(200), +primary key(id)) engine=innodb; +INSERT INTO t1 VALUES (8, 1, 3); +INSERT INTO t1 VALUES (1, 2, 1); +INSERT INTO t2 VALUES (1, 0, ''); +INSERT INTO t2 VALUES (8, 1, ''); +commit; +DELETE ml.* FROM t1 AS ml LEFT JOIN t2 AS mm ON (mm.id=ml.id) +WHERE mm.id IS NULL; +select ml.* from t1 as ml left join t2 as mm on (mm.id=ml.id) +where mm.id is null lock in share mode; +id f_id f +drop table t1,t2; +create table t1(a int not null, b int, primary key(a)) engine=innodb; +insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2),(7,3); +commit; +SET binlog_format='MIXED'; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +update t1 set b = 5 where b = 1; +SET binlog_format='MIXED'; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +select * from t1 where a = 7 and b = 3 for update; +a b +7 3 +commit; +commit; +drop table t1; +create table t1(a int not null, b int, primary key(a)) engine=innodb; +insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2); +commit; +set autocommit = 0; +select * from t1 lock in share mode; +a b +1 1 +2 2 +3 1 +4 2 +5 1 +6 2 +update t1 set b = 5 where b = 1; +set autocommit = 0; +select * from t1 where a = 2 and b = 2 for update; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +commit; +commit; +drop table t1; +create table t1(a int not null, b int, primary key(a)) engine=innodb; +insert into t1 values (1,2),(5,3),(4,2); +create table t2(d int not null, e int, primary key(d)) engine=innodb; +insert into t2 values (8,6),(12,1),(3,1); +commit; +set autocommit = 0; +select * from t2 for update; +d e +3 1 +8 6 +12 1 +SET binlog_format='MIXED'; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +insert into t1 select * from t2; +update t1 set b = (select e from t2 where a = d); +create table t3(d int not null, e int, primary key(d)) engine=innodb +select * from t2; +commit; +commit; +drop table t1, t2, t3; +create table t1(a int not null, b int, primary key(a)) engine=innodb; +insert into t1 values (1,2),(5,3),(4,2); +create table t2(a int not null, b int, primary key(a)) engine=innodb; +insert into t2 values (8,6),(12,1),(3,1); +create table t3(d int not null, b int, primary key(d)) engine=innodb; +insert into t3 values (8,6),(12,1),(3,1); +create table t5(a int not null, b int, primary key(a)) engine=innodb; +insert into t5 values (1,2),(5,3),(4,2); +create table t6(d int not null, e int, primary key(d)) engine=innodb; +insert into t6 values (8,6),(12,1),(3,1); +create table t8(a int not null, b int, primary key(a)) engine=innodb; +insert into t8 values (1,2),(5,3),(4,2); +create table t9(d int not null, e int, primary key(d)) engine=innodb; +insert into t9 values (8,6),(12,1),(3,1); +commit; +set autocommit = 0; +select * from t2 for update; +a b +3 1 +8 6 +12 1 +SET binlog_format='MIXED'; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; +insert into t1 select * from t2; +SET binlog_format='MIXED'; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; +update t3 set b = (select b from t2 where a = d); +SET binlog_format='MIXED'; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; +create table t4(a int not null, b int, primary key(a)) engine=innodb select * from t2; +SET binlog_format='MIXED'; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +insert into t5 (select * from t2 lock in share mode); +SET binlog_format='MIXED'; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +update t6 set e = (select b from t2 where a = d lock in share mode); +SET binlog_format='MIXED'; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +create table t7(a int not null, b int, primary key(a)) engine=innodb select * from t2 lock in share mode; +SET binlog_format='MIXED'; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +insert into t8 (select * from t2 for update); +SET binlog_format='MIXED'; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +update t9 set e = (select b from t2 where a = d for update); +SET binlog_format='MIXED'; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +create table t10(a int not null, b int, primary key(a)) engine=innodb select * from t2 for update; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +commit; +drop table t1, t2, t3, t5, t6, t8, t9; +CREATE TABLE t1 (DB_ROW_ID int) engine=innodb; +ERROR 42000: Incorrect column name 'DB_ROW_ID' +CREATE TABLE t1 ( +a BIGINT(20) NOT NULL, +PRIMARY KEY (a) +) ENGINE=INNODB DEFAULT CHARSET=UTF8; +CREATE TABLE t2 ( +a BIGINT(20) NOT NULL, +b VARCHAR(128) NOT NULL, +c TEXT NOT NULL, +PRIMARY KEY (a,b), +KEY idx_t2_b_c (b,c(200)), +CONSTRAINT t_fk FOREIGN KEY (a) REFERENCES t1 (a) +ON DELETE CASCADE +) ENGINE=INNODB DEFAULT CHARSET=UTF8; +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (1, 'bar', 'vbar'); +INSERT INTO t2 VALUES (1, 'BAR2', 'VBAR'); +INSERT INTO t2 VALUES (1, 'bar_bar', 'bibi'); +INSERT INTO t2 VALUES (1, 'customer_over', '1'); +SELECT * FROM t2 WHERE b = 'customer_over'; +a b c +1 customer_over 1 +SELECT * FROM t2 WHERE BINARY b = 'customer_over'; +a b c +1 customer_over 1 +SELECT DISTINCT p0.a FROM t2 p0 WHERE p0.b = 'customer_over'; +a +1 +/* Bang: Empty result set, above was expected: */ +SELECT DISTINCT p0.a FROM t2 p0 WHERE BINARY p0.b = 'customer_over'; +a +1 +SELECT p0.a FROM t2 p0 WHERE BINARY p0.b = 'customer_over'; +a +1 +drop table t2, t1; +CREATE TABLE t1 ( a int ) ENGINE=innodb; +BEGIN; +INSERT INTO t1 VALUES (1); +OPTIMIZE TABLE t1; +Table Op Msg_type Msg_text +test.t1 optimize note Table does not support optimize, doing recreate + analyze instead +test.t1 optimize status OK +DROP TABLE t1; +CREATE TABLE t1 (id int PRIMARY KEY, f int NOT NULL, INDEX(f)) ENGINE=InnoDB; +CREATE TABLE t2 (id int PRIMARY KEY, f INT NOT NULL, +CONSTRAINT t2_t1 FOREIGN KEY (id) REFERENCES t1 (id) +ON DELETE CASCADE ON UPDATE CASCADE) ENGINE=InnoDB; +ALTER TABLE t2 ADD FOREIGN KEY (f) REFERENCES t1 (f) ON +DELETE CASCADE ON UPDATE CASCADE; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `id` int(11) NOT NULL, + `f` int(11) NOT NULL, + PRIMARY KEY (`id`), + KEY `f` (`f`), + CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`f`) REFERENCES `t1` (`f`) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT `t2_t1` FOREIGN KEY (`id`) REFERENCES `t1` (`id`) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +DROP TABLE t2, t1; +CREATE TABLE t1 (a INT, INDEX(a)) ENGINE=InnoDB; +CREATE TABLE t2 (a INT, INDEX(a)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (1); +ALTER TABLE t2 ADD FOREIGN KEY (a) REFERENCES t1 (a) ON DELETE SET NULL; +ALTER TABLE t2 MODIFY a INT NOT NULL; +ERROR HY000: Error on rename of '#sql-temporary' to './test/t2' (errno: 150) +DELETE FROM t1; +DROP TABLE t2,t1; +CREATE TABLE t1 (a VARCHAR(5) COLLATE utf8_unicode_ci PRIMARY KEY) +ENGINE=InnoDB; +INSERT INTO t1 VALUES (0xEFBCA4EFBCA4EFBCA4); +DELETE FROM t1; +INSERT INTO t1 VALUES ('DDD'); +SELECT * FROM t1; +a +DDD +DROP TABLE t1; +CREATE TABLE t1 (id int PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB +AUTO_INCREMENT=42; +INSERT INTO t1 VALUES (0),(347),(0); +SELECT * FROM t1; +id +42 +347 +348 +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=349 DEFAULT CHARSET=latin1 +CREATE TABLE t2 (id int PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t2 VALUES(42),(347),(348); +ALTER TABLE t1 ADD CONSTRAINT t1_t2 FOREIGN KEY (id) REFERENCES t2(id); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`id`), + CONSTRAINT `t1_t2` FOREIGN KEY (`id`) REFERENCES `t2` (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=349 DEFAULT CHARSET=latin1 +DROP TABLE t1,t2; +SET innodb_strict_mode=ON; +CREATE TABLE t1 ( +c01 CHAR(255), c02 CHAR(255), c03 CHAR(255), c04 CHAR(255), +c05 CHAR(255), c06 CHAR(255), c07 CHAR(255), c08 CHAR(255), +c09 CHAR(255), c10 CHAR(255), c11 CHAR(255), c12 CHAR(255), +c13 CHAR(255), c14 CHAR(255), c15 CHAR(255), c16 CHAR(255), +c17 CHAR(255), c18 CHAR(255), c19 CHAR(255), c20 CHAR(255), +c21 CHAR(255), c22 CHAR(255), c23 CHAR(255), c24 CHAR(255), +c25 CHAR(255), c26 CHAR(255), c27 CHAR(255), c28 CHAR(255), +c29 CHAR(255), c30 CHAR(255), c31 CHAR(255), c32 CHAR(255) +) ENGINE = InnoDB; +ERROR 42000: Row size too large. The maximum row size for the used table type, not counting BLOBs, is 8126. You have to change some columns to TEXT or BLOBs +SET innodb_strict_mode=OFF; +DROP TABLE IF EXISTS t1; +Warnings: +Note 1051 Unknown table 't1' +CREATE TABLE t1( +id BIGINT(20) NOT NULL AUTO_INCREMENT PRIMARY KEY +) ENGINE=InnoDB; +INSERT INTO t1 VALUES(-10); +SELECT * FROM t1; +id +-10 +INSERT INTO t1 VALUES(NULL); +SELECT * FROM t1; +id +-10 +1 +DROP TABLE t1; +SET binlog_format='MIXED'; +SET TX_ISOLATION='read-committed'; +SET AUTOCOMMIT=0; +DROP TABLE IF EXISTS t1, t2; +Warnings: +Note 1051 Unknown table 't1' +Note 1051 Unknown table 't2' +CREATE TABLE t1 ( a int ) ENGINE=InnoDB; +CREATE TABLE t2 LIKE t1; +SELECT * FROM t2; +a +SET binlog_format='MIXED'; +SET TX_ISOLATION='read-committed'; +SET AUTOCOMMIT=0; +INSERT INTO t1 VALUES (1); +COMMIT; +SELECT * FROM t1 WHERE a=1; +a +1 +SET binlog_format='MIXED'; +SET TX_ISOLATION='read-committed'; +SET AUTOCOMMIT=0; +SELECT * FROM t2; +a +SET binlog_format='MIXED'; +SET TX_ISOLATION='read-committed'; +SET AUTOCOMMIT=0; +INSERT INTO t1 VALUES (2); +COMMIT; +SELECT * FROM t1 WHERE a=2; +a +2 +SELECT * FROM t1 WHERE a=2; +a +2 +DROP TABLE t1; +DROP TABLE t2; +create table t1 (i int, j int) engine=innodb; +insert into t1 (i, j) values (1, 1), (2, 2); +update t1 set j = 2; +affected rows: 1 +info: Rows matched: 2 Changed: 1 Warnings: 0 +drop table t1; +create table t1 (id int) comment='this is a comment' engine=innodb; +select table_comment, data_free > 0 as data_free_is_set +from information_schema.tables +where table_schema='test' and table_name = 't1'; +table_comment data_free_is_set +this is a comment 1 +drop table t1; +CREATE TABLE t1 ( +c1 INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, +c2 VARCHAR(128) NOT NULL, +PRIMARY KEY(c1) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=100; +CREATE TABLE t2 ( +c1 INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, +c2 INT(10) UNSIGNED DEFAULT NULL, +PRIMARY KEY(c1) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=200; +SELECT AUTO_INCREMENT FROM INFORMATION_SCHEMA.TABLES WHERE table_name = 't2'; +AUTO_INCREMENT +200 +ALTER TABLE t2 ADD CONSTRAINT t1_t2_1 FOREIGN KEY(c1) REFERENCES t1(c1); +SELECT AUTO_INCREMENT FROM INFORMATION_SCHEMA.TABLES WHERE table_name = 't2'; +AUTO_INCREMENT +200 +DROP TABLE t2; +DROP TABLE t1; +CREATE TABLE t1 (c1 int default NULL, +c2 int default NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +TRUNCATE TABLE t1; +affected rows: 0 +INSERT INTO t1 VALUES (1, 1), (2, 2), (3, 3), (4, 4), (5, 5); +affected rows: 5 +info: Records: 5 Duplicates: 0 Warnings: 0 +TRUNCATE TABLE t1; +affected rows: 0 +DROP TABLE t1; +Variable_name Value +Handler_update 0 +Variable_name Value +Handler_delete 0 +Variable_name Value +Handler_update 1 +Variable_name Value +Handler_delete 1 diff --git a/mysql-test/suite/innodb_plugin/t/innodb_misc1-master.opt b/mysql-test/suite/innodb_plugin/t/innodb_misc1-master.opt new file mode 100644 index 00000000000..4901efb416c --- /dev/null +++ b/mysql-test/suite/innodb_plugin/t/innodb_misc1-master.opt @@ -0,0 +1 @@ +--binlog_cache_size=32768 --innodb_lock_wait_timeout=1 diff --git a/mysql-test/suite/innodb_plugin/t/innodb_misc1.test b/mysql-test/suite/innodb_plugin/t/innodb_misc1.test new file mode 100644 index 00000000000..e9b6d72aa7d --- /dev/null +++ b/mysql-test/suite/innodb_plugin/t/innodb_misc1.test @@ -0,0 +1,1178 @@ +-- source include/have_innodb_plugin.inc + +let $MYSQLD_DATADIR= `select @@datadir`; + +# Save the original values of some variables in order to be able to +# estimate how much they have changed during the tests. Previously this +# test assumed that e.g. rows_deleted is 0 here and after deleting 23 +# rows it expected that rows_deleted will be 23. Now we do not make +# assumptions about the values of the variables at the beginning, e.g. +# rows_deleted should be 23 + "rows_deleted before the test". This allows +# the test to be run multiple times without restarting the mysqld server. +# See Bug#43309 Test main.innodb can't be run twice +-- disable_query_log +SET @innodb_thread_concurrency_orig = @@innodb_thread_concurrency; +-- enable_query_log + +--disable_warnings +drop table if exists t1,t2,t3,t4; +drop database if exists mysqltest; +--enable_warnings + +# InnoDB specific varchar tests +create table t1 (v varchar(16384)) engine=innodb; +drop table t1; + +# +# BUG#11039 Wrong key length in min() +# + +create table t1 (a char(1), b char(1), key(a, b)) engine=innodb; +insert into t1 values ('8', '6'), ('4', '7'); +select min(a) from t1; +select min(b) from t1 where a='8'; +drop table t1; + +# +# Bug #11080 & #11005 Multi-row REPLACE fails on a duplicate key error +# + +CREATE TABLE t1 ( `a` int(11) NOT NULL auto_increment, `b` int(11) default NULL,PRIMARY KEY (`a`),UNIQUE KEY `b` (`b`)) ENGINE=innodb; +insert into t1 (b) values (1); +replace into t1 (b) values (2), (1), (3); +select * from t1; +truncate table t1; +insert into t1 (b) values (1); +replace into t1 (b) values (2); +replace into t1 (b) values (1); +replace into t1 (b) values (3); +select * from t1; +drop table t1; + +create table t1 (rowid int not null auto_increment, val int not null,primary +key (rowid), unique(val)) engine=innodb; +replace into t1 (val) values ('1'),('2'); +replace into t1 (val) values ('1'),('2'); +--error ER_DUP_ENTRY +insert into t1 (val) values ('1'),('2'); +select * from t1; +drop table t1; + +# +# Test that update does not change internal auto-increment value +# + +create table t1 (a int not null auto_increment primary key, val int) engine=InnoDB; +insert into t1 (val) values (1); +update t1 set a=2 where a=1; +# We should get the following error because InnoDB does not update the counter +--error ER_DUP_ENTRY +insert into t1 (val) values (1); +select * from t1; +drop table t1; +# +# Bug #10465 +# + +--disable_warnings +CREATE TABLE t1 (GRADE DECIMAL(4) NOT NULL, PRIMARY KEY (GRADE)) ENGINE=INNODB; +--enable_warnings +INSERT INTO t1 (GRADE) VALUES (151),(252),(343); +SELECT GRADE FROM t1 WHERE GRADE > 160 AND GRADE < 300; +SELECT GRADE FROM t1 WHERE GRADE= 151; +DROP TABLE t1; + +# +# Bug #12340 multitable delete deletes only one record +# +create table t1 (f1 varchar(10), f2 varchar(10), primary key (f1,f2)) engine=innodb; +create table t2 (f3 varchar(10), f4 varchar(10), key (f4)) engine=innodb; +insert into t2 values ('aa','cc'); +insert into t1 values ('aa','bb'),('aa','cc'); +delete t1 from t1,t2 where f1=f3 and f4='cc'; +select * from t1; +drop table t1,t2; + +# +# Test that the slow TRUNCATE implementation resets autoincrement columns +# (bug #11946) +# + +CREATE TABLE t1 ( +id INTEGER NOT NULL AUTO_INCREMENT, PRIMARY KEY (id) +) ENGINE=InnoDB; + +CREATE TABLE t2 ( +id INTEGER NOT NULL, +FOREIGN KEY (id) REFERENCES t1 (id) +) ENGINE=InnoDB; + +INSERT INTO t1 (id) VALUES (NULL); +SELECT * FROM t1; +TRUNCATE t1; +INSERT INTO t1 (id) VALUES (NULL); +SELECT * FROM t1; + +# continued from above; test that doing a slow TRUNCATE on a table with 0 +# rows resets autoincrement columns +DELETE FROM t1; +TRUNCATE t1; +INSERT INTO t1 (id) VALUES (NULL); +SELECT * FROM t1; +DROP TABLE t2, t1; + +# Test that foreign keys in temporary tables are not accepted (bug #12084) +CREATE TABLE t1 +( + id INT PRIMARY KEY +) ENGINE=InnoDB; + +--error 1005,1005 +CREATE TEMPORARY TABLE t2 +( + id INT NOT NULL PRIMARY KEY, + b INT, + FOREIGN KEY (b) REFERENCES test.t1(id) +) ENGINE=InnoDB; +DROP TABLE t1; + +# +# Test that index column max sizes are honored (bug #13315) +# + +# prefix index +create table t1 (col1 varchar(2000), index (col1(767))) + character set = latin1 engine = innodb; + +# normal indexes +create table t2 (col1 char(255), index (col1)) + character set = latin1 engine = innodb; +create table t3 (col1 binary(255), index (col1)) + character set = latin1 engine = innodb; +create table t4 (col1 varchar(767), index (col1)) + character set = latin1 engine = innodb; +create table t5 (col1 varchar(767) primary key) + character set = latin1 engine = innodb; +create table t6 (col1 varbinary(767) primary key) + character set = latin1 engine = innodb; +create table t7 (col1 text, index(col1(767))) + character set = latin1 engine = innodb; +create table t8 (col1 blob, index(col1(767))) + character set = latin1 engine = innodb; + +# multi-column indexes are allowed to be longer +create table t9 (col1 varchar(512), col2 varchar(512), index(col1, col2)) + character set = latin1 engine = innodb; + +show create table t9; + +drop table t1, t2, t3, t4, t5, t6, t7, t8, t9; + +# these should have their index length trimmed +create table t1 (col1 varchar(768), index(col1)) + character set = latin1 engine = innodb; +create table t2 (col1 varbinary(768), index(col1)) + character set = latin1 engine = innodb; +create table t3 (col1 text, index(col1(768))) + character set = latin1 engine = innodb; +create table t4 (col1 blob, index(col1(768))) + character set = latin1 engine = innodb; + +show create table t1; + +drop table t1, t2, t3, t4; + +# these should be refused +--error 1071 +create table t1 (col1 varchar(768) primary key) + character set = latin1 engine = innodb; +--error 1071 +create table t2 (col1 varbinary(768) primary key) + character set = latin1 engine = innodb; +--error 1071 +create table t3 (col1 text, primary key(col1(768))) + character set = latin1 engine = innodb; +--error 1071 +create table t4 (col1 blob, primary key(col1(768))) + character set = latin1 engine = innodb; + +# +# Test improved foreign key error messages (bug #3443) +# + +CREATE TABLE t1 +( + id INT PRIMARY KEY +) ENGINE=InnoDB; + +CREATE TABLE t2 +( + v INT, + CONSTRAINT c1 FOREIGN KEY (v) REFERENCES t1(id) +) ENGINE=InnoDB; + +--error 1452 +INSERT INTO t2 VALUES(2); + +INSERT INTO t1 VALUES(1); +INSERT INTO t2 VALUES(1); + +--error 1451 +DELETE FROM t1 WHERE id = 1; + +--error 1217 +DROP TABLE t1; + +SET FOREIGN_KEY_CHECKS=0; +DROP TABLE t1; +SET FOREIGN_KEY_CHECKS=1; + +--error 1452 +INSERT INTO t2 VALUES(3); + +DROP TABLE t2; +# +# Test that checksum table uses a consistent read Bug #12669 +# +connect (a,localhost,root,,); +connect (b,localhost,root,,); +connection a; +create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1; +insert into t1 values (1),(2); +set autocommit=0; +checksum table t1; +connection b; +insert into t1 values(3); +connection a; +# +# Here checksum should not see insert +# +checksum table t1; +connection a; +commit; +checksum table t1; +commit; +drop table t1; +# +# autocommit = 1 +# +connection a; +create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1; +insert into t1 values (1),(2); +set autocommit=1; +checksum table t1; +connection b; +set autocommit=1; +insert into t1 values(3); +connection a; +# +# Here checksum sees insert +# +checksum table t1; +drop table t1; + +connection default; +disconnect a; +disconnect b; + +# tests for bugs #9802 and #13778 + +# test that FKs between invalid types are not accepted + +set foreign_key_checks=0; +create table t2 (a int primary key, b int, foreign key (b) references t1(a)) engine = innodb; +# Embedded server doesn't chdir to data directory +--replace_result $MYSQLTEST_VARDIR . mysqld.1/data/ '' +-- error 1005 +create table t1(a char(10) primary key, b varchar(20)) engine = innodb; +set foreign_key_checks=1; +drop table t2; + +# test that FKs between different charsets are not accepted in CREATE even +# when f_k_c is 0 + +set foreign_key_checks=0; +create table t1(a varchar(10) primary key) engine = innodb DEFAULT CHARSET=latin1; +# Embedded server doesn't chdir to data directory +--replace_result $MYSQLTEST_VARDIR . mysqld.1/data/ '' +-- error 1005 +create table t2 (a varchar(10), foreign key (a) references t1(a)) engine = innodb DEFAULT CHARSET=utf8; +set foreign_key_checks=1; +drop table t1; + +# test that invalid datatype conversions with ALTER are not allowed + +set foreign_key_checks=0; +create table t2 (a varchar(10), foreign key (a) references t1(a)) engine = innodb; +create table t1(a varchar(10) primary key) engine = innodb; +-- error 1025,1025 +alter table t1 modify column a int; +set foreign_key_checks=1; +drop table t2,t1; + +# test that charset conversions with ALTER are allowed when f_k_c is 0 + +set foreign_key_checks=0; +create table t2 (a varchar(10), foreign key (a) references t1(a)) engine = innodb DEFAULT CHARSET=latin1; +create table t1(a varchar(10) primary key) engine = innodb DEFAULT CHARSET=latin1; +alter table t1 convert to character set utf8; +set foreign_key_checks=1; +drop table t2,t1; + +# test that RENAME does not allow invalid charsets when f_k_c is 0 + +set foreign_key_checks=0; +create table t2 (a varchar(10), foreign key (a) references t1(a)) engine = innodb DEFAULT CHARSET=latin1; +create table t3(a varchar(10) primary key) engine = innodb DEFAULT CHARSET=utf8; +# Embedded server doesn't chdir to data directory +--replace_result $MYSQLD_DATADIR ./ master-data/ '' +-- error 1025 +rename table t3 to t1; +set foreign_key_checks=1; +drop table t2,t3; + +# test that foreign key errors are reported correctly (Bug #15550) + +create table t1(a int primary key) row_format=redundant engine=innodb; +create table t2(a int primary key,constraint foreign key(a)references t1(a)) row_format=compact engine=innodb; +create table t3(a int primary key) row_format=compact engine=innodb; +create table t4(a int primary key,constraint foreign key(a)references t3(a)) row_format=redundant engine=innodb; + +insert into t1 values(1); +insert into t3 values(1); +-- error 1452 +insert into t2 values(2); +-- error 1452 +insert into t4 values(2); +insert into t2 values(1); +insert into t4 values(1); +-- error 1451 +update t1 set a=2; +-- error 1452 +update t2 set a=2; +-- error 1451 +update t3 set a=2; +-- error 1452 +update t4 set a=2; +-- error 1451 +truncate t1; +-- error 1451 +truncate t3; +truncate t2; +truncate t4; +truncate t1; +truncate t3; + +drop table t4,t3,t2,t1; + + +# +# Test that we can create a large (>1K) key +# +create table t1 (a varchar(255) character set utf8, + b varchar(255) character set utf8, + c varchar(255) character set utf8, + d varchar(255) character set utf8, + key (a,b,c,d)) engine=innodb; +drop table t1; +--error ER_TOO_LONG_KEY +create table t1 (a varchar(255) character set utf8, + b varchar(255) character set utf8, + c varchar(255) character set utf8, + d varchar(255) character set utf8, + e varchar(255) character set utf8, + key (a,b,c,d,e)) engine=innodb; + + +# test the padding of BINARY types and collations (Bug #14189) + +create table t1 (s1 varbinary(2),primary key (s1)) engine=innodb; +create table t2 (s1 binary(2),primary key (s1)) engine=innodb; +create table t3 (s1 varchar(2) binary,primary key (s1)) engine=innodb; +create table t4 (s1 char(2) binary,primary key (s1)) engine=innodb; + +insert into t1 values (0x41),(0x4120),(0x4100); +-- error ER_DUP_ENTRY +insert into t2 values (0x41),(0x4120),(0x4100); +insert into t2 values (0x41),(0x4120); +-- error ER_DUP_ENTRY +insert into t3 values (0x41),(0x4120),(0x4100); +insert into t3 values (0x41),(0x4100); +-- error ER_DUP_ENTRY +insert into t4 values (0x41),(0x4120),(0x4100); +insert into t4 values (0x41),(0x4100); +select hex(s1) from t1; +select hex(s1) from t2; +select hex(s1) from t3; +select hex(s1) from t4; +drop table t1,t2,t3,t4; + +create table t1 (a int primary key,s1 varbinary(3) not null unique) engine=innodb; +create table t2 (s1 binary(2) not null, constraint c foreign key(s1) references t1(s1) on update cascade) engine=innodb; + +insert into t1 values(1,0x4100),(2,0x41),(3,0x4120),(4,0x42); +-- error 1452 +insert into t2 values(0x42); +insert into t2 values(0x41); +select hex(s1) from t2; +update t1 set s1=0x123456 where a=2; +select hex(s1) from t2; +-- error 1451 +update t1 set s1=0x12 where a=1; +-- error 1451 +update t1 set s1=0x12345678 where a=1; +-- error 1451 +update t1 set s1=0x123457 where a=1; +update t1 set s1=0x1220 where a=1; +select hex(s1) from t2; +update t1 set s1=0x1200 where a=1; +select hex(s1) from t2; +update t1 set s1=0x4200 where a=1; +select hex(s1) from t2; +-- error 1451 +delete from t1 where a=1; +delete from t1 where a=2; +update t2 set s1=0x4120; +-- error 1451 +delete from t1; +delete from t1 where a!=3; +select a,hex(s1) from t1; +select hex(s1) from t2; + +drop table t2,t1; + +create table t1 (a int primary key,s1 varchar(2) binary not null unique) engine=innodb; +create table t2 (s1 char(2) binary not null, constraint c foreign key(s1) references t1(s1) on update cascade) engine=innodb; + +insert into t1 values(1,0x4100),(2,0x41); +insert into t2 values(0x41); +select hex(s1) from t2; +update t1 set s1=0x1234 where a=1; +select hex(s1) from t2; +update t1 set s1=0x12 where a=2; +select hex(s1) from t2; +delete from t1 where a=1; +-- error 1451 +delete from t1 where a=2; +select a,hex(s1) from t1; +select hex(s1) from t2; + +drop table t2,t1; +# Ensure that _ibfk_0 is not mistreated as a +# generated foreign key identifier. (Bug #16387) + +CREATE TABLE t1(a INT, PRIMARY KEY(a)) ENGINE=InnoDB; +CREATE TABLE t2(a INT) ENGINE=InnoDB; +ALTER TABLE t2 ADD FOREIGN KEY (a) REFERENCES t1(a); +ALTER TABLE t2 DROP FOREIGN KEY t2_ibfk_1; +ALTER TABLE t2 ADD CONSTRAINT t2_ibfk_0 FOREIGN KEY (a) REFERENCES t1(a); +ALTER TABLE t2 DROP FOREIGN KEY t2_ibfk_0; +SHOW CREATE TABLE t2; +DROP TABLE t2,t1; + +# +# Test case for bug #16229: MySQL/InnoDB uses full explicit table locks in trigger processing +# + +connect (a,localhost,root,,); +connect (b,localhost,root,,); +connection a; +create table t1(a int not null, b int, c int, d int, primary key(a)) engine=innodb; +insert into t1(a) values (1),(2),(3); +commit; +connection b; +set autocommit = 0; +update t1 set b = 5 where a = 2; +connection a; +delimiter |; +create trigger t1t before insert on t1 for each row begin set NEW.b = NEW.a * 10 + 5, NEW.c = NEW.a / 10; end | +delimiter ;| +set autocommit = 0; +connection a; +insert into t1(a) values (10),(20),(30),(40),(50),(60),(70),(80),(90),(100), +(11),(21),(31),(41),(51),(61),(71),(81),(91),(101), +(12),(22),(32),(42),(52),(62),(72),(82),(92),(102), +(13),(23),(33),(43),(53),(63),(73),(83),(93),(103), +(14),(24),(34),(44),(54),(64),(74),(84),(94),(104); +connection b; +commit; +connection a; +commit; +drop trigger t1t; +drop table t1; +disconnect a; +disconnect b; +# +# Another trigger test +# +connect (a,localhost,root,,); +connect (b,localhost,root,,); +connection a; +create table t1(a int not null, b int, c int, d int, primary key(a)) engine=innodb; +create table t2(a int not null, b int, c int, d int, primary key(a)) engine=innodb; +create table t3(a int not null, b int, c int, d int, primary key(a)) engine=innodb; +create table t4(a int not null, b int, c int, d int, primary key(a)) engine=innodb; +create table t5(a int not null, b int, c int, d int, primary key(a)) engine=innodb; +insert into t1(a) values (1),(2),(3); +insert into t2(a) values (1),(2),(3); +insert into t3(a) values (1),(2),(3); +insert into t4(a) values (1),(2),(3); +insert into t3(a) values (5),(7),(8); +insert into t4(a) values (5),(7),(8); +insert into t5(a) values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12); + +delimiter |; +create trigger t1t before insert on t1 for each row begin + INSERT INTO t2 SET a = NEW.a; +end | + +create trigger t2t before insert on t2 for each row begin + DELETE FROM t3 WHERE a = NEW.a; +end | + +create trigger t3t before delete on t3 for each row begin + UPDATE t4 SET b = b + 1 WHERE a = OLD.a; +end | + +create trigger t4t before update on t4 for each row begin + UPDATE t5 SET b = b + 1 where a = NEW.a; +end | +delimiter ;| +commit; +set autocommit = 0; +update t1 set b = b + 5 where a = 1; +update t2 set b = b + 5 where a = 1; +update t3 set b = b + 5 where a = 1; +update t4 set b = b + 5 where a = 1; +insert into t5(a) values(20); +connection b; +set autocommit = 0; +insert into t1(a) values(7); +insert into t2(a) values(8); +delete from t2 where a = 3; +update t4 set b = b + 1 where a = 3; +commit; +drop trigger t1t; +drop trigger t2t; +drop trigger t3t; +drop trigger t4t; +drop table t1, t2, t3, t4, t5; +connection default; +disconnect a; +disconnect b; + +# +# Test that cascading updates leading to duplicate keys give the correct +# error message (bug #9680) +# + +CREATE TABLE t1 ( + field1 varchar(8) NOT NULL DEFAULT '', + field2 varchar(8) NOT NULL DEFAULT '', + PRIMARY KEY (field1, field2) +) ENGINE=InnoDB; + +CREATE TABLE t2 ( + field1 varchar(8) NOT NULL DEFAULT '' PRIMARY KEY, + FOREIGN KEY (field1) REFERENCES t1 (field1) + ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB; + +INSERT INTO t1 VALUES ('old', 'somevalu'); +INSERT INTO t1 VALUES ('other', 'anyvalue'); + +INSERT INTO t2 VALUES ('old'); +INSERT INTO t2 VALUES ('other'); + +--error ER_FOREIGN_DUPLICATE_KEY +UPDATE t1 SET field1 = 'other' WHERE field2 = 'somevalu'; + +DROP TABLE t2; +DROP TABLE t1; + +# +# Bug#18477 - MySQL/InnoDB Ignoring Foreign Keys in ALTER TABLE +# +create table t1 ( + c1 bigint not null, + c2 bigint not null, + primary key (c1), + unique key (c2) +) engine=innodb; +# +create table t2 ( + c1 bigint not null, + primary key (c1) +) engine=innodb; +# +alter table t1 add constraint c2_fk foreign key (c2) + references t2(c1) on delete cascade; +show create table t1; +# +alter table t1 drop foreign key c2_fk; +show create table t1; +# +drop table t1, t2; + +# +# Bug #14360: problem with intervals +# + +create table t1(a date) engine=innodb; +create table t2(a date, key(a)) engine=innodb; +insert into t1 values('2005-10-01'); +insert into t2 values('2005-10-01'); +select * from t1, t2 + where t2.a between t1.a - interval 2 day and t1.a + interval 2 day; +drop table t1, t2; + +create table t1 (id int not null, f_id int not null, f int not null, +primary key(f_id, id)) engine=innodb; +create table t2 (id int not null,s_id int not null,s varchar(200), +primary key(id)) engine=innodb; +INSERT INTO t1 VALUES (8, 1, 3); +INSERT INTO t1 VALUES (1, 2, 1); +INSERT INTO t2 VALUES (1, 0, ''); +INSERT INTO t2 VALUES (8, 1, ''); +commit; +DELETE ml.* FROM t1 AS ml LEFT JOIN t2 AS mm ON (mm.id=ml.id) +WHERE mm.id IS NULL; +select ml.* from t1 as ml left join t2 as mm on (mm.id=ml.id) +where mm.id is null lock in share mode; +drop table t1,t2; + +# +# Test case where X-locks on unused rows should be released in a +# update (because READ COMMITTED isolation level) +# + +connect (a,localhost,root,,); +connect (b,localhost,root,,); +connection a; +create table t1(a int not null, b int, primary key(a)) engine=innodb; +insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2),(7,3); +commit; +SET binlog_format='MIXED'; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +update t1 set b = 5 where b = 1; +connection b; +SET binlog_format='MIXED'; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +# +# X-lock to record (7,3) should be released in a update +# +select * from t1 where a = 7 and b = 3 for update; +connection a; +commit; +connection b; +commit; +drop table t1; +connection default; +disconnect a; +disconnect b; + +# +# Test case where no locks should be released (because we are not +# using READ COMMITTED isolation level) +# + +connect (a,localhost,root,,); +connect (b,localhost,root,,); +connection a; +create table t1(a int not null, b int, primary key(a)) engine=innodb; +insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2); +commit; +set autocommit = 0; +select * from t1 lock in share mode; +update t1 set b = 5 where b = 1; +connection b; +set autocommit = 0; +# +# S-lock to records (2,2),(4,2), and (6,2) should not be released in a update +# +--error 1205 +select * from t1 where a = 2 and b = 2 for update; +# +# X-lock to record (1,1),(3,1),(5,1) should not be released in a update +# +--error 1205 +connection a; +commit; +connection b; +commit; +connection default; +disconnect a; +disconnect b; +drop table t1; + +# +# Consistent read should be used in following selects +# +# 1) INSERT INTO ... SELECT +# 2) UPDATE ... = ( SELECT ...) +# 3) CREATE ... SELECT + +connect (a,localhost,root,,); +connect (b,localhost,root,,); +connection a; +create table t1(a int not null, b int, primary key(a)) engine=innodb; +insert into t1 values (1,2),(5,3),(4,2); +create table t2(d int not null, e int, primary key(d)) engine=innodb; +insert into t2 values (8,6),(12,1),(3,1); +commit; +set autocommit = 0; +select * from t2 for update; +connection b; +SET binlog_format='MIXED'; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +insert into t1 select * from t2; +update t1 set b = (select e from t2 where a = d); +create table t3(d int not null, e int, primary key(d)) engine=innodb +select * from t2; +commit; +connection a; +commit; +connection default; +disconnect a; +disconnect b; +drop table t1, t2, t3; + +# +# Consistent read should not be used if +# +# (a) isolation level is serializable OR +# (b) select ... lock in share mode OR +# (c) select ... for update +# +# in following queries: +# +# 1) INSERT INTO ... SELECT +# 2) UPDATE ... = ( SELECT ...) +# 3) CREATE ... SELECT + +connect (a,localhost,root,,); +connect (b,localhost,root,,); +connect (c,localhost,root,,); +connect (d,localhost,root,,); +connect (e,localhost,root,,); +connect (f,localhost,root,,); +connect (g,localhost,root,,); +connect (h,localhost,root,,); +connect (i,localhost,root,,); +connect (j,localhost,root,,); +connection a; +create table t1(a int not null, b int, primary key(a)) engine=innodb; +insert into t1 values (1,2),(5,3),(4,2); +create table t2(a int not null, b int, primary key(a)) engine=innodb; +insert into t2 values (8,6),(12,1),(3,1); +create table t3(d int not null, b int, primary key(d)) engine=innodb; +insert into t3 values (8,6),(12,1),(3,1); +create table t5(a int not null, b int, primary key(a)) engine=innodb; +insert into t5 values (1,2),(5,3),(4,2); +create table t6(d int not null, e int, primary key(d)) engine=innodb; +insert into t6 values (8,6),(12,1),(3,1); +create table t8(a int not null, b int, primary key(a)) engine=innodb; +insert into t8 values (1,2),(5,3),(4,2); +create table t9(d int not null, e int, primary key(d)) engine=innodb; +insert into t9 values (8,6),(12,1),(3,1); +commit; +set autocommit = 0; +select * from t2 for update; +connection b; +SET binlog_format='MIXED'; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; +--send +insert into t1 select * from t2; +connection c; +SET binlog_format='MIXED'; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; +--send +update t3 set b = (select b from t2 where a = d); +connection d; +SET binlog_format='MIXED'; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; +--send +create table t4(a int not null, b int, primary key(a)) engine=innodb select * from t2; +connection e; +SET binlog_format='MIXED'; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +--send +insert into t5 (select * from t2 lock in share mode); +connection f; +SET binlog_format='MIXED'; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +--send +update t6 set e = (select b from t2 where a = d lock in share mode); +connection g; +SET binlog_format='MIXED'; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +--send +create table t7(a int not null, b int, primary key(a)) engine=innodb select * from t2 lock in share mode; +connection h; +SET binlog_format='MIXED'; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +--send +insert into t8 (select * from t2 for update); +connection i; +SET binlog_format='MIXED'; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +--send +update t9 set e = (select b from t2 where a = d for update); +connection j; +SET binlog_format='MIXED'; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +--send +create table t10(a int not null, b int, primary key(a)) engine=innodb select * from t2 for update; + +connection b; +--error 1205 +reap; + +connection c; +--error 1205 +reap; + +connection d; +--error 1205 +reap; + +connection e; +--error 1205 +reap; + +connection f; +--error 1205 +reap; + +connection g; +--error 1205 +reap; + +connection h; +--error 1205 +reap; + +connection i; +--error 1205 +reap; + +connection j; +--error 1205 +reap; + +connection a; +commit; + +connection default; +disconnect a; +disconnect b; +disconnect c; +disconnect d; +disconnect e; +disconnect f; +disconnect g; +disconnect h; +disconnect i; +disconnect j; +drop table t1, t2, t3, t5, t6, t8, t9; + +# bug 18934, "InnoDB crashes when table uses column names like DB_ROW_ID" +--error ER_WRONG_COLUMN_NAME +CREATE TABLE t1 (DB_ROW_ID int) engine=innodb; + +# +# Bug #17152: Wrong result with BINARY comparison on aliased column +# + +CREATE TABLE t1 ( + a BIGINT(20) NOT NULL, + PRIMARY KEY (a) + ) ENGINE=INNODB DEFAULT CHARSET=UTF8; + +CREATE TABLE t2 ( + a BIGINT(20) NOT NULL, + b VARCHAR(128) NOT NULL, + c TEXT NOT NULL, + PRIMARY KEY (a,b), + KEY idx_t2_b_c (b,c(200)), + CONSTRAINT t_fk FOREIGN KEY (a) REFERENCES t1 (a) + ON DELETE CASCADE + ) ENGINE=INNODB DEFAULT CHARSET=UTF8; + +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (1, 'bar', 'vbar'); +INSERT INTO t2 VALUES (1, 'BAR2', 'VBAR'); +INSERT INTO t2 VALUES (1, 'bar_bar', 'bibi'); +INSERT INTO t2 VALUES (1, 'customer_over', '1'); + +SELECT * FROM t2 WHERE b = 'customer_over'; +SELECT * FROM t2 WHERE BINARY b = 'customer_over'; +SELECT DISTINCT p0.a FROM t2 p0 WHERE p0.b = 'customer_over'; +/* Bang: Empty result set, above was expected: */ +SELECT DISTINCT p0.a FROM t2 p0 WHERE BINARY p0.b = 'customer_over'; +SELECT p0.a FROM t2 p0 WHERE BINARY p0.b = 'customer_over'; + +drop table t2, t1; + +# +# Test optimize on table with open transaction +# + +CREATE TABLE t1 ( a int ) ENGINE=innodb; +BEGIN; +INSERT INTO t1 VALUES (1); +OPTIMIZE TABLE t1; +DROP TABLE t1; + +# +# Bug #24741 (existing cascade clauses disappear when adding foreign keys) +# + +CREATE TABLE t1 (id int PRIMARY KEY, f int NOT NULL, INDEX(f)) ENGINE=InnoDB; + +CREATE TABLE t2 (id int PRIMARY KEY, f INT NOT NULL, + CONSTRAINT t2_t1 FOREIGN KEY (id) REFERENCES t1 (id) + ON DELETE CASCADE ON UPDATE CASCADE) ENGINE=InnoDB; + +ALTER TABLE t2 ADD FOREIGN KEY (f) REFERENCES t1 (f) ON +DELETE CASCADE ON UPDATE CASCADE; + +SHOW CREATE TABLE t2; +DROP TABLE t2, t1; + +# +# Bug #25927: Prevent ALTER TABLE ... MODIFY ... NOT NULL on columns +# for which there is a foreign key constraint ON ... SET NULL. +# + +CREATE TABLE t1 (a INT, INDEX(a)) ENGINE=InnoDB; +CREATE TABLE t2 (a INT, INDEX(a)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (1); +ALTER TABLE t2 ADD FOREIGN KEY (a) REFERENCES t1 (a) ON DELETE SET NULL; +# mysqltest first does replace_regex, then replace_result +--replace_regex /'[^']*test\/#sql-[0-9a-f_]*'/'#sql-temporary'/ +# Embedded server doesn't chdir to data directory +--replace_result $MYSQLD_DATADIR ./ master-data/ '' +--error 1025 +ALTER TABLE t2 MODIFY a INT NOT NULL; +DELETE FROM t1; +DROP TABLE t2,t1; + +# +# Bug #26835: table corruption after delete+insert +# + +CREATE TABLE t1 (a VARCHAR(5) COLLATE utf8_unicode_ci PRIMARY KEY) +ENGINE=InnoDB; +INSERT INTO t1 VALUES (0xEFBCA4EFBCA4EFBCA4); +DELETE FROM t1; +INSERT INTO t1 VALUES ('DDD'); +SELECT * FROM t1; +DROP TABLE t1; + +# +# Bug #23313 (AUTO_INCREMENT=# not reported back for InnoDB tables) +# Bug #21404 (AUTO_INCREMENT value reset when Adding FKEY (or ALTER?)) +# + +CREATE TABLE t1 (id int PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB +AUTO_INCREMENT=42; + +INSERT INTO t1 VALUES (0),(347),(0); +SELECT * FROM t1; + +SHOW CREATE TABLE t1; + +CREATE TABLE t2 (id int PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t2 VALUES(42),(347),(348); +ALTER TABLE t1 ADD CONSTRAINT t1_t2 FOREIGN KEY (id) REFERENCES t2(id); +SHOW CREATE TABLE t1; + +DROP TABLE t1,t2; + +# +# Bug #21101 (Prints wrong error message if max row size is too large) +# +SET innodb_strict_mode=ON; +--error 1118 +CREATE TABLE t1 ( + c01 CHAR(255), c02 CHAR(255), c03 CHAR(255), c04 CHAR(255), + c05 CHAR(255), c06 CHAR(255), c07 CHAR(255), c08 CHAR(255), + c09 CHAR(255), c10 CHAR(255), c11 CHAR(255), c12 CHAR(255), + c13 CHAR(255), c14 CHAR(255), c15 CHAR(255), c16 CHAR(255), + c17 CHAR(255), c18 CHAR(255), c19 CHAR(255), c20 CHAR(255), + c21 CHAR(255), c22 CHAR(255), c23 CHAR(255), c24 CHAR(255), + c25 CHAR(255), c26 CHAR(255), c27 CHAR(255), c28 CHAR(255), + c29 CHAR(255), c30 CHAR(255), c31 CHAR(255), c32 CHAR(255) + ) ENGINE = InnoDB; +SET innodb_strict_mode=OFF; + +# +# Bug #31860 InnoDB assumes AUTOINC values can only be positive. +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1( + id BIGINT(20) NOT NULL AUTO_INCREMENT PRIMARY KEY + ) ENGINE=InnoDB; +INSERT INTO t1 VALUES(-10); +SELECT * FROM t1; +# +# NOTE: The server really needs to be restarted at this point +# for the test to be useful. +# +# Without the fix InnoDB would trip over an assertion here. +INSERT INTO t1 VALUES(NULL); +# The next value should be 1 and not -9 or a -ve number +SELECT * FROM t1; +DROP TABLE t1; + +# +# Bug #21409 Incorrect result returned when in READ-COMMITTED with +# query_cache ON +# +CONNECT (c1,localhost,root,,); +CONNECT (c2,localhost,root,,); +CONNECTION c1; +SET binlog_format='MIXED'; +SET TX_ISOLATION='read-committed'; +SET AUTOCOMMIT=0; +DROP TABLE IF EXISTS t1, t2; +CREATE TABLE t1 ( a int ) ENGINE=InnoDB; +CREATE TABLE t2 LIKE t1; +SELECT * FROM t2; +CONNECTION c2; +SET binlog_format='MIXED'; +SET TX_ISOLATION='read-committed'; +SET AUTOCOMMIT=0; +INSERT INTO t1 VALUES (1); +COMMIT; +CONNECTION c1; +SELECT * FROM t1 WHERE a=1; +DISCONNECT c1; +DISCONNECT c2; +CONNECT (c1,localhost,root,,); +CONNECT (c2,localhost,root,,); +CONNECTION c1; +SET binlog_format='MIXED'; +SET TX_ISOLATION='read-committed'; +SET AUTOCOMMIT=0; +SELECT * FROM t2; +CONNECTION c2; +SET binlog_format='MIXED'; +SET TX_ISOLATION='read-committed'; +SET AUTOCOMMIT=0; +INSERT INTO t1 VALUES (2); +COMMIT; +CONNECTION c1; +# The result set below should be the same for both selects +SELECT * FROM t1 WHERE a=2; +SELECT * FROM t1 WHERE a=2; +DROP TABLE t1; +DROP TABLE t2; +DISCONNECT c1; +DISCONNECT c2; +CONNECTION default; + +# +# Bug #29157 UPDATE, changed rows incorrect +# +create table t1 (i int, j int) engine=innodb; +insert into t1 (i, j) values (1, 1), (2, 2); +--enable_info +update t1 set j = 2; +--disable_info +drop table t1; + +# +# Bug #32440 InnoDB free space info does not appear in SHOW TABLE STATUS or +# I_S +# +create table t1 (id int) comment='this is a comment' engine=innodb; +select table_comment, data_free > 0 as data_free_is_set + from information_schema.tables + where table_schema='test' and table_name = 't1'; +drop table t1; + +# +# Bug 34920 test +# +CONNECTION default; +CREATE TABLE t1 ( + c1 INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, + c2 VARCHAR(128) NOT NULL, + PRIMARY KEY(c1) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=100; + +CREATE TABLE t2 ( + c1 INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, + c2 INT(10) UNSIGNED DEFAULT NULL, + PRIMARY KEY(c1) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=200; + +SELECT AUTO_INCREMENT FROM INFORMATION_SCHEMA.TABLES WHERE table_name = 't2'; +ALTER TABLE t2 ADD CONSTRAINT t1_t2_1 FOREIGN KEY(c1) REFERENCES t1(c1); +SELECT AUTO_INCREMENT FROM INFORMATION_SCHEMA.TABLES WHERE table_name = 't2'; +DROP TABLE t2; +DROP TABLE t1; +# End 34920 test +# +# Bug #29507 TRUNCATE shows to many rows effected +# +CONNECTION default; +CREATE TABLE t1 (c1 int default NULL, + c2 int default NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +--enable_info +TRUNCATE TABLE t1; + +INSERT INTO t1 VALUES (1, 1), (2, 2), (3, 3), (4, 4), (5, 5); +TRUNCATE TABLE t1; + +--disable_info +DROP TABLE t1; +# +# Bug#35537 Innodb doesn't increment handler_update and handler_delete. +# +-- disable_query_log +-- disable_result_log + +CONNECT (c1,localhost,root,,); + +DROP TABLE IF EXISTS bug35537; +CREATE TABLE bug35537 ( + c1 int +) ENGINE=InnoDB; + +INSERT INTO bug35537 VALUES (1); + +-- enable_result_log + +SHOW SESSION STATUS LIKE 'Handler_update%'; +SHOW SESSION STATUS LIKE 'Handler_delete%'; + +UPDATE bug35537 SET c1 = 2 WHERE c1 = 1; +DELETE FROM bug35537 WHERE c1 = 2; + +SHOW SESSION STATUS LIKE 'Handler_update%'; +SHOW SESSION STATUS LIKE 'Handler_delete%'; + +DROP TABLE bug35537; + +DISCONNECT c1; +CONNECTION default; + +SET GLOBAL innodb_thread_concurrency = @innodb_thread_concurrency_orig; From 91b5e9352a82b096197aa9f24f149cf3bf892b8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 26 Oct 2011 11:44:28 +0300 Subject: [PATCH 049/288] Revert most of revno 3560.9.1 (Bug#12704861) This was an attempt to address problems with the Bug#12612184 fix. Even with this follow-up fix, crash recovery can be broken. Let us fix the bug later. --- .../suite/innodb_plugin/r/innodb-index.result | 14 ++ .../suite/innodb_plugin/t/innodb-index.test | 19 +- storage/innobase/btr/btr0btr.c | 211 ++--------------- storage/innobase/btr/btr0cur.c | 92 +++---- storage/innobase/fsp/fsp0fsp.c | 159 ++++--------- storage/innobase/include/btr0btr.h | 31 +-- storage/innobase/include/btr0cur.h | 14 +- storage/innobase/include/fsp0fsp.h | 6 +- storage/innobase/include/mtr0mtr.h | 7 +- storage/innobase/include/mtr0mtr.ic | 4 +- storage/innobase/mtr/mtr0mtr.c | 10 +- storage/innobase/row/row0ins.c | 32 +-- storage/innobase/row/row0row.c | 32 ++- storage/innobase/row/row0upd.c | 21 +- storage/innobase/trx/trx0undo.c | 2 +- storage/innodb_plugin/ChangeLog | 9 - storage/innodb_plugin/btr/btr0btr.c | 211 ++--------------- storage/innodb_plugin/btr/btr0cur.c | 114 +++++---- storage/innodb_plugin/fsp/fsp0fsp.c | 224 +++++++----------- storage/innodb_plugin/include/btr0btr.h | 34 +-- storage/innodb_plugin/include/btr0cur.h | 38 +-- storage/innodb_plugin/include/fsp0fsp.h | 25 +- storage/innodb_plugin/include/mtr0mtr.h | 11 +- storage/innodb_plugin/include/mtr0mtr.ic | 4 +- storage/innodb_plugin/mtr/mtr0mtr.c | 5 +- storage/innodb_plugin/row/row0ins.c | 31 +-- storage/innodb_plugin/row/row0row.c | 25 +- storage/innodb_plugin/row/row0upd.c | 21 +- storage/innodb_plugin/trx/trx0undo.c | 2 +- 29 files changed, 441 insertions(+), 967 deletions(-) diff --git a/mysql-test/suite/innodb_plugin/r/innodb-index.result b/mysql-test/suite/innodb_plugin/r/innodb-index.result index 8640ff94d9e..9600d0a79b4 100644 --- a/mysql-test/suite/innodb_plugin/r/innodb-index.result +++ b/mysql-test/suite/innodb_plugin/r/innodb-index.result @@ -1094,6 +1094,20 @@ COMMIT; UPDATE bug12547647 SET c = REPEAT('b',16928); ERROR 42000: Row size too large. The maximum row size for the used table type, not counting BLOBs, is 8126. You have to change some columns to TEXT or BLOBs DROP TABLE bug12547647; +SET @r=REPEAT('a',500); +CREATE TABLE t1(a INT, +v1 VARCHAR(500), v2 VARCHAR(500), v3 VARCHAR(500), +v4 VARCHAR(500), v5 VARCHAR(500), v6 VARCHAR(500), +v7 VARCHAR(500), v8 VARCHAR(500), v9 VARCHAR(500), +v10 VARCHAR(500), v11 VARCHAR(500), v12 VARCHAR(500), +v13 VARCHAR(500), v14 VARCHAR(500), v15 VARCHAR(500), +v16 VARCHAR(500), v17 VARCHAR(500), v18 VARCHAR(500) +) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; +CREATE INDEX idx1 ON t1(a,v1); +INSERT INTO t1 VALUES(9,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r); +UPDATE t1 SET a=1000; +DELETE FROM t1; +DROP TABLE t1; set global innodb_file_per_table=0; set global innodb_file_format=Antelope; set global innodb_file_format_check=Antelope; diff --git a/mysql-test/suite/innodb_plugin/t/innodb-index.test b/mysql-test/suite/innodb_plugin/t/innodb-index.test index 568661c67f1..0d891939d6e 100644 --- a/mysql-test/suite/innodb_plugin/t/innodb-index.test +++ b/mysql-test/suite/innodb_plugin/t/innodb-index.test @@ -527,13 +527,30 @@ CREATE TABLE bug12547647( a INT NOT NULL, b BLOB NOT NULL, c TEXT, PRIMARY KEY (b(10), a), INDEX (c(10)) ) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; - INSERT INTO bug12547647 VALUES (5,repeat('khdfo5AlOq',1900),repeat('g',7731)); COMMIT; # The following used to cause infinite undo log allocation. --error ER_TOO_BIG_ROWSIZE UPDATE bug12547647 SET c = REPEAT('b',16928); DROP TABLE bug12547647; +# Bug#12637786 +SET @r=REPEAT('a',500); +CREATE TABLE t1(a INT, + v1 VARCHAR(500), v2 VARCHAR(500), v3 VARCHAR(500), + v4 VARCHAR(500), v5 VARCHAR(500), v6 VARCHAR(500), + v7 VARCHAR(500), v8 VARCHAR(500), v9 VARCHAR(500), + v10 VARCHAR(500), v11 VARCHAR(500), v12 VARCHAR(500), + v13 VARCHAR(500), v14 VARCHAR(500), v15 VARCHAR(500), + v16 VARCHAR(500), v17 VARCHAR(500), v18 VARCHAR(500) +) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; + +CREATE INDEX idx1 ON t1(a,v1); +INSERT INTO t1 VALUES(9,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r); +UPDATE t1 SET a=1000; +DELETE FROM t1; +# Let the purge thread clean up this file. +-- sleep 10 +DROP TABLE t1; eval set global innodb_file_per_table=$per_table; eval set global innodb_file_format=$format; diff --git a/storage/innobase/btr/btr0btr.c b/storage/innobase/btr/btr0btr.c index ad99913cf3b..e8e065a3116 100644 --- a/storage/innobase/btr/btr0btr.c +++ b/storage/innobase/btr/btr0btr.c @@ -300,30 +300,29 @@ btr_page_alloc_for_ibuf( /****************************************************************** Allocates a new file page to be used in an index tree. NOTE: we assume that the caller has made the reservation for free extents! */ -static -ulint -btr_page_alloc_low( -/*===============*/ - /* out: allocated page number, - FIL_NULL if out of space */ + +page_t* +btr_page_alloc( +/*===========*/ + /* out: new allocated page, x-latched; + NULL if out of space */ dict_index_t* index, /* in: index */ ulint hint_page_no, /* in: hint of a good page */ byte file_direction, /* in: direction where a possible page split is made */ ulint level, /* in: level where the page is placed in the tree */ - mtr_t* mtr, /* in/out: mini-transaction - for the allocation */ - mtr_t* init_mtr) /* in/out: mini-transaction - in which the page should be - initialized (may be the same - as mtr), or NULL if it should - not be initialized (the page - at hint was previously freed - in mtr) */ + mtr_t* mtr) /* in: mtr */ { fseg_header_t* seg_header; page_t* root; + page_t* new_page; + ulint new_page_no; + + if (index->type & DICT_IBUF) { + + return(btr_page_alloc_for_ibuf(index, mtr)); + } root = btr_root_get(index, mtr); @@ -337,61 +336,19 @@ btr_page_alloc_low( reservation for free extents, and thus we know that a page can be allocated: */ - return(fseg_alloc_free_page_general(seg_header, hint_page_no, - file_direction, TRUE, - mtr, init_mtr)); -} - -/**************************************************************//** -Allocates a new file page to be used in an index tree. NOTE: we assume -that the caller has made the reservation for free extents! */ - -page_t* -btr_page_alloc( -/*===========*/ - /* out: new allocated block, x-latched; - NULL if out of space */ - dict_index_t* index, /* in: index */ - ulint hint_page_no, /* in: hint of a good page */ - byte file_direction, /* in: direction where a possible - page split is made */ - ulint level, /* in: level where the page is placed - in the tree */ - mtr_t* mtr, /* in/out: mini-transaction - for the allocation */ - mtr_t* init_mtr) /* in/out: mini-transaction - for x-latching and initializing - the page */ -{ - page_t* new_page; - ulint new_page_no; - - if (index->type & DICT_IBUF) { - - return(btr_page_alloc_for_ibuf(index, mtr)); - } - - new_page_no = btr_page_alloc_low( - index, hint_page_no, file_direction, level, mtr, init_mtr); - + new_page_no = fseg_alloc_free_page_general(seg_header, hint_page_no, + file_direction, TRUE, mtr); if (new_page_no == FIL_NULL) { return(NULL); } new_page = buf_page_get(dict_index_get_space(index), new_page_no, - RW_X_LATCH, init_mtr); + RW_X_LATCH, mtr); #ifdef UNIV_SYNC_DEBUG buf_page_dbg_add_level(new_page, SYNC_TREE_NODE_NEW); #endif /* UNIV_SYNC_DEBUG */ - if (mtr->freed_clust_leaf) { - mtr_memo_release(mtr, new_page, MTR_MEMO_FREE_CLUST_LEAF); - ut_ad(!mtr_memo_contains(mtr, buf_block_align(new_page), - MTR_MEMO_FREE_CLUST_LEAF)); - } - - ut_ad(btr_freed_leaves_validate(mtr)); return(new_page); } @@ -538,138 +495,8 @@ btr_page_free( level = btr_page_get_level(page, mtr); btr_page_free_low(index, page, level, mtr); - - /* The handling of MTR_MEMO_FREE_CLUST_LEAF assumes this. */ - ut_ad(mtr_memo_contains(mtr, buf_block_align(page), - MTR_MEMO_PAGE_X_FIX)); - - if (level == 0 && (index->type & DICT_CLUSTERED)) { - /* We may have to call btr_mark_freed_leaves() to - temporarily mark the block nonfree for invoking - btr_store_big_rec_extern_fields() after an - update. Remember that the block was freed. */ - mtr->freed_clust_leaf = TRUE; - mtr_memo_push(mtr, buf_block_align(page), - MTR_MEMO_FREE_CLUST_LEAF); - } - - ut_ad(btr_freed_leaves_validate(mtr)); } -/**************************************************************//** -Marks all MTR_MEMO_FREE_CLUST_LEAF pages nonfree or free. -For invoking btr_store_big_rec_extern_fields() after an update, -we must temporarily mark freed clustered index pages allocated, so -that off-page columns will not be allocated from them. Between the -btr_store_big_rec_extern_fields() and mtr_commit() we have to -mark the pages free again, so that no pages will be leaked. */ - -void -btr_mark_freed_leaves( -/*==================*/ - dict_index_t* index, /* in/out: clustered index */ - mtr_t* mtr, /* in/out: mini-transaction */ - ibool nonfree)/* in: TRUE=mark nonfree, FALSE=mark freed */ -{ - /* This is loosely based on mtr_memo_release(). */ - - ulint offset; - - ut_ad(index->type & DICT_CLUSTERED); - ut_ad(mtr->magic_n == MTR_MAGIC_N); - ut_ad(mtr->state == MTR_ACTIVE); - - if (!mtr->freed_clust_leaf) { - return; - } - - offset = dyn_array_get_data_size(&mtr->memo); - - while (offset > 0) { - mtr_memo_slot_t* slot; - buf_block_t* block; - - offset -= sizeof *slot; - - slot = dyn_array_get_element(&mtr->memo, offset); - - if (slot->type != MTR_MEMO_FREE_CLUST_LEAF) { - continue; - } - - /* Because btr_page_alloc() does invoke - mtr_memo_release on MTR_MEMO_FREE_CLUST_LEAF, all - blocks tagged with MTR_MEMO_FREE_CLUST_LEAF in the - memo must still be clustered index leaf tree pages. */ - block = slot->object; - ut_a(buf_block_get_space(block) - == dict_index_get_space(index)); - ut_a(fil_page_get_type(buf_block_get_frame(block)) - == FIL_PAGE_INDEX); - ut_a(btr_page_get_level(buf_block_get_frame(block), mtr) == 0); - - if (nonfree) { - /* Allocate the same page again. */ - ulint page_no; - page_no = btr_page_alloc_low( - index, buf_block_get_page_no(block), - FSP_NO_DIR, 0, mtr, NULL); - ut_a(page_no == buf_block_get_page_no(block)); - } else { - /* Assert that the page is allocated and free it. */ - btr_page_free_low(index, buf_block_get_frame(block), - 0, mtr); - } - } - - ut_ad(btr_freed_leaves_validate(mtr)); -} - -#ifdef UNIV_DEBUG -/**************************************************************//** -Validates all pages marked MTR_MEMO_FREE_CLUST_LEAF. -See btr_mark_freed_leaves(). */ - -ibool -btr_freed_leaves_validate( -/*======================*/ - /* out: TRUE if valid */ - mtr_t* mtr) /* in: mini-transaction */ -{ - ulint offset; - - ut_ad(mtr->magic_n == MTR_MAGIC_N); - ut_ad(mtr->state == MTR_ACTIVE); - - offset = dyn_array_get_data_size(&mtr->memo); - - while (offset > 0) { - mtr_memo_slot_t* slot; - buf_block_t* block; - - offset -= sizeof *slot; - - slot = dyn_array_get_element(&mtr->memo, offset); - - if (slot->type != MTR_MEMO_FREE_CLUST_LEAF) { - continue; - } - - ut_a(mtr->freed_clust_leaf); - /* Because btr_page_alloc() does invoke - mtr_memo_release on MTR_MEMO_FREE_CLUST_LEAF, all - blocks tagged with MTR_MEMO_FREE_CLUST_LEAF in the - memo must still be clustered index leaf tree pages. */ - block = slot->object; - ut_a(fil_page_get_type(buf_block_get_frame(block)) - == FIL_PAGE_INDEX); - ut_a(btr_page_get_level(buf_block_get_frame(block), mtr) == 0); - } - - return(TRUE); -} -#endif /* UNIV_DEBUG */ - /****************************************************************** Sets the child node file address in a node pointer. */ UNIV_INLINE @@ -1199,7 +1026,7 @@ btr_root_raise_and_insert( a node pointer to the new page, and then splitting the new page. */ new_page = btr_page_alloc(index, 0, FSP_NO_DIR, - btr_page_get_level(root, mtr), mtr, mtr); + btr_page_get_level(root, mtr), mtr); btr_page_create(new_page, index, mtr); @@ -1820,7 +1647,7 @@ func_start: /* 2. Allocate a new page to the index */ new_page = btr_page_alloc(cursor->index, hint_page_no, direction, - btr_page_get_level(page, mtr), mtr, mtr); + btr_page_get_level(page, mtr), mtr); btr_page_create(new_page, cursor->index, mtr); /* 3. Calculate the first record on the upper half-page, and the diff --git a/storage/innobase/btr/btr0cur.c b/storage/innobase/btr/btr0cur.c index 37bb3188785..95d87344e93 100644 --- a/storage/innobase/btr/btr0cur.c +++ b/storage/innobase/btr/btr0cur.c @@ -2051,6 +2051,43 @@ return_after_reservations: return(err); } +/***************************************************************** +Commits and restarts a mini-transaction so that it will retain an +x-lock on index->lock and the cursor page. */ + +void +btr_cur_mtr_commit_and_start( +/*=========================*/ + btr_cur_t* cursor, /* in: cursor */ + mtr_t* mtr) /* in/out: mini-transaction */ +{ + buf_block_t* block; + + block = buf_block_align(btr_cur_get_rec(cursor)); + + ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(cursor->index), + MTR_MEMO_X_LOCK)); + ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); + /* Keep the locks across the mtr_commit(mtr). */ + rw_lock_x_lock(dict_index_get_lock(cursor->index)); + rw_lock_x_lock(&block->lock); + mutex_enter(&block->mutex); +#ifdef UNIV_SYNC_DEBUG + buf_block_buf_fix_inc_debug(block, __FILE__, __LINE__); +#else + buf_block_buf_fix_inc(block); +#endif + mutex_exit(&block->mutex); + /* Write out the redo log. */ + mtr_commit(mtr); + mtr_start(mtr); + /* Reassociate the locks with the mini-transaction. + They will be released on mtr_commit(mtr). */ + mtr_memo_push(mtr, dict_index_get_lock(cursor->index), + MTR_MEMO_X_LOCK); + mtr_memo_push(mtr, block, MTR_MEMO_PAGE_X_FIX); +} + /*==================== B-TREE DELETE MARK AND UNMARK ===============*/ /******************************************************************** @@ -3449,11 +3486,6 @@ btr_store_big_rec_extern_fields( this function returns */ big_rec_t* big_rec_vec, /* in: vector containing fields to be stored externally */ - mtr_t* alloc_mtr, /* in/out: in an insert, NULL; - in an update, local_mtr for - allocating BLOB pages and - updating BLOB pointers; alloc_mtr - must not have freed any leaf pages */ mtr_t* local_mtr __attribute__((unused))) /* in: mtr containing the latch to rec and to the tree */ @@ -3474,8 +3506,6 @@ btr_store_big_rec_extern_fields( ulint i; mtr_t mtr; - ut_ad(local_mtr); - ut_ad(!alloc_mtr || alloc_mtr == local_mtr); ut_ad(rec_offs_validate(rec, index, offsets)); ut_ad(mtr_memo_contains(local_mtr, dict_index_get_lock(index), MTR_MEMO_X_LOCK)); @@ -3485,25 +3515,6 @@ btr_store_big_rec_extern_fields( space_id = buf_frame_get_space_id(rec); - if (alloc_mtr) { - /* Because alloc_mtr will be committed after - mtr, it is possible that the tablespace has been - extended when the B-tree record was updated or - inserted, or it will be extended while allocating - pages for big_rec. - - TODO: In mtr (not alloc_mtr), write a redo log record - about extending the tablespace to its current size, - and remember the current size. Whenever the tablespace - grows as pages are allocated, write further redo log - records to mtr. (Currently tablespace extension is not - covered by the redo log. If it were, the record would - only be written to alloc_mtr, which is committed after - mtr.) */ - } else { - alloc_mtr = &mtr; - } - /* We have to create a file segment to the tablespace for each field and put the pointer to the field in rec */ @@ -3530,7 +3541,7 @@ btr_store_big_rec_extern_fields( } page = btr_page_alloc(index, hint_page_no, - FSP_NO_DIR, 0, alloc_mtr, &mtr); + FSP_NO_DIR, 0, &mtr); if (page == NULL) { mtr_commit(&mtr); @@ -3584,42 +3595,37 @@ btr_store_big_rec_extern_fields( extern_len -= store_len; - if (alloc_mtr == &mtr) { #ifdef UNIV_SYNC_DEBUG - rec_page = + rec_page = #endif /* UNIV_SYNC_DEBUG */ - buf_page_get( - space_id, - buf_frame_get_page_no(data), - RW_X_LATCH, &mtr); + buf_page_get(space_id, + buf_frame_get_page_no(data), + RW_X_LATCH, &mtr); #ifdef UNIV_SYNC_DEBUG - buf_page_dbg_add_level( - rec_page, SYNC_NO_ORDER_CHECK); + buf_page_dbg_add_level(rec_page, SYNC_NO_ORDER_CHECK); #endif /* UNIV_SYNC_DEBUG */ - } - mlog_write_ulint(data + local_len + BTR_EXTERN_LEN, 0, - MLOG_4BYTES, alloc_mtr); + MLOG_4BYTES, &mtr); mlog_write_ulint(data + local_len + BTR_EXTERN_LEN + 4, big_rec_vec->fields[i].len - extern_len, - MLOG_4BYTES, alloc_mtr); + MLOG_4BYTES, &mtr); if (prev_page_no == FIL_NULL) { mlog_write_ulint(data + local_len + BTR_EXTERN_SPACE_ID, space_id, - MLOG_4BYTES, alloc_mtr); + MLOG_4BYTES, &mtr); mlog_write_ulint(data + local_len + BTR_EXTERN_PAGE_NO, page_no, - MLOG_4BYTES, alloc_mtr); + MLOG_4BYTES, &mtr); mlog_write_ulint(data + local_len + BTR_EXTERN_OFFSET, FIL_PAGE_DATA, - MLOG_4BYTES, alloc_mtr); + MLOG_4BYTES, &mtr); /* Set the bit denoting that this field in rec is stored externally */ @@ -3627,7 +3633,7 @@ btr_store_big_rec_extern_fields( rec_set_nth_field_extern_bit( rec, index, big_rec_vec->fields[i].field_no, - TRUE, alloc_mtr); + TRUE, &mtr); } prev_page_no = page_no; diff --git a/storage/innobase/fsp/fsp0fsp.c b/storage/innobase/fsp/fsp0fsp.c index d5be8fca38f..90e6ad34a9a 100644 --- a/storage/innobase/fsp/fsp0fsp.c +++ b/storage/innobase/fsp/fsp0fsp.c @@ -300,12 +300,8 @@ fseg_alloc_free_page_low( inserted there in order, into which direction they go alphabetically: FSP_DOWN, FSP_UP, FSP_NO_DIR */ - mtr_t* mtr, /* in/out: mini-transaction */ - mtr_t* init_mtr);/* in/out: mini-transaction in which the - page should be initialized - (may be the same as mtr), or NULL if it - should not be initialized (the page at hint - was previously freed in mtr) */ + mtr_t* mtr); /* in/out: mini-transaction */ + /************************************************************************** Reads the file space size stored in the header page. */ @@ -1375,43 +1371,6 @@ fsp_alloc_free_extent( return(descr); } -/**********************************************************************//** -Allocates a single free page from a space. */ -static __attribute__((nonnull)) -void -fsp_alloc_from_free_frag( -/*=====================*/ - fsp_header_t* header, /* in/out: tablespace header */ - xdes_t* descr, /* in/out: extent descriptor */ - ulint bit, /* in: slot to allocate in the extent */ - mtr_t* mtr) /* in/out: mini-transaction */ -{ - ulint frag_n_used; - - ut_ad(xdes_get_state(descr, mtr) == XDES_FREE_FRAG); - ut_a(xdes_get_bit(descr, XDES_FREE_BIT, bit, mtr)); - xdes_set_bit(descr, XDES_FREE_BIT, bit, FALSE, mtr); - - /* Update the FRAG_N_USED field */ - frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES, - mtr); - frag_n_used++; - mlog_write_ulint(header + FSP_FRAG_N_USED, frag_n_used, MLOG_4BYTES, - mtr); - if (xdes_is_full(descr, mtr)) { - /* The fragment is full: move it to another list */ - flst_remove(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE, - mtr); - xdes_set_state(descr, XDES_FULL_FRAG, mtr); - - flst_add_last(header + FSP_FULL_FRAG, descr + XDES_FLST_NODE, - mtr); - mlog_write_ulint(header + FSP_FRAG_N_USED, - frag_n_used - FSP_EXTENT_SIZE, MLOG_4BYTES, - mtr); - } -} - /************************************************************************** Allocates a single free page from a space. The page is marked as used. */ static @@ -1422,22 +1381,19 @@ fsp_alloc_free_page( be allocated */ ulint space, /* in: space id */ ulint hint, /* in: hint of which page would be desirable */ - mtr_t* mtr, /* in/out: mini-transaction */ - mtr_t* init_mtr)/* in/out: mini-transaction in which the - page should be initialized - (may be the same as mtr) */ + mtr_t* mtr) /* in/out: mini-transaction */ { fsp_header_t* header; fil_addr_t first; xdes_t* descr; page_t* page; ulint free; + ulint frag_n_used; ulint page_no; ulint space_size; ibool success; ut_ad(mtr); - ut_ad(init_mtr); header = fsp_get_space_header(space, mtr); @@ -1517,21 +1473,40 @@ fsp_alloc_free_page( } } - fsp_alloc_from_free_frag(header, descr, free, mtr); + xdes_set_bit(descr, XDES_FREE_BIT, free, FALSE, mtr); + + /* Update the FRAG_N_USED field */ + frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES, + mtr); + frag_n_used++; + mlog_write_ulint(header + FSP_FRAG_N_USED, frag_n_used, MLOG_4BYTES, + mtr); + if (xdes_is_full(descr, mtr)) { + /* The fragment is full: move it to another list */ + flst_remove(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE, + mtr); + xdes_set_state(descr, XDES_FULL_FRAG, mtr); + + flst_add_last(header + FSP_FULL_FRAG, descr + XDES_FLST_NODE, + mtr); + mlog_write_ulint(header + FSP_FRAG_N_USED, + frag_n_used - FSP_EXTENT_SIZE, MLOG_4BYTES, + mtr); + } /* Initialize the allocated page to the buffer pool, so that it can be obtained immediately with buf_page_get without need for a disk read. */ - buf_page_create(space, page_no, init_mtr); + buf_page_create(space, page_no, mtr); - page = buf_page_get(space, page_no, RW_X_LATCH, init_mtr); + page = buf_page_get(space, page_no, RW_X_LATCH, mtr); #ifdef UNIV_SYNC_DEBUG buf_page_dbg_add_level(page, SYNC_FSP_PAGE); #endif /* UNIV_SYNC_DEBUG */ /* Prior contents of the page should be ignored */ - fsp_init_file_page(page, init_mtr); + fsp_init_file_page(page, mtr); return(page_no); } @@ -1750,7 +1725,7 @@ fsp_alloc_seg_inode_page( space = buf_frame_get_space_id(space_header); - page_no = fsp_alloc_free_page(space, 0, mtr, mtr); + page_no = fsp_alloc_free_page(space, 0, mtr); if (page_no == FIL_NULL) { @@ -2120,8 +2095,7 @@ fseg_create_general( } if (page == 0) { - page = fseg_alloc_free_page_low(space, - inode, 0, FSP_UP, mtr, mtr); + page = fseg_alloc_free_page_low(space, inode, 0, FSP_UP, mtr); if (page == FIL_NULL) { @@ -2365,12 +2339,7 @@ fseg_alloc_free_page_low( inserted there in order, into which direction they go alphabetically: FSP_DOWN, FSP_UP, FSP_NO_DIR */ - mtr_t* mtr, /* in/out: mini-transaction */ - mtr_t* init_mtr)/* in/out: mini-transaction in which the - page should be initialized - (may be the same as mtr), or NULL if it - should not be initialized (the page at hint - was previously freed in mtr) */ + mtr_t* mtr) /* in/out: mini-transaction */ { fsp_header_t* space_header; ulint space_size; @@ -2382,6 +2351,7 @@ fseg_alloc_free_page_low( if could not be allocated */ xdes_t* ret_descr; /* the extent of the allocated page */ page_t* page; + ibool frag_page_allocated = FALSE; ibool success; ulint n; @@ -2402,8 +2372,6 @@ fseg_alloc_free_page_low( if (descr == NULL) { /* Hint outside space or too high above free limit: reset hint */ - ut_a(init_mtr); - /* The file space header page is always allocated. */ hint = 0; descr = xdes_get_descriptor(space, hint, mtr); } @@ -2415,20 +2383,15 @@ fseg_alloc_free_page_low( mtr), seg_id)) && (xdes_get_bit(descr, XDES_FREE_BIT, hint % FSP_EXTENT_SIZE, mtr) == TRUE)) { -take_hinted_page: + /* 1. We can take the hinted page =================================*/ ret_descr = descr; ret_page = hint; - /* Skip the check for extending the tablespace. If the - page hint were not within the size of the tablespace, - we would have got (descr == NULL) above and reset the hint. */ - goto got_hinted_page; /*-----------------------------------------------------------*/ - } else if (xdes_get_state(descr, mtr) == XDES_FREE - && (!init_mtr - || ((reserved - used < reserved / FSEG_FILLFACTOR) - && used >= FSEG_FRAG_LIMIT))) { + } else if ((xdes_get_state(descr, mtr) == XDES_FREE) + && ((reserved - used) < reserved / FSEG_FILLFACTOR) + && (used >= FSEG_FRAG_LIMIT)) { /* 2. We allocate the free extent from space and can take ========================================================= @@ -2446,20 +2409,8 @@ take_hinted_page: /* Try to fill the segment free list */ fseg_fill_free_list(seg_inode, space, hint + FSP_EXTENT_SIZE, mtr); - goto take_hinted_page; - /*-----------------------------------------------------------*/ - } else if (!init_mtr) { - ut_a(xdes_get_state(descr, mtr) == XDES_FREE_FRAG); - fsp_alloc_from_free_frag(space_header, descr, - hint % FSP_EXTENT_SIZE, mtr); ret_page = hint; - ret_descr = NULL; - - /* Put the page in the fragment page array of the segment */ - n = fseg_find_free_frag_page_slot(seg_inode, mtr); - ut_a(n != FIL_NULL); - fseg_set_nth_frag_page_no(seg_inode, n, ret_page, mtr); - goto got_hinted_page; + /*-----------------------------------------------------------*/ } else if ((direction != FSP_NO_DIR) && ((reserved - used) < reserved / FSEG_FILLFACTOR) && (used >= FSEG_FRAG_LIMIT) @@ -2517,9 +2468,11 @@ take_hinted_page: } else if (used < FSEG_FRAG_LIMIT) { /* 6. We allocate an individual page from the space ===================================================*/ - ret_page = fsp_alloc_free_page(space, hint, mtr, init_mtr); + ret_page = fsp_alloc_free_page(space, hint, mtr); ret_descr = NULL; + frag_page_allocated = TRUE; + if (ret_page != FIL_NULL) { /* Put the page in the fragment page array of the segment */ @@ -2529,10 +2482,6 @@ take_hinted_page: fseg_set_nth_frag_page_no(seg_inode, n, ret_page, mtr); } - - /* fsp_alloc_free_page() invoked fsp_init_file_page() - already. */ - return(ret_page); /*-----------------------------------------------------------*/ } else { /* 7. We allocate a new extent and take its first page @@ -2579,31 +2528,22 @@ take_hinted_page: } } -got_hinted_page: - { + if (!frag_page_allocated) { /* Initialize the allocated page to buffer pool, so that it can be obtained immediately with buf_page_get without need for a disk read */ - mtr_t* block_mtr = init_mtr ? init_mtr : mtr; - page = buf_page_create(space, ret_page, block_mtr); + page = buf_page_create(space, ret_page, mtr); - ut_a(page == buf_page_get(space, ret_page, RW_X_LATCH, - block_mtr)); + ut_a(page == buf_page_get(space, ret_page, RW_X_LATCH, mtr)); #ifdef UNIV_SYNC_DEBUG buf_page_dbg_add_level(page, SYNC_FSP_PAGE); #endif /* UNIV_SYNC_DEBUG */ - if (init_mtr) { - /* The prior contents of the page should be ignored */ - fsp_init_file_page(page, init_mtr); - } - } + /* The prior contents of the page should be ignored */ + fsp_init_file_page(page, mtr); - /* ret_descr == NULL if the block was allocated from free_frag - (XDES_FREE_FRAG) */ - if (ret_descr != NULL) { /* At this point we know the extent and the page offset. The extent is still in the appropriate list (FSEG_NOT_FULL or FSEG_FREE), and the page is not yet marked as used. */ @@ -2640,11 +2580,7 @@ fseg_alloc_free_page_general( with fsp_reserve_free_extents, then there is no need to do the check for this individual page */ - mtr_t* mtr, /* in/out: mini-transaction handle */ - mtr_t* init_mtr)/* in/out: mtr or another mini-transaction - in which the page should be initialized, - or NULL if this is a "fake allocation" of - a page that was previously freed in mtr */ + mtr_t* mtr) /* in/out: mini-transaction */ { fseg_inode_t* inode; ulint space; @@ -2682,8 +2618,7 @@ fseg_alloc_free_page_general( } page_no = fseg_alloc_free_page_low(buf_frame_get_space_id(inode), - inode, hint, direction, - mtr, init_mtr); + inode, hint, direction, mtr); if (!has_done_reservation) { fil_space_release_free_extents(space, n_reserved); } @@ -2711,7 +2646,7 @@ fseg_alloc_free_page( mtr_t* mtr) /* in: mtr handle */ { return(fseg_alloc_free_page_general(seg_header, hint, direction, - FALSE, mtr, mtr)); + FALSE, mtr)); } /************************************************************************** diff --git a/storage/innobase/include/btr0btr.h b/storage/innobase/include/btr0btr.h index 3988019589d..269fa355558 100644 --- a/storage/innobase/include/btr0btr.h +++ b/storage/innobase/include/btr0btr.h @@ -379,11 +379,7 @@ btr_page_alloc( page split is made */ ulint level, /* in: level where the page is placed in the tree */ - mtr_t* mtr, /* in/out: mini-transaction - for the allocation */ - mtr_t* init_mtr); /* in/out: mini-transaction - for x-latching and initializing - the page */ + mtr_t* mtr); /* in: mtr */ /****************************************************************** Frees a file page used in an index tree. NOTE: cannot free field external storage pages because the page must contain info on its level. */ @@ -406,31 +402,6 @@ btr_page_free_low( page_t* page, /* in: page to be freed, x-latched */ ulint level, /* in: page level */ mtr_t* mtr); /* in: mtr */ -/**************************************************************//** -Marks all MTR_MEMO_FREE_CLUST_LEAF pages nonfree or free. -For invoking btr_store_big_rec_extern_fields() after an update, -we must temporarily mark freed clustered index pages allocated, so -that off-page columns will not be allocated from them. Between the -btr_store_big_rec_extern_fields() and mtr_commit() we have to -mark the pages free again, so that no pages will be leaked. */ - -void -btr_mark_freed_leaves( -/*==================*/ - dict_index_t* index, /* in/out: clustered index */ - mtr_t* mtr, /* in/out: mini-transaction */ - ibool nonfree);/* in: TRUE=mark nonfree, FALSE=mark freed */ -#ifdef UNIV_DEBUG -/**************************************************************//** -Validates all pages marked MTR_MEMO_FREE_CLUST_LEAF. -See btr_mark_freed_leaves(). */ - -ibool -btr_freed_leaves_validate( -/*======================*/ - /* out: TRUE if valid */ - mtr_t* mtr); /* in: mini-transaction */ -#endif /* UNIV_DEBUG */ #ifdef UNIV_BTR_PRINT /***************************************************************** Prints size info of a B-tree. */ diff --git a/storage/innobase/include/btr0cur.h b/storage/innobase/include/btr0cur.h index c2bf84ef9cb..c068d8d3318 100644 --- a/storage/innobase/include/btr0cur.h +++ b/storage/innobase/include/btr0cur.h @@ -252,6 +252,15 @@ btr_cur_pessimistic_update( updates */ que_thr_t* thr, /* in: query thread */ mtr_t* mtr); /* in: mtr */ +/***************************************************************** +Commits and restarts a mini-transaction so that it will retain an +x-lock on index->lock and the cursor page. */ + +void +btr_cur_mtr_commit_and_start( +/*=========================*/ + btr_cur_t* cursor, /* in: cursor */ + mtr_t* mtr); /* in/out: mini-transaction */ /*************************************************************** Marks a clustered index record deleted. Writes an undo log record to undo log on this delete marking. Writes in the trx id field the id @@ -462,11 +471,6 @@ btr_store_big_rec_extern_fields( this function returns */ big_rec_t* big_rec_vec, /* in: vector containing fields to be stored externally */ - mtr_t* alloc_mtr, /* in/out: in an insert, NULL; - in an update, local_mtr for - allocating BLOB pages and - updating BLOB pointers; alloc_mtr - must not have freed any leaf pages */ mtr_t* local_mtr); /* in: mtr containing the latch to rec and to the tree */ /*********************************************************************** diff --git a/storage/innobase/include/fsp0fsp.h b/storage/innobase/include/fsp0fsp.h index 4c58d6075e6..b7322944189 100644 --- a/storage/innobase/include/fsp0fsp.h +++ b/storage/innobase/include/fsp0fsp.h @@ -179,11 +179,7 @@ fseg_alloc_free_page_general( with fsp_reserve_free_extents, then there is no need to do the check for this individual page */ - mtr_t* mtr, /* in/out: mini-transaction */ - mtr_t* init_mtr);/* in/out: mtr or another mini-transaction - in which the page should be initialized, - or NULL if this is a "fake allocation" of - a page that was previously freed in mtr */ + mtr_t* mtr); /* in/out: mini-transaction */ /************************************************************************** Reserves free pages from a tablespace. All mini-transactions which may use several pages from the tablespace should call this function beforehand diff --git a/storage/innobase/include/mtr0mtr.h b/storage/innobase/include/mtr0mtr.h index 58983063361..2b41fa0059a 100644 --- a/storage/innobase/include/mtr0mtr.h +++ b/storage/innobase/include/mtr0mtr.h @@ -36,8 +36,6 @@ first 3 values must be RW_S_LATCH, RW_X_LATCH, RW_NO_LATCH */ #define MTR_MEMO_MODIFY 54 #define MTR_MEMO_S_LOCK 55 #define MTR_MEMO_X_LOCK 56 -/* The mini-transaction freed a clustered index leaf page. */ -#define MTR_MEMO_FREE_CLUST_LEAF 57 /* Log item types: we have made them to be of the type 'byte' for the compiler to warn if val and type parameters are switched @@ -317,12 +315,9 @@ struct mtr_struct{ ulint state; /* MTR_ACTIVE, MTR_COMMITTING, MTR_COMMITTED */ dyn_array_t memo; /* memo stack for locks etc. */ dyn_array_t log; /* mini-transaction log */ - unsigned modifications:1; + ibool modifications; /* TRUE if the mtr made modifications to buffer pool pages */ - unsigned freed_clust_leaf:1; - /* TRUE if MTR_MEMO_FREE_CLUST_LEAF - was logged in the mini-transaction */ ulint n_log_recs; /* count of how many page initial log records have been written to the mtr log */ diff --git a/storage/innobase/include/mtr0mtr.ic b/storage/innobase/include/mtr0mtr.ic index 6b4cacf0766..81eec3bfc92 100644 --- a/storage/innobase/include/mtr0mtr.ic +++ b/storage/innobase/include/mtr0mtr.ic @@ -26,7 +26,6 @@ mtr_start( mtr->log_mode = MTR_LOG_ALL; mtr->modifications = FALSE; - mtr->freed_clust_leaf = FALSE; mtr->n_log_recs = 0; #ifdef UNIV_DEBUG @@ -51,8 +50,7 @@ mtr_memo_push( ut_ad(object); ut_ad(type >= MTR_MEMO_PAGE_S_FIX); - ut_ad(type <= MTR_MEMO_FREE_CLUST_LEAF); - ut_ad(type != MTR_MEMO_FREE_CLUST_LEAF || mtr->freed_clust_leaf); + ut_ad(type <= MTR_MEMO_X_LOCK); ut_ad(mtr); ut_ad(mtr->magic_n == MTR_MAGIC_N); diff --git a/storage/innobase/mtr/mtr0mtr.c b/storage/innobase/mtr/mtr0mtr.c index 33b71f0766c..728c37ce564 100644 --- a/storage/innobase/mtr/mtr0mtr.c +++ b/storage/innobase/mtr/mtr0mtr.c @@ -53,13 +53,17 @@ mtr_memo_slot_release( buf_page_release((buf_block_t*)object, type, mtr); } else if (type == MTR_MEMO_S_LOCK) { rw_lock_s_unlock((rw_lock_t*)object); - } else if (type != MTR_MEMO_X_LOCK) { - ut_ad(type == MTR_MEMO_MODIFY - || type == MTR_MEMO_FREE_CLUST_LEAF); +#ifdef UNIV_DEBUG + } else if (type == MTR_MEMO_X_LOCK) { + rw_lock_x_unlock((rw_lock_t*)object); + } else { + ut_ad(type == MTR_MEMO_MODIFY); ut_ad(mtr_memo_contains(mtr, object, MTR_MEMO_PAGE_X_FIX)); +#else } else { rw_lock_x_unlock((rw_lock_t*)object); +#endif } } diff --git a/storage/innobase/row/row0ins.c b/storage/innobase/row/row0ins.c index f6e6c81534b..c3b8f54a3c5 100644 --- a/storage/innobase/row/row0ins.c +++ b/storage/innobase/row/row0ins.c @@ -2090,20 +2090,15 @@ row_ins_index_entry_low( if (big_rec) { ut_a(err == DB_SUCCESS); /* Write out the externally stored - columns, but allocate the pages and - write the pointers using the - mini-transaction of the record update. - If any pages were freed in the update, - temporarily mark them allocated so - that off-page columns will not - overwrite them. We must do this, - because we will write the redo log for - the BLOB writes before writing the - redo log for the record update. Thus, - redo log application at crash recovery - will see BLOBs being written to free pages. */ - - btr_mark_freed_leaves(index, &mtr, TRUE); + columns while still x-latching + index->lock and block->lock. We have + to mtr_commit(mtr) first, so that the + redo log will be written in the + correct order. Otherwise, we would run + into trouble on crash recovery if mtr + freed B-tree pages on which some of + the big_rec fields will be written. */ + btr_cur_mtr_commit_and_start(&cursor, &mtr); rec = btr_cur_get_rec(&cursor); offsets = rec_get_offsets(rec, index, offsets, @@ -2111,8 +2106,7 @@ row_ins_index_entry_low( &heap); err = btr_store_big_rec_extern_fields( - index, rec, offsets, big_rec, - &mtr, &mtr); + index, rec, offsets, big_rec, &mtr); /* If writing big_rec fails (for example, because of DB_OUT_OF_FILE_SPACE), the record will be corrupted. Even if @@ -2125,9 +2119,6 @@ row_ins_index_entry_low( undo log, and thus the record cannot be rolled back. */ ut_a(err == DB_SUCCESS); - /* Free the pages again - in order to avoid a leak. */ - btr_mark_freed_leaves(index, &mtr, FALSE); goto stored_big_rec; } } else { @@ -2175,8 +2166,7 @@ function_exit: ULINT_UNDEFINED, &heap); err = btr_store_big_rec_extern_fields(index, rec, - offsets, big_rec, - NULL, &mtr); + offsets, big_rec, &mtr); stored_big_rec: if (modify) { dtuple_big_rec_free(big_rec); diff --git a/storage/innobase/row/row0row.c b/storage/innobase/row/row0row.c index ccb3c1f7781..171039e34ac 100644 --- a/storage/innobase/row/row0row.c +++ b/storage/innobase/row/row0row.c @@ -212,27 +212,23 @@ row_build( } #if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG - if (rec_offs_any_null_extern(rec, offsets)) { - /* This condition can occur during crash recovery - before trx_rollback_or_clean_all_without_sess() has - completed execution. + /* This condition can occur during crash recovery before + trx_rollback_or_clean_all_without_sess() has completed + execution. - This condition is possible if the server crashed - during an insert or update before - btr_store_big_rec_extern_fields() did mtr_commit() all - BLOB pointers to the clustered index record. + This condition is possible if the server crashed + during an insert or update before + btr_store_big_rec_extern_fields() did mtr_commit() all + BLOB pointers to the clustered index record. - If the record contains a null BLOB pointer, look up the - transaction that holds the implicit lock on this record, and - assert that it is active. (In this version of InnoDB, we - cannot assert that it was recovered, because there is no - trx->is_recovered field.) */ + If the record contains a null BLOB pointer, look up the + transaction that holds the implicit lock on this record, and + assert that it is active. (In this version of InnoDB, we + cannot assert that it was recovered, because there is no + trx->is_recovered field.) */ - ut_a(trx_assert_active( - row_get_rec_trx_id(rec, index, offsets))); - ut_a(trx_undo_roll_ptr_is_insert( - row_get_rec_roll_ptr(rec, index, offsets))); - } + ut_a(!rec_offs_any_null_extern(rec, offsets) + || trx_assert_active(row_get_rec_trx_id(rec, index, offsets))); #endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ if (type != ROW_COPY_POINTERS) { diff --git a/storage/innobase/row/row0upd.c b/storage/innobase/row/row0upd.c index 58739edfd98..694b00ea265 100644 --- a/storage/innobase/row/row0upd.c +++ b/storage/innobase/row/row0upd.c @@ -1591,22 +1591,21 @@ row_upd_clust_rec( *offsets_ = (sizeof offsets_) / sizeof *offsets_; ut_a(err == DB_SUCCESS); - /* Write out the externally stored columns, but - allocate the pages and write the pointers using the - mini-transaction of the record update. If any pages - were freed in the update, temporarily mark them - allocated so that off-page columns will not overwrite - them. We must do this, because we write the redo log - for the BLOB writes before writing the redo log for - the record update. */ + /* Write out the externally stored columns while still + x-latching index->lock and block->lock. We have to + mtr_commit(mtr) first, so that the redo log will be + written in the correct order. Otherwise, we would run + into trouble on crash recovery if mtr freed B-tree + pages on which some of the big_rec fields will be + written. */ + btr_cur_mtr_commit_and_start(btr_cur, mtr); - btr_mark_freed_leaves(index, mtr, TRUE); rec = btr_cur_get_rec(btr_cur); err = btr_store_big_rec_extern_fields( index, rec, rec_get_offsets(rec, index, offsets_, ULINT_UNDEFINED, &heap), - big_rec, mtr, mtr); + big_rec, mtr); if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); } @@ -1619,8 +1618,6 @@ row_upd_clust_rec( to the undo log, and thus the record cannot be rolled back. */ ut_a(err == DB_SUCCESS); - /* Free the pages again in order to avoid a leak. */ - btr_mark_freed_leaves(index, mtr, FALSE); } mtr_commit(mtr); diff --git a/storage/innobase/trx/trx0undo.c b/storage/innobase/trx/trx0undo.c index ce09862f317..329565943c8 100644 --- a/storage/innobase/trx/trx0undo.c +++ b/storage/innobase/trx/trx0undo.c @@ -864,7 +864,7 @@ trx_undo_add_page( page_no = fseg_alloc_free_page_general(header_page + TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER, undo->top_page_no + 1, FSP_UP, - TRUE, mtr, mtr); + TRUE, mtr); fil_space_release_free_extents(undo->space, n_reserved); diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index 4e6e2be615a..e6724eb08c2 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -50,15 +50,6 @@ * include/trx0undo.h, trx/trx0rec.c, trx/trx0undo.c: Fix Bug#12547647 UPDATE LOGGING COULD EXCEED LOG PAGE SIZE -2011-08-29 The InnoDB Team - - * btr/btr0btr.c, btr/btr0cur.c, fsp/fsp0fsp.c, - include/btr0btr.h, include/btr0cur.h, include/fsp0fsp.h, - include/mtr0mtr.h, include/mtr0mtr.ic, mtr/mtr0mtr.c, - row/row0ins.c, row/row0row.c, row/row0upd.c, trx/trx0undo.c: - Fix Bug#12704861 Corruption after a crash during BLOB update - and other regressions from the fix of Bug#12612184 - 2011-08-15 The InnoDB Team * btr/btr0btr.c, btr/btr0cur.c, btr/btr0pcur.c, btr/btr0sea.c, diff --git a/storage/innodb_plugin/btr/btr0btr.c b/storage/innodb_plugin/btr/btr0btr.c index 71e1599d19e..cb94ef08cd6 100644 --- a/storage/innodb_plugin/btr/btr0btr.c +++ b/storage/innodb_plugin/btr/btr0btr.c @@ -906,29 +906,28 @@ btr_page_alloc_for_ibuf( /**************************************************************//** Allocates a new file page to be used in an index tree. NOTE: we assume that the caller has made the reservation for free extents! -@return allocated page number, FIL_NULL if out of space */ -static __attribute__((nonnull(1,5), warn_unused_result)) -ulint -btr_page_alloc_low( -/*===============*/ +@return new allocated block, x-latched; NULL if out of space */ +UNIV_INTERN +buf_block_t* +btr_page_alloc( +/*===========*/ dict_index_t* index, /*!< in: index */ ulint hint_page_no, /*!< in: hint of a good page */ byte file_direction, /*!< in: direction where a possible page split is made */ ulint level, /*!< in: level where the page is placed in the tree */ - mtr_t* mtr, /*!< in/out: mini-transaction - for the allocation */ - mtr_t* init_mtr) /*!< in/out: mini-transaction - in which the page should be - initialized (may be the same - as mtr), or NULL if it should - not be initialized (the page - at hint was previously freed - in mtr) */ + mtr_t* mtr) /*!< in: mtr */ { fseg_header_t* seg_header; page_t* root; + buf_block_t* new_block; + ulint new_page_no; + + if (dict_index_is_ibuf(index)) { + + return(btr_page_alloc_for_ibuf(index, mtr)); + } root = btr_root_get(index, mtr); @@ -942,42 +941,8 @@ btr_page_alloc_low( reservation for free extents, and thus we know that a page can be allocated: */ - return(fseg_alloc_free_page_general( - seg_header, hint_page_no, file_direction, - TRUE, mtr, init_mtr)); -} - -/**************************************************************//** -Allocates a new file page to be used in an index tree. NOTE: we assume -that the caller has made the reservation for free extents! -@return new allocated block, x-latched; NULL if out of space */ -UNIV_INTERN -buf_block_t* -btr_page_alloc( -/*===========*/ - dict_index_t* index, /*!< in: index */ - ulint hint_page_no, /*!< in: hint of a good page */ - byte file_direction, /*!< in: direction where a possible - page split is made */ - ulint level, /*!< in: level where the page is placed - in the tree */ - mtr_t* mtr, /*!< in/out: mini-transaction - for the allocation */ - mtr_t* init_mtr) /*!< in/out: mini-transaction - for x-latching and initializing - the page */ -{ - buf_block_t* new_block; - ulint new_page_no; - - if (dict_index_is_ibuf(index)) { - - return(btr_page_alloc_for_ibuf(index, mtr)); - } - - new_page_no = btr_page_alloc_low( - index, hint_page_no, file_direction, level, mtr, init_mtr); - + new_page_no = fseg_alloc_free_page_general(seg_header, hint_page_no, + file_direction, TRUE, mtr); if (new_page_no == FIL_NULL) { return(NULL); @@ -985,16 +950,9 @@ btr_page_alloc( new_block = buf_page_get(dict_index_get_space(index), dict_table_zip_size(index->table), - new_page_no, RW_X_LATCH, init_mtr); + new_page_no, RW_X_LATCH, mtr); buf_block_dbg_add_level(new_block, SYNC_TREE_NODE_NEW); - if (mtr->freed_clust_leaf) { - mtr_memo_release(mtr, new_block, MTR_MEMO_FREE_CLUST_LEAF); - ut_ad(!mtr_memo_contains(mtr, new_block, - MTR_MEMO_FREE_CLUST_LEAF)); - } - - ut_ad(btr_freed_leaves_validate(mtr)); return(new_block); } @@ -1129,140 +1087,13 @@ btr_page_free( buf_block_t* block, /*!< in: block to be freed, x-latched */ mtr_t* mtr) /*!< in: mtr */ { - const page_t* page = buf_block_get_frame(block); - ulint level = btr_page_get_level(page, mtr); + ulint level; + + level = btr_page_get_level(buf_block_get_frame(block), mtr); - ut_ad(fil_page_get_type(block->frame) == FIL_PAGE_INDEX); btr_page_free_low(index, block, level, mtr); - - /* The handling of MTR_MEMO_FREE_CLUST_LEAF assumes this. */ - ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); - - if (level == 0 && dict_index_is_clust(index)) { - /* We may have to call btr_mark_freed_leaves() to - temporarily mark the block nonfree for invoking - btr_store_big_rec_extern_fields_func() after an - update. Remember that the block was freed. */ - mtr->freed_clust_leaf = TRUE; - mtr_memo_push(mtr, block, MTR_MEMO_FREE_CLUST_LEAF); - } - - ut_ad(btr_freed_leaves_validate(mtr)); } -/**************************************************************//** -Marks all MTR_MEMO_FREE_CLUST_LEAF pages nonfree or free. -For invoking btr_store_big_rec_extern_fields() after an update, -we must temporarily mark freed clustered index pages allocated, so -that off-page columns will not be allocated from them. Between the -btr_store_big_rec_extern_fields() and mtr_commit() we have to -mark the pages free again, so that no pages will be leaked. */ -UNIV_INTERN -void -btr_mark_freed_leaves( -/*==================*/ - dict_index_t* index, /*!< in/out: clustered index */ - mtr_t* mtr, /*!< in/out: mini-transaction */ - ibool nonfree)/*!< in: TRUE=mark nonfree, FALSE=mark freed */ -{ - /* This is loosely based on mtr_memo_release(). */ - - ulint offset; - - ut_ad(dict_index_is_clust(index)); - ut_ad(mtr->magic_n == MTR_MAGIC_N); - ut_ad(mtr->state == MTR_ACTIVE); - - if (!mtr->freed_clust_leaf) { - return; - } - - offset = dyn_array_get_data_size(&mtr->memo); - - while (offset > 0) { - mtr_memo_slot_t* slot; - buf_block_t* block; - - offset -= sizeof *slot; - - slot = dyn_array_get_element(&mtr->memo, offset); - - if (slot->type != MTR_MEMO_FREE_CLUST_LEAF) { - continue; - } - - /* Because btr_page_alloc() does invoke - mtr_memo_release on MTR_MEMO_FREE_CLUST_LEAF, all - blocks tagged with MTR_MEMO_FREE_CLUST_LEAF in the - memo must still be clustered index leaf tree pages. */ - block = slot->object; - ut_a(buf_block_get_space(block) - == dict_index_get_space(index)); - ut_a(fil_page_get_type(buf_block_get_frame(block)) - == FIL_PAGE_INDEX); - ut_a(page_is_leaf(buf_block_get_frame(block))); - - if (nonfree) { - /* Allocate the same page again. */ - ulint page_no; - page_no = btr_page_alloc_low( - index, buf_block_get_page_no(block), - FSP_NO_DIR, 0, mtr, NULL); - ut_a(page_no == buf_block_get_page_no(block)); - } else { - /* Assert that the page is allocated and free it. */ - btr_page_free_low(index, block, 0, mtr); - } - } - - ut_ad(btr_freed_leaves_validate(mtr)); -} - -#ifdef UNIV_DEBUG -/**************************************************************//** -Validates all pages marked MTR_MEMO_FREE_CLUST_LEAF. -@see btr_mark_freed_leaves() -@return TRUE */ -UNIV_INTERN -ibool -btr_freed_leaves_validate( -/*======================*/ - mtr_t* mtr) /*!< in: mini-transaction */ -{ - ulint offset; - - ut_ad(mtr->magic_n == MTR_MAGIC_N); - ut_ad(mtr->state == MTR_ACTIVE); - - offset = dyn_array_get_data_size(&mtr->memo); - - while (offset > 0) { - const mtr_memo_slot_t* slot; - const buf_block_t* block; - - offset -= sizeof *slot; - - slot = dyn_array_get_element(&mtr->memo, offset); - - if (slot->type != MTR_MEMO_FREE_CLUST_LEAF) { - continue; - } - - ut_a(mtr->freed_clust_leaf); - /* Because btr_page_alloc() does invoke - mtr_memo_release on MTR_MEMO_FREE_CLUST_LEAF, all - blocks tagged with MTR_MEMO_FREE_CLUST_LEAF in the - memo must still be clustered index leaf tree pages. */ - block = slot->object; - ut_a(fil_page_get_type(buf_block_get_frame(block)) - == FIL_PAGE_INDEX); - ut_a(page_is_leaf(buf_block_get_frame(block))); - } - - return(TRUE); -} -#endif /* UNIV_DEBUG */ - /**************************************************************//** Sets the child node file address in a node pointer. */ UNIV_INLINE @@ -1984,7 +1815,7 @@ btr_root_raise_and_insert( level = btr_page_get_level(root, mtr); - new_block = btr_page_alloc(index, 0, FSP_NO_DIR, level, mtr, mtr); + new_block = btr_page_alloc(index, 0, FSP_NO_DIR, level, mtr); new_page = buf_block_get_frame(new_block); new_page_zip = buf_block_get_page_zip(new_block); ut_a(!new_page_zip == !root_page_zip); @@ -2720,7 +2551,7 @@ func_start: /* 2. Allocate a new page to the index */ new_block = btr_page_alloc(cursor->index, hint_page_no, direction, - btr_page_get_level(page, mtr), mtr, mtr); + btr_page_get_level(page, mtr), mtr); new_page = buf_block_get_frame(new_block); new_page_zip = buf_block_get_page_zip(new_block); btr_page_create(new_block, new_page_zip, cursor->index, diff --git a/storage/innodb_plugin/btr/btr0cur.c b/storage/innodb_plugin/btr/btr0cur.c index 1e603a6fc81..4c862f061c5 100644 --- a/storage/innodb_plugin/btr/btr0cur.c +++ b/storage/innodb_plugin/btr/btr0cur.c @@ -2421,6 +2421,39 @@ return_after_reservations: return(err); } +/**************************************************************//** +Commits and restarts a mini-transaction so that it will retain an +x-lock on index->lock and the cursor page. */ +UNIV_INTERN +void +btr_cur_mtr_commit_and_start( +/*=========================*/ + btr_cur_t* cursor, /*!< in: cursor */ + mtr_t* mtr) /*!< in/out: mini-transaction */ +{ + buf_block_t* block; + + block = btr_cur_get_block(cursor); + + ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(cursor->index), + MTR_MEMO_X_LOCK)); + ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); + /* Keep the locks across the mtr_commit(mtr). */ + rw_lock_x_lock(dict_index_get_lock(cursor->index)); + rw_lock_x_lock(&block->lock); + mutex_enter(&block->mutex); + buf_block_buf_fix_inc(block, __FILE__, __LINE__); + mutex_exit(&block->mutex); + /* Write out the redo log. */ + mtr_commit(mtr); + mtr_start(mtr); + /* Reassociate the locks with the mini-transaction. + They will be released on mtr_commit(mtr). */ + mtr_memo_push(mtr, dict_index_get_lock(cursor->index), + MTR_MEMO_X_LOCK); + mtr_memo_push(mtr, block, MTR_MEMO_PAGE_X_FIX); +} + /*==================== B-TREE DELETE MARK AND UNMARK ===============*/ /****************************************************************//** @@ -3863,9 +3896,6 @@ btr_store_big_rec_extern_fields_func( the "external storage" flags in offsets will not correspond to rec when this function returns */ - const big_rec_t*big_rec_vec, /*!< in: vector containing fields - to be stored externally */ - #ifdef UNIV_DEBUG mtr_t* local_mtr, /*!< in: mtr containing the latch to rec and to the tree */ @@ -3874,11 +3904,9 @@ btr_store_big_rec_extern_fields_func( ibool update_in_place,/*! in: TRUE if the record is updated in place (not delete+insert) */ #endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ - mtr_t* alloc_mtr) /*!< in/out: in an insert, NULL; - in an update, local_mtr for - allocating BLOB pages and - updating BLOB pointers; alloc_mtr - must not have freed any leaf pages */ + const big_rec_t*big_rec_vec) /*!< in: vector containing fields + to be stored externally */ + { ulint rec_page_no; byte* field_ref; @@ -3897,9 +3925,6 @@ btr_store_big_rec_extern_fields_func( ut_ad(rec_offs_validate(rec, index, offsets)); ut_ad(rec_offs_any_extern(offsets)); - ut_ad(local_mtr); - ut_ad(!alloc_mtr || alloc_mtr == local_mtr); - ut_ad(!update_in_place || alloc_mtr); ut_ad(mtr_memo_contains(local_mtr, dict_index_get_lock(index), MTR_MEMO_X_LOCK)); ut_ad(mtr_memo_contains(local_mtr, rec_block, MTR_MEMO_PAGE_X_FIX)); @@ -3915,25 +3940,6 @@ btr_store_big_rec_extern_fields_func( rec_page_no = buf_block_get_page_no(rec_block); ut_a(fil_page_get_type(page_align(rec)) == FIL_PAGE_INDEX); - if (alloc_mtr) { - /* Because alloc_mtr will be committed after - mtr, it is possible that the tablespace has been - extended when the B-tree record was updated or - inserted, or it will be extended while allocating - pages for big_rec. - - TODO: In mtr (not alloc_mtr), write a redo log record - about extending the tablespace to its current size, - and remember the current size. Whenever the tablespace - grows as pages are allocated, write further redo log - records to mtr. (Currently tablespace extension is not - covered by the redo log. If it were, the record would - only be written to alloc_mtr, which is committed after - mtr.) */ - } else { - alloc_mtr = &mtr; - } - if (UNIV_LIKELY_NULL(page_zip)) { int err; @@ -4010,7 +4016,7 @@ btr_store_big_rec_extern_fields_func( } block = btr_page_alloc(index, hint_page_no, - FSP_NO_DIR, 0, alloc_mtr, &mtr); + FSP_NO_DIR, 0, &mtr); if (UNIV_UNLIKELY(block == NULL)) { mtr_commit(&mtr); @@ -4137,15 +4143,11 @@ btr_store_big_rec_extern_fields_func( goto next_zip_page; } - if (alloc_mtr == &mtr) { - rec_block = buf_page_get( - space_id, zip_size, - rec_page_no, - RW_X_LATCH, &mtr); - buf_block_dbg_add_level( - rec_block, - SYNC_NO_ORDER_CHECK); - } + rec_block = buf_page_get(space_id, zip_size, + rec_page_no, + RW_X_LATCH, &mtr); + buf_block_dbg_add_level(rec_block, + SYNC_NO_ORDER_CHECK); if (err == Z_STREAM_END) { mach_write_to_4(field_ref @@ -4179,8 +4181,7 @@ btr_store_big_rec_extern_fields_func( page_zip_write_blob_ptr( page_zip, rec, index, offsets, - big_rec_vec->fields[i].field_no, - alloc_mtr); + big_rec_vec->fields[i].field_no, &mtr); next_zip_page: prev_page_no = page_no; @@ -4225,23 +4226,19 @@ next_zip_page: extern_len -= store_len; - if (alloc_mtr == &mtr) { - rec_block = buf_page_get( - space_id, zip_size, - rec_page_no, - RW_X_LATCH, &mtr); - buf_block_dbg_add_level( - rec_block, - SYNC_NO_ORDER_CHECK); - } + rec_block = buf_page_get(space_id, zip_size, + rec_page_no, + RW_X_LATCH, &mtr); + buf_block_dbg_add_level(rec_block, + SYNC_NO_ORDER_CHECK); mlog_write_ulint(field_ref + BTR_EXTERN_LEN, 0, - MLOG_4BYTES, alloc_mtr); + MLOG_4BYTES, &mtr); mlog_write_ulint(field_ref + BTR_EXTERN_LEN + 4, big_rec_vec->fields[i].len - extern_len, - MLOG_4BYTES, alloc_mtr); + MLOG_4BYTES, &mtr); if (prev_page_no == FIL_NULL) { btr_blob_dbg_add_blob( @@ -4251,19 +4248,18 @@ next_zip_page: mlog_write_ulint(field_ref + BTR_EXTERN_SPACE_ID, - space_id, MLOG_4BYTES, - alloc_mtr); + space_id, + MLOG_4BYTES, &mtr); mlog_write_ulint(field_ref + BTR_EXTERN_PAGE_NO, - page_no, MLOG_4BYTES, - alloc_mtr); + page_no, + MLOG_4BYTES, &mtr); mlog_write_ulint(field_ref + BTR_EXTERN_OFFSET, FIL_PAGE_DATA, - MLOG_4BYTES, - alloc_mtr); + MLOG_4BYTES, &mtr); } prev_page_no = page_no; diff --git a/storage/innodb_plugin/fsp/fsp0fsp.c b/storage/innodb_plugin/fsp/fsp0fsp.c index 19846b63d5b..fee7fde2e5c 100644 --- a/storage/innodb_plugin/fsp/fsp0fsp.c +++ b/storage/innodb_plugin/fsp/fsp0fsp.c @@ -312,9 +312,8 @@ fsp_fill_free_list( descriptor page and ibuf bitmap page; then we do not allocate more extents */ ulint space, /*!< in: space */ - fsp_header_t* header, /*!< in/out: space header */ - mtr_t* mtr) /*!< in/out: mini-transaction */ - __attribute__((nonnull)); + fsp_header_t* header, /*!< in: space header */ + mtr_t* mtr); /*!< in: mtr */ /**********************************************************************//** Allocates a single free page from a segment. This function implements the intelligent allocation strategy which tries to minimize file space @@ -334,13 +333,7 @@ fseg_alloc_free_page_low( inserted there in order, into which direction they go alphabetically: FSP_DOWN, FSP_UP, FSP_NO_DIR */ - mtr_t* mtr, /*!< in/out: mini-transaction */ - mtr_t* init_mtr)/*!< in/out: mini-transaction in which the - page should be initialized - (may be the same as mtr), or NULL if it - should not be initialized (the page at hint - was previously freed in mtr) */ - __attribute__((warn_unused_result, nonnull(3,6))); + mtr_t* mtr); /*!< in/out: mini-transaction */ #endif /* !UNIV_HOTBACKUP */ /**********************************************************************//** @@ -708,18 +701,17 @@ list, if not free limit == space size. This adding is necessary to make the descriptor defined, as they are uninitialized above the free limit. @return pointer to the extent descriptor, NULL if the page does not exist in the space or if the offset exceeds the free limit */ -UNIV_INLINE __attribute__((nonnull, warn_unused_result)) +UNIV_INLINE xdes_t* xdes_get_descriptor_with_space_hdr( /*===============================*/ - fsp_header_t* sp_header, /*!< in/out: space header, x-latched - in mtr */ - ulint space, /*!< in: space id */ - ulint offset, /*!< in: page offset; if equal - to the free limit, we try to - add new extents to the space - free list */ - mtr_t* mtr) /*!< in/out: mini-transaction */ + fsp_header_t* sp_header,/*!< in/out: space header, x-latched */ + ulint space, /*!< in: space id */ + ulint offset, /*!< in: page offset; + if equal to the free limit, + we try to add new extents to + the space free list */ + mtr_t* mtr) /*!< in: mtr handle */ { ulint limit; ulint size; @@ -727,9 +719,11 @@ xdes_get_descriptor_with_space_hdr( ulint descr_page_no; page_t* descr_page; + ut_ad(mtr); ut_ad(mtr_memo_contains(mtr, fil_space_get_latch(space, NULL), MTR_MEMO_X_LOCK)); - ut_ad(mtr_memo_contains_page(mtr, sp_header, MTR_MEMO_PAGE_X_FIX)); + ut_ad(mtr_memo_contains_page(mtr, sp_header, MTR_MEMO_PAGE_S_FIX) + || mtr_memo_contains_page(mtr, sp_header, MTR_MEMO_PAGE_X_FIX)); ut_ad(page_offset(sp_header) == FSP_HEADER_OFFSET); /* Read free limit and space size */ limit = mach_read_from_4(sp_header + FSP_FREE_LIMIT); @@ -779,7 +773,7 @@ is necessary to make the descriptor defined, as they are uninitialized above the free limit. @return pointer to the extent descriptor, NULL if the page does not exist in the space or if the offset exceeds the free limit */ -static __attribute__((nonnull, warn_unused_result)) +static xdes_t* xdes_get_descriptor( /*================*/ @@ -788,7 +782,7 @@ xdes_get_descriptor( or 0 for uncompressed pages */ ulint offset, /*!< in: page offset; if equal to the free limit, we try to add new extents to the space free list */ - mtr_t* mtr) /*!< in/out: mini-transaction */ + mtr_t* mtr) /*!< in: mtr handle */ { buf_block_t* block; fsp_header_t* sp_header; @@ -1166,14 +1160,14 @@ fsp_header_get_tablespace_size(void) Tries to extend a single-table tablespace so that a page would fit in the data file. @return TRUE if success */ -static __attribute__((nonnull, warn_unused_result)) +static ibool fsp_try_extend_data_file_with_pages( /*================================*/ ulint space, /*!< in: space */ ulint page_no, /*!< in: page number */ - fsp_header_t* header, /*!< in/out: space header */ - mtr_t* mtr) /*!< in/out: mini-transaction */ + fsp_header_t* header, /*!< in: space header */ + mtr_t* mtr) /*!< in: mtr */ { ibool success; ulint actual_size; @@ -1198,7 +1192,7 @@ fsp_try_extend_data_file_with_pages( /***********************************************************************//** Tries to extend the last data file of a tablespace if it is auto-extending. @return FALSE if not auto-extending */ -static __attribute__((nonnull)) +static ibool fsp_try_extend_data_file( /*=====================*/ @@ -1208,8 +1202,8 @@ fsp_try_extend_data_file( the actual file size rounded down to megabyte */ ulint space, /*!< in: space */ - fsp_header_t* header, /*!< in/out: space header */ - mtr_t* mtr) /*!< in/out: mini-transaction */ + fsp_header_t* header, /*!< in: space header */ + mtr_t* mtr) /*!< in: mtr */ { ulint size; ulint zip_size; @@ -1345,7 +1339,7 @@ fsp_fill_free_list( then we do not allocate more extents */ ulint space, /*!< in: space */ fsp_header_t* header, /*!< in/out: space header */ - mtr_t* mtr) /*!< in/out: mini-transaction */ + mtr_t* mtr) /*!< in: mtr */ { ulint limit; ulint size; @@ -1543,47 +1537,10 @@ fsp_alloc_free_extent( return(descr); } -/**********************************************************************//** -Allocates a single free page from a space. */ -static __attribute__((nonnull)) -void -fsp_alloc_from_free_frag( -/*=====================*/ - fsp_header_t* header, /*!< in/out: tablespace header */ - xdes_t* descr, /*!< in/out: extent descriptor */ - ulint bit, /*!< in: slot to allocate in the extent */ - mtr_t* mtr) /*!< in/out: mini-transaction */ -{ - ulint frag_n_used; - - ut_ad(xdes_get_state(descr, mtr) == XDES_FREE_FRAG); - ut_a(xdes_get_bit(descr, XDES_FREE_BIT, bit, mtr)); - xdes_set_bit(descr, XDES_FREE_BIT, bit, FALSE, mtr); - - /* Update the FRAG_N_USED field */ - frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES, - mtr); - frag_n_used++; - mlog_write_ulint(header + FSP_FRAG_N_USED, frag_n_used, MLOG_4BYTES, - mtr); - if (xdes_is_full(descr, mtr)) { - /* The fragment is full: move it to another list */ - flst_remove(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE, - mtr); - xdes_set_state(descr, XDES_FULL_FRAG, mtr); - - flst_add_last(header + FSP_FULL_FRAG, descr + XDES_FLST_NODE, - mtr); - mlog_write_ulint(header + FSP_FRAG_N_USED, - frag_n_used - FSP_EXTENT_SIZE, MLOG_4BYTES, - mtr); - } -} - /**********************************************************************//** Allocates a single free page from a space. The page is marked as used. @return the page offset, FIL_NULL if no page could be allocated */ -static __attribute__((nonnull, warn_unused_result)) +static ulint fsp_alloc_free_page( /*================*/ @@ -1591,22 +1548,19 @@ fsp_alloc_free_page( ulint zip_size,/*!< in: compressed page size in bytes or 0 for uncompressed pages */ ulint hint, /*!< in: hint of which page would be desirable */ - mtr_t* mtr, /*!< in/out: mini-transaction */ - mtr_t* init_mtr)/*!< in/out: mini-transaction in which the - page should be initialized - (may be the same as mtr) */ + mtr_t* mtr) /*!< in/out: mini-transaction */ { fsp_header_t* header; fil_addr_t first; xdes_t* descr; buf_block_t* block; ulint free; + ulint frag_n_used; ulint page_no; ulint space_size; ibool success; ut_ad(mtr); - ut_ad(init_mtr); header = fsp_get_space_header(space, zip_size, mtr); @@ -1688,19 +1642,38 @@ fsp_alloc_free_page( } } - fsp_alloc_from_free_frag(header, descr, free, mtr); + xdes_set_bit(descr, XDES_FREE_BIT, free, FALSE, mtr); + + /* Update the FRAG_N_USED field */ + frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES, + mtr); + frag_n_used++; + mlog_write_ulint(header + FSP_FRAG_N_USED, frag_n_used, MLOG_4BYTES, + mtr); + if (xdes_is_full(descr, mtr)) { + /* The fragment is full: move it to another list */ + flst_remove(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE, + mtr); + xdes_set_state(descr, XDES_FULL_FRAG, mtr); + + flst_add_last(header + FSP_FULL_FRAG, descr + XDES_FLST_NODE, + mtr); + mlog_write_ulint(header + FSP_FRAG_N_USED, + frag_n_used - FSP_EXTENT_SIZE, MLOG_4BYTES, + mtr); + } /* Initialize the allocated page to the buffer pool, so that it can be obtained immediately with buf_page_get without need for a disk read. */ - buf_page_create(space, page_no, zip_size, init_mtr); + buf_page_create(space, page_no, zip_size, mtr); - block = buf_page_get(space, zip_size, page_no, RW_X_LATCH, init_mtr); + block = buf_page_get(space, zip_size, page_no, RW_X_LATCH, mtr); buf_block_dbg_add_level(block, SYNC_FSP_PAGE); /* Prior contents of the page should be ignored */ - fsp_init_file_page(block, init_mtr); + fsp_init_file_page(block, mtr); return(page_no); } @@ -1936,7 +1909,7 @@ fsp_alloc_seg_inode_page( zip_size = dict_table_flags_to_zip_size( mach_read_from_4(FSP_SPACE_FLAGS + space_header)); - page_no = fsp_alloc_free_page(space, zip_size, 0, mtr, mtr); + page_no = fsp_alloc_free_page(space, zip_size, 0, mtr); if (page_no == FIL_NULL) { @@ -2350,7 +2323,7 @@ fseg_create_general( if (page == 0) { page = fseg_alloc_free_page_low(space, zip_size, - inode, 0, FSP_UP, mtr, mtr); + inode, 0, FSP_UP, mtr); if (page == FIL_NULL) { @@ -2606,12 +2579,7 @@ fseg_alloc_free_page_low( inserted there in order, into which direction they go alphabetically: FSP_DOWN, FSP_UP, FSP_NO_DIR */ - mtr_t* mtr, /*!< in/out: mini-transaction */ - mtr_t* init_mtr)/*!< in/out: mini-transaction in which the - page should be initialized - (may be the same as mtr), or NULL if it - should not be initialized (the page at hint - was previously freed in mtr) */ + mtr_t* mtr) /*!< in/out: mini-transaction */ { fsp_header_t* space_header; ulint space_size; @@ -2622,6 +2590,7 @@ fseg_alloc_free_page_low( ulint ret_page; /*!< the allocated page offset, FIL_NULL if could not be allocated */ xdes_t* ret_descr; /*!< the extent of the allocated page */ + ibool frag_page_allocated = FALSE; ibool success; ulint n; @@ -2643,8 +2612,6 @@ fseg_alloc_free_page_low( if (descr == NULL) { /* Hint outside space or too high above free limit: reset hint */ - ut_a(init_mtr); - /* The file space header page is always allocated. */ hint = 0; descr = xdes_get_descriptor(space, zip_size, hint, mtr); } @@ -2656,20 +2623,15 @@ fseg_alloc_free_page_low( mtr), seg_id)) && (xdes_get_bit(descr, XDES_FREE_BIT, hint % FSP_EXTENT_SIZE, mtr) == TRUE)) { -take_hinted_page: + /* 1. We can take the hinted page =================================*/ ret_descr = descr; ret_page = hint; - /* Skip the check for extending the tablespace. If the - page hint were not within the size of the tablespace, - we would have got (descr == NULL) above and reset the hint. */ - goto got_hinted_page; /*-----------------------------------------------------------*/ - } else if (xdes_get_state(descr, mtr) == XDES_FREE - && (!init_mtr - || ((reserved - used < reserved / FSEG_FILLFACTOR) - && used >= FSEG_FRAG_LIMIT))) { + } else if ((xdes_get_state(descr, mtr) == XDES_FREE) + && ((reserved - used) < reserved / FSEG_FILLFACTOR) + && (used >= FSEG_FRAG_LIMIT)) { /* 2. We allocate the free extent from space and can take ========================================================= @@ -2687,20 +2649,8 @@ take_hinted_page: /* Try to fill the segment free list */ fseg_fill_free_list(seg_inode, space, zip_size, hint + FSP_EXTENT_SIZE, mtr); - goto take_hinted_page; - /*-----------------------------------------------------------*/ - } else if (!init_mtr) { - ut_a(xdes_get_state(descr, mtr) == XDES_FREE_FRAG); - fsp_alloc_from_free_frag(space_header, descr, - hint % FSP_EXTENT_SIZE, mtr); ret_page = hint; - ret_descr = NULL; - - /* Put the page in the fragment page array of the segment */ - n = fseg_find_free_frag_page_slot(seg_inode, mtr); - ut_a(n != FIL_NULL); - fseg_set_nth_frag_page_no(seg_inode, n, ret_page, mtr); - goto got_hinted_page; + /*-----------------------------------------------------------*/ } else if ((direction != FSP_NO_DIR) && ((reserved - used) < reserved / FSEG_FILLFACTOR) && (used >= FSEG_FRAG_LIMIT) @@ -2760,10 +2710,11 @@ take_hinted_page: } else if (used < FSEG_FRAG_LIMIT) { /* 6. We allocate an individual page from the space ===================================================*/ - ret_page = fsp_alloc_free_page(space, zip_size, hint, - mtr, init_mtr); + ret_page = fsp_alloc_free_page(space, zip_size, hint, mtr); ret_descr = NULL; + frag_page_allocated = TRUE; + if (ret_page != FIL_NULL) { /* Put the page in the fragment page array of the segment */ @@ -2773,10 +2724,6 @@ take_hinted_page: fseg_set_nth_frag_page_no(seg_inode, n, ret_page, mtr); } - - /* fsp_alloc_free_page() invoked fsp_init_file_page() - already. */ - return(ret_page); /*-----------------------------------------------------------*/ } else { /* 7. We allocate a new extent and take its first page @@ -2824,34 +2771,26 @@ take_hinted_page: } } -got_hinted_page: - { + if (!frag_page_allocated) { /* Initialize the allocated page to buffer pool, so that it can be obtained immediately with buf_page_get without need for a disk read */ buf_block_t* block; ulint zip_size = dict_table_flags_to_zip_size( mach_read_from_4(FSP_SPACE_FLAGS + space_header)); - mtr_t* block_mtr = init_mtr ? init_mtr : mtr; - block = buf_page_create(space, ret_page, zip_size, block_mtr); + block = buf_page_create(space, ret_page, zip_size, mtr); buf_block_dbg_add_level(block, SYNC_FSP_PAGE); if (UNIV_UNLIKELY(block != buf_page_get(space, zip_size, ret_page, RW_X_LATCH, - block_mtr))) { + mtr))) { ut_error; } - if (init_mtr) { - /* The prior contents of the page should be ignored */ - fsp_init_file_page(block, init_mtr); - } - } + /* The prior contents of the page should be ignored */ + fsp_init_file_page(block, mtr); - /* ret_descr == NULL if the block was allocated from free_frag - (XDES_FREE_FRAG) */ - if (ret_descr != NULL) { /* At this point we know the extent and the page offset. The extent is still in the appropriate list (FSEG_NOT_FULL or FSEG_FREE), and the page is not yet marked as used. */ @@ -2888,11 +2827,7 @@ fseg_alloc_free_page_general( with fsp_reserve_free_extents, then there is no need to do the check for this individual page */ - mtr_t* mtr, /*!< in/out: mini-transaction handle */ - mtr_t* init_mtr)/*!< in/out: mtr or another mini-transaction - in which the page should be initialized, - or NULL if this is a "fake allocation" of - a page that was previously freed in mtr */ + mtr_t* mtr) /*!< in/out: mini-transaction */ { fseg_inode_t* inode; ulint space; @@ -2934,8 +2869,7 @@ fseg_alloc_free_page_general( } page_no = fseg_alloc_free_page_low(space, zip_size, - inode, hint, direction, - mtr, init_mtr); + inode, hint, direction, mtr); if (!has_done_reservation) { fil_space_release_free_extents(space, n_reserved); } @@ -2943,6 +2877,28 @@ fseg_alloc_free_page_general( return(page_no); } +/**********************************************************************//** +Allocates a single free page from a segment. This function implements +the intelligent allocation strategy which tries to minimize file space +fragmentation. +@return allocated page offset, FIL_NULL if no page could be allocated */ +UNIV_INTERN +ulint +fseg_alloc_free_page( +/*=================*/ + fseg_header_t* seg_header,/*!< in: segment header */ + ulint hint, /*!< in: hint of which page would be desirable */ + byte direction,/*!< in: if the new page is needed because + of an index page split, and records are + inserted there in order, into which + direction they go alphabetically: FSP_DOWN, + FSP_UP, FSP_NO_DIR */ + mtr_t* mtr) /*!< in: mtr handle */ +{ + return(fseg_alloc_free_page_general(seg_header, hint, direction, + FALSE, mtr)); +} + /**********************************************************************//** Checks that we have at least 2 frag pages free in the first extent of a single-table tablespace, and they are also physically initialized to the data diff --git a/storage/innodb_plugin/include/btr0btr.h b/storage/innodb_plugin/include/btr0btr.h index 476ad29adac..c0a038dd21d 100644 --- a/storage/innodb_plugin/include/btr0btr.h +++ b/storage/innodb_plugin/include/btr0btr.h @@ -557,12 +557,7 @@ btr_page_alloc( page split is made */ ulint level, /*!< in: level where the page is placed in the tree */ - mtr_t* mtr, /*!< in/out: mini-transaction - for the allocation */ - mtr_t* init_mtr) /*!< in/out: mini-transaction - for x-latching and initializing - the page */ - __attribute__((nonnull, warn_unused_result)); + mtr_t* mtr); /*!< in: mtr */ /**************************************************************//** Frees a file page used in an index tree. NOTE: cannot free field external storage pages because the page must contain info on its level. */ @@ -585,33 +580,6 @@ btr_page_free_low( buf_block_t* block, /*!< in: block to be freed, x-latched */ ulint level, /*!< in: page level */ mtr_t* mtr); /*!< in: mtr */ -/**************************************************************//** -Marks all MTR_MEMO_FREE_CLUST_LEAF pages nonfree or free. -For invoking btr_store_big_rec_extern_fields() after an update, -we must temporarily mark freed clustered index pages allocated, so -that off-page columns will not be allocated from them. Between the -btr_store_big_rec_extern_fields() and mtr_commit() we have to -mark the pages free again, so that no pages will be leaked. */ -UNIV_INTERN -void -btr_mark_freed_leaves( -/*==================*/ - dict_index_t* index, /*!< in/out: clustered index */ - mtr_t* mtr, /*!< in/out: mini-transaction */ - ibool nonfree)/*!< in: TRUE=mark nonfree, FALSE=mark freed */ - __attribute__((nonnull)); -#ifdef UNIV_DEBUG -/**************************************************************//** -Validates all pages marked MTR_MEMO_FREE_CLUST_LEAF. -@see btr_mark_freed_leaves() -@return TRUE */ -UNIV_INTERN -ibool -btr_freed_leaves_validate( -/*======================*/ - mtr_t* mtr) /*!< in: mini-transaction */ - __attribute__((nonnull, warn_unused_result)); -#endif /* UNIV_DEBUG */ #ifdef UNIV_BTR_PRINT /*************************************************************//** Prints size info of a B-tree. */ diff --git a/storage/innodb_plugin/include/btr0cur.h b/storage/innodb_plugin/include/btr0cur.h index 1d97c5b9452..6094a2a6c7a 100644 --- a/storage/innodb_plugin/include/btr0cur.h +++ b/storage/innodb_plugin/include/btr0cur.h @@ -326,6 +326,16 @@ btr_cur_pessimistic_update( que_thr_t* thr, /*!< in: query thread */ mtr_t* mtr); /*!< in: mtr; must be committed before latching any further pages */ +/***************************************************************** +Commits and restarts a mini-transaction so that it will retain an +x-lock on index->lock and the cursor page. */ +UNIV_INTERN +void +btr_cur_mtr_commit_and_start( +/*=========================*/ + btr_cur_t* cursor, /*!< in: cursor */ + mtr_t* mtr) /*!< in/out: mini-transaction */ + __attribute__((nonnull)); /***********************************************************//** Marks a clustered index record deleted. Writes an undo log record to undo log on this delete marking. Writes in the trx id field the id @@ -530,8 +540,6 @@ btr_store_big_rec_extern_fields_func( the "external storage" flags in offsets will not correspond to rec when this function returns */ - const big_rec_t*big_rec_vec, /*!< in: vector containing fields - to be stored externally */ #ifdef UNIV_DEBUG mtr_t* local_mtr, /*!< in: mtr containing the latch to rec and to the tree */ @@ -540,12 +548,9 @@ btr_store_big_rec_extern_fields_func( ibool update_in_place,/*! in: TRUE if the record is updated in place (not delete+insert) */ #endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ - mtr_t* alloc_mtr) /*!< in/out: in an insert, NULL; - in an update, local_mtr for - allocating BLOB pages and - updating BLOB pointers; alloc_mtr - must not have freed any leaf pages */ - __attribute__((nonnull(1,2,3,4,5), warn_unused_result)); + const big_rec_t*big_rec_vec) /*!< in: vector containing fields + to be stored externally */ + __attribute__((nonnull)); /** Stores the fields in big_rec_vec to the tablespace and puts pointers to them in rec. The extern flags in rec will have to be set beforehand. @@ -554,22 +559,21 @@ file segment of the index tree. @param index in: clustered index; MUST be X-latched by mtr @param b in/out: block containing rec; MUST be X-latched by mtr @param rec in/out: clustered index record -@param offs in: rec_get_offsets(rec, index); +@param offsets in: rec_get_offsets(rec, index); the "external storage" flags in offsets will not be adjusted -@param big in: vector containing fields to be stored externally @param mtr in: mini-transaction that holds x-latch on index and b @param upd in: TRUE if the record is updated in place (not delete+insert) -@param rmtr in/out: in updates, the mini-transaction that holds rec +@param big in: vector containing fields to be stored externally @return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */ #ifdef UNIV_DEBUG -# define btr_store_big_rec_extern_fields(index,b,rec,offs,big,mtr,upd,rmtr) \ - btr_store_big_rec_extern_fields_func(index,b,rec,offs,big,mtr,upd,rmtr) +# define btr_store_big_rec_extern_fields(index,b,rec,offsets,mtr,upd,big) \ + btr_store_big_rec_extern_fields_func(index,b,rec,offsets,mtr,upd,big) #elif defined UNIV_BLOB_LIGHT_DEBUG -# define btr_store_big_rec_extern_fields(index,b,rec,offs,big,mtr,upd,rmtr) \ - btr_store_big_rec_extern_fields_func(index,b,rec,offs,big,upd,rmtr) +# define btr_store_big_rec_extern_fields(index,b,rec,offsets,mtr,upd,big) \ + btr_store_big_rec_extern_fields_func(index,b,rec,offsets,upd,big) #else -# define btr_store_big_rec_extern_fields(index,b,rec,offs,big,mtr,upd,rmtr) \ - btr_store_big_rec_extern_fields_func(index,b,rec,offs,big,rmtr) +# define btr_store_big_rec_extern_fields(index,b,rec,offsets,mtr,upd,big) \ + btr_store_big_rec_extern_fields_func(index,b,rec,offsets,big) #endif /*******************************************************************//** diff --git a/storage/innodb_plugin/include/fsp0fsp.h b/storage/innodb_plugin/include/fsp0fsp.h index 2221380c9a2..403e1d404a8 100644 --- a/storage/innodb_plugin/include/fsp0fsp.h +++ b/storage/innodb_plugin/include/fsp0fsp.h @@ -176,18 +176,19 @@ fseg_n_reserved_pages( Allocates a single free page from a segment. This function implements the intelligent allocation strategy which tries to minimize file space fragmentation. -@param[in/out] seg_header segment header -@param[in] hint hint of which page would be desirable -@param[in] direction if the new page is needed because +@return the allocated page offset FIL_NULL if no page could be allocated */ +UNIV_INTERN +ulint +fseg_alloc_free_page( +/*=================*/ + fseg_header_t* seg_header, /*!< in: segment header */ + ulint hint, /*!< in: hint of which page would be desirable */ + byte direction, /*!< in: if the new page is needed because of an index page split, and records are inserted there in order, into which direction they go alphabetically: FSP_DOWN, - FSP_UP, FSP_NO_DIR -@param[in/out] mtr mini-transaction -@return the allocated page offset FIL_NULL if no page could be allocated */ -#define fseg_alloc_free_page(seg_header, hint, direction, mtr) \ - fseg_alloc_free_page_general(seg_header, hint, direction, \ - FALSE, mtr, mtr) + FSP_UP, FSP_NO_DIR */ + mtr_t* mtr); /*!< in: mtr handle */ /**********************************************************************//** Allocates a single free page from a segment. This function implements the intelligent allocation strategy which tries to minimize file space @@ -209,11 +210,7 @@ fseg_alloc_free_page_general( with fsp_reserve_free_extents, then there is no need to do the check for this individual page */ - mtr_t* mtr, /*!< in/out: mini-transaction */ - mtr_t* init_mtr)/*!< in/out: mtr or another mini-transaction - in which the page should be initialized, - or NULL if this is a "fake allocation" of - a page that was previously freed in mtr */ + mtr_t* mtr) /*!< in/out: mini-transaction */ __attribute__((warn_unused_result, nonnull(1,5))); /**********************************************************************//** Reserves free pages from a tablespace. All mini-transactions which may diff --git a/storage/innodb_plugin/include/mtr0mtr.h b/storage/innodb_plugin/include/mtr0mtr.h index 3529519e7f4..8a9ec8ea7f0 100644 --- a/storage/innodb_plugin/include/mtr0mtr.h +++ b/storage/innodb_plugin/include/mtr0mtr.h @@ -53,8 +53,6 @@ first 3 values must be RW_S_LATCH, RW_X_LATCH, RW_NO_LATCH */ #define MTR_MEMO_MODIFY 54 #define MTR_MEMO_S_LOCK 55 #define MTR_MEMO_X_LOCK 56 -/** The mini-transaction freed a clustered index leaf page. */ -#define MTR_MEMO_FREE_CLUST_LEAF 57 /** @name Log item types The log items are declared 'byte' so that the compiler can warn if val @@ -379,12 +377,9 @@ struct mtr_struct{ #endif dyn_array_t memo; /*!< memo stack for locks etc. */ dyn_array_t log; /*!< mini-transaction log */ - unsigned modifications:1; - /*!< TRUE if the mini-transaction - modified buffer pool pages */ - unsigned freed_clust_leaf:1; - /*!< TRUE if MTR_MEMO_FREE_CLUST_LEAF - was logged in the mini-transaction */ + ibool modifications; + /* TRUE if the mtr made modifications to + buffer pool pages */ ulint n_log_recs; /* count of how many page initial log records have been written to the mtr log */ diff --git a/storage/innodb_plugin/include/mtr0mtr.ic b/storage/innodb_plugin/include/mtr0mtr.ic index 9c0ddff9132..9f92d2b06a1 100644 --- a/storage/innodb_plugin/include/mtr0mtr.ic +++ b/storage/innodb_plugin/include/mtr0mtr.ic @@ -44,7 +44,6 @@ mtr_start( mtr->log_mode = MTR_LOG_ALL; mtr->modifications = FALSE; - mtr->freed_clust_leaf = FALSE; mtr->n_log_recs = 0; ut_d(mtr->state = MTR_ACTIVE); @@ -68,8 +67,7 @@ mtr_memo_push( ut_ad(object); ut_ad(type >= MTR_MEMO_PAGE_S_FIX); - ut_ad(type <= MTR_MEMO_FREE_CLUST_LEAF); - ut_ad(type != MTR_MEMO_FREE_CLUST_LEAF || mtr->freed_clust_leaf); + ut_ad(type <= MTR_MEMO_X_LOCK); ut_ad(mtr); ut_ad(mtr->magic_n == MTR_MAGIC_N); ut_ad(mtr->state == MTR_ACTIVE); diff --git a/storage/innodb_plugin/mtr/mtr0mtr.c b/storage/innodb_plugin/mtr/mtr0mtr.c index e3fefbedec7..5fad61b2922 100644 --- a/storage/innodb_plugin/mtr/mtr0mtr.c +++ b/storage/innodb_plugin/mtr/mtr0mtr.c @@ -58,11 +58,12 @@ mtr_memo_slot_release( buf_page_release((buf_block_t*)object, type, mtr); } else if (type == MTR_MEMO_S_LOCK) { rw_lock_s_unlock((rw_lock_t*)object); +#ifdef UNIV_DEBUG } else if (type != MTR_MEMO_X_LOCK) { - ut_ad(type == MTR_MEMO_MODIFY - || type == MTR_MEMO_FREE_CLUST_LEAF); + ut_ad(type == MTR_MEMO_MODIFY); ut_ad(mtr_memo_contains(mtr, object, MTR_MEMO_PAGE_X_FIX)); +#endif /* UNIV_DEBUG */ } else { rw_lock_x_unlock((rw_lock_t*)object); } diff --git a/storage/innodb_plugin/row/row0ins.c b/storage/innodb_plugin/row/row0ins.c index cd135e8ba8f..f0f6eca627f 100644 --- a/storage/innodb_plugin/row/row0ins.c +++ b/storage/innodb_plugin/row/row0ins.c @@ -2097,20 +2097,15 @@ row_ins_index_entry_low( if (big_rec) { ut_a(err == DB_SUCCESS); /* Write out the externally stored - columns, but allocate the pages and - write the pointers using the - mini-transaction of the record update. - If any pages were freed in the update, - temporarily mark them allocated so - that off-page columns will not - overwrite them. We must do this, - because we will write the redo log for - the BLOB writes before writing the - redo log for the record update. Thus, - redo log application at crash recovery - will see BLOBs being written to free pages. */ - - btr_mark_freed_leaves(index, &mtr, TRUE); + columns while still x-latching + index->lock and block->lock. We have + to mtr_commit(mtr) first, so that the + redo log will be written in the + correct order. Otherwise, we would run + into trouble on crash recovery if mtr + freed B-tree pages on which some of + the big_rec fields will be written. */ + btr_cur_mtr_commit_and_start(&cursor, &mtr); rec = btr_cur_get_rec(&cursor); offsets = rec_get_offsets( @@ -2119,8 +2114,7 @@ row_ins_index_entry_low( err = btr_store_big_rec_extern_fields( index, btr_cur_get_block(&cursor), - rec, offsets, big_rec, &mtr, - FALSE, &mtr); + rec, offsets, &mtr, FALSE, big_rec); /* If writing big_rec fails (for example, because of DB_OUT_OF_FILE_SPACE), the record will be corrupted. Even if @@ -2133,9 +2127,6 @@ row_ins_index_entry_low( undo log, and thus the record cannot be rolled back. */ ut_a(err == DB_SUCCESS); - /* Free the pages again - in order to avoid a leak. */ - btr_mark_freed_leaves(index, &mtr, FALSE); goto stored_big_rec; } } else { @@ -2177,7 +2168,7 @@ function_exit: err = btr_store_big_rec_extern_fields( index, btr_cur_get_block(&cursor), - rec, offsets, big_rec, &mtr, FALSE, NULL); + rec, offsets, &mtr, FALSE, big_rec); stored_big_rec: if (modify) { diff --git a/storage/innodb_plugin/row/row0row.c b/storage/innodb_plugin/row/row0row.c index e476ffae84e..9cdbbe76e04 100644 --- a/storage/innodb_plugin/row/row0row.c +++ b/storage/innodb_plugin/row/row0row.c @@ -243,20 +243,19 @@ row_build( } #if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG - if (rec_offs_any_null_extern(rec, offsets)) { - /* This condition can occur during crash recovery - before trx_rollback_active() has completed execution. + /* This condition can occur during crash recovery before + trx_rollback_active() has completed execution. - This condition is possible if the server crashed - during an insert or update-by-delete-and-insert before - btr_store_big_rec_extern_fields() did mtr_commit() all - BLOB pointers to the freshly inserted clustered index - record. */ - ut_a(trx_assert_recovered( - row_get_rec_trx_id(rec, index, offsets))); - ut_a(trx_undo_roll_ptr_is_insert( - row_get_rec_roll_ptr(rec, index, offsets))); - } + This condition is possible if the server crashed + during an insert or update before + btr_store_big_rec_extern_fields() did mtr_commit() all + BLOB pointers to the clustered index record. + + If the record contains a null BLOB pointer, look up the + transaction that holds the implicit lock on this record, and + assert that it was recovered (and will soon be rolled back). */ + ut_a(!rec_offs_any_null_extern(rec, offsets) + || trx_assert_recovered(row_get_rec_trx_id(rec, index, offsets))); #endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ if (type != ROW_COPY_POINTERS) { diff --git a/storage/innodb_plugin/row/row0upd.c b/storage/innodb_plugin/row/row0upd.c index 05856687015..b5952ff0a78 100644 --- a/storage/innodb_plugin/row/row0upd.c +++ b/storage/innodb_plugin/row/row0upd.c @@ -1978,22 +1978,21 @@ row_upd_clust_rec( rec_offs_init(offsets_); ut_a(err == DB_SUCCESS); - /* Write out the externally stored columns, but - allocate the pages and write the pointers using the - mini-transaction of the record update. If any pages - were freed in the update, temporarily mark them - allocated so that off-page columns will not overwrite - them. We must do this, because we write the redo log - for the BLOB writes before writing the redo log for - the record update. */ + /* Write out the externally stored columns while still + x-latching index->lock and block->lock. We have to + mtr_commit(mtr) first, so that the redo log will be + written in the correct order. Otherwise, we would run + into trouble on crash recovery if mtr freed B-tree + pages on which some of the big_rec fields will be + written. */ + btr_cur_mtr_commit_and_start(btr_cur, mtr); - btr_mark_freed_leaves(index, mtr, TRUE); rec = btr_cur_get_rec(btr_cur); err = btr_store_big_rec_extern_fields( index, btr_cur_get_block(btr_cur), rec, rec_get_offsets(rec, index, offsets_, ULINT_UNDEFINED, &heap), - big_rec, mtr, TRUE, mtr); + mtr, TRUE, big_rec); /* If writing big_rec fails (for example, because of DB_OUT_OF_FILE_SPACE), the record will be corrupted. Even if we did not update any externally stored @@ -2003,8 +2002,6 @@ row_upd_clust_rec( to the undo log, and thus the record cannot be rolled back. */ ut_a(err == DB_SUCCESS); - /* Free the pages again in order to avoid a leak. */ - btr_mark_freed_leaves(index, mtr, FALSE); } mtr_commit(mtr); diff --git a/storage/innodb_plugin/trx/trx0undo.c b/storage/innodb_plugin/trx/trx0undo.c index c36f55fbd9c..746f0808643 100644 --- a/storage/innodb_plugin/trx/trx0undo.c +++ b/storage/innodb_plugin/trx/trx0undo.c @@ -912,7 +912,7 @@ trx_undo_add_page( page_no = fseg_alloc_free_page_general(header_page + TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER, undo->top_page_no + 1, FSP_UP, - TRUE, mtr, mtr); + TRUE, mtr); fil_space_release_free_extents(undo->space, n_reserved); From 2c67d5066db7d6aada4d93297918a8ff3e57aa33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 26 Oct 2011 12:23:57 +0300 Subject: [PATCH 050/288] Revert revno:3452.71.32 (Bug#12612184 fix). Bug#12612184 RACE CONDITION AFTER BTR_CUR_PESSIMISTIC_UPDATE() The fix introduced potentially more severe crash recovery problems than the bug causes. Revert the fix for now. --- storage/innobase/btr/btr0btr.c | 40 ++------ storage/innobase/btr/btr0cur.c | 106 +++++++-------------- storage/innobase/include/btr0btr.h | 12 +-- storage/innobase/include/btr0cur.h | 39 ++++---- storage/innobase/include/buf0buf.h | 19 ---- storage/innobase/include/page0page.h | 20 +--- storage/innobase/include/page0page.ic | 16 ---- storage/innobase/page/page0page.c | 31 +++--- storage/innobase/row/row0ins.c | 44 +-------- storage/innobase/row/row0umod.c | 2 - storage/innobase/row/row0upd.c | 34 ++----- storage/innodb_plugin/ChangeLog | 10 -- storage/innodb_plugin/btr/btr0btr.c | 48 +++------- storage/innodb_plugin/btr/btr0cur.c | 80 ++-------------- storage/innodb_plugin/include/btr0btr.h | 13 +-- storage/innodb_plugin/include/btr0cur.h | 24 +---- storage/innodb_plugin/include/btr0cur.ic | 2 +- storage/innodb_plugin/include/buf0buf.h | 25 ----- storage/innodb_plugin/include/buf0buf.ic | 13 +++ storage/innodb_plugin/include/page0page.h | 37 +------ storage/innodb_plugin/include/page0page.ic | 30 ------ storage/innodb_plugin/page/page0cur.c | 15 +-- storage/innodb_plugin/page/page0page.c | 50 +++++----- storage/innodb_plugin/row/row0ins.c | 46 +-------- storage/innodb_plugin/row/row0upd.c | 33 ++----- 25 files changed, 192 insertions(+), 597 deletions(-) diff --git a/storage/innobase/btr/btr0btr.c b/storage/innobase/btr/btr0btr.c index e8e065a3116..5079757272a 100644 --- a/storage/innobase/btr/btr0btr.c +++ b/storage/innobase/btr/btr0btr.c @@ -1948,7 +1948,7 @@ btr_node_ptr_delete( ut_a(err == DB_SUCCESS); if (!compressed) { - btr_cur_compress_if_useful(&cursor, FALSE, mtr); + btr_cur_compress_if_useful(&cursor, mtr); } } @@ -1956,10 +1956,9 @@ btr_node_ptr_delete( If page is the only on its level, this function moves its records to the father page, thus reducing the tree height. */ static -page_t* +void btr_lift_page_up( /*=============*/ - /* out: father page */ dict_index_t* index, /* in: index tree */ page_t* page, /* in: page which is the only on its level; must not be empty: use @@ -2035,8 +2034,6 @@ btr_lift_page_up( ibuf_reset_free_bits(index, father_page); ut_ad(page_validate(father_page, index)); ut_ad(btr_check_node_ptr(index, father_page, mtr)); - - return(father_page); } /***************************************************************** @@ -2053,13 +2050,11 @@ enough free extents so that the compression will always succeed if done! */ void btr_compress( /*=========*/ - btr_cur_t* cursor, /* in/out: cursor on the page to merge - or lift; the page must not be empty: - when deleting records, use btr_discard_page() - if the page would become empty */ - ibool adjust, /* in: TRUE if should adjust the - cursor position even if compression occurs */ - mtr_t* mtr) /* in/out: mini-transaction */ + btr_cur_t* cursor, /* in: cursor on the page to merge or lift; + the page must not be empty: in record delete + use btr_discard_page if the page would become + empty */ + mtr_t* mtr) /* in: mtr */ { dict_index_t* index; ulint space; @@ -2074,7 +2069,6 @@ btr_compress( rec_t* node_ptr; ulint data_size; ulint n_recs; - ulint nth_rec = 0; /* remove bogus warning */ ulint max_ins_size; ulint max_ins_size_reorg; ulint comp; @@ -2082,7 +2076,6 @@ btr_compress( page = btr_cur_get_page(cursor); index = btr_cur_get_index(cursor); comp = page_is_comp(page); - ut_a((ibool)!!comp == dict_table_is_comp(index->table)); ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index), @@ -2104,10 +2097,6 @@ btr_compress( father_page = buf_frame_align(node_ptr); ut_a(comp == page_is_comp(father_page)); - if (adjust) { - nth_rec = page_rec_get_n_recs_before(btr_cur_get_rec(cursor)); - } - /* Decide the page to which we try to merge and which will inherit the locks */ @@ -2132,8 +2121,9 @@ btr_compress( } else { /* The page is the only one on the level, lift the records to the father */ - merge_page = btr_lift_page_up(index, page, mtr); - goto func_exit; + btr_lift_page_up(index, page, mtr); + + return; } n_recs = page_get_n_recs(page); @@ -2209,10 +2199,6 @@ btr_compress( index, mtr); lock_update_merge_left(merge_page, orig_pred, page); - - if (adjust) { - nth_rec += page_rec_get_n_recs_before(orig_pred); - } } else { orig_succ = page_rec_get_next( page_get_infimum_rec(merge_page)); @@ -2233,12 +2219,6 @@ btr_compress( btr_page_free(index, page, mtr); ut_ad(btr_check_node_ptr(index, merge_page, mtr)); - -func_exit: - if (adjust) { - btr_cur_position(index, page_rec_get_nth(merge_page, nth_rec), - cursor); - } } /***************************************************************** diff --git a/storage/innobase/btr/btr0cur.c b/storage/innobase/btr/btr0cur.c index 95d87344e93..3c12e28feb6 100644 --- a/storage/innobase/btr/btr0cur.c +++ b/storage/innobase/btr/btr0cur.c @@ -1790,9 +1790,7 @@ btr_cur_pessimistic_update( /* out: DB_SUCCESS or error code */ ulint flags, /* in: undo logging, locking, and rollback flags */ - btr_cur_t* cursor, /* in/out: cursor on the record to update; - cursor may become invalid if *big_rec == NULL - || !(flags & BTR_KEEP_POS_FLAG) */ + btr_cur_t* cursor, /* in: cursor on the record to update */ big_rec_t** big_rec,/* out: big rec vector whose fields have to be stored externally by the caller, or NULL */ upd_t* update, /* in: update vector; this is allowed also @@ -1927,10 +1925,6 @@ btr_cur_pessimistic_update( err = DB_TOO_BIG_RECORD; goto return_after_reservations; } - - ut_ad(index->type & DICT_CLUSTERED); - ut_ad(btr_page_get_level(page, mtr) == 0); - ut_ad(flags & BTR_KEEP_POS_FLAG); } page_cursor = btr_cur_get_page_cur(cursor); @@ -1957,8 +1951,6 @@ btr_cur_pessimistic_update( ut_a(rec || optim_err != DB_UNDERFLOW); if (rec) { - page_cursor->rec = rec; - lock_rec_restore_from_page_infimum(rec, page); rec_set_field_extern_bits(rec, index, ext_vect, n_ext_vect, mtr); @@ -1972,30 +1964,12 @@ btr_cur_pessimistic_update( btr_cur_unmark_extern_fields(rec, mtr, offsets); } - btr_cur_compress_if_useful( - cursor, - big_rec_vec != NULL && (flags & BTR_KEEP_POS_FLAG), - mtr); + btr_cur_compress_if_useful(cursor, mtr); err = DB_SUCCESS; goto return_after_reservations; } - if (big_rec_vec) { - ut_ad(index->type & DICT_CLUSTERED); - ut_ad(btr_page_get_level(page, mtr) == 0); - ut_ad(flags & BTR_KEEP_POS_FLAG); - - /* btr_page_split_and_insert() in - btr_cur_pessimistic_insert() invokes - mtr_memo_release(mtr, index->lock, MTR_MEMO_X_LOCK). - We must keep the index->lock when we created a - big_rec, so that row_upd_clust_rec() can store the - big_rec in the same mini-transaction. */ - - mtr_x_lock(dict_index_get_lock(index), mtr); - } - if (page_cur_is_before_first(page_cursor)) { /* The record to be updated was positioned as the first user record on its page */ @@ -2016,7 +1990,6 @@ btr_cur_pessimistic_update( ut_a(rec); ut_a(err == DB_SUCCESS); ut_a(dummy_big_rec == NULL); - page_cursor->rec = rec; rec_set_field_extern_bits(rec, index, ext_vect, n_ext_vect, mtr); offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap); @@ -2051,43 +2024,6 @@ return_after_reservations: return(err); } -/***************************************************************** -Commits and restarts a mini-transaction so that it will retain an -x-lock on index->lock and the cursor page. */ - -void -btr_cur_mtr_commit_and_start( -/*=========================*/ - btr_cur_t* cursor, /* in: cursor */ - mtr_t* mtr) /* in/out: mini-transaction */ -{ - buf_block_t* block; - - block = buf_block_align(btr_cur_get_rec(cursor)); - - ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(cursor->index), - MTR_MEMO_X_LOCK)); - ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); - /* Keep the locks across the mtr_commit(mtr). */ - rw_lock_x_lock(dict_index_get_lock(cursor->index)); - rw_lock_x_lock(&block->lock); - mutex_enter(&block->mutex); -#ifdef UNIV_SYNC_DEBUG - buf_block_buf_fix_inc_debug(block, __FILE__, __LINE__); -#else - buf_block_buf_fix_inc(block); -#endif - mutex_exit(&block->mutex); - /* Write out the redo log. */ - mtr_commit(mtr); - mtr_start(mtr); - /* Reassociate the locks with the mini-transaction. - They will be released on mtr_commit(mtr). */ - mtr_memo_push(mtr, dict_index_get_lock(cursor->index), - MTR_MEMO_X_LOCK); - mtr_memo_push(mtr, block, MTR_MEMO_PAGE_X_FIX); -} - /*==================== B-TREE DELETE MARK AND UNMARK ===============*/ /******************************************************************** @@ -2455,6 +2391,30 @@ btr_cur_del_unmark_for_ibuf( /*==================== B-TREE RECORD REMOVE =========================*/ +/***************************************************************** +Tries to compress a page of the tree on the leaf level. It is assumed +that mtr holds an x-latch on the tree and on the cursor page. To avoid +deadlocks, mtr must also own x-latches to brothers of page, if those +brothers exist. NOTE: it is assumed that the caller has reserved enough +free extents so that the compression will always succeed if done! */ + +void +btr_cur_compress( +/*=============*/ + btr_cur_t* cursor, /* in: cursor on the page to compress; + cursor does not stay valid */ + mtr_t* mtr) /* in: mtr */ +{ + ut_ad(mtr_memo_contains(mtr, + dict_index_get_lock(btr_cur_get_index(cursor)), + MTR_MEMO_X_LOCK)); + ut_ad(mtr_memo_contains(mtr, buf_block_align(btr_cur_get_rec(cursor)), + MTR_MEMO_PAGE_X_FIX)); + ut_ad(btr_page_get_level(btr_cur_get_page(cursor), mtr) == 0); + + btr_compress(cursor, mtr); +} + /***************************************************************** Tries to compress a page of the tree if it seems useful. It is assumed that mtr holds an x-latch on the tree and on the cursor page. To avoid @@ -2466,12 +2426,10 @@ ibool btr_cur_compress_if_useful( /*=======================*/ /* out: TRUE if compression occurred */ - btr_cur_t* cursor, /* in/out: cursor on the page to compress; - cursor does not stay valid if !adjust and - compression occurs */ - ibool adjust, /* in: TRUE if should adjust the - cursor position even if compression occurs */ - mtr_t* mtr) /* in/out: mini-transaction */ + btr_cur_t* cursor, /* in: cursor on the page to compress; + cursor does not stay valid if compression + occurs */ + mtr_t* mtr) /* in: mtr */ { ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(btr_cur_get_index(cursor)), @@ -2481,7 +2439,7 @@ btr_cur_compress_if_useful( if (btr_cur_compress_recommendation(cursor, mtr)) { - btr_compress(cursor, adjust, mtr); + btr_compress(cursor, mtr); return(TRUE); } @@ -2694,7 +2652,7 @@ return_after_reservations: mem_heap_free(heap); if (ret == FALSE) { - ret = btr_cur_compress_if_useful(cursor, FALSE, mtr); + ret = btr_cur_compress_if_useful(cursor, mtr); } if (n_extents > 0) { diff --git a/storage/innobase/include/btr0btr.h b/storage/innobase/include/btr0btr.h index 269fa355558..1573de7e818 100644 --- a/storage/innobase/include/btr0btr.h +++ b/storage/innobase/include/btr0btr.h @@ -312,13 +312,11 @@ enough free extents so that the compression will always succeed if done! */ void btr_compress( /*=========*/ - btr_cur_t* cursor, /* in/out: cursor on the page to merge - or lift; the page must not be empty: - when deleting records, use btr_discard_page() - if the page would become empty */ - ibool adjust, /* in: TRUE if should adjust the - cursor position even if compression occurs */ - mtr_t* mtr); /* in/out: mini-transaction */ + btr_cur_t* cursor, /* in: cursor on the page to merge or lift; + the page must not be empty: in record delete + use btr_discard_page if the page would become + empty */ + mtr_t* mtr); /* in: mtr */ /***************************************************************** Discards a page from a B-tree. This is used to remove the last record from a B-tree page: the whole page must be removed at the same time. This cannot diff --git a/storage/innobase/include/btr0cur.h b/storage/innobase/include/btr0cur.h index c068d8d3318..20235c55f22 100644 --- a/storage/innobase/include/btr0cur.h +++ b/storage/innobase/include/btr0cur.h @@ -23,9 +23,6 @@ Created 10/16/1994 Heikki Tuuri #define BTR_NO_LOCKING_FLAG 2 /* do no record lock checking */ #define BTR_KEEP_SYS_FLAG 4 /* sys fields will be found from the update vector or inserted entry */ -#define BTR_KEEP_POS_FLAG 8 /* btr_cur_pessimistic_update() - must keep cursor position when - moving columns to big_rec */ #define BTR_CUR_ADAPT #define BTR_CUR_HASH_ADAPT @@ -240,9 +237,7 @@ btr_cur_pessimistic_update( /* out: DB_SUCCESS or error code */ ulint flags, /* in: undo logging, locking, and rollback flags */ - btr_cur_t* cursor, /* in/out: cursor on the record to update; - cursor may become invalid if *big_rec == NULL - || !(flags & BTR_KEEP_POS_FLAG) */ + btr_cur_t* cursor, /* in: cursor on the record to update */ big_rec_t** big_rec,/* out: big rec vector whose fields have to be stored externally by the caller, or NULL */ upd_t* update, /* in: update vector; this is allowed also @@ -252,15 +247,6 @@ btr_cur_pessimistic_update( updates */ que_thr_t* thr, /* in: query thread */ mtr_t* mtr); /* in: mtr */ -/***************************************************************** -Commits and restarts a mini-transaction so that it will retain an -x-lock on index->lock and the cursor page. */ - -void -btr_cur_mtr_commit_and_start( -/*=========================*/ - btr_cur_t* cursor, /* in: cursor */ - mtr_t* mtr); /* in/out: mini-transaction */ /*************************************************************** Marks a clustered index record deleted. Writes an undo log record to undo log on this delete marking. Writes in the trx id field the id @@ -300,6 +286,19 @@ btr_cur_del_unmark_for_ibuf( rec_t* rec, /* in: record to delete unmark */ mtr_t* mtr); /* in: mtr */ /***************************************************************** +Tries to compress a page of the tree on the leaf level. It is assumed +that mtr holds an x-latch on the tree and on the cursor page. To avoid +deadlocks, mtr must also own x-latches to brothers of page, if those +brothers exist. NOTE: it is assumed that the caller has reserved enough +free extents so that the compression will always succeed if done! */ + +void +btr_cur_compress( +/*=============*/ + btr_cur_t* cursor, /* in: cursor on the page to compress; + cursor does not stay valid */ + mtr_t* mtr); /* in: mtr */ +/***************************************************************** Tries to compress a page of the tree if it seems useful. It is assumed that mtr holds an x-latch on the tree and on the cursor page. To avoid deadlocks, mtr must also own x-latches to brothers of page, if those @@ -310,12 +309,10 @@ ibool btr_cur_compress_if_useful( /*=======================*/ /* out: TRUE if compression occurred */ - btr_cur_t* cursor, /* in/out: cursor on the page to compress; - cursor does not stay valid if !adjust and - compression occurs */ - ibool adjust, /* in: TRUE if should adjust the - cursor position even if compression occurs */ - mtr_t* mtr); /* in/out: mini-transaction */ + btr_cur_t* cursor, /* in: cursor on the page to compress; + cursor does not stay valid if compression + occurs */ + mtr_t* mtr); /* in: mtr */ /*********************************************************** Removes the record on which the tree cursor is positioned. It is assumed that the mtr has an x-latch on the page where the cursor is positioned, diff --git a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h index 50e0aa9376c..0f7553a7043 100644 --- a/storage/innobase/include/buf0buf.h +++ b/storage/innobase/include/buf0buf.h @@ -654,25 +654,6 @@ buf_page_address_fold( /* out: the folded value */ ulint space, /* in: space id */ ulint offset);/* in: offset of the page within space */ -#ifdef UNIV_SYNC_DEBUG -/*********************************************************************** -Increments the bufferfix count. */ -UNIV_INLINE -void -buf_block_buf_fix_inc_debug( -/*========================*/ - buf_block_t* block, /* in: block to bufferfix */ - const char* file __attribute__ ((unused)), /* in: file name */ - ulint line __attribute__ ((unused))); /* in: line */ -#else /* UNIV_SYNC_DEBUG */ -/*********************************************************************** -Increments the bufferfix count. */ -UNIV_INLINE -void -buf_block_buf_fix_inc( -/*==================*/ - buf_block_t* block); /* in: block to bufferfix */ -#endif /* UNIV_SYNC_DEBUG */ /********************************************************************** Returns the control block of a file page, NULL if not found. */ UNIV_INLINE diff --git a/storage/innobase/include/page0page.h b/storage/innobase/include/page0page.h index 24698557e77..273007c2778 100644 --- a/storage/innobase/include/page0page.h +++ b/storage/innobase/include/page0page.h @@ -234,21 +234,10 @@ page_get_supremum_rec( /*==================*/ /* out: the last record in record list */ page_t* page); /* in: page which must have record(s) */ -/************************************************************//** -Returns the nth record of the record list. -This is the inverse function of page_rec_get_n_recs_before(). */ +/**************************************************************** +Returns the middle record of record list. If there are an even number +of records in the list, returns the first record of upper half-list. */ -rec_t* -page_rec_get_nth( -/*=============*/ - /* out: nth record */ - page_t* page, /* in: page */ - ulint nth); /* in: nth record */ -/***************************************************************** -Returns the middle record of the records on the page. If there is an -even number of records in the list, returns the first record of the -upper half-list. */ -UNIV_INLINE rec_t* page_get_middle_rec( /*================*/ @@ -291,8 +280,7 @@ page_get_n_recs( page_t* page); /* in: index page */ /******************************************************************* Returns the number of records before the given record in chain. -The number includes infimum and supremum records. -This is the inverse function of page_rec_get_nth(). */ +The number includes infimum and supremum records. */ ulint page_rec_get_n_recs_before( diff --git a/storage/innobase/include/page0page.ic b/storage/innobase/include/page0page.ic index a019aa28515..d9e67f3eeeb 100644 --- a/storage/innobase/include/page0page.ic +++ b/storage/innobase/include/page0page.ic @@ -340,22 +340,6 @@ page_rec_is_infimum( return(page_rec_is_infimum_low(page_offset(rec))); } -/***************************************************************** -Returns the middle record of the records on the page. If there is an -even number of records in the list, returns the first record of the -upper half-list. */ -UNIV_INLINE -rec_t* -page_get_middle_rec( -/*================*/ - /* out: middle record */ - page_t* page) /* in: page */ -{ - ulint middle = (page_get_n_recs(page) + 2) / 2; - - return(page_rec_get_nth(page, middle)); -} - /***************************************************************** Compares a data tuple to a physical record. Differs from the function cmp_dtuple_rec_with_match in the way that the record must reside on an diff --git a/storage/innobase/page/page0page.c b/storage/innobase/page/page0page.c index 6a89df7de22..543cf9e34eb 100644 --- a/storage/innobase/page/page0page.c +++ b/storage/innobase/page/page0page.c @@ -1194,42 +1194,49 @@ page_dir_balance_slot( } /**************************************************************** -Returns the nth record of the record list. */ +Returns the middle record of the record list. If there are an even number +of records in the list, returns the first record of the upper half-list. */ rec_t* -page_rec_get_nth( -/*=============*/ - /* out: nth record */ - page_t* page, /* in: page */ - ulint nth) /* in: nth record */ +page_get_middle_rec( +/*================*/ + /* out: middle record */ + page_t* page) /* in: page */ { page_dir_slot_t* slot; + ulint middle; ulint i; ulint n_owned; + ulint count; rec_t* rec; - ut_ad(nth < UNIV_PAGE_SIZE / (REC_N_NEW_EXTRA_BYTES + 1)); + /* This many records we must leave behind */ + middle = (page_get_n_recs(page) + 2) / 2; + + count = 0; for (i = 0;; i++) { slot = page_dir_get_nth_slot(page, i); n_owned = page_dir_slot_get_n_owned(slot); - if (n_owned > nth) { + if (count + n_owned > middle) { break; } else { - nth -= n_owned; + count += n_owned; } } ut_ad(i > 0); slot = page_dir_get_nth_slot(page, i - 1); rec = page_dir_slot_get_rec(slot); + rec = page_rec_get_next(rec); - do { + /* There are now count records behind rec */ + + for (i = 0; i < middle - count; i++) { rec = page_rec_get_next(rec); - ut_ad(rec); - } while (nth--); + } return(rec); } diff --git a/storage/innobase/row/row0ins.c b/storage/innobase/row/row0ins.c index c3b8f54a3c5..4f5f948f218 100644 --- a/storage/innobase/row/row0ins.c +++ b/storage/innobase/row/row0ins.c @@ -259,7 +259,6 @@ row_ins_sec_index_entry_by_modify( err = btr_cur_pessimistic_update(BTR_KEEP_SYS_FLAG, cursor, &dummy_big_rec, update, 0, thr, mtr); - ut_a(!dummy_big_rec); } func_exit: mem_heap_free(heap); @@ -330,9 +329,8 @@ row_ins_clust_index_entry_by_modify( goto func_exit; } - err = btr_cur_pessimistic_update( - BTR_KEEP_POS_FLAG, cursor, big_rec, update, - 0, thr, mtr); + err = btr_cur_pessimistic_update(0, cursor, big_rec, update, + 0, thr, mtr); } func_exit: mem_heap_free(heap); @@ -2086,41 +2084,6 @@ row_ins_index_entry_low( err = row_ins_clust_index_entry_by_modify( mode, &cursor, &big_rec, entry, ext_vec, n_ext_vec, thr, &mtr); - - if (big_rec) { - ut_a(err == DB_SUCCESS); - /* Write out the externally stored - columns while still x-latching - index->lock and block->lock. We have - to mtr_commit(mtr) first, so that the - redo log will be written in the - correct order. Otherwise, we would run - into trouble on crash recovery if mtr - freed B-tree pages on which some of - the big_rec fields will be written. */ - btr_cur_mtr_commit_and_start(&cursor, &mtr); - - rec = btr_cur_get_rec(&cursor); - offsets = rec_get_offsets(rec, index, offsets, - ULINT_UNDEFINED, - &heap); - - err = btr_store_big_rec_extern_fields( - index, rec, offsets, big_rec, &mtr); - /* If writing big_rec fails (for - example, because of DB_OUT_OF_FILE_SPACE), - the record will be corrupted. Even if - we did not update any externally - stored columns, our update could cause - the record to grow so that a - non-updated column was selected for - external storage. This non-update - would not have been written to the - undo log, and thus the record cannot - be rolled back. */ - ut_a(err == DB_SUCCESS); - goto stored_big_rec; - } } else { err = row_ins_sec_index_entry_by_modify( mode, &cursor, entry, thr, &mtr); @@ -2157,6 +2120,7 @@ function_exit: mtr_commit(&mtr); if (big_rec) { + rec_t* rec; mtr_start(&mtr); btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE, @@ -2167,7 +2131,7 @@ function_exit: err = btr_store_big_rec_extern_fields(index, rec, offsets, big_rec, &mtr); -stored_big_rec: + if (modify) { dtuple_big_rec_free(big_rec); } else { diff --git a/storage/innobase/row/row0umod.c b/storage/innobase/row/row0umod.c index 0b00aa2411a..a3333fcc536 100644 --- a/storage/innobase/row/row0umod.c +++ b/storage/innobase/row/row0umod.c @@ -119,7 +119,6 @@ row_undo_mod_clust_low( | BTR_KEEP_SYS_FLAG, btr_cur, &dummy_big_rec, node->update, node->cmpl_info, thr, mtr); - ut_ad(!dummy_big_rec); } return(err); @@ -472,7 +471,6 @@ row_undo_mod_del_unmark_sec_and_undo_update( BTR_KEEP_SYS_FLAG | BTR_NO_LOCKING_FLAG, btr_cur, &dummy_big_rec, update, 0, thr, &mtr); - ut_ad(!dummy_big_rec); } mem_heap_free(heap); diff --git a/storage/innobase/row/row0upd.c b/storage/innobase/row/row0upd.c index 694b00ea265..0790cfe02e2 100644 --- a/storage/innobase/row/row0upd.c +++ b/storage/innobase/row/row0upd.c @@ -1580,48 +1580,32 @@ row_upd_clust_rec( ut_ad(!rec_get_deleted_flag(btr_pcur_get_rec(pcur), dict_table_is_comp(index->table))); - err = btr_cur_pessimistic_update( - BTR_NO_LOCKING_FLAG | BTR_KEEP_POS_FLAG, btr_cur, - &big_rec, node->update, node->cmpl_info, thr, mtr); + err = btr_cur_pessimistic_update(BTR_NO_LOCKING_FLAG, btr_cur, + &big_rec, node->update, + node->cmpl_info, thr, mtr); + mtr_commit(mtr); - if (big_rec) { + if (err == DB_SUCCESS && big_rec) { mem_heap_t* heap = NULL; ulint offsets_[REC_OFFS_NORMAL_SIZE]; rec_t* rec; *offsets_ = (sizeof offsets_) / sizeof *offsets_; - ut_a(err == DB_SUCCESS); - /* Write out the externally stored columns while still - x-latching index->lock and block->lock. We have to - mtr_commit(mtr) first, so that the redo log will be - written in the correct order. Otherwise, we would run - into trouble on crash recovery if mtr freed B-tree - pages on which some of the big_rec fields will be - written. */ - btr_cur_mtr_commit_and_start(btr_cur, mtr); + mtr_start(mtr); + ut_a(btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, mtr)); rec = btr_cur_get_rec(btr_cur); err = btr_store_big_rec_extern_fields( index, rec, rec_get_offsets(rec, index, offsets_, ULINT_UNDEFINED, &heap), - big_rec, mtr); + big_rec, mtr); if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); } - /* If writing big_rec fails (for example, because of - DB_OUT_OF_FILE_SPACE), the record will be corrupted. - Even if we did not update any externally stored - columns, our update could cause the record to grow so - that a non-updated column was selected for external - storage. This non-update would not have been written - to the undo log, and thus the record cannot be rolled - back. */ - ut_a(err == DB_SUCCESS); + mtr_commit(mtr); } - mtr_commit(mtr); - if (big_rec) { dtuple_big_rec_free(big_rec); } diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index e6724eb08c2..859b9fb627a 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -101,16 +101,6 @@ * page/page0zip.c, rem/rem0rec.c: Fix Bug#61191 question about page_zip_available() -2011-06-16 The InnoDB Team - - * btr/btr0btr.c, btr/btr0cur.c, include/btr0btr.h, include/btr0cur.h, - include/btr0cur.ic, include/buf0buf.h, include/buf0buf.ic, - include/page0cur.ic, include/page0page.h, include/page0page.ic, - include/sync0rw.ic, include/sync0sync.h, page/page0cur.c, - page/page0page.c, row/row0ins.c, row/row0upd.c, - sync/sync0rw.c, sync/sync0sync.c: - Fix Bug#12612184 Race condition after btr_cur_pessimistic_update() - 2011-06-09 The InnoDB Team * btr/btr0cur.c, include/rem0rec.h, include/rem0rec.ic, * row/row0row.c, row/row0vers.c, trx/trx0rec.c: diff --git a/storage/innodb_plugin/btr/btr0btr.c b/storage/innodb_plugin/btr/btr0btr.c index cb94ef08cd6..23729c12c1a 100644 --- a/storage/innodb_plugin/btr/btr0btr.c +++ b/storage/innodb_plugin/btr/btr0btr.c @@ -3001,16 +3001,15 @@ btr_node_ptr_delete( ut_a(err == DB_SUCCESS); if (!compressed) { - btr_cur_compress_if_useful(&cursor, FALSE, mtr); + btr_cur_compress_if_useful(&cursor, mtr); } } /*************************************************************//** If page is the only on its level, this function moves its records to the -father page, thus reducing the tree height. -@return father block */ +father page, thus reducing the tree height. */ static -buf_block_t* +void btr_lift_page_up( /*=============*/ dict_index_t* index, /*!< in: index tree */ @@ -3127,8 +3126,6 @@ btr_lift_page_up( } ut_ad(page_validate(father_page, index)); ut_ad(btr_check_node_ptr(index, father_block, mtr)); - - return(father_block); } /*************************************************************//** @@ -3145,13 +3142,11 @@ UNIV_INTERN ibool btr_compress( /*=========*/ - btr_cur_t* cursor, /*!< in/out: cursor on the page to merge - or lift; the page must not be empty: - when deleting records, use btr_discard_page() - if the page would become empty */ - ibool adjust, /*!< in: TRUE if should adjust the - cursor position even if compression occurs */ - mtr_t* mtr) /*!< in/out: mini-transaction */ + btr_cur_t* cursor, /*!< in: cursor on the page to merge or lift; + the page must not be empty: in record delete + use btr_discard_page if the page would become + empty */ + mtr_t* mtr) /*!< in: mtr */ { dict_index_t* index; ulint space; @@ -3169,14 +3164,12 @@ btr_compress( ulint* offsets; ulint data_size; ulint n_recs; - ulint nth_rec = 0; /* remove bogus warning */ ulint max_ins_size; ulint max_ins_size_reorg; block = btr_cur_get_block(cursor); page = btr_cur_get_page(cursor); index = btr_cur_get_index(cursor); - ut_a((ibool) !!page_is_comp(page) == dict_table_is_comp(index->table)); ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index), @@ -3197,10 +3190,6 @@ btr_compress( offsets = btr_page_get_father_block(NULL, heap, index, block, mtr, &father_cursor); - if (adjust) { - nth_rec = page_rec_get_n_recs_before(btr_cur_get_rec(cursor)); - } - /* Decide the page to which we try to merge and which will inherit the locks */ @@ -3227,9 +3216,9 @@ btr_compress( } else { /* The page is the only one on the level, lift the records to the father */ - - merge_block = btr_lift_page_up(index, block, mtr); - goto func_exit; + btr_lift_page_up(index, block, mtr); + mem_heap_free(heap); + return(TRUE); } n_recs = page_get_n_recs(page); @@ -3311,10 +3300,6 @@ err_exit: btr_node_ptr_delete(index, block, mtr); lock_update_merge_left(merge_block, orig_pred, block); - - if (adjust) { - nth_rec += page_rec_get_n_recs_before(orig_pred); - } } else { rec_t* orig_succ; #ifdef UNIV_BTR_DEBUG @@ -3379,6 +3364,7 @@ err_exit: } btr_blob_dbg_remove(page, index, "btr_compress"); + mem_heap_free(heap); if (!dict_index_is_clust(index) && page_is_leaf(merge_page)) { /* Update the free bits of the B-tree page in the @@ -3430,16 +3416,6 @@ err_exit: btr_page_free(index, block, mtr); ut_ad(btr_check_node_ptr(index, merge_block, mtr)); -func_exit: - mem_heap_free(heap); - - if (adjust) { - btr_cur_position( - index, - page_rec_get_nth(merge_block->frame, nth_rec), - merge_block, cursor); - } - return(TRUE); } diff --git a/storage/innodb_plugin/btr/btr0cur.c b/storage/innodb_plugin/btr/btr0cur.c index 4c862f061c5..9f4be053a43 100644 --- a/storage/innodb_plugin/btr/btr0cur.c +++ b/storage/innodb_plugin/btr/btr0cur.c @@ -2099,9 +2099,7 @@ btr_cur_pessimistic_update( /*=======================*/ ulint flags, /*!< in: undo logging, locking, and rollback flags */ - btr_cur_t* cursor, /*!< in/out: cursor on the record to update; - cursor may become invalid if *big_rec == NULL - || !(flags & BTR_KEEP_POS_FLAG) */ + btr_cur_t* cursor, /*!< in: cursor on the record to update */ mem_heap_t** heap, /*!< in/out: pointer to memory heap, or NULL */ big_rec_t** big_rec,/*!< out: big rec vector whose fields have to be stored externally by the caller, or NULL */ @@ -2240,7 +2238,7 @@ btr_cur_pessimistic_update( record to be inserted: we have to remember which fields were such */ ut_ad(!page_is_comp(page) || !rec_get_node_ptr_flag(rec)); - ut_ad(rec_offs_validate(rec, index, offsets)); + offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, heap); n_ext += btr_push_update_extern_fields(new_entry, update, *heap); if (UNIV_LIKELY_NULL(page_zip)) { @@ -2263,10 +2261,6 @@ make_external: err = DB_TOO_BIG_RECORD; goto return_after_reservations; } - - ut_ad(page_is_leaf(page)); - ut_ad(dict_index_is_clust(index)); - ut_ad(flags & BTR_KEEP_POS_FLAG); } /* Store state of explicit locks on rec on the page infimum record, @@ -2294,8 +2288,6 @@ make_external: rec = btr_cur_insert_if_possible(cursor, new_entry, n_ext, mtr); if (rec) { - page_cursor->rec = rec; - lock_rec_restore_from_page_infimum(btr_cur_get_block(cursor), rec, block); @@ -2309,10 +2301,7 @@ make_external: rec, index, offsets, mtr); } - btr_cur_compress_if_useful( - cursor, - big_rec_vec != NULL && (flags & BTR_KEEP_POS_FLAG), - mtr); + btr_cur_compress_if_useful(cursor, mtr); if (page_zip && !dict_index_is_clust(index) && page_is_leaf(page)) { @@ -2332,21 +2321,6 @@ make_external: } } - if (big_rec_vec) { - ut_ad(page_is_leaf(page)); - ut_ad(dict_index_is_clust(index)); - ut_ad(flags & BTR_KEEP_POS_FLAG); - - /* btr_page_split_and_insert() in - btr_cur_pessimistic_insert() invokes - mtr_memo_release(mtr, index->lock, MTR_MEMO_X_LOCK). - We must keep the index->lock when we created a - big_rec, so that row_upd_clust_rec() can store the - big_rec in the same mini-transaction. */ - - mtr_x_lock(dict_index_get_lock(index), mtr); - } - /* Was the record to be updated positioned as the first user record on its page? */ was_first = page_cur_is_before_first(page_cursor); @@ -2362,7 +2336,6 @@ make_external: ut_a(rec); ut_a(err == DB_SUCCESS); ut_a(dummy_big_rec == NULL); - page_cursor->rec = rec; if (dict_index_is_sec_or_ibuf(index)) { /* Update PAGE_MAX_TRX_ID in the index page header. @@ -2421,39 +2394,6 @@ return_after_reservations: return(err); } -/**************************************************************//** -Commits and restarts a mini-transaction so that it will retain an -x-lock on index->lock and the cursor page. */ -UNIV_INTERN -void -btr_cur_mtr_commit_and_start( -/*=========================*/ - btr_cur_t* cursor, /*!< in: cursor */ - mtr_t* mtr) /*!< in/out: mini-transaction */ -{ - buf_block_t* block; - - block = btr_cur_get_block(cursor); - - ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(cursor->index), - MTR_MEMO_X_LOCK)); - ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); - /* Keep the locks across the mtr_commit(mtr). */ - rw_lock_x_lock(dict_index_get_lock(cursor->index)); - rw_lock_x_lock(&block->lock); - mutex_enter(&block->mutex); - buf_block_buf_fix_inc(block, __FILE__, __LINE__); - mutex_exit(&block->mutex); - /* Write out the redo log. */ - mtr_commit(mtr); - mtr_start(mtr); - /* Reassociate the locks with the mini-transaction. - They will be released on mtr_commit(mtr). */ - mtr_memo_push(mtr, dict_index_get_lock(cursor->index), - MTR_MEMO_X_LOCK); - mtr_memo_push(mtr, block, MTR_MEMO_PAGE_X_FIX); -} - /*==================== B-TREE DELETE MARK AND UNMARK ===============*/ /****************************************************************//** @@ -2829,12 +2769,10 @@ UNIV_INTERN ibool btr_cur_compress_if_useful( /*=======================*/ - btr_cur_t* cursor, /*!< in/out: cursor on the page to compress; - cursor does not stay valid if !adjust and - compression occurs */ - ibool adjust, /*!< in: TRUE if should adjust the - cursor position even if compression occurs */ - mtr_t* mtr) /*!< in/out: mini-transaction */ + btr_cur_t* cursor, /*!< in: cursor on the page to compress; + cursor does not stay valid if compression + occurs */ + mtr_t* mtr) /*!< in: mtr */ { ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(btr_cur_get_index(cursor)), @@ -2843,7 +2781,7 @@ btr_cur_compress_if_useful( MTR_MEMO_PAGE_X_FIX)); return(btr_cur_compress_recommendation(cursor, mtr) - && btr_compress(cursor, adjust, mtr)); + && btr_compress(cursor, mtr)); } /*******************************************************//** @@ -3085,7 +3023,7 @@ return_after_reservations: mem_heap_free(heap); if (ret == FALSE) { - ret = btr_cur_compress_if_useful(cursor, FALSE, mtr); + ret = btr_cur_compress_if_useful(cursor, mtr); } if (n_extents > 0) { diff --git a/storage/innodb_plugin/include/btr0btr.h b/storage/innodb_plugin/include/btr0btr.h index c0a038dd21d..e32da9e4c86 100644 --- a/storage/innodb_plugin/include/btr0btr.h +++ b/storage/innodb_plugin/include/btr0btr.h @@ -488,14 +488,11 @@ UNIV_INTERN ibool btr_compress( /*=========*/ - btr_cur_t* cursor, /*!< in/out: cursor on the page to merge - or lift; the page must not be empty: - when deleting records, use btr_discard_page() - if the page would become empty */ - ibool adjust, /*!< in: TRUE if should adjust the - cursor position even if compression occurs */ - mtr_t* mtr) /*!< in/out: mini-transaction */ - __attribute__((nonnull)); + btr_cur_t* cursor, /*!< in: cursor on the page to merge or lift; + the page must not be empty: in record delete + use btr_discard_page if the page would become + empty */ + mtr_t* mtr); /*!< in: mtr */ /*************************************************************//** Discards a page from a B-tree. This is used to remove the last record from a B-tree page: the whole page must be removed at the same time. This cannot diff --git a/storage/innodb_plugin/include/btr0cur.h b/storage/innodb_plugin/include/btr0cur.h index 6094a2a6c7a..3669ce28f02 100644 --- a/storage/innodb_plugin/include/btr0cur.h +++ b/storage/innodb_plugin/include/btr0cur.h @@ -36,9 +36,6 @@ Created 10/16/1994 Heikki Tuuri #define BTR_NO_LOCKING_FLAG 2 /* do no record lock checking */ #define BTR_KEEP_SYS_FLAG 4 /* sys fields will be found from the update vector or inserted entry */ -#define BTR_KEEP_POS_FLAG 8 /* btr_cur_pessimistic_update() - must keep cursor position when - moving columns to big_rec */ #ifndef UNIV_HOTBACKUP #include "que0types.h" @@ -312,9 +309,7 @@ btr_cur_pessimistic_update( /*=======================*/ ulint flags, /*!< in: undo logging, locking, and rollback flags */ - btr_cur_t* cursor, /*!< in/out: cursor on the record to update; - cursor may become invalid if *big_rec == NULL - || !(flags & BTR_KEEP_POS_FLAG) */ + btr_cur_t* cursor, /*!< in: cursor on the record to update */ mem_heap_t** heap, /*!< in/out: pointer to memory heap, or NULL */ big_rec_t** big_rec,/*!< out: big rec vector whose fields have to be stored externally by the caller, or NULL */ @@ -326,16 +321,6 @@ btr_cur_pessimistic_update( que_thr_t* thr, /*!< in: query thread */ mtr_t* mtr); /*!< in: mtr; must be committed before latching any further pages */ -/***************************************************************** -Commits and restarts a mini-transaction so that it will retain an -x-lock on index->lock and the cursor page. */ -UNIV_INTERN -void -btr_cur_mtr_commit_and_start( -/*=========================*/ - btr_cur_t* cursor, /*!< in: cursor */ - mtr_t* mtr) /*!< in/out: mini-transaction */ - __attribute__((nonnull)); /***********************************************************//** Marks a clustered index record deleted. Writes an undo log record to undo log on this delete marking. Writes in the trx id field the id @@ -391,13 +376,10 @@ UNIV_INTERN ibool btr_cur_compress_if_useful( /*=======================*/ - btr_cur_t* cursor, /*!< in/out: cursor on the page to compress; + btr_cur_t* cursor, /*!< in: cursor on the page to compress; cursor does not stay valid if compression occurs */ - ibool adjust, /*!< in: TRUE if should adjust the - cursor position even if compression occurs */ - mtr_t* mtr) /*!< in/out: mini-transaction */ - __attribute__((nonnull)); + mtr_t* mtr); /*!< in: mtr */ /*******************************************************//** Removes the record on which the tree cursor is positioned. It is assumed that the mtr has an x-latch on the page where the cursor is positioned, diff --git a/storage/innodb_plugin/include/btr0cur.ic b/storage/innodb_plugin/include/btr0cur.ic index c833b3e8572..cd3a5d895bb 100644 --- a/storage/innodb_plugin/include/btr0cur.ic +++ b/storage/innodb_plugin/include/btr0cur.ic @@ -139,7 +139,7 @@ btr_cur_compress_recommendation( btr_cur_t* cursor, /*!< in: btr cursor */ mtr_t* mtr) /*!< in: mtr */ { - const page_t* page; + page_t* page; ut_ad(mtr_memo_contains(mtr, btr_cur_get_block(cursor), MTR_MEMO_PAGE_X_FIX)); diff --git a/storage/innodb_plugin/include/buf0buf.h b/storage/innodb_plugin/include/buf0buf.h index e7fe3901ad4..489d1bec5b6 100644 --- a/storage/innodb_plugin/include/buf0buf.h +++ b/storage/innodb_plugin/include/buf0buf.h @@ -468,31 +468,6 @@ buf_block_get_modify_clock( #else /* !UNIV_HOTBACKUP */ # define buf_block_modify_clock_inc(block) ((void) 0) #endif /* !UNIV_HOTBACKUP */ -/*******************************************************************//** -Increments the bufferfix count. */ -UNIV_INLINE -void -buf_block_buf_fix_inc_func( -/*=======================*/ -#ifdef UNIV_SYNC_DEBUG - const char* file, /*!< in: file name */ - ulint line, /*!< in: line */ -#endif /* UNIV_SYNC_DEBUG */ - buf_block_t* block) /*!< in/out: block to bufferfix */ - __attribute__((nonnull)); -#ifdef UNIV_SYNC_DEBUG -/** Increments the bufferfix count. -@param b in/out: block to bufferfix -@param f in: file name where requested -@param l in: line number where requested */ -# define buf_block_buf_fix_inc(b,f,l) buf_block_buf_fix_inc_func(f,l,b) -#else /* UNIV_SYNC_DEBUG */ -/** Increments the bufferfix count. -@param b in/out: block to bufferfix -@param f in: file name where requested -@param l in: line number where requested */ -# define buf_block_buf_fix_inc(b,f,l) buf_block_buf_fix_inc_func(b) -#endif /* UNIV_SYNC_DEBUG */ /********************************************************************//** Calculates a page checksum which is stored to the page when it is written to a file. Note that we must be careful to calculate the same value diff --git a/storage/innodb_plugin/include/buf0buf.ic b/storage/innodb_plugin/include/buf0buf.ic index 2f3d65e80bd..0fe1dbc2da5 100644 --- a/storage/innodb_plugin/include/buf0buf.ic +++ b/storage/innodb_plugin/include/buf0buf.ic @@ -916,6 +916,19 @@ buf_block_buf_fix_inc_func( block->page.buf_fix_count++; } +#ifdef UNIV_SYNC_DEBUG +/** Increments the bufferfix count. +@param b in/out: block to bufferfix +@param f in: file name where requested +@param l in: line number where requested */ +# define buf_block_buf_fix_inc(b,f,l) buf_block_buf_fix_inc_func(f,l,b) +#else /* UNIV_SYNC_DEBUG */ +/** Increments the bufferfix count. +@param b in/out: block to bufferfix +@param f in: file name where requested +@param l in: line number where requested */ +# define buf_block_buf_fix_inc(b,f,l) buf_block_buf_fix_inc_func(b) +#endif /* UNIV_SYNC_DEBUG */ /*******************************************************************//** Decrements the bufferfix count. */ diff --git a/storage/innodb_plugin/include/page0page.h b/storage/innodb_plugin/include/page0page.h index caf4cee2c57..12c4fed75d2 100644 --- a/storage/innodb_plugin/include/page0page.h +++ b/storage/innodb_plugin/include/page0page.h @@ -281,42 +281,16 @@ page_get_supremum_offset( const page_t* page); /*!< in: page which must have record(s) */ #define page_get_infimum_rec(page) ((page) + page_get_infimum_offset(page)) #define page_get_supremum_rec(page) ((page) + page_get_supremum_offset(page)) - /************************************************************//** -Returns the nth record of the record list. -This is the inverse function of page_rec_get_n_recs_before(). -@return nth record */ -UNIV_INTERN -const rec_t* -page_rec_get_nth_const( -/*===================*/ - const page_t* page, /*!< in: page */ - ulint nth) /*!< in: nth record */ - __attribute__((nonnull, warn_unused_result)); -/************************************************************//** -Returns the nth record of the record list. -This is the inverse function of page_rec_get_n_recs_before(). -@return nth record */ -UNIV_INLINE -rec_t* -page_rec_get_nth( -/*=============*/ - page_t* page, /*< in: page */ - ulint nth) /*!< in: nth record */ - __attribute__((nonnull, warn_unused_result)); - -#ifndef UNIV_HOTBACKUP -/************************************************************//** -Returns the middle record of the records on the page. If there is an -even number of records in the list, returns the first record of the -upper half-list. +Returns the middle record of record list. If there are an even number +of records in the list, returns the first record of upper half-list. @return middle record */ -UNIV_INLINE +UNIV_INTERN rec_t* page_get_middle_rec( /*================*/ - page_t* page) /*!< in: page */ - __attribute__((nonnull, warn_unused_result)); + page_t* page); /*!< in: page */ +#ifndef UNIV_HOTBACKUP /*************************************************************//** Compares a data tuple to a physical record. Differs from the function cmp_dtuple_rec_with_match in the way that the record must reside on an @@ -371,7 +345,6 @@ page_get_n_recs( /***************************************************************//** Returns the number of records before the given record in chain. The number includes infimum and supremum records. -This is the inverse function of page_rec_get_nth(). @return number of records */ UNIV_INTERN ulint diff --git a/storage/innodb_plugin/include/page0page.ic b/storage/innodb_plugin/include/page0page.ic index 1450b0892b3..b096a5ba321 100644 --- a/storage/innodb_plugin/include/page0page.ic +++ b/storage/innodb_plugin/include/page0page.ic @@ -420,37 +420,7 @@ page_rec_is_infimum( return(page_rec_is_infimum_low(page_offset(rec))); } -/************************************************************//** -Returns the nth record of the record list. -This is the inverse function of page_rec_get_n_recs_before(). -@return nth record */ -UNIV_INLINE -rec_t* -page_rec_get_nth( -/*=============*/ - page_t* page, /*!< in: page */ - ulint nth) /*!< in: nth record */ -{ - return((rec_t*) page_rec_get_nth_const(page, nth)); -} - #ifndef UNIV_HOTBACKUP -/************************************************************//** -Returns the middle record of the records on the page. If there is an -even number of records in the list, returns the first record of the -upper half-list. -@return middle record */ -UNIV_INLINE -rec_t* -page_get_middle_rec( -/*================*/ - page_t* page) /*!< in: page */ -{ - ulint middle = (page_get_n_recs(page) + PAGE_HEAP_NO_USER_LOW) / 2; - - return(page_rec_get_nth(page, middle)); -} - /*************************************************************//** Compares a data tuple to a physical record. Differs from the function cmp_dtuple_rec_with_match in the way that the record must reside on an diff --git a/storage/innodb_plugin/page/page0cur.c b/storage/innodb_plugin/page/page0cur.c index b8c492328e8..ab5aa257338 100644 --- a/storage/innodb_plugin/page/page0cur.c +++ b/storage/innodb_plugin/page/page0cur.c @@ -1180,15 +1180,14 @@ page_cur_insert_rec_zip_reorg( /* Before trying to reorganize the page, store the number of preceding records on the page. */ pos = page_rec_get_n_recs_before(rec); - ut_ad(pos > 0); if (page_zip_reorganize(block, index, mtr)) { /* The page was reorganized: Find rec by seeking to pos, and update *current_rec. */ - if (pos > 1) { - rec = page_rec_get_nth(page, pos - 1); - } else { - rec = page + PAGE_NEW_INFIMUM; + rec = page + PAGE_NEW_INFIMUM; + + while (--pos) { + rec = page + rec_get_next_offs(rec, TRUE); } *current_rec = rec; @@ -1284,12 +1283,6 @@ page_cur_insert_rec_zip( insert_rec = page_cur_insert_rec_zip_reorg( current_rec, block, index, insert_rec, page, page_zip, mtr); -#ifdef UNIV_DEBUG - if (insert_rec) { - rec_offs_make_valid( - insert_rec, index, offsets); - } -#endif /* UNIV_DEBUG */ } return(insert_rec); diff --git a/storage/innodb_plugin/page/page0page.c b/storage/innodb_plugin/page/page0page.c index 1b9470acbbc..93869e997b5 100644 --- a/storage/innodb_plugin/page/page0page.c +++ b/storage/innodb_plugin/page/page0page.c @@ -1475,54 +1475,55 @@ page_dir_balance_slot( } } +#ifndef UNIV_HOTBACKUP /************************************************************//** -Returns the nth record of the record list. -This is the inverse function of page_rec_get_n_recs_before(). -@return nth record */ +Returns the middle record of the record list. If there are an even number +of records in the list, returns the first record of the upper half-list. +@return middle record */ UNIV_INTERN -const rec_t* -page_rec_get_nth_const( -/*===================*/ - const page_t* page, /*!< in: page */ - ulint nth) /*!< in: nth record */ +rec_t* +page_get_middle_rec( +/*================*/ + page_t* page) /*!< in: page */ { - const page_dir_slot_t* slot; + page_dir_slot_t* slot; + ulint middle; ulint i; ulint n_owned; - const rec_t* rec; + ulint count; + rec_t* rec; - ut_ad(nth < UNIV_PAGE_SIZE / (REC_N_NEW_EXTRA_BYTES + 1)); + /* This many records we must leave behind */ + middle = (page_get_n_recs(page) + PAGE_HEAP_NO_USER_LOW) / 2; + + count = 0; for (i = 0;; i++) { slot = page_dir_get_nth_slot(page, i); n_owned = page_dir_slot_get_n_owned(slot); - if (n_owned > nth) { + if (count + n_owned > middle) { break; } else { - nth -= n_owned; + count += n_owned; } } ut_ad(i > 0); slot = page_dir_get_nth_slot(page, i - 1); - rec = page_dir_slot_get_rec(slot); + rec = (rec_t*) page_dir_slot_get_rec(slot); + rec = page_rec_get_next(rec); - if (page_is_comp(page)) { - do { - rec = page_rec_get_next_low(rec, TRUE); - ut_ad(rec); - } while (nth--); - } else { - do { - rec = page_rec_get_next_low(rec, FALSE); - ut_ad(rec); - } while (nth--); + /* There are now count records behind rec */ + + for (i = 0; i < middle - count; i++) { + rec = page_rec_get_next(rec); } return(rec); } +#endif /* !UNIV_HOTBACKUP */ /***************************************************************//** Returns the number of records before the given record in chain. @@ -1584,7 +1585,6 @@ page_rec_get_n_recs_before( n--; ut_ad(n >= 0); - ut_ad(n < UNIV_PAGE_SIZE / (REC_N_NEW_EXTRA_BYTES + 1)); return((ulint) n); } diff --git a/storage/innodb_plugin/row/row0ins.c b/storage/innodb_plugin/row/row0ins.c index f0f6eca627f..82c3c931bef 100644 --- a/storage/innodb_plugin/row/row0ins.c +++ b/storage/innodb_plugin/row/row0ins.c @@ -345,9 +345,9 @@ row_ins_clust_index_entry_by_modify( return(DB_LOCK_TABLE_FULL); } - err = btr_cur_pessimistic_update( - BTR_KEEP_POS_FLAG, cursor, heap, big_rec, update, - 0, thr, mtr); + err = btr_cur_pessimistic_update(0, cursor, + heap, big_rec, update, + 0, thr, mtr); } return(err); @@ -1989,7 +1989,6 @@ row_ins_index_entry_low( ulint modify = 0; /* remove warning */ rec_t* insert_rec; rec_t* rec; - ulint* offsets; ulint err; ulint n_unique; big_rec_t* big_rec = NULL; @@ -2093,42 +2092,6 @@ row_ins_index_entry_low( err = row_ins_clust_index_entry_by_modify( mode, &cursor, &heap, &big_rec, entry, thr, &mtr); - - if (big_rec) { - ut_a(err == DB_SUCCESS); - /* Write out the externally stored - columns while still x-latching - index->lock and block->lock. We have - to mtr_commit(mtr) first, so that the - redo log will be written in the - correct order. Otherwise, we would run - into trouble on crash recovery if mtr - freed B-tree pages on which some of - the big_rec fields will be written. */ - btr_cur_mtr_commit_and_start(&cursor, &mtr); - - rec = btr_cur_get_rec(&cursor); - offsets = rec_get_offsets( - rec, index, NULL, - ULINT_UNDEFINED, &heap); - - err = btr_store_big_rec_extern_fields( - index, btr_cur_get_block(&cursor), - rec, offsets, &mtr, FALSE, big_rec); - /* If writing big_rec fails (for - example, because of DB_OUT_OF_FILE_SPACE), - the record will be corrupted. Even if - we did not update any externally - stored columns, our update could cause - the record to grow so that a - non-updated column was selected for - external storage. This non-update - would not have been written to the - undo log, and thus the record cannot - be rolled back. */ - ut_a(err == DB_SUCCESS); - goto stored_big_rec; - } } else { ut_ad(!n_ext); err = row_ins_sec_index_entry_by_modify( @@ -2157,6 +2120,8 @@ function_exit: mtr_commit(&mtr); if (UNIV_LIKELY_NULL(big_rec)) { + rec_t* rec; + ulint* offsets; mtr_start(&mtr); btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE, @@ -2170,7 +2135,6 @@ function_exit: index, btr_cur_get_block(&cursor), rec, offsets, &mtr, FALSE, big_rec); -stored_big_rec: if (modify) { dtuple_big_rec_free(big_rec); } else { diff --git a/storage/innodb_plugin/row/row0upd.c b/storage/innodb_plugin/row/row0upd.c index b5952ff0a78..072ca1d7b54 100644 --- a/storage/innodb_plugin/row/row0upd.c +++ b/storage/innodb_plugin/row/row0upd.c @@ -1969,43 +1969,28 @@ row_upd_clust_rec( ut_ad(!rec_get_deleted_flag(btr_pcur_get_rec(pcur), dict_table_is_comp(index->table))); - err = btr_cur_pessimistic_update( - BTR_NO_LOCKING_FLAG | BTR_KEEP_POS_FLAG, btr_cur, - &heap, &big_rec, node->update, node->cmpl_info, thr, mtr); - if (big_rec) { + err = btr_cur_pessimistic_update(BTR_NO_LOCKING_FLAG, btr_cur, + &heap, &big_rec, node->update, + node->cmpl_info, thr, mtr); + mtr_commit(mtr); + + if (err == DB_SUCCESS && big_rec) { ulint offsets_[REC_OFFS_NORMAL_SIZE]; rec_t* rec; rec_offs_init(offsets_); - ut_a(err == DB_SUCCESS); - /* Write out the externally stored columns while still - x-latching index->lock and block->lock. We have to - mtr_commit(mtr) first, so that the redo log will be - written in the correct order. Otherwise, we would run - into trouble on crash recovery if mtr freed B-tree - pages on which some of the big_rec fields will be - written. */ - btr_cur_mtr_commit_and_start(btr_cur, mtr); + mtr_start(mtr); + ut_a(btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, mtr)); rec = btr_cur_get_rec(btr_cur); err = btr_store_big_rec_extern_fields( index, btr_cur_get_block(btr_cur), rec, rec_get_offsets(rec, index, offsets_, ULINT_UNDEFINED, &heap), mtr, TRUE, big_rec); - /* If writing big_rec fails (for example, because of - DB_OUT_OF_FILE_SPACE), the record will be corrupted. - Even if we did not update any externally stored - columns, our update could cause the record to grow so - that a non-updated column was selected for external - storage. This non-update would not have been written - to the undo log, and thus the record cannot be rolled - back. */ - ut_a(err == DB_SUCCESS); + mtr_commit(mtr); } - mtr_commit(mtr); - if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); } From 8b482e837b3ae1da8f1b92fff970663e43b9d294 Mon Sep 17 00:00:00 2001 From: Hery Ramilison Date: Wed, 26 Oct 2011 20:44:18 +0200 Subject: [PATCH 051/288] cloning 5.5.18 off --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 7bac52ecdfb..4eec6bf9d34 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ MYSQL_VERSION_MAJOR=5 MYSQL_VERSION_MINOR=5 -MYSQL_VERSION_PATCH=18 +MYSQL_VERSION_PATCH=19 MYSQL_VERSION_EXTRA= From 006f649f4b13060a79e05f69eae8e44e0c1b0e0a Mon Sep 17 00:00:00 2001 From: Karen Langford Date: Wed, 26 Oct 2011 20:48:42 +0200 Subject: [PATCH 052/288] Increased 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 1d9c841c3bd1aea647127d39836429a9a0e4f03a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 27 Oct 2011 14:58:12 +0300 Subject: [PATCH 053/288] Bug #12884631 62146: TABLES ARE LOST FOR DDL row_rename_table_for_mysql(): Return DB_ERROR instead of DB_SUCCESS when fil_rename_tablespace() returns an error. This bug was introduced in the InnoDB Plugin. Approved by Sunny Bains over IM. --- storage/innodb_plugin/ChangeLog | 5 +++++ storage/innodb_plugin/row/row0mysql.c | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index 68f60c37f1f..5a4ef5fa4ef 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,3 +1,8 @@ +2011-10-27 The InnoDB Team + + * row/row0mysql.c: + Fix Bug #12884631 62146: TABLES ARE LOST FOR DDL + 2011-10-20 The InnoDB Team * btr/brt0cur.c: diff --git a/storage/innodb_plugin/row/row0mysql.c b/storage/innodb_plugin/row/row0mysql.c index 4e6a49cf8b0..6f689f9909d 100644 --- a/storage/innodb_plugin/row/row0mysql.c +++ b/storage/innodb_plugin/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 @@ -3971,6 +3971,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; } From 95fdeb89c2910977c12674867646649861ec7c7c Mon Sep 17 00:00:00 2001 From: Andrei Elkin Date: Thu, 27 Oct 2011 17:14:41 +0300 Subject: [PATCH 054/288] Bug#11763573 - 56299: MUTEX DEADLOCK WITH COM_BINLOG_DUMP, BINLOG PURGE, AND PROCESSLIST/KILL The bug case is similar to one fixed earlier bug_49536. Deadlock involving LOCK_log appears to be possible because the purge running thread is holding LOCK_log whereas there is no sense of doing that and which fact was exploited by the earlier bug fixes. Fixed with small reengineering of rotate_and_purge(), adding two new methods and setting up a policy to execute those instead of the former rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED). The policy for using rotate(), purge() is that if the caller acquires LOCK_log itself, it should call rotate(), release the mutex and run purge(). Side effect of this patch is refining error message of bug@11747416 to print the whole path. mysql-test/suite/rpl/r/rpl_cant_read_event_incident.result: the file name printing is changed to a relative path instead of just the file name. mysql-test/suite/rpl/r/rpl_log_pos.result: the file name printing is changed to a relative path instead of just the file name. mysql-test/suite/rpl/r/rpl_manual_change_index_file.result: the file name printing is changed to a relative path instead of just the file name. mysql-test/suite/rpl/r/rpl_packet.result: the file name printing is changed to a relative path instead of just the file name. mysql-test/suite/rpl/r/rpl_rotate_purge_deadlock.result: new result file is added. mysql-test/suite/rpl/t/rpl_cant_read_event_incident.test: The test of that bug can't satisfy windows and unix backslash interpretation so windows execution is chosen to bypass. mysql-test/suite/rpl/t/rpl_rotate_purge_deadlock-master.opt: new opt file is added. mysql-test/suite/rpl/t/rpl_rotate_purge_deadlock.test: regression test is added as well as verification of a possible side effect of the fixes is tried. sql/log.cc: LOCK_log is never taken during execution of log purging routine. The former MYSQL_BIN_LOG::rotate_and_purge is made to necessarily acquiring and releasing LOCK_log. If caller takes the mutex itself it has to use a new rotate(), purge() methods combination and to never let purge() be run with LOCK_log grabbed. split apart to allow the caller to chose either it Simulation of concurrently rotating/purging threads is added. sql/log.h: new rotate(), purge() methods are added to be used instead of the former rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED). rotate_and_purge() signature is changed. Caller should not call rotate_and_purge() but rather {rotate(), purge()} if LOCK_log is acquired by it. sql/rpl_injector.cc: changes to reflect the new rotate_and_purge() signature. sql/sql_class.h: unnecessary constants are removed. sql/sql_parse.cc: changes to reflect the new rotate_and_purge() signature. sql/sql_reload.cc: changes to reflect the new rotate_and_purge() signature. sql/sql_repl.cc: followup for bug@11747416: the file name printing is changed to a relative path instead of just the file name. --- .../rpl/r/rpl_cant_read_event_incident.result | 2 +- mysql-test/suite/rpl/r/rpl_log_pos.result | 2 +- .../rpl/r/rpl_manual_change_index_file.result | 2 +- mysql-test/suite/rpl/r/rpl_packet.result | 2 +- .../rpl/r/rpl_rotate_purge_deadlock.result | 30 ++++ .../rpl/t/rpl_cant_read_event_incident.test | 5 + .../t/rpl_rotate_purge_deadlock-master.opt | 1 + .../rpl/t/rpl_rotate_purge_deadlock.test | 92 ++++++++++++ sql/log.cc | 131 +++++++++++++----- sql/log.h | 4 +- sql/rpl_injector.cc | 4 +- sql/sql_class.h | 3 - sql/sql_parse.cc | 2 +- sql/sql_reload.cc | 2 +- sql/sql_repl.cc | 7 +- 15 files changed, 238 insertions(+), 51 deletions(-) create mode 100644 mysql-test/suite/rpl/r/rpl_rotate_purge_deadlock.result create mode 100644 mysql-test/suite/rpl/t/rpl_rotate_purge_deadlock-master.opt create mode 100644 mysql-test/suite/rpl/t/rpl_rotate_purge_deadlock.test 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..c1b2c6e3195 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 @@ -11,7 +11,7 @@ reset slave; start slave; include/wait_for_slave_param.inc [Last_IO_Errno] Last_IO_Errno = '1236' -Last_IO_Error = 'Got fatal error 1236 from master when reading data from binary log: 'binlog truncated in the middle of event; consider out of disk space on master; the last event was read from 'master-bin.000001' at 316, the last byte read was read from 'master-bin.000001' at 335.'' +Last_IO_Error = 'Got fatal error 1236 from master when reading data from binary log: 'binlog truncated in the middle of event; consider out of disk space on master; the last event was read from './master-bin.000001' at 316, the last byte read was read from './master-bin.000001' at 335.'' reset master; stop slave; reset slave; diff --git a/mysql-test/suite/rpl/r/rpl_log_pos.result b/mysql-test/suite/rpl/r/rpl_log_pos.result index 5e9c096d773..960b57992d4 100644 --- a/mysql-test/suite/rpl/r/rpl_log_pos.result +++ b/mysql-test/suite/rpl/r/rpl_log_pos.result @@ -9,7 +9,7 @@ change master to master_log_pos=MASTER_LOG_POS; Read_Master_Log_Pos = '75' start slave; include/wait_for_slave_io_error.inc [errno=1236] -Last_IO_Error = 'Got fatal error 1236 from master when reading data from binary log: 'log event entry exceeded max_allowed_packet; Increase max_allowed_packet on master; the last event was read from 'master-bin.000001' at 75, the last byte read was read from 'master-bin.000001' at 94.'' +Last_IO_Error = 'Got fatal error 1236 from master when reading data from binary log: 'log event entry exceeded max_allowed_packet; Increase max_allowed_packet on master; the last event was read from './master-bin.000001' at 75, the last byte read was read from './master-bin.000001' at 94.'' include/stop_slave_sql.inc show master status; File Position Binlog_Do_DB Binlog_Ignore_DB diff --git a/mysql-test/suite/rpl/r/rpl_manual_change_index_file.result b/mysql-test/suite/rpl/r/rpl_manual_change_index_file.result index 41101da98f8..e3efb7e7e14 100644 --- a/mysql-test/suite/rpl/r/rpl_manual_change_index_file.result +++ b/mysql-test/suite/rpl/r/rpl_manual_change_index_file.result @@ -5,7 +5,7 @@ CREATE TABLE t1(c1 INT); FLUSH LOGS; call mtr.add_suppression('Got fatal error 1236 from master when reading data from binary log: .*could not find next log'); include/wait_for_slave_io_error.inc [errno=1236] -Last_IO_Error = 'Got fatal error 1236 from master when reading data from binary log: 'could not find next log; the last event was read from 'master-bin.000002' at 237, the last byte read was read from 'master-bin.000002' at 237.'' +Last_IO_Error = 'Got fatal error 1236 from master when reading data from binary log: 'could not find next log; the last event was read from './master-bin.000002' at 237, the last byte read was read from './master-bin.000002' at 237.'' CREATE TABLE t2(c1 INT); FLUSH LOGS; CREATE TABLE t3(c1 INT); diff --git a/mysql-test/suite/rpl/r/rpl_packet.result b/mysql-test/suite/rpl/r/rpl_packet.result index a11fc16123d..2252d7be9d1 100644 --- a/mysql-test/suite/rpl/r/rpl_packet.result +++ b/mysql-test/suite/rpl/r/rpl_packet.result @@ -37,7 +37,7 @@ DROP TABLE t1; CREATE TABLE t1 (f1 int PRIMARY KEY, f2 LONGTEXT, f3 LONGTEXT) ENGINE=MyISAM; INSERT INTO t1(f1, f2, f3) VALUES(1, REPEAT('a', @@global.max_allowed_packet), REPEAT('b', @@global.max_allowed_packet)); include/wait_for_slave_io_error.inc [errno=1236] -Last_IO_Error = 'Got fatal error 1236 from master when reading data from binary log: 'log event entry exceeded max_allowed_packet; Increase max_allowed_packet on master; the last event was read from 'master-bin.000001' at 463, the last byte read was read from 'master-bin.000001' at 482.'' +Last_IO_Error = 'Got fatal error 1236 from master when reading data from binary log: 'log event entry exceeded max_allowed_packet; Increase max_allowed_packet on master; the last event was read from './master-bin.000001' at 463, the last byte read was read from './master-bin.000001' at 482.'' STOP SLAVE; RESET SLAVE; RESET MASTER; diff --git a/mysql-test/suite/rpl/r/rpl_rotate_purge_deadlock.result b/mysql-test/suite/rpl/r/rpl_rotate_purge_deadlock.result new file mode 100644 index 00000000000..34024f89617 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_rotate_purge_deadlock.result @@ -0,0 +1,30 @@ +include/master-slave.inc +[connection master] +show binary logs; +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'; +insert into t1 set f=repeat('a', 4096); +*** there must be two logs in the list *** +show binary logs; +Log_name File_size +master-bin.000001 # +master-bin.000002 # +insert into t1 set f=repeat('b', 4096); +*** there must be three logs in the list *** +show binary logs; +Log_name File_size +master-bin.000001 # +master-bin.000002 # +master-bin.000003 # +SET DEBUG_SYNC = 'now SIGNAL rotated'; +SET DEBUG_SYNC = 'RESET'; +SET DEBUG_SYNC = 'RESET'; +SET DEBUG_SYNC = 'at_purge_logs_before_date WAIT_FOR rotated'; +insert into t1 set f=repeat('b', 4096); +SET DEBUG_SYNC = 'now SIGNAL rotated'; +SET DEBUG_SYNC = 'RESET'; +SET DEBUG_SYNC = 'RESET'; +drop table t1; +include/rpl_end.inc 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 71445be55e6..5e88b163d99 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 @@ -14,6 +14,11 @@ --source include/master-slave.inc --source include/have_binlog_format_mixed.inc +# +# Bug#13050593 swallows `\' from Last_IO_Error +# todo: uncomment the filter once the bug is fixed. +# +--source include/not_windows.inc call mtr.add_suppression("Error in Log_event::read_log_event()"); diff --git a/mysql-test/suite/rpl/t/rpl_rotate_purge_deadlock-master.opt b/mysql-test/suite/rpl/t/rpl_rotate_purge_deadlock-master.opt new file mode 100644 index 00000000000..f71317fc399 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_rotate_purge_deadlock-master.opt @@ -0,0 +1 @@ +--max-binlog-size=4k --expire-logs-days=1 diff --git a/mysql-test/suite/rpl/t/rpl_rotate_purge_deadlock.test b/mysql-test/suite/rpl/t/rpl_rotate_purge_deadlock.test new file mode 100644 index 00000000000..429612c405f --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_rotate_purge_deadlock.test @@ -0,0 +1,92 @@ +# +# Bug#11763573 - 56299: MUTEX DEADLOCK WITH COM_BINLOG_DUMP, BINLOG PURGE, AND PROCESSLIST/KILL +# +source include/master-slave.inc; +source include/have_debug_sync.inc; +source include/have_binlog_format_row.inc; +source include/have_innodb.inc; + +# +# Testing that execution of two concurrent INSERTing connections both +# triggering the binlog rotation is correct even though their execution +# is interleaved. +# The test makes the first connection to complete the rotation part +# and yields control to the second connection that rotates as well and +# gets first on purging. And the fact of interleaving does not create +# any issue. +# + +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'; +send insert into t1 set f=repeat('a', 4096); + +connection master1; + +let $wait_condition= + SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST + WHERE STATE like "debug sync point: at_purge_logs_before_date%"; +--source include/wait_condition.inc + +--echo *** there must be two logs in the list *** +source include/show_binary_logs.inc; + +insert into t1 set f=repeat('b', 4096); + +--echo *** there must be three logs in the list *** +source include/show_binary_logs.inc; + +SET DEBUG_SYNC = 'now SIGNAL rotated'; +SET DEBUG_SYNC = 'RESET'; + +# the first connection finally completes its INSERT +connection master; +reap; +SET DEBUG_SYNC = 'RESET'; + +sync_slave_with_master; + + +# +# Testing the reported deadlock involving DUMP, KILL and INSERT threads +# + +connection master; +SET DEBUG_SYNC = 'at_purge_logs_before_date WAIT_FOR rotated'; +send insert into t1 set f=repeat('b', 4096); + +connection master1; + +# make sure INSERT reaches waiting point +let $wait_condition= + SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST + WHERE STATE like "debug sync point: at_purge_logs_before_date%"; +--source include/wait_condition.inc + +# find and kill DUMP thread +let $_tid= `select id from information_schema.processlist where command = 'Binlog Dump' limit 1`; +--disable_query_log +eval kill query $_tid; +--enable_query_log + +# +# Now the proof is that the new DUMP thread has executed +# a critical section of the deadlock without any regression and is UP +# +let $wait_condition= + SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST + WHERE command = 'Binlog Dump' and STATE like "Master has sent all binlog to slave%"; +--source include/wait_condition.inc + +SET DEBUG_SYNC = 'now SIGNAL rotated'; +SET DEBUG_SYNC = 'RESET'; + +connection master; +reap; +SET DEBUG_SYNC = 'RESET'; +drop table t1; + +sync_slave_with_master; + +--source include/rpl_end.inc diff --git a/sql/log.cc b/sql/log.cc index c6b41447d6a..77ba7aa6283 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -49,7 +49,7 @@ #include "sql_plugin.h" #include "rpl_handler.h" - +#include "debug_sync.h" /* max size of the log message */ #define MAX_LOG_BUFFER_SIZE 1024 #define MAX_TIME_SIZE 32 @@ -5002,19 +5002,29 @@ err: { bool synced; if ((error= flush_and_sync(&synced))) - goto unlock; - - if ((error= RUN_HOOK(binlog_storage, after_flush, + { + mysql_mutex_unlock(&LOCK_log); + } + else if ((error= RUN_HOOK(binlog_storage, after_flush, (thd, log_file_name, file->pos_in_file, synced)))) { sql_print_error("Failed to run 'after_flush' hooks"); - goto unlock; + mysql_mutex_unlock(&LOCK_log); + } + else + { + bool check_purge; + signal_update(); + error= rotate(false, &check_purge); + mysql_mutex_unlock(&LOCK_log); + if (!error && check_purge) + purge(); } - signal_update(); - rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED); } -unlock: - mysql_mutex_unlock(&LOCK_log); + else + { + mysql_mutex_unlock(&LOCK_log); + } } if (error) @@ -5100,25 +5110,29 @@ bool general_log_write(THD *thd, enum enum_server_command command, } /** + The method executes rotation when LOCK_log is already acquired + by the caller. + + @param force_rotate caller can request the log rotation + @param check_purge is set to true if rotation took place + @note If rotation fails, for instance the server was unable to create a new log file, we still try to write an incident event to the current log. @retval - nonzero - error + nonzero - error in rotating routine. */ -int MYSQL_BIN_LOG::rotate_and_purge(uint flags) +int MYSQL_BIN_LOG::rotate(bool force_rotate, bool* check_purge) { int error= 0; - DBUG_ENTER("MYSQL_BIN_LOG::rotate_and_purge"); -#ifdef HAVE_REPLICATION - bool check_purge= false; -#endif - if (!(flags & RP_LOCK_LOG_IS_ALREADY_LOCKED)) - mysql_mutex_lock(&LOCK_log); - if ((flags & RP_FORCE_ROTATE) || - (my_b_tell(&log_file) >= (my_off_t) max_size)) + DBUG_ENTER("MYSQL_BIN_LOG::rotate"); + + //todo: fix the macro def and restore safe_mutex_assert_owner(&LOCK_log); + *check_purge= false; + + if (force_rotate || (my_b_tell(&log_file) >= (my_off_t) max_size)) { if ((error= new_file_without_locking())) /** @@ -5133,24 +5147,59 @@ int MYSQL_BIN_LOG::rotate_and_purge(uint flags) if (!write_incident(current_thd, FALSE)) flush_and_sync(0); -#ifdef HAVE_REPLICATION - check_purge= true; -#endif + *check_purge= true; } - if (!(flags & RP_LOCK_LOG_IS_ALREADY_LOCKED)) - mysql_mutex_unlock(&LOCK_log); + DBUG_RETURN(error); +} + +/** + The method executes logs purging routine. + + @retval + nonzero - error in rotating routine. +*/ +void MYSQL_BIN_LOG::purge() +{ #ifdef HAVE_REPLICATION - /* - NOTE: Run purge_logs wo/ holding LOCK_log - as it otherwise will deadlock in ndbcluster_binlog_index_purge_file - */ - if (!error && check_purge && expire_logs_days) + if (expire_logs_days) { + DEBUG_SYNC(current_thd, "at_purge_logs_before_date"); time_t purge_time= my_time(0) - expire_logs_days*24*60*60; if (purge_time >= 0) + { purge_logs_before_date(purge_time); + } } #endif +} + +/** + The method is a shortcut of @c rotate() and @c purge(). + LOCK_log is acquired prior to rotate and is released after it. + + @param force_rotate caller can request the log rotation + + @retval + nonzero - error in rotating routine. +*/ +int MYSQL_BIN_LOG::rotate_and_purge(bool force_rotate) +{ + int error= 0; + DBUG_ENTER("MYSQL_BIN_LOG::rotate_and_purge"); + bool check_purge= false; + + //todo: fix the macro def and restore safe_mutex_assert_not_owner(&LOCK_log); + mysql_mutex_lock(&LOCK_log); + error= rotate(force_rotate, &check_purge); + /* + NOTE: Run purge_logs wo/ holding LOCK_log because it does not need + the mutex. Otherwise causes various deadlocks. + */ + mysql_mutex_unlock(&LOCK_log); + + if (!error && check_purge) + purge(); + DBUG_RETURN(error); } @@ -5352,10 +5401,17 @@ bool MYSQL_BIN_LOG::write_incident(THD *thd, bool lock) { if (!error && !(error= flush_and_sync(0))) { + bool check_purge= false; signal_update(); - error= rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED); + error= rotate(false, &check_purge); + mysql_mutex_unlock(&LOCK_log); + if (!error && check_purge) + purge(); + } + else + { + mysql_mutex_unlock(&LOCK_log); } - mysql_mutex_unlock(&LOCK_log); } DBUG_RETURN(error); } @@ -5388,11 +5444,13 @@ bool MYSQL_BIN_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event, bool incident) { DBUG_ENTER("MYSQL_BIN_LOG::write(THD *, IO_CACHE *, Log_event *)"); - mysql_mutex_lock(&LOCK_log); DBUG_ASSERT(is_open()); if (likely(is_open())) // Should always be true { + bool check_purge; + + mysql_mutex_lock(&LOCK_log); /* We only bother to write to the binary log if there is anything to write. @@ -5460,12 +5518,17 @@ bool MYSQL_BIN_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event, mysql_mutex_lock(&LOCK_prep_xids); prepared_xids++; mysql_mutex_unlock(&LOCK_prep_xids); + mysql_mutex_unlock(&LOCK_log); } else - if (rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED)) + { + if (rotate(false, &check_purge)) goto err; + mysql_mutex_unlock(&LOCK_log); + if (check_purge) + purge(); + } } - mysql_mutex_unlock(&LOCK_log); DBUG_RETURN(0); diff --git a/sql/log.h b/sql/log.h index 0f0f81dd402..481bd545960 100644 --- a/sql/log.h +++ b/sql/log.h @@ -455,7 +455,9 @@ public: void make_log_name(char* buf, const char* log_ident); bool is_active(const char* log_file_name); int update_log_index(LOG_INFO* linfo, bool need_update_threads); - int rotate_and_purge(uint flags); + int rotate(bool force_rotate, bool* check_purge); + void purge(); + int rotate_and_purge(bool force_rotate); /** Flush binlog cache and synchronize to disk. diff --git a/sql/rpl_injector.cc b/sql/rpl_injector.cc index d4e3e0fd7b4..c5fdc521f11 100644 --- a/sql/rpl_injector.cc +++ b/sql/rpl_injector.cc @@ -237,7 +237,7 @@ int injector::record_incident(THD *thd, Incident incident) Incident_log_event ev(thd, incident); if (int error= mysql_bin_log.write(&ev)) return error; - return mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE); + return mysql_bin_log.rotate_and_purge(true); } int injector::record_incident(THD *thd, Incident incident, LEX_STRING const message) @@ -245,5 +245,5 @@ int injector::record_incident(THD *thd, Incident incident, LEX_STRING const mess Incident_log_event ev(thd, incident, message); if (int error= mysql_bin_log.write(&ev)) return error; - return mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE); + return mysql_bin_log.rotate_and_purge(true); } diff --git a/sql/sql_class.h b/sql/sql_class.h index 9f13908d31c..1a51b66f8a6 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -161,9 +161,6 @@ typedef struct st_user_var_events bool unsigned_flag; } BINLOG_USER_VAR_EVENT; -#define RP_LOCK_LOG_IS_ALREADY_LOCKED 1 -#define RP_FORCE_ROTATE 2 - /* The COPY_INFO structure is used by INSERT/REPLACE code. The schema of the row counting by the INSERT/INSERT ... ON DUPLICATE KEY diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 4fac64749e9..e3da697ec78 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2861,7 +2861,7 @@ end_with_restore_list: { Incident_log_event ev(thd, incident); (void) mysql_bin_log.write(&ev); /* error is ignored */ - if (mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE)) + if (mysql_bin_log.rotate_and_purge(true)) { res= 1; break; diff --git a/sql/sql_reload.cc b/sql/sql_reload.cc index b567e3a1f85..089077bb89c 100644 --- a/sql/sql_reload.cc +++ b/sql/sql_reload.cc @@ -141,7 +141,7 @@ bool reload_acl_and_cache(THD *thd, unsigned long options, tmp_write_to_binlog= 0; if (mysql_bin_log.is_open()) { - if (mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE)) + if (mysql_bin_log.rotate_and_purge(true)) *write_to_binlog= -1; } } diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 80fef42434c..ef7d35ecfaa 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -1030,12 +1030,9 @@ err: detailing the fatal error message with coordinates of the last position read. */ - char b_start[FN_REFLEN], b_end[FN_REFLEN]; - fn_format(b_start, coord->file_name, "", "", MY_REPLACE_DIR); - fn_format(b_end, log_file_name, "", "", MY_REPLACE_DIR); my_snprintf(error_text, sizeof(error_text), fmt, errmsg, - b_start, (llstr(coord->pos, llbuff1), llbuff1), - b_end, (llstr(my_b_tell(&log), llbuff2), llbuff2)); + coord->file_name, (llstr(coord->pos, llbuff1), llbuff1), + log_file_name, (llstr(my_b_tell(&log), llbuff2), llbuff2)); } else strcpy(error_text, errmsg); From 20ffbd3dd76b01acc967502385cd202f3912b19f Mon Sep 17 00:00:00 2001 From: Karen Langford Date: Fri, 28 Oct 2011 16:40:46 +0200 Subject: [PATCH 055/288] Patch to fix libedit vis.h problem (OSX/FreeBSD) --- cmd-line-utils/libedit/np/unvis.c | 8 ++++---- cmd-line-utils/libedit/np/vis.c | 8 ++++---- cmd-line-utils/libedit/read.c | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/cmd-line-utils/libedit/np/unvis.c b/cmd-line-utils/libedit/np/unvis.c index 4c523608c27..9267db71137 100644 --- a/cmd-line-utils/libedit/np/unvis.c +++ b/cmd-line-utils/libedit/np/unvis.c @@ -50,11 +50,11 @@ static char sccsid[] = "@(#)unvis.c 8.1 (Berkeley) 6/4/93"; #include #include #include -#ifdef HAVE_VIS_H -#include -#else +/* + XXXMYSQL : Due to different versions of vis.h available, + use the one bundled with libedit. +*/ #include "np/vis.h" -#endif #ifdef __weak_alias __weak_alias(strnunvisx,_strnunvisx) diff --git a/cmd-line-utils/libedit/np/vis.c b/cmd-line-utils/libedit/np/vis.c index 6c75438c352..d7cc37b4f47 100644 --- a/cmd-line-utils/libedit/np/vis.c +++ b/cmd-line-utils/libedit/np/vis.c @@ -68,11 +68,11 @@ #include #include -#ifdef HAVE_VIS_H -#include -#else +/* + XXXMYSQL : Due to different versions of vis.h available, + use the one bundled with libedit. +*/ #include "np/vis.h" -#endif #include #include diff --git a/cmd-line-utils/libedit/read.c b/cmd-line-utils/libedit/read.c index 48bf4efd59b..a919b888965 100644 --- a/cmd-line-utils/libedit/read.c +++ b/cmd-line-utils/libedit/read.c @@ -333,7 +333,7 @@ memset(&state, 0, sizeof(mbstate_t)); #ifdef WIDECHAR ++cbp; - if (cbp > MB_CUR_MAX) { /* "shouldn't happen" */ + if (cbp > (size_t) MB_CUR_MAX) { /* "shouldn't happen" */ *cp = '\0'; return (-1); } From b3b1e4c7858c198a1b82c4b6818905df145e3dda Mon Sep 17 00:00:00 2001 From: Andrei Elkin Date: Sat, 29 Oct 2011 00:07:16 +0300 Subject: [PATCH 056/288] BUG#11763573 post-push fixes for show_slave_io_error= 1 of wait_for_slave_io_error.inc; Unix and win format path specifically so few tests have to change show_slave_io_error to zero. --- mysql-test/suite/rpl/r/rpl_log_pos.result | 1 - mysql-test/suite/rpl/r/rpl_manual_change_index_file.result | 1 - mysql-test/suite/rpl/r/rpl_packet.result | 1 - mysql-test/suite/rpl/t/rpl_log_pos.test | 7 ++++++- mysql-test/suite/rpl/t/rpl_manual_change_index_file.test | 7 ++++++- mysql-test/suite/rpl/t/rpl_packet.test | 7 ++++++- 6 files changed, 18 insertions(+), 6 deletions(-) diff --git a/mysql-test/suite/rpl/r/rpl_log_pos.result b/mysql-test/suite/rpl/r/rpl_log_pos.result index 960b57992d4..42b88711f03 100644 --- a/mysql-test/suite/rpl/r/rpl_log_pos.result +++ b/mysql-test/suite/rpl/r/rpl_log_pos.result @@ -9,7 +9,6 @@ change master to master_log_pos=MASTER_LOG_POS; Read_Master_Log_Pos = '75' start slave; include/wait_for_slave_io_error.inc [errno=1236] -Last_IO_Error = 'Got fatal error 1236 from master when reading data from binary log: 'log event entry exceeded max_allowed_packet; Increase max_allowed_packet on master; the last event was read from './master-bin.000001' at 75, the last byte read was read from './master-bin.000001' at 94.'' include/stop_slave_sql.inc show master status; File Position Binlog_Do_DB Binlog_Ignore_DB diff --git a/mysql-test/suite/rpl/r/rpl_manual_change_index_file.result b/mysql-test/suite/rpl/r/rpl_manual_change_index_file.result index e3efb7e7e14..a2dc5d402a7 100644 --- a/mysql-test/suite/rpl/r/rpl_manual_change_index_file.result +++ b/mysql-test/suite/rpl/r/rpl_manual_change_index_file.result @@ -5,7 +5,6 @@ CREATE TABLE t1(c1 INT); FLUSH LOGS; call mtr.add_suppression('Got fatal error 1236 from master when reading data from binary log: .*could not find next log'); include/wait_for_slave_io_error.inc [errno=1236] -Last_IO_Error = 'Got fatal error 1236 from master when reading data from binary log: 'could not find next log; the last event was read from './master-bin.000002' at 237, the last byte read was read from './master-bin.000002' at 237.'' CREATE TABLE t2(c1 INT); FLUSH LOGS; CREATE TABLE t3(c1 INT); diff --git a/mysql-test/suite/rpl/r/rpl_packet.result b/mysql-test/suite/rpl/r/rpl_packet.result index 2252d7be9d1..27f85cac7de 100644 --- a/mysql-test/suite/rpl/r/rpl_packet.result +++ b/mysql-test/suite/rpl/r/rpl_packet.result @@ -37,7 +37,6 @@ DROP TABLE t1; CREATE TABLE t1 (f1 int PRIMARY KEY, f2 LONGTEXT, f3 LONGTEXT) ENGINE=MyISAM; INSERT INTO t1(f1, f2, f3) VALUES(1, REPEAT('a', @@global.max_allowed_packet), REPEAT('b', @@global.max_allowed_packet)); include/wait_for_slave_io_error.inc [errno=1236] -Last_IO_Error = 'Got fatal error 1236 from master when reading data from binary log: 'log event entry exceeded max_allowed_packet; Increase max_allowed_packet on master; the last event was read from './master-bin.000001' at 463, the last byte read was read from './master-bin.000001' at 482.'' STOP SLAVE; RESET SLAVE; RESET MASTER; diff --git a/mysql-test/suite/rpl/t/rpl_log_pos.test b/mysql-test/suite/rpl/t/rpl_log_pos.test index 484ffa52a44..882a05712f2 100644 --- a/mysql-test/suite/rpl/t/rpl_log_pos.test +++ b/mysql-test/suite/rpl/t/rpl_log_pos.test @@ -22,7 +22,12 @@ let $status_items= Read_Master_Log_Pos; source include/show_slave_status.inc; start slave; let $slave_io_errno= 1236; -let $show_slave_io_error= 1; +# +# Win and Unix path is printed differently: BUG#13055685. So +# show_slave_io_error is made 0 until the bug fixes provide necessary +# facilities +# +let $show_slave_io_error= 0; source include/wait_for_slave_io_error.inc; source include/stop_slave_sql.inc; diff --git a/mysql-test/suite/rpl/t/rpl_manual_change_index_file.test b/mysql-test/suite/rpl/t/rpl_manual_change_index_file.test index b0d3b23b4e1..9b648de8486 100644 --- a/mysql-test/suite/rpl/t/rpl_manual_change_index_file.test +++ b/mysql-test/suite/rpl/t/rpl_manual_change_index_file.test @@ -60,7 +60,12 @@ call mtr.add_suppression('Got fatal error 1236 from master when reading data fro connection slave; # 1236 = ER_MASTER_FATAL_ERROR_READING_BINLOG --let $slave_io_errno= 1236 ---let $show_slave_io_error= 1 +# +# Win and Unix path is printed differently: BUG#13055685. So +# show_slave_io_error is made 0 until the bug fixes provide necessary +# facilities +# +--let $show_slave_io_error= 0 --source include/wait_for_slave_io_error.inc connection master; diff --git a/mysql-test/suite/rpl/t/rpl_packet.test b/mysql-test/suite/rpl/t/rpl_packet.test index 7e9a35883a3..2b8a1fd8310 100644 --- a/mysql-test/suite/rpl/t/rpl_packet.test +++ b/mysql-test/suite/rpl/t/rpl_packet.test @@ -125,7 +125,12 @@ connection slave; # The slave I/O thread must stop after receiving # 1236=ER_MASTER_FATAL_ERROR_READING_BINLOG error message from master. --let $slave_io_errno= 1236 ---let $show_slave_io_error= 1 +# +# Win and Unix path is printed differently: BUG#13055685. So +# show_slave_io_error is made 0 until the bug fixes provide necessary +# facilities +# +--let $show_slave_io_error= 0 --source include/wait_for_slave_io_error.inc # Remove the bad binlog and clear error status on slave. From aac03193362f8e68ccbc46743a52e830ce94f44f Mon Sep 17 00:00:00 2001 From: Karen Langford Date: Sat, 29 Oct 2011 20:08:40 +0200 Subject: [PATCH 057/288] Patch to fix stdint.h missing from pre Solaris 10 versions. --- cmd-line-utils/libedit/histedit.h | 5 +++++ cmd-line-utils/libedit/np/unvis.c | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/cmd-line-utils/libedit/histedit.h b/cmd-line-utils/libedit/histedit.h index 9f2b245f851..523d27b0be2 100644 --- a/cmd-line-utils/libedit/histedit.h +++ b/cmd-line-utils/libedit/histedit.h @@ -43,7 +43,12 @@ #define LIBEDIT_MAJOR 2 #define LIBEDIT_MINOR 11 +/* XXXMYSQL : stdint.h might not be available on older Solaris platforms. */ +#if defined(__sun) || defined(__sun__) +#include +#else #include +#endif #include #include diff --git a/cmd-line-utils/libedit/np/unvis.c b/cmd-line-utils/libedit/np/unvis.c index 9267db71137..812d280b2d8 100644 --- a/cmd-line-utils/libedit/np/unvis.c +++ b/cmd-line-utils/libedit/np/unvis.c @@ -47,7 +47,14 @@ static char sccsid[] = "@(#)unvis.c 8.1 (Berkeley) 6/4/93"; #include #include + +/* XXXMYSQL : stdint.h might not be available on older Solaris platforms. */ +#if defined(__sun) || defined(__sun__) +#include +#else #include +#endif + #include #include /* From 2e7dd62646b643a86e17dae6fb58a69822a68c1f Mon Sep 17 00:00:00 2001 From: Tor Didriksen Date: Mon, 31 Oct 2011 10:10:04 +0100 Subject: [PATCH 058/288] Bug#12406055 post-push fix: unused variable 'num_chars' in optimized build. --- sql/sql_string.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sql/sql_string.cc b/sql/sql_string.cc index ea146c3938c..4dbc2d77206 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -200,7 +200,8 @@ end: #else #ifdef HAVE_SNPRINTF buff[sizeof(buff)-1]=0; // Safety - int num_chars= snprintf(buff, sizeof(buff)-1, "%.*f",(int) decimals, num); + IF_DBUG(int num_chars= ) + snprintf(buff, sizeof(buff)-1, "%.*f",(int) decimals, num); DBUG_ASSERT(num_chars > 0); DBUG_ASSERT(num_chars < (int) sizeof(buff)); #else From 0e2af2cdd32bc2482483c09ac8dd9c0aa7549c15 Mon Sep 17 00:00:00 2001 From: Tor Didriksen Date: Tue, 1 Nov 2011 07:50:54 +0100 Subject: [PATCH 059/288] Bug#12406055 post-push fix: unused variable 'num_chars' in optimized build. Also fixed possibly uninitialized use of need_copy_table_res. --- client/sql_string.cc | 3 ++- sql/sql_table.cc | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/client/sql_string.cc b/client/sql_string.cc index c7e235522e0..3fd9dccd784 100644 --- a/client/sql_string.cc +++ b/client/sql_string.cc @@ -188,7 +188,8 @@ end: #else #ifdef HAVE_SNPRINTF buff[sizeof(buff)-1]=0; // Safety - int num_chars= snprintf(buff, sizeof(buff)-1, "%.*f",(int) decimals, num); + IF_DBUG(int num_chars= ) + snprintf(buff, sizeof(buff)-1, "%.*f",(int) decimals, num); DBUG_ASSERT(num_chars > 0); DBUG_ASSERT(num_chars < (int) sizeof(buff)); #else diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 105b5e7a43c..b7feed5ab4c 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -6985,7 +6985,7 @@ view_err: need_copy_table= ALTER_TABLE_DATA_CHANGED; else { - enum_alter_table_change_level need_copy_table_res; + enum_alter_table_change_level need_copy_table_res=ALTER_TABLE_METADATA_ONLY; /* Check how much the tables differ. */ if (compare_tables(table, alter_info, create_info, order_num, From e51fcf8f728d5e482017c96737665011b8fd141a Mon Sep 17 00:00:00 2001 From: Sneha MOdi Date: Wed, 2 Nov 2011 16:53:41 +0530 Subject: [PATCH 060/288] BUG#11754168:PARTS OF INDEX_MERGE_INNODB.TEST ARE DISABLED DUE TO EXPLAIN DIFFS Parts of index_merge_innodb were disabled.These have been enabled with a few changes and the test is being made experimental to study it's behaviour. --- mysql-test/collections/default.experimental | 1 + mysql-test/include/index_merge1.inc | 123 +- mysql-test/include/index_merge2.inc | 44 +- mysql-test/include/index_merge_ror.inc | 52 + mysql-test/r/index_merge_innodb.result | 1156 +++++++++++++++++++ mysql-test/t/index_merge_innodb.test | 6 +- 6 files changed, 1353 insertions(+), 29 deletions(-) diff --git a/mysql-test/collections/default.experimental b/mysql-test/collections/default.experimental index b3623402065..0241397d996 100644 --- a/mysql-test/collections/default.experimental +++ b/mysql-test/collections/default.experimental @@ -6,6 +6,7 @@ binlog.binlog_multi_engine # joro : NDB tests marked as experiment funcs_1.charset_collation_1 # depends on compile-time decisions main.func_math @freebsd # Bug#11751977 2010-05-04 alik main.func_math fails on FreeBSD in PB2 +main.index_merge_innodb #Bug 11754168 - 45727: Disabled parts of index_merge_innodb due to explain diffs have been enabled main.lock_multi_bug38499 # Bug#11755645 2009-09-19 alik main.lock_multi_bug38499 times out sporadically main.outfile_loaddata @solaris # Bug#11755168 2010-01-20 alik Test "outfile_loaddata" fails (reproducible) main.signal_demo3 @solaris # Bug#11753919 2010-01-20 alik Several test cases fail on Solaris with error Thread stack overrun diff --git a/mysql-test/include/index_merge1.inc b/mysql-test/include/index_merge1.inc index ef116c5addc..52ea2f33193 100644 --- a/mysql-test/include/index_merge1.inc +++ b/mysql-test/include/index_merge1.inc @@ -11,6 +11,7 @@ # Note: The comments/expectations refer to MyISAM. # They might be not valid for other storage engines. # + # Last update: # 2006-08-02 ML test refactored # old name was t/index_merge.test @@ -57,82 +58,129 @@ update t0 set key2=key1,key3=key1,key4=key1,key5=key1,key6=key1,key7=key1,key8=1 analyze table t0; # 1. One index +--sorted_result +--replace_column 9 # explain select * from t0 where key1 < 3 or key1 > 1020; # 2. Simple cases +--sorted_result +--replace_column 9 # explain select * from t0 where key1 < 3 or key2 > 1020; select * from t0 where key1 < 3 or key2 > 1020; +--sorted_result +--replace_column 9 # explain select * from t0 where key1 < 3 or key2 <4; +--sorted_result +--replace_column 9 # explain -select * from t0 where (key1 > 30 and key1<35) or (key2 >32 and key2 < 40); +select * from t0 where (key1 > 30 and key1<35) or (key2 >32 and key2 < 40) ; # Bug#21277: InnoDB, wrong result set, index_merge strategy, second index not evaluated select * from t0 where (key1 > 30 and key1<35) or (key2 >32 and key2 < 40); # 3. Check that index_merge doesn't break "ignore/force/use index" +--sorted_result +--replace_column 9 # explain select * from t0 ignore index (i2) where key1 < 3 or key2 <4; +--sorted_result +--replace_column 9 # explain select * from t0 where (key1 < 3 or key2 <4) and key3 = 50; +--sorted_result +--replace_column 9 # explain select * from t0 use index (i1,i2) where (key1 < 3 or key2 <4) and key3 = 50; +--sorted_result +--replace_column 9 # explain select * from t0 where (key1 > 1 or key2 > 2); +--sorted_result +--replace_column 9 # explain select * from t0 force index (i1,i2) where (key1 > 1 or key2 > 2); # 4. Check if conjuncts are grouped by keyuse +--sorted_result +--replace_column 9 # explain select * from t0 where key1<3 or key2<3 or (key1>5 and key1<8) or (key1>10 and key1<12) or (key2>100 and key2<110); # 5. Check index_merge with conjuncts that are always true/false # verify fallback to "range" if there is only one non-confluent condition +--sorted_result +--replace_column 9 # explain select * from t0 where key2 = 45 or key1 <=> null; +--sorted_result +--replace_column 9 # explain select * from t0 where key2 = 45 or key1 is not null; +--sorted_result +--replace_column 9 # explain select * from t0 where key2 = 45 or key1 is null; # the last conj. is always false and will be discarded +--sorted_result +--replace_column 9 # explain select * from t0 where key2=10 or key3=3 or key4 <=> null; # the last conj. is always true and will cause 'all' scan +--sorted_result +--replace_column 9 # explain select * from t0 where key2=10 or key3=3 or key4 is null; # some more complicated cases +--sorted_result +--replace_column 9 # explain select key1 from t0 where (key1 <=> null) or (key2 < 5) or (key3=10) or (key4 <=> null); +--sorted_result +--replace_column 9 # explain select key1 from t0 where (key1 <=> null) or (key1 < 5) or (key3=10) or (key4 <=> null); # 6.Several ways to do index_merge, (ignored) index_merge vs. range +--sorted_result +--replace_column 9 # explain select * from t0 where (key1 < 3 or key2 < 3) and (key3 < 4 or key4 < 4) and (key5 < 5 or key6 < 5); +--sorted_result +--replace_column 9 # explain select * from t0 where (key1 < 3 or key2 < 6) and (key1 < 7 or key3 < 4); select * from t0 where (key1 < 3 or key2 < 6) and (key1 < 7 or key3 < 4); - +--sorted_result +--replace_column 9 # explain select * from t0 where (key1 < 3 or key2 < 3) and (key3 < 4 or key4 < 4) and (key5 < 2 or key6 < 2); # now index_merge is not used at all when "range" is possible +--sorted_result +--replace_column 9 # explain select * from t0 where (key1 < 3 or key2 < 3) and (key3 < 100); # this even can cause "all" scan: +--sorted_result +--replace_column 9 # explain select * from t0 where (key1 < 3 or key2 < 3) and (key3 < 1000); # 7. Complex cases # tree_or(List, range SEL_TREE). +--sorted_result +--replace_column 9 # explain select * from t0 where ((key1 < 4 or key2 < 4) and (key2 <5 or key3 < 4)) or key2 > 5; +--sorted_result +--replace_column 9 # explain select * from t0 where ((key1 < 4 or key2 < 4) and (key2 <5 or key3 < 4)) or @@ -144,31 +192,43 @@ select * from t0 where key1 < 7; # tree_or(List, List). +--sorted_result +--replace_column 9 # explain select * from t0 where ((key1 < 4 or key2 < 4) and (key3 <5 or key5 < 4)) or ((key5 < 5 or key6 < 6) and (key7 <7 or key8 < 4)); +--sorted_result +--replace_column 9 # explain select * from t0 where ((key3 <5 or key5 < 4) and (key1 < 4 or key2 < 4)) or ((key7 <7 or key8 < 4) and (key5 < 5 or key6 < 6)); +--sorted_result +--replace_column 9 # explain select * from t0 where ((key3 <5 or key5 < 4) and (key1 < 4 or key2 < 4)) or ((key3 <7 or key5 < 2) and (key5 < 5 or key6 < 6)); +--sorted_result +--replace_column 9 # explain select * from t0 where ((key3 <5 or key5 < 4) and (key1 < 4 or key2 < 4)) or (((key3 <7 and key7 < 6) or key5 < 2) and (key5 < 5 or key6 < 6)); +--sorted_result +--replace_column 9 # explain select * from t0 where ((key3 <5 or key5 < 4) and (key1 < 4 or key2 < 4)) or ((key3 >=5 or key5 < 2) and (key5 < 5 or key6 < 6)); +--sorted_result +--replace_column 9 # explain select * from t0 force index(i1, i2, i3, i4, i5, i6 ) where ((key3 <5 or key5 < 4) and (key1 < 4 or key2 < 4)) or @@ -177,6 +237,8 @@ explain select * from t0 force index(i1, i2, i3, i4, i5, i6 ) where # 8. Verify that "order by" after index merge uses filesort select * from t0 where key1 < 5 or key8 < 4 order by key1; +--sorted_result +--replace_column 9 # explain select * from t0 where key1 < 5 or key8 < 4 order by key1; @@ -191,12 +253,18 @@ alter table t2 drop index i2; alter table t2 add index i321(key3, key2, key1); # index_merge vs 'index', index_merge is better. +--sorted_result +--replace_column 9 # explain select key3 from t2 where key1 = 100 or key2 = 100; # index_merge vs 'index', 'index' is better. +--sorted_result +--replace_column 9 # explain select key3 from t2 where key1 <100 or key2 < 100; # index_merge vs 'all', index_merge is better. +--sorted_result +--replace_column 9 # explain select key7 from t2 where key1 <100 or key2 < 100; # 10. Multipart keys. @@ -217,13 +285,21 @@ insert into t4 select key1,key1,key1 div 10, key1 % 10, key1 % 10, key1 from t0; # the following will be handled by index_merge: select * from t4 where key1a = 3 or key1b = 4; +--sorted_result +--replace_column 9 # explain select * from t4 where key1a = 3 or key1b = 4; # and the following will not +--sorted_result +--replace_column 9 # explain select * from t4 where key2 = 1 and (key2_1 = 1 or key3 = 5); +--sorted_result +--replace_column 9 # explain select * from t4 where key2 = 1 and (key2_1 = 1 or key2_2 = 5); +--sorted_result +--replace_column 9 # explain select * from t4 where key2_1 = 1 or key2_2 = 5; @@ -232,38 +308,54 @@ create table t1 like t0; insert into t1 select * from t0; # index_merge on first table in join +--sorted_result +--replace_column 9 # explain select * from t0 left join t1 on (t0.key1=t1.key1) where t0.key1=3 or t0.key2=4; select * from t0 left join t1 on (t0.key1=t1.key1) where t0.key1=3 or t0.key2=4; +--sorted_result +--replace_column 9 # explain select * from t0,t1 where (t0.key1=t1.key1) and ( t0.key1=3 or t0.key2=4); # index_merge vs. ref +--sorted_result +--replace_column 8 test.t0.key1 4 # 6 # 9 # 7 # 10 # explain select * from t0,t1 where (t0.key1=t1.key1) and (t0.key1=3 or t0.key2=4) and t1.key1<200; # index_merge vs. ref +--sorted_result +--replace_column 8 test.t0.key1 9 # explain select * from t0,t1 where (t0.key1=t1.key1) and (t0.key1=3 or t0.key2<4) and t1.key1=2; # index_merge on second table in join +--sorted_result +--replace_column 8 test.t0.key1 9 # explain select * from t0,t1 where t0.key1 = 5 and (t1.key1 = t0.key1 or t1.key8 = t0.key1); # Fix for bug#1974 +--sorted_result +--replace_column 8 test.t0.key1 9 # explain select * from t0,t1 where t0.key1 < 3 and (t1.key1 = t0.key1 or t1.key8 = t0.key1); # index_merge inside union +--sorted_result +--replace_column 9 # explain select * from t1 where key1=3 or key2=4 union select * from t1 where key1<4 or key3=5; # index merge in subselect +--sorted_result +--replace_column 9 # explain select * from (select * from t1 where key1 = 3 or key2 =3) as Z where key8 >5; # 12. check for long index_merges. @@ -275,6 +367,8 @@ alter table t3 add keyB int not null, add index iB(keyB); alter table t3 add keyC int not null, add index iC(keyC); update t3 set key9=key1,keyA=key1,keyB=key1,keyC=key1; +--sorted_result +--replace_column 9 # explain select * from t3 where key1=1 or key2=2 or key3=3 or key4=4 or key5=5 or key6=6 or key7=7 or key8=8 or @@ -286,6 +380,8 @@ select * from t3 where key9=9 or keyA=10 or keyB=11 or keyC=12; # Test for Bug#3183 +--sorted_result +--replace_column 9 # 4 # 6 # 7 # 10 # explain select * from t0 where key1 < 3 or key2 < 4; # Bug#21277: InnoDB, wrong result set, index_merge strategy, second index not evaluated select * from t0 where key1 < 3 or key2 < 4; @@ -304,6 +400,8 @@ create table t4 (a int); insert into t4 values (1),(4),(3); set @save_join_buffer_size=@@join_buffer_size; set join_buffer_size= 4096; +--sorted_result +--replace_column 9 # explain select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) from t0 as A force index(i1,i2), t0 as B force index (i1,i2) where (A.key1 < 500000 or A.key2 < 3) @@ -315,6 +413,8 @@ select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 and (B.key1 < 500000 or B.key2 < 3); update t0 set key1=1; +--sorted_result +--replace_column 9 # explain select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) from t0 as A force index(i1,i2), t0 as B force index (i1,i2) where (A.key1 = 1 or A.key2 = 1) @@ -331,8 +431,11 @@ update t0 set key2=1, key3=1, key4=1, key5=1,key6=1,key7=1 where key7 < 500; # The next query will not use index i7 in intersection if the OS doesn't # support file sizes > 2GB. (ha_myisam::ref_length depends on this and index # scan cost estimates depend on ha_myisam::ref_length) +--sorted_result --replace_column 9 # --replace_result "4,4,4,4,4,4,4" X "4,4,4,4,4,4" X "i6,i7" "i6,i7?" "i6" "i6,i7?" +--sorted_result +--replace_column 9 # 4 # 6 # 7 # 10 # explain select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) from t0 as A, t0 as B where (A.key1 = 1 and A.key2 = 1 and A.key3 = 1 and A.key4=1 and A.key5=1 and A.key6=1 and A.key7 = 1 or A.key8=1) @@ -374,7 +477,9 @@ while ($1) OPTIMIZE TABLE t1; select count(*) from t1; +--replace_column 9 # explain select * from t1 WHERE cola = 'foo' AND colb = 'bar'; +--replace_column 9 # explain select * from t1 force index(cola,colb) WHERE cola = 'foo' AND colb = 'bar'; drop table t1; @@ -399,9 +504,11 @@ create table t3 ( key(a),key(b) ) engine=merge union=(t1,t2); ---replace_column 9 # +--sorted_result +--replace_column 9 # explain select * from t1 where a=1 and b=1; ---replace_column 9 # +--sorted_result +--replace_column 9 # explain select * from t3 where a=1 and b=1; drop table t3; @@ -472,6 +579,7 @@ create table t2( insert into t2 select * from t1; --echo must use sort-union rather than union: +--sorted_result --replace_column 9 # explain select * from t1 where a=4 or b=4; --sorted_result @@ -480,6 +588,7 @@ select * from t1 where a=4 or b=4; select * from t1 ignore index(a,b) where a=4 or b=4; --echo must use union, not sort-union: +--sorted_result --replace_column 9 # explain select * from t2 where a=4 or b=4; --sorted_result @@ -517,6 +626,8 @@ insert into t3 select 1000, 1000,'filler' from t0 A, t0 B, t0 C; insert into t3 values (1,1,'data'); insert into t3 values (1,1,'data'); -- echo The plan should be ALL/ALL/ALL(Range checked for each record (index map: 0x3) +--sorted_result +--replace_column 9 # explain select * from t1 where exists (select 1 from t2, t3 where t2.a=t1.a and (t3.a=t2.b or t3.b=t2.b or t3.b=t2.b+1)); @@ -540,7 +651,9 @@ INSERT INTO t1 SELECT * FROM t1; INSERT INTO t1 SELECT * FROM t1; INSERT INTO t1 SELECT * FROM t1; SET SESSION sort_buffer_size=1; -EXPLAIN +--sorted_result +--replace_column 9 # +explain SELECT * FROM t1 FORCE INDEX(a,b) WHERE a LIKE 'a%' OR b LIKE 'b%' ORDER BY a,b; # we don't actually care about the result : we're checking if it crashes diff --git a/mysql-test/include/index_merge2.inc b/mysql-test/include/index_merge2.inc index 23c8c6466c7..f9777b61a7f 100644 --- a/mysql-test/include/index_merge2.inc +++ b/mysql-test/include/index_merge2.inc @@ -124,6 +124,7 @@ select count(*) from t1; if ($index_merge_random_rows_in_EXPLAIN) { + --sorted_result --replace_column 9 # } explain select count(*) from t1 where @@ -134,6 +135,7 @@ select count(*) from t1 where if ($index_merge_random_rows_in_EXPLAIN) { + --sorted_result --replace_column 9 # } explain select count(*) from t1 where @@ -324,32 +326,32 @@ SELECT COUNT(*) FROM t1 WHERE b = 0 AND a = 0 AND c = 13286427 AND drop table t1; # BUG#21277: Index Merge/sort_union: wrong query results -create table t1 -( - key1 int not null, - key2 int not null default 0, - key3 int not null default 0 -); +#create table t1 +#( +# key1 int not null, +# key2 int not null default 0, +# key3 int not null default 0 +#); -insert into t1(key1) values (1),(2),(3),(4),(5),(6),(7),(8); +#insert into t1(key1) values (1),(2),(3),(4),(5),(6),(7),(8); -let $1=7; -set @d=8; -while ($1) -{ - eval insert into t1 (key1) select key1+@d from t1; - eval set @d=@d*2; - dec $1; -} +#let $1=7; +#set @d=8; +#while ($1) +#{ +# eval insert into t1 (key1) select key1+@d from t1; +# eval set @d=@d*2; +# dec $1; +#} -alter table t1 add index i2(key2); -alter table t1 add index i3(key3); -update t1 set key2=key1,key3=key1; +#alter table t1 add index i2(key2); +#alter table t1 add index i3(key3); +#update t1 set key2=key1,key3=key1; # to test the bug, the following must use "sort_union": -explain select * from t1 where (key3 > 30 and key3<35) or (key2 >32 and key2 < 40); -select * from t1 where (key3 > 30 and key3<35) or (key2 >32 and key2 < 40); -drop table t1; +#explain select * from t1 where (key3 > 30 and key3<35) or (key2 >32 and key2 < 40); +#select * from t1 where (key3 > 30 and key3<35) or (key2 >32 and key2 < 40); +#drop table t1; --echo # --echo # Bug#56423: Different count with SELECT and CREATE SELECT queries diff --git a/mysql-test/include/index_merge_ror.inc b/mysql-test/include/index_merge_ror.inc index 2764cbea468..798afbcf1fe 100644 --- a/mysql-test/include/index_merge_ror.inc +++ b/mysql-test/include/index_merge_ror.inc @@ -118,8 +118,12 @@ alter table t1 enable keys; select count(*) from t1; # One row results tests for cases where a single row matches all conditions +--sorted_result +--replace_column 9 # explain select key1,key2 from t1 where key1=100 and key2=100; select key1,key2 from t1 where key1=100 and key2=100; +--sorted_result +--replace_column 9 # explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; @@ -128,25 +132,35 @@ insert into t1 (key1, key2, key3, key4, filler1) values (100, 100, -1, -1, 'key1 insert into t1 (key1, key2, key3, key4, filler1) values (-1, -1, 100, 100, 'key4-key3'); # ROR-intersection, not covering +--sorted_result +--replace_column 9 # explain select key1,key2,filler1 from t1 where key1=100 and key2=100; select key1,key2,filler1 from t1 where key1=100 and key2=100; # ROR-intersection, covering +--sorted_result +--replace_column 9 # explain select key1,key2 from t1 where key1=100 and key2=100; select key1,key2 from t1 where key1=100 and key2=100; # ROR-union of ROR-intersections +--sorted_result +--replace_column 9 # explain select key1,key2,key3,key4 from t1 where key1=100 and key2=100 or key3=100 and key4=100; select key1,key2,key3,key4 from t1 where key1=100 and key2=100 or key3=100 and key4=100; explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; # 3-way ROR-intersection +--sorted_result +--replace_column 9 # explain select key1,key2,key3 from t1 where key1=100 and key2=100 and key3=100; select key1,key2,key3 from t1 where key1=100 and key2=100 and key3=100; # ROR-union(ROR-intersection, ROR-range) insert into t1 (key1,key2,key3,key4,filler1) values (101,101,101,101, 'key1234-101'); +--sorted_result +--replace_column 9 # explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=101; select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=101; @@ -159,16 +173,22 @@ select key1,key2,filler1 from t1 where key2=100 and key2=200; # ROR-union(ROR-intersection) with one of ROR-intersection giving empty # results +--sorted_result +--replace_column 9 # explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; delete from t1 where key3=100 and key4=100; # ROR-union with all ROR-intersections giving empty results +--sorted_result +--replace_column 9 # explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; # ROR-intersection with empty result +--sorted_result +--replace_column 9 # explain select key1,key2 from t1 where key1=100 and key2=100; select key1,key2 from t1 where key1=100 and key2=100; @@ -178,16 +198,22 @@ insert into t1 (key1, key2, key3, key4, filler1) values (100, 100, 200, 200,'key insert into t1 (key1, key2, key3, key4, filler1) values (100, 100, 200, 200,'key1-key2-key3-key4-2'); insert into t1 (key1, key2, key3, key4, filler1) values (100, 100, 200, 200,'key1-key2-key3-key4-3'); +--sorted_result +--replace_column 9 # explain select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200; select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200; insert into t1 (key1, key2, key3, key4, filler1) values (-1, -1, -1, 200,'key4'); +--sorted_result +--replace_column 9 # explain select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200; select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200; insert into t1 (key1, key2, key3, key4, filler1) values (-1, -1, 200, -1,'key3'); +--sorted_result +--replace_column 9 # explain select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200; select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200; @@ -196,10 +222,16 @@ select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2= ## # Check that the shortest key is used for ROR-intersection, covering and non-covering. +--sorted_result +--replace_column 9 # 6 # explain select * from t1 where st_a=1 and st_b=1; +--sorted_result +--replace_column 9 # explain select st_a,st_b from t1 where st_a=1 and st_b=1; # Check if "ingore index" syntax works +--sorted_result +--replace_column 9 # 6 # explain select st_a from t1 ignore index (st_a) where st_a=1 and st_b=1; # Do many tests @@ -208,30 +240,49 @@ explain select st_a from t1 ignore index (st_a) where st_a=1 and st_b=1; # Different value on 32 and 64 bit --replace_result sta_swt12a sta_swt21a sta_swt12a, sta_swt12a, +--replace_column 9 # explain select * from t1 where st_a=1 and swt1a=1 and swt2a=1; +--sorted_result +--replace_column 9 # explain select * from t1 where st_b=1 and swt1b=1 and swt2b=1; +--sorted_result +--replace_column 9 # explain select * from t1 where st_a=1 and swt1a=1 and swt2a=1 and st_b=1 and swt1b=1 and swt2b=1; +--sorted_result +--replace_column 9 # explain select * from t1 ignore index (sta_swt21a, stb_swt1a_2b) where st_a=1 and swt1a=1 and swt2a=1 and st_b=1 and swt1b=1 and swt2b=1; +--sorted_result +--replace_column 9 # explain select * from t1 ignore index (sta_swt21a, sta_swt12a, stb_swt1a_2b) where st_a=1 and swt1a=1 and swt2a=1 and st_b=1 and swt1b=1 and swt2b=1; +--sorted_result +--replace_column 9 # explain select * from t1 ignore index (sta_swt21a, sta_swt12a, stb_swt1a_2b, stb_swt1b) where st_a=1 and swt1a=1 and swt2a=1 and st_b=1 and swt1b=1 and swt2b=1; +--sorted_result +--replace_column 9 # explain select * from t1 where st_a=1 and swt1a=1 and swt2a=1 and st_b=1 and swt1b=1; +--sorted_result +--replace_column 9 # explain select * from t1 where st_a=1 and swt1a=1 and st_b=1 and swt1b=1 and swt1b=1; +--sorted_result +--replace_column 9 # explain select st_a from t1 where st_a=1 and swt1a=1 and st_b=1 and swt1b=1 and swt1b=1; +--sorted_result +--replace_column 9 # explain select st_a from t1 where st_a=1 and swt1a=1 and st_b=1 and swt1b=1 and swt1b=1; @@ -270,6 +321,7 @@ select count(a) from t2 where a='AAAAAAAA' and b='AAAAAAAA'; select count(a) from t2 ignore index(a,b) where a='AAAAAAAA' and b='AAAAAAAA'; insert into t2 values ('ab', 'ab', 'uh', 'oh'); +--replace_column 9 # explain select a from t2 where a='ab'; drop table t2; diff --git a/mysql-test/r/index_merge_innodb.result b/mysql-test/r/index_merge_innodb.result index 8bbbed2865f..1fcdce77da8 100644 --- a/mysql-test/r/index_merge_innodb.result +++ b/mysql-test/r/index_merge_innodb.result @@ -1,3 +1,1159 @@ +#---------------- Index merge test 1 ------------------------------------------- +SET SESSION STORAGE_ENGINE = InnoDB; +drop table if exists t0, t1, t2, t3, t4; +create table t0 +( +key1 int not null, +INDEX i1(key1) +); +alter table t0 add key2 int not null, add index i2(key2); +alter table t0 add key3 int not null, add index i3(key3); +alter table t0 add key4 int not null, add index i4(key4); +alter table t0 add key5 int not null, add index i5(key5); +alter table t0 add key6 int not null, add index i6(key6); +alter table t0 add key7 int not null, add index i7(key7); +alter table t0 add key8 int not null, add index i8(key8); +update t0 set key2=key1,key3=key1,key4=key1,key5=key1,key6=key1,key7=key1,key8=1024-key1; +analyze table t0; +Table Op Msg_type Msg_text +test.t0 analyze status OK +explain select * from t0 where key1 < 3 or key1 > 1020; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 range i1 i1 4 NULL # Using where +explain +select * from t0 where key1 < 3 or key2 > 1020; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 index_merge i1,i2 i1,i2 4,4 NULL # Using sort_union(i1,i2); Using where +select * from t0 where key1 < 3 or key2 > 1020; +key1 key2 key3 key4 key5 key6 key7 key8 +1 1 1 1 1 1 1 1023 +2 2 2 2 2 2 2 1022 +1021 1021 1021 1021 1021 1021 1021 3 +1022 1022 1022 1022 1022 1022 1022 2 +1023 1023 1023 1023 1023 1023 1023 1 +1024 1024 1024 1024 1024 1024 1024 0 +explain select * from t0 where key1 < 3 or key2 <4; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 ALL i1,i2 NULL NULL NULL # Using where +explain +select * from t0 where (key1 > 30 and key1<35) or (key2 >32 and key2 < 40) ; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 index_merge i1,i2 i1,i2 4,4 NULL # Using sort_union(i1,i2); Using where +select * from t0 where (key1 > 30 and key1<35) or (key2 >32 and key2 < 40); +key1 key2 key3 key4 key5 key6 key7 key8 +31 31 31 31 31 31 31 993 +32 32 32 32 32 32 32 992 +33 33 33 33 33 33 33 991 +34 34 34 34 34 34 34 990 +35 35 35 35 35 35 35 989 +36 36 36 36 36 36 36 988 +37 37 37 37 37 37 37 987 +38 38 38 38 38 38 38 986 +39 39 39 39 39 39 39 985 +explain select * from t0 ignore index (i2) where key1 < 3 or key2 <4; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 ALL i1 NULL NULL NULL # Using where +explain select * from t0 where (key1 < 3 or key2 <4) and key3 = 50; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 ref i1,i2,i3 i3 4 const # Using where +explain select * from t0 use index (i1,i2) where (key1 < 3 or key2 <4) and key3 = 50; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 ALL i1,i2 NULL NULL NULL # Using where +explain select * from t0 where (key1 > 1 or key2 > 2); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 ALL i1,i2 NULL NULL NULL # Using where +explain select * from t0 force index (i1,i2) where (key1 > 1 or key2 > 2); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 index_merge i1,i2 i1,i2 4,4 NULL # Using sort_union(i1,i2); Using where +explain +select * from t0 where key1<3 or key2<3 or (key1>5 and key1<8) or +(key1>10 and key1<12) or (key2>100 and key2<110); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 ALL i1,i2 NULL NULL NULL # Using where +explain select * from t0 where key2 = 45 or key1 <=> null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 range i1,i2 i2 4 NULL # Using where +explain select * from t0 where key2 = 45 or key1 is not null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 ALL i1,i2 NULL NULL NULL # Using where +explain select * from t0 where key2 = 45 or key1 is null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 ref i2 i2 4 const # +explain select * from t0 where key2=10 or key3=3 or key4 <=> null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 index_merge i2,i3,i4 i2,i3 4,4 NULL # Using union(i2,i3); Using where +explain select * from t0 where key2=10 or key3=3 or key4 is null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 index_merge i2,i3 i2,i3 4,4 NULL # Using union(i2,i3); Using where +explain select key1 from t0 where (key1 <=> null) or (key2 < 5) or +(key3=10) or (key4 <=> null); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 ALL i1,i2,i3,i4 NULL NULL NULL # Using where +explain select key1 from t0 where (key1 <=> null) or (key1 < 5) or +(key3=10) or (key4 <=> null); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 index_merge i1,i3,i4 i1,i3 4,4 NULL # Using sort_union(i1,i3); Using where +explain select * from t0 where +(key1 < 3 or key2 < 3) and (key3 < 4 or key4 < 4) and (key5 < 5 or key6 < 5); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 ALL i1,i2,i3,i4,i5,i6 NULL NULL NULL # Using where +explain +select * from t0 where (key1 < 3 or key2 < 6) and (key1 < 7 or key3 < 4); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 ALL i1,i2,i3 NULL NULL NULL # Using where +select * from t0 where (key1 < 3 or key2 < 6) and (key1 < 7 or key3 < 4); +key1 key2 key3 key4 key5 key6 key7 key8 +1 1 1 1 1 1 1 1023 +2 2 2 2 2 2 2 1022 +3 3 3 3 3 3 3 1021 +4 4 4 4 4 4 4 1020 +5 5 5 5 5 5 5 1019 +explain select * from t0 where +(key1 < 3 or key2 < 3) and (key3 < 4 or key4 < 4) and (key5 < 2 or key6 < 2); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 ALL i1,i2,i3,i4,i5,i6 NULL NULL NULL # Using where +explain select * from t0 where +(key1 < 3 or key2 < 3) and (key3 < 100); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 ALL i1,i2,i3 NULL NULL NULL # Using where +explain select * from t0 where +(key1 < 3 or key2 < 3) and (key3 < 1000); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 ALL i1,i2,i3 NULL NULL NULL # Using where +explain select * from t0 where +((key1 < 4 or key2 < 4) and (key2 <5 or key3 < 4)) +or +key2 > 5; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 ALL i1,i2,i3 NULL NULL NULL # Using where +explain select * from t0 where +((key1 < 4 or key2 < 4) and (key2 <5 or key3 < 4)) +or +key1 < 7; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 ALL i1,i2,i3 NULL NULL NULL # Using where +select * from t0 where +((key1 < 4 or key2 < 4) and (key2 <5 or key3 < 4)) +or +key1 < 7; +key1 key2 key3 key4 key5 key6 key7 key8 +1 1 1 1 1 1 1 1023 +2 2 2 2 2 2 2 1022 +3 3 3 3 3 3 3 1021 +4 4 4 4 4 4 4 1020 +5 5 5 5 5 5 5 1019 +6 6 6 6 6 6 6 1018 +explain select * from t0 where +((key1 < 4 or key2 < 4) and (key3 <5 or key5 < 4)) +or +((key5 < 5 or key6 < 6) and (key7 <7 or key8 < 4)); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 ALL i1,i2,i3,i5,i6,i7,i8 NULL NULL NULL # Using where +explain select * from t0 where +((key3 <5 or key5 < 4) and (key1 < 4 or key2 < 4)) +or +((key7 <7 or key8 < 4) and (key5 < 5 or key6 < 6)); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 ALL i1,i2,i3,i5,i6,i7,i8 NULL NULL NULL # Using where +explain select * from t0 where +((key3 <5 or key5 < 4) and (key1 < 4 or key2 < 4)) +or +((key3 <7 or key5 < 2) and (key5 < 5 or key6 < 6)); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 ALL i1,i2,i3,i5,i6 NULL NULL NULL # Using where +explain select * from t0 where +((key3 <5 or key5 < 4) and (key1 < 4 or key2 < 4)) +or +(((key3 <7 and key7 < 6) or key5 < 2) and (key5 < 5 or key6 < 6)); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 ALL i1,i2,i3,i5,i6,i7 NULL NULL NULL # Using where +explain select * from t0 where +((key3 <5 or key5 < 4) and (key1 < 4 or key2 < 4)) +or +((key3 >=5 or key5 < 2) and (key5 < 5 or key6 < 6)); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 ALL i1,i2,i3,i5,i6 NULL NULL NULL # Using where +explain select * from t0 force index(i1, i2, i3, i4, i5, i6 ) where +((key3 <5 or key5 < 4) and (key1 < 4 or key2 < 4)) +or +((key3 >=5 or key5 < 2) and (key5 < 5 or key6 < 6)); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 index_merge i1,i2,i3,i5,i6 i3,i5 0,4 NULL # Using sort_union(i3,i5); Using where +select * from t0 where key1 < 5 or key8 < 4 order by key1; +key1 key2 key3 key4 key5 key6 key7 key8 +1 1 1 1 1 1 1 1023 +2 2 2 2 2 2 2 1022 +3 3 3 3 3 3 3 1021 +4 4 4 4 4 4 4 1020 +1021 1021 1021 1021 1021 1021 1021 3 +1022 1022 1022 1022 1022 1022 1022 2 +1023 1023 1023 1023 1023 1023 1023 1 +1024 1024 1024 1024 1024 1024 1024 0 +explain +select * from t0 where key1 < 5 or key8 < 4 order by key1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 ALL i1,i8 NULL NULL NULL # Using where; Using filesort +create table t2 like t0; +insert into t2 select * from t0; +alter table t2 add index i1_3(key1, key3); +alter table t2 add index i2_3(key2, key3); +alter table t2 drop index i1; +alter table t2 drop index i2; +alter table t2 add index i321(key3, key2, key1); +explain select key3 from t2 where key1 = 100 or key2 = 100; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 index_merge i1_3,i2_3 i1_3,i2_3 4,4 NULL # Using sort_union(i1_3,i2_3); Using where +explain select key3 from t2 where key1 <100 or key2 < 100; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 index i1_3,i2_3 i321 12 NULL # Using where; Using index +explain select key7 from t2 where key1 <100 or key2 < 100; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL i1_3,i2_3 NULL NULL NULL # Using where +create table t4 ( +key1a int not null, +key1b int not null, +key2 int not null, +key2_1 int not null, +key2_2 int not null, +key3 int not null, +index i1a (key1a, key1b), +index i1b (key1b, key1a), +index i2_1(key2, key2_1), +index i2_2(key2, key2_1) +); +insert into t4 select key1,key1,key1 div 10, key1 % 10, key1 % 10, key1 from t0; +select * from t4 where key1a = 3 or key1b = 4; +key1a key1b key2 key2_1 key2_2 key3 +3 3 0 3 3 3 +4 4 0 4 4 4 +explain select * from t4 where key1a = 3 or key1b = 4; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t4 index_merge i1a,i1b i1a,i1b 4,4 NULL # Using sort_union(i1a,i1b); Using where +explain select * from t4 where key2 = 1 and (key2_1 = 1 or key3 = 5); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t4 ref i2_1,i2_2 i2_1 4 const # Using where +explain select * from t4 where key2 = 1 and (key2_1 = 1 or key2_2 = 5); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t4 ref i2_1,i2_2 i2_1 4 const # Using where +explain select * from t4 where key2_1 = 1 or key2_2 = 5; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t4 ALL NULL NULL NULL NULL # Using where +create table t1 like t0; +insert into t1 select * from t0; +explain select * from t0 left join t1 on (t0.key1=t1.key1) +where t0.key1=3 or t0.key2=4; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 index_merge i1,i2 i1,i2 4,4 NULL # Using union(i1,i2); Using where +1 SIMPLE t1 ref i1 i1 4 test.t0.key1 # +select * from t0 left join t1 on (t0.key1=t1.key1) +where t0.key1=3 or t0.key2=4; +key1 key2 key3 key4 key5 key6 key7 key8 key1 key2 key3 key4 key5 key6 key7 key8 +3 3 3 3 3 3 3 1021 3 3 3 3 3 3 3 1021 +4 4 4 4 4 4 4 1020 4 4 4 4 4 4 4 1020 +explain +select * from t0,t1 where (t0.key1=t1.key1) and ( t0.key1=3 or t0.key2=4); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 index_merge i1,i2 i1,i2 4,4 NULL # Using union(i1,i2); Using where +1 SIMPLE t1 ref i1 i1 4 test.t0.key1 # +explain +select * from t0,t1 where (t0.key1=t1.key1) and +(t0.key1=3 or t0.key2=4) and t1.key1<200; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 # i1,i2 # # test.t0.key1 # # +1 SIMPLE t1 # i1 # # test.t0.key1 # # +explain +select * from t0,t1 where (t0.key1=t1.key1) and +(t0.key1=3 or t0.key2<4) and t1.key1=2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 ref i1,i2 i1 4 test.t0.key1 # Using where +1 SIMPLE t1 ref i1 i1 4 test.t0.key1 # +explain select * from t0,t1 where t0.key1 = 5 and +(t1.key1 = t0.key1 or t1.key8 = t0.key1); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 ref i1 i1 4 test.t0.key1 # +1 SIMPLE t1 index_merge i1,i8 i1,i8 4,4 test.t0.key1 # Using union(i1,i8); Using where; Using join buffer +explain select * from t0,t1 where t0.key1 < 3 and +(t1.key1 = t0.key1 or t1.key8 = t0.key1); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 range i1 i1 4 test.t0.key1 # Using where +1 SIMPLE t1 ALL i1,i8 NULL NULL test.t0.key1 # Range checked for each record (index map: 0x81) +explain select * from t1 where key1=3 or key2=4 +union select * from t1 where key1<4 or key3=5; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 index_merge i1,i2 i1,i2 4,4 NULL # Using union(i1,i2); Using where +2 UNION t1 index_merge i1,i3 i1,i3 4,4 NULL # Using sort_union(i1,i3); Using where +NULL UNION RESULT ALL NULL NULL NULL NULL # +explain select * from (select * from t1 where key1 = 3 or key2 =3) as Z where key8 >5; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY system NULL NULL NULL NULL # +2 DERIVED t1 index_merge i1,i2 i1,i2 4,4 NULL # Using union(i1,i2); Using where; Using index +create table t3 like t0; +insert into t3 select * from t0; +alter table t3 add key9 int not null, add index i9(key9); +alter table t3 add keyA int not null, add index iA(keyA); +alter table t3 add keyB int not null, add index iB(keyB); +alter table t3 add keyC int not null, add index iC(keyC); +update t3 set key9=key1,keyA=key1,keyB=key1,keyC=key1; +explain select * from t3 where +key1=1 or key2=2 or key3=3 or key4=4 or +key5=5 or key6=6 or key7=7 or key8=8 or +key9=9 or keyA=10 or keyB=11 or keyC=12; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t3 index_merge i1,i2,i3,i4,i5,i6,i7,i8,i9,iA,iB,iC i1,i2,i3,i4,i5,i6,i7,i8,i9,iA,iB,iC 4,4,4,4,4,4,4,4,4,4,4,4 NULL # Using union(i1,i2,i3,i4,i5,i6,i7,i8,i9,iA,iB,iC); Using where +select * from t3 where +key1=1 or key2=2 or key3=3 or key4=4 or +key5=5 or key6=6 or key7=7 or key8=8 or +key9=9 or keyA=10 or keyB=11 or keyC=12; +key1 key2 key3 key4 key5 key6 key7 key8 key9 keyA keyB keyC +1 1 1 1 1 1 1 1023 1 1 1 1 +2 2 2 2 2 2 2 1022 2 2 2 2 +3 3 3 3 3 3 3 1021 3 3 3 3 +4 4 4 4 4 4 4 1020 4 4 4 4 +5 5 5 5 5 5 5 1019 5 5 5 5 +6 6 6 6 6 6 6 1018 6 6 6 6 +7 7 7 7 7 7 7 1017 7 7 7 7 +9 9 9 9 9 9 9 1015 9 9 9 9 +10 10 10 10 10 10 10 1014 10 10 10 10 +11 11 11 11 11 11 11 1013 11 11 11 11 +12 12 12 12 12 12 12 1012 12 12 12 12 +1016 1016 1016 1016 1016 1016 1016 8 1016 1016 1016 1016 +explain select * from t0 where key1 < 3 or key2 < 4; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 # i1,i2 # # NULL # # +select * from t0 where key1 < 3 or key2 < 4; +key1 key2 key3 key4 key5 key6 key7 key8 +1 1 1 1 1 1 1 1023 +2 2 2 2 2 2 2 1022 +3 3 3 3 3 3 3 1021 +update t0 set key8=123 where key1 < 3 or key2 < 4; +select * from t0 where key1 < 3 or key2 < 4; +key1 key2 key3 key4 key5 key6 key7 key8 +1 1 1 1 1 1 1 123 +2 2 2 2 2 2 2 123 +3 3 3 3 3 3 3 123 +delete from t0 where key1 < 3 or key2 < 4; +select * from t0 where key1 < 3 or key2 < 4; +key1 key2 key3 key4 key5 key6 key7 key8 +select count(*) from t0; +count(*) +1021 +drop table t4; +create table t4 (a int); +insert into t4 values (1),(4),(3); +set @save_join_buffer_size=@@join_buffer_size; +set join_buffer_size= 4096; +explain select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) +from t0 as A force index(i1,i2), t0 as B force index (i1,i2) +where (A.key1 < 500000 or A.key2 < 3) +and (B.key1 < 500000 or B.key2 < 3); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE A index_merge i1,i2 i1,i2 4,4 NULL # Using sort_union(i1,i2); Using where +1 SIMPLE B index_merge i1,i2 i1,i2 4,4 NULL # Using sort_union(i1,i2); Using where; Using join buffer +select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) +from t0 as A force index(i1,i2), t0 as B force index (i1,i2) +where (A.key1 < 500000 or A.key2 < 3) +and (B.key1 < 500000 or B.key2 < 3); +max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) +10240 +update t0 set key1=1; +explain select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) +from t0 as A force index(i1,i2), t0 as B force index (i1,i2) +where (A.key1 = 1 or A.key2 = 1) +and (B.key1 = 1 or B.key2 = 1); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE A index_merge i1,i2 i1,i2 4,4 NULL # Using union(i1,i2); Using where +1 SIMPLE B index_merge i1,i2 i1,i2 4,4 NULL # Using union(i1,i2); Using where; Using join buffer +select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) +from t0 as A force index(i1,i2), t0 as B force index (i1,i2) +where (A.key1 = 1 or A.key2 = 1) +and (B.key1 = 1 or B.key2 = 1); +max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) +8194 +alter table t0 add filler1 char(200), add filler2 char(200), add filler3 char(200); +update t0 set key2=1, key3=1, key4=1, key5=1,key6=1,key7=1 where key7 < 500; +explain select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) +from t0 as A, t0 as B +where (A.key1 = 1 and A.key2 = 1 and A.key3 = 1 and A.key4=1 and A.key5=1 and A.key6=1 and A.key7 = 1 or A.key8=1) +and (B.key1 = 1 and B.key2 = 1 and B.key3 = 1 and B.key4=1 and B.key5=1 and B.key6=1 and B.key7 = 1 or B.key8=1); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE A # i1,i2,i3,i4,i5,i6,i7?,i8 # # NULL # # +1 SIMPLE B # i1,i2,i3,i4,i5,i6,i7?,i8 # # NULL # # +select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) +from t0 as A, t0 as B +where (A.key1 = 1 and A.key2 = 1 and A.key3 = 1 and A.key4=1 and A.key5=1 and A.key6=1 and A.key7 = 1 or A.key8=1) +and (B.key1 = 1 and B.key2 = 1 and B.key3 = 1 and B.key4=1 and B.key5=1 and B.key6=1 and B.key7 = 1 or B.key8=1); +max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) +8186 +set join_buffer_size= @save_join_buffer_size; +drop table t0, t1, t2, t3, t4; +CREATE TABLE t1 ( +cola char(3) not null, colb char(3) not null, filler char(200), +key(cola), key(colb) +); +INSERT INTO t1 VALUES ('foo','bar', 'ZZ'),('fuz','baz', 'ZZ'); +OPTIMIZE TABLE t1; +Table Op Msg_type Msg_text +test.t1 optimize note Table does not support optimize, doing recreate + analyze instead +test.t1 optimize status OK +select count(*) from t1; +count(*) +8704 +explain select * from t1 WHERE cola = 'foo' AND colb = 'bar'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index_merge cola,colb cola,colb 3,3 NULL # Using intersect(cola,colb); Using where +explain select * from t1 force index(cola,colb) WHERE cola = 'foo' AND colb = 'bar'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index_merge cola,colb cola,colb 3,3 NULL # Using intersect(cola,colb); Using where +drop table t1; +CREATE TABLE t1(a INT); +INSERT INTO t1 VALUES(1); +CREATE TABLE t2(a INT, b INT, dummy CHAR(16) DEFAULT '', KEY(a), KEY(b)); +INSERT INTO t2(a,b) VALUES +(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0), +(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0), +(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0), +(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0), +(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0), +(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0), +(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0), +(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0), +(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0), +(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0), +(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0), +(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0), +(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0), +(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0), +(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0), +(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0), +(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0), +(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0), +(1,2); +LOCK TABLES t1 WRITE, t2 WRITE; +INSERT INTO t2(a,b) VALUES(1,2); +SELECT t2.a FROM t1,t2 WHERE t2.b=2 AND t2.a=1; +a +1 +1 +UNLOCK TABLES; +DROP TABLE t1, t2; +CREATE TABLE `t1` ( +`a` int(11) DEFAULT NULL, +`filler` char(200) DEFAULT NULL, +`b` int(11) DEFAULT NULL, +KEY `a` (`a`), +KEY `b` (`b`) +) ENGINE=MEMORY DEFAULT CHARSET=latin1; +insert into t1 values +(0, 'filler', 0), (1, 'filler', 1), (2, 'filler', 2), (3, 'filler', 3), +(4, 'filler', 4), (5, 'filler', 5), (6, 'filler', 6), (7, 'filler', 7), +(8, 'filler', 8), (9, 'filler', 9), (0, 'filler', 0), (1, 'filler', 1), +(2, 'filler', 2), (3, 'filler', 3), (4, 'filler', 4), (5, 'filler', 5), +(6, 'filler', 6), (7, 'filler', 7), (8, 'filler', 8), (9, 'filler', 9), +(10, 'filler', 10), (11, 'filler', 11), (12, 'filler', 12), (13, 'filler', 13), +(14, 'filler', 14), (15, 'filler', 15), (16, 'filler', 16), (17, 'filler', 17), +(18, 'filler', 18), (19, 'filler', 19), (4, '5 ', 0), (5, '4 ', 0), +(4, '4 ', 0), (4, 'qq ', 5), (5, 'qq ', 4), (4, 'zz ', 4); +create table t2( +`a` int(11) DEFAULT NULL, +`filler` char(200) DEFAULT NULL, +`b` int(11) DEFAULT NULL, +KEY USING BTREE (`a`), +KEY USING BTREE (`b`) +) ENGINE=MEMORY DEFAULT CHARSET=latin1; +insert into t2 select * from t1; +must use sort-union rather than union: +explain select * from t1 where a=4 or b=4; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index_merge a,b a,b 5,5 NULL # Using sort_union(a,b); Using where +select * from t1 where a=4 or b=4; +a filler b +4 4 0 +4 5 0 +4 filler 4 +4 filler 4 +4 qq 5 +4 zz 4 +5 qq 4 +select * from t1 ignore index(a,b) where a=4 or b=4; +a filler b +4 4 0 +4 5 0 +4 filler 4 +4 filler 4 +4 qq 5 +4 zz 4 +5 qq 4 +must use union, not sort-union: +explain select * from t2 where a=4 or b=4; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 index_merge a,b a,b 5,5 NULL # Using union(a,b); Using where +select * from t2 where a=4 or b=4; +a filler b +4 4 0 +4 5 0 +4 filler 4 +4 filler 4 +4 qq 5 +4 zz 4 +5 qq 4 +drop table t1, t2; +CREATE TABLE t1 (a varchar(8), b set('a','b','c','d','e','f','g','h'), +KEY b(b), KEY a(a)); +INSERT INTO t1 VALUES ('y',''), ('z',''); +SELECT b,a from t1 WHERE (b!='c' AND b!='f' && b!='h') OR +(a='pure-S') OR (a='DE80337a') OR (a='DE80799'); +b a + y + z +DROP TABLE t1; +# +# BUG#40974: Incorrect query results when using clause evaluated using range check +# +create table t0 (a int); +insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t1 (a int); +insert into t1 values (1),(2); +create table t2(a int, b int); +insert into t2 values (1,1), (2, 1000); +create table t3 (a int, b int, filler char(100), key(a), key(b)); +insert into t3 select 1000, 1000,'filler' from t0 A, t0 B, t0 C; +insert into t3 values (1,1,'data'); +insert into t3 values (1,1,'data'); +The plan should be ALL/ALL/ALL(Range checked for each record (index map: 0x3) +explain select * from t1 +where exists (select 1 from t2, t3 +where t2.a=t1.a and (t3.a=t2.b or t3.b=t2.b or t3.b=t2.b+1)); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL # Using where +2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL # Using where +2 DEPENDENT SUBQUERY t3 ALL a,b NULL NULL NULL # Range checked for each record (index map: 0x3) +select * from t1 +where exists (select 1 from t2, t3 +where t2.a=t1.a and (t3.a=t2.b or t3.b=t2.b or t3.b=t2.b+1)); +a +1 +2 +drop table t0, t1, t2, t3; +# +# BUG#44810: index merge and order by with low sort_buffer_size +# crashes server! +# +CREATE TABLE t1(a VARCHAR(128),b VARCHAR(128),KEY(A),KEY(B)); +INSERT INTO t1 VALUES (REPEAT('a',128),REPEAT('b',128)); +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +SET SESSION sort_buffer_size=1; +Warnings: +Warning 1292 Truncated incorrect sort_buffer_size value: '1' +explain +SELECT * FROM t1 FORCE INDEX(a,b) WHERE a LIKE 'a%' OR b LIKE 'b%' +ORDER BY a,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index_merge a,b a,b 131,131 NULL # Using sort_union(a,b); Using where; Using filesort +SELECT * FROM t1 FORCE INDEX(a,b) WHERE a LIKE 'a%' OR b LIKE 'b%' +ORDER BY a,b; +SET SESSION sort_buffer_size=DEFAULT; +DROP TABLE t1; +End of 5.0 tests +#---------------- ROR-index_merge tests ----------------------- +SET SESSION STORAGE_ENGINE = InnoDB; +drop table if exists t0,t1,t2; +create table t1 +( +/* Field names reflect value(rowid) distribution, st=STairs, swt= SaWTooth */ +st_a int not null default 0, +swt1a int not null default 0, +swt2a int not null default 0, +st_b int not null default 0, +swt1b int not null default 0, +swt2b int not null default 0, +/* fields/keys for row retrieval tests */ +key1 int, +key2 int, +key3 int, +key4 int, +/* make rows much bigger then keys */ +filler1 char (200), +filler2 char (200), +filler3 char (200), +filler4 char (200), +filler5 char (200), +filler6 char (200), +/* order of keys is important */ +key sta_swt12a(st_a,swt1a,swt2a), +key sta_swt1a(st_a,swt1a), +key sta_swt2a(st_a,swt2a), +key sta_swt21a(st_a,swt2a,swt1a), +key st_a(st_a), +key stb_swt1a_2b(st_b,swt1b,swt2a), +key stb_swt1b(st_b,swt1b), +key st_b(st_b), +key(key1), +key(key2), +key(key3), +key(key4) +) ; +create table t0 as select * from t1; +# Printing of many insert into t0 values (....) disabled. +alter table t1 disable keys; +Warnings: +Note 1031 Table storage engine for 't1' doesn't have this option +# Printing of many insert into t1 select .... from t0 disabled. +# Printing of many insert into t1 (...) values (....) disabled. +alter table t1 enable keys; +Warnings: +Note 1031 Table storage engine for 't1' doesn't have this option +select count(*) from t1; +count(*) +64801 +explain select key1,key2 from t1 where key1=100 and key2=100; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index_merge key1,key2 key1,key2 5,5 NULL # Using intersect(key1,key2); Using where; Using index +select key1,key2 from t1 where key1=100 and key2=100; +key1 key2 +100 100 +explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index_merge key1,key2,key3,key4 key1,key2,key3,key4 5,5,5,5 NULL # Using union(intersect(key1,key2),intersect(key3,key4)); Using where +select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; +key1 key2 key3 key4 filler1 +100 100 100 100 key1-key2-key3-key4 +insert into t1 (key1, key2, key3, key4, filler1) values (100, 100, -1, -1, 'key1-key2'); +insert into t1 (key1, key2, key3, key4, filler1) values (-1, -1, 100, 100, 'key4-key3'); +explain select key1,key2,filler1 from t1 where key1=100 and key2=100; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index_merge key1,key2 key1,key2 5,5 NULL # Using intersect(key1,key2); Using where +select key1,key2,filler1 from t1 where key1=100 and key2=100; +key1 key2 filler1 +100 100 key1-key2-key3-key4 +100 100 key1-key2 +explain select key1,key2 from t1 where key1=100 and key2=100; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index_merge key1,key2 key1,key2 5,5 NULL # Using intersect(key1,key2); Using where; Using index +select key1,key2 from t1 where key1=100 and key2=100; +key1 key2 +100 100 +100 100 +explain select key1,key2,key3,key4 from t1 where key1=100 and key2=100 or key3=100 and key4=100; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index_merge key1,key2,key3,key4 key1,key2,key3,key4 5,5,5,5 NULL # Using union(intersect(key1,key2),intersect(key3,key4)); Using where +select key1,key2,key3,key4 from t1 where key1=100 and key2=100 or key3=100 and key4=100; +key1 key2 key3 key4 +100 100 100 100 +100 100 -1 -1 +-1 -1 100 100 +explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index_merge key1,key2,key3,key4 key1,key2,key3,key4 5,5,5,5 NULL 4 Using union(intersect(key1,key2),intersect(key3,key4)); Using where +select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; +key1 key2 key3 key4 filler1 +100 100 100 100 key1-key2-key3-key4 +100 100 -1 -1 key1-key2 +-1 -1 100 100 key4-key3 +explain select key1,key2,key3 from t1 where key1=100 and key2=100 and key3=100; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index_merge key1,key2,key3 key1,key2,key3 5,5,5 NULL # Using intersect(key1,key2,key3); Using where; Using index +select key1,key2,key3 from t1 where key1=100 and key2=100 and key3=100; +key1 key2 key3 +100 100 100 +insert into t1 (key1,key2,key3,key4,filler1) values (101,101,101,101, 'key1234-101'); +explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=101; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index_merge key1,key2,key3 key1,key2,key3 5,5,5 NULL # Using union(intersect(key1,key2),key3); Using where +select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=101; +key1 key2 key3 key4 filler1 +100 100 100 100 key1-key2-key3-key4 +100 100 -1 -1 key1-key2 +101 101 101 101 key1234-101 +select key1,key2, filler1 from t1 where key1=100 and key2=100; +key1 key2 filler1 +100 100 key1-key2-key3-key4 +100 100 key1-key2 +update t1 set filler1='to be deleted' where key1=100 and key2=100; +update t1 set key1=200,key2=200 where key1=100 and key2=100; +delete from t1 where key1=200 and key2=200; +select key1,key2,filler1 from t1 where key2=100 and key2=200; +key1 key2 filler1 +explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index_merge key1,key2,key3,key4 key1,key2,key3,key4 5,5,5,5 NULL # Using union(intersect(key1,key2),intersect(key3,key4)); Using where +select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; +key1 key2 key3 key4 filler1 +-1 -1 100 100 key4-key3 +delete from t1 where key3=100 and key4=100; +explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index_merge key1,key2,key3,key4 key1,key2,key3,key4 5,5,5,5 NULL # Using union(intersect(key1,key2),intersect(key3,key4)); Using where +select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; +key1 key2 key3 key4 filler1 +explain select key1,key2 from t1 where key1=100 and key2=100; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index_merge key1,key2 key1,key2 5,5 NULL # Using intersect(key1,key2); Using where; Using index +select key1,key2 from t1 where key1=100 and key2=100; +key1 key2 +insert into t1 (key1, key2, key3, key4, filler1) values (100, 100, 200, 200,'key1-key2-key3-key4-1'); +insert into t1 (key1, key2, key3, key4, filler1) values (100, 100, 200, 200,'key1-key2-key3-key4-2'); +insert into t1 (key1, key2, key3, key4, filler1) values (100, 100, 200, 200,'key1-key2-key3-key4-3'); +explain select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index_merge key1,key2,key3,key4 key3,key1,key2,key4 5,5,5,5 NULL # Using union(key3,intersect(key1,key2),key4); Using where +select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200; +key1 key2 key3 key4 filler1 +100 100 200 200 key1-key2-key3-key4-1 +100 100 200 200 key1-key2-key3-key4-2 +100 100 200 200 key1-key2-key3-key4-3 +insert into t1 (key1, key2, key3, key4, filler1) values (-1, -1, -1, 200,'key4'); +explain select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index_merge key1,key2,key3,key4 key3,key1,key2,key4 5,5,5,5 NULL # Using union(key3,intersect(key1,key2),key4); Using where +select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200; +key1 key2 key3 key4 filler1 +100 100 200 200 key1-key2-key3-key4-1 +100 100 200 200 key1-key2-key3-key4-2 +100 100 200 200 key1-key2-key3-key4-3 +-1 -1 -1 200 key4 +insert into t1 (key1, key2, key3, key4, filler1) values (-1, -1, 200, -1,'key3'); +explain select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index_merge key1,key2,key3,key4 key3,key1,key2,key4 5,5,5,5 NULL # Using union(key3,intersect(key1,key2),key4); Using where +select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200; +key1 key2 key3 key4 filler1 +100 100 200 200 key1-key2-key3-key4-1 +100 100 200 200 key1-key2-key3-key4-2 +100 100 200 200 key1-key2-key3-key4-3 +-1 -1 -1 200 key4 +-1 -1 200 -1 key3 +explain select * from t1 where st_a=1 and st_b=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a,stb_swt1a_2b,stb_swt1b,st_b # 4 const # Using where +explain select st_a,st_b from t1 where st_a=1 and st_b=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index_merge sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a,stb_swt1a_2b,stb_swt1b,st_b st_a,st_b 4,4 NULL # Using intersect(st_a,st_b); Using where; Using index +explain select st_a from t1 ignore index (st_a) where st_a=1 and st_b=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,stb_swt1a_2b,stb_swt1b,st_b # 4 const # Using where +explain select * from t1 where st_a=1 and swt1a=1 and swt2a=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a sta_swt21a 12 const,const,const # +explain select * from t1 where st_b=1 and swt1b=1 and swt2b=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref stb_swt1a_2b,stb_swt1b,st_b stb_swt1a_2b 8 const,const # Using where +explain select * from t1 where st_a=1 and swt1a=1 and swt2a=1 and st_b=1 and swt1b=1 and swt2b=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index_merge sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a,stb_swt1a_2b,stb_swt1b,st_b sta_swt12a,stb_swt1a_2b 12,12 NULL # Using intersect(sta_swt12a,stb_swt1a_2b); Using where +explain select * from t1 ignore index (sta_swt21a, stb_swt1a_2b) +where st_a=1 and swt1a=1 and swt2a=1 and st_b=1 and swt1b=1 and swt2b=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index_merge sta_swt12a,sta_swt1a,sta_swt2a,st_a,stb_swt1b,st_b sta_swt12a,stb_swt1b 12,8 NULL # Using intersect(sta_swt12a,stb_swt1b); Using where +explain select * from t1 ignore index (sta_swt21a, sta_swt12a, stb_swt1a_2b) +where st_a=1 and swt1a=1 and swt2a=1 and st_b=1 and swt1b=1 and swt2b=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index_merge sta_swt1a,sta_swt2a,st_a,stb_swt1b,st_b sta_swt1a,sta_swt2a,stb_swt1b 8,8,8 NULL # Using intersect(sta_swt1a,sta_swt2a,stb_swt1b); Using where +explain select * from t1 ignore index (sta_swt21a, sta_swt12a, stb_swt1a_2b, stb_swt1b) +where st_a=1 and swt1a=1 and swt2a=1 and st_b=1 and swt1b=1 and swt2b=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index_merge sta_swt1a,sta_swt2a,st_a,st_b sta_swt1a,sta_swt2a,st_b 8,8,4 NULL # Using intersect(sta_swt1a,sta_swt2a,st_b); Using where +explain select * from t1 +where st_a=1 and swt1a=1 and swt2a=1 and st_b=1 and swt1b=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index_merge sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a,stb_swt1a_2b,stb_swt1b,st_b sta_swt12a,stb_swt1a_2b 12,12 NULL # Using intersect(sta_swt12a,stb_swt1a_2b); Using where +explain select * from t1 +where st_a=1 and swt1a=1 and st_b=1 and swt1b=1 and swt1b=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index_merge sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a,stb_swt1a_2b,stb_swt1b,st_b sta_swt1a,stb_swt1b 8,8 NULL # Using intersect(sta_swt1a,stb_swt1b); Using where +explain select st_a from t1 +where st_a=1 and swt1a=1 and st_b=1 and swt1b=1 and swt1b=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index_merge sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a,stb_swt1a_2b,stb_swt1b,st_b sta_swt1a,stb_swt1b 8,8 NULL # Using intersect(sta_swt1a,stb_swt1b); Using where; Using index +explain select st_a from t1 +where st_a=1 and swt1a=1 and st_b=1 and swt1b=1 and swt1b=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index_merge sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a,stb_swt1a_2b,stb_swt1b,st_b sta_swt1a,stb_swt1b 8,8 NULL # Using intersect(sta_swt1a,stb_swt1b); Using where; Using index +drop table t0,t1; +create table t2 ( +a char(10), +b char(10), +filler1 char(255), +filler2 char(255), +key(a(5)), +key(b(5)) +); +select count(a) from t2 where a='BBBBBBBB'; +count(a) +4 +select count(a) from t2 where b='BBBBBBBB'; +count(a) +4 +expla_or_bin select count(a_or_b) from t2 where a_or_b='AAAAAAAA' a_or_bnd a_or_b='AAAAAAAA'; +id select_type ta_or_ba_or_ble type possia_or_ble_keys key key_len ref rows Extra_or_b +1 SIMPLE t2 ref a_or_b,a_or_b a_or_b 6 const 4 Using where +select count(a) from t2 where a='AAAAAAAA' and b='AAAAAAAA'; +count(a) +4 +select count(a) from t2 ignore index(a,b) where a='AAAAAAAA' and b='AAAAAAAA'; +count(a) +4 +insert into t2 values ('ab', 'ab', 'uh', 'oh'); +explain select a from t2 where a='ab'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ref a a 6 const # Using where +drop table t2; +CREATE TABLE t1(c1 INT, c2 INT DEFAULT 0, c3 CHAR(255) DEFAULT '', +KEY(c1), KEY(c2), KEY(c3)); +INSERT INTO t1(c1) VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0), +(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0); +INSERT INTO t1 VALUES(0,0,0); +CREATE TABLE t2(c1 int); +INSERT INTO t2 VALUES(1); +DELETE t1 FROM t1,t2 WHERE t1.c1=0 AND t1.c2=0; +SELECT * FROM t1; +c1 c2 c3 +DROP TABLE t1,t2; +#---------------- Index merge test 2 ------------------------------------------- +SET SESSION STORAGE_ENGINE = InnoDB; +drop table if exists t1,t2; +create table t1 +( +key1 int not null, +key2 int not null, +INDEX i1(key1), +INDEX i2(key2) +); +explain select * from t1 where key1 < 5 or key2 > 197; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index_merge i1,i2 i1,i2 4,4 NULL 8 Using sort_union(i1,i2); Using where +select * from t1 where key1 < 5 or key2 > 197; +key1 key2 +0 200 +1 199 +2 198 +3 197 +4 196 +explain select * from t1 where key1 < 3 or key2 > 195; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index_merge i1,i2 i1,i2 4,4 NULL 8 Using sort_union(i1,i2); Using where +select * from t1 where key1 < 3 or key2 > 195; +key1 key2 +0 200 +1 199 +2 198 +3 197 +4 196 +alter table t1 add str1 char (255) not null, +add zeroval int not null default 0, +add str2 char (255) not null, +add str3 char (255) not null; +update t1 set str1='aaa', str2='bbb', str3=concat(key2, '-', key1 div 2, '_' ,if(key1 mod 2 = 0, 'a', 'A')); +alter table t1 add primary key (str1, zeroval, str2, str3); +explain select * from t1 where key1 < 5 or key2 > 197; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index_merge i1,i2 i1,i2 4,4 NULL 8 Using sort_union(i1,i2); Using where +select * from t1 where key1 < 5 or key2 > 197; +key1 key2 str1 zeroval str2 str3 +4 196 aaa 0 bbb 196-2_a +3 197 aaa 0 bbb 197-1_A +2 198 aaa 0 bbb 198-1_a +1 199 aaa 0 bbb 199-0_A +0 200 aaa 0 bbb 200-0_a +explain select * from t1 where key1 < 3 or key2 > 195; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index_merge i1,i2 i1,i2 4,4 NULL 8 Using sort_union(i1,i2); Using where +select * from t1 where key1 < 3 or key2 > 195; +key1 key2 str1 zeroval str2 str3 +4 196 aaa 0 bbb 196-2_a +3 197 aaa 0 bbb 197-1_A +2 198 aaa 0 bbb 198-1_a +1 199 aaa 0 bbb 199-0_A +0 200 aaa 0 bbb 200-0_a +drop table t1; +create table t1 ( +pk integer not null auto_increment primary key, +key1 integer, +key2 integer not null, +filler char (200), +index (key1), +index (key2) +); +show warnings; +Level Code Message +explain select pk from t1 where key1 = 1 and key2 = 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index_merge key1,key2 key1,key2 5,4 NULL 1 Using intersect(key1,key2); Using where; Using index +select pk from t1 where key2 = 1 and key1 = 1; +pk +26 +27 +select pk from t1 ignore index(key1,key2) where key2 = 1 and key1 = 1; +pk +26 +27 +drop table t1; +create table t1 ( +pk int primary key auto_increment, +key1a int, +key2a int, +key1b int, +key2b int, +dummy1 int, +dummy2 int, +dummy3 int, +dummy4 int, +key3a int, +key3b int, +filler1 char (200), +index i1(key1a, key1b), +index i2(key2a, key2b), +index i3(key3a, key3b) +); +create table t2 (a int); +insert into t2 values (0),(1),(2),(3),(4),(NULL); +insert into t1 (key1a, key1b, key2a, key2b, key3a, key3b) +select A.a, B.a, C.a, D.a, C.a, D.a from t2 A,t2 B,t2 C, t2 D; +insert into t1 (key1a, key1b, key2a, key2b, key3a, key3b) +select key1a, key1b, key2a, key2b, key3a, key3b from t1; +insert into t1 (key1a, key1b, key2a, key2b, key3a, key3b) +select key1a, key1b, key2a, key2b, key3a, key3b from t1; +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +select count(*) from t1; +count(*) +5184 +explain select count(*) from t1 where +key1a = 2 and key1b is null and key2a = 2 and key2b is null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index_merge i1,i2 i1,i2 10,10 NULL # Using intersect(i1,i2); Using where; Using index +select count(*) from t1 where +key1a = 2 and key1b is null and key2a = 2 and key2b is null; +count(*) +4 +explain select count(*) from t1 where +key1a = 2 and key1b is null and key3a = 2 and key3b is null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index_merge i1,i3 i1,i3 10,10 NULL # Using intersect(i1,i3); Using where; Using index +select count(*) from t1 where +key1a = 2 and key1b is null and key3a = 2 and key3b is null; +count(*) +4 +drop table t1,t2; +create table t1 ( +id1 int, +id2 date , +index idx2 (id1,id2), +index idx1 (id2) +); +insert into t1 values(1,'20040101'), (2,'20040102'); +select * from t1 where id1 = 1 and id2= '20040101'; +id1 id2 +1 2004-01-01 +drop table t1; +drop view if exists v1; +CREATE TABLE t1 ( +`oid` int(11) unsigned NOT NULL auto_increment, +`fk_bbk_niederlassung` int(11) unsigned NOT NULL, +`fk_wochentag` int(11) unsigned NOT NULL, +`uhrzeit_von` time NOT NULL COMMENT 'HH:MM', +`uhrzeit_bis` time NOT NULL COMMENT 'HH:MM', +`geloescht` tinyint(4) NOT NULL, +`version` int(5) NOT NULL, +PRIMARY KEY (`oid`), +KEY `fk_bbk_niederlassung` (`fk_bbk_niederlassung`), +KEY `fk_wochentag` (`fk_wochentag`), +KEY `ix_version` (`version`) +) DEFAULT CHARSET=latin1; +insert into t1 values +(1, 38, 1, '08:00:00', '13:00:00', 0, 1), +(2, 38, 2, '08:00:00', '13:00:00', 0, 1), +(3, 38, 3, '08:00:00', '13:00:00', 0, 1), +(4, 38, 4, '08:00:00', '13:00:00', 0, 1), +(5, 38, 5, '08:00:00', '13:00:00', 0, 1), +(6, 38, 5, '08:00:00', '13:00:00', 1, 2), +(7, 38, 3, '08:00:00', '13:00:00', 1, 2), +(8, 38, 1, '08:00:00', '13:00:00', 1, 2), +(9, 38, 2, '08:00:00', '13:00:00', 1, 2), +(10, 38, 4, '08:00:00', '13:00:00', 1, 2), +(11, 38, 1, '08:00:00', '13:00:00', 0, 3), +(12, 38, 2, '08:00:00', '13:00:00', 0, 3), +(13, 38, 3, '08:00:00', '13:00:00', 0, 3), +(14, 38, 4, '08:00:00', '13:00:00', 0, 3), +(15, 38, 5, '08:00:00', '13:00:00', 0, 3), +(16, 38, 4, '08:00:00', '13:00:00', 0, 4), +(17, 38, 5, '08:00:00', '13:00:00', 0, 4), +(18, 38, 1, '08:00:00', '13:00:00', 0, 4), +(19, 38, 2, '08:00:00', '13:00:00', 0, 4), +(20, 38, 3, '08:00:00', '13:00:00', 0, 4), +(21, 7, 1, '08:00:00', '13:00:00', 0, 1), +(22, 7, 2, '08:00:00', '13:00:00', 0, 1), +(23, 7, 3, '08:00:00', '13:00:00', 0, 1), +(24, 7, 4, '08:00:00', '13:00:00', 0, 1), +(25, 7, 5, '08:00:00', '13:00:00', 0, 1); +create view v1 as +select +zeit1.oid AS oid, +zeit1.fk_bbk_niederlassung AS fk_bbk_niederlassung, +zeit1.fk_wochentag AS fk_wochentag, +zeit1.uhrzeit_von AS uhrzeit_von, +zeit1.uhrzeit_bis AS uhrzeit_bis, +zeit1.geloescht AS geloescht, +zeit1.version AS version +from +t1 zeit1 +where +(zeit1.version = +(select max(zeit2.version) AS `max(version)` + from t1 zeit2 +where +((zeit1.fk_bbk_niederlassung = zeit2.fk_bbk_niederlassung) and +(zeit1.fk_wochentag = zeit2.fk_wochentag) and +(zeit1.uhrzeit_von = zeit2.uhrzeit_von) and +(zeit1.uhrzeit_bis = zeit2.uhrzeit_bis) +) +) +) +and (zeit1.geloescht = 0); +select * from v1 where oid = 21; +oid fk_bbk_niederlassung fk_wochentag uhrzeit_von uhrzeit_bis geloescht version +21 7 1 08:00:00 13:00:00 0 1 +drop view v1; +drop table t1; +CREATE TABLE t1( +t_cpac varchar(2) NOT NULL, +t_vers varchar(4) NOT NULL, +t_rele varchar(2) NOT NULL, +t_cust varchar(4) NOT NULL, +filler1 char(250) default NULL, +filler2 char(250) default NULL, +PRIMARY KEY (t_cpac,t_vers,t_rele,t_cust), +UNIQUE KEY IX_4 (t_cust,t_cpac,t_vers,t_rele), +KEY IX_5 (t_vers,t_rele,t_cust) +); +insert into t1 values +('tm','2.5 ','a ',' ','',''), ('tm','2.5U','a ','stnd','',''), +('da','3.3 ','b ',' ','',''), ('da','3.3U','b ','stnd','',''), +('tl','7.6 ','a ',' ','',''), ('tt','7.6 ','a ',' ','',''), +('bc','B61 ','a ',' ','',''), ('bp','B61 ','a ',' ','',''), +('ca','B61 ','a ',' ','',''), ('ci','B61 ','a ',' ','',''), +('cp','B61 ','a ',' ','',''), ('dm','B61 ','a ',' ','',''), +('ec','B61 ','a ',' ','',''), ('ed','B61 ','a ',' ','',''), +('fm','B61 ','a ',' ','',''), ('nt','B61 ','a ',' ','',''), +('qm','B61 ','a ',' ','',''), ('tc','B61 ','a ',' ','',''), +('td','B61 ','a ',' ','',''), ('tf','B61 ','a ',' ','',''), +('tg','B61 ','a ',' ','',''), ('ti','B61 ','a ',' ','',''), +('tp','B61 ','a ',' ','',''), ('ts','B61 ','a ',' ','',''), +('wh','B61 ','a ',' ','',''), ('bc','B61U','a ','stnd','',''), +('bp','B61U','a ','stnd','',''), ('ca','B61U','a ','stnd','',''), +('ci','B61U','a ','stnd','',''), ('cp','B61U','a ','stnd','',''), +('dm','B61U','a ','stnd','',''), ('ec','B61U','a ','stnd','',''), +('fm','B61U','a ','stnd','',''), ('nt','B61U','a ','stnd','',''), +('qm','B61U','a ','stnd','',''), ('tc','B61U','a ','stnd','',''), +('td','B61U','a ','stnd','',''), ('tf','B61U','a ','stnd','',''), +('tg','B61U','a ','stnd','',''), ('ti','B61U','a ','stnd','',''), +('tp','B61U','a ','stnd','',''), ('ts','B61U','a ','stnd','',''), +('wh','B61U','a ','stnd','',''); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `t_cpac` varchar(2) NOT NULL, + `t_vers` varchar(4) NOT NULL, + `t_rele` varchar(2) NOT NULL, + `t_cust` varchar(4) NOT NULL, + `filler1` char(250) DEFAULT NULL, + `filler2` char(250) DEFAULT NULL, + PRIMARY KEY (`t_cpac`,`t_vers`,`t_rele`,`t_cust`), + UNIQUE KEY `IX_4` (`t_cust`,`t_cpac`,`t_vers`,`t_rele`), + KEY `IX_5` (`t_vers`,`t_rele`,`t_cust`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +select t_vers,t_rele,t_cust,filler1 from t1 where t_vers = '7.6'; +t_vers t_rele t_cust filler1 +7.6 a +7.6 a +select t_vers,t_rele,t_cust,filler1 from t1 where t_vers = '7.6' + and t_rele='a' and t_cust = ' '; +t_vers t_rele t_cust filler1 +7.6 a +7.6 a +drop table t1; +create table t1 ( +pk int(11) not null auto_increment, +a int(11) not null default '0', +b int(11) not null default '0', +c int(11) not null default '0', +filler1 datetime, filler2 varchar(15), +filler3 longtext, +kp1 varchar(4), kp2 varchar(7), +kp3 varchar(2), kp4 varchar(4), +kp5 varchar(7), +filler4 char(1), +primary key (pk), +key idx1(a,b,c), +key idx2(c), +key idx3(kp1,kp2,kp3,kp4,kp5) +) default charset=latin1; +set @fill=NULL; +SELECT COUNT(*) FROM t1 WHERE b = 0 AND a = 0 AND c = 13286427 AND +kp1='279' AND kp2='ELM0678' AND kp3='6' AND kp4='10' AND kp5 = 'R '; +COUNT(*) +1 +drop table t1; +# +# Bug#56423: Different count with SELECT and CREATE SELECT queries +# +CREATE TABLE t1 ( +a INT, +b INT, +c INT, +d INT, +PRIMARY KEY (a), +KEY (c), +KEY bd (b,d) +); +INSERT INTO t1 VALUES +(1, 0, 1, 0), +(2, 1, 1, 1), +(3, 1, 1, 1), +(4, 0, 1, 1); +EXPLAIN +SELECT a +FROM t1 +WHERE c = 1 AND b = 1 AND d = 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref c,bd bd 10 const,const 2 Using where +CREATE TABLE t2 ( a INT ) +SELECT a +FROM t1 +WHERE c = 1 AND b = 1 AND d = 1; +SELECT * FROM t2; +a +2 +3 +DROP TABLE t1, t2; +CREATE TABLE t1( a INT, b INT, KEY(a), KEY(b) ); +INSERT INTO t1 VALUES (1, 2), (1, 2), (1, 2), (1, 2); +SELECT * FROM t1 FORCE INDEX(a, b) WHERE a = 1 AND b = 2; +a b +1 2 +1 2 +1 2 +1 2 +DROP TABLE t1; +# Code coverage of fix. +CREATE TABLE t1 ( a INT NOT NULL AUTO_INCREMENT PRIMARY KEY, b INT); +INSERT INTO t1 (b) VALUES (1); +UPDATE t1 SET b = 2 WHERE a = 1; +SELECT * FROM t1; +a b +1 2 +CREATE TABLE t2 ( a INT NOT NULL AUTO_INCREMENT PRIMARY KEY, b VARCHAR(1) ); +INSERT INTO t2 (b) VALUES ('a'); +UPDATE t2 SET b = 'b' WHERE a = 1; +SELECT * FROM t2; +a b +1 b +DROP TABLE t1, t2; #---------------- 2-sweeps read Index merge test 2 ------------------------------- SET SESSION STORAGE_ENGINE = InnoDB; drop table if exists t1; diff --git a/mysql-test/t/index_merge_innodb.test b/mysql-test/t/index_merge_innodb.test index 10d772797a2..a188648d41f 100644 --- a/mysql-test/t/index_merge_innodb.test +++ b/mysql-test/t/index_merge_innodb.test @@ -22,9 +22,9 @@ let $index_merge_random_rows_in_EXPLAIN = 1; let $merge_table_support= 0; # -- [DISABLED Bug#45727] -# --source include/index_merge1.inc -# --source include/index_merge_ror.inc -# --source include/index_merge2.inc + --source include/index_merge1.inc + --source include/index_merge_ror.inc + --source include/index_merge2.inc --source include/index_merge_2sweeps.inc --source include/index_merge_ror_cpk.inc From 9ab8418fc0b4f33ca721b10174bdd0cc8fc80c71 Mon Sep 17 00:00:00 2001 From: Sneha MOdi Date: Wed, 2 Nov 2011 18:42:52 +0530 Subject: [PATCH 061/288] BUG#11754170: TEST CASE FOR BUG#28211 IS DISABLED IN QUERY_CACHE.TEST as RENAME DATABASE and query_cache don't play along nicely. An alternative for RENAME DATABSE using RENAME TABLE has been used to implement this. --- mysql-test/r/query_cache.result | 58 +++++++++++++++++++++-- mysql-test/t/query_cache.test | 83 +++++++++++++++++---------------- 2 files changed, 97 insertions(+), 44 deletions(-) diff --git a/mysql-test/r/query_cache.result b/mysql-test/r/query_cache.result index f209e401764..9e7f427502b 100644 --- a/mysql-test/r/query_cache.result +++ b/mysql-test/r/query_cache.result @@ -1583,6 +1583,58 @@ show status like 'Qcache_free_blocks'; Variable_name Value Qcache_free_blocks 0 Restore default values. +drop database if exists db1; +drop database if exists db2; +set GLOBAL query_cache_size=15*1024*1024; +create database db1; +use db1; +create table t1(c1 int)engine=myisam; +insert into t1(c1) values (1); +select * from db1.t1 f; +c1 +1 +show status like 'Qcache_queries_in_cache'; +Variable_name Value +Qcache_queries_in_cache 1 +create database db2; +rename table db1.t1 to db2.t2; +drop database db1; +show status like 'Qcache_queries_in_cache'; +Variable_name Value +Qcache_queries_in_cache 0 +drop database db2; +set global query_cache_size=default; +drop database if exists db1; +drop database if exists db3; +set GLOBAL query_cache_size=15*1024*1024; +create database db1; +create database db3; +use db1; +create table t1(c1 int) engine=myisam; +use db3; +create table t1(c1 int) engine=myisam; +use db1; +insert into t1(c1) values (1); +use mysql; +select * from db1.t1; +c1 +1 +select c1+1 from db1.t1; +c1+1 +2 +select * from db3.t1; +c1 +show status like 'Qcache_queries_in_cache'; +Variable_name Value +Qcache_queries_in_cache 3 +create database db2; +rename table db1.t1 to db2.t2; +drop database db1; +show status like 'Qcache_queries_in_cache'; +Variable_name Value +Qcache_queries_in_cache 1 +drop database db2; +drop database db3; set GLOBAL query_cache_type=default; set GLOBAL query_cache_limit=default; set GLOBAL query_cache_min_res_unit=default; @@ -1609,7 +1661,7 @@ c1 2 SHOW STATUS LIKE 'Qcache_hits'; Variable_name Value -Qcache_hits 1 +Qcache_hits 0 DROP TABLE t1; SET GLOBAL concurrent_insert= @save_concurrent_insert; SET GLOBAL query_cache_size= default; @@ -1639,7 +1691,7 @@ a COMMIT; SHOW STATUS LIKE 'Qcache_queries_in_cache'; Variable_name Value -Qcache_queries_in_cache 2 +Qcache_queries_in_cache 0 SHOW STATUS LIKE "Qcache_hits"; Variable_name Value Qcache_hits 0 @@ -1661,7 +1713,7 @@ a COMMIT; SHOW STATUS LIKE "Qcache_hits"; Variable_name Value -Qcache_hits 2 +Qcache_hits 0 DROP TABLE t1; SET GLOBAL query_cache_size= default; End of 5.0 tests diff --git a/mysql-test/t/query_cache.test b/mysql-test/t/query_cache.test index 51e362d4916..caf57f343eb 100644 --- a/mysql-test/t/query_cache.test +++ b/mysql-test/t/query_cache.test @@ -1193,47 +1193,48 @@ set global query_cache_type=0; show status like 'Qcache_free_blocks'; --echo Restore default values. -# Bug#28211 RENAME DATABASE and query cache don't play nicely together -# -# TODO: enable these tests when RENAME DATABASE is implemented. -# --disable_warnings -# drop database if exists db1; -# drop database if exists db2; -# --enable_warnings -# set GLOBAL query_cache_size=15*1024*1024; -# create database db1; -# use db1; -# create table t1(c1 int)engine=myisam; -# insert into t1(c1) values (1); -# select * from db1.t1 f; -# show status like 'Qcache_queries_in_cache'; -# rename schema db1 to db2; -# show status like 'Qcache_queries_in_cache'; -# drop database db2; -# set global query_cache_size=default; -# -# --disable_warnings -# drop database if exists db1; -# drop database if exists db3; -# --enable_warnings -# set GLOBAL query_cache_size=15*1024*1024; -# create database db1; -# create database db3; -# use db1; -# create table t1(c1 int) engine=myisam; -# use db3; -# create table t1(c1 int) engine=myisam; -# use db1; -# insert into t1(c1) values (1); -# use mysql; -# select * from db1.t1; -# select c1+1 from db1.t1; -# select * from db3.t1; -# show status like 'Qcache_queries_in_cache'; -# rename schema db1 to db2; -# show status like 'Qcache_queries_in_cache'; -# drop database db2; -# drop database db3; + --disable_warnings + drop database if exists db1; + drop database if exists db2; + --enable_warnings + set GLOBAL query_cache_size=15*1024*1024; + create database db1; + use db1; + create table t1(c1 int)engine=myisam; + insert into t1(c1) values (1); + select * from db1.t1 f; + show status like 'Qcache_queries_in_cache'; + create database db2; + rename table db1.t1 to db2.t2; + drop database db1; + show status like 'Qcache_queries_in_cache'; + drop database db2; + set global query_cache_size=default; + + --disable_warnings + drop database if exists db1; + drop database if exists db3; + --enable_warnings + set GLOBAL query_cache_size=15*1024*1024; + create database db1; + create database db3; + use db1; + create table t1(c1 int) engine=myisam; + use db3; + create table t1(c1 int) engine=myisam; + use db1; + insert into t1(c1) values (1); + use mysql; + select * from db1.t1; + select c1+1 from db1.t1; + select * from db3.t1; + show status like 'Qcache_queries_in_cache'; + create database db2; + rename table db1.t1 to db2.t2; + drop database db1; + show status like 'Qcache_queries_in_cache'; + drop database db2; + drop database db3; set GLOBAL query_cache_type=default; set GLOBAL query_cache_limit=default; From d1ba9b328fbc90a5201c39ea597a236a93462d4e Mon Sep 17 00:00:00 2001 From: Alfranio Correia Date: Wed, 2 Nov 2011 15:28:18 +0000 Subject: [PATCH 062/288] BUG#13337202 - REPLICATION PERFORMANCE DROP DUE TO "THE BINLOG MAY BE CORRUPTED" FLOOD In patch mysql-5.5:revno:3097.92.133, we made the gcc 4.6.1 compiler to stop complaining about the fact that binlog_can_be_corrupted was defined but not used. The fix consisted in checking the variable and printing a warning message. However, the fix caused a regression as a message was being printed out when there was no corrupted binary log causing performance problems and triggering users' suspicions when there was no need. In BUG#13337202, we do not print any message and use the variable in an "if" with an empty body to keep the compiler happy. --- sql/sql_repl.cc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 80fef42434c..5d6d8bb13e3 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -731,7 +731,15 @@ impossible position"; /Alfranio */ if (binlog_can_be_corrupted) - sql_print_information("The binlog may be corrupted."); + { + /* + Don't try to print out warning messages because this generates + erroneous messages in the error log and causes performance + problems. + + /Alfranio + */ + } pos = my_b_tell(&log); if (RUN_HOOK(binlog_transmit, before_send_event, From 2fb9894131abf3fc6f78847230f1b9642e765212 Mon Sep 17 00:00:00 2001 From: Sneha Modi Date: Thu, 3 Nov 2011 12:30:09 +0530 Subject: [PATCH 063/288] BUG#11754168: Reverting back changes as it is making other tests fail. --- mysql-test/collections/default.experimental | 1 - mysql-test/include/index_merge1.inc | 123 +- mysql-test/include/index_merge2.inc | 44 +- mysql-test/include/index_merge_ror.inc | 52 - mysql-test/r/index_merge_innodb.result | 1156 ------------------- mysql-test/t/index_merge_innodb.test | 6 +- 6 files changed, 29 insertions(+), 1353 deletions(-) diff --git a/mysql-test/collections/default.experimental b/mysql-test/collections/default.experimental index 0241397d996..b3623402065 100644 --- a/mysql-test/collections/default.experimental +++ b/mysql-test/collections/default.experimental @@ -6,7 +6,6 @@ binlog.binlog_multi_engine # joro : NDB tests marked as experiment funcs_1.charset_collation_1 # depends on compile-time decisions main.func_math @freebsd # Bug#11751977 2010-05-04 alik main.func_math fails on FreeBSD in PB2 -main.index_merge_innodb #Bug 11754168 - 45727: Disabled parts of index_merge_innodb due to explain diffs have been enabled main.lock_multi_bug38499 # Bug#11755645 2009-09-19 alik main.lock_multi_bug38499 times out sporadically main.outfile_loaddata @solaris # Bug#11755168 2010-01-20 alik Test "outfile_loaddata" fails (reproducible) main.signal_demo3 @solaris # Bug#11753919 2010-01-20 alik Several test cases fail on Solaris with error Thread stack overrun diff --git a/mysql-test/include/index_merge1.inc b/mysql-test/include/index_merge1.inc index 52ea2f33193..ef116c5addc 100644 --- a/mysql-test/include/index_merge1.inc +++ b/mysql-test/include/index_merge1.inc @@ -11,7 +11,6 @@ # Note: The comments/expectations refer to MyISAM. # They might be not valid for other storage engines. # - # Last update: # 2006-08-02 ML test refactored # old name was t/index_merge.test @@ -58,129 +57,82 @@ update t0 set key2=key1,key3=key1,key4=key1,key5=key1,key6=key1,key7=key1,key8=1 analyze table t0; # 1. One index ---sorted_result ---replace_column 9 # explain select * from t0 where key1 < 3 or key1 > 1020; # 2. Simple cases ---sorted_result ---replace_column 9 # explain select * from t0 where key1 < 3 or key2 > 1020; select * from t0 where key1 < 3 or key2 > 1020; ---sorted_result ---replace_column 9 # explain select * from t0 where key1 < 3 or key2 <4; ---sorted_result ---replace_column 9 # explain -select * from t0 where (key1 > 30 and key1<35) or (key2 >32 and key2 < 40) ; +select * from t0 where (key1 > 30 and key1<35) or (key2 >32 and key2 < 40); # Bug#21277: InnoDB, wrong result set, index_merge strategy, second index not evaluated select * from t0 where (key1 > 30 and key1<35) or (key2 >32 and key2 < 40); # 3. Check that index_merge doesn't break "ignore/force/use index" ---sorted_result ---replace_column 9 # explain select * from t0 ignore index (i2) where key1 < 3 or key2 <4; ---sorted_result ---replace_column 9 # explain select * from t0 where (key1 < 3 or key2 <4) and key3 = 50; ---sorted_result ---replace_column 9 # explain select * from t0 use index (i1,i2) where (key1 < 3 or key2 <4) and key3 = 50; ---sorted_result ---replace_column 9 # explain select * from t0 where (key1 > 1 or key2 > 2); ---sorted_result ---replace_column 9 # explain select * from t0 force index (i1,i2) where (key1 > 1 or key2 > 2); # 4. Check if conjuncts are grouped by keyuse ---sorted_result ---replace_column 9 # explain select * from t0 where key1<3 or key2<3 or (key1>5 and key1<8) or (key1>10 and key1<12) or (key2>100 and key2<110); # 5. Check index_merge with conjuncts that are always true/false # verify fallback to "range" if there is only one non-confluent condition ---sorted_result ---replace_column 9 # explain select * from t0 where key2 = 45 or key1 <=> null; ---sorted_result ---replace_column 9 # explain select * from t0 where key2 = 45 or key1 is not null; ---sorted_result ---replace_column 9 # explain select * from t0 where key2 = 45 or key1 is null; # the last conj. is always false and will be discarded ---sorted_result ---replace_column 9 # explain select * from t0 where key2=10 or key3=3 or key4 <=> null; # the last conj. is always true and will cause 'all' scan ---sorted_result ---replace_column 9 # explain select * from t0 where key2=10 or key3=3 or key4 is null; # some more complicated cases ---sorted_result ---replace_column 9 # explain select key1 from t0 where (key1 <=> null) or (key2 < 5) or (key3=10) or (key4 <=> null); ---sorted_result ---replace_column 9 # explain select key1 from t0 where (key1 <=> null) or (key1 < 5) or (key3=10) or (key4 <=> null); # 6.Several ways to do index_merge, (ignored) index_merge vs. range ---sorted_result ---replace_column 9 # explain select * from t0 where (key1 < 3 or key2 < 3) and (key3 < 4 or key4 < 4) and (key5 < 5 or key6 < 5); ---sorted_result ---replace_column 9 # explain select * from t0 where (key1 < 3 or key2 < 6) and (key1 < 7 or key3 < 4); select * from t0 where (key1 < 3 or key2 < 6) and (key1 < 7 or key3 < 4); ---sorted_result ---replace_column 9 # + explain select * from t0 where (key1 < 3 or key2 < 3) and (key3 < 4 or key4 < 4) and (key5 < 2 or key6 < 2); # now index_merge is not used at all when "range" is possible ---sorted_result ---replace_column 9 # explain select * from t0 where (key1 < 3 or key2 < 3) and (key3 < 100); # this even can cause "all" scan: ---sorted_result ---replace_column 9 # explain select * from t0 where (key1 < 3 or key2 < 3) and (key3 < 1000); # 7. Complex cases # tree_or(List, range SEL_TREE). ---sorted_result ---replace_column 9 # explain select * from t0 where ((key1 < 4 or key2 < 4) and (key2 <5 or key3 < 4)) or key2 > 5; ---sorted_result ---replace_column 9 # explain select * from t0 where ((key1 < 4 or key2 < 4) and (key2 <5 or key3 < 4)) or @@ -192,43 +144,31 @@ select * from t0 where key1 < 7; # tree_or(List, List). ---sorted_result ---replace_column 9 # explain select * from t0 where ((key1 < 4 or key2 < 4) and (key3 <5 or key5 < 4)) or ((key5 < 5 or key6 < 6) and (key7 <7 or key8 < 4)); ---sorted_result ---replace_column 9 # explain select * from t0 where ((key3 <5 or key5 < 4) and (key1 < 4 or key2 < 4)) or ((key7 <7 or key8 < 4) and (key5 < 5 or key6 < 6)); ---sorted_result ---replace_column 9 # explain select * from t0 where ((key3 <5 or key5 < 4) and (key1 < 4 or key2 < 4)) or ((key3 <7 or key5 < 2) and (key5 < 5 or key6 < 6)); ---sorted_result ---replace_column 9 # explain select * from t0 where ((key3 <5 or key5 < 4) and (key1 < 4 or key2 < 4)) or (((key3 <7 and key7 < 6) or key5 < 2) and (key5 < 5 or key6 < 6)); ---sorted_result ---replace_column 9 # explain select * from t0 where ((key3 <5 or key5 < 4) and (key1 < 4 or key2 < 4)) or ((key3 >=5 or key5 < 2) and (key5 < 5 or key6 < 6)); ---sorted_result ---replace_column 9 # explain select * from t0 force index(i1, i2, i3, i4, i5, i6 ) where ((key3 <5 or key5 < 4) and (key1 < 4 or key2 < 4)) or @@ -237,8 +177,6 @@ explain select * from t0 force index(i1, i2, i3, i4, i5, i6 ) where # 8. Verify that "order by" after index merge uses filesort select * from t0 where key1 < 5 or key8 < 4 order by key1; ---sorted_result ---replace_column 9 # explain select * from t0 where key1 < 5 or key8 < 4 order by key1; @@ -253,18 +191,12 @@ alter table t2 drop index i2; alter table t2 add index i321(key3, key2, key1); # index_merge vs 'index', index_merge is better. ---sorted_result ---replace_column 9 # explain select key3 from t2 where key1 = 100 or key2 = 100; # index_merge vs 'index', 'index' is better. ---sorted_result ---replace_column 9 # explain select key3 from t2 where key1 <100 or key2 < 100; # index_merge vs 'all', index_merge is better. ---sorted_result ---replace_column 9 # explain select key7 from t2 where key1 <100 or key2 < 100; # 10. Multipart keys. @@ -285,21 +217,13 @@ insert into t4 select key1,key1,key1 div 10, key1 % 10, key1 % 10, key1 from t0; # the following will be handled by index_merge: select * from t4 where key1a = 3 or key1b = 4; ---sorted_result ---replace_column 9 # explain select * from t4 where key1a = 3 or key1b = 4; # and the following will not ---sorted_result ---replace_column 9 # explain select * from t4 where key2 = 1 and (key2_1 = 1 or key3 = 5); ---sorted_result ---replace_column 9 # explain select * from t4 where key2 = 1 and (key2_1 = 1 or key2_2 = 5); ---sorted_result ---replace_column 9 # explain select * from t4 where key2_1 = 1 or key2_2 = 5; @@ -308,54 +232,38 @@ create table t1 like t0; insert into t1 select * from t0; # index_merge on first table in join ---sorted_result ---replace_column 9 # explain select * from t0 left join t1 on (t0.key1=t1.key1) where t0.key1=3 or t0.key2=4; select * from t0 left join t1 on (t0.key1=t1.key1) where t0.key1=3 or t0.key2=4; ---sorted_result ---replace_column 9 # explain select * from t0,t1 where (t0.key1=t1.key1) and ( t0.key1=3 or t0.key2=4); # index_merge vs. ref ---sorted_result ---replace_column 8 test.t0.key1 4 # 6 # 9 # 7 # 10 # explain select * from t0,t1 where (t0.key1=t1.key1) and (t0.key1=3 or t0.key2=4) and t1.key1<200; # index_merge vs. ref ---sorted_result ---replace_column 8 test.t0.key1 9 # explain select * from t0,t1 where (t0.key1=t1.key1) and (t0.key1=3 or t0.key2<4) and t1.key1=2; # index_merge on second table in join ---sorted_result ---replace_column 8 test.t0.key1 9 # explain select * from t0,t1 where t0.key1 = 5 and (t1.key1 = t0.key1 or t1.key8 = t0.key1); # Fix for bug#1974 ---sorted_result ---replace_column 8 test.t0.key1 9 # explain select * from t0,t1 where t0.key1 < 3 and (t1.key1 = t0.key1 or t1.key8 = t0.key1); # index_merge inside union ---sorted_result ---replace_column 9 # explain select * from t1 where key1=3 or key2=4 union select * from t1 where key1<4 or key3=5; # index merge in subselect ---sorted_result ---replace_column 9 # explain select * from (select * from t1 where key1 = 3 or key2 =3) as Z where key8 >5; # 12. check for long index_merges. @@ -367,8 +275,6 @@ alter table t3 add keyB int not null, add index iB(keyB); alter table t3 add keyC int not null, add index iC(keyC); update t3 set key9=key1,keyA=key1,keyB=key1,keyC=key1; ---sorted_result ---replace_column 9 # explain select * from t3 where key1=1 or key2=2 or key3=3 or key4=4 or key5=5 or key6=6 or key7=7 or key8=8 or @@ -380,8 +286,6 @@ select * from t3 where key9=9 or keyA=10 or keyB=11 or keyC=12; # Test for Bug#3183 ---sorted_result ---replace_column 9 # 4 # 6 # 7 # 10 # explain select * from t0 where key1 < 3 or key2 < 4; # Bug#21277: InnoDB, wrong result set, index_merge strategy, second index not evaluated select * from t0 where key1 < 3 or key2 < 4; @@ -400,8 +304,6 @@ create table t4 (a int); insert into t4 values (1),(4),(3); set @save_join_buffer_size=@@join_buffer_size; set join_buffer_size= 4096; ---sorted_result ---replace_column 9 # explain select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) from t0 as A force index(i1,i2), t0 as B force index (i1,i2) where (A.key1 < 500000 or A.key2 < 3) @@ -413,8 +315,6 @@ select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 and (B.key1 < 500000 or B.key2 < 3); update t0 set key1=1; ---sorted_result ---replace_column 9 # explain select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) from t0 as A force index(i1,i2), t0 as B force index (i1,i2) where (A.key1 = 1 or A.key2 = 1) @@ -431,11 +331,8 @@ update t0 set key2=1, key3=1, key4=1, key5=1,key6=1,key7=1 where key7 < 500; # The next query will not use index i7 in intersection if the OS doesn't # support file sizes > 2GB. (ha_myisam::ref_length depends on this and index # scan cost estimates depend on ha_myisam::ref_length) ---sorted_result --replace_column 9 # --replace_result "4,4,4,4,4,4,4" X "4,4,4,4,4,4" X "i6,i7" "i6,i7?" "i6" "i6,i7?" ---sorted_result ---replace_column 9 # 4 # 6 # 7 # 10 # explain select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) from t0 as A, t0 as B where (A.key1 = 1 and A.key2 = 1 and A.key3 = 1 and A.key4=1 and A.key5=1 and A.key6=1 and A.key7 = 1 or A.key8=1) @@ -477,9 +374,7 @@ while ($1) OPTIMIZE TABLE t1; select count(*) from t1; ---replace_column 9 # explain select * from t1 WHERE cola = 'foo' AND colb = 'bar'; ---replace_column 9 # explain select * from t1 force index(cola,colb) WHERE cola = 'foo' AND colb = 'bar'; drop table t1; @@ -504,11 +399,9 @@ create table t3 ( key(a),key(b) ) engine=merge union=(t1,t2); ---sorted_result ---replace_column 9 # +--replace_column 9 # explain select * from t1 where a=1 and b=1; ---sorted_result ---replace_column 9 # +--replace_column 9 # explain select * from t3 where a=1 and b=1; drop table t3; @@ -579,7 +472,6 @@ create table t2( insert into t2 select * from t1; --echo must use sort-union rather than union: ---sorted_result --replace_column 9 # explain select * from t1 where a=4 or b=4; --sorted_result @@ -588,7 +480,6 @@ select * from t1 where a=4 or b=4; select * from t1 ignore index(a,b) where a=4 or b=4; --echo must use union, not sort-union: ---sorted_result --replace_column 9 # explain select * from t2 where a=4 or b=4; --sorted_result @@ -626,8 +517,6 @@ insert into t3 select 1000, 1000,'filler' from t0 A, t0 B, t0 C; insert into t3 values (1,1,'data'); insert into t3 values (1,1,'data'); -- echo The plan should be ALL/ALL/ALL(Range checked for each record (index map: 0x3) ---sorted_result ---replace_column 9 # explain select * from t1 where exists (select 1 from t2, t3 where t2.a=t1.a and (t3.a=t2.b or t3.b=t2.b or t3.b=t2.b+1)); @@ -651,9 +540,7 @@ INSERT INTO t1 SELECT * FROM t1; INSERT INTO t1 SELECT * FROM t1; INSERT INTO t1 SELECT * FROM t1; SET SESSION sort_buffer_size=1; ---sorted_result ---replace_column 9 # -explain +EXPLAIN SELECT * FROM t1 FORCE INDEX(a,b) WHERE a LIKE 'a%' OR b LIKE 'b%' ORDER BY a,b; # we don't actually care about the result : we're checking if it crashes diff --git a/mysql-test/include/index_merge2.inc b/mysql-test/include/index_merge2.inc index f9777b61a7f..23c8c6466c7 100644 --- a/mysql-test/include/index_merge2.inc +++ b/mysql-test/include/index_merge2.inc @@ -124,7 +124,6 @@ select count(*) from t1; if ($index_merge_random_rows_in_EXPLAIN) { - --sorted_result --replace_column 9 # } explain select count(*) from t1 where @@ -135,7 +134,6 @@ select count(*) from t1 where if ($index_merge_random_rows_in_EXPLAIN) { - --sorted_result --replace_column 9 # } explain select count(*) from t1 where @@ -326,32 +324,32 @@ SELECT COUNT(*) FROM t1 WHERE b = 0 AND a = 0 AND c = 13286427 AND drop table t1; # BUG#21277: Index Merge/sort_union: wrong query results -#create table t1 -#( -# key1 int not null, -# key2 int not null default 0, -# key3 int not null default 0 -#); +create table t1 +( + key1 int not null, + key2 int not null default 0, + key3 int not null default 0 +); -#insert into t1(key1) values (1),(2),(3),(4),(5),(6),(7),(8); +insert into t1(key1) values (1),(2),(3),(4),(5),(6),(7),(8); -#let $1=7; -#set @d=8; -#while ($1) -#{ -# eval insert into t1 (key1) select key1+@d from t1; -# eval set @d=@d*2; -# dec $1; -#} +let $1=7; +set @d=8; +while ($1) +{ + eval insert into t1 (key1) select key1+@d from t1; + eval set @d=@d*2; + dec $1; +} -#alter table t1 add index i2(key2); -#alter table t1 add index i3(key3); -#update t1 set key2=key1,key3=key1; +alter table t1 add index i2(key2); +alter table t1 add index i3(key3); +update t1 set key2=key1,key3=key1; # to test the bug, the following must use "sort_union": -#explain select * from t1 where (key3 > 30 and key3<35) or (key2 >32 and key2 < 40); -#select * from t1 where (key3 > 30 and key3<35) or (key2 >32 and key2 < 40); -#drop table t1; +explain select * from t1 where (key3 > 30 and key3<35) or (key2 >32 and key2 < 40); +select * from t1 where (key3 > 30 and key3<35) or (key2 >32 and key2 < 40); +drop table t1; --echo # --echo # Bug#56423: Different count with SELECT and CREATE SELECT queries diff --git a/mysql-test/include/index_merge_ror.inc b/mysql-test/include/index_merge_ror.inc index 798afbcf1fe..2764cbea468 100644 --- a/mysql-test/include/index_merge_ror.inc +++ b/mysql-test/include/index_merge_ror.inc @@ -118,12 +118,8 @@ alter table t1 enable keys; select count(*) from t1; # One row results tests for cases where a single row matches all conditions ---sorted_result ---replace_column 9 # explain select key1,key2 from t1 where key1=100 and key2=100; select key1,key2 from t1 where key1=100 and key2=100; ---sorted_result ---replace_column 9 # explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; @@ -132,35 +128,25 @@ insert into t1 (key1, key2, key3, key4, filler1) values (100, 100, -1, -1, 'key1 insert into t1 (key1, key2, key3, key4, filler1) values (-1, -1, 100, 100, 'key4-key3'); # ROR-intersection, not covering ---sorted_result ---replace_column 9 # explain select key1,key2,filler1 from t1 where key1=100 and key2=100; select key1,key2,filler1 from t1 where key1=100 and key2=100; # ROR-intersection, covering ---sorted_result ---replace_column 9 # explain select key1,key2 from t1 where key1=100 and key2=100; select key1,key2 from t1 where key1=100 and key2=100; # ROR-union of ROR-intersections ---sorted_result ---replace_column 9 # explain select key1,key2,key3,key4 from t1 where key1=100 and key2=100 or key3=100 and key4=100; select key1,key2,key3,key4 from t1 where key1=100 and key2=100 or key3=100 and key4=100; explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; # 3-way ROR-intersection ---sorted_result ---replace_column 9 # explain select key1,key2,key3 from t1 where key1=100 and key2=100 and key3=100; select key1,key2,key3 from t1 where key1=100 and key2=100 and key3=100; # ROR-union(ROR-intersection, ROR-range) insert into t1 (key1,key2,key3,key4,filler1) values (101,101,101,101, 'key1234-101'); ---sorted_result ---replace_column 9 # explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=101; select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=101; @@ -173,22 +159,16 @@ select key1,key2,filler1 from t1 where key2=100 and key2=200; # ROR-union(ROR-intersection) with one of ROR-intersection giving empty # results ---sorted_result ---replace_column 9 # explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; delete from t1 where key3=100 and key4=100; # ROR-union with all ROR-intersections giving empty results ---sorted_result ---replace_column 9 # explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; # ROR-intersection with empty result ---sorted_result ---replace_column 9 # explain select key1,key2 from t1 where key1=100 and key2=100; select key1,key2 from t1 where key1=100 and key2=100; @@ -198,22 +178,16 @@ insert into t1 (key1, key2, key3, key4, filler1) values (100, 100, 200, 200,'key insert into t1 (key1, key2, key3, key4, filler1) values (100, 100, 200, 200,'key1-key2-key3-key4-2'); insert into t1 (key1, key2, key3, key4, filler1) values (100, 100, 200, 200,'key1-key2-key3-key4-3'); ---sorted_result ---replace_column 9 # explain select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200; select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200; insert into t1 (key1, key2, key3, key4, filler1) values (-1, -1, -1, 200,'key4'); ---sorted_result ---replace_column 9 # explain select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200; select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200; insert into t1 (key1, key2, key3, key4, filler1) values (-1, -1, 200, -1,'key3'); ---sorted_result ---replace_column 9 # explain select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200; select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200; @@ -222,16 +196,10 @@ select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2= ## # Check that the shortest key is used for ROR-intersection, covering and non-covering. ---sorted_result ---replace_column 9 # 6 # explain select * from t1 where st_a=1 and st_b=1; ---sorted_result ---replace_column 9 # explain select st_a,st_b from t1 where st_a=1 and st_b=1; # Check if "ingore index" syntax works ---sorted_result ---replace_column 9 # 6 # explain select st_a from t1 ignore index (st_a) where st_a=1 and st_b=1; # Do many tests @@ -240,49 +208,30 @@ explain select st_a from t1 ignore index (st_a) where st_a=1 and st_b=1; # Different value on 32 and 64 bit --replace_result sta_swt12a sta_swt21a sta_swt12a, sta_swt12a, ---replace_column 9 # explain select * from t1 where st_a=1 and swt1a=1 and swt2a=1; ---sorted_result ---replace_column 9 # explain select * from t1 where st_b=1 and swt1b=1 and swt2b=1; ---sorted_result ---replace_column 9 # explain select * from t1 where st_a=1 and swt1a=1 and swt2a=1 and st_b=1 and swt1b=1 and swt2b=1; ---sorted_result ---replace_column 9 # explain select * from t1 ignore index (sta_swt21a, stb_swt1a_2b) where st_a=1 and swt1a=1 and swt2a=1 and st_b=1 and swt1b=1 and swt2b=1; ---sorted_result ---replace_column 9 # explain select * from t1 ignore index (sta_swt21a, sta_swt12a, stb_swt1a_2b) where st_a=1 and swt1a=1 and swt2a=1 and st_b=1 and swt1b=1 and swt2b=1; ---sorted_result ---replace_column 9 # explain select * from t1 ignore index (sta_swt21a, sta_swt12a, stb_swt1a_2b, stb_swt1b) where st_a=1 and swt1a=1 and swt2a=1 and st_b=1 and swt1b=1 and swt2b=1; ---sorted_result ---replace_column 9 # explain select * from t1 where st_a=1 and swt1a=1 and swt2a=1 and st_b=1 and swt1b=1; ---sorted_result ---replace_column 9 # explain select * from t1 where st_a=1 and swt1a=1 and st_b=1 and swt1b=1 and swt1b=1; ---sorted_result ---replace_column 9 # explain select st_a from t1 where st_a=1 and swt1a=1 and st_b=1 and swt1b=1 and swt1b=1; ---sorted_result ---replace_column 9 # explain select st_a from t1 where st_a=1 and swt1a=1 and st_b=1 and swt1b=1 and swt1b=1; @@ -321,7 +270,6 @@ select count(a) from t2 where a='AAAAAAAA' and b='AAAAAAAA'; select count(a) from t2 ignore index(a,b) where a='AAAAAAAA' and b='AAAAAAAA'; insert into t2 values ('ab', 'ab', 'uh', 'oh'); ---replace_column 9 # explain select a from t2 where a='ab'; drop table t2; diff --git a/mysql-test/r/index_merge_innodb.result b/mysql-test/r/index_merge_innodb.result index 1fcdce77da8..8bbbed2865f 100644 --- a/mysql-test/r/index_merge_innodb.result +++ b/mysql-test/r/index_merge_innodb.result @@ -1,1159 +1,3 @@ -#---------------- Index merge test 1 ------------------------------------------- -SET SESSION STORAGE_ENGINE = InnoDB; -drop table if exists t0, t1, t2, t3, t4; -create table t0 -( -key1 int not null, -INDEX i1(key1) -); -alter table t0 add key2 int not null, add index i2(key2); -alter table t0 add key3 int not null, add index i3(key3); -alter table t0 add key4 int not null, add index i4(key4); -alter table t0 add key5 int not null, add index i5(key5); -alter table t0 add key6 int not null, add index i6(key6); -alter table t0 add key7 int not null, add index i7(key7); -alter table t0 add key8 int not null, add index i8(key8); -update t0 set key2=key1,key3=key1,key4=key1,key5=key1,key6=key1,key7=key1,key8=1024-key1; -analyze table t0; -Table Op Msg_type Msg_text -test.t0 analyze status OK -explain select * from t0 where key1 < 3 or key1 > 1020; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 range i1 i1 4 NULL # Using where -explain -select * from t0 where key1 < 3 or key2 > 1020; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 index_merge i1,i2 i1,i2 4,4 NULL # Using sort_union(i1,i2); Using where -select * from t0 where key1 < 3 or key2 > 1020; -key1 key2 key3 key4 key5 key6 key7 key8 -1 1 1 1 1 1 1 1023 -2 2 2 2 2 2 2 1022 -1021 1021 1021 1021 1021 1021 1021 3 -1022 1022 1022 1022 1022 1022 1022 2 -1023 1023 1023 1023 1023 1023 1023 1 -1024 1024 1024 1024 1024 1024 1024 0 -explain select * from t0 where key1 < 3 or key2 <4; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 ALL i1,i2 NULL NULL NULL # Using where -explain -select * from t0 where (key1 > 30 and key1<35) or (key2 >32 and key2 < 40) ; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 index_merge i1,i2 i1,i2 4,4 NULL # Using sort_union(i1,i2); Using where -select * from t0 where (key1 > 30 and key1<35) or (key2 >32 and key2 < 40); -key1 key2 key3 key4 key5 key6 key7 key8 -31 31 31 31 31 31 31 993 -32 32 32 32 32 32 32 992 -33 33 33 33 33 33 33 991 -34 34 34 34 34 34 34 990 -35 35 35 35 35 35 35 989 -36 36 36 36 36 36 36 988 -37 37 37 37 37 37 37 987 -38 38 38 38 38 38 38 986 -39 39 39 39 39 39 39 985 -explain select * from t0 ignore index (i2) where key1 < 3 or key2 <4; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 ALL i1 NULL NULL NULL # Using where -explain select * from t0 where (key1 < 3 or key2 <4) and key3 = 50; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 ref i1,i2,i3 i3 4 const # Using where -explain select * from t0 use index (i1,i2) where (key1 < 3 or key2 <4) and key3 = 50; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 ALL i1,i2 NULL NULL NULL # Using where -explain select * from t0 where (key1 > 1 or key2 > 2); -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 ALL i1,i2 NULL NULL NULL # Using where -explain select * from t0 force index (i1,i2) where (key1 > 1 or key2 > 2); -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 index_merge i1,i2 i1,i2 4,4 NULL # Using sort_union(i1,i2); Using where -explain -select * from t0 where key1<3 or key2<3 or (key1>5 and key1<8) or -(key1>10 and key1<12) or (key2>100 and key2<110); -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 ALL i1,i2 NULL NULL NULL # Using where -explain select * from t0 where key2 = 45 or key1 <=> null; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 range i1,i2 i2 4 NULL # Using where -explain select * from t0 where key2 = 45 or key1 is not null; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 ALL i1,i2 NULL NULL NULL # Using where -explain select * from t0 where key2 = 45 or key1 is null; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 ref i2 i2 4 const # -explain select * from t0 where key2=10 or key3=3 or key4 <=> null; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 index_merge i2,i3,i4 i2,i3 4,4 NULL # Using union(i2,i3); Using where -explain select * from t0 where key2=10 or key3=3 or key4 is null; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 index_merge i2,i3 i2,i3 4,4 NULL # Using union(i2,i3); Using where -explain select key1 from t0 where (key1 <=> null) or (key2 < 5) or -(key3=10) or (key4 <=> null); -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 ALL i1,i2,i3,i4 NULL NULL NULL # Using where -explain select key1 from t0 where (key1 <=> null) or (key1 < 5) or -(key3=10) or (key4 <=> null); -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 index_merge i1,i3,i4 i1,i3 4,4 NULL # Using sort_union(i1,i3); Using where -explain select * from t0 where -(key1 < 3 or key2 < 3) and (key3 < 4 or key4 < 4) and (key5 < 5 or key6 < 5); -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 ALL i1,i2,i3,i4,i5,i6 NULL NULL NULL # Using where -explain -select * from t0 where (key1 < 3 or key2 < 6) and (key1 < 7 or key3 < 4); -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 ALL i1,i2,i3 NULL NULL NULL # Using where -select * from t0 where (key1 < 3 or key2 < 6) and (key1 < 7 or key3 < 4); -key1 key2 key3 key4 key5 key6 key7 key8 -1 1 1 1 1 1 1 1023 -2 2 2 2 2 2 2 1022 -3 3 3 3 3 3 3 1021 -4 4 4 4 4 4 4 1020 -5 5 5 5 5 5 5 1019 -explain select * from t0 where -(key1 < 3 or key2 < 3) and (key3 < 4 or key4 < 4) and (key5 < 2 or key6 < 2); -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 ALL i1,i2,i3,i4,i5,i6 NULL NULL NULL # Using where -explain select * from t0 where -(key1 < 3 or key2 < 3) and (key3 < 100); -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 ALL i1,i2,i3 NULL NULL NULL # Using where -explain select * from t0 where -(key1 < 3 or key2 < 3) and (key3 < 1000); -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 ALL i1,i2,i3 NULL NULL NULL # Using where -explain select * from t0 where -((key1 < 4 or key2 < 4) and (key2 <5 or key3 < 4)) -or -key2 > 5; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 ALL i1,i2,i3 NULL NULL NULL # Using where -explain select * from t0 where -((key1 < 4 or key2 < 4) and (key2 <5 or key3 < 4)) -or -key1 < 7; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 ALL i1,i2,i3 NULL NULL NULL # Using where -select * from t0 where -((key1 < 4 or key2 < 4) and (key2 <5 or key3 < 4)) -or -key1 < 7; -key1 key2 key3 key4 key5 key6 key7 key8 -1 1 1 1 1 1 1 1023 -2 2 2 2 2 2 2 1022 -3 3 3 3 3 3 3 1021 -4 4 4 4 4 4 4 1020 -5 5 5 5 5 5 5 1019 -6 6 6 6 6 6 6 1018 -explain select * from t0 where -((key1 < 4 or key2 < 4) and (key3 <5 or key5 < 4)) -or -((key5 < 5 or key6 < 6) and (key7 <7 or key8 < 4)); -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 ALL i1,i2,i3,i5,i6,i7,i8 NULL NULL NULL # Using where -explain select * from t0 where -((key3 <5 or key5 < 4) and (key1 < 4 or key2 < 4)) -or -((key7 <7 or key8 < 4) and (key5 < 5 or key6 < 6)); -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 ALL i1,i2,i3,i5,i6,i7,i8 NULL NULL NULL # Using where -explain select * from t0 where -((key3 <5 or key5 < 4) and (key1 < 4 or key2 < 4)) -or -((key3 <7 or key5 < 2) and (key5 < 5 or key6 < 6)); -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 ALL i1,i2,i3,i5,i6 NULL NULL NULL # Using where -explain select * from t0 where -((key3 <5 or key5 < 4) and (key1 < 4 or key2 < 4)) -or -(((key3 <7 and key7 < 6) or key5 < 2) and (key5 < 5 or key6 < 6)); -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 ALL i1,i2,i3,i5,i6,i7 NULL NULL NULL # Using where -explain select * from t0 where -((key3 <5 or key5 < 4) and (key1 < 4 or key2 < 4)) -or -((key3 >=5 or key5 < 2) and (key5 < 5 or key6 < 6)); -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 ALL i1,i2,i3,i5,i6 NULL NULL NULL # Using where -explain select * from t0 force index(i1, i2, i3, i4, i5, i6 ) where -((key3 <5 or key5 < 4) and (key1 < 4 or key2 < 4)) -or -((key3 >=5 or key5 < 2) and (key5 < 5 or key6 < 6)); -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 index_merge i1,i2,i3,i5,i6 i3,i5 0,4 NULL # Using sort_union(i3,i5); Using where -select * from t0 where key1 < 5 or key8 < 4 order by key1; -key1 key2 key3 key4 key5 key6 key7 key8 -1 1 1 1 1 1 1 1023 -2 2 2 2 2 2 2 1022 -3 3 3 3 3 3 3 1021 -4 4 4 4 4 4 4 1020 -1021 1021 1021 1021 1021 1021 1021 3 -1022 1022 1022 1022 1022 1022 1022 2 -1023 1023 1023 1023 1023 1023 1023 1 -1024 1024 1024 1024 1024 1024 1024 0 -explain -select * from t0 where key1 < 5 or key8 < 4 order by key1; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 ALL i1,i8 NULL NULL NULL # Using where; Using filesort -create table t2 like t0; -insert into t2 select * from t0; -alter table t2 add index i1_3(key1, key3); -alter table t2 add index i2_3(key2, key3); -alter table t2 drop index i1; -alter table t2 drop index i2; -alter table t2 add index i321(key3, key2, key1); -explain select key3 from t2 where key1 = 100 or key2 = 100; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 index_merge i1_3,i2_3 i1_3,i2_3 4,4 NULL # Using sort_union(i1_3,i2_3); Using where -explain select key3 from t2 where key1 <100 or key2 < 100; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 index i1_3,i2_3 i321 12 NULL # Using where; Using index -explain select key7 from t2 where key1 <100 or key2 < 100; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 ALL i1_3,i2_3 NULL NULL NULL # Using where -create table t4 ( -key1a int not null, -key1b int not null, -key2 int not null, -key2_1 int not null, -key2_2 int not null, -key3 int not null, -index i1a (key1a, key1b), -index i1b (key1b, key1a), -index i2_1(key2, key2_1), -index i2_2(key2, key2_1) -); -insert into t4 select key1,key1,key1 div 10, key1 % 10, key1 % 10, key1 from t0; -select * from t4 where key1a = 3 or key1b = 4; -key1a key1b key2 key2_1 key2_2 key3 -3 3 0 3 3 3 -4 4 0 4 4 4 -explain select * from t4 where key1a = 3 or key1b = 4; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t4 index_merge i1a,i1b i1a,i1b 4,4 NULL # Using sort_union(i1a,i1b); Using where -explain select * from t4 where key2 = 1 and (key2_1 = 1 or key3 = 5); -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t4 ref i2_1,i2_2 i2_1 4 const # Using where -explain select * from t4 where key2 = 1 and (key2_1 = 1 or key2_2 = 5); -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t4 ref i2_1,i2_2 i2_1 4 const # Using where -explain select * from t4 where key2_1 = 1 or key2_2 = 5; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t4 ALL NULL NULL NULL NULL # Using where -create table t1 like t0; -insert into t1 select * from t0; -explain select * from t0 left join t1 on (t0.key1=t1.key1) -where t0.key1=3 or t0.key2=4; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 index_merge i1,i2 i1,i2 4,4 NULL # Using union(i1,i2); Using where -1 SIMPLE t1 ref i1 i1 4 test.t0.key1 # -select * from t0 left join t1 on (t0.key1=t1.key1) -where t0.key1=3 or t0.key2=4; -key1 key2 key3 key4 key5 key6 key7 key8 key1 key2 key3 key4 key5 key6 key7 key8 -3 3 3 3 3 3 3 1021 3 3 3 3 3 3 3 1021 -4 4 4 4 4 4 4 1020 4 4 4 4 4 4 4 1020 -explain -select * from t0,t1 where (t0.key1=t1.key1) and ( t0.key1=3 or t0.key2=4); -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 index_merge i1,i2 i1,i2 4,4 NULL # Using union(i1,i2); Using where -1 SIMPLE t1 ref i1 i1 4 test.t0.key1 # -explain -select * from t0,t1 where (t0.key1=t1.key1) and -(t0.key1=3 or t0.key2=4) and t1.key1<200; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 # i1,i2 # # test.t0.key1 # # -1 SIMPLE t1 # i1 # # test.t0.key1 # # -explain -select * from t0,t1 where (t0.key1=t1.key1) and -(t0.key1=3 or t0.key2<4) and t1.key1=2; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 ref i1,i2 i1 4 test.t0.key1 # Using where -1 SIMPLE t1 ref i1 i1 4 test.t0.key1 # -explain select * from t0,t1 where t0.key1 = 5 and -(t1.key1 = t0.key1 or t1.key8 = t0.key1); -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 ref i1 i1 4 test.t0.key1 # -1 SIMPLE t1 index_merge i1,i8 i1,i8 4,4 test.t0.key1 # Using union(i1,i8); Using where; Using join buffer -explain select * from t0,t1 where t0.key1 < 3 and -(t1.key1 = t0.key1 or t1.key8 = t0.key1); -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 range i1 i1 4 test.t0.key1 # Using where -1 SIMPLE t1 ALL i1,i8 NULL NULL test.t0.key1 # Range checked for each record (index map: 0x81) -explain select * from t1 where key1=3 or key2=4 -union select * from t1 where key1<4 or key3=5; -id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t1 index_merge i1,i2 i1,i2 4,4 NULL # Using union(i1,i2); Using where -2 UNION t1 index_merge i1,i3 i1,i3 4,4 NULL # Using sort_union(i1,i3); Using where -NULL UNION RESULT ALL NULL NULL NULL NULL # -explain select * from (select * from t1 where key1 = 3 or key2 =3) as Z where key8 >5; -id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY system NULL NULL NULL NULL # -2 DERIVED t1 index_merge i1,i2 i1,i2 4,4 NULL # Using union(i1,i2); Using where; Using index -create table t3 like t0; -insert into t3 select * from t0; -alter table t3 add key9 int not null, add index i9(key9); -alter table t3 add keyA int not null, add index iA(keyA); -alter table t3 add keyB int not null, add index iB(keyB); -alter table t3 add keyC int not null, add index iC(keyC); -update t3 set key9=key1,keyA=key1,keyB=key1,keyC=key1; -explain select * from t3 where -key1=1 or key2=2 or key3=3 or key4=4 or -key5=5 or key6=6 or key7=7 or key8=8 or -key9=9 or keyA=10 or keyB=11 or keyC=12; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t3 index_merge i1,i2,i3,i4,i5,i6,i7,i8,i9,iA,iB,iC i1,i2,i3,i4,i5,i6,i7,i8,i9,iA,iB,iC 4,4,4,4,4,4,4,4,4,4,4,4 NULL # Using union(i1,i2,i3,i4,i5,i6,i7,i8,i9,iA,iB,iC); Using where -select * from t3 where -key1=1 or key2=2 or key3=3 or key4=4 or -key5=5 or key6=6 or key7=7 or key8=8 or -key9=9 or keyA=10 or keyB=11 or keyC=12; -key1 key2 key3 key4 key5 key6 key7 key8 key9 keyA keyB keyC -1 1 1 1 1 1 1 1023 1 1 1 1 -2 2 2 2 2 2 2 1022 2 2 2 2 -3 3 3 3 3 3 3 1021 3 3 3 3 -4 4 4 4 4 4 4 1020 4 4 4 4 -5 5 5 5 5 5 5 1019 5 5 5 5 -6 6 6 6 6 6 6 1018 6 6 6 6 -7 7 7 7 7 7 7 1017 7 7 7 7 -9 9 9 9 9 9 9 1015 9 9 9 9 -10 10 10 10 10 10 10 1014 10 10 10 10 -11 11 11 11 11 11 11 1013 11 11 11 11 -12 12 12 12 12 12 12 1012 12 12 12 12 -1016 1016 1016 1016 1016 1016 1016 8 1016 1016 1016 1016 -explain select * from t0 where key1 < 3 or key2 < 4; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 # i1,i2 # # NULL # # -select * from t0 where key1 < 3 or key2 < 4; -key1 key2 key3 key4 key5 key6 key7 key8 -1 1 1 1 1 1 1 1023 -2 2 2 2 2 2 2 1022 -3 3 3 3 3 3 3 1021 -update t0 set key8=123 where key1 < 3 or key2 < 4; -select * from t0 where key1 < 3 or key2 < 4; -key1 key2 key3 key4 key5 key6 key7 key8 -1 1 1 1 1 1 1 123 -2 2 2 2 2 2 2 123 -3 3 3 3 3 3 3 123 -delete from t0 where key1 < 3 or key2 < 4; -select * from t0 where key1 < 3 or key2 < 4; -key1 key2 key3 key4 key5 key6 key7 key8 -select count(*) from t0; -count(*) -1021 -drop table t4; -create table t4 (a int); -insert into t4 values (1),(4),(3); -set @save_join_buffer_size=@@join_buffer_size; -set join_buffer_size= 4096; -explain select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) -from t0 as A force index(i1,i2), t0 as B force index (i1,i2) -where (A.key1 < 500000 or A.key2 < 3) -and (B.key1 < 500000 or B.key2 < 3); -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE A index_merge i1,i2 i1,i2 4,4 NULL # Using sort_union(i1,i2); Using where -1 SIMPLE B index_merge i1,i2 i1,i2 4,4 NULL # Using sort_union(i1,i2); Using where; Using join buffer -select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) -from t0 as A force index(i1,i2), t0 as B force index (i1,i2) -where (A.key1 < 500000 or A.key2 < 3) -and (B.key1 < 500000 or B.key2 < 3); -max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) -10240 -update t0 set key1=1; -explain select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) -from t0 as A force index(i1,i2), t0 as B force index (i1,i2) -where (A.key1 = 1 or A.key2 = 1) -and (B.key1 = 1 or B.key2 = 1); -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE A index_merge i1,i2 i1,i2 4,4 NULL # Using union(i1,i2); Using where -1 SIMPLE B index_merge i1,i2 i1,i2 4,4 NULL # Using union(i1,i2); Using where; Using join buffer -select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) -from t0 as A force index(i1,i2), t0 as B force index (i1,i2) -where (A.key1 = 1 or A.key2 = 1) -and (B.key1 = 1 or B.key2 = 1); -max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) -8194 -alter table t0 add filler1 char(200), add filler2 char(200), add filler3 char(200); -update t0 set key2=1, key3=1, key4=1, key5=1,key6=1,key7=1 where key7 < 500; -explain select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) -from t0 as A, t0 as B -where (A.key1 = 1 and A.key2 = 1 and A.key3 = 1 and A.key4=1 and A.key5=1 and A.key6=1 and A.key7 = 1 or A.key8=1) -and (B.key1 = 1 and B.key2 = 1 and B.key3 = 1 and B.key4=1 and B.key5=1 and B.key6=1 and B.key7 = 1 or B.key8=1); -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE A # i1,i2,i3,i4,i5,i6,i7?,i8 # # NULL # # -1 SIMPLE B # i1,i2,i3,i4,i5,i6,i7?,i8 # # NULL # # -select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) -from t0 as A, t0 as B -where (A.key1 = 1 and A.key2 = 1 and A.key3 = 1 and A.key4=1 and A.key5=1 and A.key6=1 and A.key7 = 1 or A.key8=1) -and (B.key1 = 1 and B.key2 = 1 and B.key3 = 1 and B.key4=1 and B.key5=1 and B.key6=1 and B.key7 = 1 or B.key8=1); -max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) -8186 -set join_buffer_size= @save_join_buffer_size; -drop table t0, t1, t2, t3, t4; -CREATE TABLE t1 ( -cola char(3) not null, colb char(3) not null, filler char(200), -key(cola), key(colb) -); -INSERT INTO t1 VALUES ('foo','bar', 'ZZ'),('fuz','baz', 'ZZ'); -OPTIMIZE TABLE t1; -Table Op Msg_type Msg_text -test.t1 optimize note Table does not support optimize, doing recreate + analyze instead -test.t1 optimize status OK -select count(*) from t1; -count(*) -8704 -explain select * from t1 WHERE cola = 'foo' AND colb = 'bar'; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge cola,colb cola,colb 3,3 NULL # Using intersect(cola,colb); Using where -explain select * from t1 force index(cola,colb) WHERE cola = 'foo' AND colb = 'bar'; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge cola,colb cola,colb 3,3 NULL # Using intersect(cola,colb); Using where -drop table t1; -CREATE TABLE t1(a INT); -INSERT INTO t1 VALUES(1); -CREATE TABLE t2(a INT, b INT, dummy CHAR(16) DEFAULT '', KEY(a), KEY(b)); -INSERT INTO t2(a,b) VALUES -(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0), -(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0), -(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0), -(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0), -(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0), -(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0), -(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0), -(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0), -(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0), -(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0), -(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0), -(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0), -(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0), -(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0), -(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0), -(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0), -(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0), -(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0),(0,0), -(1,2); -LOCK TABLES t1 WRITE, t2 WRITE; -INSERT INTO t2(a,b) VALUES(1,2); -SELECT t2.a FROM t1,t2 WHERE t2.b=2 AND t2.a=1; -a -1 -1 -UNLOCK TABLES; -DROP TABLE t1, t2; -CREATE TABLE `t1` ( -`a` int(11) DEFAULT NULL, -`filler` char(200) DEFAULT NULL, -`b` int(11) DEFAULT NULL, -KEY `a` (`a`), -KEY `b` (`b`) -) ENGINE=MEMORY DEFAULT CHARSET=latin1; -insert into t1 values -(0, 'filler', 0), (1, 'filler', 1), (2, 'filler', 2), (3, 'filler', 3), -(4, 'filler', 4), (5, 'filler', 5), (6, 'filler', 6), (7, 'filler', 7), -(8, 'filler', 8), (9, 'filler', 9), (0, 'filler', 0), (1, 'filler', 1), -(2, 'filler', 2), (3, 'filler', 3), (4, 'filler', 4), (5, 'filler', 5), -(6, 'filler', 6), (7, 'filler', 7), (8, 'filler', 8), (9, 'filler', 9), -(10, 'filler', 10), (11, 'filler', 11), (12, 'filler', 12), (13, 'filler', 13), -(14, 'filler', 14), (15, 'filler', 15), (16, 'filler', 16), (17, 'filler', 17), -(18, 'filler', 18), (19, 'filler', 19), (4, '5 ', 0), (5, '4 ', 0), -(4, '4 ', 0), (4, 'qq ', 5), (5, 'qq ', 4), (4, 'zz ', 4); -create table t2( -`a` int(11) DEFAULT NULL, -`filler` char(200) DEFAULT NULL, -`b` int(11) DEFAULT NULL, -KEY USING BTREE (`a`), -KEY USING BTREE (`b`) -) ENGINE=MEMORY DEFAULT CHARSET=latin1; -insert into t2 select * from t1; -must use sort-union rather than union: -explain select * from t1 where a=4 or b=4; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge a,b a,b 5,5 NULL # Using sort_union(a,b); Using where -select * from t1 where a=4 or b=4; -a filler b -4 4 0 -4 5 0 -4 filler 4 -4 filler 4 -4 qq 5 -4 zz 4 -5 qq 4 -select * from t1 ignore index(a,b) where a=4 or b=4; -a filler b -4 4 0 -4 5 0 -4 filler 4 -4 filler 4 -4 qq 5 -4 zz 4 -5 qq 4 -must use union, not sort-union: -explain select * from t2 where a=4 or b=4; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 index_merge a,b a,b 5,5 NULL # Using union(a,b); Using where -select * from t2 where a=4 or b=4; -a filler b -4 4 0 -4 5 0 -4 filler 4 -4 filler 4 -4 qq 5 -4 zz 4 -5 qq 4 -drop table t1, t2; -CREATE TABLE t1 (a varchar(8), b set('a','b','c','d','e','f','g','h'), -KEY b(b), KEY a(a)); -INSERT INTO t1 VALUES ('y',''), ('z',''); -SELECT b,a from t1 WHERE (b!='c' AND b!='f' && b!='h') OR -(a='pure-S') OR (a='DE80337a') OR (a='DE80799'); -b a - y - z -DROP TABLE t1; -# -# BUG#40974: Incorrect query results when using clause evaluated using range check -# -create table t0 (a int); -insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); -create table t1 (a int); -insert into t1 values (1),(2); -create table t2(a int, b int); -insert into t2 values (1,1), (2, 1000); -create table t3 (a int, b int, filler char(100), key(a), key(b)); -insert into t3 select 1000, 1000,'filler' from t0 A, t0 B, t0 C; -insert into t3 values (1,1,'data'); -insert into t3 values (1,1,'data'); -The plan should be ALL/ALL/ALL(Range checked for each record (index map: 0x3) -explain select * from t1 -where exists (select 1 from t2, t3 -where t2.a=t1.a and (t3.a=t2.b or t3.b=t2.b or t3.b=t2.b+1)); -id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t1 ALL NULL NULL NULL NULL # Using where -2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL # Using where -2 DEPENDENT SUBQUERY t3 ALL a,b NULL NULL NULL # Range checked for each record (index map: 0x3) -select * from t1 -where exists (select 1 from t2, t3 -where t2.a=t1.a and (t3.a=t2.b or t3.b=t2.b or t3.b=t2.b+1)); -a -1 -2 -drop table t0, t1, t2, t3; -# -# BUG#44810: index merge and order by with low sort_buffer_size -# crashes server! -# -CREATE TABLE t1(a VARCHAR(128),b VARCHAR(128),KEY(A),KEY(B)); -INSERT INTO t1 VALUES (REPEAT('a',128),REPEAT('b',128)); -INSERT INTO t1 SELECT * FROM t1; -INSERT INTO t1 SELECT * FROM t1; -INSERT INTO t1 SELECT * FROM t1; -INSERT INTO t1 SELECT * FROM t1; -INSERT INTO t1 SELECT * FROM t1; -INSERT INTO t1 SELECT * FROM t1; -SET SESSION sort_buffer_size=1; -Warnings: -Warning 1292 Truncated incorrect sort_buffer_size value: '1' -explain -SELECT * FROM t1 FORCE INDEX(a,b) WHERE a LIKE 'a%' OR b LIKE 'b%' -ORDER BY a,b; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge a,b a,b 131,131 NULL # Using sort_union(a,b); Using where; Using filesort -SELECT * FROM t1 FORCE INDEX(a,b) WHERE a LIKE 'a%' OR b LIKE 'b%' -ORDER BY a,b; -SET SESSION sort_buffer_size=DEFAULT; -DROP TABLE t1; -End of 5.0 tests -#---------------- ROR-index_merge tests ----------------------- -SET SESSION STORAGE_ENGINE = InnoDB; -drop table if exists t0,t1,t2; -create table t1 -( -/* Field names reflect value(rowid) distribution, st=STairs, swt= SaWTooth */ -st_a int not null default 0, -swt1a int not null default 0, -swt2a int not null default 0, -st_b int not null default 0, -swt1b int not null default 0, -swt2b int not null default 0, -/* fields/keys for row retrieval tests */ -key1 int, -key2 int, -key3 int, -key4 int, -/* make rows much bigger then keys */ -filler1 char (200), -filler2 char (200), -filler3 char (200), -filler4 char (200), -filler5 char (200), -filler6 char (200), -/* order of keys is important */ -key sta_swt12a(st_a,swt1a,swt2a), -key sta_swt1a(st_a,swt1a), -key sta_swt2a(st_a,swt2a), -key sta_swt21a(st_a,swt2a,swt1a), -key st_a(st_a), -key stb_swt1a_2b(st_b,swt1b,swt2a), -key stb_swt1b(st_b,swt1b), -key st_b(st_b), -key(key1), -key(key2), -key(key3), -key(key4) -) ; -create table t0 as select * from t1; -# Printing of many insert into t0 values (....) disabled. -alter table t1 disable keys; -Warnings: -Note 1031 Table storage engine for 't1' doesn't have this option -# Printing of many insert into t1 select .... from t0 disabled. -# Printing of many insert into t1 (...) values (....) disabled. -alter table t1 enable keys; -Warnings: -Note 1031 Table storage engine for 't1' doesn't have this option -select count(*) from t1; -count(*) -64801 -explain select key1,key2 from t1 where key1=100 and key2=100; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge key1,key2 key1,key2 5,5 NULL # Using intersect(key1,key2); Using where; Using index -select key1,key2 from t1 where key1=100 and key2=100; -key1 key2 -100 100 -explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge key1,key2,key3,key4 key1,key2,key3,key4 5,5,5,5 NULL # Using union(intersect(key1,key2),intersect(key3,key4)); Using where -select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; -key1 key2 key3 key4 filler1 -100 100 100 100 key1-key2-key3-key4 -insert into t1 (key1, key2, key3, key4, filler1) values (100, 100, -1, -1, 'key1-key2'); -insert into t1 (key1, key2, key3, key4, filler1) values (-1, -1, 100, 100, 'key4-key3'); -explain select key1,key2,filler1 from t1 where key1=100 and key2=100; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge key1,key2 key1,key2 5,5 NULL # Using intersect(key1,key2); Using where -select key1,key2,filler1 from t1 where key1=100 and key2=100; -key1 key2 filler1 -100 100 key1-key2-key3-key4 -100 100 key1-key2 -explain select key1,key2 from t1 where key1=100 and key2=100; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge key1,key2 key1,key2 5,5 NULL # Using intersect(key1,key2); Using where; Using index -select key1,key2 from t1 where key1=100 and key2=100; -key1 key2 -100 100 -100 100 -explain select key1,key2,key3,key4 from t1 where key1=100 and key2=100 or key3=100 and key4=100; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge key1,key2,key3,key4 key1,key2,key3,key4 5,5,5,5 NULL # Using union(intersect(key1,key2),intersect(key3,key4)); Using where -select key1,key2,key3,key4 from t1 where key1=100 and key2=100 or key3=100 and key4=100; -key1 key2 key3 key4 -100 100 100 100 -100 100 -1 -1 --1 -1 100 100 -explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge key1,key2,key3,key4 key1,key2,key3,key4 5,5,5,5 NULL 4 Using union(intersect(key1,key2),intersect(key3,key4)); Using where -select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; -key1 key2 key3 key4 filler1 -100 100 100 100 key1-key2-key3-key4 -100 100 -1 -1 key1-key2 --1 -1 100 100 key4-key3 -explain select key1,key2,key3 from t1 where key1=100 and key2=100 and key3=100; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge key1,key2,key3 key1,key2,key3 5,5,5 NULL # Using intersect(key1,key2,key3); Using where; Using index -select key1,key2,key3 from t1 where key1=100 and key2=100 and key3=100; -key1 key2 key3 -100 100 100 -insert into t1 (key1,key2,key3,key4,filler1) values (101,101,101,101, 'key1234-101'); -explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=101; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge key1,key2,key3 key1,key2,key3 5,5,5 NULL # Using union(intersect(key1,key2),key3); Using where -select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=101; -key1 key2 key3 key4 filler1 -100 100 100 100 key1-key2-key3-key4 -100 100 -1 -1 key1-key2 -101 101 101 101 key1234-101 -select key1,key2, filler1 from t1 where key1=100 and key2=100; -key1 key2 filler1 -100 100 key1-key2-key3-key4 -100 100 key1-key2 -update t1 set filler1='to be deleted' where key1=100 and key2=100; -update t1 set key1=200,key2=200 where key1=100 and key2=100; -delete from t1 where key1=200 and key2=200; -select key1,key2,filler1 from t1 where key2=100 and key2=200; -key1 key2 filler1 -explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge key1,key2,key3,key4 key1,key2,key3,key4 5,5,5,5 NULL # Using union(intersect(key1,key2),intersect(key3,key4)); Using where -select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; -key1 key2 key3 key4 filler1 --1 -1 100 100 key4-key3 -delete from t1 where key3=100 and key4=100; -explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge key1,key2,key3,key4 key1,key2,key3,key4 5,5,5,5 NULL # Using union(intersect(key1,key2),intersect(key3,key4)); Using where -select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; -key1 key2 key3 key4 filler1 -explain select key1,key2 from t1 where key1=100 and key2=100; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge key1,key2 key1,key2 5,5 NULL # Using intersect(key1,key2); Using where; Using index -select key1,key2 from t1 where key1=100 and key2=100; -key1 key2 -insert into t1 (key1, key2, key3, key4, filler1) values (100, 100, 200, 200,'key1-key2-key3-key4-1'); -insert into t1 (key1, key2, key3, key4, filler1) values (100, 100, 200, 200,'key1-key2-key3-key4-2'); -insert into t1 (key1, key2, key3, key4, filler1) values (100, 100, 200, 200,'key1-key2-key3-key4-3'); -explain select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge key1,key2,key3,key4 key3,key1,key2,key4 5,5,5,5 NULL # Using union(key3,intersect(key1,key2),key4); Using where -select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200; -key1 key2 key3 key4 filler1 -100 100 200 200 key1-key2-key3-key4-1 -100 100 200 200 key1-key2-key3-key4-2 -100 100 200 200 key1-key2-key3-key4-3 -insert into t1 (key1, key2, key3, key4, filler1) values (-1, -1, -1, 200,'key4'); -explain select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge key1,key2,key3,key4 key3,key1,key2,key4 5,5,5,5 NULL # Using union(key3,intersect(key1,key2),key4); Using where -select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200; -key1 key2 key3 key4 filler1 -100 100 200 200 key1-key2-key3-key4-1 -100 100 200 200 key1-key2-key3-key4-2 -100 100 200 200 key1-key2-key3-key4-3 --1 -1 -1 200 key4 -insert into t1 (key1, key2, key3, key4, filler1) values (-1, -1, 200, -1,'key3'); -explain select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge key1,key2,key3,key4 key3,key1,key2,key4 5,5,5,5 NULL # Using union(key3,intersect(key1,key2),key4); Using where -select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200; -key1 key2 key3 key4 filler1 -100 100 200 200 key1-key2-key3-key4-1 -100 100 200 200 key1-key2-key3-key4-2 -100 100 200 200 key1-key2-key3-key4-3 --1 -1 -1 200 key4 --1 -1 200 -1 key3 -explain select * from t1 where st_a=1 and st_b=1; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a,stb_swt1a_2b,stb_swt1b,st_b # 4 const # Using where -explain select st_a,st_b from t1 where st_a=1 and st_b=1; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a,stb_swt1a_2b,stb_swt1b,st_b st_a,st_b 4,4 NULL # Using intersect(st_a,st_b); Using where; Using index -explain select st_a from t1 ignore index (st_a) where st_a=1 and st_b=1; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,stb_swt1a_2b,stb_swt1b,st_b # 4 const # Using where -explain select * from t1 where st_a=1 and swt1a=1 and swt2a=1; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a sta_swt21a 12 const,const,const # -explain select * from t1 where st_b=1 and swt1b=1 and swt2b=1; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref stb_swt1a_2b,stb_swt1b,st_b stb_swt1a_2b 8 const,const # Using where -explain select * from t1 where st_a=1 and swt1a=1 and swt2a=1 and st_b=1 and swt1b=1 and swt2b=1; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a,stb_swt1a_2b,stb_swt1b,st_b sta_swt12a,stb_swt1a_2b 12,12 NULL # Using intersect(sta_swt12a,stb_swt1a_2b); Using where -explain select * from t1 ignore index (sta_swt21a, stb_swt1a_2b) -where st_a=1 and swt1a=1 and swt2a=1 and st_b=1 and swt1b=1 and swt2b=1; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge sta_swt12a,sta_swt1a,sta_swt2a,st_a,stb_swt1b,st_b sta_swt12a,stb_swt1b 12,8 NULL # Using intersect(sta_swt12a,stb_swt1b); Using where -explain select * from t1 ignore index (sta_swt21a, sta_swt12a, stb_swt1a_2b) -where st_a=1 and swt1a=1 and swt2a=1 and st_b=1 and swt1b=1 and swt2b=1; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge sta_swt1a,sta_swt2a,st_a,stb_swt1b,st_b sta_swt1a,sta_swt2a,stb_swt1b 8,8,8 NULL # Using intersect(sta_swt1a,sta_swt2a,stb_swt1b); Using where -explain select * from t1 ignore index (sta_swt21a, sta_swt12a, stb_swt1a_2b, stb_swt1b) -where st_a=1 and swt1a=1 and swt2a=1 and st_b=1 and swt1b=1 and swt2b=1; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge sta_swt1a,sta_swt2a,st_a,st_b sta_swt1a,sta_swt2a,st_b 8,8,4 NULL # Using intersect(sta_swt1a,sta_swt2a,st_b); Using where -explain select * from t1 -where st_a=1 and swt1a=1 and swt2a=1 and st_b=1 and swt1b=1; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a,stb_swt1a_2b,stb_swt1b,st_b sta_swt12a,stb_swt1a_2b 12,12 NULL # Using intersect(sta_swt12a,stb_swt1a_2b); Using where -explain select * from t1 -where st_a=1 and swt1a=1 and st_b=1 and swt1b=1 and swt1b=1; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a,stb_swt1a_2b,stb_swt1b,st_b sta_swt1a,stb_swt1b 8,8 NULL # Using intersect(sta_swt1a,stb_swt1b); Using where -explain select st_a from t1 -where st_a=1 and swt1a=1 and st_b=1 and swt1b=1 and swt1b=1; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a,stb_swt1a_2b,stb_swt1b,st_b sta_swt1a,stb_swt1b 8,8 NULL # Using intersect(sta_swt1a,stb_swt1b); Using where; Using index -explain select st_a from t1 -where st_a=1 and swt1a=1 and st_b=1 and swt1b=1 and swt1b=1; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a,stb_swt1a_2b,stb_swt1b,st_b sta_swt1a,stb_swt1b 8,8 NULL # Using intersect(sta_swt1a,stb_swt1b); Using where; Using index -drop table t0,t1; -create table t2 ( -a char(10), -b char(10), -filler1 char(255), -filler2 char(255), -key(a(5)), -key(b(5)) -); -select count(a) from t2 where a='BBBBBBBB'; -count(a) -4 -select count(a) from t2 where b='BBBBBBBB'; -count(a) -4 -expla_or_bin select count(a_or_b) from t2 where a_or_b='AAAAAAAA' a_or_bnd a_or_b='AAAAAAAA'; -id select_type ta_or_ba_or_ble type possia_or_ble_keys key key_len ref rows Extra_or_b -1 SIMPLE t2 ref a_or_b,a_or_b a_or_b 6 const 4 Using where -select count(a) from t2 where a='AAAAAAAA' and b='AAAAAAAA'; -count(a) -4 -select count(a) from t2 ignore index(a,b) where a='AAAAAAAA' and b='AAAAAAAA'; -count(a) -4 -insert into t2 values ('ab', 'ab', 'uh', 'oh'); -explain select a from t2 where a='ab'; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 ref a a 6 const # Using where -drop table t2; -CREATE TABLE t1(c1 INT, c2 INT DEFAULT 0, c3 CHAR(255) DEFAULT '', -KEY(c1), KEY(c2), KEY(c3)); -INSERT INTO t1(c1) VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0), -(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0); -INSERT INTO t1 VALUES(0,0,0); -CREATE TABLE t2(c1 int); -INSERT INTO t2 VALUES(1); -DELETE t1 FROM t1,t2 WHERE t1.c1=0 AND t1.c2=0; -SELECT * FROM t1; -c1 c2 c3 -DROP TABLE t1,t2; -#---------------- Index merge test 2 ------------------------------------------- -SET SESSION STORAGE_ENGINE = InnoDB; -drop table if exists t1,t2; -create table t1 -( -key1 int not null, -key2 int not null, -INDEX i1(key1), -INDEX i2(key2) -); -explain select * from t1 where key1 < 5 or key2 > 197; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge i1,i2 i1,i2 4,4 NULL 8 Using sort_union(i1,i2); Using where -select * from t1 where key1 < 5 or key2 > 197; -key1 key2 -0 200 -1 199 -2 198 -3 197 -4 196 -explain select * from t1 where key1 < 3 or key2 > 195; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge i1,i2 i1,i2 4,4 NULL 8 Using sort_union(i1,i2); Using where -select * from t1 where key1 < 3 or key2 > 195; -key1 key2 -0 200 -1 199 -2 198 -3 197 -4 196 -alter table t1 add str1 char (255) not null, -add zeroval int not null default 0, -add str2 char (255) not null, -add str3 char (255) not null; -update t1 set str1='aaa', str2='bbb', str3=concat(key2, '-', key1 div 2, '_' ,if(key1 mod 2 = 0, 'a', 'A')); -alter table t1 add primary key (str1, zeroval, str2, str3); -explain select * from t1 where key1 < 5 or key2 > 197; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge i1,i2 i1,i2 4,4 NULL 8 Using sort_union(i1,i2); Using where -select * from t1 where key1 < 5 or key2 > 197; -key1 key2 str1 zeroval str2 str3 -4 196 aaa 0 bbb 196-2_a -3 197 aaa 0 bbb 197-1_A -2 198 aaa 0 bbb 198-1_a -1 199 aaa 0 bbb 199-0_A -0 200 aaa 0 bbb 200-0_a -explain select * from t1 where key1 < 3 or key2 > 195; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge i1,i2 i1,i2 4,4 NULL 8 Using sort_union(i1,i2); Using where -select * from t1 where key1 < 3 or key2 > 195; -key1 key2 str1 zeroval str2 str3 -4 196 aaa 0 bbb 196-2_a -3 197 aaa 0 bbb 197-1_A -2 198 aaa 0 bbb 198-1_a -1 199 aaa 0 bbb 199-0_A -0 200 aaa 0 bbb 200-0_a -drop table t1; -create table t1 ( -pk integer not null auto_increment primary key, -key1 integer, -key2 integer not null, -filler char (200), -index (key1), -index (key2) -); -show warnings; -Level Code Message -explain select pk from t1 where key1 = 1 and key2 = 1; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge key1,key2 key1,key2 5,4 NULL 1 Using intersect(key1,key2); Using where; Using index -select pk from t1 where key2 = 1 and key1 = 1; -pk -26 -27 -select pk from t1 ignore index(key1,key2) where key2 = 1 and key1 = 1; -pk -26 -27 -drop table t1; -create table t1 ( -pk int primary key auto_increment, -key1a int, -key2a int, -key1b int, -key2b int, -dummy1 int, -dummy2 int, -dummy3 int, -dummy4 int, -key3a int, -key3b int, -filler1 char (200), -index i1(key1a, key1b), -index i2(key2a, key2b), -index i3(key3a, key3b) -); -create table t2 (a int); -insert into t2 values (0),(1),(2),(3),(4),(NULL); -insert into t1 (key1a, key1b, key2a, key2b, key3a, key3b) -select A.a, B.a, C.a, D.a, C.a, D.a from t2 A,t2 B,t2 C, t2 D; -insert into t1 (key1a, key1b, key2a, key2b, key3a, key3b) -select key1a, key1b, key2a, key2b, key3a, key3b from t1; -insert into t1 (key1a, key1b, key2a, key2b, key3a, key3b) -select key1a, key1b, key2a, key2b, key3a, key3b from t1; -analyze table t1; -Table Op Msg_type Msg_text -test.t1 analyze status OK -select count(*) from t1; -count(*) -5184 -explain select count(*) from t1 where -key1a = 2 and key1b is null and key2a = 2 and key2b is null; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge i1,i2 i1,i2 10,10 NULL # Using intersect(i1,i2); Using where; Using index -select count(*) from t1 where -key1a = 2 and key1b is null and key2a = 2 and key2b is null; -count(*) -4 -explain select count(*) from t1 where -key1a = 2 and key1b is null and key3a = 2 and key3b is null; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge i1,i3 i1,i3 10,10 NULL # Using intersect(i1,i3); Using where; Using index -select count(*) from t1 where -key1a = 2 and key1b is null and key3a = 2 and key3b is null; -count(*) -4 -drop table t1,t2; -create table t1 ( -id1 int, -id2 date , -index idx2 (id1,id2), -index idx1 (id2) -); -insert into t1 values(1,'20040101'), (2,'20040102'); -select * from t1 where id1 = 1 and id2= '20040101'; -id1 id2 -1 2004-01-01 -drop table t1; -drop view if exists v1; -CREATE TABLE t1 ( -`oid` int(11) unsigned NOT NULL auto_increment, -`fk_bbk_niederlassung` int(11) unsigned NOT NULL, -`fk_wochentag` int(11) unsigned NOT NULL, -`uhrzeit_von` time NOT NULL COMMENT 'HH:MM', -`uhrzeit_bis` time NOT NULL COMMENT 'HH:MM', -`geloescht` tinyint(4) NOT NULL, -`version` int(5) NOT NULL, -PRIMARY KEY (`oid`), -KEY `fk_bbk_niederlassung` (`fk_bbk_niederlassung`), -KEY `fk_wochentag` (`fk_wochentag`), -KEY `ix_version` (`version`) -) DEFAULT CHARSET=latin1; -insert into t1 values -(1, 38, 1, '08:00:00', '13:00:00', 0, 1), -(2, 38, 2, '08:00:00', '13:00:00', 0, 1), -(3, 38, 3, '08:00:00', '13:00:00', 0, 1), -(4, 38, 4, '08:00:00', '13:00:00', 0, 1), -(5, 38, 5, '08:00:00', '13:00:00', 0, 1), -(6, 38, 5, '08:00:00', '13:00:00', 1, 2), -(7, 38, 3, '08:00:00', '13:00:00', 1, 2), -(8, 38, 1, '08:00:00', '13:00:00', 1, 2), -(9, 38, 2, '08:00:00', '13:00:00', 1, 2), -(10, 38, 4, '08:00:00', '13:00:00', 1, 2), -(11, 38, 1, '08:00:00', '13:00:00', 0, 3), -(12, 38, 2, '08:00:00', '13:00:00', 0, 3), -(13, 38, 3, '08:00:00', '13:00:00', 0, 3), -(14, 38, 4, '08:00:00', '13:00:00', 0, 3), -(15, 38, 5, '08:00:00', '13:00:00', 0, 3), -(16, 38, 4, '08:00:00', '13:00:00', 0, 4), -(17, 38, 5, '08:00:00', '13:00:00', 0, 4), -(18, 38, 1, '08:00:00', '13:00:00', 0, 4), -(19, 38, 2, '08:00:00', '13:00:00', 0, 4), -(20, 38, 3, '08:00:00', '13:00:00', 0, 4), -(21, 7, 1, '08:00:00', '13:00:00', 0, 1), -(22, 7, 2, '08:00:00', '13:00:00', 0, 1), -(23, 7, 3, '08:00:00', '13:00:00', 0, 1), -(24, 7, 4, '08:00:00', '13:00:00', 0, 1), -(25, 7, 5, '08:00:00', '13:00:00', 0, 1); -create view v1 as -select -zeit1.oid AS oid, -zeit1.fk_bbk_niederlassung AS fk_bbk_niederlassung, -zeit1.fk_wochentag AS fk_wochentag, -zeit1.uhrzeit_von AS uhrzeit_von, -zeit1.uhrzeit_bis AS uhrzeit_bis, -zeit1.geloescht AS geloescht, -zeit1.version AS version -from -t1 zeit1 -where -(zeit1.version = -(select max(zeit2.version) AS `max(version)` - from t1 zeit2 -where -((zeit1.fk_bbk_niederlassung = zeit2.fk_bbk_niederlassung) and -(zeit1.fk_wochentag = zeit2.fk_wochentag) and -(zeit1.uhrzeit_von = zeit2.uhrzeit_von) and -(zeit1.uhrzeit_bis = zeit2.uhrzeit_bis) -) -) -) -and (zeit1.geloescht = 0); -select * from v1 where oid = 21; -oid fk_bbk_niederlassung fk_wochentag uhrzeit_von uhrzeit_bis geloescht version -21 7 1 08:00:00 13:00:00 0 1 -drop view v1; -drop table t1; -CREATE TABLE t1( -t_cpac varchar(2) NOT NULL, -t_vers varchar(4) NOT NULL, -t_rele varchar(2) NOT NULL, -t_cust varchar(4) NOT NULL, -filler1 char(250) default NULL, -filler2 char(250) default NULL, -PRIMARY KEY (t_cpac,t_vers,t_rele,t_cust), -UNIQUE KEY IX_4 (t_cust,t_cpac,t_vers,t_rele), -KEY IX_5 (t_vers,t_rele,t_cust) -); -insert into t1 values -('tm','2.5 ','a ',' ','',''), ('tm','2.5U','a ','stnd','',''), -('da','3.3 ','b ',' ','',''), ('da','3.3U','b ','stnd','',''), -('tl','7.6 ','a ',' ','',''), ('tt','7.6 ','a ',' ','',''), -('bc','B61 ','a ',' ','',''), ('bp','B61 ','a ',' ','',''), -('ca','B61 ','a ',' ','',''), ('ci','B61 ','a ',' ','',''), -('cp','B61 ','a ',' ','',''), ('dm','B61 ','a ',' ','',''), -('ec','B61 ','a ',' ','',''), ('ed','B61 ','a ',' ','',''), -('fm','B61 ','a ',' ','',''), ('nt','B61 ','a ',' ','',''), -('qm','B61 ','a ',' ','',''), ('tc','B61 ','a ',' ','',''), -('td','B61 ','a ',' ','',''), ('tf','B61 ','a ',' ','',''), -('tg','B61 ','a ',' ','',''), ('ti','B61 ','a ',' ','',''), -('tp','B61 ','a ',' ','',''), ('ts','B61 ','a ',' ','',''), -('wh','B61 ','a ',' ','',''), ('bc','B61U','a ','stnd','',''), -('bp','B61U','a ','stnd','',''), ('ca','B61U','a ','stnd','',''), -('ci','B61U','a ','stnd','',''), ('cp','B61U','a ','stnd','',''), -('dm','B61U','a ','stnd','',''), ('ec','B61U','a ','stnd','',''), -('fm','B61U','a ','stnd','',''), ('nt','B61U','a ','stnd','',''), -('qm','B61U','a ','stnd','',''), ('tc','B61U','a ','stnd','',''), -('td','B61U','a ','stnd','',''), ('tf','B61U','a ','stnd','',''), -('tg','B61U','a ','stnd','',''), ('ti','B61U','a ','stnd','',''), -('tp','B61U','a ','stnd','',''), ('ts','B61U','a ','stnd','',''), -('wh','B61U','a ','stnd','',''); -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `t_cpac` varchar(2) NOT NULL, - `t_vers` varchar(4) NOT NULL, - `t_rele` varchar(2) NOT NULL, - `t_cust` varchar(4) NOT NULL, - `filler1` char(250) DEFAULT NULL, - `filler2` char(250) DEFAULT NULL, - PRIMARY KEY (`t_cpac`,`t_vers`,`t_rele`,`t_cust`), - UNIQUE KEY `IX_4` (`t_cust`,`t_cpac`,`t_vers`,`t_rele`), - KEY `IX_5` (`t_vers`,`t_rele`,`t_cust`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -select t_vers,t_rele,t_cust,filler1 from t1 where t_vers = '7.6'; -t_vers t_rele t_cust filler1 -7.6 a -7.6 a -select t_vers,t_rele,t_cust,filler1 from t1 where t_vers = '7.6' - and t_rele='a' and t_cust = ' '; -t_vers t_rele t_cust filler1 -7.6 a -7.6 a -drop table t1; -create table t1 ( -pk int(11) not null auto_increment, -a int(11) not null default '0', -b int(11) not null default '0', -c int(11) not null default '0', -filler1 datetime, filler2 varchar(15), -filler3 longtext, -kp1 varchar(4), kp2 varchar(7), -kp3 varchar(2), kp4 varchar(4), -kp5 varchar(7), -filler4 char(1), -primary key (pk), -key idx1(a,b,c), -key idx2(c), -key idx3(kp1,kp2,kp3,kp4,kp5) -) default charset=latin1; -set @fill=NULL; -SELECT COUNT(*) FROM t1 WHERE b = 0 AND a = 0 AND c = 13286427 AND -kp1='279' AND kp2='ELM0678' AND kp3='6' AND kp4='10' AND kp5 = 'R '; -COUNT(*) -1 -drop table t1; -# -# Bug#56423: Different count with SELECT and CREATE SELECT queries -# -CREATE TABLE t1 ( -a INT, -b INT, -c INT, -d INT, -PRIMARY KEY (a), -KEY (c), -KEY bd (b,d) -); -INSERT INTO t1 VALUES -(1, 0, 1, 0), -(2, 1, 1, 1), -(3, 1, 1, 1), -(4, 0, 1, 1); -EXPLAIN -SELECT a -FROM t1 -WHERE c = 1 AND b = 1 AND d = 1; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref c,bd bd 10 const,const 2 Using where -CREATE TABLE t2 ( a INT ) -SELECT a -FROM t1 -WHERE c = 1 AND b = 1 AND d = 1; -SELECT * FROM t2; -a -2 -3 -DROP TABLE t1, t2; -CREATE TABLE t1( a INT, b INT, KEY(a), KEY(b) ); -INSERT INTO t1 VALUES (1, 2), (1, 2), (1, 2), (1, 2); -SELECT * FROM t1 FORCE INDEX(a, b) WHERE a = 1 AND b = 2; -a b -1 2 -1 2 -1 2 -1 2 -DROP TABLE t1; -# Code coverage of fix. -CREATE TABLE t1 ( a INT NOT NULL AUTO_INCREMENT PRIMARY KEY, b INT); -INSERT INTO t1 (b) VALUES (1); -UPDATE t1 SET b = 2 WHERE a = 1; -SELECT * FROM t1; -a b -1 2 -CREATE TABLE t2 ( a INT NOT NULL AUTO_INCREMENT PRIMARY KEY, b VARCHAR(1) ); -INSERT INTO t2 (b) VALUES ('a'); -UPDATE t2 SET b = 'b' WHERE a = 1; -SELECT * FROM t2; -a b -1 b -DROP TABLE t1, t2; #---------------- 2-sweeps read Index merge test 2 ------------------------------- SET SESSION STORAGE_ENGINE = InnoDB; drop table if exists t1; diff --git a/mysql-test/t/index_merge_innodb.test b/mysql-test/t/index_merge_innodb.test index a188648d41f..10d772797a2 100644 --- a/mysql-test/t/index_merge_innodb.test +++ b/mysql-test/t/index_merge_innodb.test @@ -22,9 +22,9 @@ let $index_merge_random_rows_in_EXPLAIN = 1; let $merge_table_support= 0; # -- [DISABLED Bug#45727] - --source include/index_merge1.inc - --source include/index_merge_ror.inc - --source include/index_merge2.inc +# --source include/index_merge1.inc +# --source include/index_merge_ror.inc +# --source include/index_merge2.inc --source include/index_merge_2sweeps.inc --source include/index_merge_ror_cpk.inc From d0250efa7c7103f6583884f6a2ad0f259bd129c2 Mon Sep 17 00:00:00 2001 From: Jimmy Yang Date: Thu, 3 Nov 2011 04:07:00 -0700 Subject: [PATCH 064/288] Fix Bug #12941439 - WITH UNIV_SYNC_DEBUG, PERF SCHEMA, INITIALIZATION OF 16G BUFFER POOL TAKES HOURS rb://787 approved by Sunny --- storage/innobase/buf/buf0buf.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/storage/innobase/buf/buf0buf.c b/storage/innobase/buf/buf0buf.c index 30f37a2f89a..1fcc2107f18 100644 --- a/storage/innobase/buf/buf0buf.c +++ b/storage/innobase/buf/buf0buf.c @@ -839,6 +839,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++; } @@ -895,17 +905,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 */ } /********************************************************************//** From 40f42cac72a93c0836373619ed1344a5c38faf13 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Thu, 3 Nov 2011 15:57:18 +0100 Subject: [PATCH 065/288] Bug #13096353 62712: RPM-BASED INSTALL OF THE TEST SUITE IS USELESS FOR NON-ROOT USERS Simplified fix avoiding changes to mysys: Use the MY_HOLD_ORIGINAL_MODES flag when calling my_copy(), this also stops it from attempting to chown() the file. Yes this behavior is a bit confusing.... The only case this might change the behavior is if the destination file exists, but since we also use MY_DONT_OVERWRITE_FILE, it would fail in those cases anyway. --- client/mysqltest.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/mysqltest.cc b/client/mysqltest.cc index f0184e5297b..30aa50da2ad 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -3344,8 +3344,9 @@ void do_copy_file(struct st_command *command) ' '); DBUG_PRINT("info", ("Copy %s to %s", ds_from_file.str, ds_to_file.str)); + /* MY_HOLD_ORIGINAL_MODES prevents attempts to chown the file */ error= (my_copy(ds_from_file.str, ds_to_file.str, - MYF(MY_DONT_OVERWRITE_FILE)) != 0); + MYF(MY_DONT_OVERWRITE_FILE | MY_HOLD_ORIGINAL_MODES)) != 0); handle_command_error(command, error); dynstr_free(&ds_from_file); dynstr_free(&ds_to_file); From d946b1d3689349e7593407411ca609002accf976 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 4 Nov 2011 08:59:28 -0400 Subject: [PATCH 066/288] WL#5710 : mysql_plugin client - Windows PB fix This patch corrects the test mysql_plugin so that it correctly masks the library extension of the plugin daemon_example. --- mysql-test/t/mysql_plugin.test | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mysql-test/t/mysql_plugin.test b/mysql-test/t/mysql_plugin.test index 897e22ddd62..c5968df85f8 100644 --- a/mysql-test/t/mysql_plugin.test +++ b/mysql-test/t/mysql_plugin.test @@ -142,8 +142,11 @@ EOF --echo # Simulate loading a plugin libary with multiple entry points. --echo # This will test the DISABLE to ensure all rows are removed. --echo # +--replace_regex /\.dll/.so/ eval INSERT INTO mysql.plugin VALUES ('wicky', '$DAEMONEXAMPLE'); +--replace_regex /\.dll/.so/ eval INSERT INTO mysql.plugin VALUES ('wacky', '$DAEMONEXAMPLE'); +--replace_regex /\.dll/.so/ eval INSERT INTO mysql.plugin VALUES ('wonky', '$DAEMONEXAMPLE'); --echo # From 6852a3264248dd12939a47d4eee8492a4f0c83a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 7 Nov 2011 09:28:02 +0200 Subject: [PATCH 067/288] Bug#13340047 LATCHING ORDER VIOLATION IN IBUF_SET_ENTRY_COUNTER() ibuf_insert_low(), the only caller of ibuf_set_entry_counter(), will have latched an insert buffer bitmap page in bitmap_mtr before invoking ibuf_set_entry_counter(). The latching order forbids any further pages to be latched. ibuf_set_entry_counter(): Renamed to ibuf_get_entry_counter(), simplified the code and added comments. Added the following symbols for predefined field numbers in change buffer records: #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 */ rb:802 approved by Sunny Bains --- storage/innobase/ibuf/ibuf0ibuf.c | 317 ++++++++++++------------------ 1 file changed, 128 insertions(+), 189 deletions(-) diff --git a/storage/innobase/ibuf/ibuf0ibuf.c b/storage/innobase/ibuf/ibuf0ibuf.c index 0676a7be0f7..91c9c227907 100644 --- a/storage/innobase/ibuf/ibuf0ibuf.c +++ b/storage/innobase/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. */ /* @{ */ @@ -1233,13 +1242,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); @@ -1279,13 +1288,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)); @@ -1335,9 +1344,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; @@ -1363,7 +1372,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; @@ -1407,7 +1417,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 */ @@ -1436,12 +1446,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) { @@ -1666,7 +1676,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 */ @@ -1678,13 +1688,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); @@ -1698,7 +1708,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); @@ -1745,7 +1756,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; } @@ -1806,7 +1817,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) { @@ -1829,7 +1840,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); @@ -1859,7 +1871,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); @@ -1914,11 +1927,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); @@ -1928,7 +1941,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); @@ -1940,7 +1953,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); @@ -1988,10 +2001,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); @@ -2024,13 +2034,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); } @@ -2090,11 +2100,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); @@ -2104,7 +2114,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); @@ -2114,7 +2124,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); @@ -2122,7 +2132,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); } @@ -2789,8 +2799,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; @@ -2842,8 +2854,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 @@ -2852,7 +2864,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)) { @@ -3164,7 +3176,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); @@ -3186,10 +3198,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( @@ -3210,7 +3224,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 */ @@ -3223,7 +3237,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) { @@ -3232,7 +3246,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) { @@ -3241,7 +3255,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: @@ -3257,147 +3271,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); } /*********************************************************************//** @@ -3604,16 +3532,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( + dfield_get_data(field) + IBUF_REC_OFFSET_COUNTER, + counter); } /* Set the bitmap bit denoting that the insert buffer contains From b003b6294c7d2f7cf918ed76b5380ee0439dc7e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 7 Nov 2011 13:37:19 +0200 Subject: [PATCH 068/288] Add debug assertions to catch Bug#13345378 earlier. In all callers of row_sel_convert_mysql_key_to_innobase(), assert that the converted key is empty or nonempty when it should be. --- storage/innobase/handler/ha_innodb.cc | 8 ++++++++ storage/innodb_plugin/handler/ha_innodb.cc | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 2d230e1c297..3e3db33e588 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -4713,6 +4713,7 @@ ha_innobase::index_read( index, (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 */ @@ -6168,6 +6169,7 @@ ha_innobase::records_in_range( void* heap2; DBUG_ENTER("records_in_range"); + DBUG_ASSERT(min_key || max_key); ut_a(prebuilt->trx == thd_to_trx(ha_thd())); @@ -6198,6 +6200,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, @@ -6206,6 +6211,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); diff --git a/storage/innodb_plugin/handler/ha_innodb.cc b/storage/innodb_plugin/handler/ha_innodb.cc index fc1193e55bb..35b2dcec23c 100644 --- a/storage/innodb_plugin/handler/ha_innodb.cc +++ b/storage/innodb_plugin/handler/ha_innodb.cc @@ -5428,6 +5428,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 */ @@ -7226,6 +7227,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())); @@ -7271,6 +7273,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, @@ -7279,6 +7284,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); From 941a6640aa8f17e8d364061eb382bbd264363ad2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 8 Nov 2011 08:54:52 +0200 Subject: [PATCH 069/288] Replace void pointer arithmetics with byte pointer arithmetics. --- storage/innobase/ibuf/ibuf0ibuf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/storage/innobase/ibuf/ibuf0ibuf.c b/storage/innobase/ibuf/ibuf0ibuf.c index 91c9c227907..47ec1365cb8 100644 --- a/storage/innobase/ibuf/ibuf0ibuf.c +++ b/storage/innobase/ibuf/ibuf0ibuf.c @@ -3551,8 +3551,8 @@ bitmap_fail: field = dtuple_get_nth_field( ibuf_entry, IBUF_REC_FIELD_METADATA); mach_write_to_2( - dfield_get_data(field) + IBUF_REC_OFFSET_COUNTER, - counter); + (byte*) dfield_get_data(field) + + IBUF_REC_OFFSET_COUNTER, counter); } /* Set the bitmap bit denoting that the insert buffer contains From 77eb01b82776dc222da1543dc2d20295156a123d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 8 Nov 2011 14:15:22 +0200 Subject: [PATCH 070/288] Bug#13358468 ASSERTION FAILURE IN BTR_PCUR_GET_BLOCK btr_pcur_restore_position_func(): When the cursor was positioned at the tree infimum or supremum, initialize pos_state and latch_mode. The assertion failed, because pos_state was BTR_PCUR_WAS_POSITIONED. In the test failure of WL#5874, the purge thread attempted to restore the cursor position on the infimum record (the clustered index was empty). btr_pcur_detach(), btr_pcur_is_detached(): Unused functions, remove. rb:804 approved by Inaam Rana --- storage/innodb_plugin/ChangeLog | 7 ++++- storage/innodb_plugin/btr/btr0pcur.c | 2 ++ storage/innodb_plugin/include/btr0pcur.h | 8 ------ storage/innodb_plugin/include/btr0pcur.ic | 32 ----------------------- 4 files changed, 8 insertions(+), 41 deletions(-) diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index 5a4ef5fa4ef..f7d01cd6773 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,7 +1,12 @@ +2011-11-08 The InnoDB Team + + * btr/btr0pcur.c, include/btr0pcur.h, include/btr0pcur.ic: + Fix Bug#13358468 ASSERTION FAILURE IN BTR_PCUR_GET_BLOCK + 2011-10-27 The InnoDB Team * row/row0mysql.c: - Fix Bug #12884631 62146: TABLES ARE LOST FOR DDL + Fix Bug#12884631 62146: TABLES ARE LOST FOR DDL 2011-10-20 The InnoDB Team diff --git a/storage/innodb_plugin/btr/btr0pcur.c b/storage/innodb_plugin/btr/btr0pcur.c index cbb0d21a7ed..57d9752649f 100644 --- a/storage/innodb_plugin/btr/btr0pcur.c +++ b/storage/innodb_plugin/btr/btr0pcur.c @@ -247,6 +247,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/storage/innodb_plugin/include/btr0pcur.h b/storage/innodb_plugin/include/btr0pcur.h index f59514d04b3..40ecc77dcd1 100644 --- a/storage/innodb_plugin/include/btr0pcur.h +++ b/storage/innodb_plugin/include/btr0pcur.h @@ -279,14 +279,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/storage/innodb_plugin/include/btr0pcur.ic b/storage/innodb_plugin/include/btr0pcur.ic index 0f9b969e7c5..f49e155f97e 100644 --- a/storage/innodb_plugin/include/btr0pcur.ic +++ b/storage/innodb_plugin/include/btr0pcur.ic @@ -415,38 +415,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 From 020600a4ed6af27798173a3f62b5e6786c4b9ea3 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Tue, 8 Nov 2011 15:55:25 +0100 Subject: [PATCH 071/288] Bug #13055685 NO WAY TO REPLACE NON-DETERMINISTIC FRAGMENTS IN OUTPUT OF MTR'S ECHO Don't do this for echo, instead: 1) Enable replacements also for assignment from backquoted SQL 2) Allow replace_regex to take a variable for the *entire* argument list With this, the test can be amended, but only in its version in trunk --- client/mysqltest.cc | 77 +++++++++++++++++++++++------------ mysql-test/r/mysqltest.result | 6 +++ mysql-test/t/mysqltest.test | 23 +++++++++++ 3 files changed, 79 insertions(+), 27 deletions(-) diff --git a/client/mysqltest.cc b/client/mysqltest.cc index 30aa50da2ad..1bd5d5941e5 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -502,6 +502,31 @@ struct st_command *curr_command= 0; char builtin_echo[FN_REFLEN]; +struct st_replace_regex +{ +DYNAMIC_ARRAY regex_arr; /* stores a list of st_regex subsitutions */ + +/* +Temporary storage areas for substitutions. To reduce unnessary copying +and memory freeing/allocation, we pre-allocate two buffers, and alternate +their use, one for input/one for output, the roles changing on the next +st_regex substition. At the end of substitutions buf points to the +one containing the final result. +*/ +char* buf; +char* even_buf; +char* odd_buf; +int even_buf_len; +int odd_buf_len; +}; + +struct st_replace_regex *glob_replace_regex= 0; + +struct st_replace; +struct st_replace *glob_replace= 0; +void replace_strings_append(struct st_replace *rep, DYNAMIC_STRING* ds, +const char *from, int len); + static void cleanup_and_exit(int exit_code) __attribute__((noreturn)); void die(const char *fmt, ...) @@ -531,6 +556,7 @@ void str_to_file2(const char *fname, char *str, int size, my_bool append); void fix_win_paths(const char *val, int len); const char *get_errname_from_code (uint error_code); +int multi_reg_replace(struct st_replace_regex* r,char* val); #ifdef __WIN__ void free_tmp_sh_file(); @@ -2432,7 +2458,23 @@ void var_query_set(VAR *var, const char *query, const char** query_end) if (row[i]) { /* Add column to tab separated string */ - dynstr_append_mem(&result, row[i], lengths[i]); + char *val= row[i]; + int len= lengths[i]; + + if (glob_replace_regex) + { + /* Regex replace */ + if (!multi_reg_replace(glob_replace_regex, (char*)val)) + { + val= glob_replace_regex->buf; + len= strlen(val); + } + } + + if (glob_replace) + replace_strings_append(glob_replace, &result, val, len); + else + dynstr_append_mem(&result, val, len); } dynstr_append_mem(&result, "\t", 1); } @@ -9120,16 +9162,11 @@ typedef struct st_pointer_array { /* when using array-strings */ uint array_allocs,max_count,length,max_length; } POINTER_ARRAY; -struct st_replace; struct st_replace *init_replace(char * *from, char * *to, uint count, char * word_end_chars); int insert_pointer_name(reg1 POINTER_ARRAY *pa,char * name); -void replace_strings_append(struct st_replace *rep, DYNAMIC_STRING* ds, - const char *from, int len); void free_pointer_array(POINTER_ARRAY *pa); -struct st_replace *glob_replace; - /* Get arguments for replace. The syntax is: replace from to [from to ...] @@ -9273,26 +9310,6 @@ struct st_regex int icase; /* true if the match is case insensitive */ }; -struct st_replace_regex -{ - DYNAMIC_ARRAY regex_arr; /* stores a list of st_regex subsitutions */ - - /* - Temporary storage areas for substitutions. To reduce unnessary copying - and memory freeing/allocation, we pre-allocate two buffers, and alternate - their use, one for input/one for output, the roles changing on the next - st_regex substition. At the end of substitutions buf points to the - one containing the final result. - */ - char* buf; - char* even_buf; - char* odd_buf; - int even_buf_len; - int odd_buf_len; -}; - -struct st_replace_regex *glob_replace_regex= 0; - int reg_replace(char** buf_p, int* buf_len_p, char *pattern, char *replace, char *string, int icase); @@ -9491,7 +9508,13 @@ void do_get_replace_regex(struct st_command *command) { char *expr= command->first_argument; free_replace_regex(); - if (!(glob_replace_regex=init_replace_regex(expr))) + /* Allow variable for the *entire* list of replacements */ + if (*expr == '$') + { + VAR *val= var_get(expr, NULL, 0, 1); + expr= val ? val->str_val : NULL; + } + if (expr && *expr && !(glob_replace_regex=init_replace_regex(expr))) die("Could not init replace_regex"); command->last_argument= command->end; } diff --git a/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result index a0456c65f53..82069ebedaf 100644 --- a/mysql-test/r/mysqltest.result +++ b/mysql-test/r/mysqltest.result @@ -549,6 +549,7 @@ mysqltest: At line 1: Wrong column number to replace_column in 'replace_column 1 select "LONG_STRING" as x; x LONG_STRING +dog mysqltest: At line 1: Invalid integer argument "10!" mysqltest: At line 1: Invalid integer argument "a" mysqltest: At line 1: Missing required argument 'connection name' to command 'connect' @@ -662,6 +663,11 @@ a D 1 1 1 4 drop table t1; +y +txt +b is b and more is more +txt +a is a and less is more create table t2 ( a char(10)); garbage; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'garbage' at line 1 diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test index 11ab79458d7..86ee7ccc1fa 100644 --- a/mysql-test/t/mysqltest.test +++ b/mysql-test/t/mysqltest.test @@ -1745,6 +1745,12 @@ let $long_rep= $long_rep,$long_rep; --replace_result $long_rep LONG_STRING eval select "$long_rep" as x; +# Test replace within `` + +--replace_result cat dog +--let $animal= `select "cat" as pet` +--echo $animal + # ---------------------------------------------------------------------------- # Test sync_with_master # ---------------------------------------------------------------------------- @@ -2065,6 +2071,23 @@ insert into t1 values (2,4); select * from t1; drop table t1; +# Test usage with `` + +--replace_regex /x/y/ +--let $result= `select "x" as col` +--echo $result + +# Test usage with a variable as pattern list + +--disable_query_log +--let $patt= /a /b / /less/more/ +--replace_regex $patt +select "a is a and less is more" as txt; +--let $patt= +--replace_regex $patt +select "a is a and less is more" as txt; +--enable_query_log + #------------------------------------------------------------------------- # BUG #11754855 : Passing variable to --error #------------------------------------------------------------------------- From ef97f0ae46b81dec6371fd9a6819239101bafd48 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Wed, 9 Nov 2011 09:58:18 +0100 Subject: [PATCH 072/288] Followup test fix after 13055685: Un-needed replace_result accidentally messed up a variable used *if* not running parallel. Removed the bogus --replace_result --- mysql-test/extra/binlog_tests/ctype_ucs_binlog.test | 1 - 1 file changed, 1 deletion(-) diff --git a/mysql-test/extra/binlog_tests/ctype_ucs_binlog.test b/mysql-test/extra/binlog_tests/ctype_ucs_binlog.test index b240109f6e6..733ad05b0be 100644 --- a/mysql-test/extra/binlog_tests/ctype_ucs_binlog.test +++ b/mysql-test/extra/binlog_tests/ctype_ucs_binlog.test @@ -15,7 +15,6 @@ source include/show_binlog_events.inc; # absolutely need variables names to be quoted and strings to be # escaped). flush logs; ---replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR let $MYSQLD_DATADIR= `select @@datadir`; --exec $MYSQL_BINLOG --short-form $MYSQLD_DATADIR/master-bin.000001 drop table t2; From b61c2e0b764232374bc81eaa9179f3e32d262a5d Mon Sep 17 00:00:00 2001 From: Sneha Modi Date: Thu, 10 Nov 2011 12:04:23 +0530 Subject: [PATCH 073/288] Bug#11754170:45729: TEST CASE FOR BUG#28211 IS DISABLED IN QUERY_CACHE.TEST A patch for this bug has already been pushed. A minor change is made here. The database to be used after re-enabling the disabled code is 'TEST'. But instead, 'MYSQL' was being used. This is the minor change that is being made here. --- mysql-test/r/query_cache.result | 8 ++++---- mysql-test/t/query_cache.test | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/query_cache.result b/mysql-test/r/query_cache.result index 9e7f427502b..8132f3e9e0a 100644 --- a/mysql-test/r/query_cache.result +++ b/mysql-test/r/query_cache.result @@ -1615,7 +1615,7 @@ use db3; create table t1(c1 int) engine=myisam; use db1; insert into t1(c1) values (1); -use mysql; +use test; select * from db1.t1; c1 1 @@ -1661,7 +1661,7 @@ c1 2 SHOW STATUS LIKE 'Qcache_hits'; Variable_name Value -Qcache_hits 0 +Qcache_hits 1 DROP TABLE t1; SET GLOBAL concurrent_insert= @save_concurrent_insert; SET GLOBAL query_cache_size= default; @@ -1691,7 +1691,7 @@ a COMMIT; SHOW STATUS LIKE 'Qcache_queries_in_cache'; Variable_name Value -Qcache_queries_in_cache 0 +Qcache_queries_in_cache 2 SHOW STATUS LIKE "Qcache_hits"; Variable_name Value Qcache_hits 0 @@ -1713,7 +1713,7 @@ a COMMIT; SHOW STATUS LIKE "Qcache_hits"; Variable_name Value -Qcache_hits 0 +Qcache_hits 2 DROP TABLE t1; SET GLOBAL query_cache_size= default; End of 5.0 tests diff --git a/mysql-test/t/query_cache.test b/mysql-test/t/query_cache.test index caf57f343eb..49a8817fe6b 100644 --- a/mysql-test/t/query_cache.test +++ b/mysql-test/t/query_cache.test @@ -1224,7 +1224,7 @@ show status like 'Qcache_free_blocks'; create table t1(c1 int) engine=myisam; use db1; insert into t1(c1) values (1); - use mysql; + use test; select * from db1.t1; select c1+1 from db1.t1; select * from db3.t1; From cdb19df7619a37c3bfe2702d4050dd2a60196927 Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Thu, 10 Nov 2011 10:43:34 +0400 Subject: [PATCH 074/288] BUG#11763882 - 56652: VALGRIND WARNINGS FOR MEMORY LEAK IN ALTER TABLE AND/OR PLUGIN/SEMISYNC If a plugin was uninstalled, thread local values for plugin variables of string type with PLUGIN_VAR_MEMALLOC flag were not freed. With this patch these variables are freed when thread is done (like all other variables). sql/sql_class.h: Added variable which stores memory hunks allocated for PLUGIN_VAR_MEMALLOC values. sql/sql_plugin.cc: Normally all memory allocated for dynamic variables values must be freed by cleanup_variables(). But if a plugin was uninstalled, descriptors of it's system variables are lost. Still some memory may be occupied for thread local values. It is ok for most kinds of variables, as they're stored on dynamic_variables_ptr and freed when thread is done. Values for PLUGIN_VAR_MEMALLOC variables are stored separately. These lost values are handled by plugin_var_memalloc_free(). --- sql/sql_class.h | 5 +- sql/sql_plugin.cc | 207 ++++++++++++++++++++++++++++++++++++---------- 2 files changed, 167 insertions(+), 45 deletions(-) diff --git a/sql/sql_class.h b/sql/sql_class.h index 1a51b66f8a6..36091546ff4 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -410,8 +410,9 @@ typedef struct system_variables */ ulong dynamic_variables_version; char* dynamic_variables_ptr; - uint dynamic_variables_head; /* largest valid variable offset */ - uint dynamic_variables_size; /* how many bytes are in use */ + uint dynamic_variables_head; /* largest valid variable offset */ + uint dynamic_variables_size; /* how many bytes are in use */ + LIST *dynamic_variables_allocs; /* memory hunks for PLUGIN_VAR_MEMALLOC */ ulonglong max_heap_table_size; ulonglong tmp_table_size; diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 5f5e73091ff..2b801b65a09 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -255,6 +255,13 @@ static bool register_builtin(struct st_mysql_plugin *, struct st_plugin_int *, static void unlock_variables(THD *thd, struct system_variables *vars); static void cleanup_variables(THD *thd, struct system_variables *vars); static void plugin_vars_free_values(sys_var *vars); +static bool plugin_var_memalloc_session_update(THD *thd, + struct st_mysql_sys_var *var, + char **dest, const char *value); +static bool plugin_var_memalloc_global_update(THD *thd, + struct st_mysql_sys_var *var, + char **dest, const char *value); +static void plugin_var_memalloc_free(struct system_variables *vars); static void restore_pluginvar_names(sys_var *first); static void plugin_opt_set_limits(struct my_option *, const struct st_mysql_sys_var *); @@ -2300,13 +2307,7 @@ static void update_func_longlong(THD *thd, struct st_mysql_sys_var *var, static void update_func_str(THD *thd, struct st_mysql_sys_var *var, void *tgt, const void *save) { - char *old= *(char **) tgt; - *(char **)tgt= *(char **) save; - if (var->flags & PLUGIN_VAR_MEMALLOC) - { - *(char **)tgt= my_strdup(*(char **) save, MYF(0)); - my_free(old); - } + *(char **) tgt= *(char **) save; } @@ -2565,11 +2566,13 @@ static uchar *intern_sys_var_ptr(THD* thd, int offset, bool global_lock) if ((pi->plugin_var->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR && pi->plugin_var->flags & PLUGIN_VAR_MEMALLOC) { - char **pp= (char**) (thd->variables.dynamic_variables_ptr + - *(int*)(pi->plugin_var + 1)); - if ((*pp= *(char**) (global_system_variables.dynamic_variables_ptr + - *(int*)(pi->plugin_var + 1)))) - *pp= my_strdup(*pp, MYF(MY_WME|MY_FAE)); + int varoff= *(int *) (pi->plugin_var + 1); + char **thdvar= (char **) (thd->variables. + dynamic_variables_ptr + varoff); + char **sysvar= (char **) (global_system_variables. + dynamic_variables_ptr + varoff); + *thdvar= NULL; + plugin_var_memalloc_session_update(thd, NULL, thdvar, *sysvar); } } @@ -2675,33 +2678,8 @@ static void unlock_variables(THD *thd, struct system_variables *vars) */ static void cleanup_variables(THD *thd, struct system_variables *vars) { - st_bookmark *v; - sys_var_pluginvar *pivar; - sys_var *var; - int flags; - uint idx; - - mysql_rwlock_rdlock(&LOCK_system_variables_hash); - for (idx= 0; idx < bookmark_hash.records; idx++) - { - v= (st_bookmark*) my_hash_element(&bookmark_hash, idx); - if (v->version > vars->dynamic_variables_version || - !(var= intern_find_sys_var(v->key + 1, v->name_len)) || - !(pivar= var->cast_pluginvar()) || - v->key[0] != (pivar->plugin_var->flags & PLUGIN_VAR_TYPEMASK)) - continue; - - flags= pivar->plugin_var->flags; - - if ((flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR && - flags & PLUGIN_VAR_THDLOCAL && flags & PLUGIN_VAR_MEMALLOC) - { - char **ptr= (char**) pivar->real_value_ptr(thd, OPT_SESSION); - my_free(*ptr); - *ptr= NULL; - } - } - mysql_rwlock_unlock(&LOCK_system_variables_hash); + if (thd) + plugin_var_memalloc_free(&thd->variables); DBUG_ASSERT(vars->table_plugin == NULL); @@ -2796,6 +2774,136 @@ static SHOW_TYPE pluginvar_show_type(st_mysql_sys_var *plugin_var) } +/** + Set value for thread local variable with PLUGIN_VAR_MEMALLOC flag. + + @param[in] thd Thread context. + @param[in] var Plugin variable. + @param[in,out] dest Destination memory pointer. + @param[in] value '\0'-terminated new value. + + Most plugin variable values are stored on dynamic_variables_ptr. + Releasing memory occupied by these values is as simple as freeing + dynamic_variables_ptr. + + An exception to the rule are PLUGIN_VAR_MEMALLOC variables, which + are stored on individual memory hunks. All of these hunks has to + be freed when it comes to cleanup. + + It may happen that a plugin was uninstalled and descriptors of + it's variables are lost. In this case it is impossible to locate + corresponding values. + + In addition to allocating and setting variable value, new element + is added to dynamic_variables_allocs list. When thread is done, it + has to call plugin_var_memalloc_free() to release memory used by + PLUGIN_VAR_MEMALLOC variables. + + If var is NULL, variable update function is not called. This is + needed when we take snapshot of system variables during thread + initialization. + + @note List element and variable value are stored on the same memory + hunk. List element is followed by variable value. + + @return Completion status + @retval false Success + @retval true Failure +*/ + +static bool plugin_var_memalloc_session_update(THD *thd, + struct st_mysql_sys_var *var, + char **dest, const char *value) + +{ + LIST *old_element= NULL; + struct system_variables *vars= &thd->variables; + DBUG_ENTER("plugin_var_memalloc_session_update"); + + if (value) + { + size_t length= strlen(value) + 1; + LIST *element; + if (!(element= (LIST *) my_malloc(sizeof(LIST) + length, MYF(MY_WME)))) + DBUG_RETURN(true); + memcpy(element + 1, value, length); + value= (const char *) (element + 1); + vars->dynamic_variables_allocs= list_add(vars->dynamic_variables_allocs, + element); + } + + if (*dest) + old_element= (LIST *) (*dest - sizeof(LIST)); + + if (var) + var->update(thd, var, (void **) dest, (const void *) &value); + else + *dest= (char *) value; + + if (old_element) + { + vars->dynamic_variables_allocs= list_delete(vars->dynamic_variables_allocs, + old_element); + my_free(old_element); + } + DBUG_RETURN(false); +} + + +/** + Free all elements allocated by plugin_var_memalloc_session_update(). + + @param[in] vars system variables structure + + @see plugin_var_memalloc_session_update +*/ + +static void plugin_var_memalloc_free(struct system_variables *vars) +{ + LIST *next, *root; + DBUG_ENTER("plugin_var_memalloc_free"); + for (root= vars->dynamic_variables_allocs; root; root= next) + { + next= root->next; + my_free(root); + } + vars->dynamic_variables_allocs= NULL; + DBUG_VOID_RETURN; +} + + +/** + Set value for global variable with PLUGIN_VAR_MEMALLOC flag. + + @param[in] thd Thread context. + @param[in] var Plugin variable. + @param[in,out] dest Destination memory pointer. + @param[in] value '\0'-terminated new value. + + @return Completion status + @retval false Success + @retval true Failure +*/ + +static bool plugin_var_memalloc_global_update(THD *thd, + struct st_mysql_sys_var *var, + char **dest, const char *value) +{ + char *old_value= *dest; + DBUG_ENTER("plugin_var_memalloc_global_update"); + + if (value && !(value= my_strdup(value, MYF(MY_WME)))) + DBUG_RETURN(true); + + var->update(thd, var, (void **) dest, (const void *) &value); + + if (old_value) + my_free(old_value); + + DBUG_RETURN(false); +} + + bool sys_var_pluginvar::check_update_type(Item_result type) { switch (plugin_var->flags & PLUGIN_VAR_TYPEMASK) { @@ -2880,6 +2988,7 @@ bool sys_var_pluginvar::do_check(THD *thd, set_var *var) bool sys_var_pluginvar::session_update(THD *thd, set_var *var) { + bool rc= false; DBUG_ASSERT(!is_readonly()); DBUG_ASSERT(plugin_var->flags & PLUGIN_VAR_THDLOCAL); DBUG_ASSERT(thd == current_thd); @@ -2889,13 +2998,20 @@ bool sys_var_pluginvar::session_update(THD *thd, set_var *var) const void *src= var->value ? (void*)&var->save_result : (void*)real_value_ptr(thd, OPT_GLOBAL); mysql_mutex_unlock(&LOCK_global_system_variables); - plugin_var->update(thd, plugin_var, tgt, src); - return false; + if ((plugin_var->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR && + plugin_var->flags & PLUGIN_VAR_MEMALLOC) + rc= plugin_var_memalloc_session_update(thd, plugin_var, (char **) tgt, + *(const char **) src); + else + plugin_var->update(thd, plugin_var, tgt, src); + + return rc; } bool sys_var_pluginvar::global_update(THD *thd, set_var *var) { + bool rc= false; DBUG_ASSERT(!is_readonly()); mysql_mutex_assert_owner(&LOCK_global_system_variables); @@ -2952,9 +3068,14 @@ bool sys_var_pluginvar::global_update(THD *thd, set_var *var) } } - plugin_var->update(thd, plugin_var, tgt, src); + if ((plugin_var->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR && + plugin_var->flags & PLUGIN_VAR_MEMALLOC) + rc= plugin_var_memalloc_global_update(thd, plugin_var, (char **) tgt, + *(const char **) src); + else + plugin_var->update(thd, plugin_var, tgt, src); - return false; + return rc; } From a0a51251e49365cc0f256a2ebc90994dbe0d9a95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 10 Nov 2011 12:49:31 +0200 Subject: [PATCH 075/288] Bug#11759688 52020: InnoDB can still deadlock on just INSERT...ON DUPLICATE KEY a.k.a. Bug#7975 deadlock without any locking, simple select and update Bug#7975 was reintroduced when the storage engine API was made pluggable in MySQL 5.1. Instead of looking at thd->lex directly, we rely on handler::extra(). But, we were looking at the wrong extra() flag, and we were ignoring the TRX_DUP_REPLACE flag in places where we should obey it. innodb_replace.test: Add tests for hopefully all affected statement types, so that bug should never ever resurface. This kind of tests should have been added when fixing Bug#7975 in MySQL 5.0.3 in the first place. rb:806 approved by Sunny Bains --- .../suite/innodb/r/innodb_replace.result | 77 ++++++++ mysql-test/suite/innodb/t/innodb_replace.test | 186 ++++++++++++++++++ .../innodb_plugin/r/innodb_replace.result | 77 ++++++++ .../suite/innodb_plugin/t/innodb_replace.test | 186 ++++++++++++++++++ sql/sql_insert.cc | 5 + storage/innobase/handler/ha_innodb.cc | 16 +- storage/innobase/row/row0ins.c | 6 +- storage/innodb_plugin/ChangeLog | 7 + storage/innodb_plugin/handler/ha_innodb.cc | 16 +- storage/innodb_plugin/row/row0ins.c | 8 +- 10 files changed, 559 insertions(+), 25 deletions(-) create mode 100644 mysql-test/suite/innodb/r/innodb_replace.result create mode 100644 mysql-test/suite/innodb/t/innodb_replace.test create mode 100644 mysql-test/suite/innodb_plugin/r/innodb_replace.result create mode 100644 mysql-test/suite/innodb_plugin/t/innodb_replace.test diff --git a/mysql-test/suite/innodb/r/innodb_replace.result b/mysql-test/suite/innodb/r/innodb_replace.result new file mode 100644 index 00000000000..30009b8ddc9 --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_replace.result @@ -0,0 +1,77 @@ +# +#Bug#11759688 52020: InnoDB can still deadlock +#on just INSERT...ON DUPLICATE KEY +#a.k.a. Bug#7975 deadlock without any locking, simple select and update +# +CREATE TABLE t1 (a INT PRIMARY KEY, b INT NOT NULL) ENGINE=InnoDB; +INSERT INTO t1 VALUES(3,1); +BEGIN; +SET DEBUG_SYNC='write_row_noreplace SIGNAL insert1 WAIT_FOR select1'; +INSERT INTO t1 VALUES(3,2); +SET DEBUG_SYNC='now WAIT_FOR insert1'; +SELECT * FROM t1 LOCK IN SHARE MODE; +a b +3 1 +SELECT * FROM t1 FOR UPDATE; +SET DEBUG_SYNC='now SIGNAL select1'; +ERROR 23000: Duplicate entry '3' for key 'PRIMARY' +INSERT INTO t1 VALUES(3,3) ON DUPLICATE KEY UPDATE b=b+10; +ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +COMMIT; +SET DEBUG_SYNC='write_row_replace SIGNAL insert2 WAIT_FOR select2'; +REPLACE INTO t1 VALUES(3,4); +SET DEBUG_SYNC='now WAIT_FOR insert2'; +SELECT * FROM t1; +a b +3 11 +SELECT * FROM t1 LOCK IN SHARE MODE; +SET DEBUG_SYNC='now SIGNAL select2'; +SET DEBUG_SYNC='write_row_replace SIGNAL insert3 WAIT_FOR select3'; +INSERT INTO t1 VALUES(3,5) ON DUPLICATE KEY UPDATE b=b+20; +a b +3 4 +SET DEBUG_SYNC='now WAIT_FOR insert3'; +SELECT b FROM t1 LOCK IN SHARE MODE; +SET DEBUG_SYNC='now SIGNAL select3'; +b +24 +SET DEBUG_SYNC='write_row_noreplace SIGNAL insert4 WAIT_FOR select4'; +LOAD DATA INFILE '../../std_data/loaddata5.dat' INTO TABLE t1 FIELDS TERMINATED BY '' ENCLOSED BY '' (a, b); +SET DEBUG_SYNC='now WAIT_FOR insert4'; +SELECT b FROM t1 WHERE a=3 LOCK IN SHARE MODE; +b +24 +SELECT b FROM t1 WHERE a=3 FOR UPDATE; +SET DEBUG_SYNC='now SIGNAL select4'; +b +24 +ERROR 23000: Duplicate entry '3' for key 'PRIMARY' +SET DEBUG_SYNC='write_row_noreplace SIGNAL insert5 WAIT_FOR select5'; +LOAD DATA INFILE '../../std_data/loaddata5.dat' IGNORE INTO TABLE t1 FIELDS TERMINATED BY '' ENCLOSED BY '' (a, b); +SET DEBUG_SYNC='now WAIT_FOR insert5'; +SELECT * FROM t1; +a b +3 24 +SELECT * FROM t1 WHERE a=3 LOCK IN SHARE MODE; +a b +3 24 +SELECT * FROM t1 WHERE a=3 FOR UPDATE; +SET DEBUG_SYNC='now SIGNAL select5'; +a b +3 24 +SET DEBUG_SYNC='write_row_replace SIGNAL insert6 WAIT_FOR select6'; +LOAD DATA INFILE '../../std_data/loaddata5.dat' REPLACE INTO TABLE t1 FIELDS TERMINATED BY '' ENCLOSED BY '' (a, b); +SET DEBUG_SYNC='now WAIT_FOR insert6'; +SELECT * FROM t1; +a b +1 2 +3 24 +5 6 +SELECT a,b FROM t1 LOCK IN SHARE MODE; +SET DEBUG_SYNC='now SIGNAL select6'; +a b +1 2 +3 4 +5 6 +SET DEBUG_SYNC='RESET'; +DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/innodb_replace.test b/mysql-test/suite/innodb/t/innodb_replace.test new file mode 100644 index 00000000000..a35f423c85e --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_replace.test @@ -0,0 +1,186 @@ +--source include/have_innodb.inc +--source include/have_debug_sync.inc + +--echo # +--echo #Bug#11759688 52020: InnoDB can still deadlock +--echo #on just INSERT...ON DUPLICATE KEY +--echo #a.k.a. Bug#7975 deadlock without any locking, simple select and update +--echo # + +CREATE TABLE t1 (a INT PRIMARY KEY, b INT NOT NULL) ENGINE=InnoDB; + +INSERT INTO t1 VALUES(3,1); + +connect (con1,localhost,root,,); +connect (con2,localhost,root,,); +connection con1; + +BEGIN; +# normal INSERT of a duplicate should only S-lock the existing record (3,1) +SET DEBUG_SYNC='write_row_noreplace SIGNAL insert1 WAIT_FOR select1'; +--send +INSERT INTO t1 VALUES(3,2); + +connection default; +SET DEBUG_SYNC='now WAIT_FOR insert1'; +# this should S-lock (3,1); no conflict +SELECT * FROM t1 LOCK IN SHARE MODE; +# this should X-lock (3,1), conflicting with con1 +--send +SELECT * FROM t1 FOR UPDATE; + +connection con2; +# Check that the above SELECT is blocked +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = 'Sending data' and + info = 'SELECT * FROM t1 FOR UPDATE'; +--source include/wait_condition.inc +SET DEBUG_SYNC='now SIGNAL select1'; + +connection con1; +--error ER_DUP_ENTRY +reap; +# We are still holding an S-lock on (3,1) after the failed INSERT. +# The following will upgrade it to an X-lock, causing a deadlock. +# InnoDB should resolve the deadlock by aborting the blocked SELECT. +INSERT INTO t1 VALUES(3,3) ON DUPLICATE KEY UPDATE b=b+10; + +connection default; +--error ER_LOCK_DEADLOCK +reap; +connection con1; +COMMIT; + +SET DEBUG_SYNC='write_row_replace SIGNAL insert2 WAIT_FOR select2'; +--send +REPLACE INTO t1 VALUES(3,4); + +connection default; +SET DEBUG_SYNC='now WAIT_FOR insert2'; +SELECT * FROM t1; +--send +SELECT * FROM t1 LOCK IN SHARE MODE; + +connection con2; +# Check that the above SELECT is blocked because of X lock. +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = 'Sending data' and + info = 'SELECT * FROM t1 LOCK IN SHARE MODE'; +--source include/wait_condition.inc +SET DEBUG_SYNC='now SIGNAL select2'; + +connection con1; +reap; + +SET DEBUG_SYNC='write_row_replace SIGNAL insert3 WAIT_FOR select3'; +--send +INSERT INTO t1 VALUES(3,5) ON DUPLICATE KEY UPDATE b=b+20; + +connection default; +reap; +SET DEBUG_SYNC='now WAIT_FOR insert3'; +--send +SELECT b FROM t1 LOCK IN SHARE MODE; + +connection con2; +# Check that the above SELECT is blocked because of X lock. +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = 'Sending data' and + info = 'SELECT b FROM t1 LOCK IN SHARE MODE'; +--source include/wait_condition.inc +SET DEBUG_SYNC='now SIGNAL select3'; + +connection default; +reap; + +connection con1; +reap; +SET DEBUG_SYNC='write_row_noreplace SIGNAL insert4 WAIT_FOR select4'; +--send +LOAD DATA INFILE '../../std_data/loaddata5.dat' INTO TABLE t1 FIELDS TERMINATED BY '' ENCLOSED BY '' (a, b); + +connection default; +SET DEBUG_SYNC='now WAIT_FOR insert4'; +# this should S-lock (3,1); no conflict +SELECT b FROM t1 WHERE a=3 LOCK IN SHARE MODE; +# this should X-lock (3,1), conflicting with con1 +--send +SELECT b FROM t1 WHERE a=3 FOR UPDATE; + +connection con2; +# Check that the above SELECT is blocked +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = 'statistics' and + info = 'SELECT b FROM t1 WHERE a=3 FOR UPDATE'; +--source include/wait_condition.inc +SET DEBUG_SYNC='now SIGNAL select4'; + +connection default; +reap; + +connection con1; +--error ER_DUP_ENTRY +reap; +SET DEBUG_SYNC='write_row_noreplace SIGNAL insert5 WAIT_FOR select5'; +--send +LOAD DATA INFILE '../../std_data/loaddata5.dat' IGNORE INTO TABLE t1 FIELDS TERMINATED BY '' ENCLOSED BY '' (a, b); + +connection default; +SET DEBUG_SYNC='now WAIT_FOR insert5'; +SELECT * FROM t1; +# this should S-lock; no conflict +SELECT * FROM t1 WHERE a=3 LOCK IN SHARE MODE; +# this should X-lock, conflicting with the S-lock of the IGNORE in con1 +--send +SELECT * FROM t1 WHERE a=3 FOR UPDATE; + +connection con2; +# Check that the above SELECT is blocked +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = 'statistics' and + info = 'SELECT * FROM t1 WHERE a=3 FOR UPDATE'; +--source include/wait_condition.inc +SET DEBUG_SYNC='now SIGNAL select5'; + +connection con1; +reap; +connection default; +reap; + +connection con1; +SET DEBUG_SYNC='write_row_replace SIGNAL insert6 WAIT_FOR select6'; +--send +LOAD DATA INFILE '../../std_data/loaddata5.dat' REPLACE INTO TABLE t1 FIELDS TERMINATED BY '' ENCLOSED BY '' (a, b); + +connection default; +SET DEBUG_SYNC='now WAIT_FOR insert6'; +SELECT * FROM t1; +# this should conflict with the X-lock acquired by the REPLACE +--send +SELECT a,b FROM t1 LOCK IN SHARE MODE; + +connection con2; +# Check that the above SELECT is blocked +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = 'Sending data' and + info = 'SELECT a,b FROM t1 LOCK IN SHARE MODE'; +--source include/wait_condition.inc +SET DEBUG_SYNC='now SIGNAL select6'; + +connection con1; +reap; +connection default; +reap; + +disconnect con1; +disconnect con2; + +connection default; +SET DEBUG_SYNC='RESET'; +DROP TABLE t1; diff --git a/mysql-test/suite/innodb_plugin/r/innodb_replace.result b/mysql-test/suite/innodb_plugin/r/innodb_replace.result new file mode 100644 index 00000000000..30009b8ddc9 --- /dev/null +++ b/mysql-test/suite/innodb_plugin/r/innodb_replace.result @@ -0,0 +1,77 @@ +# +#Bug#11759688 52020: InnoDB can still deadlock +#on just INSERT...ON DUPLICATE KEY +#a.k.a. Bug#7975 deadlock without any locking, simple select and update +# +CREATE TABLE t1 (a INT PRIMARY KEY, b INT NOT NULL) ENGINE=InnoDB; +INSERT INTO t1 VALUES(3,1); +BEGIN; +SET DEBUG_SYNC='write_row_noreplace SIGNAL insert1 WAIT_FOR select1'; +INSERT INTO t1 VALUES(3,2); +SET DEBUG_SYNC='now WAIT_FOR insert1'; +SELECT * FROM t1 LOCK IN SHARE MODE; +a b +3 1 +SELECT * FROM t1 FOR UPDATE; +SET DEBUG_SYNC='now SIGNAL select1'; +ERROR 23000: Duplicate entry '3' for key 'PRIMARY' +INSERT INTO t1 VALUES(3,3) ON DUPLICATE KEY UPDATE b=b+10; +ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +COMMIT; +SET DEBUG_SYNC='write_row_replace SIGNAL insert2 WAIT_FOR select2'; +REPLACE INTO t1 VALUES(3,4); +SET DEBUG_SYNC='now WAIT_FOR insert2'; +SELECT * FROM t1; +a b +3 11 +SELECT * FROM t1 LOCK IN SHARE MODE; +SET DEBUG_SYNC='now SIGNAL select2'; +SET DEBUG_SYNC='write_row_replace SIGNAL insert3 WAIT_FOR select3'; +INSERT INTO t1 VALUES(3,5) ON DUPLICATE KEY UPDATE b=b+20; +a b +3 4 +SET DEBUG_SYNC='now WAIT_FOR insert3'; +SELECT b FROM t1 LOCK IN SHARE MODE; +SET DEBUG_SYNC='now SIGNAL select3'; +b +24 +SET DEBUG_SYNC='write_row_noreplace SIGNAL insert4 WAIT_FOR select4'; +LOAD DATA INFILE '../../std_data/loaddata5.dat' INTO TABLE t1 FIELDS TERMINATED BY '' ENCLOSED BY '' (a, b); +SET DEBUG_SYNC='now WAIT_FOR insert4'; +SELECT b FROM t1 WHERE a=3 LOCK IN SHARE MODE; +b +24 +SELECT b FROM t1 WHERE a=3 FOR UPDATE; +SET DEBUG_SYNC='now SIGNAL select4'; +b +24 +ERROR 23000: Duplicate entry '3' for key 'PRIMARY' +SET DEBUG_SYNC='write_row_noreplace SIGNAL insert5 WAIT_FOR select5'; +LOAD DATA INFILE '../../std_data/loaddata5.dat' IGNORE INTO TABLE t1 FIELDS TERMINATED BY '' ENCLOSED BY '' (a, b); +SET DEBUG_SYNC='now WAIT_FOR insert5'; +SELECT * FROM t1; +a b +3 24 +SELECT * FROM t1 WHERE a=3 LOCK IN SHARE MODE; +a b +3 24 +SELECT * FROM t1 WHERE a=3 FOR UPDATE; +SET DEBUG_SYNC='now SIGNAL select5'; +a b +3 24 +SET DEBUG_SYNC='write_row_replace SIGNAL insert6 WAIT_FOR select6'; +LOAD DATA INFILE '../../std_data/loaddata5.dat' REPLACE INTO TABLE t1 FIELDS TERMINATED BY '' ENCLOSED BY '' (a, b); +SET DEBUG_SYNC='now WAIT_FOR insert6'; +SELECT * FROM t1; +a b +1 2 +3 24 +5 6 +SELECT a,b FROM t1 LOCK IN SHARE MODE; +SET DEBUG_SYNC='now SIGNAL select6'; +a b +1 2 +3 4 +5 6 +SET DEBUG_SYNC='RESET'; +DROP TABLE t1; diff --git a/mysql-test/suite/innodb_plugin/t/innodb_replace.test b/mysql-test/suite/innodb_plugin/t/innodb_replace.test new file mode 100644 index 00000000000..f052edd1d24 --- /dev/null +++ b/mysql-test/suite/innodb_plugin/t/innodb_replace.test @@ -0,0 +1,186 @@ +--source include/have_innodb_plugin.inc +--source include/have_debug_sync.inc + +--echo # +--echo #Bug#11759688 52020: InnoDB can still deadlock +--echo #on just INSERT...ON DUPLICATE KEY +--echo #a.k.a. Bug#7975 deadlock without any locking, simple select and update +--echo # + +CREATE TABLE t1 (a INT PRIMARY KEY, b INT NOT NULL) ENGINE=InnoDB; + +INSERT INTO t1 VALUES(3,1); + +connect (con1,localhost,root,,); +connect (con2,localhost,root,,); +connection con1; + +BEGIN; +# normal INSERT of a duplicate should only S-lock the existing record (3,1) +SET DEBUG_SYNC='write_row_noreplace SIGNAL insert1 WAIT_FOR select1'; +--send +INSERT INTO t1 VALUES(3,2); + +connection default; +SET DEBUG_SYNC='now WAIT_FOR insert1'; +# this should S-lock (3,1); no conflict +SELECT * FROM t1 LOCK IN SHARE MODE; +# this should X-lock (3,1), conflicting with con1 +--send +SELECT * FROM t1 FOR UPDATE; + +connection con2; +# Check that the above SELECT is blocked +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = 'Sending data' and + info = 'SELECT * FROM t1 FOR UPDATE'; +--source include/wait_condition.inc +SET DEBUG_SYNC='now SIGNAL select1'; + +connection con1; +--error ER_DUP_ENTRY +reap; +# We are still holding an S-lock on (3,1) after the failed INSERT. +# The following will upgrade it to an X-lock, causing a deadlock. +# InnoDB should resolve the deadlock by aborting the blocked SELECT. +INSERT INTO t1 VALUES(3,3) ON DUPLICATE KEY UPDATE b=b+10; + +connection default; +--error ER_LOCK_DEADLOCK +reap; +connection con1; +COMMIT; + +SET DEBUG_SYNC='write_row_replace SIGNAL insert2 WAIT_FOR select2'; +--send +REPLACE INTO t1 VALUES(3,4); + +connection default; +SET DEBUG_SYNC='now WAIT_FOR insert2'; +SELECT * FROM t1; +--send +SELECT * FROM t1 LOCK IN SHARE MODE; + +connection con2; +# Check that the above SELECT is blocked because of X lock. +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = 'Sending data' and + info = 'SELECT * FROM t1 LOCK IN SHARE MODE'; +--source include/wait_condition.inc +SET DEBUG_SYNC='now SIGNAL select2'; + +connection con1; +reap; + +SET DEBUG_SYNC='write_row_replace SIGNAL insert3 WAIT_FOR select3'; +--send +INSERT INTO t1 VALUES(3,5) ON DUPLICATE KEY UPDATE b=b+20; + +connection default; +reap; +SET DEBUG_SYNC='now WAIT_FOR insert3'; +--send +SELECT b FROM t1 LOCK IN SHARE MODE; + +connection con2; +# Check that the above SELECT is blocked because of X lock. +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = 'Sending data' and + info = 'SELECT b FROM t1 LOCK IN SHARE MODE'; +--source include/wait_condition.inc +SET DEBUG_SYNC='now SIGNAL select3'; + +connection default; +reap; + +connection con1; +reap; +SET DEBUG_SYNC='write_row_noreplace SIGNAL insert4 WAIT_FOR select4'; +--send +LOAD DATA INFILE '../../std_data/loaddata5.dat' INTO TABLE t1 FIELDS TERMINATED BY '' ENCLOSED BY '' (a, b); + +connection default; +SET DEBUG_SYNC='now WAIT_FOR insert4'; +# this should S-lock (3,1); no conflict +SELECT b FROM t1 WHERE a=3 LOCK IN SHARE MODE; +# this should X-lock (3,1), conflicting with con1 +--send +SELECT b FROM t1 WHERE a=3 FOR UPDATE; + +connection con2; +# Check that the above SELECT is blocked +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = 'statistics' and + info = 'SELECT b FROM t1 WHERE a=3 FOR UPDATE'; +--source include/wait_condition.inc +SET DEBUG_SYNC='now SIGNAL select4'; + +connection default; +reap; + +connection con1; +--error ER_DUP_ENTRY +reap; +SET DEBUG_SYNC='write_row_noreplace SIGNAL insert5 WAIT_FOR select5'; +--send +LOAD DATA INFILE '../../std_data/loaddata5.dat' IGNORE INTO TABLE t1 FIELDS TERMINATED BY '' ENCLOSED BY '' (a, b); + +connection default; +SET DEBUG_SYNC='now WAIT_FOR insert5'; +SELECT * FROM t1; +# this should S-lock; no conflict +SELECT * FROM t1 WHERE a=3 LOCK IN SHARE MODE; +# this should X-lock, conflicting with the S-lock of the IGNORE in con1 +--send +SELECT * FROM t1 WHERE a=3 FOR UPDATE; + +connection con2; +# Check that the above SELECT is blocked +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = 'statistics' and + info = 'SELECT * FROM t1 WHERE a=3 FOR UPDATE'; +--source include/wait_condition.inc +SET DEBUG_SYNC='now SIGNAL select5'; + +connection con1; +reap; +connection default; +reap; + +connection con1; +SET DEBUG_SYNC='write_row_replace SIGNAL insert6 WAIT_FOR select6'; +--send +LOAD DATA INFILE '../../std_data/loaddata5.dat' REPLACE INTO TABLE t1 FIELDS TERMINATED BY '' ENCLOSED BY '' (a, b); + +connection default; +SET DEBUG_SYNC='now WAIT_FOR insert6'; +SELECT * FROM t1; +# this should conflict with the X-lock acquired by the REPLACE +--send +SELECT a,b FROM t1 LOCK IN SHARE MODE; + +connection con2; +# Check that the above SELECT is blocked +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = 'Sending data' and + info = 'SELECT a,b FROM t1 LOCK IN SHARE MODE'; +--source include/wait_condition.inc +SET DEBUG_SYNC='now SIGNAL select6'; + +connection con1; +reap; +connection default; +reap; + +disconnect con1; +disconnect con2; + +connection default; +SET DEBUG_SYNC='RESET'; +DROP TABLE t1; diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index e176e5c9b6d..4cd456829ba 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -63,6 +63,8 @@ #include "slave.h" #include "rpl_mi.h" +#include "debug_sync.h" + #ifndef EMBEDDED_LIBRARY static bool delayed_get_table(THD *thd, TABLE_LIST *table_list); static int write_delayed(THD *thd, TABLE *table, enum_duplicates duplic, @@ -1411,6 +1413,8 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) error= HA_ERR_FOUND_DUPP_KEY; /* Database can't find key */ goto err; } + DEBUG_SYNC(thd, "write_row_replace"); + /* Read all columns for the row we are going to replace */ table->use_all_columns(); /* @@ -1604,6 +1608,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) } else if ((error=table->file->ha_write_row(table->record[0]))) { + DEBUG_SYNC(thd, "write_row_noreplace"); if (!info->ignore || table->file->is_fatal_error(error, HA_CHECK_DUP)) goto err; diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 3e3db33e588..7f82959dffd 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -4087,8 +4087,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; } @@ -4364,8 +4363,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; @@ -7099,6 +7097,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; @@ -7116,19 +7115,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 */ ; } diff --git a/storage/innobase/row/row0ins.c b/storage/innobase/row/row0ins.c index 6366beb6b47..c18b6995066 100644 --- a/storage/innobase/row/row0ins.c +++ b/storage/innobase/row/row0ins.c @@ -1674,7 +1674,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 */ @@ -1814,7 +1814,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 @@ -1856,7 +1856,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/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index f7d01cd6773..a7c9c6e3212 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,3 +1,10 @@ +2011-11-10 The InnoDB Team + + * handler/ha_innodb.cc, row/row0ins.c, innodb_replace.test: + Fix Bug#11759688 52020: InnoDB can still deadlock + on just INSERT...ON DUPLICATE KEY a.k.a. the reintroduction of + Bug#7975 deadlock without any locking, simple select and update + 2011-11-08 The InnoDB Team * btr/btr0pcur.c, include/btr0pcur.h, include/btr0pcur.ic: diff --git a/storage/innodb_plugin/handler/ha_innodb.cc b/storage/innodb_plugin/handler/ha_innodb.cc index 35b2dcec23c..5ed4abe3d08 100644 --- a/storage/innodb_plugin/handler/ha_innodb.cc +++ b/storage/innodb_plugin/handler/ha_innodb.cc @@ -4793,8 +4793,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; } @@ -5069,8 +5068,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; @@ -8423,6 +8421,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; @@ -8440,19 +8439,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 */ ; } diff --git a/storage/innodb_plugin/row/row0ins.c b/storage/innodb_plugin/row/row0ins.c index 0f158cdc706..b14ae3de2bd 100644 --- a/storage/innodb_plugin/row/row0ins.c +++ b/storage/innodb_plugin/row/row0ins.c @@ -1662,7 +1662,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]; @@ -1693,7 +1693,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 */ @@ -1827,7 +1827,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 @@ -1871,7 +1871,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 From a9150f00078064c9c4eaca0329ad6e3c16d7ec4c Mon Sep 17 00:00:00 2001 From: Sneha Modi Date: Thu, 10 Nov 2011 17:18:41 +0530 Subject: [PATCH 076/288] Bug#11748731 - 37248: SOME 'BIG' TESTS FAILING ON 6.0: alter_treable-big.test was failing due to the use of RAND() function which is no more replication safe. This has been modified using static values. Also, 'sleep' has been replaced using 'debug_sync' and the execution time of the test has been reduced significantly. This test is now taken out of the disabled.def file and is being enabled. --- mysql-test/r/alter_table-big.result | 44 ++++++++---- mysql-test/t/alter_table-big.test | 106 +++++++++++++++++++++------- mysql-test/t/disabled.def | 1 - 3 files changed, 112 insertions(+), 39 deletions(-) diff --git a/mysql-test/r/alter_table-big.result b/mysql-test/r/alter_table-big.result index d6b936bd5d7..33af60938a1 100644 --- a/mysql-test/r/alter_table-big.result +++ b/mysql-test/r/alter_table-big.result @@ -1,57 +1,77 @@ drop table if exists t1, t2; +set debug_sync='RESET'; create table t1 (n1 int, n2 int, n3 int, key (n1, n2, n3), key (n2, n3, n1), key (n3, n1, n2)); create table t2 (i int); alter table t1 disable keys; -insert into t1 values (RAND()*1000, RAND()*1000, RAND()*1000); +insert into t1 values (1, 2, 3); reset master; -set session debug="+d,sleep_alter_enable_indexes"; +set debug_sync='alter_table_enable_indexes SIGNAL parked WAIT_FOR go'; alter table t1 enable keys;; +set debug_sync='now WAIT_FOR parked'; insert into t2 values (1); -insert into t1 values (1, 1, 1); -set session debug="-d,sleep_alter_enable_indexes"; +insert into t1 values (1, 1, 1);; +set debug_sync='now SIGNAL go'; show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; insert into t2 values (1) +master-bin.000001 # Query # # COMMIT master-bin.000001 # Query # # use `test`; alter table t1 enable keys +master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; insert into t1 values (1, 1, 1) +master-bin.000001 # Query # # COMMIT drop tables t1, t2; +set debug_sync='RESET'; End of 5.0 tests drop table if exists t1, t2, t3; create table t1 (i int); reset master; -set session debug="+d,sleep_alter_before_main_binlog"; +set debug_sync='alter_table_before_main_binlog SIGNAL parked WAIT_FOR go'; alter table t1 change i c char(10) default 'Test1';; -insert into t1 values (); +set debug_sync='now WAIT_FOR parked'; +insert into t1 values ();; +set debug_sync='now SIGNAL go'; select * from t1; c Test1 +set debug_sync='alter_table_before_main_binlog SIGNAL parked WAIT_FOR go'; alter table t1 change c vc varchar(100) default 'Test2';; -rename table t1 to t2; +set debug_sync='now WAIT_FOR parked'; +rename table t1 to t2;; +set debug_sync='now SIGNAL go'; drop table t2; create table t1 (i int); +set debug_sync='alter_table_before_main_binlog SIGNAL parked WAIT_FOR go'; alter table t1 change i c char(10) default 'Test3', rename to t2;; -insert into t2 values (); +set debug_sync='now WAIT_FOR parked'; +insert into t2 values();; +set debug_sync='now SIGNAL go'; select * from t2; c Test3 alter table t2 change c vc varchar(100) default 'Test2', rename to t1;; rename table t1 to t3; drop table t3; -set session debug="-d,sleep_alter_before_main_binlog"; +set debug_sync='alter_table_before_main_binlog SIGNAL parked WAIT_FOR go'; +set debug_sync='RESET'; show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # use `test`; alter table t1 change i c char(10) default 'Test1' +master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; insert into t1 values () +master-bin.000001 # Query # # COMMIT master-bin.000001 # Query # # use `test`; alter table t1 change c vc varchar(100) default 'Test2' master-bin.000001 # Query # # use `test`; rename table t1 to t2 -master-bin.000001 # Query # # use `test`; drop table t2 +master-bin.000001 # Query # # use `test`; DROP TABLE `t2` /* generated by server */ master-bin.000001 # Query # # use `test`; create table t1 (i int) master-bin.000001 # Query # # use `test`; alter table t1 change i c char(10) default 'Test3', rename to t2 -master-bin.000001 # Query # # use `test`; insert into t2 values () +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; insert into t2 values() +master-bin.000001 # Query # # COMMIT master-bin.000001 # Query # # use `test`; alter table t2 change c vc varchar(100) default 'Test2', rename to t1 master-bin.000001 # Query # # use `test`; rename table t1 to t3 -master-bin.000001 # Query # # use `test`; drop table t3 +master-bin.000001 # Query # # use `test`; DROP TABLE `t3` /* generated by server */ End of 5.1 tests diff --git a/mysql-test/t/alter_table-big.test b/mysql-test/t/alter_table-big.test index e007a3a55e0..b010815955f 100644 --- a/mysql-test/t/alter_table-big.test +++ b/mysql-test/t/alter_table-big.test @@ -18,7 +18,10 @@ --disable_warnings drop table if exists t1, t2; --enable_warnings +set debug_sync='RESET'; + connect (addconroot, localhost, root,,); +connect (addconroot2, localhost, root,,); connection default; create table t1 (n1 int, n2 int, n3 int, key (n1, n2, n3), @@ -26,38 +29,45 @@ create table t1 (n1 int, n2 int, n3 int, key (n3, n1, n2)); create table t2 (i int); -# Starting from 5.1 we have runtime settable @@debug variable, -# which can be used for introducing delays at certain points of -# statement execution, so we don't need many rows in 't1' to make -# this test repeatable. alter table t1 disable keys; ---disable_warnings -insert into t1 values (RAND()*1000, RAND()*1000, RAND()*1000); ---enable_warnings +insert into t1 values (1, 2, 3); # Later we use binlog to check the order in which statements are # executed so let us reset it first. reset master; -set session debug="+d,sleep_alter_enable_indexes"; +set debug_sync='alter_table_enable_indexes SIGNAL parked WAIT_FOR go'; --send alter table t1 enable keys; connection addconroot; ---sleep 2 +# Wait until ALTER TABLE acquires metadata lock. +set debug_sync='now WAIT_FOR parked'; # This statement should not be blocked by in-flight ALTER and therefore # should be executed and written to binlog before ALTER TABLE ... ENABLE KEYS # finishes. insert into t2 values (1); # And this should wait until the end of ALTER TABLE ... ENABLE KEYS. -insert into t1 values (1, 1, 1); +--send insert into t1 values (1, 1, 1); +connection addconroot2; +# Wait until the above INSERT INTO t1 is blocked due to ALTER +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Waiting for table metadata lock" and + info = "insert into t1 values (1, 1, 1)"; +--source include/wait_condition.inc +# Resume ALTER execution. +set debug_sync='now SIGNAL go'; connection default; --reap -set session debug="-d,sleep_alter_enable_indexes"; +connection addconroot; +--reap +connection default; # Check that statements were executed/binlogged in correct order. source include/show_binlog_events.inc; # Clean up drop tables t1, t2; disconnect addconroot; - +disconnect addconroot2; +set debug_sync='RESET'; --echo End of 5.0 tests @@ -72,48 +82,92 @@ disconnect addconroot; --disable_warnings drop table if exists t1, t2, t3; --enable_warnings +connect (addconroot, localhost, root,,); +connect (addconroot2, localhost, root,,); +connection default; create table t1 (i int); # We are going to check that statements are logged in correct order reset master; -set session debug="+d,sleep_alter_before_main_binlog"; +set debug_sync='alter_table_before_main_binlog SIGNAL parked WAIT_FOR go'; --send alter table t1 change i c char(10) default 'Test1'; -connect (addconroot, localhost, root,,); connection addconroot; ---sleep 2 -insert into t1 values (); -select * from t1; +# Wait until ALTER TABLE acquires metadata lock. +set debug_sync='now WAIT_FOR parked'; +--send insert into t1 values (); +connection addconroot2; +# Wait until the above INSERT INTO t1 is blocked due to ALTER +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Waiting for table metadata lock" and + info = "insert into t1 values ()"; +--source include/wait_condition.inc +# Resume ALTER execution. +set debug_sync='now SIGNAL go'; connection default; --reap +connection addconroot; +--reap +connection default; +select * from t1; +set debug_sync='alter_table_before_main_binlog SIGNAL parked WAIT_FOR go'; --send alter table t1 change c vc varchar(100) default 'Test2'; connection addconroot; ---sleep 2 -rename table t1 to t2; +# Wait until ALTER TABLE acquires metadata lock. +set debug_sync='now WAIT_FOR parked'; +--send rename table t1 to t2; +connection addconroot2; +# Wait until the above RENAME TABLE is blocked due to ALTER +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Waiting for table metadata lock" and + info = "rename table t1 to t2"; +--source include/wait_condition.inc +# Resume ALTER execution. +set debug_sync='now SIGNAL go'; connection default; --reap +connection addconroot; +--reap +connection default; drop table t2; # And now tests for ALTER TABLE with RENAME clause. In this # case target table name should be properly locked as well. create table t1 (i int); +set debug_sync='alter_table_before_main_binlog SIGNAL parked WAIT_FOR go'; --send alter table t1 change i c char(10) default 'Test3', rename to t2; connection addconroot; ---sleep 2 -insert into t2 values (); -select * from t2; +# Wait until ALTER TABLE acquires metadata lock. +set debug_sync='now WAIT_FOR parked'; +--send insert into t2 values(); +connection addconroot2; +# Wait until the above INSERT INTO t2 is blocked due to ALTER +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Waiting for table metadata lock" and + info = "insert into t2 values()"; +--source include/wait_condition.inc +# Resume ALTER execution. +set debug_sync='now SIGNAL go'; connection default; --reap +connection addconroot; +--reap +connection default; +select * from t2; --send alter table t2 change c vc varchar(100) default 'Test2', rename to t1; connection addconroot; ---sleep 2 -rename table t1 to t3; connection default; --reap +rename table t1 to t3; + disconnect addconroot; +disconnect addconroot2; drop table t3; -set session debug="-d,sleep_alter_before_main_binlog"; +set debug_sync='alter_table_before_main_binlog SIGNAL parked WAIT_FOR go'; +set debug_sync='RESET'; # Check that all statements were logged in correct order source include/show_binlog_events.inc; --echo End of 5.1 tests - diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index 08db85a3f45..cb1de2cb0ff 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -12,7 +12,6 @@ lowercase_table3 : Bug#11762269 2010-06-30 alik main.lowercase_table3 on Mac OSX read_many_rows_innodb : Bug#11748886 2010-11-15 mattiasj report already exists sum_distinct-big : Bug#11764126 2010-11-15 mattiasj was not tested -alter_table-big : Bug#11748731 2010-11-15 mattiasj was not tested create-big : Bug#11748731 2010-11-15 mattiasj was not tested archive-big : Bug#11817185 2011-03-10 Anitha Disabled since this leads to timeout on Solaris Sparc log_tables-big : Bug#11756699 2010-11-15 mattiasj report already exists From 8c886b3bc0002ce5c14f9ffc9c0df4d2664b032d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 10 Nov 2011 16:45:47 +0200 Subject: [PATCH 077/288] Bug #12842206 INNODB LOCKING REGRESSION FOR INSERT IGNORE: Add a test case. The bug was accidentally fixed by fixing Bug#11759688 52020: InnoDB can still deadlock on just INSERT...ON DUPLICATE KEY a.k.a. the reintroduction of Bug#7975 deadlock without any locking, simple select and update --- mysql-test/suite/innodb/r/innodb-lock.result | 17 ++++++++ mysql-test/suite/innodb/t/innodb-lock.test | 41 +++++++++++++++++++ .../suite/innodb_plugin/r/innodb-lock.result | 17 ++++++++ .../suite/innodb_plugin/t/innodb-lock.test | 41 +++++++++++++++++++ 4 files changed, 116 insertions(+) diff --git a/mysql-test/suite/innodb/r/innodb-lock.result b/mysql-test/suite/innodb/r/innodb-lock.result index 4ace4065c34..5881d4c80b3 100644 --- a/mysql-test/suite/innodb/r/innodb-lock.result +++ b/mysql-test/suite/innodb/r/innodb-lock.result @@ -55,3 +55,20 @@ id x 1 1 2 10 drop table t1; +# +#Bug#12842206 INNODB LOCKING REGRESSION FOR INSERT IGNORE +#fixed by re-fixing Bug#7975 +#aka Bug#11759688 52020: InnoDB can still deadlock on just INSERT... +# +CREATE TABLE t1 (a INT PRIMARY KEY, b INT NOT NULL) ENGINE=InnoDB; +INSERT INTO t1 VALUES(3,1); +BEGIN; +INSERT IGNORE INTO t1 VALUES(3,14); +BEGIN; +INSERT IGNORE INTO t1 VALUES(3,23); +SELECT * FROM t1 FOR UPDATE; +COMMIT; +a b +3 1 +COMMIT; +DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/innodb-lock.test b/mysql-test/suite/innodb/t/innodb-lock.test index eacf7e562be..8e4dd80e07e 100644 --- a/mysql-test/suite/innodb/t/innodb-lock.test +++ b/mysql-test/suite/innodb/t/innodb-lock.test @@ -100,3 +100,44 @@ select * from t1; drop table t1; # End of 4.1 tests + +--echo # +--echo #Bug#12842206 INNODB LOCKING REGRESSION FOR INSERT IGNORE +--echo #fixed by re-fixing Bug#7975 +--echo #aka Bug#11759688 52020: InnoDB can still deadlock on just INSERT... +--echo # + +connection default; +CREATE TABLE t1 (a INT PRIMARY KEY, b INT NOT NULL) ENGINE=InnoDB; + +INSERT INTO t1 VALUES(3,1); + +BEGIN; +# this used to wrongly acquire an X lock; now it takes an S lock +INSERT IGNORE INTO t1 VALUES(3,14); + +connection con1; +BEGIN; +# this used to wrongly acquire an X lock; now it takes an S lock +INSERT IGNORE INTO t1 VALUES(3,23); +--send +SELECT * FROM t1 FOR UPDATE; + +connection con2; +# Check that the above SELECT is blocked +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = 'Sending data' and + info = 'SELECT * FROM t1 FOR UPDATE'; +--source include/wait_condition.inc + +connection default; +COMMIT; +connection con1; +reap; +COMMIT; +disconnect con1; +disconnect con2; + +connection default; +DROP TABLE t1; diff --git a/mysql-test/suite/innodb_plugin/r/innodb-lock.result b/mysql-test/suite/innodb_plugin/r/innodb-lock.result index 4ace4065c34..5881d4c80b3 100644 --- a/mysql-test/suite/innodb_plugin/r/innodb-lock.result +++ b/mysql-test/suite/innodb_plugin/r/innodb-lock.result @@ -55,3 +55,20 @@ id x 1 1 2 10 drop table t1; +# +#Bug#12842206 INNODB LOCKING REGRESSION FOR INSERT IGNORE +#fixed by re-fixing Bug#7975 +#aka Bug#11759688 52020: InnoDB can still deadlock on just INSERT... +# +CREATE TABLE t1 (a INT PRIMARY KEY, b INT NOT NULL) ENGINE=InnoDB; +INSERT INTO t1 VALUES(3,1); +BEGIN; +INSERT IGNORE INTO t1 VALUES(3,14); +BEGIN; +INSERT IGNORE INTO t1 VALUES(3,23); +SELECT * FROM t1 FOR UPDATE; +COMMIT; +a b +3 1 +COMMIT; +DROP TABLE t1; diff --git a/mysql-test/suite/innodb_plugin/t/innodb-lock.test b/mysql-test/suite/innodb_plugin/t/innodb-lock.test index 20467236b1c..2198c02efb0 100644 --- a/mysql-test/suite/innodb_plugin/t/innodb-lock.test +++ b/mysql-test/suite/innodb_plugin/t/innodb-lock.test @@ -100,3 +100,44 @@ select * from t1; drop table t1; # End of 4.1 tests + +--echo # +--echo #Bug#12842206 INNODB LOCKING REGRESSION FOR INSERT IGNORE +--echo #fixed by re-fixing Bug#7975 +--echo #aka Bug#11759688 52020: InnoDB can still deadlock on just INSERT... +--echo # + +connection default; +CREATE TABLE t1 (a INT PRIMARY KEY, b INT NOT NULL) ENGINE=InnoDB; + +INSERT INTO t1 VALUES(3,1); + +BEGIN; +# this used to wrongly acquire an X lock; now it takes an S lock +INSERT IGNORE INTO t1 VALUES(3,14); + +connection con1; +BEGIN; +# this used to wrongly acquire an X lock; now it takes an S lock +INSERT IGNORE INTO t1 VALUES(3,23); +--send +SELECT * FROM t1 FOR UPDATE; + +connection con2; +# Check that the above SELECT is blocked +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = 'Sending data' and + info = 'SELECT * FROM t1 FOR UPDATE'; +--source include/wait_condition.inc + +connection default; +COMMIT; +connection con1; +reap; +COMMIT; +disconnect con1; +disconnect con2; + +connection default; +DROP TABLE t1; From e13d4c95d3011200d666b93858775cddc1e5b1d2 Mon Sep 17 00:00:00 2001 From: Sneha Modi Date: Fri, 11 Nov 2011 14:53:50 +0530 Subject: [PATCH 078/288] BUG#11748731 - 37248: SOME 'BIG' TESTS FAILING ON 6.0 : A change has been made in the sql/sql_table.cc file to include debug_sync. --- sql/sql_table.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 9a68420e5fc..5363737998b 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -5958,6 +5958,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, case ENABLE: if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN)) goto err; + DEBUG_SYNC(thd,"alter_table_enable_indexes"); DBUG_EXECUTE_IF("sleep_alter_enable_indexes", my_sleep(6000000);); error= table->file->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE); break; From 8851022f41a3b19f00a1ddc1da54d55a65bf9af0 Mon Sep 17 00:00:00 2001 From: Luis Soares Date: Fri, 11 Nov 2011 17:26:56 +0000 Subject: [PATCH 079/288] BUG#11760927: 53375: RBR + NO PK => HIGH LOAD ON SLAVE (TABLE SCAN/CPU) => SLAVE FAILURE When a statement containing a large amount of ROWs to be applied on the slave, and the slave's table does not contain a PK, it can take a considerable amount of time to find and change all the rows that are to be changed. The proper slave enhancement will be implemented in WL 5597. However, in this bug we are making it clear to the user what the problem is, by printing a message to the error log if the execution time, for a given statement in RBR, takes more than LONG_FIND_ROW_THRESHOLD (set to 60 seconds). This shall help the DBA to diagnose what's happening when facing a slave server that is quiet for no apparent reason... The note is only printed to the error log if log_warnings is set to be greater than 1. sql/log_event.cc: Core of the patch. In Rows_log_event::do_apply_event, sets STMT start timestamp. In Rows_log_event::find_row, if a PK is not used, then the start timestamp is checked to see if the time spent on this STMT is enough to justify the printing of a note (only if it was not printed before). sql/log_event.h: Defining LONG_FIND_ROW_THRESHOLD. sql/rpl_rli.cc: Resets long_find_row state in rli->context_cleanup(). sql/rpl_rli.h: Two new rli properties that are necessary to control when to emit a note in the error log: 1) timestamp that states when the ROW statement started; 2) flag indicating whether the note has been emitted for the current statement or not. Also deployed accessors. --- .../suite/rpl/r/rpl_row_find_row_debug.result | 18 ++++++ .../suite/rpl/t/rpl_row_find_row_debug.test | 62 ++++++++++++++++++ sql/log_event.cc | 64 +++++++++++++++++++ sql/log_event.h | 1 + sql/rpl_rli.cc | 9 +++ sql/rpl_rli.h | 41 ++++++++++++ 6 files changed, 195 insertions(+) create mode 100644 mysql-test/suite/rpl/r/rpl_row_find_row_debug.result create mode 100644 mysql-test/suite/rpl/t/rpl_row_find_row_debug.test diff --git a/mysql-test/suite/rpl/r/rpl_row_find_row_debug.result b/mysql-test/suite/rpl/r/rpl_row_find_row_debug.result new file mode 100644 index 00000000000..295c053563d --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_row_find_row_debug.result @@ -0,0 +1,18 @@ +include/master-slave.inc +[connection master] +include/stop_slave.inc +SET GLOBAL log_warnings = 2; +SET GLOBAL debug="d,inject_long_find_row_note"; +include/start_slave.inc +CREATE TABLE t1 (c1 INT); +INSERT INTO t1 VALUES (1), (2); +UPDATE t1 SET c1= 1000 WHERE c1=2; +DELETE FROM t1; +DROP TABLE t1; +# Check if any note related to long DELETE_ROWS and UPDATE_ROWS appears in the error log +Occurrences: update=1, delete=1 +include/stop_slave.inc +SET GLOBAL debug = ''; +SET GLOBAL log_warnings = 1; +include/start_slave.inc +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_find_row_debug.test b/mysql-test/suite/rpl/t/rpl_row_find_row_debug.test new file mode 100644 index 00000000000..a8d9e878ba2 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_find_row_debug.test @@ -0,0 +1,62 @@ +# +# Bug#11760927: 53375: RBR + NO PK => HIGH LOAD ON SLAVE (TABLE SCAN/CPU) => SLAVE FAILURE +# +--source include/master-slave.inc +--source include/have_binlog_format_row.inc +--source include/have_debug.inc + +# SETUP +# - setup log_warnings and debug +--connection slave +--source include/stop_slave.inc +--let $debug_save= `SELECT @@GLOBAL.debug` +--let $log_warnings_save= `SELECT @@GLOBAL.log_warnings` + +SET GLOBAL log_warnings = 2; + +let $log_error_= `SELECT @@GLOBAL.log_error`; +if(!$log_error_) +{ + # MySQL Server on windows is started with --console and thus + # does not know the location of its .err log, use default location + let $log_error_ = $MYSQLTEST_VARDIR/log/mysqld.2.err; +} + +# Assign env variable LOG_ERROR +let LOG_ERROR=$log_error_; + +# force printing the notes to the error log +SET GLOBAL debug="d,inject_long_find_row_note"; +--source include/start_slave.inc + +# test +--connection master +CREATE TABLE t1 (c1 INT); +--sync_slave_with_master +--connection master + +INSERT INTO t1 VALUES (1), (2); +UPDATE t1 SET c1= 1000 WHERE c1=2; +DELETE FROM t1; +DROP TABLE t1; +--sync_slave_with_master + +--echo # Check if any note related to long DELETE_ROWS and UPDATE_ROWS appears in the error log +perl; + use strict; + my $log_error= $ENV{'LOG_ERROR'} or die "LOG_ERROR not set"; + open(FILE, "$log_error") or die("Unable to open $log_error: $!\n"); + my $upd_count = () = grep(/The slave is applying a ROW event on behalf of an UPDATE statement on table t1 and is currently taking a considerable amount/g,); + seek(FILE, 0, 0) or die "Can't seek to beginning of file: $!"; + my $del_count = () = grep(/The slave is applying a ROW event on behalf of a DELETE statement on table t1 and is currently taking a considerable amount/g,); + print "Occurrences: update=$upd_count, delete=$del_count\n"; + close(FILE); +EOF + +# cleanup +--source include/stop_slave.inc +--eval SET GLOBAL debug = '$debug_save' +--eval SET GLOBAL log_warnings = $log_warnings_save +--source include/start_slave.inc + +--source include/rpl_end.inc diff --git a/sql/log_event.cc b/sql/log_event.cc index b29bcfdb536..d994058f037 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -7761,6 +7761,12 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) // row processing loop + /* + set the initial time of this ROWS statement if it was not done + before in some other ROWS event. + */ + const_cast(rli)->set_row_stmt_start_timestamp(); + while (error == 0 && m_curr_row < m_rows_end) { /* in_use can have been set to NULL in close_tables_for_reopen */ @@ -9252,6 +9258,51 @@ record_compare_exit: return result; } +/* + Check if we are already spending too much time on this statement. + if we are, warn user that it might be because table does not have + a PK, but only if the warning was not printed before for this STMT. + + @param type The event type code. + @param table_name The name of the table that the slave is + operating. + @param is_index_scan States whether the slave is doing an index scan + or not. + @param rli The relay metadata info. +*/ +static inline +void issue_long_find_row_warning(Log_event_type type, + const char *table_name, + bool is_index_scan, + const Relay_log_info *rli) +{ + if ((global_system_variables.log_warnings > 1 && + !const_cast(rli)->is_long_find_row_note_printed())) + { + time_t now= my_time(0); + time_t stmt_ts= const_cast(rli)->get_row_stmt_start_timestamp(); + + DBUG_EXECUTE_IF("inject_long_find_row_note", + stmt_ts-=(LONG_FIND_ROW_THRESHOLD*2);); + + time_t delta= (now - stmt_ts); + + if (delta > LONG_FIND_ROW_THRESHOLD) + { + const_cast(rli)->set_long_find_row_note_printed(); + const char* evt_type= type == DELETE_ROWS_EVENT ? " DELETE" : "n UPDATE"; + const char* scan_type= is_index_scan ? "scanning an index" : "scanning the table"; + + sql_print_information("The slave is applying a ROW event on behalf of a%s statement " + "on table %s and is currently taking a considerable amount " + "of time (%lu seconds). This is due to the fact that it is %s " + "while looking up records to be processed. Consider adding a " + "primary key (or unique key) to the table to improve " + "performance.", evt_type, table_name, delta, scan_type); + } + } +} + /** Locate the current row in event's table. @@ -9287,6 +9338,7 @@ int Rows_log_event::find_row(const Relay_log_info *rli) TABLE *table= m_table; int error= 0; + bool is_table_scan= false, is_index_scan= false; /* rpl_row_tabledefs.test specifies that @@ -9452,6 +9504,8 @@ int Rows_log_event::find_row(const Relay_log_info *rli) } } + is_index_scan=true; + /* In case key is not unique, we still have to iterate over records found and find the one which is identical to the row given. A copy of the @@ -9508,6 +9562,8 @@ int Rows_log_event::find_row(const Relay_log_info *rli) goto err; } + is_table_scan= true; + /* Continue until we find the right record or have made a full loop */ do { @@ -9561,10 +9617,18 @@ int Rows_log_event::find_row(const Relay_log_info *rli) goto err; } ok: + if (is_table_scan || is_index_scan) + issue_long_find_row_warning(get_type_code(), m_table->alias, + is_index_scan, rli); + table->default_column_bitmaps(); DBUG_RETURN(0); err: + if (is_table_scan || is_index_scan) + issue_long_find_row_warning(get_type_code(), m_table->alias, + is_index_scan, rli); + table->default_column_bitmaps(); DBUG_RETURN(error); } diff --git a/sql/log_event.h b/sql/log_event.h index 07656ebaa72..d65f2d2c85d 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -53,6 +53,7 @@ class String; #define PREFIX_SQL_LOAD "SQL_LOAD-" +#define LONG_FIND_ROW_THRESHOLD 60 /* seconds */ /** Either assert or return an error. diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index e1c764a4248..0000ba9abb7 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -1245,6 +1245,15 @@ void Relay_log_info::cleanup_context(THD *thd, bool error) */ thd->variables.option_bits&= ~OPTION_NO_FOREIGN_KEY_CHECKS; thd->variables.option_bits&= ~OPTION_RELAXED_UNIQUE_CHECKS; + + /* + Reset state related to long_find_row notes in the error log: + - timestamp + - flag that decides whether the slave prints or not + */ + reset_row_stmt_start_timestamp(); + unset_long_find_row_note_printed(); + DBUG_VOID_RETURN; } diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h index fb62279c4c1..c8a0f549e0f 100644 --- a/sql/rpl_rli.h +++ b/sql/rpl_rli.h @@ -452,8 +452,49 @@ public: (m_flags & (1UL << IN_STMT)); } + time_t get_row_stmt_start_timestamp() + { + return row_stmt_start_timestamp; + } + + time_t set_row_stmt_start_timestamp() + { + if (row_stmt_start_timestamp == 0) + row_stmt_start_timestamp= my_time(0); + + return row_stmt_start_timestamp; + } + + void reset_row_stmt_start_timestamp() + { + row_stmt_start_timestamp= 0; + } + + void set_long_find_row_note_printed() + { + long_find_row_note_printed= true; + } + + void unset_long_find_row_note_printed() + { + long_find_row_note_printed= false; + } + + bool is_long_find_row_note_printed() + { + return long_find_row_note_printed; + } + private: + uint32 m_flags; + + /* + Runtime state for printing a note when slave is taking + too long while processing a row event. + */ + time_t row_stmt_start_timestamp; + bool long_find_row_note_printed; }; From a2f757eabea5b38db5ffcaac10751bbb8475ff06 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 11 Nov 2011 14:44:51 -0500 Subject: [PATCH 080/288] BUG#12929028: mysql_plugin : the --mysqld option is required, but not used This patch corrects a defect whereby the --mysqld, --my-print-defaults, and --plugin-ini were required. These options are not required and the code has been fixed accordingly. --- client/mysql_plugin.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/client/mysql_plugin.c b/client/mysql_plugin.c index 55f5ea0827e..fb2a031bb8e 100644 --- a/client/mysql_plugin.c +++ b/client/mysql_plugin.c @@ -929,19 +929,19 @@ static int check_access() opt_datadir); goto exit; } - if ((error= my_access(opt_plugin_ini, F_OK))) + if (opt_plugin_ini && (error= my_access(opt_plugin_ini, F_OK))) { fprintf(stderr, "ERROR: Cannot access plugin config file at '%s'.\n", opt_plugin_ini); goto exit; } - if ((error= my_access(opt_mysqld, F_OK))) + if (opt_mysqld && (error= my_access(opt_mysqld, F_OK))) { fprintf(stderr, "ERROR: Cannot access mysqld path '%s'.\n", opt_mysqld); goto exit; } - if ((error= my_access(opt_my_print_defaults, F_OK))) + if (opt_my_print_defaults && (error= my_access(opt_my_print_defaults, F_OK))) { fprintf(stderr, "ERROR: Cannot access my-print-defaults path '%s'.\n", opt_my_print_defaults); @@ -967,7 +967,7 @@ static int find_tool(const char *tool_name, char *tool_path) int i= 0; const char *paths[]= { - opt_basedir, opt_mysqld, opt_my_print_defaults, "/usr", + opt_mysqld, opt_basedir, opt_my_print_defaults, "/usr", "/usr/local/mysql", "/usr/sbin", "/usr/share", "/extra", "/extra/debug", "/extra/release", "/bin", "/usr/bin", "/mysql/bin" }; @@ -1124,7 +1124,7 @@ static int dump_bootstrap_file(char *bootstrap_file) error= 1; goto exit; } - printf("# Query: %s", query_str); + printf("# Query: %s\n", query_str); exit: if (file) From 7f746fbe74e08d79217bdf7c7cba628e3b6bef85 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Sat, 12 Nov 2011 20:50:11 +0200 Subject: [PATCH 081/288] BUG#887468: Second assertion `keypart_map' failed in maria_rkey with semijoin - in advance_sj_state: Do not try to construct LooseScan strategy if we're already behind the last LooseScan table. --- mysql-test/r/subselect_sj_aria.result | 59 +++++++++++++++++++++ mysql-test/t/subselect_sj_aria.test | 76 +++++++++++++++++++++++++++ sql/opt_subselect.cc | 3 +- 3 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 mysql-test/r/subselect_sj_aria.result create mode 100644 mysql-test/t/subselect_sj_aria.test diff --git a/mysql-test/r/subselect_sj_aria.result b/mysql-test/r/subselect_sj_aria.result new file mode 100644 index 00000000000..ea6cc8d14c4 --- /dev/null +++ b/mysql-test/r/subselect_sj_aria.result @@ -0,0 +1,59 @@ +drop table if exists t1,t2,t3,t4; +# +# BUG#887468: Second assertion `keypart_map' failed in maria_rkey with semijoin +# +CREATE TABLE t1 ( +pk int(11) NOT NULL AUTO_INCREMENT, +col_int_key int(11) DEFAULT NULL, +col_varchar_key varchar(1) DEFAULT NULL, +dummy char(30), +PRIMARY KEY (pk), +KEY col_varchar_key (col_varchar_key,col_int_key) +) ENGINE=Aria AUTO_INCREMENT=30 DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1; +INSERT INTO t1 (pk, col_varchar_key, col_int_key) VALUES +(10,NULL,0), (11,'d',4), (12,'g',8), (13,'x',NULL), (14,'f',NULL), +(15,'p',0), (16,'j',NULL), (17,'c',8), (18,'z',8), (19,'j',6), (20,NULL,2), +(21,'p',3), (22,'w',1), (23,'c',NULL), (24,'j',1), (25,'f',10), (26,'v',2), +(27,'f',103), (28,'q',3), (29,'y',6); +CREATE TABLE t2 ( +pk int(11) NOT NULL AUTO_INCREMENT, +col_int_key int(11) DEFAULT NULL, +dummy char(36), +PRIMARY KEY (pk), +KEY col_int_key (col_int_key) +) ENGINE=Aria AUTO_INCREMENT=101 DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1; +INSERT INTO t2 ( pk, col_int_key) VALUES +(1,8), (2,2), (3,9), (4,6), (5,NULL), (6,NULL), (7,48), (8,228), (9,3), (10,5), +(11,39), (12,6), (13,8), (14,3), (15,NULL), (16,2), (17,6), (18,3), (19,1), (20,4), +(21,3), (22,1), (23,NULL), (24,97), (25,0), (26,0), (27,9), (28,5), (29,9), (30,0), +(31,2), (32,172), (33,NULL), (34,5), (35,119), (36,1), (37,4), (38,8), (39,NULL), (40,6), +(41,5), (42,5), (43,1), (44,7), (45,2), (46,8), (47,9), (48,NULL), (49,NULL), (50,3), +(51,172), (52,NULL), (53,6), (54,6), (55,5), (56,4), (57,3), (58,2), (59,7), (60,4), +(61,6), (62,0), (63,8), (64,5), (65,8), (66,2), (67,9), (68,7), (69,5), (70,7), +(71,0), (72,4), (73,3), (74,1), (75,0), (76,6), (77,2), (78,NULL), (79,8), (80,NULL), +(81,NULL), (82,NULL), (83,3), (84,7), (85,3), (86,5), (87,5), (88,1), (89,2), (90,1), +(91,7), (92,1), (93,9), (94,9), (95,8), (96,3), (97,7), (98,4), (99,9), (100,0); +CREATE TABLE t3 ( +pk int(11) NOT NULL AUTO_INCREMENT, +dummy char(34), +col_varchar_key varchar(1) DEFAULT NULL, +col_int_key int(11) DEFAULT NULL, +PRIMARY KEY (pk), +KEY col_varchar_key (col_varchar_key,col_int_key) +) ENGINE=Aria AUTO_INCREMENT=4 DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1; +INSERT INTO t3 (pk, col_varchar_key) VALUES (1,'v'), (2,'c'), (3,NULL); +CREATE TABLE t4 ( +pk int(11) NOT NULL AUTO_INCREMENT, +dummy char (38), +PRIMARY KEY (pk) +) ENGINE=Aria AUTO_INCREMENT=4 DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1; +INSERT INTO t4 (pk) VALUES (1), (2), (3); +SELECT * +FROM t1 +JOIN t2 +ON ( t2.col_int_key = t1.pk ) +WHERE t1.col_varchar_key IN ( +SELECT t3.col_varchar_key FROM t3, t4 +); +pk col_int_key col_varchar_key dummy pk col_int_key dummy +drop table t1, t2, t3, t4; diff --git a/mysql-test/t/subselect_sj_aria.test b/mysql-test/t/subselect_sj_aria.test new file mode 100644 index 00000000000..806688b3f87 --- /dev/null +++ b/mysql-test/t/subselect_sj_aria.test @@ -0,0 +1,76 @@ +# +# Semi-join tests that require Aria +# +--disable_warnings +drop table if exists t1,t2,t3,t4; +--enable_warnings + + +--echo # +--echo # BUG#887468: Second assertion `keypart_map' failed in maria_rkey with semijoin +--echo # + +CREATE TABLE t1 ( + pk int(11) NOT NULL AUTO_INCREMENT, + col_int_key int(11) DEFAULT NULL, + col_varchar_key varchar(1) DEFAULT NULL, + dummy char(30), + PRIMARY KEY (pk), + KEY col_varchar_key (col_varchar_key,col_int_key) +) ENGINE=Aria AUTO_INCREMENT=30 DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1; + +INSERT INTO t1 (pk, col_varchar_key, col_int_key) VALUES +(10,NULL,0), (11,'d',4), (12,'g',8), (13,'x',NULL), (14,'f',NULL), +(15,'p',0), (16,'j',NULL), (17,'c',8), (18,'z',8), (19,'j',6), (20,NULL,2), +(21,'p',3), (22,'w',1), (23,'c',NULL), (24,'j',1), (25,'f',10), (26,'v',2), +(27,'f',103), (28,'q',3), (29,'y',6); + +CREATE TABLE t2 ( + pk int(11) NOT NULL AUTO_INCREMENT, + col_int_key int(11) DEFAULT NULL, + dummy char(36), + PRIMARY KEY (pk), + KEY col_int_key (col_int_key) +) ENGINE=Aria AUTO_INCREMENT=101 DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1; + +INSERT INTO t2 ( pk, col_int_key) VALUES +(1,8), (2,2), (3,9), (4,6), (5,NULL), (6,NULL), (7,48), (8,228), (9,3), (10,5), +(11,39), (12,6), (13,8), (14,3), (15,NULL), (16,2), (17,6), (18,3), (19,1), (20,4), +(21,3), (22,1), (23,NULL), (24,97), (25,0), (26,0), (27,9), (28,5), (29,9), (30,0), +(31,2), (32,172), (33,NULL), (34,5), (35,119), (36,1), (37,4), (38,8), (39,NULL), (40,6), +(41,5), (42,5), (43,1), (44,7), (45,2), (46,8), (47,9), (48,NULL), (49,NULL), (50,3), +(51,172), (52,NULL), (53,6), (54,6), (55,5), (56,4), (57,3), (58,2), (59,7), (60,4), +(61,6), (62,0), (63,8), (64,5), (65,8), (66,2), (67,9), (68,7), (69,5), (70,7), +(71,0), (72,4), (73,3), (74,1), (75,0), (76,6), (77,2), (78,NULL), (79,8), (80,NULL), +(81,NULL), (82,NULL), (83,3), (84,7), (85,3), (86,5), (87,5), (88,1), (89,2), (90,1), +(91,7), (92,1), (93,9), (94,9), (95,8), (96,3), (97,7), (98,4), (99,9), (100,0); + +CREATE TABLE t3 ( + pk int(11) NOT NULL AUTO_INCREMENT, + dummy char(34), + col_varchar_key varchar(1) DEFAULT NULL, + col_int_key int(11) DEFAULT NULL, + PRIMARY KEY (pk), + KEY col_varchar_key (col_varchar_key,col_int_key) +) ENGINE=Aria AUTO_INCREMENT=4 DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1; + +INSERT INTO t3 (pk, col_varchar_key) VALUES (1,'v'), (2,'c'), (3,NULL); + +CREATE TABLE t4 ( + pk int(11) NOT NULL AUTO_INCREMENT, + dummy char (38), + PRIMARY KEY (pk) +) ENGINE=Aria AUTO_INCREMENT=4 DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1; + +INSERT INTO t4 (pk) VALUES (1), (2), (3); + +SELECT * +FROM t1 +JOIN t2 +ON ( t2.col_int_key = t1.pk ) +WHERE t1.col_varchar_key IN ( + SELECT t3.col_varchar_key FROM t3, t4 +); + +drop table t1, t2, t3, t4; + diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index aa0a8152bbb..fdda502e706 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -2339,7 +2339,8 @@ void advance_sj_state(JOIN *join, table_map remaining_tables, } if ((pos->first_loosescan_table != MAX_TABLES) && - !(remaining_tables & pos->loosescan_need_tables)) + !(remaining_tables & pos->loosescan_need_tables) && + (pos->table->table->map & pos->loosescan_need_tables)) { /* Ok we have LooseScan plan and also have all LooseScan sj-nest's From 38138943618ab00d82044a82e0da81527a267a6b Mon Sep 17 00:00:00 2001 From: Tor Didriksen Date: Tue, 15 Nov 2011 10:01:29 +0100 Subject: [PATCH 082/288] Bug#13261955 TRUNCATE(DBL_MAX) RETURNS DBL_MAX RATHER THAN 'INF' my_double_round(DBL_MAX, -12, ....) should return 'inf' rather than DBL_MAX The problem is that floor(value/tmp) * tmp is inlined, and optimized away. The solution seems to be to prevent inlining by pre-computing value/tmp and storing it in a variable. No new test case: main.type_float fails without this patch. --- sql/item_func.cc | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/sql/item_func.cc b/sql/item_func.cc index 7257b411ec4..0cd6ff6357e 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2328,25 +2328,31 @@ double my_double_round(double value, longlong dec, bool dec_unsigned, /* tmp2 is here to avoid return the value with 80 bit precision This will fix that the test round(0.1,1) = round(0.1,1) is true + Tagging with volatile is no guarantee, it may still be optimized away... */ volatile double tmp2; tmp=(abs_dec < array_elements(log_10) ? log_10[abs_dec] : pow(10.0,(double) abs_dec)); + // Pre-compute these, to avoid optimizing away e.g. 'floor(v/tmp) * tmp'. + volatile double value_div_tmp= value / tmp; + volatile double value_mul_tmp= value * tmp; + if (dec_negative && my_isinf(tmp)) - tmp2= 0; - else if (!dec_negative && my_isinf(value * tmp)) + tmp2= 0.0; + else if (!dec_negative && my_isinf(value_mul_tmp)) tmp2= value; else if (truncate) { - if (value >= 0) - tmp2= dec < 0 ? floor(value/tmp)*tmp : floor(value*tmp)/tmp; + if (value >= 0.0) + tmp2= dec < 0 ? floor(value_div_tmp) * tmp : floor(value_mul_tmp) / tmp; else - tmp2= dec < 0 ? ceil(value/tmp)*tmp : ceil(value*tmp)/tmp; + tmp2= dec < 0 ? ceil(value_div_tmp) * tmp : ceil(value_mul_tmp) / tmp; } else - tmp2=dec < 0 ? rint(value/tmp)*tmp : rint(value*tmp)/tmp; + tmp2=dec < 0 ? rint(value_div_tmp) * tmp : rint(value_mul_tmp) / tmp; + return tmp2; } From ef45b799245d4c33770339619dab4d717b1e552f Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Tue, 15 Nov 2011 13:14:54 +0200 Subject: [PATCH 083/288] Fix for lp:780425 sql_buffer_result=1 gives wrong result for GROUP BY with a +# constant expression" mysql-test/r/select.result: Test case for lp:780425 mysql-test/r/select_pkeycache.result: lp:780425 mysql-test/t/select.test: lp:780425 sql/sql_select.cc: Added DBUG_ASSERT to be prove some logic and later be able to simplify the code Set implicit_grouping if we delete a GROUP BY to signal do_select() that a grouping needs to be done. --- mysql-test/r/select.result | 27 +++++++++++++++++++++++++++ mysql-test/r/select_pkeycache.result | 27 +++++++++++++++++++++++++++ mysql-test/t/select.test | 17 +++++++++++++++++ sql/sql_select.cc | 4 ++++ 4 files changed, 75 insertions(+) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index f8df72c6709..5453345d50c 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -4875,4 +4875,31 @@ f1 f1 f1 f1 f2 f1 f1 18 9 NULL NULL NULL 5 7 SET SESSION join_buffer_size = DEFAULT; DROP TABLE t1,t2,t3,t4,t5,t6; +CREATE TABLE t1(f1 int UNSIGNED) engine=myisam; +INSERT INTO t1 VALUES (3),(2),(1); +set sql_buffer_result=0; +SELECT f1 FROM t1 GROUP BY 1; +f1 +1 +2 +3 +SELECT f1 FROM t1 GROUP BY '123' = 'abc'; +f1 +3 +SELECT 1 FROM t1 GROUP BY 1; +1 +1 +set sql_buffer_result=1; +SELECT f1 FROM t1 GROUP BY 1; +f1 +1 +2 +3 +SELECT f1 FROM t1 GROUP BY '123' = 'abc'; +f1 +3 +SELECT 1 FROM t1 GROUP BY 1; +1 +1 +drop table t1; End of 5.1 tests diff --git a/mysql-test/r/select_pkeycache.result b/mysql-test/r/select_pkeycache.result index f8df72c6709..5453345d50c 100644 --- a/mysql-test/r/select_pkeycache.result +++ b/mysql-test/r/select_pkeycache.result @@ -4875,4 +4875,31 @@ f1 f1 f1 f1 f2 f1 f1 18 9 NULL NULL NULL 5 7 SET SESSION join_buffer_size = DEFAULT; DROP TABLE t1,t2,t3,t4,t5,t6; +CREATE TABLE t1(f1 int UNSIGNED) engine=myisam; +INSERT INTO t1 VALUES (3),(2),(1); +set sql_buffer_result=0; +SELECT f1 FROM t1 GROUP BY 1; +f1 +1 +2 +3 +SELECT f1 FROM t1 GROUP BY '123' = 'abc'; +f1 +3 +SELECT 1 FROM t1 GROUP BY 1; +1 +1 +set sql_buffer_result=1; +SELECT f1 FROM t1 GROUP BY 1; +f1 +1 +2 +3 +SELECT f1 FROM t1 GROUP BY '123' = 'abc'; +f1 +3 +SELECT 1 FROM t1 GROUP BY 1; +1 +1 +drop table t1; End of 5.1 tests diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index 1139e7acc60..ef1894a5405 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -4121,4 +4121,21 @@ SET SESSION join_buffer_size = DEFAULT; DROP TABLE t1,t2,t3,t4,t5,t6; +# +# Bug #780425: "sql_buffer_result=1 gives wrong result for GROUP BY with a +# constant expression" +# + +CREATE TABLE t1(f1 int UNSIGNED) engine=myisam; +INSERT INTO t1 VALUES (3),(2),(1); +set sql_buffer_result=0; +SELECT f1 FROM t1 GROUP BY 1; +SELECT f1 FROM t1 GROUP BY '123' = 'abc'; +SELECT 1 FROM t1 GROUP BY 1; +set sql_buffer_result=1; +SELECT f1 FROM t1 GROUP BY 1; +SELECT f1 FROM t1 GROUP BY '123' = 'abc'; +SELECT 1 FROM t1 GROUP BY 1; +drop table t1; + --echo End of 5.1 tests diff --git a/sql/sql_select.cc b/sql/sql_select.cc index defd7ed7c32..d1fcb5633bb 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1295,7 +1295,10 @@ JOIN::optimize() DBUG_RETURN(1); } if (old_group_list && !group_list) + { + DBUG_ASSERT(group); select_distinct= 0; + } } if (!group_list && group) { @@ -1303,6 +1306,7 @@ JOIN::optimize() simple_order=1; select_distinct= 0; // No need in distinct for 1 row group_optimized_away= 1; + implicit_grouping= TRUE; } calc_group_buffer(this, group_list); From 4df195a4caae2d084798ee50bafa0dfeef85a9bf Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Tue, 15 Nov 2011 17:48:42 +0530 Subject: [PATCH 084/288] Bug#11827359 60223: MYSQL_UPGRADE PROBLEM WITH OPTION SKIP-WRITE-BINLOG System tables were not getting upgraded when mysql_upgrade was run with --skip-write-binlog option. (Same for --write-binlog.) Also, with this option, mysql_upgrade_info file was not getting created after the upgrade. mysql_upgrade makes use of mysql client tool in order to run upgrade scripts, while doing so it passes some of the command line options (used to start mysql_upgrade) directly to mysql client. The reason behind this bug being, some options like skip-write-binlog and upgrade-system-tables were being passed to mysql tool along with other options, and hence mysql execution failed due presence of these invalid options. Fixed this issue by filtering out the above mentioned options from the list of options that will be passed to mysql and mysqlcheck tools. However, since --write-binlog is supported by mysqlcheck, this option would be used explicitly while running mysqlcheck. (not part of patch, already there) Checking the contents of general log after the upgrade is not doable via an mtr test. So performed manual test. Added a test to verify the creation of mysql_upgrade_info. client/mysql_upgrade.c: Bug#11827359 60223: MYSQL_UPGRADE PROBLEM WITH OPTION SKIP-WRITE-BINLOG With this patch, --upgrade-system-tables and --write-binlog options will not be added to the list of options, used to start mysql and mysqlcheck tools. mysql-test/r/mysql_upgrade.result: Added a testcase for Bug#11827359. mysql-test/t/mysql_upgrade.test: Added a testcase for Bug#11827359. --- client/mysql_upgrade.c | 2 ++ mysql-test/r/mysql_upgrade.result | 33 +++++++++++++++++++++++++++++++ mysql-test/t/mysql_upgrade.test | 21 +++++++++++++++++++- 3 files changed, 55 insertions(+), 1 deletion(-) diff --git a/client/mysql_upgrade.c b/client/mysql_upgrade.c index fb4be716df2..684d20c29a8 100644 --- a/client/mysql_upgrade.c +++ b/client/mysql_upgrade.c @@ -286,6 +286,8 @@ get_one_option(int optid, const struct my_option *opt, case 'v': /* --verbose */ case 'f': /* --force */ + case 's': /* --upgrade-system-tables */ + case OPT_WRITE_BINLOG: /* --write-binlog */ add_option= FALSE; break; diff --git a/mysql-test/r/mysql_upgrade.result b/mysql-test/r/mysql_upgrade.result index e36b4781ddf..8ce3f426375 100644 --- a/mysql-test/r/mysql_upgrade.result +++ b/mysql-test/r/mysql_upgrade.result @@ -194,3 +194,36 @@ GRANT ALL PRIVILEGES ON `roelt`.`test2` TO 'user3'@'%' DROP USER 'user3'@'%'; End of 5.1 tests The --upgrade-system-tables option was used, databases won't be touched. +# +# Bug#11827359 60223: MYSQL_UPGRADE PROBLEM WITH OPTION +# SKIP-WRITE-BINLOG +# +# Droping the previously created mysql_upgrade_info file.. +# Running mysql_upgrade with --skip-write-binlog.. +mtr.global_suppressions OK +mtr.test_suppressions OK +mysql.columns_priv OK +mysql.db OK +mysql.event OK +mysql.func OK +mysql.general_log OK +mysql.help_category OK +mysql.help_keyword OK +mysql.help_relation OK +mysql.help_topic OK +mysql.host OK +mysql.ndb_binlog_index OK +mysql.plugin OK +mysql.proc OK +mysql.procs_priv OK +mysql.proxies_priv OK +mysql.servers OK +mysql.slow_log OK +mysql.tables_priv OK +mysql.time_zone OK +mysql.time_zone_leap_second OK +mysql.time_zone_name OK +mysql.time_zone_transition OK +mysql.time_zone_transition_type OK +mysql.user OK +End of tests diff --git a/mysql-test/t/mysql_upgrade.test b/mysql-test/t/mysql_upgrade.test index 3c6cc45da38..05b8c81a797 100644 --- a/mysql-test/t/mysql_upgrade.test +++ b/mysql-test/t/mysql_upgrade.test @@ -102,5 +102,24 @@ DROP USER 'user3'@'%'; # Test the --upgrade-system-tables option # --replace_result $MYSQLTEST_VARDIR var ---exec $MYSQL_UPGRADE --skip-verbose --upgrade-system-tables +--exec $MYSQL_UPGRADE --skip-verbose --force --upgrade-system-tables +--echo # +--echo # Bug#11827359 60223: MYSQL_UPGRADE PROBLEM WITH OPTION +--echo # SKIP-WRITE-BINLOG +--echo # + +let $MYSQLD_DATADIR= `select @@datadir`; + +--echo # Droping the previously created mysql_upgrade_info file.. +--remove_file $MYSQLD_DATADIR/mysql_upgrade_info + +--echo # Running mysql_upgrade with --skip-write-binlog.. +--replace_result $MYSQLTEST_VARDIR var +--exec $MYSQL_UPGRADE --skip-verbose --skip-write-binlog + +# mysql_upgrade must have created mysql_upgrade_info file, +# so the following command should never fail. +--remove_file $MYSQLD_DATADIR/mysql_upgrade_info + +--echo End of tests From b6c0ed9953db444f85240a8131427279b9cacb02 Mon Sep 17 00:00:00 2001 From: Luis Soares Date: Tue, 15 Nov 2011 14:38:58 +0000 Subject: [PATCH 085/288] BUG#11760927 Follow up to fix freebsd compile issue. --- sql/log_event.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/log_event.cc b/sql/log_event.cc index d994058f037..0003a621cbb 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -9285,7 +9285,7 @@ void issue_long_find_row_warning(Log_event_type type, DBUG_EXECUTE_IF("inject_long_find_row_note", stmt_ts-=(LONG_FIND_ROW_THRESHOLD*2);); - time_t delta= (now - stmt_ts); + long delta= (long) (now - stmt_ts); if (delta > LONG_FIND_ROW_THRESHOLD) { @@ -9295,7 +9295,7 @@ void issue_long_find_row_warning(Log_event_type type, sql_print_information("The slave is applying a ROW event on behalf of a%s statement " "on table %s and is currently taking a considerable amount " - "of time (%lu seconds). This is due to the fact that it is %s " + "of time (%ld seconds). This is due to the fact that it is %s " "while looking up records to be processed. Consider adding a " "primary key (or unique key) to the table to improve " "performance.", evt_type, table_name, delta, scan_type); From 082e0b957d9da894efcb597c000134d74759c4c1 Mon Sep 17 00:00:00 2001 From: Dmitry Lenev Date: Tue, 15 Nov 2011 22:00:14 +0400 Subject: [PATCH 086/288] Fix for bug#12695572 - "IMPROVE MDL PERFORMANCE IN PRE-VISTA BY CACHING OR REDUCING CREATEEVENT CALLS". 5.5 versions of MySQL server performed worse than 5.1 versions under single-connection workload in autocommit mode on Windows XP. Part of this slowdown can be attributed to overhead associated with constant creation/destruction of MDL_lock objects in the MDL subsystem. The problem is that creation/destruction of these objects causes creation and destruction of associated synchronization primitives, which are expensive on Windows XP. This patch tries to alleviate this problem by introducing a cache of unused MDL_object_lock objects. Instead of destroying such objects we put them into the cache and then reuse with a new key when creation of a new object is requested. To limit the size of this cache, a new --metadata-locks-cache-size start-up parameter was introduced. mysql-test/r/mysqld--help-notwin.result: Updated test after adding --metadata-locks-cache-size parameter. mysql-test/r/mysqld--help-win.result: Updated test after adding --metadata-locks-cache-size parameter. mysql-test/suite/sys_vars/r/metadata_locks_cache_size_basic.result: Added test coverage for newly introduced --metadata_locks_cache_size start-up parameter and corresponding global read-only variable. mysql-test/suite/sys_vars/t/metadata_locks_cache_size_basic-master.opt: Added test coverage for newly introduced --metadata_locks_cache_size start-up parameter and corresponding global read-only variable. mysql-test/suite/sys_vars/t/metadata_locks_cache_size_basic.test: Added test coverage for newly introduced --metadata_locks_cache_size start-up parameter and corresponding global read-only variable. sql/mdl.cc: Introduced caching of unused MDL_object_lock objects, in order to avoid costs associated with constant creation and destruction of such objects in single-connection workloads run in autocommit mode. Such costs can be pretty high on systems where creation and destruction of synchronization primitives require a system call (e.g. Windows XP). To implement this cache,a list of unused MDL_object_lock instances was added to MDL_map object. Instead of being destroyed MDL_object_lock instances are put into this list and re-used later when creation of a new instance is required. Also added MDL_lock::m_version counter to allow threads having outstanding references to an MDL_object_lock instance to notice that it has been moved to the unused objects list. Added a global variable for a start-up parameter that limits the size of the unused objects list. Note that we don't cache MDL_scoped_lock objects since they are supposed to be created only during execution of DDL statements and therefore should not affect performance much. sql/mdl.h: Added a global variable for start-up parameter that limits the size of the unused MDL_object_lock objects list and constant for its default value. sql/sql_plist.h: Added I_P_List<>::pop_front() function. sql/sys_vars.cc: Introduced --metadata-locks-cache-size start-up parameter for specifying size of the cache of unused MDL_object_lock objects. --- mysql-test/r/mysqld--help-notwin.result | 3 + mysql-test/r/mysqld--help-win.result | 3 + .../r/metadata_locks_cache_size_basic.result | 21 ++ ...metadata_locks_cache_size_basic-master.opt | 1 + .../t/metadata_locks_cache_size_basic.test | 25 ++ sql/mdl.cc | 266 +++++++++++++++--- sql/mdl.h | 8 + sql/sql_plist.h | 9 + sql/sys_vars.cc | 6 + 9 files changed, 297 insertions(+), 45 deletions(-) create mode 100644 mysql-test/suite/sys_vars/r/metadata_locks_cache_size_basic.result create mode 100644 mysql-test/suite/sys_vars/t/metadata_locks_cache_size_basic-master.opt create mode 100644 mysql-test/suite/sys_vars/t/metadata_locks_cache_size_basic.test diff --git a/mysql-test/r/mysqld--help-notwin.result b/mysql-test/r/mysqld--help-notwin.result index b4faa833c1b..cb727984ec0 100644 --- a/mysql-test/r/mysqld--help-notwin.result +++ b/mysql-test/r/mysqld--help-notwin.result @@ -336,6 +336,8 @@ The following options may be given as the first argument: After this many write locks, allow some read locks to run in between --memlock Lock mysqld in memory. + --metadata-locks-cache-size=# + Size of unused metadata locks cache --min-examined-row-limit=# Don't write queries to slow log that examine fewer rows than that @@ -844,6 +846,7 @@ max-tmp-tables 32 max-user-connections 0 max-write-lock-count 18446744073709551615 memlock FALSE +metadata-locks-cache-size 1024 min-examined-row-limit 0 multi-range-count 256 myisam-block-size 1024 diff --git a/mysql-test/r/mysqld--help-win.result b/mysql-test/r/mysqld--help-win.result index 361d30620f7..38235e1a093 100644 --- a/mysql-test/r/mysqld--help-win.result +++ b/mysql-test/r/mysqld--help-win.result @@ -335,6 +335,8 @@ The following options may be given as the first argument: After this many write locks, allow some read locks to run in between --memlock Lock mysqld in memory. + --metadata-locks-cache-size=# + Size of unused metadata locks cache --min-examined-row-limit=# Don't write queries to slow log that examine fewer rows than that @@ -847,6 +849,7 @@ max-tmp-tables 32 max-user-connections 0 max-write-lock-count 18446744073709551615 memlock FALSE +metadata-locks-cache-size 1024 min-examined-row-limit 0 multi-range-count 256 myisam-block-size 1024 diff --git a/mysql-test/suite/sys_vars/r/metadata_locks_cache_size_basic.result b/mysql-test/suite/sys_vars/r/metadata_locks_cache_size_basic.result new file mode 100644 index 00000000000..a62b6011739 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/metadata_locks_cache_size_basic.result @@ -0,0 +1,21 @@ +# +# Check that the paremeter is correctly set by start-up +# option (.opt file sets it to 256 while default is 1024). +select @@global.metadata_locks_cache_size = 256; +@@global.metadata_locks_cache_size = 256 +1 +# +# Check that variable is read only +# +set @@global.metadata_locks_cache_size= 1024; +ERROR HY000: Variable 'metadata_locks_cache_size' is a read only variable +select @@global.metadata_locks_cache_size = 256; +@@global.metadata_locks_cache_size = 256 +1 +# +# And only GLOBAL +# +select @@session.metadata_locks_cache_size; +ERROR HY000: Variable 'metadata_locks_cache_size' is a GLOBAL variable +set @@session.metadata_locks_cache_size= 1024; +ERROR HY000: Variable 'metadata_locks_cache_size' is a read only variable diff --git a/mysql-test/suite/sys_vars/t/metadata_locks_cache_size_basic-master.opt b/mysql-test/suite/sys_vars/t/metadata_locks_cache_size_basic-master.opt new file mode 100644 index 00000000000..77e019cd3d4 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/metadata_locks_cache_size_basic-master.opt @@ -0,0 +1 @@ +--metadata-locks-cache-size=256 diff --git a/mysql-test/suite/sys_vars/t/metadata_locks_cache_size_basic.test b/mysql-test/suite/sys_vars/t/metadata_locks_cache_size_basic.test new file mode 100644 index 00000000000..31b033579c6 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/metadata_locks_cache_size_basic.test @@ -0,0 +1,25 @@ +# +# Basic test coverage for --metadata-locks-cache-size startup +# parameter and corresponding read-only global @@metadata_locks_cache_size +# variable. +# + +--echo # +--echo # Check that the paremeter is correctly set by start-up +--echo # option (.opt file sets it to 256 while default is 1024). +select @@global.metadata_locks_cache_size = 256; + +--echo # +--echo # Check that variable is read only +--echo # +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +set @@global.metadata_locks_cache_size= 1024; +select @@global.metadata_locks_cache_size = 256; + +--echo # +--echo # And only GLOBAL +--echo # +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +select @@session.metadata_locks_cache_size; +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +set @@session.metadata_locks_cache_size= 1024; diff --git a/sql/mdl.cc b/sql/mdl.cc index 046ac25703a..81d6c69dca4 100644 --- a/sql/mdl.cc +++ b/sql/mdl.cc @@ -91,6 +91,10 @@ const char *MDL_key::m_namespace_to_wait_state_name[NAMESPACE_END]= static bool mdl_initialized= 0; +class MDL_object_lock; +class MDL_object_lock_cache_adapter; + + /** A collection of all MDL locks. A singleton, there is only one instance of the map in the server. @@ -111,6 +115,25 @@ private: HASH m_locks; /* Protects access to m_locks hash. */ mysql_mutex_t m_mutex; + /** + Cache of (unused) MDL_lock objects available for re-use. + + On some systems (e.g. Windows XP) constructing/destructing + MDL_lock objects can be fairly expensive. We use this cache + to avoid these costs in scenarios in which they can have + significant negative effect on performance. For example, when + there is only one thread constantly executing statements in + auto-commit mode and thus constantly causing creation/ + destruction of MDL_lock objects for the tables it uses. + + Note that this cache contains only MDL_object_lock objects. + + Protected by m_mutex mutex. + */ + typedef I_P_List + Lock_cache; + Lock_cache m_unused_locks_cache; /** Pre-allocated MDL_lock object for GLOBAL namespace. */ MDL_lock *m_global_lock; /** Pre-allocated MDL_lock object for COMMIT namespace. */ @@ -379,7 +402,8 @@ public: : key(key_arg), m_ref_usage(0), m_ref_release(0), - m_is_destroyed(FALSE) + m_is_destroyed(FALSE), + m_version(0) { mysql_prlock_init(key_MDL_lock_rwlock, &m_rwlock); } @@ -414,6 +438,22 @@ public: uint m_ref_usage; uint m_ref_release; bool m_is_destroyed; + /** + We use the same idea and an additional version counter to support + caching of unused MDL_lock object for further re-use. + This counter is incremented while holding both MDL_map::m_mutex and + MDL_lock::m_rwlock locks each time when a MDL_lock is moved from + the hash to the unused objects list (or destroyed). + A thread, which has found a MDL_lock object for the key in the hash + and then released the MDL_map::m_mutex before acquiring the + MDL_lock::m_rwlock, can determine that this object was moved to the + unused objects list (or destroyed) while it held no locks by comparing + the version value which it read while holding the MDL_map::m_mutex + with the value read after acquiring the MDL_lock::m_rwlock. + Note that since it takes several years to overflow this counter such + theoretically possible overflows should not have any practical effects. + */ + ulonglong m_version; }; @@ -462,6 +502,26 @@ public: : MDL_lock(key_arg) { } + /** + Reset unused MDL_object_lock object to represent the lock context for a + different object. + */ + void reset(const MDL_key *new_key) + { + /* We need to change only object's key. */ + key.mdl_key_init(new_key); + /* m_granted and m_waiting should be already in the empty/initial state. */ + DBUG_ASSERT(is_empty()); + /* Object should not be marked as destroyed. */ + DBUG_ASSERT(! m_is_destroyed); + /* + Values of the rest of the fields should be preserved between old and + new versions of the object. E.g., m_version and m_ref_usage/release + should be kept intact to properly handle possible remaining references + to the old version of the object. + */ + } + virtual const bitmap_t *incompatible_granted_types_bitmap() const { return m_granted_incompatible; @@ -479,10 +539,29 @@ public: private: static const bitmap_t m_granted_incompatible[MDL_TYPE_END]; static const bitmap_t m_waiting_incompatible[MDL_TYPE_END]; + +public: + /** Members for linking the object into the list of unused objects. */ + MDL_object_lock *next_in_cache, **prev_in_cache; +}; + + +/** + Helper class for linking MDL_object_lock objects into the unused objects list. +*/ +class MDL_object_lock_cache_adapter : + public I_P_List_adapter +{ }; static MDL_map mdl_locks; +/** + Start-up parameter for the maximum size of the unused MDL_lock objects cache. +*/ +ulong mdl_locks_cache_size; + extern "C" { @@ -565,6 +644,10 @@ void MDL_map::destroy() my_hash_free(&m_locks); MDL_lock::destroy(m_global_lock); MDL_lock::destroy(m_commit_lock); + + MDL_object_lock *lock; + while ((lock= m_unused_locks_cache.pop_front())) + MDL_lock::destroy(lock); } @@ -614,11 +697,49 @@ retry: mdl_key->ptr(), mdl_key->length()))) { - lock= MDL_lock::create(mdl_key); + MDL_object_lock *unused_lock= NULL; + + /* + No lock object found so we need to create a new one + or reuse an existing unused object. + */ + if (mdl_key->mdl_namespace() != MDL_key::SCHEMA && + m_unused_locks_cache.elements()) + { + /* + We need a MDL_object_lock type of object and the unused objects + cache has some. Get the first object from the cache and set a new + key for it. + */ + DBUG_ASSERT(mdl_key->mdl_namespace() != MDL_key::GLOBAL && + mdl_key->mdl_namespace() != MDL_key::COMMIT); + + unused_lock= m_unused_locks_cache.pop_front(); + unused_lock->reset(mdl_key); + + lock= unused_lock; + } + else + { + lock= MDL_lock::create(mdl_key); + } + if (!lock || my_hash_insert(&m_locks, (uchar*)lock)) { + if (unused_lock) + { + /* + Note that we can't easily destroy an object from cache here as it + still might be referenced by other threads. So we simply put it + back into the cache. + */ + m_unused_locks_cache.push_front(unused_lock); + } + else + { + MDL_lock::destroy(lock); + } mysql_mutex_unlock(&m_mutex); - MDL_lock::destroy(lock); return NULL; } } @@ -633,7 +754,7 @@ retry: /** Release mdl_locks.m_mutex mutex and lock MDL_lock::m_rwlock for lock object from the hash. Handle situation when object was released - while the held no mutex. + while we held no locks. @retval FALSE - Success. @retval TRUE - Object was released while we held no mutex, caller @@ -642,6 +763,8 @@ retry: bool MDL_map::move_from_hash_to_lock_mutex(MDL_lock *lock) { + ulonglong version; + DBUG_ASSERT(! lock->m_is_destroyed); mysql_mutex_assert_owner(&m_mutex); @@ -651,26 +774,50 @@ bool MDL_map::move_from_hash_to_lock_mutex(MDL_lock *lock) m_is_destroyed is FALSE. */ lock->m_ref_usage++; + /* Read value of the version counter under protection of m_mutex lock. */ + version= lock->m_version; mysql_mutex_unlock(&m_mutex); mysql_prlock_wrlock(&lock->m_rwlock); lock->m_ref_release++; - if (unlikely(lock->m_is_destroyed)) + + if (unlikely(lock->m_version != version)) { /* - Object was released while we held no mutex, we need to - release it if no others hold references to it, while our own - reference count ensured that the object as such haven't got - its memory released yet. We can also safely compare - m_ref_usage and m_ref_release since the object is no longer - present in the hash so no one will be able to find it and - increment m_ref_usage anymore. + If the current value of version differs from one that was read while + we held m_mutex mutex, this MDL_lock object was moved to the unused + objects list or destroyed while we held no locks. + We should retry our search. But first we should destroy the MDL_lock + object if necessary. */ - uint ref_usage= lock->m_ref_usage; - uint ref_release= lock->m_ref_release; - mysql_prlock_unlock(&lock->m_rwlock); - if (ref_usage == ref_release) - MDL_lock::destroy(lock); + if (unlikely(lock->m_is_destroyed)) + { + /* + Object was released while we held no locks, we need to + release it if no others hold references to it, while our own + reference count ensured that the object as such haven't got + its memory released yet. We can also safely compare + m_ref_usage and m_ref_release since the object is no longer + present in the hash (or unused objects list) so no one will + be able to find it and increment m_ref_usage anymore. + */ + uint ref_usage= lock->m_ref_usage; + uint ref_release= lock->m_ref_release; + mysql_prlock_unlock(&lock->m_rwlock); + if (ref_usage == ref_release) + MDL_lock::destroy(lock); + } + else + { + /* + Object was not destroyed but its version has changed. + This means that it was moved to the unused objects list + (and even might be already re-used). So now it might + correspond to a different key, therefore we should simply + retry our search. + */ + mysql_prlock_unlock(&lock->m_rwlock); + } return TRUE; } return FALSE; @@ -685,8 +832,6 @@ bool MDL_map::move_from_hash_to_lock_mutex(MDL_lock *lock) void MDL_map::remove(MDL_lock *lock) { - uint ref_usage, ref_release; - if (lock->key.mdl_namespace() == MDL_key::GLOBAL || lock->key.mdl_namespace() == MDL_key::COMMIT) { @@ -698,31 +843,65 @@ void MDL_map::remove(MDL_lock *lock) return; } - /* - Destroy the MDL_lock object, but ensure that anyone that is - holding a reference to the object is not remaining, if so he - has the responsibility to release it. - - Setting of m_is_destroyed to TRUE while holding _both_ - mdl_locks.m_mutex and MDL_lock::m_rwlock mutexes transfers the - protection of m_ref_usage from mdl_locks.m_mutex to - MDL_lock::m_rwlock while removal of object from the hash makes - it read-only. Therefore whoever acquires MDL_lock::m_rwlock next - will see most up to date version of m_ref_usage. - - This means that when m_is_destroyed is TRUE and we hold the - MDL_lock::m_rwlock we can safely read the m_ref_usage - member. - */ mysql_mutex_lock(&m_mutex); my_hash_delete(&m_locks, (uchar*) lock); - lock->m_is_destroyed= TRUE; - ref_usage= lock->m_ref_usage; - ref_release= lock->m_ref_release; - mysql_prlock_unlock(&lock->m_rwlock); - mysql_mutex_unlock(&m_mutex); - if (ref_usage == ref_release) - MDL_lock::destroy(lock); + /* + To let threads holding references to the MDL_lock object know that it was + moved to the list of unused objects or destroyed, we increment the version + counter under protection of both MDL_map::m_mutex and MDL_lock::m_rwlock + locks. This allows us to read the version value while having either one + of those locks. + */ + lock->m_version++; + + if ((lock->key.mdl_namespace() != MDL_key::SCHEMA) && + (m_unused_locks_cache.elements() < mdl_locks_cache_size)) + { + /* + This is an object of MDL_object_lock type and the cache of unused + objects has not reached its maximum size yet. So instead of destroying + object we move it to the list of unused objects to allow its later + re-use with possibly different key. Any threads holding references to + this object (owning MDL_map::m_mutex or MDL_lock::m_rwlock) will notice + this thanks to the fact that we have changed the MDL_lock::m_version + counter. + */ + DBUG_ASSERT(lock->key.mdl_namespace() != MDL_key::GLOBAL && + lock->key.mdl_namespace() != MDL_key::COMMIT); + + m_unused_locks_cache.push_front((MDL_object_lock*)lock); + mysql_mutex_unlock(&m_mutex); + mysql_prlock_unlock(&lock->m_rwlock); + } + else + { + /* + Destroy the MDL_lock object, but ensure that anyone that is + holding a reference to the object is not remaining, if so he + has the responsibility to release it. + + Setting of m_is_destroyed to TRUE while holding _both_ + mdl_locks.m_mutex and MDL_lock::m_rwlock mutexes transfers the + protection of m_ref_usage from mdl_locks.m_mutex to + MDL_lock::m_rwlock while removal of the object from the hash + (and cache of unused objects) makes it read-only. Therefore + whoever acquires MDL_lock::m_rwlock next will see the most up + to date version of m_ref_usage. + + This means that when m_is_destroyed is TRUE and we hold the + MDL_lock::m_rwlock we can safely read the m_ref_usage + member. + */ + uint ref_usage, ref_release; + + lock->m_is_destroyed= TRUE; + ref_usage= lock->m_ref_usage; + ref_release= lock->m_ref_release; + mysql_mutex_unlock(&m_mutex); + mysql_prlock_unlock(&lock->m_rwlock); + if (ref_usage == ref_release) + MDL_lock::destroy(lock); + } } @@ -820,9 +999,6 @@ void MDL_request::init(const MDL_key *key_arg, Auxiliary functions needed for creation/destruction of MDL_lock objects. @note Also chooses an MDL_lock descendant appropriate for object namespace. - - @todo This naive implementation should be replaced with one that saves - on memory allocation by reusing released objects. */ inline MDL_lock *MDL_lock::create(const MDL_key *mdl_key) diff --git a/sql/mdl.h b/sql/mdl.h index fb2de45b831..5c1af23f5e2 100644 --- a/sql/mdl.h +++ b/sql/mdl.h @@ -851,4 +851,12 @@ extern "C" void thd_exit_cond(MYSQL_THD thd, const char *old_msg); extern mysql_mutex_t LOCK_open; #endif + +/* + Start-up parameter for the maximum size of the unused MDL_lock objects cache + and a constant for its default value. +*/ +extern ulong mdl_locks_cache_size; +static const ulong MDL_LOCKS_CACHE_SIZE_DEFAULT = 1024; + #endif diff --git a/sql/sql_plist.h b/sql/sql_plist.h index ca1d15f3015..2b6f1067321 100644 --- a/sql/sql_plist.h +++ b/sql/sql_plist.h @@ -128,6 +128,15 @@ public: } inline T* front() { return m_first; } inline const T *front() const { return m_first; } + inline T* pop_front() + { + T *result= front(); + + if (result) + remove(result); + + return result; + } void swap(I_P_List &rhs) { swap_variables(T *, m_first, rhs.m_first); diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index da8e61da52e..7a04015dc93 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -1156,6 +1156,12 @@ static Sys_var_ulonglong Sys_max_heap_table_size( VALID_RANGE(16384, (ulonglong)~(intptr)0), DEFAULT(16*1024*1024), BLOCK_SIZE(1024)); +static Sys_var_ulong Sys_metadata_locks_cache_size( + "metadata_locks_cache_size", "Size of unused metadata locks cache", + READ_ONLY GLOBAL_VAR(mdl_locks_cache_size), CMD_LINE(REQUIRED_ARG), + VALID_RANGE(1, 1024*1024), DEFAULT(MDL_LOCKS_CACHE_SIZE_DEFAULT), + BLOCK_SIZE(1)); + static Sys_var_ulong Sys_pseudo_thread_id( "pseudo_thread_id", "This variable is for internal server use", From 8fe4023e518aa372557bff4cc8dcc56c9227f5b3 Mon Sep 17 00:00:00 2001 From: Luis Soares Date: Wed, 16 Nov 2011 01:18:03 +0000 Subject: [PATCH 087/288] BUG#11760927 Follow-up patch to fix valgrind warnings. --- sql/rpl_rli.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index 0000ba9abb7..3371406ba65 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -52,7 +52,8 @@ Relay_log_info::Relay_log_info(bool is_slave_recovery) inited(0), abort_slave(0), slave_running(0), until_condition(UNTIL_NONE), until_log_pos(0), retried_trans(0), tables_to_lock(0), tables_to_lock_count(0), - last_event_start_time(0), m_flags(0) + last_event_start_time(0), m_flags(0), row_stmt_start_timestamp(0), + long_find_row_note_printed(false) { DBUG_ENTER("Relay_log_info::Relay_log_info"); From e36692d0c2fdfb70d1af530232a7f4ac4485e9df Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 17 Nov 2011 09:13:43 +0100 Subject: [PATCH 088/288] fix for bug 11748060/34981 --- scripts/mysqld_safe.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/mysqld_safe.sh b/scripts/mysqld_safe.sh index a537bf27aad..0d2045a65a6 100644 --- a/scripts/mysqld_safe.sh +++ b/scripts/mysqld_safe.sh @@ -464,6 +464,9 @@ export MYSQL_HOME if test -x "$MY_BASEDIR_VERSION/bin/my_print_defaults" then print_defaults="$MY_BASEDIR_VERSION/bin/my_print_defaults" +elif test -x `dirname $0`/my_print_defaults +then + print_defaults="`dirname $0`/my_print_defaults" elif test -x ./bin/my_print_defaults then print_defaults="./bin/my_print_defaults" From 1f8efaccd442af8e08a8f663893f4aee6dbbfefb Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Thu, 17 Nov 2011 12:34:52 +0100 Subject: [PATCH 089/288] Bug#13101974 SLAVE CAN'T CONNECT AS REPLICATION USER USING WINDOWS AUTH PLUGIN Problem was that built-in client-side support for Windows Native Authentication (WNA) was included only in the client library, but not into the server code (which also uses some of the sources from the client library). This is fixed by modyfying sql/CMakeLists.txt to include the client-side WNA plugin library and enable WNA related code by defining AUTHENTICATION_WIN macro. Also, the logic of libmysql/CMakeLists.txt is simplified a bit. --- libmysql/CMakeLists.txt | 16 ++++++++-------- sql/CMakeLists.txt | 9 ++++++++- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/libmysql/CMakeLists.txt b/libmysql/CMakeLists.txt index d0e383c6640..42125cffb7b 100644 --- a/libmysql/CMakeLists.txt +++ b/libmysql/CMakeLists.txt @@ -134,12 +134,6 @@ CACHE INTERNAL "Functions exported by client API" ) -IF(WIN32) - ADD_SUBDIRECTORY(authentication_win) - SET(WITH_AUTHENTICATION_WIN 1) - ADD_DEFINITIONS(-DAUTHENTICATION_WIN) -ENDIF(WIN32) - SET(CLIENT_SOURCES get_password.c libmysql.c @@ -157,9 +151,15 @@ ADD_DEPENDENCIES(clientlib GenError) SET(LIBS clientlib dbug strings vio mysys ${ZLIB_LIBRARY} ${SSL_LIBRARIES} ${LIBDL}) -IF(WITH_AUTHENTICATION_WIN) +# +# On Windows platform client library includes the client-side +# Windows Native Authentication plugin. +# +IF(WIN32) + ADD_DEFINITIONS(-DAUTHENTICATION_WIN) + ADD_SUBDIRECTORY(authentication_win) LIST(APPEND LIBS auth_win_client) -ENDIF(WITH_AUTHENTICATION_WIN) +ENDIF() # Merge several convenience libraries into one big mysqlclient # and link them together into shared library. diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index fb86d1ce60f..2e02e67c2c9 100644 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -90,7 +90,14 @@ TARGET_LINK_LIBRARIES(sql ${MYSQLD_STATIC_PLUGIN_LIBS} ${LIBWRAP} ${LIBCRYPT} ${LIBDL} ${SSL_LIBRARIES}) - +# +# On Windows platform we compile in the clinet-side Windows Native Authentication +# plugin which is used by the client connection code included in the server. +# +IF(WIN32) + ADD_DEFINITIONS(-DAUTHENTICATION_WIN) + TARGET_LINK_LIBRARIES(sql auth_win_client) +ENDIF() IF(WIN32) SET(MYSQLD_SOURCE main.cc nt_servc.cc nt_servc.h message.rc) From 523c849d14acf041670337afa6a7e2a6deeaab67 Mon Sep 17 00:00:00 2001 From: Jorgen Loland Date: Fri, 18 Nov 2011 14:47:11 +0100 Subject: [PATCH 090/288] Backmerge of BUG#12997905 --- sql/field.h | 17 +++++++++++++++++ sql/field_conv.cc | 2 +- sql/sql_select.cc | 3 +++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/sql/field.h b/sql/field.h index 8db965a8270..ca23702fd8c 100644 --- a/sql/field.h +++ b/sql/field.h @@ -2128,6 +2128,23 @@ public: uchar *from_null_ptr,*to_null_ptr; my_bool *null_row; uint from_bit,to_bit; + /** + Number of bytes in the fields pointed to by 'from_ptr' and + 'to_ptr'. Usually this is the number of bytes that are copied from + 'from_ptr' to 'to_ptr'. + + For variable-length fields (VARCHAR), the first byte(s) describe + the actual length of the text. For VARCHARs with length + < 256 there is 1 length byte + >= 256 there is 2 length bytes + Thus, if from_field is VARCHAR(10), from_length (and in most cases + to_length) is 11. For VARCHAR(1024), the length is 1026. @see + Field_varstring::length_bytes + + Note that for VARCHARs, do_copy() will be do_varstring*() which + only copies the length-bytes (1 or 2) + the actual length of the + text instead of from/to_length bytes. @see get_copy_func() + */ uint from_length,to_length; Field *from_field,*to_field; String tmp; // For items diff --git a/sql/field_conv.cc b/sql/field_conv.cc index 1dc7ec57944..ff56a1fdda8 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -707,7 +707,7 @@ Copy_field::get_copy_func(Field *to,Field *from) if (((Field_varstring*) to)->length_bytes != ((Field_varstring*) from)->length_bytes) return do_field_string; - if (to_length != from_length) + else return (((Field_varstring*) to)->length_bytes == 1 ? (from->charset()->mbmaxlen == 1 ? do_varstring1 : do_varstring1_mb) : diff --git a/sql/sql_select.cc b/sql/sql_select.cc index bf0cd7c9db8..72c826ff32d 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -10647,6 +10647,9 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, if (open_tmp_table(table)) goto err; + // Make empty record so random data is not written to disk + empty_record(table); + thd->mem_root= mem_root_save; DBUG_RETURN(table); From f28e7bd0645d478d33d7ae3b974931c7991cd0bd Mon Sep 17 00:00:00 2001 From: Inaam Rana Date: Fri, 18 Nov 2011 10:59:10 -0500 Subject: [PATCH 091/288] Bug#13390506 - VALGRIND FAILURE AFTER THE FIX FOR 13371000 rb://816 approved by: Marko Makela The title is misleading. This bug was actually introduced by bug 12635227 and was unearthed by a later optimization. We need to free buf_page_t structs that we are allocating using malloc() at shutdown. --- .../r/innodb_cmp_drop_table.result | 13 ++++ .../t/innodb_cmp_drop_table-master.opt | 1 + .../t/innodb_cmp_drop_table.test | 59 +++++++++++++++++++ storage/innodb_plugin/buf/buf0buf.c | 18 ++++++ 4 files changed, 91 insertions(+) create mode 100644 mysql-test/suite/innodb_plugin/r/innodb_cmp_drop_table.result create mode 100644 mysql-test/suite/innodb_plugin/t/innodb_cmp_drop_table-master.opt create mode 100644 mysql-test/suite/innodb_plugin/t/innodb_cmp_drop_table.test diff --git a/mysql-test/suite/innodb_plugin/r/innodb_cmp_drop_table.result b/mysql-test/suite/innodb_plugin/r/innodb_cmp_drop_table.result new file mode 100644 index 00000000000..bae2a17bd02 --- /dev/null +++ b/mysql-test/suite/innodb_plugin/r/innodb_cmp_drop_table.result @@ -0,0 +1,13 @@ +set global innodb_file_per_table=on; +set global innodb_file_format=`1`; +create table t1(a text) engine=innodb key_block_size=8; +SELECT page_size FROM information_schema.innodb_cmpmem WHERE pages_used > 0; +page_size +8192 +drop table t1; +SELECT page_size FROM information_schema.innodb_cmpmem WHERE pages_used > 0; +page_size +create table t2(a text) engine=innodb; +SELECT page_size FROM information_schema.innodb_cmpmem WHERE pages_used > 0; +page_size +drop table t2; diff --git a/mysql-test/suite/innodb_plugin/t/innodb_cmp_drop_table-master.opt b/mysql-test/suite/innodb_plugin/t/innodb_cmp_drop_table-master.opt new file mode 100644 index 00000000000..a9a3d8c3db8 --- /dev/null +++ b/mysql-test/suite/innodb_plugin/t/innodb_cmp_drop_table-master.opt @@ -0,0 +1 @@ +--innodb-buffer-pool-size=8M diff --git a/mysql-test/suite/innodb_plugin/t/innodb_cmp_drop_table.test b/mysql-test/suite/innodb_plugin/t/innodb_cmp_drop_table.test new file mode 100644 index 00000000000..b40ab526615 --- /dev/null +++ b/mysql-test/suite/innodb_plugin/t/innodb_cmp_drop_table.test @@ -0,0 +1,59 @@ +-- source include/have_innodb_plugin.inc + +let $per_table=`select @@innodb_file_per_table`; +let $format=`select @@innodb_file_format`; + +-- let $query_i_s = SELECT page_size FROM information_schema.innodb_cmpmem WHERE pages_used > 0 + +set global innodb_file_per_table=on; +set global innodb_file_format=`1`; + +create table t1(a text) engine=innodb key_block_size=8; + +-- disable_query_log + +# insert some rows so we are using compressed pages +-- let $i = 10 +while ($i) +{ + insert into t1 values(repeat('abcdefghijklmnopqrstuvwxyz',100)); + dec $i; +} +-- enable_query_log + +# we should be using some 8K pages +-- eval $query_i_s + +drop table t1; + +# no lazy eviction at drop table in 5.1 there should still be no +# used 8K pages +-- eval $query_i_s + +# create a non-compressed table and insert enough into it to evict +# compressed pages +create table t2(a text) engine=innodb; + +-- disable_query_log + +-- let $i = 200 +while ($i) +{ + insert into t2 values(repeat('abcdefghijklmnopqrstuvwxyz',1000)); + dec $i; +} + +-- enable_query_log + +# now there should be no 8K pages in the buffer pool +-- eval $query_i_s + +drop table t2; + +# +# restore environment to the state it was before this test execution +# + +-- disable_query_log +eval set global innodb_file_format=$format; +eval set global innodb_file_per_table=$per_table; diff --git a/storage/innodb_plugin/buf/buf0buf.c b/storage/innodb_plugin/buf/buf0buf.c index 7d03f08f61f..d88860b807b 100644 --- a/storage/innodb_plugin/buf/buf0buf.c +++ b/storage/innodb_plugin/buf/buf0buf.c @@ -946,6 +946,24 @@ buf_pool_free(void) { 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. */ + ut_ad(state == BUF_BLOCK_ZIP_PAGE); + buf_page_free_descriptor(bpage); + } + + bpage = prev_bpage; + } chunks = buf_pool->chunks; chunk = chunks + buf_pool->n_chunks; From a8e291cca8a29d66975e285750f2c1f415c418ca Mon Sep 17 00:00:00 2001 From: Inaam Rana Date: Fri, 18 Nov 2011 11:20:17 -0500 Subject: [PATCH 092/288] merge bug#13390506 from mysql-5.1 --- .../innodb/r/innodb_cmp_drop_table.result | 13 ++++ .../innodb/t/innodb_cmp_drop_table-master.opt | 1 + .../suite/innodb/t/innodb_cmp_drop_table.test | 59 +++++++++++++++++++ storage/innobase/buf/buf0buf.c | 18 ++++++ 4 files changed, 91 insertions(+) create mode 100644 mysql-test/suite/innodb/r/innodb_cmp_drop_table.result create mode 100644 mysql-test/suite/innodb/t/innodb_cmp_drop_table-master.opt create mode 100644 mysql-test/suite/innodb/t/innodb_cmp_drop_table.test diff --git a/mysql-test/suite/innodb/r/innodb_cmp_drop_table.result b/mysql-test/suite/innodb/r/innodb_cmp_drop_table.result new file mode 100644 index 00000000000..bae2a17bd02 --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_cmp_drop_table.result @@ -0,0 +1,13 @@ +set global innodb_file_per_table=on; +set global innodb_file_format=`1`; +create table t1(a text) engine=innodb key_block_size=8; +SELECT page_size FROM information_schema.innodb_cmpmem WHERE pages_used > 0; +page_size +8192 +drop table t1; +SELECT page_size FROM information_schema.innodb_cmpmem WHERE pages_used > 0; +page_size +create table t2(a text) engine=innodb; +SELECT page_size FROM information_schema.innodb_cmpmem WHERE pages_used > 0; +page_size +drop table t2; diff --git a/mysql-test/suite/innodb/t/innodb_cmp_drop_table-master.opt b/mysql-test/suite/innodb/t/innodb_cmp_drop_table-master.opt new file mode 100644 index 00000000000..a9a3d8c3db8 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_cmp_drop_table-master.opt @@ -0,0 +1 @@ +--innodb-buffer-pool-size=8M diff --git a/mysql-test/suite/innodb/t/innodb_cmp_drop_table.test b/mysql-test/suite/innodb/t/innodb_cmp_drop_table.test new file mode 100644 index 00000000000..481ccd646f8 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_cmp_drop_table.test @@ -0,0 +1,59 @@ +-- source include/have_innodb.inc + +let $per_table=`select @@innodb_file_per_table`; +let $format=`select @@innodb_file_format`; + +-- let $query_i_s = SELECT page_size FROM information_schema.innodb_cmpmem WHERE pages_used > 0 + +set global innodb_file_per_table=on; +set global innodb_file_format=`1`; + +create table t1(a text) engine=innodb key_block_size=8; + +-- disable_query_log + +# insert some rows so we are using compressed pages +-- let $i = 10 +while ($i) +{ + insert into t1 values(repeat('abcdefghijklmnopqrstuvwxyz',100)); + dec $i; +} +-- enable_query_log + +# we should be using some 8K pages +-- eval $query_i_s + +drop table t1; + +# no lazy eviction at drop table in 5.1 and 5.5 there should be no +# used 8K pages +-- eval $query_i_s + +# create a non-compressed table and insert enough into it to evict +# compressed pages +create table t2(a text) engine=innodb; + +-- disable_query_log + +-- let $i = 200 +while ($i) +{ + insert into t2 values(repeat('abcdefghijklmnopqrstuvwxyz',1000)); + dec $i; +} + +-- enable_query_log + +# now there should be no 8K pages in the buffer pool +-- eval $query_i_s + +drop table t2; + +# +# restore environment to the state it was before this test execution +# + +-- disable_query_log +eval set global innodb_file_format=$format; +eval set global innodb_file_per_table=$per_table; diff --git a/storage/innobase/buf/buf0buf.c b/storage/innobase/buf/buf0buf.c index 1fcc2107f18..50f90b0918a 100644 --- a/storage/innobase/buf/buf0buf.c +++ b/storage/innobase/buf/buf0buf.c @@ -1219,6 +1219,24 @@ 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. */ + ut_ad(state == BUF_BLOCK_ZIP_PAGE); + buf_page_free_descriptor(bpage); + } + + bpage = prev_bpage; + } chunks = buf_pool->chunks; chunk = chunks + buf_pool->n_chunks; From 5f3d3cdbf5c8126f14c51a386ffc66f82c6224e4 Mon Sep 17 00:00:00 2001 From: Jimmy Yang Date: Sun, 20 Nov 2011 18:21:20 -0800 Subject: [PATCH 093/288] Fix Bug #13405367 - 60212 SERVER CRASH WITH CORRUPT FETCH BUFFER rb://608 approved by Sunny Bains --- storage/innobase/row/row0mysql.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c index d06411e09f0..987d6595224 100644 --- a/storage/innobase/row/row0mysql.c +++ b/storage/innobase/row/row0mysql.c @@ -289,21 +289,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; } } From 04b1eeb19536f170cb4f71d203969f42600de9d0 Mon Sep 17 00:00:00 2001 From: Sneha Modi Date: Mon, 21 Nov 2011 10:59:28 +0530 Subject: [PATCH 094/288] Bug#11748572:ALLOCATING A LARGE QUERY CACHE IS NOT DETERMINISTIC Setting query_cache_size to larger values might fail depending on the memory pressure being put on the system. This can be seen on pushbuild as the test case query_cache_size_basic tries to allocate a +3GB query cache, which succeeds in some machines and fails in others. So this part of the code where the test case tries to allocate +3GB query cache has been disabled for now to get the test running on pb2. --- mysql-test/collections/default.experimental | 2 ++ .../sys_vars/inc/query_cache_size_basic.inc | 9 +++++-- .../r/query_cache_size_basic_32.result | 24 +++++++++++-------- .../r/query_cache_size_basic_64.result | 22 +++++++++++------ mysql-test/suite/sys_vars/t/disabled.def | 2 -- 5 files changed, 38 insertions(+), 21 deletions(-) diff --git a/mysql-test/collections/default.experimental b/mysql-test/collections/default.experimental index b3623402065..f528f1c473e 100644 --- a/mysql-test/collections/default.experimental +++ b/mysql-test/collections/default.experimental @@ -24,4 +24,6 @@ sys_vars.wait_timeout_func # Bug#11750645 2010-04-26 alik wai sys_vars.ndb_log_update_as_write_basic sys_vars.have_ndbcluster_basic sys_vars.ndb_log_updated_only_basic +sys_vars.query_cache_size_basic_64 # Bug#11748572 - 36747: ALLOCATING A LARGE QUERY CACHE IS NOT DETERMINISTIC +sys_vars.query_cache_size_basic_32 # Bug#11748572 - 36747: ALLOCATING A LARGE QUERY CACHE IS NOT DETERMINISTIC sys_vars.rpl_init_slave_func # Bug#12535301 2011-05-09 andrei sys_vars.rpl_init_slave_func mismatches in daily-5.5 diff --git a/mysql-test/suite/sys_vars/inc/query_cache_size_basic.inc b/mysql-test/suite/sys_vars/inc/query_cache_size_basic.inc index 83edefaaf25..2b1021eb8e7 100644 --- a/mysql-test/suite/sys_vars/inc/query_cache_size_basic.inc +++ b/mysql-test/suite/sys_vars/inc/query_cache_size_basic.inc @@ -80,8 +80,13 @@ SELECT @@global.query_cache_size; SET @@global.query_cache_size = -1; SELECT @@global.query_cache_size; -SET @@global.query_cache_size = 4294967296; -SELECT @@global.query_cache_size; + +# +# Bug 11748572 - 36747: ALLOCATING A LARGE QUERY CACHE IS NOT DETERMINISTIC +# +# SET @@global.query_cache_size = 4294967296; +# SELECT @@global.query_cache_size; + SET @@global.query_cache_size = 511; SELECT @@global.query_cache_size; --Error ER_WRONG_TYPE_FOR_VAR diff --git a/mysql-test/suite/sys_vars/r/query_cache_size_basic_32.result b/mysql-test/suite/sys_vars/r/query_cache_size_basic_32.result index 5ceb02182b3..6edaf22302a 100644 --- a/mysql-test/suite/sys_vars/r/query_cache_size_basic_32.result +++ b/mysql-test/suite/sys_vars/r/query_cache_size_basic_32.result @@ -1,6 +1,8 @@ SET @start_value = @@global.query_cache_size; '#--------------------FN_DYNVARS_133_01------------------------#' SET @@global.query_cache_size = 99; +Warnings: +Warning 1292 Truncated incorrect query_cache_size value: '99' SET @@global.query_cache_size = DEFAULT; SELECT @@global.query_cache_size; @@global.query_cache_size @@ -16,10 +18,14 @@ SELECT @@global.query_cache_size; @@global.query_cache_size 0 SET @@global.query_cache_size = 1; +Warnings: +Warning 1292 Truncated incorrect query_cache_size value: '1' SELECT @@global.query_cache_size; @@global.query_cache_size 0 SET @@global.query_cache_size = 512; +Warnings: +Warning 1292 Truncated incorrect query_cache_size value: '512' SELECT @@global.query_cache_size; @@global.query_cache_size 0 @@ -29,13 +35,13 @@ Warning 1282 Query cache failed to set size 1024; new query cache size is 0 SELECT @@global.query_cache_size; @@global.query_cache_size 0 -: 'Bug#34880: Warnings are coming on assinging valid values to variable -'Bug# 34877: Invalid Values are coming in variable on assigning valid values'; SET @@global.query_cache_size = 1048576; SELECT @@global.query_cache_size; @@global.query_cache_size 1048576 SET @@global.query_cache_size = 1048575; +Warnings: +Warning 1292 Truncated incorrect query_cache_size value: '1048575' SELECT @@global.query_cache_size; @@global.query_cache_size 1047552 @@ -46,14 +52,9 @@ Warning 1292 Truncated incorrect query_cache_size value: '-1' SELECT @@global.query_cache_size; @@global.query_cache_size 0 -SET @@global.query_cache_size = 4294967296; -Warnings: -Warning 1292 Truncated incorrect query_cache_size value: '4294967296' -Warning 1282 Query cache failed to set size 4294966272; new query cache size is 0 -SELECT @@global.query_cache_size; -@@global.query_cache_size -0 SET @@global.query_cache_size = 511; +Warnings: +Warning 1292 Truncated incorrect query_cache_size value: '511' SELECT @@global.query_cache_size; @@global.query_cache_size 0 @@ -75,7 +76,6 @@ Warning 1282 Query cache failed to set size 4294966272; new query cache size is SELECT @@global.query_cache_size; @@global.query_cache_size 0 -'Bug # 34837: Errors are not coming on assigning invalid values to variable'; SET @@global.query_cache_size = ON; ERROR 42000: Incorrect argument type to variable 'query_cache_size' SELECT @@global.query_cache_size; @@ -105,6 +105,8 @@ WHERE VARIABLE_NAME='query_cache_size'; 1 '#---------------------FN_DYNVARS_133_07----------------------#' SET @@global.query_cache_size = TRUE; +Warnings: +Warning 1292 Truncated incorrect query_cache_size value: '1' SELECT @@global.query_cache_size; @@global.query_cache_size 0 @@ -114,6 +116,8 @@ SELECT @@global.query_cache_size; 0 '#---------------------FN_DYNVARS_133_08----------------------#' SET @@global.query_cache_size = 1; +Warnings: +Warning 1292 Truncated incorrect query_cache_size value: '1' SELECT @@query_cache_size = @@global.query_cache_size; @@query_cache_size = @@global.query_cache_size 1 diff --git a/mysql-test/suite/sys_vars/r/query_cache_size_basic_64.result b/mysql-test/suite/sys_vars/r/query_cache_size_basic_64.result index c6d7999677f..4f18a8af651 100644 --- a/mysql-test/suite/sys_vars/r/query_cache_size_basic_64.result +++ b/mysql-test/suite/sys_vars/r/query_cache_size_basic_64.result @@ -1,6 +1,8 @@ SET @start_value = @@global.query_cache_size; '#--------------------FN_DYNVARS_133_01------------------------#' SET @@global.query_cache_size = 99; +Warnings: +Warning 1292 Truncated incorrect query_cache_size value: '99' SET @@global.query_cache_size = DEFAULT; SELECT @@global.query_cache_size; @@global.query_cache_size @@ -16,10 +18,14 @@ SELECT @@global.query_cache_size; @@global.query_cache_size 0 SET @@global.query_cache_size = 1; +Warnings: +Warning 1292 Truncated incorrect query_cache_size value: '1' SELECT @@global.query_cache_size; @@global.query_cache_size 0 SET @@global.query_cache_size = 512; +Warnings: +Warning 1292 Truncated incorrect query_cache_size value: '512' SELECT @@global.query_cache_size; @@global.query_cache_size 0 @@ -29,13 +35,13 @@ Warning 1282 Query cache failed to set size 1024; new query cache size is 0 SELECT @@global.query_cache_size; @@global.query_cache_size 0 -: 'Bug#34880: Warnings are coming on assinging valid values to variable -'Bug# 34877: Invalid Values are coming in variable on assigning valid values'; SET @@global.query_cache_size = 1048576; SELECT @@global.query_cache_size; @@global.query_cache_size 1048576 SET @@global.query_cache_size = 1048575; +Warnings: +Warning 1292 Truncated incorrect query_cache_size value: '1048575' SELECT @@global.query_cache_size; @@global.query_cache_size 1047552 @@ -46,11 +52,9 @@ Warning 1292 Truncated incorrect query_cache_size value: '-1' SELECT @@global.query_cache_size; @@global.query_cache_size 0 -SET @@global.query_cache_size = 4294967296; -SELECT @@global.query_cache_size; -@@global.query_cache_size -4294967296 SET @@global.query_cache_size = 511; +Warnings: +Warning 1292 Truncated incorrect query_cache_size value: '511' SELECT @@global.query_cache_size; @@global.query_cache_size 0 @@ -67,11 +71,11 @@ SELECT @@global.query_cache_size; 0 SET @@global.query_cache_size = 42949672950; Warnings: +Warning 1292 Truncated incorrect query_cache_size value: '42949672950' Warning 1282 Query cache failed to set size 42949671936; new query cache size is 0 SELECT @@global.query_cache_size; @@global.query_cache_size 0 -'Bug # 34837: Errors are not coming on assigning invalid values to variable'; SET @@global.query_cache_size = ON; ERROR 42000: Incorrect argument type to variable 'query_cache_size' SELECT @@global.query_cache_size; @@ -101,6 +105,8 @@ WHERE VARIABLE_NAME='query_cache_size'; 1 '#---------------------FN_DYNVARS_133_07----------------------#' SET @@global.query_cache_size = TRUE; +Warnings: +Warning 1292 Truncated incorrect query_cache_size value: '1' SELECT @@global.query_cache_size; @@global.query_cache_size 0 @@ -110,6 +116,8 @@ SELECT @@global.query_cache_size; 0 '#---------------------FN_DYNVARS_133_08----------------------#' SET @@global.query_cache_size = 1; +Warnings: +Warning 1292 Truncated incorrect query_cache_size value: '1' SELECT @@query_cache_size = @@global.query_cache_size; @@query_cache_size = @@global.query_cache_size 1 diff --git a/mysql-test/suite/sys_vars/t/disabled.def b/mysql-test/suite/sys_vars/t/disabled.def index 1cabae00b6f..f950aaf9ca5 100644 --- a/mysql-test/suite/sys_vars/t/disabled.def +++ b/mysql-test/suite/sys_vars/t/disabled.def @@ -9,8 +9,6 @@ # Do not use any TAB characters for whitespace. # ############################################################################## -query_cache_size_basic_32 : Bug#11748572: Allocating a large query cache is not deterministic -query_cache_size_basic_64 : Bug#11748572: Allocating a large query cache is not deterministic transaction_prealloc_size_basic_32 : Bug#11748572 transaction_prealloc_size_basic_64 : Bug#11748572 #thread_cache_size_func : Bug#11750172: 2008-11-07 joro main.thread_cache_size_func fails in pushbuild when run with pool of threads From f7513f398b89a659f91fb9cec27e2f1b413a1e1c Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Mon, 21 Nov 2011 12:28:35 +0100 Subject: [PATCH 095/288] Followup to 11750417: Disable federated_plugin test for embedded, like other federated tests Also removed redundant include/not_embedded.inc from federated.test --- mysql-test/suite/federated/federated.test | 2 -- mysql-test/suite/federated/federated_plugin.test | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/mysql-test/suite/federated/federated.test b/mysql-test/suite/federated/federated.test index a1d86462c11..432e19a4a68 100644 --- a/mysql-test/suite/federated/federated.test +++ b/mysql-test/suite/federated/federated.test @@ -4,8 +4,6 @@ # -# should work with embedded server after mysqltest is fixed ---source include/not_embedded.inc --source federated.inc connection default; diff --git a/mysql-test/suite/federated/federated_plugin.test b/mysql-test/suite/federated/federated_plugin.test index 8c465095cfa..a0add3af8ff 100644 --- a/mysql-test/suite/federated/federated_plugin.test +++ b/mysql-test/suite/federated/federated_plugin.test @@ -1,3 +1,4 @@ +--source include/not_embedded.inc --source include/have_federated_plugin.inc # Uninstall will not uninstall if ps has been used From 7ee2962f192e21c0e30cf030e719e1396f7be1ad Mon Sep 17 00:00:00 2001 From: Sneha Modi Date: Mon, 21 Nov 2011 17:07:08 +0530 Subject: [PATCH 096/288] Bug#11748731:SOME 'BIG' TESTS FAILING ON 6.0 A patch for alter_table-big.test has been committed earlier. This is a patch for create-big.test: The test used to time-out after 900 seconds. It relied on debug sleeps that are no longer present in the code. Since the sleeps are long gone, fixing the problem didn't involve just updating the result file or using macro "show_binlog_events2.inc" instead of "show binlog events" statement. The test needed to be rewritten using debug sync points, and result then needed to be updated. So, the sleeps have been replaced by debug_sync points and the test execution time has been reduced significantly. --- mysql-test/r/create-big.result | 221 +++++++-------- mysql-test/t/create-big.test | 488 +++++++++++++++++++++------------ mysql-test/t/disabled.def | 1 - sql/sql_insert.cc | 8 +- sql/sql_table.cc | 5 + 5 files changed, 421 insertions(+), 302 deletions(-) diff --git a/mysql-test/r/create-big.result b/mysql-test/r/create-big.result index d062b59a008..34293d7e5cd 100644 --- a/mysql-test/r/create-big.result +++ b/mysql-test/r/create-big.result @@ -1,7 +1,10 @@ drop table if exists t1,t2,t3,t4,t5; -set session debug="+d,sleep_create_select_before_create"; +set debug_sync='RESET'; +set debug_sync='create_table_select_before_create SIGNAL parked WAIT_FOR go'; create table t1 select 1 as i;; -create table t1 (j char(5)); +set debug_sync='now WAIT_FOR parked'; +create table t1 (j char(5));; +set debug_sync='now SIGNAL go'; ERROR 42S01: Table 't1' already exists show create table t1; Table Create Table @@ -9,8 +12,11 @@ t1 CREATE TABLE `t1` ( `i` int(1) NOT NULL DEFAULT '0' ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; +set debug_sync='create_table_select_before_create SIGNAL parked WAIT_FOR go'; create table t1 select 1 as i;; -create table t1 select "Test" as j; +set debug_sync='now WAIT_FOR parked'; +create table t1 select 'Test' as j;; +set debug_sync='now SIGNAL go'; ERROR 42S01: Table 't1' already exists show create table t1; Table Create Table @@ -19,8 +25,11 @@ t1 CREATE TABLE `t1` ( ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; create table t3 (j char(5)); +set debug_sync='create_table_select_before_create SIGNAL parked WAIT_FOR go'; create table t1 select 1 as i;; -create table t1 like t3; +set debug_sync='now WAIT_FOR parked'; +create table t1 like t3;; +set debug_sync='now SIGNAL go'; ERROR 42S01: Table 't1' already exists show create table t1; Table Create Table @@ -28,8 +37,11 @@ t1 CREATE TABLE `t1` ( `i` int(1) NOT NULL DEFAULT '0' ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; +set debug_sync='create_table_select_before_create SIGNAL parked WAIT_FOR go'; create table t1 select 1 as i;; -rename table t3 to t1; +set debug_sync='now WAIT_FOR parked'; +rename table t3 to t1;; +set debug_sync='now SIGNAL go'; ERROR 42S01: Table 't1' already exists show create table t1; Table Create Table @@ -37,82 +49,117 @@ t1 CREATE TABLE `t1` ( `i` int(1) NOT NULL DEFAULT '0' ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; +set debug_sync='create_table_select_before_create SIGNAL parked WAIT_FOR go'; create table t1 select 1 as i;; +set debug_sync='now WAIT_FOR parked'; alter table t3 rename to t1; ERROR 42S01: Table 't1' already exists +set debug_sync='now SIGNAL go'; show create table t1; Table Create Table t1 CREATE TABLE `t1` ( `i` int(1) NOT NULL DEFAULT '0' ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; +set debug_sync='create_table_select_before_create SIGNAL parked WAIT_FOR go'; create table t1 select 1 as i;; +set debug_sync='now WAIT_FOR parked'; alter table t3 rename to t1, add k int; ERROR 42S01: Table 't1' already exists +set debug_sync='now SIGNAL go'; show create table t1; Table Create Table t1 CREATE TABLE `t1` ( `i` int(1) NOT NULL DEFAULT '0' ) ENGINE=MyISAM DEFAULT CHARSET=latin1 -drop table t1, t3; -set session debug="-d,sleep_create_select_before_create:+d,sleep_create_select_before_open"; +drop table t1,t3; +set debug_sync='create_table_select_before_open SIGNAL parked WAIT_FOR go'; +set debug_sync='create_table_select_before_open SIGNAL parked WAIT_FOR go'; create table t1 select 1 as i;; -drop table t1; +set debug_sync='now WAIT_FOR parked'; +drop table t1;; +set debug_sync='now SIGNAL go'; +set debug_sync='create_table_select_before_create SIGNAL parked WAIT_FOR go'; create table t1 select 1 as i;; -rename table t1 to t2; +set debug_sync='now WAIT_FOR parked'; +rename table t1 to t2;; +set debug_sync='now SIGNAL go'; drop table t2; +set debug_sync='create_table_select_before_create SIGNAL parked WAIT_FOR go'; create table t1 select 1 as i;; -select * from t1; +set debug_sync='now WAIT_FOR parked'; +select * from t1;; +set debug_sync='now SIGNAL go'; i 1 drop table t1; +set debug_sync='create_table_select_before_create SIGNAL parked WAIT_FOR go'; create table t1 select 1 as i;; -insert into t1 values (2); +set debug_sync='now WAIT_FOR parked'; +insert into t1 values (2);; +set debug_sync='now SIGNAL go'; select * from t1; i 1 2 drop table t1; set @a:=0; +set debug_sync='create_table_select_before_create SIGNAL parked WAIT_FOR go'; create table t1 select 1 as i;; -create trigger t1_bi before insert on t1 for each row set @a:=1; +set debug_sync='now WAIT_FOR parked'; +create trigger t1_bi before insert on t1 for each row set @a:=1;; +set debug_sync='now SIGNAL go'; select @a; @a 0 drop table t1; -set session debug="-d,sleep_create_select_before_open:+d,sleep_create_select_before_lock"; +set debug_sync='create_table_select_before_lock SIGNAL parked WAIT_FOR go'; create table t1 select 1 as i;; -drop table t1; +set debug_sync='now WAIT_FOR parked'; +drop table t1;; +set debug_sync='now SIGNAL go'; +set debug_sync='create_table_select_before_lock SIGNAL parked WAIT_FOR go'; create table t1 select 1 as i;; -rename table t1 to t2; +set debug_sync='now WAIT_FOR parked'; +rename table t1 to t2;; +set debug_sync='now SIGNAL go'; drop table t2; +set debug_sync='create_table_select_before_lock SIGNAL parked WAIT_FOR go'; create table t1 select 1 as i;; -select * from t1; +set debug_sync='now WAIT_FOR parked'; +select * from t1;; +set debug_sync='now SIGNAL go'; i 1 drop table t1; +set debug_sync='create_table_select_before_lock SIGNAL parked WAIT_FOR go'; create table t1 select 1 as i;; -insert into t1 values (2); +set debug_sync='now WAIT_FOR parked'; +insert into t1 values (2);; +set debug_sync='now SIGNAL go'; select * from t1; i 1 2 drop table t1; set @a:=0; +set debug_sync='create_table_select_before_lock SIGNAL parked WAIT_FOR go'; create table t1 select 1 as i;; -create trigger t1_bi before insert on t1 for each row set @a:=1; +set debug_sync='now WAIT_FOR parked'; +create trigger t1_bi before insert on t1 for each row set @a:=1;; +set debug_sync='now SIGNAL go'; select @a; @a 0 drop table t1; -set session debug="-d,sleep_create_select_before_lock:+d,sleep_create_select_before_check_if_exists"; -create table t1 (i int); +set debug_sync='create_table_select_before_check_if_exists SIGNAL parked WAIT_FOR go'; create table if not exists t1 select 1 as i;; -drop table t1; -Warnings: -Note 1050 Table 't1' already exists +set debug_sync='now WAIT_FOR parked'; +drop table t1;; +set debug_sync='now SIGNAL go'; create table t1 (i int); set @a:=0; +set debug_sync='create_table_select_before_check_if_exists SIGNAL parked WAIT_FOR go'; create table if not exists t1 select 1 as i;; create trigger t1_bi before insert on t1 for each row set @a:=1; Warnings: @@ -122,53 +169,17 @@ select @a; 0 select * from t1; i -1 drop table t1; -set session debug="-d,sleep_create_select_before_check_if_exists"; -create table t2 (a int); -create table t4 (b int); -lock table t4 write; -select 1; -1 -1 -create table t3 as select * from t4;; -create table t1 select * from t2, t3;; -unlock tables; -select * from t1; -a b -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `a` int(11) DEFAULT NULL, - `b` int(11) DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1 -drop table t1, t3; -lock table t4 read; -select 1; -1 -1 -rename table t4 to t3;; -create table if not exists t1 select 1 as i from t2, t3;; -create table t5 (j int); -rename table t5 to t1; -unlock tables; -Warnings: -Note 1050 Table 't1' already exists -select * from t1; -j -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `j` int(11) DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1 -drop table t1, t2, t3; drop table if exists t1,t2; +set debug_sync='RESET'; create table t1 (i int); -set session debug="+d,sleep_create_like_before_check_if_exists"; +set debug_sync='create_table_like_after_open SIGNAL parked WAIT_FOR go'; reset master; create table t2 like t1;; +set debug_sync='now WAIT_FOR parked'; insert into t1 values (1); -drop table t1; +drop table t1;; +set debug_sync='now SIGNAL go'; show create table t2; Table Create Table t2 CREATE TABLE `t2` ( @@ -177,71 +188,41 @@ t2 CREATE TABLE `t2` ( drop table t2; show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; insert into t1 values (1) +master-bin.000001 # Query # # COMMIT master-bin.000001 # Query # # use `test`; create table t2 like t1 -master-bin.000001 # Query # # use `test`; drop table t1 -master-bin.000001 # Query # # use `test`; drop table t2 +master-bin.000001 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ +master-bin.000001 # Query # # use `test`; DROP TABLE `t2` /* generated by server */ create table t1 (i int); -set session debug="-d,sleep_create_like_before_check_if_exists:+d,sleep_create_like_before_copy"; -create table t2 like t1;; -create table if not exists t2 (j int); -Warnings: -Note 1050 Table 't2' already exists -show create table t2; -Table Create Table -t2 CREATE TABLE `t2` ( - `i` int(11) DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1 -drop table t2; +set debug_sync='create_table_like_before_binlog SIGNAL parked WAIT_FOR go'; reset master; create table t2 like t1;; -drop table t1; -drop table t2; -show binlog events from ; -Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Query # # use `test`; create table t2 like t1 -master-bin.000001 # Query # # use `test`; drop table t1 -master-bin.000001 # Query # # use `test`; drop table t2 -create table t1 (i int); -set session debug="-d,sleep_create_like_before_copy:+d,sleep_create_like_before_ha_create"; -reset master; -create table t2 like t1;; -insert into t2 values (1); -drop table t2; -create table t2 like t1;; -drop table t2; -create table t2 like t1;; -drop table t1; +set debug_sync='now WAIT_FOR parked'; +insert into t2 values (1);; +set debug_sync='now SIGNAL go'; drop table t2; +set debug_sync='create_table_like_before_binlog SIGNAL parked WAIT_FOR go'; +create table t2 like t1;; +set debug_sync='now WAIT_FOR parked'; +drop table t2;; +set debug_sync='now SIGNAL go'; +set debug_sync='create_table_like_before_binlog SIGNAL parked WAIT_FOR go'; +create table t2 like t1;; +set debug_sync='now WAIT_FOR parked'; +drop table t1;; +set debug_sync='now SIGNAL go'; +drop table t2; +set debug_sync='RESET'; show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # use `test`; create table t2 like t1 +master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; insert into t2 values (1) -master-bin.000001 # Query # # use `test`; drop table t2 +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # use `test`; DROP TABLE `t2` /* generated by server */ master-bin.000001 # Query # # use `test`; create table t2 like t1 -master-bin.000001 # Query # # use `test`; drop table t2 +master-bin.000001 # Query # # use `test`; DROP TABLE `t2` /* generated by server */ master-bin.000001 # Query # # use `test`; create table t2 like t1 -master-bin.000001 # Query # # use `test`; drop table t1 -master-bin.000001 # Query # # use `test`; drop table t2 -create table t1 (i int); -set session debug="-d,sleep_create_like_before_ha_create:+d,sleep_create_like_before_binlogging"; -reset master; -create table t2 like t1;; -insert into t2 values (1); -drop table t2; -create table t2 like t1;; -drop table t2; -create table t2 like t1;; -drop table t1; -drop table t2; -show binlog events from ; -Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Query # # use `test`; create table t2 like t1 -master-bin.000001 # Query # # use `test`; insert into t2 values (1) -master-bin.000001 # Query # # use `test`; drop table t2 -master-bin.000001 # Query # # use `test`; create table t2 like t1 -master-bin.000001 # Query # # use `test`; drop table t2 -master-bin.000001 # Query # # use `test`; create table t2 like t1 -master-bin.000001 # Query # # use `test`; drop table t1 -master-bin.000001 # Query # # use `test`; drop table t2 -set session debug="-d,sleep_create_like_before_binlogging"; +master-bin.000001 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ +master-bin.000001 # Query # # use `test`; DROP TABLE `t2` /* generated by server */ diff --git a/mysql-test/t/create-big.test b/mysql-test/t/create-big.test index e1dfbbd4ac4..d487608f7e1 100644 --- a/mysql-test/t/create-big.test +++ b/mysql-test/t/create-big.test @@ -7,11 +7,13 @@ # # This test takes rather long time so let us run it only in --big-test mode --source include/big_test.inc -# We are using some debug-only features in this test ---source include/have_debug.inc +# We need the Debug Sync Facility. +--source include/have_debug_sync.inc # Some of tests below also use binlog to check that statements are # executed and logged in correct order --source include/have_binlog_format_mixed_or_statement.inc +# Save the initial number of concurrent sessions. +--source include/count_sessions.inc # Create auxilliary connections connect (addconroot1, localhost, root,,); @@ -22,7 +24,7 @@ connection default; --disable_warnings drop table if exists t1,t2,t3,t4,t5; --enable_warnings - +set debug_sync='RESET'; # # Tests for concurrency problems in CREATE TABLE ... SELECT @@ -34,244 +36,378 @@ drop table if exists t1,t2,t3,t4,t5; # What happens in situation when other statement messes with # table to be created before it is created ? # Concurrent CREATE TABLE -set session debug="+d,sleep_create_select_before_create"; +set debug_sync='create_table_select_before_create SIGNAL parked WAIT_FOR go'; --send create table t1 select 1 as i; connection addconroot1; ---sleep 2 ---error ER_TABLE_EXISTS_ERROR -create table t1 (j char(5)); +set debug_sync='now WAIT_FOR parked'; +--send create table t1 (j char(5)); +connection addconroot2; +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Waiting for table metadata lock" and + info = "create table t1 (j char(5))"; +--source include/wait_condition.inc +set debug_sync='now SIGNAL go'; connection default; --reap +connection addconroot1; +--error ER_TABLE_EXISTS_ERROR +--reap +connection default; show create table t1; drop table t1; + # Concurrent CREATE TABLE ... SELECT +set debug_sync='create_table_select_before_create SIGNAL parked WAIT_FOR go'; --send create table t1 select 1 as i; connection addconroot1; ---sleep 2 ---error ER_TABLE_EXISTS_ERROR -create table t1 select "Test" as j; +set debug_sync='now WAIT_FOR parked'; +--send create table t1 select 'Test' as j; +connection addconroot2; +# Wait until the above CREATE TABLE t1 is blocked due to CREATE +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Waiting for table metadata lock" and + info = "create table t1 select 'Test' as j"; +--source include/wait_condition.inc +set debug_sync='now SIGNAL go'; connection default; --reap +connection addconroot1; +--error ER_TABLE_EXISTS_ERROR +--reap +connection default; show create table t1; drop table t1; + # Concurrent CREATE TABLE LIKE create table t3 (j char(5)); +set debug_sync='create_table_select_before_create SIGNAL parked WAIT_FOR go'; --send create table t1 select 1 as i; connection addconroot1; ---sleep 2 ---error ER_TABLE_EXISTS_ERROR -create table t1 like t3; +set debug_sync='now WAIT_FOR parked'; +--send create table t1 like t3; +connection addconroot2; +# Wait until the above CREATE TABLE t1 is blocked due to CREATE +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Waiting for table metadata lock" and + info = "create table t1 like t3"; +--source include/wait_condition.inc +set debug_sync='now SIGNAL go'; connection default; --reap +connection addconroot1; +--error ER_TABLE_EXISTS_ERROR +--reap +connection default; show create table t1; drop table t1; + # Concurrent RENAME TABLE +set debug_sync='create_table_select_before_create SIGNAL parked WAIT_FOR go'; --send create table t1 select 1 as i; connection addconroot1; ---sleep 2 ---error ER_TABLE_EXISTS_ERROR -rename table t3 to t1; +set debug_sync='now WAIT_FOR parked'; +--send rename table t3 to t1; +connection addconroot2; +# Wait until the above RENAME TABLE is blocked due to CREATE +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Waiting for table metadata lock" and + info = "rename table t3 to t1"; +--source include/wait_condition.inc +set debug_sync='now SIGNAL go'; connection default; --reap +connection addconroot1; +--error ER_TABLE_EXISTS_ERROR +--reap +connection default; show create table t1; drop table t1; + # Concurrent ALTER TABLE RENAME +set debug_sync='create_table_select_before_create SIGNAL parked WAIT_FOR go'; --send create table t1 select 1 as i; connection addconroot1; ---sleep 2 +set debug_sync='now WAIT_FOR parked'; --error ER_TABLE_EXISTS_ERROR alter table t3 rename to t1; +set debug_sync='now SIGNAL go'; connection default; --reap +connection default; show create table t1; drop table t1; + # Concurrent ALTER TABLE RENAME which also adds column +set debug_sync='create_table_select_before_create SIGNAL parked WAIT_FOR go'; --send create table t1 select 1 as i; connection addconroot1; ---sleep 2 +set debug_sync='now WAIT_FOR parked'; --error ER_TABLE_EXISTS_ERROR alter table t3 rename to t1, add k int; +set debug_sync='now SIGNAL go'; connection default; --reap show create table t1; -drop table t1, t3; +drop table t1,t3; + # What happens if other statement sneaks in after the table # creation but before its opening ? -set session debug="-d,sleep_create_select_before_create:+d,sleep_create_select_before_open"; +set debug_sync='create_table_select_before_open SIGNAL parked WAIT_FOR go'; +connection default; + # Concurrent DROP TABLE +set debug_sync='create_table_select_before_open SIGNAL parked WAIT_FOR go'; --send create table t1 select 1 as i; connection addconroot1; ---sleep 2 -drop table t1; +set debug_sync='now WAIT_FOR parked'; +--send drop table t1; +connection addconroot2; +# Wait until the above DROP TABLE is blocked due to CREATE +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Waiting for table metadata lock" and + info = "drop table t1"; +--source include/wait_condition.inc +set debug_sync='now SIGNAL go'; connection default; --reap +connection addconroot1; +--reap +connection default; + # Concurrent RENAME TABLE +set debug_sync='create_table_select_before_create SIGNAL parked WAIT_FOR go'; --send create table t1 select 1 as i; connection addconroot1; ---sleep 2 -rename table t1 to t2; +set debug_sync='now WAIT_FOR parked'; +--send rename table t1 to t2; +connection addconroot2; +# Wait until the above RENAME TABLE is blocked due to CREATE +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Waiting for table metadata lock" and + info = "rename table t1 to t2"; +--source include/wait_condition.inc +set debug_sync='now SIGNAL go'; connection default; --reap +connection addconroot1; +--reap +connection default; drop table t2; + # Concurrent SELECT +set debug_sync='create_table_select_before_create SIGNAL parked WAIT_FOR go'; --send create table t1 select 1 as i; connection addconroot1; ---sleep 2 -select * from t1; +set debug_sync='now WAIT_FOR parked'; +--send select * from t1; +connection addconroot2; +# Wait until the above SELECT is blocked due to CREATE +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Waiting for table metadata lock" and + info = "select * from t1"; +--source include/wait_condition.inc +set debug_sync='now SIGNAL go'; connection default; --reap +connection addconroot1; +--reap +connection default; drop table t1; + # Concurrent INSERT +set debug_sync='create_table_select_before_create SIGNAL parked WAIT_FOR go'; --send create table t1 select 1 as i; connection addconroot1; ---sleep 2 -insert into t1 values (2); +set debug_sync='now WAIT_FOR parked'; +--send insert into t1 values (2); +connection addconroot2; +# Wait until the above INSERT is blocked due to CREATE +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Waiting for table metadata lock" and + info = "insert into t1 values (2)"; +--source include/wait_condition.inc +set debug_sync='now SIGNAL go'; connection default; --reap +connection addconroot1; +--reap +connection default; select * from t1; drop table t1; + # Concurrent CREATE TRIGGER set @a:=0; +set debug_sync='create_table_select_before_create SIGNAL parked WAIT_FOR go'; --send create table t1 select 1 as i; connection addconroot1; ---sleep 2 -create trigger t1_bi before insert on t1 for each row set @a:=1; +set debug_sync='now WAIT_FOR parked'; +--send create trigger t1_bi before insert on t1 for each row set @a:=1; +connection addconroot2; +# Wait until the above CREATE TRIGGER is blocked due to CREATE TABLE +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Waiting for table metadata lock" and + info = "create trigger t1_bi before insert on t1 for each row set @a:=1"; +--source include/wait_condition.inc +set debug_sync='now SIGNAL go'; connection default; --reap +connection addconroot1; +--reap +connection default; select @a; drop table t1; + # Okay, now the same tests for the potential gap between open and lock -set session debug="-d,sleep_create_select_before_open:+d,sleep_create_select_before_lock"; +set debug_sync='create_table_select_before_lock SIGNAL parked WAIT_FOR go'; + # Concurrent DROP TABLE --send create table t1 select 1 as i; connection addconroot1; ---sleep 2 -drop table t1; +set debug_sync='now WAIT_FOR parked'; +--send drop table t1; +connection addconroot2; +# Wait until the above DROP TABLE is blocked due to CREATE TABLE +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Waiting for table metadata lock" and + info = "drop table t1"; +--source include/wait_condition.inc +set debug_sync='now SIGNAL go'; connection default; --reap +connection addconroot1; +--reap +connection default; + # Concurrent RENAME TABLE +set debug_sync='create_table_select_before_lock SIGNAL parked WAIT_FOR go'; --send create table t1 select 1 as i; connection addconroot1; ---sleep 2 -rename table t1 to t2; +set debug_sync='now WAIT_FOR parked'; +--send rename table t1 to t2; +connection addconroot2; +# Wait until the above RENAME TABLE is blocked due to CREATE TABLE +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Waiting for table metadata lock" and + info = "rename table t1 to t2"; +--source include/wait_condition.inc +set debug_sync='now SIGNAL go'; connection default; --reap +connection addconroot1; +--reap +connection default; drop table t2; + # Concurrent SELECT +set debug_sync='create_table_select_before_lock SIGNAL parked WAIT_FOR go'; --send create table t1 select 1 as i; connection addconroot1; ---sleep 2 -select * from t1; +set debug_sync='now WAIT_FOR parked'; +--send select * from t1; +connection addconroot2; +# Wait until the above SELECT is blocked due to CREATE TABLE +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Waiting for table metadata lock" and + info = "select * from t1"; +--source include/wait_condition.inc +set debug_sync='now SIGNAL go'; connection default; --reap +connection addconroot1; +--reap +connection default; drop table t1; + # Concurrent INSERT +set debug_sync='create_table_select_before_lock SIGNAL parked WAIT_FOR go'; --send create table t1 select 1 as i; connection addconroot1; ---sleep 2 -insert into t1 values (2); +set debug_sync='now WAIT_FOR parked'; +--send insert into t1 values (2); +connection addconroot2; +# Wait until the above INSERT INTO t1 is blocked due to CREATE TABLE +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Waiting for table metadata lock" and + info = "insert into t1 values (2)"; +--source include/wait_condition.inc +set debug_sync='now SIGNAL go'; connection default; --reap +connection addconroot1; +--reap +connection default; select * from t1; drop table t1; + # Concurrent CREATE TRIGGER set @a:=0; +set debug_sync='create_table_select_before_lock SIGNAL parked WAIT_FOR go'; --send create table t1 select 1 as i; connection addconroot1; ---sleep 2 -create trigger t1_bi before insert on t1 for each row set @a:=1; +set debug_sync='now WAIT_FOR parked'; +--send create trigger t1_bi before insert on t1 for each row set @a:=1; +connection addconroot2; +# Wait until the above CREATE TRIGGER is blocked due to CREATE TABLE +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Waiting for table metadata lock" and + info = "create trigger t1_bi before insert on t1 for each row set @a:=1"; +--source include/wait_condition.inc +set debug_sync='now SIGNAL go'; connection default; --reap +connection addconroot1; +--reap +connection default; select @a; drop table t1; -# Some tests for case with existing table -set session debug="-d,sleep_create_select_before_lock:+d,sleep_create_select_before_check_if_exists"; -create table t1 (i int); + # Concurrent DROP TABLE +set debug_sync='create_table_select_before_check_if_exists SIGNAL parked WAIT_FOR go'; --send create table if not exists t1 select 1 as i; connection addconroot1; ---sleep 2 -drop table t1; +set debug_sync='now WAIT_FOR parked'; +--send drop table t1; +connection addconroot2; +# Wait until the above DROP TABLE is blocked due to CREATE TABLE +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Waiting for table metadata lock" and + info = "drop table t1"; +--source include/wait_condition.inc +set debug_sync='now SIGNAL go'; connection default; --reap -# Concurrent CREATE TRIGGER +connection addconroot1; +--reap +connection default; + +# Concurrent CREATE TRIGGER create table t1 (i int); set @a:=0; +set debug_sync='create_table_select_before_check_if_exists SIGNAL parked WAIT_FOR go'; --send create table if not exists t1 select 1 as i; connection addconroot1; ---sleep 2 create trigger t1_bi before insert on t1 for each row set @a:=1; connection default; --reap +connection default; select @a; select * from t1; drop table t1; -set session debug="-d,sleep_create_select_before_check_if_exists"; - - -# Test for some details of CREATE TABLE ... SELECT implementation. -# -# We check that create placeholder is handled properly if we have -# to reopen tables in open_tables(). -# This test heavily relies on current implementation of name-locking/ -# table cache so it may stop working if it changes. OTOH it such problem -# will serve as warning that such changes should not be done lightly. -create table t2 (a int); -create table t4 (b int); -connection addconroot2; -lock table t4 write; -select 1; -connection addconroot1; -# Create placeholder/name-lock for t3 ---send create table t3 as select * from t4; ---sleep 2 -connection default; -# This statement creates placeholder for t1, then opens t2, -# then meets name-lock for t3 and then reopens all tables ---send create table t1 select * from t2, t3; ---sleep 2 -connection addconroot2; -unlock tables; -connection addconroot1; ---reap -connection default; ---reap -select * from t1; -show create table t1; -drop table t1, t3; -# Now similar test which proves that we really temporarily -# remove placeholder when we reopen tables. -connection addconroot2; -lock table t4 read; -select 1; -connection addconroot1; -# Create name-lock for t3 ---send rename table t4 to t3; ---sleep 2 -connection default; -# This statement creates placeholder for t1, then opens t2, -# then meets name-lock for t3 and then reopens all tables ---send create table if not exists t1 select 1 as i from t2, t3; ---sleep 2 -connection addconroot3; -# We should be able to take name-lock on table t1 as we should not have -# open placeholder for it at this point (otherwise it is possible to -# come-up with situation which will lead to deadlock, e.g. think of -# concurrent CREATE TABLE t1 SELECT * FROM t2 and RENAME TABLE t2 TO t1) -create table t5 (j int); -# This statement takes name-lock on t1 and therefore proves -# that there is no active open placeholder for it. -rename table t5 to t1; -connection addconroot2; -unlock tables; -connection addconroot1; ---reap -connection default; ---reap -select * from t1; -show create table t1; -drop table t1, t2, t3; - # Tests for possible concurrency issues with CREATE TABLE ... LIKE # @@ -286,103 +422,101 @@ drop table t1, t2, t3; --disable_warnings drop table if exists t1,t2; --enable_warnings +set debug_sync='RESET'; # What happens if some statements sneak in right after we have -# opened source table ? +# acquired locks and opened source table ? create table t1 (i int); -set session debug="+d,sleep_create_like_before_check_if_exists"; +set debug_sync='create_table_like_after_open SIGNAL parked WAIT_FOR go'; # Reset binlog to have clear start reset master; --send create table t2 like t1; connection addconroot1; ---sleep 2 +set debug_sync='now WAIT_FOR parked'; # DML on source table should be allowed to run concurrently insert into t1 values (1); # And DDL should wait -drop table t1; +--send drop table t1; +connection addconroot2; +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Waiting for table metadata lock" and + info = "drop table t1"; +--source include/wait_condition.inc +set debug_sync='now SIGNAL go'; connection default; --reap +connection addconroot1; +--reap +connection default; show create table t2; drop table t2; # Let us check that statements were executed/binlogged in correct order source include/show_binlog_events.inc; -# Now let us check the gap between check for target table -# existance and copying of .frm file. +# Now check the gap between table creation and binlogging create table t1 (i int); -set session debug="-d,sleep_create_like_before_check_if_exists:+d,sleep_create_like_before_copy"; -# It should be impossible to create target table concurrently ---send create table t2 like t1; -connection addconroot1; ---sleep 2 -create table if not exists t2 (j int); -connection default; ---reap -show create table t2; -drop table t2; -# And concurrent DDL on the source table should be still disallowed +set debug_sync='create_table_like_before_binlog SIGNAL parked WAIT_FOR go'; reset master; --send create table t2 like t1; connection addconroot1; ---sleep 2 -drop table t1; +set debug_sync='now WAIT_FOR parked'; +--send insert into t2 values (1); +connection addconroot2; +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Waiting for table metadata lock" and + info = "insert into t2 values (1)"; +--source include/wait_condition.inc +set debug_sync='now SIGNAL go'; connection default; --reap -drop table t2; -source include/show_binlog_events.inc; -# And now he gap between copying of .frm file and ha_create_table() call. -create table t1 (i int); -set session debug="-d,sleep_create_like_before_copy:+d,sleep_create_like_before_ha_create"; -# Both DML and DDL on target table should wait till operation completes -reset master; +connection addconroot1; +--reap +connection default; +drop table t2; +set debug_sync='create_table_like_before_binlog SIGNAL parked WAIT_FOR go'; --send create table t2 like t1; connection addconroot1; ---sleep 2 -insert into t2 values (1); +set debug_sync='now WAIT_FOR parked'; +--send drop table t2; +connection addconroot2; +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Waiting for table metadata lock" and + info = "drop table t2"; +--source include/wait_condition.inc +set debug_sync='now SIGNAL go'; connection default; --reap -drop table t2; +connection addconroot1; +--reap +connection default; +set debug_sync='create_table_like_before_binlog SIGNAL parked WAIT_FOR go'; --send create table t2 like t1; connection addconroot1; ---sleep 2 -drop table t2; +set debug_sync='now WAIT_FOR parked'; +--send drop table t1; +connection addconroot2; +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Waiting for table metadata lock" and + info = "drop table t1"; +--source include/wait_condition.inc +set debug_sync='now SIGNAL go'; connection default; --reap -# Concurrent DDL on the source table still waits ---send create table t2 like t1; connection addconroot1; ---sleep 2 -drop table t1; -connection default; --reap +connection default; drop table t2; -source include/show_binlog_events.inc; +disconnect addconroot1; +disconnect addconroot2; +disconnect addconroot3; -# Finally we check the gap between ha_create_table() and binlogging -create table t1 (i int); -set session debug="-d,sleep_create_like_before_ha_create:+d,sleep_create_like_before_binlogging"; -reset master; ---send create table t2 like t1; -connection addconroot1; ---sleep 2 -insert into t2 values (1); -connection default; ---reap -drop table t2; ---send create table t2 like t1; -connection addconroot1; ---sleep 2 -drop table t2; -connection default; ---reap ---send create table t2 like t1; -connection addconroot1; ---sleep 2 -drop table t1; -connection default; ---reap -drop table t2; +set debug_sync='RESET'; source include/show_binlog_events.inc; - -set session debug="-d,sleep_create_like_before_binlogging"; +# Check that all connections opened by test cases in this file are really +# gone so execution of other tests won't be affected by their presence. +--source include/wait_until_count_sessions.inc diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index cb1de2cb0ff..81600642c15 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -12,7 +12,6 @@ lowercase_table3 : Bug#11762269 2010-06-30 alik main.lowercase_table3 on Mac OSX read_many_rows_innodb : Bug#11748886 2010-11-15 mattiasj report already exists sum_distinct-big : Bug#11764126 2010-11-15 mattiasj was not tested -create-big : Bug#11748731 2010-11-15 mattiasj was not tested archive-big : Bug#11817185 2011-03-10 Anitha Disabled since this leads to timeout on Solaris Sparc log_tables-big : Bug#11756699 2010-11-15 mattiasj report already exists mysql_embedded : Bug#12561297 2011-05-14 Anitha Dependent on PB2 changes - eventum#41836 diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index c061a3f472c..f47f1418b4b 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -3698,7 +3698,7 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, alter_info->create_list.push_back(cr_field); } - DBUG_EXECUTE_IF("sleep_create_select_before_create", my_sleep(6000000);); + DEBUG_SYNC(thd,"create_table_select_before_create"); /* Create and lock table. @@ -3722,7 +3722,7 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, create_info, alter_info, 0, select_field_count, NULL)) { - DBUG_EXECUTE_IF("sleep_create_select_before_open", my_sleep(6000000);); + DEBUG_SYNC(thd,"create_table_select_before_open"); if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE)) { @@ -3760,7 +3760,7 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, DBUG_RETURN(0); } - DBUG_EXECUTE_IF("sleep_create_select_before_lock", my_sleep(6000000);); + DEBUG_SYNC(thd,"create_table_select_before_lock"); table->reginfo.lock_type=TL_WRITE; hooks->prelock(&table, 1); // Call prelock hooks @@ -3868,7 +3868,7 @@ select_create::prepare(List &values, SELECT_LEX_UNIT *u) DBUG_ASSERT(create_table->table == NULL); - DBUG_EXECUTE_IF("sleep_create_select_before_check_if_exists", my_sleep(6000000);); + DEBUG_SYNC(thd,"create_table_select_before_check_if_exists"); if (!(table= create_table_from_items(thd, create_info, create_table, alter_info, &values, diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 5363737998b..be1e0d009a3 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -4555,6 +4555,8 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table, goto err; src_table->table->use_all_columns(); + DEBUG_SYNC(thd, "create_table_like_after_open"); + /* Fill HA_CREATE_INFO and Alter_info with description of source table. */ bzero((char*) &local_create_info, sizeof(local_create_info)); local_create_info.db_type= src_table->table->s->db_type(); @@ -4603,6 +4605,9 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table, thd->mdl_context.is_lock_owner(MDL_key::TABLE, table->db, table->table_name, MDL_EXCLUSIVE)); + + DEBUG_SYNC(thd, "create_table_like_before_binlog"); + /* We have to write the query before we unlock the tables. */ From 190ccd244be4ad48f1ead42878a4a5c5126adf2d Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 21 Nov 2011 13:20:15 +0100 Subject: [PATCH 097/288] Updated with changes from Percona Server 5.1.56-13, from lp:percona-server/5.1, tag Percona-Server-5.1.59-13.0. Merged: revid:ignacio.nin@percona.com-20111016133841-fzpr5s89n13ft1s1 --- ChangeLog | 102 ++++ Makefile.in | 1 - btr/btr0btr.c | 629 ++++++++++++++++++++- btr/btr0cur.c | 459 ++++++++++++--- btr/btr0pcur.c | 29 +- btr/btr0sea.c | 4 +- buf/buf0buddy.c | 483 +++++----------- buf/buf0buf.c | 1053 ++++++----------------------------- buf/buf0flu.c | 11 +- buf/buf0lru.c | 376 ++++++------- buf/buf0rea.c | 179 +++++- dict/dict0dict.c | 7 + dict/dict0load.c | 63 ++- dict/dict0mem.c | 9 + fil/fil0fil.c | 560 +++++++++++++++---- ha/hash0hash.c | 64 --- handler/ha_innodb.cc | 323 +++++++---- handler/ha_innodb.h | 11 +- handler/handler0alter.cc | 71 ++- handler/i_s.cc | 379 ++++++------- handler/innodb_patch_info.h | 1 - ibuf/ibuf0ibuf.c | 2 + include/btr0btr.h | 170 +++++- include/btr0cur.h | 31 +- include/btr0cur.ic | 4 +- include/btr0pcur.h | 21 +- include/btr0pcur.ic | 9 +- include/btr0types.h | 125 +++++ include/buf0buddy.h | 21 +- include/buf0buddy.ic | 37 +- include/buf0buf.h | 81 ++- include/buf0buf.ic | 74 ++- include/buf0lru.h | 23 +- include/buf0types.h | 17 +- include/dict0mem.h | 7 + include/fil0fil.h | 3 +- include/ha_prototypes.h | 10 + include/hash0hash.h | 49 -- include/mtr0mtr.h | 12 +- include/os0file.h | 3 +- include/os0proc.h | 28 - include/page0cur.ic | 5 +- include/page0page.h | 39 +- include/page0page.ic | 32 +- include/page0zip.h | 2 +- include/rem0rec.h | 14 +- include/rem0rec.ic | 41 +- include/row0row.h | 26 +- include/row0row.ic | 45 +- include/row0upd.ic | 4 +- include/srv0srv.h | 10 +- include/sync0arr.h | 7 +- include/sync0rw.ic | 10 +- include/sync0sync.h | 6 +- include/trx0sys.h | 13 +- include/trx0sys.ic | 24 +- include/trx0trx.h | 14 + include/trx0undo.h | 9 + include/univ.i | 7 +- include/ut0lst.h | 43 -- include/ut0mem.h | 39 +- include/ut0mem.ic | 23 +- lock/lock0lock.c | 25 + log/log0log.c | 17 +- log/log0recv.c | 5 +- mtr/mtr0mtr.c | 36 +- os/os0file.c | 87 ++- os/os0proc.c | 170 ------ page/page0cur.c | 27 +- page/page0page.c | 63 ++- page/page0zip.c | 206 +++---- que/que0que.c | 6 + rem/rem0rec.c | 10 +- row/row0ins.c | 73 ++- row/row0merge.c | 4 + row/row0mysql.c | 45 ++ row/row0row.c | 109 ++-- row/row0sel.c | 99 +++- row/row0upd.c | 86 ++- row/row0vers.c | 18 +- srv/srv0srv.c | 66 ++- srv/srv0start.c | 18 +- sync/sync0arr.c | 32 +- sync/sync0rw.c | 7 +- sync/sync0sync.c | 12 +- trx/trx0i_s.c | 2 +- trx/trx0rec.c | 6 +- trx/trx0sys.c | 10 + trx/trx0trx.c | 75 ++- trx/trx0undo.c | 25 + ut/ut0mem.c | 49 +- 91 files changed, 4375 insertions(+), 2967 deletions(-) diff --git a/ChangeLog b/ChangeLog index 102db3d7824..f873f3a24bd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,105 @@ +2011-08-08 The InnoDB Team + + * row/row0sel.c: + Fix Bug#12835650 VARCHAR maximum length performance impact + +2011-08-08 The InnoDB Team + + * handler/ha_innodb.cc: + Fix Bug#12770537 I_S.TABLES.DATA_LENGTH DOES NOT SHOW ON-DISK SIZE + FOR COMPRESSED INNODB + +2011-07-19 The InnoDB Team + + * buf/buf0buf.c, buf/buf0rea.c, handler/ha_innodb.cc, + include/buf0buf.h, include/buf0buf.ic, include/srv0srv.h, + srv/srv0srv.c: + Fix Bug#12356373 by reintroducing random readahead + +2011-06-30 The InnoDB Team + + * row/row0row.c: + Fix Bug#12637786 Wrong secondary index entries on CHAR and VARCHAR + columns in ROW_FORMAT=DYNAMIC and ROW_FORMAT=COMPRESSED + +2011-06-16 The InnoDB Team + + * btr/btr0cur.c, buf/buf0buddy.c, buf/buf0buf.c, buf/buf0lru.c, + include/buf0buddy.h, include/buf0buddy.ic, include/buf0buf.h, + include/buf0buf.ic, include/buf0lru.h, include/buf0types.h: + Fix Bug#61188 DROP TABLE extremely slow + +2011-06-16 The InnoDB Team + + * buf/buf0buddy.c, buf/buf0buf.c, buf/buf0flu.c, buf/buf0lru.c, + include/buf0buf.h, include/buf0lru.h: + Fix Bug#61341 buf_LRU_insert_zip_clean can be O(N) on LRU length + +2011-06-16 The InnoDB Team + + * page/page0zip.c, rem/rem0rec.c: + Fix Bug#61191 question about page_zip_available() + +2011-06-16 The InnoDB Team + + * btr/btr0btr.c, btr/btr0cur.c, include/btr0btr.h, include/btr0cur.h, + include/btr0cur.ic, include/buf0buf.h, include/buf0buf.ic, + include/page0cur.ic, include/page0page.h, include/page0page.ic, + include/sync0rw.ic, include/sync0sync.h, page/page0cur.c, + page/page0page.c, row/row0ins.c, row/row0upd.c, + sync/sync0rw.c, sync/sync0sync.c: + Fix Bug#12612184 Race condition after btr_cur_pessimistic_update() + +2011-06-09 The InnoDB Team + * btr/btr0cur.c, include/rem0rec.h, include/rem0rec.ic, + * row/row0row.c, row/row0vers.c, trx/trx0rec.c: + Instrumentation for Bug#12612184 Race condition in row_upd_clust_rec() + +2011-05-19 The InnoDB Team + + * row/row0row.c: + Fix Bug#12429576 Assertion failure on purge of column prefix index + +2011-04-07 The InnoDB Team + + * handler/ha_innodb.cc, handler/ha_innodb.h, handler/handler0alter.cc: + Fix Bug #52409 Assertion failure: long semaphore wait + +2011-04-07 The InnoDB Team + + * handler/ha_innodb.cc, include/trx0trx.h, include/trx0undo.h, + log/log0log.c, trx/trx0sys.c, trx/trx0trx.c, trx/trx0undo.c: + Fix Bug #59641 Prepared XA transaction in system after hard crash + causes future shutdown hang + +2011-03-30 The InnoDB Team + + * srv/srv0srv.c, sync/sync0arr.h, sync/sync0arr.c: + Fix Bug#11877216 InnoDB too eager to commit suicide on a busy server + +2011-03-15 The InnoDB Team + + * btr/btr0cur.c, page/page0zip.c: + Fix Bug#11849231 inflateInit() invoked without initializing all memory + +2011-02-28 The InnoDB Team + + * btr/btr0sea.c, buf/buf0buf.c, buf/buf0lru.c: + Fix Bug#58549 Race condition in buf_LRU_drop_page_hash_for_tablespace() + and compressed tables + +2011-02-15 The InnoDB Team + + * sync/sync0rw.c, innodb_bug59307.test: + Bug#59307 Valgrind: uninitialized value in + rw_lock_set_writer_id_and_recursion_flag() + +2011-02-14 The InnoDB Team + + * handler/handler0alter.cc: + Bug#59749 Enabling concurrent reads while creating non-primary + unique index gives failures + 2011-01-31 The InnoDB Team * btr/btr0cur.c, include/row0upd.h, diff --git a/Makefile.in b/Makefile.in index 1b5ca3b7a8b..df13d3c23f6 100644 --- a/Makefile.in +++ b/Makefile.in @@ -782,7 +782,6 @@ noinst_HEADERS = \ include/ut0vec.h \ include/ut0vec.ic \ include/ut0wqueue.h \ - handler/innodb_patch_info.h \ mem/mem0dbg.c EXTRA_LIBRARIES = libinnobase.a diff --git a/btr/btr0btr.c b/btr/btr0btr.c index 2fb14b06a7b..396ad422010 100644 --- a/btr/btr0btr.c +++ b/btr/btr0btr.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2010, 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 @@ -42,6 +42,560 @@ Created 6/2/1994 Heikki Tuuri #include "ibuf0ibuf.h" #include "trx0trx.h" +#ifdef UNIV_BLOB_DEBUG +# include "srv0srv.h" +# include "ut0rbt.h" + +/** TRUE when messages about index->blobs modification are enabled. */ +static ibool btr_blob_dbg_msg; + +/** Issue a message about an operation on index->blobs. +@param op operation +@param b the entry being subjected to the operation +@param ctx the context of the operation */ +#define btr_blob_dbg_msg_issue(op, b, ctx) \ + fprintf(stderr, op " %u:%u:%u->%u %s(%u,%u,%u)\n", \ + (b)->ref_page_no, (b)->ref_heap_no, \ + (b)->ref_field_no, (b)->blob_page_no, ctx, \ + (b)->owner, (b)->always_owner, (b)->del) + +/** Insert to index->blobs a reference to an off-page column. +@param index the index tree +@param b the reference +@param ctx context (for logging) */ +UNIV_INTERN +void +btr_blob_dbg_rbt_insert( +/*====================*/ + dict_index_t* index, /*!< in/out: index tree */ + const btr_blob_dbg_t* b, /*!< in: the reference */ + const char* ctx) /*!< in: context (for logging) */ +{ + if (btr_blob_dbg_msg) { + btr_blob_dbg_msg_issue("insert", b, ctx); + } + mutex_enter(&index->blobs_mutex); + rbt_insert(index->blobs, b, b); + mutex_exit(&index->blobs_mutex); +} + +/** Remove from index->blobs a reference to an off-page column. +@param index the index tree +@param b the reference +@param ctx context (for logging) */ +UNIV_INTERN +void +btr_blob_dbg_rbt_delete( +/*====================*/ + dict_index_t* index, /*!< in/out: index tree */ + const btr_blob_dbg_t* b, /*!< in: the reference */ + const char* ctx) /*!< in: context (for logging) */ +{ + if (btr_blob_dbg_msg) { + btr_blob_dbg_msg_issue("delete", b, ctx); + } + mutex_enter(&index->blobs_mutex); + ut_a(rbt_delete(index->blobs, b)); + mutex_exit(&index->blobs_mutex); +} + +/**************************************************************//** +Comparator for items (btr_blob_dbg_t) in index->blobs. +The key in index->blobs is (ref_page_no, ref_heap_no, ref_field_no). +@return negative, 0 or positive if *a<*b, *a=*b, *a>*b */ +static +int +btr_blob_dbg_cmp( +/*=============*/ + const void* a, /*!< in: first btr_blob_dbg_t to compare */ + const void* b) /*!< in: second btr_blob_dbg_t to compare */ +{ + const btr_blob_dbg_t* aa = a; + const btr_blob_dbg_t* bb = b; + + ut_ad(aa != NULL); + ut_ad(bb != NULL); + + if (aa->ref_page_no != bb->ref_page_no) { + return(aa->ref_page_no < bb->ref_page_no ? -1 : 1); + } + if (aa->ref_heap_no != bb->ref_heap_no) { + return(aa->ref_heap_no < bb->ref_heap_no ? -1 : 1); + } + if (aa->ref_field_no != bb->ref_field_no) { + return(aa->ref_field_no < bb->ref_field_no ? -1 : 1); + } + return(0); +} + +/**************************************************************//** +Add a reference to an off-page column to the index->blobs map. */ +UNIV_INTERN +void +btr_blob_dbg_add_blob( +/*==================*/ + const rec_t* rec, /*!< in: clustered index record */ + ulint field_no, /*!< in: off-page column number */ + ulint page_no, /*!< in: start page of the column */ + dict_index_t* index, /*!< in/out: index tree */ + const char* ctx) /*!< in: context (for logging) */ +{ + btr_blob_dbg_t b; + const page_t* page = page_align(rec); + + ut_a(index->blobs); + + b.blob_page_no = page_no; + b.ref_page_no = page_get_page_no(page); + b.ref_heap_no = page_rec_get_heap_no(rec); + b.ref_field_no = field_no; + ut_a(b.ref_field_no >= index->n_uniq); + b.always_owner = b.owner = TRUE; + b.del = FALSE; + ut_a(!rec_get_deleted_flag(rec, page_is_comp(page))); + btr_blob_dbg_rbt_insert(index, &b, ctx); +} + +/**************************************************************//** +Add to index->blobs any references to off-page columns from a record. +@return number of references added */ +UNIV_INTERN +ulint +btr_blob_dbg_add_rec( +/*=================*/ + const rec_t* rec, /*!< in: record */ + dict_index_t* index, /*!< in/out: index */ + const ulint* offsets,/*!< in: offsets */ + const char* ctx) /*!< in: context (for logging) */ +{ + ulint count = 0; + ulint i; + btr_blob_dbg_t b; + ibool del; + + ut_ad(rec_offs_validate(rec, index, offsets)); + + if (!rec_offs_any_extern(offsets)) { + return(0); + } + + b.ref_page_no = page_get_page_no(page_align(rec)); + b.ref_heap_no = page_rec_get_heap_no(rec); + del = (rec_get_deleted_flag(rec, rec_offs_comp(offsets)) != 0); + + for (i = 0; i < rec_offs_n_fields(offsets); i++) { + if (rec_offs_nth_extern(offsets, i)) { + ulint len; + const byte* field_ref = rec_get_nth_field( + rec, offsets, i, &len); + + ut_a(len != UNIV_SQL_NULL); + ut_a(len >= BTR_EXTERN_FIELD_REF_SIZE); + field_ref += len - BTR_EXTERN_FIELD_REF_SIZE; + + if (!memcmp(field_ref, field_ref_zero, + BTR_EXTERN_FIELD_REF_SIZE)) { + /* the column has not been stored yet */ + continue; + } + + b.ref_field_no = i; + b.blob_page_no = mach_read_from_4( + field_ref + BTR_EXTERN_PAGE_NO); + ut_a(b.ref_field_no >= index->n_uniq); + b.always_owner = b.owner + = !(field_ref[BTR_EXTERN_LEN] + & BTR_EXTERN_OWNER_FLAG); + b.del = del; + + btr_blob_dbg_rbt_insert(index, &b, ctx); + count++; + } + } + + return(count); +} + +/**************************************************************//** +Display the references to off-page columns. +This function is to be called from a debugger, +for example when a breakpoint on ut_dbg_assertion_failed is hit. */ +UNIV_INTERN +void +btr_blob_dbg_print( +/*===============*/ + const dict_index_t* index) /*!< in: index tree */ +{ + const ib_rbt_node_t* node; + + if (!index->blobs) { + return; + } + + /* We intentionally do not acquire index->blobs_mutex here. + This function is to be called from a debugger, and the caller + should make sure that the index->blobs_mutex is held. */ + + for (node = rbt_first(index->blobs); + node != NULL; node = rbt_next(index->blobs, node)) { + const btr_blob_dbg_t* b + = rbt_value(btr_blob_dbg_t, node); + fprintf(stderr, "%u:%u:%u->%u%s%s%s\n", + b->ref_page_no, b->ref_heap_no, b->ref_field_no, + b->blob_page_no, + b->owner ? "" : "(disowned)", + b->always_owner ? "" : "(has disowned)", + b->del ? "(deleted)" : ""); + } +} + +/**************************************************************//** +Remove from index->blobs any references to off-page columns from a record. +@return number of references removed */ +UNIV_INTERN +ulint +btr_blob_dbg_remove_rec( +/*====================*/ + const rec_t* rec, /*!< in: record */ + dict_index_t* index, /*!< in/out: index */ + const ulint* offsets,/*!< in: offsets */ + const char* ctx) /*!< in: context (for logging) */ +{ + ulint i; + ulint count = 0; + btr_blob_dbg_t b; + + ut_ad(rec_offs_validate(rec, index, offsets)); + + if (!rec_offs_any_extern(offsets)) { + return(0); + } + + b.ref_page_no = page_get_page_no(page_align(rec)); + b.ref_heap_no = page_rec_get_heap_no(rec); + + for (i = 0; i < rec_offs_n_fields(offsets); i++) { + if (rec_offs_nth_extern(offsets, i)) { + ulint len; + const byte* field_ref = rec_get_nth_field( + rec, offsets, i, &len); + + ut_a(len != UNIV_SQL_NULL); + ut_a(len >= BTR_EXTERN_FIELD_REF_SIZE); + field_ref += len - BTR_EXTERN_FIELD_REF_SIZE; + + b.ref_field_no = i; + b.blob_page_no = mach_read_from_4( + field_ref + BTR_EXTERN_PAGE_NO); + + switch (b.blob_page_no) { + case 0: + /* The column has not been stored yet. + The BLOB pointer must be all zero. + There cannot be a BLOB starting at + page 0, because page 0 is reserved for + the tablespace header. */ + ut_a(!memcmp(field_ref, field_ref_zero, + BTR_EXTERN_FIELD_REF_SIZE)); + /* fall through */ + case FIL_NULL: + /* the column has been freed already */ + continue; + } + + btr_blob_dbg_rbt_delete(index, &b, ctx); + count++; + } + } + + return(count); +} + +/**************************************************************//** +Check that there are no references to off-page columns from or to +the given page. Invoked when freeing or clearing a page. +@return TRUE when no orphan references exist */ +UNIV_INTERN +ibool +btr_blob_dbg_is_empty( +/*==================*/ + dict_index_t* index, /*!< in: index */ + ulint page_no) /*!< in: page number */ +{ + const ib_rbt_node_t* node; + ibool success = TRUE; + + if (!index->blobs) { + return(success); + } + + mutex_enter(&index->blobs_mutex); + + for (node = rbt_first(index->blobs); + node != NULL; node = rbt_next(index->blobs, node)) { + const btr_blob_dbg_t* b + = rbt_value(btr_blob_dbg_t, node); + + if (b->ref_page_no != page_no && b->blob_page_no != page_no) { + continue; + } + + fprintf(stderr, + "InnoDB: orphan BLOB ref%s%s%s %u:%u:%u->%u\n", + b->owner ? "" : "(disowned)", + b->always_owner ? "" : "(has disowned)", + b->del ? "(deleted)" : "", + b->ref_page_no, b->ref_heap_no, b->ref_field_no, + b->blob_page_no); + + if (b->blob_page_no != page_no || b->owner || !b->del) { + success = FALSE; + } + } + + mutex_exit(&index->blobs_mutex); + return(success); +} + +/**************************************************************//** +Count and process all references to off-page columns on a page. +@return number of references processed */ +UNIV_INTERN +ulint +btr_blob_dbg_op( +/*============*/ + const page_t* page, /*!< in: B-tree leaf page */ + const rec_t* rec, /*!< in: record to start from + (NULL to process the whole page) */ + dict_index_t* index, /*!< in/out: index */ + const char* ctx, /*!< in: context (for logging) */ + const btr_blob_dbg_op_f op) /*!< in: operation on records */ +{ + ulint count = 0; + mem_heap_t* heap = NULL; + ulint offsets_[REC_OFFS_NORMAL_SIZE]; + ulint* offsets = offsets_; + rec_offs_init(offsets_); + + ut_a(fil_page_get_type(page) == FIL_PAGE_INDEX); + ut_a(!rec || page_align(rec) == page); + + if (!index->blobs || !page_is_leaf(page) + || !dict_index_is_clust(index)) { + return(0); + } + + if (rec == NULL) { + rec = page_get_infimum_rec(page); + } + + do { + offsets = rec_get_offsets(rec, index, offsets, + ULINT_UNDEFINED, &heap); + count += op(rec, index, offsets, ctx); + rec = page_rec_get_next_const(rec); + } while (!page_rec_is_supremum(rec)); + + if (UNIV_LIKELY_NULL(heap)) { + mem_heap_free(heap); + } + + return(count); +} + +/**************************************************************//** +Count and add to index->blobs any references to off-page columns +from records on a page. +@return number of references added */ +UNIV_INTERN +ulint +btr_blob_dbg_add( +/*=============*/ + const page_t* page, /*!< in: rewritten page */ + dict_index_t* index, /*!< in/out: index */ + const char* ctx) /*!< in: context (for logging) */ +{ + btr_blob_dbg_assert_empty(index, page_get_page_no(page)); + + return(btr_blob_dbg_op(page, NULL, index, ctx, btr_blob_dbg_add_rec)); +} + +/**************************************************************//** +Count and remove from index->blobs any references to off-page columns +from records on a page. +Used when reorganizing a page, before copying the records. +@return number of references removed */ +UNIV_INTERN +ulint +btr_blob_dbg_remove( +/*================*/ + const page_t* page, /*!< in: b-tree page */ + dict_index_t* index, /*!< in/out: index */ + const char* ctx) /*!< in: context (for logging) */ +{ + ulint count; + + count = btr_blob_dbg_op(page, NULL, index, ctx, + btr_blob_dbg_remove_rec); + + /* Check that no references exist. */ + btr_blob_dbg_assert_empty(index, page_get_page_no(page)); + + return(count); +} + +/**************************************************************//** +Restore in index->blobs any references to off-page columns +Used when page reorganize fails due to compressed page overflow. */ +UNIV_INTERN +void +btr_blob_dbg_restore( +/*=================*/ + const page_t* npage, /*!< in: page that failed to compress */ + const page_t* page, /*!< in: copy of original page */ + dict_index_t* index, /*!< in/out: index */ + const char* ctx) /*!< in: context (for logging) */ +{ + ulint removed; + ulint added; + + ut_a(page_get_page_no(npage) == page_get_page_no(page)); + ut_a(page_get_space_id(npage) == page_get_space_id(page)); + + removed = btr_blob_dbg_remove(npage, index, ctx); + added = btr_blob_dbg_add(page, index, ctx); + ut_a(added == removed); +} + +/**************************************************************//** +Modify the 'deleted' flag of a record. */ +UNIV_INTERN +void +btr_blob_dbg_set_deleted_flag( +/*==========================*/ + const rec_t* rec, /*!< in: record */ + dict_index_t* index, /*!< in/out: index */ + const ulint* offsets,/*!< in: rec_get_offs(rec, index) */ + ibool del) /*!< in: TRUE=deleted, FALSE=exists */ +{ + const ib_rbt_node_t* node; + btr_blob_dbg_t b; + btr_blob_dbg_t* c; + ulint i; + + ut_ad(rec_offs_validate(rec, index, offsets)); + ut_a(dict_index_is_clust(index)); + ut_a(del == !!del);/* must be FALSE==0 or TRUE==1 */ + + if (!rec_offs_any_extern(offsets) || !index->blobs) { + + return; + } + + b.ref_page_no = page_get_page_no(page_align(rec)); + b.ref_heap_no = page_rec_get_heap_no(rec); + + for (i = 0; i < rec_offs_n_fields(offsets); i++) { + if (rec_offs_nth_extern(offsets, i)) { + ulint len; + const byte* field_ref = rec_get_nth_field( + rec, offsets, i, &len); + + ut_a(len != UNIV_SQL_NULL); + ut_a(len >= BTR_EXTERN_FIELD_REF_SIZE); + field_ref += len - BTR_EXTERN_FIELD_REF_SIZE; + + b.ref_field_no = i; + b.blob_page_no = mach_read_from_4( + field_ref + BTR_EXTERN_PAGE_NO); + + switch (b.blob_page_no) { + case 0: + ut_a(memcmp(field_ref, field_ref_zero, + BTR_EXTERN_FIELD_REF_SIZE)); + /* page number 0 is for the + page allocation bitmap */ + case FIL_NULL: + /* the column has been freed already */ + ut_error; + } + + mutex_enter(&index->blobs_mutex); + node = rbt_lookup(index->blobs, &b); + ut_a(node); + + c = rbt_value(btr_blob_dbg_t, node); + /* The flag should be modified. */ + c->del = del; + if (btr_blob_dbg_msg) { + b = *c; + mutex_exit(&index->blobs_mutex); + btr_blob_dbg_msg_issue("del_mk", &b, ""); + } else { + mutex_exit(&index->blobs_mutex); + } + } + } +} + +/**************************************************************//** +Change the ownership of an off-page column. */ +UNIV_INTERN +void +btr_blob_dbg_owner( +/*===============*/ + const rec_t* rec, /*!< in: record */ + dict_index_t* index, /*!< in/out: index */ + const ulint* offsets,/*!< in: rec_get_offs(rec, index) */ + ulint i, /*!< in: ith field in rec */ + ibool own) /*!< in: TRUE=owned, FALSE=disowned */ +{ + const ib_rbt_node_t* node; + btr_blob_dbg_t b; + const byte* field_ref; + ulint len; + + ut_ad(rec_offs_validate(rec, index, offsets)); + ut_a(rec_offs_nth_extern(offsets, i)); + + field_ref = rec_get_nth_field(rec, offsets, i, &len); + ut_a(len != UNIV_SQL_NULL); + ut_a(len >= BTR_EXTERN_FIELD_REF_SIZE); + field_ref += len - BTR_EXTERN_FIELD_REF_SIZE; + + b.ref_page_no = page_get_page_no(page_align(rec)); + b.ref_heap_no = page_rec_get_heap_no(rec); + b.ref_field_no = i; + b.owner = !(field_ref[BTR_EXTERN_LEN] & BTR_EXTERN_OWNER_FLAG); + b.blob_page_no = mach_read_from_4(field_ref + BTR_EXTERN_PAGE_NO); + + ut_a(b.owner == own); + + mutex_enter(&index->blobs_mutex); + node = rbt_lookup(index->blobs, &b); + /* row_ins_clust_index_entry_by_modify() invokes + btr_cur_unmark_extern_fields() also for the newly inserted + references, which are all zero bytes until the columns are stored. + The node lookup must fail if and only if that is the case. */ + ut_a(!memcmp(field_ref, field_ref_zero, BTR_EXTERN_FIELD_REF_SIZE) + == !node); + + if (node) { + btr_blob_dbg_t* c = rbt_value(btr_blob_dbg_t, node); + /* Some code sets ownership from TRUE to TRUE. + We do not allow changing ownership from FALSE to FALSE. */ + ut_a(own || c->owner); + + c->owner = own; + if (!own) { + c->always_owner = FALSE; + } + } + + mutex_exit(&index->blobs_mutex); +} +#endif /* UNIV_BLOB_DEBUG */ + /* Latching strategy of the InnoDB B-tree -------------------------------------- @@ -289,7 +843,7 @@ btr_get_next_user_rec( /**************************************************************//** Creates a new index page (not the root, and also not used in page reorganization). @see btr_page_empty(). */ -static +UNIV_INTERN void btr_page_create( /*============*/ @@ -302,6 +856,7 @@ btr_page_create( page_t* page = buf_block_get_frame(block); ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); + btr_blob_dbg_assert_empty(index, buf_block_get_page_no(block)); if (UNIV_LIKELY_NULL(page_zip)) { page_create_zip(block, index, level, mtr); @@ -501,6 +1056,7 @@ btr_page_free_low( modify clock */ buf_block_modify_clock_inc(block); + btr_blob_dbg_assert_empty(index, buf_block_get_page_no(block)); if (dict_index_is_ibuf(index)) { @@ -785,6 +1341,13 @@ btr_create( block = buf_page_get(space, zip_size, page_no, RW_X_LATCH, mtr); } else { +#ifdef UNIV_BLOB_DEBUG + if ((type & DICT_CLUSTERED) && !index->blobs) { + mutex_create(&index->blobs_mutex, SYNC_ANY_LATCH); + index->blobs = rbt_create(sizeof(btr_blob_dbg_t), + btr_blob_dbg_cmp); + } +#endif /* UNIV_BLOB_DEBUG */ block = fseg_create(space, 0, PAGE_HEADER + PAGE_BTR_SEG_TOP, mtr); } @@ -1026,6 +1589,7 @@ btr_page_reorganize_low( block->check_index_page_at_flush = TRUE; #endif /* !UNIV_HOTBACKUP */ + btr_blob_dbg_remove(page, index, "btr_page_reorganize"); /* Recreate the page: note that global data on page (possible segment headers, next page-field, etc.) is preserved intact */ @@ -1054,6 +1618,8 @@ btr_page_reorganize_low( (!page_zip_compress(page_zip, page, index, NULL))) { /* Restore the old page and exit. */ + btr_blob_dbg_restore(page, temp_page, index, + "btr_page_reorganize_compress_fail"); #if defined UNIV_DEBUG || defined UNIV_ZIP_DEBUG /* Check that the bytes that we skip are identical. */ @@ -1168,7 +1734,7 @@ btr_parse_page_reorganize( #ifndef UNIV_HOTBACKUP /*************************************************************//** Empties an index page. @see btr_page_create(). */ -static +UNIV_INTERN void btr_page_empty( /*===========*/ @@ -1187,6 +1753,7 @@ btr_page_empty( #endif /* UNIV_ZIP_DEBUG */ 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 segment headers, next page-field, etc.) is preserved intact */ @@ -1729,13 +2296,13 @@ btr_insert_on_non_leaf_level_func( /**************************************************************//** Attaches the halves of an index page on the appropriate level in an index tree. */ -static +UNIV_INTERN void btr_attach_half_pages( /*==================*/ dict_index_t* index, /*!< in: the index tree */ buf_block_t* block, /*!< in/out: page to be split */ - rec_t* split_rec, /*!< in: first record on upper + const rec_t* split_rec, /*!< in: first record on upper half page */ buf_block_t* new_block, /*!< in/out: the new half page */ ulint direction, /*!< in: FSP_UP or FSP_DOWN */ @@ -2427,15 +2994,16 @@ btr_node_ptr_delete( ut_a(err == DB_SUCCESS); if (!compressed) { - btr_cur_compress_if_useful(&cursor, mtr); + btr_cur_compress_if_useful(&cursor, FALSE, mtr); } } /*************************************************************//** If page is the only on its level, this function moves its records to the -father page, thus reducing the tree height. */ +father page, thus reducing the tree height. +@return father block */ static -void +buf_block_t* btr_lift_page_up( /*=============*/ dict_index_t* index, /*!< in: index tree */ @@ -2527,6 +3095,7 @@ btr_lift_page_up( index); } + btr_blob_dbg_remove(page, index, "btr_lift_page_up"); lock_update_copy_and_discard(father_block, block); /* Go upward to root page, decrementing levels by one. */ @@ -2551,6 +3120,8 @@ btr_lift_page_up( } ut_ad(page_validate(father_page, index)); ut_ad(btr_check_node_ptr(index, father_block, mtr)); + + return(father_block); } /*************************************************************//** @@ -2567,11 +3138,13 @@ UNIV_INTERN ibool btr_compress( /*=========*/ - btr_cur_t* cursor, /*!< in: cursor on the page to merge or lift; - the page must not be empty: in record delete - use btr_discard_page if the page would become - empty */ - mtr_t* mtr) /*!< in: mtr */ + btr_cur_t* cursor, /*!< in/out: cursor on the page to merge + or lift; the page must not be empty: + when deleting records, use btr_discard_page() + if the page would become empty */ + ibool adjust, /*!< in: TRUE if should adjust the + cursor position even if compression occurs */ + mtr_t* mtr) /*!< in/out: mini-transaction */ { dict_index_t* index; ulint space; @@ -2589,12 +3162,14 @@ btr_compress( ulint* offsets; ulint data_size; ulint n_recs; + ulint nth_rec = 0; /* remove bogus warning */ ulint max_ins_size; ulint max_ins_size_reorg; block = btr_cur_get_block(cursor); page = btr_cur_get_page(cursor); index = btr_cur_get_index(cursor); + ut_a((ibool) !!page_is_comp(page) == dict_table_is_comp(index->table)); ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index), @@ -2615,6 +3190,10 @@ btr_compress( offsets = btr_page_get_father_block(NULL, heap, index, block, mtr, &father_cursor); + if (adjust) { + nth_rec = page_rec_get_n_recs_before(btr_cur_get_rec(cursor)); + } + /* Decide the page to which we try to merge and which will inherit the locks */ @@ -2641,9 +3220,9 @@ btr_compress( } else { /* The page is the only one on the level, lift the records to the father */ - btr_lift_page_up(index, block, mtr); - mem_heap_free(heap); - return(TRUE); + + merge_block = btr_lift_page_up(index, block, mtr); + goto func_exit; } n_recs = page_get_n_recs(page); @@ -2725,6 +3304,10 @@ err_exit: btr_node_ptr_delete(index, block, mtr); lock_update_merge_left(merge_block, orig_pred, block); + + if (adjust) { + nth_rec += page_rec_get_n_recs_before(orig_pred); + } } else { rec_t* orig_succ; #ifdef UNIV_BTR_DEBUG @@ -2788,7 +3371,7 @@ err_exit: lock_update_merge_right(merge_block, orig_succ, block); } - mem_heap_free(heap); + btr_blob_dbg_remove(page, index, "btr_compress"); if (!dict_index_is_clust(index) && page_is_leaf(merge_page)) { /* Update the free bits of the B-tree page in the @@ -2840,6 +3423,16 @@ err_exit: btr_page_free(index, block, mtr); ut_ad(btr_check_node_ptr(index, merge_block, mtr)); +func_exit: + mem_heap_free(heap); + + if (adjust) { + btr_cur_position( + index, + page_rec_get_nth(merge_block->frame, nth_rec), + merge_block, cursor); + } + return(TRUE); } @@ -3018,6 +3611,8 @@ btr_discard_page( block); } + btr_blob_dbg_remove(page, index, "btr_discard_page"); + /* Free the file page */ btr_page_free(index, block, mtr); diff --git a/btr/btr0cur.c b/btr/btr0cur.c index 9b306ea2864..0a352bfded3 100644 --- a/btr/btr0cur.c +++ b/btr/btr0cur.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2010, Innobase Oy. All Rights Reserved. +Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, Google Inc. Portions of this file contain modifications contributed and copyrighted by @@ -1046,6 +1046,11 @@ btr_cur_ins_lock_and_undo( rec_t* rec; roll_ptr_t roll_ptr; + if (thr && thr_get_trx(thr)->fake_changes) { + /* skip LOCK, UNDO */ + return(DB_SUCCESS); + } + /* Check if we have to wait for a lock: enqueue an explicit lock request if yes */ @@ -1177,7 +1182,7 @@ btr_cur_optimistic_insert( } #endif /* UNIV_DEBUG */ - ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); + ut_ad((thr && thr_get_trx(thr)->fake_changes) || mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); max_size = page_get_max_insert_size_after_reorganize(page, 1); leaf = page_is_leaf(page); @@ -1272,6 +1277,12 @@ fail_err: goto fail_err; } + if (thr && thr_get_trx(thr)->fake_changes) { + /* skip CHANGE, LOG */ + *big_rec = big_rec_vec; + return(err); /* == DB_SUCCESS */ + } + page_cursor = btr_cur_get_page_cur(cursor); /* Now, try the insert */ @@ -1414,10 +1425,10 @@ btr_cur_pessimistic_insert( *big_rec = NULL; - ut_ad(mtr_memo_contains(mtr, + ut_ad((thr && thr_get_trx(thr)->fake_changes) || mtr_memo_contains(mtr, dict_index_get_lock(btr_cur_get_index(cursor)), MTR_MEMO_X_LOCK)); - ut_ad(mtr_memo_contains(mtr, btr_cur_get_block(cursor), + ut_ad((thr && thr_get_trx(thr)->fake_changes) || mtr_memo_contains(mtr, btr_cur_get_block(cursor), MTR_MEMO_PAGE_X_FIX)); /* Try first an optimistic insert; reset the cursor flag: we do not @@ -1483,6 +1494,16 @@ btr_cur_pessimistic_insert( } } + if (thr && thr_get_trx(thr)->fake_changes) { + /* skip CHANGE, LOG */ + if (n_extents > 0) { + fil_space_release_free_extents(index->space, + n_reserved); + } + *big_rec = big_rec_vec; + return(DB_SUCCESS); + } + if (dict_index_get_page(index) == buf_block_get_page_no(btr_cur_get_block(cursor))) { @@ -1539,6 +1560,11 @@ btr_cur_upd_lock_and_undo( ut_ad(cursor && update && thr && roll_ptr); + if (thr && thr_get_trx(thr)->fake_changes) { + /* skip LOCK, UNDO */ + return(DB_SUCCESS); + } + rec = btr_cur_get_rec(cursor); index = cursor->index; @@ -1837,6 +1863,14 @@ btr_cur_update_in_place( return(err); } + if (trx->fake_changes) { + /* skip CHANGE, LOG */ + if (UNIV_LIKELY_NULL(heap)) { + mem_heap_free(heap); + } + return(err); /* == DB_SUCCESS */ + } + if (block->is_hashed) { /* The function row_upd_changes_ord_field_binary works only if the update vector was built for a clustered index, we must @@ -1929,7 +1963,6 @@ btr_cur_optimistic_update( ulint old_rec_size; dtuple_t* new_entry; roll_ptr_t roll_ptr; - trx_t* trx; mem_heap_t* heap; ulint i; ulint n_ext; @@ -1940,12 +1973,16 @@ btr_cur_optimistic_update( rec = btr_cur_get_rec(cursor); index = cursor->index; ut_ad(!!page_rec_is_comp(rec) == dict_table_is_comp(index->table)); - ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); + ut_ad((thr && thr_get_trx(thr)->fake_changes) || mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); /* The insert buffer tree should never be updated in place. */ ut_ad(!dict_index_is_ibuf(index)); heap = mem_heap_create(1024); offsets = rec_get_offsets(rec, index, NULL, ULINT_UNDEFINED, &heap); +#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG + ut_a(!rec_offs_any_null_extern(rec, offsets) + || trx_is_recv(thr_get_trx(thr))); +#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ #ifdef UNIV_DEBUG if (btr_cur_print_record_ops && thr) { @@ -2050,6 +2087,11 @@ any_extern: goto err_exit; } + if (thr && thr_get_trx(thr)->fake_changes) { + /* skip CHANGE, LOG */ + goto err_exit; /* == DB_SUCCESS */ + } + /* Ok, we may do the replacement. Store on the page infimum the explicit locks on rec, before deleting rec (see the comment in btr_cur_pessimistic_update). */ @@ -2068,13 +2110,11 @@ any_extern: page_cur_move_to_prev(page_cursor); - trx = thr_get_trx(thr); - if (!(flags & BTR_KEEP_SYS_FLAG)) { row_upd_index_entry_sys_field(new_entry, index, DATA_ROLL_PTR, roll_ptr); row_upd_index_entry_sys_field(new_entry, index, DATA_TRX_ID, - trx->id); + thr_get_trx(thr)->id); } /* There are no externally stored columns in new_entry */ @@ -2160,7 +2200,9 @@ btr_cur_pessimistic_update( /*=======================*/ ulint flags, /*!< in: undo logging, locking, and rollback flags */ - btr_cur_t* cursor, /*!< in: cursor on the record to update */ + btr_cur_t* cursor, /*!< in/out: cursor on the record to update; + cursor may become invalid if *big_rec == NULL + || !(flags & BTR_KEEP_POS_FLAG) */ mem_heap_t** heap, /*!< in/out: pointer to memory heap, or NULL */ big_rec_t** big_rec,/*!< out: big rec vector whose fields have to be stored externally by the caller, or NULL */ @@ -2200,9 +2242,9 @@ btr_cur_pessimistic_update( rec = btr_cur_get_rec(cursor); index = cursor->index; - ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index), + ut_ad((thr && thr_get_trx(thr)->fake_changes) || mtr_memo_contains(mtr, dict_index_get_lock(index), MTR_MEMO_X_LOCK)); - ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); + ut_ad((thr && thr_get_trx(thr)->fake_changes) || mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); #ifdef UNIV_ZIP_DEBUG ut_a(!page_zip || page_zip_validate(page_zip, page)); #endif /* UNIV_ZIP_DEBUG */ @@ -2290,6 +2332,9 @@ btr_cur_pessimistic_update( ut_ad(big_rec_vec == NULL); + /* fake_changes should not cause undo. so never reaches here */ + ut_ad(!(trx->fake_changes)); + btr_rec_free_updated_extern_fields( index, rec, page_zip, offsets, update, trx_is_recv(trx) ? RB_RECOVERY : RB_NORMAL, mtr); @@ -2299,7 +2344,7 @@ btr_cur_pessimistic_update( record to be inserted: we have to remember which fields were such */ ut_ad(!page_is_comp(page) || !rec_get_node_ptr_flag(rec)); - offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, heap); + ut_ad(rec_offs_validate(rec, index, offsets)); n_ext += btr_push_update_extern_fields(new_entry, update, *heap); if (UNIV_LIKELY_NULL(page_zip)) { @@ -2322,6 +2367,16 @@ make_external: err = DB_TOO_BIG_RECORD; goto return_after_reservations; } + + ut_ad(page_is_leaf(page)); + ut_ad(dict_index_is_clust(index)); + ut_ad(flags & BTR_KEEP_POS_FLAG); + } + + if (trx->fake_changes) { + /* skip CHANGE, LOG */ + err = DB_SUCCESS; + goto return_after_reservations; } /* Store state of explicit locks on rec on the page infimum record, @@ -2349,6 +2404,8 @@ make_external: rec = btr_cur_insert_if_possible(cursor, new_entry, n_ext, mtr); if (rec) { + page_cursor->rec = rec; + lock_rec_restore_from_page_infimum(btr_cur_get_block(cursor), rec, block); @@ -2362,7 +2419,10 @@ make_external: rec, index, offsets, mtr); } - btr_cur_compress_if_useful(cursor, mtr); + btr_cur_compress_if_useful( + cursor, + big_rec_vec != NULL && (flags & BTR_KEEP_POS_FLAG), + mtr); if (page_zip && !dict_index_is_clust(index) && page_is_leaf(page)) { @@ -2382,6 +2442,21 @@ make_external: } } + if (big_rec_vec) { + ut_ad(page_is_leaf(page)); + ut_ad(dict_index_is_clust(index)); + ut_ad(flags & BTR_KEEP_POS_FLAG); + + /* btr_page_split_and_insert() in + btr_cur_pessimistic_insert() invokes + mtr_memo_release(mtr, index->lock, MTR_MEMO_X_LOCK). + We must keep the index->lock when we created a + big_rec, so that row_upd_clust_rec() can store the + big_rec in the same mini-transaction. */ + + mtr_x_lock(dict_index_get_lock(index), mtr); + } + /* Was the record to be updated positioned as the first user record on its page? */ was_first = page_cur_is_before_first(page_cursor); @@ -2397,6 +2472,7 @@ make_external: ut_a(rec); ut_a(err == DB_SUCCESS); ut_a(dummy_big_rec == NULL); + page_cursor->rec = rec; if (dict_index_is_sec_or_ibuf(index)) { /* Update PAGE_MAX_TRX_ID in the index page header. @@ -2455,6 +2531,39 @@ return_after_reservations: return(err); } +/**************************************************************//** +Commits and restarts a mini-transaction so that it will retain an +x-lock on index->lock and the cursor page. */ +UNIV_INTERN +void +btr_cur_mtr_commit_and_start( +/*=========================*/ + btr_cur_t* cursor, /*!< in: cursor */ + mtr_t* mtr) /*!< in/out: mini-transaction */ +{ + buf_block_t* block; + + block = btr_cur_get_block(cursor); + + ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(cursor->index), + MTR_MEMO_X_LOCK)); + ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); + /* Keep the locks across the mtr_commit(mtr). */ + rw_lock_x_lock(dict_index_get_lock(cursor->index)); + rw_lock_x_lock(&block->lock); + mutex_enter(&block->mutex); + buf_block_buf_fix_inc(block, __FILE__, __LINE__); + mutex_exit(&block->mutex); + /* Write out the redo log. */ + mtr_commit(mtr); + mtr_start(mtr); + /* Reassociate the locks with the mini-transaction. + They will be released on mtr_commit(mtr). */ + mtr_memo_push(mtr, dict_index_get_lock(cursor->index), + MTR_MEMO_X_LOCK); + mtr_memo_push(mtr, block, MTR_MEMO_PAGE_X_FIX); +} + /*==================== B-TREE DELETE MARK AND UNMARK ===============*/ /****************************************************************//** @@ -2625,6 +2734,11 @@ btr_cur_del_mark_set_clust_rec( ut_ad(dict_index_is_clust(index)); ut_ad(!rec_get_deleted_flag(rec, rec_offs_comp(offsets))); + if (thr && thr_get_trx(thr)->fake_changes) { + /* skip LOCK, UNDO, CHANGE, LOG */ + return(DB_SUCCESS); + } + err = lock_clust_rec_modify_check_and_lock(flags, block, rec, index, offsets, thr); @@ -2647,6 +2761,7 @@ btr_cur_del_mark_set_clust_rec( page_zip = buf_block_get_page_zip(block); + btr_blob_dbg_set_deleted_flag(rec, index, offsets, val); btr_rec_set_deleted_flag(rec, page_zip, val); trx = thr_get_trx(thr); @@ -2761,6 +2876,11 @@ btr_cur_del_mark_set_sec_rec( rec_t* rec; ulint err; + if (thr && thr_get_trx(thr)->fake_changes) { + /* skip LOCK, CHANGE, LOG */ + return(DB_SUCCESS); + } + block = btr_cur_get_block(cursor); rec = btr_cur_get_rec(cursor); @@ -2833,10 +2953,12 @@ UNIV_INTERN ibool btr_cur_compress_if_useful( /*=======================*/ - btr_cur_t* cursor, /*!< in: cursor on the page to compress; - cursor does not stay valid if compression - occurs */ - mtr_t* mtr) /*!< in: mtr */ + btr_cur_t* cursor, /*!< in/out: cursor on the page to compress; + cursor does not stay valid if !adjust and + compression occurs */ + ibool adjust, /*!< in: TRUE if should adjust the + cursor position even if compression occurs */ + mtr_t* mtr) /*!< in/out: mini-transaction */ { ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(btr_cur_get_index(cursor)), @@ -2845,7 +2967,7 @@ btr_cur_compress_if_useful( MTR_MEMO_PAGE_X_FIX)); return(btr_cur_compress_recommendation(cursor, mtr) - && btr_compress(cursor, mtr)); + && btr_compress(cursor, adjust, mtr)); } /*******************************************************//** @@ -3092,7 +3214,7 @@ return_after_reservations: mem_heap_free(heap); if (ret == FALSE) { - ret = btr_cur_compress_if_useful(cursor, mtr); + ret = btr_cur_compress_if_useful(cursor, FALSE, mtr); } if (n_extents > 0) { @@ -3116,6 +3238,7 @@ btr_cur_add_path_info( { btr_path_t* slot; rec_t* rec; + page_t* page; ut_a(cursor->path_arr); @@ -3138,8 +3261,155 @@ btr_cur_add_path_info( slot = cursor->path_arr + (root_height - height); + page = page_align(rec); + slot->nth_rec = page_rec_get_n_recs_before(rec); - slot->n_recs = page_get_n_recs(page_align(rec)); + slot->n_recs = page_get_n_recs(page); + slot->page_no = page_get_page_no(page); + slot->page_level = btr_page_get_level_low(page); +} + +/*******************************************************************//** +Estimate the number of rows between slot1 and slot2 for any level on a +B-tree. This function starts from slot1->page and reads a few pages to +the right, counting their records. If we reach slot2->page quickly then +we know exactly how many records there are between slot1 and slot2 and +we set is_n_rows_exact to TRUE. If we cannot reach slot2->page quickly +then we calculate the average number of records in the pages scanned +so far and assume that all pages that we did not scan up to slot2->page +contain the same number of records, then we multiply that average to +the number of pages between slot1->page and slot2->page (which is +n_rows_on_prev_level). In this case we set is_n_rows_exact to FALSE. +@return number of rows (exact or estimated) */ +static +ib_int64_t +btr_estimate_n_rows_in_range_on_level( +/*==================================*/ + dict_index_t* index, /*!< in: index */ + btr_path_t* slot1, /*!< in: left border */ + btr_path_t* slot2, /*!< in: right border */ + ib_int64_t n_rows_on_prev_level, /*!< in: number of rows + on the previous level for the + same descend paths; used to + determine the numbe of pages + on this level */ + ibool* is_n_rows_exact) /*!< out: TRUE if the returned + value is exact i.e. not an + estimation */ +{ + ulint space; + ib_int64_t n_rows; + ulint n_pages_read; + ulint page_no; + ulint zip_size; + ulint level; + + space = dict_index_get_space(index); + + n_rows = 0; + n_pages_read = 0; + + /* Assume by default that we will scan all pages between + slot1->page_no and slot2->page_no */ + *is_n_rows_exact = TRUE; + + /* add records from slot1->page_no which are to the right of + the record which serves as a left border of the range, if any */ + if (slot1->nth_rec < slot1->n_recs) { + n_rows += slot1->n_recs - slot1->nth_rec; + } + + /* add records from slot2->page_no which are to the left of + the record which servers as a right border of the range, if any */ + if (slot2->nth_rec > 1) { + n_rows += slot2->nth_rec - 1; + } + + /* count the records in the pages between slot1->page_no and + slot2->page_no (non inclusive), if any */ + + zip_size = fil_space_get_zip_size(space); + + /* Do not read more than this number of pages in order not to hurt + performance with this code which is just an estimation. If we read + this many pages before reaching slot2->page_no then we estimate the + average from the pages scanned so far */ + #define N_PAGES_READ_LIMIT 10 + + page_no = slot1->page_no; + level = slot1->page_level; + + do { + mtr_t mtr; + page_t* page; + buf_block_t* block; + + mtr_start(&mtr); + + /* fetch the page */ + block = buf_page_get(space, zip_size, page_no, RW_S_LATCH, + &mtr); + + page = buf_block_get_frame(block); + + /* It is possible that the tree has been reorganized in the + meantime and this is a different page. If this happens the + calculated estimate will be bogus, which is not fatal as + this is only an estimate. We are sure that a page with + page_no exists because InnoDB never frees pages, only + reuses them. */ + if (fil_page_get_type(page) != FIL_PAGE_INDEX + || ut_dulint_cmp(btr_page_get_index_id(page), index->id) + || btr_page_get_level_low(page) != level) { + + /* The page got reused for something else */ + goto inexact; + } + + n_pages_read++; + + if (page_no != slot1->page_no) { + /* Do not count the records on slot1->page_no, + we already counted them before this loop. */ + n_rows += page_get_n_recs(page); + } + + page_no = btr_page_get_next(page, &mtr); + + mtr_commit(&mtr); + + if (n_pages_read == N_PAGES_READ_LIMIT + || page_no == FIL_NULL) { + /* Either we read too many pages or + we reached the end of the level without passing + through slot2->page_no, the tree must have changed + in the meantime */ + goto inexact; + } + + } while (page_no != slot2->page_no); + + return(n_rows); + +inexact: + + *is_n_rows_exact = FALSE; + + /* We did interrupt before reaching slot2->page */ + + if (n_pages_read > 0) { + /* The number of pages on this level is + n_rows_on_prev_level, multiply it by the + average number of recs per page so far */ + n_rows = n_rows_on_prev_level + * n_rows / n_pages_read; + } else { + /* The tree changed before we could even + start with slot1->page_no */ + n_rows = 10; + } + + return(n_rows); } /*******************************************************************//** @@ -3164,6 +3434,7 @@ btr_estimate_n_rows_in_range( ibool diverged_lot; ulint divergence_level; ib_int64_t n_rows; + ibool is_n_rows_exact; ulint i; mtr_t mtr; @@ -3206,6 +3477,7 @@ btr_estimate_n_rows_in_range( /* We have the path information for the range in path1 and path2 */ n_rows = 1; + is_n_rows_exact = TRUE; diverged = FALSE; /* This becomes true when the path is not the same any more */ diverged_lot = FALSE; /* This becomes true when the paths are @@ -3221,7 +3493,7 @@ btr_estimate_n_rows_in_range( if (slot1->nth_rec == ULINT_UNDEFINED || slot2->nth_rec == ULINT_UNDEFINED) { - if (i > divergence_level + 1) { + if (i > divergence_level + 1 && !is_n_rows_exact) { /* In trees whose height is > 1 our algorithm tends to underestimate: multiply the estimate by 2: */ @@ -3233,7 +3505,9 @@ btr_estimate_n_rows_in_range( to over 1 / 2 of the estimated rows in the whole table */ - if (n_rows > index->table->stat_n_rows / 2) { + if (n_rows > index->table->stat_n_rows / 2 + && !is_n_rows_exact) { + n_rows = index->table->stat_n_rows / 2; /* If there are just 0 or 1 rows in the table, @@ -3259,10 +3533,15 @@ btr_estimate_n_rows_in_range( divergence_level = i; } } else { - /* Maybe the tree has changed between - searches */ - - return(10); + /* It is possible that + slot1->nth_rec >= slot2->nth_rec + if, for example, we have a single page + tree which contains (inf, 5, 6, supr) + and we select where x > 20 and x < 30; + in this case slot1->nth_rec will point + to the supr record and slot2->nth_rec + will point to 6 */ + n_rows = 0; } } else if (diverged && !diverged_lot) { @@ -3286,8 +3565,9 @@ btr_estimate_n_rows_in_range( } } else if (diverged_lot) { - n_rows = (n_rows * (slot1->n_recs + slot2->n_recs)) - / 2; + n_rows = btr_estimate_n_rows_in_range_on_level( + index, slot1, slot2, n_rows, + &is_n_rows_exact); } } } @@ -3680,6 +3960,8 @@ btr_cur_set_ownership_of_extern_field( } else { mach_write_to_1(data + local_len + BTR_EXTERN_LEN, byte_val); } + + btr_blob_dbg_owner(rec, index, offsets, i, val); } /*******************************************************************//** @@ -3884,7 +4166,7 @@ btr_blob_free( && buf_block_get_space(block) == space && buf_block_get_page_no(block) == page_no) { - if (buf_LRU_free_block(&block->page, all, TRUE) != BUF_LRU_FREED + if (!buf_LRU_free_block(&block->page, all, TRUE) && all && block->page.zip.data /* Now, buf_LRU_free_block() may release mutex temporarily */ && buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE @@ -4185,6 +4467,11 @@ btr_store_big_rec_extern_fields_func( } if (prev_page_no == FIL_NULL) { + btr_blob_dbg_add_blob( + rec, big_rec_vec->fields[i] + .field_no, page_no, index, + "store"); + mach_write_to_4(field_ref + BTR_EXTERN_SPACE_ID, space_id); @@ -4260,6 +4547,11 @@ next_zip_page: MLOG_4BYTES, &mtr); if (prev_page_no == FIL_NULL) { + btr_blob_dbg_add_blob( + rec, big_rec_vec->fields[i] + .field_no, page_no, index, + "store"); + mlog_write_ulint(field_ref + BTR_EXTERN_SPACE_ID, space_id, @@ -4428,6 +4720,37 @@ btr_free_externally_stored_field( rec_zip_size = 0; } +#ifdef UNIV_BLOB_DEBUG + if (!(field_ref[BTR_EXTERN_LEN] & BTR_EXTERN_OWNER_FLAG) + && !((field_ref[BTR_EXTERN_LEN] & BTR_EXTERN_INHERITED_FLAG) + && (rb_ctx == RB_NORMAL || rb_ctx == RB_RECOVERY))) { + /* This off-page column will be freed. + Check that no references remain. */ + + btr_blob_dbg_t b; + + b.blob_page_no = mach_read_from_4( + field_ref + BTR_EXTERN_PAGE_NO); + + if (rec) { + /* Remove the reference from the record to the + BLOB. If the BLOB were not freed, the + reference would be removed when the record is + removed. Freeing the BLOB will overwrite the + BTR_EXTERN_PAGE_NO in the field_ref of the + record with FIL_NULL, which would make the + btr_blob_dbg information inconsistent with the + record. */ + b.ref_page_no = page_get_page_no(page_align(rec)); + b.ref_heap_no = page_rec_get_heap_no(rec); + b.ref_field_no = i; + btr_blob_dbg_rbt_delete(index, &b, "free"); + } + + btr_blob_dbg_assert_empty(index, b.blob_page_no); + } +#endif /* UNIV_BLOB_DEBUG */ + for (;;) { #ifdef UNIV_SYNC_DEBUG buf_block_t* rec_block; @@ -4674,27 +4997,45 @@ btr_copy_blob_prefix( /*******************************************************************//** Copies the prefix of a compressed BLOB. The clustered index record -that points to this BLOB must be protected by a lock or a page latch. */ +that points to this BLOB must be protected by a lock or a page latch. +@return number of bytes written to buf */ static -void +ulint btr_copy_zblob_prefix( /*==================*/ - z_stream* d_stream,/*!< in/out: the decompressing stream */ + byte* buf, /*!< out: the externally stored part of + the field, or a prefix of it */ + ulint len, /*!< in: length of buf, in bytes */ ulint zip_size,/*!< in: compressed BLOB page size */ ulint space_id,/*!< in: space id of the BLOB pages */ ulint page_no,/*!< in: page number of the first BLOB page */ ulint offset) /*!< in: offset on the first BLOB page */ { - ulint page_type = FIL_PAGE_TYPE_ZBLOB; + ulint page_type = FIL_PAGE_TYPE_ZBLOB; + mem_heap_t* heap; + int err; + z_stream d_stream; + + d_stream.next_out = buf; + d_stream.avail_out = len; + d_stream.next_in = Z_NULL; + d_stream.avail_in = 0; + + /* Zlib inflate needs 32 kilobytes for the default + window size, plus a few kilobytes for small objects. */ + heap = mem_heap_create(40000); + page_zip_set_alloc(&d_stream, heap); ut_ad(ut_is_2pow(zip_size)); ut_ad(zip_size >= PAGE_ZIP_MIN_SIZE); ut_ad(zip_size <= UNIV_PAGE_SIZE); ut_ad(space_id); + err = inflateInit(&d_stream); + ut_a(err == Z_OK); + for (;;) { buf_page_t* bpage; - int err; ulint next_page_no; /* There is no latch on bpage directly. Instead, @@ -4710,7 +5051,7 @@ btr_copy_zblob_prefix( " compressed BLOB" " page %lu space %lu\n", (ulong) page_no, (ulong) space_id); - return; + goto func_exit; } if (UNIV_UNLIKELY @@ -4736,13 +5077,13 @@ btr_copy_zblob_prefix( offset += 4; } - d_stream->next_in = bpage->zip.data + offset; - d_stream->avail_in = zip_size - offset; + d_stream.next_in = bpage->zip.data + offset; + d_stream.avail_in = zip_size - offset; - err = inflate(d_stream, Z_NO_FLUSH); + err = inflate(&d_stream, Z_NO_FLUSH); switch (err) { case Z_OK: - if (!d_stream->avail_out) { + if (!d_stream.avail_out) { goto end_of_blob; } break; @@ -4759,13 +5100,13 @@ inflate_error: " compressed BLOB" " page %lu space %lu returned %d (%s)\n", (ulong) page_no, (ulong) space_id, - err, d_stream->msg); + err, d_stream.msg); case Z_BUF_ERROR: goto end_of_blob; } if (next_page_no == FIL_NULL) { - if (!d_stream->avail_in) { + if (!d_stream.avail_in) { ut_print_timestamp(stderr); fprintf(stderr, " InnoDB: unexpected end of" @@ -4774,7 +5115,7 @@ inflate_error: (ulong) page_no, (ulong) space_id); } else { - err = inflate(d_stream, Z_FINISH); + err = inflate(&d_stream, Z_FINISH); switch (err) { case Z_STREAM_END: case Z_BUF_ERROR: @@ -4786,7 +5127,7 @@ inflate_error: end_of_blob: buf_page_release_zip(bpage); - return; + goto func_exit; } buf_page_release_zip(bpage); @@ -4798,6 +5139,12 @@ end_of_blob: offset = FIL_PAGE_NEXT; page_type = FIL_PAGE_TYPE_ZBLOB2; } + +func_exit: + inflateEnd(&d_stream); + mem_heap_free(heap); + UNIV_MEM_ASSERT_RW(buf, d_stream.total_out); + return(d_stream.total_out); } /*******************************************************************//** @@ -4823,28 +5170,8 @@ btr_copy_externally_stored_field_prefix_low( } if (UNIV_UNLIKELY(zip_size)) { - int err; - z_stream d_stream; - mem_heap_t* heap; - - /* Zlib inflate needs 32 kilobytes for the default - window size, plus a few kilobytes for small objects. */ - heap = mem_heap_create(40000); - page_zip_set_alloc(&d_stream, heap); - - err = inflateInit(&d_stream); - ut_a(err == Z_OK); - - d_stream.next_out = buf; - d_stream.avail_out = len; - d_stream.avail_in = 0; - - btr_copy_zblob_prefix(&d_stream, zip_size, - space_id, page_no, offset); - inflateEnd(&d_stream); - mem_heap_free(heap); - UNIV_MEM_ASSERT_RW(buf, d_stream.total_out); - return(d_stream.total_out); + return(btr_copy_zblob_prefix(buf, len, zip_size, + space_id, page_no, offset)); } else { return(btr_copy_blob_prefix(buf, len, space_id, page_no, offset)); diff --git a/btr/btr0pcur.c b/btr/btr0pcur.c index f95a5487c94..97fe06f0f5e 100644 --- a/btr/btr0pcur.c +++ b/btr/btr0pcur.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2010, 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 @@ -362,33 +362,6 @@ btr_pcur_restore_position_func( return(FALSE); } -/**************************************************************//** -If the latch mode of the cursor is BTR_LEAF_SEARCH or BTR_LEAF_MODIFY, -releases the page latch and bufferfix reserved by the cursor. -NOTE! In the case of BTR_LEAF_MODIFY, there should not exist changes -made by the current mini-transaction to the data protected by the -cursor latch, as then the latch must not be released until mtr_commit. */ -UNIV_INTERN -void -btr_pcur_release_leaf( -/*==================*/ - btr_pcur_t* cursor, /*!< in: persistent cursor */ - mtr_t* mtr) /*!< in: mtr */ -{ - buf_block_t* block; - - ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED); - ut_ad(cursor->latch_mode != BTR_NO_LATCHES); - - block = btr_pcur_get_block(cursor); - - btr_leaf_page_release(block, cursor->latch_mode, mtr); - - cursor->latch_mode = BTR_NO_LATCHES; - - cursor->pos_state = BTR_PCUR_WAS_POSITIONED; -} - /*********************************************************//** Moves the persistent cursor to the first record on the next page. Releases the latch on the current page, and bufferunfixes it. Note that there must not be diff --git a/btr/btr0sea.c b/btr/btr0sea.c index 3b38e2799c2..6e6c533f4af 100644 --- a/btr/btr0sea.c +++ b/btr/btr0sea.c @@ -1373,8 +1373,8 @@ btr_search_drop_page_hash_when_freed( having to fear a deadlock. */ block = buf_page_get_gen(space, zip_size, page_no, RW_S_LATCH, NULL, - BUF_GET_IF_IN_POOL, __FILE__, __LINE__, - &mtr); + 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 diff --git a/buf/buf0buddy.c b/buf/buf0buddy.c index db94b4bed24..673d6c55efc 100644 --- a/buf/buf0buddy.c +++ b/buf/buf0buddy.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2006, 2010, Innobase Oy. All Rights Reserved. +Copyright (c) 2006, 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 @@ -45,6 +45,14 @@ static ulint buf_buddy_n_frames; Protected by buf_pool_mutex. */ UNIV_INTERN buf_buddy_stat_t buf_buddy_stat[BUF_BUDDY_SIZES_MAX + 1]; +/** Validate a given zip_free list. */ +#define BUF_BUDDY_LIST_VALIDATE(i) \ + UT_LIST_VALIDATE(zip_list, buf_page_t, \ + buf_pool->zip_free[i], \ + ut_ad(buf_page_get_state( \ + ut_list_node_313) \ + == BUF_BLOCK_ZIP_FREE)) + /**********************************************************************//** Get the offset of the buddy of a compressed page frame. @return the buddy relative of page */ @@ -76,22 +84,11 @@ buf_buddy_add_to_free( buf_page_t* bpage, /*!< in,own: block to be freed */ ulint i) /*!< in: index of buf_pool->zip_free[] */ { -#ifdef UNIV_DEBUG_VALGRIND - buf_page_t* b = UT_LIST_GET_FIRST(buf_pool->zip_free[i]); - - if (b) UNIV_MEM_VALID(b, BUF_BUDDY_LOW << i); -#endif /* UNIV_DEBUG_VALGRIND */ - //ut_ad(buf_pool_mutex_own()); ut_ad(mutex_own(&zip_free_mutex)); ut_ad(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_FREE); ut_ad(buf_pool->zip_free[i].start != bpage); UT_LIST_ADD_FIRST(zip_list, buf_pool->zip_free[i], bpage); - -#ifdef UNIV_DEBUG_VALGRIND - if (b) UNIV_MEM_FREE(b, BUF_BUDDY_LOW << i); - UNIV_MEM_ASSERT_AND_FREE(bpage, BUF_BUDDY_LOW << i); -#endif /* UNIV_DEBUG_VALGRIND */ } /**********************************************************************//** @@ -103,26 +100,18 @@ buf_buddy_remove_from_free( buf_page_t* bpage, /*!< in: block to be removed */ ulint i) /*!< in: index of buf_pool->zip_free[] */ { -#ifdef UNIV_DEBUG_VALGRIND +#ifdef UNIV_DEBUG buf_page_t* prev = UT_LIST_GET_PREV(zip_list, bpage); buf_page_t* next = UT_LIST_GET_NEXT(zip_list, bpage); - if (prev) UNIV_MEM_VALID(prev, BUF_BUDDY_LOW << i); - if (next) UNIV_MEM_VALID(next, BUF_BUDDY_LOW << i); - ut_ad(!prev || buf_page_get_state(prev) == BUF_BLOCK_ZIP_FREE); ut_ad(!next || buf_page_get_state(next) == BUF_BLOCK_ZIP_FREE); -#endif /* UNIV_DEBUG_VALGRIND */ +#endif /* UNIV_DEBUG */ //ut_ad(buf_pool_mutex_own()); ut_ad(mutex_own(&zip_free_mutex)); ut_ad(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_FREE); UT_LIST_REMOVE(zip_list, buf_pool->zip_free[i], bpage); - -#ifdef UNIV_DEBUG_VALGRIND - if (prev) UNIV_MEM_FREE(prev, BUF_BUDDY_LOW << i); - if (next) UNIV_MEM_FREE(next, BUF_BUDDY_LOW << i); -#endif /* UNIV_DEBUG_VALGRIND */ } /**********************************************************************//** @@ -139,17 +128,13 @@ buf_buddy_alloc_zip( //ut_ad(buf_pool_mutex_own()); ut_ad(mutex_own(&zip_free_mutex)); ut_a(i < BUF_BUDDY_SIZES); + ut_a(i >= buf_buddy_get_slot(PAGE_ZIP_MIN_SIZE)); + + ut_d(BUF_BUDDY_LIST_VALIDATE(i)); -#ifndef UNIV_DEBUG_VALGRIND - /* Valgrind would complain about accessing free memory. */ - ut_d(UT_LIST_VALIDATE(zip_list, buf_page_t, buf_pool->zip_free[i], - ut_ad(buf_page_get_state(ut_list_node_313) - == BUF_BLOCK_ZIP_FREE))); -#endif /* !UNIV_DEBUG_VALGRIND */ bpage = UT_LIST_GET_LAST(buf_pool->zip_free[i]); if (bpage) { - UNIV_MEM_VALID(bpage, BUF_BUDDY_LOW << i); ut_a(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_FREE); buf_buddy_remove_from_free(bpage, i); @@ -168,13 +153,10 @@ buf_buddy_alloc_zip( } } -#ifdef UNIV_DEBUG if (bpage) { - memset(bpage, ~i, BUF_BUDDY_LOW << i); + ut_d(memset(bpage, ~i, BUF_BUDDY_LOW << i)); + UNIV_MEM_ALLOC(bpage, BUF_BUDDY_SIZES << i); } -#endif /* UNIV_DEBUG */ - - UNIV_MEM_ALLOC(bpage, BUF_BUDDY_SIZES << i); return(bpage); } @@ -266,6 +248,7 @@ buf_buddy_alloc_from( { ulint offs = BUF_BUDDY_LOW << j; ut_ad(j <= BUF_BUDDY_SIZES); + ut_ad(i >= buf_buddy_get_slot(PAGE_ZIP_MIN_SIZE)); ut_ad(j >= i); ut_ad(!ut_align_offset(buf, offs)); @@ -279,13 +262,7 @@ buf_buddy_alloc_from( bpage = (buf_page_t*) ((byte*) buf + offs); ut_d(memset(bpage, j, BUF_BUDDY_LOW << j)); bpage->state = BUF_BLOCK_ZIP_FREE; -#ifndef UNIV_DEBUG_VALGRIND - /* Valgrind would complain about accessing free memory. */ - ut_d(UT_LIST_VALIDATE(zip_list, buf_page_t, buf_pool->zip_free[i], - ut_ad(buf_page_get_state( - ut_list_node_313) - == BUF_BLOCK_ZIP_FREE))); -#endif /* !UNIV_DEBUG_VALGRIND */ + ut_d(BUF_BUDDY_LIST_VALIDATE(i)); buf_buddy_add_to_free(bpage, j); } @@ -295,8 +272,8 @@ buf_buddy_alloc_from( /**********************************************************************//** Allocate a block. The thread calling this function must hold buf_pool_mutex and must not hold buf_pool_zip_mutex or any block->mutex. -The buf_pool_mutex may only be released and reacquired if lru != NULL. -@return allocated block, possibly NULL if lru==NULL */ +The buf_pool_mutex may be released and reacquired. +@return allocated block, never NULL */ UNIV_INTERN void* buf_buddy_alloc_low( @@ -305,14 +282,15 @@ buf_buddy_alloc_low( or BUF_BUDDY_SIZES */ ibool* lru, /*!< in: pointer to a variable that will be assigned TRUE if storage was allocated from the LRU list - and buf_pool_mutex was temporarily released, - or NULL if the LRU list should not be used */ + and buf_pool_mutex was temporarily released */ ibool have_page_hash_mutex) { buf_block_t* block; + ut_ad(lru); //ut_ad(buf_pool_mutex_own()); ut_ad(!mutex_own(&buf_pool_zip_mutex)); + ut_ad(i >= buf_buddy_get_slot(PAGE_ZIP_MIN_SIZE)); if (i < BUF_BUDDY_SIZES) { /* Try to allocate from the buddy system. */ @@ -335,11 +313,6 @@ buf_buddy_alloc_low( goto alloc_big; } - if (!lru) { - - return(NULL); - } - /* Try replacing an uncompressed page in the buffer pool. */ //buf_pool_mutex_exit(); mutex_exit(&LRU_list_mutex); @@ -367,76 +340,6 @@ func_exit: return(block); } -/**********************************************************************//** -Try to relocate the control block of a compressed page. -@return TRUE if relocated */ -static -ibool -buf_buddy_relocate_block( -/*=====================*/ - buf_page_t* bpage, /*!< in: block to relocate */ - buf_page_t* dpage) /*!< in: free block to relocate to */ -{ - buf_page_t* b; - - //ut_ad(buf_pool_mutex_own()); -#ifdef UNIV_SYNC_DEBUG - ut_ad(rw_lock_own(&page_hash_latch, RW_LOCK_EX)); -#endif - - switch (buf_page_get_state(bpage)) { - case BUF_BLOCK_ZIP_FREE: - case BUF_BLOCK_NOT_USED: - case BUF_BLOCK_READY_FOR_USE: - case BUF_BLOCK_FILE_PAGE: - case BUF_BLOCK_MEMORY: - case BUF_BLOCK_REMOVE_HASH: - /* ut_error; */ /* optimistic */ - case BUF_BLOCK_ZIP_DIRTY: - /* Cannot relocate dirty pages. */ - return(FALSE); - - case BUF_BLOCK_ZIP_PAGE: - break; - } - - mutex_enter(&buf_pool_zip_mutex); - mutex_enter(&zip_free_mutex); - - if (!buf_page_can_relocate(bpage)) { - mutex_exit(&buf_pool_zip_mutex); - mutex_exit(&zip_free_mutex); - return(FALSE); - } - - if (bpage != buf_page_hash_get(bpage->space, bpage->offset)) { - mutex_exit(&buf_pool_zip_mutex); - mutex_exit(&zip_free_mutex); - return(FALSE); - } - - buf_relocate(bpage, dpage); - ut_d(bpage->state = BUF_BLOCK_ZIP_FREE); - - /* relocate buf_pool->zip_clean */ - mutex_enter(&flush_list_mutex); - b = UT_LIST_GET_PREV(zip_list, dpage); - UT_LIST_REMOVE(zip_list, buf_pool->zip_clean, dpage); - - if (b) { - UT_LIST_INSERT_AFTER(zip_list, buf_pool->zip_clean, b, dpage); - } else { - UT_LIST_ADD_FIRST(zip_list, buf_pool->zip_clean, dpage); - } - mutex_exit(&flush_list_mutex); - - UNIV_MEM_INVALID(bpage, sizeof *bpage); - - mutex_exit(&buf_pool_zip_mutex); - mutex_exit(&zip_free_mutex); - return(TRUE); -} - /**********************************************************************//** Try to relocate a block. @return TRUE if relocated */ @@ -452,159 +355,120 @@ buf_buddy_relocate( buf_page_t* bpage; const ulint size = BUF_BUDDY_LOW << i; ullint usec = ut_time_us(NULL); + mutex_t* mutex; + ulint space; + ulint page_no; //ut_ad(buf_pool_mutex_own()); ut_ad(mutex_own(&zip_free_mutex)); ut_ad(!mutex_own(&buf_pool_zip_mutex)); ut_ad(!ut_align_offset(src, size)); ut_ad(!ut_align_offset(dst, size)); + ut_ad(i >= buf_buddy_get_slot(PAGE_ZIP_MIN_SIZE)); UNIV_MEM_ASSERT_W(dst, size); + if (!have_page_hash_mutex) { + mutex_exit(&zip_free_mutex); + mutex_enter(&LRU_list_mutex); + rw_lock_x_lock(&page_hash_latch); + } + /* We assume that all memory from buf_buddy_alloc() - is used for either compressed pages or buf_page_t - objects covering compressed pages. */ + is used for compressed page frames. */ /* We look inside the allocated objects returned by - buf_buddy_alloc() and assume that anything of - PAGE_ZIP_MIN_SIZE or larger is a compressed page that contains - a valid space_id and page_no in the page header. Should the - fields be invalid, we will be unable to relocate the block. - We also assume that anything that fits sizeof(buf_page_t) - actually is a properly initialized buf_page_t object. */ + buf_buddy_alloc() and assume that each block is a compressed + page that contains a valid space_id and page_no in the page + header. Should the fields be invalid, we will be unable to + relocate the block. */ - if (size >= PAGE_ZIP_MIN_SIZE) { - /* This is a compressed page. */ - mutex_t* mutex; - ulint space, page_no; - - if (!have_page_hash_mutex) { - mutex_exit(&zip_free_mutex); - mutex_enter(&LRU_list_mutex); - rw_lock_x_lock(&page_hash_latch); - } - - /* The src block may be split into smaller blocks, - some of which may be free. Thus, the - mach_read_from_4() calls below may attempt to read - from free memory. The memory is "owned" by the buddy - allocator (and it has been allocated from the buffer - pool), so there is nothing wrong about this. The - mach_read_from_4() calls here will only trigger bogus - Valgrind memcheck warnings in UNIV_DEBUG_VALGRIND builds. */ - space = mach_read_from_4( - (const byte*) src + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID); - page_no = mach_read_from_4( - (const byte*) src + FIL_PAGE_OFFSET); - /* Suppress Valgrind warnings about conditional jump - on uninitialized value. */ - UNIV_MEM_VALID(&space, sizeof space); - UNIV_MEM_VALID(&page_no, sizeof page_no); - bpage = buf_page_hash_get(space, page_no); - - if (!bpage || bpage->zip.data != src) { - /* The block has probably been freshly - allocated by buf_LRU_get_free_block() but not - added to buf_pool->page_hash yet. Obviously, - it cannot be relocated. */ - - if (!have_page_hash_mutex) { - mutex_enter(&zip_free_mutex); - mutex_exit(&LRU_list_mutex); - rw_lock_x_unlock(&page_hash_latch); - } - return(FALSE); - } - - if (page_zip_get_size(&bpage->zip) != size) { - /* The block is of different size. We would - have to relocate all blocks covered by src. - For the sake of simplicity, give up. */ - ut_ad(page_zip_get_size(&bpage->zip) < size); - - if (!have_page_hash_mutex) { - mutex_enter(&zip_free_mutex); - mutex_exit(&LRU_list_mutex); - rw_lock_x_unlock(&page_hash_latch); - } - return(FALSE); - } - - /* To keep latch order */ - if (have_page_hash_mutex) - mutex_exit(&zip_free_mutex); - - /* The block must have been allocated, but it may - contain uninitialized data. */ - UNIV_MEM_ASSERT_W(src, size); - - mutex = buf_page_get_mutex_enter(bpage); - - mutex_enter(&zip_free_mutex); - - if (mutex && buf_page_can_relocate(bpage)) { - /* Relocate the compressed page. */ - ut_a(bpage->zip.data == src); - memcpy(dst, src, size); - bpage->zip.data = dst; - mutex_exit(mutex); -success: - UNIV_MEM_INVALID(src, size); - { - buf_buddy_stat_t* buddy_stat - = &buf_buddy_stat[i]; - buddy_stat->relocated++; - buddy_stat->relocated_usec - += ut_time_us(NULL) - usec; - } - - if (!have_page_hash_mutex) { - mutex_exit(&LRU_list_mutex); - rw_lock_x_unlock(&page_hash_latch); - } - return(TRUE); - } + /* The src block may be split into smaller blocks, + some of which may be free. Thus, the + mach_read_from_4() calls below may attempt to read + from free memory. The memory is "owned" by the buddy + allocator (and it has been allocated from the buffer + pool), so there is nothing wrong about this. The + mach_read_from_4() calls here will only trigger bogus + Valgrind memcheck warnings in UNIV_DEBUG_VALGRIND builds. */ + space = mach_read_from_4((const byte *) src + + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID); + page_no = mach_read_from_4((const byte *) src + + FIL_PAGE_OFFSET); + /* Suppress Valgrind warnings about conditional jump + on uninitialized value. */ + UNIV_MEM_VALID(&space, sizeof space); + UNIV_MEM_VALID(&page_no, sizeof page_no); + bpage = buf_page_hash_get(space, page_no); + + if (!bpage || bpage->zip.data != src) { + /* The block has probably been freshly + allocated by buf_LRU_get_free_block() but not + added to buf_pool->page_hash yet. Obviously, + it cannot be relocated. */ if (!have_page_hash_mutex) { + mutex_enter(&zip_free_mutex); mutex_exit(&LRU_list_mutex); rw_lock_x_unlock(&page_hash_latch); } + return(FALSE); + } - if (mutex) { - mutex_exit(mutex); + if (page_zip_get_size(&bpage->zip) != size) { + /* The block is of different size. We would + have to relocate all blocks covered by src. + For the sake of simplicity, give up. */ + ut_ad(page_zip_get_size(&bpage->zip) < size); + + if (!have_page_hash_mutex) { + mutex_enter(&zip_free_mutex); + mutex_exit(&LRU_list_mutex); + rw_lock_x_unlock(&page_hash_latch); } - } else if (i == buf_buddy_get_slot(sizeof(buf_page_t))) { - /* This must be a buf_page_t object. */ -#if UNIV_WORD_SIZE == 4 - /* On 32-bit systems, there is no padding in - buf_page_t. On other systems, Valgrind could complain - about uninitialized pad bytes. */ - UNIV_MEM_ASSERT_RW(src, size); -#endif + return(FALSE); + } + /* To keep latch order */ + if (have_page_hash_mutex) mutex_exit(&zip_free_mutex); - if (!have_page_hash_mutex) { - mutex_enter(&LRU_list_mutex); - rw_lock_x_lock(&page_hash_latch); + /* The block must have been allocated, but it may + contain uninitialized data. */ + UNIV_MEM_ASSERT_W(src, size); + + mutex = buf_page_get_mutex_enter(bpage); + + mutex_enter(&zip_free_mutex); + + if (mutex && buf_page_can_relocate(bpage)) { + /* Relocate the compressed page. */ + ut_a(bpage->zip.data == src); + memcpy(dst, src, size); + bpage->zip.data = dst; + mutex_exit(mutex); + UNIV_MEM_INVALID(src, size); + { + buf_buddy_stat_t* buddy_stat + = &buf_buddy_stat[i]; + buddy_stat->relocated++; + buddy_stat->relocated_usec + += ut_time_us(NULL) - usec; } - if (buf_buddy_relocate_block(src, dst)) { - mutex_enter(&zip_free_mutex); - - if (!have_page_hash_mutex) { - mutex_exit(&LRU_list_mutex); - rw_lock_x_unlock(&page_hash_latch); - } - - goto success; - } - - mutex_enter(&zip_free_mutex); - if (!have_page_hash_mutex) { mutex_exit(&LRU_list_mutex); rw_lock_x_unlock(&page_hash_latch); } + return(TRUE); + } + + if (!have_page_hash_mutex) { + mutex_exit(&LRU_list_mutex); + rw_lock_x_unlock(&page_hash_latch); + } + + if (mutex) { + mutex_exit(mutex); } return(FALSE); @@ -629,12 +493,14 @@ buf_buddy_free_low( ut_ad(mutex_own(&zip_free_mutex)); ut_ad(!mutex_own(&buf_pool_zip_mutex)); ut_ad(i <= BUF_BUDDY_SIZES); + ut_ad(i >= buf_buddy_get_slot(PAGE_ZIP_MIN_SIZE)); ut_ad(buf_buddy_stat[i].used > 0); buf_buddy_stat[i].used--; + recombine: UNIV_MEM_ASSERT_AND_ALLOC(buf, BUF_BUDDY_LOW << i); - ut_d(((buf_page_t*) buf)->state = BUF_BLOCK_ZIP_FREE); + ((buf_page_t*) buf)->state = BUF_BLOCK_ZIP_FREE; if (i == BUF_BUDDY_SIZES) { mutex_exit(&zip_free_mutex); @@ -647,32 +513,36 @@ recombine: ut_ad(buf == ut_align_down(buf, BUF_BUDDY_LOW << i)); ut_ad(!buf_pool_contains_zip(buf)); - /* Try to combine adjacent blocks. */ + /* Do not recombine blocks if there are few free blocks. + We may waste up to 15360*max_len bytes to free blocks + (1024 + 2048 + 4096 + 8192 = 15360) */ + if (UT_LIST_GET_LEN(buf_pool->zip_free[i]) < 16) { + goto func_exit; + } + /* Try to combine adjacent blocks. */ buddy = (buf_page_t*) buf_buddy_get(((byte*) buf), BUF_BUDDY_LOW << i); #ifndef UNIV_DEBUG_VALGRIND - /* Valgrind would complain about accessing free memory. */ + /* When Valgrind instrumentation is not enabled, we can read + buddy->state to quickly determine that a block is not free. + When the block is not free, buddy->state belongs to a compressed + page frame that may be flagged uninitialized in our Valgrind + instrumentation. */ if (buddy->state != BUF_BLOCK_ZIP_FREE) { goto buddy_nonfree; } - - /* The field buddy->state can only be trusted for free blocks. - If buddy->state == BUF_BLOCK_ZIP_FREE, the block is free if - it is in the free list. */ #endif /* !UNIV_DEBUG_VALGRIND */ for (bpage = UT_LIST_GET_FIRST(buf_pool->zip_free[i]); bpage; ) { - UNIV_MEM_VALID(bpage, BUF_BUDDY_LOW << i); ut_ad(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_FREE); if (bpage == buddy) { -buddy_free: /* The buddy is free: recombine */ buf_buddy_remove_from_free(bpage, i); -buddy_free2: +buddy_is_free: ut_ad(buf_page_get_state(buddy) == BUF_BLOCK_ZIP_FREE); ut_ad(!buf_pool_contains_zip(buddy)); i++; @@ -682,122 +552,43 @@ buddy_free2: } ut_a(bpage != buf); - - { - buf_page_t* next = UT_LIST_GET_NEXT(zip_list, bpage); - UNIV_MEM_ASSERT_AND_FREE(bpage, BUF_BUDDY_LOW << i); - bpage = next; - } + UNIV_MEM_ASSERT_W(bpage, BUF_BUDDY_LOW << i); + bpage = UT_LIST_GET_NEXT(zip_list, bpage); } #ifndef UNIV_DEBUG_VALGRIND buddy_nonfree: - /* Valgrind would complain about accessing free memory. */ - ut_d(UT_LIST_VALIDATE(zip_list, buf_page_t, buf_pool->zip_free[i], - ut_ad(buf_page_get_state(ut_list_node_313) - == BUF_BLOCK_ZIP_FREE))); -#endif /* UNIV_DEBUG_VALGRIND */ +#endif /* !UNIV_DEBUG_VALGRIND */ + + ut_d(BUF_BUDDY_LIST_VALIDATE(i)); /* The buddy is not free. Is there a free block of this size? */ bpage = UT_LIST_GET_LAST(buf_pool->zip_free[i]); if (bpage) { + /* Remove the block from the free list, because a successful buf_buddy_relocate() will overwrite bpage->list. */ - - UNIV_MEM_VALID(bpage, BUF_BUDDY_LOW << i); buf_buddy_remove_from_free(bpage, i); /* Try to relocate the buddy of buf to the free block. */ if (buf_buddy_relocate(buddy, bpage, i, have_page_hash_mutex)) { - ut_d(buddy->state = BUF_BLOCK_ZIP_FREE); - goto buddy_free2; + buddy->state = BUF_BLOCK_ZIP_FREE; + goto buddy_is_free; } buf_buddy_add_to_free(bpage, i); - - /* Try to relocate the buddy of the free block to buf. */ - buddy = (buf_page_t*) buf_buddy_get(((byte*) bpage), - BUF_BUDDY_LOW << i); - -#ifndef UNIV_DEBUG_VALGRIND - /* Valgrind would complain about accessing free memory. */ - - /* The buddy must not be (completely) free, because we - always recombine adjacent free blocks. - - (Parts of the buddy can be free in - buf_pool->zip_free[j] with j < i.) */ - ut_d(UT_LIST_VALIDATE(zip_list, buf_page_t, buf_pool->zip_free[i], - ut_ad(buf_page_get_state( - ut_list_node_313) - == BUF_BLOCK_ZIP_FREE - && ut_list_node_313 != buddy))); -#endif /* !UNIV_DEBUG_VALGRIND */ - - if (buf_buddy_relocate(buddy, buf, i, have_page_hash_mutex)) { - - buf = bpage; - UNIV_MEM_VALID(bpage, BUF_BUDDY_LOW << i); - ut_d(buddy->state = BUF_BLOCK_ZIP_FREE); - goto buddy_free; - } } +func_exit: /* Free the block to the buddy list. */ bpage = buf; -#ifdef UNIV_DEBUG - if (i < buf_buddy_get_slot(PAGE_ZIP_MIN_SIZE)) { - /* This area has most likely been allocated for at - least one compressed-only block descriptor. Check - that there are no live objects in the area. This is - not a complete check: it may yield false positives as - well as false negatives. Also, due to buddy blocks - being recombined, it is possible (although unlikely) - that this branch is never reached. */ - char* c; + /* Fill large blocks with a constant pattern. */ + ut_d(memset(bpage, i, BUF_BUDDY_LOW << i)); + UNIV_MEM_INVALID(bpage, BUF_BUDDY_LOW << i); -# ifndef UNIV_DEBUG_VALGRIND - /* Valgrind would complain about accessing - uninitialized memory. Besides, Valgrind performs a - more exhaustive check, at every memory access. */ - const buf_page_t* b = buf; - const buf_page_t* const b_end = (buf_page_t*) - ((char*) b + (BUF_BUDDY_LOW << i)); - - for (; b < b_end; b++) { - /* Avoid false positives (and cause false - negatives) by checking for b->space < 1000. */ - - if ((b->state == BUF_BLOCK_ZIP_PAGE - || b->state == BUF_BLOCK_ZIP_DIRTY) - && b->space > 0 && b->space < 1000) { - fprintf(stderr, - "buddy dirty %p %u (%u,%u) %p,%lu\n", - (void*) b, - b->state, b->space, b->offset, - buf, i); - } - } -# endif /* !UNIV_DEBUG_VALGRIND */ - - /* Scramble the block. This should make any pointers - invalid and trigger a segmentation violation. Because - the scrambling can be reversed, it may be possible to - track down the object pointing to the freed data by - dereferencing the unscrambled bpage->LRU or - bpage->list pointers. */ - for (c = (char*) buf + (BUF_BUDDY_LOW << i); - c-- > (char*) buf; ) { - *c = ~*c ^ i; - } - } else { - /* Fill large blocks with a constant pattern. */ - memset(bpage, i, BUF_BUDDY_LOW << i); - } -#endif /* UNIV_DEBUG */ bpage->state = BUF_BLOCK_ZIP_FREE; buf_buddy_add_to_free(bpage, i); } diff --git a/buf/buf0buf.c b/buf/buf0buf.c index 07dc09f572b..8ac3170f3ec 100644 --- a/buf/buf0buf.c +++ b/buf/buf0buf.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. Copyright (c) 2008, Google Inc. Portions of this file contain modifications contributed and copyrighted by @@ -53,10 +53,6 @@ Created 11/5/1995 Heikki Tuuri #include "page0zip.h" #include "trx0trx.h" #include "srv0start.h" -#include "que0que.h" -#include "read0read.h" -#include "row0row.h" -#include "ha_prototypes.h" /* prototypes for new functions added to ha_innodb.cc */ trx_t* innobase_get_trx(); @@ -314,30 +310,6 @@ read-ahead or flush occurs */ UNIV_INTERN ibool buf_debug_prints = FALSE; #endif /* UNIV_DEBUG */ -/* Buffer pool shared memory segment information */ -typedef struct buf_shm_info_struct buf_shm_info_t; - -struct buf_shm_info_struct { - char head_str[8]; - ulint binary_id; - ibool is_new; /* during initializing */ - ibool clean; /* clean shutdowned and free */ - ibool reusable; /* reusable */ - ulint buf_pool_size; /* backup value */ - ulint page_size; /* backup value */ - ulint frame_offset; /* offset of the first frame based on chunk->mem */ - ulint zip_hash_offset; - ulint zip_hash_n; - - ulint checksum; - - buf_pool_t buf_pool_backup; - buf_chunk_t chunk_backup; - - ib_uint64_t dummy; -}; - -#define BUF_SHM_INFO_HEAD "XTRA_SHM" #endif /* !UNIV_HOTBACKUP */ /********************************************************************//** @@ -767,6 +739,10 @@ buf_block_init( block->page.in_flush_list = FALSE; block->page.in_free_list = FALSE; #endif /* UNIV_DEBUG */ + block->page.flush_list.prev = NULL; + block->page.flush_list.next = NULL; + block->page.zip_list.prev = NULL; + block->page.zip_list.next = NULL; block->page.in_LRU_list = FALSE; block->in_unzip_LRU_list = FALSE; #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG @@ -784,45 +760,6 @@ buf_block_init( #endif /* UNIV_SYNC_DEBUG */ } -static -void -buf_block_reuse( -/*============*/ - buf_block_t* block, - ptrdiff_t frame_offset) -{ - /* block_init */ - block->frame += frame_offset; - - UNIV_MEM_DESC(block->frame, UNIV_PAGE_SIZE, block); - - block->index = NULL; - -#ifdef UNIV_DEBUG - /* recreate later */ - block->page.in_page_hash = FALSE; - block->page.in_zip_hash = FALSE; -#endif /* UNIV_DEBUG */ - -#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG - block->n_pointers = 0; -#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ - - if (block->page.zip.data) - block->page.zip.data += frame_offset; - - block->is_hashed = FALSE; - - mutex_create(&block->mutex, SYNC_BUF_BLOCK); - - rw_lock_create(&block->lock, SYNC_LEVEL_VARYING); - ut_ad(rw_lock_validate(&(block->lock))); - -#ifdef UNIV_SYNC_DEBUG - rw_lock_create(&block->debug_latch, SYNC_NO_ORDER_CHECK); -#endif /* UNIV_SYNC_DEBUG */ -} - /********************************************************************//** Allocates a chunk of buffer frames. @return chunk, or NULL on failure */ @@ -835,190 +772,28 @@ buf_chunk_init( { buf_block_t* block; byte* frame; - ulint zip_hash_n = 0; - ulint zip_hash_mem_size = 0; - hash_table_t* zip_hash_tmp = NULL; ulint i; ulint size_target; - buf_shm_info_t* shm_info = NULL; /* Round down to a multiple of page size, although it already should be. */ mem_size = ut_2pow_round(mem_size, UNIV_PAGE_SIZE); size_target = (mem_size / UNIV_PAGE_SIZE) - 1; - - srv_buffer_pool_shm_is_reused = FALSE; - - if (srv_buffer_pool_shm_key) { - /* zip_hash size */ - zip_hash_n = (mem_size / UNIV_PAGE_SIZE) * 2; - zip_hash_mem_size = ut_2pow_round(hash_create_needed(zip_hash_n) - + (UNIV_PAGE_SIZE - 1), UNIV_PAGE_SIZE); - } - /* Reserve space for the block descriptors. */ mem_size += ut_2pow_round((mem_size / UNIV_PAGE_SIZE) * (sizeof *block) + (UNIV_PAGE_SIZE - 1), UNIV_PAGE_SIZE); - if (srv_buffer_pool_shm_key) { - mem_size += ut_2pow_round(sizeof(buf_shm_info_t) - + (UNIV_PAGE_SIZE - 1), UNIV_PAGE_SIZE); - mem_size += zip_hash_mem_size; - } chunk->mem_size = mem_size; - - if (srv_buffer_pool_shm_key) { - ulint binary_id; - ibool is_new; - - ut_a(buf_pool->n_chunks == 1); - - fprintf(stderr, - "InnoDB: Warning: The innodb_buffer_pool_shm_key option has been specified.\n" - "InnoDB: Do not change the following between restarts of the server while this option is being used:\n" - "InnoDB: * the mysqld executable between restarts of the server.\n" - "InnoDB: * the value of innodb_buffer_pool_size.\n" - "InnoDB: * the value of innodb_page_size.\n" - "InnoDB: * datafiles created by InnoDB during this session.\n" - "InnoDB: Otherwise, data corruption in datafiles may result.\n"); - - /* FIXME: This is vague id still */ - binary_id = (ulint) ((byte*)mtr_commit - (byte*)btr_root_get) - + (ulint) ((byte*)os_get_os_version - (byte*)buf_calc_page_new_checksum) - + (ulint) ((byte*)page_dir_find_owner_slot - (byte*)dfield_data_is_binary_equal) - + (ulint) ((byte*)que_graph_publish - (byte*)dict_casedn_str) - + (ulint) ((byte*)read_view_oldest_copy_or_open_new - (byte*)fil_space_get_version) - + (ulint) ((byte*)rec_get_n_extern_new - (byte*)fsp_get_size_low) - + (ulint) ((byte*)row_get_trx_id_offset - (byte*)ha_create_func) - + (ulint) ((byte*)srv_set_io_thread_op_info - (byte*)thd_is_replication_slave_thread) - + (ulint) ((byte*)mutex_create_func - (byte*)ibuf_inside) - + (ulint) ((byte*)trx_set_detailed_error - (byte*)lock_check_trx_id_sanity) - + (ulint) ((byte*)ut_time - (byte*)mem_heap_strdup); - - chunk->mem = os_shm_alloc(&chunk->mem_size, srv_buffer_pool_shm_key, &is_new); - - if (UNIV_UNLIKELY(chunk->mem == NULL)) { - return(NULL); - } -init_again: -#ifdef UNIV_SET_MEM_TO_ZERO - if (is_new) { - memset(chunk->mem, '\0', chunk->mem_size); - } -#endif - /* for ut_fold_binary_32(), these values should be 32-bit aligned */ - ut_a(sizeof(buf_shm_info_t) % 4 == 0); - ut_a((ulint)chunk->mem % 4 == 0); - ut_a(chunk->mem_size % 4 == 0); - - shm_info = chunk->mem; - - zip_hash_tmp = (hash_table_t*)((byte*)chunk->mem + chunk->mem_size - zip_hash_mem_size); - - if (is_new) { - strncpy(shm_info->head_str, BUF_SHM_INFO_HEAD, 8); - shm_info->binary_id = binary_id; - shm_info->is_new = TRUE; /* changed to FALSE when the initialization is finished */ - shm_info->clean = FALSE; /* changed to TRUE when free the segment. */ - shm_info->reusable = FALSE; /* changed to TRUE when validation is finished. */ - shm_info->buf_pool_size = srv_buf_pool_size; - shm_info->page_size = srv_page_size; - shm_info->zip_hash_offset = chunk->mem_size - zip_hash_mem_size; - shm_info->zip_hash_n = zip_hash_n; - } else { - ulint checksum; - - if (strncmp(shm_info->head_str, BUF_SHM_INFO_HEAD, 8)) { - fprintf(stderr, - "InnoDB: Error: The shared memory segment seems not to be for buffer pool.\n"); - return(NULL); - } - if (shm_info->binary_id != binary_id) { - fprintf(stderr, - "InnoDB: Error: The shared memory segment seems not to be for this binary.\n"); - return(NULL); - } - if (shm_info->is_new) { - fprintf(stderr, - "InnoDB: Error: The shared memory was not initialized yet.\n"); - return(NULL); - } - if (shm_info->buf_pool_size != srv_buf_pool_size) { - fprintf(stderr, - "InnoDB: Error: srv_buf_pool_size is different (shm=%lu current=%lu).\n", - shm_info->buf_pool_size, srv_buf_pool_size); - return(NULL); - } - if (shm_info->page_size != srv_page_size) { - fprintf(stderr, - "InnoDB: Error: srv_page_size is different (shm=%lu current=%lu).\n", - shm_info->page_size, srv_page_size); - return(NULL); - } - if (!shm_info->reusable) { - fprintf(stderr, - "InnoDB: Warning: The shared memory has unrecoverable contents.\n" - "InnoDB: The shared memory segment is initialized.\n"); - is_new = TRUE; - goto init_again; - } - if (!shm_info->clean) { - fprintf(stderr, - "InnoDB: Warning: The shared memory was not shut down cleanly.\n" - "InnoDB: The shared memory segment is initialized.\n"); - is_new = TRUE; - goto init_again; - } - - ut_a(shm_info->zip_hash_offset == chunk->mem_size - zip_hash_mem_size); - ut_a(shm_info->zip_hash_n == zip_hash_n); - - /* check checksum */ - if (srv_buffer_pool_shm_checksum) { - checksum = ut_fold_binary_32((byte*)chunk->mem + sizeof(buf_shm_info_t), - chunk->mem_size - sizeof(buf_shm_info_t)); - } else { - checksum = BUF_NO_CHECKSUM_MAGIC; - } - - if (shm_info->checksum != BUF_NO_CHECKSUM_MAGIC - && shm_info->checksum != checksum) { - fprintf(stderr, - "InnoDB: Error: checksum of the shared memory is not match. " - "(stored=%lu calculated=%lu)\n", - shm_info->checksum, checksum); - return(NULL); - } - - /* flag to use the segment. */ - shm_info->clean = FALSE; /* changed to TRUE when free the segment. */ - } - - /* init zip_hash contents */ - if (is_new) { - hash_create_init(zip_hash_tmp, zip_hash_n); - } else { - /* adjust offset is done later */ - hash_create_reuse(zip_hash_tmp); - - srv_buffer_pool_shm_is_reused = TRUE; - } - } else { chunk->mem = os_mem_alloc_large(&chunk->mem_size); if (UNIV_UNLIKELY(chunk->mem == NULL)) { return(NULL); } - } /* Allocate the block descriptors from the start of the memory block. */ - if (srv_buffer_pool_shm_key) { - chunk->blocks = (buf_block_t*)((byte*)chunk->mem + sizeof(buf_shm_info_t)); - } else { chunk->blocks = chunk->mem; - } /* Align a pointer to the first frame. Note that when os_large_page_size is smaller than UNIV_PAGE_SIZE, @@ -1026,13 +801,8 @@ init_again: it is bigger, we may allocate more blocks than requested. */ frame = ut_align(chunk->mem, UNIV_PAGE_SIZE); - if (srv_buffer_pool_shm_key) { - /* reserve zip_hash space and always -1 for reproductibity */ - chunk->size = (chunk->mem_size - zip_hash_mem_size) / UNIV_PAGE_SIZE - 1; - } else { chunk->size = chunk->mem_size / UNIV_PAGE_SIZE - (frame != chunk->mem); - } /* Subtract the space needed for block descriptors. */ { @@ -1050,98 +820,6 @@ init_again: chunk->size = size_target; } - if (shm_info && !(shm_info->is_new)) { - /* convert the shared memory segment for reuse */ - ptrdiff_t phys_offset; - ptrdiff_t logi_offset; - ptrdiff_t blocks_offset; - void* previous_frame_address; - - if (chunk->size < shm_info->chunk_backup.size) { - fprintf(stderr, - "InnoDB: Error: The buffer pool became smaller because of allocated address.\n" - "InnoDB: Retrying may avoid this situation.\n"); - shm_info->clean = TRUE; /* release the flag for retrying */ - return(NULL); - } - - chunk->size = shm_info->chunk_backup.size; - phys_offset = frame - ((byte*)chunk->mem + shm_info->frame_offset); - logi_offset = frame - chunk->blocks[0].frame; - previous_frame_address = chunk->blocks[0].frame; - blocks_offset = (byte*)chunk->blocks - (byte*)shm_info->chunk_backup.blocks; - - if (phys_offset || logi_offset || blocks_offset) { - fprintf(stderr, - "InnoDB: Buffer pool in the shared memory segment should be converted.\n" - "InnoDB: Previous frames in address : %p\n" - "InnoDB: Previous frames were located : %p\n" - "InnoDB: Current frames should be located: %p\n" - "InnoDB: Pysical offset : %ld (%#lx)\n" - "InnoDB: Logical offset (frames) : %ld (%#lx)\n" - "InnoDB: Logical offset (blocks) : %ld (%#lx)\n", - (byte*)chunk->mem + shm_info->frame_offset, - chunk->blocks[0].frame, frame, - phys_offset, phys_offset, logi_offset, logi_offset, - blocks_offset, blocks_offset); - } else { - fprintf(stderr, - "InnoDB: Buffer pool in the shared memory segment can be used as it is.\n"); - } - - if (phys_offset) { - fprintf(stderr, - "InnoDB: Aligning physical offset..."); - - memmove(frame, (byte*)chunk->mem + shm_info->frame_offset, - chunk->size * UNIV_PAGE_SIZE); - - fprintf(stderr, - " Done.\n"); - } - - /* buf_block_t */ - block = chunk->blocks; - for (i = chunk->size; i--; ) { - buf_block_reuse(block, logi_offset); - block++; - } - - if (logi_offset || blocks_offset) { - fprintf(stderr, - "InnoDB: Aligning logical offset..."); - - - /* buf_pool_t buf_pool_backup */ - UT_LIST_OFFSET(flush_list, buf_page_t, shm_info->buf_pool_backup.flush_list, - previous_frame_address, logi_offset, blocks_offset); - UT_LIST_OFFSET(free, buf_page_t, shm_info->buf_pool_backup.free, - previous_frame_address, logi_offset, blocks_offset); - UT_LIST_OFFSET(LRU, buf_page_t, shm_info->buf_pool_backup.LRU, - previous_frame_address, logi_offset, blocks_offset); - if (shm_info->buf_pool_backup.LRU_old) - shm_info->buf_pool_backup.LRU_old = - (buf_page_t*)((byte*)(shm_info->buf_pool_backup.LRU_old) - + (((void*)shm_info->buf_pool_backup.LRU_old > previous_frame_address) - ? logi_offset : blocks_offset)); - - UT_LIST_OFFSET(unzip_LRU, buf_block_t, shm_info->buf_pool_backup.unzip_LRU, - previous_frame_address, logi_offset, blocks_offset); - - UT_LIST_OFFSET(zip_list, buf_page_t, shm_info->buf_pool_backup.zip_clean, - previous_frame_address, logi_offset, blocks_offset); - for (i = 0; i < BUF_BUDDY_SIZES_MAX; i++) { - UT_LIST_OFFSET(zip_list, buf_page_t, shm_info->buf_pool_backup.zip_free[i], - previous_frame_address, logi_offset, blocks_offset); - } - - HASH_OFFSET(zip_hash_tmp, buf_page_t, hash, - previous_frame_address, logi_offset, blocks_offset); - - fprintf(stderr, - " Done.\n"); - } - } else { /* Init block structs and assign frames for them. Then we assign the frames to the first blocks (we already mapped the memory above). */ @@ -1165,11 +843,6 @@ init_again: block++; frame += UNIV_PAGE_SIZE; } - } - - if (shm_info) { - shm_info->frame_offset = chunk->blocks[0].frame - (byte*)chunk->mem; - } return(chunk); } @@ -1286,76 +959,6 @@ buf_chunk_not_freed( return(NULL); } -/*********************************************************************//** -Checks that all blocks in the buffer chunk are in BUF_BLOCK_NOT_USED state. -@return TRUE if all freed */ -static -ibool -buf_chunk_all_free( -/*===============*/ - const buf_chunk_t* chunk) /*!< in: chunk being checked */ -{ - const buf_block_t* block; - ulint i; - - ut_ad(buf_pool); - ut_ad(buf_pool_mutex_own()); /* but we need all mutex here */ - - block = chunk->blocks; - - for (i = chunk->size; i--; block++) { - - if (buf_block_get_state(block) != BUF_BLOCK_NOT_USED) { - - return(FALSE); - } - } - - return(TRUE); -} - -/********************************************************************//** -Frees a chunk of buffer frames. */ -static -void -buf_chunk_free( -/*===========*/ - buf_chunk_t* chunk) /*!< out: chunk of buffers */ -{ - buf_block_t* block; - const buf_block_t* block_end; - - ut_ad(buf_pool_mutex_own()); /* but we need all mutex here */ - - block_end = chunk->blocks + chunk->size; - - for (block = chunk->blocks; block < block_end; block++) { - ut_a(buf_block_get_state(block) == BUF_BLOCK_NOT_USED); - ut_a(!block->page.zip.data); - - ut_ad(!block->page.in_LRU_list); - ut_ad(!block->in_unzip_LRU_list); - ut_ad(!block->page.in_flush_list); - /* Remove the block from the free list. */ - mutex_enter(&free_list_mutex); - ut_ad(block->page.in_free_list); - UT_LIST_REMOVE(free, buf_pool->free, (&block->page)); - mutex_exit(&free_list_mutex); - - /* Free the latches. */ - mutex_free(&block->mutex); - rw_lock_free(&block->lock); -#ifdef UNIV_SYNC_DEBUG - rw_lock_free(&block->debug_latch); -#endif /* UNIV_SYNC_DEBUG */ - UNIV_MEM_UNDESC(block); - } - - ut_a(!srv_buffer_pool_shm_key); - - os_mem_free_large(chunk->mem, chunk->mem_size); -} - /********************************************************************//** Creates the buffer pool. @return own: buf_pool object, NULL if not enough memory or error */ @@ -1402,10 +1005,7 @@ buf_pool_init(void) srv_buf_pool_curr_size = buf_pool->curr_size * UNIV_PAGE_SIZE; buf_pool->page_hash = hash_create(2 * buf_pool->curr_size); - /* zip_hash is allocated to shm when srv_buffer_pool_shm_key is enabled */ - if (!srv_buffer_pool_shm_key) { buf_pool->zip_hash = hash_create(2 * buf_pool->curr_size); - } buf_pool->last_printout_time = time(NULL); @@ -1420,86 +1020,6 @@ buf_pool_init(void) --------------------------- */ /* All fields are initialized by mem_zalloc(). */ - if (srv_buffer_pool_shm_key) { - buf_shm_info_t* shm_info; - - ut_a((byte*)chunk->blocks == (byte*)chunk->mem + sizeof(buf_shm_info_t)); - shm_info = chunk->mem; - - buf_pool->zip_hash = (hash_table_t*)((byte*)chunk->mem + shm_info->zip_hash_offset); - - if(shm_info->is_new) { - shm_info->is_new = FALSE; /* initialization was finished */ - } else { - buf_block_t* block = chunk->blocks; - buf_page_t* b; - - /* shm_info->buf_pool_backup should be converted */ - /* at buf_chunk_init(). So copy simply. */ - buf_pool->flush_list = shm_info->buf_pool_backup.flush_list; - buf_pool->freed_page_clock = shm_info->buf_pool_backup.freed_page_clock; - buf_pool->free = shm_info->buf_pool_backup.free; - buf_pool->LRU = shm_info->buf_pool_backup.LRU; - buf_pool->LRU_old = shm_info->buf_pool_backup.LRU_old; - buf_pool->LRU_old_len = shm_info->buf_pool_backup.LRU_old_len; - buf_pool->unzip_LRU = shm_info->buf_pool_backup.unzip_LRU; - buf_pool->zip_clean = shm_info->buf_pool_backup.zip_clean; - for (i = 0; i < BUF_BUDDY_SIZES_MAX; i++) { - buf_pool->zip_free[i] = shm_info->buf_pool_backup.zip_free[i]; - } - - for (i = 0; i < chunk->size; i++, block++) { - if (buf_block_get_state(block) - == BUF_BLOCK_FILE_PAGE) { - ut_d(block->page.in_page_hash = TRUE); - HASH_INSERT(buf_page_t, hash, buf_pool->page_hash, - buf_page_address_fold( - block->page.space, - block->page.offset), - &block->page); - } - } - - for (b = UT_LIST_GET_FIRST(buf_pool->zip_clean); b; - b = UT_LIST_GET_NEXT(zip_list, b)) { - ut_ad(!b->in_flush_list); - ut_ad(b->in_LRU_list); - - ut_d(b->in_page_hash = TRUE); - HASH_INSERT(buf_page_t, hash, buf_pool->page_hash, - buf_page_address_fold(b->space, b->offset), b); - } - - for (b = UT_LIST_GET_FIRST(buf_pool->flush_list); b; - b = UT_LIST_GET_NEXT(flush_list, b)) { - ut_ad(b->in_flush_list); - ut_ad(b->in_LRU_list); - - switch (buf_page_get_state(b)) { - case BUF_BLOCK_ZIP_DIRTY: - ut_d(b->in_page_hash = TRUE); - HASH_INSERT(buf_page_t, hash, buf_pool->page_hash, - buf_page_address_fold(b->space, - b->offset), b); - break; - case BUF_BLOCK_FILE_PAGE: - /* uncompressed page */ - break; - case BUF_BLOCK_ZIP_FREE: - case BUF_BLOCK_ZIP_PAGE: - case BUF_BLOCK_NOT_USED: - case BUF_BLOCK_READY_FOR_USE: - case BUF_BLOCK_MEMORY: - case BUF_BLOCK_REMOVE_HASH: - ut_error; - break; - } - } - - - } - } - mutex_exit(&LRU_list_mutex); rw_lock_x_unlock(&page_hash_latch); buf_pool_mutex_exit(); @@ -1524,49 +1044,16 @@ buf_pool_free(void) buf_chunk_t* chunk; buf_chunk_t* chunks; - if (srv_buffer_pool_shm_key) { - buf_shm_info_t* shm_info; - - ut_a(buf_pool->n_chunks == 1); - - chunk = buf_pool->chunks; - shm_info = chunk->mem; - ut_a((byte*)chunk->blocks == (byte*)chunk->mem + sizeof(buf_shm_info_t)); - - /* validation the shared memory segment doesn't have unrecoverable contents. */ - /* Currently, validation became not needed */ - shm_info->reusable = TRUE; - - memcpy(&(shm_info->buf_pool_backup), buf_pool, sizeof(buf_pool_t)); - memcpy(&(shm_info->chunk_backup), chunk, sizeof(buf_chunk_t)); - - if (srv_fast_shutdown < 2) { - if (srv_buffer_pool_shm_checksum) { - shm_info->checksum = ut_fold_binary_32((byte*)chunk->mem + sizeof(buf_shm_info_t), - chunk->mem_size - sizeof(buf_shm_info_t)); - } else { - shm_info->checksum = BUF_NO_CHECKSUM_MAGIC; - } - shm_info->clean = TRUE; - } - - os_shm_free(chunk->mem, chunk->mem_size); - } else { chunks = buf_pool->chunks; chunk = chunks + buf_pool->n_chunks; while (--chunk >= chunks) { - /* Bypass the checks of buf_chunk_free(), since they - would fail at shutdown. */ os_mem_free_large(chunk->mem, chunk->mem_size); } - } mem_free(buf_pool->chunks); hash_table_free(buf_pool->page_hash); - if (!srv_buffer_pool_shm_key) { hash_table_free(buf_pool->zip_hash); - } mem_free(buf_pool); buf_pool = NULL; } @@ -1739,335 +1226,6 @@ buf_relocate( HASH_INSERT(buf_page_t, hash, buf_pool->page_hash, fold, dpage); } -/********************************************************************//** -Shrinks the buffer pool. */ -static -void -buf_pool_shrink( -/*============*/ - ulint chunk_size) /*!< in: number of pages to remove */ -{ - buf_chunk_t* chunks; - buf_chunk_t* chunk; - ulint max_size; - ulint max_free_size; - buf_chunk_t* max_chunk; - buf_chunk_t* max_free_chunk; - - ut_ad(!buf_pool_mutex_own()); - -try_again: - btr_search_disable(); /* Empty the adaptive hash index again */ - //buf_pool_mutex_enter(); - mutex_enter(&LRU_list_mutex); - - if (srv_buffer_pool_shm_key) { - /* Cannot support shrink */ - goto func_done; - } - -shrink_again: - if (buf_pool->n_chunks <= 1) { - - /* Cannot shrink if there is only one chunk */ - goto func_done; - } - - /* Search for the largest free chunk - not larger than the size difference */ - chunks = buf_pool->chunks; - chunk = chunks + buf_pool->n_chunks; - max_size = max_free_size = 0; - max_chunk = max_free_chunk = NULL; - - while (--chunk >= chunks) { - if (chunk->size <= chunk_size - && chunk->size > max_free_size) { - if (chunk->size > max_size) { - max_size = chunk->size; - max_chunk = chunk; - } - - if (buf_chunk_all_free(chunk)) { - max_free_size = chunk->size; - max_free_chunk = chunk; - } - } - } - - if (!max_free_size) { - - ulint dirty = 0; - ulint nonfree = 0; - buf_block_t* block; - buf_block_t* bend; - - /* Cannot shrink: try again later - (do not assign srv_buf_pool_old_size) */ - if (!max_chunk) { - - goto func_exit; - } - - block = max_chunk->blocks; - bend = block + max_chunk->size; - - /* Move the blocks of chunk to the end of the - LRU list and try to flush them. */ - for (; block < bend; block++) { - switch (buf_block_get_state(block)) { - case BUF_BLOCK_NOT_USED: - continue; - case BUF_BLOCK_FILE_PAGE: - break; - default: - nonfree++; - continue; - } - - mutex_enter(&block->mutex); - /* The following calls will temporarily - release block->mutex and buf_pool_mutex. - Therefore, we have to always retry, - even if !dirty && !nonfree. */ - - if (!buf_flush_ready_for_replace(&block->page)) { - - buf_LRU_make_block_old(&block->page); - dirty++; - } else if (buf_LRU_free_block(&block->page, TRUE, FALSE) - != BUF_LRU_FREED) { - nonfree++; - } - - mutex_exit(&block->mutex); - } - - //buf_pool_mutex_exit(); - mutex_exit(&LRU_list_mutex); - - /* Request for a flush of the chunk if it helps. - Do not flush if there are non-free blocks, since - flushing will not make the chunk freeable. */ - if (nonfree) { - /* Avoid busy-waiting. */ - os_thread_sleep(100000); - } else if (dirty - && buf_flush_batch(BUF_FLUSH_LRU, dirty, 0) - == ULINT_UNDEFINED) { - - buf_flush_wait_batch_end(BUF_FLUSH_LRU); - } - - goto try_again; - } - - max_size = max_free_size; - max_chunk = max_free_chunk; - - srv_buf_pool_old_size = srv_buf_pool_size; - - /* Rewrite buf_pool->chunks. Copy everything but max_chunk. */ - chunks = mem_alloc((buf_pool->n_chunks - 1) * sizeof *chunks); - memcpy(chunks, buf_pool->chunks, - (max_chunk - buf_pool->chunks) * sizeof *chunks); - memcpy(chunks + (max_chunk - buf_pool->chunks), - max_chunk + 1, - buf_pool->chunks + buf_pool->n_chunks - - (max_chunk + 1)); - ut_a(buf_pool->curr_size > max_chunk->size); - buf_pool->curr_size -= max_chunk->size; - srv_buf_pool_curr_size = buf_pool->curr_size * UNIV_PAGE_SIZE; - chunk_size -= max_chunk->size; - buf_chunk_free(max_chunk); - mem_free(buf_pool->chunks); - buf_pool->chunks = chunks; - buf_pool->n_chunks--; - - /* Allow a slack of one megabyte. */ - if (chunk_size > 1048576 / UNIV_PAGE_SIZE) { - - goto shrink_again; - } - -func_done: - srv_buf_pool_old_size = srv_buf_pool_size; -func_exit: - //buf_pool_mutex_exit(); - mutex_exit(&LRU_list_mutex); - btr_search_enable(); -} - -/********************************************************************//** -Rebuild buf_pool->page_hash. */ -static -void -buf_pool_page_hash_rebuild(void) -/*============================*/ -{ - ulint i; - ulint n_chunks; - buf_chunk_t* chunk; - hash_table_t* page_hash; - hash_table_t* zip_hash; - buf_page_t* b; - - //buf_pool_mutex_enter(); - mutex_enter(&LRU_list_mutex); - rw_lock_x_lock(&page_hash_latch); - mutex_enter(&flush_list_mutex); - - - /* Free, create, and populate the hash table. */ - hash_table_free(buf_pool->page_hash); - buf_pool->page_hash = page_hash = hash_create(2 * buf_pool->curr_size); - zip_hash = hash_create(2 * buf_pool->curr_size); - - HASH_MIGRATE(buf_pool->zip_hash, zip_hash, buf_page_t, hash, - BUF_POOL_ZIP_FOLD_BPAGE); - - hash_table_free(buf_pool->zip_hash); - buf_pool->zip_hash = zip_hash; - - /* Insert the uncompressed file pages to buf_pool->page_hash. */ - - chunk = buf_pool->chunks; - n_chunks = buf_pool->n_chunks; - - for (i = 0; i < n_chunks; i++, chunk++) { - ulint j; - buf_block_t* block = chunk->blocks; - - for (j = 0; j < chunk->size; j++, block++) { - if (buf_block_get_state(block) - == BUF_BLOCK_FILE_PAGE) { - ut_ad(!block->page.in_zip_hash); - ut_ad(block->page.in_page_hash); - - HASH_INSERT(buf_page_t, hash, page_hash, - buf_page_address_fold( - block->page.space, - block->page.offset), - &block->page); - } - } - } - - /* Insert the compressed-only pages to buf_pool->page_hash. - All such blocks are either in buf_pool->zip_clean or - in buf_pool->flush_list. */ - - for (b = UT_LIST_GET_FIRST(buf_pool->zip_clean); b; - b = UT_LIST_GET_NEXT(zip_list, b)) { - ut_a(buf_page_get_state(b) == BUF_BLOCK_ZIP_PAGE); - ut_ad(!b->in_flush_list); - ut_ad(b->in_LRU_list); - ut_ad(b->in_page_hash); - ut_ad(!b->in_zip_hash); - - HASH_INSERT(buf_page_t, hash, page_hash, - buf_page_address_fold(b->space, b->offset), b); - } - - for (b = UT_LIST_GET_FIRST(buf_pool->flush_list); b; - b = UT_LIST_GET_NEXT(flush_list, b)) { - ut_ad(b->in_flush_list); - ut_ad(b->in_LRU_list); - ut_ad(b->in_page_hash); - ut_ad(!b->in_zip_hash); - - switch (buf_page_get_state(b)) { - case BUF_BLOCK_ZIP_DIRTY: - HASH_INSERT(buf_page_t, hash, page_hash, - buf_page_address_fold(b->space, - b->offset), b); - break; - case BUF_BLOCK_FILE_PAGE: - /* uncompressed page */ - break; - case BUF_BLOCK_ZIP_FREE: - case BUF_BLOCK_ZIP_PAGE: - case BUF_BLOCK_NOT_USED: - case BUF_BLOCK_READY_FOR_USE: - case BUF_BLOCK_MEMORY: - case BUF_BLOCK_REMOVE_HASH: - ut_error; - break; - } - } - - //buf_pool_mutex_exit(); - mutex_exit(&LRU_list_mutex); - rw_lock_x_unlock(&page_hash_latch); - mutex_exit(&flush_list_mutex); -} - -/********************************************************************//** -Resizes the buffer pool. */ -UNIV_INTERN -void -buf_pool_resize(void) -/*=================*/ -{ - if (srv_buffer_pool_shm_key) { - /* Cannot support resize */ - return; - } - - //buf_pool_mutex_enter(); - mutex_enter(&LRU_list_mutex); - - if (srv_buf_pool_old_size == srv_buf_pool_size) { - - //buf_pool_mutex_exit(); - mutex_exit(&LRU_list_mutex); - return; - } - - if (srv_buf_pool_curr_size + 1048576 > srv_buf_pool_size) { - - //buf_pool_mutex_exit(); - mutex_exit(&LRU_list_mutex); - - /* Disable adaptive hash indexes and empty the index - in order to free up memory in the buffer pool chunks. */ - buf_pool_shrink((srv_buf_pool_curr_size - srv_buf_pool_size) - / UNIV_PAGE_SIZE); - } else if (srv_buf_pool_curr_size + 1048576 < srv_buf_pool_size) { - - /* Enlarge the buffer pool by at least one megabyte */ - - ulint mem_size - = srv_buf_pool_size - srv_buf_pool_curr_size; - buf_chunk_t* chunks; - buf_chunk_t* chunk; - - chunks = mem_alloc((buf_pool->n_chunks + 1) * sizeof *chunks); - - memcpy(chunks, buf_pool->chunks, buf_pool->n_chunks - * sizeof *chunks); - - chunk = &chunks[buf_pool->n_chunks]; - - if (!buf_chunk_init(chunk, mem_size)) { - mem_free(chunks); - } else { - buf_pool->curr_size += chunk->size; - srv_buf_pool_curr_size = buf_pool->curr_size - * UNIV_PAGE_SIZE; - mem_free(buf_pool->chunks); - buf_pool->chunks = chunks; - buf_pool->n_chunks++; - } - - srv_buf_pool_old_size = srv_buf_pool_size; - //buf_pool_mutex_exit(); - mutex_exit(&LRU_list_mutex); - } - - buf_pool_page_hash_rebuild(); -} - /********************************************************************//** Moves a page to the start of the buffer pool LRU list. This high-level function can be used to prevent an important page from slipping out of @@ -2302,6 +1460,27 @@ lookup: #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */ } + if (UNIV_UNLIKELY(bpage->space_was_being_deleted)) { + /* This page is obsoleted, should discard and retry */ + rw_lock_s_unlock(&page_hash_latch); + + mutex_enter(&LRU_list_mutex); + block_mutex = buf_page_get_mutex_enter(bpage); + + if (UNIV_UNLIKELY(!block_mutex)) { + mutex_exit(&LRU_list_mutex); + goto lookup; + } + + buf_LRU_free_block(bpage, TRUE, TRUE); + + mutex_exit(&LRU_list_mutex); + mutex_exit(block_mutex); + block_mutex = NULL; + + goto lookup; + } + if (UNIV_UNLIKELY(!bpage->zip.data)) { /* There is no compressed page. */ err_exit: @@ -2310,13 +1489,12 @@ err_exit: return(NULL); } - if (srv_pass_corrupt_table) { + if (srv_pass_corrupt_table <= 1) { if (bpage->is_corrupt) { rw_lock_s_unlock(&page_hash_latch); return(NULL); } } - ut_a(!(bpage->is_corrupt)); block_mutex = buf_page_get_mutex_enter(bpage); @@ -2339,13 +1517,32 @@ err_exit: case BUF_BLOCK_FILE_PAGE: ut_a(block_mutex == &((buf_block_t*) bpage)->mutex); - /* Discard the uncompressed page frame if possible. */ - if (buf_LRU_free_block(bpage, FALSE, FALSE) == BUF_LRU_FREED) { + /* release mutex to obey to latch-order */ + mutex_exit(block_mutex); + /* get LRU_list_mutex for buf_LRU_free_block() */ + mutex_enter(&LRU_list_mutex); + mutex_enter(block_mutex); + + if (UNIV_UNLIKELY(bpage->space != space + || bpage->offset != offset + || !bpage->in_LRU_list + || !bpage->zip.data)) { + /* someone should interrupt, retry */ + mutex_exit(&LRU_list_mutex); mutex_exit(block_mutex); goto lookup; } + /* Discard the uncompressed page frame if possible. */ + if (buf_LRU_free_block(bpage, FALSE, TRUE)) { + mutex_exit(&LRU_list_mutex); + mutex_exit(block_mutex); + goto lookup; + } + + mutex_exit(&LRU_list_mutex); + buf_block_buf_fix_inc((buf_block_t*) bpage, __FILE__, __LINE__); goto got_block; @@ -2515,16 +1712,19 @@ buf_block_align( /* TODO: protect buf_pool->chunks with a mutex (it will currently remain constant after buf_pool_init()) */ for (chunk = buf_pool->chunks, i = buf_pool->n_chunks; i--; chunk++) { - lint offs = ptr - chunk->blocks->frame; + ulint offs; - if (UNIV_UNLIKELY(offs < 0)) { + if (UNIV_UNLIKELY(ptr < chunk->blocks->frame)) { continue; } + /* else */ + + offs = ptr - chunk->blocks->frame; offs >>= UNIV_PAGE_SIZE_SHIFT; - if (UNIV_LIKELY((ulint) offs < chunk->size)) { + if (UNIV_LIKELY(offs < chunk->size)) { buf_block_t* block = &chunk->blocks[offs]; /* The function buf_chunk_init() invokes @@ -2650,7 +1850,7 @@ buf_page_get_gen( ulint rw_latch,/*!< in: RW_S_LATCH, RW_X_LATCH, RW_NO_LATCH */ buf_block_t* guess, /*!< in: guessed block or NULL */ ulint mode, /*!< in: BUF_GET, BUF_GET_IF_IN_POOL, - BUF_GET_NO_LATCH */ + BUF_PEEK_IF_IN_POOL, BUF_GET_NO_LATCH */ const char* file, /*!< in: file name */ ulint line, /*!< in: line where called */ mtr_t* mtr) /*!< in: mini-transaction */ @@ -2660,7 +1860,7 @@ buf_page_get_gen( ulint fix_type; ibool must_read; ulint retries = 0; - mutex_t* block_mutex; + mutex_t* block_mutex = NULL; trx_t* trx = NULL; ulint sec; ulint ms; @@ -2672,9 +1872,19 @@ buf_page_get_gen( ut_ad((rw_latch == RW_S_LATCH) || (rw_latch == RW_X_LATCH) || (rw_latch == RW_NO_LATCH)); - ut_ad((mode != BUF_GET_NO_LATCH) || (rw_latch == RW_NO_LATCH)); - ut_ad((mode == BUF_GET) || (mode == BUF_GET_IF_IN_POOL) - || (mode == BUF_GET_NO_LATCH)); +#ifdef UNIV_DEBUG + switch (mode) { + case BUF_GET_NO_LATCH: + ut_ad(rw_latch == RW_NO_LATCH); + break; + case BUF_GET: + case BUF_GET_IF_IN_POOL: + case BUF_PEEK_IF_IN_POOL: + break; + default: + ut_error; + } +#endif /* UNIV_DEBUG */ ut_ad(zip_size == fil_space_get_zip_size(space)); ut_ad(ut_is_2pow(zip_size)); #ifndef UNIV_LOG_DEBUG @@ -2692,13 +1902,8 @@ loop: block_mutex = buf_page_get_mutex_enter((buf_page_t*)block); /* If the guess is a compressed page descriptor that - has been allocated by buf_buddy_alloc(), it may have - been invalidated by buf_buddy_relocate(). In that - case, block could point to something that happens to - contain the expected bits in block->page. Similarly, - the guess may be pointing to a buffer pool chunk that - has been released when resizing the buffer pool. */ - + has been allocated by buf_page_alloc_descriptor(), + it may have been freed by buf_relocate(). */ if (!block_mutex) { block = guess = NULL; } else if (!buf_block_is_uncompressed(block) @@ -2719,6 +1924,27 @@ loop: rw_lock_s_lock(&page_hash_latch); block = (buf_block_t*) buf_page_hash_get(space, offset); if (block) { + if (UNIV_UNLIKELY(block->page.space_was_being_deleted)) { + /* This page is obsoleted, should discard and retry */ + rw_lock_s_unlock(&page_hash_latch); + + mutex_enter(&LRU_list_mutex); + block_mutex = buf_page_get_mutex_enter((buf_page_t*)block); + + if (UNIV_UNLIKELY(!block_mutex)) { + mutex_exit(&LRU_list_mutex); + goto loop; + } + + buf_LRU_free_block((buf_page_t*)block, TRUE, TRUE); + + mutex_exit(&LRU_list_mutex); + mutex_exit(block_mutex); + block_mutex = NULL; + + goto loop; + } + block_mutex = buf_page_get_mutex_enter((buf_page_t*)block); ut_a(block_mutex); } @@ -2731,7 +1957,8 @@ loop2: //buf_pool_mutex_exit(); - if (mode == BUF_GET_IF_IN_POOL) { + if (mode == BUF_GET_IF_IN_POOL + || mode == BUF_PEEK_IF_IN_POOL) { return(NULL); } @@ -2770,7 +1997,8 @@ loop2: must_read = buf_block_get_io_fix(block) == BUF_IO_READ; - if (must_read && mode == BUF_GET_IF_IN_POOL) { + if (must_read && (mode == BUF_GET_IF_IN_POOL + || mode == BUF_PEEK_IF_IN_POOL)) { /* The page is only being read to buffer */ //buf_pool_mutex_exit(); mutex_exit(block_mutex); @@ -2778,13 +2006,12 @@ loop2: return(NULL); } - if (srv_pass_corrupt_table) { + if (srv_pass_corrupt_table <= 1) { if (block->page.is_corrupt) { mutex_exit(block_mutex); return(NULL); } } - ut_a(!(block->page.is_corrupt)); switch (buf_block_get_state(block)) { buf_page_t* bpage; @@ -2896,8 +2123,10 @@ wait_until_unfixed: if (buf_page_get_state(&block->page) == BUF_BLOCK_ZIP_PAGE) { +#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG UT_LIST_REMOVE(zip_list, buf_pool->zip_clean, &block->page); +#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */ ut_ad(!block->page.in_flush_list); } else { /* Relocate buf_pool->flush_list. */ @@ -2930,10 +2159,10 @@ wait_until_unfixed: buf_pool->n_pend_unzip++; mutex_exit(&buf_pool_mutex); - buf_buddy_free(bpage, sizeof *bpage, FALSE); - //buf_pool_mutex_exit(); + buf_page_free_descriptor(bpage); + /* Decompress the page and apply buffered operations while not holding buf_pool_mutex or block->mutex. */ success = buf_zip_decompress(block, srv_use_checksums); @@ -2980,9 +2209,9 @@ wait_until_unfixed: /* Try to evict the block from the buffer pool, to use the insert buffer as much as possible. */ - if (buf_LRU_free_block(&block->page, TRUE, FALSE) == BUF_LRU_FREED) { - buf_pool_mutex_exit(); - mutex_exit(&block->mutex); + if (buf_LRU_free_block(&block->page, TRUE, FALSE)) { + //buf_pool_mutex_exit(); + mutex_exit(block_mutex); fprintf(stderr, "innodb_change_buffering_debug evict %u %u\n", (unsigned) space, (unsigned) offset); @@ -3010,7 +2239,9 @@ wait_until_unfixed: //buf_pool_mutex_exit(); mutex_exit(block_mutex); - buf_page_set_accessed_make_young(&block->page, access_time); + if (UNIV_LIKELY(mode != BUF_PEEK_IF_IN_POOL)) { + buf_page_set_accessed_make_young(&block->page, access_time); + } #if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG ut_a(!block->page.file_page_was_freed); @@ -3076,7 +2307,7 @@ wait_until_unfixed: mtr_memo_push(mtr, block, fix_type); - if (!access_time) { + if (UNIV_LIKELY(mode != BUF_PEEK_IF_IN_POOL) && !access_time) { /* In the case of a first access, try to apply linear read-ahead */ @@ -3530,6 +2761,7 @@ buf_page_init_for_read( { buf_block_t* block; buf_page_t* bpage; + buf_page_t* bpage_in_bp; mtr_t mtr; ibool lru = FALSE; void* data; @@ -3565,11 +2797,29 @@ buf_page_init_for_read( ut_ad(block); } +retry: //buf_pool_mutex_enter(); mutex_enter(&LRU_list_mutex); rw_lock_x_lock(&page_hash_latch); - if (buf_page_hash_get(space, offset)) { + bpage_in_bp = buf_page_hash_get(space, offset); + + if (UNIV_UNLIKELY(bpage_in_bp && bpage_in_bp->space_was_being_deleted)) { + mutex_t* block_mutex = buf_page_get_mutex_enter(bpage_in_bp); + + /* This page is obsoleted, should discard and retry */ + rw_lock_x_unlock(&page_hash_latch); + ut_a(block_mutex); + + buf_LRU_free_block(bpage_in_bp, TRUE, TRUE); + + mutex_exit(&LRU_list_mutex); + mutex_exit(block_mutex); + + goto retry; + } + + if (bpage_in_bp) { /* The page is already in the buffer pool. */ err_exit: if (block) { @@ -3647,17 +2897,12 @@ err_exit: mutex_exit(&LRU_list_mutex); mutex_exit(&block->mutex); } else { - /* Defer buf_buddy_alloc() until after the block has - been found not to exist. The buf_buddy_alloc() and - buf_buddy_free() calls may be expensive because of - buf_buddy_relocate(). */ /* The compressed page must be allocated before the control block (bpage), in order to avoid the invocation of buf_buddy_relocate_block() on uninitialized data. */ data = buf_buddy_alloc(zip_size, &lru, TRUE); - bpage = buf_buddy_alloc(sizeof *bpage, &lru, TRUE); /* If buf_buddy_alloc() allocated storage from the LRU list, it released and reacquired buf_pool_mutex. Thus, we must @@ -3665,17 +2910,16 @@ err_exit: if (UNIV_UNLIKELY(lru) && UNIV_LIKELY_NULL(buf_page_hash_get(space, offset))) { - /* The block was added by some other thread. */ - buf_buddy_free(bpage, sizeof *bpage, TRUE); buf_buddy_free(data, zip_size, TRUE); mutex_exit(&LRU_list_mutex); rw_lock_x_unlock(&page_hash_latch); - bpage = NULL; goto func_exit; } + bpage = buf_page_alloc_descriptor(); + page_zip_des_init(&bpage->zip); page_zip_set_size(&bpage->zip, zip_size); bpage->zip.data = data; @@ -3705,9 +2949,11 @@ err_exit: /* The block must be put to the LRU list, to the old blocks */ buf_LRU_add_block(bpage, TRUE/* to old blocks */); +#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG mutex_enter(&flush_list_mutex); buf_LRU_insert_zip_clean(bpage); mutex_exit(&flush_list_mutex); +#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */ mutex_exit(&LRU_list_mutex); @@ -3758,12 +3004,28 @@ buf_page_create( free_block = buf_LRU_get_free_block(); +retry: //buf_pool_mutex_enter(); mutex_enter(&LRU_list_mutex); rw_lock_x_lock(&page_hash_latch); block = (buf_block_t*) buf_page_hash_get(space, offset); + if (UNIV_UNLIKELY(block && block->page.space_was_being_deleted)) { + mutex_t* block_mutex = buf_page_get_mutex_enter((buf_page_t*)block); + + /* This page is obsoleted, should discard and retry */ + rw_lock_x_unlock(&page_hash_latch); + ut_a(block_mutex); + + buf_LRU_free_block((buf_page_t*)block, TRUE, TRUE); + + mutex_exit(&LRU_list_mutex); + mutex_exit(block_mutex); + + goto retry; + } + if (block && buf_page_in_file(&block->page)) { #ifdef UNIV_IBUF_COUNT_DEBUG ut_a(ibuf_count_get(space, offset) == 0); @@ -3888,8 +3150,7 @@ UNIV_INTERN void buf_page_io_complete( /*=================*/ - buf_page_t* bpage, /*!< in: pointer to the block in question */ - trx_t* trx) + buf_page_t* bpage) /*!< in: pointer to the block in question */ { enum buf_io_fix io_type; const ibool uncompressed = (buf_page_get_state(bpage) @@ -4011,14 +3272,18 @@ corrupt: if (srv_pass_corrupt_table && !trx_sys_sys_space(bpage->space) && bpage->space < SRV_LOG_SPACE_FIRST_ID) { + trx_t* trx; + fprintf(stderr, "InnoDB: space %u will be treated as corrupt.\n", bpage->space); fil_space_set_corrupt(bpage->space); - if (trx && trx->dict_operation_lock_mode == 0) { - dict_table_set_corrupt_by_space(bpage->space, TRUE); - } else { + + trx = innobase_get_trx(); + if (trx && trx->dict_operation_lock_mode == RW_X_LATCH) { dict_table_set_corrupt_by_space(bpage->space, FALSE); + } else { + dict_table_set_corrupt_by_space(bpage->space, TRUE); } bpage->is_corrupt = TRUE; } else @@ -4780,12 +4045,16 @@ buf_print_io( /* Statistics about read ahead algorithm */ fprintf(file, "Pages read ahead %.2f/s," - " evicted without access %.2f/s\n", + " evicted without access %.2f/s," + " Random read ahead %.2f/s\n", (buf_pool->stat.n_ra_pages_read - buf_pool->old_stat.n_ra_pages_read) / time_elapsed, (buf_pool->stat.n_ra_pages_evicted - buf_pool->old_stat.n_ra_pages_evicted) + / time_elapsed, + (buf_pool->stat.n_ra_pages_read_rnd + - buf_pool->old_stat.n_ra_pages_read_rnd) / time_elapsed); /* Print some values to help us with visualizing what is diff --git a/buf/buf0flu.c b/buf/buf0flu.c index cda8d3b170e..0ea3ed29d2b 100644 --- a/buf/buf0flu.c +++ b/buf/buf0flu.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 @@ -459,7 +459,9 @@ buf_flush_remove( case BUF_BLOCK_ZIP_DIRTY: buf_page_set_state(bpage, BUF_BLOCK_ZIP_PAGE); UT_LIST_REMOVE(flush_list, buf_pool->flush_list, bpage); +#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG buf_LRU_insert_zip_clean(bpage); +#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */ break; case BUF_BLOCK_FILE_PAGE: UT_LIST_REMOVE(flush_list, buf_pool->flush_list, bpage); @@ -769,7 +771,7 @@ corrupted_page: flush: /* Now flush the doublewrite buffer data to disk */ - fil_flush(srv_doublewrite_file ? TRX_DOUBLEWRITE_SPACE : TRX_SYS_SPACE); + fil_flush(srv_doublewrite_file ? TRX_DOUBLEWRITE_SPACE : TRX_SYS_SPACE, FALSE); /* We know that the writes have been flushed to disk now and in recovery we will find them in the doublewrite buffer @@ -1084,7 +1086,7 @@ buf_flush_page_try( /*===============*/ buf_block_t* block) /*!< in/out: buffer control block */ { - ut_ad(buf_pool_mutex_own()); + //ut_ad(buf_pool_mutex_own()); ut_ad(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE); ut_ad(mutex_own(&block->mutex)); @@ -1092,8 +1094,11 @@ buf_flush_page_try( return(FALSE); } + buf_pool_mutex_enter(); + if (buf_pool->n_flush[BUF_FLUSH_LRU] > 0 || buf_pool->init_flush[BUF_FLUSH_LRU]) { + buf_pool_mutex_exit(); /* There is already a flush batch of the same type running */ return(FALSE); } diff --git a/buf/buf0lru.c b/buf/buf0lru.c index 33db5dce193..7f4d0ffaa2f 100644 --- a/buf/buf0lru.c +++ b/buf/buf0lru.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 @@ -259,18 +259,20 @@ buf_LRU_drop_page_hash_for_tablespace( * BUF_LRU_DROP_SEARCH_HASH_SIZE); //buf_pool_mutex_enter(); mutex_enter(&LRU_list_mutex); + num_entries = 0; scan_again: - num_entries = 0; bpage = UT_LIST_GET_LAST(buf_pool->LRU); while (bpage != NULL) { + /* bpage->state,space,io_fix,buf_fix_count are protected by block_mutex at XtraDB */ mutex_t* block_mutex = buf_page_get_mutex_enter(bpage); buf_page_t* prev_bpage; + ibool is_fixed; prev_bpage = UT_LIST_GET_PREV(LRU, bpage); - if (!block_mutex) { + if (UNIV_UNLIKELY(!block_mutex)) { goto next_page; } @@ -278,59 +280,77 @@ scan_again: if (buf_page_get_state(bpage) != BUF_BLOCK_FILE_PAGE || bpage->space != id - || bpage->buf_fix_count > 0 || bpage->io_fix != BUF_IO_NONE) { - /* We leave the fixed pages as is in this scan. - To be dealt with later in the final scan. */ + /* Compressed pages are never hashed. + Skip blocks of other tablespaces. + Skip I/O-fixed blocks (to be dealt with later). */ + mutex_exit(block_mutex); +next_page: + bpage = prev_bpage; + continue; + } + + //mutex_enter(&((buf_block_t*) bpage)->mutex); + is_fixed = bpage->buf_fix_count > 0 + || !((buf_block_t*) bpage)->is_hashed; + //mutex_exit(&((buf_block_t*) bpage)->mutex); + + if (is_fixed) { mutex_exit(block_mutex); goto next_page; } - if (((buf_block_t*) bpage)->is_hashed) { + /* 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); - /* Store the offset(i.e.: page_no) in the array - so that we can drop 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); - ++num_entries; + ut_a(num_entries < BUF_LRU_DROP_SEARCH_HASH_SIZE); + ++num_entries; - if (num_entries < BUF_LRU_DROP_SEARCH_HASH_SIZE) { - goto next_page; - } - /* Array full. We release the buf_pool_mutex to - obey the latching order. */ - //buf_pool_mutex_exit(); - mutex_exit(&LRU_list_mutex); - - buf_LRU_drop_page_hash_batch(id, zip_size, page_arr, - num_entries); - num_entries = 0; - //buf_pool_mutex_enter(); - mutex_enter(&LRU_list_mutex); - } else { - mutex_exit(block_mutex); + if (num_entries < BUF_LRU_DROP_SEARCH_HASH_SIZE) { + goto next_page; } -next_page: - /* Note that we may have released the buf_pool mutex - above after reading the prev_bpage during processing - of a page_hash_batch (i.e.: when the array was full). - This means that prev_bpage can change in LRU list. - This is OK because this function is a 'best effort' - to drop as many search hash entries as possible and - it does not guarantee that ALL such entries will be - dropped. */ - bpage = prev_bpage; + /* Array full. We release the buf_pool_mutex to + obey the latching order. */ + //buf_pool_mutex_exit(); + mutex_exit(&LRU_list_mutex); + buf_LRU_drop_page_hash_batch(id, zip_size, page_arr, + num_entries); + //buf_pool_mutex_enter(); + mutex_enter(&LRU_list_mutex); + num_entries = 0; + + /* Note that we released the buf_pool mutex above + after reading the prev_bpage during processing of a + page_hash_batch (i.e.: when the array was full). + Because prev_bpage could belong to a compressed-only + block, it may have been relocated, and thus the + pointer cannot be trusted. Because bpage is of type + buf_block_t, it is safe to dereference. + + bpage can change in the LRU list. This is OK because + this function is a 'best effort' to drop as many + search hash entries as possible and it does not + guarantee that ALL such entries will be dropped. */ /* If, however, bpage has been removed from LRU list to the free list then we should restart the scan. bpage->state is protected by buf_pool mutex. */ - if (bpage && !buf_page_in_file(bpage)) { - ut_a(num_entries == 0); + + /* obtain block_mutex again to avoid race condition of bpage->state */ + block_mutex = buf_page_get_mutex_enter(bpage); + if (!block_mutex) { goto scan_again; } + + if (bpage + && buf_page_get_state(bpage) != BUF_BLOCK_FILE_PAGE) { + mutex_exit(block_mutex); + goto scan_again; + } + mutex_exit(block_mutex); } //buf_pool_mutex_exit(); @@ -372,7 +392,7 @@ scan_again: while (bpage != NULL) { buf_page_t* prev_bpage; - ibool prev_bpage_buf_fix = FALSE; + mutex_t* block_mutex = NULL; ut_a(buf_page_in_file(bpage)); @@ -385,26 +405,28 @@ scan_again: if (buf_page_get_space(bpage) != id) { /* Skip this block, as it does not belong to the space that is being invalidated. */ + goto next_page; } else if (buf_page_get_io_fix(bpage) != BUF_IO_NONE) { /* 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; } else { - mutex_t* block_mutex = buf_page_get_mutex_enter(bpage); + 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_no_mutex; + 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 @@ -414,108 +436,61 @@ scan_again: goto next_page; } - -#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)); - } -#endif - if (buf_page_get_state(bpage) != BUF_BLOCK_FILE_PAGE) { - /* This is a compressed-only block - descriptor. Ensure that prev_bpage - cannot be relocated when bpage is freed. */ - if (UNIV_LIKELY(prev_bpage != NULL)) { - switch (buf_page_get_state( - prev_bpage)) { - case BUF_BLOCK_FILE_PAGE: - /* Descriptors of uncompressed - blocks will not be relocated, - because we are holding the - buf_pool_mutex. */ - break; - case BUF_BLOCK_ZIP_PAGE: - case BUF_BLOCK_ZIP_DIRTY: - /* Descriptors of compressed- - only blocks can be relocated, - unless they are buffer-fixed. - Because both bpage and - prev_bpage are protected by - buf_pool_zip_mutex, it is - not necessary to acquire - further mutexes. */ - ut_ad(&buf_pool_zip_mutex - == block_mutex); - ut_ad(mutex_own(block_mutex)); - prev_bpage_buf_fix = TRUE; - prev_bpage->buf_fix_count++; - break; - default: - ut_error; - } - } - } else if (((buf_block_t*) bpage)->is_hashed) { - ulint page_no; - ulint zip_size; - - //buf_pool_mutex_exit(); - mutex_exit(&LRU_list_mutex); - rw_lock_x_unlock(&page_hash_latch); - - zip_size = buf_page_get_zip_size(bpage); - page_no = buf_page_get_page_no(bpage); - - mutex_exit(block_mutex); - - /* Note that the following call will acquire - an S-latch on the page */ - - btr_search_drop_page_hash_when_freed( - id, zip_size, page_no); - goto scan_again; - } - - if (bpage->oldest_modification != 0) { - - 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); - } 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)); - - if (prev_bpage_buf_fix) { - /* We temporarily buffer-fixed - prev_bpage, so that - buf_buddy_free() could not - relocate it, in case it was a - compressed-only block - descriptor. */ - - mutex_enter(block_mutex); - ut_ad(prev_bpage->buf_fix_count > 0); - prev_bpage->buf_fix_count--; - mutex_exit(block_mutex); - } - - goto next_page_no_mutex; - } -next_page: - mutex_exit(block_mutex); } -next_page_no_mutex: + ut_ad(mutex_own(block_mutex)); + +#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)); + } +#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(); + mutex_exit(&LRU_list_mutex); + rw_lock_x_unlock(&page_hash_latch); + + zip_size = buf_page_get_zip_size(bpage); + page_no = buf_page_get_page_no(bpage); + + mutex_exit(block_mutex); + + /* Note that the following call will acquire + an S-latch on the page */ + + btr_search_drop_page_hash_when_freed( + id, zip_size, page_no); + goto scan_again; + } + + if (bpage->oldest_modification != 0) { + + 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)); + } +next_page: bpage = prev_bpage; } @@ -539,6 +514,8 @@ buf_LRU_mark_space_was_deleted( ulint id) /*!< in: space id */ { buf_page_t* bpage; + buf_chunk_t* chunk; + ulint i, j; mutex_enter(&LRU_list_mutex); @@ -552,8 +529,32 @@ buf_LRU_mark_space_was_deleted( } mutex_exit(&LRU_list_mutex); + + rw_lock_s_lock(&btr_search_latch); + chunk = buf_pool->chunks; + for (i = buf_pool->n_chunks; i--; chunk++) { + buf_block_t* block = chunk->blocks; + for (j = chunk->size; j--; block++) { + if (buf_block_get_state(block) + != BUF_BLOCK_FILE_PAGE + || !block->is_hashed + || buf_page_get_space(&block->page) != id) { + continue; + } + + rw_lock_s_unlock(&btr_search_latch); + + rw_lock_x_lock(&block->lock); + btr_search_drop_page_hash_index(block); + rw_lock_x_unlock(&block->lock); + + rw_lock_s_lock(&btr_search_latch); + } + } + rw_lock_s_unlock(&btr_search_latch); } +#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG /********************************************************************//** Insert a compressed block into buf_pool->zip_clean in the LRU order. */ UNIV_INTERN @@ -587,6 +588,7 @@ buf_LRU_insert_zip_clean( UT_LIST_ADD_FIRST(zip_list, buf_pool->zip_clean, bpage); } } +#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */ /******************************************************************//** Try to free an uncompressed page of a compressed block from the unzip @@ -629,7 +631,7 @@ restart: UNIV_LIKELY(block != NULL) && UNIV_LIKELY(distance > 0); block = UT_LIST_GET_PREV(unzip_LRU, block), distance--) { - enum buf_lru_free_block_status freed; + ibool freed; mutex_enter(&block->mutex); if (!block->in_unzip_LRU_list || !block->page.in_LRU_list @@ -645,24 +647,9 @@ restart: freed = buf_LRU_free_block(&block->page, FALSE, have_LRU_mutex); mutex_exit(&block->mutex); - switch (freed) { - case BUF_LRU_FREED: + if (freed) { return(TRUE); - - case BUF_LRU_CANNOT_RELOCATE: - /* If we failed to relocate, try - regular LRU eviction. */ - return(FALSE); - - case BUF_LRU_NOT_FREED: - /* The block was buffer-fixed or I/O-fixed. - Keep looking. */ - continue; } - - /* inappropriate return value from - buf_LRU_free_block() */ - ut_error; } return(FALSE); @@ -695,10 +682,9 @@ restart: UNIV_LIKELY(bpage != NULL) && UNIV_LIKELY(distance > 0); bpage = UT_LIST_GET_PREV(LRU, bpage), distance--) { - enum buf_lru_free_block_status freed; - unsigned accessed; - mutex_t* block_mutex - = buf_page_get_mutex_enter(bpage); + ibool freed; + unsigned accessed; + mutex_t* block_mutex = buf_page_get_mutex_enter(bpage); if (!block_mutex) { goto restart; @@ -717,8 +703,7 @@ restart: freed = buf_LRU_free_block(bpage, TRUE, have_LRU_mutex); mutex_exit(block_mutex); - switch (freed) { - case BUF_LRU_FREED: + if (freed) { /* Keep track of pages that are evicted without ever being accessed. This gives us a measure of the effectiveness of readahead */ @@ -726,21 +711,7 @@ restart: ++buf_pool->stat.n_ra_pages_evicted; } return(TRUE); - - case BUF_LRU_NOT_FREED: - /* The block was dirty, buffer-fixed, or I/O-fixed. - Keep looking. */ - continue; - - case BUF_LRU_CANNOT_RELOCATE: - /* This should never occur, because we - want to discard the compressed page too. */ - break; } - - /* inappropriate return value from - buf_LRU_free_block() */ - ut_error; } return(FALSE); @@ -1457,17 +1428,16 @@ buf_LRU_make_block_old( Try to free a block. If bpage is a descriptor of a compressed-only page, the descriptor object will be freed as well. -NOTE: If this function returns BUF_LRU_FREED, it will temporarily +NOTE: If this function returns TRUE, it will temporarily release buf_pool_mutex. Furthermore, the page frame will no longer be accessible via bpage. The caller must hold buf_pool_mutex and buf_page_get_mutex(bpage) and release these two mutexes after the call. No other buf_page_get_mutex() may be held when calling this function. -@return BUF_LRU_FREED if freed, BUF_LRU_CANNOT_RELOCATE or -BUF_LRU_NOT_FREED otherwise. */ +@return TRUE if freed, FALSE otherwise. */ UNIV_INTERN -enum buf_lru_free_block_status +ibool buf_LRU_free_block( /*===============*/ buf_page_t* bpage, /*!< in: block to be freed */ @@ -1493,7 +1463,7 @@ buf_LRU_free_block( if (!bpage->in_LRU_list || !block_mutex || !buf_page_can_relocate(bpage)) { /* Do not free buffer-fixed or I/O-fixed blocks. */ - return(BUF_LRU_NOT_FREED); + return(FALSE); } if (bpage->space_was_being_deleted && bpage->oldest_modification != 0) { @@ -1509,7 +1479,7 @@ buf_LRU_free_block( /* Do not completely free dirty blocks. */ if (bpage->oldest_modification) { - return(BUF_LRU_NOT_FREED); + return(FALSE); } } else if (bpage->oldest_modification) { /* Do not completely free dirty blocks. */ @@ -1517,7 +1487,7 @@ buf_LRU_free_block( if (buf_page_get_state(bpage) != BUF_BLOCK_FILE_PAGE) { ut_ad(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_DIRTY); - return(BUF_LRU_NOT_FREED); + return(FALSE); } goto alloc; @@ -1526,14 +1496,8 @@ buf_LRU_free_block( If it cannot be allocated (without freeing a block from the LRU list), refuse to free bpage. */ alloc: - //buf_pool_mutex_exit_forbid(); - b = buf_buddy_alloc(sizeof *b, NULL, FALSE); - //buf_pool_mutex_exit_allow(); - - if (UNIV_UNLIKELY(!b)) { - return(BUF_LRU_CANNOT_RELOCATE); - } - + b = buf_page_alloc_descriptor(); + ut_a(b); //memcpy(b, bpage, sizeof *b); } @@ -1563,7 +1527,7 @@ not_freed: if (!have_LRU_mutex) mutex_exit(&LRU_list_mutex); rw_lock_x_unlock(&page_hash_latch); - return(BUF_LRU_NOT_FREED); + return(FALSE); } else if (zip || !bpage->zip.data) { if (bpage->oldest_modification) goto not_freed; @@ -1670,7 +1634,9 @@ not_freed: mutex_enter(&flush_list_mutex); if (b->state == BUF_BLOCK_ZIP_PAGE) { +#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG buf_LRU_insert_zip_clean(b); +#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */ } else { /* Relocate on buf_pool->flush_list. */ buf_flush_relocate_on_flush_list(bpage, b); @@ -1746,7 +1712,7 @@ not_freed: rw_lock_x_unlock(&page_hash_latch); } - return(BUF_LRU_FREED); + return(TRUE); } /******************************************************************//** @@ -1967,15 +1933,16 @@ buf_LRU_block_remove_hashed_page( ut_a(bpage->zip.data); ut_a(buf_page_get_zip_size(bpage)); +#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG UT_LIST_REMOVE(zip_list, buf_pool->zip_clean, bpage); +#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */ mutex_exit(&buf_pool_zip_mutex); //buf_pool_mutex_exit_forbid(); buf_buddy_free(bpage->zip.data, page_zip_get_size(&bpage->zip), TRUE); - buf_buddy_free(bpage, sizeof(*bpage), TRUE); //buf_pool_mutex_exit_allow(); - UNIV_MEM_UNDESC(bpage); + buf_page_free_descriptor(bpage); return(BUF_BLOCK_ZIP_FREE); case BUF_BLOCK_FILE_PAGE: @@ -2284,6 +2251,11 @@ buf_LRU_file_restore(void) " InnoDB: cannot open %s\n", LRU_DUMP_FILE); goto end; } + + ut_print_timestamp(stderr); + fprintf(stderr, " InnoDB: Restoring buffer pool pages from %s\n", + LRU_DUMP_FILE); + if (size == 0 || size_high > 0 || size % 8) { fprintf(stderr, " InnoDB: broken LRU dump file\n"); goto end; @@ -2385,7 +2357,7 @@ buf_LRU_file_restore(void) ut_print_timestamp(stderr); fprintf(stderr, - " InnoDB: reading pages based on the dumped LRU list was done." + " InnoDB: Completed reading buffer pool pages" " (requested: %lu, read: %lu)\n", req, reads); ret = TRUE; end: diff --git a/buf/buf0rea.c b/buf/buf0rea.c index 59de70d9a8a..966a9b5d7a6 100644 --- a/buf/buf0rea.c +++ b/buf/buf0rea.c @@ -38,6 +38,14 @@ Created 11/5/1995 Heikki Tuuri #include "srv0start.h" #include "srv0srv.h" +/** The size in blocks of the area where the random read-ahead algorithm counts +the accessed pages when deciding whether to read-ahead */ +#define BUF_READ_AHEAD_RANDOM_AREA BUF_READ_AHEAD_AREA + +/** There must be at least this many pages in buf_pool in the area to start +a random read-ahead */ +#define BUF_READ_AHEAD_RANDOM_THRESHOLD (5 + BUF_READ_AHEAD_RANDOM_AREA / 8) + /** The linear read-ahead area size */ #define BUF_READ_AHEAD_LINEAR_AREA BUF_READ_AHEAD_AREA @@ -201,12 +209,178 @@ not_to_recover: if (sync) { /* The i/o is already completed when we arrive from fil_read */ - buf_page_io_complete(bpage, trx); + buf_page_io_complete(bpage); } return(1); } +/********************************************************************//** +Applies a random read-ahead in buf_pool if there are at least a threshold +value of accessed pages from the random read-ahead area. Does not read any +page, not even the one at the position (space, offset), if the read-ahead +mechanism is not activated. NOTE 1: the calling thread may own latches on +pages: to avoid deadlocks this function must be written such that it cannot +end up waiting for these latches! NOTE 2: the calling thread must want +access to the page given: this rule is set to prevent unintended read-aheads +performed by ibuf routines, a situation which could result in a deadlock if +the OS does not support asynchronous i/o. +@return number of page read requests issued; NOTE that if we read ibuf +pages, it may happen that the page at the given page number does not +get read even if we return a positive value! */ +static +ulint +buf_read_ahead_random( +/*==================*/ + ulint space, /*!< in: space id */ + ulint zip_size,/*!< in: compressed page size in bytes, or 0 */ + ulint offset, /*!< in: page number of a page which the current thread + wants to access */ + trx_t* trx) +{ + ib_int64_t tablespace_version; + ulint recent_blocks = 0; + ulint count; + ulint ibuf_mode; + ulint low, high; + ulint err; + ulint i; + ulint buf_read_ahead_random_area; + + if (!srv_random_read_ahead) { + /* Disabled by user */ + return(0); + } + + if (srv_startup_is_before_trx_rollback_phase) { + /* No read-ahead to avoid thread deadlocks */ + return(0); + } + + if (ibuf_bitmap_page(zip_size, offset) + || trx_sys_hdr_page(space, offset)) { + + /* If it is an ibuf bitmap page or trx sys hdr, we do + no read-ahead, as that could break the ibuf page access + order */ + + return(0); + } + + /* Remember the tablespace version before we ask the tablespace size + below: if DISCARD + IMPORT changes the actual .ibd file meanwhile, we + do not try to read outside the bounds of the tablespace! */ + + tablespace_version = fil_space_get_version(space); + + buf_read_ahead_random_area = BUF_READ_AHEAD_RANDOM_AREA; + + low = (offset / buf_read_ahead_random_area) + * buf_read_ahead_random_area; + high = (offset / buf_read_ahead_random_area + 1) + * buf_read_ahead_random_area; + if (high > fil_space_get_size(space)) { + + high = fil_space_get_size(space); + } + + //buf_pool_mutex_enter(); + mutex_enter(&buf_pool_mutex); + + if (buf_pool->n_pend_reads + > buf_pool->curr_size / BUF_READ_AHEAD_PEND_LIMIT) { + //buf_pool_mutex_exit(); + mutex_exit(&buf_pool_mutex); + + return(0); + } + mutex_exit(&buf_pool_mutex); + + /* Count how many blocks in the area have been recently accessed, + that is, reside near the start of the LRU list. */ + + rw_lock_s_lock(&page_hash_latch); + for (i = low; i < high; i++) { + const buf_page_t* bpage = buf_page_hash_get(space, i); + + if (bpage + && buf_page_is_accessed(bpage) + && buf_page_peek_if_young(bpage)) { + + recent_blocks++; + + if (recent_blocks >= BUF_READ_AHEAD_RANDOM_THRESHOLD) { + + //buf_pool_mutex_exit(); + rw_lock_s_unlock(&page_hash_latch); + goto read_ahead; + } + } + } + + //buf_pool_mutex_exit(); + rw_lock_s_unlock(&page_hash_latch); + /* Do nothing */ + return(0); + +read_ahead: + /* Read all the suitable blocks within the area */ + + if (ibuf_inside()) { + ibuf_mode = BUF_READ_IBUF_PAGES_ONLY; + } else { + ibuf_mode = BUF_READ_ANY_PAGE; + } + + count = 0; + + for (i = low; i < high; i++) { + /* It is only sensible to do read-ahead in the non-sync aio + mode: hence FALSE as the first parameter */ + + if (!ibuf_bitmap_page(zip_size, i)) { + count += buf_read_page_low( + &err, FALSE, + ibuf_mode | OS_AIO_SIMULATED_WAKE_LATER, + space, zip_size, FALSE, + tablespace_version, i, trx); + if (err == DB_TABLESPACE_DELETED) { + ut_print_timestamp(stderr); + fprintf(stderr, + " InnoDB: Warning: in random" + " readahead trying to access\n" + "InnoDB: tablespace %lu page %lu,\n" + "InnoDB: but the tablespace does not" + " exist or is just being dropped.\n", + (ulong) space, (ulong) i); + } + } + } + + /* In simulated aio we wake the aio handler threads only after + queuing all aio requests, in native aio the following call does + nothing: */ + + os_aio_simulated_wake_handler_threads(); + +#ifdef UNIV_DEBUG + if (buf_debug_prints && (count > 0)) { + fprintf(stderr, + "Random read-ahead space %lu offset %lu pages %lu\n", + (ulong) space, (ulong) offset, + (ulong) count); + } +#endif /* UNIV_DEBUG */ + + /* Read ahead is considered one I/O operation for the purpose of + LRU policy decision. */ + buf_LRU_stat_inc_io(); + + buf_pool->stat.n_ra_pages_read_rnd += count; + return(count); +} + + /********************************************************************//** High-level function which reads a page asynchronously from a file to the buffer buf_pool if it is not already there. Sets the io_fix flag and sets @@ -226,6 +400,9 @@ buf_read_page( ulint count; ulint err; + count = buf_read_ahead_random(space, zip_size, offset, trx); + srv_buf_pool_reads += count; + tablespace_version = fil_space_get_version(space); /* We do the i/o in the synchronous aio mode to save thread diff --git a/dict/dict0dict.c b/dict/dict0dict.c index 18880a5c72c..a8a1d7a11e6 100644 --- a/dict/dict0dict.c +++ b/dict/dict0dict.c @@ -4524,6 +4524,8 @@ dict_store_statistics( break; } + btr_pcur_store_position(&pcur, &mtr); + if (rec_get_deleted_flag(rec, 0)) { /* don't count */ i--; @@ -4564,6 +4566,10 @@ dict_store_statistics( rests--; next_rec: + mtr_commit(&mtr); + mtr_start(&mtr); + btr_pcur_restore_position(BTR_MODIFY_LEAF, &pcur, &mtr); + btr_pcur_move_to_next_user_rec(&pcur, &mtr); } btr_pcur_close(&pcur); @@ -4654,6 +4660,7 @@ dict_update_statistics( do { if (table->is_corrupt) { ut_a(srv_pass_corrupt_table); + dict_table_stats_unlock(table, RW_X_LATCH); return; } diff --git a/dict/dict0load.c b/dict/dict0load.c index edd77e2530f..64d7fad3557 100644 --- a/dict/dict0load.c +++ b/dict/dict0load.c @@ -554,9 +554,10 @@ dict_load_columns( } /********************************************************************//** -Loads definitions for index fields. */ +Loads definitions for index fields. +@return DB_SUCCESS if ok, DB_CORRUPTION if failed */ static -void +ulint dict_load_fields( /*=============*/ dict_index_t* index, /*!< in: index whose fields to load */ @@ -575,6 +576,7 @@ dict_load_fields( byte* buf; ulint i; mtr_t mtr; + ulint error = DB_SUCCESS; ut_ad(mutex_own(&(dict_sys->mutex))); @@ -641,6 +643,26 @@ dict_load_fields( field = rec_get_nth_field_old(rec, 4, &len); + if (prefix_len >= DICT_MAX_INDEX_COL_LEN) { + fprintf(stderr, "InnoDB: Error: load index" + " '%s' failed.\n" + "InnoDB: index field '%s' has a prefix" + " length of %lu bytes,\n" + "InnoDB: which exceeds the" + " maximum limit of %lu bytes.\n" + "InnoDB: Please use server that" + " supports long index prefix\n" + "InnoDB: or turn on" + " innodb_force_recovery to load" + " the table\n", + index->name, mem_heap_strdupl( + heap, (char*) field, len), + (ulong) prefix_len, + (ulong) (DICT_MAX_INDEX_COL_LEN - 1)); + error = DB_CORRUPTION; + goto func_exit; + } + dict_mem_index_add_field(index, mem_heap_strdupl(heap, (char*) field, len), @@ -650,8 +672,10 @@ next_rec: btr_pcur_move_to_next_user_rec(&pcur, &mtr); } +func_exit: btr_pcur_close(&pcur); mtr_commit(&mtr); + return(error); } /********************************************************************//** @@ -802,7 +826,25 @@ dict_load_indexes( space, type, n_fields); index->id = id; - dict_load_fields(index, heap); + error = dict_load_fields(index, heap); + + if (error != DB_SUCCESS) { + fprintf(stderr, "InnoDB: Error: load index '%s'" + " for table '%s' failed\n", + index->name, table->name); + + /* If the force recovery flag is set, and + if the failed index is not the primary index, we + will continue and open other indexes */ + if (srv_force_recovery + && !(index->type & DICT_CLUSTERED)) { + error = DB_SUCCESS; + goto next_rec; + } else { + goto func_exit; + } + } + error = dict_index_add_to_cache(table, index, page_no, FALSE); /* The data dictionary tables should never contain @@ -1028,9 +1070,18 @@ err_exit: } else { table->fk_max_recusive_level = 0; } - } else if (!srv_force_recovery) { - dict_table_remove_from_cache(table); - table = NULL; + } else { + dict_index_t* index; + + /* Make sure that at least the clustered index was loaded. + Otherwise refuse to load the table */ + index = dict_table_get_first_index(table); + + if (!srv_force_recovery || !index + || !(index->type & DICT_CLUSTERED)) { + dict_table_remove_from_cache(table); + table = NULL; + } } #if 0 if (err != DB_SUCCESS && table != NULL) { diff --git a/dict/dict0mem.c b/dict/dict0mem.c index f2d219bfd4f..c3da053c2de 100644 --- a/dict/dict0mem.c +++ b/dict/dict0mem.c @@ -36,6 +36,9 @@ Created 1/8/1996 Heikki Tuuri #ifndef UNIV_HOTBACKUP # include "lock0lock.h" #endif /* !UNIV_HOTBACKUP */ +#ifdef UNIV_BLOB_DEBUG +# include "ut0rbt.h" +#endif /* UNIV_BLOB_DEBUG */ #define DICT_HEAP_SIZE 100 /*!< initial memory heap size when creating a table or index object */ @@ -318,6 +321,12 @@ dict_mem_index_free( { ut_ad(index); ut_ad(index->magic_n == DICT_INDEX_MAGIC_N); +#ifdef UNIV_BLOB_DEBUG + if (index->blobs) { + mutex_free(&index->blobs_mutex); + rbt_free(index->blobs); + } +#endif /* UNIV_BLOB_DEBUG */ mem_heap_free(index->heap); } diff --git a/fil/fil0fil.c b/fil/fil0fil.c index fe0f591e423..de3f9fe2db8 100644 --- a/fil/fil0fil.c +++ b/fil/fil0fil.c @@ -46,6 +46,8 @@ Created 10/25/1995 Heikki Tuuri #include "row0mysql.h" #include "row0row.h" #include "que0que.h" +#include "btr0btr.h" +#include "btr0sea.h" #ifndef UNIV_HOTBACKUP # include "buf0lru.h" # include "ibuf0ibuf.h" @@ -817,7 +819,7 @@ fil_node_close_file( ut_ad(node && system); ut_ad(mutex_own(&(system->mutex))); ut_a(node->open); - ut_a(node->n_pending == 0 || srv_lazy_drop_table); + ut_a(node->n_pending == 0 || node->space->is_being_deleted); ut_a(node->n_pending_flushes == 0); ut_a(node->modification_counter == node->flush_counter); @@ -830,7 +832,7 @@ fil_node_close_file( ut_a(system->n_open > 0); system->n_open--; - if (node->space->purpose == FIL_TABLESPACE && !trx_sys_sys_space(node->space->id)) { + if (node->n_pending == 0 && node->space->purpose == FIL_TABLESPACE && !trx_sys_sys_space(node->space->id)) { ut_a(UT_LIST_GET_LEN(system->LRU) > 0); /* The node is in the LRU list, remove it */ @@ -1029,7 +1031,7 @@ fil_node_free( ut_ad(node && system && space); ut_ad(mutex_own(&(system->mutex))); ut_a(node->magic_n == FIL_NODE_MAGIC_N); - ut_a(node->n_pending == 0 || srv_lazy_drop_table); + ut_a(node->n_pending == 0 || space->is_being_deleted); if (node->open) { /* We fool the assertion in fil_node_close_file() to think @@ -2579,7 +2581,7 @@ retry: os_thread_sleep(20000); - fil_flush(id); + fil_flush(id, TRUE); goto retry; @@ -2792,7 +2794,7 @@ error_exit2: goto error_exit; } - ret = os_file_flush(file); + ret = os_file_flush(file, TRUE); if (!ret) { fputs("InnoDB: Error: file flush of tablespace ", stderr); @@ -2977,7 +2979,7 @@ fil_reset_too_high_lsns( } } - success = os_file_flush(file); + success = os_file_flush(file, TRUE); if (!success) { goto func_exit; @@ -2999,7 +3001,7 @@ fil_reset_too_high_lsns( goto func_exit; } - success = os_file_flush(file); + success = os_file_flush(file, TRUE); func_exit: os_file_close(file); ut_free(buf2); @@ -3008,6 +3010,97 @@ func_exit: return(success); } +/********************************************************************//** +Checks if a page is corrupt. (for offline page) +*/ +static +ibool +fil_page_buf_page_is_corrupted_offline( +/*===================================*/ + const byte* page, /*!< in: a database page */ + ulint zip_size) /*!< in: size of compressed page; + 0 for uncompressed pages */ +{ + ulint checksum_field; + ulint old_checksum_field; + + if (!zip_size + && memcmp(page + FIL_PAGE_LSN + 4, + page + UNIV_PAGE_SIZE + - FIL_PAGE_END_LSN_OLD_CHKSUM + 4, 4)) { + return(TRUE); + } + + checksum_field = mach_read_from_4(page + + FIL_PAGE_SPACE_OR_CHKSUM); + + if (zip_size) { + return(checksum_field != BUF_NO_CHECKSUM_MAGIC + && checksum_field + != page_zip_calc_checksum(page, zip_size)); + } + + old_checksum_field = mach_read_from_4( + page + UNIV_PAGE_SIZE + - FIL_PAGE_END_LSN_OLD_CHKSUM); + + if (old_checksum_field != mach_read_from_4(page + + FIL_PAGE_LSN) + && old_checksum_field != BUF_NO_CHECKSUM_MAGIC + && old_checksum_field + != buf_calc_page_old_checksum(page)) { + return(TRUE); + } + + if (!srv_fast_checksum + && checksum_field != 0 + && checksum_field != BUF_NO_CHECKSUM_MAGIC + && checksum_field + != buf_calc_page_new_checksum(page)) { + return(TRUE); + } + + if (srv_fast_checksum + && checksum_field != 0 + && checksum_field != BUF_NO_CHECKSUM_MAGIC + && checksum_field + != buf_calc_page_new_checksum_32(page) + && checksum_field + != buf_calc_page_new_checksum(page)) { + return(TRUE); + } + + return(FALSE); +} + +/********************************************************************//** +*/ +static +void +fil_page_buf_page_store_checksum( +/*=============================*/ + byte* page, + ulint zip_size) +{ + if (!zip_size) { + mach_write_to_4(page + FIL_PAGE_SPACE_OR_CHKSUM, + srv_use_checksums + ? (!srv_fast_checksum + ? buf_calc_page_new_checksum(page) + : buf_calc_page_new_checksum_32(page)) + : BUF_NO_CHECKSUM_MAGIC); + mach_write_to_4(page + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM, + srv_use_checksums + ? buf_calc_page_old_checksum(page) + : BUF_NO_CHECKSUM_MAGIC); + } else { + mach_write_to_4(page + FIL_PAGE_SPACE_OR_CHKSUM, + srv_use_checksums + ? page_zip_calc_checksum(page, zip_size) + : BUF_NO_CHECKSUM_MAGIC); + } +} + /********************************************************************//** Tries to open a single-table tablespace and optionally checks the space id is right in it. If does not succeed, prints an error message to the .err log. This @@ -3123,6 +3216,7 @@ fil_open_single_table_tablespace( fil_system_t* system; fil_node_t* node = NULL; fil_space_t* space; + ulint zip_size; buf3 = ut_malloc(2 * UNIV_PAGE_SIZE); descr_page = ut_align(buf3, UNIV_PAGE_SIZE); @@ -3140,12 +3234,15 @@ fil_open_single_table_tablespace( /* store as first descr page */ memcpy(descr_page, page, UNIV_PAGE_SIZE); + zip_size = dict_table_flags_to_zip_size(flags); + ut_a(zip_size == dict_table_flags_to_zip_size(space_flags)); + /* get free limit (page number) of the table space */ /* these should be same to the definition in fsp0fsp.c */ #define FSP_HEADER_OFFSET FIL_PAGE_DATA #define FSP_FREE_LIMIT 12 free_limit = mach_read_from_4(FSP_HEADER_OFFSET + FSP_FREE_LIMIT + page); - free_limit_bytes = (ib_int64_t)free_limit * (ib_int64_t)UNIV_PAGE_SIZE; + free_limit_bytes = (ib_int64_t)free_limit * (ib_int64_t)(zip_size ? zip_size : UNIV_PAGE_SIZE); /* overwrite fsp header */ fsp_header_init_fields(page, id, flags); @@ -3154,16 +3251,9 @@ fil_open_single_table_tablespace( space_flags = flags; if (mach_read_ull(page + FIL_PAGE_FILE_FLUSH_LSN) > current_lsn) mach_write_ull(page + FIL_PAGE_FILE_FLUSH_LSN, current_lsn); - mach_write_to_4(page + FIL_PAGE_SPACE_OR_CHKSUM, - srv_use_checksums - ? (!srv_fast_checksum - ? buf_calc_page_new_checksum(page) - : buf_calc_page_new_checksum_32(page)) - : BUF_NO_CHECKSUM_MAGIC); - mach_write_to_4(page + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM, - srv_use_checksums - ? buf_calc_page_old_checksum(page) - : BUF_NO_CHECKSUM_MAGIC); + + fil_page_buf_page_store_checksum(page, zip_size); + success = os_file_write(filepath, file, page, 0, 0, UNIV_PAGE_SIZE); /* get file size */ @@ -3173,7 +3263,7 @@ fil_open_single_table_tablespace( if (size_bytes < free_limit_bytes) { free_limit_bytes = size_bytes; - if (size_bytes >= (ib_int64_t) (FSP_EXTENT_SIZE * UNIV_PAGE_SIZE)) { + if (size_bytes >= (ib_int64_t) (FSP_EXTENT_SIZE * (zip_size ? zip_size : UNIV_PAGE_SIZE))) { fprintf(stderr, "InnoDB: free limit of %s is larger than its real size.\n", filepath); file_is_corrupt = TRUE; } @@ -3237,75 +3327,41 @@ skip_info: size_bytes = ut_2pow_round(size_bytes, 1024 * 1024); } */ - if (!(flags & DICT_TF_ZSSIZE_MASK)) { + + if (zip_size) { + fprintf(stderr, "InnoDB: Warning: importing compressed table is still EXPERIMENTAL, currently.\n"); + } + + { mem_heap_t* heap = NULL; ulint offsets_[REC_OFFS_NORMAL_SIZE]; ulint* offsets = offsets_; ib_int64_t offset; - size = (ulint) (size_bytes / UNIV_PAGE_SIZE); + size = (ulint) (size_bytes / (zip_size ? zip_size : UNIV_PAGE_SIZE)); /* over write space id of all pages */ rec_offs_init(offsets_); fprintf(stderr, "InnoDB: Progress in %%:"); - for (offset = 0; offset < free_limit_bytes; offset += UNIV_PAGE_SIZE) { - ulint checksum_field; - ulint old_checksum_field; + for (offset = 0; offset < free_limit_bytes; + offset += zip_size ? zip_size : UNIV_PAGE_SIZE) { ibool page_is_corrupt; success = os_file_read(file, page, (ulint)(offset & 0xFFFFFFFFUL), - (ulint)(offset >> 32), UNIV_PAGE_SIZE); + (ulint)(offset >> 32), + zip_size ? zip_size : UNIV_PAGE_SIZE); page_is_corrupt = FALSE; /* check consistency */ - if (memcmp(page + FIL_PAGE_LSN + 4, - page + UNIV_PAGE_SIZE - - FIL_PAGE_END_LSN_OLD_CHKSUM + 4, 4)) { - + if (fil_page_buf_page_is_corrupted_offline(page, zip_size)) { page_is_corrupt = TRUE; } if (mach_read_from_4(page + FIL_PAGE_OFFSET) - != offset / UNIV_PAGE_SIZE) { - - page_is_corrupt = TRUE; - } - - checksum_field = mach_read_from_4(page - + FIL_PAGE_SPACE_OR_CHKSUM); - - old_checksum_field = mach_read_from_4( - page + UNIV_PAGE_SIZE - - FIL_PAGE_END_LSN_OLD_CHKSUM); - - if (old_checksum_field != mach_read_from_4(page - + FIL_PAGE_LSN) - && old_checksum_field != BUF_NO_CHECKSUM_MAGIC - && old_checksum_field - != buf_calc_page_old_checksum(page)) { - - page_is_corrupt = TRUE; - } - - if (!srv_fast_checksum - && checksum_field != 0 - && checksum_field != BUF_NO_CHECKSUM_MAGIC - && checksum_field - != buf_calc_page_new_checksum(page)) { - - page_is_corrupt = TRUE; - } - - if (srv_fast_checksum - && checksum_field != 0 - && checksum_field != BUF_NO_CHECKSUM_MAGIC - && checksum_field - != buf_calc_page_new_checksum_32(page) - && checksum_field - != buf_calc_page_new_checksum(page)) { + != offset / (zip_size ? zip_size : UNIV_PAGE_SIZE)) { page_is_corrupt = TRUE; } @@ -3316,7 +3372,8 @@ skip_info: /* it should be overwritten already */ ut_a(!page_is_corrupt); - } else if (!((offset / UNIV_PAGE_SIZE) % UNIV_PAGE_SIZE)) { + } else if (!((offset / (zip_size ? zip_size : UNIV_PAGE_SIZE)) + % (zip_size ? zip_size : UNIV_PAGE_SIZE))) { /* descr page (not header) */ if (page_is_corrupt) { file_is_corrupt = TRUE; @@ -3327,7 +3384,7 @@ skip_info: } /* store as descr page */ - memcpy(descr_page, page, UNIV_PAGE_SIZE); + memcpy(descr_page, page, (zip_size ? zip_size : UNIV_PAGE_SIZE)); } else if (descr_is_corrupt) { /* unknown state of the page */ @@ -3355,9 +3412,12 @@ skip_info: ulint bit_index; descr = descr_page + XDES_ARR_OFFSET - + XDES_SIZE * (ut_2pow_remainder((offset / UNIV_PAGE_SIZE), UNIV_PAGE_SIZE) / FSP_EXTENT_SIZE); + + XDES_SIZE * (ut_2pow_remainder( + (offset / (zip_size ? zip_size : UNIV_PAGE_SIZE)), + (zip_size ? zip_size : UNIV_PAGE_SIZE)) / FSP_EXTENT_SIZE); - index = XDES_FREE_BIT + XDES_BITS_PER_PAGE * ((offset / UNIV_PAGE_SIZE) % FSP_EXTENT_SIZE); + index = XDES_FREE_BIT + + XDES_BITS_PER_PAGE * ((offset / (zip_size ? zip_size : UNIV_PAGE_SIZE)) % FSP_EXTENT_SIZE); byte_index = index / 8; bit_index = index % 8; @@ -3375,7 +3435,7 @@ skip_info: } if (page_is_corrupt) { - fprintf(stderr, " [errp:%lld]", offset / UNIV_PAGE_SIZE); + fprintf(stderr, " [errp:%lld]", offset / (zip_size ? zip_size : UNIV_PAGE_SIZE)); /* cannot treat corrupt page */ goto skip_write; @@ -3385,7 +3445,13 @@ skip_info: mach_write_to_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, id); for (i = 0; i < n_index; i++) { - if (offset / UNIV_PAGE_SIZE == root_page[i]) { + if (offset / (zip_size ? zip_size : UNIV_PAGE_SIZE) == root_page[i]) { + if (fil_page_get_type(page) != FIL_PAGE_INDEX) { + file_is_corrupt = TRUE; + fprintf(stderr, " [etyp:%lld]", + offset / (zip_size ? zip_size : UNIV_PAGE_SIZE)); + goto skip_write; + } /* this is index root page */ mach_write_to_4(page + FIL_PAGE_DATA + PAGE_BTR_SEG_LEAF + FSEG_HDR_SPACE, id); @@ -3398,7 +3464,14 @@ skip_info: if (fil_page_get_type(page) == FIL_PAGE_INDEX) { dulint tmp = mach_read_from_8(page + (PAGE_HEADER + PAGE_INDEX_ID)); - if (mach_read_from_2(page + PAGE_HEADER + PAGE_LEVEL) == 0 + for (i = 0; i < n_index; i++) { + if (ut_dulint_cmp(old_id[i], tmp) == 0) { + mach_write_to_8(page + (PAGE_HEADER + PAGE_INDEX_ID), new_id[i]); + break; + } + } + + if (!zip_size && mach_read_from_2(page + PAGE_HEADER + PAGE_LEVEL) == 0 && ut_dulint_cmp(old_id[0], tmp) == 0) { /* leaf page of cluster index, reset trx_id of records */ rec_t* rec; @@ -3417,7 +3490,7 @@ skip_info: ULINT_UNDEFINED, &heap); n_fields = rec_offs_n_fields(offsets); if (!offset) { - offset = row_get_trx_id_offset(rec, index, offsets); + offset = row_get_trx_id_offset(index, offsets); } trx_write_trx_id(rec + offset, ut_dulint_create(0, 1)); @@ -3437,44 +3510,34 @@ skip_info: rec = page_rec_get_next(rec); n_recs--; } - } - - for (i = 0; i < n_index; i++) { - if (ut_dulint_cmp(old_id[i], tmp) == 0) { - mach_write_to_8(page + (PAGE_HEADER + PAGE_INDEX_ID), new_id[i]); - break; - } + } else if (mach_read_from_2(page + PAGE_HEADER + PAGE_LEVEL) == 0 + && ut_dulint_cmp(old_id[0], tmp) != 0) { + mach_write_to_8(page + (PAGE_HEADER + PAGE_MAX_TRX_ID), ut_dulint_create(0, 1)); } } if (mach_read_ull(page + FIL_PAGE_LSN) > current_lsn) { mach_write_ull(page + FIL_PAGE_LSN, current_lsn); - mach_write_ull(page + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM, - current_lsn); + if (!zip_size) { + mach_write_ull(page + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM, + current_lsn); + } } - mach_write_to_4(page + FIL_PAGE_SPACE_OR_CHKSUM, - srv_use_checksums - ? (!srv_fast_checksum - ? buf_calc_page_new_checksum(page) - : buf_calc_page_new_checksum_32(page)) - : BUF_NO_CHECKSUM_MAGIC); - mach_write_to_4(page + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM, - srv_use_checksums - ? buf_calc_page_old_checksum(page) - : BUF_NO_CHECKSUM_MAGIC); + fil_page_buf_page_store_checksum(page, zip_size); success = os_file_write(filepath, file, page, (ulint)(offset & 0xFFFFFFFFUL), - (ulint)(offset >> 32), UNIV_PAGE_SIZE); + (ulint)(offset >> 32), + zip_size ? zip_size : UNIV_PAGE_SIZE); } skip_write: if (free_limit_bytes - && ((ib_int64_t)((offset + UNIV_PAGE_SIZE) * 100) / free_limit_bytes) + && ((ib_int64_t)((offset + (zip_size ? zip_size : UNIV_PAGE_SIZE)) * 100) / free_limit_bytes) != ((offset * 100) / free_limit_bytes)) { fprintf(stderr, " %lu", - (ulong)((ib_int64_t)((offset + UNIV_PAGE_SIZE) * 100) / free_limit_bytes)); + (ulong)((ib_int64_t)((offset + (zip_size ? zip_size : UNIV_PAGE_SIZE)) * 100) / free_limit_bytes)); } } @@ -3530,13 +3593,6 @@ skip_write: if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); } - } else { - /* zip page? */ - size = (ulint) - (size_bytes - / dict_table_flags_to_zip_size(flags)); - fprintf(stderr, "InnoDB: import: table %s seems to be in newer format." - " It may not be able to treated for now.\n", name); } /* .exp file should be removed */ success = os_file_delete(info_file_path); @@ -3618,6 +3674,271 @@ func_exit: os_file_close(file); mem_free(filepath); + if (srv_expand_import && dict_table_flags_to_zip_size(flags)) { + ulint page_no; + ulint zip_size; + ulint height; + ulint root_height = 0; + rec_t* node_ptr; + dict_table_t* table; + dict_index_t* index; + buf_block_t* block; + page_t* page; + page_zip_des_t* page_zip; + mtr_t mtr; + + mem_heap_t* heap = NULL; + ulint offsets_[REC_OFFS_NORMAL_SIZE]; + ulint* offsets = offsets_; + + rec_offs_init(offsets_); + + zip_size = dict_table_flags_to_zip_size(flags); + + table = dict_table_get_low(name); + index = dict_table_get_first_index(table); + page_no = dict_index_get_page(index); + ut_a(page_no == 3); + + fprintf(stderr, "InnoDB: It is compressed .ibd file. need to convert additionaly on buffer pool.\n"); + + /* down to leaf */ + mtr_start(&mtr); + mtr_set_log_mode(&mtr, MTR_LOG_NONE); + + height = ULINT_UNDEFINED; + + for (;;) { + block = buf_page_get(space_id, zip_size, page_no, + RW_NO_LATCH, &mtr); + page = buf_block_get_frame(block); + + block->check_index_page_at_flush = TRUE; + + if (height == ULINT_UNDEFINED) { + height = btr_page_get_level(page, &mtr); + root_height = height; + } + + if (height == 0) { + break; + } + + node_ptr = page_rec_get_next(page_get_infimum_rec(page)); + + height--; + + offsets = rec_get_offsets(node_ptr, index, offsets, ULINT_UNDEFINED, &heap); + page_no = btr_node_ptr_get_child_page_no(node_ptr, offsets); + } + + mtr_commit(&mtr); + + fprintf(stderr, "InnoDB: pages needs split are ..."); + + /* scan reaf pages */ + while (page_no != FIL_NULL) { + rec_t* rec; + rec_t* supremum; + ulint n_recs; + + mtr_start(&mtr); + + block = buf_page_get(space_id, zip_size, page_no, + RW_X_LATCH, &mtr); + page = buf_block_get_frame(block); + page_zip = buf_block_get_page_zip(block); + + if (!page_zip) { + /*something wrong*/ + fprintf(stderr, "InnoDB: Something wrong with reading page %lu.\n", page_no); +convert_err_exit: + mtr_commit(&mtr); + mutex_enter(&fil_system->mutex); + fil_space_free(space_id, FALSE); + mutex_exit(&fil_system->mutex); + success = FALSE; + goto convert_exit; + } + + supremum = page_get_supremum_rec(page); + rec = page_rec_get_next(page_get_infimum_rec(page)); + n_recs = page_get_n_recs(page); + + /* illegal operation as InnoDB online system. so not logged */ + while (rec && rec != supremum && n_recs > 0) { + ulint n_fields; + ulint i; + ulint offset = index->trx_id_offset; + + offsets = rec_get_offsets(rec, index, offsets, + ULINT_UNDEFINED, &heap); + n_fields = rec_offs_n_fields(offsets); + if (!offset) { + offset = row_get_trx_id_offset(index, offsets); + } + trx_write_trx_id(rec + offset, ut_dulint_create(0, 1)); + + for (i = 0; i < n_fields; i++) { + if (rec_offs_nth_extern(offsets, i)) { + ulint local_len; + byte* data; + + data = rec_get_nth_field(rec, offsets, i, &local_len); + + local_len -= BTR_EXTERN_FIELD_REF_SIZE; + + mach_write_to_4(data + local_len + BTR_EXTERN_SPACE_ID, id); + } + } + + rec = page_rec_get_next(rec); + n_recs--; + } + + /* dummy logged update for along with modified page path */ + if (ut_dulint_cmp(index->id, btr_page_get_index_id(page)) != 0) { + /* this should be adjusted already */ + fprintf(stderr, "InnoDB: The page %lu seems to be converted wrong.\n", page_no); + goto convert_err_exit; + } + btr_page_set_index_id(page, page_zip, index->id, &mtr); + + /* confirm whether fits to the page size or not */ + if (!page_zip_compress(page_zip, page, index, &mtr) + && !btr_page_reorganize(block, index, &mtr)) { + buf_block_t* new_block; + page_t* new_page; + page_zip_des_t* new_page_zip; + rec_t* split_rec; + ulint n_uniq; + + /* split page is needed */ + fprintf(stderr, " %lu", page_no); + + mtr_x_lock(dict_index_get_lock(index), &mtr); + + n_uniq = dict_index_get_n_unique_in_tree(index); + + if(page_get_n_recs(page) < 2) { + /* no way to make smaller */ + fprintf(stderr, "InnoDB: The page %lu cannot be store to the page size.\n", page_no); + goto convert_err_exit; + } + + if (UNIV_UNLIKELY(page_no == dict_index_get_page(index))) { + ulint new_page_no; + dtuple_t* node_ptr; + ulint level; + rec_t* node_ptr_rec; + page_cur_t page_cursor; + + /* it is root page, need to raise before split */ + + level = btr_page_get_level(page, &mtr); + + new_block = btr_page_alloc(index, 0, FSP_NO_DIR, level, &mtr); + new_page = buf_block_get_frame(new_block); + new_page_zip = buf_block_get_page_zip(new_block); + btr_page_create(new_block, new_page_zip, index, level, &mtr); + + btr_page_set_next(new_page, new_page_zip, FIL_NULL, &mtr); + btr_page_set_prev(new_page, new_page_zip, FIL_NULL, &mtr); + + page_zip_copy_recs(new_page_zip, new_page, + page_zip, page, index, &mtr); + btr_search_move_or_delete_hash_entries(new_block, block, index); + + rec = page_rec_get_next(page_get_infimum_rec(new_page)); + new_page_no = buf_block_get_page_no(new_block); + + node_ptr = dict_index_build_node_ptr(index, rec, new_page_no, heap, + level); + dtuple_set_info_bits(node_ptr, + dtuple_get_info_bits(node_ptr) + | REC_INFO_MIN_REC_FLAG); + btr_page_empty(block, page_zip, index, level + 1, &mtr); + + btr_page_set_next(page, page_zip, FIL_NULL, &mtr); + btr_page_set_prev(page, page_zip, FIL_NULL, &mtr); + + page_cur_set_before_first(block, &page_cursor); + + node_ptr_rec = page_cur_tuple_insert(&page_cursor, node_ptr, + index, 0, &mtr); + ut_a(node_ptr_rec); + + if (!btr_page_reorganize(block, index, &mtr)) { + fprintf(stderr, "InnoDB: failed to store the page %lu.\n", page_no); + goto convert_err_exit; + } + + /* move to the raised page */ + page_no = new_page_no; + block = new_block; + page = new_page; + page_zip = new_page_zip; + + fprintf(stderr, "(raise_to:%lu)", page_no); + } + + split_rec = page_get_middle_rec(page); + + new_block = btr_page_alloc(index, page_no + 1, FSP_UP, + btr_page_get_level(page, &mtr), &mtr); + new_page = buf_block_get_frame(new_block); + new_page_zip = buf_block_get_page_zip(new_block); + btr_page_create(new_block, new_page_zip, index, + btr_page_get_level(page, &mtr), &mtr); + + offsets = rec_get_offsets(split_rec, index, offsets, n_uniq, &heap); + + btr_attach_half_pages(index, block, + split_rec, new_block, FSP_UP, &mtr); + + page_zip_copy_recs(new_page_zip, new_page, + page_zip, page, index, &mtr); + page_delete_rec_list_start(split_rec - page + new_page, + new_block, index, &mtr); + btr_search_move_or_delete_hash_entries(new_block, block, index); + page_delete_rec_list_end(split_rec, block, index, + ULINT_UNDEFINED, ULINT_UNDEFINED, &mtr); + + fprintf(stderr, "(new:%lu)", buf_block_get_page_no(new_block)); + + /* Are they needed? */ + if (!btr_page_reorganize(block, index, &mtr)) { + fprintf(stderr, "InnoDB: failed to store the page %lu.\n", page_no); + goto convert_err_exit; + } + if (!btr_page_reorganize(new_block, index, &mtr)) { + fprintf(stderr, "InnoDB: failed to store the page %lu.\n", buf_block_get_page_no(new_block)); + goto convert_err_exit; + } + } + + page_no = btr_page_get_next(page, &mtr); + + mtr_commit(&mtr); + + if (heap) { + mem_heap_empty(heap); + } + } + + fprintf(stderr, "...done.\nInnoDB: waiting the flush batch of the additional conversion.\n"); + + /* should wait for the not-logged changes are all flushed */ + buf_flush_batch(BUF_FLUSH_LIST, ULINT_MAX, mtr.end_lsn + 1); + buf_flush_wait_batch_end(BUF_FLUSH_LIST); + + fprintf(stderr, "InnoDB: done.\n"); +convert_exit: + if (UNIV_LIKELY_NULL(heap)) { + mem_heap_free(heap); + } + } + return(success); } #endif /* !UNIV_HOTBACKUP */ @@ -4466,7 +4787,7 @@ fil_extend_space_to_desired_size( mutex_exit(&fil_system->mutex); mutex_exit(&fil_system->file_extend_mutex); - fil_flush(space_id); + fil_flush(space_id, TRUE); return(success); } @@ -4835,7 +5156,7 @@ _fil_io( && ((buf_page_t*)message)->space_was_being_deleted) { if (mode == OS_AIO_NORMAL) { - buf_page_io_complete(message, trx); + buf_page_io_complete(message); return(DB_SUCCESS); /*fake*/ } if (type == OS_FILE_READ) { @@ -4946,14 +5267,14 @@ _fil_io( ut_a(byte_offset % OS_FILE_LOG_BLOCK_SIZE == 0); ut_a((len % OS_FILE_LOG_BLOCK_SIZE) == 0); - if (srv_pass_corrupt_table && space->is_corrupt) { + if (srv_pass_corrupt_table == 1 && space->is_corrupt) { /* should ignore i/o for the crashed space */ mutex_enter(&fil_system->mutex); fil_node_complete_io(node, fil_system, type); mutex_exit(&fil_system->mutex); if (mode == OS_AIO_NORMAL) { ut_a(space->purpose == FIL_TABLESPACE); - buf_page_io_complete(message, trx); + buf_page_io_complete(message); } if (type == OS_FILE_READ) { return(DB_TABLESPACE_DELETED); @@ -4961,7 +5282,19 @@ _fil_io( return(DB_SUCCESS); } } else { - ut_a(!space->is_corrupt); + if (srv_pass_corrupt_table > 1 && space->is_corrupt) { + /* should ignore write i/o for the crashed space */ + if (type == OS_FILE_WRITE) { + mutex_enter(&fil_system->mutex); + fil_node_complete_io(node, fil_system, type); + mutex_exit(&fil_system->mutex); + if (mode == OS_AIO_NORMAL) { + ut_a(space->purpose == FIL_TABLESPACE); + buf_page_io_complete(message); + } + return(DB_SUCCESS); + } + } #ifdef UNIV_HOTBACKUP /* In ibbackup do normal i/o, not aio */ if (type == OS_FILE_READ) { @@ -5122,7 +5455,7 @@ fil_aio_wait( || buf_page_get_state(message) != BUF_BLOCK_FILE_PAGE); srv_set_io_thread_op_info(segment, "complete io for buf page"); - buf_page_io_complete(message, NULL); + buf_page_io_complete(message); return; } @@ -5146,7 +5479,7 @@ fil_aio_wait( if (fil_node->space->purpose == FIL_TABLESPACE) { srv_set_io_thread_op_info(segment, "complete io for buf page"); - buf_page_io_complete(message, NULL); + buf_page_io_complete(message); } else { srv_set_io_thread_op_info(segment, "complete io for log"); log_io_complete(message); @@ -5161,8 +5494,9 @@ UNIV_INTERN void fil_flush( /*======*/ - ulint space_id) /*!< in: file space id (this can be a group of + ulint space_id, /*!< in: file space id (this can be a group of log files or a tablespace of the database) */ + ibool metadata) { fil_space_t* space; fil_node_t* node; @@ -5233,7 +5567,7 @@ retry: /* fprintf(stderr, "Flushing to file %s\n", node->name); */ - os_file_flush(file); + os_file_flush(file, metadata); mutex_enter(&fil_system->mutex); @@ -5316,7 +5650,7 @@ fil_flush_file_spaces( a non-existing space id. */ for (i = 0; i < n_space_ids; i++) { - fil_flush(space_ids[i]); + fil_flush(space_ids[i], TRUE); } mem_free(space_ids); diff --git a/ha/hash0hash.c b/ha/hash0hash.c index 0f4fc55d895..30c304dafcd 100644 --- a/ha/hash0hash.c +++ b/ha/hash0hash.c @@ -127,70 +127,6 @@ hash_create( return(table); } -/*************************************************************//** -*/ -UNIV_INTERN -ulint -hash_create_needed( -/*===============*/ - ulint n) -{ - ulint prime; - ulint offset; - - prime = ut_find_prime(n); - - offset = (sizeof(hash_table_t) + 7) / 8; - offset *= 8; - - return(offset + sizeof(hash_cell_t) * prime); -} - -UNIV_INTERN -void -hash_create_init( -/*=============*/ - hash_table_t* table, - ulint n) -{ - ulint prime; - ulint offset; - - prime = ut_find_prime(n); - - offset = (sizeof(hash_table_t) + 7) / 8; - offset *= 8; - - table->array = (hash_cell_t*)(((byte*)table) + offset); - table->n_cells = prime; -# if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG - table->adaptive = FALSE; -# endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ - table->n_mutexes = 0; - table->mutexes = NULL; - table->heaps = NULL; - table->heap = NULL; - ut_d(table->magic_n = HASH_TABLE_MAGIC_N); - - /* Initialize the cell array */ - hash_table_clear(table); -} - -UNIV_INTERN -void -hash_create_reuse( -/*==============*/ - hash_table_t* table) -{ - ulint offset; - - offset = (sizeof(hash_table_t) + 7) / 8; - offset *= 8; - - table->array = (hash_cell_t*)(((byte*)table) + offset); - ut_ad(table->magic_n == HASH_TABLE_MAGIC_N); -} - /*************************************************************//** Frees a hash table. */ UNIV_INTERN diff --git a/handler/ha_innodb.cc b/handler/ha_innodb.cc index 5722033f4b4..def6e58c8a6 100644 --- a/handler/ha_innodb.cc +++ b/handler/ha_innodb.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2000, 2010, MySQL AB & Innobase Oy. All Rights Reserved. +Copyright (c) 2000, 2011, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, 2009 Google Inc. Copyright (c) 2009, Percona Inc. @@ -199,11 +199,14 @@ static my_bool innobase_create_status_file = FALSE; static my_bool innobase_stats_on_metadata = TRUE; static my_bool innobase_use_sys_stats_table = FALSE; static my_bool innobase_buffer_pool_shm_checksum = TRUE; +static uint innobase_buffer_pool_shm_key = 0; static char* internal_innobase_data_file_path = NULL; static char* innodb_version_str = (char*) INNODB_VERSION_STR; +static my_bool innobase_blocking_lru_restore = FALSE; + /** Possible values for system variable "innodb_stats_method". The values are defined the same as its corresponding MyISAM system variable "myisam_stats_method"(see "myisam_stats_method_names"), for better usability */ @@ -368,6 +371,12 @@ static MYSQL_THDVAR_ULONG(flush_log_at_trx_commit_session, PLUGIN_VAR_RQCMDARG, "The value 3 regards innodb_flush_log_at_trx_commit (default).", NULL, NULL, 3, 0, 3, 0); +static MYSQL_THDVAR_BOOL(fake_changes, PLUGIN_VAR_OPCMDARG, + "In the transaction after enabled, UPDATE, INSERT and DELETE only move the cursor to the records " + "and do nothing other operations (no changes, no ibuf, no undo, no transaction log) in the transaction. " + "This is to cause replication prefetch IO. ATTENTION: the transaction started after enabled is affected.", + NULL, NULL, FALSE); + static handler *innobase_create_handler(handlerton *hton, TABLE_SHARE *table, @@ -537,6 +546,8 @@ static SHOW_VAR innodb_status_variables[]= { (char*) &export_vars.innodb_buffer_pool_pages_misc, SHOW_LONG}, {"buffer_pool_pages_total", (char*) &export_vars.innodb_buffer_pool_pages_total, SHOW_LONG}, + {"buffer_pool_read_ahead_rnd", + (char*) &export_vars.innodb_buffer_pool_read_ahead_rnd, SHOW_LONG}, {"buffer_pool_read_ahead", (char*) &export_vars.innodb_buffer_pool_read_ahead, SHOW_LONG}, {"buffer_pool_read_ahead_evicted", @@ -759,6 +770,19 @@ thd_flush_log_at_trx_commit_session( return(THDVAR((THD*) thd, flush_log_at_trx_commit_session)); } +/******************************************************************//** +Returns true if expand_fast_index_creation is enabled for the current +session. +@return the value of the server's expand_fast_index_creation variable */ +extern "C" UNIV_INTERN +ibool +thd_expand_fast_index_creation( +/*================================*/ + void* thd) +{ + return((ibool) (((THD*) thd)->variables.expand_fast_index_creation)); +} + /********************************************************************//** Obtain the InnoDB transaction of a MySQL thread. @return reference to transaction pointer */ @@ -1399,6 +1423,8 @@ innobase_trx_init( trx->check_unique_secondary = !thd_test_options( thd, OPTION_RELAXED_UNIQUE_CHECKS); + trx->fake_changes = THDVAR(thd, fake_changes); + #ifdef EXTENDED_SLOWLOG if (thd_log_slow_verbosity(thd) & SLOG_V_INNODB) { trx->take_stats = TRUE; @@ -2461,6 +2487,12 @@ innobase_change_buffering_inited_ok: srv_buf_pool_size = (ulint) innobase_buffer_pool_size; + if (innobase_buffer_pool_shm_key) { + fprintf(stderr, + "InnoDB: Warning: innodb_buffer_pool_shm_key is deprecated function.\n" + "InnoDB: innodb_buffer_pool_shm_key was ignored.\n"); + } + srv_mem_pool_size = (ulint) innobase_additional_mem_pool_size; srv_n_file_io_threads = (ulint) innobase_file_io_threads; @@ -2477,7 +2509,8 @@ innobase_change_buffering_inited_ok: srv_use_doublewrite_buf = (ibool) innobase_use_doublewrite; srv_use_checksums = (ibool) innobase_use_checksums; srv_fast_checksum = (ibool) innobase_fast_checksum; - srv_buffer_pool_shm_checksum = (ibool) innobase_buffer_pool_shm_checksum; + + srv_blocking_lru_restore = (ibool) innobase_blocking_lru_restore; #ifdef HAVE_LARGE_PAGES if ((os_use_large_pages = (ibool) my_use_large_pages)) @@ -2515,6 +2548,10 @@ innobase_change_buffering_inited_ok: innobase_commit_concurrency_init_default(); +#ifndef EXTENDED_FOR_KILLIDLE + srv_kill_idle_transaction = 0; +#endif + /* Since we in this module access directly the fields of a trx struct, and due to different headers and flags it might happen that mutex_t has a different size in this module and in InnoDB @@ -2810,6 +2847,11 @@ innobase_commit( trx_search_latch_release_if_reserved(trx); } + if (trx->fake_changes && (all || (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))) { + innobase_rollback(hton, thd, all); /* rollback implicitly */ + thd->main_da.reset_diagnostics_area(); /* because debug assertion code complains, if something left */ + DBUG_RETURN(HA_ERR_WRONG_COMMAND); + } /* The flag trx->active_trans is set to 1 in 1. ::external_lock(), @@ -3800,7 +3842,7 @@ ha_innobase::open( DBUG_RETURN(1); } - if (share->ib_table && share->ib_table->is_corrupt) { + if (srv_pass_corrupt_table <= 1 && share->ib_table && share->ib_table->is_corrupt) { free_share(share); DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE); @@ -3833,18 +3875,18 @@ retry: /* Get pointer to a table object in InnoDB dictionary cache */ ib_table = dict_table_get(norm_name, TRUE); - if (ib_table && ib_table->is_corrupt) { + if (srv_pass_corrupt_table <= 1 && ib_table && ib_table->is_corrupt) { free_share(share); my_free(upd_buff, MYF(0)); DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE); } - if (share->ib_table) { - ut_a(share->ib_table == ib_table); - } else { - share->ib_table = ib_table; - } + share->ib_table = ib_table; + + + + if (NULL == ib_table) { if (is_part && retries < 10) { @@ -4141,25 +4183,6 @@ field_in_record_is_null( return(0); } -/**************************************************************//** -Sets a field in a record to SQL NULL. Uses the record format -information in table to track the null bit in record. */ -static inline -void -set_field_in_record_to_null( -/*========================*/ - TABLE* table, /*!< in: MySQL table object */ - Field* field, /*!< in: MySQL field object */ - char* record) /*!< in: a row in MySQL format */ -{ - int null_offset; - - null_offset = (uint) ((char*) field->null_ptr - - (char*) table->record[0]); - - record[null_offset] = record[null_offset] | field->null_bit; -} - /*************************************************************//** InnoDB uses this function to compare two data fields for which the data type is such that we must use MySQL code to compare them. NOTE that the prototype @@ -5804,7 +5827,7 @@ ha_innobase::index_read( ha_statistic_increment(&SSV::ha_read_key_count); - if (share->ib_table->is_corrupt) { + if (srv_pass_corrupt_table <= 1 && share->ib_table->is_corrupt) { DBUG_RETURN(HA_ERR_CRASHED); } @@ -5873,7 +5896,7 @@ ha_innobase::index_read( ret = DB_UNSUPPORTED; } - if (share->ib_table->is_corrupt) { + if (srv_pass_corrupt_table <= 1 && share->ib_table->is_corrupt) { DBUG_RETURN(HA_ERR_CRASHED); } @@ -5992,7 +6015,7 @@ ha_innobase::change_active_index( { DBUG_ENTER("change_active_index"); - if (share->ib_table->is_corrupt) { + if (srv_pass_corrupt_table <= 1 && share->ib_table->is_corrupt) { DBUG_RETURN(HA_ERR_CRASHED); } @@ -6086,7 +6109,7 @@ ha_innobase::general_fetch( DBUG_ENTER("general_fetch"); - if (share->ib_table->is_corrupt) { + if (srv_pass_corrupt_table <= 1 && share->ib_table->is_corrupt) { DBUG_RETURN(HA_ERR_CRASHED); } @@ -6099,7 +6122,7 @@ ha_innobase::general_fetch( innodb_srv_conc_exit_innodb(prebuilt->trx); - if (share->ib_table->is_corrupt) { + if (srv_pass_corrupt_table <= 1 && share->ib_table->is_corrupt) { DBUG_RETURN(HA_ERR_CRASHED); } @@ -6440,10 +6463,6 @@ create_table_def( DBUG_PRINT("enter", ("table_name: %s", table_name)); ut_a(trx->mysql_thd != NULL); - if (IS_MAGIC_TABLE_AND_USER_DENIED_ACCESS(table_name, - (THD*) trx->mysql_thd)) { - DBUG_RETURN(HA_ERR_GENERIC); - } /* MySQL does the name length check. But we do additional check on the name length here */ @@ -6563,6 +6582,8 @@ err_col: col_len); } + srv_lower_case_table_names = lower_case_table_names; + error = row_create_table_for_mysql(table, trx); if (error == DB_DUPLICATE_KEY) { @@ -6979,42 +7000,17 @@ ha_innobase::create( DBUG_RETURN(HA_ERR_TO_BIG_ROW); } - /* Get the transaction associated with the current thd, or create one - if not yet created */ - - parent_trx = check_trx_exists(thd); - - /* In case MySQL calls this in the middle of a SELECT query, release - possible adaptive hash latch to avoid deadlocks of threads */ - - trx_search_latch_release_if_reserved(parent_trx); - - trx = innobase_trx_allocate(thd); - - if (lower_case_table_names) { - srv_lower_case_table_names = TRUE; - } else { - srv_lower_case_table_names = FALSE; - } - strcpy(name2, name); normalize_table_name(norm_name, name2); - /* Latch the InnoDB data dictionary exclusively so that no deadlocks - or lock waits can happen in it during a table create operation. - Drop table etc. do this latching in row0mysql.c. */ - - row_mysql_lock_data_dictionary(trx); - /* Create the table definition in InnoDB */ flags = 0; /* Validate create options if innodb_strict_mode is set. */ if (!create_options_are_valid(thd, form, create_info)) { - error = ER_ILLEGAL_HA_CREATE_OPTION; - goto cleanup; + DBUG_RETURN(ER_ILLEGAL_HA_CREATE_OPTION); } if (create_info->key_block_size) { @@ -7156,16 +7152,43 @@ ha_innobase::create( /* Check for name conflicts (with reserved name) for any user indices to be created. */ - if (innobase_index_name_is_reserved(trx, form->key_info, + if (innobase_index_name_is_reserved(thd, form->key_info, form->s->keys)) { - error = -1; - goto cleanup; + DBUG_RETURN(-1); + } + + if (IS_MAGIC_TABLE_AND_USER_DENIED_ACCESS(norm_name, thd)) { + DBUG_RETURN(HA_ERR_GENERIC); } if (create_info->options & HA_LEX_CREATE_TMP_TABLE) { flags |= DICT_TF2_TEMPORARY << DICT_TF2_SHIFT; } + /* Get the transaction associated with the current thd, or create one + if not yet created */ + + parent_trx = check_trx_exists(thd); + + /* In case MySQL calls this in the middle of a SELECT query, release + possible adaptive hash latch to avoid deadlocks of threads */ + + trx_search_latch_release_if_reserved(parent_trx); + + trx = innobase_trx_allocate(thd); + + if (trx->fake_changes) { + innobase_commit_low(trx); + trx_free_for_mysql(trx); + DBUG_RETURN(HA_ERR_WRONG_COMMAND); + } + + /* Latch the InnoDB data dictionary exclusively so that no deadlocks + or lock waits can happen in it during a table create operation. + Drop table etc. do this latching in row0mysql.c. */ + + row_mysql_lock_data_dictionary(trx); + error = create_table_def(trx, form, norm_name, create_info->options & HA_LEX_CREATE_TMP_TABLE ? name2 : NULL, flags); @@ -7365,6 +7388,10 @@ ha_innobase::delete_all_rows(void) DBUG_RETURN(HA_ERR_CRASHED); } + if (prebuilt->trx->fake_changes) { + goto fallback; + } + /* Truncate the table in InnoDB */ error = row_truncate_table_for_mysql(prebuilt->table, prebuilt->trx); @@ -7425,10 +7452,10 @@ ha_innobase::delete_table( trx = innobase_trx_allocate(thd); - if (lower_case_table_names) { - srv_lower_case_table_names = TRUE; - } else { - srv_lower_case_table_names = FALSE; + if (trx->fake_changes) { + innobase_commit_low(trx); + trx_free_for_mysql(trx); + DBUG_RETURN(HA_ERR_WRONG_COMMAND); } name_len = strlen(name); @@ -7437,6 +7464,8 @@ ha_innobase::delete_table( /* Drop the table in InnoDB */ + srv_lower_case_table_names = lower_case_table_names; + error = row_drop_table_for_mysql(norm_name, trx, thd_sql_command(thd) == SQLCOM_DROP_DB); @@ -7517,6 +7546,12 @@ innobase_drop_database( trx->mysql_thd = NULL; #else trx = innobase_trx_allocate(thd); + if (trx->fake_changes) { + my_free(namebuf, MYF(0)); + innobase_commit_low(trx); + trx_free_for_mysql(trx); + return; /* ignore */ + } #endif row_drop_database_for_mysql(namebuf, trx); my_free(namebuf, MYF(0)); @@ -7552,12 +7587,6 @@ innobase_rename_table( char* norm_to; char* norm_from; - if (lower_case_table_names) { - srv_lower_case_table_names = TRUE; - } else { - srv_lower_case_table_names = FALSE; - } - // Magic number 64 arbitrary norm_to = (char*) my_malloc(strlen(to) + 64, MYF(0)); norm_from = (char*) my_malloc(strlen(from) + 64, MYF(0)); @@ -7572,6 +7601,8 @@ innobase_rename_table( row_mysql_lock_data_dictionary(trx); } + srv_lower_case_table_names = lower_case_table_names; + error = row_rename_table_for_mysql( norm_from, norm_to, trx, lock_and_commit); @@ -7628,6 +7659,11 @@ ha_innobase::rename_table( trx_search_latch_release_if_reserved(parent_trx); trx = innobase_trx_allocate(thd); + if (trx->fake_changes) { + innobase_commit_low(trx); + trx_free_for_mysql(trx); + DBUG_RETURN(HA_ERR_WRONG_COMMAND); + } error = innobase_rename_table(trx, from, to, TRUE); @@ -8131,6 +8167,8 @@ ha_innobase::info_low( if (flag & HA_STATUS_VARIABLE) { + ulint page_size; + dict_table_stats_lock(ib_table, RW_S_LATCH); n_rows = ib_table->stat_n_rows; @@ -8173,14 +8211,19 @@ ha_innobase::info_low( prebuilt->autoinc_last_value = 0; } + page_size = dict_table_zip_size(ib_table); + if (page_size == 0) { + page_size = UNIV_PAGE_SIZE; + } + stats.records = (ha_rows)n_rows; stats.deleted = 0; - stats.data_file_length = ((ulonglong) - ib_table->stat_clustered_index_size) - * UNIV_PAGE_SIZE; - stats.index_file_length = ((ulonglong) - ib_table->stat_sum_of_other_index_sizes) - * UNIV_PAGE_SIZE; + stats.data_file_length + = ((ulonglong) ib_table->stat_clustered_index_size) + * page_size; + stats.index_file_length = + ((ulonglong) ib_table->stat_sum_of_other_index_sizes) + * page_size; dict_table_stats_unlock(ib_table, RW_S_LATCH); @@ -9135,10 +9178,18 @@ ha_innobase::external_lock( reset_template(prebuilt); - if (lock_type == F_WRLCK) { + if (lock_type == F_WRLCK + || (table->s->tmp_table + && thd_sql_command(thd) == SQLCOM_LOCK_TABLES)) { /* If this is a SELECT, then it is in UPDATE TABLE ... - or SELECT ... FOR UPDATE */ + or SELECT ... FOR UPDATE + + For temporary tables which are locked for READ by LOCK TABLES + updates are still allowed by SQL-layer. In order to accomodate + for such a situation we always request X-lock for such table + at LOCK TABLES time. + */ prebuilt->select_lock_type = LOCK_X; prebuilt->stored_select_lock_type = LOCK_X; } @@ -10385,6 +10436,10 @@ innobase_xa_prepare( return(0); } + if (trx->fake_changes) { + return(0); + } + thd_get_xid(thd, (MYSQL_XID*) &trx->xid); /* Release a possible FIFO ticket and search latch. Since we will @@ -10502,7 +10557,7 @@ innobase_commit_by_xid( if (trx) { innobase_commit_low(trx); - + trx_free_for_background(trx); return(XA_OK); } else { return(XAER_NOTA); @@ -10528,7 +10583,9 @@ innobase_rollback_by_xid( trx = trx_get_trx_by_xid(xid); if (trx) { - return(innobase_rollback_trx(trx)); + int ret = innobase_rollback_trx(trx); + trx_free_for_background(trx); + return(ret); } else { return(XAER_NOTA); } @@ -11202,19 +11259,19 @@ static int show_innodb_vars(THD *thd, SHOW_VAR *var, char *buff) return 0; } -/*********************************************************************** +/*********************************************************************//** This function checks each index name for a table against reserved -system default primary index name 'GEN_CLUST_INDEX'. If a name matches, -this function pushes an warning message to the client, and returns true. */ +system default primary index name 'GEN_CLUST_INDEX'. If a name +matches, this function pushes an warning message to the client, +and returns true. +@return true if the index name matches the reserved name */ extern "C" UNIV_INTERN bool innobase_index_name_is_reserved( /*============================*/ - /* out: true if an index name - matches the reserved name */ - const trx_t* trx, /* in: InnoDB transaction handle */ - const KEY* key_info, /* in: Indexes to be created */ - ulint num_of_keys) /* in: Number of indexes to + THD* thd, /*!< in/out: MySQL connection */ + const KEY* key_info, /*!< in: Indexes to be created */ + ulint num_of_keys) /*!< in: Number of indexes to be created. */ { const KEY* key; @@ -11226,7 +11283,7 @@ innobase_index_name_is_reserved( if (innobase_strcasecmp(key->name, innobase_index_reserve_name) == 0) { /* Push warning to mysql */ - push_warning_printf((THD*) trx->mysql_thd, + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_WRONG_NAME_FOR_INDEX, "Cannot Create Index with name " @@ -11245,6 +11302,48 @@ innobase_index_name_is_reserved( return(false); } +/*********************************************************************** +functions for kill session of idle transaction */ +extern "C" +ibool +innobase_thd_is_idle( +/*=================*/ + const void* thd) /*!< in: thread handle (THD*) */ +{ +#ifdef EXTENDED_FOR_KILLIDLE + return(thd_command((const THD*) thd) == COM_SLEEP); +#else + return(FALSE); +#endif +} + +extern "C" +ib_int64_t +innobase_thd_get_start_time( +/*========================*/ + const void* thd) /*!< in: thread handle (THD*) */ +{ +#ifdef EXTENDED_FOR_KILLIDLE + return((ib_int64_t)thd_start_time((const THD*) thd)); +#else + return(0); /*dummy value*/ +#endif +} + +extern "C" +void +innobase_thd_kill( +/*==============*/ + void* thd) +{ +#ifdef EXTENDED_FOR_KILLIDLE + thd_kill((THD*) thd); +#else + return; +#endif +} + + static SHOW_VAR innodb_status_variables_export[]= { {"Innodb", (char*) &show_innodb_vars, SHOW_FUNC}, {NullS, NullS, SHOW_LONG} @@ -11304,7 +11403,7 @@ static MYSQL_SYSVAR_BOOL(recovery_stats, innobase_recovery_stats, static MYSQL_SYSVAR_ULONG(use_purge_thread, srv_use_purge_thread, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, "Number of purge devoted threads. #### over 1 is EXPERIMENTAL ####", - NULL, NULL, 1, 0, 64, 0); + NULL, NULL, 1, 0, UNIV_MAX_PARALLELISM, 0); static MYSQL_SYSVAR_BOOL(overwrite_relay_log_info, innobase_overwrite_relay_log_info, PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY, @@ -11478,14 +11577,14 @@ static MYSQL_SYSVAR_LONGLONG(buffer_pool_size, innobase_buffer_pool_size, "The size of the memory buffer InnoDB uses to cache data and indexes of its tables.", NULL, NULL, 128*1024*1024L, 32*1024*1024L, LONGLONG_MAX, 1024*1024L); -static MYSQL_SYSVAR_UINT(buffer_pool_shm_key, srv_buffer_pool_shm_key, +static MYSQL_SYSVAR_UINT(buffer_pool_shm_key, innobase_buffer_pool_shm_key, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, - "[experimental] The key value of shared memory segment for the buffer pool. 0 (default) disables the feature.", + "[Deprecated option] no effect", NULL, NULL, 0, 0, INT_MAX32, 0); static MYSQL_SYSVAR_BOOL(buffer_pool_shm_checksum, innobase_buffer_pool_shm_checksum, PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY, - "Enable buffer_pool_shm checksum validation (enabled by default).", + "[Deprecated option] no effect", NULL, NULL, TRUE); static MYSQL_SYSVAR_ULONG(commit_concurrency, innobase_commit_concurrency, @@ -11498,6 +11597,15 @@ static MYSQL_SYSVAR_ULONG(concurrency_tickets, srv_n_free_tickets_to_enter, "Number of times a thread is allowed to enter InnoDB within the same SQL query after it has once got the ticket", NULL, NULL, 500L, 1L, ~0L, 0); +static MYSQL_SYSVAR_LONG(kill_idle_transaction, srv_kill_idle_transaction, + PLUGIN_VAR_RQCMDARG, +#ifdef EXTENDED_FOR_KILLIDLE + "If non-zero value, the idle session with transaction which is idle over the value in seconds is killed by InnoDB.", +#else + "No effect for this build.", +#endif + NULL, NULL, 0, 0, LONG_MAX, 0); + static MYSQL_SYSVAR_LONG(file_io_threads, innobase_file_io_threads, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY | PLUGIN_VAR_NOSYSVAR, "Number of file I/O threads in InnoDB.", @@ -11633,6 +11741,11 @@ static MYSQL_SYSVAR_UINT(change_buffering_debug, ibuf_debug, NULL, NULL, 0, 0, 1, 0); #endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */ +static MYSQL_SYSVAR_BOOL(random_read_ahead, srv_random_read_ahead, + PLUGIN_VAR_NOCMDARG, + "Whether to use read ahead for random access within an extent.", + NULL, NULL, FALSE); + static MYSQL_SYSVAR_ULONG(read_ahead_threshold, srv_read_ahead_threshold, PLUGIN_VAR_RQCMDARG, "Number of pages that must be accessed sequentially for InnoDB to " @@ -11756,13 +11869,19 @@ static MYSQL_SYSVAR_UINT(auto_lru_dump, srv_auto_lru_dump, "0 (the default) disables automatic dumps.", NULL, NULL, 0, 0, UINT_MAX32, 0); +static MYSQL_SYSVAR_BOOL(blocking_lru_restore, innobase_blocking_lru_restore, + PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY, + "Block XtraDB startup process until buffer pool is full restored from a " + "dump file (if present). Disabled by default.", + NULL, NULL, FALSE); + static MYSQL_SYSVAR_ULONG(pass_corrupt_table, srv_pass_corrupt_table, PLUGIN_VAR_RQCMDARG, "Pass corruptions of user tables as 'corrupt table' instead of not crashing itself, " "when used with file_per_table. " "All file io for the datafile after detected as corrupt are disabled, " "except for the deletion.", - NULL, NULL, 0, 0, 1, 0); + NULL, NULL, 0, 0, 2, 0); static MYSQL_SYSVAR_ULONG(lazy_drop_table, srv_lazy_drop_table, PLUGIN_VAR_RQCMDARG, @@ -11782,6 +11901,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(fast_checksum), MYSQL_SYSVAR(commit_concurrency), MYSQL_SYSVAR(concurrency_tickets), + MYSQL_SYSVAR(kill_idle_transaction), MYSQL_SYSVAR(data_file_path), MYSQL_SYSVAR(doublewrite_file), MYSQL_SYSVAR(data_home_dir), @@ -11856,12 +11976,15 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { #if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG MYSQL_SYSVAR(change_buffering_debug), #endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */ + MYSQL_SYSVAR(random_read_ahead), MYSQL_SYSVAR(read_ahead_threshold), MYSQL_SYSVAR(io_capacity), MYSQL_SYSVAR(auto_lru_dump), + MYSQL_SYSVAR(blocking_lru_restore), MYSQL_SYSVAR(use_purge_thread), MYSQL_SYSVAR(pass_corrupt_table), MYSQL_SYSVAR(lazy_drop_table), + MYSQL_SYSVAR(fake_changes), NULL }; diff --git a/handler/ha_innodb.h b/handler/ha_innodb.h index c60a5eae19e..bfe7432b32d 100644 --- a/handler/ha_innodb.h +++ b/handler/ha_innodb.h @@ -319,15 +319,14 @@ innobase_trx_allocate( This function checks each index name for a table against reserved system default primary index name 'GEN_CLUST_INDEX'. If a name matches, this function pushes an warning message to the client, -and returns true. */ +and returns true. +@return true if the index name matches the reserved name */ extern "C" bool innobase_index_name_is_reserved( /*============================*/ - /* out: true if the index name - matches the reserved name */ - const trx_t* trx, /* in: InnoDB transaction handle */ - const KEY* key_info, /* in: Indexes to be created */ - ulint num_of_keys); /* in: Number of indexes to + THD* thd, /*!< in/out: MySQL connection */ + const KEY* key_info, /*!< in: Indexes to be created */ + ulint num_of_keys); /*!< in: Number of indexes to be created. */ diff --git a/handler/handler0alter.cc b/handler/handler0alter.cc index 517445f7e69..37fddf71cbc 100644 --- a/handler/handler0alter.cc +++ b/handler/handler0alter.cc @@ -649,44 +649,47 @@ ha_innobase::add_index( update_thd(); - heap = mem_heap_create(1024); - /* In case MySQL calls this in the middle of a SELECT query, release possible adaptive hash latch to avoid deadlocks of threads. */ trx_search_latch_release_if_reserved(prebuilt->trx); - trx_start_if_not_started(prebuilt->trx); + if (prebuilt->trx->fake_changes) { + DBUG_RETURN(HA_ERR_WRONG_COMMAND); + } - /* Create a background transaction for the operations on - the data dictionary tables. */ - trx = innobase_trx_allocate(user_thd); - trx_start_if_not_started(trx); + /* Check if the index name is reserved. */ + if (innobase_index_name_is_reserved(user_thd, key_info, num_of_keys)) { + DBUG_RETURN(-1); + } innodb_table = indexed_table = dict_table_get(prebuilt->table->name, FALSE); if (UNIV_UNLIKELY(!innodb_table)) { - error = HA_ERR_NO_SUCH_TABLE; - goto err_exit; + DBUG_RETURN(HA_ERR_NO_SUCH_TABLE); } - /* Check if the index name is reserved. */ - if (innobase_index_name_is_reserved(trx, key_info, num_of_keys)) { - error = -1; - } else { - /* Check that index keys are sensible */ - error = innobase_check_index_keys(key_info, num_of_keys, - innodb_table); - } + /* Check that index keys are sensible */ + error = innobase_check_index_keys(key_info, num_of_keys, innodb_table); if (UNIV_UNLIKELY(error)) { -err_exit: + DBUG_RETURN(error); + } + + heap = mem_heap_create(1024); + trx_start_if_not_started(prebuilt->trx); + + /* Create a background transaction for the operations on + the data dictionary tables. */ + trx = innobase_trx_allocate(user_thd); + if (trx->fake_changes) { mem_heap_free(heap); trx_general_rollback_for_mysql(trx, NULL); trx_free_for_mysql(trx); - trx_commit_for_mysql(prebuilt->trx); - DBUG_RETURN(error); + DBUG_RETURN(HA_ERR_WRONG_COMMAND); } + trx_start_if_not_started(trx); + /* Create table containing all indexes to be built in this alter table add index so that they are in the correct order in the table. */ @@ -758,8 +761,12 @@ err_exit: ut_d(dict_table_check_for_dup_indexes(innodb_table, FALSE)); + mem_heap_free(heap); + trx_general_rollback_for_mysql(trx, NULL); row_mysql_unlock_data_dictionary(trx); - goto err_exit; + trx_free_for_mysql(trx); + trx_commit_for_mysql(prebuilt->trx); + DBUG_RETURN(error); } trx->table_id = indexed_table->id; @@ -782,10 +789,6 @@ err_exit: ut_ad(error == DB_SUCCESS); - /* We will need to rebuild index translation table. Set - valid index entry count in the translation table to zero */ - share->idx_trans_tbl.index_count = 0; - /* Commit the data dictionary transaction in order to release the table locks on the system tables. This means that if MySQL crashes while creating a new primary key inside @@ -911,6 +914,14 @@ error: } convert_error: + if (error == DB_SUCCESS) { + /* Build index is successful. We will need to + rebuild index translation table. Reset the + index entry count in the translation table + to zero, so that translation table will be rebuilt */ + share->idx_trans_tbl.index_count = 0; + } + error = convert_error_code_to_mysql(error, innodb_table->flags, user_thd); @@ -963,6 +974,10 @@ ha_innobase::prepare_drop_index( trx_search_latch_release_if_reserved(prebuilt->trx); trx = prebuilt->trx; + if (trx->fake_changes) { + DBUG_RETURN(HA_ERR_WRONG_COMMAND); + } + /* Test and mark all the indexes to be dropped */ row_mysql_lock_data_dictionary(trx); @@ -1167,6 +1182,12 @@ ha_innobase::final_drop_index( /* Create a background transaction for the operations on the data dictionary tables. */ trx = innobase_trx_allocate(user_thd); + if (trx->fake_changes) { + trx_general_rollback_for_mysql(trx, NULL); + trx_free_for_mysql(trx); + DBUG_RETURN(HA_ERR_WRONG_COMMAND); + } + trx_start_if_not_started(trx); /* Flag this transaction as a dictionary operation, so that diff --git a/handler/i_s.cc b/handler/i_s.cc index efb0822f14b..f6dceb17b53 100644 --- a/handler/i_s.cc +++ b/handler/i_s.cc @@ -953,7 +953,7 @@ UNIV_INTERN struct st_mysql_plugin i_s_innodb_buffer_pool_pages = /* plugin author (for SHOW PLUGINS) */ /* const char* */ - STRUCT_FLD(author, plugin_author), + STRUCT_FLD(author, "Percona"), /* general descriptive text (for SHOW PLUGINS) */ /* const char* */ @@ -1002,7 +1002,7 @@ UNIV_INTERN struct st_mysql_plugin i_s_innodb_buffer_pool_pages_index = /* plugin author (for SHOW PLUGINS) */ /* const char* */ - STRUCT_FLD(author, plugin_author), + STRUCT_FLD(author, "Percona"), /* general descriptive text (for SHOW PLUGINS) */ /* const char* */ @@ -1051,7 +1051,7 @@ UNIV_INTERN struct st_mysql_plugin i_s_innodb_buffer_pool_pages_blob = /* plugin author (for SHOW PLUGINS) */ /* const char* */ - STRUCT_FLD(author, plugin_author), + STRUCT_FLD(author, "Percona"), /* general descriptive text (for SHOW PLUGINS) */ /* const char* */ @@ -2573,7 +2573,7 @@ UNIV_INTERN struct st_mysql_plugin i_s_innodb_rseg = /* plugin author (for SHOW PLUGINS) */ /* const char* */ - STRUCT_FLD(author, plugin_author), + STRUCT_FLD(author, "Percona"), /* general descriptive text (for SHOW PLUGINS) */ /* const char* */ @@ -2606,6 +2606,172 @@ UNIV_INTERN struct st_mysql_plugin i_s_innodb_rseg = STRUCT_FLD(__reserved1, NULL) }; +/*********************************************************************** +*/ +static ST_FIELD_INFO i_s_innodb_admin_command_info[] = +{ + {STRUCT_FLD(field_name, "result_message"), + STRUCT_FLD(field_length, 1024), + STRUCT_FLD(field_type, MYSQL_TYPE_STRING), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + + END_OF_ST_FIELD_INFO +}; + +#ifndef INNODB_COMPATIBILITY_HOOKS +#error InnoDB needs MySQL to be built with #define INNODB_COMPATIBILITY_HOOKS +#endif + +extern "C" { +char **thd_query(MYSQL_THD thd); +} + +static +int +i_s_innodb_admin_command_fill( +/*==========================*/ + THD* thd, + TABLE_LIST* tables, + COND* cond) +{ + TABLE* i_s_table = (TABLE *) tables->table; + char** query_str; + char* ptr; + char quote = '\0'; + const char* command_head = "XTRA_"; + + DBUG_ENTER("i_s_innodb_admin_command_fill"); + + /* deny access to non-superusers */ + if (check_global_access(thd, PROCESS_ACL)) { + DBUG_RETURN(0); + } + + if(thd_sql_command(thd) != SQLCOM_SELECT) { + field_store_string(i_s_table->field[0], + "SELECT command is only accepted."); + goto end_func; + } + + query_str = thd_query(thd); + ptr = *query_str; + + for (; *ptr; ptr++) { + if (*ptr == quote) { + quote = '\0'; + } else if (quote) { + } else if (*ptr == '`' || *ptr == '"') { + quote = *ptr; + } else { + long i; + for (i = 0; command_head[i]; i++) { + if (toupper((int)(unsigned char)(ptr[i])) + != toupper((int)(unsigned char) + (command_head[i]))) { + goto nomatch; + } + } + break; +nomatch: + ; + } + } + + if (!*ptr) { + field_store_string(i_s_table->field[0], + "No XTRA_* command in the SQL statement." + " Please add /*!XTRA_xxxx*/ to the SQL."); + goto end_func; + } + + if (!strncasecmp("XTRA_HELLO", ptr, 10)) { + /* This is example command XTRA_HELLO */ + + ut_print_timestamp(stderr); + fprintf(stderr, " InnoDB: administration command test for XtraDB" + " 'XTRA_HELLO' was detected.\n"); + + field_store_string(i_s_table->field[0], + "Hello!"); + goto end_func; + } + else if (!strncasecmp("XTRA_LRU_DUMP", ptr, 13)) { + ut_print_timestamp(stderr); + fprintf(stderr, " InnoDB: administration command 'XTRA_LRU_DUMP'" + " was detected.\n"); + + if (buf_LRU_file_dump()) { + field_store_string(i_s_table->field[0], + "XTRA_LRU_DUMP was succeeded."); + } else { + field_store_string(i_s_table->field[0], + "XTRA_LRU_DUMP was failed."); + } + + goto end_func; + } + else if (!strncasecmp("XTRA_LRU_RESTORE", ptr, 16)) { + ut_print_timestamp(stderr); + fprintf(stderr, " InnoDB: administration command 'XTRA_LRU_RESTORE'" + " was detected.\n"); + + if (buf_LRU_file_restore()) { + field_store_string(i_s_table->field[0], + "XTRA_LRU_RESTORE was succeeded."); + } else { + field_store_string(i_s_table->field[0], + "XTRA_LRU_RESTORE was failed."); + } + + goto end_func; + } + + field_store_string(i_s_table->field[0], + "Undefined XTRA_* command."); + goto end_func; + +end_func: + if (schema_table_store_record(thd, i_s_table)) { + DBUG_RETURN(1); + } else { + DBUG_RETURN(0); + } +} + +static +int +i_s_innodb_admin_command_init( +/*==========================*/ + void* p) +{ + DBUG_ENTER("i_s_innodb_admin_command_init"); + ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p; + + schema->fields_info = i_s_innodb_admin_command_info; + schema->fill_table = i_s_innodb_admin_command_fill; + + DBUG_RETURN(0); +} + +UNIV_INTERN struct st_mysql_plugin i_s_innodb_admin_command = +{ + STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN), + STRUCT_FLD(info, &i_s_info), + STRUCT_FLD(name, "XTRADB_ADMIN_COMMAND"), + STRUCT_FLD(author, "Percona"), + STRUCT_FLD(descr, "XtraDB specific command acceptor"), + STRUCT_FLD(license, PLUGIN_LICENSE_GPL), + STRUCT_FLD(init, i_s_innodb_admin_command_init), + STRUCT_FLD(deinit, i_s_common_deinit), + STRUCT_FLD(version, 0x0100 /* 1.0 */), + STRUCT_FLD(status_vars, NULL), + STRUCT_FLD(system_vars, NULL), + STRUCT_FLD(__reserved1, NULL) +}; + /*********************************************************************** */ static ST_FIELD_INFO i_s_innodb_table_stats_info[] = @@ -2923,7 +3089,7 @@ UNIV_INTERN struct st_mysql_plugin i_s_innodb_table_stats = STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN), STRUCT_FLD(info, &i_s_info), STRUCT_FLD(name, "INNODB_TABLE_STATS"), - STRUCT_FLD(author, plugin_author), + STRUCT_FLD(author, "Percona"), STRUCT_FLD(descr, "InnoDB table statistics in memory"), STRUCT_FLD(license, PLUGIN_LICENSE_GPL), STRUCT_FLD(init, i_s_innodb_table_stats_init), @@ -2939,7 +3105,7 @@ UNIV_INTERN struct st_mysql_plugin i_s_innodb_index_stats = STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN), STRUCT_FLD(info, &i_s_info), STRUCT_FLD(name, "INNODB_INDEX_STATS"), - STRUCT_FLD(author, plugin_author), + STRUCT_FLD(author, "Percona"), STRUCT_FLD(descr, "InnoDB index statistics in memory"), STRUCT_FLD(license, PLUGIN_LICENSE_GPL), STRUCT_FLD(init, i_s_innodb_index_stats_init), @@ -2950,172 +3116,6 @@ UNIV_INTERN struct st_mysql_plugin i_s_innodb_index_stats = STRUCT_FLD(__reserved1, NULL) }; -/*********************************************************************** -*/ -static ST_FIELD_INFO i_s_innodb_admin_command_info[] = -{ - {STRUCT_FLD(field_name, "result_message"), - STRUCT_FLD(field_length, 1024), - STRUCT_FLD(field_type, MYSQL_TYPE_STRING), - STRUCT_FLD(value, 0), - STRUCT_FLD(field_flags, 0), - STRUCT_FLD(old_name, ""), - STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, - - END_OF_ST_FIELD_INFO -}; - -#ifndef INNODB_COMPATIBILITY_HOOKS -#error InnoDB needs MySQL to be built with #define INNODB_COMPATIBILITY_HOOKS -#endif - -extern "C" { -char **thd_query(MYSQL_THD thd); -} - -static -int -i_s_innodb_admin_command_fill( -/*==========================*/ - THD* thd, - TABLE_LIST* tables, - COND* cond) -{ - TABLE* i_s_table = (TABLE *) tables->table; - char** query_str; - char* ptr; - char quote = '\0'; - const char* command_head = "XTRA_"; - - DBUG_ENTER("i_s_innodb_admin_command_fill"); - - /* deny access to non-superusers */ - if (check_global_access(thd, PROCESS_ACL)) { - DBUG_RETURN(0); - } - - if(thd_sql_command(thd) != SQLCOM_SELECT) { - field_store_string(i_s_table->field[0], - "SELECT command is only accepted."); - goto end_func; - } - - query_str = thd_query(thd); - ptr = *query_str; - - for (; *ptr; ptr++) { - if (*ptr == quote) { - quote = '\0'; - } else if (quote) { - } else if (*ptr == '`' || *ptr == '"') { - quote = *ptr; - } else { - long i; - for (i = 0; command_head[i]; i++) { - if (toupper((int)(unsigned char)(ptr[i])) - != toupper((int)(unsigned char) - (command_head[i]))) { - goto nomatch; - } - } - break; -nomatch: - ; - } - } - - if (!*ptr) { - field_store_string(i_s_table->field[0], - "No XTRA_* command in the SQL statement." - " Please add /*!XTRA_xxxx*/ to the SQL."); - goto end_func; - } - - if (!strncasecmp("XTRA_HELLO", ptr, 10)) { - /* This is example command XTRA_HELLO */ - - ut_print_timestamp(stderr); - fprintf(stderr, " InnoDB: administration command test for XtraDB" - " 'XTRA_HELLO' was detected.\n"); - - field_store_string(i_s_table->field[0], - "Hello!"); - goto end_func; - } - else if (!strncasecmp("XTRA_LRU_DUMP", ptr, 13)) { - ut_print_timestamp(stderr); - fprintf(stderr, " InnoDB: administration command 'XTRA_LRU_DUMP'" - " was detected.\n"); - - if (buf_LRU_file_dump()) { - field_store_string(i_s_table->field[0], - "XTRA_LRU_DUMP was succeeded."); - } else { - field_store_string(i_s_table->field[0], - "XTRA_LRU_DUMP was failed."); - } - - goto end_func; - } - else if (!strncasecmp("XTRA_LRU_RESTORE", ptr, 16)) { - ut_print_timestamp(stderr); - fprintf(stderr, " InnoDB: administration command 'XTRA_LRU_RESTORE'" - " was detected.\n"); - - if (buf_LRU_file_restore()) { - field_store_string(i_s_table->field[0], - "XTRA_LRU_RESTORE was succeeded."); - } else { - field_store_string(i_s_table->field[0], - "XTRA_LRU_RESTORE was failed."); - } - - goto end_func; - } - - field_store_string(i_s_table->field[0], - "Undefined XTRA_* command."); - goto end_func; - -end_func: - if (schema_table_store_record(thd, i_s_table)) { - DBUG_RETURN(1); - } else { - DBUG_RETURN(0); - } -} - -static -int -i_s_innodb_admin_command_init( -/*==========================*/ - void* p) -{ - DBUG_ENTER("i_s_innodb_admin_command_init"); - ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p; - - schema->fields_info = i_s_innodb_admin_command_info; - schema->fill_table = i_s_innodb_admin_command_fill; - - DBUG_RETURN(0); -} - -UNIV_INTERN struct st_mysql_plugin i_s_innodb_admin_command = -{ - STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN), - STRUCT_FLD(info, &i_s_info), - STRUCT_FLD(name, "XTRADB_ADMIN_COMMAND"), - STRUCT_FLD(author, plugin_author), - STRUCT_FLD(descr, "XtraDB specific command acceptor"), - STRUCT_FLD(license, PLUGIN_LICENSE_GPL), - STRUCT_FLD(init, i_s_innodb_admin_command_init), - STRUCT_FLD(deinit, i_s_common_deinit), - STRUCT_FLD(version, 0x0100 /* 1.0 */), - STRUCT_FLD(status_vars, NULL), - STRUCT_FLD(system_vars, NULL), - STRUCT_FLD(__reserved1, NULL) -}; - static ST_FIELD_INFO i_s_innodb_sys_tables_info[] = { {STRUCT_FLD(field_name, "SCHEMA"), @@ -3651,15 +3651,14 @@ i_s_innodb_schema_table_fill( rec = btr_pcur_get_rec(&pcur); if (!btr_pcur_is_on_user_rec(&pcur)) { /* end of index */ - btr_pcur_close(&pcur); - mtr_commit(&mtr); break; } + + btr_pcur_store_position(&pcur, &mtr); + if (rec_get_deleted_flag(rec, 0)) { /* record marked as deleted */ - btr_pcur_close(&pcur); - mtr_commit(&mtr); - continue; + goto next_record; } if (id == 0) { @@ -3670,33 +3669,23 @@ i_s_innodb_schema_table_fill( status = copy_sys_stats_rec(table, index, rec); } if (status) { - btr_pcur_close(&pcur); - mtr_commit(&mtr); break; } -#if 0 - btr_pcur_store_position(&pcur, &mtr); - mtr_commit(&mtr); - status = schema_table_store_record(thd, table); if (status) { - btr_pcur_close(&pcur); break; } +next_record: + mtr_commit(&mtr); mtr_start(&mtr); btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr); -#else - status = schema_table_store_record(thd, table); - if (status) { - btr_pcur_close(&pcur); - mtr_commit(&mtr); - break; - } -#endif } + btr_pcur_close(&pcur); + mtr_commit(&mtr); + mutex_exit(&(dict_sys->mutex)); DBUG_RETURN(status); @@ -3752,7 +3741,7 @@ UNIV_INTERN struct st_mysql_plugin i_s_innodb_sys_tables = STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN), STRUCT_FLD(info, &i_s_info), STRUCT_FLD(name, "INNODB_SYS_TABLES"), - STRUCT_FLD(author, plugin_author), + STRUCT_FLD(author, "Percona"), STRUCT_FLD(descr, "InnoDB SYS_TABLES table"), STRUCT_FLD(license, PLUGIN_LICENSE_GPL), STRUCT_FLD(init, i_s_innodb_sys_tables_init), @@ -3768,7 +3757,7 @@ UNIV_INTERN struct st_mysql_plugin i_s_innodb_sys_indexes = STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN), STRUCT_FLD(info, &i_s_info), STRUCT_FLD(name, "INNODB_SYS_INDEXES"), - STRUCT_FLD(author, plugin_author), + STRUCT_FLD(author, "Percona"), STRUCT_FLD(descr, "InnoDB SYS_INDEXES table"), STRUCT_FLD(license, PLUGIN_LICENSE_GPL), STRUCT_FLD(init, i_s_innodb_sys_indexes_init), @@ -3784,7 +3773,7 @@ UNIV_INTERN struct st_mysql_plugin i_s_innodb_sys_stats = STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN), STRUCT_FLD(info, &i_s_info), STRUCT_FLD(name, "INNODB_SYS_STATS"), - STRUCT_FLD(author, plugin_author), + STRUCT_FLD(author, "Percona"), STRUCT_FLD(descr, "InnoDB SYS_STATS table"), STRUCT_FLD(license, PLUGIN_LICENSE_GPL), STRUCT_FLD(init, i_s_innodb_sys_stats_init), diff --git a/handler/innodb_patch_info.h b/handler/innodb_patch_info.h index e68f12d0fec..38b97411340 100644 --- a/handler/innodb_patch_info.h +++ b/handler/innodb_patch_info.h @@ -47,6 +47,5 @@ struct innodb_enhancement { {"innodb_fast_checksum","Using the checksum on 32bit-unit calculation","incompatible for unpatched ver.","http://www.percona.com/docs/wiki/percona-xtradb"}, {"innodb_files_extend","allow >4GB transaction log files, and can vary universal page size of datafiles","incompatible for unpatched ver.","http://www.percona.com/docs/wiki/percona-xtradb"}, {"innodb_sys_tables_sys_indexes","Expose InnoDB SYS_TABLES and SYS_INDEXES schema tables","","http://www.percona.com/docs/wiki/percona-xtradb"}, -{"innodb_buffer_pool_shm","Put buffer pool contents to shared memory segment and reuse it at clean restart [experimental]","","http://www.percona.com/docs/wiki/percona-xtradb"}, {NULL, NULL, NULL, NULL} }; diff --git a/ibuf/ibuf0ibuf.c b/ibuf/ibuf0ibuf.c index 3f741da60bb..64dc9a5591d 100644 --- a/ibuf/ibuf0ibuf.c +++ b/ibuf/ibuf0ibuf.c @@ -2613,6 +2613,8 @@ ibuf_insert_low( ut_a(trx_sys_multiple_tablespace_format); + ut_ad(!(thr_get_trx(thr)->fake_changes)); + do_merge = FALSE; mutex_enter(&ibuf_mutex); diff --git a/include/btr0btr.h b/include/btr0btr.h index dde3a0bab69..1fe40965c0f 100644 --- a/include/btr0btr.h +++ b/include/btr0btr.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2010, 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 @@ -81,6 +81,91 @@ UNIQUE definition on secondary indexes when we decide if we can use the insert buffer to speed up inserts */ #define BTR_IGNORE_SEC_UNIQUE 2048 +#ifdef UNIV_BLOB_DEBUG +# include "ut0rbt.h" +/** An index->blobs entry for keeping track of off-page column references */ +struct btr_blob_dbg_struct +{ + unsigned blob_page_no:32; /*!< first BLOB page number */ + unsigned ref_page_no:32; /*!< referring page number */ + unsigned ref_heap_no:16; /*!< referring heap number */ + unsigned ref_field_no:10; /*!< referring field number */ + unsigned owner:1; /*!< TRUE if BLOB owner */ + unsigned always_owner:1; /*!< TRUE if always + has been the BLOB owner; + reset to TRUE on B-tree + page splits and merges */ + unsigned del:1; /*!< TRUE if currently + delete-marked */ +}; + +/**************************************************************//** +Add a reference to an off-page column to the index->blobs map. */ +UNIV_INTERN +void +btr_blob_dbg_add_blob( +/*==================*/ + const rec_t* rec, /*!< in: clustered index record */ + ulint field_no, /*!< in: number of off-page column */ + ulint page_no, /*!< in: start page of the column */ + dict_index_t* index, /*!< in/out: index tree */ + const char* ctx) /*!< in: context (for logging) */ + __attribute__((nonnull)); +/**************************************************************//** +Display the references to off-page columns. +This function is to be called from a debugger, +for example when a breakpoint on ut_dbg_assertion_failed is hit. */ +UNIV_INTERN +void +btr_blob_dbg_print( +/*===============*/ + const dict_index_t* index) /*!< in: index tree */ + __attribute__((nonnull)); +/**************************************************************//** +Check that there are no references to off-page columns from or to +the given page. Invoked when freeing or clearing a page. +@return TRUE when no orphan references exist */ +UNIV_INTERN +ibool +btr_blob_dbg_is_empty( +/*==================*/ + dict_index_t* index, /*!< in: index */ + ulint page_no) /*!< in: page number */ + __attribute__((nonnull, warn_unused_result)); + +/**************************************************************//** +Modify the 'deleted' flag of a record. */ +UNIV_INTERN +void +btr_blob_dbg_set_deleted_flag( +/*==========================*/ + const rec_t* rec, /*!< in: record */ + dict_index_t* index, /*!< in/out: index */ + const ulint* offsets,/*!< in: rec_get_offs(rec, index) */ + ibool del) /*!< in: TRUE=deleted, FALSE=exists */ + __attribute__((nonnull)); +/**************************************************************//** +Change the ownership of an off-page column. */ +UNIV_INTERN +void +btr_blob_dbg_owner( +/*===============*/ + const rec_t* rec, /*!< in: record */ + dict_index_t* index, /*!< in/out: index */ + const ulint* offsets,/*!< in: rec_get_offs(rec, index) */ + ulint i, /*!< in: ith field in rec */ + ibool own) /*!< in: TRUE=owned, FALSE=disowned */ + __attribute__((nonnull)); +/** Assert that there are no BLOB references to or from the given page. */ +# define btr_blob_dbg_assert_empty(index, page_no) \ + ut_a(btr_blob_dbg_is_empty(index, page_no)) +#else /* UNIV_BLOB_DEBUG */ +# define btr_blob_dbg_add_blob(rec, field_no, page, index, ctx) ((void) 0) +# define btr_blob_dbg_set_deleted_flag(rec, index, offsets, del)((void) 0) +# define btr_blob_dbg_owner(rec, index, offsets, i, val) ((void) 0) +# define btr_blob_dbg_assert_empty(index, page_no) ((void) 0) +#endif /* UNIV_BLOB_DEBUG */ + /**************************************************************//** Gets the root node of a tree and x-latches it. @return root page, x-latched */ @@ -123,6 +208,17 @@ btr_block_get_func( @return the uncompressed page frame */ # define btr_page_get(space,zip_size,page_no,mode,mtr) \ buf_block_get_frame(btr_block_get(space,zip_size,page_no,mode,mtr)) +/**************************************************************//** +Sets the index id field of a page. */ +UNIV_INLINE +void +btr_page_set_index_id( +/*==================*/ + page_t* page, /*!< in: page to be created */ + page_zip_des_t* page_zip,/*!< in: compressed page whose uncompressed + part will be updated, or NULL */ + dulint id, /*!< in: index id */ + mtr_t* mtr); /*!< in: mtr */ #endif /* !UNIV_HOTBACKUP */ /**************************************************************//** Gets the index id field of a page. @@ -160,6 +256,17 @@ btr_page_get_next( const page_t* page, /*!< in: index page */ mtr_t* mtr); /*!< in: mini-transaction handle */ /********************************************************//** +Sets the next index page field. */ +UNIV_INLINE +void +btr_page_set_next( +/*==============*/ + page_t* page, /*!< in: index page */ + page_zip_des_t* page_zip,/*!< in: compressed page whose uncompressed + part will be updated, or NULL */ + ulint next, /*!< in: next page number */ + mtr_t* mtr); /*!< in: mini-transaction handle */ +/********************************************************//** Gets the previous index page number. @return prev page number */ UNIV_INLINE @@ -168,6 +275,17 @@ btr_page_get_prev( /*==============*/ const page_t* page, /*!< in: index page */ mtr_t* mtr); /*!< in: mini-transaction handle */ +/********************************************************//** +Sets the previous index page field. */ +UNIV_INLINE +void +btr_page_set_prev( +/*==============*/ + page_t* page, /*!< in: index page */ + page_zip_des_t* page_zip,/*!< in: compressed page whose uncompressed + part will be updated, or NULL */ + ulint prev, /*!< in: previous page number */ + mtr_t* mtr); /*!< in: mini-transaction handle */ /*************************************************************//** Gets pointer to the previous user record in the tree. It is assumed that the caller has appropriate latches on the page and its neighbor. @@ -213,6 +331,18 @@ btr_node_ptr_get_child_page_no( /*===========================*/ const rec_t* rec, /*!< in: node pointer record */ const ulint* offsets);/*!< in: array returned by rec_get_offsets() */ +/**************************************************************//** +Creates a new index page (not the root, and also not +used in page reorganization). @see btr_page_empty(). */ +UNIV_INTERN +void +btr_page_create( +/*============*/ + buf_block_t* block, /*!< in/out: page to be created */ + page_zip_des_t* page_zip,/*!< in/out: compressed page, or NULL */ + dict_index_t* index, /*!< in: index */ + ulint level, /*!< in: the B-tree level of the page */ + mtr_t* mtr); /*!< in: mtr */ /************************************************************//** Creates the root node for a new index tree. @return page number of the created root, FIL_NULL if did not succeed */ @@ -283,6 +413,17 @@ btr_page_reorganize( dict_index_t* index, /*!< in: record descriptor */ mtr_t* mtr); /*!< in: mtr */ /*************************************************************//** +Empties an index page. @see btr_page_create(). */ +UNIV_INTERN +void +btr_page_empty( +/*===========*/ + buf_block_t* block, /*!< in: page to be emptied */ + page_zip_des_t* page_zip,/*!< out: compressed page, or NULL */ + dict_index_t* index, /*!< in: index of the page */ + ulint level, /*!< in: the B-tree level of the page */ + mtr_t* mtr); /*!< in: mtr */ +/*************************************************************//** Decides if the page should be split at the convergence point of inserts converging to left. @return TRUE if split recommended */ @@ -341,6 +482,20 @@ btr_insert_on_non_leaf_level_func( # define btr_insert_on_non_leaf_level(i,l,t,m) \ btr_insert_on_non_leaf_level_func(i,l,t,__FILE__,__LINE__,m) #endif /* !UNIV_HOTBACKUP */ +/**************************************************************//** +Attaches the halves of an index page on the appropriate level in an +index tree. */ +UNIV_INTERN +void +btr_attach_half_pages( +/*==================*/ + dict_index_t* index, /*!< in: the index tree */ + buf_block_t* block, /*!< in/out: page to be split */ + const rec_t* split_rec, /*!< in: first record on upper + half page */ + buf_block_t* new_block, /*!< in/out: the new half page */ + ulint direction, /*!< in: FSP_UP or FSP_DOWN */ + mtr_t* mtr); /*!< in: mtr */ /****************************************************************//** Sets a record as the predefined minimum record. */ UNIV_INTERN @@ -385,11 +540,14 @@ UNIV_INTERN ibool btr_compress( /*=========*/ - btr_cur_t* cursor, /*!< in: cursor on the page to merge or lift; - the page must not be empty: in record delete - use btr_discard_page if the page would become - empty */ - mtr_t* mtr); /*!< in: mtr */ + btr_cur_t* cursor, /*!< in/out: cursor on the page to merge + or lift; the page must not be empty: + when deleting records, use btr_discard_page() + if the page would become empty */ + ibool adjust, /*!< in: TRUE if should adjust the + cursor position even if compression occurs */ + mtr_t* mtr) /*!< in/out: mini-transaction */ + __attribute__((nonnull)); /*************************************************************//** Discards a page from a B-tree. This is used to remove the last record from a B-tree page: the whole page must be removed at the same time. This cannot diff --git a/include/btr0cur.h b/include/btr0cur.h index ece3621fa97..6f4ce95d72f 100644 --- a/include/btr0cur.h +++ b/include/btr0cur.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2010, 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 @@ -36,6 +36,9 @@ Created 10/16/1994 Heikki Tuuri #define BTR_NO_LOCKING_FLAG 2 /* do no record lock checking */ #define BTR_KEEP_SYS_FLAG 4 /* sys fields will be found from the update vector or inserted entry */ +#define BTR_KEEP_POS_FLAG 8 /* btr_cur_pessimistic_update() + must keep cursor position when + moving columns to big_rec */ #ifndef UNIV_HOTBACKUP #include "que0types.h" @@ -309,7 +312,9 @@ btr_cur_pessimistic_update( /*=======================*/ ulint flags, /*!< in: undo logging, locking, and rollback flags */ - btr_cur_t* cursor, /*!< in: cursor on the record to update */ + btr_cur_t* cursor, /*!< in/out: cursor on the record to update; + cursor may become invalid if *big_rec == NULL + || !(flags & BTR_KEEP_POS_FLAG) */ mem_heap_t** heap, /*!< in/out: pointer to memory heap, or NULL */ big_rec_t** big_rec,/*!< out: big rec vector whose fields have to be stored externally by the caller, or NULL */ @@ -321,6 +326,16 @@ btr_cur_pessimistic_update( que_thr_t* thr, /*!< in: query thread */ mtr_t* mtr); /*!< in: mtr; must be committed before latching any further pages */ +/***************************************************************** +Commits and restarts a mini-transaction so that it will retain an +x-lock on index->lock and the cursor page. */ +UNIV_INTERN +void +btr_cur_mtr_commit_and_start( +/*=========================*/ + btr_cur_t* cursor, /*!< in: cursor */ + mtr_t* mtr) /*!< in/out: mini-transaction */ + __attribute__((nonnull)); /***********************************************************//** Marks a clustered index record deleted. Writes an undo log record to undo log on this delete marking. Writes in the trx id field the id @@ -376,10 +391,13 @@ UNIV_INTERN ibool btr_cur_compress_if_useful( /*=======================*/ - btr_cur_t* cursor, /*!< in: cursor on the page to compress; + btr_cur_t* cursor, /*!< in/out: cursor on the page to compress; cursor does not stay valid if compression occurs */ - mtr_t* mtr); /*!< in: mtr */ + ibool adjust, /*!< in: TRUE if should adjust the + cursor position even if compression occurs */ + mtr_t* mtr) /*!< in/out: mini-transaction */ + __attribute__((nonnull)); /*******************************************************//** Removes the record on which the tree cursor is positioned. It is assumed that the mtr has an x-latch on the page where the cursor is positioned, @@ -652,6 +670,11 @@ struct btr_path_struct{ order); value ULINT_UNDEFINED denotes array end */ ulint n_recs; /*!< number of records on the page */ + ulint page_no; /*!< no of the page containing the record */ + ulint page_level; /*!< level of the page, if later we fetch + the page under page_no and it is no different + level then we know that the tree has been + reorganized */ }; #define BTR_PATH_ARRAY_N_SLOTS 250 /*!< size of path array (in slots) */ diff --git a/include/btr0cur.ic b/include/btr0cur.ic index 280583f6ccf..c833b3e8572 100644 --- a/include/btr0cur.ic +++ b/include/btr0cur.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 @@ -139,7 +139,7 @@ btr_cur_compress_recommendation( btr_cur_t* cursor, /*!< in: btr cursor */ mtr_t* mtr) /*!< in: mtr */ { - page_t* page; + const page_t* page; ut_ad(mtr_memo_contains(mtr, btr_cur_get_block(cursor), MTR_MEMO_PAGE_X_FIX)); diff --git a/include/btr0pcur.h b/include/btr0pcur.h index 2334a266280..f59514d04b3 100644 --- a/include/btr0pcur.h +++ b/include/btr0pcur.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2010, 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 @@ -244,18 +244,6 @@ btr_pcur_restore_position_func( mtr_t* mtr); /*!< in: mtr */ #define btr_pcur_restore_position(l,cur,mtr) \ btr_pcur_restore_position_func(l,cur,__FILE__,__LINE__,mtr) -/**************************************************************//** -If the latch mode of the cursor is BTR_LEAF_SEARCH or BTR_LEAF_MODIFY, -releases the page latch and bufferfix reserved by the cursor. -NOTE! In the case of BTR_LEAF_MODIFY, there should not exist changes -made by the current mini-transaction to the data protected by the -cursor latch, as then the latch must not be released until mtr_commit. */ -UNIV_INTERN -void -btr_pcur_release_leaf( -/*==================*/ - btr_pcur_t* cursor, /*!< in: persistent cursor */ - mtr_t* mtr); /*!< in: mtr */ /*********************************************************//** Gets the rel_pos field for a cursor whose position has been stored. @return BTR_PCUR_ON, ... */ @@ -282,10 +270,9 @@ btr_pcur_get_mtr( btr_pcur_t* cursor); /*!< in: persistent cursor */ /**************************************************************//** Commits the mtr and sets the pcur latch mode to BTR_NO_LATCHES, -that is, the cursor becomes detached. If there have been modifications -to the page where pcur is positioned, this can be used instead of -btr_pcur_release_leaf. Function btr_pcur_store_position should be used -before calling this, if restoration of cursor is wanted later. */ +that is, the cursor becomes detached. +Function btr_pcur_store_position should be used before calling this, +if restoration of cursor is wanted later. */ UNIV_INLINE void btr_pcur_commit_specify_mtr( diff --git a/include/btr0pcur.ic b/include/btr0pcur.ic index 0c38797e6c5..0f9b969e7c5 100644 --- a/include/btr0pcur.ic +++ b/include/btr0pcur.ic @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2010, 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 @@ -396,10 +396,9 @@ btr_pcur_move_to_next( /**************************************************************//** Commits the mtr and sets the pcur latch mode to BTR_NO_LATCHES, -that is, the cursor becomes detached. If there have been modifications -to the page where pcur is positioned, this can be used instead of -btr_pcur_release_leaf. Function btr_pcur_store_position should be used -before calling this, if restoration of cursor is wanted later. */ +that is, the cursor becomes detached. +Function btr_pcur_store_position should be used before calling this, +if restoration of cursor is wanted later. */ UNIV_INLINE void btr_pcur_commit_specify_mtr( diff --git a/include/btr0types.h b/include/btr0types.h index ef4a6b04b34..07c06fb18d7 100644 --- a/include/btr0types.h +++ b/include/btr0types.h @@ -38,6 +38,131 @@ 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; +#ifdef UNIV_BLOB_DEBUG +# include "buf0types.h" +/** An index->blobs entry for keeping track of off-page column references */ +typedef struct btr_blob_dbg_struct btr_blob_dbg_t; + +/** Insert to index->blobs a reference to an off-page column. +@param index the index tree +@param b the reference +@param ctx context (for logging) */ +UNIV_INTERN +void +btr_blob_dbg_rbt_insert( +/*====================*/ + dict_index_t* index, /*!< in/out: index tree */ + const btr_blob_dbg_t* b, /*!< in: the reference */ + const char* ctx) /*!< in: context (for logging) */ + __attribute__((nonnull)); + +/** Remove from index->blobs a reference to an off-page column. +@param index the index tree +@param b the reference +@param ctx context (for logging) */ +UNIV_INTERN +void +btr_blob_dbg_rbt_delete( +/*====================*/ + dict_index_t* index, /*!< in/out: index tree */ + const btr_blob_dbg_t* b, /*!< in: the reference */ + const char* ctx) /*!< in: context (for logging) */ + __attribute__((nonnull)); + +/**************************************************************//** +Add to index->blobs any references to off-page columns from a record. +@return number of references added */ +UNIV_INTERN +ulint +btr_blob_dbg_add_rec( +/*=================*/ + const rec_t* rec, /*!< in: record */ + dict_index_t* index, /*!< in/out: index */ + const ulint* offsets,/*!< in: offsets */ + const char* ctx) /*!< in: context (for logging) */ + __attribute__((nonnull)); +/**************************************************************//** +Remove from index->blobs any references to off-page columns from a record. +@return number of references removed */ +UNIV_INTERN +ulint +btr_blob_dbg_remove_rec( +/*====================*/ + const rec_t* rec, /*!< in: record */ + dict_index_t* index, /*!< in/out: index */ + const ulint* offsets,/*!< in: offsets */ + const char* ctx) /*!< in: context (for logging) */ + __attribute__((nonnull)); +/**************************************************************//** +Count and add to index->blobs any references to off-page columns +from records on a page. +@return number of references added */ +UNIV_INTERN +ulint +btr_blob_dbg_add( +/*=============*/ + const page_t* page, /*!< in: rewritten page */ + dict_index_t* index, /*!< in/out: index */ + const char* ctx) /*!< in: context (for logging) */ + __attribute__((nonnull)); +/**************************************************************//** +Count and remove from index->blobs any references to off-page columns +from records on a page. +Used when reorganizing a page, before copying the records. +@return number of references removed */ +UNIV_INTERN +ulint +btr_blob_dbg_remove( +/*================*/ + const page_t* page, /*!< in: b-tree page */ + dict_index_t* index, /*!< in/out: index */ + const char* ctx) /*!< in: context (for logging) */ + __attribute__((nonnull)); +/**************************************************************//** +Restore in index->blobs any references to off-page columns +Used when page reorganize fails due to compressed page overflow. */ +UNIV_INTERN +void +btr_blob_dbg_restore( +/*=================*/ + const page_t* npage, /*!< in: page that failed to compress */ + const page_t* page, /*!< in: copy of original page */ + dict_index_t* index, /*!< in/out: index */ + const char* ctx) /*!< in: context (for logging) */ + __attribute__((nonnull)); + +/** Operation that processes the BLOB references of an index record +@param[in] rec record on index page +@param[in/out] index the index tree of the record +@param[in] offsets rec_get_offsets(rec,index) +@param[in] ctx context (for logging) +@return number of BLOB references processed */ +typedef ulint (*btr_blob_dbg_op_f) +(const rec_t* rec,dict_index_t* index,const ulint* offsets,const char* ctx); + +/**************************************************************//** +Count and process all references to off-page columns on a page. +@return number of references processed */ +UNIV_INTERN +ulint +btr_blob_dbg_op( +/*============*/ + const page_t* page, /*!< in: B-tree leaf page */ + const rec_t* rec, /*!< in: record to start from + (NULL to process the whole page) */ + dict_index_t* index, /*!< in/out: index */ + const char* ctx, /*!< in: context (for logging) */ + const btr_blob_dbg_op_f op) /*!< in: operation on records */ + __attribute__((nonnull(1,3,4,5))); +#else /* UNIV_BLOB_DEBUG */ +# define btr_blob_dbg_add_rec(rec, index, offsets, ctx) ((void) 0) +# define btr_blob_dbg_add(page, index, ctx) ((void) 0) +# define btr_blob_dbg_remove_rec(rec, index, offsets, ctx) ((void) 0) +# define btr_blob_dbg_remove(page, index, ctx) ((void) 0) +# define btr_blob_dbg_restore(npage, page, index, ctx) ((void) 0) +# define btr_blob_dbg_op(page, rec, index, ctx, op) ((void) 0) +#endif /* UNIV_BLOB_DEBUG */ + /** The size of a reference to data stored on a different page. The reference is stored at the end of the prefix of the field in the index record. */ diff --git a/include/buf0buddy.h b/include/buf0buddy.h index 3a35f8e46e9..f4c3da8692d 100644 --- a/include/buf0buddy.h +++ b/include/buf0buddy.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2006, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 2006, 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 @@ -37,25 +37,20 @@ Created December 2006 by Marko Makela /**********************************************************************//** Allocate a block. The thread calling this function must hold buf_pool_mutex and must not hold buf_pool_zip_mutex or any -block->mutex. The buf_pool_mutex may only be released and reacquired -if lru != NULL. This function should only be used for allocating -compressed page frames or control blocks (buf_page_t). Allocated -control blocks must be properly initialized immediately after -buf_buddy_alloc() has returned the memory, before releasing -buf_pool_mutex. -@return allocated block, possibly NULL if lru == NULL */ +block->mutex. The buf_pool_mutex may be released and reacquired. +This function should only be used for allocating compressed page frames. +@return allocated block, never NULL */ UNIV_INLINE void* buf_buddy_alloc( /*============*/ - ulint size, /*!< in: block size, up to UNIV_PAGE_SIZE */ + ulint size, /*!< in: compressed page size + (between PAGE_ZIP_MIN_SIZE and UNIV_PAGE_SIZE) */ ibool* lru, /*!< in: pointer to a variable that will be assigned TRUE if storage was allocated from the LRU list - and buf_pool_mutex was temporarily released, - or NULL if the LRU list should not be used */ + and buf_pool_mutex was temporarily released */ ibool have_page_hash_mutex) - __attribute__((malloc)); - + __attribute__((malloc, nonnull)); /**********************************************************************//** Release a block. */ UNIV_INLINE diff --git a/include/buf0buddy.ic b/include/buf0buddy.ic index 69659fb69d6..63241311e1f 100644 --- a/include/buf0buddy.ic +++ b/include/buf0buddy.ic @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2006, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 2006, 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 @@ -36,8 +36,8 @@ Created December 2006 by Marko Makela /**********************************************************************//** Allocate a block. The thread calling this function must hold buf_pool_mutex and must not hold buf_pool_zip_mutex or any block->mutex. -The buf_pool_mutex may only be released and reacquired if lru != NULL. -@return allocated block, possibly NULL if lru==NULL */ +The buf_pool_mutex may be released and reacquired. +@return allocated block, never NULL */ UNIV_INTERN void* buf_buddy_alloc_low( @@ -46,10 +46,9 @@ buf_buddy_alloc_low( or BUF_BUDDY_SIZES */ ibool* lru, /*!< in: pointer to a variable that will be assigned TRUE if storage was allocated from the LRU list - and buf_pool_mutex was temporarily released, - or NULL if the LRU list should not be used */ + and buf_pool_mutex was temporarily released */ ibool have_page_hash_mutex) - __attribute__((malloc)); + __attribute__((malloc, nonnull)); /**********************************************************************//** Deallocate a block. */ @@ -76,6 +75,8 @@ buf_buddy_get_slot( ulint i; ulint s; + ut_ad(size >= PAGE_ZIP_MIN_SIZE); + for (i = 0, s = BUF_BUDDY_LOW; s < size; i++, s <<= 1) { } @@ -86,27 +87,26 @@ buf_buddy_get_slot( /**********************************************************************//** Allocate a block. The thread calling this function must hold buf_pool_mutex and must not hold buf_pool_zip_mutex or any -block->mutex. The buf_pool_mutex may only be released and reacquired -if lru != NULL. This function should only be used for allocating -compressed page frames or control blocks (buf_page_t). Allocated -control blocks must be properly initialized immediately after -buf_buddy_alloc() has returned the memory, before releasing -buf_pool_mutex. -@return allocated block, possibly NULL if lru == NULL */ +block->mutex. The buf_pool_mutex may be released and reacquired. +This function should only be used for allocating compressed page frames. +@return allocated block, never NULL */ UNIV_INLINE void* buf_buddy_alloc( /*============*/ - ulint size, /*!< in: block size, up to UNIV_PAGE_SIZE */ + ulint size, /*!< in: compressed page size + (between PAGE_ZIP_MIN_SIZE and UNIV_PAGE_SIZE) */ ibool* lru, /*!< in: pointer to a variable that will be assigned TRUE if storage was allocated from the LRU list - and buf_pool_mutex was temporarily released, - or NULL if the LRU list should not be used */ + and buf_pool_mutex was temporarily released */ ibool have_page_hash_mutex) { //ut_ad(buf_pool_mutex_own()); + ut_ad(ut_is_2pow(size)); + ut_ad(size >= PAGE_ZIP_MIN_SIZE); + ut_ad(size <= UNIV_PAGE_SIZE); - return(buf_buddy_alloc_low(buf_buddy_get_slot(size), lru, have_page_hash_mutex)); + return((byte*) buf_buddy_alloc_low(buf_buddy_get_slot(size), lru, have_page_hash_mutex)); } /**********************************************************************//** @@ -121,6 +121,9 @@ buf_buddy_free( ibool have_page_hash_mutex) { //ut_ad(buf_pool_mutex_own()); + ut_ad(ut_is_2pow(size)); + ut_ad(size >= PAGE_ZIP_MIN_SIZE); + ut_ad(size <= UNIV_PAGE_SIZE); if (!have_page_hash_mutex) { mutex_enter(&LRU_list_mutex); diff --git a/include/buf0buf.h b/include/buf0buf.h index bc0e9170281..838dd7f3900 100644 --- a/include/buf0buf.h +++ b/include/buf0buf.h @@ -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 @@ -36,12 +36,13 @@ Created 11/5/1995 Heikki Tuuri #include "ut0rbt.h" #ifndef UNIV_HOTBACKUP #include "os0proc.h" -#include "srv0srv.h" /** @name Modes for buf_page_get_gen */ /* @{ */ #define BUF_GET 10 /*!< get always */ #define BUF_GET_IF_IN_POOL 11 /*!< get if in pool */ +#define BUF_PEEK_IF_IN_POOL 12 /*!< get if in pool, do not make + the block young in the LRU list */ #define BUF_GET_NO_LATCH 14 /*!< get and bufferfix, but set no latch; we have separated this case, because @@ -140,12 +141,6 @@ buf_relocate( BUF_BLOCK_ZIP_DIRTY or BUF_BLOCK_ZIP_PAGE */ buf_page_t* dpage) /*!< in/out: destination control block */ __attribute__((nonnull)); -/********************************************************************//** -Resizes the buffer pool. */ -UNIV_INTERN -void -buf_pool_resize(void); -/*=================*/ /*********************************************************************//** Gets the current size of buffer buf_pool in bytes. @return size in bytes */ @@ -161,6 +156,23 @@ UNIV_INLINE ib_uint64_t buf_pool_get_oldest_modification(void); /*==================================*/ +/********************************************************************//** +Allocates a buf_page_t descriptor. This function must succeed. In case +of failure we assert in this function. */ +UNIV_INLINE +buf_page_t* +buf_page_alloc_descriptor(void) +/*===========================*/ + __attribute__((malloc)); +/********************************************************************//** +Free a buf_page_t descriptor. */ +UNIV_INLINE +void +buf_page_free_descriptor( +/*=====================*/ + buf_page_t* bpage) /*!< in: bpage descriptor to free. */ + __attribute__((nonnull)); + /********************************************************************//** Allocates a buffer block. @return own: the allocated block, in state BUF_BLOCK_MEMORY */ @@ -285,7 +297,7 @@ buf_page_get_gen( ulint rw_latch,/*!< in: RW_S_LATCH, RW_X_LATCH, RW_NO_LATCH */ buf_block_t* guess, /*!< in: guessed block or NULL */ ulint mode, /*!< in: BUF_GET, BUF_GET_IF_IN_POOL, - BUF_GET_NO_LATCH */ + BUF_PEEK_IF_IN_POOL, BUF_GET_NO_LATCH */ const char* file, /*!< in: file name */ ulint line, /*!< in: line where called */ mtr_t* mtr); /*!< in: mini-transaction */ @@ -415,6 +427,18 @@ buf_block_get_freed_page_clock( __attribute__((pure)); /********************************************************************//** +Tells if a block is still close enough to the MRU end of the LRU list +meaning that it is not in danger of getting evicted and also implying +that it has been accessed recently. +Note that this is for heuristics only and does not reserve buffer pool +mutex. +@return TRUE if block is close to MRU end of LRU */ +UNIV_INLINE +ibool +buf_page_peek_if_young( +/*===================*/ + const buf_page_t* bpage); /*!< in: block */ +/********************************************************************//** Recommends a move of a block to the start of the LRU list if there is danger of dropping from the buffer pool. NOTE: does not reserve the buffer pool mutex. @@ -466,6 +490,31 @@ buf_block_get_modify_clock( #else /* !UNIV_HOTBACKUP */ # define buf_block_modify_clock_inc(block) ((void) 0) #endif /* !UNIV_HOTBACKUP */ +/*******************************************************************//** +Increments the bufferfix count. */ +UNIV_INLINE +void +buf_block_buf_fix_inc_func( +/*=======================*/ +#ifdef UNIV_SYNC_DEBUG + const char* file, /*!< in: file name */ + ulint line, /*!< in: line */ +#endif /* UNIV_SYNC_DEBUG */ + buf_block_t* block) /*!< in/out: block to bufferfix */ + __attribute__((nonnull)); +#ifdef UNIV_SYNC_DEBUG +/** Increments the bufferfix count. +@param b in/out: block to bufferfix +@param f in: file name where requested +@param l in: line number where requested */ +# define buf_block_buf_fix_inc(b,f,l) buf_block_buf_fix_inc_func(f,l,b) +#else /* UNIV_SYNC_DEBUG */ +/** Increments the bufferfix count. +@param b in/out: block to bufferfix +@param f in: file name where requested +@param l in: line number where requested */ +# define buf_block_buf_fix_inc(b,f,l) buf_block_buf_fix_inc_func(b) +#endif /* UNIV_SYNC_DEBUG */ /********************************************************************//** Calculates a page checksum which is stored to the page when it is written to a file. Note that we must be careful to calculate the same value @@ -986,8 +1035,7 @@ UNIV_INTERN void buf_page_io_complete( /*=================*/ - buf_page_t* bpage, /*!< in: pointer to the block in question */ - trx_t* trx); + buf_page_t* bpage); /*!< in: pointer to the block in question */ /********************************************************************//** Calculates a folded value of a file page address to use in the page hash table. @@ -1301,10 +1349,7 @@ struct buf_block_struct{ /**********************************************************************//** Compute the hash fold value for blocks in buf_pool->zip_hash. */ /* @{ */ -/* the fold should be relative when srv_buffer_pool_shm_key is enabled */ -#define BUF_POOL_ZIP_FOLD_PTR(ptr) (!srv_buffer_pool_shm_key\ - ?((ulint) (ptr) / UNIV_PAGE_SIZE)\ - :((ulint) ((byte*)ptr - (byte*)(buf_pool->chunks->blocks->frame)) / UNIV_PAGE_SIZE)) +#define BUF_POOL_ZIP_FOLD_PTR(ptr) ((ulint) (ptr) / UNIV_PAGE_SIZE) #define BUF_POOL_ZIP_FOLD(b) BUF_POOL_ZIP_FOLD_PTR((b)->frame) #define BUF_POOL_ZIP_FOLD_BPAGE(b) BUF_POOL_ZIP_FOLD((buf_block_t*) (b)) /* @} */ @@ -1330,6 +1375,8 @@ struct buf_pool_stat_struct{ ulint n_pages_written;/*!< number write operations */ ulint n_pages_created;/*!< number of pages created in the pool with no read */ + ulint n_ra_pages_read_rnd;/*!< number of pages read in + as part of random read ahead */ ulint n_ra_pages_read;/*!< number of pages read in as part of read ahead */ ulint n_ra_pages_evicted;/*!< number of read ahead @@ -1453,8 +1500,10 @@ struct buf_pool_struct{ frames and buf_page_t descriptors of blocks that exist in the buffer pool only in compressed form. */ /* @{ */ +#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG UT_LIST_BASE_NODE_T(buf_page_t) zip_clean; /*!< unmodified compressed pages */ +#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */ UT_LIST_BASE_NODE_T(buf_page_t) zip_free[BUF_BUDDY_SIZES_MAX]; /*!< buddy free lists */ //#if BUF_BUDDY_HIGH != UNIV_PAGE_SIZE @@ -1486,8 +1535,8 @@ Use these instead of accessing buf_pool_mutex directly. */ /** Test if buf_pool_mutex is owned. */ #define buf_pool_mutex_own() mutex_own(&buf_pool_mutex) /** Acquire the buffer pool mutex. */ +/* the buf_pool_mutex is changed the latch order */ #define buf_pool_mutex_enter() do { \ - ut_ad(!mutex_own(&buf_pool_zip_mutex)); \ mutex_enter(&buf_pool_mutex); \ } while (0) diff --git a/include/buf0buf.ic b/include/buf0buf.ic index 2cb0d8ef497..a081d6a34c0 100644 --- a/include/buf0buf.ic +++ b/include/buf0buf.ic @@ -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. Copyright (c) 2008, Google Inc. Portions of this file contain modifications contributed and copyrighted by @@ -61,6 +61,27 @@ buf_block_get_freed_page_clock( return(buf_page_get_freed_page_clock(&block->page)); } +/********************************************************************//** +Tells if a block is still close enough to the MRU end of the LRU list +meaning that it is not in danger of getting evicted and also implying +that it has been accessed recently. +Note that this is for heuristics only and does not reserve buffer pool +mutex. +@return TRUE if block is close to MRU end of LRU */ +UNIV_INLINE +ibool +buf_page_peek_if_young( +/*===================*/ + const buf_page_t* bpage) /*!< in: block */ +{ + /* FIXME: bpage->freed_page_clock is 31 bits */ + return((buf_pool->freed_page_clock & ((1UL << 31) - 1)) + < ((ulint) bpage->freed_page_clock + + (buf_pool->curr_size + * (BUF_LRU_OLD_RATIO_DIV - buf_LRU_old_ratio) + / (BUF_LRU_OLD_RATIO_DIV * 4)))); +} + /********************************************************************//** Recommends a move of a block to the start of the LRU list if there is danger of dropping from the buffer pool. NOTE: does not reserve the buffer pool @@ -89,12 +110,7 @@ buf_page_peek_if_too_old( buf_pool->stat.n_pages_not_made_young++; return(FALSE); } else { - /* FIXME: bpage->freed_page_clock is 31 bits */ - return((buf_pool->freed_page_clock & ((1UL << 31) - 1)) - > ((ulint) bpage->freed_page_clock - + (buf_pool->curr_size - * (BUF_LRU_OLD_RATIO_DIV - buf_LRU_old_ratio) - / (BUF_LRU_OLD_RATIO_DIV * 4)))); + return(!buf_page_peek_if_young(bpage)); } } @@ -753,6 +769,35 @@ buf_block_get_lock_hash_val( return(block->lock_hash_val); } +/********************************************************************//** +Allocates a buf_page_t descriptor. This function must succeed. In case +of failure we assert in this function. +@return: the allocated descriptor. */ +UNIV_INLINE +buf_page_t* +buf_page_alloc_descriptor(void) +/*===========================*/ +{ + buf_page_t* bpage; + + bpage = (buf_page_t*) ut_malloc(sizeof *bpage); + ut_d(memset(bpage, 0, sizeof *bpage)); + UNIV_MEM_ALLOC(bpage, sizeof *bpage); + + return(bpage); +} + +/********************************************************************//** +Free a buf_page_t descriptor. */ +UNIV_INLINE +void +buf_page_free_descriptor( +/*=====================*/ + buf_page_t* bpage) /*!< in: bpage descriptor to free. */ +{ + ut_free(bpage); +} + /********************************************************************//** Allocates a buffer block. @return own: the allocated block, in state BUF_BLOCK_MEMORY */ @@ -910,19 +955,6 @@ buf_block_buf_fix_inc_func( block->page.buf_fix_count++; } -#ifdef UNIV_SYNC_DEBUG -/** Increments the bufferfix count. -@param b in/out: block to bufferfix -@param f in: file name where requested -@param l in: line number where requested */ -# define buf_block_buf_fix_inc(b,f,l) buf_block_buf_fix_inc_func(f,l,b) -#else /* UNIV_SYNC_DEBUG */ -/** Increments the bufferfix count. -@param b in/out: block to bufferfix -@param f in: file name where requested -@param l in: line number where requested */ -# define buf_block_buf_fix_inc(b,f,l) buf_block_buf_fix_inc_func(b) -#endif /* UNIV_SYNC_DEBUG */ /*******************************************************************//** Decrements the bufferfix count. */ @@ -1119,7 +1151,7 @@ buf_block_dbg_add_level( where we have acquired latch */ ulint level) /*!< in: latching order level */ { - sync_thread_add_level(&block->lock, level); + sync_thread_add_level(&block->lock, level, FALSE); } #endif /* UNIV_SYNC_DEBUG */ #endif /* !UNIV_HOTBACKUP */ diff --git a/include/buf0lru.h b/include/buf0lru.h index fe7c067dfb7..8abebfb675c 100644 --- a/include/buf0lru.h +++ b/include/buf0lru.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 @@ -30,18 +30,6 @@ Created 11/5/1995 Heikki Tuuri #include "ut0byte.h" #include "buf0types.h" -/** The return type of buf_LRU_free_block() */ -enum buf_lru_free_block_status { - /** freed */ - BUF_LRU_FREED = 0, - /** not freed because the caller asked to remove the - uncompressed frame but the control block cannot be - relocated */ - BUF_LRU_CANNOT_RELOCATE, - /** not freed because of some other reason */ - BUF_LRU_NOT_FREED -}; - /******************************************************************//** Tries to remove LRU flushed blocks from the end of the LRU list and put them to the free list. This is beneficial for the efficiency of the insert buffer @@ -91,6 +79,7 @@ void buf_LRU_mark_space_was_deleted( /*===========================*/ ulint id); /*!< in: space id */ +#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG /********************************************************************//** Insert a compressed block into buf_pool->zip_clean in the LRU order. */ UNIV_INTERN @@ -98,22 +87,22 @@ void buf_LRU_insert_zip_clean( /*=====================*/ buf_page_t* bpage); /*!< in: pointer to the block in question */ +#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */ /******************************************************************//** Try to free a block. If bpage is a descriptor of a compressed-only page, the descriptor object will be freed as well. -NOTE: If this function returns BUF_LRU_FREED, it will temporarily +NOTE: If this function returns TRUE, it will temporarily release buf_pool_mutex. Furthermore, the page frame will no longer be accessible via bpage. The caller must hold buf_pool_mutex and buf_page_get_mutex(bpage) and release these two mutexes after the call. No other buf_page_get_mutex() may be held when calling this function. -@return BUF_LRU_FREED if freed, BUF_LRU_CANNOT_RELOCATE or -BUF_LRU_NOT_FREED otherwise. */ +@return TRUE if freed, FALSE otherwise. */ UNIV_INTERN -enum buf_lru_free_block_status +ibool buf_LRU_free_block( /*===============*/ buf_page_t* bpage, /*!< in: block to be freed */ diff --git a/include/buf0types.h b/include/buf0types.h index ce3e5ecc9c5..9dd847bdaca 100644 --- a/include/buf0types.h +++ b/include/buf0types.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 @@ -26,6 +26,8 @@ Created 11/17/1995 Heikki Tuuri #ifndef buf0types_h #define buf0types_h +#include "page0types.h" + /** Buffer page (uncompressed or compressed) */ typedef struct buf_page_struct buf_page_t; /** Buffer block for which an uncompressed page exists */ @@ -58,17 +60,10 @@ enum buf_io_fix { /** Parameters of binary buddy system for compressed pages (buf0buddy.h) */ /* @{ */ -#if UNIV_WORD_SIZE <= 4 /* 32-bit system */ -/** Base-2 logarithm of the smallest buddy block size */ -# define BUF_BUDDY_LOW_SHIFT 6 -#else /* 64-bit system */ -/** Base-2 logarithm of the smallest buddy block size */ -# define BUF_BUDDY_LOW_SHIFT 7 -#endif +#define BUF_BUDDY_LOW_SHIFT PAGE_ZIP_MIN_SIZE_SHIFT + #define BUF_BUDDY_LOW (1 << BUF_BUDDY_LOW_SHIFT) - /*!< minimum block size in the binary - buddy system; must be at least - sizeof(buf_page_t) */ + #define BUF_BUDDY_SIZES (UNIV_PAGE_SIZE_SHIFT - BUF_BUDDY_LOW_SHIFT) #define BUF_BUDDY_SIZES_MAX (UNIV_PAGE_SIZE_SHIFT_MAX - BUF_BUDDY_LOW_SHIFT) /*!< number of buddy sizes */ diff --git a/include/dict0mem.h b/include/dict0mem.h index f47293bedf6..3554274847c 100644 --- a/include/dict0mem.h +++ b/include/dict0mem.h @@ -340,6 +340,13 @@ struct dict_index_struct{ index, or 0 if the index existed when InnoDB was started up */ #endif /* !UNIV_HOTBACKUP */ +#ifdef UNIV_BLOB_DEBUG + mutex_t blobs_mutex; + /*!< mutex protecting blobs */ + void* blobs; /*!< map of (page_no,heap_no,field_no) + to first_blob_page_no; protected by + blobs_mutex; @see btr_blob_dbg_t */ +#endif /* UNIV_BLOB_DEBUG */ #ifdef UNIV_DEBUG ulint magic_n;/*!< magic number */ /** Value of dict_index_struct::magic_n */ diff --git a/include/fil0fil.h b/include/fil0fil.h index fbf8ca20db3..11c4cb4ba03 100644 --- a/include/fil0fil.h +++ b/include/fil0fil.h @@ -670,8 +670,9 @@ UNIV_INTERN void fil_flush( /*======*/ - ulint space_id); /*!< in: file space id (this can be a group of + ulint space_id, /*!< in: file space id (this can be a group of log files or a tablespace of the database) */ + ibool metadata); /**********************************************************************//** Flushes to disk writes in file spaces of the given type possibly cached by the OS. */ diff --git a/include/ha_prototypes.h b/include/ha_prototypes.h index 445d94eeabb..f42811e158d 100644 --- a/include/ha_prototypes.h +++ b/include/ha_prototypes.h @@ -276,4 +276,14 @@ thd_flush_log_at_trx_commit_session( /*================================*/ void* thd); +/******************************************************************//** +Returns true if innodb_expand_fast_index_creation is enabled for the current +session. +@return the value of the server's innodb_expand_fast_index_creation variable */ + +ibool +thd_expand_fast_index_creation( +/*==================*/ + void* thd); /*!< in: thread handle (THD*) */ + #endif diff --git a/include/hash0hash.h b/include/hash0hash.h index 492c767acc4..b17c21a45ef 100644 --- a/include/hash0hash.h +++ b/include/hash0hash.h @@ -49,28 +49,6 @@ hash_table_t* hash_create( /*========*/ ulint n); /*!< in: number of array cells */ - -/*************************************************************//** -*/ -UNIV_INTERN -ulint -hash_create_needed( -/*===============*/ - ulint n); - -UNIV_INTERN -void -hash_create_init( -/*=============*/ - hash_table_t* table, - ulint n); - -UNIV_INTERN -void -hash_create_reuse( -/*==============*/ - hash_table_t* table); - #ifndef UNIV_HOTBACKUP /*************************************************************//** Creates a mutex array to protect a hash table. */ @@ -350,33 +328,6 @@ do {\ }\ } while (0) -/********************************************************************//** -Align nodes with moving location.*/ -#define HASH_OFFSET(TABLE, NODE_TYPE, PTR_NAME, FADDR, FOFFSET, BOFFSET) \ -do {\ - ulint i2222;\ - ulint cell_count2222;\ -\ - cell_count2222 = hash_get_n_cells(TABLE);\ -\ - for (i2222 = 0; i2222 < cell_count2222; i2222++) {\ - NODE_TYPE* node2222;\ -\ - if ((TABLE)->array[i2222].node) \ - (TABLE)->array[i2222].node = (void*)((byte*)(TABLE)->array[i2222].node \ - + (((TABLE)->array[i2222].node > (void*)FADDR)?FOFFSET:BOFFSET));\ - node2222 = HASH_GET_FIRST((TABLE), i2222);\ -\ - while (node2222) {\ - if (node2222->PTR_NAME) \ - node2222->PTR_NAME = (void*)((byte*)(node2222->PTR_NAME) \ - + ((((void*)node2222->PTR_NAME) > (void*)FADDR)?FOFFSET:BOFFSET));\ -\ - node2222 = node2222->PTR_NAME;\ - }\ - }\ -} while (0) - /************************************************************//** Gets the mutex index for a fold value in a hash table. @return mutex number */ diff --git a/include/mtr0mtr.h b/include/mtr0mtr.h index bc3f1951be9..8a9ec8ea7f0 100644 --- a/include/mtr0mtr.h +++ b/include/mtr0mtr.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 @@ -213,16 +213,6 @@ ulint mtr_set_savepoint( /*==============*/ mtr_t* mtr); /*!< in: mtr */ -/**********************************************************//** -Releases the latches stored in an mtr memo down to a savepoint. -NOTE! The mtr must not have made changes to buffer pages after the -savepoint, as these can be handled only by mtr_commit. */ -UNIV_INTERN -void -mtr_rollback_to_savepoint( -/*======================*/ - mtr_t* mtr, /*!< in: mtr */ - ulint savepoint); /*!< in: savepoint */ #ifndef UNIV_HOTBACKUP /**********************************************************//** Releases the (index tree) s-latch stored in an mtr memo after a diff --git a/include/os0file.h b/include/os0file.h index 732e930517b..98cab5ef874 100644 --- a/include/os0file.h +++ b/include/os0file.h @@ -469,7 +469,8 @@ UNIV_INTERN ibool os_file_flush( /*==========*/ - os_file_t file); /*!< in, own: handle to a file */ + os_file_t file, /*!< in, own: handle to a file */ + ibool metadata); /***********************************************************************//** Retrieves the last error number if an error occurs in a file io function. The number should be retrieved before any other OS calls (because they may diff --git a/include/os0proc.h b/include/os0proc.h index 582cef6f803..fd46bd7db87 100644 --- a/include/os0proc.h +++ b/include/os0proc.h @@ -32,11 +32,6 @@ Created 9/30/1995 Heikki Tuuri #ifdef UNIV_LINUX #include #include -#else -# if defined HAVE_SYS_IPC_H && HAVE_SYS_SHM_H -#include -#include -# endif #endif typedef void* os_process_t; @@ -75,29 +70,6 @@ os_mem_free_large( ulint size); /*!< in: size returned by os_mem_alloc_large() */ - -/****************************************************************//** -Allocates or attaches and reuses shared memory segment. -The content is not cleared automatically. -@return allocated memory */ -UNIV_INTERN -void* -os_shm_alloc( -/*=========*/ - ulint* n, /*!< in/out: number of bytes */ - uint key, - ibool* is_new); - -/****************************************************************//** -Detach shared memory segment. */ -UNIV_INTERN -void -os_shm_free( -/*========*/ - void *ptr, /*!< in: pointer returned by - os_shm_alloc() */ - ulint size); /*!< in: size returned by - os_shm_alloc() */ #ifndef UNIV_NONINL #include "os0proc.ic" #endif diff --git a/include/page0cur.ic b/include/page0cur.ic index 3520677dfb3..81474fa35f5 100644 --- a/include/page0cur.ic +++ b/include/page0cur.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 @@ -27,6 +27,8 @@ Created 10/4/1994 Heikki Tuuri #include "buf0types.h" #ifdef UNIV_DEBUG +# include "rem0cmp.h" + /*********************************************************//** Gets pointer to the page frame where the cursor is positioned. @return page */ @@ -268,6 +270,7 @@ page_cur_tuple_insert( index, rec, offsets, mtr); } + ut_ad(!rec || !cmp_dtuple_rec(tuple, rec, offsets)); mem_heap_free(heap); return(rec); } diff --git a/include/page0page.h b/include/page0page.h index 863b388b340..dd7026c28f2 100644 --- a/include/page0page.h +++ b/include/page0page.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 @@ -284,16 +284,42 @@ page_get_supremum_offset( const page_t* page); /*!< in: page which must have record(s) */ #define page_get_infimum_rec(page) ((page) + page_get_infimum_offset(page)) #define page_get_supremum_rec(page) ((page) + page_get_supremum_offset(page)) + /************************************************************//** -Returns the middle record of record list. If there are an even number -of records in the list, returns the first record of upper half-list. -@return middle record */ +Returns the nth record of the record list. +This is the inverse function of page_rec_get_n_recs_before(). +@return nth record */ UNIV_INTERN +const rec_t* +page_rec_get_nth_const( +/*===================*/ + const page_t* page, /*!< in: page */ + ulint nth) /*!< in: nth record */ + __attribute__((nonnull, warn_unused_result)); +/************************************************************//** +Returns the nth record of the record list. +This is the inverse function of page_rec_get_n_recs_before(). +@return nth record */ +UNIV_INLINE +rec_t* +page_rec_get_nth( +/*=============*/ + page_t* page, /*< in: page */ + ulint nth) /*!< in: nth record */ + __attribute__((nonnull, warn_unused_result)); + +#ifndef UNIV_HOTBACKUP +/************************************************************//** +Returns the middle record of the records on the page. If there is an +even number of records in the list, returns the first record of the +upper half-list. +@return middle record */ +UNIV_INLINE rec_t* page_get_middle_rec( /*================*/ - page_t* page); /*!< in: page */ -#ifndef UNIV_HOTBACKUP + page_t* page) /*!< in: page */ + __attribute__((nonnull, warn_unused_result)); /*************************************************************//** Compares a data tuple to a physical record. Differs from the function cmp_dtuple_rec_with_match in the way that the record must reside on an @@ -348,6 +374,7 @@ page_get_n_recs( /***************************************************************//** Returns the number of records before the given record in chain. The number includes infimum and supremum records. +This is the inverse function of page_rec_get_nth(). @return number of records */ UNIV_INTERN ulint diff --git a/include/page0page.ic b/include/page0page.ic index 9e571c6be1e..b22678a2e9f 100644 --- a/include/page0page.ic +++ b/include/page0page.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 @@ -423,7 +423,37 @@ page_rec_is_infimum( return(page_rec_is_infimum_low(page_offset(rec))); } +/************************************************************//** +Returns the nth record of the record list. +This is the inverse function of page_rec_get_n_recs_before(). +@return nth record */ +UNIV_INLINE +rec_t* +page_rec_get_nth( +/*=============*/ + page_t* page, /*!< in: page */ + ulint nth) /*!< in: nth record */ +{ + return((rec_t*) page_rec_get_nth_const(page, nth)); +} + #ifndef UNIV_HOTBACKUP +/************************************************************//** +Returns the middle record of the records on the page. If there is an +even number of records in the list, returns the first record of the +upper half-list. +@return middle record */ +UNIV_INLINE +rec_t* +page_get_middle_rec( +/*================*/ + page_t* page) /*!< in: page */ +{ + ulint middle = (page_get_n_recs(page) + PAGE_HEAP_NO_USER_LOW) / 2; + + return(page_rec_get_nth(page, middle)); +} + /*************************************************************//** Compares a data tuple to a physical record. Differs from the function cmp_dtuple_rec_with_match in the way that the record must reside on an diff --git a/include/page0zip.h b/include/page0zip.h index 4d37302ed20..fe3d2e52e0b 100644 --- a/include/page0zip.h +++ b/include/page0zip.h @@ -420,7 +420,7 @@ page_zip_copy_recs( const page_t* src, /*!< in: page */ dict_index_t* index, /*!< in: index of the B-tree */ mtr_t* mtr) /*!< in: mini-transaction */ - __attribute__((nonnull(1,2,3,4))); + __attribute__((nonnull)); #endif /* !UNIV_HOTBACKUP */ /**********************************************************************//** diff --git a/include/rem0rec.h b/include/rem0rec.h index 17d08afabb9..06de23be757 100644 --- a/include/rem0rec.h +++ b/include/rem0rec.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 @@ -480,6 +480,18 @@ ulint rec_offs_any_extern( /*================*/ const ulint* offsets);/*!< in: array returned by rec_get_offsets() */ +#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG +/******************************************************//** +Determine if the offsets are for a record containing null BLOB pointers. +@return first field containing a null BLOB pointer, or NULL if none found */ +UNIV_INLINE +const byte* +rec_offs_any_null_extern( +/*=====================*/ + const rec_t* rec, /*!< in: record */ + const ulint* offsets) /*!< in: rec_get_offsets(rec) */ + __attribute__((nonnull, warn_unused_result)); +#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ /******************************************************//** Returns nonzero if the extern bit is set in nth field of rec. @return nonzero if externally stored */ diff --git a/include/rem0rec.ic b/include/rem0rec.ic index 8e5bd9a7fcd..7cff36fee6c 100644 --- a/include/rem0rec.ic +++ b/include/rem0rec.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 @@ -26,6 +26,7 @@ Created 5/30/1994 Heikki Tuuri #include "mach0data.h" #include "ut0byte.h" #include "dict0dict.h" +#include "btr0types.h" /* Compact flag ORed to the extra size returned by rec_get_offsets() */ #define REC_OFFS_COMPACT ((ulint) 1 << 31) @@ -1087,6 +1088,44 @@ rec_offs_any_extern( return(UNIV_UNLIKELY(*rec_offs_base(offsets) & REC_OFFS_EXTERNAL)); } +#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG +/******************************************************//** +Determine if the offsets are for a record containing null BLOB pointers. +@return first field containing a null BLOB pointer, or NULL if none found */ +UNIV_INLINE +const byte* +rec_offs_any_null_extern( +/*=====================*/ + const rec_t* rec, /*!< in: record */ + const ulint* offsets) /*!< in: rec_get_offsets(rec) */ +{ + ulint i; + ut_ad(rec_offs_validate(rec, NULL, offsets)); + + if (!rec_offs_any_extern(offsets)) { + return(NULL); + } + + for (i = 0; i < rec_offs_n_fields(offsets); i++) { + if (rec_offs_nth_extern(offsets, i)) { + ulint len; + const byte* field + = rec_get_nth_field(rec, offsets, i, &len); + + ut_a(len >= BTR_EXTERN_FIELD_REF_SIZE); + if (!memcmp(field + len + - BTR_EXTERN_FIELD_REF_SIZE, + field_ref_zero, + BTR_EXTERN_FIELD_REF_SIZE)) { + return(field); + } + } + } + + return(NULL); +} +#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ + /******************************************************//** Returns nonzero if the extern bit is set in nth field of rec. @return nonzero if externally stored */ diff --git a/include/row0row.h b/include/row0row.h index 723b7b53395..36fb26482ce 100644 --- a/include/row0row.h +++ b/include/row0row.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 @@ -38,16 +38,16 @@ Created 4/20/1996 Heikki Tuuri #include "btr0types.h" /*********************************************************************//** -Gets the offset of the trx id field, in bytes relative to the origin of +Gets the offset of the DB_TRX_ID field, in bytes relative to the origin of a clustered index record. @return offset of DATA_TRX_ID */ -UNIV_INTERN +UNIV_INLINE ulint row_get_trx_id_offset( /*==================*/ - const rec_t* rec, /*!< in: record */ - dict_index_t* index, /*!< in: clustered index */ - const ulint* offsets);/*!< in: rec_get_offsets(rec, index) */ + const dict_index_t* index, /*!< in: clustered index */ + const ulint* offsets)/*!< in: record offsets */ + __attribute__((nonnull, warn_unused_result)); /*********************************************************************//** Reads the trx id field from a clustered index record. @return value of the field */ @@ -55,9 +55,10 @@ UNIV_INLINE trx_id_t row_get_rec_trx_id( /*===============*/ - const rec_t* rec, /*!< in: record */ - dict_index_t* index, /*!< in: clustered index */ - const ulint* offsets);/*!< in: rec_get_offsets(rec, index) */ + const rec_t* rec, /*!< in: record */ + const dict_index_t* index, /*!< in: clustered index */ + const ulint* offsets)/*!< in: rec_get_offsets(rec, index) */ + __attribute__((nonnull, warn_unused_result)); /*********************************************************************//** Reads the roll pointer field from a clustered index record. @return value of the field */ @@ -65,9 +66,10 @@ UNIV_INLINE roll_ptr_t row_get_rec_roll_ptr( /*=================*/ - const rec_t* rec, /*!< in: record */ - dict_index_t* index, /*!< in: clustered index */ - const ulint* offsets);/*!< in: rec_get_offsets(rec, index) */ + const rec_t* rec, /*!< in: record */ + const dict_index_t* index, /*!< in: clustered index */ + const ulint* offsets)/*!< in: rec_get_offsets(rec, index) */ + __attribute__((nonnull, warn_unused_result)); /*****************************************************************//** When an insert or purge to a table is performed, this function builds the entry to be inserted into or purged from an index on the table. diff --git a/include/row0row.ic b/include/row0row.ic index 05c007641af..0b9ca982af8 100644 --- a/include/row0row.ic +++ b/include/row0row.ic @@ -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 @@ -27,6 +27,33 @@ Created 4/20/1996 Heikki Tuuri #include "rem0rec.h" #include "trx0undo.h" +/*********************************************************************//** +Gets the offset of the DB_TRX_ID field, in bytes relative to the origin of +a clustered index record. +@return offset of DATA_TRX_ID */ +UNIV_INLINE +ulint +row_get_trx_id_offset( +/*==================*/ + const dict_index_t* index, /*!< in: clustered index */ + const ulint* offsets)/*!< in: record offsets */ +{ + ulint pos; + ulint offset; + ulint len; + + ut_ad(dict_index_is_clust(index)); + ut_ad(rec_offs_validate(NULL, index, offsets)); + + pos = dict_index_get_sys_col_pos(index, DATA_TRX_ID); + + offset = rec_get_nth_field_offs(offsets, pos, &len); + + ut_ad(len == DATA_TRX_ID_LEN); + + return(offset); +} + /*********************************************************************//** Reads the trx id field from a clustered index record. @return value of the field */ @@ -34,9 +61,9 @@ UNIV_INLINE trx_id_t row_get_rec_trx_id( /*===============*/ - const rec_t* rec, /*!< in: record */ - dict_index_t* index, /*!< in: clustered index */ - const ulint* offsets)/*!< in: rec_get_offsets(rec, index) */ + const rec_t* rec, /*!< in: record */ + const dict_index_t* index, /*!< in: clustered index */ + const ulint* offsets)/*!< in: rec_get_offsets(rec, index) */ { ulint offset; @@ -46,7 +73,7 @@ row_get_rec_trx_id( offset = index->trx_id_offset; if (!offset) { - offset = row_get_trx_id_offset(rec, index, offsets); + offset = row_get_trx_id_offset(index, offsets); } return(trx_read_trx_id(rec + offset)); @@ -59,9 +86,9 @@ UNIV_INLINE roll_ptr_t row_get_rec_roll_ptr( /*=================*/ - const rec_t* rec, /*!< in: record */ - dict_index_t* index, /*!< in: clustered index */ - const ulint* offsets)/*!< in: rec_get_offsets(rec, index) */ + const rec_t* rec, /*!< in: record */ + const dict_index_t* index, /*!< in: clustered index */ + const ulint* offsets)/*!< in: rec_get_offsets(rec, index) */ { ulint offset; @@ -71,7 +98,7 @@ row_get_rec_roll_ptr( offset = index->trx_id_offset; if (!offset) { - offset = row_get_trx_id_offset(rec, index, offsets); + offset = row_get_trx_id_offset(index, offsets); } return(trx_read_roll_ptr(rec + offset + DATA_TRX_ID_LEN)); diff --git a/include/row0upd.ic b/include/row0upd.ic index 18e22f1eca9..0894ed373b0 100644 --- a/include/row0upd.ic +++ b/include/row0upd.ic @@ -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 @@ -171,7 +171,7 @@ row_upd_rec_sys_fields( ulint offset = index->trx_id_offset; if (!offset) { - offset = row_get_trx_id_offset(rec, index, offsets); + offset = row_get_trx_id_offset(index, offsets); } #if DATA_TRX_ID + 1 != DATA_ROLL_PTR diff --git a/include/srv0srv.h b/include/srv0srv.h index 13bf0b5b9ea..8a4235ee605 100644 --- a/include/srv0srv.h +++ b/include/srv0srv.h @@ -159,13 +159,10 @@ extern ulint srv_buf_pool_curr_size; /*!< current size in bytes */ extern ulint srv_mem_pool_size; extern ulint srv_lock_table_size; -extern uint srv_buffer_pool_shm_key; -extern ibool srv_buffer_pool_shm_is_reused; -extern ibool srv_buffer_pool_shm_checksum; - extern ibool srv_thread_concurrency_timer_based; extern ulint srv_n_file_io_threads; +extern my_bool srv_random_read_ahead; extern ulong srv_read_ahead_threshold; extern ulint srv_n_read_io_threads; extern ulint srv_n_write_io_threads; @@ -288,6 +285,7 @@ extern ibool srv_print_latch_waits; extern ulint srv_activity_count; extern ulint srv_fatal_semaphore_wait_threshold; extern ulint srv_dml_needed_delay; +extern lint srv_kill_idle_transaction; extern mutex_t* kernel_mutex_temp;/* mutex protecting the server, trx structs, query threads, and lock table: we allocate @@ -351,6 +349,9 @@ extern ulint srv_buf_pool_reads; /** Time in seconds between automatic buffer pool dumps */ extern uint srv_auto_lru_dump; +/** Whether startup should be blocked until buffer pool is fully restored */ +extern ibool srv_blocking_lru_restore; + /** Status variables to be passed to MySQL */ typedef struct export_var_struct export_struc; @@ -694,6 +695,7 @@ struct export_var_struct{ ulint innodb_buffer_pool_wait_free; /*!< srv_buf_pool_wait_free */ ulint innodb_buffer_pool_pages_flushed; /*!< srv_buf_pool_flushed */ ulint innodb_buffer_pool_write_requests;/*!< srv_buf_pool_write_requests */ + ulint innodb_buffer_pool_read_ahead_rnd;/*!< srv_read_ahead_rnd */ ulint innodb_buffer_pool_read_ahead; /*!< srv_read_ahead */ ulint innodb_buffer_pool_read_ahead_evicted;/*!< srv_read_ahead evicted*/ ulint innodb_deadlocks; /* ??? */ diff --git a/include/sync0arr.h b/include/sync0arr.h index 5f1280f5e28..6e931346238 100644 --- a/include/sync0arr.h +++ b/include/sync0arr.h @@ -115,8 +115,11 @@ Prints warnings of long semaphore waits to stderr. @return TRUE if fatal semaphore wait threshold was exceeded */ UNIV_INTERN ibool -sync_array_print_long_waits(void); -/*=============================*/ +sync_array_print_long_waits( +/*========================*/ + os_thread_id_t* waiter, /*!< out: longest waiting thread */ + const void** sema) /*!< out: longest-waited-for semaphore */ + __attribute__((nonnull)); /********************************************************************//** Validates the integrity of the wait array. Checks that the number of reserved cells equals the count variable. */ diff --git a/include/sync0rw.ic b/include/sync0rw.ic index 7116f1b7c9b..485a63a1b18 100644 --- a/include/sync0rw.ic +++ b/include/sync0rw.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. Copyright (c) 2008, Google Inc. Portions of this file contain modifications contributed and copyrighted by @@ -603,16 +603,16 @@ rw_lock_x_unlock_direct( ut_ad((lock->lock_word % X_LOCK_DECR) == 0); -#ifdef UNIV_SYNC_DEBUG - rw_lock_remove_debug_info(lock, 0, RW_LOCK_EX); -#endif - if (lock->lock_word == 0) { lock->recursive = FALSE; UNIV_MEM_INVALID(&lock->writer_thread, sizeof lock->writer_thread); } +#ifdef UNIV_SYNC_DEBUG + rw_lock_remove_debug_info(lock, 0, RW_LOCK_EX); +#endif + lock->lock_word += X_LOCK_DECR; ut_ad(!lock->waiters); diff --git a/include/sync0sync.h b/include/sync0sync.h index f2ff83101ab..8b9a075e875 100644 --- a/include/sync0sync.h +++ b/include/sync0sync.h @@ -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. Copyright (c) 2008, Google Inc. Portions of this file contain modifications contributed and copyrighted by @@ -219,8 +219,10 @@ void sync_thread_add_level( /*==================*/ void* latch, /*!< in: pointer to a mutex or an rw-lock */ - ulint level); /*!< in: level in the latching order; if + ulint level, /*!< in: level in the latching order; if SYNC_LEVEL_VARYING, nothing is done */ + ibool relock) /*!< in: TRUE if re-entering an x-lock */ + __attribute__((nonnull)); /******************************************************************//** Removes a latch from the thread level array if it is found there. @return TRUE if found in the array; it is no error if the latch is diff --git a/include/trx0sys.h b/include/trx0sys.h index 2637189f37e..eafa1ab6409 100644 --- a/include/trx0sys.h +++ b/include/trx0sys.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 @@ -317,6 +317,17 @@ ibool trx_in_trx_list( /*============*/ trx_t* in_trx);/*!< in: trx */ +#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG +/***********************************************************//** +Assert that a transaction has been recovered. +@return TRUE */ +UNIV_INLINE +ibool +trx_assert_recovered( +/*=================*/ + trx_id_t trx_id) /*!< in: transaction identifier */ + __attribute__((warn_unused_result)); +#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ /*****************************************************************//** Updates the offset information about the end of the MySQL binlog entry which corresponds to the transaction just being committed. In a MySQL diff --git a/include/trx0sys.ic b/include/trx0sys.ic index 5e0f07c8b9d..234fc0b92e9 100644 --- a/include/trx0sys.ic +++ b/include/trx0sys.ic @@ -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 @@ -311,6 +311,28 @@ trx_get_on_id( return(NULL); } +#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG +/***********************************************************//** +Assert that a transaction has been recovered. +@return TRUE */ +UNIV_INLINE +ibool +trx_assert_recovered( +/*=================*/ + trx_id_t trx_id) /*!< in: transaction identifier */ +{ + trx_t* trx; + + mutex_enter(&kernel_mutex); + trx = trx_get_on_id(trx_id); + ut_a(trx); + ut_a(trx->is_recovered); + mutex_exit(&kernel_mutex); + + return(TRUE); +} +#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ + /****************************************************************//** Returns the minumum trx id in trx list. This is the smallest id for which the trx can possibly be active. (But, you must look at the trx->conc_state to diff --git a/include/trx0trx.h b/include/trx0trx.h index 173c63918d3..700476bcd85 100644 --- a/include/trx0trx.h +++ b/include/trx0trx.h @@ -44,6 +44,9 @@ extern sess_t* trx_dummy_sess; /** Number of transactions currently allocated for MySQL: protected by the kernel mutex */ extern ulint trx_n_mysql_transactions; +/** Number of transactions currently in the XA PREPARED state: protected by +the kernel mutex */ +extern ulint trx_n_prepared; /********************************************************************//** Releases the search latch if trx has reserved it. */ @@ -108,6 +111,14 @@ trx_free( /*=====*/ trx_t* trx); /*!< in, own: trx object */ /********************************************************************//** +At shutdown, frees a transaction object that is in the PREPARED state. */ +UNIV_INTERN +void +trx_free_prepared( +/*==============*/ + trx_t* trx) /*!< in, own: trx object */ + __attribute__((nonnull)); +/********************************************************************//** Frees a transaction object for MySQL. */ UNIV_INTERN void @@ -498,6 +509,7 @@ struct trx_struct{ 150 bytes in the undo log size as then we skip XA steps */ ulint flush_log_at_trx_commit_session; + ulint fake_changes; ulint flush_log_later;/* In 2PC, we hold the prepare_commit mutex across both phases. In that case, we @@ -589,6 +601,8 @@ struct trx_struct{ ulint mysql_process_no;/* since in Linux, 'top' reports process id's and not thread id's, we store the process number too */ + time_t idle_start; + ib_int64_t last_stmt_start; /*------------------------------*/ ulint n_mysql_tables_in_use; /* number of Innobase tables used in the processing of the current diff --git a/include/trx0undo.h b/include/trx0undo.h index a084f2394b5..4f15cd85833 100644 --- a/include/trx0undo.h +++ b/include/trx0undo.h @@ -298,6 +298,15 @@ void trx_undo_insert_cleanup( /*====================*/ trx_t* trx); /*!< in: transaction handle */ + +/********************************************************************//** +At shutdown, frees the undo logs of a PREPARED transaction. */ +UNIV_INTERN +void +trx_undo_free_prepared( +/*===================*/ + trx_t* trx) /*!< in/out: PREPARED transaction */ + __attribute__((nonnull)); #endif /* !UNIV_HOTBACKUP */ /***********************************************************//** Parses the redo log entry of an undo log page initialization. diff --git a/include/univ.i b/include/univ.i index a658c7b6eaa..c9f9381842e 100644 --- a/include/univ.i +++ b/include/univ.i @@ -1,8 +1,7 @@ /***************************************************************************** -Copyright (c) 1994, 2010, Innobase Oy. All Rights Reserved. +Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, Google Inc. -Copyright (c) 2009, Sun Microsystems, Inc. Portions of this file contain modifications contributed and copyrighted by Google, Inc. Those modifications are gratefully acknowledged and are described @@ -46,7 +45,7 @@ Created 1/20/1994 Heikki Tuuri #define INNODB_VERSION_MAJOR 1 #define INNODB_VERSION_MINOR 0 -#define INNODB_VERSION_BUGFIX 15 +#define INNODB_VERSION_BUGFIX 17 #ifndef PERCONA_INNODB_VERSION #define PERCONA_INNODB_VERSION 12.5 @@ -201,6 +200,8 @@ this will break redo log file compatibility, but it may be useful when debugging redo log application problems. */ #define UNIV_MEM_DEBUG /* detect memory leaks etc */ #define UNIV_IBUF_DEBUG /* debug the insert buffer */ +#define UNIV_BLOB_DEBUG /* track BLOB ownership; +assumes that no BLOBs survive server restart */ #define UNIV_IBUF_COUNT_DEBUG /* debug the insert buffer; this limits the database to IBUF_COUNT_N_SPACES and IBUF_COUNT_N_PAGES, and the insert buffer must be empty when the database is started */ diff --git a/include/ut0lst.h b/include/ut0lst.h index a40c8054082..261d33963dc 100644 --- a/include/ut0lst.h +++ b/include/ut0lst.h @@ -257,48 +257,5 @@ do { \ ut_a(ut_list_node_313 == NULL); \ } while (0) -/********************************************************************//** -Align nodes with moving location. -@param NAME the name of the list -@param TYPE node type -@param BASE base node (not a pointer to it) -@param OFFSET offset moved */ -#define UT_LIST_OFFSET(NAME, TYPE, BASE, FADDR, FOFFSET, BOFFSET) \ -do { \ - ulint ut_list_i_313; \ - TYPE* ut_list_node_313; \ - \ - if ((BASE).start) \ - (BASE).start = (void*)((byte*)((BASE).start) \ - + (((void*)((BASE).start) > (void*)FADDR)?FOFFSET:BOFFSET));\ - if ((BASE).end) \ - (BASE).end = (void*)((byte*)((BASE).end) \ - + (((void*)((BASE).end) > (void*)FADDR)?FOFFSET:BOFFSET));\ - \ - ut_list_node_313 = (BASE).start; \ - \ - for (ut_list_i_313 = (BASE).count; ut_list_i_313--; ) { \ - ut_a(ut_list_node_313); \ - if ((ut_list_node_313->NAME).prev) \ - (ut_list_node_313->NAME).prev = (void*)((byte*)((ut_list_node_313->NAME).prev)\ - + (((void*)((ut_list_node_313->NAME).prev) > (void*)FADDR)?FOFFSET:BOFFSET));\ - if ((ut_list_node_313->NAME).next) \ - (ut_list_node_313->NAME).next = (void*)((byte*)((ut_list_node_313->NAME).next)\ - + (((void*)((ut_list_node_313->NAME).next)> (void*)FADDR)?FOFFSET:BOFFSET));\ - ut_list_node_313 = (ut_list_node_313->NAME).next; \ - } \ - \ - ut_a(ut_list_node_313 == NULL); \ - \ - ut_list_node_313 = (BASE).end; \ - \ - for (ut_list_i_313 = (BASE).count; ut_list_i_313--; ) { \ - ut_a(ut_list_node_313); \ - ut_list_node_313 = (ut_list_node_313->NAME).prev; \ - } \ - \ - ut_a(ut_list_node_313 == NULL); \ -} while (0) - #endif diff --git a/include/ut0mem.h b/include/ut0mem.h index f14606be966..9c6ee9049ec 100644 --- a/include/ut0mem.h +++ b/include/ut0mem.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 @@ -209,43 +209,6 @@ ut_strlcpy_rev( const char* src, /*!< in: source buffer */ ulint size); /*!< in: size of destination buffer */ -/**********************************************************************//** -Compute strlen(ut_strcpyq(str, q)). -@return length of the string when quoted */ -UNIV_INLINE -ulint -ut_strlenq( -/*=======*/ - const char* str, /*!< in: null-terminated string */ - char q); /*!< in: the quote character */ - -/**********************************************************************//** -Make a quoted copy of a NUL-terminated string. Leading and trailing -quotes will not be included; only embedded quotes will be escaped. -See also ut_strlenq() and ut_memcpyq(). -@return pointer to end of dest */ -UNIV_INTERN -char* -ut_strcpyq( -/*=======*/ - char* dest, /*!< in: output buffer */ - char q, /*!< in: the quote character */ - const char* src); /*!< in: null-terminated string */ - -/**********************************************************************//** -Make a quoted copy of a fixed-length string. Leading and trailing -quotes will not be included; only embedded quotes will be escaped. -See also ut_strlenq() and ut_strcpyq(). -@return pointer to end of dest */ -UNIV_INTERN -char* -ut_memcpyq( -/*=======*/ - char* dest, /*!< in: output buffer */ - char q, /*!< in: the quote character */ - const char* src, /*!< in: string to be quoted */ - ulint len); /*!< in: length of src */ - /**********************************************************************//** Return the number of times s2 occurs in s1. Overlapping instances of s2 are only counted once. diff --git a/include/ut0mem.ic b/include/ut0mem.ic index f36c28f1989..c06e2b3ae81 100644 --- a/include/ut0mem.ic +++ b/include/ut0mem.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 @@ -98,27 +98,6 @@ ut_strcmp(const char* str1, const char* str2) return(strcmp(str1, str2)); } -/**********************************************************************//** -Compute strlen(ut_strcpyq(str, q)). -@return length of the string when quoted */ -UNIV_INLINE -ulint -ut_strlenq( -/*=======*/ - const char* str, /*!< in: null-terminated string */ - char q) /*!< in: the quote character */ -{ - ulint len; - - for (len = 0; *str; len++, str++) { - if (*str == q) { - len++; - } - } - - return(len); -} - /**********************************************************************//** Converts a raw binary data to a NUL-terminated hex string. The output is truncated if there is not enough space in "hex", make sure "hex_size" is at diff --git a/lock/lock0lock.c b/lock/lock0lock.c index 4fcb5b2c522..e5da4f46ec9 100644 --- a/lock/lock0lock.c +++ b/lock/lock0lock.c @@ -3908,6 +3908,10 @@ lock_table( trx = thr_get_trx(thr); + if (trx->fake_changes && mode == LOCK_IX) { + mode = LOCK_IS; + } + lock_mutex_enter_kernel(); /* Look for stronger locks the same trx already has on the table */ @@ -5109,6 +5113,11 @@ lock_rec_insert_check_and_lock( } trx = thr_get_trx(thr); + + if (trx->fake_changes) { + return(DB_SUCCESS); + } + next_rec = page_rec_get_next_const(rec); next_rec_heap_no = page_rec_get_heap_no(next_rec); @@ -5277,6 +5286,10 @@ lock_clust_rec_modify_check_and_lock( return(DB_SUCCESS); } + if (thr && thr_get_trx(thr)->fake_changes) { + return(DB_SUCCESS); + } + heap_no = rec_offs_comp(offsets) ? rec_get_heap_no_new(rec) : rec_get_heap_no_old(rec); @@ -5335,6 +5348,10 @@ lock_sec_rec_modify_check_and_lock( return(DB_SUCCESS); } + if (thr && thr_get_trx(thr)->fake_changes) { + return(DB_SUCCESS); + } + heap_no = page_rec_get_heap_no(rec); /* Another transaction cannot have an implicit lock on the record, @@ -5422,6 +5439,10 @@ lock_sec_rec_read_check_and_lock( return(DB_SUCCESS); } + if (thr && thr_get_trx(thr)->fake_changes && mode == LOCK_X) { + mode = LOCK_S; + } + heap_no = page_rec_get_heap_no(rec); lock_mutex_enter_kernel(); @@ -5499,6 +5520,10 @@ lock_clust_rec_read_check_and_lock( return(DB_SUCCESS); } + if (thr && thr_get_trx(thr)->fake_changes && mode == LOCK_X) { + mode = LOCK_S; + } + heap_no = page_rec_get_heap_no(rec); lock_mutex_enter_kernel(); diff --git a/log/log0log.c b/log/log0log.c index c39f60bd4b9..fc8745629d6 100644 --- a/log/log0log.c +++ b/log/log0log.c @@ -1114,7 +1114,7 @@ log_io_complete( && srv_unix_file_flush_method != SRV_UNIX_ALL_O_DIRECT && srv_unix_file_flush_method != SRV_UNIX_NOSYNC) { - fil_flush(group->space_id); + fil_flush(group->space_id, FALSE); } #ifdef UNIV_DEBUG @@ -1137,7 +1137,7 @@ log_io_complete( && srv_unix_file_flush_method != SRV_UNIX_NOSYNC && srv_flush_log_at_trx_commit != 2) { - fil_flush(group->space_id); + fil_flush(group->space_id, FALSE); } mutex_enter(&(log_sys->mutex)); @@ -1528,7 +1528,7 @@ loop: group = UT_LIST_GET_FIRST(log_sys->log_groups); - fil_flush(group->space_id); + fil_flush(group->space_id, FALSE); log_sys->flushed_to_disk_lsn = log_sys->write_lsn; } @@ -2623,7 +2623,7 @@ log_io_complete_archive(void) mutex_exit(&(log_sys->mutex)); - fil_flush(group->archive_space_id); + fil_flush(group->archive_space_id, TRUE); mutex_enter(&(log_sys->mutex)); @@ -3122,12 +3122,13 @@ loop: goto loop; } - /* Check that there are no longer transactions. We need this wait even - for the 'very fast' shutdown, because the InnoDB layer may have - committed or prepared transactions and we don't want to lose them. */ + /* Check that there are no longer transactions, except for + PREPARED ones. We need this wait even for the 'very fast' + shutdown, because the InnoDB layer may have committed or + prepared transactions and we don't want to lose them. */ if (trx_n_mysql_transactions > 0 - || UT_LIST_GET_LEN(trx_sys->trx_list) > 0) { + || UT_LIST_GET_LEN(trx_sys->trx_list) > trx_n_prepared) { mutex_exit(&kernel_mutex); diff --git a/log/log0recv.c b/log/log0recv.c index 8ef24995b09..b8ff5401129 100644 --- a/log/log0recv.c +++ b/log/log0recv.c @@ -2899,7 +2899,6 @@ recv_init_crash_recovery(void) /*==========================*/ { ut_a(!recv_needed_recovery); - ut_a(!srv_buffer_pool_shm_is_reused); recv_needed_recovery = TRUE; @@ -3621,7 +3620,7 @@ recv_reset_log_files_for_backup( exit(1); } - os_file_flush(log_file); + os_file_flush(log_file, TRUE); os_file_close(log_file); } @@ -3644,7 +3643,7 @@ recv_reset_log_files_for_backup( os_file_write(name, log_file, buf, 0, 0, LOG_FILE_HDR_SIZE + OS_FILE_LOG_BLOCK_SIZE); - os_file_flush(log_file); + os_file_flush(log_file, TRUE); os_file_close(log_file); ut_free(buf); diff --git a/mtr/mtr0mtr.c b/mtr/mtr0mtr.c index 34e6d3ffc92..a9f1c35f84c 100644 --- a/mtr/mtr0mtr.c +++ b/mtr/mtr0mtr.c @@ -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 @@ -248,40 +248,6 @@ mtr_commit( } #ifndef UNIV_HOTBACKUP -/**********************************************************//** -Releases the latches stored in an mtr memo down to a savepoint. -NOTE! The mtr must not have made changes to buffer pages after the -savepoint, as these can be handled only by mtr_commit. */ -UNIV_INTERN -void -mtr_rollback_to_savepoint( -/*======================*/ - mtr_t* mtr, /*!< in: mtr */ - ulint savepoint) /*!< in: savepoint */ -{ - mtr_memo_slot_t* slot; - dyn_array_t* memo; - ulint offset; - - ut_ad(mtr); - ut_ad(mtr->magic_n == MTR_MAGIC_N); - ut_ad(mtr->state == MTR_ACTIVE); - - memo = &(mtr->memo); - - offset = dyn_array_get_data_size(memo); - ut_ad(offset >= savepoint); - - while (offset > savepoint) { - offset -= sizeof(mtr_memo_slot_t); - - slot = dyn_array_get_element(memo, offset); - - ut_ad(slot->type != MTR_MEMO_MODIFY); - mtr_memo_slot_release(mtr, slot); - } -} - /***************************************************//** Releases an object in the memo stack. */ UNIV_INTERN diff --git a/os/os0file.c b/os/os0file.c index 31dec031af3..1b0251a5422 100644 --- a/os/os0file.c +++ b/os/os0file.c @@ -1912,7 +1912,7 @@ os_file_set_size( ut_free(buf2); - ret = os_file_flush(file); + ret = os_file_flush(file, TRUE); if (ret) { return(TRUE); @@ -1950,7 +1950,8 @@ static int os_file_fsync( /*==========*/ - os_file_t file) /*!< in: handle to a file */ + os_file_t file, /*!< in: handle to a file */ + ibool metadata) { int ret; int failures; @@ -1959,7 +1960,16 @@ os_file_fsync( failures = 0; do { +#if defined(HAVE_FDATASYNC) && HAVE_DECL_FDATASYNC + if (metadata) { + ret = fsync(file); + } else { + ret = fdatasync(file); + } +#else + (void) metadata; ret = fsync(file); +#endif os_n_fsyncs++; @@ -1977,6 +1987,9 @@ os_file_fsync( failures++; + retry = TRUE; + } else if (ret == -1 && errno == EINTR) { + /* Handle signal interruptions correctly */ retry = TRUE; } else { @@ -1995,7 +2008,8 @@ UNIV_INTERN ibool os_file_flush( /*==========*/ - os_file_t file) /*!< in, own: handle to a file */ + os_file_t file, /*!< in, own: handle to a file */ + ibool metadata) { #ifdef __WIN__ BOOL ret; @@ -2045,18 +2059,18 @@ os_file_flush( /* If we are not on an operating system that supports this, then fall back to a plain fsync. */ - ret = os_file_fsync(file); + ret = os_file_fsync(file, metadata); } else { ret = fcntl(file, F_FULLFSYNC, NULL); if (ret) { /* If we are not on a file system that supports this, then fall back to a plain fsync. */ - ret = os_file_fsync(file); + ret = os_file_fsync(file, metadata); } } #else - ret = os_file_fsync(file); + ret = os_file_fsync(file, metadata); #endif if (ret == 0) { @@ -2109,6 +2123,7 @@ _os_file_pread( off_t offs; #if defined(HAVE_PREAD) && !defined(HAVE_BROKEN_PREAD) ssize_t n_bytes; + ssize_t n_read; #endif /* HAVE_PREAD && !HAVE_BROKEN_PREAD */ ulint sec; ulint ms; @@ -2149,7 +2164,18 @@ _os_file_pread( os_n_pending_reads++; os_mutex_exit(os_file_count_mutex); - n_bytes = pread(file, buf, (ssize_t)n, offs); + /* Handle signal interruptions correctly */ + for (n_bytes = 0; n_bytes < (ssize_t) n; ) { + n_read = pread(file, buf, (ssize_t)n, offs); + if (n_read > 0) { + n_bytes += n_read; + offs += n_read; + } else if (n_read == -1 && errno == EINTR) { + continue; + } else { + break; + } + } os_mutex_enter(os_file_count_mutex); os_file_n_pending_preads--; @@ -2168,6 +2194,7 @@ _os_file_pread( { off_t ret_offset; ssize_t ret; + ssize_t n_read; #ifndef UNIV_HOTBACKUP ulint i; #endif /* !UNIV_HOTBACKUP */ @@ -2188,7 +2215,17 @@ _os_file_pread( if (ret_offset < 0) { ret = -1; } else { - ret = read(file, buf, (ssize_t)n); + /* Handle signal interruptions correctly */ + for (ret = 0; ret < (ssize_t) n; ) { + n_read = read(file, buf, (ssize_t)n); + if (n_read > 0) { + ret += n_read; + } else if (n_read == -1 && errno == EINTR) { + continue; + } else { + break; + } + } } #ifndef UNIV_HOTBACKUP @@ -2227,6 +2264,7 @@ os_file_pwrite( offset */ { ssize_t ret; + ssize_t n_written; off_t offs; ut_a((offset & 0xFFFFFFFFUL) == offset); @@ -2254,7 +2292,18 @@ os_file_pwrite( os_n_pending_writes++; os_mutex_exit(os_file_count_mutex); - ret = pwrite(file, buf, (ssize_t)n, offs); + /* Handle signal interruptions correctly */ + for (ret = 0; ret < (ssize_t) n; ) { + n_written = pwrite(file, buf, (ssize_t)n, offs); + if (n_written > 0) { + ret += n_written; + offs += n_written; + } else if (n_written == -1 && errno == EINTR) { + continue; + } else { + break; + } + } os_mutex_enter(os_file_count_mutex); os_file_n_pending_pwrites--; @@ -2270,7 +2319,7 @@ os_file_pwrite( the OS crashes, a database page is only partially physically written to disk. */ - ut_a(TRUE == os_file_flush(file)); + ut_a(TRUE == os_file_flush(file, TRUE)); } # endif /* UNIV_DO_FLUSH */ @@ -2301,7 +2350,17 @@ os_file_pwrite( goto func_exit; } - ret = write(file, buf, (ssize_t)n); + /* Handle signal interruptions correctly */ + for (ret = 0; ret < (ssize_t) n; ) { + n_written = write(file, buf, (ssize_t)n); + if (n_written > 0) { + ret += n_written; + } else if (n_written == -1 && errno == EINTR) { + continue; + } else { + break; + } + } # ifdef UNIV_DO_FLUSH if (srv_unix_file_flush_method != SRV_UNIX_LITTLESYNC @@ -2312,7 +2371,7 @@ os_file_pwrite( the OS crashes, a database page is only partially physically written to disk. */ - ut_a(TRUE == os_file_flush(file)); + ut_a(TRUE == os_file_flush(file, TRUE)); } # endif /* UNIV_DO_FLUSH */ @@ -2679,7 +2738,7 @@ retry: # ifdef UNIV_DO_FLUSH if (!os_do_not_call_flush_at_each_write) { - ut_a(TRUE == os_file_flush(file)); + ut_a(TRUE == os_file_flush(file, TRUE)); } # endif /* UNIV_DO_FLUSH */ @@ -3939,7 +3998,7 @@ os_aio_windows_handle( #ifdef UNIV_DO_FLUSH if (slot->type == OS_FILE_WRITE && !os_do_not_call_flush_at_each_write) { - ut_a(TRUE == os_file_flush(slot->file)); + ut_a(TRUE == os_file_flush(slot->file, TRUE)); } #endif /* UNIV_DO_FLUSH */ } else if (os_file_handle_error(slot->name, "Windows aio")) { diff --git a/os/os0proc.c b/os/os0proc.c index 4567d96b6f4..48922886f23 100644 --- a/os/os0proc.c +++ b/os/os0proc.c @@ -229,173 +229,3 @@ os_mem_free_large( } #endif } - -/****************************************************************//** -Allocates or attaches and reuses shared memory segment. -The content is not cleared automatically. -@return allocated memory */ -UNIV_INTERN -void* -os_shm_alloc( -/*=========*/ - ulint* n, /*!< in/out: number of bytes */ - uint key, - ibool* is_new) -{ - void* ptr; -#if defined HAVE_SYS_IPC_H && HAVE_SYS_SHM_H - ulint size; - int shmid; - - *is_new = FALSE; - fprintf(stderr, - "InnoDB: The shared memory segment containing the buffer pool is: key %#x (%d).\n", - key, key); -# if defined HAVE_LARGE_PAGES && defined UNIV_LINUX - if (!os_use_large_pages || !os_large_page_size) { - goto skip; - } - - /* Align block size to os_large_page_size */ - ut_ad(ut_is_2pow(os_large_page_size)); - size = ut_2pow_round(*n + (os_large_page_size - 1), - os_large_page_size); - - shmid = shmget((key_t)key, (size_t)size, - IPC_CREAT | IPC_EXCL | SHM_HUGETLB | SHM_R | SHM_W); - if (shmid < 0) { - if (errno == EEXIST) { - fprintf(stderr, - "InnoDB: HugeTLB: The shared memory segment exists.\n"); - shmid = shmget((key_t)key, (size_t)size, - SHM_HUGETLB | SHM_R | SHM_W); - if (shmid < 0) { - fprintf(stderr, - "InnoDB: HugeTLB: Warning: Failed to allocate %lu bytes. (reuse) errno %d\n", - size, errno); - goto skip; - } else { - fprintf(stderr, - "InnoDB: HugeTLB: The existent shared memory segment is used.\n"); - } - } else { - fprintf(stderr, - "InnoDB: HugeTLB: Warning: Failed to allocate %lu bytes. (new) errno %d\n", - size, errno); - goto skip; - } - } else { - *is_new = TRUE; - fprintf(stderr, - "InnoDB: HugeTLB: A new shared memory segment has been created .\n"); - } - - ptr = shmat(shmid, NULL, 0); - if (ptr == (void *)-1) { - fprintf(stderr, - "InnoDB: HugeTLB: Warning: Failed to attach shared memory segment, errno %d\n", - errno); - ptr = NULL; - } - - if (ptr) { - *n = size; - os_fast_mutex_lock(&ut_list_mutex); - ut_total_allocated_memory += size; - os_fast_mutex_unlock(&ut_list_mutex); - UNIV_MEM_ALLOC(ptr, size); - return(ptr); - } -skip: - *is_new = FALSE; -# endif /* HAVE_LARGE_PAGES && defined UNIV_LINUX */ -# ifdef HAVE_GETPAGESIZE - size = getpagesize(); -# else - size = UNIV_PAGE_SIZE; -# endif - /* Align block size to system page size */ - ut_ad(ut_is_2pow(size)); - size = *n = ut_2pow_round(*n + (size - 1), size); - - shmid = shmget((key_t)key, (size_t)size, - IPC_CREAT | IPC_EXCL | SHM_R | SHM_W); - if (shmid < 0) { - if (errno == EEXIST) { - fprintf(stderr, - "InnoDB: A shared memory segment containing the buffer pool seems to already exist.\n"); - shmid = shmget((key_t)key, (size_t)size, - SHM_R | SHM_W); - if (shmid < 0) { - fprintf(stderr, - "InnoDB: Warning: Failed to allocate %lu bytes. (reuse) errno %d\n", - size, errno); - ptr = NULL; - goto end; - } else { - fprintf(stderr, - "InnoDB: The existent shared memory segment is used.\n"); - } - } else { - fprintf(stderr, - "InnoDB: Warning: Failed to allocate %lu bytes. (new) errno %d\n", - size, errno); - ptr = NULL; - goto end; - } - } else { - *is_new = TRUE; - fprintf(stderr, - "InnoDB: A new shared memory segment has been created.\n"); - } - - ptr = shmat(shmid, NULL, 0); - if (ptr == (void *)-1) { - fprintf(stderr, - "InnoDB: Warning: Failed to attach shared memory segment, errno %d\n", - errno); - ptr = NULL; - } - - if (ptr) { - *n = size; - os_fast_mutex_lock(&ut_list_mutex); - ut_total_allocated_memory += size; - os_fast_mutex_unlock(&ut_list_mutex); - UNIV_MEM_ALLOC(ptr, size); - } -end: -#else /* HAVE_SYS_IPC_H && HAVE_SYS_SHM_H */ - fprintf(stderr, "InnoDB: shared memory segment is not supported.\n"); - ptr = NULL; -#endif /* HAVE_SYS_IPC_H && HAVE_SYS_SHM_H */ - return(ptr); -} - -/****************************************************************//** -Detach shared memory segment. */ -UNIV_INTERN -void -os_shm_free( -/*========*/ - void *ptr, /*!< in: pointer returned by - os_shm_alloc() */ - ulint size) /*!< in: size returned by - os_shm_alloc() */ -{ - os_fast_mutex_lock(&ut_list_mutex); - ut_a(ut_total_allocated_memory >= size); - os_fast_mutex_unlock(&ut_list_mutex); - -#if defined HAVE_SYS_IPC_H && HAVE_SYS_SHM_H - if (!shmdt(ptr)) { - os_fast_mutex_lock(&ut_list_mutex); - ut_a(ut_total_allocated_memory >= size); - ut_total_allocated_memory -= size; - os_fast_mutex_unlock(&ut_list_mutex); - UNIV_MEM_FREE(ptr, size); - } -#else /* HAVE_SYS_IPC_H && HAVE_SYS_SHM_H */ - fprintf(stderr, "InnoDB: shared memory segment is not supported.\n"); -#endif /* HAVE_SYS_IPC_H && HAVE_SYS_SHM_H */ -} diff --git a/page/page0cur.c b/page/page0cur.c index f10f16a7dd9..b8c492328e8 100644 --- a/page/page0cur.c +++ b/page/page0cur.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 @@ -1149,6 +1149,8 @@ use_heap: current_rec, index, mtr); } + btr_blob_dbg_add_rec(insert_rec, index, offsets, "insert"); + return(insert_rec); } @@ -1178,14 +1180,15 @@ page_cur_insert_rec_zip_reorg( /* Before trying to reorganize the page, store the number of preceding records on the page. */ pos = page_rec_get_n_recs_before(rec); + ut_ad(pos > 0); if (page_zip_reorganize(block, index, mtr)) { /* The page was reorganized: Find rec by seeking to pos, and update *current_rec. */ - rec = page + PAGE_NEW_INFIMUM; - - while (--pos) { - rec = page + rec_get_next_offs(rec, TRUE); + if (pos > 1) { + rec = page_rec_get_nth(page, pos - 1); + } else { + rec = page + PAGE_NEW_INFIMUM; } *current_rec = rec; @@ -1195,10 +1198,12 @@ page_cur_insert_rec_zip_reorg( } /* Out of space: restore the page */ + btr_blob_dbg_remove(page, index, "insert_zip_fail"); if (!page_zip_decompress(page_zip, page, FALSE)) { ut_error; /* Memory corrupted? */ } ut_ad(page_validate(page, index)); + btr_blob_dbg_add(page, index, "insert_zip_fail"); return(NULL); } @@ -1279,6 +1284,12 @@ page_cur_insert_rec_zip( insert_rec = page_cur_insert_rec_zip_reorg( current_rec, block, index, insert_rec, page, page_zip, mtr); +#ifdef UNIV_DEBUG + if (insert_rec) { + rec_offs_make_valid( + insert_rec, index, offsets); + } +#endif /* UNIV_DEBUG */ } return(insert_rec); @@ -1490,6 +1501,8 @@ use_heap: page_zip_write_rec(page_zip, insert_rec, index, offsets, 1); + btr_blob_dbg_add_rec(insert_rec, index, offsets, "insert_zip_ok"); + /* 9. Write log record of the insert */ if (UNIV_LIKELY(mtr != NULL)) { page_cur_insert_rec_write_log(insert_rec, rec_size, @@ -1697,6 +1710,9 @@ page_copy_rec_list_end_to_created_page( heap_top += rec_size; + rec_offs_make_valid(insert_rec, index, offsets); + btr_blob_dbg_add_rec(insert_rec, index, offsets, "copy_end"); + page_cur_insert_rec_write_log(insert_rec, rec_size, prev_rec, index, mtr); prev_rec = insert_rec; @@ -1944,6 +1960,7 @@ page_cur_delete_rec( page_dir_slot_set_n_owned(cur_dir_slot, page_zip, cur_n_owned - 1); /* 6. Free the memory occupied by the record */ + btr_blob_dbg_remove_rec(current_rec, index, offsets, "delete"); page_mem_free(page, page_zip, current_rec, index, offsets); /* 7. Now we have decremented the number of owned records of the slot. diff --git a/page/page0page.c b/page/page0page.c index 10008f9ac25..a284b1480a3 100644 --- a/page/page0page.c +++ b/page/page0page.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2010, 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 @@ -685,12 +685,16 @@ page_copy_rec_list_end( if (UNIV_UNLIKELY (!page_zip_reorganize(new_block, index, mtr))) { + btr_blob_dbg_remove(new_page, index, + "copy_end_reorg_fail"); if (UNIV_UNLIKELY (!page_zip_decompress(new_page_zip, new_page, FALSE))) { ut_error; } ut_ad(page_validate(new_page, index)); + btr_blob_dbg_add(new_page, index, + "copy_end_reorg_fail"); return(NULL); } else { /* The page was reorganized: @@ -803,12 +807,16 @@ page_copy_rec_list_start( if (UNIV_UNLIKELY (!page_zip_reorganize(new_block, index, mtr))) { + btr_blob_dbg_remove(new_page, index, + "copy_start_reorg_fail"); if (UNIV_UNLIKELY (!page_zip_decompress(new_page_zip, new_page, FALSE))) { ut_error; } ut_ad(page_validate(new_page, index)); + btr_blob_dbg_add(new_page, index, + "copy_start_reorg_fail"); return(NULL); } else { /* The page was reorganized: @@ -1080,6 +1088,9 @@ page_delete_rec_list_end( /* Remove the record chain segment from the record chain */ page_rec_set_next(prev_rec, page_get_supremum_rec(page)); + btr_blob_dbg_op(page, rec, index, "delete_end", + btr_blob_dbg_remove_rec); + /* Catenate the deleted chain segment to the page free list */ page_rec_set_next(last_rec, page_header_get_ptr(page, PAGE_FREE)); @@ -1476,55 +1487,54 @@ page_dir_balance_slot( } } -#ifndef UNIV_HOTBACKUP /************************************************************//** -Returns the middle record of the record list. If there are an even number -of records in the list, returns the first record of the upper half-list. -@return middle record */ +Returns the nth record of the record list. +This is the inverse function of page_rec_get_n_recs_before(). +@return nth record */ UNIV_INTERN -rec_t* -page_get_middle_rec( -/*================*/ - page_t* page) /*!< in: page */ +const rec_t* +page_rec_get_nth_const( +/*===================*/ + const page_t* page, /*!< in: page */ + ulint nth) /*!< in: nth record */ { - page_dir_slot_t* slot; - ulint middle; + const page_dir_slot_t* slot; ulint i; ulint n_owned; - ulint count; - rec_t* rec; + const rec_t* rec; - /* This many records we must leave behind */ - middle = (page_get_n_recs(page) + PAGE_HEAP_NO_USER_LOW) / 2; - - count = 0; + ut_ad(nth < UNIV_PAGE_SIZE / (REC_N_NEW_EXTRA_BYTES + 1)); for (i = 0;; i++) { slot = page_dir_get_nth_slot(page, i); n_owned = page_dir_slot_get_n_owned(slot); - if (count + n_owned > middle) { + if (n_owned > nth) { break; } else { - count += n_owned; + nth -= n_owned; } } ut_ad(i > 0); slot = page_dir_get_nth_slot(page, i - 1); - rec = (rec_t*) page_dir_slot_get_rec(slot); - rec = page_rec_get_next(rec); + rec = page_dir_slot_get_rec(slot); - /* There are now count records behind rec */ - - for (i = 0; i < middle - count; i++) { - rec = page_rec_get_next(rec); + if (page_is_comp(page)) { + do { + rec = page_rec_get_next_low(rec, TRUE); + ut_ad(rec); + } while (nth--); + } else { + do { + rec = page_rec_get_next_low(rec, FALSE); + ut_ad(rec); + } while (nth--); } return(rec); } -#endif /* !UNIV_HOTBACKUP */ /***************************************************************//** Returns the number of records before the given record in chain. @@ -1586,6 +1596,7 @@ page_rec_get_n_recs_before( n--; ut_ad(n >= 0); + ut_ad(n < UNIV_PAGE_SIZE / (REC_N_NEW_EXTRA_BYTES + 1)); return((ulint) n); } diff --git a/page/page0zip.c b/page/page0zip.c index 5b4f5d3b76a..3d5c5a226c7 100644 --- a/page/page0zip.c +++ b/page/page0zip.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2005, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 2005, 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 @@ -150,6 +150,20 @@ page_zip_empty_size( } #endif /* !UNIV_HOTBACKUP */ +/*************************************************************//** +Gets the number of elements in the dense page directory, +including deleted records (the free list). +@return number of elements in the dense page directory */ +UNIV_INLINE +ulint +page_zip_dir_elems( +/*===============*/ + const page_zip_des_t* page_zip) /*!< in: compressed page */ +{ + /* Exclude the page infimum and supremum from the record count. */ + return(page_dir_get_n_heap(page_zip->data) - PAGE_HEAP_NO_USER_LOW); +} + /*************************************************************//** Gets the size of the compressed page trailer (the dense page directory), including deleted records (the free list). @@ -160,13 +174,41 @@ page_zip_dir_size( /*==============*/ const page_zip_des_t* page_zip) /*!< in: compressed page */ { - /* Exclude the page infimum and supremum from the record count. */ - ulint size = PAGE_ZIP_DIR_SLOT_SIZE - * (page_dir_get_n_heap(page_zip->data) - - PAGE_HEAP_NO_USER_LOW); - return(size); + return(PAGE_ZIP_DIR_SLOT_SIZE * page_zip_dir_elems(page_zip)); } +/*************************************************************//** +Gets an offset to the compressed page trailer (the dense page directory), +including deleted records (the free list). +@return offset of the dense page directory */ +UNIV_INLINE +ulint +page_zip_dir_start_offs( +/*====================*/ + const page_zip_des_t* page_zip, /*!< in: compressed page */ + ulint n_dense) /*!< in: directory size */ +{ + ut_ad(n_dense * PAGE_ZIP_DIR_SLOT_SIZE < page_zip_get_size(page_zip)); + + return(page_zip_get_size(page_zip) - n_dense * PAGE_ZIP_DIR_SLOT_SIZE); +} + +/*************************************************************//** +Gets a pointer to the compressed page trailer (the dense page directory), +including deleted records (the free list). +@param[in] page_zip compressed page +@param[in] n_dense number of entries in the directory +@return pointer to the dense page directory */ +#define page_zip_dir_start_low(page_zip, n_dense) \ + ((page_zip)->data + page_zip_dir_start_offs(page_zip, n_dense)) +/*************************************************************//** +Gets a pointer to the compressed page trailer (the dense page directory), +including deleted records (the free list). +@param[in] page_zip compressed page +@return pointer to the dense page directory */ +#define page_zip_dir_start(page_zip) \ + page_zip_dir_start_low(page_zip, page_zip_dir_elems(page_zip)) + /*************************************************************//** Gets the size of the compressed page trailer (the dense page directory), only including user records (excluding the free list). @@ -653,13 +695,13 @@ page_zip_dir_encode( Allocate memory for zlib. */ static void* -page_zip_malloc( +page_zip_zalloc( /*============*/ void* opaque, /*!< in/out: memory heap */ uInt items, /*!< in: number of items to allocate */ uInt size) /*!< in: size of an item in bytes */ { - return(mem_heap_alloc(opaque, items * size)); + return(mem_heap_zalloc(opaque, items * size)); } /**********************************************************************//** @@ -684,7 +726,7 @@ page_zip_set_alloc( { z_stream* strm = stream; - strm->zalloc = page_zip_malloc; + strm->zalloc = page_zip_zalloc; strm->zfree = page_zip_free; strm->opaque = heap; } @@ -2246,8 +2288,7 @@ zlib_done: } /* Restore the uncompressed columns in heap_no order. */ - storage = page_zip->data + page_zip_get_size(page_zip) - - n_dense * PAGE_ZIP_DIR_SLOT_SIZE; + storage = page_zip_dir_start_low(page_zip, n_dense); for (slot = 0; slot < n_dense; slot++) { rec_t* rec = recs[slot]; @@ -2732,8 +2773,7 @@ zlib_done: return(FALSE); } - storage = page_zip->data + page_zip_get_size(page_zip) - - n_dense * PAGE_ZIP_DIR_SLOT_SIZE; + storage = page_zip_dir_start_low(page_zip, n_dense); externs = storage - n_dense * (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN); @@ -2916,19 +2956,18 @@ zlib_error: page_zip_set_alloc(&d_stream, heap); - if (UNIV_UNLIKELY(inflateInit2(&d_stream, UNIV_PAGE_SIZE_SHIFT) - != Z_OK)) { - ut_error; - } - d_stream.next_in = page_zip->data + PAGE_DATA; /* Subtract the space reserved for the page header and the end marker of the modification log. */ d_stream.avail_in = page_zip_get_size(page_zip) - (PAGE_DATA + 1); - d_stream.next_out = page + PAGE_ZIP_START; d_stream.avail_out = UNIV_PAGE_SIZE - PAGE_ZIP_START; + if (UNIV_UNLIKELY(inflateInit2(&d_stream, UNIV_PAGE_SIZE_SHIFT) + != Z_OK)) { + ut_error; + } + /* Decode the zlib header and the index information. */ if (UNIV_UNLIKELY(inflate(&d_stream, Z_BLOCK) != Z_OK)) { @@ -3462,9 +3501,7 @@ page_zip_write_rec( } /* Write the data bytes. Store the uncompressed bytes separately. */ - storage = page_zip->data + page_zip_get_size(page_zip) - - (page_dir_get_n_heap(page) - PAGE_HEAP_NO_USER_LOW) - * PAGE_ZIP_DIR_SLOT_SIZE; + storage = page_zip_dir_start(page_zip); if (page_is_leaf(page)) { ulint len; @@ -3760,9 +3797,7 @@ corrupt: field = page + offset; storage = page_zip->data + z_offset; - storage_end = page_zip->data + page_zip_get_size(page_zip) - - (page_dir_get_n_heap(page) - PAGE_HEAP_NO_USER_LOW) - * PAGE_ZIP_DIR_SLOT_SIZE; + storage_end = page_zip_dir_start(page_zip); heap_no = 1 + (storage_end - storage) / REC_NODE_PTR_SIZE; @@ -3798,7 +3833,9 @@ page_zip_write_node_ptr( { byte* field; byte* storage; +#ifdef UNIV_DEBUG page_t* page = page_align(rec); +#endif /* UNIV_DEBUG */ ut_ad(PAGE_ZIP_MATCH(rec, page_zip)); ut_ad(page_simple_validate_new(page)); @@ -3815,9 +3852,7 @@ page_zip_write_node_ptr( UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip)); UNIV_MEM_ASSERT_RW(rec, size); - storage = page_zip->data + page_zip_get_size(page_zip) - - (page_dir_get_n_heap(page) - PAGE_HEAP_NO_USER_LOW) - * PAGE_ZIP_DIR_SLOT_SIZE + storage = page_zip_dir_start(page_zip) - (rec_get_heap_no_new(rec) - 1) * REC_NODE_PTR_SIZE; field = rec + size - REC_NODE_PTR_SIZE; @@ -3866,7 +3901,9 @@ page_zip_write_trx_id_and_roll_ptr( { byte* field; byte* storage; +#ifdef UNIV_DEBUG page_t* page = page_align(rec); +#endif /* UNIV_DEBUG */ ulint len; ut_ad(PAGE_ZIP_MATCH(rec, page_zip)); @@ -3884,9 +3921,7 @@ page_zip_write_trx_id_and_roll_ptr( UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip)); - storage = page_zip->data + page_zip_get_size(page_zip) - - (page_dir_get_n_heap(page) - PAGE_HEAP_NO_USER_LOW) - * PAGE_ZIP_DIR_SLOT_SIZE + storage = page_zip_dir_start(page_zip) - (rec_get_heap_no_new(rec) - 1) * (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN); @@ -3917,17 +3952,9 @@ page_zip_write_trx_id_and_roll_ptr( UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip)); } -#ifdef UNIV_ZIP_DEBUG -/** Set this variable in a debugger to disable page_zip_clear_rec(). -The only observable effect should be the compression ratio due to -deleted records not being zeroed out. In rare cases, there can be -page_zip_validate() failures on the node_ptr, trx_id and roll_ptr -columns if the space is reallocated for a smaller record. */ -UNIV_INTERN ibool page_zip_clear_rec_disable; -#endif /* UNIV_ZIP_DEBUG */ - /**********************************************************************//** -Clear an area on the uncompressed and compressed page, if possible. */ +Clear an area on the uncompressed and compressed page. +Do not clear the data payload, as that would grow the modification log. */ static void page_zip_clear_rec( @@ -3939,6 +3966,9 @@ page_zip_clear_rec( { ulint heap_no; page_t* page = page_align(rec); + byte* storage; + byte* field; + ulint len; /* page_zip_validate() would fail here if a record containing externally stored columns is being deleted. */ ut_ad(rec_offs_validate(rec, index, offsets)); @@ -3954,60 +3984,38 @@ page_zip_clear_rec( UNIV_MEM_ASSERT_RW(rec - rec_offs_extra_size(offsets), rec_offs_extra_size(offsets)); - if ( -#ifdef UNIV_ZIP_DEBUG - !page_zip_clear_rec_disable && -#endif /* UNIV_ZIP_DEBUG */ - page_zip->m_end - + 1 + ((heap_no - 1) >= 64)/* size of the log entry */ - + page_zip_get_trailer_len(page_zip, - dict_index_is_clust(index), NULL) - < page_zip_get_size(page_zip)) { - byte* data; + if (!page_is_leaf(page)) { + /* Clear node_ptr. On the compressed page, + there is an array of node_ptr immediately before the + dense page directory, at the very end of the page. */ + storage = page_zip_dir_start(page_zip); + ut_ad(dict_index_get_n_unique_in_tree(index) == + rec_offs_n_fields(offsets) - 1); + field = rec_get_nth_field(rec, offsets, + rec_offs_n_fields(offsets) - 1, + &len); + ut_ad(len == REC_NODE_PTR_SIZE); - /* Clear only the data bytes, because the allocator and - the decompressor depend on the extra bytes. */ - memset(rec, 0, rec_offs_data_size(offsets)); + ut_ad(!rec_offs_any_extern(offsets)); + memset(field, 0, REC_NODE_PTR_SIZE); + memset(storage - (heap_no - 1) * REC_NODE_PTR_SIZE, + 0, REC_NODE_PTR_SIZE); + } else if (dict_index_is_clust(index)) { + /* Clear trx_id and roll_ptr. On the compressed page, + there is an array of these fields immediately before the + dense page directory, at the very end of the page. */ + const ulint trx_id_pos + = dict_col_get_clust_pos( + dict_table_get_sys_col( + index->table, DATA_TRX_ID), index); + storage = page_zip_dir_start(page_zip); + field = rec_get_nth_field(rec, offsets, trx_id_pos, &len); + ut_ad(len == DATA_TRX_ID_LEN); - if (!page_is_leaf(page)) { - /* Clear node_ptr on the compressed page. */ - byte* storage = page_zip->data - + page_zip_get_size(page_zip) - - (page_dir_get_n_heap(page) - - PAGE_HEAP_NO_USER_LOW) - * PAGE_ZIP_DIR_SLOT_SIZE; - - memset(storage - (heap_no - 1) * REC_NODE_PTR_SIZE, - 0, REC_NODE_PTR_SIZE); - } else if (dict_index_is_clust(index)) { - /* Clear trx_id and roll_ptr on the compressed page. */ - byte* storage = page_zip->data - + page_zip_get_size(page_zip) - - (page_dir_get_n_heap(page) - - PAGE_HEAP_NO_USER_LOW) - * PAGE_ZIP_DIR_SLOT_SIZE; - - memset(storage - (heap_no - 1) - * (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN), - 0, DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN); - } - - /* Log that the data was zeroed out. */ - data = page_zip->data + page_zip->m_end; - ut_ad(!*data); - if (UNIV_UNLIKELY(heap_no - 1 >= 64)) { - *data++ = (byte) (0x80 | (heap_no - 1) >> 7); - ut_ad(!*data); - } - *data++ = (byte) ((heap_no - 1) << 1 | 1); - ut_ad(!*data); - ut_ad((ulint) (data - page_zip->data) - < page_zip_get_size(page_zip)); - page_zip->m_end = data - page_zip->data; - page_zip->m_nonempty = TRUE; - } else if (page_is_leaf(page) && dict_index_is_clust(index)) { - /* Do not clear the record, because there is not enough space - to log the operation. */ + memset(field, 0, DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN); + memset(storage - (heap_no - 1) + * (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN), + 0, DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN); if (rec_offs_any_extern(offsets)) { ulint i; @@ -4016,15 +4024,18 @@ page_zip_clear_rec( /* Clear all BLOB pointers in order to make page_zip_validate() pass. */ if (rec_offs_nth_extern(offsets, i)) { - ulint len; - byte* field = rec_get_nth_field( + field = rec_get_nth_field( rec, offsets, i, &len); + ut_ad(len + == BTR_EXTERN_FIELD_REF_SIZE); memset(field + len - BTR_EXTERN_FIELD_REF_SIZE, 0, BTR_EXTERN_FIELD_REF_SIZE); } } } + } else { + ut_ad(!rec_offs_any_extern(offsets)); } #ifdef UNIV_ZIP_DEBUG @@ -4455,6 +4466,8 @@ page_zip_reorganize( /* Copy the old page to temporary space */ buf_frame_copy(temp_page, page); + btr_blob_dbg_remove(page, index, "zip_reorg"); + /* Recreate the page: note that global data on page (possible segment headers, next page-field, etc.) is preserved intact */ @@ -4513,7 +4526,7 @@ page_zip_copy_recs( mtr_t* mtr) /*!< in: mini-transaction */ { ut_ad(mtr_memo_contains_page(mtr, page, MTR_MEMO_PAGE_X_FIX)); - ut_ad(mtr_memo_contains_page(mtr, (page_t*) src, MTR_MEMO_PAGE_X_FIX)); + ut_ad(mtr_memo_contains_page(mtr, src, MTR_MEMO_PAGE_X_FIX)); ut_ad(!dict_index_is_ibuf(index)); #ifdef UNIV_ZIP_DEBUG /* The B-tree operations that call this function may set @@ -4583,6 +4596,7 @@ page_zip_copy_recs( #ifdef UNIV_ZIP_DEBUG ut_a(page_zip_validate(page_zip, page)); #endif /* UNIV_ZIP_DEBUG */ + btr_blob_dbg_add(page, index, "page_zip_copy_recs"); page_zip_compress_write_log(page_zip, page, index, mtr); } diff --git a/que/que0que.c b/que/que0que.c index 9c1d61c1731..5fccbb180fe 100644 --- a/que/que0que.c +++ b/que/que0que.c @@ -1418,6 +1418,12 @@ que_eval_sql( ut_a(trx->error_state == DB_SUCCESS); + if (trx->fake_changes) { + /* fake_changes should not access to system tables */ + fprintf(stderr, "InnoDB: ERROR: innodb_fake_changes tried to access to system tables.\n"); + return(DB_ERROR); + } + if (reserve_dict_mutex) { mutex_enter(&dict_sys->mutex); } diff --git a/rem/rem0rec.c b/rem/rem0rec.c index 37ba8ca2ffe..9f90d2940dd 100644 --- a/rem/rem0rec.c +++ b/rem/rem0rec.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2010, 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 @@ -408,7 +408,7 @@ rec_init_offsets( do { ulint len; if (UNIV_UNLIKELY(i == n_node_ptr_field)) { - len = offs += 4; + len = offs += REC_NODE_PTR_SIZE; goto resolved; } @@ -640,7 +640,7 @@ rec_get_offsets_reverse( do { ulint len; if (UNIV_UNLIKELY(i == n_node_ptr_field)) { - len = offs += 4; + len = offs += REC_NODE_PTR_SIZE; goto resolved; } @@ -1131,9 +1131,9 @@ rec_convert_dtuple_to_rec_comp( if (UNIV_UNLIKELY(i == n_node_ptr_field)) { ut_ad(dtype_get_prtype(type) & DATA_NOT_NULL); - ut_ad(len == 4); + ut_ad(len == REC_NODE_PTR_SIZE); memcpy(end, dfield_get_data(field), len); - end += 4; + end += REC_NODE_PTR_SIZE; break; } diff --git a/row/row0ins.c b/row/row0ins.c index efcea62f212..0e62185c02e 100644 --- a/row/row0ins.c +++ b/row/row0ins.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2010, 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 @@ -345,9 +345,9 @@ row_ins_clust_index_entry_by_modify( return(DB_LOCK_TABLE_FULL); } - err = btr_cur_pessimistic_update(0, cursor, - heap, big_rec, update, - 0, thr, mtr); + err = btr_cur_pessimistic_update( + BTR_KEEP_POS_FLAG, cursor, heap, big_rec, update, + 0, thr, mtr); } return(err); @@ -1512,6 +1512,11 @@ exit_func: if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); } + + if (trx->fake_changes) { + err = DB_SUCCESS; + } + return(err); } @@ -1992,6 +1997,7 @@ row_ins_index_entry_low( ulint modify = 0; /* remove warning */ rec_t* insert_rec; rec_t* rec; + ulint* offsets; ulint err; ulint n_unique; big_rec_t* big_rec = NULL; @@ -2013,7 +2019,7 @@ row_ins_index_entry_low( } btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE, - mode | BTR_INSERT | ignore_sec_unique, + thr_get_trx(thr)->fake_changes ? BTR_SEARCH_LEAF : (mode | BTR_INSERT | ignore_sec_unique), &cursor, 0, __FILE__, __LINE__, &mtr); if (cursor.flag == BTR_CUR_INSERT_TO_IBUF) { @@ -2073,7 +2079,7 @@ row_ins_index_entry_low( btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE, - mode | BTR_INSERT, + thr_get_trx(thr)->fake_changes ? BTR_SEARCH_LEAF : (mode | BTR_INSERT), &cursor, 0, __FILE__, __LINE__, &mtr); } @@ -2097,6 +2103,42 @@ row_ins_index_entry_low( err = row_ins_clust_index_entry_by_modify( mode, &cursor, &heap, &big_rec, entry, thr, &mtr); + + if (big_rec) { + ut_a(err == DB_SUCCESS); + /* Write out the externally stored + columns while still x-latching + index->lock and block->lock. We have + to mtr_commit(mtr) first, so that the + redo log will be written in the + correct order. Otherwise, we would run + into trouble on crash recovery if mtr + freed B-tree pages on which some of + the big_rec fields will be written. */ + btr_cur_mtr_commit_and_start(&cursor, &mtr); + + rec = btr_cur_get_rec(&cursor); + offsets = rec_get_offsets( + rec, index, NULL, + ULINT_UNDEFINED, &heap); + + err = btr_store_big_rec_extern_fields( + index, btr_cur_get_block(&cursor), + rec, offsets, &mtr, FALSE, big_rec); + /* If writing big_rec fails (for + example, because of DB_OUT_OF_FILE_SPACE), + the record will be corrupted. Even if + we did not update any externally + stored columns, our update could cause + the record to grow so that a + non-updated column was selected for + external storage. This non-update + would not have been written to the + undo log, and thus the record cannot + be rolled back. */ + ut_a(err == DB_SUCCESS); + goto stored_big_rec; + } } else { ut_ad(!n_ext); err = row_ins_sec_index_entry_by_modify( @@ -2125,8 +2167,22 @@ function_exit: mtr_commit(&mtr); if (UNIV_LIKELY_NULL(big_rec)) { - rec_t* rec; - ulint* offsets; + + if (thr_get_trx(thr)->fake_changes) { + /* skip store extern */ + if (modify) { + dtuple_big_rec_free(big_rec); + } else { + dtuple_convert_back_big_rec(index, entry, big_rec); + } + + if (UNIV_LIKELY_NULL(heap)) { + mem_heap_free(heap); + } + + return(err); + } + mtr_start(&mtr); btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE, @@ -2140,6 +2196,7 @@ function_exit: index, btr_cur_get_block(&cursor), rec, offsets, &mtr, FALSE, big_rec); +stored_big_rec: if (modify) { dtuple_big_rec_free(big_rec); } else { diff --git a/row/row0merge.c b/row/row0merge.c index 782c029fbcc..9842473865d 100644 --- a/row/row0merge.c +++ b/row/row0merge.c @@ -56,6 +56,7 @@ Completed by Sunny Bains and Marko Makela #include "log0log.h" #include "ut0sort.h" #include "handler0alter.h" +#include "ha_prototypes.h" #ifdef UNIV_DEBUG /** Set these in order ot enable debug printout. */ @@ -2630,6 +2631,9 @@ row_merge_build_indexes( } } + if (trx->mysql_thd && thd_expand_fast_index_creation(trx->mysql_thd)) + dict_update_statistics(new_table, FALSE, TRUE); + func_exit: close(tmpfd); diff --git a/row/row0mysql.c b/row/row0mysql.c index 2728b3d66d9..9595f8c22e0 100644 --- a/row/row0mysql.c +++ b/row/row0mysql.c @@ -1189,6 +1189,7 @@ run_again: prebuilt->table->stat_n_rows--; } + if (!(trx->fake_changes)) row_update_statistics_if_needed(prebuilt->table); trx->op_info = ""; @@ -1449,6 +1450,7 @@ run_again: that changes indexed columns, UPDATEs that change only non-indexed columns would not affect statistics. */ if (node->is_delete || !(node->cmpl_info & UPD_NODE_NO_ORD_CHANGE)) { + if (!(trx->fake_changes)) row_update_statistics_if_needed(prebuilt->table); } @@ -1667,6 +1669,7 @@ run_again: srv_n_rows_updated++; } + if (!(trx->fake_changes)) row_update_statistics_if_needed(table); return(err); @@ -2555,10 +2558,29 @@ row_discard_tablespace_for_mysql( err = DB_ERROR; } else { + dict_index_t* index; + /* Set the flag which tells that now it is legal to IMPORT a tablespace for this table */ table->tablespace_discarded = TRUE; table->ibd_file_missing = TRUE; + + /* check adaptive hash entries */ + index = dict_table_get_first_index(table); + while (index) { + ulint ref_count = btr_search_info_get_ref_count(index->search_info); + if (ref_count) { + fprintf(stderr, "InnoDB: Warning:" + " hash index ref_count (%lu) is not zero" + " after fil_discard_tablespace().\n" + "index: \"%s\"" + " table: \"%s\"\n", + ref_count, + index->name, + table->name); + } + index = dict_table_get_next_index(index); + } } } @@ -2596,6 +2618,11 @@ row_import_tablespace_for_mysql( current_lsn = log_get_lsn(); + /* Enlarge the fatal lock wait timeout during import. */ + mutex_enter(&kernel_mutex); + srv_fatal_semaphore_wait_threshold += 7200; /* 2 hours */ + mutex_exit(&kernel_mutex); + /* 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 merge, or rollback was performed on a backup @@ -2707,6 +2734,11 @@ funct_exit: trx->op_info = ""; + /* Restore the fatal semaphore wait timeout */ + mutex_enter(&kernel_mutex); + srv_fatal_semaphore_wait_threshold -= 7200; /* 2 hours */ + mutex_exit(&kernel_mutex); + return((int) err); } @@ -2900,6 +2932,19 @@ row_truncate_table_for_mysql( table->space = space; index = dict_table_get_first_index(table); do { + ulint ref_count = btr_search_info_get_ref_count(index->search_info); + /* check adaptive hash entries */ + if (ref_count) { + fprintf(stderr, "InnoDB: Warning:" + " hash index ref_count (%lu) is not zero" + " after fil_discard_tablespace().\n" + "index: \"%s\"" + " table: \"%s\"\n", + ref_count, + index->name, + table->name); + } + index->space = space; index = dict_table_get_next_index(index); } while (index); diff --git a/row/row0row.c b/row/row0row.c index 0783d482f76..cea70e98dee 100644 --- a/row/row0row.c +++ b/row/row0row.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2010, 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 @@ -47,35 +47,6 @@ Created 4/20/1996 Heikki Tuuri #include "read0read.h" #include "ut0mem.h" -/*********************************************************************//** -Gets the offset of trx id field, in bytes relative to the origin of -a clustered index record. -@return offset of DATA_TRX_ID */ -UNIV_INTERN -ulint -row_get_trx_id_offset( -/*==================*/ - const rec_t* rec __attribute__((unused)), - /*!< in: record */ - dict_index_t* index, /*!< in: clustered index */ - const ulint* offsets)/*!< in: rec_get_offsets(rec, index) */ -{ - ulint pos; - ulint offset; - ulint len; - - ut_ad(dict_index_is_clust(index)); - ut_ad(rec_offs_validate(rec, index, offsets)); - - pos = dict_index_get_sys_col_pos(index, DATA_TRX_ID); - - offset = rec_get_nth_field_offs(offsets, pos, &len); - - ut_ad(len == DATA_TRX_ID_LEN); - - return(offset); -} - /*****************************************************************//** When an insert or purge to a table is performed, this function builds the entry to be inserted into or purged from an index on the table. @@ -130,12 +101,27 @@ row_build_index_entry( dfield_copy(dfield, dfield2); - if (dfield_is_null(dfield) || ind_field->prefix_len == 0) { + if (dfield_is_null(dfield)) { continue; } - /* If a column prefix index, take only the prefix. - Prefix-indexed columns may be externally stored. */ + if (ind_field->prefix_len == 0 + && (!dfield_is_ext(dfield) + || dict_index_is_clust(index))) { + /* The dfield_copy() above suffices for + columns that are stored in-page, or for + clustered index record columns that are not + part of a column prefix in the PRIMARY KEY. */ + continue; + } + + /* If the column is stored externally (off-page) in + the clustered index, it must be an ordering field in + the secondary index. In the Antelope format, only + prefix-indexed columns may be stored off-page in the + clustered index record. In the Barracuda format, also + fully indexed long CHAR or VARCHAR columns may be + stored off-page. */ ut_ad(col->ord_part); if (UNIV_LIKELY_NULL(ext)) { @@ -148,17 +134,41 @@ row_build_index_entry( } dfield_set_data(dfield, buf, len); } + + if (ind_field->prefix_len == 0) { + /* In the Barracuda format + (ROW_FORMAT=DYNAMIC or + ROW_FORMAT=COMPRESSED), we can have a + secondary index on an entire column + that is stored off-page in the + clustered index. As this is not a + prefix index (prefix_len == 0), + include the entire off-page column in + the secondary index record. */ + continue; + } } else if (dfield_is_ext(dfield)) { + /* This table is either in Antelope format + (ROW_FORMAT=REDUNDANT or ROW_FORMAT=COMPACT) + or a purge record where the ordered part of + the field is not external. + In Antelope, the maximum column prefix + index length is 767 bytes, and the clustered + index record contains a 768-byte prefix of + each off-page column. */ ut_a(len >= BTR_EXTERN_FIELD_REF_SIZE); len -= BTR_EXTERN_FIELD_REF_SIZE; - ut_a(ind_field->prefix_len <= len - || dict_index_is_clust(index)); + dfield_set_len(dfield, len); } - len = dtype_get_at_most_n_mbchars( - col->prtype, col->mbminlen, col->mbmaxlen, - ind_field->prefix_len, len, dfield_get_data(dfield)); - dfield_set_len(dfield, len); + /* If a column prefix index, take only the prefix. */ + if (ind_field->prefix_len) { + len = dtype_get_at_most_n_mbchars( + col->prtype, col->mbminlen, col->mbmaxlen, + ind_field->prefix_len, len, + dfield_get_data(dfield)); + dfield_set_len(dfield, len); + } } ut_ad(dtuple_check_typed(entry)); @@ -223,6 +233,7 @@ row_build( ut_ad(index && rec && heap); ut_ad(dict_index_is_clust(index)); + ut_ad(!mutex_own(&kernel_mutex)); if (!offsets) { offsets = rec_get_offsets(rec, index, offsets_, @@ -231,6 +242,22 @@ row_build( ut_ad(rec_offs_validate(rec, index, offsets)); } +#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG + /* This condition can occur during crash recovery before + trx_rollback_active() has completed execution. + + This condition is possible if the server crashed + during an insert or update before + btr_store_big_rec_extern_fields() did mtr_commit() all + BLOB pointers to the clustered index record. + + If the record contains a null BLOB pointer, look up the + transaction that holds the implicit lock on this record, and + assert that it was recovered (and will soon be rolled back). */ + ut_a(!rec_offs_any_null_extern(rec, offsets) + || trx_assert_recovered(row_get_rec_trx_id(rec, index, offsets))); +#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ + if (type != ROW_COPY_POINTERS) { /* Take a copy of rec to heap */ buf = mem_heap_alloc(heap, rec_offs_size(offsets)); @@ -431,6 +458,10 @@ row_rec_to_index_entry( rec = rec_copy(buf, rec, offsets); /* Avoid a debug assertion in rec_offs_validate(). */ rec_offs_make_valid(rec, index, offsets); +#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG + } else { + ut_a(!rec_offs_any_null_extern(rec, offsets)); +#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ } entry = row_rec_to_index_entry_low(rec, index, offsets, n_ext, heap); diff --git a/row/row0sel.c b/row/row0sel.c index d8fc99bd9fc..36d71c94659 100644 --- a/row/row0sel.c +++ b/row/row0sel.c @@ -2544,6 +2544,8 @@ row_sel_field_store_in_mysql_format( ut_ad(len != UNIV_SQL_NULL); UNIV_MEM_ASSERT_RW(data, len); + UNIV_MEM_ASSERT_W(dest, templ->mysql_col_len); + UNIV_MEM_INVALID(dest, templ->mysql_col_len); switch (templ->type) { case DATA_INT: @@ -2580,14 +2582,16 @@ row_sel_field_store_in_mysql_format( dest = row_mysql_store_true_var_len( dest, len, templ->mysql_length_bytes); + /* Copy the actual data. Leave the rest of the + buffer uninitialized. */ + memcpy(dest, data, len); + break; } /* Copy the actual data */ ut_memcpy(dest, data, len); - /* Pad with trailing spaces. We pad with spaces also the - unused end of a >= 5.0.3 true VARCHAR column, just in case - MySQL expects its contents to be deterministic. */ + /* Pad with trailing spaces. */ pad_ptr = dest + len; @@ -3119,6 +3123,39 @@ sel_restore_position_for_mysql( return(TRUE); } +/********************************************************************//** +Copies a cached field for MySQL from the fetch cache. */ +static +void +row_sel_copy_cached_field_for_mysql( +/*================================*/ + byte* buf, /*!< in/out: row buffer */ + const byte* cache, /*!< in: cached row */ + const mysql_row_templ_t*templ) /*!< in: column template */ +{ + ulint len; + + buf += templ->mysql_col_offset; + cache += templ->mysql_col_offset; + + UNIV_MEM_ASSERT_W(buf, templ->mysql_col_len); + + if (templ->mysql_type == DATA_MYSQL_TRUE_VARCHAR + && templ->type != DATA_INT) { + /* Check for != DATA_INT to make sure we do + not treat MySQL ENUM or SET as a true VARCHAR! + Find the actual length of the true VARCHAR field. */ + row_mysql_read_true_varchar( + &len, cache, templ->mysql_length_bytes); + len += templ->mysql_length_bytes; + UNIV_MEM_INVALID(buf, templ->mysql_col_len); + } else { + len = templ->mysql_col_len; + } + + ut_memcpy(buf, cache, len); +} + /********************************************************************//** Pops a cached row for MySQL from the fetch cache. */ UNIV_INLINE @@ -3131,26 +3168,22 @@ row_sel_pop_cached_row_for_mysql( { ulint i; const mysql_row_templ_t*templ; - byte* cached_rec; + const byte* cached_rec; ut_ad(prebuilt->n_fetch_cached > 0); ut_ad(prebuilt->mysql_prefix_len <= prebuilt->mysql_row_len); + UNIV_MEM_ASSERT_W(buf, prebuilt->mysql_row_len); + + cached_rec = prebuilt->fetch_cache[prebuilt->fetch_cache_first]; + if (UNIV_UNLIKELY(prebuilt->keep_other_fields_on_keyread)) { /* Copy cache record field by field, don't touch fields that are not covered by current key */ - cached_rec = prebuilt->fetch_cache[ - prebuilt->fetch_cache_first]; for (i = 0; i < prebuilt->n_template; i++) { templ = prebuilt->mysql_template + i; -#if 0 /* Some of the cached_rec may legitimately be uninitialized. */ - UNIV_MEM_ASSERT_RW(cached_rec - + templ->mysql_col_offset, - templ->mysql_col_len); -#endif - ut_memcpy(buf + templ->mysql_col_offset, - cached_rec + templ->mysql_col_offset, - templ->mysql_col_len); + row_sel_copy_cached_field_for_mysql( + buf, cached_rec, templ); /* Copy NULL bit of the current field from cached_rec to buf */ if (templ->mysql_null_bit_mask) { @@ -3160,17 +3193,24 @@ row_sel_pop_cached_row_for_mysql( & (byte)templ->mysql_null_bit_mask; } } + } else if (prebuilt->mysql_prefix_len > 63) { + /* The record is long. Copy it field by field, in case + there are some long VARCHAR column of which only a + small length is being used. */ + UNIV_MEM_INVALID(buf, prebuilt->mysql_prefix_len); + + /* First copy the NULL bits. */ + ut_memcpy(buf, cached_rec, prebuilt->null_bitmap_len); + /* Then copy the requested fields. */ + + for (i = 0; i < prebuilt->n_template; i++) { + row_sel_copy_cached_field_for_mysql( + buf, cached_rec, prebuilt->mysql_template + i); + } + } else { + ut_memcpy(buf, cached_rec, prebuilt->mysql_prefix_len); } - else { -#if 0 /* Some of the cached_rec may legitimately be uninitialized. */ - UNIV_MEM_ASSERT_RW(prebuilt->fetch_cache - [prebuilt->fetch_cache_first], - prebuilt->mysql_prefix_len); -#endif - ut_memcpy(buf, - prebuilt->fetch_cache[prebuilt->fetch_cache_first], - prebuilt->mysql_prefix_len); - } + prebuilt->n_fetch_cached--; prebuilt->fetch_cache_first++; @@ -3958,7 +3998,13 @@ rec_loop: if (UNIV_UNLIKELY(next_offs >= UNIV_PAGE_SIZE - PAGE_DIR)) { wrong_offs: - if (srv_force_recovery == 0 || moves_up == FALSE) { + if (srv_pass_corrupt_table && !trx_sys_sys_space(index->table->space)) { + index->table->is_corrupt = TRUE; + fil_space_set_corrupt(index->table->space); + } + + if ((srv_force_recovery == 0 || moves_up == FALSE) + && srv_pass_corrupt_table <= 1) { ut_print_timestamp(stderr); buf_page_print(page_align(rec), 0); fprintf(stderr, @@ -4009,7 +4055,8 @@ wrong_offs: offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap); - if (UNIV_UNLIKELY(srv_force_recovery > 0)) { + if (UNIV_UNLIKELY(srv_force_recovery > 0) + || (srv_pass_corrupt_table == 2 && index->table->is_corrupt)) { if (!rec_validate(rec, offsets) || !btr_index_rec_validate(rec, index, FALSE)) { fprintf(stderr, diff --git a/row/row0upd.c b/row/row0upd.c index ba4096f8d4d..247a1b298f0 100644 --- a/row/row0upd.c +++ b/row/row0upd.c @@ -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 @@ -504,14 +504,49 @@ row_upd_rec_in_place( n_fields = upd_get_n_fields(update); for (i = 0; i < n_fields; i++) { +#ifdef UNIV_BLOB_DEBUG + btr_blob_dbg_t b; + const byte* field_ref = NULL; +#endif /* UNIV_BLOB_DEBUG */ + upd_field = upd_get_nth_field(update, i); new_val = &(upd_field->new_val); ut_ad(!dfield_is_ext(new_val) == !rec_offs_nth_extern(offsets, upd_field->field_no)); +#ifdef UNIV_BLOB_DEBUG + if (dfield_is_ext(new_val)) { + ulint len; + field_ref = rec_get_nth_field(rec, offsets, i, &len); + ut_a(len != UNIV_SQL_NULL); + ut_a(len >= BTR_EXTERN_FIELD_REF_SIZE); + field_ref += len - BTR_EXTERN_FIELD_REF_SIZE; + + b.ref_page_no = page_get_page_no(page_align(rec)); + b.ref_heap_no = page_rec_get_heap_no(rec); + b.ref_field_no = i; + b.blob_page_no = mach_read_from_4( + field_ref + BTR_EXTERN_PAGE_NO); + ut_a(b.ref_field_no >= index->n_uniq); + btr_blob_dbg_rbt_delete(index, &b, "upd_in_place"); + } +#endif /* UNIV_BLOB_DEBUG */ rec_set_nth_field(rec, offsets, upd_field->field_no, dfield_get_data(new_val), dfield_get_len(new_val)); + +#ifdef UNIV_BLOB_DEBUG + if (dfield_is_ext(new_val)) { + b.blob_page_no = mach_read_from_4( + field_ref + BTR_EXTERN_PAGE_NO); + b.always_owner = b.owner = !(field_ref[BTR_EXTERN_LEN] + & BTR_EXTERN_OWNER_FLAG); + b.del = rec_get_deleted_flag( + rec, rec_offs_comp(offsets)); + + btr_blob_dbg_rbt_insert(index, &b, "upd_in_place"); + } +#endif /* UNIV_BLOB_DEBUG */ } if (UNIV_LIKELY_NULL(page_zip)) { @@ -1556,8 +1591,9 @@ row_upd_sec_index_entry( mtr_start(&mtr); - found = row_search_index_entry(index, entry, BTR_MODIFY_LEAF, &pcur, - &mtr); + found = row_search_index_entry(index, entry, + trx->fake_changes ? BTR_SEARCH_LEAF : BTR_MODIFY_LEAF, + &pcur, &mtr); btr_cur = btr_pcur_get_btr_cur(&pcur); rec = btr_cur_get_rec(btr_cur); @@ -1787,9 +1823,11 @@ row_upd_clust_rec_by_insert( the previous invocation of this function. Mark the off-page columns in the entry inherited. */ + if (!(trx->fake_changes)) { change_ownership = row_upd_clust_rec_by_insert_inherit( NULL, NULL, entry, node->update); ut_a(change_ownership); + } /* fall through */ case UPD_NODE_INSERT_CLUSTERED: /* A lock wait occurred in row_ins_index_entry() in @@ -1819,7 +1857,7 @@ err_exit: delete-marked old record, mark them disowned by the old record and owned by the new entry. */ - if (rec_offs_any_extern(offsets)) { + if (rec_offs_any_extern(offsets) && !(trx->fake_changes)) { change_ownership = row_upd_clust_rec_by_insert_inherit( rec, offsets, entry, node->update); @@ -1947,33 +1985,50 @@ row_upd_clust_rec( the same transaction do not modify the record in the meantime. Therefore we can assert that the restoration of the cursor succeeds. */ - ut_a(btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, mtr)); + ut_a(btr_pcur_restore_position(thr_get_trx(thr)->fake_changes ? BTR_SEARCH_LEAF : BTR_MODIFY_TREE, + pcur, mtr)); ut_ad(!rec_get_deleted_flag(btr_pcur_get_rec(pcur), dict_table_is_comp(index->table))); - err = btr_cur_pessimistic_update(BTR_NO_LOCKING_FLAG, btr_cur, - &heap, &big_rec, node->update, - node->cmpl_info, thr, mtr); - mtr_commit(mtr); - - if (err == DB_SUCCESS && big_rec) { + err = btr_cur_pessimistic_update( + BTR_NO_LOCKING_FLAG | BTR_KEEP_POS_FLAG, btr_cur, + &heap, &big_rec, node->update, node->cmpl_info, thr, mtr); + /* skip store extern for fake_changes */ + if (big_rec && !(thr_get_trx(thr)->fake_changes)) { ulint offsets_[REC_OFFS_NORMAL_SIZE]; rec_t* rec; rec_offs_init(offsets_); - mtr_start(mtr); + ut_a(err == DB_SUCCESS); + /* Write out the externally stored columns while still + x-latching index->lock and block->lock. We have to + mtr_commit(mtr) first, so that the redo log will be + written in the correct order. Otherwise, we would run + into trouble on crash recovery if mtr freed B-tree + pages on which some of the big_rec fields will be + written. */ + btr_cur_mtr_commit_and_start(btr_cur, mtr); - ut_a(btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, mtr)); rec = btr_cur_get_rec(btr_cur); err = btr_store_big_rec_extern_fields( index, btr_cur_get_block(btr_cur), rec, rec_get_offsets(rec, index, offsets_, ULINT_UNDEFINED, &heap), mtr, TRUE, big_rec); - mtr_commit(mtr); + /* If writing big_rec fails (for example, because of + DB_OUT_OF_FILE_SPACE), the record will be corrupted. + Even if we did not update any externally stored + columns, our update could cause the record to grow so + that a non-updated column was selected for external + storage. This non-update would not have been written + to the undo log, and thus the record cannot be rolled + back. */ + ut_a(err == DB_SUCCESS); } + mtr_commit(mtr); + if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); } @@ -2082,7 +2137,8 @@ row_upd_clust_step( ut_a(pcur->rel_pos == BTR_PCUR_ON); - success = btr_pcur_restore_position(BTR_MODIFY_LEAF, pcur, mtr); + success = btr_pcur_restore_position(thr_get_trx(thr)->fake_changes ? BTR_SEARCH_LEAF : BTR_MODIFY_LEAF, + pcur, mtr); if (!success) { err = DB_RECORD_NOT_FOUND; diff --git a/row/row0vers.c b/row/row0vers.c index d4fde0b939b..8a7bb842293 100644 --- a/row/row0vers.c +++ b/row/row0vers.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1997, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1997, 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 @@ -550,6 +550,11 @@ row_vers_build_for_consistent_read( /* The view already sees this version: we can copy it to in_heap and return */ +#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG + ut_a(!rec_offs_any_null_extern( + version, *offsets)); +#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ + buf = mem_heap_alloc(in_heap, rec_offs_size(*offsets)); *old_vers = rec_copy(buf, version, *offsets); @@ -583,6 +588,10 @@ row_vers_build_for_consistent_read( *offsets = rec_get_offsets(prev_version, index, *offsets, ULINT_UNDEFINED, offset_heap); +#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG + ut_a(!rec_offs_any_null_extern(prev_version, *offsets)); +#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ + trx_id = row_get_rec_trx_id(prev_version, index, *offsets); if (read_view_sees_trx_id(view, trx_id)) { @@ -682,6 +691,10 @@ row_vers_build_for_semi_consistent_read( /* We found a version that belongs to a committed transaction: return it. */ +#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG + ut_a(!rec_offs_any_null_extern(version, *offsets)); +#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ + if (rec == version) { *old_vers = rec; err = DB_SUCCESS; @@ -739,6 +752,9 @@ row_vers_build_for_semi_consistent_read( version = prev_version; *offsets = rec_get_offsets(version, index, *offsets, ULINT_UNDEFINED, offset_heap); +#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG + ut_a(!rec_offs_any_null_extern(version, *offsets)); +#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ }/* for (;;) */ if (heap) { diff --git a/srv/srv0srv.c b/srv/srv0srv.c index 0b68574317f..c593c49336f 100644 --- a/srv/srv0srv.c +++ b/srv/srv0srv.c @@ -86,6 +86,11 @@ Created 10/8/1995 Heikki Tuuri #include "trx0i_s.h" #include "os0sync.h" /* for HAVE_ATOMIC_BUILTINS */ +/* prototypes of new functions added to ha_innodb.cc for kill_idle_transaction */ +ibool innobase_thd_is_idle(const void* thd); +ib_int64_t innobase_thd_get_start_time(const void* thd); +void innobase_thd_kill(void* thd); + /* prototypes for new functions added to ha_innodb.cc */ ibool innobase_get_slow_log(); @@ -100,6 +105,9 @@ UNIV_INTERN ulint srv_activity_count = 0; /* The following is the maximum allowed duration of a lock wait. */ UNIV_INTERN ulint srv_fatal_semaphore_wait_threshold = 600; +/**/ +UNIV_INTERN lint srv_kill_idle_transaction = 0; + /* How much data manipulation language (DML) statements need to be delayed, in microseconds, in order to reduce the lagging of the purge thread. */ UNIV_INTERN ulint srv_dml_needed_delay = 0; @@ -211,17 +219,15 @@ UNIV_INTERN ulint srv_buf_pool_curr_size = 0; UNIV_INTERN ulint srv_mem_pool_size = ULINT_MAX; UNIV_INTERN ulint srv_lock_table_size = ULINT_MAX; -/* key value for shm */ -UNIV_INTERN uint srv_buffer_pool_shm_key = 0; -UNIV_INTERN ibool srv_buffer_pool_shm_is_reused = FALSE; -UNIV_INTERN ibool srv_buffer_pool_shm_checksum = TRUE; - /* This parameter is deprecated. Use srv_n_io_[read|write]_threads instead. */ UNIV_INTERN ulint srv_n_file_io_threads = ULINT_MAX; UNIV_INTERN ulint srv_n_read_io_threads = ULINT_MAX; UNIV_INTERN ulint srv_n_write_io_threads = ULINT_MAX; +/* Switch to enable random read ahead. */ +UNIV_INTERN my_bool srv_random_read_ahead = FALSE; + /* The universal page size of the database */ UNIV_INTERN ulint srv_page_size_shift = 0; UNIV_INTERN ulint srv_page_size = 0; @@ -320,6 +326,9 @@ UNIV_INTERN ulint srv_buf_pool_reads = 0; /** Time in seconds between automatic buffer pool dumps */ UNIV_INTERN uint srv_auto_lru_dump = 0; +/** Whether startup should be blocked until buffer pool is fully restored */ +UNIV_INTERN ibool srv_blocking_lru_restore; + /* structure to pass status variables to MySQL */ UNIV_INTERN export_struc export_vars; @@ -2153,6 +2162,8 @@ srv_export_innodb_status(void) export_vars.innodb_buffer_pool_wait_free = srv_buf_pool_wait_free; export_vars.innodb_buffer_pool_pages_flushed = srv_buf_pool_flushed; export_vars.innodb_buffer_pool_reads = srv_buf_pool_reads; + export_vars.innodb_buffer_pool_read_ahead_rnd + = buf_pool->stat.n_ra_pages_read_rnd; export_vars.innodb_buffer_pool_read_ahead = buf_pool->stat.n_ra_pages_read; export_vars.innodb_buffer_pool_read_ahead_evicted @@ -2485,6 +2496,12 @@ srv_error_monitor_thread( ulint fatal_cnt = 0; ib_uint64_t old_lsn; ib_uint64_t new_lsn; + /* longest waiting thread for a semaphore */ + os_thread_id_t waiter = os_thread_get_curr_id(); + os_thread_id_t old_waiter = waiter; + /* the semaphore that is being waited for */ + const void* sema = NULL; + const void* old_sema = NULL; old_lsn = srv_start_lsn; @@ -2533,7 +2550,8 @@ loop: sync_arr_wake_threads_if_sema_free(); - if (sync_array_print_long_waits()) { + if (sync_array_print_long_waits(&waiter, &sema) + && sema == old_sema && os_thread_eq(waiter, old_waiter)) { fatal_cnt++; if (fatal_cnt > 10) { @@ -2548,6 +2566,38 @@ loop: } } else { fatal_cnt = 0; + old_waiter = waiter; + old_sema = sema; + } + + if (srv_kill_idle_transaction && trx_sys) { + trx_t* trx; + time_t now; +rescan_idle: + now = time(NULL); + mutex_enter(&kernel_mutex); + trx = UT_LIST_GET_FIRST(trx_sys->mysql_trx_list); + while (trx) { + if (trx->conc_state == TRX_ACTIVE + && trx->mysql_thd + && innobase_thd_is_idle(trx->mysql_thd)) { + ib_int64_t start_time; /* as stmt ID */ + + start_time = innobase_thd_get_start_time(trx->mysql_thd); + if (trx->last_stmt_start != start_time) { + trx->idle_start = now; + trx->last_stmt_start = start_time; + } else if (difftime(now, trx->idle_start) + > srv_kill_idle_transaction) { + /* kill the session */ + mutex_exit(&kernel_mutex); + innobase_thd_kill(trx->mysql_thd); + goto rescan_idle; + } + } + trx = UT_LIST_GET_NEXT(mysql_trx_list, trx); + } + mutex_exit(&kernel_mutex); } /* Flush stderr so that a database user gets the output @@ -2593,7 +2643,9 @@ srv_LRU_dump_restore_thread( os_thread_pf(os_thread_get_curr_id())); #endif - if (srv_auto_lru_dump) + /* If srv_blocking_lru_restore is TRUE, restore will be done + synchronously on startup. */ + if (srv_auto_lru_dump && !srv_blocking_lru_restore) buf_LRU_file_restore(); last_dump_time = time(NULL); diff --git a/srv/srv0start.c b/srv/srv0start.c index cef045d72e1..ba4328c80e1 100644 --- a/srv/srv0start.c +++ b/srv/srv0start.c @@ -88,6 +88,7 @@ Created 2/16/1996 Heikki Tuuri # include "thr0loc.h" # include "os0sync.h" /* for INNODB_RW_LOCKS_USE_ATOMICS */ # include "zlib.h" /* for ZLIB_VERSION */ +# include "buf0lru.h" /* for buf_LRU_file_restore() */ /** Log sequence number immediately after startup */ UNIV_INTERN ib_uint64_t srv_start_lsn; @@ -126,9 +127,9 @@ static mutex_t ios_mutex; static ulint ios; /** io_handler_thread parameters for thread identification */ -static ulint n[SRV_MAX_N_IO_THREADS + 7 + 64]; +static ulint n[SRV_MAX_N_IO_THREADS + 7 + UNIV_MAX_PARALLELISM]; /** io_handler_thread identifiers */ -static os_thread_id_t thread_ids[SRV_MAX_N_IO_THREADS + 7 + 64]; +static os_thread_id_t thread_ids[SRV_MAX_N_IO_THREADS + 7 + UNIV_MAX_PARALLELISM]; /** We use this mutex to test the return value of pthread_mutex_trylock on successful locking. HP-UX does NOT return 0, though Linux et al do. */ @@ -1200,6 +1201,12 @@ innobase_start_or_create_for_mysql(void) ); #endif +#ifdef UNIV_BLOB_DEBUG + fprintf(stderr, + "InnoDB: !!!!!!!! UNIV_BLOB_DEBUG switched on !!!!!!!!!\n" + "InnoDB: Server restart may fail with UNIV_BLOB_DEBUG\n"); +#endif /* UNIV_BLOB_DEBUG */ + #ifdef UNIV_SYNC_DEBUG fprintf(stderr, "InnoDB: !!!!!!!! UNIV_SYNC_DEBUG switched on !!!!!!!!!\n"); @@ -1744,8 +1751,6 @@ innobase_start_or_create_for_mysql(void) Note that this is not as heavy weight as it seems. At this point there will be only ONE page in the buf_LRU and there must be no page in the buf_flush list. */ - /* buffer_pool_shm should not be reused when recovery was needed. */ - if (!srv_buffer_pool_shm_is_reused) buf_pool_invalidate(); /* We always try to do a recovery, even if the database had @@ -1875,6 +1880,11 @@ innobase_start_or_create_for_mysql(void) os_thread_create(&srv_LRU_dump_restore_thread, NULL, thread_ids + 5 + SRV_MAX_N_IO_THREADS); + /* If srv_blocking_lru_restore is TRUE, load buffer pool contents + synchronously */ + if (srv_auto_lru_dump && srv_blocking_lru_restore) + buf_LRU_file_restore(); + srv_is_being_started = FALSE; if (trx_doublewrite == NULL) { diff --git a/sync/sync0arr.c b/sync/sync0arr.c index 57a288089c7..4e788b4a968 100644 --- a/sync/sync0arr.c +++ b/sync/sync0arr.c @@ -913,8 +913,10 @@ Prints warnings of long semaphore waits to stderr. @return TRUE if fatal semaphore wait threshold was exceeded */ UNIV_INTERN ibool -sync_array_print_long_waits(void) -/*=============================*/ +sync_array_print_long_waits( +/*========================*/ + os_thread_id_t* waiter, /*!< out: longest waiting thread */ + const void** sema) /*!< out: longest-waited-for semaphore */ { sync_cell_t* cell; ibool old_val; @@ -922,24 +924,40 @@ sync_array_print_long_waits(void) ulint i; ulint fatal_timeout = srv_fatal_semaphore_wait_threshold; ibool fatal = FALSE; + double longest_diff = 0; for (i = 0; i < sync_primary_wait_array->n_cells; i++) { + double diff; + void* wait_object; + cell = sync_array_get_nth_cell(sync_primary_wait_array, i); - if (cell->wait_object != NULL && cell->waiting - && difftime(time(NULL), cell->reservation_time) > 240) { + wait_object = cell->wait_object; + + if (wait_object == NULL || !cell->waiting) { + + continue; + } + + diff = difftime(time(NULL), cell->reservation_time); + + if (diff > 240) { fputs("InnoDB: Warning: a long semaphore wait:\n", stderr); sync_array_cell_print(stderr, cell); noticed = TRUE; } - if (cell->wait_object != NULL && cell->waiting - && difftime(time(NULL), cell->reservation_time) - > fatal_timeout) { + if (diff > fatal_timeout) { fatal = TRUE; } + + if (diff > longest_diff) { + longest_diff = diff; + *sema = wait_object; + *waiter = cell->thread; + } } if (noticed) { diff --git a/sync/sync0rw.c b/sync/sync0rw.c index 9431de15fda..fe000e7d008 100644 --- a/sync/sync0rw.c +++ b/sync/sync0rw.c @@ -261,6 +261,9 @@ rw_lock_create_func( contains garbage at initialization and cannot be used for recursive x-locking. */ lock->recursive = FALSE; + /* Silence Valgrind when UNIV_DEBUG_VALGRIND is not enabled. */ + memset((void*) &lock->writer_thread, 0, sizeof lock->writer_thread); + UNIV_MEM_INVALID(&lock->writer_thread, sizeof lock->writer_thread); #ifdef UNIV_SYNC_DEBUG UT_LIST_INIT(lock->debug_list); @@ -762,7 +765,9 @@ rw_lock_add_debug_info( rw_lock_debug_mutex_exit(); if ((pass == 0) && (lock_type != RW_LOCK_WAIT_EX)) { - sync_thread_add_level(lock, lock->level); + sync_thread_add_level(lock, lock->level, + lock_type == RW_LOCK_EX + && lock->lock_word < 0); } } diff --git a/sync/sync0sync.c b/sync/sync0sync.c index 3a80da9318b..277a53e4fb2 100644 --- a/sync/sync0sync.c +++ b/sync/sync0sync.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. Copyright (c) 2008, Google Inc. Portions of this file contain modifications contributed and copyrighted by @@ -668,7 +668,7 @@ mutex_set_debug_info( ut_ad(mutex); ut_ad(file_name); - sync_thread_add_level(mutex, mutex->level); + sync_thread_add_level(mutex, mutex->level, FALSE); mutex->file_name = file_name; mutex->line = line; @@ -1094,8 +1094,9 @@ void sync_thread_add_level( /*==================*/ void* latch, /*!< in: pointer to a mutex or an rw-lock */ - ulint level) /*!< in: level in the latching order; if + ulint level, /*!< in: level in the latching order; if SYNC_LEVEL_VARYING, nothing is done */ + ibool relock) /*!< in: TRUE if re-entering an x-lock */ { sync_level_t* array; sync_level_t* slot; @@ -1143,6 +1144,10 @@ sync_thread_add_level( array = thread_slot->levels; + if (relock) { + goto levels_ok; + } + /* NOTE that there is a problem with _NODE and _LEAF levels: if the B-tree height changes, then a leaf can change to an internal node or the other way around. We do not know at present if this can cause @@ -1287,6 +1292,7 @@ sync_thread_add_level( ut_error; } +levels_ok: for (i = 0; i < SYNC_THREAD_N_LEVELS; i++) { slot = sync_thread_levels_get_nth(array, i); diff --git a/trx/trx0i_s.c b/trx/trx0i_s.c index e148234888b..5cc9df2d5c4 100644 --- a/trx/trx0i_s.c +++ b/trx/trx0i_s.c @@ -504,7 +504,7 @@ fill_trx_row( query[stmt_len] = '\0'; row->trx_query = ha_storage_put_memlim( - cache->storage, stmt, stmt_len + 1, + cache->storage, query, stmt_len + 1, MAX_ALLOWED_FOR_STORAGE(cache)); row->trx_query_cs = innobase_get_charset(trx->mysql_thd); diff --git a/trx/trx0rec.c b/trx/trx0rec.c index 71629f01d73..a7a393d31c8 100644 --- a/trx/trx0rec.c +++ b/trx/trx0rec.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2010, 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 @@ -1590,6 +1590,10 @@ trx_undo_prev_version_build( return(DB_ERROR); } +# if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG + ut_a(!rec_offs_any_null_extern(rec, offsets)); +# endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ + if (row_upd_changes_field_size_or_external(index, offsets, update)) { ulint n_ext; diff --git a/trx/trx0sys.c b/trx/trx0sys.c index 566f7c95793..6a15d4261eb 100644 --- a/trx/trx0sys.c +++ b/trx/trx0sys.c @@ -37,6 +37,7 @@ Created 3/26/1996 Heikki Tuuri #include "trx0rseg.h" #include "trx0undo.h" #include "srv0srv.h" +#include "srv0start.h" #include "trx0purge.h" #include "log0log.h" #include "log0recv.h" @@ -1872,10 +1873,12 @@ void trx_sys_close(void) /*===============*/ { + trx_t* trx; trx_rseg_t* rseg; read_view_t* view; ut_ad(trx_sys != NULL); + ut_ad(srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS); /* Check that all read views are closed except read view owned by a purge. */ @@ -1907,6 +1910,13 @@ trx_sys_close(void) mem_free(trx_doublewrite); trx_doublewrite = NULL; + /* Only prepared transactions may be left in the system. Free them. */ + ut_a(UT_LIST_GET_LEN(trx_sys->trx_list) == trx_n_prepared); + + while ((trx = UT_LIST_GET_FIRST(trx_sys->trx_list)) != NULL) { + trx_free_prepared(trx); + } + /* There can't be any active transactions. */ rseg = UT_LIST_GET_FIRST(trx_sys->rseg_list); diff --git a/trx/trx0trx.c b/trx/trx0trx.c index 98bd9e4ac58..bf042db4972 100644 --- a/trx/trx0trx.c +++ b/trx/trx0trx.c @@ -50,6 +50,9 @@ UNIV_INTERN sess_t* trx_dummy_sess = NULL; /** Number of transactions currently allocated for MySQL: protected by the kernel mutex */ UNIV_INTERN ulint trx_n_mysql_transactions = 0; +/* Number of transactions currently in the XA PREPARED state: protected by +the kernel mutex */ +UNIV_INTERN ulint trx_n_prepared = 0; /*************************************************************//** Set detailed error message for the transaction. */ @@ -111,6 +114,8 @@ trx_create( trx->flush_log_at_trx_commit_session = 3; /* means to use innodb_flush_log_at_trx_commit value */ + trx->fake_changes = FALSE; + trx->check_foreigns = TRUE; trx->check_unique_secondary = TRUE; @@ -134,6 +139,9 @@ trx_create( trx->mysql_relay_log_file_name = ""; trx->mysql_relay_log_pos = 0; + trx->idle_start = 0; + trx->last_stmt_start = 0; + mutex_create(&trx->undo_mutex, SYNC_TRX_UNDO); trx->rseg = NULL; @@ -353,6 +361,60 @@ trx_free( mem_free(trx); } +/********************************************************************//** +At shutdown, frees a transaction object that is in the PREPARED state. */ +UNIV_INTERN +void +trx_free_prepared( +/*==============*/ + trx_t* trx) /*!< in, own: trx object */ +{ + ut_ad(mutex_own(&kernel_mutex)); + ut_a(trx->conc_state == TRX_PREPARED); + ut_a(trx->magic_n == TRX_MAGIC_N); + + /* Prepared transactions are sort of active; they allow + ROLLBACK and COMMIT operations. Because the system does not + contain any other transactions than prepared transactions at + the shutdown stage and because a transaction cannot become + PREPARED while holding locks, it is safe to release the locks + held by PREPARED transactions here at shutdown.*/ + lock_release_off_kernel(trx); + + trx_undo_free_prepared(trx); + + mutex_free(&trx->undo_mutex); + + if (trx->undo_no_arr) { + trx_undo_arr_free(trx->undo_no_arr); + } + + ut_a(UT_LIST_GET_LEN(trx->signals) == 0); + ut_a(UT_LIST_GET_LEN(trx->reply_signals) == 0); + + ut_a(trx->wait_lock == NULL); + ut_a(UT_LIST_GET_LEN(trx->wait_thrs) == 0); + + ut_a(!trx->has_search_latch); + + ut_a(trx->dict_operation_lock_mode == 0); + + if (trx->lock_heap) { + mem_heap_free(trx->lock_heap); + } + + if (trx->global_read_view_heap) { + mem_heap_free(trx->global_read_view_heap); + } + + ut_a(ib_vector_is_empty(trx->autoinc_locks)); + ib_vector_free(trx->autoinc_locks); + + UT_LIST_REMOVE(trx_list, trx_sys->trx_list, trx); + + mem_free(trx); +} + /********************************************************************//** Frees a transaction object for MySQL. */ UNIV_INTERN @@ -495,6 +557,7 @@ trx_lists_init_at_db_start(void) if (srv_force_recovery == 0) { trx->conc_state = TRX_PREPARED; + trx_n_prepared++; } else { fprintf(stderr, "InnoDB: Since" @@ -573,6 +636,7 @@ trx_lists_init_at_db_start(void) trx->conc_state = TRX_PREPARED; + trx_n_prepared++; } else { fprintf(stderr, "InnoDB: Since" @@ -878,6 +942,11 @@ trx_commit_off_kernel( || trx->conc_state == TRX_PREPARED); ut_ad(mutex_own(&kernel_mutex)); + if (UNIV_UNLIKELY(trx->conc_state == TRX_PREPARED)) { + ut_a(trx_n_prepared > 0); + trx_n_prepared--; + } + /* The following assignment makes the transaction committed in memory and makes its changes to data visible to other transactions. NOTE that there is a small discrepancy from the strict formal @@ -1945,6 +2014,7 @@ trx_prepare_off_kernel( /*--------------------------------------*/ trx->conc_state = TRX_PREPARED; + trx_n_prepared++; /*--------------------------------------*/ if (lsn) { @@ -2127,10 +2197,11 @@ trx_get_trx_by_xid( while (trx) { /* Compare two X/Open XA transaction id's: their length should be the same and binary comparison - of gtrid_lenght+bqual_length bytes should be + of gtrid_length+bqual_length bytes should be the same */ - if (trx->conc_state == TRX_PREPARED + if (trx->is_recovered + && trx->conc_state == TRX_PREPARED && xid->gtrid_length == trx->xid.gtrid_length && xid->bqual_length == trx->xid.bqual_length && memcmp(xid->data, trx->xid.data, diff --git a/trx/trx0undo.c b/trx/trx0undo.c index 9ed83b5d5c1..ec1cd2d2c43 100644 --- a/trx/trx0undo.c +++ b/trx/trx0undo.c @@ -36,6 +36,7 @@ Created 3/26/1996 Heikki Tuuri #include "trx0rseg.h" #include "trx0trx.h" #include "srv0srv.h" +#include "srv0start.h" #include "trx0rec.h" #include "trx0purge.h" @@ -2014,4 +2015,28 @@ trx_undo_insert_cleanup( mutex_exit(&(rseg->mutex)); } + +/********************************************************************//** +At shutdown, frees the undo logs of a PREPARED transaction. */ +UNIV_INTERN +void +trx_undo_free_prepared( +/*===================*/ + trx_t* trx) /*!< in/out: PREPARED transaction */ +{ + ut_ad(srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS); + + if (trx->update_undo) { + ut_a(trx->update_undo->state == TRX_UNDO_PREPARED); + UT_LIST_REMOVE(undo_list, trx->rseg->update_undo_list, + trx->update_undo); + trx_undo_mem_free(trx->update_undo); + } + if (trx->insert_undo) { + ut_a(trx->insert_undo->state == TRX_UNDO_PREPARED); + UT_LIST_REMOVE(undo_list, trx->rseg->insert_undo_list, + trx->insert_undo); + trx_undo_mem_free(trx->insert_undo); + } +} #endif /* !UNIV_HOTBACKUP */ diff --git a/ut/ut0mem.c b/ut/ut0mem.c index bf55e4273b6..95fb2187b79 100644 --- a/ut/ut0mem.c +++ b/ut/ut0mem.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 @@ -489,53 +489,6 @@ ut_strlcpy_rev( return(src_size); } -/**********************************************************************//** -Make a quoted copy of a NUL-terminated string. Leading and trailing -quotes will not be included; only embedded quotes will be escaped. -See also ut_strlenq() and ut_memcpyq(). -@return pointer to end of dest */ -UNIV_INTERN -char* -ut_strcpyq( -/*=======*/ - char* dest, /*!< in: output buffer */ - char q, /*!< in: the quote character */ - const char* src) /*!< in: null-terminated string */ -{ - while (*src) { - if ((*dest++ = *src++) == q) { - *dest++ = q; - } - } - - return(dest); -} - -/**********************************************************************//** -Make a quoted copy of a fixed-length string. Leading and trailing -quotes will not be included; only embedded quotes will be escaped. -See also ut_strlenq() and ut_strcpyq(). -@return pointer to end of dest */ -UNIV_INTERN -char* -ut_memcpyq( -/*=======*/ - char* dest, /*!< in: output buffer */ - char q, /*!< in: the quote character */ - const char* src, /*!< in: string to be quoted */ - ulint len) /*!< in: length of src */ -{ - const char* srcend = src + len; - - while (src < srcend) { - if ((*dest++ = *src++) == q) { - *dest++ = q; - } - } - - return(dest); -} - #ifndef UNIV_HOTBACKUP /**********************************************************************//** Return the number of times s2 occurs in s1. Overlapping instances of s2 From 7a48b3df7f64bc2eb077f7f2f1bda6829ed7b2a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 22 Nov 2011 13:14:55 +0200 Subject: [PATCH 098/288] Bug#13340047 LATCHING ORDER VIOLATION IN IBUF_SET_ENTRY_COUNTER() - cleanup Remove btr_cur_t::ibuf_cnt. The only dependence on cursor->ibuf_cnt was ibuf_set_entry_counter(). That code path was removed in the original bug fix (marko.makela@oracle.com-20111107072802-dgwagejlpub0rjkd). rb:819 approved by Jimmy Yang --- storage/innobase/btr/btr0cur.c | 15 --------------- storage/innobase/include/btr0cur.h | 18 ------------------ 2 files changed, 33 deletions(-) diff --git a/storage/innobase/btr/btr0cur.c b/storage/innobase/btr/btr0cur.c index 625721133fd..03346337d3f 100644 --- a/storage/innobase/btr/btr0cur.c +++ b/storage/innobase/btr/btr0cur.c @@ -458,8 +458,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 @@ -747,21 +745,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; diff --git a/storage/innobase/include/btr0cur.h b/storage/innobase/include/btr0cur.h index be918439f59..4f33aacc48e 100644 --- a/storage/innobase/include/btr0cur.h +++ b/storage/innobase/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 From de479ab3b61fd7df294a6b07a11bd60d10299789 Mon Sep 17 00:00:00 2001 From: Vasil Dimov Date: Mon, 21 Nov 2011 15:26:24 +0200 Subject: [PATCH 099/288] Followup to vasil.dimov@oracle.com-20111118115710-1xlezv0nbjz6s2ps Fix merge issues after discussing with Marko. --- storage/innobase/handler/ha_innodb.cc | 3 --- storage/innobase/row/row0ins.c | 2 -- 2 files changed, 5 deletions(-) diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 16cb61fd22e..4e01f7e1cf4 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -5261,9 +5261,6 @@ calc_row_difference( dfield_set_null(&ufield->new_val); } - /* XXX merge issues, should this be here? - ufield->extern_storage = FALSE; - */ ufield->exp = NULL; ufield->orig_len = 0; ufield->field_no = dict_col_get_clust_pos( diff --git a/storage/innobase/row/row0ins.c b/storage/innobase/row/row0ins.c index fc1ff694e32..6e311ce2e80 100644 --- a/storage/innobase/row/row0ins.c +++ b/storage/innobase/row/row0ins.c @@ -276,9 +276,7 @@ row_ins_sec_index_entry_by_modify( err = btr_cur_pessimistic_update(BTR_KEEP_SYS_FLAG, cursor, &heap, &dummy_big_rec, update, 0, thr, mtr); - /* XXX merge conflicts, should this be here? ut_ad(!dummy_big_rec); - */ } func_exit: mem_heap_free(heap); From 9f9b5996f51c27cdfa10dbe7f1c36d8184c9f208 Mon Sep 17 00:00:00 2001 From: Jon Olav Hauglid Date: Tue, 22 Nov 2011 14:16:13 +0100 Subject: [PATCH 100/288] Disabling main.query_cache_28249.test since this test fails sporadically on 5.1. See Bug#12584161. Test runs successfully on 5.5/trunk, so this changeset will be null-merged. --- mysql-test/t/disabled.def | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index 84c981c08c1..bfa051de4b6 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -12,4 +12,4 @@ kill : Bug#11748945 2008-12-03 HHunger need some changes to be robust enough for pushbuild. read_many_rows_innodb : Bug#11748886 2010-11-15 mattiasj report already exists main.log_tables-big : Bug#11756699 2010-11-15 mattiasj report already exists - +query_cache_28249 : Bug#12584161 2011-11-17 joh fails sporadically in 5.1 only From 5d81384c5a8ed557be2f14eea771475e43edaa90 Mon Sep 17 00:00:00 2001 From: Jimmy Yang Date: Tue, 22 Nov 2011 07:06:19 -0800 Subject: [PATCH 101/288] Disable innodb_corrupt_bit.test on windows, issues with innodb_change_buffering_debug prevents creating the Dup Key scenario on windows --- mysql-test/suite/innodb/t/innodb_corrupt_bit.test | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mysql-test/suite/innodb/t/innodb_corrupt_bit.test b/mysql-test/suite/innodb/t/innodb_corrupt_bit.test index 34991362f98..7c4ea00afec 100644 --- a/mysql-test/suite/innodb/t/innodb_corrupt_bit.test +++ b/mysql-test/suite/innodb/t/innodb_corrupt_bit.test @@ -3,6 +3,10 @@ # -- source include/have_innodb.inc +# Issues with innodb_change_buffering_debug on Windows, so the test scenario +# cannot be created on windows +--source include/not_windows.inc + # This test needs debug server --source include/have_debug.inc From d4635150289e5d3d1fc0d9b411296648fe2f8049 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 22 Nov 2011 21:55:11 +0100 Subject: [PATCH 102/288] fix dialog plugin to work on windows --- include/mysql/client_plugin.h | 11 +++++++++++ include/mysql/plugin_auth_common.h | 4 ++++ plugin/auth/CMakeLists.txt | 3 +++ plugin/auth/dialog.c | 18 ++++++++---------- 4 files changed, 26 insertions(+), 10 deletions(-) create mode 100644 plugin/auth/CMakeLists.txt diff --git a/include/mysql/client_plugin.h b/include/mysql/client_plugin.h index 9c7b1aee9f9..fc4db6b6553 100644 --- a/include/mysql/client_plugin.h +++ b/include/mysql/client_plugin.h @@ -28,6 +28,16 @@ #include #endif +#if defined(_MSC_VER) + #ifdef __cplusplus + #define MYSQL_PLUGIN_EXPORT extern "C" __declspec(dllexport) + #else + #define MYSQL_PLUGIN_EXPORT __declspec(dllexport) + #endif +#else /*_MSC_VER */ +#define MYSQL_PLUGIN_EXPORT +#endif + /* known plugin types */ #define MYSQL_CLIENT_reserved1 0 #define MYSQL_CLIENT_reserved2 1 @@ -38,6 +48,7 @@ #define MYSQL_CLIENT_MAX_PLUGINS 3 #define mysql_declare_client_plugin(X) \ + MYSQL_PLUGIN_EXPORT \ struct st_mysql_client_plugin_ ## X \ _mysql_client_plugin_declaration_ = { \ MYSQL_CLIENT_ ## X ## _PLUGIN, \ diff --git a/include/mysql/plugin_auth_common.h b/include/mysql/plugin_auth_common.h index b71591d6eb6..ed613b2a5ce 100644 --- a/include/mysql/plugin_auth_common.h +++ b/include/mysql/plugin_auth_common.h @@ -14,6 +14,10 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifdef _WIN32 +#include +#endif + /** @file diff --git a/plugin/auth/CMakeLists.txt b/plugin/auth/CMakeLists.txt new file mode 100644 index 00000000000..931a47fec5e --- /dev/null +++ b/plugin/auth/CMakeLists.txt @@ -0,0 +1,3 @@ +INCLUDE("${PROJECT_SOURCE_DIR}/storage/mysql_storage_engine.cmake") +SET(AUTH_SOURCES dialog.c) +MYSQL_PLUGIN(AUTH) diff --git a/plugin/auth/dialog.c b/plugin/auth/dialog.c index 49ab0c9a158..76b2ddae528 100644 --- a/plugin/auth/dialog.c +++ b/plugin/auth/dialog.c @@ -33,13 +33,16 @@ a correct password. It shows the situation when a number of questions is not known in advance. */ -#define _GNU_SOURCE /* for RTLD_DEFAULT */ +#include +#include +#include +#include + +#if defined (_WIN32) +# define RTLD_DEFAULT GetModuleHandle(NULL) +#endif #include -#include -#include -#include -#include /** first byte of the question string is the question "type". @@ -51,8 +54,6 @@ #define PASSWORD_QUESTION "\4" #define LAST_PASSWORD "\5" -typedef unsigned char uchar; - /********************* SERVER SIDE ****************************************/ /** @@ -216,9 +217,6 @@ maria_declare_plugin_end; dialog plugin will use it for communication with the user. Otherwise a default gets() based implementation will be used. */ -#include -#include - static mysql_authentication_dialog_ask_t ask; static char *builtin_ask(MYSQL *mysql __attribute__((unused)), From 694ce95557bc174dae2bc32279024102848cf5ee Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Wed, 23 Nov 2011 04:25:52 +0400 Subject: [PATCH 103/288] Semi-join optimizations code cleanup: - Break down POSITION/advance_sj_state() into four classes representing potential semi-join strategies. - Treat all strategies uniformly (before, DuplicateWeedout was special as it was the catch-all strategy. Now, we're still relying on it to be the catch-all, but are able to function,e.g. with firstmatch=on,duplicate_weedout=off. - Update test results (checked) --- mysql-test/r/subselect_sj2.result | 4 +- mysql-test/r/subselect_sj2_jcl6.result | 4 +- sql/opt_subselect.cc | 892 ++++++++++++++----------- sql/opt_subselect.h | 7 +- sql/sql_select.cc | 23 +- sql/sql_select.h | 339 +++++++--- 6 files changed, 780 insertions(+), 489 deletions(-) diff --git a/mysql-test/r/subselect_sj2.result b/mysql-test/r/subselect_sj2.result index db99d77f50c..fe9136cfccc 100644 --- a/mysql-test/r/subselect_sj2.result +++ b/mysql-test/r/subselect_sj2.result @@ -323,8 +323,8 @@ WHERE Language='English' AND Percentage > 10 AND t2.Population > 100000); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 range Population,Country Population 4 NULL 1 Using index condition; Rowid-ordered scan; Start temporary -1 PRIMARY t2 eq_ref PRIMARY,Population PRIMARY 3 test.t1.Country 1 Using where -1 PRIMARY t3 eq_ref PRIMARY,Percentage PRIMARY 33 test.t1.Country,const 1 Using index condition; Using where; End temporary +1 PRIMARY t2 eq_ref PRIMARY,Population PRIMARY 3 test.t1.Country 1 Using where; End temporary +1 PRIMARY t3 eq_ref PRIMARY,Percentage PRIMARY 33 test.t1.Country,const 1 Using index condition; Using where set optimizer_switch=@bug35674_save_optimizer_switch; DROP TABLE t1,t2,t3; CREATE TABLE t1 ( diff --git a/mysql-test/r/subselect_sj2_jcl6.result b/mysql-test/r/subselect_sj2_jcl6.result index 05da22fc10d..0f85f87096d 100644 --- a/mysql-test/r/subselect_sj2_jcl6.result +++ b/mysql-test/r/subselect_sj2_jcl6.result @@ -332,8 +332,8 @@ WHERE Language='English' AND Percentage > 10 AND t2.Population > 100000); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 range Population,Country Population 4 NULL 1 Using index condition; Rowid-ordered scan; Start temporary -1 PRIMARY t2 eq_ref PRIMARY,Population PRIMARY 3 test.t1.Country 1 Using where; Using join buffer (flat, BKA join); Key-ordered Rowid-ordered scan -1 PRIMARY t3 eq_ref PRIMARY,Percentage PRIMARY 33 test.t1.Country,const 1 Using index condition; Using where; End temporary; Using join buffer (incremental, BKA join); Key-ordered Rowid-ordered scan +1 PRIMARY t2 eq_ref PRIMARY,Population PRIMARY 3 test.t1.Country 1 Using where; End temporary; Using join buffer (flat, BKA join); Key-ordered Rowid-ordered scan +1 PRIMARY t3 eq_ref PRIMARY,Percentage PRIMARY 33 test.t1.Country,const 1 Using index condition; Using where; Using join buffer (incremental, BKA join); Key-ordered Rowid-ordered scan set optimizer_switch=@bug35674_save_optimizer_switch; DROP TABLE t1,t2,t3; CREATE TABLE t1 ( diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index fdda502e706..c7d07c21746 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -2168,70 +2168,414 @@ bool find_eq_ref_candidate(TABLE *table, table_map sj_inner_tables) See setup_semijoin_dups_elimination() for a description of what kinds of join prefixes each strategy can handle. */ +bool is_multiple_semi_joins(POSITION *prefix, uint idx, table_map inner_tables) +{ + for (int i= (int)idx; i >= 0; i--) + { + TABLE_LIST *emb_sj_nest; + if ((emb_sj_nest= prefix[i].table->emb_sj_nest)) + { + if (inner_tables & emb_sj_nest->sj_inner_tables) + return !test(inner_tables == emb_sj_nest->sj_inner_tables); + } + } + return FALSE; +} -void advance_sj_state(JOIN *join, table_map remaining_tables, - const JOIN_TAB *new_join_tab, uint idx, - double *current_record_count, double *current_read_time, + +void advance_sj_state(JOIN *join, table_map remaining_tables, uint idx, + double *current_record_count, double *current_read_time, POSITION *loose_scan_pos) { - TABLE_LIST *emb_sj_nest; POSITION *pos= join->positions + idx; - remaining_tables &= ~new_join_tab->table->map; - bool disable_jbuf= join->thd->variables.join_cache_level == 0; + const JOIN_TAB *new_join_tab= pos->table; + Semi_join_strategy_picker *pickers[]= + { + &pos->firstmatch_picker, + &pos->loosescan_picker, + &pos->sjmat_picker, + &pos->dups_weedout_picker, + NULL, + }; - pos->prefix_cost.convert_from_cost(*current_read_time); - pos->prefix_record_count= *current_record_count; - pos->sj_strategy= SJ_OPT_NONE; - - pos->prefix_dups_producing_tables= join->cur_dups_producing_tables; - - /* We're performing optimization inside SJ-Materialization nest */ if (join->emb_sjm_nest) { - pos->invalidate_firstmatch_prefix(); - pos->first_loosescan_table= MAX_TABLES; - pos->dupsweedout_tables= 0; - pos->sjm_scan_need_tables= 0; + /* + We're performing optimization inside SJ-Materialization nest: + - there are no other semi-joins inside semi-join nests + - attempts to build semi-join strategies here will confuse + the optimizer, so bail out. + */ return; } - /* Initialize the state or copy it from prev. tables */ + /* + Update join->cur_sj_inner_tables (Used by FirstMatch in this function and + LooseScan detector in best_access_path) + */ + remaining_tables &= ~new_join_tab->table->map; + pos->prefix_dups_producing_tables= join->cur_dups_producing_tables; + TABLE_LIST *emb_sj_nest; + if ((emb_sj_nest= new_join_tab->emb_sj_nest)) + { + /// join->cur_sj_inner_tables |= emb_sj_nest->sj_inner_tables; + join->cur_dups_producing_tables |= emb_sj_nest->sj_inner_tables; + + /* Remove the sj_nest if all of its SJ-inner tables are in cur_table_map */ + /// if (!(remaining_tables & + /// emb_sj_nest->sj_inner_tables & ~new_join_tab->table->map)) + /// join->cur_sj_inner_tables &= ~emb_sj_nest->sj_inner_tables; + } + + Semi_join_strategy_picker **strategy; if (idx == join->const_tables) { - pos->invalidate_firstmatch_prefix(); - pos->first_loosescan_table= MAX_TABLES; - pos->dupsweedout_tables= 0; - pos->sjm_scan_need_tables= 0; - LINT_INIT(pos->sjm_scan_last_inner); + /* First table, initialize pickers */ + for (strategy= pickers; *strategy != NULL; strategy++) + (*strategy)->set_empty(); + pos->inner_tables_handled_with_other_sjs= 0; } else { - // FirstMatch - pos->first_firstmatch_table= - (pos[-1].sj_strategy == SJ_OPT_FIRST_MATCH) ? - MAX_TABLES : pos[-1].first_firstmatch_table; - pos->first_firstmatch_rtbl= pos[-1].first_firstmatch_rtbl; - pos->firstmatch_need_tables= pos[-1].firstmatch_need_tables; + for (strategy= pickers; *strategy != NULL; strategy++) + { + (*strategy)->set_from_prev(pos - 1); + } + pos->inner_tables_handled_with_other_sjs= + pos[-1].inner_tables_handled_with_other_sjs; + } - // LooseScan - pos->first_loosescan_table= - (pos[-1].sj_strategy == SJ_OPT_LOOSE_SCAN) ? - MAX_TABLES : pos[-1].first_loosescan_table; - pos->loosescan_need_tables= pos[-1].loosescan_need_tables; + pos->prefix_cost.convert_from_cost(*current_read_time); + pos->prefix_record_count= *current_record_count; - // SJ-Materialization Scan - pos->sjm_scan_need_tables= - (pos[-1].sj_strategy == SJ_OPT_MATERIALIZE_SCAN) ? - 0 : pos[-1].sjm_scan_need_tables; - pos->sjm_scan_last_inner= pos[-1].sjm_scan_last_inner; + { + pos->sj_strategy= SJ_OPT_NONE; - // Duplicate Weedout - pos->dupsweedout_tables= pos[-1].dupsweedout_tables; - pos->first_dupsweedout_table= pos[-1].first_dupsweedout_table; + for (strategy= pickers; *strategy != NULL; strategy++) + { + table_map handled_fanout; + sj_strategy_enum sj_strategy; + double rec_count= *current_record_count; + double read_time= *current_read_time; + if ((*strategy)->check_qep(join, idx, remaining_tables, + new_join_tab, + &rec_count, + &read_time, + &handled_fanout, + &sj_strategy, + loose_scan_pos)) + { + /* + It's possible to use the strategy. Use it, if + - it removes semi-join fanout that was not removed before + - using it is cheaper than using something else, + and {if some other strategy has removed fanout + that this strategy is trying to remove, then it + did remove the fanout only for one semi-join} + This is to avoid a situation when + 1. strategy X removes fanout for semijoin X,Y + 2. using strategy Z is cheaper, but it only removes + fanout from semijoin X. + 3. We have no clue what to do about fanount of semi-join Y. + */ + if ((join->cur_dups_producing_tables & handled_fanout) || + (read_time < *current_read_time && + !(handled_fanout & pos->inner_tables_handled_with_other_sjs))) + { + /* Mark strategy as used */ + (*strategy)->mark_used(); + pos->sj_strategy= sj_strategy; + *current_read_time= read_time; + *current_record_count= rec_count; + join->cur_dups_producing_tables &= ~handled_fanout; + //TODO: update bitmap of semi-joins that were handled together with + // others. + if (is_multiple_semi_joins(join->positions, idx, handled_fanout)) + pos->inner_tables_handled_with_other_sjs |= handled_fanout; + } + else + { + /* We decided not to apply the strategy. */ + (*strategy)->set_empty(); + } + } + } + } + + if ((emb_sj_nest= new_join_tab->emb_sj_nest)) + { + join->cur_sj_inner_tables |= emb_sj_nest->sj_inner_tables; + + /* Remove the sj_nest if all of its SJ-inner tables are in cur_table_map */ + if (!(remaining_tables & + emb_sj_nest->sj_inner_tables & ~new_join_tab->table->map)) + join->cur_sj_inner_tables &= ~emb_sj_nest->sj_inner_tables; + } + + pos->prefix_cost.convert_from_cost(*current_read_time); + pos->prefix_record_count= *current_record_count; +} + + +void Sj_materialization_picker::set_from_prev(struct st_position *prev) +{ + if (prev->sjmat_picker.is_used) + set_empty(); + else + { + sjm_scan_need_tables= prev->sjmat_picker.sjm_scan_need_tables; + sjm_scan_last_inner= prev->sjmat_picker.sjm_scan_last_inner; + } + is_used= FALSE; +} + + +bool Sj_materialization_picker::check_qep(JOIN *join, + uint idx, + table_map remaining_tables, + const JOIN_TAB *new_join_tab, + double *record_count, + double *read_time, + table_map *handled_fanout, + sj_strategy_enum *strategy, + POSITION *loose_scan_pos) +{ + bool sjm_scan; + SJ_MATERIALIZATION_INFO *mat_info; + if ((mat_info= at_sjmat_pos(join, remaining_tables, + new_join_tab, idx, &sjm_scan))) + { + if (sjm_scan) + { + /* + We can't yet evaluate this option yet. This is because we can't + accout for fanout of sj-inner tables yet: + + ntX SJM-SCAN(it1 ... itN) | ot1 ... otN | + ^(1) ^(2) + + we're now at position (1). SJM temptable in general has multiple + records, so at point (1) we'll get the fanout from sj-inner tables (ie + there will be multiple record combinations). + + The final join result will not contain any semi-join produced + fanout, i.e. tables within SJM-SCAN(...) will not contribute to + the cardinality of the join output. Extra fanout produced by + SJM-SCAN(...) will be 'absorbed' into fanout produced by ot1 ... otN. + + The simple way to model this is to remove SJM-SCAN(...) fanout once + we reach the point #2. + */ + sjm_scan_need_tables= + new_join_tab->emb_sj_nest->sj_inner_tables | + new_join_tab->emb_sj_nest->nested_join->sj_depends_on | + new_join_tab->emb_sj_nest->nested_join->sj_corr_tables; + sjm_scan_last_inner= idx; + } + else + { + /* This is SJ-Materialization with lookups */ + COST_VECT prefix_cost; + signed int first_tab= (int)idx - mat_info->tables; + double prefix_rec_count; + if (first_tab < (int)join->const_tables) + { + prefix_cost.zero(); + prefix_rec_count= 1.0; + } + else + { + prefix_cost= join->positions[first_tab].prefix_cost; + prefix_rec_count= join->positions[first_tab].prefix_record_count; + } + + double mat_read_time= prefix_cost.total_cost(); + mat_read_time += mat_info->materialization_cost.total_cost() + + prefix_rec_count * mat_info->lookup_cost.total_cost(); + + /* + NOTE: When we pick to use SJM[-Scan] we don't memcpy its POSITION + elements to join->positions as that makes it hard to return things + back when making one step back in join optimization. That's done + after the QEP has been chosen. + */ + *read_time= mat_read_time; + *record_count= prefix_rec_count; + *handled_fanout= new_join_tab->emb_sj_nest->sj_inner_tables; + *strategy= SJ_OPT_MATERIALIZE; + return TRUE; + } } - table_map handled_by_fm_or_ls= 0; - /* FirstMatch Strategy */ + /* 4.A SJM-Scan second phase check */ + if (sjm_scan_need_tables && /* Have SJM-Scan prefix */ + !(sjm_scan_need_tables & remaining_tables)) + { + TABLE_LIST *mat_nest= + join->positions[sjm_scan_last_inner].table->emb_sj_nest; + SJ_MATERIALIZATION_INFO *mat_info= mat_nest->sj_mat_info; + + double prefix_cost; + double prefix_rec_count; + int first_tab= sjm_scan_last_inner + 1 - mat_info->tables; + /* Get the prefix cost */ + if (first_tab == (int)join->const_tables) + { + prefix_rec_count= 1.0; + prefix_cost= 0.0; + } + else + { + prefix_cost= join->positions[first_tab - 1].prefix_cost.total_cost(); + prefix_rec_count= join->positions[first_tab - 1].prefix_record_count; + } + + /* Add materialization cost */ + prefix_cost += mat_info->materialization_cost.total_cost() + + prefix_rec_count * mat_info->scan_cost.total_cost(); + prefix_rec_count *= mat_info->rows; + + uint i; + table_map rem_tables= remaining_tables; + for (i= idx; i != (first_tab + mat_info->tables - 1); i--) + rem_tables |= join->positions[i].table->table->map; + + POSITION curpos, dummy; + /* Need to re-run best-access-path as we prefix_rec_count has changed */ + bool disable_jbuf= (join->thd->variables.join_cache_level == 0); + for (i= first_tab + mat_info->tables; i <= idx; i++) + { + best_access_path(join, join->positions[i].table, rem_tables, i, + disable_jbuf, prefix_rec_count, &curpos, &dummy); + prefix_rec_count *= curpos.records_read; + prefix_cost += curpos.read_time; + } + + *strategy= SJ_OPT_MATERIALIZE_SCAN; + *read_time= prefix_cost; + *record_count= prefix_rec_count; + *handled_fanout= mat_nest->sj_inner_tables; + return TRUE; + } + return FALSE; +} + + +void LooseScan_picker::set_from_prev(struct st_position *prev) +{ + if (prev->loosescan_picker.is_used) + set_empty(); + else + { + first_loosescan_table= prev->loosescan_picker.first_loosescan_table; + loosescan_need_tables= prev->loosescan_picker.loosescan_need_tables; + } + is_used= FALSE; +} + + +bool LooseScan_picker::check_qep(JOIN *join, + uint idx, + table_map remaining_tables, + const JOIN_TAB *new_join_tab, + double *record_count, + double *read_time, + table_map *handled_fanout, + sj_strategy_enum *strategy, + struct st_position *loose_scan_pos) +{ + POSITION *first= join->positions + first_loosescan_table; + /* + LooseScan strategy can't handle interleaving between tables from the + semi-join that LooseScan is handling and any other tables. + + If we were considering LooseScan for the join prefix (1) + and the table we're adding creates an interleaving (2) + then + stop considering loose scan + */ + if ((first_loosescan_table != MAX_TABLES) && // (1) + (first->table->emb_sj_nest->sj_inner_tables & remaining_tables) && //(2) + new_join_tab->emb_sj_nest != first->table->emb_sj_nest) //(2) + { + first_loosescan_table= MAX_TABLES; + } + + /* + If we got an option to use LooseScan for the current table, start + considering using LooseScan strategy + */ + if (loose_scan_pos->read_time != DBL_MAX && !join->outer_join) + { + first_loosescan_table= idx; + loosescan_need_tables= + new_join_tab->emb_sj_nest->sj_inner_tables | + new_join_tab->emb_sj_nest->nested_join->sj_depends_on | + new_join_tab->emb_sj_nest->nested_join->sj_corr_tables; + } + + if ((first_loosescan_table != MAX_TABLES) && + !(remaining_tables & loosescan_need_tables) && + (new_join_tab->table->map & loosescan_need_tables)) + { + /* + Ok we have LooseScan plan and also have all LooseScan sj-nest's + inner tables and outer correlated tables into the prefix. + */ + + first= join->positions + first_loosescan_table; + uint n_tables= my_count_bits(first->table->emb_sj_nest->sj_inner_tables); + /* Got a complete LooseScan range. Calculate its cost */ + /* + The same problem as with FirstMatch - we need to save POSITIONs + somewhere but reserving space for all cases would require too + much space. We will re-calculate POSITION structures later on. + */ + bool disable_jbuf= (join->thd->variables.join_cache_level == 0); + optimize_wo_join_buffering(join, first_loosescan_table, idx, + remaining_tables, + TRUE, //first_alt + disable_jbuf ? join->table_count : + first_loosescan_table + n_tables, + record_count, + read_time); + /* + We don't yet have any other strategies that could handle this + semi-join nest (the other options are Duplicate Elimination or + Materialization, which need at least the same set of tables in + the join prefix to be considered) so unconditionally pick the + LooseScan. + */ + *strategy= SJ_OPT_LOOSE_SCAN; + *handled_fanout= first->table->emb_sj_nest->sj_inner_tables; + return TRUE; + } + return FALSE; +} + +void Firstmatch_picker::set_from_prev(struct st_position *prev) +{ + if (prev->firstmatch_picker.is_used) + invalidate_firstmatch_prefix(); + else + { + first_firstmatch_table= prev->firstmatch_picker.first_firstmatch_table; + first_firstmatch_rtbl= prev->firstmatch_picker.first_firstmatch_rtbl; + firstmatch_need_tables= prev->firstmatch_picker.firstmatch_need_tables; + } + is_used= FALSE; +} + +bool Firstmatch_picker::check_qep(JOIN *join, + uint idx, + table_map remaining_tables, + const JOIN_TAB *new_join_tab, + double *record_count, + double *read_time, + table_map *handled_fanout, + sj_strategy_enum *strategy, + POSITION *loose_scan_pos) +{ if (new_join_tab->emb_sj_nest && optimizer_flag(join->thd, OPTIMIZER_SWITCH_FIRSTMATCH) && !join->outer_join) @@ -2259,387 +2603,181 @@ void advance_sj_state(JOIN *join, table_map remaining_tables, ((remaining_tables | new_join_tab->table->map) & sj_inner_tables))) { /* Start tracking potential FirstMatch range */ - pos->first_firstmatch_table= idx; - pos->firstmatch_need_tables= sj_inner_tables; - pos->first_firstmatch_rtbl= remaining_tables; + first_firstmatch_table= idx; + firstmatch_need_tables= sj_inner_tables; + first_firstmatch_rtbl= remaining_tables; } - if (pos->in_firstmatch_prefix()) + if (in_firstmatch_prefix()) { - if (outer_corr_tables & pos->first_firstmatch_rtbl) + if (outer_corr_tables & first_firstmatch_rtbl) { /* Trying to add an sj-inner table whose sj-nest has an outer correlated table that was not in the prefix. This means FirstMatch can't be used. */ - pos->invalidate_firstmatch_prefix(); + invalidate_firstmatch_prefix(); } else { /* Record that we need all of this semi-join's inner tables, too */ - pos->firstmatch_need_tables|= sj_inner_tables; + firstmatch_need_tables|= sj_inner_tables; } - if (pos->in_firstmatch_prefix() && - !(pos->firstmatch_need_tables & remaining_tables)) + if (in_firstmatch_prefix() && + !(firstmatch_need_tables & remaining_tables)) { /* Got a complete FirstMatch range. Calculate correct costs and fanout */ - optimize_wo_join_buffering(join, pos->first_firstmatch_table, idx, + optimize_wo_join_buffering(join, first_firstmatch_table, idx, remaining_tables, FALSE, idx, - current_record_count, - current_read_time); + record_count, + read_time); /* - We don't yet know what are the other strategies, so pick the - FirstMatch. - We ought to save the alternate POSITIONs produced by optimize_wo_join_buffering but the problem is that providing save space uses too much space. Instead, we will re-calculate the alternate POSITIONs after we've picked the best QEP. */ - pos->sj_strategy= SJ_OPT_FIRST_MATCH; - handled_by_fm_or_ls= pos->firstmatch_need_tables; + *handled_fanout= firstmatch_need_tables; + /* *record_count and *read_time were set by the above call */ + *strategy= SJ_OPT_FIRST_MATCH; + return TRUE; } } } + return FALSE; +} - /* LooseScan Strategy */ + +void Duplicate_weedout_picker::set_from_prev(POSITION *prev) +{ + if (prev->dups_weedout_picker.is_used) + set_empty(); + else { - POSITION *first=join->positions+pos->first_loosescan_table; - /* - LooseScan strategy can't handle interleaving between tables from the - semi-join that LooseScan is handling and any other tables. - - If we were considering LooseScan for the join prefix (1) - and the table we're adding creates an interleaving (2) - then - stop considering loose scan - */ - if ((pos->first_loosescan_table != MAX_TABLES) && // (1) - (first->table->emb_sj_nest->sj_inner_tables & remaining_tables) && //(2) - new_join_tab->emb_sj_nest != first->table->emb_sj_nest) //(2) - { - pos->first_loosescan_table= MAX_TABLES; - } - - /* - If we got an option to use LooseScan for the current table, start - considering using LooseScan strategy - */ - if (loose_scan_pos->read_time != DBL_MAX && !join->outer_join) - { - pos->first_loosescan_table= idx; - pos->loosescan_need_tables= - new_join_tab->emb_sj_nest->sj_inner_tables | - new_join_tab->emb_sj_nest->nested_join->sj_depends_on | - new_join_tab->emb_sj_nest->nested_join->sj_corr_tables; - } - - if ((pos->first_loosescan_table != MAX_TABLES) && - !(remaining_tables & pos->loosescan_need_tables) && - (pos->table->table->map & pos->loosescan_need_tables)) - { - /* - Ok we have LooseScan plan and also have all LooseScan sj-nest's - inner tables and outer correlated tables into the prefix. - */ - - first=join->positions + pos->first_loosescan_table; - uint n_tables= my_count_bits(first->table->emb_sj_nest->sj_inner_tables); - /* Got a complete LooseScan range. Calculate its cost */ - /* - The same problem as with FirstMatch - we need to save POSITIONs - somewhere but reserving space for all cases would require too - much space. We will re-calculate POSITION structures later on. - */ - optimize_wo_join_buffering(join, pos->first_loosescan_table, idx, - remaining_tables, - TRUE, //first_alt - disable_jbuf ? join->table_count : - pos->first_loosescan_table + n_tables, - current_record_count, - current_read_time); - /* - We don't yet have any other strategies that could handle this - semi-join nest (the other options are Duplicate Elimination or - Materialization, which need at least the same set of tables in - the join prefix to be considered) so unconditionally pick the - LooseScan. - */ - pos->sj_strategy= SJ_OPT_LOOSE_SCAN; - handled_by_fm_or_ls= first->table->emb_sj_nest->sj_inner_tables; - } + dupsweedout_tables= prev->dups_weedout_picker.dupsweedout_tables; + first_dupsweedout_table= prev->dups_weedout_picker.first_dupsweedout_table; } + is_used= FALSE; +} - /* - Update join->cur_sj_inner_tables (Used by FirstMatch in this function and - LooseScan detector in best_access_path) - */ - if ((emb_sj_nest= new_join_tab->emb_sj_nest)) + +bool Duplicate_weedout_picker::check_qep(JOIN *join, + uint idx, + table_map remaining_tables, + const JOIN_TAB *new_join_tab, + double *record_count, + double *read_time, + table_map *handled_fanout, + sj_strategy_enum *strategy, + POSITION *loose_scan_pos + ) +{ + TABLE_LIST *nest; + if ((nest= new_join_tab->emb_sj_nest)) { - join->cur_sj_inner_tables |= emb_sj_nest->sj_inner_tables; - join->cur_dups_producing_tables |= emb_sj_nest->sj_inner_tables; + if (!dupsweedout_tables) + first_dupsweedout_table= idx; - /* Remove the sj_nest if all of its SJ-inner tables are in cur_table_map */ - if (!(remaining_tables & - emb_sj_nest->sj_inner_tables & ~new_join_tab->table->map)) - join->cur_sj_inner_tables &= ~emb_sj_nest->sj_inner_tables; - } - join->cur_dups_producing_tables &= ~handled_by_fm_or_ls; - - /* 4. SJ-Materialization and SJ-Materialization-scan strategy handler */ - bool sjm_scan; - SJ_MATERIALIZATION_INFO *mat_info; - if ((mat_info= at_sjmat_pos(join, remaining_tables, - new_join_tab, idx, &sjm_scan))) - { - if (sjm_scan) - { - /* - We can't yet evaluate this option yet. This is because we can't - accout for fanout of sj-inner tables yet: - - ntX SJM-SCAN(it1 ... itN) | ot1 ... otN | - ^(1) ^(2) - - we're now at position (1). SJM temptable in general has multiple - records, so at point (1) we'll get the fanout from sj-inner tables (ie - there will be multiple record combinations). - - The final join result will not contain any semi-join produced - fanout, i.e. tables within SJM-SCAN(...) will not contribute to - the cardinality of the join output. Extra fanout produced by - SJM-SCAN(...) will be 'absorbed' into fanout produced by ot1 ... otN. - - The simple way to model this is to remove SJM-SCAN(...) fanout once - we reach the point #2. - */ - pos->sjm_scan_need_tables= - new_join_tab->emb_sj_nest->sj_inner_tables | - new_join_tab->emb_sj_nest->nested_join->sj_depends_on | - new_join_tab->emb_sj_nest->nested_join->sj_corr_tables; - pos->sjm_scan_last_inner= idx; - } - else - { - /* This is SJ-Materialization with lookups */ - COST_VECT prefix_cost; - signed int first_tab= (int)idx - mat_info->tables; - double prefix_rec_count; - if (first_tab < (int)join->const_tables) - { - prefix_cost.zero(); - prefix_rec_count= 1.0; - } - else - { - prefix_cost= join->positions[first_tab].prefix_cost; - prefix_rec_count= join->positions[first_tab].prefix_record_count; - } - - double mat_read_time= prefix_cost.total_cost(); - mat_read_time += mat_info->materialization_cost.total_cost() + - prefix_rec_count * mat_info->lookup_cost.total_cost(); - - if (mat_read_time < *current_read_time || join->cur_dups_producing_tables) - { - /* - NOTE: When we pick to use SJM[-Scan] we don't memcpy its POSITION - elements to join->positions as that makes it hard to return things - back when making one step back in join optimization. That's done - after the QEP has been chosen. - */ - pos->sj_strategy= SJ_OPT_MATERIALIZE; - *current_read_time= mat_read_time; - *current_record_count= prefix_rec_count; - join->cur_dups_producing_tables&= - ~new_join_tab->emb_sj_nest->sj_inner_tables; - } - } + dupsweedout_tables |= nest->sj_inner_tables | + nest->nested_join->sj_depends_on | + nest->nested_join->sj_corr_tables; } - /* 4.A SJM-Scan second phase check */ - if (pos->sjm_scan_need_tables && /* Have SJM-Scan prefix */ - !(pos->sjm_scan_need_tables & remaining_tables)) + if (dupsweedout_tables) { - TABLE_LIST *mat_nest= - join->positions[pos->sjm_scan_last_inner].table->emb_sj_nest; - SJ_MATERIALIZATION_INFO *mat_info= mat_nest->sj_mat_info; - - double prefix_cost; + /* we're in the process of constructing a DuplicateWeedout range */ + TABLE_LIST *emb= new_join_tab->table->pos_in_table_list->embedding; + /* and we've entered an inner side of an outer join*/ + if (emb && emb->on_expr) + dupsweedout_tables |= emb->nested_join->used_tables; + } + + /* If this is the last table that we need for DuplicateWeedout range */ + if (dupsweedout_tables && !(remaining_tables & ~new_join_tab->table->map & + dupsweedout_tables)) + { + /* + Ok, reached a state where we could put a dups weedout point. + Walk back and calculate + - the join cost (this is needed as the accumulated cost may assume + some other duplicate elimination method) + - extra fanout that will be removed by duplicate elimination + - duplicate elimination cost + There are two cases: + 1. We have other strategy/ies to remove all of the duplicates. + 2. We don't. + + We need to calculate the cost in case #2 also because we need to make + choice between this join order and others. + */ + uint first_tab= first_dupsweedout_table; + double dups_cost; double prefix_rec_count; - int first_tab= pos->sjm_scan_last_inner + 1 - mat_info->tables; - /* Get the prefix cost */ - if (first_tab == (int)join->const_tables) + double sj_inner_fanout= 1.0; + double sj_outer_fanout= 1.0; + uint temptable_rec_size; + if (first_tab == join->const_tables) { prefix_rec_count= 1.0; - prefix_cost= 0.0; + temptable_rec_size= 0; + dups_cost= 0.0; } else { - prefix_cost= join->positions[first_tab - 1].prefix_cost.total_cost(); + dups_cost= join->positions[first_tab - 1].prefix_cost.total_cost(); prefix_rec_count= join->positions[first_tab - 1].prefix_record_count; - } - - /* Add materialization cost */ - prefix_cost += mat_info->materialization_cost.total_cost() + - prefix_rec_count * mat_info->scan_cost.total_cost(); - prefix_rec_count *= mat_info->rows; - - uint i; - table_map rem_tables= remaining_tables; - for (i= idx; i != (first_tab + mat_info->tables - 1); i--) - rem_tables |= join->positions[i].table->table->map; - - POSITION curpos, dummy; - /* Need to re-run best-access-path as we prefix_rec_count has changed */ - for (i= first_tab + mat_info->tables; i <= idx; i++) - { - best_access_path(join, join->positions[i].table, rem_tables, i, - disable_jbuf, prefix_rec_count, &curpos, &dummy); - prefix_rec_count *= curpos.records_read; - prefix_cost += curpos.read_time; - } - - /* - Use the strategy if - * it is cheaper then what we've had, or - * we haven't picked any other semi-join strategy yet - In the second case, we pick this strategy unconditionally because - comparing cost without semi-join duplicate removal with cost with - duplicate removal is not an apples-to-apples comparison. - */ - if (prefix_cost < *current_read_time || join->cur_dups_producing_tables) - { - pos->sj_strategy= SJ_OPT_MATERIALIZE_SCAN; - *current_read_time= prefix_cost; - *current_record_count= prefix_rec_count; - join->cur_dups_producing_tables&= ~mat_nest->sj_inner_tables; - - } - } - - /* 5. Duplicate Weedout strategy handler */ - { - /* - Duplicate weedout can be applied after all ON-correlated and - correlated - */ - TABLE_LIST *nest; - if ((nest= new_join_tab->emb_sj_nest)) - { - if (!pos->dupsweedout_tables) - pos->first_dupsweedout_table= idx; - - pos->dupsweedout_tables |= nest->sj_inner_tables | - nest->nested_join->sj_depends_on | - nest->nested_join->sj_corr_tables; + temptable_rec_size= 8; /* This is not true but we'll make it so */ } - if (pos->dupsweedout_tables) + table_map dups_removed_fanout= 0; + for (uint j= first_dupsweedout_table; j <= idx; j++) { - /* we're in the process of constructing a DuplicateWeedout range */ - TABLE_LIST *emb= new_join_tab->table->pos_in_table_list->embedding; - /* and we've entered an inner side of an outer join*/ - if (emb && emb->on_expr) - pos->dupsweedout_tables |= emb->nested_join->used_tables; - } - - if (pos->dupsweedout_tables && - !(remaining_tables & - ~new_join_tab->table->map & pos->dupsweedout_tables)) - { - /* - Ok, reached a state where we could put a dups weedout point. - Walk back and calculate - - the join cost (this is needed as the accumulated cost may assume - some other duplicate elimination method) - - extra fanout that will be removed by duplicate elimination - - duplicate elimination cost - There are two cases: - 1. We have other strategy/ies to remove all of the duplicates. - 2. We don't. - - We need to calculate the cost in case #2 also because we need to make - choice between this join order and others. - */ - uint first_tab= pos->first_dupsweedout_table; - double dups_cost; - double prefix_rec_count; - double sj_inner_fanout= 1.0; - double sj_outer_fanout= 1.0; - uint temptable_rec_size; - if (first_tab == join->const_tables) + POSITION *p= join->positions + j; + dups_cost += p->read_time; + if (p->table->emb_sj_nest) { - prefix_rec_count= 1.0; - temptable_rec_size= 0; - dups_cost= 0.0; + sj_inner_fanout *= p->records_read; + dups_removed_fanout |= p->table->table->map; } else { - dups_cost= join->positions[first_tab - 1].prefix_cost.total_cost(); - prefix_rec_count= join->positions[first_tab - 1].prefix_record_count; - temptable_rec_size= 8; /* This is not true but we'll make it so */ - } - - table_map dups_removed_fanout= 0; - for (uint j= pos->first_dupsweedout_table; j <= idx; j++) - { - POSITION *p= join->positions + j; - dups_cost += p->read_time; - if (p->table->emb_sj_nest) - { - sj_inner_fanout *= p->records_read; - dups_removed_fanout |= p->table->table->map; - } - else - { - sj_outer_fanout *= p->records_read; - temptable_rec_size += p->table->table->file->ref_length; - } - } - - /* - Add the cost of temptable use. The table will have sj_outer_fanout - records, and we will make - - sj_outer_fanout table writes - - sj_inner_fanout*sj_outer_fanout lookups. - - */ - double one_lookup_cost= get_tmp_table_lookup_cost(join->thd, - sj_outer_fanout, - temptable_rec_size); - double one_write_cost= get_tmp_table_write_cost(join->thd, - sj_outer_fanout, - temptable_rec_size); - - double write_cost= join->positions[first_tab].prefix_record_count* - sj_outer_fanout * one_write_cost; - double full_lookup_cost= join->positions[first_tab].prefix_record_count* - sj_outer_fanout* sj_inner_fanout * - one_lookup_cost; - dups_cost += write_cost + full_lookup_cost; - - /* - Use the strategy if - * it is cheaper then what we've had, or - * we haven't picked any other semi-join strategy yet - The second part is necessary because this strategy is the last one - to consider (it needs "the most" tables in the prefix) and we can't - leave duplicate-producing tables not handled by any strategy. - */ - if (dups_cost < *current_read_time || join->cur_dups_producing_tables) - { - pos->sj_strategy= SJ_OPT_DUPS_WEEDOUT; - *current_read_time= dups_cost; - *current_record_count= prefix_rec_count * sj_outer_fanout; - join->cur_dups_producing_tables &= ~dups_removed_fanout; + sj_outer_fanout *= p->records_read; + temptable_rec_size += p->table->table->file->ref_length; } } + + /* + Add the cost of temptable use. The table will have sj_outer_fanout + records, and we will make + - sj_outer_fanout table writes + - sj_inner_fanout*sj_outer_fanout lookups. + + */ + double one_lookup_cost= get_tmp_table_lookup_cost(join->thd, + sj_outer_fanout, + temptable_rec_size); + double one_write_cost= get_tmp_table_write_cost(join->thd, + sj_outer_fanout, + temptable_rec_size); + + double write_cost= join->positions[first_tab].prefix_record_count* + sj_outer_fanout * one_write_cost; + double full_lookup_cost= join->positions[first_tab].prefix_record_count* + sj_outer_fanout* sj_inner_fanout * + one_lookup_cost; + dups_cost += write_cost + full_lookup_cost; + + *read_time= dups_cost; + *record_count= prefix_rec_count * sj_outer_fanout; + *handled_fanout= dups_removed_fanout; + *strategy= SJ_OPT_DUPS_WEEDOUT; + return TRUE; } + return FALSE; } @@ -2836,11 +2974,11 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join) } else if (pos->sj_strategy == SJ_OPT_MATERIALIZE_SCAN) { - POSITION *first_inner= join->best_positions + pos->sjm_scan_last_inner; + POSITION *first_inner= join->best_positions + pos->sjmat_picker.sjm_scan_last_inner; SJ_MATERIALIZATION_INFO *sjm= first_inner->table->emb_sj_nest->sj_mat_info; sjm->is_used= TRUE; sjm->is_sj_scan= TRUE; - first= pos->sjm_scan_last_inner - sjm->tables + 1; + first= pos->sjmat_picker.sjm_scan_last_inner - sjm->tables + 1; memcpy(join->best_positions + first, sjm->positions, sizeof(POSITION) * sjm->tables); join->best_positions[first].sj_strategy= SJ_OPT_MATERIALIZE_SCAN; @@ -2878,7 +3016,7 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join) if (pos->sj_strategy == SJ_OPT_FIRST_MATCH) { - first= pos->first_firstmatch_table; + first= pos->firstmatch_picker.first_firstmatch_table; join->best_positions[first].sj_strategy= SJ_OPT_FIRST_MATCH; join->best_positions[first].n_sj_tables= tablenr - first + 1; POSITION dummy; // For loose scan paths @@ -2911,7 +3049,7 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join) if (pos->sj_strategy == SJ_OPT_LOOSE_SCAN) { - first= pos->first_loosescan_table; + first= pos->loosescan_picker.first_loosescan_table; POSITION *first_pos= join->best_positions + first; POSITION loose_scan_pos; // For loose scan paths double record_count= (first== join->const_tables)? 1.0: @@ -2950,7 +3088,7 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join) Duplicate Weedout starting at pos->first_dupsweedout_table, ending at this table. */ - first= pos->first_dupsweedout_table; + first= pos->dups_weedout_picker.first_dupsweedout_table; join->best_positions[first].sj_strategy= SJ_OPT_DUPS_WEEDOUT; join->best_positions[first].n_sj_tables= tablenr - first + 1; } @@ -3893,8 +4031,8 @@ int setup_semijoin_dups_elimination(JOIN *join, ulonglong options, /* Calculate key length */ keylen= 0; - keyno= pos->loosescan_key; - for (uint kp=0; kp < pos->loosescan_parts; kp++) + keyno= pos->loosescan_picker.loosescan_key; + 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_len= keylen; diff --git a/sql/opt_subselect.h b/sql/opt_subselect.h index 571fcbaa935..7d560588995 100644 --- a/sql/opt_subselect.h +++ b/sql/opt_subselect.h @@ -263,8 +263,8 @@ public: { pos->records_read= best_loose_scan_records; pos->key= best_loose_scan_start_key; - pos->loosescan_key= best_loose_scan_key; - pos->loosescan_parts= best_max_loose_keypart + 1; + pos->loosescan_picker.loosescan_key= best_loose_scan_key; + pos->loosescan_picker.loosescan_parts= best_max_loose_keypart + 1; pos->use_join_buffer= FALSE; pos->table= tab; // todo need ref_depend_map ? @@ -277,8 +277,7 @@ public: }; -void advance_sj_state(JOIN *join, const table_map remaining_tables, - const JOIN_TAB *new_join_tab, uint idx, +void advance_sj_state(JOIN *join, const table_map remaining_tables, uint idx, double *current_record_count, double *current_read_time, POSITION *loose_scan_pos); void restore_prev_sj_state(const table_map remaining_tables, diff --git a/sql/sql_select.cc b/sql/sql_select.cc index b9088a7ce60..ce20dfea32e 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -85,7 +85,7 @@ static int join_tab_cmp_embedded_first(const void *emb, const void* ptr1, const static bool find_best(JOIN *join,table_map rest_tables,uint index, double record_count,double read_time); static uint cache_record_length(JOIN *join,uint index); -static bool get_best_combination(JOIN *join); +bool get_best_combination(JOIN *join); static store_key *get_store_key(THD *thd, KEYUSE *keyuse, table_map used_tables, KEY_PART_INFO *key_part, uchar *key_buff, @@ -4883,7 +4883,7 @@ void set_position(JOIN *join,uint idx,JOIN_TAB *table,KEYUSE *key) join->positions[idx].records_read=1.0; /* This is a const table */ join->positions[idx].ref_depend_map= 0; - join->positions[idx].loosescan_key= MAX_KEY; /* Not a LooseScan */ +// join->positions[idx].loosescan_key= MAX_KEY; /* Not a LooseScan */ join->positions[idx].sj_strategy= SJ_OPT_NONE; join->positions[idx].use_join_buffer= FALSE; @@ -5533,7 +5533,7 @@ best_access_path(JOIN *join, pos->key= best_key; pos->table= s; pos->ref_depend_map= best_ref_depends_map; - pos->loosescan_key= MAX_KEY; + pos->loosescan_picker.loosescan_key= MAX_KEY; pos->use_join_buffer= best_uses_jbuf; loose_scan_opt.save_to_position(s, loose_scan_pos); @@ -5840,7 +5840,7 @@ optimize_straight_join(JOIN *join, table_map join_tables) /* compute the cost of the new plan extended with 's' */ record_count*= join->positions[idx].records_read; read_time+= join->positions[idx].read_time; - advance_sj_state(join, join_tables, s, idx, &record_count, &read_time, + advance_sj_state(join, join_tables, idx, &record_count, &read_time, &loose_scan_pos); join_tables&= ~(s->table->map); @@ -6356,7 +6356,7 @@ best_extension_by_limited_search(JOIN *join, current_record_count= record_count * position->records_read; current_read_time= read_time + position->read_time; - advance_sj_state(join, remaining_tables, s, idx, ¤t_record_count, + advance_sj_state(join, remaining_tables, idx, ¤t_record_count, ¤t_read_time, &loose_scan_pos); /* Expand only partial plans with lower cost than the best QEP so far */ @@ -6513,7 +6513,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, */ double current_record_count=record_count*records; double current_read_time=read_time+best; - advance_sj_state(join, rest_tables, s, idx, ¤t_record_count, + advance_sj_state(join, rest_tables, idx, ¤t_record_count, ¤t_read_time, &loose_scan_pos); if (best_record_count > current_record_count || @@ -7013,7 +7013,7 @@ static Item * const null_ptr= NULL; TRUE Out of memory */ -static bool +bool get_best_combination(JOIN *join) { uint tablenr; @@ -7091,13 +7091,6 @@ get_best_combination(JOIN *join) *j= *join->best_positions[tablenr].table; -#if 0 -/* SJ-Materialization is represented with join tab ranges */ - if (j->sj_strategy == SJ_OPT_MATERIALIZE || - j->sj_strategy == SJ_OPT_MATERIALIZE) - j->sj_strategy= SJ_OPT_NONE; -#endif - j->bush_root_tab= sjm_nest_root; form=join->table[tablenr]=j->table; @@ -7120,7 +7113,7 @@ get_best_combination(JOIN *join) (join->best_positions[tablenr].sj_strategy == SJ_OPT_LOOSE_SCAN)) { j->type=JT_ALL; - j->index= join->best_positions[tablenr].loosescan_key; + j->index= join->best_positions[tablenr].loosescan_picker.loosescan_key; if (tablenr != join->const_tables) join->full_join=1; } diff --git a/sql/sql_select.h b/sql/sql_select.h index 5476ef9b46c..21c5dc7d65e 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -158,6 +158,17 @@ enum enum_nested_loop_state }; +/* Possible sj_strategy values */ +enum sj_strategy_enum +{ + SJ_OPT_NONE=0, + SJ_OPT_DUPS_WEEDOUT=1, + SJ_OPT_LOOSE_SCAN =2, + SJ_OPT_FIRST_MATCH =3, + SJ_OPT_MATERIALIZE =4, + SJ_OPT_MATERIALIZE_SCAN=5 +}; + /* Values for JOIN_TAB::packed_info */ #define TAB_INFO_HAVE_VALUE 1 #define TAB_INFO_USING_INDEX 2 @@ -374,7 +385,7 @@ typedef struct st_join_table { POSITION::sj_strategy field. This field is set up by the fix_semijoin_strategies_for_picked_join_order. */ - uint sj_strategy; + enum sj_strategy_enum sj_strategy; uint n_sj_tables; @@ -496,66 +507,126 @@ enum_nested_loop_state end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), bool end_of_records); +/* psergey */ -/** - Information about a position of table within a join order. Used in join - optimization. -*/ -typedef struct st_position + +struct st_position; + +class Semi_join_strategy_picker { - /* - The "fanout": number of output rows that will be produced (after - pushed down selection condition is applied) per each row combination of - previous tables. - */ - double records_read; +public: + /* Called when starting to build a new join prefix */ + virtual void set_empty() = 0; /* - Cost accessing the table in course of the entire complete join execution, - i.e. cost of one access method use (e.g. 'range' or 'ref' scan ) times - number the access method will be invoked. + Update internal state after another table has been added to the join + prefix */ - double read_time; - JOIN_TAB *table; - - /* - NULL - 'index' or 'range' or 'index_merge' or 'ALL' access is used. - Other - [eq_]ref[_or_null] access is used. Pointer to {t.keypart1 = expr} - */ - KEYUSE *key; - - /* If ref-based access is used: bitmap of tables this table depends on */ - table_map ref_depend_map; - - bool use_join_buffer; + virtual void set_from_prev(struct st_position *prev) = 0; + virtual bool check_qep(JOIN *join, + uint idx, + table_map remaining_tables, + const JOIN_TAB *new_join_tab, + double *record_count, + double *read_time, + table_map *handled_fanout, + sj_strategy_enum *strategy, + struct st_position *loose_scan_pos) = 0; + + virtual void mark_used() = 0; + + virtual ~Semi_join_strategy_picker() {} +}; + + +/* + Duplicate Weedout strategy optimization state +*/ + +class Duplicate_weedout_picker : public Semi_join_strategy_picker +{ + /* The first table that the strategy will need to handle */ + uint first_dupsweedout_table; + + /* + Tables that we will need to have in the prefix to do the weedout step + (all inner and all outer that the involved semi-joins are correlated with) + */ + table_map dupsweedout_tables; - /* These form a stack of partial join order costs and output sizes */ - COST_VECT prefix_cost; - double prefix_record_count; + bool is_used; +public: + void set_empty() + { + dupsweedout_tables= 0; + first_dupsweedout_table= MAX_TABLES; + is_used= FALSE; + } + void set_from_prev(struct st_position *prev); + + bool check_qep(JOIN *join, + uint idx, + table_map remaining_tables, + const JOIN_TAB *new_join_tab, + double *record_count, + double *read_time, + table_map *handled_fanout, + sj_strategy_enum *stratey, + struct st_position *loose_scan_pos); + void mark_used() { is_used= TRUE; } + friend void fix_semijoin_strategies_for_picked_join_order(JOIN *join); +}; + + +class Firstmatch_picker : public Semi_join_strategy_picker +{ /* - Current optimization state: Semi-join strategy to be used for this - and preceding join tables. - - Join optimizer sets this for the *last* join_tab in the - duplicate-generating range. That is, in order to interpret this field, - one needs to traverse join->[best_]positions array from right to left. - When you see a join table with sj_strategy!= SJ_OPT_NONE, some other - field (depending on the strategy) tells how many preceding positions - this applies to. The values of covered_preceding_positions->sj_strategy - must be ignored. + Index of the first inner table that we intend to handle with this + strategy */ - uint sj_strategy; + uint first_firstmatch_table; /* - Valid only after fix_semijoin_strategies_for_picked_join_order() call: - if sj_strategy!=SJ_OPT_NONE, this is the number of subsequent tables that - are covered by the specified semi-join strategy + Tables that were not in the join prefix when we've started considering + FirstMatch strategy. */ - uint n_sj_tables; + table_map first_firstmatch_rtbl; + /* + Tables that need to be in the prefix before we can calculate the cost + of using FirstMatch strategy. + */ + table_map firstmatch_need_tables; -/* LooseScan strategy members */ + bool is_used; + bool in_firstmatch_prefix() { return (first_firstmatch_table != MAX_TABLES); } + void invalidate_firstmatch_prefix() { first_firstmatch_table= MAX_TABLES; } +public: + void set_empty() + { + invalidate_firstmatch_prefix(); + is_used= FALSE; + } + + void set_from_prev(struct st_position *prev); + bool check_qep(JOIN *join, + uint idx, + table_map remaining_tables, + const JOIN_TAB *new_join_tab, + double *record_count, + double *read_time, + table_map *handled_fanout, + sj_strategy_enum *strategy, + struct st_position *loose_scan_pos); + + void mark_used() { is_used= TRUE; } + friend void fix_semijoin_strategies_for_picked_join_order(JOIN *join); +}; + + +class LooseScan_picker : public Semi_join_strategy_picker +{ /* The first (i.e. driving) table we're doing loose scan for */ uint first_loosescan_table; /* @@ -573,36 +644,46 @@ typedef struct st_position uint loosescan_key; // final (one for strategy instance ) uint loosescan_parts; /* Number of keyparts to be kept distinct */ -/* FirstMatch strategy */ - /* - Index of the first inner table that we intend to handle with this - strategy - */ - uint first_firstmatch_table; - /* - Tables that were not in the join prefix when we've started considering - FirstMatch strategy. - */ - table_map first_firstmatch_rtbl; - /* - Tables that need to be in the prefix before we can calculate the cost - of using FirstMatch strategy. - */ - table_map firstmatch_need_tables; + bool is_used; +public: + void set_empty() + { + first_loosescan_table= MAX_TABLES; + is_used= FALSE; + } - bool in_firstmatch_prefix() { return (first_firstmatch_table != MAX_TABLES); } - void invalidate_firstmatch_prefix() { first_firstmatch_table= MAX_TABLES; } + void set_from_prev(struct st_position *prev); + bool check_qep(JOIN *join, + uint idx, + table_map remaining_tables, + const JOIN_TAB *new_join_tab, + double *record_count, + double *read_time, + table_map *handled_fanout, + sj_strategy_enum *strategy, + struct st_position *loose_scan_pos); + void mark_used() { is_used= TRUE; } -/* Duplicate Weedout strategy */ - /* The first table that the strategy will need to handle */ - uint first_dupsweedout_table; - /* - Tables that we will need to have in the prefix to do the weedout step - (all inner and all outer that the involved semi-joins are correlated with) - */ - table_map dupsweedout_tables; + friend class Loose_scan_opt; + friend void best_access_path(JOIN *join, + JOIN_TAB *s, + table_map remaining_tables, + uint idx, + bool disable_jbuf, + double record_count, + struct st_position *pos, + struct st_position *loose_scan_pos); + friend bool get_best_combination(JOIN *join); + friend int setup_semijoin_dups_elimination(JOIN *join, ulonglong options, + uint no_jbuf_after); + friend void fix_semijoin_strategies_for_picked_join_order(JOIN *join); +}; + + +class Sj_materialization_picker : public Semi_join_strategy_picker +{ + bool is_used; -/* SJ-Materialization-Scan strategy */ /* The last inner table (valid once we're after it) */ uint sjm_scan_last_inner; /* @@ -612,9 +693,101 @@ typedef struct st_position */ table_map sjm_scan_need_tables; - table_map prefix_dups_producing_tables; -} POSITION; +public: + void set_empty() + { + sjm_scan_need_tables= 0; + LINT_INIT(sjm_scan_last_inner); + is_used= FALSE; + } + void set_from_prev(struct st_position *prev); + bool check_qep(JOIN *join, + uint idx, + table_map remaining_tables, + const JOIN_TAB *new_join_tab, + double *record_count, + double *read_time, + table_map *handled_fanout, + sj_strategy_enum *strategy, + struct st_position *loose_scan_pos); + void mark_used() { is_used= TRUE; } + friend void fix_semijoin_strategies_for_picked_join_order(JOIN *join); +}; + + +/** + Information about a position of table within a join order. Used in join + optimization. +*/ +typedef struct st_position +{ + /* The table that's put into join order */ + JOIN_TAB *table; + + /* + The "fanout": number of output rows that will be produced (after + pushed down selection condition is applied) per each row combination of + previous tables. + */ + double records_read; + + /* + Cost accessing the table in course of the entire complete join execution, + i.e. cost of one access method use (e.g. 'range' or 'ref' scan ) times + number the access method will be invoked. + */ + double read_time; + + /* Cumulative cost and record count for the join prefix */ + COST_VECT prefix_cost; + double prefix_record_count; + + /* + NULL - 'index' or 'range' or 'index_merge' or 'ALL' access is used. + Other - [eq_]ref[_or_null] access is used. Pointer to {t.keypart1 = expr} + */ + KEYUSE *key; + + /* If ref-based access is used: bitmap of tables this table depends on */ + table_map ref_depend_map; + + /* + TRUE <=> join buffering will be used. At the moment this is based on + *very* imprecise guesses made in best_access_path(). + */ + bool use_join_buffer; + + /* + Current optimization state: Semi-join strategy to be used for this + and preceding join tables. + + Join optimizer sets this for the *last* join_tab in the + duplicate-generating range. That is, in order to interpret this field, + one needs to traverse join->[best_]positions array from right to left. + When you see a join table with sj_strategy!= SJ_OPT_NONE, some other + field (depending on the strategy) tells how many preceding positions + this applies to. The values of covered_preceding_positions->sj_strategy + must be ignored. + */ + enum sj_strategy_enum sj_strategy; + + /* + Valid only after fix_semijoin_strategies_for_picked_join_order() call: + if sj_strategy!=SJ_OPT_NONE, this is the number of subsequent tables that + are covered by the specified semi-join strategy + */ + uint n_sj_tables; + + table_map prefix_dups_producing_tables; + + table_map inner_tables_handled_with_other_sjs; + + Duplicate_weedout_picker dups_weedout_picker; + Firstmatch_picker firstmatch_picker; + LooseScan_picker loosescan_picker; + Sj_materialization_picker sjmat_picker; +} POSITION; typedef struct st_rollup { @@ -626,18 +799,6 @@ typedef struct st_rollup } ROLLUP; -#define SJ_OPT_NONE 0 -#define SJ_OPT_DUPS_WEEDOUT 1 -#define SJ_OPT_LOOSE_SCAN 2 -#define SJ_OPT_FIRST_MATCH 3 -#define SJ_OPT_MATERIALIZE 4 -#define SJ_OPT_MATERIALIZE_SCAN 5 - -inline bool sj_is_materialize_strategy(uint strategy) -{ - return strategy >= SJ_OPT_MATERIALIZE; -} - class JOIN_TAB_RANGE: public Sql_alloc { public: @@ -808,7 +969,7 @@ public: they produce. */ table_map cur_dups_producing_tables; - + /* We also maintain a stack of join optimization states in * join->positions[] */ /******* Join optimization state members end *******/ /* From c8768a091ac2d876216582813aaab7d9663008f7 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Wed, 23 Nov 2011 10:25:27 +0200 Subject: [PATCH 104/288] Fixes of testcases after merge with MySQL 5.1.59 --- mysql-test/r/index_merge_innodb.result | 4 +- mysql-test/r/rowid_order_innodb.result | 2 +- mysql-test/r/type_bit_innodb.result | 2 +- .../suite/innodb/r/innodb_bug59641.result | 1 + mysql-test/suite/innodb/r/innodb_gis.result | 2 +- mysql-test/suite/innodb/r/innodb_mysql.result | 79 +++++++++++++------ .../suite/innodb/t/innodb_bug59641.test | 3 + mysql-test/suite/innodb/t/innodb_mysql.test | 62 +++++++++++++++ .../innodb_plugin/r/innodb_bug59641.result | 1 + .../suite/innodb_plugin/r/innodb_gis.result | 2 +- .../suite/innodb_plugin/r/innodb_mysql.result | 38 ++++----- mysql-test/suite/innodb_plugin/t/disabled.def | 1 + .../innodb_plugin/t/innodb_bug59641.test | 3 + mysql-test/t/endspace.test | 2 + 14 files changed, 151 insertions(+), 51 deletions(-) diff --git a/mysql-test/r/index_merge_innodb.result b/mysql-test/r/index_merge_innodb.result index fdc5b57a2e3..157cf007dfd 100644 --- a/mysql-test/r/index_merge_innodb.result +++ b/mysql-test/r/index_merge_innodb.result @@ -346,7 +346,7 @@ SELECT a FROM t1 WHERE c = 1 AND b = 1 AND d = 1; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge c,bd c,bd 5,10 NULL 1 Using intersect(c,bd); Using where; Using index +1 SIMPLE t1 ref c,bd bd 10 const,const 2 Using where CREATE TABLE t2 ( a INT ) SELECT a FROM t1 @@ -690,7 +690,7 @@ SELECT COUNT(*) FROM WHERE a BETWEEN 2 AND 7 OR pk=1000000) AS t; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Select tables optimized away -2 DERIVED t1 index_merge PRIMARY,idx idx,PRIMARY 5,4 NULL 11419 Using sort_union(idx,PRIMARY); Using where +2 DERIVED t1 index_merge PRIMARY,idx idx,PRIMARY 5,4 NULL 6144 Using sort_union(idx,PRIMARY); Using where SELECT COUNT(*) FROM (SELECT * FROM t1 FORCE INDEX(primary,idx) WHERE a BETWEEN 2 AND 7 OR pk=1000000) AS t; diff --git a/mysql-test/r/rowid_order_innodb.result b/mysql-test/r/rowid_order_innodb.result index e0796cd7ab5..dc339304041 100644 --- a/mysql-test/r/rowid_order_innodb.result +++ b/mysql-test/r/rowid_order_innodb.result @@ -15,7 +15,7 @@ insert into t1 values (-5, 1, 1), (10, 1, 1); explain select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge key1,key2 key1,key2 5,5 NULL 4 Using sort_union(key1,key2); Using where +1 SIMPLE t1 index_merge key1,key2 key1,key2 5,5 NULL 5 Using sort_union(key1,key2); Using where select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3; pk1 key1 key2 -100 1 1 diff --git a/mysql-test/r/type_bit_innodb.result b/mysql-test/r/type_bit_innodb.result index a9c3cae1770..909db576b27 100644 --- a/mysql-test/r/type_bit_innodb.result +++ b/mysql-test/r/type_bit_innodb.result @@ -233,7 +233,7 @@ a+0 b+0 127 403 explain select a+0, b+0 from t1 where a > 40 and b > 200 order by 1; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range a a 2 NULL 19 Using where; Using index; Using filesort +1 SIMPLE t1 range a a 2 NULL 27 Using where; Using index; Using filesort select a+0, b+0 from t1 where a > 40 and b > 200 order by 1; a+0 b+0 44 307 diff --git a/mysql-test/suite/innodb/r/innodb_bug59641.result b/mysql-test/suite/innodb/r/innodb_bug59641.result index 361172aa82b..482df8914eb 100644 --- a/mysql-test/suite/innodb/r/innodb_bug59641.result +++ b/mysql-test/suite/innodb/r/innodb_bug59641.result @@ -1,3 +1,4 @@ +flush tables; CREATE TABLE t(a INT PRIMARY KEY, b INT)ENGINE=InnoDB; INSERT INTO t VALUES(2,2),(4,4),(8,8),(16,16),(32,32); COMMIT; diff --git a/mysql-test/suite/innodb/r/innodb_gis.result b/mysql-test/suite/innodb/r/innodb_gis.result index a52a1387b6e..30daaf129b1 100644 --- a/mysql-test/suite/innodb/r/innodb_gis.result +++ b/mysql-test/suite/innodb/r/innodb_gis.result @@ -572,7 +572,7 @@ COUNT(*) EXPLAIN SELECT COUNT(*) FROM t2 WHERE p=POINTFROMTEXT('POINT(1 2)'); id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 ref p p 28 const 1 Using where +1 SIMPLE t2 ref p p 28 const 2 Using where SELECT COUNT(*) FROM t2 WHERE p=POINTFROMTEXT('POINT(1 2)'); COUNT(*) 2 diff --git a/mysql-test/suite/innodb/r/innodb_mysql.result b/mysql-test/suite/innodb/r/innodb_mysql.result index df2fb3f34cf..42aca8b6464 100644 --- a/mysql-test/suite/innodb/r/innodb_mysql.result +++ b/mysql-test/suite/innodb/r/innodb_mysql.result @@ -889,13 +889,13 @@ EXPLAIN SELECT * FROM t1 WHERE b BETWEEN 1 AND 2 ORDER BY a; id 1 select_type SIMPLE table t1 -type range +type index possible_keys bkey -key bkey -key_len 5 +key PRIMARY +key_len 4 ref NULL -rows 16 -Extra Using where; Using index; Using filesort +rows 32 +Extra Using where SELECT * FROM t1 WHERE b BETWEEN 1 AND 2 ORDER BY a; a b 1 2 @@ -934,12 +934,12 @@ EXPLAIN SELECT * FROM t1 WHERE b BETWEEN 1 AND 2 ORDER BY b,a; id 1 select_type SIMPLE table t1 -type range +type index possible_keys bkey key bkey key_len 5 ref NULL -rows 16 +rows 32 Extra Using where; Using index SELECT * FROM t1 WHERE b BETWEEN 1 AND 2 ORDER BY b,a; a b @@ -989,7 +989,7 @@ possible_keys bkey key bkey key_len 5 ref const -rows 8 +rows 16 Extra Using where; Using index; Using filesort SELECT * FROM t2 WHERE b=1 ORDER BY a; a b c @@ -1018,7 +1018,7 @@ possible_keys bkey key bkey key_len 10 ref const,const -rows 8 +rows 16 Extra Using where; Using index SELECT * FROM t2 WHERE b=1 AND c=1 ORDER BY a; a b c @@ -1047,7 +1047,7 @@ possible_keys bkey key bkey key_len 10 ref const,const -rows 8 +rows 16 Extra Using where; Using index SELECT * FROM t2 WHERE b=1 AND c=1 ORDER BY b,c,a; a b c @@ -1076,7 +1076,7 @@ possible_keys bkey key bkey key_len 10 ref const,const -rows 8 +rows 16 Extra Using where; Using index SELECT * FROM t2 WHERE b=1 AND c=1 ORDER BY c,a; a b c @@ -1211,7 +1211,7 @@ possible_keys b key b key_len 5 ref const -rows 1 +rows 2 Extra Using where; Using index SELECT * FROM t1 WHERE b=2 ORDER BY a ASC; a b @@ -1226,7 +1226,7 @@ possible_keys b key b key_len 5 ref const -rows 1 +rows 2 Extra Using where; Using index SELECT * FROM t1 WHERE b=2 ORDER BY a DESC; a b @@ -1370,7 +1370,7 @@ INSERT INTO t1 (a,b,c) VALUES (1,1,1), (2,1,1), (3,1,1), (4,1,1); INSERT INTO t1 (a,b,c) SELECT a+4,b,c FROM t1; EXPLAIN SELECT a, b, c FROM t1 WHERE b = 1 ORDER BY a DESC LIMIT 5; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index t1_b PRIMARY 4 NULL 8 Using where +1 SIMPLE t1 range t1_b t1_b 5 NULL 8 Using where SELECT a, b, c FROM t1 WHERE b = 1 ORDER BY a DESC LIMIT 5; a b c 8 1 1 @@ -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 index c3,c2 c2 10 NULL 5 +2 DERIVED t1 ALL c3,c2 c3 5 5 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 index c3,c2 c2 18 NULL 5 +2 DERIVED t1 ALL c3,c2 c3 9 5 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 index c3,c2 c2 14 NULL 5 +2 DERIVED t1 ALL c3,c2 c3 7 5 Using filesort DROP TABLE t1; End of 5.1 tests drop table if exists t1, t2, t3; @@ -1844,7 +1844,7 @@ possible_keys b key b key_len 5 ref NULL -rows 3 +rows 5 Extra Using where; Using index EXPLAIN SELECT c FROM bar WHERE c>2;; id 1 @@ -2306,6 +2306,28 @@ id select_type table type possible_keys key key_len ref rows Extra drop table t1,t2; # # +# Bug #39653: find_shortest_key in sql_select.cc does not consider +# clustered primary keys +# +CREATE TABLE t1 (a INT PRIMARY KEY, b INT, c INT, d INT, e INT, f INT, +KEY (b,c)) ENGINE=INNODB; +INSERT INTO t1 VALUES (1,1,1,1,1,1), (2,2,2,2,2,2), (3,3,3,3,3,3), +(4,4,4,4,4,4), (5,5,5,5,5,5), (6,6,6,6,6,6), +(7,7,7,7,7,7), (8,8,8,8,8,8), (9,9,9,9,9,9), +(11,11,11,11,11,11); +EXPLAIN SELECT COUNT(*) FROM t1; +id 1 +select_type SIMPLE +table t1 +type index +possible_keys NULL +key PRIMARY +key_len 4 +ref NULL +rows 10 +Extra Using index +DROP TABLE t1; +# # Bug #49838: DROP INDEX and ADD UNIQUE INDEX for same index may # corrupt definition at engine # @@ -2515,7 +2537,7 @@ f1 f2 f3 f4 EXPLAIN SELECT * FROM t1 WHERE f2 = 1 AND f4 = TRUE ORDER BY f1 DESC LIMIT 5; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range f2,f4 f4 1 NULL 11 Using where +1 SIMPLE t1 range f2,f4 f4 1 NULL 22 Using where DROP TABLE t1; # # Bug#54117 crash in thr_multi_unlock, temporary table @@ -2617,13 +2639,8 @@ rows 3 Extra Using index DROP TABLE t1; # -# ALTER TABLE IGNORE didn't ignore duplicates for unique add index +# Bug#56862 Execution of a query that uses index merge returns a wrong result # -create table t1 (a int primary key, b int) engine = innodb; -insert into t1 values (1,1),(2,1); -alter ignore table t1 add unique `main` (b); -drop table t1; -End of 5.1 tests CREATE TABLE t1 ( pk int NOT NULL AUTO_INCREMENT PRIMARY KEY, a int, @@ -2654,7 +2671,7 @@ SELECT COUNT(*) FROM WHERE a BETWEEN 2 AND 7 OR pk=1000000) AS t; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Select tables optimized away -2 DERIVED t1 index_merge PRIMARY,idx idx,PRIMARY 5,4 NULL 3537 Using sort_union(idx,PRIMARY); Using where +2 DERIVED t1 index_merge PRIMARY,idx idx,PRIMARY 5,4 NULL 1536 Using sort_union(idx,PRIMARY); Using where SELECT COUNT(*) FROM (SELECT * FROM t1 FORCE INDEX (idx,PRIMARY) WHERE a BETWEEN 2 AND 7 OR pk=1000000) AS t; @@ -2663,6 +2680,16 @@ COUNT(*) SET SESSION sort_buffer_size = DEFAULT; DROP TABLE t1; # +# ALTER TABLE IGNORE didn't ignore duplicates for unique add index +# +create table t1 (a int primary key, b int) engine = innodb; +insert into t1 values (1,1),(2,1); +alter ignore table t1 add unique `main` (b); +select * from t1; +a b +1 1 +drop table t1; +# # Test for bug #39932 "create table fails if column for FK is in different # case than in corr index". # diff --git a/mysql-test/suite/innodb/t/innodb_bug59641.test b/mysql-test/suite/innodb/t/innodb_bug59641.test index 0237673061c..e19dec54bc2 100644 --- a/mysql-test/suite/innodb/t/innodb_bug59641.test +++ b/mysql-test/suite/innodb/t/innodb_bug59641.test @@ -3,6 +3,9 @@ -- source include/not_embedded.inc -- source include/have_innodb.inc +# Close tables used by other tests (to not get crashed myisam tables) +flush tables; + CREATE TABLE t(a INT PRIMARY KEY, b INT)ENGINE=InnoDB; INSERT INTO t VALUES(2,2),(4,4),(8,8),(16,16),(32,32); COMMIT; diff --git a/mysql-test/suite/innodb/t/innodb_mysql.test b/mysql-test/suite/innodb/t/innodb_mysql.test index 9fc812c2d07..0b34245dda0 100644 --- a/mysql-test/suite/innodb/t/innodb_mysql.test +++ b/mysql-test/suite/innodb/t/innodb_mysql.test @@ -558,6 +558,23 @@ drop table t1,t2; --echo # +--echo # +--echo # Bug #39653: find_shortest_key in sql_select.cc does not consider +--echo # clustered primary keys +--echo # + +CREATE TABLE t1 (a INT PRIMARY KEY, b INT, c INT, d INT, e INT, f INT, + KEY (b,c)) ENGINE=INNODB; + +INSERT INTO t1 VALUES (1,1,1,1,1,1), (2,2,2,2,2,2), (3,3,3,3,3,3), + (4,4,4,4,4,4), (5,5,5,5,5,5), (6,6,6,6,6,6), + (7,7,7,7,7,7), (8,8,8,8,8,8), (9,9,9,9,9,9), + (11,11,11,11,11,11); + +--query_vertical EXPLAIN SELECT COUNT(*) FROM t1 + +DROP TABLE t1; + --echo # --echo # Bug #49838: DROP INDEX and ADD UNIQUE INDEX for same index may --echo # corrupt definition at engine @@ -840,6 +857,50 @@ CREATE INDEX b ON t1(a,b,c,d); DROP TABLE t1; +--echo # +--echo # Bug#56862 Execution of a query that uses index merge returns a wrong result +--echo # + +CREATE TABLE t1 ( + pk int NOT NULL AUTO_INCREMENT PRIMARY KEY, + a int, + b int, + INDEX idx(a)) +ENGINE=INNODB; + +INSERT INTO t1(a,b) VALUES + (11, 1100), (2, 200), (1, 100), (14, 1400), (5, 500), + (3, 300), (17, 1700), (4, 400), (12, 1200), (8, 800), + (6, 600), (18, 1800), (9, 900), (10, 1000), (7, 700), + (13, 1300), (15, 1500), (19, 1900), (16, 1600), (20, 2000); +INSERT INTO t1(a,b) SELECT a+20, b+2000 FROM t1; +INSERT INTO t1(a,b) SELECT a+40, b+4000 FROM t1; +INSERT INTO t1(a,b) SELECT a+80, b+8000 FROM t1; +INSERT INTO t1(a,b) SELECT a,b FROM t1; +INSERT INTO t1(a,b) SELECT a,b FROM t1; +INSERT INTO t1(a,b) SELECT a,b FROM t1; +INSERT INTO t1(a,b) SELECT a,b FROM t1; +INSERT INTO t1(a,b) SELECT a,b FROM t1; +INSERT INTO t1(a,b) SELECT a,b FROM t1; +INSERT INTO t1(a,b) SELECT a,b FROM t1; +INSERT INTO t1(a,b) SELECT a,b FROM t1; +INSERT INTO t1 VALUES (1000000, 0, 0); + +SET SESSION sort_buffer_size = 1024*36; + +EXPLAIN +SELECT COUNT(*) FROM + (SELECT * FROM t1 FORCE INDEX (idx,PRIMARY) + WHERE a BETWEEN 2 AND 7 OR pk=1000000) AS t; + +SELECT COUNT(*) FROM + (SELECT * FROM t1 FORCE INDEX (idx,PRIMARY) + WHERE a BETWEEN 2 AND 7 OR pk=1000000) AS t; + +SET SESSION sort_buffer_size = DEFAULT; + +DROP TABLE t1; + --echo # --echo # ALTER TABLE IGNORE didn't ignore duplicates for unique add index --echo # @@ -847,6 +908,7 @@ DROP TABLE t1; create table t1 (a int primary key, b int) engine = innodb; insert into t1 values (1,1),(2,1); alter ignore table t1 add unique `main` (b); +select * from t1; drop table t1; --echo # diff --git a/mysql-test/suite/innodb_plugin/r/innodb_bug59641.result b/mysql-test/suite/innodb_plugin/r/innodb_bug59641.result index 361172aa82b..482df8914eb 100644 --- a/mysql-test/suite/innodb_plugin/r/innodb_bug59641.result +++ b/mysql-test/suite/innodb_plugin/r/innodb_bug59641.result @@ -1,3 +1,4 @@ +flush tables; CREATE TABLE t(a INT PRIMARY KEY, b INT)ENGINE=InnoDB; INSERT INTO t VALUES(2,2),(4,4),(8,8),(16,16),(32,32); COMMIT; diff --git a/mysql-test/suite/innodb_plugin/r/innodb_gis.result b/mysql-test/suite/innodb_plugin/r/innodb_gis.result index a52a1387b6e..30daaf129b1 100644 --- a/mysql-test/suite/innodb_plugin/r/innodb_gis.result +++ b/mysql-test/suite/innodb_plugin/r/innodb_gis.result @@ -572,7 +572,7 @@ COUNT(*) EXPLAIN SELECT COUNT(*) FROM t2 WHERE p=POINTFROMTEXT('POINT(1 2)'); id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 ref p p 28 const 1 Using where +1 SIMPLE t2 ref p p 28 const 2 Using where SELECT COUNT(*) FROM t2 WHERE p=POINTFROMTEXT('POINT(1 2)'); COUNT(*) 2 diff --git a/mysql-test/suite/innodb_plugin/r/innodb_mysql.result b/mysql-test/suite/innodb_plugin/r/innodb_mysql.result index 407e56e4aef..86d83f82b76 100644 --- a/mysql-test/suite/innodb_plugin/r/innodb_mysql.result +++ b/mysql-test/suite/innodb_plugin/r/innodb_mysql.result @@ -889,13 +889,13 @@ EXPLAIN SELECT * FROM t1 WHERE b BETWEEN 1 AND 2 ORDER BY a; id 1 select_type SIMPLE table t1 -type range +type index possible_keys bkey -key bkey -key_len 5 +key PRIMARY +key_len 4 ref NULL -rows 16 -Extra Using where; Using index; Using filesort +rows 32 +Extra Using where SELECT * FROM t1 WHERE b BETWEEN 1 AND 2 ORDER BY a; a b 1 2 @@ -934,12 +934,12 @@ EXPLAIN SELECT * FROM t1 WHERE b BETWEEN 1 AND 2 ORDER BY b,a; id 1 select_type SIMPLE table t1 -type range +type index possible_keys bkey key bkey key_len 5 ref NULL -rows 16 +rows 32 Extra Using where; Using index SELECT * FROM t1 WHERE b BETWEEN 1 AND 2 ORDER BY b,a; a b @@ -989,7 +989,7 @@ possible_keys bkey key bkey key_len 5 ref const -rows 8 +rows 16 Extra Using where; Using index; Using filesort SELECT * FROM t2 WHERE b=1 ORDER BY a; a b c @@ -1018,7 +1018,7 @@ possible_keys bkey key bkey key_len 10 ref const,const -rows 8 +rows 16 Extra Using where; Using index SELECT * FROM t2 WHERE b=1 AND c=1 ORDER BY a; a b c @@ -1047,7 +1047,7 @@ possible_keys bkey key bkey key_len 10 ref const,const -rows 8 +rows 16 Extra Using where; Using index SELECT * FROM t2 WHERE b=1 AND c=1 ORDER BY b,c,a; a b c @@ -1076,7 +1076,7 @@ possible_keys bkey key bkey key_len 10 ref const,const -rows 8 +rows 16 Extra Using where; Using index SELECT * FROM t2 WHERE b=1 AND c=1 ORDER BY c,a; a b c @@ -1211,7 +1211,7 @@ possible_keys b key b key_len 5 ref const -rows 1 +rows 2 Extra Using where; Using index SELECT * FROM t1 WHERE b=2 ORDER BY a ASC; a b @@ -1226,7 +1226,7 @@ possible_keys b key b key_len 5 ref const -rows 1 +rows 2 Extra Using where; Using index SELECT * FROM t1 WHERE b=2 ORDER BY a DESC; a b @@ -1370,7 +1370,7 @@ INSERT INTO t1 (a,b,c) VALUES (1,1,1), (2,1,1), (3,1,1), (4,1,1); INSERT INTO t1 (a,b,c) SELECT a+4,b,c FROM t1; EXPLAIN SELECT a, b, c FROM t1 WHERE b = 1 ORDER BY a DESC LIMIT 5; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index t1_b PRIMARY 4 NULL 8 Using where +1 SIMPLE t1 range t1_b t1_b 5 NULL 8 Using where SELECT a, b, c FROM t1 WHERE b = 1 ORDER BY a DESC LIMIT 5; a b c 8 1 1 @@ -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 index c3,c2 c2 10 NULL 5 +2 DERIVED t1 ALL c3,c2 c3 5 5 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 index c3,c2 c2 18 NULL 5 +2 DERIVED t1 ALL c3,c2 c3 9 5 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 index c3,c2 c2 14 NULL 5 +2 DERIVED t1 ALL c3,c2 c3 7 5 Using filesort DROP TABLE t1; End of 5.1 tests drop table if exists t1, t2, t3; @@ -1844,7 +1844,7 @@ possible_keys b key b key_len 5 ref NULL -rows 3 +rows 5 Extra Using where; Using index EXPLAIN SELECT c FROM bar WHERE c>2;; id 1 @@ -2440,7 +2440,7 @@ SELECT COUNT(*) FROM WHERE a BETWEEN 2 AND 7 OR pk=1000000) AS t; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Select tables optimized away -2 DERIVED t1 index_merge PRIMARY,idx idx,PRIMARY 5,4 NULL 3537 Using sort_union(idx,PRIMARY); Using where +2 DERIVED t1 index_merge PRIMARY,idx idx,PRIMARY 5,4 NULL 1536 Using sort_union(idx,PRIMARY); Using where SELECT COUNT(*) FROM (SELECT * FROM t1 FORCE INDEX (idx,PRIMARY) WHERE a BETWEEN 2 AND 7 OR pk=1000000) AS t; diff --git a/mysql-test/suite/innodb_plugin/t/disabled.def b/mysql-test/suite/innodb_plugin/t/disabled.def index 4c37bbc87ed..3ec373136ec 100644 --- a/mysql-test/suite/innodb_plugin/t/disabled.def +++ b/mysql-test/suite/innodb_plugin/t/disabled.def @@ -11,3 +11,4 @@ ############################################################################## innodb_bug52745: Disabled as this has valgrind failures (also in MySQL 5.1.50) +innodb-index: Disabled until merging with XtraDB 5.1.60 diff --git a/mysql-test/suite/innodb_plugin/t/innodb_bug59641.test b/mysql-test/suite/innodb_plugin/t/innodb_bug59641.test index 0fb24e47a54..b0e2dcb6cc5 100644 --- a/mysql-test/suite/innodb_plugin/t/innodb_bug59641.test +++ b/mysql-test/suite/innodb_plugin/t/innodb_bug59641.test @@ -5,6 +5,9 @@ let $innodb_file_format_check_orig=`select @@innodb_file_format_check`; +# Close tables used by other tests (to not get crashed myisam tables) +flush tables; + CREATE TABLE t(a INT PRIMARY KEY, b INT)ENGINE=InnoDB; INSERT INTO t VALUES(2,2),(4,4),(8,8),(16,16),(32,32); COMMIT; diff --git a/mysql-test/t/endspace.test b/mysql-test/t/endspace.test index b223c683cde..072000ce3cc 100644 --- a/mysql-test/t/endspace.test +++ b/mysql-test/t/endspace.test @@ -93,7 +93,9 @@ alter table t1 modify text1 text not null, pack_keys=1; select * from t1 where text1 like 'teststring_%'; # The following gives wrong result in InnoDB +--sorted_result select text1, length(text1) from t1 where text1='teststring' or text1 like 'teststring_%'; +--sorted_result select text1, length(text1) from t1 where text1='teststring' or text1 >= 'teststring\t'; select concat('|', text1, '|') from t1 order by text1; drop table t1; From e065b124fd30d2f471b731238f4d71c4780c5c0d Mon Sep 17 00:00:00 2001 From: Build Team Date: Wed, 23 Nov 2011 12:33:59 +0100 Subject: [PATCH 105/288] Bumped version number to 5.5.20 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 4eec6bf9d34..508f021f35d 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ MYSQL_VERSION_MAJOR=5 MYSQL_VERSION_MINOR=5 -MYSQL_VERSION_PATCH=19 +MYSQL_VERSION_PATCH=20 MYSQL_VERSION_EXTRA= From a00f87bf155fda703ffd314e5d8166583db92d93 Mon Sep 17 00:00:00 2001 From: Ashish Agarwal Date: Wed, 23 Nov 2011 18:33:29 +0530 Subject: [PATCH 106/288] BUG#11751793 - 42784: ARCHIVE TABLES CAUSE 100% CPU USAGE AND HANG IN SHOW TABLE STATUS. ISSUE: Table corruption due to concurrent queries. Different threads running insert and check query leads to table corruption. Not properly locked, rows are inserted in between check query. SOLUTION: In check query mutex lock is acquired for a longer time to handle concurrent insert and check query. NOTE: Additionally we backported the fix for CHECKSUM issue(bug#11758979). --- mysql-test/r/archive.result | 19 ++++++++++++++ mysql-test/t/archive.test | 14 ++++++++++ storage/archive/ha_archive.cc | 48 ++++++++++++++++++++++++++++------- 3 files changed, 72 insertions(+), 9 deletions(-) diff --git a/mysql-test/r/archive.result b/mysql-test/r/archive.result index 15ded03f414..69f5adf5b5d 100644 --- a/mysql-test/r/archive.result +++ b/mysql-test/r/archive.result @@ -12772,3 +12772,22 @@ a b c d e f -1 b c d e 1 DROP TABLE t1; SET sort_buffer_size=DEFAULT; +# +# BUG#11758979 - 51252: ARCHIVE TABLES CAUSE 100% CPU USAGE +# AND HANG IN SHOW TABLE STATUS +# (to be executed with valgrind) +CREATE TABLE t1(a BLOB, b VARCHAR(200)) ENGINE=ARCHIVE; +INSERT INTO t1 VALUES(NULL, ''); +FLUSH TABLE t1; +# we need this select to workaround BUG#11764364 +SELECT * FROM t1; +a b +NULL +CHECKSUM TABLE t1 EXTENDED; +Table Checksum +test.t1 286155052 +FLUSH TABLE t1; +OPTIMIZE TABLE t1; +Table Op Msg_type Msg_text +test.t1 optimize status OK +DROP TABLE t1; diff --git a/mysql-test/t/archive.test b/mysql-test/t/archive.test index 98ba5e03ede..0364c95db0b 100644 --- a/mysql-test/t/archive.test +++ b/mysql-test/t/archive.test @@ -1693,3 +1693,17 @@ INSERT INTO t1 SELECT t1.* FROM t1,t1 t2,t1 t3,t1 t4,t1 t5,t1 t6; SELECT * FROM t1 ORDER BY f LIMIT 1; DROP TABLE t1; SET sort_buffer_size=DEFAULT; + +--echo # +--echo # BUG#11758979 - 51252: ARCHIVE TABLES CAUSE 100% CPU USAGE +--echo # AND HANG IN SHOW TABLE STATUS +--echo # (to be executed with valgrind) +CREATE TABLE t1(a BLOB, b VARCHAR(200)) ENGINE=ARCHIVE; +INSERT INTO t1 VALUES(NULL, ''); +FLUSH TABLE t1; +--echo # we need this select to workaround BUG#11764364 +SELECT * FROM t1; +CHECKSUM TABLE t1 EXTENDED; +FLUSH TABLE t1; +OPTIMIZE TABLE t1; +DROP TABLE t1; diff --git a/storage/archive/ha_archive.cc b/storage/archive/ha_archive.cc index df5bd8bafb1..79053f284b3 100644 --- a/storage/archive/ha_archive.cc +++ b/storage/archive/ha_archive.cc @@ -760,6 +760,7 @@ uint32 ha_archive::max_row_length(const uchar *buf) ptr != end ; ptr++) { + if (!table->field[*ptr]->is_null()) length += 2 + ((Field_blob*)table->field[*ptr])->get_length(); } @@ -1110,6 +1111,17 @@ int ha_archive::unpack_row(azio_stream *file_to_read, uchar *record) /* Copy null bits */ const uchar *ptr= record_buffer->buffer; + /* + Field::unpack() is not called when field is NULL. For VARCHAR + Field::unpack() only unpacks as much bytes as occupied by field + value. In these cases respective memory area on record buffer is + not initialized. + + These uninitialized areas may be accessed by CHECKSUM TABLE or + by optimizer using temporary table (BUG#12997905). We may remove + this memset() when they're fixed. + */ + memset(record, 0, table->s->reclength); memcpy(record, ptr, table->s->null_bytes); ptr+= table->s->null_bytes; for (Field **field=table->field ; *field ; field++) @@ -1578,13 +1590,15 @@ int ha_archive::check(THD* thd, HA_CHECK_OPT* check_opt) { int rc= 0; const char *old_proc_info; - ha_rows count= share->rows_recorded; + ha_rows count; DBUG_ENTER("ha_archive::check"); old_proc_info= thd_proc_info(thd, "Checking table"); - /* Flush any waiting data */ pthread_mutex_lock(&share->mutex); - azflush(&(share->archive_write), Z_SYNC_FLUSH); + count= share->rows_recorded; + /* Flush any waiting data */ + if (share->archive_write_open) + azflush(&(share->archive_write), Z_SYNC_FLUSH); pthread_mutex_unlock(&share->mutex); if (init_archive_reader()) @@ -1594,18 +1608,34 @@ int ha_archive::check(THD* thd, HA_CHECK_OPT* check_opt) start of the file. */ read_data_header(&archive); + for (ha_rows cur_count= count; cur_count; cur_count--) + { + if ((rc= get_row(&archive, table->record[0]))) + goto error; + } + /* + Now read records that may have been inserted concurrently. + Acquire share->mutex so tail of the table is not modified by + concurrent writers. + */ + pthread_mutex_lock(&share->mutex); + count= share->rows_recorded - count; + if (share->archive_write_open) + azflush(&(share->archive_write), Z_SYNC_FLUSH); while (!(rc= get_row(&archive, table->record[0]))) count--; - - thd_proc_info(thd, old_proc_info); + pthread_mutex_unlock(&share->mutex); if ((rc && rc != HA_ERR_END_OF_FILE) || count) - { - share->crashed= FALSE; - DBUG_RETURN(HA_ADMIN_CORRUPT); - } + goto error; + thd_proc_info(thd, old_proc_info); DBUG_RETURN(HA_ADMIN_OK); + +error: + thd_proc_info(thd, old_proc_info); + share->crashed= FALSE; + DBUG_RETURN(HA_ADMIN_CORRUPT); } /* From fd3295e0acb782790eb185352a401473fd4eba99 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 23 Nov 2011 23:13:51 +0200 Subject: [PATCH 107/288] Fix bug lp:893486 Analysis: The bug is a result of an incomplete fix for bug lp:869036. That fix didn't take into account that there may be a case when ther are no NULLs in the materialized subquery, however all columns without NULLs may not be grouped in the only non-null index. This is the case when the left subquery expression has nullable columns. Solution: The patch handles two missing sub-cases of the case when there are no value (non-null matches) for any outer expression, and there are both NULLs and non-NUll values in the outer reference. a) If the materialized subquery contains no NULLs there cannot be a partial match, because there are no NULLs in those columns where the outer reference has no NULLs. b) If the materialized subquery contains NULLs, but there exists a column, such that its corresponding outer expression has no NULL, and this column also has no NULL. Then there cannot be a partial match either. --- mysql-test/r/subselect_partial_match.result | 31 +++++++++++++++++++++ mysql-test/t/subselect_partial_match.test | 22 +++++++++++++++ sql/item_subselect.cc | 26 +++++++++-------- 3 files changed, 67 insertions(+), 12 deletions(-) diff --git a/mysql-test/r/subselect_partial_match.result b/mysql-test/r/subselect_partial_match.result index dddf5e2d8d6..d23f9885f44 100644 --- a/mysql-test/r/subselect_partial_match.result +++ b/mysql-test/r/subselect_partial_match.result @@ -948,4 +948,35 @@ SELECT * from outer_sq where (f1, f2) NOT IN (select * from inner_sq); f1 f2 g c drop table outer_sq, inner_sq; +# +# LP BUG#893486 Wrong result with partial_match_rowid_merge , NOT IN , NULLs +# +CREATE TABLE t1 (a int, b int); +INSERT INTO t1 VALUES (0,NULL),(2,NULL); +CREATE TABLE t2 (c int, d int); +INSERT INTO t2 VALUES (2,3),(4,5),(6, NULL); +set @@optimizer_switch='materialization=on,partial_match_rowid_merge=on,partial_match_table_scan=off,in_to_exists=off'; +EXPLAIN SELECT * FROM t1 WHERE (a, b) NOT IN (SELECT c, d FROM t2); +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 SUBQUERY t2 ALL NULL NULL NULL NULL 3 +SELECT * FROM t1 WHERE (a, b) NOT IN (SELECT c, d FROM t2); +a b +0 NULL +SELECT a, b, (a, b) NOT IN (SELECT c, d FROM t2) subq_res FROM t1; +a b subq_res +0 NULL 1 +2 NULL NULL +EXPLAIN SELECT * FROM t1 WHERE (a, b) NOT IN (SELECT c, d FROM t2 WHERE d is not NULL); +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 SUBQUERY t2 ALL NULL NULL NULL NULL 3 Using where +SELECT * FROM t1 WHERE (a, b) NOT IN (SELECT c, d FROM t2 WHERE d is not NULL); +a b +0 NULL +SELECT a, b, (a, b) NOT IN (SELECT c, d FROM t2 WHERE d is not NULL) subq_res FROM t1; +a b subq_res +0 NULL 1 +2 NULL NULL +drop table t1,t2; set @@optimizer_switch=@save_optimizer_switch; diff --git a/mysql-test/t/subselect_partial_match.test b/mysql-test/t/subselect_partial_match.test index be78360c76b..45386efd266 100644 --- a/mysql-test/t/subselect_partial_match.test +++ b/mysql-test/t/subselect_partial_match.test @@ -775,4 +775,26 @@ SELECT * from outer_sq where (f1, f2) NOT IN (select * from inner_sq); drop table outer_sq, inner_sq; +--echo # +--echo # LP BUG#893486 Wrong result with partial_match_rowid_merge , NOT IN , NULLs +--echo # + +CREATE TABLE t1 (a int, b int); +INSERT INTO t1 VALUES (0,NULL),(2,NULL); + +CREATE TABLE t2 (c int, d int); +INSERT INTO t2 VALUES (2,3),(4,5),(6, NULL); + +set @@optimizer_switch='materialization=on,partial_match_rowid_merge=on,partial_match_table_scan=off,in_to_exists=off'; + +EXPLAIN SELECT * FROM t1 WHERE (a, b) NOT IN (SELECT c, d FROM t2); +SELECT * FROM t1 WHERE (a, b) NOT IN (SELECT c, d FROM t2); +SELECT a, b, (a, b) NOT IN (SELECT c, d FROM t2) subq_res FROM t1; + +EXPLAIN SELECT * FROM t1 WHERE (a, b) NOT IN (SELECT c, d FROM t2 WHERE d is not NULL); +SELECT * FROM t1 WHERE (a, b) NOT IN (SELECT c, d FROM t2 WHERE d is not NULL); +SELECT a, b, (a, b) NOT IN (SELECT c, d FROM t2 WHERE d is not NULL) subq_res FROM t1; + +drop table t1,t2; + set @@optimizer_switch=@save_optimizer_switch; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 18374000dff..16b23045cca 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -5542,6 +5542,8 @@ bool subselect_rowid_merge_engine::test_null_row(rownum_t row_num) /** Test if a subset of NULL-able columns contains a row of NULLs. + @retval TRUE if such a row exists + @retval FALSE no complementing null row */ bool subselect_rowid_merge_engine:: @@ -5549,34 +5551,34 @@ exists_complementing_null_row(MY_BITMAP *keys_to_complement) { rownum_t highest_min_row= 0; rownum_t lowest_max_row= UINT_MAX; - uint count_null_keys, i, j; + uint count_null_keys, i; Ordered_key *cur_key; - count_null_keys= keys_to_complement->n_bits - - bitmap_bits_set(keys_to_complement); - if (count_null_keys == 1) + if (!count_columns_with_nulls) { /* - The caller guarantees that the complement to keys_to_complement - contains only columns with NULLs. Therefore if there is only one column, - it is guaranteed to contain NULLs. + If there are both NULLs and non-NUll values in the outer reference, and + the subquery contains no NULLs, a complementing NULL row cannot exist. */ - return TRUE; + return FALSE; } - for (i= (non_null_key ? 1 : 0), j= 0; i < merge_keys_count; i++) + for (i= (non_null_key ? 1 : 0), count_null_keys= 0; i < merge_keys_count; i++) { cur_key= merge_keys[i]; if (bitmap_is_set(keys_to_complement, cur_key->get_keyid())) continue; - DBUG_ASSERT(cur_key->get_null_count()); + if (!cur_key->get_null_count()) + { + /* If there is column without NULLs, there cannot be a partial match. */ + return FALSE; + } if (cur_key->get_min_null_row() > highest_min_row) highest_min_row= cur_key->get_min_null_row(); if (cur_key->get_max_null_row() < lowest_max_row) lowest_max_row= cur_key->get_max_null_row(); - null_bitmaps[j++]= cur_key->get_null_key(); + null_bitmaps[count_null_keys++]= cur_key->get_null_key(); } - DBUG_ASSERT(count_null_keys == j); if (lowest_max_row < highest_min_row) { From 7b08d996277a5019f1e357f595ba78a3455841cc Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Thu, 24 Nov 2011 16:26:13 +0400 Subject: [PATCH 108/288] fixes to make compilers happy. per-file comments: mysql-test/t/gis-precise.test number-to-string conversion differs on Windows. Have to tolerate this while GIS data is stored in doubles. sql/spatial.cc prev_x initialization added. --- mysql-test/t/gis-precise.test | 3 +++ sql/spatial.cc | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/mysql-test/t/gis-precise.test b/mysql-test/t/gis-precise.test index 1de8726a7bc..b48da25c3c9 100644 --- a/mysql-test/t/gis-precise.test +++ b/mysql-test/t/gis-precise.test @@ -78,6 +78,7 @@ select astext(ST_symdifference(geomfromtext('polygon((0 0, 1 0, 0 1, 0 0))'), ge select astext(ST_UNION(GeomFromText('POLYGON((0 0, 50 45, 40 50, 0 0))'), GeomFromText('LINESTRING(-10 -10, 200 200, 199 201, -11 -9)'))); # Buffer() tests +--replace_result 0012045437948276 00120454379482759 select astext(ST_buffer(geometryfromtext('point(1 1)'), 1)); create table t1(geom geometrycollection); insert into t1 values (geomfromtext('POLYGON((0 0, 10 10, 0 8, 0 0))')); @@ -87,6 +88,7 @@ select astext(ST_buffer(geom,2)) from t1; set @geom=geomfromtext('LINESTRING(2 1, 4 2, 2 3, 2 5)'); set @buff=ST_buffer(@geom,1); +--replace_result 40278744502097 40278744502096 select astext(@buff); # cleanup @@ -133,6 +135,7 @@ SELECT ASTEXT(ST_INTERSECTION( #bug 804324 Assertion 0 in Gcalc_scan_iterator::pop_suitable_intersection +--replace_result 61538461538462 61538461538461 SELECT ASTEXT(ST_UNION( MULTILINESTRINGFROMTEXT('MULTILINESTRING((6 2,4 0,3 5,3 6,4 3,6 4,3 9,0 7,3 7,8 4,2 9,5 0), (8 2,1 3,9 0,4 4))'), diff --git a/sql/spatial.cc b/sql/spatial.cc index b4ce6f59185..89ecec51406 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -766,7 +766,8 @@ int Gis_line_string::store_shapes(Gcalc_shape_transporter *trn) const { uint32 n_points; double x, y; - double prev_x, prev_y; + double prev_x= 0.0; + double prev_y= 0.0; int first_point= 1; const char *data= m_data; From 6fbf8f1926851ecc377b70ad1313b1d213d51010 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 24 Nov 2011 15:12:10 +0200 Subject: [PATCH 109/288] Fix for LP BUG#859375 and LP BUG#887458. Stop attempts to apply IN/ALL/ANY optimizations to so called "fake_select" (used for ordering and filtering results of union) in union subquery execution. --- mysql-test/r/subselect.result | 47 +++++++++++++++++++ mysql-test/r/subselect_no_mat.result | 47 +++++++++++++++++++ mysql-test/r/subselect_no_opts.result | 47 +++++++++++++++++++ mysql-test/r/subselect_no_scache.result | 47 +++++++++++++++++++ mysql-test/r/subselect_no_semijoin.result | 47 +++++++++++++++++++ mysql-test/t/subselect.test | 56 +++++++++++++++++++++++ sql/opt_subselect.cc | 23 ++++++---- 7 files changed, 306 insertions(+), 8 deletions(-) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index d97811921ab..a4e24732181 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -5681,4 +5681,51 @@ select a from t1 where a in (select a from t1 where a in (select a from t1 where a 1 drop table t1; +# +# LP bug #859375: Assertion `0' failed in st_select_lex_unit::optimize +# with view , UNION and prepared statement (rewriting fake_select +# condition). +# +CREATE TABLE t1 ( f1 int NOT NULL, f4 varchar(1) NOT NULL) ; +INSERT INTO t1 VALUES (6,'d'),(7,'y'); +CREATE TABLE t2 ( f1 int NOT NULL, f2 int NOT NULL) ; +INSERT INTO t2 VALUES (10,7); +CREATE VIEW v2 AS SELECT * FROM t2; +PREPARE st1 FROM " + SELECT * + FROM t1 + LEFT JOIN v2 ON ( v2.f2 = t1.f1 ) + WHERE v2.f1 NOT IN ( + SELECT 1 UNION + SELECT 247 + ) +"; +EXECUTE st1; +f1 f4 f1 f2 +7 y 10 7 +deallocate prepare st1; +DROP VIEW v2; +DROP TABLE t1,t2; +# +# LP bug #887458 Crash in subselect_union_engine::no_rows with +# double UNION and join_cache_level=3,8 +# (IN/ALL/ANY optimizations should not be applied to fake_select) +CREATE TABLE t2 ( a int, b varchar(1)) ; +INSERT IGNORE INTO t2 VALUES (8,'y'),(8,'y'); +CREATE TABLE t1 ( b varchar(1)) ; +INSERT IGNORE INTO t1 VALUES (NULL),(NULL); +set @save_join_cache_level=@@join_cache_level; +SET SESSION join_cache_level=3; +SELECT * +FROM t1, t2 +WHERE t2.b IN ( +SELECT 'm' UNION +SELECT 'm' +) OR t1.b <> SOME ( +SELECT 'v' UNION +SELECT 't' +); +b a b +set @@join_cache_level= @save_join_cache_level; +drop table t1,t2; set optimizer_switch=@subselect_tmp; diff --git a/mysql-test/r/subselect_no_mat.result b/mysql-test/r/subselect_no_mat.result index 286f22aa14c..7ea7ae77127 100644 --- a/mysql-test/r/subselect_no_mat.result +++ b/mysql-test/r/subselect_no_mat.result @@ -5680,6 +5680,53 @@ select a from t1 where a in (select a from t1 where a in (select a from t1 where a 1 drop table t1; +# +# LP bug #859375: Assertion `0' failed in st_select_lex_unit::optimize +# with view , UNION and prepared statement (rewriting fake_select +# condition). +# +CREATE TABLE t1 ( f1 int NOT NULL, f4 varchar(1) NOT NULL) ; +INSERT INTO t1 VALUES (6,'d'),(7,'y'); +CREATE TABLE t2 ( f1 int NOT NULL, f2 int NOT NULL) ; +INSERT INTO t2 VALUES (10,7); +CREATE VIEW v2 AS SELECT * FROM t2; +PREPARE st1 FROM " + SELECT * + FROM t1 + LEFT JOIN v2 ON ( v2.f2 = t1.f1 ) + WHERE v2.f1 NOT IN ( + SELECT 1 UNION + SELECT 247 + ) +"; +EXECUTE st1; +f1 f4 f1 f2 +7 y 10 7 +deallocate prepare st1; +DROP VIEW v2; +DROP TABLE t1,t2; +# +# LP bug #887458 Crash in subselect_union_engine::no_rows with +# double UNION and join_cache_level=3,8 +# (IN/ALL/ANY optimizations should not be applied to fake_select) +CREATE TABLE t2 ( a int, b varchar(1)) ; +INSERT IGNORE INTO t2 VALUES (8,'y'),(8,'y'); +CREATE TABLE t1 ( b varchar(1)) ; +INSERT IGNORE INTO t1 VALUES (NULL),(NULL); +set @save_join_cache_level=@@join_cache_level; +SET SESSION join_cache_level=3; +SELECT * +FROM t1, t2 +WHERE t2.b IN ( +SELECT 'm' UNION +SELECT 'm' +) OR t1.b <> SOME ( +SELECT 'v' UNION +SELECT 't' +); +b a b +set @@join_cache_level= @save_join_cache_level; +drop table t1,t2; set optimizer_switch=@subselect_tmp; set optimizer_switch=default; select @@optimizer_switch like '%materialization=on%'; diff --git a/mysql-test/r/subselect_no_opts.result b/mysql-test/r/subselect_no_opts.result index 9a798dec67b..d62ba3f022d 100644 --- a/mysql-test/r/subselect_no_opts.result +++ b/mysql-test/r/subselect_no_opts.result @@ -5676,5 +5676,52 @@ select a from t1 where a in (select a from t1 where a in (select a from t1 where a 1 drop table t1; +# +# LP bug #859375: Assertion `0' failed in st_select_lex_unit::optimize +# with view , UNION and prepared statement (rewriting fake_select +# condition). +# +CREATE TABLE t1 ( f1 int NOT NULL, f4 varchar(1) NOT NULL) ; +INSERT INTO t1 VALUES (6,'d'),(7,'y'); +CREATE TABLE t2 ( f1 int NOT NULL, f2 int NOT NULL) ; +INSERT INTO t2 VALUES (10,7); +CREATE VIEW v2 AS SELECT * FROM t2; +PREPARE st1 FROM " + SELECT * + FROM t1 + LEFT JOIN v2 ON ( v2.f2 = t1.f1 ) + WHERE v2.f1 NOT IN ( + SELECT 1 UNION + SELECT 247 + ) +"; +EXECUTE st1; +f1 f4 f1 f2 +7 y 10 7 +deallocate prepare st1; +DROP VIEW v2; +DROP TABLE t1,t2; +# +# LP bug #887458 Crash in subselect_union_engine::no_rows with +# double UNION and join_cache_level=3,8 +# (IN/ALL/ANY optimizations should not be applied to fake_select) +CREATE TABLE t2 ( a int, b varchar(1)) ; +INSERT IGNORE INTO t2 VALUES (8,'y'),(8,'y'); +CREATE TABLE t1 ( b varchar(1)) ; +INSERT IGNORE INTO t1 VALUES (NULL),(NULL); +set @save_join_cache_level=@@join_cache_level; +SET SESSION join_cache_level=3; +SELECT * +FROM t1, t2 +WHERE t2.b IN ( +SELECT 'm' UNION +SELECT 'm' +) OR t1.b <> SOME ( +SELECT 'v' UNION +SELECT 't' +); +b a b +set @@join_cache_level= @save_join_cache_level; +drop table t1,t2; 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 bac8a017ece..2dd9ca12511 100644 --- a/mysql-test/r/subselect_no_scache.result +++ b/mysql-test/r/subselect_no_scache.result @@ -5685,6 +5685,53 @@ select a from t1 where a in (select a from t1 where a in (select a from t1 where a 1 drop table t1; +# +# LP bug #859375: Assertion `0' failed in st_select_lex_unit::optimize +# with view , UNION and prepared statement (rewriting fake_select +# condition). +# +CREATE TABLE t1 ( f1 int NOT NULL, f4 varchar(1) NOT NULL) ; +INSERT INTO t1 VALUES (6,'d'),(7,'y'); +CREATE TABLE t2 ( f1 int NOT NULL, f2 int NOT NULL) ; +INSERT INTO t2 VALUES (10,7); +CREATE VIEW v2 AS SELECT * FROM t2; +PREPARE st1 FROM " + SELECT * + FROM t1 + LEFT JOIN v2 ON ( v2.f2 = t1.f1 ) + WHERE v2.f1 NOT IN ( + SELECT 1 UNION + SELECT 247 + ) +"; +EXECUTE st1; +f1 f4 f1 f2 +7 y 10 7 +deallocate prepare st1; +DROP VIEW v2; +DROP TABLE t1,t2; +# +# LP bug #887458 Crash in subselect_union_engine::no_rows with +# double UNION and join_cache_level=3,8 +# (IN/ALL/ANY optimizations should not be applied to fake_select) +CREATE TABLE t2 ( a int, b varchar(1)) ; +INSERT IGNORE INTO t2 VALUES (8,'y'),(8,'y'); +CREATE TABLE t1 ( b varchar(1)) ; +INSERT IGNORE INTO t1 VALUES (NULL),(NULL); +set @save_join_cache_level=@@join_cache_level; +SET SESSION join_cache_level=3; +SELECT * +FROM t1, t2 +WHERE t2.b IN ( +SELECT 'm' UNION +SELECT 'm' +) OR t1.b <> SOME ( +SELECT 'v' UNION +SELECT 't' +); +b a b +set @@join_cache_level= @save_join_cache_level; +drop table t1,t2; set optimizer_switch=@subselect_tmp; set optimizer_switch=default; select @@optimizer_switch like '%subquery_cache=on%'; diff --git a/mysql-test/r/subselect_no_semijoin.result b/mysql-test/r/subselect_no_semijoin.result index 8b9c4d355bd..7f9cb7f7c3d 100644 --- a/mysql-test/r/subselect_no_semijoin.result +++ b/mysql-test/r/subselect_no_semijoin.result @@ -5676,5 +5676,52 @@ select a from t1 where a in (select a from t1 where a in (select a from t1 where a 1 drop table t1; +# +# LP bug #859375: Assertion `0' failed in st_select_lex_unit::optimize +# with view , UNION and prepared statement (rewriting fake_select +# condition). +# +CREATE TABLE t1 ( f1 int NOT NULL, f4 varchar(1) NOT NULL) ; +INSERT INTO t1 VALUES (6,'d'),(7,'y'); +CREATE TABLE t2 ( f1 int NOT NULL, f2 int NOT NULL) ; +INSERT INTO t2 VALUES (10,7); +CREATE VIEW v2 AS SELECT * FROM t2; +PREPARE st1 FROM " + SELECT * + FROM t1 + LEFT JOIN v2 ON ( v2.f2 = t1.f1 ) + WHERE v2.f1 NOT IN ( + SELECT 1 UNION + SELECT 247 + ) +"; +EXECUTE st1; +f1 f4 f1 f2 +7 y 10 7 +deallocate prepare st1; +DROP VIEW v2; +DROP TABLE t1,t2; +# +# LP bug #887458 Crash in subselect_union_engine::no_rows with +# double UNION and join_cache_level=3,8 +# (IN/ALL/ANY optimizations should not be applied to fake_select) +CREATE TABLE t2 ( a int, b varchar(1)) ; +INSERT IGNORE INTO t2 VALUES (8,'y'),(8,'y'); +CREATE TABLE t1 ( b varchar(1)) ; +INSERT IGNORE INTO t1 VALUES (NULL),(NULL); +set @save_join_cache_level=@@join_cache_level; +SET SESSION join_cache_level=3; +SELECT * +FROM t1, t2 +WHERE t2.b IN ( +SELECT 'm' UNION +SELECT 'm' +) OR t1.b <> SOME ( +SELECT 'v' UNION +SELECT 't' +); +b a b +set @@join_cache_level= @save_join_cache_level; +drop table t1,t2; 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 e8a778232bc..a39b7ea49b8 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -4778,4 +4778,60 @@ set @@optimizer_switch='in_to_exists=on,semijoin=off,materialization=off,subquer select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1))))))))))))))))))))))))))))); drop table t1; +--echo # +--echo # LP bug #859375: Assertion `0' failed in st_select_lex_unit::optimize +--echo # with view , UNION and prepared statement (rewriting fake_select +--echo # condition). +--echo # + +CREATE TABLE t1 ( f1 int NOT NULL, f4 varchar(1) NOT NULL) ; +INSERT INTO t1 VALUES (6,'d'),(7,'y'); + +CREATE TABLE t2 ( f1 int NOT NULL, f2 int NOT NULL) ; +INSERT INTO t2 VALUES (10,7); + +CREATE VIEW v2 AS SELECT * FROM t2; + +PREPARE st1 FROM " + SELECT * + FROM t1 + LEFT JOIN v2 ON ( v2.f2 = t1.f1 ) + WHERE v2.f1 NOT IN ( + SELECT 1 UNION + SELECT 247 + ) +"; + +EXECUTE st1; +deallocate prepare st1; + +DROP VIEW v2; +DROP TABLE t1,t2; + +--echo # +--echo # LP bug #887458 Crash in subselect_union_engine::no_rows with +--echo # double UNION and join_cache_level=3,8 +--echo # (IN/ALL/ANY optimizations should not be applied to fake_select) + +CREATE TABLE t2 ( a int, b varchar(1)) ; +INSERT IGNORE INTO t2 VALUES (8,'y'),(8,'y'); + +CREATE TABLE t1 ( b varchar(1)) ; +INSERT IGNORE INTO t1 VALUES (NULL),(NULL); + +set @save_join_cache_level=@@join_cache_level; +SET SESSION join_cache_level=3; + +SELECT * +FROM t1, t2 +WHERE t2.b IN ( + SELECT 'm' UNION + SELECT 'm' +) OR t1.b <> SOME ( + SELECT 'v' UNION + SELECT 't' +); + +set @@join_cache_level= @save_join_cache_level; +drop table t1,t2; set optimizer_switch=@subselect_tmp; diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index 167d87ed850..19ea846e7b5 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -304,6 +304,14 @@ int check_and_do_in_subquery_rewrites(JOIN *join) st_select_lex *select_lex= join->select_lex; st_select_lex_unit* parent_unit= select_lex->master_unit(); DBUG_ENTER("check_and_do_in_subquery_rewrites"); + + /* + IN/ALL/ANY rewrites are not applicable for so called fake select + (this select exists only to filter results of union if it is needed). + */ + if (select_lex == select_lex->master_unit()->fake_select_lex) + DBUG_RETURN(0); + /* If 1) this join is inside a subquery (of any type except FROM-clause @@ -376,14 +384,6 @@ int check_and_do_in_subquery_rewrites(JOIN *join) if (failure) DBUG_RETURN(-1); /* purecov: deadcode */ } - if (select_lex == parent_unit->fake_select_lex) - { - /* - The join and its select_lex object represent the 'fake' select used - to compute the result of a UNION. - */ - DBUG_RETURN(0); - } DBUG_PRINT("info", ("Checking if subq can be converted to semi-join")); /* @@ -4503,6 +4503,13 @@ bool JOIN::choose_subquery_plan(table_map join_tables) enum_reopt_result reopt_result= REOPT_NONE; Item_in_subselect *in_subs; + /* + IN/ALL/ANY optimizations are not applicable for so called fake select + (this select exists only to filter results of union if it is needed). + */ + if (select_lex == select_lex->master_unit()->fake_select_lex) + return 0; + if (is_in_subquery()) { in_subs= (Item_in_subselect*) unit->item; From d26aefb0775048128495eaab151ee4118f8f7afd Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Thu, 24 Nov 2011 16:04:19 +0200 Subject: [PATCH 110/288] Fixes for build failuers found by buildbot mysql-test/mysql-test-run.pl: Rename MYSQLD -> MYSQLD_SIMPLE_CMD to avoid conflict with new MYSQLD variable from MySQL 5.1 mysql-test/r/innodb_file_format.result: Remove old duplicated test mysql-test/suite/pbxt/r/endspace.result: Update test to last version mysql-test/suite/pbxt/r/heap.result: Removed heap test (not part of pbxt) mysql-test/suite/pbxt/r/select_safe.result: Updated results after error message change mysql-test/suite/pbxt/r/view_grant.result: Removed view test (not part of pbxt) mysql-test/suite/pbxt/t/endspace.test: Update test to last version mysql-test/suite/pbxt/t/heap.test: Removed heap test (not part of pbxt) mysql-test/suite/pbxt/t/view_grant.test: Removed view test (not part of pbxt) mysql-test/t/innodb_file_format.test: Remove old duplicated test mysql-test/t/mysqld_option_err.test: Use renamed variable sql/my_decimal.h: Fixed wrong define storage/maria/ma_loghandler.c: Fixed compiler warning --- mysql-test/mysql-test-run.pl | 2 +- mysql-test/r/innodb_file_format.result | 44 - mysql-test/suite/pbxt/r/endspace.result | 15 +- mysql-test/suite/pbxt/r/heap.result | 733 ------------ mysql-test/suite/pbxt/r/select_safe.result | 12 +- mysql-test/suite/pbxt/r/view_grant.result | 958 --------------- mysql-test/suite/pbxt/t/endspace.test | 12 +- mysql-test/suite/pbxt/t/heap.test | 476 -------- mysql-test/suite/pbxt/t/view_grant.test | 1224 -------------------- mysql-test/t/innodb_file_format.test | 31 - mysql-test/t/mysqld_option_err.test | 14 +- sql/my_decimal.h | 2 +- storage/maria/ma_loghandler.c | 2 + 13 files changed, 34 insertions(+), 3491 deletions(-) delete mode 100644 mysql-test/r/innodb_file_format.result delete mode 100644 mysql-test/suite/pbxt/r/heap.result delete mode 100644 mysql-test/suite/pbxt/r/view_grant.result delete mode 100644 mysql-test/suite/pbxt/t/heap.test delete mode 100644 mysql-test/suite/pbxt/t/view_grant.test delete mode 100644 mysql-test/t/innodb_file_format.test diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index c4bc98b9a9b..1c9d3b5159f 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -2297,7 +2297,7 @@ sub environment_setup { $ENV{'MYSQLADMIN'}= native_path($exe_mysqladmin); $ENV{'MYSQL_CLIENT_TEST'}= mysql_client_test_arguments(); $ENV{'MYSQL_FIX_SYSTEM_TABLES'}= mysql_fix_arguments(); - $ENV{'MYSQLD'}= mysqld_client_arguments(); + $ENV{'MYSQLD_SIMPLE_CMD'}= mysqld_client_arguments(); $ENV{'EXE_MYSQL'}= $exe_mysql; my $exe_mysqld= find_mysqld($basedir); diff --git a/mysql-test/r/innodb_file_format.result b/mysql-test/r/innodb_file_format.result deleted file mode 100644 index d58c4ce8b28..00000000000 --- a/mysql-test/r/innodb_file_format.result +++ /dev/null @@ -1,44 +0,0 @@ -call mtr.add_suppression("InnoDB: invalid innodb_file_format_check value"); -select @@innodb_file_format; -@@innodb_file_format -Antelope -select @@innodb_file_format_check; -@@innodb_file_format_check -Antelope -set global innodb_file_format=antelope; -set global innodb_file_format=barracuda; -set global innodb_file_format=cheetah; -ERROR HY000: Incorrect arguments to SET -select @@innodb_file_format; -@@innodb_file_format -Barracuda -set global innodb_file_format=default; -select @@innodb_file_format; -@@innodb_file_format -Antelope -set global innodb_file_format=on; -ERROR HY000: Incorrect arguments to SET -set global innodb_file_format=off; -ERROR HY000: Incorrect arguments to SET -select @@innodb_file_format; -@@innodb_file_format -Antelope -set global innodb_file_format_check=antelope; -set global innodb_file_format_check=barracuda; -set global innodb_file_format_check=cheetah; -ERROR HY000: Incorrect arguments to SET -select @@innodb_file_format_check; -@@innodb_file_format_check -Barracuda -set global innodb_file_format_check=default; -select @@innodb_file_format_check; -@@innodb_file_format_check -Barracuda -set global innodb_file_format=on; -ERROR HY000: Incorrect arguments to SET -set global innodb_file_format=off; -ERROR HY000: Incorrect arguments to SET -select @@innodb_file_format_check; -@@innodb_file_format_check -Barracuda -set global innodb_file_format_check=antelope; diff --git a/mysql-test/suite/pbxt/r/endspace.result b/mysql-test/suite/pbxt/r/endspace.result index c9a2db8bbfe..641ed14023d 100644 --- a/mysql-test/suite/pbxt/r/endspace.result +++ b/mysql-test/suite/pbxt/r/endspace.result @@ -25,10 +25,11 @@ insert into t1 values ('teststring'), ('nothing'), ('teststring\t'); check table t1; Table Op Msg_type Msg_text test.t1 check status OK -select * from t1 ignore key (key1) where text1='teststring' or text1 like 'teststring_%'; +select * from t1 ignore key (key1) where text1='teststring' or +text1 like 'teststring_%' ORDER BY text1; text1 -teststring teststring +teststring select * from t1 where text1='teststring' or text1 like 'teststring_%'; text1 teststring @@ -48,10 +49,11 @@ alter table t1 modify text1 char(32) binary not null; check table t1; Table Op Msg_type Msg_text test.t1 check status OK -select * from t1 ignore key (key1) where text1='teststring' or text1 like 'teststring_%'; +select * from t1 ignore key (key1) where text1='teststring' or +text1 like 'teststring_%' ORDER BY text1; text1 -teststring teststring +teststring select concat('|', text1, '|') from t1 where text1='teststring' or text1 like 'teststring_%'; concat('|', text1, '|') |teststring | @@ -132,10 +134,11 @@ concat('|', text1, '|') drop table t1; create table t1 (text1 varchar(32) not NULL, KEY key1 using BTREE (text1)) engine=heap; insert into t1 values ('teststring'), ('nothing'), ('teststring\t'); -select * from t1 ignore key (key1) where text1='teststring' or text1 like 'teststring_%'; +select * from t1 ignore key (key1) where text1='teststring' or +text1 like 'teststring_%' ORDER BY text1; text1 -teststring teststring +teststring select * from t1 where text1='teststring' or text1 like 'teststring_%'; text1 teststring diff --git a/mysql-test/suite/pbxt/r/heap.result b/mysql-test/suite/pbxt/r/heap.result deleted file mode 100644 index 57109f0d4c8..00000000000 --- a/mysql-test/suite/pbxt/r/heap.result +++ /dev/null @@ -1,733 +0,0 @@ -drop table if exists t1,t2,t3; -create table t1 (a int not null,b int not null, primary key (a)) engine=heap comment="testing heaps" avg_row_length=100 min_rows=1 max_rows=100; -insert into t1 values(1,1),(2,2),(3,3),(4,4); -delete from t1 where a=1 or a=0; -show keys from t1; -Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment -t1 0 PRIMARY 1 a NULL 3 NULL NULL HASH -select * from t1; -a b -2 2 -3 3 -4 4 -select * from t1 where a=4; -a b -4 4 -update t1 set b=5 where a=4; -update t1 set b=b+1 where a>=3; -replace t1 values (3,3); -select * from t1; -a b -2 2 -3 3 -4 6 -alter table t1 add c int not null, add key (c,a); -drop table t1; -create table t1 (a int not null,b int not null, primary key (a)) engine=memory comment="testing heaps"; -insert into t1 values(1,1),(2,2),(3,3),(4,4); -delete from t1 where a > 0; -select * from t1; -a b -drop table t1; -create table t1 (a int not null,b int not null, primary key (a)) engine=heap comment="testing heaps"; -insert into t1 values(1,1),(2,2),(3,3),(4,4); -alter table t1 modify a int not null auto_increment, engine=myisam, comment="new myisam table"; -select * from t1; -a b -1 1 -2 2 -3 3 -4 4 -drop table t1; -create table t1 (a int not null) engine=heap; -insert into t1 values (869751),(736494),(226312),(802616),(728912); -select * from t1 where a > 736494; -a -869751 -802616 -alter table t1 add unique uniq_id(a); -select * from t1 where a > 736494; -a -869751 -802616 -select * from t1 where a = 736494; -a -736494 -select * from t1 where a=869751 or a=736494; -a -736494 -869751 -select * from t1 where a in (869751,736494,226312,802616); -a -226312 -736494 -802616 -869751 -alter table t1 engine=myisam; -explain select * from t1 where a in (869751,736494,226312,802616); -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range uniq_id uniq_id 4 NULL 4 Using where; Using index -drop table t1; -create table t1 (x int not null, y int not null, key x (x), unique y (y)) -engine=heap; -insert into t1 values (1,1),(2,2),(1,3),(2,4),(2,5),(2,6); -select * from t1 where x=1; -x y -1 3 -1 1 -select * from t1,t1 as t2 where t1.x=t2.y; -x y x y -1 1 1 1 -2 2 2 2 -1 3 1 1 -2 4 2 2 -2 5 2 2 -2 6 2 2 -explain select * from t1,t1 as t2 where t1.x=t2.y; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL x NULL NULL NULL 6 -1 SIMPLE t2 eq_ref y y 4 test.t1.x 1 -drop table t1; -create table t1 (a int) engine=heap; -insert into t1 values(1); -select max(a) from t1; -max(a) -1 -drop table t1; -CREATE TABLE t1 ( a int not null default 0, b int not null default 0, key(a), key(b) ) ENGINE=HEAP; -insert into t1 values(1,1),(1,2),(2,3),(1,3),(1,4),(1,5),(1,6); -select * from t1 where a=1; -a b -1 6 -1 5 -1 4 -1 3 -1 2 -1 1 -insert into t1 values(1,1),(1,2),(2,3),(1,3),(1,4),(1,5),(1,6); -select * from t1 where a=1; -a b -1 6 -1 5 -1 4 -1 3 -1 2 -1 1 -1 6 -1 5 -1 4 -1 3 -1 2 -1 1 -drop table t1; -create table t1 (id int unsigned not null, primary key (id)) engine=HEAP; -insert into t1 values(1); -select max(id) from t1; -max(id) -1 -insert into t1 values(2); -select max(id) from t1; -max(id) -2 -replace into t1 values(1); -drop table t1; -create table t1 (n int) engine=heap; -drop table t1; -create table t1 (n int) engine=heap; -drop table if exists t1; -CREATE table t1(f1 int not null,f2 char(20) not -null,index(f2)) engine=heap; -INSERT into t1 set f1=12,f2="bill"; -INSERT into t1 set f1=13,f2="bill"; -INSERT into t1 set f1=14,f2="bill"; -INSERT into t1 set f1=15,f2="bill"; -INSERT into t1 set f1=16,f2="ted"; -INSERT into t1 set f1=12,f2="ted"; -INSERT into t1 set f1=12,f2="ted"; -INSERT into t1 set f1=12,f2="ted"; -INSERT into t1 set f1=12,f2="ted"; -delete from t1 where f2="bill"; -select * from t1; -f1 f2 -16 ted -12 ted -12 ted -12 ted -12 ted -drop table t1; -create table t1 (btn char(10) not null, key(btn)) engine=heap; -insert into t1 values ("hello"),("hello"),("hello"),("hello"),("hello"),("a"),("b"),("c"),("d"),("e"),("f"),("g"),("h"),("i"); -explain select * from t1 where btn like "q%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL btn NULL NULL NULL 14 Using where -select * from t1 where btn like "q%"; -btn -alter table t1 add column new_col char(1) not null, add key (btn,new_col), drop key btn; -update t1 set new_col=left(btn,1); -explain select * from t1 where btn="a"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL btn NULL NULL NULL 14 Using where -explain select * from t1 where btn="a" and new_col="a"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref btn btn 11 const,const 2 Using where -drop table t1; -CREATE TABLE t1 ( -a int default NULL, -b int default NULL, -KEY a (a), -UNIQUE b (b) -) engine=heap; -INSERT INTO t1 VALUES (NULL,99),(99,NULL),(1,1),(2,2),(1,3); -SELECT * FROM t1 WHERE a=NULL; -a b -explain SELECT * FROM t1 WHERE a IS NULL; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref a a 5 const 2 Using where -SELECT * FROM t1 WHERE a<=>NULL; -a b -NULL 99 -SELECT * FROM t1 WHERE b=NULL; -a b -explain SELECT * FROM t1 WHERE b IS NULL; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref b b 5 const 1 Using where -SELECT * FROM t1 WHERE b<=>NULL; -a b -99 NULL -INSERT INTO t1 VALUES (1,3); -ERROR 23000: Duplicate entry '3' for key 'b' -DROP TABLE t1; -CREATE TABLE t1 ( -a int default NULL, -key a (a) -) ENGINE=HEAP; -INSERT INTO t1 VALUES (10), (10), (10); -EXPLAIN SELECT * FROM t1 WHERE a=10; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref a a 5 const 3 Using where -SELECT * FROM t1 WHERE a=10; -a -10 -10 -10 -DROP TABLE t1; -CREATE TABLE t1 (a int not null, primary key(a)) engine=heap; -INSERT into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11); -DELETE from t1 where a < 100; -SELECT * from t1; -a -DROP TABLE t1; -CREATE TABLE `job_titles` ( -`job_title_id` int(6) unsigned NOT NULL default '0', -`job_title` char(18) NOT NULL default '', -PRIMARY KEY (`job_title_id`), -UNIQUE KEY `job_title_id` (`job_title_id`,`job_title`) -) ENGINE=HEAP; -SELECT MAX(job_title_id) FROM job_titles; -MAX(job_title_id) -NULL -DROP TABLE job_titles; -CREATE TABLE t1 (a INT NOT NULL, B INT, KEY(B)) ENGINE=HEAP; -INSERT INTO t1 VALUES(1,1), (1,NULL); -SELECT * FROM t1 WHERE B is not null; -a B -1 1 -DROP TABLE t1; -CREATE TABLE t1 (pseudo char(35) PRIMARY KEY, date int(10) unsigned NOT NULL) ENGINE=HEAP; -INSERT INTO t1 VALUES ('massecot',1101106491),('altec',1101106492),('stitch+',1101106304),('Seb Corgan',1101106305),('beerfilou',1101106263),('flaker',1101106529),('joce8',5),('M4vrick',1101106418),('gabay008',1101106525),('Vamp irX',1101106291),('ZoomZip',1101106546),('rip666',1101106502),('CBP ',1101106397),('guezpard',1101106496); -DELETE FROM t1 WHERE date<1101106546; -SELECT * FROM t1; -pseudo date -ZoomZip 1101106546 -DROP TABLE t1; -create table t1(a char(2)) engine=memory; -insert into t1 values (NULL), (NULL); -delete from t1 where a is null; -insert into t1 values ('2'), ('3'); -select * from t1; -a -3 -2 -drop table t1; -set storage_engine=HEAP; -create table t1 (v varchar(10), c char(10), t varchar(50)); -insert into t1 values('+ ', '+ ', '+ '); -set @a=repeat(' ',20); -insert into t1 values (concat('+',@a),concat('+',@a),concat('+',@a)); -Warnings: -Note 1265 Data truncated for column 'v' at row 1 -select concat('*',v,'*',c,'*',t,'*') from t1; -concat('*',v,'*',c,'*',t,'*') -*+ *+*+ * -*+ *+*+ * -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `v` varchar(10) DEFAULT NULL, - `c` char(10) DEFAULT NULL, - `t` varchar(50) DEFAULT NULL -) ENGINE=MEMORY DEFAULT CHARSET=latin1 -create table t2 like t1; -show create table t2; -Table Create Table -t2 CREATE TABLE `t2` ( - `v` varchar(10) DEFAULT NULL, - `c` char(10) DEFAULT NULL, - `t` varchar(50) DEFAULT NULL -) ENGINE=MEMORY DEFAULT CHARSET=latin1 -create table t3 select * from t1; -show create table t3; -Table Create Table -t3 CREATE TABLE `t3` ( - `v` varchar(10) DEFAULT NULL, - `c` char(10) DEFAULT NULL, - `t` varchar(50) DEFAULT NULL -) ENGINE=MEMORY DEFAULT CHARSET=latin1 -alter table t1 modify c varchar(10); -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `v` varchar(10) DEFAULT NULL, - `c` varchar(10) DEFAULT NULL, - `t` varchar(50) DEFAULT NULL -) ENGINE=MEMORY DEFAULT CHARSET=latin1 -alter table t1 modify v char(10); -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `v` char(10) DEFAULT NULL, - `c` varchar(10) DEFAULT NULL, - `t` varchar(50) DEFAULT NULL -) ENGINE=MEMORY DEFAULT CHARSET=latin1 -alter table t1 modify t varchar(10); -Warnings: -Warning 1265 Data truncated for column 't' at row 2 -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `v` char(10) DEFAULT NULL, - `c` varchar(10) DEFAULT NULL, - `t` varchar(10) DEFAULT NULL -) ENGINE=MEMORY DEFAULT CHARSET=latin1 -select concat('*',v,'*',c,'*',t,'*') from t1; -concat('*',v,'*',c,'*',t,'*') -*+*+*+ * -*+*+*+ * -drop table t1,t2,t3; -create table t1 (v varchar(10), c char(10), t varchar(50), key(v), key(c), key(t(10))); -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `v` varchar(10) DEFAULT NULL, - `c` char(10) DEFAULT NULL, - `t` varchar(50) DEFAULT NULL, - KEY `v` (`v`), - KEY `c` (`c`), - KEY `t` (`t`(10)) -) ENGINE=MEMORY DEFAULT CHARSET=latin1 -select count(*) from t1; -count(*) -270 -insert into t1 values(concat('a',char(1)),concat('a',char(1)),concat('a',char(1))); -select count(*) from t1 where v='a'; -count(*) -10 -select count(*) from t1 where c='a'; -count(*) -10 -select count(*) from t1 where t='a'; -count(*) -10 -select count(*) from t1 where v='a '; -count(*) -10 -select count(*) from t1 where c='a '; -count(*) -10 -select count(*) from t1 where t='a '; -count(*) -10 -select count(*) from t1 where v between 'a' and 'a '; -count(*) -10 -select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n'; -count(*) -10 -select count(*) from t1 where v like 'a%'; -count(*) -11 -select count(*) from t1 where c like 'a%'; -count(*) -11 -select count(*) from t1 where t like 'a%'; -count(*) -11 -select count(*) from t1 where v like 'a %'; -count(*) -9 -explain select count(*) from t1 where v='a '; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref v v 13 const 10 Using where -explain select count(*) from t1 where c='a '; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref c c 11 const 10 Using where -explain select count(*) from t1 where t='a '; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref t t 13 const 10 Using where -explain select count(*) from t1 where v like 'a%'; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL v NULL NULL NULL 271 Using where -explain select count(*) from t1 where v between 'a' and 'a '; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref v v 13 const 10 Using where -explain select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n'; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref v v 13 const 10 Using where -alter table t1 add unique(v); -ERROR 23000: Duplicate entry '{ ' for key 'v_2' -select concat('*',v,'*',c,'*',t,'*') as qq from t1 where v='a' order by length(concat('*',v,'*',c,'*',t,'*')); -qq -*a*a*a* -*a *a*a * -*a *a*a * -*a *a*a * -*a *a*a * -*a *a*a * -*a *a*a * -*a *a*a * -*a *a*a * -*a *a*a * -explain select * from t1 where v='a'; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref v v 13 const 10 Using where -select v,count(*) from t1 group by v limit 10; -v count(*) -a 1 -a 10 -b 10 -c 10 -d 10 -e 10 -f 10 -g 10 -h 10 -i 10 -select v,count(t) from t1 group by v limit 10; -v count(t) -a 1 -a 10 -b 10 -c 10 -d 10 -e 10 -f 10 -g 10 -h 10 -i 10 -select v,count(c) from t1 group by v limit 10; -v count(c) -a 1 -a 10 -b 10 -c 10 -d 10 -e 10 -f 10 -g 10 -h 10 -i 10 -select sql_big_result trim(v),count(t) from t1 group by v limit 10; -trim(v) count(t) -a 1 -a 10 -b 10 -c 10 -d 10 -e 10 -f 10 -g 10 -h 10 -i 10 -select sql_big_result trim(v),count(c) from t1 group by v limit 10; -trim(v) count(c) -a 1 -a 10 -b 10 -c 10 -d 10 -e 10 -f 10 -g 10 -h 10 -i 10 -select c,count(*) from t1 group by c limit 10; -c count(*) -a 1 -a 10 -b 10 -c 10 -d 10 -e 10 -f 10 -g 10 -h 10 -i 10 -select c,count(t) from t1 group by c limit 10; -c count(t) -a 1 -a 10 -b 10 -c 10 -d 10 -e 10 -f 10 -g 10 -h 10 -i 10 -select sql_big_result c,count(t) from t1 group by c limit 10; -c count(t) -a 1 -a 10 -b 10 -c 10 -d 10 -e 10 -f 10 -g 10 -h 10 -i 10 -select t,count(*) from t1 group by t limit 10; -t count(*) -a 1 -a 10 -b 10 -c 10 -d 10 -e 10 -f 10 -g 10 -h 10 -i 10 -select t,count(t) from t1 group by t limit 10; -t count(t) -a 1 -a 10 -b 10 -c 10 -d 10 -e 10 -f 10 -g 10 -h 10 -i 10 -select sql_big_result trim(t),count(t) from t1 group by t limit 10; -trim(t) count(t) -a 1 -a 10 -b 10 -c 10 -d 10 -e 10 -f 10 -g 10 -h 10 -i 10 -drop table t1; -create table t1 (a char(10), unique (a)); -insert into t1 values ('a'); -insert into t1 values ('a '); -ERROR 23000: Duplicate entry 'a' for key 'a' -alter table t1 modify a varchar(10); -insert into t1 values ('a '),('a '),('a '),('a '); -ERROR 23000: Duplicate entry 'a ' for key 'a' -insert into t1 values ('a '); -ERROR 23000: Duplicate entry 'a ' for key 'a' -insert into t1 values ('a '); -ERROR 23000: Duplicate entry 'a ' for key 'a' -insert into t1 values ('a '); -ERROR 23000: Duplicate entry 'a ' for key 'a' -update t1 set a='a ' where a like 'a '; -update t1 set a='a ' where a like 'a '; -drop table t1; -create table t1 (v varchar(10), c char(10), t varchar(50), key using btree (v), key using btree (c), key using btree (t(10))); -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `v` varchar(10) DEFAULT NULL, - `c` char(10) DEFAULT NULL, - `t` varchar(50) DEFAULT NULL, - KEY `v` (`v`) USING BTREE, - KEY `c` (`c`) USING BTREE, - KEY `t` (`t`(10)) USING BTREE -) ENGINE=MEMORY DEFAULT CHARSET=latin1 -select count(*) from t1; -count(*) -270 -insert into t1 values(concat('a',char(1)),concat('a',char(1)),concat('a',char(1))); -select count(*) from t1 where v='a'; -count(*) -10 -select count(*) from t1 where c='a'; -count(*) -10 -select count(*) from t1 where t='a'; -count(*) -10 -select count(*) from t1 where v='a '; -count(*) -10 -select count(*) from t1 where c='a '; -count(*) -10 -select count(*) from t1 where t='a '; -count(*) -10 -select count(*) from t1 where v between 'a' and 'a '; -count(*) -10 -select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n'; -count(*) -10 -explain select count(*) from t1 where v='a '; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref v v 13 const # Using where -explain select count(*) from t1 where c='a '; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref c c 11 const # Using where -explain select count(*) from t1 where t='a '; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref t t 13 const # Using where -explain select count(*) from t1 where v like 'a%'; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 13 NULL # Using where -explain select count(*) from t1 where v between 'a' and 'a '; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref v v 13 const # Using where -explain select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n'; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref v v 13 const # Using where -alter table t1 add unique(v); -ERROR 23000: Duplicate entry '{ ' for key 'v_2' -select concat('*',v,'*',c,'*',t,'*') as qq from t1 where v='a' order by length(concat('*',v,'*',c,'*',t,'*')); -qq -*a*a*a* -*a *a*a * -*a *a*a * -*a *a*a * -*a *a*a * -*a *a*a * -*a *a*a * -*a *a*a * -*a *a*a * -*a *a*a * -explain select * from t1 where v='a'; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref v v 13 const # Using where -drop table t1; -create table t1 (a char(10), unique using btree (a)) engine=heap; -insert into t1 values ('a'); -insert into t1 values ('a '); -ERROR 23000: Duplicate entry 'a' for key 'a' -alter table t1 modify a varchar(10); -insert into t1 values ('a '),('a '),('a '),('a '); -ERROR 23000: Duplicate entry 'a ' for key 'a' -insert into t1 values ('a '); -ERROR 23000: Duplicate entry 'a ' for key 'a' -insert into t1 values ('a '); -ERROR 23000: Duplicate entry 'a ' for key 'a' -insert into t1 values ('a '); -ERROR 23000: Duplicate entry 'a ' for key 'a' -update t1 set a='a ' where a like 'a '; -update t1 set a='a ' where a like 'a '; -drop table t1; -create table t1 (v varchar(10), c char(10), t varchar(50), key(v(5)), key(c(5)), key(t(5))); -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `v` varchar(10) DEFAULT NULL, - `c` char(10) DEFAULT NULL, - `t` varchar(50) DEFAULT NULL, - KEY `v` (`v`(5)), - KEY `c` (`c`(5)), - KEY `t` (`t`(5)) -) ENGINE=MEMORY DEFAULT CHARSET=latin1 -drop table t1; -create table t1 (v varchar(65530), key(v(10))); -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `v` varchar(65530) DEFAULT NULL, - KEY `v` (`v`(10)) -) ENGINE=MEMORY DEFAULT CHARSET=latin1 -insert into t1 values(repeat('a',65530)); -select length(v) from t1 where v=repeat('a',65530); -length(v) -65530 -drop table t1; -set storage_engine=PBXT; -create table t1 (a bigint unsigned auto_increment primary key, b int, -key (b, a)) engine=heap; -insert t1 (b) values (1),(1),(1),(1),(1),(1),(1),(1); -select * from t1; -a b -1 1 -2 1 -3 1 -4 1 -5 1 -6 1 -7 1 -8 1 -drop table t1; -create table t1 (a int not null, b int not null auto_increment, -primary key(a, b), key(b)) engine=heap; -insert t1 (a) values (1),(1),(1),(1),(1),(1),(1),(1); -select * from t1; -a b -1 1 -1 2 -1 3 -1 4 -1 5 -1 6 -1 7 -1 8 -drop table t1; -create table t1 (a int not null, b int not null auto_increment, -primary key(a, b)) engine=heap; -ERROR 42000: Incorrect table definition; there can be only one auto column and it must be defined as a key -create table t1 (c char(255), primary key(c(90))); -insert into t1 values ("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); -insert into t1 values ("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); -ERROR 23000: Duplicate entry 'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkl' for key 'PRIMARY' -drop table t1; -CREATE TABLE t1 (a int, key(a)) engine=heap; -insert into t1 values (0); -delete from t1; -select * from t1; -a -insert into t1 values (0), (1); -select * from t1 where a = 0; -a -0 -drop table t1; -create table t1 (c char(10)) engine=memory; -create table t2 (c varchar(10)) engine=memory; -show table status like 't_'; -Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment -t1 MEMORY 10 Fixed 0 11 0 # 0 0 NULL NULL NULL NULL latin1_swedish_ci NULL -t2 MEMORY 10 Fixed 0 12 0 # 0 0 NULL NULL NULL NULL latin1_swedish_ci NULL -drop table t1, t2; -CREATE TABLE t1(a VARCHAR(1), b VARCHAR(2), c VARCHAR(256), -KEY(a), KEY(b), KEY(c)) ENGINE=MEMORY; -INSERT INTO t1 VALUES('a','aa',REPEAT('a', 256)),('a','aa',REPEAT('a',256)); -SELECT COUNT(*) FROM t1 WHERE a='a'; -COUNT(*) -2 -SELECT COUNT(*) FROM t1 WHERE b='aa'; -COUNT(*) -2 -SELECT COUNT(*) FROM t1 WHERE c=REPEAT('a',256); -COUNT(*) -2 -DROP TABLE t1; diff --git a/mysql-test/suite/pbxt/r/select_safe.result b/mysql-test/suite/pbxt/r/select_safe.result index 8739a89eafb..70c66337b9f 100644 --- a/mysql-test/suite/pbxt/r/select_safe.result +++ b/mysql-test/suite/pbxt/r/select_safe.result @@ -35,7 +35,7 @@ ERROR HY000: You are using safe update mode and you tried to update a table with delete from t1 where a+0=1; ERROR HY000: You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column select 1 from t1,t1 as t2,t1 as t3,t1 as t4,t1 as t5; -ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay +ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET MAX_JOIN_SIZE=# if the SELECT is okay update t1 set b="a" order by a limit 1; update t1 set b="a" where b="b" order by a limit 2; delete from t1 where b="test" order by a limit 1; @@ -47,7 +47,7 @@ SELECT @@MAX_JOIN_SIZE, @@SQL_BIG_SELECTS; 2 0 insert into t1 values (null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"); SELECT * from t1 order by a; -ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay +ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET MAX_JOIN_SIZE=# if the SELECT is okay SET SQL_BIG_SELECTS=1; SELECT * from t1 order by a; a b @@ -57,7 +57,7 @@ a b 5 a SET MAX_JOIN_SIZE=2; SELECT * from t1; -ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay +ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET MAX_JOIN_SIZE=# if the SELECT is okay SET MAX_JOIN_SIZE=DEFAULT; SELECT * from t1; a b @@ -87,12 +87,12 @@ insert into t1 select * from t1; insert into t1 select * from t1; set local max_join_size=8; select * from (select * from t1) x; -ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay +ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET MAX_JOIN_SIZE=# if the SELECT is okay set local max_join_size=1; select * from (select a.a as aa, b.a as ba from t1 a, t1 b) x; -ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay +ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET MAX_JOIN_SIZE=# if the SELECT is okay set local max_join_size=1; select * from (select 1 union select 2 union select 3) x; -ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay +ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET MAX_JOIN_SIZE=# if the SELECT is okay drop table t1; SET SQL_SAFE_UPDATES=0,SQL_SELECT_LIMIT=DEFAULT, SQL_MAX_JOIN_SIZE=DEFAULT; diff --git a/mysql-test/suite/pbxt/r/view_grant.result b/mysql-test/suite/pbxt/r/view_grant.result deleted file mode 100644 index f66ff458761..00000000000 --- a/mysql-test/suite/pbxt/r/view_grant.result +++ /dev/null @@ -1,958 +0,0 @@ -drop database if exists mysqltest; -drop view if exists v1,v2,v3; -grant create view on test.* to test@localhost; -show grants for test@localhost; -Grants for test@localhost -GRANT USAGE ON *.* TO 'test'@'localhost' -GRANT CREATE VIEW ON `test`.* TO 'test'@'localhost' -revoke create view on test.* from test@localhost; -show grants for test@localhost; -Grants for test@localhost -GRANT USAGE ON *.* TO 'test'@'localhost' -drop user test@localhost; -create database mysqltest; -create table mysqltest.t1 (a int, b int); -create table mysqltest.t2 (a int, b int); -grant select on mysqltest.t1 to mysqltest_1@localhost; -grant create view,select on test.* to mysqltest_1@localhost; -create definer=root@localhost view v1 as select * from mysqltest.t1; -ERROR 42000: Access denied; you need the SUPER privilege for this operation -create view v1 as select * from mysqltest.t1; -alter view v1 as select * from mysqltest.t1; -ERROR 42000: DROP command denied to user 'mysqltest_1'@'localhost' for table 'v1' -create or replace view v1 as select * from mysqltest.t1; -ERROR 42000: DROP command denied to user 'mysqltest_1'@'localhost' for table 'v1' -create view mysqltest.v2 as select * from mysqltest.t1; -ERROR 42000: CREATE VIEW command denied to user 'mysqltest_1'@'localhost' for table 'v2' -create view v2 as select * from mysqltest.t2; -ERROR 42000: ANY command denied to user 'mysqltest_1'@'localhost' for table 't2' -show create view v1; -View Create View character_set_client collation_connection -v1 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqltest_1`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `mysqltest`.`t1`.`a` AS `a`,`mysqltest`.`t1`.`b` AS `b` from `mysqltest`.`t1` latin1 latin1_swedish_ci -grant create view,drop,select on test.* to mysqltest_1@localhost; -use test; -alter view v1 as select * from mysqltest.t1; -create or replace view v1 as select * from mysqltest.t1; -revoke all privileges on mysqltest.t1 from mysqltest_1@localhost; -revoke all privileges on test.* from mysqltest_1@localhost; -drop database mysqltest; -drop view test.v1; -create database mysqltest; -create table mysqltest.t1 (a int, b int); -create view mysqltest.v1 (c,d) as select a+1,b+1 from mysqltest.t1; -grant select (c) on mysqltest.v1 to mysqltest_1@localhost; -select c from mysqltest.v1; -c -select d from mysqltest.v1; -ERROR 42000: SELECT command denied to user 'mysqltest_1'@'localhost' for column 'd' in table 'v1' -revoke all privileges on mysqltest.v1 from mysqltest_1@localhost; -delete from mysql.user where user='mysqltest_1'; -drop database mysqltest; -create database mysqltest; -create table mysqltest.t1 (a int, b int); -create algorithm=temptable view mysqltest.v1 (c,d) as select a+1,b+1 from mysqltest.t1; -grant select (c) on mysqltest.v1 to mysqltest_1@localhost; -select c from mysqltest.v1; -c -select d from mysqltest.v1; -ERROR 42000: SELECT command denied to user 'mysqltest_1'@'localhost' for column 'd' in table 'v1' -revoke all privileges on mysqltest.v1 from mysqltest_1@localhost; -delete from mysql.user where user='mysqltest_1'; -drop database mysqltest; -create database mysqltest; -create table mysqltest.t1 (a int, b int); -create table mysqltest.t2 (a int, b int); -create view mysqltest.v1 (c,d) as select a+1,b+1 from mysqltest.t1; -create algorithm=temptable view mysqltest.v2 (c,d) as select a+1,b+1 from mysqltest.t1; -create view mysqltest.v3 (c,d) as select a+1,b+1 from mysqltest.t2; -create algorithm=temptable view mysqltest.v4 (c,d) as select a+1,b+1 from mysqltest.t2; -grant select on mysqltest.v1 to mysqltest_1@localhost; -grant select on mysqltest.v2 to mysqltest_1@localhost; -grant select on mysqltest.v3 to mysqltest_1@localhost; -grant select on mysqltest.v4 to mysqltest_1@localhost; -select c from mysqltest.v1; -c -select c from mysqltest.v2; -c -select c from mysqltest.v3; -c -select c from mysqltest.v4; -c -show columns from mysqltest.v1; -Field Type Null Key Default Extra -c bigint(12) YES NULL -d bigint(12) YES NULL -show columns from mysqltest.v2; -Field Type Null Key Default Extra -c bigint(12) YES NULL -d bigint(12) YES NULL -explain select c from mysqltest.v1; -ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table -show create view mysqltest.v1; -ERROR 42000: SHOW VIEW command denied to user 'mysqltest_1'@'localhost' for table 'v1' -explain select c from mysqltest.v2; -ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table -show create view mysqltest.v2; -ERROR 42000: SHOW VIEW command denied to user 'mysqltest_1'@'localhost' for table 'v2' -explain select c from mysqltest.v3; -ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table -show create view mysqltest.v3; -ERROR 42000: SHOW VIEW command denied to user 'mysqltest_1'@'localhost' for table 'v3' -explain select c from mysqltest.v4; -ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table -show create view mysqltest.v4; -ERROR 42000: SHOW VIEW command denied to user 'mysqltest_1'@'localhost' for table 'v4' -grant select on mysqltest.t1 to mysqltest_1@localhost; -explain select c from mysqltest.v1; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 0 -show create view mysqltest.v1; -ERROR 42000: SHOW VIEW command denied to user 'mysqltest_1'@'localhost' for table 'v1' -explain select c from mysqltest.v2; -id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY system NULL NULL NULL NULL 0 const row not found -2 DERIVED t1 ALL NULL NULL NULL NULL 0 -show create view mysqltest.v2; -ERROR 42000: SHOW VIEW command denied to user 'mysqltest_1'@'localhost' for table 'v2' -explain select c from mysqltest.v3; -ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table -show create view mysqltest.v3; -ERROR 42000: SHOW VIEW command denied to user 'mysqltest_1'@'localhost' for table 'v3' -explain select c from mysqltest.v4; -ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table -show create view mysqltest.v4; -ERROR 42000: SHOW VIEW command denied to user 'mysqltest_1'@'localhost' for table 'v4' -grant show view on mysqltest.* to mysqltest_1@localhost; -explain select c from mysqltest.v1; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 0 -show create view mysqltest.v1; -View Create View character_set_client collation_connection -v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest`.`v1` AS select (`mysqltest`.`t1`.`a` + 1) AS `c`,(`mysqltest`.`t1`.`b` + 1) AS `d` from `mysqltest`.`t1` latin1 latin1_swedish_ci -explain select c from mysqltest.v2; -id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY system NULL NULL NULL NULL 0 const row not found -2 DERIVED t1 ALL NULL NULL NULL NULL 0 -show create view mysqltest.v2; -View Create View character_set_client collation_connection -v2 CREATE ALGORITHM=TEMPTABLE DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest`.`v2` AS select (`mysqltest`.`t1`.`a` + 1) AS `c`,(`mysqltest`.`t1`.`b` + 1) AS `d` from `mysqltest`.`t1` latin1 latin1_swedish_ci -explain select c from mysqltest.v3; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 ALL NULL NULL NULL NULL 0 -show create view mysqltest.v3; -View Create View character_set_client collation_connection -v3 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest`.`v3` AS select (`mysqltest`.`t2`.`a` + 1) AS `c`,(`mysqltest`.`t2`.`b` + 1) AS `d` from `mysqltest`.`t2` latin1 latin1_swedish_ci -explain select c from mysqltest.v4; -id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY system NULL NULL NULL NULL 0 const row not found -2 DERIVED t2 ALL NULL NULL NULL NULL 0 -show create view mysqltest.v4; -View Create View character_set_client collation_connection -v4 CREATE ALGORITHM=TEMPTABLE DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest`.`v4` AS select (`mysqltest`.`t2`.`a` + 1) AS `c`,(`mysqltest`.`t2`.`b` + 1) AS `d` from `mysqltest`.`t2` latin1 latin1_swedish_ci -revoke all privileges on mysqltest.* from mysqltest_1@localhost; -delete from mysql.user where user='mysqltest_1'; -drop database mysqltest; -create database mysqltest; -create table mysqltest.t1 (a int, b int, primary key(a)); -insert into mysqltest.t1 values (10,2), (20,3), (30,4), (40,5), (50,10); -create table mysqltest.t2 (x int); -insert into mysqltest.t2 values (3), (4), (5), (6); -create view mysqltest.v1 (a,c) as select a, b+1 from mysqltest.t1; -create view mysqltest.v2 (a,c) as select a, b from mysqltest.t1; -create view mysqltest.v3 (a,c) as select a, b+1 from mysqltest.t1; -grant update (a) on mysqltest.v2 to mysqltest_1@localhost; -grant update on mysqltest.v1 to mysqltest_1@localhost; -grant select on mysqltest.* to mysqltest_1@localhost; -use mysqltest; -update t2,v1 set v1.a=v1.a+v1.c where t2.x=v1.c; -select * from t1 order by a; -a b -13 2 -24 3 -35 4 -46 5 -50 10 -update v1 set a=a+c; -select * from t1 order by a; -a b -16 2 -28 3 -40 4 -52 5 -61 10 -update t2,v2 set v2.a=v2.a+v2.c where t2.x=v2.c; -select * from t1 order by a; -a b -16 2 -31 3 -44 4 -57 5 -61 10 -update v2 set a=a+c; -select * from t1 order by a; -a b -18 2 -34 3 -48 4 -62 5 -71 10 -update t2,v2 set v2.c=v2.a+v2.c where t2.x=v2.c; -ERROR 42000: UPDATE command denied to user 'mysqltest_1'@'localhost' for column 'c' in table 'v2' -update v2 set c=a+c; -ERROR 42000: UPDATE command denied to user 'mysqltest_1'@'localhost' for column 'c' in table 'v2' -update t2,v3 set v3.a=v3.a+v3.c where t2.x=v3.c; -ERROR 42000: UPDATE command denied to user 'mysqltest_1'@'localhost' for table 'v3' -update v3 set a=a+c; -ERROR 42000: UPDATE command denied to user 'mysqltest_1'@'localhost' for table 'v3' -use test; -REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost; -drop database mysqltest; -create database mysqltest; -create table mysqltest.t1 (a int, b int, primary key(a)); -insert into mysqltest.t1 values (1,2), (2,3), (3,4), (4,5), (5,10); -create table mysqltest.t2 (x int); -insert into mysqltest.t2 values (3), (4), (5), (6); -create view mysqltest.v1 (a,c) as select a, b+1 from mysqltest.t1; -create view mysqltest.v2 (a,c) as select a, b+1 from mysqltest.t1; -grant delete on mysqltest.v1 to mysqltest_1@localhost; -grant select on mysqltest.* to mysqltest_1@localhost; -use mysqltest; -delete from v1 where c < 4; -select * from t1; -a b -2 3 -3 4 -4 5 -5 10 -delete v1 from t2,v1 where t2.x=v1.c; -select * from t1; -a b -5 10 -delete v2 from t2,v2 where t2.x=v2.c; -ERROR 42000: DELETE command denied to user 'mysqltest_1'@'localhost' for table 'v2' -delete from v2 where c < 4; -ERROR 42000: DELETE command denied to user 'mysqltest_1'@'localhost' for table 'v2' -use test; -REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost; -drop database mysqltest; -create database mysqltest; -create table mysqltest.t1 (a int, b int, primary key(a)); -insert into mysqltest.t1 values (1,2), (2,3); -create table mysqltest.t2 (x int, y int); -insert into mysqltest.t2 values (3,4); -create view mysqltest.v1 (a,c) as select a, b from mysqltest.t1; -create view mysqltest.v2 (a,c) as select a, b from mysqltest.t1; -grant insert on mysqltest.v1 to mysqltest_1@localhost; -grant select on mysqltest.* to mysqltest_1@localhost; -use mysqltest; -insert into v1 values (5,6); -select * from t1; -a b -1 2 -2 3 -5 6 -insert into v1 select x,y from t2; -select * from t1; -a b -1 2 -2 3 -5 6 -3 4 -insert into v2 values (5,6); -ERROR 42000: INSERT command denied to user 'mysqltest_1'@'localhost' for table 'v2' -insert into v2 select x,y from t2; -ERROR 42000: INSERT command denied to user 'mysqltest_1'@'localhost' for table 'v2' -use test; -REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost; -drop database mysqltest; -create database mysqltest; -create table mysqltest.t1 (a int, b int); -create table mysqltest.t2 (a int, b int); -grant update on mysqltest.t1 to mysqltest_1@localhost; -grant update(b) on mysqltest.t2 to mysqltest_1@localhost; -grant create view,update on test.* to mysqltest_1@localhost; -create view v1 as select * from mysqltest.t1; -create view v2 as select b from mysqltest.t2; -create view mysqltest.v1 as select * from mysqltest.t1; -ERROR 42000: CREATE VIEW command denied to user 'mysqltest_1'@'localhost' for table 'v1' -create view v3 as select a from mysqltest.t2; -ERROR 42000: ANY command denied to user 'mysqltest_1'@'localhost' for column 'a' in table 't2' -create table mysqltest.v3 (b int); -grant create view on mysqltest.v3 to mysqltest_1@localhost; -drop table mysqltest.v3; -create view mysqltest.v3 as select b from mysqltest.t2; -grant create view, update on mysqltest.v3 to mysqltest_1@localhost; -drop view mysqltest.v3; -create view mysqltest.v3 as select b from mysqltest.t2; -create view v4 as select b+1 from mysqltest.t2; -ERROR 42000: SELECT command denied to user 'mysqltest_1'@'localhost' for column 'b' in table 't2' -grant create view,update,select on test.* to mysqltest_1@localhost; -create view v4 as select b+1 from mysqltest.t2; -ERROR 42000: SELECT command denied to user 'mysqltest_1'@'localhost' for column 'b' in table 't2' -grant update,select(b) on mysqltest.t2 to mysqltest_1@localhost; -create view v4 as select b+1 from mysqltest.t2; -REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost; -drop database mysqltest; -drop view v1,v2,v4; -create database mysqltest; -create table mysqltest.t1 (a int); -grant all privileges on mysqltest.* to mysqltest_1@localhost; -use mysqltest; -create view v1 as select * from t1; -use test; -revoke all privileges on mysqltest.* from mysqltest_1@localhost; -drop database mysqltest; -create database mysqltest; -create table mysqltest.t1 (a int, b int); -grant select on mysqltest.t1 to mysqltest_1@localhost; -grant create view,select on test.* to mysqltest_1@localhost; -create view v1 as select * from mysqltest.t1; -show create view v1; -View Create View character_set_client collation_connection -v1 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqltest_1`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `mysqltest`.`t1`.`a` AS `a`,`mysqltest`.`t1`.`b` AS `b` from `mysqltest`.`t1` latin1 latin1_swedish_ci -revoke select on mysqltest.t1 from mysqltest_1@localhost; -select * from v1; -ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them -grant select on mysqltest.t1 to mysqltest_1@localhost; -select * from v1; -a b -REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost; -drop view v1; -drop database mysqltest; -create database mysqltest; -use mysqltest; -create table t1 (a int); -insert into t1 values (1); -create table t2 (s1 int); -drop function if exists f2; -create function f2 () returns int begin declare v int; select s1 from t2 -into v; return v; end// -create algorithm=TEMPTABLE view v1 as select f2() from t1; -create algorithm=MERGE view v2 as select f2() from t1; -create algorithm=TEMPTABLE SQL SECURITY INVOKER view v3 as select f2() from t1; -create algorithm=MERGE SQL SECURITY INVOKER view v4 as select f2() from t1; -create SQL SECURITY INVOKER view v5 as select * from v4; -grant select on v1 to mysqltest_1@localhost; -grant select on v2 to mysqltest_1@localhost; -grant select on v3 to mysqltest_1@localhost; -grant select on v4 to mysqltest_1@localhost; -grant select on v5 to mysqltest_1@localhost; -use mysqltest; -select * from v1; -f2() -NULL -Warnings: -Warning 1329 No data - zero rows fetched, selected, or processed -select * from v2; -f2() -NULL -Warnings: -Warning 1329 No data - zero rows fetched, selected, or processed -select * from v3; -ERROR HY000: View 'mysqltest.v3' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them -select * from v4; -ERROR HY000: View 'mysqltest.v4' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them -select * from v5; -ERROR HY000: View 'mysqltest.v5' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them -use test; -drop view v1, v2, v3, v4, v5; -drop function f2; -drop table t1, t2; -use test; -REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost; -drop database mysqltest; -create database mysqltest; -use mysqltest; -create table t1 (a int); -insert into t1 values (1); -create table t2 (s1 int); -drop function if exists f2; -create function f2 () returns int begin declare v int; select s1 from t2 -into v; return v; end// -grant select on t1 to mysqltest_1@localhost; -grant execute on function f2 to mysqltest_1@localhost; -grant create view on mysqltest.* to mysqltest_1@localhost; -use mysqltest; -create algorithm=TEMPTABLE view v1 as select f2() from t1; -create algorithm=MERGE view v2 as select f2() from t1; -create algorithm=TEMPTABLE SQL SECURITY INVOKER view v3 as select f2() from t1; -create algorithm=MERGE SQL SECURITY INVOKER view v4 as select f2() from t1; -use test; -create view v5 as select * from v1; -revoke execute on function f2 from mysqltest_1@localhost; -select * from v1; -ERROR HY000: View 'mysqltest.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them -select * from v2; -ERROR HY000: View 'mysqltest.v2' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them -select * from v3; -f2() -NULL -Warnings: -Warning 1329 No data - zero rows fetched, selected, or processed -select * from v4; -f2() -NULL -Warnings: -Warning 1329 No data - zero rows fetched, selected, or processed -select * from v5; -ERROR HY000: View 'mysqltest.v5' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them -drop view v1, v2, v3, v4, v5; -drop function f2; -drop table t1, t2; -use test; -REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost; -drop database mysqltest; -create database mysqltest; -use mysqltest; -create table t1 (a int); -create table v1 (a int); -insert into t1 values (1); -grant select on t1 to mysqltest_1@localhost; -grant select on v1 to mysqltest_1@localhost; -grant create view on mysqltest.* to mysqltest_1@localhost; -drop table v1; -use mysqltest; -create algorithm=TEMPTABLE view v1 as select *, a as b from t1; -create algorithm=MERGE view v2 as select *, a as b from t1; -create algorithm=TEMPTABLE SQL SECURITY INVOKER view v3 as select *, a as b from t1; -create algorithm=MERGE SQL SECURITY INVOKER view v4 as select *, a as b from t1; -create view v5 as select * from v1; -use test; -revoke select on t1 from mysqltest_1@localhost; -select * from v1; -ERROR HY000: View 'mysqltest.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them -select * from v2; -ERROR HY000: View 'mysqltest.v2' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them -select * from v3; -a b -1 1 -select * from v4; -a b -1 1 -select * from v5; -ERROR HY000: View 'mysqltest.v5' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them -drop table t1; -use test; -REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost; -drop database mysqltest; -create database mysqltest; -use mysqltest; -create table t1 (a int); -insert into t1 values (1); -create algorithm=TEMPTABLE view v1 as select *, a as b from t1; -create algorithm=MERGE view v2 as select *, a as b from t1; -create algorithm=TEMPTABLE SQL SECURITY INVOKER view v3 as select *, a as b from t1; -create algorithm=MERGE SQL SECURITY INVOKER view v4 as select *, a as b from t1; -create SQL SECURITY INVOKER view v5 as select * from v4; -grant select on v1 to mysqltest_1@localhost; -grant select on v2 to mysqltest_1@localhost; -grant select on v3 to mysqltest_1@localhost; -grant select on v4 to mysqltest_1@localhost; -grant select on v5 to mysqltest_1@localhost; -use mysqltest; -select * from v1; -a b -1 1 -select * from v2; -a b -1 1 -select * from v3; -ERROR HY000: View 'mysqltest.v3' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them -select * from v4; -ERROR HY000: View 'mysqltest.v4' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them -select * from v5; -ERROR HY000: View 'mysqltest.v5' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them -use test; -drop view v1, v2, v3, v4, v5; -drop table t1; -use test; -REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost; -drop database mysqltest; -drop view if exists v1; -create table t1 as select * from mysql.user where user=''; -delete from mysql.user where user=''; -flush privileges; -grant all on test.* to 'test14256'@'%'; -use test; -create view v1 as select 42; -show create view v1; -View Create View character_set_client collation_connection -v1 CREATE ALGORITHM=UNDEFINED DEFINER=`test14256`@`%` SQL SECURITY DEFINER VIEW `v1` AS select 42 AS `42` latin1 latin1_swedish_ci -select definer into @v1def1 from information_schema.views -where table_schema = 'test' and table_name='v1'; -drop view v1; -create definer=`test14256`@`%` view v1 as select 42; -show create view v1; -View Create View character_set_client collation_connection -v1 CREATE ALGORITHM=UNDEFINED DEFINER=`test14256`@`%` SQL SECURITY DEFINER VIEW `v1` AS select 42 AS `42` latin1 latin1_swedish_ci -select definer into @v1def2 from information_schema.views -where table_schema = 'test' and table_name='v1'; -drop view v1; -select @v1def1, @v1def2, @v1def1=@v1def2; -@v1def1 @v1def2 @v1def1=@v1def2 -test14256@% test14256@% 1 -drop user test14256; -insert into mysql.user select * from t1; -flush privileges; -drop table t1; -create database mysqltest; -use mysqltest; -CREATE TABLE t1 (i INT); -CREATE VIEW v1 AS SELECT * FROM t1; -SHOW CREATE VIEW v1; -View Create View character_set_client collation_connection -v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`i` AS `i` from `t1` latin1 latin1_swedish_ci -GRANT SELECT, LOCK TABLES ON mysqltest.* TO mysqltest_1@localhost; -use mysqltest; -LOCK TABLES v1 READ; -SHOW CREATE TABLE v1; -ERROR 42000: SHOW VIEW command denied to user 'mysqltest_1'@'localhost' for table 'v1' -UNLOCK TABLES; -use test; -use test; -drop user mysqltest_1@localhost; -drop database mysqltest; -create definer=some_user@`` sql security invoker view v1 as select 1; -Warnings: -Note 1449 The user specified as a definer ('some_user'@'') does not exist -create definer=some_user@localhost sql security invoker view v2 as select 1; -Warnings: -Note 1449 The user specified as a definer ('some_user'@'localhost') does not exist -show create view v1; -View Create View character_set_client collation_connection -v1 CREATE ALGORITHM=UNDEFINED DEFINER=`some_user`@`` SQL SECURITY INVOKER VIEW `v1` AS select 1 AS `1` latin1 latin1_swedish_ci -show create view v2; -View Create View character_set_client collation_connection -v2 CREATE ALGORITHM=UNDEFINED DEFINER=`some_user`@`localhost` SQL SECURITY INVOKER VIEW `v2` AS select 1 AS `1` latin1 latin1_swedish_ci -drop view v1; -drop view v2; -CREATE DATABASE mysqltest1; -CREATE USER readonly@localhost; -CREATE TABLE mysqltest1.t1 (x INT); -INSERT INTO mysqltest1.t1 VALUES (1), (2); -CREATE SQL SECURITY INVOKER VIEW mysqltest1.v_t1 AS SELECT * FROM mysqltest1.t1; -CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_ts AS SELECT * FROM mysqltest1.t1; -CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_ti AS SELECT * FROM mysqltest1.t1; -CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_tu AS SELECT * FROM mysqltest1.t1; -CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_tus AS SELECT * FROM mysqltest1.t1; -CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_td AS SELECT * FROM mysqltest1.t1; -CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_tds AS SELECT * FROM mysqltest1.t1; -GRANT SELECT, INSERT, UPDATE, DELETE ON mysqltest1.v_t1 TO readonly@localhost; -GRANT SELECT ON mysqltest1.v_ts TO readonly@localhost; -GRANT INSERT ON mysqltest1.v_ti TO readonly@localhost; -GRANT UPDATE ON mysqltest1.v_tu TO readonly@localhost; -GRANT UPDATE,SELECT ON mysqltest1.v_tus TO readonly@localhost; -GRANT DELETE ON mysqltest1.v_td TO readonly@localhost; -GRANT DELETE,SELECT ON mysqltest1.v_tds TO readonly@localhost; -SELECT * FROM mysqltest1.v_t1; -ERROR HY000: View 'mysqltest1.v_t1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them -INSERT INTO mysqltest1.v_t1 VALUES(4); -ERROR HY000: View 'mysqltest1.v_t1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them -DELETE FROM mysqltest1.v_t1 WHERE x = 1; -ERROR HY000: View 'mysqltest1.v_t1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them -UPDATE mysqltest1.v_t1 SET x = 3 WHERE x = 2; -ERROR HY000: View 'mysqltest1.v_t1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them -UPDATE mysqltest1.v_t1 SET x = 3; -ERROR HY000: View 'mysqltest1.v_t1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them -DELETE FROM mysqltest1.v_t1; -ERROR HY000: View 'mysqltest1.v_t1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them -SELECT 1 FROM mysqltest1.v_t1; -ERROR HY000: View 'mysqltest1.v_t1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them -SELECT * FROM mysqltest1.t1; -ERROR 42000: SELECT command denied to user 'readonly'@'localhost' for table 't1' -SELECT * FROM mysqltest1.v_ts; -x -1 -2 -SELECT * FROM mysqltest1.v_ts, mysqltest1.t1 WHERE mysqltest1.t1.x = mysqltest1.v_ts.x; -ERROR 42000: SELECT command denied to user 'readonly'@'localhost' for table 't1' -SELECT * FROM mysqltest1.v_ti; -ERROR 42000: SELECT command denied to user 'readonly'@'localhost' for table 'v_ti' -INSERT INTO mysqltest1.v_ts VALUES (100); -ERROR 42000: INSERT command denied to user 'readonly'@'localhost' for table 'v_ts' -INSERT INTO mysqltest1.v_ti VALUES (100); -UPDATE mysqltest1.v_ts SET x= 200 WHERE x = 100; -ERROR 42000: UPDATE command denied to user 'readonly'@'localhost' for table 'v_ts' -UPDATE mysqltest1.v_ts SET x= 200; -ERROR 42000: UPDATE command denied to user 'readonly'@'localhost' for table 'v_ts' -UPDATE mysqltest1.v_tu SET x= 200 WHERE x = 100; -UPDATE mysqltest1.v_tus SET x= 200 WHERE x = 100; -UPDATE mysqltest1.v_tu SET x= 200; -DELETE FROM mysqltest1.v_ts WHERE x= 200; -ERROR 42000: DELETE command denied to user 'readonly'@'localhost' for table 'v_ts' -DELETE FROM mysqltest1.v_ts; -ERROR 42000: DELETE command denied to user 'readonly'@'localhost' for table 'v_ts' -DELETE FROM mysqltest1.v_td WHERE x= 200; -ERROR 42000: SELECT command denied to user 'readonly'@'localhost' for column 'x' in table 'v_td' -DELETE FROM mysqltest1.v_tds WHERE x= 200; -DELETE FROM mysqltest1.v_td; -DROP VIEW mysqltest1.v_tds; -DROP VIEW mysqltest1.v_td; -DROP VIEW mysqltest1.v_tus; -DROP VIEW mysqltest1.v_tu; -DROP VIEW mysqltest1.v_ti; -DROP VIEW mysqltest1.v_ts; -DROP VIEW mysqltest1.v_t1; -DROP TABLE mysqltest1.t1; -DROP USER readonly@localhost; -DROP DATABASE mysqltest1; -CREATE TABLE t1 (a INT PRIMARY KEY); -INSERT INTO t1 VALUES (1), (2), (3); -CREATE DEFINER = 'no-such-user'@localhost VIEW v AS SELECT a from t1; -Warnings: -Note 1449 The user specified as a definer ('no-such-user'@'localhost') does not exist -SHOW CREATE VIEW v; -View Create View character_set_client collation_connection -v CREATE ALGORITHM=UNDEFINED DEFINER=`no-such-user`@`localhost` SQL SECURITY DEFINER VIEW `v` AS select `test`.`t1`.`a` AS `a` from `t1` latin1 latin1_swedish_ci -Warnings: -Note 1449 The user specified as a definer ('no-such-user'@'localhost') does not exist -SELECT * FROM v; -ERROR HY000: The user specified as a definer ('no-such-user'@'localhost') does not exist -DROP VIEW v; -DROP TABLE t1; -USE test; -CREATE USER mysqltest_db1@localhost identified by 'PWD'; -GRANT ALL ON mysqltest_db1.* TO mysqltest_db1@localhost WITH GRANT OPTION; -CREATE SCHEMA mysqltest_db1 ; -USE mysqltest_db1 ; -CREATE TABLE t1 (f1 INTEGER); -CREATE VIEW view1 AS -SELECT * FROM t1; -SHOW CREATE VIEW view1; -View Create View character_set_client collation_connection -view1 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqltest_db1`@`localhost` SQL SECURITY DEFINER VIEW `view1` AS select `t1`.`f1` AS `f1` from `t1` latin1 latin1_swedish_ci -CREATE VIEW view2 AS -SELECT * FROM view1; -# Here comes a suspicious warning -SHOW CREATE VIEW view2; -View Create View character_set_client collation_connection -view2 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqltest_db1`@`localhost` SQL SECURITY DEFINER VIEW `view2` AS select `view1`.`f1` AS `f1` from `view1` latin1 latin1_swedish_ci -# But the view view2 is usable -SELECT * FROM view2; -f1 -CREATE VIEW view3 AS -SELECT * FROM view2; -SELECT * from view3; -f1 -DROP VIEW mysqltest_db1.view3; -DROP VIEW mysqltest_db1.view2; -DROP VIEW mysqltest_db1.view1; -DROP TABLE mysqltest_db1.t1; -DROP SCHEMA mysqltest_db1; -DROP USER mysqltest_db1@localhost; -CREATE DATABASE test1; -CREATE DATABASE test2; -CREATE TABLE test1.t0 (a VARCHAR(20)) engine=myisam; -CREATE TABLE test2.t1 (a VARCHAR(20)); -CREATE VIEW test2.t3 AS SELECT * FROM test1.t0; -CREATE OR REPLACE VIEW test.v1 AS -SELECT ta.a AS col1, tb.a AS col2 FROM test2.t3 ta, test2.t1 tb; -DROP VIEW test.v1; -DROP VIEW test2.t3; -DROP TABLE test2.t1, test1.t0; -DROP DATABASE test2; -DROP DATABASE test1; -DROP VIEW IF EXISTS v1; -DROP VIEW IF EXISTS v2; -DROP VIEW IF EXISTS v3; -DROP FUNCTION IF EXISTS f1; -DROP FUNCTION IF EXISTS f2; -DROP PROCEDURE IF EXISTS p1; -CREATE SQL SECURITY DEFINER VIEW v1 AS SELECT CURRENT_USER() AS cu; -CREATE FUNCTION f1() RETURNS VARCHAR(77) SQL SECURITY INVOKER -RETURN CURRENT_USER(); -CREATE SQL SECURITY DEFINER VIEW v2 AS SELECT f1() AS cu; -CREATE PROCEDURE p1(OUT cu VARCHAR(77)) SQL SECURITY INVOKER -SET cu= CURRENT_USER(); -CREATE FUNCTION f2() RETURNS VARCHAR(77) SQL SECURITY INVOKER -BEGIN -DECLARE cu VARCHAR(77); -CALL p1(cu); -RETURN cu; -END| -CREATE SQL SECURITY DEFINER VIEW v3 AS SELECT f2() AS cu; -CREATE USER mysqltest_u1@localhost; -GRANT ALL ON test.* TO mysqltest_u1@localhost; - -The following tests should all return 1. - -SELECT CURRENT_USER() = 'mysqltest_u1@localhost'; -CURRENT_USER() = 'mysqltest_u1@localhost' -1 -SELECT f1() = 'mysqltest_u1@localhost'; -f1() = 'mysqltest_u1@localhost' -1 -CALL p1(@cu); -SELECT @cu = 'mysqltest_u1@localhost'; -@cu = 'mysqltest_u1@localhost' -1 -SELECT f2() = 'mysqltest_u1@localhost'; -f2() = 'mysqltest_u1@localhost' -1 -SELECT cu = 'root@localhost' FROM v1; -cu = 'root@localhost' -1 -SELECT cu = 'root@localhost' FROM v2; -cu = 'root@localhost' -1 -SELECT cu = 'root@localhost' FROM v3; -cu = 'root@localhost' -1 -DROP VIEW v3; -DROP FUNCTION f2; -DROP PROCEDURE p1; -DROP FUNCTION f1; -DROP VIEW v2; -DROP VIEW v1; -DROP USER mysqltest_u1@localhost; -CREATE DATABASE db17254; -USE db17254; -CREATE TABLE t1 (f1 INT); -INSERT INTO t1 VALUES (10),(20); -CREATE USER def_17254@localhost; -GRANT SELECT ON db17254.* TO def_17254@localhost; -CREATE USER inv_17254@localhost; -GRANT SELECT ON db17254.t1 TO inv_17254@localhost; -GRANT CREATE VIEW ON db17254.* TO def_17254@localhost; -CREATE VIEW v1 AS SELECT * FROM t1; -DROP USER def_17254@localhost; -for a user -SELECT * FROM v1; -ERROR 42000: SELECT command denied to user 'inv_17254'@'localhost' for table 'v1' -for a superuser -SELECT * FROM v1; -ERROR HY000: The user specified as a definer ('def_17254'@'localhost') does not exist -DROP USER inv_17254@localhost; -DROP DATABASE db17254; -DROP DATABASE IF EXISTS mysqltest_db1; -DROP DATABASE IF EXISTS mysqltest_db2; -DROP USER mysqltest_u1; -DROP USER mysqltest_u2; -CREATE USER mysqltest_u1@localhost; -CREATE USER mysqltest_u2@localhost; -CREATE DATABASE mysqltest_db1; -CREATE DATABASE mysqltest_db2; -GRANT ALL ON mysqltest_db1.* TO mysqltest_u1@localhost WITH GRANT OPTION; -GRANT ALL ON mysqltest_db2.* TO mysqltest_u2@localhost; -CREATE TABLE t1 (i INT); -INSERT INTO t1 VALUES (1); -CREATE VIEW v1 AS SELECT i FROM t1 WHERE 1 IN (SELECT * FROM t1); -CREATE TABLE t2 (s CHAR(7)); -INSERT INTO t2 VALUES ('public'); -GRANT SELECT ON v1 TO mysqltest_u2@localhost; -GRANT SELECT ON t2 TO mysqltest_u2@localhost; -SELECT * FROM mysqltest_db1.v1, mysqltest_db1.t2; -i s -1 public -PREPARE stmt1 FROM "SELECT * FROM mysqltest_db1.t2"; -EXECUTE stmt1; -s -public -PREPARE stmt2 FROM "SELECT * FROM mysqltest_db1.v1, mysqltest_db1.t2"; -EXECUTE stmt2; -i s -1 public -REVOKE SELECT ON t2 FROM mysqltest_u2@localhost; -UPDATE t2 SET s = 'private' WHERE s = 'public'; -SELECT * FROM mysqltest_db1.v1, mysqltest_db1.t2; -ERROR 42000: SELECT command denied to user 'mysqltest_u2'@'localhost' for table 't2' -EXECUTE stmt1; -ERROR 42000: SELECT command denied to user 'mysqltest_u2'@'localhost' for table 't2' -EXECUTE stmt2; -ERROR 42000: SELECT command denied to user 'mysqltest_u2'@'localhost' for table 't2' -REVOKE ALL ON mysqltest_db1.* FROM mysqltest_u1@localhost; -REVOKE ALL ON mysqltest_db2.* FROM mysqltest_u2@localhost; -DROP DATABASE mysqltest_db1; -DROP DATABASE mysqltest_db2; -DROP USER mysqltest_u1@localhost; -DROP USER mysqltest_u2@localhost; -CREATE DATABASE db26813; -USE db26813; -CREATE TABLE t1(f1 INT, f2 INT); -CREATE VIEW v1 AS SELECT f1 FROM t1; -CREATE VIEW v2 AS SELECT f1 FROM t1; -CREATE VIEW v3 AS SELECT f1 FROM t1; -CREATE USER u26813@localhost; -GRANT DROP ON db26813.v1 TO u26813@localhost; -GRANT CREATE VIEW ON db26813.v2 TO u26813@localhost; -GRANT DROP, CREATE VIEW ON db26813.v3 TO u26813@localhost; -GRANT SELECT ON db26813.t1 TO u26813@localhost; -ALTER VIEW v1 AS SELECT f2 FROM t1; -ERROR 42000: Access denied; you need the SUPER privilege for this operation -ALTER VIEW v2 AS SELECT f2 FROM t1; -ERROR 42000: Access denied; you need the SUPER privilege for this operation -ALTER VIEW v3 AS SELECT f2 FROM t1; -ERROR 42000: Access denied; you need the SUPER privilege for this operation -SHOW CREATE VIEW v3; -View Create View character_set_client collation_connection -v3 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v3` AS select `t1`.`f1` AS `f1` from `t1` latin1 latin1_swedish_ci -DROP USER u26813@localhost; -DROP DATABASE db26813; -# -# Bug#29908: A user can gain additional access through the ALTER VIEW. -# -CREATE DATABASE mysqltest_29908; -USE mysqltest_29908; -CREATE TABLE t1(f1 INT, f2 INT); -CREATE USER u29908_1@localhost; -CREATE DEFINER = u29908_1@localhost VIEW v1 AS SELECT f1 FROM t1; -CREATE DEFINER = u29908_1@localhost SQL SECURITY INVOKER VIEW v2 AS -SELECT f1 FROM t1; -GRANT DROP, CREATE VIEW, SHOW VIEW ON mysqltest_29908.v1 TO u29908_1@localhost; -GRANT DROP, CREATE VIEW, SHOW VIEW ON mysqltest_29908.v2 TO u29908_1@localhost; -GRANT SELECT ON mysqltest_29908.t1 TO u29908_1@localhost; -CREATE USER u29908_2@localhost; -GRANT DROP, CREATE VIEW ON mysqltest_29908.v1 TO u29908_2@localhost; -GRANT DROP, CREATE VIEW, SHOW VIEW ON mysqltest_29908.v2 TO u29908_2@localhost; -GRANT SELECT ON mysqltest_29908.t1 TO u29908_2@localhost; -ALTER VIEW v1 AS SELECT f2 FROM t1; -ERROR 42000: Access denied; you need the SUPER privilege for this operation -ALTER VIEW v2 AS SELECT f2 FROM t1; -ERROR 42000: Access denied; you need the SUPER privilege for this operation -SHOW CREATE VIEW v2; -View Create View character_set_client collation_connection -v2 CREATE ALGORITHM=UNDEFINED DEFINER=`u29908_1`@`localhost` SQL SECURITY INVOKER VIEW `v2` AS select `t1`.`f1` AS `f1` from `t1` latin1 latin1_swedish_ci -ALTER VIEW v1 AS SELECT f2 FROM t1; -SHOW CREATE VIEW v1; -View Create View character_set_client collation_connection -v1 CREATE ALGORITHM=UNDEFINED DEFINER=`u29908_1`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`f2` AS `f2` from `t1` latin1 latin1_swedish_ci -ALTER VIEW v2 AS SELECT f2 FROM t1; -SHOW CREATE VIEW v2; -View Create View character_set_client collation_connection -v2 CREATE ALGORITHM=UNDEFINED DEFINER=`u29908_1`@`localhost` SQL SECURITY INVOKER VIEW `v2` AS select `t1`.`f2` AS `f2` from `t1` latin1 latin1_swedish_ci -ALTER VIEW v1 AS SELECT f1 FROM t1; -SHOW CREATE VIEW v1; -View Create View character_set_client collation_connection -v1 CREATE ALGORITHM=UNDEFINED DEFINER=`u29908_1`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`f1` AS `f1` from `t1` latin1 latin1_swedish_ci -ALTER VIEW v2 AS SELECT f1 FROM t1; -SHOW CREATE VIEW v2; -View Create View character_set_client collation_connection -v2 CREATE ALGORITHM=UNDEFINED DEFINER=`u29908_1`@`localhost` SQL SECURITY INVOKER VIEW `v2` AS select `t1`.`f1` AS `f1` from `t1` latin1 latin1_swedish_ci -DROP USER u29908_1@localhost; -DROP USER u29908_2@localhost; -DROP DATABASE mysqltest_29908; -####################################################################### -DROP DATABASE IF EXISTS mysqltest1; -DROP DATABASE IF EXISTS mysqltest2; -CREATE DATABASE mysqltest1; -CREATE DATABASE mysqltest2; -CREATE TABLE mysqltest1.t1(c1 INT); -CREATE TABLE mysqltest1.t2(c2 INT); -CREATE TABLE mysqltest1.t3(c3 INT); -CREATE TABLE mysqltest1.t4(c4 INT); -INSERT INTO mysqltest1.t1 VALUES (11), (12), (13), (14); -INSERT INTO mysqltest1.t2 VALUES (21), (22), (23), (24); -INSERT INTO mysqltest1.t3 VALUES (31), (32), (33), (34); -INSERT INTO mysqltest1.t4 VALUES (41), (42), (43), (44); -GRANT SELECT ON mysqltest1.t1 TO mysqltest_u1@localhost; -GRANT INSERT ON mysqltest1.t2 TO mysqltest_u1@localhost; -GRANT SELECT, UPDATE ON mysqltest1.t3 TO mysqltest_u1@localhost; -GRANT SELECT, DELETE ON mysqltest1.t4 TO mysqltest_u1@localhost; -GRANT ALL PRIVILEGES ON mysqltest2.* TO mysqltest_u1@localhost; - ----> connection: bug24040_con -SELECT * FROM mysqltest1.t1; -c1 -11 -12 -13 -14 -INSERT INTO mysqltest1.t2 VALUES(25); -UPDATE mysqltest1.t3 SET c3 = 331 WHERE c3 = 31; -DELETE FROM mysqltest1.t4 WHERE c4 = 44; -CREATE VIEW v1 AS SELECT * FROM mysqltest1.t1; -CREATE VIEW v2 AS SELECT * FROM mysqltest1.t2; -CREATE VIEW v3 AS SELECT * FROM mysqltest1.t3; -CREATE VIEW v4 AS SELECT * FROM mysqltest1.t4; -SELECT * FROM v1; -c1 -11 -12 -13 -14 -INSERT INTO v2 VALUES(26); -UPDATE v3 SET c3 = 332 WHERE c3 = 32; -DELETE FROM v4 WHERE c4 = 43; -CREATE VIEW v12 AS SELECT c1, c2 FROM mysqltest1.t1, mysqltest1.t2; -ERROR 42000: create view command denied to user 'mysqltest_u1'@'localhost' for column 'c2' in table 'v12' -CREATE VIEW v13 AS SELECT c1, c3 FROM mysqltest1.t1, mysqltest1.t3; -CREATE VIEW v14 AS SELECT c1, c4 FROM mysqltest1.t1, mysqltest1.t4; -CREATE VIEW v21 AS SELECT c2, c1 FROM mysqltest1.t2, mysqltest1.t1; -ERROR 42000: create view command denied to user 'mysqltest_u1'@'localhost' for column 'c1' in table 'v21' -CREATE VIEW v23 AS SELECT c2, c3 FROM mysqltest1.t2, mysqltest1.t3; -ERROR 42000: create view command denied to user 'mysqltest_u1'@'localhost' for column 'c3' in table 'v23' -CREATE VIEW v24 AS SELECT c2, c4 FROM mysqltest1.t2, mysqltest1.t4; -ERROR 42000: create view command denied to user 'mysqltest_u1'@'localhost' for column 'c4' in table 'v24' -CREATE VIEW v31 AS SELECT c3, c1 FROM mysqltest1.t3, mysqltest1.t1; -CREATE VIEW v32 AS SELECT c3, c2 FROM mysqltest1.t3, mysqltest1.t2; -ERROR 42000: create view command denied to user 'mysqltest_u1'@'localhost' for column 'c2' in table 'v32' -CREATE VIEW v34 AS SELECT c3, c4 FROM mysqltest1.t3, mysqltest1.t4; -CREATE VIEW v41 AS SELECT c4, c1 FROM mysqltest1.t4, mysqltest1.t1; -CREATE VIEW v42 AS SELECT c4, c2 FROM mysqltest1.t4, mysqltest1.t2; -ERROR 42000: create view command denied to user 'mysqltest_u1'@'localhost' for column 'c2' in table 'v42' -CREATE VIEW v43 AS SELECT c4, c3 FROM mysqltest1.t4, mysqltest1.t3; - ----> connection: default -SELECT * FROM mysqltest1.t1; -c1 -11 -12 -13 -14 -SELECT * FROM mysqltest1.t2; -c2 -21 -22 -23 -24 -25 -26 -SELECT * FROM mysqltest1.t3 order by c3; -c3 -33 -34 -331 -332 -SELECT * FROM mysqltest1.t4; -c4 -41 -42 -DROP DATABASE mysqltest1; -DROP DATABASE mysqltest2; -DROP USER mysqltest_u1@localhost; -End of 5.0 tests. -DROP VIEW IF EXISTS v1; -DROP TABLE IF EXISTS t1; -CREATE TABLE t1 (i INT); -CREATE VIEW v1 AS SELECT * FROM t1; -ALTER VIEW v1 AS SELECT * FROM t1; -SHOW CREATE VIEW v1; -View Create View character_set_client collation_connection -v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`i` AS `i` from `t1` latin1 latin1_swedish_ci -ALTER DEFINER=no_such@user_1 VIEW v1 AS SELECT * FROM t1; -Warnings: -Note 1449 The user specified as a definer ('no_such'@'user_1') does not exist -SHOW CREATE VIEW v1; -View Create View character_set_client collation_connection -v1 CREATE ALGORITHM=UNDEFINED DEFINER=`no_such`@`user_1` SQL SECURITY DEFINER VIEW `v1` AS select `test`.`t1`.`i` AS `i` from `t1` latin1 latin1_swedish_ci -Warnings: -Note 1449 The user specified as a definer ('no_such'@'user_1') does not exist -ALTER ALGORITHM=MERGE VIEW v1 AS SELECT * FROM t1; -Warnings: -Note 1449 The user specified as a definer ('no_such'@'user_1') does not exist -SHOW CREATE VIEW v1; -View Create View character_set_client collation_connection -v1 CREATE ALGORITHM=MERGE DEFINER=`no_such`@`user_1` SQL SECURITY DEFINER VIEW `v1` AS select `test`.`t1`.`i` AS `i` from `t1` latin1 latin1_swedish_ci -Warnings: -Note 1449 The user specified as a definer ('no_such'@'user_1') does not exist -ALTER ALGORITHM=TEMPTABLE DEFINER=no_such@user_2 VIEW v1 AS SELECT * FROM t1; -Warnings: -Note 1449 The user specified as a definer ('no_such'@'user_2') does not exist -SHOW CREATE VIEW v1; -View Create View character_set_client collation_connection -v1 CREATE ALGORITHM=TEMPTABLE DEFINER=`no_such`@`user_2` SQL SECURITY DEFINER VIEW `v1` AS select `test`.`t1`.`i` AS `i` from `t1` latin1 latin1_swedish_ci -Warnings: -Note 1449 The user specified as a definer ('no_such'@'user_2') does not exist -DROP VIEW v1; -DROP TABLE t1; -End of 5.1 tests. diff --git a/mysql-test/suite/pbxt/t/endspace.test b/mysql-test/suite/pbxt/t/endspace.test index f2dcc1225a4..a2962544a43 100644 --- a/mysql-test/suite/pbxt/t/endspace.test +++ b/mysql-test/suite/pbxt/t/endspace.test @@ -16,7 +16,8 @@ drop table if exists t1; create table t1 (text1 varchar(32) not NULL, KEY key1 (text1)); insert into t1 values ('teststring'), ('nothing'), ('teststring\t'); check table t1; -select * from t1 ignore key (key1) where text1='teststring' or text1 like 'teststring_%'; +select * from t1 ignore key (key1) where text1='teststring' or + text1 like 'teststring_%' ORDER BY text1; select * from t1 where text1='teststring' or text1 like 'teststring_%'; select * from t1 where text1='teststring' or text1 > 'teststring\t'; select * from t1 order by text1; @@ -24,7 +25,8 @@ explain select * from t1 order by text1; alter table t1 modify text1 char(32) binary not null; check table t1; -select * from t1 ignore key (key1) where text1='teststring' or text1 like 'teststring_%'; +select * from t1 ignore key (key1) where text1='teststring' or + text1 like 'teststring_%' ORDER BY text1; select concat('|', text1, '|') from t1 where text1='teststring' or text1 like 'teststring_%'; select concat('|', text1, '|') from t1 where text1='teststring' or text1 > 'teststring\t'; select text1, length(text1) from t1 order by text1; @@ -57,7 +59,8 @@ drop table t1; create table t1 (text1 varchar(32) not NULL, KEY key1 using BTREE (text1)) engine=heap; insert into t1 values ('teststring'), ('nothing'), ('teststring\t'); -select * from t1 ignore key (key1) where text1='teststring' or text1 like 'teststring_%'; +select * from t1 ignore key (key1) where text1='teststring' or + text1 like 'teststring_%' ORDER BY text1; select * from t1 where text1='teststring' or text1 like 'teststring_%'; select * from t1 where text1='teststring' or text1 >= 'teststring\t'; select * from t1 order by text1; @@ -90,12 +93,13 @@ alter table t1 modify text1 text not null, pack_keys=1; select * from t1 where text1 like 'teststring_%'; # The following gives wrong result in InnoDB +--sorted_result select text1, length(text1) from t1 where text1='teststring' or text1 like 'teststring_%'; +--sorted_result select text1, length(text1) from t1 where text1='teststring' or text1 >= 'teststring\t'; select concat('|', text1, '|') from t1 order by text1; drop table t1; - --disable_query_log drop database pbxt; --enable_query_log diff --git a/mysql-test/suite/pbxt/t/heap.test b/mysql-test/suite/pbxt/t/heap.test deleted file mode 100644 index 2d863827b2b..00000000000 --- a/mysql-test/suite/pbxt/t/heap.test +++ /dev/null @@ -1,476 +0,0 @@ -# -# Test of heap tables. -# - ---disable_warnings -drop table if exists t1,t2,t3; ---enable_warnings - -create table t1 (a int not null,b int not null, primary key (a)) engine=heap comment="testing heaps" avg_row_length=100 min_rows=1 max_rows=100; -insert into t1 values(1,1),(2,2),(3,3),(4,4); -delete from t1 where a=1 or a=0; -#show table status like "t1"; -show keys from t1; -select * from t1; -select * from t1 where a=4; -update t1 set b=5 where a=4; -update t1 set b=b+1 where a>=3; -replace t1 values (3,3); -select * from t1; -alter table t1 add c int not null, add key (c,a); -drop table t1; - -create table t1 (a int not null,b int not null, primary key (a)) engine=memory comment="testing heaps"; -insert into t1 values(1,1),(2,2),(3,3),(4,4); -delete from t1 where a > 0; -select * from t1; -drop table t1; - -create table t1 (a int not null,b int not null, primary key (a)) engine=heap comment="testing heaps"; -insert into t1 values(1,1),(2,2),(3,3),(4,4); -alter table t1 modify a int not null auto_increment, engine=myisam, comment="new myisam table"; -#show table status like "t1"; -select * from t1; -drop table t1; - -create table t1 (a int not null) engine=heap; -insert into t1 values (869751),(736494),(226312),(802616),(728912); -select * from t1 where a > 736494; -alter table t1 add unique uniq_id(a); -select * from t1 where a > 736494; -select * from t1 where a = 736494; -select * from t1 where a=869751 or a=736494; -select * from t1 where a in (869751,736494,226312,802616); -alter table t1 engine=myisam; -explain select * from t1 where a in (869751,736494,226312,802616); -drop table t1; - -create table t1 (x int not null, y int not null, key x (x), unique y (y)) -engine=heap; -insert into t1 values (1,1),(2,2),(1,3),(2,4),(2,5),(2,6); -select * from t1 where x=1; -select * from t1,t1 as t2 where t1.x=t2.y; -explain select * from t1,t1 as t2 where t1.x=t2.y; -drop table t1; - -create table t1 (a int) engine=heap; -insert into t1 values(1); -select max(a) from t1; -drop table t1; - -CREATE TABLE t1 ( a int not null default 0, b int not null default 0, key(a), key(b) ) ENGINE=HEAP; -insert into t1 values(1,1),(1,2),(2,3),(1,3),(1,4),(1,5),(1,6); -select * from t1 where a=1; -insert into t1 values(1,1),(1,2),(2,3),(1,3),(1,4),(1,5),(1,6); -select * from t1 where a=1; -drop table t1; - -create table t1 (id int unsigned not null, primary key (id)) engine=HEAP; -insert into t1 values(1); -select max(id) from t1; -insert into t1 values(2); -select max(id) from t1; -replace into t1 values(1); -drop table t1; - -create table t1 (n int) engine=heap; -drop table t1; - -create table t1 (n int) engine=heap; -drop table if exists t1; - -# Test of non unique index - -CREATE table t1(f1 int not null,f2 char(20) not -null,index(f2)) engine=heap; -INSERT into t1 set f1=12,f2="bill"; -INSERT into t1 set f1=13,f2="bill"; -INSERT into t1 set f1=14,f2="bill"; -INSERT into t1 set f1=15,f2="bill"; -INSERT into t1 set f1=16,f2="ted"; -INSERT into t1 set f1=12,f2="ted"; -INSERT into t1 set f1=12,f2="ted"; -INSERT into t1 set f1=12,f2="ted"; -INSERT into t1 set f1=12,f2="ted"; -delete from t1 where f2="bill"; -select * from t1; -drop table t1; - -# -# Test when using part key searches -# - -create table t1 (btn char(10) not null, key(btn)) engine=heap; -insert into t1 values ("hello"),("hello"),("hello"),("hello"),("hello"),("a"),("b"),("c"),("d"),("e"),("f"),("g"),("h"),("i"); -explain select * from t1 where btn like "q%"; -select * from t1 where btn like "q%"; -alter table t1 add column new_col char(1) not null, add key (btn,new_col), drop key btn; -update t1 set new_col=left(btn,1); -explain select * from t1 where btn="a"; -explain select * from t1 where btn="a" and new_col="a"; -drop table t1; - -# -# Test of NULL keys -# - -CREATE TABLE t1 ( - a int default NULL, - b int default NULL, - KEY a (a), - UNIQUE b (b) -) engine=heap; -INSERT INTO t1 VALUES (NULL,99),(99,NULL),(1,1),(2,2),(1,3); -SELECT * FROM t1 WHERE a=NULL; -explain SELECT * FROM t1 WHERE a IS NULL; -SELECT * FROM t1 WHERE a<=>NULL; -SELECT * FROM t1 WHERE b=NULL; -explain SELECT * FROM t1 WHERE b IS NULL; -SELECT * FROM t1 WHERE b<=>NULL; - ---error ER_DUP_ENTRY -INSERT INTO t1 VALUES (1,3); -DROP TABLE t1; - -CREATE TABLE t1 ( - a int default NULL, - key a (a) -) ENGINE=HEAP; -INSERT INTO t1 VALUES (10), (10), (10); -EXPLAIN SELECT * FROM t1 WHERE a=10; -SELECT * FROM t1 WHERE a=10; -DROP TABLE t1; - -# -# Test when deleting all rows -# - -CREATE TABLE t1 (a int not null, primary key(a)) engine=heap; -INSERT into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11); -DELETE from t1 where a < 100; -SELECT * from t1; -DROP TABLE t1; - -# -# Bug#4411 Server hangs when trying to SELECT MAX(id) from an empty HEAP table -# -CREATE TABLE `job_titles` ( - `job_title_id` int(6) unsigned NOT NULL default '0', - `job_title` char(18) NOT NULL default '', - PRIMARY KEY (`job_title_id`), - UNIQUE KEY `job_title_id` (`job_title_id`,`job_title`) -) ENGINE=HEAP; - -SELECT MAX(job_title_id) FROM job_titles; - -DROP TABLE job_titles; - -# -# Test of delete with NOT NULL -# (Bug #6082) -# - -CREATE TABLE t1 (a INT NOT NULL, B INT, KEY(B)) ENGINE=HEAP; -INSERT INTO t1 VALUES(1,1), (1,NULL); -SELECT * FROM t1 WHERE B is not null; -DROP TABLE t1; - -# -# Bug #6748 -# heap_rfirst() doesn't work (and never did!) -# -CREATE TABLE t1 (pseudo char(35) PRIMARY KEY, date int(10) unsigned NOT NULL) ENGINE=HEAP; -INSERT INTO t1 VALUES ('massecot',1101106491),('altec',1101106492),('stitch+',1101106304),('Seb Corgan',1101106305),('beerfilou',1101106263),('flaker',1101106529),('joce8',5),('M4vrick',1101106418),('gabay008',1101106525),('Vamp irX',1101106291),('ZoomZip',1101106546),('rip666',1101106502),('CBP ',1101106397),('guezpard',1101106496); -DELETE FROM t1 WHERE date<1101106546; -SELECT * FROM t1; -DROP TABLE t1; - -# -# Bug #6878: a problem with small length records -# - -create table t1(a char(2)) engine=memory; -insert into t1 values (NULL), (NULL); -delete from t1 where a is null; -insert into t1 values ('2'), ('3'); -select * from t1; -drop table t1; - -# -# Test varchar -# We can't use varchar.inc becasue heap doesn't support blob's -# - -let $default=`select @@storage_engine`; -set storage_engine=HEAP; - -# -# Simple basic test that endspace is saved -# - -create table t1 (v varchar(10), c char(10), t varchar(50)); -insert into t1 values('+ ', '+ ', '+ '); -set @a=repeat(' ',20); -insert into t1 values (concat('+',@a),concat('+',@a),concat('+',@a)); -select concat('*',v,'*',c,'*',t,'*') from t1; - -# Check how columns are copied -show create table t1; -create table t2 like t1; -show create table t2; -create table t3 select * from t1; -show create table t3; -alter table t1 modify c varchar(10); -show create table t1; -alter table t1 modify v char(10); -show create table t1; -alter table t1 modify t varchar(10); -show create table t1; -select concat('*',v,'*',c,'*',t,'*') from t1; -drop table t1,t2,t3; - -# -# Testing of keys -# -create table t1 (v varchar(10), c char(10), t varchar(50), key(v), key(c), key(t(10))); -show create table t1; -disable_query_log; -let $1=10; -while ($1) -{ - let $2=27; - eval set @space=repeat(' ',10-$1); - while ($2) - { - eval set @char=char(ascii('a')+$2-1); - insert into t1 values(concat(@char,@space),concat(@char,@space),concat(@char,@space)); - dec $2; - } - dec $1; -} -enable_query_log; -select count(*) from t1; -insert into t1 values(concat('a',char(1)),concat('a',char(1)),concat('a',char(1))); -select count(*) from t1 where v='a'; -select count(*) from t1 where c='a'; -select count(*) from t1 where t='a'; -select count(*) from t1 where v='a '; -select count(*) from t1 where c='a '; -select count(*) from t1 where t='a '; -select count(*) from t1 where v between 'a' and 'a '; -select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n'; -select count(*) from t1 where v like 'a%'; -select count(*) from t1 where c like 'a%'; -select count(*) from t1 where t like 'a%'; -select count(*) from t1 where v like 'a %'; -explain select count(*) from t1 where v='a '; -explain select count(*) from t1 where c='a '; -explain select count(*) from t1 where t='a '; -explain select count(*) from t1 where v like 'a%'; -explain select count(*) from t1 where v between 'a' and 'a '; -explain select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n'; - ---error ER_DUP_ENTRY -alter table t1 add unique(v); -select concat('*',v,'*',c,'*',t,'*') as qq from t1 where v='a' order by length(concat('*',v,'*',c,'*',t,'*')); -explain select * from t1 where v='a'; - -# GROUP BY - -select v,count(*) from t1 group by v limit 10; -select v,count(t) from t1 group by v limit 10; -select v,count(c) from t1 group by v limit 10; -select sql_big_result trim(v),count(t) from t1 group by v limit 10; -select sql_big_result trim(v),count(c) from t1 group by v limit 10; -select c,count(*) from t1 group by c limit 10; -select c,count(t) from t1 group by c limit 10; -select sql_big_result c,count(t) from t1 group by c limit 10; -select t,count(*) from t1 group by t limit 10; -select t,count(t) from t1 group by t limit 10; -select sql_big_result trim(t),count(t) from t1 group by t limit 10; -drop table t1; - -# -# Test unique keys -# - -create table t1 (a char(10), unique (a)); -insert into t1 values ('a'); ---error ER_DUP_ENTRY -insert into t1 values ('a '); - -alter table t1 modify a varchar(10); ---error ER_DUP_ENTRY -insert into t1 values ('a '),('a '),('a '),('a '); ---error ER_DUP_ENTRY -insert into t1 values ('a '); ---error ER_DUP_ENTRY -insert into t1 values ('a '); ---error ER_DUP_ENTRY -insert into t1 values ('a '); -update t1 set a='a ' where a like 'a '; -update t1 set a='a ' where a like 'a '; -drop table t1; - -# -# Testing of btree keys -# - -create table t1 (v varchar(10), c char(10), t varchar(50), key using btree (v), key using btree (c), key using btree (t(10))); -show create table t1; -disable_query_log; -let $1=10; -while ($1) -{ - let $2=27; - eval set @space=repeat(' ',10-$1); - while ($2) - { - eval set @char=char(ascii('a')+$2-1); - insert into t1 values(concat(@char,@space),concat(@char,@space),concat(@char,@space)); - dec $2; - } - dec $1; -} -enable_query_log; -select count(*) from t1; -insert into t1 values(concat('a',char(1)),concat('a',char(1)),concat('a',char(1))); -select count(*) from t1 where v='a'; -select count(*) from t1 where c='a'; -select count(*) from t1 where t='a'; -select count(*) from t1 where v='a '; -select count(*) from t1 where c='a '; -select count(*) from t1 where t='a '; -select count(*) from t1 where v between 'a' and 'a '; ---replace_column 9 # -select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n'; ---replace_column 9 # -explain select count(*) from t1 where v='a '; ---replace_column 9 # -explain select count(*) from t1 where c='a '; ---replace_column 9 # -explain select count(*) from t1 where t='a '; ---replace_column 9 # -explain select count(*) from t1 where v like 'a%'; ---replace_column 9 # -explain select count(*) from t1 where v between 'a' and 'a '; ---replace_column 9 # -explain select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n'; - ---error ER_DUP_ENTRY -alter table t1 add unique(v); -select concat('*',v,'*',c,'*',t,'*') as qq from t1 where v='a' order by length(concat('*',v,'*',c,'*',t,'*')); -# Number of rows is not constant for b-trees keys ---replace_column 9 # -explain select * from t1 where v='a'; - -drop table t1; - -# -# Test unique btree keys -# - -create table t1 (a char(10), unique using btree (a)) engine=heap; -insert into t1 values ('a'); ---error ER_DUP_ENTRY -insert into t1 values ('a '); - -alter table t1 modify a varchar(10); ---error ER_DUP_ENTRY -insert into t1 values ('a '),('a '),('a '),('a '); ---error ER_DUP_ENTRY -insert into t1 values ('a '); ---error ER_DUP_ENTRY -insert into t1 values ('a '); ---error ER_DUP_ENTRY -insert into t1 values ('a '); -update t1 set a='a ' where a like 'a '; -update t1 set a='a ' where a like 'a '; -drop table t1; - -# -# test show create table -# - -create table t1 (v varchar(10), c char(10), t varchar(50), key(v(5)), key(c(5)), key(t(5))); -show create table t1; -drop table t1; - -create table t1 (v varchar(65530), key(v(10))); -show create table t1; -insert into t1 values(repeat('a',65530)); -select length(v) from t1 where v=repeat('a',65530); -drop table t1; - -# -# Reset varchar test -# -eval set storage_engine=$default; - -# -# Bug #8489: Strange auto_increment behaviour -# - -create table t1 (a bigint unsigned auto_increment primary key, b int, - key (b, a)) engine=heap; -insert t1 (b) values (1),(1),(1),(1),(1),(1),(1),(1); -select * from t1; -drop table t1; - -create table t1 (a int not null, b int not null auto_increment, - primary key(a, b), key(b)) engine=heap; -insert t1 (a) values (1),(1),(1),(1),(1),(1),(1),(1); -select * from t1; -drop table t1; - ---error 1075 -create table t1 (a int not null, b int not null auto_increment, - primary key(a, b)) engine=heap; - -# -# Bug #10566: Verify that we can create a prefixed key with length > 255 -# -create table t1 (c char(255), primary key(c(90))); -insert into t1 values ("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); ---error ER_DUP_ENTRY -insert into t1 values ("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); -drop table t1; - -# -# Bug 12796: Record doesn't show when selecting through index -# -CREATE TABLE t1 (a int, key(a)) engine=heap; -insert into t1 values (0); -delete from t1; -select * from t1; -insert into t1 values (0), (1); -select * from t1 where a = 0; -drop table t1; - -# End of 4.1 tests - -# -# Bug #3094: Row format of memory tables should always be reported as Fixed -# -create table t1 (c char(10)) engine=memory; -create table t2 (c varchar(10)) engine=memory; ---replace_column 8 # -show table status like 't_'; -drop table t1, t2; - -# -# BUG#18233 - Memory tables INDEX USING HASH (a,b) returns 1 row on -# SELECT WHERE a= AND b= -# -CREATE TABLE t1(a VARCHAR(1), b VARCHAR(2), c VARCHAR(256), - KEY(a), KEY(b), KEY(c)) ENGINE=MEMORY; -INSERT INTO t1 VALUES('a','aa',REPEAT('a', 256)),('a','aa',REPEAT('a',256)); -SELECT COUNT(*) FROM t1 WHERE a='a'; -SELECT COUNT(*) FROM t1 WHERE b='aa'; -SELECT COUNT(*) FROM t1 WHERE c=REPEAT('a',256); -DROP TABLE t1; - ---disable_query_log -drop database pbxt; ---enable_query_log -# End of 5.0 tests diff --git a/mysql-test/suite/pbxt/t/view_grant.test b/mysql-test/suite/pbxt/t/view_grant.test deleted file mode 100644 index 6a105da61f8..00000000000 --- a/mysql-test/suite/pbxt/t/view_grant.test +++ /dev/null @@ -1,1224 +0,0 @@ -# Can't test with embedded server --- source include/not_embedded.inc - ---disable_warnings -drop database if exists mysqltest; -drop view if exists v1,v2,v3; ---enable_warnings - - -# simple test of grants -grant create view on test.* to test@localhost; -show grants for test@localhost; -revoke create view on test.* from test@localhost; -show grants for test@localhost; -# The grant above creates a new user test@localhost, delete it -drop user test@localhost; - -# grant create view test -# -connect (root,localhost,root,,test); -connection root; ---disable_warnings -create database mysqltest; ---enable_warnings - -create table mysqltest.t1 (a int, b int); -create table mysqltest.t2 (a int, b int); - -grant select on mysqltest.t1 to mysqltest_1@localhost; -grant create view,select on test.* to mysqltest_1@localhost; - -connect (user1,localhost,mysqltest_1,,test); -connection user1; - --- error ER_SPECIFIC_ACCESS_DENIED_ERROR -create definer=root@localhost view v1 as select * from mysqltest.t1; -create view v1 as select * from mysqltest.t1; -# try to modify view without DROP privilege on it --- error 1142 -alter view v1 as select * from mysqltest.t1; --- error 1142 -create or replace view v1 as select * from mysqltest.t1; -# no CRETE VIEW privilege --- error 1142 -create view mysqltest.v2 as select * from mysqltest.t1; -# no SELECT privilege --- error 1142 -create view v2 as select * from mysqltest.t2; - -connection root; -# check view definer information -show create view v1; - -grant create view,drop,select on test.* to mysqltest_1@localhost; - -connection user1; -# following 'use' command is workaround of bug #9582 and should be removed -# when that bug will be fixed -use test; -alter view v1 as select * from mysqltest.t1; -create or replace view v1 as select * from mysqltest.t1; - -connection root; -revoke all privileges on mysqltest.t1 from mysqltest_1@localhost; -revoke all privileges on test.* from mysqltest_1@localhost; - -drop database mysqltest; -drop view test.v1; - -# -# grants per columns -# -# MERGE algorithm ---disable_warnings -create database mysqltest; ---enable_warnings - -create table mysqltest.t1 (a int, b int); -create view mysqltest.v1 (c,d) as select a+1,b+1 from mysqltest.t1; -grant select (c) on mysqltest.v1 to mysqltest_1@localhost; - -connection user1; -select c from mysqltest.v1; -# there are no privileges on column 'd' --- error 1143 -select d from mysqltest.v1; - -connection root; -revoke all privileges on mysqltest.v1 from mysqltest_1@localhost; -delete from mysql.user where user='mysqltest_1'; -drop database mysqltest; - -# TEMPORARY TABLE algorithm ---disable_warnings -create database mysqltest; ---enable_warnings - -create table mysqltest.t1 (a int, b int); -create algorithm=temptable view mysqltest.v1 (c,d) as select a+1,b+1 from mysqltest.t1; -grant select (c) on mysqltest.v1 to mysqltest_1@localhost; - -connection user1; -select c from mysqltest.v1; -# there are no privileges on column 'd' --- error 1143 -select d from mysqltest.v1; - -connection root; -revoke all privileges on mysqltest.v1 from mysqltest_1@localhost; -delete from mysql.user where user='mysqltest_1'; -drop database mysqltest; - -# -# EXPLAIN rights -# -connection root; ---disable_warnings -create database mysqltest; ---enable_warnings -#prepare views and tables -create table mysqltest.t1 (a int, b int); -create table mysqltest.t2 (a int, b int); -create view mysqltest.v1 (c,d) as select a+1,b+1 from mysqltest.t1; -create algorithm=temptable view mysqltest.v2 (c,d) as select a+1,b+1 from mysqltest.t1; -create view mysqltest.v3 (c,d) as select a+1,b+1 from mysqltest.t2; -create algorithm=temptable view mysqltest.v4 (c,d) as select a+1,b+1 from mysqltest.t2; -grant select on mysqltest.v1 to mysqltest_1@localhost; -grant select on mysqltest.v2 to mysqltest_1@localhost; -grant select on mysqltest.v3 to mysqltest_1@localhost; -grant select on mysqltest.v4 to mysqltest_1@localhost; - -connection user1; -# all selects works -select c from mysqltest.v1; -select c from mysqltest.v2; -select c from mysqltest.v3; -select c from mysqltest.v4; -# test of show coluns -show columns from mysqltest.v1; -show columns from mysqltest.v2; -# but explain/show do not --- error 1345 -explain select c from mysqltest.v1; --- error 1142 -show create view mysqltest.v1; --- error 1345 -explain select c from mysqltest.v2; --- error 1142 -show create view mysqltest.v2; --- error 1345 -explain select c from mysqltest.v3; --- error 1142 -show create view mysqltest.v3; --- error 1345 -explain select c from mysqltest.v4; --- error 1142 -show create view mysqltest.v4; - -# allow to see one of underlying table -connection root; -grant select on mysqltest.t1 to mysqltest_1@localhost; -connection user1; -# EXPLAIN of view on above table works -explain select c from mysqltest.v1; --- error 1142 -show create view mysqltest.v1; -explain select c from mysqltest.v2; --- error 1142 -show create view mysqltest.v2; -# but other EXPLAINs do not --- error 1345 -explain select c from mysqltest.v3; --- error 1142 -show create view mysqltest.v3; --- error 1345 -explain select c from mysqltest.v4; --- error 1142 -show create view mysqltest.v4; - -# allow to see any view in mysqltest database -connection root; -grant show view on mysqltest.* to mysqltest_1@localhost; -connection user1; -explain select c from mysqltest.v1; -show create view mysqltest.v1; -explain select c from mysqltest.v2; -show create view mysqltest.v2; -explain select c from mysqltest.v3; -show create view mysqltest.v3; -explain select c from mysqltest.v4; -show create view mysqltest.v4; - -connection root; -revoke all privileges on mysqltest.* from mysqltest_1@localhost; -delete from mysql.user where user='mysqltest_1'; -drop database mysqltest; - -# -# UPDATE privileges on VIEW columns and whole VIEW -# -connection root; ---disable_warnings -create database mysqltest; ---enable_warnings - -create table mysqltest.t1 (a int, b int, primary key(a)); -insert into mysqltest.t1 values (10,2), (20,3), (30,4), (40,5), (50,10); -create table mysqltest.t2 (x int); -insert into mysqltest.t2 values (3), (4), (5), (6); -create view mysqltest.v1 (a,c) as select a, b+1 from mysqltest.t1; -create view mysqltest.v2 (a,c) as select a, b from mysqltest.t1; -create view mysqltest.v3 (a,c) as select a, b+1 from mysqltest.t1; - -grant update (a) on mysqltest.v2 to mysqltest_1@localhost; -grant update on mysqltest.v1 to mysqltest_1@localhost; -grant select on mysqltest.* to mysqltest_1@localhost; - -connection user1; -use mysqltest; -# update with rights on VIEW column -update t2,v1 set v1.a=v1.a+v1.c where t2.x=v1.c; -select * from t1 order by a; # PBXT : required for order -update v1 set a=a+c; -select * from t1 order by a; # PBXT : required for order -# update with rights on whole VIEW -update t2,v2 set v2.a=v2.a+v2.c where t2.x=v2.c; -select * from t1 order by a; # PBXT : required for order -update v2 set a=a+c; -select * from t1 order by a; # PBXT : required for order -# no rights on column --- error 1143 -update t2,v2 set v2.c=v2.a+v2.c where t2.x=v2.c; --- error 1143 -update v2 set c=a+c; -# no rights for view --- error 1142 -update t2,v3 set v3.a=v3.a+v3.c where t2.x=v3.c; --- error 1142 -update v3 set a=a+c; - -use test; -connection root; -REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost; -drop database mysqltest; - -# -# DELETE privileges on VIEW -# -connection root; ---disable_warnings -create database mysqltest; ---enable_warnings - -create table mysqltest.t1 (a int, b int, primary key(a)); -insert into mysqltest.t1 values (1,2), (2,3), (3,4), (4,5), (5,10); -create table mysqltest.t2 (x int); -insert into mysqltest.t2 values (3), (4), (5), (6); -create view mysqltest.v1 (a,c) as select a, b+1 from mysqltest.t1; -create view mysqltest.v2 (a,c) as select a, b+1 from mysqltest.t1; - -grant delete on mysqltest.v1 to mysqltest_1@localhost; -grant select on mysqltest.* to mysqltest_1@localhost; - -connection user1; -use mysqltest; -# update with rights on VIEW column -delete from v1 where c < 4; -select * from t1; -delete v1 from t2,v1 where t2.x=v1.c; -select * from t1; -# no rights for view --- error 1142 -delete v2 from t2,v2 where t2.x=v2.c; --- error 1142 -delete from v2 where c < 4; - -use test; -connection root; -REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost; -drop database mysqltest; - -# -# insert privileges on VIEW -# -connection root; ---disable_warnings -create database mysqltest; ---enable_warnings - -create table mysqltest.t1 (a int, b int, primary key(a)); -insert into mysqltest.t1 values (1,2), (2,3); -create table mysqltest.t2 (x int, y int); -insert into mysqltest.t2 values (3,4); -create view mysqltest.v1 (a,c) as select a, b from mysqltest.t1; -create view mysqltest.v2 (a,c) as select a, b from mysqltest.t1; - -grant insert on mysqltest.v1 to mysqltest_1@localhost; -grant select on mysqltest.* to mysqltest_1@localhost; - -connection user1; -use mysqltest; -# update with rights on VIEW column -insert into v1 values (5,6); -select * from t1; -insert into v1 select x,y from t2; -select * from t1; -# no rights for view --- error 1142 -insert into v2 values (5,6); --- error 1142 -insert into v2 select x,y from t2; - -use test; -connection root; -REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost; -drop database mysqltest; - -# -# test of CREATE VIEW privileges if we have limited privileges -# -connection root; ---disable_warnings -create database mysqltest; ---enable_warnings - -create table mysqltest.t1 (a int, b int); -create table mysqltest.t2 (a int, b int); - -grant update on mysqltest.t1 to mysqltest_1@localhost; -grant update(b) on mysqltest.t2 to mysqltest_1@localhost; -grant create view,update on test.* to mysqltest_1@localhost; - -connection user1; - -create view v1 as select * from mysqltest.t1; -create view v2 as select b from mysqltest.t2; -# There are not rights on mysqltest.v1 --- error 1142 -create view mysqltest.v1 as select * from mysqltest.t1; -# There are not any rights on mysqltest.t2.a --- error 1143 -create view v3 as select a from mysqltest.t2; - -# give CREATE VIEW privileges (without any privileges for result column) -connection root; -create table mysqltest.v3 (b int); -grant create view on mysqltest.v3 to mysqltest_1@localhost; -drop table mysqltest.v3; -connection user1; -create view mysqltest.v3 as select b from mysqltest.t2; - -# give UPDATE privileges -connection root; -grant create view, update on mysqltest.v3 to mysqltest_1@localhost; -drop view mysqltest.v3; -connection user1; -create view mysqltest.v3 as select b from mysqltest.t2; - - -# Expression need select privileges --- error 1143 -create view v4 as select b+1 from mysqltest.t2; - -connection root; -grant create view,update,select on test.* to mysqltest_1@localhost; -connection user1; --- error 1143 -create view v4 as select b+1 from mysqltest.t2; - -connection root; -grant update,select(b) on mysqltest.t2 to mysqltest_1@localhost; -connection user1; -create view v4 as select b+1 from mysqltest.t2; - -connection root; -REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost; -drop database mysqltest; -drop view v1,v2,v4; - -# -# user with global DB privileges -# -connection root; ---disable_warnings -create database mysqltest; ---enable_warnings -create table mysqltest.t1 (a int); -grant all privileges on mysqltest.* to mysqltest_1@localhost; - -connection user1; -use mysqltest; -create view v1 as select * from t1; -use test; - -connection root; -revoke all privileges on mysqltest.* from mysqltest_1@localhost; -drop database mysqltest; - -# -# view definer grants revoking -# -connection root; ---disable_warnings -create database mysqltest; ---enable_warnings - -create table mysqltest.t1 (a int, b int); - -grant select on mysqltest.t1 to mysqltest_1@localhost; -grant create view,select on test.* to mysqltest_1@localhost; - -connection user1; - -create view v1 as select * from mysqltest.t1; - -connection root; -# check view definer information -show create view v1; -revoke select on mysqltest.t1 from mysqltest_1@localhost; --- error ER_VIEW_INVALID -select * from v1; -grant select on mysqltest.t1 to mysqltest_1@localhost; -select * from v1; -REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost; -drop view v1; -drop database mysqltest; - -# -# rights on execution of view underlying functiond (BUG#9505) -# -connection root; ---disable_warnings -create database mysqltest; ---enable_warnings - -use mysqltest; -create table t1 (a int); -insert into t1 values (1); -create table t2 (s1 int); ---disable_warnings -drop function if exists f2; ---enable_warnings -delimiter //; -create function f2 () returns int begin declare v int; select s1 from t2 -into v; return v; end// -delimiter ;// -create algorithm=TEMPTABLE view v1 as select f2() from t1; -create algorithm=MERGE view v2 as select f2() from t1; -create algorithm=TEMPTABLE SQL SECURITY INVOKER view v3 as select f2() from t1; -create algorithm=MERGE SQL SECURITY INVOKER view v4 as select f2() from t1; -create SQL SECURITY INVOKER view v5 as select * from v4; -grant select on v1 to mysqltest_1@localhost; -grant select on v2 to mysqltest_1@localhost; -grant select on v3 to mysqltest_1@localhost; -grant select on v4 to mysqltest_1@localhost; -grant select on v5 to mysqltest_1@localhost; - -connection user1; -use mysqltest; -select * from v1; -select * from v2; --- error ER_VIEW_INVALID -select * from v3; --- error ER_VIEW_INVALID -select * from v4; --- error ER_VIEW_INVALID -select * from v5; -use test; - -connection root; -drop view v1, v2, v3, v4, v5; -drop function f2; -drop table t1, t2; -use test; -REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost; -drop database mysqltest; - -# -# revertion of previous test, definer of view lost his/her rights to execute -# function -# - -connection root; ---disable_warnings -create database mysqltest; ---enable_warnings - -use mysqltest; -create table t1 (a int); -insert into t1 values (1); -create table t2 (s1 int); ---disable_warnings -drop function if exists f2; ---enable_warnings -delimiter //; -create function f2 () returns int begin declare v int; select s1 from t2 -into v; return v; end// -delimiter ;// -grant select on t1 to mysqltest_1@localhost; -grant execute on function f2 to mysqltest_1@localhost; -grant create view on mysqltest.* to mysqltest_1@localhost; - -connection user1; -use mysqltest; -create algorithm=TEMPTABLE view v1 as select f2() from t1; -create algorithm=MERGE view v2 as select f2() from t1; -create algorithm=TEMPTABLE SQL SECURITY INVOKER view v3 as select f2() from t1; -create algorithm=MERGE SQL SECURITY INVOKER view v4 as select f2() from t1; -use test; - -connection root; -create view v5 as select * from v1; -revoke execute on function f2 from mysqltest_1@localhost; --- error ER_VIEW_INVALID -select * from v1; --- error ER_VIEW_INVALID -select * from v2; -select * from v3; -select * from v4; --- error ER_VIEW_INVALID -select * from v5; - -drop view v1, v2, v3, v4, v5; -drop function f2; -drop table t1, t2; -use test; -REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost; -drop database mysqltest; - -# -# definer/invoker rights for columns -# -connection root; ---disable_warnings -create database mysqltest; ---enable_warnings - -use mysqltest; -create table t1 (a int); -create table v1 (a int); -insert into t1 values (1); -grant select on t1 to mysqltest_1@localhost; -grant select on v1 to mysqltest_1@localhost; -grant create view on mysqltest.* to mysqltest_1@localhost; -drop table v1; - -connection user1; -use mysqltest; -create algorithm=TEMPTABLE view v1 as select *, a as b from t1; -create algorithm=MERGE view v2 as select *, a as b from t1; -create algorithm=TEMPTABLE SQL SECURITY INVOKER view v3 as select *, a as b from t1; -create algorithm=MERGE SQL SECURITY INVOKER view v4 as select *, a as b from t1; -create view v5 as select * from v1; -use test; - -connection root; -revoke select on t1 from mysqltest_1@localhost; --- error ER_VIEW_INVALID -select * from v1; --- error ER_VIEW_INVALID -select * from v2; -select * from v3; -select * from v4; --- error ER_VIEW_INVALID -select * from v5; - -#drop view v1, v2, v3, v4, v5; -drop table t1; -use test; -REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost; -drop database mysqltest; - - -connection root; ---disable_warnings -create database mysqltest; ---enable_warnings - -use mysqltest; -create table t1 (a int); -insert into t1 values (1); -create algorithm=TEMPTABLE view v1 as select *, a as b from t1; -create algorithm=MERGE view v2 as select *, a as b from t1; -create algorithm=TEMPTABLE SQL SECURITY INVOKER view v3 as select *, a as b from t1; -create algorithm=MERGE SQL SECURITY INVOKER view v4 as select *, a as b from t1; -create SQL SECURITY INVOKER view v5 as select * from v4; -grant select on v1 to mysqltest_1@localhost; -grant select on v2 to mysqltest_1@localhost; -grant select on v3 to mysqltest_1@localhost; -grant select on v4 to mysqltest_1@localhost; -grant select on v5 to mysqltest_1@localhost; - -connection user1; -use mysqltest; -select * from v1; -select * from v2; --- error ER_VIEW_INVALID -select * from v3; --- error ER_VIEW_INVALID -select * from v4; --- error ER_VIEW_INVALID -select * from v5; -use test; - -connection root; -drop view v1, v2, v3, v4, v5; -drop table t1; -use test; -REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost; -drop database mysqltest; - -# -# BUG#14256: definer in view definition is not fully qualified -# ---disable_warnings -drop view if exists v1; ---enable_warnings - -# Backup anonymous users and remove them. (They get in the way of -# the one we test with here otherwise.) -create table t1 as select * from mysql.user where user=''; -delete from mysql.user where user=''; -flush privileges; - -# Create the test user -grant all on test.* to 'test14256'@'%'; - -connect (test14256,localhost,test14256,,test); -connection test14256; -use test; - -create view v1 as select 42; -show create view v1; - -select definer into @v1def1 from information_schema.views - where table_schema = 'test' and table_name='v1'; -drop view v1; - -create definer=`test14256`@`%` view v1 as select 42; -show create view v1; - -select definer into @v1def2 from information_schema.views - where table_schema = 'test' and table_name='v1'; -drop view v1; - -select @v1def1, @v1def2, @v1def1=@v1def2; - -connection root; -drop user test14256; - -# Restore the anonymous users. -insert into mysql.user select * from t1; -flush privileges; - -drop table t1; - -# -# BUG#14726: freeing stack variable in case of an error of opening -# a view when we have locked tables with LOCK TABLES statement. -# -connection root; ---disable_warnings -create database mysqltest; ---enable_warnings - -use mysqltest; -CREATE TABLE t1 (i INT); -CREATE VIEW v1 AS SELECT * FROM t1; -SHOW CREATE VIEW v1; -GRANT SELECT, LOCK TABLES ON mysqltest.* TO mysqltest_1@localhost; - -connection user1; - -use mysqltest; -LOCK TABLES v1 READ; --- error ER_TABLEACCESS_DENIED_ERROR -SHOW CREATE TABLE v1; -UNLOCK TABLES; -use test; - -connection root; -use test; -drop user mysqltest_1@localhost; -drop database mysqltest; - -# -# switch to default connaction -# -disconnect user1; -disconnect root; -connection default; - -# -# DEFINER information check -# -create definer=some_user@`` sql security invoker view v1 as select 1; -create definer=some_user@localhost sql security invoker view v2 as select 1; -show create view v1; -show create view v2; -drop view v1; -drop view v2; - -# -# Bug#18681: View privileges are broken -# -CREATE DATABASE mysqltest1; -CREATE USER readonly@localhost; -CREATE TABLE mysqltest1.t1 (x INT); -INSERT INTO mysqltest1.t1 VALUES (1), (2); -CREATE SQL SECURITY INVOKER VIEW mysqltest1.v_t1 AS SELECT * FROM mysqltest1.t1; -CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_ts AS SELECT * FROM mysqltest1.t1; -CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_ti AS SELECT * FROM mysqltest1.t1; -CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_tu AS SELECT * FROM mysqltest1.t1; -CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_tus AS SELECT * FROM mysqltest1.t1; -CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_td AS SELECT * FROM mysqltest1.t1; -CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_tds AS SELECT * FROM mysqltest1.t1; -GRANT SELECT, INSERT, UPDATE, DELETE ON mysqltest1.v_t1 TO readonly@localhost; -GRANT SELECT ON mysqltest1.v_ts TO readonly@localhost; -GRANT INSERT ON mysqltest1.v_ti TO readonly@localhost; -GRANT UPDATE ON mysqltest1.v_tu TO readonly@localhost; -GRANT UPDATE,SELECT ON mysqltest1.v_tus TO readonly@localhost; -GRANT DELETE ON mysqltest1.v_td TO readonly@localhost; -GRANT DELETE,SELECT ON mysqltest1.v_tds TO readonly@localhost; - -CONNECT (n1,localhost,readonly,,); -CONNECTION n1; - ---error 1356 -SELECT * FROM mysqltest1.v_t1; ---error 1356 -INSERT INTO mysqltest1.v_t1 VALUES(4); ---error 1356 -DELETE FROM mysqltest1.v_t1 WHERE x = 1; ---error 1356 -UPDATE mysqltest1.v_t1 SET x = 3 WHERE x = 2; ---error 1356 -UPDATE mysqltest1.v_t1 SET x = 3; ---error 1356 -DELETE FROM mysqltest1.v_t1; ---error 1356 -SELECT 1 FROM mysqltest1.v_t1; ---error 1142 -SELECT * FROM mysqltest1.t1; - -SELECT * FROM mysqltest1.v_ts; ---error 1142 -SELECT * FROM mysqltest1.v_ts, mysqltest1.t1 WHERE mysqltest1.t1.x = mysqltest1.v_ts.x; ---error 1142 -SELECT * FROM mysqltest1.v_ti; - ---error 1142 -INSERT INTO mysqltest1.v_ts VALUES (100); -INSERT INTO mysqltest1.v_ti VALUES (100); - ---error 1142 -UPDATE mysqltest1.v_ts SET x= 200 WHERE x = 100; ---error 1142 -UPDATE mysqltest1.v_ts SET x= 200; -UPDATE mysqltest1.v_tu SET x= 200 WHERE x = 100; -UPDATE mysqltest1.v_tus SET x= 200 WHERE x = 100; -UPDATE mysqltest1.v_tu SET x= 200; - ---error 1142 -DELETE FROM mysqltest1.v_ts WHERE x= 200; ---error 1142 -DELETE FROM mysqltest1.v_ts; ---error 1143 -DELETE FROM mysqltest1.v_td WHERE x= 200; -DELETE FROM mysqltest1.v_tds WHERE x= 200; -DELETE FROM mysqltest1.v_td; - -CONNECTION default; -DROP VIEW mysqltest1.v_tds; -DROP VIEW mysqltest1.v_td; -DROP VIEW mysqltest1.v_tus; -DROP VIEW mysqltest1.v_tu; -DROP VIEW mysqltest1.v_ti; -DROP VIEW mysqltest1.v_ts; -DROP VIEW mysqltest1.v_t1; -DROP TABLE mysqltest1.t1; -DROP USER readonly@localhost; -DROP DATABASE mysqltest1; - -# -# BUG#14875: Bad view DEFINER makes SHOW CREATE VIEW fail -# -CREATE TABLE t1 (a INT PRIMARY KEY); -INSERT INTO t1 VALUES (1), (2), (3); -CREATE DEFINER = 'no-such-user'@localhost VIEW v AS SELECT a from t1; -#--warning 1448 -SHOW CREATE VIEW v; ---error 1449 -SELECT * FROM v; -DROP VIEW v; -DROP TABLE t1; -USE test; - -# -# Bug#20363: Create view on just created view is now denied -# -eval CREATE USER mysqltest_db1@localhost identified by 'PWD'; -eval GRANT ALL ON mysqltest_db1.* TO mysqltest_db1@localhost WITH GRANT OPTION; - -# The session with the non root user is needed. ---replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK -connect (session1,localhost,mysqltest_db1,PWD,test); - -CREATE SCHEMA mysqltest_db1 ; -USE mysqltest_db1 ; - -CREATE TABLE t1 (f1 INTEGER); - -CREATE VIEW view1 AS -SELECT * FROM t1; -SHOW CREATE VIEW view1; - -CREATE VIEW view2 AS -SELECT * FROM view1; ---echo # Here comes a suspicious warning -SHOW CREATE VIEW view2; ---echo # But the view view2 is usable -SELECT * FROM view2; - -CREATE VIEW view3 AS -SELECT * FROM view2; - -SELECT * from view3; - -connection default; -DROP VIEW mysqltest_db1.view3; -DROP VIEW mysqltest_db1.view2; -DROP VIEW mysqltest_db1.view1; -DROP TABLE mysqltest_db1.t1; -DROP SCHEMA mysqltest_db1; -DROP USER mysqltest_db1@localhost; -# -# BUG#20482: failure on Create join view with sources views/tables -# in different schemas -# ---disable_warnings -CREATE DATABASE test1; -CREATE DATABASE test2; ---enable_warnings - -CREATE TABLE test1.t0 (a VARCHAR(20)) engine=myisam; # PBXT can't mix databases; -CREATE TABLE test2.t1 (a VARCHAR(20)); -CREATE VIEW test2.t3 AS SELECT * FROM test1.t0; -CREATE OR REPLACE VIEW test.v1 AS - SELECT ta.a AS col1, tb.a AS col2 FROM test2.t3 ta, test2.t1 tb; - -DROP VIEW test.v1; -DROP VIEW test2.t3; -DROP TABLE test2.t1, test1.t0; -DROP DATABASE test2; -DROP DATABASE test1; - - -# -# BUG#20570: CURRENT_USER() in a VIEW with SQL SECURITY DEFINER -# returns invoker name -# ---disable_warnings -DROP VIEW IF EXISTS v1; -DROP VIEW IF EXISTS v2; -DROP VIEW IF EXISTS v3; -DROP FUNCTION IF EXISTS f1; -DROP FUNCTION IF EXISTS f2; -DROP PROCEDURE IF EXISTS p1; ---enable_warnings - -CREATE SQL SECURITY DEFINER VIEW v1 AS SELECT CURRENT_USER() AS cu; - -CREATE FUNCTION f1() RETURNS VARCHAR(77) SQL SECURITY INVOKER - RETURN CURRENT_USER(); -CREATE SQL SECURITY DEFINER VIEW v2 AS SELECT f1() AS cu; - -CREATE PROCEDURE p1(OUT cu VARCHAR(77)) SQL SECURITY INVOKER - SET cu= CURRENT_USER(); -delimiter |; -CREATE FUNCTION f2() RETURNS VARCHAR(77) SQL SECURITY INVOKER -BEGIN - DECLARE cu VARCHAR(77); - CALL p1(cu); - RETURN cu; -END| -delimiter ;| -CREATE SQL SECURITY DEFINER VIEW v3 AS SELECT f2() AS cu; - -CREATE USER mysqltest_u1@localhost; -GRANT ALL ON test.* TO mysqltest_u1@localhost; - -connect (conn1, localhost, mysqltest_u1,,); - ---echo ---echo The following tests should all return 1. ---echo -SELECT CURRENT_USER() = 'mysqltest_u1@localhost'; -SELECT f1() = 'mysqltest_u1@localhost'; -CALL p1(@cu); -SELECT @cu = 'mysqltest_u1@localhost'; -SELECT f2() = 'mysqltest_u1@localhost'; -SELECT cu = 'root@localhost' FROM v1; -SELECT cu = 'root@localhost' FROM v2; -SELECT cu = 'root@localhost' FROM v3; - -disconnect conn1; -connection default; - -DROP VIEW v3; -DROP FUNCTION f2; -DROP PROCEDURE p1; -DROP FUNCTION f1; -DROP VIEW v2; -DROP VIEW v1; -DROP USER mysqltest_u1@localhost; - - -# -# Bug#17254: Error for DEFINER security on VIEW provides too much info -# -connect (root,localhost,root,,); -connection root; -CREATE DATABASE db17254; -USE db17254; -CREATE TABLE t1 (f1 INT); -INSERT INTO t1 VALUES (10),(20); -CREATE USER def_17254@localhost; -GRANT SELECT ON db17254.* TO def_17254@localhost; -CREATE USER inv_17254@localhost; -GRANT SELECT ON db17254.t1 TO inv_17254@localhost; -GRANT CREATE VIEW ON db17254.* TO def_17254@localhost; - -connect (def,localhost,def_17254,,db17254); -connection def; -CREATE VIEW v1 AS SELECT * FROM t1; - -connection root; -DROP USER def_17254@localhost; - -connect (inv,localhost,inv_17254,,db17254); -connection inv; ---echo for a user ---error 1142 -SELECT * FROM v1; - -connection root; ---echo for a superuser ---error 1449 -SELECT * FROM v1; -DROP USER inv_17254@localhost; -DROP DATABASE db17254; -disconnect def; -disconnect inv; - - -# -# BUG#24404: strange bug with view+permission+prepared statement -# ---disable_warnings -DROP DATABASE IF EXISTS mysqltest_db1; -DROP DATABASE IF EXISTS mysqltest_db2; ---enable_warnings ---error 0,ER_CANNOT_USER -DROP USER mysqltest_u1; ---error 0,ER_CANNOT_USER -DROP USER mysqltest_u2; - -CREATE USER mysqltest_u1@localhost; -CREATE USER mysqltest_u2@localhost; - -CREATE DATABASE mysqltest_db1; -CREATE DATABASE mysqltest_db2; - -GRANT ALL ON mysqltest_db1.* TO mysqltest_u1@localhost WITH GRANT OPTION; -GRANT ALL ON mysqltest_db2.* TO mysqltest_u2@localhost; - -connect (conn1, localhost, mysqltest_u1, , mysqltest_db1); - -CREATE TABLE t1 (i INT); -INSERT INTO t1 VALUES (1); - -# Use view with subquery for better coverage. -CREATE VIEW v1 AS SELECT i FROM t1 WHERE 1 IN (SELECT * FROM t1); - -CREATE TABLE t2 (s CHAR(7)); -INSERT INTO t2 VALUES ('public'); - -GRANT SELECT ON v1 TO mysqltest_u2@localhost; -GRANT SELECT ON t2 TO mysqltest_u2@localhost; - -connect (conn2, localhost, mysqltest_u2, , mysqltest_db2); - -SELECT * FROM mysqltest_db1.v1, mysqltest_db1.t2; -PREPARE stmt1 FROM "SELECT * FROM mysqltest_db1.t2"; -EXECUTE stmt1; -PREPARE stmt2 FROM "SELECT * FROM mysqltest_db1.v1, mysqltest_db1.t2"; -EXECUTE stmt2; - -connection conn1; -# Make table 't2' private. -REVOKE SELECT ON t2 FROM mysqltest_u2@localhost; -UPDATE t2 SET s = 'private' WHERE s = 'public'; - -connection conn2; ---error ER_TABLEACCESS_DENIED_ERROR -SELECT * FROM mysqltest_db1.v1, mysqltest_db1.t2; ---error ER_TABLEACCESS_DENIED_ERROR -EXECUTE stmt1; -# Original bug was here: the statement didn't fail. ---error ER_TABLEACCESS_DENIED_ERROR -EXECUTE stmt2; - -# Cleanup. -disconnect conn2; -disconnect conn1; -connection default; -REVOKE ALL ON mysqltest_db1.* FROM mysqltest_u1@localhost; -REVOKE ALL ON mysqltest_db2.* FROM mysqltest_u2@localhost; -DROP DATABASE mysqltest_db1; -DROP DATABASE mysqltest_db2; -DROP USER mysqltest_u1@localhost; -DROP USER mysqltest_u2@localhost; - -# -# Bug#26813: The SUPER privilege is wrongly required to alter a view created -# by another user. -# -connection root; -CREATE DATABASE db26813; -USE db26813; -CREATE TABLE t1(f1 INT, f2 INT); -CREATE VIEW v1 AS SELECT f1 FROM t1; -CREATE VIEW v2 AS SELECT f1 FROM t1; -CREATE VIEW v3 AS SELECT f1 FROM t1; -CREATE USER u26813@localhost; -GRANT DROP ON db26813.v1 TO u26813@localhost; -GRANT CREATE VIEW ON db26813.v2 TO u26813@localhost; -GRANT DROP, CREATE VIEW ON db26813.v3 TO u26813@localhost; -GRANT SELECT ON db26813.t1 TO u26813@localhost; - -connect (u1,localhost,u26813,,db26813); -connection u1; ---error ER_SPECIFIC_ACCESS_DENIED_ERROR -ALTER VIEW v1 AS SELECT f2 FROM t1; ---error ER_SPECIFIC_ACCESS_DENIED_ERROR -ALTER VIEW v2 AS SELECT f2 FROM t1; ---error ER_SPECIFIC_ACCESS_DENIED_ERROR -ALTER VIEW v3 AS SELECT f2 FROM t1; - -connection root; -SHOW CREATE VIEW v3; - -DROP USER u26813@localhost; -DROP DATABASE db26813; -disconnect u1; - ---echo # ---echo # Bug#29908: A user can gain additional access through the ALTER VIEW. ---echo # -connection root; -CREATE DATABASE mysqltest_29908; -USE mysqltest_29908; -CREATE TABLE t1(f1 INT, f2 INT); -CREATE USER u29908_1@localhost; -CREATE DEFINER = u29908_1@localhost VIEW v1 AS SELECT f1 FROM t1; -CREATE DEFINER = u29908_1@localhost SQL SECURITY INVOKER VIEW v2 AS - SELECT f1 FROM t1; -GRANT DROP, CREATE VIEW, SHOW VIEW ON mysqltest_29908.v1 TO u29908_1@localhost; -GRANT DROP, CREATE VIEW, SHOW VIEW ON mysqltest_29908.v2 TO u29908_1@localhost; -GRANT SELECT ON mysqltest_29908.t1 TO u29908_1@localhost; -CREATE USER u29908_2@localhost; -GRANT DROP, CREATE VIEW ON mysqltest_29908.v1 TO u29908_2@localhost; -GRANT DROP, CREATE VIEW, SHOW VIEW ON mysqltest_29908.v2 TO u29908_2@localhost; -GRANT SELECT ON mysqltest_29908.t1 TO u29908_2@localhost; - -connect (u2,localhost,u29908_2,,mysqltest_29908); ---error ER_SPECIFIC_ACCESS_DENIED_ERROR -ALTER VIEW v1 AS SELECT f2 FROM t1; ---error ER_SPECIFIC_ACCESS_DENIED_ERROR -ALTER VIEW v2 AS SELECT f2 FROM t1; -SHOW CREATE VIEW v2; - -connect (u1,localhost,u29908_1,,mysqltest_29908); -ALTER VIEW v1 AS SELECT f2 FROM t1; -SHOW CREATE VIEW v1; -ALTER VIEW v2 AS SELECT f2 FROM t1; -SHOW CREATE VIEW v2; - -connection root; -ALTER VIEW v1 AS SELECT f1 FROM t1; -SHOW CREATE VIEW v1; -ALTER VIEW v2 AS SELECT f1 FROM t1; -SHOW CREATE VIEW v2; - -DROP USER u29908_1@localhost; -DROP USER u29908_2@localhost; -DROP DATABASE mysqltest_29908; -disconnect u1; -disconnect u2; ---echo ####################################################################### - -# -# BUG#24040: Create View don't succed with "all privileges" on a database. -# - -# Prepare. - ---disable_warnings -DROP DATABASE IF EXISTS mysqltest1; -DROP DATABASE IF EXISTS mysqltest2; ---enable_warnings - -CREATE DATABASE mysqltest1; -CREATE DATABASE mysqltest2; - -# Test. - -CREATE TABLE mysqltest1.t1(c1 INT); -CREATE TABLE mysqltest1.t2(c2 INT); -CREATE TABLE mysqltest1.t3(c3 INT); -CREATE TABLE mysqltest1.t4(c4 INT); - -INSERT INTO mysqltest1.t1 VALUES (11), (12), (13), (14); -INSERT INTO mysqltest1.t2 VALUES (21), (22), (23), (24); -INSERT INTO mysqltest1.t3 VALUES (31), (32), (33), (34); -INSERT INTO mysqltest1.t4 VALUES (41), (42), (43), (44); - -GRANT SELECT ON mysqltest1.t1 TO mysqltest_u1@localhost; -GRANT INSERT ON mysqltest1.t2 TO mysqltest_u1@localhost; -GRANT SELECT, UPDATE ON mysqltest1.t3 TO mysqltest_u1@localhost; -GRANT SELECT, DELETE ON mysqltest1.t4 TO mysqltest_u1@localhost; - -GRANT ALL PRIVILEGES ON mysqltest2.* TO mysqltest_u1@localhost; - ---connect (bug24040_con,localhost,mysqltest_u1,,mysqltest2) ---echo ---echo ---> connection: bug24040_con - -SELECT * FROM mysqltest1.t1; -INSERT INTO mysqltest1.t2 VALUES(25); -UPDATE mysqltest1.t3 SET c3 = 331 WHERE c3 = 31; -DELETE FROM mysqltest1.t4 WHERE c4 = 44; - -CREATE VIEW v1 AS SELECT * FROM mysqltest1.t1; -CREATE VIEW v2 AS SELECT * FROM mysqltest1.t2; -CREATE VIEW v3 AS SELECT * FROM mysqltest1.t3; -CREATE VIEW v4 AS SELECT * FROM mysqltest1.t4; - -SELECT * FROM v1; -INSERT INTO v2 VALUES(26); -UPDATE v3 SET c3 = 332 WHERE c3 = 32; -DELETE FROM v4 WHERE c4 = 43; - ---error ER_COLUMNACCESS_DENIED_ERROR -CREATE VIEW v12 AS SELECT c1, c2 FROM mysqltest1.t1, mysqltest1.t2; -CREATE VIEW v13 AS SELECT c1, c3 FROM mysqltest1.t1, mysqltest1.t3; -CREATE VIEW v14 AS SELECT c1, c4 FROM mysqltest1.t1, mysqltest1.t4; - ---error ER_COLUMNACCESS_DENIED_ERROR -CREATE VIEW v21 AS SELECT c2, c1 FROM mysqltest1.t2, mysqltest1.t1; ---error ER_COLUMNACCESS_DENIED_ERROR -CREATE VIEW v23 AS SELECT c2, c3 FROM mysqltest1.t2, mysqltest1.t3; ---error ER_COLUMNACCESS_DENIED_ERROR -CREATE VIEW v24 AS SELECT c2, c4 FROM mysqltest1.t2, mysqltest1.t4; - -CREATE VIEW v31 AS SELECT c3, c1 FROM mysqltest1.t3, mysqltest1.t1; ---error ER_COLUMNACCESS_DENIED_ERROR -CREATE VIEW v32 AS SELECT c3, c2 FROM mysqltest1.t3, mysqltest1.t2; -CREATE VIEW v34 AS SELECT c3, c4 FROM mysqltest1.t3, mysqltest1.t4; - -CREATE VIEW v41 AS SELECT c4, c1 FROM mysqltest1.t4, mysqltest1.t1; ---error ER_COLUMNACCESS_DENIED_ERROR -CREATE VIEW v42 AS SELECT c4, c2 FROM mysqltest1.t4, mysqltest1.t2; -CREATE VIEW v43 AS SELECT c4, c3 FROM mysqltest1.t4, mysqltest1.t3; - ---connection default ---echo ---echo ---> connection: default - -SELECT * FROM mysqltest1.t1; -SELECT * FROM mysqltest1.t2; -SELECT * FROM mysqltest1.t3 order by c3; # PBXT: order required -SELECT * FROM mysqltest1.t4; - -# Cleanup. - --- disconnect bug24040_con - -DROP DATABASE mysqltest1; -DROP DATABASE mysqltest2; -DROP USER mysqltest_u1@localhost; - ---echo End of 5.0 tests. - - -# -# Test that ALTER VIEW accepts DEFINER and ALGORITHM, see bug#16425. -# -connection default; ---disable_warnings -DROP VIEW IF EXISTS v1; -DROP TABLE IF EXISTS t1; ---enable_warnings - -CREATE TABLE t1 (i INT); -CREATE VIEW v1 AS SELECT * FROM t1; - -ALTER VIEW v1 AS SELECT * FROM t1; -SHOW CREATE VIEW v1; -ALTER DEFINER=no_such@user_1 VIEW v1 AS SELECT * FROM t1; -SHOW CREATE VIEW v1; -ALTER ALGORITHM=MERGE VIEW v1 AS SELECT * FROM t1; -SHOW CREATE VIEW v1; -ALTER ALGORITHM=TEMPTABLE DEFINER=no_such@user_2 VIEW v1 AS SELECT * FROM t1; -SHOW CREATE VIEW v1; - -DROP VIEW v1; -DROP TABLE t1; - - ---disable_query_log -drop database pbxt; ---enable_query_log ---echo End of 5.1 tests. diff --git a/mysql-test/t/innodb_file_format.test b/mysql-test/t/innodb_file_format.test deleted file mode 100644 index 6de026ad97f..00000000000 --- a/mysql-test/t/innodb_file_format.test +++ /dev/null @@ -1,31 +0,0 @@ --- source include/have_innodb.inc - -call mtr.add_suppression("InnoDB: invalid innodb_file_format_check value"); - -select @@innodb_file_format; -select @@innodb_file_format_check; -set global innodb_file_format=antelope; -set global innodb_file_format=barracuda; ---error ER_WRONG_ARGUMENTS -set global innodb_file_format=cheetah; -select @@innodb_file_format; -set global innodb_file_format=default; -select @@innodb_file_format; ---error ER_WRONG_ARGUMENTS -set global innodb_file_format=on; ---error ER_WRONG_ARGUMENTS -set global innodb_file_format=off; -select @@innodb_file_format; -set global innodb_file_format_check=antelope; -set global innodb_file_format_check=barracuda; ---error ER_WRONG_ARGUMENTS -set global innodb_file_format_check=cheetah; -select @@innodb_file_format_check; -set global innodb_file_format_check=default; -select @@innodb_file_format_check; ---error ER_WRONG_ARGUMENTS -set global innodb_file_format=on; ---error ER_WRONG_ARGUMENTS -set global innodb_file_format=off; -select @@innodb_file_format_check; -set global innodb_file_format_check=antelope; diff --git a/mysql-test/t/mysqld_option_err.test b/mysql-test/t/mysqld_option_err.test index 9c02dec51e6..5e35f924b15 100644 --- a/mysql-test/t/mysqld_option_err.test +++ b/mysql-test/t/mysqld_option_err.test @@ -21,22 +21,22 @@ mkdir $MYSQLTEST_VARDIR/tmp/mysqld_option_err; --echo Test that unknown option is not silently ignored. --error 2 ---exec $MYSQLD --skip-networking --datadir=$MYSQLTEST_VARDIR/tmp/mysqld_option_err --skip-grant-tables --nonexistentoption >$MYSQLTEST_VARDIR/tmp/mysqld_option_err/mysqltest.log 2>&1 +--exec $MYSQLD_SIMPLE_CMD --skip-networking --datadir=$MYSQLTEST_VARDIR/tmp/mysqld_option_err --skip-grant-tables --nonexistentoption --loose-skip-innodb --loose-skip-pbxt >$MYSQLTEST_VARDIR/tmp/mysqld_option_err/mysqltest.log 2>&1 --echo Test bad binlog format. --error 1 ---exec $MYSQLD --skip-networking --datadir=$MYSQLTEST_VARDIR/tmp/mysqld_option_err --skip-grant-tables --log-bin --binlog-format=badformat >>$MYSQLTEST_VARDIR/tmp/mysqld_option_err/mysqltest.log 2>&1 +--exec $MYSQLD_SIMPLE_CMD --skip-networking --datadir=$MYSQLTEST_VARDIR/tmp/mysqld_option_err --skip-grant-tables --log-bin --binlog-format=badformat >>$MYSQLTEST_VARDIR/tmp/mysqld_option_err/mysqltest.log 2>&1 --echo Test bad default storage engine. --error 1 ---exec $MYSQLD --skip-networking --datadir=$MYSQLTEST_VARDIR/tmp/mysqld_option_err --skip-grant-tables --default-storage-engine=nonexistentengine >>$MYSQLTEST_VARDIR/tmp/mysqld_option_err/mysqltest.log 2>&1 +--exec $MYSQLD_SIMPLE_CMD --skip-networking --datadir=$MYSQLTEST_VARDIR/tmp/mysqld_option_err --skip-grant-tables --default-storage-engine=nonexistentengine >>$MYSQLTEST_VARDIR/tmp/mysqld_option_err/mysqltest.log 2>&1 --echo Test non-numeric value passed to number option. --error 1 ---exec $MYSQLD --skip-networking --datadir=$MYSQLTEST_VARDIR/tmp/mysqld_option_err --skip-grant-tables --min-examined-row-limit=notanumber >>$MYSQLTEST_VARDIR/tmp/mysqld_option_err/mysqltest.log 2>&1 +--exec $MYSQLD_SIMPLE_CMD --skip-networking --datadir=$MYSQLTEST_VARDIR/tmp/mysqld_option_err --skip-grant-tables --min-examined-row-limit=notanumber >>$MYSQLTEST_VARDIR/tmp/mysqld_option_err/mysqltest.log 2>&1 # Test for MBug#423035: error in parsing enum value for plugin @@ -44,16 +44,16 @@ mkdir $MYSQLTEST_VARDIR/tmp/mysqld_option_err; # See also Bug#32034. --echo Test that bad value for plugin enum option is rejected correctly. --error 7 ---exec $MYSQLD --skip-networking --datadir=$MYSQLTEST_VARDIR/tmp/mysqld_option_err --skip-grant-tables --plugin-dir=$MYSQLTEST_VARDIR/plugins --plugin-load=example=ha_example.so --plugin-example-enum-var=noexist >>$MYSQLTEST_VARDIR/tmp/mysqld_option_err/mysqltest.log 2>&1 +--exec $MYSQLD_SIMPLE_CMD --skip-networking --datadir=$MYSQLTEST_VARDIR/tmp/mysqld_option_err --skip-grant-tables --plugin-dir=$MYSQLTEST_VARDIR/plugins --plugin-load=example=ha_example.so --plugin-example-enum-var=noexist >>$MYSQLTEST_VARDIR/tmp/mysqld_option_err/mysqltest.log 2>&1 # # Test that an wrong option with --help --verbose gives an error # --echo Test that --help --verbose works ---exec $MYSQLD --help --verbose >>$MYSQLTEST_VARDIR/tmp/mysqld_option_err/mysqltest.log 2>&1 +--exec $MYSQLD_SIMPLE_CMD --help --verbose >>$MYSQLTEST_VARDIR/tmp/mysqld_option_err/mysqltest.log 2>&1 --echo Test that --not-known-option --help --verbose gives error --error 2 ---exec $MYSQLD --not-known-option --help --verbose >>$MYSQLTEST_VARDIR/tmp/mysqld_option_err/mysqltest.log 2>&1 +--exec $MYSQLD_SIMPLE_CMD --not-known-option --help --verbose >>$MYSQLTEST_VARDIR/tmp/mysqld_option_err/mysqltest.log 2>&1 --echo Done. diff --git a/sql/my_decimal.h b/sql/my_decimal.h index 72692e54d35..845aecb972c 100644 --- a/sql/my_decimal.h +++ b/sql/my_decimal.h @@ -99,7 +99,7 @@ class my_decimal :public decimal_t To catch them, we allocate dummy fields around the buffer, and test that their values do not change. */ -#if !defined(DBUG_OFF) && defined(HAVE_valgrind) +#if !defined(DBUG_OFF) int foo1; #endif diff --git a/storage/maria/ma_loghandler.c b/storage/maria/ma_loghandler.c index 7e1943e7c68..ce7253d4c39 100644 --- a/storage/maria/ma_loghandler.c +++ b/storage/maria/ma_loghandler.c @@ -2534,7 +2534,9 @@ static my_bool translog_buffer_flush(struct st_translog_buffer *buffer) i < buffer->size; i+= TRANSLOG_PAGE_SIZE, pg++) { +#ifndef DBUG_OFF TRANSLOG_ADDRESS addr= (buffer->offset + i); +#endif DBUG_PRINT("info", ("send log form %lu till %lu address: (%lu,0x%lx) " "page #: %lu buffer size: %lu buffer: 0x%lx", (ulong) i, (ulong) (i + TRANSLOG_PAGE_SIZE), From 4b157e1556b5c7d5da11b6eb0e4ba72378ce9cfd Mon Sep 17 00:00:00 2001 From: Luis Soares Date: Thu, 24 Nov 2011 14:51:18 +0000 Subject: [PATCH 111/288] BUG#13427949: CHANGE MASTER TO USER='' (EMPTY USER) CAUSES ERRORS ON VALGRING When passing an empty user to the connect function will cause valgrind warnings. Seems that the client code is not prepared to handle empty users. On 5.6 this can even be triggered by START SLAVE PASSWORD='...'; i.e., without setting USER='...' on the START SLAVE command (see WL#4143 for details on the new additional START SLAVE commands). To fix this, we disallow empty users when configuring the slave connection parameters (this decision might be revisited if the client code accepts empty users in the future). sql/slave.cc: We throw an error if an empty user is supplied to the connection function. --- mysql-test/suite/rpl/r/rpl_connection.result | 11 +++++++++ mysql-test/suite/rpl/t/rpl_connection.test | 24 ++++++++++++++++++++ sql/slave.cc | 14 +++++++++++- 3 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 mysql-test/suite/rpl/r/rpl_connection.result create mode 100644 mysql-test/suite/rpl/t/rpl_connection.test diff --git a/mysql-test/suite/rpl/r/rpl_connection.result b/mysql-test/suite/rpl/r/rpl_connection.result new file mode 100644 index 00000000000..02a7a36278e --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_connection.result @@ -0,0 +1,11 @@ +include/master-slave.inc +[connection master] +call mtr.add_suppression(".*Invalid .* username when attempting to connect to the master server.*"); +include/stop_slave.inc +CHANGE MASTER TO MASTER_USER= '', MASTER_PASSWORD= ''; +START SLAVE; +include/wait_for_slave_io_error.inc [errno=1045, 1593] +include/stop_slave.inc +CHANGE MASTER TO MASTER_USER= 'root', MASTER_PASSWORD= ''; +START SLAVE; +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_connection.test b/mysql-test/suite/rpl/t/rpl_connection.test new file mode 100644 index 00000000000..1233e28dc86 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_connection.test @@ -0,0 +1,24 @@ +--source include/not_embedded.inc +--source include/master-slave.inc +--source include/have_binlog_format_mixed.inc + +# +# BUG#13427949: CHANGE MASTER TO USER='' (EMPTY USER) CAUSES ERRORS ON VALGRING +# + +--connection slave +call mtr.add_suppression(".*Invalid .* username when attempting to connect to the master server.*"); + + +# Assert that we disallow empty users and that no problem +--source include/stop_slave.inc +CHANGE MASTER TO MASTER_USER= '', MASTER_PASSWORD= ''; +START SLAVE; +--let $slave_io_errno= 1045, 1593 +--source include/wait_for_slave_io_error.inc +--source include/stop_slave.inc + +CHANGE MASTER TO MASTER_USER= 'root', MASTER_PASSWORD= ''; +START SLAVE; + +--source include/rpl_end.inc diff --git a/sql/slave.cc b/sql/slave.cc index 7a3eee952c3..5c931a79695 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -4208,6 +4208,16 @@ static int connect_to_master(THD* thd, MYSQL* mysql, Master_info* mi, if (opt_plugin_dir_ptr && *opt_plugin_dir_ptr) mysql_options(mysql, MYSQL_PLUGIN_DIR, opt_plugin_dir_ptr); + /* we disallow empty users */ + if (mi->user == NULL || mi->user[0] == 0) + { + mi->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, + ER(ER_SLAVE_FATAL_ERROR), + "Invalid (empty) username when attempting to " + "connect to the master server. Connection attempt " + "terminated."); + DBUG_RETURN(1); + } while (!(slave_was_killed = io_slave_killed(thd,mi)) && (reconnect ? mysql_reconnect(mysql) != 0 : mysql_real_connect(mysql, mi->host, mi->user, mi->password, 0, @@ -4336,7 +4346,9 @@ MYSQL *rpl_connect_master(MYSQL *mysql) /* This one is not strictly needed but we have it here for completeness */ mysql_options(mysql, MYSQL_SET_CHARSET_DIR, (char *) charsets_dir); - if (io_slave_killed(thd, mi) + if (mi->user == NULL + || mi->user[0] == 0 + || io_slave_killed(thd, mi) || !mysql_real_connect(mysql, mi->host, mi->user, mi->password, 0, mi->port, 0, 0)) { From aa5b9cf8f9bd3dea46a0ca42a6361453c51f5db7 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Thu, 24 Nov 2011 19:07:36 +0200 Subject: [PATCH 112/288] Added test case forlp:875797 Using 'innodb_sys_indexes' causes core dump --- .../suite/percona/innodb_sys_index.result | 17 +++++++++++++++ .../suite/percona/innodb_sys_index.test | 21 +++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 mysql-test/suite/percona/innodb_sys_index.result create mode 100644 mysql-test/suite/percona/innodb_sys_index.test diff --git a/mysql-test/suite/percona/innodb_sys_index.result b/mysql-test/suite/percona/innodb_sys_index.result new file mode 100644 index 00000000000..8bf4fa745ba --- /dev/null +++ b/mysql-test/suite/percona/innodb_sys_index.result @@ -0,0 +1,17 @@ +drop table if exists t1; +Warnings: +Note 1051 Unknown table 't1' +select @@version_comment limit 1 ; +@@version_comment +Source distribution +SELECT COUNT(*) FROM `information_schema`.`INNODB_SYS_INDEXES` ; +CREATE TABLE test.t1 ( `a` SERIAL NOT NULL , `b` VARCHAR( 255 ) NOT NULL , INDEX ( `b` ) ) ENGINE = InnoDB ; +SHOW TABLE STATUS FROM `information_schema` LIKE 'INNODB\_SYS\_INDEXES%' ; +drop table test.t1; +SHOW TABLE STATUS FROM `information_schema` LIKE 'INNODB\_SYS\_INDEXES%' ; +SELECT COUNT(*) FROM `information_schema`.`INNODB_SYS_INDEXES` ; +CREATE TABLE test.t1 ( `a` SERIAL NOT NULL , `b` VARCHAR( 255 ) NOT NULL , INDEX ( `b` ) ) ENGINE = InnoDB ; +SHOW TABLE STATUS FROM `information_schema` LIKE 'INNODB\_SYS\_INDEXES%' ; +SELECT COUNT(*) FROM `information_schema`.`INNODB_SYS_INDEXES` ; +drop table test.t1; +SHOW TABLE STATUS FROM `information_schema` LIKE 'INNODB\_SYS\_INDEXES%' ; diff --git a/mysql-test/suite/percona/innodb_sys_index.test b/mysql-test/suite/percona/innodb_sys_index.test new file mode 100644 index 00000000000..9b1ac4c87e8 --- /dev/null +++ b/mysql-test/suite/percona/innodb_sys_index.test @@ -0,0 +1,21 @@ +--source include/big_test.inc +--source include/have_innodb.inc + +drop table if exists t1; +# +# test for bug LP#875797 "Using 'innodb_sys_indexes' causes core dump" +# +select @@version_comment limit 1 ; +--disable_result_log +SELECT COUNT(*) FROM `information_schema`.`INNODB_SYS_INDEXES` ; +CREATE TABLE test.t1 ( `a` SERIAL NOT NULL , `b` VARCHAR( 255 ) NOT NULL , INDEX ( `b` ) ) ENGINE = InnoDB ; +SHOW TABLE STATUS FROM `information_schema` LIKE 'INNODB\_SYS\_INDEXES%' ; +drop table test.t1; +SHOW TABLE STATUS FROM `information_schema` LIKE 'INNODB\_SYS\_INDEXES%' ; +SELECT COUNT(*) FROM `information_schema`.`INNODB_SYS_INDEXES` ; +CREATE TABLE test.t1 ( `a` SERIAL NOT NULL , `b` VARCHAR( 255 ) NOT NULL , INDEX ( `b` ) ) ENGINE = InnoDB ; +SHOW TABLE STATUS FROM `information_schema` LIKE 'INNODB\_SYS\_INDEXES%' ; +SELECT COUNT(*) FROM `information_schema`.`INNODB_SYS_INDEXES` ; +drop table test.t1; +SHOW TABLE STATUS FROM `information_schema` LIKE 'INNODB\_SYS\_INDEXES%' ; +--enable_result_log From eec4836a1b75531edc58c46e7ca778a7ecba82d6 Mon Sep 17 00:00:00 2001 From: Luis Soares Date: Thu, 24 Nov 2011 17:15:58 +0000 Subject: [PATCH 113/288] BUG#11745230: 12133: MASTER.INDEX FILE KEEPS MYSQLD FROM STARTING IF BIN LOG HAS BEEN MOVED When moving the binary/relay log files from one location to another and restarting the server with a different log-bin or relay-log paths, would cause the startup process to abort. The root cause was that the server would not be able to find the log files because it would consider old paths for entries in the index file instead of the new location. What's even worse, the relative paths would not be considered relative to the path provided in log-bin and relay-log, but to mysql_data_dir. We fix the cases where the server contains relative paths. When the server is reading from the index file, it checks whether the entry contains relative paths. If it does, we replace it with the absolute path set in log-bin/relay-log option. Absolute paths remain unchanged and the index must be manually edited to consider the new log-bin and/or relay-log path (this should be documented). This is a fix for a GA version, that does not break behavior (that much). For development versions, we should go with Zhenxing's approach that removes paths altogether from index files. mysql-test/include/begin_include_file.inc: Added parameter to keep the begin_include_file.inc silent. Useful when including scripts that contain platform dependent parameters, for example: --let $rpl_server_parameters=--log-bin=$tmpdir/slave-bin --relay-log=$tmpdir/slave-relay-bin --let $keep_include_silent=1 source include/rpl_start_server.inc; --let $keep_include_silent=0 We want the paths ($tmpdir/slave-bin and $tmpdir/slave-relay-bin) not to be in the result file. mysql-test/suite/rpl/t/rpl_binlog_index.test: Test case. sql/log.cc: When finding the corresponding log entry in the index file, we first normalize the paths before doing the comparison. This will make relative paths to be turned into absolute paths (based on the opt_bin_logname or opt_relay_logname) and then compared against also, expanded paths entered, through CHANGE MASTER for instance. sql/log.h: Added normalize_binlog_name, which turns relative paths, into absolute paths given the parameter: is_relay_log ? opt_relay_logname : opt_bin_logname . sql/mysqld.cc: Exposing opt_bin_logname. sql/mysqld.h: Exposing opt_bin_logname. --- mysql-test/include/begin_include_file.inc | 10 +- .../suite/rpl/r/rpl_binlog_index.result | 35 ++++ mysql-test/suite/rpl/t/rpl_binlog_index.test | 160 ++++++++++++++++++ sql/log.cc | 56 ++++-- sql/log.h | 62 +++++++ sql/mysqld.cc | 3 +- sql/mysqld.h | 3 +- 7 files changed, 315 insertions(+), 14 deletions(-) create mode 100644 mysql-test/suite/rpl/r/rpl_binlog_index.result create mode 100644 mysql-test/suite/rpl/t/rpl_binlog_index.test diff --git a/mysql-test/include/begin_include_file.inc b/mysql-test/include/begin_include_file.inc index 1b69fb0e52d..6c438f3df30 100644 --- a/mysql-test/include/begin_include_file.inc +++ b/mysql-test/include/begin_include_file.inc @@ -48,6 +48,11 @@ # must be provided both for begin_include_file.inc and # end_include_file.inc. # +# $keep_include_silent +# This specifies whether it should be echoed to the result file +# the following string: include/$include_filename +# If not set, the string will be echoed. +# # $rpl_debug # If set, this script will print the following text: # ==== BEGIN include/$include_filename.inc ==== @@ -59,7 +64,10 @@ # recursively. if (!$_include_file_depth) { - --echo include/$include_filename + if (!$keep_include_silent) + { + --echo include/$include_filename + } --let $_include_file_depth= 0 } --inc $_include_file_depth diff --git a/mysql-test/suite/rpl/r/rpl_binlog_index.result b/mysql-test/suite/rpl/r/rpl_binlog_index.result new file mode 100644 index 00000000000..9861a156a62 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_binlog_index.result @@ -0,0 +1,35 @@ +include/master-slave.inc +[connection master] +CREATE TABLE t1 (a INT); +FLUSH BINARY LOGS; +INSERT INTO t1 VALUES (1); +# Shutdown master +include/rpl_stop_server.inc [server_number=1] +# Move the master binlog files and the index file to a new place +# Restart master with log-bin option set to the new path +# Master has restarted successfully +# Create the master-bin.index file with the old format +# Shutdown master +include/rpl_stop_server.inc [server_number=1] +# Move back the master binlog files +# Remove the unneeded master-bin.index file +# Restart master with log-bin option set to default +# Master has restarted successfully +include/stop_slave.inc +# Move the slave binlog and relay log files and index to the new place +# Shutdown slave +include/rpl_stop_server.inc [server_number=2] +# Restart slave with options log-bin, relay-log set to the new paths +# Slave has restarted successfully +include/start_slave.inc +include/stop_slave.inc +FLUSH LOGS; +INSERT INTO t1 VALUES (2); +INSERT INTO t1 VALUES (2); +INSERT INTO t1 VALUES (2); +INSERT INTO t1 VALUES (2); +FLUSH LOGS; +FLUSH LOGS; +include/start_slave.inc +include/diff_tables.inc [master:t1,slave:t1] +DROP TABLE t1; diff --git a/mysql-test/suite/rpl/t/rpl_binlog_index.test b/mysql-test/suite/rpl/t/rpl_binlog_index.test new file mode 100644 index 00000000000..900a6819c2f --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_binlog_index.test @@ -0,0 +1,160 @@ +# ==== Purpose ==== +# +# Test that server can work fine after moving binlog or relay log +# files to another directory and setting binlog or relay log paths to +# the new path. +# +# ==== Method ==== +# +# Start replication, and then shutdown the master, move the binary +# logs and the log index file to a another directory and then restart +# the server with option to set the new binlog directory. After master +# restarted successfully, do the similar on slave to check the relay +# log of slave. +# +# ==== Reference ==== +# +# BUG#12133 master.index file keeps mysqld from starting if bin log has been moved +# BUG#42576 Relay logs in relay-log.info&localhost-relay-bin.index not processed after move + +source include/master-slave.inc; +# There is no need to run this test case on all binlog format +source include/have_binlog_format_row.inc; + +connection master; +--let $master_datadir= `select @@datadir` +connection slave; +--let $slave_datadir= `select @@datadir` +connection master; +--let $tmpdir= $MYSQLTEST_VARDIR/tmp/rpl_binlog_index +--mkdir $tmpdir + +CREATE TABLE t1 (a INT); +# flush to generate one more binlog file. +FLUSH BINARY LOGS; +INSERT INTO t1 VALUES (1); + +sync_slave_with_master; + + +# +# Test on master +# +connection master; +--echo # Shutdown master +--let $rpl_server_number=1 +source include/rpl_stop_server.inc; + +--echo # Move the master binlog files and the index file to a new place +--move_file $master_datadir/master-bin.000001 $tmpdir/master-bin.000001 +--move_file $master_datadir/master-bin.000002 $tmpdir/master-bin.000002 +--move_file $master_datadir/master-bin.index $tmpdir/master-bin.index + +--echo # Restart master with log-bin option set to the new path +--let $rpl_server_parameters=--log-bin=$tmpdir/master-bin +--let $keep_include_silent=1 +source include/rpl_start_server.inc; +--let $keep_include_silent=0 + +--echo # Master has restarted successfully + +# +# Test master can handle old format with directory path in index file +# +--let $is_windows= `select convert(@@version_compile_os using latin1) in ('Win32', 'Win64', 'Windows')` + +# write_var_to_file.inc will call SELECT INTO DUMPFILE, which has to be +# done before shutdown the server +--echo # Create the master-bin.index file with the old format +--let $write_to_file= $master_datadir/master-bin.index +if ($is_windows) +{ + --let $write_var= .\\master-bin.000001\n.\\master-bin.000002\n +} +if (!$is_windows) +{ + --let $write_var= ./master-bin.000001\n./master-bin.000002\n +} +--disable_query_log +source include/write_var_to_file.inc; +--enable_query_log + +--echo # Shutdown master +--let $rpl_server_number=1 +source include/rpl_stop_server.inc; + +--echo # Move back the master binlog files +--move_file $tmpdir/master-bin.000001 $master_datadir/master-bin.000001 +--move_file $tmpdir/master-bin.000002 $master_datadir/master-bin.000002 + +--echo # Remove the unneeded master-bin.index file +--remove_file $tmpdir/master-bin.index + +--echo # Restart master with log-bin option set to default +--let $rpl_server_parameters=--log-bin=$master_datadir/master-bin +--let $keep_include_silent=1 +source include/rpl_start_server.inc; +--let $keep_include_silent=0 + +--echo # Master has restarted successfully + +connection slave; +source include/stop_slave.inc; + +--disable_query_log +# slave-relay-bin.* files can vary, so read the slave-relay-bin.index +# to figure out the slave-relay-bin.* files +CREATE TEMPORARY TABLE tmp (id INT AUTO_INCREMENT PRIMARY KEY, filename VARCHAR(1024)); +# chmod to allow the following LOAD DATA +--chmod 0666 $slave_datadir/slave-relay-bin.index +--eval LOAD DATA INFILE '$slave_datadir/slave-relay-bin.index' INTO TABLE tmp (filename) +--let $count= `SELECT count(*) FROM tmp` +--echo # Move the slave binlog and relay log files and index to the new place +--move_file $slave_datadir/slave-bin.index $tmpdir/slave-bin.index +--move_file $slave_datadir/slave-bin.000001 $tmpdir/slave-bin.000001 +--move_file $slave_datadir/slave-relay-bin.index $tmpdir/slave-relay-bin.index +while ($count) +{ + --let $filename= `select filename from tmp where id=$count` + --move_file $slave_datadir/$filename $tmpdir/$filename + --dec $count +} +DROP TEMPORARY TABLE tmp; +--enable_query_log + +--echo # Shutdown slave +--let $rpl_server_number=2 +source include/rpl_stop_server.inc; + +--echo # Restart slave with options log-bin, relay-log set to the new paths +--let $rpl_server_parameters=--log-bin=$tmpdir/slave-bin --relay-log=$tmpdir/slave-relay-bin +--let $keep_include_silent=1 +source include/rpl_start_server.inc; +--let $keep_include_silent=0 + +--echo # Slave has restarted successfully +source include/start_slave.inc; +--source include/stop_slave.inc + +connection master; +FLUSH LOGS; +INSERT INTO t1 VALUES (2); +INSERT INTO t1 VALUES (2); +INSERT INTO t1 VALUES (2); +INSERT INTO t1 VALUES (2); + +FLUSH LOGS; + +connection slave; +FLUSH LOGS; +--source include/start_slave.inc +connection master; +sync_slave_with_master; +--let $diff_tables= master:t1,slave:t1 +source include/diff_tables.inc; + +connection master; +DROP TABLE t1; +sync_slave_with_master; +--remove_files_wildcard $tmpdir * +--rmdir $tmpdir diff --git a/sql/log.cc b/sql/log.cc index 77ba7aa6283..ec4c01003e0 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -3242,10 +3242,11 @@ int MYSQL_BIN_LOG::find_log_pos(LOG_INFO *linfo, const char *log_name, bool need_lock) { int error= 0; - char *fname= linfo->log_file_name; - uint log_name_len= log_name ? (uint) strlen(log_name) : 0; + char *full_fname= linfo->log_file_name; + char full_log_name[FN_REFLEN], fname[FN_REFLEN]; + uint log_name_len= 0, fname_len= 0; DBUG_ENTER("find_log_pos"); - DBUG_PRINT("enter",("log_name: %s", log_name ? log_name : "NULL")); + full_log_name[0]= full_fname[0]= 0; /* Mutex needed because we need to make sure the file pointer does not @@ -3255,6 +3256,20 @@ int MYSQL_BIN_LOG::find_log_pos(LOG_INFO *linfo, const char *log_name, mysql_mutex_lock(&LOCK_index); mysql_mutex_assert_owner(&LOCK_index); + // extend relative paths for log_name to be searched + if (log_name) + { + if(normalize_binlog_name(full_log_name, log_name, is_relay_log)) + { + error= LOG_INFO_EOF; + goto end; + } + } + + log_name_len= log_name ? (uint) strlen(full_log_name) : 0; + DBUG_PRINT("enter", ("log_name: %s, full_log_name: %s", + log_name ? log_name : "NULL", full_log_name)); + /* As the file is flushed, we can't get an error here */ (void) reinit_io_cache(&index_file, READ_CACHE, (my_off_t) 0, 0, 0); @@ -3273,19 +3288,28 @@ int MYSQL_BIN_LOG::find_log_pos(LOG_INFO *linfo, const char *log_name, break; } + // extend relative paths and match against full path + if (normalize_binlog_name(full_fname, fname, is_relay_log)) + { + error= LOG_INFO_EOF; + break; + } + fname_len= (uint) strlen(full_fname); + // if the log entry matches, null string matching anything if (!log_name || - (log_name_len == length-1 && fname[log_name_len] == '\n' && - !memcmp(fname, log_name, log_name_len))) + (log_name_len == fname_len-1 && full_fname[log_name_len] == '\n' && + !memcmp(full_fname, full_log_name, log_name_len))) { - DBUG_PRINT("info",("Found log file entry")); - fname[length-1]=0; // remove last \n + DBUG_PRINT("info", ("Found log file entry")); + full_fname[fname_len-1]= 0; // remove last \n linfo->index_file_start_offset= offset; linfo->index_file_offset = my_b_tell(&index_file); break; } } +end: if (need_lock) mysql_mutex_unlock(&LOCK_index); DBUG_RETURN(error); @@ -3320,7 +3344,8 @@ int MYSQL_BIN_LOG::find_next_log(LOG_INFO* linfo, bool need_lock) { int error= 0; uint length; - char *fname= linfo->log_file_name; + char fname[FN_REFLEN]; + char *full_fname= linfo->log_file_name; if (need_lock) mysql_mutex_lock(&LOCK_index); @@ -3336,8 +3361,19 @@ int MYSQL_BIN_LOG::find_next_log(LOG_INFO* linfo, bool need_lock) error = !index_file.error ? LOG_INFO_EOF : LOG_INFO_IO; goto err; } - fname[length-1]=0; // kill \n - linfo->index_file_offset = my_b_tell(&index_file); + + if (fname[0] != 0) + { + if(normalize_binlog_name(full_fname, fname, is_relay_log)) + { + error= LOG_INFO_EOF; + goto err; + } + length= strlen(full_fname); + } + + full_fname[length-1]= 0; // kill \n + linfo->index_file_offset= my_b_tell(&index_file); err: if (need_lock) diff --git a/sql/log.h b/sql/log.h index 481bd545960..2e9d308e5e5 100644 --- a/sql/log.h +++ b/sql/log.h @@ -715,4 +715,66 @@ char *make_log_name(char *buff, const char *name, const char* log_ext); extern MYSQL_PLUGIN_IMPORT MYSQL_BIN_LOG mysql_bin_log; extern LOGGER logger; + +/** + Turns a relative log binary log path into a full path, based on the + opt_bin_logname or opt_relay_logname. + + @param from The log name we want to make into an absolute path. + @param to The buffer where to put the results of the + normalization. + @param is_relay_log Switch that makes is used inside to choose which + option (opt_bin_logname or opt_relay_logname) to + use when calculating the base path. + + @returns true if a problem occurs, false otherwise. + */ + +inline bool normalize_binlog_name(char *to, const char *from, bool is_relay_log) +{ + DBUG_ENTER("normalize_binlog_name"); + bool error= false; + char buff[FN_REFLEN]; + char *ptr= (char*) from; + char *opt_name= is_relay_log ? opt_relay_logname : opt_bin_logname; + + DBUG_ASSERT(from); + + /* opt_name is not null and not empty and from is a relative path */ + if (opt_name && opt_name[0] && from && !test_if_hard_path(from)) + { + // take the path from opt_name + // take the filename from from + char log_dirpart[FN_REFLEN], log_dirname[FN_REFLEN]; + size_t log_dirpart_len, log_dirname_len; + dirname_part(log_dirpart, opt_name, &log_dirpart_len); + dirname_part(log_dirname, from, &log_dirname_len); + + /* log may be empty => relay-log or log-bin did not + hold paths, just filename pattern */ + if (log_dirpart_len > 0) + { + /* create the new path name */ + if(fn_format(buff, from+log_dirname_len, log_dirpart, "", + MYF(MY_UNPACK_FILENAME | MY_SAFE_PATH)) == NULL) + { + error= true; + goto end; + } + + ptr= buff; + } + } + + DBUG_ASSERT(ptr); + + if (ptr) + strmake(to, ptr, strlen(ptr)); + +end: + DBUG_RETURN(error); +} + + + #endif /* LOG_H */ diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 0f5087c6ccf..285b10154ce 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -652,7 +652,7 @@ ulong master_retry_count=0; char *master_info_file; char *relay_log_info_file, *report_user, *report_password, *report_host; char *opt_relay_logname = 0, *opt_relaylog_index_name=0; -char *opt_logname, *opt_slow_logname; +char *opt_logname, *opt_slow_logname, *opt_bin_logname; /* Static variables */ @@ -677,7 +677,6 @@ static char **defaults_argv; static int remaining_argc; /** Remaining command line arguments (arguments), filtered by handle_options().*/ static char **remaining_argv; -static char *opt_bin_logname; int orig_argc; char **orig_argv; diff --git a/sql/mysqld.h b/sql/mysqld.h index fc9182ed02e..70089f56e4e 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -139,7 +139,8 @@ extern my_bool relay_log_recovery; extern uint test_flags,select_errors,ha_open_options; extern uint protocol_version, mysqld_port, dropping_tables; extern ulong delay_key_write_options; -extern char *opt_logname, *opt_slow_logname; +extern char *opt_logname, *opt_slow_logname, *opt_bin_logname, + *opt_relay_logname; extern char *opt_backup_history_logname, *opt_backup_progress_logname, *opt_backup_settings_name; extern const char *log_output_str; From 1670845c3b3364720881ad778e456c6b7d852397 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Thu, 24 Nov 2011 19:23:20 +0200 Subject: [PATCH 114/288] Fixed that one can use --maria-recover=backup,force (Before we only allowed one option) --- storage/maria/ha_maria.cc | 4 ++-- storage/maria/ha_maria.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/storage/maria/ha_maria.cc b/storage/maria/ha_maria.cc index 5661e1f06d7..4d1348bd07f 100644 --- a/storage/maria/ha_maria.cc +++ b/storage/maria/ha_maria.cc @@ -60,7 +60,7 @@ ulonglong pagecache_buffer_size; good. It would happen only after Recovery, if the table is still corrupted. */ -ulong maria_recover_options= HA_RECOVER_NONE; +ulonglong maria_recover_options= HA_RECOVER_NONE; handlerton *maria_hton; /* bits in maria_recover_options */ @@ -198,7 +198,7 @@ static MYSQL_SYSVAR_ULONG(pagecache_division_limit, pagecache_division_limit, "The minimum percentage of warm blocks in key cache", 0, 0, 100, 1, 100, 1); -static MYSQL_SYSVAR_ENUM(recover, maria_recover_options, PLUGIN_VAR_OPCMDARG, +static MYSQL_SYSVAR_SET(recover, maria_recover_options, PLUGIN_VAR_OPCMDARG, "Specifies how corrupted tables should be automatically repaired." " Possible values are \"NORMAL\" (the default), \"BACKUP\", \"FORCE\"," " \"QUICK\", or \"OFF\" which is like not using the option.", diff --git a/storage/maria/ha_maria.h b/storage/maria/ha_maria.h index 6171f89cb18..f326efe17a2 100644 --- a/storage/maria/ha_maria.h +++ b/storage/maria/ha_maria.h @@ -30,7 +30,7 @@ extern ulong maria_sort_buffer_size; extern TYPELIB maria_recover_typelib; -extern ulong maria_recover_options; +extern ulonglong maria_recover_options; class ha_maria :public handler { From adb4e64eaf2bbdb56a553144511820a327a79774 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Thu, 24 Nov 2011 12:19:37 -0800 Subject: [PATCH 115/288] Currently innodb_plugin does not support ICP. --- .../suite/innodb_plugin/r/innodb_lock_wait_timeout_1.result | 5 ++++- .../suite/innodb_plugin/t/innodb_lock_wait_timeout_1.test | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/mysql-test/suite/innodb_plugin/r/innodb_lock_wait_timeout_1.result b/mysql-test/suite/innodb_plugin/r/innodb_lock_wait_timeout_1.result index e8ba522af2e..3329d420edc 100644 --- a/mysql-test/suite/innodb_plugin/r/innodb_lock_wait_timeout_1.result +++ b/mysql-test/suite/innodb_plugin/r/innodb_lock_wait_timeout_1.result @@ -97,6 +97,8 @@ insert into t1 values (1,1), (2,null), (3,1), (4,1), # Demonstrate that for the SELECT statement # used later in the test JT_EQ_REF access method is used. # +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='index_condition_pushdown=off'; explain select 1 from t1 natural join (select 2 as a, 1 as b union all select 2 as a, 2 as b) as t2 for update; @@ -119,7 +121,7 @@ key PRIMARY key_len 4 ref t2.a rows 1 -Extra Using index condition; Using where +Extra Using where id 2 select_type DERIVED table NULL @@ -150,6 +152,7 @@ key_len NULL ref NULL rows NULL Extra +set optimizer_switch=@tmp_optimizer_switch; # # Demonstrate that the reported SELECT statement # no longer produces warnings. diff --git a/mysql-test/suite/innodb_plugin/t/innodb_lock_wait_timeout_1.test b/mysql-test/suite/innodb_plugin/t/innodb_lock_wait_timeout_1.test index d7272779bdd..5d5f78093a7 100644 --- a/mysql-test/suite/innodb_plugin/t/innodb_lock_wait_timeout_1.test +++ b/mysql-test/suite/innodb_plugin/t/innodb_lock_wait_timeout_1.test @@ -140,9 +140,12 @@ insert into t1 values (1,1), (2,null), (3,1), (4,1), --echo # used later in the test JT_EQ_REF access method is used. --echo # --vertical_results +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='index_condition_pushdown=off'; explain select 1 from t1 natural join (select 2 as a, 1 as b union all select 2 as a, 2 as b) as t2 for update; +set optimizer_switch=@tmp_optimizer_switch; --horizontal_results --echo # --echo # Demonstrate that the reported SELECT statement From dc1b1d39a19bbd07ddc361d0cdbeb0d611b5e5df Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 24 Nov 2011 23:15:40 +0200 Subject: [PATCH 116/288] Fix bug lp:894326 The patch also fixes an unrelated compiler warning. Analysis: The temporary table created during SJ-materialization might be used for sorting for a group by operation. The sort buffers for this internal temporary table were not cleared by the execution code after each subquery re-execution. This resulted in a memory leak detected by valgrind. Solution: Cleanup the sort buffers for the semijon tables as well. sql/item_subselect.cc: - Fix a compiler warning and add logic to revert to table scan partial match when there are more rows in the materialized subquery than there can be bits in the NULL bitmap index used for partial matching. sql/opt_subselect.cc: - Fixed a memory leak detected by valgrind --- sql/item_subselect.cc | 16 ++++++++++++++-- sql/opt_subselect.cc | 2 ++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 16b23045cca..e131c9b0c9b 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -4024,6 +4024,7 @@ ulonglong subselect_hash_sj_engine::rowid_merge_buff_size( uint rowid_length= tmp_table->file->ref_length; select_materialize_with_stats *result_sink= (select_materialize_with_stats *) result; + ha_rows max_null_row; /* Size of the subselect_rowid_merge_engine::row_num_to_rowid buffer. */ buff_size= row_count * rowid_length * sizeof(uchar); @@ -4046,7 +4047,18 @@ ulonglong subselect_hash_sj_engine::rowid_merge_buff_size( buff_size+= (row_count - result_sink->get_null_count_of_col(i)) * sizeof(rownum_t); /* Add the size of Ordered_key::null_key */ - buff_size+= bitmap_buffer_size(result_sink->get_max_null_of_col(i)); + max_null_row= result_sink->get_max_null_of_col(i); + if (max_null_row >= UINT_MAX) + { + /* + There can be at most UINT_MAX bits in a MY_BITMAP that is used to + store NULLs in an Ordered_key. Return a number of bytes bigger than + the maximum allowed memory buffer for partial matching to disable + the rowid merge strategy. + */ + return ULONGLONG_MAX; + } + buff_size+= bitmap_buffer_size(max_null_row); } } @@ -5588,7 +5600,7 @@ exists_complementing_null_row(MY_BITMAP *keys_to_complement) return bitmap_exists_intersection((const MY_BITMAP**) null_bitmaps, count_null_keys, - highest_min_row, lowest_max_row); + (uint)highest_min_row, (uint)lowest_max_row); } diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index 19ea846e7b5..b61d5c421b2 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -4075,6 +4075,8 @@ int clear_sj_tmp_tables(JOIN *join) { if ((res= table->file->ha_delete_all_rows())) return res; /* purecov: inspected */ + free_io_cache(table); + filesort_free_buffers(table,0); } SJ_MATERIALIZATION_INFO *sjm; From 81f22df467087e0e2c9273e47eaee02a2a25d141 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 24 Nov 2011 23:47:50 +0200 Subject: [PATCH 117/288] Added valgrind suppression for an error due to http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=577135 --- mysql-test/valgrind.supp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/mysql-test/valgrind.supp b/mysql-test/valgrind.supp index 3edb7df03b3..0297b9ff650 100644 --- a/mysql-test/valgrind.supp +++ b/mysql-test/valgrind.supp @@ -273,6 +273,15 @@ fun:do_flush } +{ + libz inflatereset2 + Memcheck:Cond + fun:inflateReset2 + fun:inflateInit2_ + fun:uncompress +} + + # # Warning from my_thread_init becasue mysqld dies before kill thread exists # From f84dbf4b205f311f379a8fd0c6dc1f0fd893e073 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Fri, 25 Nov 2011 05:56:58 +0400 Subject: [PATCH 118/288] Semi-join optimizations code cleanup part 2: - Make EXPLAIN display "Start temporary" at the start of the fanout (it used to display at the first table whose rowid gets into temp. table which is not that useful for the user) - Updated test results (all checked) --- mysql-test/r/subselect.result | 8 +- mysql-test/r/subselect3.result | 48 ++++---- mysql-test/r/subselect3_jcl6.result | 48 ++++---- mysql-test/r/subselect_extra.result | 20 ++-- mysql-test/r/subselect_no_mat.result | 8 +- mysql-test/r/subselect_no_scache.result | 8 +- mysql-test/r/subselect_sj.result | 40 +++---- mysql-test/r/subselect_sj2.result | 6 +- mysql-test/r/subselect_sj2_jcl6.result | 6 +- mysql-test/r/subselect_sj2_mat.result | 6 +- mysql-test/r/subselect_sj_jcl6.result | 46 +++---- mysql-test/r/subselect_sj_mat.result | 98 ++++++++------- mysql-test/t/subselect_sj2.test | 2 +- sql/opt_subselect.cc | 153 +++++++++++++----------- sql/opt_subselect.h | 3 +- sql/sql_select.cc | 10 +- sql/sql_select.h | 2 + 17 files changed, 263 insertions(+), 249 deletions(-) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index b87aa59a037..be6f644a8d2 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -5146,8 +5146,8 @@ explain SELECT * FROM ot1,ot4 WHERE (ot1.a,ot4.a) IN (SELECT it2.a,it3.a FROM it2,it3); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY ot1 ALL NULL NULL NULL NULL 2 Start temporary -1 PRIMARY it2 ALL NULL NULL NULL NULL 4 Using where; Using join buffer (flat, BNL join) +1 PRIMARY ot1 ALL NULL NULL NULL NULL 2 +1 PRIMARY it2 ALL NULL NULL NULL NULL 4 Using where; Start temporary; Using join buffer (flat, BNL join) 1 PRIMARY it3 ALL NULL NULL NULL NULL 6 Using join buffer (flat, BNL join) 1 PRIMARY ot4 ALL NULL NULL NULL NULL 8 Using where; End temporary; Using join buffer (flat, BNL join) DROP TABLE IF EXISTS ot1, ot4, it2, it3; @@ -5192,8 +5192,8 @@ INSERT INTO t2 VALUES (12,2); INSERT INTO t2 VALUES (15,4); EXPLAIN SELECT * FROM t1 WHERE pk IN (SELECT it.pk FROM t2 JOIN t2 AS it ON 1); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t1 ALL PRIMARY NULL NULL NULL 3 Start temporary -1 PRIMARY t2 index NULL PRIMARY 4 NULL 3 Using index; Using join buffer (flat, BNL join) +1 PRIMARY t1 ALL PRIMARY NULL NULL NULL 3 +1 PRIMARY t2 index NULL PRIMARY 4 NULL 3 Using index; Start temporary; Using join buffer (flat, BNL join) 1 PRIMARY it eq_ref PRIMARY PRIMARY 4 test.t1.pk 1 Using index; End temporary SELECT * FROM t1 WHERE pk IN (SELECT it.pk FROM t2 JOIN t2 AS it ON 1); pk i diff --git a/mysql-test/r/subselect3.result b/mysql-test/r/subselect3.result index 1279fc6b8f4..c945efb4448 100644 --- a/mysql-test/r/subselect3.result +++ b/mysql-test/r/subselect3.result @@ -1045,8 +1045,8 @@ explain select (select max(Y.a) from t1 Y where a in (select a from t1 Z) and a < X.a) as subq from t1 X; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY X ALL NULL NULL NULL NULL 2 -2 DEPENDENT SUBQUERY Y ALL NULL NULL NULL NULL 2 Using where; Start temporary -2 DEPENDENT SUBQUERY Z ALL NULL NULL NULL NULL 2 Using where; End temporary; Using join buffer (flat, BNL join) +2 DEPENDENT SUBQUERY Y ALL NULL NULL NULL NULL 2 Using where +2 DEPENDENT SUBQUERY Z ALL NULL NULL NULL NULL 2 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) select (select max(Y.a) from t1 Y where a in (select a from t1 Z) and a < X.a) as subq from t1 X; subq NULL @@ -1186,27 +1186,27 @@ insert into t3 select * from t1; insert into t3 values (1),(2); explain select * from t2 where a in (select a from t1); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Start temporary -1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 +1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) explain select * from t2 where a in (select a from t2); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Start temporary -1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) explain select * from t2 where a in (select a from t3); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Start temporary -1 PRIMARY t3 ALL NULL NULL NULL NULL 6 Using where; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 +1 PRIMARY t3 ALL NULL NULL NULL NULL 6 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) explain select * from t1 where a in (select a from t3); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Start temporary -1 PRIMARY t3 ALL NULL NULL NULL NULL 6 Using where; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY t1 ALL NULL NULL NULL NULL 4 +1 PRIMARY t3 ALL NULL NULL NULL NULL 6 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) drop table t1, t2, t3; create table t1 (a decimal); insert into t1 values (1),(2); explain select * from t1 where a in (select a from t1); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Start temporary -1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) drop table t1; set @@optimizer_switch=@save_optimizer_switch; create table t1 (a int); @@ -1216,8 +1216,8 @@ create table t3 (a int, b int, filler char(100), key(a)); insert into t3 select A.a + 10*B.a, A.a + 10*B.a, 'filler' from t1 A, t1 B, t1 C; explain select * from t1, t3 where t3.a in (select a from t2) and (t3.a < 10 or t3.a >30) and t1.a =3; id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t1 ALL NULL NULL NULL NULL 10 Using where; Start temporary -1 PRIMARY t2 ALL NULL NULL NULL NULL 10 Using where; Using join buffer (flat, BNL join) +1 PRIMARY t1 ALL NULL NULL NULL NULL 10 Using where +1 PRIMARY t2 ALL NULL NULL NULL NULL 10 Using where; Start temporary; Using join buffer (flat, BNL join) 1 PRIMARY t3 ref a a 5 test.t2.a 10 End temporary explain select straight_join * from t1 A, t1 B where A.a in (select a from t2); id select_type table type possible_keys key key_len ref rows Extra @@ -1276,14 +1276,14 @@ insert into t2 select A.a + 10*B.a, A.a + 10*B.a from t0 A, t0 B; set @@optimizer_switch='firstmatch=off'; explain select * from t1 where (a,b) in (select a,b from t2); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t1 ALL NULL NULL NULL NULL 10 Start temporary -1 PRIMARY t2 ALL NULL NULL NULL NULL 100 Using where; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY t1 ALL NULL NULL NULL NULL 10 +1 PRIMARY t2 ALL NULL NULL NULL NULL 100 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) set @save_optimizer_search_depth=@@optimizer_search_depth; set @@optimizer_search_depth=63; explain select * from t1 where (a,b) in (select a,b from t2); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t1 ALL NULL NULL NULL NULL 10 Start temporary -1 PRIMARY t2 ALL NULL NULL NULL NULL 100 Using where; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY t1 ALL NULL NULL NULL NULL 10 +1 PRIMARY t2 ALL NULL NULL NULL NULL 100 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) set @@optimizer_search_depth=@save_optimizer_search_depth; set @@optimizer_switch=@save_optimizer_switch; drop table t0, t1, t2; @@ -1293,8 +1293,8 @@ create table t1 as select * from t0; insert into t1 select * from t0; explain select * from t0 where a in (select a from t1); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t0 ALL NULL NULL NULL NULL 2 Start temporary -1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY t0 ALL NULL NULL NULL NULL 2 +1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) select * from t0 where a in (select a from t1); a 10.24 @@ -1306,8 +1306,8 @@ create table t1 as select * from t0; insert into t1 select * from t0; explain select * from t0 where a in (select a from t1); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t0 ALL NULL NULL NULL NULL 2 Start temporary -1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY t0 ALL NULL NULL NULL NULL 2 +1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) select * from t0 where a in (select a from t1); a 2008-01-01 @@ -1320,8 +1320,8 @@ create table t2 as select a as a, a as b from t0 where a < 3; insert into t2 select * from t2; explain select * from t1 where (a,b,c) in (select X.a, Y.a, Z.a from t2 X, t2 Y, t2 Z where X.b=33); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Start temporary -1 PRIMARY X ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join) +1 PRIMARY t1 ALL NULL NULL NULL NULL 3 +1 PRIMARY X ALL NULL NULL NULL NULL 6 Using where; Start temporary; Using join buffer (flat, BNL join) 1 PRIMARY Y ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join) 1 PRIMARY Z ALL NULL NULL NULL NULL 6 Using where; End temporary; Using join buffer (flat, BNL join) drop table t0,t1,t2; diff --git a/mysql-test/r/subselect3_jcl6.result b/mysql-test/r/subselect3_jcl6.result index 15dd920d95d..8c8e448a836 100644 --- a/mysql-test/r/subselect3_jcl6.result +++ b/mysql-test/r/subselect3_jcl6.result @@ -1054,8 +1054,8 @@ explain select (select max(Y.a) from t1 Y where a in (select a from t1 Z) and a < X.a) as subq from t1 X; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY X ALL NULL NULL NULL NULL 2 -2 DEPENDENT SUBQUERY Y ALL NULL NULL NULL NULL 2 Using where; Start temporary -2 DEPENDENT SUBQUERY Z hash_ALL NULL #hash#$hj 5 test.Y.a 2 Using where; End temporary; Using join buffer (flat, BNLH join) +2 DEPENDENT SUBQUERY Y ALL NULL NULL NULL NULL 2 Using where +2 DEPENDENT SUBQUERY Z hash_ALL NULL #hash#$hj 5 test.Y.a 2 Using where; Start temporary; End temporary; Using join buffer (flat, BNLH join) select (select max(Y.a) from t1 Y where a in (select a from t1 Z) and a < X.a) as subq from t1 X; subq NULL @@ -1195,27 +1195,27 @@ insert into t3 select * from t1; insert into t3 values (1),(2); explain select * from t2 where a in (select a from t1); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where; Start temporary -1 PRIMARY t1 hash_ALL NULL #hash#$hj 4 test.t2.a 4 Using where; End temporary; Using join buffer (flat, BNLH join) +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where +1 PRIMARY t1 hash_ALL NULL #hash#$hj 4 test.t2.a 4 Using where; Start temporary; End temporary; Using join buffer (flat, BNLH join) explain select * from t2 where a in (select a from t2); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where; Start temporary -1 PRIMARY t2 hash_ALL NULL #hash#$hj 5 test.t2.a 2 Using where; End temporary; Using join buffer (flat, BNLH join) +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where +1 PRIMARY t2 hash_ALL NULL #hash#$hj 5 test.t2.a 2 Using where; Start temporary; End temporary; Using join buffer (flat, BNLH join) explain select * from t2 where a in (select a from t3); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Start temporary -1 PRIMARY t3 ALL NULL NULL NULL NULL 6 Using where; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 +1 PRIMARY t3 ALL NULL NULL NULL NULL 6 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) explain select * from t1 where a in (select a from t3); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Start temporary -1 PRIMARY t3 ALL NULL NULL NULL NULL 6 Using where; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY t1 ALL NULL NULL NULL NULL 4 +1 PRIMARY t3 ALL NULL NULL NULL NULL 6 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) drop table t1, t2, t3; create table t1 (a decimal); insert into t1 values (1),(2); explain select * from t1 where a in (select a from t1); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where; Start temporary -1 PRIMARY t1 hash_ALL NULL #hash#$hj 6 test.t1.a 2 Using where; End temporary; Using join buffer (flat, BNLH join) +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where +1 PRIMARY t1 hash_ALL NULL #hash#$hj 6 test.t1.a 2 Using where; Start temporary; End temporary; Using join buffer (flat, BNLH join) drop table t1; set @@optimizer_switch=@save_optimizer_switch; create table t1 (a int); @@ -1225,8 +1225,8 @@ create table t3 (a int, b int, filler char(100), key(a)); insert into t3 select A.a + 10*B.a, A.a + 10*B.a, 'filler' from t1 A, t1 B, t1 C; explain select * from t1, t3 where t3.a in (select a from t2) and (t3.a < 10 or t3.a >30) and t1.a =3; id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t1 ALL NULL NULL NULL NULL 10 Using where; Start temporary -1 PRIMARY t2 ALL NULL NULL NULL NULL 10 Using where; Using join buffer (flat, BNL join) +1 PRIMARY t1 ALL NULL NULL NULL NULL 10 Using where +1 PRIMARY t2 ALL NULL NULL NULL NULL 10 Using where; Start temporary; Using join buffer (flat, BNL join) 1 PRIMARY t3 ref a a 5 test.t2.a 10 End temporary; Using join buffer (incremental, BKA join); Key-ordered Rowid-ordered scan explain select straight_join * from t1 A, t1 B where A.a in (select a from t2); id select_type table type possible_keys key key_len ref rows Extra @@ -1285,14 +1285,14 @@ insert into t2 select A.a + 10*B.a, A.a + 10*B.a from t0 A, t0 B; set @@optimizer_switch='firstmatch=off'; explain select * from t1 where (a,b) in (select a,b from t2); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t1 ALL NULL NULL NULL NULL 10 Using where; Start temporary -1 PRIMARY t2 hash_ALL NULL #hash#$hj 10 test.t1.a,test.t1.b 100 Using where; End temporary; Using join buffer (flat, BNLH join) +1 PRIMARY t1 ALL NULL NULL NULL NULL 10 Using where +1 PRIMARY t2 hash_ALL NULL #hash#$hj 10 test.t1.a,test.t1.b 100 Using where; Start temporary; End temporary; Using join buffer (flat, BNLH join) set @save_optimizer_search_depth=@@optimizer_search_depth; set @@optimizer_search_depth=63; explain select * from t1 where (a,b) in (select a,b from t2); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t1 ALL NULL NULL NULL NULL 10 Using where; Start temporary -1 PRIMARY t2 hash_ALL NULL #hash#$hj 10 test.t1.a,test.t1.b 100 Using where; End temporary; Using join buffer (flat, BNLH join) +1 PRIMARY t1 ALL NULL NULL NULL NULL 10 Using where +1 PRIMARY t2 hash_ALL NULL #hash#$hj 10 test.t1.a,test.t1.b 100 Using where; Start temporary; End temporary; Using join buffer (flat, BNLH join) set @@optimizer_search_depth=@save_optimizer_search_depth; set @@optimizer_switch=@save_optimizer_switch; drop table t0, t1, t2; @@ -1302,8 +1302,8 @@ create table t1 as select * from t0; insert into t1 select * from t0; explain select * from t0 where a in (select a from t1); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t0 ALL NULL NULL NULL NULL 2 Using where; Start temporary -1 PRIMARY t1 hash_ALL NULL #hash#$hj 3 test.t0.a 4 Using where; End temporary; Using join buffer (flat, BNLH join) +1 PRIMARY t0 ALL NULL NULL NULL NULL 2 Using where +1 PRIMARY t1 hash_ALL NULL #hash#$hj 3 test.t0.a 4 Using where; Start temporary; End temporary; Using join buffer (flat, BNLH join) select * from t0 where a in (select a from t1); a 10.24 @@ -1315,8 +1315,8 @@ create table t1 as select * from t0; insert into t1 select * from t0; explain select * from t0 where a in (select a from t1); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t0 ALL NULL NULL NULL NULL 2 Using where; Start temporary -1 PRIMARY t1 hash_ALL NULL #hash#$hj 4 test.t0.a 4 Using where; End temporary; Using join buffer (flat, BNLH join) +1 PRIMARY t0 ALL NULL NULL NULL NULL 2 Using where +1 PRIMARY t1 hash_ALL NULL #hash#$hj 4 test.t0.a 4 Using where; Start temporary; End temporary; Using join buffer (flat, BNLH join) select * from t0 where a in (select a from t1); a 2008-01-01 @@ -1329,8 +1329,8 @@ create table t2 as select a as a, a as b from t0 where a < 3; insert into t2 select * from t2; explain select * from t1 where (a,b,c) in (select X.a, Y.a, Z.a from t2 X, t2 Y, t2 Z where X.b=33); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where; Start temporary -1 PRIMARY X hash_ALL NULL #hash#$hj 5 test.t1.a 6 Using where; Using join buffer (flat, BNLH join) +1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where +1 PRIMARY X hash_ALL NULL #hash#$hj 5 test.t1.a 6 Using where; Start temporary; Using join buffer (flat, BNLH join) 1 PRIMARY Y hash_ALL NULL #hash#$hj 5 test.t1.b 6 Using where; Using join buffer (incremental, BNLH join) 1 PRIMARY Z hash_ALL NULL #hash#$hj 5 test.t1.c 6 Using where; End temporary; Using join buffer (incremental, BNLH join) drop table t0,t1,t2; diff --git a/mysql-test/r/subselect_extra.result b/mysql-test/r/subselect_extra.result index 3dfe2bab4a6..30b5586a0d6 100644 --- a/mysql-test/r/subselect_extra.result +++ b/mysql-test/r/subselect_extra.result @@ -12,16 +12,16 @@ insert into t2 values ('2001-01-01 1:1:1'), ('2001-01-01 1:1:1'); flush tables; EXPLAIN SELECT OUTR.dt FROM t1 AS OUTR WHERE OUTR.dt IN (SELECT INNR.dt FROM t2 AS INNR WHERE OUTR.dt IS NULL ); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY OUTR ALL NULL NULL NULL NULL 2 Using where; Start temporary -1 PRIMARY INNR ALL NULL NULL NULL NULL 2 Using where; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY OUTR ALL NULL NULL NULL NULL 2 Using where +1 PRIMARY INNR ALL NULL NULL NULL NULL 2 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) flush tables; SELECT OUTR.dt FROM t1 AS OUTR WHERE OUTR.dt IN (SELECT INNR.dt FROM t2 AS INNR WHERE OUTR.dt IS NULL ); dt flush tables; EXPLAIN SELECT OUTR.dt FROM t1 AS OUTR WHERE OUTR.dt IN ( SELECT INNR.dt FROM t2 AS INNR WHERE OUTR.t < '2005-11-13 7:41:31' ); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY OUTR ALL NULL NULL NULL NULL 2 Using where; Start temporary -1 PRIMARY INNR ALL NULL NULL NULL NULL 2 Using where; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY OUTR ALL NULL NULL NULL NULL 2 Using where +1 PRIMARY INNR ALL NULL NULL NULL NULL 2 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) flush tables; SELECT OUTR.dt FROM t1 AS OUTR WHERE OUTR.dt IN ( SELECT INNR.dt FROM t2 AS INNR WHERE OUTR.t < '2005-11-13 7:41:31' ); dt @@ -64,8 +64,8 @@ explain extended select * from t1 where id in (select id from t1 as x1 where (t1.cur_date is null)); 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 Using where; Start temporary -1 PRIMARY x1 ALL NULL NULL NULL NULL 2 100.00 Using where; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00 Using where +1 PRIMARY x1 ALL NULL NULL NULL NULL 2 100.00 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) Warnings: Note 1276 Field or reference 'test.t1.cur_date' of SELECT #2 was resolved in SELECT #1 Note 1003 select `test`.`t1`.`id` AS `id`,`test`.`t1`.`cur_date` AS `cur_date` from `test`.`t1` semi join (`test`.`t1` `x1`) where ((`test`.`x1`.`id` = `test`.`t1`.`id`) and (`test`.`t1`.`cur_date` = 0)) @@ -76,8 +76,8 @@ explain extended select * from t2 where id in (select id from t2 as x1 where (t2.cur_date is null)); id select_type table type possible_keys key key_len ref rows filtered Extra -1 PRIMARY t2 ALL NULL NULL NULL NULL 2 100.00 Using where; Start temporary -1 PRIMARY x1 ALL NULL NULL NULL NULL 2 100.00 Using where; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 100.00 Using where +1 PRIMARY x1 ALL NULL NULL NULL NULL 2 100.00 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) Warnings: Note 1276 Field or reference 'test.t2.cur_date' of SELECT #2 was resolved in SELECT #1 Note 1003 select `test`.`t2`.`id` AS `id`,`test`.`t2`.`cur_date` AS `cur_date` from `test`.`t2` semi join (`test`.`t2` `x1`) where ((`test`.`x1`.`id` = `test`.`t2`.`id`) and (`test`.`t2`.`cur_date` = 0)) @@ -427,8 +427,8 @@ WHERE t3.b IN (SELECT v1.b FROM v1, t2 WHERE t2.c = v1.c AND t2.c = v1.b AND v1.b = t3.c); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 system NULL NULL NULL NULL 1 -1 PRIMARY t3 ALL NULL NULL NULL NULL 2 Using where; Start temporary -1 PRIMARY ALL NULL NULL NULL NULL 3 Using where; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY t3 ALL NULL NULL NULL NULL 2 Using where +1 PRIMARY ALL NULL NULL NULL NULL 3 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) 3 DERIVED t1 ALL NULL NULL NULL NULL 3 SELECT * FROM t3 WHERE t3.b IN (SELECT v1.b FROM v1, t2 diff --git a/mysql-test/r/subselect_no_mat.result b/mysql-test/r/subselect_no_mat.result index 4827524ae63..df0d5fe8460 100644 --- a/mysql-test/r/subselect_no_mat.result +++ b/mysql-test/r/subselect_no_mat.result @@ -5151,8 +5151,8 @@ explain SELECT * FROM ot1,ot4 WHERE (ot1.a,ot4.a) IN (SELECT it2.a,it3.a FROM it2,it3); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY ot1 ALL NULL NULL NULL NULL 2 Start temporary -1 PRIMARY it2 ALL NULL NULL NULL NULL 4 Using where; Using join buffer (flat, BNL join) +1 PRIMARY ot1 ALL NULL NULL NULL NULL 2 +1 PRIMARY it2 ALL NULL NULL NULL NULL 4 Using where; Start temporary; Using join buffer (flat, BNL join) 1 PRIMARY it3 ALL NULL NULL NULL NULL 6 Using join buffer (flat, BNL join) 1 PRIMARY ot4 ALL NULL NULL NULL NULL 8 Using where; End temporary; Using join buffer (flat, BNL join) DROP TABLE IF EXISTS ot1, ot4, it2, it3; @@ -5197,8 +5197,8 @@ INSERT INTO t2 VALUES (12,2); INSERT INTO t2 VALUES (15,4); EXPLAIN SELECT * FROM t1 WHERE pk IN (SELECT it.pk FROM t2 JOIN t2 AS it ON 1); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t1 ALL PRIMARY NULL NULL NULL 3 Start temporary -1 PRIMARY t2 index NULL PRIMARY 4 NULL 3 Using index; Using join buffer (flat, BNL join) +1 PRIMARY t1 ALL PRIMARY NULL NULL NULL 3 +1 PRIMARY t2 index NULL PRIMARY 4 NULL 3 Using index; Start temporary; Using join buffer (flat, BNL join) 1 PRIMARY it eq_ref PRIMARY PRIMARY 4 test.t1.pk 1 Using index; End temporary SELECT * FROM t1 WHERE pk IN (SELECT it.pk FROM t2 JOIN t2 AS it ON 1); pk i diff --git a/mysql-test/r/subselect_no_scache.result b/mysql-test/r/subselect_no_scache.result index 756431a2c6b..0a88d82e3d8 100644 --- a/mysql-test/r/subselect_no_scache.result +++ b/mysql-test/r/subselect_no_scache.result @@ -5150,8 +5150,8 @@ explain SELECT * FROM ot1,ot4 WHERE (ot1.a,ot4.a) IN (SELECT it2.a,it3.a FROM it2,it3); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY ot1 ALL NULL NULL NULL NULL 2 Start temporary -1 PRIMARY it2 ALL NULL NULL NULL NULL 4 Using where; Using join buffer (flat, BNL join) +1 PRIMARY ot1 ALL NULL NULL NULL NULL 2 +1 PRIMARY it2 ALL NULL NULL NULL NULL 4 Using where; Start temporary; Using join buffer (flat, BNL join) 1 PRIMARY it3 ALL NULL NULL NULL NULL 6 Using join buffer (flat, BNL join) 1 PRIMARY ot4 ALL NULL NULL NULL NULL 8 Using where; End temporary; Using join buffer (flat, BNL join) DROP TABLE IF EXISTS ot1, ot4, it2, it3; @@ -5196,8 +5196,8 @@ INSERT INTO t2 VALUES (12,2); INSERT INTO t2 VALUES (15,4); EXPLAIN SELECT * FROM t1 WHERE pk IN (SELECT it.pk FROM t2 JOIN t2 AS it ON 1); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t1 ALL PRIMARY NULL NULL NULL 3 Start temporary -1 PRIMARY t2 index NULL PRIMARY 4 NULL 3 Using index; Using join buffer (flat, BNL join) +1 PRIMARY t1 ALL PRIMARY NULL NULL NULL 3 +1 PRIMARY t2 index NULL PRIMARY 4 NULL 3 Using index; Start temporary; Using join buffer (flat, BNL join) 1 PRIMARY it eq_ref PRIMARY PRIMARY 4 test.t1.pk 1 Using index; End temporary SELECT * FROM t1 WHERE pk IN (SELECT it.pk FROM t2 JOIN t2 AS it ON 1); pk i diff --git a/mysql-test/r/subselect_sj.result b/mysql-test/r/subselect_sj.result index 99d8e9d2d77..2a4d7cd7f1e 100644 --- a/mysql-test/r/subselect_sj.result +++ b/mysql-test/r/subselect_sj.result @@ -1046,9 +1046,9 @@ WHERE t2.val LIKE 'a%' OR t2.val LIKE 'e%') AND t1.val IN (SELECT t3.val FROM t3 WHERE t3.val LIKE 'a%' OR t3.val LIKE 'e%'); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t1 ALL NULL NULL NULL NULL 5 Start temporary -1 PRIMARY t3 ALL NULL NULL NULL NULL 5 Using where; Using join buffer (flat, BNL join) -1 PRIMARY t2 ALL NULL NULL NULL NULL 6 Using where; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY t1 ALL NULL NULL NULL NULL 5 +1 PRIMARY t3 ALL NULL NULL NULL NULL 5 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY t2 ALL NULL NULL NULL NULL 6 Using where; FirstMatch(t3) SELECT * FROM t1 WHERE t1.val IN (SELECT t2.val FROM t2 @@ -1237,8 +1237,8 @@ A.t1field IN (SELECT A.t1field FROM t2 B) AND A.t1field IN (SELECT C.t2field FROM t2 C WHERE C.t2field IN (SELECT D.t2field FROM t2 D)); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY A index PRIMARY PRIMARY 4 NULL 3 Using index; Start temporary -1 PRIMARY B index NULL PRIMARY 4 NULL 3 Using index; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY A index PRIMARY PRIMARY 4 NULL 3 Using index +1 PRIMARY B index NULL PRIMARY 4 NULL 3 Using index; Start temporary; End temporary; Using join buffer (flat, BNL join) 1 PRIMARY C eq_ref PRIMARY PRIMARY 4 test.A.t1field 1 Using index 1 PRIMARY D eq_ref PRIMARY PRIMARY 4 test.A.t1field 1 Using index SELECT * FROM t1 A @@ -1266,10 +1266,10 @@ explain select * from t1 A, t1 B where A.a = B.a and A.a in (select a from t2 C) and B.a in (select a from t2 D); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY A ALL NULL NULL NULL NULL 3 Start temporary +1 PRIMARY A ALL NULL NULL NULL NULL 3 +1 PRIMARY C ALL NULL NULL NULL NULL 3 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) 1 PRIMARY B ALL NULL NULL NULL NULL 3 Using where; Using join buffer (flat, BNL join) -1 PRIMARY C ALL NULL NULL NULL NULL 3 Using where; Using join buffer (flat, BNL join) -1 PRIMARY D ALL NULL NULL NULL NULL 3 Using where; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY D ALL NULL NULL NULL NULL 3 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) drop table t1, t2; # # BUG#784441: Abort on semijoin with a view as the inner table @@ -1431,8 +1431,8 @@ set optimizer_switch='firstmatch=off,loosescan=off,materialization=off'; explain select * from t0 where a in (select t1.a from t1 left join t2 on t1.a=t2.a); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t0 ALL NULL NULL NULL NULL 2 Start temporary -1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where; Using join buffer (flat, BNL join) +1 PRIMARY t0 ALL NULL NULL NULL NULL 2 +1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where; Start temporary; Using join buffer (flat, BNL join) 1 PRIMARY t2 ALL NULL NULL NULL NULL 1 Using where; End temporary select * from t0 where a in (select t1.a from t1 left join t2 on t1.a=t2.a); a @@ -1490,8 +1490,8 @@ explain select * from t0 where a in (select t1.a from t1 left join (t3 join t2 on t3.b=t2.b) on t1.a=t3.a); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t0 ALL NULL NULL NULL NULL 2 Start temporary -1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where; Using join buffer (flat, BNL join) +1 PRIMARY t0 ALL NULL NULL NULL NULL 2 +1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where; Start temporary; Using join buffer (flat, BNL join) 1 PRIMARY t3 ALL NULL NULL NULL NULL 1 Using where 1 PRIMARY t2 ALL NULL NULL NULL NULL 1 Using where; End temporary select * from t0 @@ -1508,8 +1508,8 @@ explain select * from t0 where a in (select t1.a from t1 left join (t3 join t2 on t3.b=t2.b) on t1.a=t3.a); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t0 ALL NULL NULL NULL NULL 2 Start temporary -1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where; Using join buffer (flat, BNL join) +1 PRIMARY t0 ALL NULL NULL NULL NULL 2 +1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where; Start temporary; Using join buffer (flat, BNL join) 1 PRIMARY t2 ALL NULL NULL NULL NULL 1 1 PRIMARY t3 ALL NULL NULL NULL NULL 2 Using where; End temporary select * from t0 @@ -1703,10 +1703,10 @@ INSERT INTO t4 VALUES (0),(NULL); explain SELECT * FROM t1 NATURAL LEFT JOIN (t2, t3) WHERE IFNULL(t2.f3,'foo') IN (SELECT * FROM t4); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Start temporary +1 PRIMARY t1 ALL NULL NULL NULL NULL 3 1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where 1 PRIMARY t3 ALL NULL NULL NULL NULL 5 Using where -1 PRIMARY t4 ALL NULL NULL NULL NULL 2 Using where; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY t4 ALL NULL NULL NULL NULL 2 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) SELECT * FROM t1 NATURAL LEFT JOIN (t2, t3 ) WHERE IFNULL(t2.f3,'foo') IN (SELECT * FROM t4); f1 f2 f3 f3 2 0 0 0 @@ -1764,9 +1764,9 @@ INSERT INTO t3 VALUES (6,5),(6,2),(8,0),(9,1),(6,5); explain SELECT * FROM t1, t2 WHERE (t2.a , t1.b) IN (SELECT a, b FROM t3); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Start temporary +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 1 PRIMARY t2 index PRIMARY PRIMARY 4 NULL 2 Using index; Using join buffer (flat, BNL join) -1 PRIMARY t3 ALL b NULL NULL NULL 5 Using where; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY t3 ALL b NULL NULL NULL 5 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) SELECT * FROM t1, t2 WHERE (t2.a , t1.b) IN (SELECT a, b FROM t3); b a 5 6 @@ -1869,10 +1869,10 @@ alias1.c IN (SELECT SQ3_alias1.b FROM t2 AS SQ3_alias1 STRAIGHT_JOIN t2 AS SQ3_alias2) LIMIT 100; id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY ALL NULL NULL NULL NULL 20 Start temporary +1 PRIMARY ALL NULL NULL NULL NULL 20 1 PRIMARY alias2 ALL NULL NULL NULL NULL 20 Using join buffer (flat, BNL join) 1 PRIMARY t2 ALL NULL NULL NULL NULL 20 Using join buffer (flat, BNL join) -1 PRIMARY SQ3_alias1 ALL NULL NULL NULL NULL 20 Using where; Using join buffer (flat, BNL join) +1 PRIMARY SQ3_alias1 ALL NULL NULL NULL NULL 20 Using where; Start temporary; Using join buffer (flat, BNL join) 1 PRIMARY SQ3_alias2 index NULL PRIMARY 4 NULL 20 Using index; End temporary; Using join buffer (flat, BNL join) 2 DERIVED t2 ALL NULL NULL NULL NULL 20 create table t3 as diff --git a/mysql-test/r/subselect_sj2.result b/mysql-test/r/subselect_sj2.result index fe9136cfccc..ba347b9ef78 100644 --- a/mysql-test/r/subselect_sj2.result +++ b/mysql-test/r/subselect_sj2.result @@ -1,7 +1,7 @@ set @subselect_sj2_tmp= @@optimizer_switch; set optimizer_switch='semijoin=on,firstmatch=on,loosescan=on'; set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; -drop table if exists t0, t1, t2, t3; +drop table if exists t0, t1, t2, t3, t4, t5; drop view if exists v1; create table t0 (a int); insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); @@ -864,10 +864,10 @@ EXPLAIN SELECT * FROM t3 LEFT JOIN (v1,t2) ON t3.a = t2.a WHERE t3.b IN (SELECT b FROM t4); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t3 ALL NULL NULL NULL NULL 1 Start temporary +1 PRIMARY t3 ALL NULL NULL NULL NULL 1 1 PRIMARY t2 ALL NULL NULL NULL NULL 1 Using where 1 PRIMARY ALL NULL NULL NULL NULL 2 -1 PRIMARY t4 ALL NULL NULL NULL NULL 2 Using where; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY t4 ALL NULL NULL NULL NULL 2 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) 3 DERIVED t1 ALL NULL NULL NULL NULL 1 SELECT * FROM t3 LEFT JOIN (v1,t2) ON t3.a = t2.a WHERE t3.b IN (SELECT b FROM t4); diff --git a/mysql-test/r/subselect_sj2_jcl6.result b/mysql-test/r/subselect_sj2_jcl6.result index 0f85f87096d..834ea35c315 100644 --- a/mysql-test/r/subselect_sj2_jcl6.result +++ b/mysql-test/r/subselect_sj2_jcl6.result @@ -10,7 +10,7 @@ join_cache_level 6 set @subselect_sj2_tmp= @@optimizer_switch; set optimizer_switch='semijoin=on,firstmatch=on,loosescan=on'; set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; -drop table if exists t0, t1, t2, t3; +drop table if exists t0, t1, t2, t3, t4, t5; drop view if exists v1; create table t0 (a int); insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); @@ -875,10 +875,10 @@ EXPLAIN SELECT * FROM t3 LEFT JOIN (v1,t2) ON t3.a = t2.a WHERE t3.b IN (SELECT b FROM t4); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t3 ALL NULL NULL NULL NULL 1 Using where; Start temporary +1 PRIMARY t3 ALL NULL NULL NULL NULL 1 Using where 1 PRIMARY t2 hash_ALL NULL #hash#$hj 5 test.t3.a 1 Using where; Using join buffer (flat, BNLH join) 1 PRIMARY ALL NULL NULL NULL NULL 2 Using join buffer (incremental, BNL join) -1 PRIMARY t4 hash_ALL NULL #hash#$hj 5 test.t3.b 2 Using where; End temporary; Using join buffer (incremental, BNLH join) +1 PRIMARY t4 hash_ALL NULL #hash#$hj 5 test.t3.b 2 Using where; Start temporary; End temporary; Using join buffer (incremental, BNLH join) 3 DERIVED t1 ALL NULL NULL NULL NULL 1 SELECT * FROM t3 LEFT JOIN (v1,t2) ON t3.a = t2.a WHERE t3.b IN (SELECT b FROM t4); diff --git a/mysql-test/r/subselect_sj2_mat.result b/mysql-test/r/subselect_sj2_mat.result index 75d61d42c31..21635fa0a55 100644 --- a/mysql-test/r/subselect_sj2_mat.result +++ b/mysql-test/r/subselect_sj2_mat.result @@ -3,7 +3,7 @@ set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; set @subselect_sj2_tmp= @@optimizer_switch; set optimizer_switch='semijoin=on,firstmatch=on,loosescan=on'; set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; -drop table if exists t0, t1, t2, t3; +drop table if exists t0, t1, t2, t3, t4, t5; drop view if exists v1; create table t0 (a int); insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); @@ -333,8 +333,8 @@ WHERE Language='English' AND Percentage > 10 AND t2.Population > 100000); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 range Population,Country Population 4 NULL 1 Using index condition; Rowid-ordered scan; Start temporary -1 PRIMARY t2 eq_ref PRIMARY,Population PRIMARY 3 test.t1.Country 1 Using where -1 PRIMARY t3 eq_ref PRIMARY,Percentage PRIMARY 33 test.t1.Country,const 1 Using index condition; Using where; End temporary +1 PRIMARY t2 eq_ref PRIMARY,Population PRIMARY 3 test.t1.Country 1 Using where; End temporary +1 PRIMARY t3 eq_ref PRIMARY,Percentage PRIMARY 33 test.t1.Country,const 1 Using index condition; Using where set optimizer_switch=@bug35674_save_optimizer_switch; DROP TABLE t1,t2,t3; CREATE TABLE t1 ( diff --git a/mysql-test/r/subselect_sj_jcl6.result b/mysql-test/r/subselect_sj_jcl6.result index 2d1da2ea953..6fd1ed810ff 100644 --- a/mysql-test/r/subselect_sj_jcl6.result +++ b/mysql-test/r/subselect_sj_jcl6.result @@ -1057,9 +1057,9 @@ WHERE t2.val LIKE 'a%' OR t2.val LIKE 'e%') AND t1.val IN (SELECT t3.val FROM t3 WHERE t3.val LIKE 'a%' OR t3.val LIKE 'e%'); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t1 ALL NULL NULL NULL NULL 5 Start temporary -1 PRIMARY t3 ALL NULL NULL NULL NULL 5 Using where; Using join buffer (flat, BNL join) -1 PRIMARY t2 ALL NULL NULL NULL NULL 6 Using where; End temporary; Using join buffer (incremental, BNL join) +1 PRIMARY t1 ALL NULL NULL NULL NULL 5 +1 PRIMARY t3 ALL NULL NULL NULL NULL 5 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY t2 ALL NULL NULL NULL NULL 6 Using where; FirstMatch(t3); Using join buffer (incremental, BNL join) SELECT * FROM t1 WHERE t1.val IN (SELECT t2.val FROM t2 @@ -1248,8 +1248,8 @@ A.t1field IN (SELECT A.t1field FROM t2 B) AND A.t1field IN (SELECT C.t2field FROM t2 C WHERE C.t2field IN (SELECT D.t2field FROM t2 D)); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY A index PRIMARY PRIMARY 4 NULL 3 Using index; Start temporary -1 PRIMARY B index NULL PRIMARY 4 NULL 3 Using index; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY A index PRIMARY PRIMARY 4 NULL 3 Using index +1 PRIMARY B index NULL PRIMARY 4 NULL 3 Using index; Start temporary; End temporary; Using join buffer (flat, BNL join) 1 PRIMARY C eq_ref PRIMARY PRIMARY 4 test.A.t1field 1 Using index 1 PRIMARY D eq_ref PRIMARY PRIMARY 4 test.A.t1field 1 Using index SELECT * FROM t1 A @@ -1277,10 +1277,10 @@ explain select * from t1 A, t1 B where A.a = B.a and A.a in (select a from t2 C) and B.a in (select a from t2 D); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY A ALL NULL NULL NULL NULL 3 Start temporary -1 PRIMARY B ALL NULL NULL NULL NULL 3 Using where; Using join buffer (flat, BNL join) -1 PRIMARY C ALL NULL NULL NULL NULL 3 Using where; Using join buffer (incremental, BNL join) -1 PRIMARY D ALL NULL NULL NULL NULL 3 Using where; End temporary; Using join buffer (incremental, BNL join) +1 PRIMARY A ALL NULL NULL NULL NULL 3 +1 PRIMARY C ALL NULL NULL NULL NULL 3 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY B ALL NULL NULL NULL NULL 3 Using where; Using join buffer (incremental, BNL join) +1 PRIMARY D ALL NULL NULL NULL NULL 3 Using where; Start temporary; End temporary; Using join buffer (incremental, BNL join) drop table t1, t2; # # BUG#784441: Abort on semijoin with a view as the inner table @@ -1442,8 +1442,8 @@ set optimizer_switch='firstmatch=off,loosescan=off,materialization=off'; explain select * from t0 where a in (select t1.a from t1 left join t2 on t1.a=t2.a); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t0 ALL NULL NULL NULL NULL 2 Start temporary -1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where; Using join buffer (flat, BNL join) +1 PRIMARY t0 ALL NULL NULL NULL NULL 2 +1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where; Start temporary; Using join buffer (flat, BNL join) 1 PRIMARY t2 ALL NULL NULL NULL NULL 1 Using where; End temporary; Using join buffer (incremental, BNL join) select * from t0 where a in (select t1.a from t1 left join t2 on t1.a=t2.a); a @@ -1501,8 +1501,8 @@ explain select * from t0 where a in (select t1.a from t1 left join (t3 join t2 on t3.b=t2.b) on t1.a=t3.a); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t0 ALL NULL NULL NULL NULL 2 Start temporary -1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where; Using join buffer (flat, BNL join) +1 PRIMARY t0 ALL NULL NULL NULL NULL 2 +1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where; Start temporary; Using join buffer (flat, BNL join) 1 PRIMARY t3 ALL NULL NULL NULL NULL 1 Using where; Using join buffer (incremental, BNL join) 1 PRIMARY t2 ALL NULL NULL NULL NULL 1 Using where; End temporary; Using join buffer (incremental, BNL join) select * from t0 @@ -1519,8 +1519,8 @@ explain select * from t0 where a in (select t1.a from t1 left join (t3 join t2 on t3.b=t2.b) on t1.a=t3.a); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t0 ALL NULL NULL NULL NULL 2 Start temporary -1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where; Using join buffer (flat, BNL join) +1 PRIMARY t0 ALL NULL NULL NULL NULL 2 +1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where; Start temporary; Using join buffer (flat, BNL join) 1 PRIMARY t2 ALL NULL NULL NULL NULL 1 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 t0 @@ -1714,10 +1714,10 @@ INSERT INTO t4 VALUES (0),(NULL); explain SELECT * FROM t1 NATURAL LEFT JOIN (t2, t3) WHERE IFNULL(t2.f3,'foo') IN (SELECT * FROM t4); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Start temporary +1 PRIMARY t1 ALL NULL NULL NULL NULL 3 1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where; Using join buffer (flat, BNL join) 1 PRIMARY t3 ALL NULL NULL NULL NULL 5 Using where; Using join buffer (incremental, BNL join) -1 PRIMARY t4 ALL NULL NULL NULL NULL 2 Using where; End temporary; Using join buffer (incremental, BNL join) +1 PRIMARY t4 ALL NULL NULL NULL NULL 2 Using where; Start temporary; End temporary; Using join buffer (incremental, BNL join) SELECT * FROM t1 NATURAL LEFT JOIN (t2, t3 ) WHERE IFNULL(t2.f3,'foo') IN (SELECT * FROM t4); f1 f2 f3 f3 2 0 0 0 @@ -1775,9 +1775,9 @@ INSERT INTO t3 VALUES (6,5),(6,2),(8,0),(9,1),(6,5); explain SELECT * FROM t1, t2 WHERE (t2.a , t1.b) IN (SELECT a, b FROM t3); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Start temporary +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 1 PRIMARY t2 index PRIMARY PRIMARY 4 NULL 2 Using index; Using join buffer (flat, BNL join) -1 PRIMARY t3 ALL b NULL NULL NULL 5 Using where; End temporary; Using join buffer (incremental, BNL join) +1 PRIMARY t3 ALL b NULL NULL NULL 5 Using where; Start temporary; End temporary; Using join buffer (incremental, BNL join) SELECT * FROM t1, t2 WHERE (t2.a , t1.b) IN (SELECT a, b FROM t3); b a 5 6 @@ -1880,10 +1880,10 @@ alias1.c IN (SELECT SQ3_alias1.b FROM t2 AS SQ3_alias1 STRAIGHT_JOIN t2 AS SQ3_alias2) LIMIT 100; id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY ALL NULL NULL NULL NULL 20 Start temporary +1 PRIMARY ALL NULL NULL NULL NULL 20 1 PRIMARY alias2 ALL NULL NULL NULL NULL 20 Using join buffer (flat, BNL join) 1 PRIMARY t2 ALL NULL NULL NULL NULL 20 Using join buffer (incremental, BNL join) -1 PRIMARY SQ3_alias1 ALL NULL NULL NULL NULL 20 Using where; Using join buffer (incremental, BNL join) +1 PRIMARY SQ3_alias1 ALL NULL NULL NULL NULL 20 Using where; Start temporary; Using join buffer (incremental, BNL join) 1 PRIMARY SQ3_alias2 index NULL PRIMARY 4 NULL 20 Using index; End temporary; Using join buffer (incremental, BNL join) 2 DERIVED t2 ALL NULL NULL NULL NULL 20 create table t3 as @@ -2050,8 +2050,8 @@ explain SELECT * FROM t0 WHERE t0.a IN (SELECT t1.a FROM t1, t2 WHERE t2.a=t0.a AND t1.b=t2.b); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t0 ALL NULL NULL NULL NULL 5 Using where; Start temporary -1 PRIMARY t1 ref a a 5 test.t0.a 1 Using join buffer (flat, BKA join); Key-ordered Rowid-ordered scan +1 PRIMARY t0 ALL NULL NULL NULL NULL 5 Using where +1 PRIMARY t1 ref a a 5 test.t0.a 1 Start temporary; Using join buffer (flat, BKA join); Key-ordered Rowid-ordered scan 1 PRIMARY t2 eq_ref PRIMARY PRIMARY 4 test.t0.a 1 Using where; End temporary; Using join buffer (incremental, BKA join); Key-ordered Rowid-ordered scan SELECT * FROM t0 WHERE t0.a IN (SELECT t1.a FROM t1, t2 WHERE t2.a=t0.a AND t1.b=t2.b); diff --git a/mysql-test/r/subselect_sj_mat.result b/mysql-test/r/subselect_sj_mat.result index 465e482fb66..e6566d70ba3 100644 --- a/mysql-test/r/subselect_sj_mat.result +++ b/mysql-test/r/subselect_sj_mat.result @@ -297,11 +297,11 @@ where (a1, a2) in (select b1, b2 from t2 where b1 > '0') and where (c1, c2) in (select b1, b2 from t2i where b2 > '0')); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 -1 PRIMARY eq_ref distinct_key distinct_key 18 func,func 1 100.00 1 PRIMARY eq_ref distinct_key distinct_key 18 func,func 1 100.00 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 5 100.00 Using where +1 PRIMARY eq_ref distinct_key distinct_key 18 func,func 1 100.00 3 SUBQUERY t3 ALL NULL NULL NULL NULL 4 100.00 Using where 3 SUBQUERY t2i index it2i1,it2i2,it2i3 it2i3 18 NULL 5 80.00 Using where; Using index; Using join buffer (flat, BNL join) +2 SUBQUERY t2 ALL NULL NULL NULL NULL 5 100.00 Using where Warnings: Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` semi join (`test`.`t2`) semi join (`test`.`t2i` join `test`.`t3`) where ((`test`.`t2i`.`b2` = `test`.`t3`.`c2`) and (`test`.`t2i`.`b1` = `test`.`t3`.`c1`) and (`test`.`t2`.`b1` > '0') and (`test`.`t3`.`c2` > '0')) select * from t1 @@ -317,14 +317,12 @@ where (a1, a2) in (select b1, b2 from t2i where b1 > '0') and (a1, a2) in (select c1, c2 from t3i where (c1, c2) in (select b1, b2 from t2i where b2 > '0')); id select_type table type possible_keys key key_len ref rows filtered Extra -1 PRIMARY t1i index it1i1,it1i2,it1i3 # # # 3 100.00 # -1 PRIMARY eq_ref distinct_key # # # 1 100.00 # -1 PRIMARY eq_ref distinct_key # # # 1 100.00 # -2 SUBQUERY t2i index it2i1,it2i2,it2i3 # # # 5 100.00 # -3 SUBQUERY t2i index it2i1,it2i2,it2i3 # # # 5 100.00 # -3 SUBQUERY t3i index it3i1,it3i2,it3i3 # # # 4 75.00 # +1 PRIMARY t2i index it2i1,it2i2,it2i3 # # # 5 40.00 # +1 PRIMARY t1i ref it1i1,it1i2,it1i3 # # # 1 100.00 # +1 PRIMARY t3i ref it3i1,it3i2,it3i3 # # # 1 100.00 # +1 PRIMARY t2i ref it2i1,it2i2,it2i3 # # # 2 100.00 # Warnings: -Note 1003 select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from `test`.`t1i` semi join (`test`.`t2i`) semi join (`test`.`t2i` join `test`.`t3i`) where ((`test`.`t3i`.`c2` = `test`.`t2i`.`b2`) and (`test`.`t3i`.`c1` = `test`.`t2i`.`b1`) and (`test`.`t2i`.`b1` > '0') and (`test`.`t2i`.`b2` > '0')) +Note 1003 select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from `test`.`t1i` semi join (`test`.`t2i`) semi join (`test`.`t2i` join `test`.`t3i`) where ((`test`.`t1i`.`a2` = `test`.`t2i`.`b2`) and (`test`.`t3i`.`c2` = `test`.`t2i`.`b2`) and (`test`.`t2i`.`b2` = `test`.`t2i`.`b2`) and (`test`.`t1i`.`a1` = `test`.`t2i`.`b1`) and (`test`.`t3i`.`c1` = `test`.`t2i`.`b1`) and (`test`.`t2i`.`b1` = `test`.`t2i`.`b1`) and (`test`.`t2i`.`b1` > '0') and (`test`.`t2i`.`b2` > '0')) select * from t1i where (a1, a2) in (select b1, b2 from t2i where b1 > '0') and (a1, a2) in (select c1, c2 from t3i @@ -341,11 +339,11 @@ b2 in (select c2 from t3 where c2 LIKE '%03')) and where (c1, c2) in (select b1, b2 from t2i where b2 > '0')); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 -1 PRIMARY eq_ref distinct_key distinct_key 18 func,func 1 100.00 1 PRIMARY eq_ref distinct_key distinct_key 18 func,func 1 100.00 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 5 100.00 Using where +1 PRIMARY eq_ref distinct_key distinct_key 18 func,func 1 100.00 5 SUBQUERY t3 ALL NULL NULL NULL NULL 4 100.00 Using where 5 SUBQUERY t2i index it2i1,it2i2,it2i3 it2i3 18 NULL 5 80.00 Using where; Using index; Using join buffer (flat, BNL join) +2 SUBQUERY t2 ALL NULL NULL NULL NULL 5 100.00 Using where 4 SUBQUERY t3 ALL NULL NULL NULL NULL 4 100.00 Using where 3 SUBQUERY t3 ALL NULL NULL NULL NULL 4 100.00 Using where Warnings: @@ -366,16 +364,16 @@ b2 in (select c2 from t3 t3b where c2 LIKE '%03')) and (a1, a2) in (select c1, c2 from t3 t3c where (c1, c2) in (select b1, b2 from t2i where b2 > '0')); id select_type table type possible_keys key key_len ref rows filtered Extra -1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Start temporary -1 PRIMARY t2 ALL NULL NULL NULL NULL 5 100.00 Using where; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 1 PRIMARY eq_ref distinct_key distinct_key 18 func,func 1 100.00 +1 PRIMARY t2 ALL NULL NULL NULL NULL 5 100.00 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) 5 SUBQUERY t3c ALL NULL NULL NULL NULL 4 100.00 Using where 5 SUBQUERY t2i index it2i1,it2i2,it2i3 it2i3 18 NULL 5 80.00 Using where; Using index; Using join buffer (flat, BNL join) 4 SUBQUERY t3b ALL NULL NULL NULL NULL 4 100.00 Using where 3 DEPENDENT SUBQUERY t3a ALL NULL NULL NULL NULL 4 100.00 Using where Warnings: Note 1276 Field or reference 'test.t1.a1' of SELECT #3 was resolved in SELECT #1 -Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` semi join (`test`.`t2`) semi join (`test`.`t2i` join `test`.`t3` `t3c`) where ((`test`.`t2`.`b2` = `test`.`t1`.`a2`) and (`test`.`t2i`.`b2` = `test`.`t3c`.`c2`) and (`test`.`t2`.`b1` = `test`.`t1`.`a1`) and (`test`.`t2i`.`b1` = `test`.`t3c`.`c1`) and (<`test`.`t2`.`b2`,`test`.`t1`.`a1`>((`test`.`t2`.`b2`,(select `test`.`t3a`.`c2` from `test`.`t3` `t3a` where ((`test`.`t3a`.`c1` = `test`.`t1`.`a1`) and ((`test`.`t2`.`b2`) = `test`.`t3a`.`c2`))))) or <`test`.`t2`.`b2`>((`test`.`t2`.`b2`,`test`.`t2`.`b2` in ( (select `test`.`t3b`.`c2` from `test`.`t3` `t3b` where (`test`.`t3b`.`c2` like '%03') ), (`test`.`t2`.`b2` in on distinct_key where ((`test`.`t2`.`b2` = ``.`c2`))))))) and (`test`.`t3c`.`c2` > '0')) +Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` semi join (`test`.`t2`) semi join (`test`.`t2i` join `test`.`t3` `t3c`) where ((`test`.`t2i`.`b2` = `test`.`t3c`.`c2`) and (`test`.`t2`.`b2` = `test`.`t1`.`a2`) and (`test`.`t2i`.`b1` = `test`.`t3c`.`c1`) and (`test`.`t2`.`b1` = `test`.`t1`.`a1`) and (<`test`.`t2`.`b2`,`test`.`t1`.`a1`>((`test`.`t2`.`b2`,(select `test`.`t3a`.`c2` from `test`.`t3` `t3a` where ((`test`.`t3a`.`c1` = `test`.`t1`.`a1`) and ((`test`.`t2`.`b2`) = `test`.`t3a`.`c2`))))) or <`test`.`t2`.`b2`>((`test`.`t2`.`b2`,`test`.`t2`.`b2` in ( (select `test`.`t3b`.`c2` from `test`.`t3` `t3b` where (`test`.`t3b`.`c2` like '%03') ), (`test`.`t2`.`b2` in on distinct_key where ((`test`.`t2`.`b2` = ``.`c2`))))))) and (`test`.`t3c`.`c2` > '0')) select * from t1 where (a1, a2) in (select b1, b2 from t2 where b2 in (select c2 from t3 t3a where c1 = a1) or @@ -406,15 +404,13 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 2 SUBQUERY t2 ALL NULL # # # 5 100.00 # 4 SUBQUERY t3 ALL NULL # # # 4 100.00 # 3 SUBQUERY t3 ALL NULL # # # 4 100.00 # -7 UNION t1i index it1i1,it1i2,it1i3 # # # 3 100.00 # -7 UNION eq_ref distinct_key # # # 1 100.00 # -7 UNION eq_ref distinct_key # # # 1 100.00 # -8 SUBQUERY t2i index it2i1,it2i2,it2i3 # # # 5 100.00 # -9 SUBQUERY t2i index it2i1,it2i2,it2i3 # # # 5 100.00 # -9 SUBQUERY t3i index it3i1,it3i2,it3i3 # # # 4 75.00 # +7 UNION t2i index it2i1,it2i2,it2i3 # # # 5 40.00 # +7 UNION t1i ref it1i1,it1i2,it1i3 # # # 1 100.00 # +7 UNION t3i ref it3i1,it3i2,it3i3 # # # 1 100.00 # +7 UNION t2i ref it2i1,it2i2,it2i3 # # # 2 100.00 # NULL UNION RESULT ALL NULL # # # NULL NULL # Warnings: -Note 1003 (select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from (select `test`.`t2`.`b1`,`test`.`t2`.`b2` from `test`.`t2` where (<`test`.`t2`.`b2`>((`test`.`t2`.`b2`,`test`.`t2`.`b2` in ( (select `test`.`t3`.`c2` from `test`.`t3` where (`test`.`t3`.`c2` like '%02') ), (`test`.`t2`.`b2` in on distinct_key where ((`test`.`t2`.`b2` = ``.`c2`)))))) or <`test`.`t2`.`b2`>((`test`.`t2`.`b2`,`test`.`t2`.`b2` in ( (select `test`.`t3`.`c2` from `test`.`t3` where (`test`.`t3`.`c2` like '%03') ), (`test`.`t2`.`b2` in on distinct_key where ((`test`.`t2`.`b2` = ``.`c2`))))))) group by `test`.`t2`.`b1`,`test`.`t2`.`b2`) semi join (`test`.`t2i` join `test`.`t3`) join `test`.`t1` where ((`test`.`t3`.`c2` = ``.`b2`) and (`test`.`t1`.`a2` = ``.`b2`) and (`test`.`t2i`.`b2` = ``.`b2`) and (`test`.`t3`.`c1` = ``.`b1`) and (`test`.`t1`.`a1` = ``.`b1`) and (`test`.`t2i`.`b1` = ``.`b1`) and (``.`b2` > '0'))) union (select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from `test`.`t1i` semi join (`test`.`t2i`) semi join (`test`.`t2i` join `test`.`t3i`) where ((`test`.`t3i`.`c2` = `test`.`t2i`.`b2`) and (`test`.`t3i`.`c1` = `test`.`t2i`.`b1`) and (`test`.`t2i`.`b1` > '0') and (`test`.`t2i`.`b2` > '0'))) +Note 1003 (select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from (select `test`.`t2`.`b1`,`test`.`t2`.`b2` from `test`.`t2` where (<`test`.`t2`.`b2`>((`test`.`t2`.`b2`,`test`.`t2`.`b2` in ( (select `test`.`t3`.`c2` from `test`.`t3` where (`test`.`t3`.`c2` like '%02') ), (`test`.`t2`.`b2` in on distinct_key where ((`test`.`t2`.`b2` = ``.`c2`)))))) or <`test`.`t2`.`b2`>((`test`.`t2`.`b2`,`test`.`t2`.`b2` in ( (select `test`.`t3`.`c2` from `test`.`t3` where (`test`.`t3`.`c2` like '%03') ), (`test`.`t2`.`b2` in on distinct_key where ((`test`.`t2`.`b2` = ``.`c2`))))))) group by `test`.`t2`.`b1`,`test`.`t2`.`b2`) semi join (`test`.`t2i` join `test`.`t3`) join `test`.`t1` where ((`test`.`t3`.`c2` = ``.`b2`) and (`test`.`t1`.`a2` = ``.`b2`) and (`test`.`t2i`.`b2` = ``.`b2`) and (`test`.`t3`.`c1` = ``.`b1`) and (`test`.`t1`.`a1` = ``.`b1`) and (`test`.`t2i`.`b1` = ``.`b1`) and (``.`b2` > '0'))) union (select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from `test`.`t1i` semi join (`test`.`t2i`) semi join (`test`.`t2i` join `test`.`t3i`) where ((`test`.`t1i`.`a2` = `test`.`t2i`.`b2`) and (`test`.`t3i`.`c2` = `test`.`t2i`.`b2`) and (`test`.`t2i`.`b2` = `test`.`t2i`.`b2`) and (`test`.`t1i`.`a1` = `test`.`t2i`.`b1`) and (`test`.`t3i`.`c1` = `test`.`t2i`.`b1`) and (`test`.`t2i`.`b1` = `test`.`t2i`.`b1`) and (`test`.`t2i`.`b1` > '0') and (`test`.`t2i`.`b2` > '0'))) (select * from t1 where (a1, a2) in (select b1, b2 from t2 where b2 in (select c2 from t3 where c2 LIKE '%02') or @@ -505,16 +501,16 @@ b2 in (select c2 from t3 t3b where c2 LIKE '%03')) and (a1, a2) in (select c1, c2 from t3 t3c where (c1, c2) in (select b1, b2 from t2i where b2 > '0' or b2 = a2)); id select_type table type possible_keys key key_len ref rows filtered Extra -1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where; Start temporary -1 PRIMARY t2i ref it2i1,it2i2,it2i3 it2i3 18 test.t1.a1,test.t1.a2 2 100.00 Using index -1 PRIMARY t2 ALL NULL NULL NULL NULL 5 100.00 Using where; Using join buffer (flat, BNL join) +1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where +1 PRIMARY t2 ALL NULL NULL NULL NULL 5 100.00 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY t2i ref it2i1,it2i2,it2i3 it2i3 18 test.t1.a1,test.t1.a2 2 100.00 Using index; Start temporary 1 PRIMARY t3c ALL NULL NULL NULL NULL 4 100.00 Using where; End temporary; Using join buffer (flat, BNL join) 4 SUBQUERY t3b ALL NULL NULL NULL NULL 4 100.00 Using where 3 DEPENDENT SUBQUERY t3a ALL NULL NULL NULL NULL 4 100.00 Using where Warnings: Note 1276 Field or reference 'test.t1.a1' of SELECT #3 was resolved in SELECT #1 Note 1276 Field or reference 'test.t1.a2' of SELECT #6 was resolved in SELECT #1 -Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` semi join (`test`.`t2`) semi join (`test`.`t2i` join `test`.`t3` `t3c`) where ((`test`.`t2i`.`b2` = `test`.`t1`.`a2`) and (`test`.`t2`.`b2` = `test`.`t1`.`a2`) and (`test`.`t3c`.`c2` = `test`.`t1`.`a2`) and (`test`.`t2i`.`b1` = `test`.`t1`.`a1`) and (`test`.`t2`.`b1` = `test`.`t1`.`a1`) and (`test`.`t3c`.`c1` = `test`.`t1`.`a1`) and (<`test`.`t2`.`b2`,`test`.`t1`.`a1`>((`test`.`t2`.`b2`,(select `test`.`t3a`.`c2` from `test`.`t3` `t3a` where ((`test`.`t3a`.`c1` = `test`.`t1`.`a1`) and ((`test`.`t2`.`b2`) = `test`.`t3a`.`c2`))))) or <`test`.`t2`.`b2`>((`test`.`t2`.`b2`,`test`.`t2`.`b2` in ( (select `test`.`t3b`.`c2` from `test`.`t3` `t3b` where (`test`.`t3b`.`c2` like '%03') ), (`test`.`t2`.`b2` in on distinct_key where ((`test`.`t2`.`b2` = ``.`c2`)))))))) +Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` semi join (`test`.`t2`) semi join (`test`.`t2i` join `test`.`t3` `t3c`) where ((`test`.`t2`.`b2` = `test`.`t1`.`a2`) and (`test`.`t2i`.`b2` = `test`.`t1`.`a2`) and (`test`.`t3c`.`c2` = `test`.`t1`.`a2`) and (`test`.`t2`.`b1` = `test`.`t1`.`a1`) and (`test`.`t2i`.`b1` = `test`.`t1`.`a1`) and (`test`.`t3c`.`c1` = `test`.`t1`.`a1`) and (<`test`.`t2`.`b2`,`test`.`t1`.`a1`>((`test`.`t2`.`b2`,(select `test`.`t3a`.`c2` from `test`.`t3` `t3a` where ((`test`.`t3a`.`c1` = `test`.`t1`.`a1`) and ((`test`.`t2`.`b2`) = `test`.`t3a`.`c2`))))) or <`test`.`t2`.`b2`>((`test`.`t2`.`b2`,`test`.`t2`.`b2` in ( (select `test`.`t3b`.`c2` from `test`.`t3` `t3b` where (`test`.`t3b`.`c2` like '%03') ), (`test`.`t2`.`b2` in on distinct_key where ((`test`.`t2`.`b2` = ``.`c2`)))))))) explain extended select * from t1 where (a1, a2) in (select '1 - 01', '2 - 01'); id select_type table type possible_keys key key_len ref rows filtered Extra @@ -617,8 +613,8 @@ explain extended select left(a1,7), left(a2,7) from t1_16 where a1 in (select b1 from t2_16 where b1 > '0'); id select_type table type possible_keys key key_len ref rows filtered Extra -1 PRIMARY t1_16 ALL NULL NULL NULL NULL 3 100.00 Using where; Start temporary -1 PRIMARY t2_16 ALL NULL NULL NULL NULL 3 100.00 Using where; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY t1_16 ALL NULL NULL NULL NULL 3 100.00 Using where +1 PRIMARY t2_16 ALL NULL NULL NULL NULL 3 100.00 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) Warnings: Note 1003 select left(`test`.`t1_16`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_16`.`a2`,7) AS `left(a2,7)` from `test`.`t1_16` semi join (`test`.`t2_16`) where ((`test`.`t2_16`.`b1` = `test`.`t1_16`.`a1`) and (`test`.`t1_16`.`a1` > '0')) select left(a1,7), left(a2,7) @@ -631,8 +627,8 @@ explain extended select left(a1,7), left(a2,7) from t1_16 where (a1,a2) in (select b1, b2 from t2_16 where b1 > '0'); id select_type table type possible_keys key key_len ref rows filtered Extra -1 PRIMARY t1_16 ALL NULL NULL NULL NULL 3 100.00 Using where; Start temporary -1 PRIMARY t2_16 ALL NULL NULL NULL NULL 3 100.00 Using where; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY t1_16 ALL NULL NULL NULL NULL 3 100.00 Using where +1 PRIMARY t2_16 ALL NULL NULL NULL NULL 3 100.00 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) Warnings: Note 1003 select left(`test`.`t1_16`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_16`.`a2`,7) AS `left(a2,7)` from `test`.`t1_16` semi join (`test`.`t2_16`) where ((`test`.`t2_16`.`b2` = `test`.`t1_16`.`a2`) and (`test`.`t2_16`.`b1` = `test`.`t1_16`.`a1`) and (`test`.`t1_16`.`a1` > '0')) select left(a1,7), left(a2,7) @@ -695,8 +691,8 @@ where (a1, a2) IN where t2.b2 = substring(t2_16.b2,1,6) and t2.b1 IN (select c1 from t3 where c2 > '0'))); id select_type table type possible_keys key key_len ref rows filtered Extra -1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Start temporary -1 PRIMARY t1_16 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (flat, BNL join) +1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 +1 PRIMARY t1_16 ALL NULL NULL NULL NULL 3 100.00 Using where; Start temporary; Using join buffer (flat, BNL join) 1 PRIMARY t2_16 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (flat, BNL join) 1 PRIMARY t3 ALL NULL NULL NULL NULL 4 100.00 Using where; Using join buffer (flat, BNL join) 1 PRIMARY t2 ALL NULL NULL NULL NULL 5 100.00 Using where; End temporary; Using join buffer (flat, BNL join) @@ -732,8 +728,8 @@ explain extended select left(a1,7), left(a2,7) from t1_512 where a1 in (select b1 from t2_512 where b1 > '0'); id select_type table type possible_keys key key_len ref rows filtered Extra -1 PRIMARY t1_512 ALL NULL NULL NULL NULL 3 100.00 Using where; Start temporary -1 PRIMARY t2_512 ALL NULL NULL NULL NULL 3 100.00 Using where; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY t1_512 ALL NULL NULL NULL NULL 3 100.00 Using where +1 PRIMARY t2_512 ALL NULL NULL NULL NULL 3 100.00 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) Warnings: Note 1003 select left(`test`.`t1_512`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_512`.`a2`,7) AS `left(a2,7)` from `test`.`t1_512` semi join (`test`.`t2_512`) where ((`test`.`t2_512`.`b1` = `test`.`t1_512`.`a1`) and (`test`.`t1_512`.`a1` > '0')) select left(a1,7), left(a2,7) @@ -746,8 +742,8 @@ explain extended select left(a1,7), left(a2,7) from t1_512 where (a1,a2) in (select b1, b2 from t2_512 where b1 > '0'); id select_type table type possible_keys key key_len ref rows filtered Extra -1 PRIMARY t1_512 ALL NULL NULL NULL NULL 3 100.00 Using where; Start temporary -1 PRIMARY t2_512 ALL NULL NULL NULL NULL 3 100.00 Using where; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY t1_512 ALL NULL NULL NULL NULL 3 100.00 Using where +1 PRIMARY t2_512 ALL NULL NULL NULL NULL 3 100.00 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) Warnings: Note 1003 select left(`test`.`t1_512`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_512`.`a2`,7) AS `left(a2,7)` from `test`.`t1_512` semi join (`test`.`t2_512`) where ((`test`.`t2_512`.`b2` = `test`.`t1_512`.`a2`) and (`test`.`t2_512`.`b1` = `test`.`t1_512`.`a1`) and (`test`.`t1_512`.`a1` > '0')) select left(a1,7), left(a2,7) @@ -828,8 +824,8 @@ explain extended select left(a1,7), left(a2,7) from t1_1024 where a1 in (select b1 from t2_1024 where b1 > '0'); id select_type table type possible_keys key key_len ref rows filtered Extra -1 PRIMARY t1_1024 ALL NULL NULL NULL NULL 3 100.00 Using where; Start temporary -1 PRIMARY t2_1024 ALL NULL NULL NULL NULL 3 100.00 Using where; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY t1_1024 ALL NULL NULL NULL NULL 3 100.00 Using where +1 PRIMARY t2_1024 ALL NULL NULL NULL NULL 3 100.00 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) Warnings: Note 1003 select left(`test`.`t1_1024`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_1024`.`a2`,7) AS `left(a2,7)` from `test`.`t1_1024` semi join (`test`.`t2_1024`) where ((`test`.`t2_1024`.`b1` = `test`.`t1_1024`.`a1`) and (`test`.`t1_1024`.`a1` > '0')) select left(a1,7), left(a2,7) @@ -842,8 +838,8 @@ explain extended select left(a1,7), left(a2,7) from t1_1024 where (a1,a2) in (select b1, b2 from t2_1024 where b1 > '0'); id select_type table type possible_keys key key_len ref rows filtered Extra -1 PRIMARY t1_1024 ALL NULL NULL NULL NULL 3 100.00 Using where; Start temporary -1 PRIMARY t2_1024 ALL NULL NULL NULL NULL 3 100.00 Using where; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY t1_1024 ALL NULL NULL NULL NULL 3 100.00 Using where +1 PRIMARY t2_1024 ALL NULL NULL NULL NULL 3 100.00 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) Warnings: Note 1003 select left(`test`.`t1_1024`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_1024`.`a2`,7) AS `left(a2,7)` from `test`.`t1_1024` semi join (`test`.`t2_1024`) where ((`test`.`t2_1024`.`b2` = `test`.`t1_1024`.`a2`) and (`test`.`t2_1024`.`b1` = `test`.`t1_1024`.`a1`) and (`test`.`t1_1024`.`a1` > '0')) select left(a1,7), left(a2,7) @@ -856,8 +852,8 @@ explain extended select left(a1,7), left(a2,7) from t1_1024 where a1 in (select substring(b1,1,1024) from t2_1024 where b1 > '0'); id select_type table type possible_keys key key_len ref rows filtered Extra -1 PRIMARY t1_1024 ALL NULL NULL NULL NULL 3 100.00 Start temporary -1 PRIMARY t2_1024 ALL NULL NULL NULL NULL 3 100.00 Using where; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY t1_1024 ALL NULL NULL NULL NULL 3 100.00 +1 PRIMARY t2_1024 ALL NULL NULL NULL NULL 3 100.00 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) Warnings: Note 1003 select left(`test`.`t1_1024`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_1024`.`a2`,7) AS `left(a2,7)` from `test`.`t1_1024` semi join (`test`.`t2_1024`) where ((`test`.`t2_1024`.`b1` > '0') and (`test`.`t1_1024`.`a1` = substr(`test`.`t2_1024`.`b1`,1,1024))) select left(a1,7), left(a2,7) @@ -923,8 +919,8 @@ explain extended select left(a1,7), left(a2,7) from t1_1025 where a1 in (select b1 from t2_1025 where b1 > '0'); id select_type table type possible_keys key key_len ref rows filtered Extra -1 PRIMARY t1_1025 ALL NULL NULL NULL NULL 3 100.00 Using where; Start temporary -1 PRIMARY t2_1025 ALL NULL NULL NULL NULL 3 100.00 Using where; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY t1_1025 ALL NULL NULL NULL NULL 3 100.00 Using where +1 PRIMARY t2_1025 ALL NULL NULL NULL NULL 3 100.00 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) Warnings: Note 1003 select left(`test`.`t1_1025`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_1025`.`a2`,7) AS `left(a2,7)` from `test`.`t1_1025` semi join (`test`.`t2_1025`) where ((`test`.`t2_1025`.`b1` = `test`.`t1_1025`.`a1`) and (`test`.`t1_1025`.`a1` > '0')) select left(a1,7), left(a2,7) @@ -937,8 +933,8 @@ explain extended select left(a1,7), left(a2,7) from t1_1025 where (a1,a2) in (select b1, b2 from t2_1025 where b1 > '0'); id select_type table type possible_keys key key_len ref rows filtered Extra -1 PRIMARY t1_1025 ALL NULL NULL NULL NULL 3 100.00 Using where; Start temporary -1 PRIMARY t2_1025 ALL NULL NULL NULL NULL 3 100.00 Using where; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY t1_1025 ALL NULL NULL NULL NULL 3 100.00 Using where +1 PRIMARY t2_1025 ALL NULL NULL NULL NULL 3 100.00 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) Warnings: Note 1003 select left(`test`.`t1_1025`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_1025`.`a2`,7) AS `left(a2,7)` from `test`.`t1_1025` semi join (`test`.`t2_1025`) where ((`test`.`t2_1025`.`b2` = `test`.`t1_1025`.`a2`) and (`test`.`t2_1025`.`b1` = `test`.`t1_1025`.`a1`) and (`test`.`t1_1025`.`a1` > '0')) select left(a1,7), left(a2,7) @@ -951,8 +947,8 @@ explain extended select left(a1,7), left(a2,7) from t1_1025 where a1 in (select substring(b1,1,1025) from t2_1025 where b1 > '0'); id select_type table type possible_keys key key_len ref rows filtered Extra -1 PRIMARY t1_1025 ALL NULL NULL NULL NULL 3 100.00 Start temporary -1 PRIMARY t2_1025 ALL NULL NULL NULL NULL 3 100.00 Using where; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY t1_1025 ALL NULL NULL NULL NULL 3 100.00 +1 PRIMARY t2_1025 ALL NULL NULL NULL NULL 3 100.00 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) Warnings: Note 1003 select left(`test`.`t1_1025`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_1025`.`a2`,7) AS `left(a2,7)` from `test`.`t1_1025` semi join (`test`.`t2_1025`) where ((`test`.`t2_1025`.`b1` > '0') and (`test`.`t1_1025`.`a1` = substr(`test`.`t2_1025`.`b1`,1,1025))) select left(a1,7), left(a2,7) @@ -1025,8 +1021,8 @@ explain extended select bin(a1), a2 from t1bb where (a1, a2) in (select b1, b2 from t2bb); id select_type table type possible_keys key key_len ref rows filtered Extra -1 PRIMARY t1bb ALL NULL NULL NULL NULL 3 100.00 Start temporary -1 PRIMARY t2bb ALL NULL NULL NULL NULL 3 100.00 Using where; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY t1bb ALL NULL NULL NULL NULL 3 100.00 +1 PRIMARY t2bb ALL NULL NULL NULL NULL 3 100.00 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) Warnings: Note 1003 select conv(`test`.`t1bb`.`a1`,10,2) AS `bin(a1)`,`test`.`t1bb`.`a2` AS `a2` from `test`.`t1bb` semi join (`test`.`t2bb`) where ((`test`.`t2bb`.`b2` = `test`.`t1bb`.`a2`) and (`test`.`t2bb`.`b1` = `test`.`t1bb`.`a1`)) select bin(a1), a2 @@ -1274,8 +1270,8 @@ GROUP BY t3i ); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 1 -1 PRIMARY eq_ref distinct_key distinct_key 5 const 1 Start temporary -1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY eq_ref distinct_key distinct_key 5 const 1 +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) 1 PRIMARY t4 ALL NULL NULL NULL NULL 2 Using where; Using join buffer (flat, BNL join) 3 SUBQUERY t3 ALL NULL NULL NULL NULL 2 Using temporary DROP TABLE t1,t2,t3,t4; diff --git a/mysql-test/t/subselect_sj2.test b/mysql-test/t/subselect_sj2.test index b2721574deb..2ec15d4dfae 100644 --- a/mysql-test/t/subselect_sj2.test +++ b/mysql-test/t/subselect_sj2.test @@ -7,7 +7,7 @@ set @subselect_sj2_tmp= @@optimizer_switch; set optimizer_switch='semijoin=on,firstmatch=on,loosescan=on'; set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; --disable_warnings -drop table if exists t0, t1, t2, t3; +drop table if exists t0, t1, t2, t3, t4, t5; drop view if exists v1; --enable_warnings diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index c7d07c21746..79eb0cb9551 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -2168,7 +2168,8 @@ bool find_eq_ref_candidate(TABLE *table, table_map sj_inner_tables) See setup_semijoin_dups_elimination() for a description of what kinds of join prefixes each strategy can handle. */ -bool is_multiple_semi_joins(POSITION *prefix, uint idx, table_map inner_tables) + +bool is_multiple_semi_joins(JOIN *join, POSITION *prefix, uint idx, table_map inner_tables) { for (int i= (int)idx; i >= 0; i--) { @@ -2176,7 +2177,8 @@ bool is_multiple_semi_joins(POSITION *prefix, uint idx, table_map inner_tables) if ((emb_sj_nest= prefix[i].table->emb_sj_nest)) { if (inner_tables & emb_sj_nest->sj_inner_tables) - return !test(inner_tables == emb_sj_nest->sj_inner_tables); + return !test(inner_tables == (emb_sj_nest->sj_inner_tables & + ~join->const_table_map)); } } return FALSE; @@ -2206,6 +2208,7 @@ void advance_sj_state(JOIN *join, table_map remaining_tables, uint idx, - attempts to build semi-join strategies here will confuse the optimizer, so bail out. */ + pos->sj_strategy= SJ_OPT_NONE; return; } @@ -2290,7 +2293,7 @@ void advance_sj_state(JOIN *join, table_map remaining_tables, uint idx, join->cur_dups_producing_tables &= ~handled_fanout; //TODO: update bitmap of semi-joins that were handled together with // others. - if (is_multiple_semi_joins(join->positions, idx, handled_fanout)) + if (is_multiple_semi_joins(join, join->positions, idx, handled_fanout)) pos->inner_tables_handled_with_other_sjs |= handled_fanout; } else @@ -3906,6 +3909,80 @@ int do_sj_dups_weedout(THD *thd, SJ_TMP_TABLE *sjtbl) } +int init_dups_weedout(JOIN *join, uint first_table, int first_fanout_table, uint n_tables) +{ + THD *thd= join->thd; + DBUG_ENTER("init_dups_weedout"); + SJ_TMP_TABLE::TAB sjtabs[MAX_TABLES]; + SJ_TMP_TABLE::TAB *last_tab= sjtabs; + uint jt_rowid_offset= 0; // # tuple bytes are already occupied (w/o NULL bytes) + uint jt_null_bits= 0; // # null bits in tuple bytes + /* + Walk through the range and remember + - tables that need their rowids to be put into temptable + - the last outer table + */ + for (JOIN_TAB *j=join->join_tab + first_table; + j < join->join_tab + first_table + n_tables; j++) + { + if (sj_table_is_included(join, j)) + { + last_tab->join_tab= j; + last_tab->rowid_offset= jt_rowid_offset; + jt_rowid_offset += j->table->file->ref_length; + if (j->table->maybe_null) + { + last_tab->null_byte= jt_null_bits / 8; + last_tab->null_bit= jt_null_bits++; + } + last_tab++; + j->table->prepare_for_position(); + j->keep_current_rowid= TRUE; + } + } + + SJ_TMP_TABLE *sjtbl; + if (jt_rowid_offset) /* Temptable has at least one rowid */ + { + size_t tabs_size= (last_tab - sjtabs) * sizeof(SJ_TMP_TABLE::TAB); + if (!(sjtbl= (SJ_TMP_TABLE*)thd->alloc(sizeof(SJ_TMP_TABLE))) || + !(sjtbl->tabs= (SJ_TMP_TABLE::TAB*) thd->alloc(tabs_size))) + DBUG_RETURN(TRUE); /* purecov: inspected */ + memcpy(sjtbl->tabs, sjtabs, tabs_size); + sjtbl->is_degenerate= FALSE; + sjtbl->tabs_end= sjtbl->tabs + (last_tab - sjtabs); + sjtbl->rowid_len= jt_rowid_offset; + sjtbl->null_bits= jt_null_bits; + sjtbl->null_bytes= (jt_null_bits + 7)/8; + sjtbl->tmp_table= + create_duplicate_weedout_tmp_table(thd, + sjtbl->rowid_len + + sjtbl->null_bytes, + sjtbl); + join->sj_tmp_tables.push_back(sjtbl->tmp_table); + } + else + { + /* + This is a special case where the entire subquery predicate does + not depend on anything at all, ie this is + WHERE const IN (uncorrelated select) + */ + if (!(sjtbl= (SJ_TMP_TABLE*)thd->alloc(sizeof(SJ_TMP_TABLE)))) + DBUG_RETURN(TRUE); /* purecov: inspected */ + sjtbl->tmp_table= NULL; + sjtbl->is_degenerate= TRUE; + sjtbl->have_degenerate_row= FALSE; + } + + sjtbl->next_flush_table= join->join_tab[first_table].flush_weedout_table; + join->join_tab[first_table].flush_weedout_table= sjtbl; + join->join_tab[first_fanout_table].first_weedout_table= sjtbl; + join->join_tab[first_table + n_tables - 1].check_weed_out_table= sjtbl; + DBUG_RETURN(0); +} + + /* Setup the strategies to eliminate semi-join duplicates. @@ -4006,9 +4083,9 @@ int setup_semijoin_dups_elimination(JOIN *join, ulonglong options, uint no_jbuf_after) { uint i; - THD *thd= join->thd; DBUG_ENTER("setup_semijoin_dups_elimination"); - + + POSITION *pos= join->best_positions + join->const_tables; for (i= join->const_tables ; i < join->top_join_tab_count; ) { @@ -4049,6 +4126,7 @@ int setup_semijoin_dups_elimination(JOIN *join, ulonglong options, forwards, but do not destroy other duplicate elimination methods. */ uint first_table= i; + uint join_cache_level= join->thd->variables.join_cache_level; for (uint j= i; j < i + pos->n_sj_tables; j++) { @@ -4072,70 +4150,7 @@ int setup_semijoin_dups_elimination(JOIN *join, ulonglong options, } } - SJ_TMP_TABLE::TAB sjtabs[MAX_TABLES]; - SJ_TMP_TABLE::TAB *last_tab= sjtabs; - uint jt_rowid_offset= 0; // # tuple bytes are already occupied (w/o NULL bytes) - uint jt_null_bits= 0; // # null bits in tuple bytes - /* - Walk through the range and remember - - tables that need their rowids to be put into temptable - - the last outer table - */ - for (JOIN_TAB *j=join->join_tab + first_table; - j < join->join_tab + i + pos->n_sj_tables; j++) - { - if (sj_table_is_included(join, j)) - { - last_tab->join_tab= j; - last_tab->rowid_offset= jt_rowid_offset; - jt_rowid_offset += j->table->file->ref_length; - if (j->table->maybe_null) - { - last_tab->null_byte= jt_null_bits / 8; - last_tab->null_bit= jt_null_bits++; - } - last_tab++; - j->table->prepare_for_position(); - j->keep_current_rowid= TRUE; - } - } - - SJ_TMP_TABLE *sjtbl; - if (jt_rowid_offset) /* Temptable has at least one rowid */ - { - size_t tabs_size= (last_tab - sjtabs) * sizeof(SJ_TMP_TABLE::TAB); - if (!(sjtbl= (SJ_TMP_TABLE*)thd->alloc(sizeof(SJ_TMP_TABLE))) || - !(sjtbl->tabs= (SJ_TMP_TABLE::TAB*) thd->alloc(tabs_size))) - DBUG_RETURN(TRUE); /* purecov: inspected */ - memcpy(sjtbl->tabs, sjtabs, tabs_size); - sjtbl->is_degenerate= FALSE; - sjtbl->tabs_end= sjtbl->tabs + (last_tab - sjtabs); - sjtbl->rowid_len= jt_rowid_offset; - sjtbl->null_bits= jt_null_bits; - sjtbl->null_bytes= (jt_null_bits + 7)/8; - sjtbl->tmp_table= - create_duplicate_weedout_tmp_table(thd, - sjtbl->rowid_len + - sjtbl->null_bytes, - sjtbl); - join->sj_tmp_tables.push_back(sjtbl->tmp_table); - } - else - { - /* - This is a special case where the entire subquery predicate does - not depend on anything at all, ie this is - WHERE const IN (uncorrelated select) - */ - if (!(sjtbl= (SJ_TMP_TABLE*)thd->alloc(sizeof(SJ_TMP_TABLE)))) - DBUG_RETURN(TRUE); /* purecov: inspected */ - sjtbl->tmp_table= NULL; - sjtbl->is_degenerate= TRUE; - sjtbl->have_degenerate_row= FALSE; - } - join->join_tab[first_table].flush_weedout_table= sjtbl; - join->join_tab[i + pos->n_sj_tables - 1].check_weed_out_table= sjtbl; - + init_dups_weedout(join, first_table, i, i + pos->n_sj_tables - first_table); i+= pos->n_sj_tables; pos+= pos->n_sj_tables; break; diff --git a/sql/opt_subselect.h b/sql/opt_subselect.h index 7d560588995..0e7fa22cfe7 100644 --- a/sql/opt_subselect.h +++ b/sql/opt_subselect.h @@ -358,8 +358,7 @@ public: ENGINE_COLUMNDEF *start_recinfo; ENGINE_COLUMNDEF *recinfo; - /* Pointer to next table (next->start_idx > this->end_idx) */ - SJ_TMP_TABLE *next; + SJ_TMP_TABLE *next_flush_table; }; int setup_semijoin_dups_elimination(JOIN *join, ulonglong options, diff --git a/sql/sql_select.cc b/sql/sql_select.cc index ce20dfea32e..f56cb920a3d 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -15087,10 +15087,12 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records) int error; enum_nested_loop_state rc= NESTED_LOOP_OK; READ_RECORD *info= &join_tab->read_record; - - if (join_tab->flush_weedout_table) + + for (SJ_TMP_TABLE *flush_dups_table= join_tab->flush_weedout_table; + flush_dups_table; + flush_dups_table= flush_dups_table->next_flush_table) { - do_sj_reset(join_tab->flush_weedout_table); + do_sj_reset(flush_dups_table); } if (!join_tab->preread_init_done && join_tab->preread_init()) @@ -21013,7 +21015,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, extra.append(STRING_WITH_LEN("; LooseScan")); } - if (tab->flush_weedout_table) + if (tab->first_weedout_table) extra.append(STRING_WITH_LEN("; Start temporary")); if (tab->check_weed_out_table) extra.append(STRING_WITH_LEN("; End temporary")); diff --git a/sql/sql_select.h b/sql/sql_select.h index 21c5dc7d65e..2b307c20dbe 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -341,6 +341,8 @@ typedef struct st_join_table { /* Variables for semi-join duplicate elimination */ SJ_TMP_TABLE *flush_weedout_table; SJ_TMP_TABLE *check_weed_out_table; + /* for EXPLAIN only: */ + SJ_TMP_TABLE *first_weedout_table; /* If set, means we should stop join enumeration after we've got the first From 962bff5dcaa585f041058a7f75b331bc7c6dbc29 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Thu, 24 Nov 2011 22:56:02 -0800 Subject: [PATCH 119/288] Currently innodb_plugin does not support ICP. Part2. --- .../suite/innodb_plugin/r/innodb_lock_wait_timeout_1.result | 5 ++++- .../suite/innodb_plugin/t/innodb_lock_wait_timeout_1.test | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/mysql-test/suite/innodb_plugin/r/innodb_lock_wait_timeout_1.result b/mysql-test/suite/innodb_plugin/r/innodb_lock_wait_timeout_1.result index 3329d420edc..c1e54465066 100644 --- a/mysql-test/suite/innodb_plugin/r/innodb_lock_wait_timeout_1.result +++ b/mysql-test/suite/innodb_plugin/r/innodb_lock_wait_timeout_1.result @@ -304,6 +304,8 @@ begin; # is retreived and processed first. # # Verify that JT_EQ_REF is used. +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='index_condition_pushdown=off'; explain select 1 from t1 natural join (select 3 as a, 2 as b union all select 3 as a, 1 as b) as t2 for update; @@ -326,7 +328,7 @@ key PRIMARY key_len 4 ref t2.a rows 1 -Extra Using index condition; Using where +Extra Using where id 2 select_type DERIVED table NULL @@ -357,6 +359,7 @@ key_len NULL ref NULL rows NULL Extra +set optimizer_switch=@tmp_optimizer_switch; # Lock the record. select 1 from t1 natural join (select 3 as a, 2 as b union all select 3 as a, 1 as b) as t2 for update; diff --git a/mysql-test/suite/innodb_plugin/t/innodb_lock_wait_timeout_1.test b/mysql-test/suite/innodb_plugin/t/innodb_lock_wait_timeout_1.test index 5d5f78093a7..c458b0ba44d 100644 --- a/mysql-test/suite/innodb_plugin/t/innodb_lock_wait_timeout_1.test +++ b/mysql-test/suite/innodb_plugin/t/innodb_lock_wait_timeout_1.test @@ -239,9 +239,12 @@ begin; --echo # --echo # Verify that JT_EQ_REF is used. --vertical_results +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='index_condition_pushdown=off'; explain select 1 from t1 natural join (select 3 as a, 2 as b union all select 3 as a, 1 as b) as t2 for update; +set optimizer_switch=@tmp_optimizer_switch; --horizontal_results --echo # Lock the record. select 1 from t1 natural join (select 3 as a, 2 as b union all From 69e7b1887696a88472d25951341d5bb1df134c0b Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Fri, 25 Nov 2011 14:57:27 +0400 Subject: [PATCH 120/288] Remove garbage comments --- sql/opt_subselect.cc | 8 -------- 1 file changed, 8 deletions(-) diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index 45b8b2facf1..d9f02d381e4 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -2217,16 +2217,8 @@ void advance_sj_state(JOIN *join, table_map remaining_tables, uint idx, pos->prefix_dups_producing_tables= join->cur_dups_producing_tables; TABLE_LIST *emb_sj_nest; if ((emb_sj_nest= new_join_tab->emb_sj_nest)) - { - /// join->cur_sj_inner_tables |= emb_sj_nest->sj_inner_tables; join->cur_dups_producing_tables |= emb_sj_nest->sj_inner_tables; - /* Remove the sj_nest if all of its SJ-inner tables are in cur_table_map */ - /// if (!(remaining_tables & - /// emb_sj_nest->sj_inner_tables & ~new_join_tab->table->map)) - /// join->cur_sj_inner_tables &= ~emb_sj_nest->sj_inner_tables; - } - Semi_join_strategy_picker **strategy; if (idx == join->const_tables) { From aa98fe3a7a240306c2b02260c2b292b7d3b5ac32 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Fri, 25 Nov 2011 15:48:56 +0400 Subject: [PATCH 121/288] Update test results --- mysql-test/r/derived_view.result | 4 ++-- mysql-test/r/explain.result | 8 ++++---- mysql-test/r/join_cache.result | 8 ++++---- mysql-test/r/type_datetime.result | 8 ++++---- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/mysql-test/r/derived_view.result b/mysql-test/r/derived_view.result index d1dc2c7919d..040b3b266d9 100644 --- a/mysql-test/r/derived_view.result +++ b/mysql-test/r/derived_view.result @@ -1479,8 +1479,8 @@ WHERE t3.b IN (SELECT v1.b FROM v1, t2 WHERE t2.c = v1.c AND t2.c = v1.b AND v1.b = t3.c); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 system NULL NULL NULL NULL 1 -1 PRIMARY t3 ALL NULL NULL NULL NULL 2 Using where; Start temporary -1 PRIMARY ALL NULL NULL NULL NULL 3 Using where; End temporary +1 PRIMARY t3 ALL NULL NULL NULL NULL 2 Using where +1 PRIMARY ALL NULL NULL NULL NULL 3 Using where; Start temporary; End temporary 3 DERIVED t1 ALL NULL NULL NULL NULL 3 SELECT * FROM t3 WHERE t3.b IN (SELECT v1.b FROM v1, t2 diff --git a/mysql-test/r/explain.result b/mysql-test/r/explain.result index ab48ccdcf15..856e33258c1 100644 --- a/mysql-test/r/explain.result +++ b/mysql-test/r/explain.result @@ -199,16 +199,16 @@ insert into t2 values ('2001-01-01 1:1:1'), ('2001-01-01 1:1:1'); flush tables; EXPLAIN SELECT OUTR.dt FROM t1 AS OUTR WHERE OUTR.dt IN (SELECT INNR.dt FROM t2 AS INNR WHERE OUTR.dt IS NULL ); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY OUTR ALL NULL NULL NULL NULL 2 Using where; Start temporary -1 PRIMARY INNR ALL NULL NULL NULL NULL 2 Using where; End temporary +1 PRIMARY OUTR ALL NULL NULL NULL NULL 2 Using where +1 PRIMARY INNR ALL NULL NULL NULL NULL 2 Using where; Start temporary; End temporary flush tables; SELECT OUTR.dt FROM t1 AS OUTR WHERE OUTR.dt IN (SELECT INNR.dt FROM t2 AS INNR WHERE OUTR.dt IS NULL ); dt flush tables; EXPLAIN SELECT OUTR.dt FROM t1 AS OUTR WHERE OUTR.dt IN ( SELECT INNR.dt FROM t2 AS INNR WHERE OUTR.t < '2005-11-13 7:41:31' ); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY OUTR ALL NULL NULL NULL NULL 2 Using where; Start temporary -1 PRIMARY INNR ALL NULL NULL NULL NULL 2 Using where; End temporary +1 PRIMARY OUTR ALL NULL NULL NULL NULL 2 Using where +1 PRIMARY INNR ALL NULL NULL NULL NULL 2 Using where; Start temporary; End temporary flush tables; SELECT OUTR.dt FROM t1 AS OUTR WHERE OUTR.dt IN ( SELECT INNR.dt FROM t2 AS INNR WHERE OUTR.t < '2005-11-13 7:41:31' ); dt diff --git a/mysql-test/r/join_cache.result b/mysql-test/r/join_cache.result index af3d238c1fd..be579c9240f 100644 --- a/mysql-test/r/join_cache.result +++ b/mysql-test/r/join_cache.result @@ -5137,8 +5137,8 @@ EXPLAIN SELECT * FROM (SELECT DISTINCT * FROM t1) t WHERE t.a IN (SELECT t2.a FROM t2); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY ALL key0 NULL NULL NULL 3 Start temporary -1 PRIMARY t2 ALL NULL NULL NULL NULL 4 Using where; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY ALL key0 NULL NULL NULL 3 +1 PRIMARY t2 ALL NULL NULL NULL NULL 4 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) 2 DERIVED t1 ALL NULL NULL NULL NULL 3 Using temporary SELECT * FROM (SELECT DISTINCT * FROM t1) t WHERE t.a IN (SELECT t2.a FROM t2); @@ -5170,8 +5170,8 @@ SET SESSION join_cache_level=3; EXPLAIN SELECT * FROM t1 WHERE (t1.b) IN (SELECT c FROM t2); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where; Start temporary -1 PRIMARY t2 hash_index c #hash#c:c 5:5 test.t1.b 8 End temporary; Using join buffer (flat, BNLH join) +1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where +1 PRIMARY t2 hash_index c #hash#c:c 5:5 test.t1.b 8 Start temporary; End temporary; Using join buffer (flat, BNLH join) SELECT * FROM t1 WHERE (t1.b) IN (SELECT c FROM t2); a b 3914 17 diff --git a/mysql-test/r/type_datetime.result b/mysql-test/r/type_datetime.result index e4c289711a1..966343fa80f 100644 --- a/mysql-test/r/type_datetime.result +++ b/mysql-test/r/type_datetime.result @@ -538,8 +538,8 @@ explain extended select * from t1 where id in (select id from t1 as x1 where (t1.cur_date is null)); 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 Using where; Start temporary -1 PRIMARY x1 ALL NULL NULL NULL NULL 2 100.00 Using where; End temporary +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00 Using where +1 PRIMARY x1 ALL NULL NULL NULL NULL 2 100.00 Using where; Start temporary; End temporary Warnings: Note 1276 Field or reference 'test.t1.cur_date' of SELECT #2 was resolved in SELECT #1 Note 1003 select `test`.`t1`.`id` AS `id`,`test`.`t1`.`cur_date` AS `cur_date` from `test`.`t1` semi join (`test`.`t1` `x1`) where ((`test`.`x1`.`id` = `test`.`t1`.`id`) and (`test`.`t1`.`cur_date` = 0)) @@ -550,8 +550,8 @@ explain extended select * from t2 where id in (select id from t2 as x1 where (t2.cur_date is null)); id select_type table type possible_keys key key_len ref rows filtered Extra -1 PRIMARY t2 ALL NULL NULL NULL NULL 2 100.00 Using where; Start temporary -1 PRIMARY x1 ALL NULL NULL NULL NULL 2 100.00 Using where; End temporary +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 100.00 Using where +1 PRIMARY x1 ALL NULL NULL NULL NULL 2 100.00 Using where; Start temporary; End temporary Warnings: Note 1276 Field or reference 'test.t2.cur_date' of SELECT #2 was resolved in SELECT #1 Note 1003 select `test`.`t2`.`id` AS `id`,`test`.`t2`.`cur_date` AS `cur_date` from `test`.`t2` semi join (`test`.`t2` `x1`) where ((`test`.`x1`.`id` = `test`.`t2`.`id`) and (`test`.`t2`.`cur_date` = 0)) From b796833e8da682dbbca38eab5650fc569000dcf7 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Fri, 25 Nov 2011 21:45:58 +0400 Subject: [PATCH 122/288] Update test results --- mysql-test/suite/pbxt/r/subselect.result | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/pbxt/r/subselect.result b/mysql-test/suite/pbxt/r/subselect.result index ce017889762..6b1ed9ea052 100644 --- a/mysql-test/suite/pbxt/r/subselect.result +++ b/mysql-test/suite/pbxt/r/subselect.result @@ -1360,8 +1360,8 @@ a 3 explain extended select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a); id select_type table type possible_keys key key_len ref rows filtered Extra -1 PRIMARY t2 index a a 5 NULL 4 100.00 Using where; Using index; Start temporary -1 PRIMARY t1 ref a a 5 test.t2.a 1 100.00 Using index +1 PRIMARY t2 index a a 5 NULL 4 100.00 Using where; Using index +1 PRIMARY t1 ref a a 5 test.t2.a 1 100.00 Using index; Start temporary 1 PRIMARY t3 index a a 5 NULL 3 100.00 Using where; Using index; End temporary Warnings: Note 1003 select `test`.`t2`.`a` AS `a` from `test`.`t2` semi join (`test`.`t1` join `test`.`t3`) where ((`test`.`t1`.`a` = `test`.`t2`.`a`) and (`test`.`t3`.`a` = `test`.`t1`.`b`)) From fa366521cf80fd2ed968a0a4ac9d68ca4d7c5b20 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Fri, 25 Nov 2011 22:54:13 +0400 Subject: [PATCH 123/288] Remove garbage comment --- sql/opt_subselect.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index b61d5c421b2..c1b2eab5279 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -2962,7 +2962,6 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join) if (tablenr != first) pos->sj_strategy= SJ_OPT_NONE; remaining_tables |= s->table->map; - //s->sj_strategy= pos->sj_strategy; join->join_tab[first].sj_strategy= join->best_positions[first].sj_strategy; join->join_tab[first].n_sj_tables= join->best_positions[first].n_sj_tables; } From 8325848b6ec4189b8339355689060a19d226a92f Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Fri, 25 Nov 2011 23:54:36 +0400 Subject: [PATCH 124/288] Subquery code cleanups: - Make functions that operate on SJ_TMP_TABLE be member functions - Make Loose_scan_opt data members private --- sql/opt_subselect.cc | 86 ++++++++++++++++++++----------------------- sql/opt_subselect.h | 10 ++--- sql/sql_join_cache.cc | 2 +- sql/sql_select.cc | 6 +-- 4 files changed, 48 insertions(+), 56 deletions(-) diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index d9f02d381e4..f8e495de9bf 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -3472,12 +3472,8 @@ static bool is_cond_sj_in_equality(Item *item) SYNOPSIS - create_duplicate_weedout_tmp_table() + create_sj_weedout_tmp_table() thd Thread handle - uniq_tuple_length_arg Length of the table's column - sjtbl Update sjtbl->[start_]recinfo values which - will be needed if we'll need to convert the - created temptable from HEAP to MyISAM/Maria. DESCRIPTION Create a temporary table to weed out duplicate rowid combinations. The @@ -3502,9 +3498,8 @@ static bool is_cond_sj_in_equality(Item *item) NULL on error */ -TABLE *create_duplicate_weedout_tmp_table(THD *thd, - uint uniq_tuple_length_arg, - SJ_TMP_TABLE *sjtbl) +bool +SJ_TMP_TABLE::create_sj_weedout_tmp_table(THD *thd) { MEM_ROOT *mem_root_save, own_root; TABLE *table; @@ -3517,15 +3512,17 @@ TABLE *create_duplicate_weedout_tmp_table(THD *thd, uchar *group_buff; uchar *bitmaps; uint *blob_field; - ENGINE_COLUMNDEF *recinfo, *start_recinfo; bool using_unique_constraint=FALSE; bool use_packed_rows= FALSE; Field *field, *key_field; uint null_pack_length, null_count; uchar *null_flags; uchar *pos; - DBUG_ENTER("create_duplicate_weedout_tmp_table"); - DBUG_ASSERT(!sjtbl->is_degenerate); + DBUG_ENTER("create_sj_weedout_tmp_table"); + DBUG_ASSERT(!is_degenerate); + + tmp_table= NULL; + uint uniq_tuple_length_arg= rowid_len + null_bytes; /* STEP 1: Get temporary table name */ @@ -3567,7 +3564,7 @@ TABLE *create_duplicate_weedout_tmp_table(THD *thd, { if (temp_pool_slot != MY_BIT_NONE) bitmap_lock_clear_bit(&temp_pool, temp_pool_slot); - DBUG_RETURN(NULL); + DBUG_RETURN(TRUE); } strmov(tmpname,path); @@ -3771,20 +3768,19 @@ TABLE *create_duplicate_weedout_tmp_table(THD *thd, if (create_internal_tmp_table(table, keyinfo, start_recinfo, &recinfo, 0)) goto err; } - sjtbl->start_recinfo= start_recinfo; - sjtbl->recinfo= recinfo; if (open_tmp_table(table)) goto err; thd->mem_root= mem_root_save; - DBUG_RETURN(table); + tmp_table= table; + DBUG_RETURN(FALSE); err: thd->mem_root= mem_root_save; free_tmp_table(thd,table); /* purecov: inspected */ if (temp_pool_slot != MY_BIT_NONE) bitmap_lock_clear_bit(&temp_pool, temp_pool_slot); - DBUG_RETURN(NULL); /* purecov: inspected */ + DBUG_RETURN(TRUE); /* purecov: inspected */ } @@ -3792,25 +3788,25 @@ err: SemiJoinDuplicateElimination: Reset the temporary table */ -int do_sj_reset(SJ_TMP_TABLE *sj_tbl) +int SJ_TMP_TABLE::sj_weedout_delete_rows() { - DBUG_ENTER("do_sj_reset"); - if (sj_tbl->tmp_table) + DBUG_ENTER("SJ_TMP_TABLE::sj_weedout_delete_rows"); + if (tmp_table) { - int rc= sj_tbl->tmp_table->file->ha_delete_all_rows(); + int rc= tmp_table->file->ha_delete_all_rows(); DBUG_RETURN(rc); } - sj_tbl->have_degenerate_row= FALSE; + have_degenerate_row= FALSE; DBUG_RETURN(0); } + /* SemiJoinDuplicateElimination: Weed out duplicate row combinations SYNPOSIS - do_sj_dups_weedout() + sj_weedout_check_row() thd Thread handle - sjtbl Duplicate weedout table DESCRIPTION Try storing current record combination of outer tables (i.e. their @@ -3823,47 +3819,47 @@ int do_sj_reset(SJ_TMP_TABLE *sj_tbl) 0 The row combination is not a duplicate (continue) */ -int do_sj_dups_weedout(THD *thd, SJ_TMP_TABLE *sjtbl) +int SJ_TMP_TABLE::sj_weedout_check_row(THD *thd) { int error; - SJ_TMP_TABLE::TAB *tab= sjtbl->tabs; - SJ_TMP_TABLE::TAB *tab_end= sjtbl->tabs_end; + SJ_TMP_TABLE::TAB *tab= tabs; + SJ_TMP_TABLE::TAB *tab_end= tabs_end; uchar *ptr; uchar *nulls_ptr; - DBUG_ENTER("do_sj_dups_weedout"); + DBUG_ENTER("SJ_TMP_TABLE::sj_weedout_check_row"); - if (sjtbl->is_degenerate) + if (is_degenerate) { - if (sjtbl->have_degenerate_row) + if (have_degenerate_row) DBUG_RETURN(1); - sjtbl->have_degenerate_row= TRUE; + have_degenerate_row= TRUE; DBUG_RETURN(0); } - ptr= sjtbl->tmp_table->record[0] + 1; + ptr= tmp_table->record[0] + 1; /* Put the the rowids tuple into table->record[0]: */ // 1. Store the length - if (((Field_varstring*)(sjtbl->tmp_table->field[0]))->length_bytes == 1) + if (((Field_varstring*)(tmp_table->field[0]))->length_bytes == 1) { - *ptr= (uchar)(sjtbl->rowid_len + sjtbl->null_bytes); + *ptr= (uchar)(rowid_len + null_bytes); ptr++; } else { - int2store(ptr, sjtbl->rowid_len + sjtbl->null_bytes); + int2store(ptr, rowid_len + null_bytes); ptr += 2; } nulls_ptr= ptr; // 2. Zero the null bytes - if (sjtbl->null_bytes) + if (null_bytes) { - bzero(ptr, sjtbl->null_bytes); - ptr += sjtbl->null_bytes; + bzero(ptr, null_bytes); + ptr += null_bytes; } // 3. Put the rowids @@ -3883,15 +3879,14 @@ int do_sj_dups_weedout(THD *thd, SJ_TMP_TABLE *sjtbl) } } - error= sjtbl->tmp_table->file->ha_write_tmp_row(sjtbl->tmp_table->record[0]); + error= tmp_table->file->ha_write_tmp_row(tmp_table->record[0]); if (error) { /* create_internal_tmp_table_from_heap will generate error if needed */ - if (!sjtbl->tmp_table->file->is_fatal_error(error, HA_CHECK_DUP)) + if (!tmp_table->file->is_fatal_error(error, HA_CHECK_DUP)) DBUG_RETURN(1); /* Duplicate */ - if (create_internal_tmp_table_from_heap(thd, sjtbl->tmp_table, - sjtbl->start_recinfo, - &sjtbl->recinfo, error, 1)) + if (create_internal_tmp_table_from_heap(thd, tmp_table, start_recinfo, + &recinfo, error, 1)) DBUG_RETURN(-1); } DBUG_RETURN(0); @@ -3943,11 +3938,8 @@ int init_dups_weedout(JOIN *join, uint first_table, int first_fanout_table, uint sjtbl->rowid_len= jt_rowid_offset; sjtbl->null_bits= jt_null_bits; sjtbl->null_bytes= (jt_null_bits + 7)/8; - sjtbl->tmp_table= - create_duplicate_weedout_tmp_table(thd, - sjtbl->rowid_len + - sjtbl->null_bytes, - sjtbl); + if (sjtbl->create_sj_weedout_tmp_table(thd)) + DBUG_RETURN(TRUE); join->sj_tmp_tables.push_back(sjtbl->tmp_table); } else diff --git a/sql/opt_subselect.h b/sql/opt_subselect.h index b5886ae06a2..94c6153f0c1 100644 --- a/sql/opt_subselect.h +++ b/sql/opt_subselect.h @@ -40,7 +40,6 @@ ulonglong get_bound_sj_equalities(TABLE_LIST *sj_nest, class Loose_scan_opt { -public: /* All methods must check this before doing anything else */ bool try_loosescan; @@ -71,6 +70,7 @@ public: uint best_max_loose_keypart; +public: Loose_scan_opt(): try_loosescan(FALSE), bound_sj_equalities(0), @@ -288,10 +288,6 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join); bool setup_sj_materialization_part1(JOIN_TAB *sjm_tab); bool setup_sj_materialization_part2(JOIN_TAB *sjm_tab); -TABLE *create_duplicate_weedout_tmp_table(THD *thd, uint uniq_tuple_length_arg, - SJ_TMP_TABLE *sjtbl); -int do_sj_reset(SJ_TMP_TABLE *sj_tbl); -int do_sj_dups_weedout(THD *thd, SJ_TMP_TABLE *sjtbl); /* Temporary table used by semi-join DuplicateElimination strategy @@ -359,6 +355,10 @@ public: ENGINE_COLUMNDEF *recinfo; SJ_TMP_TABLE *next_flush_table; + + int sj_weedout_delete_rows(); + int sj_weedout_check_row(THD *thd); + bool create_sj_weedout_tmp_table(THD *thd); }; int setup_semijoin_dups_elimination(JOIN *join, ulonglong options, diff --git a/sql/sql_join_cache.cc b/sql/sql_join_cache.cc index f53bf738b86..af4b157ba90 100644 --- a/sql/sql_join_cache.cc +++ b/sql/sql_join_cache.cc @@ -2367,7 +2367,7 @@ enum_nested_loop_state JOIN_CACHE::generate_full_extensions(uchar *rec_ptr) int res= 0; if (!join_tab->check_weed_out_table || - !(res= do_sj_dups_weedout(join->thd, join_tab->check_weed_out_table))) + !(res= join_tab->check_weed_out_table->sj_weedout_check_row(join->thd))) { set_curr_rec_link(rec_ptr); rc= (join_tab->next_select)(join, join_tab+1, 0); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 11fadf56656..d8c17012196 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -15105,7 +15105,7 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records) flush_dups_table; flush_dups_table= flush_dups_table->next_flush_table) { - do_sj_reset(flush_dups_table); + flush_dups_table->sj_weedout_delete_rows(); } if (!join_tab->preread_init_done && join_tab->preread_init()) @@ -15321,7 +15321,7 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, if (join_tab->check_weed_out_table && found) { - int res= do_sj_dups_weedout(join->thd, join_tab->check_weed_out_table); + int res= join_tab->check_weed_out_table->sj_weedout_check_row(join->thd); if (res == -1) DBUG_RETURN(NESTED_LOOP_ERROR); else if (res == 1) @@ -15445,7 +15445,7 @@ evaluate_null_complemented_join_record(JOIN *join, JOIN_TAB *join_tab) */ if (join_tab->check_weed_out_table) { - int res= do_sj_dups_weedout(join->thd, join_tab->check_weed_out_table); + int res= join_tab->check_weed_out_table->sj_weedout_check_row(join->thd); if (res == -1) return NESTED_LOOP_ERROR; else if (res == 1) From 17b4e4a194ea513f776bab5010d88d24a51b9d9e Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Sat, 26 Nov 2011 14:23:00 -0800 Subject: [PATCH 125/288] Set new default values for the optimizer switch flags 'derived_merge' and 'derived_with_keys'. Now they are set on by default. --- mysql-test/include/index_merge1.inc | 3 ++ mysql-test/r/derived.result | 4 +++ mysql-test/r/explain.result | 3 ++ mysql-test/r/func_group.result | 3 ++ mysql-test/r/func_str.result | 3 ++ mysql-test/r/index_merge_innodb.result | 3 ++ mysql-test/r/index_merge_myisam.result | 3 ++ mysql-test/r/information_schema.result | 3 ++ mysql-test/r/optimizer_switch.result | 36 +++++++++---------- mysql-test/r/ps.result | 3 ++ mysql-test/r/subselect.result | 6 ++++ mysql-test/r/subselect3.result | 3 ++ mysql-test/r/subselect3_jcl6.result | 3 ++ mysql-test/r/subselect_mat.result | 3 ++ mysql-test/r/subselect_mat_cost_bugs.result | 6 ++++ mysql-test/r/subselect_no_mat.result | 6 ++++ mysql-test/r/subselect_no_opts.result | 6 ++++ mysql-test/r/subselect_no_scache.result | 6 ++++ mysql-test/r/subselect_no_semijoin.result | 6 ++++ mysql-test/r/subselect_partial_match.result | 3 ++ mysql-test/r/subselect_sj.result | 3 ++ mysql-test/r/subselect_sj_jcl6.result | 3 ++ mysql-test/r/subselect_sj_mat.result | 3 ++ .../r/innodb_lock_wait_timeout_1.result | 6 ++++ .../innodb/t/innodb_lock_wait_timeout_1.test | 6 ++++ .../r/innodb_lock_wait_timeout_1.result | 2 ++ .../t/innodb_lock_wait_timeout_1.test | 2 ++ mysql-test/suite/pbxt/r/derived.result | 4 +++ mysql-test/suite/pbxt/r/subselect.result | 3 ++ mysql-test/suite/pbxt/t/derived.test | 6 ++++ mysql-test/suite/pbxt/t/subselect.test | 3 ++ mysql-test/suite/vcol/inc/vcol_select.inc | 6 ++++ .../suite/vcol/r/vcol_select_innodb.result | 3 ++ .../suite/vcol/r/vcol_select_myisam.result | 3 ++ mysql-test/t/derived.test | 6 ++++ mysql-test/t/explain.test | 3 ++ mysql-test/t/func_group.test | 3 ++ mysql-test/t/func_str.test | 6 +++- mysql-test/t/index_merge_innodb.test | 3 ++ mysql-test/t/information_schema.test | 3 ++ mysql-test/t/ps.test | 6 ++++ mysql-test/t/subselect.test | 6 ++++ mysql-test/t/subselect3.test | 3 ++ mysql-test/t/subselect_mat_cost_bugs.test | 8 +++++ mysql-test/t/subselect_partial_match.test | 3 ++ mysql-test/t/subselect_sj.test | 5 +++ mysql-test/t/subselect_sj_mat.test | 3 ++ sql/mysql_priv.h | 2 ++ sql/mysqld.cc | 4 +-- 49 files changed, 208 insertions(+), 21 deletions(-) diff --git a/mysql-test/include/index_merge1.inc b/mysql-test/include/index_merge1.inc index 238d3797fe8..4ad9c2046e0 100644 --- a/mysql-test/include/index_merge1.inc +++ b/mysql-test/include/index_merge1.inc @@ -264,7 +264,10 @@ explain select * from t1 where key1=3 or key2=4 union select * from t1 where key1<4 or key3=5; # index merge in subselect +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; explain select * from (select * from t1 where key1 = 3 or key2 =3) as Z where key8 >5; +set optimizer_switch=@tmp_optimizer_switch; # 12. check for long index_merges. create table t3 like t0; diff --git a/mysql-test/r/derived.result b/mysql-test/r/derived.result index cb84d10e0fa..f34810ada6a 100644 --- a/mysql-test/r/derived.result +++ b/mysql-test/r/derived.result @@ -1,4 +1,6 @@ drop table if exists t1,t2,t3; +set @save_derived_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; select * from (select 2 from DUAL) b; 2 2 @@ -205,6 +207,7 @@ x 1 create user mysqltest_1; create table t1 select 1 as a; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; select 2 as a from (select * from t1) b; ERROR 3D000: No database selected use test; @@ -413,3 +416,4 @@ MIN(i) 1 DROP TABLE t1; # End of 5.0 tests +set optimizer_switch=@save_derived_optimizer_switch; diff --git a/mysql-test/r/explain.result b/mysql-test/r/explain.result index 856e33258c1..2493b04488f 100644 --- a/mysql-test/r/explain.result +++ b/mysql-test/r/explain.result @@ -309,6 +309,8 @@ End of 5.1 tests. CREATE TABLE t1 (a int) ; CREATE TABLE t2 (a int) ; INSERT INTO t2 VALUES (8); +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; EXPLAIN EXTENDED SELECT * FROM ( SELECT t1.a FROM t1,t2 WHERE t2.a = t1.a ) AS t; id select_type table type possible_keys key key_len ref rows filtered Extra @@ -316,4 +318,5 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 2 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL no matching row in const table Warnings: Note 1003 select NULL AS `a` from (select NULL AS `a` from `test`.`t1` join `test`.`t2` where 0) `t` +set optimizer_switch=@tmp_optimizer_switch; DROP TABLE t1,t2; diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result index a24784ace4b..0983d76f449 100644 --- a/mysql-test/r/func_group.result +++ b/mysql-test/r/func_group.result @@ -1930,6 +1930,8 @@ FROM t2); MIN(a) NULL +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; EXPLAIN SELECT MIN(a) FROM (SELECT a FROM empty1) tt @@ -1940,6 +1942,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY system NULL NULL NULL NULL 0 const row not found 3 SUBQUERY t2 ALL NULL NULL NULL NULL 2 2 DERIVED NULL NULL NULL NULL NULL NULL NULL no matching row in const table +set optimizer_switch=@tmp_optimizer_switch; # # 5) Test that subquery materialization is setup for query with diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index f23026096a5..a239a74acb1 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -2547,6 +2547,8 @@ End of 5.0 tests drop table if exists t1; create table t1(f1 tinyint default null)engine=myisam; insert into t1 values (-1),(null); +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; explain select 1 as a from t1,(select decode(f1,f1) as b from t1) a; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 2 @@ -2557,6 +2559,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 2 1 PRIMARY ALL NULL NULL NULL NULL 2 Using join buffer (flat, BNL join) 2 DERIVED t1 ALL NULL NULL NULL NULL 2 +set optimizer_switch=@tmp_optimizer_switch; drop table t1; # # Bug#49141: Encode function is significantly slower in 5.1 compared to 5.0 diff --git a/mysql-test/r/index_merge_innodb.result b/mysql-test/r/index_merge_innodb.result index 773e74f9701..bde2324028f 100644 --- a/mysql-test/r/index_merge_innodb.result +++ b/mysql-test/r/index_merge_innodb.result @@ -686,6 +686,8 @@ INSERT INTO t1(a,b) SELECT a,b FROM t1; INSERT INTO t1(a,b) SELECT a,b FROM t1; INSERT INTO t1 VALUES (1000000, 0, 0); SET SESSION sort_buffer_size = 1024*36; +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; EXPLAIN SELECT COUNT(*) FROM (SELECT * FROM t1 FORCE INDEX(primary,idx) @@ -711,6 +713,7 @@ WHERE a BETWEEN 2 AND 7 OR pk=1000000) AS t; COUNT(*) 6145 DROP TABLE t1; +set optimizer_switch=@tmp_optimizer_switch; # # Testcase Backport: BUG#48093: 6.0 Server not processing equivalent IN clauses properly # with Innodb tables diff --git a/mysql-test/r/index_merge_myisam.result b/mysql-test/r/index_merge_myisam.result index 1f35fb7a16e..3616171ef58 100644 --- a/mysql-test/r/index_merge_myisam.result +++ b/mysql-test/r/index_merge_myisam.result @@ -285,10 +285,13 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 index_merge i1,i2 i1,i2 4,4 NULL 2 Using union(i1,i2); Using where 2 UNION t1 index_merge i1,i3 i1,i3 4,4 NULL 5 Using sort_union(i1,i3); Using where NULL UNION RESULT ALL NULL NULL NULL NULL NULL +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; explain select * from (select * from t1 where key1 = 3 or key2 =3) as Z where key8 >5; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL NULL NULL NULL NULL 2 Using where 2 DERIVED t1 index_merge i1,i2 i1,i2 4,4 NULL 2 Using union(i1,i2); Using where +set optimizer_switch=@tmp_optimizer_switch; create table t3 like t0; insert into t3 select * from t0; alter table t3 add key9 int not null, add index i9(key9); diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index 1f56ee4d53b..6694cf48109 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -1277,6 +1277,8 @@ COLUMN_NAME MD5(COLUMN_DEFAULT) LENGTH(COLUMN_DEFAULT) COLUMN_DEFAULT=get_value( fld1 7cf7a6782be951a1f2464a350da926a5 65532 1 DROP TABLE bug23037; DROP FUNCTION get_value; +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; create view v1 as select table_schema as object_schema, table_name as object_name, @@ -1290,6 +1292,7 @@ explain select * from (select table_name from information_schema.tables) as a; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL NULL NULL NULL NULL 2 2 DERIVED tables ALL NULL NULL NULL NULL NULL Skip_open_table; Scanned all databases +set optimizer_switch=@tmp_optimizer_switch; drop view v1; create table t1 (f1 int(11)); create table t2 (f1 int(11), f2 int(11)); diff --git a/mysql-test/r/optimizer_switch.result b/mysql-test/r/optimizer_switch.result index 842b99ccb11..1606547e137 100644 --- a/mysql-test/r/optimizer_switch.result +++ b/mysql-test/r/optimizer_switch.result @@ -4,19 +4,19 @@ # select @@optimizer_switch; @@optimizer_switch -index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=off,derived_with_keys=off,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off +index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off set optimizer_switch='index_merge=off,index_merge_union=off'; select @@optimizer_switch; @@optimizer_switch -index_merge=off,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=off,derived_with_keys=off,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off +index_merge=off,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off set optimizer_switch='index_merge_union=on'; select @@optimizer_switch; @@optimizer_switch -index_merge=off,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=off,derived_with_keys=off,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off +index_merge=off,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off set optimizer_switch='default,index_merge_sort_union=off'; select @@optimizer_switch; @@optimizer_switch -index_merge=on,index_merge_union=on,index_merge_sort_union=off,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=off,derived_with_keys=off,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off +index_merge=on,index_merge_union=on,index_merge_sort_union=off,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off set optimizer_switch=4; ERROR 42000: Variable 'optimizer_switch' can't be set to the value of '4' set optimizer_switch=NULL; @@ -43,60 +43,60 @@ set optimizer_switch=default; set optimizer_switch='index_merge=off,index_merge_union=off,default'; select @@optimizer_switch; @@optimizer_switch -index_merge=off,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=off,derived_with_keys=off,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off +index_merge=off,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off set optimizer_switch=default; select @@global.optimizer_switch; @@global.optimizer_switch -index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=off,derived_with_keys=off,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off +index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off set @@global.optimizer_switch=default; select @@global.optimizer_switch; @@global.optimizer_switch -index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=off,derived_with_keys=off,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off +index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off # # Check index_merge's @@optimizer_switch flags # select @@optimizer_switch; @@optimizer_switch -index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=off,derived_with_keys=off,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off +index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off BUG#37120 optimizer_switch allowable values not according to specification select @@optimizer_switch; @@optimizer_switch -index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=off,derived_with_keys=off,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off +index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off set optimizer_switch='default,materialization=off'; select @@optimizer_switch; @@optimizer_switch -index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=off,derived_with_keys=off,firstmatch=on,loosescan=on,materialization=off,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off +index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=off,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off set optimizer_switch='default,semijoin=off'; select @@optimizer_switch; @@optimizer_switch -index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=off,derived_with_keys=off,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off +index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off set optimizer_switch='default,loosescan=off'; select @@optimizer_switch; @@optimizer_switch -index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=off,derived_with_keys=off,firstmatch=on,loosescan=off,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off +index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=off,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off set optimizer_switch='default,semijoin=off,materialization=off'; select @@optimizer_switch; @@optimizer_switch -index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=off,derived_with_keys=off,firstmatch=on,loosescan=on,materialization=off,in_to_exists=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off +index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=off,in_to_exists=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off set optimizer_switch='default,materialization=off,semijoin=off'; select @@optimizer_switch; @@optimizer_switch -index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=off,derived_with_keys=off,firstmatch=on,loosescan=on,materialization=off,in_to_exists=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off +index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=off,in_to_exists=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off set optimizer_switch='default,semijoin=off,materialization=off,loosescan=off'; select @@optimizer_switch; @@optimizer_switch -index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=off,derived_with_keys=off,firstmatch=on,loosescan=off,materialization=off,in_to_exists=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off +index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=off,materialization=off,in_to_exists=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off set optimizer_switch='default,semijoin=off,loosescan=off'; select @@optimizer_switch; @@optimizer_switch -index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=off,derived_with_keys=off,firstmatch=on,loosescan=off,materialization=on,in_to_exists=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off +index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=off,materialization=on,in_to_exists=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off set optimizer_switch='default,materialization=off,loosescan=off'; select @@optimizer_switch; @@optimizer_switch -index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=off,derived_with_keys=off,firstmatch=on,loosescan=off,materialization=off,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off +index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=off,materialization=off,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off set optimizer_switch=default; select @@optimizer_switch; @@optimizer_switch -index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=off,derived_with_keys=off,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off +index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index 90981166fb6..becea752810 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -151,6 +151,8 @@ c32 set('monday', 'tuesday', 'wednesday') create table t2 like t1; set @save_optimizer_switch=@@optimizer_switch; set @@optimizer_switch="partial_match_rowid_merge=off,partial_match_table_scan=off"; +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; set @stmt= ' explain SELECT (SELECT SUM(c1 + c12 + 0.0) FROM t2 where (t1.c2 - 0e-3) = t2.c2 GROUP BY t1.c15 LIMIT 1) as scalar_s, exists (select 1.0e+0 from t2 where t2.c3 * 9.0000000000 = t1.c4) as exists_s, c5 * 4 in (select c6 + 0.3e+1 from t2) as in_s, (c7 - 4, c8 - 4) in (select c9 + 4.0, c10 + 40e-1 from t2) as in_row_s FROM t1, (select c25 x, c32 y from t2) tt WHERE x * 1 = c25 ' ; prepare stmt1 from @stmt ; execute stmt1 ; @@ -178,6 +180,7 @@ id select_type table type possible_keys key key_len ref rows Extra 3 DEPENDENT SUBQUERY 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 WHERE noticed after reading const tables deallocate prepare stmt1; +set optimizer_switch=@tmp_optimizer_switch; drop tables t1,t2; set @@optimizer_switch=@save_optimizer_switch; set @arg00=1; diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index cf501b3fb28..c2acdf7f018 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -201,6 +201,8 @@ select (select t3.a from t3 where a<8 order by 1 desc limit 1), a from (select * from t2 where a>1) as tt; (select t3.a from t3 where a<8 order by 1 desc limit 1) a 7 2 +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; explain extended select (select t3.a from t3 where a<8 order by 1 desc limit 1), a from (select * from t2 where a>1) as tt; id select_type table type possible_keys key key_len ref rows filtered Extra @@ -209,6 +211,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 2 SUBQUERY t3 ALL NULL NULL NULL NULL 3 100.00 Using where; Using filesort Warnings: Note 1003 select (select `test`.`t3`.`a` from `test`.`t3` where (`test`.`t3`.`a` < 8) order by 1 desc limit 1) AS `(select t3.a from t3 where a<8 order by 1 desc limit 1)`,`tt`.`a` AS `a` from (select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t2` where (`test`.`t2`.`a` > 1)) `tt` +set optimizer_switch=@tmp_optimizer_switch; select * from t1 where t1.a=(select t2.a from t2 where t2.b=(select max(a) from t3) order by 1 desc limit 1); a 2 @@ -5536,10 +5539,13 @@ DROP TABLE parent, child; CREATE TABLE t1 (a INT, b INT, INDEX (a)); INSERT INTO t1 VALUES (3, 10), (2, 20), (7, 10), (5, 20); +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; 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 ALL NULL NULL NULL NULL 2 2 DERIVED t1 ref a a 5 const 1 +set optimizer_switch=@tmp_optimizer_switch; 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 diff --git a/mysql-test/r/subselect3.result b/mysql-test/r/subselect3.result index 8b1d7e46e4e..28436a7cc23 100644 --- a/mysql-test/r/subselect3.result +++ b/mysql-test/r/subselect3.result @@ -1119,12 +1119,15 @@ a set @@optimizer_switch=@save_optimizer_switch; set @@optimizer_switch=@save_optimizer_switch; set @@optimizer_switch='materialization=off'; +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; explain select * from (select a from t0) X where a in (select a from t1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL NULL NULL NULL NULL 11 1 PRIMARY t1 ALL NULL NULL NULL NULL 20 Using where; FirstMatch(); Using join buffer (flat, BNL join) 2 DERIVED t0 ALL NULL NULL NULL NULL 11 drop table t0, t1; +set optimizer_switch=@tmp_optimizer_switch; 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)); diff --git a/mysql-test/r/subselect3_jcl6.result b/mysql-test/r/subselect3_jcl6.result index 8bf699fbc4d..59848c565d5 100644 --- a/mysql-test/r/subselect3_jcl6.result +++ b/mysql-test/r/subselect3_jcl6.result @@ -1128,12 +1128,15 @@ a set @@optimizer_switch=@save_optimizer_switch; set @@optimizer_switch=@save_optimizer_switch; set @@optimizer_switch='materialization=off'; +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; explain select * from (select a from t0) X where a in (select a from t1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL NULL NULL NULL NULL 11 1 PRIMARY t1 ALL NULL NULL NULL NULL 20 Using where; FirstMatch(); Using join buffer (flat, BNL join) 2 DERIVED t0 ALL NULL NULL NULL NULL 11 drop table t0, t1; +set optimizer_switch=@tmp_optimizer_switch; 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)); diff --git a/mysql-test/r/subselect_mat.result b/mysql-test/r/subselect_mat.result index 499963710e1..8eaad6d8034 100644 --- a/mysql-test/r/subselect_mat.result +++ b/mysql-test/r/subselect_mat.result @@ -1337,6 +1337,8 @@ DROP TABLE t1,t2,t3; CREATE TABLE t1 (a INTEGER); CREATE TABLE t2 (b INTEGER); INSERT INTO t2 VALUES (1); +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; explain SELECT a FROM ( SELECT t1.* FROM t1 LEFT JOIN t2 ON t1.a > 3 OR t2.b IN (SELECT a FROM t1) ) table1; @@ -1348,6 +1350,7 @@ SELECT a FROM ( SELECT t1.* FROM t1 LEFT JOIN t2 ON t1.a > 3 OR t2.b IN (SELECT a FROM t1) ) table1; a +set optimizer_switch=@tmp_optimizer_switch; DROP TABLE t1, t2; # End BUG#56367 # diff --git a/mysql-test/r/subselect_mat_cost_bugs.result b/mysql-test/r/subselect_mat_cost_bugs.result index dc6421df395..5623aef011e 100644 --- a/mysql-test/r/subselect_mat_cost_bugs.result +++ b/mysql-test/r/subselect_mat_cost_bugs.result @@ -156,6 +156,8 @@ drop table t1, t2, t3; CREATE TABLE t2 ( f2 int(11)) ; CREATE TABLE t1 ( f3 int(11), KEY (f3)) ; INSERT INTO t1 VALUES (6),(4); +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; EXPLAIN SELECT * FROM (SELECT * FROM t2) AS a2 WHERE (SELECT distinct SUM(distinct f3 ) FROM t1); @@ -171,6 +173,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL NULL NULL NULL NULL 2 3 SUBQUERY t1 index NULL f3 5 NULL 2 Using index 2 DERIVED t2 ALL NULL NULL NULL NULL 2 +set optimizer_switch=@tmp_optimizer_switch; drop table t1,t2; # # LP BUG#715027 Assertion `!table || (!table->read_set || bitmap_is_set(table->read_set, field_index))' failed @@ -179,6 +182,8 @@ CREATE TABLE t1 ( f1 int(11), PRIMARY KEY (f1)) ; INSERT INTO t1 VALUES (28),(29); CREATE TABLE t2 ( f2 int(11), f3 int(11), f10 varchar(1)) ; INSERT INTO t2 VALUES (NULL,6,'f'),(4,2,'d'); +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; EXPLAIN SELECT alias2.f2 AS field1 FROM t1 AS alias1 JOIN ( SELECT * FROM t2 ) AS alias2 ON alias2.f3 = alias1.f1 @@ -203,6 +208,7 @@ WHERE t1.f1 AND alias2.f10 ) ORDER BY field1 ; field1 +set optimizer_switch=@tmp_optimizer_switch; drop table t1,t2; # # LP BUG#718578 Yet another Assertion `!table || diff --git a/mysql-test/r/subselect_no_mat.result b/mysql-test/r/subselect_no_mat.result index 8a5443c70de..bf7a9504279 100644 --- a/mysql-test/r/subselect_no_mat.result +++ b/mysql-test/r/subselect_no_mat.result @@ -206,6 +206,8 @@ select (select t3.a from t3 where a<8 order by 1 desc limit 1), a from (select * from t2 where a>1) as tt; (select t3.a from t3 where a<8 order by 1 desc limit 1) a 7 2 +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; explain extended select (select t3.a from t3 where a<8 order by 1 desc limit 1), a from (select * from t2 where a>1) as tt; id select_type table type possible_keys key key_len ref rows filtered Extra @@ -214,6 +216,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 2 SUBQUERY t3 ALL NULL NULL NULL NULL 3 100.00 Using where; Using filesort Warnings: Note 1003 select (select `test`.`t3`.`a` from `test`.`t3` where (`test`.`t3`.`a` < 8) order by 1 desc limit 1) AS `(select t3.a from t3 where a<8 order by 1 desc limit 1)`,`tt`.`a` AS `a` from (select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t2` where (`test`.`t2`.`a` > 1)) `tt` +set optimizer_switch=@tmp_optimizer_switch; select * from t1 where t1.a=(select t2.a from t2 where t2.b=(select max(a) from t3) order by 1 desc limit 1); a 2 @@ -5535,10 +5538,13 @@ DROP TABLE parent, child; CREATE TABLE t1 (a INT, b INT, INDEX (a)); INSERT INTO t1 VALUES (3, 10), (2, 20), (7, 10), (5, 20); +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; 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 ALL NULL NULL NULL NULL 2 2 DERIVED t1 ref a a 5 const 1 +set optimizer_switch=@tmp_optimizer_switch; 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 diff --git a/mysql-test/r/subselect_no_opts.result b/mysql-test/r/subselect_no_opts.result index d62ba3f022d..514efeefe3a 100644 --- a/mysql-test/r/subselect_no_opts.result +++ b/mysql-test/r/subselect_no_opts.result @@ -202,6 +202,8 @@ select (select t3.a from t3 where a<8 order by 1 desc limit 1), a from (select * from t2 where a>1) as tt; (select t3.a from t3 where a<8 order by 1 desc limit 1) a 7 2 +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; explain extended select (select t3.a from t3 where a<8 order by 1 desc limit 1), a from (select * from t2 where a>1) as tt; id select_type table type possible_keys key key_len ref rows filtered Extra @@ -210,6 +212,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 2 SUBQUERY t3 ALL NULL NULL NULL NULL 3 100.00 Using where; Using filesort Warnings: Note 1003 select (select `test`.`t3`.`a` from `test`.`t3` where (`test`.`t3`.`a` < 8) order by 1 desc limit 1) AS `(select t3.a from t3 where a<8 order by 1 desc limit 1)`,`tt`.`a` AS `a` from (select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t2` where (`test`.`t2`.`a` > 1)) `tt` +set optimizer_switch=@tmp_optimizer_switch; select * from t1 where t1.a=(select t2.a from t2 where t2.b=(select max(a) from t3) order by 1 desc limit 1); a 2 @@ -5531,10 +5534,13 @@ DROP TABLE parent, child; CREATE TABLE t1 (a INT, b INT, INDEX (a)); INSERT INTO t1 VALUES (3, 10), (2, 20), (7, 10), (5, 20); +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; 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 ALL NULL NULL NULL NULL 2 2 DERIVED t1 ref a a 5 const 1 +set optimizer_switch=@tmp_optimizer_switch; 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 diff --git a/mysql-test/r/subselect_no_scache.result b/mysql-test/r/subselect_no_scache.result index b1c62cfc7dd..5cf75c54a7f 100644 --- a/mysql-test/r/subselect_no_scache.result +++ b/mysql-test/r/subselect_no_scache.result @@ -205,6 +205,8 @@ select (select t3.a from t3 where a<8 order by 1 desc limit 1), a from (select * from t2 where a>1) as tt; (select t3.a from t3 where a<8 order by 1 desc limit 1) a 7 2 +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; explain extended select (select t3.a from t3 where a<8 order by 1 desc limit 1), a from (select * from t2 where a>1) as tt; id select_type table type possible_keys key key_len ref rows filtered Extra @@ -213,6 +215,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 2 SUBQUERY t3 ALL NULL NULL NULL NULL 3 100.00 Using where; Using filesort Warnings: Note 1003 select (select `test`.`t3`.`a` from `test`.`t3` where (`test`.`t3`.`a` < 8) order by 1 desc limit 1) AS `(select t3.a from t3 where a<8 order by 1 desc limit 1)`,`tt`.`a` AS `a` from (select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t2` where (`test`.`t2`.`a` > 1)) `tt` +set optimizer_switch=@tmp_optimizer_switch; select * from t1 where t1.a=(select t2.a from t2 where t2.b=(select max(a) from t3) order by 1 desc limit 1); a 2 @@ -5540,10 +5543,13 @@ DROP TABLE parent, child; CREATE TABLE t1 (a INT, b INT, INDEX (a)); INSERT INTO t1 VALUES (3, 10), (2, 20), (7, 10), (5, 20); +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; 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 ALL NULL NULL NULL NULL 2 2 DERIVED t1 ref a a 5 const 1 +set optimizer_switch=@tmp_optimizer_switch; 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 diff --git a/mysql-test/r/subselect_no_semijoin.result b/mysql-test/r/subselect_no_semijoin.result index 7f9cb7f7c3d..eafddafb368 100644 --- a/mysql-test/r/subselect_no_semijoin.result +++ b/mysql-test/r/subselect_no_semijoin.result @@ -202,6 +202,8 @@ select (select t3.a from t3 where a<8 order by 1 desc limit 1), a from (select * from t2 where a>1) as tt; (select t3.a from t3 where a<8 order by 1 desc limit 1) a 7 2 +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; explain extended select (select t3.a from t3 where a<8 order by 1 desc limit 1), a from (select * from t2 where a>1) as tt; id select_type table type possible_keys key key_len ref rows filtered Extra @@ -210,6 +212,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 2 SUBQUERY t3 ALL NULL NULL NULL NULL 3 100.00 Using where; Using filesort Warnings: Note 1003 select (select `test`.`t3`.`a` from `test`.`t3` where (`test`.`t3`.`a` < 8) order by 1 desc limit 1) AS `(select t3.a from t3 where a<8 order by 1 desc limit 1)`,`tt`.`a` AS `a` from (select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t2` where (`test`.`t2`.`a` > 1)) `tt` +set optimizer_switch=@tmp_optimizer_switch; select * from t1 where t1.a=(select t2.a from t2 where t2.b=(select max(a) from t3) order by 1 desc limit 1); a 2 @@ -5531,10 +5534,13 @@ DROP TABLE parent, child; CREATE TABLE t1 (a INT, b INT, INDEX (a)); INSERT INTO t1 VALUES (3, 10), (2, 20), (7, 10), (5, 20); +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; 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 ALL NULL NULL NULL NULL 2 2 DERIVED t1 ref a a 5 const 1 +set optimizer_switch=@tmp_optimizer_switch; 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 diff --git a/mysql-test/r/subselect_partial_match.result b/mysql-test/r/subselect_partial_match.result index d23f9885f44..a01d6375064 100644 --- a/mysql-test/r/subselect_partial_match.result +++ b/mysql-test/r/subselect_partial_match.result @@ -766,6 +766,8 @@ CREATE TABLE t2 (b1 int DEFAULT NULL, b2 int DEFAULT NULL); INSERT INTO t2 VALUES (6,NULL); INSERT INTO t2 VALUES (NULL,0); set @@optimizer_switch='materialization=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on'; +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; EXPLAIN EXTENDED SELECT * FROM (SELECT * FROM t1 WHERE a1 NOT IN (SELECT b2 FROM t2)) table1; id select_type table type possible_keys key key_len ref rows filtered Extra @@ -774,6 +776,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 3 SUBQUERY t2 ALL NULL NULL NULL NULL 2 100.00 Warnings: Note 1003 select `table1`.`a1` AS `a1`,`table1`.`a2` AS `a2` from (select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where (not((`test`.`t1`.`a1`,`test`.`t1`.`a1` in ( (select `test`.`t2`.`b2` from `test`.`t2` ), (`test`.`t1`.`a1` in on distinct_key where ((`test`.`t1`.`a1` = ``.`b2`)))))))) `table1` +set optimizer_switch=@tmp_optimizer_switch; DROP TABLE t1, t2; # # LP BUG#613009 Crash in Ordered_key::get_field_idx diff --git a/mysql-test/r/subselect_sj.result b/mysql-test/r/subselect_sj.result index d5ab105207f..a9b4b4cb0cf 100644 --- a/mysql-test/r/subselect_sj.result +++ b/mysql-test/r/subselect_sj.result @@ -1862,6 +1862,8 @@ INSERT INTO t2 VALUES (1,2,4,'22:34:09','v','v'), (16,8,1,'02:57:29',NULL,NULL),(17,3,1,'16:46:13','r','r'), (18,3,9,'19:39:02','v','v'),(19,9,1,NULL,NULL,NULL), (20,6,5,'20:58:33','r','r'); +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; explain SELECT alias1.a, alias1.b, alias1.c, alias1.d, alias1.e, alias1.f, @@ -1897,6 +1899,7 @@ WHERE alias1.c IN (SELECT SQ3_alias1.b FROM t2 AS SQ3_alias1 STRAIGHT_JOIN t2 AS SQ3_alias2) LIMIT 100; +set optimizer_switch=@tmp_optimizer_switch; drop table t1,t2, t3; set optimizer_switch=@tmp_830993; set join_buffer_size= @tmp_830993_jbs; diff --git a/mysql-test/r/subselect_sj_jcl6.result b/mysql-test/r/subselect_sj_jcl6.result index 871f58199e7..68a130b04bf 100644 --- a/mysql-test/r/subselect_sj_jcl6.result +++ b/mysql-test/r/subselect_sj_jcl6.result @@ -1873,6 +1873,8 @@ INSERT INTO t2 VALUES (1,2,4,'22:34:09','v','v'), (16,8,1,'02:57:29',NULL,NULL),(17,3,1,'16:46:13','r','r'), (18,3,9,'19:39:02','v','v'),(19,9,1,NULL,NULL,NULL), (20,6,5,'20:58:33','r','r'); +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; explain SELECT alias1.a, alias1.b, alias1.c, alias1.d, alias1.e, alias1.f, @@ -1908,6 +1910,7 @@ WHERE alias1.c IN (SELECT SQ3_alias1.b FROM t2 AS SQ3_alias1 STRAIGHT_JOIN t2 AS SQ3_alias2) LIMIT 100; +set optimizer_switch=@tmp_optimizer_switch; drop table t1,t2, t3; set optimizer_switch=@tmp_830993; set join_buffer_size= @tmp_830993_jbs; diff --git a/mysql-test/r/subselect_sj_mat.result b/mysql-test/r/subselect_sj_mat.result index ec2ee967b22..472cadf04c4 100644 --- a/mysql-test/r/subselect_sj_mat.result +++ b/mysql-test/r/subselect_sj_mat.result @@ -1372,6 +1372,8 @@ DROP TABLE t1,t2,t3; CREATE TABLE t1 (a INTEGER); CREATE TABLE t2 (b INTEGER); INSERT INTO t2 VALUES (1); +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; explain SELECT a FROM ( SELECT t1.* FROM t1 LEFT JOIN t2 ON t1.a > 3 OR t2.b IN (SELECT a FROM t1) ) table1; @@ -1383,6 +1385,7 @@ SELECT a FROM ( SELECT t1.* FROM t1 LEFT JOIN t2 ON t1.a > 3 OR t2.b IN (SELECT a FROM t1) ) table1; a +set optimizer_switch=@tmp_optimizer_switch; DROP TABLE t1, t2; # End BUG#56367 # diff --git a/mysql-test/suite/innodb/r/innodb_lock_wait_timeout_1.result b/mysql-test/suite/innodb/r/innodb_lock_wait_timeout_1.result index e8ba522af2e..30e58aacff5 100644 --- a/mysql-test/suite/innodb/r/innodb_lock_wait_timeout_1.result +++ b/mysql-test/suite/innodb/r/innodb_lock_wait_timeout_1.result @@ -97,6 +97,8 @@ insert into t1 values (1,1), (2,null), (3,1), (4,1), # Demonstrate that for the SELECT statement # used later in the test JT_EQ_REF access method is used. # +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; explain select 1 from t1 natural join (select 2 as a, 1 as b union all select 2 as a, 2 as b) as t2 for update; @@ -150,6 +152,7 @@ key_len NULL ref NULL rows NULL Extra +set optimizer_switch=@tmp_optimizer_switch; # # Demonstrate that the reported SELECT statement # no longer produces warnings. @@ -301,6 +304,8 @@ begin; # is retreived and processed first. # # Verify that JT_EQ_REF is used. +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; explain select 1 from t1 natural join (select 3 as a, 2 as b union all select 3 as a, 1 as b) as t2 for update; @@ -354,6 +359,7 @@ key_len NULL ref NULL rows NULL Extra +set optimizer_switch=@tmp_optimizer_switch; # Lock the record. select 1 from t1 natural join (select 3 as a, 2 as b union all select 3 as a, 1 as b) as t2 for update; diff --git a/mysql-test/suite/innodb/t/innodb_lock_wait_timeout_1.test b/mysql-test/suite/innodb/t/innodb_lock_wait_timeout_1.test index fcbf2b1cfc7..2707b97bfa2 100644 --- a/mysql-test/suite/innodb/t/innodb_lock_wait_timeout_1.test +++ b/mysql-test/suite/innodb/t/innodb_lock_wait_timeout_1.test @@ -140,9 +140,12 @@ insert into t1 values (1,1), (2,null), (3,1), (4,1), --echo # used later in the test JT_EQ_REF access method is used. --echo # --vertical_results +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; explain select 1 from t1 natural join (select 2 as a, 1 as b union all select 2 as a, 2 as b) as t2 for update; +set optimizer_switch=@tmp_optimizer_switch; --horizontal_results --echo # --echo # Demonstrate that the reported SELECT statement @@ -236,9 +239,12 @@ begin; --echo # --echo # Verify that JT_EQ_REF is used. --vertical_results +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; explain select 1 from t1 natural join (select 3 as a, 2 as b union all select 3 as a, 1 as b) as t2 for update; +set optimizer_switch=@tmp_optimizer_switch; --horizontal_results --echo # Lock the record. select 1 from t1 natural join (select 3 as a, 2 as b union all diff --git a/mysql-test/suite/innodb_plugin/r/innodb_lock_wait_timeout_1.result b/mysql-test/suite/innodb_plugin/r/innodb_lock_wait_timeout_1.result index c1e54465066..5d8c24ed11f 100644 --- a/mysql-test/suite/innodb_plugin/r/innodb_lock_wait_timeout_1.result +++ b/mysql-test/suite/innodb_plugin/r/innodb_lock_wait_timeout_1.result @@ -99,6 +99,7 @@ insert into t1 values (1,1), (2,null), (3,1), (4,1), # set @tmp_optimizer_switch=@@optimizer_switch; set optimizer_switch='index_condition_pushdown=off'; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; explain select 1 from t1 natural join (select 2 as a, 1 as b union all select 2 as a, 2 as b) as t2 for update; @@ -306,6 +307,7 @@ begin; # Verify that JT_EQ_REF is used. set @tmp_optimizer_switch=@@optimizer_switch; set optimizer_switch='index_condition_pushdown=off'; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; explain select 1 from t1 natural join (select 3 as a, 2 as b union all select 3 as a, 1 as b) as t2 for update; diff --git a/mysql-test/suite/innodb_plugin/t/innodb_lock_wait_timeout_1.test b/mysql-test/suite/innodb_plugin/t/innodb_lock_wait_timeout_1.test index c458b0ba44d..f8aef2af86d 100644 --- a/mysql-test/suite/innodb_plugin/t/innodb_lock_wait_timeout_1.test +++ b/mysql-test/suite/innodb_plugin/t/innodb_lock_wait_timeout_1.test @@ -142,6 +142,7 @@ insert into t1 values (1,1), (2,null), (3,1), (4,1), --vertical_results set @tmp_optimizer_switch=@@optimizer_switch; set optimizer_switch='index_condition_pushdown=off'; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; explain select 1 from t1 natural join (select 2 as a, 1 as b union all select 2 as a, 2 as b) as t2 for update; @@ -241,6 +242,7 @@ begin; --vertical_results set @tmp_optimizer_switch=@@optimizer_switch; set optimizer_switch='index_condition_pushdown=off'; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; explain select 1 from t1 natural join (select 3 as a, 2 as b union all select 3 as a, 1 as b) as t2 for update; diff --git a/mysql-test/suite/pbxt/r/derived.result b/mysql-test/suite/pbxt/r/derived.result index 4fc9216f126..1e4126315fb 100644 --- a/mysql-test/suite/pbxt/r/derived.result +++ b/mysql-test/suite/pbxt/r/derived.result @@ -1,4 +1,6 @@ drop table if exists t1,t2,t3; +set @save_derived_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; select * from (select 2 from DUAL) b; 2 2 @@ -208,6 +210,7 @@ create table t1 select 1 as a; analyze table t1; Table Op Msg_type Msg_text test.t1 analyze status OK +set optimizer_switch='derived_merge=off,derived_with_keys=off'; select 2 as a from (select * from t1) b; ERROR 3D000: No database selected use test; @@ -389,3 +392,4 @@ select t2.* from (select * from t1) as A inner join t2 on A.ID = t2.FID; ID DATA FID drop table t1, t2; drop user mysqltest_1; +set optimizer_switch=@save_derived_optimizer_switch; diff --git a/mysql-test/suite/pbxt/r/subselect.result b/mysql-test/suite/pbxt/r/subselect.result index 6b1ed9ea052..0b5bfc579cf 100644 --- a/mysql-test/suite/pbxt/r/subselect.result +++ b/mysql-test/suite/pbxt/r/subselect.result @@ -196,6 +196,8 @@ select (select t3.a from t3 where a<8 order by 1 desc limit 1), a from (select * from t2 where a>1) as tt; (select t3.a from t3 where a<8 order by 1 desc limit 1) a 7 2 +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; explain extended select (select t3.a from t3 where a<8 order by 1 desc limit 1), a from (select * from t2 where a>1) as tt; id select_type table type possible_keys key key_len ref rows filtered Extra @@ -204,6 +206,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 2 SUBQUERY t3 ALL NULL NULL NULL NULL 3 100.00 Using where; Using filesort Warnings: Note 1003 select (select `test`.`t3`.`a` from `test`.`t3` where (`test`.`t3`.`a` < 8) order by 1 desc limit 1) AS `(select t3.a from t3 where a<8 order by 1 desc limit 1)`,`tt`.`a` AS `a` from (select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t2` where (`test`.`t2`.`a` > 1)) `tt` +set optimizer_switch=@tmp_optimizer_switch; select * from t1 where t1.a=(select t2.a from t2 where t2.b=(select max(a) from t3) order by 1 desc limit 1); a 2 diff --git a/mysql-test/suite/pbxt/t/derived.test b/mysql-test/suite/pbxt/t/derived.test index a9127b49741..49effe4f14b 100644 --- a/mysql-test/suite/pbxt/t/derived.test +++ b/mysql-test/suite/pbxt/t/derived.test @@ -3,6 +3,9 @@ drop table if exists t1,t2,t3; --enable_warnings +set @save_derived_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; + select * from (select 2 from DUAL) b; -- error 1054 SELECT 1 as a FROM (SELECT 1 UNION SELECT a) b; @@ -107,6 +110,7 @@ create table t1 select 1 as a; analyze table t1; # PBXT: Required to get a consitent result connect (con1,localhost,mysqltest_1,,*NO-ONE*,$MASTER_MYPORT,$MASTER_MYSOCK); connection con1; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; --error 1046 select 2 as a from (select * from t1) b; use test; @@ -283,3 +287,5 @@ drop user mysqltest_1; drop database pbxt; --enable_query_log # End of 4.1 tests + +set optimizer_switch=@save_derived_optimizer_switch; diff --git a/mysql-test/suite/pbxt/t/subselect.test b/mysql-test/suite/pbxt/t/subselect.test index 5e9c6eee6a6..fa838363403 100644 --- a/mysql-test/suite/pbxt/t/subselect.test +++ b/mysql-test/suite/pbxt/t/subselect.test @@ -80,8 +80,11 @@ explain extended (select * from t2 where t2.b=(select a from t3 order by 1 desc select (select a from t3 where a1) as tt; +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; explain extended select (select t3.a from t3 where a<8 order by 1 desc limit 1), a from (select * from t2 where a>1) as tt; +set optimizer_switch=@tmp_optimizer_switch; select * from t1 where t1.a=(select t2.a from t2 where t2.b=(select max(a) from t3) order by 1 desc limit 1); select * from t1 where t1.a=(select t2.a from t2 where t2.b=(select max(a) from t3 where t3.a > t1.a) order by 1 desc limit 1); select * from t1 where t1.a=(select t2.a from t2 where t2.b=(select max(a) from t3 where t3.a < t1.a) order by 1 desc limit 1); diff --git a/mysql-test/suite/vcol/inc/vcol_select.inc b/mysql-test/suite/vcol/inc/vcol_select.inc index 28c3416a55a..0641e14564a 100644 --- a/mysql-test/suite/vcol/inc/vcol_select.inc +++ b/mysql-test/suite/vcol/inc/vcol_select.inc @@ -84,10 +84,16 @@ eval $s; eval explain $s; --echo # select_type=DERIVED, type=system + +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; + let $s = select * from (select a,b,c from t1) as t11; eval $s; eval explain $s; +set optimizer_switch=@tmp_optimizer_switch; + --echo ### --echo ### Using aggregate functions with/without DISTINCT --echo ### diff --git a/mysql-test/suite/vcol/r/vcol_select_innodb.result b/mysql-test/suite/vcol/r/vcol_select_innodb.result index a0ccc166199..a41c13a2a4c 100644 --- a/mysql-test/suite/vcol/r/vcol_select_innodb.result +++ b/mysql-test/suite/vcol/r/vcol_select_innodb.result @@ -89,6 +89,8 @@ id select_type table type possible_keys key key_len ref rows Extra 2 UNION t2 ALL NULL NULL NULL NULL 1 NULL UNION RESULT ALL NULL NULL NULL NULL NULL # select_type=DERIVED, type=system +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; select * from (select a,b,c from t1) as t11; a b c 2 -2 -2 @@ -100,6 +102,7 @@ explain select * from (select a,b,c from t1) as t11; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL NULL NULL NULL NULL 5 2 DERIVED t1 ALL NULL NULL NULL NULL 5 +set optimizer_switch=@tmp_optimizer_switch; ### ### Using aggregate functions with/without DISTINCT ### diff --git a/mysql-test/suite/vcol/r/vcol_select_myisam.result b/mysql-test/suite/vcol/r/vcol_select_myisam.result index 7e716b8b897..3ad15009c76 100644 --- a/mysql-test/suite/vcol/r/vcol_select_myisam.result +++ b/mysql-test/suite/vcol/r/vcol_select_myisam.result @@ -89,6 +89,8 @@ id select_type table type possible_keys key key_len ref rows Extra 2 UNION t2 system NULL NULL NULL NULL 1 NULL UNION RESULT ALL NULL NULL NULL NULL NULL # select_type=DERIVED, type=system +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; select * from (select a,b,c from t1) as t11; a b c 2 -2 -2 @@ -100,6 +102,7 @@ explain select * from (select a,b,c from t1) as t11; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL NULL NULL NULL NULL 5 2 DERIVED t1 ALL NULL NULL NULL NULL 5 +set optimizer_switch=@tmp_optimizer_switch; ### ### Using aggregate functions with/without DISTINCT ### diff --git a/mysql-test/t/derived.test b/mysql-test/t/derived.test index 962cec95add..7defc55b473 100644 --- a/mysql-test/t/derived.test +++ b/mysql-test/t/derived.test @@ -3,6 +3,9 @@ drop table if exists t1,t2,t3; --enable_warnings +set @save_derived_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; + select * from (select 2 from DUAL) b; -- error 1054 SELECT 1 as a FROM (SELECT 1 UNION SELECT a) b; @@ -106,6 +109,7 @@ create user mysqltest_1; create table t1 select 1 as a; connect (con1,localhost,mysqltest_1,,*NO-ONE*,$MASTER_MYPORT,$MASTER_MYSOCK); connection con1; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; --error 1046 select 2 as a from (select * from t1) b; use test; @@ -315,3 +319,5 @@ WHERE j = SUBSTRING('12', (SELECT * FROM (SELECT MIN(j) FROM t1) t2))) t3; DROP TABLE t1; --echo # End of 5.0 tests + +set optimizer_switch=@save_derived_optimizer_switch; diff --git a/mysql-test/t/explain.test b/mysql-test/t/explain.test index 186a00af16a..94548fd5fde 100644 --- a/mysql-test/t/explain.test +++ b/mysql-test/t/explain.test @@ -279,8 +279,11 @@ CREATE TABLE t1 (a int) ; CREATE TABLE t2 (a int) ; INSERT INTO t2 VALUES (8); +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; EXPLAIN EXTENDED SELECT * FROM ( SELECT t1.a FROM t1,t2 WHERE t2.a = t1.a ) AS t; +set optimizer_switch=@tmp_optimizer_switch; DROP TABLE t1,t2; diff --git a/mysql-test/t/func_group.test b/mysql-test/t/func_group.test index 874b26f7549..65b5b3936cc 100644 --- a/mysql-test/t/func_group.test +++ b/mysql-test/t/func_group.test @@ -1250,12 +1250,15 @@ SELECT v FROM t2); --echo +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; EXPLAIN SELECT MIN(a) FROM (SELECT a FROM empty1) tt HAVING ('m') IN ( SELECT v FROM t2); +set optimizer_switch=@tmp_optimizer_switch; --echo --echo # diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index 92c4bae5327..4302bf5e7eb 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -1314,9 +1314,13 @@ DROP TABLE t1, t2; drop table if exists t1; --enable_warnings create table t1(f1 tinyint default null)engine=myisam; -insert into t1 values (-1),(null); +insert into t1 values (-1),(null); + +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; explain select 1 as a from t1,(select decode(f1,f1) as b from t1) a; explain select 1 as a from t1,(select encode(f1,f1) as b from t1) a; +set optimizer_switch=@tmp_optimizer_switch; drop table t1; --echo # diff --git a/mysql-test/t/index_merge_innodb.test b/mysql-test/t/index_merge_innodb.test index fa05c96a6f9..ae568c5b5d9 100644 --- a/mysql-test/t/index_merge_innodb.test +++ b/mysql-test/t/index_merge_innodb.test @@ -68,6 +68,8 @@ INSERT INTO t1(a,b) SELECT a,b FROM t1; INSERT INTO t1 VALUES (1000000, 0, 0); SET SESSION sort_buffer_size = 1024*36; +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; # We have to use FORCE INDEX here as Innodb gives inconsistent estimates # which causes different query plans. @@ -89,6 +91,7 @@ SELECT COUNT(*) FROM WHERE a BETWEEN 2 AND 7 OR pk=1000000) AS t; DROP TABLE t1; +set optimizer_switch=@tmp_optimizer_switch; --echo # --echo # Testcase Backport: BUG#48093: 6.0 Server not processing equivalent IN clauses properly diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test index e78b180caf7..e1962255cf6 100644 --- a/mysql-test/t/information_schema.test +++ b/mysql-test/t/information_schema.test @@ -962,6 +962,8 @@ DROP FUNCTION get_value; # # Bug#22413 EXPLAIN SELECT FROM view with ORDER BY yield server crash # +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; create view v1 as select table_schema as object_schema, table_name as object_name, @@ -970,6 +972,7 @@ from information_schema.tables order by object_schema; explain select * from v1; explain select * from (select table_name from information_schema.tables) as a; +set optimizer_switch=@tmp_optimizer_switch; drop view v1; # diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test index f4e27f3ba42..357e7d4fe8f 100644 --- a/mysql-test/t/ps.test +++ b/mysql-test/t/ps.test @@ -166,12 +166,18 @@ create table t2 like t1; set @save_optimizer_switch=@@optimizer_switch; set @@optimizer_switch="partial_match_rowid_merge=off,partial_match_table_scan=off"; +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; + set @stmt= ' explain SELECT (SELECT SUM(c1 + c12 + 0.0) FROM t2 where (t1.c2 - 0e-3) = t2.c2 GROUP BY t1.c15 LIMIT 1) as scalar_s, exists (select 1.0e+0 from t2 where t2.c3 * 9.0000000000 = t1.c4) as exists_s, c5 * 4 in (select c6 + 0.3e+1 from t2) as in_s, (c7 - 4, c8 - 4) in (select c9 + 4.0, c10 + 40e-1 from t2) as in_row_s FROM t1, (select c25 x, c32 y from t2) tt WHERE x * 1 = c25 ' ; prepare stmt1 from @stmt ; execute stmt1 ; execute stmt1 ; explain SELECT (SELECT SUM(c1 + c12 + 0.0) FROM t2 where (t1.c2 - 0e-3) = t2.c2 GROUP BY t1.c15 LIMIT 1) as scalar_s, exists (select 1.0e+0 from t2 where t2.c3 * 9.0000000000 = t1.c4) as exists_s, c5 * 4 in (select c6 + 0.3e+1 from t2) as in_s, (c7 - 4, c8 - 4) in (select c9 + 4.0, c10 + 40e-1 from t2) as in_row_s FROM t1, (select c25 x, c32 y from t2) tt WHERE x * 1 = c25; deallocate prepare stmt1; + +set optimizer_switch=@tmp_optimizer_switch; + drop tables t1,t2; set @@optimizer_switch=@save_optimizer_switch; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index a39b7ea49b8..abce58348da 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -94,8 +94,11 @@ explain extended (select * from t2 where t2.b=(select a from t3 order by 1 desc select (select a from t3 where a1) as tt; +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; explain extended select (select t3.a from t3 where a<8 order by 1 desc limit 1), a from (select * from t2 where a>1) as tt; +set optimizer_switch=@tmp_optimizer_switch; select * from t1 where t1.a=(select t2.a from t2 where t2.b=(select max(a) from t3) order by 1 desc limit 1); select * from t1 where t1.a=(select t2.a from t2 where t2.b=(select max(a) from t3 where t3.a > t1.a) order by 1 desc limit 1); select * from t1 where t1.a=(select t2.a from t2 where t2.b=(select max(a) from t3 where t3.a < t1.a) order by 1 desc limit 1); @@ -4648,7 +4651,10 @@ CREATE TABLE t1 (a INT, b INT, INDEX (a)); INSERT INTO t1 VALUES (3, 10), (2, 20), (7, 10), (5, 20); --echo +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; EXPLAIN SELECT * FROM (SELECT * FROM t1 WHERE a=7) t; +set optimizer_switch=@tmp_optimizer_switch; --echo EXPLAIN SELECT * FROM t1 WHERE EXISTS (SELECT * FROM t1 WHERE a=7); diff --git a/mysql-test/t/subselect3.test b/mysql-test/t/subselect3.test index 7e4943d85ba..aadc08e18e0 100644 --- a/mysql-test/t/subselect3.test +++ b/mysql-test/t/subselect3.test @@ -925,8 +925,11 @@ set @@optimizer_switch='materialization=off'; # # FirstMatch referring to a derived table # +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; explain select * from (select a from t0) X where a in (select a from t1); drop table t0, t1; +set optimizer_switch=@tmp_optimizer_switch; # # LooseScan: Check if we can pick it together with range access diff --git a/mysql-test/t/subselect_mat_cost_bugs.test b/mysql-test/t/subselect_mat_cost_bugs.test index 4ce19012e0c..463685bbdf0 100644 --- a/mysql-test/t/subselect_mat_cost_bugs.test +++ b/mysql-test/t/subselect_mat_cost_bugs.test @@ -183,6 +183,9 @@ CREATE TABLE t2 ( f2 int(11)) ; CREATE TABLE t1 ( f3 int(11), KEY (f3)) ; INSERT INTO t1 VALUES (6),(4); +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; + EXPLAIN SELECT * FROM (SELECT * FROM t2) AS a2 WHERE (SELECT distinct SUM(distinct f3 ) FROM t1); @@ -192,6 +195,7 @@ EXPLAIN SELECT * FROM (SELECT * FROM t2) AS a2 WHERE (SELECT distinct SUM(distinct f3 ) FROM t1); +set optimizer_switch=@tmp_optimizer_switch; drop table t1,t2; --echo # @@ -204,6 +208,9 @@ INSERT INTO t1 VALUES (28),(29); CREATE TABLE t2 ( f2 int(11), f3 int(11), f10 varchar(1)) ; INSERT INTO t2 VALUES (NULL,6,'f'),(4,2,'d'); +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; + EXPLAIN SELECT alias2.f2 AS field1 FROM t1 AS alias1 JOIN ( SELECT * FROM t2 ) AS alias2 ON alias2.f3 = alias1.f1 @@ -223,6 +230,7 @@ WHERE ( ) ORDER BY field1 ; +set optimizer_switch=@tmp_optimizer_switch; drop table t1,t2; --echo # diff --git a/mysql-test/t/subselect_partial_match.test b/mysql-test/t/subselect_partial_match.test index 45386efd266..fd1e6de716c 100644 --- a/mysql-test/t/subselect_partial_match.test +++ b/mysql-test/t/subselect_partial_match.test @@ -622,8 +622,11 @@ INSERT INTO t2 VALUES (NULL,0); set @@optimizer_switch='materialization=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on'; +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; EXPLAIN EXTENDED SELECT * FROM (SELECT * FROM t1 WHERE a1 NOT IN (SELECT b2 FROM t2)) table1; +set optimizer_switch=@tmp_optimizer_switch; DROP TABLE t1, t2; diff --git a/mysql-test/t/subselect_sj.test b/mysql-test/t/subselect_sj.test index 5ae968742aa..a2f46c76fce 100644 --- a/mysql-test/t/subselect_sj.test +++ b/mysql-test/t/subselect_sj.test @@ -1690,6 +1690,9 @@ INSERT INTO t2 VALUES (1,2,4,'22:34:09','v','v'), (18,3,9,'19:39:02','v','v'),(19,9,1,NULL,NULL,NULL), (20,6,5,'20:58:33','r','r'); +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; + explain SELECT alias1.a, alias1.b, alias1.c, alias1.d, alias1.e, alias1.f, @@ -1720,6 +1723,8 @@ WHERE FROM t2 AS SQ3_alias1 STRAIGHT_JOIN t2 AS SQ3_alias2) LIMIT 100; +set optimizer_switch=@tmp_optimizer_switch; + drop table t1,t2, t3; set optimizer_switch=@tmp_830993; set join_buffer_size= @tmp_830993_jbs; diff --git a/mysql-test/t/subselect_sj_mat.test b/mysql-test/t/subselect_sj_mat.test index a72128bf5ed..4ddc19f49f5 100644 --- a/mysql-test/t/subselect_sj_mat.test +++ b/mysql-test/t/subselect_sj_mat.test @@ -1022,12 +1022,15 @@ CREATE TABLE t1 (a INTEGER); CREATE TABLE t2 (b INTEGER); INSERT INTO t2 VALUES (1); +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='derived_merge=off,derived_with_keys=off'; let $query = SELECT a FROM ( SELECT t1.* FROM t1 LEFT JOIN t2 ON t1.a > 3 OR t2.b IN (SELECT a FROM t1) ) table1; eval explain $query; eval $query; +set optimizer_switch=@tmp_optimizer_switch; DROP TABLE t1, t2; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 298f31d8494..dd630aa9bc3 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -598,6 +598,8 @@ protected: OPTIMIZER_SWITCH_INDEX_MERGE_SORT_UNION | \ OPTIMIZER_SWITCH_INDEX_MERGE_INTERSECT | \ OPTIMIZER_SWITCH_INDEX_COND_PUSHDOWN | \ + OPTIMIZER_SWITCH_DERIVED_MERGE | \ + OPTIMIZER_SWITCH_DERIVED_WITH_KEYS | \ OPTIMIZER_SWITCH_TABLE_ELIMINATION | \ OPTIMIZER_SWITCH_IN_TO_EXISTS | \ OPTIMIZER_SWITCH_MATERIALIZATION | \ diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 64781adf3e2..cb98af04af1 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -482,8 +482,8 @@ static const char *optimizer_switch_str="index_merge=on,index_merge_union=on," "index_merge_intersection=on," "index_merge_sort_intersection=off," "index_condition_pushdown=on," - "derived_merge=off," - "derived_with_keys=off," + "derived_merge=on," + "derived_with_keys=on," "firstmatch=on," "loosescan=on," "materialization=on," From 5412e82c01aa126448af8c64279e2cb9a7ffdd38 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 28 Nov 2011 12:42:14 +0200 Subject: [PATCH 126/288] Fixed LP BUG#747278 The problem was that when we have single row subquery with no rows Item_cache(es) which represent result row was not null and being requested via element_index() returned random value. The fix is setting all Item_cache(es) in NULL before executing the query (reset() method) which guaranty NULL value of whole query or its elements requested in any way if no rows was found. set_null() method was added to Item_cache to guaranty correct NULL value in case of reseting the cache. --- mysql-test/r/subselect.result | 81 +++++++++++++++++++++++ mysql-test/r/subselect_no_mat.result | 81 +++++++++++++++++++++++ mysql-test/r/subselect_no_opts.result | 81 +++++++++++++++++++++++ mysql-test/r/subselect_no_scache.result | 81 +++++++++++++++++++++++ mysql-test/r/subselect_no_semijoin.result | 81 +++++++++++++++++++++++ mysql-test/t/subselect.test | 45 +++++++++++++ sql/item.cc | 28 ++++++++ sql/item.h | 2 + sql/item_subselect.cc | 10 ++- sql/sql_view.cc | 2 + 10 files changed, 491 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index c2acdf7f018..5e8432f2509 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -5734,4 +5734,85 @@ SELECT 't' b a b set @@join_cache_level= @save_join_cache_level; drop table t1,t2; +# +# LP BUG#747278 incorrect values of the NULL (no rows) single +# row subquery requested via element_index() interface +# +CREATE TABLE t1 (f1a int, f1b int) ; +INSERT IGNORE INTO t1 VALUES (1,1),(2,2); +CREATE TABLE t2 ( f2 int); +INSERT IGNORE INTO t2 VALUES (3),(4); +CREATE TABLE t3 (f3a int default 1, f3b int default 2); +INSERT INTO t3 VALUES (1,1),(2,2); +set @old_optimizer_switch = @@session.optimizer_switch; +set @@optimizer_switch='materialization=on,partial_match_rowid_merge=on,partial_match_table_scan=off,subquery_cache=off,semijoin=off'; +SELECT (SELECT f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a FROM t1) FROM t2; +(SELECT f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a FROM t1) +NULL +NULL +SELECT (SELECT f3a,f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a,f1a FROM t1) FROM t2; +(SELECT f3a,f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a,f1a FROM t1) +NULL +NULL +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) NOT IN (SELECT f1a, f1b FROM t1) FROM t2; +(SELECT f3a, f3b FROM t3 where f3a > 3) NOT IN (SELECT f1a, f1b FROM t1) +NULL +NULL +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) NOT IN (SELECT f1a, f1b FROM t1); +(SELECT f3a, f3b FROM t3 where f3a > 3) NOT IN (SELECT f1a, f1b FROM t1) +NULL +SELECT (SELECT f3a FROM t3 where f3a > 3) IN (SELECT f1a FROM t1) FROM t2; +(SELECT f3a FROM t3 where f3a > 3) IN (SELECT f1a FROM t1) +NULL +NULL +SELECT (SELECT f3a,f3a FROM t3 where f3a > 3) IN (SELECT f1a,f1a FROM t1) FROM t2; +(SELECT f3a,f3a FROM t3 where f3a > 3) IN (SELECT f1a,f1a FROM t1) +NULL +NULL +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) IN (SELECT f1a, f1b FROM t1) FROM t2; +(SELECT f3a, f3b FROM t3 where f3a > 3) IN (SELECT f1a, f1b FROM t1) +NULL +NULL +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) IN (SELECT f1a, f1b FROM t1); +(SELECT f3a, f3b FROM t3 where f3a > 3) IN (SELECT f1a, f1b FROM t1) +NULL +set @@session.optimizer_switch=@old_optimizer_switch; +SELECT (SELECT f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a FROM t1) FROM t2; +(SELECT f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a FROM t1) +NULL +NULL +SELECT (SELECT f3a,f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a,f1a FROM t1) FROM t2; +(SELECT f3a,f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a,f1a FROM t1) +NULL +NULL +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) NOT IN (SELECT f1a, f1b FROM t1) FROM t2; +(SELECT f3a, f3b FROM t3 where f3a > 3) NOT IN (SELECT f1a, f1b FROM t1) +NULL +NULL +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) NOT IN (SELECT f1a, f1b FROM t1); +(SELECT f3a, f3b FROM t3 where f3a > 3) NOT IN (SELECT f1a, f1b FROM t1) +NULL +SELECT (SELECT f3a FROM t3 where f3a > 3) IN (SELECT f1a FROM t1) FROM t2; +(SELECT f3a FROM t3 where f3a > 3) IN (SELECT f1a FROM t1) +NULL +NULL +SELECT (SELECT f3a,f3a FROM t3 where f3a > 3) IN (SELECT f1a,f1a FROM t1) FROM t2; +(SELECT f3a,f3a FROM t3 where f3a > 3) IN (SELECT f1a,f1a FROM t1) +NULL +NULL +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) IN (SELECT f1a, f1b FROM t1) FROM t2; +(SELECT f3a, f3b FROM t3 where f3a > 3) IN (SELECT f1a, f1b FROM t1) +NULL +NULL +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) IN (SELECT f1a, f1b FROM t1); +(SELECT f3a, f3b FROM t3 where f3a > 3) IN (SELECT f1a, f1b FROM t1) +NULL +select (null, null) = (null, null); +(null, null) = (null, null) +NULL +SELECT (SELECT f3a, f3a FROM t3 where f3a > 3) = (0, 0); +(SELECT f3a, f3a FROM t3 where f3a > 3) = (0, 0) +NULL +drop tables t1,t2,t3; +# 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 bf7a9504279..2b1f3ecdaf2 100644 --- a/mysql-test/r/subselect_no_mat.result +++ b/mysql-test/r/subselect_no_mat.result @@ -5733,6 +5733,87 @@ SELECT 't' b a b set @@join_cache_level= @save_join_cache_level; drop table t1,t2; +# +# LP BUG#747278 incorrect values of the NULL (no rows) single +# row subquery requested via element_index() interface +# +CREATE TABLE t1 (f1a int, f1b int) ; +INSERT IGNORE INTO t1 VALUES (1,1),(2,2); +CREATE TABLE t2 ( f2 int); +INSERT IGNORE INTO t2 VALUES (3),(4); +CREATE TABLE t3 (f3a int default 1, f3b int default 2); +INSERT INTO t3 VALUES (1,1),(2,2); +set @old_optimizer_switch = @@session.optimizer_switch; +set @@optimizer_switch='materialization=on,partial_match_rowid_merge=on,partial_match_table_scan=off,subquery_cache=off,semijoin=off'; +SELECT (SELECT f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a FROM t1) FROM t2; +(SELECT f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a FROM t1) +NULL +NULL +SELECT (SELECT f3a,f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a,f1a FROM t1) FROM t2; +(SELECT f3a,f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a,f1a FROM t1) +NULL +NULL +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) NOT IN (SELECT f1a, f1b FROM t1) FROM t2; +(SELECT f3a, f3b FROM t3 where f3a > 3) NOT IN (SELECT f1a, f1b FROM t1) +NULL +NULL +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) NOT IN (SELECT f1a, f1b FROM t1); +(SELECT f3a, f3b FROM t3 where f3a > 3) NOT IN (SELECT f1a, f1b FROM t1) +NULL +SELECT (SELECT f3a FROM t3 where f3a > 3) IN (SELECT f1a FROM t1) FROM t2; +(SELECT f3a FROM t3 where f3a > 3) IN (SELECT f1a FROM t1) +NULL +NULL +SELECT (SELECT f3a,f3a FROM t3 where f3a > 3) IN (SELECT f1a,f1a FROM t1) FROM t2; +(SELECT f3a,f3a FROM t3 where f3a > 3) IN (SELECT f1a,f1a FROM t1) +NULL +NULL +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) IN (SELECT f1a, f1b FROM t1) FROM t2; +(SELECT f3a, f3b FROM t3 where f3a > 3) IN (SELECT f1a, f1b FROM t1) +NULL +NULL +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) IN (SELECT f1a, f1b FROM t1); +(SELECT f3a, f3b FROM t3 where f3a > 3) IN (SELECT f1a, f1b FROM t1) +NULL +set @@session.optimizer_switch=@old_optimizer_switch; +SELECT (SELECT f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a FROM t1) FROM t2; +(SELECT f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a FROM t1) +NULL +NULL +SELECT (SELECT f3a,f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a,f1a FROM t1) FROM t2; +(SELECT f3a,f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a,f1a FROM t1) +NULL +NULL +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) NOT IN (SELECT f1a, f1b FROM t1) FROM t2; +(SELECT f3a, f3b FROM t3 where f3a > 3) NOT IN (SELECT f1a, f1b FROM t1) +NULL +NULL +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) NOT IN (SELECT f1a, f1b FROM t1); +(SELECT f3a, f3b FROM t3 where f3a > 3) NOT IN (SELECT f1a, f1b FROM t1) +NULL +SELECT (SELECT f3a FROM t3 where f3a > 3) IN (SELECT f1a FROM t1) FROM t2; +(SELECT f3a FROM t3 where f3a > 3) IN (SELECT f1a FROM t1) +NULL +NULL +SELECT (SELECT f3a,f3a FROM t3 where f3a > 3) IN (SELECT f1a,f1a FROM t1) FROM t2; +(SELECT f3a,f3a FROM t3 where f3a > 3) IN (SELECT f1a,f1a FROM t1) +NULL +NULL +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) IN (SELECT f1a, f1b FROM t1) FROM t2; +(SELECT f3a, f3b FROM t3 where f3a > 3) IN (SELECT f1a, f1b FROM t1) +NULL +NULL +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) IN (SELECT f1a, f1b FROM t1); +(SELECT f3a, f3b FROM t3 where f3a > 3) IN (SELECT f1a, f1b FROM t1) +NULL +select (null, null) = (null, null); +(null, null) = (null, null) +NULL +SELECT (SELECT f3a, f3a FROM t3 where f3a > 3) = (0, 0); +(SELECT f3a, f3a FROM t3 where f3a > 3) = (0, 0) +NULL +drop tables t1,t2,t3; +# return optimizer switch changed in the beginning of this test set optimizer_switch=@subselect_tmp; set optimizer_switch=default; select @@optimizer_switch like '%materialization=on%'; diff --git a/mysql-test/r/subselect_no_opts.result b/mysql-test/r/subselect_no_opts.result index 514efeefe3a..8675a7a7e89 100644 --- a/mysql-test/r/subselect_no_opts.result +++ b/mysql-test/r/subselect_no_opts.result @@ -5729,5 +5729,86 @@ SELECT 't' b a b set @@join_cache_level= @save_join_cache_level; drop table t1,t2; +# +# LP BUG#747278 incorrect values of the NULL (no rows) single +# row subquery requested via element_index() interface +# +CREATE TABLE t1 (f1a int, f1b int) ; +INSERT IGNORE INTO t1 VALUES (1,1),(2,2); +CREATE TABLE t2 ( f2 int); +INSERT IGNORE INTO t2 VALUES (3),(4); +CREATE TABLE t3 (f3a int default 1, f3b int default 2); +INSERT INTO t3 VALUES (1,1),(2,2); +set @old_optimizer_switch = @@session.optimizer_switch; +set @@optimizer_switch='materialization=on,partial_match_rowid_merge=on,partial_match_table_scan=off,subquery_cache=off,semijoin=off'; +SELECT (SELECT f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a FROM t1) FROM t2; +(SELECT f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a FROM t1) +NULL +NULL +SELECT (SELECT f3a,f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a,f1a FROM t1) FROM t2; +(SELECT f3a,f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a,f1a FROM t1) +NULL +NULL +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) NOT IN (SELECT f1a, f1b FROM t1) FROM t2; +(SELECT f3a, f3b FROM t3 where f3a > 3) NOT IN (SELECT f1a, f1b FROM t1) +NULL +NULL +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) NOT IN (SELECT f1a, f1b FROM t1); +(SELECT f3a, f3b FROM t3 where f3a > 3) NOT IN (SELECT f1a, f1b FROM t1) +NULL +SELECT (SELECT f3a FROM t3 where f3a > 3) IN (SELECT f1a FROM t1) FROM t2; +(SELECT f3a FROM t3 where f3a > 3) IN (SELECT f1a FROM t1) +NULL +NULL +SELECT (SELECT f3a,f3a FROM t3 where f3a > 3) IN (SELECT f1a,f1a FROM t1) FROM t2; +(SELECT f3a,f3a FROM t3 where f3a > 3) IN (SELECT f1a,f1a FROM t1) +NULL +NULL +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) IN (SELECT f1a, f1b FROM t1) FROM t2; +(SELECT f3a, f3b FROM t3 where f3a > 3) IN (SELECT f1a, f1b FROM t1) +NULL +NULL +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) IN (SELECT f1a, f1b FROM t1); +(SELECT f3a, f3b FROM t3 where f3a > 3) IN (SELECT f1a, f1b FROM t1) +NULL +set @@session.optimizer_switch=@old_optimizer_switch; +SELECT (SELECT f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a FROM t1) FROM t2; +(SELECT f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a FROM t1) +NULL +NULL +SELECT (SELECT f3a,f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a,f1a FROM t1) FROM t2; +(SELECT f3a,f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a,f1a FROM t1) +NULL +NULL +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) NOT IN (SELECT f1a, f1b FROM t1) FROM t2; +(SELECT f3a, f3b FROM t3 where f3a > 3) NOT IN (SELECT f1a, f1b FROM t1) +NULL +NULL +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) NOT IN (SELECT f1a, f1b FROM t1); +(SELECT f3a, f3b FROM t3 where f3a > 3) NOT IN (SELECT f1a, f1b FROM t1) +NULL +SELECT (SELECT f3a FROM t3 where f3a > 3) IN (SELECT f1a FROM t1) FROM t2; +(SELECT f3a FROM t3 where f3a > 3) IN (SELECT f1a FROM t1) +NULL +NULL +SELECT (SELECT f3a,f3a FROM t3 where f3a > 3) IN (SELECT f1a,f1a FROM t1) FROM t2; +(SELECT f3a,f3a FROM t3 where f3a > 3) IN (SELECT f1a,f1a FROM t1) +NULL +NULL +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) IN (SELECT f1a, f1b FROM t1) FROM t2; +(SELECT f3a, f3b FROM t3 where f3a > 3) IN (SELECT f1a, f1b FROM t1) +NULL +NULL +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) IN (SELECT f1a, f1b FROM t1); +(SELECT f3a, f3b FROM t3 where f3a > 3) IN (SELECT f1a, f1b FROM t1) +NULL +select (null, null) = (null, null); +(null, null) = (null, null) +NULL +SELECT (SELECT f3a, f3a FROM t3 where f3a > 3) = (0, 0); +(SELECT f3a, f3a FROM t3 where f3a > 3) = (0, 0) +NULL +drop tables t1,t2,t3; +# 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 5cf75c54a7f..2674c651002 100644 --- a/mysql-test/r/subselect_no_scache.result +++ b/mysql-test/r/subselect_no_scache.result @@ -5738,6 +5738,87 @@ SELECT 't' b a b set @@join_cache_level= @save_join_cache_level; drop table t1,t2; +# +# LP BUG#747278 incorrect values of the NULL (no rows) single +# row subquery requested via element_index() interface +# +CREATE TABLE t1 (f1a int, f1b int) ; +INSERT IGNORE INTO t1 VALUES (1,1),(2,2); +CREATE TABLE t2 ( f2 int); +INSERT IGNORE INTO t2 VALUES (3),(4); +CREATE TABLE t3 (f3a int default 1, f3b int default 2); +INSERT INTO t3 VALUES (1,1),(2,2); +set @old_optimizer_switch = @@session.optimizer_switch; +set @@optimizer_switch='materialization=on,partial_match_rowid_merge=on,partial_match_table_scan=off,subquery_cache=off,semijoin=off'; +SELECT (SELECT f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a FROM t1) FROM t2; +(SELECT f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a FROM t1) +NULL +NULL +SELECT (SELECT f3a,f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a,f1a FROM t1) FROM t2; +(SELECT f3a,f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a,f1a FROM t1) +NULL +NULL +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) NOT IN (SELECT f1a, f1b FROM t1) FROM t2; +(SELECT f3a, f3b FROM t3 where f3a > 3) NOT IN (SELECT f1a, f1b FROM t1) +NULL +NULL +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) NOT IN (SELECT f1a, f1b FROM t1); +(SELECT f3a, f3b FROM t3 where f3a > 3) NOT IN (SELECT f1a, f1b FROM t1) +NULL +SELECT (SELECT f3a FROM t3 where f3a > 3) IN (SELECT f1a FROM t1) FROM t2; +(SELECT f3a FROM t3 where f3a > 3) IN (SELECT f1a FROM t1) +NULL +NULL +SELECT (SELECT f3a,f3a FROM t3 where f3a > 3) IN (SELECT f1a,f1a FROM t1) FROM t2; +(SELECT f3a,f3a FROM t3 where f3a > 3) IN (SELECT f1a,f1a FROM t1) +NULL +NULL +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) IN (SELECT f1a, f1b FROM t1) FROM t2; +(SELECT f3a, f3b FROM t3 where f3a > 3) IN (SELECT f1a, f1b FROM t1) +NULL +NULL +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) IN (SELECT f1a, f1b FROM t1); +(SELECT f3a, f3b FROM t3 where f3a > 3) IN (SELECT f1a, f1b FROM t1) +NULL +set @@session.optimizer_switch=@old_optimizer_switch; +SELECT (SELECT f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a FROM t1) FROM t2; +(SELECT f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a FROM t1) +NULL +NULL +SELECT (SELECT f3a,f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a,f1a FROM t1) FROM t2; +(SELECT f3a,f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a,f1a FROM t1) +NULL +NULL +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) NOT IN (SELECT f1a, f1b FROM t1) FROM t2; +(SELECT f3a, f3b FROM t3 where f3a > 3) NOT IN (SELECT f1a, f1b FROM t1) +NULL +NULL +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) NOT IN (SELECT f1a, f1b FROM t1); +(SELECT f3a, f3b FROM t3 where f3a > 3) NOT IN (SELECT f1a, f1b FROM t1) +NULL +SELECT (SELECT f3a FROM t3 where f3a > 3) IN (SELECT f1a FROM t1) FROM t2; +(SELECT f3a FROM t3 where f3a > 3) IN (SELECT f1a FROM t1) +NULL +NULL +SELECT (SELECT f3a,f3a FROM t3 where f3a > 3) IN (SELECT f1a,f1a FROM t1) FROM t2; +(SELECT f3a,f3a FROM t3 where f3a > 3) IN (SELECT f1a,f1a FROM t1) +NULL +NULL +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) IN (SELECT f1a, f1b FROM t1) FROM t2; +(SELECT f3a, f3b FROM t3 where f3a > 3) IN (SELECT f1a, f1b FROM t1) +NULL +NULL +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) IN (SELECT f1a, f1b FROM t1); +(SELECT f3a, f3b FROM t3 where f3a > 3) IN (SELECT f1a, f1b FROM t1) +NULL +select (null, null) = (null, null); +(null, null) = (null, null) +NULL +SELECT (SELECT f3a, f3a FROM t3 where f3a > 3) = (0, 0); +(SELECT f3a, f3a FROM t3 where f3a > 3) = (0, 0) +NULL +drop tables t1,t2,t3; +# return optimizer switch changed in the beginning of this test set optimizer_switch=@subselect_tmp; set optimizer_switch=default; select @@optimizer_switch like '%subquery_cache=on%'; diff --git a/mysql-test/r/subselect_no_semijoin.result b/mysql-test/r/subselect_no_semijoin.result index eafddafb368..a2d3cab4dca 100644 --- a/mysql-test/r/subselect_no_semijoin.result +++ b/mysql-test/r/subselect_no_semijoin.result @@ -5729,5 +5729,86 @@ SELECT 't' b a b set @@join_cache_level= @save_join_cache_level; drop table t1,t2; +# +# LP BUG#747278 incorrect values of the NULL (no rows) single +# row subquery requested via element_index() interface +# +CREATE TABLE t1 (f1a int, f1b int) ; +INSERT IGNORE INTO t1 VALUES (1,1),(2,2); +CREATE TABLE t2 ( f2 int); +INSERT IGNORE INTO t2 VALUES (3),(4); +CREATE TABLE t3 (f3a int default 1, f3b int default 2); +INSERT INTO t3 VALUES (1,1),(2,2); +set @old_optimizer_switch = @@session.optimizer_switch; +set @@optimizer_switch='materialization=on,partial_match_rowid_merge=on,partial_match_table_scan=off,subquery_cache=off,semijoin=off'; +SELECT (SELECT f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a FROM t1) FROM t2; +(SELECT f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a FROM t1) +NULL +NULL +SELECT (SELECT f3a,f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a,f1a FROM t1) FROM t2; +(SELECT f3a,f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a,f1a FROM t1) +NULL +NULL +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) NOT IN (SELECT f1a, f1b FROM t1) FROM t2; +(SELECT f3a, f3b FROM t3 where f3a > 3) NOT IN (SELECT f1a, f1b FROM t1) +NULL +NULL +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) NOT IN (SELECT f1a, f1b FROM t1); +(SELECT f3a, f3b FROM t3 where f3a > 3) NOT IN (SELECT f1a, f1b FROM t1) +NULL +SELECT (SELECT f3a FROM t3 where f3a > 3) IN (SELECT f1a FROM t1) FROM t2; +(SELECT f3a FROM t3 where f3a > 3) IN (SELECT f1a FROM t1) +NULL +NULL +SELECT (SELECT f3a,f3a FROM t3 where f3a > 3) IN (SELECT f1a,f1a FROM t1) FROM t2; +(SELECT f3a,f3a FROM t3 where f3a > 3) IN (SELECT f1a,f1a FROM t1) +NULL +NULL +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) IN (SELECT f1a, f1b FROM t1) FROM t2; +(SELECT f3a, f3b FROM t3 where f3a > 3) IN (SELECT f1a, f1b FROM t1) +NULL +NULL +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) IN (SELECT f1a, f1b FROM t1); +(SELECT f3a, f3b FROM t3 where f3a > 3) IN (SELECT f1a, f1b FROM t1) +NULL +set @@session.optimizer_switch=@old_optimizer_switch; +SELECT (SELECT f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a FROM t1) FROM t2; +(SELECT f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a FROM t1) +NULL +NULL +SELECT (SELECT f3a,f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a,f1a FROM t1) FROM t2; +(SELECT f3a,f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a,f1a FROM t1) +NULL +NULL +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) NOT IN (SELECT f1a, f1b FROM t1) FROM t2; +(SELECT f3a, f3b FROM t3 where f3a > 3) NOT IN (SELECT f1a, f1b FROM t1) +NULL +NULL +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) NOT IN (SELECT f1a, f1b FROM t1); +(SELECT f3a, f3b FROM t3 where f3a > 3) NOT IN (SELECT f1a, f1b FROM t1) +NULL +SELECT (SELECT f3a FROM t3 where f3a > 3) IN (SELECT f1a FROM t1) FROM t2; +(SELECT f3a FROM t3 where f3a > 3) IN (SELECT f1a FROM t1) +NULL +NULL +SELECT (SELECT f3a,f3a FROM t3 where f3a > 3) IN (SELECT f1a,f1a FROM t1) FROM t2; +(SELECT f3a,f3a FROM t3 where f3a > 3) IN (SELECT f1a,f1a FROM t1) +NULL +NULL +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) IN (SELECT f1a, f1b FROM t1) FROM t2; +(SELECT f3a, f3b FROM t3 where f3a > 3) IN (SELECT f1a, f1b FROM t1) +NULL +NULL +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) IN (SELECT f1a, f1b FROM t1); +(SELECT f3a, f3b FROM t3 where f3a > 3) IN (SELECT f1a, f1b FROM t1) +NULL +select (null, null) = (null, null); +(null, null) = (null, null) +NULL +SELECT (SELECT f3a, f3a FROM t3 where f3a > 3) = (0, 0); +(SELECT f3a, f3a FROM t3 where f3a > 3) = (0, 0) +NULL +drop tables t1,t2,t3; +# 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 abce58348da..848509d9a7c 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -4840,4 +4840,49 @@ WHERE t2.b IN ( set @@join_cache_level= @save_join_cache_level; drop table t1,t2; + +--echo # +--echo # LP BUG#747278 incorrect values of the NULL (no rows) single +--echo # row subquery requested via element_index() interface +--echo # + +CREATE TABLE t1 (f1a int, f1b int) ; +INSERT IGNORE INTO t1 VALUES (1,1),(2,2); +CREATE TABLE t2 ( f2 int); +INSERT IGNORE INTO t2 VALUES (3),(4); +CREATE TABLE t3 (f3a int default 1, f3b int default 2); +INSERT INTO t3 VALUES (1,1),(2,2); + +# check different IN with switches where the bug was found +set @old_optimizer_switch = @@session.optimizer_switch; +set @@optimizer_switch='materialization=on,partial_match_rowid_merge=on,partial_match_table_scan=off,subquery_cache=off,semijoin=off'; + +SELECT (SELECT f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a FROM t1) FROM t2; +SELECT (SELECT f3a,f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a,f1a FROM t1) FROM t2; +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) NOT IN (SELECT f1a, f1b FROM t1) FROM t2; +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) NOT IN (SELECT f1a, f1b FROM t1); +SELECT (SELECT f3a FROM t3 where f3a > 3) IN (SELECT f1a FROM t1) FROM t2; +SELECT (SELECT f3a,f3a FROM t3 where f3a > 3) IN (SELECT f1a,f1a FROM t1) FROM t2; +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) IN (SELECT f1a, f1b FROM t1) FROM t2; +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) IN (SELECT f1a, f1b FROM t1); + +set @@session.optimizer_switch=@old_optimizer_switch; + +# check different IN with default switches +SELECT (SELECT f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a FROM t1) FROM t2; +SELECT (SELECT f3a,f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a,f1a FROM t1) FROM t2; +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) NOT IN (SELECT f1a, f1b FROM t1) FROM t2; +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) NOT IN (SELECT f1a, f1b FROM t1); +SELECT (SELECT f3a FROM t3 where f3a > 3) IN (SELECT f1a FROM t1) FROM t2; +SELECT (SELECT f3a,f3a FROM t3 where f3a > 3) IN (SELECT f1a,f1a FROM t1) FROM t2; +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) IN (SELECT f1a, f1b FROM t1) FROM t2; +SELECT (SELECT f3a, f3b FROM t3 where f3a > 3) IN (SELECT f1a, f1b FROM t1); + +# other row operation with NULL single row subquery also should work +select (null, null) = (null, null); +SELECT (SELECT f3a, f3a FROM t3 where f3a > 3) = (0, 0); + +drop tables t1,t2,t3; + +--echo # return optimizer switch changed in the beginning of this test set optimizer_switch=@subselect_tmp; diff --git a/sql/item.cc b/sql/item.cc index d321b74c1fc..9ba93780334 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -8201,6 +8201,20 @@ void Item_cache::print(String *str, enum_query_type query_type) str->append(')'); } +/** + Assign to this cache NULL value if it is possible +*/ + +void Item_cache::set_null() +{ + if (maybe_null) + { + null_value= TRUE; + value_cached= TRUE; + } +} + + bool Item_cache_int::cache_value() { if (!example) @@ -8671,6 +8685,20 @@ void Item_cache_row::bring_value() } +/** + Assign to this cache NULL value if it is possible +*/ + +void Item_cache_row::set_null() +{ + Item_cache::set_null(); + if (!values) + return; + for (uint i= 0; i < item_count; i++) + values[i]->set_null(); +}; + + Item_type_holder::Item_type_holder(THD *thd, Item *item) :Item(thd, item), enum_set_typelib(0), fld_type(get_real_type(item)) { diff --git a/sql/item.h b/sql/item.h index e05fbf3b67d..fb6421c23b2 100644 --- a/sql/item.h +++ b/sql/item.h @@ -3651,6 +3651,7 @@ public: return false; return example->is_expensive_processor(arg); } + virtual void set_null(); }; @@ -3825,6 +3826,7 @@ public: DBUG_VOID_RETURN; } bool cache_value(); + virtual void set_null(); }; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index e131c9b0c9b..2baf530279f 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -893,7 +893,10 @@ void Item_singlerow_subselect::reset() { Item_subselect::reset(); if (value) - value->null_value= TRUE; + { + for(uint i= 0; i < engine->cols(); i++) + row[i]->set_null(); + } } @@ -1004,6 +1007,11 @@ void Item_singlerow_subselect::fix_length_and_dec() */ if (engine->no_tables()) maybe_null= engine->may_be_null(); + else + { + for (uint i= 0; i < max_columns; i++) + row[i]->maybe_null= TRUE; + } } diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 9d71a61f411..669b6aa14fb 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -1691,6 +1691,8 @@ frm_type_enum mysql_frm_type(THD *thd, char *path, enum legacy_db_type *dbt) *dbt= DB_TYPE_UNKNOWN; + + if ((file= my_open(path, O_RDONLY | O_SHARE, MYF(0))) < 0) DBUG_RETURN(FRMTYPE_ERROR); error= my_read(file, (uchar*) header, sizeof(header), MYF(MY_NABP)); From 62e7ab3ac7a7dc6c89308f9883610d9951d85a73 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 28 Nov 2011 15:24:07 +0200 Subject: [PATCH 127/288] Fix bugs lp:833777, lp:894397 Analysis: lp:894397 was a consequence of a prior incorrect fix of lp:833777 which didn't take into account that even when all tables are constant there may be correlated conditions, and the where clause is not equivalent to the constant conditions. Solution: When there are constant tables only, evaluate only the conditions that reference outer fields, because the constant conditions are already checked, and the where clause doesn't have other conditions than constant ones, and outer referencing ones. The fix for lp:894397 also fixes lp:833777. --- mysql-test/r/subselect.result | 13 +++++++++++++ mysql-test/r/subselect_no_mat.result | 13 +++++++++++++ mysql-test/r/subselect_no_opts.result | 13 +++++++++++++ mysql-test/r/subselect_no_scache.result | 13 +++++++++++++ mysql-test/r/subselect_no_semijoin.result | 13 +++++++++++++ mysql-test/t/subselect.test | 14 ++++++++++++++ sql/sql_select.cc | 16 ++++++++-------- 7 files changed, 87 insertions(+), 8 deletions(-) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 5e8432f2509..87c5a3da69d 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -5686,8 +5686,21 @@ set @@optimizer_switch='in_to_exists=on,semijoin=off,materialization=off,subquer select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1))))))))))))))))))))))))))))); a 1 +set @@optimizer_switch=@subselect_tmp; drop table t1; # +# LP BUG#894397 Wrong result with in_to_exists, constant table , semijoin=OFF,materialization=OFF +# +CREATE TABLE t1 (a varchar(3)); +INSERT INTO t1 VALUES ('AAA'),('BBB'); +CREATE TABLE t2 (a varchar(3)); +INSERT INTO t2 VALUES ('CCC'); +set @@optimizer_switch='semijoin=off,materialization=off,in_to_exists=on,subquery_cache=off'; +SELECT * FROM t1 WHERE t1.a IN (SELECT t2.a FROM t2 WHERE t2.a < 'ZZZ'); +a +set @@optimizer_switch=@subselect_tmp; +drop table t1, t2; +# # LP bug #859375: Assertion `0' failed in st_select_lex_unit::optimize # with view , UNION and prepared statement (rewriting fake_select # condition). diff --git a/mysql-test/r/subselect_no_mat.result b/mysql-test/r/subselect_no_mat.result index 2b1f3ecdaf2..a7625db5ff3 100644 --- a/mysql-test/r/subselect_no_mat.result +++ b/mysql-test/r/subselect_no_mat.result @@ -5685,8 +5685,21 @@ set @@optimizer_switch='in_to_exists=on,semijoin=off,materialization=off,subquer select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1))))))))))))))))))))))))))))); a 1 +set @@optimizer_switch=@subselect_tmp; drop table t1; # +# LP BUG#894397 Wrong result with in_to_exists, constant table , semijoin=OFF,materialization=OFF +# +CREATE TABLE t1 (a varchar(3)); +INSERT INTO t1 VALUES ('AAA'),('BBB'); +CREATE TABLE t2 (a varchar(3)); +INSERT INTO t2 VALUES ('CCC'); +set @@optimizer_switch='semijoin=off,materialization=off,in_to_exists=on,subquery_cache=off'; +SELECT * FROM t1 WHERE t1.a IN (SELECT t2.a FROM t2 WHERE t2.a < 'ZZZ'); +a +set @@optimizer_switch=@subselect_tmp; +drop table t1, t2; +# # LP bug #859375: Assertion `0' failed in st_select_lex_unit::optimize # with view , UNION and prepared statement (rewriting fake_select # condition). diff --git a/mysql-test/r/subselect_no_opts.result b/mysql-test/r/subselect_no_opts.result index 8675a7a7e89..d7c67131970 100644 --- a/mysql-test/r/subselect_no_opts.result +++ b/mysql-test/r/subselect_no_opts.result @@ -5681,8 +5681,21 @@ set @@optimizer_switch='in_to_exists=on,semijoin=off,materialization=off,subquer select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1))))))))))))))))))))))))))))); a 1 +set @@optimizer_switch=@subselect_tmp; drop table t1; # +# LP BUG#894397 Wrong result with in_to_exists, constant table , semijoin=OFF,materialization=OFF +# +CREATE TABLE t1 (a varchar(3)); +INSERT INTO t1 VALUES ('AAA'),('BBB'); +CREATE TABLE t2 (a varchar(3)); +INSERT INTO t2 VALUES ('CCC'); +set @@optimizer_switch='semijoin=off,materialization=off,in_to_exists=on,subquery_cache=off'; +SELECT * FROM t1 WHERE t1.a IN (SELECT t2.a FROM t2 WHERE t2.a < 'ZZZ'); +a +set @@optimizer_switch=@subselect_tmp; +drop table t1, t2; +# # LP bug #859375: Assertion `0' failed in st_select_lex_unit::optimize # with view , UNION and prepared statement (rewriting fake_select # condition). diff --git a/mysql-test/r/subselect_no_scache.result b/mysql-test/r/subselect_no_scache.result index 2674c651002..ef1b268f5ba 100644 --- a/mysql-test/r/subselect_no_scache.result +++ b/mysql-test/r/subselect_no_scache.result @@ -5690,8 +5690,21 @@ set @@optimizer_switch='in_to_exists=on,semijoin=off,materialization=off,subquer select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1))))))))))))))))))))))))))))); a 1 +set @@optimizer_switch=@subselect_tmp; drop table t1; # +# LP BUG#894397 Wrong result with in_to_exists, constant table , semijoin=OFF,materialization=OFF +# +CREATE TABLE t1 (a varchar(3)); +INSERT INTO t1 VALUES ('AAA'),('BBB'); +CREATE TABLE t2 (a varchar(3)); +INSERT INTO t2 VALUES ('CCC'); +set @@optimizer_switch='semijoin=off,materialization=off,in_to_exists=on,subquery_cache=off'; +SELECT * FROM t1 WHERE t1.a IN (SELECT t2.a FROM t2 WHERE t2.a < 'ZZZ'); +a +set @@optimizer_switch=@subselect_tmp; +drop table t1, t2; +# # LP bug #859375: Assertion `0' failed in st_select_lex_unit::optimize # with view , UNION and prepared statement (rewriting fake_select # condition). diff --git a/mysql-test/r/subselect_no_semijoin.result b/mysql-test/r/subselect_no_semijoin.result index a2d3cab4dca..9f50a975b84 100644 --- a/mysql-test/r/subselect_no_semijoin.result +++ b/mysql-test/r/subselect_no_semijoin.result @@ -5681,8 +5681,21 @@ set @@optimizer_switch='in_to_exists=on,semijoin=off,materialization=off,subquer select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1))))))))))))))))))))))))))))); a 1 +set @@optimizer_switch=@subselect_tmp; drop table t1; # +# LP BUG#894397 Wrong result with in_to_exists, constant table , semijoin=OFF,materialization=OFF +# +CREATE TABLE t1 (a varchar(3)); +INSERT INTO t1 VALUES ('AAA'),('BBB'); +CREATE TABLE t2 (a varchar(3)); +INSERT INTO t2 VALUES ('CCC'); +set @@optimizer_switch='semijoin=off,materialization=off,in_to_exists=on,subquery_cache=off'; +SELECT * FROM t1 WHERE t1.a IN (SELECT t2.a FROM t2 WHERE t2.a < 'ZZZ'); +a +set @@optimizer_switch=@subselect_tmp; +drop table t1, t2; +# # LP bug #859375: Assertion `0' failed in st_select_lex_unit::optimize # with view , UNION and prepared statement (rewriting fake_select # condition). diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 848509d9a7c..92df79d7777 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -4782,8 +4782,22 @@ create table t1 (a int not null, b char(10) not null); insert into t1 values (1, 'a'); set @@optimizer_switch='in_to_exists=on,semijoin=off,materialization=off,subquery_cache=off'; select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1 where a in (select a from t1))))))))))))))))))))))))))))); +set @@optimizer_switch=@subselect_tmp; drop table t1; +--echo # +--echo # LP BUG#894397 Wrong result with in_to_exists, constant table , semijoin=OFF,materialization=OFF +--echo # + +CREATE TABLE t1 (a varchar(3)); +INSERT INTO t1 VALUES ('AAA'),('BBB'); +CREATE TABLE t2 (a varchar(3)); +INSERT INTO t2 VALUES ('CCC'); +set @@optimizer_switch='semijoin=off,materialization=off,in_to_exists=on,subquery_cache=off'; +SELECT * FROM t1 WHERE t1.a IN (SELECT t2.a FROM t2 WHERE t2.a < 'ZZZ'); +set @@optimizer_switch=@subselect_tmp; +drop table t1, t2; + --echo # --echo # LP bug #859375: Assertion `0' failed in st_select_lex_unit::optimize --echo # with view , UNION and prepared statement (rewriting fake_select diff --git a/sql/sql_select.cc b/sql/sql_select.cc index d8c17012196..0ef417c9567 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -14775,15 +14775,15 @@ do_select(JOIN *join,List *fields,TABLE *table,Procedure *procedure) { /* HAVING will be checked after processing aggregate functions, - But WHERE should checkd here (we alredy have read tables). - If there is join->exec_const_cond, and all tables are constant, then it - is equivalent to join->conds. exec_const_cond is already checked in the - beginning of JOIN::exec. If it is false, JOIN::exec returns zero - result already there, therefore execution reaches this point only if - exec_const_cond is TRUE. Since it is equvalent to join->conds, then - join->conds is also TRUE. + But WHERE should checked here (we alredy have read tables). + Notice that make_join_select() splits all conditions into three groups - + exec_const_cond, outer_ref_cond, and conditions attached to non-constant + tables. Within this IF the latter do not exist. At the same time + exec_const_cond is already checked either by make_join_select or in the + beginning of JOIN::exec. Therefore here it is sufficient to check only + outer_ref_cond. */ - if (!join->conds || join->exec_const_cond || join->conds->val_int()) + if (!join->outer_ref_cond || join->outer_ref_cond->val_int()) { error= (*end_select)(join, 0, 0); if (error == NESTED_LOOP_OK || error == NESTED_LOOP_QUERY_LIMIT) From e79847d16a0f51137ca46f23af7d5276dce7952d Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 28 Nov 2011 15:08:12 +0100 Subject: [PATCH 128/288] after merge fixes sql/sql_base.cc: fix a memory leak storage/xtradb/handler/ha_innodb.cc: fix for a visual studio storage/xtradb/row/row0ins.c: valgrind complains about uninitialized variable. incorrect errors in the innodb.test too --- mysql-test/suite/innodb_plugin/t/innodb_gis.test | 2 +- mysql-test/suite/innodb_plugin/t/innodb_mysql.test | 2 +- sql/password.c | 4 ++-- sql/sql_base.cc | 10 ++++++++-- storage/xtradb/handler/ha_innodb.cc | 9 ++++----- storage/xtradb/row/row0ins.c | 3 ++- 6 files changed, 18 insertions(+), 12 deletions(-) diff --git a/mysql-test/suite/innodb_plugin/t/innodb_gis.test b/mysql-test/suite/innodb_plugin/t/innodb_gis.test index ad1d081f29c..3ad20e3dce6 100644 --- a/mysql-test/suite/innodb_plugin/t/innodb_gis.test +++ b/mysql-test/suite/innodb_plugin/t/innodb_gis.test @@ -1,4 +1,4 @@ ---source include/have_innodb_plugin.inc +--source include/have_xtradb.inc SET storage_engine=innodb; --source include/gis_generic.inc --source include/gis_keys.inc diff --git a/mysql-test/suite/innodb_plugin/t/innodb_mysql.test b/mysql-test/suite/innodb_plugin/t/innodb_mysql.test index 1cdc1b4e2fe..fc77d9aaa8a 100644 --- a/mysql-test/suite/innodb_plugin/t/innodb_mysql.test +++ b/mysql-test/suite/innodb_plugin/t/innodb_mysql.test @@ -5,7 +5,7 @@ # main testing code t/innodb_mysql.test -> include/mix1.inc # --- source include/have_innodb_plugin.inc +-- source include/have_xtradb.inc -- source include/have_query_cache.inc let $engine_type= InnoDB; diff --git a/sql/password.c b/sql/password.c index 27fbb07b6e3..64b3d69862d 100644 --- a/sql/password.c +++ b/sql/password.c @@ -196,8 +196,8 @@ check_scramble_323(const unsigned char *scrambled, const char *message, struct my_rnd_struct rand_st; ulong hash_message[2]; /* Big enough for checks. */ - char buff[16], scrambled_buff[SCRAMBLE_LENGTH_323 + 1]; - char *to, extra; + uchar buff[16], scrambled_buff[SCRAMBLE_LENGTH_323 + 1]; + uchar *to, extra; const uchar *pos; /* Ensure that the scrambled message is null-terminated. */ diff --git a/sql/sql_base.cc b/sql/sql_base.cc index c8b1067425b..ee44629a192 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2309,7 +2309,12 @@ bool reopen_name_locked_table(THD* thd, TABLE_LIST* table_list, bool link_in) if (thd->killed || !table) DBUG_RETURN(TRUE); - orig_table= *table; + /* + make a copy. we may need to restore it later. + don't use orig_table=*table, because we need an exact replica, + not a C++ copy that may modify the data in the copy constructor. + */ + memcpy(&orig_table, table, sizeof(*table)); if (open_unireg_entry(thd, table, table_list, table_name, table->s->table_cache_key.str, @@ -2322,9 +2327,10 @@ bool reopen_name_locked_table(THD* thd, TABLE_LIST* table_list, bool link_in) properly release name-lock in this case we should restore this object to its original state. */ - *table= orig_table; + memcpy(table, &orig_table, sizeof(*table)); DBUG_RETURN(TRUE); } + orig_table.alias.free(); share= table->s; /* diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index 66243ad2e34..beb45305ba3 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -11614,14 +11614,13 @@ static MYSQL_SYSVAR_ULONG(concurrency_tickets, srv_n_free_tickets_to_enter, "Number of times a thread is allowed to enter InnoDB within the same SQL query after it has once got the ticket", NULL, NULL, 500L, 1L, ~0L, 0); -static MYSQL_SYSVAR_LONG(kill_idle_transaction, srv_kill_idle_transaction, - PLUGIN_VAR_RQCMDARG, #ifdef EXTENDED_FOR_KILLIDLE - "If non-zero value, the idle session with transaction which is idle over the value in seconds is killed by InnoDB.", +#define kill_idle_help_text "If non-zero value, the idle session with transaction which is idle over the value in seconds is killed by InnoDB." #else - "No effect for this build.", +#define kill_idle_help_text "No effect for this build." #endif - NULL, NULL, 0, 0, LONG_MAX, 0); +static MYSQL_SYSVAR_LONG(kill_idle_transaction, srv_kill_idle_transaction, + PLUGIN_VAR_RQCMDARG, kill_idle_help_text, NULL, NULL, 0, 0, LONG_MAX, 0); static MYSQL_SYSVAR_LONG(file_io_threads, innobase_file_io_threads, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY | PLUGIN_VAR_NOSYSVAR, diff --git a/storage/xtradb/row/row0ins.c b/storage/xtradb/row/row0ins.c index 0e62185c02e..6068c3547df 100644 --- a/storage/xtradb/row/row0ins.c +++ b/storage/xtradb/row/row0ins.c @@ -493,7 +493,8 @@ row_ins_cascade_calc_update_vec( ufield->field_no = dict_table_get_nth_col_pos( table, dict_col_get_no(col)); - ufield->exp = NULL; + + ufield->orig_len = 0; ufield->new_val = parent_ufield->new_val; ufield_len = dfield_get_len(&ufield->new_val); From 18d9f8d429c539b9ba7543615e54de03e8a71c96 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Tue, 29 Nov 2011 02:11:13 +0400 Subject: [PATCH 129/288] bug 857066 Wrong result with ST_DISJOINT when using an index the ST_DISJOINT can't be properly optimized with the RTree key at the moment. per-file comments: storage/maria/ma_rt_index.c bug 857066 Wrong result with ST_DISJOINT when using an index disabled optimization for the DISJOINT case. --- storage/maria/ma_rt_index.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/maria/ma_rt_index.c b/storage/maria/ma_rt_index.c index bd1b9038ccf..f4c5b26f40a 100644 --- a/storage/maria/ma_rt_index.c +++ b/storage/maria/ma_rt_index.c @@ -1258,7 +1258,7 @@ ha_rows maria_rtree_estimate(MARIA_HA *info, MARIA_KEY *key, uint32 flag) MARIA_PAGE page; if (flag & MBR_DISJOINT) - return info->state->records; + return HA_POS_ERROR; if ((root= share->state.key_root[key->keyinfo->key_nr]) == HA_OFFSET_ERROR) return HA_POS_ERROR; From 0c3b78438b627127f1a567aaede90466be549f52 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Tue, 29 Nov 2011 01:10:17 +0100 Subject: [PATCH 130/288] Fix Windows build, and a conversion truncation warning. --- storage/maria/ma_bitmap.c | 4 ++-- storage/xtradb/handler/ha_innodb.cc | 9 ++++----- storage/xtradb/include/srv0srv.h | 2 +- storage/xtradb/srv/srv0srv.c | 2 +- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/storage/maria/ma_bitmap.c b/storage/maria/ma_bitmap.c index 81b436346b1..00f529be92d 100644 --- a/storage/maria/ma_bitmap.c +++ b/storage/maria/ma_bitmap.c @@ -282,7 +282,7 @@ my_bool _ma_bitmap_init(MARIA_SHARE *share, File file, */ { pgcache_page_no_t last_bitmap_page; - ulong blocks, bytes; + pgcache_page_no_t blocks, bytes; last_bitmap_page= *last_page - *last_page % bitmap->pages_covered; blocks= *last_page - last_bitmap_page; @@ -291,7 +291,7 @@ my_bool _ma_bitmap_init(MARIA_SHARE *share, File file, bytes/= 6; bytes*= 6; bitmap->last_bitmap_page= last_bitmap_page; - bitmap->last_total_size= bytes; + bitmap->last_total_size= (uint)bytes; *last_page= ((last_bitmap_page + bytes*8/3)); } diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index b07f6f0b93d..744865a31f3 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -11603,14 +11603,13 @@ static MYSQL_SYSVAR_ULONG(concurrency_tickets, srv_n_free_tickets_to_enter, "Number of times a thread is allowed to enter InnoDB within the same SQL query after it has once got the ticket", NULL, NULL, 500L, 1L, ~0L, 0); -static MYSQL_SYSVAR_LONG(kill_idle_transaction, srv_kill_idle_transaction, - PLUGIN_VAR_RQCMDARG, #ifdef EXTENDED_FOR_KILLIDLE - "If non-zero value, the idle session with transaction which is idle over the value in seconds is killed by InnoDB.", +#define kill_idle_help_text "If non-zero value, the idle session with transaction which is idle over the value in seconds is killed by InnoDB." #else - "No effect for this build.", +#define kill_idle_help_text "No effect for this build." #endif - NULL, NULL, 0, 0, LONG_MAX, 0); +static MYSQL_SYSVAR_LONGLONG(kill_idle_transaction, srv_kill_idle_transaction, + PLUGIN_VAR_RQCMDARG, kill_idle_help_text, NULL, NULL, 0, 0, LONG_MAX, 0); static MYSQL_SYSVAR_LONG(file_io_threads, innobase_file_io_threads, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY | PLUGIN_VAR_NOSYSVAR, diff --git a/storage/xtradb/include/srv0srv.h b/storage/xtradb/include/srv0srv.h index c120db5cbcc..8038178c2f3 100644 --- a/storage/xtradb/include/srv0srv.h +++ b/storage/xtradb/include/srv0srv.h @@ -285,7 +285,7 @@ extern ibool srv_print_latch_waits; extern ulint srv_activity_count; extern ulint srv_fatal_semaphore_wait_threshold; extern ulint srv_dml_needed_delay; -extern lint srv_kill_idle_transaction; +extern long long srv_kill_idle_transaction; extern mutex_t* kernel_mutex_temp;/* mutex protecting the server, trx structs, query threads, and lock table: we allocate diff --git a/storage/xtradb/srv/srv0srv.c b/storage/xtradb/srv/srv0srv.c index 2ff729efbb1..176b063d147 100644 --- a/storage/xtradb/srv/srv0srv.c +++ b/storage/xtradb/srv/srv0srv.c @@ -106,7 +106,7 @@ UNIV_INTERN ulint srv_activity_count = 0; UNIV_INTERN ulint srv_fatal_semaphore_wait_threshold = 600; /**/ -UNIV_INTERN lint srv_kill_idle_transaction = 0; +UNIV_INTERN long long srv_kill_idle_transaction = 0; /* How much data manipulation language (DML) statements need to be delayed, in microseconds, in order to reduce the lagging of the purge thread. */ From 82adfe7b2a695fd9357e1f2f04415fd1691956b8 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Tue, 29 Nov 2011 02:00:24 +0100 Subject: [PATCH 131/288] merge, fix Windows warnings --- include/mysql/client_plugin.h | 3 +++ plugin/feedback/feedback.h | 3 ++- storage/maria/ma_bitmap.c | 2 +- storage/xtradb/handler/ha_innodb.cc | 2 +- storage/xtradb/include/srv0srv.h | 2 +- storage/xtradb/srv/srv0srv.c | 2 +- 6 files changed, 9 insertions(+), 5 deletions(-) diff --git a/include/mysql/client_plugin.h b/include/mysql/client_plugin.h index fc4db6b6553..33c63b9df33 100644 --- a/include/mysql/client_plugin.h +++ b/include/mysql/client_plugin.h @@ -28,6 +28,9 @@ #include #endif +#ifdef MYSQL_PLUGIN_EXPORT +#undef MYSQL_PLUGIN_EXPORT +#endif #if defined(_MSC_VER) #ifdef __cplusplus #define MYSQL_PLUGIN_EXPORT extern "C" __declspec(dllexport) diff --git a/plugin/feedback/feedback.h b/plugin/feedback/feedback.h index 60ef72eed84..df9020fc37e 100644 --- a/plugin/feedback/feedback.h +++ b/plugin/feedback/feedback.h @@ -12,8 +12,9 @@ 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 */ - +#ifndef MYSQL_SERVER #define MYSQL_SERVER +#endif #include namespace feedback { diff --git a/storage/maria/ma_bitmap.c b/storage/maria/ma_bitmap.c index 18ea1fc3997..7a68c91598c 100644 --- a/storage/maria/ma_bitmap.c +++ b/storage/maria/ma_bitmap.c @@ -293,7 +293,7 @@ my_bool _ma_bitmap_init(MARIA_SHARE *share, File file, bytes/= 6; bytes*= 6; bitmap->last_bitmap_page= last_bitmap_page; - bitmap->last_total_size= bytes; + bitmap->last_total_size= (uint)bytes; *last_page= ((last_bitmap_page + bytes*8/3)); } diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index beb45305ba3..6161a5f10ce 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -11619,7 +11619,7 @@ static MYSQL_SYSVAR_ULONG(concurrency_tickets, srv_n_free_tickets_to_enter, #else #define kill_idle_help_text "No effect for this build." #endif -static MYSQL_SYSVAR_LONG(kill_idle_transaction, srv_kill_idle_transaction, +static MYSQL_SYSVAR_LONGLONG(kill_idle_transaction, srv_kill_idle_transaction, PLUGIN_VAR_RQCMDARG, kill_idle_help_text, NULL, NULL, 0, 0, LONG_MAX, 0); static MYSQL_SYSVAR_LONG(file_io_threads, innobase_file_io_threads, diff --git a/storage/xtradb/include/srv0srv.h b/storage/xtradb/include/srv0srv.h index c120db5cbcc..8038178c2f3 100644 --- a/storage/xtradb/include/srv0srv.h +++ b/storage/xtradb/include/srv0srv.h @@ -285,7 +285,7 @@ extern ibool srv_print_latch_waits; extern ulint srv_activity_count; extern ulint srv_fatal_semaphore_wait_threshold; extern ulint srv_dml_needed_delay; -extern lint srv_kill_idle_transaction; +extern long long srv_kill_idle_transaction; extern mutex_t* kernel_mutex_temp;/* mutex protecting the server, trx structs, query threads, and lock table: we allocate diff --git a/storage/xtradb/srv/srv0srv.c b/storage/xtradb/srv/srv0srv.c index 2ff729efbb1..176b063d147 100644 --- a/storage/xtradb/srv/srv0srv.c +++ b/storage/xtradb/srv/srv0srv.c @@ -106,7 +106,7 @@ UNIV_INTERN ulint srv_activity_count = 0; UNIV_INTERN ulint srv_fatal_semaphore_wait_threshold = 600; /**/ -UNIV_INTERN lint srv_kill_idle_transaction = 0; +UNIV_INTERN long long srv_kill_idle_transaction = 0; /* How much data manipulation language (DML) statements need to be delayed, in microseconds, in order to reduce the lagging of the purge thread. */ From 389acf0a30415c745d2c241e1584b0b637ab95ed Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Tue, 29 Nov 2011 08:50:54 +0100 Subject: [PATCH 132/288] Fix testcases: 1. main.merge fails with errno 13 in copy_file(). The reason for the error is that copy_file tries to create a file with the same name as recently deleted one, and there is still an open handle for the deleted file. To fix, use my_delete_allow_opened() for MTR's delete_file. On Windows, this renames file to unique name prior to deletion, and prevents EACCES errors for files opened with FILE_SHARE_DELETE. 2. innodb_bug59641 generates warnings, after server was killed and restarted in the test case. The warnings are about test_suppression table (needs to be repaired, as it that was written just prior to the crash) Fixed by using FLUSH TABLES after populating warning suppression table. --- client/mysqltest.cc | 2 +- mysql-test/suite/innodb/r/innodb_bug59641.result | 1 + mysql-test/suite/innodb/t/innodb_bug59641.test | 2 +- mysql-test/suite/innodb_plugin/r/innodb_bug59641.result | 1 + mysql-test/suite/innodb_plugin/t/innodb_bug59641.test | 2 +- 5 files changed, 5 insertions(+), 3 deletions(-) diff --git a/client/mysqltest.cc b/client/mysqltest.cc index 84cbd314b4a..6a3b75f2410 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -3060,7 +3060,7 @@ void do_remove_file(struct st_command *command) ' '); DBUG_PRINT("info", ("removing file: %s", ds_filename.str)); - error= my_delete(ds_filename.str, MYF(disable_warnings ? 0 : MY_WME)) != 0; + error= my_delete_allow_opened(ds_filename.str, MYF(disable_warnings ? 0 : MY_WME)) != 0; handle_command_error(command, error, my_errno); dynstr_free(&ds_filename); DBUG_VOID_RETURN; diff --git a/mysql-test/suite/innodb/r/innodb_bug59641.result b/mysql-test/suite/innodb/r/innodb_bug59641.result index 482df8914eb..de8bb61bd0d 100644 --- a/mysql-test/suite/innodb/r/innodb_bug59641.result +++ b/mysql-test/suite/innodb/r/innodb_bug59641.result @@ -16,6 +16,7 @@ UPDATE t SET b=4*a WHERE a=32; XA END '789'; XA PREPARE '789'; call mtr.add_suppression("Found 3 prepared XA transactions"); +FLUSH TABLES; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; SELECT * FROM t; a b diff --git a/mysql-test/suite/innodb/t/innodb_bug59641.test b/mysql-test/suite/innodb/t/innodb_bug59641.test index e19dec54bc2..22cd4e49753 100644 --- a/mysql-test/suite/innodb/t/innodb_bug59641.test +++ b/mysql-test/suite/innodb/t/innodb_bug59641.test @@ -33,7 +33,7 @@ XA PREPARE '789'; # The server would issue this warning on restart. call mtr.add_suppression("Found 3 prepared XA transactions"); - +FLUSH TABLES; # Kill the server without sending a shutdown command -- exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect -- shutdown_server 0 diff --git a/mysql-test/suite/innodb_plugin/r/innodb_bug59641.result b/mysql-test/suite/innodb_plugin/r/innodb_bug59641.result index 482df8914eb..de8bb61bd0d 100644 --- a/mysql-test/suite/innodb_plugin/r/innodb_bug59641.result +++ b/mysql-test/suite/innodb_plugin/r/innodb_bug59641.result @@ -16,6 +16,7 @@ UPDATE t SET b=4*a WHERE a=32; XA END '789'; XA PREPARE '789'; call mtr.add_suppression("Found 3 prepared XA transactions"); +FLUSH TABLES; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; SELECT * FROM t; a b diff --git a/mysql-test/suite/innodb_plugin/t/innodb_bug59641.test b/mysql-test/suite/innodb_plugin/t/innodb_bug59641.test index e2e893a0487..75a8fc235bf 100644 --- a/mysql-test/suite/innodb_plugin/t/innodb_bug59641.test +++ b/mysql-test/suite/innodb_plugin/t/innodb_bug59641.test @@ -33,7 +33,7 @@ XA PREPARE '789'; # The server would issue this warning on restart. call mtr.add_suppression("Found 3 prepared XA transactions"); - +FLUSH TABLES; # Kill the server without sending a shutdown command -- exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect -- shutdown_server 0 From cdde6187d1d2e7f407043f73376c266f540217d9 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Tue, 29 Nov 2011 15:27:52 +0400 Subject: [PATCH 133/288] bug 857066 Wrong result with ST_DISJOINT when using an index. DISJOINT can't be properly optimized with the RTree keys in MyISAM also. per-file comments: storage/myisam/rt_index.c bug 857066 Wrong result with ST_DISJOINT when using an index. don't optimize DISJOINT with the RTree keys. --- storage/myisam/rt_index.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/myisam/rt_index.c b/storage/myisam/rt_index.c index 6a825bab1fa..06d4ab9ccce 100644 --- a/storage/myisam/rt_index.c +++ b/storage/myisam/rt_index.c @@ -1028,7 +1028,7 @@ ha_rows rtree_estimate(MI_INFO *info, uint keynr, uchar *key, ha_rows res = 0; if (flag & MBR_DISJOINT) - return info->state->records; + return HA_POS_ERROR; if ((root = info->s->state.key_root[keynr]) == HA_OFFSET_ERROR) return HA_POS_ERROR; From c67a91f11afd730ab050e3c5da16411b95c325a7 Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Tue, 29 Nov 2011 17:59:35 +0530 Subject: [PATCH 134/288] Bug#11756764 48726: MYSQLD KEEPS CRASHING WITH SIGSEGV WITH MYISAM_USE_MMAP ENABLED MySQL server can crash due to segmentation fault when started with myisam_use_mmap. The reason behind this being, while making a request to unmap (munmap) the previously mapped memory (mmap), the size passed was 7 bytes larger than the size requested at the time of mapping. This can eventually unmap the adjacent memory mapped block, belonging to some other memory-map pool. Hence the subsequent call to mmap can map a region which was still a valid memory mapped area. Fixed by removing the extra 7-byte margin which was erroneously added to the size, used for unmappping. storage/myisam/mi_close.c: Bug#11756764 48726: MYSQLD KEEPS CRASHING WITH SIGSEGV WITH MYISAM_USE_MMAP ENABLED Added a condition to call _mi_unmap_file() in case of compressed records. mi_munmap_file() is called otherwise. storage/myisam/mi_packrec.c: Bug#11756764 48726: MYSQLD KEEPS CRASHING WITH SIGSEGV WITH MYISAM_USE_MMAP ENABLED mi_dynmap_file() function, after successfully executing mmap, stores the total size in info->s->mapped_length variable. Now, if mi_dynmap_file() is invoked with a size with an extra 7-byte margin (MEMMAP_EXTRA_MARGIN), the margin will eventually also get stored in mapped_length. So, un-mapping function can simply use the value stored in mapped_length in order to unmap the previously mapped region. --- storage/myisam/mi_close.c | 7 ++++++- storage/myisam/mi_packrec.c | 7 ++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/storage/myisam/mi_close.c b/storage/myisam/mi_close.c index bb95aff24d7..a6911814608 100644 --- a/storage/myisam/mi_close.c +++ b/storage/myisam/mi_close.c @@ -87,7 +87,12 @@ int mi_close(register MI_INFO *info) } #ifdef HAVE_MMAP if (share->file_map) - _mi_unmap_file(info); + { + if (share->options & HA_OPTION_COMPRESS_RECORD) + _mi_unmap_file(info); + else + mi_munmap_file(info); + } #endif if (share->decode_trees) { diff --git a/storage/myisam/mi_packrec.c b/storage/myisam/mi_packrec.c index e6ad4c3defc..005f8c65d71 100644 --- a/storage/myisam/mi_packrec.c +++ b/storage/myisam/mi_packrec.c @@ -1553,13 +1553,14 @@ my_bool _mi_memmap_file(MI_INFO *info) void _mi_unmap_file(MI_INFO *info) { - VOID(my_munmap((char*) info->s->file_map, - (size_t) info->s->mmaped_length + MEMMAP_EXTRA_MARGIN)); + DBUG_ASSERT(info->s->options & HA_OPTION_COMPRESS_RECORD); + + VOID(my_munmap((char*) info->s->file_map, (size_t) info->s->mmaped_length)); if (myisam_mmap_size != SIZE_T_MAX) { pthread_mutex_lock(&THR_LOCK_myisam_mmap); - myisam_mmap_used-= info->s->mmaped_length + MEMMAP_EXTRA_MARGIN; + myisam_mmap_used-= info->s->mmaped_length; pthread_mutex_unlock(&THR_LOCK_myisam_mmap); } } From a19f4e3a3af4c18ec89f8f8a4ae32e3c7d7fec70 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Tue, 29 Nov 2011 15:32:25 +0200 Subject: [PATCH 135/288] Fixed that maria-recover works as expected. - "" is now used if no option is set include/maria.h: Added HA_RECOVER_ANY storage/maria/ha_maria.cc: Insert of checking if maria_recover_options == 0, check if any bit is set. Fix maria_recover_names to match bitmap. This fixes that recover options works as expected. storage/maria/ha_maria.h: Insert of checking if maria_recover_options == 0, check if any bit is set. storage/maria/ma_check.c: Fixed wrong print --- include/maria.h | 2 ++ storage/maria/ha_maria.cc | 16 ++++++---------- storage/maria/ha_maria.h | 3 ++- storage/maria/ma_check.c | 2 +- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/include/maria.h b/include/maria.h index 1f054bce58d..192e5a565aa 100644 --- a/include/maria.h +++ b/include/maria.h @@ -335,6 +335,8 @@ extern int maria_begin(MARIA_HA *info); extern void maria_disable_logging(MARIA_HA *info); extern void maria_enable_logging(MARIA_HA *info); +#define HA_RECOVER_ANY (HA_RECOVER_DEFAULT | HA_RECOVER_BACKUP | HA_RECOVER_FORCE | HA_RECOVER_QUICK) + /* this is used to pass to mysql_mariachk_table */ #define MARIA_CHK_REPAIR 1 /* equivalent to mariachk -r */ diff --git a/storage/maria/ha_maria.cc b/storage/maria/ha_maria.cc index 4d1348bd07f..e02c8c5e2cd 100644 --- a/storage/maria/ha_maria.cc +++ b/storage/maria/ha_maria.cc @@ -70,10 +70,9 @@ const char *maria_recover_names[]= Compared to MyISAM, "default" was renamed to "normal" as it collided with SET var=default which sets to the var's default i.e. what happens when the var is not set i.e. HA_RECOVER_NONE. - Another change is that OFF is used to disable, not ""; this is to have OFF - display in SHOW VARIABLES which is better than "". + OFF flag is ignored. */ - "OFF", "NORMAL", "BACKUP", "FORCE", "QUICK", NullS + "NORMAL", "BACKUP", "FORCE", "QUICK", "OFF", NullS }; TYPELIB maria_recover_typelib= { @@ -200,8 +199,8 @@ static MYSQL_SYSVAR_ULONG(pagecache_division_limit, pagecache_division_limit, static MYSQL_SYSVAR_SET(recover, maria_recover_options, PLUGIN_VAR_OPCMDARG, "Specifies how corrupted tables should be automatically repaired." - " Possible values are \"NORMAL\" (the default), \"BACKUP\", \"FORCE\"," - " \"QUICK\", or \"OFF\" which is like not using the option.", + " Possible values are one or more of \"NORMAL\" (the default), " + "\"BACKUP\", \"FORCE\", or \"QUICK\".", NULL, NULL, HA_RECOVER_DEFAULT, &maria_recover_typelib); static MYSQL_THDVAR_ULONG(repair_threads, PLUGIN_VAR_RQCMDARG, @@ -966,7 +965,7 @@ int ha_maria::open(const char *name, int mode, uint test_if_locked) test_if_locked|= HA_OPEN_MMAP; #endif - if (unlikely(maria_recover_options != HA_RECOVER_NONE)) + if (maria_recover_options & HA_RECOVER_ANY) { /* user asked to trigger a repair if table was not properly closed */ test_if_locked|= HA_OPEN_ABORT_IF_CRASHED; @@ -1568,9 +1567,6 @@ int ha_maria::repair(THD *thd, HA_CHECK *param, bool do_optimize) _ma_check_print_warning(param, "Number of rows changed from %s to %s", llstr(rows, llbuff), llstr(file->state->records, llbuff2)); - /* Abort if warning was converted to error */ - if (table->in_use->is_error()) - error= 1; } } else @@ -3199,7 +3195,7 @@ static int mark_recovery_start(const char* log_dir) { int res; DBUG_ENTER("mark_recovery_start"); - if (unlikely(maria_recover_options == HA_RECOVER_NONE)) + if (!(maria_recover_options & HA_RECOVER_ANY)) ma_message_no_user(ME_JUST_WARNING, "Please consider using option" " --maria-recover[=...] to automatically check and" " repair tables when logs are removed by option" diff --git a/storage/maria/ha_maria.h b/storage/maria/ha_maria.h index f326efe17a2..47545b67ff3 100644 --- a/storage/maria/ha_maria.h +++ b/storage/maria/ha_maria.h @@ -142,7 +142,8 @@ public: bool check_and_repair(THD * thd); bool is_crashed() const; bool is_changed() const; - bool auto_repair() const { return maria_recover_options != HA_RECOVER_NONE; } + bool auto_repair() const + { return test(maria_recover_options & HA_RECOVER_ANY); } int optimize(THD * thd, HA_CHECK_OPT * check_opt); int restore(THD * thd, HA_CHECK_OPT * check_opt); int backup(THD * thd, HA_CHECK_OPT * check_opt); diff --git a/storage/maria/ma_check.c b/storage/maria/ma_check.c index 62299df9f7d..9f3c9059397 100644 --- a/storage/maria/ma_check.c +++ b/storage/maria/ma_check.c @@ -3884,7 +3884,7 @@ int maria_repair_by_sort(HA_CHECK *param, register MARIA_HA *info, _ma_check_print_error(param, "Rows lost (Found %lu of %lu); Aborting " "because safe repair was requested", - (ulong) share->state.state.records, + sort_info.new_info->s->state.state.records, (ulong) start_records); share->state.state.records=start_records; goto err; From 98adda50958504db0439ad6c72c96d663fb99bec Mon Sep 17 00:00:00 2001 From: Tor Didriksen Date: Tue, 29 Nov 2011 15:52:47 +0100 Subject: [PATCH 136/288] Build broken for gcc 4.5.1 in optimized mode. readline.cc: In function char* batch_readline(LINE_BUFFER*): readline.cc:60:9: error: out_length may be used uninitialized in this function log.cc: In function int find_uniq_filename(char*): log.cc:1857:8: error: number may be used uninitialized in this function --- client/readline.cc | 2 +- sql/log.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/readline.cc b/client/readline.cc index 0f3fab7e43d..7765a62766f 100644 --- a/client/readline.cc +++ b/client/readline.cc @@ -57,7 +57,7 @@ LINE_BUFFER *batch_readline_init(ulong max_size,FILE *file) char *batch_readline(LINE_BUFFER *line_buff) { char *pos; - ulong out_length; + ulong out_length= 0; if (!(pos=intern_read_line(line_buff, &out_length))) return 0; diff --git a/sql/log.cc b/sql/log.cc index 77d12641442..cca403ca1be 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1854,7 +1854,7 @@ static void setup_windows_event_source() static int find_uniq_filename(char *name) { - long number; + long number= 0; uint i; char buff[FN_REFLEN]; struct st_my_dir *dir_info; From 8d154f7a99e0b00cd37b9f92a5d2bf4cded25a10 Mon Sep 17 00:00:00 2001 From: Andrei Elkin Date: Tue, 29 Nov 2011 20:17:02 +0200 Subject: [PATCH 137/288] Bug#13437900 - VALGRIND REPORTS A LEAK FOR REPL_IGNORE_SERVER_IDS There was memory leak when running some tests on PB2. The reason of the failure is an early return from change_master() that was supposed to deallocate a dyn-array. Fixed with relocating the dyn-array's destructor at ~LEX() that is the end of the session, per Gleb's patch idea. Two optimizations were done: the static buffer for the dyn-array to base on, and the array initialization is called precisely when it's necessary rather than per each CHANGE-MASTER as before. mysql-test/suite/rpl/t/rpl_empty_master_host.test: the test is binlog-format insensitive so it will be run with MIXED mode only. sql/sql_lex.cc: the new flag is initialized. sql/sql_lex.h: A new bool flag new member to LEX.mi is added to stay UP since after LEX.mi.repl_ignore_server_ids dynarray initialization was called for the first time on the session. So it is set once and its life time is session. The array is destroyed at the end of the session. sql/sql_repl.cc: dyn-array destruction is relocated to ~LEX. sql/sql_yacc.yy: Refining logics of Lex->mi.repl_ignore_server_ids initialization. The array is initialized once a corresponding option in CHANGE MASTER token sequence is found. The fact of initialization is memorized into the new flag. --- .../suite/rpl/t/rpl_empty_master_host.test | 1 + sql/sql_lex.cc | 1 + sql/sql_lex.h | 7 +++++++ sql/sql_repl.cc | 1 - sql/sql_yacc.yy | 16 ++++++++++------ 5 files changed, 19 insertions(+), 7 deletions(-) diff --git a/mysql-test/suite/rpl/t/rpl_empty_master_host.test b/mysql-test/suite/rpl/t/rpl_empty_master_host.test index df0c85ad7ec..66d30375a59 100644 --- a/mysql-test/suite/rpl/t/rpl_empty_master_host.test +++ b/mysql-test/suite/rpl/t/rpl_empty_master_host.test @@ -17,6 +17,7 @@ # working when expected. --source include/master-slave.inc +--source include/have_binlog_format_mixed.inc connection slave; STOP SLAVE; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 869a5916339..00a67e2c134 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -2352,6 +2352,7 @@ LEX::LEX() INITIAL_LEX_PLUGIN_LIST_SIZE, INITIAL_LEX_PLUGIN_LIST_SIZE); reset_query_tables_list(TRUE); + repl_ignore_server_ids_inited= false; } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 542e8b42ae2..474fa87495b 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -291,7 +291,9 @@ typedef struct st_lex_master_info char *ssl_key, *ssl_cert, *ssl_ca, *ssl_capath, *ssl_cipher; char *relay_log_name; ulong relay_log_pos; + bool repl_ignore_server_ids_inited; DYNAMIC_ARRAY repl_ignore_server_ids; + typeof(::server_id) repl_ignore_server_ids_static_buffer[4]; } LEX_MASTER_INFO; typedef struct st_lex_reset_slave @@ -2455,6 +2457,11 @@ struct LEX: public Query_tables_list destroy_query_tables_list(); plugin_unlock_list(NULL, (plugin_ref *)plugins.buffer, plugins.elements); delete_dynamic(&plugins); + if (mi.repl_ignore_server_ids_inited) + { + delete_dynamic(&mi.repl_ignore_server_ids); + mi.repl_ignore_server_ids_inited= false; + } } inline bool is_ps_or_view_context_analysis() diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 00c85d8eb43..5300a327029 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -1689,7 +1689,6 @@ err: thd_proc_info(thd, 0); if (ret == FALSE) my_ok(thd); - delete_dynamic(&lex_mi->repl_ignore_server_ids); //freeing of parser-time alloc DBUG_RETURN(ret); } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 87c3ae5b129..209ec1ff0fc 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1863,12 +1863,7 @@ change: LEX *lex = Lex; lex->sql_command = SQLCOM_CHANGE_MASTER; bzero((char*) &lex->mi, sizeof(lex->mi)); - /* - resetting flags that can left from the previous CHANGE MASTER - */ lex->mi.repl_ignore_server_ids_opt= LEX_MASTER_INFO::LEX_MI_UNCHANGED; - my_init_dynamic_array(&Lex->mi.repl_ignore_server_ids, - sizeof(::server_id), 16, 16); } master_defs {} @@ -1965,7 +1960,7 @@ master_def: | IGNORE_SERVER_IDS_SYM EQ '(' ignore_server_id_list ')' { Lex->mi.repl_ignore_server_ids_opt= LEX_MASTER_INFO::LEX_MI_ENABLE; - } + } | master_file_def ; @@ -1979,6 +1974,15 @@ ignore_server_id_list: ignore_server_id: ulong_num { + if (!Lex->mi.repl_ignore_server_ids_inited) + { + my_init_dynamic_array2(&Lex->mi.repl_ignore_server_ids, + sizeof(::server_id), + Lex->mi.repl_ignore_server_ids_static_buffer, + array_elements(Lex->mi.repl_ignore_server_ids_static_buffer), + 16); + Lex->mi.repl_ignore_server_ids_inited= true; + } insert_dynamic(&Lex->mi.repl_ignore_server_ids, (uchar*) &($1)); } From 6a59acbad53402ab79dcc17910bc8de8af471f1b Mon Sep 17 00:00:00 2001 From: Andrei Elkin Date: Tue, 29 Nov 2011 22:30:04 +0200 Subject: [PATCH 138/288] reverting the initial patch for bug#13437900 for refinement. --- .../suite/rpl/t/rpl_empty_master_host.test | 1 - sql/slave.cc | 2 +- sql/sql_lex.cc | 1 - sql/sql_lex.h | 7 ------- sql/sql_repl.cc | 1 + sql/sql_yacc.yy | 16 ++++++---------- 6 files changed, 8 insertions(+), 20 deletions(-) diff --git a/mysql-test/suite/rpl/t/rpl_empty_master_host.test b/mysql-test/suite/rpl/t/rpl_empty_master_host.test index 66d30375a59..df0c85ad7ec 100644 --- a/mysql-test/suite/rpl/t/rpl_empty_master_host.test +++ b/mysql-test/suite/rpl/t/rpl_empty_master_host.test @@ -17,7 +17,6 @@ # working when expected. --source include/master-slave.inc ---source include/have_binlog_format_mixed.inc connection slave; STOP SLAVE; diff --git a/sql/slave.cc b/sql/slave.cc index 5c931a79695..797bd8e37e7 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1129,7 +1129,7 @@ int init_dynarray_intvar_from_file(DYNAMIC_ARRAY* arr, IO_CACHE* f) memcpy(buf_act, buf, read_size); snd_size= my_b_gets(f, buf_act + read_size, max_size - read_size); if (snd_size == 0 || - ((snd_size + 1 == max_size - read_size) && buf[max_size - 2] != '\n')) + ((snd_size + 1 == max_size - read_size) && buf_act[max_size - 2] != '\n')) { /* failure to make the 2nd read or short read again diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 00a67e2c134..869a5916339 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -2352,7 +2352,6 @@ LEX::LEX() INITIAL_LEX_PLUGIN_LIST_SIZE, INITIAL_LEX_PLUGIN_LIST_SIZE); reset_query_tables_list(TRUE); - repl_ignore_server_ids_inited= false; } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 474fa87495b..542e8b42ae2 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -291,9 +291,7 @@ typedef struct st_lex_master_info char *ssl_key, *ssl_cert, *ssl_ca, *ssl_capath, *ssl_cipher; char *relay_log_name; ulong relay_log_pos; - bool repl_ignore_server_ids_inited; DYNAMIC_ARRAY repl_ignore_server_ids; - typeof(::server_id) repl_ignore_server_ids_static_buffer[4]; } LEX_MASTER_INFO; typedef struct st_lex_reset_slave @@ -2457,11 +2455,6 @@ struct LEX: public Query_tables_list destroy_query_tables_list(); plugin_unlock_list(NULL, (plugin_ref *)plugins.buffer, plugins.elements); delete_dynamic(&plugins); - if (mi.repl_ignore_server_ids_inited) - { - delete_dynamic(&mi.repl_ignore_server_ids); - mi.repl_ignore_server_ids_inited= false; - } } inline bool is_ps_or_view_context_analysis() diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 5300a327029..00c85d8eb43 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -1689,6 +1689,7 @@ err: thd_proc_info(thd, 0); if (ret == FALSE) my_ok(thd); + delete_dynamic(&lex_mi->repl_ignore_server_ids); //freeing of parser-time alloc DBUG_RETURN(ret); } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 209ec1ff0fc..87c3ae5b129 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1863,7 +1863,12 @@ change: LEX *lex = Lex; lex->sql_command = SQLCOM_CHANGE_MASTER; bzero((char*) &lex->mi, sizeof(lex->mi)); + /* + resetting flags that can left from the previous CHANGE MASTER + */ lex->mi.repl_ignore_server_ids_opt= LEX_MASTER_INFO::LEX_MI_UNCHANGED; + my_init_dynamic_array(&Lex->mi.repl_ignore_server_ids, + sizeof(::server_id), 16, 16); } master_defs {} @@ -1960,7 +1965,7 @@ master_def: | IGNORE_SERVER_IDS_SYM EQ '(' ignore_server_id_list ')' { Lex->mi.repl_ignore_server_ids_opt= LEX_MASTER_INFO::LEX_MI_ENABLE; - } + } | master_file_def ; @@ -1974,15 +1979,6 @@ ignore_server_id_list: ignore_server_id: ulong_num { - if (!Lex->mi.repl_ignore_server_ids_inited) - { - my_init_dynamic_array2(&Lex->mi.repl_ignore_server_ids, - sizeof(::server_id), - Lex->mi.repl_ignore_server_ids_static_buffer, - array_elements(Lex->mi.repl_ignore_server_ids_static_buffer), - 16); - Lex->mi.repl_ignore_server_ids_inited= true; - } insert_dynamic(&Lex->mi.repl_ignore_server_ids, (uchar*) &($1)); } From 625cdb8078550d30399209d58edcb38cdfcc411d Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 29 Nov 2011 23:06:39 +0200 Subject: [PATCH 139/288] Fixed bug lp:825051 The cause of the wrong result was that Item_ref_null_helper::get_date() didn't use a method of the *_result() family, and fetched the data for the field from the current row instead of result_field. Changed to use the correct *_result() method, like to all other similar methods of Item_ref_null_helper. --- mysql-test/r/subselect.result | 26 +++++++++++++++++++++++ mysql-test/r/subselect_no_mat.result | 26 +++++++++++++++++++++++ mysql-test/r/subselect_no_opts.result | 26 +++++++++++++++++++++++ mysql-test/r/subselect_no_scache.result | 26 +++++++++++++++++++++++ mysql-test/r/subselect_no_semijoin.result | 26 +++++++++++++++++++++++ mysql-test/t/subselect.test | 16 ++++++++++++++ sql/item.cc | 2 +- 7 files changed, 147 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 87c5a3da69d..31ec50e5256 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -5827,5 +5827,31 @@ SELECT (SELECT f3a, f3a FROM t3 where f3a > 3) = (0, 0); (SELECT f3a, f3a FROM t3 where f3a > 3) = (0, 0) NULL drop tables t1,t2,t3; +# +# LP BUG#825051 Wrong result with date/datetime and subquery with GROUP BY and in_to_exists +# +CREATE TABLE t1 (a date, KEY (a)) ; +INSERT INTO t1 VALUES ('2009-01-01'),('2009-02-02'); +set @old_optimizer_switch = @@optimizer_switch; +SET @@optimizer_switch='semijoin=off,materialization=off,in_to_exists=on,subquery_cache=off'; +EXPLAIN SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 index NULL a 4 NULL 2 Using where; Using index +2 DEPENDENT SUBQUERY t1 index NULL a 4 NULL 1 Using index +SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1); +a +2009-01-01 +2009-02-02 +SET @@optimizer_switch='semijoin=off,materialization=on,in_to_exists=off,subquery_cache=off'; +EXPLAIN SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 index NULL a 4 NULL 2 Using where; Using index +2 SUBQUERY t1 index NULL a 4 NULL 2 Using index +SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1); +a +2009-01-01 +2009-02-02 +set @@optimizer_switch=@old_optimizer_switch; +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 a7625db5ff3..792d75f8d7c 100644 --- a/mysql-test/r/subselect_no_mat.result +++ b/mysql-test/r/subselect_no_mat.result @@ -5826,6 +5826,32 @@ SELECT (SELECT f3a, f3a FROM t3 where f3a > 3) = (0, 0); (SELECT f3a, f3a FROM t3 where f3a > 3) = (0, 0) NULL drop tables t1,t2,t3; +# +# LP BUG#825051 Wrong result with date/datetime and subquery with GROUP BY and in_to_exists +# +CREATE TABLE t1 (a date, KEY (a)) ; +INSERT INTO t1 VALUES ('2009-01-01'),('2009-02-02'); +set @old_optimizer_switch = @@optimizer_switch; +SET @@optimizer_switch='semijoin=off,materialization=off,in_to_exists=on,subquery_cache=off'; +EXPLAIN SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 index NULL a 4 NULL 2 Using where; Using index +2 DEPENDENT SUBQUERY t1 index NULL a 4 NULL 1 Using index +SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1); +a +2009-01-01 +2009-02-02 +SET @@optimizer_switch='semijoin=off,materialization=on,in_to_exists=off,subquery_cache=off'; +EXPLAIN SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 index NULL a 4 NULL 2 Using where; Using index +2 SUBQUERY t1 index NULL a 4 NULL 2 Using index +SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1); +a +2009-01-01 +2009-02-02 +set @@optimizer_switch=@old_optimizer_switch; +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 d7c67131970..73150de0a6f 100644 --- a/mysql-test/r/subselect_no_opts.result +++ b/mysql-test/r/subselect_no_opts.result @@ -5822,6 +5822,32 @@ SELECT (SELECT f3a, f3a FROM t3 where f3a > 3) = (0, 0); (SELECT f3a, f3a FROM t3 where f3a > 3) = (0, 0) NULL drop tables t1,t2,t3; +# +# LP BUG#825051 Wrong result with date/datetime and subquery with GROUP BY and in_to_exists +# +CREATE TABLE t1 (a date, KEY (a)) ; +INSERT INTO t1 VALUES ('2009-01-01'),('2009-02-02'); +set @old_optimizer_switch = @@optimizer_switch; +SET @@optimizer_switch='semijoin=off,materialization=off,in_to_exists=on,subquery_cache=off'; +EXPLAIN SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 index NULL a 4 NULL 2 Using where; Using index +2 DEPENDENT SUBQUERY t1 index NULL a 4 NULL 1 Using index +SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1); +a +2009-01-01 +2009-02-02 +SET @@optimizer_switch='semijoin=off,materialization=on,in_to_exists=off,subquery_cache=off'; +EXPLAIN SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 index NULL a 4 NULL 2 Using where; Using index +2 SUBQUERY t1 index NULL a 4 NULL 2 Using index +SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1); +a +2009-01-01 +2009-02-02 +set @@optimizer_switch=@old_optimizer_switch; +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 ef1b268f5ba..3a35d64681a 100644 --- a/mysql-test/r/subselect_no_scache.result +++ b/mysql-test/r/subselect_no_scache.result @@ -5831,6 +5831,32 @@ SELECT (SELECT f3a, f3a FROM t3 where f3a > 3) = (0, 0); (SELECT f3a, f3a FROM t3 where f3a > 3) = (0, 0) NULL drop tables t1,t2,t3; +# +# LP BUG#825051 Wrong result with date/datetime and subquery with GROUP BY and in_to_exists +# +CREATE TABLE t1 (a date, KEY (a)) ; +INSERT INTO t1 VALUES ('2009-01-01'),('2009-02-02'); +set @old_optimizer_switch = @@optimizer_switch; +SET @@optimizer_switch='semijoin=off,materialization=off,in_to_exists=on,subquery_cache=off'; +EXPLAIN SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 index NULL a 4 NULL 2 Using where; Using index +2 DEPENDENT SUBQUERY t1 index NULL a 4 NULL 1 Using index +SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1); +a +2009-01-01 +2009-02-02 +SET @@optimizer_switch='semijoin=off,materialization=on,in_to_exists=off,subquery_cache=off'; +EXPLAIN SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 index NULL a 4 NULL 2 Using where; Using index +2 SUBQUERY t1 index NULL a 4 NULL 2 Using index +SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1); +a +2009-01-01 +2009-02-02 +set @@optimizer_switch=@old_optimizer_switch; +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 9f50a975b84..4e7abbd5702 100644 --- a/mysql-test/r/subselect_no_semijoin.result +++ b/mysql-test/r/subselect_no_semijoin.result @@ -5822,6 +5822,32 @@ SELECT (SELECT f3a, f3a FROM t3 where f3a > 3) = (0, 0); (SELECT f3a, f3a FROM t3 where f3a > 3) = (0, 0) NULL drop tables t1,t2,t3; +# +# LP BUG#825051 Wrong result with date/datetime and subquery with GROUP BY and in_to_exists +# +CREATE TABLE t1 (a date, KEY (a)) ; +INSERT INTO t1 VALUES ('2009-01-01'),('2009-02-02'); +set @old_optimizer_switch = @@optimizer_switch; +SET @@optimizer_switch='semijoin=off,materialization=off,in_to_exists=on,subquery_cache=off'; +EXPLAIN SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 index NULL a 4 NULL 2 Using where; Using index +2 DEPENDENT SUBQUERY t1 index NULL a 4 NULL 1 Using index +SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1); +a +2009-01-01 +2009-02-02 +SET @@optimizer_switch='semijoin=off,materialization=on,in_to_exists=off,subquery_cache=off'; +EXPLAIN SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 index NULL a 4 NULL 2 Using where; Using index +2 SUBQUERY t1 index NULL a 4 NULL 2 Using index +SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1); +a +2009-01-01 +2009-02-02 +set @@optimizer_switch=@old_optimizer_switch; +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 92df79d7777..aac06e349b5 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -4898,5 +4898,21 @@ SELECT (SELECT f3a, f3a FROM t3 where f3a > 3) = (0, 0); drop tables t1,t2,t3; +--echo # +--echo # LP BUG#825051 Wrong result with date/datetime and subquery with GROUP BY and in_to_exists +--echo # + +CREATE TABLE t1 (a date, KEY (a)) ; +INSERT INTO t1 VALUES ('2009-01-01'),('2009-02-02'); +set @old_optimizer_switch = @@optimizer_switch; +SET @@optimizer_switch='semijoin=off,materialization=off,in_to_exists=on,subquery_cache=off'; +EXPLAIN SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1); +SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1); +SET @@optimizer_switch='semijoin=off,materialization=on,in_to_exists=off,subquery_cache=off'; +EXPLAIN SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1); +SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1); +set @@optimizer_switch=@old_optimizer_switch; +drop table t1; + --echo # return optimizer switch changed in the beginning of this test set optimizer_switch=@subselect_tmp; diff --git a/sql/item.cc b/sql/item.cc index 9ba93780334..b0cd5b1388a 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -3864,7 +3864,7 @@ String* Item_ref_null_helper::val_str(String* s) bool Item_ref_null_helper::get_date(MYSQL_TIME *ltime, uint fuzzydate) { - return (owner->was_null|= null_value= (*ref)->get_date(ltime, fuzzydate)); + return (owner->was_null|= null_value= (*ref)->get_date_result(ltime, fuzzydate)); } From 264aaf111d0493f0472e704ad7dda426f81376ea Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 29 Nov 2011 23:09:06 +0200 Subject: [PATCH 140/288] Added test suite for the LP BUG#885162 (fixed by the patch for LP BUG#859375 and LP BUG#887458). --- mysql-test/r/subselect.result | 15 +++++++++++++++ mysql-test/r/subselect_no_mat.result | 15 +++++++++++++++ mysql-test/r/subselect_no_opts.result | 15 +++++++++++++++ mysql-test/r/subselect_no_scache.result | 15 +++++++++++++++ mysql-test/r/subselect_no_semijoin.result | 15 +++++++++++++++ mysql-test/t/subselect.test | 18 ++++++++++++++++++ 6 files changed, 93 insertions(+) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 87c5a3da69d..e49baeadcb0 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -5748,6 +5748,21 @@ b a b set @@join_cache_level= @save_join_cache_level; drop table t1,t2; # +# LP bug #885162 Got error 124 from storage engine with UNION inside +# subquery and join_cache_level=3..8 +# (IN/ALL/ANY optimizations should not be applied to fake_select) +# +CREATE TABLE t1 ( +f1 varchar(1) DEFAULT NULL +); +INSERT INTO t1 VALUES ('c'); +set @save_join_cache_level=@@join_cache_level; +SET SESSION join_cache_level=8; +SELECT * FROM t1 WHERE t1.f1 IN ( SELECT 'k' UNION SELECT 'e' ); +f1 +set @@join_cache_level= @save_join_cache_level; +drop table t1; +# # LP BUG#747278 incorrect values of the NULL (no rows) single # row subquery requested via element_index() interface # diff --git a/mysql-test/r/subselect_no_mat.result b/mysql-test/r/subselect_no_mat.result index a7625db5ff3..d315a16d2ce 100644 --- a/mysql-test/r/subselect_no_mat.result +++ b/mysql-test/r/subselect_no_mat.result @@ -5747,6 +5747,21 @@ b a b set @@join_cache_level= @save_join_cache_level; drop table t1,t2; # +# LP bug #885162 Got error 124 from storage engine with UNION inside +# subquery and join_cache_level=3..8 +# (IN/ALL/ANY optimizations should not be applied to fake_select) +# +CREATE TABLE t1 ( +f1 varchar(1) DEFAULT NULL +); +INSERT INTO t1 VALUES ('c'); +set @save_join_cache_level=@@join_cache_level; +SET SESSION join_cache_level=8; +SELECT * FROM t1 WHERE t1.f1 IN ( SELECT 'k' UNION SELECT 'e' ); +f1 +set @@join_cache_level= @save_join_cache_level; +drop table t1; +# # LP BUG#747278 incorrect values of the NULL (no rows) single # row subquery requested via element_index() interface # diff --git a/mysql-test/r/subselect_no_opts.result b/mysql-test/r/subselect_no_opts.result index d7c67131970..d6212c756cf 100644 --- a/mysql-test/r/subselect_no_opts.result +++ b/mysql-test/r/subselect_no_opts.result @@ -5743,6 +5743,21 @@ b a b set @@join_cache_level= @save_join_cache_level; drop table t1,t2; # +# LP bug #885162 Got error 124 from storage engine with UNION inside +# subquery and join_cache_level=3..8 +# (IN/ALL/ANY optimizations should not be applied to fake_select) +# +CREATE TABLE t1 ( +f1 varchar(1) DEFAULT NULL +); +INSERT INTO t1 VALUES ('c'); +set @save_join_cache_level=@@join_cache_level; +SET SESSION join_cache_level=8; +SELECT * FROM t1 WHERE t1.f1 IN ( SELECT 'k' UNION SELECT 'e' ); +f1 +set @@join_cache_level= @save_join_cache_level; +drop table t1; +# # LP BUG#747278 incorrect values of the NULL (no rows) single # row subquery requested via element_index() interface # diff --git a/mysql-test/r/subselect_no_scache.result b/mysql-test/r/subselect_no_scache.result index ef1b268f5ba..e1e0317c815 100644 --- a/mysql-test/r/subselect_no_scache.result +++ b/mysql-test/r/subselect_no_scache.result @@ -5752,6 +5752,21 @@ b a b set @@join_cache_level= @save_join_cache_level; drop table t1,t2; # +# LP bug #885162 Got error 124 from storage engine with UNION inside +# subquery and join_cache_level=3..8 +# (IN/ALL/ANY optimizations should not be applied to fake_select) +# +CREATE TABLE t1 ( +f1 varchar(1) DEFAULT NULL +); +INSERT INTO t1 VALUES ('c'); +set @save_join_cache_level=@@join_cache_level; +SET SESSION join_cache_level=8; +SELECT * FROM t1 WHERE t1.f1 IN ( SELECT 'k' UNION SELECT 'e' ); +f1 +set @@join_cache_level= @save_join_cache_level; +drop table t1; +# # LP BUG#747278 incorrect values of the NULL (no rows) single # row subquery requested via element_index() interface # diff --git a/mysql-test/r/subselect_no_semijoin.result b/mysql-test/r/subselect_no_semijoin.result index 9f50a975b84..6438f06e179 100644 --- a/mysql-test/r/subselect_no_semijoin.result +++ b/mysql-test/r/subselect_no_semijoin.result @@ -5743,6 +5743,21 @@ b a b set @@join_cache_level= @save_join_cache_level; drop table t1,t2; # +# LP bug #885162 Got error 124 from storage engine with UNION inside +# subquery and join_cache_level=3..8 +# (IN/ALL/ANY optimizations should not be applied to fake_select) +# +CREATE TABLE t1 ( +f1 varchar(1) DEFAULT NULL +); +INSERT INTO t1 VALUES ('c'); +set @save_join_cache_level=@@join_cache_level; +SET SESSION join_cache_level=8; +SELECT * FROM t1 WHERE t1.f1 IN ( SELECT 'k' UNION SELECT 'e' ); +f1 +set @@join_cache_level= @save_join_cache_level; +drop table t1; +# # LP BUG#747278 incorrect values of the NULL (no rows) single # row subquery requested via element_index() interface # diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 92df79d7777..26ba75a6f46 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -4855,6 +4855,24 @@ WHERE t2.b IN ( set @@join_cache_level= @save_join_cache_level; drop table t1,t2; + +--echo # +--echo # LP bug #885162 Got error 124 from storage engine with UNION inside +--echo # subquery and join_cache_level=3..8 +--echo # (IN/ALL/ANY optimizations should not be applied to fake_select) +--echo # + +CREATE TABLE t1 ( + f1 varchar(1) DEFAULT NULL + ); +INSERT INTO t1 VALUES ('c'); +set @save_join_cache_level=@@join_cache_level; +SET SESSION join_cache_level=8; +SELECT * FROM t1 WHERE t1.f1 IN ( SELECT 'k' UNION SELECT 'e' ); +set @@join_cache_level= @save_join_cache_level; +drop table t1; + + --echo # --echo # LP BUG#747278 incorrect values of the NULL (no rows) single --echo # row subquery requested via element_index() interface From 47575bd0e05d49955a4d7f46409cc6316fed8d7c Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Wed, 30 Nov 2011 00:34:05 +0200 Subject: [PATCH 141/288] Fixed compiler warnings dbug/tests.c: Added __attribute__((unused)) to get rid of compiler warning server-tools/instance-manager/guardian.cc: Added __attribute__((unused)) to get rid of compiler warning sql/filesort.cc: Added __attribute__((unused)) to get rid of compiler warning sql/slave.cc: Added __attribute__((unused)) to get rid of compiler warning sql/sql_load.cc: Added __attribute__((unused)) to get rid of compiler warning sql/sql_table.cc: Added __attribute__((unused)) to get rid of compiler warning storage/maria/ma_blockrec.c: Added __attribute__((unused)) to get rid of compiler warning storage/maria/ma_check.c: Added missing cast storage/maria/ma_loghandler.c: Added __attribute__((unused)) to get rid of compiler warning storage/maria/ma_recovery.c: Added __attribute__((unused)) to get rid of compiler warning storage/pbxt/src/cache_xt.cc: Added __attribute__((unused)) to get rid of compiler warning storage/xtradb/fil/fil0fil.c: Removed not used variable storage/xtradb/handler/ha_innodb.cc: Use unused variable vio/viosocket.c: Remove usage of not used variable vio/viosslfactories.c: Added cast --- dbug/tests.c | 2 +- server-tools/instance-manager/guardian.cc | 2 +- sql/filesort.cc | 2 +- sql/slave.cc | 2 +- sql/sql_load.cc | 2 +- sql/sql_table.cc | 2 +- storage/maria/ma_blockrec.c | 2 +- storage/maria/ma_check.c | 3 ++- storage/maria/ma_loghandler.c | 2 +- storage/maria/ma_recovery.c | 2 +- storage/pbxt/src/cache_xt.cc | 2 +- storage/xtradb/fil/fil0fil.c | 2 -- storage/xtradb/handler/ha_innodb.cc | 2 +- vio/viosocket.c | 12 ++++++++---- vio/viosslfactories.c | 6 ++++-- 15 files changed, 25 insertions(+), 20 deletions(-) diff --git a/dbug/tests.c b/dbug/tests.c index d76266d34a3..e1d416d6c43 100644 --- a/dbug/tests.c +++ b/dbug/tests.c @@ -16,7 +16,7 @@ const char *func3() void func2() { - const char *s; + const char *s __attribute__((unused)); DBUG_ENTER("func2"); s=func3(); DBUG_PRINT("info", ("s=%s", s)); diff --git a/server-tools/instance-manager/guardian.cc b/server-tools/instance-manager/guardian.cc index b49b0ec0a00..1df602534e0 100644 --- a/server-tools/instance-manager/guardian.cc +++ b/server-tools/instance-manager/guardian.cc @@ -440,7 +440,7 @@ void Guardian::stop_instances() /* Request mysqld to stop. */ - bool instance_stopped= FALSE; + bool instance_stopped __attribute__((unused))= FALSE; for (int cur_attempt= 0; cur_attempt < NUM_STOP_ATTEMPTS; ++cur_attempt) { diff --git a/sql/filesort.cc b/sql/filesort.cc index e95ff08fcdd..54b41531cdd 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -827,7 +827,7 @@ static void make_sortkey(register SORTPARAM *param, if (sort_field->need_strxnfrm) { char *from=(char*) res->ptr(); - uint tmp_length; + uint tmp_length __attribute__((unused)); if ((uchar*) from == to) { set_if_smaller(length,sort_field->length); diff --git a/sql/slave.cc b/sql/slave.cc index d779d8cdc9e..1971001d759 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -513,7 +513,7 @@ terminate_slave_thread(THD *thd, while (*slave_running) // Should always be true { - int error; + int error __attribute__((unused)); DBUG_PRINT("loop", ("killing slave thread")); pthread_mutex_lock(&thd->LOCK_thd_data); diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 23105d84a9d..42e4489cb07 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -140,7 +140,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, */ char *tdb= thd->db ? thd->db : db; // Result is never null ulong skip_lines= ex->skip_lines; - bool transactional_table; + bool transactional_table __attribute__((unused)); DBUG_ENTER("mysql_load"); /* diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 7328157182d..465404d32d2 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -6619,7 +6619,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, uint fast_alter_partition= 0; bool partition_changed= FALSE; #endif - bool need_lock_for_indexes= TRUE; + bool need_lock_for_indexes __attribute__((unused)) = TRUE; KEY *key_info_buffer; uint index_drop_count= 0; uint *index_drop_buffer= NULL; diff --git a/storage/maria/ma_blockrec.c b/storage/maria/ma_blockrec.c index c7c1a131441..71bbb389ca2 100644 --- a/storage/maria/ma_blockrec.c +++ b/storage/maria/ma_blockrec.c @@ -3676,7 +3676,7 @@ static my_bool _ma_update_block_record2(MARIA_HA *info, MARIA_PINNED_PAGE page_link; uint rownr, org_empty_size, head_length; uint block_size= info->s->block_size; - uint errpos= 0; + uint errpos __attribute__((unused)) = 0; uchar *dir; pgcache_page_no_t page; struct st_row_pos_info row_pos; diff --git a/storage/maria/ma_check.c b/storage/maria/ma_check.c index 9f3c9059397..9ce8e42cae0 100644 --- a/storage/maria/ma_check.c +++ b/storage/maria/ma_check.c @@ -3884,7 +3884,8 @@ int maria_repair_by_sort(HA_CHECK *param, register MARIA_HA *info, _ma_check_print_error(param, "Rows lost (Found %lu of %lu); Aborting " "because safe repair was requested", - sort_info.new_info->s->state.state.records, + (ulong) sort_info.new_info->s-> + state.state.records, (ulong) start_records); share->state.state.records=start_records; goto err; diff --git a/storage/maria/ma_loghandler.c b/storage/maria/ma_loghandler.c index ce7253d4c39..709bcd26e6a 100644 --- a/storage/maria/ma_loghandler.c +++ b/storage/maria/ma_loghandler.c @@ -3201,7 +3201,7 @@ static uint16 translog_get_chunk_header_length(uchar *chunk) case TRANSLOG_CHUNK_LSN: { /* 0 chunk referred as LSN (head or tail) */ - translog_size_t rec_len; + translog_size_t rec_len __attribute__((unused)); uchar *start= chunk; uchar *ptr= start + 1 + 2; uint16 chunk_len, header_len; diff --git a/storage/maria/ma_recovery.c b/storage/maria/ma_recovery.c index 73ecb208662..ccd9af612be 100644 --- a/storage/maria/ma_recovery.c +++ b/storage/maria/ma_recovery.c @@ -2884,7 +2884,7 @@ static uint end_of_redo_phase(my_bool prepare_for_undo_phase) static int run_undo_phase(uint uncommitted) { - LSN last_undo; + LSN last_undo __attribute__((unused)); DBUG_ENTER("run_undo_phase"); if (uncommitted > 0) diff --git a/storage/pbxt/src/cache_xt.cc b/storage/pbxt/src/cache_xt.cc index 24e42d9e984..f4a2c4a4fde 100644 --- a/storage/pbxt/src/cache_xt.cc +++ b/storage/pbxt/src/cache_xt.cc @@ -789,7 +789,7 @@ xtPublic void xt_ind_check_cache(XTIndexPtr ind) ASSERT_NS(ind_cac_globals.cg_free_count == free_count); /* Check the LRU list: */ - XTIndBlockPtr list_block, plist_block; + XTIndBlockPtr list_block, plist_block __attribute__((unused)); plist_block = NULL; list_block = ind_cac_globals.cg_lru_block; diff --git a/storage/xtradb/fil/fil0fil.c b/storage/xtradb/fil/fil0fil.c index 1ef0a9a46fb..bcf134f4292 100644 --- a/storage/xtradb/fil/fil0fil.c +++ b/storage/xtradb/fil/fil0fil.c @@ -3678,7 +3678,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; @@ -3717,7 +3716,6 @@ func_exit: if (height == ULINT_UNDEFINED) { height = btr_page_get_level(page, &mtr); - root_height = height; } if (height == 0) { diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index 744865a31f3..e865172a0f7 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -10801,7 +10801,7 @@ ha_innobase::check_if_incompatible_data( if (info_row_type == ROW_TYPE_DEFAULT) info_row_type = ROW_TYPE_COMPACT; if ((info->used_fields & HA_CREATE_USED_ROW_FORMAT) && - get_row_type() != ((info->row_type == ROW_TYPE_DEFAULT) + row_type != ((info->row_type == ROW_TYPE_DEFAULT) ? ROW_TYPE_COMPACT : info->row_type)) { DBUG_PRINT("info", ("get_row_type()=%d != info->row_type=%d -> " diff --git a/vio/viosocket.c b/vio/viosocket.c index 381d028d6a0..f3799351de9 100644 --- a/vio/viosocket.c +++ b/vio/viosocket.c @@ -391,7 +391,9 @@ my_bool vio_poll_read(Vio *vio,uint timeout) void vio_timeout(Vio *vio, uint which, uint timeout) { #if defined(SO_SNDTIMEO) && defined(SO_RCVTIMEO) +#ifndef DBUG_OFF int r; +#endif DBUG_ENTER("vio_timeout"); { @@ -405,10 +407,12 @@ void vio_timeout(Vio *vio, uint which, uint timeout) wait_timeout.tv_usec= 0; #endif - r= setsockopt(vio->sd, SOL_SOCKET, which ? SO_SNDTIMEO : SO_RCVTIMEO, - IF_WIN(const char*, const void*)&wait_timeout, - sizeof(wait_timeout)); - +#ifndef DBUG_OFF + r= +#endif + setsockopt(vio->sd, SOL_SOCKET, which ? SO_SNDTIMEO : SO_RCVTIMEO, + IF_WIN(const char*, const void*)&wait_timeout, + sizeof(wait_timeout)); } #ifndef DBUG_OFF diff --git a/vio/viosslfactories.c b/vio/viosslfactories.c index 3c0c2f3a7ec..31863a0830f 100644 --- a/vio/viosslfactories.c +++ b/vio/viosslfactories.c @@ -300,7 +300,8 @@ new_VioSSLConnectorFd(const char *key_file, const char *cert_file, verify= SSL_VERIFY_NONE; if (!(ssl_fd= new_VioSSLFd(key_file, cert_file, ca_file, - ca_path, cipher, TLSv1_client_method(), &dummy))) + ca_path, cipher, + (SSL_METHOD*) TLSv1_client_method(), &dummy))) { return 0; } @@ -322,7 +323,8 @@ new_VioSSLAcceptorFd(const char *key_file, const char *cert_file, struct st_VioSSLFd *ssl_fd; int verify= SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE; if (!(ssl_fd= new_VioSSLFd(key_file, cert_file, ca_file, - ca_path, cipher, TLSv1_server_method(), error))) + ca_path, cipher, + (SSL_METHOD*) TLSv1_server_method(), error))) { return 0; } From be505e3ebf843f462173080d6cd0b6e0f5fb6be9 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 30 Nov 2011 13:53:25 +0100 Subject: [PATCH 142/288] Cherrypick into XtraDB: Bug#13002783 PARTIALLY UNINITIALIZED CASCADE UPDATE VECTOR We merged the test case for this into MariaDB 5.1, but the fix was not yet part of XtraDB. --- storage/xtradb/ChangeLog | 5 +++++ storage/xtradb/handler/ha_innodb.cc | 9 +++++---- storage/xtradb/row/row0ins.c | 17 ++++++++++------- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/storage/xtradb/ChangeLog b/storage/xtradb/ChangeLog index f873f3a24bd..7a4cacb5b43 100644 --- a/storage/xtradb/ChangeLog +++ b/storage/xtradb/ChangeLog @@ -1,3 +1,8 @@ +2011-10-25 The InnoDB Team + + * handler/ha_innodb.cc, row/row0ins.c: + Fix Bug#13002783 PARTIALLY UNINITIALIZED CASCADE UPDATE VECTOR + 2011-08-08 The InnoDB Team * row/row0sel.c: diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index e865172a0f7..4f4db23d06c 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -5360,14 +5360,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, @@ -5375,7 +5376,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); } diff --git a/storage/xtradb/row/row0ins.c b/storage/xtradb/row/row0ins.c index 0e62185c02e..0bcbc14fbf6 100644 --- a/storage/xtradb/row/row0ins.c +++ b/storage/xtradb/row/row0ins.c @@ -434,11 +434,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; @@ -474,13 +472,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); @@ -493,6 +493,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; @@ -993,10 +995,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 */ @@ -1005,6 +1006,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]; From ca5b1b54312cf9bc4a8252134874d82cf394eb48 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 30 Nov 2011 11:37:28 +0100 Subject: [PATCH 143/288] test both federated and federatedX in the federated suite. mysql-test/lib/My/Options.pm: My::Options::is_set() now matches both option names and values! mysql-test/lib/mtr_cases.pm: 1. don't merge --plugin-load here, it's too early 2. don't skip combinations that set --plugin-load just because the test needs another --plugin-load. Skip *only* if test's --plugin-load matches *exactly* --plugin-load of one of the combinations. 3. if skipping all combinations but one, still assign the test to the combination mysql-test/mysql-test-run.pl: 1. remove dead code - don't set variables that aren't used. 2. bugfix: allow one-letter combination names 3. in the command line, merge all --plugin-load options in one storage/federated/ha_federated.cc: bugfix: garbage character in the generated SELECT query --- mysql-test/include/have_federated_plugin.inc | 5 -- mysql-test/lib/My/Options.pm | 2 +- mysql-test/lib/mtr_cases.pm | 57 +++++------- mysql-test/mysql-test-run.pl | 88 +++---------------- mysql-test/suite/federated/combinations | 8 ++ mysql-test/suite/federated/federated.inc | 1 - .../suite/federated/federated_partition.test | 1 + .../federated/federated_plugin-master.opt | 2 - .../suite/federated/federated_plugin.result | 19 ---- .../suite/federated/federated_plugin.test | 37 -------- .../suite/federated/federated_server.result | 2 +- .../suite/federated/federated_server.test | 2 +- .../federated/federated_transactions.test | 1 + .../{federated.result => federatedx.result} | 0 .../{federated.test => federatedx.test} | 1 + .../suite/federated/have_federated_db.inc | 6 -- .../suite/federated/have_federatedx.inc | 5 ++ .../{suite.opt => have_federatedx.opt} | 1 - mysql-test/suite/federated/suite.pm | 20 +++++ storage/federated/ha_federated.cc | 2 +- 20 files changed, 75 insertions(+), 185 deletions(-) delete mode 100644 mysql-test/include/have_federated_plugin.inc create mode 100644 mysql-test/suite/federated/combinations delete mode 100644 mysql-test/suite/federated/federated_plugin-master.opt delete mode 100644 mysql-test/suite/federated/federated_plugin.result delete mode 100644 mysql-test/suite/federated/federated_plugin.test rename mysql-test/suite/federated/{federated.result => federatedx.result} (100%) rename mysql-test/suite/federated/{federated.test => federatedx.test} (99%) delete mode 100644 mysql-test/suite/federated/have_federated_db.inc create mode 100644 mysql-test/suite/federated/have_federatedx.inc rename mysql-test/suite/federated/{suite.opt => have_federatedx.opt} (72%) create mode 100644 mysql-test/suite/federated/suite.pm diff --git a/mysql-test/include/have_federated_plugin.inc b/mysql-test/include/have_federated_plugin.inc deleted file mode 100644 index 5c7549de53f..00000000000 --- a/mysql-test/include/have_federated_plugin.inc +++ /dev/null @@ -1,5 +0,0 @@ -if (`select plugin_library IS NULL from information_schema.plugins where plugin_name LIKE '%federated%'`) -{ - --skip federated plugin not available -} - diff --git a/mysql-test/lib/My/Options.pm b/mysql-test/lib/My/Options.pm index 6e8cf7ec919..a0713f7c07e 100644 --- a/mysql-test/lib/My/Options.pm +++ b/mysql-test/lib/My/Options.pm @@ -153,7 +153,7 @@ sub is_set { foreach my $set_opt (@$set_opts){ my ($opt_name2, $value2)= _split_option($set_opt); - if ($opt_name1 eq $opt_name2){ + if ($opt_name1 eq $opt_name2 and $value1 eq $value2){ # Option already set return 1; } diff --git a/mysql-test/lib/mtr_cases.pm b/mysql-test/lib/mtr_cases.pm index e311a9bc3ba..727e56ac77a 100644 --- a/mysql-test/lib/mtr_cases.pm +++ b/mysql-test/lib/mtr_cases.pm @@ -491,20 +491,32 @@ sub collect_one_suite #print_testcases(@cases); my @new_cases; - foreach my $comb (@combinations) + TEST: foreach my $test (@cases) { - foreach my $test (@cases) - { + if ( $test->{'skip'} ) + { + push(@new_cases, $test); + next; + } - next if ( $test->{'skip'} ); - - # Skip this combination if the values it provides - # already are set in master_opt or slave_opt + foreach my $comb (@combinations) + { + # Skip all other combinations if the values they change + # are already fixed in master_opt or slave_opt if (My::Options::is_set($test->{master_opt}, $comb->{comb_opt}) && My::Options::is_set($test->{slave_opt}, $comb->{comb_opt}) ){ - next; - } + # Add combination name short name + $test->{combination}= $comb->{name}; + + # Add the test to new test cases list + push(@new_cases, $test); + next TEST; + } + } + + foreach my $comb (@combinations) + { # Copy test options my $new_test= My::Test->new(); while (my ($key, $value) = each(%$test)) { @@ -527,17 +539,6 @@ sub collect_one_suite } } - # Add the plain test if it was not already added - # as part of a combination - my %added; - foreach my $new_test (@new_cases){ - $added{$new_test->{name}}= 1; - } - foreach my $test (@cases){ - push(@new_cases, $test) unless $added{$test->{name}}; - } - - #print_testcases(@new_cases); @cases= @new_cases; #print_testcases(@cases); @@ -661,9 +662,6 @@ sub process_opts { my @opts= @{$tinfo->{$opt_name}}; $tinfo->{$opt_name} = []; - my @plugins; - my %seen; - foreach my $opt (@opts) { my $value; @@ -679,14 +677,6 @@ sub process_opts { next; } - $value= mtr_match_prefix($opt, "--plugin-load="); - if (defined $value) - { - push @plugins, $value unless $seen{$value}; - $seen{$value}=1; - next; - } - $value= mtr_match_prefix($opt, "--result-file="); if ( defined $value ) { @@ -733,11 +723,6 @@ sub process_opts { # Ok, this was a real option, add it push(@{$tinfo->{$opt_name}}, $opt); } - - if (@plugins) { - my $sep = (IS_WINDOWS) ? ';' : ':'; - push @{$tinfo->{$opt_name}}, "--plugin-load=" . join($sep, @plugins); - } } diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 1c9d3b5159f..b2c7ee2fc37 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -2096,79 +2096,6 @@ sub environment_setup { push(@ld_library_paths, "$basedir/storage/ndb/src/.libs"); } - # -------------------------------------------------------------------------- - # Add the path where mysqld will find udf_example.so - # -------------------------------------------------------------------------- - my $lib_udf_example= - mtr_file_exists(vs_config_dirs('sql', 'udf_example.dll'), - "$basedir/sql/.libs/udf_example.so",); - - if ( $lib_udf_example ) - { - push(@ld_library_paths, dirname($lib_udf_example)); - } - - $ENV{'UDF_EXAMPLE_LIB'}= - ($lib_udf_example ? basename($lib_udf_example) : ""); - $ENV{'UDF_EXAMPLE_LIB_OPT'}= "--plugin-dir=". - ($lib_udf_example ? dirname($lib_udf_example) : ""); - - # -------------------------------------------------------------------------- - # Add the path where mysqld will find ha_example.so - # -------------------------------------------------------------------------- - if ($mysql_version_id >= 50100) { - my $plugin_filename; - if (IS_WINDOWS) - { - $plugin_filename = "ha_example.dll"; - } - else - { - $plugin_filename = "ha_example.so"; - } - my $lib_example_plugin= - mtr_file_exists(vs_config_dirs('storage/example',$plugin_filename), - "$basedir/storage/example/.libs/".$plugin_filename, - "$basedir/lib/mysql/plugin/".$plugin_filename); - $ENV{'EXAMPLE_PLUGIN'}= - ($lib_example_plugin ? basename($lib_example_plugin) : ""); - $ENV{'EXAMPLE_PLUGIN_OPT'}= "--plugin-dir=". - ($lib_example_plugin ? dirname($lib_example_plugin) : ""); - - $ENV{'HA_EXAMPLE_SO'}="'".$plugin_filename."'"; - $ENV{'EXAMPLE_PLUGIN_LOAD'}="--plugin_load=EXAMPLE=".$plugin_filename; - } - - # -------------------------------------------------------------------------- - # Add the path where mysqld will find ha_federated.so - # -------------------------------------------------------------------------- - my $fedplug_filename; - if (IS_WINDOWS) { - $fedplug_filename = "ha_federated.dll"; - } else { - $fedplug_filename = "ha_federated.so"; - } - my $lib_fed_plugin= - mtr_file_exists(vs_config_dirs('storage/federated',$fedplug_filename), - "$basedir/storage/federated/.libs/".$fedplug_filename, - "$basedir/lib/mysql/plugin/".$fedplug_filename); - - $ENV{'FEDERATED_PLUGIN'}= $fedplug_filename; - $ENV{'FEDERATED_PLUGIN_DIR'}= - ($lib_fed_plugin ? dirname($lib_fed_plugin) : ""); - - # ---------------------------------------------------- - # Add the path where mysqld will find mypluglib.so - # ---------------------------------------------------- - my $lib_simple_parser= - mtr_file_exists(vs_config_dirs('plugin/fulltext', 'mypluglib.dll'), - "$basedir/plugin/fulltext/.libs/mypluglib.so",); - - $ENV{'SIMPLE_PARSER'}= - ($lib_simple_parser ? basename($lib_simple_parser) : ""); - $ENV{'SIMPLE_PARSER_OPT'}= "--plugin-dir=". - ($lib_simple_parser ? dirname($lib_simple_parser) : ""); - # -------------------------------------------------------------------------- # Valgrind need to be run with debug libraries otherwise it's almost # impossible to add correct supressions, that means if "/usr/lib/debug" @@ -3917,7 +3844,7 @@ sub run_testcase ($$) { # Allow only alpanumerics pluss _ - + . in combination names, # or anything beginning with -- (the latter comes from --combination) my $combination= $tinfo->{combination}; - if ($combination && $combination !~ /^\w[-\w\.\+]+$/ + if ($combination && $combination !~ /^\w[-\w\.\+]*$/ && $combination !~ /^--/) { mtr_error("Combination '$combination' contains illegal characters"); @@ -5050,6 +4977,9 @@ sub mysqld_arguments ($$$) { } my $found_skip_core= 0; + my @plugins; + my %seen; + my $plugin; foreach my $arg ( @$extra_opts ) { # Allow --skip-core-file to be set in -[master|slave].opt file @@ -5066,6 +4996,11 @@ sub mysqld_arguments ($$$) { { ; # Dont add --skip-log-bin when mysqld have --log-slave-updates in config } + elsif ($plugin = mtr_match_prefix($arg, "--plugin-load=")) + { + push @plugins, $plugin unless $seen{$plugin}; + $seen{$plugin} = 1; + } else { mtr_add_arg($args, "%s", $arg); @@ -5082,6 +5017,11 @@ sub mysqld_arguments ($$$) { mtr_add_arg($args, "--loose-debug-sync-timeout=%s", $opt_debug_sync_timeout) unless $opt_user_args; + if (@plugins) { + my $sep = (IS_WINDOWS) ? ';' : ':'; + mtr_add_arg($args, "--plugin-load=%s" . join($sep, @plugins)); + } + return $args; } diff --git a/mysql-test/suite/federated/combinations b/mysql-test/suite/federated/combinations new file mode 100644 index 00000000000..18fd5f0d721 --- /dev/null +++ b/mysql-test/suite/federated/combinations @@ -0,0 +1,8 @@ +[old] +--federated +--plugin-load=$HA_FEDERATED_SO + +[X] +--federated +--plugin-load=$HA_FEDERATEDX_SO + diff --git a/mysql-test/suite/federated/federated.inc b/mysql-test/suite/federated/federated.inc index ad640dcbb61..17410846604 100644 --- a/mysql-test/suite/federated/federated.inc +++ b/mysql-test/suite/federated/federated.inc @@ -1,5 +1,4 @@ --source include/not_embedded.inc ---source have_federated_db.inc connect (master,127.0.0.1,root,,test,$MASTER_MYPORT,); connect (slave,127.0.0.1,root,,test,$SLAVE_MYPORT,); diff --git a/mysql-test/suite/federated/federated_partition.test b/mysql-test/suite/federated/federated_partition.test index 6f093bfb63d..13f26ecd756 100644 --- a/mysql-test/suite/federated/federated_partition.test +++ b/mysql-test/suite/federated/federated_partition.test @@ -1,6 +1,7 @@ # # Tests for partitioned FEDERATED # +source have_federatedx.inc; source include/have_partition.inc; source include/have_innodb.inc; source federated.inc; diff --git a/mysql-test/suite/federated/federated_plugin-master.opt b/mysql-test/suite/federated/federated_plugin-master.opt deleted file mode 100644 index 027a6d949c0..00000000000 --- a/mysql-test/suite/federated/federated_plugin-master.opt +++ /dev/null @@ -1,2 +0,0 @@ ---plugin_dir=$FEDERATED_PLUGIN_DIR ---loose-federated=ON diff --git a/mysql-test/suite/federated/federated_plugin.result b/mysql-test/suite/federated/federated_plugin.result deleted file mode 100644 index b49a977d9df..00000000000 --- a/mysql-test/suite/federated/federated_plugin.result +++ /dev/null @@ -1,19 +0,0 @@ -CREATE TABLE t2(a int); -CREATE TABLE t1(a int) ENGINE=FEDERATED -CONNECTION='mysql://root@localhost:$MASTER_MYPORT/test/t2'; -Warnings: -Warning 1286 Unknown table engine 'FEDERATED' -Warning 1266 Using storage engine MyISAM for table 't1' -DROP TABLE t1; -INSTALL PLUGIN federated SONAME 'FEDERATED_PLUGIN'; -INSTALL PLUGIN FEDERATED SONAME 'FEDERATED_PLUGIN'; -ERROR HY000: Function 'FEDERATED' already exists -UNINSTALL PLUGIN federated; -INSTALL PLUGIN federated SONAME 'FEDERATED_PLUGIN'; -CREATE TABLE t1(a int) ENGINE=FEDERATED -CONNECTION='mysql://root@localhost:$MASTER_MYPORT/test/t2'; -DROP TABLE t1; -UNINSTALL PLUGIN federated; -UNINSTALL PLUGIN federated; -ERROR 42000: PLUGIN federated does not exist -DROP TABLE t2; diff --git a/mysql-test/suite/federated/federated_plugin.test b/mysql-test/suite/federated/federated_plugin.test deleted file mode 100644 index 8c465095cfa..00000000000 --- a/mysql-test/suite/federated/federated_plugin.test +++ /dev/null @@ -1,37 +0,0 @@ ---source include/have_federated_plugin.inc - -# Uninstall will not uninstall if ps has been used ---disable_ps_protocol - -connect (master,localhost,root,,test,$MASTER_MYPORT,); -connect (slave,localhost,root,,test,$SLAVE_MYPORT,); - -connection master; -CREATE TABLE t2(a int); - -connection slave; -CREATE TABLE t1(a int) ENGINE=FEDERATED - CONNECTION='mysql://root@localhost:$MASTER_MYPORT/test/t2'; -DROP TABLE t1; - ---replace_result $FEDERATED_PLUGIN FEDERATED_PLUGIN -eval INSTALL PLUGIN federated SONAME '$FEDERATED_PLUGIN'; ---replace_result $FEDERATED_PLUGIN FEDERATED_PLUGIN ---error ER_UDF_EXISTS -eval INSTALL PLUGIN FEDERATED SONAME '$FEDERATED_PLUGIN'; - -UNINSTALL PLUGIN federated; - ---replace_result $FEDERATED_PLUGIN FEDERATED_PLUGIN -eval INSTALL PLUGIN federated SONAME '$FEDERATED_PLUGIN'; - -CREATE TABLE t1(a int) ENGINE=FEDERATED - CONNECTION='mysql://root@localhost:$MASTER_MYPORT/test/t2'; -DROP TABLE t1; - -UNINSTALL PLUGIN federated; ---error ER_SP_DOES_NOT_EXIST -UNINSTALL PLUGIN federated; - -connection master; -DROP TABLE t2; diff --git a/mysql-test/suite/federated/federated_server.result b/mysql-test/suite/federated/federated_server.result index 05782c6ef81..af6bf9bc88d 100644 --- a/mysql-test/suite/federated/federated_server.result +++ b/mysql-test/suite/federated/federated_server.result @@ -213,7 +213,7 @@ id name alter server s1 options (database 'db_bogus'); flush tables; select * from federated.t1; -ERROR 42000: Received error: 1044 : Access denied for user 'test_fed'@'localhost' to database 'db_bogus' +Got one of the listed errors drop server if exists 's1'; ERROR 42000: Access denied; you need the SUPER privilege for this operation create server 's1' foreign data wrapper 'mysql' options diff --git a/mysql-test/suite/federated/federated_server.test b/mysql-test/suite/federated/federated_server.test index d03c2d26014..0fddc95e1f3 100644 --- a/mysql-test/suite/federated/federated_server.test +++ b/mysql-test/suite/federated/federated_server.test @@ -239,7 +239,7 @@ alter server s1 options (database 'db_bogus'); connection master; flush tables; ---error ER_DBACCESS_DENIED_ERROR +--error ER_DBACCESS_DENIED_ERROR,ER_CONNECT_TO_FOREIGN_DATA_SOURCE select * from federated.t1; connection conn_select; diff --git a/mysql-test/suite/federated/federated_transactions.test b/mysql-test/suite/federated/federated_transactions.test index cd08d310273..637df45a52a 100644 --- a/mysql-test/suite/federated/federated_transactions.test +++ b/mysql-test/suite/federated/federated_transactions.test @@ -1,3 +1,4 @@ +source have_federatedx.inc; source include/have_innodb.inc; source federated.inc; diff --git a/mysql-test/suite/federated/federated.result b/mysql-test/suite/federated/federatedx.result similarity index 100% rename from mysql-test/suite/federated/federated.result rename to mysql-test/suite/federated/federatedx.result diff --git a/mysql-test/suite/federated/federated.test b/mysql-test/suite/federated/federatedx.test similarity index 99% rename from mysql-test/suite/federated/federated.test rename to mysql-test/suite/federated/federatedx.test index 7789070adc3..cabcf0cea1b 100644 --- a/mysql-test/suite/federated/federated.test +++ b/mysql-test/suite/federated/federatedx.test @@ -7,6 +7,7 @@ # should work with embedded server after mysqltest is fixed --source include/not_embedded.inc --source federated.inc +--source have_federatedx.inc connection default; diff --git a/mysql-test/suite/federated/have_federated_db.inc b/mysql-test/suite/federated/have_federated_db.inc deleted file mode 100644 index 81f49aaa48e..00000000000 --- a/mysql-test/suite/federated/have_federated_db.inc +++ /dev/null @@ -1,6 +0,0 @@ -if (!`SELECT count(*) FROM information_schema.engines WHERE - (support = 'YES' OR support = 'DEFAULT') AND - engine = 'federated'`) -{ - skip Need federated engine; -} diff --git a/mysql-test/suite/federated/have_federatedx.inc b/mysql-test/suite/federated/have_federatedx.inc new file mode 100644 index 00000000000..56ce31f5b2f --- /dev/null +++ b/mysql-test/suite/federated/have_federatedx.inc @@ -0,0 +1,5 @@ +if (!`SELECT count(*) FROM information_schema.plugins WHERE + plugin_name = 'federated' AND plugin_status = 'active' AND + plugin_description LIKE '%FederatedX%'`){ + skip Need FederatedX engine; +} diff --git a/mysql-test/suite/federated/suite.opt b/mysql-test/suite/federated/have_federatedx.opt similarity index 72% rename from mysql-test/suite/federated/suite.opt rename to mysql-test/suite/federated/have_federatedx.opt index 2cce1887441..22f40b6d3d7 100644 --- a/mysql-test/suite/federated/suite.opt +++ b/mysql-test/suite/federated/have_federatedx.opt @@ -1,2 +1 @@ ---federated --plugin-load=$HA_FEDERATEDX_SO diff --git a/mysql-test/suite/federated/suite.pm b/mysql-test/suite/federated/suite.pm new file mode 100644 index 00000000000..06458b97adc --- /dev/null +++ b/mysql-test/suite/federated/suite.pm @@ -0,0 +1,20 @@ +package My::Suite::Federated; + +@ISA = qw(My::Suite); + +############# initialization ###################### +my @combinations; + +push @combinations, 'old' + if $ENV{HA_FEDERATED_SO} and not $::mysqld_variables{'federated'}; +push @combinations, 'X' + if $ENV{HA_FEDERATEDX_SO} or $::mysqld_variables{'federated'}; + +return "Neither Federated nor FederatedX are available" unless @combinations; + +$ENV{FEDERATED_COMBINATIONS}=join ':', @combinations + unless $ENV{FEDERATED_COMBINATIONS}; + +############# return an object ###################### +bless { }; + diff --git a/storage/federated/ha_federated.cc b/storage/federated/ha_federated.cc index 27e4d787766..4449dc576eb 100644 --- a/storage/federated/ha_federated.cc +++ b/storage/federated/ha_federated.cc @@ -1513,7 +1513,7 @@ static FEDERATED_SHARE *get_share(const char *table_name, TABLE *table) tmp_share.table_name_length, ident_quote_char); if (!(share= (FEDERATED_SHARE *) memdup_root(&mem_root, (char*)&tmp_share, sizeof(*share))) || - !(share->select_query= (char*) strmake_root(&mem_root, query.ptr(), query.length() + 1))) + !(share->select_query= (char*) strmake_root(&mem_root, query.ptr(), query.length()))) goto error; share->use_count= 0; From 9a15f2492b1bccfa085a19c252ed5224c1fde3b2 Mon Sep 17 00:00:00 2001 From: Tor Didriksen Date: Wed, 30 Nov 2011 15:39:29 +0100 Subject: [PATCH 144/288] Bug#11761576 54082: HANDLE_SEGFAULT MAKES USE OF UNSAFE FUNCTIONS handle_segfault is the signal handler code of mysqld. however, it makes calls to potentially unsafe functions localtime_r, fprintf, fflush. include/my_stacktrace.h: Add safe versions of itoa() write() and snprintf(). libmysqld/CMakeLists.txt: Move signal handler to separate file. mysys/stacktrace.c: Remove unsafe function calls. sql/CMakeLists.txt: Move signal handler to separate file. sql/Makefile.am: Move signal handler to separate file. sql/mysqld.cc: Move signal handler to separate file. sql/signal_handler.cc: Remove unsafe function calls. --- include/my_stacktrace.h | 69 +++++++- libmysqld/CMakeLists.txt | 1 + mysys/stacktrace.c | 341 +++++++++++++++++++++++++++++++-------- sql/CMakeLists.txt | 3 +- sql/Makefile.am | 1 + sql/mysqld.cc | 190 +++------------------- sql/signal_handler.cc | 257 +++++++++++++++++++++++++++++ 7 files changed, 620 insertions(+), 242 deletions(-) create mode 100644 sql/signal_handler.cc diff --git a/include/my_stacktrace.h b/include/my_stacktrace.h index e7713f46fc3..30cac3871c5 100644 --- a/include/my_stacktrace.h +++ b/include/my_stacktrace.h @@ -1,5 +1,4 @@ -/* - Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2001, 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 @@ -12,8 +11,7 @@ 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _my_stacktrace_h_ #define _my_stacktrace_h_ @@ -63,6 +61,69 @@ void my_set_exception_pointers(EXCEPTION_POINTERS *ep); void my_write_core(int sig); #endif + + +/** + Async-signal-safe utility functions used by signal handler routines. + Declared here in order to unit-test them. + These are not general-purpose, but tailored to the signal handling routines. +*/ +/** + Converts a longlong value to string. + @param base 10 for decimal, 16 for hex values (0..9a..f) + @param val The value to convert + @param buf Assumed to point to the *end* of the buffer. + @returns Pointer to the first character of the converted string. + Negative values: + for base-10 the return string will be prepended with '-' + for base-16 the return string will contain 16 characters + Implemented with simplicity, and async-signal-safety in mind. +*/ +char *my_safe_itoa(int base, longlong val, char *buf); + +/** + Converts a ulonglong value to string. + @param base 10 for decimal, 16 for hex values (0..9a..f) + @param val The value to convert + @param buf Assumed to point to the *end* of the buffer. + @returns Pointer to the first character of the converted string. + Implemented with simplicity, and async-signal-safety in mind. +*/ +char *my_safe_utoa(int base, ulonglong val, char *buf); + +/** + A (very) limited version of snprintf. + @param to Destination buffer. + @param n Size of destination buffer. + @param fmt printf() style format string. + @returns Number of bytes written, including terminating '\0' + Supports 'd' 'i' 'u' 'x' 'p' 's' conversion. + Supports 'l' and 'll' modifiers for integral types. + Does not support any width/precision. + Implemented with simplicity, and async-signal-safety in mind. +*/ +size_t my_safe_snprintf(char* to, size_t n, const char* fmt, ...) + ATTRIBUTE_FORMAT(printf, 3, 4); + +/** + A (very) limited version of snprintf, which writes the result to STDERR. + @sa my_safe_snprintf + Implemented with simplicity, and async-signal-safety in mind. + @note Has an internal buffer capacity of 512 bytes, + which should suffice for our signal handling routines. +*/ +size_t my_safe_printf_stderr(const char* fmt, ...) + ATTRIBUTE_FORMAT(printf, 1, 2); + +/** + Writes up to count bytes from buffer to STDERR. + Implemented with simplicity, and async-signal-safety in mind. + @param buf Buffer containing data to be written. + @param count Number of bytes to write. + @returns Number of bytes written. +*/ +size_t my_write_stderr(const void *buf, size_t count); + C_MODE_END #endif /* _my_stacktrace_h_ */ diff --git a/libmysqld/CMakeLists.txt b/libmysqld/CMakeLists.txt index 344079cd61e..a1a3dbd6658 100644 --- a/libmysqld/CMakeLists.txt +++ b/libmysqld/CMakeLists.txt @@ -109,6 +109,7 @@ SET(LIBMYSQLD_SOURCES emb_qcache.cc libmysqld.c lib_sql.cc ../sql/password.c ../sql/discover.cc ../sql/derror.cc ../sql/field.cc ../sql/field_conv.cc ../sql/filesort.cc ../sql/gstream.cc ../sql/ha_partition.cc + ../sql/signal_handler.cc ../sql/handler.cc ../sql/hash_filo.cc ../sql/hostname.cc ../sql/init.cc ../sql/item_buff.cc ../sql/item_cmpfunc.cc ../sql/item.cc ../sql/item_create.cc ../sql/item_func.cc diff --git a/mysys/stacktrace.c b/mysys/stacktrace.c index 95f06937faa..b2eae0fb4c6 100644 --- a/mysys/stacktrace.c +++ b/mysys/stacktrace.c @@ -1,5 +1,4 @@ -/* - Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2001, 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 @@ -12,8 +11,8 @@ 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + /* Workaround for Bug#32082: VOID redefinition on Win results in compile errors*/ #define DONT_DEFINE_VOID 1 @@ -57,10 +56,11 @@ void my_init_stacktrace() static void print_buffer(char *buffer, size_t count) { + const char s[]= " "; for (; count && *buffer; --count) { - int c= (int) *buffer++; - fputc(isprint(c) ? c : ' ', stderr); + my_write_stderr(isprint(*buffer) ? buffer : s, 1); + ++buffer; } } @@ -124,10 +124,10 @@ static int safe_print_str(const char *addr, int max_len) /* Output a new line if something was printed. */ if (total != (size_t) max_len) - fputc('\n', stderr); + my_safe_printf_stderr("%s", "\n"); if (nbytes == -1) - fprintf(stderr, "Can't read from address %p: %m.\n", addr); + my_safe_printf_stderr("Can't read from address %p\n", addr); close(fd); @@ -149,13 +149,13 @@ void my_safe_print_str(const char* val, int max_len) if (!PTR_SANE(val)) { - fprintf(stderr, "is an invalid pointer\n"); + my_safe_printf_stderr("%s", "is an invalid pointer\n"); return; } for (; max_len && PTR_SANE(val) && *val; --max_len) - fputc(*val++, stderr); - fputc('\n', stderr); + my_write_stderr((val++), 1); + my_safe_printf_stderr("%s", "\n"); } #if defined(HAVE_PRINTSTACK) @@ -167,14 +167,15 @@ void my_print_stacktrace(uchar* stack_bottom __attribute__((unused)), ulong thread_stack __attribute__((unused))) { if (printstack(fileno(stderr)) == -1) - fprintf(stderr, "Error when traversing the stack, stack appears corrupt.\n"); + my_safe_printf_stderr("%s", + "Error when traversing the stack, stack appears corrupt.\n"); else - fprintf(stderr, - "Please read " - "http://dev.mysql.com/doc/refman/5.1/en/resolve-stack-dump.html\n" - "and follow instructions on how to resolve the stack trace.\n" - "Resolved stack trace is much more helpful in diagnosing the\n" - "problem, so please do resolve it\n"); + my_safe_printf_stderr("%s" + "Please read " + "http://dev.mysql.com/doc/refman/5.1/en/resolve-stack-dump.html\n" + "and follow instructions on how to resolve the stack trace.\n" + "Resolved stack trace is much more helpful in diagnosing the\n" + "problem, so please do resolve it\n"); } #elif HAVE_BACKTRACE && (HAVE_BACKTRACE_SYMBOLS || HAVE_BACKTRACE_SYMBOLS_FD) @@ -212,9 +213,9 @@ static void my_demangle_symbols(char **addrs, int n) } if (demangled) - fprintf(stderr, "%s(%s+%s\n", addrs[i], demangled, end); + my_safe_printf_stderr("%s(%s+%s\n", addrs[i], demangled, end); else - fprintf(stderr, "%s\n", addrs[i]); + my_safe_printf_stderr("%s\n", addrs[i]); } } @@ -225,8 +226,8 @@ void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack) void *addrs[128]; char **strings= NULL; int n = backtrace(addrs, array_elements(addrs)); - fprintf(stderr, "stack_bottom = %p thread_stack 0x%lx\n", - stack_bottom, thread_stack); + my_safe_printf_stderr("stack_bottom = %p thread_stack 0x%lx\n", + stack_bottom, thread_stack); #if BACKTRACE_DEMANGLE if ((strings= backtrace_symbols(addrs, n))) { @@ -319,8 +320,9 @@ void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack) #endif if (!fp) { - fprintf(stderr, "frame pointer is NULL, did you compile with\n\ --fomit-frame-pointer? Aborting backtrace!\n"); + my_safe_printf_stderr("%s", + "frame pointer is NULL, did you compile with\n" + "-fomit-frame-pointer? Aborting backtrace!\n"); return; } @@ -328,24 +330,28 @@ void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack) { ulong tmp= min(0x10000,thread_stack); /* Assume that the stack starts at the previous even 65K */ - stack_bottom= (uchar*) (((ulong) &fp + tmp) & - ~(ulong) 0xFFFF); - fprintf(stderr, "Cannot determine thread, fp=%p, backtrace may not be correct.\n", fp); + stack_bottom= (uchar*) (((ulong) &fp + tmp) & ~(ulong) 0xFFFF); + my_safe_printf_stderr("Cannot determine thread, fp=%p, " + "backtrace may not be correct.\n", fp); } if (fp > (uchar**) stack_bottom || fp < (uchar**) stack_bottom - thread_stack) { - fprintf(stderr, "Bogus stack limit or frame pointer,\ - fp=%p, stack_bottom=%p, thread_stack=%ld, aborting backtrace.\n", - fp, stack_bottom, thread_stack); + my_safe_printf_stderr("Bogus stack limit or frame pointer, " + "fp=%p, stack_bottom=%p, thread_stack=%ld, " + "aborting backtrace.\n", + fp, stack_bottom, thread_stack); return; } - fprintf(stderr, "Stack range sanity check OK, backtrace follows:\n"); + my_safe_printf_stderr("%s", + "Stack range sanity check OK, backtrace follows:\n"); #if defined(__alpha__) && defined(__GNUC__) - fprintf(stderr, "Warning: Alpha stacks are difficult -\ - will be taking some wild guesses, stack trace may be incorrect or \ - terminate abruptly\n"); + my_safe_printf_stderr("%s", + "Warning: Alpha stacks are difficult -" + "will be taking some wild guesses, stack trace may be incorrect or " + "terminate abruptly\n"); + /* On Alpha, we need to get pc */ __asm __volatile__ ("bsr %0, do_next; do_next: " :"=r"(pc) @@ -359,8 +365,9 @@ void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack) { #if defined(__i386__) || defined(__x86_64__) uchar** new_fp = (uchar**)*fp; - fprintf(stderr, "%p\n", frame_count == sigreturn_frame_count ? - *(fp + SIGRETURN_FRAME_OFFSET) : *(fp + 1)); + my_safe_printf_stderr("%p\n", + frame_count == sigreturn_frame_count ? + *(fp + SIGRETURN_FRAME_OFFSET) : *(fp + 1)); #endif /* defined(__386__) || defined(__x86_64__) */ #if defined(__alpha__) && defined(__GNUC__) @@ -374,38 +381,40 @@ void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack) { pc = find_prev_pc(pc, fp); if (pc) - fprintf(stderr, "%p\n", pc); + my_safe_printf_stderr("%p\n", pc); else { - fprintf(stderr, "Not smart enough to deal with the rest\ - of this stack\n"); + my_safe_printf_stderr("%s", + "Not smart enough to deal with the rest of this stack\n"); goto end; } } else { - fprintf(stderr, "Not smart enough to deal with the rest of this stack\n"); + my_safe_printf_stderr("%s", + "Not smart enough to deal with the rest of this stack\n"); goto end; } #endif /* defined(__alpha__) && defined(__GNUC__) */ if (new_fp <= fp ) { - fprintf(stderr, "New value of fp=%p failed sanity check,\ - terminating stack trace!\n", new_fp); + my_safe_printf_stderr("New value of fp=%p failed sanity check, " + "terminating stack trace!\n", new_fp); goto end; } fp = new_fp; ++frame_count; } - - fprintf(stderr, "Stack trace seems successful - bottom reached\n"); + my_safe_printf_stderr("%s", + "Stack trace seems successful - bottom reached\n"); end: - fprintf(stderr, - "Please read http://dev.mysql.com/doc/refman/5.1/en/resolve-stack-dump.html\n" - "and follow instructions on how to resolve the stack trace.\n" - "Resolved stack trace is much more helpful in diagnosing the\n" - "problem, so please do resolve it\n"); + my_safe_printf_stderr("%s", + "Please read " + "http://dev.mysql.com/doc/refman/5.1/en/resolve-stack-dump.html\n" + "and follow instructions on how to resolve the stack trace.\n" + "Resolved stack trace is much more helpful in diagnosing the\n" + "problem, so please do resolve it\n"); } #endif /* TARGET_OS_LINUX */ #endif /* HAVE_STACKTRACE */ @@ -670,7 +679,7 @@ void my_print_stacktrace(uchar* unused1, ulong unused2) &(package.sym)); have_source= pSymGetLineFromAddr64(hProcess, addr, &line_offset, &line); - fprintf(stderr, "%p ", addr); + my_safe_printf_stderr("%p ", addr); if(have_module) { char *base_image_name= strrchr(module.ImageName, '\\'); @@ -678,12 +687,13 @@ void my_print_stacktrace(uchar* unused1, ulong unused2) base_image_name++; else base_image_name= module.ImageName; - fprintf(stderr, "%s!", base_image_name); + my_safe_printf_stderr("%s!", base_image_name); } if(have_symbol) - fprintf(stderr, "%s()", package.sym.Name); + my_safe_printf_stderr("%s()", package.sym.Name); + else if(have_module) - fprintf(stderr, "???"); + my_safe_printf_stderr("%s", "???"); if(have_source) { @@ -692,11 +702,11 @@ void my_print_stacktrace(uchar* unused1, ulong unused2) base_file_name++; else base_file_name= line.FileName; - fprintf(stderr,"[%s:%u]", base_file_name, line.LineNumber); + my_safe_printf_stderr("[%s:%u]", + base_file_name, line.LineNumber); } - fprintf(stderr, "\n"); + my_safe_printf_stderr("%s", "\n"); } - fflush(stderr); } @@ -733,22 +743,22 @@ void my_write_core(int unused) if(pMiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &info, 0, 0)) { - fprintf(stderr, "Minidump written to %s\n", - _fullpath(path, dump_fname, sizeof(path)) ? path : dump_fname); + my_safe_printf_stderr("Minidump written to %s\n", + _fullpath(path, dump_fname, sizeof(path)) ? + path : dump_fname); } else { - fprintf(stderr,"MiniDumpWriteDump() failed, last error %u\n", - GetLastError()); + my_safe_printf_stderr("MiniDumpWriteDump() failed, last error %u\n", + (uint) GetLastError()); } CloseHandle(hFile); } else { - fprintf(stderr, "CreateFile(%s) failed, last error %u\n", dump_fname, - GetLastError()); + my_safe_printf_stderr("CreateFile(%s) failed, last error %u\n", + dump_fname, (uint) GetLastError()); } - fflush(stderr); } @@ -756,11 +766,212 @@ void my_safe_print_str(const char *val, int len) { __try { - fprintf(stderr,"=%.*s\n", len, val); + my_write_stderr(val, len); } __except(EXCEPTION_EXECUTE_HANDLER) { - fprintf(stderr,"is an invalid string pointer\n"); + my_safe_printf_stderr("%s", "is an invalid string pointer\n"); } } #endif /*__WIN__*/ + + +#ifdef __WIN__ +size_t my_write_stderr(const void *buf, size_t count) +{ + DWORD bytes_written; + SetFilePointer(GetStdHandle(STD_ERROR_HANDLE), 0, NULL, FILE_END); + WriteFile(GetStdHandle(STD_ERROR_HANDLE), buf, count, &bytes_written, NULL); + return bytes_written; +} +#else +size_t my_write_stderr(const void *buf, size_t count) +{ + return (size_t) write(STDERR_FILENO, buf, count); +} +#endif + + +static const char digits[]= "0123456789abcdef"; + +char *my_safe_utoa(int base, ulonglong val, char *buf) +{ + *buf--= 0; + do { + *buf--= digits[val % base]; + } while ((val /= base) != 0); + return buf + 1; +} + + +char *my_safe_itoa(int base, longlong val, char *buf) +{ + char *orig_buf= buf; + const my_bool is_neg= (val < 0); + *buf--= 0; + + if (is_neg) + val= -val; + if (is_neg && base == 16) + { + int ix; + val-= 1; + for (ix= 0; ix < 16; ++ix) + buf[-ix]= '0'; + } + + do { + *buf--= digits[val % base]; + } while ((val /= base) != 0); + + if (is_neg && base == 10) + *buf--= '-'; + + if (is_neg && base == 16) + { + int ix; + buf= orig_buf - 1; + for (ix= 0; ix < 16; ++ix, --buf) + { + switch (*buf) + { + case '0': *buf= 'f'; break; + case '1': *buf= 'e'; break; + case '2': *buf= 'd'; break; + case '3': *buf= 'c'; break; + case '4': *buf= 'b'; break; + case '5': *buf= 'a'; break; + case '6': *buf= '9'; break; + case '7': *buf= '8'; break; + case '8': *buf= '7'; break; + case '9': *buf= '6'; break; + case 'a': *buf= '5'; break; + case 'b': *buf= '4'; break; + case 'c': *buf= '3'; break; + case 'd': *buf= '2'; break; + case 'e': *buf= '1'; break; + case 'f': *buf= '0'; break; + } + } + } + return buf+1; +} + + +static const char *check_longlong(const char *fmt, my_bool *have_longlong) +{ + *have_longlong= FALSE; + if (*fmt == 'l') + { + fmt++; + if (*fmt != 'l') + *have_longlong= (sizeof(long) == sizeof(longlong)); + else + { + fmt++; + *have_longlong= TRUE; + } + } + return fmt; +} + +static size_t my_safe_vsnprintf(char *to, size_t size, + const char* format, va_list ap) +{ + char *start= to; + char *end= start + size - 1; + for (; *format; ++format) + { + my_bool have_longlong = FALSE; + if (*format != '%') + { + if (to == end) /* end of buffer */ + break; + *to++= *format; /* copy ordinary char */ + continue; + } + ++format; /* skip '%' */ + + format= check_longlong(format, &have_longlong); + + switch (*format) + { + case 'd': + case 'i': + case 'u': + case 'x': + case 'p': + { + longlong ival= 0; + ulonglong uval = 0; + if (*format == 'p') + have_longlong= (sizeof(void *) == sizeof(longlong)); + if (have_longlong) + { + if (*format == 'u') + uval= va_arg(ap, ulonglong); + else + ival= va_arg(ap, longlong); + } + else + { + if (*format == 'u') + uval= va_arg(ap, unsigned int); + else + ival= va_arg(ap, int); + } + + { + char buff[22]; + const int base= (*format == 'x' || *format == 'p') ? 16 : 10; + char *val_as_str= (*format == 'u') ? + my_safe_utoa(base, uval, &buff[sizeof(buff)-1]) : + my_safe_itoa(base, ival, &buff[sizeof(buff)-1]); + + /* Strip off "ffffffff" if we have 'x' format without 'll' */ + if (*format == 'x' && !have_longlong && ival < 0) + val_as_str+= 8; + + while (*val_as_str && to < end) + *to++= *val_as_str++; + continue; + } + } + case 's': + { + const char *val= va_arg(ap, char*); + if (!val) + val= "(null)"; + while (*val && to < end) + *to++= *val++; + continue; + } + } + } + *to= 0; + return to - start; +} + + +size_t my_safe_snprintf(char* to, size_t n, const char* fmt, ...) +{ + size_t result; + va_list args; + va_start(args,fmt); + result= my_safe_vsnprintf(to, n, fmt, args); + va_end(args); + return result; +} + + +size_t my_safe_printf_stderr(const char* fmt, ...) +{ + char to[512]; + size_t result; + va_list args; + va_start(args,fmt); + result= my_safe_vsnprintf(to, sizeof(to), fmt, args); + va_end(args); + my_write_stderr(to, result); + return result; +} diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index c050b329787..8f6e9cc7b32 100755 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -65,6 +65,7 @@ SET (SQL_SOURCE sql_list.cc sql_load.cc sql_manager.cc sql_map.cc sql_parse.cc sql_partition.cc sql_plugin.cc sql_prepare.cc sql_rename.cc debug_sync.cc debug_sync.h + signal_handler.cc sql_repl.cc sql_select.cc sql_show.cc sql_state.c sql_string.cc sql_table.cc sql_test.cc sql_trigger.cc sql_udf.cc sql_union.cc sql_update.cc sql_view.cc strfunc.cc table.cc thr_malloc.cc @@ -113,7 +114,7 @@ IF(MSVC AND NOT WITHOUT_DYNAMIC_PLUGINS) ADD_CUSTOM_COMMAND(TARGET mysqld PRE_LINK COMMAND cscript ARGS //nologo ${PROJECT_SOURCE_DIR}/win/create_def_file.js ${PLATFORM} ${LIB_LOCATIONS} > mysqld.def - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/sql) + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) ENDIF(MSVC AND NOT WITHOUT_DYNAMIC_PLUGINS) ADD_DEPENDENCIES(sql GenError) diff --git a/sql/Makefile.am b/sql/Makefile.am index 6040e4d498d..829523c7ba3 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -103,6 +103,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \ records.cc filesort.cc handler.cc \ ha_partition.cc \ debug_sync.cc \ + signal_handler.cc \ sql_db.cc sql_table.cc sql_rename.cc sql_crypt.cc \ sql_load.cc mf_iocache.cc field_conv.cc sql_show.cc \ sql_udf.cc sql_analyse.cc sql_analyse.h sql_cache.cc \ diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 37eb6d95ce8..73b107e4746 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -122,13 +122,6 @@ extern "C" { // Because of SCO 3.2V4.2 #include #endif -#ifdef __WIN__ -#include -#define SIGNAL_FMT "exception 0x%x" -#else -#define SIGNAL_FMT "signal %d" -#endif - #ifdef __NETWARE__ #define zVOLSTATE_ACTIVE 6 #define zVOLSTATE_DEACTIVE 2 @@ -269,7 +262,7 @@ inline void setup_fpu() extern "C" int gethostname(char *name, int namelen); #endif -extern "C" sig_handler handle_segfault(int sig); +extern "C" sig_handler handle_fatal_signal(int sig); #if defined(__linux__) #define ENABLE_TEMP_POOL 1 @@ -415,6 +408,10 @@ TYPELIB log_output_typelib= {array_elements(log_output_names)-1,"", /* static variables */ +#ifdef HAVE_NPTL +volatile sig_atomic_t ld_assume_kernel_is_set= 0; +#endif + /* the default log output is log tables */ static bool lower_case_table_names_used= 0; static bool max_long_data_size_used= false; @@ -424,7 +421,7 @@ static my_bool opt_debugging= 0, opt_external_locking= 0, opt_console= 0; static my_bool opt_short_log_format= 0; static uint kill_cached_threads, wake_thread; static ulong killed_threads, thread_created; -static ulong max_used_connections; + ulong max_used_connections; static ulong my_bind_addr; /**< the address we bind to */ static volatile ulong cached_thread_count= 0; static const char *sql_mode_str= "OFF"; @@ -553,7 +550,7 @@ TYPELIB binlog_format_typelib= ulong opt_binlog_format_id= (ulong) BINLOG_FORMAT_UNSPEC; const char *opt_binlog_format= binlog_format_names[opt_binlog_format_id]; #ifdef HAVE_INITGROUPS -static bool calling_initgroups= FALSE; /**< Used in SIGSEGV handler. */ +volatile sig_atomic_t calling_initgroups= 0; /**< Used in SIGSEGV handler. */ #endif uint mysqld_port, test_flags, select_errors, dropping_tables, ha_open_options; uint mysqld_port_timeout; @@ -727,7 +724,7 @@ char *opt_logname, *opt_slow_logname; /* Static variables */ -static bool kill_in_progress, segfaulted; +static volatile sig_atomic_t kill_in_progress; #ifdef HAVE_STACK_TRACE_ON_SEGV static my_bool opt_do_pstack; #endif /* HAVE_STACK_TRACE_ON_SEGV */ @@ -1616,9 +1613,9 @@ static void set_user(const char *user, struct passwd *user_info_arg) calling_initgroups as a flag to the SIGSEGV handler that is then used to output a specific message to help the user resolve this problem. */ - calling_initgroups= TRUE; + calling_initgroups= 1; initgroups((char*) user, user_info_arg->pw_gid); - calling_initgroups= FALSE; + calling_initgroups= 0; #endif if (setgid(user_info_arg->pw_gid) == -1) { @@ -2170,7 +2167,7 @@ LONG WINAPI my_unhandler_exception_filter(EXCEPTION_POINTERS *ex_pointers) __try { my_set_exception_pointers(ex_pointers); - handle_segfault(ex_pointers->ExceptionRecord->ExceptionCode); + handle_fatal_signal(ex_pointers->ExceptionRecord->ExceptionCode); } __except(EXCEPTION_EXECUTE_HANDLER) { @@ -2481,161 +2478,6 @@ extern "C" char *my_demangle(const char *mangled_name, int *status) #endif -extern "C" sig_handler handle_segfault(int sig) -{ - time_t curr_time; - struct tm tm; - - /* - Strictly speaking, one needs a mutex here - but since we have got SIGSEGV already, things are a mess - so not having the mutex is not as bad as possibly using a buggy - mutex - so we keep things simple - */ - if (segfaulted) - { - fprintf(stderr, "Fatal " SIGNAL_FMT " while backtracing\n", sig); - exit(1); - } - - segfaulted = 1; - - curr_time= my_time(0); - localtime_r(&curr_time, &tm); - - fprintf(stderr,"\ -%02d%02d%02d %2d:%02d:%02d - mysqld got " SIGNAL_FMT " ;\n\ -This could be because you hit a bug. It is also possible that this binary\n\ -or one of the libraries it was linked against is corrupt, improperly built,\n\ -or misconfigured. This error can also be caused by malfunctioning hardware.\n", - tm.tm_year % 100, tm.tm_mon+1, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec, - sig); - fprintf(stderr, "\ -We will try our best to scrape up some info that will hopefully help diagnose\n\ -the problem, but since we have already crashed, something is definitely wrong\n\ -and this may fail.\n\n"); - fprintf(stderr, "key_buffer_size=%lu\n", - (ulong) dflt_key_cache->key_cache_mem_size); - fprintf(stderr, "read_buffer_size=%ld\n", (long) global_system_variables.read_buff_size); - fprintf(stderr, "max_used_connections=%lu\n", max_used_connections); - fprintf(stderr, "max_threads=%u\n", thread_scheduler.max_threads); - fprintf(stderr, "threads_connected=%u\n", thread_count); - fprintf(stderr, "It is possible that mysqld could use up to \n\ -key_buffer_size + (read_buffer_size + sort_buffer_size)*max_threads = %lu K\n\ -bytes of memory\n", ((ulong) dflt_key_cache->key_cache_mem_size + - (global_system_variables.read_buff_size + - global_system_variables.sortbuff_size) * - thread_scheduler.max_threads + - max_connections * sizeof(THD)) / 1024); - fprintf(stderr, "Hope that's ok; if not, decrease some variables in the equation.\n\n"); - -#if defined(HAVE_LINUXTHREADS) - if (sizeof(char*) == 4 && thread_count > UNSAFE_DEFAULT_LINUX_THREADS) - { - fprintf(stderr, "\ -You seem to be running 32-bit Linux and have %d concurrent connections.\n\ -If you have not changed STACK_SIZE in LinuxThreads and built the binary \n\ -yourself, LinuxThreads is quite likely to steal a part of the global heap for\n\ -the thread stack. Please read http://dev.mysql.com/doc/mysql/en/linux.html\n\n", - thread_count); - } -#endif /* HAVE_LINUXTHREADS */ - -#ifdef HAVE_STACKTRACE - THD *thd=current_thd; - - if (!(test_flags & TEST_NO_STACKTRACE)) - { - fprintf(stderr, "Thread pointer: 0x%lx\n", (long) thd); - fprintf(stderr, "Attempting backtrace. You can use the following " - "information to find out\nwhere mysqld died. If " - "you see no messages after this, something went\n" - "terribly wrong...\n"); - my_print_stacktrace(thd ? (uchar*) thd->thread_stack : NULL, - my_thread_stack_size); - } - if (thd) - { - const char *kreason= "UNKNOWN"; - switch (thd->killed) { - case THD::NOT_KILLED: - kreason= "NOT_KILLED"; - break; - case THD::KILL_BAD_DATA: - kreason= "KILL_BAD_DATA"; - break; - case THD::KILL_CONNECTION: - kreason= "KILL_CONNECTION"; - break; - case THD::KILL_QUERY: - kreason= "KILL_QUERY"; - break; - case THD::KILLED_NO_VALUE: - kreason= "KILLED_NO_VALUE"; - break; - } - fprintf(stderr, "\nTrying to get some variables.\n" - "Some pointers may be invalid and cause the dump to abort.\n"); - fprintf(stderr, "Query (%p): ", thd->query()); - my_safe_print_str(thd->query(), min(1024, thd->query_length())); - fprintf(stderr, "Connection ID (thread ID): %lu\n", (ulong) thd->thread_id); - fprintf(stderr, "Status: %s\n", kreason); - fputc('\n', stderr); - } - fprintf(stderr, "\ -The manual page at http://dev.mysql.com/doc/mysql/en/crashing.html contains\n\ -information that should help you find out what is causing the crash.\n"); - fflush(stderr); -#endif /* HAVE_STACKTRACE */ - -#ifdef HAVE_INITGROUPS - if (calling_initgroups) - fprintf(stderr, "\n\ -This crash occured while the server was calling initgroups(). This is\n\ -often due to the use of a mysqld that is statically linked against glibc\n\ -and configured to use LDAP in /etc/nsswitch.conf. You will need to either\n\ -upgrade to a version of glibc that does not have this problem (2.3.4 or\n\ -later when used with nscd), disable LDAP in your nsswitch.conf, or use a\n\ -mysqld that is not statically linked.\n"); -#endif - -#ifdef HAVE_NPTL - if (thd_lib_detected == THD_LIB_LT && !getenv("LD_ASSUME_KERNEL")) - fprintf(stderr,"\n\ -You are running a statically-linked LinuxThreads binary on an NPTL system.\n\ -This can result in crashes on some distributions due to LT/NPTL conflicts.\n\ -You should either build a dynamically-linked binary, or force LinuxThreads\n\ -to be used with the LD_ASSUME_KERNEL environment variable. Please consult\n\ -the documentation for your distribution on how to do that.\n"); -#endif - - if (locked_in_memory) - { - fprintf(stderr, "\n\ -The \"--memlock\" argument, which was enabled, uses system calls that are\n\ -unreliable and unstable on some operating systems and operating-system\n\ -versions (notably, some versions of Linux). This crash could be due to use\n\ -of those buggy OS calls. You should consider whether you really need the\n\ -\"--memlock\" parameter and/or consult the OS distributer about \"mlockall\"\n\ -bugs.\n"); - } - -#ifdef HAVE_WRITE_CORE - if (test_flags & TEST_CORE_ON_SIGNAL) - { - fprintf(stderr, "Writing a core file\n"); - fflush(stderr); - my_write_core(sig); - } -#endif - -#ifndef __WIN__ - /* On Windows, do not terminate, but pass control to exception filter */ - exit(1); -#endif -} - #if !defined(__WIN__) && !defined(__NETWARE__) #ifndef SA_RESETHAND #define SA_RESETHAND 0 @@ -2664,9 +2506,9 @@ static void init_signals(void) my_init_stacktrace(); #endif #if defined(__amiga__) - sa.sa_handler=(void(*)())handle_segfault; + sa.sa_handler=(void(*)())handle_fatal_signal; #else - sa.sa_handler=handle_segfault; + sa.sa_handler=handle_fatal_signal; #endif sigaction(SIGSEGV, &sa, NULL); sigaction(SIGABRT, &sa, NULL); @@ -4363,6 +4205,10 @@ int win_main(int argc, char **argv) int main(int argc, char **argv) #endif { +#ifdef HAVE_NPTL + ld_assume_kernel_is_set= (getenv("LD_ASSUME_KERNEL") != 0); +#endif + MY_INIT(argv[0]); // init my_sys library & pthreads /* nothing should come before this line ^^^ */ @@ -7876,7 +7722,7 @@ static int mysql_init_variables(void) opt_secure_file_priv= 0; opt_bootstrap= opt_myisam_log= 0; mqh_used= 0; - segfaulted= kill_in_progress= 0; + kill_in_progress= 0; cleanup_done= 0; defaults_argc= 0; defaults_argv= 0; diff --git a/sql/signal_handler.cc b/sql/signal_handler.cc new file mode 100644 index 00000000000..54b456ec2c4 --- /dev/null +++ b/sql/signal_handler.cc @@ -0,0 +1,257 @@ +/* Copyright (c) 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 Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT 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., 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA */ + +#include "my_global.h" +#include + +#include "mysql_priv.h" +#include "my_stacktrace.h" + +#ifdef __WIN__ +#include +#define SIGNAL_FMT "exception 0x%x" +#else +#define SIGNAL_FMT "signal %d" +#endif + +/* + We are handling signals in this file. + Any global variables we read should be 'volatile sig_atomic_t' + to guarantee that we read some consistent value. + */ +static volatile sig_atomic_t segfaulted= 0; +extern ulong max_used_connections; +extern volatile sig_atomic_t calling_initgroups; +#ifdef HAVE_NPTL +extern volatile sig_atomic_t ld_assume_kernel_is_set; +#endif + +/** + * Handler for fatal signals + * + * Fatal events (seg.fault, bus error etc.) will trigger + * this signal handler. The handler will try to dump relevant + * debugging information to stderr and dump a core image. + * + * Signal handlers can only use a set of 'safe' system calls + * and library functions. A list of safe calls in POSIX systems + * are available at: + * http://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html + * For MS Windows, guidelines are available at: + * http://msdn.microsoft.com/en-us/library/xdkz3x12(v=vs.71).aspx + * + * @param sig Signal number +*/ +extern "C" sig_handler handle_fatal_signal(int sig) +{ + if (segfaulted) + { + my_safe_printf_stderr("Fatal " SIGNAL_FMT " while backtracing\n", sig); + _exit(1); /* Quit without running destructors */ + } + + segfaulted = 1; + +#ifdef __WIN__ + SYSTEMTIME utc_time; + GetSystemTime(&utc_time); + const long hrs= utc_time.wHour; + const long mins= utc_time.wMinute; + const long secs= utc_time.wSecond; +#else + /* Using time() instead of my_time() to avoid looping */ + const time_t curr_time= time(NULL); + /* Calculate time of day */ + const long tmins = curr_time / 60; + const long thrs = tmins / 60; + const long hrs = thrs % 24; + const long mins = tmins % 60; + const long secs = curr_time % 60; +#endif + + char hrs_buf[3]= "00"; + char mins_buf[3]= "00"; + char secs_buf[3]= "00"; + my_safe_itoa(10, hrs, &hrs_buf[2]); + my_safe_itoa(10, mins, &mins_buf[2]); + my_safe_itoa(10, secs, &secs_buf[2]); + + my_safe_printf_stderr("%s:%s:%s UTC - mysqld got " SIGNAL_FMT " ;\n", + hrs_buf, mins_buf, secs_buf, sig); + + my_safe_printf_stderr("%s", + "This could be because you hit a bug. It is also possible that this binary\n" + "or one of the libraries it was linked against is corrupt, improperly built,\n" + "or misconfigured. This error can also be caused by malfunctioning hardware.\n"); + + my_safe_printf_stderr("%s", + "We will try our best to scrape up some info that will hopefully help\n" + "diagnose the problem, but since we have already crashed, \n" + "something is definitely wrong and this may fail.\n\n"); + + my_safe_printf_stderr("key_buffer_size=%lu\n", + (ulong) dflt_key_cache->key_cache_mem_size); + + my_safe_printf_stderr("read_buffer_size=%ld\n", + (long) global_system_variables.read_buff_size); + + my_safe_printf_stderr("max_used_connections=%lu\n", + (ulong) max_used_connections); + + my_safe_printf_stderr("max_threads=%u\n", + (uint) thread_scheduler.max_threads); + + my_safe_printf_stderr("thread_count=%u\n", (uint) thread_count); + + my_safe_printf_stderr("connection_count=%u\n", (uint) connection_count); + + my_safe_printf_stderr("It is possible that mysqld could use up to \n" + "key_buffer_size + " + "(read_buffer_size + sort_buffer_size)*max_threads = " + "%lu K bytes of memory\n", + ((ulong) dflt_key_cache->key_cache_mem_size + + (global_system_variables.read_buff_size + + global_system_variables.sortbuff_size) * + thread_scheduler.max_threads + + max_connections * sizeof(THD)) / 1024); + + my_safe_printf_stderr("%s", + "Hope that's ok; if not, decrease some variables in the equation.\n\n"); + +#if defined(HAVE_LINUXTHREADS) + if (sizeof(char*) == 4 && thread_count > UNSAFE_DEFAULT_LINUX_THREADS) + { + my_safe_printf_stderr( + "You seem to be running 32-bit Linux and have " + "%d concurrent connections.\n" + "If you have not changed STACK_SIZE in LinuxThreads " + "and built the binary \n" + "yourself, LinuxThreads is quite likely to steal " + "a part of the global heap for\n" + "the thread stack. Please read " + "http://dev.mysql.com/doc/mysql/en/linux-installation.html\n\n" + thread_count); + } +#endif /* HAVE_LINUXTHREADS */ + +#ifdef HAVE_STACKTRACE + THD *thd=current_thd; + + if (!(test_flags & TEST_NO_STACKTRACE)) + { + my_safe_printf_stderr("Thread pointer: 0x%p\n", thd); + my_safe_printf_stderr("%s", + "Attempting backtrace. You can use the following " + "information to find out\n" + "where mysqld died. If you see no messages after this, something went\n" + "terribly wrong...\n"); + my_print_stacktrace(thd ? (uchar*) thd->thread_stack : NULL, + my_thread_stack_size); + } + if (thd) + { + const char *kreason= "UNKNOWN"; + switch (thd->killed) { + case THD::NOT_KILLED: + kreason= "NOT_KILLED"; + break; + case THD::KILL_BAD_DATA: + kreason= "KILL_BAD_DATA"; + break; + case THD::KILL_CONNECTION: + kreason= "KILL_CONNECTION"; + break; + case THD::KILL_QUERY: + kreason= "KILL_QUERY"; + break; + case THD::KILLED_NO_VALUE: + kreason= "KILLED_NO_VALUE"; + break; + } + my_safe_printf_stderr("%s", "\n" + "Trying to get some variables.\n" + "Some pointers may be invalid and cause the dump to abort.\n"); + + my_safe_printf_stderr("Query (%p): ", thd->query()); + my_safe_print_str(thd->query(), min(1024U, thd->query_length())); + my_safe_printf_stderr("Connection ID (thread ID): %lu\n", + (ulong) thd->thread_id); + my_safe_printf_stderr("Status: %s\n\n", kreason); + } + my_safe_printf_stderr("%s", + "The manual page at " + "http://dev.mysql.com/doc/mysql/en/crashing.html contains\n" + "information that should help you find out what is causing the crash.\n"); + +#endif /* HAVE_STACKTRACE */ + +#ifdef HAVE_INITGROUPS + if (calling_initgroups) + { + my_safe_printf_stderr("%s", "\n" + "This crash occured while the server was calling initgroups(). This is\n" + "often due to the use of a mysqld that is statically linked against \n" + "glibc and configured to use LDAP in /etc/nsswitch.conf.\n" + "You will need to either upgrade to a version of glibc that does not\n" + "have this problem (2.3.4 or later when used with nscd),\n" + "disable LDAP in your nsswitch.conf, or use a " + "mysqld that is not statically linked.\n"); + } +#endif + +#ifdef HAVE_NPTL + if (thd_lib_detected == THD_LIB_LT && !ld_assume_kernel_is_set) + { + my_safe_printf_stderr("%s", + "You are running a statically-linked LinuxThreads binary on an NPTL\n" + "system. This can result in crashes on some distributions due to " + "LT/NPTL conflicts.\n" + "You should either build a dynamically-linked binary, " + "or force LinuxThreads\n" + "to be used with the LD_ASSUME_KERNEL environment variable.\n" + "Please consult the documentation for your distribution " + "on how to do that.\n"); + } +#endif + + if (locked_in_memory) + { + my_safe_printf_stderr("%s", "\n" + "The \"--memlock\" argument, which was enabled, " + "uses system calls that are\n" + "unreliable and unstable on some operating systems and " + "operating-system versions (notably, some versions of Linux).\n" + "This crash could be due to use of those buggy OS calls.\n" + "You should consider whether you really need the " + "\"--memlock\" parameter and/or consult the OS distributer about " + "\"mlockall\" bugs.\n"); + } + +#ifdef HAVE_WRITE_CORE + if (test_flags & TEST_CORE_ON_SIGNAL) + { + my_safe_printf_stderr("%s", "Writing a core file\n"); + my_write_core(sig); + } +#endif + +#ifndef __WIN__ + /* + Quit, without running destructors (etc.) + On Windows, do not terminate, but pass control to exception filter. + */ + _exit(1); // Using _exit(), since exit() is not async signal safe +#endif +} From 23dce762a45c634cafaeef73fefd34c0ee2f096f Mon Sep 17 00:00:00 2001 From: Tor Didriksen Date: Wed, 30 Nov 2011 17:11:13 +0100 Subject: [PATCH 145/288] Bug#11761576 54082: HANDLE_SEGFAULT MAKES USE OF UNSAFE FUNCTIONS Post-push fix: build break on windows/optimized --- sql/mysqld.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 73b107e4746..c47d39721b9 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -122,6 +122,10 @@ extern "C" { // Because of SCO 3.2V4.2 #include #endif +#ifdef __WIN__ +#include +#endif + #ifdef __NETWARE__ #define zVOLSTATE_ACTIVE 6 #define zVOLSTATE_DEACTIVE 2 From 692fcba40397e71c08ed1bcf34d37283eee5a13e Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Wed, 30 Nov 2011 18:44:51 +0200 Subject: [PATCH 146/288] Fixed compiler warnings and other bugs found by buildbot. client/mysqltest.cc: Free mutex after usage (fixes valgrind warnings in embedded server) mysql-test/include/gis_keys.inc: Fixed failure in innodb.gis_test mysql-test/r/gis.result: Updated result mysql-test/suite/innodb/r/innodb_gis.result: Updated results mysql-test/suite/innodb/t/innodb_bug38231.test: Added handling of timeouts (happend on some servers in buildbot) mysql-test/suite/innodb_plugin/r/innodb_gis.result: Updated results mysql-test/suite/innodb_plugin/t/innodb.test: Use error names instead of numbers mysql-test/suite/innodb_plugin/t/innodb_misc1.test: This test requires utf8 mysql-test/suite/innodb_plugin/t/innodb_mysql.test: This test requires Xtradb sql/sql_base.cc: Don't print table names for placeholders. sql/sql_show.cc: Temporary fix: Save and restore db and table_name in mysqld_show_create (to get rid of valgrind warning) A better solution that needs to be investgated is to not change these fields in mysql_derived_prepare() sql/sql_view.cc: Fixed valgrind warning storage/xtradb/handler/ha_innodb.cc: Don't access THD directly --- client/mysqltest.cc | 21 ++++++++-- mysql-test/include/gis_keys.inc | 1 + mysql-test/r/gis.result | 2 +- mysql-test/suite/innodb/r/innodb_gis.result | 2 +- .../suite/innodb/t/innodb_bug38231.test | 1 + .../suite/innodb_plugin/r/innodb_gis.result | 2 +- mysql-test/suite/innodb_plugin/t/innodb.test | 6 +-- .../suite/innodb_plugin/t/innodb_misc1.test | 1 + .../suite/innodb_plugin/t/innodb_mysql.test | 3 ++ sql/sql_base.cc | 6 +-- sql/sql_show.cc | 42 +++++++++++++++---- sql/sql_view.cc | 2 +- storage/xtradb/handler/ha_innodb.cc | 2 +- 13 files changed, 70 insertions(+), 21 deletions(-) diff --git a/client/mysqltest.cc b/client/mysqltest.cc index 668d9ba45ba..a5d9fa677a1 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -262,7 +262,7 @@ struct st_connection pthread_cond_t cond; pthread_t tid; int query_done; - my_bool has_thread; + my_bool has_thread, mutex_inited; #endif /*EMBEDDED_LIBRARY*/ }; @@ -776,10 +776,12 @@ static int do_send_query(struct st_connection *cn, const char *q, int q_len, if (flags & QUERY_REAP_FLAG) return mysql_send_query(cn->mysql, q, q_len); - if (pthread_mutex_init(&cn->mutex, NULL) || - pthread_cond_init(&cn->cond, NULL)) + if (!cn->mutex_inited && + (pthread_mutex_init(&cn->mutex, NULL) || + pthread_cond_init(&cn->cond, NULL))) die("Error in the thread library"); + cn->mutex_inited= 1; cn->cur_query= q; cn->cur_query_len= q_len; cn->query_done= 0; @@ -809,9 +811,20 @@ static void wait_query_thread_end(struct st_connection *con) } } +static void free_embedded_data(struct st_connection *con) +{ + if (con->mutex_inited) + { + con->mutex_inited= 0; + pthread_mutex_destroy(&con->mutex); + pthread_cond_destroy(&con->cond); + } +} + #else /*EMBEDDED_LIBRARY*/ #define do_send_query(cn,q,q_len,flags) mysql_send_query(cn->mysql, q, q_len) +#define free_embedded_data(next_con) do { } while(0) #endif /*EMBEDDED_LIBRARY*/ @@ -1165,6 +1178,7 @@ void close_connections() if (next_con->util_mysql) mysql_close(next_con->util_mysql); my_free(next_con->name, MYF(MY_ALLOW_ZERO_PTR)); + free_embedded_data(next_con); } my_free(connections, MYF(MY_WME)); DBUG_VOID_RETURN; @@ -4988,6 +5002,7 @@ void do_close_connection(struct st_command *command) mysql_close(con->mysql); con->mysql= 0; + free_embedded_data(con); if (con->util_mysql) mysql_close(con->util_mysql); diff --git a/mysql-test/include/gis_keys.inc b/mysql-test/include/gis_keys.inc index ad00c7e1ef9..cc8ec68f7d1 100644 --- a/mysql-test/include/gis_keys.inc +++ b/mysql-test/include/gis_keys.inc @@ -33,6 +33,7 @@ EXPLAIN SELECT COUNT(*) FROM t1 WHERE p=POINTFROMTEXT('POINT(1 2)'); SELECT COUNT(*) FROM t1 WHERE p=POINTFROMTEXT('POINT(1 2)'); +--replace_column 9 # EXPLAIN SELECT COUNT(*) FROM t2 WHERE p=POINTFROMTEXT('POINT(1 2)'); SELECT COUNT(*) FROM t2 WHERE p=POINTFROMTEXT('POINT(1 2)'); diff --git a/mysql-test/r/gis.result b/mysql-test/r/gis.result index acb55d225a7..2cf5630e90b 100644 --- a/mysql-test/r/gis.result +++ b/mysql-test/r/gis.result @@ -947,7 +947,7 @@ COUNT(*) EXPLAIN SELECT COUNT(*) FROM t2 WHERE p=POINTFROMTEXT('POINT(1 2)'); id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 ref p p 28 const 1 Using where +1 SIMPLE t2 ref p p 28 const # Using where SELECT COUNT(*) FROM t2 WHERE p=POINTFROMTEXT('POINT(1 2)'); COUNT(*) 2 diff --git a/mysql-test/suite/innodb/r/innodb_gis.result b/mysql-test/suite/innodb/r/innodb_gis.result index 30daaf129b1..d1237942a6a 100644 --- a/mysql-test/suite/innodb/r/innodb_gis.result +++ b/mysql-test/suite/innodb/r/innodb_gis.result @@ -572,7 +572,7 @@ COUNT(*) EXPLAIN SELECT COUNT(*) FROM t2 WHERE p=POINTFROMTEXT('POINT(1 2)'); id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 ref p p 28 const 2 Using where +1 SIMPLE t2 ref p p 28 const # Using where SELECT COUNT(*) FROM t2 WHERE p=POINTFROMTEXT('POINT(1 2)'); COUNT(*) 2 diff --git a/mysql-test/suite/innodb/t/innodb_bug38231.test b/mysql-test/suite/innodb/t/innodb_bug38231.test index 5021f23d07e..4cf16beba56 100644 --- a/mysql-test/suite/innodb/t/innodb_bug38231.test +++ b/mysql-test/suite/innodb/t/innodb_bug38231.test @@ -72,6 +72,7 @@ UNLOCK TABLES; # clean up -- connection con2 +-- error 0, 1205 -- reap UNLOCK TABLES; diff --git a/mysql-test/suite/innodb_plugin/r/innodb_gis.result b/mysql-test/suite/innodb_plugin/r/innodb_gis.result index 30daaf129b1..d1237942a6a 100644 --- a/mysql-test/suite/innodb_plugin/r/innodb_gis.result +++ b/mysql-test/suite/innodb_plugin/r/innodb_gis.result @@ -572,7 +572,7 @@ COUNT(*) EXPLAIN SELECT COUNT(*) FROM t2 WHERE p=POINTFROMTEXT('POINT(1 2)'); id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 ref p p 28 const 2 Using where +1 SIMPLE t2 ref p p 28 const # Using where SELECT COUNT(*) FROM t2 WHERE p=POINTFROMTEXT('POINT(1 2)'); COUNT(*) 2 diff --git a/mysql-test/suite/innodb_plugin/t/innodb.test b/mysql-test/suite/innodb_plugin/t/innodb.test index 03c8336f214..59e0328bb8d 100644 --- a/mysql-test/suite/innodb_plugin/t/innodb.test +++ b/mysql-test/suite/innodb_plugin/t/innodb.test @@ -1034,11 +1034,11 @@ create table `t2` (`id` int( 11 ) not null default '0',unique key `id` ( `id` ) insert into `t2`values ( 1 ) ; create table `t3` (`id` int( 11 ) not null default '0',key `id` ( `id` ) ,constraint `t2_id_fk` foreign key ( `id` ) references `t2` (`id` )) engine = innodb; insert into `t3`values ( 1 ) ; ---error 1451 +--error ER_ROW_IS_REFERENCED_2 delete t3,t2,t1 from t1,t2,t3 where t1.id =1 and t2.id = t1.id and t3.id = t2.id; ---error 1451 +--error ER_ROW_IS_REFERENCED_2 update t1,t2,t3 set t3.id=5, t2.id=6, t1.id=7 where t1.id =1 and t2.id = t1.id and t3.id = t2.id; ---error 1054 +--error ER_BAD_FIELD_ERROR update t3 set t3.id=7 where t1.id =1 and t2.id = t1.id and t3.id = t2.id; drop table t3,t2,t1; diff --git a/mysql-test/suite/innodb_plugin/t/innodb_misc1.test b/mysql-test/suite/innodb_plugin/t/innodb_misc1.test index e9b6d72aa7d..31f9988d1ac 100644 --- a/mysql-test/suite/innodb_plugin/t/innodb_misc1.test +++ b/mysql-test/suite/innodb_plugin/t/innodb_misc1.test @@ -1,4 +1,5 @@ -- source include/have_innodb_plugin.inc +-- source include/have_utf8.inc let $MYSQLD_DATADIR= `select @@datadir`; diff --git a/mysql-test/suite/innodb_plugin/t/innodb_mysql.test b/mysql-test/suite/innodb_plugin/t/innodb_mysql.test index 1cdc1b4e2fe..d9981af2d0d 100644 --- a/mysql-test/suite/innodb_plugin/t/innodb_mysql.test +++ b/mysql-test/suite/innodb_plugin/t/innodb_mysql.test @@ -8,6 +8,9 @@ -- source include/have_innodb_plugin.inc -- source include/have_query_cache.inc +# We must run this with XtraDB as otherwise we will get different EXPLAIN's +-- source include/have_xtradb.inc + let $engine_type= InnoDB; let $other_engine_type= MEMORY; # InnoDB does support FOREIGN KEYFOREIGN KEYs diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 54921500e93..e895793f3c8 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -4699,9 +4699,6 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags) */ for (tables= *start; tables ;tables= tables->next_global) { - DBUG_PRINT("tcache", ("opening table: '%s'.'%s' item: 0x%lx", - tables->db, tables->table_name, (long) tables)); - safe_to_ignore_table= FALSE; /* @@ -4714,8 +4711,11 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags) { if (tables->view) goto process_view_routines; + DBUG_PRINT("tcache", ("ignoring placeholder for derived table")); continue; } + DBUG_PRINT("tcache", ("opening table: '%s'.'%s' item: 0x%lx", + tables->db, tables->table_name, (long) tables)); /* If this TABLE_LIST object is a placeholder for an information_schema table, create a temporary table to represent the information_schema diff --git a/sql/sql_show.cc b/sql/sql_show.cc index bb9a4a1e062..fccb071ccb3 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -708,12 +708,30 @@ public: }; +/* + Return CREATE command for table or view + + @param thd Thread handler + @param table_list Table / view + + @return + @retval 0 OK + @retval 1 Error + + @notes + table_list->db and table_list->table_name are kept unchanged to + not cause problems with SP. +*/ + bool mysqld_show_create(THD *thd, TABLE_LIST *table_list) { Protocol *protocol= thd->protocol; char buff[2048]; String buffer(buff, sizeof(buff), system_charset_info); + char *save_db, *save_table_name; + bool retval= TRUE; // Assume error + List field_list; DBUG_ENTER("mysqld_show_create"); DBUG_PRINT("enter",("db: %s table: %s",table_list->db, table_list->table_name)); @@ -721,13 +739,17 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) /* We want to preserve the tree for views. */ thd->lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_VIEW; + /* Store original names if called from SP */ + save_db= table_list->db; + save_table_name= table_list->table_name; + { Show_create_error_handler view_error_suppressor(thd, table_list); thd->push_internal_handler(&view_error_suppressor); bool error= open_normal_and_derived_tables(thd, table_list, 0); thd->pop_internal_handler(); if (error && (thd->killed || thd->main_da.is_error())) - DBUG_RETURN(TRUE); + goto error; } /* TODO: add environment variables show when it become possible */ @@ -735,7 +757,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) { my_error(ER_WRONG_OBJECT, MYF(0), table_list->db, table_list->table_name, "VIEW"); - DBUG_RETURN(TRUE); + goto error; } buffer.length(0); @@ -747,9 +769,8 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) view_store_create_info(thd, table_list, &buffer) : store_create_info(thd, table_list, &buffer, NULL, FALSE /* show_database */))) - DBUG_RETURN(TRUE); + goto error; - List field_list; if (table_list->view) { field_list.push_back(new Item_empty_string("View",NAME_CHAR_LEN)); @@ -770,7 +791,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) if (protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) - DBUG_RETURN(TRUE); + goto error; protocol->prepare_for_resend(); if (table_list->view) protocol->store(table_list->view_name.str, system_charset_info); @@ -798,10 +819,17 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) protocol->store(buffer.ptr(), buffer.length(), buffer.charset()); if (protocol->write()) - DBUG_RETURN(TRUE); + goto error; my_eof(thd); - DBUG_RETURN(FALSE); + retval= FALSE; // ok + +error: + /* Restore table list if called by stored procedure */ + table_list->db= save_db; + table_list->table_name= save_table_name; + DBUG_RETURN(retval); + } bool mysqld_show_create_db(THD *thd, char *dbname, diff --git a/sql/sql_view.cc b/sql/sql_view.cc index df9df89f972..27bdfed6bea 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -848,7 +848,7 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view, thd->variables.sql_mode|= sql_mode; } - DBUG_PRINT("info", ("View: %s", view_query.ptr())); + DBUG_PRINT("info", ("View: %.*s", view_query.length(), view_query.ptr())); /* fill structure */ view->source= thd->lex->create_view_select; diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index 4f4db23d06c..536871fb9ab 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -2735,7 +2735,7 @@ innobase_commit_low( #ifdef MYSQL_SERVER THD *thd=current_thd; - if (thd && thd->slave_thread) { + if (thd && thd_is_replication_slave_thread(thd)) { /* Update the replication position info inside InnoDB. In embedded server, does nothing. */ const char *log_file_name, *group_relay_log_name; From 2f9734172f2552c6fdb0483e33423a92acd9285b Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Wed, 30 Nov 2011 10:22:53 -0800 Subject: [PATCH 147/288] Fixed LP bug #898073. The tables from the same semi-join or outer join nest cannot use join buffers if in the join sequence of the query execution plan they are separated by a table that is planned to be joined without usage of a join buffer. --- mysql-test/r/subselect_sj2_jcl6.result | 29 +++++++++++++++++++++++ mysql-test/t/subselect_sj2_jcl6.test | 32 ++++++++++++++++++++++++++ sql/sql_select.cc | 5 ++-- 3 files changed, 64 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/subselect_sj2_jcl6.result b/mysql-test/r/subselect_sj2_jcl6.result index bd330dd8143..46b62ce843c 100644 --- a/mysql-test/r/subselect_sj2_jcl6.result +++ b/mysql-test/r/subselect_sj2_jcl6.result @@ -899,6 +899,35 @@ DROP VIEW v1; DROP TABLE t1,t2,t3,t4; # This must be the last in the file: set optimizer_switch=@subselect_sj2_tmp; +# +# Bug #898073: potential incremental join cache for semijoin +# +CREATE TABLE t1 (a int, b varchar(1), KEY (b,a)); +INSERT INTO t1 VALUES (0,'x'), (5,'r'); +CREATE TABLE t2 (a int) ENGINE=InnoDB; +INSERT INTO t2 VALUES (8); +CREATE TABLE t3 (b varchar(1), c varchar(1)) ENGINE=InnoDB; +INSERT INTO t3 VALUES ('x','x'); +CREATE TABLE t4 (a int NOT NULL, b varchar(1)) ENGINE=InnoDB; +INSERT INTO t4 VALUES (20,'r'), (10,'x'); +set @tmp_optimizer_switch=@@optimizer_switch; +SET SESSION optimizer_switch='semijoin_with_cache=on'; +SET SESSION join_cache_level=2; +EXPLAIN +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 t1 ref b b 4 test.t3.b 1 Using index +1 PRIMARY t4 ALL NULL NULL NULL NULL 2 Using where; FirstMatch(t2) +SELECT t3.* FROM t1 JOIN t3 ON t3.b = t1.b +WHERE c IN (SELECT t4.b FROM t4 JOIN t2); +b c +x x +set optimizer_switch=@tmp_optimizer_switch; +set join_cache_level=default; +DROP TABLE t1,t2,t3,t4; set join_cache_level=default; show variables like 'join_cache_level'; Variable_name Value diff --git a/mysql-test/t/subselect_sj2_jcl6.test b/mysql-test/t/subselect_sj2_jcl6.test index e4ae249c711..9628bd5c4b9 100644 --- a/mysql-test/t/subselect_sj2_jcl6.test +++ b/mysql-test/t/subselect_sj2_jcl6.test @@ -13,6 +13,38 @@ show variables like 'join_cache_level'; --source t/subselect_sj2.test +--echo # +--echo # Bug #898073: potential incremental join cache for semijoin +--echo # + +CREATE TABLE t1 (a int, b varchar(1), KEY (b,a)); +INSERT INTO t1 VALUES (0,'x'), (5,'r'); + +CREATE TABLE t2 (a int) ENGINE=InnoDB; +INSERT INTO t2 VALUES (8); + +CREATE TABLE t3 (b varchar(1), c varchar(1)) ENGINE=InnoDB; +INSERT INTO t3 VALUES ('x','x'); + +CREATE TABLE t4 (a int NOT NULL, b varchar(1)) ENGINE=InnoDB; +INSERT INTO t4 VALUES (20,'r'), (10,'x'); + +set @tmp_optimizer_switch=@@optimizer_switch; + +SET SESSION optimizer_switch='semijoin_with_cache=on'; + +SET SESSION join_cache_level=2; +EXPLAIN +SELECT t3.* FROM t1 JOIN t3 ON t3.b = t1.b + WHERE c IN (SELECT t4.b FROM t4 JOIN t2); +SELECT t3.* FROM t1 JOIN t3 ON t3.b = t1.b + WHERE c IN (SELECT t4.b FROM t4 JOIN t2); + +set optimizer_switch=@tmp_optimizer_switch; +set join_cache_level=default; + +DROP TABLE t1,t2,t3,t4; + set join_cache_level=default; show variables like 'join_cache_level'; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 0ef417c9567..47adbd97289 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -9052,11 +9052,12 @@ uint check_join_cache_usage(JOIN_TAB *tab, for (JOIN_TAB *first_inner= tab->first_inner; first_inner; first_inner= first_inner->first_upper) { - if (first_inner != tab && !first_inner->use_join_cache) + if (first_inner != tab && + (!first_inner->use_join_cache || !(tab-1)->use_join_cache)) goto no_join_cache; } if (tab->first_sj_inner_tab && tab->first_sj_inner_tab != tab && - !tab->first_sj_inner_tab->use_join_cache) + (!tab->first_sj_inner_tab->use_join_cache || !(tab-1)->use_join_cache)) goto no_join_cache; if (!prev_tab->use_join_cache) { From 6378bdbf47af72b2f899853586faa5a2d2f0fee1 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Wed, 30 Nov 2011 20:57:09 +0200 Subject: [PATCH 148/288] Fixed compiler warning and errors mysql-test/suite/funcs_1/t/is_engines_federated.test: Corrected path storage/xtradb/fil/fil0fil.c: Fixed compiler warning --- mysql-test/suite/funcs_1/t/is_engines_federated.test | 2 +- storage/xtradb/fil/fil0fil.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mysql-test/suite/funcs_1/t/is_engines_federated.test b/mysql-test/suite/funcs_1/t/is_engines_federated.test index 81eac89c0d2..f39edefe43c 100644 --- a/mysql-test/suite/funcs_1/t/is_engines_federated.test +++ b/mysql-test/suite/funcs_1/t/is_engines_federated.test @@ -9,7 +9,7 @@ # let $engine_type= FEDERATED; ---source suite/federated/have_federated_db.inc +--source suite/federated/have_federatedx.inc --vertical_results eval SELECT * FROM information_schema.engines WHERE ENGINE = '$engine_type'; diff --git a/storage/xtradb/fil/fil0fil.c b/storage/xtradb/fil/fil0fil.c index bcf134f4292..17ca4cb1745 100644 --- a/storage/xtradb/fil/fil0fil.c +++ b/storage/xtradb/fil/fil0fil.c @@ -3448,8 +3448,8 @@ skip_info: if ((ulint) (offset / (zip_size ? zip_size : UNIV_PAGE_SIZE)) == root_page[i]) { if (fil_page_get_type(page) != FIL_PAGE_INDEX) { file_is_corrupt = TRUE; - fprintf(stderr, " [etyp:%lld]", - offset / (zip_size ? zip_size : UNIV_PAGE_SIZE)); + fprintf(stderr, " [etyp:%ld]", + (long) (offset / (zip_size ? zip_size : UNIV_PAGE_SIZE))); goto skip_write; } /* this is index root page */ From a899a4050b96928d5a048ce75f6909c3082dd028 Mon Sep 17 00:00:00 2001 From: Luis Soares Date: Thu, 1 Dec 2011 00:54:54 +0000 Subject: [PATCH 149/288] BUG#11745230 Refactored the test case: hardened and extended it. Created test inc file to abstract the task of relocating binlogs. Also, disabled it on windows for not cluttering the test case any further, as it depends heavily on doing filesystem operations and path handling. mysql-test/include/relocate_binlogs.inc: Auxiliar include file that performs the relocation of binary logs listed in an index file. --- mysql-test/include/relocate_binlogs.inc | 137 ++++++++++++++++++ .../suite/rpl/r/rpl_binlog_index.result | 13 +- mysql-test/suite/rpl/t/rpl_binlog_index.test | 111 ++++++++++---- 3 files changed, 227 insertions(+), 34 deletions(-) create mode 100644 mysql-test/include/relocate_binlogs.inc diff --git a/mysql-test/include/relocate_binlogs.inc b/mysql-test/include/relocate_binlogs.inc new file mode 100644 index 00000000000..d5d1135dda3 --- /dev/null +++ b/mysql-test/include/relocate_binlogs.inc @@ -0,0 +1,137 @@ +# ==== Purpose ==== +# +# Relocates the relay logs and index file from +# a directory into another. The logs relocated +# are the one listed in the index file. +# +# ==== Usage ==== +# +# [--let $relocate_disable_query_log= 1] +# [--let $rpl_debug= 1] +# [--let $relocate_is_windows= 0] +# [--let $relocate_recreate_index= 0] +# [--let $relocate_fix_relay_log_info= 0] +# --let $relocate_from= DIR +# --let $relocate_to= DIR +# --let $relocate_index_file= FNAME +# --source include/relocate_binlogs.inc + +if ($relocate_disable_query_log) +{ + --disable_query_log +} + +--let $_path_separator=/ +if ($relocate_is_windows) +{ + --let $_path_separator=\ +} + +if ($relocate_index_file) +{ + SET SQL_LOG_BIN=0; + CREATE TEMPORARY TABLE tmp(id INT AUTO_INCREMENT PRIMARY KEY, filename VARCHAR(1024)); + + --let $write_var= + --let $_index_file= $relocate_index_file + --let $_index_file_basename= `SELECT RIGHT(RTRIM("$_index_file"), LOCATE("$_path_separator",REVERSE(RTRIM("$_index_file"))) -1)` + --let $_from= $relocate_from + --let $_to= $relocate_into + + # chmod to allow the following LOAD DATA + --chmod 0666 $_index_file + + --eval LOAD DATA INFILE '$_index_file' INTO TABLE tmp (filename) + --let $count= `SELECT count(*) FROM tmp` + + while ($count) + { + --let $_filename= `select filename from tmp where id=$count` + + --let $_filename= `SELECT RIGHT(RTRIM("$_filename"), LOCATE("$_path_separator",REVERSE(RTRIM("$_filename"))) -1)` + --move_file $_from/$_filename $_to/$_filename + + if ($relocate_recreate_index) + { + + if ($relocate_is_windows) + { + --let $_write_var=$_to\$_filename\n + } + if (!$relocate_is_windows) + { + --let $_write_var=$_to/$_filename\n + } + if (!$write_var) + { + --let $write_var=$_write_var + } + + if (!`SELECT STRCMP('$write_var', '$_write_var') = 0`) + { + --let $write_var=$_write_var$write_var + } + } + + --dec $count + } + + if (!$relocate_recreate_index) + { + --move_file $_index_file $_to/$_index_file_basename + } + + if ($relocate_recreate_index) + { + --let $write_to_file= $_to/$_index_file_basename + --source include/write_var_to_file.inc + --remove_file $_index_file + } + + DROP TEMPORARY TABLE tmp; + + if ($relocate_fix_relay_log_info) + { + CREATE TEMPORARY TABLE tmp(id INT AUTO_INCREMENT PRIMARY KEY, entry VARCHAR(1024)); + --let $write_var= + + # chmod to allow the following LOAD DATA + --chmod 0666 $relocate_fix_relay_log_info + + --eval LOAD DATA INFILE '$relocate_fix_relay_log_info' INTO TABLE tmp (entry) + --let $count= `SELECT count(*) FROM tmp` + + --let $_curr_entry= `SELECT entry FROM tmp WHERE id=1` + --let $_curr_entry_basename= `SELECT RIGHT(RTRIM("$_curr_entry"), LOCATE("$_path_separator",REVERSE(RTRIM("$_curr_entry"))) -1)` + + if ($relocate_is_windows) + { + --eval UPDATE tmp SET entry='$_to\$_curr_entry_basename' WHERE id=1 + } + if (!$relocate_is_windows) + { + --eval UPDATE tmp SET entry='$_to/$_curr_entry_basename' WHERE id=1 + } + + --remove_file $relocate_fix_relay_log_info + + while($count) + { + --let $_write_var= `SELECT entry FROM tmp WHERE id= $count` + --let $write_var=$_write_var\n$write_var + --dec $count + } + + --let $write_to_file= $relocate_fix_relay_log_info + --source include/write_var_to_file.inc + + DROP TEMPORARY TABLE tmp; + } + SET SQL_LOG_BIN=1; +} + + +if ($relocate_disable_query_log) +{ + --enable_query_log +} diff --git a/mysql-test/suite/rpl/r/rpl_binlog_index.result b/mysql-test/suite/rpl/r/rpl_binlog_index.result index 9861a156a62..6611a9ef2c0 100644 --- a/mysql-test/suite/rpl/r/rpl_binlog_index.result +++ b/mysql-test/suite/rpl/r/rpl_binlog_index.result @@ -15,12 +15,13 @@ include/rpl_stop_server.inc [server_number=1] # Remove the unneeded master-bin.index file # Restart master with log-bin option set to default # Master has restarted successfully +# stop slave include/stop_slave.inc -# Move the slave binlog and relay log files and index to the new place -# Shutdown slave include/rpl_stop_server.inc [server_number=2] +# relocate binlogs +# relocate relay logs # Restart slave with options log-bin, relay-log set to the new paths -# Slave has restarted successfully +# Slave server has restarted successfully include/start_slave.inc include/stop_slave.inc FLUSH LOGS; @@ -33,3 +34,9 @@ FLUSH LOGS; include/start_slave.inc include/diff_tables.inc [master:t1,slave:t1] DROP TABLE t1; +include/stop_slave.inc +include/rpl_stop_server.inc [server_number=2] +# remove tmpdir +# restarted with previous slave settings +include/start_slave.inc +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_binlog_index.test b/mysql-test/suite/rpl/t/rpl_binlog_index.test index 900a6819c2f..3147447227a 100644 --- a/mysql-test/suite/rpl/t/rpl_binlog_index.test +++ b/mysql-test/suite/rpl/t/rpl_binlog_index.test @@ -21,12 +21,20 @@ source include/master-slave.inc; # There is no need to run this test case on all binlog format source include/have_binlog_format_row.inc; +# Since this test relies heavily on filesystem operations (like +# moving files around, backslashes and so forth) we avoid messing +# around with windows access violations for not cluttering the +# test case any further. It is prepared to support windows, but +# it is not 100% compliant. +--source include/not_windows.inc + connection master; --let $master_datadir= `select @@datadir` connection slave; --let $slave_datadir= `select @@datadir` connection master; ---let $tmpdir= $MYSQLTEST_VARDIR/tmp/rpl_binlog_index +--let $dirname= `select uuid()` +--let $tmpdir= $MYSQLTEST_VARDIR/tmp/$dirname --mkdir $tmpdir CREATE TABLE t1 (a INT); @@ -36,7 +44,6 @@ INSERT INTO t1 VALUES (1); sync_slave_with_master; - # # Test on master # @@ -69,11 +76,11 @@ source include/rpl_start_server.inc; --let $write_to_file= $master_datadir/master-bin.index if ($is_windows) { - --let $write_var= .\\master-bin.000001\n.\\master-bin.000002\n + --let $write_var= .\\\\master-bin.000001\n.\\\\master-bin.000002\n.\\\\master-bin.000003\n } if (!$is_windows) { - --let $write_var= ./master-bin.000001\n./master-bin.000002\n + --let $write_var= ./master-bin.000001\n./master-bin.000002\n./master-bin.000003\n } --disable_query_log source include/write_var_to_file.inc; @@ -86,6 +93,7 @@ source include/rpl_stop_server.inc; --echo # Move back the master binlog files --move_file $tmpdir/master-bin.000001 $master_datadir/master-bin.000001 --move_file $tmpdir/master-bin.000002 $master_datadir/master-bin.000002 +--move_file $tmpdir/master-bin.000003 $master_datadir/master-bin.000003 --echo # Remove the unneeded master-bin.index file --remove_file $tmpdir/master-bin.index @@ -99,41 +107,40 @@ source include/rpl_start_server.inc; --echo # Master has restarted successfully connection slave; -source include/stop_slave.inc; +--echo # stop slave +--source include/stop_slave.inc +--let $rpl_server_number= 2 +--source include/rpl_stop_server.inc ---disable_query_log -# slave-relay-bin.* files can vary, so read the slave-relay-bin.index -# to figure out the slave-relay-bin.* files -CREATE TEMPORARY TABLE tmp (id INT AUTO_INCREMENT PRIMARY KEY, filename VARCHAR(1024)); -# chmod to allow the following LOAD DATA ---chmod 0666 $slave_datadir/slave-relay-bin.index ---eval LOAD DATA INFILE '$slave_datadir/slave-relay-bin.index' INTO TABLE tmp (filename) ---let $count= `SELECT count(*) FROM tmp` ---echo # Move the slave binlog and relay log files and index to the new place ---move_file $slave_datadir/slave-bin.index $tmpdir/slave-bin.index ---move_file $slave_datadir/slave-bin.000001 $tmpdir/slave-bin.000001 ---move_file $slave_datadir/slave-relay-bin.index $tmpdir/slave-relay-bin.index -while ($count) -{ - --let $filename= `select filename from tmp where id=$count` - --move_file $slave_datadir/$filename $tmpdir/$filename - --dec $count -} -DROP TEMPORARY TABLE tmp; ---enable_query_log +# switch to master because the slave has been shutdown +# and relocate_binlogs requires a running server to do +# SQL operations +--connection master ---echo # Shutdown slave ---let $rpl_server_number=2 -source include/rpl_stop_server.inc; +--let $relocate_disable_query_log= 1 +--let $relocate_is_windows= $is_windows +--let $relocate_from=$slave_datadir +--let $relocate_into=$tmpdir + +--echo # relocate binlogs +--let $relocate_index_file=$slave_datadir/slave-bin.index +--source include/relocate_binlogs.inc + +--echo # relocate relay logs +--let $relocate_index_file=$slave_datadir/slave-relay-bin.index +--source include/relocate_binlogs.inc --echo # Restart slave with options log-bin, relay-log set to the new paths --let $rpl_server_parameters=--log-bin=$tmpdir/slave-bin --relay-log=$tmpdir/slave-relay-bin --let $keep_include_silent=1 +--let $rpl_server_number= 2 source include/rpl_start_server.inc; --let $keep_include_silent=0 ---echo # Slave has restarted successfully -source include/start_slave.inc; +--connection slave + +--echo # Slave server has restarted successfully +--source include/start_slave.inc --source include/stop_slave.inc connection master; @@ -155,6 +162,48 @@ source include/diff_tables.inc; connection master; DROP TABLE t1; -sync_slave_with_master; +--sync_slave_with_master +--source include/stop_slave.inc +--let $rpl_server_number= 2 +--source include/rpl_stop_server.inc + +--connection master + +--let $relocate_from=$tmpdir +--let $relocate_into=$slave_datadir +--let $relocate_recreate_index= 1 + +# binlogs +--let $relocate_index_file=$tmpdir/slave-bin.index +--source include/relocate_binlogs.inc + +# relay logs + +# since the complete fix for the relocation of logs is +# done in BUG#13428851 it does not help here to try +# to start the slave as it would fail (relay-log.info is +# tainted with the full path in the RELAY_LOG_FILE position). +# Instead, we reset the slave and let the test clean up. +--let $relocate_fix_relay_log_info= $slave_datadir/relay-log.info +--let $relocate_index_file=$tmpdir/slave-relay-bin.index +--source include/relocate_binlogs.inc + +--echo # remove tmpdir --remove_files_wildcard $tmpdir * --rmdir $tmpdir + +--echo # restarted with previous slave settings +--let $rpl_server_parameters=--log-bin=$slave_datadir/slave-bin --relay-log=$slave_datadir/slave-relay-bin +--let $keep_include_silent=1 +--let $rpl_server_number= 2 +--source include/rpl_start_server.inc +--let $keep_include_silent=0 + +--connection slave + +# The slave will restart if we have fixed the relay-log.info +# correctly +--source include/start_slave.inc + +--connection master +--source include/rpl_end.inc From a22e18730801da2a3006a75b4dd5c3b0994fad82 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 1 Dec 2011 18:54:29 +0530 Subject: [PATCH 150/288] BUG #11746897 - 29508: PLEASE IMPLEMENT MYSQL-TEST-RUN.PL --STRACE-MASTER Includes fix for strace-client and restricted to strace and linux only. ****** --- mysql-test/mysql-test-run.pl | 56 +++++++++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 11 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index d278c36f033..2df6087f2b4 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -280,6 +280,7 @@ my $opt_reorder= 1; my $opt_force_restart= 0; my $opt_strace_client; +my $opt_strace_server; our $opt_user = "root"; @@ -1117,7 +1118,8 @@ sub command_line_setup { 'debugger=s' => \$opt_debugger, 'boot-dbx' => \$opt_boot_dbx, 'client-debugger=s' => \$opt_client_debugger, - 'strace-client:s' => \$opt_strace_client, + 'strace-server' => \$opt_strace_server, + 'strace-client' => \$opt_strace_client, 'max-save-core=i' => \$opt_max_save_core, 'max-save-datadir=i' => \$opt_max_save_datadir, 'max-test-fail=i' => \$opt_max_test_fail, @@ -1721,6 +1723,19 @@ sub command_line_setup { $debug_d= "d,query,info,error,enter,exit"; } + if ( $opt_strace_server && ($^O ne "linux") ) + { + $opt_strace_server=0; + mtr_warning("Strace only supported in Linux "); + } + + if ( $opt_strace_client && ($^O ne "linux") ) + { + $opt_strace_client=0; + mtr_warning("Strace only supported in Linux "); + } + + mtr_report("Checking supported features..."); check_ndbcluster_support(\%mysqld_variables); @@ -4875,6 +4890,12 @@ sub mysqld_start ($$) { my $args; mtr_init_args(\$args); +# implementation for strace-server + if ( $opt_strace_server ) + { + strace_server_arguments($args, \$exe, $mysqld->name()); + } + if ( $opt_valgrind_mysqld ) { @@ -5440,6 +5461,14 @@ sub start_mysqltest ($) { mtr_init_args(\$args); + if ( $opt_strace_client ) + { + $exe= "strace"; + mtr_add_arg($args, "-o"); + mtr_add_arg($args, "%s/log/mysqltest.strace", $opt_vardir); + mtr_add_arg($args, "$exe_mysqltest"); + } + mtr_add_arg($args, "--defaults-file=%s", $path_config_file); mtr_add_arg($args, "--silent"); mtr_add_arg($args, "--tmpdir=%s", $opt_tmpdir); @@ -5476,13 +5505,6 @@ sub start_mysqltest ($) { mtr_add_arg($args, "--cursor-protocol"); } - if ( $opt_strace_client ) - { - $exe= $opt_strace_client || "strace"; - mtr_add_arg($args, "-o"); - mtr_add_arg($args, "%s/log/mysqltest.strace", $opt_vardir); - mtr_add_arg($args, "$exe_mysqltest"); - } mtr_add_arg($args, "--timer-file=%s/log/timer", $opt_vardir); @@ -5783,6 +5805,19 @@ sub debugger_arguments { } } +# +# Modify the exe and args so that program is run in strace +# +sub strace_server_arguments { + my $args= shift; + my $exe= shift; + my $type= shift; + + mtr_add_arg($args, "-o"); + mtr_add_arg($args, "%s/log/%s.strace", $opt_vardir, $type); + mtr_add_arg($args, $$exe); + $$exe= "strace"; +} # # Modify the exe and args so that program is run in valgrind @@ -6099,9 +6134,8 @@ Options for debugging the product test(s) manual-dbx Let user manually start mysqld in dbx, before running test(s) - strace-client[=path] Create strace output for mysqltest client, optionally - specifying name and path to the trace program to use. - Example: $0 --strace-client=ktrace + strace-client Create strace output for mysqltest client, + strace-server Create strace output for mysqltest server, max-save-core Limit the number of core files saved (to avoid filling up disks for heavily crashing server). Defaults to $opt_max_save_core, set to 0 for no limit. Set From f22437ab503c2f5e73250210af032d66d87ff912 Mon Sep 17 00:00:00 2001 From: Inaam Rana Date: Thu, 1 Dec 2011 09:41:52 -0500 Subject: [PATCH 151/288] Bug#13414773 -INNODB_FAST_SHUTDOWN=2, ASSERT STATE == BUF_BLOCK_ZIP_PAGE We can have dirty pages during a fast shutdown. Relax the assertion. --- storage/innodb_plugin/buf/buf0buf.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/storage/innodb_plugin/buf/buf0buf.c b/storage/innodb_plugin/buf/buf0buf.c index d88860b807b..8332727cfde 100644 --- a/storage/innodb_plugin/buf/buf0buf.c +++ b/storage/innodb_plugin/buf/buf0buf.c @@ -957,8 +957,10 @@ buf_pool_free(void) ut_ad(bpage->in_LRU_list); if (state != BUF_BLOCK_FILE_PAGE) { - /* We must not have any dirty block. */ - ut_ad(state == BUF_BLOCK_ZIP_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); } From dad1322940f89aec19ff805c4218ea9daa766435 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Thu, 1 Dec 2011 20:11:41 +0200 Subject: [PATCH 152/288] Fixed that --with-libedit --without-readline works Fixed buildbot failures (compiler warnings, failing tests) cmd-line-utils/libedit/map.c: Fixed compiler warning cmd-line-utils/libedit/terminal.c: Fixed compiler warning cmd-line-utils/libedit/tty.c: Fixed compiler warning configure.in: Fixed that --with-libedit --without-readline works mysql-test/suite/innodb_plugin/t/innodb_misc1.test: Fixed test that failed when characterset was missing --- cmd-line-utils/libedit/map.c | 2 +- cmd-line-utils/libedit/terminal.c | 16 ++++++++-------- cmd-line-utils/libedit/tty.c | 2 +- configure.in | 2 +- .../suite/innodb_plugin/t/innodb_misc1.test | 3 ++- 5 files changed, 13 insertions(+), 12 deletions(-) diff --git a/cmd-line-utils/libedit/map.c b/cmd-line-utils/libedit/map.c index 946bc185437..17b07391b69 100644 --- a/cmd-line-utils/libedit/map.c +++ b/cmd-line-utils/libedit/map.c @@ -1300,7 +1300,7 @@ map_bind(EditLine *el, int argc, const Char **argv) default: (void) fprintf(el->el_errfile, "" FSTR ": Invalid switch `%c'.\n", - argv[0], p[1]); + argv[0], (int) p[1]); } else break; diff --git a/cmd-line-utils/libedit/terminal.c b/cmd-line-utils/libedit/terminal.c index 8cfbeac7c52..fb5600a4140 100644 --- a/cmd-line-utils/libedit/terminal.c +++ b/cmd-line-utils/libedit/terminal.c @@ -908,17 +908,17 @@ terminal_set(EditLine *el, const char *term) terminal_alloc(el, t, NULL); } else { /* auto/magic margins */ - Val(T_am) = tgetflag("am"); - Val(T_xn) = tgetflag("xn"); + Val(T_am) = tgetflag((char*) "am"); + Val(T_xn) = tgetflag((char*) "xn"); /* Can we tab */ - Val(T_pt) = tgetflag("pt"); - Val(T_xt) = tgetflag("xt"); + Val(T_pt) = tgetflag((char*) "pt"); + Val(T_xt) = tgetflag((char*) "xt"); /* do we have a meta? */ - Val(T_km) = tgetflag("km"); - Val(T_MT) = tgetflag("MT"); + Val(T_km) = tgetflag((char*) "km"); + Val(T_MT) = tgetflag((char*) "MT"); /* Get the size */ - Val(T_co) = tgetnum("co"); - Val(T_li) = tgetnum("li"); + Val(T_co) = tgetnum((char*) "co"); + Val(T_li) = tgetnum((char*) "li"); for (t = tstr; t->name != NULL; t++) { /* XXX: some systems' tgetstr needs non const */ terminal_alloc(el, t, tgetstr(strchr(t->name, *t->name), diff --git a/cmd-line-utils/libedit/tty.c b/cmd-line-utils/libedit/tty.c index 46624a87077..eea00bfc245 100644 --- a/cmd-line-utils/libedit/tty.c +++ b/cmd-line-utils/libedit/tty.c @@ -1215,7 +1215,7 @@ tty_stty(EditLine *el, int argc __attribute__((__unused__)), const Char **argv) default: (void) fprintf(el->el_errfile, "%s: Unknown switch `%c'.\n", - name, argv[0][1]); + name, (int) argv[0][1]); return -1; } diff --git a/configure.in b/configure.in index e8a2979de68..34ca4e171b2 100644 --- a/configure.in +++ b/configure.in @@ -2702,7 +2702,7 @@ case $SYSTEM_TYPE in echo "Skipping readline" ;; *) - if [test "$with_libedit" = "yes"] || [test "$with_libedit" = "undefined"] && [test "$with_readline" = "undefined"] + if [test "$with_libedit" = "yes"] || ( [test "$with_libedit" = "undefined"] && [test "$with_readline" = "undefined"] ) then readline_topdir="cmd-line-utils" readline_basedir="libedit" diff --git a/mysql-test/suite/innodb_plugin/t/innodb_misc1.test b/mysql-test/suite/innodb_plugin/t/innodb_misc1.test index 31f9988d1ac..4d66701c927 100644 --- a/mysql-test/suite/innodb_plugin/t/innodb_misc1.test +++ b/mysql-test/suite/innodb_plugin/t/innodb_misc1.test @@ -1,5 +1,6 @@ -- source include/have_innodb_plugin.inc --- source include/have_utf8.inc +let collation=utf8_unicode_ci; +--source include/have_collation.inc let $MYSQLD_DATADIR= `select @@datadir`; From a01c955793fb1fd0ec20b5e0da6948750cd0aeed Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Thu, 1 Dec 2011 19:15:09 +0100 Subject: [PATCH 153/288] Fix main.merge testcase on Windows --- client/mysqltest.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/mysqltest.cc b/client/mysqltest.cc index a5d9fa677a1..68f076818dd 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -3063,7 +3063,7 @@ void do_remove_file(struct st_command *command) ' '); DBUG_PRINT("info", ("removing file: %s", ds_filename.str)); - error= my_delete(ds_filename.str, MYF(disable_warnings ? 0 : MY_WME)) != 0; + error= my_delete_allow_opened(ds_filename.str, MYF(disable_warnings ? 0 : MY_WME)) != 0; handle_command_error(command, error, my_errno); dynstr_free(&ds_filename); DBUG_VOID_RETURN; From 02963d45e37e85619e33f49d82e26157c8b580f6 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Thu, 1 Dec 2011 20:21:11 +0200 Subject: [PATCH 154/288] Fixed compiler warning --- storage/example/ha_example.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/storage/example/ha_example.cc b/storage/example/ha_example.cc index 067bd00cdbf..8d5185ae0c7 100644 --- a/storage/example/ha_example.cc +++ b/storage/example/ha_example.cc @@ -977,6 +977,7 @@ bool ha_example::check_if_incompatible_data(HA_CREATE_INFO *info, param_new->boolparam != param_old->boolparam) DBUG_RETURN(COMPATIBLE_DATA_NO); +#ifndef DBUG_OFF for (i= 0; i < table->s->fields; i++) { ha_field_option_struct *f_old, *f_new; @@ -997,6 +998,7 @@ bool ha_example::check_if_incompatible_data(HA_CREATE_INFO *info, else DBUG_PRINT("info", ("old field %i did not changed", i)); } +#endif DBUG_RETURN(COMPATIBLE_DATA_YES); } From 1054de8699cc64174ec57771fb631ea14a48158e Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Thu, 1 Dec 2011 22:37:45 +0100 Subject: [PATCH 155/288] Fix intermittently failing variables-notembedded test case. After sending packet that is too large, clienrt can get either an error packet with ER_NET_PACKET_TOO_LARGE, or a socket error. Both cases are valid, since the server does not ensure reply was fully read by client, before shutting down and closing the socket. --- mysql-test/r/variables-notembedded.result | 2 +- mysql-test/t/variables-notembedded.test | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/variables-notembedded.result b/mysql-test/r/variables-notembedded.result index 6089d39780b..2c707765aca 100644 --- a/mysql-test/r/variables-notembedded.result +++ b/mysql-test/r/variables-notembedded.result @@ -125,7 +125,7 @@ max_allowed_packet 2048 SHOW SESSION VARIABLES LIKE 'net_buffer_length'; Variable_name Value net_buffer_length 4096 -ERROR 08S01: Got a packet bigger than 'max_allowed_packet' bytes +Got one of the listed errors SELECT LENGTH(a) FROM t1; LENGTH(a) SET GLOBAL max_allowed_packet=default; diff --git a/mysql-test/t/variables-notembedded.test b/mysql-test/t/variables-notembedded.test index b440cfa47b0..471212bf38f 100644 --- a/mysql-test/t/variables-notembedded.test +++ b/mysql-test/t/variables-notembedded.test @@ -123,7 +123,12 @@ CONNECT (con1,localhost,root,,test); SHOW SESSION VARIABLES LIKE 'max_allowed_packet'; SHOW SESSION VARIABLES LIKE 'net_buffer_length'; --disable_query_log ---error ER_NET_PACKET_TOO_LARGE +#Sending a packet that is too big can result in either +#ER_NET_PACKET_TOO_LARGE or a socket error on the client side (2013= CR_SERVER_LOST) +#The server does not make any attempts to gracefully close client connection and ensuring +#client fully read the last packet. Server just closes the socket after it has send. +#Client thus can get either a socket error, or EOF, or an error packet with ER_NET_PACKET_TOO_LARGE +--error ER_NET_PACKET_TOO_LARGE,2013 INSERT INTO t1 VALUES ('123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890'); --enable_query_log From ffab2a90dcf6aec84d95d5de24c55fc536c96968 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Fri, 2 Dec 2011 00:24:58 +0200 Subject: [PATCH 156/288] Patch to get MariaDB to compile on CYGWIN; By Guenter Knauf Increased number of locks in thr_lock (used only when testing) include/my_global.h: Patch for CYGWIN mysys/my_getsystime.c: Patch for CYGWIN mysys/thr_lock.c: Increase number of locks for testing --- include/my_global.h | 2 ++ mysys/my_getsystime.c | 5 +++++ mysys/thr_lock.c | 4 ++-- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/include/my_global.h b/include/my_global.h index eff16d0dfff..746eabcb11e 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -39,6 +39,8 @@ #undef __WIN__ #undef __WIN32__ #define HAVE_ERRNO_AS_DEFINE +#define _POSIX_MONOTONIC_CLOCK +#define _POSIX_THREAD_CPUTIME #endif /* __CYGWIN__ */ #if defined(__QNXNTO__) && !defined(FD_SETSIZE) diff --git a/mysys/my_getsystime.c b/mysys/my_getsystime.c index cb063e27c1f..268619a1334 100644 --- a/mysys/my_getsystime.c +++ b/mysys/my_getsystime.c @@ -28,6 +28,11 @@ static ulonglong query_performance_frequency; #include #endif +/* For CYGWIN */ +#if !defined(CLOCK_THREAD_CPUTIME_ID) && defined(CLOCK_THREAD_CPUTIME) +#define CLOCK_THREAD_CPUTIME_ID CLOCK_THREAD_CPUTIME +#endif + /* return number of nanoseconds since unspecified (but always the same) point in the past diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c index ac70282c050..f50e9818e74 100644 --- a/mysys/thr_lock.c +++ b/mysys/thr_lock.c @@ -98,8 +98,8 @@ ulong table_lock_wait_timeout; enum thr_lock_type thr_upgraded_concurrent_insert_lock = TL_WRITE; /* The following constants are only for debug output */ -#define MAX_THREADS 100 -#define MAX_LOCKS 100 +#define MAX_THREADS 1000 +#define MAX_LOCKS 1000 LIST *thr_lock_thread_list; /* List of threads in use */ From 55f0e6bf0c9b68f02b0e620c01bceb896970e888 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Fri, 2 Dec 2011 00:34:59 +0200 Subject: [PATCH 157/288] Fixes for netware by Guenter Knauf --- include/config-netware.h | 1 + netware/Makefile.am | 1 + netware/my_manage.c | 10 +- netware/mysql_install_db.c | 14 +- netware/mysqld_safe.c | 730 ++++++++++++++++++------------------- 5 files changed, 380 insertions(+), 376 deletions(-) diff --git a/include/config-netware.h b/include/config-netware.h index 156b1eff0e4..076b9684f4f 100644 --- a/include/config-netware.h +++ b/include/config-netware.h @@ -57,6 +57,7 @@ extern "C" { #undef HAVE_RWLOCK_INIT #undef HAVE_SCHED_H #undef HAVE_SYS_MMAN_H +#undef HAVE_SYS_UN_H #undef HAVE_SYNCH_H #undef HAVE_MMAP #undef HAVE_RINT diff --git a/netware/Makefile.am b/netware/Makefile.am index f537022495b..0eb7fe65f25 100644 --- a/netware/Makefile.am +++ b/netware/Makefile.am @@ -108,6 +108,7 @@ init_db.sql: $(top_srcdir)/scripts/mysql_system_tables.sql \ @echo "CREATE DATABASE test;" >> $@; @echo "use mysql;" >> $@; @cat $(top_srcdir)/scripts/mysql_system_tables.sql >> $@; + @cat $(top_srcdir)/scripts/mysql_system_tables_data.sql | grep -v '@current_hostname' >> $@; # Build test_db.sql from init_db.sql plus # some test data diff --git a/netware/my_manage.c b/netware/my_manage.c index d5032da2208..4b149afe5c2 100644 --- a/netware/my_manage.c +++ b/netware/my_manage.c @@ -24,8 +24,10 @@ #include #include #include +#include #include #include +#include #include "my_manage.h" @@ -356,17 +358,17 @@ pid_t get_server_pid(char *pid_file) // terminate string if ((p = strchr(buf, '\n')) != NULL) { - *p = NULL; + *p = 0; // check for a '\r' if ((p = strchr(buf, '\r')) != NULL) { - *p = NULL; + *p = 0; } } else { - buf[err] = NULL; + buf[err] = 0; } id = strtol(buf, NULL, 0); @@ -471,7 +473,7 @@ void get_basedir(char *argv0, char *basedir) if ((p = strindex(temp, "/bin/")) != NULL) { - *p = NULL; + *p = 0; strcpy(basedir, temp); } } diff --git a/netware/mysql_install_db.c b/netware/mysql_install_db.c index 98852c89825..09960eacb59 100644 --- a/netware/mysql_install_db.c +++ b/netware/mysql_install_db.c @@ -34,7 +34,7 @@ global variables ******************************************************************************/ -char autoclose; +int autoclose; char basedir[PATH_MAX]; char datadir[PATH_MAX]; char err_log[PATH_MAX]; @@ -99,7 +99,7 @@ void start_defaults(int argc, char *argv[]) } // default option - default_option[0] = NULL; + default_option[0] = 0; for (i=0; (argc > 1) && default_options[i]; i++) { if(!strnicmp(argv[1], default_options[i], strlen(default_options[i]))) @@ -110,11 +110,11 @@ void start_defaults(int argc, char *argv[]) } // set after basedir is established - datadir[0] = NULL; - err_log[0] = NULL; - out_log[0] = NULL; - mysqld[0] = NULL; - sql_file[0] = NULL; + datadir[0] = 0; + err_log[0] = 0; + out_log[0] = 0; + mysqld[0] = 0; + sql_file[0] = 0; } /****************************************************************************** diff --git a/netware/mysqld_safe.c b/netware/mysqld_safe.c index 6ed04c9ff0d..228c7c23fa4 100644 --- a/netware/mysqld_safe.c +++ b/netware/mysqld_safe.c @@ -1,6 +1,6 @@ -/* +/* Copyright (c) 2003 Novell, Inc. 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 Foundation; either version 2 of the License, or @@ -10,74 +10,74 @@ but WITHOUT 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 + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "my_config.h" -#include "my_manage.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "my_config.h" +#include "my_manage.h" #include "mysql_version.h" - -/****************************************************************************** - - global variables -******************************************************************************/ -char autoclose; -char basedir[PATH_MAX]; +/****************************************************************************** + + global variables + +******************************************************************************/ +char autoclose; +char basedir[PATH_MAX]; char checktables; -char datadir[PATH_MAX]; -char pid_file[PATH_MAX]; -char address[PATH_MAX]; -char port[PATH_MAX]; -char err_log[PATH_MAX]; -char safe_log[PATH_MAX]; -char mysqld[PATH_MAX]; -char hostname[PATH_MAX]; -char default_option[PATH_MAX]; - -FILE *log_fd= NULL; - -/****************************************************************************** - - prototypes +char datadir[PATH_MAX]; +char pid_file[PATH_MAX]; +char address[PATH_MAX]; +char port[PATH_MAX]; +char err_log[PATH_MAX]; +char safe_log[PATH_MAX]; +char mysqld[PATH_MAX]; +char hostname[PATH_MAX]; +char default_option[PATH_MAX]; + +FILE *log_fd= NULL; + +/****************************************************************************** + + prototypes + +******************************************************************************/ -******************************************************************************/ - void usage(void); -void vlog(char *, va_list); -void log(char *, ...); +void vlog(char *, va_list); +void log(char *, ...); void start_defaults(int, char *[]); -void finish_defaults(); +void finish_defaults(); void read_defaults(arg_list_t *); void parse_args(int, char *[]); void get_options(int, char *[]); -void check_data_vol(); -void check_setup(); -void check_tables(); +void check_data_vol(); +void check_setup(); +void check_tables(); void mysql_start(int, char *[]); void parse_setvar(char *arg); - -/****************************************************************************** - - functions -******************************************************************************/ - -/****************************************************************************** - +/****************************************************************************** + + functions + +******************************************************************************/ + +/****************************************************************************** + usage() Show usage. @@ -114,86 +114,86 @@ options:\n\ /****************************************************************************** - vlog() + vlog() - Log the message. - -******************************************************************************/ -void vlog(char *format, va_list ap) -{ - vfprintf(stdout, format, ap); - fflush(stdout); + Log the message. - if (log_fd) - { - vfprintf(log_fd, format, ap); - fflush(log_fd); - } -} - -/****************************************************************************** - - log() +******************************************************************************/ +void vlog(char *format, va_list ap) +{ + vfprintf(stdout, format, ap); + fflush(stdout); - Log the message. - -******************************************************************************/ -void log(char *format, ...) -{ - va_list ap; + if (log_fd) + { + vfprintf(log_fd, format, ap); + fflush(log_fd); + } +} - va_start(ap, format); - - vlog(format, ap); +/****************************************************************************** - va_end(ap); -} - -/****************************************************************************** - - start_defaults() + log() - Start setting the defaults. - -******************************************************************************/ -void start_defaults(int argc, char *argv[]) -{ - struct stat buf; - int i; + Log the message. - // default options +******************************************************************************/ +void log(char *format, ...) +{ + va_list ap; + + va_start(ap, format); + + vlog(format, ap); + + va_end(ap); +} + +/****************************************************************************** + + start_defaults() + + Start setting the defaults. + +******************************************************************************/ +void start_defaults(int argc, char *argv[]) +{ + struct stat buf; + int i; + + // default options static char *default_options[]= - { + { "--no-defaults", "--defaults-file=", "--defaults-extra-file=", NULL - }; + }; - // autoclose + // autoclose autoclose= FALSE; - // basedir - get_basedir(argv[0], basedir); + // basedir + get_basedir(argv[0], basedir); // check-tables checktables= FALSE; - // hostname + // hostname if (gethostname(hostname, PATH_MAX) < 0) - { - // default + { + // default strcpy(hostname, "mysql"); - } - - // address - snprintf(address, PATH_MAX, "0.0.0.0"); - - // port + } + + // address + snprintf(address, PATH_MAX, "0.0.0.0"); + + // port snprintf(port, PATH_MAX, "%d", MYSQL_PORT); - // default option - default_option[0]= NULL; + // default option + default_option[0]= 0; for (i= 0; (argc > 1) && default_options[i]; i++) { if (!strnicmp(argv[1], default_options[i], strlen(default_options[i]))) @@ -203,73 +203,73 @@ void start_defaults(int argc, char *argv[]) } } - // set after basedir is established - datadir[0]= NULL; - pid_file[0]= NULL; - err_log[0]= NULL; - safe_log[0]= NULL; - mysqld[0]= NULL; -} - -/****************************************************************************** - - finish_defaults() + // set after basedir is established + datadir[0]= 0; + pid_file[0]= 0; + err_log[0]= 0; + safe_log[0]= 0; + mysqld[0]= 0; +} - Finish settig the defaults. - -******************************************************************************/ -void finish_defaults() -{ - struct stat buf; - int i; +/****************************************************************************** - // datadir + finish_defaults() + + Finish settig the defaults. + +******************************************************************************/ +void finish_defaults() +{ + struct stat buf; + int i; + + // datadir if (!datadir[0]) snprintf(datadir, PATH_MAX, "%s/data", basedir); - // pid-file + // pid-file if (!pid_file[0]) snprintf(pid_file, PATH_MAX, "%s/%s.pid", datadir, hostname); - // err-log + // err-log if (!err_log[0]) snprintf(err_log, PATH_MAX, "%s/%s.err", datadir, hostname); - - // safe-log + + // safe-log if (!safe_log[0]) snprintf(safe_log, PATH_MAX, "%s/%s.safe", datadir, hostname); - - // mysqld + + // mysqld if (!mysqld[0]) snprintf(mysqld, PATH_MAX, "%s/bin/mysqld-max", basedir); - if (stat(mysqld, &buf)) - { - snprintf(mysqld, PATH_MAX, "%s/bin/mysqld", basedir); - } -} - -/****************************************************************************** - - read_defaults() + if (stat(mysqld, &buf)) + { + snprintf(mysqld, PATH_MAX, "%s/bin/mysqld", basedir); + } +} - Read the defaults. - -******************************************************************************/ +/****************************************************************************** + + read_defaults() + + Read the defaults. + +******************************************************************************/ void read_defaults(arg_list_t *pal) -{ +{ arg_list_t al; char defaults_file[PATH_MAX]; - char mydefaults[PATH_MAX]; - char line[PATH_MAX]; - FILE *fp; + char mydefaults[PATH_MAX]; + char line[PATH_MAX]; + FILE *fp; // defaults output file snprintf(defaults_file, PATH_MAX, "%s/bin/defaults.out", basedir); remove(defaults_file); // mysqladmin file - snprintf(mydefaults, PATH_MAX, "%s/bin/my_print_defaults", basedir); + snprintf(mydefaults, PATH_MAX, "%s/bin/my_print_defaults", basedir); // args init_args(&al); @@ -290,13 +290,13 @@ void read_defaults(arg_list_t *pal) { while (fgets(line, PATH_MAX, fp)) { - char *p; + char *p; - // remove end-of-line character + // remove end-of-line character if ((p= strrchr(line, '\n')) != NULL) *p= '\0'; - // add the option as an argument + // add the option as an argument add_arg(pal, line); } @@ -305,37 +305,37 @@ void read_defaults(arg_list_t *pal) // remove file remove(defaults_file); -} - -/****************************************************************************** - - parse_args() +} - Get the options. - -******************************************************************************/ -void parse_args(int argc, char *argv[]) -{ +/****************************************************************************** + + parse_args() + + Get the options. + +******************************************************************************/ +void parse_args(int argc, char *argv[]) +{ int index= 0; - int c; + int c; - // parse options - enum opts - { + // parse options + enum opts + { OPT_BASEDIR= 0xFF, - OPT_DATADIR, - OPT_PID_FILE, - OPT_BIND_ADDRESS, - OPT_PORT, - OPT_ERR_LOG, - OPT_SAFE_LOG, + OPT_DATADIR, + OPT_PID_FILE, + OPT_BIND_ADDRESS, + OPT_PORT, + OPT_ERR_LOG, + OPT_SAFE_LOG, OPT_MYSQLD, OPT_HELP, OPT_SETVAR - }; + }; static struct option options[]= - { + { {"autoclose", no_argument, &autoclose, TRUE}, {"basedir", required_argument, 0, OPT_BASEDIR}, {"check-tables", no_argument, &checktables, TRUE}, @@ -349,51 +349,51 @@ void parse_args(int argc, char *argv[]) {"help", no_argument, 0, OPT_HELP}, {"set-variable", required_argument, 0, OPT_SETVAR}, {0, 0, 0, 0} - }; + }; - // we have to reset getopt_long because we use it multiple times + // we have to reset getopt_long because we use it multiple times optind= 1; - // turn off error reporting + // turn off error reporting opterr= 0; while ((c= getopt_long(argc, argv, "b:h:P:", options, &index)) >= 0) - { + { switch (c) { - case OPT_BASEDIR: - case 'b': - strcpy(basedir, optarg); - break; + case OPT_BASEDIR: + case 'b': + strcpy(basedir, optarg); + break; - case OPT_DATADIR: - case 'h': - strcpy(datadir, optarg); - break; + case OPT_DATADIR: + case 'h': + strcpy(datadir, optarg); + break; - case OPT_PID_FILE: - strcpy(pid_file, optarg); - break; + case OPT_PID_FILE: + strcpy(pid_file, optarg); + break; - case OPT_BIND_ADDRESS: - strcpy(address, optarg); - break; + case OPT_BIND_ADDRESS: + strcpy(address, optarg); + break; - case OPT_PORT: - case 'P': - strcpy(port, optarg); - break; + case OPT_PORT: + case 'P': + strcpy(port, optarg); + break; - case OPT_ERR_LOG: - strcpy(err_log, optarg); - break; + case OPT_ERR_LOG: + strcpy(err_log, optarg); + break; - case OPT_SAFE_LOG: - strcpy(safe_log, optarg); - break; + case OPT_SAFE_LOG: + strcpy(safe_log, optarg); + break; - case OPT_MYSQLD: - strcpy(mysqld, optarg); - break; + case OPT_MYSQLD: + strcpy(mysqld, optarg); + break; case OPT_SETVAR: parse_setvar(optarg); @@ -403,13 +403,13 @@ void parse_args(int argc, char *argv[]) usage(); break; - default: - // ignore - break; - } - } -} - + default: + // ignore + break; + } + } +} + /* parse_setvar(char *arg) Pasrsing for port just to display the port num on the mysqld_safe screen @@ -430,148 +430,148 @@ void parse_setvar(char *arg) -/****************************************************************************** - - get_options() +/****************************************************************************** - Get the options. - -******************************************************************************/ -void get_options(int argc, char *argv[]) -{ + get_options() + + Get the options. + +******************************************************************************/ +void get_options(int argc, char *argv[]) +{ arg_list_t al; - // start defaults - start_defaults(argc, argv); - - // default file arguments + // start defaults + start_defaults(argc, argv); + + // default file arguments init_args(&al); add_arg(&al, "ignore"); read_defaults(&al); parse_args(al.argc, al.argv); free_args(&al); - // command-line arguments - parse_args(argc, argv); + // command-line arguments + parse_args(argc, argv); - // finish defaults - finish_defaults(); -} - -/****************************************************************************** - - check_data_vol() + // finish defaults + finish_defaults(); +} - Check the database volume. - -******************************************************************************/ -void check_data_vol() -{ - // warn if the data is on a Traditional volume - struct volume_info vol; - char buff[PATH_MAX]; - char *p; +/****************************************************************************** - // clear struct - memset(&vol, 0, sizeof(vol)); + check_data_vol() - // find volume name - strcpy(buff, datadir); + Check the database volume. + +******************************************************************************/ +void check_data_vol() +{ + // warn if the data is on a Traditional volume + struct volume_info vol; + char buff[PATH_MAX]; + char *p; + + // clear struct + memset(&vol, 0, sizeof(vol)); + + // find volume name + strcpy(buff, datadir); if (p= strchr(buff, ':')) - { - // terminate after volume name + { + // terminate after volume name *p= 0; - } - else - { - // assume SYS volume - strcpy(buff, "SYS"); - } + } + else + { + // assume SYS volume + strcpy(buff, "SYS"); + } - // retrieve information - netware_vol_info_from_name(&vol, buff); + // retrieve information + netware_vol_info_from_name(&vol, buff); - if ((vol.flags & VOL_NSS_PRESENT) == 0) - { + if ((vol.flags & VOL_NSS_PRESENT) == 0) + { log("Error: Either the data directory does not exist or is not on an NSS volume!\n\n"); - exit(-1); - } -} - -/****************************************************************************** - - check_setup() + exit(-1); + } +} - Check the current setup. - -******************************************************************************/ -void check_setup() -{ +/****************************************************************************** + + check_setup() + + Check the current setup. + +******************************************************************************/ +void check_setup() +{ struct stat info; - char temp[PATH_MAX]; + char temp[PATH_MAX]; - // remove any current pid_file + // remove any current pid_file if (!stat(pid_file, &info) && (remove(pid_file) < 0)) { - log("ERROR: Unable to remove current pid file!\n\n"); - exit(-1); + log("ERROR: Unable to remove current pid file!\n\n"); + exit(-1); } // check the data volume - check_data_vol(); + check_data_vol(); - // check for a database - snprintf(temp, PATH_MAX, "%s/mysql/host.frm", datadir); - if (stat(temp, &info)) - { - log("ERROR: No database found in the data directory!\n\n"); - exit(-1); - } -} - -/****************************************************************************** - - check_tables() + // check for a database + snprintf(temp, PATH_MAX, "%s/mysql/host.frm", datadir); + if (stat(temp, &info)) + { + log("ERROR: No database found in the data directory!\n\n"); + exit(-1); + } +} - Check the database tables. - -******************************************************************************/ -void check_tables() -{ +/****************************************************************************** + + check_tables() + + Check the database tables. + +******************************************************************************/ +void check_tables() +{ arg_list_t al; - char mycheck[PATH_MAX]; + char mycheck[PATH_MAX]; char table[PATH_MAX]; char db[PATH_MAX]; DIR *datadir_entry, *db_entry, *table_entry; // status - log("checking tables...\n"); + log("checking tables...\n"); - // list databases + // list databases if ((datadir_entry= opendir(datadir)) == NULL) { return; } - + while ((db_entry= readdir(datadir_entry)) != NULL) { - if (db_entry->d_name[0] == '.') - { - // Skip - } - else if (S_ISDIR(db_entry->d_type)) - { - // create long db name - snprintf(db, PATH_MAX, "%s/%s", datadir, db_entry->d_name); + if (db_entry->d_name[0] == '.') + { + // Skip + } + else if (S_ISDIR(db_entry->d_type)) + { + // create long db name + snprintf(db, PATH_MAX, "%s/%s", datadir, db_entry->d_name); - // list tables + // list tables if ((db_entry= opendir(db)) == NULL) - { + { continue; - } + } while ((table_entry= readdir(db_entry)) != NULL) - { + { // create long table name snprintf(table, PATH_MAX, "%s/%s", db, strlwr(table_entry->d_name)); @@ -581,7 +581,7 @@ void check_tables() // mysqladmin file snprintf(mycheck, PATH_MAX, "%s/bin/myisamchk", basedir); - + // args init_args(&al); add_arg(&al, mycheck); @@ -594,7 +594,7 @@ void check_tables() add_arg(&al, "-O"); add_arg(&al, "sort_buffer=64M"); add_arg(&al, table); - + spawn(mycheck, &al, TRUE, NULL, NULL, NULL); free_args(&al); @@ -619,20 +619,20 @@ void check_tables() free_args(&al); } - } - } + } + } } -} - -/****************************************************************************** - - mysql_start() +} - Start the mysql server. - -******************************************************************************/ -void mysql_start(int argc, char *argv[]) -{ +/****************************************************************************** + + mysql_start() + + Start the mysql server. + +******************************************************************************/ +void mysql_start(int argc, char *argv[]) +{ arg_list_t al; int i, j, err; struct stat info; @@ -641,16 +641,16 @@ void mysql_start(int argc, char *argv[]) char stamp[PATH_MAX]; char skip; - // private options + // private options static char *private_options[]= - { + { "--autoclose", "--check-tables", "--help", "--err-log=", "--mysqld=", NULL - }; + }; // args init_args(&al); @@ -661,22 +661,22 @@ void mysql_start(int argc, char *argv[]) { skip= FALSE; - // skip private arguments + // skip private arguments for (j= 0; private_options[j]; j++) - { + { if (!strnicmp(argv[i], private_options[j], strlen(private_options[j]))) - { + { skip= TRUE; break; - } - } + } + } if (!skip) { add_arg(&al, "%s", argv[i]); } } - // spawn + // spawn do { // check the database tables @@ -684,10 +684,10 @@ void mysql_start(int argc, char *argv[]) check_tables(); // status - time(&cal); - localtime_r(&cal, <); - strftime(stamp, PATH_MAX, "%d %b %Y %H:%M:%S", <); - log("mysql started : %s\n", stamp); + time(&cal); + localtime_r(&cal, <); + strftime(stamp, PATH_MAX, "%d %b %Y %H:%M:%S", <); + log("mysql started : %s\n", stamp); // spawn mysqld spawn(mysqld, &al, TRUE, NULL, NULL, err_log); @@ -695,57 +695,57 @@ void mysql_start(int argc, char *argv[]) while (!stat(pid_file, &info)); // status - time(&cal); - localtime_r(&cal, <); - strftime(stamp, PATH_MAX, "%d %b %Y %H:%M:%S", <); - log("mysql stopped : %s\n\n", stamp); + time(&cal); + localtime_r(&cal, <); + strftime(stamp, PATH_MAX, "%d %b %Y %H:%M:%S", <); + log("mysql stopped : %s\n\n", stamp); // free args free_args(&al); -} - -/****************************************************************************** - - main() +} -******************************************************************************/ -int main(int argc, char **argv) -{ +/****************************************************************************** + + main() + +******************************************************************************/ +int main(int argc, char **argv) +{ char temp[PATH_MAX]; - // get the options + // get the options get_options(argc, argv); - - // keep the screen up + + // keep the screen up if (!autoclose) setscreenmode(SCR_NO_MODE); - // create log file + // create log file log_fd= fopen(safe_log, "w+"); - // header - log("MySQL Server %s, for %s (%s)\n\n", VERSION, SYSTEM_TYPE, MACHINE_TYPE); + // header + log("MySQL Server %s, for %s (%s)\n\n", VERSION, SYSTEM_TYPE, MACHINE_TYPE); // status log("address : %s\n", address); log("port : %s\n", port); - log("daemon : %s\n", mysqld); + log("daemon : %s\n", mysqld); log("base directory : %s\n", basedir); log("data directory : %s\n", datadir); log("pid file : %s\n", pid_file); log("error file : %s\n", err_log); log("log file : %s\n", safe_log); - log("\n"); + log("\n"); - // check setup - check_setup(); + // check setup + check_setup(); - // start the MySQL server + // start the MySQL server mysql_start(argc, argv); // close log file if (log_fd) fclose(log_fd); - return 0; -} + return 0; +} From 921004e79dfece9bd4cc4239521b190c82f19560 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Fri, 2 Dec 2011 00:36:55 +0200 Subject: [PATCH 158/288] Added new file (for netware) Added some file to ignore --- .bzrignore | 2 ++ netware/mysql_tzinfo_to_sql.def | 11 +++++++++++ 2 files changed, 13 insertions(+) create mode 100644 netware/mysql_tzinfo_to_sql.def diff --git a/.bzrignore b/.bzrignore index 68f47a7f1f2..a956e0c6ab4 100644 --- a/.bzrignore +++ b/.bzrignore @@ -1980,3 +1980,5 @@ plugin/handler_socket/perl-Net-HandlerSocket/blib plugin/handler_socket/perl-Net-HandlerSocket/pm_to_blib plugin/handler_socket/perl-Net-HandlerSocket/HandlerSocket.bs plugin/handler_socket/perl-Net-HandlerSocket/Makefile.PL +libmysqld/gcalc_slicescan.cc +libmysqld/gcalc_tools.cc diff --git a/netware/mysql_tzinfo_to_sql.def b/netware/mysql_tzinfo_to_sql.def new file mode 100644 index 00000000000..ff9d35a07fa --- /dev/null +++ b/netware/mysql_tzinfo_to_sql.def @@ -0,0 +1,11 @@ +#------------------------------------------------------------------------------ +# MySQL TzInfo To SQL +#------------------------------------------------------------------------------ +MODULE libc.nlm +COPYRIGHT "(c) 2003-2005 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." +DESCRIPTION "MySQL Tool - Create Time Zone Info to SQL" +VERSION 5, 0 +STACKSIZE 131072 +XDCDATA ../netware/mysql.xdc +#DEBUG + From b522a6ce78bfe7bea3e52715c993c7d190159139 Mon Sep 17 00:00:00 2001 From: Tor Didriksen Date: Fri, 2 Dec 2011 14:16:48 +0100 Subject: [PATCH 159/288] Bug#11761576 54082: HANDLE_SEGFAULT MAKES USE OF UNSAFE FUNCTIONS handle_segfault is the signal handler code of mysqld. however, it makes calls to potentially unsafe functions localtime_r, fprintf, fflush. include/my_stacktrace.h: Add safe versions of itoa() write() and snprintf(). libmysqld/CMakeLists.txt: Move signal handler to separate file. mysys/stacktrace.c: Remove unsafe function calls. sql/CMakeLists.txt: Move signal handler to separate file. sql/mysqld.cc: Move signal handler to separate file. sql/set_var.h: Add missing #include dependency. sql/sys_vars.cc: Cleanup .h and .cc files. sql/sys_vars.h: Cleanup .h and .cc files. --- include/my_stacktrace.h | 65 +++++++- libmysqld/CMakeLists.txt | 1 + mysys/stacktrace.c | 334 ++++++++++++++++++++++++++++++++------- sql/CMakeLists.txt | 1 + sql/mysqld.cc | 187 +++------------------- sql/set_var.h | 1 + sql/signal_handler.cc | 6 +- sql/sys_vars.cc | 73 +++++++++ sql/sys_vars.h | 71 --------- 9 files changed, 435 insertions(+), 304 deletions(-) diff --git a/include/my_stacktrace.h b/include/my_stacktrace.h index df5741fa3d8..ee038678947 100644 --- a/include/my_stacktrace.h +++ b/include/my_stacktrace.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2001, 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 @@ -59,6 +59,69 @@ void my_set_exception_pointers(EXCEPTION_POINTERS *ep); void my_write_core(int sig); #endif + + +/** + Async-signal-safe utility functions used by signal handler routines. + Declared here in order to unit-test them. + These are not general-purpose, but tailored to the signal handling routines. +*/ +/** + Converts a longlong value to string. + @param base 10 for decimal, 16 for hex values (0..9a..f) + @param val The value to convert + @param buf Assumed to point to the *end* of the buffer. + @returns Pointer to the first character of the converted string. + Negative values: + for base-10 the return string will be prepended with '-' + for base-16 the return string will contain 16 characters + Implemented with simplicity, and async-signal-safety in mind. +*/ +char *my_safe_itoa(int base, longlong val, char *buf); + +/** + Converts a ulonglong value to string. + @param base 10 for decimal, 16 for hex values (0..9a..f) + @param val The value to convert + @param buf Assumed to point to the *end* of the buffer. + @returns Pointer to the first character of the converted string. + Implemented with simplicity, and async-signal-safety in mind. +*/ +char *my_safe_utoa(int base, ulonglong val, char *buf); + +/** + A (very) limited version of snprintf. + @param to Destination buffer. + @param n Size of destination buffer. + @param fmt printf() style format string. + @returns Number of bytes written, including terminating '\0' + Supports 'd' 'i' 'u' 'x' 'p' 's' conversion. + Supports 'l' and 'll' modifiers for integral types. + Does not support any width/precision. + Implemented with simplicity, and async-signal-safety in mind. +*/ +size_t my_safe_snprintf(char* to, size_t n, const char* fmt, ...) + ATTRIBUTE_FORMAT(printf, 3, 4); + +/** + A (very) limited version of snprintf, which writes the result to STDERR. + @sa my_safe_snprintf + Implemented with simplicity, and async-signal-safety in mind. + @note Has an internal buffer capacity of 512 bytes, + which should suffice for our signal handling routines. +*/ +size_t my_safe_printf_stderr(const char* fmt, ...) + ATTRIBUTE_FORMAT(printf, 1, 2); + +/** + Writes up to count bytes from buffer to STDERR. + Implemented with simplicity, and async-signal-safety in mind. + @param buf Buffer containing data to be written. + @param count Number of bytes to write. + @returns Number of bytes written. +*/ +size_t my_write_stderr(const void *buf, size_t count); + C_MODE_END #endif /* _my_stacktrace_h_ */ diff --git a/libmysqld/CMakeLists.txt b/libmysqld/CMakeLists.txt index 25f4b752a30..3019f234b14 100644 --- a/libmysqld/CMakeLists.txt +++ b/libmysqld/CMakeLists.txt @@ -45,6 +45,7 @@ SET(SQL_EMBEDDED_SOURCES emb_qcache.cc libmysqld.c lib_sql.cc ../sql/password.c ../sql/discover.cc ../sql/derror.cc ../sql/field.cc ../sql/field_conv.cc ../sql/filesort.cc ../sql/gstream.cc + ../sql/signal_handler.cc ../sql/handler.cc ../sql/hash_filo.cc ../sql/hostname.cc ../sql/init.cc ../sql/item_buff.cc ../sql/item_cmpfunc.cc ../sql/item.cc ../sql/item_create.cc ../sql/item_func.cc diff --git a/mysys/stacktrace.c b/mysys/stacktrace.c index 5efe44a037d..175ee8a3025 100644 --- a/mysys/stacktrace.c +++ b/mysys/stacktrace.c @@ -52,10 +52,11 @@ void my_init_stacktrace() static void print_buffer(char *buffer, size_t count) { + const char s[]= " "; for (; count && *buffer; --count) { - int c= (int) *buffer++; - fputc(isprint(c) ? c : ' ', stderr); + my_write_stderr(isprint(*buffer) ? buffer : s, 1); + ++buffer; } } @@ -119,10 +120,10 @@ static int safe_print_str(const char *addr, int max_len) /* Output a new line if something was printed. */ if (total != (size_t) max_len) - fputc('\n', stderr); + my_safe_printf_stderr("%s", "\n"); if (nbytes == -1) - fprintf(stderr, "Can't read from address %p: %m.\n", addr); + my_safe_printf_stderr("Can't read from address %p\n", addr); close(fd); @@ -144,13 +145,13 @@ void my_safe_print_str(const char* val, int max_len) if (!PTR_SANE(val)) { - fprintf(stderr, "is an invalid pointer\n"); + my_safe_printf_stderr("%s", "is an invalid pointer\n"); return; } for (; max_len && PTR_SANE(val) && *val; --max_len) - fputc(*val++, stderr); - fputc('\n', stderr); + my_write_stderr((val++), 1); + my_safe_printf_stderr("%s", "\n"); } #if defined(HAVE_PRINTSTACK) @@ -162,14 +163,15 @@ void my_print_stacktrace(uchar* stack_bottom __attribute__((unused)), ulong thread_stack __attribute__((unused))) { if (printstack(fileno(stderr)) == -1) - fprintf(stderr, "Error when traversing the stack, stack appears corrupt.\n"); + my_safe_printf_stderr("%s", + "Error when traversing the stack, stack appears corrupt.\n"); else - fprintf(stderr, - "Please read " - "http://dev.mysql.com/doc/refman/5.1/en/resolve-stack-dump.html\n" - "and follow instructions on how to resolve the stack trace.\n" - "Resolved stack trace is much more helpful in diagnosing the\n" - "problem, so please do resolve it\n"); + my_safe_printf_stderr("%s" + "Please read " + "http://dev.mysql.com/doc/refman/5.1/en/resolve-stack-dump.html\n" + "and follow instructions on how to resolve the stack trace.\n" + "Resolved stack trace is much more helpful in diagnosing the\n" + "problem, so please do resolve it\n"); } #elif HAVE_BACKTRACE && (HAVE_BACKTRACE_SYMBOLS || HAVE_BACKTRACE_SYMBOLS_FD) @@ -207,9 +209,9 @@ static void my_demangle_symbols(char **addrs, int n) } if (demangled) - fprintf(stderr, "%s(%s+%s\n", addrs[i], demangled, end); + my_safe_printf_stderr("%s(%s+%s\n", addrs[i], demangled, end); else - fprintf(stderr, "%s\n", addrs[i]); + my_safe_printf_stderr("%s\n", addrs[i]); } } @@ -220,8 +222,8 @@ void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack) void *addrs[128]; char **strings= NULL; int n = backtrace(addrs, array_elements(addrs)); - fprintf(stderr, "stack_bottom = %p thread_stack 0x%lx\n", - stack_bottom, thread_stack); + my_safe_printf_stderr("stack_bottom = %p thread_stack 0x%lx\n", + stack_bottom, thread_stack); #if BACKTRACE_DEMANGLE if ((strings= backtrace_symbols(addrs, n))) { @@ -314,8 +316,9 @@ void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack) #endif if (!fp) { - fprintf(stderr, "frame pointer is NULL, did you compile with\n\ --fomit-frame-pointer? Aborting backtrace!\n"); + my_safe_printf_stderr("%s", + "frame pointer is NULL, did you compile with\n" + "-fomit-frame-pointer? Aborting backtrace!\n"); return; } @@ -323,24 +326,28 @@ void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack) { ulong tmp= min(0x10000,thread_stack); /* Assume that the stack starts at the previous even 65K */ - stack_bottom= (uchar*) (((ulong) &fp + tmp) & - ~(ulong) 0xFFFF); - fprintf(stderr, "Cannot determine thread, fp=%p, backtrace may not be correct.\n", fp); + stack_bottom= (uchar*) (((ulong) &fp + tmp) & ~(ulong) 0xFFFF); + my_safe_printf_stderr("Cannot determine thread, fp=%p, " + "backtrace may not be correct.\n", fp); } if (fp > (uchar**) stack_bottom || fp < (uchar**) stack_bottom - thread_stack) { - fprintf(stderr, "Bogus stack limit or frame pointer,\ - fp=%p, stack_bottom=%p, thread_stack=%ld, aborting backtrace.\n", - fp, stack_bottom, thread_stack); + my_safe_printf_stderr("Bogus stack limit or frame pointer, " + "fp=%p, stack_bottom=%p, thread_stack=%ld, " + "aborting backtrace.\n", + fp, stack_bottom, thread_stack); return; } - fprintf(stderr, "Stack range sanity check OK, backtrace follows:\n"); + my_safe_printf_stderr("%s", + "Stack range sanity check OK, backtrace follows:\n"); #if defined(__alpha__) && defined(__GNUC__) - fprintf(stderr, "Warning: Alpha stacks are difficult -\ - will be taking some wild guesses, stack trace may be incorrect or \ - terminate abruptly\n"); + my_safe_printf_stderr("%s", + "Warning: Alpha stacks are difficult -" + "will be taking some wild guesses, stack trace may be incorrect or " + "terminate abruptly\n"); + /* On Alpha, we need to get pc */ __asm __volatile__ ("bsr %0, do_next; do_next: " :"=r"(pc) @@ -354,8 +361,9 @@ void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack) { #if defined(__i386__) || defined(__x86_64__) uchar** new_fp = (uchar**)*fp; - fprintf(stderr, "%p\n", frame_count == sigreturn_frame_count ? - *(fp + SIGRETURN_FRAME_OFFSET) : *(fp + 1)); + my_safe_printf_stderr("%p\n", + frame_count == sigreturn_frame_count ? + *(fp + SIGRETURN_FRAME_OFFSET) : *(fp + 1)); #endif /* defined(__386__) || defined(__x86_64__) */ #if defined(__alpha__) && defined(__GNUC__) @@ -369,38 +377,40 @@ void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack) { pc = find_prev_pc(pc, fp); if (pc) - fprintf(stderr, "%p\n", pc); + my_safe_printf_stderr("%p\n", pc); else { - fprintf(stderr, "Not smart enough to deal with the rest\ - of this stack\n"); + my_safe_printf_stderr("%s", + "Not smart enough to deal with the rest of this stack\n"); goto end; } } else { - fprintf(stderr, "Not smart enough to deal with the rest of this stack\n"); + my_safe_printf_stderr("%s", + "Not smart enough to deal with the rest of this stack\n"); goto end; } #endif /* defined(__alpha__) && defined(__GNUC__) */ if (new_fp <= fp ) { - fprintf(stderr, "New value of fp=%p failed sanity check,\ - terminating stack trace!\n", new_fp); + my_safe_printf_stderr("New value of fp=%p failed sanity check, " + "terminating stack trace!\n", new_fp); goto end; } fp = new_fp; ++frame_count; } - - fprintf(stderr, "Stack trace seems successful - bottom reached\n"); + my_safe_printf_stderr("%s", + "Stack trace seems successful - bottom reached\n"); end: - fprintf(stderr, - "Please read http://dev.mysql.com/doc/refman/5.1/en/resolve-stack-dump.html\n" - "and follow instructions on how to resolve the stack trace.\n" - "Resolved stack trace is much more helpful in diagnosing the\n" - "problem, so please do resolve it\n"); + my_safe_printf_stderr("%s", + "Please read " + "http://dev.mysql.com/doc/refman/5.1/en/resolve-stack-dump.html\n" + "and follow instructions on how to resolve the stack trace.\n" + "Resolved stack trace is much more helpful in diagnosing the\n" + "problem, so please do resolve it\n"); } #endif /* TARGET_OS_LINUX */ #endif /* HAVE_STACKTRACE */ @@ -618,7 +628,7 @@ void my_print_stacktrace(uchar* unused1, ulong unused2) &(package.sym)); have_source= SymGetLineFromAddr64(hProcess, addr, &line_offset, &line); - fprintf(stderr, "%p ", addr); + my_safe_printf_stderr("%p ", addr); if(have_module) { char *base_image_name= strrchr(module.ImageName, '\\'); @@ -626,12 +636,13 @@ void my_print_stacktrace(uchar* unused1, ulong unused2) base_image_name++; else base_image_name= module.ImageName; - fprintf(stderr, "%s!", base_image_name); + my_safe_printf_stderr("%s!", base_image_name); } if(have_symbol) - fprintf(stderr, "%s()", package.sym.Name); + my_safe_printf_stderr("%s()", package.sym.Name); + else if(have_module) - fprintf(stderr, "???"); + my_safe_printf_stderr("%s", "???"); if(have_source) { @@ -640,11 +651,11 @@ void my_print_stacktrace(uchar* unused1, ulong unused2) base_file_name++; else base_file_name= line.FileName; - fprintf(stderr,"[%s:%u]", base_file_name, line.LineNumber); + my_safe_printf_stderr("[%s:%u]", + base_file_name, line.LineNumber); } - fprintf(stderr, "\n"); + my_safe_printf_stderr("%s", "\n"); } - fflush(stderr); } @@ -681,22 +692,22 @@ void my_write_core(int unused) if(MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &info, 0, 0)) { - fprintf(stderr, "Minidump written to %s\n", - _fullpath(path, dump_fname, sizeof(path)) ? path : dump_fname); + my_safe_printf_stderr("Minidump written to %s\n", + _fullpath(path, dump_fname, sizeof(path)) ? + path : dump_fname); } else { - fprintf(stderr,"MiniDumpWriteDump() failed, last error %u\n", - GetLastError()); + my_safe_printf_stderr("MiniDumpWriteDump() failed, last error %u\n", + (uint) GetLastError()); } CloseHandle(hFile); } else { - fprintf(stderr, "CreateFile(%s) failed, last error %u\n", dump_fname, - GetLastError()); + my_safe_printf_stderr("CreateFile(%s) failed, last error %u\n", + dump_fname, (uint) GetLastError()); } - fflush(stderr); } @@ -704,11 +715,212 @@ void my_safe_print_str(const char *val, int len) { __try { - fprintf(stderr, "%.*s\n", len, val); + my_write_stderr(val, len); } __except(EXCEPTION_EXECUTE_HANDLER) { - fprintf(stderr, "is an invalid string pointer\n"); + my_safe_printf_stderr("%s", "is an invalid string pointer\n"); } } #endif /*__WIN__*/ + + +#ifdef __WIN__ +size_t my_write_stderr(const void *buf, size_t count) +{ + DWORD bytes_written; + SetFilePointer(GetStdHandle(STD_ERROR_HANDLE), 0, NULL, FILE_END); + WriteFile(GetStdHandle(STD_ERROR_HANDLE), buf, count, &bytes_written, NULL); + return bytes_written; +} +#else +size_t my_write_stderr(const void *buf, size_t count) +{ + return (size_t) write(STDERR_FILENO, buf, count); +} +#endif + + +static const char digits[]= "0123456789abcdef"; + +char *my_safe_utoa(int base, ulonglong val, char *buf) +{ + *buf--= 0; + do { + *buf--= digits[val % base]; + } while ((val /= base) != 0); + return buf + 1; +} + + +char *my_safe_itoa(int base, longlong val, char *buf) +{ + char *orig_buf= buf; + const my_bool is_neg= (val < 0); + *buf--= 0; + + if (is_neg) + val= -val; + if (is_neg && base == 16) + { + int ix; + val-= 1; + for (ix= 0; ix < 16; ++ix) + buf[-ix]= '0'; + } + + do { + *buf--= digits[val % base]; + } while ((val /= base) != 0); + + if (is_neg && base == 10) + *buf--= '-'; + + if (is_neg && base == 16) + { + int ix; + buf= orig_buf - 1; + for (ix= 0; ix < 16; ++ix, --buf) + { + switch (*buf) + { + case '0': *buf= 'f'; break; + case '1': *buf= 'e'; break; + case '2': *buf= 'd'; break; + case '3': *buf= 'c'; break; + case '4': *buf= 'b'; break; + case '5': *buf= 'a'; break; + case '6': *buf= '9'; break; + case '7': *buf= '8'; break; + case '8': *buf= '7'; break; + case '9': *buf= '6'; break; + case 'a': *buf= '5'; break; + case 'b': *buf= '4'; break; + case 'c': *buf= '3'; break; + case 'd': *buf= '2'; break; + case 'e': *buf= '1'; break; + case 'f': *buf= '0'; break; + } + } + } + return buf+1; +} + + +static const char *check_longlong(const char *fmt, my_bool *have_longlong) +{ + *have_longlong= FALSE; + if (*fmt == 'l') + { + fmt++; + if (*fmt != 'l') + *have_longlong= (sizeof(long) == sizeof(longlong)); + else + { + fmt++; + *have_longlong= TRUE; + } + } + return fmt; +} + +static size_t my_safe_vsnprintf(char *to, size_t size, + const char* format, va_list ap) +{ + char *start= to; + char *end= start + size - 1; + for (; *format; ++format) + { + my_bool have_longlong = FALSE; + if (*format != '%') + { + if (to == end) /* end of buffer */ + break; + *to++= *format; /* copy ordinary char */ + continue; + } + ++format; /* skip '%' */ + + format= check_longlong(format, &have_longlong); + + switch (*format) + { + case 'd': + case 'i': + case 'u': + case 'x': + case 'p': + { + longlong ival= 0; + ulonglong uval = 0; + if (*format == 'p') + have_longlong= (sizeof(void *) == sizeof(longlong)); + if (have_longlong) + { + if (*format == 'u') + uval= va_arg(ap, ulonglong); + else + ival= va_arg(ap, longlong); + } + else + { + if (*format == 'u') + uval= va_arg(ap, unsigned int); + else + ival= va_arg(ap, int); + } + + { + char buff[22]; + const int base= (*format == 'x' || *format == 'p') ? 16 : 10; + char *val_as_str= (*format == 'u') ? + my_safe_utoa(base, uval, &buff[sizeof(buff)-1]) : + my_safe_itoa(base, ival, &buff[sizeof(buff)-1]); + + /* Strip off "ffffffff" if we have 'x' format without 'll' */ + if (*format == 'x' && !have_longlong && ival < 0) + val_as_str+= 8; + + while (*val_as_str && to < end) + *to++= *val_as_str++; + continue; + } + } + case 's': + { + const char *val= va_arg(ap, char*); + if (!val) + val= "(null)"; + while (*val && to < end) + *to++= *val++; + continue; + } + } + } + *to= 0; + return to - start; +} + + +size_t my_safe_snprintf(char* to, size_t n, const char* fmt, ...) +{ + size_t result; + va_list args; + va_start(args,fmt); + result= my_safe_vsnprintf(to, n, fmt, args); + va_end(args); + return result; +} + + +size_t my_safe_printf_stderr(const char* fmt, ...) +{ + char to[512]; + size_t result; + va_list args; + va_start(args,fmt); + result= my_safe_vsnprintf(to, sizeof(to), fmt, args); + va_end(args); + my_write_stderr(to, result); + return result; +} diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 2e02e67c2c9..09672561c11 100644 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -41,6 +41,7 @@ SET (SQL_SOURCE ../sql-common/client.c derror.cc des_key_file.cc discover.cc ../libmysql/errmsg.c field.cc field_conv.cc filesort.cc gstream.cc sha2.cc + signal_handler.cc handler.cc hash_filo.h sql_plugin_services.h hostname.cc init.cc item.cc item_buff.cc item_cmpfunc.cc item_create.cc item_func.cc item_geofunc.cc item_row.cc diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 285b10154ce..7363128ec04 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -144,9 +144,6 @@ extern "C" { // Because of SCO 3.2V4.2 #ifdef __WIN__ #include -#define SIGNAL_FMT "exception 0x%x" -#else -#define SIGNAL_FMT "signal %d" #endif #ifdef HAVE_SOLARIS_LARGE_PAGES @@ -256,7 +253,7 @@ inline void setup_fpu() extern "C" int gethostname(char *name, int namelen); #endif -extern "C" sig_handler handle_segfault(int sig); +extern "C" sig_handler handle_fatal_signal(int sig); #if defined(__linux__) #define ENABLE_TEMP_POOL 1 @@ -323,6 +320,10 @@ static PSI_rwlock_key key_rwlock_openssl; #endif #endif /* HAVE_PSI_INTERFACE */ +#ifdef HAVE_NPTL +volatile sig_atomic_t ld_assume_kernel_is_set= 0; +#endif + /* the default log output is log tables */ static bool lower_case_table_names_used= 0; static bool max_long_data_size_used= false; @@ -333,7 +334,7 @@ static my_bool opt_debugging= 0, opt_external_locking= 0, opt_console= 0; static my_bool opt_short_log_format= 0; static uint kill_cached_threads, wake_thread; static ulong killed_threads; -static ulong max_used_connections; + ulong max_used_connections; static volatile ulong cached_thread_count= 0; static char *mysqld_user, *mysqld_chroot; static char *default_character_set_name; @@ -442,7 +443,7 @@ my_bool sp_automatic_privileges= 1; ulong opt_binlog_rows_event_max_size; const char *binlog_format_names[]= {"MIXED", "STATEMENT", "ROW", NullS}; #ifdef HAVE_INITGROUPS -static bool calling_initgroups= FALSE; /**< Used in SIGSEGV handler. */ +volatile sig_atomic_t calling_initgroups= 0; /**< Used in SIGSEGV handler. */ #endif uint mysqld_port, test_flags, select_errors, dropping_tables, ha_open_options; uint mysqld_port_timeout; @@ -656,7 +657,9 @@ char *opt_logname, *opt_slow_logname, *opt_bin_logname; /* Static variables */ -static bool kill_in_progress, segfaulted; +static volatile sig_atomic_t kill_in_progress; + + static my_bool opt_bootstrap, opt_myisam_log; static int cleanup_done; static ulong opt_specialflag; @@ -1703,9 +1706,9 @@ static void set_user(const char *user, struct passwd *user_info_arg) calling_initgroups as a flag to the SIGSEGV handler that is then used to output a specific message to help the user resolve this problem. */ - calling_initgroups= TRUE; + calling_initgroups= 1; initgroups((char*) user, user_info_arg->pw_gid); - calling_initgroups= FALSE; + calling_initgroups= 0; #endif if (setgid(user_info_arg->pw_gid) == -1) { @@ -2335,7 +2338,7 @@ LONG WINAPI my_unhandler_exception_filter(EXCEPTION_POINTERS *ex_pointers) __try { my_set_exception_pointers(ex_pointers); - handle_segfault(ex_pointers->ExceptionRecord->ExceptionCode); + handle_fatal_signal(ex_pointers->ExceptionRecord->ExceptionCode); } __except(EXCEPTION_EXECUTE_HANDLER) { @@ -2409,161 +2412,6 @@ extern "C" char *my_demangle(const char *mangled_name, int *status) #endif -extern "C" sig_handler handle_segfault(int sig) -{ - time_t curr_time; - struct tm tm; - - /* - Strictly speaking, one needs a mutex here - but since we have got SIGSEGV already, things are a mess - so not having the mutex is not as bad as possibly using a buggy - mutex - so we keep things simple - */ - if (segfaulted) - { - fprintf(stderr, "Fatal " SIGNAL_FMT " while backtracing\n", sig); - exit(1); - } - - segfaulted = 1; - - curr_time= my_time(0); - localtime_r(&curr_time, &tm); - - fprintf(stderr,"\ -%02d%02d%02d %2d:%02d:%02d - mysqld got " SIGNAL_FMT " ;\n\ -This could be because you hit a bug. It is also possible that this binary\n\ -or one of the libraries it was linked against is corrupt, improperly built,\n\ -or misconfigured. This error can also be caused by malfunctioning hardware.\n", - tm.tm_year % 100, tm.tm_mon+1, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec, - sig); - fprintf(stderr, "\ -We will try our best to scrape up some info that will hopefully help diagnose\n\ -the problem, but since we have already crashed, something is definitely wrong\n\ -and this may fail.\n\n"); - fprintf(stderr, "key_buffer_size=%lu\n", - (ulong) dflt_key_cache->key_cache_mem_size); - fprintf(stderr, "read_buffer_size=%ld\n", (long) global_system_variables.read_buff_size); - fprintf(stderr, "max_used_connections=%lu\n", max_used_connections); - fprintf(stderr, "max_threads=%u\n", thread_scheduler->max_threads); - fprintf(stderr, "thread_count=%u\n", thread_count); - fprintf(stderr, "connection_count=%u\n", connection_count); - fprintf(stderr, "It is possible that mysqld could use up to \n\ -key_buffer_size + (read_buffer_size + sort_buffer_size)*max_threads = %lu K\n\ -bytes of memory\n", ((ulong) dflt_key_cache->key_cache_mem_size + - (global_system_variables.read_buff_size + - global_system_variables.sortbuff_size) * - thread_scheduler->max_threads + - max_connections * sizeof(THD)) / 1024); - fprintf(stderr, "Hope that's ok; if not, decrease some variables in the equation.\n\n"); - -#if defined(HAVE_LINUXTHREADS) - if (sizeof(char*) == 4 && thread_count > UNSAFE_DEFAULT_LINUX_THREADS) - { - fprintf(stderr, "\ -You seem to be running 32-bit Linux and have %d concurrent connections.\n\ -If you have not changed STACK_SIZE in LinuxThreads and built the binary \n\ -yourself, LinuxThreads is quite likely to steal a part of the global heap for\n\ -the thread stack. Please read http://dev.mysql.com/doc/mysql/en/linux.html\n\n", - thread_count); - } -#endif /* HAVE_LINUXTHREADS */ - -#ifdef HAVE_STACKTRACE - THD *thd=current_thd; - - if (!(test_flags & TEST_NO_STACKTRACE)) - { - fprintf(stderr, "Thread pointer: 0x%lx\n", (long) thd); - fprintf(stderr, "Attempting backtrace. You can use the following " - "information to find out\nwhere mysqld died. If " - "you see no messages after this, something went\n" - "terribly wrong...\n"); - my_print_stacktrace(thd ? (uchar*) thd->thread_stack : NULL, - my_thread_stack_size); - } - if (thd) - { - const char *kreason= "UNKNOWN"; - switch (thd->killed) { - case THD::NOT_KILLED: - kreason= "NOT_KILLED"; - break; - case THD::KILL_BAD_DATA: - kreason= "KILL_BAD_DATA"; - break; - case THD::KILL_CONNECTION: - kreason= "KILL_CONNECTION"; - break; - case THD::KILL_QUERY: - kreason= "KILL_QUERY"; - break; - case THD::KILLED_NO_VALUE: - kreason= "KILLED_NO_VALUE"; - break; - } - fprintf(stderr, "\nTrying to get some variables.\n" - "Some pointers may be invalid and cause the dump to abort.\n"); - fprintf(stderr, "Query (%p): ", thd->query()); - my_safe_print_str(thd->query(), min(1024, thd->query_length())); - fprintf(stderr, "Connection ID (thread ID): %lu\n", (ulong) thd->thread_id); - fprintf(stderr, "Status: %s\n", kreason); - fputc('\n', stderr); - } - fprintf(stderr, "\ -The manual page at http://dev.mysql.com/doc/mysql/en/crashing.html contains\n\ -information that should help you find out what is causing the crash.\n"); - fflush(stderr); -#endif /* HAVE_STACKTRACE */ - -#ifdef HAVE_INITGROUPS - if (calling_initgroups) - fprintf(stderr, "\n\ -This crash occured while the server was calling initgroups(). This is\n\ -often due to the use of a mysqld that is statically linked against glibc\n\ -and configured to use LDAP in /etc/nsswitch.conf. You will need to either\n\ -upgrade to a version of glibc that does not have this problem (2.3.4 or\n\ -later when used with nscd), disable LDAP in your nsswitch.conf, or use a\n\ -mysqld that is not statically linked.\n"); -#endif - -#ifdef HAVE_NPTL - if (thd_lib_detected == THD_LIB_LT && !getenv("LD_ASSUME_KERNEL")) - fprintf(stderr,"\n\ -You are running a statically-linked LinuxThreads binary on an NPTL system.\n\ -This can result in crashes on some distributions due to LT/NPTL conflicts.\n\ -You should either build a dynamically-linked binary, or force LinuxThreads\n\ -to be used with the LD_ASSUME_KERNEL environment variable. Please consult\n\ -the documentation for your distribution on how to do that.\n"); -#endif - - if (locked_in_memory) - { - fprintf(stderr, "\n\ -The \"--memlock\" argument, which was enabled, uses system calls that are\n\ -unreliable and unstable on some operating systems and operating-system\n\ -versions (notably, some versions of Linux). This crash could be due to use\n\ -of those buggy OS calls. You should consider whether you really need the\n\ -\"--memlock\" parameter and/or consult the OS distributer about \"mlockall\"\n\ -bugs.\n"); - } - -#ifdef HAVE_WRITE_CORE - if (test_flags & TEST_CORE_ON_SIGNAL) - { - fprintf(stderr, "Writing a core file\n"); - fflush(stderr); - my_write_core(sig); - } -#endif - -#ifndef __WIN__ - /* On Windows, do not terminate, but pass control to exception filter */ - exit(1); -#endif -} #if !defined(__WIN__) #ifndef SA_RESETHAND @@ -2593,9 +2441,9 @@ static void init_signals(void) my_init_stacktrace(); #endif #if defined(__amiga__) - sa.sa_handler=(void(*)())handle_segfault; + sa.sa_handler=(void(*)())handle_fatal_signal; #else - sa.sa_handler=handle_segfault; + sa.sa_handler=handle_fatal_signal; #endif sigaction(SIGSEGV, &sa, NULL); sigaction(SIGABRT, &sa, NULL); @@ -4282,6 +4130,9 @@ int mysqld_main(int argc, char **argv) to be able to read defaults files and parse options. */ my_progname= argv[0]; +#ifdef HAVE_NPTL + ld_assume_kernel_is_set= (getenv("LD_ASSUME_KERNEL") != 0); +#endif #ifndef _WIN32 // For windows, my_init() is called from the win specific mysqld_main if (my_init()) // init my_sys library & pthreads @@ -6778,7 +6629,7 @@ static int mysql_init_variables(void) opt_secure_auth= 0; opt_bootstrap= opt_myisam_log= 0; mqh_used= 0; - segfaulted= kill_in_progress= 0; + kill_in_progress= 0; cleanup_done= 0; server_id_supplied= 0; test_flags= select_errors= dropping_tables= ha_open_options=0; diff --git a/sql/set_var.h b/sql/set_var.h index 52679aa636c..990112362f8 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -34,6 +34,7 @@ class Item_func_set_user_var; // This include needs to be here since item.h requires enum_var_type :-P #include "item.h" /* Item */ +#include "sql_class.h" /* THD */ extern TYPELIB bool_typelib; diff --git a/sql/signal_handler.cc b/sql/signal_handler.cc index 54b456ec2c4..27fcf741e2a 100644 --- a/sql/signal_handler.cc +++ b/sql/signal_handler.cc @@ -16,7 +16,7 @@ #include "my_global.h" #include -#include "mysql_priv.h" +#include "sys_vars.h" #include "my_stacktrace.h" #ifdef __WIN__ @@ -111,7 +111,7 @@ extern "C" sig_handler handle_fatal_signal(int sig) (ulong) max_used_connections); my_safe_printf_stderr("max_threads=%u\n", - (uint) thread_scheduler.max_threads); + (uint) thread_scheduler->max_threads); my_safe_printf_stderr("thread_count=%u\n", (uint) thread_count); @@ -124,7 +124,7 @@ extern "C" sig_handler handle_fatal_signal(int sig) ((ulong) dflt_key_cache->key_cache_mem_size + (global_system_variables.read_buff_size + global_system_variables.sortbuff_size) * - thread_scheduler.max_threads + + thread_scheduler->max_threads + max_connections * sizeof(THD)) / 1024); my_safe_printf_stderr("%s", diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 7a04015dc93..65cc4d4c4ab 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -49,6 +49,8 @@ #include "../storage/perfschema/pfs_server.h" #endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */ +TYPELIB bool_typelib={ array_elements(bool_values)-1, "", bool_values, 0 }; + /* This forward declaration is needed because including sql_base.h causes further includes. [TODO] Eliminate this forward declaration @@ -56,6 +58,77 @@ */ extern void close_thread_tables(THD *thd); + +static bool update_buffer_size(THD *thd, KEY_CACHE *key_cache, + ptrdiff_t offset, ulonglong new_value) +{ + bool error= false; + DBUG_ASSERT(offset == offsetof(KEY_CACHE, param_buff_size)); + + if (new_value == 0) + { + if (key_cache == dflt_key_cache) + { + my_error(ER_WARN_CANT_DROP_DEFAULT_KEYCACHE, MYF(0)); + return true; + } + + if (key_cache->key_cache_inited) // If initied + { + /* + Move tables using this key cache to the default key cache + and clear the old key cache. + */ + key_cache->in_init= 1; + mysql_mutex_unlock(&LOCK_global_system_variables); + key_cache->param_buff_size= 0; + ha_resize_key_cache(key_cache); + ha_change_key_cache(key_cache, dflt_key_cache); + /* + We don't delete the key cache as some running threads my still be in + the key cache code with a pointer to the deleted (empty) key cache + */ + mysql_mutex_lock(&LOCK_global_system_variables); + key_cache->in_init= 0; + } + return error; + } + + key_cache->param_buff_size= new_value; + + /* If key cache didn't exist initialize it, else resize it */ + key_cache->in_init= 1; + mysql_mutex_unlock(&LOCK_global_system_variables); + + if (!key_cache->key_cache_inited) + error= ha_init_key_cache(0, key_cache); + else + error= ha_resize_key_cache(key_cache); + + mysql_mutex_lock(&LOCK_global_system_variables); + key_cache->in_init= 0; + + return error; +} + +static bool update_keycache_param(THD *thd, KEY_CACHE *key_cache, + ptrdiff_t offset, ulonglong new_value) +{ + bool error= false; + DBUG_ASSERT(offset != offsetof(KEY_CACHE, param_buff_size)); + + keycache_var(key_cache, offset)= new_value; + + key_cache->in_init= 1; + mysql_mutex_unlock(&LOCK_global_system_variables); + error= ha_resize_key_cache(key_cache); + + mysql_mutex_lock(&LOCK_global_system_variables); + key_cache->in_init= 0; + + return error; +} + /* The rule for this file: everything should be 'static'. When a sys_var variable or a function from this file is - in very rare cases - needed diff --git a/sql/sys_vars.h b/sql/sys_vars.h index 14d99407f37..98ff5f9fa02 100644 --- a/sql/sys_vars.h +++ b/sql/sys_vars.h @@ -72,7 +72,6 @@ enum charset_enum {IN_SYSTEM_CHARSET, IN_FS_CHARSET}; static const char *bool_values[3]= {"OFF", "ON", 0}; -TYPELIB bool_typelib={ array_elements(bool_values)-1, "", bool_values, 0 }; /** A small wrapper class to pass getopt arguments as a pair @@ -710,76 +709,6 @@ public: } }; -static bool update_buffer_size(THD *thd, KEY_CACHE *key_cache, - ptrdiff_t offset, ulonglong new_value) -{ - bool error= false; - DBUG_ASSERT(offset == offsetof(KEY_CACHE, param_buff_size)); - - if (new_value == 0) - { - if (key_cache == dflt_key_cache) - { - my_error(ER_WARN_CANT_DROP_DEFAULT_KEYCACHE, MYF(0)); - return true; - } - - if (key_cache->key_cache_inited) // If initied - { - /* - Move tables using this key cache to the default key cache - and clear the old key cache. - */ - key_cache->in_init= 1; - mysql_mutex_unlock(&LOCK_global_system_variables); - key_cache->param_buff_size= 0; - ha_resize_key_cache(key_cache); - ha_change_key_cache(key_cache, dflt_key_cache); - /* - We don't delete the key cache as some running threads my still be in - the key cache code with a pointer to the deleted (empty) key cache - */ - mysql_mutex_lock(&LOCK_global_system_variables); - key_cache->in_init= 0; - } - return error; - } - - key_cache->param_buff_size= new_value; - - /* If key cache didn't exist initialize it, else resize it */ - key_cache->in_init= 1; - mysql_mutex_unlock(&LOCK_global_system_variables); - - if (!key_cache->key_cache_inited) - error= ha_init_key_cache(0, key_cache); - else - error= ha_resize_key_cache(key_cache); - - mysql_mutex_lock(&LOCK_global_system_variables); - key_cache->in_init= 0; - - return error; -} - -static bool update_keycache_param(THD *thd, KEY_CACHE *key_cache, - ptrdiff_t offset, ulonglong new_value) -{ - bool error= false; - DBUG_ASSERT(offset != offsetof(KEY_CACHE, param_buff_size)); - - keycache_var(key_cache, offset)= new_value; - - key_cache->in_init= 1; - mysql_mutex_unlock(&LOCK_global_system_variables); - error= ha_resize_key_cache(key_cache); - - mysql_mutex_lock(&LOCK_global_system_variables); - key_cache->in_init= 0; - - return error; -} - /** The class for floating point variables From bce2360f53eb238aba4196c4893bc0ecf560a6cd Mon Sep 17 00:00:00 2001 From: Tor Didriksen Date: Fri, 2 Dec 2011 15:16:39 +0100 Subject: [PATCH 160/288] Bug#11761576 post-push fix: HAVE_EXPLICIT_TEMPLATE_INSTANTIATION in header file broke Mac build --- sql/sys_vars.cc | 14 ++++++++++++++ sql/sys_vars.h | 14 -------------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 65cc4d4c4ab..f5a9ab3b55c 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -3253,3 +3253,17 @@ static Sys_var_tz Sys_time_zone( SESSION_VAR(time_zone), NO_CMD_LINE, DEFAULT(&default_tz), NO_MUTEX_GUARD, IN_BINLOG); + +/**************************************************************************** + Used templates +****************************************************************************/ + +#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION +template class List; +template class List_iterator_fast; +template class Sys_var_unsigned; +template class Sys_var_unsigned; +template class Sys_var_unsigned; +template class Sys_var_unsigned; +#endif + diff --git a/sql/sys_vars.h b/sql/sys_vars.h index 98ff5f9fa02..bde48209251 100644 --- a/sql/sys_vars.h +++ b/sql/sys_vars.h @@ -1606,17 +1606,3 @@ public: {} virtual bool session_update(THD *thd, set_var *var); }; - -/**************************************************************************** - Used templates -****************************************************************************/ - -#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION -template class List; -template class List_iterator_fast; -template class Sys_var_unsigned; -template class Sys_var_unsigned; -template class Sys_var_unsigned; -template class Sys_var_unsigned; -#endif - From 9d0ea0ab4bd4b4be302ca63ddbcc47fd3a4a8c7d Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Fri, 2 Dec 2011 17:22:17 +0200 Subject: [PATCH 161/288] Fixed bug where automaticly zerofilled table was not part of recovery if crash happended before next checkpoint. mysql-test/suite/maria/r/maria-autozerofill.result: Updated test case storage/maria/ha_maria.cc: Write create_rename_lsn for auto_zerofilled tables. storage/maria/ma_delete.c: Added DBUG_ASSERT() to find errors when deleting pages. storage/maria/ma_locking.c: Fixed typo storage/maria/ma_open.c: Don't regard file as movable if create_rename_lsn is not LSN_NEEDS_NEW_STATE_LSNS --- mysql-test/suite/maria/r/maria-autozerofill.result | 3 +-- storage/maria/ha_maria.cc | 4 ++++ storage/maria/ma_delete.c | 1 + storage/maria/ma_locking.c | 2 +- storage/maria/ma_open.c | 5 +++++ 5 files changed, 12 insertions(+), 3 deletions(-) diff --git a/mysql-test/suite/maria/r/maria-autozerofill.result b/mysql-test/suite/maria/r/maria-autozerofill.result index ad0ea32362a..81df4cbab90 100644 --- a/mysql-test/suite/maria/r/maria-autozerofill.result +++ b/mysql-test/suite/maria/r/maria-autozerofill.result @@ -13,8 +13,7 @@ a Warnings: Error 1194 t1' is marked as crashed and should be repaired flush table t1; -Status: changed,sorted index pages,zerofilled,movable -create_rename_lsn has magic value +Status: changed,sorted index pages,zerofilled insert into t1 values(2); flush table t1; create_rename_lsn has non-magic value diff --git a/storage/maria/ha_maria.cc b/storage/maria/ha_maria.cc index 2afa32e4f01..cbe91791bee 100644 --- a/storage/maria/ha_maria.cc +++ b/storage/maria/ha_maria.cc @@ -1425,8 +1425,12 @@ int ha_maria::zerofill(THD * thd, HA_CHECK_OPT *check_opt) if (!error) { + TrID create_trid= trnman_get_min_safe_trid(); pthread_mutex_lock(&share->intern_lock); + share->state.changed|= STATE_NOT_MOVABLE; maria_update_state_info(¶m, file, UPDATE_TIME | UPDATE_OPEN_COUNT); + _ma_update_state_lsns_sub(share, LSN_IMPOSSIBLE, create_trid, + TRUE, TRUE); pthread_mutex_unlock(&share->intern_lock); } return error; diff --git a/storage/maria/ma_delete.c b/storage/maria/ma_delete.c index a4e485066f5..a2e2d9b040c 100644 --- a/storage/maria/ma_delete.c +++ b/storage/maria/ma_delete.c @@ -247,6 +247,7 @@ my_bool _ma_ck_real_delete(register MARIA_HA *info, MARIA_KEY *key, if (page.size <= page.node + share->keypage_header + 1) { + DBUG_ASSERT(page.size == page.node + share->keypage_header); if (page.node) *root= _ma_kpos(page.node, root_buff +share->keypage_header + page.node); diff --git a/storage/maria/ma_locking.c b/storage/maria/ma_locking.c index acc359ff212..078c0602d9b 100644 --- a/storage/maria/ma_locking.c +++ b/storage/maria/ma_locking.c @@ -398,7 +398,7 @@ int _ma_mark_file_changed(register MARIA_SHARE *share) /* For transactional tables, the table is marked changed when the first page is written. Here we just mark the state to be updated so that caller - can do 'anaylze table' and find that is has changed before any pages + can do 'analyze table' and find that is has changed before any pages are written. */ if (! test_all_bits(share->state.changed, diff --git a/storage/maria/ma_open.c b/storage/maria/ma_open.c index 3f15749ced5..fc98945d582 100644 --- a/storage/maria/ma_open.c +++ b/storage/maria/ma_open.c @@ -748,6 +748,11 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags) HA_ERR_CRASHED_ON_REPAIR : HA_ERR_CRASHED_ON_USAGE); goto err; } + else + { + /* create_rename_lsn != LSN_NEEDS_NEW_STATE_LSNS */ + share->state.changed|= STATE_NOT_MOVABLE; + } } else share->page_type= PAGECACHE_PLAIN_PAGE; From 791286ee1c3c705cb8853e242cdf718a7b5ce5b7 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 3 Dec 2011 10:53:00 +0100 Subject: [PATCH 162/288] update tests --- .../maria/unittest/ma_test_recovery.expected | 192 +++++++++--------- 1 file changed, 96 insertions(+), 96 deletions(-) diff --git a/storage/maria/unittest/ma_test_recovery.expected b/storage/maria/unittest/ma_test_recovery.expected index 5f7dd54e673..6a6051735c5 100644 --- a/storage/maria/unittest/ma_test_recovery.expected +++ b/storage/maria/unittest/ma_test_recovery.expected @@ -70,7 +70,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -79,7 +79,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -88,7 +88,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -99,7 +99,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -108,7 +108,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -117,7 +117,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -167,7 +167,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -176,7 +176,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -185,7 +185,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -196,7 +196,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -205,7 +205,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -214,7 +214,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -264,7 +264,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -273,7 +273,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -282,7 +282,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -293,7 +293,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -302,7 +302,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -311,7 +311,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -361,7 +361,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -370,7 +370,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -379,7 +379,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -390,7 +390,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -399,7 +399,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -408,7 +408,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -458,7 +458,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -467,7 +467,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -476,7 +476,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -487,7 +487,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -496,7 +496,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -505,7 +505,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -555,7 +555,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -564,7 +564,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -573,7 +573,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -584,7 +584,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -593,7 +593,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -602,7 +602,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -652,7 +652,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -661,7 +661,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -670,7 +670,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -681,7 +681,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -690,7 +690,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -699,7 +699,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -749,7 +749,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -758,7 +758,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -767,7 +767,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -778,7 +778,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -787,7 +787,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -796,7 +796,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -846,7 +846,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -855,7 +855,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -864,7 +864,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -875,7 +875,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -884,7 +884,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -893,7 +893,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -943,7 +943,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -952,7 +952,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -961,7 +961,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -972,7 +972,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -981,7 +981,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -990,7 +990,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -1040,7 +1040,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -1049,7 +1049,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -1058,7 +1058,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -1069,7 +1069,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -1078,7 +1078,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -1087,7 +1087,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -1137,7 +1137,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -1146,7 +1146,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -1155,7 +1155,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -1166,7 +1166,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -1175,7 +1175,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -1184,7 +1184,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -1234,7 +1234,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -1243,7 +1243,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -1252,7 +1252,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -1263,7 +1263,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -1272,7 +1272,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -1281,7 +1281,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -1331,7 +1331,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -1340,7 +1340,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -1349,7 +1349,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -1360,7 +1360,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -1369,7 +1369,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -1378,7 +1378,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -1428,7 +1428,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -1437,7 +1437,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -1446,7 +1446,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -1457,7 +1457,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -1466,7 +1466,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -1475,7 +1475,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -1525,7 +1525,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -1534,7 +1534,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -1543,7 +1543,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -1554,7 +1554,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -1563,7 +1563,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= @@ -1572,7 +1572,7 @@ applying log Differences in aria_chk -dvv, recovery not yet perfect ! ========DIFF START======= 6c6 -< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable +< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled --- > Status: changed ========DIFF END======= From d5fd757a4279f4fa8f032c6dd63d1d121d8e1fea Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 2 Dec 2011 16:26:43 +0100 Subject: [PATCH 163/288] 1. add --plugin-dir and --default-auth to mysqltest. 2. dialog plugin now always returns mysql->password if non-empty and the first question is of password type 3. split get_tty_password into get_tty_password_buff and strdup. 4. dialog plugin now uses get_tty_password by default 5. dialog.test 6. moved small tests of individual plugins into a dedicated suite --- client/mysql.cc | 7 +- client/mysqltest.cc | 44 +++++++++++++ include/my_global.h | 10 +-- include/mysql.h.pp | 1 + include/mysql/client_plugin.h | 8 ++- include/mysql/plugin.h | 34 +++++----- include/mysql_com.h | 1 + libmysql/CMakeLists.txt | 1 - libmysql/get_password.c | 31 ++++----- libmysqld/CMakeLists.txt | 2 +- mysql-test/Makefile.am | 2 +- mysql-test/mysql-test-run.pl | 2 +- mysql-test/suite/plugins/r/dialog.result | 26 ++++++++ .../plugins}/r/feedback_plugin_install.result | 0 .../plugins}/r/feedback_plugin_load.result | 0 .../plugins}/r/feedback_plugin_send.result | 0 .../plugins}/r/fulltext_plugin.result | 0 mysql-test/suite/plugins/t/dialog.test | 51 +++++++++++++++ .../plugins}/t/feedback_plugin_install.opt | 0 .../plugins}/t/feedback_plugin_install.test | 0 .../plugins}/t/feedback_plugin_load.opt | 0 .../plugins}/t/feedback_plugin_load.test | 0 .../plugins}/t/feedback_plugin_send.test | 2 +- .../plugins}/t/fulltext_plugin.test | 0 plugin/auth/CMakeLists.txt | 2 +- plugin/auth/Makefile.am | 2 +- plugin/auth/dialog.c | 64 +++++++------------ plugin/feedback/feedback.h | 5 +- sql/CMakeLists.txt | 2 +- 29 files changed, 203 insertions(+), 94 deletions(-) create mode 100644 mysql-test/suite/plugins/r/dialog.result rename mysql-test/{ => suite/plugins}/r/feedback_plugin_install.result (100%) rename mysql-test/{ => suite/plugins}/r/feedback_plugin_load.result (100%) rename mysql-test/{ => suite/plugins}/r/feedback_plugin_send.result (100%) rename mysql-test/{ => suite/plugins}/r/fulltext_plugin.result (100%) create mode 100644 mysql-test/suite/plugins/t/dialog.test rename mysql-test/{ => suite/plugins}/t/feedback_plugin_install.opt (100%) rename mysql-test/{ => suite/plugins}/t/feedback_plugin_install.test (100%) rename mysql-test/{ => suite/plugins}/t/feedback_plugin_load.opt (100%) rename mysql-test/{ => suite/plugins}/t/feedback_plugin_load.test (100%) rename mysql-test/{ => suite/plugins}/t/feedback_plugin_send.test (95%) rename mysql-test/{ => suite/plugins}/t/fulltext_plugin.test (100%) diff --git a/client/mysql.cc b/client/mysql.cc index 82ffaa22032..0ce28fa90c6 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -4319,9 +4319,10 @@ char *get_arg(char *line, my_bool get_next_arg) string, and the "dialog" plugin will free() it. */ -extern "C" char *mysql_authentication_dialog_ask(MYSQL *mysql, int type, - const char *prompt, - char *buf, int buf_len) +MYSQL_PLUGIN_EXPORT +char *mysql_authentication_dialog_ask(MYSQL *mysql, int type, + const char *prompt, + char *buf, int buf_len) { char *s=buf; diff --git a/client/mysqltest.cc b/client/mysqltest.cc index cf1b81d6169..45de35ab84b 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -117,6 +117,7 @@ static my_bool disable_connect_log= 1; static my_bool disable_warnings= 0; static my_bool prepare_warnings_enabled= 0; static my_bool disable_info= 1; +static char *opt_plugin_dir= 0, *opt_default_auth; static my_bool abort_on_error= 1; static my_bool server_initialized= 0; static my_bool is_windows= 0; @@ -6235,6 +6236,13 @@ static struct my_option my_long_options[] = {"view-protocol", OPT_VIEW_PROTOCOL, "Use views for select.", &view_protocol, &view_protocol, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"plugin_dir", OPT_PLUGIN_DIR, "Directory for client-side plugins.", + (uchar**) &opt_plugin_dir, (uchar**) &opt_plugin_dir, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"default_auth", OPT_PLUGIN_DIR, + "Default authentication client-side plugin to use.", + (uchar**) &opt_default_auth, (uchar**) &opt_default_auth, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; @@ -8218,6 +8226,12 @@ int main(int argc, char **argv) if (opt_protocol) mysql_options(con->mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol); + if (opt_plugin_dir && *opt_plugin_dir) + mysql_options(con->mysql, MYSQL_PLUGIN_DIR, opt_plugin_dir); + + if (opt_default_auth && *opt_default_auth) + mysql_options(con->mysql, MYSQL_DEFAULT_AUTH, opt_default_auth); + #ifdef HAVE_OPENSSL if (opt_use_ssl) @@ -10176,3 +10190,33 @@ static int setenv(const char *name, const char *value, int overwrite) return 0; } #endif + +/* + for the purpose of testing (see dialog.test) + we replace default mysql_authentication_dialog_ask function with the one, + that always reads from stdin with explicit echo. + +*/ +MYSQL_PLUGIN_EXPORT +char *mysql_authentication_dialog_ask(MYSQL *mysql, int type, + const char *prompt, + char *buf, int buf_len) +{ + char *s=buf; + + fputs(prompt, stdout); + fputs(" ", stdout); + + if (!fgets(buf, buf_len-1, stdin)) + buf[0]= 0; + else if (buf[0] && (s= strend(buf))[-1] == '\n') + s[-1]= 0; + + for (s= buf; *s; s++) + fputc(type == 2 ? '*' : *s, stdout); + + fputc('\n', stdout); + + return buf; +} + diff --git a/include/my_global.h b/include/my_global.h index 92aa2352621..58147f85ee3 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -1520,18 +1520,20 @@ do { doubleget_union _tmp; \ #define NO_EMBEDDED_ACCESS_CHECKS #endif -#ifdef HAVE_DLOPEN -#if defined(__WIN__) +#if defined(_WIN32) #define dlsym(lib, name) GetProcAddress((HMODULE)lib, name) #define dlopen(libname, unused) LoadLibraryEx(libname, NULL, 0) #define dlclose(lib) FreeLibrary((HMODULE)lib) -#elif defined(HAVE_DLFCN_H) +#define HAVE_DLOPEN +#endif + +#ifdef HAVE_DLFCN_H #include #endif + #ifndef HAVE_DLERROR #define dlerror() "" #endif -#endif /* FreeBSD 2.2.2 does not define RTLD_NOW) */ #ifndef RTLD_NOW diff --git a/include/mysql.h.pp b/include/mysql.h.pp index 6e71f886eba..44f07c8a541 100644 --- a/include/mysql.h.pp +++ b/include/mysql.h.pp @@ -139,6 +139,7 @@ void get_salt_from_password(unsigned char *res, const char *password); void make_password_from_salt(char *to, const unsigned char *hash_stage2); char *octet2hex(char *to, const char *str, unsigned int len); char *get_tty_password(const char *opt_message); +void get_tty_password_buff(const char *opt_message, char *to, size_t length); const char *mysql_errno_to_sqlstate(unsigned int mysql_errno); my_bool my_thread_init(void); void my_thread_end(void); diff --git a/include/mysql/client_plugin.h b/include/mysql/client_plugin.h index 33c63b9df33..f463277c530 100644 --- a/include/mysql/client_plugin.h +++ b/include/mysql/client_plugin.h @@ -28,9 +28,7 @@ #include #endif -#ifdef MYSQL_PLUGIN_EXPORT #undef MYSQL_PLUGIN_EXPORT -#endif #if defined(_MSC_VER) #ifdef __cplusplus #define MYSQL_PLUGIN_EXPORT extern "C" __declspec(dllexport) @@ -38,7 +36,11 @@ #define MYSQL_PLUGIN_EXPORT __declspec(dllexport) #endif #else /*_MSC_VER */ -#define MYSQL_PLUGIN_EXPORT + #ifdef __cplusplus + #define MYSQL_PLUGIN_EXPORT extern "C" + #else + #define MYSQL_PLUGIN_EXPORT + #endif #endif /* known plugin types */ diff --git a/include/mysql/plugin.h b/include/mysql/plugin.h index bacc4bd7bd8..b8f4ad6f3fc 100644 --- a/include/mysql/plugin.h +++ b/include/mysql/plugin.h @@ -25,21 +25,17 @@ for functions. */ #if defined(_MSC_VER) -#if defined(MYSQL_DYNAMIC_PLUGIN) #ifdef __cplusplus #define MYSQL_PLUGIN_EXPORT extern "C" __declspec(dllexport) #else #define MYSQL_PLUGIN_EXPORT __declspec(dllexport) #endif -#else /* MYSQL_DYNAMIC_PLUGIN */ - #ifdef __cplusplus - #define MYSQL_PLUGIN_EXPORT extern "C" - #else - #define MYSQL_PLUGIN_EXPORT - #endif -#endif /*MYSQL_DYNAMIC_PLUGIN */ #else /*_MSC_VER */ -#define MYSQL_PLUGIN_EXPORT + #ifdef __cplusplus + #define MYSQL_PLUGIN_EXPORT extern "C" + #else + #define MYSQL_PLUGIN_EXPORT + #endif #endif #ifdef __cplusplus @@ -129,14 +125,20 @@ struct st_maria_plugin DECLS[]= { #else #define __MYSQL_DECLARE_PLUGIN(NAME, VERSION, PSIZE, DECLS) \ -MYSQL_PLUGIN_EXPORT int _mysql_plugin_interface_version_= MYSQL_PLUGIN_INTERFACE_VERSION; \ -MYSQL_PLUGIN_EXPORT int _mysql_sizeof_struct_st_plugin_= sizeof(struct st_mysql_plugin); \ -MYSQL_PLUGIN_EXPORT struct st_mysql_plugin _mysql_plugin_declarations_[]= { +MYSQL_PLUGIN_EXPORT int _mysql_plugin_interface_version_; \ +int _mysql_plugin_interface_version_= MYSQL_PLUGIN_INTERFACE_VERSION; \ +MYSQL_PLUGIN_EXPORT int _mysql_sizeof_struct_st_plugin_; \ +int _mysql_sizeof_struct_st_plugin_= sizeof(struct st_mysql_plugin); \ +MYSQL_PLUGIN_EXPORT struct st_mysql_plugin _mysql_plugin_declarations_[]; \ +struct st_mysql_plugin _mysql_plugin_declarations_[]= { -#define MARIA_DECLARE_PLUGIN__(NAME, VERSION, PSIZE, DECLS) \ -MYSQL_PLUGIN_EXPORT int _maria_plugin_interface_version_= MARIA_PLUGIN_INTERFACE_VERSION; \ -MYSQL_PLUGIN_EXPORT int _maria_sizeof_struct_st_plugin_= sizeof(struct st_maria_plugin); \ -MYSQL_PLUGIN_EXPORT struct st_maria_plugin _maria_plugin_declarations_[]= { +#define MARIA_DECLARE_PLUGIN__(NAME, VERSION, PSIZE, DECLS) \ +MYSQL_PLUGIN_EXPORT int _maria_plugin_interface_version_; \ +int _maria_plugin_interface_version_= MARIA_PLUGIN_INTERFACE_VERSION; \ +MYSQL_PLUGIN_EXPORT int _maria_sizeof_struct_st_plugin_; \ +int _maria_sizeof_struct_st_plugin_= sizeof(struct st_maria_plugin); \ +MYSQL_PLUGIN_EXPORT struct st_maria_plugin _maria_plugin_declarations_[]; \ +struct st_maria_plugin _maria_plugin_declarations_[]= { #endif diff --git a/include/mysql_com.h b/include/mysql_com.h index affd24a4636..d7441036a98 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -517,6 +517,7 @@ char *octet2hex(char *to, const char *str, unsigned int len); /* end of password.c */ char *get_tty_password(const char *opt_message); +void get_tty_password_buff(const char *opt_message, char *to, size_t length); const char *mysql_errno_to_sqlstate(unsigned int mysql_errno); /* Some other useful functions */ diff --git a/libmysql/CMakeLists.txt b/libmysql/CMakeLists.txt index 2e99b2a001d..aa6ea8dc851 100755 --- a/libmysql/CMakeLists.txt +++ b/libmysql/CMakeLists.txt @@ -120,7 +120,6 @@ IF(WIN32) ENDIF(WIN32) ADD_DEPENDENCIES(libmysql GenError) TARGET_LINK_LIBRARIES(libmysql mysqlclient ws2_32) -ADD_DEFINITIONS(-DHAVE_DLOPEN) MYSQL_INSTALL_TARGETS(mysqlclient DESTINATION lib COMPONENT Development) MYSQL_INSTALL_TARGETS(libmysql DESTINATION lib COMPONENT SharedLibraries) diff --git a/libmysql/get_password.c b/libmysql/get_password.c index cbe5fce6949..747d598d72a 100644 --- a/libmysql/get_password.c +++ b/libmysql/get_password.c @@ -75,12 +75,10 @@ #define _cputs(A) putstring(A) #endif -char *get_tty_password(const char *opt_message) +void get_tty_password_buff(const char *opt_message, char *to, size_t length) { - char to[80]; - char *pos=to,*end=to+sizeof(to)-1; + char *pos=to,*end=to+length-1; int i=0; - DBUG_ENTER("get_tty_password"); _cputs(opt_message ? opt_message : "Enter password: "); for (;;) { @@ -106,7 +104,6 @@ char *get_tty_password(const char *opt_message) pos--; /* Allow dummy space at end */ *pos=0; _cputs("\n"); - DBUG_RETURN(my_strdup(to,MYF(MY_FAE))); } #else @@ -159,22 +156,19 @@ static void get_password(char *to,uint length,int fd, my_bool echo) #endif /* ! HAVE_GETPASS */ -char *get_tty_password(const char *opt_message) +void get_tty_password_buff(const char *opt_message, char *buff, size_t buflen) { #ifdef HAVE_GETPASS char *passbuff; #else /* ! HAVE_GETPASS */ TERMIO org,tmp; #endif /* HAVE_GETPASS */ - char buff[80]; - - DBUG_ENTER("get_tty_password"); #ifdef HAVE_GETPASS passbuff = getpass(opt_message ? opt_message : "Enter password: "); /* copy the password to buff and clear original (static) buffer */ - strnmov(buff, passbuff, sizeof(buff) - 1); + strnmov(buff, passbuff, buflen - 1); #ifdef _PASSWORD_LEN memset(passbuff, 0, _PASSWORD_LEN); #endif @@ -191,7 +185,7 @@ char *get_tty_password(const char *opt_message) tmp.c_cc[VMIN] = 1; tmp.c_cc[VTIME] = 0; tcsetattr(fileno(stdin), TCSADRAIN, &tmp); - get_password(buff, sizeof(buff)-1, fileno(stdin), isatty(fileno(stdout))); + get_password(buff, buflen, fileno(stdin), isatty(fileno(stdout))); tcsetattr(fileno(stdin), TCSADRAIN, &org); #elif defined(HAVE_TERMIO_H) ioctl(fileno(stdin), (int) TCGETA, &org); @@ -200,7 +194,7 @@ char *get_tty_password(const char *opt_message) tmp.c_cc[VMIN] = 1; tmp.c_cc[VTIME]= 0; ioctl(fileno(stdin),(int) TCSETA, &tmp); - get_password(buff,sizeof(buff)-1,fileno(stdin),isatty(fileno(stdout))); + get_password(buff,buflen-1,fileno(stdin),isatty(fileno(stdout))); ioctl(fileno(stdin),(int) TCSETA, &org); #else gtty(fileno(stdin), &org); @@ -208,13 +202,20 @@ char *get_tty_password(const char *opt_message) tmp.sg_flags &= ~ECHO; tmp.sg_flags |= RAW; stty(fileno(stdin), &tmp); - get_password(buff,sizeof(buff)-1,fileno(stdin),isatty(fileno(stdout))); + get_password(buff,buflen-1,fileno(stdin),isatty(fileno(stdout))); stty(fileno(stdin), &org); #endif if (isatty(fileno(stdout))) fputc('\n',stdout); #endif /* HAVE_GETPASS */ - - DBUG_RETURN(my_strdup(buff,MYF(MY_FAE))); } #endif /*__WIN__*/ + +#ifndef MYSQL_DYNAMIC_PLUGIN +char *get_tty_password(const char *opt_message) +{ + char buff[80]; + get_tty_password_buff(opt_message, buff, sizeof(buff)); + return my_strdup(buff, MYF(MY_FAE)); +} +#endif diff --git a/libmysqld/CMakeLists.txt b/libmysqld/CMakeLists.txt index d964def7505..c4ca3d62afe 100644 --- a/libmysqld/CMakeLists.txt +++ b/libmysqld/CMakeLists.txt @@ -21,7 +21,7 @@ IF(WIN32) ADD_DEFINITIONS(-DUSE_TLS) ENDIF(WIN32) -ADD_DEFINITIONS(-DMYSQL_SERVER -DEMBEDDED_LIBRARY -DHAVE_DLOPEN) +ADD_DEFINITIONS(-DMYSQL_SERVER -DEMBEDDED_LIBRARY) INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/libmysqld diff --git a/mysql-test/Makefile.am b/mysql-test/Makefile.am index ddf8d0457f3..b73771391c2 100644 --- a/mysql-test/Makefile.am +++ b/mysql-test/Makefile.am @@ -110,7 +110,7 @@ TEST_DIRS = t r include std_data std_data/parts collections \ suite/innodb suite/innodb/t suite/innodb/r suite/innodb/include \ suite/innodb_plugin suite/innodb_plugin/t suite/innodb_plugin/r \ suite/innodb_plugin/include \ - suite/percona suite/handler \ + suite/percona suite/handler suite/plugins suite/plugins/t suite/plugins/r \ suite/engines suite/engines/funcs suite/engines/iuds suite/engines/rr_trx \ suite/engines/funcs/r suite/engines/funcs/t suite/engines/iuds/r \ suite/engines/iuds/t suite/engines/rr_trx/include suite/engines/rr_trx/r \ diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index bc3518ed2bc..dc03a6bf5b5 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -160,7 +160,7 @@ my $path_config_file; # The generated config file, var/my.cnf # executables will be used by the test suite. our $opt_vs_config = $ENV{'MTR_VS_CONFIG'}; -my $DEFAULT_SUITES= "main,binlog,federated,rpl,maria,handler,parts,innodb,innodb_plugin,percona,ndb,vcol,oqgraph,sphinx"; +my $DEFAULT_SUITES= "main,binlog,federated,rpl,maria,handler,parts,innodb,innodb_plugin,percona,ndb,vcol,oqgraph,sphinx,plugins"; my $opt_suites; our $opt_verbose= 0; # Verbose output, enable with --verbose diff --git a/mysql-test/suite/plugins/r/dialog.result b/mysql-test/suite/plugins/r/dialog.result new file mode 100644 index 00000000000..da3117fd491 --- /dev/null +++ b/mysql-test/suite/plugins/r/dialog.result @@ -0,0 +1,26 @@ +install plugin three_attempts soname 'dialog.so'; +create user test_dialog identified via three_attempts using 'SECRET'; +# +# -pSECRET is picked up, no questions asked. +# +select user(), current_user(); +user() current_user() +test_dialog@localhost test_dialog@% +# +# without -p. up to three questions are asked on the stdin. +# athentication is successful, the correct pasword is on the third line +# +Password, please: *** +Password, please: **** +Password, please: ****** +select user(), current_user(); +user() current_user() +test_dialog@localhost test_dialog@% +# +# athentication is unsuccessful, first three lines are all wrong +# +Password, please: *** +Password, please: **** +Password, please: ***** +drop user test_dialog; +uninstall plugin three_attempts; diff --git a/mysql-test/r/feedback_plugin_install.result b/mysql-test/suite/plugins/r/feedback_plugin_install.result similarity index 100% rename from mysql-test/r/feedback_plugin_install.result rename to mysql-test/suite/plugins/r/feedback_plugin_install.result diff --git a/mysql-test/r/feedback_plugin_load.result b/mysql-test/suite/plugins/r/feedback_plugin_load.result similarity index 100% rename from mysql-test/r/feedback_plugin_load.result rename to mysql-test/suite/plugins/r/feedback_plugin_load.result diff --git a/mysql-test/r/feedback_plugin_send.result b/mysql-test/suite/plugins/r/feedback_plugin_send.result similarity index 100% rename from mysql-test/r/feedback_plugin_send.result rename to mysql-test/suite/plugins/r/feedback_plugin_send.result diff --git a/mysql-test/r/fulltext_plugin.result b/mysql-test/suite/plugins/r/fulltext_plugin.result similarity index 100% rename from mysql-test/r/fulltext_plugin.result rename to mysql-test/suite/plugins/r/fulltext_plugin.result diff --git a/mysql-test/suite/plugins/t/dialog.test b/mysql-test/suite/plugins/t/dialog.test new file mode 100644 index 00000000000..47452643609 --- /dev/null +++ b/mysql-test/suite/plugins/t/dialog.test @@ -0,0 +1,51 @@ +# +# test for the client "dialog" plugin +# + +--source include/not_embedded.inc + +if (!$DIALOG_SO) { + skip No dialog auth plugin; +} + +--replace_result .dll .so +eval install plugin three_attempts soname '$DIALOG_SO'; +create user test_dialog identified via three_attempts using 'SECRET'; + +let $plugindir=`SELECT @@global.plugin_dir`; + +--write_file $MYSQLTEST_VARDIR/tmp/dialog_good.txt +foo +1234 +SECRET +select user(), current_user(); +EOF + +--write_file $MYSQLTEST_VARDIR/tmp/dialog_bad.txt +foo +1234 +wrong +SECRET +EOF + +--echo # +--echo # -pSECRET is picked up, no questions asked. +--echo # +--exec echo "select user(), current_user();"|$MYSQL_TEST -u test_dialog -pSECRET --plugin-dir=$plugindir + +--echo # +--echo # without -p. up to three questions are asked on the stdin. +--echo # athentication is successful, the correct pasword is on the third line +--echo # +--exec $MYSQL_TEST -u test_dialog --plugin-dir=$plugindir < $MYSQLTEST_VARDIR/tmp/dialog_good.txt + +--echo # +--echo # athentication is unsuccessful, first three lines are all wrong +--echo # +--error 1 +--exec $MYSQL_TEST -u test_dialog --plugin-dir=$plugindir < $MYSQLTEST_VARDIR/tmp/dialog_bad.txt + +--remove_file $MYSQLTEST_VARDIR/tmp/dialog_good.txt +--remove_file $MYSQLTEST_VARDIR/tmp/dialog_bad.txt +drop user test_dialog; +uninstall plugin three_attempts; diff --git a/mysql-test/t/feedback_plugin_install.opt b/mysql-test/suite/plugins/t/feedback_plugin_install.opt similarity index 100% rename from mysql-test/t/feedback_plugin_install.opt rename to mysql-test/suite/plugins/t/feedback_plugin_install.opt diff --git a/mysql-test/t/feedback_plugin_install.test b/mysql-test/suite/plugins/t/feedback_plugin_install.test similarity index 100% rename from mysql-test/t/feedback_plugin_install.test rename to mysql-test/suite/plugins/t/feedback_plugin_install.test diff --git a/mysql-test/t/feedback_plugin_load.opt b/mysql-test/suite/plugins/t/feedback_plugin_load.opt similarity index 100% rename from mysql-test/t/feedback_plugin_load.opt rename to mysql-test/suite/plugins/t/feedback_plugin_load.opt diff --git a/mysql-test/t/feedback_plugin_load.test b/mysql-test/suite/plugins/t/feedback_plugin_load.test similarity index 100% rename from mysql-test/t/feedback_plugin_load.test rename to mysql-test/suite/plugins/t/feedback_plugin_load.test diff --git a/mysql-test/t/feedback_plugin_send.test b/mysql-test/suite/plugins/t/feedback_plugin_send.test similarity index 95% rename from mysql-test/t/feedback_plugin_send.test rename to mysql-test/suite/plugins/t/feedback_plugin_send.test index d882539cfea..3324ef469fe 100644 --- a/mysql-test/t/feedback_plugin_send.test +++ b/mysql-test/suite/plugins/t/feedback_plugin_send.test @@ -1,4 +1,4 @@ -source t/feedback_plugin_load.test; +source feedback_plugin_load.test; if (!$MTR_FEEDBACK_PLUGIN) { skip MTR_FEEDBACK_PLUGIN is not set; diff --git a/mysql-test/t/fulltext_plugin.test b/mysql-test/suite/plugins/t/fulltext_plugin.test similarity index 100% rename from mysql-test/t/fulltext_plugin.test rename to mysql-test/suite/plugins/t/fulltext_plugin.test diff --git a/plugin/auth/CMakeLists.txt b/plugin/auth/CMakeLists.txt index 931a47fec5e..2174826b2cd 100644 --- a/plugin/auth/CMakeLists.txt +++ b/plugin/auth/CMakeLists.txt @@ -1,3 +1,3 @@ INCLUDE("${PROJECT_SOURCE_DIR}/storage/mysql_storage_engine.cmake") -SET(AUTH_SOURCES dialog.c) +SET(AUTH_SOURCES dialog.c ${CMAKE_SOURCE_DIR}/libmysql/get_password.c) MYSQL_PLUGIN(AUTH) diff --git a/plugin/auth/Makefile.am b/plugin/auth/Makefile.am index acca98e26f8..2995d35adf4 100644 --- a/plugin/auth/Makefile.am +++ b/plugin/auth/Makefile.am @@ -4,7 +4,7 @@ AM_LDFLAGS=-module -rpath $(pkgplugindir) AM_CPPFLAGS=-DMYSQL_DYNAMIC_PLUGIN -I$(top_srcdir)/include pkgplugin_LTLIBRARIES= dialog.la -dialog_la_SOURCES= dialog.c +dialog_la_SOURCES= dialog.c $(top_srcdir)/libmysql/get_password.c if HAVE_PEERCRED pkgplugin_LTLIBRARIES+= auth_socket.la diff --git a/plugin/auth/dialog.c b/plugin/auth/dialog.c index 76b2ddae528..24765c17d1c 100644 --- a/plugin/auth/dialog.c +++ b/plugin/auth/dialog.c @@ -142,36 +142,6 @@ static struct st_mysql_auth three_handler= three_attempts }; -mysql_declare_plugin(dialog) -{ - MYSQL_AUTHENTICATION_PLUGIN, - &two_handler, - "two_questions", - "Sergei Golubchik", - "Dialog plugin demo 1", - PLUGIN_LICENSE_GPL, - NULL, - NULL, - 0x0100, - NULL, - NULL, - NULL -}, -{ - MYSQL_AUTHENTICATION_PLUGIN, - &three_handler, - "three_attempts", - "Sergei Golubchik", - "Dialog plugin demo 2", - PLUGIN_LICENSE_GPL, - NULL, - NULL, - 0x0100, - NULL, - NULL, - NULL -} -mysql_declare_plugin_end; maria_declare_plugin(dialog) { MYSQL_AUTHENTICATION_PLUGIN, @@ -186,7 +156,7 @@ maria_declare_plugin(dialog) NULL, NULL, "1.0", - MariaDB_PLUGIN_MATURITY_BETA + MariaDB_PLUGIN_MATURITY_EXPERIMENTAL }, { MYSQL_AUTHENTICATION_PLUGIN, @@ -201,7 +171,7 @@ maria_declare_plugin(dialog) NULL, NULL, "1.0", - MariaDB_PLUGIN_MATURITY_BETA + MariaDB_PLUGIN_MATURITY_EXPERIMENTAL } maria_declare_plugin_end; @@ -224,16 +194,25 @@ static char *builtin_ask(MYSQL *mysql __attribute__((unused)), const char *prompt, char *buf, int buf_len) { - int len; - fputs(prompt, stdout); fputc(' ', stdout); - if (fgets(buf, buf_len, stdin) == 0) - return 0; - len= strlen(buf); - if (len && buf[len-1]=='\n') - buf[len-1]=0; + if (type == 2) /* password */ + { + get_tty_password_buff("", buf, buf_len); + buf[buf_len-1]= 0; + } + else + { + if (!fgets(buf, buf_len-1, stdin)) + buf[0]= 0; + else + { + int len= strlen(buf); + if (len && buf[len-1] == '\n') + buf[len-1]= 0; + } + } return buf; } @@ -261,6 +240,7 @@ static int perform_dialog(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql) unsigned char *pkt, cmd= 0; int pkt_len, res; char reply_buf[1024], *reply; + int first = 1; do { @@ -269,7 +249,7 @@ static int perform_dialog(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql) if (pkt_len < 0) return CR_ERROR; - if (pkt == 0) + if (pkt == 0 && first) { /* in mysql_change_user() the client sends the first packet, so @@ -291,10 +271,10 @@ static int perform_dialog(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql) return CR_OK_HANDSHAKE_COMPLETE; /* yes. we're done */ /* - asking for a password with an empty prompt means mysql->password + asking for a password in the first packet mean mysql->password, if it's set otherwise we ask the user and read the reply */ - if ((cmd >> 1) == 2 && *pkt == 0) + if ((cmd >> 1) == 2 && first && mysql->passwd[0]) reply= mysql->passwd; else reply= ask(mysql, cmd >> 1, (char*) pkt, reply_buf, sizeof(reply_buf)); diff --git a/plugin/feedback/feedback.h b/plugin/feedback/feedback.h index df9020fc37e..f9e2cd34231 100644 --- a/plugin/feedback/feedback.h +++ b/plugin/feedback/feedback.h @@ -12,9 +12,8 @@ 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 */ -#ifndef MYSQL_SERVER -#define MYSQL_SERVER -#endif + +#define MYSQL_SERVER 1 #include namespace feedback { diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index e281b187149..6255402e3ab 100755 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -36,7 +36,7 @@ SET_SOURCE_FILES_PROPERTIES(${CMAKE_BINARY_DIR}/sql/sql_yacc.h ${CMAKE_BINARY_DIR}/include/sql_state.h PROPERTIES GENERATED 1) -ADD_DEFINITIONS(-DMYSQL_SERVER -D_CONSOLE -DHAVE_DLOPEN -DHAVE_EVENT_SCHEDULER) +ADD_DEFINITIONS(-DMYSQL_SERVER -D_CONSOLE -DHAVE_EVENT_SCHEDULER) IF(WITH_FEEDBACK_STORAGE_ENGINE) ADD_DEFINITIONS(-DWITH_FEEDBACK_PLUGIN) ENDIF() From 57c22f2a75684dfc43c1a8cdb9f9aa1df69acd87 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 2 Dec 2011 16:27:13 +0100 Subject: [PATCH 164/288] PAM plugin with test --- mysql-test/suite/plugins/r/pam.result | 22 ++++ mysql-test/suite/plugins/suite.pm | 8 ++ mysql-test/suite/plugins/t/pam.test | 46 ++++++++ plugin/auth_pam/Makefile.am | 16 +++ plugin/auth_pam/auth_pam.c | 130 ++++++++++++++++++++++ plugin/auth_pam/plug.in | 4 + plugin/auth_pam/testing/pam_mariadb_mtr.c | 87 +++++++++++++++ 7 files changed, 313 insertions(+) create mode 100644 mysql-test/suite/plugins/r/pam.result create mode 100644 mysql-test/suite/plugins/suite.pm create mode 100644 mysql-test/suite/plugins/t/pam.test create mode 100644 plugin/auth_pam/Makefile.am create mode 100644 plugin/auth_pam/auth_pam.c create mode 100644 plugin/auth_pam/plug.in create mode 100644 plugin/auth_pam/testing/pam_mariadb_mtr.c diff --git a/mysql-test/suite/plugins/r/pam.result b/mysql-test/suite/plugins/r/pam.result new file mode 100644 index 00000000000..1c9036c317e --- /dev/null +++ b/mysql-test/suite/plugins/r/pam.result @@ -0,0 +1,22 @@ +install plugin pam soname 'auth_pam.so'; +create user test_pam identified via pam using 'mariadb_mtr'; +# +# athentication is successful, challenge/pin are ok +# note that current_user() differts from user() +# +Challenge input first. +Enter: not very secret challenge +Now, the magic number! +PIN: **** +select user(), current_user(), database(); +user() current_user() database() +test_pam@localhost pam_test@% test +# +# athentication is unsuccessful +# +Challenge input first. +Enter: not very secret challenge +Now, the magic number! +PIN: **** +drop user test_pam; +uninstall plugin pam; diff --git a/mysql-test/suite/plugins/suite.pm b/mysql-test/suite/plugins/suite.pm new file mode 100644 index 00000000000..f8f78086c15 --- /dev/null +++ b/mysql-test/suite/plugins/suite.pm @@ -0,0 +1,8 @@ +package My::Suite::Plugins; + +@ISA = qw(My::Suite); + +$ENV{PAM_SETUP_FOR_MTR}=1 if -e '/etc/pam.d/mariadb_mtr'; + +bless { }; + diff --git a/mysql-test/suite/plugins/t/pam.test b/mysql-test/suite/plugins/t/pam.test new file mode 100644 index 00000000000..3f4c563d8dc --- /dev/null +++ b/mysql-test/suite/plugins/t/pam.test @@ -0,0 +1,46 @@ + +--source include/not_embedded.inc + +if (!$AUTH_PAM_SO) { + skip No pam auth plugin; +} + +if (!$PAM_SETUP_FOR_MTR) { + skip No pam setup for mtr; +} + +--replace_result .dll .so +eval install plugin pam soname '$AUTH_PAM_SO'; +create user test_pam identified via pam using 'mariadb_mtr'; + +let $plugindir=`SELECT @@global.plugin_dir`; + +--write_file $MYSQLTEST_VARDIR/tmp/pam_good.txt +not very secret challenge +9225 +select user(), current_user(), database(); +EOF + +--write_file $MYSQLTEST_VARDIR/tmp/pam_bad.txt +not very secret challenge +9224 +select user(), current_user(), database(); +EOF + +--echo # +--echo # athentication is successful, challenge/pin are ok +--echo # note that current_user() differts from user() +--echo # +--exec $MYSQL_TEST -u test_pam --plugin-dir=$plugindir < $MYSQLTEST_VARDIR/tmp/pam_good.txt + +--echo # +--echo # athentication is unsuccessful +--echo # +--error 1 +--exec $MYSQL_TEST -u test_pam --plugin-dir=$plugindir < $MYSQLTEST_VARDIR/tmp/pam_bad.txt + +--remove_file $MYSQLTEST_VARDIR/tmp/pam_good.txt +--remove_file $MYSQLTEST_VARDIR/tmp/pam_bad.txt +drop user test_pam; +uninstall plugin pam; + diff --git a/plugin/auth_pam/Makefile.am b/plugin/auth_pam/Makefile.am new file mode 100644 index 00000000000..be20d393781 --- /dev/null +++ b/plugin/auth_pam/Makefile.am @@ -0,0 +1,16 @@ +EXTRA_LTLIBRARIES = auth_pam.la libauth_pam.la + +pkgplugindir=$(pkglibdir)/plugin +AM_CPPFLAGS = -I$(top_srcdir)/include + +pkgplugin_LTLIBRARIES = @plugin_auth_pam_shared_target@ +auth_pam_la_LDFLAGS = -module -rpath $(pkgplugindir) -L$(top_builddir)/libservices -lmysqlservices -lpam +auth_pam_la_CFLAGS = -shared -DMYSQL_DYNAMIC_PLUGIN +auth_pam_la_SOURCES = auth_pam.c + +noinst_LTLIBRARIES = @plugin_auth_pam_static_target@ +libauth_pam_la_LDFLAGS = -lpam +libauth_pam_la_SOURCES = auth_pam.c + +EXTRA_DIST = plug.in + diff --git a/plugin/auth_pam/auth_pam.c b/plugin/auth_pam/auth_pam.c new file mode 100644 index 00000000000..45c49975f6e --- /dev/null +++ b/plugin/auth_pam/auth_pam.c @@ -0,0 +1,130 @@ +#include +#include +#include +#include + +struct param { + unsigned char buf[10240], *ptr; + MYSQL_PLUGIN_VIO *vio; +}; + +static int conv(int n, const struct pam_message **msg, + struct pam_response **resp, void *data) +{ + struct param *param = (struct param *)data; + unsigned char *end = param->buf + sizeof(param->buf) - 1; + int i; + + *resp = 0; + + for (i = 0; i < n; i++) + { + /* if there's a message - append it to the buffer */ + if (msg[i]->msg) + { + int len = strlen(msg[i]->msg); + if (len > end - param->ptr) + len = end - param->ptr; + if (len > 0) + { + memcpy(param->ptr, msg[i]->msg, len); + param->ptr+= len; + *(param->ptr)++ = '\n'; + } + } + /* if the message style is *_PROMPT_*, meaning PAM asks a question, + send the accumulated text to the client, read the reply */ + if (msg[i]->msg_style == PAM_PROMPT_ECHO_OFF || + msg[i]->msg_style == PAM_PROMPT_ECHO_ON) + { + int pkt_len; + unsigned char *pkt; + + /* allocate the response array. + freeing it is the responsibility of the caller */ + if (*resp == 0) + { + *resp = calloc(sizeof(struct pam_response), n); + if (*resp == 0) + return PAM_BUF_ERR; + } + + /* dialog plugin interprets the first byte of the packet + as the magic number. + 2 means "read the input with the echo enabled" + 4 means "password-like input, echo disabled" + C'est la vie. */ + param->buf[0] = msg[i]->msg_style == PAM_PROMPT_ECHO_ON ? 2 : 4; + if (param->vio->write_packet(param->vio, param->buf, param->ptr - param->buf - 1)) + return PAM_CONV_ERR; + + pkt_len = param->vio->read_packet(param->vio, &pkt); + if (pkt_len < 0) + return PAM_CONV_ERR; + /* allocate and copy the reply to the response array */ + (*resp)[i].resp = strndup((char*)pkt, pkt_len); + param->ptr = param->buf + 1; + } + } + return PAM_SUCCESS; +} + +#define DO(X) if ((status = (X)) != PAM_SUCCESS) goto end + +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 }; + + /* + get the service name, as specified in + + CREATE USER ... IDENTIFIED WITH pam_auth AS "service" + */ + const char *service = info->auth_string && info->auth_string[0] + ? info->auth_string : "mysql"; + + param.ptr = param.buf + 1; + param.vio = vio; + + DO( pam_start(service, info->user_name, &c, &pamh) ); + DO( pam_authenticate (pamh, 0) ); + DO( pam_acct_mgmt(pamh, 0) ); + DO( pam_get_item(pamh, PAM_USER, (const void**)&new_username) ); + + if (new_username && strcmp(new_username, info->user_name)) + strncpy(info->authenticated_as, new_username, + sizeof(info->authenticated_as)); + +end: + pam_end(pamh, status); + return status == PAM_SUCCESS ? CR_OK : CR_ERROR; +} + +static struct st_mysql_auth pam_info = +{ + MYSQL_AUTHENTICATION_INTERFACE_VERSION, + "dialog", + pam_auth +}; + +maria_declare_plugin(pam) +{ + MYSQL_AUTHENTICATION_PLUGIN, + &pam_info, + "pam", + "Sergei Golubchik", + "PAM based authentication", + PLUGIN_LICENSE_GPL, + NULL, + NULL, + 0x0100, + NULL, + NULL, + "1.0", + MariaDB_PLUGIN_MATURITY_BETA +} +maria_declare_plugin_end; diff --git a/plugin/auth_pam/plug.in b/plugin/auth_pam/plug.in new file mode 100644 index 00000000000..05af6ce6461 --- /dev/null +++ b/plugin/auth_pam/plug.in @@ -0,0 +1,4 @@ +MYSQL_PLUGIN(auth_pam, [PAM Authentication Plugin], [PAM Authentication Plugin]) +MYSQL_PLUGIN_DYNAMIC(auth_pam, [auth_pam.la]) + +AC_CHECK_HEADER([security/pam_appl.h],,[MYSQL_PLUGIN_WITHOUT(auth_pam)]) diff --git a/plugin/auth_pam/testing/pam_mariadb_mtr.c b/plugin/auth_pam/testing/pam_mariadb_mtr.c new file mode 100644 index 00000000000..73defe30112 --- /dev/null +++ b/plugin/auth_pam/testing/pam_mariadb_mtr.c @@ -0,0 +1,87 @@ +/* + Pam module to test pam authentication plugin. Used in pam.test. + Linux only. + + Compile as + + gcc pam_mariadb_mtr.c -shared -lpam -fPIC -o pam_mariadb_mtr.so + + Install as appropriate (for example, in /lib/security/). + Create /etc/pam.d/mariadb_mtr with +========================================================= +auth required pam_mariadb_mtr.so pam_test +account required pam_mariadb_mtr.so +========================================================= +*/ + +#include +#include +#include +#include + +#define N 3 + +PAM_EXTERN int +pam_sm_authenticate(pam_handle_t *pamh, int flags, + int argc, const char *argv[]) +{ + struct pam_conv *conv; + struct pam_response *resp = 0; + int pam_err, retval = PAM_SYSTEM_ERR; + struct pam_message msg[N] = { + { PAM_TEXT_INFO, "Challenge input first." }, + { PAM_PROMPT_ECHO_ON, "Enter:" }, + { PAM_ERROR_MSG, "Now, the magic number!" } + }; + const struct pam_message *msgp[N] = { msg, msg+1, msg+2 }; + char *r1 = 0, *r2 = 0; + + pam_err = pam_get_item(pamh, PAM_CONV, (const void **)&conv); + if (pam_err != PAM_SUCCESS) + goto ret; + + pam_err = (*conv->conv)(N, msgp, &resp, conv->appdata_ptr); + + if (pam_err != PAM_SUCCESS || !resp || !((r1= resp[1].resp))) + goto ret; + + free(resp); + + msg[0].msg_style = PAM_PROMPT_ECHO_OFF; + msg[0].msg = "PIN:"; + pam_err = (*conv->conv)(1, msgp, &resp, conv->appdata_ptr); + + if (pam_err != PAM_SUCCESS || !resp || !((r2= resp[0].resp))) + goto ret; + + if (strlen(r1) == atoi(r2) % 100) + retval = PAM_SUCCESS; + else + retval = PAM_AUTH_ERR; + + if (argc > 0 && argv[0]) + pam_set_item(pamh, PAM_USER, argv[0]); + +ret: + free(resp); + free(r1); + free(r2); + return retval; +} + +PAM_EXTERN int +pam_sm_setcred(pam_handle_t *pamh, int flags, + int argc, const char *argv[]) +{ + + return PAM_SUCCESS; +} + +PAM_EXTERN int +pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, + int argc, const char *argv[]) +{ + + return PAM_SUCCESS; +} + From c0311edfb90c96a2bf9db746fb0bbf1b1cee54e1 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Fri, 2 Dec 2011 18:10:54 +0200 Subject: [PATCH 165/288] Fixed some Aria limits to be more sane --- storage/maria/ha_maria.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/storage/maria/ha_maria.cc b/storage/maria/ha_maria.cc index cbe91791bee..ead0a3eb5c5 100644 --- a/storage/maria/ha_maria.cc +++ b/storage/maria/ha_maria.cc @@ -233,7 +233,7 @@ static MYSQL_SYSVAR_ULONGLONG(pagecache_buffer_size, pagecache_buffer_size, "The size of the buffer used for index blocks for Aria tables. " "Increase this to get better index handling (for all reads and " "multiple writes) to as much as you can afford.", 0, 0, - KEY_CACHE_SIZE, 8192*16L, ~(ulong) 0, 1); + KEY_CACHE_SIZE, 8192*16L, ~(ulonglong) 0, 1); static MYSQL_SYSVAR_ULONG(pagecache_division_limit, pagecache_division_limit, PLUGIN_VAR_RQCMDARG, @@ -249,12 +249,12 @@ static MYSQL_SYSVAR_SET(recover, maria_recover_options, PLUGIN_VAR_OPCMDARG, static MYSQL_THDVAR_ULONG(repair_threads, PLUGIN_VAR_RQCMDARG, "Number of threads to use when repairing Aria tables. The value of 1 " "disables parallel repair.", - 0, 0, 1, 1, ~0L, 1); + 0, 0, 1, 1, 128, 1); static MYSQL_THDVAR_ULONG(sort_buffer_size, PLUGIN_VAR_RQCMDARG, "The buffer that is allocated when sorting the index when doing a " "REPAIR or when creating indexes with CREATE INDEX or ALTER TABLE.", - 0, 0, 128L*1024L*1024L, 4, ~0L, 1); + 0, 0, 128L*1024L*1024L, 4, UINT_MAX32, 1); static MYSQL_THDVAR_ENUM(stats_method, PLUGIN_VAR_RQCMDARG, "Specifies how Aria index statistics collection code should treat " From 2e34f1828ec6b1bf897eaa23dec8fce544047278 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Sat, 3 Dec 2011 20:29:15 +0200 Subject: [PATCH 166/288] Added suppressions Fixed feedback_plugin_send to not generate a random number of lines. mysql-test/t/feedback_plugin_send.test: Don't print more than 4 lines (sometimes there are 6 feedback lines in the log...) mysql-test/valgrind.supp: Added suppression for failure on work support-files/compiler_warnings.supp: Suppress warning from xtradb --- mysql-test/t/feedback_plugin_send.test | 13 +++++++++++-- mysql-test/valgrind.supp | 10 ++++++++++ support-files/compiler_warnings.supp | 1 + 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/mysql-test/t/feedback_plugin_send.test b/mysql-test/t/feedback_plugin_send.test index 14765ee9543..d882539cfea 100644 --- a/mysql-test/t/feedback_plugin_send.test +++ b/mysql-test/t/feedback_plugin_send.test @@ -17,7 +17,16 @@ replace_result https http; perl; $log_error= $ENV{'MYSQLTEST_VARDIR'} . '/log/mysqld.1.err'; open(LOG, '<', $log_error) or die "open(< $log_error): $!"; - /feedback plugin:.*/ && print "$&\n" while $_=; + + # Get the first few rows (as there may be different number rows in the log) + $i= 0; + while ($_=) + { + if (/feedback plugin:.*/) + { + print "$&\n"; + break if ($i++ >= 3); + } + } close LOG; EOF - diff --git a/mysql-test/valgrind.supp b/mysql-test/valgrind.supp index f48fe1b9967..ff649db144a 100644 --- a/mysql-test/valgrind.supp +++ b/mysql-test/valgrind.supp @@ -1118,3 +1118,13 @@ fun:fil_delete_tablespace fun:row_drop_table_for_mysql } + +{ + Problem with udf and libresolve + Memcheck:Cond + obj:*/libresolv*.so + fun:__libc_res_nquery + fun:_nss_dns_gethostbyaddr2_r + fun:_nss_dns_gethostbyaddr_r + fun:gethostbyaddr_r +} diff --git a/support-files/compiler_warnings.supp b/support-files/compiler_warnings.supp index a56c39b51a0..b131f2cc1b2 100644 --- a/support-files/compiler_warnings.supp +++ b/support-files/compiler_warnings.supp @@ -183,3 +183,4 @@ ctype-simple\.c : .*unary minus operator applied to unsigned type, result still regexec\.c : passing argument 3 of.*matcher.* discards qualifiers from pointer target type libmysql\.c: passing argument 2 of .*memcpy.* discards qualifiers from pointer target type : 3000-4000 storage/xtradb/dict/dict0dict\.c : passing argument 1 of .*strcpy.* discards qualifiers from pointer target type : 2500-3500 +storage/xtradb/sync/sync0rw\.c : passing argument 1 of .*memset.* discards qualifiers from pointer target type : 200-300 From ef841d4c874b0635a07b6592356d575a555beeb5 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Sat, 3 Dec 2011 20:44:54 +0200 Subject: [PATCH 167/288] Fixed buildbot warnings mysql-test/suite/maria/t/compat_aliases-master.opt: Fixed wrong limit storage/example/ha_example.cc: Fixed compiler warning --- mysql-test/suite/maria/t/compat_aliases-master.opt | 2 +- storage/example/ha_example.cc | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/mysql-test/suite/maria/t/compat_aliases-master.opt b/mysql-test/suite/maria/t/compat_aliases-master.opt index 73f18586361..a1dcde828cd 100644 --- a/mysql-test/suite/maria/t/compat_aliases-master.opt +++ b/mysql-test/suite/maria/t/compat_aliases-master.opt @@ -1 +1 @@ ---maria-max-sort-file-size=100M --aria-repair-threads=10000 +--maria-max-sort-file-size=100M --aria-repair-threads=100 diff --git a/storage/example/ha_example.cc b/storage/example/ha_example.cc index 8d5185ae0c7..013a92fc780 100644 --- a/storage/example/ha_example.cc +++ b/storage/example/ha_example.cc @@ -947,7 +947,6 @@ bool ha_example::check_if_incompatible_data(HA_CREATE_INFO *info, uint table_changes) { ha_table_option_struct *param_old, *param_new; - uint i; DBUG_ENTER("ha_example::check_if_incompatible_data"); /* This example shows how custom engine specific table and field @@ -978,7 +977,7 @@ bool ha_example::check_if_incompatible_data(HA_CREATE_INFO *info, DBUG_RETURN(COMPATIBLE_DATA_NO); #ifndef DBUG_OFF - for (i= 0; i < table->s->fields; i++) + for (uint i= 0; i < table->s->fields; i++) { ha_field_option_struct *f_old, *f_new; f_old= table->s->field[i]->option_struct; From 3e2cb35e11cb5ee6668d538a62a3b32e017944a5 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Sat, 3 Dec 2011 23:06:16 +0200 Subject: [PATCH 168/288] Added handler and temporary table usage to mytop Fixed prompt on reconnect in mysql client client/mysql.cc: Free server_version for reconnect. This ensures that prompt is correct if reconnecting to a different server. scripts/mytop.sh: Added handler and temporary table usage --- client/mysql.cc | 2 ++ scripts/mytop.sh | 38 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/client/mysql.cc b/client/mysql.cc index 824a416ec36..765c44e49c9 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -2780,6 +2780,8 @@ static int reconnect(void) } if (!connected) return put_info("Can't connect to the server\n",INFO_ERROR); + my_free(server_version,MYF(MY_ALLOW_ZERO_PTR)); + server_version= 0; /* purecov: end */ return 0; } diff --git a/scripts/mytop.sh b/scripts/mytop.sh index 5c88cf580a4..7cec85e2136 100755 --- a/scripts/mytop.sh +++ b/scripts/mytop.sh @@ -830,6 +830,11 @@ sub GetData() %OLD_STATUS = %STATUS; + # Set some status that may not exist in all versions + $STATUS{Handler_tmp_write}= 0; + $STATUS{Handler_tmp_update}= 0; + $STATUS{Rows_tmp_read}= 0; + foreach my $ref (@recs) { my $key = $ref->{Variable_name}; @@ -926,7 +931,7 @@ sub GetData() $lines_left--; - printf " Queries: %-6s qps: %4.0f Slow: %7s Se/In/Up/De(%%): %02.0f/%02.0f/%02.0f/%02.0f \n", + printf " Queries: %-6s qps: %4.0f Slow: %7s Se/In/Up/De(%%): %02.0f/%02.0f/%02.0f/%02.0f\n", make_short( $STATUS{Questions} ), # q total $STATUS{Questions} / $STATUS{Uptime}, # qps, average make_short( $STATUS{Slow_queries} ), # slow @@ -944,7 +949,7 @@ sub GetData() my $q_diff = ( $STATUS{Questions} - $OLD_STATUS{Questions} ); # print("q_diff: $STATUS{Questions} - $OLD_STATUS{Questions} / $t_delta = $q_diff\n"); - printf(" Sorts: %5.0f qps now: %4.0f Slow qps: %3.1f Threads: %4.0f (%4.0f/%4.0f) %02.0f/%02.0f/%02.0f/%02.0f \n", + printf(" Sorts: %5.0f qps now: %4.0f Slow qps: %3.1f Threads: %4.0f (%4.0f/%4.0f) %02.0f/%02.0f/%02.0f/%02.0f\n", ( $STATUS{Sort_rows} - $OLD_STATUS{Sort_rows} ) / $t_delta, ( $STATUS{Questions} - $OLD_STATUS{Questions} ) / $t_delta, ( # slow now (qps) @@ -1014,6 +1019,35 @@ sub GetData() } $lines_left--; + if ($t_delta) + { + printf(" Handler: (R/W/U/D) %5d/%5d/%5d/%5d Tmp: R/W/U: %5d/%5d/%5d\n", + ($STATUS{Handler_read_first}+$STATUS{Handler_read_key}+ + $STATUS{Handler_read_next}+$STATUS{Handler_read_prev}+ + $STATUS{Handler_read_rnd}+$STATUS{Handler_read_rnd_next} - + $OLD_STATUS{Handler_read_first}-$OLD_STATUS{Handler_read_key}- + $OLD_STATUS{Handler_read_next}-$OLD_STATUS{Handler_read_prev}- + $OLD_STATUS{Handler_read_rnd}- + $OLD_STATUS{Handler_read_rnd_next})/$t_delta, + ($STATUS{Handler_write} - $OLD_STATUS{Handler_write}) / + $t_delta, + ($STATUS{Handler_update} - $OLD_STATUS{Handler_update}) / + $t_delta, + ($STATUS{Handler_delete} - $OLD_STATUS{Handler_delete}) / + $t_delta, + ($STATUS{Rows_tmp_read} - $OLD_STATUS{Rows_tmp_read}) / + $t_delta, + ($STATUS{Handler_tmp_write} + -$OLD_STATUS{Handler_tmp_write})/$t_delta, + ($STATUS{Handler_tmp_update} - + $OLD_STATUS{Handler_tmp_update})/$t_delta); + } + else + { + print "\n"; + } + + $lines_left--; printf(" MyISAM Key Efficiency: %2.1f%% Bps in/out: %5s/%5s ", $cache_hits_percent, From 1f3e540385fd7705047242e58800fcceb5ef3da5 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 3 Dec 2011 22:44:33 +0100 Subject: [PATCH 169/288] updated the version in configure --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index 1e1441ef59b..51e1da541eb 100644 --- a/configure.in +++ b/configure.in @@ -13,7 +13,7 @@ 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([MariaDB Server], [5.2.9-MariaDB], [], [mysql]) +AC_INIT([MariaDB Server], [5.2.10-MariaDB], [], [mysql]) AC_CONFIG_SRCDIR([sql/mysqld.cc]) AC_CANONICAL_SYSTEM From b5a05df61ea263aa3c3b9df78c56148adf029f04 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Sun, 4 Dec 2011 07:43:33 -0800 Subject: [PATCH 170/288] Fixed LP bug #899696. If has been decided that the first match strategy is to be used to join table T from a semi-join nest while no buffer can be employed to join this table then no join buffer can be used to join any table in the join sequence between the first one belonging to the semi-join nest and table T. --- mysql-test/r/subselect_sj2_jcl6.result | 27 +++++++++++++++++++++++++ mysql-test/t/subselect_sj2_jcl6.test | 28 ++++++++++++++++++++++++++ sql/sql_select.cc | 3 +-- 3 files changed, 56 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/subselect_sj2_jcl6.result b/mysql-test/r/subselect_sj2_jcl6.result index 46b62ce843c..32d8d245477 100644 --- a/mysql-test/r/subselect_sj2_jcl6.result +++ b/mysql-test/r/subselect_sj2_jcl6.result @@ -928,6 +928,33 @@ x x set optimizer_switch=@tmp_optimizer_switch; set join_cache_level=default; DROP TABLE t1,t2,t3,t4; +# +# Bug #899696: potential incremental join cache for semijoin +# +CREATE TABLE t1 (pk int PRIMARY KEY, a int); +INSERT INTO t1 VALUES (1, 6), (2, 8); +CREATE TABLE t2 (b int) ENGINE=InnoDB; +INSERT INTO t2 VALUES (8); +CREATE TABLE t3 (pk int PRIMARY KEY, a int); +INSERT INTO t3 VALUES (1, 6), (2, 8); +CREATE TABLE t4 (b int) ENGINE=InnoDB; +INSERT INTO t4 VALUES (2); +set @tmp_optimizer_switch=@@optimizer_switch; +SET optimizer_switch = 'semijoin_with_cache=on'; +SET join_cache_level = 2; +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 t1 ALL NULL NULL NULL NULL 2 +1 PRIMARY t3 eq_ref PRIMARY PRIMARY 4 test.t4.b 1 Using where; FirstMatch(t4) +SELECT * FROM t1, t2 WHERE b IN (SELECT a FROM t3, t4 WHERE b = pk); +pk a b +1 6 8 +set optimizer_switch=@tmp_optimizer_switch; +set join_cache_level=default; +DROP TABLE t1,t2,t3,t4; set join_cache_level=default; show variables like 'join_cache_level'; Variable_name Value diff --git a/mysql-test/t/subselect_sj2_jcl6.test b/mysql-test/t/subselect_sj2_jcl6.test index 9628bd5c4b9..374fbd946c3 100644 --- a/mysql-test/t/subselect_sj2_jcl6.test +++ b/mysql-test/t/subselect_sj2_jcl6.test @@ -45,6 +45,34 @@ set join_cache_level=default; DROP TABLE t1,t2,t3,t4; +--echo # +--echo # Bug #899696: potential incremental join cache for semijoin +--echo # + +CREATE TABLE t1 (pk int PRIMARY KEY, a int); +INSERT INTO t1 VALUES (1, 6), (2, 8); +CREATE TABLE t2 (b int) ENGINE=InnoDB; +INSERT INTO t2 VALUES (8); +CREATE TABLE t3 (pk int PRIMARY KEY, a int); +INSERT INTO t3 VALUES (1, 6), (2, 8); +CREATE TABLE t4 (b int) ENGINE=InnoDB; +INSERT INTO t4 VALUES (2); + +set @tmp_optimizer_switch=@@optimizer_switch; + +SET optimizer_switch = 'semijoin_with_cache=on'; +SET join_cache_level = 2; + +EXPLAIN +SELECT * FROM t1, t2 WHERE b IN (SELECT a FROM t3, t4 WHERE b = pk); +SELECT * FROM t1, t2 WHERE b IN (SELECT a FROM t3, t4 WHERE b = pk); + +set optimizer_switch=@tmp_optimizer_switch; +set join_cache_level=default; + +DROP TABLE t1,t2,t3,t4; + + set join_cache_level=default; show variables like 'join_cache_level'; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 47adbd97289..7c36f7c4d8c 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -8767,8 +8767,7 @@ void revise_cache_usage(JOIN_TAB *join_tab) first_inner= join_tab->first_sj_inner_tab; for (tab= join_tab-1; tab >= first_inner; tab--) { - if (tab->first_sj_inner_tab == first_inner) - set_join_cache_denial(tab); + set_join_cache_denial(tab); } } else set_join_cache_denial(join_tab); From 255fd6c9294025ced406382980b0ad51960f0971 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Mon, 5 Dec 2011 01:31:42 +0400 Subject: [PATCH 171/288] Make subquery Materialization, as well as semi-join Materialization be shown in EXPLAIN as select_type==MATERIALIZED. Before, we had select_type==SUBQUERY and it was difficult to tell materialized subqueries from uncorrelated scalar-context subqueries. --- mysql-test/r/func_group.result | 12 +- mysql-test/r/group_by.result | 2 +- mysql-test/r/group_min_max.result | 2 +- mysql-test/r/myisam_icp.result | 4 +- mysql-test/r/subselect.result | 16 +- mysql-test/r/subselect3.result | 4 +- mysql-test/r/subselect3_jcl6.result | 4 +- mysql-test/r/subselect4.result | 116 ++++++------- mysql-test/r/subselect_cache.result | 2 +- mysql-test/r/subselect_extra.result | 2 +- .../r/subselect_extra_no_semijoin.result | 8 +- mysql-test/r/subselect_mat.result | 160 +++++++++--------- mysql-test/r/subselect_mat_cost.result | 30 ++-- mysql-test/r/subselect_mat_cost_bugs.result | 12 +- mysql-test/r/subselect_no_mat.result | 2 +- mysql-test/r/subselect_no_opts.result | 2 +- mysql-test/r/subselect_no_scache.result | 16 +- mysql-test/r/subselect_no_semijoin.result | 58 +++---- mysql-test/r/subselect_partial_match.result | 50 +++--- mysql-test/r/subselect_sj.result | 30 ++-- mysql-test/r/subselect_sj2.result | 28 +-- mysql-test/r/subselect_sj2_jcl6.result | 28 +-- mysql-test/r/subselect_sj2_mat.result | 28 +-- mysql-test/r/subselect_sj_jcl6.result | 30 ++-- mysql-test/r/subselect_sj_mat.result | 110 ++++++------ mysql-test/r/subselect_sj_nonmerged.result | 28 +-- mysql-test/suite/pbxt/r/subselect.result | 6 +- sql/sql_lex.cc | 64 +++++-- sql/sql_select.cc | 2 +- 29 files changed, 447 insertions(+), 409 deletions(-) diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result index 0983d76f449..5b193afafb1 100644 --- a/mysql-test/r/func_group.result +++ b/mysql-test/r/func_group.result @@ -1865,7 +1865,7 @@ SELECT v FROM t2); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE -2 SUBQUERY t2 ALL NULL NULL NULL NULL 2 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 Warnings: Warning 1292 Truncated incorrect INTEGER value: 'j' @@ -1891,7 +1891,7 @@ SELECT v FROM t2); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No matching min/max row -2 SUBQUERY t2 ALL NULL NULL NULL NULL 2 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 # # 3) Test that subquery materialization is setup for query with @@ -1915,7 +1915,7 @@ SELECT v FROM t2); 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 SUBQUERY t2 ALL NULL NULL NULL NULL 2 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 # # 4) Test that subquery materialization is setup for query with @@ -1940,7 +1940,7 @@ SELECT v FROM t2); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY system NULL NULL NULL NULL 0 const row not found -3 SUBQUERY t2 ALL NULL NULL NULL NULL 2 +3 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 2 DERIVED NULL NULL NULL NULL NULL NULL NULL no matching row in const table set optimizer_switch=@tmp_optimizer_switch; @@ -1967,8 +1967,8 @@ SELECT v FROM t2); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 index NULL PRIMARY 4 NULL 2 Using where; Using index -3 SUBQUERY t2 ALL NULL NULL NULL NULL 2 -2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +3 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 +2 MATERIALIZED NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables set @@optimizer_switch=@save_optimizer_switch; # # Cleanup for BUG#46680 diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result index 1f93171c09d..5804e8983a3 100644 --- a/mysql-test/r/group_by.result +++ b/mysql-test/r/group_by.result @@ -1544,7 +1544,7 @@ EXPLAIN SELECT 1 FROM t1 WHERE a IN id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 index PRIMARY,i2 PRIMARY 4 NULL 144 Using index 1 PRIMARY eq_ref distinct_key distinct_key 4 func 1 -2 SUBQUERY t1 ALL NULL NULL NULL NULL 144 +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 144 CREATE TABLE t2 (a INT, b INT, KEY(a)); INSERT INTO t2 VALUES (1, 1), (2, 2), (3,3), (4,4); EXPLAIN SELECT a, SUM(b) FROM t2 GROUP BY a LIMIT 2; diff --git a/mysql-test/r/group_min_max.result b/mysql-test/r/group_min_max.result index 56bfcf6c71c..a215063d0aa 100644 --- a/mysql-test/r/group_min_max.result +++ b/mysql-test/r/group_min_max.result @@ -2403,7 +2403,7 @@ a IN (SELECT max(b) FROM t1 GROUP BY a HAVING a < 2); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL distinct_key NULL NULL NULL 8 Using where 1 PRIMARY t1_outer ref a a 5 .max(b) 2 Using index -2 SUBQUERY t1 range NULL a 5 NULL 8 Using index for group-by +2 MATERIALIZED t1 range NULL a 5 NULL 8 Using index for group-by EXPLAIN SELECT 1 FROM t1 AS t1_outer GROUP BY a HAVING a > (SELECT max(b) FROM t1 GROUP BY a HAVING a < 2); id select_type table type possible_keys key key_len ref rows Extra diff --git a/mysql-test/r/myisam_icp.result b/mysql-test/r/myisam_icp.result index f357247d384..6d8b28ae23d 100644 --- a/mysql-test/r/myisam_icp.result +++ b/mysql-test/r/myisam_icp.result @@ -763,8 +763,8 @@ t2.b NOT IN (SELECT t4.b FROM t3 STRAIGHT_JOIN t4 WHERE t4.b <= 2 AND t4.c = t3. 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 -2 SUBQUERY t3 ALL NULL NULL NULL NULL 2 -2 SUBQUERY t4 range b b 5 NULL 1 Using index condition; Using where; Rowid-ordered scan; Using join buffer (flat, BNL join) +2 MATERIALIZED t3 ALL NULL NULL NULL NULL 2 +2 MATERIALIZED t4 range b b 5 NULL 1 Using index condition; Using where; Rowid-ordered scan; Using join buffer (flat, BNL join) SELECT * FROM t1 LEFT JOIN t2 ON t1.c=t2.b WHERE t2.b NOT IN (SELECT t4.b FROM t3 STRAIGHT_JOIN t4 WHERE t4.b <= 2 AND t4.c = t3.c); diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 221a313968a..0a4a16962ff 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -2973,7 +2973,7 @@ explain extended SELECT one,two from t1 where ROW(one,two) IN (SELECT one,two FR id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 8 100.00 1 PRIMARY eq_ref distinct_key distinct_key 10 func,func 1 100.00 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 9 100.00 Using where +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 9 100.00 Using where Warnings: Note 1003 select `test`.`t1`.`one` AS `one`,`test`.`t1`.`two` AS `two` from `test`.`t1` semi join (`test`.`t2`) where ((`test`.`t2`.`flag` = 'N')) explain extended SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0' group by one,two) as 'test' from t1; @@ -3563,7 +3563,7 @@ SELECT * FROM t1 WHERE (a,b) = ANY (SELECT a, max(b) FROM t1 GROUP BY a); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 9 Using where 1 PRIMARY eq_ref distinct_key distinct_key 23 test.t1.a,test.t1.b 1 -2 SUBQUERY t1 ALL NULL NULL NULL NULL 9 Using temporary +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 9 Using temporary ALTER TABLE t1 ADD INDEX(a); SELECT * FROM t1 WHERE (a,b) = ANY (SELECT a, max(b) FROM t1 GROUP BY a); a b @@ -3575,7 +3575,7 @@ SELECT * FROM t1 WHERE (a,b) = ANY (SELECT a, max(b) FROM t1 GROUP BY a); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL a NULL NULL NULL 9 Using where 1 PRIMARY eq_ref distinct_key distinct_key 23 test.t1.a,test.t1.b 1 -2 SUBQUERY t1 ALL NULL NULL NULL NULL 9 Using temporary +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 9 Using temporary DROP TABLE t1; create table t1( f1 int,f2 int); insert into t1 values (1,1),(2,2); @@ -4466,14 +4466,14 @@ 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 1 PRIMARY const distinct_key distinct_key 4 const 1 100.00 -2 SUBQUERY t1 ALL NULL NULL NULL NULL 2 100.00 Using temporary +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 2 100.00 Using temporary Warnings: Note 1003 select 1 AS `1` from (select 1 from `test`.`t1` group by `test`.`t1`.`a`) join `test`.`t1` where (``.`1` = 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 t1 ALL NULL NULL NULL NULL 2 100.00 1 PRIMARY const distinct_key distinct_key 4 const 1 100.00 -2 SUBQUERY t1 ALL NULL NULL NULL NULL 2 100.00 Using where; Using temporary +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 2 100.00 Using where; Using temporary Warnings: Note 1003 select 1 AS `1` from (select 1 from `test`.`t1` where (`test`.`t1`.`a` > 3) group by `test`.`t1`.`a`) join `test`.`t1` where (``.`1` = 1) DROP TABLE t1; @@ -5160,8 +5160,8 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ot1 ALL NULL NULL NULL NULL 2 1 PRIMARY ALL distinct_key NULL NULL NULL 24 Using where 1 PRIMARY ot4 ALL NULL NULL NULL NULL 8 Using where; Using join buffer (flat, BNL join) -2 SUBQUERY it2 ALL NULL NULL NULL NULL 4 -2 SUBQUERY it3 ALL NULL NULL NULL NULL 6 Using join buffer (flat, BNL join) +2 MATERIALIZED it2 ALL NULL NULL NULL NULL 4 +2 MATERIALIZED it3 ALL NULL NULL NULL NULL 6 Using join buffer (flat, BNL join) DROP TABLE IF EXISTS ot1, ot4, it2, it3; # # Bug#729039: NULL keys used to evaluate subquery @@ -5861,7 +5861,7 @@ SET @@optimizer_switch='semijoin=off,materialization=on,in_to_exists=off,subquer EXPLAIN SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 index NULL a 4 NULL 2 Using where; Using index -2 SUBQUERY t1 index NULL a 4 NULL 2 Using index +2 MATERIALIZED t1 index NULL a 4 NULL 2 Using index SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1); a 2009-01-01 diff --git a/mysql-test/r/subselect3.result b/mysql-test/r/subselect3.result index 28436a7cc23..898eed164b7 100644 --- a/mysql-test/r/subselect3.result +++ b/mysql-test/r/subselect3.result @@ -1180,7 +1180,7 @@ explain select * from t3 where a in (select a from t2) and (a > 5 or a < 10); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL distinct_key NULL NULL NULL 2 1 PRIMARY t3 ref a a 5 test.t2.a 1 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 2 Using where +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 Using where select * from t3 where a in (select a from t2); a filler 1 filler @@ -1474,7 +1474,7 @@ FROM t3 ); 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 -3 SUBQUERY t3 ALL NULL NULL NULL NULL 2 100.00 +3 MATERIALIZED t3 ALL NULL NULL NULL NULL 2 100.00 2 SUBQUERY t2 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (not(<(select `test`.`t2`.`a` from `test`.`t2` where (`test`.`t2`.`a` = 9))>(((select `test`.`t2`.`a` from `test`.`t2` where (`test`.`t2`.`a` = 9)),(select `test`.`t2`.`a` from `test`.`t2` where (`test`.`t2`.`a` = 9)) in ( (select `test`.`t3`.`b` from `test`.`t3` ), (9 in on distinct_key where ((9 = ``.`b`)))))))) diff --git a/mysql-test/r/subselect3_jcl6.result b/mysql-test/r/subselect3_jcl6.result index 59848c565d5..59750f2cfa0 100644 --- a/mysql-test/r/subselect3_jcl6.result +++ b/mysql-test/r/subselect3_jcl6.result @@ -1189,7 +1189,7 @@ explain select * from t3 where a in (select a from t2) and (a > 5 or a < 10); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL distinct_key NULL NULL NULL 2 1 PRIMARY t3 ref a a 5 test.t2.a 1 Using join buffer (flat, BKA join); Key-ordered Rowid-ordered scan -2 SUBQUERY t2 ALL NULL NULL NULL NULL 2 Using where +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 Using where select * from t3 where a in (select a from t2); a filler 1 filler @@ -1483,7 +1483,7 @@ FROM t3 ); 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 -3 SUBQUERY t3 ALL NULL NULL NULL NULL 2 100.00 +3 MATERIALIZED t3 ALL NULL NULL NULL NULL 2 100.00 2 SUBQUERY t2 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (not(<(select `test`.`t2`.`a` from `test`.`t2` where (`test`.`t2`.`a` = 9))>(((select `test`.`t2`.`a` from `test`.`t2` where (`test`.`t2`.`a` = 9)),(select `test`.`t2`.`a` from `test`.`t2` where (`test`.`t2`.`a` = 9)) in ( (select `test`.`t3`.`b` from `test`.`t3` ), (9 in on distinct_key where ((9 = ``.`b`)))))))) diff --git a/mysql-test/r/subselect4.result b/mysql-test/r/subselect4.result index e9e2924884a..76496d73ef9 100644 --- a/mysql-test/r/subselect4.result +++ b/mysql-test/r/subselect4.result @@ -337,8 +337,8 @@ WHERE PTYPE = 'Design')); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL t1_IDX NULL NULL NULL 5 1 PRIMARY eq_ref distinct_key distinct_key 3 func 1 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 6 Using where -2 SUBQUERY t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 6 Using where +2 MATERIALIZED t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) PREPARE stmt FROM "EXPLAIN SELECT EMPNAME FROM t1 WHERE EMPNUM IN @@ -352,14 +352,14 @@ EXECUTE stmt; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL t1_IDX NULL NULL NULL 5 1 PRIMARY eq_ref distinct_key distinct_key 3 func 1 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 6 Using where -2 SUBQUERY t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 6 Using where +2 MATERIALIZED t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) EXECUTE stmt; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL t1_IDX NULL NULL NULL 5 1 SIMPLE eq_ref distinct_key distinct_key 3 func 1 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 6 Using where -2 SUBQUERY t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 6 Using where +2 MATERIALIZED t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) DEALLOCATE PREPARE stmt; DROP INDEX t1_IDX ON t1; CREATE INDEX t1_IDX ON t1(EMPNUM); @@ -375,8 +375,8 @@ WHERE PTYPE = 'Design')); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL t1_IDX NULL NULL NULL 5 1 PRIMARY eq_ref distinct_key distinct_key 3 func 1 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 6 Using where -2 SUBQUERY t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 6 Using where +2 MATERIALIZED t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) PREPARE stmt FROM "EXPLAIN SELECT EMPNAME FROM t1 WHERE EMPNUM IN @@ -390,14 +390,14 @@ EXECUTE stmt; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL t1_IDX NULL NULL NULL 5 1 PRIMARY eq_ref distinct_key distinct_key 3 func 1 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 6 Using where -2 SUBQUERY t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 6 Using where +2 MATERIALIZED t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) EXECUTE stmt; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL t1_IDX NULL NULL NULL 5 1 SIMPLE eq_ref distinct_key distinct_key 3 func 1 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 6 Using where -2 SUBQUERY t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 6 Using where +2 MATERIALIZED t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) DEALLOCATE PREPARE stmt; DROP INDEX t1_IDX ON t1; EXPLAIN SELECT EMPNAME @@ -412,8 +412,8 @@ WHERE PTYPE = 'Design')); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 5 1 PRIMARY eq_ref distinct_key distinct_key 3 func 1 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 6 Using where -2 SUBQUERY t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 6 Using where +2 MATERIALIZED t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) PREPARE stmt FROM "EXPLAIN SELECT EMPNAME FROM t1 WHERE EMPNUM IN @@ -427,14 +427,14 @@ EXECUTE stmt; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 5 1 PRIMARY eq_ref distinct_key distinct_key 3 func 1 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 6 Using where -2 SUBQUERY t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 6 Using where +2 MATERIALIZED t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) EXECUTE stmt; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 5 1 SIMPLE eq_ref distinct_key distinct_key 3 func 1 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 6 Using where -2 SUBQUERY t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 6 Using where +2 MATERIALIZED t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) DEALLOCATE PREPARE stmt; SET SESSION optimizer_switch = @old_optimizer_switch; SET SESSION join_cache_level = @old_join_cache_level; @@ -560,8 +560,8 @@ WHERE PTYPE = 'Design')); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL t1_IDX NULL NULL NULL 5 1 PRIMARY eq_ref distinct_key distinct_key 3 func 1 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 6 Using where -2 SUBQUERY t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 6 Using where +2 MATERIALIZED t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) PREPARE stmt FROM "EXPLAIN SELECT EMPNAME FROM t1 WHERE EMPNUM IN @@ -575,14 +575,14 @@ EXECUTE stmt; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL t1_IDX NULL NULL NULL 5 1 PRIMARY eq_ref distinct_key distinct_key 3 func 1 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 6 Using where -2 SUBQUERY t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 6 Using where +2 MATERIALIZED t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) EXECUTE stmt; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL t1_IDX NULL NULL NULL 5 1 SIMPLE eq_ref distinct_key distinct_key 3 func 1 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 6 Using where -2 SUBQUERY t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 6 Using where +2 MATERIALIZED t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) DEALLOCATE PREPARE stmt; DROP INDEX t1_IDX ON t1; CREATE INDEX t1_IDX ON t1(EMPNUM); @@ -598,8 +598,8 @@ WHERE PTYPE = 'Design')); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL t1_IDX NULL NULL NULL 5 1 PRIMARY eq_ref distinct_key distinct_key 3 func 1 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 6 Using where -2 SUBQUERY t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 6 Using where +2 MATERIALIZED t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) PREPARE stmt FROM "EXPLAIN SELECT EMPNAME FROM t1 WHERE EMPNUM IN @@ -613,14 +613,14 @@ EXECUTE stmt; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL t1_IDX NULL NULL NULL 5 1 PRIMARY eq_ref distinct_key distinct_key 3 func 1 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 6 Using where -2 SUBQUERY t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 6 Using where +2 MATERIALIZED t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) EXECUTE stmt; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL t1_IDX NULL NULL NULL 5 1 SIMPLE eq_ref distinct_key distinct_key 3 func 1 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 6 Using where -2 SUBQUERY t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 6 Using where +2 MATERIALIZED t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) DEALLOCATE PREPARE stmt; DROP INDEX t1_IDX ON t1; EXPLAIN SELECT EMPNAME @@ -635,8 +635,8 @@ WHERE PTYPE = 'Design')); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 5 1 PRIMARY eq_ref distinct_key distinct_key 3 func 1 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 6 Using where -2 SUBQUERY t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 6 Using where +2 MATERIALIZED t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) PREPARE stmt FROM "EXPLAIN SELECT EMPNAME FROM t1 WHERE EMPNUM IN @@ -650,14 +650,14 @@ EXECUTE stmt; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 5 1 PRIMARY eq_ref distinct_key distinct_key 3 func 1 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 6 Using where -2 SUBQUERY t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 6 Using where +2 MATERIALIZED t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) EXECUTE stmt; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 5 1 SIMPLE eq_ref distinct_key distinct_key 3 func 1 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 6 Using where -2 SUBQUERY t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 6 Using where +2 MATERIALIZED t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) DEALLOCATE PREPARE stmt; SET SESSION optimizer_switch = @old_optimizer_switch; SET SESSION join_cache_level = @old_join_cache_level; @@ -716,7 +716,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ref f3 f3 5 const 0 Using index condition 2 SUBQUERY t1 ALL NULL NULL NULL NULL 2 Using where 2 SUBQUERY eq_ref distinct_key distinct_key 5 test.t1.f10 1 -3 SUBQUERY t2 ALL NULL NULL NULL NULL 2 Using temporary +3 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 Using temporary SELECT * FROM t1 WHERE f3 = ( SELECT t1.f3 FROM t1 @@ -731,7 +731,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ref f3 f3 5 const 0 Using index condition 2 SUBQUERY t1 ALL NULL NULL NULL NULL 2 Using where 2 SUBQUERY eq_ref distinct_key distinct_key 10 test.t1.f10,test.t1.f10 1 -3 SUBQUERY t2 ALL NULL NULL NULL NULL 2 Using temporary +3 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 Using temporary SELECT * FROM t1 WHERE f3 = ( SELECT f3 FROM t1 @@ -750,21 +750,21 @@ EXPLAIN SELECT * FROM t1 WHERE (2, 0) NOT IN (SELECT f3, min(f4) FROM t2); 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 SUBQUERY t2 system NULL NULL NULL NULL 0 const row not found +2 MATERIALIZED t2 system NULL NULL NULL NULL 0 const row not found SELECT * FROM t1 WHERE (2, 0) NOT IN (SELECT f3, min(f4) FROM t2); f1 f2 EXPLAIN SELECT * FROM t1 WHERE (2, 0) NOT IN (SELECT f3+f4, min(f4) FROM t2); 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 SUBQUERY t2 system NULL NULL NULL NULL 0 const row not found +2 MATERIALIZED t2 system NULL NULL NULL NULL 0 const row not found SELECT * FROM t1 WHERE (2, 0) NOT IN (SELECT f3+f4, min(f4) FROM t2); f1 f2 EXPLAIN SELECT * FROM t1 WHERE (2, 0) NOT IN (SELECT f3, min(f4)+max(f4) FROM t2); 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 SUBQUERY t2 system NULL NULL NULL NULL 0 const row not found +2 MATERIALIZED t2 system NULL NULL NULL NULL 0 const row not found SELECT * FROM t1 WHERE (2, 0) NOT IN (SELECT f3, min(f4)+max(f4) FROM t2); f1 f2 EXPLAIN @@ -779,14 +779,14 @@ EXPLAIN SELECT * FROM t1 WHERE (2, 0) NOT IN (SELECT f3, count(f4) FROM t2); 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 SUBQUERY t2 system NULL NULL NULL NULL 0 const row not found +2 MATERIALIZED t2 system NULL NULL NULL NULL 0 const row not found SELECT * FROM t1 WHERE (2, 0) NOT IN (SELECT f3, count(f4) FROM t2); f1 f2 EXPLAIN SELECT * FROM t1 WHERE (2, 0) NOT IN (SELECT f3, f3 + count(f4) FROM t2); 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 SUBQUERY t2 system NULL NULL NULL NULL 0 const row not found +2 MATERIALIZED t2 system NULL NULL NULL NULL 0 const row not found SELECT * FROM t1 WHERE (2, 0) NOT IN (SELECT f3, f3 + count(f4) FROM t2); f1 f2 EXPLAIN @@ -936,21 +936,21 @@ EXPLAIN SELECT * FROM t1 WHERE (2, 0) NOT IN (SELECT f3, min(f4) FROM t2 WHERE f3 > 10); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 2 -2 SUBQUERY t2 range PRIMARY PRIMARY 4 NULL 1 Using index condition; Rowid-ordered scan +2 MATERIALIZED t2 range PRIMARY PRIMARY 4 NULL 1 Using index condition; Rowid-ordered scan SELECT * FROM t1 WHERE (2, 0) NOT IN (SELECT f3, min(f4) FROM t2 WHERE f3 > 10); f1 f2 EXPLAIN SELECT * FROM t1 WHERE (2, 0) NOT IN (SELECT f3+f4, min(f4) FROM t2 WHERE f3 > 10); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 2 -2 SUBQUERY t2 range PRIMARY PRIMARY 4 NULL 1 Using index condition; Rowid-ordered scan +2 MATERIALIZED t2 range PRIMARY PRIMARY 4 NULL 1 Using index condition; Rowid-ordered scan SELECT * FROM t1 WHERE (2, 0) NOT IN (SELECT f3+f4, min(f4) FROM t2 WHERE f3 > 10); f1 f2 EXPLAIN SELECT * FROM t1 WHERE (2, 0) NOT IN (SELECT f3, min(f4)+max(f4) FROM t2 WHERE f3 > 10); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 2 -2 SUBQUERY t2 range PRIMARY PRIMARY 4 NULL 1 Using index condition; Rowid-ordered scan +2 MATERIALIZED t2 range PRIMARY PRIMARY 4 NULL 1 Using index condition; Rowid-ordered scan SELECT * FROM t1 WHERE (2, 0) NOT IN (SELECT f3, min(f4)+max(f4) FROM t2 WHERE f3 > 10); f1 f2 EXPLAIN @@ -965,14 +965,14 @@ EXPLAIN SELECT * FROM t1 WHERE (2, 0) NOT IN (SELECT f3, count(f4) FROM t2 WHERE f3 > 10); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 2 -2 SUBQUERY t2 range PRIMARY PRIMARY 4 NULL 1 Using index condition; Rowid-ordered scan +2 MATERIALIZED t2 range PRIMARY PRIMARY 4 NULL 1 Using index condition; Rowid-ordered scan SELECT * FROM t1 WHERE (2, 0) NOT IN (SELECT f3, count(f4) FROM t2 WHERE f3 > 10); f1 f2 EXPLAIN SELECT * FROM t1 WHERE (2, 0) NOT IN (SELECT f3, f3 + count(f4) FROM t2 WHERE f3 > 10); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 2 -2 SUBQUERY t2 range PRIMARY PRIMARY 4 NULL 1 Using index condition; Rowid-ordered scan +2 MATERIALIZED t2 range PRIMARY PRIMARY 4 NULL 1 Using index condition; Rowid-ordered scan SELECT * FROM t1 WHERE (2, 0) NOT IN (SELECT f3, f3 + count(f4) FROM t2 WHERE f3 > 10); f1 f2 EXPLAIN @@ -1158,7 +1158,7 @@ WHERE (t2.pk = t1.pk) AND t2.pk IN (SELECT f2 FROM t1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 system PRIMARY NULL NULL NULL 1 1 PRIMARY t1 const PRIMARY PRIMARY 4 const 1 -2 SUBQUERY t1 index NULL f2 4 NULL 2 Using index +2 MATERIALIZED t1 index NULL f2 4 NULL 2 Using index SELECT t1.f3, MAX(t1.f2) FROM t1, t2 WHERE (t2.pk = t1.pk) AND t2.pk IN (SELECT f2 FROM t1); @@ -1249,7 +1249,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY eq_ref distinct_key distinct_key 5 func 1 1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using join buffer (flat, BNL join) 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 Using where -2 SUBQUERY t2 ALL NULL NULL NULL NULL 2 Using where +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 Using where SELECT * FROM (t2 LEFT JOIN t1 ON t1.c1) LEFT JOIN t3 on t3.c1 WHERE 's' IN (SELECT c1 FROM t2); c1 c1 c1 EXPLAIN @@ -1258,7 +1258,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY eq_ref distinct_key distinct_key 5 func 1 1 PRIMARY t4 index NULL PRIMARY 3 NULL 2 Using index; Using join buffer (flat, BNL join) 1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where -2 SUBQUERY t2 ALL NULL NULL NULL NULL 2 Using where +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 Using where SELECT * FROM t4 LEFT JOIN t2 ON t4.c1 WHERE 's' IN (SELECT c1 FROM t2); c1 c1 drop table t1, t2, t3, t4; @@ -1534,7 +1534,7 @@ EXPLAIN SELECT 'bug' FROM t3 WHERE ( 5 ) IN (SELECT * FROM v2); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t3 system NULL NULL NULL NULL 1 -2 SUBQUERY ALL NULL NULL NULL NULL 2 +2 MATERIALIZED ALL NULL NULL NULL NULL 2 3 DERIVED t1 system NULL NULL NULL NULL 1 4 UNION t2 system NULL NULL NULL NULL 1 NULL UNION RESULT ALL NULL NULL NULL NULL NULL @@ -1661,7 +1661,7 @@ WHERE ( alias2.f1 , alias2.f2 ) IN ( SELECT f2 , f1 FROM t0 GROUP BY f2 , f1 ); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY alias2 ALL NULL NULL NULL NULL 2 Using where 1 PRIMARY alias1 index NULL PRIMARY 4 NULL 2 Using where; Using index -2 SUBQUERY t0 ALL NULL NULL NULL NULL 2 +2 MATERIALIZED t0 ALL NULL NULL NULL NULL 2 SELECT alias2.f1 , alias2.f2 FROM t0 AS alias1 RIGHT JOIN t0 AS alias2 ON alias2.f10 @@ -1880,7 +1880,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 index NULL col_int_key 5 NULL 2 Using index 2 SUBQUERY SUBQUERY2_t1 index NULL col_int_key 5 NULL 2 Using index 2 SUBQUERY SUBQUERY2_t2 ALL col_varchar_key NULL NULL NULL 2 Using where; Using join buffer (flat, BNL join) -3 SUBQUERY t1 ALL NULL NULL NULL NULL 2 Using temporary +3 MATERIALIZED t1 ALL NULL NULL NULL NULL 2 Using temporary SELECT col_int_key FROM t2 WHERE (SELECT SUBQUERY2_t1.col_int_key @@ -1927,7 +1927,7 @@ EXPLAIN SELECT * FROM t1 JOIN v2 ON t1.f2 > 'a' WHERE v2.f3 IN ( SELECT f2 FROM id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where 1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where; Using join buffer (flat, BNL join) -2 SUBQUERY t1 ALL NULL NULL NULL NULL 2 +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 2 PREPARE st1 FROM "SELECT * FROM t1 JOIN v2 ON t1.f2 > 'a' WHERE v2.f3 IN ( SELECT f2 FROM t1 )"; EXECUTE st1; f1 f2 f3 @@ -1957,7 +1957,7 @@ EXPLAIN SELECT * FROM t1 JOIN v2 ON t1.f2 > 'a' WHERE v2.f3 IN ( SELECT f2 FROM id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where 1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where; Using join buffer (flat, BNL join) -2 SUBQUERY t1 ALL NULL NULL NULL NULL 2 +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 2 PREPARE st3 FROM "SELECT * FROM t1 JOIN v2 ON t1.f2 > 'a' WHERE v2.f3 IN ( SELECT f2 FROM t1 )"; EXECUTE st3; f1 f2 f3 @@ -1989,7 +1989,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t3 system NULL NULL NULL NULL 1 Using temporary; Using filesort 1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where 2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables -3 SUBQUERY t1 system NULL NULL NULL NULL 0 const row not found +3 MATERIALIZED t1 system NULL NULL NULL NULL 0 const row not found PREPARE st1 FROM " SELECT t2.f1, (SELECT f2 FROM t1 WHERE (7) IN (SELECT f1 FROM t1)) FROM t2 JOIN t3 ON t3.f4 = t2.f4 @@ -2021,7 +2021,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 1 1 PRIMARY t3 system NULL NULL NULL NULL 1 1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where -2 SUBQUERY t2 ALL NULL NULL NULL NULL 2 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 SELECT t1.f4 FROM t1 JOIN ( t2 JOIN t3 ON t3.f3 = t2.f4 ) ON t3.f3 = t2.f3 WHERE t1.f4 IN ( SELECT f4 FROM t2 ) ; diff --git a/mysql-test/r/subselect_cache.result b/mysql-test/r/subselect_cache.result index 8b04cc0c202..9bedf154cfd 100644 --- a/mysql-test/r/subselect_cache.result +++ b/mysql-test/r/subselect_cache.result @@ -1807,7 +1807,7 @@ set optimizer_switch='default,semijoin=off,materialization=on,subquery_cache=on' explain select * from t1 where a in (select pk from t2); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 15 Using where -2 SUBQUERY t2 ALL NULL NULL NULL NULL 10 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 10 flush status; select * from t1 where a in (select pk from t2); a b diff --git a/mysql-test/r/subselect_extra.result b/mysql-test/r/subselect_extra.result index 308e6715fe6..c9f69c9e3c1 100644 --- a/mysql-test/r/subselect_extra.result +++ b/mysql-test/r/subselect_extra.result @@ -308,7 +308,7 @@ EXPLAIN SELECT 1 FROM t1 WHERE a IN id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 index PRIMARY,i2 PRIMARY 4 NULL 144 Using index 1 PRIMARY eq_ref distinct_key distinct_key 4 func 1 -2 SUBQUERY t1 ALL NULL NULL NULL NULL 144 +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 144 CREATE TABLE t2 (a INT, b INT, KEY(a)); INSERT INTO t2 VALUES (1, 1), (2, 2), (3,3), (4,4); EXPLAIN SELECT a, SUM(b) FROM t2 GROUP BY a LIMIT 2; diff --git a/mysql-test/r/subselect_extra_no_semijoin.result b/mysql-test/r/subselect_extra_no_semijoin.result index ebe99550e46..cf789d5909c 100644 --- a/mysql-test/r/subselect_extra_no_semijoin.result +++ b/mysql-test/r/subselect_extra_no_semijoin.result @@ -311,7 +311,7 @@ EXPLAIN SELECT 1 FROM t1 WHERE a IN (SELECT a FROM t1 USE INDEX (i2) IGNORE INDEX (i2)); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 index NULL PRIMARY 4 NULL 144 Using where; Using index -2 SUBQUERY t1 ALL NULL NULL NULL NULL 144 +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 144 CREATE TABLE t2 (a INT, b INT, KEY(a)); INSERT INTO t2 VALUES (1, 1), (2, 2), (3,3), (4,4); EXPLAIN SELECT a, SUM(b) FROM t2 GROUP BY a LIMIT 2; @@ -324,7 +324,7 @@ EXPLAIN SELECT 1 FROM t2 WHERE a IN (SELECT a FROM t1 USE INDEX (i2) IGNORE INDEX (i2)); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 index NULL a 5 NULL 4 Using where; Using index -2 SUBQUERY t1 ALL NULL NULL NULL NULL 144 +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 144 DROP TABLE t1, t2; # # From derived_view.test @@ -349,7 +349,7 @@ WHERE t.a IN (SELECT b FROM t1); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 system NULL NULL NULL NULL 1 100.00 1 PRIMARY t2 ALL NULL NULL NULL NULL 2 100.00 Using where -3 SUBQUERY t1 system NULL NULL NULL NULL 1 100.00 +3 MATERIALIZED t1 system NULL NULL NULL NULL 1 100.00 Warnings: Note 1003 select `test`.`t2`.`a` AS `a`,0 AS `a`,0 AS `b` from `test`.`t1` left join `test`.`t2` on((0 <> 0)) where <0>((0,0 in ( (select 0 from `test`.`t1` ), (0 in on distinct_key where ((0 = ``.`b`)))))) SELECT * FROM t2 RIGHT JOIN v1 AS t ON t.a != 0 @@ -362,7 +362,7 @@ WHERE t.a IN (SELECT b FROM t1); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 system NULL NULL NULL NULL 1 100.00 1 PRIMARY t2 ALL NULL NULL NULL NULL 2 100.00 Using where -2 SUBQUERY t1 system NULL NULL NULL NULL 1 100.00 +2 MATERIALIZED t1 system NULL NULL NULL NULL 1 100.00 Warnings: Note 1003 select `test`.`t2`.`a` AS `a`,0 AS `a`,0 AS `b` from `test`.`t1` left join `test`.`t2` on((0 <> 0)) where <0>((0,0 in ( (select 0 from `test`.`t1` ), (0 in on distinct_key where ((0 = ``.`b`)))))) DROP VIEW v1; diff --git a/mysql-test/r/subselect_mat.result b/mysql-test/r/subselect_mat.result index 8eaad6d8034..31a9227ab0f 100644 --- a/mysql-test/r/subselect_mat.result +++ b/mysql-test/r/subselect_mat.result @@ -46,7 +46,7 @@ explain extended select * from t1 where a1 in (select b1 from t2 where b1 > '0'); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where -2 SUBQUERY t2 ALL NULL NULL NULL NULL 5 100.00 Using where +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 5 100.00 Using where Warnings: Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where <`test`.`t1`.`a1`>((`test`.`t1`.`a1`,`test`.`t1`.`a1` in ( (select `test`.`t2`.`b1` from `test`.`t2` where (`test`.`t2`.`b1` > '0') ), (`test`.`t1`.`a1` in on distinct_key where ((`test`.`t1`.`a1` = ``.`b1`)))))) select * from t1 where a1 in (select b1 from t2 where b1 > '0'); @@ -57,7 +57,7 @@ explain extended select * from t1 where a1 in (select b1 from t2 where b1 > '0' group by b1); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where -2 SUBQUERY t2 ALL NULL NULL NULL NULL 5 100.00 Using where; Using temporary +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 5 100.00 Using where; Using temporary Warnings: Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where <`test`.`t1`.`a1`>((`test`.`t1`.`a1`,`test`.`t1`.`a1` in ( (select `test`.`t2`.`b1` from `test`.`t2` where (`test`.`t2`.`b1` > '0') group by `test`.`t2`.`b1` ), (`test`.`t1`.`a1` in on distinct_key where ((`test`.`t1`.`a1` = ``.`b1`)))))) select * from t1 where a1 in (select b1 from t2 where b1 > '0' group by b1); @@ -68,7 +68,7 @@ explain extended select * from t1 where (a1, a2) in (select b1, b2 from t2 where b1 > '0' group by b1, b2); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where -2 SUBQUERY t2 ALL NULL NULL NULL NULL 5 100.00 Using where; Using temporary +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 5 100.00 Using where; Using temporary Warnings: Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where <`test`.`t1`.`a1`,`test`.`t1`.`a2`>(((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( (select `test`.`t2`.`b1`,`test`.`t2`.`b2` from `test`.`t2` where (`test`.`t2`.`b1` > '0') group by `test`.`t2`.`b1`,`test`.`t2`.`b2` ), (`test`.`t1`.`a1` in on distinct_key where ((`test`.`t1`.`a1` = ``.`b1`) and (`test`.`t1`.`a2` = ``.`b2`)))))) select * from t1 where (a1, a2) in (select b1, b2 from t2 where b1 > '0' group by b1, b2); @@ -79,7 +79,7 @@ explain extended select * from t1 where (a1, a2) in (select b1, min(b2) from t2 where b1 > '0' group by b1); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where -2 SUBQUERY t2 ALL NULL NULL NULL NULL 5 100.00 Using where; Using temporary +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 5 100.00 Using where; Using temporary Warnings: Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where <`test`.`t1`.`a1`,`test`.`t1`.`a2`>(((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( (select `test`.`t2`.`b1`,min(`test`.`t2`.`b2`) from `test`.`t2` where (`test`.`t2`.`b1` > '0') group by `test`.`t2`.`b1` ), (`test`.`t1`.`a1` in on distinct_key where ((`test`.`t1`.`a1` = ``.`b1`) and (`test`.`t1`.`a2` = ``.`min(b2)`)))))) select * from t1 where (a1, a2) in (select b1, min(b2) from t2 where b1 > '0' group by b1); @@ -90,7 +90,7 @@ explain extended select * from t1i where a1 in (select b1 from t2i where b1 > '0'); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1i index NULL _it1_idx # NULL 3 100.00 Using where; -2 SUBQUERY t2i index it2i1,it2i3 it2i1 # NULL 5 100.00 Using where; +2 MATERIALIZED t2i index it2i1,it2i3 it2i1 # NULL 5 100.00 Using where; Warnings: Note 1003 select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from `test`.`t1i` where <`test`.`t1i`.`a1`>((`test`.`t1i`.`a1`,`test`.`t1i`.`a1` in ( (select `test`.`t2i`.`b1` from `test`.`t2i` where (`test`.`t2i`.`b1` > '0') ), (`test`.`t1i`.`a1` in on distinct_key where ((`test`.`t1i`.`a1` = ``.`b1`)))))) select * from t1i where a1 in (select b1 from t2i where b1 > '0'); @@ -101,7 +101,7 @@ explain extended select * from t1i where a1 in (select b1 from t2i where b1 > '0' group by b1); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1i index NULL # 18 # 3 100.00 # -2 SUBQUERY t2i range it2i1,it2i3 # 9 # 3 100.00 # +2 MATERIALIZED t2i range it2i1,it2i3 # 9 # 3 100.00 # Warnings: Note 1003 select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from `test`.`t1i` where <`test`.`t1i`.`a1`>((`test`.`t1i`.`a1`,`test`.`t1i`.`a1` in ( (select `test`.`t2i`.`b1` from `test`.`t2i` where (`test`.`t2i`.`b1` > '0') group by `test`.`t2i`.`b1` ), (`test`.`t1i`.`a1` in on distinct_key where ((`test`.`t1i`.`a1` = ``.`b1`)))))) select * from t1i where a1 in (select b1 from t2i where b1 > '0' group by b1); @@ -112,7 +112,7 @@ explain extended select * from t1i where (a1, a2) in (select b1, b2 from t2i where b1 > '0'); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1i index NULL _it1_idx # NULL 3 100.00 Using where; -2 SUBQUERY t2i index it2i1,it2i3 it2i3 # NULL 5 100.00 Using where; +2 MATERIALIZED t2i index it2i1,it2i3 it2i3 # NULL 5 100.00 Using where; Warnings: Note 1003 select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from `test`.`t1i` where <`test`.`t1i`.`a1`,`test`.`t1i`.`a2`>(((`test`.`t1i`.`a1`,`test`.`t1i`.`a2`),(`test`.`t1i`.`a1`,`test`.`t1i`.`a2`) in ( (select `test`.`t2i`.`b1`,`test`.`t2i`.`b2` from `test`.`t2i` where (`test`.`t2i`.`b1` > '0') ), (`test`.`t1i`.`a1` in on distinct_key where ((`test`.`t1i`.`a1` = ``.`b1`) and (`test`.`t1i`.`a2` = ``.`b2`)))))) select * from t1i where (a1, a2) in (select b1, b2 from t2i where b1 > '0'); @@ -123,7 +123,7 @@ explain extended select * from t1i where (a1, a2) in (select b1, b2 from t2i where b1 > '0' group by b1, b2); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1i index NULL # # # 3 100.00 # -2 SUBQUERY t2i range it2i1,it2i3 # # # 3 100.00 # +2 MATERIALIZED t2i range it2i1,it2i3 # # # 3 100.00 # Warnings: Note 1003 select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from `test`.`t1i` where <`test`.`t1i`.`a1`,`test`.`t1i`.`a2`>(((`test`.`t1i`.`a1`,`test`.`t1i`.`a2`),(`test`.`t1i`.`a1`,`test`.`t1i`.`a2`) in ( (select `test`.`t2i`.`b1`,`test`.`t2i`.`b2` from `test`.`t2i` where (`test`.`t2i`.`b1` > '0') group by `test`.`t2i`.`b1`,`test`.`t2i`.`b2` ), (`test`.`t1i`.`a1` in on distinct_key where ((`test`.`t1i`.`a1` = ``.`b1`) and (`test`.`t1i`.`a2` = ``.`b2`)))))) select * from t1i where (a1, a2) in (select b1, b2 from t2i where b1 > '0' group by b1, b2); @@ -134,7 +134,7 @@ explain extended select * from t1i where (a1, a2) in (select b1, min(b2) from t2i where b1 > '0' group by b1); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1i index NULL # # # 3 100.00 # -2 SUBQUERY t2i range it2i1,it2i3 # # # 3 100.00 # +2 MATERIALIZED t2i range it2i1,it2i3 # # # 3 100.00 # Warnings: Note 1003 select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from `test`.`t1i` where <`test`.`t1i`.`a1`,`test`.`t1i`.`a2`>(((`test`.`t1i`.`a1`,`test`.`t1i`.`a2`),(`test`.`t1i`.`a1`,`test`.`t1i`.`a2`) in ( (select `test`.`t2i`.`b1`,min(`test`.`t2i`.`b2`) from `test`.`t2i` where (`test`.`t2i`.`b1` > '0') group by `test`.`t2i`.`b1` ), (`test`.`t1i`.`a1` in on distinct_key where ((`test`.`t1i`.`a1` = ``.`b1`) and (`test`.`t1i`.`a2` = ``.`min(b2)`)))))) select * from t1i where (a1, a2) in (select b1, min(b2) from t2i where b1 > '0' group by b1); @@ -145,7 +145,7 @@ explain extended select * from t1 where (a1, a2) in (select b1, max(b2) from t2i group by b1); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where -2 SUBQUERY t2i range NULL it2i3 9 NULL 3 100.00 Using index for group-by +2 MATERIALIZED t2i range NULL it2i3 9 NULL 3 100.00 Using index for group-by Warnings: Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where <`test`.`t1`.`a1`,`test`.`t1`.`a2`>(((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( (select `test`.`t2i`.`b1`,max(`test`.`t2i`.`b2`) from `test`.`t2i` group by `test`.`t2i`.`b1` ), (`test`.`t1`.`a1` in on distinct_key where ((`test`.`t1`.`a1` = ``.`b1`) and (`test`.`t1`.`a2` = ``.`max(b2)`)))))) select * from t1 where (a1, a2) in (select b1, max(b2) from t2i group by b1); @@ -156,11 +156,11 @@ prepare st1 from "explain select * from t1 where (a1, a2) in (select b1, max(b2) execute st1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where -2 SUBQUERY t2i range NULL it2i3 9 NULL 3 Using index for group-by +2 MATERIALIZED t2i range NULL it2i3 9 NULL 3 Using index for group-by execute st1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where -2 SUBQUERY t2i range NULL it2i3 9 NULL 3 Using index for group-by +2 MATERIALIZED t2i range NULL it2i3 9 NULL 3 Using index for group-by prepare st2 from "select * from t1 where (a1, a2) in (select b1, max(b2) from t2i group by b1)"; execute st2; a1 a2 @@ -174,7 +174,7 @@ explain extended select * from t1 where (a1, a2) in (select b1, min(b2) from t2i where b1 > '0' group by b1); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where -2 SUBQUERY t2i range it2i1,it2i3 it2i3 18 NULL 3 100.00 Using where; Using index for group-by +2 MATERIALIZED t2i range it2i1,it2i3 it2i3 18 NULL 3 100.00 Using where; Using index for group-by Warnings: Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where <`test`.`t1`.`a1`,`test`.`t1`.`a2`>(((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( (select `test`.`t2i`.`b1`,min(`test`.`t2i`.`b2`) from `test`.`t2i` where (`test`.`t2i`.`b1` > '0') group by `test`.`t2i`.`b1` ), (`test`.`t1`.`a1` in on distinct_key where ((`test`.`t1`.`a1` = ``.`b1`) and (`test`.`t1`.`a2` = ``.`min(b2)`)))))) select * from t1 where (a1, a2) in (select b1, min(b2) from t2i where b1 > '0' group by b1); @@ -221,7 +221,7 @@ explain extended select * from t1 where (a1, a2) in (select b1, b2 from t2 order by b1, b2); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where -2 SUBQUERY t2 ALL NULL NULL NULL NULL 5 100.00 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 5 100.00 Warnings: Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where <`test`.`t1`.`a1`,`test`.`t1`.`a2`>(((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( (select `test`.`t2`.`b1`,`test`.`t2`.`b2` from `test`.`t2` order by `test`.`t2`.`b1`,`test`.`t2`.`b2` ), (`test`.`t1`.`a1` in on distinct_key where ((`test`.`t1`.`a1` = ``.`b1`) and (`test`.`t1`.`a2` = ``.`b2`)))))) select * from t1 where (a1, a2) in (select b1, b2 from t2 order by b1, b2); @@ -232,7 +232,7 @@ explain extended select * from t1i where (a1, a2) in (select b1, b2 from t2i order by b1, b2); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1i index NULL it1i3 18 NULL 3 100.00 Using where; Using index -2 SUBQUERY t2i index NULL it2i3 18 NULL 5 100.00 Using index +2 MATERIALIZED t2i index NULL it2i3 18 NULL 5 100.00 Using index Warnings: Note 1003 select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from `test`.`t1i` where <`test`.`t1i`.`a1`,`test`.`t1i`.`a2`>(((`test`.`t1i`.`a1`,`test`.`t1i`.`a2`),(`test`.`t1i`.`a1`,`test`.`t1i`.`a2`) in ( (select `test`.`t2i`.`b1`,`test`.`t2i`.`b2` from `test`.`t2i` order by `test`.`t2i`.`b1`,`test`.`t2i`.`b2` ), (`test`.`t1i`.`a1` in on distinct_key where ((`test`.`t1i`.`a1` = ``.`b1`) and (`test`.`t1i`.`a2` = ``.`b2`)))))) select * from t1i where (a1, a2) in (select b1, b2 from t2i order by b1, b2); @@ -285,9 +285,9 @@ where (a1, a2) in (select b1, b2 from t2 where b1 > '0') and where (c1, c2) in (select b1, b2 from t2i where b2 > '0')); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where -3 SUBQUERY t3 ALL NULL NULL NULL NULL 4 100.00 Using where -4 SUBQUERY t2i index it2i2 it2i3 18 NULL 5 100.00 Using where; Using index -2 SUBQUERY t2 ALL NULL NULL NULL NULL 5 100.00 Using where +3 MATERIALIZED t3 ALL NULL NULL NULL NULL 4 100.00 Using where +4 MATERIALIZED t2i index it2i2 it2i3 18 NULL 5 100.00 Using where; Using index +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 5 100.00 Using where Warnings: Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where (<`test`.`t1`.`a1`,`test`.`t1`.`a2`>(((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( (select `test`.`t2`.`b1`,`test`.`t2`.`b2` from `test`.`t2` where (`test`.`t2`.`b1` > '0') ), (`test`.`t1`.`a1` in on distinct_key where ((`test`.`t1`.`a1` = ``.`b1`) and (`test`.`t1`.`a2` = ``.`b2`)))))) and <`test`.`t1`.`a1`,`test`.`t1`.`a2`>(((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( (select `test`.`t3`.`c1`,`test`.`t3`.`c2` from `test`.`t3` where <`test`.`t3`.`c1`,`test`.`t3`.`c2`>(((`test`.`t3`.`c1`,`test`.`t3`.`c2`),(`test`.`t3`.`c1`,`test`.`t3`.`c2`) in ( (select `test`.`t2i`.`b1`,`test`.`t2i`.`b2` from `test`.`t2i` where (`test`.`t2i`.`b2` > '0') ), (`test`.`t3`.`c1` in on distinct_key where ((`test`.`t3`.`c1` = ``.`b1`) and (`test`.`t3`.`c2` = ``.`b2`)))))) ), (`test`.`t1`.`a1` in on distinct_key where ((`test`.`t1`.`a1` = ``.`c1`) and (`test`.`t1`.`a2` = ``.`c2`))))))) select * from t1 @@ -304,9 +304,9 @@ where (a1, a2) in (select b1, b2 from t2i where b1 > '0') and where (c1, c2) in (select b1, b2 from t2i where b2 > '0')); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1i index NULL # # # 3 100.00 # -3 SUBQUERY t3i index NULL # # # 4 100.00 # -4 SUBQUERY t2i index it2i2 # # # 5 100.00 # -2 SUBQUERY t2i index it2i1,it2i3 # # # 5 100.00 # +3 MATERIALIZED t3i index NULL # # # 4 100.00 # +4 MATERIALIZED t2i index it2i2 # # # 5 100.00 # +2 MATERIALIZED t2i index it2i1,it2i3 # # # 5 100.00 # Warnings: Note 1003 select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from `test`.`t1i` where (<`test`.`t1i`.`a1`,`test`.`t1i`.`a2`>(((`test`.`t1i`.`a1`,`test`.`t1i`.`a2`),(`test`.`t1i`.`a1`,`test`.`t1i`.`a2`) in ( (select `test`.`t2i`.`b1`,`test`.`t2i`.`b2` from `test`.`t2i` where (`test`.`t2i`.`b1` > '0') ), (`test`.`t1i`.`a1` in on distinct_key where ((`test`.`t1i`.`a1` = ``.`b1`) and (`test`.`t1i`.`a2` = ``.`b2`)))))) and <`test`.`t1i`.`a1`,`test`.`t1i`.`a2`>(((`test`.`t1i`.`a1`,`test`.`t1i`.`a2`),(`test`.`t1i`.`a1`,`test`.`t1i`.`a2`) in ( (select `test`.`t3i`.`c1`,`test`.`t3i`.`c2` from `test`.`t3i` where <`test`.`t3i`.`c1`,`test`.`t3i`.`c2`>(((`test`.`t3i`.`c1`,`test`.`t3i`.`c2`),(`test`.`t3i`.`c1`,`test`.`t3i`.`c2`) in ( (select `test`.`t2i`.`b1`,`test`.`t2i`.`b2` from `test`.`t2i` where (`test`.`t2i`.`b2` > '0') ), (`test`.`t3i`.`c1` in on distinct_key where ((`test`.`t3i`.`c1` = ``.`b1`) and (`test`.`t3i`.`c2` = ``.`b2`)))))) ), (`test`.`t1i`.`a1` in on distinct_key where ((`test`.`t1i`.`a1` = ``.`c1`) and (`test`.`t1i`.`a2` = ``.`c2`))))))) select * from t1i @@ -325,11 +325,11 @@ b2 in (select c2 from t3 where c2 LIKE '%03')) and where (c1, c2) in (select b1, b2 from t2i where b2 > '0')); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where -5 SUBQUERY t3 ALL NULL NULL NULL NULL 4 100.00 Using where -6 SUBQUERY t2i index it2i2 it2i3 18 NULL 5 100.00 Using where; Using index -2 SUBQUERY t2 ALL NULL NULL NULL NULL 5 100.00 Using where -4 SUBQUERY t3 ALL NULL NULL NULL NULL 4 100.00 Using where -3 SUBQUERY t3 ALL NULL NULL NULL NULL 4 100.00 Using where +5 MATERIALIZED t3 ALL NULL NULL NULL NULL 4 100.00 Using where +6 MATERIALIZED t2i index it2i2 it2i3 18 NULL 5 100.00 Using where; Using index +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 5 100.00 Using where +4 MATERIALIZED t3 ALL NULL NULL NULL NULL 4 100.00 Using where +3 MATERIALIZED t3 ALL NULL NULL NULL NULL 4 100.00 Using where Warnings: Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where (<`test`.`t1`.`a1`,`test`.`t1`.`a2`>(((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( (select `test`.`t2`.`b1`,`test`.`t2`.`b2` from `test`.`t2` where (<`test`.`t2`.`b2`>((`test`.`t2`.`b2`,`test`.`t2`.`b2` in ( (select `test`.`t3`.`c2` from `test`.`t3` where (`test`.`t3`.`c2` like '%02') ), (`test`.`t2`.`b2` in on distinct_key where ((`test`.`t2`.`b2` = ``.`c2`)))))) or <`test`.`t2`.`b2`>((`test`.`t2`.`b2`,`test`.`t2`.`b2` in ( (select `test`.`t3`.`c2` from `test`.`t3` where (`test`.`t3`.`c2` like '%03') ), (`test`.`t2`.`b2` in on distinct_key where ((`test`.`t2`.`b2` = ``.`c2`))))))) ), (`test`.`t1`.`a1` in on distinct_key where ((`test`.`t1`.`a1` = ``.`b1`) and (`test`.`t1`.`a2` = ``.`b2`)))))) and <`test`.`t1`.`a1`,`test`.`t1`.`a2`>(((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( (select `test`.`t3`.`c1`,`test`.`t3`.`c2` from `test`.`t3` where <`test`.`t3`.`c1`,`test`.`t3`.`c2`>(((`test`.`t3`.`c1`,`test`.`t3`.`c2`),(`test`.`t3`.`c1`,`test`.`t3`.`c2`) in ( (select `test`.`t2i`.`b1`,`test`.`t2i`.`b2` from `test`.`t2i` where (`test`.`t2i`.`b2` > '0') ), (`test`.`t3`.`c1` in on distinct_key where ((`test`.`t3`.`c1` = ``.`b1`) and (`test`.`t3`.`c2` = ``.`b2`)))))) ), (`test`.`t1`.`a1` in on distinct_key where ((`test`.`t1`.`a1` = ``.`c1`) and (`test`.`t1`.`a2` = ``.`c2`))))))) select * from t1 @@ -349,10 +349,10 @@ b2 in (select c2 from t3 t3b where c2 LIKE '%03')) and where (c1, c2) in (select b1, b2 from t2i where b2 > '0')); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where -5 SUBQUERY t3c ALL NULL NULL NULL NULL 4 100.00 Using where -6 SUBQUERY t2i index it2i2 it2i3 18 NULL 5 100.00 Using where; Using index +5 MATERIALIZED t3c ALL NULL NULL NULL NULL 4 100.00 Using where +6 MATERIALIZED t2i index it2i2 it2i3 18 NULL 5 100.00 Using where; Using index 2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 5 100.00 Using where -4 SUBQUERY t3b ALL NULL NULL NULL NULL 4 100.00 Using where +4 MATERIALIZED t3b ALL NULL NULL NULL NULL 4 100.00 Using where 3 DEPENDENT SUBQUERY t3a ALL NULL NULL NULL NULL 4 100.00 Using where Warnings: Note 1276 Field or reference 'test.t1.a1' of SELECT #3 was resolved in SELECT #1 @@ -381,15 +381,15 @@ where (a1, a2) in (select b1, b2 from t2i where b1 > '0') and where (c1, c2) in (select b1, b2 from t2i where b2 > '0'))); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL # # # 3 100.00 # -5 SUBQUERY t3 ALL NULL # # # 4 100.00 # -6 SUBQUERY t2i index it2i2 # # # 5 100.00 # -2 SUBQUERY t2 ALL NULL # # # 5 100.00 # -4 SUBQUERY t3 ALL NULL # # # 4 100.00 # -3 SUBQUERY t3 ALL NULL # # # 4 100.00 # +5 MATERIALIZED t3 ALL NULL # # # 4 100.00 # +6 MATERIALIZED t2i index it2i2 # # # 5 100.00 # +2 MATERIALIZED t2 ALL NULL # # # 5 100.00 # +4 MATERIALIZED t3 ALL NULL # # # 4 100.00 # +3 MATERIALIZED t3 ALL NULL # # # 4 100.00 # 7 UNION t1i index NULL # # # 3 100.00 # -9 SUBQUERY t3i index NULL # # # 4 100.00 # -10 SUBQUERY t2i index it2i2 # # # 5 100.00 # -8 SUBQUERY t2i index it2i1,it2i3 # # # 5 100.00 # +9 MATERIALIZED t3i index NULL # # # 4 100.00 # +10 MATERIALIZED t2i index it2i2 # # # 5 100.00 # +8 MATERIALIZED t2i index it2i1,it2i3 # # # 5 100.00 # NULL UNION RESULT ALL NULL # # # NULL NULL # Warnings: Note 1003 (select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where (<`test`.`t1`.`a1`,`test`.`t1`.`a2`>(((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( (select `test`.`t2`.`b1`,`test`.`t2`.`b2` from `test`.`t2` where (<`test`.`t2`.`b2`>((`test`.`t2`.`b2`,`test`.`t2`.`b2` in ( (select `test`.`t3`.`c2` from `test`.`t3` where (`test`.`t3`.`c2` like '%02') ), (`test`.`t2`.`b2` in on distinct_key where ((`test`.`t2`.`b2` = ``.`c2`)))))) or <`test`.`t2`.`b2`>((`test`.`t2`.`b2`,`test`.`t2`.`b2` in ( (select `test`.`t3`.`c2` from `test`.`t3` where (`test`.`t3`.`c2` like '%03') ), (`test`.`t2`.`b2` in on distinct_key where ((`test`.`t2`.`b2` = ``.`c2`))))))) group by `test`.`t2`.`b1`,`test`.`t2`.`b2` ), (`test`.`t1`.`a1` in on distinct_key where ((`test`.`t1`.`a1` = ``.`b1`) and (`test`.`t1`.`a2` = ``.`b2`)))))) and <`test`.`t1`.`a1`,`test`.`t1`.`a2`>(((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( (select `test`.`t3`.`c1`,`test`.`t3`.`c2` from `test`.`t3` where <`test`.`t3`.`c1`,`test`.`t3`.`c2`>(((`test`.`t3`.`c1`,`test`.`t3`.`c2`),(`test`.`t3`.`c1`,`test`.`t3`.`c2`) in ( (select `test`.`t2i`.`b1`,`test`.`t2i`.`b2` from `test`.`t2i` where (`test`.`t2i`.`b2` > '0') ), (`test`.`t3`.`c1` in on distinct_key where ((`test`.`t3`.`c1` = ``.`b1`) and (`test`.`t3`.`c2` = ``.`b2`)))))) ), (`test`.`t1`.`a1` in on distinct_key where ((`test`.`t1`.`a1` = ``.`c1`) and (`test`.`t1`.`a2` = ``.`c2`)))))))) union (select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from `test`.`t1i` where (<`test`.`t1i`.`a1`,`test`.`t1i`.`a2`>(((`test`.`t1i`.`a1`,`test`.`t1i`.`a2`),(`test`.`t1i`.`a1`,`test`.`t1i`.`a2`) in ( (select `test`.`t2i`.`b1`,`test`.`t2i`.`b2` from `test`.`t2i` where (`test`.`t2i`.`b1` > '0') ), (`test`.`t1i`.`a1` in on distinct_key where ((`test`.`t1i`.`a1` = ``.`b1`) and (`test`.`t1i`.`a2` = ``.`b2`)))))) and <`test`.`t1i`.`a1`,`test`.`t1i`.`a2`>(((`test`.`t1i`.`a1`,`test`.`t1i`.`a2`),(`test`.`t1i`.`a1`,`test`.`t1i`.`a2`) in ( (select `test`.`t3i`.`c1`,`test`.`t3i`.`c2` from `test`.`t3i` where <`test`.`t3i`.`c1`,`test`.`t3i`.`c2`>(((`test`.`t3i`.`c1`,`test`.`t3i`.`c2`),(`test`.`t3i`.`c1`,`test`.`t3i`.`c2`) in ( (select `test`.`t2i`.`b1`,`test`.`t2i`.`b2` from `test`.`t2i` where (`test`.`t2i`.`b2` > '0') ), (`test`.`t3i`.`c1` in on distinct_key where ((`test`.`t3i`.`c1` = ``.`b1`) and (`test`.`t3i`.`c2` = ``.`b2`)))))) ), (`test`.`t1i`.`a1` in on distinct_key where ((`test`.`t1i`.`a1` = ``.`c1`) and (`test`.`t1i`.`a2` = ``.`c2`)))))))) @@ -415,8 +415,8 @@ where (a1, a2) in (select * from t1 where a1 > '0' UNION select * from t2 where where (c1, c2) in (select b1, b2 from t2i where b2 > '0')); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where -4 SUBQUERY t3 ALL NULL NULL NULL NULL 4 100.00 Using where -5 SUBQUERY t2i index it2i2 it2i3 18 NULL 5 100.00 Using where; Using index +4 MATERIALIZED t3 ALL NULL NULL NULL NULL 4 100.00 Using where +5 MATERIALIZED t2i index it2i2 it2i3 18 NULL 5 100.00 Using where; Using index 2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 3 100.00 Using where 3 DEPENDENT UNION t2 ALL NULL NULL NULL NULL 5 100.00 Using where NULL UNION RESULT ALL NULL NULL NULL NULL NULL NULL @@ -438,8 +438,8 @@ a1 = c1; id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where 1 PRIMARY t3 ALL NULL NULL NULL NULL 4 100.00 Using where; Using join buffer (flat, BNL join) -4 SUBQUERY t3 ALL NULL NULL NULL NULL 4 100.00 Using where -5 SUBQUERY t2i index it2i2 it2i3 18 NULL 5 100.00 Using where; Using index +4 MATERIALIZED t3 ALL NULL NULL NULL NULL 4 100.00 Using where +5 MATERIALIZED t2i index it2i2 it2i3 18 NULL 5 100.00 Using where; Using index 2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 3 100.00 Using where 3 DEPENDENT UNION t2 ALL NULL NULL NULL NULL 5 100.00 Using where NULL UNION RESULT ALL NULL NULL NULL NULL NULL NULL @@ -485,7 +485,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 5 DEPENDENT SUBQUERY t3c ALL NULL NULL NULL NULL 4 100.00 Using where 6 DEPENDENT SUBQUERY t2i index_subquery it2i1,it2i2,it2i3 it2i3 18 func,func 2 100.00 Using index; Using where 2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 5 100.00 Using where -4 SUBQUERY t3b ALL NULL NULL NULL NULL 4 100.00 Using where +4 MATERIALIZED t3b ALL NULL NULL NULL NULL 4 100.00 Using where 3 DEPENDENT SUBQUERY t3a ALL NULL NULL NULL NULL 4 100.00 Using where Warnings: Note 1276 Field or reference 'test.t1.a1' of SELECT #3 was resolved in SELECT #1 @@ -622,7 +622,7 @@ from t1_16 where a1 in (select substring(b1,1,16) from t2_16 where b1 > '0'); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1_16 ALL NULL NULL NULL NULL 3 100.00 Using where -2 SUBQUERY t2_16 ALL NULL NULL NULL NULL 3 100.00 Using where +2 MATERIALIZED t2_16 ALL NULL NULL NULL NULL 3 100.00 Using where Warnings: Note 1003 select left(`test`.`t1_16`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_16`.`a2`,7) AS `left(a2,7)` from `test`.`t1_16` where <`test`.`t1_16`.`a1`>((`test`.`t1_16`.`a1`,`test`.`t1_16`.`a1` in ( (select substr(`test`.`t2_16`.`b1`,1,16) from `test`.`t2_16` where (`test`.`t2_16`.`b1` > '0') ), (`test`.`t1_16`.`a1` in on distinct_key where ((`test`.`t1_16`.`a1` = ``.`substring(b1,1,16)`)))))) select left(a1,7), left(a2,7) @@ -651,7 +651,7 @@ from t1_16 where a1 in (select group_concat(b1) from t2_16 group by b2); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1_16 ALL NULL NULL NULL NULL 3 100.00 Using where -2 SUBQUERY t2_16 ALL NULL NULL NULL NULL 3 100.00 Using filesort +2 MATERIALIZED t2_16 ALL NULL NULL NULL NULL 3 100.00 Using filesort Warnings: Note 1003 select left(`test`.`t1_16`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_16`.`a2`,7) AS `left(a2,7)` from `test`.`t1_16` where <`test`.`t1_16`.`a1`>((`test`.`t1_16`.`a1`,`test`.`t1_16`.`a1` in ( (select group_concat(`test`.`t2_16`.`b1` separator ',') from `test`.`t2_16` group by `test`.`t2_16`.`b2` ), (`test`.`t1_16`.`a1` in on distinct_key where ((`test`.`t1_16`.`a1` = ``.`group_concat(b1)`)))))) select left(a1,7), left(a2,7) @@ -673,7 +673,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 2 DEPENDENT SUBQUERY t1_16 ALL NULL NULL NULL NULL 3 100.00 Using where 3 DEPENDENT SUBQUERY t2_16 ALL NULL NULL NULL NULL 3 100.00 Using where 3 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 5 100.00 Using where; Using join buffer (flat, BNL join) -4 SUBQUERY t3 ALL NULL NULL NULL NULL 4 100.00 Using where +4 MATERIALIZED t3 ALL NULL NULL NULL NULL 4 100.00 Using where Warnings: Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where ((concat(`test`.`t1`.`a1`,'x'),(select left(`test`.`t1_16`.`a1`,8) from `test`.`t1_16` where (<`test`.`t1_16`.`a1`,`test`.`t1_16`.`a2`>(((`test`.`t1_16`.`a1`,`test`.`t1_16`.`a2`),(select `test`.`t2_16`.`b1`,`test`.`t2_16`.`b2` from `test`.`t2_16` join `test`.`t2` where ((`test`.`t2`.`b2` = substr(`test`.`t2_16`.`b2`,1,6)) and <`test`.`t2`.`b1`>((`test`.`t2`.`b1`,`test`.`t2`.`b1` in ( (select `test`.`t3`.`c1` from `test`.`t3` where (`test`.`t3`.`c2` > '0') ), (`test`.`t2`.`b1` in on distinct_key where ((`test`.`t2`.`b1` = ``.`c1`)))))) and ((`test`.`t1_16`.`a1`) = `test`.`t2_16`.`b1`) and ((`test`.`t1_16`.`a2`) = `test`.`t2_16`.`b2`))))) and ((concat(`test`.`t1`.`a1`,'x')) = left(`test`.`t1_16`.`a1`,8)))))) drop table t1_16, t2_16, t3_16; @@ -735,7 +735,7 @@ from t1_512 where a1 in (select substring(b1,1,512) from t2_512 where b1 > '0'); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1_512 ALL NULL NULL NULL NULL 3 100.00 Using where -2 SUBQUERY t2_512 ALL NULL NULL NULL NULL 3 100.00 Using where +2 MATERIALIZED t2_512 ALL NULL NULL NULL NULL 3 100.00 Using where Warnings: Note 1003 select left(`test`.`t1_512`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_512`.`a2`,7) AS `left(a2,7)` from `test`.`t1_512` where <`test`.`t1_512`.`a1`>((`test`.`t1_512`.`a1`,`test`.`t1_512`.`a1` in ( (select substr(`test`.`t2_512`.`b1`,1,512) from `test`.`t2_512` where (`test`.`t2_512`.`b1` > '0') ), (`test`.`t1_512`.`a1` in on distinct_key where ((`test`.`t1_512`.`a1` = ``.`substring(b1,1,512)`)))))) select left(a1,7), left(a2,7) @@ -749,7 +749,7 @@ from t1_512 where a1 in (select group_concat(b1) from t2_512 group by b2); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1_512 ALL NULL NULL NULL NULL 3 100.00 Using where -2 SUBQUERY t2_512 ALL NULL NULL NULL NULL 3 100.00 Using filesort +2 MATERIALIZED t2_512 ALL NULL NULL NULL NULL 3 100.00 Using filesort Warnings: Note 1003 select left(`test`.`t1_512`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_512`.`a2`,7) AS `left(a2,7)` from `test`.`t1_512` where <`test`.`t1_512`.`a1`>((`test`.`t1_512`.`a1`,`test`.`t1_512`.`a1` in ( (select group_concat(`test`.`t2_512`.`b1` separator ',') from `test`.`t2_512` group by `test`.`t2_512`.`b2` ), (`test`.`t1_512`.`a1` in on distinct_key where ((`test`.`t1_512`.`a1` = ``.`group_concat(b1)`)))))) select left(a1,7), left(a2,7) @@ -762,7 +762,7 @@ from t1_512 where a1 in (select group_concat(b1) from t2_512 group by b2); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1_512 ALL NULL NULL NULL NULL 3 100.00 Using where -2 SUBQUERY t2_512 ALL NULL NULL NULL NULL 3 100.00 Using filesort +2 MATERIALIZED t2_512 ALL NULL NULL NULL NULL 3 100.00 Using filesort Warnings: Note 1003 select left(`test`.`t1_512`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_512`.`a2`,7) AS `left(a2,7)` from `test`.`t1_512` where <`test`.`t1_512`.`a1`>((`test`.`t1_512`.`a1`,`test`.`t1_512`.`a1` in ( (select group_concat(`test`.`t2_512`.`b1` separator ',') from `test`.`t2_512` group by `test`.`t2_512`.`b2` ), (`test`.`t1_512`.`a1` in on distinct_key where ((`test`.`t1_512`.`a1` = ``.`group_concat(b1)`)))))) select left(a1,7), left(a2,7) @@ -842,7 +842,7 @@ from t1_1024 where a1 in (select group_concat(b1) from t2_1024 group by b2); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1_1024 ALL NULL NULL NULL NULL 3 100.00 Using where -2 SUBQUERY t2_1024 ALL NULL NULL NULL NULL 3 100.00 Using filesort +2 MATERIALIZED t2_1024 ALL NULL NULL NULL NULL 3 100.00 Using filesort Warnings: Note 1003 select left(`test`.`t1_1024`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_1024`.`a2`,7) AS `left(a2,7)` from `test`.`t1_1024` where <`test`.`t1_1024`.`a1`>((`test`.`t1_1024`.`a1`,`test`.`t1_1024`.`a1` in ( (select group_concat(`test`.`t2_1024`.`b1` separator ',') from `test`.`t2_1024` group by `test`.`t2_1024`.`b2` ), (`test`.`t1_1024`.`a1` in on distinct_key where ((`test`.`t1_1024`.`a1` = ``.`group_concat(b1)`)))))) select left(a1,7), left(a2,7) @@ -855,7 +855,7 @@ from t1_1024 where a1 in (select group_concat(b1) from t2_1024 group by b2); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1_1024 ALL NULL NULL NULL NULL 3 100.00 Using where -2 SUBQUERY t2_1024 ALL NULL NULL NULL NULL 3 100.00 Using filesort +2 MATERIALIZED t2_1024 ALL NULL NULL NULL NULL 3 100.00 Using filesort Warnings: Note 1003 select left(`test`.`t1_1024`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_1024`.`a2`,7) AS `left(a2,7)` from `test`.`t1_1024` where <`test`.`t1_1024`.`a1`>((`test`.`t1_1024`.`a1`,`test`.`t1_1024`.`a1` in ( (select group_concat(`test`.`t2_1024`.`b1` separator ',') from `test`.`t2_1024` group by `test`.`t2_1024`.`b2` ), (`test`.`t1_1024`.`a1` in on distinct_key where ((`test`.`t1_1024`.`a1` = ``.`group_concat(b1)`)))))) select left(a1,7), left(a2,7) @@ -935,7 +935,7 @@ from t1_1025 where a1 in (select group_concat(b1) from t2_1025 group by b2); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1_1025 ALL NULL NULL NULL NULL 3 100.00 Using where -2 SUBQUERY t2_1025 ALL NULL NULL NULL NULL 3 100.00 Using filesort +2 MATERIALIZED t2_1025 ALL NULL NULL NULL NULL 3 100.00 Using filesort Warnings: Note 1003 select left(`test`.`t1_1025`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_1025`.`a2`,7) AS `left(a2,7)` from `test`.`t1_1025` where <`test`.`t1_1025`.`a1`>((`test`.`t1_1025`.`a1`,`test`.`t1_1025`.`a1` in ( (select group_concat(`test`.`t2_1025`.`b1` separator ',') from `test`.`t2_1025` group by `test`.`t2_1025`.`b2` ), (`test`.`t1_1025`.`a1` in on distinct_key where ((`test`.`t1_1025`.`a1` = ``.`group_concat(b1)`)))))) select left(a1,7), left(a2,7) @@ -948,7 +948,7 @@ from t1_1025 where a1 in (select group_concat(b1) from t2_1025 group by b2); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1_1025 ALL NULL NULL NULL NULL 3 100.00 Using where -2 SUBQUERY t2_1025 ALL NULL NULL NULL NULL 3 100.00 Using filesort +2 MATERIALIZED t2_1025 ALL NULL NULL NULL NULL 3 100.00 Using filesort Warnings: Note 1003 select left(`test`.`t1_1025`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_1025`.`a2`,7) AS `left(a2,7)` from `test`.`t1_1025` where <`test`.`t1_1025`.`a1`>((`test`.`t1_1025`.`a1`,`test`.`t1_1025`.`a1` in ( (select group_concat(`test`.`t2_1025`.`b1` separator ',') from `test`.`t2_1025` group by `test`.`t2_1025`.`b2` ), (`test`.`t1_1025`.`a1` in on distinct_key where ((`test`.`t1_1025`.`a1` = ``.`group_concat(b1)`)))))) select left(a1,7), left(a2,7) @@ -969,7 +969,7 @@ from t1bit where (a1, a2) in (select b1, b2 from t2bit); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1bit ALL NULL NULL NULL NULL 3 100.00 Using where -2 SUBQUERY t2bit ALL NULL NULL NULL NULL 3 100.00 +2 MATERIALIZED t2bit ALL NULL NULL NULL NULL 3 100.00 Warnings: Note 1003 select conv(`test`.`t1bit`.`a1`,10,2) AS `bin(a1)`,conv(`test`.`t1bit`.`a2`,10,2) AS `bin(a2)` from `test`.`t1bit` where <`test`.`t1bit`.`a1`,`test`.`t1bit`.`a2`>(((`test`.`t1bit`.`a1`,`test`.`t1bit`.`a2`),(`test`.`t1bit`.`a1`,`test`.`t1bit`.`a2`) in ( (select `test`.`t2bit`.`b1`,`test`.`t2bit`.`b2` from `test`.`t2bit` ), (`test`.`t1bit`.`a1` in on distinct_key where ((`test`.`t1bit`.`a1` = ``.`b1`) and (`test`.`t1bit`.`a2` = ``.`b2`)))))) select bin(a1), bin(a2) @@ -1040,7 +1040,7 @@ explain extended select a from t1 where a in (select c from t2 where d >= 20); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 7 100.00 Using where -2 SUBQUERY t2 ALL NULL NULL NULL NULL 6 100.00 Using where +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 6 100.00 Using where Warnings: Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where <`test`.`t1`.`a`>((`test`.`t1`.`a`,`test`.`t1`.`a` in ( (select `test`.`t2`.`c` from `test`.`t2` where (`test`.`t2`.`d` >= 20) ), (`test`.`t1`.`a` in on distinct_key where ((`test`.`t1`.`a` = ``.`c`)))))) select a from t1 where a in (select c from t2 where d >= 20); @@ -1054,7 +1054,7 @@ explain extended select a from t1 where a in (select c from t2 where d >= 20); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 index NULL it1a 4 NULL 7 100.00 Using where; Using index -2 SUBQUERY t2 ALL NULL NULL NULL NULL 6 100.00 Using where +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 6 100.00 Using where Warnings: Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where <`test`.`t1`.`a`>((`test`.`t1`.`a`,`test`.`t1`.`a` in ( (select `test`.`t2`.`c` from `test`.`t2` where (`test`.`t2`.`d` >= 20) ), (`test`.`t1`.`a` in on distinct_key where ((`test`.`t1`.`a` = ``.`c`)))))) select a from t1 where a in (select c from t2 where d >= 20); @@ -1068,7 +1068,7 @@ explain extended select a from t1 where a in (select c from t2 where d >= 20); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 index NULL it1a 4 NULL 7 100.00 Using where; Using index -2 SUBQUERY t2 ALL NULL NULL NULL NULL 7 100.00 Using where +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 7 100.00 Using where Warnings: Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where <`test`.`t1`.`a`>((`test`.`t1`.`a`,`test`.`t1`.`a` in ( (select `test`.`t2`.`c` from `test`.`t2` where (`test`.`t2`.`d` >= 20) ), (`test`.`t1`.`a` in on distinct_key where ((`test`.`t1`.`a` = ``.`c`)))))) select a from t1 where a in (select c from t2 where d >= 20); @@ -1081,7 +1081,7 @@ explain extended select a from t1 group by a having a in (select c from t2 where d >= 20); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 index NULL it1a 4 NULL 7 100.00 Using index -2 SUBQUERY t2 ALL NULL NULL NULL NULL 7 100.00 Using where +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 7 100.00 Using where Warnings: Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` group by `test`.`t1`.`a` having <`test`.`t1`.`a`>((`test`.`t1`.`a`,`test`.`t1`.`a` in ( (select `test`.`t2`.`c` from `test`.`t2` where (`test`.`t2`.`d` >= 20) ), (`test`.`t1`.`a` in on distinct_key where ((`test`.`t1`.`a` = ``.`c`)))))) select a from t1 group by a having a in (select c from t2 where d >= 20); @@ -1093,7 +1093,7 @@ explain extended select a from t1 group by a having a in (select c from t2 where d >= 20); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 index NULL it1a 4 NULL 7 100.00 Using index -2 SUBQUERY t2 ALL NULL NULL NULL NULL 7 100.00 Using where +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 7 100.00 Using where Warnings: Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` group by `test`.`t1`.`a` having <`test`.`t1`.`a`>((`test`.`t1`.`a`,`test`.`t1`.`a` in ( (select `test`.`t2`.`c` from `test`.`t2` where (`test`.`t2`.`d` >= 20) ), (`test`.`t1`.`a` in on distinct_key where ((`test`.`t1`.`a` = ``.`c`)))))) select a from t1 group by a having a in (select c from t2 where d >= 20); @@ -1151,7 +1151,7 @@ insert into t1 values (5); explain select min(a1) from t1 where 7 in (select b1 from t2 group by b1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 1 -2 SUBQUERY t2 system NULL NULL NULL NULL 0 const row not found +2 MATERIALIZED t2 system NULL NULL NULL NULL 0 const row not found select min(a1) from t1 where 7 in (select b1 from t2 group by b1); min(a1) NULL @@ -1170,7 +1170,7 @@ set @@optimizer_switch='semijoin=off'; explain select min(a1) from t1 where 7 in (select b1 from t2); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 1 -2 SUBQUERY t2 system NULL NULL NULL NULL 0 const row not found +2 MATERIALIZED t2 system NULL NULL NULL NULL 0 const row not found select min(a1) from t1 where 7 in (select b1 from t2); min(a1) NULL @@ -1200,7 +1200,7 @@ insert into t1 values ('aa', 'aaaa'); explain select a,b from t1 where b in (select a from t1); 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 SUBQUERY t1 ALL NULL NULL NULL NULL 2 +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 2 select a,b from t1 where b in (select a from t1); a b prepare st1 from "select a,b from t1 where b in (select a from t1)"; @@ -1237,8 +1237,8 @@ GROUP BY t3i id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 1 1 PRIMARY t4 ALL NULL NULL NULL NULL 2 Using where -2 SUBQUERY t2 ALL NULL NULL NULL NULL 2 Using where -3 SUBQUERY t3 ALL NULL NULL NULL NULL 2 Using temporary +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 Using where +3 MATERIALIZED t3 ALL NULL NULL NULL NULL 2 Using temporary DROP TABLE t1,t2,t3,t4; CREATE TABLE t1 ( pk INTEGER AUTO_INCREMENT, @@ -1345,7 +1345,7 @@ SELECT t1.* FROM t1 LEFT JOIN t2 ON t1.a > 3 OR t2.b IN (SELECT a FROM t1) id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL NULL NULL NULL NULL 2 2 DERIVED NULL NULL NULL NULL NULL NULL NULL no matching row in const table -3 SUBQUERY NULL NULL NULL NULL NULL NULL NULL no matching row in const table +3 MATERIALIZED NULL NULL NULL NULL NULL NULL NULL no matching row in const table SELECT a FROM ( SELECT t1.* FROM t1 LEFT JOIN t2 ON t1.a > 3 OR t2.b IN (SELECT a FROM t1) ) table1; @@ -1374,7 +1374,7 @@ WHERE t1.f1 IN (SELECT t1.pk FROM t1 ORDER BY t1.f1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 1 1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where -2 SUBQUERY t1 system NULL NULL NULL NULL 1 +2 MATERIALIZED t1 system NULL NULL NULL NULL 1 SELECT * FROM t1 JOIN t2 USING (f1) WHERE t1.f1 IN (SELECT t1.pk FROM t1 ORDER BY t1.f1); f1 pk pk @@ -1448,7 +1448,7 @@ EXPLAIN SELECT COUNT(*) FROM t1 WHERE (f1,f2) IN (SELECT f1,f2 FROM t2); 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 3 Using where; Using join buffer (flat, BNL join) -2 SUBQUERY t2 ALL NULL NULL NULL NULL 2 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 SELECT COUNT(*) FROM t1 WHERE (f1,f2) IN (SELECT f1,f2 FROM t2); COUNT(*) 2 @@ -1472,7 +1472,7 @@ EXPLAIN SELECT pk FROM t1 WHERE (a) IN (SELECT a FROM t2 WHERE pk > 0); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 2 1 PRIMARY eq_ref distinct_key distinct_key 5 func 1 -2 SUBQUERY t2 range PRIMARY PRIMARY 4 NULL 2 Using index condition; Rowid-ordered scan +2 MATERIALIZED t2 range PRIMARY PRIMARY 4 NULL 2 Using index condition; Rowid-ordered scan SELECT pk FROM t1 WHERE (a) IN (SELECT a FROM t2 WHERE pk > 0); pk 2 @@ -1513,7 +1513,7 @@ insert into t1 values (0),(1),(2); explain select a, a in (select a from t1) from t0; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t0 ALL NULL NULL NULL NULL 3 -2 SUBQUERY t1 ALL NULL NULL NULL NULL 3 +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 3 select a, a in (select a from t1) from t0; a a in (select a from t1) 0 1 @@ -1740,7 +1740,7 @@ insert into t1 values (0),(1),(2); explain select a, a in (select a from t1) from t0; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t0 ALL NULL NULL NULL NULL 3 -2 SUBQUERY t1 ALL NULL NULL NULL NULL 3 +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 3 select a, a in (select a from t1) from t0; a a in (select a from t1) 0 1 @@ -1772,7 +1772,7 @@ EXPLAIN SELECT SUM(c1) c1_sum FROM t1 WHERE c1 IN (SELECT c2 FROM t2); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 1 -2 SUBQUERY t2 system NULL NULL NULL NULL 1 +2 MATERIALIZED t2 system NULL NULL NULL NULL 1 SELECT SUM(c1) c1_sum FROM t1 WHERE c1 IN (SELECT c2 FROM t2); c1_sum NULL @@ -1780,7 +1780,7 @@ EXPLAIN SELECT SUM(c1) c1_sum FROM t1 WHERE c1 IN (SELECT c2 FROM t2) HAVING c1_sum; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 1 -2 SUBQUERY t2 system NULL NULL NULL NULL 1 +2 MATERIALIZED t2 system NULL NULL NULL NULL 1 SELECT SUM(c1) c1_sum FROM t1 WHERE c1 IN (SELECT c2 FROM t2) HAVING c1_sum; c1_sum drop table t1, t2; @@ -1799,7 +1799,7 @@ SELECT i FROM t1 LEFT JOIN t2 ON (j) IN (SELECT k FROM t3); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 1 1 PRIMARY t2 ALL NULL NULL NULL NULL 1 Using where -2 SUBQUERY t3 system NULL NULL NULL NULL 0 const row not found +2 MATERIALIZED t3 system NULL NULL NULL NULL 0 const row not found SELECT i FROM t1 LEFT JOIN t2 ON (j) IN (SELECT k FROM t3); i 10 @@ -1808,7 +1808,7 @@ SELECT i FROM t1 LEFT JOIN t2 ON (j) IN (SELECT max(k) FROM t3); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 1 1 PRIMARY t2 ALL NULL NULL NULL NULL 1 Using where -2 SUBQUERY t3 system NULL NULL NULL NULL 0 const row not found +2 MATERIALIZED t3 system NULL NULL NULL NULL 0 const row not found SELECT i FROM t1 LEFT JOIN t2 ON (j) IN (SELECT max(k) FROM t3); i 10 @@ -1850,7 +1850,7 @@ EXPLAIN SELECT pk FROM t1 WHERE (a) IN (SELECT a FROM t2 WHERE pk > 0); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 2 1 PRIMARY eq_ref distinct_key distinct_key 5 func 1 -2 SUBQUERY t2 range PRIMARY PRIMARY 4 NULL 2 Using index condition +2 MATERIALIZED t2 range PRIMARY PRIMARY 4 NULL 2 Using index condition SELECT pk FROM t1 WHERE (a) IN (SELECT a FROM t2 WHERE pk > 0); pk 2 @@ -1895,7 +1895,7 @@ EXPLAIN SELECT * FROM t2 WHERE (SELECT f3a FROM t3) NOT IN (SELECT f1a FROM t1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 ALL NULL NULL NULL NULL 2 -3 SUBQUERY t1 ALL NULL NULL NULL NULL 2 +3 MATERIALIZED t1 ALL NULL NULL NULL NULL 2 2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL no matching row in const table SELECT * FROM t2 WHERE (SELECT f3a FROM t3) NOT IN (SELECT f1a FROM t1); f2 @@ -1912,7 +1912,7 @@ EXPLAIN SELECT * FROM t2 WHERE (SELECT f3a, f3b FROM t3) NOT IN (SELECT f1a, f1b FROM t1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 ALL NULL NULL NULL NULL 2 -3 SUBQUERY t1 ALL NULL NULL NULL NULL 2 +3 MATERIALIZED t1 ALL NULL NULL NULL NULL 2 2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL no matching row in const table SELECT * FROM t2 WHERE (SELECT f3a, f3b FROM t3) NOT IN (SELECT f1a, f1b FROM t1); f2 @@ -1941,7 +1941,7 @@ SELECT (f1, f2, f3) NOT IN FROM t2; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 system NULL NULL NULL NULL 1 -2 SUBQUERY t1 ALL NULL NULL NULL NULL 2 Using filesort +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 2 Using filesort SELECT (f1, f2, f3) NOT IN (SELECT COUNT(DISTINCT f2), f1, f3 FROM t1 GROUP BY f1, f3) FROM t2; @@ -1964,7 +1964,7 @@ EXPLAIN EXTENDED SELECT MAX(t1.b) AS max_res FROM t1 WHERE (9) IN (SELECT a FROM t2); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 index NULL b 5 NULL 2 100.00 Using index -2 SUBQUERY t2 ALL NULL NULL NULL NULL 2 100.00 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 100.00 Warnings: Note 1003 select max(`test`.`t1`.`b`) AS `max_res` from `test`.`t1` where <9>((9,9 in ( (select `test`.`t2`.`a` from `test`.`t2` ), (9 in on distinct_key where ((9 = ``.`a`)))))) set @@optimizer_switch='materialization=off,in_to_exists=on,semijoin=off'; @@ -1992,7 +1992,7 @@ FROM t1 WHERE (a, b) NOT IN (SELECT a, b FROM t2); 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 SUBQUERY t2 ALL NULL NULL NULL NULL 2 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 SELECT * FROM t1 WHERE (a, b) NOT IN (SELECT a, b FROM t2); @@ -2004,7 +2004,7 @@ SELECT a, b, (a, b) NOT IN (SELECT a, b FROM t2) as sq FROM t1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 2 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 2 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 SELECT a, b, (a, b) NOT IN (SELECT a, b FROM t2) as sq FROM t1; a b sq diff --git a/mysql-test/r/subselect_mat_cost.result b/mysql-test/r/subselect_mat_cost.result index 7a28b82455c..003d7b0231b 100644 --- a/mysql-test/r/subselect_mat_cost.result +++ b/mysql-test/r/subselect_mat_cost.result @@ -65,7 +65,7 @@ Name LIKE 'L%') AND surfacearea > 1000000; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY Country ALL Name,SurfaceArea NULL NULL NULL 239 Using where -2 SUBQUERY City ALL Population,Country NULL NULL NULL 4080 Using where +2 MATERIALIZED City ALL Population,Country NULL NULL NULL 4080 Using where SELECT Name FROM Country WHERE (Code IN (select Country from City where City.Population > 100000) OR Name LIKE 'L%') AND @@ -134,7 +134,7 @@ City.name LIKE '%Island%'); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY Country ALL PRIMARY,SurfaceArea NULL NULL NULL 239 Using where 1 PRIMARY City ref Country Country 3 world.Country.Code 18 Using where -2 SUBQUERY CountryLanguage ALL Percentage,Language NULL NULL NULL 984 Using where +2 MATERIALIZED CountryLanguage ALL Percentage,Language NULL NULL NULL 984 Using where SELECT * FROM Country, City WHERE City.Country = Country.Code AND @@ -204,7 +204,7 @@ OR id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY Country ALL PRIMARY,SurfaceArea NULL NULL NULL 239 Using where 1 PRIMARY City ref Country Country 3 world.Country.Code 18 Using where -3 SUBQUERY CountryLanguage index PRIMARY,Language PRIMARY 33 NULL 984 Using index +3 MATERIALIZED CountryLanguage index PRIMARY,Language PRIMARY 33 NULL 984 Using index 2 DEPENDENT SUBQUERY CountryLanguage unique_subquery PRIMARY,Percentage,Language PRIMARY 33 func,func 1 Using where SELECT City.Name, Country.Name FROM City,Country @@ -233,7 +233,7 @@ where City.id not in (select capital from Country where capital is not null and population < 100000); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY City index NULL PRIMARY 4 NULL 4080 Using where; Using index -2 SUBQUERY Country ALL NULL NULL NULL NULL 239 Using where +2 MATERIALIZED Country ALL NULL NULL NULL NULL 239 Using where Q2.2e: Countries that speak French, but do not speak English @@ -287,7 +287,7 @@ AND Code = Country; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY CountryLanguage range PRIMARY,Language Language 30 NULL 45 Using index condition; Using where; Rowid-ordered scan 1 PRIMARY Country eq_ref PRIMARY PRIMARY 3 world.CountryLanguage.Country 1 Using index condition -2 SUBQUERY CountryLanguage ref PRIMARY,Language Language 30 const 47 Using index condition +2 MATERIALIZED CountryLanguage ref PRIMARY,Language Language 30 const 47 Using index condition SELECT Country.Name FROM Country, CountryLanguage WHERE Code NOT IN (SELECT Country FROM CountryLanguage WHERE Language = 'English') @@ -371,8 +371,8 @@ FROM City LEFT JOIN Country ON (Country = Code) HAVING City.Name LIKE "Santa%"); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY CountryLanguage index NULL PRIMARY 33 NULL 984 Using where; Using index -2 SUBQUERY City ALL NULL NULL NULL NULL 4080 -2 SUBQUERY Country eq_ref PRIMARY PRIMARY 3 world.City.Country 1 Using index +2 MATERIALIZED City ALL NULL NULL NULL NULL 4080 +2 MATERIALIZED Country eq_ref PRIMARY PRIMARY 3 world.City.Country 1 Using index select count(*) from CountryLanguage where (Language, Country) NOT IN @@ -399,10 +399,10 @@ WHERE Code = Country GROUP BY Code) order by Country; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY CountryLanguage index NULL PRIMARY 33 NULL 984 Using where; Using index -3 SUBQUERY CountryLanguage index PRIMARY PRIMARY 33 NULL 984 Using index; Using temporary -3 SUBQUERY Country eq_ref PRIMARY PRIMARY 3 world.CountryLanguage.Country 1 Using index -2 SUBQUERY CountryLanguage index PRIMARY PRIMARY 33 NULL 984 Using index; Using temporary -2 SUBQUERY Country eq_ref PRIMARY PRIMARY 3 world.CountryLanguage.Country 1 Using index +3 MATERIALIZED CountryLanguage index PRIMARY PRIMARY 33 NULL 984 Using index; Using temporary +3 MATERIALIZED Country eq_ref PRIMARY PRIMARY 3 world.CountryLanguage.Country 1 Using index +2 MATERIALIZED CountryLanguage index PRIMARY PRIMARY 33 NULL 984 Using index; Using temporary +2 MATERIALIZED Country eq_ref PRIMARY PRIMARY 3 world.CountryLanguage.Country 1 Using index select count(*) from CountryLanguage where @@ -429,7 +429,7 @@ capital is null); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY Country ALL NULL NULL NULL NULL 239 Using where 1 PRIMARY City eq_ref PRIMARY PRIMARY 4 world.Country.Capital 1 Using where -2 SUBQUERY City index NULL CityName 35 NULL 4080 Using index +2 MATERIALIZED City index NULL CityName 35 NULL 4080 Using index select * from Country, City where capital = id and (City.name in (SELECT name FROM City @@ -450,7 +450,7 @@ WHERE Country.Code NOT IN (SELECT Country FROM City GROUP BY Name HAVING COUNT(Name) = 1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY Country ALL NULL NULL NULL NULL 239 Using where -2 SUBQUERY City ALL NULL NULL NULL NULL 4080 Using temporary +2 MATERIALIZED City ALL NULL NULL NULL NULL 4080 Using temporary SELECT Name FROM Country WHERE Country.Code NOT IN @@ -480,7 +480,7 @@ from City where City.population > 10000000; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY City range Population Population 5 NULL 4 Using index condition; Rowid-ordered scan -2 SUBQUERY Country ALL NULL NULL NULL NULL 239 Using where +2 MATERIALIZED Country ALL NULL NULL NULL NULL 239 Using where select Name, City.id in (select capital from Country where capital is not null) as is_capital from City where City.population > 10000000; @@ -514,7 +514,7 @@ HAVING City.Name IN (select Name from Country where population < 1000000); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY City ALL Country NULL NULL NULL 4080 Using temporary; Using filesort 1 PRIMARY Country eq_ref PRIMARY PRIMARY 3 world.City.Country 1 Using index -2 SUBQUERY Country ALL Name NULL NULL NULL 239 Using where +2 MATERIALIZED Country ALL Name NULL NULL NULL 239 Using where SELECT City.Name, City.Population FROM City JOIN Country ON City.Country = Country.Code GROUP BY City.Name diff --git a/mysql-test/r/subselect_mat_cost_bugs.result b/mysql-test/r/subselect_mat_cost_bugs.result index 5623aef011e..87e1060aa87 100644 --- a/mysql-test/r/subselect_mat_cost_bugs.result +++ b/mysql-test/r/subselect_mat_cost_bugs.result @@ -260,8 +260,8 @@ WHERE alias1.f11 OR alias1.f3 = 50 AND alias1.f10 ); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where -2 SUBQUERY alias1 ALL NULL NULL NULL NULL 2 Using where -2 SUBQUERY alias2 ALL NULL NULL NULL NULL 2 Using where; Using join buffer (flat, BNL join) +2 MATERIALIZED alias1 ALL NULL NULL NULL NULL 2 Using where +2 MATERIALIZED alias2 ALL NULL NULL NULL NULL 2 Using where; Using join buffer (flat, BNL join) SELECT * FROM t2 WHERE ( f12 ) IN ( SELECT alias2.f3 @@ -277,8 +277,8 @@ FROM t1 AS alias1, t1 AS alias2 WHERE (alias2.f10 = alias1.f11) AND (alias1.f11 OR alias1.f3 = 50 AND alias1.f10)); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where -2 SUBQUERY alias1 ALL NULL NULL NULL NULL 2 Using where -2 SUBQUERY alias2 ALL NULL NULL NULL NULL 2 Using where; Using join buffer (flat, BNL join) +2 MATERIALIZED alias1 ALL NULL NULL NULL NULL 2 Using where +2 MATERIALIZED alias2 ALL NULL NULL NULL NULL 2 Using where; Using join buffer (flat, BNL join) SELECT * FROM t2 WHERE ( f12 ) IN ( SELECT alias2.f3 @@ -380,14 +380,14 @@ set @@optimizer_switch='in_to_exists=off,materialization=on,partial_match_rowid_ explain select * from t1 where c1 = 'a2' and (c1, c2) not in (select * from t2); 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 SUBQUERY t2 ALL NULL NULL NULL NULL 2 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 select * from t1 where c1 = 'a2' and (c1, c2) not in (select * from t2); c1 c2 set @@optimizer_switch='in_to_exists=off,materialization=on,partial_match_rowid_merge=on,partial_match_table_scan=off'; explain select * from t1 where c1 = 'a2' and (c1, c2) not in (select * from t2); 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 SUBQUERY t2 ALL NULL NULL NULL NULL 2 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 select * from t1 where c1 = 'a2' and (c1, c2) not in (select * from t2); c1 c2 drop table t1, t2; diff --git a/mysql-test/r/subselect_no_mat.result b/mysql-test/r/subselect_no_mat.result index 89f494f15fe..01b83916c4b 100644 --- a/mysql-test/r/subselect_no_mat.result +++ b/mysql-test/r/subselect_no_mat.result @@ -5860,7 +5860,7 @@ SET @@optimizer_switch='semijoin=off,materialization=on,in_to_exists=off,subquer EXPLAIN SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 index NULL a 4 NULL 2 Using where; Using index -2 SUBQUERY t1 index NULL a 4 NULL 2 Using index +2 MATERIALIZED t1 index NULL a 4 NULL 2 Using index SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1); a 2009-01-01 diff --git a/mysql-test/r/subselect_no_opts.result b/mysql-test/r/subselect_no_opts.result index c83b930da79..2c440016931 100644 --- a/mysql-test/r/subselect_no_opts.result +++ b/mysql-test/r/subselect_no_opts.result @@ -5856,7 +5856,7 @@ SET @@optimizer_switch='semijoin=off,materialization=on,in_to_exists=off,subquer EXPLAIN SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 index NULL a 4 NULL 2 Using where; Using index -2 SUBQUERY t1 index NULL a 4 NULL 2 Using index +2 MATERIALIZED t1 index NULL a 4 NULL 2 Using index SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1); a 2009-01-01 diff --git a/mysql-test/r/subselect_no_scache.result b/mysql-test/r/subselect_no_scache.result index bc0953afb02..606a19fa500 100644 --- a/mysql-test/r/subselect_no_scache.result +++ b/mysql-test/r/subselect_no_scache.result @@ -2977,7 +2977,7 @@ explain extended SELECT one,two from t1 where ROW(one,two) IN (SELECT one,two FR id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 8 100.00 1 PRIMARY eq_ref distinct_key distinct_key 10 func,func 1 100.00 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 9 100.00 Using where +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 9 100.00 Using where Warnings: Note 1003 select `test`.`t1`.`one` AS `one`,`test`.`t1`.`two` AS `two` from `test`.`t1` semi join (`test`.`t2`) where ((`test`.`t2`.`flag` = 'N')) explain extended SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0' group by one,two) as 'test' from t1; @@ -3567,7 +3567,7 @@ SELECT * FROM t1 WHERE (a,b) = ANY (SELECT a, max(b) FROM t1 GROUP BY a); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 9 Using where 1 PRIMARY eq_ref distinct_key distinct_key 23 test.t1.a,test.t1.b 1 -2 SUBQUERY t1 ALL NULL NULL NULL NULL 9 Using temporary +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 9 Using temporary ALTER TABLE t1 ADD INDEX(a); SELECT * FROM t1 WHERE (a,b) = ANY (SELECT a, max(b) FROM t1 GROUP BY a); a b @@ -3579,7 +3579,7 @@ SELECT * FROM t1 WHERE (a,b) = ANY (SELECT a, max(b) FROM t1 GROUP BY a); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL a NULL NULL NULL 9 Using where 1 PRIMARY eq_ref distinct_key distinct_key 23 test.t1.a,test.t1.b 1 -2 SUBQUERY t1 ALL NULL NULL NULL NULL 9 Using temporary +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 9 Using temporary DROP TABLE t1; create table t1( f1 int,f2 int); insert into t1 values (1,1),(2,2); @@ -4470,14 +4470,14 @@ 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 1 PRIMARY const distinct_key distinct_key 4 const 1 100.00 -2 SUBQUERY t1 ALL NULL NULL NULL NULL 2 100.00 Using temporary +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 2 100.00 Using temporary Warnings: Note 1003 select 1 AS `1` from (select 1 from `test`.`t1` group by `test`.`t1`.`a`) join `test`.`t1` where (``.`1` = 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 t1 ALL NULL NULL NULL NULL 2 100.00 1 PRIMARY const distinct_key distinct_key 4 const 1 100.00 -2 SUBQUERY t1 ALL NULL NULL NULL NULL 2 100.00 Using where; Using temporary +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 2 100.00 Using where; Using temporary Warnings: Note 1003 select 1 AS `1` from (select 1 from `test`.`t1` where (`test`.`t1`.`a` > 3) group by `test`.`t1`.`a`) join `test`.`t1` where (``.`1` = 1) DROP TABLE t1; @@ -5164,8 +5164,8 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ot1 ALL NULL NULL NULL NULL 2 1 PRIMARY ALL distinct_key NULL NULL NULL 24 Using where 1 PRIMARY ot4 ALL NULL NULL NULL NULL 8 Using where; Using join buffer (flat, BNL join) -2 SUBQUERY it2 ALL NULL NULL NULL NULL 4 -2 SUBQUERY it3 ALL NULL NULL NULL NULL 6 Using join buffer (flat, BNL join) +2 MATERIALIZED it2 ALL NULL NULL NULL NULL 4 +2 MATERIALIZED it3 ALL NULL NULL NULL NULL 6 Using join buffer (flat, BNL join) DROP TABLE IF EXISTS ot1, ot4, it2, it3; # # Bug#729039: NULL keys used to evaluate subquery @@ -5865,7 +5865,7 @@ SET @@optimizer_switch='semijoin=off,materialization=on,in_to_exists=off,subquer EXPLAIN SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 index NULL a 4 NULL 2 Using where; Using index -2 SUBQUERY t1 index NULL a 4 NULL 2 Using index +2 MATERIALIZED t1 index NULL a 4 NULL 2 Using index SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1); a 2009-01-01 diff --git a/mysql-test/r/subselect_no_semijoin.result b/mysql-test/r/subselect_no_semijoin.result index 8a8b73eb5bb..665b4213b60 100644 --- a/mysql-test/r/subselect_no_semijoin.result +++ b/mysql-test/r/subselect_no_semijoin.result @@ -907,7 +907,7 @@ a t1.a in (select t2.a from t2) explain extended SELECT t1.a, t1.a in (select t2.a from t2) FROM t1; id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 index NULL PRIMARY 4 NULL 4 100.00 Using index -2 SUBQUERY t2 index a a 5 NULL 3 100.00 Using index +2 MATERIALIZED t2 index a a 5 NULL 3 100.00 Using index Warnings: Note 1003 select `test`.`t1`.`a` AS `a`,<`test`.`t1`.`a`>((`test`.`t1`.`a`,`test`.`t1`.`a` in ( (select `test`.`t2`.`a` from `test`.`t2` ), (`test`.`t1`.`a` in on distinct_key where ((`test`.`t1`.`a` = ``.`a`)))))) AS `t1.a in (select t2.a from t2)` from `test`.`t1` CREATE TABLE t3 (a int(11) default '0'); @@ -921,8 +921,8 @@ a t1.a in (select t2.a from t2,t3 where t3.a=t2.a) explain extended SELECT t1.a, t1.a in (select t2.a from t2,t3 where t3.a=t2.a) FROM t1; id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 index NULL PRIMARY 4 NULL 4 100.00 Using index -2 SUBQUERY t2 index a a 5 NULL 3 100.00 Using index -2 SUBQUERY t3 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (flat, BNL join) +2 MATERIALIZED t2 index a a 5 NULL 3 100.00 Using index +2 MATERIALIZED t3 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (flat, BNL join) Warnings: Note 1003 select `test`.`t1`.`a` AS `a`,<`test`.`t1`.`a`>((`test`.`t1`.`a`,`test`.`t1`.`a` in ( (select `test`.`t2`.`a` from `test`.`t2` join `test`.`t3` where (`test`.`t3`.`a` = `test`.`t2`.`a`) ), (`test`.`t1`.`a` in on distinct_key where ((`test`.`t1`.`a` = ``.`a`)))))) AS `t1.a in (select t2.a from t2,t3 where t3.a=t2.a)` from `test`.`t1` drop table t1,t2,t3; @@ -1437,7 +1437,7 @@ a explain extended select * from t2 where t2.a in (select a from t1); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 index NULL PRIMARY 4 NULL 4 100.00 Using where; Using index -2 SUBQUERY t1 index PRIMARY PRIMARY 4 NULL 4 100.00 Using index +2 MATERIALIZED t1 index PRIMARY PRIMARY 4 NULL 4 100.00 Using index Warnings: Note 1003 select `test`.`t2`.`a` AS `a` from `test`.`t2` where <`test`.`t2`.`a`>((`test`.`t2`.`a`,`test`.`t2`.`a` in ( (select `test`.`t1`.`a` from `test`.`t1` ), (`test`.`t2`.`a` in on distinct_key where ((`test`.`t2`.`a` = ``.`a`)))))) select * from t2 where t2.a in (select a from t1 where t1.b <> 30); @@ -1447,7 +1447,7 @@ a explain extended select * from t2 where t2.a in (select a from t1 where t1.b <> 30); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 index NULL PRIMARY 4 NULL 4 100.00 Using where; Using index -2 SUBQUERY t1 ALL PRIMARY NULL NULL NULL 4 100.00 Using where +2 MATERIALIZED t1 ALL PRIMARY NULL NULL NULL 4 100.00 Using where Warnings: Note 1003 select `test`.`t2`.`a` AS `a` from `test`.`t2` where <`test`.`t2`.`a`>((`test`.`t2`.`a`,`test`.`t2`.`a` in ( (select `test`.`t1`.`a` from `test`.`t1` where (`test`.`t1`.`b` <> 30) ), (`test`.`t2`.`a` in on distinct_key where ((`test`.`t2`.`a` = ``.`a`)))))) select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a); @@ -1457,8 +1457,8 @@ a explain extended select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 index NULL PRIMARY 4 NULL 4 100.00 Using where; Using index -2 SUBQUERY t3 index PRIMARY PRIMARY 4 NULL 3 100.00 Using index -2 SUBQUERY t1 ALL PRIMARY NULL NULL NULL 4 100.00 Using where; Using join buffer (flat, BNL join) +2 MATERIALIZED t3 index PRIMARY PRIMARY 4 NULL 3 100.00 Using index +2 MATERIALIZED t1 ALL PRIMARY NULL NULL NULL 4 100.00 Using where; Using join buffer (flat, BNL join) Warnings: Note 1003 select `test`.`t2`.`a` AS `a` from `test`.`t2` where <`test`.`t2`.`a`>((`test`.`t2`.`a`,`test`.`t2`.`a` in ( (select `test`.`t1`.`a` from `test`.`t1` join `test`.`t3` where (`test`.`t1`.`b` = `test`.`t3`.`a`) ), (`test`.`t2`.`a` in on distinct_key where ((`test`.`t2`.`a` = ``.`a`)))))) drop table t1, t2, t3; @@ -1608,25 +1608,25 @@ a3 1 explain extended select s1, s1 NOT IN (SELECT s1 FROM t2) from t1; id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 index NULL s1 6 NULL 3 100.00 Using index -2 SUBQUERY t2 index s1 s1 6 NULL 2 100.00 Using index +2 MATERIALIZED t2 index s1 s1 6 NULL 2 100.00 Using index Warnings: Note 1003 select `test`.`t1`.`s1` AS `s1`,(not(<`test`.`t1`.`s1`>((`test`.`t1`.`s1`,`test`.`t1`.`s1` in ( (select `test`.`t2`.`s1` from `test`.`t2` ), (`test`.`t1`.`s1` in on distinct_key where ((`test`.`t1`.`s1` = ``.`s1`)))))))) AS `s1 NOT IN (SELECT s1 FROM t2)` from `test`.`t1` explain extended select s1, s1 = ANY (SELECT s1 FROM t2) from t1; id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 index NULL s1 6 NULL 3 100.00 Using index -2 SUBQUERY t2 index s1 s1 6 NULL 2 100.00 Using index +2 MATERIALIZED t2 index s1 s1 6 NULL 2 100.00 Using index Warnings: Note 1003 select `test`.`t1`.`s1` AS `s1`,<`test`.`t1`.`s1`>((`test`.`t1`.`s1`,`test`.`t1`.`s1` in ( (select `test`.`t2`.`s1` from `test`.`t2` ), (`test`.`t1`.`s1` in on distinct_key where ((`test`.`t1`.`s1` = ``.`s1`)))))) AS `s1 = ANY (SELECT s1 FROM t2)` from `test`.`t1` explain extended select s1, s1 <> ALL (SELECT s1 FROM t2) from t1; id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 index NULL s1 6 NULL 3 100.00 Using index -2 SUBQUERY t2 index s1 s1 6 NULL 2 100.00 Using index +2 MATERIALIZED t2 index s1 s1 6 NULL 2 100.00 Using index Warnings: Note 1003 select `test`.`t1`.`s1` AS `s1`,(not(<`test`.`t1`.`s1`>((`test`.`t1`.`s1`,`test`.`t1`.`s1` in ( (select `test`.`t2`.`s1` from `test`.`t2` ), (`test`.`t1`.`s1` in on distinct_key where ((`test`.`t1`.`s1` = ``.`s1`)))))))) AS `s1 <> ALL (SELECT s1 FROM t2)` from `test`.`t1` explain extended select s1, s1 NOT IN (SELECT s1 FROM t2 WHERE s1 < 'a2') from t1; id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 index NULL s1 6 NULL 3 100.00 Using index -2 SUBQUERY t2 index s1 s1 6 NULL 2 50.00 Using where; Using index +2 MATERIALIZED t2 index s1 s1 6 NULL 2 50.00 Using where; Using index Warnings: Note 1003 select `test`.`t1`.`s1` AS `s1`,(not(<`test`.`t1`.`s1`>((`test`.`t1`.`s1`,`test`.`t1`.`s1` in ( (select `test`.`t2`.`s1` from `test`.`t2` where (`test`.`t2`.`s1` < 'a2') ), (`test`.`t1`.`s1` in on distinct_key where ((`test`.`t1`.`s1` = ``.`s1`)))))))) AS `s1 NOT IN (SELECT s1 FROM t2 WHERE s1 < 'a2')` from `test`.`t1` drop table t1,t2; @@ -1881,7 +1881,7 @@ id text explain extended select * from t1 where id not in (select id from t1 where id < 8); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 12 100.00 Using where -2 SUBQUERY t1 range PRIMARY PRIMARY 4 NULL 7 100.00 Using where; Using index +2 MATERIALIZED t1 range PRIMARY PRIMARY 4 NULL 7 100.00 Using where; Using index Warnings: Note 1003 select `test`.`t1`.`id` AS `id`,`test`.`t1`.`text` AS `text` from `test`.`t1` where (not(<`test`.`t1`.`id`>((`test`.`t1`.`id`,`test`.`t1`.`id` in ( (select `test`.`t1`.`id` from `test`.`t1` where (`test`.`t1`.`id` < 8) ), (`test`.`t1`.`id` in on distinct_key where ((`test`.`t1`.`id` = ``.`id`)))))))) explain extended select * from t1 as tt where not exists (select id from t1 where id < 8 and (id = tt.id or id is null) having id is not null); @@ -2967,19 +2967,19 @@ one two test explain extended SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0') as 'test' from t1; id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 8 100.00 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 9 100.00 Using where +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 9 100.00 Using where Warnings: Note 1003 select `test`.`t1`.`one` AS `one`,`test`.`t1`.`two` AS `two`,<`test`.`t1`.`one`,`test`.`t1`.`two`>(((`test`.`t1`.`one`,`test`.`t1`.`two`),(`test`.`t1`.`one`,`test`.`t1`.`two`) in ( (select `test`.`t2`.`one`,`test`.`t2`.`two` from `test`.`t2` where (`test`.`t2`.`flag` = '0') ), (`test`.`t1`.`one` in on distinct_key where ((`test`.`t1`.`one` = ``.`one`) and (`test`.`t1`.`two` = ``.`two`)))))) AS `test` from `test`.`t1` explain extended SELECT one,two from t1 where ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = 'N'); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 8 100.00 Using where -2 SUBQUERY t2 ALL NULL NULL NULL NULL 9 100.00 Using where +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 9 100.00 Using where Warnings: Note 1003 select `test`.`t1`.`one` AS `one`,`test`.`t1`.`two` AS `two` from `test`.`t1` where <`test`.`t1`.`one`,`test`.`t1`.`two`>(((`test`.`t1`.`one`,`test`.`t1`.`two`),(`test`.`t1`.`one`,`test`.`t1`.`two`) in ( (select `test`.`t2`.`one`,`test`.`t2`.`two` from `test`.`t2` where (`test`.`t2`.`flag` = 'N') ), (`test`.`t1`.`one` in on distinct_key where ((`test`.`t1`.`one` = ``.`one`) and (`test`.`t1`.`two` = ``.`two`)))))) explain extended SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0' group by one,two) as 'test' from t1; id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 8 100.00 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 9 100.00 Using where; Using temporary +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 9 100.00 Using where; Using temporary Warnings: Note 1003 select `test`.`t1`.`one` AS `one`,`test`.`t1`.`two` AS `two`,<`test`.`t1`.`one`,`test`.`t1`.`two`>(((`test`.`t1`.`one`,`test`.`t1`.`two`),(`test`.`t1`.`one`,`test`.`t1`.`two`) in ( (select `test`.`t2`.`one`,`test`.`t2`.`two` from `test`.`t2` where (`test`.`t2`.`flag` = '0') group by `test`.`t2`.`one`,`test`.`t2`.`two` ), (`test`.`t1`.`one` in on distinct_key where ((`test`.`t1`.`one` = ``.`one`) and (`test`.`t1`.`two` = ``.`two`)))))) AS `test` from `test`.`t1` DROP TABLE t1,t2; @@ -3162,7 +3162,7 @@ INSERT INTO t2 VALUES (1),(2),(3); EXPLAIN SELECT a, a IN (SELECT a FROM t1) FROM t2; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 ALL NULL NULL NULL NULL 3 -2 SUBQUERY t1 index a a 5 NULL 5 Using index +2 MATERIALIZED t1 index a a 5 NULL 5 Using index SELECT a, a IN (SELECT a FROM t1) FROM t2; a a IN (SELECT a FROM t1) 1 1 @@ -3562,7 +3562,7 @@ EXPLAIN SELECT * FROM t1 WHERE (a,b) = ANY (SELECT a, max(b) FROM t1 GROUP BY a); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 9 Using where -2 SUBQUERY t1 ALL NULL NULL NULL NULL 9 Using temporary +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 9 Using temporary ALTER TABLE t1 ADD INDEX(a); SELECT * FROM t1 WHERE (a,b) = ANY (SELECT a, max(b) FROM t1 GROUP BY a); a b @@ -3573,7 +3573,7 @@ EXPLAIN SELECT * FROM t1 WHERE (a,b) = ANY (SELECT a, max(b) FROM t1 GROUP BY a); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 9 Using where -2 SUBQUERY t1 ALL NULL NULL NULL NULL 9 Using temporary +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 9 Using temporary DROP TABLE t1; create table t1( f1 int,f2 int); insert into t1 values (1,1),(2,2); @@ -4343,7 +4343,7 @@ CREATE INDEX I2 ON t1 (b); EXPLAIN SELECT a,b FROM t1 WHERE b IN (SELECT a FROM t1); 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 SUBQUERY t1 index I1 I1 2 NULL 2 Using index +2 MATERIALIZED t1 index I1 I1 2 NULL 2 Using index SELECT a,b FROM t1 WHERE b IN (SELECT a FROM t1); a b CREATE TABLE t2 (a VARCHAR(1), b VARCHAR(10)); @@ -4353,14 +4353,14 @@ CREATE INDEX I2 ON t2 (b); EXPLAIN SELECT a,b FROM t2 WHERE b IN (SELECT a FROM t2); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where -2 SUBQUERY t2 index I1 I1 4 NULL 2 Using index +2 MATERIALIZED t2 index I1 I1 4 NULL 2 Using index SELECT a,b FROM t2 WHERE b IN (SELECT a FROM t2); a b EXPLAIN SELECT a,b FROM t1 WHERE b IN (SELECT a FROM t1 WHERE LENGTH(a)<500); 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 SUBQUERY t1 index I1 I1 2 NULL 2 Using where; Using index +2 MATERIALIZED t1 index I1 I1 2 NULL 2 Using where; Using index SELECT a,b FROM t1 WHERE b IN (SELECT a FROM t1 WHERE LENGTH(a)<500); a b DROP TABLE t1,t2; @@ -4463,13 +4463,13 @@ 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 SUBQUERY t1 ALL NULL NULL NULL NULL 2 100.00 Using temporary +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 2 100.00 Using temporary Warnings: Note 1003 select 1 AS `1` from `test`.`t1` where <1>((1,1 in ( (select 1 from `test`.`t1` group by `test`.`t1`.`a` ), (1 in on distinct_key where ((1 = ``.`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 t1 ALL NULL NULL NULL NULL 2 100.00 -2 SUBQUERY t1 ALL NULL NULL NULL NULL 2 100.00 Using where; Using temporary +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 2 100.00 Using where; Using temporary Warnings: Note 1003 select 1 AS `1` from `test`.`t1` where <1>((1,1 in ( (select 1 from `test`.`t1` where (`test`.`t1`.`a` > 3) group by `test`.`t1`.`a` ), (1 in on distinct_key where ((1 = ``.`1`)))))) DROP TABLE t1; @@ -5155,8 +5155,8 @@ FROM it2,it3); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ot1 ALL NULL NULL NULL NULL 2 1 PRIMARY ot4 ALL NULL NULL NULL NULL 8 Using where; Using join buffer (flat, BNL join) -2 SUBQUERY it2 ALL NULL NULL NULL NULL 4 -2 SUBQUERY it3 ALL NULL NULL NULL NULL 6 Using join buffer (flat, BNL join) +2 MATERIALIZED it2 ALL NULL NULL NULL NULL 4 +2 MATERIALIZED it3 ALL NULL NULL NULL NULL 6 Using join buffer (flat, BNL join) DROP TABLE IF EXISTS ot1, ot4, it2, it3; # # Bug#729039: NULL keys used to evaluate subquery @@ -5200,8 +5200,8 @@ INSERT INTO t2 VALUES (15,4); EXPLAIN SELECT * FROM t1 WHERE pk IN (SELECT it.pk FROM t2 JOIN t2 AS it ON 1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where -2 SUBQUERY t2 index NULL PRIMARY 4 NULL 3 Using index -2 SUBQUERY it index PRIMARY PRIMARY 4 NULL 3 Using index; Using join buffer (flat, BNL join) +2 MATERIALIZED t2 index NULL PRIMARY 4 NULL 3 Using index +2 MATERIALIZED it index PRIMARY PRIMARY 4 NULL 3 Using index; Using join buffer (flat, BNL join) SELECT * FROM t1 WHERE pk IN (SELECT it.pk FROM t2 JOIN t2 AS it ON 1); pk i 11 0 @@ -5444,7 +5444,7 @@ WHERE (t2.b , t1.c) NOT IN (SELECT * from t3); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 ALL NULL NULL NULL NULL 2 1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where -2 SUBQUERY t3 ALL NULL NULL NULL NULL 2 +2 MATERIALIZED t3 ALL NULL NULL NULL NULL 2 SELECT t2.b , t1.c FROM t2 LEFT JOIN t1 ON t1.c < 3 WHERE (t2.b, t1.c) NOT IN (SELECT * from t3); @@ -5856,7 +5856,7 @@ SET @@optimizer_switch='semijoin=off,materialization=on,in_to_exists=off,subquer EXPLAIN SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 index NULL a 4 NULL 2 Using where; Using index -2 SUBQUERY t1 index NULL a 4 NULL 2 Using index +2 MATERIALIZED t1 index NULL a 4 NULL 2 Using index SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1); a 2009-01-01 diff --git a/mysql-test/r/subselect_partial_match.result b/mysql-test/r/subselect_partial_match.result index a01d6375064..4e37b831326 100644 --- a/mysql-test/r/subselect_partial_match.result +++ b/mysql-test/r/subselect_partial_match.result @@ -74,7 +74,7 @@ EXPLAIN SELECT t1.*, (a1, a2, a3) IN (select * from t2) as in_res from t1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 1 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 3 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 SELECT t1.*, (a1, a2, a3) IN (select * from t2) as in_res from t1; a1 a2 a3 in_res c NULL a NULL @@ -82,7 +82,7 @@ EXPLAIN SELECT * from t1 where (a1, a2, a3) NOT IN (select * from t2); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 1 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 3 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 SELECT * from t1 where (a1, a2, a3) NOT IN (select * from t2); a1 a2 a3 set @@optimizer_switch='partial_match_rowid_merge=off,partial_match_table_scan=on'; @@ -90,7 +90,7 @@ EXPLAIN SELECT t1.*, (a1, a2, a3) IN (select * from t2) as in_res from t1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 1 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 3 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 SELECT t1.*, (a1, a2, a3) IN (select * from t2) as in_res from t1; a1 a2 a3 in_res c NULL a NULL @@ -98,7 +98,7 @@ EXPLAIN SELECT * from t1 where (a1, a2, a3) NOT IN (select * from t2); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 1 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 3 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 SELECT * from t1 where (a1, a2, a3) NOT IN (select * from t2); a1 a2 a3 set @@optimizer_switch=@in_exists; @@ -129,7 +129,7 @@ EXPLAIN SELECT t1.*, (a1, a2, a3) IN (select * from t2) as in_res from t1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 1 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 2 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 SELECT t1.*, (a1, a2, a3) IN (select * from t2) as in_res from t1; a1 a2 a3 in_res NULL y NULL NULL @@ -137,7 +137,7 @@ EXPLAIN SELECT * from t1 where (a1, a2, a3) NOT IN (select * from t2); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 1 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 2 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 SELECT * from t1 where (a1, a2, a3) NOT IN (select * from t2); a1 a2 a3 set @@optimizer_switch='partial_match_rowid_merge=off,partial_match_table_scan=on'; @@ -145,7 +145,7 @@ EXPLAIN SELECT t1.*, (a1, a2, a3) IN (select * from t2) as in_res from t1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 1 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 2 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 SELECT t1.*, (a1, a2, a3) IN (select * from t2) as in_res from t1; a1 a2 a3 in_res NULL y NULL NULL @@ -153,7 +153,7 @@ EXPLAIN SELECT * from t1 where (a1, a2, a3) NOT IN (select * from t2); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 1 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 2 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 SELECT * from t1 where (a1, a2, a3) NOT IN (select * from t2); a1 a2 a3 set @@optimizer_switch=@in_exists; @@ -188,7 +188,7 @@ EXPLAIN SELECT t1.*, (a1, a2, a3) IN (select * from t2) as in_res from t1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 1 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 2 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 SELECT t1.*, (a1, a2, a3) IN (select * from t2) as in_res from t1; a1 a2 a3 in_res NULL g NULL NULL @@ -196,7 +196,7 @@ EXPLAIN SELECT * from t1 where (a1, a2, a3) NOT IN (select * from t2); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 1 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 2 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 SELECT * from t1 where (a1, a2, a3) NOT IN (select * from t2); a1 a2 a3 set @@optimizer_switch='partial_match_rowid_merge=off,partial_match_table_scan=on'; @@ -204,7 +204,7 @@ EXPLAIN SELECT t1.*, (a1, a2, a3) IN (select * from t2) as in_res from t1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 1 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 2 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 SELECT t1.*, (a1, a2, a3) IN (select * from t2) as in_res from t1; a1 a2 a3 in_res NULL g NULL NULL @@ -212,7 +212,7 @@ EXPLAIN SELECT * from t1 where (a1, a2, a3) NOT IN (select * from t2); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 1 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 2 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 SELECT * from t1 where (a1, a2, a3) NOT IN (select * from t2); a1 a2 a3 set @@optimizer_switch=@in_exists; @@ -247,7 +247,7 @@ EXPLAIN SELECT t1.*, (a1, a2, a3) IN (select * from t2) as in_res from t1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 1 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 2 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 SELECT t1.*, (a1, a2, a3) IN (select * from t2) as in_res from t1; a1 a2 a3 in_res b g NULL 0 @@ -255,7 +255,7 @@ EXPLAIN SELECT * from t1 where (a1, a2, a3) NOT IN (select * from t2); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 1 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 2 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 SELECT * from t1 where (a1, a2, a3) NOT IN (select * from t2); a1 a2 a3 b g NULL @@ -264,7 +264,7 @@ EXPLAIN SELECT t1.*, (a1, a2, a3) IN (select * from t2) as in_res from t1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 1 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 2 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 SELECT t1.*, (a1, a2, a3) IN (select * from t2) as in_res from t1; a1 a2 a3 in_res b g NULL 0 @@ -272,7 +272,7 @@ EXPLAIN SELECT * from t1 where (a1, a2, a3) NOT IN (select * from t2); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 1 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 2 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 SELECT * from t1 where (a1, a2, a3) NOT IN (select * from t2); a1 a2 a3 b g NULL @@ -773,7 +773,7 @@ SELECT * FROM (SELECT * FROM t1 WHERE a1 NOT IN (SELECT b2 FROM t2)) table1; id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY ALL NULL NULL NULL NULL 2 100.00 2 DERIVED t1 ALL NULL NULL NULL NULL 2 100.00 Using where -3 SUBQUERY t2 ALL NULL NULL NULL NULL 2 100.00 +3 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 100.00 Warnings: Note 1003 select `table1`.`a1` AS `a1`,`table1`.`a2` AS `a2` from (select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where (not((`test`.`t1`.`a1`,`test`.`t1`.`a1` in ( (select `test`.`t2`.`b2` from `test`.`t2` ), (`test`.`t1`.`a1` in on distinct_key where ((`test`.`t1`.`a1` = ``.`b2`)))))))) `table1` set optimizer_switch=@tmp_optimizer_switch; @@ -787,7 +787,7 @@ insert into t1 values (NULL, 'a21'), (NULL, 'a22'); explain select * from t1 where (a1, a2) not in (select a1, a2 from t1); 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 SUBQUERY t1 ALL NULL NULL NULL NULL 2 +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 2 select * from t1 where (a1, a2) not in (select a1, a2 from t1); a1 a2 drop table t1; @@ -821,8 +821,8 @@ SELECT t3.d , t2.c FROM t3 LEFT JOIN t2 ON t3.a = t2.a); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 1 -2 SUBQUERY t3 system NULL NULL NULL NULL 1 -2 SUBQUERY t2 system NULL NULL NULL NULL 1 +2 MATERIALIZED t3 system NULL NULL NULL NULL 1 +2 MATERIALIZED t2 system NULL NULL NULL NULL 1 SELECT * FROM t1 WHERE (t1.d , t1.d) NOT IN ( @@ -860,7 +860,7 @@ EXPLAIN SELECT * FROM t1 WHERE (6, 4 ) NOT IN (SELECT b, a FROM t2); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 2 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 2 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 SELECT * FROM t1 WHERE (6, 4 ) NOT IN (SELECT b, a FROM t2); c 0 @@ -869,7 +869,7 @@ EXPLAIN SELECT * FROM t1 WHERE (6, 4 ) NOT IN (SELECT a, b FROM t2); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 2 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 2 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 SELECT * FROM t1 WHERE (6, 4 ) NOT IN (SELECT a, b FROM t2); c 0 @@ -905,7 +905,7 @@ set @@optimizer_switch='in_to_exists=off,materialization=on,partial_match_rowid_ EXPLAIN SELECT * FROM t2 WHERE ( 3 , 1 ) NOT IN ( SELECT f1 , f2 FROM t1 ); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 system NULL NULL NULL NULL 1 -2 SUBQUERY t1 ALL NULL NULL NULL NULL 3 +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 3 SELECT * FROM t2 WHERE ( 3 , 1 ) NOT IN ( SELECT f1 , f2 FROM t1 ); f3 5 @@ -962,7 +962,7 @@ set @@optimizer_switch='materialization=on,partial_match_rowid_merge=on,partial_ EXPLAIN SELECT * FROM t1 WHERE (a, b) NOT IN (SELECT c, d FROM t2); 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 SUBQUERY t2 ALL NULL NULL NULL NULL 3 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 SELECT * FROM t1 WHERE (a, b) NOT IN (SELECT c, d FROM t2); a b 0 NULL @@ -973,7 +973,7 @@ a b subq_res EXPLAIN SELECT * FROM t1 WHERE (a, b) NOT IN (SELECT c, d FROM t2 WHERE d is not NULL); 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 SUBQUERY t2 ALL NULL NULL NULL NULL 3 Using where +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 Using where SELECT * FROM t1 WHERE (a, b) NOT IN (SELECT c, d FROM t2 WHERE d is not NULL); a b 0 NULL diff --git a/mysql-test/r/subselect_sj.result b/mysql-test/r/subselect_sj.result index a9b4b4cb0cf..9f37dbf4e04 100644 --- a/mysql-test/r/subselect_sj.result +++ b/mysql-test/r/subselect_sj.result @@ -79,7 +79,7 @@ id select_type tABle type possiBle_keys key key_len ref rows filtered ExtrA 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 1 PRIMARY A ALL NULL NULL NULL NULL 3 100.00 Using where 1 PRIMARY B ALL NULL NULL NULL NULL 3 100.00 Using where -2 SUBQUERY t10 index PRIMARY PRIMARY 4 NULL 10 100.00 Using index +2 MATERIALIZED t10 index PRIMARY PRIMARY 4 NULL 10 100.00 Using index Warnings: Note 1003 select `test`.`t1`.`A` AS `A`,`test`.`t1`.`B` AS `B`,`test`.`A`.`A` AS `A`,`test`.`A`.`B` AS `B`,`test`.`B`.`A` AS `A`,`test`.`B`.`B` AS `B` from `test`.`t1` left join (`test`.`t2` `A` join `test`.`t2` `B`) on(((`test`.`B`.`A`,`test`.`B`.`A` in ( (select `test`.`t10`.`pk` from `test`.`t10` ), (`test`.`B`.`A` in on distinct_key where ((`test`.`B`.`A` = ``.`pk`))))) And (`test`.`A`.`A` = `test`.`t1`.`A`))) where 1 t2 should be wrapped into OJ-nest, so we have "t1 LJ (t2 J t10)" @@ -88,7 +88,7 @@ select * from t1 left join t2 on (t2.A= t1.A And t2.A in (select pk from t10)); id select_type tABle type possiBle_keys key key_len ref rows filtered ExtrA 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 1 PRIMARY t2 ALL NULL NULL NULL NULL 3 100.00 Using where -2 SUBQUERY t10 index PRIMARY PRIMARY 4 NULL 10 100.00 Using index +2 MATERIALIZED t10 index PRIMARY PRIMARY 4 NULL 10 100.00 Using index Warnings: Note 1003 select `test`.`t1`.`A` AS `A`,`test`.`t1`.`B` AS `B`,`test`.`t2`.`A` AS `A`,`test`.`t2`.`B` AS `B` from `test`.`t1` left join `test`.`t2` on(((`test`.`t2`.`A`,`test`.`t2`.`A` in ( (select `test`.`t10`.`pk` from `test`.`t10` ), (`test`.`t2`.`A` in on distinct_key where ((`test`.`t2`.`A` = ``.`pk`))))) And (`test`.`t2`.`A` = `test`.`t1`.`A`))) where 1 we shouldn't flatten if we're going to get a join of > MAX_TABLES. @@ -726,8 +726,8 @@ FROM it1 LEFT JOIN it2 ON it2.datetime_key); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL distinct_key NULL NULL NULL 11 1 PRIMARY ot1 ALL NULL NULL NULL NULL 20 Using where; Using join buffer (flat, BNL join) -2 SUBQUERY it1 index NULL int_key 4 NULL 2 Using index -2 SUBQUERY it2 ALL int_key,datetime_key NULL NULL NULL 20 Using where +2 MATERIALIZED it1 index NULL int_key 4 NULL 2 Using index +2 MATERIALIZED it2 ALL int_key,datetime_key NULL NULL NULL 20 Using where DROP TABLE ot1, it1, it2; # End of BUG#38075 # @@ -800,7 +800,7 @@ EXPLAIN EXTENDED SELECT pk FROM t1 WHERE (a, b) IN (SELECT a, b FROM t2 WHERE pk 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 1 PRIMARY eq_ref distinct_key distinct_key 13 func,func 1 100.00 -2 SUBQUERY t2 range PRIMARY PRIMARY 4 NULL 2 100.00 Using index condition; Rowid-ordered scan +2 MATERIALIZED t2 range PRIMARY PRIMARY 4 NULL 2 100.00 Using index condition; Rowid-ordered scan Warnings: Note 1003 select `test`.`t1`.`pk` AS `pk` from `test`.`t1` semi join (`test`.`t2`) where ((`test`.`t2`.`pk` > 0)) SELECT pk FROM t1 WHERE (a, b) IN (SELECT a, b FROM t2 WHERE pk > 0); @@ -969,7 +969,7 @@ WHERE `varchar_nokey` < 'n' XOR `pk` ) ; id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 ALL NULL NULL NULL NULL 18 100.00 1 PRIMARY eq_ref distinct_key distinct_key 8 func,func 1 100.00 -2 SUBQUERY t1 ALL varchar_key NULL NULL NULL 15 100.00 Using where +2 MATERIALIZED t1 ALL varchar_key NULL NULL NULL 15 100.00 Using where Warnings: Note 1003 select `test`.`t2`.`varchar_nokey` AS `varchar_nokey` from `test`.`t2` semi join (`test`.`t1`) where ((`test`.`t1`.`varchar_nokey` = `test`.`t1`.`varchar_key`) and ((`test`.`t1`.`varchar_key` < 'n') xor `test`.`t1`.`pk`)) SELECT varchar_nokey @@ -1052,8 +1052,8 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 5 1 PRIMARY eq_ref distinct_key distinct_key 14 func 1 1 PRIMARY eq_ref distinct_key distinct_key 14 func 1 -3 SUBQUERY t3 ALL NULL NULL NULL NULL 5 Using where -2 SUBQUERY t2 ALL NULL NULL NULL NULL 6 Using where +3 MATERIALIZED t3 ALL NULL NULL NULL NULL 5 Using where +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 6 Using where SELECT * FROM t1 WHERE t1.val IN (SELECT t2.val FROM t2 @@ -1275,8 +1275,8 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY eq_ref distinct_key distinct_key 5 func 1 1 PRIMARY B ALL NULL NULL NULL NULL 3 Using where; Using join buffer (flat, BNL join) 1 PRIMARY eq_ref distinct_key distinct_key 5 func 1 -2 SUBQUERY C ALL NULL NULL NULL NULL 3 -3 SUBQUERY D ALL NULL NULL NULL NULL 3 +2 MATERIALIZED C ALL NULL NULL NULL NULL 3 +3 MATERIALIZED D ALL NULL NULL NULL NULL 3 drop table t1, t2; # # BUG#784441: Abort on semijoin with a view as the inner table @@ -1291,7 +1291,7 @@ SELECT * FROM t1 INNER JOIN t2 ON t2.a != 0 AND t2.a IN (SELECT * FROM v1); 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; Using join buffer (flat, BNL join) -2 SUBQUERY system NULL NULL NULL NULL 1 +2 MATERIALIZED system NULL NULL NULL NULL 1 3 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used SELECT * FROM t1 INNER JOIN t2 ON t2.a != 0 AND t2.a IN (SELECT * FROM v1); a a @@ -1386,8 +1386,8 @@ explain select * from t3 where t3.b in (select t2.b from t1 left join t2 on t1.a id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL distinct_key NULL NULL NULL 2 1 PRIMARY t3 ALL NULL NULL NULL NULL 8 Using where; Using join buffer (flat, BNL join) -2 SUBQUERY t1 ALL NULL NULL NULL NULL 2 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 2 Using where +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 2 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 Using where select * from t3 where t3.b in (select t2.b from t1 left join t2 on t1.a=t2.a); b drop table t1, t2, t3; @@ -1990,8 +1990,8 @@ SELECT * FROM t1 WHERE (a) IN (SELECT a FROM t2 JOIN t3 ON b = a); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 9 1 PRIMARY eq_ref distinct_key distinct_key 5 func 1 -2 SUBQUERY t3 ALL NULL NULL NULL NULL 13 Using where -2 SUBQUERY t2 ref b b 4 test.t3.a 1 Using index +2 MATERIALIZED t3 ALL NULL NULL NULL NULL 13 Using where +2 MATERIALIZED t2 ref b b 4 test.t3.a 1 Using index SELECT * FROM t1 WHERE (a) IN (SELECT a FROM t2 JOIN t3 ON b = a); a 19 diff --git a/mysql-test/r/subselect_sj2.result b/mysql-test/r/subselect_sj2.result index d476de2dea1..cd147e55d1d 100644 --- a/mysql-test/r/subselect_sj2.result +++ b/mysql-test/r/subselect_sj2.result @@ -48,7 +48,7 @@ explain select * from t2 where b in (select a from t1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL distinct_key NULL NULL NULL 3 1 PRIMARY t2 ref b b 5 test.t1.a 2 -2 SUBQUERY t1 ALL NULL NULL NULL NULL 3 Using where +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 3 Using where select * from t2 where b in (select a from t1); a b 1 1 @@ -68,7 +68,7 @@ explain select * from t3 where b in (select a from t1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t3 ALL b NULL NULL NULL 20 1 PRIMARY eq_ref distinct_key distinct_key 5 func 1 -2 SUBQUERY t1 ALL NULL NULL NULL NULL 3 +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 3 select * from t3 where b in (select a from t1); a b pk1 pk2 pk3 1 1 1 1 1 @@ -94,7 +94,7 @@ explain select * from t3 where b in (select a from t0); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL distinct_key NULL NULL NULL 10 1 PRIMARY t3 ref b b 5 test.t0.a 1 -2 SUBQUERY t0 ALL NULL NULL NULL NULL 10 Using where +2 MATERIALIZED t0 ALL NULL NULL NULL NULL 10 Using where set @save_ecp= @@engine_condition_pushdown; set engine_condition_pushdown=0; select * from t3 where b in (select A.a+B.a from t0 A, t0 B where B.a<5); @@ -148,7 +148,7 @@ from t1 ot where a in (select a from t2 it); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL distinct_key NULL NULL NULL 22 1 PRIMARY ot ALL NULL NULL NULL NULL 32 Using where; Using join buffer (flat, BNL join) -2 SUBQUERY it ALL NULL NULL NULL NULL 22 +2 MATERIALIZED it ALL NULL NULL NULL NULL 22 select a, mid(filler1, 1,10), length(filler1)=length(filler2) as Z from t1 ot where a in (select a from t2 it); @@ -181,7 +181,7 @@ from t2 ot where a in (select a from t1 it); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ot ALL NULL NULL NULL NULL 22 1 PRIMARY eq_ref distinct_key distinct_key 5 func 1 -2 SUBQUERY it ALL NULL NULL NULL NULL 32 +2 MATERIALIZED it ALL NULL NULL NULL NULL 32 select a, mid(filler1, 1,10), length(filler1)=length(filler2) from t2 ot where a in (select a from t1 it); @@ -216,7 +216,7 @@ from t1 ot where a in (select a from t2 it); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL distinct_key NULL NULL NULL 22 1 PRIMARY ot ALL NULL NULL NULL NULL 52 Using where; Using join buffer (flat, BNL join) -2 SUBQUERY it ALL NULL NULL NULL NULL 22 +2 MATERIALIZED it ALL NULL NULL NULL NULL 22 select a, mid(filler1, 1,10), length(filler1)=length(filler2) as Z from t1 ot where a in (select a from t2 it); @@ -249,7 +249,7 @@ from t2 ot where a in (select a from t1 it); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ot ALL NULL NULL NULL NULL 22 1 PRIMARY eq_ref distinct_key distinct_key 5 func 1 -2 SUBQUERY it ALL NULL NULL NULL NULL 52 +2 MATERIALIZED it ALL NULL NULL NULL NULL 52 select a, mid(filler1, 1,10), length(filler1)=length(filler2) from t2 ot where a in (select a from t1 it); @@ -290,9 +290,9 @@ from t0 where a in id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t0 ALL NULL NULL NULL NULL 10 1 PRIMARY eq_ref distinct_key distinct_key 9 func 1 Using where -2 SUBQUERY t1 index a a 5 NULL 10 Using where; Using index -2 SUBQUERY t2 ref a a 5 test.t1.a 1 Using index -2 SUBQUERY t3 ref a a 5 test.t1.a 1 Using index +2 MATERIALIZED t1 index a a 5 NULL 10 Using where; Using index +2 MATERIALIZED t2 ref a a 5 test.t1.a 1 Using index +2 MATERIALIZED t3 ref a a 5 test.t1.a 1 Using index drop table t0, t1,t2,t3; CREATE TABLE t1 ( ID int(11) NOT NULL auto_increment, @@ -370,7 +370,7 @@ SELECT t2.CountryCode FROM t2 WHERE Population > 5000000); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL PRIMARY NULL NULL NULL 31 1 PRIMARY eq_ref distinct_key distinct_key 3 func 1 -2 SUBQUERY t2 ALL CountryCode NULL NULL NULL 545 Using where +2 MATERIALIZED t2 ALL CountryCode NULL NULL NULL 545 Using where SELECT Name FROM t1 WHERE t1.Code IN ( SELECT t2.CountryCode FROM t2 WHERE Population > 5000000); @@ -605,7 +605,7 @@ select * from t1 left join t2 on (t2.a= t1.a and t2.a in (select pk from t3)); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 1 PRIMARY t2 ALL NULL NULL NULL NULL 3 Using where -2 SUBQUERY t3 index PRIMARY PRIMARY 4 NULL 10 Using index +2 MATERIALIZED t3 index PRIMARY PRIMARY 4 NULL 10 Using index drop table t0, t1, t2, t3; create table t1 (a int); insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); @@ -719,7 +719,7 @@ explain select count(a) from t2 where a in ( SELECT a FROM t3); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 index a a 5 NULL 1000 Using index 1 PRIMARY eq_ref distinct_key distinct_key 5 func 1 -2 SUBQUERY t3 index a a 5 NULL 30000 Using index +2 MATERIALIZED t3 index a a 5 NULL 30000 Using index select count(a) from t2 where a in ( SELECT a FROM t3); count(a) 1000 @@ -878,7 +878,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 ALL NULL NULL NULL NULL 1 Using where 1 PRIMARY ALL NULL NULL NULL NULL 2 1 PRIMARY eq_ref distinct_key distinct_key 5 func 1 -2 SUBQUERY t4 ALL NULL NULL NULL NULL 2 +2 MATERIALIZED t4 ALL NULL NULL NULL NULL 2 3 DERIVED t1 ALL NULL NULL NULL NULL 1 SELECT * FROM t3 LEFT JOIN (v1,t2) ON t3.a = t2.a WHERE t3.b IN (SELECT b FROM t4); diff --git a/mysql-test/r/subselect_sj2_jcl6.result b/mysql-test/r/subselect_sj2_jcl6.result index 32d8d245477..0f990d44545 100644 --- a/mysql-test/r/subselect_sj2_jcl6.result +++ b/mysql-test/r/subselect_sj2_jcl6.result @@ -57,7 +57,7 @@ explain select * from t2 where b in (select a from t1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL distinct_key NULL NULL NULL 3 1 PRIMARY t2 ref b b 5 test.t1.a 2 Using join buffer (flat, BKA join); Key-ordered Rowid-ordered scan -2 SUBQUERY t1 ALL NULL NULL NULL NULL 3 Using where +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 3 Using where select * from t2 where b in (select a from t1); a b 1 1 @@ -77,7 +77,7 @@ explain select * from t3 where b in (select a from t1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t3 ALL b NULL NULL NULL 20 1 PRIMARY eq_ref distinct_key distinct_key 5 func 1 -2 SUBQUERY t1 ALL NULL NULL NULL NULL 3 +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 3 select * from t3 where b in (select a from t1); a b pk1 pk2 pk3 1 1 1 1 1 @@ -103,7 +103,7 @@ explain select * from t3 where b in (select a from t0); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL distinct_key NULL NULL NULL 10 1 PRIMARY t3 ref b b 5 test.t0.a 1 Using join buffer (flat, BKA join); Key-ordered Rowid-ordered scan -2 SUBQUERY t0 ALL NULL NULL NULL NULL 10 Using where +2 MATERIALIZED t0 ALL NULL NULL NULL NULL 10 Using where set @save_ecp= @@engine_condition_pushdown; set engine_condition_pushdown=0; select * from t3 where b in (select A.a+B.a from t0 A, t0 B where B.a<5); @@ -157,7 +157,7 @@ from t1 ot where a in (select a from t2 it); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL distinct_key NULL NULL NULL 22 1 PRIMARY ot hash_ALL NULL #hash#$hj 5 test.it.a 32 Using where; Using join buffer (flat, BNLH join) -2 SUBQUERY it ALL NULL NULL NULL NULL 22 Using where +2 MATERIALIZED it ALL NULL NULL NULL NULL 22 Using where select a, mid(filler1, 1,10), length(filler1)=length(filler2) as Z from t1 ot where a in (select a from t2 it); @@ -190,7 +190,7 @@ from t2 ot where a in (select a from t1 it); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ot ALL NULL NULL NULL NULL 22 1 PRIMARY eq_ref distinct_key distinct_key 5 func 1 -2 SUBQUERY it ALL NULL NULL NULL NULL 32 +2 MATERIALIZED it ALL NULL NULL NULL NULL 32 select a, mid(filler1, 1,10), length(filler1)=length(filler2) from t2 ot where a in (select a from t1 it); @@ -225,7 +225,7 @@ from t1 ot where a in (select a from t2 it); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL distinct_key NULL NULL NULL 22 1 PRIMARY ot hash_ALL NULL #hash#$hj 5 test.it.a 52 Using where; Using join buffer (flat, BNLH join) -2 SUBQUERY it ALL NULL NULL NULL NULL 22 Using where +2 MATERIALIZED it ALL NULL NULL NULL NULL 22 Using where select a, mid(filler1, 1,10), length(filler1)=length(filler2) as Z from t1 ot where a in (select a from t2 it); @@ -258,7 +258,7 @@ from t2 ot where a in (select a from t1 it); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ot ALL NULL NULL NULL NULL 22 1 PRIMARY eq_ref distinct_key distinct_key 5 func 1 -2 SUBQUERY it ALL NULL NULL NULL NULL 52 +2 MATERIALIZED it ALL NULL NULL NULL NULL 52 select a, mid(filler1, 1,10), length(filler1)=length(filler2) from t2 ot where a in (select a from t1 it); @@ -299,9 +299,9 @@ from t0 where a in id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t0 ALL NULL NULL NULL NULL 10 1 PRIMARY eq_ref distinct_key distinct_key 9 func 1 Using where -2 SUBQUERY t1 index a a 5 NULL 10 Using where; Using index -2 SUBQUERY t2 ref a a 5 test.t1.a 1 Using index -2 SUBQUERY t3 ref a a 5 test.t1.a 1 Using index +2 MATERIALIZED t1 index a a 5 NULL 10 Using where; Using index +2 MATERIALIZED t2 ref a a 5 test.t1.a 1 Using index +2 MATERIALIZED t3 ref a a 5 test.t1.a 1 Using index drop table t0, t1,t2,t3; CREATE TABLE t1 ( ID int(11) NOT NULL auto_increment, @@ -379,7 +379,7 @@ SELECT t2.CountryCode FROM t2 WHERE Population > 5000000); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL PRIMARY NULL NULL NULL 31 1 PRIMARY eq_ref distinct_key distinct_key 3 func 1 -2 SUBQUERY t2 ALL CountryCode NULL NULL NULL 545 Using where +2 MATERIALIZED t2 ALL CountryCode NULL NULL NULL 545 Using where SELECT Name FROM t1 WHERE t1.Code IN ( SELECT t2.CountryCode FROM t2 WHERE Population > 5000000); @@ -616,7 +616,7 @@ select * from t1 left join t2 on (t2.a= t1.a and t2.a in (select pk from t3)); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 1 PRIMARY t2 hash_ALL NULL #hash#$hj 5 test.t1.a 3 Using where; Using join buffer (flat, BNLH join) -2 SUBQUERY t3 index PRIMARY PRIMARY 4 NULL 10 Using index +2 MATERIALIZED t3 index PRIMARY PRIMARY 4 NULL 10 Using index drop table t0, t1, t2, t3; create table t1 (a int); insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); @@ -730,7 +730,7 @@ explain select count(a) from t2 where a in ( SELECT a FROM t3); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 index a a 5 NULL 1000 Using index 1 PRIMARY eq_ref distinct_key distinct_key 5 func 1 -2 SUBQUERY t3 index a a 5 NULL 30000 Using index +2 MATERIALIZED t3 index a a 5 NULL 30000 Using index select count(a) from t2 where a in ( SELECT a FROM t3); count(a) 1000 @@ -889,7 +889,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 hash_ALL NULL #hash#$hj 5 test.t3.a 1 Using where; Using join buffer (flat, BNLH join) 1 PRIMARY ALL NULL NULL NULL NULL 2 Using join buffer (incremental, BNL join) 1 PRIMARY eq_ref distinct_key distinct_key 5 func 1 -2 SUBQUERY t4 ALL NULL NULL NULL NULL 2 +2 MATERIALIZED t4 ALL NULL NULL NULL NULL 2 3 DERIVED t1 ALL NULL NULL NULL NULL 1 SELECT * FROM t3 LEFT JOIN (v1,t2) ON t3.a = t2.a WHERE t3.b IN (SELECT b FROM t4); diff --git a/mysql-test/r/subselect_sj2_mat.result b/mysql-test/r/subselect_sj2_mat.result index 4a61266a317..6f3e1de4113 100644 --- a/mysql-test/r/subselect_sj2_mat.result +++ b/mysql-test/r/subselect_sj2_mat.result @@ -50,7 +50,7 @@ explain select * from t2 where b in (select a from t1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL distinct_key NULL NULL NULL 3 1 PRIMARY t2 ref b b 5 test.t1.a 2 -2 SUBQUERY t1 ALL NULL NULL NULL NULL 3 Using where +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 3 Using where select * from t2 where b in (select a from t1); a b 1 1 @@ -70,7 +70,7 @@ explain select * from t3 where b in (select a from t1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t3 ALL b NULL NULL NULL 20 1 PRIMARY eq_ref distinct_key distinct_key 5 func 1 -2 SUBQUERY t1 ALL NULL NULL NULL NULL 3 +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 3 select * from t3 where b in (select a from t1); a b pk1 pk2 pk3 1 1 1 1 1 @@ -96,7 +96,7 @@ explain select * from t3 where b in (select a from t0); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL distinct_key NULL NULL NULL 10 1 PRIMARY t3 ref b b 5 test.t0.a 1 -2 SUBQUERY t0 ALL NULL NULL NULL NULL 10 Using where +2 MATERIALIZED t0 ALL NULL NULL NULL NULL 10 Using where set @save_ecp= @@engine_condition_pushdown; set engine_condition_pushdown=0; select * from t3 where b in (select A.a+B.a from t0 A, t0 B where B.a<5); @@ -150,7 +150,7 @@ from t1 ot where a in (select a from t2 it); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL distinct_key NULL NULL NULL 22 1 PRIMARY ot ALL NULL NULL NULL NULL 32 Using where; Using join buffer (flat, BNL join) -2 SUBQUERY it ALL NULL NULL NULL NULL 22 +2 MATERIALIZED it ALL NULL NULL NULL NULL 22 select a, mid(filler1, 1,10), length(filler1)=length(filler2) as Z from t1 ot where a in (select a from t2 it); @@ -183,7 +183,7 @@ from t2 ot where a in (select a from t1 it); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ot ALL NULL NULL NULL NULL 22 1 PRIMARY eq_ref distinct_key distinct_key 5 func 1 -2 SUBQUERY it ALL NULL NULL NULL NULL 32 +2 MATERIALIZED it ALL NULL NULL NULL NULL 32 select a, mid(filler1, 1,10), length(filler1)=length(filler2) from t2 ot where a in (select a from t1 it); @@ -218,7 +218,7 @@ from t1 ot where a in (select a from t2 it); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL distinct_key NULL NULL NULL 22 1 PRIMARY ot ALL NULL NULL NULL NULL 52 Using where; Using join buffer (flat, BNL join) -2 SUBQUERY it ALL NULL NULL NULL NULL 22 +2 MATERIALIZED it ALL NULL NULL NULL NULL 22 select a, mid(filler1, 1,10), length(filler1)=length(filler2) as Z from t1 ot where a in (select a from t2 it); @@ -251,7 +251,7 @@ from t2 ot where a in (select a from t1 it); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ot ALL NULL NULL NULL NULL 22 1 PRIMARY eq_ref distinct_key distinct_key 5 func 1 -2 SUBQUERY it ALL NULL NULL NULL NULL 52 +2 MATERIALIZED it ALL NULL NULL NULL NULL 52 select a, mid(filler1, 1,10), length(filler1)=length(filler2) from t2 ot where a in (select a from t1 it); @@ -292,9 +292,9 @@ from t0 where a in id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t0 ALL NULL NULL NULL NULL 10 1 PRIMARY eq_ref distinct_key distinct_key 9 func 1 Using where -2 SUBQUERY t1 index a a 5 NULL 10 Using where; Using index -2 SUBQUERY t2 ref a a 5 test.t1.a 1 Using index -2 SUBQUERY t3 ref a a 5 test.t1.a 1 Using index +2 MATERIALIZED t1 index a a 5 NULL 10 Using where; Using index +2 MATERIALIZED t2 ref a a 5 test.t1.a 1 Using index +2 MATERIALIZED t3 ref a a 5 test.t1.a 1 Using index drop table t0, t1,t2,t3; CREATE TABLE t1 ( ID int(11) NOT NULL auto_increment, @@ -372,7 +372,7 @@ SELECT t2.CountryCode FROM t2 WHERE Population > 5000000); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL PRIMARY NULL NULL NULL 31 1 PRIMARY eq_ref distinct_key distinct_key 3 func 1 -2 SUBQUERY t2 ALL CountryCode NULL NULL NULL 545 Using where +2 MATERIALIZED t2 ALL CountryCode NULL NULL NULL 545 Using where SELECT Name FROM t1 WHERE t1.Code IN ( SELECT t2.CountryCode FROM t2 WHERE Population > 5000000); @@ -607,7 +607,7 @@ select * from t1 left join t2 on (t2.a= t1.a and t2.a in (select pk from t3)); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 1 PRIMARY t2 ALL NULL NULL NULL NULL 3 Using where -2 SUBQUERY t3 index PRIMARY PRIMARY 4 NULL 10 Using index +2 MATERIALIZED t3 index PRIMARY PRIMARY 4 NULL 10 Using index drop table t0, t1, t2, t3; create table t1 (a int); insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); @@ -721,7 +721,7 @@ explain select count(a) from t2 where a in ( SELECT a FROM t3); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 index a a 5 NULL 1000 Using index 1 PRIMARY eq_ref distinct_key distinct_key 5 func 1 -2 SUBQUERY t3 index a a 5 NULL 30000 Using index +2 MATERIALIZED t3 index a a 5 NULL 30000 Using index select count(a) from t2 where a in ( SELECT a FROM t3); count(a) 1000 @@ -880,7 +880,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 ALL NULL NULL NULL NULL 1 Using where 1 PRIMARY ALL NULL NULL NULL NULL 2 1 PRIMARY eq_ref distinct_key distinct_key 5 func 1 -2 SUBQUERY t4 ALL NULL NULL NULL NULL 2 +2 MATERIALIZED t4 ALL NULL NULL NULL NULL 2 3 DERIVED t1 ALL NULL NULL NULL NULL 1 SELECT * FROM t3 LEFT JOIN (v1,t2) ON t3.a = t2.a WHERE t3.b IN (SELECT b FROM t4); diff --git a/mysql-test/r/subselect_sj_jcl6.result b/mysql-test/r/subselect_sj_jcl6.result index 68a130b04bf..03940e0e5eb 100644 --- a/mysql-test/r/subselect_sj_jcl6.result +++ b/mysql-test/r/subselect_sj_jcl6.result @@ -90,7 +90,7 @@ id select_type tABle type possiBle_keys key key_len ref rows filtered ExtrA 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 1 PRIMARY A ALL NULL NULL NULL NULL 3 100.00 Using where; Using join Buffer (flAt, BNL join) 1 PRIMARY B ALL NULL NULL NULL NULL 3 100.00 Using where; Using join Buffer (incrementAl, BNL join) -2 SUBQUERY t10 index PRIMARY PRIMARY 4 NULL 10 100.00 Using index +2 MATERIALIZED t10 index PRIMARY PRIMARY 4 NULL 10 100.00 Using index Warnings: Note 1003 select `test`.`t1`.`A` AS `A`,`test`.`t1`.`B` AS `B`,`test`.`A`.`A` AS `A`,`test`.`A`.`B` AS `B`,`test`.`B`.`A` AS `A`,`test`.`B`.`B` AS `B` from `test`.`t1` left join (`test`.`t2` `A` join `test`.`t2` `B`) on(((`test`.`B`.`A`,`test`.`B`.`A` in ( (select `test`.`t10`.`pk` from `test`.`t10` ), (`test`.`B`.`A` in on distinct_key where ((`test`.`B`.`A` = ``.`pk`))))) And (`test`.`A`.`A` = `test`.`t1`.`A`))) where 1 t2 should be wrapped into OJ-nest, so we have "t1 LJ (t2 J t10)" @@ -99,7 +99,7 @@ select * from t1 left join t2 on (t2.A= t1.A And t2.A in (select pk from t10)); id select_type tABle type possiBle_keys key key_len ref rows filtered ExtrA 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 1 PRIMARY t2 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join Buffer (flAt, BNL join) -2 SUBQUERY t10 index PRIMARY PRIMARY 4 NULL 10 100.00 Using index +2 MATERIALIZED t10 index PRIMARY PRIMARY 4 NULL 10 100.00 Using index Warnings: Note 1003 select `test`.`t1`.`A` AS `A`,`test`.`t1`.`B` AS `B`,`test`.`t2`.`A` AS `A`,`test`.`t2`.`B` AS `B` from `test`.`t1` left join `test`.`t2` on(((`test`.`t2`.`A`,`test`.`t2`.`A` in ( (select `test`.`t10`.`pk` from `test`.`t10` ), (`test`.`t2`.`A` in on distinct_key where ((`test`.`t2`.`A` = ``.`pk`))))) And (`test`.`t2`.`A` = `test`.`t1`.`A`))) where 1 we shouldn't flatten if we're going to get a join of > MAX_TABLES. @@ -737,8 +737,8 @@ FROM it1 LEFT JOIN it2 ON it2.datetime_key); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL distinct_key NULL NULL NULL 11 1 PRIMARY ot1 ALL NULL NULL NULL NULL 20 Using where; Using join buffer (flat, BNL join) -2 SUBQUERY it1 index NULL int_key 4 NULL 2 Using index -2 SUBQUERY it2 ALL int_key,datetime_key NULL NULL NULL 20 Using where; Using join buffer (flat, BNL join) +2 MATERIALIZED it1 index NULL int_key 4 NULL 2 Using index +2 MATERIALIZED it2 ALL int_key,datetime_key NULL NULL NULL 20 Using where; Using join buffer (flat, BNL join) DROP TABLE ot1, it1, it2; # End of BUG#38075 # @@ -811,7 +811,7 @@ EXPLAIN EXTENDED SELECT pk FROM t1 WHERE (a, b) IN (SELECT a, b FROM t2 WHERE pk 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 1 PRIMARY eq_ref distinct_key distinct_key 13 func,func 1 100.00 -2 SUBQUERY t2 range PRIMARY PRIMARY 4 NULL 2 100.00 Using index condition; Rowid-ordered scan +2 MATERIALIZED t2 range PRIMARY PRIMARY 4 NULL 2 100.00 Using index condition; Rowid-ordered scan Warnings: Note 1003 select `test`.`t1`.`pk` AS `pk` from `test`.`t1` semi join (`test`.`t2`) where ((`test`.`t2`.`pk` > 0)) SELECT pk FROM t1 WHERE (a, b) IN (SELECT a, b FROM t2 WHERE pk > 0); @@ -980,7 +980,7 @@ WHERE `varchar_nokey` < 'n' XOR `pk` ) ; id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 ALL NULL NULL NULL NULL 18 100.00 1 PRIMARY eq_ref distinct_key distinct_key 8 func,func 1 100.00 -2 SUBQUERY t1 ALL varchar_key NULL NULL NULL 15 100.00 Using where +2 MATERIALIZED t1 ALL varchar_key NULL NULL NULL 15 100.00 Using where Warnings: Note 1003 select `test`.`t2`.`varchar_nokey` AS `varchar_nokey` from `test`.`t2` semi join (`test`.`t1`) where ((`test`.`t1`.`varchar_nokey` = `test`.`t1`.`varchar_key`) and ((`test`.`t1`.`varchar_key` < 'n') xor `test`.`t1`.`pk`)) SELECT varchar_nokey @@ -1063,8 +1063,8 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 5 1 PRIMARY eq_ref distinct_key distinct_key 14 func 1 1 PRIMARY eq_ref distinct_key distinct_key 14 func 1 -3 SUBQUERY t3 ALL NULL NULL NULL NULL 5 Using where -2 SUBQUERY t2 ALL NULL NULL NULL NULL 6 Using where +3 MATERIALIZED t3 ALL NULL NULL NULL NULL 5 Using where +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 6 Using where SELECT * FROM t1 WHERE t1.val IN (SELECT t2.val FROM t2 @@ -1286,8 +1286,8 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY eq_ref distinct_key distinct_key 5 func 1 1 PRIMARY B ALL NULL NULL NULL NULL 3 Using where; Using join buffer (flat, BNL join) 1 PRIMARY eq_ref distinct_key distinct_key 5 func 1 -2 SUBQUERY C ALL NULL NULL NULL NULL 3 -3 SUBQUERY D ALL NULL NULL NULL NULL 3 +2 MATERIALIZED C ALL NULL NULL NULL NULL 3 +3 MATERIALIZED D ALL NULL NULL NULL NULL 3 drop table t1, t2; # # BUG#784441: Abort on semijoin with a view as the inner table @@ -1302,7 +1302,7 @@ SELECT * FROM t1 INNER JOIN t2 ON t2.a != 0 AND t2.a IN (SELECT * FROM v1); 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; Using join buffer (flat, BNL join) -2 SUBQUERY system NULL NULL NULL NULL 1 +2 MATERIALIZED system NULL NULL NULL NULL 1 3 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used SELECT * FROM t1 INNER JOIN t2 ON t2.a != 0 AND t2.a IN (SELECT * FROM v1); a a @@ -1397,8 +1397,8 @@ explain select * from t3 where t3.b in (select t2.b from t1 left join t2 on t1.a id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL distinct_key NULL NULL NULL 2 1 PRIMARY t3 ALL NULL NULL NULL NULL 8 Using where; Using join buffer (flat, BNL join) -2 SUBQUERY t1 ALL NULL NULL NULL NULL 2 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 2 Using where; Using join buffer (flat, BNL join) +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 2 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 Using where; Using join buffer (flat, BNL join) select * from t3 where t3.b in (select t2.b from t1 left join t2 on t1.a=t2.a); b drop table t1, t2, t3; @@ -2001,8 +2001,8 @@ SELECT * FROM t1 WHERE (a) IN (SELECT a FROM t2 JOIN t3 ON b = a); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 9 1 PRIMARY eq_ref distinct_key distinct_key 5 func 1 -2 SUBQUERY t3 ALL NULL NULL NULL NULL 13 Using where -2 SUBQUERY t2 ref b b 4 test.t3.a 1 Using index +2 MATERIALIZED t3 ALL NULL NULL NULL NULL 13 Using where +2 MATERIALIZED t2 ref b b 4 test.t3.a 1 Using index SELECT * FROM t1 WHERE (a) IN (SELECT a FROM t2 JOIN t3 ON b = a); a 19 diff --git a/mysql-test/r/subselect_sj_mat.result b/mysql-test/r/subselect_sj_mat.result index 472cadf04c4..b578749b862 100644 --- a/mysql-test/r/subselect_sj_mat.result +++ b/mysql-test/r/subselect_sj_mat.result @@ -46,7 +46,7 @@ select * from t1 where a1 in (select b1 from t2 where b1 > '0'); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 1 PRIMARY eq_ref distinct_key distinct_key 9 func 1 100.00 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 5 100.00 Using where +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 5 100.00 Using where Warnings: Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` semi join (`test`.`t2`) where ((`test`.`t2`.`b1` > '0')) select * from t1 where a1 in (select b1 from t2 where b1 > '0'); @@ -58,7 +58,7 @@ select * from t1 where a1 in (select b1 from t2 where b1 > '0' group by b1); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where 1 PRIMARY eq_ref distinct_key distinct_key 9 test.t1.a1 1 100.00 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 5 100.00 Using where; Using temporary +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 5 100.00 Using where; Using temporary Warnings: Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from (select `test`.`t2`.`b1` from `test`.`t2` where (`test`.`t2`.`b1` > '0') group by `test`.`t2`.`b1`) join `test`.`t1` where (``.`b1` = `test`.`t1`.`a1`) select * from t1 where a1 in (select b1 from t2 where b1 > '0' group by b1); @@ -70,7 +70,7 @@ select * from t1 where (a1, a2) in (select b1, b2 from t2 where b1 > '0' group b id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where 1 PRIMARY eq_ref distinct_key distinct_key 18 test.t1.a1,test.t1.a2 1 100.00 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 5 100.00 Using where; Using temporary +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 5 100.00 Using where; Using temporary Warnings: Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from (select `test`.`t2`.`b1`,`test`.`t2`.`b2` from `test`.`t2` where (`test`.`t2`.`b1` > '0') group by `test`.`t2`.`b1`,`test`.`t2`.`b2`) join `test`.`t1` where ((``.`b2` = `test`.`t1`.`a2`) and (``.`b1` = `test`.`t1`.`a1`)) select * from t1 where (a1, a2) in (select b1, b2 from t2 where b1 > '0' group by b1, b2); @@ -82,7 +82,7 @@ select * from t1 where (a1, a2) in (select b1, min(b2) from t2 where b1 > '0' gr id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where 1 PRIMARY eq_ref distinct_key distinct_key 18 test.t1.a1,test.t1.a2 1 100.00 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 5 100.00 Using where; Using temporary +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 5 100.00 Using where; Using temporary Warnings: Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from (select `test`.`t2`.`b1`,min(`test`.`t2`.`b2`) from `test`.`t2` where (`test`.`t2`.`b1` > '0') group by `test`.`t2`.`b1`) join `test`.`t1` where ((``.`min(b2)` = `test`.`t1`.`a2`) and (``.`b1` = `test`.`t1`.`a1`)) select * from t1 where (a1, a2) in (select b1, min(b2) from t2 where b1 > '0' group by b1); @@ -105,7 +105,7 @@ select * from t1i where a1 in (select b1 from t2i where b1 > '0' group by b1); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY ALL distinct_key # NULL # 3 100.00 # 1 PRIMARY t1i ref it1i1,it1i3 # 9 # 1 100.00 # -2 SUBQUERY t2i range it2i1,it2i3 # 9 # 3 100.00 # +2 MATERIALIZED t2i range it2i1,it2i3 # 9 # 3 100.00 # Warnings: Note 1003 select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from (select `test`.`t2i`.`b1` from `test`.`t2i` where (`test`.`t2i`.`b1` > '0') group by `test`.`t2i`.`b1`) join `test`.`t1i` where (`test`.`t1i`.`a1` = ``.`b1`) select * from t1i where a1 in (select b1 from t2i where b1 > '0' group by b1); @@ -128,7 +128,7 @@ select * from t1i where (a1, a2) in (select b1, b2 from t2i where b1 > '0' group id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1i index it1i1,it1i2,it1i3 # # # 3 100.00 # 1 PRIMARY eq_ref distinct_key # # # 1 100.00 # -2 SUBQUERY t2i range it2i1,it2i3 # # # 3 100.00 # +2 MATERIALIZED t2i range it2i1,it2i3 # # # 3 100.00 # Warnings: Note 1003 select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from (select `test`.`t2i`.`b1`,`test`.`t2i`.`b2` from `test`.`t2i` where (`test`.`t2i`.`b1` > '0') group by `test`.`t2i`.`b1`,`test`.`t2i`.`b2`) join `test`.`t1i` where ((``.`b2` = `test`.`t1i`.`a2`) and (``.`b1` = `test`.`t1i`.`a1`)) select * from t1i where (a1, a2) in (select b1, b2 from t2i where b1 > '0' group by b1, b2); @@ -140,7 +140,7 @@ select * from t1i where (a1, a2) in (select b1, min(b2) from t2i where b1 > '0' id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1i index it1i1,it1i2,it1i3 # # # 3 100.00 # 1 PRIMARY eq_ref distinct_key # # # 1 100.00 # -2 SUBQUERY t2i range it2i1,it2i3 # # # 3 100.00 # +2 MATERIALIZED t2i range it2i1,it2i3 # # # 3 100.00 # Warnings: Note 1003 select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from (select `test`.`t2i`.`b1`,min(`test`.`t2i`.`b2`) from `test`.`t2i` where (`test`.`t2i`.`b1` > '0') group by `test`.`t2i`.`b1`) join `test`.`t1i` where ((``.`min(b2)` = `test`.`t1i`.`a2`) and (``.`b1` = `test`.`t1i`.`a1`)) select * from t1i where (a1, a2) in (select b1, min(b2) from t2i where b1 > '0' group by b1); @@ -152,7 +152,7 @@ select * from t1 where (a1, a2) in (select b1, max(b2) from t2i group by b1); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where 1 PRIMARY eq_ref distinct_key distinct_key 18 test.t1.a1,test.t1.a2 1 100.00 -2 SUBQUERY t2i range NULL it2i3 9 NULL 3 100.00 Using index for group-by +2 MATERIALIZED t2i range NULL it2i3 9 NULL 3 100.00 Using index for group-by Warnings: Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from (select `test`.`t2i`.`b1`,max(`test`.`t2i`.`b2`) from `test`.`t2i` group by `test`.`t2i`.`b1`) join `test`.`t1` where ((``.`max(b2)` = `test`.`t1`.`a2`) and (``.`b1` = `test`.`t1`.`a1`)) select * from t1 where (a1, a2) in (select b1, max(b2) from t2i group by b1); @@ -164,12 +164,12 @@ execute st1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where 1 PRIMARY eq_ref distinct_key distinct_key 18 test.t1.a1,test.t1.a2 1 -2 SUBQUERY t2i range NULL it2i3 9 NULL 3 Using index for group-by +2 MATERIALIZED t2i range NULL it2i3 9 NULL 3 Using index for group-by execute st1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where 1 PRIMARY eq_ref distinct_key distinct_key 18 test.t1.a1,test.t1.a2 1 -2 SUBQUERY t2i range NULL it2i3 9 NULL 3 Using index for group-by +2 MATERIALIZED t2i range NULL it2i3 9 NULL 3 Using index for group-by prepare st2 from "select * from t1 where (a1, a2) in (select b1, max(b2) from t2i group by b1)"; execute st2; a1 a2 @@ -184,7 +184,7 @@ select * from t1 where (a1, a2) in (select b1, min(b2) from t2i where b1 > '0' g id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where 1 PRIMARY eq_ref distinct_key distinct_key 18 test.t1.a1,test.t1.a2 1 100.00 -2 SUBQUERY t2i range it2i1,it2i3 it2i3 18 NULL 3 100.00 Using where; Using index for group-by +2 MATERIALIZED t2i range it2i1,it2i3 it2i3 18 NULL 3 100.00 Using where; Using index for group-by Warnings: Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from (select `test`.`t2i`.`b1`,min(`test`.`t2i`.`b2`) from `test`.`t2i` where (`test`.`t2i`.`b1` > '0') group by `test`.`t2i`.`b1`) join `test`.`t1` where ((``.`min(b2)` = `test`.`t1`.`a2`) and (``.`b1` = `test`.`t1`.`a1`)) select * from t1 where (a1, a2) in (select b1, min(b2) from t2i where b1 > '0' group by b1); @@ -232,7 +232,7 @@ select * from t1 where (a1, a2) in (select b1, b2 from t2 order by b1, b2); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where 1 PRIMARY eq_ref distinct_key distinct_key 18 test.t1.a1,test.t1.a2 1 100.00 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 5 100.00 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 5 100.00 Warnings: Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from (select `test`.`t2`.`b1`,`test`.`t2`.`b2` from `test`.`t2` order by `test`.`t2`.`b1`,`test`.`t2`.`b2`) join `test`.`t1` where ((``.`b2` = `test`.`t1`.`a2`) and (``.`b1` = `test`.`t1`.`a1`)) select * from t1 where (a1, a2) in (select b1, b2 from t2 order by b1, b2); @@ -244,7 +244,7 @@ select * from t1i where (a1, a2) in (select b1, b2 from t2i order by b1, b2); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1i index it1i1,it1i2,it1i3 it1i3 18 NULL 3 100.00 Using where; Using index 1 PRIMARY eq_ref distinct_key distinct_key 18 test.t1i.a1,test.t1i.a2 1 100.00 -2 SUBQUERY t2i index NULL it2i3 18 NULL 5 100.00 Using index +2 MATERIALIZED t2i index NULL it2i3 18 NULL 5 100.00 Using index Warnings: Note 1003 select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from (select `test`.`t2i`.`b1`,`test`.`t2i`.`b2` from `test`.`t2i` order by `test`.`t2i`.`b1`,`test`.`t2i`.`b2`) join `test`.`t1i` where ((``.`b2` = `test`.`t1i`.`a2`) and (``.`b1` = `test`.`t1i`.`a1`)) select * from t1i where (a1, a2) in (select b1, b2 from t2i order by b1, b2); @@ -299,9 +299,9 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 1 PRIMARY eq_ref distinct_key distinct_key 18 func,func 1 100.00 1 PRIMARY eq_ref distinct_key distinct_key 18 func,func 1 100.00 -3 SUBQUERY t3 ALL NULL NULL NULL NULL 4 100.00 Using where -3 SUBQUERY t2i index it2i1,it2i2,it2i3 it2i3 18 NULL 5 80.00 Using where; Using index; Using join buffer (flat, BNL join) -2 SUBQUERY t2 ALL NULL NULL NULL NULL 5 100.00 Using where +3 MATERIALIZED t3 ALL NULL NULL NULL NULL 4 100.00 Using where +3 MATERIALIZED t2i index it2i1,it2i2,it2i3 it2i3 18 NULL 5 80.00 Using where; Using index; Using join buffer (flat, BNL join) +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 5 100.00 Using where Warnings: Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` semi join (`test`.`t2`) semi join (`test`.`t2i` join `test`.`t3`) where ((`test`.`t2i`.`b2` = `test`.`t3`.`c2`) and (`test`.`t2i`.`b1` = `test`.`t3`.`c1`) and (`test`.`t2`.`b1` > '0') and (`test`.`t3`.`c2` > '0')) select * from t1 @@ -341,11 +341,11 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 1 PRIMARY eq_ref distinct_key distinct_key 18 func,func 1 100.00 1 PRIMARY eq_ref distinct_key distinct_key 18 func,func 1 100.00 -5 SUBQUERY t3 ALL NULL NULL NULL NULL 4 100.00 Using where -5 SUBQUERY t2i index it2i1,it2i2,it2i3 it2i3 18 NULL 5 80.00 Using where; Using index; Using join buffer (flat, BNL join) -2 SUBQUERY t2 ALL NULL NULL NULL NULL 5 100.00 Using where -4 SUBQUERY t3 ALL NULL NULL NULL NULL 4 100.00 Using where -3 SUBQUERY t3 ALL NULL NULL NULL NULL 4 100.00 Using where +5 MATERIALIZED t3 ALL NULL NULL NULL NULL 4 100.00 Using where +5 MATERIALIZED t2i index it2i1,it2i2,it2i3 it2i3 18 NULL 5 80.00 Using where; Using index; Using join buffer (flat, BNL join) +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 5 100.00 Using where +4 MATERIALIZED t3 ALL NULL NULL NULL NULL 4 100.00 Using where +3 MATERIALIZED t3 ALL NULL NULL NULL NULL 4 100.00 Using where Warnings: Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` semi join (`test`.`t2`) semi join (`test`.`t2i` join `test`.`t3`) where ((`test`.`t2i`.`b2` = `test`.`t3`.`c2`) and (`test`.`t2i`.`b1` = `test`.`t3`.`c1`) and (<`test`.`t2`.`b2`>((`test`.`t2`.`b2`,`test`.`t2`.`b2` in ( (select `test`.`t3`.`c2` from `test`.`t3` where (`test`.`t3`.`c2` like '%02') ), (`test`.`t2`.`b2` in on distinct_key where ((`test`.`t2`.`b2` = ``.`c2`)))))) or <`test`.`t2`.`b2`>((`test`.`t2`.`b2`,`test`.`t2`.`b2` in ( (select `test`.`t3`.`c2` from `test`.`t3` where (`test`.`t3`.`c2` like '%03') ), (`test`.`t2`.`b2` in on distinct_key where ((`test`.`t2`.`b2` = ``.`c2`))))))) and (`test`.`t3`.`c2` > '0')) select * from t1 @@ -367,9 +367,9 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 1 PRIMARY eq_ref distinct_key distinct_key 18 func,func 1 100.00 1 PRIMARY t2 ALL NULL NULL NULL NULL 5 100.00 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) -5 SUBQUERY t3c ALL NULL NULL NULL NULL 4 100.00 Using where -5 SUBQUERY t2i index it2i1,it2i2,it2i3 it2i3 18 NULL 5 80.00 Using where; Using index; Using join buffer (flat, BNL join) -4 SUBQUERY t3b ALL NULL NULL NULL NULL 4 100.00 Using where +5 MATERIALIZED t3c ALL NULL NULL NULL NULL 4 100.00 Using where +5 MATERIALIZED t2i index it2i1,it2i2,it2i3 it2i3 18 NULL 5 80.00 Using where; Using index; Using join buffer (flat, BNL join) +4 MATERIALIZED t3b ALL NULL NULL NULL NULL 4 100.00 Using where 3 DEPENDENT SUBQUERY t3a ALL NULL NULL NULL NULL 4 100.00 Using where Warnings: Note 1276 Field or reference 'test.t1.a1' of SELECT #3 was resolved in SELECT #1 @@ -401,9 +401,9 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL # # # 4 100.00 # 1 PRIMARY t1 ALL NULL # # # 3 100.00 # 1 PRIMARY t2i ref it2i1,it2i2,it2i3 # # # 2 100.00 # -2 SUBQUERY t2 ALL NULL # # # 5 100.00 # -4 SUBQUERY t3 ALL NULL # # # 4 100.00 # -3 SUBQUERY t3 ALL NULL # # # 4 100.00 # +2 MATERIALIZED t2 ALL NULL # # # 5 100.00 # +4 MATERIALIZED t3 ALL NULL # # # 4 100.00 # +3 MATERIALIZED t3 ALL NULL # # # 4 100.00 # 7 UNION t2i index it2i1,it2i2,it2i3 # # # 5 40.00 # 7 UNION t1i ref it1i1,it1i2,it1i3 # # # 1 100.00 # 7 UNION t3i ref it3i1,it3i2,it3i3 # # # 1 100.00 # @@ -434,8 +434,8 @@ where (c1, c2) in (select b1, b2 from t2i where b2 > '0')); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where 1 PRIMARY eq_ref distinct_key distinct_key 18 func,func 1 100.00 -4 SUBQUERY t3 ALL NULL NULL NULL NULL 4 100.00 Using where -4 SUBQUERY t2i index it2i1,it2i2,it2i3 it2i3 18 NULL 5 80.00 Using where; Using index; Using join buffer (flat, BNL join) +4 MATERIALIZED t3 ALL NULL NULL NULL NULL 4 100.00 Using where +4 MATERIALIZED t2i index it2i1,it2i2,it2i3 it2i3 18 NULL 5 80.00 Using where; Using index; Using join buffer (flat, BNL join) 2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 3 100.00 Using where 3 DEPENDENT UNION t2 ALL NULL NULL NULL NULL 5 100.00 Using where NULL UNION RESULT ALL NULL NULL NULL NULL NULL NULL @@ -458,8 +458,8 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where 1 PRIMARY t3 ALL NULL NULL NULL NULL 4 100.00 Using where; Using join buffer (flat, BNL join) 1 PRIMARY eq_ref distinct_key distinct_key 18 func,func 1 100.00 -4 SUBQUERY t3 ALL NULL NULL NULL NULL 4 100.00 Using where -4 SUBQUERY t2i index it2i1,it2i2,it2i3 it2i3 18 NULL 5 80.00 Using where; Using index; Using join buffer (flat, BNL join) +4 MATERIALIZED t3 ALL NULL NULL NULL NULL 4 100.00 Using where +4 MATERIALIZED t2i index it2i1,it2i2,it2i3 it2i3 18 NULL 5 80.00 Using where; Using index; Using join buffer (flat, BNL join) 2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 3 100.00 Using where 3 DEPENDENT UNION t2 ALL NULL NULL NULL NULL 5 100.00 Using where NULL UNION RESULT ALL NULL NULL NULL NULL NULL NULL @@ -505,7 +505,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 ALL NULL NULL NULL NULL 5 100.00 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) 1 PRIMARY t2i ref it2i1,it2i2,it2i3 it2i3 18 test.t1.a1,test.t1.a2 2 100.00 Using index; Start temporary 1 PRIMARY t3c ALL NULL NULL NULL NULL 4 100.00 Using where; End temporary; Using join buffer (flat, BNL join) -4 SUBQUERY t3b ALL NULL NULL NULL NULL 4 100.00 Using where +4 MATERIALIZED t3b ALL NULL NULL NULL NULL 4 100.00 Using where 3 DEPENDENT SUBQUERY t3a ALL NULL NULL NULL NULL 4 100.00 Using where Warnings: Note 1276 Field or reference 'test.t1.a1' of SELECT #3 was resolved in SELECT #1 @@ -643,7 +643,7 @@ where a1 in (select substring(b1,1,16) from t2_16 where b1 > '0'); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1_16 ALL NULL NULL NULL NULL 3 100.00 1 PRIMARY eq_ref distinct_key distinct_key 20 func 1 100.00 Using where -2 SUBQUERY t2_16 ALL NULL NULL NULL NULL 3 100.00 Using where +2 MATERIALIZED t2_16 ALL NULL NULL NULL NULL 3 100.00 Using where Warnings: Note 1003 select left(`test`.`t1_16`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_16`.`a2`,7) AS `left(a2,7)` from `test`.`t1_16` semi join (`test`.`t2_16`) where ((`test`.`t2_16`.`b1` > '0') and (`test`.`t1_16`.`a1` = substr(`test`.`t2_16`.`b1`,1,16))) select left(a1,7), left(a2,7) @@ -673,7 +673,7 @@ where a1 in (select group_concat(b1) from t2_16 group by b2); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1_16 ALL NULL NULL NULL NULL 3 100.00 Using where 1 PRIMARY eq_ref distinct_key distinct_key 261 test.t1_16.a1 1 100.00 Using where -2 SUBQUERY t2_16 ALL NULL NULL NULL NULL 3 100.00 Using filesort +2 MATERIALIZED t2_16 ALL NULL NULL NULL NULL 3 100.00 Using filesort Warnings: Note 1003 select left(`test`.`t1_16`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_16`.`a2`,7) AS `left(a2,7)` from (select group_concat(`test`.`t2_16`.`b1` separator ',') from `test`.`t2_16` group by `test`.`t2_16`.`b2`) join `test`.`t1_16` where (`test`.`t1_16`.`a1` = ``.`group_concat(b1)`) select left(a1,7), left(a2,7) @@ -758,7 +758,7 @@ where a1 in (select substring(b1,1,512) from t2_512 where b1 > '0'); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1_512 ALL NULL NULL NULL NULL 3 100.00 1 PRIMARY eq_ref distinct_key distinct_key 517 func 1 100.00 Using where -2 SUBQUERY t2_512 ALL NULL NULL NULL NULL 3 100.00 Using where +2 MATERIALIZED t2_512 ALL NULL NULL NULL NULL 3 100.00 Using where Warnings: Note 1003 select left(`test`.`t1_512`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_512`.`a2`,7) AS `left(a2,7)` from `test`.`t1_512` semi join (`test`.`t2_512`) where ((`test`.`t2_512`.`b1` > '0') and (`test`.`t1_512`.`a1` = substr(`test`.`t2_512`.`b1`,1,512))) select left(a1,7), left(a2,7) @@ -773,7 +773,7 @@ where a1 in (select group_concat(b1) from t2_512 group by b2); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1_512 ALL NULL NULL NULL NULL 3 100.00 Using where 1 PRIMARY eq_ref distinct_key distinct_key 261 test.t1_512.a1 1 100.00 Using where -2 SUBQUERY t2_512 ALL NULL NULL NULL NULL 3 100.00 Using filesort +2 MATERIALIZED t2_512 ALL NULL NULL NULL NULL 3 100.00 Using filesort Warnings: Note 1003 select left(`test`.`t1_512`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_512`.`a2`,7) AS `left(a2,7)` from (select group_concat(`test`.`t2_512`.`b1` separator ',') from `test`.`t2_512` group by `test`.`t2_512`.`b2`) join `test`.`t1_512` where (`test`.`t1_512`.`a1` = ``.`group_concat(b1)`) select left(a1,7), left(a2,7) @@ -787,7 +787,7 @@ where a1 in (select group_concat(b1) from t2_512 group by b2); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1_512 ALL NULL NULL NULL NULL 3 100.00 Using where 1 PRIMARY eq_ref distinct_key distinct_key 261 test.t1_512.a1 1 100.00 Using where -2 SUBQUERY t2_512 ALL NULL NULL NULL NULL 3 100.00 Using filesort +2 MATERIALIZED t2_512 ALL NULL NULL NULL NULL 3 100.00 Using filesort Warnings: Note 1003 select left(`test`.`t1_512`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_512`.`a2`,7) AS `left(a2,7)` from (select group_concat(`test`.`t2_512`.`b1` separator ',') from `test`.`t2_512` group by `test`.`t2_512`.`b2`) join `test`.`t1_512` where (`test`.`t1_512`.`a1` = ``.`group_concat(b1)`) select left(a1,7), left(a2,7) @@ -868,7 +868,7 @@ where a1 in (select group_concat(b1) from t2_1024 group by b2); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1_1024 ALL NULL NULL NULL NULL 3 100.00 Using where 1 PRIMARY eq_ref distinct_key distinct_key 261 test.t1_1024.a1 1 100.00 Using where -2 SUBQUERY t2_1024 ALL NULL NULL NULL NULL 3 100.00 Using filesort +2 MATERIALIZED t2_1024 ALL NULL NULL NULL NULL 3 100.00 Using filesort Warnings: Note 1003 select left(`test`.`t1_1024`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_1024`.`a2`,7) AS `left(a2,7)` from (select group_concat(`test`.`t2_1024`.`b1` separator ',') from `test`.`t2_1024` group by `test`.`t2_1024`.`b2`) join `test`.`t1_1024` where (`test`.`t1_1024`.`a1` = ``.`group_concat(b1)`) select left(a1,7), left(a2,7) @@ -882,7 +882,7 @@ where a1 in (select group_concat(b1) from t2_1024 group by b2); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1_1024 ALL NULL NULL NULL NULL 3 100.00 Using where 1 PRIMARY eq_ref distinct_key distinct_key 261 test.t1_1024.a1 1 100.00 Using where -2 SUBQUERY t2_1024 ALL NULL NULL NULL NULL 3 100.00 Using filesort +2 MATERIALIZED t2_1024 ALL NULL NULL NULL NULL 3 100.00 Using filesort Warnings: Note 1003 select left(`test`.`t1_1024`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_1024`.`a2`,7) AS `left(a2,7)` from (select group_concat(`test`.`t2_1024`.`b1` separator ',') from `test`.`t2_1024` group by `test`.`t2_1024`.`b2`) join `test`.`t1_1024` where (`test`.`t1_1024`.`a1` = ``.`group_concat(b1)`) select left(a1,7), left(a2,7) @@ -963,7 +963,7 @@ where a1 in (select group_concat(b1) from t2_1025 group by b2); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1_1025 ALL NULL NULL NULL NULL 3 100.00 Using where 1 PRIMARY eq_ref distinct_key distinct_key 261 test.t1_1025.a1 1 100.00 Using where -2 SUBQUERY t2_1025 ALL NULL NULL NULL NULL 3 100.00 Using filesort +2 MATERIALIZED t2_1025 ALL NULL NULL NULL NULL 3 100.00 Using filesort Warnings: Note 1003 select left(`test`.`t1_1025`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_1025`.`a2`,7) AS `left(a2,7)` from (select group_concat(`test`.`t2_1025`.`b1` separator ',') from `test`.`t2_1025` group by `test`.`t2_1025`.`b2`) join `test`.`t1_1025` where (`test`.`t1_1025`.`a1` = ``.`group_concat(b1)`) select left(a1,7), left(a2,7) @@ -977,7 +977,7 @@ where a1 in (select group_concat(b1) from t2_1025 group by b2); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1_1025 ALL NULL NULL NULL NULL 3 100.00 Using where 1 PRIMARY eq_ref distinct_key distinct_key 261 test.t1_1025.a1 1 100.00 Using where -2 SUBQUERY t2_1025 ALL NULL NULL NULL NULL 3 100.00 Using filesort +2 MATERIALIZED t2_1025 ALL NULL NULL NULL NULL 3 100.00 Using filesort Warnings: Note 1003 select left(`test`.`t1_1025`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_1025`.`a2`,7) AS `left(a2,7)` from (select group_concat(`test`.`t2_1025`.`b1` separator ',') from `test`.`t2_1025` group by `test`.`t2_1025`.`b2`) join `test`.`t1_1025` where (`test`.`t1_1025`.`a1` = ``.`group_concat(b1)`) select left(a1,7), left(a2,7) @@ -999,7 +999,7 @@ where (a1, a2) in (select b1, b2 from t2bit); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1bit ALL NULL NULL NULL NULL 3 100.00 1 PRIMARY eq_ref distinct_key distinct_key 10 func,func 1 100.00 -2 SUBQUERY t2bit ALL NULL NULL NULL NULL 3 100.00 +2 MATERIALIZED t2bit ALL NULL NULL NULL NULL 3 100.00 Warnings: Note 1003 select conv(`test`.`t1bit`.`a1`,10,2) AS `bin(a1)`,conv(`test`.`t1bit`.`a2`,10,2) AS `bin(a2)` from `test`.`t1bit` semi join (`test`.`t2bit`) where 1 select bin(a1), bin(a2) @@ -1071,7 +1071,7 @@ select a from t1 where a in (select c from t2 where d >= 20); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY ALL distinct_key NULL NULL NULL 6 100.00 1 PRIMARY t1 ALL NULL NULL NULL NULL 7 100.00 Using where; Using join buffer (flat, BNL join) -2 SUBQUERY t2 ALL NULL NULL NULL NULL 6 100.00 Using where +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 6 100.00 Using where Warnings: Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` semi join (`test`.`t2`) where ((`test`.`t1`.`a` = `test`.`t2`.`c`) and (`test`.`t2`.`d` >= 20)) select a from t1 where a in (select c from t2 where d >= 20); @@ -1086,7 +1086,7 @@ select a from t1 where a in (select c from t2 where d >= 20); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY ALL distinct_key NULL NULL NULL 6 100.00 1 PRIMARY t1 ref it1a it1a 4 test.t2.c 2 100.00 Using index -2 SUBQUERY t2 ALL NULL NULL NULL NULL 6 100.00 Using where +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 6 100.00 Using where Warnings: Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` semi join (`test`.`t2`) where ((`test`.`t1`.`a` = `test`.`t2`.`c`) and (`test`.`t2`.`d` >= 20)) select a from t1 where a in (select c from t2 where d >= 20); @@ -1101,7 +1101,7 @@ select a from t1 where a in (select c from t2 where d >= 20); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 index it1a it1a 4 NULL 7 100.00 Using index 1 PRIMARY eq_ref distinct_key distinct_key 4 func 1 100.00 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 7 100.00 Using where +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 7 100.00 Using where Warnings: Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` semi join (`test`.`t2`) where ((`test`.`t2`.`d` >= 20)) select a from t1 where a in (select c from t2 where d >= 20); @@ -1114,7 +1114,7 @@ explain extended select a from t1 group by a having a in (select c from t2 where d >= 20); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 index NULL it1a 4 NULL 7 100.00 Using index -2 SUBQUERY t2 ALL NULL NULL NULL NULL 7 100.00 Using where +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 7 100.00 Using where Warnings: Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` group by `test`.`t1`.`a` having <`test`.`t1`.`a`>((`test`.`t1`.`a`,`test`.`t1`.`a` in ( (select `test`.`t2`.`c` from `test`.`t2` where (`test`.`t2`.`d` >= 20) ), (`test`.`t1`.`a` in on distinct_key where ((`test`.`t1`.`a` = ``.`c`)))))) select a from t1 group by a having a in (select c from t2 where d >= 20); @@ -1126,7 +1126,7 @@ explain extended select a from t1 group by a having a in (select c from t2 where d >= 20); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 index NULL it1a 4 NULL 7 100.00 Using index -2 SUBQUERY t2 ALL NULL NULL NULL NULL 7 100.00 Using where +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 7 100.00 Using where Warnings: Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` group by `test`.`t1`.`a` having <`test`.`t1`.`a`>((`test`.`t1`.`a`,`test`.`t1`.`a` in ( (select `test`.`t2`.`c` from `test`.`t2` where (`test`.`t2`.`d` >= 20) ), (`test`.`t1`.`a` in on distinct_key where ((`test`.`t1`.`a` = ``.`c`)))))) select a from t1 group by a having a in (select c from t2 where d >= 20); @@ -1185,7 +1185,7 @@ explain select min(a1) from t1 where 7 in (select b1 from t2 group by b1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 1 1 PRIMARY const distinct_key distinct_key 5 const 1 -2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL no matching row in const table +2 MATERIALIZED NULL NULL NULL NULL NULL NULL NULL no matching row in const table select min(a1) from t1 where 7 in (select b1 from t2 group by b1); min(a1) NULL @@ -1234,7 +1234,7 @@ explain select a,b from t1 where b in (select a from t1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 2 1 PRIMARY eq_ref distinct_key distinct_key 3 func 1 Using where -2 SUBQUERY t1 ALL NULL NULL NULL NULL 2 +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 2 select a,b from t1 where b in (select a from t1); a b prepare st1 from "select a,b from t1 where b in (select a from t1)"; @@ -1273,7 +1273,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY eq_ref distinct_key distinct_key 5 const 1 1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) 1 PRIMARY t4 ALL NULL NULL NULL NULL 2 Using where; Using join buffer (flat, BNL join) -3 SUBQUERY t3 ALL NULL NULL NULL NULL 2 Using temporary +3 MATERIALIZED t3 ALL NULL NULL NULL NULL 2 Using temporary DROP TABLE t1,t2,t3,t4; CREATE TABLE t1 ( pk INTEGER AUTO_INCREMENT, @@ -1380,7 +1380,7 @@ SELECT t1.* FROM t1 LEFT JOIN t2 ON t1.a > 3 OR t2.b IN (SELECT a FROM t1) id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL NULL NULL NULL NULL 2 2 DERIVED NULL NULL NULL NULL NULL NULL NULL no matching row in const table -3 SUBQUERY NULL NULL NULL NULL NULL NULL NULL no matching row in const table +3 MATERIALIZED NULL NULL NULL NULL NULL NULL NULL no matching row in const table SELECT a FROM ( SELECT t1.* FROM t1 LEFT JOIN t2 ON t1.a > 3 OR t2.b IN (SELECT a FROM t1) ) table1; @@ -1410,7 +1410,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 1 1 PRIMARY eq_ref distinct_key distinct_key 4 const 1 1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where; Using join buffer (flat, BNL join) -2 SUBQUERY t1 system NULL NULL NULL NULL 1 +2 MATERIALIZED t1 system NULL NULL NULL NULL 1 SELECT * FROM t1 JOIN t2 USING (f1) WHERE t1.f1 IN (SELECT t1.pk FROM t1 ORDER BY t1.f1); f1 pk pk @@ -1484,7 +1484,7 @@ EXPLAIN SELECT COUNT(*) FROM t1 WHERE (f1,f2) IN (SELECT f1,f2 FROM t2); 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 3 Using where; Using join buffer (flat, BNL join) -2 SUBQUERY t2 ALL NULL NULL NULL NULL 2 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 SELECT COUNT(*) FROM t1 WHERE (f1,f2) IN (SELECT f1,f2 FROM t2); COUNT(*) 2 @@ -1508,7 +1508,7 @@ EXPLAIN SELECT pk FROM t1 WHERE (a) IN (SELECT a FROM t2 WHERE pk > 0); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 2 1 PRIMARY eq_ref distinct_key distinct_key 5 func 1 -2 SUBQUERY t2 range PRIMARY PRIMARY 4 NULL 2 Using index condition; Rowid-ordered scan +2 MATERIALIZED t2 range PRIMARY PRIMARY 4 NULL 2 Using index condition; Rowid-ordered scan SELECT pk FROM t1 WHERE (a) IN (SELECT a FROM t2 WHERE pk > 0); pk 2 @@ -1549,7 +1549,7 @@ insert into t1 values (0),(1),(2); explain select a, a in (select a from t1) from t0; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t0 ALL NULL NULL NULL NULL 3 -2 SUBQUERY t1 ALL NULL NULL NULL NULL 3 +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 3 select a, a in (select a from t1) from t0; a a in (select a from t1) 0 1 diff --git a/mysql-test/r/subselect_sj_nonmerged.result b/mysql-test/r/subselect_sj_nonmerged.result index 192c0812236..fe1f9c35626 100644 --- a/mysql-test/r/subselect_sj_nonmerged.result +++ b/mysql-test/r/subselect_sj_nonmerged.result @@ -10,7 +10,7 @@ explain select * from t0 where a in (select max(a) from t1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL distinct_key NULL NULL NULL 1 1 PRIMARY t0 ALL NULL NULL NULL NULL 10 Using where; Using join buffer (flat, BNL join) -2 SUBQUERY t1 ALL NULL NULL NULL NULL 10 +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 10 select * from t0 where a in (select max(a) from t1); a 9 @@ -42,23 +42,23 @@ explain select * from t3 where a in (select max(t2.a) from t1, t2 group by t2.b) id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL distinct_key NULL NULL NULL 5 Using where 1 PRIMARY t3 eq_ref PRIMARY PRIMARY 8 .max(t2.a) 1 Using where; Using index -2 SUBQUERY t2 ALL NULL NULL NULL NULL 5 Using temporary -2 SUBQUERY t1 ALL NULL NULL NULL NULL 10 Using join buffer (flat, BNL join) +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 5 Using temporary +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 10 Using join buffer (flat, BNL join) # Compare to this which really will have 50 record combinations: explain select * from t3 where a in (select max(t2.a) from t1, t2 group by t2.b, t1.b); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL distinct_key NULL NULL NULL 50 Using where 1 PRIMARY t3 eq_ref PRIMARY PRIMARY 8 .max(t2.a) 1 Using where; Using index -2 SUBQUERY t2 ALL NULL NULL NULL NULL 5 Using temporary -2 SUBQUERY t1 ALL NULL NULL NULL NULL 10 Using join buffer (flat, BNL join) +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 5 Using temporary +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 10 Using join buffer (flat, BNL join) # Outer joins also work: explain select * from t3 where a in (select max(t2.a) from t1 left join t2 on t1.a=t2.a group by t2.b, t1.b); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL distinct_key NULL NULL NULL 50 Using where 1 PRIMARY t3 eq_ref PRIMARY PRIMARY 8 .max(t2.a) 1 Using where; Using index -2 SUBQUERY t1 ALL NULL NULL NULL NULL 10 Using temporary -2 SUBQUERY t2 ALL NULL NULL NULL NULL 5 Using where +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 10 Using temporary +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 5 Using where create table t4 (a int, b int, filler char(20), unique key(a,b)); insert into t4 select A.a + 10*B.a, A.a + 10*B.a, 'filler' from t0 A, t0 B; explain select * from t0, t4 where @@ -67,8 +67,8 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t0 ALL NULL NULL NULL NULL 10 1 PRIMARY t4 ALL a NULL NULL NULL 100 Using where; Using join buffer (flat, BNL join) 1 PRIMARY eq_ref distinct_key distinct_key 5 test.t4.a 1 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 5 Using temporary -2 SUBQUERY t1 ALL NULL NULL NULL NULL 10 Using join buffer (flat, BNL join) +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 5 Using temporary +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 10 Using join buffer (flat, BNL join) insert into t4 select 100 + (B.a *100 + A.a), 100 + (B.a*100 + A.a), 'filler' from t4 A, t0 B; explain select * from t4 where t4.a in (select max(t2.a) from t1, t2 group by t2.b) and @@ -77,10 +77,10 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL distinct_key NULL NULL NULL 5 Using where 1 PRIMARY ALL distinct_key NULL NULL NULL 5 Using where; Using join buffer (flat, BNL join) 1 PRIMARY t4 ref a a 10 .max(t2.a),.max(t2.a) 12 -3 SUBQUERY t2 ALL NULL NULL NULL NULL 5 Using temporary -3 SUBQUERY t1 ALL NULL NULL NULL NULL 10 Using join buffer (flat, BNL join) -2 SUBQUERY t2 ALL NULL NULL NULL NULL 5 Using temporary -2 SUBQUERY t1 ALL NULL NULL NULL NULL 10 Using join buffer (flat, BNL join) +3 MATERIALIZED t2 ALL NULL NULL NULL NULL 5 Using temporary +3 MATERIALIZED t1 ALL NULL NULL NULL NULL 10 Using join buffer (flat, BNL join) +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 5 Using temporary +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 10 Using join buffer (flat, BNL join) drop table t1,t2,t3,t4; drop table t0; # @@ -114,6 +114,6 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL distinct_key NULL NULL NULL 1 Using where 1 PRIMARY X ref a a 5 .max(a) 1 Using index 1 PRIMARY Y ALL NULL NULL NULL NULL 10 Using where; Using join buffer (flat, BNL join) -2 SUBQUERY t0 ALL NULL NULL NULL NULL 10 +2 MATERIALIZED t0 ALL NULL NULL NULL NULL 10 drop table t0, t1; set optimizer_switch=@save_optimizer_switch; diff --git a/mysql-test/suite/pbxt/r/subselect.result b/mysql-test/suite/pbxt/r/subselect.result index 0b5bfc579cf..a4777ad107b 100644 --- a/mysql-test/suite/pbxt/r/subselect.result +++ b/mysql-test/suite/pbxt/r/subselect.result @@ -2839,7 +2839,7 @@ explain extended SELECT one,two from t1 where ROW(one,two) IN (SELECT one,two FR id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 8 100.00 1 PRIMARY eq_ref distinct_key distinct_key 10 func,func 1 100.00 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 9 100.00 Using where +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 9 100.00 Using where Warnings: Note 1003 select `test`.`t1`.`one` AS `one`,`test`.`t1`.`two` AS `two` from `test`.`t1` semi join (`test`.`t2`) where ((`test`.`t2`.`flag` = 'N')) explain extended SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0' group by one,two) as 'test' from t1; @@ -3432,7 +3432,7 @@ SELECT * FROM t1 WHERE (a,b) = ANY (SELECT a, max(b) FROM t1 GROUP BY a); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 9 Using where 1 PRIMARY eq_ref distinct_key distinct_key 23 test.t1.a,test.t1.b 1 -2 SUBQUERY t1 ALL NULL NULL NULL NULL 9 Using temporary +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 9 Using temporary ALTER TABLE t1 ADD INDEX(a); SELECT * FROM t1 WHERE (a,b) = ANY (SELECT a, max(b) FROM t1 GROUP BY a); a b @@ -3444,7 +3444,7 @@ SELECT * FROM t1 WHERE (a,b) = ANY (SELECT a, max(b) FROM t1 GROUP BY a); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL a NULL NULL NULL 9 Using where 1 PRIMARY eq_ref distinct_key distinct_key 23 test.t1.a,test.t1.b 1 -2 SUBQUERY t1 ALL NULL NULL NULL NULL 9 Using temporary +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 9 Using temporary DROP TABLE t1; create table t1( f1 int,f2 int); insert into t1 values (1,1),(2,2); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 117a866555c..2e2bec06c06 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -3527,20 +3527,58 @@ void st_select_lex::set_explain_type() SELECT_LEX *first= master_unit()->first_select(); /* drop UNCACHEABLE_EXPLAIN, because it is for internal usage only */ uint8 is_uncacheable= (uncacheable & ~UNCACHEABLE_EXPLAIN); + + bool using_materialization= FALSE; + Item_subselect *parent_item; + if ((parent_item= master_unit()->item) && + parent_item->substype() == Item_subselect::IN_SUBS) + { + Item_in_subselect *in_subs= (Item_in_subselect*)parent_item; + /* + Surprisingly, in_subs->is_set_strategy() can return FALSE here, + even for the last invocation of this function for the select. + */ + if (in_subs->test_strategy(SUBS_MATERIALIZATION)) + using_materialization= TRUE; + } - type= ((&master_unit()->thd->lex->select_lex == this) ? - (is_primary ? "PRIMARY" : "SIMPLE"): - ((this == first) ? - ((linkage == DERIVED_TABLE_TYPE) ? - "DERIVED" : - ((is_uncacheable & UNCACHEABLE_DEPENDENT) ? - "DEPENDENT SUBQUERY" : - (is_uncacheable ? "UNCACHEABLE SUBQUERY" : - "SUBQUERY"))) : - ((is_uncacheable & UNCACHEABLE_DEPENDENT) ? - "DEPENDENT UNION": - is_uncacheable ? "UNCACHEABLE UNION": - "UNION"))); + if (&master_unit()->thd->lex->select_lex == this) + { + type= is_primary ? "PRIMARY" : "SIMPLE"; + } + else + { + if (this == first) + { + /* If we're a direct child of a UNION, we're the first sibling there */ + if (linkage == DERIVED_TABLE_TYPE) + type= "DERIVED"; + else if (using_materialization) + type= "MATERIALIZED"; + else + { + if (is_uncacheable & UNCACHEABLE_DEPENDENT) + type= "DEPENDENT SUBQUERY"; + else + { + type= is_uncacheable? "UNCACHEABLE SUBQUERY" : + "SUBQUERY"; + } + } + } + else + { + /* This a non-first sibling in UNION */ + if (is_uncacheable & UNCACHEABLE_DEPENDENT) + type= "DEPENDENT UNION"; + else if (using_materialization) + type= "MATERIALIZED UNION"; + else + { + type= is_uncacheable ? "UNCACHEABLE UNION": "UNION"; + } + } + } options|= SELECT_DESCRIBE; } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 7c36f7c4d8c..4ff660286d6 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -20642,7 +20642,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, /* id */ item_list.push_back(new Item_uint((uint32)select_id)); /* select_type */ - const char* stype= printing_materialize_nest? "SUBQUERY" : + const char* stype= printing_materialize_nest? "MATERIALIZED" : join->select_lex->type; item_list.push_back(new Item_string(stype, strlen(stype), cs)); From a85454def888a71669860240c7a622c674accd37 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Mon, 5 Dec 2011 10:24:14 +0400 Subject: [PATCH 172/288] Update test result missed in the previous cset --- mysql-test/suite/pbxt/r/group_min_max.result | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/suite/pbxt/r/group_min_max.result b/mysql-test/suite/pbxt/r/group_min_max.result index ecc19e1531a..b73b393f9da 100644 --- a/mysql-test/suite/pbxt/r/group_min_max.result +++ b/mysql-test/suite/pbxt/r/group_min_max.result @@ -2258,7 +2258,7 @@ a IN (SELECT max(b) FROM t1 GROUP BY a HAVING a < 2); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL distinct_key NULL NULL NULL 15 Using where 1 PRIMARY t1_outer ref a a 5 .max(b) 1 Using index -2 SUBQUERY t1 index NULL a 10 NULL 15 Using index +2 MATERIALIZED t1 index NULL a 10 NULL 15 Using index EXPLAIN SELECT 1 FROM t1 AS t1_outer GROUP BY a HAVING a > (SELECT max(b) FROM t1 GROUP BY a HAVING a < 2); id select_type table type possible_keys key key_len ref rows Extra From 0cd9228124266a1e8cf41e74994cdba1380ac2e2 Mon Sep 17 00:00:00 2001 From: Tor Didriksen Date: Mon, 5 Dec 2011 15:42:45 +0100 Subject: [PATCH 173/288] Bug#13013970 MORE CRASHES IN FIELD_BLOB::GET_KEY_IMAGE The predicate is re-written from ((`test`.`g1`.`a` = geometryfromtext('')) or ... to ((`test`.`g1`.`a` = (geometryfromtext(''))) or ... The range optimizer calls save_in_field_no_warnings, in order to fetch keys. save_in_field_no_warnings returns 0 because of the cache wrapper, and get_mm_leaf() proceeded to call Field_blob::get_key_image() which accesses un-initialized data. mysql-test/r/gis.result: New test case. mysql-test/t/gis.test: New test case. sql/item.cc: If we have cached a null_value, then verify that the Field can accept it. --- mysql-test/r/gis.result | 9 +++++++++ mysql-test/t/gis.test | 11 +++++++++++ sql/item.cc | 4 ++-- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/gis.result b/mysql-test/r/gis.result index 0dc10c56bd0..bcfc95bd905 100644 --- a/mysql-test/r/gis.result +++ b/mysql-test/r/gis.result @@ -1091,4 +1091,13 @@ FORCE INDEX(i) WHERE a = date_sub(now(), interval 2808.4 year_month) Warnings: Warning 1441 Datetime function: datetime field overflow DROP TABLE g1; +# +# Bug#13013970 MORE CRASHES IN FIELD_BLOB::GET_KEY_IMAGE +# +CREATE TABLE g1(a TEXT NOT NULL, KEY(a(255))); +INSERT INTO g1 VALUES ('a'),('a'); +SELECT 1 FROM g1 WHERE a >= ANY +(SELECT 1 FROM g1 WHERE a = geomfromtext('') OR a) ; +1 +DROP TABLE g1; End of 5.5 tests diff --git a/mysql-test/t/gis.test b/mysql-test/t/gis.test index 104afddeee5..e75ae732979 100644 --- a/mysql-test/t/gis.test +++ b/mysql-test/t/gis.test @@ -838,5 +838,16 @@ FORCE INDEX(i) WHERE a = date_sub(now(), interval 2808.4 year_month) DROP TABLE g1; +--echo # +--echo # Bug#13013970 MORE CRASHES IN FIELD_BLOB::GET_KEY_IMAGE +--echo # + +CREATE TABLE g1(a TEXT NOT NULL, KEY(a(255))); + +INSERT INTO g1 VALUES ('a'),('a'); +SELECT 1 FROM g1 WHERE a >= ANY +(SELECT 1 FROM g1 WHERE a = geomfromtext('') OR a) ; + +DROP TABLE g1; --echo End of 5.5 tests diff --git a/sql/item.cc b/sql/item.cc index ca1ae1c4f71..c8c68a3924b 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -7924,8 +7924,8 @@ my_decimal *Item_cache_str::val_decimal(my_decimal *decimal_val) int Item_cache_str::save_in_field(Field *field, bool no_conversions) { - if (!has_value()) - return 0; + if (!value_cached && !cache_value()) + return -1; // Fatal: couldn't cache the value int res= Item_cache::save_in_field(field, no_conversions); return (is_varbinary && field->type() == MYSQL_TYPE_STRING && value->length() < field->field_length) ? 1 : res; From 7d1f41265c7d9e36b8d85af33225b68a4eec1a2f Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Mon, 5 Dec 2011 09:50:24 -0800 Subject: [PATCH 174/288] Fixed LP bug #899777. KEYUSE elements for a possible hash join key are not sorted by field numbers of the second table T of the hash join operation. Besides some of these KEYUSE elements cannot be used to build any key as their key expressions depend on the tables that are planned to be accessed after the table T. The code before the patch did not take this into account and, as a result, execition of a query the employing block-based hash join algorithm could cause a crash or return a wrong result set. --- mysql-test/r/join_cache.result | 47 ++++++++++++++++++++++++++ mysql-test/t/join_cache.test | 40 +++++++++++++++++++++++ sql/sql_select.cc | 60 ++++++++++++++++++++++++++-------- sql/sql_select.h | 2 ++ 4 files changed, 135 insertions(+), 14 deletions(-) diff --git a/mysql-test/r/join_cache.result b/mysql-test/r/join_cache.result index be579c9240f..8372f68fde0 100644 --- a/mysql-test/r/join_cache.result +++ b/mysql-test/r/join_cache.result @@ -5179,4 +5179,51 @@ a b SET SESSION join_cache_level = DEFAULT; SET optimizer_switch=@tmp887479_optimizer_switch; DROP TABLE t1,t2; +# +# Bug #899777: join_cache_level=4 + semijoin=on +# +CREATE TABLE t1 (a int, b int, c int, UNIQUE INDEX idx (a)); +INSERT INTO t1 VALUES (1,8,6), (2,2,8); +CREATE TABLE t2 (a int, b int, c int, UNIQUE INDEX idx (a)); +INSERT INTO t2 VALUES (1,8,6), (2,2,8); +CREATE TABLE t3 (a int, b int, c int, UNIQUE INDEX idx (a)); +INSERT INTO t3 VALUES (1,8,6), (2,2,8); +CREATE TABLE t4 (a int, b int, c int, UNIQUE INDEX idx (a)); +INSERT INTO t4 VALUES (1,8,6), (2,2,8); +SET @tmp_optimizer_switch=@@optimizer_switch; +SET SESSION optimizer_switch='semijoin=on'; +SET SESSION optimizer_switch='semijoin_with_cache=on'; +SET SESSION join_cache_level=1; +EXPLAIN +SELECT t1.* FROM t1,t2 +WHERE (t1.b,t2.b) IN (SELECT t3.b,t4.b FROM t3,t4 WHERE t4.c=t3.b) +AND t1.a = 1; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 const idx idx 5 const 1 +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 +1 PRIMARY t3 ALL NULL NULL NULL NULL 2 Using where; Start temporary; Using join buffer (flat, BNL join) +1 PRIMARY t4 ALL NULL NULL NULL NULL 2 Using where; End temporary; Using join buffer (flat, BNL join) +SELECT t1.* FROM t1,t2 +WHERE (t1.b,t2.b) IN (SELECT t3.b,t4.b FROM t3,t4 WHERE t4.c=t3.b) +AND t1.a = 1; +a b c +1 8 6 +SET SESSION join_cache_level=4; +EXPLAIN +SELECT t1.* FROM t1,t2 +WHERE (t1.b,t2.b) IN (SELECT t3.b,t4.b FROM t3,t4 WHERE t4.c=t3.b) +AND t1.a = 1; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 const idx idx 5 const 1 +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where +1 PRIMARY t3 hash_ALL NULL #hash#$hj 5 const 2 Using where; Start temporary; Using join buffer (flat, BNLH join) +1 PRIMARY t4 hash_ALL NULL #hash#$hj 10 const,test.t2.b 2 Using where; End temporary; Using join buffer (incremental, BNLH join) +SELECT t1.* FROM t1,t2 +WHERE (t1.b,t2.b) IN (SELECT t3.b,t4.b FROM t3,t4 WHERE t4.c=t3.b) +AND t1.a = 1; +a b c +1 8 6 +SET SESSION join_cache_level = DEFAULT; +SET optimizer_switch=@tmp_optimizer_switch; +DROP TABLE t1,t2,t3,t4; set @@optimizer_switch=@save_optimizer_switch; diff --git a/mysql-test/t/join_cache.test b/mysql-test/t/join_cache.test index 530528ead2c..66381150ede 100644 --- a/mysql-test/t/join_cache.test +++ b/mysql-test/t/join_cache.test @@ -3254,5 +3254,45 @@ SET optimizer_switch=@tmp887479_optimizer_switch; DROP TABLE t1,t2; +--echo # +--echo # Bug #899777: join_cache_level=4 + semijoin=on +--echo # + +CREATE TABLE t1 (a int, b int, c int, UNIQUE INDEX idx (a)); +INSERT INTO t1 VALUES (1,8,6), (2,2,8); +CREATE TABLE t2 (a int, b int, c int, UNIQUE INDEX idx (a)); +INSERT INTO t2 VALUES (1,8,6), (2,2,8); +CREATE TABLE t3 (a int, b int, c int, UNIQUE INDEX idx (a)); +INSERT INTO t3 VALUES (1,8,6), (2,2,8); +CREATE TABLE t4 (a int, b int, c int, UNIQUE INDEX idx (a)); +INSERT INTO t4 VALUES (1,8,6), (2,2,8); + +SET @tmp_optimizer_switch=@@optimizer_switch; +SET SESSION optimizer_switch='semijoin=on'; +SET SESSION optimizer_switch='semijoin_with_cache=on'; + +SET SESSION join_cache_level=1; +EXPLAIN +SELECT t1.* FROM t1,t2 + WHERE (t1.b,t2.b) IN (SELECT t3.b,t4.b FROM t3,t4 WHERE t4.c=t3.b) + AND t1.a = 1; +SELECT t1.* FROM t1,t2 + WHERE (t1.b,t2.b) IN (SELECT t3.b,t4.b FROM t3,t4 WHERE t4.c=t3.b) + AND t1.a = 1; + +SET SESSION join_cache_level=4; +EXPLAIN +SELECT t1.* FROM t1,t2 + WHERE (t1.b,t2.b) IN (SELECT t3.b,t4.b FROM t3,t4 WHERE t4.c=t3.b) + AND t1.a = 1; +SELECT t1.* FROM t1,t2 + WHERE (t1.b,t2.b) IN (SELECT t3.b,t4.b FROM t3,t4 WHERE t4.c=t3.b) + AND t1.a = 1; + +SET SESSION join_cache_level = DEFAULT; +SET optimizer_switch=@tmp_optimizer_switch; + +DROP TABLE t1,t2,t3,t4; + # this must be the last command in the file set @@optimizer_switch=@save_optimizer_switch; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 7c36f7c4d8c..8bb490e5045 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -7183,10 +7183,26 @@ static bool create_hj_key_for_table(JOIN *join, JOIN_TAB *join_tab, do { - if (!(~used_tables & keyuse->used_tables) && - (first_keyuse || keyuse->keypart != (keyuse-1)->keypart)) - key_parts++; - first_keyuse= FALSE; + if (!(~used_tables & keyuse->used_tables)) + { + if (first_keyuse) + { + key_parts++; + first_keyuse= FALSE; + } + else + { + KEYUSE *curr= org_keyuse; + for( ; curr < keyuse; curr++) + { + if (curr->keypart == keyuse->keypart && + !(~used_tables & curr->used_tables)) + break; + } + if (curr == keyuse) + key_parts++; + } + } keyuse++; } while (keyuse->table == table && keyuse->is_for_hash_join()); if (!key_parts) @@ -7211,15 +7227,31 @@ static bool create_hj_key_for_table(JOIN *join, JOIN_TAB *join_tab, keyuse= org_keyuse; do { - if (!(~used_tables & keyuse->used_tables) && - (first_keyuse || keyuse->keypart != (keyuse-1)->keypart)) - { - Field *field= table->field[keyuse->keypart]; - uint fieldnr= keyuse->keypart+1; - table->create_key_part_by_field(keyinfo, key_part_info, field, fieldnr); - first_keyuse= FALSE; - key_part_info++; + if (!(~used_tables & keyuse->used_tables)) + { + bool add_key_part= TRUE; + if (!first_keyuse) + { + for(KEYUSE *curr= org_keyuse; curr < keyuse; curr++) + { + if (curr->keypart == keyuse->keypart && + !(~used_tables & curr->used_tables)) + { + keyuse->keypart= NO_KEYPART; + add_key_part= FALSE; + break; + } + } + } + if (add_key_part) + { + Field *field= table->field[keyuse->keypart]; + uint fieldnr= keyuse->keypart+1; + table->create_key_part_by_field(keyinfo, key_part_info, field, fieldnr); + key_part_info++; + } } + first_keyuse= FALSE; keyuse++; } while (keyuse->table == table && keyuse->is_for_hash_join()); @@ -7302,8 +7334,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, { if (are_tables_local(j, keyuse->val->used_tables())) { - if ((is_hash_join_key_no(key) && - (keyparts == 0 || keyuse->keypart != (keyuse-1)->keypart)) || + if ((is_hash_join_key_no(key) && keyuse->keypart != NO_KEYPART) || (!is_hash_join_key_no(key) && keyparts == keyuse->keypart && !(found_part_ref_or_null & keyuse->optimize))) { @@ -7357,6 +7388,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, for (i=0 ; i < keyparts ; keyuse++,i++) { while (((~used_tables) & keyuse->used_tables) || + keyuse->keypart == NO_KEYPART || (keyuse->keypart != (is_hash_join_key_no(key) ? keyinfo->key_part[i].field->field_index : i)) || diff --git a/sql/sql_select.h b/sql/sql_select.h index 4333b825c28..ffe3985c3c3 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -77,6 +77,8 @@ typedef struct keyuse_t { bool is_for_hash_join() { return is_hash_join_key_no(key); } } KEYUSE; +#define NO_KEYPART ((uint)(-1)) + class store_key; const int NO_REF_PART= uint(-1); From 136408b1cfa9c197aaf2c5b8698db76144474077 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Tue, 6 Dec 2011 01:04:27 +0400 Subject: [PATCH 175/288] Bug #899962: materialized subquery with join_cache_level=3 - Make create_tmp_table() set KEY_PART_INFO attributes for the keys it creates. This wasn't needed before but is needed now, when temp. tables that are results of SJ-Materialization are being used for joins. This particular bug depended on HA_VAR_LENGTH_PART being set, but also added code to set HA_BLOB_PART and HA_NULL_PART when appropriate. --- mysql-test/r/subselect_sj2_jcl6.result | 22 ++++++++++++++++++++++ mysql-test/t/subselect_sj2_jcl6.test | 24 ++++++++++++++++++++++++ sql/sql_select.cc | 18 +++++++++++++++--- 3 files changed, 61 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/subselect_sj2_jcl6.result b/mysql-test/r/subselect_sj2_jcl6.result index 0f990d44545..8fd9122465c 100644 --- a/mysql-test/r/subselect_sj2_jcl6.result +++ b/mysql-test/r/subselect_sj2_jcl6.result @@ -955,6 +955,28 @@ pk a b set optimizer_switch=@tmp_optimizer_switch; set join_cache_level=default; DROP TABLE t1,t2,t3,t4; +# +# Bug #899962: materialized subquery with join_cache_level=3 +# +CREATE TABLE t1 (a varchar(1), b varchar(1)) ENGINE=InnoDB; +INSERT INTO t1 VALUES ('v','v'); +CREATE TABLE t2 (a varchar(1), b varchar(1)) ENGINE=InnoDB; +INSERT INTO t2 VALUES ('v','v'); +set @tmp_optimizer_switch=@@optimizer_switch; +SET optimizer_switch = 'semijoin_with_cache=on'; +SET join_cache_level = 3; +EXPLAIN +SELECT * FROM t1 WHERE b IN (SELECT a FROM t2 GROUP BY a); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 1 Using where +1 PRIMARY hash_ALL distinct_key #hash#distinct_key 5 test.t1.b 1 Using join buffer (flat, BNLH join) +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 1 Using temporary +SELECT * FROM t1 WHERE b IN (SELECT a FROM t2 GROUP BY a); +a b +v v +set optimizer_switch=@tmp_optimizer_switch; +set join_cache_level=default; +DROP TABLE t1,t2; set join_cache_level=default; show variables like 'join_cache_level'; Variable_name Value diff --git a/mysql-test/t/subselect_sj2_jcl6.test b/mysql-test/t/subselect_sj2_jcl6.test index 374fbd946c3..95f84a9e89e 100644 --- a/mysql-test/t/subselect_sj2_jcl6.test +++ b/mysql-test/t/subselect_sj2_jcl6.test @@ -73,6 +73,30 @@ set join_cache_level=default; DROP TABLE t1,t2,t3,t4; +--echo # +--echo # Bug #899962: materialized subquery with join_cache_level=3 +--echo # + +CREATE TABLE t1 (a varchar(1), b varchar(1)) ENGINE=InnoDB; +INSERT INTO t1 VALUES ('v','v'); +CREATE TABLE t2 (a varchar(1), b varchar(1)) ENGINE=InnoDB; +INSERT INTO t2 VALUES ('v','v'); + +set @tmp_optimizer_switch=@@optimizer_switch; + +SET optimizer_switch = 'semijoin_with_cache=on'; +SET join_cache_level = 3; + +EXPLAIN +SELECT * FROM t1 WHERE b IN (SELECT a FROM t2 GROUP BY a); +SELECT * FROM t1 WHERE b IN (SELECT a FROM t2 GROUP BY a); + +set optimizer_switch=@tmp_optimizer_switch; +set join_cache_level=default; + +DROP TABLE t1,t2; + + set join_cache_level=default; show variables like 'join_cache_level'; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 4ff660286d6..6fbba67e156 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -13937,10 +13937,22 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List &fields, key_part_info->store_length= key_part_info->length; if ((*reg_field)->real_maybe_null()) + { key_part_info->store_length+= HA_KEY_NULL_LENGTH; - if ((*reg_field)->type() == MYSQL_TYPE_BLOB || - (*reg_field)->real_type() == MYSQL_TYPE_VARCHAR) - key_part_info->store_length+= HA_KEY_BLOB_LENGTH; + key_part_info->key_part_flag |= HA_NULL_PART; + } + if ((*reg_field)->type() == MYSQL_TYPE_BLOB || + (*reg_field)->real_type() == MYSQL_TYPE_VARCHAR || + (*reg_field)->type() == MYSQL_TYPE_GEOMETRY) + { + if ((*reg_field)->type() == MYSQL_TYPE_BLOB || + (*reg_field)->type() == MYSQL_TYPE_GEOMETRY) + key_part_info->key_part_flag|= HA_BLOB_PART; + else + key_part_info->key_part_flag|= HA_VAR_LENGTH_PART; + + key_part_info->store_length+=HA_KEY_BLOB_LENGTH; + } keyinfo->key_length+= key_part_info->store_length; From b4c9fa321dd1fc08227333439695ec4314fb34c8 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Tue, 6 Dec 2011 02:46:42 -0800 Subject: [PATCH 176/288] Fixed LP bug #899509. The optimizer must ignore any possible hash join key when looking for the query execution plan with join_cache_level set to 0. --- mysql-test/r/derived.result | 4 +-- mysql-test/r/join_cache.result | 38 ++++++++++++++++++++++++++ mysql-test/r/subselect_extra.result | 2 +- mysql-test/suite/pbxt/r/derived.result | 4 +-- mysql-test/t/join_cache.test | 29 ++++++++++++++++++++ sql/sql_select.cc | 4 ++- 6 files changed, 75 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/derived.result b/mysql-test/r/derived.result index f34810ada6a..a9247ff41bf 100644 --- a/mysql-test/r/derived.result +++ b/mysql-test/r/derived.result @@ -192,13 +192,13 @@ pla_id test explain SELECT STRAIGHT_JOIN d.pla_id, m2.mat_id FROM t1 m2 INNER JOIN (SELECT mp.pla_id, MIN(m1.matintnum) AS matintnum FROM t2 mp INNER JOIN t1 m1 ON mp.mat_id=m1.mat_id GROUP BY mp.pla_id) d ON d.matintnum=m2.matintnum; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY m2 ALL NULL NULL NULL NULL 9 -1 PRIMARY ALL NULL NULL NULL NULL 9 Using where +1 PRIMARY ALL NULL NULL NULL NULL 9 Using where; Using join buffer (flat, BNL join) 2 DERIVED mp ALL NULL NULL NULL NULL 9 Using temporary; Using filesort 2 DERIVED m1 eq_ref PRIMARY PRIMARY 3 test.mp.mat_id 1 explain SELECT STRAIGHT_JOIN d.pla_id, m2.test FROM t1 m2 INNER JOIN (SELECT mp.pla_id, MIN(m1.matintnum) AS matintnum FROM t2 mp INNER JOIN t1 m1 ON mp.mat_id=m1.mat_id GROUP BY mp.pla_id) d ON d.matintnum=m2.matintnum; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY m2 ALL NULL NULL NULL NULL 9 -1 PRIMARY ALL NULL NULL NULL NULL 9 Using where +1 PRIMARY ALL NULL NULL NULL NULL 9 Using where; Using join buffer (flat, BNL join) 2 DERIVED mp ALL NULL NULL NULL NULL 9 Using temporary; Using filesort 2 DERIVED m1 eq_ref PRIMARY PRIMARY 3 test.mp.mat_id 1 drop table t1,t2; diff --git a/mysql-test/r/join_cache.result b/mysql-test/r/join_cache.result index 8372f68fde0..ef5c0a66130 100644 --- a/mysql-test/r/join_cache.result +++ b/mysql-test/r/join_cache.result @@ -5226,4 +5226,42 @@ a b c SET SESSION join_cache_level = DEFAULT; SET optimizer_switch=@tmp_optimizer_switch; DROP TABLE t1,t2,t3,t4; +# +# Bug #899509: an attempt to use hash join with join_cache_level=0 +# +CREATE TABLE t1 (a int); +INSERT INTO t1 VALUES (8), (7); +CREATE TABLE t2 (a int); +INSERT INTO t2 VALUES (8), (7); +CREATE TABLE t3 (a int); +INSERT INTO t3 VALUES (8), (7); +SET @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch=default; +set @@optimizer_switch='semijoin_with_cache=off'; +set @@optimizer_switch='outer_join_with_cache=off'; +SET optimizer_switch='derived_merge=off,derived_with_keys=off'; +SET join_cache_level=0; +EXPLAIN +SELECT * FROM (SELECT t1.* FROM t1, t2) t WHERE t.a IN (SELECT * FROM t3); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ALL distinct_key NULL NULL NULL 2 +1 PRIMARY ALL NULL NULL NULL NULL 4 Using where +3 MATERIALIZED t3 ALL NULL NULL NULL NULL 2 +2 DERIVED t1 ALL NULL NULL NULL NULL 2 +2 DERIVED t2 ALL NULL NULL NULL NULL 2 +SELECT * FROM (SELECT t1.* FROM t1, t2) t WHERE t.a IN (SELECT * FROM t3); +a +8 +8 +7 +7 +SELECT * FROM ( SELECT ta.* FROM t1 AS ta, t1 ) tb WHERE a IN ( SELECT * FROM t1 ); +a +8 +8 +7 +7 +SET SESSION 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_extra.result b/mysql-test/r/subselect_extra.result index c9f69c9e3c1..23c4849b120 100644 --- a/mysql-test/r/subselect_extra.result +++ b/mysql-test/r/subselect_extra.result @@ -432,7 +432,7 @@ WHERE t2.c = v1.c AND t2.c = v1.b AND v1.b = t3.c); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 system NULL NULL NULL NULL 1 1 PRIMARY t3 ALL NULL NULL NULL NULL 2 Using where -1 PRIMARY ALL NULL NULL NULL NULL 3 Using where; Start temporary; End temporary +1 PRIMARY ALL NULL NULL NULL NULL 3 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) 3 DERIVED t1 ALL NULL NULL NULL NULL 3 SELECT * FROM t3 WHERE t3.b IN (SELECT v1.b FROM v1, t2 diff --git a/mysql-test/suite/pbxt/r/derived.result b/mysql-test/suite/pbxt/r/derived.result index 1e4126315fb..d59316b04db 100644 --- a/mysql-test/suite/pbxt/r/derived.result +++ b/mysql-test/suite/pbxt/r/derived.result @@ -192,13 +192,13 @@ pla_id test explain SELECT STRAIGHT_JOIN d.pla_id, m2.mat_id FROM t1 m2 INNER JOIN (SELECT mp.pla_id, MIN(m1.matintnum) AS matintnum FROM t2 mp INNER JOIN t1 m1 ON mp.mat_id=m1.mat_id GROUP BY mp.pla_id) d ON d.matintnum=m2.matintnum; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY m2 ALL NULL NULL NULL NULL 9 -1 PRIMARY ALL NULL NULL NULL NULL 9 Using where +1 PRIMARY ALL NULL NULL NULL NULL 9 Using where; Using join buffer (flat, BNL join) 2 DERIVED mp ALL NULL NULL NULL NULL 9 Using temporary; Using filesort 2 DERIVED m1 eq_ref PRIMARY PRIMARY 3 test.mp.mat_id 1 explain SELECT STRAIGHT_JOIN d.pla_id, m2.test FROM t1 m2 INNER JOIN (SELECT mp.pla_id, MIN(m1.matintnum) AS matintnum FROM t2 mp INNER JOIN t1 m1 ON mp.mat_id=m1.mat_id GROUP BY mp.pla_id) d ON d.matintnum=m2.matintnum; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY m2 ALL NULL NULL NULL NULL 9 -1 PRIMARY ALL NULL NULL NULL NULL 9 Using where +1 PRIMARY ALL NULL NULL NULL NULL 9 Using where; Using join buffer (flat, BNL join) 2 DERIVED mp ALL NULL NULL NULL NULL 9 Using temporary; Using filesort 2 DERIVED m1 eq_ref PRIMARY PRIMARY 3 test.mp.mat_id 1 drop table t1,t2; diff --git a/mysql-test/t/join_cache.test b/mysql-test/t/join_cache.test index 66381150ede..ac92ff1631b 100644 --- a/mysql-test/t/join_cache.test +++ b/mysql-test/t/join_cache.test @@ -3294,5 +3294,34 @@ SET optimizer_switch=@tmp_optimizer_switch; DROP TABLE t1,t2,t3,t4; +--echo # +--echo # Bug #899509: an attempt to use hash join with join_cache_level=0 +--echo # + +CREATE TABLE t1 (a int); +INSERT INTO t1 VALUES (8), (7); +CREATE TABLE t2 (a int); +INSERT INTO t2 VALUES (8), (7); +CREATE TABLE t3 (a int); +INSERT INTO t3 VALUES (8), (7); + +SET @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch=default; +set @@optimizer_switch='semijoin_with_cache=off'; +set @@optimizer_switch='outer_join_with_cache=off'; +SET optimizer_switch='derived_merge=off,derived_with_keys=off'; +SET join_cache_level=0; + +EXPLAIN +SELECT * FROM (SELECT t1.* FROM t1, t2) t WHERE t.a IN (SELECT * FROM t3); +SELECT * FROM (SELECT t1.* FROM t1, t2) t WHERE t.a IN (SELECT * FROM t3); + +SELECT * FROM ( SELECT ta.* FROM t1 AS ta, t1 ) tb WHERE a IN ( SELECT * FROM t1 ); + +SET SESSION 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_select.cc b/sql/sql_select.cc index b0fd09b7f24..ba7ae875be9 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -5381,7 +5381,9 @@ best_access_path(JOIN *join, (1) s is inner table of semi-join -> join cache is allowed for semijoins (2) s is inner table of outer join -> join cache is allowed for outer joins */ - if (idx > join->const_tables && best_key == 0 && + if (idx > join->const_tables && best_key == 0 && + (join->allowed_join_cache_types & JOIN_CACHE_HASHED_BIT) && + join->max_allowed_join_cache_level > 2 && !bitmap_is_clear_all(eq_join_set) && !disable_jbuf && (!s->emb_sj_nest || join->allowed_semijoin_with_cache) && // (1) From 8e25dcfcd7bc1ccf9d65b2f12eba4543ed1bf9f4 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Wed, 7 Dec 2011 01:03:00 +0400 Subject: [PATCH 177/288] BUG#868908: Crash in check_simple_equality() with semijoin + materialization + prepared statement - Part 1 of the fix: for semi-join merged subqueries, calling child_join->optimize() until we're done with all PS-lifetime optimizations in the parent. --- mysql-test/r/subselect_mat.result | 23 +++++ mysql-test/r/subselect_sj_mat.result | 23 +++++ mysql-test/t/subselect_sj_mat.test | 23 +++++ sql/item_subselect.cc | 2 +- sql/item_subselect.h | 1 + sql/lock.cc | 10 ++- sql/opt_subselect.cc | 25 ++++-- sql/sql_lex.cc | 6 +- sql/sql_select.cc | 124 ++++++++++++++++++++++----- sql/table.cc | 2 + sql/table.h | 20 +++++ 11 files changed, 225 insertions(+), 34 deletions(-) diff --git a/mysql-test/r/subselect_mat.result b/mysql-test/r/subselect_mat.result index 8eaad6d8034..afd1b14b4e2 100644 --- a/mysql-test/r/subselect_mat.result +++ b/mysql-test/r/subselect_mat.result @@ -1728,6 +1728,29 @@ FROM t4 , t5 ); f1 f5 DROP TABLE t1, t2, t3, t4, t5; +# +# BUG#868908: Crash in check_simple_equality() with semijoin + materialization + prepared statement +# +CREATE TABLE t1 ( a int ); +CREATE TABLE t3 ( b int, c int) ; +CREATE TABLE t2 ( a int ) ; +CREATE TABLE t4 ( a int , c int) ; +PREPARE st1 FROM " +SELECT STRAIGHT_JOIN * +FROM t1 +WHERE ( 3 ) IN ( + SELECT t3.b + FROM t3 + LEFT JOIN ( + t2 STRAIGHT_JOIN t4 ON ( t4.c = t2.a ) + ) ON ( t4.a = t3.c ) +); +"; +EXECUTE st1; +a +EXECUTE st1; +a +DROP TABLE t1,t2,t3,t4; # This must be at the end: set optimizer_switch=@subselect_sj_mat_tmp; set @subselect_mat_test_optimizer_switch_value=null; diff --git a/mysql-test/r/subselect_sj_mat.result b/mysql-test/r/subselect_sj_mat.result index 472cadf04c4..7a6c4952091 100644 --- a/mysql-test/r/subselect_sj_mat.result +++ b/mysql-test/r/subselect_sj_mat.result @@ -1764,5 +1764,28 @@ FROM t4 , t5 ); f1 f5 DROP TABLE t1, t2, t3, t4, t5; +# +# BUG#868908: Crash in check_simple_equality() with semijoin + materialization + prepared statement +# +CREATE TABLE t1 ( a int ); +CREATE TABLE t3 ( b int, c int) ; +CREATE TABLE t2 ( a int ) ; +CREATE TABLE t4 ( a int , c int) ; +PREPARE st1 FROM " +SELECT STRAIGHT_JOIN * +FROM t1 +WHERE ( 3 ) IN ( + SELECT t3.b + FROM t3 + LEFT JOIN ( + t2 STRAIGHT_JOIN t4 ON ( t4.c = t2.a ) + ) ON ( t4.a = t3.c ) +); +"; +EXECUTE st1; +a +EXECUTE st1; +a +DROP TABLE t1,t2,t3,t4; # This must be at the end: set optimizer_switch=@subselect_sj_mat_tmp; diff --git a/mysql-test/t/subselect_sj_mat.test b/mysql-test/t/subselect_sj_mat.test index 4ddc19f49f5..fc3c7089db9 100644 --- a/mysql-test/t/subselect_sj_mat.test +++ b/mysql-test/t/subselect_sj_mat.test @@ -1427,7 +1427,30 @@ ON ( t2.f5 ) IN ( ); DROP TABLE t1, t2, t3, t4, t5; +--echo # +--echo # BUG#868908: Crash in check_simple_equality() with semijoin + materialization + prepared statement +--echo # +CREATE TABLE t1 ( a int ); +CREATE TABLE t3 ( b int, c int) ; +CREATE TABLE t2 ( a int ) ; +CREATE TABLE t4 ( a int , c int) ; + +PREPARE st1 FROM " +SELECT STRAIGHT_JOIN * +FROM t1 +WHERE ( 3 ) IN ( + SELECT t3.b + FROM t3 + LEFT JOIN ( + t2 STRAIGHT_JOIN t4 ON ( t4.c = t2.a ) + ) ON ( t4.a = t3.c ) +); +"; +EXECUTE st1; +EXECUTE st1; + +DROP TABLE t1,t2,t3,t4; --echo # This must be at the end: set optimizer_switch=@subselect_sj_mat_tmp; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 2baf530279f..f4dc7c6873a 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -616,7 +616,7 @@ int Item_in_subselect::optimize(double *out_rows, double *cost) thd->lex->current_select= join->select_lex; if ((res= join->optimize())) DBUG_RETURN(res); - +//psergey-todo: subq predicate can be made forced const! /* Calculate #rows and cost of join execution */ join->get_partial_cost_and_fanout(join->table_count - join->const_tables, table_map(-1), diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 28ce0061729..ae096ac1a39 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -449,6 +449,7 @@ public: double jtbm_read_time; double jtbm_record_count; bool is_jtbm_merged; + bool is_jtbm_const_tab; /* TRUE<=>this is a flattenable semi-join, false overwise. diff --git a/sql/lock.cc b/sql/lock.cc index 2dc6bc357f4..9fdb30eb1a0 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -866,8 +866,10 @@ MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, for (i=tables=lock_count=0 ; i < count ; i++) { TABLE *t= table_ptr[i]; - - if (t->s->tmp_table != NON_TRANSACTIONAL_TMP_TABLE) + + + if (t->s->tmp_table != NON_TRANSACTIONAL_TMP_TABLE && + t->s->tmp_table != INTERNAL_TMP_TABLE) { tables+= t->file->lock_count(); lock_count++; @@ -895,7 +897,9 @@ MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, TABLE *table; enum thr_lock_type lock_type; THR_LOCK_DATA **locks_start; - if ((table=table_ptr[i])->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE) + table= table_ptr[i]; + if (table->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE || + table->s->tmp_table == INTERNAL_TMP_TABLE) continue; lock_type= table->reginfo.lock_type; DBUG_ASSERT(lock_type != TL_WRITE_DEFAULT && lock_type != TL_READ_DEFAULT); diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index f065de31ac5..178d0bac3d3 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -1266,10 +1266,9 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred) List_iterator_fast si(subq_lex->leaf_tables); while ((tl= si++)) { - tl->table->tablenr= table_no; - tl->table->map= ((table_map)1) << table_no; + tl->set_tablenr(table_no); if (tl->is_jtbm()) - tl->jtbm_table_no= tl->table->tablenr; + tl->jtbm_table_no= table_no; SELECT_LEX *old_sl= tl->select_lex; tl->select_lex= parent_join->select_lex; for (TABLE_LIST *emb= tl->embedding; @@ -1430,21 +1429,22 @@ static bool convert_subq_to_jtbm(JOIN *parent_join, double rows; double read_time; DBUG_ENTER("convert_subq_to_jtbm"); - + bool optimization_delayed= TRUE; subq_pred->set_strategy(SUBS_MATERIALIZATION); - if (subq_pred->optimize(&rows, &read_time)) - DBUG_RETURN(TRUE); +// if (subq_pred->optimize(&rows, &read_time)) psergey-fix +// DBUG_RETURN(TRUE); subq_pred->jtbm_read_time= read_time; subq_pred->jtbm_record_count=rows; subq_pred->is_jtbm_merged= TRUE; +/* psergey-fix if (subq_pred->engine->engine_type() != subselect_engine::HASH_SJ_ENGINE) { *remove_item= FALSE; DBUG_RETURN(FALSE); } - +*/ *remove_item= TRUE; @@ -1481,7 +1481,18 @@ static bool convert_subq_to_jtbm(JOIN *parent_join, tl->next_local= jtbm; /* A theory: no need to re-connect the next_global chain */ + if (optimization_delayed) + { + DBUG_ASSERT(parent_join->table_count < MAX_TABLES); + jtbm->jtbm_table_no= parent_join->table_count; + + create_subquery_temptable_name(tbl_alias, + subq_pred->unit->first_select()->select_number); + jtbm->alias= tbl_alias; + parent_join->table_count++; + DBUG_RETURN(FALSE); + } subselect_hash_sj_engine *hash_sj_engine= ((subselect_hash_sj_engine*)subq_pred->engine); jtbm->table= hash_sj_engine->tmp_table; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 117a866555c..50eed3b34dc 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -3606,12 +3606,12 @@ bool st_select_lex::save_leaf_tables(THD *thd) { if (leaf_tables_exec.push_back(table)) return 1; - table->tablenr_exec= table->table->tablenr; - table->map_exec= table->table->map; + table->tablenr_exec= table->get_tablenr(); + table->map_exec= table->get_map(); if (join && (join->select_options & SELECT_DESCRIBE)) table->maybe_null_exec= 0; else - table->maybe_null_exec= table->table->maybe_null; + table->maybe_null_exec= table->table? table->table->maybe_null: 0; } if (arena) thd->restore_active_arena(arena, &backup); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 0ef417c9567..1c484b13233 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -798,6 +798,39 @@ err: } +/* + Create a dummy temporary table, useful only for the sake of having a + TABLE* object with map,tablenr and maybe_null properties. + + This is used by non-mergeable semi-join materilization code to handle + degenerate cases where materialized subquery produced "Impossible WHERE" + and thus wasn't materialized. +*/ + +TABLE *create_dummy_tmp_table(THD *thd) +{ + DBUG_ENTER("create_dummy_tmp_table"); + TABLE *table; + TMP_TABLE_PARAM sjm_table_param; + sjm_table_param.init(); + sjm_table_param.field_count= 1; + List sjm_table_cols; + Item *column_item= new Item_int(1); + sjm_table_cols.push_back(column_item); + if (!(table= create_tmp_table(thd, &sjm_table_param, + sjm_table_cols, (ORDER*) 0, + TRUE /* distinct */, + 1, /*save_sum_fields*/ + thd->options | TMP_TABLE_ALL_COLUMNS, + HA_POS_ERROR /*rows_limit */, + (char*)"dummy", TRUE /* Do not open */))) + { + DBUG_RETURN(NULL); + } + DBUG_RETURN(table); +} + + void inject_jtbm_conds(JOIN *join, List *join_list, Item **join_where) { @@ -817,29 +850,58 @@ inject_jtbm_conds(JOIN *join, List *join_list, Item **join_where) double rows; double read_time; - //DBUG_ASSERT(subq_pred->test_set_strategy(SUBS_MATERIALIZATION)); subq_pred->optimize(&rows, &read_time); - subq_pred->jtbm_read_time= read_time; subq_pred->jtbm_record_count=rows; subq_pred->is_jtbm_merged= TRUE; + JOIN *subq_join= subq_pred->unit->first_select()->join; + if (!subq_join->tables_list || !subq_join->table_count) + { + /* + This is an empty and constant table. - subselect_hash_sj_engine *hash_sj_engine= - ((subselect_hash_sj_engine*)item->engine); - - - //repeat of convert_subq_to_jtbm: - table->table= hash_sj_engine->tmp_table; - table->table->pos_in_table_list= table; + TODO: what if this is not empty but still constant? + + We'll need to check the equality but there's no materializatnion + table? - setup_table_map(table->table, table, table->jtbm_table_no); + A: create an IN-equality from + - left_expr + - right_expr. Q: how can right-expr exist in the context of + parent select? We don't have refs from outside to inside! + A: create/check in the context of the child select? + + for injection, check how in->exists is performed. + */ + subq_pred->is_jtbm_const_tab= TRUE; - Item *sj_conds= hash_sj_engine->semi_join_conds; + TABLE *dummy_table= create_dummy_tmp_table(join->thd); + table->table= dummy_table; + table->table->pos_in_table_list= table; - (*join_where)= and_items(*join_where, sj_conds); - if (!(*join_where)->fixed) - (*join_where)->fix_fields(join->thd, join_where); - //parent_join->select_lex->where= parent_join->conds; + setup_table_map(table->table, table, table->jtbm_table_no); + + } + else + { + DBUG_ASSERT(subq_pred->test_set_strategy(SUBS_MATERIALIZATION)); + subq_pred->is_jtbm_const_tab= FALSE; + subselect_hash_sj_engine *hash_sj_engine= + ((subselect_hash_sj_engine*)item->engine); + + //repeat of convert_subq_to_jtbm: + table->table= hash_sj_engine->tmp_table; + table->table->pos_in_table_list= table; + + setup_table_map(table->table, table, table->jtbm_table_no); + + Item *sj_conds= hash_sj_engine->semi_join_conds; + + (*join_where)= and_items(*join_where, sj_conds); + if (!(*join_where)->fixed) + (*join_where)->fix_fields(join->thd, join_where); + //parent_join->select_lex->where= parent_join->conds; + } } if ((nested_join= table->nested_join)) @@ -3120,6 +3182,14 @@ make_join_statistics(JOIN *join, List &tables_list, set_position(join,const_count++,s,(KEYUSE*) 0); no_rows_const_tables |= table->map; } + + /* SJ-Materialization handling: */ + if (table->pos_in_table_list->jtbm_subselect && + table->pos_in_table_list->jtbm_subselect->is_jtbm_const_tab) + { + set_position(join,const_count++,s,(KEYUSE*) 0); + no_rows_const_tables |= table->map; + } } stat_vector[i]=0; @@ -9629,8 +9699,16 @@ void JOIN_TAB::cleanup() if (table->pos_in_table_list && table->pos_in_table_list->jtbm_subselect) { - end_read_record(&read_record); - table->pos_in_table_list->jtbm_subselect->cleanup(); + if (table->pos_in_table_list->jtbm_subselect->is_jtbm_const_tab) + { + free_tmp_table(join->thd, table); + table= NULL; + } + else + { + end_read_record(&read_record); + table->pos_in_table_list->jtbm_subselect->cleanup(); + } DBUG_VOID_RETURN; } /* @@ -11904,7 +11982,7 @@ simplify_joins(JOIN *join, List *join_list, COND *conds, bool top, { if (!table->prep_on_expr) table->prep_on_expr= table->on_expr; - used_tables= table->table->map; + used_tables= table->get_map(); if (conds) not_null_tables= conds->not_null_tables(); } @@ -11961,7 +12039,7 @@ simplify_joins(JOIN *join, List *join_list, COND *conds, bool top, table->embedding->on_expr_dep_tables|= table->on_expr->used_tables(); } else - table->dep_tables&= ~table->table->map; + table->dep_tables&= ~table->get_map(); } if (prev_table) @@ -11974,7 +12052,7 @@ simplify_joins(JOIN *join, List *join_list, COND *conds, bool top, prev_table->dep_tables|= table->on_expr_dep_tables; table_map prev_used_tables= prev_table->nested_join ? prev_table->nested_join->used_tables : - prev_table->table->map; + prev_table->get_map(); /* If on expression contains only references to inner tables we still make the inner tables dependent on the outer tables. @@ -15525,6 +15603,12 @@ join_read_const_table(JOIN_TAB *tab, POSITION *pos) /* Skip materialized derived tables/views. */ DBUG_RETURN(0); } + else if (tab->table->pos_in_table_list->jtbm_subselect && + tab->table->pos_in_table_list->jtbm_subselect->is_jtbm_const_tab) + { + /* Row will not be found */ + DBUG_RETURN(-1); + } else if (tab->type == JT_SYSTEM) { if ((error=join_read_system(tab))) diff --git a/sql/table.cc b/sql/table.cc index 23c43f91d22..28c45a77396 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -5922,6 +5922,8 @@ bool TABLE_LIST::init_derived(THD *thd, bool init_view) int TABLE_LIST::fetch_number_of_rows() { int error= 0; + if (jtbm_subselect) /* psergey-todo: how did we work before? */ + return 0; /*psergey-todo: check if we still need to set it? */ if (is_materialized_derived() && !fill_me) { diff --git a/sql/table.h b/sql/table.h index 5dd464ac876..376aa9824dc 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1377,6 +1377,26 @@ struct TABLE_LIST select_union *derived_result; /* Stub used for materialized derived tables. */ table_map map; /* ID bit of table (1,2,4,8,16...) */ + table_map get_map() + { + return jtbm_subselect? table_map(1) << jtbm_table_no : table->map; + } + uint get_tablenr() + { + return jtbm_subselect? jtbm_table_no : table->tablenr; + } + void set_tablenr(uint new_tablenr) + { + if (jtbm_subselect) + { + jtbm_table_no= new_tablenr; + } + if (table) + { + table->tablenr= new_tablenr; + table->map= table_map(1) << new_tablenr; + } + } /* Reference from aux_tables to local list entry of main select of multi-delete statement: From 7414a0b6d6307f8c2644660cf2f8daf986c25970 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Tue, 6 Dec 2011 13:42:18 -0800 Subject: [PATCH 178/288] Fixed LP bug #900469. The execution plan cannot use sorting on the first table from the sequence of the joined tables if it plans to employ the block-based hash join algorithm. --- mysql-test/r/join_cache.result | 49 ++++++++++++++++++++++++++++++++++ mysql-test/t/join_cache.test | 38 ++++++++++++++++++++++++++ sql/sql_select.cc | 8 +++++- sql/sql_select.h | 1 + 4 files changed, 95 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/join_cache.result b/mysql-test/r/join_cache.result index ef5c0a66130..6dbaa5a93a0 100644 --- a/mysql-test/r/join_cache.result +++ b/mysql-test/r/join_cache.result @@ -5264,4 +5264,53 @@ a SET SESSION join_cache_level = DEFAULT; SET optimizer_switch=@tmp_optimizer_switch; DROP TABLE t1,t2,t3; +# +# Bug #900469: semijoin + BNLH + ORDER BY +# +CREATE TABLE t1 (a int, b int); +INSERT INTO t1 VALUES (8,10); +CREATE TABLE t2 (c int, d int); +INSERT INTO t2 VALUES (8,10); +INSERT INTO t2 VALUES (9,11); +CREATE TABLE t3 (c int, d int); +INSERT INTO t3 VALUES (8,10); +INSERT INTO t3 VALUES (9,11); +SET @tmp_optimizer_switch=@@optimizer_switch; +set @@optimizer_switch='semijoin_with_cache=on'; +SET join_cache_level=1; +EXPLAIN +SELECT * FROM t1,t2 WHERE b IN (SELECT d FROM t3 WHERE c <= t2.c) ORDER BY a,d; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 system NULL NULL NULL NULL 1 Using temporary; Using filesort +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 +1 PRIMARY t3 ALL NULL NULL NULL NULL 2 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) +SELECT * FROM t1,t2 WHERE b IN (SELECT d FROM t3 WHERE c <= t2.c) ORDER BY a,d; +a b c d +8 10 8 10 +8 10 9 11 +SET join_cache_level=3; +EXPLAIN +SELECT * FROM t1,t2 WHERE b IN (SELECT d FROM t3 WHERE c <= t2.c); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 system NULL NULL NULL NULL 1 +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 +1 PRIMARY t3 hash_ALL NULL #hash#$hj 5 const 2 Using where; Start temporary; End temporary; Using join buffer (flat, BNLH join) +SELECT * FROM t1,t2 WHERE b IN (SELECT d FROM t3 WHERE c <= t2.c); +a b c d +8 10 8 10 +8 10 9 11 +SET join_cache_level=3; +EXPLAIN +SELECT * FROM t1,t2 WHERE b IN (SELECT d FROM t3 WHERE c <= t2.c) ORDER BY a,d; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 system NULL NULL NULL NULL 1 Using temporary; Using filesort +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 +1 PRIMARY t3 hash_ALL NULL #hash#$hj 5 const 2 Using where; Start temporary; End temporary; Using join buffer (flat, BNLH join) +SELECT * FROM t1,t2 WHERE b IN (SELECT d FROM t3 WHERE c <= t2.c) ORDER BY a,d; +a b c d +8 10 8 10 +8 10 9 11 +SET SESSION 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 ac92ff1631b..ef64e8caea1 100644 --- a/mysql-test/t/join_cache.test +++ b/mysql-test/t/join_cache.test @@ -3323,5 +3323,43 @@ SET optimizer_switch=@tmp_optimizer_switch; DROP TABLE t1,t2,t3; +--echo # +--echo # Bug #900469: semijoin + BNLH + ORDER BY +--echo # + +CREATE TABLE t1 (a int, b int); +INSERT INTO t1 VALUES (8,10); + +CREATE TABLE t2 (c int, d int); +INSERT INTO t2 VALUES (8,10); +INSERT INTO t2 VALUES (9,11); + +CREATE TABLE t3 (c int, d int); +INSERT INTO t3 VALUES (8,10); +INSERT INTO t3 VALUES (9,11); + +SET @tmp_optimizer_switch=@@optimizer_switch; +set @@optimizer_switch='semijoin_with_cache=on'; + +SET join_cache_level=1; +EXPLAIN +SELECT * FROM t1,t2 WHERE b IN (SELECT d FROM t3 WHERE c <= t2.c) ORDER BY a,d; +SELECT * FROM t1,t2 WHERE b IN (SELECT d FROM t3 WHERE c <= t2.c) ORDER BY a,d; + +SET join_cache_level=3; +EXPLAIN +SELECT * FROM t1,t2 WHERE b IN (SELECT d FROM t3 WHERE c <= t2.c); +SELECT * FROM t1,t2 WHERE b IN (SELECT d FROM t3 WHERE c <= t2.c); + +SET join_cache_level=3; +EXPLAIN +SELECT * FROM t1,t2 WHERE b IN (SELECT d FROM t3 WHERE c <= t2.c) ORDER BY a,d; +SELECT * FROM t1,t2 WHERE b IN (SELECT d FROM t3 WHERE c <= t2.c) ORDER BY a,d; + +SET SESSION 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_select.cc b/sql/sql_select.cc index ba7ae875be9..03ba5bb7790 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1448,7 +1448,7 @@ JOIN::optimize() order=0; // Can't use sort on head table if using join buffering - if (full_join) + if (full_join || hash_join) { TABLE *stable= (sort_by_table == (TABLE *) 1 ? join_tab[const_tables].table : sort_by_table); @@ -7036,6 +7036,7 @@ get_best_combination(JOIN *join) DBUG_RETURN(TRUE); join->full_join=0; + join->hash_join= FALSE; used_tables= OUTER_REF_TABLE_BIT; // Outer row is already read @@ -7125,6 +7126,11 @@ get_best_combination(JOIN *join) } else if (create_ref_for_key(join, j, keyuse, used_tables)) DBUG_RETURN(TRUE); // Something went wrong + + if ((j->type == JT_REF || j->type == JT_EQ_REF) && + is_hash_join_key_no(j->ref.key)) + join->hash_join= TRUE; + loop_end: /* Save records_read in JOIN_TAB so that select_describe()/etc don't have diff --git a/sql/sql_select.h b/sql/sql_select.h index ffe3985c3c3..e24cab714fd 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -912,6 +912,7 @@ public: */ bool sort_and_group; bool first_record,full_join, no_field_update; + bool hash_join; bool do_send_rows; /** TRUE when we want to resume nested loop iterations when From 358a31df435d2e18f93a48be76bc2224e479948a Mon Sep 17 00:00:00 2001 From: Inaam Rana Date: Wed, 7 Dec 2011 09:12:53 -0500 Subject: [PATCH 179/288] Bug#11759044 - 51325: DROPPING AN EMPTY INNODB TABLE TAKES A LONG TIME WITH LARGE BUFFER POOL (Note: this a backport of revno:3472 from mysql-trunk) rb://845 approved by: Marko When dropping a table (with an .ibd file i.e.: with innodb_file_per_table set) we scan entire LRU to invalidate pages from that table. This can be painful in case of large buffer pools as we hold the buf_pool->mutex for the scan. Note that gravity of the problem does not depend on the size of the table. Even with an empty table but a large and filled up buffer pool we'll end up scanning a very long LRU list. The fix is to scan flush_list and just remove the blocks belonging to the table from the flush_list, marking them as non-dirty. The blocks are left in the LRU list for eventual eviction due to aging. The flush_list is typically much smaller than the LRU list but for cases where it is very long we have the solution of releasing the buf_pool->mutex after scanning 1K pages. buf_page_[set|unset]_sticky(): Use new IO-state BUF_IO_PIN to ensure that a block stays in the flush_list and LRU list when we release buf_pool->mutex. Previously we have been abusing BUF_IO_READ to achieve this. --- .../innodb/r/innodb_cmp_drop_table.result | 1 + .../suite/innodb/t/innodb_cmp_drop_table.test | 4 +- storage/innobase/buf/buf0buf.c | 5 + storage/innobase/buf/buf0lru.c | 167 ++++++++++-------- storage/innobase/include/buf0buf.h | 22 ++- storage/innobase/include/buf0buf.ic | 44 +++++ storage/innobase/include/buf0types.h | 5 +- 7 files changed, 166 insertions(+), 82 deletions(-) diff --git a/mysql-test/suite/innodb/r/innodb_cmp_drop_table.result b/mysql-test/suite/innodb/r/innodb_cmp_drop_table.result index bae2a17bd02..1f6d6948756 100644 --- a/mysql-test/suite/innodb/r/innodb_cmp_drop_table.result +++ b/mysql-test/suite/innodb/r/innodb_cmp_drop_table.result @@ -7,6 +7,7 @@ page_size drop table t1; SELECT page_size FROM information_schema.innodb_cmpmem WHERE pages_used > 0; page_size +8192 create table t2(a text) engine=innodb; SELECT page_size FROM information_schema.innodb_cmpmem WHERE pages_used > 0; page_size diff --git a/mysql-test/suite/innodb/t/innodb_cmp_drop_table.test b/mysql-test/suite/innodb/t/innodb_cmp_drop_table.test index 481ccd646f8..92f4f715241 100644 --- a/mysql-test/suite/innodb/t/innodb_cmp_drop_table.test +++ b/mysql-test/suite/innodb/t/innodb_cmp_drop_table.test @@ -26,7 +26,7 @@ while ($i) drop table t1; -# no lazy eviction at drop table in 5.1 and 5.5 there should be no +# because of lazy eviction at drop table in 5.5 there should be some # used 8K pages -- eval $query_i_s @@ -36,7 +36,7 @@ create table t2(a text) engine=innodb; -- disable_query_log --- let $i = 200 +-- let $i = 400 while ($i) { insert into t2 values(repeat('abcdefghijklmnopqrstuvwxyz',1000)); diff --git a/storage/innobase/buf/buf0buf.c b/storage/innobase/buf/buf0buf.c index fbb6fecadf6..c3191e677f7 100644 --- a/storage/innobase/buf/buf0buf.c +++ b/storage/innobase/buf/buf0buf.c @@ -3888,6 +3888,9 @@ buf_pool_validate_instance( ut_a(rw_lock_is_locked(&block->lock, RW_LOCK_EX)); break; + + case BUF_IO_PIN: + break; } n_lru++; @@ -3917,6 +3920,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: @@ -3956,6 +3960,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/storage/innobase/buf/buf0lru.c b/storage/innobase/buf/buf0lru.c index 510f6eefba5..15b0ad40aaa 100644 --- a/storage/innobase/buf/buf0lru.c +++ b/storage/innobase/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 */ @@ -210,7 +214,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, @@ -244,7 +248,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); num_entries = 0; @@ -283,10 +287,10 @@ next_page: /* Store the page number so that we can drop the hash index in a batch later. */ page_arr[num_entries] = bpage->offset; - 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; } @@ -331,37 +335,40 @@ 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); + 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(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 @@ -374,79 +381,83 @@ scan_again: all_freed = FALSE; goto next_page; - } else { - block_mutex = buf_page_get_mutex(bpage); - mutex_enter(block_mutex); - - 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)); - -#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)); - } -#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)->index) { - ulint page_no; - ulint zip_size; - - buf_pool_mutex_exit(buf_pool); - - zip_size = buf_page_get_zip_size(bpage); - page_no = buf_page_get_page_no(bpage); + /* 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(bpage); + mutex_enter(block_mutex); + if (bpage->buf_fix_count > 0) { mutex_exit(block_mutex); + buf_flush_list_mutex_enter(buf_pool); - /* Note that the following call will acquire - and release an X-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); - 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); + os_thread_yield(); + buf_pool_mutex_enter(buf_pool); + + 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_flush_list_mutex_exit(buf_pool); + + ut_ad(buf_flush_validate(buf_pool)); if (!all_freed) { os_thread_sleep(20000); @@ -477,7 +488,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); } } @@ -1532,8 +1543,9 @@ alloc: /* 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; + mutex_enter(&buf_pool->zip_mutex); + buf_page_set_sticky(b); + mutex_exit(&buf_pool->zip_mutex); } buf_pool_mutex_exit(buf_pool); @@ -1573,8 +1585,7 @@ alloc: 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/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h index c0ff7b1766b..456f077a13d 100644 --- a/storage/innobase/include/buf0buf.h +++ b/storage/innobase/include/buf0buf.h @@ -910,7 +910,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. */ diff --git a/storage/innobase/include/buf0buf.ic b/storage/innobase/include/buf0buf.ic index b65b5133c15..99e55df3312 100644 --- a/storage/innobase/include/buf0buf.ic +++ b/storage/innobase/include/buf0buf.ic @@ -414,6 +414,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; @@ -464,6 +465,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(buf_pool_mutex_own(buf_pool)); +#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(buf_pool_mutex_own(buf_pool)); +#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/storage/innobase/include/buf0types.h b/storage/innobase/include/buf0types.h index 0cc2defb3ff..12b9e22f673 100644 --- a/storage/innobase/include/buf0types.h +++ b/storage/innobase/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) */ From a1b4eadf89a3940b80a6ed0eadd15ba456c2fa7a Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Wed, 7 Dec 2011 19:21:51 +0400 Subject: [PATCH 180/288] BUG#868908: Crash in check_simple_equality() with semijoin + materialization + prepared statement - Part2: safety and code cleanup --- sql/item_subselect.cc | 7 +++++-- sql/item_subselect.h | 2 +- sql/opt_subselect.cc | 10 ---------- sql/sql_select.cc | 11 ++++------- sql/table.cc | 4 ++-- 5 files changed, 12 insertions(+), 22 deletions(-) diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index f4dc7c6873a..a9488cc08c0 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -616,7 +616,7 @@ int Item_in_subselect::optimize(double *out_rows, double *cost) thd->lex->current_select= join->select_lex; if ((res= join->optimize())) DBUG_RETURN(res); -//psergey-todo: subq predicate can be made forced const! + /* Calculate #rows and cost of join execution */ join->get_partial_cost_and_fanout(join->table_count - join->const_tables, table_map(-1), @@ -1197,7 +1197,8 @@ Item_in_subselect::Item_in_subselect(Item * left_exp, Item_exists_subselect(), left_expr_cache(0), first_execution(TRUE), in_strategy(SUBS_NOT_TRANSFORMED), optimizer(0), pushed_cond_guards(NULL), emb_on_expr_nest(NULL), - is_jtbm_merged(FALSE), is_flattenable_semijoin(FALSE), + is_jtbm_merged(FALSE), is_jtbm_const_tab(FALSE), + is_flattenable_semijoin(FALSE), is_registered_semijoin(FALSE), upper_item(0) { @@ -4182,6 +4183,8 @@ bool subselect_hash_sj_engine::init(List *tmp_columns, uint subquery_id) */ if (tmp_table->s->keys == 0) { + //fprintf(stderr, "Q: %s\n", current_thd->query()); + DBUG_ASSERT(0); DBUG_ASSERT( tmp_table->s->uniques || tmp_table->key_info->key_length >= tmp_table->file->max_key_length() || diff --git a/sql/item_subselect.h b/sql/item_subselect.h index ae096ac1a39..880b505a8d1 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -491,7 +491,7 @@ public: :Item_exists_subselect(), left_expr_cache(0), first_execution(TRUE), abort_on_null(0), in_strategy(SUBS_NOT_TRANSFORMED), optimizer(0), pushed_cond_guards(NULL), func(NULL), emb_on_expr_nest(NULL), - is_jtbm_merged(FALSE), + is_jtbm_merged(FALSE), is_jtbm_const_tab(FALSE), upper_item(0) {} void cleanup(); diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index 178d0bac3d3..82309c8cece 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -1431,21 +1431,11 @@ static bool convert_subq_to_jtbm(JOIN *parent_join, DBUG_ENTER("convert_subq_to_jtbm"); bool optimization_delayed= TRUE; subq_pred->set_strategy(SUBS_MATERIALIZATION); -// if (subq_pred->optimize(&rows, &read_time)) psergey-fix -// DBUG_RETURN(TRUE); subq_pred->jtbm_read_time= read_time; subq_pred->jtbm_record_count=rows; subq_pred->is_jtbm_merged= TRUE; -/* psergey-fix - if (subq_pred->engine->engine_type() != subselect_engine::HASH_SJ_ENGINE) - { - *remove_item= FALSE; - DBUG_RETURN(FALSE); - } -*/ - *remove_item= TRUE; TABLE_LIST *jtbm; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 1c484b13233..5af287fbed0 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -832,12 +832,12 @@ TABLE *create_dummy_tmp_table(THD *thd) void -inject_jtbm_conds(JOIN *join, List *join_list, Item **join_where) +setup_jtbm_semi_joins(JOIN *join, List *join_list, Item **join_where) { TABLE_LIST *table; NESTED_JOIN *nested_join; List_iterator li(*join_list); - DBUG_ENTER("inject_jtbm_conds"); + DBUG_ENTER("setup_jtbm_semi_joins"); while ((table= li++)) @@ -880,7 +880,6 @@ inject_jtbm_conds(JOIN *join, List *join_list, Item **join_where) table->table->pos_in_table_list= table; setup_table_map(table->table, table, table->jtbm_table_no); - } else { @@ -889,7 +888,6 @@ inject_jtbm_conds(JOIN *join, List *join_list, Item **join_where) subselect_hash_sj_engine *hash_sj_engine= ((subselect_hash_sj_engine*)item->engine); - //repeat of convert_subq_to_jtbm: table->table= hash_sj_engine->tmp_table; table->table->pos_in_table_list= table; @@ -900,13 +898,12 @@ inject_jtbm_conds(JOIN *join, List *join_list, Item **join_where) (*join_where)= and_items(*join_where, sj_conds); if (!(*join_where)->fixed) (*join_where)->fix_fields(join->thd, join_where); - //parent_join->select_lex->where= parent_join->conds; } } if ((nested_join= table->nested_join)) { - inject_jtbm_conds(join, &nested_join->join_list, join_where); + setup_jtbm_semi_joins(join, &nested_join->join_list, join_where); } } DBUG_VOID_RETURN; @@ -1036,7 +1033,7 @@ JOIN::optimize() thd->restore_active_arena(arena, &backup); } - inject_jtbm_conds(this, join_list, &conds); + setup_jtbm_semi_joins(this, join_list, &conds); conds= optimize_cond(this, conds, join_list, &cond_value, &cond_equal); diff --git a/sql/table.cc b/sql/table.cc index 28c45a77396..5c0d4a81384 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -5922,8 +5922,8 @@ bool TABLE_LIST::init_derived(THD *thd, bool init_view) int TABLE_LIST::fetch_number_of_rows() { int error= 0; - if (jtbm_subselect) /* psergey-todo: how did we work before? */ - return 0; /*psergey-todo: check if we still need to set it? */ + if (jtbm_subselect) + return 0; if (is_materialized_derived() && !fill_me) { From cdd1197060c1adb458131c9d9ec2d66dbe945864 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Wed, 7 Dec 2011 23:15:57 +0400 Subject: [PATCH 181/288] Remove garbage assignments causing failures on Windows --- sql/opt_subselect.cc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index 82309c8cece..233305f3da6 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -1426,14 +1426,10 @@ static bool convert_subq_to_jtbm(JOIN *parent_join, List *emb_join_list= &parent_lex->top_join_list; TABLE_LIST *emb_tbl_nest= NULL; // will change when we learn to handle outer joins TABLE_LIST *tl; - double rows; - double read_time; DBUG_ENTER("convert_subq_to_jtbm"); bool optimization_delayed= TRUE; subq_pred->set_strategy(SUBS_MATERIALIZATION); - subq_pred->jtbm_read_time= read_time; - subq_pred->jtbm_record_count=rows; subq_pred->is_jtbm_merged= TRUE; *remove_item= TRUE; From 49ecc880699b9627a1fbec8fa5c4d025ccb9a7cf Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Thu, 8 Dec 2011 02:12:48 +0400 Subject: [PATCH 182/288] BUG#901032: Wrong result for MIN/MAX on an indexed column with materialization and semijoin - opt_sum_query() should not assume that join tables from sj-materialization have known numbers of rows. --- mysql-test/r/subselect_mat.result | 13 +++++++++++++ mysql-test/r/subselect_sj_mat.result | 13 +++++++++++++ mysql-test/t/subselect_sj_mat.test | 13 +++++++++++++ sql/opt_sum.cc | 3 ++- 4 files changed, 41 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/subselect_mat.result b/mysql-test/r/subselect_mat.result index 31a9227ab0f..f8bafa03bed 100644 --- a/mysql-test/r/subselect_mat.result +++ b/mysql-test/r/subselect_mat.result @@ -1728,6 +1728,19 @@ FROM t4 , t5 ); f1 f5 DROP TABLE t1, t2, t3, t4, t5; +# +# BUG#901032: Wrong result for MIN/MAX on an indexed column with materialization and semijoin +# +CREATE TABLE t1 ( a INT, KEY(a) ); +INSERT INTO t1 VALUES (1); +CREATE TABLE t2 ( b INT ); +INSERT INTO t2 VALUES (2); +CREATE TABLE t3 ( c INT ); +INSERT INTO t3 VALUES (2); +SELECT MIN(a) FROM t1, t2 WHERE b IN (SELECT c FROM t3 GROUP BY c); +MIN(a) +1 +DROP TABLE t1,t2,t3; # This must be at the end: set optimizer_switch=@subselect_sj_mat_tmp; set @subselect_mat_test_optimizer_switch_value=null; diff --git a/mysql-test/r/subselect_sj_mat.result b/mysql-test/r/subselect_sj_mat.result index b578749b862..1b3793bed42 100644 --- a/mysql-test/r/subselect_sj_mat.result +++ b/mysql-test/r/subselect_sj_mat.result @@ -1764,5 +1764,18 @@ FROM t4 , t5 ); f1 f5 DROP TABLE t1, t2, t3, t4, t5; +# +# BUG#901032: Wrong result for MIN/MAX on an indexed column with materialization and semijoin +# +CREATE TABLE t1 ( a INT, KEY(a) ); +INSERT INTO t1 VALUES (1); +CREATE TABLE t2 ( b INT ); +INSERT INTO t2 VALUES (2); +CREATE TABLE t3 ( c INT ); +INSERT INTO t3 VALUES (2); +SELECT MIN(a) FROM t1, t2 WHERE b IN (SELECT c FROM t3 GROUP BY c); +MIN(a) +1 +DROP TABLE t1,t2,t3; # This must be at the end: set optimizer_switch=@subselect_sj_mat_tmp; diff --git a/mysql-test/t/subselect_sj_mat.test b/mysql-test/t/subselect_sj_mat.test index 4ddc19f49f5..c2badddba5b 100644 --- a/mysql-test/t/subselect_sj_mat.test +++ b/mysql-test/t/subselect_sj_mat.test @@ -1428,6 +1428,19 @@ ON ( t2.f5 ) IN ( DROP TABLE t1, t2, t3, t4, t5; +--echo # +--echo # BUG#901032: Wrong result for MIN/MAX on an indexed column with materialization and semijoin +--echo # +CREATE TABLE t1 ( a INT, KEY(a) ); +INSERT INTO t1 VALUES (1); +CREATE TABLE t2 ( b INT ); +INSERT INTO t2 VALUES (2); +CREATE TABLE t3 ( c INT ); +INSERT INTO t3 VALUES (2); + +SELECT MIN(a) FROM t1, t2 WHERE b IN (SELECT c FROM t3 GROUP BY c); + +DROP TABLE t1,t2,t3; --echo # This must be at the end: set optimizer_switch=@subselect_sj_mat_tmp; diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc index 7b4c48497fa..6e293e8b686 100644 --- a/sql/opt_sum.cc +++ b/sql/opt_sum.cc @@ -299,7 +299,8 @@ int opt_sum_query(THD *thd, is_exact_count= FALSE; count= 1; // ensure count != 0 } - else if (tl->is_materialized_derived()) + else if (tl->is_materialized_derived() || + tl->jtbm_subselect) { /* Can't remove a derived table as it's number of rows is just an From ae480437ce98bbba8624e52833b8edbcc495b014 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Thu, 8 Dec 2011 04:22:38 +0400 Subject: [PATCH 183/288] Small semi-join optimization improvement: - if we're considering FirstMatch access with one inner table, and @@optimizer_switch has semijoin_with_cache flag, calculate costs as if we used join cache (because we will be able to do so) --- mysql-test/r/subselect.result | 4 ++-- mysql-test/r/subselect3.result | 6 +++--- mysql-test/r/subselect3_jcl6.result | 10 ++++----- mysql-test/r/subselect4.result | 8 ++++---- mysql-test/r/subselect_extra.result | 13 ++++++------ mysql-test/r/subselect_no_mat.result | 4 ++-- mysql-test/r/subselect_no_scache.result | 4 ++-- mysql-test/r/subselect_sj2_jcl6.result | 3 +-- mysql-test/r/subselect_sj_jcl6.result | 27 ++++++++++--------------- sql/opt_subselect.cc | 26 ++++++++++++++++++------ 10 files changed, 56 insertions(+), 49 deletions(-) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 0a4a16962ff..a31a6b6c3cf 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -5205,8 +5205,8 @@ INSERT INTO t2 VALUES (15,4); EXPLAIN SELECT * FROM t1 WHERE pk IN (SELECT it.pk FROM t2 JOIN t2 AS it ON 1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL PRIMARY NULL NULL NULL 3 -1 PRIMARY t2 index NULL PRIMARY 4 NULL 3 Using index; Start temporary; Using join buffer (flat, BNL join) -1 PRIMARY it eq_ref PRIMARY PRIMARY 4 test.t1.pk 1 Using index; End temporary +1 PRIMARY it eq_ref PRIMARY PRIMARY 4 test.t1.pk 1 Using index +1 PRIMARY t2 index NULL PRIMARY 4 NULL 3 Using index; FirstMatch(it); Using join buffer (flat, BNL join) SELECT * FROM t1 WHERE pk IN (SELECT it.pk FROM t2 JOIN t2 AS it ON 1); pk i 11 0 diff --git a/mysql-test/r/subselect3.result b/mysql-test/r/subselect3.result index 898eed164b7..7d13bce1f85 100644 --- a/mysql-test/r/subselect3.result +++ b/mysql-test/r/subselect3.result @@ -105,7 +105,7 @@ oref a 1 1 show status like '%Handler_read_rnd_next'; Variable_name Value -Handler_read_rnd_next 14 +Handler_read_rnd_next 5 delete from t2; insert into t2 values (NULL, 0),(NULL, 0), (NULL, 0), (NULL, 0); set optimizer_switch='subquery_cache=off'; @@ -1308,7 +1308,7 @@ insert into t1 select * from t0; explain select * from t0 where a in (select a from t1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t0 ALL NULL NULL NULL NULL 2 -1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where; FirstMatch(t0); Using join buffer (flat, BNL join) select * from t0 where a in (select a from t1); a 10.24 @@ -1321,7 +1321,7 @@ insert into t1 select * from t0; explain select * from t0 where a in (select a from t1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t0 ALL NULL NULL NULL NULL 2 -1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where; FirstMatch(t0); Using join buffer (flat, BNL join) select * from t0 where a in (select a from t1); a 2008-01-01 diff --git a/mysql-test/r/subselect3_jcl6.result b/mysql-test/r/subselect3_jcl6.result index 59750f2cfa0..5ad5878623d 100644 --- a/mysql-test/r/subselect3_jcl6.result +++ b/mysql-test/r/subselect3_jcl6.result @@ -114,7 +114,7 @@ oref a 1 1 show status like '%Handler_read_rnd_next'; Variable_name Value -Handler_read_rnd_next 14 +Handler_read_rnd_next 5 delete from t2; insert into t2 values (NULL, 0),(NULL, 0), (NULL, 0), (NULL, 0); set optimizer_switch='subquery_cache=off'; @@ -1316,8 +1316,8 @@ create table t1 as select * from t0; insert into t1 select * from t0; explain select * from t0 where a in (select a from t1); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t0 ALL NULL NULL NULL NULL 2 Using where -1 PRIMARY t1 hash_ALL NULL #hash#$hj 3 test.t0.a 4 Using where; Start temporary; End temporary; Using join buffer (flat, BNLH join) +1 PRIMARY t0 ALL NULL NULL NULL NULL 2 +1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where; FirstMatch(t0); Using join buffer (flat, BNL join) select * from t0 where a in (select a from t1); a 10.24 @@ -1329,8 +1329,8 @@ create table t1 as select * from t0; insert into t1 select * from t0; explain select * from t0 where a in (select a from t1); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t0 ALL NULL NULL NULL NULL 2 Using where -1 PRIMARY t1 hash_ALL NULL #hash#$hj 4 test.t0.a 4 Using where; Start temporary; End temporary; Using join buffer (flat, BNLH join) +1 PRIMARY t0 ALL NULL NULL NULL NULL 2 +1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where; FirstMatch(t0); Using join buffer (flat, BNL join) select * from t0 where a in (select a from t1); a 2008-01-01 diff --git a/mysql-test/r/subselect4.result b/mysql-test/r/subselect4.result index 76496d73ef9..f830be38321 100644 --- a/mysql-test/r/subselect4.result +++ b/mysql-test/r/subselect4.result @@ -1230,16 +1230,16 @@ EXPLAIN SELECT * FROM t1 RIGHT JOIN t2 ON t1.c1 WHERE 's' IN (SELECT c1 FROM t2); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 0 const row not found -1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where; FirstMatch(t1) -1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using join buffer (flat, BNL join) +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where; FirstMatch(t2); Using join buffer (flat, BNL join) SELECT * FROM t1 RIGHT JOIN t2 ON t1.c1 WHERE 's' IN (SELECT c1 FROM t2); c1 c1 EXPLAIN SELECT * FROM t2 LEFT JOIN t1 ON t1.c1 WHERE 's' IN (SELECT c1 FROM t2); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 0 const row not found -1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where; FirstMatch(t1) -1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using join buffer (flat, BNL join) +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where; FirstMatch(t2); Using join buffer (flat, BNL join) SELECT * FROM t2 LEFT JOIN t1 ON t1.c1 WHERE 's' IN (SELECT c1 FROM t2); c1 c1 EXPLAIN diff --git a/mysql-test/r/subselect_extra.result b/mysql-test/r/subselect_extra.result index 23c4849b120..9246128391e 100644 --- a/mysql-test/r/subselect_extra.result +++ b/mysql-test/r/subselect_extra.result @@ -16,7 +16,7 @@ flush tables; EXPLAIN SELECT OUTR.dt FROM t1 AS OUTR WHERE OUTR.dt IN (SELECT INNR.dt FROM t2 AS INNR WHERE OUTR.dt IS NULL ); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY OUTR ALL NULL NULL NULL NULL 2 Using where -1 PRIMARY INNR ALL NULL NULL NULL NULL 2 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY INNR ALL NULL NULL NULL NULL 2 Using where; FirstMatch(OUTR); Using join buffer (flat, BNL join) flush tables; SELECT OUTR.dt FROM t1 AS OUTR WHERE OUTR.dt IN (SELECT INNR.dt FROM t2 AS INNR WHERE OUTR.dt IS NULL ); dt @@ -24,7 +24,7 @@ flush tables; EXPLAIN SELECT OUTR.dt FROM t1 AS OUTR WHERE OUTR.dt IN ( SELECT INNR.dt FROM t2 AS INNR WHERE OUTR.t < '2005-11-13 7:41:31' ); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY OUTR ALL NULL NULL NULL NULL 2 Using where -1 PRIMARY INNR ALL NULL NULL NULL NULL 2 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY INNR ALL NULL NULL NULL NULL 2 Using where; FirstMatch(OUTR); Using join buffer (flat, BNL join) flush tables; SELECT OUTR.dt FROM t1 AS OUTR WHERE OUTR.dt IN ( SELECT INNR.dt FROM t2 AS INNR WHERE OUTR.t < '2005-11-13 7:41:31' ); dt @@ -68,7 +68,7 @@ select * from t1 where id in (select id from t1 as x1 where (t1.cur_date is null)); 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 Using where -1 PRIMARY x1 ALL NULL NULL NULL NULL 2 100.00 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY x1 ALL NULL NULL NULL NULL 2 100.00 Using where; FirstMatch(t1); Using join buffer (flat, BNL join) Warnings: Note 1276 Field or reference 'test.t1.cur_date' of SELECT #2 was resolved in SELECT #1 Note 1003 select `test`.`t1`.`id` AS `id`,`test`.`t1`.`cur_date` AS `cur_date` from `test`.`t1` semi join (`test`.`t1` `x1`) where ((`test`.`x1`.`id` = `test`.`t1`.`id`) and (`test`.`t1`.`cur_date` = 0)) @@ -80,7 +80,7 @@ select * from t2 where id in (select id from t2 as x1 where (t2.cur_date is null)); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 ALL NULL NULL NULL NULL 2 100.00 Using where -1 PRIMARY x1 ALL NULL NULL NULL NULL 2 100.00 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY x1 ALL NULL NULL NULL NULL 2 100.00 Using where; FirstMatch(t2); Using join buffer (flat, BNL join) Warnings: Note 1276 Field or reference 'test.t2.cur_date' of SELECT #2 was resolved in SELECT #1 Note 1003 select `test`.`t2`.`id` AS `id`,`test`.`t2`.`cur_date` AS `cur_date` from `test`.`t2` semi join (`test`.`t2` `x1`) where ((`test`.`x1`.`id` = `test`.`t2`.`id`) and (`test`.`t2`.`cur_date` = 0)) @@ -307,8 +307,7 @@ EXPLAIN SELECT 1 FROM t1 WHERE a IN (SELECT a FROM t1 USE INDEX (i2) IGNORE INDEX (i2)); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 index PRIMARY,i2 PRIMARY 4 NULL 144 Using index -1 PRIMARY eq_ref distinct_key distinct_key 4 func 1 -2 MATERIALIZED t1 ALL NULL NULL NULL NULL 144 +1 PRIMARY t1 ALL NULL NULL NULL NULL 144 Using where; FirstMatch(t1); Using join buffer (flat, BNL join) CREATE TABLE t2 (a INT, b INT, KEY(a)); INSERT INTO t2 VALUES (1, 1), (2, 2), (3,3), (4,4); EXPLAIN SELECT a, SUM(b) FROM t2 GROUP BY a LIMIT 2; @@ -432,7 +431,7 @@ WHERE t2.c = v1.c AND t2.c = v1.b AND v1.b = t3.c); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 system NULL NULL NULL NULL 1 1 PRIMARY t3 ALL NULL NULL NULL NULL 2 Using where -1 PRIMARY ALL NULL NULL NULL NULL 3 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY ALL NULL NULL NULL NULL 3 Using where; FirstMatch(t3); Using join buffer (flat, BNL join) 3 DERIVED t1 ALL NULL NULL NULL NULL 3 SELECT * FROM t3 WHERE t3.b IN (SELECT v1.b FROM v1, t2 diff --git a/mysql-test/r/subselect_no_mat.result b/mysql-test/r/subselect_no_mat.result index 01b83916c4b..3a184cb0a54 100644 --- a/mysql-test/r/subselect_no_mat.result +++ b/mysql-test/r/subselect_no_mat.result @@ -5204,8 +5204,8 @@ INSERT INTO t2 VALUES (15,4); EXPLAIN SELECT * FROM t1 WHERE pk IN (SELECT it.pk FROM t2 JOIN t2 AS it ON 1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL PRIMARY NULL NULL NULL 3 -1 PRIMARY t2 index NULL PRIMARY 4 NULL 3 Using index; Start temporary; Using join buffer (flat, BNL join) -1 PRIMARY it eq_ref PRIMARY PRIMARY 4 test.t1.pk 1 Using index; End temporary +1 PRIMARY it eq_ref PRIMARY PRIMARY 4 test.t1.pk 1 Using index +1 PRIMARY t2 index NULL PRIMARY 4 NULL 3 Using index; FirstMatch(it); Using join buffer (flat, BNL join) SELECT * FROM t1 WHERE pk IN (SELECT it.pk FROM t2 JOIN t2 AS it ON 1); pk i 11 0 diff --git a/mysql-test/r/subselect_no_scache.result b/mysql-test/r/subselect_no_scache.result index 606a19fa500..31d1c61a014 100644 --- a/mysql-test/r/subselect_no_scache.result +++ b/mysql-test/r/subselect_no_scache.result @@ -5209,8 +5209,8 @@ INSERT INTO t2 VALUES (15,4); EXPLAIN SELECT * FROM t1 WHERE pk IN (SELECT it.pk FROM t2 JOIN t2 AS it ON 1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL PRIMARY NULL NULL NULL 3 -1 PRIMARY t2 index NULL PRIMARY 4 NULL 3 Using index; Start temporary; Using join buffer (flat, BNL join) -1 PRIMARY it eq_ref PRIMARY PRIMARY 4 test.t1.pk 1 Using index; End temporary +1 PRIMARY it eq_ref PRIMARY PRIMARY 4 test.t1.pk 1 Using index +1 PRIMARY t2 index NULL PRIMARY 4 NULL 3 Using index; FirstMatch(it); Using join buffer (flat, BNL join) SELECT * FROM t1 WHERE pk IN (SELECT it.pk FROM t2 JOIN t2 AS it ON 1); pk i 11 0 diff --git a/mysql-test/r/subselect_sj2_jcl6.result b/mysql-test/r/subselect_sj2_jcl6.result index 8fd9122465c..02d2fb01d93 100644 --- a/mysql-test/r/subselect_sj2_jcl6.result +++ b/mysql-test/r/subselect_sj2_jcl6.result @@ -76,8 +76,7 @@ insert into t3 select a,a, a+100,a+100,a+100 from t0; explain select * from t3 where b in (select a from t1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t3 ALL b NULL NULL NULL 20 -1 PRIMARY eq_ref distinct_key distinct_key 5 func 1 -2 MATERIALIZED t1 ALL NULL NULL NULL NULL 3 +1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where; FirstMatch(t3); Using join buffer (flat, BNL join) select * from t3 where b in (select a from t1); a b pk1 pk2 pk3 1 1 1 1 1 diff --git a/mysql-test/r/subselect_sj_jcl6.result b/mysql-test/r/subselect_sj_jcl6.result index 03940e0e5eb..2f0db469bd9 100644 --- a/mysql-test/r/subselect_sj_jcl6.result +++ b/mysql-test/r/subselect_sj_jcl6.result @@ -979,10 +979,9 @@ FROM t1 WHERE `varchar_nokey` < 'n' XOR `pk` ) ; id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 ALL NULL NULL NULL NULL 18 100.00 -1 PRIMARY eq_ref distinct_key distinct_key 8 func,func 1 100.00 -2 MATERIALIZED t1 ALL varchar_key NULL NULL NULL 15 100.00 Using where +1 PRIMARY t1 ref varchar_key varchar_key 3 test.t2.varchar_nokey 2 100.00 Using where; FirstMatch(t2); Using join buffer (flat, BKA join); Key-ordered Rowid-ordered scan Warnings: -Note 1003 select `test`.`t2`.`varchar_nokey` AS `varchar_nokey` from `test`.`t2` semi join (`test`.`t1`) where ((`test`.`t1`.`varchar_nokey` = `test`.`t1`.`varchar_key`) and ((`test`.`t1`.`varchar_key` < 'n') xor `test`.`t1`.`pk`)) +Note 1003 select `test`.`t2`.`varchar_nokey` AS `varchar_nokey` from `test`.`t2` semi join (`test`.`t1`) where ((`test`.`t1`.`varchar_key` = `test`.`t2`.`varchar_nokey`) and (`test`.`t1`.`varchar_nokey` = `test`.`t2`.`varchar_nokey`) and ((`test`.`t2`.`varchar_nokey` < 'n') xor `test`.`t1`.`pk`)) SELECT varchar_nokey FROM t2 WHERE ( `varchar_nokey` , `varchar_nokey` ) IN ( @@ -1061,10 +1060,8 @@ AND t1.val IN (SELECT t3.val FROM t3 WHERE t3.val LIKE 'a%' OR t3.val LIKE 'e%'); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 5 -1 PRIMARY eq_ref distinct_key distinct_key 14 func 1 -1 PRIMARY eq_ref distinct_key distinct_key 14 func 1 -3 MATERIALIZED t3 ALL NULL NULL NULL NULL 5 Using where -2 MATERIALIZED t2 ALL NULL NULL NULL NULL 6 Using where +1 PRIMARY t3 ALL NULL NULL NULL NULL 5 Using where; FirstMatch(t1); Using join buffer (flat, BNL join) +1 PRIMARY t2 ALL NULL NULL NULL NULL 6 Using where; FirstMatch(t3); Using join buffer (incremental, BNL join) SELECT * FROM t1 WHERE t1.val IN (SELECT t2.val FROM t2 @@ -1254,7 +1251,7 @@ A.t1field IN (SELECT C.t2field FROM t2 C WHERE C.t2field IN (SELECT D.t2field FROM t2 D)); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY A index PRIMARY PRIMARY 4 NULL 3 Using index -1 PRIMARY B index NULL PRIMARY 4 NULL 3 Using index; Start temporary; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY B index NULL PRIMARY 4 NULL 3 Using index; FirstMatch(A); Using join buffer (flat, BNL join) 1 PRIMARY C eq_ref PRIMARY PRIMARY 4 test.A.t1field 1 Using index 1 PRIMARY D eq_ref PRIMARY PRIMARY 4 test.A.t1field 1 Using index SELECT * FROM t1 A @@ -1283,11 +1280,9 @@ select * from t1 A, t1 B where A.a = B.a and A.a in (select a from t2 C) and B.a in (select a from t2 D); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY A ALL NULL NULL NULL NULL 3 -1 PRIMARY eq_ref distinct_key distinct_key 5 func 1 1 PRIMARY B ALL NULL NULL NULL NULL 3 Using where; Using join buffer (flat, BNL join) -1 PRIMARY eq_ref distinct_key distinct_key 5 func 1 -2 MATERIALIZED C ALL NULL NULL NULL NULL 3 -3 MATERIALIZED D ALL NULL NULL NULL NULL 3 +1 PRIMARY C ALL NULL NULL NULL NULL 3 Using where; FirstMatch(B); Using join buffer (incremental, BNL join) +1 PRIMARY D ALL NULL NULL NULL NULL 3 Using where; FirstMatch(C); Using join buffer (incremental, BNL join) drop table t1, t2; # # BUG#784441: Abort on semijoin with a view as the inner table @@ -2160,8 +2155,8 @@ SELECT * FROM t1, t2 WHERE t2.a IN (SELECT b FROM t3 WHERE t3.d <= t1.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 t3 ALL d NULL NULL NULL 5 Range checked for each record (index map: 0x2); Start temporary -1 PRIMARY t2 hash_ALL PRIMARY #hash#PRIMARY 4 test.t3.b 4 End temporary; Using join buffer (flat, BNLH join) +1 PRIMARY t2 ALL PRIMARY NULL NULL NULL 4 Using join buffer (flat, BNL join) +1 PRIMARY t3 ALL d NULL NULL NULL 5 Range checked for each record (index map: 0x2); FirstMatch(t2) SELECT * FROM t1, t2 WHERE t2.a IN (SELECT b FROM t3 WHERE t3.d <= t1.a); a a b @@ -2175,8 +2170,8 @@ SELECT * FROM t1, t2 WHERE t2.a IN (SELECT b FROM t3 WHERE t3.d <= t1.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 t3 ALL d NULL NULL NULL 5 Range checked for each record (index map: 0x2); Start temporary -1 PRIMARY t2 eq_ref PRIMARY PRIMARY 4 test.t3.b 1 End temporary; Using join buffer (flat, BKA join); Key-ordered Rowid-ordered scan +1 PRIMARY t2 ALL PRIMARY NULL NULL NULL 4 Using join buffer (flat, BNL join) +1 PRIMARY t3 ALL d NULL NULL NULL 5 Range checked for each record (index map: 0x2); FirstMatch(t2) SELECT * FROM t1, t2 WHERE t2.a IN (SELECT b FROM t3 WHERE t3.d <= t1.a); a a b diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index 233305f3da6..46ecb5ff65a 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -2617,13 +2617,27 @@ bool Firstmatch_picker::check_qep(JOIN *join, !(firstmatch_need_tables & remaining_tables)) { /* - Got a complete FirstMatch range. - Calculate correct costs and fanout + Got a complete FirstMatch range. Calculate correct costs and fanout */ - optimize_wo_join_buffering(join, first_firstmatch_table, idx, - remaining_tables, FALSE, idx, - record_count, - read_time); + + if (idx == first_firstmatch_table && + optimizer_flag(join->thd, OPTIMIZER_SWITCH_SEMIJOIN_WITH_CACHE)) + { + /* + An important special case: only one inner table, and @@optimizer_switch + allows join buffering. + - read_time is the same (i.e. FirstMatch doesn't add any cost + - remove fanout added by the last table + */ + *record_count /= join->positions[idx].records_read; + } + else + { + optimize_wo_join_buffering(join, first_firstmatch_table, idx, + remaining_tables, FALSE, idx, + record_count, + read_time); + } /* We ought to save the alternate POSITIONs produced by optimize_wo_join_buffering but the problem is that providing save From 8bb893f5c31b7b61abdea998cab5bed73dce6c9a Mon Sep 17 00:00:00 2001 From: Jimmy Yang Date: Wed, 7 Dec 2011 18:44:52 -0800 Subject: [PATCH 184/288] Fix Bug #13083023 - 60229: BROKEN COMPATIBILITY: ERROR WHILE CREATE TABLE WITH FOREIGN KEY CONSTRAI rb://844 approved by marko --- .../suite/innodb/r/innodb_bug60229.result | 26 +++++++++++++ .../suite/innodb/t/innodb_bug60229-master.opt | 1 + .../suite/innodb/t/innodb_bug60229.test | 39 +++++++++++++++++++ storage/innobase/dict/dict0dict.c | 5 +++ 4 files changed, 71 insertions(+) create mode 100644 mysql-test/suite/innodb/r/innodb_bug60229.result create mode 100644 mysql-test/suite/innodb/t/innodb_bug60229-master.opt create mode 100644 mysql-test/suite/innodb/t/innodb_bug60229.test diff --git a/mysql-test/suite/innodb/r/innodb_bug60229.result b/mysql-test/suite/innodb/r/innodb_bug60229.result new file mode 100644 index 00000000000..a3971876193 --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_bug60229.result @@ -0,0 +1,26 @@ +CREATE TABLE PERSON ( +PERSON_ID VARCHAR(50) NOT NULL, +DOB VARCHAR(50) NOT NULL, +NAME NVARCHAR(255) NOT NULL, +CONSTRAINT PK_PERSON PRIMARY KEY (PERSON_ID, DOB) +)Engine=InnoDB; +CREATE TABLE PHOTO ( +PERSON_ID VARCHAR(50) NOT NULL, +DOB VARCHAR(50) NOT NULL, +PHOTO_DETAILS VARCHAR(50) NULL, +CONSTRAINT PK_PHOTO PRIMARY KEY (PERSON_ID, DOB), +CONSTRAINT FK_PHOTO_2_PERSON FOREIGN KEY (PERSON_ID, DOB) REFERENCES PERSON (PERSON_ID, DOB) +)Engine=InnoDB; +CREATE TABLE ADDRESS ( +PERSON_ID VARCHAR(50) NOT NULL, +DOB VARCHAR(50) NOT NULL, +ADDRESS_ID VARCHAR(50) NOT NULL, +ADDRESS_DETAILS NVARCHAR(250) NULL, +CONSTRAINT PK_ADDRESS PRIMARY KEY (PERSON_ID, DOB, ADDRESS_ID), +CONSTRAINT FK_ADDRESS_2_PERSON FOREIGN KEY (PERSON_ID, DOB) REFERENCES PERSON (PERSON_ID, DOB) ON DELETE CASCADE +)Engine=InnoDB; +INSERT INTO PERSON VALUES("10", "11011999", "John"); +INSERT INTO PHOTO VALUES("10", "11011999", "new photo"); +DROP TABLE PHOTO; +DROP TABLE ADDRESS; +DROP TABLE PERSON; diff --git a/mysql-test/suite/innodb/t/innodb_bug60229-master.opt b/mysql-test/suite/innodb/t/innodb_bug60229-master.opt new file mode 100644 index 00000000000..9b27aef9bf8 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_bug60229-master.opt @@ -0,0 +1 @@ +--lower_case_table_names=0 diff --git a/mysql-test/suite/innodb/t/innodb_bug60229.test b/mysql-test/suite/innodb/t/innodb_bug60229.test new file mode 100644 index 00000000000..8dcf15157d6 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_bug60229.test @@ -0,0 +1,39 @@ +# +# Bug #13083023 - 60229: BROKEN COMPATIBILITY: ERROR WHILE CREATE TABLE +# WITH FOREIGN KEY CONSTRAINT. + +-- source include/have_innodb.inc + +CREATE TABLE PERSON ( + PERSON_ID VARCHAR(50) NOT NULL, + DOB VARCHAR(50) NOT NULL, + NAME NVARCHAR(255) NOT NULL, + CONSTRAINT PK_PERSON PRIMARY KEY (PERSON_ID, DOB) +)Engine=InnoDB; + + +CREATE TABLE PHOTO ( + PERSON_ID VARCHAR(50) NOT NULL, + DOB VARCHAR(50) NOT NULL, + PHOTO_DETAILS VARCHAR(50) NULL, + CONSTRAINT PK_PHOTO PRIMARY KEY (PERSON_ID, DOB), + CONSTRAINT FK_PHOTO_2_PERSON FOREIGN KEY (PERSON_ID, DOB) REFERENCES PERSON (PERSON_ID, DOB) +)Engine=InnoDB; + + +CREATE TABLE ADDRESS ( + PERSON_ID VARCHAR(50) NOT NULL, + DOB VARCHAR(50) NOT NULL, + ADDRESS_ID VARCHAR(50) NOT NULL, + ADDRESS_DETAILS NVARCHAR(250) NULL, + CONSTRAINT PK_ADDRESS PRIMARY KEY (PERSON_ID, DOB, ADDRESS_ID), + CONSTRAINT FK_ADDRESS_2_PERSON FOREIGN KEY (PERSON_ID, DOB) REFERENCES PERSON (PERSON_ID, DOB) ON DELETE CASCADE +)Engine=InnoDB; + +INSERT INTO PERSON VALUES("10", "11011999", "John"); +INSERT INTO PHOTO VALUES("10", "11011999", "new photo"); + +DROP TABLE PHOTO; +DROP TABLE ADDRESS; +DROP TABLE PERSON; + diff --git a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.c index 2a2c7652817..19f1e145085 100644 --- a/storage/innobase/dict/dict0dict.c +++ b/storage/innobase/dict/dict0dict.c @@ -3069,10 +3069,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); } From 314c377422dd13c86591a4de32162467eb540c33 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 8 Dec 2011 12:05:52 +0200 Subject: [PATCH 185/288] Fixed bug lp:888456 Analysis: The class member QUICK_GROUP_MIN_MAX_SELECT::seen_first_key was not reset between subquery re-executions. Thus each subsequent execution continued from the group that was reached by the previous subquery execution. As a result loose scan reached end of file much earlier, and returned empty result where it shouldn't. Solution: Reset seen_first_key before each re-execution of the loose scan. --- mysql-test/r/group_min_max.result | 17 +++++++++++++++++ mysql-test/t/group_min_max.test | 14 ++++++++++++++ sql/opt_range.cc | 1 + 3 files changed, 32 insertions(+) diff --git a/mysql-test/r/group_min_max.result b/mysql-test/r/group_min_max.result index 6fef66b9d93..5b6ae943529 100644 --- a/mysql-test/r/group_min_max.result +++ b/mysql-test/r/group_min_max.result @@ -2780,4 +2780,21 @@ ORDER BY min_a; min_a NULL DROP TABLE t1; +# +# LP BUG#888456 Wrong result with DISTINCT , ANY , subquery_cache=off , NOT NULL +# +CREATE TABLE t1 ( a int NOT NULL) ; +INSERT INTO t1 VALUES (28),(29),(9); +CREATE TABLE t2 ( a int, KEY (a)) ; +INSERT INTO t2 VALUES (1),(1),(1),(4),(4),(5),(5),(8),(8),(9); +explain select (select t2.a from t2 where t2.a >= t1.a group by t2.a) from t1; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 3 +2 DEPENDENT SUBQUERY t2 range a a 5 NULL 6 Using where; Using index for group-by +select (select t2.a from t2 where t2.a >= t1.a group by t2.a) from t1; +(select t2.a from t2 where t2.a >= t1.a group by t2.a) +NULL +NULL +9 +drop table t1, t2; End of 5.1 tests diff --git a/mysql-test/t/group_min_max.test b/mysql-test/t/group_min_max.test index 8ab7e1c9cb4..bd2cbd8a9f0 100644 --- a/mysql-test/t/group_min_max.test +++ b/mysql-test/t/group_min_max.test @@ -1099,5 +1099,19 @@ ORDER BY min_a; DROP TABLE t1; +--echo # +--echo # LP BUG#888456 Wrong result with DISTINCT , ANY , subquery_cache=off , NOT NULL +--echo # + +CREATE TABLE t1 ( a int NOT NULL) ; +INSERT INTO t1 VALUES (28),(29),(9); + +CREATE TABLE t2 ( a int, KEY (a)) ; +INSERT INTO t2 VALUES (1),(1),(1),(4),(4),(5),(5),(8),(8),(9); + +explain select (select t2.a from t2 where t2.a >= t1.a group by t2.a) from t1; +select (select t2.a from t2 where t2.a >= t1.a group by t2.a) from t1; + +drop table t1, t2; --echo End of 5.1 tests diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 3821665fb22..889af68f77a 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -10627,6 +10627,7 @@ int QUICK_GROUP_MIN_MAX_SELECT::reset(void) int result; DBUG_ENTER("QUICK_GROUP_MIN_MAX_SELECT::reset"); + seen_first_key= FALSE; if (!head->key_read) { doing_key_read= 1; From fc9d34cabf06038f930db356d53ed76dab5fdf0d Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Thu, 8 Dec 2011 16:29:45 +0400 Subject: [PATCH 186/288] bug #901655 ST_BUFFER asserts with a coplicated shape. Coinciding nodes can appear as a result of DOUBLE inaccuracy. We should test that before we start the loop. Also the spatial relations can be calculated faster if we check MBR relations first. And we do have the shape's MBR-s now. per-file comments: sql/gcalc_slicescan.cc set_extent() method added. bug #901655 ST_BUFFER asserts with a coplicated shape. sql/gcalc_slicescan.h set_extent() method declared. bug #901655 ST_BUFFER asserts with a coplicated shape. sql/gcalc_tools.cc bug #901655 ST_BUFFER asserts with a coplicated shape. checks for equal nodes added. sql/item_geofunc.cc bug #901655 ST_BUFFER asserts with a coplicated shape. MBR for the shapes calculated, and MBR checks added before we start the heavy calculations. sql/spatial.h bug #901655 ST_BUFFER asserts with a coplicated shape. MBR::buffer() method implemented. --- sql/gcalc_slicescan.cc | 106 ++++++++++++++-------- sql/gcalc_slicescan.h | 5 ++ sql/gcalc_tools.cc | 9 -- sql/item_geofunc.cc | 197 +++++++++++------------------------------ sql/spatial.h | 7 ++ 5 files changed, 132 insertions(+), 192 deletions(-) diff --git a/sql/gcalc_slicescan.cc b/sql/gcalc_slicescan.cc index 7021902ffb7..3c02bf62e53 100644 --- a/sql/gcalc_slicescan.cc +++ b/sql/gcalc_slicescan.cc @@ -406,7 +406,7 @@ static int de_weak_check(long double a, long double b, long double ex) static int de_check(long double a, long double b) { - return de_weak_check(a, b, (long double) 1e-10); + return de_weak_check(a, b, (long double) 1e-9); } #endif /*GCALC_CHECK_WITH_FLOAT*/ @@ -792,10 +792,51 @@ static int cmp_intersections(const Gcalc_heap::Info *i1, /* Internal coordinates implementation end */ +#define GCALC_SCALE_1 1e18 + +static double find_scale(double extent) +{ + double scale= 1e-2; + while (scale < extent) + scale*= (double ) 10; + return GCALC_SCALE_1 / scale / 10; +} + + +void Gcalc_heap::set_extent(double xmin, double xmax, double ymin, double ymax) +{ + xmin= fabs(xmin); + xmax= fabs(xmax); + ymin= fabs(ymin); + ymax= fabs(ymax); + + if (xmax < xmin) + xmax= xmin; + if (ymax < ymin) + ymax= ymin; + + coord_extent= xmax > ymax ? xmax : ymax; + coord_extent= find_scale(coord_extent); +#ifdef GCALC_CHECK_WITH_FLOAT + gcalc_coord_extent= &coord_extent; +#endif /*GCALC_CHECK_WITH_FLOAT*/ +} + + +void Gcalc_heap::free_point_info(Gcalc_heap::Info *i, + Gcalc_dyn_list::Item **i_hook) +{ + if (m_hook == &i->next) + m_hook= i_hook; + *i_hook= i->next; + free_item(i); + m_n_points--; +} + + Gcalc_heap::Info *Gcalc_heap::new_point_info(double x, double y, gcalc_shape_info shape) { - double abs= fabs(x); Info *result= (Info *)new_item(); if (!result) return NULL; @@ -806,17 +847,8 @@ Gcalc_heap::Info *Gcalc_heap::new_point_info(double x, double y, result->shape= shape; result->top_node= 1; result->type= nt_shape_node; - if (m_n_points) - { - if (abs > coord_extent) - coord_extent= abs; - } - else - coord_extent= abs; - - abs= fabs(y); - if (abs > coord_extent) - coord_extent= abs; + gcalc_set_double(result->ix, x, coord_extent); + gcalc_set_double(result->iy, y, coord_extent); m_n_points++; return result; @@ -927,32 +959,12 @@ static int compare_point_info(const void *e0, const void *e1) } -#define GCALC_SCALE_1 1e18 - -static double find_scale(double extent) -{ - double scale= 1e-2; - while (scale < extent) - scale*= (double ) 10; - return GCALC_SCALE_1 / scale / 10; -} - - void Gcalc_heap::prepare_operation() { Info *cur; GCALC_DBUG_ASSERT(m_hook); - coord_extent= find_scale(coord_extent); -#ifdef GCALC_CHECK_WITH_FLOAT - gcalc_coord_extent= &coord_extent; -#endif /*GCALC_CHECK_WITH_FLOAT*/ *m_hook= NULL; m_hook= NULL; /* just to check it's not called twice */ - for (cur= get_first(); cur; cur= cur->get_next()) - { - gcalc_set_double(cur->ix, cur->x, coord_extent); - gcalc_set_double(cur->iy, cur->y, coord_extent); - } m_first= sort_list(compare_point_info, m_first, m_n_points); /* TODO - move this to the 'normal_scan' loop */ @@ -990,18 +1002,28 @@ int Gcalc_shape_transporter::int_add_point(gcalc_shape_info Info, double x, double y) { Gcalc_heap::Info *point; - GCALC_DBUG_ASSERT(!m_prev || m_prev->x != x || m_prev->y != y); + Gcalc_dyn_list::Item **hook; + + hook= m_heap->get_cur_hook(); if (!(point= m_heap->new_point_info(x, y, Info))) return 1; if (m_first) { + if (cmp_point_info(m_prev, point) == 0) + { + /* Coinciding points, do nothing */ + m_heap->free_point_info(point, hook); + return 0; + } + GCALC_DBUG_ASSERT(!m_prev || m_prev->x != x || m_prev->y != y); m_prev->left= point; point->right= m_prev; } else m_first= point; m_prev= point; + m_prev_hook= hook; return 0; } @@ -1029,10 +1051,20 @@ void Gcalc_shape_transporter::int_complete() return; } - GCALC_DBUG_ASSERT(m_prev->x != m_first->x || m_prev->y != m_first->y); /* polygon */ - m_first->right= m_prev; - m_prev->left= m_first; + if (cmp_point_info(m_first, m_prev) == 0) + { + /* Coinciding points, remove the last one from the list */ + m_prev->right->left= m_first; + m_first->right= m_prev->right; + m_heap->free_point_info(m_prev, m_prev_hook); + } + else + { + GCALC_DBUG_ASSERT(m_prev->x != m_first->x || m_prev->y != m_first->y); + m_first->right= m_prev; + m_prev->left= m_first; + } } diff --git a/sql/gcalc_slicescan.h b/sql/gcalc_slicescan.h index 9fc4cea5199..55de497f1ee 100644 --- a/sql/gcalc_slicescan.h +++ b/sql/gcalc_slicescan.h @@ -229,7 +229,9 @@ public: Gcalc_dyn_list(blk_size, sizeof(Info)), m_hook(&m_first), m_n_points(0) {} + void set_extent(double xmin, double xmax, double ymin, double ymax); Info *new_point_info(double x, double y, gcalc_shape_info shape); + void free_point_info(Info *i, Gcalc_dyn_list::Item **i_hook); Info *new_intersection(const Info *p1, const Info *p2, const Info *p3, const Info *p4); void prepare_operation(); @@ -242,6 +244,8 @@ public: long double get_double(const Gcalc_internal_coord *c) const; #endif /*GCALC_CHECK_WITH_FLOAT*/ double coord_extent; + Gcalc_dyn_list::Item **get_cur_hook() { return m_hook; } + private: Gcalc_dyn_list::Item *m_first; Gcalc_dyn_list::Item **m_hook; @@ -269,6 +273,7 @@ class Gcalc_shape_transporter private: Gcalc_heap::Info *m_first; Gcalc_heap::Info *m_prev; + Gcalc_dyn_list::Item **m_prev_hook; int m_shape_started; void int_complete(); protected: diff --git a/sql/gcalc_tools.cc b/sql/gcalc_tools.cc index 161fa385f16..8af94039c2d 100644 --- a/sql/gcalc_tools.cc +++ b/sql/gcalc_tools.cc @@ -650,15 +650,6 @@ Gcalc_operation_reducer(Gcalc_function *fn, modes mode, size_t blk_size) : } -#ifdef TMP_BLOCK -void Gcalc_operation_reducer::res_point::set(const Gcalc_scan_iterator *si) -{ - if ((intersection_point= si->intersection_step())) - ii= si->get_cur_ii(); - else - pi= si->get_cur_pi(); -} -#endif /*TMP_BLOCK*/ void Gcalc_operation_reducer::res_point::set(const Gcalc_scan_iterator *si) { intersection_point= si->intersection_step(); diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index acaa50536ff..0c9ebc06749 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -657,140 +657,6 @@ static double distance_points(const Gcalc_heap::Info *a, } -/* - Calculates the distance between objects. -*/ - -#ifdef TMP_BLOCK -static int calc_distance(double *result, Gcalc_heap *collector, uint obj2_si, - Gcalc_function *func, Gcalc_scan_iterator *scan_it) -{ - bool above_cur_point, cur_point_edge; - const Gcalc_scan_iterator::point *evpos; - const Gcalc_heap::Info *cur_point= NULL; - const Gcalc_heap::Info *dist_point; - const Gcalc_scan_iterator::point *ev; - double t, distance, cur_distance; - double ex, ey, vx, vy, e_sqrlen; - int o1, o2; - - DBUG_ENTER("calc_distance"); - - above_cur_point= false; - distance= DBL_MAX; - - while (scan_it->more_points()) - { - if (scan_it->step()) - goto mem_error; - evpos= scan_it->get_event_position(); - ev= scan_it->get_events(); - cur_point= NULL; - - if (ev->simple_event()) - { - cur_point= ev->pi; - goto calculate_distance; - } - - /* - handling intersection we only need to check if it's the intersecion - of objects 1 and 2. In this case distance is 0 - */ - o1= 0; - o2= 0; - for (; ev; ev= ev->get_next()) - { - if (ev->event != scev_intersection) - cur_point= ev->pi; - if (ev->pi->shape >= obj2_si) - o2= 1; - else - o1= 1; - if (o1 && o2) - { - distance= 0; - goto exit; - } - } - if (!cur_point) - continue; - -#ifdef TO_REMOVE - goto calculate_distance; - /* - having these events we need to check for possible intersection - of objects - scev_thread | scev_two_threads | scev_single_point - */ - DBUG_ASSERT(ev & (scev_thread | scev_two_threads | scev_single_point)); - - func->clear_state(); - for (Gcalc_point_iterator pit(scan_it); pit.point() != evpos; ++pit) - { - gcalc_shape_info si= pit.point()->get_shape(); - if ((func->get_shape_kind(si) == Gcalc_function::shape_polygon)) - func->invert_state(si); - } - func->invert_state(evpos->get_shape()); - if (func->count()) - { - /* Point of one object is inside the other - intersection found */ - distance= 0; - goto exit; - } -#endif /*TO_REMOVE*/ - -calculate_distance: - if (cur_point->shape >= obj2_si) - continue; - cur_point_edge= !cur_point->is_bottom(); - - for (dist_point= collector->get_first(); dist_point; dist_point= dist_point->get_next()) - { - /* We only check vertices of object 2 */ - if (dist_point->shape < obj2_si) - continue; - - /* if we have an edge to check */ - if (dist_point->left) - { - t= count_edge_t(dist_point, dist_point->left, cur_point, - ex, ey, vx, vy, e_sqrlen); - if ((t > 0.0) && (t < 1.0)) - { - cur_distance= distance_to_line(ex, ey, vx, vy, e_sqrlen); - if (distance > cur_distance) - distance= cur_distance; - } - } - if (cur_point_edge) - { - t= count_edge_t(cur_point, cur_point->left, dist_point, - ex, ey, vx, vy, e_sqrlen); - if ((t > 0.0) && (t < 1.0)) - { - cur_distance= distance_to_line(ex, ey, vx, vy, e_sqrlen); - if (distance > cur_distance) - distance= cur_distance; - } - } - cur_distance= distance_points(cur_point, dist_point); - if (distance > cur_distance) - distance= cur_distance; - } - } - -exit: - *result= distance; - DBUG_RETURN(0); - -mem_error: - DBUG_RETURN(1); -} -#endif /*TMP_BLOCK*/ - - #define GIS_ZERO 0.00000000001 longlong Item_func_spatial_rel::val_int() @@ -804,6 +670,8 @@ longlong Item_func_spatial_rel::val_int() int result= 0; int mask= 0; uint shape_a, shape_b; + MBR umbr, mbr1, mbr2; + const char *c_end; res1= args[0]->val_str(&tmp_value1); res2= args[1]->val_str(&tmp_value2); @@ -818,19 +686,35 @@ longlong Item_func_spatial_rel::val_int() !(g2= Geometry::construct(&buffer2, res2->ptr(), res2->length()))))) goto exit; + g1->get_mbr(&mbr1, &c_end); + g2->get_mbr(&mbr2, &c_end); + + umbr= mbr1; + umbr.add_mbr(&mbr2); + collector.set_extent(umbr.xmin, umbr.xmax, umbr.ymin, umbr.ymax); + + mbr1.buffer(1e-5); + switch (spatial_rel) { case SP_CONTAINS_FUNC: + if (!mbr1.contains(&mbr2)) + goto exit; mask= 1; func.add_operation(Gcalc_function::op_difference, 2); /* Mind the g2 goes first. */ null_value= g2->store_shapes(&trn) || g1->store_shapes(&trn); break; case SP_WITHIN_FUNC: + mbr2.buffer(2e-5); + if (!mbr1.within(&mbr2)) + goto exit; mask= 1; func.add_operation(Gcalc_function::op_difference, 2); null_value= g1->store_shapes(&trn) || g2->store_shapes(&trn); break; case SP_EQUALS_FUNC: + if (!mbr1.contains(&mbr2)) + goto exit; mask= 1; func.add_operation(Gcalc_function::op_symdifference, 2); null_value= g1->store_shapes(&trn) || g2->store_shapes(&trn); @@ -841,6 +725,8 @@ longlong Item_func_spatial_rel::val_int() null_value= g1->store_shapes(&trn) || g2->store_shapes(&trn); break; case SP_INTERSECTS_FUNC: + if (!mbr1.intersects(&mbr2)) + goto exit; func.add_operation(Gcalc_function::op_intersection, 2); null_value= g1->store_shapes(&trn) || g2->store_shapes(&trn); break; @@ -898,15 +784,6 @@ longlong Item_func_spatial_rel::val_int() scan_it.init(&collector); scan_it.killed= (int *) &(current_thd->killed); -#ifdef TMP_BLOCK - if (spatial_rel == SP_EQUALS_FUNC) - { - result= (g1->get_class_info()->m_type_id == g1->get_class_info()->m_type_id) && - func_equals(); - goto exit; - } -#endif /*TMP_BLOCK*/ - if (func.alloc_states()) goto exit; @@ -935,6 +812,8 @@ String *Item_func_spatial_operation::val_str(String *str_value) Geometry *g1, *g2; uint32 srid= 0; Gcalc_operation_transporter trn(&func, &collector); + MBR mbr1, mbr2; + const char *c_end; if (func.reserve_op_buffer(1)) DBUG_RETURN(0); @@ -943,14 +822,23 @@ String *Item_func_spatial_operation::val_str(String *str_value) if ((null_value= (args[0]->null_value || args[1]->null_value || !(g1= Geometry::construct(&buffer1, res1->ptr(), res1->length())) || - !(g2= Geometry::construct(&buffer2, res2->ptr(), res2->length())) || - g1->store_shapes(&trn) || g2->store_shapes(&trn)))) + !(g2= Geometry::construct(&buffer2, res2->ptr(), res2->length()))))) { str_value= 0; goto exit; } + g1->get_mbr(&mbr1, &c_end); + g2->get_mbr(&mbr2, &c_end); + mbr1.add_mbr(&mbr2); + collector.set_extent(mbr1.xmin, mbr1.xmax, mbr1.ymin, mbr1.ymax); + if ((null_value= g1->store_shapes(&trn) || g2->store_shapes(&trn))) + { + str_value= 0; + goto exit; + } + collector.prepare_operation(); if (func.alloc_states()) goto exit; @@ -1374,12 +1262,18 @@ String *Item_func_buffer::val_str(String *str_value) uint32 srid= 0; String *str_result= NULL; Transporter trn(&func, &collector, dist); + MBR mbr; + const char *c_end; null_value= 1; if (args[0]->null_value || args[1]->null_value || - !(g= Geometry::construct(&buffer, obj->ptr(), obj->length()))) + !(g= Geometry::construct(&buffer, obj->ptr(), obj->length())) || + g->get_mbr(&mbr, &c_end)) goto mem_error; + if (dist > 0.0) + mbr.buffer(dist); + collector.set_extent(mbr.xmin, mbr.xmax, mbr.ymin, mbr.ymax); /* If the distance given is 0, the Buffer function is in fact NOOP, so it's natural just to return the argument1. @@ -1446,6 +1340,8 @@ longlong Item_func_issimple::val_int() Geometry *g; int result= 1; const Gcalc_scan_iterator::event_point *ev; + MBR mbr; + const char *c_end; DBUG_ENTER("Item_func_issimple::val_int"); DBUG_ASSERT(fixed == 1); @@ -1454,6 +1350,8 @@ longlong Item_func_issimple::val_int() !(g= Geometry::construct(&buffer, swkb->ptr(), swkb->length()))) DBUG_RETURN(0); + g->get_mbr(&mbr, &c_end); + collector.set_extent(mbr.xmin, mbr.xmax, mbr.ymin, mbr.ymax); if (g->get_class_info()->m_type_id == Geometry::wkb_point) DBUG_RETURN(1); @@ -1682,6 +1580,8 @@ double Item_func_distance::val_real() String *res2= args[1]->val_str(&tmp_value2); Geometry_buffer buffer1, buffer2; Geometry *g1, *g2; + MBR mbr1, mbr2; + const char *c_end; if ((null_value= (args[0]->null_value || args[1]->null_value || @@ -1689,6 +1589,11 @@ double Item_func_distance::val_real() !(g2= Geometry::construct(&buffer2, res2->ptr(), res2->length()))))) goto mem_error; + g1->get_mbr(&mbr1, &c_end); + g2->get_mbr(&mbr2, &c_end); + mbr1.add_mbr(&mbr2); + collector.set_extent(mbr1.xmin, mbr1.xmax, mbr1.ymin, mbr1.ymax); + if ((g1->get_class_info()->m_type_id == Geometry::wkb_point) && (g2->get_class_info()->m_type_id == Geometry::wkb_point)) { diff --git a/sql/spatial.h b/sql/spatial.h index d55fc639acc..3ca5ed9ae20 100644 --- a/sql/spatial.h +++ b/sql/spatial.h @@ -98,6 +98,13 @@ struct MBR if (mbr->ymax > ymax) ymax= mbr->ymax; } + void buffer(double d) + { + xmin-= d; + ymin-= d; + xmax+= d; + ymax+= d; + } int equals(const MBR *mbr) { From 7532976dd99ab89061d6f39910d25a760908c44b Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 8 Dec 2011 13:32:19 -0600 Subject: [PATCH 187/288] Bug #13116225 LIVE DOWNGRADE CRASHES WITH INNODB_PAGE_SIZE=4K This bug ensures that a live downgrade from an InnoDB 5.6 with WL5756 and a database created with innodb-page-size=8k or 4k will make a version 5.5 installation politely refuse to start. Instead of crashing or giving some indication about a corrupted database, it will indicate the page size difference. This patch takes only that part of the Wl5756 patch that is needed to protect against opening a tablespace that is stamped with a different page size. It also contains the change in dict_index_find_on_id_low() just in case a database with another page size is created by recompiling a pre-WL5756 InnoDB. --- storage/innobase/dict/dict0dict.c | 5 ++ storage/innobase/fil/fil0fil.c | 36 ++++++---- storage/innobase/fsp/fsp0fsp.c | 67 +----------------- storage/innobase/include/fil0fil.h | 17 +++-- storage/innobase/include/fsp0fsp.h | 102 +++++++++++++++++++++++++++- storage/innobase/include/fsp0fsp.ic | 34 +++++++++- storage/innobase/srv/srv0start.c | 24 ++++++- 7 files changed, 193 insertions(+), 92 deletions(-) diff --git a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.c index 19f1e145085..9dc3cef229e 100644 --- a/storage/innobase/dict/dict0dict.c +++ b/storage/innobase/dict/dict0dict.c @@ -911,6 +911,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) { diff --git a/storage/innobase/fil/fil0fil.c b/storage/innobase/fil/fil0fil.c index 196f4bd3f42..2e4c6aeeb60 100644 --- a/storage/innobase/fil/fil0fil.c +++ b/storage/innobase/fil/fil0fil.c @@ -1803,36 +1803,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; diff --git a/storage/innobase/fsp/fsp0fsp.c b/storage/innobase/fsp/fsp0fsp.c index 3f09732a676..2d626405c5c 100644 --- a/storage/innobase/fsp/fsp0fsp.c +++ b/storage/innobase/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" -#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/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h index 3a6336f1a01..d50b0cb4162 100644 --- a/storage/innobase/include/fil0fil.h +++ b/storage/innobase/include/fil0fil.h @@ -328,18 +328,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. diff --git a/storage/innobase/include/fsp0fsp.h b/storage/innobase/include/fsp0fsp.h index 7abd3914eda..d5e235aa870 100644 --- a/storage/innobase/include/fsp0fsp.h +++ b/storage/innobase/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/storage/innobase/include/fsp0fsp.ic b/storage/innobase/include/fsp0fsp.ic index 434c370b527..c92111a9d89 100644 --- a/storage/innobase/include/fsp0fsp.ic +++ b/storage/innobase/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/storage/innobase/srv/srv0start.c b/storage/innobase/srv/srv0start.c index cf11e75b8e0..edc655e93b9 100644 --- a/storage/innobase/srv/srv0start.c +++ b/storage/innobase/srv/srv0start.c @@ -733,6 +733,7 @@ open_or_create_data_files( ibool one_created = FALSE; ulint size; ulint size_high; + ulint flags; ulint rounded_size_pages; char name[10000]; @@ -914,12 +915,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 From 8a09adb3eaf036b652b11afea7d9d86a978fa566 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Fri, 9 Dec 2011 14:30:50 -0800 Subject: [PATCH 188/288] Fixed LP bug #901312. The function setup_sj_materialization_part1() forgot to set the value of TABLE::map for any materialized IN subquery. This could lead to wrong results for queries with subqueries that were converted to queries with semijoins. --- mysql-test/r/subselect_sj.result | 24 ++++++++++++++++++++++++ mysql-test/r/subselect_sj_jcl6.result | 24 ++++++++++++++++++++++++ mysql-test/t/subselect_sj.test | 22 ++++++++++++++++++++++ sql/opt_subselect.cc | 1 + 4 files changed, 71 insertions(+) diff --git a/mysql-test/r/subselect_sj.result b/mysql-test/r/subselect_sj.result index 9f37dbf4e04..b0ded6e04e6 100644 --- a/mysql-test/r/subselect_sj.result +++ b/mysql-test/r/subselect_sj.result @@ -2094,4 +2094,28 @@ a 5 set optimizer_switch= @tmp_otimizer_switch; DROP TABLE t1,t2,t3; +# +# Bug #901312: materialized semijoin + right join +# +CREATE TABLE t1 (a int); +INSERT INTO t1 VALUES (4), (1); +CREATE TABLE t2 (b int); +INSERT INTO t2 VALUES (4), (1); +CREATE TABLE t3 (c int); +INSERT INTO t3 VALUES (4), (1); +set @tmp_otimizer_switch= @@optimizer_switch; +SET SESSION optimizer_switch='semijoin=on,materialization=on'; +EXPLAIN +SELECT * FROM t1 RIGHT JOIN t2 ON b = a WHERE t2.b IN (SELECT c FROM t3); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 +1 PRIMARY eq_ref distinct_key distinct_key 5 func 1 +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where +2 MATERIALIZED t3 ALL NULL NULL NULL NULL 2 +SELECT * FROM t1 RIGHT JOIN t2 ON b = a WHERE t2.b IN (SELECT c FROM t3); +a b +4 4 +1 1 +set optimizer_switch= @tmp_otimizer_switch; +DROP TABLE t1,t2,t3; 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 2f0db469bd9..29d5ef73608 100644 --- a/mysql-test/r/subselect_sj_jcl6.result +++ b/mysql-test/r/subselect_sj_jcl6.result @@ -2100,6 +2100,30 @@ a 5 set optimizer_switch= @tmp_otimizer_switch; DROP TABLE t1,t2,t3; +# +# Bug #901312: materialized semijoin + right join +# +CREATE TABLE t1 (a int); +INSERT INTO t1 VALUES (4), (1); +CREATE TABLE t2 (b int); +INSERT INTO t2 VALUES (4), (1); +CREATE TABLE t3 (c int); +INSERT INTO t3 VALUES (4), (1); +set @tmp_otimizer_switch= @@optimizer_switch; +SET SESSION optimizer_switch='semijoin=on,materialization=on'; +EXPLAIN +SELECT * FROM t1 RIGHT JOIN t2 ON b = a WHERE t2.b IN (SELECT c FROM t3); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 +1 PRIMARY eq_ref distinct_key distinct_key 5 func 1 +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 +SELECT * FROM t1 RIGHT JOIN t2 ON b = a WHERE t2.b IN (SELECT c FROM t3); +a b +4 4 +1 1 +set optimizer_switch= @tmp_otimizer_switch; +DROP TABLE t1,t2,t3; 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 a2f46c76fce..130a5251846 100644 --- a/mysql-test/t/subselect_sj.test +++ b/mysql-test/t/subselect_sj.test @@ -1915,5 +1915,27 @@ set optimizer_switch= @tmp_otimizer_switch; DROP TABLE t1,t2,t3; +--echo # +--echo # Bug #901312: materialized semijoin + right join +--echo # + +CREATE TABLE t1 (a int); +INSERT INTO t1 VALUES (4), (1); +CREATE TABLE t2 (b int); +INSERT INTO t2 VALUES (4), (1); +CREATE TABLE t3 (c int); +INSERT INTO t3 VALUES (4), (1); + +set @tmp_otimizer_switch= @@optimizer_switch; +SET SESSION optimizer_switch='semijoin=on,materialization=on'; + +EXPLAIN +SELECT * FROM t1 RIGHT JOIN t2 ON b = a WHERE t2.b IN (SELECT c FROM t3); +SELECT * FROM t1 RIGHT JOIN t2 ON b = a WHERE t2.b IN (SELECT c FROM t3); + +set optimizer_switch= @tmp_otimizer_switch; + +DROP TABLE t1,t2,t3; + # 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 46ecb5ff65a..0819667e068 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -3173,6 +3173,7 @@ bool setup_sj_materialization_part1(JOIN_TAB *sjm_tab) HA_POS_ERROR /*rows_limit */, (char*)"sj-materialize"))) DBUG_RETURN(TRUE); /* purecov: inspected */ + sjm->table->map= emb_sj_nest->nested_join->used_tables; sjm->table->file->extra(HA_EXTRA_WRITE_CACHE); sjm->table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); From 148587461954b544355bc808a89bfed1a70694e1 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Sun, 11 Dec 2011 18:39:33 +0200 Subject: [PATCH 189/288] Rewrite IGNORE handling: - Instead of supressing all errors, only suppress safe ones like: ER_DUP_KEY, ER_BAD_NULL_ERROR, ER_SUBQUERY_NO_1_ROW, ER_ROW_IS_REFERENCED_2 --- sql/handler.cc | 38 +++++++++++++++++++++----------------- sql/mysqld.cc | 46 +++++++++++++++------------------------------- sql/sql_base.cc | 13 +++++++++---- sql/sql_class.cc | 13 ++----------- sql/sql_delete.cc | 21 ++++++--------------- sql/sql_insert.cc | 29 ++++++++++++----------------- sql/sql_lex.cc | 2 +- sql/sql_lex.h | 1 - sql/sql_prepare.cc | 3 --- sql/sql_select.cc | 6 ------ 10 files changed, 66 insertions(+), 106 deletions(-) diff --git a/sql/handler.cc b/sql/handler.cc index 4640597d2ec..e165a16b544 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -2853,15 +2853,15 @@ void handler::print_error(int error, myf errflag) str.length(max_length-4); str.append(STRING_WITH_LEN("...")); } - my_error(ER_FOREIGN_DUPLICATE_KEY, MYF(0), table_share->table_name.str, - str.c_ptr_safe(), key_nr+1); + my_error(ER_FOREIGN_DUPLICATE_KEY, errflag, table_share->table_name.str, + str.c_ptr_safe(), key_nr+1); DBUG_VOID_RETURN; } textno= ER_DUP_KEY; break; } case HA_ERR_NULL_IN_SPATIAL: - my_error(ER_CANT_CREATE_GEOMETRY_OBJECT, MYF(0)); + my_error(ER_CANT_CREATE_GEOMETRY_OBJECT, errflag); DBUG_VOID_RETURN; case HA_ERR_FOUND_DUPP_UNIQUE: textno=ER_DUP_UNIQUE; @@ -2931,21 +2931,21 @@ void handler::print_error(int error, myf errflag) { String str; get_error_message(error, &str); - my_error(ER_ROW_IS_REFERENCED_2, MYF(0), str.c_ptr_safe()); + my_error(ER_ROW_IS_REFERENCED_2, errflag, str.c_ptr_safe()); DBUG_VOID_RETURN; } case HA_ERR_NO_REFERENCED_ROW: { String str; get_error_message(error, &str); - my_error(ER_NO_REFERENCED_ROW_2, MYF(0), str.c_ptr_safe()); + my_error(ER_NO_REFERENCED_ROW_2, errflag, str.c_ptr_safe()); DBUG_VOID_RETURN; } case HA_ERR_TABLE_DEF_CHANGED: textno=ER_TABLE_DEF_CHANGED; break; case HA_ERR_NO_SUCH_TABLE: - my_error(ER_NO_SUCH_TABLE, MYF(0), table_share->db.str, + my_error(ER_NO_SUCH_TABLE, errflag, table_share->db.str, table_share->table_name.str); DBUG_VOID_RETURN; case HA_ERR_RBR_LOGGING_FAILED: @@ -2957,7 +2957,7 @@ void handler::print_error(int error, myf errflag) uint key_nr= get_dup_key(error); if ((int) key_nr >= 0) ptr= table->key_info[key_nr].name; - my_error(ER_DROP_INDEX_FK, MYF(0), ptr); + my_error(ER_DROP_INDEX_FK, errflag, ptr); DBUG_VOID_RETURN; } case HA_ERR_TABLE_NEEDS_UPGRADE: @@ -2986,12 +2986,12 @@ void handler::print_error(int error, myf errflag) { const char* engine= table_type(); if (temporary) - my_error(ER_GET_TEMPORARY_ERRMSG, MYF(0), error, str.c_ptr(), + my_error(ER_GET_TEMPORARY_ERRMSG, errflag, error, str.c_ptr(), engine); else { SET_FATAL_ERROR; - my_error(ER_GET_ERRMSG, MYF(0), error, str.c_ptr(), engine); + my_error(ER_GET_ERRMSG, errflag, error, str.c_ptr(), engine); } } else @@ -2999,15 +2999,19 @@ void handler::print_error(int error, myf errflag) DBUG_VOID_RETURN; } } - if (fatal_error && (debug_assert_if_crashed_table || - global_system_variables.log_warnings > 1)) + if (fatal_error) { - /* - Log error to log before we crash or if extended warnings are requested - */ - errflag|= ME_NOREFRESH; - } - + /* Ensure this becomes a true error */ + errflag&= ~(ME_JUST_WARNING | ME_JUST_INFO); + if ((debug_assert_if_crashed_table || + global_system_variables.log_warnings > 1)) + { + /* + Log error to log before we crash or if extended warnings are requested + */ + errflag|= ME_NOREFRESH; + } + } my_error(textno, errflag, table_share->table_name.str, error); DBUG_ASSERT(!fatal_error || !debug_assert_if_crashed_table); DBUG_VOID_RETURN; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index c43b384f169..0767ca561df 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3187,41 +3187,25 @@ int my_message_sql(uint error, const char *str, myf MyFlags) thd->is_slave_error= 1; // needed to catch query errors during replication - /* - thd->lex->current_select == 0 if lex structure is not inited - (not query command (COM_QUERY)) - */ - if (thd->lex->current_select && - thd->lex->current_select->no_error && !thd->is_fatal_error) + if (thd->main_da.is_ok() && !thd->main_da.can_overwrite_status) { - DBUG_PRINT("error", - ("Error converted to warning: current_select: no_error %d " - "fatal_error: %d", - (thd->lex->current_select ? - thd->lex->current_select->no_error : 0), - (int) thd->is_fatal_error)); + /* + Client has already got ok packet and we are not in net_flush(), so + we write a message to error log. + This could happen if we get an error in implicit commit. + This should never happen in normal operation, so lets + assert here in debug builds. + */ + DBUG_ASSERT(0); + func= sql_print_error; + MyFlags|= ME_NOREFRESH; } - else + else if (! thd->main_da.is_error()) // Return only first message { - if (thd->main_da.is_ok() && !thd->main_da.can_overwrite_status) - { - /* - Client has already got ok packet and we are not in net_flush(), so - we write a message to error log. - This could happen if we get an error in implicit commit. - This should never happen in normal operation, so lets - assert here in debug builds. - */ - DBUG_ASSERT(0); - func= sql_print_error; - MyFlags|= ME_NOREFRESH; - } - else if (! thd->main_da.is_error()) // Return only first message - { - thd->main_da.set_error_status(thd, error, str); - } - query_cache_abort(&thd->net); + thd->main_da.set_error_status(thd, error, str); } + query_cache_abort(&thd->net); + /* If a continue handler is found, the error message will be cleared by the stored procedures code. diff --git a/sql/sql_base.cc b/sql/sql_base.cc index c625aaab9a0..558e7b0aa9e 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -8549,9 +8549,11 @@ fill_record(THD * thd, List &fields, List &values, Item *value, *fld; Item_field *field; TABLE *table= 0, *vcol_table= 0; - bool abort_on_warning_saved= thd->abort_on_warning; + bool save_abort_on_warning= thd->abort_on_warning; + bool save_no_errors= thd->no_errors; DBUG_ENTER("fill_record"); + thd->no_errors= ignore_errors; /* Reset the table->auto_increment_field_not_null as it is valid for only one row. @@ -8596,7 +8598,7 @@ fill_record(THD * thd, List &fields, List &values, ER(ER_WARNING_NON_DEFAULT_VALUE_FOR_VIRTUAL_COLUMN), rfield->field_name, table->s->table_name.str); } - if ((value->save_in_field(rfield, 0) < 0) && !ignore_errors) + if ((value->save_in_field(rfield, 0)) < 0 && !ignore_errors) { my_message(ER_UNKNOWN_ERROR, ER(ER_UNKNOWN_ERROR), MYF(0)); goto err; @@ -8614,10 +8616,13 @@ fill_record(THD * thd, List &fields, List &values, goto err; } } - thd->abort_on_warning= abort_on_warning_saved; + thd->abort_on_warning= save_abort_on_warning; + thd->no_errors= save_no_errors; DBUG_RETURN(thd->is_error()); + err: - thd->abort_on_warning= abort_on_warning_saved; + thd->abort_on_warning= save_abort_on_warning; + thd->no_errors= save_no_errors; if (table) table->auto_increment_field_not_null= FALSE; DBUG_RETURN(TRUE); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index ecd87b554e7..a0ed1cdc83f 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -2585,7 +2585,8 @@ int select_singlerow_subselect::send_data(List &items) Item_singlerow_subselect *it= (Item_singlerow_subselect *)item; if (it->assigned()) { - my_message(ER_SUBQUERY_NO_1_ROW, ER(ER_SUBQUERY_NO_1_ROW), MYF(0)); + my_message(ER_SUBQUERY_NO_1_ROW, ER(ER_SUBQUERY_NO_1_ROW), + MYF(current_thd->lex->ignore ? ME_JUST_WARNING : 0)); DBUG_RETURN(1); } if (unit->offset_limit_cnt) @@ -3830,16 +3831,6 @@ void mark_transaction_to_rollback(THD *thd, bool all) { thd->is_fatal_sub_stmt_error= TRUE; thd->transaction_rollback_request= all; - /* - Aborted transactions can not be IGNOREd. - Switch off the IGNORE flag for the current - SELECT_LEX. This should allow my_error() - to report the error and abort the execution - flow, even in presence - of IGNORE clause. - */ - if (thd->lex->current_select) - thd->lex->current_select->no_error= FALSE; } } /*************************************************************************** diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 5c7909c4043..722b6f7478f 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -124,8 +124,6 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, DBUG_RETURN(TRUE); } - select_lex->no_error= thd->lex->ignore; - const_cond_result= const_cond && (!conds || conds->val_int()); if (thd->is_error()) { @@ -365,16 +363,9 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, } else { - table->file->print_error(error,MYF(0)); - /* - In < 4.0.14 we set the error number to 0 here, but that - was not sensible, because then MySQL would not roll back the - failed DELETE, and also wrote it to the binlog. For MyISAM - tables a DELETE probably never should fail (?), but for - InnoDB it can fail in a FOREIGN KEY error or an - out-of-tablespace error. - */ - if (!select_lex->no_error) + table->file->print_error(error, + MYF(thd->lex->ignore ? ME_JUST_WARNING : 0)); + if (thd->is_error()) { error= 1; break; @@ -809,7 +800,7 @@ int multi_delete::send_data(List &values) TABLE_LIST *del_table; DBUG_ENTER("multi_delete::send_data"); - bool ignore= thd->lex->current_select->no_error; + bool ignore= thd->lex->ignore; for (del_table= delete_tables; del_table; @@ -958,11 +949,11 @@ int multi_delete::do_deletes() table_being_deleted= table_being_deleted->next_local, counter++) { TABLE *table = table_being_deleted->table; + int local_error; if (tempfiles[counter]->get(table)) DBUG_RETURN(1); - int local_error= - do_table_deletes(table, thd->lex->current_select->no_error); + local_error= do_table_deletes(table, thd->lex->ignore); if (thd->killed && !local_error) DBUG_RETURN(1); diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index cd91d2cf3bf..d01a594708e 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1579,11 +1579,12 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) else error= 0; /* - If ON DUP KEY UPDATE updates a row instead of inserting one, it's - like a regular UPDATE statement: it should not affect the value of a - next SELECT LAST_INSERT_ID() or mysql_insert_id(). - Except if LAST_INSERT_ID(#) was in the INSERT query, which is - handled separately by THD::arg_of_last_insert_id_function. + If ON DUP KEY UPDATE updates a row instead of inserting + one, it's like a regular UPDATE statement: it should not + affect the value of a next SELECT LAST_INSERT_ID() or + mysql_insert_id(). Except if LAST_INSERT_ID(#) was in the + INSERT query, which is handled separately by + THD::arg_of_last_insert_id_function. */ insert_id_for_cur_row= table->file->insert_id_for_cur_row= 0; trg_error= (table->triggers && @@ -1660,11 +1661,12 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) } /* - If more than one iteration of the above while loop is done, from the second - one the row being inserted will have an explicit value in the autoinc field, - which was set at the first call of handler::update_auto_increment(). This - value is saved to avoid thd->insert_id_for_cur_row becoming 0. Use this saved - autoinc value. + If more than one iteration of the above while loop is done, from + the second one the row being inserted will have an explicit + value in the autoinc field, which was set at the first call of + handler::update_auto_increment(). This value is saved to avoid + thd->insert_id_for_cur_row becoming 0. Use this saved autoinc + value. */ if (table->file->insert_id_for_cur_row == 0) table->file->insert_id_for_cur_row= insert_id_for_cur_row; @@ -1704,9 +1706,6 @@ ok_or_after_trg_err: err: info->last_errno= error; - /* current_select is NULL if this is a delayed insert */ - if (thd->lex->current_select) - thd->lex->current_select->no_error= 0; // Give error table->file->print_error(error,MYF(0)); before_trg_err: @@ -3078,8 +3077,6 @@ select_insert::prepare(List &values, SELECT_LEX_UNIT *u) */ lex->current_select= &lex->select_lex; - /* Errors during check_insert_fields() should not be ignored. */ - lex->current_select->no_error= FALSE; res= (setup_fields(thd, 0, values, MARK_COLUMNS_READ, 0, 0) || check_insert_fields(thd, table_list, *fields, values, !insert_into_view, 1, &map)); @@ -3213,8 +3210,6 @@ select_insert::prepare(List &values, SELECT_LEX_UNIT *u) if (!res) prepare_triggers_for_insert_stmt(table); - lex->current_select->no_error= lex->ignore; - DBUG_RETURN(res); } diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 18c0dc241cc..f24e2f1b845 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1572,7 +1572,7 @@ void st_select_lex_node::init_query() options= 0; sql_cache= SQL_CACHE_UNSPECIFIED; linkage= UNSPECIFIED_TYPE; - no_error= no_table_names_allowed= 0; + no_table_names_allowed= 0; uncacheable= 0; } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index d5c72032114..cefa092a874 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -429,7 +429,6 @@ public: uint8 uncacheable; enum sub_select_type linkage; bool no_table_names_allowed; /* used for global order by */ - bool no_error; /* suppress error message (convert it to warnings) */ static void *operator new(size_t size) throw () { diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index c03ed12cc96..611c8ddf944 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2460,9 +2460,6 @@ void reinit_stmt_before_use(THD *thd, LEX *lex) for (order= sl->order_list.first; order; order= order->next) order->item= &order->item_ptr; sl->handle_derived(lex, DT_REINIT); - - /* clear the no_error flag for INSERT/UPDATE IGNORE */ - sl->no_error= FALSE; } { SELECT_LEX_UNIT *unit= sl->master_unit(); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index c16568e9c9c..36582223703 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -284,7 +284,6 @@ bool handle_select(THD *thd, LEX *lex, select_result *result, } DBUG_PRINT("info",("res: %d report_error: %d", res, thd->is_error())); - DBUG_ASSERT(res == 0 || thd->is_error()); res|= thd->is_error(); if (unlikely(res)) result->abort(); @@ -1615,9 +1614,6 @@ JOIN::optimize() error= 0; - // Ignore errors of execution if option IGNORE present - if (thd->lex->ignore) - thd->lex->current_select->no_error= 1; DBUG_RETURN(0); setup_subq_exit: @@ -9602,8 +9598,6 @@ bool error_if_full_join(JOIN *join) { if (tab->type == JT_ALL && (!tab->select || !tab->select->quick)) { - /* This error should not be ignored. */ - join->select_lex->no_error= FALSE; my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE, ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0)); return(1); From 81d390ac8669b65f1e2dcffc65d129e42c8664c1 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Sun, 11 Dec 2011 12:42:43 -0800 Subject: [PATCH 190/288] Adjusted the results of pbxt.subselect after the latest merge 5.1->5.2->5.3. --- mysql-test/suite/pbxt/r/subselect.result | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/suite/pbxt/r/subselect.result b/mysql-test/suite/pbxt/r/subselect.result index a4777ad107b..c6913d32fe8 100644 --- a/mysql-test/suite/pbxt/r/subselect.result +++ b/mysql-test/suite/pbxt/r/subselect.result @@ -1267,7 +1267,7 @@ insert into t1 values (1,0), (2,0), (3,0); insert into t2 values (1,1), (2,1), (3,1), (2,2); update ignore t1 set b=(select b from t2 where t1.a=t2.a); Warnings: -Error 1242 Subquery returns more than 1 row +Warning 1242 Subquery returns more than 1 row select * from t1; a b 1 1 From fa29f18ffbc8c60c4aec3c74b4013056c7c32169 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Sun, 11 Dec 2011 12:56:06 -0800 Subject: [PATCH 191/288] Fixed LP bug #901478. If the duplicate elimination strategy is used for a semi-join and potentially one of the block-based join algorithms can be employed to join the inner tables of the semi-join then sorting of the head (first non-constant) table for a query with ORDER BY / GROUP BY cannot be used. --- mysql-test/r/join_cache.result | 79 ++++++++++++++++++++++++++++++++++ mysql-test/t/join_cache.test | 63 +++++++++++++++++++++++++++ sql/opt_subselect.cc | 10 +++++ sql/sql_select.cc | 17 +------- sql/sql_select.h | 19 ++++++++ 5 files changed, 172 insertions(+), 16 deletions(-) diff --git a/mysql-test/r/join_cache.result b/mysql-test/r/join_cache.result index 6dbaa5a93a0..f2fda746e5e 100644 --- a/mysql-test/r/join_cache.result +++ b/mysql-test/r/join_cache.result @@ -5313,4 +5313,83 @@ a b c d SET SESSION join_cache_level = DEFAULT; SET optimizer_switch=@tmp_optimizer_switch; DROP TABLE t1,t2,t3; +# +# Bug #901478: semijoin + ORDER BY + join_cache_level=4|6 +# +CREATE TABLE t1 (a char(1)); +INSERT INTO t1 VALUES ('x'); +CREATE TABLE t2 (a int, b int, c int, KEY(a), KEY(b), KEY(c)); +INSERT INTO t2 VALUES +(9,1,0), (7,2,8), (2,3,5), (4,2,9), (8,3,8), (3,4,1), (5,5,4); +CREATE TABLE t3 (a CHAR(1)); +INSERT INTO t3 VALUES ('x'); +CREATE TABLE t4 (a int, b int, c int, KEY(b), KEY(c)); +INSERT INTO t4 VALUES +(9,1,0), (7,2,8), (2,3,5), (4,2,9), (8,3,8), (3,4,1), (5,5,4); +INSERT INTO t4 VALUES +(19,11,10), (17,12,18), (12,13,15), (14,12,19), +(18,13,18), (13,14,11), (15,15,14); +SET @tmp_optimizer_switch=@@optimizer_switch; +SET @@optimizer_switch='semijoin=on'; +SET @@optimizer_switch='firstmatch=off'; +SET @@optimizer_switch='mrr=off'; +SET @@optimizer_switch='semijoin_with_cache=off'; +set join_cache_level=1; +EXPLAIN +SELECT * FROM t1,t2 +WHERE t2.c IN (SELECT c FROM t3,t4 WHERE t4.a < 10) AND +t2.a BETWEEN 4 and 5 +ORDER BY t2.b; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 system NULL NULL NULL NULL 1 Using filesort +1 PRIMARY t3 system NULL NULL NULL NULL 1 +1 PRIMARY t2 range a,c a 5 NULL 1 Using index condition; Using where +1 PRIMARY t4 ref c c 5 test.t2.c 2 Using where; Start temporary; End temporary +SELECT * FROM t1,t2 +WHERE t2.c IN (SELECT c FROM t3,t4 WHERE t4.a < 10) AND +t2.a BETWEEN 4 and 5 +ORDER BY t2.b; +a a b c +x 4 2 9 +x 5 5 4 +set join_cache_level=4; +EXPLAIN +SELECT * FROM t1,t2 +WHERE t2.c IN (SELECT c FROM t3,t4 WHERE t4.a < 10) AND +t2.a BETWEEN 4 and 5 +ORDER BY t2.b; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 system NULL NULL NULL NULL 1 Using temporary; Using filesort +1 PRIMARY t3 system NULL NULL NULL NULL 1 +1 PRIMARY t2 range a,c a 5 NULL 1 Using index condition; Using where +1 PRIMARY t4 ref c c 5 test.t2.c 2 Using where; Start temporary; End temporary +SELECT * FROM t1,t2 +WHERE t2.c IN (SELECT c FROM t3,t4 WHERE t4.a < 10) AND +t2.a BETWEEN 4 and 5 +ORDER BY t2.b; +a a b c +x 4 2 9 +x 5 5 4 +SET @@optimizer_switch='semijoin_with_cache=on'; +set join_cache_level=6; +EXPLAIN +SELECT * FROM t1,t2 +WHERE t2.c IN (SELECT c FROM t3,t4 WHERE t4.a < 10) AND +t2.a BETWEEN 4 and 5 +ORDER BY t2.b; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 system NULL NULL NULL NULL 1 Using temporary; Using filesort +1 PRIMARY t3 system NULL NULL NULL NULL 1 +1 PRIMARY t2 range a,c a 5 NULL 1 Using index condition; Using where +1 PRIMARY t4 ref c c 5 test.t2.c 2 Using where; Start temporary; End temporary +SELECT * FROM t1,t2 +WHERE t2.c IN (SELECT c FROM t3,t4 WHERE t4.a < 10) AND +t2.a BETWEEN 4 and 5 +ORDER BY t2.b; +a a b c +x 4 2 9 +x 5 5 4 +SET join_cache_level = DEFAULT; +SET optimizer_switch=@tmp_optimizer_switch; +DROP TABLE t1,t2,t3,t4; set @@optimizer_switch=@save_optimizer_switch; diff --git a/mysql-test/t/join_cache.test b/mysql-test/t/join_cache.test index ef64e8caea1..5a48f7653e4 100644 --- a/mysql-test/t/join_cache.test +++ b/mysql-test/t/join_cache.test @@ -3361,5 +3361,68 @@ SET optimizer_switch=@tmp_optimizer_switch; DROP TABLE t1,t2,t3; +--echo # +--echo # Bug #901478: semijoin + ORDER BY + join_cache_level=4|6 +--echo # + +CREATE TABLE t1 (a char(1)); +INSERT INTO t1 VALUES ('x'); +CREATE TABLE t2 (a int, b int, c int, KEY(a), KEY(b), KEY(c)); +INSERT INTO t2 VALUES + (9,1,0), (7,2,8), (2,3,5), (4,2,9), (8,3,8), (3,4,1), (5,5,4); +CREATE TABLE t3 (a CHAR(1)); +INSERT INTO t3 VALUES ('x'); +CREATE TABLE t4 (a int, b int, c int, KEY(b), KEY(c)); +INSERT INTO t4 VALUES + (9,1,0), (7,2,8), (2,3,5), (4,2,9), (8,3,8), (3,4,1), (5,5,4); +INSERT INTO t4 VALUES + (19,11,10), (17,12,18), (12,13,15), (14,12,19), + (18,13,18), (13,14,11), (15,15,14); + +SET @tmp_optimizer_switch=@@optimizer_switch; +SET @@optimizer_switch='semijoin=on'; +SET @@optimizer_switch='firstmatch=off'; +SET @@optimizer_switch='mrr=off'; +SET @@optimizer_switch='semijoin_with_cache=off'; + +set join_cache_level=1; +EXPLAIN +SELECT * FROM t1,t2 + WHERE t2.c IN (SELECT c FROM t3,t4 WHERE t4.a < 10) AND + t2.a BETWEEN 4 and 5 + ORDER BY t2.b; +SELECT * FROM t1,t2 + WHERE t2.c IN (SELECT c FROM t3,t4 WHERE t4.a < 10) AND + t2.a BETWEEN 4 and 5 + ORDER BY t2.b; + +set join_cache_level=4; +EXPLAIN +SELECT * FROM t1,t2 + WHERE t2.c IN (SELECT c FROM t3,t4 WHERE t4.a < 10) AND + t2.a BETWEEN 4 and 5 + ORDER BY t2.b; +SELECT * FROM t1,t2 + WHERE t2.c IN (SELECT c FROM t3,t4 WHERE t4.a < 10) AND + t2.a BETWEEN 4 and 5 + ORDER BY t2.b; + +SET @@optimizer_switch='semijoin_with_cache=on'; +set join_cache_level=6; +EXPLAIN +SELECT * FROM t1,t2 + WHERE t2.c IN (SELECT c FROM t3,t4 WHERE t4.a < 10) AND + t2.a BETWEEN 4 and 5 + ORDER BY t2.b; +SELECT * FROM t1,t2 + WHERE t2.c IN (SELECT c FROM t3,t4 WHERE t4.a < 10) AND + t2.a BETWEEN 4 and 5 + ORDER BY t2.b; + +SET join_cache_level = DEFAULT; +SET optimizer_switch=@tmp_optimizer_switch; + +DROP TABLE t1,t2,t3,t4; + # this must be the last command in the file set @@optimizer_switch=@save_optimizer_switch; diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index 0819667e068..217966eb296 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -4138,6 +4138,16 @@ int setup_semijoin_dups_elimination(JOIN *join, ulonglong options, { /* Looks like we'll be using join buffer */ first_table= join->const_tables; + /* + Make sure that possible sorting of rows from the head table + is not to be employed. + */ + if (join->get_sort_by_join_tab()) + { + join->simple_order= 0; + join->simple_group= 0; + join->need_tmp= join->test_if_need_tmp_table(); + } break; } } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 7a86557901f..a4f3a1ee467 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1524,22 +1524,7 @@ JOIN::optimize() } } - /* - Check if we need to create a temporary table. - This has to be done if all tables are not already read (const tables) - and one of the following conditions holds: - - We are using DISTINCT (simple distinct's are already optimized away) - - We are using an ORDER BY or GROUP BY on fields not in the first table - - We are using different ORDER BY and GROUP BY orders - - The user wants us to buffer the result. - When the WITH ROLLUP modifier is present, we cannot skip temporary table - creation for the DISTINCT clause just because there are only const tables. - */ - need_tmp= ((const_tables != table_count && - ((select_distinct || !simple_order || !simple_group) || - (group_list && order) || - test(select_options & OPTION_BUFFER_RESULT))) || - (rollup.state != ROLLUP::STATE_NONE && select_distinct)); + need_tmp= test_if_need_tmp_table(); /* If the hint FORCE INDEX FOR ORDER BY/GROUP BY is used for the table diff --git a/sql/sql_select.h b/sql/sql_select.h index e24cab714fd..5a8dc846c92 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -1318,6 +1318,25 @@ public: return test(allowed_join_cache_types & JOIN_CACHE_HASHED_BIT) && max_allowed_join_cache_level > JOIN_CACHE_HASHED_BIT; } + /* + Check if we need to create a temporary table. + This has to be done if all tables are not already read (const tables) + and one of the following conditions holds: + - We are using DISTINCT (simple distinct's are already optimized away) + - We are using an ORDER BY or GROUP BY on fields not in the first table + - We are using different ORDER BY and GROUP BY orders + - The user wants us to buffer the result. + When the WITH ROLLUP modifier is present, we cannot skip temporary table + creation for the DISTINCT clause just because there are only const tables. + */ + bool test_if_need_tmp_table() + { + return ((const_tables != table_count && + ((select_distinct || !simple_order || !simple_group) || + (group_list && order) || + test(select_options & OPTION_BUFFER_RESULT))) || + (rollup.state != ROLLUP::STATE_NONE && select_distinct)); + } bool choose_subquery_plan(table_map join_tables); void get_partial_cost_and_fanout(int end_tab_idx, table_map filter_map, From 15e9be7a86189013f9b76c2625c8da65045e75d1 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 11 Dec 2011 22:58:01 +0200 Subject: [PATCH 192/288] Fixed valgrind problem: reference on deleted memory of temporary table name. Removed previous patch of this problem. --- sql/sql_derived.cc | 2 -- sql/sql_show.cc | 9 --------- 2 files changed, 11 deletions(-) diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 3eb89f65f40..713a9d86863 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -211,8 +211,6 @@ exit: } orig_table_list->derived_result= derived_result; orig_table_list->table= table; - orig_table_list->table_name= table->s->table_name.str; - orig_table_list->table_name_length= table->s->table_name.length; table->derived_select_number= first_select->select_number; table->s->tmp_table= NON_TRANSACTIONAL_TMP_TABLE; #ifndef NO_EMBEDDED_ACCESS_CHECKS diff --git a/sql/sql_show.cc b/sql/sql_show.cc index fccb071ccb3..f800a173672 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -729,7 +729,6 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) Protocol *protocol= thd->protocol; char buff[2048]; String buffer(buff, sizeof(buff), system_charset_info); - char *save_db, *save_table_name; bool retval= TRUE; // Assume error List field_list; DBUG_ENTER("mysqld_show_create"); @@ -739,10 +738,6 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) /* We want to preserve the tree for views. */ thd->lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_VIEW; - /* Store original names if called from SP */ - save_db= table_list->db; - save_table_name= table_list->table_name; - { Show_create_error_handler view_error_suppressor(thd, table_list); thd->push_internal_handler(&view_error_suppressor); @@ -825,11 +820,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) retval= FALSE; // ok error: - /* Restore table list if called by stored procedure */ - table_list->db= save_db; - table_list->table_name= save_table_name; DBUG_RETURN(retval); - } bool mysqld_show_create_db(THD *thd, char *dbname, From 63d32c115dd962b53cf7bcaa340472ee2f44f9e2 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Sun, 11 Dec 2011 19:41:53 -0800 Subject: [PATCH 193/288] Fixed LP bug #901709. The cause of the reported assertion failure was a division of a double value by 0. --- mysql-test/r/subselect_sj.result | 31 +++++++++++++++++++++++++++ mysql-test/r/subselect_sj_jcl6.result | 31 +++++++++++++++++++++++++++ mysql-test/t/subselect_sj.test | 30 ++++++++++++++++++++++++++ sql/opt_subselect.cc | 3 ++- 4 files changed, 94 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/subselect_sj.result b/mysql-test/r/subselect_sj.result index 9c4368a809b..a7b3cffb8d2 100644 --- a/mysql-test/r/subselect_sj.result +++ b/mysql-test/r/subselect_sj.result @@ -2118,4 +2118,35 @@ a b 1 1 set optimizer_switch= @tmp_otimizer_switch; DROP TABLE t1,t2,t3; +# +# Bug #901709: assertion failure with record count == 0 +# +CREATE TABLE t1 (a int, KEY (a)); +INSERT INTO t1 VALUES (4), (6); +CREATE TABLE t2 (a int, KEY (a)); +INSERT INTO t2 VALUES (4), (6); +CREATE TABLE t3 (b int); +INSERT INTO t3 VALUES (4); +CREATE TABLE t4 (c int); +SET @tmp_optimizer_switch=@@optimizer_switch; +SET @@optimizer_switch='semijoin=on'; +SET @@optimizer_switch='materialization=on'; +SET @@optimizer_switch='firstmatch=on'; +SET optimizer_switch='semijoin_with_cache=on'; +SET optimizer_prune_level=0; +EXPLAIN +SELECT * FROM t1, t2 +WHERE t1.a = t2.a AND t2.a IN (SELECT b FROM t3 STRAIGHT_JOIN t4); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t3 system NULL NULL NULL NULL 1 +1 PRIMARY ALL distinct_key NULL NULL NULL 1 +1 PRIMARY t1 ref a a 5 const 1 Using index +1 PRIMARY t2 ref a a 5 test.t3.b 1 Using index +2 MATERIALIZED t4 ALL NULL NULL NULL NULL 0 +SELECT * FROM t1, t2 +WHERE t1.a = t2.a AND t2.a IN (SELECT b FROM t3 STRAIGHT_JOIN t4); +a a +SET optimizer_prune_level=DEFAULT; +SET optimizer_switch=@tmp_optimizer_switch; +DROP TABLE t1,t2,t3,t4; 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 18882ce1db3..8de5af4cf56 100644 --- a/mysql-test/r/subselect_sj_jcl6.result +++ b/mysql-test/r/subselect_sj_jcl6.result @@ -2124,6 +2124,37 @@ a b 1 1 set optimizer_switch= @tmp_otimizer_switch; DROP TABLE t1,t2,t3; +# +# Bug #901709: assertion failure with record count == 0 +# +CREATE TABLE t1 (a int, KEY (a)); +INSERT INTO t1 VALUES (4), (6); +CREATE TABLE t2 (a int, KEY (a)); +INSERT INTO t2 VALUES (4), (6); +CREATE TABLE t3 (b int); +INSERT INTO t3 VALUES (4); +CREATE TABLE t4 (c int); +SET @tmp_optimizer_switch=@@optimizer_switch; +SET @@optimizer_switch='semijoin=on'; +SET @@optimizer_switch='materialization=on'; +SET @@optimizer_switch='firstmatch=on'; +SET optimizer_switch='semijoin_with_cache=on'; +SET optimizer_prune_level=0; +EXPLAIN +SELECT * FROM t1, t2 +WHERE t1.a = t2.a AND t2.a IN (SELECT b FROM t3 STRAIGHT_JOIN t4); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t3 system NULL NULL NULL NULL 1 +1 PRIMARY ALL distinct_key NULL NULL NULL 1 +1 PRIMARY t1 ref a a 5 const 1 Using index +1 PRIMARY t2 ref a a 5 test.t3.b 1 Using index +2 MATERIALIZED t4 ALL NULL NULL NULL NULL 0 +SELECT * FROM t1, t2 +WHERE t1.a = t2.a AND t2.a IN (SELECT b FROM t3 STRAIGHT_JOIN t4); +a a +SET optimizer_prune_level=DEFAULT; +SET optimizer_switch=@tmp_optimizer_switch; +DROP TABLE t1,t2,t3,t4; 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 130a5251846..4f8ed7f1643 100644 --- a/mysql-test/t/subselect_sj.test +++ b/mysql-test/t/subselect_sj.test @@ -1937,5 +1937,35 @@ set optimizer_switch= @tmp_otimizer_switch; DROP TABLE t1,t2,t3; +--echo # +--echo # Bug #901709: assertion failure with record count == 0 +--echo # + +CREATE TABLE t1 (a int, KEY (a)); +INSERT INTO t1 VALUES (4), (6); +CREATE TABLE t2 (a int, KEY (a)); +INSERT INTO t2 VALUES (4), (6); +CREATE TABLE t3 (b int); +INSERT INTO t3 VALUES (4); +CREATE TABLE t4 (c int); + +SET @tmp_optimizer_switch=@@optimizer_switch; +SET @@optimizer_switch='semijoin=on'; +SET @@optimizer_switch='materialization=on'; +SET @@optimizer_switch='firstmatch=on'; +SET optimizer_switch='semijoin_with_cache=on'; +SET optimizer_prune_level=0; + +EXPLAIN +SELECT * FROM t1, t2 + WHERE t1.a = t2.a AND t2.a IN (SELECT b FROM t3 STRAIGHT_JOIN t4); +SELECT * FROM t1, t2 + WHERE t1.a = t2.a AND t2.a IN (SELECT b FROM t3 STRAIGHT_JOIN t4); + +SET optimizer_prune_level=DEFAULT; +SET optimizer_switch=@tmp_optimizer_switch; + +DROP TABLE t1,t2,t3,t4; + # 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 217966eb296..ff0b80acb0e 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -2629,7 +2629,8 @@ bool Firstmatch_picker::check_qep(JOIN *join, - read_time is the same (i.e. FirstMatch doesn't add any cost - remove fanout added by the last table */ - *record_count /= join->positions[idx].records_read; + if (*record_count) + *record_count /= join->positions[idx].records_read; } else { From 6404504d0c10d58ad5861bdb72edd54508f1364c Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 12 Dec 2011 12:36:46 +0200 Subject: [PATCH 194/288] Fixed bug lp:900375 The range optimizer incorrectly chose a loose scan for group by when there is a correlated WHERE condition. This range access method cannot be executed for correlated conditions also with the "range checked for each record" because generally the range access method can change for each outer record. Loose scan destructively changes the query plan and removes the GROUP operation, which will result in wrong query plans if another range access is chosen dynamically. --- mysql-test/r/group_min_max.result | 231 +++++++++++++++++++++++++++++- mysql-test/t/group_min_max.test | 23 +++ sql/opt_range.cc | 2 + 3 files changed, 255 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/group_min_max.result b/mysql-test/r/group_min_max.result index 5b6ae943529..62c29d8fd01 100644 --- a/mysql-test/r/group_min_max.result +++ b/mysql-test/r/group_min_max.result @@ -2790,11 +2790,240 @@ INSERT INTO t2 VALUES (1),(1),(1),(4),(4),(5),(5),(8),(8),(9); explain select (select t2.a from t2 where t2.a >= t1.a group by t2.a) from t1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 -2 DEPENDENT SUBQUERY t2 range a a 5 NULL 6 Using where; Using index for group-by +2 DEPENDENT SUBQUERY t2 index a a 5 NULL 10 Using where; Using index select (select t2.a from t2 where t2.a >= t1.a group by t2.a) from t1; (select t2.a from t2 where t2.a >= t1.a group by t2.a) NULL NULL 9 drop table t1, t2; +# +# LP BUG#900375 Wrong result with derived_merge=ON, DISTINCT or GROUP BY, EXISTS +# +CREATE TABLE t1 ( a INT, b INT, KEY (b) ); +INSERT INTO t1 VALUES +(100,10),(101,11),(102,12),(103,13),(104,14), +(105,15),(106,16),(107,17),(108,18),(109,19); +EXPLAIN +SELECT alias1.* FROM t1, (SELECT * FROM t1) AS alias1 +WHERE EXISTS ( SELECT DISTINCT b FROM t1 WHERE b <= alias1.a ) ; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 index NULL b 5 NULL 10 Using index +1 PRIMARY ALL NULL NULL NULL NULL 10 Using where; Using join buffer +3 DEPENDENT SUBQUERY t1 index b b 5 NULL 10 Using where; Using index; Using temporary +2 DERIVED t1 ALL NULL NULL NULL NULL 10 +SELECT alias1.* FROM t1, (SELECT * FROM t1) AS alias1 +WHERE EXISTS ( SELECT DISTINCT b FROM t1 WHERE b <= alias1.a ) ; +a b +100 10 +100 10 +100 10 +100 10 +100 10 +100 10 +100 10 +100 10 +100 10 +100 10 +101 11 +101 11 +101 11 +101 11 +101 11 +101 11 +101 11 +101 11 +101 11 +101 11 +102 12 +102 12 +102 12 +102 12 +102 12 +102 12 +102 12 +102 12 +102 12 +102 12 +103 13 +103 13 +103 13 +103 13 +103 13 +103 13 +103 13 +103 13 +103 13 +103 13 +104 14 +104 14 +104 14 +104 14 +104 14 +104 14 +104 14 +104 14 +104 14 +104 14 +105 15 +105 15 +105 15 +105 15 +105 15 +105 15 +105 15 +105 15 +105 15 +105 15 +106 16 +106 16 +106 16 +106 16 +106 16 +106 16 +106 16 +106 16 +106 16 +106 16 +107 17 +107 17 +107 17 +107 17 +107 17 +107 17 +107 17 +107 17 +107 17 +107 17 +108 18 +108 18 +108 18 +108 18 +108 18 +108 18 +108 18 +108 18 +108 18 +108 18 +109 19 +109 19 +109 19 +109 19 +109 19 +109 19 +109 19 +109 19 +109 19 +109 19 +EXPLAIN +SELECT alias1.* FROM t1, t1 AS alias1 +WHERE EXISTS ( SELECT DISTINCT b FROM t1 WHERE b <= alias1.a ) ; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 index NULL b 5 NULL 10 Using index +1 PRIMARY alias1 ALL NULL NULL NULL NULL 10 Using where; Using join buffer +2 DEPENDENT SUBQUERY t1 index b b 5 NULL 10 Using where; Using index; Using temporary +SELECT alias1.* FROM t1, t1 AS alias1 +WHERE EXISTS ( SELECT DISTINCT b FROM t1 WHERE b <= alias1.a ) ; +a b +100 10 +100 10 +100 10 +100 10 +100 10 +100 10 +100 10 +100 10 +100 10 +100 10 +101 11 +101 11 +101 11 +101 11 +101 11 +101 11 +101 11 +101 11 +101 11 +101 11 +102 12 +102 12 +102 12 +102 12 +102 12 +102 12 +102 12 +102 12 +102 12 +102 12 +103 13 +103 13 +103 13 +103 13 +103 13 +103 13 +103 13 +103 13 +103 13 +103 13 +104 14 +104 14 +104 14 +104 14 +104 14 +104 14 +104 14 +104 14 +104 14 +104 14 +105 15 +105 15 +105 15 +105 15 +105 15 +105 15 +105 15 +105 15 +105 15 +105 15 +106 16 +106 16 +106 16 +106 16 +106 16 +106 16 +106 16 +106 16 +106 16 +106 16 +107 17 +107 17 +107 17 +107 17 +107 17 +107 17 +107 17 +107 17 +107 17 +107 17 +108 18 +108 18 +108 18 +108 18 +108 18 +108 18 +108 18 +108 18 +108 18 +108 18 +109 19 +109 19 +109 19 +109 19 +109 19 +109 19 +109 19 +109 19 +109 19 +109 19 +drop table t1; End of 5.1 tests diff --git a/mysql-test/t/group_min_max.test b/mysql-test/t/group_min_max.test index bd2cbd8a9f0..7c9c2b05eda 100644 --- a/mysql-test/t/group_min_max.test +++ b/mysql-test/t/group_min_max.test @@ -1114,4 +1114,27 @@ select (select t2.a from t2 where t2.a >= t1.a group by t2.a) from t1; drop table t1, t2; +--echo # +--echo # LP BUG#900375 Wrong result with derived_merge=ON, DISTINCT or GROUP BY, EXISTS +--echo # + +CREATE TABLE t1 ( a INT, b INT, KEY (b) ); +INSERT INTO t1 VALUES +(100,10),(101,11),(102,12),(103,13),(104,14), +(105,15),(106,16),(107,17),(108,18),(109,19); + +EXPLAIN +SELECT alias1.* FROM t1, (SELECT * FROM t1) AS alias1 +WHERE EXISTS ( SELECT DISTINCT b FROM t1 WHERE b <= alias1.a ) ; +SELECT alias1.* FROM t1, (SELECT * FROM t1) AS alias1 +WHERE EXISTS ( SELECT DISTINCT b FROM t1 WHERE b <= alias1.a ) ; + +EXPLAIN +SELECT alias1.* FROM t1, t1 AS alias1 +WHERE EXISTS ( SELECT DISTINCT b FROM t1 WHERE b <= alias1.a ) ; +SELECT alias1.* FROM t1, t1 AS alias1 +WHERE EXISTS ( SELECT DISTINCT b FROM t1 WHERE b <= alias1.a ) ; + +drop table t1; + --echo End of 5.1 tests diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 889af68f77a..bc434e2edc1 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -9337,6 +9337,8 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) DBUG_RETURN(NULL); if (table->s->keys == 0) /* There are no indexes to use. */ DBUG_RETURN(NULL); + if (join->conds && join->conds->used_tables() & OUTER_REF_TABLE_BIT) + DBUG_RETURN(NULL); /* Cannot execute with correlated conditions. */ /* Analyze the query in more detail. */ List_iterator select_items_it(join->fields_list); From 3d58fd6900128503d8516515496868c516ce63a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 12 Dec 2011 13:48:24 +0200 Subject: [PATCH 195/288] Bug#13418887 ERROR IN DIAGNOSTIC FUNCTION PAGE_REC_PRINT() When printing information about a ROW_FORMAT=REDUNDANT record, pass the correct flag to rec_get_next_offs(). rb:821 approved by Jimmy Yang --- storage/innodb_plugin/ChangeLog | 5 +++++ storage/innodb_plugin/include/page0page.h | 4 ++++ storage/innodb_plugin/page/page0page.c | 4 +++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index 951a1bd9c3b..37668b43697 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,3 +1,8 @@ +2011-12-10 The InnoDB Team + + * include/page0page.h, page/page0page.c: + Fix Bug#13418887 ERROR IN DIAGNOSTIC FUNCTION PAGE_REC_PRINT() + 2011-11-10 The InnoDB Team * handler/ha_innodb.cc, row/row0ins.c, innodb_replace.test: diff --git a/storage/innodb_plugin/include/page0page.h b/storage/innodb_plugin/include/page0page.h index 12c4fed75d2..ea9c212581c 100644 --- a/storage/innodb_plugin/include/page0page.h +++ b/storage/innodb_plugin/include/page0page.h @@ -892,6 +892,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. */ @@ -901,6 +902,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. */ @@ -940,6 +942,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/storage/innodb_plugin/page/page0page.c b/storage/innodb_plugin/page/page0page.c index 93869e997b5..52f6678be0a 100644 --- a/storage/innodb_plugin/page/page0page.c +++ b/storage/innodb_plugin/page/page0page.c @@ -1613,13 +1613,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. */ @@ -1780,6 +1781,7 @@ page_print( page_dir_print(page, dn); page_print_list(block, index, rn); } +# endif /* UNIV_BTR_PRINT */ #endif /* !UNIV_HOTBACKUP */ /***************************************************************//** From 6ad3179d6d7facbf55897088c7f0b4d2fcdbd675 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 12 Dec 2011 13:37:18 +0100 Subject: [PATCH 196/288] Fix GCC build failure in PBXT in some cases/platforms. --- storage/pbxt/src/lock_xt.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/storage/pbxt/src/lock_xt.h b/storage/pbxt/src/lock_xt.h index 4e5af648c37..ec426354e4e 100644 --- a/storage/pbxt/src/lock_xt.h +++ b/storage/pbxt/src/lock_xt.h @@ -67,9 +67,9 @@ inline void xt_atomic_inc1(volatile xtWord1 *mptr) #elif defined(XT_ATOMIC_GNUC_X86) xtWord1 val; - asm volatile ("movb %1,%0" : "=r" (val) : "m" (*mptr) : "memory"); + asm volatile ("movb %1,%0" : "=q" (val) : "m" (*mptr) : "memory"); val++; - asm volatile ("xchgb %1,%0" : "=r" (val) : "m" (*mptr), "0" (val) : "memory"); + asm volatile ("xchgb %1,%0" : "=q" (val) : "m" (*mptr), "0" (val) : "memory"); #elif defined(XT_ATOMIC_SOLARIS_LIB) atomic_inc_8(mptr); #else @@ -91,9 +91,9 @@ inline xtWord1 xt_atomic_dec1(volatile xtWord1 *mptr) #elif defined(XT_ATOMIC_GNUC_X86) xtWord1 val2; - asm volatile ("movb %1, %0" : "=r" (val) : "m" (*mptr) : "memory"); + asm volatile ("movb %1, %0" : "=q" (val) : "m" (*mptr) : "memory"); val--; - asm volatile ("xchgb %1,%0" : "=r" (val2) : "m" (*mptr), "0" (val) : "memory"); + asm volatile ("xchgb %1,%0" : "=q" (val2) : "m" (*mptr), "0" (val) : "memory"); /* Should work, but compiler makes a mistake? * asm volatile ("xchgb %1, %0" : : "r" (val), "m" (*mptr) : "memory"); */ From a3e8ce275c9de6e01bce1c0d4a44e0a4b9a8b867 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 12 Dec 2011 16:28:16 +0100 Subject: [PATCH 197/288] new "./configure --disable-distribution" option --- config/ac-macros/readline.m4 | 39 +++++++++++++++++++++++++++--------- configure.in | 29 ++++++++++++++++++++++++--- 2 files changed, 56 insertions(+), 12 deletions(-) diff --git a/config/ac-macros/readline.m4 b/config/ac-macros/readline.m4 index e1ed8420bfb..9e62d9add3e 100644 --- a/config/ac-macros/readline.m4 +++ b/config/ac-macros/readline.m4 @@ -40,23 +40,44 @@ AC_DEFUN([MYSQL_CHECK_LIBEDIT_INTERFACE], [ ]) AC_DEFUN([MYSQL_CHECK_NEW_RL_INTERFACE], [ - AC_CACHE_CHECK([defined rl_compentry_func_t and rl_completion_func_t], mysql_cv_new_rl_interface, - AC_TRY_COMPILE( - [ + AC_CACHE_CHECK([for system libreadline], mysql_cv_new_rl_interface, + AC_COMPILE_IFELSE( + [AC_LANG_SOURCE([ #include "stdio.h" #include "readline/readline.h" - ], - [ rl_completion_func_t *func1= (rl_completion_func_t*)0; rl_compentry_func_t *func2= (rl_compentry_func_t*)0; - ], + ])], [ - mysql_cv_new_rl_interface=yes - AC_DEFINE_UNQUOTED([USE_NEW_READLINE_INTERFACE], [1], - [used new readline interface (are rl_completion_func_t and rl_compentry_func_t defined)]) + AC_PREPROC_IFELSE( + [AC_LANG_SOURCE([ + #include "stdio.h" + #include "readline/readline.h" + #if RL_VERSION_MAJOR > 5 + #error + #endif + ])], [ rl_v5=yes ], [ rl_v5=no ], + ) + if [test "$rl_v5" = "yes"] + then + mysql_cv_new_rl_interface=yes + else + if [test "$enable_distribution" = "yes"] + then + mysql_cv_new_rl_interface=no + else + mysql_cv_new_rl_interface=yes + enable_distribution=warn + fi + fi ], [mysql_cv_new_rl_interface=no] ) + if [test "$mysql_cv_new_rl_interface" = yes] + then + AC_DEFINE_UNQUOTED([USE_NEW_READLINE_INTERFACE], [1], + [used new readline interface (are rl_completion_func_t and rl_compentry_func_t defined)]) + fi ) ]) diff --git a/configure.in b/configure.in index 34ca4e171b2..179f4bfcce2 100644 --- a/configure.in +++ b/configure.in @@ -632,6 +632,14 @@ AC_ARG_WITH(other-libc, ) AC_SUBST(NOINST_LDFLAGS) +AC_ARG_ENABLE(distribution, + AC_HELP_STRING( + [--disable-distribution], + [Allow linking with system GPLv3 libraries. It may result in a binary that can not be legally distributed.]), + [ enable_distribution=$enableval ], + [ enable_distribution=yes ] + ) + # # Check if we are using Linux and a glibc compiled with static nss # (this is true on the MySQL build machines to avoid NSS problems) @@ -1573,7 +1581,7 @@ fi AC_MSG_CHECKING([for OpenSolaris Bug 6611808]) save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Werror" -AC_COMPILE_IFELSE([ +AC_COMPILE_IFELSE([AC_LANG_SOURCE([ #include void dummy() {} int main() @@ -1582,7 +1590,7 @@ AC_COMPILE_IFELSE([ pthread_once(&once_control, dummy); return 0; } -], [ +])], [ AC_DEFINE([PTHREAD_ONCE_INITIALIZER], [{PTHREAD_ONCE_INIT}], [See OpenSolaris Bug 6611808]) AC_MSG_RESULT([yes]) @@ -2712,6 +2720,8 @@ case $SYSTEM_TYPE in compile_libedit=yes AC_DEFINE_UNQUOTED(HAVE_HIST_ENTRY, 1) AC_DEFINE_UNQUOTED(USE_LIBEDIT_INTERFACE, 1) + AC_MSG_CHECKING([for libedit/readline]) + AC_MSG_RESULT([libedit bundled]) elif test "$with_readline" = "yes" then readline_topdir="cmd-line-utils" @@ -2722,6 +2732,8 @@ case $SYSTEM_TYPE in compile_readline=yes want_to_use_readline="yes" AC_DEFINE_UNQUOTED(USE_NEW_READLINE_INTERFACE, 1) + AC_MSG_CHECKING([for libedit/readline]) + AC_MSG_RESULT([readline bundled]) else # Use system readline library AC_LANG_SAVE @@ -2736,12 +2748,16 @@ case $SYSTEM_TYPE in # this way we avoid linking commercial source with GPL readline readline_link="-lreadline" want_to_use_readline="yes" + AC_MSG_CHECKING([for libedit/readline]) + AC_MSG_RESULT([readline system]) elif [test "$mysql_cv_libedit_interface" = "yes"] then # Use libedit readline_link="-ledit" + AC_MSG_CHECKING([for libedit/readline]) + AC_MSG_RESULT([libedit system]) else - AC_MSG_ERROR([Could not find system readline or libedit libraries + AC_MSG_ERROR([Could not find usable system readline or libedit libraries Use --with-readline or --with-libedit to use the bundled versions of libedit or readline]) fi @@ -2987,6 +3003,13 @@ if test X"$with_plugin_ndbcluster" = Xyes ; then echo for more details. fi +if test "$enable_distribution" = "warn" +then + echo "You have linked MariaDB with GPLv3 libraries!" + echo "You may not distribute the resulting binary. If you do, you will " + echo "put yourself into a legal problem with Free Software Foundation." +fi + # The first line "Thank you ..." is checked in ./Do-compile to verify that configure # ended sucessfully - don't remove it. echo From ad84fb5c3763b3a5c6c2146c8fc824f0d385c77c Mon Sep 17 00:00:00 2001 From: Annamalai Gurusami Date: Tue, 13 Dec 2011 14:26:12 +0530 Subject: [PATCH 198/288] Bug #13117023: Innodb increments handler_read_key when it should not The counter handler_read_key (SSV::ha_read_key_count) is incremented incorrectly. The mysql server maintains a per thread system_status_var (SSV) object. This object contains among other things the counter SSV::ha_read_key_count. The purpose of this counter is to measure the number of requests to read a row based on a key (or the number of index lookups). This counter was wrongly incremented in the ha_innobase::innobase_get_index(). The fix removes this increment statement (for both innodb and innodb_plugin). The various callers of the innobase_get_index() was checked to determine if anybody must increment this counter (if they first call innobase_get_index() and then perform an index lookup). It was found that no caller of innobase_get_index() needs to worry about the SSV::ha_read_key_count counter. --- mysql-test/suite/innodb/r/innodb.result | 5 +++++ mysql-test/suite/innodb/t/innodb.test | 11 +++++++++++ mysql-test/suite/innodb_plugin/r/innodb.result | 11 +++++++++++ mysql-test/suite/innodb_plugin/t/innodb.test | 11 +++++++++++ storage/innobase/handler/ha_innodb.cc | 1 - storage/innodb_plugin/ChangeLog | 6 ++++++ storage/innodb_plugin/handler/ha_innodb.cc | 1 - 7 files changed, 44 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/innodb/r/innodb.result b/mysql-test/suite/innodb/r/innodb.result index ad140cc59be..fd311de001c 100644 --- a/mysql-test/suite/innodb/r/innodb.result +++ b/mysql-test/suite/innodb/r/innodb.result @@ -2365,3 +2365,8 @@ t1 CREATE TABLE `t1` ( ) ENGINE=InnoDB DEFAULT CHARSET=latin1 drop table t1; set storage_engine=MyISAM; +Variable_name Value +Handler_read_key 0 +f1 +Variable_name Value +Handler_read_key 1 diff --git a/mysql-test/suite/innodb/t/innodb.test b/mysql-test/suite/innodb/t/innodb.test index ef050390b48..f20ea46b200 100644 --- a/mysql-test/suite/innodb/t/innodb.test +++ b/mysql-test/suite/innodb/t/innodb.test @@ -1389,6 +1389,17 @@ eval set storage_engine=$default; -- disable_query_log SET GLOBAL innodb_thread_concurrency = @innodb_thread_concurrency_orig; +# +# Test fix for bug 13117023. InnoDB increments HA_READ_KEY_COUNT (aka +# HANDLER_READ_KEY) when it should not. +# +create table t1 (f1 integer primary key) engine=innodb; +flush status; +show status like "handler_read_key"; +select f1 from t1; +show status like "handler_read_key"; +drop table t1; + ####################################################################### # # # Please, DO NOT TOUCH this file as well as the innodb.result file. # diff --git a/mysql-test/suite/innodb_plugin/r/innodb.result b/mysql-test/suite/innodb_plugin/r/innodb.result index cdb61f3ba98..9435670f42d 100644 --- a/mysql-test/suite/innodb_plugin/r/innodb.result +++ b/mysql-test/suite/innodb_plugin/r/innodb.result @@ -3257,3 +3257,14 @@ Handler_update 1 Variable_name Value Handler_delete 1 DROP TABLE bug58912; +create table t1 (f1 integer primary key) engine=innodb; +flush status; +show status like "handler_read_key"; +Variable_name Value +Handler_read_key 0 +select f1 from t1; +f1 +show status like "handler_read_key"; +Variable_name Value +Handler_read_key 1 +drop table t1; diff --git a/mysql-test/suite/innodb_plugin/t/innodb.test b/mysql-test/suite/innodb_plugin/t/innodb.test index 1480492cf2a..d4f2088cc50 100644 --- a/mysql-test/suite/innodb_plugin/t/innodb.test +++ b/mysql-test/suite/innodb_plugin/t/innodb.test @@ -2571,6 +2571,17 @@ SET GLOBAL innodb_thread_concurrency = @innodb_thread_concurrency_orig; # Clean up after the Bug#55284/Bug#58912 test case. DROP TABLE bug58912; +# +# Test fix for bug 13117023. InnoDB increments HA_READ_KEY_COUNT (aka +# HANDLER_READ_KEY) when it should not. +# +create table t1 (f1 integer primary key) engine=innodb; +flush status; +show status like "handler_read_key"; +select f1 from t1; +show status like "handler_read_key"; +drop table t1; + ####################################################################### # # # Please, DO NOT TOUCH this file as well as the innodb.result file. # diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 6709f790994..a4d79a5934e 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -4802,7 +4802,6 @@ ha_innobase::innobase_get_index( dict_index_t* index = 0; DBUG_ENTER("innobase_get_index"); - ha_statistic_increment(&SSV::ha_read_key_count); ut_ad(user_thd == ha_thd()); ut_a(prebuilt->trx == thd_to_trx(user_thd)); diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index 37668b43697..5fc0cce3ff2 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,3 +1,9 @@ +2011-12-13 The InnoDB Team + + * handler/ha_innodb.cc, innodb.test, innodb.result: + Fix Bug#13117023: InnoDB was incrementing the handler_read_key, + also the SSV::ha_read_key_count, at the wrong place. + 2011-12-10 The InnoDB Team * include/page0page.h, page/page0page.c: diff --git a/storage/innodb_plugin/handler/ha_innodb.cc b/storage/innodb_plugin/handler/ha_innodb.cc index d84bd38ba7e..122bf1f7846 100644 --- a/storage/innodb_plugin/handler/ha_innodb.cc +++ b/storage/innodb_plugin/handler/ha_innodb.cc @@ -5520,7 +5520,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; From b653115c8e0ce1015b74f9aeab3ad30f71ce4379 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Tue, 13 Dec 2011 14:00:20 +0200 Subject: [PATCH 199/288] Fixed valgrind error when storing db_name_length in query_cache. - Changed storage to be 2 bytes instead of sizeof(size_t) (simple optimization) - Fixed bug when using query_cache_strip_comments and query that started with '(' - Fixed DBUG_PRINT() that used wrong (not initialized) variables. mysql-test/mysql-test-run.pl: Added some space to make output more readable. mysql-test/r/query_cache.result: Updated test results mysql-test/t/query_cache.test: Added test with query_cache_strip_comments sql/mysql_priv.h: Added QUERY_CACHE_DB_LENGTH_SIZE sql/sql_cache.cc: Fixed bug when using query_cache_strip_comments and query that started with '(' Store db length in 2 characters instead of size_t. Get db length from correct position (earlier we had an error when query started with ' ') Fixed DBUG_PRINT() that used wrong (not initialized) variables. --- mysql-test/mysql-test-run.pl | 6 ++--- mysql-test/r/query_cache.result | 33 ++++++++++++++++++------ mysql-test/t/query_cache.test | 12 +++++++++ sql/mysql_priv.h | 1 + sql/sp_head.cc | 11 ++++---- sql/sql_cache.cc | 45 +++++++++++++++++++++------------ sql/sql_parse.cc | 10 ++++---- 7 files changed, 81 insertions(+), 37 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 8cf7c8b7970..85b47864701 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -5145,10 +5145,10 @@ sub mysqld_start ($$) { # Write a message about this to the normal log file my $trace_name= "$opt_vardir/log/".$mysqld->name().".trace"; mtr_tofile($output, - "NOTE: When running with --valgrind --debug the output from", - "mysqld(where the valgrind messages shows up) is stored ", + "NOTE: When running with --valgrind --debug the output from ", + "mysqld (where the valgrind messages shows up) is stored ", "together with the trace file to make it ", - "easier to find the exact position of valgrind errors.", + "easier to find the exact position of valgrind errors. ", "See trace file $trace_name.\n"); $output= $trace_name; diff --git a/mysql-test/r/query_cache.result b/mysql-test/r/query_cache.result index a5d995ffea0..26bf4e74219 100644 --- a/mysql-test/r/query_cache.result +++ b/mysql-test/r/query_cache.result @@ -912,13 +912,13 @@ a a show status like "Qcache_queries_in_cache"; Variable_name Value -Qcache_queries_in_cache 0 +Qcache_queries_in_cache 1 show status like "Qcache_inserts"; Variable_name Value -Qcache_inserts 18 +Qcache_inserts 19 show status like "Qcache_hits"; Variable_name Value -Qcache_hits 6 +Qcache_hits 7 DROP TABLE t1; SET GLOBAL query_cache_size=0; SET SESSION query_cache_type = 2; @@ -1070,10 +1070,10 @@ flush status; a show status like "Qcache_queries_in_cache"; Variable_name Value -Qcache_queries_in_cache 0 +Qcache_queries_in_cache 1 show status like "Qcache_inserts"; Variable_name Value -Qcache_inserts 0 +Qcache_inserts 1 show status like "Qcache_hits"; Variable_name Value Qcache_hits 0 @@ -1081,13 +1081,30 @@ Qcache_hits 0 a show status like "Qcache_queries_in_cache"; Variable_name Value -Qcache_queries_in_cache 0 +Qcache_queries_in_cache 1 show status like "Qcache_inserts"; Variable_name Value -Qcache_inserts 0 +Qcache_inserts 1 show status like "Qcache_hits"; Variable_name Value -Qcache_hits 0 +Qcache_hits 1 +set global query_cache_strip_comments=1; +(select a from t1) union (select a from t1); +a +(select a from t1) /* */union (select a from t1); +a +set global query_cache_strip_comments=0; +(select a from t1) union (select a from t1); +a +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 4 drop table t1; create table t1 (a int); insert into t1 values (1),(2); diff --git a/mysql-test/t/query_cache.test b/mysql-test/t/query_cache.test index 0d57a5640bf..dc403a30732 100644 --- a/mysql-test/t/query_cache.test +++ b/mysql-test/t/query_cache.test @@ -776,7 +776,19 @@ show status like "Qcache_hits"; show status like "Qcache_queries_in_cache"; show status like "Qcache_inserts"; show status like "Qcache_hits"; + +set global query_cache_strip_comments=1; +(select a from t1) union (select a from t1); +(select a from t1) /* */union (select a from t1); +set global query_cache_strip_comments=0; +(select a from t1) union (select a from t1); +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; + drop table t1; + +# # SP cursors and selects with query cache (BUG#9715) # create table t1 (a int); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index f0365a856da..d263c8aba4f 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1045,6 +1045,7 @@ struct Query_cache_query_flags MY_LOCALE *lc_time_names; }; #define QUERY_CACHE_FLAGS_SIZE sizeof(Query_cache_query_flags) +#define QUERY_CACHE_DB_LENGTH_SIZE 2 #include "sql_cache.h" #define query_cache_store_query(A, B) query_cache.store_query(A, B) #define query_cache_destroy() query_cache.destroy() diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 2d0870674f9..b30347a5ca7 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1024,17 +1024,18 @@ subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str) buffer :== The input statement(s) '\0' Terminating null char - Length of following current database name (size_t) + Length of following current database name 2 Name of current database Flags struct */ - buf_len= qbuf.length() + 1 + sizeof(size_t) + thd->db_length + - QUERY_CACHE_FLAGS_SIZE + 1; + buf_len= (qbuf.length() + 1 + QUERY_CACHE_DB_LENGTH_SIZE + thd->db_length + + QUERY_CACHE_FLAGS_SIZE + 1); if ((pbuf= (char *) alloc_root(thd->mem_root, buf_len))) { + char *ptr= pbuf + qbuf.length(); memcpy(pbuf, qbuf.ptr(), qbuf.length()); - pbuf[qbuf.length()]= 0; - memcpy(pbuf+qbuf.length()+1, (char *) &thd->db_length, sizeof(size_t)); + *ptr= 0; + int2store(ptr+1, thd->db_length); } else DBUG_RETURN(TRUE); diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 98d98c1696e..16b6d78576a 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -462,6 +462,7 @@ static void make_base_query(String *new_query, DBUG_ASSERT(query[query_length] == 0); DBUG_ASSERT(!is_white_space(query[0])); + new_query->length(0); // Don't copy anything from old buffer if (new_query->realloc(query_length + additional_length)) { /* @@ -540,8 +541,11 @@ insert_space: } if (buffer == last_space) buffer--; // Remove the last space - *buffer= 0; + *buffer= 0; // End zero after query new_query->length((size_t) (buffer - new_query->ptr())); + + /* Copy db_length */ + memcpy(buffer+1, query_end+1, QUERY_CACHE_DB_LENGTH_SIZE); } @@ -1473,8 +1477,8 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d", /* Key is query + database + flag */ if (thd->db_length) { - memcpy((char*) (query + query_length + 1 + sizeof(size_t)), thd->db, - thd->db_length); + memcpy((char*) (query + query_length + 1 + QUERY_CACHE_DB_LENGTH_SIZE), + thd->db, thd->db_length); DBUG_PRINT("qcache", ("database: %s length: %u", thd->db, (unsigned) thd->db_length)); } @@ -1482,8 +1486,8 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d", { DBUG_PRINT("qcache", ("No active database")); } - tot_length= query_length + thd->db_length + 1 + sizeof(size_t) + - QUERY_CACHE_FLAGS_SIZE; + tot_length= (query_length + thd->db_length + 1 + + QUERY_CACHE_DB_LENGTH_SIZE + QUERY_CACHE_FLAGS_SIZE); /* We should only copy structure (don't use it location directly) because of alignment issue @@ -1642,7 +1646,7 @@ Query_cache::send_result_to_client(THD *thd, char *org_sql, uint query_length) Query_cache_block_table *block_table, *block_table_end; ulong tot_length; Query_cache_query_flags flags; - const char *sql, *sql_end; + const char *sql, *sql_end, *found_brace= 0; DBUG_ENTER("Query_cache::send_result_to_client"); /* @@ -1716,9 +1720,16 @@ Query_cache::send_result_to_client(THD *thd, char *org_sql, uint query_length) case '\n': case '\t': case ' ': - case '(': // To handle (select a from t1) union (select a from t1); sql++; continue; + case '(': // To handle (select a from t1) union (select a from t1); + if (!found_brace) + { + found_brace= sql; + sql++; + continue; + } + /* fall trough */ default: break; } @@ -1752,8 +1763,7 @@ Query_cache::send_result_to_client(THD *thd, char *org_sql, uint query_length) sure the new current database has a name with the same length as the previous one. */ - size_t db_len; - memcpy((char *) &db_len, (sql + query_length + 1), sizeof(size_t)); + size_t db_len= uint2korr(sql_end+1); if (thd->db_length != db_len) { /* @@ -1788,8 +1798,11 @@ Query_cache::send_result_to_client(THD *thd, char *org_sql, uint query_length) Query_cache_block *query_block; if (opt_query_cache_strip_comments) { + if (found_brace) + sql= found_brace; make_base_query(&thd->base_query, sql, (size_t) (sql_end - sql), - thd->db_length + 1 + QUERY_CACHE_FLAGS_SIZE); + thd->db_length + 1 + QUERY_CACHE_DB_LENGTH_SIZE + + QUERY_CACHE_FLAGS_SIZE); sql= thd->base_query.ptr(); query_length= thd->base_query.length(); } @@ -1799,15 +1812,15 @@ Query_cache::send_result_to_client(THD *thd, char *org_sql, uint query_length) thd->base_query.set(sql, query_length, system_charset_info); } - tot_length= query_length + 1 + sizeof(size_t) + - thd->db_length + QUERY_CACHE_FLAGS_SIZE; + tot_length= (query_length + 1 + QUERY_CACHE_DB_LENGTH_SIZE + + thd->db_length + QUERY_CACHE_FLAGS_SIZE); if (thd->db_length) { - memcpy((char*) (sql+query_length+1+ sizeof(size_t)), thd->db, - thd->db_length); + memcpy((uchar*) sql + query_length + 1 + QUERY_CACHE_DB_LENGTH_SIZE, + thd->db, thd->db_length); DBUG_PRINT("qcache", ("database: '%s' length: %u", - thd->db, (unsigned)thd->db_length)); + thd->db, (uint) thd->db_length)); } else { @@ -1929,7 +1942,7 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d", { DBUG_PRINT("qcache", ("Temporary table detected: '%s.%s'", - table_list.db, table_list.alias)); + tmptable->s->db.str, tmptable->alias.c_ptr())); unlock(); /* We should not store result of this query because it contain diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index cdfbce7f0e3..1676d4a09f4 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -508,10 +508,10 @@ static void handle_bootstrap_impl(THD *thd) query= (char *) thd->memdup_w_gap(buff, length + 1, thd->db_length + 1 + + QUERY_CACHE_DB_LENGTH_SIZE + QUERY_CACHE_FLAGS_SIZE); - size_t db_len= 0; - memcpy(query + length + 1, (char *) &db_len, sizeof(size_t)); thd->set_query(query, length); + int2store(query + length + 1, 0); // No db in bootstrap DBUG_PRINT("query",("%-.4096s", thd->query())); #if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) thd->profiling.start_new_query(); @@ -1880,7 +1880,8 @@ bool alloc_query(THD *thd, const char *packet, uint packet_length) */ if (! (query= (char*) thd->memdup_w_gap(packet, packet_length, - 1 + sizeof(size_t) + thd->db_length + + 1 + thd->db_length + + QUERY_CACHE_DB_LENGTH_SIZE + QUERY_CACHE_FLAGS_SIZE))) return TRUE; query[packet_length]= '\0'; @@ -1889,8 +1890,7 @@ bool alloc_query(THD *thd, const char *packet, uint packet_length) also store this length, in case current database is changed during execution. We might need to reallocate the 'query' buffer */ - char *len_pos = (query + packet_length + 1); - memcpy(len_pos, (char *) &thd->db_length, sizeof(size_t)); + int2store(query + packet_length + 1, thd->db_length); thd->set_query(query, packet_length); From a64a25baf9dd9ecff571bbab7a0dcb860eb06d24 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Tue, 13 Dec 2011 17:44:19 +0200 Subject: [PATCH 200/288] Bug#11754011: 45546: START WINDOWS SERVICE, THEN EXECUTE WHAT IS NEEDED. Added a global read-only option slow-start-timeout to control the Windows service control manager's service start timeout, that was currently hard-coded to be 15 seconds. The default of the new option is 15 seconds. The timeout can also be set to 0 (to mean no timeout applicable). --- sql/mysqld.cc | 18 ++++++++++++++++++ sql/nt_servc.cc | 8 +++++++- sql/nt_servc.h | 10 ++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 7363128ec04..6afc20141e1 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -368,6 +368,9 @@ my_bool locked_in_memory; bool opt_using_transactions; bool volatile abort_loop; bool volatile shutdown_in_progress; +#if defined(_WIN32) && !defined(EMBEDDED_LIBRARY) +ulong slow_start_timeout; +#endif /* True if the bootstrap thread is running. Protected by LOCK_thread_count, just like thread_count. @@ -4369,6 +4372,14 @@ int mysqld_main(int argc, char **argv) #endif } + /* + The subsequent calls may take a long time : e.g. innodb log read. + Thus set the long running service control manager timeout + */ +#if defined(_WIN32) && !defined(EMBEDDED_LIBRARY) + Service.SetSlowStarting(slow_start_timeout); +#endif + if (init_server_components()) unireg_abort(1); @@ -5883,6 +5894,13 @@ struct my_option my_long_options[]= "Don't give threads different priorities. This option is deprecated " "because it has no effect; the implied behavior is already the default.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, +#if defined(_WIN32) && !defined(EMBEDDED_LIBRARY) + {"slow-start-timeout", 0, + "Maximum number of milliseconds that the service control manager should wait " + "before trying to kill the windows service during startup" + "(Default: 15000).", &slow_start_timeout, &slow_start_timeout, 0, + GET_ULONG, REQUIRED_ARG, 15000, 0, 0, 0, 0, 0}, +#endif #ifdef HAVE_REPLICATION {"sporadic-binlog-dump-fail", 0, "Option used by mysql-test for debugging and testing of replication.", diff --git a/sql/nt_servc.cc b/sql/nt_servc.cc index 1f1b7f0c20f..d6a8eac7ed5 100644 --- a/sql/nt_servc.cc +++ b/sql/nt_servc.cc @@ -276,7 +276,13 @@ error: void NTService::SetRunning() { if (pService) - pService->SetStatus(SERVICE_RUNNING,NO_ERROR, 0, 0, 0); + pService->SetStatus(SERVICE_RUNNING, NO_ERROR, 0, 0, 0); +} + +void NTService::SetSlowStarting(unsigned long timeout) +{ + if (pService) + pService->SetStatus(SERVICE_START_PENDING,NO_ERROR, 0, 0, timeout); } diff --git a/sql/nt_servc.h b/sql/nt_servc.h index 5bee42dedf0..949499d8d7f 100644 --- a/sql/nt_servc.h +++ b/sql/nt_servc.h @@ -71,6 +71,16 @@ class NTService */ void SetRunning(void); + /** + Sets a timeout after which SCM will abort service startup if SetRunning() + was not called or the timeout was not extended with another call to + SetSlowStarting(). Should be called when static initialization completes, + and the variable initialization part begins + + @arg timeout the timeout to pass to the SCM (in milliseconds) + */ + void SetSlowStarting(unsigned long timeout); + /* Stop() is to be called by the application to stop the service From 33c26f78428d30e1ca860803e5e0142ca41f8b61 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Tue, 13 Dec 2011 19:57:19 +0200 Subject: [PATCH 201/288] Fixed bug: lp:887051 ; Error in recovery with LOAD DATA + DELETE mysql-test/suite/maria/r/maria-recovery3.result: Added test case for recovery bug mysql-test/suite/maria/t/maria-recovery3.test: Added test case for recovery bug storage/maria/ha_maria.cc: Don't print query twice to log storage/maria/ma_delete.c: More DBUG_PRINT storage/maria/ma_key_recover.c: Added new asserts to detect errors earlier storage/maria/ma_recovery.c: Update all states when moving a non-transactional file to transactional. This fixes lp:887051 --- mysql-test/std_data/bug887051.txt | 2 ++ .../suite/maria/r/maria-recovery3.result | 22 +++++++++++++++++++ mysql-test/suite/maria/t/maria-recovery3.test | 18 +++++++++++++++ storage/maria/ha_maria.cc | 12 ++++++++-- storage/maria/ma_delete.c | 5 +++-- storage/maria/ma_key_recover.c | 5 ++++- storage/maria/ma_recovery.c | 4 ++++ 7 files changed, 63 insertions(+), 5 deletions(-) create mode 100644 mysql-test/std_data/bug887051.txt diff --git a/mysql-test/std_data/bug887051.txt b/mysql-test/std_data/bug887051.txt new file mode 100644 index 00000000000..a1df5f35bb1 --- /dev/null +++ b/mysql-test/std_data/bug887051.txt @@ -0,0 +1,2 @@ +saved1 +saved2 diff --git a/mysql-test/suite/maria/r/maria-recovery3.result b/mysql-test/suite/maria/r/maria-recovery3.result index cab3fd55091..89643b7c7a0 100644 --- a/mysql-test/suite/maria/r/maria-recovery3.result +++ b/mysql-test/suite/maria/r/maria-recovery3.result @@ -89,6 +89,28 @@ check table t1 extended; Table Op Msg_type Msg_text mysqltest.t1 check status OK drop table t1; +CREATE TABLE t1 ( word VARCHAR(255) PRIMARY KEY ) ENGINE=Aria; +LOAD DATA INFILE '../../std_data/bug887051.txt' INTO TABLE t1; +SET AUTOCOMMIT=0; +DELETE FROM t1; +LOAD DATA INFILE '../../std_data/bug887051.txt' INTO TABLE t1 IGNORE 1 LINES; +COMMIT; +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 +* 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 +failure +use mysqltest; +select * from t1; +word +saved2 +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-recovery3.test b/mysql-test/suite/maria/t/maria-recovery3.test index 192361633ca..c8333a66f30 100644 --- a/mysql-test/suite/maria/t/maria-recovery3.test +++ b/mysql-test/suite/maria/t/maria-recovery3.test @@ -109,6 +109,24 @@ truncate table t1; check table t1 extended; drop table t1; +# +# Test for BUG#887051; Failure in recovery with delete +# + +let $mvr_restore_old_snapshot=0; +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; +CREATE TABLE t1 ( word VARCHAR(255) PRIMARY KEY ) ENGINE=Aria; +LOAD DATA INFILE '../../std_data/bug887051.txt' INTO TABLE t1; +SET AUTOCOMMIT=0; +DELETE FROM t1; +LOAD DATA INFILE '../../std_data/bug887051.txt' INTO TABLE t1 IGNORE 1 LINES; +COMMIT; +-- source include/maria_verify_recovery.inc +select * from t1; +drop table t1; + # clean up everything let $mms_purpose=feeding_recovery; eval drop database mysqltest_for_$mms_purpose; diff --git a/storage/maria/ha_maria.cc b/storage/maria/ha_maria.cc index ead0a3eb5c5..99a1e2cc903 100644 --- a/storage/maria/ha_maria.cc +++ b/storage/maria/ha_maria.cc @@ -2431,8 +2431,16 @@ int ha_maria::extra_opt(enum ha_extra_function operation, ulong cache_size) int ha_maria::delete_all_rows() { THD *thd= table->in_use; - (void) translog_log_debug_info(file->trn, LOGREC_DEBUG_INFO_QUERY, - (uchar*) thd->query(), thd->query_length()); +#ifdef EXTRA_DEBUG + TRN *trn= file->trn; + if (trn && ! (trnman_get_flags(trn) & TRN_STATE_INFO_LOGGED)) + { + trnman_set_flags(trn, trnman_get_flags(trn) | TRN_STATE_INFO_LOGGED | + TRN_STATE_TABLES_CAN_CHANGE); + (void) translog_log_debug_info(trn, LOGREC_DEBUG_INFO_QUERY, + (uchar*) thd->query(), thd->query_length()); + } +#endif if (file->s->now_transactional && ((table->in_use->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) || table->in_use->locked_tables)) diff --git a/storage/maria/ma_delete.c b/storage/maria/ma_delete.c index a2e2d9b040c..149a4316dcf 100644 --- a/storage/maria/ma_delete.c +++ b/storage/maria/ma_delete.c @@ -1481,8 +1481,9 @@ my_bool _ma_log_delete(MARIA_PAGE *ma_page, const uchar *key_pos, MARIA_SHARE *share= info->s; my_off_t page= ma_page->pos / share->block_size; DBUG_ENTER("_ma_log_delete"); - DBUG_PRINT("enter", ("page: %lu changed_length: %u move_length: %d", - (ulong) page, changed_length, move_length)); + DBUG_PRINT("enter", ("page: %lu offset: %u changed_length: %u move_length: %u append_length: %u page_size: %u", + (ulong) page, offset, changed_length, move_length, + append_length, ma_page->size)); DBUG_ASSERT(share->now_transactional && move_length); DBUG_ASSERT(offset + changed_length <= ma_page->size); DBUG_ASSERT(ma_page->org_size - move_length + append_length == ma_page->size); diff --git a/storage/maria/ma_key_recover.c b/storage/maria/ma_key_recover.c index 48bb9cb13d0..c0d906117b6 100644 --- a/storage/maria/ma_key_recover.c +++ b/storage/maria/ma_key_recover.c @@ -945,7 +945,7 @@ uint _ma_apply_redo_index(MARIA_HA *info, const uchar *header_end= header + head_length; uint page_offset= 0, org_page_length; uint page_length, keypage_header, keynr; - uint max_page_size= share->max_index_block_size; + uint max_page_size= share->max_index_block_size, new_page_length= 0; int result; MARIA_PAGE page; DBUG_ENTER("_ma_apply_redo_index"); @@ -1106,6 +1106,8 @@ uint _ma_apply_redo_index(MARIA_HA *info, case KEY_OP_DEBUG_2: DBUG_PRINT("redo", ("org_page_length: %u new_page_length: %u", uint2korr(header), uint2korr(header+2))); + DBUG_ASSERT(uint2korr(header) == page_length); + new_page_length= uint2korr(header+2); header+= 4; break; case KEY_OP_MAX_PAGELENGTH: @@ -1171,6 +1173,7 @@ uint _ma_apply_redo_index(MARIA_HA *info, } } while (header < header_end); DBUG_ASSERT(header == header_end); + DBUG_ASSERT(new_page_length == 0 || new_page_length == page_length); /* Write modified page */ page.size= page_length; diff --git a/storage/maria/ma_recovery.c b/storage/maria/ma_recovery.c index 8702431d9a6..fff317a7e6e 100644 --- a/storage/maria/ma_recovery.c +++ b/storage/maria/ma_recovery.c @@ -3592,6 +3592,10 @@ my_bool _ma_reenable_logging_for_table(MARIA_HA *info, my_bool flush_pages) if (flush_pages) { + /* Ensure that recover is not executing any redo before this */ + if (!maria_in_recovery) + share->state.is_of_horizon= share->state.create_rename_lsn= + share->state.skip_redo_lsn= translog_get_horizon(); /* We are going to change callbacks; if a page is flushed at this moment this can cause race conditions, that's one reason to flush pages From 43c8a6ac19c48dad77aae7deb4eb0ef22a5b0ba7 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Tue, 13 Dec 2011 20:07:23 +0200 Subject: [PATCH 202/288] Fixed failure with query_cache.test for embedded server sql/set_var.cc: Moved query_cache_strip_comments from EMBEDDED_LIBRARY to HAVE_QUERY_CACHE --- sql/set_var.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sql/set_var.cc b/sql/set_var.cc index 926ae4696b8..01223eaaf57 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -650,6 +650,7 @@ static sys_var_thd_enum sys_query_cache_type(&vars, "query_cache_type", static sys_var_thd_bool sys_query_cache_wlock_invalidate(&vars, "query_cache_wlock_invalidate", &SV::query_cache_wlock_invalidate); +static sys_var_bool_ptr sys_query_cache_strip_comments(&vars, "query_cache_strip_comments", &opt_query_cache_strip_comments); #endif /* HAVE_QUERY_CACHE */ static sys_var_bool_ptr sys_secure_auth(&vars, "secure_auth", &opt_secure_auth); static sys_var_const_str_ptr sys_secure_file_priv(&vars, "secure_file_priv", @@ -942,8 +943,6 @@ static sys_var_const_str_ptr sys_log_basename(&vars, "log_basename", #ifndef EMBEDDED_LIBRARY static sys_var_const_str_ptr sys_repl_report_host(&vars, "report_host", &report_host); static sys_var_const_str_ptr sys_repl_report_user(&vars, "report_user", &report_user); -static sys_var_bool_ptr sys_query_cache_strip_comments(&vars, "query_cache_strip_comments", - &opt_query_cache_strip_comments); static sys_var_const_str_ptr sys_repl_report_password(&vars, "report_password", &report_password); static uchar *slave_get_report_port(THD *thd) From 988bd172b9ab285a4cc7a4abfdf00d5a096ff02e Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 13 Dec 2011 20:52:06 +0200 Subject: [PATCH 203/288] The variable query_cache_strip_comments allowed in embedded server. --- sql/set_var.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/set_var.cc b/sql/set_var.cc index 926ae4696b8..12ec76327f4 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -939,11 +939,11 @@ static sys_var_const_str sys_hostname(&vars, "hostname", glob_hostname); static sys_var_const_str_ptr sys_log_basename(&vars, "log_basename", &opt_log_basename); +static sys_var_bool_ptr sys_query_cache_strip_comments(&vars, "query_cache_strip_comments", + &opt_query_cache_strip_comments); #ifndef EMBEDDED_LIBRARY static sys_var_const_str_ptr sys_repl_report_host(&vars, "report_host", &report_host); static sys_var_const_str_ptr sys_repl_report_user(&vars, "report_user", &report_user); -static sys_var_bool_ptr sys_query_cache_strip_comments(&vars, "query_cache_strip_comments", - &opt_query_cache_strip_comments); static sys_var_const_str_ptr sys_repl_report_password(&vars, "report_password", &report_password); static uchar *slave_get_report_port(THD *thd) From 190aa085577fb6e08aa861138036e50d7fc25313 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Wed, 14 Dec 2011 02:15:15 +0400 Subject: [PATCH 204/288] BUG#902632: Crash or invalid read at st_join_table::cleanup, st_table::disable_keyread - Do a "more thorough" cleanup of SJ-Materialization join tab in JOIN_TAB::cleanup. The bug was due to the fact that JOIN_TAB::cleanup() may be called multiple times for the same tab if the join has grouping. --- mysql-test/r/subselect_mat.result | 16 ++++++++++++++++ mysql-test/r/subselect_sj_mat.result | 16 ++++++++++++++++ mysql-test/t/subselect_sj_mat.test | 17 +++++++++++++++++ sql/sql_select.cc | 6 ++++++ 4 files changed, 55 insertions(+) diff --git a/mysql-test/r/subselect_mat.result b/mysql-test/r/subselect_mat.result index 81c8b2e1e84..b770cb8afd5 100644 --- a/mysql-test/r/subselect_mat.result +++ b/mysql-test/r/subselect_mat.result @@ -1764,6 +1764,22 @@ SELECT MIN(a) FROM t1, t2 WHERE b IN (SELECT c FROM t3 GROUP BY c); MIN(a) 1 DROP TABLE t1,t2,t3; +# +# BUG#902632: Crash or invalid read at st_join_table::cleanup, st_table::disable_keyread +# +CREATE TABLE t1 ( a INT ); +INSERT INTO t1 VALUES (1), (2); +CREATE TABLE t2 ( b INT ); +INSERT INTO t2 VALUES (3), (4); +CREATE TABLE t3 ( c INT ); +INSERT INTO t3 VALUES (5), (6); +SELECT * FROM t1 WHERE EXISTS ( +SELECT DISTINCT b FROM t2 +WHERE b <= a +AND b IN ( SELECT c FROM t3 GROUP BY c ) +); +a +DROP TABLE t1,t2,t3; # This must be at the end: set optimizer_switch=@subselect_sj_mat_tmp; set @subselect_mat_test_optimizer_switch_value=null; diff --git a/mysql-test/r/subselect_sj_mat.result b/mysql-test/r/subselect_sj_mat.result index 4845616018c..50e2f047005 100644 --- a/mysql-test/r/subselect_sj_mat.result +++ b/mysql-test/r/subselect_sj_mat.result @@ -1800,5 +1800,21 @@ SELECT MIN(a) FROM t1, t2 WHERE b IN (SELECT c FROM t3 GROUP BY c); MIN(a) 1 DROP TABLE t1,t2,t3; +# +# BUG#902632: Crash or invalid read at st_join_table::cleanup, st_table::disable_keyread +# +CREATE TABLE t1 ( a INT ); +INSERT INTO t1 VALUES (1), (2); +CREATE TABLE t2 ( b INT ); +INSERT INTO t2 VALUES (3), (4); +CREATE TABLE t3 ( c INT ); +INSERT INTO t3 VALUES (5), (6); +SELECT * FROM t1 WHERE EXISTS ( +SELECT DISTINCT b FROM t2 +WHERE b <= a +AND b IN ( SELECT c FROM t3 GROUP BY c ) +); +a +DROP TABLE t1,t2,t3; # This must be at the end: set optimizer_switch=@subselect_sj_mat_tmp; diff --git a/mysql-test/t/subselect_sj_mat.test b/mysql-test/t/subselect_sj_mat.test index a8dbeded84a..9614a41767e 100644 --- a/mysql-test/t/subselect_sj_mat.test +++ b/mysql-test/t/subselect_sj_mat.test @@ -1465,6 +1465,23 @@ SELECT MIN(a) FROM t1, t2 WHERE b IN (SELECT c FROM t3 GROUP BY c); DROP TABLE t1,t2,t3; +--echo # +--echo # BUG#902632: Crash or invalid read at st_join_table::cleanup, st_table::disable_keyread +--echo # +CREATE TABLE t1 ( a INT ); +INSERT INTO t1 VALUES (1), (2); +CREATE TABLE t2 ( b INT ); +INSERT INTO t2 VALUES (3), (4); +CREATE TABLE t3 ( c INT ); +INSERT INTO t3 VALUES (5), (6); + +SELECT * FROM t1 WHERE EXISTS ( + SELECT DISTINCT b FROM t2 + WHERE b <= a + AND b IN ( SELECT c FROM t3 GROUP BY c ) + ); +DROP TABLE t1,t2,t3; + --echo # This must be at the end: set optimizer_switch=@subselect_sj_mat_tmp; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 87d3ee77f78..c95bd6cbcda 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -9738,6 +9738,12 @@ void JOIN_TAB::cleanup() { end_read_record(&read_record); table->pos_in_table_list->jtbm_subselect->cleanup(); + /* + The above call freed the materializedd temptable. Set it to NULL so + that we don't attempt to touch it if JOIN_TAB::cleanup() is invoked + multiple times (it may be) + */ + table=NULL; } DBUG_VOID_RETURN; } From d274e32c8c0363073e924446f02ff18f7c3c4821 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Tue, 13 Dec 2011 14:20:47 -0800 Subject: [PATCH 205/288] Fixed LP bug #902356. A memory overwrite in the function test_if_skip_sort_order() could cause a crash for some queries with subqueries. --- mysql-test/r/subselect2.result | 33 +++++++++++++++++++++++++++++++++ mysql-test/t/subselect2.test | 31 +++++++++++++++++++++++++++++++ sql/sql_select.cc | 7 ++++--- 3 files changed, 68 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/subselect2.result b/mysql-test/r/subselect2.result index a7b6e40d9c9..52297a65e39 100644 --- a/mysql-test/r/subselect2.result +++ b/mysql-test/r/subselect2.result @@ -146,4 +146,37 @@ and t2.a='1' AND t1.a=t3.b) > 0; a 2 DROP TABLE t1,t2,t3; +# +# Bug #902356: DISTINCT in materialized subquery +# +CREATE TABLE t1 (pk int PRIMARY KEY, a int, KEY(a)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (0, 4), (8, 6); +CREATE TABLE t2 (pk int PRIMARY KEY, a int, KEY(a)) ENGINE=InnoDB; +INSERT INTO t2 VALUES (0, 4), (8, 6); +CREATE TABLE t3 (b INT, KEY(b)); +INSERT INTO t3 VALUES (7), (0), (4), (2); +CREATE VIEW v1 AS SELECT * FROM t1; +SET @tmp_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='materialization=on,in_to_exists=on'; +EXPLAIN +SELECT * FROM t2,t3 WHERE (2,9) IN (SELECT DISTINCT a,pk FROM t1) OR a = b; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2 index a a 5 NULL 2 Using index +1 PRIMARY t3 index b b 5 NULL 4 Using where; Using index; Using join buffer (flat, BNL join) +2 MATERIALIZED t1 index PRIMARY,a a 5 NULL 2 Using index +SELECT * FROM t2,t3 WHERE (2,9) IN (SELECT DISTINCT a,pk FROM t1) OR a = b; +pk a b +0 4 4 +EXPLAIN +SELECT * FROM t2,t3 WHERE (2,9) IN (SELECT DISTINCT a,pk FROM v1) OR a = b; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2 index a a 5 NULL 2 Using index +1 PRIMARY t3 index b b 5 NULL 4 Using where; Using index; Using join buffer (flat, BNL join) +2 MATERIALIZED t1 index PRIMARY,a a 5 NULL 2 Using index +SELECT * FROM t2,t3 WHERE (2,9) IN (SELECT DISTINCT a,pk FROM v1) OR a = b; +pk a b +0 4 4 +SET optimizer_switch=@tmp_optimizer_switch; +DROP VIEW v1; +DROP TABLE t1,t2,t3; set optimizer_switch=@subselect2_test_tmp; diff --git a/mysql-test/t/subselect2.test b/mysql-test/t/subselect2.test index 5f819ed39ba..8d2939bdb53 100644 --- a/mysql-test/t/subselect2.test +++ b/mysql-test/t/subselect2.test @@ -172,5 +172,36 @@ SELECT t1.* FROM t1 WHERE (SELECT COUNT(*) FROM t3,t2 WHERE t3.c=t2.a DROP TABLE t1,t2,t3; +--echo # +--echo # Bug #902356: DISTINCT in materialized subquery +--echo # + +CREATE TABLE t1 (pk int PRIMARY KEY, a int, KEY(a)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (0, 4), (8, 6); + +CREATE TABLE t2 (pk int PRIMARY KEY, a int, KEY(a)) ENGINE=InnoDB; +INSERT INTO t2 VALUES (0, 4), (8, 6); + +CREATE TABLE t3 (b INT, KEY(b)); +INSERT INTO t3 VALUES (7), (0), (4), (2); + +CREATE VIEW v1 AS SELECT * FROM t1; + +SET @tmp_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='materialization=on,in_to_exists=on'; + +EXPLAIN +SELECT * FROM t2,t3 WHERE (2,9) IN (SELECT DISTINCT a,pk FROM t1) OR a = b; +SELECT * FROM t2,t3 WHERE (2,9) IN (SELECT DISTINCT a,pk FROM t1) OR a = b; + +EXPLAIN +SELECT * FROM t2,t3 WHERE (2,9) IN (SELECT DISTINCT a,pk FROM v1) OR a = b; +SELECT * FROM t2,t3 WHERE (2,9) IN (SELECT DISTINCT a,pk FROM v1) OR a = b; + +SET optimizer_switch=@tmp_optimizer_switch; + +DROP VIEW v1; +DROP TABLE t1,t2,t3; + set optimizer_switch=@subselect2_test_tmp; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 87d3ee77f78..ab3f80ae290 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -17530,8 +17530,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; @@ -17827,7 +17827,8 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit_arg, 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 05e0127478c39437be53668f0db1d674071e2485 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Wed, 14 Dec 2011 04:39:29 +0400 Subject: [PATCH 206/288] BUG#901506: Crash in TABLE_LIST::print on EXPLAIN EXTENDED - Let JTBM optimization code handle the case where the subquery is degenerate and doesn't have a join query plan. Regular materialization would fall back to IN->EXISTS for such cases. Semi-Join materialization does not have such option, instead we introduce and use "constant JTBM join tabs". --- mysql-test/r/subselect_mat.result | 14 ++ mysql-test/r/subselect_sj_mat.result | 15 ++ mysql-test/t/subselect_sj_mat.test | 12 ++ sql/item_subselect.h | 44 ++++- sql/opt_subselect.cc | 240 ++++++++++++++++++++++++++- sql/opt_subselect.h | 2 + sql/sql_select.cc | 140 +++------------- 7 files changed, 343 insertions(+), 124 deletions(-) diff --git a/mysql-test/r/subselect_mat.result b/mysql-test/r/subselect_mat.result index 81c8b2e1e84..fa8ce49941c 100644 --- a/mysql-test/r/subselect_mat.result +++ b/mysql-test/r/subselect_mat.result @@ -1764,6 +1764,20 @@ SELECT MIN(a) FROM t1, t2 WHERE b IN (SELECT c FROM t3 GROUP BY c); MIN(a) 1 DROP TABLE t1,t2,t3; +# +# BUG#901506: Crash in TABLE_LIST::print on EXPLAIN EXTENDED +# +CREATE TABLE t1 ( a INT, KEY(a) ); +INSERT INTO t1 VALUES (8); +EXPLAIN EXTENDED +SELECT * FROM t1 +WHERE a IN ( SELECT MIN(a) FROM t1 ); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 system NULL NULL NULL NULL 1 100.00 +2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +Warnings: +Note 1003 select 8 AS `a` from `test`.`t1` where <8>((8,(select min(`test`.`t1`.`a`) from `test`.`t1` having ((8) = (min(`test`.`t1`.`a`)))))) +DROP TABLE t1; # This must be at the end: set optimizer_switch=@subselect_sj_mat_tmp; set @subselect_mat_test_optimizer_switch_value=null; diff --git a/mysql-test/r/subselect_sj_mat.result b/mysql-test/r/subselect_sj_mat.result index 4845616018c..7bbf5aaf66d 100644 --- a/mysql-test/r/subselect_sj_mat.result +++ b/mysql-test/r/subselect_sj_mat.result @@ -1800,5 +1800,20 @@ SELECT MIN(a) FROM t1, t2 WHERE b IN (SELECT c FROM t3 GROUP BY c); MIN(a) 1 DROP TABLE t1,t2,t3; +# +# BUG#901506: Crash in TABLE_LIST::print on EXPLAIN EXTENDED +# +CREATE TABLE t1 ( a INT, KEY(a) ); +INSERT INTO t1 VALUES (8); +EXPLAIN EXTENDED +SELECT * FROM t1 +WHERE a IN ( SELECT MIN(a) FROM t1 ); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 system a NULL NULL NULL 1 100.00 +1 PRIMARY system NULL NULL NULL NULL 1 100.00 +2 MATERIALIZED NULL NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +Warnings: +Note 1003 select 8 AS `a` from (select min(`test`.`t1`.`a`) from `test`.`t1`) join `test`.`t1` where 1 +DROP TABLE t1; # This must be at the end: set optimizer_switch=@subselect_sj_mat_tmp; diff --git a/mysql-test/t/subselect_sj_mat.test b/mysql-test/t/subselect_sj_mat.test index a8dbeded84a..12d04097a51 100644 --- a/mysql-test/t/subselect_sj_mat.test +++ b/mysql-test/t/subselect_sj_mat.test @@ -1465,6 +1465,18 @@ SELECT MIN(a) FROM t1, t2 WHERE b IN (SELECT c FROM t3 GROUP BY c); DROP TABLE t1,t2,t3; +--echo # +--echo # BUG#901506: Crash in TABLE_LIST::print on EXPLAIN EXTENDED +--echo # +CREATE TABLE t1 ( a INT, KEY(a) ); +INSERT INTO t1 VALUES (8); + +EXPLAIN EXTENDED + SELECT * FROM t1 + WHERE a IN ( SELECT MIN(a) FROM t1 ); + +DROP TABLE t1; + --echo # This must be at the end: set optimizer_switch=@subselect_sj_mat_tmp; diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 880b505a8d1..fad951dd80f 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -446,11 +446,44 @@ public: Same as above, but they also allow to scan the materialized table. */ bool sjm_scan_allowed; - double jtbm_read_time; - double jtbm_record_count; - bool is_jtbm_merged; - bool is_jtbm_const_tab; + /* + JoinTaB Materialization (JTBM) members + */ + + /* + TRUE <=> This subselect has been converted into non-mergeable semi-join + table. + */ + bool is_jtbm_merged; + + /* (Applicable if is_jtbm_merged==TRUE) Time required to run the materialized join */ + double jtbm_read_time; + + /* (Applicable if is_jtbm_merged==TRUE) Number of output rows in materialized join */ + double jtbm_record_count; + + /* + (Applicable if is_jtbm_merged==TRUE) TRUE <=> The materialized subselect is + a degenerate subselect which produces 0 or 1 rows, which we know at + optimization phase. + Examples: + 1. subquery has "Impossible WHERE": + + SELECT * FROM ot WHERE ot.column IN (SELECT it.col FROM it WHERE 2 > 3) + + 2. Subquery produces one row which opt_sum.cc is able to get with one lookup: + + SELECT * FROM ot WHERE ot.column IN (SELECT MAX(it.key_col) FROM it) + */ + bool is_jtbm_const_tab; + + /* + (Applicable if is_jtbm_const_tab==TRUE) Whether the subquery has produced + the row (or not) + */ + bool jtbm_const_row_found; + /* TRUE<=>this is a flattenable semi-join, false overwise. */ @@ -741,6 +774,9 @@ public: friend class subselect_hash_sj_engine; friend class Item_in_subselect; + friend bool setup_jtbm_semi_joins(JOIN *join, List *join_list, + Item **join_where); + }; diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index 46ecb5ff65a..794bbf3e5dc 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -4611,6 +4611,234 @@ enum_nested_loop_state join_tab_execution_startup(JOIN_TAB *tab) } +/* + Create a dummy temporary table, useful only for the sake of having a + TABLE* object with map,tablenr and maybe_null properties. + + This is used by non-mergeable semi-join materilization code to handle + degenerate cases where materialized subquery produced "Impossible WHERE" + and thus wasn't materialized. +*/ + +TABLE *create_dummy_tmp_table(THD *thd) +{ + DBUG_ENTER("create_dummy_tmp_table"); + TABLE *table; + TMP_TABLE_PARAM sjm_table_param; + sjm_table_param.init(); + sjm_table_param.field_count= 1; + List sjm_table_cols; + Item *column_item= new Item_int(1); + sjm_table_cols.push_back(column_item); + if (!(table= create_tmp_table(thd, &sjm_table_param, + sjm_table_cols, (ORDER*) 0, + TRUE /* distinct */, + 1, /*save_sum_fields*/ + thd->options | TMP_TABLE_ALL_COLUMNS, + HA_POS_ERROR /*rows_limit */, + (char*)"dummy", TRUE /* Do not open */))) + { + DBUG_RETURN(NULL); + } + DBUG_RETURN(table); +} + + +/* + A class that is used to catch one single tuple that is sent to the join + output, and save it in Item_cache element(s). + + It is very similar to select_singlerow_subselect but doesn't require a + Item_singlerow_subselect item. +*/ + +class select_value_catcher :public select_subselect +{ +public: + select_value_catcher(Item_subselect *item_arg) + :select_subselect(item_arg) + {} + int send_data(List &items); + int setup(List *items); + bool assigned; /* TRUE <=> we've caught a value */ + uint n_elements; /* How many elements we get */ + Item_cache **row; /* Array of cache elements */ +}; + + +int select_value_catcher::setup(List *items) +{ + assigned= FALSE; + n_elements= items->elements; + + if (!(row= (Item_cache**) sql_alloc(sizeof(Item_cache*)*n_elements))) + return TRUE; + + Item *sel_item; + List_iterator li(*items); + for (uint i= 0; (sel_item= li++); i++) + { + if (!(row[i]= Item_cache::get_cache(sel_item))) + return TRUE; + row[i]->setup(sel_item); + } + return FALSE; +} + + +int select_value_catcher::send_data(List &items) +{ + DBUG_ENTER("select_value_catcher::send_data"); + DBUG_ASSERT(!assigned); + DBUG_ASSERT(items.elements == n_elements); + + if (unit->offset_limit_cnt) + { // Using limit offset,count + unit->offset_limit_cnt--; + DBUG_RETURN(0); + } + + Item *val_item; + List_iterator_fast li(items); + for (uint i= 0; (val_item= li++); i++) + { + row[i]->store(val_item); + row[i]->cache_value(); + } + assigned= TRUE; + DBUG_RETURN(0); +} + + +/* + Setup JTBM join tabs for execution +*/ + +bool setup_jtbm_semi_joins(JOIN *join, List *join_list, + Item **join_where) +{ + TABLE_LIST *table; + NESTED_JOIN *nested_join; + List_iterator li(*join_list); + DBUG_ENTER("setup_jtbm_semi_joins"); + + while ((table= li++)) + { + Item_in_subselect *item; + + if ((item= table->jtbm_subselect)) + { + Item_in_subselect *subq_pred= item; + double rows; + double read_time; + + /* + Perform optimization of the subquery, so that we know estmated + - cost of materialization process + - how many records will be in the materialized temp.table + */ + if (subq_pred->optimize(&rows, &read_time)) + DBUG_RETURN(TRUE); + + subq_pred->jtbm_read_time= read_time; + subq_pred->jtbm_record_count=rows; + JOIN *subq_join= subq_pred->unit->first_select()->join; + + if (!subq_join->tables_list || !subq_join->table_count) + { + /* + A special case; subquery's join is degenerate, and it either produces + 0 or 1 record. Examples of both cases: + + select * from ot where col in (select ... from it where 2>3) + select * from ot where col in (select min(it.key) from it) + + in this case, the subquery predicate has not been setup for + materialization. In particular, there is no materialized temp.table. + We'll now need to + 1. Check whether 1 or 0 records are produced, setup this as a + constant join tab. + 2. Create a dummy temporary table, because all of the join + optimization code relies on TABLE object being present (here we + follow a bad tradition started by derived tables) + */ + DBUG_ASSERT(subq_pred->engine->engine_type() == + subselect_engine::SINGLE_SELECT_ENGINE); + subselect_single_select_engine *engine= + (subselect_single_select_engine*)subq_pred->engine; + select_value_catcher *new_sink; + if (!(new_sink= new select_value_catcher(subq_pred))) + DBUG_RETURN(TRUE); + if (new_sink->setup(&engine->select_lex->join->fields_list) || + engine->select_lex->join->change_result(new_sink) || + engine->exec()) + { + DBUG_RETURN(TRUE); + } + subq_pred->is_jtbm_const_tab= TRUE; + + if (new_sink->assigned) + { + subq_pred->jtbm_const_row_found= TRUE; + /* + Subselect produced one row, which is saved in new_sink->row. + Inject "left_expr[i] == row[i] equalities into parent's WHERE. + */ + Item *eq_cond; + for (uint i= 0; i < subq_pred->left_expr->cols(); i++) + { + eq_cond= new Item_func_eq(subq_pred->left_expr->element_index(i), + new_sink->row[i]); + if (!eq_cond || eq_cond->fix_fields(join->thd, &eq_cond)) + DBUG_RETURN(1); + + (*join_where)= and_items(*join_where, eq_cond); + } + } + else + { + /* Subselect produced no rows. Just set the flag, */ + subq_pred->jtbm_const_row_found= FALSE; + } + + /* Set up a dummy TABLE*, optimizer code needs JOIN_TABs to have TABLE */ + TABLE *dummy_table; + if (!(dummy_table= create_dummy_tmp_table(join->thd))) + DBUG_RETURN(1); + table->table= dummy_table; + table->table->pos_in_table_list= table; + setup_table_map(table->table, table, table->jtbm_table_no); + } + else + { + DBUG_ASSERT(subq_pred->test_set_strategy(SUBS_MATERIALIZATION)); + subq_pred->is_jtbm_const_tab= FALSE; + subselect_hash_sj_engine *hash_sj_engine= + ((subselect_hash_sj_engine*)item->engine); + + table->table= hash_sj_engine->tmp_table; + table->table->pos_in_table_list= table; + + setup_table_map(table->table, table, table->jtbm_table_no); + + Item *sj_conds= hash_sj_engine->semi_join_conds; + + (*join_where)= and_items(*join_where, sj_conds); + if (!(*join_where)->fixed) + (*join_where)->fix_fields(join->thd, join_where); + } + } + + if ((nested_join= table->nested_join)) + { + if (setup_jtbm_semi_joins(join, &nested_join->join_list, join_where)) + DBUG_RETURN(TRUE); + } + } + DBUG_RETURN(FALSE); +} + + /** Choose an optimal strategy to execute an IN/ALL/ANY subquery predicate based on cost. @@ -4919,8 +5147,16 @@ bool JOIN::choose_tableless_subquery_plan() NULL. */ } - - if (subs_predicate->is_in_predicate()) + + /* + For IN subqueries, use IN->EXISTS transfomation, unless the subquery + has been converted to a JTBM semi-join. In that case, just leave + everything as-is, setup_jtbm_semi_joins() has special handling for cases + like this. + */ + if (subs_predicate->is_in_predicate() && + !(subs_predicate->substype() == Item_subselect::IN_SUBS && + ((Item_in_subselect*)subs_predicate)->is_jtbm_merged)) { Item_in_subselect *in_subs; in_subs= (Item_in_subselect*) subs_predicate; diff --git a/sql/opt_subselect.h b/sql/opt_subselect.h index 94c6153f0c1..07f1fc77a20 100644 --- a/sql/opt_subselect.h +++ b/sql/opt_subselect.h @@ -10,6 +10,8 @@ int check_and_do_in_subquery_rewrites(JOIN *join); bool convert_join_subqueries_to_semijoins(JOIN *join); int pull_out_semijoin_tables(JOIN *join); bool optimize_semijoin_nests(JOIN *join, table_map all_table_map); +bool setup_jtbm_semi_joins(JOIN *join, List *join_list, + Item **join_where); // used by Loose_scan_opt ulonglong get_bound_sj_equalities(TABLE_LIST *sj_nest, diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 7a86557901f..9c1f53ce0d9 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -798,117 +798,6 @@ err: } -/* - Create a dummy temporary table, useful only for the sake of having a - TABLE* object with map,tablenr and maybe_null properties. - - This is used by non-mergeable semi-join materilization code to handle - degenerate cases where materialized subquery produced "Impossible WHERE" - and thus wasn't materialized. -*/ - -TABLE *create_dummy_tmp_table(THD *thd) -{ - DBUG_ENTER("create_dummy_tmp_table"); - TABLE *table; - TMP_TABLE_PARAM sjm_table_param; - sjm_table_param.init(); - sjm_table_param.field_count= 1; - List sjm_table_cols; - Item *column_item= new Item_int(1); - sjm_table_cols.push_back(column_item); - if (!(table= create_tmp_table(thd, &sjm_table_param, - sjm_table_cols, (ORDER*) 0, - TRUE /* distinct */, - 1, /*save_sum_fields*/ - thd->options | TMP_TABLE_ALL_COLUMNS, - HA_POS_ERROR /*rows_limit */, - (char*)"dummy", TRUE /* Do not open */))) - { - DBUG_RETURN(NULL); - } - DBUG_RETURN(table); -} - - -void -setup_jtbm_semi_joins(JOIN *join, List *join_list, Item **join_where) -{ - TABLE_LIST *table; - NESTED_JOIN *nested_join; - List_iterator li(*join_list); - DBUG_ENTER("setup_jtbm_semi_joins"); - - - while ((table= li++)) - { - Item_in_subselect *item; - - if ((item= table->jtbm_subselect)) - { - Item_in_subselect *subq_pred= item; - double rows; - double read_time; - - subq_pred->optimize(&rows, &read_time); - subq_pred->jtbm_read_time= read_time; - subq_pred->jtbm_record_count=rows; - subq_pred->is_jtbm_merged= TRUE; - JOIN *subq_join= subq_pred->unit->first_select()->join; - if (!subq_join->tables_list || !subq_join->table_count) - { - /* - This is an empty and constant table. - - TODO: what if this is not empty but still constant? - - We'll need to check the equality but there's no materializatnion - table? - - A: create an IN-equality from - - left_expr - - right_expr. Q: how can right-expr exist in the context of - parent select? We don't have refs from outside to inside! - A: create/check in the context of the child select? - - for injection, check how in->exists is performed. - */ - subq_pred->is_jtbm_const_tab= TRUE; - - TABLE *dummy_table= create_dummy_tmp_table(join->thd); - table->table= dummy_table; - table->table->pos_in_table_list= table; - - setup_table_map(table->table, table, table->jtbm_table_no); - } - else - { - DBUG_ASSERT(subq_pred->test_set_strategy(SUBS_MATERIALIZATION)); - subq_pred->is_jtbm_const_tab= FALSE; - subselect_hash_sj_engine *hash_sj_engine= - ((subselect_hash_sj_engine*)item->engine); - - table->table= hash_sj_engine->tmp_table; - table->table->pos_in_table_list= table; - - setup_table_map(table->table, table, table->jtbm_table_no); - - Item *sj_conds= hash_sj_engine->semi_join_conds; - - (*join_where)= and_items(*join_where, sj_conds); - if (!(*join_where)->fixed) - (*join_where)->fix_fields(join->thd, join_where); - } - } - - if ((nested_join= table->nested_join)) - { - setup_jtbm_semi_joins(join, &nested_join->join_list, join_where); - } - } - DBUG_VOID_RETURN; -} - /** global select optimisation. @@ -1033,7 +922,8 @@ JOIN::optimize() thd->restore_active_arena(arena, &backup); } - setup_jtbm_semi_joins(this, join_list, &conds); + if (setup_jtbm_semi_joins(this, join_list, &conds)) + DBUG_RETURN(1); conds= optimize_cond(this, conds, join_list, &cond_value, &cond_equal); @@ -15656,7 +15546,12 @@ join_read_const_table(JOIN_TAB *tab, POSITION *pos) tab->table->pos_in_table_list->jtbm_subselect->is_jtbm_const_tab) { /* Row will not be found */ - DBUG_RETURN(-1); + int res; + if (tab->table->pos_in_table_list->jtbm_subselect->jtbm_const_row_found) + res= 0; + else + res= -1; + DBUG_RETURN(res); } else if (tab->type == JT_SYSTEM) { @@ -21452,11 +21347,20 @@ void TABLE_LIST::print(THD *thd, table_map eliminated_tables, String *str, } else if (jtbm_subselect) { - str->append(STRING_WITH_LEN(" (")); - subselect_hash_sj_engine *hash_engine; - hash_engine= (subselect_hash_sj_engine*)jtbm_subselect->engine; - hash_engine->materialize_engine->print(str, query_type); - str->append(')'); + if (jtbm_subselect->is_jtbm_const_tab) + { + str->append(STRING_WITH_LEN(" (")); + jtbm_subselect->engine->print(str, query_type); + str->append(')'); + } + else + { + str->append(STRING_WITH_LEN(" (")); + subselect_hash_sj_engine *hash_engine; + hash_engine= (subselect_hash_sj_engine*)jtbm_subselect->engine; + hash_engine->materialize_engine->print(str, query_type); + str->append(')'); + } } else { From 2b05ef11fcc5d0781553944ea85f28b2857f7bbc Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Wed, 14 Dec 2011 12:49:32 +0200 Subject: [PATCH 207/288] Addendum to the fix for bug #11754011: fixed a testcase result to include the new --slow-start-timeout option's help output --- mysql-test/r/mysqld--help-win.result | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mysql-test/r/mysqld--help-win.result b/mysql-test/r/mysqld--help-win.result index 38235e1a093..2ef52355f90 100644 --- a/mysql-test/r/mysqld--help-win.result +++ b/mysql-test/r/mysqld--help-win.result @@ -665,6 +665,10 @@ The following options may be given as the first argument: Log slow queries to given log file. Defaults logging to hostname-slow.log. Must be enabled to activate other slow log options + --slow-start-timeout=# + Maximum number of milliseconds that the service control + manager should wait before trying to kill the windows + service during startup(Default: 15000). --socket=name Socket file to use for connection --sort-buffer-size=# Each thread that needs to do a sort allocates a buffer of @@ -938,6 +942,7 @@ slave-transaction-retries 10 slave-type-conversions slow-launch-time 2 slow-query-log FALSE +slow-start-timeout 15000 sort-buffer-size 2097152 sporadic-binlog-dump-fail FALSE sql-mode From ed3e19aca84d40ee191da8e817994df2e6831abc Mon Sep 17 00:00:00 2001 From: Andrei Elkin Date: Wed, 14 Dec 2011 15:33:43 +0200 Subject: [PATCH 208/288] Bug#13437900 - VALGRIND REPORTS A LEAK FOR REPL_IGNORE_SERVER_IDS There was memory leak when running some tests on PB2. The reason of the failure is an early return from change_master() that was supposed to deallocate a dyn-array. Actually the same bug58915 was fixed in trunk with relocating the dyn-array destruction into THD::cleanup_after_query() which can't be bypassed. The current patch backports magne.mahre@oracle.com-20110203101306-q8auashb3d7icxho and adds two optimizations: were done: the static buffer for the dyn-array to base on, and the array initialization is called precisely when it's necessary rather than per each CHANGE-MASTER as before. mysql-test/suite/rpl/t/rpl_empty_master_host.test: the test is binlog-format insensitive so it will be run with MIXED mode only. mysql-test/suite/rpl/t/rpl_server_id_ignore.test: the test is binlog-format insensitive so it will be run with MIXED mode only. sql/sql_class.cc: relocating the dyn-array destruction into THD::cleanup_after_query(). sql/sql_lex.cc: LEX.mi zero initialization is done in LEX(). sql/sql_lex.h: Optimization for repl_ignore_server_ids to base on a static buffer which size is chosen to fit to most common use cases. sql/sql_repl.cc: dyn-array destruction is relocated to THD::cleanup_after_query(). sql/sql_yacc.yy: Refining logics of Lex->mi.repl_ignore_server_ids initialization. The array is initialized once a corresponding option in CHANGE MASTER token sequence is found. --- mysql-test/suite/rpl/t/rpl_empty_master_host.test | 1 + mysql-test/suite/rpl/t/rpl_server_id_ignore.test | 1 + sql/sql_class.cc | 5 +++++ sql/sql_lex.cc | 1 + sql/sql_lex.h | 1 + sql/sql_repl.cc | 1 - sql/sql_yacc.yy | 15 ++++++++++----- 7 files changed, 19 insertions(+), 6 deletions(-) diff --git a/mysql-test/suite/rpl/t/rpl_empty_master_host.test b/mysql-test/suite/rpl/t/rpl_empty_master_host.test index df0c85ad7ec..66d30375a59 100644 --- a/mysql-test/suite/rpl/t/rpl_empty_master_host.test +++ b/mysql-test/suite/rpl/t/rpl_empty_master_host.test @@ -17,6 +17,7 @@ # working when expected. --source include/master-slave.inc +--source include/have_binlog_format_mixed.inc connection slave; STOP SLAVE; diff --git a/mysql-test/suite/rpl/t/rpl_server_id_ignore.test b/mysql-test/suite/rpl/t/rpl_server_id_ignore.test index 004f4daa19d..1e6d46c9d40 100644 --- a/mysql-test/suite/rpl/t/rpl_server_id_ignore.test +++ b/mysql-test/suite/rpl/t/rpl_server_id_ignore.test @@ -18,6 +18,7 @@ # executing events this time source include/master-slave.inc; +source include/have_binlog_format_mixed.inc; connection slave; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 9b5772d3d07..a644729961c 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1673,6 +1673,11 @@ void THD::cleanup_after_query() /* reset table map for multi-table update */ table_map_for_update= 0; m_binlog_invoker= FALSE; + /* reset replication info structure */ + if (lex && lex->mi.repl_ignore_server_ids.buffer) + { + delete_dynamic(&lex->mi.repl_ignore_server_ids); + } } diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 869a5916339..0cabab9fae7 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -2351,6 +2351,7 @@ LEX::LEX() plugins_static_buffer, INITIAL_LEX_PLUGIN_LIST_SIZE, INITIAL_LEX_PLUGIN_LIST_SIZE); + memset(&mi, 0, sizeof(LEX_MASTER_INFO)); reset_query_tables_list(TRUE); } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 542e8b42ae2..440828a2669 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -292,6 +292,7 @@ typedef struct st_lex_master_info char *relay_log_name; ulong relay_log_pos; DYNAMIC_ARRAY repl_ignore_server_ids; + typeof(::server_id) server_ids_buffer[2]; } LEX_MASTER_INFO; typedef struct st_lex_reset_slave diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 00c85d8eb43..5300a327029 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -1689,7 +1689,6 @@ err: thd_proc_info(thd, 0); if (ret == FALSE) my_ok(thd); - delete_dynamic(&lex_mi->repl_ignore_server_ids); //freeing of parser-time alloc DBUG_RETURN(ret); } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 87c3ae5b129..8f3e6373666 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1863,12 +1863,9 @@ change: LEX *lex = Lex; lex->sql_command = SQLCOM_CHANGE_MASTER; bzero((char*) &lex->mi, sizeof(lex->mi)); - /* - resetting flags that can left from the previous CHANGE MASTER - */ lex->mi.repl_ignore_server_ids_opt= LEX_MASTER_INFO::LEX_MI_UNCHANGED; - my_init_dynamic_array(&Lex->mi.repl_ignore_server_ids, - sizeof(::server_id), 16, 16); + + DBUG_ASSERT(Lex->mi.repl_ignore_server_ids.elements == 0); } master_defs {} @@ -1979,6 +1976,14 @@ ignore_server_id_list: ignore_server_id: ulong_num { + if (Lex->mi.repl_ignore_server_ids.elements == 0) + { + my_init_dynamic_array2(&Lex->mi.repl_ignore_server_ids, + sizeof(::server_id), + Lex->mi.server_ids_buffer, + array_elements(Lex->mi.server_ids_buffer), + 16); + } insert_dynamic(&Lex->mi.repl_ignore_server_ids, (uchar*) &($1)); } From be7fc143185070d15f036920644679bb3a36b8bf Mon Sep 17 00:00:00 2001 From: Andrei Elkin Date: Wed, 14 Dec 2011 17:02:55 +0200 Subject: [PATCH 209/288] bug#13437900 post-push changes to please solaris compiler. --- sql/sql_lex.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 440828a2669..8aaead811a0 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -292,7 +292,7 @@ typedef struct st_lex_master_info char *relay_log_name; ulong relay_log_pos; DYNAMIC_ARRAY repl_ignore_server_ids; - typeof(::server_id) server_ids_buffer[2]; + ulong server_ids_buffer[2]; } LEX_MASTER_INFO; typedef struct st_lex_reset_slave From 464278246a2c7d6b3b6fe90439f85f87d2f45fe5 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Thu, 15 Dec 2011 02:49:19 +0400 Subject: [PATCH 210/288] Make MyISAM's version of create_internal_tmp_table set QPLAN_TMP_DISK, like Aria version does (otherwise slow query log would show Tmp_table_on_disk=No when it should have said Yes) --- sql/sql_select.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 313159d33d1..7a8f4e854ec 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -14473,6 +14473,7 @@ bool create_internal_tmp_table(TABLE *table, KEY *keyinfo, goto err; } status_var_increment(table->in_use->status_var.created_tmp_disk_tables); + table->in_use->query_plan_flags|= QPLAN_TMP_DISK; share->db_record_offset= 1; table->created= TRUE; DBUG_RETURN(0); From f5dac20f38fcf581b0616562cd2da21fb8c50218 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Thu, 15 Dec 2011 00:21:15 -0800 Subject: [PATCH 211/288] Made the optimizer switch flags 'outer_join_with_cache', 'semijoin_with_cache' set to 'on' by default. --- mysql-test/include/common-tests.inc | 6 ++++ mysql-test/r/compress.result | 3 ++ mysql-test/r/derived_view.result | 9 +++++ mysql-test/r/error_simulation.result | 3 ++ mysql-test/r/explain.result | 3 ++ mysql-test/r/func_group.result | 3 ++ mysql-test/r/func_op.result | 3 ++ mysql-test/r/group_by.result | 9 +++++ mysql-test/r/group_min_max.result | 6 ++++ mysql-test/r/join.result | 3 ++ mysql-test/r/join_nested.result | 3 ++ mysql-test/r/join_nested_jcl6.result | 5 +++ mysql-test/r/join_outer.result | 3 ++ mysql-test/r/join_outer_jcl6.result | 5 +++ mysql-test/r/myisam_icp.result | 3 ++ mysql-test/r/optimizer_switch.result | 36 +++++++++---------- mysql-test/r/order_by.result | 3 ++ mysql-test/r/pool_of_threads.result | 6 ++++ mysql-test/r/ps.result | 3 ++ mysql-test/r/select.result | 3 ++ mysql-test/r/select_jcl6.result | 5 +++ mysql-test/r/select_pkeycache.result | 3 ++ mysql-test/r/ssl.result | 3 ++ mysql-test/r/ssl_compress.result | 3 ++ mysql-test/r/subselect.result | 3 ++ mysql-test/r/subselect4.result | 4 +++ mysql-test/r/subselect_cache.result | 4 +++ mysql-test/r/subselect_no_mat.result | 3 ++ mysql-test/r/subselect_no_opts.result | 3 ++ mysql-test/r/subselect_no_scache.result | 3 ++ mysql-test/r/subselect_no_semijoin.result | 3 ++ mysql-test/r/subselect_sj.result | 2 ++ mysql-test/r/subselect_sj2.result | 2 ++ mysql-test/r/subselect_sj2_jcl6.result | 4 +++ mysql-test/r/subselect_sj2_mat.result | 2 ++ mysql-test/r/subselect_sj_jcl6.result | 4 +++ mysql-test/r/subselect_sj_nonmerged.result | 3 ++ mysql-test/r/table_elim.result | 3 ++ mysql-test/r/type_datetime.result | 3 ++ mysql-test/r/union.result | 3 ++ mysql-test/r/view.result | 3 ++ mysql-test/suite/pbxt/r/func_group.result | 3 ++ mysql-test/suite/pbxt/r/func_op.result | 3 ++ mysql-test/suite/pbxt/r/group_by.result | 3 ++ mysql-test/suite/pbxt/r/join.result | 3 ++ mysql-test/suite/pbxt/r/join_nested.result | 3 ++ mysql-test/suite/pbxt/r/join_outer.result | 3 ++ mysql-test/suite/pbxt/r/select.result | 3 ++ mysql-test/suite/pbxt/r/subselect.result | 4 +++ mysql-test/suite/pbxt/r/union.result | 3 ++ mysql-test/suite/pbxt/t/func_group.test | 3 ++ mysql-test/suite/pbxt/t/func_op.test | 3 ++ mysql-test/suite/pbxt/t/group_by.test | 3 ++ mysql-test/suite/pbxt/t/join.test | 5 +++ mysql-test/suite/pbxt/t/join_nested.test | 6 ++++ mysql-test/suite/pbxt/t/join_outer.test | 5 +++ mysql-test/suite/pbxt/t/select.test | 6 ++++ mysql-test/suite/pbxt/t/subselect.test | 5 +++ mysql-test/suite/pbxt/t/union.test | 3 ++ mysql-test/suite/vcol/inc/vcol_view.inc | 6 ++++ .../suite/vcol/r/vcol_view_innodb.result | 3 ++ .../suite/vcol/r/vcol_view_myisam.result | 3 ++ mysql-test/t/derived_view.test | 13 +++++++ mysql-test/t/error_simulation.test | 5 +++ mysql-test/t/explain.test | 3 ++ mysql-test/t/func_group.test | 3 ++ mysql-test/t/func_op.test | 3 ++ mysql-test/t/group_by.test | 9 +++++ mysql-test/t/group_min_max.test | 6 ++++ mysql-test/t/join.test | 4 +++ mysql-test/t/join_nested.test | 5 +++ mysql-test/t/join_nested_jcl6.test | 3 ++ mysql-test/t/join_outer.test | 6 ++++ mysql-test/t/join_outer_jcl6.test | 3 ++ mysql-test/t/myisam_icp.test | 5 +++ mysql-test/t/order_by.test | 5 +++ mysql-test/t/pool_of_threads.test | 4 ++- mysql-test/t/ps.test | 3 ++ mysql-test/t/select.test | 5 +++ mysql-test/t/select_jcl6.test | 3 ++ mysql-test/t/subselect.test | 5 +++ mysql-test/t/subselect4.test | 8 +++++ mysql-test/t/subselect_cache.test | 5 +++ mysql-test/t/subselect_sj.test | 3 ++ mysql-test/t/subselect_sj2.test | 4 ++- mysql-test/t/subselect_sj2_jcl6.test | 3 ++ mysql-test/t/subselect_sj_jcl6.test | 3 ++ mysql-test/t/subselect_sj_nonmerged.test | 6 ++++ mysql-test/t/table_elim.test | 4 +++ mysql-test/t/type_datetime.test | 5 +++ mysql-test/t/union.test | 3 ++ mysql-test/t/view.test | 5 +++ sql/mysql_priv.h | 4 ++- sql/mysqld.cc | 4 +-- 94 files changed, 390 insertions(+), 23 deletions(-) diff --git a/mysql-test/include/common-tests.inc b/mysql-test/include/common-tests.inc index 2273d7d688d..4b61826c347 100644 --- a/mysql-test/include/common-tests.inc +++ b/mysql-test/include/common-tests.inc @@ -1536,6 +1536,10 @@ select t2.fld1,t22.fld1 from t2,t2 t22 where t2.fld1 >= 250501 and t2.fld1 <= 25 # # Test of left join. # + +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; + insert into t2 (fld1, companynr) values (999999,99); select t2.companynr,companyname from t2 left join t4 using (companynr) where t4.companynr is null; @@ -1568,6 +1572,8 @@ explain select companynr,companyname from t4 left join t2 using (companynr) wher explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0 or companynr < 0 or companynr > 0; explain select companynr,companyname from t4 left join t2 using (companynr) where ifnull(companynr,1)>0; +SET optimizer_switch=@save_optimizer_switch; + # # Joins with forms. # diff --git a/mysql-test/r/compress.result b/mysql-test/r/compress.result index 4c1c49bf3e0..3a3586fdb32 100644 --- a/mysql-test/r/compress.result +++ b/mysql-test/r/compress.result @@ -1353,6 +1353,8 @@ fld1 fld1 250503 250505 250504 250505 250505 250505 +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; insert into t2 (fld1, companynr) values (999999,99); select t2.companynr,companyname from t2 left join t4 using (companynr) where t4.companynr is null; companynr companyname @@ -1428,6 +1430,7 @@ explain select companynr,companyname from t4 left join t2 using (companynr) wher id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where 1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where +SET optimizer_switch=@save_optimizer_switch; select distinct t2.companynr,t4.companynr from t2,t4 where t2.companynr=t4.companynr+1; companynr companynr 37 36 diff --git a/mysql-test/r/derived_view.result b/mysql-test/r/derived_view.result index 040b3b266d9..5281dd4bae4 100644 --- a/mysql-test/r/derived_view.result +++ b/mysql-test/r/derived_view.result @@ -1472,6 +1472,8 @@ INSERT INTO t1 VALUES (1,NULL,NULL), (5,'r','r'), (7,'y','y'); CREATE TABLE t2 (a int NOT NULL , b int, c varchar(1)); INSERT INTO t2 VALUES (4,3,'r'); CREATE ALGORITHM=TEMPTABLE VIEW v1 AS SELECT * FROM t1; +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='semijoin_with_cache=off'; SET SESSION optimizer_switch='derived_with_keys=off'; EXPLAIN SELECT * FROM t3 @@ -1502,6 +1504,7 @@ WHERE t3.b IN (SELECT v1.b FROM v1, t2 WHERE t2.c = v1.c AND t2.c = v1.b AND v1.b = t3.c); a b c 20 r r +SET optimizer_switch=@save_optimizer_switch; DROP VIEW v1; DROP TABLE t1,t2,t3; # @@ -1639,6 +1642,8 @@ INSERT INTO t1 VALUES ('c'), ('a'); CREATE TABLE t2 (a int, b int, c varchar(1)); INSERT INTO t2 VALUES (29,8,'c'), (39,7,'b'); CREATE TABLE t3 (b int); +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; EXPLAIN EXTENDED SELECT t.b, t.c, t1.a FROM t1, (SELECT t2.b, t2.c FROM t3 RIGHT JOIN t2 ON t2.a = t3.b) AS t @@ -1700,6 +1705,7 @@ FROM t1, (SELECT t2.b, t2.c FROM t3 RIGHT JOIN t2 ON t2.a = t3.b) AS t WHERE t.b <> 0 AND t.c = t1.a; b c a 8 c c +SET optimizer_switch=@save_optimizer_switch; DROP TABLE t1,t2,t3; # # Bug #880724: materialized const view as inner table of outer join @@ -1709,6 +1715,8 @@ INSERT INTO t1 VALUES (9,NULL), (6,'r'), (7,'c'); CREATE TABLE t2 (a int); INSERT INTO t2 VALUES (6); CREATE ALGORITHM=TEMPTABLE VIEW v2 AS SELECT * FROM t2; +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; SET SESSION optimizer_switch = 'derived_with_keys=on'; SET SESSION join_cache_level = 4; EXPLAIN @@ -1739,6 +1747,7 @@ a b 5 r 9 y SET SESSION join_cache_level = default; +SET optimizer_switch=@save_optimizer_switch; DROP VIEW v2; DROP TABLE t1,t2,t3; # diff --git a/mysql-test/r/error_simulation.result b/mysql-test/r/error_simulation.result index f76d9a8c547..6d9ec36bb1d 100644 --- a/mysql-test/r/error_simulation.result +++ b/mysql-test/r/error_simulation.result @@ -62,6 +62,8 @@ INSERT INTO t2 VALUES (1, 1, 'data'); # re-scanned for every record in the outer table. if we used inner join, # we would need to have thousands of records and/or more columns in both # tables so that the join buffer is filled and re-scans are triggered). +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; SET SESSION debug = '+d,only_one_Unique_may_be_created'; EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON ( t2.a < 10 OR t2.b < 10 ); @@ -81,6 +83,7 @@ a a b filler 8 1 1 data 9 1 1 data SET SESSION debug = DEFAULT; +SET optimizer_switch=@save_optimizer_switch; DROP TABLE t1, t2; # # Bug#11747970 34660: CRASH WHEN FEDERATED TABLE LOSES CONNECTION DURING INSERT ... SELECT diff --git a/mysql-test/r/explain.result b/mysql-test/r/explain.result index 2493b04488f..f3d2a567227 100644 --- a/mysql-test/r/explain.result +++ b/mysql-test/r/explain.result @@ -196,6 +196,8 @@ create table t2 (dt datetime not null); insert into t1 values ('2001-01-01 1:1:1', '1:1:1'), ('2001-01-01 1:1:1', '1:1:1'); insert into t2 values ('2001-01-01 1:1:1'), ('2001-01-01 1:1:1'); +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='semijoin_with_cache=off'; flush tables; EXPLAIN SELECT OUTR.dt FROM t1 AS OUTR WHERE OUTR.dt IN (SELECT INNR.dt FROM t2 AS INNR WHERE OUTR.dt IS NULL ); id select_type table type possible_keys key key_len ref rows Extra @@ -214,6 +216,7 @@ SELECT OUTR.dt FROM t1 AS OUTR WHERE OUTR.dt IN ( SELECT INNR.dt FROM t2 AS INNR dt 2001-01-01 01:01:01 2001-01-01 01:01:01 +SET optimizer_switch=@save_optimizer_switch; drop tables t1, t2; # # Bug#47669: Query showed by EXPLAIN EXTENDED gives different result from original query diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result index 5b193afafb1..d5ea7311cc4 100644 --- a/mysql-test/r/func_group.result +++ b/mysql-test/r/func_group.result @@ -215,6 +215,8 @@ a1 a2 a1 a2 10 bbb BBB 20 20 zzz AAA 10 20 zzz BBB 20 +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; select max(t1.a1), max(t2.a1) from t1, t2 where t2.a2=9; max(t1.a1) max(t2.a1) NULL NULL @@ -245,6 +247,7 @@ NULL select max(t1.a2),max(t2.a1) from t1 left outer join t2 on t1.a1=10; max(t1.a2) max(t2.a1) zzz BBB +SET optimizer_switch=@save_optimizer_switch; drop table t1,t2; CREATE TABLE t1 (a int, b int); select count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1; diff --git a/mysql-test/r/func_op.result b/mysql-test/r/func_op.result index 636163e6b29..ce755e86b4c 100644 --- a/mysql-test/r/func_op.result +++ b/mysql-test/r/func_op.result @@ -40,9 +40,12 @@ create table t1(a int); create table t2(a int, b int); insert into t1 values (1), (2), (3); insert into t2 values (1, 7), (3, 7); +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; select t1.a, t2.a, t2.b, bit_count(t2.b) from t1 left join t2 on t1.a=t2.a; a a b bit_count(t2.b) 1 1 7 3 2 NULL NULL NULL 3 3 7 3 +SET optimizer_switch=@save_optimizer_switch; drop table t1, t2; diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result index 7073a6cdfbc..6ac3257ca6c 100644 --- a/mysql-test/r/group_by.result +++ b/mysql-test/r/group_by.result @@ -450,6 +450,8 @@ drop table t1,t2; CREATE TABLE t1 (ID1 int, ID2 int, ID int NOT NULL AUTO_INCREMENT,PRIMARY KEY(ID )); insert into t1 values (1,244,NULL),(2,243,NULL),(134,223,NULL),(185,186,NULL); +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; select S.ID as xID, S.ID1 as xID1 from t1 as S left join t1 as yS on S.ID1 between yS.ID1 and yS.ID2; xID xID1 1 1 @@ -468,6 +470,7 @@ xID xID1 Level 2 2 ** 3 134 *** 4 185 **** +SET optimizer_switch=@save_optimizer_switch; drop table t1; CREATE TABLE t1 ( pid int(11) unsigned NOT NULL default '0', @@ -1539,12 +1542,15 @@ USE INDEX FOR JOIN (i2) USE INDEX FOR JOIN (i2,i2); id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 index NULL i2 9 NULL 144 Using index +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='semijoin_with_cache=off'; EXPLAIN SELECT 1 FROM t1 WHERE a IN (SELECT a FROM t1 USE INDEX (i2) IGNORE INDEX (i2)); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 index PRIMARY,i2 PRIMARY 4 NULL 144 Using index 1 PRIMARY eq_ref distinct_key distinct_key 4 func 1 2 MATERIALIZED t1 ALL NULL NULL NULL NULL 144 +SET optimizer_switch=@save_optimizer_switch; CREATE TABLE t2 (a INT, b INT, KEY(a)); INSERT INTO t2 VALUES (1, 1), (2, 2), (3,3), (4,4); EXPLAIN SELECT a, SUM(b) FROM t2 GROUP BY a LIMIT 2; @@ -1553,11 +1559,14 @@ id select_type table type possible_keys key key_len ref rows Extra EXPLAIN SELECT a, SUM(b) FROM t2 IGNORE INDEX (a) GROUP BY a LIMIT 2; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 4 Using temporary; Using filesort +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='semijoin_with_cache=off'; EXPLAIN SELECT 1 FROM t2 WHERE a IN (SELECT a FROM t1 USE INDEX (i2) IGNORE INDEX (i2)); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 index a a 5 NULL 4 Using index 1 PRIMARY t1 ALL NULL NULL NULL NULL 144 Using where; FirstMatch(t2) +SET optimizer_switch=@save_optimizer_switch; SHOW VARIABLES LIKE 'old'; Variable_name Value old OFF diff --git a/mysql-test/r/group_min_max.result b/mysql-test/r/group_min_max.result index 09e7cf1b5a5..4c863d25257 100644 --- a/mysql-test/r/group_min_max.result +++ b/mysql-test/r/group_min_max.result @@ -1424,6 +1424,8 @@ c a b h312 e312 h312 c b b p322 m322 p322 d a b h412 e412 h412 d b b p422 m422 p422 +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='semijoin_with_cache=off'; explain select a1,a2,b,c,min(c), max(c) from t1 where exists ( select * from t2 where t2.c in (select c from t3 where t3.c > t1.b) and @@ -1455,6 +1457,7 @@ d a a d411 a411 d411 d a b h412 e412 h412 d b a l421 i421 l421 d b b p422 m422 p422 +SET optimizer_switch=@save_optimizer_switch; explain select a1,a2,b,c,min(c), max(c) from t1 where exists ( select * from t2 where t1.c > 'a' and t2.c > 'b1' ) group by a1,a2,b; @@ -1481,6 +1484,8 @@ d a a a411 a411 d411 d a b e412 e412 h412 d b a i421 i421 l421 d b b m422 m422 p422 +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='semijoin_with_cache=off'; explain select a1,a2,b,c,min(c), max(c) from t1 where exists ( select * from t2 where t2.c in (select c from t3 where t3.c > t1.c) and @@ -1512,6 +1517,7 @@ d a a a411 a411 d411 d a b e412 e412 h412 d b a i421 i421 l421 d b b m422 m422 o422 +SET optimizer_switch=@save_optimizer_switch; explain select a1,a2,b,min(c),max(c) from t1 where (a1 >= 'c' or a2 < 'b') and (b > 'a') group by a1,a2,b; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 17 Using where; Using index for group-by diff --git a/mysql-test/r/join.result b/mysql-test/r/join.result index d7cd1491796..4496bcf36d2 100644 --- a/mysql-test/r/join.result +++ b/mysql-test/r/join.result @@ -1,5 +1,7 @@ drop table if exists t1,t2,t3; drop view if exists v1,v2; +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; CREATE TABLE t1 (S1 INT); CREATE TABLE t2 (S1 INT); INSERT INTO t1 VALUES (1); @@ -1347,3 +1349,4 @@ select t2.i from t1 left join t2 on t2.i = t1.i where t1.i = '1:1:1'; i 01:01:01 drop table t1,t2; +SET optimizer_switch=@save_optimizer_switch; diff --git a/mysql-test/r/join_nested.result b/mysql-test/r/join_nested.result index fb4ebb3c4b7..87f0478f284 100644 --- a/mysql-test/r/join_nested.result +++ b/mysql-test/r/join_nested.result @@ -1,4 +1,6 @@ DROP TABLE IF EXISTS t0,t1,t2,t3,t4,t5,t6,t7,t8,t9; +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch=ifnull(@optimizer_switch_for_join_nested_test,'outer_join_with_cache=off'); CREATE TABLE t0 (a int, b int, c int); CREATE TABLE t1 (a int, b int, c int); CREATE TABLE t2 (a int, b int, c int); @@ -1842,4 +1844,5 @@ id select_type table type possible_keys key key_len ref rows filtered Extra Warnings: Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t2`.`a` AS `a`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b`,`test`.`t4`.`b` AS `b` from `test`.`t1` left join (`test`.`t2` left join `test`.`t3` on(((`test`.`t2`.`a` = `test`.`t1`.`a`) and (`test`.`t3`.`b` = `test`.`t1`.`a`))) left join `test`.`t4` on((`test`.`t4`.`b` = `test`.`t3`.`a`))) on((`test`.`t2`.`a` = `test`.`t1`.`a`)) where isnull(`test`.`t3`.`a`) DROP TABLE t1,t2,t3,t4; +SET optimizer_switch=@save_optimizer_switch; End of 5.0 tests diff --git a/mysql-test/r/join_nested_jcl6.result b/mysql-test/r/join_nested_jcl6.result index ff5a31b599b..53107b1941f 100644 --- a/mysql-test/r/join_nested_jcl6.result +++ b/mysql-test/r/join_nested_jcl6.result @@ -7,7 +7,10 @@ set join_cache_level=6; show variables like 'join_cache_level'; Variable_name Value join_cache_level 6 +set @optimizer_switch_for_join_nested_test=@@optimizer_switch; DROP TABLE IF EXISTS t0,t1,t2,t3,t4,t5,t6,t7,t8,t9; +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch=ifnull(@optimizer_switch_for_join_nested_test,'outer_join_with_cache=off'); CREATE TABLE t0 (a int, b int, c int); CREATE TABLE t1 (a int, b int, c int); CREATE TABLE t2 (a int, b int, c int); @@ -1851,6 +1854,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra Warnings: Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t2`.`a` AS `a`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b`,`test`.`t4`.`b` AS `b` from `test`.`t1` left join (`test`.`t2` left join `test`.`t3` on(((`test`.`t2`.`a` = `test`.`t1`.`a`) and (`test`.`t3`.`b` = `test`.`t1`.`a`))) left join `test`.`t4` on(((`test`.`t4`.`b` = `test`.`t3`.`a`) and (`test`.`t3`.`a` is not null)))) on((`test`.`t2`.`a` = `test`.`t1`.`a`)) where isnull(`test`.`t3`.`a`) DROP TABLE t1,t2,t3,t4; +SET optimizer_switch=@save_optimizer_switch; End of 5.0 tests CREATE TABLE t5 (a int, b int, c int, PRIMARY KEY(a), KEY b_i (b)); CREATE TABLE t6 (a int, b int, c int, PRIMARY KEY(a), KEY b_i (b)); @@ -1962,3 +1966,4 @@ show variables like 'join_cache_level'; Variable_name Value join_cache_level 1 set @@optimizer_switch=@save_optimizer_switch_jcl6; +set @optimizer_switch_for_join_nested_test=NULL; diff --git a/mysql-test/r/join_outer.result b/mysql-test/r/join_outer.result index ae8ae88dc8d..02ad3a1a16a 100644 --- a/mysql-test/r/join_outer.result +++ b/mysql-test/r/join_outer.result @@ -1,4 +1,6 @@ drop table if exists t0,t1,t2,t3,t4,t5; +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch=ifnull(@optimizer_switch_for_join_outer_test,'outer_join_with_cache=off'); CREATE TABLE t1 ( grp int(11) default NULL, a bigint(20) unsigned default NULL, @@ -1650,3 +1652,4 @@ b b a b DEALLOCATE PREPARE stmt; SET SESSION join_cache_level=default; DROP TABLE t1,t2,t3; +SET optimizer_switch=@save_optimizer_switch; diff --git a/mysql-test/r/join_outer_jcl6.result b/mysql-test/r/join_outer_jcl6.result index 11b5edf5a13..ec6e773fbae 100644 --- a/mysql-test/r/join_outer_jcl6.result +++ b/mysql-test/r/join_outer_jcl6.result @@ -7,7 +7,10 @@ set join_cache_level=6; show variables like 'join_cache_level'; Variable_name Value join_cache_level 6 +set @optimizer_switch_for_join_outer_test=@@optimizer_switch; drop table if exists t0,t1,t2,t3,t4,t5; +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch=ifnull(@optimizer_switch_for_join_outer_test,'outer_join_with_cache=off'); CREATE TABLE t1 ( grp int(11) default NULL, a bigint(20) unsigned default NULL, @@ -1659,8 +1662,10 @@ b b a b DEALLOCATE PREPARE stmt; SET SESSION join_cache_level=default; DROP TABLE t1,t2,t3; +SET optimizer_switch=@save_optimizer_switch; set join_cache_level=default; show variables like 'join_cache_level'; Variable_name Value join_cache_level 1 set @@optimizer_switch=@save_optimizer_switch_jcl6; +set @optimizer_switch_for_join_outer_test=NULL; diff --git a/mysql-test/r/myisam_icp.result b/mysql-test/r/myisam_icp.result index 6d8b28ae23d..753db6d6fc3 100644 --- a/mysql-test/r/myisam_icp.result +++ b/mysql-test/r/myisam_icp.result @@ -755,6 +755,8 @@ INSERT INTO t3 VALUES ('c'); CREATE TABLE t4 ( b int, c varchar(1), KEY (b)); INSERT INTO t4 VALUES (7,'c'); INSERT INTO t4 VALUES (7,'c'); +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; # Must be t1,t2,t3,t4, with t4 having Full-scan-on-NULL but not Using index condition explain SELECT * FROM t1 LEFT JOIN t2 ON t1.c=t2.b @@ -771,5 +773,6 @@ t2.b NOT IN (SELECT t4.b FROM t3 STRAIGHT_JOIN t4 WHERE t4.b <= 2 AND t4.c = t3. c c b c NULL NULL c NULL NULL +SET optimizer_switch=@save_optimizer_switch; DROP TABLE t1,t2,t3,t4; set optimizer_switch=@myisam_icp_tmp; diff --git a/mysql-test/r/optimizer_switch.result b/mysql-test/r/optimizer_switch.result index 1606547e137..7169ee60650 100644 --- a/mysql-test/r/optimizer_switch.result +++ b/mysql-test/r/optimizer_switch.result @@ -4,19 +4,19 @@ # select @@optimizer_switch; @@optimizer_switch -index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off +index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off set optimizer_switch='index_merge=off,index_merge_union=off'; select @@optimizer_switch; @@optimizer_switch -index_merge=off,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off +index_merge=off,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off set optimizer_switch='index_merge_union=on'; select @@optimizer_switch; @@optimizer_switch -index_merge=off,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off +index_merge=off,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off set optimizer_switch='default,index_merge_sort_union=off'; select @@optimizer_switch; @@optimizer_switch -index_merge=on,index_merge_union=on,index_merge_sort_union=off,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off +index_merge=on,index_merge_union=on,index_merge_sort_union=off,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off set optimizer_switch=4; ERROR 42000: Variable 'optimizer_switch' can't be set to the value of '4' set optimizer_switch=NULL; @@ -43,60 +43,60 @@ set optimizer_switch=default; set optimizer_switch='index_merge=off,index_merge_union=off,default'; select @@optimizer_switch; @@optimizer_switch -index_merge=off,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off +index_merge=off,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off set optimizer_switch=default; select @@global.optimizer_switch; @@global.optimizer_switch -index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off +index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off set @@global.optimizer_switch=default; select @@global.optimizer_switch; @@global.optimizer_switch -index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off +index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off # # Check index_merge's @@optimizer_switch flags # select @@optimizer_switch; @@optimizer_switch -index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off +index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off BUG#37120 optimizer_switch allowable values not according to specification select @@optimizer_switch; @@optimizer_switch -index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off +index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off set optimizer_switch='default,materialization=off'; select @@optimizer_switch; @@optimizer_switch -index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=off,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off +index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=off,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off set optimizer_switch='default,semijoin=off'; select @@optimizer_switch; @@optimizer_switch -index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off +index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off set optimizer_switch='default,loosescan=off'; select @@optimizer_switch; @@optimizer_switch -index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=off,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off +index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=off,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off set optimizer_switch='default,semijoin=off,materialization=off'; select @@optimizer_switch; @@optimizer_switch -index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=off,in_to_exists=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off +index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=off,in_to_exists=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off set optimizer_switch='default,materialization=off,semijoin=off'; select @@optimizer_switch; @@optimizer_switch -index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=off,in_to_exists=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off +index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=off,in_to_exists=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off set optimizer_switch='default,semijoin=off,materialization=off,loosescan=off'; select @@optimizer_switch; @@optimizer_switch -index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=off,materialization=off,in_to_exists=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off +index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=off,materialization=off,in_to_exists=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off set optimizer_switch='default,semijoin=off,loosescan=off'; select @@optimizer_switch; @@optimizer_switch -index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=off,materialization=on,in_to_exists=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off +index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=off,materialization=on,in_to_exists=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off set optimizer_switch='default,materialization=off,loosescan=off'; select @@optimizer_switch; @@optimizer_switch -index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=off,materialization=off,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off +index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=off,materialization=off,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off set optimizer_switch=default; select @@optimizer_switch; @@optimizer_switch -index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off +index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off diff --git a/mysql-test/r/order_by.result b/mysql-test/r/order_by.result index c05cba43401..e73ff62366c 100644 --- a/mysql-test/r/order_by.result +++ b/mysql-test/r/order_by.result @@ -179,6 +179,8 @@ INSERT INTO t2 VALUES (1,50); INSERT INTO t2 VALUES (2,25); INSERT INTO t3 VALUES (1,'123 Park Place'); INSERT INTO t3 VALUES (2,'453 Boardwalk'); +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; SELECT a,b,if(b = 1,i,if(b = 2,v,'')) FROM t1 LEFT JOIN t2 USING(c) @@ -217,6 +219,7 @@ a b if(b = 1,i,if(b = 2,v,'')) 2 1 25 3 2 123 Park Place 4 2 453 Boardwalk +SET optimizer_switch=@save_optimizer_switch; drop table t1,t2,t3; create table t1 (ID int not null primary key, TransactionID int not null); insert into t1 (ID, TransactionID) values (1, 87), (2, 89), (3, 92), (4, 94), (5, 486), (6, 490), (7, 753), (9, 828), (10, 832), (11, 834), (12, 840); diff --git a/mysql-test/r/pool_of_threads.result b/mysql-test/r/pool_of_threads.result index 74ea7ba12eb..1a6ab80293f 100644 --- a/mysql-test/r/pool_of_threads.result +++ b/mysql-test/r/pool_of_threads.result @@ -1,3 +1,5 @@ +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; drop table if exists t1,t2,t3,t4; CREATE TABLE t1 ( Period smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, @@ -1347,6 +1349,8 @@ fld1 fld1 250503 250505 250504 250505 250505 250505 +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; insert into t2 (fld1, companynr) values (999999,99); select t2.companynr,companyname from t2 left join t4 using (companynr) where t4.companynr is null; companynr companyname @@ -1422,6 +1426,7 @@ explain select companynr,companyname from t4 left join t2 using (companynr) wher id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where 1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where +SET optimizer_switch=@save_optimizer_switch; select distinct t2.companynr,t4.companynr from t2,t4 where t2.companynr=t4.companynr+1; companynr companynr 37 36 @@ -2151,6 +2156,7 @@ Privat (Private Nutzung) Mobilfunk Warnings: Warning 1052 Column 'kundentyp' in group statement is ambiguous drop table t1; +SET optimizer_switch=@save_optimizer_switch; SELECT sleep(5); SELECT sleep(5); # -- Success: more than --thread-pool-size normal connections not possible diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index becea752810..08944da6182 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -3012,6 +3012,8 @@ DROP TABLE t1; # CREATE TABLE t1(a INT); INSERT INTO t1 VALUES (1),(2); +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; PREPARE stmt FROM 'EXPLAIN EXTENDED SELECT 1 FROM t1 RIGHT JOIN t1 t2 ON 1'; EXECUTE stmt; id select_type table type possible_keys key key_len ref rows filtered Extra @@ -3026,6 +3028,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra Warnings: Note 1003 select 1 AS `1` from `test`.`t1` `t2` left join `test`.`t1` on(1) where 1 DEALLOCATE PREPARE stmt; +SET optimizer_switch=@save_optimizer_switch; DROP TABLE t1; # # Bug#54488 crash when using explain and prepared statements with subqueries diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index 5f8ff00d79f..a3647c10350 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -1,6 +1,8 @@ drop table if exists t1,t2,t3,t4,t11; drop table if exists t1_1,t1_2,t9_1,t9_2,t1aa,t2aa; drop view if exists v1; +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch=ifnull(@optimizer_switch_for_select_test,'outer_join_with_cache=off'); CREATE TABLE t1 ( Period smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, Varor_period smallint(4) unsigned DEFAULT '0' NOT NULL @@ -5096,3 +5098,4 @@ Warning 1292 Incorrect datetime value: 'zz' Warning 1292 Incorrect datetime value: 'aa' DROP TABLE t1; DROP VIEW v1; +SET optimizer_switch=@save_optimizer_switch; diff --git a/mysql-test/r/select_jcl6.result b/mysql-test/r/select_jcl6.result index e0be3247282..f5104ce254d 100644 --- a/mysql-test/r/select_jcl6.result +++ b/mysql-test/r/select_jcl6.result @@ -7,9 +7,12 @@ set join_cache_level=6; show variables like 'join_cache_level'; Variable_name Value join_cache_level 6 +set @optimizer_switch_for_select_test=@@optimizer_switch; drop table if exists t1,t2,t3,t4,t11; drop table if exists t1_1,t1_2,t9_1,t9_2,t1aa,t2aa; drop view if exists v1; +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch=ifnull(@optimizer_switch_for_select_test,'outer_join_with_cache=off'); CREATE TABLE t1 ( Period smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, Varor_period smallint(4) unsigned DEFAULT '0' NOT NULL @@ -5105,8 +5108,10 @@ Warning 1292 Incorrect datetime value: 'zz' Warning 1292 Incorrect datetime value: 'aa' DROP TABLE t1; DROP VIEW v1; +SET optimizer_switch=@save_optimizer_switch; set join_cache_level=default; show variables like 'join_cache_level'; Variable_name Value join_cache_level 1 set @@optimizer_switch=@save_optimizer_switch_jcl6; +set @optimizer_switch_for_select_test=NULL; diff --git a/mysql-test/r/select_pkeycache.result b/mysql-test/r/select_pkeycache.result index 5f8ff00d79f..a3647c10350 100644 --- a/mysql-test/r/select_pkeycache.result +++ b/mysql-test/r/select_pkeycache.result @@ -1,6 +1,8 @@ drop table if exists t1,t2,t3,t4,t11; drop table if exists t1_1,t1_2,t9_1,t9_2,t1aa,t2aa; drop view if exists v1; +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch=ifnull(@optimizer_switch_for_select_test,'outer_join_with_cache=off'); CREATE TABLE t1 ( Period smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, Varor_period smallint(4) unsigned DEFAULT '0' NOT NULL @@ -5096,3 +5098,4 @@ Warning 1292 Incorrect datetime value: 'zz' Warning 1292 Incorrect datetime value: 'aa' DROP TABLE t1; DROP VIEW v1; +SET optimizer_switch=@save_optimizer_switch; diff --git a/mysql-test/r/ssl.result b/mysql-test/r/ssl.result index 1a52571c2d7..eae5bb5c2c9 100644 --- a/mysql-test/r/ssl.result +++ b/mysql-test/r/ssl.result @@ -1350,6 +1350,8 @@ fld1 fld1 250503 250505 250504 250505 250505 250505 +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; insert into t2 (fld1, companynr) values (999999,99); select t2.companynr,companyname from t2 left join t4 using (companynr) where t4.companynr is null; companynr companyname @@ -1425,6 +1427,7 @@ explain select companynr,companyname from t4 left join t2 using (companynr) wher id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where 1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where +SET optimizer_switch=@save_optimizer_switch; select distinct t2.companynr,t4.companynr from t2,t4 where t2.companynr=t4.companynr+1; companynr companynr 37 36 diff --git a/mysql-test/r/ssl_compress.result b/mysql-test/r/ssl_compress.result index d66b0a3a7f5..d39d09322c8 100644 --- a/mysql-test/r/ssl_compress.result +++ b/mysql-test/r/ssl_compress.result @@ -1353,6 +1353,8 @@ fld1 fld1 250503 250505 250504 250505 250505 250505 +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; insert into t2 (fld1, companynr) values (999999,99); select t2.companynr,companyname from t2 left join t4 using (companynr) where t4.companynr is null; companynr companyname @@ -1428,6 +1430,7 @@ explain select companynr,companyname from t4 left join t2 using (companynr) wher id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where 1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where +SET optimizer_switch=@save_optimizer_switch; select distinct t2.companynr,t4.companynr from t2,t4 where t2.companynr=t4.companynr+1; companynr companynr 37 36 diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 414e31f238b..2eaf4062659 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -5468,6 +5468,8 @@ CREATE TABLE t2 (a int, b int) ; INSERT INTO t2 VALUES (20,9),(20,9); create table t3 (d int, e int); insert into t3 values (2, 9), (3,10); +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; EXPLAIN SELECT t2.b , t1.c FROM t2 LEFT JOIN t1 ON t1.c < 3 @@ -5482,6 +5484,7 @@ WHERE (t2.b, t1.c) NOT IN (SELECT * from t3); b c 9 NULL 9 NULL +SET optimizer_switch=@save_optimizer_switch; drop table t1, t2, t3; End of 5.3 tests # diff --git a/mysql-test/r/subselect4.result b/mysql-test/r/subselect4.result index f830be38321..a1501099d72 100644 --- a/mysql-test/r/subselect4.result +++ b/mysql-test/r/subselect4.result @@ -1226,6 +1226,8 @@ CREATE TABLE t3 (c1 varchar(1) DEFAULT NULL); INSERT INTO t3 VALUES ('a'), ('b'), ('c'); CREATE TABLE t4 (c1 varchar(1) primary key); INSERT INTO t4 VALUES ('k'), ('d'); +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; EXPLAIN SELECT * FROM t1 RIGHT JOIN t2 ON t1.c1 WHERE 's' IN (SELECT c1 FROM t2); id select_type table type possible_keys key key_len ref rows Extra @@ -1261,6 +1263,7 @@ id select_type table type possible_keys key key_len ref rows Extra 2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 Using where SELECT * FROM t4 LEFT JOIN t2 ON t4.c1 WHERE 's' IN (SELECT c1 FROM t2); c1 c1 +SET optimizer_switch=@save_optimizer_switch; drop table t1, t2, t3, t4; # # LP BUG#675981 Assertion `cache != __null' failed in sub_select_cache() @@ -1620,6 +1623,7 @@ CREATE TABLE t2 (f1b int, f2b int not null, f3b varchar(3) not null, PRIMARY KEY INSERT INTO t2 VALUES (10,5,'d1d'); set @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; set @@optimizer_switch = 'materialization=off'; EXPLAIN SELECT alias2.f1 , alias2.f2 diff --git a/mysql-test/r/subselect_cache.result b/mysql-test/r/subselect_cache.result index 9bedf154cfd..1dd1655c2a6 100644 --- a/mysql-test/r/subselect_cache.result +++ b/mysql-test/r/subselect_cache.result @@ -1,5 +1,8 @@ drop table if exists t1,t2,t3,t4,t5; drop view if exists v1; +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; +SET optimizer_switch='semijoin_with_cache=off'; set optimizer_switch='subquery_cache=on'; create table t1 (a int, b int); insert into t1 values (1,2),(3,4),(1,2),(3,4),(3,4),(4,5),(4,5),(5,6),(5,6),(4,5); @@ -3382,5 +3385,6 @@ pk b 29 3 drop view v1; drop table t1,t2,t3,t4; +SET optimizer_switch=@save_optimizer_switch; # restore default set @@optimizer_switch= default; diff --git a/mysql-test/r/subselect_no_mat.result b/mysql-test/r/subselect_no_mat.result index 10b4f5a6af7..2acca5e0af9 100644 --- a/mysql-test/r/subselect_no_mat.result +++ b/mysql-test/r/subselect_no_mat.result @@ -5467,6 +5467,8 @@ CREATE TABLE t2 (a int, b int) ; INSERT INTO t2 VALUES (20,9),(20,9); create table t3 (d int, e int); insert into t3 values (2, 9), (3,10); +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; EXPLAIN SELECT t2.b , t1.c FROM t2 LEFT JOIN t1 ON t1.c < 3 @@ -5481,6 +5483,7 @@ WHERE (t2.b, t1.c) NOT IN (SELECT * from t3); b c 9 NULL 9 NULL +SET optimizer_switch=@save_optimizer_switch; drop table t1, t2, t3; End of 5.3 tests # diff --git a/mysql-test/r/subselect_no_opts.result b/mysql-test/r/subselect_no_opts.result index c809dcdfda8..b5e0f16c388 100644 --- a/mysql-test/r/subselect_no_opts.result +++ b/mysql-test/r/subselect_no_opts.result @@ -5463,6 +5463,8 @@ CREATE TABLE t2 (a int, b int) ; INSERT INTO t2 VALUES (20,9),(20,9); create table t3 (d int, e int); insert into t3 values (2, 9), (3,10); +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; EXPLAIN SELECT t2.b , t1.c FROM t2 LEFT JOIN t1 ON t1.c < 3 @@ -5477,6 +5479,7 @@ WHERE (t2.b, t1.c) NOT IN (SELECT * from t3); b c 9 NULL 9 NULL +SET optimizer_switch=@save_optimizer_switch; drop table t1, t2, t3; End of 5.3 tests # diff --git a/mysql-test/r/subselect_no_scache.result b/mysql-test/r/subselect_no_scache.result index 6dabc727214..aaa162528fc 100644 --- a/mysql-test/r/subselect_no_scache.result +++ b/mysql-test/r/subselect_no_scache.result @@ -5472,6 +5472,8 @@ CREATE TABLE t2 (a int, b int) ; INSERT INTO t2 VALUES (20,9),(20,9); create table t3 (d int, e int); insert into t3 values (2, 9), (3,10); +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; EXPLAIN SELECT t2.b , t1.c FROM t2 LEFT JOIN t1 ON t1.c < 3 @@ -5486,6 +5488,7 @@ WHERE (t2.b, t1.c) NOT IN (SELECT * from t3); b c 9 NULL 9 NULL +SET optimizer_switch=@save_optimizer_switch; drop table t1, t2, t3; End of 5.3 tests # diff --git a/mysql-test/r/subselect_no_semijoin.result b/mysql-test/r/subselect_no_semijoin.result index cb2704127c4..7923d4cc68b 100644 --- a/mysql-test/r/subselect_no_semijoin.result +++ b/mysql-test/r/subselect_no_semijoin.result @@ -5463,6 +5463,8 @@ CREATE TABLE t2 (a int, b int) ; INSERT INTO t2 VALUES (20,9),(20,9); create table t3 (d int, e int); insert into t3 values (2, 9), (3,10); +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; EXPLAIN SELECT t2.b , t1.c FROM t2 LEFT JOIN t1 ON t1.c < 3 @@ -5477,6 +5479,7 @@ WHERE (t2.b, t1.c) NOT IN (SELECT * from t3); b c 9 NULL 9 NULL +SET optimizer_switch=@save_optimizer_switch; drop table t1, t2, t3; End of 5.3 tests # diff --git a/mysql-test/r/subselect_sj.result b/mysql-test/r/subselect_sj.result index a7b3cffb8d2..6bea2c8c17b 100644 --- a/mysql-test/r/subselect_sj.result +++ b/mysql-test/r/subselect_sj.result @@ -4,6 +4,8 @@ drop procedure if exists p1; set @subselect_sj_tmp= @@optimizer_switch; set optimizer_switch='semijoin=on,firstmatch=on,loosescan=on'; set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; +SET optimizer_switch=ifnull(@optimizer_switch_for_subselect_sj_test,'outer_join_with_cache=off'); +SET optimizer_switch=ifnull(@optimizer_switch_for_subselect_sj_test,'semijoin_with_cache=off'); set @save_optimizer_switch=@@optimizer_switch; create table t0 (a int); insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); diff --git a/mysql-test/r/subselect_sj2.result b/mysql-test/r/subselect_sj2.result index cd147e55d1d..f9d70fd8943 100644 --- a/mysql-test/r/subselect_sj2.result +++ b/mysql-test/r/subselect_sj2.result @@ -1,6 +1,8 @@ set @subselect_sj2_tmp= @@optimizer_switch; set optimizer_switch='semijoin=on,firstmatch=on,loosescan=on'; set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; +SET optimizer_switch=ifnull(@optimizer_switch_for_subselect_sj2_test,'outer_join_with_cache=off'); +SET optimizer_switch=ifnull(@optimizer_switch_for_subselect_sj2_test,'semijoin_with_cache=off'); drop table if exists t0, t1, t2, t3, t4, t5; drop view if exists v1; create table t0 (a int); diff --git a/mysql-test/r/subselect_sj2_jcl6.result b/mysql-test/r/subselect_sj2_jcl6.result index 02d2fb01d93..eb5b86a3dc6 100644 --- a/mysql-test/r/subselect_sj2_jcl6.result +++ b/mysql-test/r/subselect_sj2_jcl6.result @@ -7,9 +7,12 @@ set join_cache_level=6; show variables like 'join_cache_level'; Variable_name Value join_cache_level 6 +set @optimizer_switch_for_subselect_sj2_test=@@optimizer_switch; set @subselect_sj2_tmp= @@optimizer_switch; set optimizer_switch='semijoin=on,firstmatch=on,loosescan=on'; set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; +SET optimizer_switch=ifnull(@optimizer_switch_for_subselect_sj2_test,'outer_join_with_cache=off'); +SET optimizer_switch=ifnull(@optimizer_switch_for_subselect_sj2_test,'semijoin_with_cache=off'); drop table if exists t0, t1, t2, t3, t4, t5; drop view if exists v1; create table t0 (a int); @@ -981,3 +984,4 @@ show variables like 'join_cache_level'; Variable_name Value join_cache_level 1 set @@optimizer_switch=@save_optimizer_switch_jcl6; +set @optimizer_switch_for_subselect_sj2_test=NULL; diff --git a/mysql-test/r/subselect_sj2_mat.result b/mysql-test/r/subselect_sj2_mat.result index 6f3e1de4113..021eedab5b8 100644 --- a/mysql-test/r/subselect_sj2_mat.result +++ b/mysql-test/r/subselect_sj2_mat.result @@ -3,6 +3,8 @@ set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; set @subselect_sj2_tmp= @@optimizer_switch; set optimizer_switch='semijoin=on,firstmatch=on,loosescan=on'; set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; +SET optimizer_switch=ifnull(@optimizer_switch_for_subselect_sj2_test,'outer_join_with_cache=off'); +SET optimizer_switch=ifnull(@optimizer_switch_for_subselect_sj2_test,'semijoin_with_cache=off'); drop table if exists t0, t1, t2, t3, t4, t5; drop view if exists v1; create table t0 (a int); diff --git a/mysql-test/r/subselect_sj_jcl6.result b/mysql-test/r/subselect_sj_jcl6.result index 8de5af4cf56..26f6ef11878 100644 --- a/mysql-test/r/subselect_sj_jcl6.result +++ b/mysql-test/r/subselect_sj_jcl6.result @@ -9,12 +9,15 @@ set join_cache_level=6; show variables like 'join_cache_level'; Variable_name Value join_cache_level 6 +set @optimizer_switch_for_subselect_sj_test=@@optimizer_switch; drop table if exists t0, t1, t2, t3, t4, t5, t10, t11, t12; drop view if exists v1, v2, v3, v4; drop procedure if exists p1; set @subselect_sj_tmp= @@optimizer_switch; set optimizer_switch='semijoin=on,firstmatch=on,loosescan=on'; set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; +SET optimizer_switch=ifnull(@optimizer_switch_for_subselect_sj_test,'outer_join_with_cache=off'); +SET optimizer_switch=ifnull(@optimizer_switch_for_subselect_sj_test,'semijoin_with_cache=off'); set @save_optimizer_switch=@@optimizer_switch; create table t0 (a int); insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); @@ -2242,3 +2245,4 @@ show variables like 'join_cache_level'; Variable_name Value join_cache_level 1 set @@optimizer_switch=@save_optimizer_switch_jcl6; +set @optimizer_switch_for_subselect_sj_test=NULL; diff --git a/mysql-test/r/subselect_sj_nonmerged.result b/mysql-test/r/subselect_sj_nonmerged.result index fe1f9c35626..8df74536de7 100644 --- a/mysql-test/r/subselect_sj_nonmerged.result +++ b/mysql-test/r/subselect_sj_nonmerged.result @@ -51,6 +51,8 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t3 eq_ref PRIMARY PRIMARY 8 .max(t2.a) 1 Using where; Using index 2 MATERIALIZED t2 ALL NULL NULL NULL NULL 5 Using temporary 2 MATERIALIZED t1 ALL NULL NULL NULL NULL 10 Using join buffer (flat, BNL join) +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; # Outer joins also work: explain select * from t3 where a in (select max(t2.a) from t1 left join t2 on t1.a=t2.a group by t2.b, t1.b); @@ -59,6 +61,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t3 eq_ref PRIMARY PRIMARY 8 .max(t2.a) 1 Using where; Using index 2 MATERIALIZED t1 ALL NULL NULL NULL NULL 10 Using temporary 2 MATERIALIZED t2 ALL NULL NULL NULL NULL 5 Using where +SET optimizer_switch=@save_optimizer_switch; create table t4 (a int, b int, filler char(20), unique key(a,b)); insert into t4 select A.a + 10*B.a, A.a + 10*B.a, 'filler' from t0 A, t0 B; explain select * from t0, t4 where diff --git a/mysql-test/r/table_elim.result b/mysql-test/r/table_elim.result index 4b4ea83fcce..9b2656c17e4 100644 --- a/mysql-test/r/table_elim.result +++ b/mysql-test/r/table_elim.result @@ -1,5 +1,7 @@ drop table if exists t0, t1, t2, t3, t4, t5, t6; drop view if exists v1, v2; +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; create table t1 (a int); insert into t1 values (0),(1),(2),(3); create table t0 as select * from t1; @@ -586,3 +588,4 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 eq_ref PRIMARY PRIMARY 4 test.t1.a 1 Using where; Using index drop view v1; DROP TABLE t1,t2,t3; +SET optimizer_switch=@save_optimizer_switch; diff --git a/mysql-test/r/type_datetime.result b/mysql-test/r/type_datetime.result index 966343fa80f..1a111fe591a 100644 --- a/mysql-test/r/type_datetime.result +++ b/mysql-test/r/type_datetime.result @@ -510,6 +510,8 @@ create table t1 (id int(10) not null, cur_date datetime not null); create table t2 (id int(10) not null, cur_date date not null); insert into t1 (id, cur_date) values (1, '2007-04-25 18:30:22'); insert into t2 (id, cur_date) values (1, '2007-04-25'); +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='semijoin_with_cache=off'; explain extended select * from t1 where id in (select id from t1 as x1 where (t1.cur_date is null)); @@ -558,6 +560,7 @@ Note 1003 select `test`.`t2`.`id` AS `id`,`test`.`t2`.`cur_date` AS `cur_date` f select * from t2 where id in (select id from t2 as x1 where (t2.cur_date is null)); id cur_date +SET optimizer_switch=@save_optimizer_switch; drop table t1,t2; SELECT CAST('NULL' AS DATE) <=> CAST('2008-01-01' AS DATE) n1, diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result index 338ce242d48..13941d3f84d 100644 --- a/mysql-test/r/union.result +++ b/mysql-test/r/union.result @@ -918,6 +918,8 @@ Slow_queries 1 drop table t1; create table t1 ( RID int(11) not null default '0', IID int(11) not null default '0', nada varchar(50) not null,NAME varchar(50) not null,PHONE varchar(50) not null) engine=MyISAM; insert into t1 ( RID,IID,nada,NAME,PHONE) values (1, 1, 'main', 'a', '111'), (2, 1, 'main', 'b', '222'), (3, 1, 'main', 'c', '333'), (4, 1, 'main', 'd', '444'), (5, 1, 'main', 'e', '555'), (6, 2, 'main', 'c', '333'), (7, 2, 'main', 'd', '454'), (8, 2, 'main', 'e', '555'), (9, 2, 'main', 'f', '666'), (10, 2, 'main', 'g', '777'); +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; select A.NAME, A.PHONE, B.NAME, B.PHONE from t1 A left join t1 B on A.NAME = B.NAME and B.IID = 2 where A.IID = 1 and (A.PHONE <> B.PHONE or B.NAME is null) union select A.NAME, A.PHONE, B.NAME, B.PHONE from t1 B left join t1 A on B.NAME = A.NAME and A.IID = 1 where B.IID = 2 and (A.PHONE <> B.PHONE or A.NAME is null); NAME PHONE NAME PHONE a 111 NULL NULL @@ -925,6 +927,7 @@ b 222 NULL NULL d 444 d 454 NULL NULL f 666 NULL NULL g 777 +SET optimizer_switch=@save_optimizer_switch; drop table t1; create table t1 (col1 tinyint unsigned, col2 tinyint unsigned); insert into t1 values (1,2),(3,4),(5,6),(7,8),(9,10); diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index f9e5c875726..644f7f7289e 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -2,6 +2,8 @@ drop table if exists t1,t2,t3,t4,t9,`t1a``b`,v1,v2,v3,v4,v5,v6; drop view if exists t1,t2,`t1a``b`,v1,v2,v3,v4,v5,v6; drop database if exists mysqltest; use test; +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; create view v1 (c,d) as select a,b from t1; ERROR 42S02: Table 'test.t1' doesn't exist create temporary table t1 (a int, b int); @@ -4372,3 +4374,4 @@ NULL NULL 1 0 NULL NULL 1 0 DROP VIEW v2; DROP TABLE t1, t2, t3; +SET optimizer_switch=@save_optimizer_switch; diff --git a/mysql-test/suite/pbxt/r/func_group.result b/mysql-test/suite/pbxt/r/func_group.result index c3474e2f3ad..8817afa6462 100644 --- a/mysql-test/suite/pbxt/r/func_group.result +++ b/mysql-test/suite/pbxt/r/func_group.result @@ -215,6 +215,8 @@ a1 a2 a1 a2 10 bbb BBB 20 20 zzz AAA 10 20 zzz BBB 20 +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; select max(t1.a1), max(t2.a1) from t1, t2 where t2.a2=9; max(t1.a1) max(t2.a1) NULL NULL @@ -245,6 +247,7 @@ NULL select max(t1.a2),max(t2.a1) from t1 left outer join t2 on t1.a1=10; max(t1.a2) max(t2.a1) zzz BBB +SET optimizer_switch=@save_optimizer_switch; drop table t1,t2; CREATE TABLE t1 (a int, b int); select count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1; diff --git a/mysql-test/suite/pbxt/r/func_op.result b/mysql-test/suite/pbxt/r/func_op.result index 636163e6b29..ce755e86b4c 100644 --- a/mysql-test/suite/pbxt/r/func_op.result +++ b/mysql-test/suite/pbxt/r/func_op.result @@ -40,9 +40,12 @@ create table t1(a int); create table t2(a int, b int); insert into t1 values (1), (2), (3); insert into t2 values (1, 7), (3, 7); +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; select t1.a, t2.a, t2.b, bit_count(t2.b) from t1 left join t2 on t1.a=t2.a; a a b bit_count(t2.b) 1 1 7 3 2 NULL NULL NULL 3 3 7 3 +SET optimizer_switch=@save_optimizer_switch; drop table t1, t2; diff --git a/mysql-test/suite/pbxt/r/group_by.result b/mysql-test/suite/pbxt/r/group_by.result index c7f87f2dc35..06cb168b3aa 100644 --- a/mysql-test/suite/pbxt/r/group_by.result +++ b/mysql-test/suite/pbxt/r/group_by.result @@ -450,6 +450,8 @@ drop table t1,t2; CREATE TABLE t1 (ID1 int, ID2 int, ID int NOT NULL AUTO_INCREMENT,PRIMARY KEY(ID )); insert into t1 values (1,244,NULL),(2,243,NULL),(134,223,NULL),(185,186,NULL); +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; select S.ID as xID, S.ID1 as xID1 from t1 as S left join t1 as yS on S.ID1 between yS.ID1 and yS.ID2; xID xID1 1 1 @@ -468,6 +470,7 @@ xID xID1 Level 2 2 ** 3 134 *** 4 185 **** +SET optimizer_switch=@save_optimizer_switch; drop table t1; CREATE TABLE t1 ( pid int(11) unsigned NOT NULL default '0', diff --git a/mysql-test/suite/pbxt/r/join.result b/mysql-test/suite/pbxt/r/join.result index 570d04bfbfc..5035f5da9bd 100644 --- a/mysql-test/suite/pbxt/r/join.result +++ b/mysql-test/suite/pbxt/r/join.result @@ -1,4 +1,6 @@ drop table if exists t1,t2,t3; +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; CREATE TABLE t1 (S1 INT); CREATE TABLE t2 (S1 INT); INSERT INTO t1 VALUES (1); @@ -819,4 +821,5 @@ Field Type Null Key Default Extra Name varchar(50) YES NULL DROP VIEW v1; DROP TABLE t1,t2,tv1,tv2; +SET optimizer_switch=@save_optimizer_switch; End of 5.0 tests. diff --git a/mysql-test/suite/pbxt/r/join_nested.result b/mysql-test/suite/pbxt/r/join_nested.result index 1a195cb13a8..199e56ee150 100644 --- a/mysql-test/suite/pbxt/r/join_nested.result +++ b/mysql-test/suite/pbxt/r/join_nested.result @@ -1,4 +1,6 @@ DROP TABLE IF EXISTS t0,t1,t2,t3,t4,t5,t6,t7,t8,t9; +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; CREATE TABLE t0 (a int, b int, c int); CREATE TABLE t1 (a int, b int, c int); CREATE TABLE t2 (a int, b int, c int); @@ -1614,3 +1616,4 @@ WHERE t1.id='5'; id ct pc nm 5 NULL NULL NULL DROP TABLE t1,t2,t3,t4; +SET optimizer_switch=@save_optimizer_switch; diff --git a/mysql-test/suite/pbxt/r/join_outer.result b/mysql-test/suite/pbxt/r/join_outer.result index e6ae055d811..fa41e005e07 100644 --- a/mysql-test/suite/pbxt/r/join_outer.result +++ b/mysql-test/suite/pbxt/r/join_outer.result @@ -1,4 +1,6 @@ drop table if exists t0,t1,t2,t3,t4,t5; +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; CREATE TABLE t1 ( grp int(11) default NULL, a bigint(20) unsigned default NULL, @@ -1194,3 +1196,4 @@ a b 3 3 4 NULL DROP TABLE t1,t2; +SET optimizer_switch=@save_optimizer_switch; diff --git a/mysql-test/suite/pbxt/r/select.result b/mysql-test/suite/pbxt/r/select.result index 51e5d95edea..869df25504a 100644 --- a/mysql-test/suite/pbxt/r/select.result +++ b/mysql-test/suite/pbxt/r/select.result @@ -1,6 +1,8 @@ drop table if exists t1,t2,t3,t4,t11; drop table if exists t1_1,t1_2,t9_1,t9_2,t1aa,t2aa; drop view if exists v1; +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; CREATE TABLE t1 ( Period smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, Varor_period smallint(4) unsigned DEFAULT '0' NOT NULL @@ -3639,3 +3641,4 @@ INSERT into t1 values (1), (2), (3); SELECT * FROM t1 LIMIT 2, -1; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '-1' at line 1 DROP TABLE t1; +SET optimizer_switch=@save_optimizer_switch; diff --git a/mysql-test/suite/pbxt/r/subselect.result b/mysql-test/suite/pbxt/r/subselect.result index c6913d32fe8..d83b216a391 100644 --- a/mysql-test/suite/pbxt/r/subselect.result +++ b/mysql-test/suite/pbxt/r/subselect.result @@ -1336,6 +1336,8 @@ create table t3 (a int, b int, index a (a)); insert into t1 values (1,10), (2,20), (3,30), (4,40); insert into t2 values (2), (3), (4), (5); insert into t3 values (10,3), (20,4), (30,5); +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='semijoin_with_cache=off'; select * from t2 where t2.a in (select a from t1); a 2 @@ -1384,6 +1386,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ref a a 5 test.t2.a 1 100.00 Using where; Using index; FirstMatch(t2) Warnings: Note 1003 select `test`.`t2`.`a` AS `a` from `test`.`t2` semi join (`test`.`t1`) where ((`test`.`t1`.`a` = `test`.`t2`.`a`) and (`test`.`t1`.`b` <> 30)) +SET optimizer_switch=@save_optimizer_switch; drop table t1, t2, t3; create table t1 (a int, b int); create table t2 (a int, b int); @@ -2764,6 +2767,7 @@ max(fld) drop table t1; set @save_optimizer_switch=@@optimizer_switch; set @@optimizer_switch="partial_match_rowid_merge=off,partial_match_table_scan=off"; +SET optimizer_switch='semijoin_with_cache=off'; CREATE TABLE t1 (one int, two int, flag char(1)); CREATE TABLE t2 (one int, two int, flag char(1)); INSERT INTO t1 VALUES(1,2,'Y'),(2,3,'Y'),(3,4,'Y'),(5,6,'N'),(7,8,'N'); diff --git a/mysql-test/suite/pbxt/r/union.result b/mysql-test/suite/pbxt/r/union.result index 82327b6d2f8..424604fb4bb 100644 --- a/mysql-test/suite/pbxt/r/union.result +++ b/mysql-test/suite/pbxt/r/union.result @@ -876,6 +876,8 @@ Slow_queries 0 drop table t1; create table t1 ( RID int(11) not null default '0', IID int(11) not null default '0', nada varchar(50) not null,NAME varchar(50) not null,PHONE varchar(50) not null) engine=MyISAM; insert into t1 ( RID,IID,nada,NAME,PHONE) values (1, 1, 'main', 'a', '111'), (2, 1, 'main', 'b', '222'), (3, 1, 'main', 'c', '333'), (4, 1, 'main', 'd', '444'), (5, 1, 'main', 'e', '555'), (6, 2, 'main', 'c', '333'), (7, 2, 'main', 'd', '454'), (8, 2, 'main', 'e', '555'), (9, 2, 'main', 'f', '666'), (10, 2, 'main', 'g', '777'); +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; select A.NAME, A.PHONE, B.NAME, B.PHONE from t1 A left join t1 B on A.NAME = B.NAME and B.IID = 2 where A.IID = 1 and (A.PHONE <> B.PHONE or B.NAME is null) union select A.NAME, A.PHONE, B.NAME, B.PHONE from t1 B left join t1 A on B.NAME = A.NAME and A.IID = 1 where B.IID = 2 and (A.PHONE <> B.PHONE or A.NAME is null); NAME PHONE NAME PHONE a 111 NULL NULL @@ -883,6 +885,7 @@ b 222 NULL NULL d 444 d 454 NULL NULL f 666 NULL NULL g 777 +SET optimizer_switch=@save_optimizer_switch; drop table t1; create table t1 (col1 tinyint unsigned, col2 tinyint unsigned); insert into t1 values (1,2),(3,4),(5,6),(7,8),(9,10); diff --git a/mysql-test/suite/pbxt/t/func_group.test b/mysql-test/suite/pbxt/t/func_group.test index ca303030749..f3b466c463d 100644 --- a/mysql-test/suite/pbxt/t/func_group.test +++ b/mysql-test/suite/pbxt/t/func_group.test @@ -136,6 +136,8 @@ insert into t2 values('AAA', 10, 0.5); insert into t2 values('BBB', 20, 1.0); select t1.a1, t1.a2, t2.a1, t2.a2 from t1,t2; +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; select max(t1.a1), max(t2.a1) from t1, t2 where t2.a2=9; select max(t2.a1), max(t1.a1) from t1, t2 where t2.a2=9; select t1.a1, t1.a2, t2.a1, t2.a2 from t1 left outer join t2 on t1.a1=10; @@ -144,6 +146,7 @@ select max(t2.a1) from t2 left outer join t1 on t2.a2=10 where t2.a2=20; select max(t2.a1) from t2 left outer join t1 on t2.a2=10 where t2.a2=10; select max(t2.a1) from t1 left outer join t2 on t1.a2=t2.a1 and 1=0 where t2.a1='AAA'; select max(t1.a2),max(t2.a1) from t1 left outer join t2 on t1.a1=10; +SET optimizer_switch=@save_optimizer_switch; drop table t1,t2; # diff --git a/mysql-test/suite/pbxt/t/func_op.test b/mysql-test/suite/pbxt/t/func_op.test index 5ac127ad25f..4a6474df946 100644 --- a/mysql-test/suite/pbxt/t/func_op.test +++ b/mysql-test/suite/pbxt/t/func_op.test @@ -28,7 +28,10 @@ create table t1(a int); create table t2(a int, b int); insert into t1 values (1), (2), (3); insert into t2 values (1, 7), (3, 7); +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; select t1.a, t2.a, t2.b, bit_count(t2.b) from t1 left join t2 on t1.a=t2.a; +SET optimizer_switch=@save_optimizer_switch; drop table t1, t2; --disable_query_log diff --git a/mysql-test/suite/pbxt/t/group_by.test b/mysql-test/suite/pbxt/t/group_by.test index c1909668b55..b29519369c7 100644 --- a/mysql-test/suite/pbxt/t/group_by.test +++ b/mysql-test/suite/pbxt/t/group_by.test @@ -338,8 +338,11 @@ drop table t1,t2; CREATE TABLE t1 (ID1 int, ID2 int, ID int NOT NULL AUTO_INCREMENT,PRIMARY KEY(ID )); insert into t1 values (1,244,NULL),(2,243,NULL),(134,223,NULL),(185,186,NULL); +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; select S.ID as xID, S.ID1 as xID1 from t1 as S left join t1 as yS on S.ID1 between yS.ID1 and yS.ID2; select S.ID as xID, S.ID1 as xID1, repeat('*',count(distinct yS.ID)) as Level from t1 as S left join t1 as yS on S.ID1 between yS.ID1 and yS.ID2 group by xID order by xID1; +SET optimizer_switch=@save_optimizer_switch; drop table t1; # diff --git a/mysql-test/suite/pbxt/t/join.test b/mysql-test/suite/pbxt/t/join.test index 02c17d8bcaa..fe73c67a6a3 100644 --- a/mysql-test/suite/pbxt/t/join.test +++ b/mysql-test/suite/pbxt/t/join.test @@ -4,6 +4,9 @@ drop table if exists t1,t2,t3; --enable_warnings +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; + # # Test different join syntaxes # @@ -648,6 +651,8 @@ DESCRIBE tv2; DROP VIEW v1; DROP TABLE t1,t2,tv1,tv2; +SET optimizer_switch=@save_optimizer_switch; + --disable_query_log drop database pbxt; --enable_query_log diff --git a/mysql-test/suite/pbxt/t/join_nested.test b/mysql-test/suite/pbxt/t/join_nested.test index 98ffcbc9a8a..25c8a5a782e 100644 --- a/mysql-test/suite/pbxt/t/join_nested.test +++ b/mysql-test/suite/pbxt/t/join_nested.test @@ -3,6 +3,9 @@ DROP TABLE IF EXISTS t0,t1,t2,t3,t4,t5,t6,t7,t8,t9; --enable_warnings +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; + CREATE TABLE t0 (a int, b int, c int); CREATE TABLE t1 (a int, b int, c int); CREATE TABLE t2 (a int, b int, c int); @@ -1063,6 +1066,9 @@ SELECT t1.*, t4.nm DROP TABLE t1,t2,t3,t4; + +SET optimizer_switch=@save_optimizer_switch; + --disable_query_log drop database pbxt; --enable_query_log diff --git a/mysql-test/suite/pbxt/t/join_outer.test b/mysql-test/suite/pbxt/t/join_outer.test index a9635de7081..4c5006c6b0a 100644 --- a/mysql-test/suite/pbxt/t/join_outer.test +++ b/mysql-test/suite/pbxt/t/join_outer.test @@ -6,6 +6,9 @@ drop table if exists t0,t1,t2,t3,t4,t5; --enable_warnings +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; + CREATE TABLE t1 ( grp int(11) default NULL, a bigint(20) unsigned default NULL, @@ -809,6 +812,8 @@ SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.b WHERE (1=1 OR 1=0); DROP TABLE t1,t2; +SET optimizer_switch=@save_optimizer_switch; + --disable_query_log drop database pbxt; --enable_query_log diff --git a/mysql-test/suite/pbxt/t/select.test b/mysql-test/suite/pbxt/t/select.test index 7074f4ac364..3a1cdcf5451 100644 --- a/mysql-test/suite/pbxt/t/select.test +++ b/mysql-test/suite/pbxt/t/select.test @@ -13,6 +13,9 @@ drop table if exists t1_1,t1_2,t9_1,t9_2,t1aa,t2aa; drop view if exists v1; --enable_warnings +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; + CREATE TABLE t1 ( Period smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, Varor_period smallint(4) unsigned DEFAULT '0' NOT NULL @@ -3130,6 +3133,9 @@ SELECT * FROM t1 LIMIT 2, -1; DROP TABLE t1; + +SET optimizer_switch=@save_optimizer_switch; + --disable_query_log drop database pbxt; --enable_query_log diff --git a/mysql-test/suite/pbxt/t/subselect.test b/mysql-test/suite/pbxt/t/subselect.test index fa838363403..5f0835e0b03 100644 --- a/mysql-test/suite/pbxt/t/subselect.test +++ b/mysql-test/suite/pbxt/t/subselect.test @@ -832,6 +832,8 @@ commit; enable_query_log; insert into t2 values (2), (3), (4), (5); insert into t3 values (10,3), (20,4), (30,5); +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='semijoin_with_cache=off'; select * from t2 where t2.a in (select a from t1); explain extended select * from t2 where t2.a in (select a from t1); select * from t2 where t2.a in (select a from t1 where t1.b <> 30); @@ -842,6 +844,7 @@ insert into t1 values (3,31); select * from t2 where t2.a in (select a from t1 where t1.b <> 30); select * from t2 where t2.a in (select a from t1 where t1.b <> 30 and t1.b <> 31); explain extended select * from t2 where t2.a in (select a from t1 where t1.b <> 30); +SET optimizer_switch=@save_optimizer_switch; drop table t1, t2, t3; # @@ -1795,6 +1798,7 @@ drop table t1; set @save_optimizer_switch=@@optimizer_switch; set @@optimizer_switch="partial_match_rowid_merge=off,partial_match_table_scan=off"; +SET optimizer_switch='semijoin_with_cache=off'; CREATE TABLE t1 (one int, two int, flag char(1)); CREATE TABLE t2 (one int, two int, flag char(1)); @@ -3232,6 +3236,7 @@ INSERT INTO t1 VALUES ('a'); SELECT * FROM t1 WHERE _utf8'a' = ANY (SELECT s1 FROM t1); DROP TABLE t1; + --disable_query_log drop database pbxt; --enable_query_log diff --git a/mysql-test/suite/pbxt/t/union.test b/mysql-test/suite/pbxt/t/union.test index c216b3caceb..5a719f00cb3 100644 --- a/mysql-test/suite/pbxt/t/union.test +++ b/mysql-test/suite/pbxt/t/union.test @@ -481,7 +481,10 @@ drop table t1; # create table t1 ( RID int(11) not null default '0', IID int(11) not null default '0', nada varchar(50) not null,NAME varchar(50) not null,PHONE varchar(50) not null) engine=MyISAM; insert into t1 ( RID,IID,nada,NAME,PHONE) values (1, 1, 'main', 'a', '111'), (2, 1, 'main', 'b', '222'), (3, 1, 'main', 'c', '333'), (4, 1, 'main', 'd', '444'), (5, 1, 'main', 'e', '555'), (6, 2, 'main', 'c', '333'), (7, 2, 'main', 'd', '454'), (8, 2, 'main', 'e', '555'), (9, 2, 'main', 'f', '666'), (10, 2, 'main', 'g', '777'); +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; select A.NAME, A.PHONE, B.NAME, B.PHONE from t1 A left join t1 B on A.NAME = B.NAME and B.IID = 2 where A.IID = 1 and (A.PHONE <> B.PHONE or B.NAME is null) union select A.NAME, A.PHONE, B.NAME, B.PHONE from t1 B left join t1 A on B.NAME = A.NAME and A.IID = 1 where B.IID = 2 and (A.PHONE <> B.PHONE or A.NAME is null); +SET optimizer_switch=@save_optimizer_switch; drop table t1; # diff --git a/mysql-test/suite/vcol/inc/vcol_view.inc b/mysql-test/suite/vcol/inc/vcol_view.inc index 64149a7bb31..abbeda60b75 100644 --- a/mysql-test/suite/vcol/inc/vcol_view.inc +++ b/mysql-test/suite/vcol/inc/vcol_view.inc @@ -106,6 +106,10 @@ drop view v1; # # outer join based on VIEW with WHERE clause # + +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; + create table t1 (a int, b int as (-a), c int as (-a) persistent, @@ -119,6 +123,8 @@ select t1.a, v1.x, v1.y, v1.z from t1 left join v1 on (t1.c= v1.z); drop view v1; drop table t1; +SET optimizer_switch=@save_optimizer_switch; + # # VIEW built over UNION # diff --git a/mysql-test/suite/vcol/r/vcol_view_innodb.result b/mysql-test/suite/vcol/r/vcol_view_innodb.result index 88681ca305f..94c311fb8b9 100644 --- a/mysql-test/suite/vcol/r/vcol_view_innodb.result +++ b/mysql-test/suite/vcol/r/vcol_view_innodb.result @@ -154,6 +154,8 @@ insert into v1 (a,e) values (60,15); ERROR HY000: The target table v1 of the INSERT is not insertable-into drop table t1; drop view v1; +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; create table t1 (a int, b int as (-a), c int as (-a) persistent, @@ -174,6 +176,7 @@ a x y z 3 3 -3 -3 drop view v1; drop table t1; +SET optimizer_switch=@save_optimizer_switch; create table t1 (a1 int, b1 int as (-a1), c1 int as (-a1) persistent); diff --git a/mysql-test/suite/vcol/r/vcol_view_myisam.result b/mysql-test/suite/vcol/r/vcol_view_myisam.result index 72e0bdb16a4..b96e003e1cc 100644 --- a/mysql-test/suite/vcol/r/vcol_view_myisam.result +++ b/mysql-test/suite/vcol/r/vcol_view_myisam.result @@ -154,6 +154,8 @@ insert into v1 (a,e) values (60,15); ERROR HY000: The target table v1 of the INSERT is not insertable-into drop table t1; drop view v1; +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; create table t1 (a int, b int as (-a), c int as (-a) persistent, @@ -174,6 +176,7 @@ a x y z 3 3 -3 -3 drop view v1; drop table t1; +SET optimizer_switch=@save_optimizer_switch; create table t1 (a1 int, b1 int as (-a1), c1 int as (-a1) persistent); diff --git a/mysql-test/t/derived_view.test b/mysql-test/t/derived_view.test index e35aca9b718..953a4c8fcef 100644 --- a/mysql-test/t/derived_view.test +++ b/mysql-test/t/derived_view.test @@ -925,6 +925,8 @@ INSERT INTO t2 VALUES (4,3,'r'); CREATE ALGORITHM=TEMPTABLE VIEW v1 AS SELECT * FROM t1; +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='semijoin_with_cache=off'; SET SESSION optimizer_switch='derived_with_keys=off'; EXPLAIN SELECT * FROM t3 @@ -942,6 +944,7 @@ SELECT * FROM t3 SELECT * FROM t3 WHERE t3.b IN (SELECT v1.b FROM v1, t2 WHERE t2.c = v1.c AND t2.c = v1.b AND v1.b = t3.c); +SET optimizer_switch=@save_optimizer_switch; DROP VIEW v1; DROP TABLE t1,t2,t3; @@ -1071,6 +1074,9 @@ INSERT INTO t2 VALUES (29,8,'c'), (39,7,'b'); CREATE TABLE t3 (b int); +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; + EXPLAIN EXTENDED SELECT t.b, t.c, t1.a FROM t1, (SELECT t2.b, t2.c FROM t3 RIGHT JOIN t2 ON t2.a = t3.b) AS t @@ -1105,6 +1111,8 @@ SELECT t.b, t.c, t1.a FROM t1, (SELECT t2.b, t2.c FROM t3 RIGHT JOIN t2 ON t2.a = t3.b) AS t WHERE t.b <> 0 AND t.c = t1.a; +SET optimizer_switch=@save_optimizer_switch; + DROP TABLE t1,t2,t3; --echo # @@ -1119,6 +1127,9 @@ INSERT INTO t2 VALUES (6); CREATE ALGORITHM=TEMPTABLE VIEW v2 AS SELECT * FROM t2; +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; + SET SESSION optimizer_switch = 'derived_with_keys=on'; SET SESSION join_cache_level = 4; @@ -1137,6 +1148,8 @@ SELECT * FROM t3 SET SESSION join_cache_level = default; +SET optimizer_switch=@save_optimizer_switch; + DROP VIEW v2; DROP TABLE t1,t2,t3; diff --git a/mysql-test/t/error_simulation.test b/mysql-test/t/error_simulation.test index 15d172cc7e6..5dcc1fa9dcf 100644 --- a/mysql-test/t/error_simulation.test +++ b/mysql-test/t/error_simulation.test @@ -78,6 +78,9 @@ INSERT INTO t2 VALUES (1, 1, 'data'); --echo # we would need to have thousands of records and/or more columns in both --echo # tables so that the join buffer is filled and re-scans are triggered). +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; + SET SESSION debug = '+d,only_one_Unique_may_be_created'; --replace_column 1 x 2 x 3 x 4 x 5 x 6 x 7 x 8 x 9 x @@ -87,6 +90,8 @@ SELECT * FROM t1 LEFT JOIN t2 ON ( t2.a < 10 OR t2.b < 10 ); SET SESSION debug = DEFAULT; +SET optimizer_switch=@save_optimizer_switch; + DROP TABLE t1, t2; diff --git a/mysql-test/t/explain.test b/mysql-test/t/explain.test index 6dbbdf5f28e..8700cd48c45 100644 --- a/mysql-test/t/explain.test +++ b/mysql-test/t/explain.test @@ -180,6 +180,8 @@ create table t2 (dt datetime not null); insert into t1 values ('2001-01-01 1:1:1', '1:1:1'), ('2001-01-01 1:1:1', '1:1:1'); insert into t2 values ('2001-01-01 1:1:1'), ('2001-01-01 1:1:1'); +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='semijoin_with_cache=off'; flush tables; EXPLAIN SELECT OUTR.dt FROM t1 AS OUTR WHERE OUTR.dt IN (SELECT INNR.dt FROM t2 AS INNR WHERE OUTR.dt IS NULL ); flush tables; @@ -188,6 +190,7 @@ flush tables; EXPLAIN SELECT OUTR.dt FROM t1 AS OUTR WHERE OUTR.dt IN ( SELECT INNR.dt FROM t2 AS INNR WHERE OUTR.t < '2005-11-13 7:41:31' ); flush tables; SELECT OUTR.dt FROM t1 AS OUTR WHERE OUTR.dt IN ( SELECT INNR.dt FROM t2 AS INNR WHERE OUTR.t < '2005-11-13 7:41:31' ); +SET optimizer_switch=@save_optimizer_switch; drop tables t1, t2; --echo # diff --git a/mysql-test/t/func_group.test b/mysql-test/t/func_group.test index 65b5b3936cc..de0eac10927 100644 --- a/mysql-test/t/func_group.test +++ b/mysql-test/t/func_group.test @@ -138,6 +138,8 @@ insert into t2 values('AAA', 10, 0.5); insert into t2 values('BBB', 20, 1.0); select t1.a1, t1.a2, t2.a1, t2.a2 from t1,t2; +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; select max(t1.a1), max(t2.a1) from t1, t2 where t2.a2=9; select max(t2.a1), max(t1.a1) from t1, t2 where t2.a2=9; select t1.a1, t1.a2, t2.a1, t2.a2 from t1 left outer join t2 on t1.a1=10; @@ -146,6 +148,7 @@ select max(t2.a1) from t2 left outer join t1 on t2.a2=10 where t2.a2=20; select max(t2.a1) from t2 left outer join t1 on t2.a2=10 where t2.a2=10; select max(t2.a1) from t1 left outer join t2 on t1.a2=t2.a1 and 1=0 where t2.a1='AAA'; select max(t1.a2),max(t2.a1) from t1 left outer join t2 on t1.a1=10; +SET optimizer_switch=@save_optimizer_switch; drop table t1,t2; # diff --git a/mysql-test/t/func_op.test b/mysql-test/t/func_op.test index 0a4f5034f4c..13fa40b513b 100644 --- a/mysql-test/t/func_op.test +++ b/mysql-test/t/func_op.test @@ -28,7 +28,10 @@ create table t1(a int); create table t2(a int, b int); insert into t1 values (1), (2), (3); insert into t2 values (1, 7), (3, 7); +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; select t1.a, t2.a, t2.b, bit_count(t2.b) from t1 left join t2 on t1.a=t2.a; +SET optimizer_switch=@save_optimizer_switch; drop table t1, t2; # End of 4.1 tests diff --git a/mysql-test/t/group_by.test b/mysql-test/t/group_by.test index ec64aaed18f..5d7421904d2 100644 --- a/mysql-test/t/group_by.test +++ b/mysql-test/t/group_by.test @@ -338,8 +338,11 @@ drop table t1,t2; CREATE TABLE t1 (ID1 int, ID2 int, ID int NOT NULL AUTO_INCREMENT,PRIMARY KEY(ID )); insert into t1 values (1,244,NULL),(2,243,NULL),(134,223,NULL),(185,186,NULL); +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; select S.ID as xID, S.ID1 as xID1 from t1 as S left join t1 as yS on S.ID1 between yS.ID1 and yS.ID2; select S.ID as xID, S.ID1 as xID1, repeat('*',count(distinct yS.ID)) as Level from t1 as S left join t1 as yS on S.ID1 between yS.ID1 and yS.ID2 group by xID order by xID1; +SET optimizer_switch=@save_optimizer_switch; drop table t1; # @@ -1031,16 +1034,22 @@ EXPLAIN SELECT a FROM t1 USE INDEX FOR JOIN (i2) USE INDEX FOR JOIN (i2,i2); +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='semijoin_with_cache=off'; EXPLAIN SELECT 1 FROM t1 WHERE a IN (SELECT a FROM t1 USE INDEX (i2) IGNORE INDEX (i2)); +SET optimizer_switch=@save_optimizer_switch; CREATE TABLE t2 (a INT, b INT, KEY(a)); INSERT INTO t2 VALUES (1, 1), (2, 2), (3,3), (4,4); EXPLAIN SELECT a, SUM(b) FROM t2 GROUP BY a LIMIT 2; EXPLAIN SELECT a, SUM(b) FROM t2 IGNORE INDEX (a) GROUP BY a LIMIT 2; +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='semijoin_with_cache=off'; EXPLAIN SELECT 1 FROM t2 WHERE a IN (SELECT a FROM t1 USE INDEX (i2) IGNORE INDEX (i2)); +SET optimizer_switch=@save_optimizer_switch; SHOW VARIABLES LIKE 'old'; --error ER_INCORRECT_GLOBAL_LOCAL_VAR diff --git a/mysql-test/t/group_min_max.test b/mysql-test/t/group_min_max.test index 391d997d8b6..c3fc1f4eab7 100644 --- a/mysql-test/t/group_min_max.test +++ b/mysql-test/t/group_min_max.test @@ -428,6 +428,8 @@ select a1,a2,b,c,min(c), max(c) from t1 where exists ( select * from t2 where t1.b > 'a' and t2.c > 'b1' ) group by a1,a2,b; +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='semijoin_with_cache=off'; explain select a1,a2,b,c,min(c), max(c) from t1 where exists ( select * from t2 where t2.c in (select c from t3 where t3.c > t1.b) and @@ -439,6 +441,7 @@ where exists ( select * from t2 where t2.c in (select c from t3 where t3.c > t1.b) and t2.c > 'b1' ) group by a1,a2,b; +SET optimizer_switch=@save_optimizer_switch; # correlated subselect that references the min/max argument explain select a1,a2,b,c,min(c), max(c) from t1 @@ -449,6 +452,8 @@ select a1,a2,b,c,min(c), max(c) from t1 where exists ( select * from t2 where t1.c > 'a' and t2.c > 'b1' ) group by a1,a2,b; +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='semijoin_with_cache=off'; explain select a1,a2,b,c,min(c), max(c) from t1 where exists ( select * from t2 where t2.c in (select c from t3 where t3.c > t1.c) and @@ -460,6 +465,7 @@ where exists ( select * from t2 where t2.c in (select c from t3 where t3.c > t1.c) and t2.c > 'b1' ) group by a1,a2,b; +SET optimizer_switch=@save_optimizer_switch; # A,B,C) Predicates referencing mixed classes of attributes diff --git a/mysql-test/t/join.test b/mysql-test/t/join.test index 82e67904e9f..bfe5f085e93 100644 --- a/mysql-test/t/join.test +++ b/mysql-test/t/join.test @@ -5,6 +5,9 @@ drop table if exists t1,t2,t3; drop view if exists v1,v2; --enable_warnings +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; + # # Test different join syntaxes # @@ -1025,3 +1028,4 @@ insert into t2 values ('1:1:1'); select t2.i from t1 left join t2 on t2.i = t1.i where t1.i = '1:1:1'; drop table t1,t2; +SET optimizer_switch=@save_optimizer_switch; diff --git a/mysql-test/t/join_nested.test b/mysql-test/t/join_nested.test index b617331de38..fa7b59e84c3 100644 --- a/mysql-test/t/join_nested.test +++ b/mysql-test/t/join_nested.test @@ -3,6 +3,9 @@ DROP TABLE IF EXISTS t0,t1,t2,t3,t4,t5,t6,t7,t8,t9; --enable_warnings +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch=ifnull(@optimizer_switch_for_join_nested_test,'outer_join_with_cache=off'); + CREATE TABLE t0 (a int, b int, c int); CREATE TABLE t1 (a int, b int, c int); CREATE TABLE t2 (a int, b int, c int); @@ -1271,5 +1274,7 @@ SELECT * FROM t1 LEFT JOIN DROP TABLE t1,t2,t3,t4; +SET optimizer_switch=@save_optimizer_switch; + --echo End of 5.0 tests diff --git a/mysql-test/t/join_nested_jcl6.test b/mysql-test/t/join_nested_jcl6.test index 809755b1fbf..f250702da7e 100644 --- a/mysql-test/t/join_nested_jcl6.test +++ b/mysql-test/t/join_nested_jcl6.test @@ -11,6 +11,8 @@ set @@optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; set join_cache_level=6; show variables like 'join_cache_level'; +set @optimizer_switch_for_join_nested_test=@@optimizer_switch; + --source t/join_nested.test # @@ -104,3 +106,4 @@ set join_cache_level=default; show variables like 'join_cache_level'; set @@optimizer_switch=@save_optimizer_switch_jcl6; +set @optimizer_switch_for_join_nested_test=NULL; diff --git a/mysql-test/t/join_outer.test b/mysql-test/t/join_outer.test index f88759c7b67..3bd5532ada0 100644 --- a/mysql-test/t/join_outer.test +++ b/mysql-test/t/join_outer.test @@ -8,6 +8,10 @@ drop table if exists t0,t1,t2,t3,t4,t5; --enable_warnings +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch=ifnull(@optimizer_switch_for_join_outer_test,'outer_join_with_cache=off'); + + CREATE TABLE t1 ( grp int(11) default NULL, a bigint(20) unsigned default NULL, @@ -1209,3 +1213,5 @@ DEALLOCATE PREPARE stmt; SET SESSION join_cache_level=default; DROP TABLE t1,t2,t3; + +SET optimizer_switch=@save_optimizer_switch; diff --git a/mysql-test/t/join_outer_jcl6.test b/mysql-test/t/join_outer_jcl6.test index 025e44493af..ba0a6686a51 100644 --- a/mysql-test/t/join_outer_jcl6.test +++ b/mysql-test/t/join_outer_jcl6.test @@ -11,9 +11,12 @@ set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; set join_cache_level=6; show variables like 'join_cache_level'; +set @optimizer_switch_for_join_outer_test=@@optimizer_switch; + --source t/join_outer.test set join_cache_level=default; show variables like 'join_cache_level'; set @@optimizer_switch=@save_optimizer_switch_jcl6; +set @optimizer_switch_for_join_outer_test=NULL; diff --git a/mysql-test/t/myisam_icp.test b/mysql-test/t/myisam_icp.test index bbff6c30e56..0e306a850c5 100644 --- a/mysql-test/t/myisam_icp.test +++ b/mysql-test/t/myisam_icp.test @@ -245,6 +245,9 @@ CREATE TABLE t4 ( b int, c varchar(1), KEY (b)); INSERT INTO t4 VALUES (7,'c'); INSERT INTO t4 VALUES (7,'c'); +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; + --echo # Must be t1,t2,t3,t4, with t4 having Full-scan-on-NULL but not Using index condition explain SELECT * FROM t1 LEFT JOIN t2 ON t1.c=t2.b @@ -255,6 +258,8 @@ SELECT * FROM t1 LEFT JOIN t2 ON t1.c=t2.b WHERE t2.b NOT IN (SELECT t4.b FROM t3 STRAIGHT_JOIN t4 WHERE t4.b <= 2 AND t4.c = t3.c); +SET optimizer_switch=@save_optimizer_switch; + DROP TABLE t1,t2,t3,t4; set optimizer_switch=@myisam_icp_tmp; diff --git a/mysql-test/t/order_by.test b/mysql-test/t/order_by.test index 0fc0d125c1a..c7a958b293a 100644 --- a/mysql-test/t/order_by.test +++ b/mysql-test/t/order_by.test @@ -157,6 +157,9 @@ INSERT INTO t2 VALUES (2,25); INSERT INTO t3 VALUES (1,'123 Park Place'); INSERT INTO t3 VALUES (2,'453 Boardwalk'); +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; + SELECT a,b,if(b = 1,i,if(b = 2,v,'')) FROM t1 LEFT JOIN t2 USING(c) @@ -179,6 +182,8 @@ LEFT JOIN t2 ON t1.c = t2.c LEFT JOIN t3 ON t3.c = t1.c ORDER BY a; +SET optimizer_switch=@save_optimizer_switch; + drop table t1,t2,t3; # diff --git a/mysql-test/t/pool_of_threads.test b/mysql-test/t/pool_of_threads.test index 530038cee91..5cde9a9fb4b 100644 --- a/mysql-test/t/pool_of_threads.test +++ b/mysql-test/t/pool_of_threads.test @@ -2,11 +2,13 @@ # and run a number of tests -- source include/have_pool_of_threads.inc +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; # Slow test, don't run during staging part -- source include/not_staging.inc -- source include/long_test.inc -- source include/common-tests.inc - +SET optimizer_switch=@save_optimizer_switch; # Test that we cannot have more simultaneous connections than # --thread-pool-size on the standard port, but _can_ have additional diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test index 357e7d4fe8f..a3b064acb04 100644 --- a/mysql-test/t/ps.test +++ b/mysql-test/t/ps.test @@ -3095,10 +3095,13 @@ DROP TABLE t1; --echo # CREATE TABLE t1(a INT); INSERT INTO t1 VALUES (1),(2); +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; PREPARE stmt FROM 'EXPLAIN EXTENDED SELECT 1 FROM t1 RIGHT JOIN t1 t2 ON 1'; EXECUTE stmt; EXECUTE stmt; DEALLOCATE PREPARE stmt; +SET optimizer_switch=@save_optimizer_switch; DROP TABLE t1; --echo # diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index 0106c3d54fb..9c037fa9106 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -13,6 +13,9 @@ drop table if exists t1_1,t1_2,t9_1,t9_2,t1aa,t2aa; drop view if exists v1; --enable_warnings +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch=ifnull(@optimizer_switch_for_select_test,'outer_join_with_cache=off'); + CREATE TABLE t1 ( Period smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, Varor_period smallint(4) unsigned DEFAULT '0' NOT NULL @@ -4259,3 +4262,5 @@ SELECT * FROM t1 WHERE f1 = 'zz' AND f1 <= 'aa' ; SELECT * FROM v1 HAVING f1 = 'zz' AND f1 <= 'aa' ; DROP TABLE t1; DROP VIEW v1; + +SET optimizer_switch=@save_optimizer_switch; diff --git a/mysql-test/t/select_jcl6.test b/mysql-test/t/select_jcl6.test index 295efa632db..29c86679515 100644 --- a/mysql-test/t/select_jcl6.test +++ b/mysql-test/t/select_jcl6.test @@ -11,9 +11,12 @@ set @@optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; set join_cache_level=6; show variables like 'join_cache_level'; +set @optimizer_switch_for_select_test=@@optimizer_switch; + --source t/select.test set join_cache_level=default; show variables like 'join_cache_level'; set @@optimizer_switch=@save_optimizer_switch_jcl6; +set @optimizer_switch_for_select_test=NULL; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 4f6999bf611..13bbc01af17 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -4587,6 +4587,9 @@ INSERT INTO t2 VALUES (20,9),(20,9); create table t3 (d int, e int); insert into t3 values (2, 9), (3,10); +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; + EXPLAIN SELECT t2.b , t1.c FROM t2 LEFT JOIN t1 ON t1.c < 3 @@ -4596,6 +4599,8 @@ SELECT t2.b , t1.c FROM t2 LEFT JOIN t1 ON t1.c < 3 WHERE (t2.b, t1.c) NOT IN (SELECT * from t3); +SET optimizer_switch=@save_optimizer_switch; + drop table t1, t2, t3; --echo End of 5.3 tests diff --git a/mysql-test/t/subselect4.test b/mysql-test/t/subselect4.test index 0fd89bee42b..aa3cb30c6f3 100644 --- a/mysql-test/t/subselect4.test +++ b/mysql-test/t/subselect4.test @@ -991,6 +991,9 @@ INSERT INTO t3 VALUES ('a'), ('b'), ('c'); CREATE TABLE t4 (c1 varchar(1) primary key); INSERT INTO t4 VALUES ('k'), ('d'); +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; + EXPLAIN SELECT * FROM t1 RIGHT JOIN t2 ON t1.c1 WHERE 's' IN (SELECT c1 FROM t2); SELECT * FROM t1 RIGHT JOIN t2 ON t1.c1 WHERE 's' IN (SELECT c1 FROM t2); @@ -1003,6 +1006,9 @@ SELECT * FROM (t2 LEFT JOIN t1 ON t1.c1) LEFT JOIN t3 on t3.c1 WHERE 's' IN (SEL EXPLAIN SELECT * FROM t4 LEFT JOIN t2 ON t4.c1 WHERE 's' IN (SELECT c1 FROM t2); SELECT * FROM t4 LEFT JOIN t2 ON t4.c1 WHERE 's' IN (SELECT c1 FROM t2); + +SET optimizer_switch=@save_optimizer_switch; + drop table t1, t2, t3, t4; --echo # @@ -1297,6 +1303,8 @@ INSERT INTO t2 VALUES (10,5,'d1d'); set @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; + set @@optimizer_switch = 'materialization=off'; EXPLAIN diff --git a/mysql-test/t/subselect_cache.test b/mysql-test/t/subselect_cache.test index 6bf5028b6cf..0abd20cc50e 100644 --- a/mysql-test/t/subselect_cache.test +++ b/mysql-test/t/subselect_cache.test @@ -4,6 +4,9 @@ drop table if exists t1,t2,t3,t4,t5; drop view if exists v1; --enable_warnings +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; +SET optimizer_switch='semijoin_with_cache=off'; set optimizer_switch='subquery_cache=on'; @@ -1698,5 +1701,7 @@ SELECT * FROM t4 WHERE b NOT IN ( SELECT * FROM v1 ); drop view v1; drop table t1,t2,t3,t4; +SET optimizer_switch=@save_optimizer_switch; + --echo # restore default set @@optimizer_switch= default; diff --git a/mysql-test/t/subselect_sj.test b/mysql-test/t/subselect_sj.test index 4f8ed7f1643..3b419dc0d09 100644 --- a/mysql-test/t/subselect_sj.test +++ b/mysql-test/t/subselect_sj.test @@ -10,6 +10,9 @@ drop procedure if exists p1; set @subselect_sj_tmp= @@optimizer_switch; set optimizer_switch='semijoin=on,firstmatch=on,loosescan=on'; set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; +SET optimizer_switch=ifnull(@optimizer_switch_for_subselect_sj_test,'outer_join_with_cache=off'); +SET optimizer_switch=ifnull(@optimizer_switch_for_subselect_sj_test,'semijoin_with_cache=off'); + # The 'default' value within the scope of this test: set @save_optimizer_switch=@@optimizer_switch; diff --git a/mysql-test/t/subselect_sj2.test b/mysql-test/t/subselect_sj2.test index 2ec15d4dfae..5229546c08e 100644 --- a/mysql-test/t/subselect_sj2.test +++ b/mysql-test/t/subselect_sj2.test @@ -6,6 +6,9 @@ set @subselect_sj2_tmp= @@optimizer_switch; set optimizer_switch='semijoin=on,firstmatch=on,loosescan=on'; set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; +SET optimizer_switch=ifnull(@optimizer_switch_for_subselect_sj2_test,'outer_join_with_cache=off'); +SET optimizer_switch=ifnull(@optimizer_switch_for_subselect_sj2_test,'semijoin_with_cache=off'); + --disable_warnings drop table if exists t0, t1, t2, t3, t4, t5; drop view if exists v1; @@ -46,7 +49,6 @@ create table t3 ( insert into t3 select a,a, a,a,a from t0; insert into t3 select a,a, a+100,a+100,a+100 from t0; - explain select * from t3 where b in (select a from t1); select * from t3 where b in (select a from t1); diff --git a/mysql-test/t/subselect_sj2_jcl6.test b/mysql-test/t/subselect_sj2_jcl6.test index 95f84a9e89e..0b20c39c183 100644 --- a/mysql-test/t/subselect_sj2_jcl6.test +++ b/mysql-test/t/subselect_sj2_jcl6.test @@ -11,6 +11,8 @@ set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; set join_cache_level=6; show variables like 'join_cache_level'; +set @optimizer_switch_for_subselect_sj2_test=@@optimizer_switch; + --source t/subselect_sj2.test --echo # @@ -101,4 +103,5 @@ set join_cache_level=default; show variables like 'join_cache_level'; set @@optimizer_switch=@save_optimizer_switch_jcl6; +set @optimizer_switch_for_subselect_sj2_test=NULL; diff --git a/mysql-test/t/subselect_sj_jcl6.test b/mysql-test/t/subselect_sj_jcl6.test index fc539ec1a01..bfb867830c4 100644 --- a/mysql-test/t/subselect_sj_jcl6.test +++ b/mysql-test/t/subselect_sj_jcl6.test @@ -13,6 +13,8 @@ set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; set join_cache_level=6; show variables like 'join_cache_level'; +set @optimizer_switch_for_subselect_sj_test=@@optimizer_switch; + --source t/subselect_sj.test --echo # @@ -91,3 +93,4 @@ set join_cache_level=default; show variables like 'join_cache_level'; set @@optimizer_switch=@save_optimizer_switch_jcl6; +set @optimizer_switch_for_subselect_sj_test=NULL; diff --git a/mysql-test/t/subselect_sj_nonmerged.test b/mysql-test/t/subselect_sj_nonmerged.test index 4f50b4cbc4d..e47e72ffe97 100644 --- a/mysql-test/t/subselect_sj_nonmerged.test +++ b/mysql-test/t/subselect_sj_nonmerged.test @@ -55,13 +55,19 @@ explain select * from t3 where a in (select max(t2.a) from t1, t2 group by t2.b) --echo # Compare to this which really will have 50 record combinations: explain select * from t3 where a in (select max(t2.a) from t1, t2 group by t2.b, t1.b); +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; + --echo # Outer joins also work: explain select * from t3 where a in (select max(t2.a) from t1 left join t2 on t1.a=t2.a group by t2.b, t1.b); +SET optimizer_switch=@save_optimizer_switch; + # # Check if joins on the outer side also work # + create table t4 (a int, b int, filler char(20), unique key(a,b)); insert into t4 select A.a + 10*B.a, A.a + 10*B.a, 'filler' from t0 A, t0 B; # 100 rows explain select * from t0, t4 where diff --git a/mysql-test/t/table_elim.test b/mysql-test/t/table_elim.test index 3b584ce2b38..dc32618eb8c 100644 --- a/mysql-test/t/table_elim.test +++ b/mysql-test/t/table_elim.test @@ -6,6 +6,9 @@ drop table if exists t0, t1, t2, t3, t4, t5, t6; drop view if exists v1, v2; --enable_warnings +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; + create table t1 (a int); insert into t1 values (0),(1),(2),(3); create table t0 as select * from t1; @@ -518,3 +521,4 @@ EXPLAIN SELECT alias1.* FROM t3 LEFT JOIN v1 as alias1 ON ( t3.a = alias1.b ); drop view v1; DROP TABLE t1,t2,t3; +SET optimizer_switch=@save_optimizer_switch; diff --git a/mysql-test/t/type_datetime.test b/mysql-test/t/type_datetime.test index 4e091e14b30..f9ee8dfd5d3 100644 --- a/mysql-test/t/type_datetime.test +++ b/mysql-test/t/type_datetime.test @@ -359,6 +359,9 @@ create table t2 (id int(10) not null, cur_date date not null); insert into t1 (id, cur_date) values (1, '2007-04-25 18:30:22'); insert into t2 (id, cur_date) values (1, '2007-04-25'); +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='semijoin_with_cache=off'; + explain extended select * from t1 where id in (select id from t1 as x1 where (t1.cur_date is null)); @@ -386,6 +389,8 @@ where id in (select id from t2 as x1 where (t2.cur_date is null)); select * from t2 where id in (select id from t2 as x1 where (t2.cur_date is null)); +SET optimizer_switch=@save_optimizer_switch; + drop table t1,t2; diff --git a/mysql-test/t/union.test b/mysql-test/t/union.test index 507f0ffa09f..d3bc94961ef 100644 --- a/mysql-test/t/union.test +++ b/mysql-test/t/union.test @@ -563,7 +563,10 @@ drop table t1; # create table t1 ( RID int(11) not null default '0', IID int(11) not null default '0', nada varchar(50) not null,NAME varchar(50) not null,PHONE varchar(50) not null) engine=MyISAM; insert into t1 ( RID,IID,nada,NAME,PHONE) values (1, 1, 'main', 'a', '111'), (2, 1, 'main', 'b', '222'), (3, 1, 'main', 'c', '333'), (4, 1, 'main', 'd', '444'), (5, 1, 'main', 'e', '555'), (6, 2, 'main', 'c', '333'), (7, 2, 'main', 'd', '454'), (8, 2, 'main', 'e', '555'), (9, 2, 'main', 'f', '666'), (10, 2, 'main', 'g', '777'); +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; select A.NAME, A.PHONE, B.NAME, B.PHONE from t1 A left join t1 B on A.NAME = B.NAME and B.IID = 2 where A.IID = 1 and (A.PHONE <> B.PHONE or B.NAME is null) union select A.NAME, A.PHONE, B.NAME, B.PHONE from t1 B left join t1 A on B.NAME = A.NAME and A.IID = 1 where B.IID = 2 and (A.PHONE <> B.PHONE or A.NAME is null); +SET optimizer_switch=@save_optimizer_switch; drop table t1; # diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 7486ffc38f8..821bbe055e6 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -5,6 +5,9 @@ drop database if exists mysqltest; --enable_warnings use test; +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; + # # some basic test of views and its functionality # @@ -4308,3 +4311,5 @@ 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; + +SET optimizer_switch=@save_optimizer_switch; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index d263c8aba4f..fbd0d8549f7 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -607,10 +607,12 @@ protected: OPTIMIZER_SWITCH_MATERIALIZATION | \ OPTIMIZER_SWITCH_PARTIAL_MATCH_ROWID_MERGE|\ OPTIMIZER_SWITCH_PARTIAL_MATCH_TABLE_SCAN|\ + OPTIMIZER_SWITCH_OUTER_JOIN_WITH_CACHE | \ + OPTIMIZER_SWITCH_SEMIJOIN_WITH_CACHE | \ OPTIMIZER_SWITCH_JOIN_CACHE_INCREMENTAL | \ OPTIMIZER_SWITCH_JOIN_CACHE_HASHED | \ OPTIMIZER_SWITCH_JOIN_CACHE_BKA | \ - OPTIMIZER_SWITCH_SUBQUERY_CACHE |\ + OPTIMIZER_SWITCH_SUBQUERY_CACHE | \ OPTIMIZER_SWITCH_SEMIJOIN | \ OPTIMIZER_SWITCH_FIRSTMATCH | \ OPTIMIZER_SWITCH_LOOSE_SCAN ) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 0767ca561df..606af24e0db 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -500,8 +500,8 @@ static const char *optimizer_switch_str="index_merge=on,index_merge_union=on," "mrr=off," "mrr_cost_based=off," "mrr_sort_keys=off," - "outer_join_with_cache=off," - "semijoin_with_cache=off," + "outer_join_with_cache=on," + "semijoin_with_cache=on," "join_cache_incremental=on," "join_cache_hashed=on," "join_cache_bka=on," From b507df6145978e649f332da6358b5a61f8d6e141 Mon Sep 17 00:00:00 2001 From: Tor Didriksen Date: Thu, 15 Dec 2011 10:44:33 +0100 Subject: [PATCH 212/288] Bug#13463417 63487: ANNOYING TRACE MESSAGE IN CMAKE CODE Remove it. --- cmake/install_macros.cmake | 1 - 1 file changed, 1 deletion(-) diff --git a/cmake/install_macros.cmake b/cmake/install_macros.cmake index a8a84e48455..3b732bfa3ba 100644 --- a/cmake/install_macros.cmake +++ b/cmake/install_macros.cmake @@ -78,7 +78,6 @@ FUNCTION(INSTALL_MANPAGE file) ELSE() SET(SECTION man8) ENDIF() - MESSAGE("huj!") INSTALL(FILES "${MANPAGE}" DESTINATION "${INSTALL_MANDIR}/${SECTION}" COMPONENT ManPages) ENDIF() From 7615cb0890da8e33636af88511404b1822254d3f Mon Sep 17 00:00:00 2001 From: Chaithra Gopalareddy Date: Thu, 15 Dec 2011 16:48:40 +0530 Subject: [PATCH 213/288] Bug#13344643:Format function in view looses locale information Problem description: When a view is created using function FORMAT and if FORMAT function uses locale option,definition of view saved into server doesn't contain that locale information, Ex: create table test2 (bb decimal (10,2)); insert into test2 values (10.32),(10009.2),(12345678.21); create view test3 as select format(bb,1,'sk_SK') as cc from test2; select * from test3; +--------------+ | cc | +--------------+ | 10.3 | | 10,009.2 | | 12,345,678.2 | +--------------+ 3 rows in set (0.02 sec) show create view test3 View: test3 Create View: CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `test3` AS select format(`test2`.`bb`,1) AS `cc` from `test2` character_set_client: latin1 collation_connection: latin1_swedish_ci 1 row in set (0.02 sec) Problem Analysis: The function Item_func_format::print() which prints the query string to create the view does not print the third argument (i.e the locale information). Hence view is created without locale information. Problem Solution: If argument count is more than 2 we now print the third argument onto the query string. Files changed: sql/item_strfunc.cc Function call changes: Item_func_format::print() mysql-test/t/select.test Added test case to test the bug mysql-test/r/select.result Result of the test case appended here --- mysql-test/r/select.result | 18 ++++++++++++++++++ mysql-test/t/select.test | 17 +++++++++++++++++ sql/item_strfunc.cc | 5 +++++ 3 files changed, 40 insertions(+) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index af0ef29bb53..57f650f4c56 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -4970,3 +4970,21 @@ avg(distinct(t1.a)) 0 DROP TABLE t1; # End of test BUG#57203 +# +# Bug#63020: Function "format"'s 'locale' argument is not considered +# when creating a "view' +# +CREATE TABLE t1 (f1 DECIMAL(10,2)); +INSERT INTO t1 VALUES (11.67),(17865.3),(12345678.92); +CREATE VIEW view_t1 AS SELECT FORMAT(f1,1,'sk_SK') AS f1 FROM t1; +SHOW CREATE VIEW view_t1; +View Create View character_set_client collation_connection +view_t1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `view_t1` AS select format(`t1`.`f1`,1,'sk_SK') AS `f1` from `t1` latin1 latin1_swedish_ci +SELECT * FROM view_t1; +f1 +11,7 +17 865,3 +12 345 678,9 +DROP TABLE t1; +DROP VIEW view_t1; +# End of test BUG#63020 diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index 043b03e4686..d9e9c27650f 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -4236,3 +4236,20 @@ GROUP BY t2.a ORDER BY t1.a; DROP TABLE t1; --echo # End of test BUG#57203 + +--echo # +--echo # Bug#63020: Function "format"'s 'locale' argument is not considered +--echo # when creating a "view' +--echo # + +CREATE TABLE t1 (f1 DECIMAL(10,2)); +INSERT INTO t1 VALUES (11.67),(17865.3),(12345678.92); +CREATE VIEW view_t1 AS SELECT FORMAT(f1,1,'sk_SK') AS f1 FROM t1; +SHOW CREATE VIEW view_t1; +SELECT * FROM view_t1; + +DROP TABLE t1; +DROP VIEW view_t1; + +--echo # End of test BUG#63020 + diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index a0fdb3cf811..86082f3d893 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -2385,6 +2385,11 @@ void Item_func_format::print(String *str, enum_query_type query_type) args[0]->print(str, query_type); str->append(','); args[1]->print(str, query_type); + if(arg_count > 2) + { + str->append(','); + args[2]->print(str,query_type); + } str->append(')'); } From 7a99121b2cd93f60845a4c3db54dbb5c215a24b6 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Thu, 15 Dec 2011 16:43:28 +0400 Subject: [PATCH 214/288] Fix trivial merge error --- sql/set_var.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sql/set_var.cc b/sql/set_var.cc index 028339319af..e6c1bf94135 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -650,7 +650,8 @@ static sys_var_thd_enum sys_query_cache_type(&vars, "query_cache_type", static sys_var_thd_bool sys_query_cache_wlock_invalidate(&vars, "query_cache_wlock_invalidate", &SV::query_cache_wlock_invalidate); -static sys_var_bool_ptr sys_query_cache_strip_comments(&vars, "query_cache_strip_comments", &opt_query_cache_strip_comments); +static sys_var_bool_ptr sys_query_cache_strip_comments(&vars, "query_cache_strip_comments", + &opt_query_cache_strip_comments); #endif /* HAVE_QUERY_CACHE */ static sys_var_bool_ptr sys_secure_auth(&vars, "secure_auth", &opt_secure_auth); static sys_var_const_str_ptr sys_secure_file_priv(&vars, "secure_file_priv", @@ -940,8 +941,6 @@ static sys_var_const_str sys_hostname(&vars, "hostname", glob_hostname); static sys_var_const_str_ptr sys_log_basename(&vars, "log_basename", &opt_log_basename); -static sys_var_bool_ptr sys_query_cache_strip_comments(&vars, "query_cache_strip_comments", - &opt_query_cache_strip_comments); #ifndef EMBEDDED_LIBRARY static sys_var_const_str_ptr sys_repl_report_host(&vars, "report_host", &report_host); static sys_var_const_str_ptr sys_repl_report_user(&vars, "report_user", &report_user); From 876f16afbb038992bc984960821d8bb8a830cc6f Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Thu, 15 Dec 2011 17:26:32 +0400 Subject: [PATCH 215/288] Fix unused variable 'thd' error. --- 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 695fc93c9aa..92b2a965706 100644 --- a/storage/maria/ha_maria.cc +++ b/storage/maria/ha_maria.cc @@ -2561,8 +2561,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 a910e8ef5b5d33cd600acaba9ec3cc8c49881196 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Thu, 15 Dec 2011 14:26:59 -0800 Subject: [PATCH 216/288] Made join_cache_level == 2 by default. --- mysql-test/r/derived_view.result | 3 +++ mysql-test/r/distinct.result | 3 +++ mysql-test/r/greedy_optimizer.result | 3 +++ mysql-test/r/join_cache.result | 8 +++++--- mysql-test/r/join_nested.result | 1 + mysql-test/r/join_nested_jcl6.result | 5 ++++- mysql-test/r/join_outer.result | 1 + mysql-test/r/join_outer_jcl6.result | 5 ++++- mysql-test/r/maria_mrr.result | 3 +++ mysql-test/r/select.result | 1 + mysql-test/r/select_jcl6.result | 5 ++++- mysql-test/r/select_pkeycache.result | 1 + mysql-test/r/subselect.result | 1 + mysql-test/r/subselect3.result | 1 + mysql-test/r/subselect3_jcl6.result | 5 ++++- mysql-test/r/subselect_mat.result | 3 +++ mysql-test/r/subselect_no_mat.result | 4 ++++ mysql-test/r/subselect_no_opts.result | 3 +++ mysql-test/r/subselect_no_scache.result | 4 ++++ mysql-test/r/subselect_no_semijoin.result | 4 ++++ mysql-test/r/subselect_sj.result | 1 + mysql-test/r/subselect_sj2.result | 1 + mysql-test/r/subselect_sj2_jcl6.result | 5 ++++- mysql-test/r/subselect_sj2_mat.result | 1 + mysql-test/r/subselect_sj_jcl6.result | 5 ++++- mysql-test/r/subselect_sj_mat.result | 3 +++ mysql-test/suite/pbxt/r/distinct.result | 3 +++ mysql-test/suite/pbxt/r/greedy_optimizer.result | 3 +++ mysql-test/suite/pbxt/t/distinct.test | 6 ++++++ mysql-test/suite/pbxt/t/greedy_optimizer.test | 5 +++++ mysql-test/t/derived_view.test | 3 +++ mysql-test/t/distinct.test | 6 ++++++ mysql-test/t/greedy_optimizer.test | 5 +++++ mysql-test/t/join_cache.test | 6 +++++- mysql-test/t/join_nested.test | 9 +++++++++ mysql-test/t/join_nested_jcl6.test | 2 ++ mysql-test/t/join_outer.test | 9 ++++++++- mysql-test/t/join_outer_jcl6.test | 2 ++ mysql-test/t/maria_mrr.test | 5 +++++ mysql-test/t/select.test | 8 ++++++++ mysql-test/t/select_jcl6.test | 2 ++ mysql-test/t/subselect.test | 11 ++++++++++- mysql-test/t/subselect3.test | 8 ++++++++ mysql-test/t/subselect3_jcl6.test | 3 +++ mysql-test/t/subselect_no_mat.test | 5 +++++ mysql-test/t/subselect_no_opts.test | 4 ++++ mysql-test/t/subselect_no_scache.test | 4 ++++ mysql-test/t/subselect_no_semijoin.test | 4 ++++ mysql-test/t/subselect_sj.test | 8 ++++++++ mysql-test/t/subselect_sj2.test | 8 ++++++++ mysql-test/t/subselect_sj2_jcl6.test | 2 ++ mysql-test/t/subselect_sj_jcl6.test | 2 ++ mysql-test/t/subselect_sj_mat.test | 3 +++ sql/mysqld.cc | 2 +- 54 files changed, 205 insertions(+), 13 deletions(-) diff --git a/mysql-test/r/derived_view.result b/mysql-test/r/derived_view.result index 5281dd4bae4..a109aa3198b 100644 --- a/mysql-test/r/derived_view.result +++ b/mysql-test/r/derived_view.result @@ -1,8 +1,10 @@ drop table if exists t1,t2; drop view if exists v1,v2,v3,v4; set @exit_optimizer_switch=@@optimizer_switch; +set @exit_join_cache_level=@@join_cache_level; set optimizer_switch='derived_merge=on,derived_with_keys=on'; set @save_optimizer_switch=@@optimizer_switch; +set join_cache_level=1; create table t1(f1 int, f11 int); create table t2(f2 int, f22 int); insert into t1 values(1,1),(2,2),(3,3),(5,5),(9,9),(7,7); @@ -1871,3 +1873,4 @@ col_varchar_key pk col_varchar_key col_varchar_nokey set max_heap_table_size= @tmp_882994; drop table t1,t2,t3; set optimizer_switch=@exit_optimizer_switch; +set join_cache_level=@exit_join_cache_level; diff --git a/mysql-test/r/distinct.result b/mysql-test/r/distinct.result index eafd16440b0..99d98d2a9bc 100644 --- a/mysql-test/r/distinct.result +++ b/mysql-test/r/distinct.result @@ -280,6 +280,8 @@ unique (id, idx) insert into t1 values (1,'yes'), (2,'no'); insert into t2 values (1,1); insert into t3 values (1,1); +set @save_join_cache_level=@@join_cache_level; +set join_cache_level=1; EXPLAIN SELECT DISTINCT t1.id @@ -326,6 +328,7 @@ AND ((t1.id=j_lj_t3.id AND t3_lj.id IS NULL) OR (t1.id=t3.id AND t3.idx=2)); id 2 drop table t1,t2,t3; +set join_cache_level=@save_join_cache_level; create table t1 (a int not null, b int not null, t time); insert into t1 values (1,1,"00:06:15"),(1,2,"00:06:15"),(1,2,"00:30:15"),(1,3,"00:06:15"),(1,3,"00:30:15"); select a,sec_to_time(sum(time_to_sec(t))) from t1 group by a,b; diff --git a/mysql-test/r/greedy_optimizer.result b/mysql-test/r/greedy_optimizer.result index b4844785318..b4c3f4ec9e0 100644 --- a/mysql-test/r/greedy_optimizer.result +++ b/mysql-test/r/greedy_optimizer.result @@ -1,4 +1,6 @@ drop table if exists t1,t2,t3,t4,t5,t6,t7; +set @save_join_cache_level=@@join_cache_level; +set join_cache_level=1; create table t1 ( c11 integer,c12 integer,c13 integer,c14 integer,c15 integer,c16 integer, primary key (c11) @@ -732,3 +734,4 @@ t4 LEFT JOIN (t5 JOIN t5_1 ON t5.l = t5_1.l) ON t5.d = t4.d SET optimizer_search_depth = DEFAULT; DROP TABLE t1,t2,t2_1,t3,t3_1,t4,t4_1,t5,t5_1; End of 5.0 tests +set join_cache_level=@save_join_cache_level; diff --git a/mysql-test/r/join_cache.result b/mysql-test/r/join_cache.result index f2fda746e5e..f4c995ab1ac 100644 --- a/mysql-test/r/join_cache.result +++ b/mysql-test/r/join_cache.result @@ -40,6 +40,7 @@ COUNT(*) show variables like 'join_buffer_size'; Variable_name Value join_buffer_size 131072 +set join_cache_level=1; show variables like 'join_cache_level'; Variable_name Value join_cache_level 1 @@ -453,7 +454,7 @@ Côte d?Ivoire 14786000 NULL NULL Czech Republic 10278100 NULL NULL DROP INDEX City_Population ON City; DROP INDEX City_Name ON City; -set join_cache_level=default; +set join_cache_level=1; set join_buffer_size=256; show variables like 'join_buffer_size'; Variable_name Value @@ -776,7 +777,7 @@ Variable_name Value join_buffer_size 131072 show variables like 'join_cache_level'; Variable_name Value -join_cache_level 1 +join_cache_level 2 DROP DATABASE world; CREATE DATABASE world; use world; @@ -2690,7 +2691,7 @@ Variable_name Value join_buffer_size 131072 show variables like 'join_cache_level'; Variable_name Value -join_cache_level 1 +join_cache_level 2 set join_cache_level=1; SELECT City.Name, Country.Name FROM City,Country WHERE City.Country=Country.Code AND City.Population > 3000000; @@ -3875,6 +3876,7 @@ create table t2 (a int, b int); insert into t2 values (1,1),(2,2); create table t3 (a int, b int); insert into t3 values (1,1),(2,2); +set join_cache_level=1; explain select t1.* from t1,t2,t3; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 diff --git a/mysql-test/r/join_nested.result b/mysql-test/r/join_nested.result index 87f0478f284..dfb1a8c72d3 100644 --- a/mysql-test/r/join_nested.result +++ b/mysql-test/r/join_nested.result @@ -1,6 +1,7 @@ DROP TABLE IF EXISTS t0,t1,t2,t3,t4,t5,t6,t7,t8,t9; SET @save_optimizer_switch=@@optimizer_switch; SET optimizer_switch=ifnull(@optimizer_switch_for_join_nested_test,'outer_join_with_cache=off'); +set join_cache_level=1; CREATE TABLE t0 (a int, b int, c int); CREATE TABLE t1 (a int, b int, c int); CREATE TABLE t2 (a int, b int, c int); diff --git a/mysql-test/r/join_nested_jcl6.result b/mysql-test/r/join_nested_jcl6.result index 53107b1941f..69eb4532c73 100644 --- a/mysql-test/r/join_nested_jcl6.result +++ b/mysql-test/r/join_nested_jcl6.result @@ -8,9 +8,11 @@ show variables like 'join_cache_level'; Variable_name Value join_cache_level 6 set @optimizer_switch_for_join_nested_test=@@optimizer_switch; +set @join_cache_level_for_join_nested_test=@@join_cache_level; DROP TABLE IF EXISTS t0,t1,t2,t3,t4,t5,t6,t7,t8,t9; SET @save_optimizer_switch=@@optimizer_switch; SET optimizer_switch=ifnull(@optimizer_switch_for_join_nested_test,'outer_join_with_cache=off'); +set join_cache_level=@join_cache_level_for_join_nested_test; CREATE TABLE t0 (a int, b int, c int); CREATE TABLE t1 (a int, b int, c int); CREATE TABLE t2 (a int, b int, c int); @@ -1964,6 +1966,7 @@ DROP TABLE t5,t6,t7,t8; set join_cache_level=default; show variables like 'join_cache_level'; Variable_name Value -join_cache_level 1 +join_cache_level 2 set @@optimizer_switch=@save_optimizer_switch_jcl6; set @optimizer_switch_for_join_nested_test=NULL; +set @join_cache_level_for_join_nested_test=NULL; diff --git a/mysql-test/r/join_outer.result b/mysql-test/r/join_outer.result index 02ad3a1a16a..9e84010d5ce 100644 --- a/mysql-test/r/join_outer.result +++ b/mysql-test/r/join_outer.result @@ -1,6 +1,7 @@ drop table if exists t0,t1,t2,t3,t4,t5; SET @save_optimizer_switch=@@optimizer_switch; SET optimizer_switch=ifnull(@optimizer_switch_for_join_outer_test,'outer_join_with_cache=off'); +set join_cache_level=1; CREATE TABLE t1 ( grp int(11) default NULL, a bigint(20) unsigned default NULL, diff --git a/mysql-test/r/join_outer_jcl6.result b/mysql-test/r/join_outer_jcl6.result index ec6e773fbae..ab9e437c6bf 100644 --- a/mysql-test/r/join_outer_jcl6.result +++ b/mysql-test/r/join_outer_jcl6.result @@ -8,9 +8,11 @@ show variables like 'join_cache_level'; Variable_name Value join_cache_level 6 set @optimizer_switch_for_join_outer_test=@@optimizer_switch; +set @join_cache_level_for_join_outer_test=@@join_cache_level; drop table if exists t0,t1,t2,t3,t4,t5; SET @save_optimizer_switch=@@optimizer_switch; SET optimizer_switch=ifnull(@optimizer_switch_for_join_outer_test,'outer_join_with_cache=off'); +set join_cache_level=@join_cache_level_for_join_outer_test; CREATE TABLE t1 ( grp int(11) default NULL, a bigint(20) unsigned default NULL, @@ -1666,6 +1668,7 @@ SET optimizer_switch=@save_optimizer_switch; set join_cache_level=default; show variables like 'join_cache_level'; Variable_name Value -join_cache_level 1 +join_cache_level 2 set @@optimizer_switch=@save_optimizer_switch_jcl6; set @optimizer_switch_for_join_outer_test=NULL; +set @join_cache_level_for_join_outer_test=NULL; diff --git a/mysql-test/r/maria_mrr.result b/mysql-test/r/maria_mrr.result index 652bea93e7a..b3f5ada833d 100644 --- a/mysql-test/r/maria_mrr.result +++ b/mysql-test/r/maria_mrr.result @@ -347,6 +347,8 @@ INSERT INTO t3 SELECT * FROM t1; INSERT INTO t3 VALUES (88, 442, 'y'), (99, 445, 'w'), (87, 442, 'z'), (98, 445, 'v'), (86, 442, 'x'), (97, 445, 't'), (85, 442, 'b'), (96, 445, 'l'), (84, 442, 'a'), (95, 445, 'k'); +set @save_join_cache_level=@@join_cache_level; +set join_cache_level=1; SELECT COUNT(t1.v) FROM t1, t2 IGNORE INDEX (idx), t3 IGNORE INDEX (idx) WHERE t3.v = t2.v AND t3.i < t2.i AND t3.pk > 0 AND t2.pk > 0; COUNT(t1.v) @@ -369,6 +371,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 index NULL idx 7 NULL 15 Using index 1 SIMPLE t2 ALL PRIMARY,idx NULL NULL NULL 16 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t3 ref PRIMARY,idx idx 3 test.t2.v 2 Using index condition; Using where +set join_cache_level=@save_join_cache_level; DROP TABLE t1,t2,t3; # # BUG#671361: virtual int Mrr_ordered_index_reader::refill_buffer(): Assertion `!know_key_tuple_params diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index a3647c10350..29a6bb4bf35 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -3,6 +3,7 @@ drop table if exists t1_1,t1_2,t9_1,t9_2,t1aa,t2aa; drop view if exists v1; SET @save_optimizer_switch=@@optimizer_switch; SET optimizer_switch=ifnull(@optimizer_switch_for_select_test,'outer_join_with_cache=off'); +set join_cache_level=1; CREATE TABLE t1 ( Period smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, Varor_period smallint(4) unsigned DEFAULT '0' NOT NULL diff --git a/mysql-test/r/select_jcl6.result b/mysql-test/r/select_jcl6.result index f5104ce254d..fd23d6cc2d6 100644 --- a/mysql-test/r/select_jcl6.result +++ b/mysql-test/r/select_jcl6.result @@ -8,11 +8,13 @@ show variables like 'join_cache_level'; Variable_name Value join_cache_level 6 set @optimizer_switch_for_select_test=@@optimizer_switch; +set @join_cache_level_for_select_test=@@join_cache_level; drop table if exists t1,t2,t3,t4,t11; drop table if exists t1_1,t1_2,t9_1,t9_2,t1aa,t2aa; drop view if exists v1; SET @save_optimizer_switch=@@optimizer_switch; SET optimizer_switch=ifnull(@optimizer_switch_for_select_test,'outer_join_with_cache=off'); +set join_cache_level=@join_cache_level_for_select_test; CREATE TABLE t1 ( Period smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, Varor_period smallint(4) unsigned DEFAULT '0' NOT NULL @@ -5112,6 +5114,7 @@ SET optimizer_switch=@save_optimizer_switch; set join_cache_level=default; show variables like 'join_cache_level'; Variable_name Value -join_cache_level 1 +join_cache_level 2 set @@optimizer_switch=@save_optimizer_switch_jcl6; set @optimizer_switch_for_select_test=NULL; +set @join_cache_level_for_select_test=NULL; diff --git a/mysql-test/r/select_pkeycache.result b/mysql-test/r/select_pkeycache.result index a3647c10350..29a6bb4bf35 100644 --- a/mysql-test/r/select_pkeycache.result +++ b/mysql-test/r/select_pkeycache.result @@ -3,6 +3,7 @@ drop table if exists t1_1,t1_2,t9_1,t9_2,t1aa,t2aa; drop view if exists v1; SET @save_optimizer_switch=@@optimizer_switch; SET optimizer_switch=ifnull(@optimizer_switch_for_select_test,'outer_join_with_cache=off'); +set join_cache_level=1; CREATE TABLE t1 ( Period smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, Varor_period smallint(4) unsigned DEFAULT '0' NOT NULL diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 2eaf4062659..58a4e61ce0b 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -3,6 +3,7 @@ drop view if exists v2; set @subselect_tmp=@@optimizer_switch; set @@optimizer_switch=ifnull(@optimizer_switch_for_subselect_test, "semijoin=on,firstmatch=on,loosescan=on,semijoin_with_cache=on,partial_match_rowid_merge=off,partial_match_table_scan=off"); +set join_cache_level=1; set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; select (select 2); (select 2) diff --git a/mysql-test/r/subselect3.result b/mysql-test/r/subselect3.result index 7d13bce1f85..8d79eb26557 100644 --- a/mysql-test/r/subselect3.result +++ b/mysql-test/r/subselect3.result @@ -1,6 +1,7 @@ drop table if exists t0, t1, t2, t3, t4, t5, t11, t12, t21, t22; set @subselect3_tmp= @@optimizer_switch; set optimizer_switch='semijoin=on,firstmatch=on,loosescan=on,semijoin_with_cache=on'; +set join_cache_level=1; create table t1 (oref int, grp int, ie int) ; insert into t1 (oref, grp, ie) values (1, 1, 1), diff --git a/mysql-test/r/subselect3_jcl6.result b/mysql-test/r/subselect3_jcl6.result index 5ad5878623d..a0153cf209d 100644 --- a/mysql-test/r/subselect3_jcl6.result +++ b/mysql-test/r/subselect3_jcl6.result @@ -7,9 +7,11 @@ set join_cache_level=6; show variables like 'join_cache_level'; Variable_name Value join_cache_level 6 +set @join_cache_level_for_subselect3_test=@@join_cache_level; drop table if exists t0, t1, t2, t3, t4, t5, t11, t12, t21, t22; set @subselect3_tmp= @@optimizer_switch; set optimizer_switch='semijoin=on,firstmatch=on,loosescan=on,semijoin_with_cache=on'; +set join_cache_level=@join_cache_level_for_subselect3_test; create table t1 (oref int, grp int, ie int) ; insert into t1 (oref, grp, ie) values (1, 1, 1), @@ -1502,5 +1504,6 @@ set @@optimizer_switch=@subselect3_tmp; set join_cache_level=default; show variables like 'join_cache_level'; Variable_name Value -join_cache_level 1 +join_cache_level 2 set @@optimizer_switch=@save_optimizer_switch; +set @join_cache_level_for_subselect3_test=NULL; diff --git a/mysql-test/r/subselect_mat.result b/mysql-test/r/subselect_mat.result index cf615caf30b..7e4cf4ed9f1 100644 --- a/mysql-test/r/subselect_mat.result +++ b/mysql-test/r/subselect_mat.result @@ -3,6 +3,8 @@ set @subselect_sj_mat_tmp= @@optimizer_switch; set optimizer_switch=ifnull(@subselect_mat_test_optimizer_switch_value, 'semijoin=on,firstmatch=on,loosescan=on,semijoin_with_cache=on'); set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; set @optimizer_switch_local_default= @@optimizer_switch; +set @save_join_cache_level=@@join_cache_level; +set join_cache_level=1; drop table if exists t1, t2, t3, t4, t5, t1i, t2i, t3i; drop table if exists columns; drop table if exists t1_16, t2_16, t3_16; @@ -1797,6 +1799,7 @@ Note 1003 select 8 AS `a` from `test`.`t1` where <8>(( DROP TABLE t1; # This must be at the end: set optimizer_switch=@subselect_sj_mat_tmp; +set join_cache_level=@save_join_cache_level; set @subselect_mat_test_optimizer_switch_value=null; set @@optimizer_switch='materialization=on,in_to_exists=off,semijoin=off'; set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; diff --git a/mysql-test/r/subselect_no_mat.result b/mysql-test/r/subselect_no_mat.result index 2acca5e0af9..6d9cdc08572 100644 --- a/mysql-test/r/subselect_no_mat.result +++ b/mysql-test/r/subselect_no_mat.result @@ -3,11 +3,14 @@ select @@optimizer_switch like '%materialization=on%'; 1 set optimizer_switch='materialization=off'; set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; +set join_cache_level=1; +set @join_cache_level_for_subselect_test=@@join_cache_level; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t11,t12; drop view if exists v2; set @subselect_tmp=@@optimizer_switch; set @@optimizer_switch=ifnull(@optimizer_switch_for_subselect_test, "semijoin=on,firstmatch=on,loosescan=on,semijoin_with_cache=on,partial_match_rowid_merge=off,partial_match_table_scan=off"); +set join_cache_level=@join_cache_level_for_subselect_test; set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; select (select 2); (select 2) @@ -5901,3 +5904,4 @@ set optimizer_switch=default; select @@optimizer_switch like '%materialization=on%'; @@optimizer_switch like '%materialization=on%' 1 +set @join_cache_level_for_subselect_test=NULL; diff --git a/mysql-test/r/subselect_no_opts.result b/mysql-test/r/subselect_no_opts.result index b5e0f16c388..53ac091b722 100644 --- a/mysql-test/r/subselect_no_opts.result +++ b/mysql-test/r/subselect_no_opts.result @@ -1,9 +1,12 @@ set @optimizer_switch_for_subselect_test='materialization=off,semijoin=off,subquery_cache=off,mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; +set join_cache_level=1; +set @join_cache_level_for_subselect_test=@@join_cache_level; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t11,t12; drop view if exists v2; set @subselect_tmp=@@optimizer_switch; set @@optimizer_switch=ifnull(@optimizer_switch_for_subselect_test, "semijoin=on,firstmatch=on,loosescan=on,semijoin_with_cache=on,partial_match_rowid_merge=off,partial_match_table_scan=off"); +set join_cache_level=@join_cache_level_for_subselect_test; set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; select (select 2); (select 2) diff --git a/mysql-test/r/subselect_no_scache.result b/mysql-test/r/subselect_no_scache.result index aaa162528fc..e3ad1397c02 100644 --- a/mysql-test/r/subselect_no_scache.result +++ b/mysql-test/r/subselect_no_scache.result @@ -2,11 +2,14 @@ select @@optimizer_switch like '%subquery_cache=on%'; @@optimizer_switch like '%subquery_cache=on%' 1 set optimizer_switch='subquery_cache=off'; +set join_cache_level=1; +set @join_cache_level_for_subselect_test=@@join_cache_level; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t11,t12; drop view if exists v2; set @subselect_tmp=@@optimizer_switch; set @@optimizer_switch=ifnull(@optimizer_switch_for_subselect_test, "semijoin=on,firstmatch=on,loosescan=on,semijoin_with_cache=on,partial_match_rowid_merge=off,partial_match_table_scan=off"); +set join_cache_level=@join_cache_level_for_subselect_test; set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; select (select 2); (select 2) @@ -5906,3 +5909,4 @@ set optimizer_switch=default; select @@optimizer_switch like '%subquery_cache=on%'; @@optimizer_switch like '%subquery_cache=on%' 1 +set @join_cache_level_for_subselect_test=NULL; diff --git a/mysql-test/r/subselect_no_semijoin.result b/mysql-test/r/subselect_no_semijoin.result index 7923d4cc68b..d5c6af1640a 100644 --- a/mysql-test/r/subselect_no_semijoin.result +++ b/mysql-test/r/subselect_no_semijoin.result @@ -1,9 +1,12 @@ set @optimizer_switch_for_subselect_test='semijoin=off,mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; +set join_cache_level=1; +set @join_cache_level_for_subselect_test=@@join_cache_level; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t11,t12; drop view if exists v2; set @subselect_tmp=@@optimizer_switch; set @@optimizer_switch=ifnull(@optimizer_switch_for_subselect_test, "semijoin=on,firstmatch=on,loosescan=on,semijoin_with_cache=on,partial_match_rowid_merge=off,partial_match_table_scan=off"); +set join_cache_level=@join_cache_level_for_subselect_test; set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; select (select 2); (select 2) @@ -5894,3 +5897,4 @@ 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; +set @join_cache_level_for_subselect_test=NULL; diff --git a/mysql-test/r/subselect_sj.result b/mysql-test/r/subselect_sj.result index 6bea2c8c17b..c0a37be68cf 100644 --- a/mysql-test/r/subselect_sj.result +++ b/mysql-test/r/subselect_sj.result @@ -6,6 +6,7 @@ set optimizer_switch='semijoin=on,firstmatch=on,loosescan=on'; set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; SET optimizer_switch=ifnull(@optimizer_switch_for_subselect_sj_test,'outer_join_with_cache=off'); SET optimizer_switch=ifnull(@optimizer_switch_for_subselect_sj_test,'semijoin_with_cache=off'); +set join_cache_level=1; set @save_optimizer_switch=@@optimizer_switch; create table t0 (a int); insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); diff --git a/mysql-test/r/subselect_sj2.result b/mysql-test/r/subselect_sj2.result index f9d70fd8943..5bf470a5245 100644 --- a/mysql-test/r/subselect_sj2.result +++ b/mysql-test/r/subselect_sj2.result @@ -3,6 +3,7 @@ set optimizer_switch='semijoin=on,firstmatch=on,loosescan=on'; set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; SET optimizer_switch=ifnull(@optimizer_switch_for_subselect_sj2_test,'outer_join_with_cache=off'); SET optimizer_switch=ifnull(@optimizer_switch_for_subselect_sj2_test,'semijoin_with_cache=off'); +set join_cache_level=1; drop table if exists t0, t1, t2, t3, t4, t5; drop view if exists v1; create table t0 (a int); diff --git a/mysql-test/r/subselect_sj2_jcl6.result b/mysql-test/r/subselect_sj2_jcl6.result index eb5b86a3dc6..1f84da5433d 100644 --- a/mysql-test/r/subselect_sj2_jcl6.result +++ b/mysql-test/r/subselect_sj2_jcl6.result @@ -8,11 +8,13 @@ show variables like 'join_cache_level'; Variable_name Value join_cache_level 6 set @optimizer_switch_for_subselect_sj2_test=@@optimizer_switch; +set @join_cache_level_for_subselect_sj2_test=@@join_cache_level; set @subselect_sj2_tmp= @@optimizer_switch; set optimizer_switch='semijoin=on,firstmatch=on,loosescan=on'; set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; SET optimizer_switch=ifnull(@optimizer_switch_for_subselect_sj2_test,'outer_join_with_cache=off'); SET optimizer_switch=ifnull(@optimizer_switch_for_subselect_sj2_test,'semijoin_with_cache=off'); +set join_cache_level=@join_cache_level_for_subselect_sj2_test; drop table if exists t0, t1, t2, t3, t4, t5; drop view if exists v1; create table t0 (a int); @@ -982,6 +984,7 @@ DROP TABLE t1,t2; set join_cache_level=default; show variables like 'join_cache_level'; Variable_name Value -join_cache_level 1 +join_cache_level 2 set @@optimizer_switch=@save_optimizer_switch_jcl6; set @optimizer_switch_for_subselect_sj2_test=NULL; +set @join_cache_level_subselect_sj2_test=NULL; diff --git a/mysql-test/r/subselect_sj2_mat.result b/mysql-test/r/subselect_sj2_mat.result index 021eedab5b8..f217cee38ce 100644 --- a/mysql-test/r/subselect_sj2_mat.result +++ b/mysql-test/r/subselect_sj2_mat.result @@ -5,6 +5,7 @@ set optimizer_switch='semijoin=on,firstmatch=on,loosescan=on'; set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; SET optimizer_switch=ifnull(@optimizer_switch_for_subselect_sj2_test,'outer_join_with_cache=off'); SET optimizer_switch=ifnull(@optimizer_switch_for_subselect_sj2_test,'semijoin_with_cache=off'); +set join_cache_level=1; drop table if exists t0, t1, t2, t3, t4, t5; drop view if exists v1; create table t0 (a int); diff --git a/mysql-test/r/subselect_sj_jcl6.result b/mysql-test/r/subselect_sj_jcl6.result index 26f6ef11878..df3ab436f41 100644 --- a/mysql-test/r/subselect_sj_jcl6.result +++ b/mysql-test/r/subselect_sj_jcl6.result @@ -10,6 +10,7 @@ show variables like 'join_cache_level'; Variable_name Value join_cache_level 6 set @optimizer_switch_for_subselect_sj_test=@@optimizer_switch; +set @join_cache_level_for_subselect_sj_test=@@join_cache_level; drop table if exists t0, t1, t2, t3, t4, t5, t10, t11, t12; drop view if exists v1, v2, v3, v4; drop procedure if exists p1; @@ -18,6 +19,7 @@ set optimizer_switch='semijoin=on,firstmatch=on,loosescan=on'; set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; SET optimizer_switch=ifnull(@optimizer_switch_for_subselect_sj_test,'outer_join_with_cache=off'); SET optimizer_switch=ifnull(@optimizer_switch_for_subselect_sj_test,'semijoin_with_cache=off'); +set join_cache_level=@join_cache_level_for_subselect_sj_test; set @save_optimizer_switch=@@optimizer_switch; create table t0 (a int); insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); @@ -2243,6 +2245,7 @@ DROP TABLE t1,t2,t3; set join_cache_level=default; show variables like 'join_cache_level'; Variable_name Value -join_cache_level 1 +join_cache_level 2 set @@optimizer_switch=@save_optimizer_switch_jcl6; set @optimizer_switch_for_subselect_sj_test=NULL; +set @join_cache_level_subselect_sj_test=NULL; diff --git a/mysql-test/r/subselect_sj_mat.result b/mysql-test/r/subselect_sj_mat.result index af7c9a1de5b..bdfa834977b 100644 --- a/mysql-test/r/subselect_sj_mat.result +++ b/mysql-test/r/subselect_sj_mat.result @@ -2,6 +2,8 @@ set @subselect_sj_mat_tmp= @@optimizer_switch; set optimizer_switch=ifnull(@subselect_mat_test_optimizer_switch_value, 'semijoin=on,firstmatch=on,loosescan=on,semijoin_with_cache=on'); set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; set @optimizer_switch_local_default= @@optimizer_switch; +set @save_join_cache_level=@@join_cache_level; +set join_cache_level=1; drop table if exists t1, t2, t3, t4, t5, t1i, t2i, t3i; drop table if exists columns; drop table if exists t1_16, t2_16, t3_16; @@ -1834,3 +1836,4 @@ Note 1003 select 8 AS `a` from (select min(`test`.`t1`.`a`) from DROP TABLE t1; # 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/suite/pbxt/r/distinct.result b/mysql-test/suite/pbxt/r/distinct.result index f821023f03a..aa4ba4bef06 100644 --- a/mysql-test/suite/pbxt/r/distinct.result +++ b/mysql-test/suite/pbxt/r/distinct.result @@ -280,6 +280,8 @@ unique (id, idx) insert into t1 values (1,'yes'), (2,'no'); insert into t2 values (1,1); insert into t3 values (1,1); +set @save_join_cache_level=@@join_cache_level; +set join_cache_level=1; EXPLAIN SELECT DISTINCT t1.id @@ -326,6 +328,7 @@ AND ((t1.id=j_lj_t3.id AND t3_lj.id IS NULL) OR (t1.id=t3.id AND t3.idx=2)); id 2 drop table t1,t2,t3; +set join_cache_level=@save_join_cache_level; create table t1 (a int not null, b int not null, t time); insert into t1 values (1,1,"00:06:15"),(1,2,"00:06:15"),(1,2,"00:30:15"),(1,3,"00:06:15"),(1,3,"00:30:15"); select a,sec_to_time(sum(time_to_sec(t))) from t1 group by a,b; diff --git a/mysql-test/suite/pbxt/r/greedy_optimizer.result b/mysql-test/suite/pbxt/r/greedy_optimizer.result index 2fb65d4d824..7b46f4275b0 100644 --- a/mysql-test/suite/pbxt/r/greedy_optimizer.result +++ b/mysql-test/suite/pbxt/r/greedy_optimizer.result @@ -1,4 +1,6 @@ drop table if exists t1,t2,t3,t4,t5,t6,t7; +set @save_join_cache_level=@@join_cache_level; +set join_cache_level=1; create table t1 ( c11 integer,c12 integer,c13 integer,c14 integer,c15 integer,c16 integer, primary key (c11) @@ -655,3 +657,4 @@ show status like 'Last_query_cost'; Variable_name Value Last_query_cost 795.625316 drop table t1,t2,t3,t4,t5,t6,t7; +set join_cache_level=@save_join_cache_level; diff --git a/mysql-test/suite/pbxt/t/distinct.test b/mysql-test/suite/pbxt/t/distinct.test index 5d02b38aed8..854d7fc838e 100644 --- a/mysql-test/suite/pbxt/t/distinct.test +++ b/mysql-test/suite/pbxt/t/distinct.test @@ -158,6 +158,10 @@ create table t3 ( insert into t1 values (1,'yes'), (2,'no'); insert into t2 values (1,1); insert into t3 values (1,1); + +set @save_join_cache_level=@@join_cache_level; +set join_cache_level=1; + EXPLAIN SELECT DISTINCT t1.id @@ -195,6 +199,8 @@ WHERE AND ((t1.id=j_lj_t3.id AND t3_lj.id IS NULL) OR (t1.id=t3.id AND t3.idx=2)); drop table t1,t2,t3; +set join_cache_level=@save_join_cache_level; + # # Test using DISTINCT on a function that contains a group function # This also test the case when one doesn't use all fields in GROUP BY. diff --git a/mysql-test/suite/pbxt/t/greedy_optimizer.test b/mysql-test/suite/pbxt/t/greedy_optimizer.test index fd0be172e83..b3c05f4b3cd 100644 --- a/mysql-test/suite/pbxt/t/greedy_optimizer.test +++ b/mysql-test/suite/pbxt/t/greedy_optimizer.test @@ -10,6 +10,9 @@ drop table if exists t1,t2,t3,t4,t5,t6,t7; --enable_warnings +set @save_join_cache_level=@@join_cache_level; +set join_cache_level=1; + create table t1 ( c11 integer,c12 integer,c13 integer,c14 integer,c15 integer,c16 integer, primary key (c11) @@ -312,6 +315,8 @@ show status like 'Last_query_cost'; drop table t1,t2,t3,t4,t5,t6,t7; +set join_cache_level=@save_join_cache_level; + --disable_query_log drop database pbxt; --enable_query_log diff --git a/mysql-test/t/derived_view.test b/mysql-test/t/derived_view.test index 953a4c8fcef..581d01058db 100644 --- a/mysql-test/t/derived_view.test +++ b/mysql-test/t/derived_view.test @@ -4,9 +4,11 @@ drop view if exists v1,v2,v3,v4; --enable_warnings set @exit_optimizer_switch=@@optimizer_switch; +set @exit_join_cache_level=@@join_cache_level; set optimizer_switch='derived_merge=on,derived_with_keys=on'; # The 'default' value within the scope of this test: set @save_optimizer_switch=@@optimizer_switch; +set join_cache_level=1; create table t1(f1 int, f11 int); create table t2(f2 int, f22 int); @@ -1276,3 +1278,4 @@ drop table t1,t2,t3; # 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/mysql-test/t/distinct.test b/mysql-test/t/distinct.test index 796732fa097..0f0cbcf26d0 100644 --- a/mysql-test/t/distinct.test +++ b/mysql-test/t/distinct.test @@ -158,6 +158,10 @@ create table t3 ( insert into t1 values (1,'yes'), (2,'no'); insert into t2 values (1,1); insert into t3 values (1,1); + +set @save_join_cache_level=@@join_cache_level; +set join_cache_level=1; + EXPLAIN SELECT DISTINCT t1.id @@ -195,6 +199,8 @@ WHERE AND ((t1.id=j_lj_t3.id AND t3_lj.id IS NULL) OR (t1.id=t3.id AND t3.idx=2)); drop table t1,t2,t3; +set join_cache_level=@save_join_cache_level; + # # Test using DISTINCT on a function that contains a group function # This also test the case when one doesn't use all fields in GROUP BY. diff --git a/mysql-test/t/greedy_optimizer.test b/mysql-test/t/greedy_optimizer.test index 5131c97f122..8f969f2562a 100644 --- a/mysql-test/t/greedy_optimizer.test +++ b/mysql-test/t/greedy_optimizer.test @@ -10,6 +10,9 @@ drop table if exists t1,t2,t3,t4,t5,t6,t7; --enable_warnings +set @save_join_cache_level=@@join_cache_level; +set join_cache_level=1; + create table t1 ( c11 integer,c12 integer,c13 integer,c14 integer,c15 integer,c16 integer, primary key (c11) @@ -384,3 +387,5 @@ SET optimizer_search_depth = DEFAULT; DROP TABLE t1,t2,t2_1,t3,t3_1,t4,t4_1,t5,t5_1; --echo End of 5.0 tests + +set join_cache_level=@save_join_cache_level; diff --git a/mysql-test/t/join_cache.test b/mysql-test/t/join_cache.test index 5a48f7653e4..0feb4e30af0 100644 --- a/mysql-test/t/join_cache.test +++ b/mysql-test/t/join_cache.test @@ -33,6 +33,8 @@ SELECT COUNT(*) FROM CountryLanguage; show variables like 'join_buffer_size'; +set join_cache_level=1; + show variables like 'join_cache_level'; EXPLAIN @@ -196,7 +198,7 @@ SELECT Country.Name, Country.Population, City.Name, City.Population DROP INDEX City_Population ON City; DROP INDEX City_Name ON City; -set join_cache_level=default; +set join_cache_level=1; set join_buffer_size=256; show variables like 'join_buffer_size'; @@ -2191,6 +2193,8 @@ insert into t2 values (1,1),(2,2); create table t3 (a int, b int); insert into t3 values (1,1),(2,2); +set join_cache_level=1; + explain select t1.* from t1,t2,t3; select t1.* from t1,t2,t3; diff --git a/mysql-test/t/join_nested.test b/mysql-test/t/join_nested.test index fa7b59e84c3..3168e95f620 100644 --- a/mysql-test/t/join_nested.test +++ b/mysql-test/t/join_nested.test @@ -5,6 +5,15 @@ DROP TABLE IF EXISTS t0,t1,t2,t3,t4,t5,t6,t7,t8,t9; SET @save_optimizer_switch=@@optimizer_switch; SET optimizer_switch=ifnull(@optimizer_switch_for_join_nested_test,'outer_join_with_cache=off'); +if (`select @join_cache_level_for_join_nested_test is null`) +{ + set join_cache_level=1; +} +if (`select @join_cache_level_for_join_nested_test is not null`) +{ + set join_cache_level=@join_cache_level_for_join_nested_test; +} + CREATE TABLE t0 (a int, b int, c int); CREATE TABLE t1 (a int, b int, c int); diff --git a/mysql-test/t/join_nested_jcl6.test b/mysql-test/t/join_nested_jcl6.test index f250702da7e..0e8646bceda 100644 --- a/mysql-test/t/join_nested_jcl6.test +++ b/mysql-test/t/join_nested_jcl6.test @@ -12,6 +12,7 @@ set join_cache_level=6; show variables like 'join_cache_level'; set @optimizer_switch_for_join_nested_test=@@optimizer_switch; +set @join_cache_level_for_join_nested_test=@@join_cache_level; --source t/join_nested.test @@ -107,3 +108,4 @@ show variables like 'join_cache_level'; set @@optimizer_switch=@save_optimizer_switch_jcl6; set @optimizer_switch_for_join_nested_test=NULL; +set @join_cache_level_for_join_nested_test=NULL; diff --git a/mysql-test/t/join_outer.test b/mysql-test/t/join_outer.test index 3bd5532ada0..04816402205 100644 --- a/mysql-test/t/join_outer.test +++ b/mysql-test/t/join_outer.test @@ -10,7 +10,14 @@ drop table if exists t0,t1,t2,t3,t4,t5; SET @save_optimizer_switch=@@optimizer_switch; SET optimizer_switch=ifnull(@optimizer_switch_for_join_outer_test,'outer_join_with_cache=off'); - +if (`select @join_cache_level_for_join_outer_test is null`) +{ + set join_cache_level=1; +} +if (`select @join_cache_level_for_join_outer_test is not null`) +{ + set join_cache_level=@join_cache_level_for_join_outer_test; +} CREATE TABLE t1 ( grp int(11) default NULL, diff --git a/mysql-test/t/join_outer_jcl6.test b/mysql-test/t/join_outer_jcl6.test index ba0a6686a51..e34cc615216 100644 --- a/mysql-test/t/join_outer_jcl6.test +++ b/mysql-test/t/join_outer_jcl6.test @@ -12,6 +12,7 @@ set join_cache_level=6; show variables like 'join_cache_level'; set @optimizer_switch_for_join_outer_test=@@optimizer_switch; +set @join_cache_level_for_join_outer_test=@@join_cache_level; --source t/join_outer.test @@ -20,3 +21,4 @@ show variables like 'join_cache_level'; set @@optimizer_switch=@save_optimizer_switch_jcl6; set @optimizer_switch_for_join_outer_test=NULL; +set @join_cache_level_for_join_outer_test=NULL; diff --git a/mysql-test/t/maria_mrr.test b/mysql-test/t/maria_mrr.test index 4cd4c277a7f..fe7dc7acc79 100644 --- a/mysql-test/t/maria_mrr.test +++ b/mysql-test/t/maria_mrr.test @@ -78,6 +78,9 @@ INSERT INTO t3 VALUES (88, 442, 'y'), (99, 445, 'w'), (87, 442, 'z'), (98, 445, 'v'), (86, 442, 'x'), (97, 445, 't'), (85, 442, 'b'), (96, 445, 'l'), (84, 442, 'a'), (95, 445, 'k'); +set @save_join_cache_level=@@join_cache_level; +set join_cache_level=1; + SELECT COUNT(t1.v) FROM t1, t2 IGNORE INDEX (idx), t3 IGNORE INDEX (idx) WHERE t3.v = t2.v AND t3.i < t2.i AND t3.pk > 0 AND t2.pk > 0; EXPLAIN @@ -90,6 +93,8 @@ EXPLAIN SELECT COUNT(t1.v) FROM t1, t2, t3 WHERE t3.v = t2.v AND t3.i < t2.i AND t3.pk > 0 AND t2.pk > 0; +set join_cache_level=@save_join_cache_level; + DROP TABLE t1,t2,t3; --echo # diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index 9c037fa9106..75ea88b6bde 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -15,6 +15,14 @@ drop view if exists v1; SET @save_optimizer_switch=@@optimizer_switch; SET optimizer_switch=ifnull(@optimizer_switch_for_select_test,'outer_join_with_cache=off'); +if (`select @join_cache_level_for_select_test is null`) +{ + set join_cache_level=1; +} +if (`select @join_cache_level_for_select_test is not null`) +{ + set join_cache_level=@join_cache_level_for_select_test; +} CREATE TABLE t1 ( Period smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, diff --git a/mysql-test/t/select_jcl6.test b/mysql-test/t/select_jcl6.test index 29c86679515..f7c1aa988c7 100644 --- a/mysql-test/t/select_jcl6.test +++ b/mysql-test/t/select_jcl6.test @@ -12,6 +12,7 @@ set join_cache_level=6; show variables like 'join_cache_level'; set @optimizer_switch_for_select_test=@@optimizer_switch; +set @join_cache_level_for_select_test=@@join_cache_level; --source t/select.test @@ -20,3 +21,4 @@ show variables like 'join_cache_level'; set @@optimizer_switch=@save_optimizer_switch_jcl6; set @optimizer_switch_for_select_test=NULL; +set @join_cache_level_for_select_test=NULL; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 13bbc01af17..d53ba706388 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -15,7 +15,16 @@ drop view if exists v2; set @subselect_tmp=@@optimizer_switch; set @@optimizer_switch=ifnull(@optimizer_switch_for_subselect_test, "semijoin=on,firstmatch=on,loosescan=on,semijoin_with_cache=on,partial_match_rowid_merge=off,partial_match_table_scan=off"); -set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; + +if (`select @join_cache_level_for_subselect_test is null`) +{ + set join_cache_level=1; +} +if (`select @join_cache_level_for_subselect_test is not null`) +{ + set join_cache_level=@join_cache_level_for_subselect_test; +} + set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; select (select 2); explain extended select (select 2); diff --git a/mysql-test/t/subselect3.test b/mysql-test/t/subselect3.test index aadc08e18e0..ec6ceff8822 100644 --- a/mysql-test/t/subselect3.test +++ b/mysql-test/t/subselect3.test @@ -4,6 +4,14 @@ drop table if exists t0, t1, t2, t3, t4, t5, t11, t12, t21, t22; set @subselect3_tmp= @@optimizer_switch; set optimizer_switch='semijoin=on,firstmatch=on,loosescan=on,semijoin_with_cache=on'; +if (`select @join_cache_level_for_subselect3_test is null`) +{ + set join_cache_level=1; +} +if (`select @join_cache_level_for_subselect3_test is not null`) +{ + set join_cache_level=@join_cache_level_for_subselect3_test; +} # # 1. Subquery with GROUP/HAVING diff --git a/mysql-test/t/subselect3_jcl6.test b/mysql-test/t/subselect3_jcl6.test index 8d880809476..e4b1c144b93 100644 --- a/mysql-test/t/subselect3_jcl6.test +++ b/mysql-test/t/subselect3_jcl6.test @@ -11,9 +11,12 @@ set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; set join_cache_level=6; show variables like 'join_cache_level'; +set @join_cache_level_for_subselect3_test=@@join_cache_level; + --source t/subselect3.test set join_cache_level=default; show variables like 'join_cache_level'; set @@optimizer_switch=@save_optimizer_switch; +set @join_cache_level_for_subselect3_test=NULL; diff --git a/mysql-test/t/subselect_no_mat.test b/mysql-test/t/subselect_no_mat.test index 0265ec91e88..ccd93af64ce 100644 --- a/mysql-test/t/subselect_no_mat.test +++ b/mysql-test/t/subselect_no_mat.test @@ -5,8 +5,13 @@ select @@optimizer_switch like '%materialization=on%'; set optimizer_switch='materialization=off'; set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; +set join_cache_level=1; +set @join_cache_level_for_subselect_test=@@join_cache_level; + --source t/subselect.test set optimizer_switch=default; select @@optimizer_switch like '%materialization=on%'; +set @join_cache_level_for_subselect_test=NULL; + diff --git a/mysql-test/t/subselect_no_opts.test b/mysql-test/t/subselect_no_opts.test index 724cbab6310..8a699fefaf7 100644 --- a/mysql-test/t/subselect_no_opts.test +++ b/mysql-test/t/subselect_no_opts.test @@ -4,6 +4,10 @@ set @optimizer_switch_for_subselect_test='materialization=off,semijoin=off,subquery_cache=off,mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; + +set join_cache_level=1; +set @join_cache_level_for_subselect_test=@@join_cache_level; + --source t/subselect.test set @optimizer_switch_for_subselect_test=null; diff --git a/mysql-test/t/subselect_no_scache.test b/mysql-test/t/subselect_no_scache.test index fe8ff749a59..a8ff559b82b 100644 --- a/mysql-test/t/subselect_no_scache.test +++ b/mysql-test/t/subselect_no_scache.test @@ -4,8 +4,12 @@ select @@optimizer_switch like '%subquery_cache=on%'; set optimizer_switch='subquery_cache=off'; +set join_cache_level=1; +set @join_cache_level_for_subselect_test=@@join_cache_level; + --source t/subselect.test set optimizer_switch=default; select @@optimizer_switch like '%subquery_cache=on%'; +set @join_cache_level_for_subselect_test=NULL; diff --git a/mysql-test/t/subselect_no_semijoin.test b/mysql-test/t/subselect_no_semijoin.test index c836c12ec50..46791667173 100644 --- a/mysql-test/t/subselect_no_semijoin.test +++ b/mysql-test/t/subselect_no_semijoin.test @@ -3,6 +3,10 @@ # set @optimizer_switch_for_subselect_test='semijoin=off,mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; +set join_cache_level=1; +set @join_cache_level_for_subselect_test=@@join_cache_level; + --source t/subselect.test set @optimizer_switch_for_subselect_test=null; +set @join_cache_level_for_subselect_test=NULL; diff --git a/mysql-test/t/subselect_sj.test b/mysql-test/t/subselect_sj.test index 3b419dc0d09..6cd74b9689d 100644 --- a/mysql-test/t/subselect_sj.test +++ b/mysql-test/t/subselect_sj.test @@ -12,6 +12,14 @@ set optimizer_switch='semijoin=on,firstmatch=on,loosescan=on'; set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; SET optimizer_switch=ifnull(@optimizer_switch_for_subselect_sj_test,'outer_join_with_cache=off'); SET optimizer_switch=ifnull(@optimizer_switch_for_subselect_sj_test,'semijoin_with_cache=off'); +if (`select @join_cache_level_for_subselect_sj_test is null`) +{ + set join_cache_level=1; +} +if (`select @join_cache_level_for_subselect_sj_test is not null`) +{ + set join_cache_level=@join_cache_level_for_subselect_sj_test; +} # The 'default' value within the scope of this test: set @save_optimizer_switch=@@optimizer_switch; diff --git a/mysql-test/t/subselect_sj2.test b/mysql-test/t/subselect_sj2.test index 5229546c08e..9a664ee9881 100644 --- a/mysql-test/t/subselect_sj2.test +++ b/mysql-test/t/subselect_sj2.test @@ -8,6 +8,14 @@ set optimizer_switch='semijoin=on,firstmatch=on,loosescan=on'; set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; SET optimizer_switch=ifnull(@optimizer_switch_for_subselect_sj2_test,'outer_join_with_cache=off'); SET optimizer_switch=ifnull(@optimizer_switch_for_subselect_sj2_test,'semijoin_with_cache=off'); +if (`select @join_cache_level_for_subselect_sj2_test is null`) +{ + set join_cache_level=1; +} +if (`select @join_cache_level_for_subselect_sj2_test is not null`) +{ + set join_cache_level=@join_cache_level_for_subselect_sj2_test; +} --disable_warnings drop table if exists t0, t1, t2, t3, t4, t5; diff --git a/mysql-test/t/subselect_sj2_jcl6.test b/mysql-test/t/subselect_sj2_jcl6.test index 0b20c39c183..09212ba63d0 100644 --- a/mysql-test/t/subselect_sj2_jcl6.test +++ b/mysql-test/t/subselect_sj2_jcl6.test @@ -12,6 +12,7 @@ set join_cache_level=6; show variables like 'join_cache_level'; set @optimizer_switch_for_subselect_sj2_test=@@optimizer_switch; +set @join_cache_level_for_subselect_sj2_test=@@join_cache_level; --source t/subselect_sj2.test @@ -104,4 +105,5 @@ show variables like 'join_cache_level'; set @@optimizer_switch=@save_optimizer_switch_jcl6; set @optimizer_switch_for_subselect_sj2_test=NULL; +set @join_cache_level_subselect_sj2_test=NULL; diff --git a/mysql-test/t/subselect_sj_jcl6.test b/mysql-test/t/subselect_sj_jcl6.test index bfb867830c4..4eeaa465b11 100644 --- a/mysql-test/t/subselect_sj_jcl6.test +++ b/mysql-test/t/subselect_sj_jcl6.test @@ -14,6 +14,7 @@ set join_cache_level=6; show variables like 'join_cache_level'; set @optimizer_switch_for_subselect_sj_test=@@optimizer_switch; +set @join_cache_level_for_subselect_sj_test=@@join_cache_level; --source t/subselect_sj.test @@ -94,3 +95,4 @@ show variables like 'join_cache_level'; set @@optimizer_switch=@save_optimizer_switch_jcl6; set @optimizer_switch_for_subselect_sj_test=NULL; +set @join_cache_level_subselect_sj_test=NULL; diff --git a/mysql-test/t/subselect_sj_mat.test b/mysql-test/t/subselect_sj_mat.test index e660c63df5b..a0d24aa53ed 100644 --- a/mysql-test/t/subselect_sj_mat.test +++ b/mysql-test/t/subselect_sj_mat.test @@ -7,6 +7,8 @@ set @subselect_sj_mat_tmp= @@optimizer_switch; set optimizer_switch=ifnull(@subselect_mat_test_optimizer_switch_value, 'semijoin=on,firstmatch=on,loosescan=on,semijoin_with_cache=on'); set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; set @optimizer_switch_local_default= @@optimizer_switch; +set @save_join_cache_level=@@join_cache_level; +set join_cache_level=1; --disable_warnings drop table if exists t1, t2, t3, t4, t5, t1i, t2i, t3i; @@ -1497,4 +1499,5 @@ DROP TABLE t1; --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/mysqld.cc b/sql/mysqld.cc index 606af24e0db..1a60d996fed 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -7294,7 +7294,7 @@ each time the SQL thread starts.", "Controls what join operations can be executed with join buffers. Odd numbers are used for plain join buffers while even numbers are used for linked buffers", &global_system_variables.join_cache_level, &max_system_variables.join_cache_level, - 0, GET_ULONG, REQUIRED_ARG, 1, 0, 8, 0, 1, 0}, + 0, GET_ULONG, REQUIRED_ARG, 2, 0, 8, 0, 1, 0}, {"keep_files_on_create", OPT_KEEP_FILES_ON_CREATE, "Don't overwrite stale .MYD and .MYI even if no directory is specified.", &global_system_variables.keep_files_on_create, From 04e9004fa32c9066788db6f2633022a912f349e2 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Fri, 16 Dec 2011 03:44:25 +0400 Subject: [PATCH 217/288] BUG#901399: Wrong result (extra row) with semijoin=ON, materialization=OFF, optimizer_prune_level=0 - Correctly handle plan refinement stage for LooseScan plans: run create_ref_for_key() if LooseScan plan includes a ref access, and if we don't have any fixed key components, switch to a full index scan. --- mysql-test/r/subselect3.result | 4 ++-- mysql-test/r/subselect3_jcl6.result | 4 ++-- mysql-test/r/subselect_sj.result | 27 ++++++++++++++++++++++ mysql-test/r/subselect_sj_jcl6.result | 27 ++++++++++++++++++++++ mysql-test/t/subselect_sj.test | 29 +++++++++++++++++++++++ sql/sql_select.cc | 33 +++++++++++++++++++-------- sql/sql_select.h | 11 ++++++++- 7 files changed, 121 insertions(+), 14 deletions(-) diff --git a/mysql-test/r/subselect3.result b/mysql-test/r/subselect3.result index 7d13bce1f85..8c55df90f62 100644 --- a/mysql-test/r/subselect3.result +++ b/mysql-test/r/subselect3.result @@ -1274,11 +1274,11 @@ insert into t1 select A.a, B.a, 'filler' from t0 A, t0 B; create table t2 as select * from t1; explain select * from t2 where a in (select b from t1 where a=3); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t1 range a a 5 NULL 8 Using where; Using index; LooseScan +1 PRIMARY t1 ref a a 5 const 8 Using index; LooseScan 1 PRIMARY t2 ALL NULL NULL NULL NULL 100 Using where; Using join buffer (flat, BNL join) explain select * from t2 where (b,a) in (select a,b from t1 where a=3); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t1 range a a 5 NULL 8 Using where; Using index; LooseScan +1 PRIMARY t1 ref a a 5 const 8 Using index; LooseScan 1 PRIMARY t2 ALL NULL NULL NULL NULL 100 Using where; Using join buffer (flat, BNL join) drop table t1,t2; set @@optimizer_switch=@save_optimizer_switch; diff --git a/mysql-test/r/subselect3_jcl6.result b/mysql-test/r/subselect3_jcl6.result index 5ad5878623d..66b305bcf14 100644 --- a/mysql-test/r/subselect3_jcl6.result +++ b/mysql-test/r/subselect3_jcl6.result @@ -1283,11 +1283,11 @@ insert into t1 select A.a, B.a, 'filler' from t0 A, t0 B; create table t2 as select * from t1; explain select * from t2 where a in (select b from t1 where a=3); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t1 range a a 5 NULL 8 Using where; Using index; LooseScan +1 PRIMARY t1 ref a a 5 const 8 Using index; LooseScan 1 PRIMARY t2 ALL NULL NULL NULL NULL 100 Using where; Using join buffer (flat, BNL join) explain select * from t2 where (b,a) in (select a,b from t1 where a=3); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t1 range a a 5 NULL 8 Using where; Using index; LooseScan +1 PRIMARY t1 ref a a 5 const 8 Using index; LooseScan 1 PRIMARY t2 ALL NULL NULL NULL NULL 100 Using where; Using join buffer (flat, BNL join) drop table t1,t2; set @@optimizer_switch=@save_optimizer_switch; diff --git a/mysql-test/r/subselect_sj.result b/mysql-test/r/subselect_sj.result index a7b3cffb8d2..82804681eef 100644 --- a/mysql-test/r/subselect_sj.result +++ b/mysql-test/r/subselect_sj.result @@ -2149,4 +2149,31 @@ a a SET optimizer_prune_level=DEFAULT; SET optimizer_switch=@tmp_optimizer_switch; DROP TABLE t1,t2,t3,t4; +# +# BUG#901399: Wrong result (extra row) with semijoin=ON, materialization=OFF, optimizer_prune_level=0 +# +set @opl_901399= @@optimizer_prune_level; +set @os_091399= @@optimizer_switch; +SET optimizer_prune_level=0; +SET optimizer_switch = 'materialization=off'; +CREATE TABLE t1 ( c INT ) ENGINE=MyISAM; +INSERT INTO t1 VALUES +(0),(1),(2),(3),(4),(5), +(6),(7),(8),(9),(10),(11),(12); +CREATE TABLE t2 ( a INT, b INT, KEY(a)) ENGINE=MyISAM; +INSERT INTO t2 VALUES (3,20),(2,21),(3,22); +SELECT * +FROM t1 AS alias1, t1 AS alias2 +WHERE ( alias1.c, alias2.c ) +IN ( +SELECT alias3.a, alias3.a +FROM t2 AS alias3, t2 alias4 +WHERE alias3.b = alias4.b +); +c c +2 2 +3 3 +set optimizer_prune_level= @opl_901399; +set optimizer_switch= @os_091399; +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 8de5af4cf56..7a3fe20a4e5 100644 --- a/mysql-test/r/subselect_sj_jcl6.result +++ b/mysql-test/r/subselect_sj_jcl6.result @@ -2155,6 +2155,33 @@ a a SET optimizer_prune_level=DEFAULT; SET optimizer_switch=@tmp_optimizer_switch; DROP TABLE t1,t2,t3,t4; +# +# BUG#901399: Wrong result (extra row) with semijoin=ON, materialization=OFF, optimizer_prune_level=0 +# +set @opl_901399= @@optimizer_prune_level; +set @os_091399= @@optimizer_switch; +SET optimizer_prune_level=0; +SET optimizer_switch = 'materialization=off'; +CREATE TABLE t1 ( c INT ) ENGINE=MyISAM; +INSERT INTO t1 VALUES +(0),(1),(2),(3),(4),(5), +(6),(7),(8),(9),(10),(11),(12); +CREATE TABLE t2 ( a INT, b INT, KEY(a)) ENGINE=MyISAM; +INSERT INTO t2 VALUES (3,20),(2,21),(3,22); +SELECT * +FROM t1 AS alias1, t1 AS alias2 +WHERE ( alias1.c, alias2.c ) +IN ( +SELECT alias3.a, alias3.a +FROM t2 AS alias3, t2 alias4 +WHERE alias3.b = alias4.b +); +c c +2 2 +3 3 +set optimizer_prune_level= @opl_901399; +set optimizer_switch= @os_091399; +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 4f8ed7f1643..55074787700 100644 --- a/mysql-test/t/subselect_sj.test +++ b/mysql-test/t/subselect_sj.test @@ -1967,5 +1967,34 @@ SET optimizer_switch=@tmp_optimizer_switch; DROP TABLE t1,t2,t3,t4; +--echo # +--echo # BUG#901399: Wrong result (extra row) with semijoin=ON, materialization=OFF, optimizer_prune_level=0 +--echo # +set @opl_901399= @@optimizer_prune_level; +set @os_091399= @@optimizer_switch; +SET optimizer_prune_level=0; +SET optimizer_switch = 'materialization=off'; + +CREATE TABLE t1 ( c INT ) ENGINE=MyISAM; +INSERT INTO t1 VALUES + (0),(1),(2),(3),(4),(5), + (6),(7),(8),(9),(10),(11),(12); +CREATE TABLE t2 ( a INT, b INT, KEY(a)) ENGINE=MyISAM; +INSERT INTO t2 VALUES (3,20),(2,21),(3,22); + +SELECT * +FROM t1 AS alias1, t1 AS alias2 +WHERE ( alias1.c, alias2.c ) + IN ( + SELECT alias3.a, alias3.a + FROM t2 AS alias3, t2 alias4 + WHERE alias3.b = alias4.b + ); +set optimizer_prune_level= @opl_901399; +set optimizer_switch= @os_091399; + +DROP TABLE t1,t2; + + # The following command must be the last one the file set optimizer_switch=@subselect_sj_tmp; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 7a8f4e854ec..2c17e5dbff6 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -61,7 +61,7 @@ static bool sort_and_filter_keyuse(THD *thd, DYNAMIC_ARRAY *keyuse, bool skip_unprefixed_keyparts); static int sort_keyuse(KEYUSE *a,KEYUSE *b); static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse, - table_map used_tables); + bool allow_full_scan, table_map used_tables); void best_access_path(JOIN *join, JOIN_TAB *s, table_map remaining_tables, uint idx, bool disable_jbuf, double record_count, @@ -3313,7 +3313,7 @@ make_join_statistics(JOIN *join, List &tables_list, s->type= JT_CONST; join->const_table_map|=table->map; set_position(join,const_count++,s,start_keyuse); - if (create_ref_for_key(join, s, start_keyuse, + if (create_ref_for_key(join, s, start_keyuse, FALSE, found_const_table_map)) goto error; if ((tmp=join_read_const_table(s, @@ -7068,15 +7068,21 @@ get_best_combination(JOIN *join) if (j->type == JT_SYSTEM) goto loop_end; - if ( !(keyuse= join->best_positions[tablenr].key) || - (join->best_positions[tablenr].sj_strategy == SJ_OPT_LOOSE_SCAN)) + if ( !(keyuse= join->best_positions[tablenr].key)) { j->type=JT_ALL; - j->index= join->best_positions[tablenr].loosescan_picker.loosescan_key; if (tablenr != join->const_tables) join->full_join=1; } - else if (create_ref_for_key(join, j, keyuse, used_tables)) + + /*if (join->best_positions[tablenr].sj_strategy == SJ_OPT_LOOSE_SCAN) + { + DBUG_ASSERT(!keyuse || keyuse->key == + join->best_positions[tablenr].loosescan_picker.loosescan_key); + j->index= join->best_positions[tablenr].loosescan_picker.loosescan_key; + }*/ + + if (keyuse && create_ref_for_key(join, j, keyuse, TRUE, used_tables)) DBUG_RETURN(TRUE); // Something went wrong if ((j->type == JT_REF || j->type == JT_EQ_REF) && @@ -7249,7 +7255,8 @@ static bool are_tables_local(JOIN_TAB *jtab, table_map used_tables) } static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, - KEYUSE *org_keyuse, table_map used_tables) + KEYUSE *org_keyuse, bool allow_full_scan, + table_map used_tables) { uint keyparts, length, key; TABLE *table; @@ -7307,6 +7314,14 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, keyuse++; } while (keyuse->table == table && keyuse->key == key); } /* not ftkey */ + + if (!keyparts && allow_full_scan) + { + /* It's a LooseIndexScan strategy scanning whole index */ + j->type= JT_ALL; + j->index= key; + DBUG_RETURN(FALSE); + } /* set up fieldref */ j->ref.key_parts= keyparts; @@ -15188,7 +15203,7 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records) join_tab->loosescan_match_tab->found_match) { KEY *key= join_tab->table->key_info + join_tab->index; - key_copy(join_tab->loosescan_buf, info->record, key, + key_copy(join_tab->loosescan_buf, join_tab->table->record[0], key, join_tab->loosescan_key_len); skip_over= TRUE; } @@ -17571,7 +17586,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit_arg, while (keyuse->key != new_ref_key && keyuse->table == tab->table) keyuse++; - if (create_ref_for_key(tab->join, tab, keyuse, + if (create_ref_for_key(tab->join, tab, keyuse, FALSE, tab->join->const_table_map)) goto use_filesort; diff --git a/sql/sql_select.h b/sql/sql_select.h index 99ed8abc04b..ad4607a4b78 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -296,7 +296,16 @@ typedef struct st_join_table { double partial_join_cardinality; table_map dependent,key_dependent; - uint use_quick,index; + /* + 1 - use quick select + 2 - use "Range checked for each record" + */ + uint use_quick; + /* + Index to use. Note: this is valid only for 'index' access, but not range or + ref access. + */ + uint index; uint status; ///< Save status for cache uint used_fields; ulong used_fieldlength; From 56125a3bceb7a375610d4f4c04c9465fa324d516 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Fri, 16 Dec 2011 10:21:46 +0400 Subject: [PATCH 218/288] GIS issues fixed. Failures on SUN Solaris. Buggy compiler there required some extra initialization for variables. Then the 02 optimization leads to bugs when values set through the pointer are not always taken into account. Finally, the (long long) / (long) crashes there, the explicit typeconverstion added. Failing innodb_plunin.innodb_gis.test fixed. per-file comments: mysql-test/suite/innodb_plugin/t/innodb_gis.test GIS issues fixed. sql/gcalc_slicescan.cc GIS issues fixed. sql/gcalc_tools.cc GIS issues fixed. --- mysql-test/suite/innodb_plugin/t/innodb_gis.test | 1 + sql/gcalc_slicescan.cc | 2 +- sql/gcalc_tools.cc | 5 +++++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/mysql-test/suite/innodb_plugin/t/innodb_gis.test b/mysql-test/suite/innodb_plugin/t/innodb_gis.test index dec0c8bf725..6869f179fd7 100644 --- a/mysql-test/suite/innodb_plugin/t/innodb_gis.test +++ b/mysql-test/suite/innodb_plugin/t/innodb_gis.test @@ -1,3 +1,4 @@ +-- source include/have_innodb_plugin.inc SET storage_engine=innodb; --source include/gis_generic.inc --source include/gis_keys.inc diff --git a/sql/gcalc_slicescan.cc b/sql/gcalc_slicescan.cc index 3c02bf62e53..9e88f0a00ad 100644 --- a/sql/gcalc_slicescan.cc +++ b/sql/gcalc_slicescan.cc @@ -432,7 +432,7 @@ void gcalc_mul_coord(Gcalc_internal_coord *result, int result_len, gcalc_coord2 cur_b= n_b ? b[n_b] : FIRST_DIGIT(b[0]); gcalc_coord2 mul= cur_a * cur_b + carry + result[n_a + n_b + 1]; result[n_a + n_b + 1]= mul % GCALC_DIG_BASE; - carry= (gcalc_digit_t) (mul / GCALC_DIG_BASE); + carry= (gcalc_digit_t) (mul / (gcalc_coord2) GCALC_DIG_BASE); } while (n_b--); if (carry) { diff --git a/sql/gcalc_tools.cc b/sql/gcalc_tools.cc index 8af94039c2d..729b322769c 100644 --- a/sql/gcalc_tools.cc +++ b/sql/gcalc_tools.cc @@ -1353,6 +1353,10 @@ int Gcalc_operation_reducer::get_result(Gcalc_result_receiver *storage) GCALC_DBUG_ENTER("Gcalc_operation_reducer::get_result"); *m_res_hook= NULL; + /* This is to workaround an old gcc's bug */ + if (m_res_hook == (Gcalc_dyn_list::Item **) &m_result) + goto done; + while (m_result) { Gcalc_function::shape_type shape= m_result->type; @@ -1403,6 +1407,7 @@ int Gcalc_operation_reducer::get_result(Gcalc_result_receiver *storage) } } +done: m_res_hook= (Gcalc_dyn_list::Item **)&m_result; storage->done(); GCALC_DBUG_RETURN(0); From a4073c1990b5513730b8c070232f5de080dcd2bf Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Fri, 16 Dec 2011 14:19:58 +0400 Subject: [PATCH 219/288] Update test results for previous push --- mysql-test/r/named_pipe.result | 3 +++ mysql-test/r/shm.result | 3 +++ 2 files changed, 6 insertions(+) diff --git a/mysql-test/r/named_pipe.result b/mysql-test/r/named_pipe.result index dbe552eeeeb..609fb80c811 100644 --- a/mysql-test/r/named_pipe.result +++ b/mysql-test/r/named_pipe.result @@ -1347,6 +1347,8 @@ fld1 fld1 250503 250505 250504 250505 250505 250505 +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; insert into t2 (fld1, companynr) values (999999,99); select t2.companynr,companyname from t2 left join t4 using (companynr) where t4.companynr is null; companynr companyname @@ -1422,6 +1424,7 @@ explain select companynr,companyname from t4 left join t2 using (companynr) wher id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where 1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where +SET optimizer_switch=@save_optimizer_switch; select distinct t2.companynr,t4.companynr from t2,t4 where t2.companynr=t4.companynr+1; companynr companynr 37 36 diff --git a/mysql-test/r/shm.result b/mysql-test/r/shm.result index 4dfb88771aa..f6ce63555d7 100644 --- a/mysql-test/r/shm.result +++ b/mysql-test/r/shm.result @@ -1347,6 +1347,8 @@ fld1 fld1 250503 250505 250504 250505 250505 250505 +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='outer_join_with_cache=off'; insert into t2 (fld1, companynr) values (999999,99); select t2.companynr,companyname from t2 left join t4 using (companynr) where t4.companynr is null; companynr companyname @@ -1422,6 +1424,7 @@ explain select companynr,companyname from t4 left join t2 using (companynr) wher id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where 1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where +SET optimizer_switch=@save_optimizer_switch; select distinct t2.companynr,t4.companynr from t2,t4 where t2.companynr=t4.companynr+1; companynr companynr 37 36 From 2d63ea643b82ea6ed673a3bf42f02197edca98fe Mon Sep 17 00:00:00 2001 From: Joerg Bruehe Date: Fri, 16 Dec 2011 12:31:57 +0100 Subject: [PATCH 220/288] Raise version number after cloning --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index 080de523c1b..fb6155aa0be 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.61], [], [mysql]) +AC_INIT([MySQL Server], [5.1.62], [], [mysql]) AC_CONFIG_SRCDIR([sql/mysqld.cc]) AC_CANONICAL_SYSTEM From b42c3932f83afc80015a1800465548b646d9e749 Mon Sep 17 00:00:00 2001 From: Joerg Bruehe Date: Fri, 16 Dec 2011 12:33:54 +0100 Subject: [PATCH 221/288] Raise version number after cloning --- configure.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.in b/configure.in index a06f726c738..908171ca857 100644 --- a/configure.in +++ b/configure.in @@ -7,7 +7,7 @@ AC_INIT(sql/mysqld.cc) AC_CANONICAL_SYSTEM # The Docs Makefile.am parses this line! # remember to also change ndb version below and update version.c in ndb -AM_INIT_AUTOMAKE(mysql, 5.0.95) +AM_INIT_AUTOMAKE(mysql, 5.0.96) AM_CONFIG_HEADER([include/config.h:config.h.in]) PROTOCOL_VERSION=10 @@ -23,7 +23,7 @@ NDB_SHARED_LIB_VERSION=$NDB_SHARED_LIB_MAJOR_VERSION:0:0 # ndb version NDB_VERSION_MAJOR=5 NDB_VERSION_MINOR=0 -NDB_VERSION_BUILD=95 +NDB_VERSION_BUILD=96 NDB_VERSION_STATUS="" # Set all version vars based on $VERSION. How do we do this more elegant ? From 68dad6776202980f3f8c232acbc52ace7d854723 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Fri, 16 Dec 2011 08:05:14 -0800 Subject: [PATCH 222/288] Adjusted test cases of the suite funcs_1. --- mysql-test/suite/funcs_1/r/innodb_views.result | 3 +++ mysql-test/suite/funcs_1/r/memory_views.result | 3 +++ mysql-test/suite/funcs_1/r/myisam_views-big.result | 3 +++ mysql-test/suite/funcs_1/views/views_master.inc | 6 ++++++ 4 files changed, 15 insertions(+) diff --git a/mysql-test/suite/funcs_1/r/innodb_views.result b/mysql-test/suite/funcs_1/r/innodb_views.result index a335e135a4f..c5c4b01e014 100644 --- a/mysql-test/suite/funcs_1/r/innodb_views.result +++ b/mysql-test/suite/funcs_1/r/innodb_views.result @@ -21081,6 +21081,8 @@ f59 f60 f61 a b 2 double 6 2 2 3 single-f3 6 NULL 3 4 single 4 NULL 4 +set @save_optimizer_switch=@@optimizer_switch; +set optimizer_switch='outer_join_with_cache=off'; Create or replace view test.v1 as Select t1.f59 t1_f59, t2.f59 t2_f59, t1.f60 t1_f60, t2.f60 t2_f60, t1.f61 t1_f61, t2.f61 t2_f61 @@ -21111,6 +21113,7 @@ f59 f60 a b 1 single 1 NULL 2 double 2 2 3 single-f3 3 NULL +set optimizer_switch=@save_optimizer_switch; drop table t1, t2; drop view v1 ; Use test; diff --git a/mysql-test/suite/funcs_1/r/memory_views.result b/mysql-test/suite/funcs_1/r/memory_views.result index ccbd086b71f..27eacf8ee12 100644 --- a/mysql-test/suite/funcs_1/r/memory_views.result +++ b/mysql-test/suite/funcs_1/r/memory_views.result @@ -21083,6 +21083,8 @@ f59 f60 f61 a b 2 double 6 2 2 3 single-f3 6 NULL 3 4 single 4 NULL 4 +set @save_optimizer_switch=@@optimizer_switch; +set optimizer_switch='outer_join_with_cache=off'; Create or replace view test.v1 as Select t1.f59 t1_f59, t2.f59 t2_f59, t1.f60 t1_f60, t2.f60 t2_f60, t1.f61 t1_f61, t2.f61 t2_f61 @@ -21113,6 +21115,7 @@ f59 f60 a b 1 single 1 NULL 2 double 2 2 3 single-f3 3 NULL +set optimizer_switch=@save_optimizer_switch; drop table t1, t2; drop view v1 ; Use test; diff --git a/mysql-test/suite/funcs_1/r/myisam_views-big.result b/mysql-test/suite/funcs_1/r/myisam_views-big.result index 9b07a0ae45b..83363502b26 100644 --- a/mysql-test/suite/funcs_1/r/myisam_views-big.result +++ b/mysql-test/suite/funcs_1/r/myisam_views-big.result @@ -22750,6 +22750,8 @@ f59 f60 f61 a b 2 double 6 2 2 3 single-f3 6 NULL 3 4 single 4 NULL 4 +set @save_optimizer_switch=@@optimizer_switch; +set optimizer_switch='outer_join_with_cache=off'; Create or replace view test.v1 as Select t1.f59 t1_f59, t2.f59 t2_f59, t1.f60 t1_f60, t2.f60 t2_f60, t1.f61 t1_f61, t2.f61 t2_f61 @@ -22780,6 +22782,7 @@ f59 f60 a b 1 single 1 NULL 2 double 2 2 3 single-f3 3 NULL +set optimizer_switch=@save_optimizer_switch; drop table t1, t2; drop view v1 ; Use test; diff --git a/mysql-test/suite/funcs_1/views/views_master.inc b/mysql-test/suite/funcs_1/views/views_master.inc index 5ab8d52629c..1069ba3eaa7 100644 --- a/mysql-test/suite/funcs_1/views/views_master.inc +++ b/mysql-test/suite/funcs_1/views/views_master.inc @@ -2541,6 +2541,10 @@ Select f59, f60, f61, t1.a, t2.b FROM t2 natural left outer join t1; # Testcase 3.3.1.61 ; + +set @save_optimizer_switch=@@optimizer_switch; +set optimizer_switch='outer_join_with_cache=off'; + Create or replace view test.v1 as Select t1.f59 t1_f59, t2.f59 t2_f59, t1.f60 t1_f60, t2.f60 t2_f60, t1.f61 t1_f61, t2.f61 t2_f61 @@ -2558,6 +2562,8 @@ Select * from v1 order by f59 desc; Select f59, f60, a, b FROM t2 natural right outer join t1; +set optimizer_switch=@save_optimizer_switch; + drop table t1, t2; drop view v1 ; From f2f0185a1d9c63f9eedd6dc306c9a3086f5374fe Mon Sep 17 00:00:00 2001 From: Joerg Bruehe Date: Fri, 16 Dec 2011 19:41:35 +0100 Subject: [PATCH 223/288] Raise version number after cloning 5.5.20 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 508f021f35d..d05c93f6e73 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ MYSQL_VERSION_MAJOR=5 MYSQL_VERSION_MINOR=5 -MYSQL_VERSION_PATCH=20 +MYSQL_VERSION_PATCH=21 MYSQL_VERSION_EXTRA= From 2bfd02cea95a774dbc82b51fafa2bf727b9bb0ff Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Sun, 18 Dec 2011 19:25:00 +0400 Subject: [PATCH 224/288] Bump version number: now it's 5.3.3 (5.3.2 has been released some time ago) --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index e430e4f12f3..2435d864162 100644 --- a/configure.in +++ b/configure.in @@ -13,7 +13,7 @@ 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([MariaDB Server], [5.3.2-MariaDB-beta], [], [mysql]) +AC_INIT([MariaDB Server], [5.3.2-MariaDB-rc], [], [mysql]) AC_CONFIG_SRCDIR([sql/mysqld.cc]) AC_CANONICAL_SYSTEM From 7a1406f229df002befeb91f39f57e15444aecb21 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Sun, 18 Dec 2011 23:38:37 -0800 Subject: [PATCH 225/288] Fixed LP bug #904832. Do not perform index condition pushdown for conditions containing subqueries and stored functions. --- mysql-test/include/icp_tests.inc | 108 ++++++++++++++++++++++ mysql-test/r/innodb_icp.result | 107 +++++++++++++++++++++ mysql-test/r/maria_icp.result | 107 +++++++++++++++++++++ mysql-test/r/myisam_icp.result | 107 +++++++++++++++++++++ mysql-test/r/subselect.result | 2 +- mysql-test/r/subselect4.result | 8 +- mysql-test/r/subselect_mat_cost.result | 4 +- mysql-test/r/subselect_no_mat.result | 2 +- mysql-test/r/subselect_no_opts.result | 2 +- mysql-test/r/subselect_no_scache.result | 2 +- mysql-test/r/subselect_no_semijoin.result | 2 +- sql/item.h | 4 + sql/item_func.h | 4 + sql/item_subselect.h | 4 + sql/opt_index_cond_pushdown.cc | 5 + 15 files changed, 457 insertions(+), 11 deletions(-) diff --git a/mysql-test/include/icp_tests.inc b/mysql-test/include/icp_tests.inc index ea4fc6439d2..e77cb220375 100644 --- a/mysql-test/include/icp_tests.inc +++ b/mysql-test/include/icp_tests.inc @@ -437,6 +437,7 @@ LIMIT 1; DROP TABLE t1; +--echo # --echo # --echo # Bug#59259 "Incorrect rows returned for a correlated subquery --echo # when ICP is on" @@ -744,3 +745,110 @@ SELECT a FROM t1 WHERE c IS NULL AND d IS NOT NULL GROUP BY 1; DROP TABLE t1; +--echo # +--echo # Bug#904832: an attempt to perform an index condition pushdown +--echo # of a condition containing a subquery +--echo # + +CREATE TABLE t1 ( + a INT PRIMARY KEY NOT NULL AUTO_INCREMENT, + b INT, c INT, d DATE NOT NULL, e VARCHAR(1), + KEY (c), KEY (d), KEY k2(b), KEY k3(b), KEY k4(b) +); + +INSERT INTO t1 (b,c,d,e) VALUES +(6,5,'2006-05-25','y'),(1,5,'2008-01-23','t'), +(6,5,'2007-06-18','d'),(4,5,'1900-01-01','r'), +(8,5,'1900-01-01','m'),(4,5,'2006-03-09','b'), +(4,5,'2001-06-05','x'),(1,5,'2008-01-23','t'), +(6,5,'2007-06-18','d'),(4,5,'1900-01-01','r'), +(8,5,'1900-01-01','m'),(4,5,'2006-03-09','b'), +(4,5,'2001-06-05','x'),(1,5,'2008-01-23','t'), +(4,5,'1900-01-01','r'),(8,5,'1900-01-01','m'), +(4,5,'2006-03-09','b'),(4,5,'2001-06-05','x'), +(1,5,'2008-01-23','t'),(6,5,'2007-06-18','d'), +(4,5,'1900-01-01','r'),(8,5,'1900-01-01','m'), +(4,5,'2006-03-09','b'),(4,5,'2001-06-05','f'), +(4,5,'2001-06-05','x'),(8,5,'1900-01-01','m'), +(4,5,'2006-03-09','b'),(4,5,'2001-06-05','x'), +(1,5,'2008-01-23','t'),(6,5,'2007-06-18','d'), +(4,5,'1900-01-01','r'),(8,5,'1900-01-01','m'), +(4,5,'2006-03-09','b'),(6,5,'2007-06-18','d'), +(6,5,'2007-06-18','d'),(4,5,'1900-01-01','r'), +(8,5,'1900-01-01','m'),(4,5,'2006-03-09','b'), +(6,5,'2007-06-18','d'),(4,5,'1900-01-01','r'), +(8,5,'1900-01-01','m'),(4,5,'2006-03-09','b'), +(4,5,'2006-03-09','b'),(4,5,'2001-06-05','x'), +(1,5,'2008-01-23','t'),(6,5,'2007-06-18','d'), +(4,5,'1900-01-01','r'),(8,5,'1900-01-01','m'), +(4,5,'2006-03-09','b'),(4,5,'2001-06-05','x'), +(4,5,'2001-06-05','x'),(1,5,'2008-01-23','t'), +(6,5,'2007-06-18','d'),(4,5,'1900-01-01','r'), +(8,5,'1900-01-01','m'),(4,5,'2006-03-09','b'), +(4,5,'2001-06-05','x'),(1,5,'2008-01-23','t'), +(6,5,'2007-06-18','d'),(4,1,'1900-01-01','r'), +(8,8,'1900-01-01','m'),(4,1,'2006-03-09','b'), +(4,1,'2001-06-05','x'),(7,1,'2006-05-28','g'); + +CREATE TABLE t2 ( + f INT PRIMARY KEY NOT NULL AUTO_INCREMENT, + g INT, + h VARCHAR(1), + KEY (g) +); + +INSERT INTO t2 (g,h) VALUES +(3,'e'),(1,'u'),(4,'v'),(9,'u'),(6,'i'),(1,'x'), +(5,'l'),(8,'y'),(0,'p'),(0,'f'),(0,'p'),(7,'d'), +(7,'f'),(5,'j'),(3,'e'),(1,'u'),(4,'v'),(9,'u'), +(6,'i'),(1,'x'),(5,'l'),(8,'y'),(0,'p'),(0,'f'), +(0,'p'),(0,'f'),(0,'p'),(7,'d'),(7,'f'),(5,'j'), +(3,'e'),(1,'u'),(4,'v'),(9,'u'),(6,'i'),(1,'x'), +(7,'d'),(7,'f'),(5,'j'),(3,'e'),(1,'u'),(4,'v'), +(9,'u'),(6,'i'),(1,'x'),(5,'l'),(8,'y'),(0,'p'), +(0,'f'),(0,'p'),(7,'d'),(7,'f'),(5,'j'),(3,'e'), +(1,'u'),(4,'v'),(9,'u'),(6,'i'),(1,'x'),(5,'l'), +(6,'q'),(2,'n'),(4,'r'),(4,'b'),(8,'y'),(0,'p'), +(0,'f'),(0,'p'),(7,'d'),(7,'f'),(5,'j'),(3,'e'), +(1,'u'),(4,'v'),(9,'u'),(6,'i'),(1,'x'),(5,'l'), +(8,'y'),(0,'p'),(0,'f'),(0,'p'),(7,'d'),(7,'f'), +(5,'j'),(3,'e'),(1,'u'),(4,'v'),(9,'u'),(6,'i'), +(1,'x'),(5,'l'),(8,'y'),(0,'p'),(0,'f'),(0,'p'), +(0,'f'),(0,'p'),(7,'d'),(7,'f'),(5,'j'),(3,'e'), +(1,'u'),(4,'v'),(9,'u'),(6,'i'),(1,'x'),(7,'d'), +(7,'f'),(5,'j'),(3,'e'),(1,'u'),(0,'f'),(0,'p'), +(7,'d'),(7,'f'),(5,'j'),(3,'e'),(1,'u'),(4,'v'), +(9,'u'),(6,'i'),(1,'x'),(5,'l'),(8,'y'),(0,'p'), +(0,'f'),(0,'p'),(0,'f'),(0,'p'),(7,'d'),(7,'f'), +(5,'j'),(3,'e'),(1,'u'),(4,'v'),(9,'u'),(6,'i'), +(1,'x'),(7,'d'),(7,'f'),(5,'j'),(3,'e'),(1,'u'), +(4,'v'),(9,'u'),(6,'i'),(1,'x'),(5,'l'),(8,'y'), +(0,'p'),(0,'f'),(0,'p'),(7,'d'),(7,'f'),(5,'j'), +(3,'e'),(1,'u'),(4,'v'),(9,'u'),(6,'i'),(1,'x'), +(5,'l'),(6,'q'),(2,'n'),(4,'r'),(4,'b'),(8,'y'), +(0,'p'),(0,'f'),(0,'p'),(7,'d'),(7,'f'),(5,'j'), +(3,'e'),(1,'u'),(4,'v'),(9,'u'),(6,'i'),(1,'x'), +(7,'f'),(5,'j'),(3,'e'),(1,'u'),(4,'v'),(9,'u'); + +SET @save_optimize_switch=@@optimizer_switch; +SET optimizer_switch='materialization=on'; + +EXPLAIN +SELECT COUNT(*) FROM t1 AS t, t2 +WHERE c = g + AND (EXISTS (SELECT * FROM t1, t2 WHERE a = f AND h <= t.e AND a > t.b) + OR a = 0 AND h < 'z' ); + +SELECT COUNT(*) FROM t1 AS t, t2 +WHERE c = g + AND (EXISTS (SELECT * FROM t1, t2 WHERE a = f AND h <= t.e AND a > t.b) + OR a = 0 AND h < 'z' ); +SELECT COUNT(*) FROM t1 AS t, t2 +WHERE c = g + AND (EXISTS (SELECT * FROM t1, t2 WHERE a = f AND h <= t.e AND a > t.b) + OR a = 0 AND h < 'z' ); + +SET optimizer_switch=@save_optimizer_switch; + +DROP TABLE t1,t2; + diff --git a/mysql-test/r/innodb_icp.result b/mysql-test/r/innodb_icp.result index b3b59bcdea6..5046b7b4b8b 100644 --- a/mysql-test/r/innodb_icp.result +++ b/mysql-test/r/innodb_icp.result @@ -412,6 +412,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range PRIMARY,k1 k1 5 NULL 3 Using where; Using index DROP TABLE t1; # +# # Bug#59259 "Incorrect rows returned for a correlated subquery # when ICP is on" # @@ -701,5 +702,111 @@ SET SESSION optimizer_switch='index_condition_pushdown=on'; SELECT a FROM t1 WHERE c IS NULL AND d IS NOT NULL GROUP BY 1; a DROP TABLE t1; +# +# Bug#904832: an attempt to perform an index condition pushdown +# of a condition containing a subquery +# +CREATE TABLE t1 ( +a INT PRIMARY KEY NOT NULL AUTO_INCREMENT, +b INT, c INT, d DATE NOT NULL, e VARCHAR(1), +KEY (c), KEY (d), KEY k2(b), KEY k3(b), KEY k4(b) +); +INSERT INTO t1 (b,c,d,e) VALUES +(6,5,'2006-05-25','y'),(1,5,'2008-01-23','t'), +(6,5,'2007-06-18','d'),(4,5,'1900-01-01','r'), +(8,5,'1900-01-01','m'),(4,5,'2006-03-09','b'), +(4,5,'2001-06-05','x'),(1,5,'2008-01-23','t'), +(6,5,'2007-06-18','d'),(4,5,'1900-01-01','r'), +(8,5,'1900-01-01','m'),(4,5,'2006-03-09','b'), +(4,5,'2001-06-05','x'),(1,5,'2008-01-23','t'), +(4,5,'1900-01-01','r'),(8,5,'1900-01-01','m'), +(4,5,'2006-03-09','b'),(4,5,'2001-06-05','x'), +(1,5,'2008-01-23','t'),(6,5,'2007-06-18','d'), +(4,5,'1900-01-01','r'),(8,5,'1900-01-01','m'), +(4,5,'2006-03-09','b'),(4,5,'2001-06-05','f'), +(4,5,'2001-06-05','x'),(8,5,'1900-01-01','m'), +(4,5,'2006-03-09','b'),(4,5,'2001-06-05','x'), +(1,5,'2008-01-23','t'),(6,5,'2007-06-18','d'), +(4,5,'1900-01-01','r'),(8,5,'1900-01-01','m'), +(4,5,'2006-03-09','b'),(6,5,'2007-06-18','d'), +(6,5,'2007-06-18','d'),(4,5,'1900-01-01','r'), +(8,5,'1900-01-01','m'),(4,5,'2006-03-09','b'), +(6,5,'2007-06-18','d'),(4,5,'1900-01-01','r'), +(8,5,'1900-01-01','m'),(4,5,'2006-03-09','b'), +(4,5,'2006-03-09','b'),(4,5,'2001-06-05','x'), +(1,5,'2008-01-23','t'),(6,5,'2007-06-18','d'), +(4,5,'1900-01-01','r'),(8,5,'1900-01-01','m'), +(4,5,'2006-03-09','b'),(4,5,'2001-06-05','x'), +(4,5,'2001-06-05','x'),(1,5,'2008-01-23','t'), +(6,5,'2007-06-18','d'),(4,5,'1900-01-01','r'), +(8,5,'1900-01-01','m'),(4,5,'2006-03-09','b'), +(4,5,'2001-06-05','x'),(1,5,'2008-01-23','t'), +(6,5,'2007-06-18','d'),(4,1,'1900-01-01','r'), +(8,8,'1900-01-01','m'),(4,1,'2006-03-09','b'), +(4,1,'2001-06-05','x'),(7,1,'2006-05-28','g'); +CREATE TABLE t2 ( +f INT PRIMARY KEY NOT NULL AUTO_INCREMENT, +g INT, +h VARCHAR(1), +KEY (g) +); +INSERT INTO t2 (g,h) VALUES +(3,'e'),(1,'u'),(4,'v'),(9,'u'),(6,'i'),(1,'x'), +(5,'l'),(8,'y'),(0,'p'),(0,'f'),(0,'p'),(7,'d'), +(7,'f'),(5,'j'),(3,'e'),(1,'u'),(4,'v'),(9,'u'), +(6,'i'),(1,'x'),(5,'l'),(8,'y'),(0,'p'),(0,'f'), +(0,'p'),(0,'f'),(0,'p'),(7,'d'),(7,'f'),(5,'j'), +(3,'e'),(1,'u'),(4,'v'),(9,'u'),(6,'i'),(1,'x'), +(7,'d'),(7,'f'),(5,'j'),(3,'e'),(1,'u'),(4,'v'), +(9,'u'),(6,'i'),(1,'x'),(5,'l'),(8,'y'),(0,'p'), +(0,'f'),(0,'p'),(7,'d'),(7,'f'),(5,'j'),(3,'e'), +(1,'u'),(4,'v'),(9,'u'),(6,'i'),(1,'x'),(5,'l'), +(6,'q'),(2,'n'),(4,'r'),(4,'b'),(8,'y'),(0,'p'), +(0,'f'),(0,'p'),(7,'d'),(7,'f'),(5,'j'),(3,'e'), +(1,'u'),(4,'v'),(9,'u'),(6,'i'),(1,'x'),(5,'l'), +(8,'y'),(0,'p'),(0,'f'),(0,'p'),(7,'d'),(7,'f'), +(5,'j'),(3,'e'),(1,'u'),(4,'v'),(9,'u'),(6,'i'), +(1,'x'),(5,'l'),(8,'y'),(0,'p'),(0,'f'),(0,'p'), +(0,'f'),(0,'p'),(7,'d'),(7,'f'),(5,'j'),(3,'e'), +(1,'u'),(4,'v'),(9,'u'),(6,'i'),(1,'x'),(7,'d'), +(7,'f'),(5,'j'),(3,'e'),(1,'u'),(0,'f'),(0,'p'), +(7,'d'),(7,'f'),(5,'j'),(3,'e'),(1,'u'),(4,'v'), +(9,'u'),(6,'i'),(1,'x'),(5,'l'),(8,'y'),(0,'p'), +(0,'f'),(0,'p'),(0,'f'),(0,'p'),(7,'d'),(7,'f'), +(5,'j'),(3,'e'),(1,'u'),(4,'v'),(9,'u'),(6,'i'), +(1,'x'),(7,'d'),(7,'f'),(5,'j'),(3,'e'),(1,'u'), +(4,'v'),(9,'u'),(6,'i'),(1,'x'),(5,'l'),(8,'y'), +(0,'p'),(0,'f'),(0,'p'),(7,'d'),(7,'f'),(5,'j'), +(3,'e'),(1,'u'),(4,'v'),(9,'u'),(6,'i'),(1,'x'), +(5,'l'),(6,'q'),(2,'n'),(4,'r'),(4,'b'),(8,'y'), +(0,'p'),(0,'f'),(0,'p'),(7,'d'),(7,'f'),(5,'j'), +(3,'e'),(1,'u'),(4,'v'),(9,'u'),(6,'i'),(1,'x'), +(7,'f'),(5,'j'),(3,'e'),(1,'u'),(4,'v'),(9,'u'); +SET @save_optimize_switch=@@optimizer_switch; +SET optimizer_switch='materialization=on'; +EXPLAIN +SELECT COUNT(*) FROM t1 AS t, t2 +WHERE c = g +AND (EXISTS (SELECT * FROM t1, t2 WHERE a = f AND h <= t.e AND a > t.b) +OR a = 0 AND h < 'z' ); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t ALL PRIMARY,c NULL NULL NULL 64 Using where +1 PRIMARY t2 ref g g 5 test.t.c 9 Using where +2 DEPENDENT SUBQUERY t1 index PRIMARY d 3 NULL 64 Using where; Using index +2 DEPENDENT SUBQUERY t2 eq_ref PRIMARY PRIMARY 4 test.t1.a 1 Using index condition; Using where +SELECT COUNT(*) FROM t1 AS t, t2 +WHERE c = g +AND (EXISTS (SELECT * FROM t1, t2 WHERE a = f AND h <= t.e AND a > t.b) +OR a = 0 AND h < 'z' ); +COUNT(*) +1478 +SELECT COUNT(*) FROM t1 AS t, t2 +WHERE c = g +AND (EXISTS (SELECT * FROM t1, t2 WHERE a = f AND h <= t.e AND a > t.b) +OR a = 0 AND h < 'z' ); +COUNT(*) +1478 +SET optimizer_switch=@save_optimizer_switch; +DROP TABLE t1,t2; set optimizer_switch=@innodb_icp_tmp; set storage_engine= @save_storage_engine; diff --git a/mysql-test/r/maria_icp.result b/mysql-test/r/maria_icp.result index 2d755daf0d6..c0275d41d43 100644 --- a/mysql-test/r/maria_icp.result +++ b/mysql-test/r/maria_icp.result @@ -412,6 +412,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range PRIMARY,k1 k1 5 NULL 4 Using where DROP TABLE t1; # +# # Bug#59259 "Incorrect rows returned for a correlated subquery # when ICP is on" # @@ -707,5 +708,111 @@ SET SESSION optimizer_switch='index_condition_pushdown=on'; SELECT a FROM t1 WHERE c IS NULL AND d IS NOT NULL GROUP BY 1; a DROP TABLE t1; +# +# Bug#904832: an attempt to perform an index condition pushdown +# of a condition containing a subquery +# +CREATE TABLE t1 ( +a INT PRIMARY KEY NOT NULL AUTO_INCREMENT, +b INT, c INT, d DATE NOT NULL, e VARCHAR(1), +KEY (c), KEY (d), KEY k2(b), KEY k3(b), KEY k4(b) +); +INSERT INTO t1 (b,c,d,e) VALUES +(6,5,'2006-05-25','y'),(1,5,'2008-01-23','t'), +(6,5,'2007-06-18','d'),(4,5,'1900-01-01','r'), +(8,5,'1900-01-01','m'),(4,5,'2006-03-09','b'), +(4,5,'2001-06-05','x'),(1,5,'2008-01-23','t'), +(6,5,'2007-06-18','d'),(4,5,'1900-01-01','r'), +(8,5,'1900-01-01','m'),(4,5,'2006-03-09','b'), +(4,5,'2001-06-05','x'),(1,5,'2008-01-23','t'), +(4,5,'1900-01-01','r'),(8,5,'1900-01-01','m'), +(4,5,'2006-03-09','b'),(4,5,'2001-06-05','x'), +(1,5,'2008-01-23','t'),(6,5,'2007-06-18','d'), +(4,5,'1900-01-01','r'),(8,5,'1900-01-01','m'), +(4,5,'2006-03-09','b'),(4,5,'2001-06-05','f'), +(4,5,'2001-06-05','x'),(8,5,'1900-01-01','m'), +(4,5,'2006-03-09','b'),(4,5,'2001-06-05','x'), +(1,5,'2008-01-23','t'),(6,5,'2007-06-18','d'), +(4,5,'1900-01-01','r'),(8,5,'1900-01-01','m'), +(4,5,'2006-03-09','b'),(6,5,'2007-06-18','d'), +(6,5,'2007-06-18','d'),(4,5,'1900-01-01','r'), +(8,5,'1900-01-01','m'),(4,5,'2006-03-09','b'), +(6,5,'2007-06-18','d'),(4,5,'1900-01-01','r'), +(8,5,'1900-01-01','m'),(4,5,'2006-03-09','b'), +(4,5,'2006-03-09','b'),(4,5,'2001-06-05','x'), +(1,5,'2008-01-23','t'),(6,5,'2007-06-18','d'), +(4,5,'1900-01-01','r'),(8,5,'1900-01-01','m'), +(4,5,'2006-03-09','b'),(4,5,'2001-06-05','x'), +(4,5,'2001-06-05','x'),(1,5,'2008-01-23','t'), +(6,5,'2007-06-18','d'),(4,5,'1900-01-01','r'), +(8,5,'1900-01-01','m'),(4,5,'2006-03-09','b'), +(4,5,'2001-06-05','x'),(1,5,'2008-01-23','t'), +(6,5,'2007-06-18','d'),(4,1,'1900-01-01','r'), +(8,8,'1900-01-01','m'),(4,1,'2006-03-09','b'), +(4,1,'2001-06-05','x'),(7,1,'2006-05-28','g'); +CREATE TABLE t2 ( +f INT PRIMARY KEY NOT NULL AUTO_INCREMENT, +g INT, +h VARCHAR(1), +KEY (g) +); +INSERT INTO t2 (g,h) VALUES +(3,'e'),(1,'u'),(4,'v'),(9,'u'),(6,'i'),(1,'x'), +(5,'l'),(8,'y'),(0,'p'),(0,'f'),(0,'p'),(7,'d'), +(7,'f'),(5,'j'),(3,'e'),(1,'u'),(4,'v'),(9,'u'), +(6,'i'),(1,'x'),(5,'l'),(8,'y'),(0,'p'),(0,'f'), +(0,'p'),(0,'f'),(0,'p'),(7,'d'),(7,'f'),(5,'j'), +(3,'e'),(1,'u'),(4,'v'),(9,'u'),(6,'i'),(1,'x'), +(7,'d'),(7,'f'),(5,'j'),(3,'e'),(1,'u'),(4,'v'), +(9,'u'),(6,'i'),(1,'x'),(5,'l'),(8,'y'),(0,'p'), +(0,'f'),(0,'p'),(7,'d'),(7,'f'),(5,'j'),(3,'e'), +(1,'u'),(4,'v'),(9,'u'),(6,'i'),(1,'x'),(5,'l'), +(6,'q'),(2,'n'),(4,'r'),(4,'b'),(8,'y'),(0,'p'), +(0,'f'),(0,'p'),(7,'d'),(7,'f'),(5,'j'),(3,'e'), +(1,'u'),(4,'v'),(9,'u'),(6,'i'),(1,'x'),(5,'l'), +(8,'y'),(0,'p'),(0,'f'),(0,'p'),(7,'d'),(7,'f'), +(5,'j'),(3,'e'),(1,'u'),(4,'v'),(9,'u'),(6,'i'), +(1,'x'),(5,'l'),(8,'y'),(0,'p'),(0,'f'),(0,'p'), +(0,'f'),(0,'p'),(7,'d'),(7,'f'),(5,'j'),(3,'e'), +(1,'u'),(4,'v'),(9,'u'),(6,'i'),(1,'x'),(7,'d'), +(7,'f'),(5,'j'),(3,'e'),(1,'u'),(0,'f'),(0,'p'), +(7,'d'),(7,'f'),(5,'j'),(3,'e'),(1,'u'),(4,'v'), +(9,'u'),(6,'i'),(1,'x'),(5,'l'),(8,'y'),(0,'p'), +(0,'f'),(0,'p'),(0,'f'),(0,'p'),(7,'d'),(7,'f'), +(5,'j'),(3,'e'),(1,'u'),(4,'v'),(9,'u'),(6,'i'), +(1,'x'),(7,'d'),(7,'f'),(5,'j'),(3,'e'),(1,'u'), +(4,'v'),(9,'u'),(6,'i'),(1,'x'),(5,'l'),(8,'y'), +(0,'p'),(0,'f'),(0,'p'),(7,'d'),(7,'f'),(5,'j'), +(3,'e'),(1,'u'),(4,'v'),(9,'u'),(6,'i'),(1,'x'), +(5,'l'),(6,'q'),(2,'n'),(4,'r'),(4,'b'),(8,'y'), +(0,'p'),(0,'f'),(0,'p'),(7,'d'),(7,'f'),(5,'j'), +(3,'e'),(1,'u'),(4,'v'),(9,'u'),(6,'i'),(1,'x'), +(7,'f'),(5,'j'),(3,'e'),(1,'u'),(4,'v'),(9,'u'); +SET @save_optimize_switch=@@optimizer_switch; +SET optimizer_switch='materialization=on'; +EXPLAIN +SELECT COUNT(*) FROM t1 AS t, t2 +WHERE c = g +AND (EXISTS (SELECT * FROM t1, t2 WHERE a = f AND h <= t.e AND a > t.b) +OR a = 0 AND h < 'z' ); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t ALL PRIMARY,c NULL NULL NULL 64 Using where +1 PRIMARY t2 ref g g 5 test.t.c 19 Using where +2 DEPENDENT SUBQUERY t1 index PRIMARY PRIMARY 4 NULL 64 Using where; Using index +2 DEPENDENT SUBQUERY t2 eq_ref PRIMARY PRIMARY 4 test.t1.a 1 Using index condition; Using where +SELECT COUNT(*) FROM t1 AS t, t2 +WHERE c = g +AND (EXISTS (SELECT * FROM t1, t2 WHERE a = f AND h <= t.e AND a > t.b) +OR a = 0 AND h < 'z' ); +COUNT(*) +1478 +SELECT COUNT(*) FROM t1 AS t, t2 +WHERE c = g +AND (EXISTS (SELECT * FROM t1, t2 WHERE a = f AND h <= t.e AND a > t.b) +OR a = 0 AND h < 'z' ); +COUNT(*) +1478 +SET optimizer_switch=@save_optimizer_switch; +DROP TABLE t1,t2; set storage_engine= @save_storage_engine; set optimizer_switch=@maria_icp_tmp; diff --git a/mysql-test/r/myisam_icp.result b/mysql-test/r/myisam_icp.result index 753db6d6fc3..68d0ce4e381 100644 --- a/mysql-test/r/myisam_icp.result +++ b/mysql-test/r/myisam_icp.result @@ -410,6 +410,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range PRIMARY,k1 k1 5 NULL 4 Using where DROP TABLE t1; # +# # Bug#59259 "Incorrect rows returned for a correlated subquery # when ICP is on" # @@ -705,6 +706,112 @@ SET SESSION optimizer_switch='index_condition_pushdown=on'; SELECT a FROM t1 WHERE c IS NULL AND d IS NOT NULL GROUP BY 1; a DROP TABLE t1; +# +# Bug#904832: an attempt to perform an index condition pushdown +# of a condition containing a subquery +# +CREATE TABLE t1 ( +a INT PRIMARY KEY NOT NULL AUTO_INCREMENT, +b INT, c INT, d DATE NOT NULL, e VARCHAR(1), +KEY (c), KEY (d), KEY k2(b), KEY k3(b), KEY k4(b) +); +INSERT INTO t1 (b,c,d,e) VALUES +(6,5,'2006-05-25','y'),(1,5,'2008-01-23','t'), +(6,5,'2007-06-18','d'),(4,5,'1900-01-01','r'), +(8,5,'1900-01-01','m'),(4,5,'2006-03-09','b'), +(4,5,'2001-06-05','x'),(1,5,'2008-01-23','t'), +(6,5,'2007-06-18','d'),(4,5,'1900-01-01','r'), +(8,5,'1900-01-01','m'),(4,5,'2006-03-09','b'), +(4,5,'2001-06-05','x'),(1,5,'2008-01-23','t'), +(4,5,'1900-01-01','r'),(8,5,'1900-01-01','m'), +(4,5,'2006-03-09','b'),(4,5,'2001-06-05','x'), +(1,5,'2008-01-23','t'),(6,5,'2007-06-18','d'), +(4,5,'1900-01-01','r'),(8,5,'1900-01-01','m'), +(4,5,'2006-03-09','b'),(4,5,'2001-06-05','f'), +(4,5,'2001-06-05','x'),(8,5,'1900-01-01','m'), +(4,5,'2006-03-09','b'),(4,5,'2001-06-05','x'), +(1,5,'2008-01-23','t'),(6,5,'2007-06-18','d'), +(4,5,'1900-01-01','r'),(8,5,'1900-01-01','m'), +(4,5,'2006-03-09','b'),(6,5,'2007-06-18','d'), +(6,5,'2007-06-18','d'),(4,5,'1900-01-01','r'), +(8,5,'1900-01-01','m'),(4,5,'2006-03-09','b'), +(6,5,'2007-06-18','d'),(4,5,'1900-01-01','r'), +(8,5,'1900-01-01','m'),(4,5,'2006-03-09','b'), +(4,5,'2006-03-09','b'),(4,5,'2001-06-05','x'), +(1,5,'2008-01-23','t'),(6,5,'2007-06-18','d'), +(4,5,'1900-01-01','r'),(8,5,'1900-01-01','m'), +(4,5,'2006-03-09','b'),(4,5,'2001-06-05','x'), +(4,5,'2001-06-05','x'),(1,5,'2008-01-23','t'), +(6,5,'2007-06-18','d'),(4,5,'1900-01-01','r'), +(8,5,'1900-01-01','m'),(4,5,'2006-03-09','b'), +(4,5,'2001-06-05','x'),(1,5,'2008-01-23','t'), +(6,5,'2007-06-18','d'),(4,1,'1900-01-01','r'), +(8,8,'1900-01-01','m'),(4,1,'2006-03-09','b'), +(4,1,'2001-06-05','x'),(7,1,'2006-05-28','g'); +CREATE TABLE t2 ( +f INT PRIMARY KEY NOT NULL AUTO_INCREMENT, +g INT, +h VARCHAR(1), +KEY (g) +); +INSERT INTO t2 (g,h) VALUES +(3,'e'),(1,'u'),(4,'v'),(9,'u'),(6,'i'),(1,'x'), +(5,'l'),(8,'y'),(0,'p'),(0,'f'),(0,'p'),(7,'d'), +(7,'f'),(5,'j'),(3,'e'),(1,'u'),(4,'v'),(9,'u'), +(6,'i'),(1,'x'),(5,'l'),(8,'y'),(0,'p'),(0,'f'), +(0,'p'),(0,'f'),(0,'p'),(7,'d'),(7,'f'),(5,'j'), +(3,'e'),(1,'u'),(4,'v'),(9,'u'),(6,'i'),(1,'x'), +(7,'d'),(7,'f'),(5,'j'),(3,'e'),(1,'u'),(4,'v'), +(9,'u'),(6,'i'),(1,'x'),(5,'l'),(8,'y'),(0,'p'), +(0,'f'),(0,'p'),(7,'d'),(7,'f'),(5,'j'),(3,'e'), +(1,'u'),(4,'v'),(9,'u'),(6,'i'),(1,'x'),(5,'l'), +(6,'q'),(2,'n'),(4,'r'),(4,'b'),(8,'y'),(0,'p'), +(0,'f'),(0,'p'),(7,'d'),(7,'f'),(5,'j'),(3,'e'), +(1,'u'),(4,'v'),(9,'u'),(6,'i'),(1,'x'),(5,'l'), +(8,'y'),(0,'p'),(0,'f'),(0,'p'),(7,'d'),(7,'f'), +(5,'j'),(3,'e'),(1,'u'),(4,'v'),(9,'u'),(6,'i'), +(1,'x'),(5,'l'),(8,'y'),(0,'p'),(0,'f'),(0,'p'), +(0,'f'),(0,'p'),(7,'d'),(7,'f'),(5,'j'),(3,'e'), +(1,'u'),(4,'v'),(9,'u'),(6,'i'),(1,'x'),(7,'d'), +(7,'f'),(5,'j'),(3,'e'),(1,'u'),(0,'f'),(0,'p'), +(7,'d'),(7,'f'),(5,'j'),(3,'e'),(1,'u'),(4,'v'), +(9,'u'),(6,'i'),(1,'x'),(5,'l'),(8,'y'),(0,'p'), +(0,'f'),(0,'p'),(0,'f'),(0,'p'),(7,'d'),(7,'f'), +(5,'j'),(3,'e'),(1,'u'),(4,'v'),(9,'u'),(6,'i'), +(1,'x'),(7,'d'),(7,'f'),(5,'j'),(3,'e'),(1,'u'), +(4,'v'),(9,'u'),(6,'i'),(1,'x'),(5,'l'),(8,'y'), +(0,'p'),(0,'f'),(0,'p'),(7,'d'),(7,'f'),(5,'j'), +(3,'e'),(1,'u'),(4,'v'),(9,'u'),(6,'i'),(1,'x'), +(5,'l'),(6,'q'),(2,'n'),(4,'r'),(4,'b'),(8,'y'), +(0,'p'),(0,'f'),(0,'p'),(7,'d'),(7,'f'),(5,'j'), +(3,'e'),(1,'u'),(4,'v'),(9,'u'),(6,'i'),(1,'x'), +(7,'f'),(5,'j'),(3,'e'),(1,'u'),(4,'v'),(9,'u'); +SET @save_optimize_switch=@@optimizer_switch; +SET optimizer_switch='materialization=on'; +EXPLAIN +SELECT COUNT(*) FROM t1 AS t, t2 +WHERE c = g +AND (EXISTS (SELECT * FROM t1, t2 WHERE a = f AND h <= t.e AND a > t.b) +OR a = 0 AND h < 'z' ); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t ALL PRIMARY,c NULL NULL NULL 64 Using where +1 PRIMARY t2 ref g g 5 test.t.c 19 Using where +2 DEPENDENT SUBQUERY t1 index PRIMARY PRIMARY 4 NULL 64 Using where; Using index +2 DEPENDENT SUBQUERY t2 eq_ref PRIMARY PRIMARY 4 test.t1.a 1 Using index condition; Using where +SELECT COUNT(*) FROM t1 AS t, t2 +WHERE c = g +AND (EXISTS (SELECT * FROM t1, t2 WHERE a = f AND h <= t.e AND a > t.b) +OR a = 0 AND h < 'z' ); +COUNT(*) +1478 +SELECT COUNT(*) FROM t1 AS t, t2 +WHERE c = g +AND (EXISTS (SELECT * FROM t1, t2 WHERE a = f AND h <= t.e AND a > t.b) +OR a = 0 AND h < 'z' ); +COUNT(*) +1478 +SET optimizer_switch=@save_optimizer_switch; +DROP TABLE t1,t2; drop table if exists t0, t1, t1i, t1m; # # BUG#826935 Assertion `!table || (!table->read_set || bitmap_is_set(table->read_set, field_index))' failed diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 58a4e61ce0b..8008d887823 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -1374,7 +1374,7 @@ create table t1 (id int not null auto_increment primary key, salary int, key(sal insert into t1 (salary) values (100),(1000),(10000),(10),(500),(5000),(50000); explain extended SELECT id FROM t1 where salary = (SELECT MAX(salary) FROM t1); id select_type table type possible_keys key key_len ref rows filtered Extra -1 PRIMARY t1 ref salary salary 5 const 0 0.00 Using index condition +1 PRIMARY t1 ref salary salary 5 const 0 0.00 Using where 2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL Select tables optimized away Warnings: Note 1003 select `test`.`t1`.`id` AS `id` from `test`.`t1` where (`test`.`t1`.`salary` = (select max(`test`.`t1`.`salary`) from `test`.`t1`)) diff --git a/mysql-test/r/subselect4.result b/mysql-test/r/subselect4.result index a1501099d72..51f89fd2a51 100644 --- a/mysql-test/r/subselect4.result +++ b/mysql-test/r/subselect4.result @@ -713,7 +713,7 @@ WHERE f3 = ( SELECT t1.f3 FROM t1 WHERE ( t1.f10 ) IN ( SELECT f11 FROM t2 GROUP BY f11 )); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t1 ref f3 f3 5 const 0 Using index condition +1 PRIMARY t1 ref f3 f3 5 const 0 Using where 2 SUBQUERY t1 ALL NULL NULL NULL NULL 2 Using where 2 SUBQUERY eq_ref distinct_key distinct_key 5 test.t1.f10 1 3 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 Using temporary @@ -728,7 +728,7 @@ WHERE f3 = ( SELECT f3 FROM t1 WHERE ( f10, f10 ) IN ( SELECT f11, f11 FROM t2 GROUP BY f11 )); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t1 ref f3 f3 5 const 0 Using index condition +1 PRIMARY t1 ref f3 f3 5 const 0 Using where 2 SUBQUERY t1 ALL NULL NULL NULL NULL 2 Using where 2 SUBQUERY eq_ref distinct_key distinct_key 10 test.t1.f10,test.t1.f10 1 3 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 Using temporary @@ -1790,7 +1790,7 @@ WHERE t2.f2 = (SELECT f2 FROM t3 WHERE EXISTS (SELECT DISTINCT f1 FROM t4)) AND t2.f2 = t1.f1; id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t1 ref f1 f1 5 const 0 Using index condition +1 PRIMARY t1 ref f1 f1 5 const 0 Using where 1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where; Using join buffer (flat, BNL join) 2 SUBQUERY t3 ALL NULL NULL NULL NULL 2 3 SUBQUERY t4 index NULL f1 5 NULL 2 Using index; Using temporary @@ -1807,7 +1807,7 @@ WHERE t2.f2 = (SELECT f2 FROM t3 WHERE EXISTS (SELECT DISTINCT f1 FROM t4) LIMIT 1) AND t2.f2 = t1.f1; id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t1 ref f1 f1 5 const 0 Using index condition +1 PRIMARY t1 ref f1 f1 5 const 0 Using where 1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where; Using join buffer (flat, BNL join) 2 SUBQUERY t3 ALL NULL NULL NULL NULL 2 3 SUBQUERY t4 index NULL f1 5 NULL 2 Using index; Using temporary diff --git a/mysql-test/r/subselect_mat_cost.result b/mysql-test/r/subselect_mat_cost.result index 003d7b0231b..3f465f1a7d0 100644 --- a/mysql-test/r/subselect_mat_cost.result +++ b/mysql-test/r/subselect_mat_cost.result @@ -247,7 +247,7 @@ AND CountryLanguage.Language = 'French' AND Code = Country; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY CountryLanguage ref PRIMARY,Language Language 30 const 20 Using index condition -1 PRIMARY Country eq_ref PRIMARY PRIMARY 3 world.CountryLanguage.Country 1 Using index condition +1 PRIMARY Country eq_ref PRIMARY PRIMARY 3 world.CountryLanguage.Country 1 Using where 2 DEPENDENT SUBQUERY CountryLanguage unique_subquery PRIMARY,Language PRIMARY 33 func,const 1 Using index; Using where SELECT Country.Name FROM Country, CountryLanguage @@ -286,7 +286,7 @@ AND (CountryLanguage.Language = 'French' OR CountryLanguage.Language = 'Spanish' AND Code = Country; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY CountryLanguage range PRIMARY,Language Language 30 NULL 45 Using index condition; Using where; Rowid-ordered scan -1 PRIMARY Country eq_ref PRIMARY PRIMARY 3 world.CountryLanguage.Country 1 Using index condition +1 PRIMARY Country eq_ref PRIMARY PRIMARY 3 world.CountryLanguage.Country 1 Using where 2 MATERIALIZED CountryLanguage ref PRIMARY,Language Language 30 const 47 Using index condition SELECT Country.Name FROM Country, CountryLanguage diff --git a/mysql-test/r/subselect_no_mat.result b/mysql-test/r/subselect_no_mat.result index 6d9cdc08572..59d108dc5c0 100644 --- a/mysql-test/r/subselect_no_mat.result +++ b/mysql-test/r/subselect_no_mat.result @@ -1381,7 +1381,7 @@ create table t1 (id int not null auto_increment primary key, salary int, key(sal insert into t1 (salary) values (100),(1000),(10000),(10),(500),(5000),(50000); explain extended SELECT id FROM t1 where salary = (SELECT MAX(salary) FROM t1); id select_type table type possible_keys key key_len ref rows filtered Extra -1 PRIMARY t1 ref salary salary 5 const 0 0.00 Using index condition +1 PRIMARY t1 ref salary salary 5 const 0 0.00 Using where 2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL Select tables optimized away Warnings: Note 1003 select `test`.`t1`.`id` AS `id` from `test`.`t1` where (`test`.`t1`.`salary` = (select max(`test`.`t1`.`salary`) from `test`.`t1`)) diff --git a/mysql-test/r/subselect_no_opts.result b/mysql-test/r/subselect_no_opts.result index 53ac091b722..d4c3694f2c6 100644 --- a/mysql-test/r/subselect_no_opts.result +++ b/mysql-test/r/subselect_no_opts.result @@ -1377,7 +1377,7 @@ create table t1 (id int not null auto_increment primary key, salary int, key(sal insert into t1 (salary) values (100),(1000),(10000),(10),(500),(5000),(50000); explain extended SELECT id FROM t1 where salary = (SELECT MAX(salary) FROM t1); id select_type table type possible_keys key key_len ref rows filtered Extra -1 PRIMARY t1 ref salary salary 5 const 0 0.00 Using index condition +1 PRIMARY t1 ref salary salary 5 const 0 0.00 Using where 2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL Select tables optimized away Warnings: Note 1003 select `test`.`t1`.`id` AS `id` from `test`.`t1` where (`test`.`t1`.`salary` = (select max(`test`.`t1`.`salary`) from `test`.`t1`)) diff --git a/mysql-test/r/subselect_no_scache.result b/mysql-test/r/subselect_no_scache.result index e3ad1397c02..aac4ce6e39d 100644 --- a/mysql-test/r/subselect_no_scache.result +++ b/mysql-test/r/subselect_no_scache.result @@ -1380,7 +1380,7 @@ create table t1 (id int not null auto_increment primary key, salary int, key(sal insert into t1 (salary) values (100),(1000),(10000),(10),(500),(5000),(50000); explain extended SELECT id FROM t1 where salary = (SELECT MAX(salary) FROM t1); id select_type table type possible_keys key key_len ref rows filtered Extra -1 PRIMARY t1 ref salary salary 5 const 0 0.00 Using index condition +1 PRIMARY t1 ref salary salary 5 const 0 0.00 Using where 2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL Select tables optimized away Warnings: Note 1003 select `test`.`t1`.`id` AS `id` from `test`.`t1` where (`test`.`t1`.`salary` = (select max(`test`.`t1`.`salary`) from `test`.`t1`)) diff --git a/mysql-test/r/subselect_no_semijoin.result b/mysql-test/r/subselect_no_semijoin.result index d5c6af1640a..3647e2fe2b3 100644 --- a/mysql-test/r/subselect_no_semijoin.result +++ b/mysql-test/r/subselect_no_semijoin.result @@ -1377,7 +1377,7 @@ create table t1 (id int not null auto_increment primary key, salary int, key(sal insert into t1 (salary) values (100),(1000),(10000),(10),(500),(5000),(50000); explain extended SELECT id FROM t1 where salary = (SELECT MAX(salary) FROM t1); id select_type table type possible_keys key key_len ref rows filtered Extra -1 PRIMARY t1 ref salary salary 5 const 0 0.00 Using index condition +1 PRIMARY t1 ref salary salary 5 const 0 0.00 Using where 2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL Select tables optimized away Warnings: Note 1003 select `test`.`t1`.`id` AS `id` from `test`.`t1` where (`test`.`t1`.`salary` = (select max(`test`.`t1`.`salary`) from `test`.`t1`)) diff --git a/sql/item.h b/sql/item.h index fb6421c23b2..d9aa6f3497e 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1024,6 +1024,10 @@ public: virtual bool eval_not_null_tables(uchar *opt_arg) { return 0; } virtual bool clear_sum_processor(uchar *opt_arg) { return 0; } virtual bool is_subquery_processor (uchar *opt_arg) { return 0; } + virtual bool limit_index_condition_pushdown_processor(uchar *opt_arg) + { + return FALSE; + } /* To call bool function for all arguments */ struct bool_func_call_args diff --git a/sql/item_func.h b/sql/item_func.h index bf4dd240253..54635bf21f7 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -1870,6 +1870,10 @@ public: { return trace_unsupported_by_check_vcol_func_processor(func_name()); } + bool limit_index_condition_pushdown_processor(uchar *opt_arg) + { + return TRUE; + } }; diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 60ca851c881..79044ccf3f7 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -229,6 +229,10 @@ public: virtual bool expr_cache_is_needed(THD *); virtual void get_cache_parameters(List ¶meters); virtual bool is_subquery_processor (uchar *opt_arg) { return 1; } + bool limit_index_condition_pushdown_processor(uchar *opt_arg) + { + return TRUE; + } friend class select_result_interceptor; friend class Item_in_optimizer; diff --git a/sql/opt_index_cond_pushdown.cc b/sql/opt_index_cond_pushdown.cc index 3a9c813b93c..5240267b4ac 100644 --- a/sql/opt_index_cond_pushdown.cc +++ b/sql/opt_index_cond_pushdown.cc @@ -29,6 +29,11 @@ bool uses_index_fields_only(Item *item, TABLE *tbl, uint keyno, bool other_tbls_ok) { + if (item->walk(&Item::limit_index_condition_pushdown_processor, FALSE, NULL)) + { + return FALSE; + } + if (item->const_item()) return TRUE; From 11e2462152f0ecbead726b65f06ed93e953693ac Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 19 Dec 2011 10:11:21 +0200 Subject: [PATCH 226/288] Supression condition made wider to cover some other system cases. --- mysql-test/valgrind.supp | 1 - 1 file changed, 1 deletion(-) diff --git a/mysql-test/valgrind.supp b/mysql-test/valgrind.supp index 3744598982b..871bd6e55b8 100644 --- a/mysql-test/valgrind.supp +++ b/mysql-test/valgrind.supp @@ -472,7 +472,6 @@ obj:/lib*/ld-*.so obj:/lib*/libdl-*.so fun:dlclose - fun:_ZL15free_plugin_memP12st_plugin_dl } { From 263ee553188960ada7a1589485a32434c8dc5b47 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Mon, 19 Dec 2011 18:07:19 +0400 Subject: [PATCH 227/288] Remove garbage comments --- sql/sql_select.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/sql/sql_select.h b/sql/sql_select.h index ad4607a4b78..8b3da18c976 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -525,8 +525,6 @@ enum_nested_loop_state end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), bool end_of_records); -/* psergey */ - struct st_position; From be3e52984fe20f5aa7862cf9ace86beb588d3240 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Mon, 19 Dec 2011 20:58:55 +0400 Subject: [PATCH 228/288] BUG#904432: Wrong result with LEFT JOIN, constant table, semijoin=ON,materialization=ON - Correct handling for SJ-Materialization + outer joins (details in the comments in the code) --- mysql-test/r/subselect_mat.result | 14 ++++++++++++ mysql-test/r/subselect_sj_mat.result | 14 ++++++++++++ mysql-test/t/subselect_sj_mat.test | 13 +++++++++++ sql/sql_select.cc | 34 ++++++++++++++++++++++++++-- 4 files changed, 73 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/subselect_mat.result b/mysql-test/r/subselect_mat.result index 7e4cf4ed9f1..f368f787407 100644 --- a/mysql-test/r/subselect_mat.result +++ b/mysql-test/r/subselect_mat.result @@ -1797,6 +1797,20 @@ id select_type table type possible_keys key key_len ref rows filtered Extra Warnings: Note 1003 select 8 AS `a` from `test`.`t1` where <8>((8,(select min(`test`.`t1`.`a`) from `test`.`t1` having ((8) = (min(`test`.`t1`.`a`)))))) DROP TABLE t1; +# +# BUG#904432: Wrong result with LEFT JOIN, constant table, semijoin=ON,materialization=ON +# +CREATE TABLE t1 ( a INT ) ENGINE=MyISAM; +INSERT INTO t1 VALUES (4); +CREATE TABLE t2 ( b INT NOT NULL, c INT ); +INSERT INTO t2 VALUES (4,2),(4,2),(4,4),(1,1); +SELECT * FROM t1 LEFT JOIN t2 ON ( a = b ) +WHERE a IN ( SELECT c FROM t2 ); +a b c +4 4 2 +4 4 2 +4 4 4 +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 bdfa834977b..f8d8505926c 100644 --- a/mysql-test/r/subselect_sj_mat.result +++ b/mysql-test/r/subselect_sj_mat.result @@ -1834,6 +1834,20 @@ id select_type table type possible_keys key key_len ref rows filtered Extra Warnings: Note 1003 select 8 AS `a` from (select min(`test`.`t1`.`a`) from `test`.`t1`) join `test`.`t1` where 1 DROP TABLE t1; +# +# BUG#904432: Wrong result with LEFT JOIN, constant table, semijoin=ON,materialization=ON +# +CREATE TABLE t1 ( a INT ) ENGINE=MyISAM; +INSERT INTO t1 VALUES (4); +CREATE TABLE t2 ( b INT NOT NULL, c INT ); +INSERT INTO t2 VALUES (4,2),(4,2),(4,4),(1,1); +SELECT * FROM t1 LEFT JOIN t2 ON ( a = b ) +WHERE a IN ( SELECT c FROM t2 ); +a b c +4 4 2 +4 4 2 +4 4 4 +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 a0d24aa53ed..b9e0beaa5e3 100644 --- a/mysql-test/t/subselect_sj_mat.test +++ b/mysql-test/t/subselect_sj_mat.test @@ -1497,6 +1497,19 @@ EXPLAIN EXTENDED DROP TABLE t1; +--echo # +--echo # BUG#904432: Wrong result with LEFT JOIN, constant table, semijoin=ON,materialization=ON +--echo # +CREATE TABLE t1 ( a INT ) ENGINE=MyISAM; +INSERT INTO t1 VALUES (4); +CREATE TABLE t2 ( b INT NOT NULL, c INT ); +INSERT INTO t2 VALUES (4,2),(4,2),(4,4),(1,1); + +SELECT * FROM t1 LEFT JOIN t2 ON ( a = b ) + WHERE a IN ( SELECT c FROM t2 ); + +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 2c17e5dbff6..dc9485e0f94 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -8343,9 +8343,39 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) COND *tmp_cond= make_cond_for_table(thd, on_expr, used_tables2, current_map, /*(tab - first_tab)*/ -1, FALSE, FALSE); - if (tab == first_inner_tab && tab->on_precond) + bool is_sjm_lookup_tab= FALSE; + if (tab->bush_children) + { + /* + 'tab' is an SJ-Materialization tab, i.e. we have a join order + like this: + + ot1 sjm_tab LEFT JOIN ot2 ot3 + ^ ^ + 'tab'-+ +--- left join we're adding triggers for + + LEFT JOIN's ON expression may not have references to subquery + columns. The subquery was in the WHERE clause, so IN-equality + is in the WHERE clause, also. + However, equality propagation code may have propagated the + IN-equality into ON expression, and we may get things like + + subquery_inner_table=const + + in the ON expression. We must not check such conditions during + SJM-lookup, because 1) subquery_inner_table has no valid current + row (materialization temp.table has it instead), and 2) they + would be true anyway. + */ + SJ_MATERIALIZATION_INFO *sjm= + tab->bush_children->start->emb_sj_nest->sj_mat_info; + if (sjm->is_used && !sjm->is_sj_scan) + is_sjm_lookup_tab= TRUE; + } + + if (tab == first_inner_tab && tab->on_precond && !is_sjm_lookup_tab) add_cond_and_fix(thd, &tmp_cond, tab->on_precond); - if (tmp_cond) + if (tmp_cond && !is_sjm_lookup_tab) { JOIN_TAB *cond_tab= tab < first_inner_tab ? first_inner_tab : tab; Item **sel_cond_ref= tab < first_inner_tab ? From 15ea7238e42ea62da32c926c0a1667802f7646d9 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Mon, 19 Dec 2011 22:24:10 +0400 Subject: [PATCH 229/288] BUG#906385: EXPLAIN EXTENDED crashes in TABLE_LIST::print with limited max_join_size - Take into account that subquery's optimization can fail because of @@max_join_size error. --- mysql-test/r/subselect_sj2_mat.result | 22 ++++++++++++++++++++ mysql-test/t/subselect_sj2_mat.test | 29 +++++++++++++++++++++++++++ sql/sql_select.cc | 11 +++++++++- 3 files changed, 61 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/subselect_sj2_mat.result b/mysql-test/r/subselect_sj2_mat.result index f217cee38ce..5a9c3b90755 100644 --- a/mysql-test/r/subselect_sj2_mat.result +++ b/mysql-test/r/subselect_sj2_mat.result @@ -897,3 +897,25 @@ set optimizer_switch=default; select @@optimizer_switch like '%materialization=on%'; @@optimizer_switch like '%materialization=on%' 1 +# +# BUG#906385: EXPLAIN EXTENDED crashes in TABLE_LIST::print with limited max_join_size +# +CREATE TABLE t1 ( a INT ); +CREATE TABLE t2 ( b INT ); +INSERT INTO t1 VALUES (1),(2); +INSERT INTO t2 VALUES +(1),(2),(3),(4),(5), +(6),(7),(8),(9),(10), +(11),(12),(13),(14),(15), +(16),(17),(18),(19),(20); +set @tmp_906385=@@max_join_size; +SET max_join_size = 80; +EXPLAIN EXTENDED +SELECT COUNT(*) FROM t1 +WHERE a IN +( SELECT b FROM t2 GROUP BY b ) +AND ( 6 ) IN +( SELECT MIN( t2.b ) FROM t2 alias1, t2 ); +ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET MAX_JOIN_SIZE=# if the SELECT is okay +DROP TABLE t1, t2; +set max_join_size= @tmp_906385; diff --git a/mysql-test/t/subselect_sj2_mat.test b/mysql-test/t/subselect_sj2_mat.test index fdfa0f311d3..7c3b37b517a 100644 --- a/mysql-test/t/subselect_sj2_mat.test +++ b/mysql-test/t/subselect_sj2_mat.test @@ -8,3 +8,32 @@ set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; set optimizer_switch=default; select @@optimizer_switch like '%materialization=on%'; + +--echo # +--echo # BUG#906385: EXPLAIN EXTENDED crashes in TABLE_LIST::print with limited max_join_size +--echo # +CREATE TABLE t1 ( a INT ); +CREATE TABLE t2 ( b INT ); + +INSERT INTO t1 VALUES (1),(2); +INSERT INTO t2 VALUES + (1),(2),(3),(4),(5), + (6),(7),(8),(9),(10), + (11),(12),(13),(14),(15), + (16),(17),(18),(19),(20); + +set @tmp_906385=@@max_join_size; +SET max_join_size = 80; + +--error ER_TOO_BIG_SELECT +EXPLAIN EXTENDED +SELECT COUNT(*) FROM t1 +WHERE a IN + ( SELECT b FROM t2 GROUP BY b ) + AND ( 6 ) IN + ( SELECT MIN( t2.b ) FROM t2 alias1, t2 ); + +DROP TABLE t1, t2; +set max_join_size= @tmp_906385; + + diff --git a/sql/sql_select.cc b/sql/sql_select.cc index dc9485e0f94..18925f0f83f 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -21396,8 +21396,17 @@ void TABLE_LIST::print(THD *thd, table_map eliminated_tables, String *str, } else if (jtbm_subselect) { - if (jtbm_subselect->is_jtbm_const_tab) + if (jtbm_subselect->engine->engine_type() == + subselect_engine::SINGLE_SELECT_ENGINE) { + /* + We get here when conversion into materialization didn't finish (this + happens when + - The subquery is a degenerate case which produces 0 or 1 record + - subquery's optimization didn't finish because of @@max_join_size + limits + - ... maybe some other cases like this + */ str->append(STRING_WITH_LEN(" (")); jtbm_subselect->engine->print(str, query_type); str->append(')'); From a05a566cf0f14bb71740ea7f54f371b4df4f9604 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Tue, 20 Dec 2011 00:55:32 +0400 Subject: [PATCH 230/288] BUG#906357: Incorrect result with outer join and full text match - The problem was that const-table-reading code would try to evaluate MATCH() before init_ftfuncs() was called. - Fixed by making MATCH function "expensive" so that nobody tries to evaluate it at optimization phase. --- mysql-test/r/fulltext_left_join.result | 14 ++++++++++++++ mysql-test/r/fulltext_order_by.result | 4 ++-- mysql-test/t/fulltext_left_join.test | 13 +++++++++++++ sql/item_func.h | 1 + 4 files changed, 30 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/fulltext_left_join.result b/mysql-test/r/fulltext_left_join.result index ea4cacf2fab..d5373037538 100644 --- a/mysql-test/r/fulltext_left_join.result +++ b/mysql-test/r/fulltext_left_join.result @@ -97,3 +97,17 @@ INSERT INTO t2(b,c) VALUES(2,'castle'),(3,'castle'); SELECT * FROM t1 LEFT JOIN t2 ON a=b WHERE MATCH(c) AGAINST('+castle' IN BOOLEAN MODE); a b c DROP TABLE t1, t2; +# +# BUG#906357: Incorrect result with outer join and full text match +# +CREATE TABLE t1(f1 VARCHAR(6) NOT NULL, FULLTEXT KEY(f1), UNIQUE(f1)); +INSERT INTO t1 VALUES ('test'); +CREATE TABLE t2(f2 VARCHAR(6) NOT NULL, FULLTEXT KEY(f2), UNIQUE(f2)); +INSERT INTO t2 VALUES ('test'); +SELECT * FROM t2 LEFT OUTER JOIN t1 ON (MATCH(f1) against ("")); +f2 f1 +test NULL +SELECT * FROM t1 RIGHT OUTER JOIN t2 ON (MATCH(f1) against ("")); +f1 f2 +NULL test +DROP table t1,t2; diff --git a/mysql-test/r/fulltext_order_by.result b/mysql-test/r/fulltext_order_by.result index bd3e79ec5c2..58ed6aac6f9 100644 --- a/mysql-test/r/fulltext_order_by.result +++ b/mysql-test/r/fulltext_order_by.result @@ -46,10 +46,10 @@ a MATCH (message) AGAINST ('steve' IN BOOLEAN MODE) 7 1 SELECT a, FORMAT(MATCH (message) AGAINST ('steve'),6) as rel FROM t1 ORDER BY rel; a rel -1 0.000000 -2 0.000000 3 0.000000 +1 0.000000 5 0.000000 +2 0.000000 6 0.000000 7 0.895690 4 0.905873 diff --git a/mysql-test/t/fulltext_left_join.test b/mysql-test/t/fulltext_left_join.test index 8c13ae5cad9..3a81c1a5d1b 100644 --- a/mysql-test/t/fulltext_left_join.test +++ b/mysql-test/t/fulltext_left_join.test @@ -98,3 +98,16 @@ INSERT INTO t1 VALUES(1); INSERT INTO t2(b,c) VALUES(2,'castle'),(3,'castle'); SELECT * FROM t1 LEFT JOIN t2 ON a=b WHERE MATCH(c) AGAINST('+castle' IN BOOLEAN MODE); DROP TABLE t1, t2; + +--echo # +--echo # BUG#906357: Incorrect result with outer join and full text match +--echo # +CREATE TABLE t1(f1 VARCHAR(6) NOT NULL, FULLTEXT KEY(f1), UNIQUE(f1)); +INSERT INTO t1 VALUES ('test'); + +CREATE TABLE t2(f2 VARCHAR(6) NOT NULL, FULLTEXT KEY(f2), UNIQUE(f2)); +INSERT INTO t2 VALUES ('test'); +SELECT * FROM t2 LEFT OUTER JOIN t1 ON (MATCH(f1) against ("")); +SELECT * FROM t1 RIGHT OUTER JOIN t2 ON (MATCH(f1) against ("")); + +DROP table t1,t2; diff --git a/sql/item_func.h b/sql/item_func.h index 54635bf21f7..abaf07c51d5 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -1676,6 +1676,7 @@ public: table= 0; // required by Item_func_match::eq() DBUG_VOID_RETURN; } + bool is_expensive_processor(uchar *arg) { return TRUE; } enum Functype functype() const { return FT_FUNC; } const char *func_name() const { return "match"; } void update_used_tables() {} From 072073c09e0308ac58f1dbd2ee8f0fbc53e11467 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 19 Dec 2011 23:05:44 +0200 Subject: [PATCH 231/288] Backport of WL#5953 from MySQL 5.6 The patch differs from the original MySQL patch as follows: - All test case differences have been reviewed one by one, and care has been taken to restore the original plan so that each test case executes the code path it was designed for. - A bug was found and fixed in MariaDB 5.3 in Item_allany_subselect::cleanup(). - ORDER BY is not removed because we are unsure of all effects, and it would prevent enabling ORDER BY ... LIMIT subqueries. - ref_pointer_array.m_size is not adjusted because we don't do array bounds checking, and because it looks risky. Original comment by Jorgen Loland: ------------------------------------------------------------- WL#5953 - Optimize away useless subquery clauses For IN/ALL/ANY/SOME/EXISTS subqueries, the following clauses are meaningless: * ORDER BY (since we don't support LIMIT in these subqueries) * DISTINCT * GROUP BY if there is no HAVING clause and no aggregate functions This WL detects and optimizes away these useless parts of the query during JOIN::prepare() --- mysql-test/include/mix1.inc | 4 +- mysql-test/r/explain.result | 6 +- mysql-test/r/fulltext.result | 2 - mysql-test/r/group_min_max.result | 4 +- mysql-test/r/myisam_mrr.result | 4 +- mysql-test/r/subselect.result | 35 ++++---- mysql-test/r/subselect4.result | 66 +++++++-------- mysql-test/r/subselect_innodb.result | 2 +- mysql-test/r/subselect_mat.result | 34 ++++---- mysql-test/r/subselect_mat_cost_bugs.result | 6 +- mysql-test/r/subselect_no_mat.result | 31 +++---- mysql-test/r/subselect_no_opts.result | 31 +++---- mysql-test/r/subselect_no_scache.result | 35 ++++---- mysql-test/r/subselect_no_semijoin.result | 31 +++---- mysql-test/r/subselect_sj2_jcl6.result | 10 ++- mysql-test/r/subselect_sj_mat.result | 53 ++++++------ mysql-test/suite/innodb/r/innodb_mysql.result | 4 +- .../suite/innodb_plugin/r/innodb_mysql.result | 4 +- mysql-test/t/explain.test | 6 +- mysql-test/t/subselect.test | 9 +- mysql-test/t/subselect4.test | 40 ++++----- mysql-test/t/subselect_mat_cost_bugs.test | 4 +- mysql-test/t/subselect_sj2_jcl6.test | 4 + mysql-test/t/subselect_sj_mat.test | 18 ++-- sql/item_subselect.cc | 2 +- sql/sql_select.cc | 83 +++++++++++++++++++ 26 files changed, 313 insertions(+), 215 deletions(-) diff --git a/mysql-test/include/mix1.inc b/mysql-test/include/mix1.inc index a86e4818d15..65e488c538f 100644 --- a/mysql-test/include/mix1.inc +++ b/mysql-test/include/mix1.inc @@ -1184,9 +1184,9 @@ DROP TABLE t1; create table t1 (a bit(1) not null,b int) engine=myisam; create table t2 (c int) engine=innodb; set @save_optimizer_switch=@@optimizer_switch; -set @@optimizer_switch='partial_match_rowid_merge=off,partial_match_table_scan=off'; +set @@optimizer_switch='in_to_exists=on,materialization=off'; explain -select b from t1 where a not in (select b from t1,t2 group by a) group by a; +select b from t1 where a not in (select max(b) from t1,t2 group by a) group by a; set optimizer_switch=@save_optimizer_switch; DROP TABLE t1,t2; diff --git a/mysql-test/r/explain.result b/mysql-test/r/explain.result index f3d2a567227..52c58f088a1 100644 --- a/mysql-test/r/explain.result +++ b/mysql-test/r/explain.result @@ -265,7 +265,7 @@ CREATE TABLE t1(f1 VARCHAR(6) NOT NULL, FULLTEXT KEY(f1),UNIQUE(f1)); INSERT INTO t1 VALUES ('test'); EXPLAIN SELECT 1 FROM t1 -WHERE 1 > ALL((SELECT 1 FROM t1 JOIN t1 a ON (MATCH(t1.f1) AGAINST ("")) +WHERE 1 > ALL((SELECT t1.f1 FROM t1 JOIN t1 a ON (MATCH(t1.f1) AGAINST ("")) WHERE t1.f1 GROUP BY t1.f1)); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 1 @@ -273,7 +273,7 @@ id select_type table type possible_keys key key_len ref rows Extra 2 SUBQUERY t1 fulltext f1_2,f1 f1 0 1 Using where PREPARE stmt FROM 'EXPLAIN SELECT 1 FROM t1 - WHERE 1 > ALL((SELECT 1 FROM t1 RIGHT OUTER JOIN t1 a + WHERE 1 > ALL((SELECT t1.f1 FROM t1 RIGHT OUTER JOIN t1 a ON (MATCH(t1.f1) AGAINST ("")) WHERE t1.f1 GROUP BY t1.f1))'; EXECUTE stmt; @@ -289,7 +289,7 @@ id select_type table type possible_keys key key_len ref rows Extra DEALLOCATE PREPARE stmt; PREPARE stmt FROM 'EXPLAIN SELECT 1 FROM t1 - WHERE 1 > ALL((SELECT 1 FROM t1 JOIN t1 a + WHERE 1 > ALL((SELECT t1.f1 FROM t1 JOIN t1 a ON (MATCH(t1.f1) AGAINST ("")) WHERE t1.f1 GROUP BY t1.f1))'; EXECUTE stmt; diff --git a/mysql-test/r/fulltext.result b/mysql-test/r/fulltext.result index 33ec3d1f39c..5374d856343 100644 --- a/mysql-test/r/fulltext.result +++ b/mysql-test/r/fulltext.result @@ -684,10 +684,8 @@ PREPARE stmt FROM WHERE t1.f1 GROUP BY t1.f1))'; EXECUTE stmt; 1 -1 EXECUTE stmt; 1 -1 DEALLOCATE PREPARE stmt; DROP TABLE t1; End of 5.1 tests diff --git a/mysql-test/r/group_min_max.result b/mysql-test/r/group_min_max.result index 4c863d25257..858d31e05c8 100644 --- a/mysql-test/r/group_min_max.result +++ b/mysql-test/r/group_min_max.result @@ -2963,7 +2963,7 @@ WHERE EXISTS ( SELECT DISTINCT b FROM t1 WHERE b <= alias1.a ) ; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 index NULL b 5 NULL 10 Using index 1 PRIMARY t1 ALL NULL NULL NULL NULL 10 Using where; Using join buffer (flat, BNL join) -3 DEPENDENT SUBQUERY t1 index b b 5 NULL 10 Using where; Using index; Using temporary +3 DEPENDENT SUBQUERY t1 index b b 5 NULL 10 Using where; Using index SELECT alias1.* FROM t1, (SELECT * FROM t1) AS alias1 WHERE EXISTS ( SELECT DISTINCT b FROM t1 WHERE b <= alias1.a ) ; a b @@ -3073,7 +3073,7 @@ WHERE EXISTS ( SELECT DISTINCT b FROM t1 WHERE b <= alias1.a ) ; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 index NULL b 5 NULL 10 Using index 1 PRIMARY alias1 ALL NULL NULL NULL NULL 10 Using where; Using join buffer (flat, BNL join) -2 DEPENDENT SUBQUERY t1 ALL b NULL NULL NULL 10 Range checked for each record (index map: 0x1); Using temporary +2 DEPENDENT SUBQUERY t1 index b b 5 NULL 10 Using where; Using index SELECT alias1.* FROM t1, t1 AS alias1 WHERE EXISTS ( SELECT DISTINCT b FROM t1 WHERE b <= alias1.a ) ; a b diff --git a/mysql-test/r/myisam_mrr.result b/mysql-test/r/myisam_mrr.result index 5bb6b9db49e..4e1e4f01c07 100644 --- a/mysql-test/r/myisam_mrr.result +++ b/mysql-test/r/myisam_mrr.result @@ -350,9 +350,9 @@ GROUP BY t2.pk ); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 system NULL NULL NULL NULL 1 100.00 -2 SUBQUERY t2 ref int_key int_key 5 const 1 100.00 Using index condition; Using where; Using filesort +2 SUBQUERY t2 ref int_key int_key 5 const 1 100.00 Using index condition Warnings: -Note 1003 select min(1) AS `MIN(t1.pk)` from `test`.`t1` where exists(select `test`.`t2`.`pk` from `test`.`t2` where isnull(`test`.`t2`.`int_key`) group by `test`.`t2`.`pk`) +Note 1003 select min(1) AS `MIN(t1.pk)` from `test`.`t1` where exists(select `test`.`t2`.`pk` from `test`.`t2` where isnull(`test`.`t2`.`int_key`)) DROP TABLE t1, t2; # # BUG#42048 Discrepancy between MyISAM and Maria's ICP implementation diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 8008d887823..f54106b5fa0 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -1662,7 +1662,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,((select NULL from `test`.`t2` group by 1) > (`test`.`t3`.`a`)))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,((select max(NULL) from `test`.`t2`) > (`test`.`t3`.`a`)))) select * from t3 where a >= some (select b from t2 group by 1); a explain extended select * from t3 where a >= some (select b from t2 group by 1); @@ -1670,7 +1670,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,((select NULL from `test`.`t2` group by 1) <= (`test`.`t3`.`a`)))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,((select min(NULL) from `test`.`t2`) <= (`test`.`t3`.`a`)))) select * from t3 where NULL >= any (select b from t2); a explain extended select * from t3 where NULL >= any (select b from t2); @@ -1686,7 +1686,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL,((select NULL from `test`.`t2` group by 1) <= NULL))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL,((select min(NULL) from `test`.`t2`) <= NULL))) select * from t3 where NULL >= some (select b from t2); a explain extended select * from t3 where NULL >= some (select b from t2); @@ -1702,7 +1702,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL,((select NULL from `test`.`t2` group by 1) <= NULL))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL,((select min(NULL) from `test`.`t2`) <= NULL))) insert into t2 values (2,2), (2,1), (3,3), (3,1); select * from t3 where a > all (select max(b) from t2 group by a); a @@ -2980,9 +2980,9 @@ Note 1003 select `test`.`t1`.`one` AS `one`,`test`.`t1`.`two` AS `two` from `tes explain extended SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0' group by one,two) as 'test' from t1; id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 8 100.00 -2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 9 100.00 Using where; Using temporary +2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 9 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`one` AS `one`,`test`.`t1`.`two` AS `two`,<`test`.`t1`.`one`,`test`.`t1`.`two`>(((`test`.`t1`.`one`,`test`.`t1`.`two`),(select `test`.`t2`.`one`,`test`.`t2`.`two` from `test`.`t2` where (`test`.`t2`.`flag` = '0') group by `test`.`t2`.`one`,`test`.`t2`.`two` having (trigcond((((`test`.`t1`.`one`) = `test`.`t2`.`one`) or isnull(`test`.`t2`.`one`))) and trigcond((((`test`.`t1`.`two`) = `test`.`t2`.`two`) or isnull(`test`.`t2`.`two`))) and trigcond((`test`.`t2`.`one`)) and trigcond((`test`.`t2`.`two`)))))) AS `test` from `test`.`t1` +Note 1003 select `test`.`t1`.`one` AS `one`,`test`.`t1`.`two` AS `two`,<`test`.`t1`.`one`,`test`.`t1`.`two`>(((`test`.`t1`.`one`,`test`.`t1`.`two`),(select `test`.`t2`.`one`,`test`.`t2`.`two` from `test`.`t2` where ((`test`.`t2`.`flag` = '0') and trigcond((((`test`.`t1`.`one`) = `test`.`t2`.`one`) or isnull(`test`.`t2`.`one`))) and trigcond((((`test`.`t1`.`two`) = `test`.`t2`.`two`) or isnull(`test`.`t2`.`two`)))) having (trigcond((`test`.`t2`.`one`)) and trigcond((`test`.`t2`.`two`)))))) AS `test` from `test`.`t1` DROP TABLE t1,t2; set optimizer_switch=@tmp11867_optimizer_switch; CREATE TABLE t1 (a char(5), b char(5)); @@ -4463,20 +4463,20 @@ a drop table t1, t2; CREATE TABLE t1 (a INT); INSERT INTO t1 VALUES (1),(2); -EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1 IN (SELECT 1 FROM t1 GROUP BY a); +EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1 IN (SELECT min(a) 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 -1 PRIMARY const distinct_key distinct_key 4 const 1 100.00 +1 PRIMARY const distinct_key distinct_key 5 const 1 100.00 2 MATERIALIZED t1 ALL NULL NULL NULL NULL 2 100.00 Using temporary Warnings: -Note 1003 select 1 AS `1` from (select 1 from `test`.`t1` group by `test`.`t1`.`a`) join `test`.`t1` where (``.`1` = 1) -EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1 IN (SELECT 1 FROM t1 WHERE a > 3 GROUP BY a); +Note 1003 select 1 AS `1` from (select min(`test`.`t1`.`a`) from `test`.`t1` group by `test`.`t1`.`a`) join `test`.`t1` where (``.`min(a)` = 1) +EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1 IN (SELECT min(a) FROM t1 WHERE a > 3 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 -1 PRIMARY const distinct_key distinct_key 4 const 1 100.00 +1 PRIMARY const distinct_key distinct_key 5 const 1 100.00 2 MATERIALIZED t1 ALL NULL NULL NULL NULL 2 100.00 Using where; Using temporary Warnings: -Note 1003 select 1 AS `1` from (select 1 from `test`.`t1` where (`test`.`t1`.`a` > 3) group by `test`.`t1`.`a`) join `test`.`t1` where (``.`1` = 1) +Note 1003 select 1 AS `1` from (select min(`test`.`t1`.`a`) from `test`.`t1` where (`test`.`t1`.`a` > 3) group by `test`.`t1`.`a`) join `test`.`t1` where (``.`min(a)` = 1) DROP TABLE t1; # # Bug#45061: Incorrectly market field caused wrong result. @@ -4820,8 +4820,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); @@ -5246,18 +5244,21 @@ DROP table t1,t2; # CREATE TABLE t1 (a int, b int) ; INSERT INTO t1 VALUES (0,0),(0,0); +set @optimizer_switch_save=@@optimizer_switch; +set @@optimizer_switch='semijoin=off,materialization=on,in_to_exists=on'; EXPLAIN SELECT b FROM t1 WHERE ('0') IN ( SELECT a FROM t1 GROUP BY a ) GROUP BY b; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using temporary; Using filesort -2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 2 Using temporary +2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 2 Using where SELECT b FROM t1 WHERE ('0') IN ( SELECT a FROM t1 GROUP BY a ) GROUP BY b; b 0 +set @@optimizer_switch=@optimizer_switch_save; DROP TABLE t1; # # Bug #11765713 58705: @@ -5653,7 +5654,7 @@ 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 (flat, BNL join) -2 DEPENDENT SUBQUERY t2 ALL f1_key NULL NULL NULL 10 Range checked for each record (index map: 0x1); Using temporary +2 DEPENDENT SUBQUERY t2 index f1_key f1_key 4 NULL 10 Using where; Using index DROP TABLE t1,t2; # # LP bug #826279: assertion failure with GROUP BY a result of subquery @@ -5881,7 +5882,7 @@ SET @@optimizer_switch='semijoin=off,materialization=off,in_to_exists=on,subquer EXPLAIN SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 index NULL a 4 NULL 2 Using where; Using index -2 DEPENDENT SUBQUERY t1 index NULL a 4 NULL 1 Using index +2 DEPENDENT SUBQUERY t1 index_subquery a a 4 func 2 Using index SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1); a 2009-01-01 diff --git a/mysql-test/r/subselect4.result b/mysql-test/r/subselect4.result index 51f89fd2a51..f9337ddc78a 100644 --- a/mysql-test/r/subselect4.result +++ b/mysql-test/r/subselect4.result @@ -706,36 +706,34 @@ INSERT INTO t1 VALUES ('28','6','m'),('29','4','c'); CREATE TABLE t2 (f11 varchar(1)) ; INSERT INTO t2 VALUES ('f'),('d'); SET @old_optimizer_switch = @@session.optimizer_switch; -SET SESSION optimizer_switch = 'materialization=on,in_to_exists=off,'; +SET @@optimizer_switch = 'materialization=on,in_to_exists=off,semijoin=off'; EXPLAIN SELECT * FROM t1 WHERE f3 = ( SELECT t1.f3 FROM t1 -WHERE ( t1.f10 ) IN ( SELECT f11 FROM t2 GROUP BY f11 )); +WHERE ( t1.f10 ) IN ( SELECT max(f11) FROM t2 GROUP BY f11 )); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ref f3 f3 5 const 0 Using where 2 SUBQUERY t1 ALL NULL NULL NULL NULL 2 Using where -2 SUBQUERY eq_ref distinct_key distinct_key 5 test.t1.f10 1 3 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 Using temporary SELECT * FROM t1 WHERE f3 = ( SELECT t1.f3 FROM t1 -WHERE ( t1.f10 ) IN ( SELECT f11 FROM t2 GROUP BY f11 )); +WHERE ( t1.f10 ) IN ( SELECT max(f11) FROM t2 GROUP BY f11 )); f1 f3 f10 EXPLAIN SELECT * FROM t1 WHERE f3 = ( SELECT f3 FROM t1 -WHERE ( f10, f10 ) IN ( SELECT f11, f11 FROM t2 GROUP BY f11 )); +WHERE ( f10, f10 ) IN ( SELECT max(f11), f11 FROM t2 GROUP BY f11 )); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ref f3 f3 5 const 0 Using where 2 SUBQUERY t1 ALL NULL NULL NULL NULL 2 Using where -2 SUBQUERY eq_ref distinct_key distinct_key 10 test.t1.f10,test.t1.f10 1 3 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 Using temporary SELECT * FROM t1 WHERE f3 = ( SELECT f3 FROM t1 -WHERE ( f10, f10 ) IN ( SELECT f11, f11 FROM t2 GROUP BY f11 )); +WHERE ( f10, f10 ) IN ( SELECT max(f11), f11 FROM t2 GROUP BY f11 )); f1 f3 f10 SET SESSION optimizer_switch = @old_optimizer_switch; drop table t1,t2; @@ -1331,7 +1329,7 @@ EXPLAIN SELECT * FROM t1 WHERE (SELECT f2 FROM t2 WHERE f4 <= ALL -(SELECT SQ1_t1.f4 +(SELECT max(SQ1_t1.f4) FROM t3 AS SQ1_t1 JOIN t3 AS SQ1_t3 ON SQ1_t3.f4 GROUP BY SQ1_t1.f4)); id select_type table type possible_keys key key_len ref rows Extra @@ -1624,68 +1622,68 @@ INSERT INTO t2 VALUES (10,5,'d1d'); set @save_optimizer_switch=@@optimizer_switch; SET optimizer_switch='outer_join_with_cache=off'; -set @@optimizer_switch = 'materialization=off'; +set @@optimizer_switch = 'in_to_exists=on,materialization=off,semijoin=off'; EXPLAIN SELECT alias2.f1 , alias2.f2 FROM t0 AS alias1 RIGHT JOIN t0 AS alias2 ON alias2.f10 -WHERE ( alias2.f1 , alias2.f2 ) IN ( SELECT f2 , f1 FROM t0 GROUP BY f2 , f1 ); +WHERE ( alias2.f1 , alias2.f2 ) IN ( SELECT max(f2) , f1 FROM t0 GROUP BY f2 , f1 ); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY alias2 ALL NULL NULL NULL NULL 2 Using where 1 PRIMARY alias1 index NULL PRIMARY 4 NULL 2 Using where; Using index -2 DEPENDENT SUBQUERY t0 ALL NULL NULL NULL NULL 2 +2 DEPENDENT SUBQUERY t0 ALL NULL NULL NULL NULL 2 Using temporary SELECT alias2.f1 , alias2.f2 FROM t0 AS alias1 RIGHT JOIN t0 AS alias2 ON alias2.f10 -WHERE ( alias2.f1 , alias2.f2 ) IN ( SELECT f2 , f1 FROM t0 GROUP BY f2 , f1 ); +WHERE ( alias2.f1 , alias2.f2 ) IN ( SELECT max(f2) , f1 FROM t0 GROUP BY f2 , f1 ); f1 f2 8 8 EXPLAIN -SELECT * FROM t2 WHERE (f1b, f2b) IN (SELECT f1a, f2a FROM t1 GROUP BY f1a, f2a); +SELECT * FROM t2 WHERE (f1b, f2b) IN (SELECT max(f1a), f2a FROM t1 GROUP BY f1a, f2a); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 system NULL NULL NULL NULL 1 -2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 2 -SELECT * FROM t2 WHERE (f1b, f2b) IN (SELECT f1a, f2a FROM t1 GROUP BY f1a, f2a); +2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 2 Using temporary +SELECT * FROM t2 WHERE (f1b, f2b) IN (SELECT max(f1a), f2a FROM t1 GROUP BY f1a, f2a); f1b f2b f3b 10 5 d1d EXPLAIN -SELECT * FROM t2 WHERE (f1b) IN (SELECT f1a FROM t1 GROUP BY f1a, f2a); +SELECT * FROM t2 WHERE (f1b) IN (SELECT max(f1a) FROM t1 GROUP BY f1a, f2a); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 system NULL NULL NULL NULL 1 -2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 2 -SELECT * FROM t2 WHERE (f1b) IN (SELECT f1a FROM t1 GROUP BY f1a, f2a); +2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 2 Using temporary +SELECT * FROM t2 WHERE (f1b) IN (SELECT max(f1a) FROM t1 GROUP BY f1a, f2a); f1b f2b f3b 10 5 d1d -SET @@optimizer_switch = 'materialization=on'; +set @@optimizer_switch = 'in_to_exists=off,materialization=on,semijoin=off'; EXPLAIN SELECT alias2.f1 , alias2.f2 FROM t0 AS alias1 RIGHT JOIN t0 AS alias2 ON alias2.f10 -WHERE ( alias2.f1 , alias2.f2 ) IN ( SELECT f2 , f1 FROM t0 GROUP BY f2 , f1 ); +WHERE ( alias2.f1 , alias2.f2 ) IN ( SELECT max(f2) , f1 FROM t0 GROUP BY f2 , f1 ); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY alias2 ALL NULL NULL NULL NULL 2 Using where 1 PRIMARY alias1 index NULL PRIMARY 4 NULL 2 Using where; Using index -2 MATERIALIZED t0 ALL NULL NULL NULL NULL 2 +2 MATERIALIZED t0 ALL NULL NULL NULL NULL 2 Using temporary SELECT alias2.f1 , alias2.f2 FROM t0 AS alias1 RIGHT JOIN t0 AS alias2 ON alias2.f10 -WHERE ( alias2.f1 , alias2.f2 ) IN ( SELECT f2 , f1 FROM t0 GROUP BY f2 , f1 ); +WHERE ( alias2.f1 , alias2.f2 ) IN ( SELECT max(f2) , f1 FROM t0 GROUP BY f2 , f1 ); f1 f2 8 8 EXPLAIN -SELECT * FROM t2 WHERE (f1b, f2b) IN (SELECT f1a, f2a FROM t1 GROUP BY f1a, f2a); +SELECT * FROM t2 WHERE (f1b, f2b) IN (SELECT max(f1a), f2a FROM t1 GROUP BY f1a, f2a); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 system NULL NULL NULL NULL 1 -2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 2 -SELECT * FROM t2 WHERE (f1b, f2b) IN (SELECT f1a, f2a FROM t1 GROUP BY f1a, f2a); +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 2 Using temporary +SELECT * FROM t2 WHERE (f1b, f2b) IN (SELECT max(f1a), f2a FROM t1 GROUP BY f1a, f2a); f1b f2b f3b 10 5 d1d EXPLAIN -SELECT * FROM t2 WHERE (f1b) IN (SELECT f1a FROM t1 GROUP BY f1a, f2a); +SELECT * FROM t2 WHERE (f1b) IN (SELECT max(f1a) FROM t1 GROUP BY f1a, f2a); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 system NULL NULL NULL NULL 1 -2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 2 -SELECT * FROM t2 WHERE (f1b) IN (SELECT f1a FROM t1 GROUP BY f1a, f2a); +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 2 Using temporary +SELECT * FROM t2 WHERE (f1b) IN (SELECT max(f1a) FROM t1 GROUP BY f1a, f2a); f1b f2b f3b 10 5 d1d set @@optimizer_switch=@save_optimizer_switch; @@ -1770,7 +1768,7 @@ FROM t1)); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 system NULL NULL NULL NULL 1 2 SUBQUERY t3 ALL NULL NULL NULL NULL 2 -3 SUBQUERY t1 ALL NULL NULL NULL NULL 2 Using temporary +3 SUBQUERY t1 ALL NULL NULL NULL NULL 2 drop table t1, t2, t3; # # LP BUG#802979 Assertion `table->key_read == 0' in close_thread_table @@ -1793,7 +1791,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ref f1 f1 5 const 0 Using where 1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where; Using join buffer (flat, BNL join) 2 SUBQUERY t3 ALL NULL NULL NULL NULL 2 -3 SUBQUERY t4 index NULL f1 5 NULL 2 Using index; Using temporary +3 SUBQUERY t4 index NULL f1 5 NULL 2 Using index SELECT * FROM t1, t2 WHERE t2.f2 = (SELECT f2 FROM t3 @@ -1810,7 +1808,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ref f1 f1 5 const 0 Using where 1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where; Using join buffer (flat, BNL join) 2 SUBQUERY t3 ALL NULL NULL NULL NULL 2 -3 SUBQUERY t4 index NULL f1 5 NULL 2 Using index; Using temporary +3 SUBQUERY t4 index NULL f1 5 NULL 2 Using index SELECT * FROM t1, t2 WHERE t2.f2 = (SELECT f2 FROM t3 @@ -1838,7 +1836,7 @@ FROM t1)); 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 SUBQUERY t4 ALL NULL NULL NULL NULL 2 -3 SUBQUERY t1 ALL NULL NULL NULL NULL 2 Using temporary +3 SUBQUERY t1 ALL NULL NULL NULL NULL 2 SELECT * FROM t2, t3 WHERE t3.f1 = ( @@ -1884,7 +1882,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 index NULL col_int_key 5 NULL 2 Using index 2 SUBQUERY SUBQUERY2_t1 index NULL col_int_key 5 NULL 2 Using index 2 SUBQUERY SUBQUERY2_t2 ALL col_varchar_key NULL NULL NULL 2 Using where; Using join buffer (flat, BNL join) -3 MATERIALIZED t1 ALL NULL NULL NULL NULL 2 Using temporary +3 MATERIALIZED t1 ALL NULL NULL NULL NULL 2 SELECT col_int_key FROM t2 WHERE (SELECT SUBQUERY2_t1.col_int_key @@ -1906,7 +1904,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 index NULL col_int_key 5 NULL 2 Using index 2 SUBQUERY SUBQUERY2_t1 index NULL col_int_key 5 NULL 2 Using index 2 SUBQUERY SUBQUERY2_t2 ALL col_varchar_key NULL NULL NULL 2 Using where; Using join buffer (flat, BNL join) -3 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 2 Using temporary +3 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 2 Using where SELECT col_int_key FROM t2 WHERE (SELECT SUBQUERY2_t1.col_int_key diff --git a/mysql-test/r/subselect_innodb.result b/mysql-test/r/subselect_innodb.result index 402c18f2bbd..de0914e5f18 100644 --- a/mysql-test/r/subselect_innodb.result +++ b/mysql-test/r/subselect_innodb.result @@ -291,7 +291,7 @@ GROUP BY 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 SUBQUERY t1 ALL NULL NULL NULL NULL 1 -3 SUBQUERY t3 ALL NULL NULL NULL NULL 1 Using temporary; Using filesort +3 SUBQUERY t3 ALL NULL NULL NULL NULL 1 SELECT MAX( f1 ) FROM t2 WHERE f2 >= ( SELECT SUM( f1 ) diff --git a/mysql-test/r/subselect_mat.result b/mysql-test/r/subselect_mat.result index f368f787407..7225cf7c825 100644 --- a/mysql-test/r/subselect_mat.result +++ b/mysql-test/r/subselect_mat.result @@ -59,9 +59,9 @@ explain extended select * from t1 where a1 in (select b1 from t2 where b1 > '0' group by b1); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where -2 MATERIALIZED t2 ALL NULL NULL NULL NULL 5 100.00 Using where; Using temporary +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 5 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where <`test`.`t1`.`a1`>((`test`.`t1`.`a1`,`test`.`t1`.`a1` in ( (select `test`.`t2`.`b1` from `test`.`t2` where (`test`.`t2`.`b1` > '0') group by `test`.`t2`.`b1` ), (`test`.`t1`.`a1` in on distinct_key where ((`test`.`t1`.`a1` = ``.`b1`)))))) +Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where <`test`.`t1`.`a1`>((`test`.`t1`.`a1`,`test`.`t1`.`a1` in ( (select `test`.`t2`.`b1` from `test`.`t2` where (`test`.`t2`.`b1` > '0') ), (`test`.`t1`.`a1` in on distinct_key where ((`test`.`t1`.`a1` = ``.`b1`)))))) select * from t1 where a1 in (select b1 from t2 where b1 > '0' group by b1); a1 a2 1 - 01 2 - 01 @@ -70,9 +70,9 @@ explain extended select * from t1 where (a1, a2) in (select b1, b2 from t2 where b1 > '0' group by b1, b2); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where -2 MATERIALIZED t2 ALL NULL NULL NULL NULL 5 100.00 Using where; Using temporary +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 5 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where <`test`.`t1`.`a1`,`test`.`t1`.`a2`>(((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( (select `test`.`t2`.`b1`,`test`.`t2`.`b2` from `test`.`t2` where (`test`.`t2`.`b1` > '0') group by `test`.`t2`.`b1`,`test`.`t2`.`b2` ), (`test`.`t1`.`a1` in on distinct_key where ((`test`.`t1`.`a1` = ``.`b1`) and (`test`.`t1`.`a2` = ``.`b2`)))))) +Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where <`test`.`t1`.`a1`,`test`.`t1`.`a2`>(((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( (select `test`.`t2`.`b1`,`test`.`t2`.`b2` from `test`.`t2` where (`test`.`t2`.`b1` > '0') ), (`test`.`t1`.`a1` in on distinct_key where ((`test`.`t1`.`a1` = ``.`b1`) and (`test`.`t1`.`a2` = ``.`b2`)))))) select * from t1 where (a1, a2) in (select b1, b2 from t2 where b1 > '0' group by b1, b2); a1 a2 1 - 01 2 - 01 @@ -100,13 +100,13 @@ a1 a2 1 - 01 2 - 01 1 - 02 2 - 02 explain extended -select * from t1i where a1 in (select b1 from t2i where b1 > '0' group by b1); +select * from t1i where a1 in (select max(b1) from t2i where b1 > '0' group by b1); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1i index NULL # 18 # 3 100.00 # -2 MATERIALIZED t2i range it2i1,it2i3 # 9 # 3 100.00 # +2 MATERIALIZED t2i index it2i1,it2i3 # 9 # 5 100.00 # Warnings: -Note 1003 select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from `test`.`t1i` where <`test`.`t1i`.`a1`>((`test`.`t1i`.`a1`,`test`.`t1i`.`a1` in ( (select `test`.`t2i`.`b1` from `test`.`t2i` where (`test`.`t2i`.`b1` > '0') group by `test`.`t2i`.`b1` ), (`test`.`t1i`.`a1` in on distinct_key where ((`test`.`t1i`.`a1` = ``.`b1`)))))) -select * from t1i where a1 in (select b1 from t2i where b1 > '0' group by b1); +Note 1003 select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from `test`.`t1i` where <`test`.`t1i`.`a1`>((`test`.`t1i`.`a1`,`test`.`t1i`.`a1` in ( (select max(`test`.`t2i`.`b1`) from `test`.`t2i` where (`test`.`t2i`.`b1` > '0') group by `test`.`t2i`.`b1` ), (`test`.`t1i`.`a1` in on distinct_key where ((`test`.`t1i`.`a1` = ``.`max(b1)`)))))) +select * from t1i where a1 in (select max(b1) from t2i where b1 > '0' group by b1); a1 a2 1 - 01 2 - 01 1 - 02 2 - 02 @@ -122,13 +122,13 @@ a1 a2 1 - 01 2 - 01 1 - 02 2 - 02 explain extended -select * from t1i where (a1, a2) in (select b1, b2 from t2i where b1 > '0' group by b1, b2); +select * from t1i where (a1, a2) in (select b1, max(b2) from t2i where b1 > '0' group by b1); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1i index NULL # # # 3 100.00 # 2 MATERIALIZED t2i range it2i1,it2i3 # # # 3 100.00 # Warnings: -Note 1003 select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from `test`.`t1i` where <`test`.`t1i`.`a1`,`test`.`t1i`.`a2`>(((`test`.`t1i`.`a1`,`test`.`t1i`.`a2`),(`test`.`t1i`.`a1`,`test`.`t1i`.`a2`) in ( (select `test`.`t2i`.`b1`,`test`.`t2i`.`b2` from `test`.`t2i` where (`test`.`t2i`.`b1` > '0') group by `test`.`t2i`.`b1`,`test`.`t2i`.`b2` ), (`test`.`t1i`.`a1` in on distinct_key where ((`test`.`t1i`.`a1` = ``.`b1`) and (`test`.`t1i`.`a2` = ``.`b2`)))))) -select * from t1i where (a1, a2) in (select b1, b2 from t2i where b1 > '0' group by b1, b2); +Note 1003 select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from `test`.`t1i` where <`test`.`t1i`.`a1`,`test`.`t1i`.`a2`>(((`test`.`t1i`.`a1`,`test`.`t1i`.`a2`),(`test`.`t1i`.`a1`,`test`.`t1i`.`a2`) in ( (select `test`.`t2i`.`b1`,max(`test`.`t2i`.`b2`) from `test`.`t2i` where (`test`.`t2i`.`b1` > '0') group by `test`.`t2i`.`b1` ), (`test`.`t1i`.`a1` in on distinct_key where ((`test`.`t1i`.`a1` = ``.`b1`) and (`test`.`t1i`.`a2` = ``.`max(b2)`)))))) +select * from t1i where (a1, a2) in (select b1, max(b2) from t2i where b1 > '0' group by b1); a1 a2 1 - 01 2 - 01 1 - 02 2 - 02 @@ -394,7 +394,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 8 MATERIALIZED t2i index it2i1,it2i3 # # # 5 100.00 # NULL UNION RESULT ALL NULL # # # NULL NULL # Warnings: -Note 1003 (select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where (<`test`.`t1`.`a1`,`test`.`t1`.`a2`>(((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( (select `test`.`t2`.`b1`,`test`.`t2`.`b2` from `test`.`t2` where (<`test`.`t2`.`b2`>((`test`.`t2`.`b2`,`test`.`t2`.`b2` in ( (select `test`.`t3`.`c2` from `test`.`t3` where (`test`.`t3`.`c2` like '%02') ), (`test`.`t2`.`b2` in on distinct_key where ((`test`.`t2`.`b2` = ``.`c2`)))))) or <`test`.`t2`.`b2`>((`test`.`t2`.`b2`,`test`.`t2`.`b2` in ( (select `test`.`t3`.`c2` from `test`.`t3` where (`test`.`t3`.`c2` like '%03') ), (`test`.`t2`.`b2` in on distinct_key where ((`test`.`t2`.`b2` = ``.`c2`))))))) group by `test`.`t2`.`b1`,`test`.`t2`.`b2` ), (`test`.`t1`.`a1` in on distinct_key where ((`test`.`t1`.`a1` = ``.`b1`) and (`test`.`t1`.`a2` = ``.`b2`)))))) and <`test`.`t1`.`a1`,`test`.`t1`.`a2`>(((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( (select `test`.`t3`.`c1`,`test`.`t3`.`c2` from `test`.`t3` where <`test`.`t3`.`c1`,`test`.`t3`.`c2`>(((`test`.`t3`.`c1`,`test`.`t3`.`c2`),(`test`.`t3`.`c1`,`test`.`t3`.`c2`) in ( (select `test`.`t2i`.`b1`,`test`.`t2i`.`b2` from `test`.`t2i` where (`test`.`t2i`.`b2` > '0') ), (`test`.`t3`.`c1` in on distinct_key where ((`test`.`t3`.`c1` = ``.`b1`) and (`test`.`t3`.`c2` = ``.`b2`)))))) ), (`test`.`t1`.`a1` in on distinct_key where ((`test`.`t1`.`a1` = ``.`c1`) and (`test`.`t1`.`a2` = ``.`c2`)))))))) union (select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from `test`.`t1i` where (<`test`.`t1i`.`a1`,`test`.`t1i`.`a2`>(((`test`.`t1i`.`a1`,`test`.`t1i`.`a2`),(`test`.`t1i`.`a1`,`test`.`t1i`.`a2`) in ( (select `test`.`t2i`.`b1`,`test`.`t2i`.`b2` from `test`.`t2i` where (`test`.`t2i`.`b1` > '0') ), (`test`.`t1i`.`a1` in on distinct_key where ((`test`.`t1i`.`a1` = ``.`b1`) and (`test`.`t1i`.`a2` = ``.`b2`)))))) and <`test`.`t1i`.`a1`,`test`.`t1i`.`a2`>(((`test`.`t1i`.`a1`,`test`.`t1i`.`a2`),(`test`.`t1i`.`a1`,`test`.`t1i`.`a2`) in ( (select `test`.`t3i`.`c1`,`test`.`t3i`.`c2` from `test`.`t3i` where <`test`.`t3i`.`c1`,`test`.`t3i`.`c2`>(((`test`.`t3i`.`c1`,`test`.`t3i`.`c2`),(`test`.`t3i`.`c1`,`test`.`t3i`.`c2`) in ( (select `test`.`t2i`.`b1`,`test`.`t2i`.`b2` from `test`.`t2i` where (`test`.`t2i`.`b2` > '0') ), (`test`.`t3i`.`c1` in on distinct_key where ((`test`.`t3i`.`c1` = ``.`b1`) and (`test`.`t3i`.`c2` = ``.`b2`)))))) ), (`test`.`t1i`.`a1` in on distinct_key where ((`test`.`t1i`.`a1` = ``.`c1`) and (`test`.`t1i`.`a2` = ``.`c2`)))))))) +Note 1003 (select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where (<`test`.`t1`.`a1`,`test`.`t1`.`a2`>(((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( (select `test`.`t2`.`b1`,`test`.`t2`.`b2` from `test`.`t2` where (<`test`.`t2`.`b2`>((`test`.`t2`.`b2`,`test`.`t2`.`b2` in ( (select `test`.`t3`.`c2` from `test`.`t3` where (`test`.`t3`.`c2` like '%02') ), (`test`.`t2`.`b2` in on distinct_key where ((`test`.`t2`.`b2` = ``.`c2`)))))) or <`test`.`t2`.`b2`>((`test`.`t2`.`b2`,`test`.`t2`.`b2` in ( (select `test`.`t3`.`c2` from `test`.`t3` where (`test`.`t3`.`c2` like '%03') ), (`test`.`t2`.`b2` in on distinct_key where ((`test`.`t2`.`b2` = ``.`c2`))))))) ), (`test`.`t1`.`a1` in on distinct_key where ((`test`.`t1`.`a1` = ``.`b1`) and (`test`.`t1`.`a2` = ``.`b2`)))))) and <`test`.`t1`.`a1`,`test`.`t1`.`a2`>(((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( (select `test`.`t3`.`c1`,`test`.`t3`.`c2` from `test`.`t3` where <`test`.`t3`.`c1`,`test`.`t3`.`c2`>(((`test`.`t3`.`c1`,`test`.`t3`.`c2`),(`test`.`t3`.`c1`,`test`.`t3`.`c2`) in ( (select `test`.`t2i`.`b1`,`test`.`t2i`.`b2` from `test`.`t2i` where (`test`.`t2i`.`b2` > '0') ), (`test`.`t3`.`c1` in on distinct_key where ((`test`.`t3`.`c1` = ``.`b1`) and (`test`.`t3`.`c2` = ``.`b2`)))))) ), (`test`.`t1`.`a1` in on distinct_key where ((`test`.`t1`.`a1` = ``.`c1`) and (`test`.`t1`.`a2` = ``.`c2`)))))))) union (select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from `test`.`t1i` where (<`test`.`t1i`.`a1`,`test`.`t1i`.`a2`>(((`test`.`t1i`.`a1`,`test`.`t1i`.`a2`),(`test`.`t1i`.`a1`,`test`.`t1i`.`a2`) in ( (select `test`.`t2i`.`b1`,`test`.`t2i`.`b2` from `test`.`t2i` where (`test`.`t2i`.`b1` > '0') ), (`test`.`t1i`.`a1` in on distinct_key where ((`test`.`t1i`.`a1` = ``.`b1`) and (`test`.`t1i`.`a2` = ``.`b2`)))))) and <`test`.`t1i`.`a1`,`test`.`t1i`.`a2`>(((`test`.`t1i`.`a1`,`test`.`t1i`.`a2`),(`test`.`t1i`.`a1`,`test`.`t1i`.`a2`) in ( (select `test`.`t3i`.`c1`,`test`.`t3i`.`c2` from `test`.`t3i` where <`test`.`t3i`.`c1`,`test`.`t3i`.`c2`>(((`test`.`t3i`.`c1`,`test`.`t3i`.`c2`),(`test`.`t3i`.`c1`,`test`.`t3i`.`c2`) in ( (select `test`.`t2i`.`b1`,`test`.`t2i`.`b2` from `test`.`t2i` where (`test`.`t2i`.`b2` > '0') ), (`test`.`t3i`.`c1` in on distinct_key where ((`test`.`t3i`.`c1` = ``.`b1`) and (`test`.`t3i`.`c2` = ``.`b2`)))))) ), (`test`.`t1i`.`a1` in on distinct_key where ((`test`.`t1i`.`a1` = ``.`c1`) and (`test`.`t1i`.`a2` = ``.`c2`)))))))) (select * from t1 where (a1, a2) in (select b1, b2 from t2 where b2 in (select c2 from t3 where c2 LIKE '%02') or @@ -1150,21 +1150,21 @@ drop table t2; create table t1 (a1 int key); create table t2 (b1 int); insert into t1 values (5); -explain select min(a1) from t1 where 7 in (select b1 from t2 group by b1); +explain select min(a1) from t1 where 7 in (select max(b1) from t2 group by b1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 1 2 MATERIALIZED t2 system NULL NULL NULL NULL 0 const row not found -select min(a1) from t1 where 7 in (select b1 from t2 group by b1); +select min(a1) from t1 where 7 in (select max(b1) from t2 group by b1); min(a1) NULL set @save_optimizer_switch=@@optimizer_switch; set @@optimizer_switch=@optimizer_switch_local_default; set @@optimizer_switch='materialization=off,in_to_exists=on'; -explain select min(a1) from t1 where 7 in (select b1 from t2 group by b1); +explain select min(a1) from t1 where 7 in (select max(b1) from t2 group by b1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 1 2 DEPENDENT SUBQUERY t2 system NULL NULL NULL NULL 0 const row not found -select min(a1) from t1 where 7 in (select b1 from t2 group by b1); +select min(a1) from t1 where 7 in (select max(b1) from t2 group by b1); min(a1) NULL set @@optimizer_switch=@optimizer_switch_local_default; @@ -1231,7 +1231,7 @@ WHERE (t1i) IN ( SELECT t2i FROM t2 WHERE (t2i) IN ( -SELECT t3i +SELECT max(t3i) FROM t3 GROUP BY t3i ) diff --git a/mysql-test/r/subselect_mat_cost_bugs.result b/mysql-test/r/subselect_mat_cost_bugs.result index 87e1060aa87..a8fadfe43bd 100644 --- a/mysql-test/r/subselect_mat_cost_bugs.result +++ b/mysql-test/r/subselect_mat_cost_bugs.result @@ -141,14 +141,14 @@ CREATE TABLE t3 ( f2 varchar(1)) ; EXPLAIN SELECT f2 FROM t3 WHERE ( SELECT MAX( pk ) FROM t1 WHERE EXISTS ( -SELECT DISTINCT f1 -FROM t2 +SELECT max(f1) +FROM t2 GROUP BY f1 ) ) 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 SUBQUERY t1 system NULL NULL NULL NULL 1 -3 SUBQUERY t2 ALL NULL NULL NULL NULL 2 Using temporary +3 SUBQUERY t2 ALL NULL NULL NULL NULL 2 Using temporary; Using filesort drop table t1, t2, t3; # # LP BUG#715034 Item_sum_distinct::clear(): Assertion `tree != 0' failed diff --git a/mysql-test/r/subselect_no_mat.result b/mysql-test/r/subselect_no_mat.result index 59d108dc5c0..c55cb0a425a 100644 --- a/mysql-test/r/subselect_no_mat.result +++ b/mysql-test/r/subselect_no_mat.result @@ -1669,7 +1669,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,((select NULL from `test`.`t2` group by 1) > (`test`.`t3`.`a`)))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,((select max(NULL) from `test`.`t2`) > (`test`.`t3`.`a`)))) select * from t3 where a >= some (select b from t2 group by 1); a explain extended select * from t3 where a >= some (select b from t2 group by 1); @@ -1677,7 +1677,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,((select NULL from `test`.`t2` group by 1) <= (`test`.`t3`.`a`)))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,((select min(NULL) from `test`.`t2`) <= (`test`.`t3`.`a`)))) select * from t3 where NULL >= any (select b from t2); a explain extended select * from t3 where NULL >= any (select b from t2); @@ -1693,7 +1693,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL,((select NULL from `test`.`t2` group by 1) <= NULL))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL,((select min(NULL) from `test`.`t2`) <= NULL))) select * from t3 where NULL >= some (select b from t2); a explain extended select * from t3 where NULL >= some (select b from t2); @@ -1709,7 +1709,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL,((select NULL from `test`.`t2` group by 1) <= NULL))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL,((select min(NULL) from `test`.`t2`) <= NULL))) insert into t2 values (2,2), (2,1), (3,3), (3,1); select * from t3 where a > all (select max(b) from t2 group by a); a @@ -2986,9 +2986,9 @@ Note 1003 select `test`.`t1`.`one` AS `one`,`test`.`t1`.`two` AS `two` from `tes explain extended SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0' group by one,two) as 'test' from t1; id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 8 100.00 -2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 9 100.00 Using where; Using temporary +2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 9 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`one` AS `one`,`test`.`t1`.`two` AS `two`,<`test`.`t1`.`one`,`test`.`t1`.`two`>(((`test`.`t1`.`one`,`test`.`t1`.`two`),(select `test`.`t2`.`one`,`test`.`t2`.`two` from `test`.`t2` where (`test`.`t2`.`flag` = '0') group by `test`.`t2`.`one`,`test`.`t2`.`two` having (trigcond((((`test`.`t1`.`one`) = `test`.`t2`.`one`) or isnull(`test`.`t2`.`one`))) and trigcond((((`test`.`t1`.`two`) = `test`.`t2`.`two`) or isnull(`test`.`t2`.`two`))) and trigcond((`test`.`t2`.`one`)) and trigcond((`test`.`t2`.`two`)))))) AS `test` from `test`.`t1` +Note 1003 select `test`.`t1`.`one` AS `one`,`test`.`t1`.`two` AS `two`,<`test`.`t1`.`one`,`test`.`t1`.`two`>(((`test`.`t1`.`one`,`test`.`t1`.`two`),(select `test`.`t2`.`one`,`test`.`t2`.`two` from `test`.`t2` where ((`test`.`t2`.`flag` = '0') and trigcond((((`test`.`t1`.`one`) = `test`.`t2`.`one`) or isnull(`test`.`t2`.`one`))) and trigcond((((`test`.`t1`.`two`) = `test`.`t2`.`two`) or isnull(`test`.`t2`.`two`)))) having (trigcond((`test`.`t2`.`one`)) and trigcond((`test`.`t2`.`two`)))))) AS `test` from `test`.`t1` DROP TABLE t1,t2; set optimizer_switch=@tmp11867_optimizer_switch; CREATE TABLE t1 (a char(5), b char(5)); @@ -4467,18 +4467,18 @@ a drop table t1, t2; CREATE TABLE t1 (a INT); INSERT INTO t1 VALUES (1),(2); -EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1 IN (SELECT 1 FROM t1 GROUP BY a); +EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1 IN (SELECT min(a) 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 Warnings: -Note 1003 select 1 AS `1` from `test`.`t1` where <1>((1,(select 1 from `test`.`t1` group by `test`.`t1`.`a` having (1 = (1))))) -EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1 IN (SELECT 1 FROM t1 WHERE a > 3 GROUP BY a); +Note 1003 select 1 AS `1` from `test`.`t1` where <1>((1,(select min(`test`.`t1`.`a`) from `test`.`t1` group by `test`.`t1`.`a` having (1 = (min(`test`.`t1`.`a`)))))) +EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1 IN (SELECT min(a) FROM t1 WHERE a > 3 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 where; Using temporary Warnings: -Note 1003 select 1 AS `1` from `test`.`t1` where <1>((1,(select 1 from `test`.`t1` where (`test`.`t1`.`a` > 3) group by `test`.`t1`.`a` having (1 = (1))))) +Note 1003 select 1 AS `1` from `test`.`t1` where <1>((1,(select min(`test`.`t1`.`a`) from `test`.`t1` where (`test`.`t1`.`a` > 3) group by `test`.`t1`.`a` having (1 = (min(`test`.`t1`.`a`)))))) DROP TABLE t1; # # Bug#45061: Incorrectly market field caused wrong result. @@ -4822,8 +4822,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); @@ -5247,18 +5245,21 @@ DROP table t1,t2; # CREATE TABLE t1 (a int, b int) ; INSERT INTO t1 VALUES (0,0),(0,0); +set @optimizer_switch_save=@@optimizer_switch; +set @@optimizer_switch='semijoin=off,materialization=on,in_to_exists=on'; EXPLAIN SELECT b FROM t1 WHERE ('0') IN ( SELECT a FROM t1 GROUP BY a ) GROUP BY b; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using temporary; Using filesort -2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 2 Using temporary +2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 2 Using where SELECT b FROM t1 WHERE ('0') IN ( SELECT a FROM t1 GROUP BY a ) GROUP BY b; b 0 +set @@optimizer_switch=@optimizer_switch_save; DROP TABLE t1; # # Bug #11765713 58705: @@ -5654,7 +5655,7 @@ 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 (flat, BNL join) -2 DEPENDENT SUBQUERY t2 ALL f1_key NULL NULL NULL 10 Range checked for each record (index map: 0x1); Using temporary +2 DEPENDENT SUBQUERY t2 index f1_key f1_key 4 NULL 10 Using where; Using index DROP TABLE t1,t2; # # LP bug #826279: assertion failure with GROUP BY a result of subquery @@ -5882,7 +5883,7 @@ SET @@optimizer_switch='semijoin=off,materialization=off,in_to_exists=on,subquer EXPLAIN SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 index NULL a 4 NULL 2 Using where; Using index -2 DEPENDENT SUBQUERY t1 index NULL a 4 NULL 1 Using index +2 DEPENDENT SUBQUERY t1 index_subquery a a 4 func 2 Using index SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1); a 2009-01-01 diff --git a/mysql-test/r/subselect_no_opts.result b/mysql-test/r/subselect_no_opts.result index d4c3694f2c6..0b77366469c 100644 --- a/mysql-test/r/subselect_no_opts.result +++ b/mysql-test/r/subselect_no_opts.result @@ -1665,7 +1665,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,((select NULL from `test`.`t2` group by 1) > (`test`.`t3`.`a`)))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,((select max(NULL) from `test`.`t2`) > (`test`.`t3`.`a`)))) select * from t3 where a >= some (select b from t2 group by 1); a explain extended select * from t3 where a >= some (select b from t2 group by 1); @@ -1673,7 +1673,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,((select NULL from `test`.`t2` group by 1) <= (`test`.`t3`.`a`)))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,((select min(NULL) from `test`.`t2`) <= (`test`.`t3`.`a`)))) select * from t3 where NULL >= any (select b from t2); a explain extended select * from t3 where NULL >= any (select b from t2); @@ -1689,7 +1689,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL,((select NULL from `test`.`t2` group by 1) <= NULL))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL,((select min(NULL) from `test`.`t2`) <= NULL))) select * from t3 where NULL >= some (select b from t2); a explain extended select * from t3 where NULL >= some (select b from t2); @@ -1705,7 +1705,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL,((select NULL from `test`.`t2` group by 1) <= NULL))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL,((select min(NULL) from `test`.`t2`) <= NULL))) insert into t2 values (2,2), (2,1), (3,3), (3,1); select * from t3 where a > all (select max(b) from t2 group by a); a @@ -2982,9 +2982,9 @@ Note 1003 select `test`.`t1`.`one` AS `one`,`test`.`t1`.`two` AS `two` from `tes explain extended SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0' group by one,two) as 'test' from t1; id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 8 100.00 -2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 9 100.00 Using where; Using temporary +2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 9 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`one` AS `one`,`test`.`t1`.`two` AS `two`,((`test`.`t1`.`one`,`test`.`t1`.`two`),(select `test`.`t2`.`one`,`test`.`t2`.`two` from `test`.`t2` where (`test`.`t2`.`flag` = '0') group by `test`.`t2`.`one`,`test`.`t2`.`two` having (trigcond((((`test`.`t1`.`one`) = `test`.`t2`.`one`) or isnull(`test`.`t2`.`one`))) and trigcond((((`test`.`t1`.`two`) = `test`.`t2`.`two`) or isnull(`test`.`t2`.`two`))) and trigcond((`test`.`t2`.`one`)) and trigcond((`test`.`t2`.`two`))))) AS `test` from `test`.`t1` +Note 1003 select `test`.`t1`.`one` AS `one`,`test`.`t1`.`two` AS `two`,((`test`.`t1`.`one`,`test`.`t1`.`two`),(select `test`.`t2`.`one`,`test`.`t2`.`two` from `test`.`t2` where ((`test`.`t2`.`flag` = '0') and trigcond((((`test`.`t1`.`one`) = `test`.`t2`.`one`) or isnull(`test`.`t2`.`one`))) and trigcond((((`test`.`t1`.`two`) = `test`.`t2`.`two`) or isnull(`test`.`t2`.`two`)))) having (trigcond((`test`.`t2`.`one`)) and trigcond((`test`.`t2`.`two`))))) AS `test` from `test`.`t1` DROP TABLE t1,t2; set optimizer_switch=@tmp11867_optimizer_switch; CREATE TABLE t1 (a char(5), b char(5)); @@ -4463,18 +4463,18 @@ a drop table t1, t2; CREATE TABLE t1 (a INT); INSERT INTO t1 VALUES (1),(2); -EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1 IN (SELECT 1 FROM t1 GROUP BY a); +EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1 IN (SELECT min(a) 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 Warnings: -Note 1003 select 1 AS `1` from `test`.`t1` where (1,(select 1 from `test`.`t1` group by `test`.`t1`.`a` having (1 = (1)))) -EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1 IN (SELECT 1 FROM t1 WHERE a > 3 GROUP BY a); +Note 1003 select 1 AS `1` from `test`.`t1` where (1,(select min(`test`.`t1`.`a`) from `test`.`t1` group by `test`.`t1`.`a` having (1 = (min(`test`.`t1`.`a`))))) +EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1 IN (SELECT min(a) FROM t1 WHERE a > 3 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 where; Using temporary 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 = (1)))) +Note 1003 select 1 AS `1` from `test`.`t1` where (1,(select min(`test`.`t1`.`a`) from `test`.`t1` where (`test`.`t1`.`a` > 3) group by `test`.`t1`.`a` having (1 = (min(`test`.`t1`.`a`))))) DROP TABLE t1; # # Bug#45061: Incorrectly market field caused wrong result. @@ -4818,8 +4818,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); @@ -5243,18 +5241,21 @@ DROP table t1,t2; # CREATE TABLE t1 (a int, b int) ; INSERT INTO t1 VALUES (0,0),(0,0); +set @optimizer_switch_save=@@optimizer_switch; +set @@optimizer_switch='semijoin=off,materialization=on,in_to_exists=on'; EXPLAIN SELECT b FROM t1 WHERE ('0') IN ( SELECT a FROM t1 GROUP BY a ) GROUP BY b; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using temporary; Using filesort -2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 2 Using temporary +2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 2 Using where SELECT b FROM t1 WHERE ('0') IN ( SELECT a FROM t1 GROUP BY a ) GROUP BY b; b 0 +set @@optimizer_switch=@optimizer_switch_save; DROP TABLE t1; # # Bug #11765713 58705: @@ -5650,7 +5651,7 @@ 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 (flat, BNL join) -2 DEPENDENT SUBQUERY t2 ALL f1_key NULL NULL NULL 10 Range checked for each record (index map: 0x1); Using temporary +2 DEPENDENT SUBQUERY t2 index f1_key f1_key 4 NULL 10 Using where; Using index DROP TABLE t1,t2; # # LP bug #826279: assertion failure with GROUP BY a result of subquery @@ -5878,7 +5879,7 @@ SET @@optimizer_switch='semijoin=off,materialization=off,in_to_exists=on,subquer EXPLAIN SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 index NULL a 4 NULL 2 Using where; Using index -2 DEPENDENT SUBQUERY t1 index NULL a 4 NULL 1 Using index +2 DEPENDENT SUBQUERY t1 index_subquery a a 4 func 2 Using index SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1); a 2009-01-01 diff --git a/mysql-test/r/subselect_no_scache.result b/mysql-test/r/subselect_no_scache.result index aac4ce6e39d..fb9cda3c412 100644 --- a/mysql-test/r/subselect_no_scache.result +++ b/mysql-test/r/subselect_no_scache.result @@ -1668,7 +1668,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,((select NULL from `test`.`t2` group by 1) > (`test`.`t3`.`a`)))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,((select max(NULL) from `test`.`t2`) > (`test`.`t3`.`a`)))) select * from t3 where a >= some (select b from t2 group by 1); a explain extended select * from t3 where a >= some (select b from t2 group by 1); @@ -1676,7 +1676,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,((select NULL from `test`.`t2` group by 1) <= (`test`.`t3`.`a`)))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,((select min(NULL) from `test`.`t2`) <= (`test`.`t3`.`a`)))) select * from t3 where NULL >= any (select b from t2); a explain extended select * from t3 where NULL >= any (select b from t2); @@ -1692,7 +1692,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL,((select NULL from `test`.`t2` group by 1) <= NULL))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL,((select min(NULL) from `test`.`t2`) <= NULL))) select * from t3 where NULL >= some (select b from t2); a explain extended select * from t3 where NULL >= some (select b from t2); @@ -1708,7 +1708,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL,((select NULL from `test`.`t2` group by 1) <= NULL))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL,((select min(NULL) from `test`.`t2`) <= NULL))) insert into t2 values (2,2), (2,1), (3,3), (3,1); select * from t3 where a > all (select max(b) from t2 group by a); a @@ -2986,9 +2986,9 @@ Note 1003 select `test`.`t1`.`one` AS `one`,`test`.`t1`.`two` AS `two` from `tes explain extended SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0' group by one,two) as 'test' from t1; id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 8 100.00 -2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 9 100.00 Using where; Using temporary +2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 9 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`one` AS `one`,`test`.`t1`.`two` AS `two`,((`test`.`t1`.`one`,`test`.`t1`.`two`),(select `test`.`t2`.`one`,`test`.`t2`.`two` from `test`.`t2` where (`test`.`t2`.`flag` = '0') group by `test`.`t2`.`one`,`test`.`t2`.`two` having (trigcond((((`test`.`t1`.`one`) = `test`.`t2`.`one`) or isnull(`test`.`t2`.`one`))) and trigcond((((`test`.`t1`.`two`) = `test`.`t2`.`two`) or isnull(`test`.`t2`.`two`))) and trigcond((`test`.`t2`.`one`)) and trigcond((`test`.`t2`.`two`))))) AS `test` from `test`.`t1` +Note 1003 select `test`.`t1`.`one` AS `one`,`test`.`t1`.`two` AS `two`,((`test`.`t1`.`one`,`test`.`t1`.`two`),(select `test`.`t2`.`one`,`test`.`t2`.`two` from `test`.`t2` where ((`test`.`t2`.`flag` = '0') and trigcond((((`test`.`t1`.`one`) = `test`.`t2`.`one`) or isnull(`test`.`t2`.`one`))) and trigcond((((`test`.`t1`.`two`) = `test`.`t2`.`two`) or isnull(`test`.`t2`.`two`)))) having (trigcond((`test`.`t2`.`one`)) and trigcond((`test`.`t2`.`two`))))) AS `test` from `test`.`t1` DROP TABLE t1,t2; set optimizer_switch=@tmp11867_optimizer_switch; CREATE TABLE t1 (a char(5), b char(5)); @@ -4469,20 +4469,20 @@ a drop table t1, t2; CREATE TABLE t1 (a INT); INSERT INTO t1 VALUES (1),(2); -EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1 IN (SELECT 1 FROM t1 GROUP BY a); +EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1 IN (SELECT min(a) 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 -1 PRIMARY const distinct_key distinct_key 4 const 1 100.00 +1 PRIMARY const distinct_key distinct_key 5 const 1 100.00 2 MATERIALIZED t1 ALL NULL NULL NULL NULL 2 100.00 Using temporary Warnings: -Note 1003 select 1 AS `1` from (select 1 from `test`.`t1` group by `test`.`t1`.`a`) join `test`.`t1` where (``.`1` = 1) -EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1 IN (SELECT 1 FROM t1 WHERE a > 3 GROUP BY a); +Note 1003 select 1 AS `1` from (select min(`test`.`t1`.`a`) from `test`.`t1` group by `test`.`t1`.`a`) join `test`.`t1` where (``.`min(a)` = 1) +EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1 IN (SELECT min(a) FROM t1 WHERE a > 3 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 -1 PRIMARY const distinct_key distinct_key 4 const 1 100.00 +1 PRIMARY const distinct_key distinct_key 5 const 1 100.00 2 MATERIALIZED t1 ALL NULL NULL NULL NULL 2 100.00 Using where; Using temporary Warnings: -Note 1003 select 1 AS `1` from (select 1 from `test`.`t1` where (`test`.`t1`.`a` > 3) group by `test`.`t1`.`a`) join `test`.`t1` where (``.`1` = 1) +Note 1003 select 1 AS `1` from (select min(`test`.`t1`.`a`) from `test`.`t1` where (`test`.`t1`.`a` > 3) group by `test`.`t1`.`a`) join `test`.`t1` where (``.`min(a)` = 1) DROP TABLE t1; # # Bug#45061: Incorrectly market field caused wrong result. @@ -4826,8 +4826,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); @@ -5252,18 +5250,21 @@ DROP table t1,t2; # CREATE TABLE t1 (a int, b int) ; INSERT INTO t1 VALUES (0,0),(0,0); +set @optimizer_switch_save=@@optimizer_switch; +set @@optimizer_switch='semijoin=off,materialization=on,in_to_exists=on'; EXPLAIN SELECT b FROM t1 WHERE ('0') IN ( SELECT a FROM t1 GROUP BY a ) GROUP BY b; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using temporary; Using filesort -2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 2 Using temporary +2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 2 Using where SELECT b FROM t1 WHERE ('0') IN ( SELECT a FROM t1 GROUP BY a ) GROUP BY b; b 0 +set @@optimizer_switch=@optimizer_switch_save; DROP TABLE t1; # # Bug #11765713 58705: @@ -5659,7 +5660,7 @@ 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 (flat, BNL join) -2 DEPENDENT SUBQUERY t2 ALL f1_key NULL NULL NULL 10 Range checked for each record (index map: 0x1); Using temporary +2 DEPENDENT SUBQUERY t2 index f1_key f1_key 4 NULL 10 Using where; Using index DROP TABLE t1,t2; # # LP bug #826279: assertion failure with GROUP BY a result of subquery @@ -5887,7 +5888,7 @@ SET @@optimizer_switch='semijoin=off,materialization=off,in_to_exists=on,subquer EXPLAIN SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 index NULL a 4 NULL 2 Using where; Using index -2 DEPENDENT SUBQUERY t1 index NULL a 4 NULL 1 Using index +2 DEPENDENT SUBQUERY t1 index_subquery a a 4 func 2 Using index SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1); a 2009-01-01 diff --git a/mysql-test/r/subselect_no_semijoin.result b/mysql-test/r/subselect_no_semijoin.result index 3647e2fe2b3..381b2f12665 100644 --- a/mysql-test/r/subselect_no_semijoin.result +++ b/mysql-test/r/subselect_no_semijoin.result @@ -1665,7 +1665,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,((select NULL from `test`.`t2` group by 1) > (`test`.`t3`.`a`)))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,((select max(NULL) from `test`.`t2`) > (`test`.`t3`.`a`)))) select * from t3 where a >= some (select b from t2 group by 1); a explain extended select * from t3 where a >= some (select b from t2 group by 1); @@ -1673,7 +1673,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,((select NULL from `test`.`t2` group by 1) <= (`test`.`t3`.`a`)))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,((select min(NULL) from `test`.`t2`) <= (`test`.`t3`.`a`)))) select * from t3 where NULL >= any (select b from t2); a explain extended select * from t3 where NULL >= any (select b from t2); @@ -1689,7 +1689,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL,((select NULL from `test`.`t2` group by 1) <= NULL))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL,((select min(NULL) from `test`.`t2`) <= NULL))) select * from t3 where NULL >= some (select b from t2); a explain extended select * from t3 where NULL >= some (select b from t2); @@ -1705,7 +1705,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL,((select NULL from `test`.`t2` group by 1) <= NULL))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL,((select min(NULL) from `test`.`t2`) <= NULL))) insert into t2 values (2,2), (2,1), (3,3), (3,1); select * from t3 where a > all (select max(b) from t2 group by a); a @@ -2982,9 +2982,9 @@ Note 1003 select `test`.`t1`.`one` AS `one`,`test`.`t1`.`two` AS `two` from `tes explain extended SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0' group by one,two) as 'test' from t1; id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 8 100.00 -2 MATERIALIZED t2 ALL NULL NULL NULL NULL 9 100.00 Using where; Using temporary +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 9 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`one` AS `one`,`test`.`t1`.`two` AS `two`,<`test`.`t1`.`one`,`test`.`t1`.`two`>(((`test`.`t1`.`one`,`test`.`t1`.`two`),(`test`.`t1`.`one`,`test`.`t1`.`two`) in ( (select `test`.`t2`.`one`,`test`.`t2`.`two` from `test`.`t2` where (`test`.`t2`.`flag` = '0') group by `test`.`t2`.`one`,`test`.`t2`.`two` ), (`test`.`t1`.`one` in on distinct_key where ((`test`.`t1`.`one` = ``.`one`) and (`test`.`t1`.`two` = ``.`two`)))))) AS `test` from `test`.`t1` +Note 1003 select `test`.`t1`.`one` AS `one`,`test`.`t1`.`two` AS `two`,<`test`.`t1`.`one`,`test`.`t1`.`two`>(((`test`.`t1`.`one`,`test`.`t1`.`two`),(`test`.`t1`.`one`,`test`.`t1`.`two`) in ( (select `test`.`t2`.`one`,`test`.`t2`.`two` from `test`.`t2` where (`test`.`t2`.`flag` = '0') ), (`test`.`t1`.`one` in on distinct_key where ((`test`.`t1`.`one` = ``.`one`) and (`test`.`t1`.`two` = ``.`two`)))))) AS `test` from `test`.`t1` DROP TABLE t1,t2; set optimizer_switch=@tmp11867_optimizer_switch; CREATE TABLE t1 (a char(5), b char(5)); @@ -4463,18 +4463,18 @@ a drop table t1, t2; CREATE TABLE t1 (a INT); INSERT INTO t1 VALUES (1),(2); -EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1 IN (SELECT 1 FROM t1 GROUP BY a); +EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1 IN (SELECT min(a) 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 MATERIALIZED t1 ALL NULL NULL NULL NULL 2 100.00 Using temporary Warnings: -Note 1003 select 1 AS `1` from `test`.`t1` where <1>((1,1 in ( (select 1 from `test`.`t1` group by `test`.`t1`.`a` ), (1 in on distinct_key where ((1 = ``.`1`)))))) -EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1 IN (SELECT 1 FROM t1 WHERE a > 3 GROUP BY a); +Note 1003 select 1 AS `1` from `test`.`t1` where <1>((1,1 in ( (select min(`test`.`t1`.`a`) from `test`.`t1` group by `test`.`t1`.`a` ), (1 in on distinct_key where ((1 = ``.`min(a)`)))))) +EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1 IN (SELECT min(a) FROM t1 WHERE a > 3 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 MATERIALIZED t1 ALL NULL NULL NULL NULL 2 100.00 Using where; Using temporary Warnings: -Note 1003 select 1 AS `1` from `test`.`t1` where <1>((1,1 in ( (select 1 from `test`.`t1` where (`test`.`t1`.`a` > 3) group by `test`.`t1`.`a` ), (1 in on distinct_key where ((1 = ``.`1`)))))) +Note 1003 select 1 AS `1` from `test`.`t1` where <1>((1,1 in ( (select min(`test`.`t1`.`a`) from `test`.`t1` where (`test`.`t1`.`a` > 3) group by `test`.`t1`.`a` ), (1 in on distinct_key where ((1 = ``.`min(a)`)))))) DROP TABLE t1; # # Bug#45061: Incorrectly market field caused wrong result. @@ -4818,8 +4818,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); @@ -5243,18 +5241,21 @@ DROP table t1,t2; # CREATE TABLE t1 (a int, b int) ; INSERT INTO t1 VALUES (0,0),(0,0); +set @optimizer_switch_save=@@optimizer_switch; +set @@optimizer_switch='semijoin=off,materialization=on,in_to_exists=on'; EXPLAIN SELECT b FROM t1 WHERE ('0') IN ( SELECT a FROM t1 GROUP BY a ) GROUP BY b; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using temporary; Using filesort -2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 2 Using temporary +2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 2 Using where SELECT b FROM t1 WHERE ('0') IN ( SELECT a FROM t1 GROUP BY a ) GROUP BY b; b 0 +set @@optimizer_switch=@optimizer_switch_save; DROP TABLE t1; # # Bug #11765713 58705: @@ -5650,7 +5651,7 @@ 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 (flat, BNL join) -2 DEPENDENT SUBQUERY t2 ALL f1_key NULL NULL NULL 10 Range checked for each record (index map: 0x1); Using temporary +2 DEPENDENT SUBQUERY t2 index f1_key f1_key 4 NULL 10 Using where; Using index DROP TABLE t1,t2; # # LP bug #826279: assertion failure with GROUP BY a result of subquery @@ -5878,7 +5879,7 @@ SET @@optimizer_switch='semijoin=off,materialization=off,in_to_exists=on,subquer EXPLAIN SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 index NULL a 4 NULL 2 Using where; Using index -2 DEPENDENT SUBQUERY t1 index NULL a 4 NULL 1 Using index +2 DEPENDENT SUBQUERY t1 index_subquery a a 4 func 2 Using index SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1); a 2009-01-01 diff --git a/mysql-test/r/subselect_sj2_jcl6.result b/mysql-test/r/subselect_sj2_jcl6.result index 1f84da5433d..80c24652cbd 100644 --- a/mysql-test/r/subselect_sj2_jcl6.result +++ b/mysql-test/r/subselect_sj2_jcl6.result @@ -972,10 +972,18 @@ SET join_cache_level = 3; EXPLAIN SELECT * FROM t1 WHERE b IN (SELECT a FROM t2 GROUP BY a); id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 1 +1 PRIMARY t2 ALL NULL NULL NULL NULL 1 Using where; FirstMatch(t1); Using join buffer (flat, BNL join) +SELECT * FROM t1 WHERE b IN (SELECT a FROM t2 GROUP BY a); +a b +v v +EXPLAIN +SELECT * FROM t1 WHERE b IN (SELECT max(a) FROM t2 GROUP BY a); +id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 1 Using where 1 PRIMARY hash_ALL distinct_key #hash#distinct_key 5 test.t1.b 1 Using join buffer (flat, BNLH join) 2 MATERIALIZED t2 ALL NULL NULL NULL NULL 1 Using temporary -SELECT * FROM t1 WHERE b IN (SELECT a FROM t2 GROUP BY a); +SELECT * FROM t1 WHERE b IN (SELECT max(a) FROM t2 GROUP BY a); a b v v set optimizer_switch=@tmp_optimizer_switch; diff --git a/mysql-test/r/subselect_sj_mat.result b/mysql-test/r/subselect_sj_mat.result index f8d8505926c..82f012bcbf1 100644 --- a/mysql-test/r/subselect_sj_mat.result +++ b/mysql-test/r/subselect_sj_mat.result @@ -58,11 +58,11 @@ a1 a2 explain extended select * from t1 where a1 in (select b1 from t2 where b1 > '0' group by b1); id select_type table type possible_keys key key_len ref rows filtered Extra -1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where -1 PRIMARY eq_ref distinct_key distinct_key 9 test.t1.a1 1 100.00 -2 MATERIALIZED t2 ALL NULL NULL NULL NULL 5 100.00 Using where; Using temporary +1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 +1 PRIMARY eq_ref distinct_key distinct_key 9 func 1 100.00 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 5 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from (select `test`.`t2`.`b1` from `test`.`t2` where (`test`.`t2`.`b1` > '0') group by `test`.`t2`.`b1`) join `test`.`t1` where (``.`b1` = `test`.`t1`.`a1`) +Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` semi join (`test`.`t2`) where ((`test`.`t2`.`b1` > '0')) select * from t1 where a1 in (select b1 from t2 where b1 > '0' group by b1); a1 a2 1 - 01 2 - 01 @@ -70,11 +70,11 @@ a1 a2 explain extended select * from t1 where (a1, a2) in (select b1, b2 from t2 where b1 > '0' group by b1, b2); id select_type table type possible_keys key key_len ref rows filtered Extra -1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where -1 PRIMARY eq_ref distinct_key distinct_key 18 test.t1.a1,test.t1.a2 1 100.00 -2 MATERIALIZED t2 ALL NULL NULL NULL NULL 5 100.00 Using where; Using temporary +1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 +1 PRIMARY eq_ref distinct_key distinct_key 18 func,func 1 100.00 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 5 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from (select `test`.`t2`.`b1`,`test`.`t2`.`b2` from `test`.`t2` where (`test`.`t2`.`b1` > '0') group by `test`.`t2`.`b1`,`test`.`t2`.`b2`) join `test`.`t1` where ((``.`b2` = `test`.`t1`.`a2`) and (``.`b1` = `test`.`t1`.`a1`)) +Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` semi join (`test`.`t2`) where ((`test`.`t2`.`b1` > '0')) select * from t1 where (a1, a2) in (select b1, b2 from t2 where b1 > '0' group by b1, b2); a1 a2 1 - 01 2 - 01 @@ -103,14 +103,14 @@ a1 a2 1 - 01 2 - 01 1 - 02 2 - 02 explain extended -select * from t1i where a1 in (select b1 from t2i where b1 > '0' group by b1); +select * from t1i where a1 in (select max(b1) from t2i where b1 > '0' group by b1); id select_type table type possible_keys key key_len ref rows filtered Extra -1 PRIMARY ALL distinct_key # NULL # 3 100.00 # -1 PRIMARY t1i ref it1i1,it1i3 # 9 # 1 100.00 # -2 MATERIALIZED t2i range it2i1,it2i3 # 9 # 3 100.00 # +1 PRIMARY t1i index it1i1,it1i3 # 18 # 3 100.00 # +1 PRIMARY eq_ref distinct_key # 9 # 1 100.00 # +2 MATERIALIZED t2i index it2i1,it2i3 # 9 # 5 100.00 # Warnings: -Note 1003 select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from (select `test`.`t2i`.`b1` from `test`.`t2i` where (`test`.`t2i`.`b1` > '0') group by `test`.`t2i`.`b1`) join `test`.`t1i` where (`test`.`t1i`.`a1` = ``.`b1`) -select * from t1i where a1 in (select b1 from t2i where b1 > '0' group by b1); +Note 1003 select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from (select max(`test`.`t2i`.`b1`) from `test`.`t2i` where (`test`.`t2i`.`b1` > '0') group by `test`.`t2i`.`b1`) join `test`.`t1i` where (``.`max(b1)` = `test`.`t1i`.`a1`) +select * from t1i where a1 in (select max(b1) from t2i where b1 > '0' group by b1); a1 a2 1 - 01 2 - 01 1 - 02 2 - 02 @@ -126,14 +126,14 @@ a1 a2 1 - 01 2 - 01 1 - 02 2 - 02 explain extended -select * from t1i where (a1, a2) in (select b1, b2 from t2i where b1 > '0' group by b1, b2); +select * from t1i where (a1, a2) in (select b1, max(b2) from t2i where b1 > '0' group by b1); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1i index it1i1,it1i2,it1i3 # # # 3 100.00 # 1 PRIMARY eq_ref distinct_key # # # 1 100.00 # 2 MATERIALIZED t2i range it2i1,it2i3 # # # 3 100.00 # Warnings: -Note 1003 select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from (select `test`.`t2i`.`b1`,`test`.`t2i`.`b2` from `test`.`t2i` where (`test`.`t2i`.`b1` > '0') group by `test`.`t2i`.`b1`,`test`.`t2i`.`b2`) join `test`.`t1i` where ((``.`b2` = `test`.`t1i`.`a2`) and (``.`b1` = `test`.`t1i`.`a1`)) -select * from t1i where (a1, a2) in (select b1, b2 from t2i where b1 > '0' group by b1, b2); +Note 1003 select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from (select `test`.`t2i`.`b1`,max(`test`.`t2i`.`b2`) from `test`.`t2i` where (`test`.`t2i`.`b1` > '0') group by `test`.`t2i`.`b1`) join `test`.`t1i` where ((``.`max(b2)` = `test`.`t1i`.`a2`) and (``.`b1` = `test`.`t1i`.`a1`)) +select * from t1i where (a1, a2) in (select b1, max(b2) from t2i where b1 > '0' group by b1); a1 a2 1 - 01 2 - 01 1 - 02 2 - 02 @@ -399,10 +399,11 @@ where (a1, a2) in (select b1, b2 from t2i where b1 > '0') and (a1, a2) in (select c1, c2 from t3i where (c1, c2) in (select b1, b2 from t2i where b2 > '0'))); id select_type table type possible_keys key key_len ref rows filtered Extra -1 PRIMARY ALL distinct_key # # # 5 0.00 # -1 PRIMARY t3 ALL NULL # # # 4 100.00 # 1 PRIMARY t1 ALL NULL # # # 3 100.00 # -1 PRIMARY t2i ref it2i1,it2i2,it2i3 # # # 2 100.00 # +1 PRIMARY eq_ref distinct_key # # # 1 100.00 # +1 PRIMARY eq_ref distinct_key # # # 1 100.00 # +5 MATERIALIZED t3 ALL NULL # # # 4 100.00 # +5 MATERIALIZED t2i index it2i1,it2i2,it2i3 # # # 5 80.00 # 2 MATERIALIZED t2 ALL NULL # # # 5 100.00 # 4 MATERIALIZED t3 ALL NULL # # # 4 100.00 # 3 MATERIALIZED t3 ALL NULL # # # 4 100.00 # @@ -412,7 +413,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 7 UNION t2i ref it2i1,it2i2,it2i3 # # # 2 100.00 # NULL UNION RESULT ALL NULL # # # NULL NULL # Warnings: -Note 1003 (select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from (select `test`.`t2`.`b1`,`test`.`t2`.`b2` from `test`.`t2` where (<`test`.`t2`.`b2`>((`test`.`t2`.`b2`,`test`.`t2`.`b2` in ( (select `test`.`t3`.`c2` from `test`.`t3` where (`test`.`t3`.`c2` like '%02') ), (`test`.`t2`.`b2` in on distinct_key where ((`test`.`t2`.`b2` = ``.`c2`)))))) or <`test`.`t2`.`b2`>((`test`.`t2`.`b2`,`test`.`t2`.`b2` in ( (select `test`.`t3`.`c2` from `test`.`t3` where (`test`.`t3`.`c2` like '%03') ), (`test`.`t2`.`b2` in on distinct_key where ((`test`.`t2`.`b2` = ``.`c2`))))))) group by `test`.`t2`.`b1`,`test`.`t2`.`b2`) semi join (`test`.`t2i` join `test`.`t3`) join `test`.`t1` where ((`test`.`t3`.`c2` = ``.`b2`) and (`test`.`t1`.`a2` = ``.`b2`) and (`test`.`t2i`.`b2` = ``.`b2`) and (`test`.`t3`.`c1` = ``.`b1`) and (`test`.`t1`.`a1` = ``.`b1`) and (`test`.`t2i`.`b1` = ``.`b1`) and (``.`b2` > '0'))) union (select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from `test`.`t1i` semi join (`test`.`t2i`) semi join (`test`.`t2i` join `test`.`t3i`) where ((`test`.`t1i`.`a2` = `test`.`t2i`.`b2`) and (`test`.`t3i`.`c2` = `test`.`t2i`.`b2`) and (`test`.`t2i`.`b2` = `test`.`t2i`.`b2`) and (`test`.`t1i`.`a1` = `test`.`t2i`.`b1`) and (`test`.`t3i`.`c1` = `test`.`t2i`.`b1`) and (`test`.`t2i`.`b1` = `test`.`t2i`.`b1`) and (`test`.`t2i`.`b1` > '0') and (`test`.`t2i`.`b2` > '0'))) +Note 1003 (select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` semi join (`test`.`t2`) semi join (`test`.`t2i` join `test`.`t3`) where ((`test`.`t2i`.`b2` = `test`.`t3`.`c2`) and (`test`.`t2i`.`b1` = `test`.`t3`.`c1`) and (<`test`.`t2`.`b2`>((`test`.`t2`.`b2`,`test`.`t2`.`b2` in ( (select `test`.`t3`.`c2` from `test`.`t3` where (`test`.`t3`.`c2` like '%02') ), (`test`.`t2`.`b2` in on distinct_key where ((`test`.`t2`.`b2` = ``.`c2`)))))) or <`test`.`t2`.`b2`>((`test`.`t2`.`b2`,`test`.`t2`.`b2` in ( (select `test`.`t3`.`c2` from `test`.`t3` where (`test`.`t3`.`c2` like '%03') ), (`test`.`t2`.`b2` in on distinct_key where ((`test`.`t2`.`b2` = ``.`c2`))))))) and (`test`.`t3`.`c2` > '0'))) union (select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from `test`.`t1i` semi join (`test`.`t2i`) semi join (`test`.`t2i` join `test`.`t3i`) where ((`test`.`t1i`.`a2` = `test`.`t2i`.`b2`) and (`test`.`t3i`.`c2` = `test`.`t2i`.`b2`) and (`test`.`t2i`.`b2` = `test`.`t2i`.`b2`) and (`test`.`t1i`.`a1` = `test`.`t2i`.`b1`) and (`test`.`t3i`.`c1` = `test`.`t2i`.`b1`) and (`test`.`t2i`.`b1` = `test`.`t2i`.`b1`) and (`test`.`t2i`.`b1` > '0') and (`test`.`t2i`.`b2` > '0'))) (select * from t1 where (a1, a2) in (select b1, b2 from t2 where b2 in (select c2 from t3 where c2 LIKE '%02') or @@ -1183,22 +1184,22 @@ drop table t2; create table t1 (a1 int key); create table t2 (b1 int); insert into t1 values (5); -explain select min(a1) from t1 where 7 in (select b1 from t2 group by b1); +explain select min(a1) from t1 where 7 in (select max(b1) from t2 group by b1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 1 1 PRIMARY const distinct_key distinct_key 5 const 1 2 MATERIALIZED NULL NULL NULL NULL NULL NULL NULL no matching row in const table -select min(a1) from t1 where 7 in (select b1 from t2 group by b1); +select min(a1) from t1 where 7 in (select max(b1) from t2 group by b1); min(a1) NULL set @save_optimizer_switch=@@optimizer_switch; set @@optimizer_switch=@optimizer_switch_local_default; set @@optimizer_switch='materialization=off,in_to_exists=on'; -explain select min(a1) from t1 where 7 in (select b1 from t2 group by b1); +explain select min(a1) from t1 where 7 in (select max(b1) from t2 group by b1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 1 2 DEPENDENT SUBQUERY t2 system NULL NULL NULL NULL 0 const row not found -select min(a1) from t1 where 7 in (select b1 from t2 group by b1); +select min(a1) from t1 where 7 in (select max(b1) from t2 group by b1); min(a1) NULL set @@optimizer_switch=@optimizer_switch_local_default; @@ -1265,7 +1266,7 @@ WHERE (t1i) IN ( SELECT t2i FROM t2 WHERE (t2i) IN ( -SELECT t3i +SELECT max(t3i) FROM t3 GROUP BY t3i ) diff --git a/mysql-test/suite/innodb/r/innodb_mysql.result b/mysql-test/suite/innodb/r/innodb_mysql.result index d4bc8bc662b..4dcce4d0373 100644 --- a/mysql-test/suite/innodb/r/innodb_mysql.result +++ b/mysql-test/suite/innodb/r/innodb_mysql.result @@ -1425,9 +1425,9 @@ DROP TABLE t1; create table t1 (a bit(1) not null,b int) engine=myisam; create table t2 (c int) engine=innodb; set @save_optimizer_switch=@@optimizer_switch; -set @@optimizer_switch='partial_match_rowid_merge=off,partial_match_table_scan=off'; +set @@optimizer_switch='in_to_exists=on,materialization=off'; explain -select b from t1 where a not in (select b from t1,t2 group by a) group by a; +select b from t1 where a not in (select max(b) from t1,t2 group by a) group by a; 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 t1 system NULL NULL NULL NULL 0 const row not found diff --git a/mysql-test/suite/innodb_plugin/r/innodb_mysql.result b/mysql-test/suite/innodb_plugin/r/innodb_mysql.result index d42c61fe3ac..5a91335beeb 100644 --- a/mysql-test/suite/innodb_plugin/r/innodb_mysql.result +++ b/mysql-test/suite/innodb_plugin/r/innodb_mysql.result @@ -1425,9 +1425,9 @@ DROP TABLE t1; create table t1 (a bit(1) not null,b int) engine=myisam; create table t2 (c int) engine=innodb; set @save_optimizer_switch=@@optimizer_switch; -set @@optimizer_switch='partial_match_rowid_merge=off,partial_match_table_scan=off'; +set @@optimizer_switch='in_to_exists=on,materialization=off'; explain -select b from t1 where a not in (select b from t1,t2 group by a) group by a; +select b from t1 where a not in (select max(b) from t1,t2 group by a) group by a; 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 t1 system NULL NULL NULL NULL 0 const row not found diff --git a/mysql-test/t/explain.test b/mysql-test/t/explain.test index 8700cd48c45..d07f36b37a4 100644 --- a/mysql-test/t/explain.test +++ b/mysql-test/t/explain.test @@ -243,12 +243,12 @@ FULLTEXT KEY(f1),UNIQUE(f1)); INSERT INTO t1 VALUES ('test'); EXPLAIN SELECT 1 FROM t1 -WHERE 1 > ALL((SELECT 1 FROM t1 JOIN t1 a ON (MATCH(t1.f1) AGAINST ("")) +WHERE 1 > ALL((SELECT t1.f1 FROM t1 JOIN t1 a ON (MATCH(t1.f1) AGAINST ("")) WHERE t1.f1 GROUP BY t1.f1)); PREPARE stmt FROM 'EXPLAIN SELECT 1 FROM t1 - WHERE 1 > ALL((SELECT 1 FROM t1 RIGHT OUTER JOIN t1 a + WHERE 1 > ALL((SELECT t1.f1 FROM t1 RIGHT OUTER JOIN t1 a ON (MATCH(t1.f1) AGAINST ("")) WHERE t1.f1 GROUP BY t1.f1))'; @@ -259,7 +259,7 @@ DEALLOCATE PREPARE stmt; PREPARE stmt FROM 'EXPLAIN SELECT 1 FROM t1 - WHERE 1 > ALL((SELECT 1 FROM t1 JOIN t1 a + WHERE 1 > ALL((SELECT t1.f1 FROM t1 JOIN t1 a ON (MATCH(t1.f1) AGAINST ("")) WHERE t1.f1 GROUP BY t1.f1))'; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index d53ba706388..2540232bd3b 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -3418,8 +3418,8 @@ drop table t1, t2; CREATE TABLE t1 (a INT); INSERT INTO t1 VALUES (1),(2); -EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1 IN (SELECT 1 FROM t1 GROUP BY a); -EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1 IN (SELECT 1 FROM t1 WHERE a > 3 GROUP BY a); +EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1 IN (SELECT min(a) FROM t1 GROUP BY a); +EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1 IN (SELECT min(a) FROM t1 WHERE a > 3 GROUP BY a); DROP TABLE t1; --echo # @@ -4442,7 +4442,8 @@ DROP table t1,t2; CREATE TABLE t1 (a int, b int) ; INSERT INTO t1 VALUES (0,0),(0,0); - +set @optimizer_switch_save=@@optimizer_switch; +set @@optimizer_switch='semijoin=off,materialization=on,in_to_exists=on'; EXPLAIN SELECT b FROM t1 WHERE ('0') IN ( SELECT a FROM t1 GROUP BY a ) @@ -4451,7 +4452,7 @@ SELECT b FROM t1 SELECT b FROM t1 WHERE ('0') IN ( SELECT a FROM t1 GROUP BY a ) GROUP BY b; - +set @@optimizer_switch=@optimizer_switch_save; DROP TABLE t1; --echo # diff --git a/mysql-test/t/subselect4.test b/mysql-test/t/subselect4.test index aa3cb30c6f3..0e51373fb01 100644 --- a/mysql-test/t/subselect4.test +++ b/mysql-test/t/subselect4.test @@ -642,27 +642,27 @@ CREATE TABLE t2 (f11 varchar(1)) ; INSERT INTO t2 VALUES ('f'),('d'); SET @old_optimizer_switch = @@session.optimizer_switch; -SET SESSION optimizer_switch = 'materialization=on,in_to_exists=off,'; +SET @@optimizer_switch = 'materialization=on,in_to_exists=off,semijoin=off'; EXPLAIN SELECT * FROM t1 WHERE f3 = ( SELECT t1.f3 FROM t1 - WHERE ( t1.f10 ) IN ( SELECT f11 FROM t2 GROUP BY f11 )); + WHERE ( t1.f10 ) IN ( SELECT max(f11) FROM t2 GROUP BY f11 )); SELECT * FROM t1 WHERE f3 = ( SELECT t1.f3 FROM t1 - WHERE ( t1.f10 ) IN ( SELECT f11 FROM t2 GROUP BY f11 )); + WHERE ( t1.f10 ) IN ( SELECT max(f11) FROM t2 GROUP BY f11 )); EXPLAIN SELECT * FROM t1 WHERE f3 = ( SELECT f3 FROM t1 - WHERE ( f10, f10 ) IN ( SELECT f11, f11 FROM t2 GROUP BY f11 )); + WHERE ( f10, f10 ) IN ( SELECT max(f11), f11 FROM t2 GROUP BY f11 )); SELECT * FROM t1 WHERE f3 = ( SELECT f3 FROM t1 - WHERE ( f10, f10 ) IN ( SELECT f11, f11 FROM t2 GROUP BY f11 )); + WHERE ( f10, f10 ) IN ( SELECT max(f11), f11 FROM t2 GROUP BY f11 )); SET SESSION optimizer_switch = @old_optimizer_switch; drop table t1,t2; @@ -1084,7 +1084,7 @@ EXPLAIN SELECT * FROM t1 WHERE (SELECT f2 FROM t2 WHERE f4 <= ALL - (SELECT SQ1_t1.f4 + (SELECT max(SQ1_t1.f4) FROM t3 AS SQ1_t1 JOIN t3 AS SQ1_t3 ON SQ1_t3.f4 GROUP BY SQ1_t1.f4)); @@ -1305,47 +1305,47 @@ INSERT INTO t2 VALUES set @save_optimizer_switch=@@optimizer_switch; SET optimizer_switch='outer_join_with_cache=off'; -set @@optimizer_switch = 'materialization=off'; +set @@optimizer_switch = 'in_to_exists=on,materialization=off,semijoin=off'; EXPLAIN SELECT alias2.f1 , alias2.f2 FROM t0 AS alias1 RIGHT JOIN t0 AS alias2 ON alias2.f10 -WHERE ( alias2.f1 , alias2.f2 ) IN ( SELECT f2 , f1 FROM t0 GROUP BY f2 , f1 ); +WHERE ( alias2.f1 , alias2.f2 ) IN ( SELECT max(f2) , f1 FROM t0 GROUP BY f2 , f1 ); SELECT alias2.f1 , alias2.f2 FROM t0 AS alias1 RIGHT JOIN t0 AS alias2 ON alias2.f10 -WHERE ( alias2.f1 , alias2.f2 ) IN ( SELECT f2 , f1 FROM t0 GROUP BY f2 , f1 ); +WHERE ( alias2.f1 , alias2.f2 ) IN ( SELECT max(f2) , f1 FROM t0 GROUP BY f2 , f1 ); EXPLAIN -SELECT * FROM t2 WHERE (f1b, f2b) IN (SELECT f1a, f2a FROM t1 GROUP BY f1a, f2a); -SELECT * FROM t2 WHERE (f1b, f2b) IN (SELECT f1a, f2a FROM t1 GROUP BY f1a, f2a); +SELECT * FROM t2 WHERE (f1b, f2b) IN (SELECT max(f1a), f2a FROM t1 GROUP BY f1a, f2a); +SELECT * FROM t2 WHERE (f1b, f2b) IN (SELECT max(f1a), f2a FROM t1 GROUP BY f1a, f2a); EXPLAIN -SELECT * FROM t2 WHERE (f1b) IN (SELECT f1a FROM t1 GROUP BY f1a, f2a); -SELECT * FROM t2 WHERE (f1b) IN (SELECT f1a FROM t1 GROUP BY f1a, f2a); +SELECT * FROM t2 WHERE (f1b) IN (SELECT max(f1a) FROM t1 GROUP BY f1a, f2a); +SELECT * FROM t2 WHERE (f1b) IN (SELECT max(f1a) FROM t1 GROUP BY f1a, f2a); -SET @@optimizer_switch = 'materialization=on'; +set @@optimizer_switch = 'in_to_exists=off,materialization=on,semijoin=off'; EXPLAIN SELECT alias2.f1 , alias2.f2 FROM t0 AS alias1 RIGHT JOIN t0 AS alias2 ON alias2.f10 -WHERE ( alias2.f1 , alias2.f2 ) IN ( SELECT f2 , f1 FROM t0 GROUP BY f2 , f1 ); +WHERE ( alias2.f1 , alias2.f2 ) IN ( SELECT max(f2) , f1 FROM t0 GROUP BY f2 , f1 ); SELECT alias2.f1 , alias2.f2 FROM t0 AS alias1 RIGHT JOIN t0 AS alias2 ON alias2.f10 -WHERE ( alias2.f1 , alias2.f2 ) IN ( SELECT f2 , f1 FROM t0 GROUP BY f2 , f1 ); +WHERE ( alias2.f1 , alias2.f2 ) IN ( SELECT max(f2) , f1 FROM t0 GROUP BY f2 , f1 ); EXPLAIN -SELECT * FROM t2 WHERE (f1b, f2b) IN (SELECT f1a, f2a FROM t1 GROUP BY f1a, f2a); -SELECT * FROM t2 WHERE (f1b, f2b) IN (SELECT f1a, f2a FROM t1 GROUP BY f1a, f2a); +SELECT * FROM t2 WHERE (f1b, f2b) IN (SELECT max(f1a), f2a FROM t1 GROUP BY f1a, f2a); +SELECT * FROM t2 WHERE (f1b, f2b) IN (SELECT max(f1a), f2a FROM t1 GROUP BY f1a, f2a); EXPLAIN -SELECT * FROM t2 WHERE (f1b) IN (SELECT f1a FROM t1 GROUP BY f1a, f2a); -SELECT * FROM t2 WHERE (f1b) IN (SELECT f1a FROM t1 GROUP BY f1a, f2a); +SELECT * FROM t2 WHERE (f1b) IN (SELECT max(f1a) FROM t1 GROUP BY f1a, f2a); +SELECT * FROM t2 WHERE (f1b) IN (SELECT max(f1a) FROM t1 GROUP BY f1a, f2a); set @@optimizer_switch=@save_optimizer_switch; diff --git a/mysql-test/t/subselect_mat_cost_bugs.test b/mysql-test/t/subselect_mat_cost_bugs.test index 463685bbdf0..8205e94b203 100644 --- a/mysql-test/t/subselect_mat_cost_bugs.test +++ b/mysql-test/t/subselect_mat_cost_bugs.test @@ -167,8 +167,8 @@ CREATE TABLE t3 ( f2 varchar(1)) ; EXPLAIN SELECT f2 FROM t3 WHERE ( SELECT MAX( pk ) FROM t1 WHERE EXISTS ( - SELECT DISTINCT f1 - FROM t2 + SELECT max(f1) + FROM t2 GROUP BY f1 ) ) IS NULL ; diff --git a/mysql-test/t/subselect_sj2_jcl6.test b/mysql-test/t/subselect_sj2_jcl6.test index 09212ba63d0..fbc474f7067 100644 --- a/mysql-test/t/subselect_sj2_jcl6.test +++ b/mysql-test/t/subselect_sj2_jcl6.test @@ -94,6 +94,10 @@ EXPLAIN SELECT * FROM t1 WHERE b IN (SELECT a FROM t2 GROUP BY a); SELECT * FROM t1 WHERE b IN (SELECT a FROM t2 GROUP BY a); +EXPLAIN +SELECT * FROM t1 WHERE b IN (SELECT max(a) FROM t2 GROUP BY a); +SELECT * FROM t1 WHERE b IN (SELECT max(a) FROM t2 GROUP BY a); + set optimizer_switch=@tmp_optimizer_switch; set join_cache_level=default; diff --git a/mysql-test/t/subselect_sj_mat.test b/mysql-test/t/subselect_sj_mat.test index b9e0beaa5e3..2a5b0f56877 100644 --- a/mysql-test/t/subselect_sj_mat.test +++ b/mysql-test/t/subselect_sj_mat.test @@ -88,8 +88,8 @@ select * from t1i where a1 in (select b1 from t2i where b1 > '0'); --replace_column 6 # 8 # 11 # explain extended -select * from t1i where a1 in (select b1 from t2i where b1 > '0' group by b1); -select * from t1i where a1 in (select b1 from t2i where b1 > '0' group by b1); +select * from t1i where a1 in (select max(b1) from t2i where b1 > '0' group by b1); +select * from t1i where a1 in (select max(b1) from t2i where b1 > '0' group by b1); --replace_column 7 # --replace_regex /it1.*/_it1_idx/ /test.t2i.*/_ref_/ /Using index$// /Using where$// @@ -99,8 +99,8 @@ select * from t1i where (a1, a2) in (select b1, b2 from t2i where b1 > '0'); --replace_column 6 # 7 # 8 # 11 # explain extended -select * from t1i where (a1, a2) in (select b1, b2 from t2i where b1 > '0' group by b1, b2); -select * from t1i where (a1, a2) in (select b1, b2 from t2i where b1 > '0' group by b1, b2); +select * from t1i where (a1, a2) in (select b1, max(b2) from t2i where b1 > '0' group by b1); +select * from t1i where (a1, a2) in (select b1, max(b2) from t2i where b1 > '0' group by b1); --replace_column 6 # 7 # 8 # 11 # explain extended @@ -835,14 +835,14 @@ create table t2 (b1 int); insert into t1 values (5); # Query with group by, executed via materialization -explain select min(a1) from t1 where 7 in (select b1 from t2 group by b1); -select min(a1) from t1 where 7 in (select b1 from t2 group by b1); +explain select min(a1) from t1 where 7 in (select max(b1) from t2 group by b1); +select min(a1) from t1 where 7 in (select max(b1) from t2 group by b1); # Query with group by, executed via IN=>EXISTS set @save_optimizer_switch=@@optimizer_switch; set @@optimizer_switch=@optimizer_switch_local_default; set @@optimizer_switch='materialization=off,in_to_exists=on'; -explain select min(a1) from t1 where 7 in (select b1 from t2 group by b1); -select min(a1) from t1 where 7 in (select b1 from t2 group by b1); +explain select min(a1) from t1 where 7 in (select max(b1) from t2 group by b1); +select min(a1) from t1 where 7 in (select max(b1) from t2 group by b1); # Executed with materialization set @@optimizer_switch=@optimizer_switch_local_default; @@ -900,7 +900,7 @@ WHERE (t1i) IN ( SELECT t2i FROM t2 WHERE (t2i) IN ( - SELECT t3i + SELECT max(t3i) FROM t3 GROUP BY t3i ) diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 00f5c7a948a..48522f8a70f 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -178,7 +178,7 @@ void Item_allany_subselect::cleanup() */ for (SELECT_LEX *sl= unit->first_select(); sl; sl= sl->next_select()) - if (test_strategy(SUBS_MAXMIN_INJECTED)) + if (test_set_strategy(SUBS_MAXMIN_INJECTED)) sl->with_sum_func= false; Item_in_subselect::cleanup(); } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 18925f0f83f..9ad945a22b3 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -424,6 +424,73 @@ fix_inner_refs(THD *thd, List &all_fields, SELECT_LEX *select, return false; } +/** + The following clauses are redundant for subqueries: + + DISTINCT + GROUP BY if there are no aggregate functions and no HAVING + clause + + Because redundant clauses are removed both from JOIN and + select_lex, the removal is permanent. Thus, it only makes sense to + call this function for normal queries and on first execution of + SP/PS + + @param subq_select_lex select_lex that is part of a subquery + predicate. This object and the associated + join is modified. +*/ + +static +void remove_redundant_subquery_clauses(st_select_lex *subq_select_lex) +{ + Item_subselect *subq_predicate= subq_select_lex->master_unit()->item; + /* + The removal should happen for IN, ALL, ANY and EXISTS subqueries, + which means all but single row subqueries. Example single row + subqueries: + a) SELECT * FROM t1 WHERE t1.a = () + b) SELECT a, (substype() == Item_subselect::SINGLEROW_SUBS) + return; + + /* A subquery that is not single row should be one of IN/ALL/ANY/EXISTS. */ + DBUG_ASSERT (subq_predicate->substype() == Item_subselect::EXISTS_SUBS || + subq_predicate->is_in_predicate()); + + if (subq_select_lex->options & SELECT_DISTINCT) + { + subq_select_lex->join->select_distinct= false; + subq_select_lex->options&= ~SELECT_DISTINCT; + } + + /* + Remove GROUP BY if there are no aggregate functions and no HAVING + clause + */ + if (subq_select_lex->group_list.elements && + !subq_select_lex->with_sum_func && !subq_select_lex->join->having) + { + subq_select_lex->join->group_list= NULL; + subq_select_lex->group_list.empty(); + } + + /* + TODO: This would prevent processing quries with ORDER BY ... LIMIT + therefore we disable this optimization for now. + Remove GROUP BY if there are no aggregate functions and no HAVING + clause + if (subq_select_lex->group_list.elements && + !subq_select_lex->with_sum_func && !subq_select_lex->join->having) + { + subq_select_lex->join->group_list= NULL; + subq_select_lex->group_list.empty(); + } + */ +} + + /** Function to setup clauses without sum functions. */ @@ -521,6 +588,22 @@ JOIN::prepare(Item ***rref_pointer_array, tables_list, select_lex->leaf_tables, FALSE, SELECT_ACL, SELECT_ACL, FALSE)) DBUG_RETURN(-1); + + /* + Permanently remove redundant parts from the query if + 1) This is a subquery + 2) This is the first time this query is optimized (since the + transformation is permanent + 3) Not normalizing a view. Removal should take place when a + query involving a view is optimized, not when the view + is created + */ + if (select_lex->master_unit()->item && // 1) + select_lex->first_cond_optimization && // 2) + !(thd->lex->context_analysis_only & CONTEXT_ANALYSIS_ONLY_VIEW)) // 3) + { + remove_redundant_subquery_clauses(select_lex); + } /* TRUE if the SELECT list mixes elements with and without grouping, From fa061af3736448463fbd9152ca6986526dfb4fc3 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Tue, 20 Dec 2011 09:57:42 +0400 Subject: [PATCH 232/288] Update mysql-test/suite/pbxt/r/subselect.result for the previous push --- mysql-test/suite/pbxt/r/subselect.result | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/mysql-test/suite/pbxt/r/subselect.result b/mysql-test/suite/pbxt/r/subselect.result index d83b216a391..cc513a1444d 100644 --- a/mysql-test/suite/pbxt/r/subselect.result +++ b/mysql-test/suite/pbxt/r/subselect.result @@ -1527,17 +1527,17 @@ a explain extended select * from t3 where a >= all (select b from t2 group by 1); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where -2 SUBQUERY t2 ALL NULL NULL NULL NULL 0 0.00 Using temporary +2 SUBQUERY t2 ALL NULL NULL NULL NULL 0 0.00 Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,((select `test`.`t2`.`b` from `test`.`t2` group by 1) > (`test`.`t3`.`a`)))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,((select max(`test`.`t2`.`b`) from `test`.`t2`) > (`test`.`t3`.`a`)))) select * from t3 where a >= some (select b from t2 group by 1); a explain extended select * from t3 where a >= some (select b from t2 group by 1); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where -2 SUBQUERY t2 ALL NULL NULL NULL NULL 0 0.00 Using temporary +2 SUBQUERY t2 ALL NULL NULL NULL NULL 0 0.00 Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,((select `test`.`t2`.`b` from `test`.`t2` group by 1) <= (`test`.`t3`.`a`)))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,((select min(`test`.`t2`.`b`) from `test`.`t2`) <= (`test`.`t3`.`a`)))) select * from t3 where NULL >= any (select b from t2); a explain extended select * from t3 where NULL >= any (select b from t2); @@ -1551,9 +1551,9 @@ a explain extended select * from t3 where NULL >= any (select b from t2 group by 1); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 0 0.00 Using temporary +2 SUBQUERY t2 ALL NULL NULL NULL NULL 0 0.00 Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL,((select `test`.`t2`.`b` from `test`.`t2` group by 1) <= NULL))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL,((select min(`test`.`t2`.`b`) from `test`.`t2`) <= NULL))) select * from t3 where NULL >= some (select b from t2); a explain extended select * from t3 where NULL >= some (select b from t2); @@ -1567,9 +1567,9 @@ a explain extended select * from t3 where NULL >= some (select b from t2 group by 1); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 0 0.00 Using temporary +2 SUBQUERY t2 ALL NULL NULL NULL NULL 0 0.00 Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL,((select `test`.`t2`.`b` from `test`.`t2` group by 1) <= NULL))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL,((select min(`test`.`t2`.`b`) from `test`.`t2`) <= NULL))) insert into t2 values (2,2), (2,1), (3,3), (3,1); select * from t3 where a > all (select max(b) from t2 group by a); a @@ -2849,9 +2849,9 @@ Note 1003 select `test`.`t1`.`one` AS `one`,`test`.`t1`.`two` AS `two` from `tes explain extended SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0' group by one,two) as 'test' from t1; id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 8 100.00 -2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 9 100.00 Using where; Using temporary +2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 9 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`one` AS `one`,`test`.`t1`.`two` AS `two`,<`test`.`t1`.`one`,`test`.`t1`.`two`>(((`test`.`t1`.`one`,`test`.`t1`.`two`),(select `test`.`t2`.`one`,`test`.`t2`.`two` from `test`.`t2` where (`test`.`t2`.`flag` = '0') group by `test`.`t2`.`one`,`test`.`t2`.`two` having (trigcond((((`test`.`t1`.`one`) = `test`.`t2`.`one`) or isnull(`test`.`t2`.`one`))) and trigcond((((`test`.`t1`.`two`) = `test`.`t2`.`two`) or isnull(`test`.`t2`.`two`))) and trigcond((`test`.`t2`.`one`)) and trigcond((`test`.`t2`.`two`)))))) AS `test` from `test`.`t1` +Note 1003 select `test`.`t1`.`one` AS `one`,`test`.`t1`.`two` AS `two`,<`test`.`t1`.`one`,`test`.`t1`.`two`>(((`test`.`t1`.`one`,`test`.`t1`.`two`),(select `test`.`t2`.`one`,`test`.`t2`.`two` from `test`.`t2` where ((`test`.`t2`.`flag` = '0') and trigcond((((`test`.`t1`.`one`) = `test`.`t2`.`one`) or isnull(`test`.`t2`.`one`))) and trigcond((((`test`.`t1`.`two`) = `test`.`t2`.`two`) or isnull(`test`.`t2`.`two`)))) having (trigcond((`test`.`t2`.`one`)) and trigcond((`test`.`t2`.`two`)))))) AS `test` from `test`.`t1` DROP TABLE t1,t2; set @@optimizer_switch=@save_optimizer_switch; CREATE TABLE t1 (a char(5), b char(5)); From 5d9fbc617724ce0bb7f90090596772dbb792139d Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Tue, 20 Dec 2011 12:13:47 +0400 Subject: [PATCH 233/288] Fix version number: it's 5.3.3 --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index 2435d864162..bea191e370e 100644 --- a/configure.in +++ b/configure.in @@ -13,7 +13,7 @@ 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([MariaDB Server], [5.3.2-MariaDB-rc], [], [mysql]) +AC_INIT([MariaDB Server], [5.3.3-MariaDB-rc], [], [mysql]) AC_CONFIG_SRCDIR([sql/mysqld.cc]) AC_CANONICAL_SYSTEM From 8a8155f11fd290a95951d41aa29e94fa9f346101 Mon Sep 17 00:00:00 2001 From: Sneha Modi Date: Wed, 21 Dec 2011 15:14:55 +0530 Subject: [PATCH 234/288] Bug#11754150: A TEST CASE FOR BUG#6857 IS DISABLED IN SP.TEST The time comparison using current_time() stored in an int variable was giving wrong results as the current_time() format as an int implementation has been changed in mysql-trunk but not in mysql-5.5. The time is stored in the format hh:mm:ss as 'time' datatype.But as an int, it is stored as hhmmss, but only on the trunk. On mysql-5.5,as an int, it is stored as hh. Hence, the current_time() function has been changed to unix_timestamp() function. --- mysql-test/r/sp.result | 7 +++++-- mysql-test/t/sp.test | 6 +++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 1644c764431..a48f82af915 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -2776,16 +2776,19 @@ create procedure bug6857(counter int) begin declare t0, t1 int; declare plus bool default 0; -set t0 = current_time(); +set t0 = unix_timestamp(); while counter > 0 do set counter = counter - 1; end while; -set t1 = current_time(); +set t1 = unix_timestamp(); if t1 > t0 then set plus = 1; end if; select plus; end| +call bug6857(300000)| +plus +1 drop procedure bug6857| drop procedure if exists bug8757| create procedure bug8757() diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 3f6c50a9095..6ac88f4f5bf 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -3341,11 +3341,11 @@ begin declare t0, t1 int; declare plus bool default 0; - set t0 = current_time(); + set t0 = unix_timestamp(); while counter > 0 do set counter = counter - 1; end while; - set t1 = current_time(); + set t1 = unix_timestamp(); if t1 > t0 then set plus = 1; end if; @@ -3357,7 +3357,7 @@ end| # painful. # Make sure this takes at least one second on all machines in all builds. # 30000 makes it about 3 seconds on an old 1.1GHz linux. -#call bug6857(300000)| +call bug6857(300000)| drop procedure bug6857| From 11fd796f8d3394a5b0c7133109e7a06961e6307b Mon Sep 17 00:00:00 2001 From: Sneha Modi Date: Wed, 21 Dec 2011 19:00:07 +0530 Subject: [PATCH 235/288] Bug#11754150: A TEST CASE FOR BUG#6857 IS DISABLED IN SP.TEST Unix_timestamp for time comparison has some problems...Re-using current_time for time comparison. --- mysql-test/r/sp.result | 7 ++----- mysql-test/t/sp.test | 6 +++--- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index a48f82af915..1644c764431 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -2776,19 +2776,16 @@ create procedure bug6857(counter int) begin declare t0, t1 int; declare plus bool default 0; -set t0 = unix_timestamp(); +set t0 = current_time(); while counter > 0 do set counter = counter - 1; end while; -set t1 = unix_timestamp(); +set t1 = current_time(); if t1 > t0 then set plus = 1; end if; select plus; end| -call bug6857(300000)| -plus -1 drop procedure bug6857| drop procedure if exists bug8757| create procedure bug8757() diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 6ac88f4f5bf..3f6c50a9095 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -3341,11 +3341,11 @@ begin declare t0, t1 int; declare plus bool default 0; - set t0 = unix_timestamp(); + set t0 = current_time(); while counter > 0 do set counter = counter - 1; end while; - set t1 = unix_timestamp(); + set t1 = current_time(); if t1 > t0 then set plus = 1; end if; @@ -3357,7 +3357,7 @@ end| # painful. # Make sure this takes at least one second on all machines in all builds. # 30000 makes it about 3 seconds on an old 1.1GHz linux. -call bug6857(300000)| +#call bug6857(300000)| drop procedure bug6857| From aff6b0fd825717342cab2be4acc5e5790e4d766b Mon Sep 17 00:00:00 2001 From: Alexander Nozdrin Date: Wed, 21 Dec 2011 19:26:11 +0400 Subject: [PATCH 236/288] A patch for Bug#13023858 - MYSQL_UPGRADE PRINTS THE ORACLE_WELCOME_COPYRIGHT_NOTICE TWICE. Fix of a merge error. --- client/mysql_upgrade.c | 1 - 1 file changed, 1 deletion(-) diff --git a/client/mysql_upgrade.c b/client/mysql_upgrade.c index 684d20c29a8..00cfdcf964a 100644 --- a/client/mysql_upgrade.c +++ b/client/mysql_upgrade.c @@ -243,7 +243,6 @@ get_one_option(int optid, const struct my_option *opt, switch (optid) { case '?': - puts(ORACLE_WELCOME_COPYRIGHT_NOTICE("2000, 2011")); printf("%s Ver %s Distrib %s, for %s (%s)\n", my_progname, VER, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE); puts(ORACLE_WELCOME_COPYRIGHT_NOTICE("2000, 2010")); From 3953b489714ee5eaf329894256e7fa56a7698d6b Mon Sep 17 00:00:00 2001 From: Inaam Rana Date: Wed, 21 Dec 2011 21:33:13 -0500 Subject: [PATCH 237/288] Bug#11866367 FPE WHEN SETTING INNODB_SPIN_WAIT_DELAY rb://865 approved by: Jimmy Integer overflow causes division by zero. --- storage/innobase/include/ut0rnd.ic | 2 +- storage/innodb_plugin/include/ut0rnd.ic | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/storage/innobase/include/ut0rnd.ic b/storage/innobase/include/ut0rnd.ic index dc4c0d62f56..b54f629de37 100644 --- a/storage/innobase/include/ut0rnd.ic +++ b/storage/innobase/include/ut0rnd.ic @@ -96,7 +96,7 @@ ut_rnd_interval( rnd = ut_rnd_gen_ulint(); - return(low + (rnd % (high - low + 1))); + return(low + (rnd % (high - low))); } /************************************************************* diff --git a/storage/innodb_plugin/include/ut0rnd.ic b/storage/innodb_plugin/include/ut0rnd.ic index a33813037ea..3ae12f69186 100644 --- a/storage/innodb_plugin/include/ut0rnd.ic +++ b/storage/innodb_plugin/include/ut0rnd.ic @@ -114,7 +114,7 @@ ut_rnd_interval( rnd = ut_rnd_gen_ulint(); - return(low + (rnd % (high - low + 1))); + return(low + (rnd % (high - low))); } /*********************************************************//** From 564d4a65bda21e36a408036723137d14a1aa1372 Mon Sep 17 00:00:00 2001 From: Inaam Rana Date: Wed, 21 Dec 2011 21:36:52 -0500 Subject: [PATCH 238/288] Add ChangeLog message. --- storage/innodb_plugin/ChangeLog | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index 5fc0cce3ff2..1385da94bfb 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,3 +1,8 @@ +2011-12-21 The InnoDB Team + + * include/ut0rnd.ic: + Fix Bug#11866367:FPE WHEN SETTING INNODB_SPIN_WAIT_DELAY + 2011-12-13 The InnoDB Team * handler/ha_innodb.cc, innodb.test, innodb.result: From 805989f6cea992f93f4755ac44860919f9fee2c8 Mon Sep 17 00:00:00 2001 From: Sneha Modi Date: Thu, 22 Dec 2011 16:39:08 +0530 Subject: [PATCH 239/288] Bug#11754150: A TEST CASE FOR BUG#6857 IS DISABLED IN SP.TEST unix_timestamp() is implemented in this part of the code in place of current_time(). Also, since the pb2 machines may be extremely fast, instead of looping through the code, we use sleep(1.1) so that the variables t0 and t1 have different values. --- mysql-test/r/sp.result | 15 +++++++++------ mysql-test/t/sp.test | 17 +++++------------ 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 1644c764431..07c945db5e6 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -2772,20 +2772,23 @@ userid drop procedure bug8116| drop table t3| drop procedure if exists bug6857| -create procedure bug6857(counter int) +create procedure bug6857() begin declare t0, t1 int; declare plus bool default 0; -set t0 = current_time(); -while counter > 0 do -set counter = counter - 1; -end while; -set t1 = current_time(); +set t0 = unix_timestamp(); +select sleep(1.1); +set t1 = unix_timestamp(); if t1 > t0 then set plus = 1; end if; select plus; end| +call bug6857()| +sleep(1.1) +0 +plus +1 drop procedure bug6857| drop procedure if exists bug8757| create procedure bug8757() diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 3f6c50a9095..a6e06e4aabe 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -3336,28 +3336,21 @@ drop table t3| --disable_warnings drop procedure if exists bug6857| --enable_warnings -create procedure bug6857(counter int) +create procedure bug6857() begin declare t0, t1 int; declare plus bool default 0; - set t0 = current_time(); - while counter > 0 do - set counter = counter - 1; - end while; - set t1 = current_time(); + set t0 = unix_timestamp(); + select sleep(1.1); + set t1 = unix_timestamp(); if t1 > t0 then set plus = 1; end if; select plus; end| -# QQ: This is currently disabled. Not only does it slow down a normal test -# run, it makes running with valgrind (or similar tools) extremely -# painful. -# Make sure this takes at least one second on all machines in all builds. -# 30000 makes it about 3 seconds on an old 1.1GHz linux. -#call bug6857(300000)| +call bug6857()| drop procedure bug6857| From 086ee89a38b548ebdbfd7373c76abd66a81d344c Mon Sep 17 00:00:00 2001 From: Sneha Modi Date: Thu, 22 Dec 2011 23:11:48 +0530 Subject: [PATCH 240/288] Bug#11754150: A test case for Bug#6857 has been disabled in sp.test: An extra space was inserted in the code by mistake which was producing a result content mismatch. --- mysql-test/t/sp.test | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index a6e06e4aabe..d0fe9779da9 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -3340,9 +3340,8 @@ create procedure bug6857() begin declare t0, t1 int; declare plus bool default 0; - set t0 = unix_timestamp(); - select sleep(1.1); + select sleep(1.1); set t1 = unix_timestamp(); if t1 > t0 then set plus = 1; From 790a3a46f38ca1040f756fd64c0cca7b78b50f67 Mon Sep 17 00:00:00 2001 From: Ramil Kalimullin Date: Fri, 23 Dec 2011 17:22:48 +0400 Subject: [PATCH 241/288] Fix for bug#11758931 - 51196: SLAVE SQL: GOT AN ERROR WRITING COMMUNICATION PACKETS, ERROR_CODE: 1160 If idle FEDERATED table is evicted from the table cache when a connection to remote server is lost, query that initiated eviction may fail. If this query is executed by slave SQL thread it may fail as well. An error of close was stored in diagnostics area, which was later attributed to the statement that caused eviction. With this patch FEDERATED clears an error of close. --- storage/federated/ha_federated.cc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/storage/federated/ha_federated.cc b/storage/federated/ha_federated.cc index 21c0b7b178d..64d5af446d8 100644 --- a/storage/federated/ha_federated.cc +++ b/storage/federated/ha_federated.cc @@ -1651,6 +1651,15 @@ int ha_federated::close(void) mysql_close(mysql); mysql= NULL; + /* + mysql_close() might return an error if a remote server's gone + for some reason. If that happens while removing a table from + the table cache, the error will be propagated to a client even + if the original query was not issued against the FEDERATED table. + So, don't propagate errors from mysql_close(). + */ + table->in_use->clear_error(); + DBUG_RETURN(free_share(share)); } From 289af2579b5084d554b71a9307ec705afbba8ae7 Mon Sep 17 00:00:00 2001 From: Ramil Kalimullin Date: Fri, 23 Dec 2011 18:52:44 +0400 Subject: [PATCH 242/288] Fix for bug#11758931 - 51196: SLAVE SQL: GOT AN ERROR WRITING COMMUNICATION PACKETS, ERROR_CODE: 1160 Addendum: for some queries table->in_use might be NULL - check it. --- storage/federated/ha_federated.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/storage/federated/ha_federated.cc b/storage/federated/ha_federated.cc index 64d5af446d8..f53066a4b22 100644 --- a/storage/federated/ha_federated.cc +++ b/storage/federated/ha_federated.cc @@ -1658,7 +1658,8 @@ int ha_federated::close(void) if the original query was not issued against the FEDERATED table. So, don't propagate errors from mysql_close(). */ - table->in_use->clear_error(); + if (table->in_use) + table->in_use->clear_error(); DBUG_RETURN(free_share(share)); } From 5e487124aaeb6628e241301f16960e81a1e04035 Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Fri, 23 Dec 2011 23:05:00 +0530 Subject: [PATCH 243/288] Bug#12809202 61854: MYSQLDUMP --SINGLE-TRANSACTION --FLUSH-LOG BREAKS CONSISTENCY The transaction started by mysqldump gets committed implicitly when flush-log is specified along with single-transaction option, and hence can break consistency. This is because, COM_REFRESH is executed in order to flush logs and starting from 5.5 this command performs an implicit commit. Fixed by making sure that COM_REFRESH is executed before the transaction has started and not after it. Note : This patch triggers following behavioral changes in mysqldump : 1) After this patch we no longer flush logs before dumping each database if --single-transaction option is given like it was done before (in the absence of --lock-all-tables and --master-data options). 2) Also, after this patch, we start acquiring FTWRL before flushing logs in cases when only --single-transaction and --flush-logs are given. It becomes safe to use mysqldump with these two options and without --master-data parameter for backups. client/mysqldump.c: Bug#12809202 61854: MYSQLDUMP --SINGLE-TRANSACTION --FLUSH-LOG BREAKS CONSISTENCY Added logic to make sure that, if flush-log option is specified, mysql_refresh() is never executed after the transaction has started. Added verbose messages for all the executions of mysql_refresh() in order to track its invocation. mysql-test/r/mysqldump.result: Added test case for Bug#12809202. mysql-test/t/mysqldump.test: Added test case for Bug#12809202. --- client/mysqldump.c | 42 ++++++++++---- mysql-test/r/mysqldump.result | 100 ++++++++++++++++++++++++++++++++++ mysql-test/t/mysqldump.test | 32 +++++++++++ 3 files changed, 164 insertions(+), 10 deletions(-) diff --git a/client/mysqldump.c b/client/mysqldump.c index 8ccf1f90c97..11b76932692 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -4079,6 +4079,8 @@ static int dump_all_tables_in_db(char *database) if (mysql_refresh(mysql, REFRESH_LOG)) DB_error(mysql, "when doing refresh"); /* We shall continue here, if --force was given */ + else + verbose_msg("-- dump_all_tables_in_db : logs flushed successfully!\n"); } while ((table= getTableName(0))) { @@ -4179,6 +4181,8 @@ static my_bool dump_all_views_in_db(char *database) if (mysql_refresh(mysql, REFRESH_LOG)) DB_error(mysql, "when doing refresh"); /* We shall continue here, if --force was given */ + else + verbose_msg("-- dump_all_views_in_db : logs flushed successfully!\n"); } while ((table= getTableName(0))) { @@ -4317,6 +4321,8 @@ static int dump_selected_tables(char *db, char **table_names, int tables) DB_error(mysql, "when doing refresh"); } /* We shall countinue here, if --force was given */ + else + verbose_msg("-- dump_selected_tables : logs flushed successfully!\n"); } if (opt_xml) print_xml_tag(md_result_file, "", "\n", "database", "name=", db, NullS); @@ -4600,6 +4606,7 @@ static int purge_bin_logs_to(MYSQL *mysql_con, char* log_name) static int start_transaction(MYSQL *mysql_con) { + verbose_msg("-- Starting transaction...\n"); /* We use BEGIN for old servers. --single-transaction --master-data will fail on old servers, but that's ok as it was already silently broken (it didn't @@ -5199,24 +5206,39 @@ int main(int argc, char **argv) if (opt_slave_data && do_stop_slave_sql(mysql)) goto err; - if ((opt_lock_all_tables || opt_master_data) && + if ((opt_lock_all_tables || opt_master_data || + (opt_single_transaction && flush_logs)) && do_flush_tables_read_lock(mysql)) goto err; - if (opt_single_transaction && start_transaction(mysql)) - goto err; - if (opt_delete_master_logs) + + /* + Flush logs before starting transaction since + this causes implicit commit starting mysql-5.5. + */ + if (opt_lock_all_tables || opt_master_data || + (opt_single_transaction && flush_logs) || + opt_delete_master_logs) { - if (mysql_refresh(mysql, REFRESH_LOG) || - get_bin_log_name(mysql, bin_log_name, sizeof(bin_log_name))) - goto err; + if (flush_logs || opt_delete_master_logs) + { + if (mysql_refresh(mysql, REFRESH_LOG)) + goto err; + verbose_msg("-- main : logs flushed successfully!\n"); + } + + /* Not anymore! That would not be sensible. */ flush_logs= 0; } - if (opt_lock_all_tables || opt_master_data) + + if (opt_delete_master_logs) { - if (flush_logs && mysql_refresh(mysql, REFRESH_LOG)) + if (get_bin_log_name(mysql, bin_log_name, sizeof(bin_log_name))) goto err; - flush_logs= 0; /* not anymore; that would not be sensible */ } + + if (opt_single_transaction && start_transaction(mysql)) + goto err; + /* Add 'STOP SLAVE to beginning of dump */ if (opt_slave_apply && add_stop_slave()) goto err; diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index 8f6add75fd3..5d03976f3a5 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -4662,3 +4662,103 @@ UNLOCK TABLES; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; DROP TABLE t1; +# +# Bug#12809202 61854: MYSQLDUMP --SINGLE-TRANSACTION --FLUSH-LOG BREAKS +# CONSISTENCY +# +DROP DATABASE IF EXISTS b12809202_db; +CREATE DATABASE b12809202_db; +CREATE TABLE b12809202_db.t1 (c1 INT); +CREATE TABLE b12809202_db.t2 (c1 INT); +INSERT INTO b12809202_db.t1 VALUES (1), (2), (3); +INSERT INTO b12809202_db.t2 VALUES (1), (2), (3); +# Starting mysqldump with --single-transaction & --flush-log options.. +# Note : In the following dump the transaction +# should start only after the logs are +# flushed, as 'flush logs' causes implicit +# commit starting 5.5. + +#### Dump starts here #### +-- Connecting to localhost... +-- main : logs flushed successfully! +-- Starting transaction... +-- 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; +DROP DATABASE b12809202_db; diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test index e224bf6afe3..b1688986090 100644 --- a/mysql-test/t/mysqldump.test +++ b/mysql-test/t/mysqldump.test @@ -2215,5 +2215,37 @@ CREATE TABLE t1 (a INT); --exec $MYSQL_DUMP --compatible=no_t,no_f --skip-comments test DROP TABLE t1; +--echo # +--echo # Bug#12809202 61854: MYSQLDUMP --SINGLE-TRANSACTION --FLUSH-LOG BREAKS +--echo # CONSISTENCY +--echo # + +--disable_warnings +DROP DATABASE IF EXISTS b12809202_db; +--enable_warnings + +CREATE DATABASE b12809202_db; +CREATE TABLE b12809202_db.t1 (c1 INT); +CREATE TABLE b12809202_db.t2 (c1 INT); + +INSERT INTO b12809202_db.t1 VALUES (1), (2), (3); +INSERT INTO b12809202_db.t2 VALUES (1), (2), (3); + +--echo # Starting mysqldump with --single-transaction & --flush-log options.. +--echo # Note : In the following dump the transaction +--echo # should start only after the logs are +--echo # flushed, as 'flush logs' causes implicit +--echo # commit starting 5.5. +--echo +--echo #### Dump starts here #### +--replace_regex /-- Server version.*// /-- MySQL dump .*// /-- Dump completed on .*/-- Dump completed/ +--exec $MYSQL_DUMP --verbose --single-transaction --flush-log b12809202_db 2>&1 +--echo +--echo #### Dump ends here #### + +DROP TABLE b12809202_db.t1; +DROP TABLE b12809202_db.t2; +DROP DATABASE b12809202_db; + # Wait till we reached the initial number of concurrent sessions --source include/wait_until_count_sessions.inc From 49d2790aff0cd579b7f101c26e39afdd0ba2524c Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Sat, 24 Dec 2011 15:08:59 +0530 Subject: [PATCH 244/288] Bug#12809202 61854: MYSQLDUMP --SINGLE-TRANSACTION --FLUSH-LOG BREAKS CONSISTENCY Post-fix for some failing tests. --- client/mysqldump.c | 2 ++ mysql-test/r/mysqldump.result | 4 ++++ mysql-test/t/mysqldump.test | 6 ++++++ 3 files changed, 12 insertions(+) diff --git a/client/mysqldump.c b/client/mysqldump.c index 11b76932692..e22ae5a8b09 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -562,6 +562,8 @@ static void verbose_msg(const char *fmt, ...) vfprintf(stderr, fmt, args); va_end(args); + fflush(stderr); + DBUG_VOID_RETURN; } diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index 5d03976f3a5..ee9b6a878cd 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -4762,3 +4762,7 @@ UNLOCK TABLES; DROP TABLE b12809202_db.t1; DROP TABLE b12809202_db.t2; DROP DATABASE b12809202_db; +# +# Delete all existing binary logs. +# +RESET MASTER; diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test index b1688986090..871b3735b1b 100644 --- a/mysql-test/t/mysqldump.test +++ b/mysql-test/t/mysqldump.test @@ -2243,9 +2243,15 @@ INSERT INTO b12809202_db.t2 VALUES (1), (2), (3); --echo --echo #### Dump ends here #### +# Cleanup DROP TABLE b12809202_db.t1; DROP TABLE b12809202_db.t2; DROP DATABASE b12809202_db; +--echo # +--echo # Delete all existing binary logs. +--echo # +RESET MASTER; + # Wait till we reached the initial number of concurrent sessions --source include/wait_until_count_sessions.inc From 2b1f0b875775b65496e959db7f54f6eb4220400e Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Sat, 24 Dec 2011 08:55:10 -0800 Subject: [PATCH 245/288] Back-ported the patch of the mysql-5.6 code line that fixed several defects in the greedy optimization: 1) The greedy optimizer calculated the 'compare-cost' (CPU-cost) for iterating over the partial plan result at each level in the query plan as 'record_count / (double) TIME_FOR_COMPARE' This cost was only used locally for 'best' calculation at each level, and *not* accumulated into the total cost for the query plan. This fix added the 'CPU-cost' of processing 'current_record_count' records at each level to 'current_read_time' *before* it is used as 'accumulated cost' argument to recursive best_extension_by_limited_search() calls. This ensured that the cost of a huge join-fanout early in the QEP was correctly reflected in the cost of the final QEP. To get identical cost for a 'best' optimized query and a straight_join with the same join order, the same change was also applied to optimize_straight_join() and get_partial_join_cost() 2) Furthermore to get equal cost for 'best' optimized query and a straight_join the new code substrcated the same '0.001' in optimize_straight_join() as it had been already done in best_extension_by_limited_search() 3) When best_extension_by_limited_search() aggregated the 'best' plan a plan was 'best' by the check : 'if ((search_depth == 1) || (current_read_time < join->best_read))' The term '(search_depth == 1' incorrectly caused a new best plan to be collected whenever the specified 'search_depth' was reached - even if this partial query plan was more expensive than what we had already found. --- mysql-test/r/derived_view.result | 33 ++-- mysql-test/r/explain.result | 10 +- mysql-test/r/greedy_optimizer.result | 160 +++++++++--------- mysql-test/r/innodb_icp.result | 2 +- mysql-test/r/join.result | 2 +- mysql-test/r/join_cache.result | 12 +- mysql-test/r/maria_icp.result | 2 +- mysql-test/r/myisam_icp.result | 2 +- mysql-test/r/select.result | 4 +- mysql-test/r/select_jcl6.result | 4 +- mysql-test/r/select_pkeycache.result | 4 +- mysql-test/r/status.result | 2 +- mysql-test/r/subselect.result | 16 +- mysql-test/r/subselect2.result | 4 +- mysql-test/r/subselect3.result | 10 +- mysql-test/r/subselect3_jcl6.result | 12 +- mysql-test/r/subselect4.result | 11 +- mysql-test/r/subselect_extra.result | 6 +- mysql-test/r/subselect_mat_cost.result | 4 +- mysql-test/r/subselect_no_mat.result | 12 +- mysql-test/r/subselect_no_opts.result | 18 +- mysql-test/r/subselect_no_scache.result | 16 +- mysql-test/r/subselect_no_semijoin.result | 24 ++- mysql-test/r/subselect_sj.result | 43 +---- mysql-test/r/subselect_sj2.result | 8 +- mysql-test/r/subselect_sj2_jcl6.result | 15 +- mysql-test/r/subselect_sj2_mat.result | 8 +- mysql-test/r/subselect_sj_jcl6.result | 63 +++---- .../suite/pbxt/r/greedy_optimizer.result | 160 +++++++++--------- mysql-test/suite/pbxt/r/join.result | 2 +- mysql-test/suite/pbxt/r/select.result | 4 +- mysql-test/suite/pbxt/r/subselect.result | 8 +- mysql-test/suite/pbxt/t/subselect.test | 5 + mysql-test/t/derived_view.test | 1 + mysql-test/t/explain.test | 6 +- mysql-test/t/subselect.test | 12 ++ mysql-test/t/subselect4.test | 3 + mysql-test/t/subselect_sj.test | 55 +++--- sql/opt_subselect.cc | 4 +- sql/sql_select.cc | 26 +-- 40 files changed, 414 insertions(+), 379 deletions(-) diff --git a/mysql-test/r/derived_view.result b/mysql-test/r/derived_view.result index a109aa3198b..cee19237230 100644 --- a/mysql-test/r/derived_view.result +++ b/mysql-test/r/derived_view.result @@ -1592,6 +1592,7 @@ CREATE TABLE t3 ( b int NOT NULL, e varchar(1) NOT NULL, d varchar(1) NOT NULL, KEY (e,b) ); INSERT INTO t3 VALUES (4,'x','x'),(9,'w','w'),(4,'d','d'),(8,'e','e'); +INSERT INTO t3 VALUES (14,'a','a'),(19,'b','b'),(14,'c','c'),(18,'d','d'); CREATE TABLE t4 (i int NOT NULL, m varchar(1) NOT NULL) ; INSERT INTO t4 VALUES (8,'m'),(9,'d'),(2,'s'),(4,'r'),(8,'m'); CREATE TABLE t5 ( @@ -1607,30 +1608,36 @@ SET SESSION join_buffer_size = 512; EXPLAIN SELECT t2.d FROM t1,t2,v3 WHERE v3.e = t2.d AND v3.i < 3; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 ALL NULL NULL NULL NULL 3 -1 SIMPLE t3 ref e e 3 test.t2.d 1 Using index -1 SIMPLE t5 ALL NULL NULL NULL NULL 2 Using join buffer (flat, BNL join) +1 SIMPLE t5 ALL NULL NULL NULL NULL 2 1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using join buffer (flat, BNL join) +1 SIMPLE t2 ALL NULL NULL NULL NULL 3 Using join buffer (flat, BNL join) +1 SIMPLE t3 ref e e 3 test.t2.d 1 Using index 1 SIMPLE t4 ALL NULL NULL NULL NULL 5 Using where; Using join buffer (flat, BNL join) SELECT t2.d FROM t1,t2,v3 WHERE v3.e = t2.d AND v3.i < 3; d w -d -e +w +w +w +w w d -e -w +d +d +d +d +d +d +d +d +d +d d e -w -d e -w -d e -w -d +e +e e SET SESSION join_cache_level = DEFAULT; SET SESSION join_buffer_size = DEFAULT; diff --git a/mysql-test/r/explain.result b/mysql-test/r/explain.result index 52c58f088a1..e08e3e22307 100644 --- a/mysql-test/r/explain.result +++ b/mysql-test/r/explain.result @@ -196,13 +196,13 @@ create table t2 (dt datetime not null); insert into t1 values ('2001-01-01 1:1:1', '1:1:1'), ('2001-01-01 1:1:1', '1:1:1'); insert into t2 values ('2001-01-01 1:1:1'), ('2001-01-01 1:1:1'); -SET @save_optimizer_switch=@@optimizer_switch; -SET optimizer_switch='semijoin_with_cache=off'; +SET @save_join_cache_level=@@join_cache_level; +SET join_cache_level=0; flush tables; EXPLAIN SELECT OUTR.dt FROM t1 AS OUTR WHERE OUTR.dt IN (SELECT INNR.dt FROM t2 AS INNR WHERE OUTR.dt IS NULL ); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY OUTR ALL NULL NULL NULL NULL 2 Using where -1 PRIMARY INNR ALL NULL NULL NULL NULL 2 Using where; Start temporary; End temporary +1 PRIMARY INNR ALL NULL NULL NULL NULL 2 Using where; FirstMatch(OUTR) flush tables; SELECT OUTR.dt FROM t1 AS OUTR WHERE OUTR.dt IN (SELECT INNR.dt FROM t2 AS INNR WHERE OUTR.dt IS NULL ); dt @@ -210,13 +210,13 @@ flush tables; EXPLAIN SELECT OUTR.dt FROM t1 AS OUTR WHERE OUTR.dt IN ( SELECT INNR.dt FROM t2 AS INNR WHERE OUTR.t < '2005-11-13 7:41:31' ); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY OUTR ALL NULL NULL NULL NULL 2 Using where -1 PRIMARY INNR ALL NULL NULL NULL NULL 2 Using where; Start temporary; End temporary +1 PRIMARY INNR ALL NULL NULL NULL NULL 2 Using where; FirstMatch(OUTR) flush tables; SELECT OUTR.dt FROM t1 AS OUTR WHERE OUTR.dt IN ( SELECT INNR.dt FROM t2 AS INNR WHERE OUTR.t < '2005-11-13 7:41:31' ); dt 2001-01-01 01:01:01 2001-01-01 01:01:01 -SET optimizer_switch=@save_optimizer_switch; +SET join_cache_level=@save_join_cache_level; drop tables t1, t2; # # Bug#47669: Query showed by EXPLAIN EXTENDED gives different result from original query diff --git a/mysql-test/r/greedy_optimizer.result b/mysql-test/r/greedy_optimizer.result index b4c3f4ec9e0..65ec63e2cd9 100644 --- a/mysql-test/r/greedy_optimizer.result +++ b/mysql-test/r/greedy_optimizer.result @@ -202,28 +202,28 @@ select @@optimizer_search_depth; 0 explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 3 -1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where 1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1 1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1 1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 821.837037 +Last_query_cost 1371.437037 explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 3 -1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where 1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1 1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1 1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 821.837037 +Last_query_cost 1371.437037 explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where @@ -231,11 +231,11 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.c21 1 Using where 1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index 1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index -1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 289.418727 +Last_query_cost 362.618727 explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where @@ -243,11 +243,11 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.c21 1 Using where 1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index 1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index -1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 289.418727 +Last_query_cost 362.618727 explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where @@ -255,11 +255,11 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.c21 1 Using where 1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using where 1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where -1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 289.418727 +Last_query_cost 362.618727 explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where @@ -267,11 +267,11 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.c21 1 Using where 1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using where 1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where -1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 289.418727 +Last_query_cost 362.618727 set optimizer_search_depth=1; select @@optimizer_search_depth; @@optimizer_search_depth @@ -287,7 +287,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 821.837037 +Last_query_cost 1693.637037 explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 3 @@ -299,7 +299,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 821.837037 +Last_query_cost 1693.637037 explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 Using where @@ -311,7 +311,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 794.837037 +Last_query_cost 844.037037 explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 Using where @@ -323,7 +323,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 794.837037 +Last_query_cost 844.037037 explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 Using where @@ -335,7 +335,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 794.837037 +Last_query_cost 844.037037 explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 Using where @@ -347,35 +347,35 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 794.837037 +Last_query_cost 844.037037 set optimizer_search_depth=62; select @@optimizer_search_depth; @@optimizer_search_depth 62 explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 3 -1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where 1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1 1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1 1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 821.837037 +Last_query_cost 1371.437037 explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 3 -1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where 1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1 1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1 1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 821.837037 +Last_query_cost 1371.437037 explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where @@ -383,11 +383,11 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.c21 1 Using where 1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index 1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index -1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 289.418727 +Last_query_cost 362.618727 explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where @@ -395,11 +395,11 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.c21 1 Using where 1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index 1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index -1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 289.418727 +Last_query_cost 362.618727 explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where @@ -407,11 +407,11 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.c21 1 Using where 1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using where 1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where -1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 289.418727 +Last_query_cost 362.618727 explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where @@ -419,11 +419,11 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.c21 1 Using where 1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using where 1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where -1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 289.418727 +Last_query_cost 362.618727 set optimizer_prune_level=1; select @@optimizer_prune_level; @@optimizer_prune_level @@ -443,7 +443,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 821.837037 +Last_query_cost 1693.637037 explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 3 @@ -455,55 +455,55 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 821.837037 +Last_query_cost 1693.637037 explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 Using where -1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index -1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index -1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 794.837037 +Last_query_cost 844.037037 explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 Using where -1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index -1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index -1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 794.837037 +Last_query_cost 844.037037 explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 Using where -1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join) -1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using where -1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where -1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 794.837037 +Last_query_cost 844.037037 explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 Using where -1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join) -1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using where -1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where -1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 794.837037 +Last_query_cost 844.037037 set optimizer_search_depth=1; select @@optimizer_search_depth; @@optimizer_search_depth @@ -519,7 +519,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 821.837037 +Last_query_cost 1693.637037 explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 3 @@ -531,7 +531,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 821.837037 +Last_query_cost 1693.637037 explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 Using where @@ -543,7 +543,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 794.837037 +Last_query_cost 844.037037 explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 Using where @@ -555,7 +555,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 794.837037 +Last_query_cost 844.037037 explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 Using where @@ -567,7 +567,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 794.837037 +Last_query_cost 844.037037 explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 Using where @@ -579,7 +579,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 794.837037 +Last_query_cost 844.037037 set optimizer_search_depth=62; select @@optimizer_search_depth; @@optimizer_search_depth @@ -595,7 +595,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 821.837037 +Last_query_cost 1693.637037 explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 3 @@ -607,55 +607,55 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 821.837037 +Last_query_cost 1693.637037 explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 Using where -1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index -1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index -1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 794.837037 +Last_query_cost 844.037037 explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 Using where -1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index -1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index -1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 794.837037 +Last_query_cost 844.037037 explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 Using where -1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join) -1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using where -1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where -1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 794.837037 +Last_query_cost 844.037037 explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 Using where -1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join) -1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using where -1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where -1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 794.837037 +Last_query_cost 844.037037 drop table t1,t2,t3,t4,t5,t6,t7; CREATE TABLE t1 (a int, b int, d int, i int); INSERT INTO t1 VALUES (1,1,1,1); diff --git a/mysql-test/r/innodb_icp.result b/mysql-test/r/innodb_icp.result index 5046b7b4b8b..08238289330 100644 --- a/mysql-test/r/innodb_icp.result +++ b/mysql-test/r/innodb_icp.result @@ -431,8 +431,8 @@ SELECT * FROM t1 WHERE pk IN (SELECT it.pk FROM t2 JOIN t2 AS it ON it.i=it.i WHERE it.pk-t1.i<10); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where -2 DEPENDENT SUBQUERY t2 index NULL PRIMARY 4 NULL 3 Using index 2 DEPENDENT SUBQUERY it eq_ref PRIMARY PRIMARY 4 func 1 Using index condition +2 DEPENDENT SUBQUERY t2 index NULL PRIMARY 4 NULL 3 Using where; Using index; Using join buffer (flat, BNL join) SELECT * FROM t1 WHERE pk IN (SELECT it.pk FROM t2 JOIN t2 AS it ON it.i=it.i WHERE it.pk-t1.i<10); pk i diff --git a/mysql-test/r/join.result b/mysql-test/r/join.result index 4496bcf36d2..8a8b9a690a9 100644 --- a/mysql-test/r/join.result +++ b/mysql-test/r/join.result @@ -897,7 +897,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE B eq_ref PRIMARY PRIMARY 4 test.A.b 1 show status like '%cost%'; Variable_name Value -Last_query_cost 24.016090 +Last_query_cost 28.016090 select '^^: The above should be ~= 20 + cost(select * from t1). Value less than 20 is an error' Z; Z ^^: The above should be ~= 20 + cost(select * from t1). Value less than 20 is an error diff --git a/mysql-test/r/join_cache.result b/mysql-test/r/join_cache.result index f4c995ab1ac..2fc8cc83821 100644 --- a/mysql-test/r/join_cache.result +++ b/mysql-test/r/join_cache.result @@ -314,8 +314,8 @@ CountryLanguage.Percentage > 50 AND LENGTH(Language) < LENGTH(City.Name) - 2; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE Country ALL NULL NULL NULL NULL 239 Using where -1 SIMPLE City hash_ALL NULL #hash#$hj 3 world.Country.Code 4079 Using where; Using join buffer (flat, BNLH join) -1 SIMPLE CountryLanguage hash_ALL NULL #hash#$hj 3 world.Country.Code 984 Using where; Using join buffer (incremental, BNLH join) +1 SIMPLE CountryLanguage hash_ALL NULL #hash#$hj 3 world.Country.Code 984 Using where; Using join buffer (flat, BNLH join) +1 SIMPLE City hash_ALL NULL #hash#$hj 3 world.Country.Code 4079 Using where; Using join buffer (incremental, BNLH join) SELECT City.Name, Country.Name, CountryLanguage.Language FROM City,Country,CountryLanguage WHERE City.Country=Country.Code AND @@ -3927,8 +3927,8 @@ EXPLAIN SELECT t3.a FROM t1,t2,t3 WHERE t1.a = t3.a AND t1.b = t3.b; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where -1 SIMPLE t2 ALL NULL NULL NULL NULL 5 Using join buffer (flat, BNL join) -1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.a 1 Using where; Using join buffer (incremental, BKA join); Key-ordered Rowid-ordered scan +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.a 1 Using where; Using join buffer (flat, BKA join); Key-ordered Rowid-ordered scan +1 SIMPLE t2 ALL NULL NULL NULL NULL 5 Using join buffer (incremental, BNL join) SELECT t3.a FROM t1,t2,t3 WHERE t1.a = t3.a AND t1.b = t3.b; a 27 @@ -4410,8 +4410,8 @@ SET SESSION join_buffer_size = 192; EXPLAIN SELECT t1.a, t2.c FROM t1,t2 WHERE t1.a=t2.a AND t2.b=99; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 36 Using where -1 SIMPLE t2 hash_ALL idx #hash#idx 10 test.t1.a,const 30 Using join buffer (flat, BNLH join) +1 SIMPLE t2 ALL idx NULL NULL NULL 30 Using where +1 SIMPLE t1 hash_ALL NULL #hash#$hj 5 test.t2.a 36 Using where; Using join buffer (flat, BNLH join) SELECT t1.a, t2.c FROM t1,t2 WHERE t1.a=t2.a AND t2.b=99; a c SET SESSION join_cache_level = DEFAULT; diff --git a/mysql-test/r/maria_icp.result b/mysql-test/r/maria_icp.result index c0275d41d43..2d2b4d0c1f7 100644 --- a/mysql-test/r/maria_icp.result +++ b/mysql-test/r/maria_icp.result @@ -437,8 +437,8 @@ SELECT * FROM t1 WHERE pk IN (SELECT it.pk FROM t2 JOIN t2 AS it ON it.i=it.i WHERE it.pk-t1.i<10); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where -2 DEPENDENT SUBQUERY t2 index NULL PRIMARY 4 NULL 3 Using index 2 DEPENDENT SUBQUERY it eq_ref PRIMARY PRIMARY 4 func 1 Using index condition +2 DEPENDENT SUBQUERY t2 index NULL PRIMARY 4 NULL 3 Using where; Using index; Using join buffer (flat, BNL join) SELECT * FROM t1 WHERE pk IN (SELECT it.pk FROM t2 JOIN t2 AS it ON it.i=it.i WHERE it.pk-t1.i<10); pk i diff --git a/mysql-test/r/myisam_icp.result b/mysql-test/r/myisam_icp.result index 68d0ce4e381..c480e35df42 100644 --- a/mysql-test/r/myisam_icp.result +++ b/mysql-test/r/myisam_icp.result @@ -435,8 +435,8 @@ SELECT * FROM t1 WHERE pk IN (SELECT it.pk FROM t2 JOIN t2 AS it ON it.i=it.i WHERE it.pk-t1.i<10); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where -2 DEPENDENT SUBQUERY t2 index NULL PRIMARY 4 NULL 3 Using index 2 DEPENDENT SUBQUERY it eq_ref PRIMARY PRIMARY 4 func 1 Using index condition +2 DEPENDENT SUBQUERY t2 index NULL PRIMARY 4 NULL 3 Using where; Using index; Using join buffer (flat, BNL join) SELECT * FROM t1 WHERE pk IN (SELECT it.pk FROM t2 JOIN t2 AS it ON it.i=it.i WHERE it.pk-t1.i<10); pk i diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index 29a6bb4bf35..fc0f7283981 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -2199,10 +2199,10 @@ a a select * from (t1 as t2 left join t1 as t3 using (a)) inner join t1 on t1.a>1; a a 1 2 -2 2 -3 2 1 3 +2 2 2 3 +3 2 3 3 select * from t1 inner join (t1 as t2 left join t1 as t3 using (a)) on t1.a>1; a a diff --git a/mysql-test/r/select_jcl6.result b/mysql-test/r/select_jcl6.result index fd23d6cc2d6..2d3add1b922 100644 --- a/mysql-test/r/select_jcl6.result +++ b/mysql-test/r/select_jcl6.result @@ -2210,10 +2210,10 @@ a a select * from (t1 as t2 left join t1 as t3 using (a)) inner join t1 on t1.a>1; a a 1 2 -2 2 -3 2 1 3 +2 2 2 3 +3 2 3 3 select * from t1 inner join (t1 as t2 left join t1 as t3 using (a)) on t1.a>1; a a diff --git a/mysql-test/r/select_pkeycache.result b/mysql-test/r/select_pkeycache.result index 29a6bb4bf35..fc0f7283981 100644 --- a/mysql-test/r/select_pkeycache.result +++ b/mysql-test/r/select_pkeycache.result @@ -2199,10 +2199,10 @@ a a select * from (t1 as t2 left join t1 as t3 using (a)) inner join t1 on t1.a>1; a a 1 2 -2 2 -3 2 1 3 +2 2 2 3 +3 2 3 3 select * from t1 inner join (t1 as t2 left join t1 as t3 using (a)) on t1.a>1; a a diff --git a/mysql-test/r/status.result b/mysql-test/r/status.result index 2c88345646c..5579728e0b2 100644 --- a/mysql-test/r/status.result +++ b/mysql-test/r/status.result @@ -149,7 +149,7 @@ a a 1 1 SHOW SESSION STATUS LIKE 'Last_query_cost'; Variable_name Value -Last_query_cost 4.805836 +Last_query_cost 5.205836 DROP TABLE t1; show status like 'com_show_status'; Variable_name Value diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index f54106b5fa0..95fc6e03e56 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -4336,6 +4336,9 @@ LEFT(t1.a1,1) SELECT a2 FROM t2 WHERE t2.a2 IN (SELECT t1.a1 FROM t1,t3 WHERE t1.b1=t3.a3); a2 DROP TABLE t1, t2, t3; +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='semijoin_with_cache=off'; +SET optimizer_switch='materialization=off'; CREATE TABLE t1 (a CHAR(1), b VARCHAR(10)); INSERT INTO t1 VALUES ('a', 'aa'); INSERT INTO t1 VALUES ('a', 'aaa'); @@ -4367,6 +4370,7 @@ id select_type table type possible_keys key key_len ref rows Extra SELECT a,b FROM t1 WHERE b IN (SELECT a FROM t1 WHERE LENGTH(a)<500); a b DROP TABLE t1,t2; +SET optimizer_switch= @save_optimizer_switch; CREATE TABLE t1(a INT, b INT); INSERT INTO t1 VALUES (1,1), (1,2), (2,3), (2,4); EXPLAIN @@ -4463,20 +4467,23 @@ a drop table t1, t2; CREATE TABLE t1 (a INT); INSERT INTO t1 VALUES (1),(2); +SET @save_join_cache_level=@@join_cache_level; +SET join_cache_level=0; EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1 IN (SELECT min(a) 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 1 PRIMARY const distinct_key distinct_key 5 const 1 100.00 +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00 2 MATERIALIZED t1 ALL NULL NULL NULL NULL 2 100.00 Using temporary Warnings: Note 1003 select 1 AS `1` from (select min(`test`.`t1`.`a`) from `test`.`t1` group by `test`.`t1`.`a`) join `test`.`t1` where (``.`min(a)` = 1) EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1 IN (SELECT min(a) FROM t1 WHERE a > 3 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 1 PRIMARY const distinct_key distinct_key 5 const 1 100.00 +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00 2 MATERIALIZED t1 ALL NULL NULL NULL NULL 2 100.00 Using where; Using temporary Warnings: Note 1003 select 1 AS `1` from (select min(`test`.`t1`.`a`) from `test`.`t1` where (`test`.`t1`.`a` > 3) group by `test`.`t1`.`a`) join `test`.`t1` where (``.`min(a)` = 1) +SET join_cache_level=@save_join_cache_level; DROP TABLE t1; # # Bug#45061: Incorrectly market field caused wrong result. @@ -5227,16 +5234,19 @@ CREATE TABLE t2 (pk INTEGER PRIMARY KEY, i INTEGER NOT NULL); INSERT INTO t2 VALUES (11,1); INSERT INTO t2 VALUES (12,2); INSERT INTO t2 VALUES (15,4); +SET @save_join_cache_level=@@join_cache_level; +SET join_cache_level=0; EXPLAIN SELECT * FROM t1 WHERE pk IN (SELECT it.pk FROM t2 JOIN t2 AS it ON 1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL PRIMARY NULL NULL NULL 3 1 PRIMARY it eq_ref PRIMARY PRIMARY 4 test.t1.pk 1 Using index -1 PRIMARY t2 index NULL PRIMARY 4 NULL 3 Using index; FirstMatch(it); Using join buffer (flat, BNL join) +1 PRIMARY t2 index NULL PRIMARY 4 NULL 3 Using index; FirstMatch(it) SELECT * FROM t1 WHERE pk IN (SELECT it.pk FROM t2 JOIN t2 AS it ON 1); pk i 11 0 12 5 15 0 +SET join_cache_level=@save_join_cache_level; DROP table t1,t2; # # Bug#751350: crash with pushed condition for outer references when diff --git a/mysql-test/r/subselect2.result b/mysql-test/r/subselect2.result index 52297a65e39..41c445329cb 100644 --- a/mysql-test/r/subselect2.result +++ b/mysql-test/r/subselect2.result @@ -125,9 +125,9 @@ DOCID DOCNAME DOCTYPEID FOLDERID AUTHOR CREATED TITLE SUBTITLE DOCABSTRACT PUBLI c373e9f5ad07993f3859444553544200 Last Discussion c373e9f5ad079174ff17444553544200 c373e9f5ad0796c0eca4444553544200 Goldilocks 2003-06-09 11:21:06 Title: Last Discussion NULL Setting new abstract and keeping doc checked out 2003-06-09 10:51:26 2003-06-09 10:51:26 NULL NULL NULL 03eea05112b845949f3fd03278b5fe43 2003-06-09 11:21:06 admin 0 NULL Discussion NULL NULL EXPLAIN SELECT t2.*, t4.DOCTYPENAME, t1.CONTENTSIZE,t1.MIMETYPE FROM t2 INNER JOIN t4 ON t2.DOCTYPEID = t4.DOCTYPEID LEFT OUTER JOIN t1 ON t2.DOCID = t1.DOCID WHERE t2.FOLDERID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID='2f6161e879db43c1a5b82c21ddc49089' AND t3.FOLDERNAME = 'Level1') AND t3.FOLDERNAME = 'Level2') AND t3.FOLDERNAME = 'Level3') AND t3.FOLDERNAME = 'CopiedFolder') AND t3.FOLDERNAME = 'Movie Reviews') AND t2.DOCNAME = 'Last Discussion'; id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t4 ALL PRIMARY NULL NULL NULL 10 -1 PRIMARY t2 ALL DDOCTYPEID_IDX,DFOLDERID_IDX NULL NULL NULL 9 Using where; Using join buffer (flat, BNL join) +1 PRIMARY t2 ALL DDOCTYPEID_IDX,DFOLDERID_IDX NULL NULL NULL 9 Using where 1 PRIMARY t1 eq_ref PRIMARY PRIMARY 34 test.t2.DOCID 1 +1 PRIMARY t4 eq_ref PRIMARY PRIMARY 34 test.t2.DOCTYPEID 1 1 PRIMARY t3 eq_ref PRIMARY,FFOLDERID_IDX,CMFLDRPARNT_IDX PRIMARY 34 test.t2.FOLDERID 1 Using where 1 PRIMARY t3 eq_ref PRIMARY,FFOLDERID_IDX,CMFLDRPARNT_IDX PRIMARY 34 test.t3.PARENTID 1 Using where 1 PRIMARY t3 eq_ref PRIMARY,FFOLDERID_IDX,CMFLDRPARNT_IDX PRIMARY 34 test.t3.PARENTID 1 Using where diff --git a/mysql-test/r/subselect3.result b/mysql-test/r/subselect3.result index 29518fb6df9..ae629ccb928 100644 --- a/mysql-test/r/subselect3.result +++ b/mysql-test/r/subselect3.result @@ -1138,8 +1138,8 @@ create table t3 (a int); insert into t3 select A.a + 10*B.a from t0 A, t0 B; 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 t3 ALL NULL NULL NULL NULL 100 Using where -1 PRIMARY t1 ref kp1 kp1 5 test.t3.a 1 Using index; FirstMatch(t3) +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) create table t4 (pk int primary key); insert into t4 select a from t3; explain select * from t3 where a in (select t1.kp1 from t1,t4 where kp1<20 @@ -1336,9 +1336,9 @@ insert into t2 select * from t2; explain select * from t1 where (a,b,c) in (select X.a, Y.a, Z.a from t2 X, t2 Y, t2 Z where X.b=33); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 -1 PRIMARY X ALL NULL NULL NULL NULL 6 Using where; Start temporary; Using join buffer (flat, BNL join) -1 PRIMARY Y ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join) -1 PRIMARY Z ALL NULL NULL NULL NULL 6 Using where; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY X ALL NULL NULL NULL NULL 6 Using where +1 PRIMARY Y ALL NULL NULL NULL NULL 6 Using where +1 PRIMARY Z ALL NULL NULL NULL NULL 6 Using where; FirstMatch(t1) drop table t0,t1,t2; set @@optimizer_switch=@save_optimizer_switch; diff --git a/mysql-test/r/subselect3_jcl6.result b/mysql-test/r/subselect3_jcl6.result index c70adc7e71c..7d20f81fbb9 100644 --- a/mysql-test/r/subselect3_jcl6.result +++ b/mysql-test/r/subselect3_jcl6.result @@ -1148,8 +1148,8 @@ create table t3 (a int); insert into t3 select A.a + 10*B.a from t0 A, t0 B; 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 t3 ALL NULL NULL NULL NULL 100 Using where -1 PRIMARY t1 ref kp1 kp1 5 test.t3.a 1 Using index; FirstMatch(t3) +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) create table t4 (pk int primary key); insert into t4 select a from t3; explain select * from t3 where a in (select t1.kp1 from t1,t4 where kp1<20 @@ -1345,10 +1345,10 @@ create table t2 as select a as a, a as b from t0 where a < 3; insert into t2 select * from t2; explain select * from t1 where (a,b,c) in (select X.a, Y.a, Z.a from t2 X, t2 Y, t2 Z where X.b=33); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where -1 PRIMARY X hash_ALL NULL #hash#$hj 5 test.t1.a 6 Using where; Start temporary; Using join buffer (flat, BNLH join) -1 PRIMARY Y hash_ALL NULL #hash#$hj 5 test.t1.b 6 Using where; Using join buffer (incremental, BNLH join) -1 PRIMARY Z hash_ALL NULL #hash#$hj 5 test.t1.c 6 Using where; End temporary; Using join buffer (incremental, BNLH join) +1 PRIMARY t1 ALL NULL NULL NULL NULL 3 +1 PRIMARY X ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join) +1 PRIMARY Y ALL NULL NULL NULL NULL 6 Using where; Using join buffer (incremental, BNL join) +1 PRIMARY Z ALL NULL NULL NULL NULL 6 Using where; FirstMatch(t1); Using join buffer (incremental, BNL join) drop table t0,t1,t2; set @@optimizer_switch=@save_optimizer_switch; diff --git a/mysql-test/r/subselect4.result b/mysql-test/r/subselect4.result index f9337ddc78a..6c942bca31a 100644 --- a/mysql-test/r/subselect4.result +++ b/mysql-test/r/subselect4.result @@ -1226,22 +1226,25 @@ CREATE TABLE t4 (c1 varchar(1) primary key); INSERT INTO t4 VALUES ('k'), ('d'); SET @save_optimizer_switch=@@optimizer_switch; SET optimizer_switch='outer_join_with_cache=off'; +SET optimizer_switch='semijoin_with_cache=off'; +SET optimizer_switch='materialization=off'; EXPLAIN SELECT * FROM t1 RIGHT JOIN t2 ON t1.c1 WHERE 's' IN (SELECT c1 FROM t2); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 0 const row not found -1 PRIMARY t2 ALL NULL NULL NULL NULL 2 -1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where; FirstMatch(t2); Using join buffer (flat, BNL join) +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where; FirstMatch(t1) +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using join buffer (flat, BNL join) SELECT * FROM t1 RIGHT JOIN t2 ON t1.c1 WHERE 's' IN (SELECT c1 FROM t2); c1 c1 EXPLAIN SELECT * FROM t2 LEFT JOIN t1 ON t1.c1 WHERE 's' IN (SELECT c1 FROM t2); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 0 const row not found -1 PRIMARY t2 ALL NULL NULL NULL NULL 2 -1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where; FirstMatch(t2); Using join buffer (flat, BNL join) +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where; FirstMatch(t1) +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using join buffer (flat, BNL join) SELECT * FROM t2 LEFT JOIN t1 ON t1.c1 WHERE 's' IN (SELECT c1 FROM t2); c1 c1 +SET optimizer_switch='materialization=on'; EXPLAIN SELECT * FROM (t2 LEFT JOIN t1 ON t1.c1) LEFT JOIN t3 on t3.c1 WHERE 's' IN (SELECT c1 FROM t2); id select_type table type possible_keys key key_len ref rows Extra diff --git a/mysql-test/r/subselect_extra.result b/mysql-test/r/subselect_extra.result index 9246128391e..53a38bf6e8e 100644 --- a/mysql-test/r/subselect_extra.result +++ b/mysql-test/r/subselect_extra.result @@ -307,7 +307,8 @@ EXPLAIN SELECT 1 FROM t1 WHERE a IN (SELECT a FROM t1 USE INDEX (i2) IGNORE INDEX (i2)); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 index PRIMARY,i2 PRIMARY 4 NULL 144 Using index -1 PRIMARY t1 ALL NULL NULL NULL NULL 144 Using where; FirstMatch(t1); Using join buffer (flat, BNL join) +1 PRIMARY eq_ref distinct_key distinct_key 4 func 1 +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 144 CREATE TABLE t2 (a INT, b INT, KEY(a)); INSERT INTO t2 VALUES (1, 1), (2, 2), (3,3), (4,4); EXPLAIN SELECT a, SUM(b) FROM t2 GROUP BY a LIMIT 2; @@ -320,7 +321,8 @@ EXPLAIN SELECT 1 FROM t2 WHERE a IN (SELECT a FROM t1 USE INDEX (i2) IGNORE INDEX (i2)); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 index a a 5 NULL 4 Using index -1 PRIMARY t1 ALL NULL NULL NULL NULL 144 Using where; FirstMatch(t2); Using join buffer (flat, BNL join) +1 PRIMARY eq_ref distinct_key distinct_key 4 func 1 +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 144 DROP TABLE t1, t2; # # From derived_view.test diff --git a/mysql-test/r/subselect_mat_cost.result b/mysql-test/r/subselect_mat_cost.result index 3f465f1a7d0..e5f2df1c5c1 100644 --- a/mysql-test/r/subselect_mat_cost.result +++ b/mysql-test/r/subselect_mat_cost.result @@ -512,8 +512,8 @@ FROM City JOIN Country ON City.Country = Country.Code GROUP BY City.Name HAVING City.Name IN (select Name from Country where population < 1000000); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY City ALL Country NULL NULL NULL 4080 Using temporary; Using filesort -1 PRIMARY Country eq_ref PRIMARY PRIMARY 3 world.City.Country 1 Using index +1 PRIMARY Country index PRIMARY PRIMARY 3 NULL 239 Using index; Using temporary; Using filesort +1 PRIMARY City ref Country Country 3 world.Country.Code 18 2 MATERIALIZED Country ALL Name NULL NULL NULL 239 Using where SELECT City.Name, City.Population FROM City JOIN Country ON City.Country = Country.Code diff --git a/mysql-test/r/subselect_no_mat.result b/mysql-test/r/subselect_no_mat.result index c55cb0a425a..8959853f16f 100644 --- a/mysql-test/r/subselect_no_mat.result +++ b/mysql-test/r/subselect_no_mat.result @@ -4340,6 +4340,9 @@ LEFT(t1.a1,1) SELECT a2 FROM t2 WHERE t2.a2 IN (SELECT t1.a1 FROM t1,t3 WHERE t1.b1=t3.a3); a2 DROP TABLE t1, t2, t3; +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='semijoin_with_cache=off'; +SET optimizer_switch='materialization=off'; CREATE TABLE t1 (a CHAR(1), b VARCHAR(10)); INSERT INTO t1 VALUES ('a', 'aa'); INSERT INTO t1 VALUES ('a', 'aaa'); @@ -4371,6 +4374,7 @@ id select_type table type possible_keys key key_len ref rows Extra SELECT a,b FROM t1 WHERE b IN (SELECT a FROM t1 WHERE LENGTH(a)<500); a b DROP TABLE t1,t2; +SET optimizer_switch= @save_optimizer_switch; CREATE TABLE t1(a INT, b INT); INSERT INTO t1 VALUES (1,1), (1,2), (2,3), (2,4); EXPLAIN @@ -4467,6 +4471,8 @@ a drop table t1, t2; CREATE TABLE t1 (a INT); INSERT INTO t1 VALUES (1),(2); +SET @save_join_cache_level=@@join_cache_level; +SET join_cache_level=0; EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1 IN (SELECT min(a) 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 @@ -4479,6 +4485,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 2 100.00 Using where; Using temporary Warnings: Note 1003 select 1 AS `1` from `test`.`t1` where <1>((1,(select min(`test`.`t1`.`a`) from `test`.`t1` where (`test`.`t1`.`a` > 3) group by `test`.`t1`.`a` having (1 = (min(`test`.`t1`.`a`)))))) +SET join_cache_level=@save_join_cache_level; DROP TABLE t1; # # Bug#45061: Incorrectly market field caused wrong result. @@ -5228,16 +5235,19 @@ CREATE TABLE t2 (pk INTEGER PRIMARY KEY, i INTEGER NOT NULL); INSERT INTO t2 VALUES (11,1); INSERT INTO t2 VALUES (12,2); INSERT INTO t2 VALUES (15,4); +SET @save_join_cache_level=@@join_cache_level; +SET join_cache_level=0; EXPLAIN SELECT * FROM t1 WHERE pk IN (SELECT it.pk FROM t2 JOIN t2 AS it ON 1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL PRIMARY NULL NULL NULL 3 1 PRIMARY it eq_ref PRIMARY PRIMARY 4 test.t1.pk 1 Using index -1 PRIMARY t2 index NULL PRIMARY 4 NULL 3 Using index; FirstMatch(it); Using join buffer (flat, BNL join) +1 PRIMARY t2 index NULL PRIMARY 4 NULL 3 Using index; FirstMatch(it) SELECT * FROM t1 WHERE pk IN (SELECT it.pk FROM t2 JOIN t2 AS it ON 1); pk i 11 0 12 5 15 0 +SET join_cache_level=@save_join_cache_level; DROP table t1,t2; # # Bug#751350: crash with pushed condition for outer references when diff --git a/mysql-test/r/subselect_no_opts.result b/mysql-test/r/subselect_no_opts.result index 0b77366469c..1a937bbcd5f 100644 --- a/mysql-test/r/subselect_no_opts.result +++ b/mysql-test/r/subselect_no_opts.result @@ -1503,10 +1503,10 @@ a explain extended select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 index NULL a 5 NULL 4 100.00 Using where; Using index -2 DEPENDENT SUBQUERY t1 ref a a 5 func 1001 100.00 Using index -2 DEPENDENT SUBQUERY t3 index a a 5 NULL 3 100.00 Using where; Using index; Using join buffer (flat, BNL join) +2 DEPENDENT SUBQUERY t3 index a a 5 NULL 3 100.00 Using where; Using index +2 DEPENDENT SUBQUERY t1 ref a a 10 func,test.t3.a 1167 100.00 Using index Warnings: -Note 1003 select `test`.`t2`.`a` AS `a` from `test`.`t2` where (`test`.`t2`.`a`,(select `test`.`t1`.`a` from `test`.`t1` join `test`.`t3` where ((`test`.`t3`.`a` = `test`.`t1`.`b`) and ((`test`.`t2`.`a`) = `test`.`t1`.`a`)))) +Note 1003 select `test`.`t2`.`a` AS `a` from `test`.`t2` where (`test`.`t2`.`a`,(select `test`.`t1`.`a` from `test`.`t1` join `test`.`t3` where ((`test`.`t1`.`b` = `test`.`t3`.`a`) and ((`test`.`t2`.`a`) = `test`.`t1`.`a`)))) insert into t1 values (3,31); select * from t2 where t2.a in (select a from t1 where t1.b <> 30); a @@ -4336,6 +4336,9 @@ LEFT(t1.a1,1) SELECT a2 FROM t2 WHERE t2.a2 IN (SELECT t1.a1 FROM t1,t3 WHERE t1.b1=t3.a3); a2 DROP TABLE t1, t2, t3; +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='semijoin_with_cache=off'; +SET optimizer_switch='materialization=off'; CREATE TABLE t1 (a CHAR(1), b VARCHAR(10)); INSERT INTO t1 VALUES ('a', 'aa'); INSERT INTO t1 VALUES ('a', 'aaa'); @@ -4367,6 +4370,7 @@ id select_type table type possible_keys key key_len ref rows Extra SELECT a,b FROM t1 WHERE b IN (SELECT a FROM t1 WHERE LENGTH(a)<500); a b DROP TABLE t1,t2; +SET optimizer_switch= @save_optimizer_switch; CREATE TABLE t1(a INT, b INT); INSERT INTO t1 VALUES (1,1), (1,2), (2,3), (2,4); EXPLAIN @@ -4463,6 +4467,8 @@ a drop table t1, t2; CREATE TABLE t1 (a INT); INSERT INTO t1 VALUES (1),(2); +SET @save_join_cache_level=@@join_cache_level; +SET join_cache_level=0; EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1 IN (SELECT min(a) 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 @@ -4475,6 +4481,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 2 100.00 Using where; Using temporary Warnings: Note 1003 select 1 AS `1` from `test`.`t1` where (1,(select min(`test`.`t1`.`a`) from `test`.`t1` where (`test`.`t1`.`a` > 3) group by `test`.`t1`.`a` having (1 = (min(`test`.`t1`.`a`))))) +SET join_cache_level=@save_join_cache_level; DROP TABLE t1; # # Bug#45061: Incorrectly market field caused wrong result. @@ -5224,16 +5231,19 @@ CREATE TABLE t2 (pk INTEGER PRIMARY KEY, i INTEGER NOT NULL); INSERT INTO t2 VALUES (11,1); INSERT INTO t2 VALUES (12,2); INSERT INTO t2 VALUES (15,4); +SET @save_join_cache_level=@@join_cache_level; +SET join_cache_level=0; EXPLAIN SELECT * FROM t1 WHERE pk IN (SELECT it.pk FROM t2 JOIN t2 AS it ON 1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where -2 DEPENDENT SUBQUERY t2 index NULL PRIMARY 4 NULL 3 Using index 2 DEPENDENT SUBQUERY it eq_ref PRIMARY PRIMARY 4 func 1 Using index +2 DEPENDENT SUBQUERY t2 index NULL PRIMARY 4 NULL 3 Using index SELECT * FROM t1 WHERE pk IN (SELECT it.pk FROM t2 JOIN t2 AS it ON 1); pk i 11 0 12 5 15 0 +SET join_cache_level=@save_join_cache_level; DROP table t1,t2; # # Bug#751350: crash with pushed condition for outer references when diff --git a/mysql-test/r/subselect_no_scache.result b/mysql-test/r/subselect_no_scache.result index fb9cda3c412..56e06b948a1 100644 --- a/mysql-test/r/subselect_no_scache.result +++ b/mysql-test/r/subselect_no_scache.result @@ -4342,6 +4342,9 @@ LEFT(t1.a1,1) SELECT a2 FROM t2 WHERE t2.a2 IN (SELECT t1.a1 FROM t1,t3 WHERE t1.b1=t3.a3); a2 DROP TABLE t1, t2, t3; +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='semijoin_with_cache=off'; +SET optimizer_switch='materialization=off'; CREATE TABLE t1 (a CHAR(1), b VARCHAR(10)); INSERT INTO t1 VALUES ('a', 'aa'); INSERT INTO t1 VALUES ('a', 'aaa'); @@ -4373,6 +4376,7 @@ id select_type table type possible_keys key key_len ref rows Extra SELECT a,b FROM t1 WHERE b IN (SELECT a FROM t1 WHERE LENGTH(a)<500); a b DROP TABLE t1,t2; +SET optimizer_switch= @save_optimizer_switch; CREATE TABLE t1(a INT, b INT); INSERT INTO t1 VALUES (1,1), (1,2), (2,3), (2,4); EXPLAIN @@ -4469,20 +4473,23 @@ a drop table t1, t2; CREATE TABLE t1 (a INT); INSERT INTO t1 VALUES (1),(2); +SET @save_join_cache_level=@@join_cache_level; +SET join_cache_level=0; EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1 IN (SELECT min(a) 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 1 PRIMARY const distinct_key distinct_key 5 const 1 100.00 +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00 2 MATERIALIZED t1 ALL NULL NULL NULL NULL 2 100.00 Using temporary Warnings: Note 1003 select 1 AS `1` from (select min(`test`.`t1`.`a`) from `test`.`t1` group by `test`.`t1`.`a`) join `test`.`t1` where (``.`min(a)` = 1) EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1 IN (SELECT min(a) FROM t1 WHERE a > 3 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 1 PRIMARY const distinct_key distinct_key 5 const 1 100.00 +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00 2 MATERIALIZED t1 ALL NULL NULL NULL NULL 2 100.00 Using where; Using temporary Warnings: Note 1003 select 1 AS `1` from (select min(`test`.`t1`.`a`) from `test`.`t1` where (`test`.`t1`.`a` > 3) group by `test`.`t1`.`a`) join `test`.`t1` where (``.`min(a)` = 1) +SET join_cache_level=@save_join_cache_level; DROP TABLE t1; # # Bug#45061: Incorrectly market field caused wrong result. @@ -5233,16 +5240,19 @@ CREATE TABLE t2 (pk INTEGER PRIMARY KEY, i INTEGER NOT NULL); INSERT INTO t2 VALUES (11,1); INSERT INTO t2 VALUES (12,2); INSERT INTO t2 VALUES (15,4); +SET @save_join_cache_level=@@join_cache_level; +SET join_cache_level=0; EXPLAIN SELECT * FROM t1 WHERE pk IN (SELECT it.pk FROM t2 JOIN t2 AS it ON 1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL PRIMARY NULL NULL NULL 3 1 PRIMARY it eq_ref PRIMARY PRIMARY 4 test.t1.pk 1 Using index -1 PRIMARY t2 index NULL PRIMARY 4 NULL 3 Using index; FirstMatch(it); Using join buffer (flat, BNL join) +1 PRIMARY t2 index NULL PRIMARY 4 NULL 3 Using index; FirstMatch(it) SELECT * FROM t1 WHERE pk IN (SELECT it.pk FROM t2 JOIN t2 AS it ON 1); pk i 11 0 12 5 15 0 +SET join_cache_level=@save_join_cache_level; DROP table t1,t2; # # Bug#751350: crash with pushed condition for outer references when diff --git a/mysql-test/r/subselect_no_semijoin.result b/mysql-test/r/subselect_no_semijoin.result index 381b2f12665..b92230cff3b 100644 --- a/mysql-test/r/subselect_no_semijoin.result +++ b/mysql-test/r/subselect_no_semijoin.result @@ -1503,10 +1503,10 @@ a explain extended select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 index NULL a 5 NULL 4 100.00 Using where; Using index -2 DEPENDENT SUBQUERY t1 ref a a 5 func 1001 100.00 Using index -2 DEPENDENT SUBQUERY t3 index a a 5 NULL 3 100.00 Using where; Using index; Using join buffer (flat, BNL join) +2 DEPENDENT SUBQUERY t3 index a a 5 NULL 3 100.00 Using where; Using index +2 DEPENDENT SUBQUERY t1 ref a a 10 func,test.t3.a 1167 100.00 Using index Warnings: -Note 1003 select `test`.`t2`.`a` AS `a` from `test`.`t2` where <`test`.`t2`.`a`>((`test`.`t2`.`a`,(select `test`.`t1`.`a` from `test`.`t1` join `test`.`t3` where ((`test`.`t3`.`a` = `test`.`t1`.`b`) and ((`test`.`t2`.`a`) = `test`.`t1`.`a`))))) +Note 1003 select `test`.`t2`.`a` AS `a` from `test`.`t2` where <`test`.`t2`.`a`>((`test`.`t2`.`a`,(select `test`.`t1`.`a` from `test`.`t1` join `test`.`t3` where ((`test`.`t1`.`b` = `test`.`t3`.`a`) and ((`test`.`t2`.`a`) = `test`.`t1`.`a`))))) insert into t1 values (3,31); select * from t2 where t2.a in (select a from t1 where t1.b <> 30); a @@ -4336,6 +4336,9 @@ LEFT(t1.a1,1) SELECT a2 FROM t2 WHERE t2.a2 IN (SELECT t1.a1 FROM t1,t3 WHERE t1.b1=t3.a3); a2 DROP TABLE t1, t2, t3; +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='semijoin_with_cache=off'; +SET optimizer_switch='materialization=off'; CREATE TABLE t1 (a CHAR(1), b VARCHAR(10)); INSERT INTO t1 VALUES ('a', 'aa'); INSERT INTO t1 VALUES ('a', 'aaa'); @@ -4346,7 +4349,7 @@ CREATE INDEX I2 ON t1 (b); EXPLAIN SELECT a,b FROM t1 WHERE b IN (SELECT a FROM t1); 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 t1 index I1 I1 2 NULL 2 Using index +2 DEPENDENT SUBQUERY t1 index_subquery I1 I1 2 func 2 Using index; Using where SELECT a,b FROM t1 WHERE b IN (SELECT a FROM t1); a b CREATE TABLE t2 (a VARCHAR(1), b VARCHAR(10)); @@ -4356,17 +4359,18 @@ CREATE INDEX I2 ON t2 (b); EXPLAIN SELECT a,b FROM t2 WHERE b IN (SELECT a FROM t2); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where -2 MATERIALIZED t2 index I1 I1 4 NULL 2 Using index +2 DEPENDENT SUBQUERY t2 index_subquery I1 I1 4 func 2 Using index; Using where SELECT a,b FROM t2 WHERE b IN (SELECT a FROM t2); a b EXPLAIN SELECT a,b FROM t1 WHERE b IN (SELECT a FROM t1 WHERE LENGTH(a)<500); 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 t1 index I1 I1 2 NULL 2 Using where; Using index +2 DEPENDENT SUBQUERY t1 index_subquery I1 I1 2 func 2 Using index; Using where SELECT a,b FROM t1 WHERE b IN (SELECT a FROM t1 WHERE LENGTH(a)<500); a b DROP TABLE t1,t2; +SET optimizer_switch= @save_optimizer_switch; CREATE TABLE t1(a INT, b INT); INSERT INTO t1 VALUES (1,1), (1,2), (2,3), (2,4); EXPLAIN @@ -4463,6 +4467,8 @@ a drop table t1, t2; CREATE TABLE t1 (a INT); INSERT INTO t1 VALUES (1),(2); +SET @save_join_cache_level=@@join_cache_level; +SET join_cache_level=0; EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1 IN (SELECT min(a) 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 @@ -4475,6 +4481,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 2 MATERIALIZED t1 ALL NULL NULL NULL NULL 2 100.00 Using where; Using temporary Warnings: Note 1003 select 1 AS `1` from `test`.`t1` where <1>((1,1 in ( (select min(`test`.`t1`.`a`) from `test`.`t1` where (`test`.`t1`.`a` > 3) group by `test`.`t1`.`a` ), (1 in on distinct_key where ((1 = ``.`min(a)`)))))) +SET join_cache_level=@save_join_cache_level; DROP TABLE t1; # # Bug#45061: Incorrectly market field caused wrong result. @@ -5224,16 +5231,19 @@ CREATE TABLE t2 (pk INTEGER PRIMARY KEY, i INTEGER NOT NULL); INSERT INTO t2 VALUES (11,1); INSERT INTO t2 VALUES (12,2); INSERT INTO t2 VALUES (15,4); +SET @save_join_cache_level=@@join_cache_level; +SET join_cache_level=0; EXPLAIN SELECT * FROM t1 WHERE pk IN (SELECT it.pk FROM t2 JOIN t2 AS it ON 1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where 2 MATERIALIZED t2 index NULL PRIMARY 4 NULL 3 Using index -2 MATERIALIZED it index PRIMARY PRIMARY 4 NULL 3 Using index; Using join buffer (flat, BNL join) +2 MATERIALIZED it index PRIMARY PRIMARY 4 NULL 3 Using index SELECT * FROM t1 WHERE pk IN (SELECT it.pk FROM t2 JOIN t2 AS it ON 1); pk i 11 0 12 5 15 0 +SET join_cache_level=@save_join_cache_level; DROP table t1,t2; # # Bug#751350: crash with pushed condition for outer references when diff --git a/mysql-test/r/subselect_sj.result b/mysql-test/r/subselect_sj.result index 47cf21f3e43..b1b0bde7c57 100644 --- a/mysql-test/r/subselect_sj.result +++ b/mysql-test/r/subselect_sj.result @@ -970,11 +970,11 @@ SELECT `varchar_key` , `varchar_nokey` FROM t1 WHERE `varchar_nokey` < 'n' XOR `pk` ) ; id select_type table type possible_keys key key_len ref rows filtered Extra -1 PRIMARY t2 ALL NULL NULL NULL NULL 18 100.00 -1 PRIMARY eq_ref distinct_key distinct_key 8 func,func 1 100.00 +1 PRIMARY ALL distinct_key NULL NULL NULL 15 100.00 +1 PRIMARY t2 ALL NULL NULL NULL NULL 18 100.00 Using where; Using join buffer (flat, BNL join) 2 MATERIALIZED t1 ALL varchar_key NULL NULL NULL 15 100.00 Using where Warnings: -Note 1003 select `test`.`t2`.`varchar_nokey` AS `varchar_nokey` from `test`.`t2` semi join (`test`.`t1`) where ((`test`.`t1`.`varchar_nokey` = `test`.`t1`.`varchar_key`) and ((`test`.`t1`.`varchar_key` < 'n') xor `test`.`t1`.`pk`)) +Note 1003 select `test`.`t2`.`varchar_nokey` AS `varchar_nokey` from `test`.`t2` semi join (`test`.`t1`) where ((`test`.`t1`.`varchar_nokey` = `test`.`t1`.`varchar_key`) and (`test`.`t2`.`varchar_nokey` = `test`.`t1`.`varchar_key`) and ((`test`.`t1`.`varchar_key` < 'n') xor `test`.`t1`.`pk`)) SELECT varchar_nokey FROM t2 WHERE ( `varchar_nokey` , `varchar_nokey` ) IN ( @@ -1938,45 +1938,18 @@ DROP TABLE t1, t2, t4, t5; # # BUG#861147: Assertion `fixed == 1' failed in Item_func_eq::val_int() with semijoin + materialization + max_join_size # -CREATE TABLE t1 ( f2 int) ; -CREATE TABLE t2 ( f1 int, f3 int, f4 varchar(3), f5 varchar(35)) ; -INSERT INTO t2 VALUES (4057,9,'USA','Visalia'),(3993,11,'USA','Waco'), -(3948,14,'USA','Warren'),(3813,57,'USA','Washington'), -(4010,11,'USA','Waterbury'),(4017,11,'USA','West Covina'), -(4004,11,'USA','West Valley City'),(4033,10,'USA','Westminster'), -(3842,34,'USA','Wichita'),(4018,10,'USA','Wichita Falls'), -(3899,19,'USA','Winston-Salem'),(3914,17,'USA','Worcester'), -(3888,20,'USA','Yonkers'); -CREATE TABLE t3 ( f3 int, f4 varchar(3)) ; -INSERT INTO t3 VALUES (86,'USA'); -CREATE TABLE t4 ( f3 int, f4 varchar(3), f5 varchar(52)) ; -INSERT INTO t4 VALUES (0,'RUS','Belorussian'),(0,'USA','Portuguese'); -CREATE TABLE t5 ( f2 int) ; -CREATE TABLE t6 ( f4 varchar(3)); -INSERT INTO t6 VALUES ('RUS'),('USA'); +create table t1 (a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); set @tmp_mjs_861147= @@max_join_size; SET max_join_size=10; set @tmp_os_861147= @@optimizer_switch; set @@optimizer_switch='semijoin=on,materialization=on'; -SELECT * -FROM t1 -WHERE ( 1 , 3 ) IN ( -SELECT t2.f1 , MAX( t3.f3 ) -FROM t2 -JOIN t3 -WHERE t3.f4 IN ( -SELECT t4.f5 -FROM t4 -STRAIGHT_JOIN t5 -WHERE t4.f4 < t2.f5 -) -) AND ( 'p' , 'k' ) IN ( -SELECT f4 , f4 FROM t6 -); +explain +select * from t1 where a in (select max(A.a + B.a + C.a) from t1 A, t1 B, t1 C); ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET MAX_JOIN_SIZE=# if the SELECT is okay set max_join_size= @tmp_mjs_861147; set optimizer_switch= @tmp_os_861147; -DROP TABLE t1,t2,t3,t4,t5,t6; +drop table t1; # # BUG#877288: Wrong result with semijoin + materialization + multipart key # diff --git a/mysql-test/r/subselect_sj2.result b/mysql-test/r/subselect_sj2.result index 5bf470a5245..8df3bd8f9b8 100644 --- a/mysql-test/r/subselect_sj2.result +++ b/mysql-test/r/subselect_sj2.result @@ -69,9 +69,9 @@ insert into t3 select a,a, a,a,a from t0; insert into t3 select a,a, a+100,a+100,a+100 from t0; explain select * from t3 where b in (select a from t1); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t3 ALL b NULL NULL NULL 20 -1 PRIMARY eq_ref distinct_key distinct_key 5 func 1 -2 MATERIALIZED t1 ALL NULL NULL NULL NULL 3 +1 PRIMARY ALL distinct_key NULL NULL NULL 3 +1 PRIMARY t3 ref b b 5 test.t1.a 1 +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 3 Using where select * from t3 where b in (select a from t1); a b pk1 pk2 pk3 1 1 1 1 1 @@ -878,9 +878,9 @@ SELECT * FROM t3 LEFT JOIN (v1,t2) ON t3.a = t2.a WHERE t3.b IN (SELECT b FROM t4); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 1 +1 PRIMARY eq_ref distinct_key distinct_key 5 func 1 1 PRIMARY t2 ALL NULL NULL NULL NULL 1 Using where 1 PRIMARY ALL NULL NULL NULL NULL 2 -1 PRIMARY eq_ref distinct_key distinct_key 5 func 1 2 MATERIALIZED t4 ALL NULL NULL NULL NULL 2 3 DERIVED t1 ALL NULL NULL NULL NULL 1 SELECT * FROM t3 LEFT JOIN (v1,t2) ON t3.a = t2.a diff --git a/mysql-test/r/subselect_sj2_jcl6.result b/mysql-test/r/subselect_sj2_jcl6.result index 80c24652cbd..222d34d9bf4 100644 --- a/mysql-test/r/subselect_sj2_jcl6.result +++ b/mysql-test/r/subselect_sj2_jcl6.result @@ -80,8 +80,9 @@ insert into t3 select a,a, a,a,a from t0; insert into t3 select a,a, a+100,a+100,a+100 from t0; explain select * from t3 where b in (select a from t1); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t3 ALL b NULL NULL NULL 20 -1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where; FirstMatch(t3); Using join buffer (flat, BNL join) +1 PRIMARY ALL distinct_key NULL NULL NULL 3 +1 PRIMARY t3 ref b b 5 test.t1.a 1 Using join buffer (flat, BKA join); Key-ordered Rowid-ordered scan +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 3 Using where select * from t3 where b in (select a from t1); a b pk1 pk2 pk3 1 1 1 1 1 @@ -131,8 +132,9 @@ set join_buffer_size= @save_join_buffer_size; set max_heap_table_size= @save_max_heap_table_size; explain select * from t1 where a in (select b from t2); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where -1 PRIMARY t2 ref b b 5 test.t1.a 2 Using index; FirstMatch(t1) +1 PRIMARY t1 ALL NULL NULL NULL NULL 3 +1 PRIMARY eq_ref distinct_key distinct_key 5 func 1 +2 MATERIALIZED t2 index b b 5 NULL 20 Using index select * from t1; a b 1 1 @@ -890,9 +892,9 @@ SELECT * FROM t3 LEFT JOIN (v1,t2) ON t3.a = t2.a WHERE t3.b IN (SELECT b FROM t4); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 1 +1 PRIMARY eq_ref distinct_key distinct_key 5 func 1 1 PRIMARY t2 hash_ALL NULL #hash#$hj 5 test.t3.a 1 Using where; Using join buffer (flat, BNLH join) 1 PRIMARY ALL NULL NULL NULL NULL 2 Using join buffer (incremental, BNL join) -1 PRIMARY eq_ref distinct_key distinct_key 5 func 1 2 MATERIALIZED t4 ALL NULL NULL NULL NULL 2 3 DERIVED t1 ALL NULL NULL NULL NULL 1 SELECT * FROM t3 LEFT JOIN (v1,t2) ON t3.a = t2.a @@ -973,7 +975,8 @@ EXPLAIN SELECT * FROM t1 WHERE b IN (SELECT a FROM t2 GROUP BY a); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 1 -1 PRIMARY t2 ALL NULL NULL NULL NULL 1 Using where; FirstMatch(t1); Using join buffer (flat, BNL join) +1 PRIMARY eq_ref distinct_key distinct_key 5 func 1 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 1 SELECT * FROM t1 WHERE b IN (SELECT a FROM t2 GROUP BY a); a b v v diff --git a/mysql-test/r/subselect_sj2_mat.result b/mysql-test/r/subselect_sj2_mat.result index 5a9c3b90755..252f3c73a55 100644 --- a/mysql-test/r/subselect_sj2_mat.result +++ b/mysql-test/r/subselect_sj2_mat.result @@ -71,9 +71,9 @@ insert into t3 select a,a, a,a,a from t0; insert into t3 select a,a, a+100,a+100,a+100 from t0; explain select * from t3 where b in (select a from t1); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t3 ALL b NULL NULL NULL 20 -1 PRIMARY eq_ref distinct_key distinct_key 5 func 1 -2 MATERIALIZED t1 ALL NULL NULL NULL NULL 3 +1 PRIMARY ALL distinct_key NULL NULL NULL 3 +1 PRIMARY t3 ref b b 5 test.t1.a 1 +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 3 Using where select * from t3 where b in (select a from t1); a b pk1 pk2 pk3 1 1 1 1 1 @@ -880,9 +880,9 @@ SELECT * FROM t3 LEFT JOIN (v1,t2) ON t3.a = t2.a WHERE t3.b IN (SELECT b FROM t4); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 1 +1 PRIMARY eq_ref distinct_key distinct_key 5 func 1 1 PRIMARY t2 ALL NULL NULL NULL NULL 1 Using where 1 PRIMARY ALL NULL NULL NULL NULL 2 -1 PRIMARY eq_ref distinct_key distinct_key 5 func 1 2 MATERIALIZED t4 ALL NULL NULL NULL NULL 2 3 DERIVED t1 ALL NULL NULL NULL NULL 1 SELECT * FROM t3 LEFT JOIN (v1,t2) ON t3.a = t2.a diff --git a/mysql-test/r/subselect_sj_jcl6.result b/mysql-test/r/subselect_sj_jcl6.result index b5c79ac153c..2df7d99ee64 100644 --- a/mysql-test/r/subselect_sj_jcl6.result +++ b/mysql-test/r/subselect_sj_jcl6.result @@ -983,10 +983,11 @@ SELECT `varchar_key` , `varchar_nokey` FROM t1 WHERE `varchar_nokey` < 'n' XOR `pk` ) ; id select_type table type possible_keys key key_len ref rows filtered Extra -1 PRIMARY t2 ALL NULL NULL NULL NULL 18 100.00 -1 PRIMARY t1 ref varchar_key varchar_key 3 test.t2.varchar_nokey 2 100.00 Using where; FirstMatch(t2); Using join buffer (flat, BKA join); Key-ordered Rowid-ordered scan +1 PRIMARY ALL distinct_key NULL NULL NULL 15 100.00 +1 PRIMARY t2 ALL NULL NULL NULL NULL 18 100.00 Using where; Using join buffer (flat, BNL join) +2 MATERIALIZED t1 ALL varchar_key NULL NULL NULL 15 100.00 Using where Warnings: -Note 1003 select `test`.`t2`.`varchar_nokey` AS `varchar_nokey` from `test`.`t2` semi join (`test`.`t1`) where ((`test`.`t1`.`varchar_key` = `test`.`t2`.`varchar_nokey`) and (`test`.`t1`.`varchar_nokey` = `test`.`t2`.`varchar_nokey`) and ((`test`.`t2`.`varchar_nokey` < 'n') xor `test`.`t1`.`pk`)) +Note 1003 select `test`.`t2`.`varchar_nokey` AS `varchar_nokey` from `test`.`t2` semi join (`test`.`t1`) where ((`test`.`t1`.`varchar_nokey` = `test`.`t1`.`varchar_key`) and (`test`.`t2`.`varchar_nokey` = `test`.`t1`.`varchar_key`) and ((`test`.`t1`.`varchar_key` < 'n') xor `test`.`t1`.`pk`)) SELECT varchar_nokey FROM t2 WHERE ( `varchar_nokey` , `varchar_nokey` ) IN ( @@ -1065,8 +1066,10 @@ AND t1.val IN (SELECT t3.val FROM t3 WHERE t3.val LIKE 'a%' OR t3.val LIKE 'e%'); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 5 -1 PRIMARY t3 ALL NULL NULL NULL NULL 5 Using where; FirstMatch(t1); Using join buffer (flat, BNL join) -1 PRIMARY t2 ALL NULL NULL NULL NULL 6 Using where; FirstMatch(t3); Using join buffer (incremental, BNL join) +1 PRIMARY eq_ref distinct_key distinct_key 14 func 1 +1 PRIMARY eq_ref distinct_key distinct_key 14 func 1 +3 MATERIALIZED t3 ALL NULL NULL NULL NULL 5 Using where +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 6 Using where SELECT * FROM t1 WHERE t1.val IN (SELECT t2.val FROM t2 @@ -1285,9 +1288,11 @@ select * from t1 A, t1 B where A.a = B.a and A.a in (select a from t2 C) and B.a in (select a from t2 D); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY A ALL NULL NULL NULL NULL 3 +1 PRIMARY eq_ref distinct_key distinct_key 5 func 1 1 PRIMARY B ALL NULL NULL NULL NULL 3 Using where; Using join buffer (flat, BNL join) -1 PRIMARY C ALL NULL NULL NULL NULL 3 Using where; FirstMatch(B); Using join buffer (incremental, BNL join) -1 PRIMARY D ALL NULL NULL NULL NULL 3 Using where; FirstMatch(C); Using join buffer (incremental, BNL join) +1 PRIMARY eq_ref distinct_key distinct_key 5 func 1 +2 MATERIALIZED C ALL NULL NULL NULL NULL 3 +3 MATERIALIZED D ALL NULL NULL NULL NULL 3 drop table t1, t2; # # BUG#784441: Abort on semijoin with a view as the inner table @@ -1629,12 +1634,13 @@ CREATE VIEW v4 AS SELECT DISTINCT f2 FROM t4 ; explain extended SELECT * FROM t1 NATURAL LEFT JOIN (t2, t3) WHERE t2.f3 IN (SELECT * FROM t4); id select_type table type possible_keys key key_len ref rows filtered Extra -1 PRIMARY t2 ALL NULL NULL NULL NULL 2 100.00 Using where -1 PRIMARY t4 ref f2 f2 5 test.t2.f3 2 100.00 Using index; FirstMatch(t2) +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 100.00 +1 PRIMARY eq_ref distinct_key distinct_key 5 func 1 100.00 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (flat, BNL join) 1 PRIMARY t3 ALL NULL NULL NULL NULL 5 100.00 Using where; Using join buffer (incremental, BNL join) +2 MATERIALIZED t4 index f2 f2 5 NULL 2 100.00 Using index Warnings: -Note 1003 select `test`.`t1`.`f1` AS `f1`,`test`.`t1`.`f2` AS `f2`,`test`.`t2`.`f3` AS `f3`,`test`.`t3`.`f3` AS `f3` from `test`.`t1` semi join (`test`.`t4`) join `test`.`t2` join `test`.`t3` where ((`test`.`t1`.`f2` = `test`.`t2`.`f2`) and (`test`.`t3`.`f1` = `test`.`t1`.`f1`) and (`test`.`t4`.`f2` = `test`.`t2`.`f3`)) +Note 1003 select `test`.`t1`.`f1` AS `f1`,`test`.`t1`.`f2` AS `f2`,`test`.`t2`.`f3` AS `f3`,`test`.`t3`.`f3` AS `f3` from `test`.`t1` semi join (`test`.`t4`) join `test`.`t2` join `test`.`t3` where ((`test`.`t1`.`f2` = `test`.`t2`.`f2`) and (`test`.`t3`.`f1` = `test`.`t1`.`f1`)) SELECT * FROM t1 NATURAL LEFT JOIN (t2, t3) WHERE t2.f3 IN (SELECT * FROM t4); f1 f2 f3 f3 2 0 0 0 @@ -1946,45 +1952,18 @@ DROP TABLE t1, t2, t4, t5; # # BUG#861147: Assertion `fixed == 1' failed in Item_func_eq::val_int() with semijoin + materialization + max_join_size # -CREATE TABLE t1 ( f2 int) ; -CREATE TABLE t2 ( f1 int, f3 int, f4 varchar(3), f5 varchar(35)) ; -INSERT INTO t2 VALUES (4057,9,'USA','Visalia'),(3993,11,'USA','Waco'), -(3948,14,'USA','Warren'),(3813,57,'USA','Washington'), -(4010,11,'USA','Waterbury'),(4017,11,'USA','West Covina'), -(4004,11,'USA','West Valley City'),(4033,10,'USA','Westminster'), -(3842,34,'USA','Wichita'),(4018,10,'USA','Wichita Falls'), -(3899,19,'USA','Winston-Salem'),(3914,17,'USA','Worcester'), -(3888,20,'USA','Yonkers'); -CREATE TABLE t3 ( f3 int, f4 varchar(3)) ; -INSERT INTO t3 VALUES (86,'USA'); -CREATE TABLE t4 ( f3 int, f4 varchar(3), f5 varchar(52)) ; -INSERT INTO t4 VALUES (0,'RUS','Belorussian'),(0,'USA','Portuguese'); -CREATE TABLE t5 ( f2 int) ; -CREATE TABLE t6 ( f4 varchar(3)); -INSERT INTO t6 VALUES ('RUS'),('USA'); +create table t1 (a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); set @tmp_mjs_861147= @@max_join_size; SET max_join_size=10; set @tmp_os_861147= @@optimizer_switch; set @@optimizer_switch='semijoin=on,materialization=on'; -SELECT * -FROM t1 -WHERE ( 1 , 3 ) IN ( -SELECT t2.f1 , MAX( t3.f3 ) -FROM t2 -JOIN t3 -WHERE t3.f4 IN ( -SELECT t4.f5 -FROM t4 -STRAIGHT_JOIN t5 -WHERE t4.f4 < t2.f5 -) -) AND ( 'p' , 'k' ) IN ( -SELECT f4 , f4 FROM t6 -); +explain +select * from t1 where a in (select max(A.a + B.a + C.a) from t1 A, t1 B, t1 C); ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET MAX_JOIN_SIZE=# if the SELECT is okay set max_join_size= @tmp_mjs_861147; set optimizer_switch= @tmp_os_861147; -DROP TABLE t1,t2,t3,t4,t5,t6; +drop table t1; # # BUG#877288: Wrong result with semijoin + materialization + multipart key # diff --git a/mysql-test/suite/pbxt/r/greedy_optimizer.result b/mysql-test/suite/pbxt/r/greedy_optimizer.result index 7b46f4275b0..6297b51328a 100644 --- a/mysql-test/suite/pbxt/r/greedy_optimizer.result +++ b/mysql-test/suite/pbxt/r/greedy_optimizer.result @@ -202,28 +202,28 @@ select @@optimizer_search_depth; 0 explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 3 -1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where 1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1 1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1 1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 822.625316 +Last_query_cost 1372.225316 explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 3 -1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where 1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1 1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1 1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 822.625316 +Last_query_cost 1372.225316 explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where @@ -231,11 +231,11 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.c21 1 Using where 1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index 1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index -1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 290.146368 +Last_query_cost 363.346368 explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where @@ -243,11 +243,11 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.c21 1 Using where 1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index 1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index -1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 290.146368 +Last_query_cost 363.346368 explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where @@ -255,11 +255,11 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.c21 1 Using where 1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using where 1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where -1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 290.146368 +Last_query_cost 363.346368 explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where @@ -267,11 +267,11 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.c21 1 Using where 1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using where 1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where -1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 290.146368 +Last_query_cost 363.346368 set optimizer_search_depth=1; select @@optimizer_search_depth; @@optimizer_search_depth @@ -287,7 +287,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 822.625316 +Last_query_cost 1694.425316 explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 3 @@ -299,7 +299,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 822.625316 +Last_query_cost 1694.425316 explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 Using where @@ -311,7 +311,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 795.625316 +Last_query_cost 844.825316 explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 Using where @@ -323,7 +323,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 795.625316 +Last_query_cost 844.825316 explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 Using where @@ -335,7 +335,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 795.625316 +Last_query_cost 844.825316 explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 Using where @@ -347,35 +347,35 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 795.625316 +Last_query_cost 844.825316 set optimizer_search_depth=62; select @@optimizer_search_depth; @@optimizer_search_depth 62 explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 3 -1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where 1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1 1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1 1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 822.625316 +Last_query_cost 1372.225316 explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 3 -1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where 1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1 1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1 1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 822.625316 +Last_query_cost 1372.225316 explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where @@ -383,11 +383,11 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.c21 1 Using where 1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index 1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index -1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 290.146368 +Last_query_cost 363.346368 explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where @@ -395,11 +395,11 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.c21 1 Using where 1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index 1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index -1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 290.146368 +Last_query_cost 363.346368 explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where @@ -407,11 +407,11 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.c21 1 Using where 1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using where 1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where -1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 290.146368 +Last_query_cost 363.346368 explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where @@ -419,11 +419,11 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.c21 1 Using where 1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using where 1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where -1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 290.146368 +Last_query_cost 363.346368 set optimizer_prune_level=1; select @@optimizer_prune_level; @@optimizer_prune_level @@ -443,7 +443,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 822.625316 +Last_query_cost 1694.425316 explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 3 @@ -455,55 +455,55 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 822.625316 +Last_query_cost 1694.425316 explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 Using where -1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index -1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index -1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 795.625316 +Last_query_cost 844.825316 explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 Using where -1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index -1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index -1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 795.625316 +Last_query_cost 844.825316 explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 Using where -1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join) -1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using where -1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where -1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 795.625316 +Last_query_cost 844.825316 explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 Using where -1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join) -1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using where -1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where -1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 795.625316 +Last_query_cost 844.825316 set optimizer_search_depth=1; select @@optimizer_search_depth; @@optimizer_search_depth @@ -519,7 +519,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 822.625316 +Last_query_cost 1694.425316 explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 3 @@ -531,7 +531,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 822.625316 +Last_query_cost 1694.425316 explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 Using where @@ -543,7 +543,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 795.625316 +Last_query_cost 844.825316 explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 Using where @@ -555,7 +555,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 795.625316 +Last_query_cost 844.825316 explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 Using where @@ -567,7 +567,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 795.625316 +Last_query_cost 844.825316 explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 Using where @@ -579,7 +579,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 795.625316 +Last_query_cost 844.825316 set optimizer_search_depth=62; select @@optimizer_search_depth; @@optimizer_search_depth @@ -595,7 +595,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 822.625316 +Last_query_cost 1694.425316 explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 3 @@ -607,54 +607,54 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 822.625316 +Last_query_cost 1694.425316 explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 Using where -1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index -1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index -1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 795.625316 +Last_query_cost 844.825316 explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 Using where -1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index -1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index -1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 795.625316 +Last_query_cost 844.825316 explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 Using where -1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join) -1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using where -1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where -1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 795.625316 +Last_query_cost 844.825316 explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 Using where -1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join) -1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using where -1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where -1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 795.625316 +Last_query_cost 844.825316 drop table t1,t2,t3,t4,t5,t6,t7; set join_cache_level=@save_join_cache_level; diff --git a/mysql-test/suite/pbxt/r/join.result b/mysql-test/suite/pbxt/r/join.result index 5035f5da9bd..3a1759a18f4 100644 --- a/mysql-test/suite/pbxt/r/join.result +++ b/mysql-test/suite/pbxt/r/join.result @@ -801,7 +801,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE B eq_ref PRIMARY PRIMARY 4 test.A.b 1 show status like '%cost%'; Variable_name Value -Last_query_cost 24.262158 +Last_query_cost 28.262158 select '^^: The above should be ~= 20 + cost(select * from t1). Value less than 20 is an error' Z; Z ^^: The above should be ~= 20 + cost(select * from t1). Value less than 20 is an error diff --git a/mysql-test/suite/pbxt/r/select.result b/mysql-test/suite/pbxt/r/select.result index 869df25504a..58a1a326f6b 100644 --- a/mysql-test/suite/pbxt/r/select.result +++ b/mysql-test/suite/pbxt/r/select.result @@ -2204,10 +2204,10 @@ a a select * from (t1 as t2 left join t1 as t3 using (a)) inner join t1 on t1.a>1; a a 1 2 -2 2 -3 2 1 3 +2 2 2 3 +3 2 3 3 select * from t1 inner join (t1 as t2 left join t1 as t3 using (a)) on t1.a>1; a a diff --git a/mysql-test/suite/pbxt/r/subselect.result b/mysql-test/suite/pbxt/r/subselect.result index cc513a1444d..0a065e61edf 100644 --- a/mysql-test/suite/pbxt/r/subselect.result +++ b/mysql-test/suite/pbxt/r/subselect.result @@ -1366,8 +1366,8 @@ a explain extended select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 index a a 5 NULL 4 100.00 Using where; Using index -1 PRIMARY t1 ref a a 5 test.t2.a 1 100.00 Using index; Start temporary -1 PRIMARY t3 index a a 5 NULL 3 100.00 Using where; Using index; End temporary +1 PRIMARY t1 ref a a 5 test.t2.a 1 100.00 Using where; Using index +1 PRIMARY t3 ref a a 5 test.t1.b 1 100.00 Using index; FirstMatch(t2) Warnings: Note 1003 select `test`.`t2`.`a` AS `a` from `test`.`t2` semi join (`test`.`t1` join `test`.`t3`) where ((`test`.`t1`.`a` = `test`.`t2`.`a`) and (`test`.`t3`.`a` = `test`.`t1`.`b`)) insert into t1 values (3,31); @@ -4225,6 +4225,9 @@ LEFT(t1.a1,1) SELECT a2 FROM t2 WHERE t2.a2 IN (SELECT t1.a1 FROM t1,t3 WHERE t1.b1=t3.a3); a2 DROP TABLE t1, t2, t3; +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='semijoin_with_cache=off'; +SET optimizer_switch='materialization=off'; CREATE TABLE t1 (a CHAR(1), b VARCHAR(10)); INSERT INTO t1 VALUES ('a', 'aa'); INSERT INTO t1 VALUES ('a', 'aaa'); @@ -4256,6 +4259,7 @@ id select_type table type possible_keys key key_len ref rows Extra SELECT a,b FROM t1 WHERE b IN (SELECT a FROM t1 WHERE LENGTH(a)<500); a b DROP TABLE t1,t2; +SET optimizer_switch= @save_optimizer_switch; CREATE TABLE t1(a INT, b INT); INSERT INTO t1 VALUES (1,1), (1,2), (2,3), (2,4); EXPLAIN diff --git a/mysql-test/suite/pbxt/t/subselect.test b/mysql-test/suite/pbxt/t/subselect.test index 5f0835e0b03..aae7ff2d5f5 100644 --- a/mysql-test/suite/pbxt/t/subselect.test +++ b/mysql-test/suite/pbxt/t/subselect.test @@ -3099,6 +3099,10 @@ DROP TABLE t1, t2, t3; # Bug #30788: Inconsistent retrieval of char/varchar # +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='semijoin_with_cache=off'; +SET optimizer_switch='materialization=off'; + CREATE TABLE t1 (a CHAR(1), b VARCHAR(10)); INSERT INTO t1 VALUES ('a', 'aa'); INSERT INTO t1 VALUES ('a', 'aaa'); @@ -3120,6 +3124,7 @@ SELECT a,b FROM t1 WHERE b IN (SELECT a FROM t1 WHERE LENGTH(a)<500); DROP TABLE t1,t2; +SET optimizer_switch= @save_optimizer_switch; # # Bug #32400: Complex SELECT query returns correct result only on some diff --git a/mysql-test/t/derived_view.test b/mysql-test/t/derived_view.test index 581d01058db..b674350af0a 100644 --- a/mysql-test/t/derived_view.test +++ b/mysql-test/t/derived_view.test @@ -1036,6 +1036,7 @@ CREATE TABLE t3 ( b int NOT NULL, e varchar(1) NOT NULL, d varchar(1) NOT NULL, KEY (e,b) ); INSERT INTO t3 VALUES (4,'x','x'),(9,'w','w'),(4,'d','d'),(8,'e','e'); +INSERT INTO t3 VALUES (14,'a','a'),(19,'b','b'),(14,'c','c'),(18,'d','d'); CREATE TABLE t4 (i int NOT NULL, m varchar(1) NOT NULL) ; INSERT INTO t4 VALUES (8,'m'),(9,'d'),(2,'s'),(4,'r'),(8,'m'); diff --git a/mysql-test/t/explain.test b/mysql-test/t/explain.test index d07f36b37a4..3e585656ba9 100644 --- a/mysql-test/t/explain.test +++ b/mysql-test/t/explain.test @@ -180,8 +180,8 @@ create table t2 (dt datetime not null); insert into t1 values ('2001-01-01 1:1:1', '1:1:1'), ('2001-01-01 1:1:1', '1:1:1'); insert into t2 values ('2001-01-01 1:1:1'), ('2001-01-01 1:1:1'); -SET @save_optimizer_switch=@@optimizer_switch; -SET optimizer_switch='semijoin_with_cache=off'; +SET @save_join_cache_level=@@join_cache_level; +SET join_cache_level=0; flush tables; EXPLAIN SELECT OUTR.dt FROM t1 AS OUTR WHERE OUTR.dt IN (SELECT INNR.dt FROM t2 AS INNR WHERE OUTR.dt IS NULL ); flush tables; @@ -190,7 +190,7 @@ flush tables; EXPLAIN SELECT OUTR.dt FROM t1 AS OUTR WHERE OUTR.dt IN ( SELECT INNR.dt FROM t2 AS INNR WHERE OUTR.t < '2005-11-13 7:41:31' ); flush tables; SELECT OUTR.dt FROM t1 AS OUTR WHERE OUTR.dt IN ( SELECT INNR.dt FROM t2 AS INNR WHERE OUTR.t < '2005-11-13 7:41:31' ); -SET optimizer_switch=@save_optimizer_switch; +SET join_cache_level=@save_join_cache_level; drop tables t1, t2; --echo # diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 2540232bd3b..9d87cbc486c 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -3248,6 +3248,10 @@ DROP TABLE t1, t2, t3; # Bug#30788 Inconsistent retrieval of char/varchar # +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='semijoin_with_cache=off'; +SET optimizer_switch='materialization=off'; + CREATE TABLE t1 (a CHAR(1), b VARCHAR(10)); INSERT INTO t1 VALUES ('a', 'aa'); INSERT INTO t1 VALUES ('a', 'aaa'); @@ -3269,6 +3273,7 @@ SELECT a,b FROM t1 WHERE b IN (SELECT a FROM t1 WHERE LENGTH(a)<500); DROP TABLE t1,t2; +SET optimizer_switch= @save_optimizer_switch; # # Bug#32400 Complex SELECT query returns correct result only on some occasions @@ -3418,8 +3423,11 @@ drop table t1, t2; CREATE TABLE t1 (a INT); INSERT INTO t1 VALUES (1),(2); +SET @save_join_cache_level=@@join_cache_level; +SET join_cache_level=0; EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1 IN (SELECT min(a) FROM t1 GROUP BY a); EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1 IN (SELECT min(a) FROM t1 WHERE a > 3 GROUP BY a); +SET join_cache_level=@save_join_cache_level; DROP TABLE t1; --echo # @@ -4430,8 +4438,12 @@ INSERT INTO t2 VALUES (11,1); INSERT INTO t2 VALUES (12,2); INSERT INTO t2 VALUES (15,4); + +SET @save_join_cache_level=@@join_cache_level; +SET join_cache_level=0; EXPLAIN SELECT * FROM t1 WHERE pk IN (SELECT it.pk FROM t2 JOIN t2 AS it ON 1); SELECT * FROM t1 WHERE pk IN (SELECT it.pk FROM t2 JOIN t2 AS it ON 1); +SET join_cache_level=@save_join_cache_level; DROP table t1,t2; diff --git a/mysql-test/t/subselect4.test b/mysql-test/t/subselect4.test index 0e51373fb01..b2e15c457d7 100644 --- a/mysql-test/t/subselect4.test +++ b/mysql-test/t/subselect4.test @@ -993,13 +993,16 @@ INSERT INTO t4 VALUES ('k'), ('d'); SET @save_optimizer_switch=@@optimizer_switch; SET optimizer_switch='outer_join_with_cache=off'; +SET optimizer_switch='semijoin_with_cache=off'; +SET optimizer_switch='materialization=off'; EXPLAIN SELECT * FROM t1 RIGHT JOIN t2 ON t1.c1 WHERE 's' IN (SELECT c1 FROM t2); SELECT * FROM t1 RIGHT JOIN t2 ON t1.c1 WHERE 's' IN (SELECT c1 FROM t2); EXPLAIN SELECT * FROM t2 LEFT JOIN t1 ON t1.c1 WHERE 's' IN (SELECT c1 FROM t2); SELECT * FROM t2 LEFT JOIN t1 ON t1.c1 WHERE 's' IN (SELECT c1 FROM t2); +SET optimizer_switch='materialization=on'; EXPLAIN SELECT * FROM (t2 LEFT JOIN t1 ON t1.c1) LEFT JOIN t3 on t3.c1 WHERE 's' IN (SELECT c1 FROM t2); SELECT * FROM (t2 LEFT JOIN t1 ON t1.c1) LEFT JOIN t3 on t3.c1 WHERE 's' IN (SELECT c1 FROM t2); diff --git a/mysql-test/t/subselect_sj.test b/mysql-test/t/subselect_sj.test index 2b64de47439..aee61e9bca3 100644 --- a/mysql-test/t/subselect_sj.test +++ b/mysql-test/t/subselect_sj.test @@ -1777,52 +1777,43 @@ DROP TABLE t1, t2, t4, t5; --echo # --echo # BUG#861147: Assertion `fixed == 1' failed in Item_func_eq::val_int() with semijoin + materialization + max_join_size --echo # -CREATE TABLE t1 ( f2 int) ; -CREATE TABLE t2 ( f1 int, f3 int, f4 varchar(3), f5 varchar(35)) ; -INSERT INTO t2 VALUES (4057,9,'USA','Visalia'),(3993,11,'USA','Waco'), - (3948,14,'USA','Warren'),(3813,57,'USA','Washington'), - (4010,11,'USA','Waterbury'),(4017,11,'USA','West Covina'), - (4004,11,'USA','West Valley City'),(4033,10,'USA','Westminster'), - (3842,34,'USA','Wichita'),(4018,10,'USA','Wichita Falls'), - (3899,19,'USA','Winston-Salem'),(3914,17,'USA','Worcester'), - (3888,20,'USA','Yonkers'); +#CREATE TABLE t1 ( f2 int) ; +#CREATE TABLE t2 ( f1 int, f3 int, f4 varchar(3), f5 varchar(35)) ; +#INSERT INTO t2 VALUES (4057,9,'USA','Visalia'),(3993,11,'USA','Waco'), +# (3948,14,'USA','Warren'),(3813,57,'USA','Washington'), +# (4010,11,'USA','Waterbury'),(4017,11,'USA','West Covina'), +# (4004,11,'USA','West Valley City'),(4033,10,'USA','Westminster'), +# (3842,34,'USA','Wichita'),(4018,10,'USA','Wichita Falls'), +# (3899,19,'USA','Winston-Salem'),(3914,17,'USA','Worcester'), +# (3888,20,'USA','Yonkers'); -CREATE TABLE t3 ( f3 int, f4 varchar(3)) ; -INSERT INTO t3 VALUES (86,'USA'); +#CREATE TABLE t3 ( f3 int, f4 varchar(3)) ; +#INSERT INTO t3 VALUES (86,'USA'); -CREATE TABLE t4 ( f3 int, f4 varchar(3), f5 varchar(52)) ; -INSERT INTO t4 VALUES (0,'RUS','Belorussian'),(0,'USA','Portuguese'); +#CREATE TABLE t4 ( f3 int, f4 varchar(3), f5 varchar(52)) ; +#INSERT INTO t4 VALUES (0,'RUS','Belorussian'),(0,'USA','Portuguese'); -CREATE TABLE t5 ( f2 int) ; +#CREATE TABLE t5 ( f2 int) ; -CREATE TABLE t6 ( f4 varchar(3)); -INSERT INTO t6 VALUES ('RUS'),('USA'); +#CREATE TABLE t6 ( f4 varchar(3)); +#INSERT INTO t6 VALUES ('RUS'),('USA'); +create table t1 (a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); set @tmp_mjs_861147= @@max_join_size; SET max_join_size=10; set @tmp_os_861147= @@optimizer_switch; set @@optimizer_switch='semijoin=on,materialization=on'; --error ER_TOO_BIG_SELECT -SELECT * -FROM t1 -WHERE ( 1 , 3 ) IN ( - SELECT t2.f1 , MAX( t3.f3 ) - FROM t2 - JOIN t3 - WHERE t3.f4 IN ( - SELECT t4.f5 - FROM t4 - STRAIGHT_JOIN t5 - WHERE t4.f4 < t2.f5 - ) -) AND ( 'p' , 'k' ) IN ( - SELECT f4 , f4 FROM t6 -); +explain +select * from t1 where a in (select max(A.a + B.a + C.a) from t1 A, t1 B, t1 C); + set max_join_size= @tmp_mjs_861147; set optimizer_switch= @tmp_os_861147; -DROP TABLE t1,t2,t3,t4,t5,t6; +#DROP TABLE t1,t2,t3,t4,t5,t6; +drop table t1; --echo # --echo # BUG#877288: Wrong result with semijoin + materialization + multipart key diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index 3aa5a188a26..d06480391be 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -2738,10 +2738,12 @@ bool Duplicate_weedout_picker::check_qep(JOIN *join, } table_map dups_removed_fanout= 0; + double current_fanout= prefix_rec_count; for (uint j= first_dupsweedout_table; j <= idx; j++) { POSITION *p= join->positions + j; - dups_cost += p->read_time; + current_fanout *= p->records_read; + dups_cost += p->read_time + current_fanout / TIME_FOR_COMPARE; if (p->table->emb_sj_nest) { sj_inner_fanout *= p->records_read; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 9ad945a22b3..cb620495897 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -5020,6 +5020,8 @@ best_access_path(JOIN *join, MY_BITMAP *eq_join_set= &s->table->eq_join_set; KEYUSE *hj_start_key= 0; + disable_jbuf= disable_jbuf || idx == join->const_tables; + Loose_scan_opt loose_scan_opt; DBUG_ENTER("best_access_path"); @@ -5880,7 +5882,8 @@ optimize_straight_join(JOIN *join, table_map join_tables) /* compute the cost of the new plan extended with 's' */ record_count*= join->positions[idx].records_read; - read_time+= join->positions[idx].read_time; + read_time+= join->positions[idx].read_time + + record_count / (double) TIME_FOR_COMPARE; advance_sj_state(join, join_tables, idx, &record_count, &read_time, &loose_scan_pos); @@ -5888,14 +5891,13 @@ optimize_straight_join(JOIN *join, table_map join_tables) ++idx; } - read_time+= record_count / (double) TIME_FOR_COMPARE; if (join->sort_by_table && join->sort_by_table != join->positions[join->const_tables].table->table) read_time+= record_count; // We have to make a temp table memcpy((uchar*) join->best_positions, (uchar*) join->positions, sizeof(POSITION)*idx); join->record_count= record_count; - join->best_read= read_time; + join->best_read= read_time - 0.001; } @@ -6063,7 +6065,8 @@ greedy_search(JOIN *join, /* compute the cost of the new plan extended with 'best_table' */ record_count*= join->positions[idx].records_read; - read_time+= join->positions[idx].read_time; + read_time+= join->positions[idx].read_time + + record_count / (double) TIME_FOR_COMPARE; remaining_tables&= ~(best_table->table->map); --size_remain; @@ -6171,7 +6174,7 @@ void JOIN::get_partial_cost_and_fanout(int end_tab_idx, if (tab->records_read && (cur_table_map & filter_map)) { record_count *= tab->records_read; - read_time += tab->read_time; + read_time += tab->read_time + record_count / (double) TIME_FOR_COMPARE; if (tab->emb_sj_nest) sj_inner_fanout *= tab->records_read; } @@ -6395,21 +6398,19 @@ best_extension_by_limited_search(JOIN *join, /* Compute the cost of extending the plan with 's' */ current_record_count= record_count * position->records_read; - current_read_time= read_time + position->read_time; + current_read_time=read_time + position->read_time + + current_record_count / (double) TIME_FOR_COMPARE; advance_sj_state(join, remaining_tables, idx, ¤t_record_count, ¤t_read_time, &loose_scan_pos); /* Expand only partial plans with lower cost than the best QEP so far */ - if ((current_read_time + - current_record_count / (double) TIME_FOR_COMPARE) >= join->best_read) + if (current_read_time >= join->best_read) { DBUG_EXECUTE("opt", print_plan(join, idx+1, current_record_count, read_time, - (current_read_time + - current_record_count / - (double) TIME_FOR_COMPARE), + current_read_time, "prune_by_cost");); restore_prev_nj_state(s); restore_prev_sj_state(remaining_tables, s, idx); @@ -6468,13 +6469,12 @@ best_extension_by_limited_search(JOIN *join, 'join' is either the best partial QEP with 'search_depth' relations, or the best complete QEP so far, whichever is smaller. */ - current_read_time+= current_record_count / (double) TIME_FOR_COMPARE; if (join->sort_by_table && join->sort_by_table != join->positions[join->const_tables].table->table) /* We have to make a temp table */ current_read_time+= current_record_count; - if ((search_depth == 1) || (current_read_time < join->best_read)) + if (current_read_time < join->best_read) { memcpy((uchar*) join->best_positions, (uchar*) join->positions, sizeof(POSITION) * (idx + 1)); From c583aaf56ba14484745e7a38bcc07b8652e516d4 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Sun, 25 Dec 2011 18:03:03 -0800 Subject: [PATCH 246/288] Changed a test case from join_cache.test to make it platform independent. --- mysql-test/r/join_cache.result | 7 +------ mysql-test/t/join_cache.test | 5 ----- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/mysql-test/r/join_cache.result b/mysql-test/r/join_cache.result index 2fc8cc83821..362158cfdbe 100644 --- a/mysql-test/r/join_cache.result +++ b/mysql-test/r/join_cache.result @@ -4400,17 +4400,12 @@ INSERT INTO t2 VALUES (1, 12, 102), (8, 81, 801), (7, 70, 700), (12, 120, 1200), (8, 82, 802), (1, 13, 103), (1, 14, 104), (3, 31, 301), (1, 15, 105), (8, 83, 803), (7, 71, 701); -INSERT INTO t2 VALUES -(108, 80, 800), (101, 10, 100), (101, 11, 101), (103, 30, 300), -(101, 12, 102), (108, 81, 801), (107, 70, 700), (1012, 120, 1200), -(108, 82, 802), (101, 13, 103), (101, 14, 104), (103, 31, 301), -(101, 15, 105), (108, 83, 803), (107, 71, 701); SET SESSION join_cache_level = 4; SET SESSION join_buffer_size = 192; EXPLAIN SELECT t1.a, t2.c FROM t1,t2 WHERE t1.a=t2.a AND t2.b=99; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 ALL idx NULL NULL NULL 30 Using where +1 SIMPLE t2 ALL idx NULL NULL NULL 15 Using where 1 SIMPLE t1 hash_ALL NULL #hash#$hj 5 test.t2.a 36 Using where; Using join buffer (flat, BNLH join) SELECT t1.a, t2.c FROM t1,t2 WHERE t1.a=t2.a AND t2.b=99; a c diff --git a/mysql-test/t/join_cache.test b/mysql-test/t/join_cache.test index 0feb4e30af0..e39dcb72916 100644 --- a/mysql-test/t/join_cache.test +++ b/mysql-test/t/join_cache.test @@ -2581,11 +2581,6 @@ INSERT INTO t2 VALUES (1, 12, 102), (8, 81, 801), (7, 70, 700), (12, 120, 1200), (8, 82, 802), (1, 13, 103), (1, 14, 104), (3, 31, 301), (1, 15, 105), (8, 83, 803), (7, 71, 701); -INSERT INTO t2 VALUES - (108, 80, 800), (101, 10, 100), (101, 11, 101), (103, 30, 300), - (101, 12, 102), (108, 81, 801), (107, 70, 700), (1012, 120, 1200), - (108, 82, 802), (101, 13, 103), (101, 14, 104), (103, 31, 301), - (101, 15, 105), (108, 83, 803), (107, 71, 701); SET SESSION join_cache_level = 4; SET SESSION join_buffer_size = 192; From dcd0058723e3b0d9d2222ac414ffdc6bd3518be3 Mon Sep 17 00:00:00 2001 From: Rohit Kalhans Date: Mon, 26 Dec 2011 22:40:56 +0530 Subject: [PATCH 247/288] rpl.rpl_known_bugs_detection fails on PB2 daily mysql-5.5. The rpl.rpl_known_bugs_detection fails on pb2 as warnings were found in the mysqld log file. We fix this problem by suppressing the warning. --- mysql-test/suite/rpl/r/rpl_known_bugs_detection.result | 1 + mysql-test/suite/rpl/t/rpl_known_bugs_detection.test | 2 ++ 2 files changed, 3 insertions(+) diff --git a/mysql-test/suite/rpl/r/rpl_known_bugs_detection.result b/mysql-test/suite/rpl/r/rpl_known_bugs_detection.result index 92ccc78aaca..8ed402b9f8d 100644 --- a/mysql-test/suite/rpl/r/rpl_known_bugs_detection.result +++ b/mysql-test/suite/rpl/r/rpl_known_bugs_detection.result @@ -1,5 +1,6 @@ include/master-slave.inc [connection master] +call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT."); CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY AUTO_INCREMENT, b INT, UNIQUE(b)); INSERT INTO t1(b) VALUES(1),(1),(2) ON DUPLICATE KEY UPDATE t1.b=10; diff --git a/mysql-test/suite/rpl/t/rpl_known_bugs_detection.test b/mysql-test/suite/rpl/t/rpl_known_bugs_detection.test index 99871b695a6..a713691ec2d 100644 --- a/mysql-test/suite/rpl/t/rpl_known_bugs_detection.test +++ b/mysql-test/suite/rpl/t/rpl_known_bugs_detection.test @@ -6,6 +6,8 @@ source include/have_debug.inc; source include/master-slave.inc; +call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT."); + # Currently only statement-based-specific bugs are here -- source include/have_binlog_format_statement.inc From 3759df08ebb51c4af8afa961215407d71fe58ae5 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Wed, 28 Dec 2011 12:12:48 +0400 Subject: [PATCH 248/288] Update test results. --- mysql-test/r/fulltext_order_by.result | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/r/fulltext_order_by.result b/mysql-test/r/fulltext_order_by.result index 58ed6aac6f9..2085e7ea885 100644 --- a/mysql-test/r/fulltext_order_by.result +++ b/mysql-test/r/fulltext_order_by.result @@ -46,11 +46,11 @@ a MATCH (message) AGAINST ('steve' IN BOOLEAN MODE) 7 1 SELECT a, FORMAT(MATCH (message) AGAINST ('steve'),6) as rel FROM t1 ORDER BY rel; a rel -3 0.000000 1 0.000000 5 0.000000 2 0.000000 6 0.000000 +3 0.000000 7 0.895690 4 0.905873 SELECT a, MATCH (message) AGAINST ('steve' IN BOOLEAN MODE) as rel FROM t1 ORDER BY rel; From e498a1bf65101878f51d0b2ca3eb0d05a8d3d01c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 28 Dec 2011 12:19:30 +0200 Subject: [PATCH 249/288] Bug#13418934 REMOVE HAVE_PURIFY DEPENDENCES FROM INNODB InnoDB: Remove HAVE_purify, UNIV_INIT_MEM_TO_ZERO, UNIV_SET_MEM_TO_ZERO. The compile-time setting HAVE_purify can mask potential bugs. It is being set in PB2 Valgrind runs. We should simply get rid of it, and replace it with UNIV_MEM_INVALID() to declare uninitialized memory as such in Valgrind-instrumented binaries. os_mem_alloc_large(), ut_malloc_low(): Remove the parameter set_to_zero. ut_malloc(): Define as a macro that invokes ut_malloc_low(). buf_pool_init(): Never initialize the buffer pool frames. All pages must be initialized before flushing them to disk. mem_heap_alloc(): Never initialize the allocated memory block. os_mem_alloc_nocache(), ut_test_malloc(): Unused function, remove. rb:813 approved by Jimmy Yang --- storage/innobase/buf/buf0buf.c | 8 +-- storage/innobase/include/mem0mem.ic | 4 -- storage/innobase/include/os0proc.h | 11 ---- storage/innobase/include/univ.i | 17 ----- storage/innobase/include/ut0mem.h | 26 +------- storage/innobase/mem/mem0pool.c | 6 +- storage/innobase/os/os0proc.c | 33 +--------- storage/innobase/ut/ut0mem.c | 65 +------------------ storage/innodb_plugin/buf/buf0buf.c | 5 +- storage/innodb_plugin/include/mem0mem.ic | 4 -- storage/innodb_plugin/include/univ.i | 17 ----- storage/innodb_plugin/include/ut0mem.h | 31 ++------- storage/innodb_plugin/mem/mem0pool.c | 6 +- storage/innodb_plugin/os/os0proc.c | 3 - storage/innodb_plugin/ut/ut0mem.c | 82 +----------------------- 15 files changed, 16 insertions(+), 302 deletions(-) diff --git a/storage/innobase/buf/buf0buf.c b/storage/innobase/buf/buf0buf.c index 78b39812cff..5463098a654 100644 --- a/storage/innobase/buf/buf0buf.c +++ b/storage/innobase/buf/buf0buf.c @@ -634,7 +634,7 @@ buf_pool_init( /*----------------------------------------*/ } else { buf_pool->frame_mem = os_mem_alloc_large( - UNIV_PAGE_SIZE * (n_frames + 1), TRUE, FALSE); + UNIV_PAGE_SIZE * (n_frames + 1), FALSE); } if (buf_pool->frame_mem == NULL) { @@ -756,12 +756,8 @@ buf_pool_init( block = buf_pool_get_nth_block(buf_pool, i); if (block->frame) { - /* Wipe contents of frame to eliminate a Purify - warning */ + UNIV_MEM_INVALID(block->frame, UNIV_PAGE_SIZE); -#ifdef HAVE_purify - memset(block->frame, '\0', UNIV_PAGE_SIZE); -#endif if (srv_use_awe) { /* Add to the list of blocks mapped to frames */ diff --git a/storage/innobase/include/mem0mem.ic b/storage/innobase/include/mem0mem.ic index 782672dbc18..0191e9a3ffd 100644 --- a/storage/innobase/include/mem0mem.ic +++ b/storage/innobase/include/mem0mem.ic @@ -194,10 +194,6 @@ mem_heap_alloc( caller */ buf = (byte*)buf + MEM_FIELD_HEADER_SIZE; -#endif -#ifdef UNIV_SET_MEM_TO_ZERO - UNIV_MEM_ALLOC(buf, n); - memset(buf, '\0', n); #endif UNIV_MEM_ALLOC(buf, n); return(buf); diff --git a/storage/innobase/include/os0proc.h b/storage/innobase/include/os0proc.h index f54e08de7ee..8c169f92431 100644 --- a/storage/innobase/include/os0proc.h +++ b/storage/innobase/include/os0proc.h @@ -104,14 +104,6 @@ ulint os_proc_get_number(void); /*====================*/ /******************************************************************** -Allocates non-cacheable memory. */ - -void* -os_mem_alloc_nocache( -/*=================*/ - /* out: allocated memory */ - ulint n); /* in: number of bytes */ -/******************************************************************** Allocates large pages memory. */ void* @@ -119,9 +111,6 @@ os_mem_alloc_large( /*===============*/ /* out: allocated memory */ ulint n, /* in: number of bytes */ - ibool set_to_zero, /* in: TRUE if allocated memory - should be set to zero if - UNIV_SET_MEM_TO_ZERO is defined */ ibool assert_on_error);/* in: if TRUE, we crash mysqld if the memory cannot be allocated */ /******************************************************************** diff --git a/storage/innobase/include/univ.i b/storage/innobase/include/univ.i index a67b1b3895e..4ac0809bcd2 100644 --- a/storage/innobase/include/univ.i +++ b/storage/innobase/include/univ.i @@ -72,14 +72,6 @@ Microsoft Visual C++ */ /* DEBUG VERSION CONTROL ===================== */ -/* The following flag will make InnoDB to initialize -all memory it allocates to zero. It hides Purify -warnings about reading unallocated memory unless -memory is read outside the allocated blocks. */ -/* -#define UNIV_INIT_MEM_TO_ZERO -*/ - /* Make a non-inline debug version */ #if defined HAVE_VALGRIND @@ -112,15 +104,6 @@ operations (very slow); also UNIV_DEBUG must be defined */ #define UNIV_BTR_DEBUG /* check B-tree links */ #define UNIV_LIGHT_MEM_DEBUG /* light memory debugging */ -#ifdef HAVE_purify -/* The following sets all new allocated memory to zero before use: -this can be used to eliminate unnecessary Purify warnings, but note that -it also masks many bugs Purify could detect. For detailed Purify analysis it -is best to remove the define below and look through the warnings one -by one. */ -#define UNIV_SET_MEM_TO_ZERO -#endif - /* #define UNIV_SQL_DEBUG #define UNIV_LOG_DEBUG diff --git a/storage/innobase/include/ut0mem.h b/storage/innobase/include/ut0mem.h index cb369e85c39..0dff70abc3a 100644 --- a/storage/innobase/include/ut0mem.h +++ b/storage/innobase/include/ut0mem.h @@ -30,38 +30,18 @@ ut_memcmp(const void* str1, const void* str2, ulint n); /************************************************************************** -Allocates memory. Sets it also to zero if UNIV_SET_MEM_TO_ZERO is -defined and set_to_zero is TRUE. */ +Allocates memory. */ void* ut_malloc_low( /*==========*/ /* out, own: allocated memory */ ulint n, /* in: number of bytes to allocate */ - ibool set_to_zero, /* in: TRUE if allocated memory - should be set to zero if - UNIV_SET_MEM_TO_ZERO is defined */ ibool assert_on_error); /* in: if TRUE, we crash mysqld if the memory cannot be allocated */ /************************************************************************** -Allocates memory. Sets it also to zero if UNIV_SET_MEM_TO_ZERO is -defined. */ - -void* -ut_malloc( -/*======*/ - /* out, own: allocated memory */ - ulint n); /* in: number of bytes to allocate */ -/************************************************************************** -Tests if malloc of n bytes would succeed. ut_malloc() asserts if memory runs -out. It cannot be used if we want to return an error message. Prints to -stderr a message if fails. */ - -ibool -ut_test_malloc( -/*===========*/ - /* out: TRUE if succeeded */ - ulint n); /* in: try to allocate this many bytes */ +Allocates memory. */ +#define ut_malloc(n) ut_malloc_low(n, TRUE) /************************************************************************** Frees a memory block allocated with ut_malloc. */ diff --git a/storage/innobase/mem/mem0pool.c b/storage/innobase/mem/mem0pool.c index 27da86a0309..6740ff04a4f 100644 --- a/storage/innobase/mem/mem0pool.c +++ b/storage/innobase/mem/mem0pool.c @@ -196,11 +196,7 @@ mem_pool_create( pool = ut_malloc(sizeof(mem_pool_t)); - /* We do not set the memory to zero (FALSE) in the pool, - but only when allocated at a higher level in mem0mem.c. - This is to avoid masking useful Purify warnings. */ - - pool->buf = ut_malloc_low(size, FALSE, TRUE); + pool->buf = ut_malloc_low(size, TRUE); pool->size = size; mutex_create(&pool->mutex, SYNC_MEM_POOL); diff --git a/storage/innobase/os/os0proc.c b/storage/innobase/os/os0proc.c index f00475fc528..6092392616f 100644 --- a/storage/innobase/os/os0proc.c +++ b/storage/innobase/os/os0proc.c @@ -531,28 +531,6 @@ os_proc_get_number(void) #endif } -/******************************************************************** -Allocates non-cacheable memory. */ - -void* -os_mem_alloc_nocache( -/*=================*/ - /* out: allocated memory */ - ulint n) /* in: number of bytes */ -{ -#ifdef __WIN__ - void* ptr; - - ptr = VirtualAlloc(NULL, n, MEM_COMMIT, - PAGE_READWRITE | PAGE_NOCACHE); - ut_a(ptr); - - return(ptr); -#else - return(ut_malloc(n)); -#endif -} - /******************************************************************** Allocates large pages memory. */ @@ -561,9 +539,6 @@ os_mem_alloc_large( /*===============*/ /* out: allocated memory */ ulint n, /* in: number of bytes */ - ibool set_to_zero, /* in: TRUE if allocated memory - should be set to zero if - UNIV_SET_MEM_TO_ZERO is defined */ ibool assert_on_error)/* in: if TRUE, we crash mysqld if the memory cannot be allocated */ { @@ -602,12 +577,6 @@ os_mem_alloc_large( #endif if (ptr) { - if (set_to_zero) { -#ifdef UNIV_SET_MEM_TO_ZERO - memset(ptr, '\0', size); -#endif - } - return(ptr); } @@ -616,7 +585,7 @@ os_mem_alloc_large( skip: #endif /* HAVE_LARGE_PAGES */ - return(ut_malloc_low(n, set_to_zero, assert_on_error)); + return(ut_malloc_low(n, assert_on_error)); } /******************************************************************** diff --git a/storage/innobase/ut/ut0mem.c b/storage/innobase/ut/ut0mem.c index 2e0dd27edf4..55f1c8593b8 100644 --- a/storage/innobase/ut/ut0mem.c +++ b/storage/innobase/ut/ut0mem.c @@ -54,17 +54,13 @@ ut_mem_block_list_init(void) } /************************************************************************** -Allocates memory. Sets it also to zero if UNIV_SET_MEM_TO_ZERO is -defined and set_to_zero is TRUE. */ +Allocates memory. */ void* ut_malloc_low( /*==========*/ /* out, own: allocated memory */ ulint n, /* in: number of bytes to allocate */ - ibool set_to_zero, /* in: TRUE if allocated memory should be - set to zero if UNIV_SET_MEM_TO_ZERO is - defined */ ibool assert_on_error)/* in: if TRUE, we crash mysqld if the memory cannot be allocated */ { @@ -156,12 +152,6 @@ retry: #endif } - if (set_to_zero) { -#ifdef UNIV_SET_MEM_TO_ZERO - memset(ret, '\0', n + sizeof(ut_mem_block_t)); -#endif - } - UNIV_MEM_ALLOC(ret, n + sizeof(ut_mem_block_t)); ((ut_mem_block_t*)ret)->size = n + sizeof(ut_mem_block_t); @@ -176,59 +166,6 @@ retry: return((void*)((byte*)ret + sizeof(ut_mem_block_t))); } -/************************************************************************** -Allocates memory. Sets it also to zero if UNIV_SET_MEM_TO_ZERO is -defined. */ - -void* -ut_malloc( -/*======*/ - /* out, own: allocated memory */ - ulint n) /* in: number of bytes to allocate */ -{ - return(ut_malloc_low(n, TRUE, TRUE)); -} - -/************************************************************************** -Tests if malloc of n bytes would succeed. ut_malloc() asserts if memory runs -out. It cannot be used if we want to return an error message. Prints to -stderr a message if fails. */ - -ibool -ut_test_malloc( -/*===========*/ - /* out: TRUE if succeeded */ - ulint n) /* in: try to allocate this many bytes */ -{ - void* ret; - - ret = malloc(n); - - if (ret == NULL) { - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Error: cannot allocate" - " %lu bytes of memory for\n" - "InnoDB: a BLOB with malloc! Total allocated memory\n" - "InnoDB: by InnoDB %lu bytes." - " Operating system errno: %d\n" - "InnoDB: Check if you should increase" - " the swap file or\n" - "InnoDB: ulimits of your operating system.\n" - "InnoDB: On FreeBSD check you have" - " compiled the OS with\n" - "InnoDB: a big enough maximum process size.\n", - (ulong) n, - (ulong) ut_total_allocated_memory, - (int) errno); - return(FALSE); - } - - free(ret); - - return(TRUE); -} - /************************************************************************** Frees a memory block allocated with ut_malloc. */ diff --git a/storage/innodb_plugin/buf/buf0buf.c b/storage/innodb_plugin/buf/buf0buf.c index d88860b807b..6daaacb0ac0 100644 --- a/storage/innodb_plugin/buf/buf0buf.c +++ b/storage/innodb_plugin/buf/buf0buf.c @@ -750,11 +750,8 @@ buf_chunk_init( for (i = chunk->size; i--; ) { buf_block_init(block, frame); + UNIV_MEM_INVALID(block->frame, UNIV_PAGE_SIZE); -#ifdef HAVE_purify - /* Wipe contents of frame to eliminate a Purify warning */ - memset(block->frame, '\0', UNIV_PAGE_SIZE); -#endif /* Add the block to the free list */ UT_LIST_ADD_LAST(list, buf_pool->free, (&block->page)); ut_d(block->page.in_free_list = TRUE); diff --git a/storage/innodb_plugin/include/mem0mem.ic b/storage/innodb_plugin/include/mem0mem.ic index cbce2edc661..bf7b1c20cb4 100644 --- a/storage/innodb_plugin/include/mem0mem.ic +++ b/storage/innodb_plugin/include/mem0mem.ic @@ -208,10 +208,6 @@ mem_heap_alloc( caller */ buf = (byte*)buf + MEM_FIELD_HEADER_SIZE; -#endif -#ifdef UNIV_SET_MEM_TO_ZERO - UNIV_MEM_ALLOC(buf, n); - memset(buf, '\0', n); #endif UNIV_MEM_ALLOC(buf, n); return(buf); diff --git a/storage/innodb_plugin/include/univ.i b/storage/innodb_plugin/include/univ.i index 5e36867f05a..c3aa3d25e36 100644 --- a/storage/innodb_plugin/include/univ.i +++ b/storage/innodb_plugin/include/univ.i @@ -146,14 +146,6 @@ Sun Studio */ /* DEBUG VERSION CONTROL ===================== */ -/* The following flag will make InnoDB to initialize -all memory it allocates to zero. It hides Purify -warnings about reading unallocated memory unless -memory is read outside the allocated blocks. */ -/* -#define UNIV_INIT_MEM_TO_ZERO -*/ - /* When this macro is defined then additional test functions will be compiled. These functions live at the end of each relevant source file and have "test_" prefix. These functions are not called from anywhere in @@ -218,15 +210,6 @@ operations (very slow); also UNIV_DEBUG must be defined */ #define UNIV_BTR_DEBUG /* check B-tree links */ #define UNIV_LIGHT_MEM_DEBUG /* light memory debugging */ -#ifdef HAVE_purify -/* The following sets all new allocated memory to zero before use: -this can be used to eliminate unnecessary Purify warnings, but note that -it also masks many bugs Purify could detect. For detailed Purify analysis it -is best to remove the define below and look through the warnings one -by one. */ -#define UNIV_SET_MEM_TO_ZERO -#endif - /* #define UNIV_SQL_DEBUG #define UNIV_LOG_DEBUG diff --git a/storage/innodb_plugin/include/ut0mem.h b/storage/innodb_plugin/include/ut0mem.h index 9c6ee9049ec..5002c9e3801 100644 --- a/storage/innodb_plugin/include/ut0mem.h +++ b/storage/innodb_plugin/include/ut0mem.h @@ -78,40 +78,19 @@ ut_mem_init(void); /*=============*/ /**********************************************************************//** -Allocates memory. Sets it also to zero if UNIV_SET_MEM_TO_ZERO is -defined and set_to_zero is TRUE. +Allocates memory. @return own: allocated memory */ UNIV_INTERN void* ut_malloc_low( /*==========*/ ulint n, /*!< in: number of bytes to allocate */ - ibool set_to_zero, /*!< in: TRUE if allocated memory - should be set to zero if - UNIV_SET_MEM_TO_ZERO is defined */ - ibool assert_on_error); /*!< in: if TRUE, we crash mysqld if + ibool assert_on_error) /*!< in: if TRUE, we crash mysqld if the memory cannot be allocated */ + __attribute__((malloc)); /**********************************************************************//** -Allocates memory. Sets it also to zero if UNIV_SET_MEM_TO_ZERO is -defined. -@return own: allocated memory */ -UNIV_INTERN -void* -ut_malloc( -/*======*/ - ulint n); /*!< in: number of bytes to allocate */ -#ifndef UNIV_HOTBACKUP -/**********************************************************************//** -Tests if malloc of n bytes would succeed. ut_malloc() asserts if memory runs -out. It cannot be used if we want to return an error message. Prints to -stderr a message if fails. -@return TRUE if succeeded */ -UNIV_INTERN -ibool -ut_test_malloc( -/*===========*/ - ulint n); /*!< in: try to allocate this many bytes */ -#endif /* !UNIV_HOTBACKUP */ +Allocates memory. */ +#define ut_malloc(n) ut_malloc_low(n, TRUE) /**********************************************************************//** Frees a memory block allocated with ut_malloc. Freeing a NULL pointer is a nop. */ diff --git a/storage/innodb_plugin/mem/mem0pool.c b/storage/innodb_plugin/mem/mem0pool.c index 3291453eeb5..8a01be66506 100644 --- a/storage/innodb_plugin/mem/mem0pool.c +++ b/storage/innodb_plugin/mem/mem0pool.c @@ -223,11 +223,7 @@ mem_pool_create( pool = ut_malloc(sizeof(mem_pool_t)); - /* We do not set the memory to zero (FALSE) in the pool, - but only when allocated at a higher level in mem0mem.c. - This is to avoid masking useful Purify warnings. */ - - pool->buf = ut_malloc_low(size, FALSE, TRUE); + pool->buf = ut_malloc_low(size, TRUE); pool->size = size; mutex_create(&pool->mutex, SYNC_MEM_POOL); diff --git a/storage/innodb_plugin/os/os0proc.c b/storage/innodb_plugin/os/os0proc.c index 48922886f23..a0679e31570 100644 --- a/storage/innodb_plugin/os/os0proc.c +++ b/storage/innodb_plugin/os/os0proc.c @@ -111,9 +111,6 @@ os_mem_alloc_large( os_fast_mutex_lock(&ut_list_mutex); ut_total_allocated_memory += size; os_fast_mutex_unlock(&ut_list_mutex); -# ifdef UNIV_SET_MEM_TO_ZERO - memset(ptr, '\0', size); -# endif UNIV_MEM_ALLOC(ptr, size); return(ptr); } diff --git a/storage/innodb_plugin/ut/ut0mem.c b/storage/innodb_plugin/ut/ut0mem.c index 95fb2187b79..9f9eb1c4d49 100644 --- a/storage/innodb_plugin/ut/ut0mem.c +++ b/storage/innodb_plugin/ut/ut0mem.c @@ -84,17 +84,13 @@ ut_mem_init(void) #endif /* !UNIV_HOTBACKUP */ /**********************************************************************//** -Allocates memory. Sets it also to zero if UNIV_SET_MEM_TO_ZERO is -defined and set_to_zero is TRUE. +Allocates memory. @return own: allocated memory */ UNIV_INTERN void* ut_malloc_low( /*==========*/ ulint n, /*!< in: number of bytes to allocate */ - ibool set_to_zero, /*!< in: TRUE if allocated memory should be - set to zero if UNIV_SET_MEM_TO_ZERO is - defined */ ibool assert_on_error)/*!< in: if TRUE, we crash mysqld if the memory cannot be allocated */ { @@ -106,12 +102,6 @@ ut_malloc_low( ret = malloc(n); ut_a(ret || !assert_on_error); -#ifdef UNIV_SET_MEM_TO_ZERO - if (set_to_zero) { - memset(ret, '\0', n); - UNIV_MEM_ALLOC(ret, n); - } -#endif return(ret); } @@ -199,12 +189,6 @@ retry: #endif } - if (set_to_zero) { -#ifdef UNIV_SET_MEM_TO_ZERO - memset(ret, '\0', n + sizeof(ut_mem_block_t)); -#endif - } - UNIV_MEM_ALLOC(ret, n + sizeof(ut_mem_block_t)); ((ut_mem_block_t*)ret)->size = n + sizeof(ut_mem_block_t); @@ -221,74 +205,10 @@ retry: void* ret = malloc(n); ut_a(ret || !assert_on_error); -# ifdef UNIV_SET_MEM_TO_ZERO - if (set_to_zero) { - memset(ret, '\0', n); - } -# endif return(ret); #endif /* !UNIV_HOTBACKUP */ } -/**********************************************************************//** -Allocates memory. Sets it also to zero if UNIV_SET_MEM_TO_ZERO is -defined. -@return own: allocated memory */ -UNIV_INTERN -void* -ut_malloc( -/*======*/ - ulint n) /*!< in: number of bytes to allocate */ -{ -#ifndef UNIV_HOTBACKUP - return(ut_malloc_low(n, TRUE, TRUE)); -#else /* !UNIV_HOTBACKUP */ - return(malloc(n)); -#endif /* !UNIV_HOTBACKUP */ -} - -#ifndef UNIV_HOTBACKUP -/**********************************************************************//** -Tests if malloc of n bytes would succeed. ut_malloc() asserts if memory runs -out. It cannot be used if we want to return an error message. Prints to -stderr a message if fails. -@return TRUE if succeeded */ -UNIV_INTERN -ibool -ut_test_malloc( -/*===========*/ - ulint n) /*!< in: try to allocate this many bytes */ -{ - void* ret; - - ret = malloc(n); - - if (ret == NULL) { - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Error: cannot allocate" - " %lu bytes of memory for\n" - "InnoDB: a BLOB with malloc! Total allocated memory\n" - "InnoDB: by InnoDB %lu bytes." - " Operating system errno: %d\n" - "InnoDB: Check if you should increase" - " the swap file or\n" - "InnoDB: ulimits of your operating system.\n" - "InnoDB: On FreeBSD check you have" - " compiled the OS with\n" - "InnoDB: a big enough maximum process size.\n", - (ulong) n, - (ulong) ut_total_allocated_memory, - (int) errno); - return(FALSE); - } - - free(ret); - - return(TRUE); -} -#endif /* !UNIV_HOTBACKUP */ - /**********************************************************************//** Frees a memory block allocated with ut_malloc. Freeing a NULL pointer is a nop. */ From 841e8ddbc56fd315460d8f7ae28e3a95b8d37825 Mon Sep 17 00:00:00 2001 From: Vasil Dimov Date: Thu, 29 Dec 2011 16:05:08 +0200 Subject: [PATCH 250/288] Partial fix for Bug#11764622 57480: MEMORY LEAK WHEN HAVING 256+ TABLES Port vasil.dimov@oracle.com-20111205082626-87j5f48dq1ouk86r from mysql-trunk --- storage/innobase/pars/pars0pars.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/innobase/pars/pars0pars.c b/storage/innobase/pars/pars0pars.c index ef107f2896f..86f54195682 100644 --- a/storage/innobase/pars/pars0pars.c +++ b/storage/innobase/pars/pars0pars.c @@ -1857,7 +1857,7 @@ pars_sql( ut_ad(str); - heap = mem_heap_create(256); + heap = mem_heap_create(16000); /* Currently, the parser is not reentrant: */ ut_ad(mutex_own(&(dict_sys->mutex))); From b7b9a4e8102f7be5ac6eca34b9f3f743dc0af100 Mon Sep 17 00:00:00 2001 From: Vasil Dimov Date: Thu, 29 Dec 2011 16:11:07 +0200 Subject: [PATCH 251/288] Partial fix for Bug#11764622 57480: MEMORY LEAK WHEN HAVING 256+ TABLES Port vasil.dimov@oracle.com-20111205082756-wtlg8isyn4yohyny from mysql-trunk --- storage/innobase/handler/ha_innodb.cc | 3 +- storage/innobase/handler/handler0alter.cc | 7 ++- storage/innobase/include/data0data.h | 9 +++- storage/innobase/include/data0data.ic | 6 +-- storage/innobase/include/row0mysql.h | 4 +- storage/innobase/row/row0mysql.c | 61 ++++++++++++++++++----- 6 files changed, 70 insertions(+), 20 deletions(-) diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 371ef9787c1..7f587a31039 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -3816,9 +3816,8 @@ retry: DBUG_RETURN(HA_ERR_NO_SUCH_TABLE); } - prebuilt = row_create_prebuilt(ib_table); + prebuilt = row_create_prebuilt(ib_table, table->s->reclength); - prebuilt->mysql_row_len = table->s->reclength; prebuilt->default_rec = table->s->default_values; ut_ad(prebuilt->default_rec); diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 6d5b7b4668f..c6754660b84 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -1008,7 +1008,12 @@ ha_innobase::final_add_index( row_prebuilt_free(prebuilt, TRUE); error = row_merge_drop_table(trx, old_table); add->indexed_table->n_mysql_handles_opened++; - prebuilt = row_create_prebuilt(add->indexed_table); + prebuilt = row_create_prebuilt(add->indexed_table, + 0 /* XXX Do we know the mysql_row_len here? + Before the addition of this parameter to + row_create_prebuilt() the mysql_row_len + member was left 0 (from zalloc) in the + prebuilt object. */); } err = convert_error_code_to_mysql( diff --git a/storage/innobase/include/data0data.h b/storage/innobase/include/data0data.h index f7bdd29ed90..9435169a0fd 100644 --- a/storage/innobase/include/data0data.h +++ b/storage/innobase/include/data0data.h @@ -231,6 +231,12 @@ dtuple_set_n_fields_cmp( dtuple_t* tuple, /*!< in: tuple */ ulint n_fields_cmp); /*!< in: number of fields used in comparisons in rem0cmp.* */ + +/* Estimate the number of bytes that are going to be allocated when +creating a new dtuple_t object */ +#define DTUPLE_EST_ALLOC(n_fields) \ + (sizeof(dtuple_t) + (n_fields) * sizeof(dfield_t)) + /**********************************************************//** Creates a data tuple to a memory heap. The default value for number of fields used in record comparisons for this tuple is n_fields. @@ -240,7 +246,8 @@ dtuple_t* dtuple_create( /*==========*/ mem_heap_t* heap, /*!< in: memory heap where the tuple - is created */ + is created, DTUPLE_EST_ALLOC(n_fields) + bytes will be allocated from this heap */ ulint n_fields); /*!< in: number of fields */ /**********************************************************//** diff --git a/storage/innobase/include/data0data.ic b/storage/innobase/include/data0data.ic index 5c0f8039c80..971f58412c0 100644 --- a/storage/innobase/include/data0data.ic +++ b/storage/innobase/include/data0data.ic @@ -356,15 +356,15 @@ dtuple_t* dtuple_create( /*==========*/ mem_heap_t* heap, /*!< in: memory heap where the tuple - is created */ + is created, DTUPLE_EST_ALLOC(n_fields) + bytes will be allocated from this heap */ ulint n_fields) /*!< in: number of fields */ { dtuple_t* tuple; ut_ad(heap); - tuple = (dtuple_t*) mem_heap_alloc(heap, sizeof(dtuple_t) - + n_fields * sizeof(dfield_t)); + tuple = (dtuple_t*) mem_heap_alloc(heap, DTUPLE_EST_ALLOC(n_fields)); tuple->info_bits = 0; tuple->n_fields = n_fields; tuple->n_fields_cmp = n_fields; diff --git a/storage/innobase/include/row0mysql.h b/storage/innobase/include/row0mysql.h index dd619406ab9..27fc1b95808 100644 --- a/storage/innobase/include/row0mysql.h +++ b/storage/innobase/include/row0mysql.h @@ -168,7 +168,9 @@ UNIV_INTERN row_prebuilt_t* row_create_prebuilt( /*================*/ - dict_table_t* table); /*!< in: Innobase table handle */ + dict_table_t* table, /*!< in: Innobase table handle */ + ulint mysql_row_len); /*!< in: length in bytes of a row in + the MySQL format */ /********************************************************************//** Free a prebuilt struct for a MySQL table handle. */ UNIV_INTERN diff --git a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c index 987d6595224..9289a2930d4 100644 --- a/storage/innobase/row/row0mysql.c +++ b/storage/innobase/row/row0mysql.c @@ -667,17 +667,60 @@ UNIV_INTERN row_prebuilt_t* row_create_prebuilt( /*================*/ - dict_table_t* table) /*!< in: Innobase table handle */ + dict_table_t* table, /*!< in: Innobase table handle */ + ulint mysql_row_len) /*!< in: length in bytes of a row in + the MySQL format */ { row_prebuilt_t* prebuilt; mem_heap_t* heap; dict_index_t* clust_index; dtuple_t* ref; ulint ref_len; + ulint search_tuple_n_fields; - heap = mem_heap_create(sizeof *prebuilt + 128); + search_tuple_n_fields = 2 * dict_table_get_n_cols(table); - prebuilt = mem_heap_zalloc(heap, sizeof *prebuilt); + clust_index = dict_table_get_first_index(table); + + /* Make sure that search_tuple is long enough for clustered index */ + ut_a(2 * dict_table_get_n_cols(table) >= clust_index->n_fields); + + ref_len = dict_index_get_n_unique(clust_index); + +#define PREBUILT_HEAP_INITIAL_SIZE \ + ( \ + sizeof(*prebuilt) \ + /* allocd in this function */ \ + + DTUPLE_EST_ALLOC(search_tuple_n_fields) \ + + DTUPLE_EST_ALLOC(ref_len) \ + /* allocd in row_prebuild_sel_graph() */ \ + + sizeof(sel_node_t) \ + + sizeof(que_fork_t) \ + + sizeof(que_thr_t) \ + /* allocd in row_get_prebuilt_update_vector() */ \ + + sizeof(upd_node_t) \ + + sizeof(upd_t) \ + + sizeof(upd_field_t) \ + * dict_table_get_n_cols(table) \ + + sizeof(que_fork_t) \ + + sizeof(que_thr_t) \ + /* allocd in row_get_prebuilt_insert_row() */ \ + + sizeof(ins_node_t) \ + /* mysql_row_len could be huge and we are not \ + sure if this prebuilt instance is going to be \ + used in inserts */ \ + + (mysql_row_len < 256 ? mysql_row_len : 0) \ + + DTUPLE_EST_ALLOC(dict_table_get_n_cols(table)) \ + + sizeof(que_fork_t) \ + + sizeof(que_thr_t) \ + ) + + /* We allocate enough space for the objects that are likely to + be created later in order to minimize the number of malloc() + calls */ + heap = mem_heap_create(PREBUILT_HEAP_INITIAL_SIZE); + + prebuilt = mem_heap_zalloc(heap, sizeof(*prebuilt)); prebuilt->magic_n = ROW_PREBUILT_ALLOCATED; prebuilt->magic_n2 = ROW_PREBUILT_ALLOCATED; @@ -695,15 +738,7 @@ row_create_prebuilt( UNIV_MEM_INVALID(&prebuilt->stored_select_lock_type, sizeof prebuilt->stored_select_lock_type); - prebuilt->search_tuple = dtuple_create( - heap, 2 * dict_table_get_n_cols(table)); - - clust_index = dict_table_get_first_index(table); - - /* Make sure that search_tuple is long enough for clustered index */ - ut_a(2 * dict_table_get_n_cols(table) >= clust_index->n_fields); - - ref_len = dict_index_get_n_unique(clust_index); + prebuilt->search_tuple = dtuple_create(heap, search_tuple_n_fields); ref = dtuple_create(heap, ref_len); @@ -720,6 +755,8 @@ row_create_prebuilt( prebuilt->autoinc_last_value = 0; + prebuilt->mysql_row_len = mysql_row_len; + return(prebuilt); } From 93ab1d547dc462f0c723bfdf6a9822afeb6c1df6 Mon Sep 17 00:00:00 2001 From: Vasil Dimov Date: Thu, 29 Dec 2011 16:12:55 +0200 Subject: [PATCH 252/288] Partial fix for Bug#11764622 57480: MEMORY LEAK WHEN HAVING 256+ TABLES Port vasil.dimov@oracle.com-20111205082831-7v1qu50hvd9hjr3g from mysql-trunk --- storage/innobase/btr/btr0pcur.c | 20 ++++++++++++++++---- storage/innobase/include/btr0pcur.h | 10 ++++++++++ storage/innobase/include/row0mysql.h | 4 ++-- storage/innobase/row/row0mysql.c | 18 +++++++++--------- storage/innobase/row/row0sel.c | 16 ++++++++-------- 5 files changed, 45 insertions(+), 23 deletions(-) diff --git a/storage/innobase/btr/btr0pcur.c b/storage/innobase/btr/btr0pcur.c index 57d9752649f..fb153556b2f 100644 --- a/storage/innobase/btr/btr0pcur.c +++ b/storage/innobase/btr/btr0pcur.c @@ -52,12 +52,13 @@ btr_pcur_create_for_mysql(void) } /**************************************************************//** -Frees the memory for a persistent cursor object. */ +Resets a persistent cursor object, freeing ::old_rec_buf if it is +allocated and resetting the other members to their initial values. */ UNIV_INTERN void -btr_pcur_free_for_mysql( -/*====================*/ - btr_pcur_t* cursor) /*!< in, own: persistent cursor */ +btr_pcur_reset( +/*===========*/ + btr_pcur_t* cursor) /*!< in, out: persistent cursor */ { if (cursor->old_rec_buf != NULL) { @@ -66,6 +67,7 @@ btr_pcur_free_for_mysql( cursor->old_rec_buf = NULL; } + cursor->btr_cur.index = NULL; cursor->btr_cur.page_cur.rec = NULL; cursor->old_rec = NULL; cursor->old_n_fields = 0; @@ -73,7 +75,17 @@ btr_pcur_free_for_mysql( cursor->latch_mode = BTR_NO_LATCHES; cursor->pos_state = BTR_PCUR_NOT_POSITIONED; +} +/**************************************************************//** +Frees the memory for a persistent cursor object. */ +UNIV_INTERN +void +btr_pcur_free_for_mysql( +/*====================*/ + btr_pcur_t* cursor) /*!< in, own: persistent cursor */ +{ + btr_pcur_reset(cursor); mem_free(cursor); } diff --git a/storage/innobase/include/btr0pcur.h b/storage/innobase/include/btr0pcur.h index 140f94466db..2ebd70a6f23 100644 --- a/storage/innobase/include/btr0pcur.h +++ b/storage/innobase/include/btr0pcur.h @@ -53,6 +53,16 @@ UNIV_INTERN btr_pcur_t* btr_pcur_create_for_mysql(void); /*============================*/ + +/**************************************************************//** +Resets a persistent cursor object, freeing ::old_rec_buf if it is +allocated and resetting the other members to their initial values. */ +UNIV_INTERN +void +btr_pcur_reset( +/*===========*/ + btr_pcur_t* cursor);/*!< in, out: persistent cursor */ + /**************************************************************//** Frees the memory for a persistent cursor object. */ UNIV_INTERN diff --git a/storage/innobase/include/row0mysql.h b/storage/innobase/include/row0mysql.h index 27fc1b95808..e17fd584110 100644 --- a/storage/innobase/include/row0mysql.h +++ b/storage/innobase/include/row0mysql.h @@ -674,9 +674,9 @@ struct row_prebuilt_struct { in inserts */ que_fork_t* upd_graph; /*!< Innobase SQL query graph used in updates or deletes */ - btr_pcur_t* pcur; /*!< persistent cursor used in selects + btr_pcur_t pcur; /*!< persistent cursor used in selects and updates */ - btr_pcur_t* clust_pcur; /*!< persistent cursor used in + btr_pcur_t clust_pcur; /*!< persistent cursor used in some selects and updates */ que_fork_t* sel_graph; /*!< dummy query graph used in selects */ diff --git a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c index 9289a2930d4..996a49f76e8 100644 --- a/storage/innobase/row/row0mysql.c +++ b/storage/innobase/row/row0mysql.c @@ -730,8 +730,8 @@ row_create_prebuilt( prebuilt->sql_stat_start = TRUE; prebuilt->heap = heap; - prebuilt->pcur = btr_pcur_create_for_mysql(); - prebuilt->clust_pcur = btr_pcur_create_for_mysql(); + btr_pcur_reset(&prebuilt->pcur); + btr_pcur_reset(&prebuilt->clust_pcur); prebuilt->select_lock_type = LOCK_NONE; prebuilt->stored_select_lock_type = 99999999; @@ -792,8 +792,8 @@ row_prebuilt_free( prebuilt->magic_n = ROW_PREBUILT_FREED; prebuilt->magic_n2 = ROW_PREBUILT_FREED; - btr_pcur_free_for_mysql(prebuilt->pcur); - btr_pcur_free_for_mysql(prebuilt->clust_pcur); + btr_pcur_reset(&prebuilt->pcur); + btr_pcur_reset(&prebuilt->clust_pcur); if (prebuilt->mysql_template) { mem_free(prebuilt->mysql_template); @@ -1453,11 +1453,11 @@ row_update_for_mysql( clust_index = dict_table_get_first_index(table); - if (prebuilt->pcur->btr_cur.index == clust_index) { - btr_pcur_copy_stored_position(node->pcur, prebuilt->pcur); + if (prebuilt->pcur.btr_cur.index == clust_index) { + btr_pcur_copy_stored_position(node->pcur, &prebuilt->pcur); } else { btr_pcur_copy_stored_position(node->pcur, - prebuilt->clust_pcur); + &prebuilt->clust_pcur); } ut_a(node->pcur->rel_pos == BTR_PCUR_ON); @@ -1561,8 +1561,8 @@ row_unlock_for_mysql( clust_pcur, and we do not need to reposition the cursors. */ { - btr_pcur_t* pcur = prebuilt->pcur; - btr_pcur_t* clust_pcur = prebuilt->clust_pcur; + btr_pcur_t* pcur = &prebuilt->pcur; + btr_pcur_t* clust_pcur = &prebuilt->clust_pcur; trx_t* trx = prebuilt->trx; ut_ad(prebuilt && trx); diff --git a/storage/innobase/row/row0sel.c b/storage/innobase/row/row0sel.c index 5d8f53f68da..10dfd51e9b3 100644 --- a/storage/innobase/row/row0sel.c +++ b/storage/innobase/row/row0sel.c @@ -2915,17 +2915,17 @@ row_sel_get_clust_rec_for_mysql( btr_pcur_open_with_no_init(clust_index, prebuilt->clust_ref, PAGE_CUR_LE, BTR_SEARCH_LEAF, - prebuilt->clust_pcur, 0, mtr); + &prebuilt->clust_pcur, 0, mtr); - clust_rec = btr_pcur_get_rec(prebuilt->clust_pcur); + clust_rec = btr_pcur_get_rec(&prebuilt->clust_pcur); - prebuilt->clust_pcur->trx_if_known = trx; + prebuilt->clust_pcur.trx_if_known = trx; /* Note: only if the search ends up on a non-infimum record is the low_match value the real match to the search tuple */ if (!page_rec_is_user_rec(clust_rec) - || btr_pcur_get_low_match(prebuilt->clust_pcur) + || btr_pcur_get_low_match(&prebuilt->clust_pcur) < dict_index_get_n_unique(clust_index)) { /* In a rare case it is possible that no clust rec is found @@ -2974,7 +2974,7 @@ row_sel_get_clust_rec_for_mysql( we set a LOCK_REC_NOT_GAP type lock */ err = lock_clust_rec_read_check_and_lock( - 0, btr_pcur_get_block(prebuilt->clust_pcur), + 0, btr_pcur_get_block(&prebuilt->clust_pcur), clust_rec, clust_index, *offsets, prebuilt->select_lock_type, LOCK_REC_NOT_GAP, thr); switch (err) { @@ -3052,7 +3052,7 @@ func_exit: /* We may use the cursor in update or in unlock_row(): store its position */ - btr_pcur_store_position(prebuilt->clust_pcur, mtr); + btr_pcur_store_position(&prebuilt->clust_pcur, mtr); } err_exit: @@ -3300,7 +3300,7 @@ row_sel_try_search_shortcut_for_mysql( { dict_index_t* index = prebuilt->index; const dtuple_t* search_tuple = prebuilt->search_tuple; - btr_pcur_t* pcur = prebuilt->pcur; + btr_pcur_t* pcur = &prebuilt->pcur; trx_t* trx = prebuilt->trx; const rec_t* rec; @@ -3389,7 +3389,7 @@ row_search_for_mysql( dict_index_t* index = prebuilt->index; ibool comp = dict_table_is_comp(index->table); const dtuple_t* search_tuple = prebuilt->search_tuple; - btr_pcur_t* pcur = prebuilt->pcur; + btr_pcur_t* pcur = &prebuilt->pcur; trx_t* trx = prebuilt->trx; dict_index_t* clust_index; que_thr_t* thr; From a4fa485f5f171edcf9e26d650c55bebc26522420 Mon Sep 17 00:00:00 2001 From: Vasil Dimov Date: Thu, 29 Dec 2011 16:14:45 +0200 Subject: [PATCH 253/288] Partial fix for Bug#11764622 57480: MEMORY LEAK WHEN HAVING 256+ TABLES Port vasil.dimov@oracle.com-20111205082900-lx9om1joscejr25e from mysql-trunk --- storage/innobase/dict/dict0load.c | 42 ++++++++++----------- storage/innobase/include/data0data.h | 14 +++++++ storage/innobase/include/data0data.ic | 53 +++++++++++++++++++++------ 3 files changed, 76 insertions(+), 33 deletions(-) diff --git a/storage/innobase/dict/dict0load.c b/storage/innobase/dict/dict0load.c index e13cc1b31f1..9828326dde1 100644 --- a/storage/innobase/dict/dict0load.c +++ b/storage/innobase/dict/dict0load.c @@ -2066,8 +2066,9 @@ static void dict_load_foreign_cols( /*===================*/ - const char* id, /*!< in: foreign constraint id as a - null-terminated string */ + const char* id, /*!< in: foreign constraint id, not + necessary '\0'-terminated */ + ulint id_len, /*!< in: id length */ dict_foreign_t* foreign)/*!< in: foreign constraint object */ { dict_table_t* sys_foreign_cols; @@ -2097,7 +2098,7 @@ dict_load_foreign_cols( tuple = dtuple_create(foreign->heap, 1); dfield = dtuple_get_nth_field(tuple, 0); - dfield_set_data(dfield, id, ut_strlen(id)); + dfield_set_data(dfield, id, id_len); dict_index_copy_types(tuple, sys_index, 1); btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE, @@ -2110,7 +2111,7 @@ dict_load_foreign_cols( ut_a(!rec_get_deleted_flag(rec, 0)); field = rec_get_nth_field_old(rec, 0, &len); - ut_a(len == ut_strlen(id)); + ut_a(len == id_len); ut_a(ut_memcmp(id, field, len) == 0); field = rec_get_nth_field_old(rec, 1, &len); @@ -2139,8 +2140,9 @@ static ulint dict_load_foreign( /*==============*/ - const char* id, /*!< in: foreign constraint id as a - null-terminated string */ + const char* id, /*!< in: foreign constraint id, not + necessary '\0'-terminated */ + ulint id_len, /*!< in: id length */ ibool check_charsets, /*!< in: TRUE=check charset compatibility */ ibool check_recursive) @@ -2176,7 +2178,7 @@ dict_load_foreign( tuple = dtuple_create(heap2, 1); dfield = dtuple_get_nth_field(tuple, 0); - dfield_set_data(dfield, id, ut_strlen(id)); + dfield_set_data(dfield, id, id_len); dict_index_copy_types(tuple, sys_index, 1); btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE, @@ -2188,8 +2190,8 @@ dict_load_foreign( /* Not found */ fprintf(stderr, - "InnoDB: Error A: cannot load foreign constraint %s\n", - id); + "InnoDB: Error A: cannot load foreign constraint " + "%.*s\n", (int) id_len, id); btr_pcur_close(&pcur); mtr_commit(&mtr); @@ -2201,11 +2203,11 @@ dict_load_foreign( field = rec_get_nth_field_old(rec, 0, &len); /* Check if the id in record is the searched one */ - if (len != ut_strlen(id) || ut_memcmp(id, field, len) != 0) { + if (len != id_len || ut_memcmp(id, field, len) != 0) { fprintf(stderr, - "InnoDB: Error B: cannot load foreign constraint %s\n", - id); + "InnoDB: Error B: cannot load foreign constraint " + "%.*s\n", (int) id_len, id); btr_pcur_close(&pcur); mtr_commit(&mtr); @@ -2231,7 +2233,7 @@ dict_load_foreign( foreign->type = (unsigned int) (n_fields_and_type >> 24); foreign->n_fields = (unsigned int) (n_fields_and_type & 0x3FFUL); - foreign->id = mem_heap_strdup(foreign->heap, id); + foreign->id = mem_heap_strdupl(foreign->heap, id, id_len); field = rec_get_nth_field_old(rec, 3, &len); @@ -2247,7 +2249,7 @@ dict_load_foreign( btr_pcur_close(&pcur); mtr_commit(&mtr); - dict_load_foreign_cols(id, foreign); + dict_load_foreign_cols(id, id_len, foreign); ref_table = dict_table_check_if_in_cache_low( foreign->referenced_table_name_lookup); @@ -2326,8 +2328,8 @@ dict_load_foreigns( ibool check_charsets) /*!< in: TRUE=check charset compatibility */ { + char tuple_buf[DTUPLE_EST_ALLOC(1)]; btr_pcur_t pcur; - mem_heap_t* heap; dtuple_t* tuple; dfield_t* dfield; dict_index_t* sec_index; @@ -2335,7 +2337,6 @@ dict_load_foreigns( const rec_t* rec; const byte* field; ulint len; - char* id ; ulint err; mtr_t mtr; @@ -2362,9 +2363,8 @@ dict_load_foreigns( sec_index = dict_table_get_next_index( dict_table_get_first_index(sys_foreign)); start_load: - heap = mem_heap_create(256); - tuple = dtuple_create(heap, 1); + tuple = dtuple_create_from_mem(tuple_buf, sizeof(tuple_buf), 1); dfield = dtuple_get_nth_field(tuple, 0); dfield_set_data(dfield, table_name, ut_strlen(table_name)); @@ -2418,7 +2418,6 @@ loop: /* Now we get a foreign key constraint id */ field = rec_get_nth_field_old(rec, 1, &len); - id = mem_heap_strdupl(heap, (char*) field, len); btr_pcur_store_position(&pcur, &mtr); @@ -2426,11 +2425,11 @@ loop: /* Load the foreign constraint definition to the dictionary cache */ - err = dict_load_foreign(id, check_charsets, check_recursive); + err = dict_load_foreign((char*) field, len, check_charsets, + check_recursive); if (err != DB_SUCCESS) { btr_pcur_close(&pcur); - mem_heap_free(heap); return(err); } @@ -2446,7 +2445,6 @@ next_rec: load_next_index: btr_pcur_close(&pcur); mtr_commit(&mtr); - mem_heap_free(heap); sec_index = dict_table_get_next_index(sec_index); diff --git a/storage/innobase/include/data0data.h b/storage/innobase/include/data0data.h index 9435169a0fd..6d3c2988fdc 100644 --- a/storage/innobase/include/data0data.h +++ b/storage/innobase/include/data0data.h @@ -237,6 +237,20 @@ creating a new dtuple_t object */ #define DTUPLE_EST_ALLOC(n_fields) \ (sizeof(dtuple_t) + (n_fields) * sizeof(dfield_t)) +/**********************************************************//** +Creates a data tuple from an already allocated chunk of memory. +The size of the chunk must be at least DTUPLE_EST_ALLOC(n_fields). +The default value for number of fields used in record comparisons +for this tuple is n_fields. +@return created tuple (inside buf) */ +UNIV_INLINE +dtuple_t* +dtuple_create_from_mem( +/*===================*/ + void* buf, /*!< in, out: buffer to use */ + ulint buf_size, /*!< in: buffer size */ + ulint n_fields); /*!< in: number of fields */ + /**********************************************************//** Creates a data tuple to a memory heap. The default value for number of fields used in record comparisons for this tuple is n_fields. diff --git a/storage/innobase/include/data0data.ic b/storage/innobase/include/data0data.ic index 971f58412c0..205fa397987 100644 --- a/storage/innobase/include/data0data.ic +++ b/storage/innobase/include/data0data.ic @@ -348,23 +348,25 @@ dtuple_get_nth_field( #endif /* UNIV_DEBUG */ /**********************************************************//** -Creates a data tuple to a memory heap. The default value for number -of fields used in record comparisons for this tuple is n_fields. -@return own: created tuple */ +Creates a data tuple from an already allocated chunk of memory. +The size of the chunk must be at least DTUPLE_EST_ALLOC(n_fields). +The default value for number of fields used in record comparisons +for this tuple is n_fields. +@return created tuple (inside buf) */ UNIV_INLINE dtuple_t* -dtuple_create( -/*==========*/ - mem_heap_t* heap, /*!< in: memory heap where the tuple - is created, DTUPLE_EST_ALLOC(n_fields) - bytes will be allocated from this heap */ - ulint n_fields) /*!< in: number of fields */ +dtuple_create_from_mem( +/*===================*/ + void* buf, /*!< in, out: buffer to use */ + ulint buf_size, /*!< in: buffer size */ + ulint n_fields) /*!< in: number of fields */ { dtuple_t* tuple; - ut_ad(heap); + ut_ad(buf != NULL); + ut_a(buf_size >= DTUPLE_EST_ALLOC(n_fields)); - tuple = (dtuple_t*) mem_heap_alloc(heap, DTUPLE_EST_ALLOC(n_fields)); + tuple = (dtuple_t*) buf; tuple->info_bits = 0; tuple->n_fields = n_fields; tuple->n_fields_cmp = n_fields; @@ -386,9 +388,38 @@ dtuple_create( dfield_get_type(field)->mtype = DATA_ERROR; } } +#endif + return(tuple); +} +/**********************************************************//** +Creates a data tuple to a memory heap. The default value for number +of fields used in record comparisons for this tuple is n_fields. +@return own: created tuple */ +UNIV_INLINE +dtuple_t* +dtuple_create( +/*==========*/ + mem_heap_t* heap, /*!< in: memory heap where the tuple + is created, DTUPLE_EST_ALLOC(n_fields) + bytes will be allocated from this heap */ + ulint n_fields) /*!< in: number of fields */ +{ + void* buf; + ulint buf_size; + dtuple_t* tuple; + + ut_ad(heap); + + buf_size = DTUPLE_EST_ALLOC(n_fields); + buf = mem_heap_alloc(heap, buf_size); + + tuple = dtuple_create_from_mem(buf, buf_size, n_fields); + +#ifdef UNIV_DEBUG UNIV_MEM_INVALID(tuple->fields, n_fields * sizeof *tuple->fields); #endif + return(tuple); } From cb80ad09da1571b6ecf3668ced4f0272d9ef0167 Mon Sep 17 00:00:00 2001 From: Vasil Dimov Date: Thu, 29 Dec 2011 16:19:33 +0200 Subject: [PATCH 254/288] Partial fix for Bug#11764622 57480: MEMORY LEAK WHEN HAVING 256+ TABLES Port vasil.dimov@oracle.com-20111205083046-jtgi1emlvtfnjatt from mysql-trunk --- storage/innobase/handler/ha_innodb.cc | 70 +++++++++++++-------------- storage/innobase/handler/ha_innodb.h | 13 ++--- storage/innobase/include/row0sel.h | 7 ++- storage/innobase/row/row0sel.c | 8 ++- 4 files changed, 55 insertions(+), 43 deletions(-) diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 7f587a31039..4c947e532b1 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -3737,22 +3737,9 @@ ha_innobase::open( DBUG_RETURN(1); } - /* Create buffers for packing the fields of a record. Why - table->reclength did not work here? Obviously, because char - fields when packed actually became 1 byte longer, when we also - stored the string length as the first byte. */ - - upd_and_key_val_buff_len = - table->s->reclength + table->s->max_key_length - + MAX_REF_PARTS * 3; - if (!(uchar*) my_multi_malloc(MYF(MY_WME), - &upd_buff, upd_and_key_val_buff_len, - &key_val_buff, upd_and_key_val_buff_len, - NullS)) { - free_share(share); - - DBUG_RETURN(1); - } + /* Will be allocated if it is needed in ::update_row() */ + upd_buf = NULL; + upd_buf_size = 0; /* We look for pattern #P# to see if the table is partitioned MySQL table. The retry logic for partitioned tables is a @@ -3793,7 +3780,6 @@ retry: "how you can resolve the problem.\n", norm_name); free_share(share); - my_free(upd_buff); my_errno = ENOENT; DBUG_RETURN(HA_ERR_NO_SUCH_TABLE); @@ -3809,7 +3795,6 @@ retry: "how you can resolve the problem.\n", norm_name); free_share(share); - my_free(upd_buff); my_errno = ENOENT; dict_table_decrement_handle_count(ib_table, FALSE); @@ -4006,7 +3991,13 @@ ha_innobase::close(void) row_prebuilt_free(prebuilt, FALSE); - my_free(upd_buff); + if (upd_buf != NULL) { + ut_ad(upd_buf_size != 0); + my_free(upd_buf); + upd_buf = NULL; + upd_buf_size = 0; + } + free_share(share); /* Tell InnoDB server that there might be work for @@ -5299,6 +5290,23 @@ ha_innobase::update_row( ut_a(prebuilt->trx == trx); + if (upd_buf == NULL) { + ut_ad(upd_buf_size == 0); + + /* Create a buffer for packing the fields of a record. Why + table->reclength did not work here? Obviously, because char + fields when packed actually became 1 byte longer, when we also + stored the string length as the first byte. */ + + upd_buf_size = table->s->reclength + table->s->max_key_length + + MAX_REF_PARTS * 3; + upd_buf = (uchar*) my_malloc(upd_buf_size, MYF(MY_WME)); + if (upd_buf == NULL) { + upd_buf_size = 0; + DBUG_RETURN(HA_ERR_OUT_OF_MEM); + } + } + ha_statistic_increment(&SSV::ha_update_count); if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE) @@ -5311,11 +5319,10 @@ ha_innobase::update_row( } /* Build an update vector from the modified fields in the rows - (uses upd_buff of the handle) */ + (uses upd_buf of the handle) */ calc_row_difference(uvect, (uchar*) old_row, new_row, table, - upd_buff, (ulint)upd_and_key_val_buff_len, - prebuilt, user_thd); + upd_buf, upd_buf_size, prebuilt, user_thd); /* This is not a delete */ prebuilt->upd_node->is_delete = FALSE; @@ -5692,8 +5699,7 @@ ha_innobase::index_read( row_sel_convert_mysql_key_to_innobase( prebuilt->search_tuple, - (byte*) key_val_buff, - (ulint)upd_and_key_val_buff_len, + srch_key_val1, sizeof(srch_key_val1), index, (byte*) key_ptr, (ulint) key_len, @@ -7511,12 +7517,6 @@ ha_innobase::records_in_range( { KEY* key; dict_index_t* index; - uchar* key_val_buff2 = (uchar*) my_malloc( - table->s->reclength - + table->s->max_key_length + 100, - MYF(MY_FAE)); - ulint buff2_len = table->s->reclength - + table->s->max_key_length + 100; dtuple_t* range_start; dtuple_t* range_end; ib_int64_t n_rows; @@ -7568,8 +7568,8 @@ ha_innobase::records_in_range( dict_index_copy_types(range_end, index, key->key_parts); row_sel_convert_mysql_key_to_innobase( - range_start, (byte*) key_val_buff, - (ulint)upd_and_key_val_buff_len, + range_start, + srch_key_val1, sizeof(srch_key_val1), index, (byte*) (min_key ? min_key->key : (const uchar*) 0), @@ -7580,8 +7580,9 @@ ha_innobase::records_in_range( : range_start->n_fields == 0); row_sel_convert_mysql_key_to_innobase( - range_end, (byte*) key_val_buff2, - buff2_len, index, + range_end, + srch_key_val2, sizeof(srch_key_val2), + index, (byte*) (max_key ? max_key->key : (const uchar*) 0), (ulint) (max_key ? max_key->length : 0), @@ -7608,7 +7609,6 @@ ha_innobase::records_in_range( mem_heap_free(heap); func_exit: - my_free(key_val_buff2); prebuilt->trx->op_info = (char*)""; diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h index 7ab91a12e81..5fcac4589cc 100644 --- a/storage/innobase/handler/ha_innodb.h +++ b/storage/innobase/handler/ha_innodb.h @@ -78,13 +78,14 @@ class ha_innobase: public handler INNOBASE_SHARE* share; /*!< information for MySQL table locking */ - uchar* upd_buff; /*!< buffer used in updates */ - uchar* key_val_buff; /*!< buffer used in converting + uchar* upd_buf; /*!< buffer used in updates */ + ulint upd_buf_size; /*!< the size of upd_buf in bytes */ + uchar srch_key_val1[REC_VERSION_56_MAX_INDEX_COL_LEN + 2]; + uchar srch_key_val2[REC_VERSION_56_MAX_INDEX_COL_LEN + 2]; + /*!< buffers used in converting search key values from MySQL format - to Innodb format */ - ulong upd_and_key_val_buff_len; - /* the length of each of the previous - two buffers */ + to InnoDB format. "+ 2" for the two + bytes where the length is stored */ Table_flags int_table_flags; uint primary_key; ulong start_of_scan; /*!< this is set to 1 when we are diff --git a/storage/innobase/include/row0sel.h b/storage/innobase/include/row0sel.h index 8544b9d08ba..1c4ea6f7244 100644 --- a/storage/innobase/include/row0sel.h +++ b/storage/innobase/include/row0sel.h @@ -128,7 +128,12 @@ row_sel_convert_mysql_key_to_innobase( in the tuple is already according to index! */ byte* buf, /*!< in: buffer to use in field - conversions */ + conversions; NOTE that dtuple->data + may end up pointing inside buf so + do not discard that buffer while + the tuple is being used. See + row_mysql_store_col_in_innobase_format() + in the case of DATA_INT */ ulint buf_len, /*!< in: buffer length */ dict_index_t* index, /*!< in: index of the key value */ const byte* key_ptr, /*!< in: MySQL key value */ diff --git a/storage/innobase/row/row0sel.c b/storage/innobase/row/row0sel.c index 10dfd51e9b3..20d45c1884d 100644 --- a/storage/innobase/row/row0sel.c +++ b/storage/innobase/row/row0sel.c @@ -2301,7 +2301,12 @@ row_sel_convert_mysql_key_to_innobase( in the tuple is already according to index! */ byte* buf, /*!< in: buffer to use in field - conversions */ + conversions; NOTE that dtuple->data + may end up pointing inside buf so + do not discard that buffer while + the tuple is being used. See + row_mysql_store_col_in_innobase_format() + in the case of DATA_INT */ ulint buf_len, /*!< in: buffer length */ dict_index_t* index, /*!< in: index of the key value */ const byte* key_ptr, /*!< in: MySQL key value */ @@ -2433,6 +2438,7 @@ row_sel_convert_mysql_key_to_innobase( /* Storing may use at most data_len bytes of buf */ if (UNIV_LIKELY(!is_null)) { + ut_a(buf + data_len <= original_buf + buf_len); row_mysql_store_col_in_innobase_format( dfield, buf, FALSE, /* MySQL key value format col */ From d9fcec5acdbe5aa06428dfbb9b828ebef845e7ca Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Thu, 29 Dec 2011 22:29:02 +0100 Subject: [PATCH 255/288] Make test results stable (they weren't, because filesort() used to read from a heap temptable, which uses pointers to records (that is, byte* pointers) as rowids. This meant that for rows with the same sort key value, the order was determined by memory layout. --- mysql-test/r/fulltext_order_by.result | 36 +++++++++++++-------------- mysql-test/t/fulltext_order_by.test | 4 +-- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/mysql-test/r/fulltext_order_by.result b/mysql-test/r/fulltext_order_by.result index 2085e7ea885..9203f40ba6c 100644 --- a/mysql-test/r/fulltext_order_by.result +++ b/mysql-test/r/fulltext_order_by.result @@ -44,24 +44,24 @@ a FORMAT(MATCH (message) AGAINST ('steve'),6) SELECT a, MATCH (message) AGAINST ('steve' IN BOOLEAN MODE) FROM t1 WHERE a=7 and MATCH (message) AGAINST ('steve' IN BOOLEAN MODE) ORDER BY 1; a MATCH (message) AGAINST ('steve' IN BOOLEAN MODE) 7 1 -SELECT a, FORMAT(MATCH (message) AGAINST ('steve'),6) as rel FROM t1 ORDER BY rel; -a rel -1 0.000000 -5 0.000000 -2 0.000000 -6 0.000000 -3 0.000000 -7 0.895690 -4 0.905873 -SELECT a, MATCH (message) AGAINST ('steve' IN BOOLEAN MODE) as rel FROM t1 ORDER BY rel; -a rel -1 0 -2 0 -3 0 -5 0 -6 0 -4 1 -7 1 +SELECT IF(a=7,'steve-is-cool',IF(a=4,'cool', 'other')), FORMAT(MATCH (message) AGAINST ('steve'),6) as rel FROM t1 ORDER BY rel; +IF(a=7,'steve-is-cool',IF(a=4,'cool', 'other')) rel +other 0.000000 +other 0.000000 +other 0.000000 +other 0.000000 +other 0.000000 +steve-is-cool 0.895690 +cool 0.905873 +SELECT IF(a=7,'steve-is-cool',IF(a=4,'cool', 'other')), MATCH (message) AGAINST ('steve' IN BOOLEAN MODE) as rel FROM t1 ORDER BY rel; +IF(a=7,'steve-is-cool',IF(a=4,'cool', 'other')) rel +other 0 +other 0 +other 0 +other 0 +other 0 +steve-is-cool 1 +cool 1 alter table t1 add key m (message); explain SELECT message FROM t1 WHERE MATCH (message) AGAINST ('steve') ORDER BY message; id select_type table type possible_keys key key_len ref rows Extra diff --git a/mysql-test/t/fulltext_order_by.test b/mysql-test/t/fulltext_order_by.test index 814cd4a5954..6a5c7eb1615 100644 --- a/mysql-test/t/fulltext_order_by.test +++ b/mysql-test/t/fulltext_order_by.test @@ -28,8 +28,8 @@ SELECT a, FORMAT(MATCH (message) AGAINST ('steve'),6) FROM t1 WHERE a=7 and MATC SELECT a, MATCH (message) AGAINST ('steve' IN BOOLEAN MODE) FROM t1 WHERE a=7 and MATCH (message) AGAINST ('steve' IN BOOLEAN MODE) ORDER BY 1; # ORDER BY MATCH -SELECT a, FORMAT(MATCH (message) AGAINST ('steve'),6) as rel FROM t1 ORDER BY rel; -SELECT a, MATCH (message) AGAINST ('steve' IN BOOLEAN MODE) as rel FROM t1 ORDER BY rel; +SELECT IF(a=7,'steve-is-cool',IF(a=4,'cool', 'other')), FORMAT(MATCH (message) AGAINST ('steve'),6) as rel FROM t1 ORDER BY rel; +SELECT IF(a=7,'steve-is-cool',IF(a=4,'cool', 'other')), MATCH (message) AGAINST ('steve' IN BOOLEAN MODE) as rel FROM t1 ORDER BY rel; # # BUG#6635 - test_if_skip_sort_order() thought it can skip filesort From 0346e25f07266b6905f8bd5dbb664e32be3155fd Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Fri, 30 Dec 2011 11:34:29 +0100 Subject: [PATCH 256/288] Continuation of the efforts in previous cset. --- mysql-test/r/fulltext_order_by.result | 18 +++++++++--------- mysql-test/t/fulltext_order_by.test | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/mysql-test/r/fulltext_order_by.result b/mysql-test/r/fulltext_order_by.result index 9203f40ba6c..419c1f53a2c 100644 --- a/mysql-test/r/fulltext_order_by.result +++ b/mysql-test/r/fulltext_order_by.result @@ -53,15 +53,15 @@ other 0.000000 other 0.000000 steve-is-cool 0.895690 cool 0.905873 -SELECT IF(a=7,'steve-is-cool',IF(a=4,'cool', 'other')), MATCH (message) AGAINST ('steve' IN BOOLEAN MODE) as rel FROM t1 ORDER BY rel; -IF(a=7,'steve-is-cool',IF(a=4,'cool', 'other')) rel -other 0 -other 0 -other 0 -other 0 -other 0 -steve-is-cool 1 -cool 1 +SELECT IF(a=7,'match',IF(a=4,'match', 'no-match')), MATCH (message) AGAINST ('steve' IN BOOLEAN MODE) as rel FROM t1 ORDER BY rel; +IF(a=7,'match',IF(a=4,'match', 'no-match')) rel +no-match 0 +no-match 0 +no-match 0 +no-match 0 +no-match 0 +match 1 +match 1 alter table t1 add key m (message); explain SELECT message FROM t1 WHERE MATCH (message) AGAINST ('steve') ORDER BY message; id select_type table type possible_keys key key_len ref rows Extra diff --git a/mysql-test/t/fulltext_order_by.test b/mysql-test/t/fulltext_order_by.test index 6a5c7eb1615..0f800e5c077 100644 --- a/mysql-test/t/fulltext_order_by.test +++ b/mysql-test/t/fulltext_order_by.test @@ -29,7 +29,7 @@ SELECT a, MATCH (message) AGAINST ('steve' IN BOOLEAN MODE) FROM t1 WHERE a=7 an # ORDER BY MATCH SELECT IF(a=7,'steve-is-cool',IF(a=4,'cool', 'other')), FORMAT(MATCH (message) AGAINST ('steve'),6) as rel FROM t1 ORDER BY rel; -SELECT IF(a=7,'steve-is-cool',IF(a=4,'cool', 'other')), MATCH (message) AGAINST ('steve' IN BOOLEAN MODE) as rel FROM t1 ORDER BY rel; +SELECT IF(a=7,'match',IF(a=4,'match', 'no-match')), MATCH (message) AGAINST ('steve' IN BOOLEAN MODE) as rel FROM t1 ORDER BY rel; # # BUG#6635 - test_if_skip_sort_order() thought it can skip filesort From 0868847b55a9ac7b05ca90dc8dbb1af427ef2a11 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 30 Dec 2011 20:22:52 +0100 Subject: [PATCH 257/288] Update version in configure.in (was forgotten in 5.3.3 release). --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index bea191e370e..b3ed594ef70 100644 --- a/configure.in +++ b/configure.in @@ -13,7 +13,7 @@ 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([MariaDB Server], [5.3.3-MariaDB-rc], [], [mysql]) +AC_INIT([MariaDB Server], [5.3.4-MariaDB-rc], [], [mysql]) AC_CONFIG_SRCDIR([sql/mysqld.cc]) AC_CANONICAL_SYSTEM From 7714496dc1c72d01fd214cb7737ca4216a982e0f Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Fri, 30 Dec 2011 22:19:05 +0100 Subject: [PATCH 258/288] Make test results stable. --- mysql-test/t/union.test | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/t/union.test b/mysql-test/t/union.test index d3bc94961ef..fefd67fd2f7 100644 --- a/mysql-test/t/union.test +++ b/mysql-test/t/union.test @@ -1137,6 +1137,7 @@ SELECT * FROM t1 UNION SELECT * FROM t1 ORDER BY MATCH(a) AGAINST ('+abc' IN BOOLEAN MODE); --echo # Should not crash +--sorted_result (SELECT * FROM t1) UNION (SELECT * FROM t1) ORDER BY MATCH(a) AGAINST ('+abc' IN BOOLEAN MODE); From 251fa88afacbd03a00894c04037d987b62f3ca58 Mon Sep 17 00:00:00 2001 From: Tatjana Azundris Nuernberg Date: Mon, 2 Jan 2012 06:25:48 +0000 Subject: [PATCH 259/288] BUG#11755281/47032: ERROR 2006 / ERROR 2013 INSTEAD OF PROPER ERROR MESSAGE If init_command was incorrect, we couldn't let users execute queries, but we couldn't report the issue to the client either as it does not expect error messages before even sending a command. Thus, we simply disconnected them without throwing a clear error. We now go through the proper sequence once (without executing any user statements) so we can report back what the problem is. Only then do we disconnect the user. As always, root remains unaffected by this as init_command is (still) not executed for them. mysql-test/r/init_connect.result: We now report a proper error if init_command fails. Expect as much. mysql-test/t/init_connect.test: We now report a proper error if init_command fails. Expect as much. sql/sql_connect.cc: If init_command fails, throw an error explaining this to the user. --- mysql-test/r/init_connect.result | 2 ++ mysql-test/t/init_connect.test | 8 ++++++++ sql/sql_connect.cc | 29 +++++++++++++++++++++++++++-- 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/init_connect.result b/mysql-test/r/init_connect.result index f5ec0bdc932..0ff6c206422 100644 --- a/mysql-test/r/init_connect.result +++ b/mysql-test/r/init_connect.result @@ -20,6 +20,8 @@ hex(a) 616263 set GLOBAL init_connect="adsfsdfsdfs"; select @a; +ERROR 08S01: Aborted connection to db: 'test' user: 'user_1' host: 'localhost' (init_connect command failed) +select @a; Got one of the listed errors drop table t1; End of 4.1 tests diff --git a/mysql-test/t/init_connect.test b/mysql-test/t/init_connect.test index b6bac5f65fa..e96d02fe0d1 100644 --- a/mysql-test/t/init_connect.test +++ b/mysql-test/t/init_connect.test @@ -36,6 +36,14 @@ connection con0; set GLOBAL init_connect="adsfsdfsdfs"; connect (con5,localhost,user_1,,); connection con5; +# BUG#11755281/47032: ERROR 2006 / ERROR 2013 INSTEAD OF PROPER ERROR MESSAGE +# We now throw a proper error message here: +--replace_regex /connection .* to/connection to/ +--error ER_NEW_ABORTING_CONNECTION +select @a; +# We got disconnected after receiving the above error message; any further +# requests should fail with a notice that no one's listening to us. +# --error CR_SERVER_GONE_ERROR,CR_SERVER_LOST --error 2013,2006 select @a; connection con0; diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 44b4af74ef1..03f9d1e2732 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -1342,13 +1342,38 @@ static void prepare_new_connection_state(THD* thd) execute_init_command(thd, &sys_init_connect, &LOCK_sys_init_connect); if (thd->is_error()) { - thd->killed= THD::KILL_CONNECTION; + ulong packet_length; + NET *net= &thd->net; + sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION), - thd->thread_id,(thd->db ? thd->db : "unconnected"), + thd->thread_id, + thd->db ? thd->db : "unconnected", sctx->user ? sctx->user : "unauthenticated", sctx->host_or_ip, "init_connect command failed"); sql_print_warning("%s", thd->main_da.message()); + + thd->lex->current_select= 0; + my_net_set_read_timeout(net, thd->variables.net_wait_timeout); + thd->clear_error(); + net_new_transaction(net); + packet_length= my_net_read(net); + /* + If my_net_read() failed, my_error() has been already called, + and the main Diagnostics Area contains an error condition. + */ + if (packet_length != packet_error) + my_error(ER_NEW_ABORTING_CONNECTION, MYF(0), + thd->thread_id, + thd->db ? thd->db : "unconnected", + sctx->user ? sctx->user : "unauthenticated", + sctx->host_or_ip, "init_connect command failed"); + + thd->server_status&= ~SERVER_STATUS_CLEAR_SET; + net_end_statement(thd); + thd->killed = THD::KILL_CONNECTION; + return; } + thd->proc_info=0; thd->set_time(); thd->init_for_queries(); From cd55894a52b5b2bf4a740eb0f39d91d7a82f673c Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Mon, 2 Jan 2012 20:06:36 -0800 Subject: [PATCH 260/288] Fixed LP bug #910083. The patch for bug 685411 erroneously removed a call of engine->set_thd() from Item_subselect::fix_fields(). --- mysql-test/r/trigger.result | 44 +++++++++++++++++++++++++++++++++++++ mysql-test/t/trigger.test | 40 +++++++++++++++++++++++++++++++++ sql/item_subselect.cc | 3 +-- 3 files changed, 85 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result index 479778deca3..9cf769983c6 100644 --- a/mysql-test/r/trigger.result +++ b/mysql-test/r/trigger.result @@ -2134,3 +2134,47 @@ i 2 drop table t1,t2; End of 5.2 tests. +# +# BUG #910083: materialized subquery in a trigger +# +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='materialization=on'; +CREATE TABLE t1 (a int); +CREATE TABLE t2 (b int); +CREATE TRIGGER tr AFTER UPDATE ON t1 FOR EACH ROW +UPDATE t2 SET b = (SELECT COUNT(a) FROM t1); +INSERT INTO t1 +VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9); +INSERT INTO t2 +VALUES (0),(0),(0),(0),(0),(0),(0),(0),(0); +UPDATE t1 SET a = 3; +SELECT COUNT(*) FROM t1; +COUNT(*) +9 +SELECT * FROM t2; +b +9 +9 +9 +9 +9 +9 +9 +9 +9 +UPDATE t1 SET a = 2; +SELECT * FROM t2; +b +9 +9 +9 +9 +9 +9 +9 +9 +9 +SET optimizer_switch=@save_optimizer_switch; +DROP TRIGGER tr; +DROP TABLE t1, t2; +End of 5.3 tests. diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test index 8d84330ec44..4b261c9f023 100644 --- a/mysql-test/t/trigger.test +++ b/mysql-test/t/trigger.test @@ -2434,3 +2434,43 @@ select * from t2; drop table t1,t2; --echo End of 5.2 tests. + +--echo # +--echo # BUG #910083: materialized subquery in a trigger +--echo # + +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='materialization=on'; + +CREATE TABLE t1 (a int); +CREATE TABLE t2 (b int); + +CREATE TRIGGER tr AFTER UPDATE ON t1 FOR EACH ROW + UPDATE t2 SET b = (SELECT COUNT(a) FROM t1); + +INSERT INTO t1 + VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9); + +INSERT INTO t2 + VALUES (0),(0),(0),(0),(0),(0),(0),(0),(0); + +send + UPDATE t1 SET a = 3; + +connect(con1,localhost,root,,); + SELECT COUNT(*) FROM t1; +disconnect con1; + +connection default; +reap; +SELECT * FROM t2; +UPDATE t1 SET a = 2; +SELECT * FROM t2; + +SET optimizer_switch=@save_optimizer_switch; + +DROP TRIGGER tr; +DROP TABLE t1, t2; + +--echo End of 5.3 tests. + diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 48522f8a70f..699c6e11cc1 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -211,8 +211,7 @@ bool Item_subselect::fix_fields(THD *thd_param, Item **ref) bool res; DBUG_ASSERT(fixed == 0); - /* There is no reason to get a different THD. */ - DBUG_ASSERT(thd == thd_param); + engine->set_thd((thd= thd_param)); if (!done_first_fix_fields) { done_first_fix_fields= TRUE; From 0b590282fc116a1911eabe4cf1c7804a66f9bb48 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Sun, 8 Jan 2012 14:43:14 +0400 Subject: [PATCH 261/288] BUG#912510: Crash in do_copy_not_null with semijoin=ON, firstmatch=ON, aggregate ... - Create/use do_copy_nullable_row_to_notnull() function for ref access, which is used when copying from not-NULL field in table that can be NULL-complemented to not-NULL field. --- mysql-test/r/subselect_sj.result | 17 ++++++++++++++++ mysql-test/r/subselect_sj_jcl6.result | 17 ++++++++++++++++ mysql-test/t/subselect_sj.test | 19 ++++++++++++++++++ sql/field_conv.cc | 29 ++++++++++++++++++++++++++- sql/sql_select.cc | 3 +++ 5 files changed, 84 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/subselect_sj.result b/mysql-test/r/subselect_sj.result index b1b0bde7c57..f5c3f84bcd7 100644 --- a/mysql-test/r/subselect_sj.result +++ b/mysql-test/r/subselect_sj.result @@ -2152,4 +2152,21 @@ c c set optimizer_prune_level= @opl_901399; set optimizer_switch= @os_091399; DROP TABLE t1,t2; +# +# BUG#912510: Crash in do_copy_not_null with semijoin=ON, firstmatch=ON, aggregate ... +# +CREATE TABLE t1 ( a VARCHAR(1) NOT NULL ); +INSERT INTO t1 VALUES ('k'),('l'); +CREATE TABLE t2 ( b VARCHAR(1) NOT NULL, KEY(b) ); +INSERT INTO t2 VALUES ('k'),('l'); +CREATE TABLE t3 ( c VARCHAR(1) NOT NULL, KEY(c) ); +INSERT INTO t3 VALUES ('m'),('n'); +SELECT a, COUNT(*) FROM t1 +WHERE a IN ( +SELECT b FROM t2 force index(b), t3 force index(c) +WHERE c = b AND b = a +); +a COUNT(*) +NULL 0 +DROP TABLE t1, t2, t3; 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 2df7d99ee64..21a8ea39457 100644 --- a/mysql-test/r/subselect_sj_jcl6.result +++ b/mysql-test/r/subselect_sj_jcl6.result @@ -2166,6 +2166,23 @@ c c set optimizer_prune_level= @opl_901399; set optimizer_switch= @os_091399; DROP TABLE t1,t2; +# +# BUG#912510: Crash in do_copy_not_null with semijoin=ON, firstmatch=ON, aggregate ... +# +CREATE TABLE t1 ( a VARCHAR(1) NOT NULL ); +INSERT INTO t1 VALUES ('k'),('l'); +CREATE TABLE t2 ( b VARCHAR(1) NOT NULL, KEY(b) ); +INSERT INTO t2 VALUES ('k'),('l'); +CREATE TABLE t3 ( c VARCHAR(1) NOT NULL, KEY(c) ); +INSERT INTO t3 VALUES ('m'),('n'); +SELECT a, COUNT(*) FROM t1 +WHERE a IN ( +SELECT b FROM t2 force index(b), t3 force index(c) +WHERE c = b AND b = a +); +a COUNT(*) +NULL 0 +DROP TABLE t1, t2, t3; 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 aee61e9bca3..f34cf5ba338 100644 --- a/mysql-test/t/subselect_sj.test +++ b/mysql-test/t/subselect_sj.test @@ -1997,6 +1997,25 @@ set optimizer_switch= @os_091399; DROP TABLE t1,t2; +--echo # +--echo # BUG#912510: Crash in do_copy_not_null with semijoin=ON, firstmatch=ON, aggregate ... +--echo # +CREATE TABLE t1 ( a VARCHAR(1) NOT NULL ); +INSERT INTO t1 VALUES ('k'),('l'); + +CREATE TABLE t2 ( b VARCHAR(1) NOT NULL, KEY(b) ); +INSERT INTO t2 VALUES ('k'),('l'); + +CREATE TABLE t3 ( c VARCHAR(1) NOT NULL, KEY(c) ); +INSERT INTO t3 VALUES ('m'),('n'); + +SELECT a, COUNT(*) FROM t1 + WHERE a IN ( + SELECT b FROM t2 force index(b), t3 force index(c) + WHERE c = b AND b = a + ); + +DROP TABLE t1, t2, t3; # The following command must be the last one the file set optimizer_switch=@subselect_sj_tmp; diff --git a/sql/field_conv.cc b/sql/field_conv.cc index ce914f7b368..ed910c4ef70 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -248,6 +248,25 @@ static void do_outer_field_null(Copy_field *copy) } } +/* + Copy: (not-NULL field in table that can be NULL-complemented) -> (not-NULL + field) +*/ +static void do_copy_nullable_row_to_notnull(Copy_field *copy) +{ + if (*copy->null_row || + (copy->from_null_ptr && (*copy->from_null_ptr & copy->from_bit))) + { + copy->to_field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, + WARN_DATA_TRUNCATED, 1); + copy->to_field->reset(); + } + else + { + (copy->do_copy2)(copy); + } + +} /* Copy: (NULL-able field) -> (not NULL-able field) */ static void do_copy_not_null(Copy_field *copy) @@ -638,7 +657,15 @@ void Copy_field::set(Field *to,Field *from,bool save) else if (to_field == to_field->table->next_number_field) do_copy= do_copy_next_number; else - do_copy= do_copy_not_null; + { + if (!from_null_ptr) + { + null_row= &from->table->null_row; + do_copy= do_copy_nullable_row_to_notnull; + } + else + do_copy= do_copy_not_null; + } } } else if (to_field->real_maybe_null()) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index cb620495897..c332b13dff6 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -646,6 +646,9 @@ JOIN::prepare(Item ***rref_pointer_array, aggregate functions and non-aggregate fields, any non-aggregated field may produce a NULL value. Set all fields of each table as nullable before semantic analysis to take into account this change of nullability. + + Note: this loop doesn't touch tables inside merged semi-joins, because + subquery-to-semijoin conversion has not been done yet. This is intended. */ if (mixed_implicit_grouping) tbl->table->maybe_null= 1; From cf86abffbfe5fb95dc79260e6a21332d1adadd2a Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Sun, 8 Jan 2012 21:14:07 +0100 Subject: [PATCH 262/288] MDEV-77 - possible deadlock in XtraDB async io subsystem on Windows. Split IO threads into ones that handle only read completion and ones that handle only write completion, as it was originally done, but got lost with "completion port" patch. The reason we need to have dedicated read and dedicated write threads is that read completion routine can block waiting for write io to complete, and in rare cases where all io threads are handling async reads, it can deadlock. --- storage/xtradb/os/os0file.c | 56 +++++++++++++++++++++++++++++-------- 1 file changed, 45 insertions(+), 11 deletions(-) diff --git a/storage/xtradb/os/os0file.c b/storage/xtradb/os/os0file.c index ef20869c4c5..810a254f9fc 100644 --- a/storage/xtradb/os/os0file.c +++ b/storage/xtradb/os/os0file.c @@ -249,6 +249,8 @@ UNIV_INTERN ulint os_n_pending_reads = 0; #ifdef _WIN32 /** IO completion port used by background io threads */ static HANDLE completion_port; +/** IO completion port used by background io READ threads */ +static HANDLE read_completion_port; /** Thread local storage index for the per-thread event used for synchronous IO */ static DWORD tls_sync_io = TLS_OUT_OF_INDEXES; #endif @@ -3251,9 +3253,10 @@ os_aio_init( os_last_printout = time(NULL); #ifdef _WIN32 - ut_a(completion_port == 0); + ut_a(completion_port == 0 && read_completion_port == 0); completion_port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0); - ut_a(completion_port); + read_completion_port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0); + ut_a(completion_port && read_completion_port); #endif } @@ -3299,6 +3302,7 @@ os_aio_array_wake_win_aio_at_shutdown( if(completion_port) { PostQueuedCompletionStatus(completion_port, 0, IOCP_SHUTDOWN_KEY, NULL); + PostQueuedCompletionStatus(read_completion_port, 0, IOCP_SHUTDOWN_KEY, NULL); } } #endif @@ -3860,6 +3864,9 @@ try_again: } #ifdef WIN_ASYNC_IO +#define READ_SEGMENT(x) (x < srv_n_read_io_threads) +#define WRITE_SEGMENT(x) !READ_SEGMENT(x) + /**********************************************************************//** This function is only used in Windows asynchronous i/o. Waits for an aio operation to complete. This function is used to wait the @@ -3898,18 +3905,45 @@ os_aio_windows_handle( DWORD len; BOOL retry = FALSE; ULONG_PTR key; + HANDLE port = READ_SEGMENT(segment)? read_completion_port : completion_port; - ret = GetQueuedCompletionStatus(completion_port, &len, &key, - (OVERLAPPED **)&slot, INFINITE); + for(;;) { + ret = GetQueuedCompletionStatus(port, &len, &key, + (OVERLAPPED **)&slot, INFINITE); - /* If shutdown key was received, repost the shutdown message and exit */ - if (ret && (key == IOCP_SHUTDOWN_KEY)) { - PostQueuedCompletionStatus(completion_port, 0, key, NULL); - os_thread_exit(NULL); - } + /* If shutdown key was received, repost the shutdown message and exit */ + if (ret && (key == IOCP_SHUTDOWN_KEY)) { + PostQueuedCompletionStatus(port, 0, key, NULL); + os_thread_exit(NULL); + } - if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) { - os_thread_exit(NULL); + if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) { + os_thread_exit(NULL); + } + + if(WRITE_SEGMENT(segment)&& slot->type == OS_FILE_READ) { + /* + Redirect read completions to the dedicated completion port + and thread. We need to split read and write threads. If we do not + do that, and just allow all io threads process all IO, it is possible + to get stuck in a deadlock in buffer pool code, + + Currently, the problem is solved this way - "write io" threads + always get all completion notifications, from both async reads and + writes. Write completion is handled in the same thread that gets it. + Read completion is forwarded via PostQueueCompletionStatus()) + to the second completion port dedicated solely to reads. One of the + "read io" threads waiting on this port will finally handle the IO. + + Forwarding IO completion this way costs a context switch , and this + seems tolerable since asynchronous reads are by far less frequent. + */ + ut_a(PostQueuedCompletionStatus(read_completion_port, len, key, + &slot->control)); + } + else { + break; + } } From a148cf7fb092578d85f0dd2936e933b2acbb88e5 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Mon, 9 Jan 2012 13:49:47 +0200 Subject: [PATCH 263/288] Fixed that --sorted-result in mysql-test-run also works for exec mysql-test/r/information_schema_all_engines.result: Update result mysql-test/t/information_schema_all_engines.test: Added --sorted-results as tables in information_schema are not sorted. --- client/mysqltest.cc | 50 +++-- .../r/information_schema_all_engines.result | 200 +++++++++--------- .../t/information_schema_all_engines.test | 8 +- 3 files changed, 140 insertions(+), 118 deletions(-) diff --git a/client/mysqltest.cc b/client/mysqltest.cc index 6d54fa8ad7b..77fbbb1757e 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2000, 2011, Oracle and/or its affiliates. - Copyright (c) 2009-2011 Monty Program Ab. + Copyright (c) 2009-2012 Monty Program Ab. 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 @@ -732,7 +732,8 @@ void replace_dynstr_append_mem(DYNAMIC_STRING *ds, const char *val, int len); void replace_dynstr_append(DYNAMIC_STRING *ds, const char *val); void replace_dynstr_append_uint(DYNAMIC_STRING *ds, uint val); -void dynstr_append_sorted(DYNAMIC_STRING* ds, DYNAMIC_STRING* ds_input); +void dynstr_append_sorted(DYNAMIC_STRING* ds, DYNAMIC_STRING* ds_input, + bool keep_header); static int match_expected_error(struct st_command *command, unsigned int err_errno, @@ -2790,6 +2791,7 @@ void do_exec(struct st_command *command) FILE *res_file; char *cmd= command->first_argument; DYNAMIC_STRING ds_cmd; + DYNAMIC_STRING ds_sorted, *ds_result; DBUG_ENTER("do_exec"); DBUG_PRINT("enter", ("cmd: '%s'", cmd)); @@ -2835,6 +2837,13 @@ void do_exec(struct st_command *command) die("popen(\"%s\", \"r\") failed", command->first_argument); } + ds_result= &ds_res; + if (display_result_sorted) + { + init_dynamic_string(&ds_sorted, "", 1024, 1024); + ds_result= &ds_sorted; + } + while (fgets(buf, sizeof(buf), res_file)) { if (disable_result_log) @@ -2844,10 +2853,17 @@ void do_exec(struct st_command *command) } else { - replace_dynstr_append(&ds_res, buf); + replace_dynstr_append(ds_result, buf); } } error= pclose(res_file); + + if (display_result_sorted) + { + dynstr_append_sorted(&ds_res, &ds_sorted, 0); + dynstr_free(&ds_sorted); + } + if (error > 0) { uint status= WEXITSTATUS(error); @@ -7743,7 +7759,7 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags) if (display_result_sorted) { /* Sort the result set and append it to result */ - dynstr_append_sorted(save_ds, &ds_sorted); + dynstr_append_sorted(save_ds, &ds_sorted, 1); ds= save_ds; dynstr_free(&ds_sorted); } @@ -10125,17 +10141,16 @@ void replace_dynstr_append_uint(DYNAMIC_STRING *ds, uint val) } - /* Build a list of pointer to each line in ds_input, sort the list and use the sorted list to append the strings sorted to the output ds SYNOPSIS - dynstr_append_sorted - ds - string where the sorted output will be appended - ds_input - string to be sorted - + dynstr_append_sorted() + ds string where the sorted output will be appended + ds_input string to be sorted + keep_header If header should not be sorted */ static int comp_lines(const char **a, const char **b) @@ -10143,7 +10158,8 @@ static int comp_lines(const char **a, const char **b) return (strcmp(*a,*b)); } -void dynstr_append_sorted(DYNAMIC_STRING* ds, DYNAMIC_STRING *ds_input) +void dynstr_append_sorted(DYNAMIC_STRING* ds, DYNAMIC_STRING *ds_input, + bool keep_header) { unsigned i; char *start= ds_input->str; @@ -10155,11 +10171,14 @@ void dynstr_append_sorted(DYNAMIC_STRING* ds, DYNAMIC_STRING *ds_input) my_init_dynamic_array(&lines, sizeof(const char*), 32, 32); - /* First line is result header, skip past it */ - while (*start && *start != '\n') - start++; - start++; /* Skip past \n */ - dynstr_append_mem(ds, ds_input->str, start - ds_input->str); + if (keep_header) + { + /* First line is result header, skip past it */ + while (*start && *start != '\n') + start++; + start++; /* Skip past \n */ + dynstr_append_mem(ds, ds_input->str, start - ds_input->str); + } /* Insert line(s) in array */ while (*start) @@ -10237,4 +10256,3 @@ char *mysql_authentication_dialog_ask(MYSQL *mysql, int type, return buf; } - diff --git a/mysql-test/r/information_schema_all_engines.result b/mysql-test/r/information_schema_all_engines.result index 7a2c548a329..c2bcbeb2315 100644 --- a/mysql-test/r/information_schema_all_engines.result +++ b/mysql-test/r/information_schema_all_engines.result @@ -13,9 +13,26 @@ FILES GLOBAL_STATUS GLOBAL_VARIABLES INDEX_STATISTICS +INNODB_BUFFER_POOL_PAGES +INNODB_BUFFER_POOL_PAGES_BLOB +INNODB_BUFFER_POOL_PAGES_INDEX +INNODB_CMP +INNODB_CMPMEM +INNODB_CMPMEM_RESET +INNODB_CMP_RESET +INNODB_INDEX_STATS +INNODB_LOCKS +INNODB_LOCK_WAITS +INNODB_RSEG +INNODB_SYS_INDEXES +INNODB_SYS_STATS +INNODB_SYS_TABLES +INNODB_TABLE_STATS +INNODB_TRX KEY_CACHES KEY_COLUMN_USAGE PARTITIONS +PBXT_STATISTICS PLUGINS PROCESSLIST PROFILING @@ -34,25 +51,8 @@ TRIGGERS USER_PRIVILEGES USER_STATISTICS VIEWS -INNODB_BUFFER_POOL_PAGES -PBXT_STATISTICS -INNODB_CMP -INNODB_RSEG -XTRADB_ENHANCEMENTS -INNODB_BUFFER_POOL_PAGES_INDEX XTRADB_ADMIN_COMMAND -INNODB_TRX -INNODB_SYS_TABLES -INNODB_LOCK_WAITS -INNODB_SYS_STATS -INNODB_LOCKS -INNODB_CMPMEM -INNODB_TABLE_STATS -INNODB_SYS_INDEXES -INNODB_CMP_RESET -INNODB_BUFFER_POOL_PAGES_BLOB -INNODB_CMPMEM_RESET -INNODB_INDEX_STATS +XTRADB_ENHANCEMENTS SELECT t.table_name, c1.column_name FROM information_schema.tables t INNER JOIN @@ -66,7 +66,7 @@ FROM information_schema.columns c2 WHERE c2.table_schema = t.table_schema AND c2.table_name = t.table_name AND c2.column_name LIKE '%SCHEMA%' - ); + ) order by t.table_name; table_name column_name CHARACTER_SETS CHARACTER_SET_NAME CLIENT_STATISTICS CLIENT @@ -80,9 +80,26 @@ FILES TABLE_SCHEMA GLOBAL_STATUS VARIABLE_NAME GLOBAL_VARIABLES VARIABLE_NAME INDEX_STATISTICS TABLE_SCHEMA +INNODB_BUFFER_POOL_PAGES page_type +INNODB_BUFFER_POOL_PAGES_BLOB space_id +INNODB_BUFFER_POOL_PAGES_INDEX index_id +INNODB_CMP page_size +INNODB_CMPMEM page_size +INNODB_CMPMEM_RESET page_size +INNODB_CMP_RESET page_size +INNODB_INDEX_STATS table_schema +INNODB_LOCKS lock_id +INNODB_LOCK_WAITS requesting_trx_id +INNODB_RSEG rseg_id +INNODB_SYS_INDEXES TABLE_ID +INNODB_SYS_STATS INDEX_ID +INNODB_SYS_TABLES SCHEMA +INNODB_TABLE_STATS table_schema +INNODB_TRX trx_id KEY_CACHES KEY_CACHE_NAME KEY_COLUMN_USAGE CONSTRAINT_SCHEMA PARTITIONS TABLE_SCHEMA +PBXT_STATISTICS ID PLUGINS PLUGIN_NAME PROCESSLIST ID PROFILING QUERY_ID @@ -101,25 +118,8 @@ TRIGGERS TRIGGER_SCHEMA USER_PRIVILEGES GRANTEE USER_STATISTICS USER VIEWS TABLE_SCHEMA -INNODB_BUFFER_POOL_PAGES page_type -PBXT_STATISTICS ID -INNODB_CMP page_size -INNODB_RSEG rseg_id -XTRADB_ENHANCEMENTS name -INNODB_BUFFER_POOL_PAGES_INDEX index_id XTRADB_ADMIN_COMMAND result_message -INNODB_TRX trx_id -INNODB_SYS_TABLES SCHEMA -INNODB_LOCK_WAITS requesting_trx_id -INNODB_SYS_STATS INDEX_ID -INNODB_LOCKS lock_id -INNODB_CMPMEM page_size -INNODB_TABLE_STATS table_schema -INNODB_SYS_INDEXES TABLE_ID -INNODB_CMP_RESET page_size -INNODB_BUFFER_POOL_PAGES_BLOB space_id -INNODB_CMPMEM_RESET page_size -INNODB_INDEX_STATS table_schema +XTRADB_ENHANCEMENTS name SELECT t.table_name, c1.column_name FROM information_schema.tables t INNER JOIN @@ -133,7 +133,7 @@ FROM information_schema.columns c2 WHERE c2.table_schema = 'information_schema' AND c2.table_name = t.table_name AND c2.column_name LIKE '%SCHEMA%' - ); + ) order by t.table_name; table_name column_name CHARACTER_SETS CHARACTER_SET_NAME CLIENT_STATISTICS CLIENT @@ -147,9 +147,26 @@ FILES TABLE_SCHEMA GLOBAL_STATUS VARIABLE_NAME GLOBAL_VARIABLES VARIABLE_NAME INDEX_STATISTICS TABLE_SCHEMA +INNODB_BUFFER_POOL_PAGES page_type +INNODB_BUFFER_POOL_PAGES_BLOB space_id +INNODB_BUFFER_POOL_PAGES_INDEX index_id +INNODB_CMP page_size +INNODB_CMPMEM page_size +INNODB_CMPMEM_RESET page_size +INNODB_CMP_RESET page_size +INNODB_INDEX_STATS table_schema +INNODB_LOCKS lock_id +INNODB_LOCK_WAITS requesting_trx_id +INNODB_RSEG rseg_id +INNODB_SYS_INDEXES TABLE_ID +INNODB_SYS_STATS INDEX_ID +INNODB_SYS_TABLES SCHEMA +INNODB_TABLE_STATS table_schema +INNODB_TRX trx_id KEY_CACHES KEY_CACHE_NAME KEY_COLUMN_USAGE CONSTRAINT_SCHEMA PARTITIONS TABLE_SCHEMA +PBXT_STATISTICS ID PLUGINS PLUGIN_NAME PROCESSLIST ID PROFILING QUERY_ID @@ -168,25 +185,8 @@ TRIGGERS TRIGGER_SCHEMA USER_PRIVILEGES GRANTEE USER_STATISTICS USER VIEWS TABLE_SCHEMA -INNODB_BUFFER_POOL_PAGES page_type -PBXT_STATISTICS ID -INNODB_CMP page_size -INNODB_RSEG rseg_id -XTRADB_ENHANCEMENTS name -INNODB_BUFFER_POOL_PAGES_INDEX index_id XTRADB_ADMIN_COMMAND result_message -INNODB_TRX trx_id -INNODB_SYS_TABLES SCHEMA -INNODB_LOCK_WAITS requesting_trx_id -INNODB_SYS_STATS INDEX_ID -INNODB_LOCKS lock_id -INNODB_CMPMEM page_size -INNODB_TABLE_STATS table_schema -INNODB_SYS_INDEXES TABLE_ID -INNODB_CMP_RESET page_size -INNODB_BUFFER_POOL_PAGES_BLOB space_id -INNODB_CMPMEM_RESET page_size -INNODB_INDEX_STATS table_schema +XTRADB_ENHANCEMENTS name select 1 as f1 from information_schema.tables where "CHARACTER_SETS"= (select cast(table_name as char) from information_schema.tables order by table_name limit 1) limit 1; @@ -259,10 +259,11 @@ USER_PRIVILEGES information_schema.USER_PRIVILEGES 1 USER_STATISTICS information_schema.USER_STATISTICS 1 VIEWS information_schema.VIEWS 1 XTRADB_ENHANCEMENTS information_schema.XTRADB_ENHANCEMENTS 1 ++---------------------------------------+ ++---------------------------------------+ ++---------------------------------------+ Database: information_schema -+---------------------------------------+ | Tables | -+---------------------------------------+ | CHARACTER_SETS | | CLIENT_STATISTICS | | COLLATIONS | @@ -275,9 +276,26 @@ Database: information_schema | GLOBAL_STATUS | | GLOBAL_VARIABLES | | INDEX_STATISTICS | +| INNODB_BUFFER_POOL_PAGES | +| INNODB_BUFFER_POOL_PAGES_BLOB | +| INNODB_BUFFER_POOL_PAGES_INDEX | +| INNODB_CMP | +| INNODB_CMPMEM | +| INNODB_CMPMEM_RESET | +| INNODB_CMP_RESET | +| INNODB_INDEX_STATS | +| INNODB_LOCKS | +| INNODB_LOCK_WAITS | +| INNODB_RSEG | +| INNODB_SYS_INDEXES | +| INNODB_SYS_STATS | +| INNODB_SYS_TABLES | +| INNODB_TABLE_STATS | +| INNODB_TRX | | KEY_CACHES | | KEY_COLUMN_USAGE | | PARTITIONS | +| PBXT_STATISTICS | | PLUGINS | | PROCESSLIST | | PROFILING | @@ -296,30 +314,13 @@ Database: information_schema | USER_PRIVILEGES | | USER_STATISTICS | | VIEWS | -| INNODB_BUFFER_POOL_PAGES | -| PBXT_STATISTICS | -| INNODB_CMP | -| INNODB_RSEG | -| XTRADB_ENHANCEMENTS | -| INNODB_BUFFER_POOL_PAGES_INDEX | | XTRADB_ADMIN_COMMAND | -| INNODB_TRX | -| INNODB_SYS_TABLES | -| INNODB_LOCK_WAITS | -| INNODB_SYS_STATS | -| INNODB_LOCKS | -| INNODB_CMPMEM | -| INNODB_TABLE_STATS | -| INNODB_SYS_INDEXES | -| INNODB_CMP_RESET | -| INNODB_BUFFER_POOL_PAGES_BLOB | -| INNODB_CMPMEM_RESET | -| INNODB_INDEX_STATS | +| XTRADB_ENHANCEMENTS | ++---------------------------------------+ ++---------------------------------------+ +---------------------------------------+ Database: INFORMATION_SCHEMA -+---------------------------------------+ | Tables | -+---------------------------------------+ | CHARACTER_SETS | | CLIENT_STATISTICS | | COLLATIONS | @@ -332,9 +333,26 @@ Database: INFORMATION_SCHEMA | GLOBAL_STATUS | | GLOBAL_VARIABLES | | INDEX_STATISTICS | +| INNODB_BUFFER_POOL_PAGES | +| INNODB_BUFFER_POOL_PAGES_BLOB | +| INNODB_BUFFER_POOL_PAGES_INDEX | +| INNODB_CMP | +| INNODB_CMPMEM | +| INNODB_CMPMEM_RESET | +| INNODB_CMP_RESET | +| INNODB_INDEX_STATS | +| INNODB_LOCKS | +| INNODB_LOCK_WAITS | +| INNODB_RSEG | +| INNODB_SYS_INDEXES | +| INNODB_SYS_STATS | +| INNODB_SYS_TABLES | +| INNODB_TABLE_STATS | +| INNODB_TRX | | KEY_CACHES | | KEY_COLUMN_USAGE | | PARTITIONS | +| PBXT_STATISTICS | | PLUGINS | | PROCESSLIST | | PROFILING | @@ -353,32 +371,14 @@ Database: INFORMATION_SCHEMA | USER_PRIVILEGES | | USER_STATISTICS | | VIEWS | -| INNODB_BUFFER_POOL_PAGES | -| PBXT_STATISTICS | -| INNODB_CMP | -| INNODB_RSEG | -| XTRADB_ENHANCEMENTS | -| INNODB_BUFFER_POOL_PAGES_INDEX | | XTRADB_ADMIN_COMMAND | -| INNODB_TRX | -| INNODB_SYS_TABLES | -| INNODB_LOCK_WAITS | -| INNODB_SYS_STATS | -| INNODB_LOCKS | -| INNODB_CMPMEM | -| INNODB_TABLE_STATS | -| INNODB_SYS_INDEXES | -| INNODB_CMP_RESET | -| INNODB_BUFFER_POOL_PAGES_BLOB | -| INNODB_CMPMEM_RESET | -| INNODB_INDEX_STATS | -+---------------------------------------+ +| XTRADB_ENHANCEMENTS | ++--------------------+ ++--------------------+ ++--------------------+ Wildcard: inf_rmation_schema -+--------------------+ | Databases | -+--------------------+ | information_schema | -+--------------------+ SELECT table_schema, count(*) FROM information_schema.TABLES WHERE table_schema IN ('mysql', 'INFORMATION_SCHEMA', 'test', 'mysqltest') AND table_name<>'ndb_binlog_index' AND table_name<>'ndb_apply_status' GROUP BY TABLE_SCHEMA; table_schema count(*) information_schema 52 diff --git a/mysql-test/t/information_schema_all_engines.test b/mysql-test/t/information_schema_all_engines.test index b20ce60985c..9887845cb7e 100644 --- a/mysql-test/t/information_schema_all_engines.test +++ b/mysql-test/t/information_schema_all_engines.test @@ -9,6 +9,7 @@ use INFORMATION_SCHEMA; --replace_result Tables_in_INFORMATION_SCHEMA Tables_in_information_schema +--sorted_result show tables; # @@ -28,7 +29,7 @@ SELECT t.table_name, c1.column_name WHERE c2.table_schema = t.table_schema AND c2.table_name = t.table_name AND c2.column_name LIKE '%SCHEMA%' - ); + ) order by t.table_name; SELECT t.table_name, c1.column_name FROM information_schema.tables t INNER JOIN @@ -42,7 +43,7 @@ SELECT t.table_name, c1.column_name WHERE c2.table_schema = 'information_schema' AND c2.table_name = t.table_name AND c2.column_name LIKE '%SCHEMA%' - ); + ) order by t.table_name; # # Bug#24630 Subselect query crashes mysqld @@ -70,8 +71,11 @@ group by t.table_name order by num1, t.table_name; # # Bug #19147: mysqlshow INFORMATION_SCHEMA does not work # +--sorted_result --exec $MYSQL_SHOW information_schema +--sorted_result --exec $MYSQL_SHOW INFORMATION_SCHEMA +--sorted_result --exec $MYSQL_SHOW inf_rmation_schema # From cf31ccc33c2f5ac5e2ae92c672bd54cc7ce63107 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 10 Jan 2012 23:26:00 +0200 Subject: [PATCH 264/288] Fix for LP BUG#908269 Wrong result with subquery in select list, EXISTS, constant MyISAM/Aria table. Problem: When building the condition for JOIN::outer_ref_cond the optimizer forgot to take into account that this condition could depend on constant tables as well. --- mysql-test/r/subselect.result | 24 ++++++++++++ mysql-test/r/subselect_no_mat.result | 24 ++++++++++++ mysql-test/r/subselect_no_opts.result | 24 ++++++++++++ mysql-test/r/subselect_no_scache.result | 24 ++++++++++++ mysql-test/r/subselect_no_semijoin.result | 24 ++++++++++++ mysql-test/t/subselect.test | 28 ++++++++++++++ sql/sql_select.cc | 46 ++++++++++++++++------- sql/sql_select.h | 3 +- 8 files changed, 183 insertions(+), 14 deletions(-) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 95fc6e03e56..7dfcad074fe 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -5908,5 +5908,29 @@ a 2009-02-02 set @@optimizer_switch=@old_optimizer_switch; drop table t1; +# +# LP BUG#908269 incorrect condition in case of subqueries depending +# on constant tables +# +CREATE TABLE t1 ( a INT ); +INSERT INTO t1 VALUES (1),(5); +CREATE TABLE t2 ( b INT ) ENGINE=MyISAM; +INSERT INTO t2 VALUES (1); +CREATE TABLE t3 ( c INT ); +INSERT INTO t3 VALUES (4),(5); +SET optimizer_switch='subquery_cache=off'; +SELECT ( SELECT b FROM t2 WHERE b = a OR EXISTS ( SELECT c FROM t3 WHERE c = b ) ) FROM t1; +( SELECT b FROM t2 WHERE b = a OR EXISTS ( SELECT c FROM t3 WHERE c = b ) ) +1 +NULL +SELECT ( SELECT b FROM t2 WHERE b = a OR b * 0) FROM t1; +( SELECT b FROM t2 WHERE b = a OR b * 0) +1 +NULL +SELECT ( SELECT b FROM t2 WHERE b = a OR rand() * 0) FROM t1; +( SELECT b FROM t2 WHERE b = a OR rand() * 0) +1 +NULL +drop table t1,t2,t3; # 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 8959853f16f..c7d9fd96e5d 100644 --- a/mysql-test/r/subselect_no_mat.result +++ b/mysql-test/r/subselect_no_mat.result @@ -5909,6 +5909,30 @@ a 2009-02-02 set @@optimizer_switch=@old_optimizer_switch; drop table t1; +# +# LP BUG#908269 incorrect condition in case of subqueries depending +# on constant tables +# +CREATE TABLE t1 ( a INT ); +INSERT INTO t1 VALUES (1),(5); +CREATE TABLE t2 ( b INT ) ENGINE=MyISAM; +INSERT INTO t2 VALUES (1); +CREATE TABLE t3 ( c INT ); +INSERT INTO t3 VALUES (4),(5); +SET optimizer_switch='subquery_cache=off'; +SELECT ( SELECT b FROM t2 WHERE b = a OR EXISTS ( SELECT c FROM t3 WHERE c = b ) ) FROM t1; +( SELECT b FROM t2 WHERE b = a OR EXISTS ( SELECT c FROM t3 WHERE c = b ) ) +1 +NULL +SELECT ( SELECT b FROM t2 WHERE b = a OR b * 0) FROM t1; +( SELECT b FROM t2 WHERE b = a OR b * 0) +1 +NULL +SELECT ( SELECT b FROM t2 WHERE b = a OR rand() * 0) FROM t1; +( SELECT b FROM t2 WHERE b = a OR rand() * 0) +1 +NULL +drop table t1,t2,t3; # 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 1a937bbcd5f..3d6efa28e19 100644 --- a/mysql-test/r/subselect_no_opts.result +++ b/mysql-test/r/subselect_no_opts.result @@ -5905,6 +5905,30 @@ a 2009-02-02 set @@optimizer_switch=@old_optimizer_switch; drop table t1; +# +# LP BUG#908269 incorrect condition in case of subqueries depending +# on constant tables +# +CREATE TABLE t1 ( a INT ); +INSERT INTO t1 VALUES (1),(5); +CREATE TABLE t2 ( b INT ) ENGINE=MyISAM; +INSERT INTO t2 VALUES (1); +CREATE TABLE t3 ( c INT ); +INSERT INTO t3 VALUES (4),(5); +SET optimizer_switch='subquery_cache=off'; +SELECT ( SELECT b FROM t2 WHERE b = a OR EXISTS ( SELECT c FROM t3 WHERE c = b ) ) FROM t1; +( SELECT b FROM t2 WHERE b = a OR EXISTS ( SELECT c FROM t3 WHERE c = b ) ) +1 +NULL +SELECT ( SELECT b FROM t2 WHERE b = a OR b * 0) FROM t1; +( SELECT b FROM t2 WHERE b = a OR b * 0) +1 +NULL +SELECT ( SELECT b FROM t2 WHERE b = a OR rand() * 0) FROM t1; +( SELECT b FROM t2 WHERE b = a OR rand() * 0) +1 +NULL +drop table t1,t2,t3; # 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 56e06b948a1..602905dd5b8 100644 --- a/mysql-test/r/subselect_no_scache.result +++ b/mysql-test/r/subselect_no_scache.result @@ -5914,6 +5914,30 @@ a 2009-02-02 set @@optimizer_switch=@old_optimizer_switch; drop table t1; +# +# LP BUG#908269 incorrect condition in case of subqueries depending +# on constant tables +# +CREATE TABLE t1 ( a INT ); +INSERT INTO t1 VALUES (1),(5); +CREATE TABLE t2 ( b INT ) ENGINE=MyISAM; +INSERT INTO t2 VALUES (1); +CREATE TABLE t3 ( c INT ); +INSERT INTO t3 VALUES (4),(5); +SET optimizer_switch='subquery_cache=off'; +SELECT ( SELECT b FROM t2 WHERE b = a OR EXISTS ( SELECT c FROM t3 WHERE c = b ) ) FROM t1; +( SELECT b FROM t2 WHERE b = a OR EXISTS ( SELECT c FROM t3 WHERE c = b ) ) +1 +NULL +SELECT ( SELECT b FROM t2 WHERE b = a OR b * 0) FROM t1; +( SELECT b FROM t2 WHERE b = a OR b * 0) +1 +NULL +SELECT ( SELECT b FROM t2 WHERE b = a OR rand() * 0) FROM t1; +( SELECT b FROM t2 WHERE b = a OR rand() * 0) +1 +NULL +drop table t1,t2,t3; # 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 b92230cff3b..9b2370efd61 100644 --- a/mysql-test/r/subselect_no_semijoin.result +++ b/mysql-test/r/subselect_no_semijoin.result @@ -5905,6 +5905,30 @@ a 2009-02-02 set @@optimizer_switch=@old_optimizer_switch; drop table t1; +# +# LP BUG#908269 incorrect condition in case of subqueries depending +# on constant tables +# +CREATE TABLE t1 ( a INT ); +INSERT INTO t1 VALUES (1),(5); +CREATE TABLE t2 ( b INT ) ENGINE=MyISAM; +INSERT INTO t2 VALUES (1); +CREATE TABLE t3 ( c INT ); +INSERT INTO t3 VALUES (4),(5); +SET optimizer_switch='subquery_cache=off'; +SELECT ( SELECT b FROM t2 WHERE b = a OR EXISTS ( SELECT c FROM t3 WHERE c = b ) ) FROM t1; +( SELECT b FROM t2 WHERE b = a OR EXISTS ( SELECT c FROM t3 WHERE c = b ) ) +1 +NULL +SELECT ( SELECT b FROM t2 WHERE b = a OR b * 0) FROM t1; +( SELECT b FROM t2 WHERE b = a OR b * 0) +1 +NULL +SELECT ( SELECT b FROM t2 WHERE b = a OR rand() * 0) FROM t1; +( SELECT b FROM t2 WHERE b = a OR rand() * 0) +1 +NULL +drop table t1,t2,t3; # 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 9d87cbc486c..b92fb6f961c 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -4990,5 +4990,33 @@ SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1); set @@optimizer_switch=@old_optimizer_switch; drop table t1; +--echo # +--echo # LP BUG#908269 incorrect condition in case of subqueries depending +--echo # on constant tables +--echo # +CREATE TABLE t1 ( a INT ); +INSERT INTO t1 VALUES (1),(5); + +# t2 must be MyISAM or Aria and contain 1 row +CREATE TABLE t2 ( b INT ) ENGINE=MyISAM; +INSERT INTO t2 VALUES (1); + +CREATE TABLE t3 ( c INT ); +INSERT INTO t3 VALUES (4),(5); + +SET optimizer_switch='subquery_cache=off'; + +SELECT ( SELECT b FROM t2 WHERE b = a OR EXISTS ( SELECT c FROM t3 WHERE c = b ) ) FROM t1; + +# This query just for example, it should return the same as above (1 and NULL) +SELECT ( SELECT b FROM t2 WHERE b = a OR b * 0) FROM t1; + +# example with "random" +SELECT ( SELECT b FROM t2 WHERE b = a OR rand() * 0) FROM t1; + + +drop table t1,t2,t3; + + --echo # return optimizer switch changed in the beginning of this test set optimizer_switch=@subselect_tmp; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index c332b13dff6..c4a62ce6bc4 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -8033,14 +8033,33 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) DBUG_RETURN(1); // Impossible const condition } - COND *outer_ref_cond= make_cond_for_table(thd, cond, - OUTER_REF_TABLE_BIT, - OUTER_REF_TABLE_BIT, - -1, FALSE, FALSE); - if (outer_ref_cond) - { - add_cond_and_fix(thd, &outer_ref_cond, join->outer_ref_cond); - join->outer_ref_cond= outer_ref_cond; + if (join->table_count != join->const_tables) + { + COND *outer_ref_cond= make_cond_for_table(thd, cond, + join->const_table_map | + OUTER_REF_TABLE_BIT, + OUTER_REF_TABLE_BIT, + -1, FALSE, FALSE); + if (outer_ref_cond) + { + add_cond_and_fix(thd, &outer_ref_cond, join->outer_ref_cond); + join->outer_ref_cond= outer_ref_cond; + } + } + else + { + COND *pseudo_bits_cond= + make_cond_for_table(thd, cond, + join->const_table_map | + PSEUDO_TABLE_BITS, + PSEUDO_TABLE_BITS, + -1, FALSE, FALSE); + if (pseudo_bits_cond) + { + add_cond_and_fix(thd, &pseudo_bits_cond, + join->pseudo_bits_cond); + join->pseudo_bits_cond= pseudo_bits_cond; + } } } } @@ -14927,14 +14946,15 @@ do_select(JOIN *join,List *fields,TABLE *table,Procedure *procedure) /* HAVING will be checked after processing aggregate functions, But WHERE should checked here (we alredy have read tables). - Notice that make_join_select() splits all conditions into three groups - - exec_const_cond, outer_ref_cond, and conditions attached to non-constant - tables. Within this IF the latter do not exist. At the same time + Notice that make_join_select() splits all conditions in this case + into two groups exec_const_cond and outer_ref_cond. + Within this other conditions are not exists. At the same time exec_const_cond is already checked either by make_join_select or in the beginning of JOIN::exec. Therefore here it is sufficient to check only - outer_ref_cond. + pseudo_bits_cond. */ - if (!join->outer_ref_cond || join->outer_ref_cond->val_int()) + DBUG_ASSERT(join->outer_ref_cond == NULL); + if (!join->pseudo_bits_cond || join->pseudo_bits_cond->val_int()) { error= (*end_select)(join, 0, 0); if (error == NESTED_LOOP_OK || error == NESTED_LOOP_QUERY_LIMIT) diff --git a/sql/sql_select.h b/sql/sql_select.h index 8b3da18c976..8b448130eaf 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -1111,6 +1111,7 @@ public: COND *conds; // ---"--- Item *conds_history; // store WHERE for explain COND *outer_ref_cond; /// *join_list; ///< list of joined tables in reverse order COND_EQUAL *cond_equal; @@ -1237,7 +1238,7 @@ public: rollup.state= ROLLUP::STATE_NONE; no_const_tables= FALSE; - outer_ref_cond= 0; + outer_ref_cond= pseudo_bits_cond= NULL; in_to_exists_where= NULL; in_to_exists_having= NULL; } From 296b450d3b58ded0fd4d4972161414c6cc7a80e5 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 11 Jan 2012 10:35:16 +0200 Subject: [PATCH 265/288] Fix the comment. --- sql/sql_select.cc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index c4a62ce6bc4..fe52bc05465 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -14948,10 +14948,8 @@ do_select(JOIN *join,List *fields,TABLE *table,Procedure *procedure) But WHERE should checked here (we alredy have read tables). Notice that make_join_select() splits all conditions in this case into two groups exec_const_cond and outer_ref_cond. - Within this other conditions are not exists. At the same time - exec_const_cond is already checked either by make_join_select or in the - beginning of JOIN::exec. Therefore here it is sufficient to check only - pseudo_bits_cond. + If join->table_count == join->const_tables then it is + sufficient to check only the condition pseudo_bits_cond. */ DBUG_ASSERT(join->outer_ref_cond == NULL); if (!join->pseudo_bits_cond || join->pseudo_bits_cond->val_int()) From 6ca4ca7d37fed3b3da18666768de6a2f8c34bc7b Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 13 Jan 2012 13:54:55 +0100 Subject: [PATCH 266/288] 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 c56483d972d023105fbcb0f47af0042ee092657c Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 13 Jan 2012 15:52:19 +0100 Subject: [PATCH 267/288] remove duplicate .opt with AUTH_PLUGIN_SO --- .../{t/auth_rpl-master.opt => include/have_plugin_auth.opt} | 0 mysql-test/t/auth_rpl-slave.opt | 1 - mysql-test/t/mysql_client_test-master.opt | 1 - mysql-test/t/plugin_auth-master.opt | 1 - mysql-test/t/plugin_auth_qa-master.opt | 1 - mysql-test/t/plugin_auth_qa_1-master.opt | 1 - 6 files changed, 5 deletions(-) rename mysql-test/{t/auth_rpl-master.opt => include/have_plugin_auth.opt} (100%) delete mode 100644 mysql-test/t/plugin_auth-master.opt delete mode 100644 mysql-test/t/plugin_auth_qa-master.opt delete mode 100644 mysql-test/t/plugin_auth_qa_1-master.opt diff --git a/mysql-test/t/auth_rpl-master.opt b/mysql-test/include/have_plugin_auth.opt similarity index 100% rename from mysql-test/t/auth_rpl-master.opt rename to mysql-test/include/have_plugin_auth.opt diff --git a/mysql-test/t/auth_rpl-slave.opt b/mysql-test/t/auth_rpl-slave.opt index ca6eee95ded..1e471f65645 100644 --- a/mysql-test/t/auth_rpl-slave.opt +++ b/mysql-test/t/auth_rpl-slave.opt @@ -1,2 +1 @@ --master-retry-count=1 ---plugin-load=$AUTH_TEST_PLUGIN_SO diff --git a/mysql-test/t/mysql_client_test-master.opt b/mysql-test/t/mysql_client_test-master.opt index d2db22b8634..69debb24dae 100644 --- a/mysql-test/t/mysql_client_test-master.opt +++ b/mysql-test/t/mysql_client_test-master.opt @@ -1,3 +1,2 @@ --log=$MYSQLTEST_VARDIR/log/master.log --log-output=FILE,TABLE ---plugin-load=$AUTH_TEST_PLUGIN_SO diff --git a/mysql-test/t/plugin_auth-master.opt b/mysql-test/t/plugin_auth-master.opt deleted file mode 100644 index ff91abb1bef..00000000000 --- a/mysql-test/t/plugin_auth-master.opt +++ /dev/null @@ -1 +0,0 @@ ---plugin-load=$AUTH_TEST_PLUGIN_SO diff --git a/mysql-test/t/plugin_auth_qa-master.opt b/mysql-test/t/plugin_auth_qa-master.opt deleted file mode 100644 index ff91abb1bef..00000000000 --- a/mysql-test/t/plugin_auth_qa-master.opt +++ /dev/null @@ -1 +0,0 @@ ---plugin-load=$AUTH_TEST_PLUGIN_SO diff --git a/mysql-test/t/plugin_auth_qa_1-master.opt b/mysql-test/t/plugin_auth_qa_1-master.opt deleted file mode 100644 index ff91abb1bef..00000000000 --- a/mysql-test/t/plugin_auth_qa_1-master.opt +++ /dev/null @@ -1 +0,0 @@ ---plugin-load=$AUTH_TEST_PLUGIN_SO From 0c075461759d88a2bfb180f8a557f7ba6adb0688 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 16 Jan 2012 20:58:00 +0100 Subject: [PATCH 268/288] minor mtr fix mysql-test/mysql-test-run.pl: strace-client does not take an argument --- mysql-test/mysql-test-run.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index ba6e79c98d8..7cbd225178e 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1191,7 +1191,7 @@ sub command_line_setup { 'boot-dbx' => \$opt_boot_dbx, 'client-debugger=s' => \$opt_client_debugger, 'strace' => \$opt_strace, - 'strace-client:s' => \$opt_strace_client, + 'strace-client' => \$opt_strace_client, 'strace-option=s' => \@strace_args, 'max-save-core=i' => \$opt_max_save_core, 'max-save-datadir=i' => \$opt_max_save_datadir, From baca1a40e98c4d1ac107118f5f4b6012f398bdf2 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 16 Jan 2012 21:02:43 +0100 Subject: [PATCH 269/288] enable test cases for bugs fixed in xtradb. disable test cases for bugs not fixed in xtradb. mysql-test/suite/innodb/t/innodb-lock.test: instead of disabling the test in disabled.def (hoping that somebody someday will enable it), skip it only for xtradb (not for innodb), and only for the current xtradb version. the test will enable itself automatically on the next xtradb merge mysql-test/suite/innodb/t/innodb_cmp_drop_table.test: instead of disabling the test in disabled.def (hoping that somebody someday will enable it), skip it only for xtradb (not for innodb), and only for the current xtradb version. the test will enable itself automatically on the next xtradb merge mysql-test/suite/innodb/t/innodb_corrupt_bit.test: fix the error number storage/innobase/handler/ha_innodb.cc: fix the error number storage/xtradb/handler/ha_innodb.cc: fix the error number --- mysql-test/suite/innodb/r/innodb_corrupt_bit.result | 8 ++++---- mysql-test/suite/innodb/t/disabled.def | 3 --- mysql-test/suite/innodb/t/innodb-lock.test | 4 ++++ mysql-test/suite/innodb/t/innodb_cmp_drop_table.test | 4 ++++ mysql-test/suite/innodb/t/innodb_corrupt_bit.test | 6 +++--- mysql-test/suite/sys_vars/t/disabled.def | 3 --- storage/innobase/handler/ha_innodb.cc | 2 +- storage/xtradb/handler/ha_innodb.cc | 2 +- 8 files changed, 17 insertions(+), 15 deletions(-) diff --git a/mysql-test/suite/innodb/r/innodb_corrupt_bit.result b/mysql-test/suite/innodb/r/innodb_corrupt_bit.result index c88e1ed2504..7e8792bb5b4 100644 --- a/mysql-test/suite/innodb/r/innodb_corrupt_bit.result +++ b/mysql-test/suite/innodb/r/innodb_corrupt_bit.result @@ -40,13 +40,13 @@ test.corrupt_bit_test_ā check Warning InnoDB: The B-tree of index "idxā" is co test.corrupt_bit_test_ā check Warning InnoDB: The B-tree of index "idxē" is corrupted. test.corrupt_bit_test_ā check error Corrupt select c from corrupt_bit_test_ā; -ERROR HY000: Incorrect key file for table 'corrupt_bit_test_ā'; try to repair it +ERROR HY000: Index corrupt_bit_test_ā is corrupted select z from corrupt_bit_test_ā; -ERROR HY000: Incorrect key file for table 'corrupt_bit_test_ā'; try to repair it +ERROR HY000: Index corrupt_bit_test_ā is corrupted show warnings; Level Code Message Warning 179 InnoDB: Index "idxē" for table "test"."corrupt_bit_test_ā" is marked as corrupted -Error 1034 Incorrect key file for table 'corrupt_bit_test_ā'; try to repair it +Error 1712 Index corrupt_bit_test_ā is corrupted insert into corrupt_bit_test_ā values (10001, "a", 20001, 20001); select * from corrupt_bit_test_ā use index(primary) where a = 10001; a b c z @@ -63,7 +63,7 @@ test.corrupt_bit_test_ā check Warning InnoDB: Index "idxē" is marked as corrup test.corrupt_bit_test_ā check error Corrupt set names utf8; select z from corrupt_bit_test_ā; -ERROR HY000: Incorrect key file for table 'corrupt_bit_test_ā'; try to repair it +ERROR HY000: Index corrupt_bit_test_ā is corrupted drop index idxē on corrupt_bit_test_ā; select z from corrupt_bit_test_ā limit 10; z diff --git a/mysql-test/suite/innodb/t/disabled.def b/mysql-test/suite/innodb/t/disabled.def index 2080a009fb6..888298bbb09 100644 --- a/mysql-test/suite/innodb/t/disabled.def +++ b/mysql-test/suite/innodb/t/disabled.def @@ -9,6 +9,3 @@ # Do not use any TAB characters for whitespace. # ############################################################################## - -innodb-index : the fix is not in XtraDB yet -innodb_corrupt_bit : the fix is not in XtraDB yet diff --git a/mysql-test/suite/innodb/t/innodb-lock.test b/mysql-test/suite/innodb/t/innodb-lock.test index 49fe1127074..817b18ee6df 100644 --- a/mysql-test/suite/innodb/t/innodb-lock.test +++ b/mysql-test/suite/innodb/t/innodb-lock.test @@ -1,3 +1,7 @@ +if (`select plugin_auth_version <= "1.1.8-20.1" from information_schema.plugins where plugin_name='innodb'`) +{ + --skip Not supported by XtraDB 1.1.8-20.1 or earlier +} # # Check and select innodb lock type diff --git a/mysql-test/suite/innodb/t/innodb_cmp_drop_table.test b/mysql-test/suite/innodb/t/innodb_cmp_drop_table.test index 84527e1b035..827bb4bcc74 100644 --- a/mysql-test/suite/innodb/t/innodb_cmp_drop_table.test +++ b/mysql-test/suite/innodb/t/innodb_cmp_drop_table.test @@ -1,3 +1,7 @@ +if (`select plugin_auth_version <= "1.1.8-20.1" from information_schema.plugins where plugin_name='innodb'`) +{ + --skip Not supported by XtraDB 1.1.8-20.1 or earlier +} let $per_table=`select @@innodb_file_per_table`; let $format=`select @@innodb_file_format`; diff --git a/mysql-test/suite/innodb/t/innodb_corrupt_bit.test b/mysql-test/suite/innodb/t/innodb_corrupt_bit.test index 7c4ea00afec..b8d19ddfcee 100644 --- a/mysql-test/suite/innodb/t/innodb_corrupt_bit.test +++ b/mysql-test/suite/innodb/t/innodb_corrupt_bit.test @@ -79,10 +79,10 @@ CREATE INDEX idx4 ON corrupt_bit_test_ā(b, z); check table corrupt_bit_test_ā; # This selection intend to use the corrupted index. Expect to fail --- error ER_NOT_KEYFILE +-- error ER_INDEX_CORRUPT select c from corrupt_bit_test_ā; --- error ER_NOT_KEYFILE +-- error ER_INDEX_CORRUPT select z from corrupt_bit_test_ā; show warnings; @@ -108,7 +108,7 @@ check table corrupt_bit_test_ā; set names utf8; --- error ER_NOT_KEYFILE +-- error ER_INDEX_CORRUPT select z from corrupt_bit_test_ā; # Drop the corrupted index diff --git a/mysql-test/suite/sys_vars/t/disabled.def b/mysql-test/suite/sys_vars/t/disabled.def index 133754ed6ce..888298bbb09 100644 --- a/mysql-test/suite/sys_vars/t/disabled.def +++ b/mysql-test/suite/sys_vars/t/disabled.def @@ -9,6 +9,3 @@ # Do not use any TAB characters for whitespace. # ############################################################################## - -innodb_force_load_corrupted_basic : not in XtraDB (yet?) -innodb_random_read_ahead_basic : not in XtraDB (yet?) diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 27ad19456cc..8b6d347bef9 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -5913,7 +5913,7 @@ ha_innobase::change_active_index( "InnoDB: Index %s for table %s is" " marked as corrupted", index_name, table_name); - DBUG_RETURN(1); + DBUG_RETURN(HA_ERR_INDEX_CORRUPT); } else { push_warning_printf( user_thd, MYSQL_ERROR::WARN_LEVEL_WARN, diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index b706523596f..3aa5ff1622d 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -6710,7 +6710,7 @@ ha_innobase::change_active_index( "InnoDB: Index %s for table %s is" " marked as corrupted", index_name, table_name); - DBUG_RETURN(1); + DBUG_RETURN(HA_ERR_INDEX_CORRUPT); } else { push_warning_printf( user_thd, MYSQL_ERROR::WARN_LEVEL_WARN, From 2ec0f46b88bc5f1d565d65025b7a868c6943ab0c Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 16 Jan 2012 21:06:23 +0100 Subject: [PATCH 270/288] query cache sysvar fixes sql/share/errmsg-utf8.txt: correct the error message, as query_cache_type variable is not read-ony anymore sql/sql_cache.cc: the caller should verify that query cache resize is possible, before trying it sql/sys_vars.cc: * test if qc resize is possible in the sysvar on_check() funntion, not in the on_update() function. * use the error message that better describes the problem --- sql/share/errmsg-utf8.txt | 3 +-- sql/sql_cache.cc | 1 + sql/sys_vars.cc | 15 +++++++++++++-- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 4798483860c..872e80ab542 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -6270,8 +6270,7 @@ ER_SLAVE_IGNORE_SERVER_IDS eng "The requested server id %d clashes with the slave startup option --replicate-same-server-id" ger "Die angeforderte Server-ID %d steht im Konflikt mit der Startoption --replicate-same-server-id für den Slave" ER_QUERY_CACHE_DISABLED - eng "Query cache is disabled; restart the server with query_cache_type=1 to enable it" - ger "Abfragen-Cache ist deaktiviert. Starten Sie den Server neu mit query_cache_type=1, um ihn zu aktivieren" + eng "Query cache is disabled; set query_cache_type to ON or DEMAND to enable it" ER_SAME_NAME_PARTITION_FIELD eng "Duplicate partition field name '%-.192s'" ger "Partitionsfeld '%-.192s' ist ein Duplikat" diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 7212f6996eb..0a1185a9924 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -1292,6 +1292,7 @@ ulong Query_cache::resize(ulong query_cache_size_arg) if (global_system_variables.query_cache_type == 0) { + DBUG_ASSERT(query_cache_size_arg == 0); if (query_cache_size_arg != 0) my_error(ER_QUERY_CACHE_IS_DISABLED, MYF(0)); DBUG_RETURN(0); diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 7cdd5b3f65e..9da2393a0ad 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -1819,6 +1819,17 @@ static Sys_var_enum Sys_thread_handling( thread_handling_names, DEFAULT(0)); #ifdef HAVE_QUERY_CACHE +static bool check_query_cache_size(sys_var *self, THD *thd, set_var *var) +{ + if (global_system_variables.query_cache_type == 0 && + var->value && var->value->val_int() != 0) + { + my_error(ER_QUERY_CACHE_DISABLED, MYF(0)); + return true; + } + + return false; +} static bool fix_query_cache_size(sys_var *self, THD *thd, enum_var_type type) { ulong new_cache_size= query_cache.resize(query_cache_size); @@ -1839,7 +1850,7 @@ static Sys_var_ulonglong Sys_query_cache_size( "The memory allocated to store results from old queries", GLOBAL_VAR(query_cache_size), CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, ULONGLONG_MAX), DEFAULT(0), BLOCK_SIZE(1024), - NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), + NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_query_cache_size), ON_UPDATE(fix_query_cache_size)); static Sys_var_ulong Sys_query_cache_limit( @@ -1867,7 +1878,7 @@ static bool check_query_cache_type(sys_var *self, THD *thd, set_var *var) { if (query_cache.is_disable_in_progress()) { - my_error(ER_QUERY_CACHE_DISABLED, MYF(0)); + my_error(ER_QUERY_CACHE_IS_DISABLED, MYF(0)); return true; } if (var->type != OPT_GLOBAL && From 8d13f97084bf5b5753bf34392442afd2c00f63bb Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 16 Jan 2012 21:06:44 +0100 Subject: [PATCH 271/288] remove unused flag --- sql/mysqld.h | 1 - 1 file changed, 1 deletion(-) diff --git a/sql/mysqld.h b/sql/mysqld.h index bc6bd5779f8..9246ea90fa1 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -48,7 +48,6 @@ typedef Bitmap<((MAX_INDEXES+7)/8*8)> key_map; /* Used for finding keys */ #define TEST_READCHECK 64 /**< Force use of readcheck */ #define TEST_NO_EXTRA 128 #define TEST_CORE_ON_SIGNAL 256 /**< Give core if signal */ -#define TEST_NO_STACKTRACE 512 #define TEST_SIGINT 1024 /**< Allow sigint on threads */ #define TEST_SYNCHRONIZATION 2048 /**< get server to do sleep in some places */ From 1433621c14e480dbedf3d7ea2b4885cff94bc6e5 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 17 Jan 2012 09:11:20 +0100 Subject: [PATCH 272/288] fixes for non-debug builds (CMAKE_BUILD_TYPE=Release or RelWithDebInfo) client/CMakeLists.txt: 1. -rdynamic is a linker flag. 2. it should be used in all builds, not debug only libmysql/get_password.c: prefer a standard function, when possible (otherwise a plugin will need to load it from the client) --- client/CMakeLists.txt | 2 +- libmysql/get_password.c | 2 +- sql/sql_partition.cc | 2 +- sql/sql_trigger.cc | 2 +- vio/viosocket.c | 2 -- 5 files changed, 4 insertions(+), 6 deletions(-) diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index a5a73298122..de503e8927e 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -31,7 +31,7 @@ MYSQL_ADD_EXECUTABLE(mysql completion_hash.cc mysql.cc readline.cc TARGET_LINK_LIBRARIES(mysql mysqlclient) IF(UNIX) TARGET_LINK_LIBRARIES(mysql ${MY_READLINE_LIBRARY}) - SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -rdynamic") + SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -rdynamic") ENDIF(UNIX) MYSQL_ADD_EXECUTABLE(mysqltest mysqltest.cc COMPONENT Test) diff --git a/libmysql/get_password.c b/libmysql/get_password.c index dc1a29f7935..c3428dd2838 100644 --- a/libmysql/get_password.c +++ b/libmysql/get_password.c @@ -157,7 +157,7 @@ void get_tty_password_buff(const char *opt_message, char *buff, size_t buflen) passbuff = getpass(opt_message ? opt_message : "Enter password: "); /* copy the password to buff and clear original (static) buffer */ - strnmov(buff, passbuff, buflen - 1); + strncpy(buff, passbuff, buflen - 1); #ifdef _PASSWORD_LEN memset(passbuff, 0, _PASSWORD_LEN); #endif diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index ace785948e0..070b48f7a7b 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -7348,7 +7348,7 @@ int get_part_iter_for_interval_cols_via_map(partition_info *part_info, PARTITION_ITERATOR *part_iter) { uint32 nparts; - get_col_endpoint_func get_col_endpoint; + get_col_endpoint_func UNINIT_VAR(get_col_endpoint); DBUG_ENTER("get_part_iter_for_interval_cols_via_map"); if (part_info->part_type == RANGE_PARTITION) diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index dacdaca3fa2..1ac1d7bbb5e 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -1722,7 +1722,7 @@ bool add_table_for_trigger(THD *thd, LEX *lex= thd->lex; char trn_path_buff[FN_REFLEN]; LEX_STRING trn_path= { trn_path_buff, 0 }; - LEX_STRING tbl_name; + LEX_STRING tbl_name= null_lex_str; DBUG_ENTER("add_table_for_trigger"); diff --git a/vio/viosocket.c b/vio/viosocket.c index 9840891b69e..6a33937d4bd 100644 --- a/vio/viosocket.c +++ b/vio/viosocket.c @@ -692,9 +692,7 @@ my_bool vio_is_connected(Vio *vio) void vio_timeout(Vio *vio, uint which, uint timeout) { #if defined(SO_SNDTIMEO) && defined(SO_RCVTIMEO) -#ifndef DBUG_OFF int r; -#endif DBUG_ENTER("vio_timeout"); { From 4cd19779c7bf4f05e03896c33be8e38849d06747 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 17 Jan 2012 10:55:27 +0100 Subject: [PATCH 273/288] MDEV-69 SET optimizer_switch = REPLACE(...) causes ER_WRONG_VALUE_FOR_VAR find_set() in typelib.c expected a zero-terminated string include/typelib.h: disable unused flags --- include/typelib.h | 8 +- .../sys_vars/r/optimizer_switch_basic.result | 4 + .../sys_vars/t/optimizer_switch_basic.test | 3 + mysys/typelib.c | 74 +++++++++++-------- 4 files changed, 54 insertions(+), 35 deletions(-) diff --git a/include/typelib.h b/include/typelib.h index 2cfe5e6c0da..8aabc6fa059 100644 --- a/include/typelib.h +++ b/include/typelib.h @@ -35,10 +35,10 @@ extern int find_type_or_exit(const char *x, TYPELIB *typelib, /** makes @c find_type() require the whole name, no prefix */ #define FIND_TYPE_NO_PREFIX (1 << 0) /** always implicitely on, so unused, but old code may pass it */ -#define FIND_TYPE_NO_OVERWRITE (1 << 1) -/** makes @c find_type() accept a number */ -#define FIND_TYPE_ALLOW_NUMBER (1 << 2) -/** makes @c find_type() treat ',' as terminator */ +#define FIND_TYPE_NO_OVERWRITE 0 +/** makes @c find_type() accept a number. Not used either */ +#define FIND_TYPE_ALLOW_NUMBER 0 +/** makes @c find_type() treat ',' and '=' as terminators */ #define FIND_TYPE_COMMA_TERM (1 << 3) extern int find_type(const char *x, const TYPELIB *typelib, unsigned int flags); diff --git a/mysql-test/suite/sys_vars/r/optimizer_switch_basic.result b/mysql-test/suite/sys_vars/r/optimizer_switch_basic.result index 879015fc456..84f346d0f9e 100644 --- a/mysql-test/suite/sys_vars/r/optimizer_switch_basic.result +++ b/mysql-test/suite/sys_vars/r/optimizer_switch_basic.result @@ -52,6 +52,10 @@ set session optimizer_switch="default"; select @@session.optimizer_switch; @@session.optimizer_switch index_merge=off,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off +set optimizer_switch = replace(@@optimizer_switch, '=off', '=on'); +select @@optimizer_switch; +@@optimizer_switch +index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=on,engine_condition_pushdown=on,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=on,mrr_cost_based=on,mrr_sort_keys=on,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=on,table_elimination=on set global optimizer_switch=1.1; ERROR 42000: Incorrect argument type to variable 'optimizer_switch' set global optimizer_switch=1e1; diff --git a/mysql-test/suite/sys_vars/t/optimizer_switch_basic.test b/mysql-test/suite/sys_vars/t/optimizer_switch_basic.test index 4267b3726aa..210910d7a86 100644 --- a/mysql-test/suite/sys_vars/t/optimizer_switch_basic.test +++ b/mysql-test/suite/sys_vars/t/optimizer_switch_basic.test @@ -34,6 +34,9 @@ select * from information_schema.session_variables where variable_name='optimize set session optimizer_switch="default"; select @@session.optimizer_switch; +set optimizer_switch = replace(@@optimizer_switch, '=off', '=on'); +select @@optimizer_switch; + # # incorrect assignments # diff --git a/mysys/typelib.c b/mysys/typelib.c index 3b4e1014f15..402d108e51c 100644 --- a/mysys/typelib.c +++ b/mysys/typelib.c @@ -20,7 +20,8 @@ #include -#define is_field_separator(X) ((X) == ',' || (X) == '=') +#define is_field_separator(F, X) \ + ((F & FIND_TYPE_COMMA_TERM) && ((X) == ',' || (X) == '=')) int find_type_with_warning(const char *x, TYPELIB *typelib, const char *option) { @@ -58,14 +59,14 @@ int find_type_or_exit(const char *x, TYPELIB *typelib, const char *option) /** Search after a string in a list of strings. Endspace in x is not compared. - @param x String to find + @param x pointer to string to find + (not necessarily zero-terminated). + by return it'll be advanced to point to the terminator. @param typelib TYPELIB (struct of pointer to values + count) @param flags flags to tune behaviour: a combination of FIND_TYPE_NO_PREFIX - FIND_TYPE_ALLOW_NUMBER FIND_TYPE_COMMA_TERM. - FIND_TYPE_NO_OVERWRITE can be passed but is - superfluous (is always implicitely on). + @param eol a pointer to the end of the string. @retval -1 Too many matching values @@ -76,17 +77,20 @@ int find_type_or_exit(const char *x, TYPELIB *typelib, const char *option) */ -int find_type(const char *x, const TYPELIB *typelib, uint flags) +static int find_type_eol(const char **x, const TYPELIB *typelib, uint flags, + const char *eol) { int find,pos; int UNINIT_VAR(findpos); /* guarded by find */ + const char *UNINIT_VAR(termptr); const char *i; const char *j; - DBUG_ENTER("find_type"); - DBUG_PRINT("enter",("x: '%s' lib: 0x%lx", x, (long) typelib)); + CHARSET_INFO *cs= &my_charset_latin1; + DBUG_ENTER("find_type_eol"); + DBUG_PRINT("enter",("x: '%s' lib: 0x%lx", *x, (long) typelib)); + + DBUG_ASSERT(!(flags & ~(FIND_TYPE_NO_PREFIX | FIND_TYPE_COMMA_TERM))); - DBUG_ASSERT(!(flags & ~(FIND_TYPE_NO_PREFIX | FIND_TYPE_ALLOW_NUMBER | - FIND_TYPE_NO_OVERWRITE | FIND_TYPE_COMMA_TERM))); if (!typelib->count) { DBUG_PRINT("exit",("no count")); @@ -95,43 +99,53 @@ int find_type(const char *x, const TYPELIB *typelib, uint flags) find=0; for (pos=0 ; (j=typelib->type_names[pos]) ; pos++) { - for (i=x ; - *i && (!(flags & FIND_TYPE_COMMA_TERM) || !is_field_separator(*i)) && - my_toupper(&my_charset_latin1,*i) == - my_toupper(&my_charset_latin1,*j) ; i++, j++) ; + for (i=*x ; + i < eol && !is_field_separator(flags, *i) && + my_toupper(cs, *i) == my_toupper(cs, *j) ; i++, j++) ; if (! *j) { - while (*i == ' ') + while (i < eol && *i == ' ') i++; /* skip_end_space */ - if (! *i || ((flags & FIND_TYPE_COMMA_TERM) && is_field_separator(*i))) + if (i >= eol || is_field_separator(flags, *i)) + { + *x= i; DBUG_RETURN(pos+1); + } } - if ((!*i && - (!(flags & FIND_TYPE_COMMA_TERM) || !is_field_separator(*i))) && + if ((i >= eol && !is_field_separator(flags, *i)) && (!*j || !(flags & FIND_TYPE_NO_PREFIX))) { find++; findpos=pos; + termptr=i; } } - if (find == 0 && (flags & FIND_TYPE_ALLOW_NUMBER) && x[0] == '#' && - strend(x)[-1] == '#' && - (findpos=atoi(x+1)-1) >= 0 && (uint) findpos < typelib->count) - find=1; - else if (find == 0 || ! x[0]) + if (find == 0 || *x == eol) { DBUG_PRINT("exit",("Couldn't find type")); DBUG_RETURN(0); } else if (find != 1 || (flags & FIND_TYPE_NO_PREFIX)) { - DBUG_PRINT("exit",("Too many possybilities")); + DBUG_PRINT("exit",("Too many possibilities")); DBUG_RETURN(-1); } + *x= termptr; DBUG_RETURN(findpos+1); -} /* find_type */ +} /* find_type_eol */ +/** + Search after a string in a list of strings. Endspace in x is not compared. + + Same as find_type_eol, but for zero-terminated strings, + and without advancing the pointer. +*/ +int find_type(const char *x, const TYPELIB *typelib, uint flags) +{ + return find_type_eol(&x, typelib, flags, x + strlen(x)); +} + /** Get name of type nr @@ -198,7 +212,7 @@ my_ulonglong find_typeset(char *x, TYPELIB *lib, int *err) { (*err)++; i= x; - while (*x && !is_field_separator(*x)) + while (*x && *x != ',') x++; if (x[0] && x[1]) /* skip separator if found */ x++; @@ -283,12 +297,10 @@ static TYPELIB on_off_default_typelib= {array_elements(on_off_default_names)-1, >0 Offset+1 in typelib for matched name */ -static uint parse_name(const TYPELIB *lib, const char **strpos, const char *end) +static uint parse_name(const TYPELIB *lib, const char **pos, const char *end) { - const char *pos= *strpos; - uint find= find_type(pos, lib, FIND_TYPE_COMMA_TERM); - for (; pos != end && *pos != '=' && *pos !=',' ; pos++); - *strpos= pos; + uint find= find_type_eol(pos, lib, + FIND_TYPE_COMMA_TERM | FIND_TYPE_NO_PREFIX, end); return find; } From 4fa282db2b9e5c1f75a640749af6f8f1c0221d7e Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Tue, 17 Jan 2012 23:42:49 -0800 Subject: [PATCH 274/288] Fixed the failure of sp.test reported in the issue MDEV-86. --- sql/sql_derived.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 01125bdb97b..13985becff7 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -750,6 +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->optimized= TRUE; if ((res= join->optimize())) goto err; From 309ca7b4470d4a1e0244d82908aed516f68ee323 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 18 Jan 2012 22:09:20 +0100 Subject: [PATCH 275/288] fix the linking failure on windows --- include/mysql/plugin.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/include/mysql/plugin.h b/include/mysql/plugin.h index 32c971bb99e..e46bea9f24f 100644 --- a/include/mysql/plugin.h +++ b/include/mysql/plugin.h @@ -118,8 +118,11 @@ int PSIZE= sizeof(struct st_mysql_plugin); \ struct st_mysql_plugin DECLS[]= { #define MARIA_DECLARE_PLUGIN__(NAME, VERSION, PSIZE, DECLS) \ -int VERSION= MARIA_PLUGIN_INTERFACE_VERSION; \ -int PSIZE= sizeof(struct st_maria_plugin); \ +MYSQL_PLUGIN_EXPORT int VERSION; \ +int VERSION= MARIA_PLUGIN_INTERFACE_VERSION; \ +MYSQL_PLUGIN_EXPORT int PSIZE; \ +int PSIZE= sizeof(struct st_maria_plugin); \ +MYSQL_PLUGIN_EXPORT struct st_maria_plugin DECLS[]; \ struct st_maria_plugin DECLS[]= { #else From e3e15687a0c311b0b10ef4073d349f54f2764ac4 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 19 Jan 2012 14:12:16 +0100 Subject: [PATCH 276/288] update the test result --- mysql-test/r/mysqld--help-win.result | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/mysqld--help-win.result b/mysql-test/r/mysqld--help-win.result index 9fd1b8479d2..94379684518 100644 --- a/mysql-test/r/mysqld--help-win.result +++ b/mysql-test/r/mysqld--help-win.result @@ -908,7 +908,7 @@ init-slave interactive-timeout 28800 join-buffer-size 131072 join-buffer-space-limit 2097152 -join-cache-level 1 +join-cache-level 2 keep-files-on-create FALSE key-buffer-size 134217728 key-cache-age-threshold 300 @@ -989,7 +989,7 @@ old-passwords FALSE old-style-user-limits FALSE optimizer-prune-level 1 optimizer-search-depth 62 -optimizer-switch index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=off,derived_with_keys=off,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on +optimizer-switch index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on performance-schema FALSE performance-schema-events-waits-history-long-size 10000 performance-schema-events-waits-history-size 10 From 607c9a6c68de39e208ec36c55ad42d99817d83e2 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Thu, 19 Jan 2012 17:31:07 +0100 Subject: [PATCH 277/288] Fix innodb_bug60229 (get the innodb change into xtradb) --- storage/xtradb/dict/dict0dict.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/storage/xtradb/dict/dict0dict.c b/storage/xtradb/dict/dict0dict.c index 93334747c8e..07f22e4d1d6 100644 --- a/storage/xtradb/dict/dict0dict.c +++ b/storage/xtradb/dict/dict0dict.c @@ -3140,10 +3140,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); } From 3482963ad6f438f40388f36b697f227a733405a4 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Thu, 19 Jan 2012 17:44:22 +0100 Subject: [PATCH 278/288] fix broken result file --- .../suite/sys_vars/r/query_cache_size_basic_32.result | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/mysql-test/suite/sys_vars/r/query_cache_size_basic_32.result b/mysql-test/suite/sys_vars/r/query_cache_size_basic_32.result index ef302c500d5..319948deefa 100644 --- a/mysql-test/suite/sys_vars/r/query_cache_size_basic_32.result +++ b/mysql-test/suite/sys_vars/r/query_cache_size_basic_32.result @@ -69,16 +69,6 @@ Warning 1292 Truncated incorrect query_cache_size value: '-1024' SELECT @@global.query_cache_size; @@global.query_cache_size 0 -<<<<<<< TREE -SET @@global.query_cache_size = 42949672950; -Warnings: -Warning 1292 Truncated incorrect query_cache_size value: '42949672950' -Warning 1282 Query cache failed to set size 4294966272; new query cache size is 0 -SELECT @@global.query_cache_size; -@@global.query_cache_size -0 -======= ->>>>>>> MERGE-SOURCE SET @@global.query_cache_size = ON; ERROR 42000: Incorrect argument type to variable 'query_cache_size' SELECT @@global.query_cache_size; From 4502f3b93f4f70fb68ff00cb0ff72f234de50665 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Thu, 19 Jan 2012 18:41:56 +0100 Subject: [PATCH 279/288] disable character_sets_dir_basic - slashes vs backslashes problem is not possible to resolve --- mysql-test/suite/sys_vars/t/character_sets_dir_basic.test | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mysql-test/suite/sys_vars/t/character_sets_dir_basic.test b/mysql-test/suite/sys_vars/t/character_sets_dir_basic.test index 3d9de961530..cc3423c71f1 100644 --- a/mysql-test/suite/sys_vars/t/character_sets_dir_basic.test +++ b/mysql-test/suite/sys_vars/t/character_sets_dir_basic.test @@ -1,6 +1,8 @@ +--source include/not_windows.inc # # show the global and session values; # +--eval select '$MYSQL_CHARSETSDIR' --replace_result $MYSQL_CHARSETSDIR MYSQL_CHARSETSDIR select @@global.character_sets_dir; --error ER_INCORRECT_GLOBAL_LOCAL_VAR From 139bf5ce4c3e67c287418a3c5043b056c9a5cf4d Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Fri, 20 Jan 2012 01:57:34 +0100 Subject: [PATCH 280/288] MDEV-103: 'debug' is disabled in this build warnings causes tests to fail The root cause is that after recent fixes around --debug variable (lp:909051) the variable is now available in both release and debug builds, such that MTR cannot tell a debug compiled server from optimized one. To fix, assign a special default value 'disabled' for 'debug' variable in optimized build and fix MTR to check for this special value to recognize optimized build. --- mysql-test/mysql-test-run.pl | 5 +++-- sql/mysqld.cc | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 7cbd225178e..1bef01e3bd5 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -2826,8 +2826,9 @@ sub check_ipv6_support { sub check_debug_support ($) { my $mysqld_variables= shift; - - if ( ! $mysqld_variables->{'debug'} ) + my $debug_var= $mysqld_variables->{'debug'}; + + if ( !$debug_var || $debug_var eq "disabled") { #mtr_report(" - binaries are not debug compiled"); $debug_compiled_binaries= 0; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 41e554fabd5..cc0ee652b16 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1182,7 +1182,7 @@ static my_bool plugins_are_initialized= FALSE; #ifndef DBUG_OFF static const char* default_dbug_option; #endif -static const char *current_dbug_option; +static const char *current_dbug_option="disabled"; #ifdef HAVE_LIBWRAP const char *libwrapName= NULL; int allow_severity = LOG_INFO; From 74cac79218c58e399bec261683617d66652663fe Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Fri, 20 Jan 2012 01:57:58 +0100 Subject: [PATCH 281/288] - Fix rpl_checksum test. Use basename of file in error messages, not the o nes prefixed with .\ or ./ - Add my_basename() to mysys. - Do not compile files that are not needed on Windows (my_addr_resolve, an d safemalloc related stuff it it is not used) Avoids linker warnings about compilation of essentially empty files. --- include/my_sys.h | 1 + mysql-test/suite/rpl/r/rpl_checksum.result | 2 +- mysys/CMakeLists.txt | 13 +++++-- mysys/my_basename.c | 41 ++++++++++++++++++++++ mysys/stacktrace.c | 15 +++----- sql/sql_repl.cc | 5 +-- 6 files changed, 61 insertions(+), 16 deletions(-) create mode 100644 mysys/my_basename.c diff --git a/include/my_sys.h b/include/my_sys.h index cb5fa317888..fa79af51c7e 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -639,6 +639,7 @@ extern int my_fclose(FILE *fd,myf MyFlags); extern File my_fileno(FILE *fd); extern int my_chsize(File fd,my_off_t newlength, int filler, myf MyFlags); extern int my_chmod(const char *name, mode_t mode, myf my_flags); +extern const char *my_basename(const char *filename); extern void thr_set_sync_wait_callback(void (*before_sync)(void), void (*after_sync)(void)); extern int my_sync(File fd, myf my_flags); diff --git a/mysql-test/suite/rpl/r/rpl_checksum.result b/mysql-test/suite/rpl/r/rpl_checksum.result index 9c008540bb8..3297e8c2754 100644 --- a/mysql-test/suite/rpl/r/rpl_checksum.result +++ b/mysql-test/suite/rpl/r/rpl_checksum.result @@ -71,7 +71,7 @@ insert into t1 values (1) /* will not be applied on slave due to simulation */; set @@global.debug_dbug='d,simulate_slave_unaware_checksum'; start slave; include/wait_for_slave_io_error.inc [errno=1236] -Last_IO_Error = 'Got fatal error 1236 from master when reading data from binary log: 'Slave can not handle replication events with the checksum that master is configured to log; the last event was read from './master-bin.000010' at 245, the last byte read was read from './master-bin.000010' at 245.'' +Last_IO_Error = 'Got fatal error 1236 from master when reading data from binary log: 'Slave can not handle replication events with the checksum that master is configured to log; the last event was read from 'master-bin.000010' at 245, the last byte read was read from 'master-bin.000010' at 245.'' select count(*) as zero from t1; zero 0 diff --git a/mysys/CMakeLists.txt b/mysys/CMakeLists.txt index bf70b4615c1..819406b67e1 100644 --- a/mysys/CMakeLists.txt +++ b/mysys/CMakeLists.txt @@ -29,11 +29,11 @@ SET(MYSYS_SOURCES array.c charset-def.c charset.c checksum.c default.c my_mkdir.c my_mmap.c my_once.c my_open.c my_pread.c my_pthread.c my_quick.c my_read.c my_redel.c my_rename.c my_seek.c my_sleep.c my_static.c my_symlink.c my_symlink2.c my_sync.c my_thr_init.c + my_basename.c my_write.c ptr_cmp.c queues.c stacktrace.c rijndael.c sha1.c string.c thr_alarm.c thr_lock.c thr_mutex.c thr_rwlock.c tree.c typelib.c base64.c my_memmem.c my_getpagesize.c lf_alloc-pin.c lf_dynarray.c lf_hash.c - my_addr_resolve.c safemalloc.c my_new.cc my_atomic.c my_getncpus.c my_safehash.c my_chmod.c my_rnd.c my_uuid.c wqueue.c waiting_threads.c ma_dyncol.c my_rdtsc.c) @@ -42,8 +42,17 @@ IF (WIN32) SET (MYSYS_SOURCES ${MYSYS_SOURCES} my_winthread.c my_wincond.c my_winerr.c my_winfile.c my_windac.c my_conio.c) ENDIF() -IF(NOT HAVE_CXX_NEW) +IF(UNIX) + SET (MYSYS_SOURCES ${MYSYS_SOURCES} my_addr_resolve.c) +ENDIF() + +IF(WITH_SAFEMALLOC OR NOT HAVE_CXX_NEW) ADD_DEFINITIONS( -DUSE_MYSYS_NEW) + SET (MYSYS_SOURCES ${MYSYS_SOURCES} my_new.cc) +ENDIF() + +IF(WITH_SAFEMALLOC) + SET (MYSYS_SOURCES ${MYSYS_SOURCES} safemalloc.c) ENDIF() IF(HAVE_ALARM) diff --git a/mysys/my_basename.c b/mysys/my_basename.c new file mode 100644 index 00000000000..9d1eaf53efa --- /dev/null +++ b/mysys/my_basename.c @@ -0,0 +1,41 @@ +/* Copyright (C) 2011 Monty Program Ab + + 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 Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include +/** + @brief retrieve last component of the filename. + Loosely based on Single Unix Spec definition. + + @fn my_basename() + @param filename Filename +*/ +const char *my_basename(const char *filename) +{ + const char *last; + const char *s=filename; + + /* Handle basename()'s special cases, as per single unix spec */ + if (!filename || !filename[0]) + return "."; + if(filename[0] == '/' && filename[1]== '\0') + return filename; + + for(last= s; *s; s++) + { + if (*s == '/' || *s == '\\') + last= s + 1; + } + return last; +} diff --git a/mysys/stacktrace.c b/mysys/stacktrace.c index 1766c0f503a..30c9fafcb82 100644 --- a/mysys/stacktrace.c +++ b/mysys/stacktrace.c @@ -465,6 +465,7 @@ void my_write_core(int sig) #include #include +#include #if _MSC_VER #pragma comment(lib, "dbghelp") #endif @@ -652,14 +653,10 @@ void my_print_stacktrace(uchar* unused1, ulong unused2) &(package.sym)); have_source= SymGetLineFromAddr64(hProcess, addr, &line_offset, &line); - my_safe_printf_stderr("%p ", addr); + my_safe_printf_stderr("%p ", (uintptr_t)addr); if(have_module) { - char *base_image_name= strrchr(module.ImageName, '\\'); - if(base_image_name) - base_image_name++; - else - base_image_name= module.ImageName; + const char *base_image_name= my_basename(module.ImageName); my_safe_printf_stderr("%s!", base_image_name); } if(have_symbol) @@ -670,11 +667,7 @@ void my_print_stacktrace(uchar* unused1, ulong unused2) if(have_source) { - char *base_file_name= strrchr(line.FileName, '\\'); - if(base_file_name) - base_file_name++; - else - base_file_name= line.FileName; + const char *base_file_name= my_basename(line.FileName); my_safe_printf_stderr("[%s:%u]", base_file_name, line.LineNumber); } diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 1c87d8b3116..9974c56f3d1 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -554,6 +554,7 @@ static int send_heartbeat_event(NET* net, String* packet, DBUG_RETURN(0); } + /* TODO: Clean up loop to only have one call to send_file() */ @@ -1194,8 +1195,8 @@ err: of the last position read. */ my_snprintf(error_text, sizeof(error_text), fmt, errmsg, - coord->file_name, (llstr(coord->pos, llbuff1), llbuff1), - log_file_name, (llstr(my_b_tell(&log), llbuff2), llbuff2)); + my_basename(coord->file_name), (llstr(coord->pos, llbuff1), llbuff1), + my_basename(log_file_name), (llstr(my_b_tell(&log), llbuff2), llbuff2)); } else strcpy(error_text, errmsg); From 2ed40859c4f79ec5403b86c37e2753813faf4676 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Fri, 20 Jan 2012 12:39:06 +0100 Subject: [PATCH 282/288] Remove debug output --- mysql-test/suite/sys_vars/t/character_sets_dir_basic.test | 1 - 1 file changed, 1 deletion(-) diff --git a/mysql-test/suite/sys_vars/t/character_sets_dir_basic.test b/mysql-test/suite/sys_vars/t/character_sets_dir_basic.test index cc3423c71f1..0bbfd04133d 100644 --- a/mysql-test/suite/sys_vars/t/character_sets_dir_basic.test +++ b/mysql-test/suite/sys_vars/t/character_sets_dir_basic.test @@ -2,7 +2,6 @@ # # show the global and session values; # ---eval select '$MYSQL_CHARSETSDIR' --replace_result $MYSQL_CHARSETSDIR MYSQL_CHARSETSDIR select @@global.character_sets_dir; --error ER_INCORRECT_GLOBAL_LOCAL_VAR From c232b2023205b6b898448cb1f603b4d42a7a2656 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Fri, 20 Jan 2012 16:54:35 +0100 Subject: [PATCH 283/288] Fix embedded build on Windows. --- mysys/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysys/CMakeLists.txt b/mysys/CMakeLists.txt index 819406b67e1..329c132a9f1 100644 --- a/mysys/CMakeLists.txt +++ b/mysys/CMakeLists.txt @@ -46,7 +46,7 @@ IF(UNIX) SET (MYSYS_SOURCES ${MYSYS_SOURCES} my_addr_resolve.c) ENDIF() -IF(WITH_SAFEMALLOC OR NOT HAVE_CXX_NEW) +IF(NOT HAVE_CXX_NEW) ADD_DEFINITIONS( -DUSE_MYSYS_NEW) SET (MYSYS_SOURCES ${MYSYS_SOURCES} my_new.cc) ENDIF() From 3cb24fff33105f40c2f4b696a06449032ec09604 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Fri, 20 Jan 2012 22:32:31 +0100 Subject: [PATCH 284/288] - Always compile my_new.cc and safemalloc.c with mysys Preprocessor macros USE_MYSYS_NEW and -DSAFEMALLOC are used to conditionally compile safemalloc or overwritten new/delete. -Define dummy symbol in my_new.cc in case -DUSE_MYSYS_NEW is not set. This avoids compiler/linker warnings about an essentially empty file being compiled. --- mysys/CMakeLists.txt | 10 +--------- mysys/my_new.cc | 7 ++++++- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/mysys/CMakeLists.txt b/mysys/CMakeLists.txt index 329c132a9f1..c565f7f12d5 100644 --- a/mysys/CMakeLists.txt +++ b/mysys/CMakeLists.txt @@ -34,6 +34,7 @@ SET(MYSYS_SOURCES array.c charset-def.c charset.c checksum.c default.c rijndael.c sha1.c string.c thr_alarm.c thr_lock.c thr_mutex.c thr_rwlock.c tree.c typelib.c base64.c my_memmem.c my_getpagesize.c lf_alloc-pin.c lf_dynarray.c lf_hash.c + safemalloc.c my_new.cc my_atomic.c my_getncpus.c my_safehash.c my_chmod.c my_rnd.c my_uuid.c wqueue.c waiting_threads.c ma_dyncol.c my_rdtsc.c) @@ -46,15 +47,6 @@ IF(UNIX) SET (MYSYS_SOURCES ${MYSYS_SOURCES} my_addr_resolve.c) ENDIF() -IF(NOT HAVE_CXX_NEW) - ADD_DEFINITIONS( -DUSE_MYSYS_NEW) - SET (MYSYS_SOURCES ${MYSYS_SOURCES} my_new.cc) -ENDIF() - -IF(WITH_SAFEMALLOC) - SET (MYSYS_SOURCES ${MYSYS_SOURCES} safemalloc.c) -ENDIF() - IF(HAVE_ALARM) SET(MYSYS_SOURCES ${MYSYS_SOURCES} my_alarm.c) ENDIF() diff --git a/mysys/my_new.cc b/mysys/my_new.cc index 8724f9cc4a4..03b3d0f5870 100644 --- a/mysys/my_new.cc +++ b/mysys/my_new.cc @@ -55,6 +55,11 @@ int __cxa_pure_virtual() } C_MODE_END - +#else +/* + Define a dummy symbol, just to avoid compiler/linker warnings + about compiling an essentially empty file. +*/ +int my_new_cc_symbol; #endif /* USE_MYSYS_NEW */ From cfd4fcb0bc3d469dfca74dae30d17250d65fdd91 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 23 Jan 2012 12:20:16 +0100 Subject: [PATCH 285/288] Initial draft for building .deb packages for MariaDB 5.5. --- cmake/install_layout.cmake | 16 +- debian/README.Maintainer | 114 + debian/additions/Docs__Images__Makefile.in | 6 + debian/additions/Docs__Makefile.in | 6 + debian/additions/debian-start | 35 + debian/additions/debian-start.inc.sh | 72 + debian/additions/echo_stderr | 2 + debian/additions/innotop/changelog.innotop | 357 + debian/additions/innotop/innotop | 10946 ++++++++++++++++ debian/additions/innotop/innotop.1 | 2084 +++ debian/additions/msql2mysql.1 | 16 + debian/additions/my.cnf | 195 + debian/additions/my_print_defaults.1 | 16 + debian/additions/myisam_ftdump.1 | 16 + debian/additions/myisamchk.1 | 17 + debian/additions/myisamlog.1 | 16 + debian/additions/myisampack.1 | 19 + .../additions/mysql-server.lintian-overrides | 2 + debian/additions/mysql_config.1 | 17 + debian/additions/mysql_convert_table_format.1 | 17 + debian/additions/mysql_find_rows.1 | 18 + debian/additions/mysql_fix_extensions.1 | 18 + debian/additions/mysql_install_db.1 | 16 + debian/additions/mysql_secure_installation.1 | 17 + debian/additions/mysql_setpermission.1 | 23 + debian/additions/mysql_tableinfo.1 | 322 + debian/additions/mysql_waitpid.1 | 20 + debian/additions/mysqlbinlog.1 | 17 + debian/additions/mysqlbug.1 | 14 + debian/additions/mysqlcheck.1 | 28 + debian/additions/mysqld_safe_syslog.cnf | 2 + debian/additions/mysqldumpslow.1 | 50 + debian/additions/mysqlimport.1 | 20 + debian/additions/mysqlreport | 1298 ++ debian/additions/mysqlreport.1 | 180 + debian/additions/mysqltest.1 | 16 + debian/additions/pack_isam.1 | 19 + debian/additions/resolve_stack_dump.1 | 16 + debian/additions/resolveip.1 | 16 + debian/autobake-deb.sh | 74 + debian/changelog | 23 + debian/compat | 1 + debian/copyright | 61 + debian/dist/Debian/control | 227 + .../Debian/mariadb-server-5.5.README.Debian | 109 + debian/dist/Debian/mariadb-server-5.5.dirs | 10 + debian/dist/Debian/mariadb-server-5.5.files | 61 + .../dist/Debian/mariadb-server-5.5.postinst | 268 + debian/dist/Debian/mariadb-server-5.5.postrm | 83 + debian/dist/Debian/rules | 294 + debian/dist/Ubuntu/apparmor-profile | 15 + debian/dist/Ubuntu/control | 221 + .../Ubuntu/mariadb-server-5.5.README.Debian | 109 + debian/dist/Ubuntu/mariadb-server-5.5.dirs | 10 + debian/dist/Ubuntu/mariadb-server-5.5.files | 63 + .../dist/Ubuntu/mariadb-server-5.5.postinst | 284 + debian/dist/Ubuntu/mariadb-server-5.5.postrm | 86 + debian/dist/Ubuntu/mariadb-server-5.5.py | 52 + debian/dist/Ubuntu/rules | 299 + debian/libmariadbclient-dev.README.Maintainer | 4 + debian/libmariadbclient-dev.dirs | 2 + debian/libmariadbclient-dev.examples | 1 + debian/libmariadbclient-dev.files | 6 + debian/libmariadbclient-dev.links | 2 + debian/libmariadbclient18.dirs | 1 + debian/libmariadbclient18.files | 1 + debian/libmariadbclient18.postinst | 12 + debian/libmariadbd-dev.files | 2 + debian/mariadb-client-5.5.README.Debian | 4 + debian/mariadb-client-5.5.dirs | 3 + debian/mariadb-client-5.5.docs | 2 + debian/mariadb-client-5.5.files | 31 + debian/mariadb-client-5.5.links | 3 + debian/mariadb-client-5.5.lintian-overrides | 3 + debian/mariadb-client-5.5.menu | 3 + debian/mariadb-client-core-5.5.files | 4 + debian/mariadb-server-5.5.NEWS | 34 + debian/mariadb-server-5.5.config | 46 + debian/mariadb-server-5.5.lintian-overrides | 5 + ...ariadb-server-5.5.logcheck.ignore.paranoid | 9 + .../mariadb-server-5.5.logcheck.ignore.server | 32 + ...adb-server-5.5.logcheck.ignore.workstation | 32 + .../mariadb-server-5.5.mysql-server.logrotate | 27 + debian/mariadb-server-5.5.mysql.init | 187 + debian/mariadb-server-5.5.preinst | 182 + debian/mariadb-server-5.5.prerm | 8 + debian/mariadb-server-5.5.templates | 89 + debian/mariadb-server-core-5.5.files | 26 + debian/mariadb-test-5.5.dirs | 98 + debian/mariadb-test-5.5.files | 9 + debian/mariadb-test-5.5.links | 2 + debian/mysql-common.dirs | 1 + debian/mysql-common.files | 3 + debian/mysql-common.lintian-overrides | 2 + debian/mysql-common.postrm | 7 + debian/patches/00list | 11 + ..._MAKEFILES__Docs_Images_Makefile.in.dpatch | 776 ++ .../01_MAKEFILES__Docs_Makefile.in.dpatch | 776 ++ .../02_no_builtin_ndbcluster_plugin.dpatch | 18 + .../21_init__openquery_configtest.dpatch | 33 + ...mysql_create_system_tables__no_test.dpatch | 30 + ...38_scripts__mysqld_safe.sh__signals.dpatch | 43 + ...ripts__mysql_install_db.sh__no_test.dpatch | 20 + .../44_scripts__mysql_config__libs.dpatch | 24 + debian/patches/50_mysql-test__db_test.dpatch | 23 + .../patches/60_zlib_innodb_workaround.dpatch | 31 + ...1_replace_dash_with_bash_mbug675185.dpatch | 20 + debian/po/POTFILES.in | 1 + debian/po/ar.po | 252 + debian/po/ca.po | 342 + debian/po/cs.po | 348 + debian/po/da.po | 382 + debian/po/de.po | 234 + debian/po/es.po | 391 + debian/po/eu.po | 237 + debian/po/fr.po | 246 + debian/po/gl.po | 249 + debian/po/it.po | 218 + debian/po/ja.po | 224 + debian/po/nb.po | 299 + debian/po/nl.po | 302 + debian/po/pt.po | 308 + debian/po/pt_BR.po | 443 + debian/po/ro.po | 320 + debian/po/ru.po | 225 + debian/po/sv.po | 226 + debian/po/templates.pot | 187 + debian/po/tr.po | 342 + debian/source.lintian-overrides | 2 + debian/watch | 3 + 130 files changed, 26890 insertions(+), 8 deletions(-) create mode 100644 debian/README.Maintainer create mode 100644 debian/additions/Docs__Images__Makefile.in create mode 100644 debian/additions/Docs__Makefile.in create mode 100644 debian/additions/debian-start create mode 100644 debian/additions/debian-start.inc.sh create mode 100644 debian/additions/echo_stderr create mode 100644 debian/additions/innotop/changelog.innotop create mode 100644 debian/additions/innotop/innotop create mode 100644 debian/additions/innotop/innotop.1 create mode 100644 debian/additions/msql2mysql.1 create mode 100644 debian/additions/my.cnf create mode 100644 debian/additions/my_print_defaults.1 create mode 100644 debian/additions/myisam_ftdump.1 create mode 100644 debian/additions/myisamchk.1 create mode 100644 debian/additions/myisamlog.1 create mode 100644 debian/additions/myisampack.1 create mode 100644 debian/additions/mysql-server.lintian-overrides create mode 100644 debian/additions/mysql_config.1 create mode 100644 debian/additions/mysql_convert_table_format.1 create mode 100644 debian/additions/mysql_find_rows.1 create mode 100644 debian/additions/mysql_fix_extensions.1 create mode 100644 debian/additions/mysql_install_db.1 create mode 100644 debian/additions/mysql_secure_installation.1 create mode 100644 debian/additions/mysql_setpermission.1 create mode 100644 debian/additions/mysql_tableinfo.1 create mode 100644 debian/additions/mysql_waitpid.1 create mode 100644 debian/additions/mysqlbinlog.1 create mode 100644 debian/additions/mysqlbug.1 create mode 100644 debian/additions/mysqlcheck.1 create mode 100644 debian/additions/mysqld_safe_syslog.cnf create mode 100644 debian/additions/mysqldumpslow.1 create mode 100644 debian/additions/mysqlimport.1 create mode 100755 debian/additions/mysqlreport create mode 100644 debian/additions/mysqlreport.1 create mode 100644 debian/additions/mysqltest.1 create mode 100644 debian/additions/pack_isam.1 create mode 100644 debian/additions/resolve_stack_dump.1 create mode 100644 debian/additions/resolveip.1 create mode 100755 debian/autobake-deb.sh create mode 100644 debian/changelog create mode 100644 debian/compat create mode 100644 debian/copyright create mode 100644 debian/dist/Debian/control create mode 100644 debian/dist/Debian/mariadb-server-5.5.README.Debian create mode 100644 debian/dist/Debian/mariadb-server-5.5.dirs create mode 100644 debian/dist/Debian/mariadb-server-5.5.files create mode 100644 debian/dist/Debian/mariadb-server-5.5.postinst create mode 100644 debian/dist/Debian/mariadb-server-5.5.postrm create mode 100755 debian/dist/Debian/rules create mode 100644 debian/dist/Ubuntu/apparmor-profile create mode 100644 debian/dist/Ubuntu/control create mode 100644 debian/dist/Ubuntu/mariadb-server-5.5.README.Debian create mode 100644 debian/dist/Ubuntu/mariadb-server-5.5.dirs create mode 100644 debian/dist/Ubuntu/mariadb-server-5.5.files create mode 100644 debian/dist/Ubuntu/mariadb-server-5.5.postinst create mode 100644 debian/dist/Ubuntu/mariadb-server-5.5.postrm create mode 100644 debian/dist/Ubuntu/mariadb-server-5.5.py create mode 100755 debian/dist/Ubuntu/rules create mode 100644 debian/libmariadbclient-dev.README.Maintainer create mode 100644 debian/libmariadbclient-dev.dirs create mode 100644 debian/libmariadbclient-dev.examples create mode 100644 debian/libmariadbclient-dev.files create mode 100644 debian/libmariadbclient-dev.links create mode 100644 debian/libmariadbclient18.dirs create mode 100644 debian/libmariadbclient18.files create mode 100644 debian/libmariadbclient18.postinst create mode 100644 debian/libmariadbd-dev.files create mode 100644 debian/mariadb-client-5.5.README.Debian create mode 100644 debian/mariadb-client-5.5.dirs create mode 100644 debian/mariadb-client-5.5.docs create mode 100644 debian/mariadb-client-5.5.files create mode 100644 debian/mariadb-client-5.5.links create mode 100644 debian/mariadb-client-5.5.lintian-overrides create mode 100644 debian/mariadb-client-5.5.menu create mode 100644 debian/mariadb-client-core-5.5.files create mode 100644 debian/mariadb-server-5.5.NEWS create mode 100644 debian/mariadb-server-5.5.config create mode 100644 debian/mariadb-server-5.5.lintian-overrides create mode 100644 debian/mariadb-server-5.5.logcheck.ignore.paranoid create mode 100644 debian/mariadb-server-5.5.logcheck.ignore.server create mode 100644 debian/mariadb-server-5.5.logcheck.ignore.workstation create mode 100644 debian/mariadb-server-5.5.mysql-server.logrotate create mode 100644 debian/mariadb-server-5.5.mysql.init create mode 100644 debian/mariadb-server-5.5.preinst create mode 100644 debian/mariadb-server-5.5.prerm create mode 100644 debian/mariadb-server-5.5.templates create mode 100644 debian/mariadb-server-core-5.5.files create mode 100644 debian/mariadb-test-5.5.dirs create mode 100644 debian/mariadb-test-5.5.files create mode 100644 debian/mariadb-test-5.5.links create mode 100644 debian/mysql-common.dirs create mode 100644 debian/mysql-common.files create mode 100644 debian/mysql-common.lintian-overrides create mode 100644 debian/mysql-common.postrm create mode 100644 debian/patches/00list create mode 100755 debian/patches/01_MAKEFILES__Docs_Images_Makefile.in.dpatch create mode 100755 debian/patches/01_MAKEFILES__Docs_Makefile.in.dpatch create mode 100644 debian/patches/02_no_builtin_ndbcluster_plugin.dpatch create mode 100644 debian/patches/21_init__openquery_configtest.dpatch create mode 100755 debian/patches/33_scripts__mysql_create_system_tables__no_test.dpatch create mode 100755 debian/patches/38_scripts__mysqld_safe.sh__signals.dpatch create mode 100755 debian/patches/41_scripts__mysql_install_db.sh__no_test.dpatch create mode 100755 debian/patches/44_scripts__mysql_config__libs.dpatch create mode 100755 debian/patches/50_mysql-test__db_test.dpatch create mode 100644 debian/patches/60_zlib_innodb_workaround.dpatch create mode 100755 debian/patches/61_replace_dash_with_bash_mbug675185.dpatch create mode 100644 debian/po/POTFILES.in create mode 100644 debian/po/ar.po create mode 100644 debian/po/ca.po create mode 100644 debian/po/cs.po create mode 100644 debian/po/da.po create mode 100644 debian/po/de.po create mode 100644 debian/po/es.po create mode 100644 debian/po/eu.po create mode 100644 debian/po/fr.po create mode 100644 debian/po/gl.po create mode 100644 debian/po/it.po create mode 100644 debian/po/ja.po create mode 100644 debian/po/nb.po create mode 100644 debian/po/nl.po create mode 100644 debian/po/pt.po create mode 100644 debian/po/pt_BR.po create mode 100644 debian/po/ro.po create mode 100644 debian/po/ru.po create mode 100644 debian/po/sv.po create mode 100644 debian/po/templates.pot create mode 100644 debian/po/tr.po create mode 100644 debian/source.lintian-overrides create mode 100644 debian/watch diff --git a/cmake/install_layout.cmake b/cmake/install_layout.cmake index 23c787a7c97..38d3fd3d01e 100644 --- a/cmake/install_layout.cmake +++ b/cmake/install_layout.cmake @@ -166,26 +166,26 @@ SET(INSTALL_PLUGINTESTDIR_RPM ${plugin_tests}) # DEB layout # SET(INSTALL_BINDIR_DEB "bin") -SET(INSTALL_SBINDIR_DEB "bin") -SET(INSTALL_SCRIPTDIR_DEB "scripts") +SET(INSTALL_SBINDIR_DEB "sbin") +SET(INSTALL_SCRIPTDIR_DEB "bin") # SET(INSTALL_LIBDIR_DEB "lib") -SET(INSTALL_PLUGINDIR_DEB "lib/plugin") +SET(INSTALL_PLUGINDIR_DEB "lib/mysql/plugin") # -SET(INSTALL_INCLUDEDIR_DEB "include") +SET(INSTALL_INCLUDEDIR_DEB "include/mysql") # SET(INSTALL_DOCDIR_DEB "docs") SET(INSTALL_DOCREADMEDIR_DEB ".") -SET(INSTALL_MANDIR_DEB "man") -SET(INSTALL_INFODIR_DEB "docs") +SET(INSTALL_MANDIR_DEB "share/man") +SET(INSTALL_INFODIR_DEB "share/info") # SET(INSTALL_SHAREDIR_DEB "share") -SET(INSTALL_MYSQLSHAREDIR_DEB "share") +SET(INSTALL_MYSQLSHAREDIR_DEB "share/mysql") SET(INSTALL_MYSQLTESTDIR_DEB "mysql-test") SET(INSTALL_SQLBENCHDIR_DEB ".") SET(INSTALL_SUPPORTFILESDIR_DEB "support-files") # -SET(INSTALL_MYSQLDATADIR_DEB "data") +SET(INSTALL_MYSQLDATADIR_DEB "/var/lib/mysql") SET(INSTALL_PLUGINTESTDIR_DEB ${plugin_tests}) # diff --git a/debian/README.Maintainer b/debian/README.Maintainer new file mode 100644 index 00000000000..b1e0a602781 --- /dev/null +++ b/debian/README.Maintainer @@ -0,0 +1,114 @@ + +########################### +## FIXME for 5.1 ## +########################### + +* put this trigger-recreation thing into the init scripts -- what?! + +########################################################################### +# Here are some information that are only of interest for the current and # +# following Debian maintainers of MySQL. # +########################################################################### + +The debian/ directory is under SVN control, see debian/control for URL. + +# +# Preparing a new version +# +The new orig.tar.gz (without non-free documentation) is created in /tmp/ when +running this command: + +debian/rules get-orig-source + +# +# mysqlreport +# +The authors e-mail address is . + +# +# Remarks to dependencies +# +libwrap0-dev (>= 7.6-8.3) + According to bug report 114582 where where build problems on + IA-64/sid with at least two prior versions. +psmisc + /usr/bin/killall in the initscript + +zlib1g in libmysqlclient-dev: + "mysql_config --libs" ads "-lz" + +Build-Dep: + +debhelper (>=4.1.16): + See po-debconf(7). + +autoconf (>= 2.13-20), automake1.7 + Try to get rid of them. + +doxygen, tetex-bin, tetex-extra, gs + for ndb/docs/*tex + +# +# Remarks to the start scripts +# + +## initscripts rely on mysqladmin from a different package +We have the problem that "/etc/init.d/mysql stop" relies on mysqladmin which +is in another package (mysql-client) and a passwordless access that's maybe +only available if the user configured his /root/.my.cnf. Can this be a problem? +* normal mode: not because the user is required to have it. Else: +* purge/remove: not, same as normal mode +* upgrade: not, same as normal mode +* first install: not, it depends on mysql-client which at least is unpacked + so mysqladmin is there (to ping). It is not yet configured + passwordles but if there's a server running then there's a + /root/.my.cnf. Anyways, we simply kill anything that's mysqld. + +## Passwordless access for the maintainer scripts +Another issue is that the scripts needs passwordless access. To ensure this +a debian-sys-maint user is configured which has process and shutdown privs. +The file with the randomly (that's important!) generated password must be +present as long as the databases remain installed because else a new install +would have no access. This file should be used like: + mysqladmin --defaults-file=/etc/mysql/debian.cnf restart +to avoid providing the password in plaintext on a commandline where it would +be visible to any user via the "ps" command. + +## When to start the daemon? +We aim to give the admin full control on when MySQL is running. +Issues to be faced here: +OLD: + 1. Debconf asks whether MySQL should be started on boot so update-rc.d is + only run if the answer has been yes. The admin is likely to forget + this decision but update-rc.d checks for an existing line in + /etc/runlevel.conf and leaves it intact. + 2. On initial install, if the answer is yes, the daemon has to be started. + 3. On upgrades it should only be started if it was already running, everything + else is confusing. Especiall relying on an debconf decision made month ago + is considered suboptimal. See bug #274264 + Implementation so far: + prerm (called on upgrade before stopping the server): + check for a running server and set flag if necessary + preinst (called on initial install and before unpacking when upgrading): + check for the debconf variable and set flag if necessary + postinst (called on initial install and after each upgrade after unpacking): + call update-rc.d if debconf says yes + call invoce-rc.d if the flag has been set + Problems remaining: + dpkg-reconfigure and setting mysql start on boot to yes did not start mysql + (ok "start on boot" literally does not mean "start now" so that might have been ok) +NEW: + 1. --- no debconf anymore for the sake of simplicity. We have runlevel.conf, + the admin should use it + 2. On initial install the server is started. + 3. On upgrades the server is started exactly if it was running before so the + runlevel configuration is irrelevant. It will be preserved by the mean of + update-rc.d's builtin check. + Implementation: + prerm (called on upgrade before stopping the server): + check for a running server and set flag if necessary + preinst (called on initial install and before unpacking when upgrading): + check for $1 beeing (initial) "install" and set flag + postinst (called on initial install and after each upgrade after unpacking): + call update-rc.d + call invoce-rc.d if the flag has been set diff --git a/debian/additions/Docs__Images__Makefile.in b/debian/additions/Docs__Images__Makefile.in new file mode 100644 index 00000000000..f7316d4e345 --- /dev/null +++ b/debian/additions/Docs__Images__Makefile.in @@ -0,0 +1,6 @@ +all: + +distclean: + -rm -f Makefile + +.PHONY: all distclean clean install check diff --git a/debian/additions/Docs__Makefile.in b/debian/additions/Docs__Makefile.in new file mode 100644 index 00000000000..f7316d4e345 --- /dev/null +++ b/debian/additions/Docs__Makefile.in @@ -0,0 +1,6 @@ +all: + +distclean: + -rm -f Makefile + +.PHONY: all distclean clean install check diff --git a/debian/additions/debian-start b/debian/additions/debian-start new file mode 100644 index 00000000000..9fd0030d0ec --- /dev/null +++ b/debian/additions/debian-start @@ -0,0 +1,35 @@ +#!/bin/bash +# +# This script is executed by "/etc/init.d/mysql" on every (re)start. +# +# Changes to this file will be preserved when updating the Debian package. +# + +source /usr/share/mysql/debian-start.inc.sh + +MYSQL="/usr/bin/mysql --defaults-file=/etc/mysql/debian.cnf" +MYADMIN="/usr/bin/mysqladmin --defaults-file=/etc/mysql/debian.cnf" +MYUPGRADE="/usr/bin/mysql_upgrade --defaults-extra-file=/etc/mysql/debian.cnf" +MYCHECK="/usr/bin/mysqlcheck --defaults-file=/etc/mysql/debian.cnf" +MYCHECK_SUBJECT="WARNING: mysqlcheck has found corrupt tables" +MYCHECK_PARAMS="--all-databases --fast --silent" +MYCHECK_RCPT="root" + +# The following commands should be run when the server is up but in background +# where they do not block the server start and in one shell instance so that +# they run sequentially. They are supposed not to echo anything to stdout. +# If you want to disable the check for crashed tables comment +# "check_for_crashed_tables" out. +# (There may be no output to stdout inside the background process!) +echo "Checking for corrupt, not cleanly closed and upgrade needing tables." + +# Need to ignore SIGHUP, as otherwise a SIGHUP can sometimes abort the upgrade +# process in the middle. +trap "" SIGHUP +( + upgrade_system_tables_if_necessary; + check_root_accounts; + check_for_crashed_tables; +) >&2 & + +exit 0 diff --git a/debian/additions/debian-start.inc.sh b/debian/additions/debian-start.inc.sh new file mode 100644 index 00000000000..f50712882c1 --- /dev/null +++ b/debian/additions/debian-start.inc.sh @@ -0,0 +1,72 @@ +#!/bin/bash +# +# This file is included by /etc/mysql/debian-start +# + +## Check all unclosed tables. +# - Requires the server to be up. +# - Is supposed to run silently in background. +function check_for_crashed_tables() { + set -e + set -u + + # But do it in the background to not stall the boot process. + logger -p daemon.info -i -t$0 "Triggering myisam-recover for all MyISAM tables" + + # Checking for $? is unreliable so the size of the output is checked. + # Some table handlers like HEAP do not support CHECK TABLE. + tempfile=`tempfile` + # We have to use xargs in this case, because a for loop barfs on the + # spaces in the thing to be looped over. + LC_ALL=C $MYSQL --skip-column-names --batch -e ' + select concat('\''select count(*) into @discard from `'\'', + TABLE_SCHEMA, '\''`.`'\'', TABLE_NAME, '\''`'\'') + from information_schema.TABLES where ENGINE='\''MyISAM'\' | \ + xargs -i $MYSQL --skip-column-names --silent --batch \ + --force -e "{}" >$tempfile + if [ -s $tempfile ]; then + ( + /bin/echo -e "\n" \ + "Improperly closed tables are also reported if clients are accessing\n" \ + "the tables *now*. A list of current connections is below.\n"; + $MYADMIN processlist status + ) >> $tempfile + # Check for presence as a dependency on mailx would require an MTA. + if [ -x /usr/bin/mailx ]; then + mailx -e -s"$MYCHECK_SUBJECT" $MYCHECK_RCPT < $tempfile + fi + (echo "$MYCHECK_SUBJECT"; cat $tempfile) | logger -p daemon.warn -i -t$0 + fi + rm $tempfile +} + +## Check for tables needing an upgrade. +# - Requires the server to be up. +# - Is supposed to run silently in background. +function upgrade_system_tables_if_necessary() { + set -e + set -u + + logger -p daemon.info -i -t$0 "Upgrading MySQL tables if necessary." + + # Filter all "duplicate column", "duplicate key" and "unknown column" + # errors as the script is designed to be idempotent. + LC_ALL=C $MYUPGRADE \ + 2>&1 \ + | egrep -v '^(1|@had|ERROR (1054|1060|1061))' \ + | logger -p daemon.warn -i -t$0 +} + +## Check for the presence of both, root accounts with and without password. +# This might have been caused by a bug related to mysql_install_db (#418672). +function check_root_accounts() { + set -e + set -u + + logger -p daemon.info -i -t$0 "Checking for insecure root accounts." + + ret=$( echo "SELECT count(*) FROM mysql.user WHERE user='root' and password='';" | $MYSQL --skip-column-names ) + if [ "$ret" -ne "0" ]; then + logger -p daemon.warn -i -t$0 "WARNING: mysql.user contains $ret root accounts without password!" + fi +} diff --git a/debian/additions/echo_stderr b/debian/additions/echo_stderr new file mode 100644 index 00000000000..67b3ed7cfb3 --- /dev/null +++ b/debian/additions/echo_stderr @@ -0,0 +1,2 @@ +#!/bin/bash +echo "$*" 1>&2 diff --git a/debian/additions/innotop/changelog.innotop b/debian/additions/innotop/changelog.innotop new file mode 100644 index 00000000000..ab4c154d6e6 --- /dev/null +++ b/debian/additions/innotop/changelog.innotop @@ -0,0 +1,357 @@ +Changelog for innotop: + +2009-03-09: version 1.7.1 + + Changes: + * Don't display the CXN column if only one connection is active in + the current view + + Bugs fixed: + * fixed bug where trying to aggregate the time column would result + in a crash if the time column had an undef value in it, which is + the case when a thread is in the 'Connect' state + * updated innotop.spec file to reflect current version + +2009-02-23: version 1.7.0 + + Changes: + * supports a central config (/etc/innotop/innotop.conf) + * changed the default home directory config to ~/.innotop/innotop.conf + (away from .ini) + * embedded InnoDBParser.pm into innotop so it can be run with no + installation + * no longer writes a new config file by default + * added --skipcentral (skip reading central config) and --write (write + a config if none were loaded at start-up) + * if no config file is loaded, connect to a MySQL database on + localhost using mysql_read_default_group=client + * embedded maatkit's DSNParser.pm and added support for --user, + --password, --host, --port + * changed default mode from T (InnoDB Transactions) to Q (Query List) + * in addition to connected threads, now displays running and cached + threads in statusbar + * don't load connections from a config file if any DSN information or + a username or password is specified on the command-line + + Bugs fixed: + * fixed bug preventing utilization of command-line options that + override default config settings if no config file was loaded + * fixed a bug where migrating from an old version of the config will + delete ~/innotop.ini, if it exists. Now uses File::Temp::tempfile(). + +2007-11-09: version 1.6.0 + + * S mode crashed on non-numeric values. + * New user-defined columns crashed upon restart. + * Added --color option to control terminal coloring. + +2007-09-18: version 1.5.2 + + * Added the ability to monitor InnoDB status from a file. + * Changed W mode to L mode; it monitors all locks, not just lock waits. + +2007-09-16: version 1.5.1 + + * Added C (Command Summary) mode. + * Fixed a bug in the 'avg' aggregate function. + +2007-09-10: version 1.5.0 + + Changes: + * Added plugin functionality. + * Added group-by functionality. + * Moved the configuration file to a directory. + * Enhanced filtering and sorting on pivoted tables. + * Many small bug fixes. + +2007-07-16: version 1.4.3 + + Changes: + * Added standard --version command-line option + * Changed colors to cyan instead of blue; more visible on dark terminals. + * Added information to the filter-choosing dialog. + * Added column auto-completion when entering a filter expression. + * Changed Term::ReadKey from optional to mandatory. + * Clarified username in password prompting. + * Ten thousand words of documentation! + + Bugs fixed: + * innotop crashed in W mode when InnoDB status data was truncated. + * innotop didn't display errors in tables if debug was enabled. + * The colored() subroutine wasn't being created in non-interactive mode. + * Don't prompt to save password except the first time. + +2007-05-03: version 1.4.2 + + This version contains all changes to the trunk until revision 239; some + changes in revisions 240:250 are included. + + MAJOR CHANGES: + + * Quick-filters to easily filter any column in any display + * Compatibility with MySQL 3.23 through 6.0 + * Improved error handling when a server is down, permissions denied, etc + * Use additional SHOW INNODB STATUS information in 5.1.x + * Make all modes use tables consistently, so they can all be edited, + filtered, colored and sorted consistently + * Combine V, G and S modes into S mode, with v, g, and s hot-keys + * Let DBD driver read MySQL option files; permit connections without + user/pass/etc + * Compile SQL-like expressions into Perl subroutines; eliminate need to + know Perl + * Do not save all config data to config file, only save user's customizations + * Rewritten and improved command-line option handling + * Added --count, --delay, and other command-line options to support + run-and-exit operation + * Improve built-in variable sets + * Improve help screen with three-part balanced-column layout + * Simplify table-editor and improve hotkey support + * Require Perl to have high-resolution time support (Time::HiRes) + * Help the user choose a query to analyze or kill + * Enable EXPLAIN, show-full-query in T mode just like Q mode + * Let data-extraction access current, previous and incremental data sets + all at once + + MINOR CHANGES: + + * Column stabilizing for Q mode + * New color rules for T, Q, W modes + * Apply slave I/O filter to Q mode + * Improve detection of server version and other meta-data + * Make connection timeout a config variable + * Improve cross-version-compatible SQL syntax + * Get some information from the DBD driver instead of asking MySQL for it + * Improved error messages + * Improve server group creation/editing + * Improve connection/thread killing + * Fix broken key bindings and restore previously mapped hot-keys for + choosing columns + * Some documentation updates (but not nearly enough) + * Allow the user to specify graphing char in S mode (formerly G mode) + * Allow easy switching between variable sets in S mode + * Bind 'n' key globally to choose the 'next' server connection + * Bind '%' key globally to filter displayed tables + * Allow aligning columns on the decimal place for easy readability + * Add hide_hdr config variable to hide column headers in tables + * Add a feature to smartly run PURGE MASTER LOGS in Replication mode + * Enable debug mode as a globally configurable variable + * Improve error messages when an expression or filter doesn't compile or has + a run-time error; die on error when debug is enabled + * Allow user-configurable delays after executing SQL (to let the server + settle down before taking another measurement) + * Add an expression to show how long until a transaction is finished + * Add skip_innodb as a global config variable + * Add '%' after percentages to help disambiguate (user-configurable) + * Add column to M mode to help see how fast slave is catching up to master + + BUG FIXES: + + * T and W modes had wrong value for wait_status column + * Error tracking on connections didn't reset when the connection recovered + * wait_timeout on connections couldn't be set before MySQL 4.0.3 + * There was a crash on 3.23 when wiping deadlocks + * Lettercase changes in some result sets (SHOW MASTER/SLAVE STATUS) between + MySQL versions crashed innotop + * Inactive connections crashed innotop upon access to DBD driver + * set_precision did not respect user defaults for number of digits + * --inc command-line option could not be negated + * InnoDB status parsing was not always parsing all needed information + * S mode (formerly G mode) could crash trying to divide non-numeric data + * M table didn't show Slave_open_temp_tables variable; incorrect lettercase + * DBD drivers with broken AutoCommit would crash innotop + * Some key bindings had incorrect labels + * Some config-file loading routines could load data for things that didn't + exist + * Headers printed too often in S mode + * High-resolution time was not used even when the user had it + * Non-interactive mode printed blank lines sometimes + * Q-mode header and statusbar showed different QPS numbers + * Formulas for key-cache and query-cache hit ratios were wrong + * Mac OS "Darwin" machines were mis-identified as Microsoft Windows + * Some multiplications crashed when given undefined input + * The commify transformation did not check its input and could crash + * Specifying an invalid mode on the command line or config file could crash + innotop + +2007-03-29: version 1.4.1 + + * More tweaks to display of connection errors. + * Fixed a problem with skip-innodb in MySQL 5.1. + * Fix a bug with dead connections in single-connection mode. + * Fix a regex to allow parsing more data from truncated deadlocks. + * Don't load active cxns from the config file if the cxn isn't defined. + +2007-03-03: version 1.4.0 + + * Further tweak error handling and display of connection errors + * More centralization of querying + * Fix forking so it doesn't kill all database connections + * Allow user to run innotop without permissions for GLOBAL variables and status + +2007-02-11: version 1.3.6 + + * Handle some connection failures so innotop doesn't crash because of one server. + * Enable incremental display in more modes. + * Tweaks to colorizing, color editor, and default color rules. + * Tweaks to default sorting rules. + * Use prepared statements for efficiency. + * Bug fixes and code cleanups. + * Data storage is keyed on clock ticks now. + +2007-02-03: version 1.3.5 + + * Bug fixes. + * More tools for editing configuration from within innotop. + * Filters and transformations are constrained to valid values. + * Support for colorizing rows. + * Sorting by multiple columns. + * Compress headers when display is very wide. + * Stabilize and limit column widths. + * Check config file formats when upgrading so upgrades go smoothly. + * Make D mode handle many connections at once. + * Extract simple expressions from data sets in column src property. + This makes innotop more awk-ish. + +2007-01-16: version 1.3 + + * Readline support. + * Can be used unattended, or in a pipe-and-filter mode + where it outputs tab-separated data to standard output. + * You can specify a config file on the command line. + Config files can be marked read-only. + * Monitor multiple servers simultaneously. + * Server groups to help manage many servers conveniently. + * Monitor master/slave status, and control slaves. + * Columns can have user-defined expressions as their data sources. + * Better configuration tools. + * InnoDB status information is merged into SHOW VARIABLES and + SHOW STATUS information, so you can access it all together. + * High-precision time support in more places. + * Lots of tweaks to make things display more readably and compactly. + * Column transformations and filters. + +2007-01-16: version 1.0.1 + * NOTE: innotop is now hosted at Sourceforge, in Subversion not CVS. + The new project homepage is http://sourceforge.net/projects/innotop/ + * Tweak default T/Q mode sort columns to match what people expect. + * Fix broken InnoDBParser.pm documentation (and hence man page). + +2007-01-06: version 1.0 + * NOTE: innotop is now hosted at Sourceforge, in Subversion not CVS. + The new project homepage is http://sourceforge.net/projects/innotop/ + * Prevent control characters from freaking terminal out. + * Set timeout to keep busy servers from closing connection. + * There is only one InnoDB insert buffer. + * Make licenses clear and consistent. + +2006-11-14: innotop 0.1.160, InnoDBParser version 1.69 + * Support for ANSI color on Microsoft Windows (more readable, compact + display; thanks Gisbert W. Selke). + * Better handling of $ENV{HOME} on Windows. + * Added a LICENSE file to the package as per Gentoo bug: + http://bugs.gentoo.org/show_bug.cgi?id=147600 + +2006-11-11: innotop 0.1.157, InnoDBParser version 1.69 + * Add Microsoft Windows support. + +2006-10-19: innotop 0.1.154, InnoDBParser version 1.69 + * Add O (Open Tables) mode + * Add some more checks to handle incomplete InnoDB status information + +2006-09-30: innotop 0.1.152, InnoDBParser version 1.69 + * Figured out what was wrong with package $VERSION variable: it wasn't + after the package declaration! + +2006-09-28: innotop 0.1.152, InnoDBParser version 1.67 + * Make more efforts towards crash-resistance and tolerance of completely + messed-up inputs. If innotop itself is broken, it is now much harder to + tell, because it just keeps on running without complaining. + * Fix a small bug parsing out some information and displaying it. + +2006-09-05: innotop 0.1.149, InnoDBParser version 1.64 + * Try to find and eliminate any parsing code that assumes pattern matches + will succeed. + +2006-09-05: innotop 0.1.149, InnoDBParser version 1.62 + * Make innotop crash-resistant, so I can declare it STABLE finally. + * Instead of using SQL conditional comments, detect MySQL version. + +2006-08-22: innotop 0.1.147, InnoDBParser version 1.60 + * Fix some innotop bugs with undefined values, bad formatting etc. + +2006-08-19: innotop 0.1.146, InnoDBParser version 1.60 + * Make innotop handle some unexpected NULL values in Q mode. + * Add OS wait information to W mode, so it is now "everything that waits." + * Center section captions better. + * Make R mode more readable and compact. + * Make InnoDBParser parse lock waits even when they've been waiting 0 secs. + +2006-08-12: innotop 0.1.139, InnoDBParser version 1.59 + * Add more documentation + * Tweak V mode to show more info in less space. + * Fix a bug in G mode. + +2006-08-10: innotop 0.1.132, InnoDBParser version 1.58 + * Handle yet more types of FK error... it will never end! + * Handle some special cases when DEADLOCK info truncated + * Add a bit more FK info to F mode in innotop + * More tests added to the test suite + +2006-08-07: innotop 0.1.131, InnoDBParser version 1.55 + * Fix another issue with configuration + * Handle another type of FK error + +2006-08-03: innotop 0.1.130, InnoDBParser version 1.54 + * Fix an issue loading config file + * Add heap_no to 'D' (InnoDB Deadlock) mode to ease deadlock debugging. + +2006-08-02: innotop 0.1.128, InnoDBParser version 1.54 + * Parse lock wait information from the TRANSACTION section. + * Even more OS-specific parsing... pain in the butt... + * Add 'W' (InnoDB Lock Wait) mode. + * Fix some minor display issues with statusbar. + +2006-08-02: innotop 0.1.125, InnoDBParser version 1.50 + * Don't try to get references to Perl built-in functions like time() + * Handle more OS-specific variations of InnoDB status text + * Add some more information to various places in innotop + +2006-08-01: innotop 0.1.123, InnoDBParser version 1.47 + + * Enhance S and G modes: clear screen and re-print headers + * Don't crash when deadlock data is truncated + * Make Analyze mode say how to get back to whatever you came from + * Display 'nothing to display' when there is nothing + * Add ability to read InnoDB status text from a file (mostly helps test) + * Add table of Wait Array Information in Row Op/Semaphore mode + * Add table of lock information in InnoDB deadlock mode + * Ensure new features in upgrades don't get masked by existing config files + * Tweak default column choices for T mode + * Enhance foreign key parsing + * Enhance physical record and data tuple parsing + * Enhance lock parsing (handle old-style and new-style formats) + +2006-07-24: innotop 0.1.112, InnoDBParser version 1.36 + + * InnoDBParser enhancements for FK error messages. + * A fix to innotop to prevent it from crashing while trying to display a FK + error message. + * Some minor cosmetic changes to number formatting in innotop. + +2006-07-22: innotop 0.1.106, InnoDBParser version 1.35 + + * InnoDBParser is much more complete and accurate. + * Tons of bug fixes. + * Add partitions to EXPLAIN mode. + * Enhance Q mode header, add T mode header. + * Share some configuration variables across modes. + * Add formatted time columns to Q, T modes. + * Add command-line argument parsing. + * Turn off echo when asking for password. + * Add option to specify port when connecting. + * Let display-optimized-query display multiple notes. + * Lots of small improvements, such as showing more info in statusbar. + +2006-07-02: innotop 0.1.74, InnoDBParser version 1.24 + + * Initial release for public consumption. diff --git a/debian/additions/innotop/innotop b/debian/additions/innotop/innotop new file mode 100644 index 00000000000..646f0d7f0fb --- /dev/null +++ b/debian/additions/innotop/innotop @@ -0,0 +1,10946 @@ +#!/usr/bin/perl + +# vim: tw=160:nowrap:expandtab:tabstop=3:shiftwidth=3:softtabstop=3 + +# This program is copyright (c) 2006 Baron Schwartz, baron at xaprb dot com. +# Feedback and improvements are gratefully received. +# +# THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +# MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. +# +# 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 +# Foundation, version 2; OR the Perl Artistic License. On UNIX and similar +# systems, you can issue `man perlgpl' or `man perlartistic' to read these + +# 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 + +use strict; +use warnings FATAL => 'all'; + +our $VERSION = '1.7.1'; + +# Find the home directory; it's different on different OSes. +our $homepath = $ENV{HOME} || $ENV{HOMEPATH} || $ENV{USERPROFILE} || '.'; + +# Configuration files +our $default_home_conf = "$homepath/.innotop/innotop.conf"; +our $default_central_conf = "/etc/innotop/innotop.conf"; +our $conf_file = ""; + +## Begin packages ## + +package DSNParser; + +use DBI; +use Data::Dumper; +$Data::Dumper::Indent = 0; +$Data::Dumper::Quotekeys = 0; +use English qw(-no_match_vars); + +use constant MKDEBUG => $ENV{MKDEBUG}; + +# Defaults are built-in, but you can add/replace items by passing them as +# hashrefs of {key, desc, copy, dsn}. The desc and dsn items are optional. +# You can set properties with the prop() sub. Don't set the 'opts' property. +sub new { + my ( $class, @opts ) = @_; + my $self = { + opts => { + A => { + desc => 'Default character set', + dsn => 'charset', + copy => 1, + }, + D => { + desc => 'Database to use', + dsn => 'database', + copy => 1, + }, + F => { + desc => 'Only read default options from the given file', + dsn => 'mysql_read_default_file', + copy => 1, + }, + h => { + desc => 'Connect to host', + dsn => 'host', + copy => 1, + }, + p => { + desc => 'Password to use when connecting', + dsn => 'password', + copy => 1, + }, + P => { + desc => 'Port number to use for connection', + dsn => 'port', + copy => 1, + }, + S => { + desc => 'Socket file to use for connection', + dsn => 'mysql_socket', + copy => 1, + }, + u => { + desc => 'User for login if not current user', + dsn => 'user', + copy => 1, + }, + }, + }; + foreach my $opt ( @opts ) { + MKDEBUG && _d('Adding extra property ' . $opt->{key}); + $self->{opts}->{$opt->{key}} = { desc => $opt->{desc}, copy => $opt->{copy} }; + } + return bless $self, $class; +} + +# Recognized properties: +# * autokey: which key to treat a bareword as (typically h=host). +# * dbidriver: which DBI driver to use; assumes mysql, supports Pg. +# * required: which parts are required (hashref). +# * setvars: a list of variables to set after connecting +sub prop { + my ( $self, $prop, $value ) = @_; + if ( @_ > 2 ) { + MKDEBUG && _d("Setting $prop property"); + $self->{$prop} = $value; + } + return $self->{$prop}; +} + +sub parse { + my ( $self, $dsn, $prev, $defaults ) = @_; + if ( !$dsn ) { + MKDEBUG && _d('No DSN to parse'); + return; + } + MKDEBUG && _d("Parsing $dsn"); + $prev ||= {}; + $defaults ||= {}; + my %given_props; + my %final_props; + my %opts = %{$self->{opts}}; + my $prop_autokey = $self->prop('autokey'); + + # Parse given props + foreach my $dsn_part ( split(/,/, $dsn) ) { + if ( my ($prop_key, $prop_val) = $dsn_part =~ m/^(.)=(.*)$/ ) { + # Handle the typical DSN parts like h=host, P=3306, etc. + $given_props{$prop_key} = $prop_val; + } + elsif ( $prop_autokey ) { + # Handle barewords + MKDEBUG && _d("Interpreting $dsn_part as $prop_autokey=$dsn_part"); + $given_props{$prop_autokey} = $dsn_part; + } + else { + MKDEBUG && _d("Bad DSN part: $dsn_part"); + } + } + + # Fill in final props from given, previous, and/or default props + foreach my $key ( keys %opts ) { + MKDEBUG && _d("Finding value for $key"); + $final_props{$key} = $given_props{$key}; + if ( !defined $final_props{$key} + && defined $prev->{$key} && $opts{$key}->{copy} ) + { + $final_props{$key} = $prev->{$key}; + MKDEBUG && _d("Copying value for $key from previous DSN"); + } + if ( !defined $final_props{$key} ) { + $final_props{$key} = $defaults->{$key}; + MKDEBUG && _d("Copying value for $key from defaults"); + } + } + + # Sanity check props + foreach my $key ( keys %given_props ) { + die "Unrecognized DSN part '$key' in '$dsn'\n" + unless exists $opts{$key}; + } + if ( (my $required = $self->prop('required')) ) { + foreach my $key ( keys %$required ) { + die "Missing DSN part '$key' in '$dsn'\n" unless $final_props{$key}; + } + } + + return \%final_props; +} + +sub as_string { + my ( $self, $dsn ) = @_; + return $dsn unless ref $dsn; + return join(',', + map { "$_=" . ($_ eq 'p' ? '...' : $dsn->{$_}) } + grep { defined $dsn->{$_} && $self->{opts}->{$_} } + sort keys %$dsn ); +} + +sub usage { + my ( $self ) = @_; + my $usage + = "DSN syntax is key=value[,key=value...] Allowable DSN keys:\n" + . " KEY COPY MEANING\n" + . " === ==== =============================================\n"; + my %opts = %{$self->{opts}}; + foreach my $key ( sort keys %opts ) { + $usage .= " $key " + . ($opts{$key}->{copy} ? 'yes ' : 'no ') + . ($opts{$key}->{desc} || '[No description]') + . "\n"; + } + if ( (my $key = $self->prop('autokey')) ) { + $usage .= " If the DSN is a bareword, the word is treated as the '$key' key.\n"; + } + return $usage; +} + +# Supports PostgreSQL via the dbidriver element of $info, but assumes MySQL by +# default. +sub get_cxn_params { + my ( $self, $info ) = @_; + my $dsn; + my %opts = %{$self->{opts}}; + my $driver = $self->prop('dbidriver') || ''; + if ( $driver eq 'Pg' ) { + $dsn = 'DBI:Pg:dbname=' . ( $info->{D} || '' ) . ';' + . join(';', map { "$opts{$_}->{dsn}=$info->{$_}" } + grep { defined $info->{$_} } + qw(h P)); + } + else { + $dsn = 'DBI:mysql:' . ( $info->{D} || '' ) . ';' + . join(';', map { "$opts{$_}->{dsn}=$info->{$_}" } + grep { defined $info->{$_} } + qw(F h P S A)) + . ';mysql_read_default_group=client'; + } + MKDEBUG && _d($dsn); + return ($dsn, $info->{u}, $info->{p}); +} + + +# Fills in missing info from a DSN after successfully connecting to the server. +sub fill_in_dsn { + my ( $self, $dbh, $dsn ) = @_; + my $vars = $dbh->selectall_hashref('SHOW VARIABLES', 'Variable_name'); + my ($user, $db) = $dbh->selectrow_array('SELECT USER(), DATABASE()'); + $user =~ s/@.*//; + $dsn->{h} ||= $vars->{hostname}->{Value}; + $dsn->{S} ||= $vars->{'socket'}->{Value}; + $dsn->{P} ||= $vars->{port}->{Value}; + $dsn->{u} ||= $user; + $dsn->{D} ||= $db; +} + +sub get_dbh { + my ( $self, $cxn_string, $user, $pass, $opts ) = @_; + $opts ||= {}; + my $defaults = { + AutoCommit => 0, + RaiseError => 1, + PrintError => 0, + mysql_enable_utf8 => ($cxn_string =~ m/charset=utf8/ ? 1 : 0), + }; + @{$defaults}{ keys %$opts } = values %$opts; + my $dbh; + my $tries = 2; + while ( !$dbh && $tries-- ) { + eval { + MKDEBUG && _d($cxn_string, ' ', $user, ' ', $pass, ' {', + join(', ', map { "$_=>$defaults->{$_}" } keys %$defaults ), '}'); + $dbh = DBI->connect($cxn_string, $user, $pass, $defaults); + # Immediately set character set and binmode on STDOUT. + if ( my ($charset) = $cxn_string =~ m/charset=(\w+)/ ) { + my $sql = "/*!40101 SET NAMES $charset*/"; + MKDEBUG && _d("$dbh: $sql"); + $dbh->do($sql); + MKDEBUG && _d('Enabling charset for STDOUT'); + if ( $charset eq 'utf8' ) { + binmode(STDOUT, ':utf8') + or die "Can't binmode(STDOUT, ':utf8'): $OS_ERROR"; + } + else { + binmode(STDOUT) or die "Can't binmode(STDOUT): $OS_ERROR"; + } + } + }; + if ( !$dbh && $EVAL_ERROR ) { + MKDEBUG && _d($EVAL_ERROR); + if ( $EVAL_ERROR =~ m/not a compiled character set|character set utf8/ ) { + MKDEBUG && _d("Going to try again without utf8 support"); + delete $defaults->{mysql_enable_utf8}; + } + if ( !$tries ) { + die $EVAL_ERROR; + } + } + } + # If setvars exists and it's MySQL connection, set them + my $setvars = $self->prop('setvars'); + if ( $cxn_string =~ m/mysql/i && $setvars ) { + my $sql = "SET $setvars"; + MKDEBUG && _d("$dbh: $sql"); + eval { + $dbh->do($sql); + }; + if ( $EVAL_ERROR ) { + MKDEBUG && _d($EVAL_ERROR); + } + } + MKDEBUG && _d('DBH info: ', + $dbh, + Dumper($dbh->selectrow_hashref( + 'SELECT DATABASE(), CONNECTION_ID(), VERSION()/*!50038 , @@hostname*/')), + ' Connection info: ', ($dbh->{mysql_hostinfo} || 'undef'), + ' Character set info: ', + Dumper($dbh->selectall_arrayref( + 'SHOW VARIABLES LIKE "character_set%"', { Slice => {}})), + ' $DBD::mysql::VERSION: ', $DBD::mysql::VERSION, + ' $DBI::VERSION: ', $DBI::VERSION, + ); + return $dbh; +} + +# Tries to figure out a hostname for the connection. +sub get_hostname { + my ( $self, $dbh ) = @_; + if ( my ($host) = ($dbh->{mysql_hostinfo} || '') =~ m/^(\w+) via/ ) { + return $host; + } + my ( $hostname, $one ) = $dbh->selectrow_array( + 'SELECT /*!50038 @@hostname, */ 1'); + return $hostname; +} + +# Disconnects a database handle, but complains verbosely if there are any active +# children. These are usually $sth handles that haven't been finish()ed. +sub disconnect { + my ( $self, $dbh ) = @_; + MKDEBUG && $self->print_active_handles($dbh); + $dbh->disconnect; +} + +sub print_active_handles { + my ( $self, $thing, $level ) = @_; + $level ||= 0; + printf("# Active %sh: %s %s %s\n", ($thing->{Type} || 'undef'), "\t" x $level, + $thing, (($thing->{Type} || '') eq 'st' ? $thing->{Statement} || '' : '')) + or die "Cannot print: $OS_ERROR"; + foreach my $handle ( grep {defined} @{ $thing->{ChildHandles} } ) { + $self->print_active_handles( $handle, $level + 1 ); + } +} + +sub _d { + my ($package, undef, $line) = caller 0; + @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } + map { defined $_ ? $_ : 'undef' } + @_; + # Use $$ instead of $PID in case the package + # does not use English. + print "# $package:$line $$ ", @_, "\n"; +} + +1; + +package InnoDBParser; + +use Data::Dumper; +$Data::Dumper::Sortkeys = 1; +use English qw(-no_match_vars); +use List::Util qw(max); + +# Some common patterns +my $d = qr/(\d+)/; # Digit +my $f = qr/(\d+\.\d+)/; # Float +my $t = qr/(\d+ \d+)/; # Transaction ID +my $i = qr/((?:\d{1,3}\.){3}\d+)/; # IP address +my $n = qr/([^`\s]+)/; # MySQL object name +my $w = qr/(\w+)/; # Words +my $fl = qr/([\w\.\/]+) line $d/; # Filename and line number +my $h = qr/((?:0x)?[0-9a-f]*)/; # Hex +my $s = qr/(\d{6} .\d:\d\d:\d\d)/; # InnoDB timestamp + +# If you update this variable, also update the SYNOPSIS in the pod. +my %innodb_section_headers = ( + "TRANSACTIONS" => "tx", + "BUFFER POOL AND MEMORY" => "bp", + "SEMAPHORES" => "sm", + "LOG" => "lg", + "ROW OPERATIONS" => "ro", + "INSERT BUFFER AND ADAPTIVE HASH INDEX" => "ib", + "FILE I/O" => "io", + "LATEST DETECTED DEADLOCK" => "dl", + "LATEST FOREIGN KEY ERROR" => "fk", +); + +my %parser_for = ( + tx => \&parse_tx_section, + bp => \&parse_bp_section, + sm => \&parse_sm_section, + lg => \&parse_lg_section, + ro => \&parse_ro_section, + ib => \&parse_ib_section, + io => \&parse_io_section, + dl => \&parse_dl_section, + fk => \&parse_fk_section, +); + +my %fk_parser_for = ( + Transaction => \&parse_fk_transaction_error, + Error => \&parse_fk_bad_constraint_error, + Cannot => \&parse_fk_cant_drop_parent_error, +); + +# A thread's proc_info can be at least 98 different things I've found in the +# source. Fortunately, most of them begin with a gerunded verb. These are +# the ones that don't. +my %is_proc_info = ( + 'After create' => 1, + 'Execution of init_command' => 1, + 'FULLTEXT initialization' => 1, + 'Reopen tables' => 1, + 'Repair done' => 1, + 'Repair with keycache' => 1, + 'System lock' => 1, + 'Table lock' => 1, + 'Thread initialized' => 1, + 'User lock' => 1, + 'copy to tmp table' => 1, + 'discard_or_import_tablespace' => 1, + 'end' => 1, + 'got handler lock' => 1, + 'got old table' => 1, + 'init' => 1, + 'key cache' => 1, + 'locks' => 1, + 'malloc' => 1, + 'query end' => 1, + 'rename result table' => 1, + 'rename' => 1, + 'setup' => 1, + 'statistics' => 1, + 'status' => 1, + 'table cache' => 1, + 'update' => 1, +); + +sub new { + bless {}, shift; +} + +# Parse the status and return it. +# See srv_printf_innodb_monitor in innobase/srv/srv0srv.c +# Pass in the text to parse, whether to be in debugging mode, which sections +# to parse (hashref; if empty, parse all), and whether to parse full info from +# locks and such (probably shouldn't unless you need to). +sub parse_status_text { + my ( $self, $fulltext, $debug, $sections, $full ) = @_; + + die "I can't parse undef" unless defined $fulltext; + $fulltext =~ s/[\r\n]+/\n/g; + + $sections ||= {}; + die '$sections must be a hashref' unless ref($sections) eq 'HASH'; + + my %innodb_data = ( + got_all => 0, # Whether I was able to get the whole thing + ts => '', # Timestamp the server put on it + last_secs => 0, # Num seconds the averages are over + sections => {}, # Parsed values from each section + ); + + if ( $debug ) { + $innodb_data{'fulltext'} = $fulltext; + } + + # Get the most basic info about the status: beginning and end, and whether + # I got the whole thing (if there has been a big deadlock and there are + # too many locks to print, the output might be truncated) + my ( $time_text ) = $fulltext =~ m/^$s INNODB MONITOR OUTPUT$/m; + $innodb_data{'ts'} = [ parse_innodb_timestamp( $time_text ) ]; + $innodb_data{'timestring'} = ts_to_string($innodb_data{'ts'}); + ( $innodb_data{'last_secs'} ) = $fulltext + =~ m/Per second averages calculated from the last $d seconds/; + + ( my $got_all ) = $fulltext =~ m/END OF INNODB MONITOR OUTPUT/; + $innodb_data{'got_all'} = $got_all || 0; + + # Split it into sections. Each section begins with + # ----- + # LABEL + # ----- + my %innodb_sections; + my @matches = $fulltext + =~ m#\n(---+)\n([A-Z /]+)\n\1\n(.*?)(?=\n(---+)\n[A-Z /]+\n\4\n|$)#gs; + while ( my ( $start, $name, $text, $end ) = splice(@matches, 0, 4) ) { + $innodb_sections{$name} = [ $text, $end ? 1 : 0 ]; + } + # The Row Operations section is a special case, because instead of ending + # with the beginning of another section, it ends with the end of the file. + # So this section is complete if the entire file is complete. + $innodb_sections{'ROW OPERATIONS'}->[1] ||= $innodb_data{'got_all'}; + + # Just for sanity's sake, make sure I understand what to do with each + # section + eval { + foreach my $section ( keys %innodb_sections ) { + my $header = $innodb_section_headers{$section}; + die "Unknown section $section in $fulltext\n" + unless $header; + $innodb_data{'sections'}->{ $header } + ->{'fulltext'} = $innodb_sections{$section}->[0]; + $innodb_data{'sections'}->{ $header } + ->{'complete'} = $innodb_sections{$section}->[1]; + } + }; + if ( $EVAL_ERROR ) { + _debug( $debug, $EVAL_ERROR); + } + + # ################################################################ + # Parse the detailed data out of the sections. + # ################################################################ + eval { + foreach my $section ( keys %parser_for ) { + if ( defined $innodb_data{'sections'}->{$section} + && (!%$sections || (defined($sections->{$section} && $sections->{$section})) )) { + $parser_for{$section}->( + $innodb_data{'sections'}->{$section}, + $innodb_data{'sections'}->{$section}->{'complete'}, + $debug, + $full ) + or delete $innodb_data{'sections'}->{$section}; + } + else { + delete $innodb_data{'sections'}->{$section}; + } + } + }; + if ( $EVAL_ERROR ) { + _debug( $debug, $EVAL_ERROR); + } + + return \%innodb_data; +} + +# Parses the status text and returns it flattened out as a single hash. +sub get_status_hash { + my ( $self, $fulltext, $debug, $sections, $full ) = @_; + + # Parse the status text... + my $innodb_status + = $self->parse_status_text($fulltext, $debug, $sections, $full ); + + # Flatten the hierarchical structure into a single list by grabbing desired + # sections from it. + return + (map { 'IB_' . $_ => $innodb_status->{$_} } qw(timestring last_secs got_all)), + (map { 'IB_bp_' . $_ => $innodb_status->{'sections'}->{'bp'}->{$_} } + qw( writes_pending buf_pool_hit_rate total_mem_alloc buf_pool_reads + awe_mem_alloc pages_modified writes_pending_lru page_creates_sec + reads_pending pages_total buf_pool_hits writes_pending_single_page + page_writes_sec pages_read pages_written page_reads_sec + writes_pending_flush_list buf_pool_size add_pool_alloc + dict_mem_alloc pages_created buf_free complete )), + (map { 'IB_tx_' . $_ => $innodb_status->{'sections'}->{'tx'}->{$_} } + qw( num_lock_structs history_list_len purge_done_for transactions + purge_undo_for is_truncated trx_id_counter complete )), + (map { 'IB_ib_' . $_ => $innodb_status->{'sections'}->{'ib'}->{$_} } + qw( hash_table_size hash_searches_s non_hash_searches_s + bufs_in_node_heap used_cells size free_list_len seg_size inserts + merged_recs merges complete )), + (map { 'IB_lg_' . $_ => $innodb_status->{'sections'}->{'lg'}->{$_} } + qw( log_ios_done pending_chkp_writes last_chkp log_ios_s + log_flushed_to log_seq_no pending_log_writes complete )), + (map { 'IB_sm_' . $_ => $innodb_status->{'sections'}->{'sm'}->{$_} } + qw( wait_array_size rw_shared_spins rw_excl_os_waits mutex_os_waits + mutex_spin_rounds mutex_spin_waits rw_excl_spins rw_shared_os_waits + waits signal_count reservation_count complete )), + (map { 'IB_ro_' . $_ => $innodb_status->{'sections'}->{'ro'}->{$_} } + qw( queries_in_queue n_reserved_extents main_thread_state + main_thread_proc_no main_thread_id read_sec del_sec upd_sec ins_sec + read_views_open num_rows_upd num_rows_ins num_rows_read + queries_inside num_rows_del complete )), + (map { 'IB_fk_' . $_ => $innodb_status->{'sections'}->{'fk'}->{$_} } + qw( trigger parent_table child_index parent_index attempted_op + child_db timestring fk_name records col_name reason txn parent_db + type child_table parent_col complete )), + (map { 'IB_io_' . $_ => $innodb_status->{'sections'}->{'io'}->{$_} } + qw( pending_buffer_pool_flushes pending_pwrites pending_preads + pending_normal_aio_reads fsyncs_s os_file_writes pending_sync_ios + reads_s flush_type avg_bytes_s pending_ibuf_aio_reads writes_s + threads os_file_reads pending_aio_writes pending_log_ios os_fsyncs + pending_log_flushes complete )), + (map { 'IB_dl_' . $_ => $innodb_status->{'sections'}->{'dl'}->{$_} } + qw( timestring rolled_back txns complete )); + +} + +sub ts_to_string { + my $parts = shift; + return sprintf('%02d-%02d-%02d %02d:%02d:%02d', @$parts); +} + +sub parse_innodb_timestamp { + my $text = shift; + my ( $y, $m, $d, $h, $i, $s ) + = $text =~ m/^(\d\d)(\d\d)(\d\d) +(\d+):(\d+):(\d+)$/; + die("Can't get timestamp from $text\n") unless $y; + $y += 2000; + return ( $y, $m, $d, $h, $i, $s ); +} + +sub parse_fk_section { + my ( $section, $complete, $debug, $full ) = @_; + my $fulltext = $section->{'fulltext'}; + + return 0 unless $fulltext; + + my ( $ts, $type ) = $fulltext =~ m/^$s\s+(\w+)/m; + $section->{'ts'} = [ parse_innodb_timestamp( $ts ) ]; + $section->{'timestring'} = ts_to_string($section->{'ts'}); + $section->{'type'} = $type; + + # Decide which type of FK error happened, and dispatch to the right parser. + if ( $type && $fk_parser_for{$type} ) { + $fk_parser_for{$type}->( $section, $complete, $debug, $fulltext, $full ); + } + + delete $section->{'fulltext'} unless $debug; + + return 1; +} + +sub parse_fk_cant_drop_parent_error { + my ( $section, $complete, $debug, $fulltext, $full ) = @_; + + # Parse the parent/child table info out + @{$section}{ qw(attempted_op parent_db parent_table) } = $fulltext + =~ m{Cannot $w table `(.*)/(.*)`}m; + @{$section}{ qw(child_db child_table) } = $fulltext + =~ m{because it is referenced by `(.*)/(.*)`}m; + + ( $section->{'reason'} ) = $fulltext =~ m/(Cannot .*)/s; + $section->{'reason'} =~ s/\n(?:InnoDB: )?/ /gm + if $section->{'reason'}; + + # Certain data may not be present. Make them '' if not present. + map { $section->{$_} ||= "" } + qw(child_index fk_name col_name parent_col); +} + +# See dict/dict0dict.c, function dict_foreign_error_report +# I don't care much about these. There are lots of different messages, and +# they come from someone trying to create a foreign key, or similar +# statements. They aren't indicative of some transaction trying to insert, +# delete or update data. Sometimes it is possible to parse out a lot of +# information about the tables and indexes involved, but often the message +# contains the DDL string the user entered, which is way too much for this +# module to try to handle. +sub parse_fk_bad_constraint_error { + my ( $section, $complete, $debug, $fulltext, $full ) = @_; + + # Parse the parent/child table and index info out + @{$section}{ qw(child_db child_table) } = $fulltext + =~ m{Error in foreign key constraint of table (.*)/(.*):$}m; + $section->{'attempted_op'} = 'DDL'; + + # FK name, parent info... if possible. + @{$section}{ qw(fk_name col_name parent_db parent_table parent_col) } + = $fulltext + =~ m/CONSTRAINT `?$n`? FOREIGN KEY \(`?$n`?\) REFERENCES (?:`?$n`?\.)?`?$n`? \(`?$n`?\)/; + + if ( !defined($section->{'fk_name'}) ) { + # Try to parse SQL a user might have typed in a CREATE statement or such + @{$section}{ qw(col_name parent_db parent_table parent_col) } + = $fulltext + =~ m/FOREIGN\s+KEY\s*\(`?$n`?\)\s+REFERENCES\s+(?:`?$n`?\.)?`?$n`?\s*\(`?$n`?\)/i; + } + $section->{'parent_db'} ||= $section->{'child_db'}; + + # Name of the child index (index in the same table where the FK is, see + # definition of dict_foreign_struct in include/dict0mem.h, where it is + # called foreign_index, as opposed to referenced_index which is in the + # parent table. This may not be possible to find. + @{$section}{ qw(child_index) } = $fulltext + =~ m/^The index in the foreign key in table is $n$/m; + + @{$section}{ qw(reason) } = $fulltext =~ m/:\s*([^:]+)(?= Constraint:|$)/ms; + $section->{'reason'} =~ s/\s+/ /g + if $section->{'reason'}; + + # Certain data may not be present. Make them '' if not present. + map { $section->{$_} ||= "" } + qw(child_index fk_name col_name parent_table parent_col); +} + +# see source file row/row0ins.c +sub parse_fk_transaction_error { + my ( $section, $complete, $debug, $fulltext, $full ) = @_; + + # Parse the txn info out + my ( $txn ) = $fulltext + =~ m/Transaction:\n(TRANSACTION.*)\nForeign key constraint fails/s; + if ( $txn ) { + $section->{'txn'} = parse_tx_text( $txn, $complete, $debug, $full ); + } + + # Parse the parent/child table and index info out. There are two types: an + # update or a delete of a parent record leaves a child orphaned + # (row_ins_foreign_report_err), and an insert or update of a child record has + # no matching parent record (row_ins_foreign_report_add_err). + + @{$section}{ qw(reason child_db child_table) } + = $fulltext =~ m{^(Foreign key constraint fails for table `(.*)/(.*)`:)$}m; + + @{$section}{ qw(fk_name col_name parent_db parent_table parent_col) } + = $fulltext + =~ m/CONSTRAINT `$n` FOREIGN KEY \(`$n`\) REFERENCES (?:`$n`\.)?`$n` \(`$n`\)/; + $section->{'parent_db'} ||= $section->{'child_db'}; + + # Special case, which I don't know how to trigger, but see + # innobase/row/row0ins.c row_ins_check_foreign_constraint + if ( $fulltext =~ m/ibd file does not currently exist!/ ) { + my ( $attempted_op, $index, $records ) + = $fulltext =~ m/^Trying to (add to index) `$n` tuple:\n(.*))?/sm; + $section->{'child_index'} = $index; + $section->{'attempted_op'} = $attempted_op || ''; + if ( $records && $full ) { + ( $section->{'records'} ) + = parse_innodb_record_dump( $records, $complete, $debug ); + } + @{$section}{qw(parent_db parent_table)} + =~ m/^But the parent table `$n`\.`$n`$/m; + } + else { + my ( $attempted_op, $which, $index ) + = $fulltext =~ m/^Trying to ([\w ]*) in (child|parent) table, in index `$n` tuple:$/m; + if ( $which ) { + $section->{$which . '_index'} = $index; + $section->{'attempted_op'} = $attempted_op || ''; + + # Parse out the related records in the other table. + my ( $search_index, $records ); + if ( $which eq 'child' ) { + ( $search_index, $records ) = $fulltext + =~ m/^But in parent table [^,]*, in index `$n`,\nthe closest match we can find is record:\n(.*)/ms; + $section->{'parent_index'} = $search_index; + } + else { + ( $search_index, $records ) = $fulltext + =~ m/^But in child table [^,]*, in index `$n`, (?:the record is not available|there is a record:\n(.*))?/ms; + $section->{'child_index'} = $search_index; + } + if ( $records && $full ) { + $section->{'records'} + = parse_innodb_record_dump( $records, $complete, $debug ); + } + else { + $section->{'records'} = ''; + } + } + } + + # Parse out the tuple trying to be updated, deleted or inserted. + my ( $trigger ) = $fulltext =~ m/^(DATA TUPLE: \d+ fields;\n.*)$/m; + if ( $trigger ) { + $section->{'trigger'} = parse_innodb_record_dump( $trigger, $complete, $debug ); + } + + # Certain data may not be present. Make them '' if not present. + map { $section->{$_} ||= "" } + qw(child_index fk_name col_name parent_table parent_col); +} + +# There are new-style and old-style record formats. See rem/rem0rec.c +# TODO: write some tests for this +sub parse_innodb_record_dump { + my ( $dump, $complete, $debug ) = @_; + return undef unless $dump; + + my $result = {}; + + if ( $dump =~ m/PHYSICAL RECORD/ ) { + my $style = $dump =~ m/compact format/ ? 'new' : 'old'; + $result->{'style'} = $style; + + # This is a new-style record. + if ( $style eq 'new' ) { + @{$result}{qw( heap_no type num_fields info_bits )} + = $dump + =~ m/^(?:Record lock, heap no $d )?([A-Z ]+): n_fields $d; compact format; info bits $d$/m; + } + + # OK, it's old-style. Unfortunately there are variations here too. + elsif ( $dump =~ m/-byte offs / ) { + # Older-old style. + @{$result}{qw( heap_no type num_fields byte_offset info_bits )} + = $dump + =~ m/^(?:Record lock, heap no $d )?([A-Z ]+): n_fields $d; $d-byte offs [A-Z]+; info bits $d$/m; + if ( $dump !~ m/-byte offs TRUE/ ) { + $result->{'byte_offset'} = 0; + } + } + else { + # Newer-old style. + @{$result}{qw( heap_no type num_fields byte_offset info_bits )} + = $dump + =~ m/^(?:Record lock, heap no $d )?([A-Z ]+): n_fields $d; $d-byte offsets; info bits $d$/m; + } + + } + else { + $result->{'style'} = 'tuple'; + @{$result}{qw( type num_fields )} + = $dump =~ m/^(DATA TUPLE): $d fields;$/m; + } + + # Fill in default values for things that couldn't be parsed. + map { $result->{$_} ||= 0 } + qw(heap_no num_fields byte_offset info_bits); + map { $result->{$_} ||= '' } + qw(style type ); + + my @fields = $dump =~ m/ (\d+:.*?;?);(?=$| \d+:)/gm; + $result->{'fields'} = [ map { parse_field($_, $complete, $debug ) } @fields ]; + + return $result; +} + +# New/old-style applies here. See rem/rem0rec.c +# $text should not include the leading space or the second trailing semicolon. +sub parse_field { + my ( $text, $complete, $debug ) = @_; + + # Sample fields: + # '4: SQL NULL, size 4 ' + # '1: len 6; hex 000000005601; asc V ;' + # '6: SQL NULL' + # '5: len 30; hex 687474703a2f2f7777772e737765657477617465722e636f6d2f73746f72; asc http://www.sweetwater.com/stor;...(truncated)' + my ( $id, $nullsize, $len, $hex, $asc, $truncated ); + ( $id, $nullsize ) = $text =~ m/^$d: SQL NULL, size $d $/; + if ( !defined($id) ) { + ( $id ) = $text =~ m/^$d: SQL NULL$/; + } + if ( !defined($id) ) { + ( $id, $len, $hex, $asc, $truncated ) + = $text =~ m/^$d: len $d; hex $h; asc (.*);(\.\.\.\(truncated\))?$/; + } + + die "Could not parse this field: '$text'" unless defined $id; + return { + id => $id, + len => defined($len) ? $len : defined($nullsize) ? $nullsize : 0, + 'hex' => defined($hex) ? $hex : '', + asc => defined($asc) ? $asc : '', + trunc => $truncated ? 1 : 0, + }; + +} + +sub parse_dl_section { + my ( $dl, $complete, $debug, $full ) = @_; + return unless $dl; + my $fulltext = $dl->{'fulltext'}; + return 0 unless $fulltext; + + my ( $ts ) = $fulltext =~ m/^$s$/m; + return 0 unless $ts; + + $dl->{'ts'} = [ parse_innodb_timestamp( $ts ) ]; + $dl->{'timestring'} = ts_to_string($dl->{'ts'}); + $dl->{'txns'} = {}; + + my @sections + = $fulltext + =~ m{ + ^\*{3}\s([^\n]*) # *** (1) WAITING FOR THIS... + (.*?) # Followed by anything, non-greedy + (?=(?:^\*{3})|\z) # Followed by another three stars or EOF + }gmsx; + + + # Loop through each section. There are no assumptions about how many + # there are, who holds and wants what locks, and who gets rolled back. + while ( my ($header, $body) = splice(@sections, 0, 2) ) { + my ( $txn_id, $what ) = $header =~ m/^\($d\) (.*):$/; + next unless $txn_id; + $dl->{'txns'}->{$txn_id} ||= {}; + my $txn = $dl->{'txns'}->{$txn_id}; + + if ( $what eq 'TRANSACTION' ) { + $txn->{'tx'} = parse_tx_text( $body, $complete, $debug, $full ); + } + else { + push @{$txn->{'locks'}}, parse_innodb_record_locks( $body, $complete, $debug, $full ); + } + } + + @{ $dl }{ qw(rolled_back) } + = $fulltext =~ m/^\*\*\* WE ROLL BACK TRANSACTION \($d\)$/m; + + # Make sure certain values aren't undef + map { $dl->{$_} ||= '' } qw(rolled_back); + + delete $dl->{'fulltext'} unless $debug; + return 1; +} + +sub parse_innodb_record_locks { + my ( $text, $complete, $debug, $full ) = @_; + my @result; + + foreach my $lock ( $text =~ m/(^(?:RECORD|TABLE) LOCKS?.*$)/gm ) { + my $hash = {}; + @{$hash}{ qw(lock_type space_id page_no n_bits index db table txn_id lock_mode) } + = $lock + =~ m{^(RECORD|TABLE) LOCKS? (?:space id $d page no $d n bits $d index `?$n`? of )?table `$n(?:/|`\.`)$n` trx id $t lock.mode (\S+)}m; + ( $hash->{'special'} ) + = $lock =~ m/^(?:RECORD|TABLE) .*? locks (rec but not gap|gap before rec)/m; + $hash->{'insert_intention'} + = $lock =~ m/^(?:RECORD|TABLE) .*? insert intention/m ? 1 : 0; + $hash->{'waiting'} + = $lock =~ m/^(?:RECORD|TABLE) .*? waiting/m ? 1 : 0; + + # Some things may not be in the text, so make sure they are not + # undef. + map { $hash->{$_} ||= 0 } qw(n_bits page_no space_id); + map { $hash->{$_} ||= "" } qw(index special); + push @result, $hash; + } + + return @result; +} + +sub parse_tx_text { + my ( $txn, $complete, $debug, $full ) = @_; + + my ( $txn_id, $txn_status, $active_secs, $proc_no, $os_thread_id ) + = $txn + =~ m/^(?:---)?TRANSACTION $t, (\D*?)(?: $d sec)?, (?:process no $d, )?OS thread id $d/m; + my ( $thread_status, $thread_decl_inside ) + = $txn + =~ m/OS thread id \d+(?: ([^,]+?))?(?:, thread declared inside InnoDB $d)?$/m; + + # Parsing the line that begins 'MySQL thread id' is complicated. The only + # thing always in the line is the thread and query id. See function + # innobase_mysql_print_thd in InnoDB source file sql/ha_innodb.cc. + my ( $thread_line ) = $txn =~ m/^(MySQL thread id .*)$/m; + my ( $mysql_thread_id, $query_id, $hostname, $ip, $user, $query_status ); + + if ( $thread_line ) { + # These parts can always be gotten. + ( $mysql_thread_id, $query_id ) = $thread_line =~ m/^MySQL thread id $d, query id $d/m; + + # If it's a master/slave thread, "Has (read|sent) all" may be the thread's + # proc_info. In these cases, there won't be any host/ip/user info + ( $query_status ) = $thread_line =~ m/(Has (?:read|sent) all .*$)/m; + if ( defined($query_status) ) { + $user = 'system user'; + } + + # It may be the case that the query id is the last thing in the line. + elsif ( $thread_line =~ m/query id \d+ / ) { + # The IP address is the only non-word thing left, so it's the most + # useful marker for where I have to start guessing. + ( $hostname, $ip ) = $thread_line =~ m/query id \d+(?: ([A-Za-z]\S+))? $i/m; + if ( defined $ip ) { + ( $user, $query_status ) = $thread_line =~ m/$ip $w(?: (.*))?$/; + } + else { # OK, there wasn't an IP address. + # There might not be ANYTHING except the query status. + ( $query_status ) = $thread_line =~ m/query id \d+ (.*)$/; + if ( $query_status !~ m/^\w+ing/ && !exists($is_proc_info{$query_status}) ) { + # The remaining tokens are, in order: hostname, user, query_status. + # It's basically impossible to know which is which. + ( $hostname, $user, $query_status ) = $thread_line + =~ m/query id \d+(?: ([A-Za-z]\S+))?(?: $w(?: (.*))?)?$/m; + } + else { + $user = 'system user'; + } + } + } + } + + my ( $lock_wait_status, $lock_structs, $heap_size, $row_locks, $undo_log_entries ) + = $txn + =~ m/^(?:(\D*) )?$d lock struct\(s\), heap size $d(?:, $d row lock\(s\))?(?:, undo log entries $d)?$/m; + my ( $lock_wait_time ) + = $txn + =~ m/^------- TRX HAS BEEN WAITING $d SEC/m; + + my $locks; + # If the transaction has locks, grab the locks. + if ( $txn =~ m/^TABLE LOCK|RECORD LOCKS/ ) { + $locks = [parse_innodb_record_locks($txn, $complete, $debug, $full)]; + } + + my ( $tables_in_use, $tables_locked ) + = $txn + =~ m/^mysql tables in use $d, locked $d$/m; + my ( $txn_doesnt_see_ge, $txn_sees_lt ) + = $txn + =~ m/^Trx read view will not see trx with id >= $t, sees < $t$/m; + my $has_read_view = defined($txn_doesnt_see_ge); + # Only a certain number of bytes of the query text are included here, at least + # under some circumstances. Some versions include 300, some 600. + my ( $query_text ) + = $txn + =~ m{ + ^MySQL\sthread\sid\s[^\n]+\n # This comes before the query text + (.*?) # The query text + (?= # Followed by any of... + ^Trx\sread\sview + |^-------\sTRX\sHAS\sBEEN\sWAITING + |^TABLE\sLOCK + |^RECORD\sLOCKS\sspace\sid + |^(?:---)?TRANSACTION + |^\*\*\*\s\(\d\) + |\Z + ) + }xms; + if ( $query_text ) { + $query_text =~ s/\s+$//; + } + else { + $query_text = ''; + } + + my %stuff = ( + active_secs => $active_secs, + has_read_view => $has_read_view, + heap_size => $heap_size, + hostname => $hostname, + ip => $ip, + lock_structs => $lock_structs, + lock_wait_status => $lock_wait_status, + lock_wait_time => $lock_wait_time, + mysql_thread_id => $mysql_thread_id, + os_thread_id => $os_thread_id, + proc_no => $proc_no, + query_id => $query_id, + query_status => $query_status, + query_text => $query_text, + row_locks => $row_locks, + tables_in_use => $tables_in_use, + tables_locked => $tables_locked, + thread_decl_inside => $thread_decl_inside, + thread_status => $thread_status, + txn_doesnt_see_ge => $txn_doesnt_see_ge, + txn_id => $txn_id, + txn_sees_lt => $txn_sees_lt, + txn_status => $txn_status, + undo_log_entries => $undo_log_entries, + user => $user, + ); + $stuff{'fulltext'} = $txn if $debug; + $stuff{'locks'} = $locks if $locks; + + # Some things may not be in the txn text, so make sure they are not + # undef. + map { $stuff{$_} ||= 0 } qw(active_secs heap_size lock_structs + tables_in_use undo_log_entries tables_locked has_read_view + thread_decl_inside lock_wait_time proc_no row_locks); + map { $stuff{$_} ||= "" } qw(thread_status txn_doesnt_see_ge + txn_sees_lt query_status ip query_text lock_wait_status user); + $stuff{'hostname'} ||= $stuff{'ip'}; + + return \%stuff; +} + +sub parse_tx_section { + my ( $section, $complete, $debug, $full ) = @_; + return unless $section && $section->{'fulltext'}; + my $fulltext = $section->{'fulltext'}; + $section->{'transactions'} = []; + + # Handle the individual transactions + my @transactions = $fulltext =~ m/(---TRANSACTION \d.*?)(?=\n---TRANSACTION|$)/gs; + foreach my $txn ( @transactions ) { + my $stuff = parse_tx_text( $txn, $complete, $debug, $full ); + delete $stuff->{'fulltext'} unless $debug; + push @{$section->{'transactions'}}, $stuff; + } + + # Handle the general info + @{$section}{ 'trx_id_counter' } + = $fulltext =~ m/^Trx id counter $t$/m; + @{$section}{ 'purge_done_for', 'purge_undo_for' } + = $fulltext =~ m/^Purge done for trx's n:o < $t undo n:o < $t$/m; + @{$section}{ 'history_list_len' } # This isn't present in some 4.x versions + = $fulltext =~ m/^History list length $d$/m; + @{$section}{ 'num_lock_structs' } + = $fulltext =~ m/^Total number of lock structs in row lock hash table $d$/m; + @{$section}{ 'is_truncated' } + = $fulltext =~ m/^\.\.\. truncated\.\.\.$/m ? 1 : 0; + + # Fill in things that might not be present + foreach ( qw(history_list_len) ) { + $section->{$_} ||= 0; + } + + delete $section->{'fulltext'} unless $debug; + return 1; +} + +# I've read the source for this section. +sub parse_ro_section { + my ( $section, $complete, $debug, $full ) = @_; + return unless $section && $section->{'fulltext'}; + my $fulltext = $section->{'fulltext'}; + + # Grab the info + @{$section}{ 'queries_inside', 'queries_in_queue' } + = $fulltext =~ m/^$d queries inside InnoDB, $d queries in queue$/m; + ( $section->{ 'read_views_open' } ) + = $fulltext =~ m/^$d read views open inside InnoDB$/m; + ( $section->{ 'n_reserved_extents' } ) + = $fulltext =~ m/^$d tablespace extents now reserved for B-tree/m; + @{$section}{ 'main_thread_proc_no', 'main_thread_id', 'main_thread_state' } + = $fulltext =~ m/^Main thread (?:process no. $d, )?id $d, state: (.*)$/m; + @{$section}{ 'num_rows_ins', 'num_rows_upd', 'num_rows_del', 'num_rows_read' } + = $fulltext =~ m/^Number of rows inserted $d, updated $d, deleted $d, read $d$/m; + @{$section}{ 'ins_sec', 'upd_sec', 'del_sec', 'read_sec' } + = $fulltext =~ m#^$f inserts/s, $f updates/s, $f deletes/s, $f reads/s$#m; + $section->{'main_thread_proc_no'} ||= 0; + + map { $section->{$_} ||= 0 } qw(read_views_open n_reserved_extents); + delete $section->{'fulltext'} unless $debug; + return 1; +} + +sub parse_lg_section { + my ( $section, $complete, $debug, $full ) = @_; + return unless $section; + my $fulltext = $section->{'fulltext'}; + + # Grab the info + ( $section->{ 'log_seq_no' } ) + = $fulltext =~ m/Log sequence number \s*(\d.*)$/m; + ( $section->{ 'log_flushed_to' } ) + = $fulltext =~ m/Log flushed up to \s*(\d.*)$/m; + ( $section->{ 'last_chkp' } ) + = $fulltext =~ m/Last checkpoint at \s*(\d.*)$/m; + @{$section}{ 'pending_log_writes', 'pending_chkp_writes' } + = $fulltext =~ m/$d pending log writes, $d pending chkp writes/; + @{$section}{ 'log_ios_done', 'log_ios_s' } + = $fulltext =~ m#$d log i/o's done, $f log i/o's/second#; + + delete $section->{'fulltext'} unless $debug; + return 1; +} + +sub parse_ib_section { + my ( $section, $complete, $debug, $full ) = @_; + return unless $section && $section->{'fulltext'}; + my $fulltext = $section->{'fulltext'}; + + # Some servers will output ibuf information for tablespace 0, as though there + # might be many tablespaces with insert buffers. (In practice I believe + # the source code shows there will only ever be one). I have to parse both + # cases here, but I assume there will only be one. + @{$section}{ 'size', 'free_list_len', 'seg_size' } + = $fulltext =~ m/^Ibuf(?: for space 0)?: size $d, free list len $d, seg size $d,$/m; + @{$section}{ 'inserts', 'merged_recs', 'merges' } + = $fulltext =~ m/^$d inserts, $d merged recs, $d merges$/m; + + @{$section}{ 'hash_table_size', 'used_cells', 'bufs_in_node_heap' } + = $fulltext =~ m/^Hash table size $d, used cells $d, node heap has $d buffer\(s\)$/m; + @{$section}{ 'hash_searches_s', 'non_hash_searches_s' } + = $fulltext =~ m{^$f hash searches/s, $f non-hash searches/s$}m; + + delete $section->{'fulltext'} unless $debug; + return 1; +} + +sub parse_wait_array { + my ( $text, $complete, $debug, $full ) = @_; + my %result; + + @result{ qw(thread waited_at_filename waited_at_line waited_secs) } + = $text =~ m/^--Thread $d has waited at $fl for $f seconds/m; + + # Depending on whether it's a SYNC_MUTEX,RW_LOCK_EX,RW_LOCK_SHARED, + # there will be different text output + if ( $text =~ m/^Mutex at/m ) { + $result{'request_type'} = 'M'; + @result{ qw( lock_mem_addr lock_cfile_name lock_cline lock_var) } + = $text =~ m/^Mutex at $h created file $fl, lock var $d$/m; + @result{ qw( waiters_flag )} + = $text =~ m/^waiters flag $d$/m; + } + else { + @result{ qw( request_type lock_mem_addr lock_cfile_name lock_cline) } + = $text =~ m/^(.)-lock on RW-latch at $h created in file $fl$/m; + @result{ qw( writer_thread writer_lock_mode ) } + = $text =~ m/^a writer \(thread id $d\) has reserved it in mode (.*)$/m; + @result{ qw( num_readers waiters_flag )} + = $text =~ m/^number of readers $d, waiters flag $d$/m; + @result{ qw(last_s_file_name last_s_line ) } + = $text =~ m/Last time read locked in file $fl$/m; + @result{ qw(last_x_file_name last_x_line ) } + = $text =~ m/Last time write locked in file $fl$/m; + } + + $result{'cell_waiting'} = $text =~ m/^wait has ended$/m ? 0 : 1; + $result{'cell_event_set'} = $text =~ m/^wait is ending$/m ? 1 : 0; + + # Because there are two code paths, some things won't get set. + map { $result{$_} ||= '' } + qw(last_s_file_name last_x_file_name writer_lock_mode); + map { $result{$_} ||= 0 } + qw(num_readers lock_var last_s_line last_x_line writer_thread); + + return \%result; +} + +sub parse_sm_section { + my ( $section, $complete, $debug, $full ) = @_; + return 0 unless $section && $section->{'fulltext'}; + my $fulltext = $section->{'fulltext'}; + + # Grab the info + @{$section}{ 'reservation_count', 'signal_count' } + = $fulltext =~ m/^OS WAIT ARRAY INFO: reservation count $d, signal count $d$/m; + @{$section}{ 'mutex_spin_waits', 'mutex_spin_rounds', 'mutex_os_waits' } + = $fulltext =~ m/^Mutex spin waits $d, rounds $d, OS waits $d$/m; + @{$section}{ 'rw_shared_spins', 'rw_shared_os_waits', 'rw_excl_spins', 'rw_excl_os_waits' } + = $fulltext =~ m/^RW-shared spins $d, OS waits $d; RW-excl spins $d, OS waits $d$/m; + + # Look for info on waits. + my @waits = $fulltext =~ m/^(--Thread.*?)^(?=Mutex spin|--Thread)/gms; + $section->{'waits'} = [ map { parse_wait_array($_, $complete, $debug) } @waits ]; + $section->{'wait_array_size'} = scalar(@waits); + + delete $section->{'fulltext'} unless $debug; + return 1; +} + +# I've read the source for this section. +sub parse_bp_section { + my ( $section, $complete, $debug, $full ) = @_; + return unless $section && $section->{'fulltext'}; + my $fulltext = $section->{'fulltext'}; + + # Grab the info + @{$section}{ 'total_mem_alloc', 'add_pool_alloc' } + = $fulltext =~ m/^Total memory allocated $d; in additional pool allocated $d$/m; + @{$section}{'dict_mem_alloc'} = $fulltext =~ m/Dictionary memory allocated $d/; + @{$section}{'awe_mem_alloc'} = $fulltext =~ m/$d MB of AWE memory/; + @{$section}{'buf_pool_size'} = $fulltext =~ m/^Buffer pool size\s*$d$/m; + @{$section}{'buf_free'} = $fulltext =~ m/^Free buffers\s*$d$/m; + @{$section}{'pages_total'} = $fulltext =~ m/^Database pages\s*$d$/m; + @{$section}{'pages_modified'} = $fulltext =~ m/^Modified db pages\s*$d$/m; + @{$section}{'pages_read', 'pages_created', 'pages_written'} + = $fulltext =~ m/^Pages read $d, created $d, written $d$/m; + @{$section}{'page_reads_sec', 'page_creates_sec', 'page_writes_sec'} + = $fulltext =~ m{^$f reads/s, $f creates/s, $f writes/s$}m; + @{$section}{'buf_pool_hits', 'buf_pool_reads'} + = $fulltext =~ m{Buffer pool hit rate $d / $d$}m; + if ($fulltext =~ m/^No buffer pool page gets since the last printout$/m) { + @{$section}{'buf_pool_hits', 'buf_pool_reads'} = (0, 0); + @{$section}{'buf_pool_hit_rate'} = '--'; + } + else { + @{$section}{'buf_pool_hit_rate'} + = $fulltext =~ m{Buffer pool hit rate (\d+ / \d+)$}m; + } + @{$section}{'reads_pending'} = $fulltext =~ m/^Pending reads $d/m; + @{$section}{'writes_pending_lru', 'writes_pending_flush_list', 'writes_pending_single_page' } + = $fulltext =~ m/^Pending writes: LRU $d, flush list $d, single page $d$/m; + + map { $section->{$_} ||= 0 } + qw(writes_pending_lru writes_pending_flush_list writes_pending_single_page + awe_mem_alloc dict_mem_alloc); + @{$section}{'writes_pending'} = List::Util::sum( + @{$section}{ qw(writes_pending_lru writes_pending_flush_list writes_pending_single_page) }); + + delete $section->{'fulltext'} unless $debug; + return 1; +} + +# I've read the source for this. +sub parse_io_section { + my ( $section, $complete, $debug, $full ) = @_; + return unless $section && $section->{'fulltext'}; + my $fulltext = $section->{'fulltext'}; + $section->{'threads'} = {}; + + # Grab the I/O thread info + my @threads = $fulltext =~ m<^(I/O thread \d+ .*)$>gm; + foreach my $thread (@threads) { + my ( $tid, $state, $purpose, $event_set ) + = $thread =~ m{I/O thread $d state: (.+?) \((.*)\)(?: ev set)?$}m; + if ( defined $tid ) { + $section->{'threads'}->{$tid} = { + thread => $tid, + state => $state, + purpose => $purpose, + event_set => $event_set ? 1 : 0, + }; + } + } + + # Grab the reads/writes/flushes info + @{$section}{ 'pending_normal_aio_reads', 'pending_aio_writes' } + = $fulltext =~ m/^Pending normal aio reads: $d, aio writes: $d,$/m; + @{$section}{ 'pending_ibuf_aio_reads', 'pending_log_ios', 'pending_sync_ios' } + = $fulltext =~ m{^ ibuf aio reads: $d, log i/o's: $d, sync i/o's: $d$}m; + @{$section}{ 'flush_type', 'pending_log_flushes', 'pending_buffer_pool_flushes' } + = $fulltext =~ m/^Pending flushes \($w\) log: $d; buffer pool: $d$/m; + @{$section}{ 'os_file_reads', 'os_file_writes', 'os_fsyncs' } + = $fulltext =~ m/^$d OS file reads, $d OS file writes, $d OS fsyncs$/m; + @{$section}{ 'reads_s', 'avg_bytes_s', 'writes_s', 'fsyncs_s' } + = $fulltext =~ m{^$f reads/s, $d avg bytes/read, $f writes/s, $f fsyncs/s$}m; + @{$section}{ 'pending_preads', 'pending_pwrites' } + = $fulltext =~ m/$d pending preads, $d pending pwrites$/m; + @{$section}{ 'pending_preads', 'pending_pwrites' } = (0, 0) + unless defined($section->{'pending_preads'}); + + delete $section->{'fulltext'} unless $debug; + return 1; +} + +sub _debug { + my ( $debug, $msg ) = @_; + if ( $debug ) { + die $msg; + } + else { + warn $msg; + } + return 1; +} + +1; + +# end_of_package InnoDBParser + +package main; + +use sigtrap qw(handler finish untrapped normal-signals); + +use Data::Dumper; +use DBI; +use English qw(-no_match_vars); +use File::Basename qw(dirname); +use File::Temp; +use Getopt::Long; +use List::Util qw(max min maxstr sum); +use POSIX qw(ceil); +use Time::HiRes qw(time sleep); +use Term::ReadKey qw(ReadMode ReadKey); + +# License and warranty information. {{{1 +# ########################################################################### + +my $innotop_license = <<"LICENSE"; + +This is innotop version $VERSION, a MySQL and InnoDB monitor. + +This program is copyright (c) 2006 Baron Schwartz. +Feedback and improvements are welcome. + +THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + +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 +Foundation, version 2; OR the Perl Artistic License. On UNIX and similar +systems, you can issue `man perlgpl' or `man perlartistic' to read these +licenses. + +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. +LICENSE + +# Configuration information and global setup {{{1 +# ########################################################################### + +# Really, really, super-global variables. +my @config_versions = ( + "000-000-000", "001-003-000", # config file was one big name-value hash. + "001-003-000", "001-004-002", # config file contained non-user-defined stuff. +); + +my $clear_screen_sub; +my $dsn_parser = new DSNParser(); + +# This defines expected properties and defaults for the column definitions that +# eventually end up in tbl_meta. +my %col_props = ( + hdr => '', + just => '-', + dec => 0, # Whether to align the column on the decimal point + num => 0, + label => '', + user => 0, + src => '', + tbl => '', # Helps when writing/reading custom columns in config files + minw => 0, + maxw => 0, + trans => [], + agg => 'first', # Aggregate function + aggonly => 0, # Whether to show only when tbl_meta->{aggregate} is true +); + +# Actual DBI connections to MySQL servers. +my %dbhs; + +# Command-line parameters {{{2 +# ########################################################################### + +my @opt_spec = ( + { s => 'help', d => 'Show this help message' }, + { s => 'color|C!', d => 'Use terminal coloring (default)', c => 'color' }, + { s => 'config|c=s', d => 'Config file to read' }, + { s => 'nonint|n', d => 'Non-interactive, output tab-separated fields' }, + { s => 'count=i', d => 'Number of updates before exiting' }, + { s => 'delay|d=f', d => 'Delay between updates in seconds', c => 'interval' }, + { s => 'mode|m=s', d => 'Operating mode to start in', c => 'mode' }, + { s => 'inc|i!', d => 'Measure incremental differences', c => 'status_inc' }, + { s => 'write|w', d => 'Write running configuration into home directory if no config files were loaded' }, + { s => 'skipcentral|s', d => 'Skip reading the central configuration file' }, + { s => 'version', d => 'Output version information and exit' }, + { s => 'user|u=s', d => 'User for login if not current user' }, + { s => 'password|p=s', d => 'Password to use for connection' }, + { s => 'host|h=s', d => 'Connect to host' }, + { s => 'port|P=i', d => 'Port number to use for connection' }, +); + +# This is the container for the command-line options' values to be stored in +# after processing. Initial values are defaults. +my %opts = ( + n => !( -t STDIN && -t STDOUT ), # If in/out aren't to terminals, we're interactive +); +# Post-process... +my %opt_seen; +foreach my $spec ( @opt_spec ) { + my ( $long, $short ) = $spec->{s} =~ m/^(\w+)(?:\|([^!+=]*))?/; + $spec->{k} = $short || $long; + $spec->{l} = $long; + $spec->{t} = $short; + $spec->{n} = $spec->{s} =~ m/!/; + $opts{$spec->{k}} = undef unless defined $opts{$spec->{k}}; + die "Duplicate option $spec->{k}" if $opt_seen{$spec->{k}}++; +} + +Getopt::Long::Configure('no_ignore_case', 'bundling'); +GetOptions( map { $_->{s} => \$opts{$_->{k}} } @opt_spec) or $opts{help} = 1; + +if ( $opts{version} ) { + print "innotop Ver $VERSION\n"; + exit(0); +} + +if ( $opts{c} and ! -f $opts{c} ) { + print $opts{c} . " doesn't exist. Exiting.\n"; + exit(1); +} +if ( $opts{'help'} ) { + print "Usage: innotop \n\n"; + my $maxw = max(map { length($_->{l}) + ($_->{n} ? 4 : 0)} @opt_spec); + foreach my $spec ( sort { $a->{l} cmp $b->{l} } @opt_spec ) { + my $long = $spec->{n} ? "[no]$spec->{l}" : $spec->{l}; + my $short = $spec->{t} ? "-$spec->{t}" : ''; + printf(" --%-${maxw}s %-4s %s\n", $long, $short, $spec->{d}); + } + print < q{my $host = host || hostname || ''; ($host) = $host =~ m/^((?:[\d.]+(?=:))|(?:[a-zA-Z]\w+))/; return $host || ''}, + Port => q{my ($p) = host =~ m/:(.*)$/; return $p || 0}, + OldVersions => q{dulint_to_int(IB_tx_trx_id_counter) - dulint_to_int(IB_tx_purge_done_for)}, + MaxTxnTime => q/max(map{ $_->{active_secs} } @{ IB_tx_transactions }) || 0/, + NumTxns => q{scalar @{ IB_tx_transactions } }, + DirtyBufs => q{ $cur->{IB_bp_pages_modified} / ($cur->{IB_bp_buf_pool_size} || 1) }, + BufPoolFill => q{ $cur->{IB_bp_pages_total} / ($cur->{IB_bp_buf_pool_size} || 1) }, + ServerLoad => q{ $cur->{Threads_connected}/(Questions||1)/Uptime_hires }, + TxnTimeRemain => q{ defined undo_log_entries && defined $pre->{undo_log_entries} && undo_log_entries < $pre->{undo_log_entries} ? undo_log_entries / (($pre->{undo_log_entries} - undo_log_entries)/((active_secs-$pre->{active_secs})||1))||1 : 0}, + SlaveCatchupRate => ' defined $cur->{seconds_behind_master} && defined $pre->{seconds_behind_master} && $cur->{seconds_behind_master} < $pre->{seconds_behind_master} ? ($pre->{seconds_behind_master}-$cur->{seconds_behind_master})/($cur->{Uptime_hires}-$pre->{Uptime_hires}) : 0', + QcacheHitRatio => q{(Qcache_hits||0)/(((Com_select||0)+(Qcache_hits||0))||1)}, +); + +# ########################################################################### +# Column definitions {{{3 +# Defines every column in every table. A named column has the following +# properties: +# * hdr Column header/title +# * label Documentation for humans. +# * num Whether it's numeric (for sorting). +# * just Alignment; generated from num, user-overridable in tbl_meta +# * minw, maxw Auto-generated, user-overridable. +# Values from this hash are just copied to tbl_meta, which is where everything +# else in the program should read from. +# ########################################################################### + +my %columns = ( + active_secs => { hdr => 'SecsActive', num => 1, label => 'Seconds transaction has been active', }, + add_pool_alloc => { hdr => 'Add\'l Pool', num => 1, label => 'Additonal pool allocated' }, + attempted_op => { hdr => 'Action', num => 0, label => 'The action that caused the error' }, + awe_mem_alloc => { hdr => 'AWE Memory', num => 1, label => '[Windows] AWE memory allocated' }, + binlog_cache_overflow => { hdr => 'Binlog Cache', num => 1, label => 'Transactions too big for binlog cache that went to disk' }, + binlog_do_db => { hdr => 'Binlog Do DB', num => 0, label => 'binlog-do-db setting' }, + binlog_ignore_db => { hdr => 'Binlog Ignore DB', num => 0, label => 'binlog-ignore-db setting' }, + bps_in => { hdr => 'BpsIn', num => 1, label => 'Bytes per second received by the server', }, + bps_out => { hdr => 'BpsOut', num => 1, label => 'Bytes per second sent by the server', }, + buf_free => { hdr => 'Free Bufs', num => 1, label => 'Buffers free in the buffer pool' }, + buf_pool_hit_rate => { hdr => 'Hit Rate', num => 0, label => 'Buffer pool hit rate' }, + buf_pool_hits => { hdr => 'Hits', num => 1, label => 'Buffer pool hits' }, + buf_pool_reads => { hdr => 'Reads', num => 1, label => 'Buffer pool reads' }, + buf_pool_size => { hdr => 'Size', num => 1, label => 'Buffer pool size' }, + bufs_in_node_heap => { hdr => 'Node Heap Bufs', num => 1, label => 'Buffers in buffer pool node heap' }, + bytes_behind_master => { hdr => 'ByteLag', num => 1, label => 'Bytes the slave lags the master in binlog' }, + cell_event_set => { hdr => 'Ending?', num => 1, label => 'Whether the cell event is set' }, + cell_waiting => { hdr => 'Waiting?', num => 1, label => 'Whether the cell is waiting' }, + child_db => { hdr => 'Child DB', num => 0, label => 'The database of the child table' }, + child_index => { hdr => 'Child Index', num => 0, label => 'The index in the child table' }, + child_table => { hdr => 'Child Table', num => 0, label => 'The child table' }, + cmd => { hdr => 'Cmd', num => 0, label => 'Type of command being executed', }, + cnt => { hdr => 'Cnt', num => 0, label => 'Count', agg => 'count', aggonly => 1 }, + connect_retry => { hdr => 'Connect Retry', num => 1, label => 'Slave connect-retry timeout' }, + cxn => { hdr => 'CXN', num => 0, label => 'Connection from which the data came', }, + db => { hdr => 'DB', num => 0, label => 'Current database', }, + dict_mem_alloc => { hdr => 'Dict Mem', num => 1, label => 'Dictionary memory allocated' }, + dirty_bufs => { hdr => 'Dirty Buf', num => 1, label => 'Dirty buffer pool pages' }, + dl_txn_num => { hdr => 'Num', num => 0, label => 'Deadlocked transaction number', }, + event_set => { hdr => 'Evt Set?', num => 1, label => '[Win32] if a wait event is set', }, + exec_master_log_pos => { hdr => 'Exec Master Log Pos', num => 1, label => 'Exec Master Log Position' }, + fk_name => { hdr => 'Constraint', num => 0, label => 'The name of the FK constraint' }, + free_list_len => { hdr => 'Free List Len', num => 1, label => 'Length of the free list' }, + has_read_view => { hdr => 'Rd View', num => 1, label => 'Whether the transaction has a read view' }, + hash_searches_s => { hdr => 'Hash/Sec', num => 1, label => 'Number of hash searches/sec' }, + hash_table_size => { hdr => 'Size', num => 1, label => 'Number of non-hash searches/sec' }, + heap_no => { hdr => 'Heap', num => 1, label => 'Heap number' }, + heap_size => { hdr => 'Heap', num => 1, label => 'Heap size' }, + history_list_len => { hdr => 'History', num => 1, label => 'History list length' }, + host_and_domain => { hdr => 'Host', num => 0, label => 'Hostname/IP and domain' }, + host_and_port => { hdr => 'Host/IP', num => 0, label => 'Hostname or IP address, and port number', }, + hostname => { hdr => 'Host', num => 0, label => 'Hostname' }, + index => { hdr => 'Index', num => 0, label => 'The index involved' }, + index_ref => { hdr => 'Index Ref', num => 0, label => 'Index referenced' }, + info => { hdr => 'Query', num => 0, label => 'Info or the current query', }, + insert_intention => { hdr => 'Ins Intent', num => 1, label => 'Whether the thread was trying to insert' }, + inserts => { hdr => 'Inserts', num => 1, label => 'Inserts' }, + io_bytes_s => { hdr => 'Bytes/Sec', num => 1, label => 'Average I/O bytes/sec' }, + io_flush_type => { hdr => 'Flush Type', num => 0, label => 'I/O Flush Type' }, + io_fsyncs_s => { hdr => 'fsyncs/sec', num => 1, label => 'I/O fsyncs/sec' }, + io_reads_s => { hdr => 'Reads/Sec', num => 1, label => 'Average I/O reads/sec' }, + io_writes_s => { hdr => 'Writes/Sec', num => 1, label => 'Average I/O writes/sec' }, + ip => { hdr => 'IP', num => 0, label => 'IP address' }, + is_name_locked => { hdr => 'Locked', num => 1, label => 'Whether table is name locked', }, + key_buffer_hit => { hdr => 'KCacheHit', num => 1, label => 'Key cache hit ratio', }, + key_len => { hdr => 'Key Length', num => 1, label => 'Number of bytes used in the key' }, + last_chkp => { hdr => 'Last Checkpoint', num => 0, label => 'Last log checkpoint' }, + last_errno => { hdr => 'Last Errno', num => 1, label => 'Last error number' }, + last_error => { hdr => 'Last Error', num => 0, label => 'Last error' }, + last_s_file_name => { hdr => 'S-File', num => 0, label => 'Filename where last read locked' }, + last_s_line => { hdr => 'S-Line', num => 1, label => 'Line where last read locked' }, + last_x_file_name => { hdr => 'X-File', num => 0, label => 'Filename where last write locked' }, + last_x_line => { hdr => 'X-Line', num => 1, label => 'Line where last write locked' }, + last_pct => { hdr => 'Pct', num => 1, label => 'Last Percentage' }, + last_total => { hdr => 'Last Total', num => 1, label => 'Last Total' }, + last_value => { hdr => 'Last Incr', num => 1, label => 'Last Value' }, + load => { hdr => 'Load', num => 1, label => 'Server load' }, + lock_cfile_name => { hdr => 'Crtd File', num => 0, label => 'Filename where lock created' }, + lock_cline => { hdr => 'Crtd Line', num => 1, label => 'Line where lock created' }, + lock_mem_addr => { hdr => 'Addr', num => 0, label => 'The lock memory address' }, + lock_mode => { hdr => 'Mode', num => 0, label => 'The lock mode' }, + lock_structs => { hdr => 'LStrcts', num => 1, label => 'Number of lock structs' }, + lock_type => { hdr => 'Type', num => 0, label => 'The lock type' }, + lock_var => { hdr => 'Lck Var', num => 1, label => 'The lock variable' }, + lock_wait_time => { hdr => 'Wait', num => 1, label => 'How long txn has waited for a lock' }, + log_flushed_to => { hdr => 'Flushed To', num => 0, label => 'Log position flushed to' }, + log_ios_done => { hdr => 'IO Done', num => 1, label => 'Log I/Os done' }, + log_ios_s => { hdr => 'IO/Sec', num => 1, label => 'Average log I/Os per sec' }, + log_seq_no => { hdr => 'Sequence No.', num => 0, label => 'Log sequence number' }, + main_thread_id => { hdr => 'Main Thread ID', num => 1, label => 'Main thread ID' }, + main_thread_proc_no => { hdr => 'Main Thread Proc', num => 1, label => 'Main thread process number' }, + main_thread_state => { hdr => 'Main Thread State', num => 0, label => 'Main thread state' }, + master_file => { hdr => 'File', num => 0, label => 'Master file' }, + master_host => { hdr => 'Master', num => 0, label => 'Master server hostname' }, + master_log_file => { hdr => 'Master Log File', num => 0, label => 'Master log file' }, + master_port => { hdr => 'Master Port', num => 1, label => 'Master port' }, + master_pos => { hdr => 'Position', num => 1, label => 'Master position' }, + master_ssl_allowed => { hdr => 'Master SSL Allowed', num => 0, label => 'Master SSL Allowed' }, + master_ssl_ca_file => { hdr => 'Master SSL CA File', num => 0, label => 'Master SSL Cert Auth File' }, + master_ssl_ca_path => { hdr => 'Master SSL CA Path', num => 0, label => 'Master SSL Cert Auth Path' }, + master_ssl_cert => { hdr => 'Master SSL Cert', num => 0, label => 'Master SSL Cert' }, + master_ssl_cipher => { hdr => 'Master SSL Cipher', num => 0, label => 'Master SSL Cipher' }, + master_ssl_key => { hdr => 'Master SSL Key', num => 0, label => 'Master SSL Key' }, + master_user => { hdr => 'Master User', num => 0, label => 'Master username' }, + max_txn => { hdr => 'MaxTxnTime', num => 1, label => 'MaxTxn' }, + merged_recs => { hdr => 'Merged Recs', num => 1, label => 'Merged records' }, + merges => { hdr => 'Merges', num => 1, label => 'Merges' }, + mutex_os_waits => { hdr => 'Waits', num => 1, label => 'Mutex OS Waits' }, + mutex_spin_rounds => { hdr => 'Rounds', num => 1, label => 'Mutex Spin Rounds' }, + mutex_spin_waits => { hdr => 'Spins', num => 1, label => 'Mutex Spin Waits' }, + mysql_thread_id => { hdr => 'ID', num => 1, label => 'MySQL connection (thread) ID', }, + name => { hdr => 'Name', num => 0, label => 'Variable Name' }, + n_bits => { hdr => '# Bits', num => 1, label => 'Number of bits' }, + non_hash_searches_s => { hdr => 'Non-Hash/Sec', num => 1, label => 'Non-hash searches/sec' }, + num_deletes => { hdr => 'Del', num => 1, label => 'Number of deletes' }, + num_deletes_sec => { hdr => 'Del/Sec', num => 1, label => 'Number of deletes' }, + num_inserts => { hdr => 'Ins', num => 1, label => 'Number of inserts' }, + num_inserts_sec => { hdr => 'Ins/Sec', num => 1, label => 'Number of inserts' }, + num_readers => { hdr => 'Readers', num => 1, label => 'Number of readers' }, + num_reads => { hdr => 'Read', num => 1, label => 'Number of reads' }, + num_reads_sec => { hdr => 'Read/Sec', num => 1, label => 'Number of reads' }, + num_res_ext => { hdr => 'BTree Extents', num => 1, label => 'Number of extents reserved for B-Tree' }, + num_rows => { hdr => 'Row Count', num => 1, label => 'Number of rows estimated to examine' }, + num_times_open => { hdr => 'In Use', num => 1, label => '# times table is opened', }, + num_txns => { hdr => 'Txns', num => 1, label => 'Number of transactions' }, + num_updates => { hdr => 'Upd', num => 1, label => 'Number of updates' }, + num_updates_sec => { hdr => 'Upd/Sec', num => 1, label => 'Number of updates' }, + os_file_reads => { hdr => 'OS Reads', num => 1, label => 'OS file reads' }, + os_file_writes => { hdr => 'OS Writes', num => 1, label => 'OS file writes' }, + os_fsyncs => { hdr => 'OS fsyncs', num => 1, label => 'OS fsyncs' }, + os_thread_id => { hdr => 'OS Thread', num => 1, label => 'The operating system thread ID' }, + p_aio_writes => { hdr => 'Async Wrt', num => 1, label => 'Pending asynchronous I/O writes' }, + p_buf_pool_flushes => { hdr => 'Buffer Pool Flushes', num => 1, label => 'Pending buffer pool flushes' }, + p_ibuf_aio_reads => { hdr => 'IBuf Async Rds', num => 1, label => 'Pending insert buffer asynch I/O reads' }, + p_log_flushes => { hdr => 'Log Flushes', num => 1, label => 'Pending log flushes' }, + p_log_ios => { hdr => 'Log I/Os', num => 1, label => 'Pending log I/O operations' }, + p_normal_aio_reads => { hdr => 'Async Rds', num => 1, label => 'Pending asynchronous I/O reads' }, + p_preads => { hdr => 'preads', num => 1, label => 'Pending p-reads' }, + p_pwrites => { hdr => 'pwrites', num => 1, label => 'Pending p-writes' }, + p_sync_ios => { hdr => 'Sync I/Os', num => 1, label => 'Pending synchronous I/O operations' }, + page_creates_sec => { hdr => 'Creates/Sec', num => 1, label => 'Page creates/sec' }, + page_no => { hdr => 'Page', num => 1, label => 'Page number' }, + page_reads_sec => { hdr => 'Reads/Sec', num => 1, label => 'Page reads per second' }, + page_writes_sec => { hdr => 'Writes/Sec', num => 1, label => 'Page writes per second' }, + pages_created => { hdr => 'Created', num => 1, label => 'Pages created' }, + pages_modified => { hdr => 'Dirty Pages', num => 1, label => 'Pages modified (dirty)' }, + pages_read => { hdr => 'Reads', num => 1, label => 'Pages read' }, + pages_total => { hdr => 'Pages', num => 1, label => 'Pages total' }, + pages_written => { hdr => 'Writes', num => 1, label => 'Pages written' }, + parent_col => { hdr => 'Parent Column', num => 0, label => 'The referred column in the parent table', }, + parent_db => { hdr => 'Parent DB', num => 0, label => 'The database of the parent table' }, + parent_index => { hdr => 'Parent Index', num => 0, label => 'The referred index in the parent table' }, + parent_table => { hdr => 'Parent Table', num => 0, label => 'The parent table' }, + part_id => { hdr => 'Part ID', num => 1, label => 'Sub-part ID of the query' }, + partitions => { hdr => 'Partitions', num => 0, label => 'Query partitions used' }, + pct => { hdr => 'Pct', num => 1, label => 'Percentage' }, + pending_chkp_writes => { hdr => 'Chkpt Writes', num => 1, label => 'Pending log checkpoint writes' }, + pending_log_writes => { hdr => 'Log Writes', num => 1, label => 'Pending log writes' }, + port => { hdr => 'Port', num => 1, label => 'Client port number', }, + possible_keys => { hdr => 'Poss. Keys', num => 0, label => 'Possible keys' }, + proc_no => { hdr => 'Proc', num => 1, label => 'Process number' }, + q_cache_hit => { hdr => 'QCacheHit', num => 1, label => 'Query cache hit ratio', }, + qps => { hdr => 'QPS', num => 1, label => 'How many queries/sec', }, + queries_in_queue => { hdr => 'Queries Queued', num => 1, label => 'Queries in queue' }, + queries_inside => { hdr => 'Queries Inside', num => 1, label => 'Queries inside InnoDB' }, + query_id => { hdr => 'Query ID', num => 1, label => 'Query ID' }, + query_status => { hdr => 'Query Status', num => 0, label => 'The query status' }, + query_text => { hdr => 'Query Text', num => 0, label => 'The query text' }, + questions => { hdr => 'Questions', num => 1, label => 'How many queries the server has gotten', }, + read_master_log_pos => { hdr => 'Read Master Pos', num => 1, label => 'Read master log position' }, + read_views_open => { hdr => 'Rd Views', num => 1, label => 'Number of read views open' }, + reads_pending => { hdr => 'Pending Reads', num => 1, label => 'Reads pending' }, + relay_log_file => { hdr => 'Relay File', num => 0, label => 'Relay log file' }, + relay_log_pos => { hdr => 'Relay Pos', num => 1, label => 'Relay log position' }, + relay_log_size => { hdr => 'Relay Size', num => 1, label => 'Relay log size' }, + relay_master_log_file => { hdr => 'Relay Master File', num => 0, label => 'Relay master log file' }, + replicate_do_db => { hdr => 'Do DB', num => 0, label => 'Replicate-do-db setting' }, + replicate_do_table => { hdr => 'Do Table', num => 0, label => 'Replicate-do-table setting' }, + replicate_ignore_db => { hdr => 'Ignore DB', num => 0, label => 'Replicate-ignore-db setting' }, + replicate_ignore_table => { hdr => 'Ignore Table', num => 0, label => 'Replicate-do-table setting' }, + replicate_wild_do_table => { hdr => 'Wild Do Table', num => 0, label => 'Replicate-wild-do-table setting' }, + replicate_wild_ignore_table => { hdr => 'Wild Ignore Table', num => 0, label => 'Replicate-wild-ignore-table setting' }, + request_type => { hdr => 'Type', num => 0, label => 'Type of lock the thread waits for' }, + reservation_count => { hdr => 'ResCnt', num => 1, label => 'Reservation Count' }, + row_locks => { hdr => 'RLocks', num => 1, label => 'Number of row locks' }, + rw_excl_os_waits => { hdr => 'RW Waits', num => 1, label => 'R/W Excl. OS Waits' }, + rw_excl_spins => { hdr => 'RW Spins', num => 1, label => 'R/W Excl. Spins' }, + rw_shared_os_waits => { hdr => 'Sh Waits', num => 1, label => 'R/W Shared OS Waits' }, + rw_shared_spins => { hdr => 'Sh Spins', num => 1, label => 'R/W Shared Spins' }, + scan_type => { hdr => 'Type', num => 0, label => 'Scan type in chosen' }, + seg_size => { hdr => 'Seg. Size', num => 1, label => 'Segment size' }, + select_type => { hdr => 'Select Type', num => 0, label => 'Type of select used' }, + signal_count => { hdr => 'Signals', num => 1, label => 'Signal Count' }, + size => { hdr => 'Size', num => 1, label => 'Size of the tablespace' }, + skip_counter => { hdr => 'Skip Counter', num => 1, label => 'Skip counter' }, + slave_catchup_rate => { hdr => 'Catchup', num => 1, label => 'How fast the slave is catching up in the binlog' }, + slave_io_running => { hdr => 'Slave-IO', num => 0, label => 'Whether the slave I/O thread is running' }, + slave_io_state => { hdr => 'Slave IO State', num => 0, label => 'Slave I/O thread state' }, + slave_open_temp_tables => { hdr => 'Temp', num => 1, label => 'Slave open temp tables' }, + slave_sql_running => { hdr => 'Slave-SQL', num => 0, label => 'Whether the slave SQL thread is running' }, + slow => { hdr => 'Slow', num => 1, label => 'How many slow queries', }, + space_id => { hdr => 'Space', num => 1, label => 'Tablespace ID' }, + special => { hdr => 'Special', num => 0, label => 'Special/Other info' }, + state => { hdr => 'State', num => 0, label => 'Connection state', maxw => 18, }, + tables_in_use => { hdr => 'Tbl Used', num => 1, label => 'Number of tables in use' }, + tables_locked => { hdr => 'Tbl Lck', num => 1, label => 'Number of tables locked' }, + tbl => { hdr => 'Table', num => 0, label => 'Table', }, + thread => { hdr => 'Thread', num => 1, label => 'Thread number' }, + thread_decl_inside => { hdr => 'Thread Inside', num => 0, label => 'What the thread is declared inside' }, + thread_purpose => { hdr => 'Purpose', num => 0, label => "The thread's purpose" }, + thread_status => { hdr => 'Thread Status', num => 0, label => 'The thread status' }, + time => { hdr => 'Time', num => 1, label => 'Time since the last event', }, + time_behind_master => { hdr => 'TimeLag', num => 1, label => 'Time slave lags master' }, + timestring => { hdr => 'Timestring', num => 0, label => 'Time the event occurred' }, + total => { hdr => 'Total', num => 1, label => 'Total' }, + total_mem_alloc => { hdr => 'Memory', num => 1, label => 'Total memory allocated' }, + truncates => { hdr => 'Trunc', num => 0, label => 'Whether the deadlock is truncating InnoDB status' }, + txn_doesnt_see_ge => { hdr => "Txn Won't See", num => 0, label => 'Where txn read view is limited' }, + txn_id => { hdr => 'ID', num => 0, label => 'Transaction ID' }, + txn_sees_lt => { hdr => 'Txn Sees', num => 1, label => 'Where txn read view is limited' }, + txn_status => { hdr => 'Txn Status', num => 0, label => 'Transaction status' }, + txn_time_remain => { hdr => 'Remaining', num => 1, label => 'Time until txn rollback/commit completes' }, + undo_log_entries => { hdr => 'Undo', num => 1, label => 'Number of undo log entries' }, + undo_for => { hdr => 'Undo', num => 0, label => 'Undo for' }, + until_condition => { hdr => 'Until Condition', num => 0, label => 'Slave until condition' }, + until_log_file => { hdr => 'Until Log File', num => 0, label => 'Slave until log file' }, + until_log_pos => { hdr => 'Until Log Pos', num => 1, label => 'Slave until log position' }, + used_cells => { hdr => 'Cells Used', num => 1, label => 'Number of cells used' }, + used_bufs => { hdr => 'Used Bufs', num => 1, label => 'Number of buffer pool pages used' }, + user => { hdr => 'User', num => 0, label => 'Database username', }, + value => { hdr => 'Value', num => 1, label => 'Value' }, + versions => { hdr => 'Versions', num => 1, label => 'Number of InnoDB MVCC versions unpurged' }, + victim => { hdr => 'Victim', num => 0, label => 'Whether this txn was the deadlock victim' }, + wait_array_size => { hdr => 'Wait Array Size', num => 1, label => 'Wait Array Size' }, + wait_status => { hdr => 'Lock Status', num => 0, label => 'Status of txn locks' }, + waited_at_filename => { hdr => 'File', num => 0, label => 'Filename at which thread waits' }, + waited_at_line => { hdr => 'Line', num => 1, label => 'Line at which thread waits' }, + waiters_flag => { hdr => 'Waiters', num => 1, label => 'Waiters Flag' }, + waiting => { hdr => 'Waiting', num => 1, label => 'Whether lock is being waited for' }, + when => { hdr => 'When', num => 0, label => 'Time scale' }, + writer_lock_mode => { hdr => 'Wrtr Lck Mode', num => 0, label => 'Writer lock mode' }, + writer_thread => { hdr => 'Wrtr Thread', num => 1, label => 'Writer thread ID' }, + writes_pending => { hdr => 'Writes', num => 1, label => 'Number of writes pending' }, + writes_pending_flush_list => { hdr => 'Flush List Writes', num => 1, label => 'Number of flush list writes pending' }, + writes_pending_lru => { hdr => 'LRU Writes', num => 1, label => 'Number of LRU writes pending' }, + writes_pending_single_page => { hdr => '1-Page Writes', num => 1, label => 'Number of 1-page writes pending' }, +); + +# Apply a default property or three. By default, columns are not width-constrained, +# aligned left, and sorted alphabetically, not numerically. +foreach my $col ( values %columns ) { + map { $col->{$_} ||= 0 } qw(num minw maxw); + $col->{just} = $col->{num} ? '' : '-'; +} + +# Filters {{{3 +# This hash defines every filter that can be applied to a table. These +# become part of tbl_meta as well. Each filter is just an expression that +# returns true or false. +# Properties of each entry: +# * func: the subroutine +# * name: the name, repeated +# * user: whether it's a user-defined filter (saved in config) +# * text: text of the subroutine +# * note: explanation +my %filters = (); + +# These are pre-processed to live in %filters above, by compiling them. +my %builtin_filters = ( + hide_self => { + text => <<' END', + return ( !$set->{info} || $set->{info} ne 'SHOW FULL PROCESSLIST' ) + && ( !$set->{query_text} || $set->{query_text} !~ m/INNODB STATUS$/ ); + END + note => 'Removes the innotop processes from the list', + tbls => [qw(innodb_transactions processlist)], + }, + hide_inactive => { + text => <<' END', + return ( !defined($set->{txn_status}) || $set->{txn_status} ne 'not started' ) + && ( !defined($set->{cmd}) || $set->{cmd} !~ m/Sleep|Binlog Dump/ ) + && ( !defined($set->{info}) || $set->{info} =~ m/\S/ ); + END + note => 'Removes processes which are not doing anything', + tbls => [qw(innodb_transactions processlist)], + }, + hide_slave_io => { + text => <<' END', + return !$set->{state} || $set->{state} !~ m/^(?:Waiting for master|Has read all relay)/; + END + note => 'Removes slave I/O threads from the list', + tbls => [qw(processlist slave_io_status)], + }, + table_is_open => { + text => <<' END', + return $set->{num_times_open} + $set->{is_name_locked}; + END + note => 'Removes tables that are not in use or locked', + tbls => [qw(open_tables)], + }, + cxn_is_master => { + text => <<' END', + return $set->{master_file} ? 1 : 0; + END + note => 'Removes servers that are not masters', + tbls => [qw(master_status)], + }, + cxn_is_slave => { + text => <<' END', + return $set->{master_host} ? 1 : 0; + END + note => 'Removes servers that are not slaves', + tbls => [qw(slave_io_status slave_sql_status)], + }, + thd_is_not_waiting => { + text => <<' END', + return $set->{thread_status} !~ m#waiting for i/o request#; + END + note => 'Removes idle I/O threads', + tbls => [qw(io_threads)], + }, +); +foreach my $key ( keys %builtin_filters ) { + my ( $sub, $err ) = compile_filter($builtin_filters{$key}->{text}); + $filters{$key} = { + func => $sub, + text => $builtin_filters{$key}->{text}, + user => 0, + name => $key, # useful for later + note => $builtin_filters{$key}->{note}, + tbls => $builtin_filters{$key}->{tbls}, + } +} + +# Variable sets {{{3 +# Sets (arrayrefs) of variables that are used in S mode. They are read/written to +# the config file. +my %var_sets = ( + general => { + text => join( + ', ', + 'set_precision(Questions/Uptime_hires) as QPS', + 'set_precision(Com_commit/Uptime_hires) as Commit_PS', + 'set_precision((Com_rollback||0)/(Com_commit||1)) as Rollback_Commit', + 'set_precision((' + . join('+', map { "($_||0)" } + qw(Com_delete Com_delete_multi Com_insert Com_insert_select Com_replace + Com_replace_select Com_select Com_update Com_update_multi)) + . ')/(Com_commit||1)) as Write_Commit', + 'set_precision((Com_select+(Qcache_hits||0))/((' + . join('+', map { "($_||0)" } + qw(Com_delete Com_delete_multi Com_insert Com_insert_select Com_replace + Com_replace_select Com_select Com_update Com_update_multi)) + . ')||1)) as R_W_Ratio', + 'set_precision(Opened_tables/Uptime_hires) as Opens_PS', + 'percent($cur->{Open_tables}/($cur->{table_cache})) as Table_Cache_Used', + 'set_precision(Threads_created/Uptime_hires) as Threads_PS', + 'percent($cur->{Threads_cached}/($cur->{thread_cache_size}||1)) as Thread_Cache_Used', + 'percent($cur->{Max_used_connections}/($cur->{max_connections}||1)) as CXN_Used_Ever', + 'percent($cur->{Threads_connected}/($cur->{max_connections}||1)) as CXN_Used_Now', + ), + }, + commands => { + text => join( + ', ', + qw(Uptime Questions Com_delete Com_delete_multi Com_insert + Com_insert_select Com_replace Com_replace_select Com_select Com_update + Com_update_multi) + ), + }, + query_status => { + text => join( + ',', + qw( Uptime Select_full_join Select_full_range_join Select_range + Select_range_check Select_scan Slow_queries Sort_merge_passes + Sort_range Sort_rows Sort_scan) + ), + }, + innodb => { + text => join( + ',', + qw( Uptime Innodb_row_lock_current_waits Innodb_row_lock_time + Innodb_row_lock_time_avg Innodb_row_lock_time_max Innodb_row_lock_waits + Innodb_rows_deleted Innodb_rows_inserted Innodb_rows_read + Innodb_rows_updated) + ), + }, + txn => { + text => join( + ',', + qw( Uptime Com_begin Com_commit Com_rollback Com_savepoint + Com_xa_commit Com_xa_end Com_xa_prepare Com_xa_recover Com_xa_rollback + Com_xa_start) + ), + }, + key_cache => { + text => join( + ',', + qw( Uptime Key_blocks_not_flushed Key_blocks_unused Key_blocks_used + Key_read_requests Key_reads Key_write_requests Key_writes ) + ), + }, + query_cache => { + text => join( + ',', + "percent($exprs{QcacheHitRatio}) as Hit_Pct", + 'set_precision((Qcache_hits||0)/(Qcache_inserts||1)) as Hit_Ins', + 'set_precision((Qcache_lowmem_prunes||0)/Uptime_hires) as Lowmem_Prunes_sec', + 'percent(1-((Qcache_free_blocks||0)/(Qcache_total_blocks||1))) as Blocks_used', + qw( Qcache_free_blocks Qcache_free_memory Qcache_not_cached Qcache_queries_in_cache) + ), + }, + handler => { + text => join( + ',', + qw( Uptime Handler_read_key Handler_read_first Handler_read_next + Handler_read_prev Handler_read_rnd Handler_read_rnd_next Handler_delete + Handler_update Handler_write) + ), + }, + cxns_files_threads => { + text => join( + ',', + qw( Uptime Aborted_clients Aborted_connects Bytes_received Bytes_sent + Compression Connections Created_tmp_disk_tables Created_tmp_files + Created_tmp_tables Max_used_connections Open_files Open_streams + Open_tables Opened_tables Table_locks_immediate Table_locks_waited + Threads_cached Threads_connected Threads_created Threads_running) + ), + }, + prep_stmt => { + text => join( + ',', + qw( Uptime Com_dealloc_sql Com_execute_sql Com_prepare_sql Com_reset + Com_stmt_close Com_stmt_execute Com_stmt_fetch Com_stmt_prepare + Com_stmt_reset Com_stmt_send_long_data ) + ), + }, + innodb_health => { + text => join( + ',', + "$exprs{OldVersions} as OldVersions", + qw(IB_sm_mutex_spin_waits IB_sm_mutex_spin_rounds IB_sm_mutex_os_waits), + "$exprs{NumTxns} as NumTxns", + "$exprs{MaxTxnTime} as MaxTxnTime", + qw(IB_ro_queries_inside IB_ro_queries_in_queue), + "set_precision($exprs{DirtyBufs} * 100) as dirty_bufs", + "set_precision($exprs{BufPoolFill} * 100) as buf_fill", + qw(IB_bp_pages_total IB_bp_pages_read IB_bp_pages_written IB_bp_pages_created) + ), + }, + innodb_health2 => { + text => join( + ', ', + 'percent(1-((Innodb_buffer_pool_pages_free||0)/($cur->{Innodb_buffer_pool_pages_total}||1))) as BP_page_cache_usage', + 'percent(1-((Innodb_buffer_pool_reads||0)/(Innodb_buffer_pool_read_requests||1))) as BP_cache_hit_ratio', + 'Innodb_buffer_pool_wait_free', + 'Innodb_log_waits', + ), + }, + slow_queries => { + text => join( + ', ', + 'set_precision(Slow_queries/Uptime_hires) as Slow_PS', + 'set_precision(Select_full_join/Uptime_hires) as Full_Join_PS', + 'percent(Select_full_join/(Com_select||1)) as Full_Join_Ratio', + ), + }, +); + +# Server sets {{{3 +# Defines sets of servers between which the user can quickly switch. +my %server_groups; + +# Connections {{{3 +# This hash defines server connections. Each connection is a string that can be passed to +# the DBI connection. These are saved in the connections section in the config file. +my %connections; +# Defines the parts of connections. +my @conn_parts = qw(user have_user pass have_pass dsn savepass dl_table); + +# Graph widths {{{3 +# This hash defines the max values seen for various status/variable values, for graphing. +# These are stored in their own section in the config file. These are just initial values: +my %mvs = ( + Com_select => 50, + Com_insert => 50, + Com_update => 50, + Com_delete => 50, + Questions => 100, +); + +# ########################################################################### +# Valid Term::ANSIColor color strings. +# ########################################################################### +my %ansicolors = map { $_ => 1 } + qw( black blink blue bold clear concealed cyan dark green magenta on_black + on_blue on_cyan on_green on_magenta on_red on_white on_yellow red reset + reverse underline underscore white yellow); + +# ########################################################################### +# Valid comparison operators for color rules +# ########################################################################### +my %comp_ops = ( + '==' => 'Numeric equality', + '>' => 'Numeric greater-than', + '<' => 'Numeric less-than', + '>=' => 'Numeric greater-than/equal', + '<=' => 'Numeric less-than/equal', + '!=' => 'Numeric not-equal', + 'eq' => 'String equality', + 'gt' => 'String greater-than', + 'lt' => 'String less-than', + 'ge' => 'String greater-than/equal', + 'le' => 'String less-than/equal', + 'ne' => 'String not-equal', + '=~' => 'Pattern match', + '!~' => 'Negated pattern match', +); + +# ########################################################################### +# Valid aggregate functions. +# ########################################################################### +my %agg_funcs = ( + first => sub { + return $_[0] + }, + count => sub { + return 0 + @_; + }, + avg => sub { + my @args = grep { defined $_ } @_; + return (sum(map { m/([\d\.-]+)/g } @args) || 0) / (scalar(@args) || 1); + }, + sum => sub { + my @args = grep { defined $_ } @_; + return sum(@args); + } +); + +# ########################################################################### +# Valid functions for transformations. +# ########################################################################### +my %trans_funcs = ( + shorten => \&shorten, + secs_to_time => \&secs_to_time, + no_ctrl_char => \&no_ctrl_char, + percent => \&percent, + commify => \&commify, + dulint_to_int => \&dulint_to_int, + set_precision => \&set_precision, +); + +# Table definitions {{{3 +# This hash defines every table that can get displayed in every mode. Each +# table specifies columns and column data sources. The column is +# defined by the %columns hash. +# +# Example: foo => { src => 'bar' } means the foo column (look at +# $columns{foo} for its definition) gets its data from the 'bar' element of +# the current data set, whatever that is. +# +# These columns are post-processed after being defined, because they get stuff +# from %columns. After all the config is loaded for columns, there's more +# post-processing too; the subroutines compiled from src get added to +# the hash elements for extract_values to use. +# ########################################################################### + +my %tbl_meta = ( + adaptive_hash_index => { + capt => 'Adaptive Hash Index', + cust => {}, + cols => { + cxn => { src => 'cxn' }, + hash_table_size => { src => 'IB_ib_hash_table_size', trans => [qw(shorten)], }, + used_cells => { src => 'IB_ib_used_cells' }, + bufs_in_node_heap => { src => 'IB_ib_bufs_in_node_heap' }, + hash_searches_s => { src => 'IB_ib_hash_searches_s' }, + non_hash_searches_s => { src => 'IB_ib_non_hash_searches_s' }, + }, + visible => [ qw(cxn hash_table_size used_cells bufs_in_node_heap hash_searches_s non_hash_searches_s) ], + filters => [], + sort_cols => 'cxn', + sort_dir => '1', + innodb => 'ib', + group_by => [], + aggregate => 0, + }, + buffer_pool => { + capt => 'Buffer Pool', + cust => {}, + cols => { + cxn => { src => 'cxn' }, + total_mem_alloc => { src => 'IB_bp_total_mem_alloc', trans => [qw(shorten)], }, + awe_mem_alloc => { src => 'IB_bp_awe_mem_alloc', trans => [qw(shorten)], }, + add_pool_alloc => { src => 'IB_bp_add_pool_alloc', trans => [qw(shorten)], }, + buf_pool_size => { src => 'IB_bp_buf_pool_size', trans => [qw(shorten)], }, + buf_free => { src => 'IB_bp_buf_free' }, + buf_pool_hit_rate => { src => 'IB_bp_buf_pool_hit_rate' }, + buf_pool_reads => { src => 'IB_bp_buf_pool_reads' }, + buf_pool_hits => { src => 'IB_bp_buf_pool_hits' }, + dict_mem_alloc => { src => 'IB_bp_dict_mem_alloc' }, + pages_total => { src => 'IB_bp_pages_total' }, + pages_modified => { src => 'IB_bp_pages_modified' }, + reads_pending => { src => 'IB_bp_reads_pending' }, + writes_pending => { src => 'IB_bp_writes_pending' }, + writes_pending_lru => { src => 'IB_bp_writes_pending_lru' }, + writes_pending_flush_list => { src => 'IB_bp_writes_pending_flush_list' }, + writes_pending_single_page => { src => 'IB_bp_writes_pending_single_page' }, + page_creates_sec => { src => 'IB_bp_page_creates_sec' }, + page_reads_sec => { src => 'IB_bp_page_reads_sec' }, + page_writes_sec => { src => 'IB_bp_page_writes_sec' }, + pages_created => { src => 'IB_bp_pages_created' }, + pages_read => { src => 'IB_bp_pages_read' }, + pages_written => { src => 'IB_bp_pages_written' }, + }, + visible => [ qw(cxn buf_pool_size buf_free pages_total pages_modified buf_pool_hit_rate total_mem_alloc add_pool_alloc)], + filters => [], + sort_cols => 'cxn', + sort_dir => '1', + innodb => 'bp', + group_by => [], + aggregate => 0, + }, + # TODO: a new step in set_to_tbl: join result to itself, grouped? + # TODO: this would also enable pulling Q and T data together. + # TODO: using a SQL-ish language would also allow pivots to be easier -- treat the pivoted data as a view and SELECT from it. + cmd_summary => { + capt => 'Command Summary', + cust => {}, + cols => { + name => { src => 'name' }, + total => { src => 'total' }, + value => { src => 'value', agg => 'sum'}, + pct => { src => 'value/total', trans => [qw(percent)] }, + last_total => { src => 'last_total' }, + last_value => { src => 'last_value', agg => 'sum'}, + last_pct => { src => 'last_value/last_total', trans => [qw(percent)] }, + }, + visible => [qw(name value pct last_value last_pct)], + filters => [qw()], + sort_cols => '-value', + sort_dir => '1', + innodb => '', + group_by => [qw(name)], + aggregate => 1, + }, + deadlock_locks => { + capt => 'Deadlock Locks', + cust => {}, + cols => { + cxn => { src => 'cxn' }, + mysql_thread_id => { src => 'mysql_thread_id' }, + dl_txn_num => { src => 'dl_txn_num' }, + lock_type => { src => 'lock_type' }, + space_id => { src => 'space_id' }, + page_no => { src => 'page_no' }, + heap_no => { src => 'heap_no' }, + n_bits => { src => 'n_bits' }, + index => { src => 'index' }, + db => { src => 'db' }, + tbl => { src => 'table' }, + lock_mode => { src => 'lock_mode' }, + special => { src => 'special' }, + insert_intention => { src => 'insert_intention' }, + waiting => { src => 'waiting' }, + }, + visible => [ qw(cxn mysql_thread_id waiting lock_mode db tbl index special insert_intention)], + filters => [], + sort_cols => 'cxn mysql_thread_id', + sort_dir => '1', + innodb => 'dl', + group_by => [], + aggregate => 0, + }, + deadlock_transactions => { + capt => 'Deadlock Transactions', + cust => {}, + cols => { + cxn => { src => 'cxn' }, + active_secs => { src => 'active_secs' }, + dl_txn_num => { src => 'dl_txn_num' }, + has_read_view => { src => 'has_read_view' }, + heap_size => { src => 'heap_size' }, + host_and_domain => { src => 'hostname' }, + hostname => { src => $exprs{Host} }, + ip => { src => 'ip' }, + lock_structs => { src => 'lock_structs' }, + lock_wait_time => { src => 'lock_wait_time', trans => [ qw(secs_to_time) ] }, + mysql_thread_id => { src => 'mysql_thread_id' }, + os_thread_id => { src => 'os_thread_id' }, + proc_no => { src => 'proc_no' }, + query_id => { src => 'query_id' }, + query_status => { src => 'query_status' }, + query_text => { src => 'query_text', trans => [ qw(no_ctrl_char) ] }, + row_locks => { src => 'row_locks' }, + tables_in_use => { src => 'tables_in_use' }, + tables_locked => { src => 'tables_locked' }, + thread_decl_inside => { src => 'thread_decl_inside' }, + thread_status => { src => 'thread_status' }, + 'time' => { src => 'active_secs', trans => [ qw(secs_to_time) ] }, + timestring => { src => 'timestring' }, + txn_doesnt_see_ge => { src => 'txn_doesnt_see_ge' }, + txn_id => { src => 'txn_id' }, + txn_sees_lt => { src => 'txn_sees_lt' }, + txn_status => { src => 'txn_status' }, + truncates => { src => 'truncates' }, + undo_log_entries => { src => 'undo_log_entries' }, + user => { src => 'user' }, + victim => { src => 'victim' }, + wait_status => { src => 'lock_wait_status' }, + }, + visible => [ qw(cxn mysql_thread_id timestring user hostname victim time undo_log_entries lock_structs query_text)], + filters => [], + sort_cols => 'cxn mysql_thread_id', + sort_dir => '1', + innodb => 'dl', + group_by => [], + aggregate => 0, + }, + explain => { + capt => 'EXPLAIN Results', + cust => {}, + cols => { + part_id => { src => 'id' }, + select_type => { src => 'select_type' }, + tbl => { src => 'table' }, + partitions => { src => 'partitions' }, + scan_type => { src => 'type' }, + possible_keys => { src => 'possible_keys' }, + index => { src => 'key' }, + key_len => { src => 'key_len' }, + index_ref => { src => 'ref' }, + num_rows => { src => 'rows' }, + special => { src => 'extra' }, + }, + visible => [ qw(select_type tbl partitions scan_type possible_keys index key_len index_ref num_rows special)], + filters => [], + sort_cols => '', + sort_dir => '1', + innodb => '', + group_by => [], + aggregate => 0, + }, + file_io_misc => { + capt => 'File I/O Misc', + cust => {}, + cols => { + cxn => { src => 'cxn' }, + io_bytes_s => { src => 'IB_io_avg_bytes_s' }, + io_flush_type => { src => 'IB_io_flush_type' }, + io_fsyncs_s => { src => 'IB_io_fsyncs_s' }, + io_reads_s => { src => 'IB_io_reads_s' }, + io_writes_s => { src => 'IB_io_writes_s' }, + os_file_reads => { src => 'IB_io_os_file_reads' }, + os_file_writes => { src => 'IB_io_os_file_writes' }, + os_fsyncs => { src => 'IB_io_os_fsyncs' }, + }, + visible => [ qw(cxn os_file_reads os_file_writes os_fsyncs io_reads_s io_writes_s io_bytes_s)], + filters => [], + sort_cols => 'cxn', + sort_dir => '1', + innodb => 'io', + group_by => [], + aggregate => 0, + }, + fk_error => { + capt => 'Foreign Key Error Info', + cust => {}, + cols => { + timestring => { src => 'IB_fk_timestring' }, + child_db => { src => 'IB_fk_child_db' }, + child_table => { src => 'IB_fk_child_table' }, + child_index => { src => 'IB_fk_child_index' }, + fk_name => { src => 'IB_fk_fk_name' }, + parent_db => { src => 'IB_fk_parent_db' }, + parent_table => { src => 'IB_fk_parent_table' }, + parent_col => { src => 'IB_fk_parent_col' }, + parent_index => { src => 'IB_fk_parent_index' }, + attempted_op => { src => 'IB_fk_attempted_op' }, + }, + visible => [ qw(timestring child_db child_table child_index parent_db parent_table parent_col parent_index fk_name attempted_op)], + filters => [], + sort_cols => '', + sort_dir => '1', + innodb => 'fk', + group_by => [], + aggregate => 0, + }, + insert_buffers => { + capt => 'Insert Buffers', + cust => {}, + cols => { + cxn => { src => 'cxn' }, + inserts => { src => 'IB_ib_inserts' }, + merged_recs => { src => 'IB_ib_merged_recs' }, + merges => { src => 'IB_ib_merges' }, + size => { src => 'IB_ib_size' }, + free_list_len => { src => 'IB_ib_free_list_len' }, + seg_size => { src => 'IB_ib_seg_size' }, + }, + visible => [ qw(cxn inserts merged_recs merges size free_list_len seg_size)], + filters => [], + sort_cols => 'cxn', + sort_dir => '1', + innodb => 'ib', + group_by => [], + aggregate => 0, + }, + innodb_locks => { + capt => 'InnoDB Locks', + cust => {}, + cols => { + cxn => { src => 'cxn' }, + db => { src => 'db' }, + index => { src => 'index' }, + insert_intention => { src => 'insert_intention' }, + lock_mode => { src => 'lock_mode' }, + lock_type => { src => 'lock_type' }, + lock_wait_time => { src => 'lock_wait_time', trans => [ qw(secs_to_time) ] }, + mysql_thread_id => { src => 'mysql_thread_id' }, + n_bits => { src => 'n_bits' }, + page_no => { src => 'page_no' }, + space_id => { src => 'space_id' }, + special => { src => 'special' }, + tbl => { src => 'table' }, + 'time' => { src => 'active_secs', hdr => 'Active', trans => [ qw(secs_to_time) ] }, + txn_id => { src => 'txn_id' }, + waiting => { src => 'waiting' }, + }, + visible => [ qw(cxn mysql_thread_id lock_type waiting lock_wait_time time lock_mode db tbl index insert_intention special)], + filters => [], + sort_cols => 'cxn -lock_wait_time', + sort_dir => '1', + innodb => 'tx', + colors => [ + { col => 'lock_wait_time', op => '>', arg => 60, color => 'red' }, + { col => 'lock_wait_time', op => '>', arg => 30, color => 'yellow' }, + { col => 'lock_wait_time', op => '>', arg => 10, color => 'green' }, + ], + group_by => [], + aggregate => 0, + }, + innodb_transactions => { + capt => 'InnoDB Transactions', + cust => {}, + cols => { + cxn => { src => 'cxn' }, + active_secs => { src => 'active_secs' }, + has_read_view => { src => 'has_read_view' }, + heap_size => { src => 'heap_size' }, + hostname => { src => $exprs{Host} }, + ip => { src => 'ip' }, + wait_status => { src => 'lock_wait_status' }, + lock_wait_time => { src => 'lock_wait_time', trans => [ qw(secs_to_time) ] }, + lock_structs => { src => 'lock_structs' }, + mysql_thread_id => { src => 'mysql_thread_id' }, + os_thread_id => { src => 'os_thread_id' }, + proc_no => { src => 'proc_no' }, + query_id => { src => 'query_id' }, + query_status => { src => 'query_status' }, + query_text => { src => 'query_text', trans => [ qw(no_ctrl_char) ] }, + txn_time_remain => { src => $exprs{TxnTimeRemain}, trans => [ qw(secs_to_time) ] }, + row_locks => { src => 'row_locks' }, + tables_in_use => { src => 'tables_in_use' }, + tables_locked => { src => 'tables_locked' }, + thread_decl_inside => { src => 'thread_decl_inside' }, + thread_status => { src => 'thread_status' }, + 'time' => { src => 'active_secs', trans => [ qw(secs_to_time) ], agg => 'sum' }, + txn_doesnt_see_ge => { src => 'txn_doesnt_see_ge' }, + txn_id => { src => 'txn_id' }, + txn_sees_lt => { src => 'txn_sees_lt' }, + txn_status => { src => 'txn_status', minw => 10, maxw => 10 }, + undo_log_entries => { src => 'undo_log_entries' }, + user => { src => 'user', maxw => 10 }, + cnt => { src => 'mysql_thread_id', minw => 0 }, + }, + visible => [ qw(cxn cnt mysql_thread_id user hostname txn_status time undo_log_entries query_text)], + filters => [ qw( hide_self hide_inactive ) ], + sort_cols => '-active_secs txn_status cxn mysql_thread_id', + sort_dir => '1', + innodb => 'tx', + hide_caption => 1, + colors => [ + { col => 'wait_status', op => 'eq', arg => 'LOCK WAIT', color => 'black on_red' }, + { col => 'time', op => '>', arg => 600, color => 'red' }, + { col => 'time', op => '>', arg => 300, color => 'yellow' }, + { col => 'time', op => '>', arg => 60, color => 'green' }, + { col => 'time', op => '>', arg => 30, color => 'cyan' }, + { col => 'txn_status', op => 'eq', arg => 'not started', color => 'white' }, + ], + group_by => [ qw(cxn txn_status) ], + aggregate => 0, + }, + io_threads => { + capt => 'I/O Threads', + cust => {}, + cols => { + cxn => { src => 'cxn' }, + thread => { src => 'thread' }, + thread_purpose => { src => 'purpose' }, + event_set => { src => 'event_set' }, + thread_status => { src => 'state' }, + }, + visible => [ qw(cxn thread thread_purpose thread_status)], + filters => [ qw() ], + sort_cols => 'cxn thread', + sort_dir => '1', + innodb => 'io', + group_by => [], + aggregate => 0, + }, + log_statistics => { + capt => 'Log Statistics', + cust => {}, + cols => { + cxn => { src => 'cxn' }, + last_chkp => { src => 'IB_lg_last_chkp' }, + log_flushed_to => { src => 'IB_lg_log_flushed_to' }, + log_ios_done => { src => 'IB_lg_log_ios_done' }, + log_ios_s => { src => 'IB_lg_log_ios_s' }, + log_seq_no => { src => 'IB_lg_log_seq_no' }, + pending_chkp_writes => { src => 'IB_lg_pending_chkp_writes' }, + pending_log_writes => { src => 'IB_lg_pending_log_writes' }, + }, + visible => [ qw(cxn log_seq_no log_flushed_to last_chkp log_ios_done log_ios_s)], + filters => [], + sort_cols => 'cxn', + sort_dir => '1', + innodb => 'lg', + group_by => [], + aggregate => 0, + }, + master_status => { + capt => 'Master Status', + cust => {}, + cols => { + cxn => { src => 'cxn' }, + binlog_do_db => { src => 'binlog_do_db' }, + binlog_ignore_db => { src => 'binlog_ignore_db' }, + master_file => { src => 'file' }, + master_pos => { src => 'position' }, + binlog_cache_overflow => { src => '(Binlog_cache_disk_use||0)/(Binlog_cache_use||1)', trans => [ qw(percent) ] }, + }, + visible => [ qw(cxn master_file master_pos binlog_cache_overflow)], + filters => [ qw(cxn_is_master) ], + sort_cols => 'cxn', + sort_dir => '1', + innodb => '', + group_by => [], + aggregate => 0, + }, + pending_io => { + capt => 'Pending I/O', + cust => {}, + cols => { + cxn => { src => 'cxn' }, + p_normal_aio_reads => { src => 'IB_io_pending_normal_aio_reads' }, + p_aio_writes => { src => 'IB_io_pending_aio_writes' }, + p_ibuf_aio_reads => { src => 'IB_io_pending_ibuf_aio_reads' }, + p_sync_ios => { src => 'IB_io_pending_sync_ios' }, + p_buf_pool_flushes => { src => 'IB_io_pending_buffer_pool_flushes' }, + p_log_flushes => { src => 'IB_io_pending_log_flushes' }, + p_log_ios => { src => 'IB_io_pending_log_ios' }, + p_preads => { src => 'IB_io_pending_preads' }, + p_pwrites => { src => 'IB_io_pending_pwrites' }, + }, + visible => [ qw(cxn p_normal_aio_reads p_aio_writes p_ibuf_aio_reads p_sync_ios p_log_flushes p_log_ios)], + filters => [], + sort_cols => 'cxn', + sort_dir => '1', + innodb => 'io', + group_by => [], + aggregate => 0, + }, + open_tables => { + capt => 'Open Tables', + cust => {}, + cols => { + cxn => { src => 'cxn' }, + db => { src => 'database' }, + tbl => { src => 'table' }, + num_times_open => { src => 'in_use' }, + is_name_locked => { src => 'name_locked' }, + }, + visible => [ qw(cxn db tbl num_times_open is_name_locked)], + filters => [ qw(table_is_open) ], + sort_cols => '-num_times_open cxn db tbl', + sort_dir => '1', + innodb => '', + group_by => [], + aggregate => 0, + }, + page_statistics => { + capt => 'Page Statistics', + cust => {}, + cols => { + cxn => { src => 'cxn' }, + pages_read => { src => 'IB_bp_pages_read' }, + pages_written => { src => 'IB_bp_pages_written' }, + pages_created => { src => 'IB_bp_pages_created' }, + page_reads_sec => { src => 'IB_bp_page_reads_sec' }, + page_writes_sec => { src => 'IB_bp_page_writes_sec' }, + page_creates_sec => { src => 'IB_bp_page_creates_sec' }, + }, + visible => [ qw(cxn pages_read pages_written pages_created page_reads_sec page_writes_sec page_creates_sec)], + filters => [], + sort_cols => 'cxn', + sort_dir => '1', + innodb => 'bp', + group_by => [], + aggregate => 0, + }, + processlist => { + capt => 'MySQL Process List', + cust => {}, + cols => { + cxn => { src => 'cxn', minw => 6, maxw => 10 }, + mysql_thread_id => { src => 'id', minw => 6, maxw => 0 }, + user => { src => 'user', minw => 5, maxw => 8 }, + hostname => { src => $exprs{Host}, minw => 13, maxw => 8, }, + port => { src => $exprs{Port}, minw => 0, maxw => 0, }, + host_and_port => { src => 'host', minw => 0, maxw => 0 }, + db => { src => 'db', minw => 6, maxw => 12 }, + cmd => { src => 'command', minw => 5, maxw => 0 }, + time => { src => 'time', minw => 5, maxw => 0, trans => [ qw(secs_to_time) ], agg => 'sum' }, + state => { src => 'state', minw => 0, maxw => 0 }, + info => { src => 'info', minw => 0, maxw => 0, trans => [ qw(no_ctrl_char) ] }, + cnt => { src => 'id', minw => 0, maxw => 0 }, + }, + visible => [ qw(cxn cmd cnt mysql_thread_id state user hostname db time info)], + filters => [ qw(hide_self hide_inactive hide_slave_io) ], + sort_cols => '-time cxn hostname mysql_thread_id', + sort_dir => '1', + innodb => '', + hide_caption => 1, + colors => [ + { col => 'state', op => 'eq', arg => 'Locked', color => 'black on_red' }, + { col => 'cmd', op => 'eq', arg => 'Sleep', color => 'white' }, + { col => 'user', op => 'eq', arg => 'system user', color => 'white' }, + { col => 'cmd', op => 'eq', arg => 'Connect', color => 'white' }, + { col => 'cmd', op => 'eq', arg => 'Binlog Dump', color => 'white' }, + { col => 'time', op => '>', arg => 600, color => 'red' }, + { col => 'time', op => '>', arg => 120, color => 'yellow' }, + { col => 'time', op => '>', arg => 60, color => 'green' }, + { col => 'time', op => '>', arg => 30, color => 'cyan' }, + ], + group_by => [qw(cxn cmd)], + aggregate => 0, + }, + + # TODO: some more columns: + # kb_used=hdr='BufUsed' minw='0' num='0' src='percent(1 - ((Key_blocks_unused * key_cache_block_size) / (key_buffer_size||1)))' dec='0' trans='' tbl='q_header' just='-' user='1' maxw='0' label='User-defined' + # retries=hdr='Retries' minw='0' num='0' src='Slave_retried_transactions' dec='0' trans='' tbl='slave_sql_status' just='-' user='1' maxw='0' label='User-defined' + # thd=hdr='Thd' minw='0' num='0' src='Threads_connected' dec='0' trans='' tbl='slave_sql_status' just='-' user='1' maxw='0' label='User-defined' + + q_header => { + capt => 'Q-mode Header', + cust => {}, + cols => { + cxn => { src => 'cxn' }, + questions => { src => 'Questions' }, + qps => { src => 'Questions/Uptime_hires', dec => 1, trans => [qw(shorten)] }, + load => { src => $exprs{ServerLoad}, dec => 1, trans => [qw(shorten)] }, + slow => { src => 'Slow_queries', dec => 1, trans => [qw(shorten)] }, + q_cache_hit => { src => $exprs{QcacheHitRatio}, dec => 1, trans => [qw(percent)] }, + key_buffer_hit => { src => '1-(Key_reads/(Key_read_requests||1))', dec => 1, trans => [qw(percent)] }, + bps_in => { src => 'Bytes_received/Uptime_hires', dec => 1, trans => [qw(shorten)] }, + bps_out => { src => 'Bytes_sent/Uptime_hires', dec => 1, trans => [qw(shorten)] }, + when => { src => 'when' }, + }, + visible => [ qw(cxn when load qps slow q_cache_hit key_buffer_hit bps_in bps_out)], + filters => [], + sort_cols => 'when cxn', + sort_dir => '1', + innodb => '', + hide_caption => 1, + group_by => [], + aggregate => 0, + }, + row_operations => { + capt => 'InnoDB Row Operations', + cust => {}, + cols => { + cxn => { src => 'cxn' }, + num_inserts => { src => 'IB_ro_num_rows_ins' }, + num_updates => { src => 'IB_ro_num_rows_upd' }, + num_reads => { src => 'IB_ro_num_rows_read' }, + num_deletes => { src => 'IB_ro_num_rows_del' }, + num_inserts_sec => { src => 'IB_ro_ins_sec' }, + num_updates_sec => { src => 'IB_ro_upd_sec' }, + num_reads_sec => { src => 'IB_ro_read_sec' }, + num_deletes_sec => { src => 'IB_ro_del_sec' }, + }, + visible => [ qw(cxn num_inserts num_updates num_reads num_deletes num_inserts_sec + num_updates_sec num_reads_sec num_deletes_sec)], + filters => [], + sort_cols => 'cxn', + sort_dir => '1', + innodb => 'ro', + group_by => [], + aggregate => 0, + }, + row_operation_misc => { + capt => 'Row Operation Misc', + cust => {}, + cols => { + cxn => { src => 'cxn' }, + queries_in_queue => { src => 'IB_ro_queries_in_queue' }, + queries_inside => { src => 'IB_ro_queries_inside' }, + read_views_open => { src => 'IB_ro_read_views_open' }, + main_thread_id => { src => 'IB_ro_main_thread_id' }, + main_thread_proc_no => { src => 'IB_ro_main_thread_proc_no' }, + main_thread_state => { src => 'IB_ro_main_thread_state' }, + num_res_ext => { src => 'IB_ro_n_reserved_extents' }, + }, + visible => [ qw(cxn queries_in_queue queries_inside read_views_open main_thread_state)], + filters => [], + sort_cols => 'cxn', + sort_dir => '1', + innodb => 'ro', + group_by => [], + aggregate => 0, + }, + semaphores => { + capt => 'InnoDB Semaphores', + cust => {}, + cols => { + cxn => { src => 'cxn' }, + mutex_os_waits => { src => 'IB_sm_mutex_os_waits' }, + mutex_spin_rounds => { src => 'IB_sm_mutex_spin_rounds' }, + mutex_spin_waits => { src => 'IB_sm_mutex_spin_waits' }, + reservation_count => { src => 'IB_sm_reservation_count' }, + rw_excl_os_waits => { src => 'IB_sm_rw_excl_os_waits' }, + rw_excl_spins => { src => 'IB_sm_rw_excl_spins' }, + rw_shared_os_waits => { src => 'IB_sm_rw_shared_os_waits' }, + rw_shared_spins => { src => 'IB_sm_rw_shared_spins' }, + signal_count => { src => 'IB_sm_signal_count' }, + wait_array_size => { src => 'IB_sm_wait_array_size' }, + }, + visible => [ qw(cxn mutex_os_waits mutex_spin_waits mutex_spin_rounds + rw_excl_os_waits rw_excl_spins rw_shared_os_waits rw_shared_spins + signal_count reservation_count )], + filters => [], + sort_cols => 'cxn', + sort_dir => '1', + innodb => 'sm', + group_by => [], + aggregate => 0, + }, + slave_io_status => { + capt => 'Slave I/O Status', + cust => {}, + cols => { + cxn => { src => 'cxn' }, + connect_retry => { src => 'connect_retry' }, + master_host => { src => 'master_host', hdr => 'Master'}, + master_log_file => { src => 'master_log_file', hdr => 'File' }, + master_port => { src => 'master_port' }, + master_ssl_allowed => { src => 'master_ssl_allowed' }, + master_ssl_ca_file => { src => 'master_ssl_ca_file' }, + master_ssl_ca_path => { src => 'master_ssl_ca_path' }, + master_ssl_cert => { src => 'master_ssl_cert' }, + master_ssl_cipher => { src => 'master_ssl_cipher' }, + master_ssl_key => { src => 'master_ssl_key' }, + master_user => { src => 'master_user' }, + read_master_log_pos => { src => 'read_master_log_pos', hdr => 'Pos' }, + relay_log_size => { src => 'relay_log_space', trans => [qw(shorten)] }, + slave_io_running => { src => 'slave_io_running', hdr => 'On?' }, + slave_io_state => { src => 'slave_io_state', hdr => 'State' }, + }, + visible => [ qw(cxn master_host slave_io_running master_log_file relay_log_size read_master_log_pos slave_io_state)], + filters => [ qw( cxn_is_slave ) ], + sort_cols => 'slave_io_running cxn', + colors => [ + { col => 'slave_io_running', op => 'ne', arg => 'Yes', color => 'black on_red' }, + ], + sort_dir => '1', + innodb => '', + group_by => [], + aggregate => 0, + }, + slave_sql_status => { + capt => 'Slave SQL Status', + cust => {}, + cols => { + cxn => { src => 'cxn' }, + exec_master_log_pos => { src => 'exec_master_log_pos', hdr => 'Master Pos' }, + last_errno => { src => 'last_errno' }, + last_error => { src => 'last_error' }, + master_host => { src => 'master_host', hdr => 'Master' }, + relay_log_file => { src => 'relay_log_file' }, + relay_log_pos => { src => 'relay_log_pos' }, + relay_log_size => { src => 'relay_log_space', trans => [qw(shorten)] }, + relay_master_log_file => { src => 'relay_master_log_file', hdr => 'Master File' }, + replicate_do_db => { src => 'replicate_do_db' }, + replicate_do_table => { src => 'replicate_do_table' }, + replicate_ignore_db => { src => 'replicate_ignore_db' }, + replicate_ignore_table => { src => 'replicate_ignore_table' }, + replicate_wild_do_table => { src => 'replicate_wild_do_table' }, + replicate_wild_ignore_table => { src => 'replicate_wild_ignore_table' }, + skip_counter => { src => 'skip_counter' }, + slave_sql_running => { src => 'slave_sql_running', hdr => 'On?' }, + until_condition => { src => 'until_condition' }, + until_log_file => { src => 'until_log_file' }, + until_log_pos => { src => 'until_log_pos' }, + time_behind_master => { src => 'seconds_behind_master', trans => [ qw(secs_to_time) ] }, + bytes_behind_master => { src => 'master_log_file && master_log_file eq relay_master_log_file ? read_master_log_pos - exec_master_log_pos : 0', trans => [qw(shorten)] }, + slave_catchup_rate => { src => $exprs{SlaveCatchupRate}, trans => [ qw(set_precision) ] }, + slave_open_temp_tables => { src => 'Slave_open_temp_tables' }, + }, + visible => [ qw(cxn master_host slave_sql_running time_behind_master slave_catchup_rate slave_open_temp_tables relay_log_pos last_error)], + filters => [ qw( cxn_is_slave ) ], + sort_cols => 'slave_sql_running cxn', + sort_dir => '1', + innodb => '', + colors => [ + { col => 'slave_sql_running', op => 'ne', arg => 'Yes', color => 'black on_red' }, + { col => 'time_behind_master', op => '>', arg => 600, color => 'red' }, + { col => 'time_behind_master', op => '>', arg => 60, color => 'yellow' }, + { col => 'time_behind_master', op => '==', arg => 0, color => 'white' }, + ], + group_by => [], + aggregate => 0, + }, + t_header => { + capt => 'T-Mode Header', + cust => {}, + cols => { + cxn => { src => 'cxn' }, + dirty_bufs => { src => $exprs{DirtyBufs}, trans => [qw(percent)] }, + history_list_len => { src => 'IB_tx_history_list_len' }, + lock_structs => { src => 'IB_tx_num_lock_structs' }, + num_txns => { src => $exprs{NumTxns} }, + max_txn => { src => $exprs{MaxTxnTime}, trans => [qw(secs_to_time)] }, + undo_for => { src => 'IB_tx_purge_undo_for' }, + used_bufs => { src => $exprs{BufPoolFill}, trans => [qw(percent)]}, + versions => { src => $exprs{OldVersions} }, + }, + visible => [ qw(cxn history_list_len versions undo_for dirty_bufs used_bufs num_txns max_txn lock_structs)], + filters => [ ], + sort_cols => 'cxn', + sort_dir => '1', + innodb => '', + colors => [], + hide_caption => 1, + group_by => [], + aggregate => 0, + }, + var_status => { + capt => 'Variables & Status', + cust => {}, + cols => {}, # Generated from current varset + visible => [], # Generated from current varset + filters => [], + sort_cols => '', + sort_dir => 1, + innodb => '', + temp => 1, # Do not persist to config file. + hide_caption => 1, + pivot => 0, + group_by => [], + aggregate => 0, + }, + wait_array => { + capt => 'InnoDB Wait Array', + cust => {}, + cols => { + cxn => { src => 'cxn' }, + thread => { src => 'thread' }, + waited_at_filename => { src => 'waited_at_filename' }, + waited_at_line => { src => 'waited_at_line' }, + 'time' => { src => 'waited_secs', trans => [ qw(secs_to_time) ] }, + request_type => { src => 'request_type' }, + lock_mem_addr => { src => 'lock_mem_addr' }, + lock_cfile_name => { src => 'lock_cfile_name' }, + lock_cline => { src => 'lock_cline' }, + writer_thread => { src => 'writer_thread' }, + writer_lock_mode => { src => 'writer_lock_mode' }, + num_readers => { src => 'num_readers' }, + lock_var => { src => 'lock_var' }, + waiters_flag => { src => 'waiters_flag' }, + last_s_file_name => { src => 'last_s_file_name' }, + last_s_line => { src => 'last_s_line' }, + last_x_file_name => { src => 'last_x_file_name' }, + last_x_line => { src => 'last_x_line' }, + cell_waiting => { src => 'cell_waiting' }, + cell_event_set => { src => 'cell_event_set' }, + }, + visible => [ qw(cxn thread time waited_at_filename waited_at_line request_type num_readers lock_var waiters_flag cell_waiting cell_event_set)], + filters => [], + sort_cols => 'cxn -time', + sort_dir => '1', + innodb => 'sm', + group_by => [], + aggregate => 0, + }, +); + +# Initialize %tbl_meta from %columns and do some checks. +foreach my $table_name ( keys %tbl_meta ) { + my $table = $tbl_meta{$table_name}; + my $cols = $table->{cols}; + + foreach my $col_name ( keys %$cols ) { + my $col_def = $table->{cols}->{$col_name}; + die "I can't find a column named '$col_name' for '$table_name'" unless $columns{$col_name}; + $columns{$col_name}->{referenced} = 1; + + foreach my $prop ( keys %col_props ) { + # Each column gets non-existing values set from %columns or defaults from %col_props. + if ( !$col_def->{$prop} ) { + $col_def->{$prop} + = defined($columns{$col_name}->{$prop}) + ? $columns{$col_name}->{$prop} + : $col_props{$prop}; + } + } + + # Ensure transformations and aggregate functions are valid + die "Unknown aggregate function '$col_def->{agg}' " + . "for column '$col_name' in table '$table_name'" + unless exists $agg_funcs{$col_def->{agg}}; + foreach my $trans ( @{$col_def->{trans}} ) { + die "Unknown transformation '$trans' " + . "for column '$col_name' in table '$table_name'" + unless exists $trans_funcs{$trans}; + } + } + + # Ensure each column in visible and group_by exists in cols + foreach my $place ( qw(visible group_by) ) { + foreach my $col_name ( @{$table->{$place}} ) { + if ( !exists $cols->{$col_name} ) { + die "Column '$col_name' is listed in '$place' for '$table_name', but doesn't exist"; + } + } + } + + # Compile sort and color subroutines + $table->{sort_func} = make_sort_func($table); + $table->{color_func} = make_color_func($table); +} + +# This is for code cleanup: +{ + my @unused_cols = grep { !$columns{$_}->{referenced} } sort keys %columns; + if ( @unused_cols ) { + die "The following columns are not used: " + . join(' ', @unused_cols); + } +} + +# ########################################################################### +# Operating modes {{{3 +# ########################################################################### +my %modes = ( + B => { + hdr => 'InnoDB Buffers', + cust => {}, + note => 'Shows buffer info from InnoDB', + action_for => { + i => { + action => sub { toggle_config('status_inc') }, + label => 'Toggle incremental status display', + }, + }, + display_sub => \&display_B, + connections => [], + server_group => '', + one_connection => 0, + tables => [qw(buffer_pool page_statistics insert_buffers adaptive_hash_index)], + visible_tables => [qw(buffer_pool page_statistics insert_buffers adaptive_hash_index)], + }, + C => { + hdr => 'Command Summary', + cust => {}, + note => 'Shows relative magnitude of variables', + action_for => { + s => { + action => sub { get_config_interactive('cmd_filter') }, + label => 'Choose variable prefix', + }, + }, + display_sub => \&display_C, + connections => [], + server_group => '', + one_connection => 0, + tables => [qw(cmd_summary)], + visible_tables => [qw(cmd_summary)], + }, + D => { + hdr => 'InnoDB Deadlocks', + cust => {}, + note => 'View InnoDB deadlock information', + action_for => { + c => { + action => sub { edit_table('deadlock_transactions') }, + label => 'Choose visible columns', + }, + w => { + action => \&create_deadlock, + label => 'Wipe deadlock status info by creating a deadlock', + }, + }, + display_sub => \&display_D, + connections => [], + server_group => '', + one_connection => 0, + tables => [qw(deadlock_transactions deadlock_locks)], + visible_tables => [qw(deadlock_transactions deadlock_locks)], + }, + F => { + hdr => 'InnoDB FK Err', + cust => {}, + note => 'View the latest InnoDB foreign key error', + action_for => {}, + display_sub => \&display_F, + connections => [], + server_group => '', + one_connection => 1, + tables => [qw(fk_error)], + visible_tables => [qw(fk_error)], + }, + I => { + hdr => 'InnoDB I/O Info', + cust => {}, + note => 'Shows I/O info (i/o, log...) from InnoDB', + action_for => { + i => { + action => sub { toggle_config('status_inc') }, + label => 'Toggle incremental status display', + }, + }, + display_sub => \&display_I, + connections => [], + server_group => '', + one_connection => 0, + tables => [qw(io_threads pending_io file_io_misc log_statistics)], + visible_tables => [qw(io_threads pending_io file_io_misc log_statistics)], + }, + L => { + hdr => 'Locks', + cust => {}, + note => 'Shows transaction locks', + action_for => { + a => { + action => sub { send_cmd_to_servers('CREATE TABLE IF NOT EXISTS test.innodb_lock_monitor(a int) ENGINE=InnoDB', 0, '', []); }, + label => 'Start the InnoDB Lock Monitor', + }, + o => { + action => sub { send_cmd_to_servers('DROP TABLE IF EXISTS test.innodb_lock_monitor', 0, '', []); }, + label => 'Stop the InnoDB Lock Monitor', + }, + }, + display_sub => \&display_L, + connections => [], + server_group => '', + one_connection => 0, + tables => [qw(innodb_locks)], + visible_tables => [qw(innodb_locks)], + }, + M => { + hdr => 'Replication Status', + cust => {}, + note => 'Shows replication (master and slave) status', + action_for => { + a => { + action => sub { send_cmd_to_servers('START SLAVE', 0, 'START SLAVE SQL_THREAD UNTIL MASTER_LOG_FILE = ?, MASTER_LOG_POS = ?', []); }, + label => 'Start slave(s)', + }, + i => { + action => sub { toggle_config('status_inc') }, + label => 'Toggle incremental status display', + }, + o => { + action => sub { send_cmd_to_servers('STOP SLAVE', 0, '', []); }, + label => 'Stop slave(s)', + }, + b => { + action => sub { purge_master_logs() }, + label => 'Purge unused master logs', + }, + }, + display_sub => \&display_M, + connections => [], + server_group => '', + one_connection => 0, + tables => [qw(slave_sql_status slave_io_status master_status)], + visible_tables => [qw(slave_sql_status slave_io_status master_status)], + }, + O => { + hdr => 'Open Tables', + cust => {}, + note => 'Shows open tables in MySQL', + action_for => { + r => { + action => sub { reverse_sort('open_tables'); }, + label => 'Reverse sort order', + }, + s => { + action => sub { choose_sort_cols('open_tables'); }, + label => "Choose sort column", + }, + }, + display_sub => \&display_O, + connections => [], + server_group => '', + one_connection => 0, + tables => [qw(open_tables)], + visible_tables => [qw(open_tables)], + }, + Q => { + hdr => 'Query List', + cust => {}, + note => 'Shows queries from SHOW FULL PROCESSLIST', + action_for => { + a => { + action => sub { toggle_filter('processlist', 'hide_self') }, + label => 'Toggle the innotop process', + }, + c => { + action => sub { edit_table('processlist') }, + label => 'Choose visible columns', + }, + e => { + action => sub { analyze_query('e'); }, + label => "Explain a thread's query", + }, + f => { + action => sub { analyze_query('f'); }, + label => "Show a thread's full query", + }, + h => { + action => sub { toggle_visible_table('Q', 'q_header') }, + label => 'Toggle the header on and off', + }, + i => { + action => sub { toggle_filter('processlist', 'hide_inactive') }, + label => 'Toggle idle processes', + }, + k => { + action => sub { kill_query('CONNECTION') }, + label => "Kill a query's connection", + }, + r => { + action => sub { reverse_sort('processlist'); }, + label => 'Reverse sort order', + }, + s => { + action => sub { choose_sort_cols('processlist'); }, + label => "Change the display's sort column", + }, + x => { + action => sub { kill_query('QUERY') }, + label => "Kill a query", + }, + }, + display_sub => \&display_Q, + connections => [], + server_group => '', + one_connection => 0, + tables => [qw(q_header processlist)], + visible_tables => [qw(q_header processlist)], + }, + R => { + hdr => 'InnoDB Row Ops', + cust => {}, + note => 'Shows InnoDB row operation and semaphore info', + action_for => { + i => { + action => sub { toggle_config('status_inc') }, + label => 'Toggle incremental status display', + }, + }, + display_sub => \&display_R, + connections => [], + server_group => '', + one_connection => 0, + tables => [qw(row_operations row_operation_misc semaphores wait_array)], + visible_tables => [qw(row_operations row_operation_misc semaphores wait_array)], + }, + S => { + hdr => 'Variables & Status', + cust => {}, + note => 'Shows query load statistics a la vmstat', + action_for => { + '>' => { + action => sub { switch_var_set('S_set', 1) }, + label => 'Switch to next variable set', + }, + '<' => { + action => sub { switch_var_set('S_set', -1) }, + label => 'Switch to prev variable set', + }, + c => { + action => sub { + choose_var_set('S_set'); + start_S_mode(); + }, + label => "Choose which set to display", + }, + e => { + action => \&edit_current_var_set, + label => 'Edit the current set of variables', + }, + i => { + action => sub { $clear_screen_sub->(); toggle_config('status_inc') }, + label => 'Toggle incremental status display', + }, + '-' => { + action => sub { set_display_precision(-1) }, + label => 'Decrease fractional display precision', + }, + '+' => { + action => sub { set_display_precision(1) }, + label => 'Increase fractional display precision', + }, + g => { + action => sub { set_s_mode('g') }, + label => 'Switch to graph (tload) view', + }, + s => { + action => sub { set_s_mode('s') }, + label => 'Switch to standard (vmstat) view', + }, + v => { + action => sub { set_s_mode('v') }, + label => 'Switch to pivoted view', + }, + }, + display_sub => \&display_S, + no_clear_screen => 1, + connections => [], + server_group => '', + one_connection => 0, + tables => [qw(var_status)], + visible_tables => [qw(var_status)], + }, + T => { + hdr => 'InnoDB Txns', + cust => {}, + note => 'Shows InnoDB transactions in top-like format', + action_for => { + a => { + action => sub { toggle_filter('innodb_transactions', 'hide_self') }, + label => 'Toggle the innotop process', + }, + c => { + action => sub { edit_table('innodb_transactions') }, + label => 'Choose visible columns', + }, + e => { + action => sub { analyze_query('e'); }, + label => "Explain a thread's query", + }, + f => { + action => sub { analyze_query('f'); }, + label => "Show a thread's full query", + }, + h => { + action => sub { toggle_visible_table('T', 't_header') }, + label => 'Toggle the header on and off', + }, + i => { + action => sub { toggle_filter('innodb_transactions', 'hide_inactive') }, + label => 'Toggle inactive transactions', + }, + k => { + action => sub { kill_query('CONNECTION') }, + label => "Kill a transaction's connection", + }, + r => { + action => sub { reverse_sort('innodb_transactions'); }, + label => 'Reverse sort order', + }, + s => { + action => sub { choose_sort_cols('innodb_transactions'); }, + label => "Change the display's sort column", + }, + x => { + action => sub { kill_query('QUERY') }, + label => "Kill a query", + }, + }, + display_sub => \&display_T, + connections => [], + server_group => '', + one_connection => 0, + tables => [qw(t_header innodb_transactions)], + visible_tables => [qw(t_header innodb_transactions)], + }, +); + +# ########################################################################### +# Global key mappings {{{3 +# Keyed on a single character, which is read from the keyboard. Uppercase +# letters switch modes. Lowercase letters access commands when in a mode. +# These can be overridden by action_for in %modes. +# ########################################################################### +my %action_for = ( + '$' => { + action => \&edit_configuration, + label => 'Edit configuration settings', + }, + '?' => { + action => \&display_help, + label => 'Show help', + }, + '!' => { + action => \&display_license, + label => 'Show license and warranty', + }, + '^' => { + action => \&edit_table, + label => "Edit the displayed table(s)", + }, + '#' => { + action => \&choose_server_groups, + label => 'Select/create server groups', + }, + '@' => { + action => \&choose_servers, + label => 'Select/create server connections', + }, + '/' => { + action => \&add_quick_filter, + label => 'Quickly filter what you see', + }, + '\\' => { + action => \&clear_quick_filters, + label => 'Clear quick-filters', + }, + '%' => { + action => \&choose_filters, + label => 'Choose and edit table filters', + }, + "\t" => { + action => \&next_server_group, + label => 'Switch to the next server group', + key => 'TAB', + }, + '=' => { + action => \&toggle_aggregate, + label => 'Toggle aggregation', + }, + # TODO: can these be auto-generated from %modes? + B => { + action => sub { switch_mode('B') }, + label => '', + }, + C => { + action => sub { switch_mode('C') }, + label => '', + }, + D => { + action => sub { switch_mode('D') }, + label => '', + }, + F => { + action => sub { switch_mode('F') }, + label => '', + }, + I => { + action => sub { switch_mode('I') }, + label => '', + }, + L => { + action => sub { switch_mode('L') }, + label => '', + }, + M => { + action => sub { switch_mode('M') }, + label => '', + }, + O => { + action => sub { switch_mode('O') }, + label => '', + }, + Q => { + action => sub { switch_mode('Q') }, + label => '', + }, + R => { + action => sub { switch_mode('R') }, + label => '', + }, + S => { + action => \&start_S_mode, + label => '', + }, + T => { + action => sub { switch_mode('T') }, + label => '', + }, + d => { + action => sub { get_config_interactive('interval') }, + label => 'Change refresh interval', + }, + n => { action => \&next_server, label => 'Switch to the next connection' }, + p => { action => \&pause, label => 'Pause innotop', }, + q => { action => \&finish, label => 'Quit innotop', }, +); + +# ########################################################################### +# Sleep times after certain statements {{{3 +# ########################################################################### +my %stmt_sleep_time_for = (); + +# ########################################################################### +# Config editor key mappings {{{3 +# ########################################################################### +my %cfg_editor_action = ( + c => { + note => 'Edit columns, etc in the displayed table(s)', + func => \&edit_table, + }, + g => { + note => 'Edit general configuration', + func => \&edit_configuration_variables, + }, + k => { + note => 'Edit row-coloring rules', + func => \&edit_color_rules, + }, + p => { + note => 'Manage plugins', + func => \&edit_plugins, + }, + s => { + note => 'Edit server groups', + func => \&edit_server_groups, + }, + S => { + note => 'Edit SQL statement sleep delays', + func => \&edit_stmt_sleep_times, + }, + t => { + note => 'Choose which table(s) to display in this mode', + func => \&choose_mode_tables, + }, +); + +# ########################################################################### +# Color editor key mappings {{{3 +# ########################################################################### +my %color_editor_action = ( + n => { + note => 'Create a new color rule', + func => sub { + my ( $tbl, $idx ) = @_; + my $meta = $tbl_meta{$tbl}; + + $clear_screen_sub->(); + my $col; + do { + $col = prompt_list( + 'Choose the target column for the rule', + '', + sub { return keys %{$meta->{cols}} }, + { map { $_ => $meta->{cols}->{$_}->{label} } keys %{$meta->{cols}} }); + } while ( !$col ); + ( $col ) = grep { $_ } split(/\W+/, $col); + return $idx unless $col && exists $meta->{cols}->{$col}; + + $clear_screen_sub->(); + my $op; + do { + $op = prompt_list( + 'Choose the comparison operator for the rule', + '', + sub { return keys %comp_ops }, + { map { $_ => $comp_ops{$_} } keys %comp_ops } ); + } until ( $op ); + $op =~ s/\s+//g; + return $idx unless $op && exists $comp_ops{$op}; + + my $arg; + do { + $arg = prompt('Specify an argument for the comparison'); + } until defined $arg; + + my $color; + do { + $color = prompt_list( + 'Choose the color(s) the row should be when the rule matches', + '', + sub { return keys %ansicolors }, + { map { $_ => $_ } keys %ansicolors } ); + } until defined $color; + $color = join(' ', unique(grep { exists $ansicolors{$_} } split(/\W+/, $color))); + return $idx unless $color; + + push @{$tbl_meta{$tbl}->{colors}}, { + col => $col, + op => $op, + arg => $arg, + color => $color + }; + $tbl_meta{$tbl}->{cust}->{colors} = 1; + + return $idx; + }, + }, + d => { + note => 'Remove the selected rule', + func => sub { + my ( $tbl, $idx ) = @_; + my @rules = @{ $tbl_meta{$tbl}->{colors} }; + return 0 unless @rules > 0 && $idx < @rules && $idx >= 0; + splice(@{$tbl_meta{$tbl}->{colors}}, $idx, 1); + $tbl_meta{$tbl}->{cust}->{colors} = 1; + return $idx == @rules ? $#rules : $idx; + }, + }, + j => { + note => 'Move highlight down one', + func => sub { + my ( $tbl, $idx ) = @_; + my $num_rules = scalar @{$tbl_meta{$tbl}->{colors}}; + return ($idx + 1) % $num_rules; + }, + }, + k => { + note => 'Move highlight up one', + func => sub { + my ( $tbl, $idx ) = @_; + my $num_rules = scalar @{$tbl_meta{$tbl}->{colors}}; + return ($idx - 1) % $num_rules; + }, + }, + '+' => { + note => 'Move selected rule up one', + func => sub { + my ( $tbl, $idx ) = @_; + my $meta = $tbl_meta{$tbl}; + my $dest = $idx == 0 ? scalar(@{$meta->{colors}} - 1) : $idx - 1; + my $temp = $meta->{colors}->[$idx]; + $meta->{colors}->[$idx] = $meta->{colors}->[$dest]; + $meta->{colors}->[$dest] = $temp; + $meta->{cust}->{colors} = 1; + return $dest; + }, + }, + '-' => { + note => 'Move selected rule down one', + func => sub { + my ( $tbl, $idx ) = @_; + my $meta = $tbl_meta{$tbl}; + my $dest = $idx == scalar(@{$meta->{colors}} - 1) ? 0 : $idx + 1; + my $temp = $meta->{colors}->[$idx]; + $meta->{colors}->[$idx] = $meta->{colors}->[$dest]; + $meta->{colors}->[$dest] = $temp; + $meta->{cust}->{colors} = 1; + return $dest; + }, + }, +); + +# ########################################################################### +# Plugin editor key mappings {{{3 +# ########################################################################### +my %plugin_editor_action = ( + '*' => { + note => 'Toggle selected plugin active/inactive', + func => sub { + my ( $plugins, $idx ) = @_; + my $plugin = $plugins->[$idx]; + $plugin->{active} = $plugin->{active} ? 0 : 1; + return $idx; + }, + }, + j => { + note => 'Move highlight down one', + func => sub { + my ( $plugins, $idx ) = @_; + return ($idx + 1) % scalar(@$plugins); + }, + }, + k => { + note => 'Move highlight up one', + func => sub { + my ( $plugins, $idx ) = @_; + return $idx == 0 ? @$plugins - 1 : $idx - 1; + }, + }, +); + +# ########################################################################### +# Table editor key mappings {{{3 +# ########################################################################### +my %tbl_editor_action = ( + a => { + note => 'Add a column to the table', + func => sub { + my ( $tbl, $col ) = @_; + my @visible_cols = @{ $tbl_meta{$tbl}->{visible} }; + my %all_cols = %{ $tbl_meta{$tbl}->{cols} }; + delete @all_cols{@visible_cols}; + my $choice = prompt_list( + 'Choose a column', + '', + sub { return keys %all_cols; }, + { map { $_ => $all_cols{$_}->{label} || $all_cols{$_}->{hdr} } keys %all_cols }); + if ( $all_cols{$choice} ) { + push @{$tbl_meta{$tbl}->{visible}}, $choice; + $tbl_meta{$tbl}->{cust}->{visible} = 1; + return $choice; + } + return $col; + }, + }, + n => { + note => 'Create a new column and add it to the table', + func => sub { + my ( $tbl, $col ) = @_; + + $clear_screen_sub->(); + print word_wrap("Choose a name for the column. This name is not displayed, and is used only " + . "for internal reference. It can contain only lowercase letters, numbers, " + . "and underscores."); + print "\n\n"; + do { + $col = prompt("Enter column name"); + $col = '' if $col =~ m/[^a-z0-9_]/; + } while ( !$col ); + + $clear_screen_sub->(); + my $hdr; + do { + $hdr = prompt("Enter column header"); + } while ( !$hdr ); + + $clear_screen_sub->(); + print "Choose a source for the column's data\n\n"; + my ( $src, $sub, $err ); + do { + if ( $err ) { + print "Error: $err\n\n"; + } + $src = prompt("Enter column source"); + if ( $src ) { + ( $sub, $err ) = compile_expr($src); + } + } until ( !$err); + + # TODO: this duplicates %col_props. + $tbl_meta{$tbl}->{cols}->{$col} = { + hdr => $hdr, + src => $src, + just => '-', + num => 0, + label => 'User-defined', + user => 1, + tbl => $tbl, + minw => 0, + maxw => 0, + trans => [], + func => $sub, + dec => 0, + agg => 0, + aggonly => 0, + }; + + $tbl_meta{$tbl}->{visible} = [ unique(@{$tbl_meta{$tbl}->{visible}}, $col) ]; + $tbl_meta{$tbl}->{cust}->{visible} = 1; + return $col; + }, + }, + d => { + note => 'Remove selected column', + func => sub { + my ( $tbl, $col ) = @_; + my @visible_cols = @{ $tbl_meta{$tbl}->{visible} }; + my $idx = 0; + return $col unless @visible_cols > 1; + while ( $visible_cols[$idx] ne $col ) { + $idx++; + } + $tbl_meta{$tbl}->{visible} = [ grep { $_ ne $col } @visible_cols ]; + $tbl_meta{$tbl}->{cust}->{visible} = 1; + return $idx == $#visible_cols ? $visible_cols[$idx - 1] : $visible_cols[$idx + 1]; + }, + }, + e => { + note => 'Edit selected column', + func => sub { + # TODO: make this editor hotkey-driven and give readline support. + my ( $tbl, $col ) = @_; + $clear_screen_sub->(); + my $meta = $tbl_meta{$tbl}->{cols}->{$col}; + my @prop = qw(hdr label src just num minw maxw trans agg); # TODO redundant + + my $answer; + do { + # Do what the user asked... + if ( $answer && grep { $_ eq $answer } @prop ) { + # Some properties are arrays, others scalars. + my $ini = ref $col_props{$answer} ? join(' ', @{$meta->{$answer}}) : $meta->{$answer}; + my $val = prompt("New value for $answer", undef, $ini); + $val = [ split(' ', $val) ] if ref($col_props{$answer}); + if ( $answer eq 'trans' ) { + $val = [ unique(grep{ exists $trans_funcs{$_} } @$val) ]; + } + @{$meta}{$answer, 'user', 'tbl' } = ( $val, 1, $tbl ); + } + + my @display_lines = ( + '', + "You are editing column $tbl.$col.\n", + ); + + push @display_lines, create_table2( + \@prop, + { map { $_ => $_ } @prop }, + { map { $_ => ref $meta->{$_} eq 'ARRAY' ? join(' ', @{$meta->{$_}}) + : ref $meta->{$_} ? '[expression code]' + : $meta->{$_} + } @prop + }, + { sep => ' ' }); + draw_screen(\@display_lines, { raw => 1 }); + print "\n\n"; # One to add space, one to clear readline artifacts + $answer = prompt('Edit what? (q to quit)'); + } while ( $answer ne 'q' ); + + return $col; + }, + }, + j => { + note => 'Move highlight down one', + func => sub { + my ( $tbl, $col ) = @_; + my @visible_cols = @{ $tbl_meta{$tbl}->{visible} }; + my $idx = 0; + while ( $visible_cols[$idx] ne $col ) { + $idx++; + } + return $visible_cols[ ($idx + 1) % @visible_cols ]; + }, + }, + k => { + note => 'Move highlight up one', + func => sub { + my ( $tbl, $col ) = @_; + my @visible_cols = @{ $tbl_meta{$tbl}->{visible} }; + my $idx = 0; + while ( $visible_cols[$idx] ne $col ) { + $idx++; + } + return $visible_cols[ $idx - 1 ]; + }, + }, + '+' => { + note => 'Move selected column up one', + func => sub { + my ( $tbl, $col ) = @_; + my $meta = $tbl_meta{$tbl}; + my @visible_cols = @{$meta->{visible}}; + my $idx = 0; + while ( $visible_cols[$idx] ne $col ) { + $idx++; + } + if ( $idx ) { + $visible_cols[$idx] = $visible_cols[$idx - 1]; + $visible_cols[$idx - 1] = $col; + $meta->{visible} = \@visible_cols; + } + else { + shift @{$meta->{visible}}; + push @{$meta->{visible}}, $col; + } + $meta->{cust}->{visible} = 1; + return $col; + }, + }, + '-' => { + note => 'Move selected column down one', + func => sub { + my ( $tbl, $col ) = @_; + my $meta = $tbl_meta{$tbl}; + my @visible_cols = @{$meta->{visible}}; + my $idx = 0; + while ( $visible_cols[$idx] ne $col ) { + $idx++; + } + if ( $idx == $#visible_cols ) { + unshift @{$meta->{visible}}, $col; + pop @{$meta->{visible}}; + } + else { + $visible_cols[$idx] = $visible_cols[$idx + 1]; + $visible_cols[$idx + 1] = $col; + $meta->{visible} = \@visible_cols; + } + $meta->{cust}->{visible} = 1; + return $col; + }, + }, + f => { + note => 'Choose filters', + func => sub { + my ( $tbl, $col ) = @_; + choose_filters($tbl); + return $col; + }, + }, + o => { + note => 'Edit color rules', + func => sub { + my ( $tbl, $col ) = @_; + edit_color_rules($tbl); + return $col; + }, + }, + s => { + note => 'Choose sort columns', + func => sub { + my ( $tbl, $col ) = @_; + choose_sort_cols($tbl); + return $col; + }, + }, + g => { + note => 'Choose group-by (aggregate) columns', + func => sub { + my ( $tbl, $col ) = @_; + choose_group_cols($tbl); + return $col; + }, + }, +); + +# ########################################################################### +# Global variables and environment {{{2 +# ########################################################################### + +my @this_term_size; # w_chars, h_chars, w_pix, h_pix +my @last_term_size; # w_chars, h_chars, w_pix, h_pix +my $char; +my $windows = $OSNAME =~ m/MSWin/; +my $have_color = 0; +my $MAX_ULONG = 4294967295; # 2^32-1 +my $num_regex = qr/^[+-]?(?=\d|\.)\d*(?:\.\d+)?(?:E[+-]?\d+|)$/i; +my $int_regex = qr/^\d+$/; +my $bool_regex = qr/^[01]$/; +my $term = undef; +my $file = undef; # File to watch for InnoDB monitor output +my $file_mtime = undef; # Status of watched file +my $file_data = undef; # Last chunk of text read from file +my $innodb_parser = InnoDBParser->new; + +my $nonfatal_errs = join('|', + 'Access denied for user', + 'Unknown MySQL server host', + 'Unknown database', + 'Can\'t connect to local MySQL server through socket', + 'Can\'t connect to MySQL server on', + 'MySQL server has gone away', + 'Cannot call SHOW INNODB STATUS', + 'Access denied', + 'AutoCommit', +); + +if ( !$opts{n} ) { + require Term::ReadLine; + $term = Term::ReadLine->new('innotop'); +} + +# Stores status, variables, innodb status, master/slave status etc. +# Keyed on connection name. Each entry is a hashref of current and past data sets, +# keyed on clock tick. +my %vars; +my %info_gotten = (); # Which things have been retrieved for the current clock tick. + +# Stores info on currently displayed queries: cxn, connection ID, query text. +my @current_queries; + +my $lines_printed = 0; +my $clock = 0; # Incremented with every wake-sleep cycle +my $clearing_deadlocks = 0; + +# If terminal coloring is available, use it. The only function I want from +# the module is the colored() function. +eval { + if ( !$opts{n} ) { + if ( $windows ) { + require Win32::Console::ANSI; + } + require Term::ANSIColor; + import Term::ANSIColor qw(colored); + $have_color = 1; + } +}; +if ( $EVAL_ERROR || $opts{n} ) { + # If there was an error, manufacture my own colored() function that does no + # coloring. + *colored = sub { pop @_; @_; }; +} + +if ( $opts{n} ) { + $clear_screen_sub = sub {}; +} +elsif ( $windows ) { + $clear_screen_sub = sub { $lines_printed = 0; system("cls") }; +} +else { + my $clear = `clear`; + $clear_screen_sub = sub { $lines_printed = 0; print $clear }; +} + +# ########################################################################### +# Config storage. {{{2 +# ########################################################################### +my %config = ( + color => { + val => $have_color, + note => 'Whether to use terminal coloring', + conf => 'ALL', + pat => $bool_regex, + }, + cmd_filter => { + val => 'Com_', + note => 'Prefix for values in C mode', + conf => [qw(C)], + }, + plugin_dir => { + val => "$homepath/.innotop/plugins", + note => 'Directory where plugins can be found', + conf => 'ALL', + }, + show_percent => { + val => 1, + note => 'Show the % symbol after percentages', + conf => 'ALL', + pat => $bool_regex, + }, + skip_innodb => { + val => 0, + note => 'Disable SHOW INNODB STATUS', + conf => 'ALL', + pat => $bool_regex, + }, + S_func => { + val => 's', + note => 'What to display in S mode: graph, status, pivoted status', + conf => [qw(S)], + pat => qr/^[gsv]$/, + }, + cxn_timeout => { + val => 28800, + note => 'Connection timeout for keeping unused connections alive', + conf => 'ALL', + pat => $int_regex, + }, + graph_char => { + val => '*', + note => 'Character for drawing graphs', + conf => [ qw(S) ], + pat => qr/^.$/, + }, + show_cxn_errors_in_tbl => { + val => 1, + note => 'Whether to display connection errors as rows in the table', + conf => 'ALL', + pat => $bool_regex, + }, + hide_hdr => { + val => 0, + note => 'Whether to show column headers', + conf => 'ALL', + pat => $bool_regex, + }, + show_cxn_errors => { + val => 1, + note => 'Whether to print connection errors to STDOUT', + conf => 'ALL', + pat => $bool_regex, + }, + readonly => { + val => 1, + note => 'Whether the config file is read-only', + conf => [ qw() ], + pat => $bool_regex, + }, + global => { + val => 1, + note => 'Whether to show GLOBAL variables and status', + conf => 'ALL', + pat => $bool_regex, + }, + header_highlight => { + val => 'bold', + note => 'How to highlight table column headers', + conf => 'ALL', + pat => qr/^(?:bold|underline)$/, + }, + display_table_captions => { + val => 1, + note => 'Whether to put captions on tables', + conf => 'ALL', + pat => $bool_regex, + }, + charset => { + val => 'ascii', + note => 'What type of characters should be displayed in queries (ascii, unicode, none)', + conf => 'ALL', + pat => qr/^(?:ascii|unicode|none)$/, + }, + auto_wipe_dl => { + val => 0, + note => 'Whether to auto-wipe InnoDB deadlocks', + conf => 'ALL', + pat => $bool_regex, + }, + max_height => { + val => 30, + note => '[Win32] Max window height', + conf => 'ALL', + }, + debug => { + val => 0, + pat => $bool_regex, + note => 'Debug mode (more verbose errors, uses more memory)', + conf => 'ALL', + }, + num_digits => { + val => 2, + pat => $int_regex, + note => 'How many digits to show in fractional numbers and percents', + conf => 'ALL', + }, + debugfile => { + val => "$homepath/.innotop/core_dump", + note => 'A debug file in case you are interested in error output', + }, + show_statusbar => { + val => 1, + pat => $bool_regex, + note => 'Whether to show the status bar in the display', + conf => 'ALL', + }, + mode => { + val => "Q", + note => "Which mode to start in", + cmdline => 1, + }, + status_inc => { + val => 0, + note => 'Whether to show raw or incremental values for status variables', + pat => $bool_regex, + }, + interval => { + val => 10, + pat => qr/^(?:(?:\d*?[1-9]\d*(?:\.\d*)?)|(?:\d*\.\d*?[1-9]\d*))$/, + note => "The interval at which the display will be refreshed. Fractional values allowed.", + }, + num_status_sets => { + val => 9, + pat => $int_regex, + note => 'How many sets of STATUS and VARIABLES values to show', + conf => [ qw(S) ], + }, + S_set => { + val => 'general', + pat => qr/^\w+$/, + note => 'Which set of variables to display in S (Variables & Status) mode', + conf => [ qw(S) ], + }, +); + +# ########################################################################### +# Config file sections {{{2 +# The configuration file is broken up into sections like a .ini file. This +# variable defines those sections and the subroutines responsible for reading +# and writing them. +# ########################################################################### +my %config_file_sections = ( + plugins => { + reader => \&load_config_plugins, + writer => \&save_config_plugins, + }, + group_by => { + reader => \&load_config_group_by, + writer => \&save_config_group_by, + }, + filters => { + reader => \&load_config_filters, + writer => \&save_config_filters, + }, + active_filters => { + reader => \&load_config_active_filters, + writer => \&save_config_active_filters, + }, + visible_tables => { + reader => \&load_config_visible_tables, + writer => \&save_config_visible_tables, + }, + sort_cols => { + reader => \&load_config_sort_cols, + writer => \&save_config_sort_cols, + }, + active_columns => { + reader => \&load_config_active_columns, + writer => \&save_config_active_columns, + }, + tbl_meta => { + reader => \&load_config_tbl_meta, + writer => \&save_config_tbl_meta, + }, + general => { + reader => \&load_config_config, + writer => \&save_config_config, + }, + connections => { + reader => \&load_config_connections, + writer => \&save_config_connections, + }, + active_connections => { + reader => \&load_config_active_connections, + writer => \&save_config_active_connections, + }, + server_groups => { + reader => \&load_config_server_groups, + writer => \&save_config_server_groups, + }, + active_server_groups => { + reader => \&load_config_active_server_groups, + writer => \&save_config_active_server_groups, + }, + max_values_seen => { + reader => \&load_config_mvs, + writer => \&save_config_mvs, + }, + varsets => { + reader => \&load_config_varsets, + writer => \&save_config_varsets, + }, + colors => { + reader => \&load_config_colors, + writer => \&save_config_colors, + }, + stmt_sleep_times => { + reader => \&load_config_stmt_sleep_times, + writer => \&save_config_stmt_sleep_times, + }, +); + +# Config file sections have some dependencies, so they have to be read/written in order. +my @ordered_config_file_sections = qw(general plugins filters active_filters tbl_meta + connections active_connections server_groups active_server_groups max_values_seen + active_columns sort_cols visible_tables varsets colors stmt_sleep_times + group_by); + +# All events for which plugins may register themselves. Entries are arrayrefs. +my %event_listener_for = map { $_ => [] } + qw( + extract_values + set_to_tbl_pre_filter set_to_tbl_pre_sort set_to_tbl_pre_group + set_to_tbl_pre_colorize set_to_tbl_pre_transform set_to_tbl_pre_pivot + set_to_tbl_pre_create set_to_tbl_post_create + draw_screen + ); + +# All variables to which plugins have access. +my %pluggable_vars = ( + action_for => \%action_for, + agg_funcs => \%agg_funcs, + config => \%config, + connections => \%connections, + dbhs => \%dbhs, + filters => \%filters, + modes => \%modes, + server_groups => \%server_groups, + tbl_meta => \%tbl_meta, + trans_funcs => \%trans_funcs, + var_sets => \%var_sets, +); + +# ########################################################################### +# Contains logic to generate prepared statements for a given function for a +# given DB connection. Returns a $sth. +# ########################################################################### +my %stmt_maker_for = ( + INNODB_STATUS => sub { + my ( $dbh ) = @_; + return $dbh->prepare(version_ge( $dbh, '5.0.0' ) + ? 'SHOW ENGINE INNODB STATUS' + : 'SHOW INNODB STATUS'); + }, + SHOW_VARIABLES => sub { + my ( $dbh ) = @_; + return $dbh->prepare($config{global}->{val} && version_ge( $dbh, '4.0.3' ) + ? 'SHOW GLOBAL VARIABLES' + : 'SHOW VARIABLES'); + }, + SHOW_STATUS => sub { + my ( $dbh ) = @_; + return $dbh->prepare($config{global}->{val} && version_ge( $dbh, '5.0.2' ) + ? 'SHOW GLOBAL STATUS' + : 'SHOW STATUS'); + }, + KILL_QUERY => sub { + my ( $dbh ) = @_; + return $dbh->prepare(version_ge( $dbh, '5.0.0' ) + ? 'KILL QUERY ?' + : 'KILL ?'); + }, + SHOW_MASTER_LOGS => sub { + my ( $dbh ) = @_; + return $dbh->prepare('SHOW MASTER LOGS'); + }, + SHOW_MASTER_STATUS => sub { + my ( $dbh ) = @_; + return $dbh->prepare('SHOW MASTER STATUS'); + }, + SHOW_SLAVE_STATUS => sub { + my ( $dbh ) = @_; + return $dbh->prepare('SHOW SLAVE STATUS'); + }, + KILL_CONNECTION => sub { + my ( $dbh ) = @_; + return $dbh->prepare(version_ge( $dbh, '5.0.0' ) + ? 'KILL CONNECTION ?' + : 'KILL ?'); + }, + OPEN_TABLES => sub { + my ( $dbh ) = @_; + return version_ge($dbh, '4.0.0') + ? $dbh->prepare('SHOW OPEN TABLES') + : undef; + }, + PROCESSLIST => sub { + my ( $dbh ) = @_; + return $dbh->prepare('SHOW FULL PROCESSLIST'); + }, +); + +# Plugins! +my %plugins = ( +); + +# ########################################################################### +# Run the program {{{1 +# ########################################################################### + +# This config variable is only useful for MS Windows because its terminal +# can't tell how tall it is. +if ( !$windows ) { + delete $config{max_height}; +} + +# Try to lower my priority. +eval { setpriority(0, 0, getpriority(0, 0) + 10); }; + +# Print stuff to the screen immediately, don't wait for a newline. +$OUTPUT_AUTOFLUSH = 1; + +# Clear the screen and load the configuration. +$clear_screen_sub->(); +load_config(); + +# Override config variables with command-line options +my %cmdline = + map { $_->{c} => $opts{$_->{k}} } + grep { exists $_->{c} && exists $opts{$_->{k}} } + @opt_spec; + +foreach my $name (keys %cmdline) { + next if not defined $cmdline{$name}; + my $val = $cmdline{$name}; + if ( exists($config{$name}) and (!$config{$name}->{pat} or $val =~ m/$config{$name}->{pat}/ )) { + $config{$name}->{val} = $val; + } +} + +post_process_tbl_meta(); + +# Make sure no changes are written to config file in non-interactive mode. +if ( $opts{n} ) { + $config{readonly}->{val} = 1; +} + +eval { + + # Open the file for InnoDB status + if ( @ARGV ) { + my $filename = shift @ARGV; + open $file, "<", $filename + or die "Cannot open '$filename': $OS_ERROR"; + } + + # In certain modes we might have to collect data for two cycles + # before printing anything out, so we need to bump up the count one. + if ( $opts{n} && $opts{count} && $config{status_inc}->{val} + && $config{mode}->{val} =~ m/[S]/ ) + { + $opts{count}++; + } + + while (++$clock) { + + my $mode = $config{mode}->{val} || 'Q'; + if ( !$modes{$mode} ) { + die "Mode '$mode' doesn't exist; try one of these:\n" + . join("\n", map { " $_ $modes{$_}->{hdr}" } sort keys %modes) + . "\n"; + } + + if ( !$opts{n} ) { + @last_term_size = @this_term_size; + @this_term_size = Term::ReadKey::GetTerminalSize(\*STDOUT); + if ( $windows ) { + $this_term_size[0]--; + $this_term_size[1] + = min($this_term_size[1], $config{max_height}->{val}); + } + die("Can't read terminal size") unless @this_term_size; + } + + # If there's no connection to a database server, we need to fix that... + if ( !%connections ) { + print "You have not defined any database connections.\n\n"; + add_new_dsn(); + } + + # See whether there are any connections defined for this mode. If there's only one + # connection total, assume the user wants to just use innotop for a single server + # and don't ask which server to connect to. Also, if we're monitoring from a file, + # we just use the first connection. + if ( !get_connections() ) { + if ( $file || 1 == scalar keys %connections ) { + $modes{$config{mode}->{val}}->{connections} = [ keys %connections ]; + } + else { + choose_connections(); + } + } + + # Term::ReadLine might have re-set $OUTPUT_AUTOFLUSH. + $OUTPUT_AUTOFLUSH = 1; + + # Prune old data + my $sets = $config{num_status_sets}->{val}; + foreach my $store ( values %vars ) { + delete @{$store}{ grep { $_ < $clock - $sets } keys %$store }; + } + %info_gotten = (); + + # Call the subroutine to display this mode. + $modes{$mode}->{display_sub}->(); + + # It may be time to quit now. + if ( $opts{count} && $clock >= $opts{count} ) { + finish(); + } + + # Wait for a bit. + if ( $opts{n} ) { + sleep($config{interval}->{val}); + } + else { + ReadMode('cbreak'); + $char = ReadKey($config{interval}->{val}); + ReadMode('normal'); + } + + # Handle whatever action the key indicates. + do_key_action(); + + } +}; +if ( $EVAL_ERROR ) { + core_dump( $EVAL_ERROR ); +} +finish(); + +# Subroutines {{{1 +# Mode functions{{{2 +# switch_mode {{{3 +sub switch_mode { + my $mode = shift; + $config{mode}->{val} = $mode; +} + +# Prompting functions {{{2 +# prompt_list {{{3 +# Prompts the user for a value, given a question, initial value, +# a completion function and a hashref of hints. +sub prompt_list { + die "Can't call in non-interactive mode" if $opts{n}; + my ( $question, $init, $completion, $hints ) = @_; + if ( $hints ) { + # Figure out how wide the table will be + my $max_name = max(map { length($_) } keys %$hints ); + $max_name ||= 0; + $max_name += 3; + my @meta_rows = create_table2( + [ sort keys %$hints ], + { map { $_ => $_ } keys %$hints }, + { map { $_ => trunc($hints->{$_}, $this_term_size[0] - $max_name) } keys %$hints }, + { sep => ' ' }); + if (@meta_rows > 10) { + # Try to split and stack the meta rows next to each other + my $split = int(@meta_rows / 2); + @meta_rows = stack_next( + [@meta_rows[0..$split - 1]], + [@meta_rows[$split..$#meta_rows]], + { pad => ' | '}, + ); + } + print join( "\n", + '', + map { ref $_ ? colored(@$_) : $_ } create_caption('Choose from', @meta_rows), ''), + "\n"; + } + $term->Attribs->{completion_function} = $completion; + my $answer = $term->readline("$question: ", $init); + $OUTPUT_AUTOFLUSH = 1; + $answer = '' if !defined($answer); + $answer =~ s/\s+$//; + return $answer; +} + +# prompt {{{3 +# Prints out a prompt and reads from the keyboard, then validates with the +# validation regex until the input is correct. +sub prompt { + die "Can't call in non-interactive mode" if $opts{n}; + my ( $prompt, $regex, $init, $completion ) = @_; + my $response; + my $success = 0; + do { + if ( $completion ) { + $term->Attribs->{completion_function} = $completion; + } + $response = $term->readline("$prompt: ", $init); + if ( $regex && $response !~ m/$regex/ ) { + print "Invalid response.\n\n"; + } + else { + $success = 1; + } + } while ( !$success ); + $OUTPUT_AUTOFLUSH = 1; + $response =~ s/\s+$//; + return $response; +} + +# prompt_noecho {{{3 +# Unfortunately, suppressing echo with Term::ReadLine isn't reliable; the user might not +# have that library, or it might not support that feature. +sub prompt_noecho { + my ( $prompt ) = @_; + print colored("$prompt: ", 'underline'); + my $response; + ReadMode('noecho'); + $response = ; + chomp($response); + ReadMode('normal'); + return $response; +} + +# do_key_action {{{3 +# Depending on whether a key was read, do something. Keys have certain +# actions defined in lookup tables. Each mode may have its own lookup table, +# which trumps the global table -- so keys can be context-sensitive. The key +# may be read and written in a subroutine, so it's a global. +sub do_key_action { + if ( defined $char ) { + my $mode = $config{mode}->{val}; + my $action + = defined($modes{$mode}->{action_for}->{$char}) + ? $modes{$mode}->{action_for}->{$char}->{action} + : defined($action_for{$char}) + ? $action_for{$char}->{action} + : sub{}; + $action->(); + } +} + +# pause {{{3 +sub pause { + die "Can't call in non-interactive mode" if $opts{n}; + my $msg = shift; + print defined($msg) ? "\n$msg" : "\nPress any key to continue"; + ReadMode('cbreak'); + my $char = ReadKey(0); + ReadMode('normal'); + return $char; +} + +# reverse_sort {{{3 +sub reverse_sort { + my $tbl = shift; + $tbl_meta{$tbl}->{sort_dir} *= -1; +} + +# select_cxn {{{3 +# Selects connection(s). If the mode (or argument list) has only one, returns +# it without prompt. +sub select_cxn { + my ( $prompt, @cxns ) = @_; + if ( !@cxns ) { + @cxns = get_connections(); + } + if ( @cxns == 1 ) { + return $cxns[0]; + } + my $choices = prompt_list( + $prompt, + $cxns[0], + sub{ return @cxns }, + { map { $_ => $connections{$_}->{dsn} } @cxns }); + my @result = unique(grep { my $a = $_; grep { $_ eq $a } @cxns } split(/\s+/, $choices)); + return @result; +} + +# kill_query {{{3 +# Kills a connection, or on new versions, optionally a query but not connection. +sub kill_query { + my ( $q_or_c ) = @_; + + my $info = choose_thread( + sub { 1 }, + 'Select a thread to kill the ' . $q_or_c, + ); + return unless $info; + return unless pause("Kill $info->{id}?") =~ m/y/i; + + eval { + do_stmt($info->{cxn}, $q_or_c eq 'QUERY' ? 'KILL_QUERY' : 'KILL_CONNECTION', $info->{id} ); + }; + + if ( $EVAL_ERROR ) { + print "\nError: $EVAL_ERROR"; + pause(); + } +} + +# set_display_precision {{{3 +sub set_display_precision { + my $dir = shift; + $config{num_digits}->{val} = min(9, max(0, $config{num_digits}->{val} + $dir)); +} + +sub toggle_visible_table { + my ( $mode, $table ) = @_; + my $visible = $modes{$mode}->{visible_tables}; + if ( grep { $_ eq $table } @$visible ) { + $modes{$mode}->{visible_tables} = [ grep { $_ ne $table } @$visible ]; + } + else { + unshift @$visible, $table; + } + $modes{$mode}->{cust}->{visible_tables} = 1; +} + +# toggle_filter{{{3 +sub toggle_filter { + my ( $tbl, $filter ) = @_; + my $filters = $tbl_meta{$tbl}->{filters}; + if ( grep { $_ eq $filter } @$filters ) { + $tbl_meta{$tbl}->{filters} = [ grep { $_ ne $filter } @$filters ]; + } + else { + push @$filters, $filter; + } + $tbl_meta{$tbl}->{cust}->{filters} = 1; +} + +# toggle_config {{{3 +sub toggle_config { + my ( $key ) = @_; + $config{$key}->{val} ^= 1; +} + +# create_deadlock {{{3 +sub create_deadlock { + $clear_screen_sub->(); + + print "This function will deliberately cause a small deadlock, " + . "clearing deadlock information from the InnoDB monitor.\n\n"; + + my $answer = prompt("Are you sure you want to proceed? Say 'y' if you do"); + return 0 unless $answer eq 'y'; + + my ( $cxn ) = select_cxn('Clear on which server? '); + return unless $cxn && exists($connections{$cxn}); + + clear_deadlock($cxn); +} + +# deadlock_thread {{{3 +sub deadlock_thread { + my ( $id, $tbl, $cxn ) = @_; + + eval { + my $dbh = get_new_db_connection($cxn, 1); + my @stmts = ( + "set transaction isolation level serializable", + (version_ge($dbh, '4.0.11') ? "start transaction" : 'begin'), + "select * from $tbl where a = $id", + "update $tbl set a = $id where a <> $id", + ); + + foreach my $stmt (@stmts[0..2]) { + $dbh->do($stmt); + } + sleep(1 + $id); + $dbh->do($stmts[-1]); + }; + if ( $EVAL_ERROR ) { + if ( $EVAL_ERROR !~ m/Deadlock found/ ) { + die $EVAL_ERROR; + } + } + exit(0); +} + +# Purges unused binlogs on the master, up to but not including the latest log. +# TODO: guess which connections are slaves of a given master. +sub purge_master_logs { + my @cxns = get_connections(); + + get_master_slave_status(@cxns); + + # Toss out the rows that don't have master/slave status... + my @vars = + grep { $_ && ($_->{file} || $_->{master_host}) } + map { $vars{$_}->{$clock} } @cxns; + @cxns = map { $_->{cxn} } @vars; + + # Figure out which master to purge ons. + my @masters = map { $_->{cxn} } grep { $_->{file} } @vars; + my ( $master ) = select_cxn('Which master?', @masters ); + return unless $master; + my ($master_status) = grep { $_->{cxn} eq $master } @vars; + + # Figure out the result order (not lexical order) of master logs. + my @master_logs = get_master_logs($master); + my $i = 0; + my %master_logs = map { $_->{log_name} => $i++ } @master_logs; + + # Ask which slave(s) are reading from this master. + my @slave_status = grep { $_->{master_host} } @vars; + my @slaves = map { $_->{cxn} } @slave_status; + @slaves = select_cxn("Which slaves are reading from $master?", @slaves); + @slave_status = grep { my $item = $_; grep { $item->{cxn} eq $_ } @slaves } @slave_status; + return unless @slave_status; + + # Find the minimum binary log in use. + my $min_log = min(map { $master_logs{$_->{master_log_file}} } @slave_status); + my $log_name = $master_logs[$min_log]->{log_name}; + + my $stmt = "PURGE MASTER LOGS TO '$log_name'"; + send_cmd_to_servers($stmt, 0, 'PURGE {MASTER | BINARY} LOGS {TO "log_name" | BEFORE "date"}', [$master]); +} + +sub send_cmd_to_servers { + my ( $cmd, $all, $hint, $cxns ) = @_; + if ( $all ) { + @$cxns = get_connections(); + } + elsif ( !@$cxns ) { + @$cxns = select_cxn('Which servers?', @$cxns); + } + if ( $hint ) { + print "\nHint: $hint\n"; + } + $cmd = prompt('Command to send', undef, $cmd); + foreach my $cxn ( @$cxns ) { + eval { + my $sth = do_query($cxn, $cmd); + }; + if ( $EVAL_ERROR ) { + print "Error from $cxn: $EVAL_ERROR\n"; + } + else { + print "Success on $cxn\n"; + } + } + pause(); +} + +# Display functions {{{2 + +sub set_s_mode { + my ( $func ) = @_; + $clear_screen_sub->(); + $config{S_func}->{val} = $func; +} + +# start_S_mode {{{3 +sub start_S_mode { + $clear_screen_sub->(); + switch_mode('S'); +} + +# display_B {{{3 +sub display_B { + my @display_lines; + my @cxns = get_connections(); + get_innodb_status(\@cxns); + + my @buffer_pool; + my @page_statistics; + my @insert_buffers; + my @adaptive_hash_index; + my %rows_for = ( + buffer_pool => \@buffer_pool, + page_statistics => \@page_statistics, + insert_buffers => \@insert_buffers, + adaptive_hash_index => \@adaptive_hash_index, + ); + + my @visible = get_visible_tables(); + my %wanted = map { $_ => 1 } @visible; + + foreach my $cxn ( @cxns ) { + my $set = $vars{$cxn}->{$clock}; + my $pre = $vars{$cxn}->{$clock-1} || $set; + + if ( $set->{IB_bp_complete} ) { + if ( $wanted{buffer_pool} ) { + push @buffer_pool, extract_values($set, $set, $pre, 'buffer_pool'); + } + if ( $wanted{page_statistics} ) { + push @page_statistics, extract_values($set, $set, $pre, 'page_statistics'); + } + } + if ( $set->{IB_ib_complete} ) { + if ( $wanted{insert_buffers} ) { + push @insert_buffers, extract_values( + $config{status_inc}->{val} ? inc(0, $cxn) : $set, $set, $pre, + 'insert_buffers'); + } + if ( $wanted{adaptive_hash_index} ) { + push @adaptive_hash_index, extract_values($set, $set, $pre, 'adaptive_hash_index'); + } + } + } + + my $first_table = 0; + foreach my $tbl ( @visible ) { + push @display_lines, '', set_to_tbl($rows_for{$tbl}, $tbl); + push @display_lines, get_cxn_errors(@cxns) + if ( $config{debug}->{val} || !$first_table++ ); + } + + draw_screen(\@display_lines); +} + +# display_C {{{3 +sub display_C { + my @display_lines; + my @cxns = get_connections(); + get_status_info(@cxns); + + my @cmd_summary; + my %rows_for = ( + cmd_summary => \@cmd_summary, + ); + + my @visible = get_visible_tables(); + my %wanted = map { $_ => 1 } @visible; + + # For now, I'm manually pulling these variables out and pivoting. Eventually a SQL-ish + # dialect should let me join a table to a grouped and pivoted table and do this more easily. + # TODO: make it so. + my $prefix = qr/^$config{cmd_filter}->{val}/; # TODO: this is a total hack + my @values; + my ($total, $last_total) = (0, 0); + foreach my $cxn ( @cxns ) { + my $set = $vars{$cxn}->{$clock}; + my $pre = $vars{$cxn}->{$clock-1} || $set; + foreach my $key ( keys %$set ) { + next unless $key =~ m/$prefix/i; + my $val = $set->{$key}; + next unless defined $val && $val =~ m/^\d+$/; + my $last_val = $val - ($pre->{$key} || 0); + $total += $val; + $last_total += $last_val; + push @values, { + name => $key, + value => $val, + last_value => $last_val, + }; + } + } + + # Add aggregation and turn into a real set TODO: total hack + if ( $wanted{cmd_summary} ) { + foreach my $value ( @values ) { + @{$value}{qw(total last_total)} = ($total, $last_total); + push @cmd_summary, extract_values($value, $value, $value, 'cmd_summary'); + } + } + + my $first_table = 0; + foreach my $tbl ( @visible ) { + push @display_lines, '', set_to_tbl($rows_for{$tbl}, $tbl); + push @display_lines, get_cxn_errors(@cxns) + if ( $config{debug}->{val} || !$first_table++ ); + } + + draw_screen(\@display_lines); +} + +# display_D {{{3 +sub display_D { + my @display_lines; + my @cxns = get_connections(); + get_innodb_status(\@cxns); + + my @deadlock_transactions; + my @deadlock_locks; + my %rows_for = ( + deadlock_transactions => \@deadlock_transactions, + deadlock_locks => \@deadlock_locks, + ); + + my @visible = get_visible_tables(); + my %wanted = map { $_ => 1 } @visible; + + foreach my $cxn ( @cxns ) { + my $innodb_status = $vars{$cxn}->{$clock}; + my $prev_status = $vars{$cxn}->{$clock-1} || $innodb_status; + + if ( $innodb_status->{IB_dl_timestring} ) { + + my $victim = $innodb_status->{IB_dl_rolled_back} || 0; + + if ( %wanted ) { + foreach my $txn_id ( keys %{$innodb_status->{IB_dl_txns}} ) { + my $txn = $innodb_status->{IB_dl_txns}->{$txn_id}; + my $pre = $prev_status->{IB_dl_txns}->{$txn_id} || $txn; + + if ( $wanted{deadlock_transactions} ) { + my $hash = extract_values($txn->{tx}, $txn->{tx}, $pre->{tx}, 'deadlock_transactions'); + $hash->{cxn} = $cxn; + $hash->{dl_txn_num} = $txn_id; + $hash->{victim} = $txn_id == $victim ? 'Yes' : 'No'; + $hash->{timestring} = $innodb_status->{IB_dl_timestring}; + $hash->{truncates} = $innodb_status->{IB_dl_complete} ? 'No' : 'Yes'; + push @deadlock_transactions, $hash; + } + + if ( $wanted{deadlock_locks} ) { + foreach my $lock ( @{$txn->{locks}} ) { + my $hash = extract_values($lock, $lock, $lock, 'deadlock_locks'); + $hash->{dl_txn_num} = $txn_id; + $hash->{cxn} = $cxn; + $hash->{mysql_thread_id} = $txn->{tx}->{mysql_thread_id}; + push @deadlock_locks, $hash; + } + } + + } + } + } + } + + my $first_table = 0; + foreach my $tbl ( @visible ) { + push @display_lines, '', set_to_tbl($rows_for{$tbl}, $tbl); + push @display_lines, get_cxn_errors(@cxns) + if ( $config{debug}->{val} || !$first_table++ ); + } + + draw_screen(\@display_lines); +} + +# display_F {{{3 +sub display_F { + my @display_lines; + my ( $cxn ) = get_connections(); + get_innodb_status([$cxn]); + my $innodb_status = $vars{$cxn}->{$clock}; + + if ( $innodb_status->{IB_fk_timestring} ) { + + push @display_lines, 'Reason: ' . $innodb_status->{IB_fk_reason}; + + # Display FK errors caused by invalid DML. + if ( $innodb_status->{IB_fk_txn} ) { + my $txn = $innodb_status->{IB_fk_txn}; + push @display_lines, + '', + "User $txn->{user} from $txn->{hostname}, thread $txn->{mysql_thread_id} was executing:", + '', no_ctrl_char($txn->{query_text}); + } + + my @fk_table = create_table2( + $tbl_meta{fk_error}->{visible}, + meta_to_hdr('fk_error'), + extract_values($innodb_status, $innodb_status, $innodb_status, 'fk_error'), + { just => '-', sep => ' '}); + push @display_lines, '', @fk_table; + + } + else { + push @display_lines, '', 'No foreign key error data.'; + } + draw_screen(\@display_lines, { raw => 1 } ); +} + +# display_I {{{3 +sub display_I { + my @display_lines; + my @cxns = get_connections(); + get_innodb_status(\@cxns); + + my @io_threads; + my @pending_io; + my @file_io_misc; + my @log_statistics; + my %rows_for = ( + io_threads => \@io_threads, + pending_io => \@pending_io, + file_io_misc => \@file_io_misc, + log_statistics => \@log_statistics, + ); + + my @visible = get_visible_tables(); + my %wanted = map { $_ => 1 } @visible; + + foreach my $cxn ( @cxns ) { + my $set = $vars{$cxn}->{$clock}; + my $pre = $vars{$cxn}->{$clock-1} || $set; + + if ( $set->{IB_io_complete} ) { + if ( $wanted{io_threads} ) { + my $cur_threads = $set->{IB_io_threads}; + my $pre_threads = $pre->{IB_io_threads} || $cur_threads; + foreach my $key ( sort keys %$cur_threads ) { + my $cur_thd = $cur_threads->{$key}; + my $pre_thd = $pre_threads->{$key} || $cur_thd; + my $hash = extract_values($cur_thd, $cur_thd, $pre_thd, 'io_threads'); + $hash->{cxn} = $cxn; + push @io_threads, $hash; + } + } + if ( $wanted{pending_io} ) { + push @pending_io, extract_values($set, $set, $pre, 'pending_io'); + } + if ( $wanted{file_io_misc} ) { + push @file_io_misc, extract_values( + $config{status_inc}->{val} ? inc(0, $cxn) : $set, + $set, $pre, 'file_io_misc'); + } + } + if ( $set->{IB_lg_complete} && $wanted{log_statistics} ) { + push @log_statistics, extract_values($set, $set, $pre, 'log_statistics'); + } + } + + my $first_table = 0; + foreach my $tbl ( @visible ) { + push @display_lines, '', set_to_tbl($rows_for{$tbl}, $tbl); + push @display_lines, get_cxn_errors(@cxns) + if ( $config{debug}->{val} || !$first_table++ ); + } + + draw_screen(\@display_lines); +} + +# display_L {{{3 +sub display_L { + my @display_lines; + my @cxns = get_connections(); + get_innodb_status(\@cxns); + + my @innodb_locks; + my %rows_for = ( + innodb_locks => \@innodb_locks, + ); + + my @visible = get_visible_tables(); + my %wanted = map { $_ => 1 } @visible; + + # Get info on locks + foreach my $cxn ( @cxns ) { + my $set = $vars{$cxn}->{$clock} or next; + my $pre = $vars{$cxn}->{$clock-1} || $set; + + if ( $wanted{innodb_locks} && defined $set->{IB_tx_transactions} && @{$set->{IB_tx_transactions}} ) { + + my $cur_txns = $set->{IB_tx_transactions}; + my $pre_txns = $pre->{IB_tx_transactions} || $cur_txns; + my %cur_txns = map { $_->{mysql_thread_id} => $_ } @$cur_txns; + my %pre_txns = map { $_->{mysql_thread_id} => $_ } @$pre_txns; + foreach my $txn ( @$cur_txns ) { + foreach my $lock ( @{$txn->{locks}} ) { + my %hash = map { $_ => $txn->{$_} } qw(txn_id mysql_thread_id lock_wait_time active_secs); + map { $hash{$_} = $lock->{$_} } qw(lock_type space_id page_no n_bits index db table txn_id lock_mode special insert_intention waiting); + $hash{cxn} = $cxn; + push @innodb_locks, extract_values(\%hash, \%hash, \%hash, 'innodb_locks'); + } + } + } + } + + my $first_table = 0; + foreach my $tbl ( @visible ) { + push @display_lines, '', set_to_tbl($rows_for{$tbl}, $tbl); + push @display_lines, get_cxn_errors(@cxns) + if ( $config{debug}->{val} || !$first_table++ ); + } + + draw_screen(\@display_lines); +} + +# display_M {{{3 +sub display_M { + my @display_lines; + my @cxns = get_connections(); + get_master_slave_status(@cxns); + get_status_info(@cxns); + + my @slave_sql_status; + my @slave_io_status; + my @master_status; + my %rows_for = ( + slave_sql_status => \@slave_sql_status, + slave_io_status => \@slave_io_status, + master_status => \@master_status, + ); + + my @visible = get_visible_tables(); + my %wanted = map { $_ => 1 } @visible; + + foreach my $cxn ( @cxns ) { + my $set = $config{status_inc}->{val} ? inc(0, $cxn) : $vars{$cxn}->{$clock}; + my $pre = $vars{$cxn}->{$clock - 1} || $set; + if ( $wanted{slave_sql_status} ) { + push @slave_sql_status, extract_values($set, $set, $pre, 'slave_sql_status'); + } + if ( $wanted{slave_io_status} ) { + push @slave_io_status, extract_values($set, $set, $pre, 'slave_io_status'); + } + if ( $wanted{master_status} ) { + push @master_status, extract_values($set, $set, $pre, 'master_status'); + } + } + + my $first_table = 0; + foreach my $tbl ( @visible ) { + push @display_lines, '', set_to_tbl($rows_for{$tbl}, $tbl); + push @display_lines, get_cxn_errors(@cxns) + if ( $config{debug}->{val} || !$first_table++ ); + } + + draw_screen(\@display_lines); +} + +# display_O {{{3 +sub display_O { + my @display_lines = (''); + my @cxns = get_connections(); + my @open_tables = get_open_tables(@cxns); + my @tables = map { extract_values($_, $_, $_, 'open_tables') } @open_tables; + push @display_lines, set_to_tbl(\@tables, 'open_tables'), get_cxn_errors(@cxns); + draw_screen(\@display_lines); +} + +# display_Q {{{3 +sub display_Q { + my @display_lines; + + my @q_header; + my @processlist; + my %rows_for = ( + q_header => \@q_header, + processlist => \@processlist, + ); + + my @visible = $opts{n} ? 'processlist' : get_visible_tables(); + my %wanted = map { $_ => 1 } @visible; + + # Get the data + my @cxns = get_connections(); + my @full_processlist = get_full_processlist(@cxns); + + # Create header + if ( $wanted{q_header} ) { + get_status_info(@cxns); + foreach my $cxn ( @cxns ) { + my $set = $vars{$cxn}->{$clock}; + my $pre = $vars{$cxn}->{$clock-1} || $set; + my $hash = extract_values($set, $set, $pre, 'q_header'); + $hash->{cxn} = $cxn; + $hash->{when} = 'Total'; + push @q_header, $hash; + + if ( exists $vars{$cxn}->{$clock - 1} ) { + my $inc = inc(0, $cxn); + my $hash = extract_values($inc, $set, $pre, 'q_header'); + $hash->{cxn} = $cxn; + $hash->{when} = 'Now'; + push @q_header, $hash; + } + } + } + + if ( $wanted{processlist} ) { + # TODO: save prev values + push @processlist, map { extract_values($_, $_, $_, 'processlist') } @full_processlist; + } + + my $first_table = 0; + foreach my $tbl ( @visible ) { + next unless $wanted{$tbl}; + push @display_lines, '', set_to_tbl($rows_for{$tbl}, $tbl); + push @display_lines, get_cxn_errors(@cxns) + if ( $config{debug}->{val} || !$first_table++ ); + } + + # Save queries in global variable for analysis. The rows in %rows_for have been + # filtered, etc as a side effect of set_to_tbl(), so they are the same as the rows + # that get pushed to the screen. + @current_queries = map { + my %hash; + @hash{ qw(cxn id db query secs) } = @{$_}{ qw(cxn mysql_thread_id db info secs) }; + \%hash; + } @{$rows_for{processlist}}; + + draw_screen(\@display_lines); +} + +# display_R {{{3 +sub display_R { + my @display_lines; + my @cxns = get_connections(); + get_innodb_status(\@cxns); + + my @row_operations; + my @row_operation_misc; + my @semaphores; + my @wait_array; + my %rows_for = ( + row_operations => \@row_operations, + row_operation_misc => \@row_operation_misc, + semaphores => \@semaphores, + wait_array => \@wait_array, + ); + + my @visible = get_visible_tables(); + my %wanted = map { $_ => 1 } @visible; + my $incvar = $config{status_inc}->{val}; + + foreach my $cxn ( @cxns ) { + my $set = $vars{$cxn}->{$clock}; + my $pre = $vars{$cxn}->{$clock-1} || $set; + my $inc; # Only assigned to if wanted + + if ( $set->{IB_ro_complete} ) { + if ( $wanted{row_operations} ) { + $inc ||= $incvar ? inc(0, $cxn) : $set; + push @row_operations, extract_values($inc, $set, $pre, 'row_operations'); + } + if ( $wanted{row_operation_misc} ) { + push @row_operation_misc, extract_values($set, $set, $pre, 'row_operation_misc'), + } + } + + if ( $set->{IB_sm_complete} && $wanted{semaphores} ) { + $inc ||= $incvar ? inc(0, $cxn) : $set; + push @semaphores, extract_values($inc, $set, $pre, 'semaphores'); + } + + if ( $set->{IB_sm_wait_array_size} && $wanted{wait_array} ) { + foreach my $wait ( @{$set->{IB_sm_waits}} ) { + my $hash = extract_values($wait, $wait, $wait, 'wait_array'); + $hash->{cxn} = $cxn; + push @wait_array, $hash; + } + } + } + + my $first_table = 0; + foreach my $tbl ( @visible ) { + push @display_lines, '', set_to_tbl($rows_for{$tbl}, $tbl); + push @display_lines, get_cxn_errors(@cxns) + if ( $config{debug}->{val} || !$first_table++ ); + } + + draw_screen(\@display_lines); +} + +# display_T {{{3 +sub display_T { + my @display_lines; + + my @t_header; + my @innodb_transactions; + my %rows_for = ( + t_header => \@t_header, + innodb_transactions => \@innodb_transactions, + ); + + my @visible = $opts{n} ? 'innodb_transactions' : get_visible_tables(); + my %wanted = map { $_ => 1 } @visible; + + my @cxns = get_connections(); + + # If the header is to be shown, buffer pool data is required. + get_innodb_status( \@cxns, [ $wanted{t_header} ? qw(bp) : () ] ); + + foreach my $cxn ( get_connections() ) { + my $set = $vars{$cxn}->{$clock}; + my $pre = $vars{$cxn}->{$clock-1} || $set; + + next unless $set->{IB_tx_transactions}; + + if ( $wanted{t_header} ) { + my $hash = extract_values($set, $set, $pre, 't_header'); + push @t_header, $hash; + } + + if ( $wanted{innodb_transactions} ) { + my $cur_txns = $set->{IB_tx_transactions}; + my $pre_txns = $pre->{IB_tx_transactions} || $cur_txns; + my %cur_txns = map { $_->{mysql_thread_id} => $_ } @$cur_txns; + my %pre_txns = map { $_->{mysql_thread_id} => $_ } @$pre_txns; + foreach my $thd_id ( sort keys %cur_txns ) { + my $cur_txn = $cur_txns{$thd_id}; + my $pre_txn = $pre_txns{$thd_id} || $cur_txn; + my $hash = extract_values($cur_txn, $cur_txn, $pre_txn, 'innodb_transactions'); + $hash->{cxn} = $cxn; + push @innodb_transactions, $hash; + } + } + + } + + my $first_table = 0; + foreach my $tbl ( @visible ) { + push @display_lines, '', set_to_tbl($rows_for{$tbl}, $tbl); + push @display_lines, get_cxn_errors(@cxns) + if ( $config{debug}->{val} || !$first_table++ ); + } + + # Save queries in global variable for analysis. The rows in %rows_for have been + # filtered, etc as a side effect of set_to_tbl(), so they are the same as the rows + # that get pushed to the screen. + @current_queries = map { + my %hash; + @hash{ qw(cxn id db query secs) } = @{$_}{ qw(cxn mysql_thread_id db query_text active_secs) }; + \%hash; + } @{$rows_for{innodb_transactions}}; + + draw_screen(\@display_lines); +} + +# display_S {{{3 +sub display_S { + my $fmt = get_var_set('S_set'); + my $func = $config{S_func}->{val}; + my $inc = $func eq 'g' || $config{status_inc}->{val}; + + # The table's meta-data is generated from the compiled var_set. + my ( $cols, $visible ); + if ( $tbl_meta{var_status}->{fmt} && $fmt eq $tbl_meta{var_status}->{fmt} ) { + ( $cols, $visible ) = @{$tbl_meta{var_status}}{qw(cols visible)}; + } + else { + ( $cols, $visible ) = compile_select_stmt($fmt); + + # Apply missing values to columns. Always apply averages across all connections. + map { + $_->{agg} = 'avg'; + $_->{label} = $_->{hdr}; + } values %$cols; + + $tbl_meta{var_status}->{cols} = $cols; + $tbl_meta{var_status}->{visible} = $visible; + $tbl_meta{var_status}->{fmt} = $fmt; + map { $tbl_meta{var_status}->{cols}->{$_}->{just} = ''} @$visible; + } + + my @var_status; + my %rows_for = ( + var_status => \@var_status, + ); + + my @visible = get_visible_tables(); + my %wanted = map { $_ => 1 } @visible; + my @cxns = get_connections(); + + get_status_info(@cxns); + get_innodb_status(\@cxns); + + # Set up whether to pivot and how many sets to extract. + $tbl_meta{var_status}->{pivot} = $func eq 'v'; + + my $num_sets + = $func eq 'v' + ? $config{num_status_sets}->{val} + : 0; + foreach my $set ( 0 .. $num_sets ) { + my @rows; + foreach my $cxn ( @cxns ) { + my $vars = $inc ? inc($set, $cxn) : $vars{$cxn}->{$clock - $set}; + my $cur = $vars{$cxn}->{$clock-$set}; + my $pre = $vars{$cxn}->{$clock-$set-1} || $cur; + next unless $vars && %$vars; + my $hash = extract_values($vars, $cur, $pre, 'var_status'); + push @rows, $hash; + } + @rows = apply_group_by('var_status', [], @rows); + push @var_status, @rows; + } + + # Recompile the sort func. TODO: avoid recompiling at every refresh. + # Figure out whether the data is all numeric and decide on a sort type. + # my $cmp + # = scalar( + # grep { !defined $_ || $_ !~ m/^\d+$/ } + # map { my $col = $_; map { $_->{$col} } @var_status } + # $tbl_meta{var_status}->{sort_cols} =~ m/(\w+)/g) + # ? 'cmp' + # : '<=>'; + $tbl_meta{var_status}->{sort_func} = make_sort_func($tbl_meta{var_status}); + + # ################################################################ + # Now there is specific display code based on $config{S_func} + # ################################################################ + if ( $func =~ m/s|g/ ) { + my $min_width = 4; + + # Clear the screen if the display width changed. + if ( @last_term_size && $this_term_size[0] != $last_term_size[0] ) { + $lines_printed = 0; + $clear_screen_sub->(); + } + + if ( $func eq 's' ) { + # Decide how wide columns should be. + my $num_cols = scalar(@$visible); + my $width = $opts{n} ? 0 : max($min_width, int(($this_term_size[0] - $num_cols + 1) / $num_cols)); + my $g_format = $opts{n} ? ( "%s\t" x $num_cols ) : ( "%-${width}s " x $num_cols ); + + # Print headers every now and then. Headers can get really long, so compact them. + my @hdr = @$visible; + if ( $opts{n} ) { + if ( $lines_printed == 0 ) { + print join("\t", @hdr), "\n"; + $lines_printed++; + } + } + elsif ( $lines_printed == 0 || $lines_printed > $this_term_size[1] - 2 ) { + @hdr = map { donut(crunch($_, $width), $width) } @hdr; + print join(' ', map { sprintf( "%${width}s", donut($_, $width)) } @hdr) . "\n"; + $lines_printed = 1; + } + + # Design a column format for the values. + my $format + = $opts{n} + ? join("\t", map { '%s' } @$visible) . "\n" + : join(' ', map { "%${width}s" } @hdr) . "\n"; + + foreach my $row ( @var_status ) { + printf($format, map { defined $_ ? $_ : '' } @{$row}{ @$visible }); + $lines_printed++; + } + } + else { # 'g' mode + # Design a column format for the values. + my $num_cols = scalar(@$visible); + my $width = $opts{n} ? 0 : int(($this_term_size[0] - $num_cols + 1) / $num_cols); + my $format = $opts{n} ? ( "%s\t" x $num_cols ) : ( "%-${width}s " x $num_cols ); + $format =~ s/\s$/\n/; + + # Print headers every now and then. + if ( $opts{n} ) { + if ( $lines_printed == 0 ) { + print join("\t", @$visible), "\n"; + print join("\t", map { shorten($mvs{$_}) } @$visible), "\n"; + } + } + elsif ( $lines_printed == 0 || $lines_printed > $this_term_size[1] - 2 ) { + printf($format, map { donut(crunch($_, $width), $width) } @$visible); + printf($format, map { shorten($mvs{$_} || 0) } @$visible); + $lines_printed = 2; + } + + # Update the max ever seen, and scale by the max ever seen. + my $set = $var_status[0]; + foreach my $col ( @$visible ) { + $set->{$col} = 1 unless defined $set->{$col} && $set->{$col} =~ m/$num_regex/; + $set->{$col} = ($set->{$col} || 1) / ($set->{Uptime_hires} || 1); + $mvs{$col} = max($mvs{$col} || 1, $set->{$col}); + $set->{$col} /= $mvs{$col}; + } + printf($format, map { ( $config{graph_char}->{val} x int( $width * $set->{$_} )) || '.' } @$visible ); + $lines_printed++; + + } + } + else { # 'v' + my $first_table = 0; + my @display_lines; + foreach my $tbl ( @visible ) { + push @display_lines, '', set_to_tbl($rows_for{$tbl}, $tbl); + push @display_lines, get_cxn_errors(@cxns) + if ( $config{debug}->{val} || !$first_table++ ); + } + $clear_screen_sub->(); + draw_screen( \@display_lines ); + } +} + +# display_explain {{{3 +sub display_explain { + my $info = shift; + my $cxn = $info->{cxn}; + my $db = $info->{db}; + + my ( $mods, $query ) = rewrite_for_explain($info->{query}); + + my @display_lines; + + if ( $query ) { + + my $part = version_ge($dbhs{$cxn}->{dbh}, '5.1.5') ? 'PARTITIONS' : ''; + $query = "EXPLAIN $part\n" . $query; + + eval { + if ( $db ) { + do_query($cxn, "use $db"); + } + my $sth = do_query($cxn, $query); + + my $res; + while ( $res = $sth->fetchrow_hashref() ) { + map { $res->{$_} ||= '' } ( 'partitions', keys %$res); + my @this_table = create_caption("Sub-Part $res->{id}", + create_table2( + $tbl_meta{explain}->{visible}, + meta_to_hdr('explain'), + extract_values($res, $res, $res, 'explain'))); + @display_lines = stack_next(\@display_lines, \@this_table, { pad => ' ', vsep => 2 }); + } + }; + + if ( $EVAL_ERROR ) { + push @display_lines, + '', + "The query could not be explained. Only SELECT queries can be " + . "explained; innotop tries to rewrite certain REPLACE and INSERT queries " + . "into SELECT, but this doesn't always succeed."; + } + + } + else { + push @display_lines, '', 'The query could not be explained.'; + } + + if ( $mods ) { + push @display_lines, '', '[This query has been re-written to be explainable]'; + } + + unshift @display_lines, no_ctrl_char($query); + draw_screen(\@display_lines, { raw => 1 } ); +} + +# rewrite_for_explain {{{3 +sub rewrite_for_explain { + my $query = shift; + + my $mods = 0; + my $orig = $query; + $mods += $query =~ s/^\s*(?:replace|insert).*?select/select/is; + $mods += $query =~ s/^ + \s*create\s+(?:temporary\s+)?table + \s+(?:\S+\s+)as\s+select/select/xis; + $mods += $query =~ s/\s+on\s+duplicate\s+key\s+update.*$//is; + return ( $mods, $query ); +} + +# show_optimized_query {{{3 +sub show_optimized_query { + my $info = shift; + my $cxn = $info->{cxn}; + my $db = $info->{db}; + my $meta = $dbhs{$cxn}; + + my @display_lines; + + my ( $mods, $query ) = rewrite_for_explain($info->{query}); + + if ( $mods ) { + push @display_lines, '[This query has been re-written to be explainable]'; + } + + if ( $query ) { + push @display_lines, no_ctrl_char($info->{query}); + + eval { + if ( $db ) { + do_query($cxn, "use $db"); + } + do_query( $cxn, 'EXPLAIN EXTENDED ' . $query ) or die "Can't explain query"; + my $sth = do_query($cxn, 'SHOW WARNINGS'); + my $res = $sth->fetchall_arrayref({}); + + if ( $res ) { + foreach my $result ( @$res ) { + push @display_lines, 'Note:', no_ctrl_char($result->{message}); + } + } + else { + push @display_lines, '', 'The query optimization could not be generated.'; + } + }; + + if ( $EVAL_ERROR ) { + push @display_lines, '', "The optimization could not be generated: $EVAL_ERROR"; + } + + } + else { + push @display_lines, '', 'The query optimization could not be generated.'; + } + + draw_screen(\@display_lines, { raw => 1 } ); +} + +# display_help {{{3 +sub display_help { + my $mode = $config{mode}->{val}; + + # Get globally mapped keys, then overwrite them with mode-specific ones. + my %keys = map { + $_ => $action_for{$_}->{label} + } keys %action_for; + foreach my $key ( keys %{$modes{$mode}->{action_for}} ) { + $keys{$key} = $modes{$mode}->{action_for}->{$key}->{label}; + } + delete $keys{'?'}; + + # Split them into three kinds of keys: MODE keys, action keys, and + # magic (special character) keys. + my @modes = sort grep { m/[A-Z]/ } keys %keys; + my @actions = sort grep { m/[a-z]/ } keys %keys; + my @magic = sort grep { m/[^A-Z]/i } keys %keys; + + my @display_lines = ( '', 'Switch to a different mode:' ); + + # Mode keys + my @all_modes = map { "$_ $modes{$_}->{hdr}" } @modes; + my @col1 = splice(@all_modes, 0, ceil(@all_modes/3)); + my @col2 = splice(@all_modes, 0, ceil(@all_modes/2)); + my $max1 = max(map {length($_)} @col1); + my $max2 = max(map {length($_)} @col2); + while ( @col1 ) { + push @display_lines, sprintf(" %-${max1}s %-${max2}s %s", + (shift @col1 || ''), + (shift @col2 || ''), + (shift @all_modes || '')); + } + + # Action keys + my @all_actions = map { "$_ $keys{$_}" } @actions; + @col1 = splice(@all_actions, 0, ceil(@all_actions/2)); + $max1 = max(map {length($_)} @col1); + push @display_lines, '', 'Actions:'; + while ( @col1 ) { + push @display_lines, sprintf(" %-${max1}s %s", + (shift @col1 || ''), + (shift @all_actions || '')); + } + + # Magic keys + my @all_magic = map { sprintf('%4s', $action_for{$_}->{key} || $_) . " $keys{$_}" } @magic; + @col1 = splice(@all_magic, 0, ceil(@all_magic/2)); + $max1 = max(map {length($_)} @col1); + push @display_lines, '', 'Other:'; + while ( @col1 ) { + push @display_lines, sprintf("%-${max1}s%s", + (shift @col1 || ''), + (shift @all_magic || '')); + } + + $clear_screen_sub->(); + draw_screen(\@display_lines, { show_all => 1 } ); + pause(); + $clear_screen_sub->(); +} + +# show_full_query {{{3 +sub show_full_query { + my $info = shift; + my @display_lines = no_ctrl_char($info->{query}); + draw_screen(\@display_lines, { raw => 1 }); +} + +# Formatting functions {{{2 + +# create_table2 {{{3 +# Makes a two-column table, labels on left, data on right. +# Takes refs of @cols, %labels and %data, %user_prefs +sub create_table2 { + my ( $cols, $labels, $data, $user_prefs ) = @_; + my @rows; + + if ( @$cols && %$data ) { + + # Override defaults + my $p = { + just => '', + sep => ':', + just1 => '-', + }; + if ( $user_prefs ) { + map { $p->{$_} = $user_prefs->{$_} } keys %$user_prefs; + } + + # Fix undef values + map { $data->{$_} = '' unless defined $data->{$_} } @$cols; + + # Format the table + my $max_l = max(map{ length($labels->{$_}) } @$cols); + my $max_v = max(map{ length($data->{$_}) } @$cols); + my $format = "%$p->{just}${max_l}s$p->{sep} %$p->{just1}${max_v}s"; + foreach my $col ( @$cols ) { + push @rows, sprintf($format, $labels->{$col}, $data->{$col}); + } + } + return @rows; +} + +# stack_next {{{3 +# Stacks one display section next to the other. Accepts left-hand arrayref, +# right-hand arrayref, and options hashref. Tries to stack as high as +# possible, so +# aaaaaa +# bbb +# can stack ccc next to the bbb. +# NOTE: this DOES modify its arguments, even though it returns a new array. +sub stack_next { + my ( $left, $right, $user_prefs ) = @_; + my @result; + + my $p = { + pad => ' ', + vsep => 0, + }; + if ( $user_prefs ) { + map { $p->{$_} = $user_prefs->{$_} } keys %$user_prefs; + } + + # Find out how wide the LHS can be and still let the RHS fit next to it. + my $pad = $p->{pad}; + my $max_r = max( map { length($_) } @$right) || 0; + my $max_l = $this_term_size[0] - $max_r - length($pad); + + # Find the minimum row on the LHS that the RHS will fit next to. + my $i = scalar(@$left) - 1; + while ( $i >= 0 && length($left->[$i]) <= $max_l ) { + $i--; + } + $i++; + my $offset = $i; + + if ( $i < scalar(@$left) ) { + # Find the max width of the section of the LHS against which the RHS + # will sit. + my $max_i_in_common = min($i + scalar(@$right) - 1, scalar(@$left) - 1); + my $max_width = max( map { length($_) } @{$left}[$i..$max_i_in_common]); + + # Append the RHS onto the LHS until one runs out. + while ( $i < @$left && $i - $offset < @$right ) { + my $format = "%-${max_width}s$pad%${max_r}s"; + $left->[$i] = sprintf($format, $left->[$i], $right->[$i - $offset]); + $i++; + } + while ( $i - $offset < @$right ) { + # There is more RHS to push on the end of the array + push @$left, + sprintf("%${max_width}s$pad%${max_r}s", ' ', $right->[$i - $offset]); + $i++; + } + push @result, @$left; + } + else { + # There is no room to put them side by side. Add them below, with + # a blank line above them if specified. + push @result, @$left; + push @result, (' ' x $this_term_size[0]) if $p->{vsep} && @$left; + push @result, @$right; + } + return @result; +} + +# create_caption {{{3 +sub create_caption { + my ( $caption, @rows ) = @_; + if ( @rows ) { + + # Calculate the width of what will be displayed, so it can be centered + # in that space. When the thing is wider than the display, center the + # caption in the display. + my $width = min($this_term_size[0], max(map { length(ref($_) ? $_->[0] : $_) } @rows)); + + my $cap_len = length($caption); + + # It may be narrow enough to pad the sides with underscores and save a + # line on the screen. + if ( $cap_len <= $width - 6 ) { + my $left = int(($width - 2 - $cap_len) / 2); + unshift @rows, + ("_" x $left) . " $caption " . ("_" x ($width - $left - $cap_len - 2)); + } + + # The caption is too wide to add underscores on each side. + else { + + # Color is supported, so we can use terminal underlining. + if ( $config{color}->{val} ) { + my $left = int(($width - $cap_len) / 2); + unshift @rows, [ + (" " x $left) . $caption . (" " x ($width - $left - $cap_len)), + 'underline', + ]; + } + + # Color is not supported, so we have to add a line underneath to separate the + # caption from whatever it's captioning. + else { + my $left = int(($width - $cap_len) / 2); + unshift @rows, ('-' x $width); + unshift @rows, (" " x $left) . $caption . (" " x ($width - $left - $cap_len)); + } + + # The caption is wider than the thing it labels, so we have to pad the + # thing it labels to a consistent width. + if ( $cap_len > $width ) { + @rows = map { + ref($_) + ? [ sprintf('%-' . $cap_len . 's', $_->[0]), $_->[1] ] + : sprintf('%-' . $cap_len . 's', $_); + } @rows; + } + + } + } + return @rows; +} + +# create_table {{{3 +# Input: an arrayref of columns, hashref of col info, and an arrayref of hashes +# Example: [ 'a', 'b' ] +# { a => spec, b => spec } +# [ { a => 1, b => 2}, { a => 3, b => 4 } ] +# The 'spec' is a hashref of hdr => label, just => ('-' or ''). It also supports min and max-widths +# vi the minw and maxw params. +# Output: an array of strings, one per row. +# Example: +# Column One Column Two +# ---------- ---------- +# 1 2 +# 3 4 +sub create_table { + my ( $cols, $info, $data, $prefs ) = @_; + $prefs ||= {}; + $prefs->{no_hdr} ||= ($opts{n} && $clock != 1); + + # Truncate rows that will surely be off screen even if this is the only table. + if ( !$opts{n} && !$prefs->{raw} && !$prefs->{show_all} && $this_term_size[1] < @$data-1 ) { + $data = [ @$data[0..$this_term_size[1] - 1] ]; + } + + my @rows = (); + + if ( @$cols && %$info ) { + + # Fix undef values, collapse whitespace. + foreach my $row ( @$data ) { + map { $row->{$_} = collapse_ws($row->{$_}) } @$cols; + } + + my $col_sep = $opts{n} ? "\t" : ' '; + + # Find each column's max width. + my %width_for; + if ( !$opts{n} ) { + %width_for = map { + my $col_name = $_; + if ( $info->{$_}->{dec} ) { + # Align along the decimal point + my $max_rodp = max(0, map { $_->{$col_name} =~ m/([^\s\d-].*)$/ ? length($1) : 0 } @$data); + foreach my $row ( @$data ) { + my $col = $row->{$col_name}; + my ( $l, $r ) = $col =~ m/^([\s\d]*)(.*)$/; + $row->{$col_name} = sprintf("%s%-${max_rodp}s", $l, $r); + } + } + my $max_width = max( length($info->{$_}->{hdr}), map { length($_->{$col_name}) } @$data); + if ( $info->{$col_name}->{maxw} ) { + $max_width = min( $max_width, $info->{$col_name}->{maxw} ); + } + if ( $info->{$col_name}->{minw} ) { + $max_width = max( $max_width, $info->{$col_name}->{minw} ); + } + $col_name => $max_width; + } @$cols; + } + + # The table header. + if ( !$config{hide_hdr}->{val} && !$prefs->{no_hdr} ) { + push @rows, $opts{n} + ? join( $col_sep, @$cols ) + : join( $col_sep, map { sprintf( "%-$width_for{$_}s", trunc($info->{$_}->{hdr}, $width_for{$_}) ) } @$cols ); + if ( $config{color}->{val} && $config{header_highlight}->{val} ) { + push @rows, [ pop @rows, $config{header_highlight}->{val} ]; + } + elsif ( !$opts{n} ) { + push @rows, join( $col_sep, map { "-" x $width_for{$_} } @$cols ); + } + } + + # The table data. + if ( $opts{n} ) { + foreach my $item ( @$data ) { + push @rows, join($col_sep, map { $item->{$_} } @$cols ); + } + } + else { + my $format = join( $col_sep, + map { "%$info->{$_}->{just}$width_for{$_}s" } @$cols ); + foreach my $item ( @$data ) { + my $row = sprintf($format, map { trunc($item->{$_}, $width_for{$_}) } @$cols ); + if ( $config{color}->{val} && $item->{_color} ) { + push @rows, [ $row, $item->{_color} ]; + } + else { + push @rows, $row; + } + } + } + } + + return @rows; +} + +# Aggregates a table. If $group_by is an arrayref of columns, the grouping key +# is the specified columns; otherwise it's just the empty string (e.g. +# everything is grouped as one group). +sub apply_group_by { + my ( $tbl, $group_by, @rows ) = @_; + my $meta = $tbl_meta{$tbl}; + my %is_group = map { $_ => 1 } @$group_by; + my @non_grp = grep { !$is_group{$_} } keys %{$meta->{cols}}; + + my %temp_table; + foreach my $row ( @rows ) { + my $group_key + = @$group_by + ? '{' . join('}{', map { defined $_ ? $_ : '' } @{$row}{@$group_by}) . '}' + : ''; + $temp_table{$group_key} ||= []; + push @{$temp_table{$group_key}}, $row; + } + + # Crush the rows together... + my @new_rows; + foreach my $key ( sort keys %temp_table ) { + my $group = $temp_table{$key}; + my %new_row; + @new_row{@$group_by} = @{$group->[0]}{@$group_by}; + foreach my $col ( @non_grp ) { + my $agg = $meta->{cols}->{$col}->{agg} || 'first'; + $new_row{$col} = $agg_funcs{$agg}->( map { $_->{$col} } @$group ); + } + push @new_rows, \%new_row; + } + return @new_rows; +} + +# set_to_tbl {{{3 +# Unifies all the work of filtering, sorting etc. Alters the input. +# TODO: pull all the little pieces out into subroutines and stick events in each of them. +sub set_to_tbl { + my ( $rows, $tbl ) = @_; + my $meta = $tbl_meta{$tbl} or die "No such table $tbl in tbl_meta"; + + # don't show cxn if there's only one connection being displayed + my @visible; + if (scalar @{$modes{$config{mode}->{val}}->{connections}} == 1) { + map { push @visible, $_ if $_ !~ /^cxn$/ } @{$meta->{visible}}; + delete $$rows[0]{cxn} if defined $$rows[0]{cxn}; + } + else { + @visible = @{$meta->{visible}}; + } + + if ( !$meta->{pivot} ) { + + # Hook in event listeners + foreach my $listener ( @{$event_listener_for{set_to_tbl_pre_filter}} ) { + $listener->set_to_tbl_pre_filter($rows, $tbl); + } + + # Apply filters. Note that if the table is pivoted, filtering and sorting + # are applied later. + foreach my $filter ( @{$meta->{filters}} ) { + eval { + @$rows = grep { $filters{$filter}->{func}->($_) } @$rows; + }; + if ( $EVAL_ERROR && $config{debug}->{val} ) { + die $EVAL_ERROR; + } + } + + foreach my $listener ( @{$event_listener_for{set_to_tbl_pre_sort}} ) { + $listener->set_to_tbl_pre_sort($rows, $tbl); + } + + # Sort. Note that if the table is pivoted, sorting might have the wrong + # columns and it could crash. This will only be an issue if it's possible + # to toggle pivoting on and off, which it's not at the moment. + if ( @$rows && $meta->{sort_func} && !$meta->{aggregate} ) { + if ( $meta->{sort_dir} > 0 ) { + @$rows = $meta->{sort_func}->( @$rows ); + } + else { + @$rows = reverse $meta->{sort_func}->( @$rows ); + } + } + + } + + # Stop altering arguments now. + my @rows = @$rows; + + foreach my $listener ( @{$event_listener_for{set_to_tbl_pre_group}} ) { + $listener->set_to_tbl_pre_group(\@rows, $tbl); + } + + # Apply group-by. + if ( $meta->{aggregate} ) { + @rows = apply_group_by($tbl, $meta->{group_by}, @rows); + + # Sort. Note that if the table is pivoted, sorting might have the wrong + # columns and it could crash. This will only be an issue if it's possible + # to toggle pivoting on and off, which it's not at the moment. + if ( @rows && $meta->{sort_func} ) { + if ( $meta->{sort_dir} > 0 ) { + @rows = $meta->{sort_func}->( @rows ); + } + else { + @rows = reverse $meta->{sort_func}->( @rows ); + } + } + + } + + foreach my $listener ( @{$event_listener_for{set_to_tbl_pre_colorize}} ) { + $listener->set_to_tbl_pre_colorize(\@rows, $tbl); + } + + if ( !$meta->{pivot} ) { + # Colorize. Adds a _color column to rows. + if ( @rows && $meta->{color_func} ) { + eval { + foreach my $row ( @rows ) { + $row->{_color} = $meta->{color_func}->($row); + } + }; + if ( $EVAL_ERROR ) { + pause($EVAL_ERROR); + } + } + } + + foreach my $listener ( @{$event_listener_for{set_to_tbl_pre_transform}} ) { + $listener->set_to_tbl_pre_transform(\@rows, $tbl); + } + + # Apply_transformations. + if ( @rows ) { + my $cols = $meta->{cols}; + foreach my $col ( keys %{$rows->[0]} ) { + # Don't auto-vivify $tbl_meta{tbl}-{cols}->{_color}->{trans} + next if $col eq '_color'; + foreach my $trans ( @{$cols->{$col}->{trans}} ) { + map { $_->{$col} = $trans_funcs{$trans}->($_->{$col}) } @rows; + } + } + } + + my ($fmt_cols, $fmt_meta); + + # Pivot. + if ( $meta->{pivot} ) { + + foreach my $listener ( @{$event_listener_for{set_to_tbl_pre_pivot}} ) { + $listener->set_to_tbl_pre_pivot(\@rows, $tbl); + } + + my @vars = @{$meta->{visible}}; + my @tmp = map { { name => $_ } } @vars; + my @cols = 'name'; + foreach my $i ( 0..@$rows-1 ) { + my $col = "set_$i"; + push @cols, $col; + foreach my $j ( 0..@vars-1 ) { + $tmp[$j]->{$col} = $rows[$i]->{$vars[$j]}; + } + } + $fmt_meta = { map { $_ => { hdr => $_, just => '-' } } @cols }; + $fmt_cols = \@cols; + @rows = @tmp; + + # Hook in event listeners + foreach my $listener ( @{$event_listener_for{set_to_tbl_pre_filter}} ) { + $listener->set_to_tbl_pre_filter($rows, $tbl); + } + + # Apply filters. + foreach my $filter ( @{$meta->{filters}} ) { + eval { + @rows = grep { $filters{$filter}->{func}->($_) } @rows; + }; + if ( $EVAL_ERROR && $config{debug}->{val} ) { + die $EVAL_ERROR; + } + } + + foreach my $listener ( @{$event_listener_for{set_to_tbl_pre_sort}} ) { + $listener->set_to_tbl_pre_sort($rows, $tbl); + } + + # Sort. + if ( @rows && $meta->{sort_func} ) { + if ( $meta->{sort_dir} > 0 ) { + @rows = $meta->{sort_func}->( @rows ); + } + else { + @rows = reverse $meta->{sort_func}->( @rows ); + } + } + + } + else { + # If the table isn't pivoted, just show all columns that are supposed to + # be shown; but eliminate aggonly columns if the table isn't aggregated. + my $aggregated = $meta->{aggregate}; + $fmt_cols = [ grep { $aggregated || !$meta->{cols}->{$_}->{aggonly} } @visible ]; + $fmt_meta = { map { $_ => $meta->{cols}->{$_} } @$fmt_cols }; + + # If the table is aggregated, re-order the group_by columns to the left of + # the display. + if ( $aggregated ) { + my %is_group = map { $_ => 1 } @{$meta->{group_by}}; + $fmt_cols = [ @{$meta->{group_by}}, grep { !$is_group{$_} } @$fmt_cols ]; + } + } + + foreach my $listener ( @{$event_listener_for{set_to_tbl_pre_create}} ) { + $listener->set_to_tbl_pre_create(\@rows, $tbl); + } + + @rows = create_table( $fmt_cols, $fmt_meta, \@rows); + if ( !$meta->{hide_caption} && !$opts{n} && $config{display_table_captions}->{val} ) { + @rows = create_caption($meta->{capt}, @rows) + } + + foreach my $listener ( @{$event_listener_for{set_to_tbl_post_create}} ) { + $listener->set_to_tbl_post_create(\@rows, $tbl); + } + + return @rows; +} + +# meta_to_hdr {{{3 +sub meta_to_hdr { + my $tbl = shift; + my $meta = $tbl_meta{$tbl}; + my %labels = map { $_ => $meta->{cols}->{$_}->{hdr} } @{$meta->{visible}}; + return \%labels; +} + +# commify {{{3 +# From perlfaq5: add commas. +sub commify { + my ( $num ) = @_; + $num = 0 unless defined $num; + $num =~ s/(^[-+]?\d+?(?=(?>(?:\d{3})+)(?!\d))|\G\d{3}(?=\d))/$1,/g; + return $num; +} + +# set_precision {{{3 +# Trim to desired precision. +sub set_precision { + my ( $num, $precision ) = @_; + $precision = $config{num_digits}->{val} if !defined $precision; + sprintf("%.${precision}f", $num); +} + +# percent {{{3 +# Convert to percent +sub percent { + my ( $num ) = @_; + $num = 0 unless defined $num; + my $digits = $config{num_digits}->{val}; + return sprintf("%.${digits}f", $num * 100) + . ($config{show_percent}->{val} ? '%' : ''); +} + +# shorten {{{3 +sub shorten { + my ( $num, $opts ) = @_; + + return $num if !defined($num) || $opts{n} || $num !~ m/$num_regex/; + + $opts ||= {}; + my $pad = defined $opts->{pad} ? $opts->{pad} : ''; + my $num_digits = defined $opts->{num_digits} + ? $opts->{num_digits} + : $config{num_digits}->{val}; + my $force = defined $opts->{force}; + + my $n = 0; + while ( $num >= 1_024 ) { + $num /= 1_024; + ++$n; + } + return sprintf( + $num =~ m/\./ || $n || $force + ? "%.${num_digits}f%s" + : '%d', + $num, ($pad,'k','M','G', 'T')[$n]); + +} + +# Utility functions {{{2 +# unique {{{3 +sub unique { + my %seen; + return grep { !$seen{$_}++ } @_; +} + +# make_color_func {{{3 +sub make_color_func { + my ( $tbl ) = @_; + my @criteria; + foreach my $spec ( @{$tbl->{colors}} ) { + next unless exists $comp_ops{$spec->{op}}; + my $val = $spec->{op} =~ m/^(?:eq|ne|le|ge|lt|gt)$/ ? "'$spec->{arg}'" + : $spec->{op} =~ m/^(?:=~|!~)$/ ? "m/" . quotemeta($spec->{arg}) . "/" + : $spec->{arg}; + push @criteria, + "( defined \$set->{$spec->{col}} && \$set->{$spec->{col}} $spec->{op} $val ) { return '$spec->{color}'; }"; + } + return undef unless @criteria; + my $sub = eval 'sub { my ( $set ) = @_; if ' . join(" elsif ", @criteria) . '}'; + die if $EVAL_ERROR; + return $sub; +} + +# make_sort_func {{{3 +# Gets a list of sort columns from the table, like "+cxn -time" and returns a +# subroutine that will sort that way. +sub make_sort_func { + my ( $tbl ) = @_; + my @criteria; + + # Pivoted tables can be sorted by 'name' and set_x columns; others must be + # sorted by existing columns. TODO: this will crash if you toggle between + # pivoted and nonpivoted. I have several other 'crash' notes about this if + # this ever becomes possible. + + if ( $tbl->{pivot} ) { + # Sort type is not really possible on pivoted columns, because a 'column' + # contains data from an entire non-pivoted row, so there could be a mix of + # numeric and non-numeric data. Thus everything has to be 'cmp' type. + foreach my $col ( split(/\s+/, $tbl->{sort_cols} ) ) { + next unless $col; + my ( $dir, $name ) = $col =~ m/([+-])?(\w+)$/; + next unless $name && $name =~ m/^(?:name|set_\d+)$/; + $dir ||= '+'; + my $op = 'cmp'; + my $df = "''"; + push @criteria, + $dir eq '+' + ? "(\$a->{$name} || $df) $op (\$b->{$name} || $df)" + : "(\$b->{$name} || $df) $op (\$a->{$name} || $df)"; + } + } + else { + foreach my $col ( split(/\s+/, $tbl->{sort_cols} ) ) { + next unless $col; + my ( $dir, $name ) = $col =~ m/([+-])?(\w+)$/; + next unless $name && $tbl->{cols}->{$name}; + $dir ||= '+'; + my $op = $tbl->{cols}->{$name}->{num} ? "<=>" : "cmp"; + my $df = $tbl->{cols}->{$name}->{num} ? "0" : "''"; + push @criteria, + $dir eq '+' + ? "(\$a->{$name} || $df) $op (\$b->{$name} || $df)" + : "(\$b->{$name} || $df) $op (\$a->{$name} || $df)"; + } + } + return sub { return @_ } unless @criteria; + my $sub = eval 'sub { sort {' . join("||", @criteria) . '} @_; }'; + die if $EVAL_ERROR; + return $sub; +} + +# trunc {{{3 +# Shortens text to specified length. +sub trunc { + my ( $text, $len ) = @_; + if ( length($text) <= $len ) { + return $text; + } + return substr($text, 0, $len); +} + +# donut {{{3 +# Takes out the middle of text to shorten it. +sub donut { + my ( $text, $len ) = @_; + return $text if length($text) <= $len; + my $max = length($text) - $len; + my $min = $max - 1; + + # Try to remove a single "word" from somewhere in the center + if ( $text =~ s/_[^_]{$min,$max}_/_/ ) { + return $text; + } + + # Prefer removing the end of a "word" + if ( $text =~ s/([^_]+)[^_]{$max}_/$1_/ ) { + return $text; + } + + $text = substr($text, 0, int($len/2)) + . "_" + . substr($text, int($len/2) + $max + 1); + return $text; +} + +# crunch {{{3 +# Removes vowels and compacts repeated letters to shorten text. +sub crunch { + my ( $text, $len ) = @_; + return $text if $len && length($text) <= $len; + $text =~ s/^IB_\w\w_//; + $text =~ s/(?{val}; + if ( $charset && $charset eq 'unicode' ) { + $text =~ s/ + ("(?:(?!(?{val} ) { + unshift @$display_lines, create_statusbar(); + } + + foreach my $listener ( @{$event_listener_for{draw_screen}} ) { + $listener->draw_screen($display_lines); + } + + $clear_screen_sub->() + if $prefs->{clear} || !$modes{$config{mode}->{val}}->{no_clear_screen}; + if ( $opts{n} || $prefs->{raw} ) { + my $num_lines = 0; + print join("\n", + map { + $num_lines++; + ref $_ + ? colored($_->[0], $_->[1]) + : $_; + } + grep { !$opts{n} || $_ } # Suppress empty lines + @$display_lines); + if ( $opts{n} && $num_lines ) { + print "\n"; + } + } + else { + my $max_lines = $prefs->{show_all} + ? scalar(@$display_lines)- 1 + : min(scalar(@$display_lines), $this_term_size[1]); + print join("\n", + map { + ref $_ + ? colored(substr($_->[0], 0, $this_term_size[0]), $_->[1]) + : substr($_, 0, $this_term_size[0]); + } @$display_lines[0..$max_lines - 1]); + } +} + +# secs_to_time {{{3 +sub secs_to_time { + my ( $secs, $fmt ) = @_; + $secs ||= 0; + return '00:00' unless $secs; + + # Decide what format to use, if not given + $fmt ||= $secs >= 86_400 ? 'd' + : $secs >= 3_600 ? 'h' + : 'm'; + + return + $fmt eq 'd' ? sprintf( + "%d+%02d:%02d:%02d", + int($secs / 86_400), + int(($secs % 86_400) / 3_600), + int(($secs % 3_600) / 60), + $secs % 60) + : $fmt eq 'h' ? sprintf( + "%02d:%02d:%02d", + int(($secs % 86_400) / 3_600), + int(($secs % 3_600) / 60), + $secs % 60) + : sprintf( + "%02d:%02d", + int(($secs % 3_600) / 60), + $secs % 60); +} + +# dulint_to_int {{{3 +# Takes a number that InnoDB formats as two ulint integers, like transaction IDs +# and such, and turns it into a single integer +sub dulint_to_int { + my $num = shift; + return 0 unless $num; + my ( $high, $low ) = $num =~ m/^(\d+) (\d+)$/; + return $low unless $high; + return $low + ( $high * $MAX_ULONG ); +} + +# create_statusbar {{{3 +sub create_statusbar { + my $mode = $config{mode}->{val}; + my @cxns = sort { $a cmp $b } get_connections(); + + my $modeline = ( $config{readonly}->{val} ? '[RO] ' : '' ) + . $modes{$mode}->{hdr} . " (? for help)"; + my $mode_width = length($modeline); + my $remaining_width = $this_term_size[0] - $mode_width - 1; + my $result; + + # The thingie in top-right that says what we're monitoring. + my $cxn = ''; + + if ( 1 == @cxns && $dbhs{$cxns[0]} && $dbhs{$cxns[0]}->{dbh} ) { + $cxn = $dbhs{$cxns[0]}->{dbh}->{mysql_serverinfo} || ''; + } + else { + if ( $modes{$mode}->{server_group} ) { + $cxn = "Servers: " . $modes{$mode}->{server_group}; + my $err_count = grep { $dbhs{$_} && $dbhs{$_}->{err_count} } @cxns; + if ( $err_count ) { + $cxn .= "(" . ( scalar(@cxns) - $err_count ) . "/" . scalar(@cxns) . ")"; + } + } + else { + $cxn = join(' ', map { ($dbhs{$_}->{err_count} ? '!' : '') . $_ } + grep { $dbhs{$_} } @cxns); + } + } + + if ( 1 == @cxns ) { + get_driver_status(@cxns); + my $vars = $vars{$cxns[0]}->{$clock}; + my $inc = inc(0, $cxns[0]); + + # Format server uptime human-readably, calculate QPS... + my $uptime = secs_to_time( $vars->{Uptime_hires} ); + my $qps = ($inc->{Questions}||0) / ($inc->{Uptime_hires}||1); + my $ibinfo = ''; + + if ( exists $vars->{IB_last_secs} ) { + $ibinfo .= "InnoDB $vars->{IB_last_secs}s "; + if ( $vars->{IB_got_all} ) { + if ( ($mode eq 'T' || $mode eq 'W') + && $vars->{IB_tx_is_truncated} ) { + $ibinfo .= ':^|'; + } + else { + $ibinfo .= ':-)'; + } + } + else { + $ibinfo .= ':-('; + } + } + $result = sprintf( + "%-${mode_width}s %${remaining_width}s", + $modeline, + join(', ', grep { $_ } ( + $cxns[0], + $uptime, + $ibinfo, + shorten($qps) . " QPS", + ($vars->{Threads} || 0) . "/" . ($vars->{Threads_running} || 0) . "/" . ($vars->{Threads_cached} || 0) . " con/run/cac thds", + $cxn))); + } + else { + $result = sprintf( + "%-${mode_width}s %${remaining_width}s", + $modeline, + $cxn); + } + + return $config{color}->{val} ? [ $result, 'bold reverse' ] : $result; +} + +# Database connections {{{3 +sub add_new_dsn { + my ( $name, $dsn, $dl_table, $have_user, $user, $have_pass, $pass, $savepass ) = @_; + + if ( defined $name ) { + $name =~ s/[\s:;]//g; + } + + if ( !$name ) { + print word_wrap("Choose a name for the connection. It cannot contain " + . "whitespace, colons or semicolons."), "\n\n"; + do { + $name = prompt("Enter a name"); + $name =~ s/[\s:;]//g; + } until ( $name ); + } + + if ( !$dsn ) { + do { + $clear_screen_sub->(); + print "Typical DSN strings look like\n DBI:mysql:;host=hostname;port=port\n" + . "The db and port are optional and can usually be omitted.\n" + . "If you specify 'mysql_read_default_group=mysql' many options can be read\n" + . "from your mysql options files (~/.my.cnf, /etc/my.cnf).\n\n"; + $dsn = prompt("Enter a DSN string", undef, "DBI:mysql:;mysql_read_default_group=mysql;host=$name"); + } until ( $dsn ); + } + if ( !$dl_table ) { + $clear_screen_sub->(); + my $dl_table = prompt("Optional: enter a table (must not exist) to use when resetting InnoDB deadlock information", + undef, 'test.innotop_dl'); + } + + $connections{$name} = { + dsn => $dsn, + dl_table => $dl_table, + have_user => $have_user, + user => $user, + have_pass => $have_pass, + pass => $pass, + savepass => $savepass + }; +} + +sub add_new_server_group { + my ( $name ) = @_; + + if ( defined $name ) { + $name =~ s/[\s:;]//g; + } + + if ( !$name ) { + print word_wrap("Choose a name for the group. It cannot contain " + . "whitespace, colons or semicolons."), "\n\n"; + do { + $name = prompt("Enter a name"); + $name =~ s/[\s:;]//g; + } until ( $name ); + } + + my @cxns; + do { + $clear_screen_sub->(); + @cxns = select_cxn("Choose servers for $name", keys %connections); + } until ( @cxns ); + + $server_groups{$name} = \@cxns; + return $name; +} + +sub get_var_set { + my ( $name ) = @_; + while ( !$name || !exists($var_sets{$config{$name}->{val}}) ) { + $name = choose_var_set($name); + } + return $var_sets{$config{$name}->{val}}->{text}; +} + +sub add_new_var_set { + my ( $name ) = @_; + + if ( defined $name ) { + $name =~ s/\W//g; + } + + if ( !$name ) { + do { + $name = prompt("Enter a name"); + $name =~ s/\W//g; + } until ( $name ); + } + + my $variables; + do { + $clear_screen_sub->(); + $variables = prompt("Enter variables for $name", undef ); + } until ( $variables ); + + $var_sets{$name} = { text => $variables, user => 1 }; +} + +sub next_server { + my $mode = $config{mode}->{val}; + my @cxns = sort keys %connections; + my ($cur) = get_connections($mode); + $cur ||= $cxns[0]; + my $pos = grep { $_ lt $cur } @cxns; + my $newpos = ($pos + 1) % @cxns; + $modes{$mode}->{server_group} = ''; + $modes{$mode}->{connections} = [ $cxns[$newpos] ]; + $clear_screen_sub->(); +} + +sub next_server_group { + my $mode = shift || $config{mode}->{val}; + my @grps = sort keys %server_groups; + my $curr = $modes{$mode}->{server_group}; + + return unless @grps; + + if ( $curr ) { + # Find the current group's position. + my $pos = 0; + while ( $curr ne $grps[$pos] ) { + $pos++; + } + $modes{$mode}->{server_group} = $grps[ ($pos + 1) % @grps ]; + } + else { + $modes{$mode}->{server_group} = $grps[0]; + } +} + +# Get a list of connection names used in this mode. +sub get_connections { + if ( $file ) { + return qw(file); + } + my $mode = shift || $config{mode}->{val}; + my @connections = $modes{$mode}->{server_group} + ? @{$server_groups{$modes{$mode}->{server_group}}} + : @{$modes{$mode}->{connections}}; + if ( $modes{$mode}->{one_connection} ) { + @connections = @connections ? $connections[0] : (); + } + return unique(@connections); +} + +# Get a list of tables used in this mode. If innotop is running non-interactively, just use the first. +sub get_visible_tables { + my $mode = shift || $config{mode}->{val}; + my @tbls = @{$modes{$mode}->{visible_tables}}; + if ( $opts{n} ) { + return $tbls[0]; + } + else { + return @tbls; + } +} + +# Choose from among available connections or server groups. +# If the mode has a server set in use, prefers that instead. +sub choose_connections { + $clear_screen_sub->(); + my $mode = $config{mode}->{val}; + my $meta = { map { $_ => $connections{$_}->{dsn} } keys %connections }; + foreach my $group ( keys %server_groups ) { + $meta->{"#$group"} = join(' ', @{$server_groups{$group}}); + } + + my $choices = prompt_list("Choose connections or a group for $mode mode", + undef, sub { return keys %$meta }, $meta); + + my @choices = unique(grep { $_ } split(/\s+/, $choices)); + if ( @choices ) { + if ( $choices[0] =~ s/^#// && exists $server_groups{$choices[0]} ) { + $modes{$mode}->{server_group} = $choices[0]; + } + else { + $modes{$mode}->{connections} = [ grep { exists $connections{$_} } @choices ]; + } + } +} + +# Accepts a DB connection name and the name of a prepared query (e.g. status, kill). +# Also a list of params for the prepared query. This allows not storing prepared +# statements globally. Returns a $sth that's been executed. +# ERROR-HANDLING SEMANTICS: if the statement throws an error, propagate, but if the +# connection has gone away or can't connect, DO NOT. Just return undef. +sub do_stmt { + my ( $cxn, $stmt_name, @args ) = @_; + + return undef if $file; + + # Test if the cxn should not even be tried + return undef if $dbhs{$cxn} + && $dbhs{$cxn}->{err_count} + && ( !$dbhs{$cxn}->{dbh} || !$dbhs{$cxn}->{dbh}->{Active} || $dbhs{$cxn}->{mode} eq $config{mode}->{val} ) + && $dbhs{$cxn}->{wake_up} > $clock; + + my $sth; + my $retries = 1; + my $success = 0; + TRY: + while ( $retries-- >= 0 && !$success ) { + + eval { + my $dbh = connect_to_db($cxn); + + # If the prepared query doesn't exist, make it. + if ( !exists $dbhs{$cxn}->{stmts}->{$stmt_name} ) { + $dbhs{$cxn}->{stmts}->{$stmt_name} = $stmt_maker_for{$stmt_name}->($dbh); + } + + $sth = $dbhs{$cxn}->{stmts}->{$stmt_name}; + if ( $sth ) { + $sth->execute(@args); + } + $success = 1; + }; + if ( $EVAL_ERROR ) { + if ( $EVAL_ERROR =~ m/$nonfatal_errs/ ) { + handle_cxn_error($cxn, $EVAL_ERROR); + } + else { + die "$cxn $stmt_name: $EVAL_ERROR"; + } + if ( $retries < 0 ) { + $sth = undef; + } + } + } + + if ( $sth && $sth->{NUM_OF_FIELDS} ) { + sleep($stmt_sleep_time_for{$stmt_name}) if $stmt_sleep_time_for{$stmt_name}; + return $sth; + } +} + +# Keeps track of error count, sleep times till retries, etc etc. +# When there's an error we retry the connection every so often, increasing in +# Fibonacci series to prevent too much banging on the server. +sub handle_cxn_error { + my ( $cxn, $err ) = @_; + my $meta = $dbhs{$cxn}; + $meta->{err_count}++; + + # This is used so errors that have to do with permissions needed by the current + # mode will get displayed as long as we're in this mode, but get ignored if the + # mode changes. + $meta->{mode} = $config{mode}->{val}; + + # Strip garbage from the error text if possible. + $err =~ s/\s+/ /g; + if ( $err =~ m/failed: (.*?) at \S*innotop line/ ) { + $err = $1; + } + + $meta->{last_err} = $err; + my $sleep_time = $meta->{this_sleep} + $meta->{prev_sleep}; + $meta->{prev_sleep} = $meta->{this_sleep}; + $meta->{this_sleep} = $sleep_time; + $meta->{wake_up} = $clock + $sleep_time; + if ( $config{show_cxn_errors}->{val} ) { + print STDERR "Error at tick $clock $cxn $err" if $config{debug}->{val}; + } +} + +# Accepts a DB connection name and a (string) query. Returns a $sth that's been +# executed. +sub do_query { + my ( $cxn, $query ) = @_; + + return undef if $file; + + # Test if the cxn should not even be tried + return undef if $dbhs{$cxn} + && $dbhs{$cxn}->{err_count} + && ( !$dbhs{$cxn}->{dbh} || !$dbhs{$cxn}->{dbh}->{Active} || $dbhs{$cxn}->{mode} eq $config{mode}->{val} ) + && $dbhs{$cxn}->{wake_up} > $clock; + + my $sth; + my $retries = 1; + my $success = 0; + TRY: + while ( $retries-- >= 0 && !$success ) { + + eval { + my $dbh = connect_to_db($cxn); + + $sth = $dbh->prepare($query); + $sth->execute(); + $success = 1; + }; + if ( $EVAL_ERROR ) { + if ( $EVAL_ERROR =~ m/$nonfatal_errs/ ) { + handle_cxn_error($cxn, $EVAL_ERROR); + } + else { + die $EVAL_ERROR; + } + if ( $retries < 0 ) { + $sth = undef; + } + } + } + + return $sth; +} + +sub get_uptime { + my ( $cxn ) = @_; + $dbhs{$cxn}->{start_time} ||= time(); + # Avoid dividing by zero + return (time() - $dbhs{$cxn}->{start_time}) || .001; +} + +sub connect_to_db { + my ( $cxn ) = @_; + + $dbhs{$cxn} ||= { + stmts => {}, # bucket for prepared statements. + prev_sleep => 0, + this_sleep => 1, + wake_up => 0, + start_time => 0, + dbh => undef, + }; + my $href = $dbhs{$cxn}; + + if ( !$href->{dbh} || ref($href->{dbh}) !~ m/DBI/ || !$href->{dbh}->ping ) { + my $dbh = get_new_db_connection($cxn); + @{$href}{qw(dbh err_count wake_up this_sleep start_time prev_sleep)} + = ($dbh, 0, 0, 1, 0, 0); + + # Derive and store the server's start time in hi-res + my $uptime = $dbh->selectrow_hashref("show status like 'Uptime'")->{value}; + $href->{start_time} = time() - $uptime; + + # Set timeouts so an unused connection stays alive. + # For example, a connection might be used in Q mode but idle in T mode. + if ( version_ge($dbh, '4.0.3')) { + my $timeout = $config{cxn_timeout}->{val}; + $dbh->do("set session wait_timeout=$timeout, interactive_timeout=$timeout"); + } + } + return $href->{dbh}; +} + +# Compares versions like 5.0.27 and 4.1.15-standard-log +sub version_ge { + my ( $dbh, $target ) = @_; + my $version = sprintf('%03d%03d%03d', $dbh->{mysql_serverinfo} =~ m/(\d+)/g); + return $version ge sprintf('%03d%03d%03d', $target =~ m/(\d+)/g); +} + +# Extracts status values that can be gleaned from the DBD driver without doing a whole query. +sub get_driver_status { + my @cxns = @_; + if ( !$info_gotten{driver_status}++ ) { + foreach my $cxn ( @cxns ) { + next unless $dbhs{$cxn} && $dbhs{$cxn}->{dbh} && $dbhs{$cxn}->{dbh}->{Active}; + $vars{$cxn}->{$clock} ||= {}; + my $vars = $vars{$cxn}->{$clock}; + my %res = map { $_ =~ s/ +/_/g; $_ } $dbhs{$cxn}->{dbh}->{mysql_stat} =~ m/(\w[^:]+): ([\d\.]+)/g; + map { $vars->{$_} ||= $res{$_} } keys %res; + $vars->{Uptime_hires} ||= get_uptime($cxn); + $vars->{cxn} = $cxn; + } + } +} + +sub get_new_db_connection { + my ( $connection, $destroy ) = @_; + if ( $file ) { + die "You can't connect to a MySQL server while monitoring a file. This is probably a bug."; + } + + my $dsn = $connections{$connection} + or die "No connection named '$connection' is defined in your configuration"; + + # don't ask for a username if mysql_read_default_group=client is in the DSN + if ( !defined $dsn->{have_user} and $dsn->{dsn} !~ /mysql_read_default_group=client/ ) { + my $answer = prompt("Do you want to specify a username for $connection?", undef, 'n'); + $dsn->{have_user} = $answer && $answer =~ m/1|y/i; + } + + # don't ask for a password if mysql_read_default_group=client is in the DSN + if ( !defined $dsn->{have_pass} and $dsn->{dsn} !~ /mysql_read_default_group=client/ ) { + my $answer = prompt("Do you want to specify a password for $connection?", undef, 'n'); + $dsn->{have_pass} = $answer && $answer =~ m/1|y/i; + } + + if ( !$dsn->{user} && $dsn->{have_user} ) { + my $user = $ENV{USERNAME} || $ENV{USER} || getlogin() || getpwuid($REAL_USER_ID) || undef; + $dsn->{user} = prompt("Enter username for $connection", undef, $user); + } + + if ( !defined $dsn->{user} ) { + $dsn->{user} = ''; + } + + if ( !$dsn->{pass} && !$dsn->{savepass} && $dsn->{have_pass} ) { + $dsn->{pass} = prompt_noecho("Enter password for '$dsn->{user}' on $connection"); + print "\n"; + if ( !defined($dsn->{savepass}) ) { + my $answer = prompt("Save password in plain text in the config file?", undef, 'y'); + $dsn->{savepass} = $answer && $answer =~ m/1|y/i; + } + } + + my $dbh = DBI->connect( + $dsn->{dsn}, $dsn->{user}, $dsn->{pass}, + { RaiseError => 1, PrintError => 0, AutoCommit => 1 }); + $dbh->{InactiveDestroy} = 1 unless $destroy; # Can't be set in $db_options + $dbh->{FetchHashKeyName} = 'NAME_lc'; # Lowercases all column names for fetchrow_hashref + return $dbh; +} + +sub get_cxn_errors { + my @cxns = @_; + return () unless $config{show_cxn_errors_in_tbl}->{val}; + return + map { [ $_ . ': ' . $dbhs{$_}->{last_err}, 'red' ] } + grep { $dbhs{$_} && $dbhs{$_}->{err_count} && $dbhs{$_}->{mode} eq $config{mode}->{val} } + @cxns; +} + +# Setup and tear-down functions {{{2 + +# Takes a string and turns it into a hashref you can apply to %tbl_meta tables. The string +# can be in the form 'foo, bar, foo/bar, foo as bar' much like a SQL SELECT statement. +sub compile_select_stmt { + my ($str) = @_; + my @exps = $str =~ m/\s*([^,]+(?i:\s+as\s+[^,\s]+)?)\s*(?=,|$)/g; + my %cols; + my @visible; + foreach my $exp ( @exps ) { + my ( $text, $colname ); + if ( $exp =~ m/as\s+(\w+)\s*/ ) { + $colname = $1; + $exp =~ s/as\s+(\w+)\s*//; + $text = $exp; + } + else { + $text = $colname = $exp; + } + my ($func, $err) = compile_expr($text); + $cols{$colname} = { + src => $text, + hdr => $colname, + num => 0, + func => $func, + }; + push @visible, $colname; + } + return (\%cols, \@visible); +} + +# compile_filter {{{3 +sub compile_filter { + my ( $text ) = @_; + my ( $sub, $err ); + eval "\$sub = sub { my \$set = shift; $text }"; + if ( $EVAL_ERROR ) { + $EVAL_ERROR =~ s/at \(eval.*$//; + $sub = sub { return $EVAL_ERROR }; + $err = $EVAL_ERROR; + } + return ( $sub, $err ); +} + +# compile_expr {{{3 +sub compile_expr { + my ( $expr ) = @_; + # Leave built-in functions alone so they get called as Perl functions, unless + # they are the only word in $expr, in which case treat them as hash keys. + if ( $expr =~ m/\W/ ) { + $expr =~ s/(?{$1}"/eg; + } + else { + $expr = "\$set->{$expr}"; + } + my ( $sub, $err ); + my $quoted = quotemeta($expr); + eval qq{ + \$sub = sub { + my (\$set, \$cur, \$pre) = \@_; + my \$val = eval { $expr }; + if ( \$EVAL_ERROR && \$config{debug}->{val} ) { + \$EVAL_ERROR =~ s/ at \\(eval.*//s; + die "\$EVAL_ERROR in expression $quoted"; + } + return \$val; + } + }; + if ( $EVAL_ERROR ) { + if ( $config{debug}->{val} ) { + die $EVAL_ERROR; + } + $EVAL_ERROR =~ s/ at \(eval.*$//; + $sub = sub { return $EVAL_ERROR }; + $err = $EVAL_ERROR; + } + return ( $sub, $err ); +} + +# finish {{{3 +# This is a subroutine because it's called from a key to quit the program. +sub finish { + save_config(); + ReadMode('normal') unless $opts{n}; + print "\n"; + exit(0); +} + +# core_dump {{{3 +sub core_dump { + my $msg = shift; + if ($config{debugfile}->{val} && $config{debug}->{val}) { + eval { + open my $file, '>>', $config{debugfile}->{val}; + if ( %vars ) { + print $file "Current variables:\n" . Dumper(\%vars); + } + close $file; + }; + } + print $msg; +} + +# migrate_config {{{3 +sub migrate_config { + + my ($old_filename, $new_filename) = @_; + + # don't proceed if old file doesn't exist + if ( ! -f $old_filename ) { + die "Error migrating '$old_filename': file doesn't exist.\n"; + } + # don't migrate files if new file exists + elsif ( -f $new_filename ) { + die "Error migrating '$old_filename' to '$new_filename': new file already exists.\n"; + } + # if migrating from one file to another in the same directory, just rename them + if (dirname($old_filename) eq dirname($new_filename)) { + rename($old_filename, $new_filename) + or die "Can't rename '$old_filename' to '$new_filename': $OS_ERROR"; + } + # otherwise, move the existing conf file to a temp file, make the necessary directory structure, + # and move the temp conf file to its new home + else { + my $tmp = File::Temp->new( TEMPLATE => 'innotopXXXXX', DIR => $homepath, SUFFIX => '.conf'); + my $tmp_filename = $tmp->filename; + my $dirname = dirname($new_filename); + rename($old_filename, $tmp_filename) + or die "Can't rename '$old_filename' to '$tmp_filename': $OS_ERROR"; + mkdir($dirname) or die "Can't create directory '$dirname': $OS_ERROR"; + mkdir("$dirname/plugins") or die "Can't create directory '$dirname/plugins': $OS_ERROR"; + rename($tmp_filename, $new_filename) + or die "Can't rename '$tmp_filename' to '$new_filename': $OS_ERROR"; + } +} + +# load_config {{{3 +sub load_config { + + my ($old_filename, $answer); + + if ( $opts{u} or $opts{p} or $opts{h} or $opts{P} ) { + my @params = $dsn_parser->get_cxn_params(\%opts); # dsn=$params[0] + add_new_dsn($opts{h} || 'localhost', $params[0], 'test.innotop_dl', + $opts{u} ? 1 : 0, $opts{u}, $opts{p} ? 1 : 0, $opts{p}); + } + if ($opts{c}) { + $conf_file = $opts{c}; + } + # innotop got upgraded and this is an old config file. + elsif ( -f "$homepath/.innotop" or -f "$homepath/.innotop/innotop.ini" ) { + $conf_file = $default_home_conf; + if ( -f "$homepath/.innotop") { + $old_filename = "$homepath/.innotop"; + } + elsif ( -f "$homepath/.innotop/innotop.ini" ) { + $old_filename = "$homepath/.innotop/innotop.ini"; + } + $answer = pause("Innotop's default config location has moved to '$conf_file'. Move old config file '$old_filename' there now? y/n"); + if ( lc $answer eq 'y' ) { + migrate_config($old_filename, $conf_file); + } + else { + print "\nInnotop will now exit so you can fix the config file.\n"; + exit(0); + } + } + elsif ( -f $default_home_conf ) { + $conf_file = $default_home_conf; + } + elsif ( -f $default_central_conf and not $opts{s} ) { + $conf_file = $default_central_conf; + } + else { + # If no config file was loaded, set readonly to 0 if the user wants to + # write a config + $config{readonly}->{val} = 0 if $opts{w}; + # If no connections have been defined, connect to a MySQL database + # on localhost using mysql_read_default_group=client + if (!%connections) { + add_new_dsn('localhost', + 'DBI:mysql:;host=localhost;mysql_read_default_group=client', + 'test.innotop_dl'); + } + } + + if ( -f "$conf_file" ) { + open my $file, "<", $conf_file or die("Can't open '$conf_file': $OS_ERROR"); + + # Check config file version. Just ignore if either innotop or the file has + # garbage in the version number. + if ( defined(my $line = <$file>) && $VERSION =~ m/\d/ ) { + chomp $line; + if ( my ($maj, $min, $rev) = $line =~ m/^version=(\d+)\.(\d+)(?:\.(\d+))?$/ ) { + $rev ||= 0; + my $cfg_ver = sprintf('%03d-%03d-%03d', $maj, $min, $rev); + ( $maj, $min, $rev ) = $VERSION =~ m/^(\d+)\.(\d+)(?:\.(\d+))?$/; + $rev ||= 0; + my $innotop_ver = sprintf('%03d-%03d-%03d', $maj, $min, $rev); + + if ( $cfg_ver gt $innotop_ver ) { + pause("The config file is for a newer version of innotop and may not be read correctly."); + } + else { + my @ver_history = @config_versions; + while ( my ($start, $end) = splice(@ver_history, 0, 2) ) { + # If the config file is between the endpoints and innotop is greater than + # the endpoint, innotop has a newer config file format than the file. + if ( $cfg_ver ge $start && $cfg_ver lt $end && $innotop_ver ge $end ) { + my $msg = "innotop's config file format has changed. Overwrite $conf_file? y or n"; + if ( pause($msg) eq 'n' ) { + $config{readonly}->{val} = 1; + print "\ninnotop will not save any configuration changes you make."; + pause(); + print "\n"; + } + close $file; + return; + } + } + } + } + } + + while ( my $line = <$file> ) { + chomp $line; + next unless $line =~ m/^\[([a-z_]+)\]$/; + if ( exists $config_file_sections{$1} ) { + $config_file_sections{$1}->{reader}->($file); + } + else { + warn "Unknown config file section '$1'"; + } + } + close $file or die("Can't close $conf_file: $OS_ERROR"); + } + +} + +# Do some post-processing on %tbl_meta: compile src properties into func etc. +sub post_process_tbl_meta { + foreach my $table ( values %tbl_meta ) { + foreach my $col_name ( keys %{$table->{cols}} ) { + my $col_def = $table->{cols}->{$col_name}; + my ( $sub, $err ) = compile_expr($col_def->{src}); + $col_def->{func} = $sub; + } + } +} + +# load_config_plugins {{{3 +sub load_config_plugins { + my ( $file ) = @_; + + # First, find a list of all plugins that exist on disk, and get information about them. + my $dir = $config{plugin_dir}->{val}; + foreach my $p_file ( <$dir/*.pm> ) { + my ($package, $desc); + eval { + open my $p_in, "<", $p_file or die $OS_ERROR; + while ( my $line = <$p_in> ) { + chomp $line; + if ( $line =~ m/^package\s+(.*?);/ ) { + $package = $1; + } + elsif ( $line =~ m/^# description: (.*)/ ) { + $desc = $1; + } + last if $package && $desc; + } + close $p_in; + }; + if ( $package ) { + $plugins{$package} = { + file => $p_file, + desc => $desc, + class => $package, + active => 0, + }; + if ( $config{debug}->{val} && $EVAL_ERROR ) { + die $EVAL_ERROR; + } + } + } + + # Now read which ones the user has activated. Each line simply represents an active plugin. + while ( my $line = <$file> ) { + chomp $line; + next if $line =~ m/^#/; + last if $line =~ m/^\[/; + next unless $line && $plugins{$line}; + + my $obj; + eval { + require $plugins{$line}->{file}; + $obj = $line->new(%pluggable_vars); + foreach my $event ( $obj->register_for_events() ) { + my $queue = $event_listener_for{$event}; + if ( $queue ) { + push @$queue, $obj; + } + } + }; + if ( $config{debug}->{val} && $EVAL_ERROR ) { + die $EVAL_ERROR; + } + if ( $obj ) { + $plugins{$line}->{active} = 1; + $plugins{$line}->{object} = $obj; + } + } +} + +# save_config_plugins {{{3 +sub save_config_plugins { + my $file = shift; + foreach my $class ( sort keys %plugins ) { + next unless $plugins{$class}->{active}; + print $file "$class\n"; + } +} + +# load_config_active_server_groups {{{3 +sub load_config_active_server_groups { + my ( $file ) = @_; + while ( my $line = <$file> ) { + chomp $line; + next if $line =~ m/^#/; + last if $line =~ m/^\[/; + + my ( $mode, $group ) = $line =~ m/^(.*?)=(.*)$/; + next unless $mode && $group + && exists $modes{$mode} && exists $server_groups{$group}; + $modes{$mode}->{server_group} = $group; + } +} + +# save_config_active_server_groups {{{3 +sub save_config_active_server_groups { + my $file = shift; + foreach my $mode ( sort keys %modes ) { + print $file "$mode=$modes{$mode}->{server_group}\n"; + } +} + +# load_config_server_groups {{{3 +sub load_config_server_groups { + my ( $file ) = @_; + while ( my $line = <$file> ) { + chomp $line; + next if $line =~ m/^#/; + last if $line =~ m/^\[/; + + my ( $name, $rest ) = $line =~ m/^(.*?)=(.*)$/; + next unless $name && $rest; + my @vars = unique(grep { $_ && exists $connections{$_} } split(/\s+/, $rest)); + next unless @vars; + $server_groups{$name} = \@vars; + } +} + +# save_config_server_groups {{{3 +sub save_config_server_groups { + my $file = shift; + foreach my $set ( sort keys %server_groups ) { + print $file "$set=", join(' ', @{$server_groups{$set}}), "\n"; + } +} + +# load_config_varsets {{{3 +sub load_config_varsets { + my ( $file ) = @_; + while ( my $line = <$file> ) { + chomp $line; + next if $line =~ m/^#/; + last if $line =~ m/^\[/; + + my ( $name, $rest ) = $line =~ m/^(.*?)=(.*)$/; + next unless $name && $rest; + $var_sets{$name} = { + text => $rest, + user => 1, + }; + } +} + +# save_config_varsets {{{3 +sub save_config_varsets { + my $file = shift; + foreach my $varset ( sort keys %var_sets ) { + next unless $var_sets{$varset}->{user}; + print $file "$varset=$var_sets{$varset}->{text}\n"; + } +} + +# load_config_group_by {{{3 +sub load_config_group_by { + my ( $file ) = @_; + while ( my $line = <$file> ) { + chomp $line; + next if $line =~ m/^#/; + last if $line =~ m/^\[/; + + my ( $tbl , $rest ) = $line =~ m/^(.*?)=(.*)$/; + next unless $tbl && exists $tbl_meta{$tbl}; + my @parts = unique(grep { exists($tbl_meta{$tbl}->{cols}->{$_}) } split(/\s+/, $rest)); + $tbl_meta{$tbl}->{group_by} = [ @parts ]; + $tbl_meta{$tbl}->{cust}->{group_by} = 1; + } +} + +# save_config_group_by {{{3 +sub save_config_group_by { + my $file = shift; + foreach my $tbl ( sort keys %tbl_meta ) { + next if $tbl_meta{$tbl}->{temp}; + next unless $tbl_meta{$tbl}->{cust}->{group_by}; + my $aref = $tbl_meta{$tbl}->{group_by}; + print $file "$tbl=", join(' ', @$aref), "\n"; + } +} + +# load_config_filters {{{3 +sub load_config_filters { + my ( $file ) = @_; + while ( my $line = <$file> ) { + chomp $line; + next if $line =~ m/^#/; + last if $line =~ m/^\[/; + + my ( $key, $rest ) = $line =~ m/^(.+?)=(.*)$/; + next unless $key && $rest; + + my %parts = $rest =~ m/(\w+)='((?:(?!(? $sub, + text => $parts{text}, + user => 1, + name => $key, + note => 'User-defined filter', + tbls => \@tbls, + } + } +} + +# save_config_filters {{{3 +sub save_config_filters { + my $file = shift; + foreach my $key ( sort keys %filters ) { + next if !$filters{$key}->{user} || $filters{$key}->{quick}; + my $text = $filters{$key}->{text}; + $text =~ s/([\\'])/\\$1/g; + my $tbls = join(" ", @{$filters{$key}->{tbls}}); + print $file "$key=text='$text' tbls='$tbls'\n"; + } +} + +# load_config_visible_tables {{{3 +sub load_config_visible_tables { + my ( $file ) = @_; + while ( my $line = <$file> ) { + chomp $line; + next if $line =~ m/^#/; + last if $line =~ m/^\[/; + + my ( $mode, $rest ) = $line =~ m/^(.*?)=(.*)$/; + next unless $mode && exists $modes{$mode}; + $modes{$mode}->{visible_tables} = + [ unique(grep { $_ && exists $tbl_meta{$_} } split(/\s+/, $rest)) ]; + $modes{$mode}->{cust}->{visible_tables} = 1; + } +} + +# save_config_visible_tables {{{3 +sub save_config_visible_tables { + my $file = shift; + foreach my $mode ( sort keys %modes ) { + next unless $modes{$mode}->{cust}->{visible_tables}; + my $tables = $modes{$mode}->{visible_tables}; + print $file "$mode=", join(' ', @$tables), "\n"; + } +} + +# load_config_sort_cols {{{3 +sub load_config_sort_cols { + my ( $file ) = @_; + while ( my $line = <$file> ) { + chomp $line; + next if $line =~ m/^#/; + last if $line =~ m/^\[/; + + my ( $key , $rest ) = $line =~ m/^(.*?)=(.*)$/; + next unless $key && exists $tbl_meta{$key}; + $tbl_meta{$key}->{sort_cols} = $rest; + $tbl_meta{$key}->{cust}->{sort_cols} = 1; + $tbl_meta{$key}->{sort_func} = make_sort_func($tbl_meta{$key}); + } +} + +# save_config_sort_cols {{{3 +sub save_config_sort_cols { + my $file = shift; + foreach my $tbl ( sort keys %tbl_meta ) { + next unless $tbl_meta{$tbl}->{cust}->{sort_cols}; + my $col = $tbl_meta{$tbl}->{sort_cols}; + print $file "$tbl=$col\n"; + } +} + +# load_config_active_filters {{{3 +sub load_config_active_filters { + my ( $file ) = @_; + while ( my $line = <$file> ) { + chomp $line; + next if $line =~ m/^#/; + last if $line =~ m/^\[/; + + my ( $tbl , $rest ) = $line =~ m/^(.*?)=(.*)$/; + next unless $tbl && exists $tbl_meta{$tbl}; + my @parts = unique(grep { exists($filters{$_}) } split(/\s+/, $rest)); + @parts = grep { grep { $tbl eq $_ } @{$filters{$_}->{tbls}} } @parts; + $tbl_meta{$tbl}->{filters} = [ @parts ]; + $tbl_meta{$tbl}->{cust}->{filters} = 1; + } +} + +# save_config_active_filters {{{3 +sub save_config_active_filters { + my $file = shift; + foreach my $tbl ( sort keys %tbl_meta ) { + next if $tbl_meta{$tbl}->{temp}; + next unless $tbl_meta{$tbl}->{cust}->{filters}; + my $aref = $tbl_meta{$tbl}->{filters}; + print $file "$tbl=", join(' ', @$aref), "\n"; + } +} + +# load_config_active_columns {{{3 +sub load_config_active_columns { + my ( $file ) = @_; + while ( my $line = <$file> ) { + chomp $line; + next if $line =~ m/^#/; + last if $line =~ m/^\[/; + + my ( $key , $rest ) = $line =~ m/^(.*?)=(.*)$/; + next unless $key && exists $tbl_meta{$key}; + my @parts = grep { exists($tbl_meta{$key}->{cols}->{$_}) } unique split(/ /, $rest); + $tbl_meta{$key}->{visible} = [ @parts ]; + $tbl_meta{$key}->{cust}->{visible} = 1; + } +} + +# save_config_active_columns {{{3 +sub save_config_active_columns { + my $file = shift; + foreach my $tbl ( sort keys %tbl_meta ) { + next unless $tbl_meta{$tbl}->{cust}->{visible}; + my $aref = $tbl_meta{$tbl}->{visible}; + print $file "$tbl=", join(' ', @$aref), "\n"; + } +} + +# save_config_tbl_meta {{{3 +sub save_config_tbl_meta { + my $file = shift; + foreach my $tbl ( sort keys %tbl_meta ) { + foreach my $col ( keys %{$tbl_meta{$tbl}->{cols}} ) { + my $meta = $tbl_meta{$tbl}->{cols}->{$col}; + next unless $meta->{user}; + print $file "$col=", join( + " ", + map { + # Some properties (trans) are arrays, others scalars + my $val = ref($meta->{$_}) ? join(',', @{$meta->{$_}}) : $meta->{$_}; + $val =~ s/([\\'])/\\$1/g; # Escape backslashes and single quotes + "$_='$val'"; # Enclose in single quotes + } + grep { $_ ne 'func' } + keys %$meta + ), "\n"; + } + } +} + +# save_config_config {{{3 +sub save_config_config { + my $file = shift; + foreach my $key ( sort keys %config ) { + eval { + if ( $key ne 'password' || $config{savepass}->{val} ) { + print $file "# $config{$key}->{note}\n" + or die "Cannot print to file: $OS_ERROR"; + my $val = $config{$key}->{val}; + $val = '' unless defined($val); + if ( ref( $val ) eq 'ARRAY' ) { + print $file "$key=" + . join( " ", @$val ) . "\n" + or die "Cannot print to file: $OS_ERROR"; + } + elsif ( ref( $val ) eq 'HASH' ) { + print $file "$key=" + . join( " ", + map { "$_:$val->{$_}" } keys %$val + ) . "\n"; + } + else { + print $file "$key=$val\n"; + } + } + }; + if ( $EVAL_ERROR ) { print "$EVAL_ERROR in $key"; }; + } + +} + +# load_config_config {{{3 +sub load_config_config { + my ( $file ) = @_; + + while ( my $line = <$file> ) { + chomp $line; + next if $line =~ m/^#/; + last if $line =~ m/^\[/; + + my ( $name, $val ) = $line =~ m/^(.+?)=(.*)$/; + next unless defined $name && defined $val; + + # Validate the incoming values... + if ( $name && exists( $config{$name} ) ) { + if ( !$config{$name}->{pat} || $val =~ m/$config{$name}->{pat}/ ) { + $config{$name}->{val} = $val; + $config{$name}->{read} = 1; + } + } + } +} + +# load_config_tbl_meta {{{3 +sub load_config_tbl_meta { + my ( $file ) = @_; + + while ( my $line = <$file> ) { + chomp $line; + next if $line =~ m/^#/; + last if $line =~ m/^\[/; + + # Each tbl_meta section has all the properties defined in %col_props. + my ( $col , $rest ) = $line =~ m/^(.*?)=(.*)$/; + next unless $col; + my %parts = $rest =~ m/(\w+)='((?:(?!(?{cols}->{$col} ||= {}; + + foreach my $prop ( keys %col_props ) { + if ( !defined($parts{$prop}) ) { + die "Undefined property $prop for column $col in table $tbl"; + } + + # Un-escape escaping + $parts{$prop} =~ s/\\\\/\\/g; + $parts{$prop} =~ s/\\'/'/g; + + if ( ref $col_props{$prop} ) { + if ( $prop eq 'trans' ) { + $meta->{cols}->{$col}->{trans} + = [ unique(grep { exists $trans_funcs{$_} } split(',', $parts{$prop})) ]; + } + else { + $meta->{cols}->{$col}->{$prop} = [ split(',', $parts{$prop}) ]; + } + } + else { + $meta->{cols}->{$col}->{$prop} = $parts{$prop}; + } + } + + } +} + +# save_config {{{3 +sub save_config { + print "\n"; + return if $config{readonly}->{val}; + # return if no config file was loaded and -w wasn't specified + if (not $conf_file) { + if (not $opts{w}) { + return; + } + else { + # if no config was loaded but -w was specified, + # write to $default_home_conf + $conf_file = $default_home_conf; + } + } + elsif ($conf_file and $opts{w}) { + print "Loaded config file on start-up, so ignoring -w (see --help)\n" + } + + my $dirname = dirname($conf_file); + + # if directories don't exist, create them. This could cause errors + # or warnings if a central config doesn't have readonly=1, but being + # flexible requires giving the user enough rope to hang themselves with. + if ( ! -d $dirname ) { + mkdir $dirname + or die "Can't create directory '$dirname': $OS_ERROR"; + } + if ( ! -d "$dirname/plugins" ) { + mkdir "$dirname/plugins" + or warn "Can't create directory '$dirname/plugins': $OS_ERROR\n"; + } + + # Save to a temp file first, so a crash doesn't destroy the main config file + my $tmpfile = File::Temp->new( TEMPLATE => 'innotopXXXXX', DIR => $dirname, SUFFIX => '.conf.tmp'); + open my $file, "+>", $tmpfile + or die("Can't write to $tmpfile: $OS_ERROR"); + print $file "version=$VERSION\n"; + + foreach my $section ( @ordered_config_file_sections ) { + die "No such config file section $section" unless $config_file_sections{$section}; + print $file "\n[$section]\n\n"; + $config_file_sections{$section}->{writer}->($file); + print $file "\n[/$section]\n"; + } + + # Now clobber the main config file with the temp. + close $file or die("Can't close $tmpfile: $OS_ERROR"); + rename($tmpfile, $conf_file) or die("Can't rename $tmpfile to $conf_file: $OS_ERROR"); +} + +# load_config_connections {{{3 +sub load_config_connections { + return if $opts{u} or $opts{p} or $opts{h} or $opts{P}; # don't load connections if DSN or user/pass options used + my ( $file ) = @_; + while ( my $line = <$file> ) { + chomp $line; + next if $line =~ m/^#/; + last if $line =~ m/^\[/; + + my ( $key , $rest ) = $line =~ m/^(.*?)=(.*)$/; + next unless $key; + my %parts = $rest =~ m/(\S+?)=(\S*)/g; + my %conn = map { $_ => $parts{$_} || '' } @conn_parts; + $connections{$key} = \%conn; + } +} + +# save_config_connections {{{3 +sub save_config_connections { + my $file = shift; + foreach my $conn ( sort keys %connections ) { + my $href = $connections{$conn}; + my @keys = $href->{savepass} ? @conn_parts : grep { $_ ne 'pass' } @conn_parts; + print $file "$conn=", join(' ', map { "$_=$href->{$_}" } grep { defined $href->{$_} } @keys), "\n"; + } +} + +sub load_config_colors { + my ( $file ) = @_; + my %rule_set_for; + + while ( my $line = <$file> ) { + chomp $line; + next if $line =~ m/^#/; + last if $line =~ m/^\[/; + + my ( $tbl, $rule ) = $line =~ m/^(.*?)=(.*)$/; + next unless $tbl && $rule; + next unless exists $tbl_meta{$tbl}; + my %parts = $rule =~ m/(\w+)='((?:(?!(?{cols}->{$parts{col}}; + next unless $parts{op} && exists $comp_ops{$parts{op}}; + next unless defined $parts{arg}; + next unless defined $parts{color}; + my @colors = unique(grep { exists $ansicolors{$_} } split(/\W+/, $parts{color})); + next unless @colors; + + # Finally! Enough validation... + $rule_set_for{$tbl} ||= []; + push @{$rule_set_for{$tbl}}, \%parts; + } + + foreach my $tbl ( keys %rule_set_for ) { + $tbl_meta{$tbl}->{colors} = $rule_set_for{$tbl}; + $tbl_meta{$tbl}->{color_func} = make_color_func($tbl_meta{$tbl}); + $tbl_meta{$tbl}->{cust}->{colors} = 1; + } +} + +# save_config_colors {{{3 +sub save_config_colors { + my $file = shift; + foreach my $tbl ( sort keys %tbl_meta ) { + my $meta = $tbl_meta{$tbl}; + next unless $meta->{cust}->{colors}; + foreach my $rule ( @{$meta->{colors}} ) { + print $file "$tbl=", join( + ' ', + map { + my $val = $rule->{$_}; + $val =~ s/([\\'])/\\$1/g; # Escape backslashes and single quotes + "$_='$val'"; # Enclose in single quotes + } + qw(col op arg color) + ), "\n"; + } + } +} + +# load_config_active_connections {{{3 +sub load_config_active_connections { + my ( $file ) = @_; + while ( my $line = <$file> ) { + chomp $line; + next if $line =~ m/^#/; + last if $line =~ m/^\[/; + + my ( $key , $rest ) = $line =~ m/^(.*?)=(.*)$/; + next unless $key && exists $modes{$key}; + my @parts = grep { exists $connections{$_} } split(/ /, $rest); + $modes{$key}->{connections} = [ @parts ] if exists $modes{$key}; + } +} + +# save_config_active_connections {{{3 +sub save_config_active_connections { + my $file = shift; + foreach my $mode ( sort keys %modes ) { + my @connections = get_connections($mode); + print $file "$mode=", join(' ', @connections), "\n"; + } +} + +# load_config_stmt_sleep_times {{{3 +sub load_config_stmt_sleep_times { + my ( $file ) = @_; + while ( my $line = <$file> ) { + chomp $line; + next if $line =~ m/^#/; + last if $line =~ m/^\[/; + + my ( $key , $val ) = split('=', $line); + next unless $key && defined $val && $val =~ m/$num_regex/; + $stmt_sleep_time_for{$key} = $val; + } +} + +# save_config_stmt_sleep_times {{{3 +sub save_config_stmt_sleep_times { + my $file = shift; + foreach my $key ( sort keys %stmt_sleep_time_for ) { + print $file "$key=$stmt_sleep_time_for{$key}\n"; + } +} + +# load_config_mvs {{{3 +sub load_config_mvs { + my ( $file ) = @_; + while ( my $line = <$file> ) { + chomp $line; + next if $line =~ m/^#/; + last if $line =~ m/^\[/; + + my ( $key , $val ) = split('=', $line); + next unless $key && defined $val && $val =~ m/$num_regex/; + $mvs{$key} = $val; + } +} + +# save_config_mvs {{{3 +sub save_config_mvs { + my $file = shift; + foreach my $key ( sort keys %mvs ) { + print $file "$key=$mvs{$key}\n"; + } +} + +# edit_configuration {{{3 +sub edit_configuration { + my $key = ''; + while ( $key ne 'q' ) { + $clear_screen_sub->(); + my @display_lines = ''; + + if ( $key && $cfg_editor_action{$key} ) { + $cfg_editor_action{$key}->{func}->(); + } + + # Show help + push @display_lines, create_caption('What configuration do you want to edit?', + create_table2( + [ sort keys %cfg_editor_action ], + { map { $_ => $_ } keys %cfg_editor_action }, + { map { $_ => $cfg_editor_action{$_}->{note} } keys %cfg_editor_action }, + { sep => ' ' })); + + draw_screen(\@display_lines); + $key = pause(''); + } +} + +# edit_configuration_variables {{{3 +sub edit_configuration_variables { + $clear_screen_sub->(); + my $mode = $config{mode}->{val}; + + my %config_choices + = map { $_ => $config{$_}->{note} || '' } + # Only config values that are marked as applying to this mode. + grep { + my $key = $_; + $config{$key}->{conf} && + ( $config{$key}->{conf} eq 'ALL' + || grep { $mode eq $_ } @{$config{$key}->{conf}} ) + } keys %config; + + my $key = prompt_list( + "Enter the name of the variable you wish to configure", + '', + sub{ return keys %config_choices }, + \%config_choices); + + if ( exists($config_choices{$key}) ) { + get_config_interactive($key); + } +} + +# edit_color_rules {{{3 +sub edit_color_rules { + my ( $tbl ) = @_; + $clear_screen_sub->(); + $tbl ||= choose_visible_table(); + if ( $tbl && exists($tbl_meta{$tbl}) ) { + my $meta = $tbl_meta{$tbl}; + my @cols = ('', qw(col op arg color)); + my $info = { map { $_ => { hdr => $_, just => '-', } } @cols }; + $info->{label}->{maxw} = 30; + my $key; + my $selected_rule; + + # This loop builds a tabular view of the rules. + do { + + # Show help + if ( $key && $key eq '?' ) { + my @display_lines = ''; + push @display_lines, create_caption('Editor key mappings', + create_table2( + [ sort keys %color_editor_action ], + { map { $_ => $_ } keys %color_editor_action }, + { map { $_ => $color_editor_action{$_}->{note} } keys %color_editor_action }, + { sep => ' ' })); + draw_screen(\@display_lines); + pause(); + $key = ''; + } + else { + + # Do the action specified + $selected_rule ||= 0; + if ( $key && $color_editor_action{$key} ) { + $selected_rule = $color_editor_action{$key}->{func}->($tbl, $selected_rule); + $selected_rule ||= 0; + } + + # Build the table of rules. If the terminal has color, the selected rule + # will be highlighted; otherwise a > at the left will indicate. + my $data = $meta->{colors} || []; + foreach my $i ( 0..@$data - 1 ) { + $data->[$i]->{''} = $i == $selected_rule ? '>' : ''; + } + my @display_lines = create_table(\@cols, $info, $data); + + # Highlight selected entry + for my $i ( 0 .. $#display_lines ) { + if ( $display_lines[$i] =~ m/^>/ ) { + $display_lines[$i] = [ $display_lines[$i], 'reverse' ]; + } + } + + # Draw the screen and wait for a command. + unshift @display_lines, '', + "Editing color rules for $meta->{capt}. Press ? for help, q to " + . "quit.", ''; + draw_screen(\@display_lines); + print "\n\n", word_wrap('Rules are applied in order from top to ' + . 'bottom. The first matching rule wins and prevents the ' + . 'rest of the rules from being applied.'); + $key = pause(''); + } + } while ( $key ne 'q' ); + $meta->{color_func} = make_color_func($meta); + } +} + +# add_quick_filter {{{3 +sub add_quick_filter { + my $tbl = choose_visible_table(); + if ( $tbl && exists($tbl_meta{$tbl}) ) { + print "\n"; + my $response = prompt_list( + "Enter column name and filter text", + '', + sub { return keys %{$tbl_meta{$tbl}->{cols}} }, + () + ); + my ( $col, $text ) = split(/\s+/, $response, 2); + + # You can't filter on a nonexistent column. But if you filter on a pivoted + # table, the columns are different, so on a pivoted table, allow filtering + # on the 'name' column. + # NOTE: if a table is pivoted and un-pivoted, this will likely cause crashes. + # Currently not an issue since there's no way to toggle pivot/nopivot. + return unless $col && $text && + (exists($tbl_meta{$tbl}->{cols}->{$col}) + || ($tbl_meta{$tbl}->{pivot} && $col eq 'name')); + + my ( $sub, $err ) = compile_filter( "defined \$set->{$col} && \$set->{$col} =~ m/$text/" ); + return if !$sub || $err; + my $name = "quick_$tbl.$col"; + $filters{$name} = { + func => $sub, + text => $text, + user => 1, + quick => 1, + name => $name, + note => 'Quick-filter', + tbls => [$tbl], + }; + push @{$tbl_meta{$tbl}->{filters}}, $name; + } +} + +# clear_quick_filters {{{3 +sub clear_quick_filters { + my $tbl = choose_visible_table( + # Only tables that have quick-filters + sub { + my ( $tbl ) = @_; + return scalar grep { $filters{$_}->{quick} } @{ $tbl_meta{$tbl}->{filters} }; + } + ); + if ( $tbl && exists($tbl_meta{$tbl}) ) { + my @current = @{$tbl_meta{$tbl}->{filters}}; + @current = grep { !$filters{$_}->{quick} } @current; + $tbl_meta{$tbl}->{filters} = \@current; + } +} + +sub edit_plugins { + $clear_screen_sub->(); + + my @cols = ('', qw(class desc active)); + my $info = { map { $_ => { hdr => $_, just => '-', } } @cols }; + my @rows = map { $plugins{$_} } sort keys %plugins; + my $key; + my $selected; + + # This loop builds a tabular view of the plugins. + do { + + # Show help + if ( $key && $key eq '?' ) { + my @display_lines = ''; + push @display_lines, create_caption('Editor key mappings', + create_table2( + [ sort keys %plugin_editor_action ], + { map { $_ => $_ } keys %plugin_editor_action }, + { map { $_ => $plugin_editor_action{$_}->{note} } keys %plugin_editor_action }, + { sep => ' ' })); + draw_screen(\@display_lines); + pause(); + $key = ''; + } + + # Do the action specified + else { + $selected ||= 0; + if ( $key && $plugin_editor_action{$key} ) { + $selected = $plugin_editor_action{$key}->{func}->(\@rows, $selected); + $selected ||= 0; + } + + # Build the table of plugins. + foreach my $row ( 0.. $#rows ) { + $rows[$row]->{''} = $row eq $selected ? '>' : ' '; + } + my @display_lines = create_table(\@cols, $info, \@rows); + + # Highlight selected entry + for my $i ( 0 .. $#display_lines ) { + if ( $display_lines[$i] =~ m/^>/ ) { + $display_lines[$i] = [ $display_lines[$i], 'reverse' ]; + } + } + + # Draw the screen and wait for a command. + unshift @display_lines, '', + "Plugin Management. Press ? for help, q to quit.", ''; + draw_screen(\@display_lines); + $key = pause(''); + } + } while ( $key ne 'q' ); +} + +# edit_table {{{3 +sub edit_table { + $clear_screen_sub->(); + my ( $tbl ) = @_; + $tbl ||= choose_visible_table(); + if ( $tbl && exists($tbl_meta{$tbl}) ) { + my $meta = $tbl_meta{$tbl}; + my @cols = ('', qw(name hdr label src)); + my $info = { map { $_ => { hdr => $_, just => '-', } } @cols }; + $info->{label}->{maxw} = 30; + my $key; + my $selected_column; + + # This loop builds a tabular view of the tbl_meta's structure, showing each column + # in the entry as a row. + do { + + # Show help + if ( $key && $key eq '?' ) { + my @display_lines = ''; + push @display_lines, create_caption('Editor key mappings', + create_table2( + [ sort keys %tbl_editor_action ], + { map { $_ => $_ } keys %tbl_editor_action }, + { map { $_ => $tbl_editor_action{$_}->{note} } keys %tbl_editor_action }, + { sep => ' ' })); + draw_screen(\@display_lines); + pause(); + $key = ''; + } + else { + + # Do the action specified + $selected_column ||= $meta->{visible}->[0]; + if ( $key && $tbl_editor_action{$key} ) { + $selected_column = $tbl_editor_action{$key}->{func}->($tbl, $selected_column); + $selected_column ||= $meta->{visible}->[0]; + } + + # Build the pivoted view of the table's meta-data. If the terminal has color, + # The selected row will be highlighted; otherwise a > at the left will indicate. + my $data = []; + foreach my $row ( @{$meta->{visible}} ) { + my %hash; + @hash{ @cols } = @{$meta->{cols}->{$row}}{@cols}; + $hash{src} = '' if ref $hash{src}; + $hash{name} = $row; + $hash{''} = $row eq $selected_column ? '>' : ' '; + push @$data, \%hash; + } + my @display_lines = create_table(\@cols, $info, $data); + + # Highlight selected entry + for my $i ( 0 .. $#display_lines ) { + if ( $display_lines[$i] =~ m/^>/ ) { + $display_lines[$i] = [ $display_lines[$i], 'reverse' ]; + } + } + + # Draw the screen and wait for a command. + unshift @display_lines, '', + "Editing table definition for $meta->{capt}. Press ? for help, q to quit.", ''; + draw_screen(\@display_lines, { clear => 1 }); + $key = pause(''); + } + } while ( $key ne 'q' ); + } +} + +# choose_mode_tables {{{3 +# Choose which table(s), and in what order, to display in a given mode. +sub choose_mode_tables { + my $mode = $config{mode}->{val}; + my @tbls = @{$modes{$mode}->{visible_tables}}; + my $new = prompt_list( + "Choose tables to display", + join(' ', @tbls), + sub { return @{$modes{$mode}->{tables}} }, + { map { $_ => $tbl_meta{$_}->{capt} } @{$modes{$mode}->{tables}} } + ); + $modes{$mode}->{visible_tables} = + [ unique(grep { $_ && exists $tbl_meta{$_} } split(/\s+/, $new)) ]; + $modes{$mode}->{cust}->{visible_tables} = 1; +} + +# choose_visible_table {{{3 +sub choose_visible_table { + my ( $grep_cond ) = @_; + my $mode = $config{mode}->{val}; + my @tbls + = grep { $grep_cond ? $grep_cond->($_) : 1 } + @{$modes{$mode}->{visible_tables}}; + my $tbl = $tbls[0]; + if ( @tbls > 1 ) { + $tbl = prompt_list( + "Choose a table", + '', + sub { return @tbls }, + { map { $_ => $tbl_meta{$_}->{capt} } @tbls } + ); + } + return $tbl; +} + +sub toggle_aggregate { + my ( $tbl ) = @_; + $tbl ||= choose_visible_table(); + return unless $tbl && exists $tbl_meta{$tbl}; + my $meta = $tbl_meta{$tbl}; + $meta->{aggregate} ^= 1; +} + +sub choose_filters { + my ( $tbl ) = @_; + $tbl ||= choose_visible_table(); + return unless $tbl && exists $tbl_meta{$tbl}; + my $meta = $tbl_meta{$tbl}; + $clear_screen_sub->(); + + print "Choose filters for $meta->{capt}:\n"; + + my $ini = join(' ', @{$meta->{filters}}); + my $val = prompt_list( + 'Choose filters', + $ini, + sub { return keys %filters }, + { + map { $_ => $filters{$_}->{note} } + grep { grep { $tbl eq $_ } @{$filters{$_}->{tbls}} } + keys %filters + } + ); + + my @choices = unique(split(/\s+/, $val)); + foreach my $new ( grep { !exists($filters{$_}) } @choices ) { + my $answer = prompt("There is no filter called '$new'. Create it?", undef, 'y'); + if ( $answer eq 'y' ) { + create_new_filter($new, $tbl); + } + } + @choices = grep { exists $filters{$_} } @choices; + @choices = grep { grep { $tbl eq $_ } @{$filters{$_}->{tbls}} } @choices; + $meta->{filters} = [ @choices ]; + $meta->{cust}->{filters} = 1; +} + +sub choose_group_cols { + my ( $tbl ) = @_; + $tbl ||= choose_visible_table(); + return unless $tbl && exists $tbl_meta{$tbl}; + $clear_screen_sub->(); + my $meta = $tbl_meta{$tbl}; + my $curr = join(', ', @{$meta->{group_by}}); + my $val = prompt_list( + 'Group-by columns', + $curr, + sub { return keys %{$meta->{cols}} }, + { map { $_ => $meta->{cols}->{$_}->{label} } keys %{$meta->{cols}} }); + if ( $curr ne $val ) { + $meta->{group_by} = [ grep { exists $meta->{cols}->{$_} } $val =~ m/(\w+)/g ]; + $meta->{cust}->{group_by} = 1; + } +} + +sub choose_sort_cols { + my ( $tbl ) = @_; + $tbl ||= choose_visible_table(); + return unless $tbl && exists $tbl_meta{$tbl}; + $clear_screen_sub->(); + my $meta = $tbl_meta{$tbl}; + + my ( $cols, $hints ); + if ( $meta->{pivot} ) { + $cols = sub { qw(name set_0) }; + $hints = { name => 'name', set_0 => 'set_0' }; + } + else { + $cols = sub { return keys %{$meta->{cols}} }; + $hints = { map { $_ => $meta->{cols}->{$_}->{label} } keys %{$meta->{cols}} }; + } + + my $val = prompt_list( + 'Sort columns (reverse sort with -col)', + $meta->{sort_cols}, + $cols, + $hints ); + if ( $meta->{sort_cols} ne $val ) { + $meta->{sort_cols} = $val; + $meta->{cust}->{sort_cols} = 1; + $tbl_meta{$tbl}->{sort_func} = make_sort_func($tbl_meta{$tbl}); + } +} + +# create_new_filter {{{3 +sub create_new_filter { + my ( $filter, $tbl ) = @_; + $clear_screen_sub->(); + + if ( !$filter || $filter =~ m/\W/ ) { + print word_wrap("Choose a name for the filter. This name is not displayed, and is only used " + . "for internal reference. It can only contain lowercase letters, numbers, and underscores."); + print "\n\n"; + do { + $filter = prompt("Enter filter name"); + } while ( !$filter || $filter =~ m/\W/ ); + } + + my $completion = sub { keys %{$tbl_meta{$tbl}->{cols}} }; + my ( $err, $sub, $body ); + do { + $clear_screen_sub->(); + print word_wrap("A filter is a Perl subroutine that accepts a hashref of columns " + . "called \$set, and returns a true value if the filter accepts the row. Example:\n" + . " \$set->{active_secs} > 5\n" + . "will only allow rows if their active_secs column is greater than 5."); + print "\n\n"; + if ( $err ) { + print "There's an error in your filter expression: $err\n\n"; + } + $body = prompt("Enter subroutine body", undef, undef, $completion); + ( $sub, $err ) = compile_filter($body); + } while ( $err ); + + $filters{$filter} = { + func => $sub, + text => $body, + user => 1, + name => $filter, + note => 'User-defined filter', + tbls => [$tbl], + }; +} + +# get_config_interactive {{{3 +sub get_config_interactive { + my $key = shift; + $clear_screen_sub->(); + + # Print help first. + print "Enter a new value for '$key' ($config{$key}->{note}).\n"; + + my $current = ref($config{$key}->{val}) ? join(" ", @{$config{$key}->{val}}) : $config{$key}->{val}; + + my $new_value = prompt('Enter a value', $config{$key}->{pat}, $current); + $config{$key}->{val} = $new_value; +} + +sub edit_current_var_set { + my $mode = $config{mode}->{val}; + my $name = $config{"${mode}_set"}->{val}; + my $variables = $var_sets{$name}->{text}; + + my $new = $variables; + do { + $clear_screen_sub->(); + $new = prompt("Enter variables for $name", undef, $variables); + } until ( $new ); + + if ( $new ne $variables ) { + @{$var_sets{$name}}{qw(text user)} = ( $new, 1); + } +} + + +sub choose_var_set { + my ( $key ) = @_; + $clear_screen_sub->(); + + my $new_value = prompt_list( + 'Choose a set of values to display, or enter the name of a new one', + $config{$key}->{val}, + sub { return keys %var_sets }, + { map { $_ => $var_sets{$_}->{text} } keys %var_sets }); + + if ( !exists $var_sets{$new_value} ) { + add_new_var_set($new_value); + } + + $config{$key}->{val} = $new_value if exists $var_sets{$new_value}; +} + +sub switch_var_set { + my ( $cfg_var, $dir ) = @_; + my @var_sets = sort keys %var_sets; + my $cur = $config{$cfg_var}->{val}; + my $pos = grep { $_ lt $cur } @var_sets; + my $newpos = ($pos + $dir) % @var_sets; + $config{$cfg_var}->{val} = $var_sets[$newpos]; + $clear_screen_sub->(); +} + +# Online configuration and prompting functions {{{2 + +# edit_stmt_sleep_times {{{3 +sub edit_stmt_sleep_times { + $clear_screen_sub->(); + my $stmt = prompt_list('Specify a statement', '', sub { return sort keys %stmt_maker_for }); + return unless $stmt && exists $stmt_maker_for{$stmt}; + $clear_screen_sub->(); + my $curr_val = $stmt_sleep_time_for{$stmt} || 0; + my $new_val = prompt('Specify a sleep delay after calling this SQL', $num_regex, $curr_val); + if ( $new_val ) { + $stmt_sleep_time_for{$stmt} = $new_val; + } + else { + delete $stmt_sleep_time_for{$stmt}; + } +} + +# edit_server_groups {{{3 +# Choose which server connections are in a server group. First choose a group, +# then choose which connections are in it. +sub edit_server_groups { + $clear_screen_sub->(); + my $mode = $config{mode}->{val}; + my $group = $modes{$mode}->{server_group}; + my %curr = %server_groups; + my $new = choose_or_create_server_group($group, 'to edit'); + $clear_screen_sub->(); + if ( exists $curr{$new} ) { + # Don't do this step if the user just created a new server group, + # because part of that process was to choose connections. + my $cxns = join(' ', @{$server_groups{$new}}); + my @conns = choose_or_create_connection($cxns, 'for this group'); + $server_groups{$new} = \@conns; + } +} + +# choose_server_groups {{{3 +sub choose_server_groups { + $clear_screen_sub->(); + my $mode = $config{mode}->{val}; + my $group = $modes{$mode}->{server_group}; + my $new = choose_or_create_server_group($group, 'for this mode'); + $modes{$mode}->{server_group} = $new if exists $server_groups{$new}; +} + +sub choose_or_create_server_group { + my ( $group, $prompt ) = @_; + my $new = ''; + + my @available = sort keys %server_groups; + + if ( @available ) { + print "You can enter the name of a new group to create it.\n"; + + $new = prompt_list( + "Choose a server group $prompt", + $group, + sub { return @available }, + { map { $_ => join(' ', @{$server_groups{$_}}) } @available }); + + $new =~ s/\s.*//; + + if ( !exists $server_groups{$new} ) { + my $answer = prompt("There is no server group called '$new'. Create it?", undef, "y"); + if ( $answer eq 'y' ) { + add_new_server_group($new); + } + } + } + else { + $new = add_new_server_group(); + } + return $new; +} + +sub choose_or_create_connection { + my ( $cxns, $prompt ) = @_; + print "You can enter the name of a new connection to create it.\n"; + + my @available = sort keys %connections; + my $new_cxns = prompt_list( + "Choose connections $prompt", + $cxns, + sub { return @available }, + { map { $_ => $connections{$_}->{dsn} } @available }); + + my @new = unique(grep { !exists $connections{$_} } split(/\s+/, $new_cxns)); + foreach my $new ( @new ) { + my $answer = prompt("There is no connection called '$new'. Create it?", undef, "y"); + if ( $answer eq 'y' ) { + add_new_dsn($new); + } + } + + return unique(grep { exists $connections{$_} } split(/\s+/, $new_cxns)); +} + +# choose_servers {{{3 +sub choose_servers { + $clear_screen_sub->(); + my $mode = $config{mode}->{val}; + my $cxns = join(' ', get_connections()); + my @chosen = choose_or_create_connection($cxns, 'for this mode'); + $modes{$mode}->{connections} = \@chosen; + $modes{$mode}->{server_group} = ''; # Clear this because it overrides {connections} +} + +# display_license {{{3 +sub display_license { + $clear_screen_sub->(); + + print $innotop_license; + + pause(); +} + +# Data-retrieval functions {{{2 +# get_status_info {{{3 +# Get SHOW STATUS and SHOW VARIABLES together. +sub get_status_info { + my @cxns = @_; + if ( !$info_gotten{status}++ ) { + foreach my $cxn ( @cxns ) { + $vars{$cxn}->{$clock} ||= {}; + my $vars = $vars{$cxn}->{$clock}; + + my $sth = do_stmt($cxn, 'SHOW_STATUS') or next; + my $res = $sth->fetchall_arrayref(); + map { $vars->{$_->[0]} = $_->[1] || 0 } @$res; + + # Calculate hi-res uptime and add cxn to the hash. This duplicates get_driver_status, + # but it's most important to have consistency. + $vars->{Uptime_hires} ||= get_uptime($cxn); + $vars->{cxn} = $cxn; + + # Add SHOW VARIABLES to the hash + $sth = do_stmt($cxn, 'SHOW_VARIABLES') or next; + $res = $sth->fetchall_arrayref(); + map { $vars->{$_->[0]} = $_->[1] || 0 } @$res; + } + } +} + +# Chooses a thread for explaining, killing, etc... +# First arg is a func that can be called in grep. +sub choose_thread { + my ( $grep_cond, $prompt ) = @_; + + # Narrow the list to queries that can be explained. + my %thread_for = map { + # Eliminate innotop's own threads. + $_ => $dbhs{$_}->{dbh} ? $dbhs{$_}->{dbh}->{mysql_thread_id} : 0 + } keys %connections; + + my @candidates = grep { + $_->{id} != $thread_for{$_->{cxn}} && $grep_cond->($_) + } @current_queries; + return unless @candidates; + + # Find out which server. + my @cxns = unique map { $_->{cxn} } @candidates; + my ( $cxn ) = select_cxn('On which server', @cxns); + return unless $cxn && exists($connections{$cxn}); + + # Re-filter the list of candidates to only those on this server + @candidates = grep { $_->{cxn} eq $cxn } @candidates; + + # Find out which thread to do. + my $info; + if ( @candidates > 1 ) { + + # Sort longest-active first, then longest-idle. + my $sort_func = sub { + my ( $a, $b ) = @_; + return $a->{query} && !$b->{query} ? 1 + : $b->{query} && !$a->{query} ? -1 + : ($a->{time} || 0) <=> ($b->{time} || 0); + }; + my @threads = map { $_->{id} } reverse sort { $sort_func->($a, $b) } @candidates; + + print "\n"; + my $thread = prompt_list($prompt, + $threads[0], + sub { return @threads }); + return unless $thread && $thread =~ m/$int_regex/; + + # Find the info hash of that query on that server. + ( $info ) = grep { $thread == $_->{id} } @candidates; + } + else { + $info = $candidates[0]; + } + return $info; +} + +# analyze_query {{{3 +# Allows the user to show fulltext, explain, show optimized... +sub analyze_query { + my ( $action ) = @_; + + my $info = choose_thread( + sub { $_[0]->{query} }, + 'Select a thread to analyze', + ); + return unless $info; + + my %actions = ( + e => \&display_explain, + f => \&show_full_query, + o => \&show_optimized_query, + ); + do { + $actions{$action}->($info); + print "\n"; + $action = pause('Press e to explain, f for full query, o for optimized query'); + } while ( exists($actions{$action}) ); +} + +# inc {{{3 +# Returns the difference between two sets of variables/status/innodb stuff. +sub inc { + my ( $offset, $cxn ) = @_; + my $vars = $vars{$cxn}; + if ( $offset < 0 ) { + return $vars->{$clock}; + } + elsif ( exists $vars{$clock - $offset} && !exists $vars->{$clock - $offset - 1} ) { + return $vars->{$clock - $offset}; + } + my $cur = $vars->{$clock - $offset}; + my $pre = $vars->{$clock - $offset - 1}; + return { + # Numeric variables get subtracted, non-numeric get passed straight through. + map { + $_ => + ( (defined $cur->{$_} && $cur->{$_} =~ m/$num_regex/) + ? $cur->{$_} - ($pre->{$_} || 0) + : $cur->{$_} ) + } keys %{$cur} + }; +} + +# extract_values {{{3 +# Arguments are a set of values (which may be incremental, derived from +# current and previous), current, and previous values. +# TODO: there are a few places that don't remember prev set so can't pass it. +sub extract_values { + my ( $set, $cur, $pre, $tbl ) = @_; + + # Hook in event listeners + foreach my $listener ( @{$event_listener_for{extract_values}} ) { + $listener->extract_values($set, $cur, $pre, $tbl); + } + + my $result = {}; + my $meta = $tbl_meta{$tbl}; + my $cols = $meta->{cols}; + foreach my $key ( keys %$cols ) { + my $info = $cols->{$key} + or die "Column '$key' doesn't exist in $tbl"; + die "No func defined for '$key' in $tbl" + unless $info->{func}; + eval { + $result->{$key} = $info->{func}->($set, $cur, $pre) + }; + if ( $EVAL_ERROR ) { + if ( $config{debug}->{val} ) { + die $EVAL_ERROR; + } + $result->{$key} = $info->{num} ? 0 : ''; + } + } + return $result; +} + +# get_full_processlist {{{3 +sub get_full_processlist { + my @cxns = @_; + my @result; + foreach my $cxn ( @cxns ) { + my $stmt = do_stmt($cxn, 'PROCESSLIST') or next; + my $arr = $stmt->fetchall_arrayref({}); + push @result, map { $_->{cxn} = $cxn; $_ } @$arr; + } + return @result; +} + +# get_open_tables {{{3 +sub get_open_tables { + my @cxns = @_; + my @result; + foreach my $cxn ( @cxns ) { + my $stmt = do_stmt($cxn, 'OPEN_TABLES') or next; + my $arr = $stmt->fetchall_arrayref({}); + push @result, map { $_->{cxn} = $cxn; $_ } @$arr; + } + return @result; +} + +# get_innodb_status {{{3 +sub get_innodb_status { + my ( $cxns, $addl_sections ) = @_; + if ( !$config{skip_innodb}->{val} && !$info_gotten{innodb_status}++ ) { + + # Determine which sections need to be parsed + my %sections_required = + map { $tbl_meta{$_}->{innodb} => 1 } + grep { $_ && $tbl_meta{$_}->{innodb} } + get_visible_tables(); + + # Add in any other sections the caller requested. + foreach my $sec ( @$addl_sections ) { + $sections_required{$sec} = 1; + } + + foreach my $cxn ( @$cxns ) { + my $innodb_status_text; + + if ( $file ) { # Try to fetch status text from the file. + my @stat = stat($file); + + # Initialize the file. + if ( !$file_mtime ) { + # Initialize to 130k from the end of the file (because the limit + # on the size of innodb status is 128k even with Google's patches) + # and try to grab the last status from the file. + sysseek($file, (-128 * 1_024), 2); + } + + # Read from the file. + my $buffer; + if ( !$file_mtime || $file_mtime != $stat[9] ) { + $file_data = ''; + while ( sysread($file, $buffer, 4096) ) { + $file_data .= $buffer; + } + $file_mtime = $stat[9]; + } + + # Delete everything but the last InnoDB status text from the file. + $file_data =~ s/\A.*(?=^=====================================\n...... ........ INNODB MONITOR OUTPUT)//ms; + $innodb_status_text = $file_data; + } + + else { + my $stmt = do_stmt($cxn, 'INNODB_STATUS') or next; + $innodb_status_text = $stmt->fetchrow_hashref()->{status}; + } + + next unless $innodb_status_text + && substr($innodb_status_text, 0, 100) =~ m/INNODB MONITOR OUTPUT/; + + # Parse and merge into %vars storage + my %innodb_status = ( + $innodb_parser->get_status_hash( + $innodb_status_text, + $config{debug}->{val}, + \%sections_required, + 0, # don't parse full lock information + ) + ); + if ( !$innodb_status{IB_got_all} && $config{auto_wipe_dl}->{val} ) { + clear_deadlock($cxn); + } + + # Merge using a hash slice, which is the fastest way + $vars{$cxn}->{$clock} ||= {}; + my $hash = $vars{$cxn}->{$clock}; + @{$hash}{ keys %innodb_status } = values %innodb_status; + $hash->{cxn} = $cxn; + $hash->{Uptime_hires} ||= get_uptime($cxn); + } + } +} + +# clear_deadlock {{{3 +sub clear_deadlock { + my ( $cxn ) = @_; + return if $clearing_deadlocks++; + my $tbl = $connections{$cxn}->{dl_table}; + return unless $tbl; + + eval { + # Set up the table for creating a deadlock. + my $engine = version_ge($dbhs{$cxn}->{dbh}, '4.1.2') ? 'engine' : 'type'; + return unless do_query($cxn, "drop table if exists $tbl"); + return unless do_query($cxn, "create table $tbl(a int) $engine=innodb"); + return unless do_query($cxn, "delete from $tbl"); + return unless do_query($cxn, "insert into $tbl(a) values(0), (1)"); + return unless do_query($cxn, "commit"); # Or the children will block against the parent + + # Fork off two children to deadlock against each other. + my %children; + foreach my $child ( 0..1 ) { + my $pid = fork(); + if ( defined($pid) && $pid == 0 ) { # I am a child + deadlock_thread( $child, $tbl, $cxn ); + } + elsif ( !defined($pid) ) { + die("Unable to fork for clearing deadlocks!\n"); + } + # I already exited if I'm a child, so I'm the parent. + $children{$child} = $pid; + } + + # Wait for the children to exit. + foreach my $child ( keys %children ) { + my $pid = waitpid($children{$child}, 0); + } + + # Clean up. + do_query($cxn, "drop table $tbl"); + }; + if ( $EVAL_ERROR ) { + print $EVAL_ERROR; + pause(); + } + + $clearing_deadlocks = 0; +} + +sub get_master_logs { + my @cxns = @_; + my @result; + if ( !$info_gotten{master_logs}++ ) { + foreach my $cxn ( @cxns ) { + my $stmt = do_stmt($cxn, 'SHOW_MASTER_LOGS') or next; + push @result, @{$stmt->fetchall_arrayref({})}; + } + } + return @result; +} + +# get_master_slave_status {{{3 +sub get_master_slave_status { + my @cxns = @_; + if ( !$info_gotten{replication_status}++ ) { + foreach my $cxn ( @cxns ) { + $vars{$cxn}->{$clock} ||= {}; + my $vars = $vars{$cxn}->{$clock}; + $vars->{cxn} = $cxn; + + my $stmt = do_stmt($cxn, 'SHOW_MASTER_STATUS') or next; + my $res = $stmt->fetchall_arrayref({})->[0]; + @{$vars}{ keys %$res } = values %$res; + $stmt = do_stmt($cxn, 'SHOW_SLAVE_STATUS') or next; + $res = $stmt->fetchall_arrayref({})->[0]; + @{$vars}{ keys %$res } = values %$res; + $vars->{Uptime_hires} ||= get_uptime($cxn); + } + } +} + +sub is_func { + my ( $word ) = @_; + return defined(&$word) + || eval "my \$x= sub { $word }; 1" + || $EVAL_ERROR !~ m/^Bareword/; +} + +# Documentation {{{1 +# ############################################################################ +# I put this last as per the Dog book. +# ############################################################################ +=pod + +=head1 NAME + +innotop - MySQL and InnoDB transaction/status monitor. + +=head1 SYNOPSIS + +To monitor servers normally: + + innotop + +To monitor InnoDB status information from a file: + + innotop /var/log/mysql/mysqld.err + +To run innotop non-interactively in a pipe-and-filter configuration: + + innotop --count 5 -d 1 -n + +To monitor a database on another system using a particular username and password: + + innotop -u -p -h + +=head1 DESCRIPTION + +innotop monitors MySQL servers. Each of its modes shows you a different aspect +of what's happening in the server. For example, there's a mode for monitoring +replication, one for queries, and one for transactions. innotop refreshes its +data periodically, so you see an updating view. + +innotop has lots of features for power users, but you can start and run it with +virtually no configuration. If you're just getting started, see +L<"QUICK-START">. Press '?' at any time while running innotop for +context-sensitive help. + +=head1 QUICK-START + +To start innotop, open a terminal or command prompt. If you have installed +innotop on your system, you should be able to just type "innotop" and press +Enter; otherwise, you will need to change to innotop's directory and type "perl +innotop". + +With no options specified, innotop will attempt to connect to a MySQL server on +localhost using mysql_read_default_group=client for other connection +parameters. If you need to specify a different username and password, use the +-u and -p options, respectively. To monitor a MySQL database on another +host, use the -h option. + +After you've connected, innotop should show you something like the following: + + [RO] Query List (? for help) localhost, 01:11:19, 449.44 QPS, 14/7/163 con/run + + CXN When Load QPS Slow QCacheHit KCacheHit BpsIn BpsOut + localhost Total 0.00 1.07k 697 0.00% 98.17% 476.83k 242.83k + + CXN Cmd ID User Host DB Time Query + localhost Query 766446598 test 10.0.0.1 foo 00:02 INSERT INTO table ( + + +(This sample is truncated at the right so it will fit on a terminal when running +'man innotop') + +If your server is busy, you'll see more output. Notice the first line on the +screen, which tells you that readonly is set to true ([RO]), what mode you're +in and what server you're connected to. You can change to other modes with +keystrokes; press 'T' to switch to a list of InnoDB transactions, for example. + +Press the '?' key to see what keys are active in the current mode. You can +press any of these keys and innotop will either take the requested action or +prompt you for more input. If your system has Term::ReadLine support, you can +use TAB and other keys to auto-complete and edit input. + +To quit innotop, press the 'q' key. + +=head1 OPTIONS + +innotop is mostly configured via its configuration file, but some of the +configuration options can come from the command line. You can also specify a +file to monitor for InnoDB status output; see L<"MONITORING A FILE"> for more +details. + +You can negate some options by prefixing the option name with --no. For +example, --noinc (or --no-inc) negates L<"--inc">. + +=over + +=item --color + +Enable or disable terminal coloring. Corresponds to the L<"color"> config file +setting. + +=item --config + +Specifies a configuration file to read. This option is non-sticky, that is to +say it does not persist to the configuration file itself. + +=item --count + +Refresh only the specified number of times (ticks) before exiting. Each refresh +is a pause for L<"interval"> seconds, followed by requesting data from MySQL +connections and printing it to the terminal. + +=item --delay + +Specifies the amount of time to pause between ticks (refreshes). Corresponds to +the configuration option L<"interval">. + +=item --help + +Print a summary of command-line usage and exit. + +=item --host + +Host to connect to. + +=item --inc + +Specifies whether innotop should display absolute numbers or relative numbers +(offsets from their previous values). Corresponds to the configuration option +L<"status_inc">. + +=item --mode + +Specifies the mode in which innotop should start. Corresponds to the +configuration option L<"mode">. + +=item --nonint + +Enable non-interactive operation. See L<"NON-INTERACTIVE OPERATION"> for more. + +=item --password + +Password to use for connection. + +=item --port + +Port to use for connection. + +=item --skipcentral + +Don't read the central configuration file. + +=item --user + +User to use for connection. + +=item --version + +Output version information and exit. + +=item --write + +Sets the configuration option L<"readonly"> to 0, making innotop write the +running configuration to ~/.innotop/innotop.conf on exit, if no configuration +file was loaded at start-up. + +=back + +=head1 HOTKEYS + +innotop is interactive, and you control it with key-presses. + +=over + +=item * + +Uppercase keys switch between modes. + +=item * + +Lowercase keys initiate some action within the current mode. + +=item * + +Other keys do something special like change configuration or show the +innotop license. + +=back + +Press '?' at any time to see the currently active keys and what they do. + +=head1 MODES + +Each of innotop's modes retrieves and displays a particular type of data from +the servers you're monitoring. You switch between modes with uppercase keys. +The following is a brief description of each mode, in alphabetical order. To +switch to the mode, press the key listed in front of its heading in the +following list: + +=over + +=item B: InnoDB Buffers + +This mode displays information about the InnoDB buffer pool, page statistics, +insert buffer, and adaptive hash index. The data comes from SHOW INNODB STATUS. + +This mode contains the L<"buffer_pool">, L<"page_statistics">, +L<"insert_buffers">, and L<"adaptive_hash_index"> tables by default. + +=item C: Command Summary + +This mode is similar to mytop's Command Summary mode. It shows the +L<"cmd_summary"> table, which looks something like the following: + + Command Summary (? for help) localhost, 25+07:16:43, 2.45 QPS, 3 thd, 5.0.40 + _____________________ Command Summary _____________________ + Name Value Pct Last Incr Pct + Select_scan 3244858 69.89% 2 100.00% + Select_range 1354177 29.17% 0 0.00% + Select_full_join 39479 0.85% 0 0.00% + Select_full_range_join 4097 0.09% 0 0.00% + Select_range_check 0 0.00% 0 0.00% + +The command summary table is built by extracting variables from +L<"STATUS_VARIABLES">. The variables must be numeric and must match the prefix +given by the L<"cmd_filter"> configuration variable. The variables are then +sorted by value descending and compared to the last variable, as shown above. +The percentage columns are percentage of the total of all variables in the +table, so you can see the relative weight of the variables. + +The example shows what you see if the prefix is "Select_". The default +prefix is "Com_". You can choose a prefix with the 's' key. + +It's rather like running SHOW VARIABLES LIKE "prefix%" with memory and +nice formatting. + +Values are aggregated across all servers. The Pct columns are not correctly +aggregated across multiple servers. This is a known limitation of the grouping +algorithm that may be fixed in the future. + +=item D: InnoDB Deadlocks + +This mode shows the transactions involved in the last InnoDB deadlock. A second +table shows the locks each transaction held and waited for. A deadlock is +caused by a cycle in the waits-for graph, so there should be two locks held and +one waited for unless the deadlock information is truncated. + +InnoDB puts deadlock information before some other information in the SHOW +INNODB STATUS output. If there are a lot of locks, the deadlock information can +grow very large, and there is a limit on the size of the SHOW INNODB +STATUS output. A large deadlock can fill the entire output, or even be +truncated, and prevent you from seeing other information at all. If you are +running innotop in another mode, for example T mode, and suddenly you don't see +anything, you might want to check and see if a deadlock has wiped out the data +you need. + +If it has, you can create a small deadlock to replace the large one. Use the +'w' key to 'wipe' the large deadlock with a small one. This will not work +unless you have defined a deadlock table for the connection (see L<"SERVER +CONNECTIONS">). + +You can also configure innotop to automatically detect when a large deadlock +needs to be replaced with a small one (see L<"auto_wipe_dl">). + +This mode displays the L<"deadlock_transactions"> and L<"deadlock_locks"> tables +by default. + +=item F: InnoDB Foreign Key Errors + +This mode shows the last InnoDB foreign key error information, such as the +table where it happened, when and who and what query caused it, and so on. + +InnoDB has a huge variety of foreign key error messages, and many of them are +just hard to parse. innotop doesn't always do the best job here, but there's +so much code devoted to parsing this messy, unparseable output that innotop is +likely never to be perfect in this regard. If innotop doesn't show you what +you need to see, just look at the status text directly. + +This mode displays the L<"fk_error"> table by default. + +=item I: InnoDB I/O Info + +This mode shows InnoDB's I/O statistics, including the I/O threads, pending I/O, +file I/O miscellaneous, and log statistics. It displays the L<"io_threads">, +L<"pending_io">, L<"file_io_misc">, and L<"log_statistics"> tables by default. + +=item L: Locks + +This mode shows information about current locks. At the moment only InnoDB +locks are supported, and by default you'll only see locks for which transactions +are waiting. This information comes from the TRANSACTIONS section of the InnoDB +status text. If you have a very busy server, you may have frequent lock waits; +it helps to be able to see which tables and indexes are the "hot spot" for +locks. If your server is running pretty well, this mode should show nothing. + +You can configure MySQL and innotop to monitor not only locks for which a +transaction is waiting, but those currently held, too. You can do this with the +InnoDB Lock Monitor (L). It's +not documented in the MySQL manual, but creating the lock monitor with the +following statement also affects the output of SHOW INNODB STATUS, which innotop +uses: + + CREATE TABLE innodb_lock_monitor(a int) ENGINE=INNODB; + +This causes InnoDB to print its output to the MySQL file every 16 seconds or so, +as stated in the manual, but it also makes the normal SHOW INNODB STATUS output +include lock information, which innotop can parse and display (that's the +undocumented feature). + +This means you can do what may have seemed impossible: to a limited extent +(InnoDB truncates some information in the output), you can see which transaction +holds the locks something else is waiting for. You can also enable and disable +the InnoDB Lock Monitor with the key mappings in this mode. + +This mode displays the L<"innodb_locks"> table by default. Here's a sample of +the screen when one connection is waiting for locks another connection holds: + + _________________________________ InnoDB Locks __________________________ + CXN ID Type Waiting Wait Active Mode DB Table Index + localhost 12 RECORD 1 00:10 00:10 X test t1 PRIMARY + localhost 12 TABLE 0 00:10 00:10 IX test t1 + localhost 12 RECORD 1 00:10 00:10 X test t1 PRIMARY + localhost 11 TABLE 0 00:00 00:25 IX test t1 + localhost 11 RECORD 0 00:00 00:25 X test t1 PRIMARY + +You can see the first connection, ID 12, is waiting for a lock on the PRIMARY +key on test.t1, and has been waiting for 10 seconds. The second connection +isn't waiting, because the Waiting column is 0, but it holds locks on the same +index. That tells you connection 11 is blocking connection 12. + +=item M: Master/Slave Replication Status + +This mode shows the output of SHOW SLAVE STATUS and SHOW MASTER STATUS in three +tables. The first two divide the slave's status into SQL and I/O thread status, +and the last shows master status. Filters are applied to eliminate non-slave +servers from the slave tables, and non-master servers from the master table. + +This mode displays the L<"slave_sql_status">, L<"slave_io_status">, and +L<"master_status"> tables by default. + +=item O: Open Tables + +This section comes from MySQL's SHOW OPEN TABLES command. By default it is +filtered to show tables which are in use by one or more queries, so you can +get a quick look at which tables are 'hot'. You can use this to guess which +tables might be locked implicitly. + +This mode displays the L<"open_tables"> mode by default. + +=item Q: Query List + +This mode displays the output from SHOW FULL PROCESSLIST, much like B's +query list mode. This mode does B show InnoDB-related information. This +is probably one of the most useful modes for general usage. + +There is an informative header that shows general status information about +your server. You can toggle it on and off with the 'h' key. By default, +innotop hides inactive processes and its own process. You can toggle these on +and off with the 'i' and 'a' keys. + +You can EXPLAIN a query from this mode with the 'e' key. This displays the +query's full text, the results of EXPLAIN, and in newer MySQL versions, even +the optimized query resulting from EXPLAIN EXTENDED. innotop also tries to +rewrite certain queries to make them EXPLAIN-able. For example, INSERT/SELECT +statements are rewritable. + +This mode displays the L<"q_header"> and L<"processlist"> tables by default. + +=item R: InnoDB Row Operations and Semaphores + +This mode shows InnoDB row operations, row operation miscellaneous, semaphores, +and information from the wait array. It displays the L<"row_operations">, +L<"row_operation_misc">, L<"semaphores">, and L<"wait_array"> tables by default. + +=item S: Variables & Status + +This mode calculates statistics, such as queries per second, and prints them out +in several different styles. You can show absolute values, or incremental values +between ticks. + +You can switch between the views by pressing a key. The 's' key prints a +single line each time the screen updates, in the style of B. The 'g' +key changes the view to a graph of the same numbers, sort of like B. +The 'v' key changes the view to a pivoted table of variable names on the left, +with successive updates scrolling across the screen from left to right. You can +choose how many updates to put on the screen with the L<"num_status_sets"> +configuration variable. + +Headers may be abbreviated to fit on the screen in interactive operation. You +choose which variables to display with the 'c' key, which selects from +predefined sets, or lets you create your own sets. You can edit the current set +with the 'e' key. + +This mode doesn't really display any tables like other modes. Instead, it uses +a table definition to extract and format the data, but it then transforms the +result in special ways before outputting it. It uses the L<"var_status"> table +definition for this. + +=item T: InnoDB Transactions + +This mode shows transactions from the InnoDB monitor's output, in B-like +format. This mode is the reason I wrote innotop. + +You can kill queries or processes with the 'k' and 'x' keys, and EXPLAIN a query +with the 'e' or 'f' keys. InnoDB doesn't print the full query in transactions, +so explaining may not work right if the query is truncated. + +The informational header can be toggled on and off with the 'h' key. By +default, innotop hides inactive transactions and its own transaction. You can +toggle this on and off with the 'i' and 'a' keys. + +This mode displays the L<"t_header"> and L<"innodb_transactions"> tables by +default. + +=back + +=head1 INNOTOP STATUS + +The first line innotop displays is a "status bar" of sorts. What it contains +depends on the mode you're in, and what servers you're monitoring. The first +few words are always [RO] (if readonly is set to 1), the innotop mode, such as +"InnoDB Txns" for T mode, followed by a reminder to press '?' for help at any +time. + +=head2 ONE SERVER + +The simplest case is when you're monitoring a single server. In this case, the +name of the connection is next on the status line. This is the name you gave +when you created the connection -- most likely the MySQL server's hostname. +This is followed by the server's uptime. + +If you're in an InnoDB mode, such as T or B, the next word is "InnoDB" followed +by some information about the SHOW INNODB STATUS output used to render the +screen. The first word is the number of seconds since the last SHOW INNODB +STATUS, which InnoDB uses to calculate some per-second statistics. The next is +a smiley face indicating whether the InnoDB output is truncated. If the smiley +face is a :-), all is well; there is no truncation. A :^| means the transaction +list is so long, InnoDB has only printed out some of the transactions. Finally, +a frown :-( means the output is incomplete, which is probably due to a deadlock +printing too much lock information (see L<"D: InnoDB Deadlocks">). + +The next two words indicate the server's queries per second (QPS) and how many +threads (connections) exist. Finally, the server's version number is the last +thing on the line. + +=head2 MULTIPLE SERVERS + +If you are monitoring multiple servers (see L<"SERVER CONNECTIONS">), the status +line does not show any details about individual servers. Instead, it shows the +names of the connections that are active. Again, these are connection names you +specified, which are likely to be the server's hostname. A connection that has +an error is prefixed with an exclamation point. + +If you are monitoring a group of servers (see L<"SERVER GROUPS">), the status +line shows the name of the group. If any connection in the group has an +error, the group's name is followed by the fraction of the connections that +don't have errors. + +See L<"ERROR HANDLING"> for more details about innotop's error handling. + +=head2 MONITORING A FILE + +If you give a filename on the command line, innotop will not connect to ANY +servers at all. It will watch the specified file for InnoDB status output and +use that as its data source. It will always show a single connection called +'file'. And since it can't connect to a server, it can't determine how long the +server it's monitoring has been up; so it calculates the server's uptime as time +since innotop started running. + +=head1 SERVER ADMINISTRATION + +While innotop is primarily a monitor that lets you watch and analyze your +servers, it can also send commands to servers. The most frequently useful +commands are killing queries and stopping or starting slaves. + +You can kill a connection, or in newer versions of MySQL kill a query but not a +connection, from L<"Q: Query List"> and L<"T: InnoDB Transactions"> modes. +Press 'k' to issue a KILL command, or 'x' to issue a KILL QUERY command. +innotop will prompt you for the server and/or connection ID to kill (innotop +does not prompt you if there is only one possible choice for any input). +innotop pre-selects the longest-running query, or the oldest connection. +Confirm the command with 'y'. + +In L<"M: Master/Slave Replication Status"> mode, you can start and stop slaves +with the 'a' and 'o' keys, respectively. You can send these commands to many +slaves at once. innotop fills in a default command of START SLAVE or STOP SLAVE +for you, but you can actually edit the command and send anything you wish, such +as SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1 to make the slave skip one binlog event +when it starts. + +You can also ask innotop to calculate the earliest binlog in use by any slave +and issue a PURGE MASTER LOGS on the master. Use the 'b' key for this. innotop +will prompt you for a master to run the command on, then prompt you for the +connection names of that master's slaves (there is no way for innotop to +determine this reliably itself). innotop will find the minimum binlog in use by +these slave connections and suggest it as the argument to PURGE MASTER LOGS. + +=head1 SERVER CONNECTIONS + +When you create a server connection using '@', innotop asks you for a series of +inputs, as follows: + +=over + +=item DSN + +A DSN is a Data Source Name, which is the initial argument passed to the DBI +module for connecting to a server. It is usually of the form + + DBI:mysql:;mysql_read_default_group=mysql;host=HOSTNAME + +Since this DSN is passed to the DBD::mysql driver, you should read the driver's +documentation at L<"http://search.cpan.org/dist/DBD-mysql/lib/DBD/mysql.pm"> for +the exact details on all the options you can pass the driver in the DSN. You +can read more about DBI at L, and especially at +L. + +The mysql_read_default_group=mysql option lets the DBD driver read your MySQL +options files, such as ~/.my.cnf on UNIX-ish systems. You can use this to avoid +specifying a username or password for the connection. + +=item InnoDB Deadlock Table + +This optional item tells innotop a table name it can use to deliberately create +a small deadlock (see L<"D: InnoDB Deadlocks">). If you specify this option, +you just need to be sure the table doesn't exist, and that innotop can create +and drop the table with the InnoDB storage engine. You can safely omit or just +accept the default if you don't intend to use this. + +=item Username + +innotop will ask you if you want to specify a username. If you say 'y', it will +then prompt you for a user name. If you have a MySQL option file that specifies +your username, you don't have to specify a username. + +The username defaults to your login name on the system you're running innotop on. + +=item Password + +innotop will ask you if you want to specify a password. Like the username, the +password is optional, but there's an additional prompt that asks if you want to +save the password in the innotop configuration file. If you don't save it in +the configuration file, innotop will prompt you for a password each time it +starts. Passwords in the innotop configuration file are saved in plain text, +not encrypted in any way. + +=back + +Once you finish answering these questions, you should be connected to a server. +But innotop isn't limited to monitoring a single server; you can define many +server connections and switch between them by pressing the '@' key. See +L<"SWITCHING BETWEEN CONNECTIONS">. + +=head1 SERVER GROUPS + +If you have multiple MySQL instances, you can put them into named groups, such +as 'all', 'masters', and 'slaves', which innotop can monitor all together. + +You can choose which group to monitor with the '#' key, and you can press the +TAB key to switch to the next group. If you're not currently monitoring a +group, pressing TAB selects the first group. + +To create a group, press the '#' key and type the name of your new group, then +type the names of the connections you want the group to contain. + +=head1 SWITCHING BETWEEN CONNECTIONS + +innotop lets you quickly switch which servers you're monitoring. The most basic +way is by pressing the '@' key and typing the name(s) of the connection(s) you +want to use. This setting is per-mode, so you can monitor different connections +in each mode, and innotop remembers which connections you choose. + +You can quickly switch to the 'next' connection in alphabetical order with the +'n' key. If you're monitoring a server group (see L<"SERVER GROUPS">) this will +switch to the first connection. + +You can also type many connection names, and innotop will fetch and display data +from them all. Just separate the connection names with spaces, for example +"server1 server2." Again, if you type the name of a connection that doesn't +exist, innotop will prompt you for connection information and create the +connection. + +Another way to monitor multiple connections at once is with server groups. You +can use the TAB key to switch to the 'next' group in alphabetical order, or if +you're not monitoring any groups, TAB will switch to the first group. + +innotop does not fetch data in parallel from connections, so if you are +monitoring a large group or many connections, you may notice increased delay +between ticks. + +When you monitor more than one connection, innotop's status bar changes. See +L<"INNOTOP STATUS">. + +=head1 ERROR HANDLING + +Error handling is not that important when monitoring a single connection, but is +crucial when you have many active connections. A crashed server or lost +connection should not crash innotop. As a result, innotop will continue to run +even when there is an error; it just won't display any information from the +connection that had an error. Because of this, innotop's behavior might confuse +you. It's a feature, not a bug! + +innotop does not continue to query connections that have errors, because they +may slow innotop and make it hard to use, especially if the error is a problem +connecting and causes a long time-out. Instead, innotop retries the connection +occasionally to see if the error still exists. If so, it will wait until some +point in the future. The wait time increases in ticks as the Fibonacci series, +so it tries less frequently as time passes. + +Since errors might only happen in certain modes because of the SQL commands +issued in those modes, innotop keeps track of which mode caused the error. If +you switch to a different mode, innotop will retry the connection instead of +waiting. + +By default innotop will display the problem in red text at the bottom of the +first table on the screen. You can disable this behavior with the +L<"show_cxn_errors_in_tbl"> configuration option, which is enabled by default. +If the L<"debug"> option is enabled, innotop will display the error at the +bottom of every table, not just the first. And if L<"show_cxn_errors"> is +enabled, innotop will print the error text to STDOUT as well. Error messages +might only display in the mode that caused the error, depending on the mode and +whether innotop is avoiding querying that connection. + +=head1 NON-INTERACTIVE OPERATION + +You can run innotop in non-interactive mode, in which case it is entirely +controlled from the configuration file and command-line options. To start +innotop in non-interactive mode, give the L"<--nonint"> command-line option. +This changes innotop's behavior in the following ways: + +=over + +=item * + +Certain Perl modules are not loaded. Term::Readline is not loaded, since +innotop doesn't prompt interactively. Term::ANSIColor and Win32::Console::ANSI +modules are not loaded. Term::ReadKey is still used, since innotop may have to +prompt for connection passwords when starting up. + +=item * + +innotop does not clear the screen after each tick. + +=item * + +innotop does not persist any changes to the configuration file. + +=item * + +If L<"--count"> is given and innotop is in incremental mode (see L<"status_inc"> +and L<"--inc">), innotop actually refreshes one more time than specified so it +can print incremental statistics. This suppresses output during the first +tick, so innotop may appear to hang. + +=item * + +innotop only displays the first table in each mode. This is so the output can +be easily processed with other command-line utilities such as awk and sed. To +change which tables display in each mode, see L<"TABLES">. Since L<"Q: Query +List"> mode is so important, innotop automatically disables the L<"q_header"> +table. This ensures you'll see the L<"processlist"> table, even if you have +innotop configured to show the q_header table during interactive operation. +Similarly, in L<"T: InnoDB Transactions"> mode, the L<"t_header"> table is +suppressed so you see only the L<"innodb_transactions"> table. + +=item * + +All output is tab-separated instead of being column-aligned with whitespace, and +innotop prints the full contents of each table instead of only printing one +screenful at a time. + +=item * + +innotop only prints column headers once instead of every tick (see +L<"hide_hdr">). innotop does not print table captions (see +L<"display_table_captions">). innotop ensures there are no empty lines in the +output. + +=item * + +innotop does not honor the L<"shorten"> transformation, which normally shortens +some numbers to human-readable formats. + +=item * + +innotop does not print a status line (see L<"INNOTOP STATUS">). + +=back + +=head1 CONFIGURING + +Nearly everything about innotop is configurable. Most things are possible to +change with built-in commands, but you can also edit the configuration file. + +While running innotop, press the '$' key to bring up the configuration editing +dialog. Press another key to select the type of data you want to edit: + +=over + +=item S: Statement Sleep Times + +Edits SQL statement sleep delays, which make innotop pause for the specified +amount of time after executing a statement. See L<"SQL STATEMENTS"> for a +definition of each statement and what it does. By default innotop does not +delay after any statements. + +This feature is included so you can customize the side-effects caused by +monitoring your server. You may not see any effects, but some innotop users +have noticed that certain MySQL versions under very high load with InnoDB +enabled take longer than usual to execute SHOW GLOBAL STATUS. If innotop calls +SHOW FULL PROCESSLIST immediately afterward, the processlist contains more +queries than the machine actually averages at any given moment. Configuring +innotop to pause briefly after calling SHOW GLOBAL STATUS alleviates this +effect. + +Sleep times are stored in the L<"stmt_sleep_times"> section of the configuration +file. Fractional-second sleeps are supported, subject to your hardware's +limitations. + +=item c: Edit Columns + +Starts the table editor on one of the displayed tables. See L<"TABLE EDITOR">. +An alternative way to start the table editor without entering the configuration +dialog is with the '^' key. + +=item g: General Configuration + +Starts the configuration editor to edit global and mode-specific configuration +variables (see L<"MODES">). innotop prompts you to choose a variable from among +the global and mode-specific ones depending on the current mode. + +=item k: Row-Coloring Rules + +Starts the row-coloring rules editor on one of the displayed table(s). See +L<"COLORS"> for details. + +=item p: Manage Plugins + +Starts the plugin configuration editor. See L<"PLUGINS"> for details. + +=item s: Server Groups + +Lets you create and edit server groups. See L<"SERVER GROUPS">. + +=item t: Choose Displayed Tables + +Lets you choose which tables to display in this mode. See L<"MODES"> and +L<"TABLES">. + +=back + +=head1 CONFIGURATION FILE + +innotop's default configuration file locations are $HOME/.innotop and +/etc/innotop/innotop.conf, and they are looked for in that order. If the first +configuration file exists, the second will not be processed. Those can be +overridden with the L<"--config"> command-line option. You can edit it by hand +safely, however innotop reads the configuration file when it starts, and, if +readonly is set to 0, writes it out again when it exits. Thus, if readonly is +set to 0, any changes you make by hand while innotop is running will be lost. + +innotop doesn't store its entire configuration in the configuration file. It +has a huge set of default configuration values that it holds only in memory, +and the configuration file only overrides these defaults. When you customize a +default setting, innotop notices, and then stores the customizations into the +file. This keeps the file size down, makes it easier to edit, and makes +upgrades easier. + +A configuration file is read-only be default. You can override that with +L<"--write">. See L<"readonly">. + +The configuration file is arranged into sections like an INI file. Each +section begins with [section-name] and ends with [/section-name]. Each +section's entries have a different syntax depending on the data they need to +store. You can put comments in the file; any line that begins with a # +character is a comment. innotop will not read the comments, so it won't write +them back out to the file when it exits. Comments in read-only configuration +files are still useful, though. + +The first line in the file is innotop's version number. This lets innotop +notice when the file format is not backwards-compatible, and upgrade smoothly +without destroying your customized configuration. + +The following list describes each section of the configuration file and the data +it contains: + +=over + +=item general + +The 'general' section contains global configuration variables and variables that +may be mode-specific, but don't belong in any other section. The syntax is a +simple key=value list. innotop writes a comment above each value to help you +edit the file by hand. + +=over + +=item S_func + +Controls S mode presentation (see L<"S: Variables & Status">). If g, values are +graphed; if s, values are like vmstat; if p, values are in a pivoted table. + +=item S_set + +Specifies which set of variables to display in L<"S: Variables & Status"> mode. +See L<"VARIABLE SETS">. + +=item auto_wipe_dl + +Instructs innotop to automatically wipe large deadlocks when it notices them. +When this happens you may notice a slight delay. At the next tick, you will +usually see the information that was being truncated by the large deadlock. + +=item charset + +Specifies what kind of characters to allow through the L<"no_ctrl_char"> +transformation. This keeps non-printable characters from confusing a +terminal when you monitor queries that contain binary data, such as images. + +The default is 'ascii', which considers anything outside normal ASCII to be a +control character. The other allowable values are 'unicode' and 'none'. 'none' +considers every character a control character, which can be useful for +collapsing ALL text fields in queries. + +=item cmd_filter + +This is the prefix that filters variables in L<"C: Command Summary"> mode. + +=item color + +Whether terminal coloring is permitted. + +=item cxn_timeout + +On MySQL versions 4.0.3 and newer, this variable is used to set the connection's +timeout, so MySQL doesn't close the connection if it is not used for a while. +This might happen because a connection isn't monitored in a particular mode, for +example. + +=item debug + +This option enables more verbose errors and makes innotop more strict in some +places. It can help in debugging filters and other user-defined code. It also +makes innotop write a lot of information to L<"debugfile"> when there is a +crash. + +=item debugfile + +A file to which innotop will write information when there is a crash. See +L<"FILES">. + +=item display_table_captions + +innotop displays a table caption above most tables. This variable suppresses or +shows captions on all tables globally. Some tables are configured with the +hide_caption property, which overrides this. + +=item global + +Whether to show GLOBAL variables and status. innotop only tries to do this on +servers which support the GLOBAL option to SHOW VARIABLES and SHOW STATUS. In +some MySQL versions, you need certain privileges to do this; if you don't have +them, innotop will not be able to fetch any variable and status data. This +configuration variable lets you run innotop and fetch what data you can even +without the elevated privileges. + +I can no longer find or reproduce the situation where GLOBAL wasn't allowed, but +I know there was one. + +=item graph_char + +Defines the character to use when drawing graphs in L<"S: Variables & Status"> +mode. + +=item header_highlight + +Defines how to highlight column headers. This only works if Term::ANSIColor is +available. Valid values are 'bold' and 'underline'. + +=item hide_hdr + +Hides column headers globally. + +=item interval + +The interval at which innotop will refresh its data (ticks). The interval is +implemented as a sleep time between ticks, so the true interval will vary +depending on how long it takes innotop to fetch and render data. + +This variable accepts fractions of a second. + +=item mode + +The mode in which innotop should start. Allowable arguments are the same as the +key presses that select a mode interactively. See L<"MODES">. + +=item num_digits + +How many digits to show in fractional numbers and percents. This variable's +range is between 0 and 9 and can be set directly from L<"S: Variables & Status"> +mode with the '+' and '-' keys. It is used in the L<"set_precision">, +L<"shorten">, and L<"percent"> transformations. + +=item num_status_sets + +Controls how many sets of status variables to display in pivoted L<"S: Variables +& Status"> mode. It also controls the number of old sets of variables innotop +keeps in its memory, so the larger this variable is, the more memory innotop +uses. + +=item plugin_dir + +Specifies where plugins can be found. By default, innotop stores plugins in the +'plugins' subdirectory of your innotop configuration directory. + +=item readonly + +Whether the configuration file is readonly. This cannot be set interactively. + +=item show_cxn_errors + +Makes innotop print connection errors to STDOUT. See L<"ERROR HANDLING">. + +=item show_cxn_errors_in_tbl + +Makes innotop display connection errors as rows in the first table on screen. +See L<"ERROR HANDLING">. + +=item show_percent + +Adds a '%' character after the value returned by the L<"percent"> +transformation. + +=item show_statusbar + +Controls whether to show the status bar in the display. See L<"INNOTOP +STATUS">. + +=item skip_innodb + +Disables fetching SHOW INNODB STATUS, in case your server(s) do not have InnoDB +enabled and you don't want innotop to try to fetch it. This can also be useful +when you don't have the SUPER privilege, required to run SHOW INNODB STATUS. + +=item status_inc + +Whether to show absolute or incremental values for status variables. +Incremental values are calculated as an offset from the last value innotop saw +for that variable. This is a global setting, but will probably become +mode-specific at some point. Right now it is honored a bit inconsistently; some +modes don't pay attention to it. + +=back + +=item plugins + +This section holds a list of package names of active plugins. If the plugin +exists, innotop will activate it. See L<"PLUGINS"> for more information. + +=item filters + +This section holds user-defined filters (see L<"FILTERS">). Each line is in the +format filter_name=text='filter text' tbls='table list'. + +The filter text is the text of the subroutine's code. The table list is a list +of tables to which the filter can apply. By default, user-defined filters apply +to the table for which they were created, but you can manually override that by +editing the definition in the configuration file. + +=item active_filters + +This section stores which filters are active on each table. Each line is in the +format table_name=filter_list. + +=item tbl_meta + +This section stores user-defined or user-customized columns (see L<"COLUMNS">). +Each line is in the format col_name=properties, where the properties are a +name=quoted-value list. + +=item connections + +This section holds the server connections you have defined. Each line is in +the format name=properties, where the properties are a name=value list. The +properties are self-explanatory, and the only one that is treated specially is +'pass' which is only present if 'savepass' is set. This section of the +configuration file will be skipped if any DSN, username, or password +command-line options are used. See L<"SERVER CONNECTIONS">. + +=item active_connections + +This section holds a list of which connections are active in each mode. Each +line is in the format mode_name=connection_list. + +=item server_groups + +This section holds server groups. Each line is in the format +name=connection_list. See L<"SERVER GROUPS">. + +=item active_server_groups + +This section holds a list of which server group is active in each mode. Each +line is in the format mode_name=server_group. + +=item max_values_seen + +This section holds the maximum values seen for variables. This is used to scale +the graphs in L<"S: Variables & Status"> mode. Each line is in the format +name=value. + +=item active_columns + +This section holds table column lists. Each line is in the format +tbl_name=column_list. See L<"COLUMNS">. + +=item sort_cols + +This section holds the sort definition. Each line is in the format +tbl_name=column_list. If a column is prefixed with '-', that column sorts +descending. See L<"SORTING">. + +=item visible_tables + +This section defines which tables are visible in each mode. Each line is in the +format mode_name=table_list. See L<"TABLES">. + +=item varsets + +This section defines variable sets for use in L<"S: Status & Variables"> mode. +Each line is in the format name=variable_list. See L<"VARIABLE SETS">. + +=item colors + +This section defines colorization rules. Each line is in the format +tbl_name=property_list. See L<"COLORS">. + +=item stmt_sleep_times + +This section contains statement sleep times. Each line is in the format +statement_name=sleep_time. See L<"S: Statement Sleep Times">. + +=item group_by + +This section contains column lists for table group_by expressions. Each line is +in the format tbl_name=column_list. See L<"GROUPING">. + +=back + +=head1 CUSTOMIZING + +You can customize innotop a great deal. For example, you can: + +=over + +=item * + +Choose which tables to display, and in what order. + +=item * + +Choose which columns are in those tables, and create new columns. + +=item * + +Filter which rows display with built-in filters, user-defined filters, and +quick-filters. + +=item * + +Sort the rows to put important data first or group together related rows. + +=item * + +Highlight rows with color. + +=item * + +Customize the alignment, width, and formatting of columns, and apply +transformations to columns to extract parts of their values or format the values +as you wish (for example, shortening large numbers to familiar units). + +=item * + +Design your own expressions to extract and combine data as you need. This gives +you unlimited flexibility. + +=back + +All these and more are explained in the following sections. + +=head2 TABLES + +A table is what you'd expect: a collection of columns. It also has some other +properties, such as a caption. Filters, sorting rules, and colorization rules +belong to tables and are covered in later sections. + +Internally, table meta-data is defined in a data structure called %tbl_meta. +This hash holds all built-in table definitions, which contain a lot of default +instructions to innotop. The meta-data includes the caption, a list of columns +the user has customized, a list of columns, a list of visible columns, a list of +filters, color rules, a sort-column list, sort direction, and some information +about the table's data sources. Most of this is customizable via the table +editor (see L<"TABLE EDITOR">). + +You can choose which tables to show by pressing the '$' key. See L<"MODES"> and +L<"TABLES">. + +The table life-cycle is as follows: + +=over + +=item * + +Each table begins with a data source, which is an array of hashes. See below +for details on data sources. + +=item * + +Each element of the data source becomes a row in the final table. + +=item * + +For each element in the data source, innotop extracts values from the source and +creates a row. This row is another hash, which later steps will refer to as +$set. The values innotop extracts are determined by the table's columns. Each +column has an extraction subroutine, compiled from an expression (see +L<"EXPRESSIONS">). The resulting row is a hash whose keys are named the same as +the column name. + +=item * + +innotop filters the rows, removing those that don't need to be displayed. See +L<"FILTERS">. + +=item * + +innotop sorts the rows. See L<"SORTING">. + +=item * + +innotop groups the rows together, if specified. See L<"GROUPING">. + +=item * + +innotop colorizes the rows. See L<"COLORS">. + +=item * + +innotop transforms the column values in each row. See L<"TRANSFORMATIONS">. + +=item * + +innotop optionally pivots the rows (see L<"PIVOTING">), then filters and sorts +them. + +=item * + +innotop formats and justifies the rows as a table. During this step, innotop +applies further formatting to the column values, including alignment, maximum +and minimum widths. innotop also does final error checking to ensure there are +no crashes due to undefined values. innotop then adds a caption if specified, +and the table is ready to print. + +=back + +The lifecycle is slightly different if the table is pivoted, as noted above. To +clarify, if the table is pivoted, the process is extract, group, transform, +pivot, filter, sort, create. If it's not pivoted, the process is extract, +filter, sort, group, color, transform, create. This slightly convoluted process +doesn't map all that well to SQL, but pivoting complicates things pretty +thoroughly. Roughly speaking, filtering and sorting happen as late as needed to +effect the final result as you might expect, but as early as possible for +efficiency. + +Each built-in table is described below: + +=over + +=item adaptive_hash_index + +Displays data about InnoDB's adaptive hash index. Data source: +L<"STATUS_VARIABLES">. + +=item buffer_pool + +Displays data about InnoDB's buffer pool. Data source: L<"STATUS_VARIABLES">. + +=item cmd_summary + +Displays weighted status variables. Data source: L<"STATUS_VARIABLES">. + +=item deadlock_locks + +Shows which locks were held and waited for by the last detected deadlock. Data +source: L<"DEADLOCK_LOCKS">. + +=item deadlock_transactions + +Shows transactions involved in the last detected deadlock. Data source: +L<"DEADLOCK_TRANSACTIONS">. + +=item explain + +Shows the output of EXPLAIN. Data source: L<"EXPLAIN">. + +=item file_io_misc + +Displays data about InnoDB's file and I/O operations. Data source: +L<"STATUS_VARIABLES">. + +=item fk_error + +Displays various data about InnoDB's last foreign key error. Data source: +L<"STATUS_VARIABLES">. + +=item innodb_locks + +Displays InnoDB locks. Data source: L<"INNODB_LOCKS">. + +=item innodb_transactions + +Displays data about InnoDB's current transactions. Data source: +L<"INNODB_TRANSACTIONS">. + +=item insert_buffers + +Displays data about InnoDB's insert buffer. Data source: L<"STATUS_VARIABLES">. + +=item io_threads + +Displays data about InnoDB's I/O threads. Data source: L<"IO_THREADS">. + +=item log_statistics + +Displays data about InnoDB's logging system. Data source: L<"STATUS_VARIABLES">. + +=item master_status + +Displays replication master status. Data source: L<"STATUS_VARIABLES">. + +=item open_tables + +Displays open tables. Data source: L<"OPEN_TABLES">. + +=item page_statistics + +Displays InnoDB page statistics. Data source: L<"STATUS_VARIABLES">. + +=item pending_io + +Displays InnoDB pending I/O operations. Data source: L<"STATUS_VARIABLES">. + +=item processlist + +Displays current MySQL processes (threads/connections). Data source: +L<"PROCESSLIST">. + +=item q_header + +Displays various status values. Data source: L<"STATUS_VARIABLES">. + +=item row_operation_misc + +Displays data about InnoDB's row operations. Data source: +L<"STATUS_VARIABLES">. + +=item row_operations + +Displays data about InnoDB's row operations. Data source: +L<"STATUS_VARIABLES">. + +=item semaphores + +Displays data about InnoDB's semaphores and mutexes. Data source: +L<"STATUS_VARIABLES">. + +=item slave_io_status + +Displays data about the slave I/O thread. Data source: +L<"STATUS_VARIABLES">. + +=item slave_sql_status + +Displays data about the slave SQL thread. Data source: L<"STATUS_VARIABLES">. + +=item t_header + +Displays various InnoDB status values. Data source: L<"STATUS_VARIABLES">. + +=item var_status + +Displays user-configurable data. Data source: L<"STATUS_VARIABLES">. + +=item wait_array + +Displays data about InnoDB's OS wait array. Data source: L<"OS_WAIT_ARRAY">. + +=back + +=head2 COLUMNS + +Columns belong to tables. You can choose a table's columns by pressing the '^' +key, which starts the L<"TABLE EDITOR"> and lets you choose and edit columns. +Pressing 'e' from within the table editor lets you edit the column's properties: + +=over + +=item * + +hdr: a column header. This appears in the first row of the table. + +=item * + +just: justification. '-' means left-justified and '' means right-justified, +just as with printf formatting codes (not a coincidence). + +=item * + +dec: whether to further align the column on the decimal point. + +=item * + +num: whether the column is numeric. This affects how values are sorted +(lexically or numerically). + +=item * + +label: a small note about the column, which appears in dialogs that help the +user choose columns. + +=item * + +src: an expression that innotop uses to extract the column's data from its +source (see L<"DATA SOURCES">). See L<"EXPRESSIONS"> for more on expressions. + +=item * + +minw: specifies a minimum display width. This helps stabilize the display, +which makes it easier to read if the data is changing frequently. + +=item * + +maxw: similar to minw. + +=item * + +trans: a list of column transformations. See L<"TRANSFORMATIONS">. + +=item * + +agg: an aggregate function. See L<"GROUPING">. The default is L<"first">. + +=item * + +aggonly: controls whether the column only shows when grouping is enabled on the +table (see L<"GROUPING">). By default, this is disabled. This means columns +will always be shown by default, whether grouping is enabled or not. If a +column's aggonly is set true, the column will appear when you toggle grouping on +the table. Several columns are set this way, such as the count column on +L<"processlist"> and L<"innodb_transactions">, so you don't see a count when the +grouping isn't enabled, but you do when it is. + +=back + +=head2 FILTERS + +Filters remove rows from the display. They behave much like a WHERE clause in +SQL. innotop has several built-in filters, which remove irrelevant information +like inactive queries, but you can define your own as well. innotop also lets +you create quick-filters, which do not get saved to the configuration file, and +are just an easy way to quickly view only some rows. + +You can enable or disable a filter on any table. Press the '%' key (mnemonic: % +looks kind of like a line being filtered between two circles) and choose which +table you want to filter, if asked. You'll then see a list of possible filters +and a list of filters currently enabled for that table. Type the names of +filters you want to apply and press Enter. + +=head3 USER-DEFINED FILTERS + +If you type a name that doesn't exist, innotop will prompt you to create the +filter. Filters are easy to create if you know Perl, and not hard if you don't. +What you're doing is creating a subroutine that returns true if the row should +be displayed. The row is a hash reference passed to your subroutine as $set. + +For example, imagine you want to filter the processlist table so you only see +queries that have been running more than five minutes. Type a new name for your +filter, and when prompted for the subroutine body, press TAB to initiate your +terminal's auto-completion. You'll see the names of the columns in the +L<"processlist"> table (innotop generally tries to help you with auto-completion +lists). You want to filter on the 'time' column. Type the text "$set->{time} > +300" to return true when the query is more than five minutes old. That's all +you need to do. + +In other words, the code you're typing is surrounded by an implicit context, +which looks like this: + + sub filter { + my ( $set ) = @_; + # YOUR CODE HERE + } + +If your filter doesn't work, or if something else suddenly behaves differently, +you might have made an error in your filter, and innotop is silently catching +the error. Try enabling L<"debug"> to make innotop throw an error instead. + +=head3 QUICK-FILTERS + +innotop's quick-filters are a shortcut to create a temporary filter that doesn't +persist when you restart innotop. To create a quick-filter, press the '/' key. +innotop will prompt you for the column name and filter text. Again, you can use +auto-completion on column names. The filter text can be just the text you want +to "search for." For example, to filter the L<"processlist"> table on queries +that refer to the products table, type '/' and then 'info product'. + +The filter text can actually be any Perl regular expression, but of course a +literal string like 'product' works fine as a regular expression. + +Behind the scenes innotop compiles the quick-filter into a specially tagged +filter that is otherwise like any other filter. It just isn't saved to the +configuration file. + +To clear quick-filters, press the '\' key and innotop will clear them all at +once. + +=head2 SORTING + +innotop has sensible built-in defaults to sort the most important rows to the +top of the table. Like anything else in innotop, you can customize how any +table is sorted. + +To start the sort dialog, start the L<"TABLE EDITOR"> with the '^' key, choose a +table if necessary, and press the 's' key. You'll see a list of columns you can +use in the sort expression and the current sort expression, if any. Enter a +list of columns by which you want to sort and press Enter. If you want to +reverse sort, prefix the column name with a minus sign. For example, if you +want to sort by column a ascending, then column b descending, type 'a -b'. You +can also explicitly add a + in front of columns you want to sort ascending, but +it's not required. + +Some modes have keys mapped to open this dialog directly, and to quickly reverse +sort direction. Press '?' as usual to see which keys are mapped in any mode. + +=head2 GROUPING + +innotop can group, or aggregate, rows together (the terms are used +interchangeably). This is quite similar to an SQL GROUP BY clause. You can +specify to group on certain columns, or if you don't specify any, the entire set +of rows is treated as one group. This is quite like SQL so far, but unlike SQL, +you can also select un-grouped columns. innotop actually aggregates every +column. If you don't explicitly specify a grouping function, the default is +'first'. This is basically a convenience so you don't have to specify an +aggregate function for every column you want in the result. + +You can quickly toggle grouping on a table with the '=' key, which toggles its +aggregate property. This property doesn't persist to the config file. + +The columns by which the table is grouped are specified in its group_by +property. When you turn grouping on, innotop places the group_by columns at the +far left of the table, even if they're not supposed to be visible. The rest of +the visible columns appear in order after them. + +Two tables have default group_by lists and a count column built in: +L<"processlist"> and L<"innodb_transactions">. The grouping is by connection +and status, so you can quickly see how many queries or transactions are in a +given status on each server you're monitoring. The time columns are aggregated +as a sum; other columns are left at the default 'first' aggregation. + +By default, the table shown in L<"S: Variables & Status"> mode also uses +grouping so you can monitor variables and status across many servers. The +default aggregation function in this mode is 'avg'. + +Valid grouping functions are defined in the %agg_funcs hash. They include + +=over + +=item first + +Returns the first element in the group. + +=item count + +Returns the number of elements in the group, including undefined elements, much +like SQL's COUNT(*). + +=item avg + +Returns the average of defined elements in the group. + +=item sum + +Returns the sum of elements in the group. + +=back + +Here's an example of grouping at work. Suppose you have a very busy server with +hundreds of open connections, and you want to see how many connections are in +what status. Using the built-in grouping rules, you can press 'Q' to enter +L<"Q: Query List"> mode. Press '=' to toggle grouping (if necessary, select the +L<"processlist"> table when prompted). + +Your display might now look like the following: + + Query List (? for help) localhost, 32:33, 0.11 QPS, 1 thd, 5.0.38-log + + CXN Cmd Cnt ID User Host Time Query + localhost Query 49 12933 webusr localhost 19:38 SELECT * FROM + localhost Sending Da 23 2383 webusr localhost 12:43 SELECT col1, + localhost Sleep 120 140 webusr localhost 5:18:12 + localhost Statistics 12 19213 webusr localhost 01:19 SELECT * FROM + +That's actually quite a worrisome picture. You've got a lot of idle connections +(Sleep), and some connections executing queries (Query and Sending Data). +That's okay, but you also have a lot in Statistics status, collectively spending +over a minute. That means the query optimizer is having a really hard time +optimizing your statements. Something is wrong; it should normally take +milliseconds to optimize queries. You might not have seen this pattern if you +didn't look at your connections in aggregate. (This is a made-up example, but +it can happen in real life). + +=head2 PIVOTING + +innotop can pivot a table for more compact display, similar to a Pivot Table in +a spreadsheet (also known as a crosstab). Pivoting a table makes columns into +rows. Assume you start with this table: + + foo bar + === === + 1 3 + 2 4 + +After pivoting, the table will look like this: + + name set0 set1 + ==== ==== ==== + foo 1 2 + bar 3 4 + +To get reasonable results, you might need to group as well as pivoting. +innotop currently does this for L<"S: Variables & Status"> mode. + +=head2 COLORS + +By default, innotop highlights rows with color so you can see at a glance which +rows are more important. You can customize the colorization rules and add your +own to any table. Open the table editor with the '^' key, choose a table if +needed, and press 'o' to open the color editor dialog. + +The color editor dialog displays the rules applied to the table, in the order +they are evaluated. Each row is evaluated against each rule to see if the rule +matches the row; if it does, the row gets the specified color, and no further +rules are evaluated. The rules look like the following: + + state eq Locked black on_red + cmd eq Sleep white + user eq system user white + cmd eq Connect white + cmd eq Binlog Dump white + time > 600 red + time > 120 yellow + time > 60 green + time > 30 cyan + +This is the default rule set for the L<"processlist"> table. In order of +priority, these rules make locked queries black on a red background, "gray out" +connections from replication and sleeping queries, and make queries turn from +cyan to red as they run longer. + +(For some reason, the ANSI color code "white" is actually a light gray. Your +terminal's display may vary; experiment to find colors you like). + +You can use keystrokes to move the rules up and down, which re-orders their +priority. You can also delete rules and add new ones. If you add a new rule, +innotop prompts you for the column, an operator for the comparison, a value +against which to compare the column, and a color to assign if the rule matches. +There is auto-completion and prompting at each step. + +The value in the third step needs to be correctly quoted. innotop does not try +to quote the value because it doesn't know whether it should treat the value as +a string or a number. If you want to compare the column against a string, as +for example in the first rule above, you should enter 'Locked' surrounded by +quotes. If you get an error message about a bareword, you probably should have +quoted something. + +=head2 EXPRESSIONS + +Expressions are at the core of how innotop works, and are what enables you to +extend innotop as you wish. Recall the table lifecycle explained in +L<"TABLES">. Expressions are used in the earliest step, where it extracts +values from a data source to form rows. + +It does this by calling a subroutine for each column, passing it the source data +set, a set of current values, and a set of previous values. These are all +needed so the subroutine can calculate things like the difference between this +tick and the previous tick. + +The subroutines that extract the data from the set are compiled from +expressions. This gives significantly more power than just naming the values to +fill the columns, because it allows the column's value to be calculated from +whatever data is necessary, but avoids the need to write complicated and lengthy +Perl code. + +innotop begins with a string of text that can look as simple as a value's name +or as complicated as a full-fledged Perl expression. It looks at each +'bareword' token in the string and decides whether it's supposed to be a key +into the $set hash. A bareword is an unquoted value that isn't already +surrounded by code-ish things like dollar signs or curly brackets. If innotop +decides that the bareword isn't a function or other valid Perl code, it converts +it into a hash access. After the whole string is processed, innotop compiles a +subroutine, like this: + + sub compute_column_value { + my ( $set, $cur, $pre ) = @_; + my $val = # EXPANDED STRING GOES HERE + return $val; + } + +Here's a concrete example, taken from the header table L<"q_header"> in L<"Q: +Query List"> mode. This expression calculates the qps, or Queries Per Second, +column's values, from the values returned by SHOW STATUS: + + Questions/Uptime_hires + +innotop decides both words are barewords, and transforms this expression into +the following Perl code: + + $set->{Questions}/$set->{Uptime_hires} + +When surrounded by the rest of the subroutine's code, this is executable Perl +that calculates a high-resolution queries-per-second value. + +The arguments to the subroutine are named $set, $cur, and $pre. In most cases, +$set and $cur will be the same values. However, if L<"status_inc"> is set, $cur +will not be the same as $set, because $set will already contain values that are +the incremental difference between $cur and $pre. + +Every column in innotop is computed by subroutines compiled in the same fashion. +There is no difference between innotop's built-in columns and user-defined +columns. This keeps things consistent and predictable. + +=head2 TRANSFORMATIONS + +Transformations change how a value is rendered. For example, they can take a +number of seconds and display it in H:M:S format. The following transformations +are defined: + +=over + +=item commify + +Adds commas to large numbers every three decimal places. + +=item dulint_to_int + +Accepts two unsigned integers and converts them into a single longlong. This is +useful for certain operations with InnoDB, which uses two integers as +transaction identifiers, for example. + +=item no_ctrl_char + +Removes quoted control characters from the value. This is affected by the +L<"charset"> configuration variable. + +This transformation only operates within quoted strings, for example, values to +a SET clause in an UPDATE statement. It will not alter the UPDATE statement, +but will collapse the quoted string to [BINARY] or [TEXT], depending on the +charset. + +=item percent + +Converts a number to a percentage by multiplying it by two, formatting it with +L<"num_digits"> digits after the decimal point, and optionally adding a percent +sign (see L<"show_percent">). + +=item secs_to_time + +Formats a number of seconds as time in days+hours:minutes:seconds format. + +=item set_precision + +Formats numbers with L<"num_digits"> number of digits after the decimal point. + +=item shorten + +Formats a number as a unit of 1024 (k/M/G/T) and with L<"num_digits"> number of +digits after the decimal point. + +=back + +=head2 TABLE EDITOR + +The innotop table editor lets you customize tables with keystrokes. You start +the table editor with the '^' key. If there's more than one table on the +screen, it will prompt you to choose one of them. Once you do, innotop will +show you something like this: + + Editing table definition for Buffer Pool. Press ? for help, q to quit. + + name hdr label src + cxn CXN Connection from which cxn + buf_pool_size Size Buffer pool size IB_bp_buf_poo + buf_free Free Bufs Buffers free in the b IB_bp_buf_fre + pages_total Pages Pages total IB_bp_pages_t + pages_modified Dirty Pages Pages modified (dirty IB_bp_pages_m + buf_pool_hit_rate Hit Rate Buffer pool hit rate IB_bp_buf_poo + total_mem_alloc Memory Total memory allocate IB_bp_total_m + add_pool_alloc Add'l Pool Additonal pool alloca IB_bp_add_poo + +The first line shows which table you're editing, and reminds you again to press +'?' for a list of key mappings. The rest is a tabular representation of the +table's columns, because that's likely what you're trying to edit. However, you +can edit more than just the table's columns; this screen can start the filter +editor, color rule editor, and more. + +Each row in the display shows a single column in the table you're editing, along +with a couple of its properties such as its header and source expression (see +L<"EXPRESSIONS">). + +The key mappings are Vim-style, as in many other places. Pressing 'j' and 'k' +moves the highlight up or down. You can then (d)elete or (e)dit the highlighted +column. You can also (a)dd a column to the table. This actually just activates +one of the columns already defined for the table; it prompts you to choose from +among the columns available but not currently displayed. Finally, you can +re-order the columns with the '+' and '-' keys. + +You can do more than just edit the columns with the table editor, you can also +edit other properties, such as the table's sort expression and group-by +expression. Press '?' to see the full list, of course. + +If you want to really customize and create your own column, as opposed to just +activating a built-in one that's not currently displayed, press the (n)ew key, +and innotop will prompt you for the information it needs: + +=over + +=item * + +The column name: this needs to be a word without any funny characters, e.g. just +letters, numbers and underscores. + +=item * + +The column header: this is the label that appears at the top of the column, in +the table header. This can have spaces and funny characters, but be careful not +to make it too wide and waste space on-screen. + +=item * + +The column's data source: this is an expression that determines what data from +the source (see L<"TABLES">) innotop will put into the column. This can just be +the name of an item in the source, or it can be a more complex expression, as +described in L<"EXPRESSIONS">. + +=back + +Once you've entered the required data, your table has a new column. There is no +difference between this column and the built-in ones; it can have all the same +properties and behaviors. innotop will write the column's definition to the +configuration file, so it will persist across sessions. + +Here's an example: suppose you want to track how many times your slaves have +retried transactions. According to the MySQL manual, the +Slave_retried_transactions status variable gives you that data: "The total +number of times since startup that the replication slave SQL thread has retried +transactions. This variable was added in version 5.0.4." This is appropriate to +add to the L<"slave_sql_status"> table. + +To add the column, switch to the replication-monitoring mode with the 'M' key, +and press the '^' key to start the table editor. When prompted, choose +slave_sql_status as the table, then press 'n' to create the column. Type +'retries' as the column name, 'Retries' as the column header, and +'Slave_retried_transactions' as the source. Now the column is created, and you +see the table editor screen again. Press 'q' to exit the table editor, and +you'll see your column at the end of the table. + +=head1 VARIABLE SETS + +Variable sets are used in L<"S: Variables & Status"> mode to define more easily +what variables you want to monitor. Behind the scenes they are compiled to a +list of expressions, and then into a column list so they can be treated just +like columns in any other table, in terms of data extraction and +transformations. However, you're protected from the tedious details by a syntax +that ought to feel very natural to you: a SQL SELECT list. + +The data source for variable sets, and indeed the entire S mode, is the +combination of SHOW STATUS, SHOW VARIABLES, and SHOW INNODB STATUS. Imagine +that you had a huge table with one column per variable returned from those +statements. That's the data source for variable sets. You can now query this +data source just like you'd expect. For example: + + Questions, Uptime, Questions/Uptime as QPS + +Behind the scenes innotop will split that variable set into three expressions, +compile them and turn them into a table definition, then extract as usual. This +becomes a "variable set," or a "list of variables you want to monitor." + +innotop lets you name and save your variable sets, and writes them to the +configuration file. You can choose which variable set you want to see with the +'c' key, or activate the next and previous sets with the '>' and '<' keys. +There are many built-in variable sets as well, which should give you a good +start for creating your own. Press 'e' to edit the current variable set, or +just to see how it's defined. To create a new one, just press 'c' and type its +name. + +You may want to use some of the functions listed in L<"TRANSFORMATIONS"> to help +format the results. In particular, L<"set_precision"> is often useful to limit +the number of digits you see. Extending the above example, here's how: + + Questions, Uptime, set_precision(Questions/Uptime) as QPS + +Actually, this still needs a little more work. If your L<"interval"> is less +than one second, you might be dividing by zero because Uptime is incremental in +this mode by default. Instead, use Uptime_hires: + + Questions, Uptime, set_precision(Questions/Uptime_hires) as QPS + +This example is simple, but it shows how easy it is to choose which variables +you want to monitor. + +=head1 PLUGINS + +innotop has a simple but powerful plugin mechanism by which you can extend +or modify its existing functionality, and add new functionality. innotop's +plugin functionality is event-based: plugins register themselves to be called +when events happen. They then have a chance to influence the event. + +An innotop plugin is a Perl module placed in innotop's L<"plugin_dir"> +directory. On UNIX systems, you can place a symbolic link to the module instead +of putting the actual file there. innotop automatically discovers the file. If +there is a corresponding entry in the L<"plugins"> configuration file section, +innotop loads and activates the plugin. + +The module must conform to innotop's plugin interface. Additionally, the source +code of the module must be written in such a way that innotop can inspect the +file and determine the package name and description. + +=head2 Package Source Convention + +innotop inspects the plugin module's source to determine the Perl package name. +It looks for a line of the form "package Foo;" and if found, considers the +plugin's package name to be Foo. Of course the package name can be a valid Perl +package name, with double semicolons and so on. + +It also looks for a description in the source code, to make the plugin editor +more human-friendly. The description is a comment line of the form "# +description: Foo", where "Foo" is the text innotop will consider to be the +plugin's description. + +=head2 Plugin Interface + +The innotop plugin interface is quite simple: innotop expects the plugin to be +an object-oriented module it can call certain methods on. The methods are + +=over + +=item new(%variables) + +This is the plugin's constructor. It is passed a hash of innotop's variables, +which it can manipulate (see L<"Plugin Variables">). It must return a reference +to the newly created plugin object. + +At construction time, innotop has only loaded the general configuration and +created the default built-in variables with their default contents (which is +quite a lot). Therefore, the state of the program is exactly as in the innotop +source code, plus the configuration variables from the L<"general"> section in +the config file. + +If your plugin manipulates the variables, it is changing global data, which is +shared by innotop and all plugins. Plugins are loaded in the order they're +listed in the config file. Your plugin may load before or after another plugin, +so there is a potential for conflict or interaction between plugins if they +modify data other plugins use or modify. + +=item register_for_events() + +This method must return a list of events in which the plugin is interested, if +any. See L<"Plugin Events"> for the defined events. If the plugin returns an +event that's not defined, the event is ignored. + +=item event handlers + +The plugin must implement a method named the same as each event for which it has +registered. In other words, if the plugin returns qw(foo bar) from +register_for_events(), it must have foo() and bar() methods. These methods are +callbacks for the events. See L<"Plugin Events"> for more details about each +event. + +=back + +=head2 Plugin Variables + +The plugin's constructor is passed a hash of innotop's variables, which it can +manipulate. It is probably a good idea if the plugin object saves a copy of it +for later use. The variables are defined in the innotop variable +%pluggable_vars, and are as follows: + +=over + +=item action_for + +A hashref of key mappings. These are innotop's global hot-keys. + +=item agg_funcs + +A hashref of functions that can be used for grouping. See L<"GROUPING">. + +=item config + +The global configuration hash. + +=item connections + +A hashref of connection specifications. These are just specifications of how to +connect to a server. + +=item dbhs + +A hashref of innotop's database connections. These are actual DBI connection +objects. + +=item filters + +A hashref of filters applied to table rows. See L<"FILTERS"> for more. + +=item modes + +A hashref of modes. See L<"MODES"> for more. + +=item server_groups + +A hashref of server groups. See L<"SERVER GROUPS">. + +=item tbl_meta + +A hashref of innotop's table meta-data, with one entry per table (see +L<"TABLES"> for more information). + +=item trans_funcs + +A hashref of transformation functions. See L<"TRANSFORMATIONS">. + +=item var_sets + +A hashref of variable sets. See L<"VARIABLE SETS">. + +=back + +=head2 Plugin Events + +Each event is defined somewhere in the innotop source code. When innotop runs +that code, it executes the callback function for each plugin that expressed its +interest in the event. innotop passes some data for each event. The events are +defined in the %event_listener_for variable, and are as follows: + +=over + +=item extract_values($set, $cur, $pre, $tbl) + +This event occurs inside the function that extracts values from a data source. +The arguments are the set of values, the current values, the previous values, +and the table name. + +=item set_to_tbl + +Events are defined at many places in this subroutine, which is responsible for +turning an arrayref of hashrefs into an arrayref of lines that can be printed to +the screen. The events all pass the same data: an arrayref of rows and the name +of the table being created. The events are set_to_tbl_pre_filter, +set_to_tbl_pre_sort,set_to_tbl_pre_group, set_to_tbl_pre_colorize, +set_to_tbl_pre_transform, set_to_tbl_pre_pivot, set_to_tbl_pre_create, +set_to_tbl_post_create. + +=item draw_screen($lines) + +This event occurs inside the subroutine that prints the lines to the screen. +$lines is an arrayref of strings. + +=back + +=head2 Simple Plugin Example + +The easiest way to explain the plugin functionality is probably with a simple +example. The following module adds a column to the beginning of every table and +sets its value to 1. + + use strict; + use warnings FATAL => 'all'; + + package Innotop::Plugin::Example; + # description: Adds an 'example' column to every table + + sub new { + my ( $class, %vars ) = @_; + # Store reference to innotop's variables in $self + my $self = bless { %vars }, $class; + + # Design the example column + my $col = { + hdr => 'Example', + just => '', + dec => 0, + num => 1, + label => 'Example', + src => 'example', # Get data from this column in the data source + tbl => '', + trans => [], + }; + + # Add the column to every table. + my $tbl_meta = $vars{tbl_meta}; + foreach my $tbl ( values %$tbl_meta ) { + # Add the column to the list of defined columns + $tbl->{cols}->{example} = $col; + # Add the column to the list of visible columns + unshift @{$tbl->{visible}}, 'example'; + } + + # Be sure to return a reference to the object. + return $self; + } + + # I'd like to be called when a data set is being rendered into a table, please. + sub register_for_events { + my ( $self ) = @_; + return qw(set_to_tbl_pre_filter); + } + + # This method will be called when the event fires. + sub set_to_tbl_pre_filter { + my ( $self, $rows, $tbl ) = @_; + # Set the example column's data source to the value 1. + foreach my $row ( @$rows ) { + $row->{example} = 1; + } + } + + 1; + +=head2 Plugin Editor + +The plugin editor lets you view the plugins innotop discovered and activate or +deactivate them. Start the editor by pressing $ to start the configuration +editor from any mode. Press the 'p' key to start the plugin editor. You'll see +a list of plugins innotop discovered. You can use the 'j' and 'k' keys to move +the highlight to the desired one, then press the * key to toggle it active or +inactive. Exit the editor and restart innotop for the changes to take effect. + +=head1 SQL STATEMENTS + +innotop uses a limited set of SQL statements to retrieve data from MySQL for +display. The statements are customized depending on the server version against +which they are executed; for example, on MySQL 5 and newer, INNODB_STATUS +executes "SHOW ENGINE INNODB STATUS", while on earlier versions it executes +"SHOW INNODB STATUS". The statements are as follows: + + Statement SQL executed + =================== =============================== + INNODB_STATUS SHOW [ENGINE] INNODB STATUS + KILL_CONNECTION KILL + KILL_QUERY KILL QUERY + OPEN_TABLES SHOW OPEN TABLES + PROCESSLIST SHOW FULL PROCESSLIST + SHOW_MASTER_LOGS SHOW MASTER LOGS + SHOW_MASTER_STATUS SHOW MASTER STATUS + SHOW_SLAVE_STATUS SHOW SLAVE STATUS + SHOW_STATUS SHOW [GLOBAL] STATUS + SHOW_VARIABLES SHOW [GLOBAL] VARIABLES + +=head1 DATA SOURCES + +Each time innotop extracts values to create a table (see L<"EXPRESSIONS"> and +L<"TABLES">), it does so from a particular data source. Largely because of the +complex data extracted from SHOW INNODB STATUS, this is slightly messy. SHOW +INNODB STATUS contains a mixture of single values and repeated values that form +nested data sets. + +Whenever innotop fetches data from MySQL, it adds two extra bits to each set: +cxn and Uptime_hires. cxn is the name of the connection from which the data +came. Uptime_hires is a high-resolution version of the server's Uptime status +variable, which is important if your L<"interval"> setting is sub-second. + +Here are the kinds of data sources from which data is extracted: + +=over + +=item STATUS_VARIABLES + +This is the broadest category, into which the most kinds of data fall. It +begins with the combination of SHOW STATUS and SHOW VARIABLES, but other sources +may be included as needed, for example, SHOW MASTER STATUS and SHOW SLAVE +STATUS, as well as many of the non-repeated values from SHOW INNODB STATUS. + +=item DEADLOCK_LOCKS + +This data is extracted from the transaction list in the LATEST DETECTED DEADLOCK +section of SHOW INNODB STATUS. It is nested two levels deep: transactions, then +locks. + +=item DEADLOCK_TRANSACTIONS + +This data is from the transaction list in the LATEST DETECTED DEADLOCK +section of SHOW INNODB STATUS. It is nested one level deep. + +=item EXPLAIN + +This data is from the result set returned by EXPLAIN. + +=item INNODB_TRANSACTIONS + +This data is from the TRANSACTIONS section of SHOW INNODB STATUS. + +=item IO_THREADS + +This data is from the list of threads in the the FILE I/O section of SHOW INNODB +STATUS. + +=item INNODB_LOCKS + +This data is from the TRANSACTIONS section of SHOW INNODB STATUS and is nested +two levels deep. + +=item OPEN_TABLES + +This data is from SHOW OPEN TABLES. + +=item PROCESSLIST + +This data is from SHOW FULL PROCESSLIST. + +=item OS_WAIT_ARRAY + +This data is from the SEMAPHORES section of SHOW INNODB STATUS and is nested one +level deep. It comes from the lines that look like this: + + --Thread 1568861104 has waited at btr0cur.c line 424 .... + +=back + +=head1 MYSQL PRIVILEGES + +=over + +=item * + +You must connect to MySQL as a user who has the SUPER privilege for many of the +functions. + +=item * + +If you don't have the SUPER privilege, you can still run some functions, but you +won't necessarily see all the same data. + +=item * + +You need the PROCESS privilege to see the list of currently running queries in Q +mode. + +=item * + +You need special privileges to start and stop slave servers. + +=item * + +You need appropriate privileges to create and drop the deadlock tables if needed +(see L<"SERVER CONNECTIONS">). + +=back + +=head1 SYSTEM REQUIREMENTS + +You need Perl to run innotop, of course. You also need a few Perl modules: DBI, +DBD::mysql, Term::ReadKey, and Time::HiRes. These should be included with most +Perl distributions, but in case they are not, I recommend using versions +distributed with your operating system or Perl distribution, not from CPAN. +Term::ReadKey in particular has been known to cause problems if installed from +CPAN. + +If you have Term::ANSIColor, innotop will use it to format headers more readably +and compactly. (Under Microsoft Windows, you also need Win32::Console::ANSI for +terminal formatting codes to be honored). If you install Term::ReadLine, +preferably Term::ReadLine::Gnu, you'll get nice auto-completion support. + +I run innotop on Gentoo GNU/Linux, Debian and Ubuntu, and I've had feedback from +people successfully running it on Red Hat, CentOS, Solaris, and Mac OSX. I +don't see any reason why it won't work on other UNIX-ish operating systems, but +I don't know for sure. It also runs on Windows under ActivePerl without +problem. + +innotop has been used on MySQL versions 3.23.58, 4.0.27, 4.1.0, 4.1.22, 5.0.26, +5.1.15, and 5.2.3. If it doesn't run correctly for you, that is a bug that +should be reported. + +=head1 FILES + +$HOMEDIR/.innotop and/or /etc/innotop are used to store +configuration information. Files include the configuration file innotop.conf, +the core_dump file which contains verbose error messages if L<"debug"> is +enabled, and the plugins/ subdirectory. + +=head1 GLOSSARY OF TERMS + +=over + +=item tick + +A tick is a refresh event, when innotop re-fetches data from connections and +displays it. + +=back + +=head1 ACKNOWLEDGEMENTS + +The following people and organizations are acknowledged for various reasons. +Hopefully no one has been forgotten. + +Allen K. Smith, +Aurimas Mikalauskas, +Bartosz Fenski, +Brian Miezejewski, +Christian Hammers, +Cyril Scetbon, +Dane Miller, +David Multer, +Dr. Frank Ullrich, +Giuseppe Maxia, +Google.com Site Reliability Engineers, +Google Code, +Jan Pieter Kunst, +Jari Aalto, +Jay Pipes, +Jeremy Zawodny, +Johan Idren, +Kristian Kohntopp, +Lenz Grimmer, +Maciej Dobrzanski, +Michiel Betel, +MySQL AB, +Paul McCullagh, +Sebastien Estienne, +Sourceforge.net, +Steven Kreuzer, +The Gentoo MySQL Team, +Trevor Price, +Yaar Schnitman, +and probably more people that have not been included. + +(If your name has been misspelled, it's probably out of fear of putting +international characters into this documentation; earlier versions of Perl might +not be able to compile it then). + +=head1 COPYRIGHT, LICENSE AND WARRANTY + +This program is copyright (c) 2006 Baron Schwartz. +Feedback and improvements are welcome. + +THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + +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 +Foundation, version 2; OR the Perl Artistic License. On UNIX and similar +systems, you can issue `man perlgpl' or `man perlartistic' to read these +licenses. + +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. + +Execute innotop and press '!' to see this information at any time. + +=head1 AUTHOR + +Originally written by Baron Schwartz; currently maintained by Aaron Racine. + +=head1 BUGS + +You can report bugs, ask for improvements, and get other help and support at +L. There are mailing lists, a source code +browser, a bug tracker, etc. Please use these instead of contacting the +maintainer or author directly, as it makes our job easier and benefits others if the +discussions are permanent and public. Of course, if you need to contact us in +private, please do. + +=cut diff --git a/debian/additions/innotop/innotop.1 b/debian/additions/innotop/innotop.1 new file mode 100644 index 00000000000..b2e7fce084e --- /dev/null +++ b/debian/additions/innotop/innotop.1 @@ -0,0 +1,2084 @@ +.\" Automatically generated by Pod::Man 2.1801 (Pod::Simple 3.07) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "INNOTOP 1" +.TH INNOTOP 1 "2009-03-09" "perl v5.10.0" "User Contributed Perl Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +innotop \- MySQL and InnoDB transaction/status monitor. +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +To monitor servers normally: +.PP +.Vb 1 +\& innotop +.Ve +.PP +To monitor InnoDB status information from a file: +.PP +.Vb 1 +\& innotop /var/log/mysql/mysqld.err +.Ve +.PP +To run innotop non-interactively in a pipe-and-filter configuration: +.PP +.Vb 1 +\& innotop \-\-count 5 \-d 1 \-n +.Ve +.PP +To monitor a database on another system using a particular username and password: +.PP +.Vb 1 +\& innotop \-u \-p \-h +.Ve +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +innotop monitors MySQL servers. Each of its modes shows you a different aspect +of what's happening in the server. For example, there's a mode for monitoring +replication, one for queries, and one for transactions. innotop refreshes its +data periodically, so you see an updating view. +.PP +innotop has lots of features for power users, but you can start and run it with +virtually no configuration. If you're just getting started, see +\&\*(L"QUICK-START\*(R". Press '?' at any time while running innotop for +context-sensitive help. +.SH "QUICK-START" +.IX Header "QUICK-START" +To start innotop, open a terminal or command prompt. If you have installed +innotop on your system, you should be able to just type \*(L"innotop\*(R" and press +Enter; otherwise, you will need to change to innotop's directory and type \*(L"perl +innotop\*(R". +.PP +With no options specified, innotop will attempt to connect to a MySQL server on +localhost using mysql_read_default_group=client for other connection +parameters. If you need to specify a different username and password, use the +\&\-u and \-p options, respectively. To monitor a MySQL database on another +host, use the \-h option. +.PP +After you've connected, innotop should show you something like the following: +.PP +.Vb 1 +\& [RO] Query List (? for help) localhost, 01:11:19, 449.44 QPS, 14/7/163 con/run +\& +\& CXN When Load QPS Slow QCacheHit KCacheHit BpsIn BpsOut +\& localhost Total 0.00 1.07k 697 0.00% 98.17% 476.83k 242.83k +\& +\& CXN Cmd ID User Host DB Time Query +\& localhost Query 766446598 test 10.0.0.1 foo 00:02 INSERT INTO table ( +.Ve +.PP +(This sample is truncated at the right so it will fit on a terminal when running +\&'man innotop') +.PP +If your server is busy, you'll see more output. Notice the first line on the +screen, which tells you that readonly is set to true ([\s-1RO\s0]), what mode you're +in and what server you're connected to. You can change to other modes with +keystrokes; press 'T' to switch to a list of InnoDB transactions, for example. +.PP +Press the '?' key to see what keys are active in the current mode. You can +press any of these keys and innotop will either take the requested action or +prompt you for more input. If your system has Term::ReadLine support, you can +use \s-1TAB\s0 and other keys to auto-complete and edit input. +.PP +To quit innotop, press the 'q' key. +.SH "OPTIONS" +.IX Header "OPTIONS" +innotop is mostly configured via its configuration file, but some of the +configuration options can come from the command line. You can also specify a +file to monitor for InnoDB status output; see \*(L"\s-1MONITORING\s0 A \s-1FILE\s0\*(R" for more +details. +.PP +You can negate some options by prefixing the option name with \-\-no. For +example, \-\-noinc (or \-\-no\-inc) negates \*(L"\-\-inc\*(R". +.IP "\-\-color" 4 +.IX Item "--color" +Enable or disable terminal coloring. Corresponds to the \*(L"color\*(R" config file +setting. +.IP "\-\-config" 4 +.IX Item "--config" +Specifies a configuration file to read. This option is non-sticky, that is to +say it does not persist to the configuration file itself. +.IP "\-\-count" 4 +.IX Item "--count" +Refresh only the specified number of times (ticks) before exiting. Each refresh +is a pause for \*(L"interval\*(R" seconds, followed by requesting data from MySQL +connections and printing it to the terminal. +.IP "\-\-delay" 4 +.IX Item "--delay" +Specifies the amount of time to pause between ticks (refreshes). Corresponds to +the configuration option \*(L"interval\*(R". +.IP "\-\-help" 4 +.IX Item "--help" +Print a summary of command-line usage and exit. +.IP "\-\-host" 4 +.IX Item "--host" +Host to connect to. +.IP "\-\-inc" 4 +.IX Item "--inc" +Specifies whether innotop should display absolute numbers or relative numbers +(offsets from their previous values). Corresponds to the configuration option +\&\*(L"status_inc\*(R". +.IP "\-\-mode" 4 +.IX Item "--mode" +Specifies the mode in which innotop should start. Corresponds to the +configuration option \*(L"mode\*(R". +.IP "\-\-nonint" 4 +.IX Item "--nonint" +Enable non-interactive operation. See \*(L"NON-INTERACTIVE \s-1OPERATION\s0\*(R" for more. +.IP "\-\-password" 4 +.IX Item "--password" +Password to use for connection. +.IP "\-\-port" 4 +.IX Item "--port" +Port to use for connection. +.IP "\-\-skipcentral" 4 +.IX Item "--skipcentral" +Don't read the central configuration file. +.IP "\-\-user" 4 +.IX Item "--user" +User to use for connection. +.IP "\-\-version" 4 +.IX Item "--version" +Output version information and exit. +.IP "\-\-write" 4 +.IX Item "--write" +Sets the configuration option \*(L"readonly\*(R" to 0, making innotop write the +running configuration to ~/.innotop/innotop.conf on exit, if no configuration +file was loaded at start-up. +.SH "HOTKEYS" +.IX Header "HOTKEYS" +innotop is interactive, and you control it with key-presses. +.IP "\(bu" 4 +Uppercase keys switch between modes. +.IP "\(bu" 4 +Lowercase keys initiate some action within the current mode. +.IP "\(bu" 4 +Other keys do something special like change configuration or show the +innotop license. +.PP +Press '?' at any time to see the currently active keys and what they do. +.SH "MODES" +.IX Header "MODES" +Each of innotop's modes retrieves and displays a particular type of data from +the servers you're monitoring. You switch between modes with uppercase keys. +The following is a brief description of each mode, in alphabetical order. To +switch to the mode, press the key listed in front of its heading in the +following list: +.IP "B: InnoDB Buffers" 4 +.IX Item "B: InnoDB Buffers" +This mode displays information about the InnoDB buffer pool, page statistics, +insert buffer, and adaptive hash index. The data comes from \s-1SHOW\s0 \s-1INNODB\s0 \s-1STATUS\s0. +.Sp +This mode contains the \*(L"buffer_pool\*(R", \*(L"page_statistics\*(R", +\&\*(L"insert_buffers\*(R", and \*(L"adaptive_hash_index\*(R" tables by default. +.IP "C: Command Summary" 4 +.IX Item "C: Command Summary" +This mode is similar to mytop's Command Summary mode. It shows the +\&\*(L"cmd_summary\*(R" table, which looks something like the following: +.Sp +.Vb 8 +\& Command Summary (? for help) localhost, 25+07:16:43, 2.45 QPS, 3 thd, 5.0.40 +\& _\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_ Command Summary _\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_ +\& Name Value Pct Last Incr Pct +\& Select_scan 3244858 69.89% 2 100.00% +\& Select_range 1354177 29.17% 0 0.00% +\& Select_full_join 39479 0.85% 0 0.00% +\& Select_full_range_join 4097 0.09% 0 0.00% +\& Select_range_check 0 0.00% 0 0.00% +.Ve +.Sp +The command summary table is built by extracting variables from +\&\*(L"\s-1STATUS_VARIABLES\s0\*(R". The variables must be numeric and must match the prefix +given by the \*(L"cmd_filter\*(R" configuration variable. The variables are then +sorted by value descending and compared to the last variable, as shown above. +The percentage columns are percentage of the total of all variables in the +table, so you can see the relative weight of the variables. +.Sp +The example shows what you see if the prefix is \*(L"Select_\*(R". The default +prefix is \*(L"Com_\*(R". You can choose a prefix with the 's' key. +.Sp +It's rather like running \s-1SHOW\s0 \s-1VARIABLES\s0 \s-1LIKE\s0 \*(L"prefix%\*(R" with memory and +nice formatting. +.Sp +Values are aggregated across all servers. The Pct columns are not correctly +aggregated across multiple servers. This is a known limitation of the grouping +algorithm that may be fixed in the future. +.IP "D: InnoDB Deadlocks" 4 +.IX Item "D: InnoDB Deadlocks" +This mode shows the transactions involved in the last InnoDB deadlock. A second +table shows the locks each transaction held and waited for. A deadlock is +caused by a cycle in the waits-for graph, so there should be two locks held and +one waited for unless the deadlock information is truncated. +.Sp +InnoDB puts deadlock information before some other information in the \s-1SHOW\s0 +\&\s-1INNODB\s0 \s-1STATUS\s0 output. If there are a lot of locks, the deadlock information can +grow very large, and there is a limit on the size of the \s-1SHOW\s0 \s-1INNODB\s0 +\&\s-1STATUS\s0 output. A large deadlock can fill the entire output, or even be +truncated, and prevent you from seeing other information at all. If you are +running innotop in another mode, for example T mode, and suddenly you don't see +anything, you might want to check and see if a deadlock has wiped out the data +you need. +.Sp +If it has, you can create a small deadlock to replace the large one. Use the +\&'w' key to 'wipe' the large deadlock with a small one. This will not work +unless you have defined a deadlock table for the connection (see \*(L"\s-1SERVER\s0 +\&\s-1CONNECTIONS\s0\*(R"). +.Sp +You can also configure innotop to automatically detect when a large deadlock +needs to be replaced with a small one (see \*(L"auto_wipe_dl\*(R"). +.Sp +This mode displays the \*(L"deadlock_transactions\*(R" and \*(L"deadlock_locks\*(R" tables +by default. +.IP "F: InnoDB Foreign Key Errors" 4 +.IX Item "F: InnoDB Foreign Key Errors" +This mode shows the last InnoDB foreign key error information, such as the +table where it happened, when and who and what query caused it, and so on. +.Sp +InnoDB has a huge variety of foreign key error messages, and many of them are +just hard to parse. innotop doesn't always do the best job here, but there's +so much code devoted to parsing this messy, unparseable output that innotop is +likely never to be perfect in this regard. If innotop doesn't show you what +you need to see, just look at the status text directly. +.Sp +This mode displays the \*(L"fk_error\*(R" table by default. +.IP "I: InnoDB I/O Info" 4 +.IX Item "I: InnoDB I/O Info" +This mode shows InnoDB's I/O statistics, including the I/O threads, pending I/O, +file I/O miscellaneous, and log statistics. It displays the \*(L"io_threads\*(R", +\&\*(L"pending_io\*(R", \*(L"file_io_misc\*(R", and \*(L"log_statistics\*(R" tables by default. +.IP "L: Locks" 4 +.IX Item "L: Locks" +This mode shows information about current locks. At the moment only InnoDB +locks are supported, and by default you'll only see locks for which transactions +are waiting. This information comes from the \s-1TRANSACTIONS\s0 section of the InnoDB +status text. If you have a very busy server, you may have frequent lock waits; +it helps to be able to see which tables and indexes are the \*(L"hot spot\*(R" for +locks. If your server is running pretty well, this mode should show nothing. +.Sp +You can configure MySQL and innotop to monitor not only locks for which a +transaction is waiting, but those currently held, too. You can do this with the +InnoDB Lock Monitor (). It's +not documented in the MySQL manual, but creating the lock monitor with the +following statement also affects the output of \s-1SHOW\s0 \s-1INNODB\s0 \s-1STATUS\s0, which innotop +uses: +.Sp +.Vb 1 +\& CREATE TABLE innodb_lock_monitor(a int) ENGINE=INNODB; +.Ve +.Sp +This causes InnoDB to print its output to the MySQL file every 16 seconds or so, +as stated in the manual, but it also makes the normal \s-1SHOW\s0 \s-1INNODB\s0 \s-1STATUS\s0 output +include lock information, which innotop can parse and display (that's the +undocumented feature). +.Sp +This means you can do what may have seemed impossible: to a limited extent +(InnoDB truncates some information in the output), you can see which transaction +holds the locks something else is waiting for. You can also enable and disable +the InnoDB Lock Monitor with the key mappings in this mode. +.Sp +This mode displays the \*(L"innodb_locks\*(R" table by default. Here's a sample of +the screen when one connection is waiting for locks another connection holds: +.Sp +.Vb 7 +\& _\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_ InnoDB Locks _\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_ +\& CXN ID Type Waiting Wait Active Mode DB Table Index +\& localhost 12 RECORD 1 00:10 00:10 X test t1 PRIMARY +\& localhost 12 TABLE 0 00:10 00:10 IX test t1 +\& localhost 12 RECORD 1 00:10 00:10 X test t1 PRIMARY +\& localhost 11 TABLE 0 00:00 00:25 IX test t1 +\& localhost 11 RECORD 0 00:00 00:25 X test t1 PRIMARY +.Ve +.Sp +You can see the first connection, \s-1ID\s0 12, is waiting for a lock on the \s-1PRIMARY\s0 +key on test.t1, and has been waiting for 10 seconds. The second connection +isn't waiting, because the Waiting column is 0, but it holds locks on the same +index. That tells you connection 11 is blocking connection 12. +.IP "M: Master/Slave Replication Status" 4 +.IX Item "M: Master/Slave Replication Status" +This mode shows the output of \s-1SHOW\s0 \s-1SLAVE\s0 \s-1STATUS\s0 and \s-1SHOW\s0 \s-1MASTER\s0 \s-1STATUS\s0 in three +tables. The first two divide the slave's status into \s-1SQL\s0 and I/O thread status, +and the last shows master status. Filters are applied to eliminate non-slave +servers from the slave tables, and non-master servers from the master table. +.Sp +This mode displays the \*(L"slave_sql_status\*(R", \*(L"slave_io_status\*(R", and +\&\*(L"master_status\*(R" tables by default. +.IP "O: Open Tables" 4 +.IX Item "O: Open Tables" +This section comes from MySQL's \s-1SHOW\s0 \s-1OPEN\s0 \s-1TABLES\s0 command. By default it is +filtered to show tables which are in use by one or more queries, so you can +get a quick look at which tables are 'hot'. You can use this to guess which +tables might be locked implicitly. +.Sp +This mode displays the \*(L"open_tables\*(R" mode by default. +.IP "Q: Query List" 4 +.IX Item "Q: Query List" +This mode displays the output from \s-1SHOW\s0 \s-1FULL\s0 \s-1PROCESSLIST\s0, much like \fBmytop\fR's +query list mode. This mode does \fBnot\fR show InnoDB-related information. This +is probably one of the most useful modes for general usage. +.Sp +There is an informative header that shows general status information about +your server. You can toggle it on and off with the 'h' key. By default, +innotop hides inactive processes and its own process. You can toggle these on +and off with the 'i' and 'a' keys. +.Sp +You can \s-1EXPLAIN\s0 a query from this mode with the 'e' key. This displays the +query's full text, the results of \s-1EXPLAIN\s0, and in newer MySQL versions, even +the optimized query resulting from \s-1EXPLAIN\s0 \s-1EXTENDED\s0. innotop also tries to +rewrite certain queries to make them EXPLAIN-able. For example, \s-1INSERT/SELECT\s0 +statements are rewritable. +.Sp +This mode displays the \*(L"q_header\*(R" and \*(L"processlist\*(R" tables by default. +.IP "R: InnoDB Row Operations and Semaphores" 4 +.IX Item "R: InnoDB Row Operations and Semaphores" +This mode shows InnoDB row operations, row operation miscellaneous, semaphores, +and information from the wait array. It displays the \*(L"row_operations\*(R", +\&\*(L"row_operation_misc\*(R", \*(L"semaphores\*(R", and \*(L"wait_array\*(R" tables by default. +.IP "S: Variables & Status" 4 +.IX Item "S: Variables & Status" +This mode calculates statistics, such as queries per second, and prints them out +in several different styles. You can show absolute values, or incremental values +between ticks. +.Sp +You can switch between the views by pressing a key. The 's' key prints a +single line each time the screen updates, in the style of \fBvmstat\fR. The 'g' +key changes the view to a graph of the same numbers, sort of like \fBtload\fR. +The 'v' key changes the view to a pivoted table of variable names on the left, +with successive updates scrolling across the screen from left to right. You can +choose how many updates to put on the screen with the \*(L"num_status_sets\*(R" +configuration variable. +.Sp +Headers may be abbreviated to fit on the screen in interactive operation. You +choose which variables to display with the 'c' key, which selects from +predefined sets, or lets you create your own sets. You can edit the current set +with the 'e' key. +.Sp +This mode doesn't really display any tables like other modes. Instead, it uses +a table definition to extract and format the data, but it then transforms the +result in special ways before outputting it. It uses the \*(L"var_status\*(R" table +definition for this. +.IP "T: InnoDB Transactions" 4 +.IX Item "T: InnoDB Transactions" +This mode shows transactions from the InnoDB monitor's output, in \fBtop\fR\-like +format. This mode is the reason I wrote innotop. +.Sp +You can kill queries or processes with the 'k' and 'x' keys, and \s-1EXPLAIN\s0 a query +with the 'e' or 'f' keys. InnoDB doesn't print the full query in transactions, +so explaining may not work right if the query is truncated. +.Sp +The informational header can be toggled on and off with the 'h' key. By +default, innotop hides inactive transactions and its own transaction. You can +toggle this on and off with the 'i' and 'a' keys. +.Sp +This mode displays the \*(L"t_header\*(R" and \*(L"innodb_transactions\*(R" tables by +default. +.SH "INNOTOP STATUS" +.IX Header "INNOTOP STATUS" +The first line innotop displays is a \*(L"status bar\*(R" of sorts. What it contains +depends on the mode you're in, and what servers you're monitoring. The first +few words are always [\s-1RO\s0] (if readonly is set to 1), the innotop mode, such as +\&\*(L"InnoDB Txns\*(R" for T mode, followed by a reminder to press '?' for help at any +time. +.SS "\s-1ONE\s0 \s-1SERVER\s0" +.IX Subsection "ONE SERVER" +The simplest case is when you're monitoring a single server. In this case, the +name of the connection is next on the status line. This is the name you gave +when you created the connection \*(-- most likely the MySQL server's hostname. +This is followed by the server's uptime. +.PP +If you're in an InnoDB mode, such as T or B, the next word is \*(L"InnoDB\*(R" followed +by some information about the \s-1SHOW\s0 \s-1INNODB\s0 \s-1STATUS\s0 output used to render the +screen. The first word is the number of seconds since the last \s-1SHOW\s0 \s-1INNODB\s0 +\&\s-1STATUS\s0, which InnoDB uses to calculate some per-second statistics. The next is +a smiley face indicating whether the InnoDB output is truncated. If the smiley +face is a :\-), all is well; there is no truncation. A :^| means the transaction +list is so long, InnoDB has only printed out some of the transactions. Finally, +a frown :\-( means the output is incomplete, which is probably due to a deadlock +printing too much lock information (see \*(L"D: InnoDB Deadlocks\*(R"). +.PP +The next two words indicate the server's queries per second (\s-1QPS\s0) and how many +threads (connections) exist. Finally, the server's version number is the last +thing on the line. +.SS "\s-1MULTIPLE\s0 \s-1SERVERS\s0" +.IX Subsection "MULTIPLE SERVERS" +If you are monitoring multiple servers (see \*(L"\s-1SERVER\s0 \s-1CONNECTIONS\s0\*(R"), the status +line does not show any details about individual servers. Instead, it shows the +names of the connections that are active. Again, these are connection names you +specified, which are likely to be the server's hostname. A connection that has +an error is prefixed with an exclamation point. +.PP +If you are monitoring a group of servers (see \*(L"\s-1SERVER\s0 \s-1GROUPS\s0\*(R"), the status +line shows the name of the group. If any connection in the group has an +error, the group's name is followed by the fraction of the connections that +don't have errors. +.PP +See \*(L"\s-1ERROR\s0 \s-1HANDLING\s0\*(R" for more details about innotop's error handling. +.SS "\s-1MONITORING\s0 A \s-1FILE\s0" +.IX Subsection "MONITORING A FILE" +If you give a filename on the command line, innotop will not connect to \s-1ANY\s0 +servers at all. It will watch the specified file for InnoDB status output and +use that as its data source. It will always show a single connection called +\&'file'. And since it can't connect to a server, it can't determine how long the +server it's monitoring has been up; so it calculates the server's uptime as time +since innotop started running. +.SH "SERVER ADMINISTRATION" +.IX Header "SERVER ADMINISTRATION" +While innotop is primarily a monitor that lets you watch and analyze your +servers, it can also send commands to servers. The most frequently useful +commands are killing queries and stopping or starting slaves. +.PP +You can kill a connection, or in newer versions of MySQL kill a query but not a +connection, from \*(L"Q: Query List\*(R" and \*(L"T: InnoDB Transactions\*(R" modes. +Press 'k' to issue a \s-1KILL\s0 command, or 'x' to issue a \s-1KILL\s0 \s-1QUERY\s0 command. +innotop will prompt you for the server and/or connection \s-1ID\s0 to kill (innotop +does not prompt you if there is only one possible choice for any input). +innotop pre-selects the longest-running query, or the oldest connection. +Confirm the command with 'y'. +.PP +In \*(L"Slave Replication Status\*(R"\*(L" in \*(R"M: Master mode, you can start and stop slaves +with the 'a' and 'o' keys, respectively. You can send these commands to many +slaves at once. innotop fills in a default command of \s-1START\s0 \s-1SLAVE\s0 or \s-1STOP\s0 \s-1SLAVE\s0 +for you, but you can actually edit the command and send anything you wish, such +as \s-1SET\s0 \s-1GLOBAL\s0 SQL_SLAVE_SKIP_COUNTER=1 to make the slave skip one binlog event +when it starts. +.PP +You can also ask innotop to calculate the earliest binlog in use by any slave +and issue a \s-1PURGE\s0 \s-1MASTER\s0 \s-1LOGS\s0 on the master. Use the 'b' key for this. innotop +will prompt you for a master to run the command on, then prompt you for the +connection names of that master's slaves (there is no way for innotop to +determine this reliably itself). innotop will find the minimum binlog in use by +these slave connections and suggest it as the argument to \s-1PURGE\s0 \s-1MASTER\s0 \s-1LOGS\s0. +.SH "SERVER CONNECTIONS" +.IX Header "SERVER CONNECTIONS" +When you create a server connection using '@', innotop asks you for a series of +inputs, as follows: +.IP "\s-1DSN\s0" 4 +.IX Item "DSN" +A \s-1DSN\s0 is a Data Source Name, which is the initial argument passed to the \s-1DBI\s0 +module for connecting to a server. It is usually of the form +.Sp +.Vb 1 +\& DBI:mysql:;mysql_read_default_group=mysql;host=HOSTNAME +.Ve +.Sp +Since this \s-1DSN\s0 is passed to the DBD::mysql driver, you should read the driver's +documentation at \*(L"/search.cpan.org/dist/DBD\-mysql/lib/DBD/mysql.pm\*(R"\*(L" in \*(R"http: for +the exact details on all the options you can pass the driver in the \s-1DSN\s0. You +can read more about \s-1DBI\s0 at , and especially at +. +.Sp +The mysql_read_default_group=mysql option lets the \s-1DBD\s0 driver read your MySQL +options files, such as ~/.my.cnf on UNIX-ish systems. You can use this to avoid +specifying a username or password for the connection. +.IP "InnoDB Deadlock Table" 4 +.IX Item "InnoDB Deadlock Table" +This optional item tells innotop a table name it can use to deliberately create +a small deadlock (see \*(L"D: InnoDB Deadlocks\*(R"). If you specify this option, +you just need to be sure the table doesn't exist, and that innotop can create +and drop the table with the InnoDB storage engine. You can safely omit or just +accept the default if you don't intend to use this. +.IP "Username" 4 +.IX Item "Username" +innotop will ask you if you want to specify a username. If you say 'y', it will +then prompt you for a user name. If you have a MySQL option file that specifies +your username, you don't have to specify a username. +.Sp +The username defaults to your login name on the system you're running innotop on. +.IP "Password" 4 +.IX Item "Password" +innotop will ask you if you want to specify a password. Like the username, the +password is optional, but there's an additional prompt that asks if you want to +save the password in the innotop configuration file. If you don't save it in +the configuration file, innotop will prompt you for a password each time it +starts. Passwords in the innotop configuration file are saved in plain text, +not encrypted in any way. +.PP +Once you finish answering these questions, you should be connected to a server. +But innotop isn't limited to monitoring a single server; you can define many +server connections and switch between them by pressing the '@' key. See +\&\*(L"\s-1SWITCHING\s0 \s-1BETWEEN\s0 \s-1CONNECTIONS\s0\*(R". +.SH "SERVER GROUPS" +.IX Header "SERVER GROUPS" +If you have multiple MySQL instances, you can put them into named groups, such +as 'all', 'masters', and 'slaves', which innotop can monitor all together. +.PP +You can choose which group to monitor with the '#' key, and you can press the +\&\s-1TAB\s0 key to switch to the next group. If you're not currently monitoring a +group, pressing \s-1TAB\s0 selects the first group. +.PP +To create a group, press the '#' key and type the name of your new group, then +type the names of the connections you want the group to contain. +.SH "SWITCHING BETWEEN CONNECTIONS" +.IX Header "SWITCHING BETWEEN CONNECTIONS" +innotop lets you quickly switch which servers you're monitoring. The most basic +way is by pressing the '@' key and typing the name(s) of the connection(s) you +want to use. This setting is per-mode, so you can monitor different connections +in each mode, and innotop remembers which connections you choose. +.PP +You can quickly switch to the 'next' connection in alphabetical order with the +\&'n' key. If you're monitoring a server group (see \*(L"\s-1SERVER\s0 \s-1GROUPS\s0\*(R") this will +switch to the first connection. +.PP +You can also type many connection names, and innotop will fetch and display data +from them all. Just separate the connection names with spaces, for example +\&\*(L"server1 server2.\*(R" Again, if you type the name of a connection that doesn't +exist, innotop will prompt you for connection information and create the +connection. +.PP +Another way to monitor multiple connections at once is with server groups. You +can use the \s-1TAB\s0 key to switch to the 'next' group in alphabetical order, or if +you're not monitoring any groups, \s-1TAB\s0 will switch to the first group. +.PP +innotop does not fetch data in parallel from connections, so if you are +monitoring a large group or many connections, you may notice increased delay +between ticks. +.PP +When you monitor more than one connection, innotop's status bar changes. See +\&\*(L"\s-1INNOTOP\s0 \s-1STATUS\s0\*(R". +.SH "ERROR HANDLING" +.IX Header "ERROR HANDLING" +Error handling is not that important when monitoring a single connection, but is +crucial when you have many active connections. A crashed server or lost +connection should not crash innotop. As a result, innotop will continue to run +even when there is an error; it just won't display any information from the +connection that had an error. Because of this, innotop's behavior might confuse +you. It's a feature, not a bug! +.PP +innotop does not continue to query connections that have errors, because they +may slow innotop and make it hard to use, especially if the error is a problem +connecting and causes a long time-out. Instead, innotop retries the connection +occasionally to see if the error still exists. If so, it will wait until some +point in the future. The wait time increases in ticks as the Fibonacci series, +so it tries less frequently as time passes. +.PP +Since errors might only happen in certain modes because of the \s-1SQL\s0 commands +issued in those modes, innotop keeps track of which mode caused the error. If +you switch to a different mode, innotop will retry the connection instead of +waiting. +.PP +By default innotop will display the problem in red text at the bottom of the +first table on the screen. You can disable this behavior with the +\&\*(L"show_cxn_errors_in_tbl\*(R" configuration option, which is enabled by default. +If the \*(L"debug\*(R" option is enabled, innotop will display the error at the +bottom of every table, not just the first. And if \*(L"show_cxn_errors\*(R" is +enabled, innotop will print the error text to \s-1STDOUT\s0 as well. Error messages +might only display in the mode that caused the error, depending on the mode and +whether innotop is avoiding querying that connection. +.SH "NON-INTERACTIVE OPERATION" +.IX Header "NON-INTERACTIVE OPERATION" +You can run innotop in non-interactive mode, in which case it is entirely +controlled from the configuration file and command-line options. To start +innotop in non-interactive mode, give the L\*(L"<\-\-nonint\*(R"> command-line option. +This changes innotop's behavior in the following ways: +.IP "\(bu" 4 +Certain Perl modules are not loaded. Term::Readline is not loaded, since +innotop doesn't prompt interactively. Term::ANSIColor and Win32::Console::ANSI +modules are not loaded. Term::ReadKey is still used, since innotop may have to +prompt for connection passwords when starting up. +.IP "\(bu" 4 +innotop does not clear the screen after each tick. +.IP "\(bu" 4 +innotop does not persist any changes to the configuration file. +.IP "\(bu" 4 +If \*(L"\-\-count\*(R" is given and innotop is in incremental mode (see \*(L"status_inc\*(R" +and \*(L"\-\-inc\*(R"), innotop actually refreshes one more time than specified so it +can print incremental statistics. This suppresses output during the first +tick, so innotop may appear to hang. +.IP "\(bu" 4 +innotop only displays the first table in each mode. This is so the output can +be easily processed with other command-line utilities such as awk and sed. To +change which tables display in each mode, see \*(L"\s-1TABLES\s0\*(R". Since \*(L"Q: Query +List\*(R" mode is so important, innotop automatically disables the \*(L"q_header\*(R" +table. This ensures you'll see the \*(L"processlist\*(R" table, even if you have +innotop configured to show the q_header table during interactive operation. +Similarly, in \*(L"T: InnoDB Transactions\*(R" mode, the \*(L"t_header\*(R" table is +suppressed so you see only the \*(L"innodb_transactions\*(R" table. +.IP "\(bu" 4 +All output is tab-separated instead of being column-aligned with whitespace, and +innotop prints the full contents of each table instead of only printing one +screenful at a time. +.IP "\(bu" 4 +innotop only prints column headers once instead of every tick (see +\&\*(L"hide_hdr\*(R"). innotop does not print table captions (see +\&\*(L"display_table_captions\*(R"). innotop ensures there are no empty lines in the +output. +.IP "\(bu" 4 +innotop does not honor the \*(L"shorten\*(R" transformation, which normally shortens +some numbers to human-readable formats. +.IP "\(bu" 4 +innotop does not print a status line (see \*(L"\s-1INNOTOP\s0 \s-1STATUS\s0\*(R"). +.SH "CONFIGURING" +.IX Header "CONFIGURING" +Nearly everything about innotop is configurable. Most things are possible to +change with built-in commands, but you can also edit the configuration file. +.PP +While running innotop, press the '$' key to bring up the configuration editing +dialog. Press another key to select the type of data you want to edit: +.IP "S: Statement Sleep Times" 4 +.IX Item "S: Statement Sleep Times" +Edits \s-1SQL\s0 statement sleep delays, which make innotop pause for the specified +amount of time after executing a statement. See \*(L"\s-1SQL\s0 \s-1STATEMENTS\s0\*(R" for a +definition of each statement and what it does. By default innotop does not +delay after any statements. +.Sp +This feature is included so you can customize the side-effects caused by +monitoring your server. You may not see any effects, but some innotop users +have noticed that certain MySQL versions under very high load with InnoDB +enabled take longer than usual to execute \s-1SHOW\s0 \s-1GLOBAL\s0 \s-1STATUS\s0. If innotop calls +\&\s-1SHOW\s0 \s-1FULL\s0 \s-1PROCESSLIST\s0 immediately afterward, the processlist contains more +queries than the machine actually averages at any given moment. Configuring +innotop to pause briefly after calling \s-1SHOW\s0 \s-1GLOBAL\s0 \s-1STATUS\s0 alleviates this +effect. +.Sp +Sleep times are stored in the \*(L"stmt_sleep_times\*(R" section of the configuration +file. Fractional-second sleeps are supported, subject to your hardware's +limitations. +.IP "c: Edit Columns" 4 +.IX Item "c: Edit Columns" +Starts the table editor on one of the displayed tables. See \*(L"\s-1TABLE\s0 \s-1EDITOR\s0\*(R". +An alternative way to start the table editor without entering the configuration +dialog is with the '^' key. +.IP "g: General Configuration" 4 +.IX Item "g: General Configuration" +Starts the configuration editor to edit global and mode-specific configuration +variables (see \*(L"\s-1MODES\s0\*(R"). innotop prompts you to choose a variable from among +the global and mode-specific ones depending on the current mode. +.IP "k: Row-Coloring Rules" 4 +.IX Item "k: Row-Coloring Rules" +Starts the row-coloring rules editor on one of the displayed table(s). See +\&\*(L"\s-1COLORS\s0\*(R" for details. +.IP "p: Manage Plugins" 4 +.IX Item "p: Manage Plugins" +Starts the plugin configuration editor. See \*(L"\s-1PLUGINS\s0\*(R" for details. +.IP "s: Server Groups" 4 +.IX Item "s: Server Groups" +Lets you create and edit server groups. See \*(L"\s-1SERVER\s0 \s-1GROUPS\s0\*(R". +.IP "t: Choose Displayed Tables" 4 +.IX Item "t: Choose Displayed Tables" +Lets you choose which tables to display in this mode. See \*(L"\s-1MODES\s0\*(R" and +\&\*(L"\s-1TABLES\s0\*(R". +.SH "CONFIGURATION FILE" +.IX Header "CONFIGURATION FILE" +innotop's default configuration file locations are \f(CW$HOME\fR/.innotop and +/etc/innotop/innotop.conf, and they are looked for in that order. If the first +configuration file exists, the second will not be processed. Those can be +overridden with the \*(L"\-\-config\*(R" command-line option. You can edit it by hand +safely, however innotop reads the configuration file when it starts, and, if +readonly is set to 0, writes it out again when it exits. Thus, if readonly is +set to 0, any changes you make by hand while innotop is running will be lost. +.PP +innotop doesn't store its entire configuration in the configuration file. It +has a huge set of default configuration values that it holds only in memory, +and the configuration file only overrides these defaults. When you customize a +default setting, innotop notices, and then stores the customizations into the +file. This keeps the file size down, makes it easier to edit, and makes +upgrades easier. +.PP +A configuration file is read-only be default. You can override that with +\&\*(L"\-\-write\*(R". See \*(L"readonly\*(R". +.PP +The configuration file is arranged into sections like an \s-1INI\s0 file. Each +section begins with [section\-name] and ends with [/section\-name]. Each +section's entries have a different syntax depending on the data they need to +store. You can put comments in the file; any line that begins with a # +character is a comment. innotop will not read the comments, so it won't write +them back out to the file when it exits. Comments in read-only configuration +files are still useful, though. +.PP +The first line in the file is innotop's version number. This lets innotop +notice when the file format is not backwards-compatible, and upgrade smoothly +without destroying your customized configuration. +.PP +The following list describes each section of the configuration file and the data +it contains: +.IP "general" 4 +.IX Item "general" +The 'general' section contains global configuration variables and variables that +may be mode-specific, but don't belong in any other section. The syntax is a +simple key=value list. innotop writes a comment above each value to help you +edit the file by hand. +.RS 4 +.IP "S_func" 4 +.IX Item "S_func" +Controls S mode presentation (see \*(L"S: Variables & Status\*(R"). If g, values are +graphed; if s, values are like vmstat; if p, values are in a pivoted table. +.IP "S_set" 4 +.IX Item "S_set" +Specifies which set of variables to display in \*(L"S: Variables & Status\*(R" mode. +See \*(L"\s-1VARIABLE\s0 \s-1SETS\s0\*(R". +.IP "auto_wipe_dl" 4 +.IX Item "auto_wipe_dl" +Instructs innotop to automatically wipe large deadlocks when it notices them. +When this happens you may notice a slight delay. At the next tick, you will +usually see the information that was being truncated by the large deadlock. +.IP "charset" 4 +.IX Item "charset" +Specifies what kind of characters to allow through the \*(L"no_ctrl_char\*(R" +transformation. This keeps non-printable characters from confusing a +terminal when you monitor queries that contain binary data, such as images. +.Sp +The default is 'ascii', which considers anything outside normal \s-1ASCII\s0 to be a +control character. The other allowable values are 'unicode' and 'none'. 'none' +considers every character a control character, which can be useful for +collapsing \s-1ALL\s0 text fields in queries. +.IP "cmd_filter" 4 +.IX Item "cmd_filter" +This is the prefix that filters variables in \*(L"C: Command Summary\*(R" mode. +.IP "color" 4 +.IX Item "color" +Whether terminal coloring is permitted. +.IP "cxn_timeout" 4 +.IX Item "cxn_timeout" +On MySQL versions 4.0.3 and newer, this variable is used to set the connection's +timeout, so MySQL doesn't close the connection if it is not used for a while. +This might happen because a connection isn't monitored in a particular mode, for +example. +.IP "debug" 4 +.IX Item "debug" +This option enables more verbose errors and makes innotop more strict in some +places. It can help in debugging filters and other user-defined code. It also +makes innotop write a lot of information to \*(L"debugfile\*(R" when there is a +crash. +.IP "debugfile" 4 +.IX Item "debugfile" +A file to which innotop will write information when there is a crash. See +\&\*(L"\s-1FILES\s0\*(R". +.IP "display_table_captions" 4 +.IX Item "display_table_captions" +innotop displays a table caption above most tables. This variable suppresses or +shows captions on all tables globally. Some tables are configured with the +hide_caption property, which overrides this. +.IP "global" 4 +.IX Item "global" +Whether to show \s-1GLOBAL\s0 variables and status. innotop only tries to do this on +servers which support the \s-1GLOBAL\s0 option to \s-1SHOW\s0 \s-1VARIABLES\s0 and \s-1SHOW\s0 \s-1STATUS\s0. In +some MySQL versions, you need certain privileges to do this; if you don't have +them, innotop will not be able to fetch any variable and status data. This +configuration variable lets you run innotop and fetch what data you can even +without the elevated privileges. +.Sp +I can no longer find or reproduce the situation where \s-1GLOBAL\s0 wasn't allowed, but +I know there was one. +.IP "graph_char" 4 +.IX Item "graph_char" +Defines the character to use when drawing graphs in \*(L"S: Variables & Status\*(R" +mode. +.IP "header_highlight" 4 +.IX Item "header_highlight" +Defines how to highlight column headers. This only works if Term::ANSIColor is +available. Valid values are 'bold' and 'underline'. +.IP "hide_hdr" 4 +.IX Item "hide_hdr" +Hides column headers globally. +.IP "interval" 4 +.IX Item "interval" +The interval at which innotop will refresh its data (ticks). The interval is +implemented as a sleep time between ticks, so the true interval will vary +depending on how long it takes innotop to fetch and render data. +.Sp +This variable accepts fractions of a second. +.IP "mode" 4 +.IX Item "mode" +The mode in which innotop should start. Allowable arguments are the same as the +key presses that select a mode interactively. See \*(L"\s-1MODES\s0\*(R". +.IP "num_digits" 4 +.IX Item "num_digits" +How many digits to show in fractional numbers and percents. This variable's +range is between 0 and 9 and can be set directly from \*(L"S: Variables & Status\*(R" +mode with the '+' and '\-' keys. It is used in the \*(L"set_precision\*(R", +\&\*(L"shorten\*(R", and \*(L"percent\*(R" transformations. +.IP "num_status_sets" 4 +.IX Item "num_status_sets" +Controls how many sets of status variables to display in pivoted \*(L"S: Variables +& Status\*(R" mode. It also controls the number of old sets of variables innotop +keeps in its memory, so the larger this variable is, the more memory innotop +uses. +.IP "plugin_dir" 4 +.IX Item "plugin_dir" +Specifies where plugins can be found. By default, innotop stores plugins in the +\&'plugins' subdirectory of your innotop configuration directory. +.IP "readonly" 4 +.IX Item "readonly" +Whether the configuration file is readonly. This cannot be set interactively. +.IP "show_cxn_errors" 4 +.IX Item "show_cxn_errors" +Makes innotop print connection errors to \s-1STDOUT\s0. See \*(L"\s-1ERROR\s0 \s-1HANDLING\s0\*(R". +.IP "show_cxn_errors_in_tbl" 4 +.IX Item "show_cxn_errors_in_tbl" +Makes innotop display connection errors as rows in the first table on screen. +See \*(L"\s-1ERROR\s0 \s-1HANDLING\s0\*(R". +.IP "show_percent" 4 +.IX Item "show_percent" +Adds a '%' character after the value returned by the \*(L"percent\*(R" +transformation. +.IP "show_statusbar" 4 +.IX Item "show_statusbar" +Controls whether to show the status bar in the display. See \*(L"\s-1INNOTOP\s0 +\&\s-1STATUS\s0\*(R". +.IP "skip_innodb" 4 +.IX Item "skip_innodb" +Disables fetching \s-1SHOW\s0 \s-1INNODB\s0 \s-1STATUS\s0, in case your server(s) do not have InnoDB +enabled and you don't want innotop to try to fetch it. This can also be useful +when you don't have the \s-1SUPER\s0 privilege, required to run \s-1SHOW\s0 \s-1INNODB\s0 \s-1STATUS\s0. +.IP "status_inc" 4 +.IX Item "status_inc" +Whether to show absolute or incremental values for status variables. +Incremental values are calculated as an offset from the last value innotop saw +for that variable. This is a global setting, but will probably become +mode-specific at some point. Right now it is honored a bit inconsistently; some +modes don't pay attention to it. +.RE +.RS 4 +.RE +.IP "plugins" 4 +.IX Item "plugins" +This section holds a list of package names of active plugins. If the plugin +exists, innotop will activate it. See \*(L"\s-1PLUGINS\s0\*(R" for more information. +.IP "filters" 4 +.IX Item "filters" +This section holds user-defined filters (see \*(L"\s-1FILTERS\s0\*(R"). Each line is in the +format filter_name=text='filter text' tbls='table list'. +.Sp +The filter text is the text of the subroutine's code. The table list is a list +of tables to which the filter can apply. By default, user-defined filters apply +to the table for which they were created, but you can manually override that by +editing the definition in the configuration file. +.IP "active_filters" 4 +.IX Item "active_filters" +This section stores which filters are active on each table. Each line is in the +format table_name=filter_list. +.IP "tbl_meta" 4 +.IX Item "tbl_meta" +This section stores user-defined or user-customized columns (see \*(L"\s-1COLUMNS\s0\*(R"). +Each line is in the format col_name=properties, where the properties are a +name=quoted\-value list. +.IP "connections" 4 +.IX Item "connections" +This section holds the server connections you have defined. Each line is in +the format name=properties, where the properties are a name=value list. The +properties are self-explanatory, and the only one that is treated specially is +\&'pass' which is only present if 'savepass' is set. This section of the +configuration file will be skipped if any \s-1DSN\s0, username, or password +command-line options are used. See \*(L"\s-1SERVER\s0 \s-1CONNECTIONS\s0\*(R". +.IP "active_connections" 4 +.IX Item "active_connections" +This section holds a list of which connections are active in each mode. Each +line is in the format mode_name=connection_list. +.IP "server_groups" 4 +.IX Item "server_groups" +This section holds server groups. Each line is in the format +name=connection_list. See \*(L"\s-1SERVER\s0 \s-1GROUPS\s0\*(R". +.IP "active_server_groups" 4 +.IX Item "active_server_groups" +This section holds a list of which server group is active in each mode. Each +line is in the format mode_name=server_group. +.IP "max_values_seen" 4 +.IX Item "max_values_seen" +This section holds the maximum values seen for variables. This is used to scale +the graphs in \*(L"S: Variables & Status\*(R" mode. Each line is in the format +name=value. +.IP "active_columns" 4 +.IX Item "active_columns" +This section holds table column lists. Each line is in the format +tbl_name=column_list. See \*(L"\s-1COLUMNS\s0\*(R". +.IP "sort_cols" 4 +.IX Item "sort_cols" +This section holds the sort definition. Each line is in the format +tbl_name=column_list. If a column is prefixed with '\-', that column sorts +descending. See \*(L"\s-1SORTING\s0\*(R". +.IP "visible_tables" 4 +.IX Item "visible_tables" +This section defines which tables are visible in each mode. Each line is in the +format mode_name=table_list. See \*(L"\s-1TABLES\s0\*(R". +.IP "varsets" 4 +.IX Item "varsets" +This section defines variable sets for use in \*(L"S: Status & Variables\*(R" mode. +Each line is in the format name=variable_list. See \*(L"\s-1VARIABLE\s0 \s-1SETS\s0\*(R". +.IP "colors" 4 +.IX Item "colors" +This section defines colorization rules. Each line is in the format +tbl_name=property_list. See \*(L"\s-1COLORS\s0\*(R". +.IP "stmt_sleep_times" 4 +.IX Item "stmt_sleep_times" +This section contains statement sleep times. Each line is in the format +statement_name=sleep_time. See \*(L"S: Statement Sleep Times\*(R". +.IP "group_by" 4 +.IX Item "group_by" +This section contains column lists for table group_by expressions. Each line is +in the format tbl_name=column_list. See \*(L"\s-1GROUPING\s0\*(R". +.SH "CUSTOMIZING" +.IX Header "CUSTOMIZING" +You can customize innotop a great deal. For example, you can: +.IP "\(bu" 4 +Choose which tables to display, and in what order. +.IP "\(bu" 4 +Choose which columns are in those tables, and create new columns. +.IP "\(bu" 4 +Filter which rows display with built-in filters, user-defined filters, and +quick-filters. +.IP "\(bu" 4 +Sort the rows to put important data first or group together related rows. +.IP "\(bu" 4 +Highlight rows with color. +.IP "\(bu" 4 +Customize the alignment, width, and formatting of columns, and apply +transformations to columns to extract parts of their values or format the values +as you wish (for example, shortening large numbers to familiar units). +.IP "\(bu" 4 +Design your own expressions to extract and combine data as you need. This gives +you unlimited flexibility. +.PP +All these and more are explained in the following sections. +.SS "\s-1TABLES\s0" +.IX Subsection "TABLES" +A table is what you'd expect: a collection of columns. It also has some other +properties, such as a caption. Filters, sorting rules, and colorization rules +belong to tables and are covered in later sections. +.PP +Internally, table meta-data is defined in a data structure called \f(CW%tbl_meta\fR. +This hash holds all built-in table definitions, which contain a lot of default +instructions to innotop. The meta-data includes the caption, a list of columns +the user has customized, a list of columns, a list of visible columns, a list of +filters, color rules, a sort-column list, sort direction, and some information +about the table's data sources. Most of this is customizable via the table +editor (see \*(L"\s-1TABLE\s0 \s-1EDITOR\s0\*(R"). +.PP +You can choose which tables to show by pressing the '$' key. See \*(L"\s-1MODES\s0\*(R" and +\&\*(L"\s-1TABLES\s0\*(R". +.PP +The table life-cycle is as follows: +.IP "\(bu" 4 +Each table begins with a data source, which is an array of hashes. See below +for details on data sources. +.IP "\(bu" 4 +Each element of the data source becomes a row in the final table. +.IP "\(bu" 4 +For each element in the data source, innotop extracts values from the source and +creates a row. This row is another hash, which later steps will refer to as +\&\f(CW$set\fR. The values innotop extracts are determined by the table's columns. Each +column has an extraction subroutine, compiled from an expression (see +\&\*(L"\s-1EXPRESSIONS\s0\*(R"). The resulting row is a hash whose keys are named the same as +the column name. +.IP "\(bu" 4 +innotop filters the rows, removing those that don't need to be displayed. See +\&\*(L"\s-1FILTERS\s0\*(R". +.IP "\(bu" 4 +innotop sorts the rows. See \*(L"\s-1SORTING\s0\*(R". +.IP "\(bu" 4 +innotop groups the rows together, if specified. See \*(L"\s-1GROUPING\s0\*(R". +.IP "\(bu" 4 +innotop colorizes the rows. See \*(L"\s-1COLORS\s0\*(R". +.IP "\(bu" 4 +innotop transforms the column values in each row. See \*(L"\s-1TRANSFORMATIONS\s0\*(R". +.IP "\(bu" 4 +innotop optionally pivots the rows (see \*(L"\s-1PIVOTING\s0\*(R"), then filters and sorts +them. +.IP "\(bu" 4 +innotop formats and justifies the rows as a table. During this step, innotop +applies further formatting to the column values, including alignment, maximum +and minimum widths. innotop also does final error checking to ensure there are +no crashes due to undefined values. innotop then adds a caption if specified, +and the table is ready to print. +.PP +The lifecycle is slightly different if the table is pivoted, as noted above. To +clarify, if the table is pivoted, the process is extract, group, transform, +pivot, filter, sort, create. If it's not pivoted, the process is extract, +filter, sort, group, color, transform, create. This slightly convoluted process +doesn't map all that well to \s-1SQL\s0, but pivoting complicates things pretty +thoroughly. Roughly speaking, filtering and sorting happen as late as needed to +effect the final result as you might expect, but as early as possible for +efficiency. +.PP +Each built-in table is described below: +.IP "adaptive_hash_index" 4 +.IX Item "adaptive_hash_index" +Displays data about InnoDB's adaptive hash index. Data source: +\&\*(L"\s-1STATUS_VARIABLES\s0\*(R". +.IP "buffer_pool" 4 +.IX Item "buffer_pool" +Displays data about InnoDB's buffer pool. Data source: \*(L"\s-1STATUS_VARIABLES\s0\*(R". +.IP "cmd_summary" 4 +.IX Item "cmd_summary" +Displays weighted status variables. Data source: \*(L"\s-1STATUS_VARIABLES\s0\*(R". +.IP "deadlock_locks" 4 +.IX Item "deadlock_locks" +Shows which locks were held and waited for by the last detected deadlock. Data +source: \*(L"\s-1DEADLOCK_LOCKS\s0\*(R". +.IP "deadlock_transactions" 4 +.IX Item "deadlock_transactions" +Shows transactions involved in the last detected deadlock. Data source: +\&\*(L"\s-1DEADLOCK_TRANSACTIONS\s0\*(R". +.IP "explain" 4 +.IX Item "explain" +Shows the output of \s-1EXPLAIN\s0. Data source: \*(L"\s-1EXPLAIN\s0\*(R". +.IP "file_io_misc" 4 +.IX Item "file_io_misc" +Displays data about InnoDB's file and I/O operations. Data source: +\&\*(L"\s-1STATUS_VARIABLES\s0\*(R". +.IP "fk_error" 4 +.IX Item "fk_error" +Displays various data about InnoDB's last foreign key error. Data source: +\&\*(L"\s-1STATUS_VARIABLES\s0\*(R". +.IP "innodb_locks" 4 +.IX Item "innodb_locks" +Displays InnoDB locks. Data source: \*(L"\s-1INNODB_LOCKS\s0\*(R". +.IP "innodb_transactions" 4 +.IX Item "innodb_transactions" +Displays data about InnoDB's current transactions. Data source: +\&\*(L"\s-1INNODB_TRANSACTIONS\s0\*(R". +.IP "insert_buffers" 4 +.IX Item "insert_buffers" +Displays data about InnoDB's insert buffer. Data source: \*(L"\s-1STATUS_VARIABLES\s0\*(R". +.IP "io_threads" 4 +.IX Item "io_threads" +Displays data about InnoDB's I/O threads. Data source: \*(L"\s-1IO_THREADS\s0\*(R". +.IP "log_statistics" 4 +.IX Item "log_statistics" +Displays data about InnoDB's logging system. Data source: \*(L"\s-1STATUS_VARIABLES\s0\*(R". +.IP "master_status" 4 +.IX Item "master_status" +Displays replication master status. Data source: \*(L"\s-1STATUS_VARIABLES\s0\*(R". +.IP "open_tables" 4 +.IX Item "open_tables" +Displays open tables. Data source: \*(L"\s-1OPEN_TABLES\s0\*(R". +.IP "page_statistics" 4 +.IX Item "page_statistics" +Displays InnoDB page statistics. Data source: \*(L"\s-1STATUS_VARIABLES\s0\*(R". +.IP "pending_io" 4 +.IX Item "pending_io" +Displays InnoDB pending I/O operations. Data source: \*(L"\s-1STATUS_VARIABLES\s0\*(R". +.IP "processlist" 4 +.IX Item "processlist" +Displays current MySQL processes (threads/connections). Data source: +\&\*(L"\s-1PROCESSLIST\s0\*(R". +.IP "q_header" 4 +.IX Item "q_header" +Displays various status values. Data source: \*(L"\s-1STATUS_VARIABLES\s0\*(R". +.IP "row_operation_misc" 4 +.IX Item "row_operation_misc" +Displays data about InnoDB's row operations. Data source: +\&\*(L"\s-1STATUS_VARIABLES\s0\*(R". +.IP "row_operations" 4 +.IX Item "row_operations" +Displays data about InnoDB's row operations. Data source: +\&\*(L"\s-1STATUS_VARIABLES\s0\*(R". +.IP "semaphores" 4 +.IX Item "semaphores" +Displays data about InnoDB's semaphores and mutexes. Data source: +\&\*(L"\s-1STATUS_VARIABLES\s0\*(R". +.IP "slave_io_status" 4 +.IX Item "slave_io_status" +Displays data about the slave I/O thread. Data source: +\&\*(L"\s-1STATUS_VARIABLES\s0\*(R". +.IP "slave_sql_status" 4 +.IX Item "slave_sql_status" +Displays data about the slave \s-1SQL\s0 thread. Data source: \*(L"\s-1STATUS_VARIABLES\s0\*(R". +.IP "t_header" 4 +.IX Item "t_header" +Displays various InnoDB status values. Data source: \*(L"\s-1STATUS_VARIABLES\s0\*(R". +.IP "var_status" 4 +.IX Item "var_status" +Displays user-configurable data. Data source: \*(L"\s-1STATUS_VARIABLES\s0\*(R". +.IP "wait_array" 4 +.IX Item "wait_array" +Displays data about InnoDB's \s-1OS\s0 wait array. Data source: \*(L"\s-1OS_WAIT_ARRAY\s0\*(R". +.SS "\s-1COLUMNS\s0" +.IX Subsection "COLUMNS" +Columns belong to tables. You can choose a table's columns by pressing the '^' +key, which starts the \*(L"\s-1TABLE\s0 \s-1EDITOR\s0\*(R" and lets you choose and edit columns. +Pressing 'e' from within the table editor lets you edit the column's properties: +.IP "\(bu" 4 +hdr: a column header. This appears in the first row of the table. +.IP "\(bu" 4 +just: justification. '\-' means left-justified and '' means right-justified, +just as with printf formatting codes (not a coincidence). +.IP "\(bu" 4 +dec: whether to further align the column on the decimal point. +.IP "\(bu" 4 +num: whether the column is numeric. This affects how values are sorted +(lexically or numerically). +.IP "\(bu" 4 +label: a small note about the column, which appears in dialogs that help the +user choose columns. +.IP "\(bu" 4 +src: an expression that innotop uses to extract the column's data from its +source (see \*(L"\s-1DATA\s0 \s-1SOURCES\s0\*(R"). See \*(L"\s-1EXPRESSIONS\s0\*(R" for more on expressions. +.IP "\(bu" 4 +minw: specifies a minimum display width. This helps stabilize the display, +which makes it easier to read if the data is changing frequently. +.IP "\(bu" 4 +maxw: similar to minw. +.IP "\(bu" 4 +trans: a list of column transformations. See \*(L"\s-1TRANSFORMATIONS\s0\*(R". +.IP "\(bu" 4 +agg: an aggregate function. See \*(L"\s-1GROUPING\s0\*(R". The default is \*(L"first\*(R". +.IP "\(bu" 4 +aggonly: controls whether the column only shows when grouping is enabled on the +table (see \*(L"\s-1GROUPING\s0\*(R"). By default, this is disabled. This means columns +will always be shown by default, whether grouping is enabled or not. If a +column's aggonly is set true, the column will appear when you toggle grouping on +the table. Several columns are set this way, such as the count column on +\&\*(L"processlist\*(R" and \*(L"innodb_transactions\*(R", so you don't see a count when the +grouping isn't enabled, but you do when it is. +.SS "\s-1FILTERS\s0" +.IX Subsection "FILTERS" +Filters remove rows from the display. They behave much like a \s-1WHERE\s0 clause in +\&\s-1SQL\s0. innotop has several built-in filters, which remove irrelevant information +like inactive queries, but you can define your own as well. innotop also lets +you create quick-filters, which do not get saved to the configuration file, and +are just an easy way to quickly view only some rows. +.PP +You can enable or disable a filter on any table. Press the '%' key (mnemonic: % +looks kind of like a line being filtered between two circles) and choose which +table you want to filter, if asked. You'll then see a list of possible filters +and a list of filters currently enabled for that table. Type the names of +filters you want to apply and press Enter. +.PP +\fIUSER-DEFINED \s-1FILTERS\s0\fR +.IX Subsection "USER-DEFINED FILTERS" +.PP +If you type a name that doesn't exist, innotop will prompt you to create the +filter. Filters are easy to create if you know Perl, and not hard if you don't. +What you're doing is creating a subroutine that returns true if the row should +be displayed. The row is a hash reference passed to your subroutine as \f(CW$set\fR. +.PP +For example, imagine you want to filter the processlist table so you only see +queries that have been running more than five minutes. Type a new name for your +filter, and when prompted for the subroutine body, press \s-1TAB\s0 to initiate your +terminal's auto-completion. You'll see the names of the columns in the +\&\*(L"processlist\*(R" table (innotop generally tries to help you with auto-completion +lists). You want to filter on the 'time' column. Type the text \*(L"$set\->{time} > +300\*(R" to return true when the query is more than five minutes old. That's all +you need to do. +.PP +In other words, the code you're typing is surrounded by an implicit context, +which looks like this: +.PP +.Vb 4 +\& sub filter { +\& my ( $set ) = @_; +\& # YOUR CODE HERE +\& } +.Ve +.PP +If your filter doesn't work, or if something else suddenly behaves differently, +you might have made an error in your filter, and innotop is silently catching +the error. Try enabling \*(L"debug\*(R" to make innotop throw an error instead. +.PP +\fIQUICK-FILTERS\fR +.IX Subsection "QUICK-FILTERS" +.PP +innotop's quick-filters are a shortcut to create a temporary filter that doesn't +persist when you restart innotop. To create a quick-filter, press the '/' key. +innotop will prompt you for the column name and filter text. Again, you can use +auto-completion on column names. The filter text can be just the text you want +to \*(L"search for.\*(R" For example, to filter the \*(L"processlist\*(R" table on queries +that refer to the products table, type '/' and then 'info product'. +.PP +The filter text can actually be any Perl regular expression, but of course a +literal string like 'product' works fine as a regular expression. +.PP +Behind the scenes innotop compiles the quick-filter into a specially tagged +filter that is otherwise like any other filter. It just isn't saved to the +configuration file. +.PP +To clear quick-filters, press the '\e' key and innotop will clear them all at +once. +.SS "\s-1SORTING\s0" +.IX Subsection "SORTING" +innotop has sensible built-in defaults to sort the most important rows to the +top of the table. Like anything else in innotop, you can customize how any +table is sorted. +.PP +To start the sort dialog, start the \*(L"\s-1TABLE\s0 \s-1EDITOR\s0\*(R" with the '^' key, choose a +table if necessary, and press the 's' key. You'll see a list of columns you can +use in the sort expression and the current sort expression, if any. Enter a +list of columns by which you want to sort and press Enter. If you want to +reverse sort, prefix the column name with a minus sign. For example, if you +want to sort by column a ascending, then column b descending, type 'a \-b'. You +can also explicitly add a + in front of columns you want to sort ascending, but +it's not required. +.PP +Some modes have keys mapped to open this dialog directly, and to quickly reverse +sort direction. Press '?' as usual to see which keys are mapped in any mode. +.SS "\s-1GROUPING\s0" +.IX Subsection "GROUPING" +innotop can group, or aggregate, rows together (the terms are used +interchangeably). This is quite similar to an \s-1SQL\s0 \s-1GROUP\s0 \s-1BY\s0 clause. You can +specify to group on certain columns, or if you don't specify any, the entire set +of rows is treated as one group. This is quite like \s-1SQL\s0 so far, but unlike \s-1SQL\s0, +you can also select un-grouped columns. innotop actually aggregates every +column. If you don't explicitly specify a grouping function, the default is +\&'first'. This is basically a convenience so you don't have to specify an +aggregate function for every column you want in the result. +.PP +You can quickly toggle grouping on a table with the '=' key, which toggles its +aggregate property. This property doesn't persist to the config file. +.PP +The columns by which the table is grouped are specified in its group_by +property. When you turn grouping on, innotop places the group_by columns at the +far left of the table, even if they're not supposed to be visible. The rest of +the visible columns appear in order after them. +.PP +Two tables have default group_by lists and a count column built in: +\&\*(L"processlist\*(R" and \*(L"innodb_transactions\*(R". The grouping is by connection +and status, so you can quickly see how many queries or transactions are in a +given status on each server you're monitoring. The time columns are aggregated +as a sum; other columns are left at the default 'first' aggregation. +.PP +By default, the table shown in \*(L"S: Variables & Status\*(R" mode also uses +grouping so you can monitor variables and status across many servers. The +default aggregation function in this mode is 'avg'. +.PP +Valid grouping functions are defined in the \f(CW%agg_funcs\fR hash. They include +.IP "first" 4 +.IX Item "first" +Returns the first element in the group. +.IP "count" 4 +.IX Item "count" +Returns the number of elements in the group, including undefined elements, much +like \s-1SQL\s0's \s-1COUNT\s0(*). +.IP "avg" 4 +.IX Item "avg" +Returns the average of defined elements in the group. +.IP "sum" 4 +.IX Item "sum" +Returns the sum of elements in the group. +.PP +Here's an example of grouping at work. Suppose you have a very busy server with +hundreds of open connections, and you want to see how many connections are in +what status. Using the built-in grouping rules, you can press 'Q' to enter +\&\*(L"Q: Query List\*(R" mode. Press '=' to toggle grouping (if necessary, select the +\&\*(L"processlist\*(R" table when prompted). +.PP +Your display might now look like the following: +.PP +.Vb 1 +\& Query List (? for help) localhost, 32:33, 0.11 QPS, 1 thd, 5.0.38\-log +\& +\& CXN Cmd Cnt ID User Host Time Query +\& localhost Query 49 12933 webusr localhost 19:38 SELECT * FROM +\& localhost Sending Da 23 2383 webusr localhost 12:43 SELECT col1, +\& localhost Sleep 120 140 webusr localhost 5:18:12 +\& localhost Statistics 12 19213 webusr localhost 01:19 SELECT * FROM +.Ve +.PP +That's actually quite a worrisome picture. You've got a lot of idle connections +(Sleep), and some connections executing queries (Query and Sending Data). +That's okay, but you also have a lot in Statistics status, collectively spending +over a minute. That means the query optimizer is having a really hard time +optimizing your statements. Something is wrong; it should normally take +milliseconds to optimize queries. You might not have seen this pattern if you +didn't look at your connections in aggregate. (This is a made-up example, but +it can happen in real life). +.SS "\s-1PIVOTING\s0" +.IX Subsection "PIVOTING" +innotop can pivot a table for more compact display, similar to a Pivot Table in +a spreadsheet (also known as a crosstab). Pivoting a table makes columns into +rows. Assume you start with this table: +.PP +.Vb 4 +\& foo bar +\& === === +\& 1 3 +\& 2 4 +.Ve +.PP +After pivoting, the table will look like this: +.PP +.Vb 4 +\& name set0 set1 +\& ==== ==== ==== +\& foo 1 2 +\& bar 3 4 +.Ve +.PP +To get reasonable results, you might need to group as well as pivoting. +innotop currently does this for \*(L"S: Variables & Status\*(R" mode. +.SS "\s-1COLORS\s0" +.IX Subsection "COLORS" +By default, innotop highlights rows with color so you can see at a glance which +rows are more important. You can customize the colorization rules and add your +own to any table. Open the table editor with the '^' key, choose a table if +needed, and press 'o' to open the color editor dialog. +.PP +The color editor dialog displays the rules applied to the table, in the order +they are evaluated. Each row is evaluated against each rule to see if the rule +matches the row; if it does, the row gets the specified color, and no further +rules are evaluated. The rules look like the following: +.PP +.Vb 9 +\& state eq Locked black on_red +\& cmd eq Sleep white +\& user eq system user white +\& cmd eq Connect white +\& cmd eq Binlog Dump white +\& time > 600 red +\& time > 120 yellow +\& time > 60 green +\& time > 30 cyan +.Ve +.PP +This is the default rule set for the \*(L"processlist\*(R" table. In order of +priority, these rules make locked queries black on a red background, \*(L"gray out\*(R" +connections from replication and sleeping queries, and make queries turn from +cyan to red as they run longer. +.PP +(For some reason, the \s-1ANSI\s0 color code \*(L"white\*(R" is actually a light gray. Your +terminal's display may vary; experiment to find colors you like). +.PP +You can use keystrokes to move the rules up and down, which re-orders their +priority. You can also delete rules and add new ones. If you add a new rule, +innotop prompts you for the column, an operator for the comparison, a value +against which to compare the column, and a color to assign if the rule matches. +There is auto-completion and prompting at each step. +.PP +The value in the third step needs to be correctly quoted. innotop does not try +to quote the value because it doesn't know whether it should treat the value as +a string or a number. If you want to compare the column against a string, as +for example in the first rule above, you should enter 'Locked' surrounded by +quotes. If you get an error message about a bareword, you probably should have +quoted something. +.SS "\s-1EXPRESSIONS\s0" +.IX Subsection "EXPRESSIONS" +Expressions are at the core of how innotop works, and are what enables you to +extend innotop as you wish. Recall the table lifecycle explained in +\&\*(L"\s-1TABLES\s0\*(R". Expressions are used in the earliest step, where it extracts +values from a data source to form rows. +.PP +It does this by calling a subroutine for each column, passing it the source data +set, a set of current values, and a set of previous values. These are all +needed so the subroutine can calculate things like the difference between this +tick and the previous tick. +.PP +The subroutines that extract the data from the set are compiled from +expressions. This gives significantly more power than just naming the values to +fill the columns, because it allows the column's value to be calculated from +whatever data is necessary, but avoids the need to write complicated and lengthy +Perl code. +.PP +innotop begins with a string of text that can look as simple as a value's name +or as complicated as a full-fledged Perl expression. It looks at each +\&'bareword' token in the string and decides whether it's supposed to be a key +into the \f(CW$set\fR hash. A bareword is an unquoted value that isn't already +surrounded by code-ish things like dollar signs or curly brackets. If innotop +decides that the bareword isn't a function or other valid Perl code, it converts +it into a hash access. After the whole string is processed, innotop compiles a +subroutine, like this: +.PP +.Vb 5 +\& sub compute_column_value { +\& my ( $set, $cur, $pre ) = @_; +\& my $val = # EXPANDED STRING GOES HERE +\& return $val; +\& } +.Ve +.PP +Here's a concrete example, taken from the header table \*(L"q_header\*(R" in \*(L"Q: +Query List\*(R" mode. This expression calculates the qps, or Queries Per Second, +column's values, from the values returned by \s-1SHOW\s0 \s-1STATUS:\s0 +.PP +.Vb 1 +\& Questions/Uptime_hires +.Ve +.PP +innotop decides both words are barewords, and transforms this expression into +the following Perl code: +.PP +.Vb 1 +\& $set\->{Questions}/$set\->{Uptime_hires} +.Ve +.PP +When surrounded by the rest of the subroutine's code, this is executable Perl +that calculates a high-resolution queries-per-second value. +.PP +The arguments to the subroutine are named \f(CW$set\fR, \f(CW$cur\fR, and \f(CW$pre\fR. In most cases, +\&\f(CW$set\fR and \f(CW$cur\fR will be the same values. However, if \*(L"status_inc\*(R" is set, \f(CW$cur\fR +will not be the same as \f(CW$set\fR, because \f(CW$set\fR will already contain values that are +the incremental difference between \f(CW$cur\fR and \f(CW$pre\fR. +.PP +Every column in innotop is computed by subroutines compiled in the same fashion. +There is no difference between innotop's built-in columns and user-defined +columns. This keeps things consistent and predictable. +.SS "\s-1TRANSFORMATIONS\s0" +.IX Subsection "TRANSFORMATIONS" +Transformations change how a value is rendered. For example, they can take a +number of seconds and display it in H:M:S format. The following transformations +are defined: +.IP "commify" 4 +.IX Item "commify" +Adds commas to large numbers every three decimal places. +.IP "dulint_to_int" 4 +.IX Item "dulint_to_int" +Accepts two unsigned integers and converts them into a single longlong. This is +useful for certain operations with InnoDB, which uses two integers as +transaction identifiers, for example. +.IP "no_ctrl_char" 4 +.IX Item "no_ctrl_char" +Removes quoted control characters from the value. This is affected by the +\&\*(L"charset\*(R" configuration variable. +.Sp +This transformation only operates within quoted strings, for example, values to +a \s-1SET\s0 clause in an \s-1UPDATE\s0 statement. It will not alter the \s-1UPDATE\s0 statement, +but will collapse the quoted string to [\s-1BINARY\s0] or [\s-1TEXT\s0], depending on the +charset. +.IP "percent" 4 +.IX Item "percent" +Converts a number to a percentage by multiplying it by two, formatting it with +\&\*(L"num_digits\*(R" digits after the decimal point, and optionally adding a percent +sign (see \*(L"show_percent\*(R"). +.IP "secs_to_time" 4 +.IX Item "secs_to_time" +Formats a number of seconds as time in days+hours:minutes:seconds format. +.IP "set_precision" 4 +.IX Item "set_precision" +Formats numbers with \*(L"num_digits\*(R" number of digits after the decimal point. +.IP "shorten" 4 +.IX Item "shorten" +Formats a number as a unit of 1024 (k/M/G/T) and with \*(L"num_digits\*(R" number of +digits after the decimal point. +.SS "\s-1TABLE\s0 \s-1EDITOR\s0" +.IX Subsection "TABLE EDITOR" +The innotop table editor lets you customize tables with keystrokes. You start +the table editor with the '^' key. If there's more than one table on the +screen, it will prompt you to choose one of them. Once you do, innotop will +show you something like this: +.PP +.Vb 1 +\& Editing table definition for Buffer Pool. Press ? for help, q to quit. +\& +\& name hdr label src +\& cxn CXN Connection from which cxn +\& buf_pool_size Size Buffer pool size IB_bp_buf_poo +\& buf_free Free Bufs Buffers free in the b IB_bp_buf_fre +\& pages_total Pages Pages total IB_bp_pages_t +\& pages_modified Dirty Pages Pages modified (dirty IB_bp_pages_m +\& buf_pool_hit_rate Hit Rate Buffer pool hit rate IB_bp_buf_poo +\& total_mem_alloc Memory Total memory allocate IB_bp_total_m +\& add_pool_alloc Add\*(Aql Pool Additonal pool alloca IB_bp_add_poo +.Ve +.PP +The first line shows which table you're editing, and reminds you again to press +\&'?' for a list of key mappings. The rest is a tabular representation of the +table's columns, because that's likely what you're trying to edit. However, you +can edit more than just the table's columns; this screen can start the filter +editor, color rule editor, and more. +.PP +Each row in the display shows a single column in the table you're editing, along +with a couple of its properties such as its header and source expression (see +\&\*(L"\s-1EXPRESSIONS\s0\*(R"). +.PP +The key mappings are Vim-style, as in many other places. Pressing 'j' and 'k' +moves the highlight up or down. You can then (d)elete or (e)dit the highlighted +column. You can also (a)dd a column to the table. This actually just activates +one of the columns already defined for the table; it prompts you to choose from +among the columns available but not currently displayed. Finally, you can +re-order the columns with the '+' and '\-' keys. +.PP +You can do more than just edit the columns with the table editor, you can also +edit other properties, such as the table's sort expression and group-by +expression. Press '?' to see the full list, of course. +.PP +If you want to really customize and create your own column, as opposed to just +activating a built-in one that's not currently displayed, press the (n)ew key, +and innotop will prompt you for the information it needs: +.IP "\(bu" 4 +The column name: this needs to be a word without any funny characters, e.g. just +letters, numbers and underscores. +.IP "\(bu" 4 +The column header: this is the label that appears at the top of the column, in +the table header. This can have spaces and funny characters, but be careful not +to make it too wide and waste space on-screen. +.IP "\(bu" 4 +The column's data source: this is an expression that determines what data from +the source (see \*(L"\s-1TABLES\s0\*(R") innotop will put into the column. This can just be +the name of an item in the source, or it can be a more complex expression, as +described in \*(L"\s-1EXPRESSIONS\s0\*(R". +.PP +Once you've entered the required data, your table has a new column. There is no +difference between this column and the built-in ones; it can have all the same +properties and behaviors. innotop will write the column's definition to the +configuration file, so it will persist across sessions. +.PP +Here's an example: suppose you want to track how many times your slaves have +retried transactions. According to the MySQL manual, the +Slave_retried_transactions status variable gives you that data: \*(L"The total +number of times since startup that the replication slave \s-1SQL\s0 thread has retried +transactions. This variable was added in version 5.0.4.\*(R" This is appropriate to +add to the \*(L"slave_sql_status\*(R" table. +.PP +To add the column, switch to the replication-monitoring mode with the 'M' key, +and press the '^' key to start the table editor. When prompted, choose +slave_sql_status as the table, then press 'n' to create the column. Type +\&'retries' as the column name, 'Retries' as the column header, and +\&'Slave_retried_transactions' as the source. Now the column is created, and you +see the table editor screen again. Press 'q' to exit the table editor, and +you'll see your column at the end of the table. +.SH "VARIABLE SETS" +.IX Header "VARIABLE SETS" +Variable sets are used in \*(L"S: Variables & Status\*(R" mode to define more easily +what variables you want to monitor. Behind the scenes they are compiled to a +list of expressions, and then into a column list so they can be treated just +like columns in any other table, in terms of data extraction and +transformations. However, you're protected from the tedious details by a syntax +that ought to feel very natural to you: a \s-1SQL\s0 \s-1SELECT\s0 list. +.PP +The data source for variable sets, and indeed the entire S mode, is the +combination of \s-1SHOW\s0 \s-1STATUS\s0, \s-1SHOW\s0 \s-1VARIABLES\s0, and \s-1SHOW\s0 \s-1INNODB\s0 \s-1STATUS\s0. Imagine +that you had a huge table with one column per variable returned from those +statements. That's the data source for variable sets. You can now query this +data source just like you'd expect. For example: +.PP +.Vb 1 +\& Questions, Uptime, Questions/Uptime as QPS +.Ve +.PP +Behind the scenes innotop will split that variable set into three expressions, +compile them and turn them into a table definition, then extract as usual. This +becomes a \*(L"variable set,\*(R" or a \*(L"list of variables you want to monitor.\*(R" +.PP +innotop lets you name and save your variable sets, and writes them to the +configuration file. You can choose which variable set you want to see with the +\&'c' key, or activate the next and previous sets with the '>' and '<' keys. +There are many built-in variable sets as well, which should give you a good +start for creating your own. Press 'e' to edit the current variable set, or +just to see how it's defined. To create a new one, just press 'c' and type its +name. +.PP +You may want to use some of the functions listed in \*(L"\s-1TRANSFORMATIONS\s0\*(R" to help +format the results. In particular, \*(L"set_precision\*(R" is often useful to limit +the number of digits you see. Extending the above example, here's how: +.PP +.Vb 1 +\& Questions, Uptime, set_precision(Questions/Uptime) as QPS +.Ve +.PP +Actually, this still needs a little more work. If your \*(L"interval\*(R" is less +than one second, you might be dividing by zero because Uptime is incremental in +this mode by default. Instead, use Uptime_hires: +.PP +.Vb 1 +\& Questions, Uptime, set_precision(Questions/Uptime_hires) as QPS +.Ve +.PP +This example is simple, but it shows how easy it is to choose which variables +you want to monitor. +.SH "PLUGINS" +.IX Header "PLUGINS" +innotop has a simple but powerful plugin mechanism by which you can extend +or modify its existing functionality, and add new functionality. innotop's +plugin functionality is event-based: plugins register themselves to be called +when events happen. They then have a chance to influence the event. +.PP +An innotop plugin is a Perl module placed in innotop's \*(L"plugin_dir\*(R" +directory. On \s-1UNIX\s0 systems, you can place a symbolic link to the module instead +of putting the actual file there. innotop automatically discovers the file. If +there is a corresponding entry in the \*(L"plugins\*(R" configuration file section, +innotop loads and activates the plugin. +.PP +The module must conform to innotop's plugin interface. Additionally, the source +code of the module must be written in such a way that innotop can inspect the +file and determine the package name and description. +.SS "Package Source Convention" +.IX Subsection "Package Source Convention" +innotop inspects the plugin module's source to determine the Perl package name. +It looks for a line of the form \*(L"package Foo;\*(R" and if found, considers the +plugin's package name to be Foo. Of course the package name can be a valid Perl +package name, with double semicolons and so on. +.PP +It also looks for a description in the source code, to make the plugin editor +more human-friendly. The description is a comment line of the form \*(L"# +description: Foo\*(R", where \*(L"Foo\*(R" is the text innotop will consider to be the +plugin's description. +.SS "Plugin Interface" +.IX Subsection "Plugin Interface" +The innotop plugin interface is quite simple: innotop expects the plugin to be +an object-oriented module it can call certain methods on. The methods are +.IP "new(%variables)" 4 +.IX Item "new(%variables)" +This is the plugin's constructor. It is passed a hash of innotop's variables, +which it can manipulate (see \*(L"Plugin Variables\*(R"). It must return a reference +to the newly created plugin object. +.Sp +At construction time, innotop has only loaded the general configuration and +created the default built-in variables with their default contents (which is +quite a lot). Therefore, the state of the program is exactly as in the innotop +source code, plus the configuration variables from the \*(L"general\*(R" section in +the config file. +.Sp +If your plugin manipulates the variables, it is changing global data, which is +shared by innotop and all plugins. Plugins are loaded in the order they're +listed in the config file. Your plugin may load before or after another plugin, +so there is a potential for conflict or interaction between plugins if they +modify data other plugins use or modify. +.IP "\fIregister_for_events()\fR" 4 +.IX Item "register_for_events()" +This method must return a list of events in which the plugin is interested, if +any. See \*(L"Plugin Events\*(R" for the defined events. If the plugin returns an +event that's not defined, the event is ignored. +.IP "event handlers" 4 +.IX Item "event handlers" +The plugin must implement a method named the same as each event for which it has +registered. In other words, if the plugin returns qw(foo bar) from +\&\fIregister_for_events()\fR, it must have \fIfoo()\fR and \fIbar()\fR methods. These methods are +callbacks for the events. See \*(L"Plugin Events\*(R" for more details about each +event. +.SS "Plugin Variables" +.IX Subsection "Plugin Variables" +The plugin's constructor is passed a hash of innotop's variables, which it can +manipulate. It is probably a good idea if the plugin object saves a copy of it +for later use. The variables are defined in the innotop variable +\&\f(CW%pluggable_vars\fR, and are as follows: +.IP "action_for" 4 +.IX Item "action_for" +A hashref of key mappings. These are innotop's global hot-keys. +.IP "agg_funcs" 4 +.IX Item "agg_funcs" +A hashref of functions that can be used for grouping. See \*(L"\s-1GROUPING\s0\*(R". +.IP "config" 4 +.IX Item "config" +The global configuration hash. +.IP "connections" 4 +.IX Item "connections" +A hashref of connection specifications. These are just specifications of how to +connect to a server. +.IP "dbhs" 4 +.IX Item "dbhs" +A hashref of innotop's database connections. These are actual \s-1DBI\s0 connection +objects. +.IP "filters" 4 +.IX Item "filters" +A hashref of filters applied to table rows. See \*(L"\s-1FILTERS\s0\*(R" for more. +.IP "modes" 4 +.IX Item "modes" +A hashref of modes. See \*(L"\s-1MODES\s0\*(R" for more. +.IP "server_groups" 4 +.IX Item "server_groups" +A hashref of server groups. See \*(L"\s-1SERVER\s0 \s-1GROUPS\s0\*(R". +.IP "tbl_meta" 4 +.IX Item "tbl_meta" +A hashref of innotop's table meta-data, with one entry per table (see +\&\*(L"\s-1TABLES\s0\*(R" for more information). +.IP "trans_funcs" 4 +.IX Item "trans_funcs" +A hashref of transformation functions. See \*(L"\s-1TRANSFORMATIONS\s0\*(R". +.IP "var_sets" 4 +.IX Item "var_sets" +A hashref of variable sets. See \*(L"\s-1VARIABLE\s0 \s-1SETS\s0\*(R". +.SS "Plugin Events" +.IX Subsection "Plugin Events" +Each event is defined somewhere in the innotop source code. When innotop runs +that code, it executes the callback function for each plugin that expressed its +interest in the event. innotop passes some data for each event. The events are +defined in the \f(CW%event_listener_for\fR variable, and are as follows: +.ie n .IP "extract_values($set, $cur, $pre, $tbl)" 4 +.el .IP "extract_values($set, \f(CW$cur\fR, \f(CW$pre\fR, \f(CW$tbl\fR)" 4 +.IX Item "extract_values($set, $cur, $pre, $tbl)" +This event occurs inside the function that extracts values from a data source. +The arguments are the set of values, the current values, the previous values, +and the table name. +.IP "set_to_tbl" 4 +.IX Item "set_to_tbl" +Events are defined at many places in this subroutine, which is responsible for +turning an arrayref of hashrefs into an arrayref of lines that can be printed to +the screen. The events all pass the same data: an arrayref of rows and the name +of the table being created. The events are set_to_tbl_pre_filter, +set_to_tbl_pre_sort,set_to_tbl_pre_group, set_to_tbl_pre_colorize, +set_to_tbl_pre_transform, set_to_tbl_pre_pivot, set_to_tbl_pre_create, +set_to_tbl_post_create. +.IP "draw_screen($lines)" 4 +.IX Item "draw_screen($lines)" +This event occurs inside the subroutine that prints the lines to the screen. +\&\f(CW$lines\fR is an arrayref of strings. +.SS "Simple Plugin Example" +.IX Subsection "Simple Plugin Example" +The easiest way to explain the plugin functionality is probably with a simple +example. The following module adds a column to the beginning of every table and +sets its value to 1. +.PP +.Vb 2 +\& use strict; +\& use warnings FATAL => \*(Aqall\*(Aq; +\& +\& package Innotop::Plugin::Example; +\& # description: Adds an \*(Aqexample\*(Aq column to every table +\& +\& sub new { +\& my ( $class, %vars ) = @_; +\& # Store reference to innotop\*(Aqs variables in $self +\& my $self = bless { %vars }, $class; +\& +\& # Design the example column +\& my $col = { +\& hdr => \*(AqExample\*(Aq, +\& just => \*(Aq\*(Aq, +\& dec => 0, +\& num => 1, +\& label => \*(AqExample\*(Aq, +\& src => \*(Aqexample\*(Aq, # Get data from this column in the data source +\& tbl => \*(Aq\*(Aq, +\& trans => [], +\& }; +\& +\& # Add the column to every table. +\& my $tbl_meta = $vars{tbl_meta}; +\& foreach my $tbl ( values %$tbl_meta ) { +\& # Add the column to the list of defined columns +\& $tbl\->{cols}\->{example} = $col; +\& # Add the column to the list of visible columns +\& unshift @{$tbl\->{visible}}, \*(Aqexample\*(Aq; +\& } +\& +\& # Be sure to return a reference to the object. +\& return $self; +\& } +\& +\& # I\*(Aqd like to be called when a data set is being rendered into a table, please. +\& sub register_for_events { +\& my ( $self ) = @_; +\& return qw(set_to_tbl_pre_filter); +\& } +\& +\& # This method will be called when the event fires. +\& sub set_to_tbl_pre_filter { +\& my ( $self, $rows, $tbl ) = @_; +\& # Set the example column\*(Aqs data source to the value 1. +\& foreach my $row ( @$rows ) { +\& $row\->{example} = 1; +\& } +\& } +\& +\& 1; +.Ve +.SS "Plugin Editor" +.IX Subsection "Plugin Editor" +The plugin editor lets you view the plugins innotop discovered and activate or +deactivate them. Start the editor by pressing $ to start the configuration +editor from any mode. Press the 'p' key to start the plugin editor. You'll see +a list of plugins innotop discovered. You can use the 'j' and 'k' keys to move +the highlight to the desired one, then press the * key to toggle it active or +inactive. Exit the editor and restart innotop for the changes to take effect. +.SH "SQL STATEMENTS" +.IX Header "SQL STATEMENTS" +innotop uses a limited set of \s-1SQL\s0 statements to retrieve data from MySQL for +display. The statements are customized depending on the server version against +which they are executed; for example, on MySQL 5 and newer, \s-1INNODB_STATUS\s0 +executes \*(L"\s-1SHOW\s0 \s-1ENGINE\s0 \s-1INNODB\s0 \s-1STATUS\s0\*(R", while on earlier versions it executes +\&\*(L"\s-1SHOW\s0 \s-1INNODB\s0 \s-1STATUS\s0\*(R". The statements are as follows: +.PP +.Vb 12 +\& Statement SQL executed +\& =================== =============================== +\& INNODB_STATUS SHOW [ENGINE] INNODB STATUS +\& KILL_CONNECTION KILL +\& KILL_QUERY KILL QUERY +\& OPEN_TABLES SHOW OPEN TABLES +\& PROCESSLIST SHOW FULL PROCESSLIST +\& SHOW_MASTER_LOGS SHOW MASTER LOGS +\& SHOW_MASTER_STATUS SHOW MASTER STATUS +\& SHOW_SLAVE_STATUS SHOW SLAVE STATUS +\& SHOW_STATUS SHOW [GLOBAL] STATUS +\& SHOW_VARIABLES SHOW [GLOBAL] VARIABLES +.Ve +.SH "DATA SOURCES" +.IX Header "DATA SOURCES" +Each time innotop extracts values to create a table (see \*(L"\s-1EXPRESSIONS\s0\*(R" and +\&\*(L"\s-1TABLES\s0\*(R"), it does so from a particular data source. Largely because of the +complex data extracted from \s-1SHOW\s0 \s-1INNODB\s0 \s-1STATUS\s0, this is slightly messy. \s-1SHOW\s0 +\&\s-1INNODB\s0 \s-1STATUS\s0 contains a mixture of single values and repeated values that form +nested data sets. +.PP +Whenever innotop fetches data from MySQL, it adds two extra bits to each set: +cxn and Uptime_hires. cxn is the name of the connection from which the data +came. Uptime_hires is a high-resolution version of the server's Uptime status +variable, which is important if your \*(L"interval\*(R" setting is sub-second. +.PP +Here are the kinds of data sources from which data is extracted: +.IP "\s-1STATUS_VARIABLES\s0" 4 +.IX Item "STATUS_VARIABLES" +This is the broadest category, into which the most kinds of data fall. It +begins with the combination of \s-1SHOW\s0 \s-1STATUS\s0 and \s-1SHOW\s0 \s-1VARIABLES\s0, but other sources +may be included as needed, for example, \s-1SHOW\s0 \s-1MASTER\s0 \s-1STATUS\s0 and \s-1SHOW\s0 \s-1SLAVE\s0 +\&\s-1STATUS\s0, as well as many of the non-repeated values from \s-1SHOW\s0 \s-1INNODB\s0 \s-1STATUS\s0. +.IP "\s-1DEADLOCK_LOCKS\s0" 4 +.IX Item "DEADLOCK_LOCKS" +This data is extracted from the transaction list in the \s-1LATEST\s0 \s-1DETECTED\s0 \s-1DEADLOCK\s0 +section of \s-1SHOW\s0 \s-1INNODB\s0 \s-1STATUS\s0. It is nested two levels deep: transactions, then +locks. +.IP "\s-1DEADLOCK_TRANSACTIONS\s0" 4 +.IX Item "DEADLOCK_TRANSACTIONS" +This data is from the transaction list in the \s-1LATEST\s0 \s-1DETECTED\s0 \s-1DEADLOCK\s0 +section of \s-1SHOW\s0 \s-1INNODB\s0 \s-1STATUS\s0. It is nested one level deep. +.IP "\s-1EXPLAIN\s0" 4 +.IX Item "EXPLAIN" +This data is from the result set returned by \s-1EXPLAIN\s0. +.IP "\s-1INNODB_TRANSACTIONS\s0" 4 +.IX Item "INNODB_TRANSACTIONS" +This data is from the \s-1TRANSACTIONS\s0 section of \s-1SHOW\s0 \s-1INNODB\s0 \s-1STATUS\s0. +.IP "\s-1IO_THREADS\s0" 4 +.IX Item "IO_THREADS" +This data is from the list of threads in the the \s-1FILE\s0 I/O section of \s-1SHOW\s0 \s-1INNODB\s0 +\&\s-1STATUS\s0. +.IP "\s-1INNODB_LOCKS\s0" 4 +.IX Item "INNODB_LOCKS" +This data is from the \s-1TRANSACTIONS\s0 section of \s-1SHOW\s0 \s-1INNODB\s0 \s-1STATUS\s0 and is nested +two levels deep. +.IP "\s-1OPEN_TABLES\s0" 4 +.IX Item "OPEN_TABLES" +This data is from \s-1SHOW\s0 \s-1OPEN\s0 \s-1TABLES\s0. +.IP "\s-1PROCESSLIST\s0" 4 +.IX Item "PROCESSLIST" +This data is from \s-1SHOW\s0 \s-1FULL\s0 \s-1PROCESSLIST\s0. +.IP "\s-1OS_WAIT_ARRAY\s0" 4 +.IX Item "OS_WAIT_ARRAY" +This data is from the \s-1SEMAPHORES\s0 section of \s-1SHOW\s0 \s-1INNODB\s0 \s-1STATUS\s0 and is nested one +level deep. It comes from the lines that look like this: +.Sp +.Vb 1 +\& \-\-Thread 1568861104 has waited at btr0cur.c line 424 .... +.Ve +.SH "MYSQL PRIVILEGES" +.IX Header "MYSQL PRIVILEGES" +.IP "\(bu" 4 +You must connect to MySQL as a user who has the \s-1SUPER\s0 privilege for many of the +functions. +.IP "\(bu" 4 +If you don't have the \s-1SUPER\s0 privilege, you can still run some functions, but you +won't necessarily see all the same data. +.IP "\(bu" 4 +You need the \s-1PROCESS\s0 privilege to see the list of currently running queries in Q +mode. +.IP "\(bu" 4 +You need special privileges to start and stop slave servers. +.IP "\(bu" 4 +You need appropriate privileges to create and drop the deadlock tables if needed +(see \*(L"\s-1SERVER\s0 \s-1CONNECTIONS\s0\*(R"). +.SH "SYSTEM REQUIREMENTS" +.IX Header "SYSTEM REQUIREMENTS" +You need Perl to run innotop, of course. You also need a few Perl modules: \s-1DBI\s0, +DBD::mysql, Term::ReadKey, and Time::HiRes. These should be included with most +Perl distributions, but in case they are not, I recommend using versions +distributed with your operating system or Perl distribution, not from \s-1CPAN\s0. +Term::ReadKey in particular has been known to cause problems if installed from +\&\s-1CPAN\s0. +.PP +If you have Term::ANSIColor, innotop will use it to format headers more readably +and compactly. (Under Microsoft Windows, you also need Win32::Console::ANSI for +terminal formatting codes to be honored). If you install Term::ReadLine, +preferably Term::ReadLine::Gnu, you'll get nice auto-completion support. +.PP +I run innotop on Gentoo GNU/Linux, Debian and Ubuntu, and I've had feedback from +people successfully running it on Red Hat, CentOS, Solaris, and Mac \s-1OSX\s0. I +don't see any reason why it won't work on other UNIX-ish operating systems, but +I don't know for sure. It also runs on Windows under ActivePerl without +problem. +.PP +innotop has been used on MySQL versions 3.23.58, 4.0.27, 4.1.0, 4.1.22, 5.0.26, +5.1.15, and 5.2.3. If it doesn't run correctly for you, that is a bug that +should be reported. +.SH "FILES" +.IX Header "FILES" +\&\f(CW$HOMEDIR\fR/.innotop and/or /etc/innotop are used to store +configuration information. Files include the configuration file innotop.conf, +the core_dump file which contains verbose error messages if \*(L"debug\*(R" is +enabled, and the plugins/ subdirectory. +.SH "GLOSSARY OF TERMS" +.IX Header "GLOSSARY OF TERMS" +.IP "tick" 4 +.IX Item "tick" +A tick is a refresh event, when innotop re-fetches data from connections and +displays it. +.SH "ACKNOWLEDGEMENTS" +.IX Header "ACKNOWLEDGEMENTS" +The following people and organizations are acknowledged for various reasons. +Hopefully no one has been forgotten. +.PP +Allen K. Smith, +Aurimas Mikalauskas, +Bartosz Fenski, +Brian Miezejewski, +Christian Hammers, +Cyril Scetbon, +Dane Miller, +David Multer, +Dr. Frank Ullrich, +Giuseppe Maxia, +Google.com Site Reliability Engineers, +Google Code, +Jan Pieter Kunst, +Jari Aalto, +Jay Pipes, +Jeremy Zawodny, +Johan Idren, +Kristian Kohntopp, +Lenz Grimmer, +Maciej Dobrzanski, +Michiel Betel, +MySQL \s-1AB\s0, +Paul McCullagh, +Sebastien Estienne, +Sourceforge.net, +Steven Kreuzer, +The Gentoo MySQL Team, +Trevor Price, +Yaar Schnitman, +and probably more people that have not been included. +.PP +(If your name has been misspelled, it's probably out of fear of putting +international characters into this documentation; earlier versions of Perl might +not be able to compile it then). +.SH "COPYRIGHT, LICENSE AND WARRANTY" +.IX Header "COPYRIGHT, LICENSE AND WARRANTY" +This program is copyright (c) 2006 Baron Schwartz. +Feedback and improvements are welcome. +.PP +\&\s-1THIS\s0 \s-1PROGRAM\s0 \s-1IS\s0 \s-1PROVIDED\s0 \*(L"\s-1AS\s0 \s-1IS\s0\*(R" \s-1AND\s0 \s-1WITHOUT\s0 \s-1ANY\s0 \s-1EXPRESS\s0 \s-1OR\s0 \s-1IMPLIED\s0 +\&\s-1WARRANTIES\s0, \s-1INCLUDING\s0, \s-1WITHOUT\s0 \s-1LIMITATION\s0, \s-1THE\s0 \s-1IMPLIED\s0 \s-1WARRANTIES\s0 \s-1OF\s0 +\&\s-1MERCHANTIBILITY\s0 \s-1AND\s0 \s-1FITNESS\s0 \s-1FOR\s0 A \s-1PARTICULAR\s0 \s-1PURPOSE\s0. +.PP +This program is free software; you can redistribute it and/or modify it under +the terms of the \s-1GNU\s0 General Public License as published by the Free Software +Foundation, version 2; \s-1OR\s0 the Perl Artistic License. On \s-1UNIX\s0 and similar +systems, you can issue `man perlgpl' or `man perlartistic' to read these +licenses. +.PP +You should have received a copy of the \s-1GNU\s0 General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place, Suite 330, Boston, \s-1MA\s0 02111\-1307 \s-1USA\s0. +.PP +Execute innotop and press '!' to see this information at any time. +.SH "AUTHOR" +.IX Header "AUTHOR" +Originally written by Baron Schwartz; currently maintained by Aaron Racine. +.SH "BUGS" +.IX Header "BUGS" +You can report bugs, ask for improvements, and get other help and support at +. There are mailing lists, a source code +browser, a bug tracker, etc. Please use these instead of contacting the +maintainer or author directly, as it makes our job easier and benefits others if the +discussions are permanent and public. Of course, if you need to contact us in +private, please do. diff --git a/debian/additions/msql2mysql.1 b/debian/additions/msql2mysql.1 new file mode 100644 index 00000000000..8fe05e7415d --- /dev/null +++ b/debian/additions/msql2mysql.1 @@ -0,0 +1,16 @@ +.TH mysql 1 "17 March 2003" "MySQL 3.23" "MySQL database" +.SH NAME +msql2mysql \- MySQL importer for msql style data. +.SH SYNOPSIS +msql2mysql [options] +.SH DESCRIPTION +This program imports old msql database files. + +For more information start the program with '--help'. +.SH "SEE ALSO" +mysql (1), mysqld (1) +.SH AUTHOR +This manpage was written by Christian Hammers . + +MySQL is available at http://www.mysql.com/. +.\" end of man page diff --git a/debian/additions/my.cnf b/debian/additions/my.cnf new file mode 100644 index 00000000000..a62465e5627 --- /dev/null +++ b/debian/additions/my.cnf @@ -0,0 +1,195 @@ +# MariaDB database server configuration file. +# +# ================================================================= +# Base configuration courtesy of Open Query (http://openquery.com/) +# For production use, case-specific preparation is still required. +# 2009-10-07 +# +# This is *not* an optimised config, merely a more sane baseline: +# - InnoDB default (e.g., ACID out-of-the-box, same as on Windows) +# - strict mode (for proper input checks, same as on Windows) +# - various other useful settings +# - make use of MariaDB/Percona/OurDelta enhancements/extensions +# +# For tuning assistance, please see http://openquery.com/services +# ================================================================= +# +# You can copy this file to one of: +# - "/etc/mysql/my.cnf" to set global options, +# - "~/.my.cnf" to set user-specific options. +# +# One can use all long options that the program supports. +# Run program with --help to get a list of available options and with +# --print-defaults to see which it would actually understand and use. +# +# For explanations see +# http://dev.mysql.com/doc/mysql/en/server-system-variables.html + +# This will be passed to all mysql clients +# It has been reported that passwords should be enclosed with ticks/quotes +# escpecially if they contain "#" chars... +# Remember to edit /etc/mysql/debian.cnf when changing the socket location. +[client] +port = 3306 +socket = /var/run/mysqld/mysqld.sock +# Default is Latin1, if you need UTF-8 set this (also in server section) +#default-character-set = utf8 + +# Here is entries for some specific programs +# The following values assume you have at least 32M ram + +# This was formally known as [safe_mysqld]. Both versions are currently parsed. +[mysqld_safe] +socket = /var/run/mysqld/mysqld.sock +nice = 0 + +[mysqld] +# +# * Basic Settings +# +user = mysql +pid-file = /var/run/mysqld/mysqld.pid +socket = /var/run/mysqld/mysqld.sock +port = 3306 +basedir = /usr +datadir = /var/lib/mysql +tmpdir = /tmp +language = /usr/share/mysql/english +skip-external-locking +# +# * Character sets +# +# Default is Latin1, if you need UTF-8 set all this (also in client section) +# +#default-character-set = utf8 +#default-collation = utf8_general_ci +#character_set_server = utf8 +#collation_server = utf8_general_ci +# +# Instead of skip-networking the default is now to listen only on +# localhost which is more compatible and is not less secure. +bind-address = 127.0.0.1 +# +# * Fine Tuning +# +max_connections = 100 +connect_timeout = 5 +wait_timeout = 600 +max_allowed_packet = 16M +thread_cache_size = 128 +sort_buffer_size = 4M +bulk_insert_buffer_size = 16M +tmp_table_size = 32M +max_heap_table_size = 32M +# +# * MyISAM +# +# This replaces the startup script and checks MyISAM tables if needed +# the first time they are touched. On error, make copy and try a repair. +myisam_recover = BACKUP +key_buffer_size = 128M +#open-files-limit = 2000 +table_cache = 400 +myisam_sort_buffer_size = 512M +concurrent_insert = 2 +read_buffer_size = 2M +read_rnd_buffer_size = 1M +# +# * Query Cache Configuration +# +# Cache only tiny result sets, so we can fit more in the query cache. +query_cache_limit = 128K +query_cache_size = 64M +# for more write intensive setups, set to DEMAND or OFF +#query_cache_type = DEMAND +# +# * Logging and Replication +# +# Both location gets rotated by the cronjob. +# Be aware that this log type is a performance killer. +# As of 5.1 you can enable the log at runtime! +#general_log_file = /var/log/mysql/mysql.log +#general_log = 1 +# +# Error logging goes to syslog due to /etc/mysql/conf.d/mysqld_safe_syslog.cnf. +# +# we do want to know about network errors and such +log_warnings = 2 +# +# Enable the slow query log to see queries with especially long duration +#slow_query_log[={0|1}] +slow_query_log_file = /var/log/mysql/mariadb-slow.log +long_query_time = 10 +#log_slow_rate_limit = 1000 +log_slow_verbosity = query_plan + +#log-queries-not-using-indexes +#log_slow_admin_statements +# +# The following can be used as easy to replay backup logs or for replication. +# note: if you are setting up a replication slave, see README.Debian about +# other settings you may need to change. +#server-id = 1 +#report_host = master1 +#auto_increment_increment = 2 +#auto_increment_offset = 1 +log_bin = /var/log/mysql/mariadb-bin +log_bin_index = /var/log/mysql/mariadb-bin.index +# not fab for performance, but safer +#sync_binlog = 1 +expire_logs_days = 10 +max_binlog_size = 100M +# slaves +#relay_log = /var/log/mysql/relay-bin +#relay_log_index = /var/log/mysql/relay-bin.index +#relay_log_info_file = /var/log/mysql/relay-bin.info +#log_slave_updates +#read_only +# +# If applications support it, this stricter sql_mode prevents some +# mistakes like inserting invalid dates etc. +#sql_mode = NO_ENGINE_SUBSTITUTION,TRADITIONAL +# +# * InnoDB +# +# InnoDB is enabled by default with a 10MB datafile in /var/lib/mysql/. +# Read the manual for more InnoDB related options. There are many! +default_storage_engine = InnoDB +# you can't just change log file size, requires special procedure +#innodb_log_file_size = 50M +innodb_buffer_pool_size = 256M +innodb_log_buffer_size = 8M +innodb_file_per_table = 1 +innodb_open_files = 400 +innodb_io_capacity = 400 +innodb_flush_method = O_DIRECT +# +# * Security Features +# +# Read the manual, too, if you want chroot! +# chroot = /var/lib/mysql/ +# +# For generating SSL certificates I recommend the OpenSSL GUI "tinyca". +# +# ssl-ca=/etc/mysql/cacert.pem +# ssl-cert=/etc/mysql/server-cert.pem +# ssl-key=/etc/mysql/server-key.pem + + + +[mysqldump] +quick +quote-names +max_allowed_packet = 16M + +[mysql] +#no-auto-rehash # faster start of mysql but no tab completition + +[isamchk] +key_buffer = 16M + +# +# * IMPORTANT: Additional settings that can override those from this file! +# The files must end with '.cnf', otherwise they'll be ignored. +# +!includedir /etc/mysql/conf.d/ diff --git a/debian/additions/my_print_defaults.1 b/debian/additions/my_print_defaults.1 new file mode 100644 index 00000000000..ebef4157016 --- /dev/null +++ b/debian/additions/my_print_defaults.1 @@ -0,0 +1,16 @@ +.TH mysql 1 "17 March 2003" "MySQL 3.23" "MySQL database" +.SH NAME +my_print_defaults \- MySQL helper script that prints defaults. +.SH SYNOPSIS +my_print_defaults [options] +.SH DESCRIPTION +Prints all arguments that is give to some program using the default files. + +For more information start the program with '--help'. +.SH "SEE ALSO" +mysql (1), mysqld (1) +.SH AUTHOR +This manpage was written by Christian Hammers . + +MySQL is available at http://www.mysql.com/. +.\" end of man page diff --git a/debian/additions/myisam_ftdump.1 b/debian/additions/myisam_ftdump.1 new file mode 100644 index 00000000000..e2de358efcc --- /dev/null +++ b/debian/additions/myisam_ftdump.1 @@ -0,0 +1,16 @@ +.TH mysql 1 "17 March 2003" "MySQL 3.23" "MySQL database" +.SH NAME +myisam_ftdump \- Dumps full text tables. +.SH SYNOPSIS +myisam_ftdump [options] +.SH DESCRIPTION +Dumps information and contents of full text tables. + +For more information start the program with '--help'. +.SH "SEE ALSO" +mysql (1), mysqld (1) +.SH AUTHOR +This manpage was written by Christian Hammers . + +MySQL is available at http://www.mysql.com/. +.\" end of man page diff --git a/debian/additions/myisamchk.1 b/debian/additions/myisamchk.1 new file mode 100644 index 00000000000..fe7f34961e0 --- /dev/null +++ b/debian/additions/myisamchk.1 @@ -0,0 +1,17 @@ +.TH mysql 1 "17 March 2003" "MySQL 3.23" "MySQL database" +.SH NAME +myisamchk \- Checks MySQL myisam type databases. +.SH SYNOPSIS +myisamchk [options] +.SH DESCRIPTION +Description, check and repair of ISAM tables. +Used without options all tables on the command will be checked for errors + +For more information start the program with '--help'. +.SH "SEE ALSO" +mysql (1), mysqld (1) +.SH AUTHOR +This manpage was written by Christian Hammers . + +MySQL is available at http://www.mysql.com/. +.\" end of man page diff --git a/debian/additions/myisamlog.1 b/debian/additions/myisamlog.1 new file mode 100644 index 00000000000..959d547df94 --- /dev/null +++ b/debian/additions/myisamlog.1 @@ -0,0 +1,16 @@ +.TH mysql 1 "17 March 2003" "MySQL 3.23" "MySQL database" +.SH NAME +myisamlog \- MySQL helper script. +.SH SYNOPSIS +myisamlog [options] +.SH DESCRIPTION +Function unknown. Mail to ch@debian.org. + +For more information start the program with '--help'. +.SH "SEE ALSO" +mysql (1), mysqld (1) +.SH AUTHOR +This manpage was written by Christian Hammers . + +MySQL is available at http://www.mysql.com/. +.\" end of man page diff --git a/debian/additions/myisampack.1 b/debian/additions/myisampack.1 new file mode 100644 index 00000000000..93168304a17 --- /dev/null +++ b/debian/additions/myisampack.1 @@ -0,0 +1,19 @@ +.TH mysql 1 "17 March 2003" "MySQL 3.23" "MySQL database" +.SH NAME +myisampack \- Compresses MySQL database files. +.SH SYNOPSIS +myisampack [options] +.SH DESCRIPTION +Pack a MyISAM-table to take much less space. +Keys are not updated, you must run myisamchk -rq on the datafile +afterwards to update the keys. +You should give the .MYI file as the filename argument. + +For more information start the program with '--help'. +.SH "SEE ALSO" +mysql (1), mysqld (1) +.SH AUTHOR +This manpage was written by Christian Hammers . + +MySQL is available at http://www.mysql.com/. +.\" end of man page diff --git a/debian/additions/mysql-server.lintian-overrides b/debian/additions/mysql-server.lintian-overrides new file mode 100644 index 00000000000..9d741cf16e9 --- /dev/null +++ b/debian/additions/mysql-server.lintian-overrides @@ -0,0 +1,2 @@ +W: mysql-dfsg source: maintainer-script-lacks-debhelper-token debian/mysql-server.postinst +W: mysql-server: possible-bashism-in-maintainer-script postinst:68 'p{("a".."z","A".."Z",0..9)[int(rand(62))]}' diff --git a/debian/additions/mysql_config.1 b/debian/additions/mysql_config.1 new file mode 100644 index 00000000000..88095e22b9e --- /dev/null +++ b/debian/additions/mysql_config.1 @@ -0,0 +1,17 @@ +.TH mysql 1 "17 March 2003" "MySQL 3.23" "MySQL database" +.SH NAME +mysqlconfig \- MySQL compile settings. +.SH SYNOPSIS +mysqlconfig [options] +.SH DESCRIPTION +This program is only useful for people who want to compile agains +libmysqlclient. + +For more information start the program with '--help'. +.SH "SEE ALSO" +mysql (1), mysqld (1) +.SH AUTHOR +This manpage was written by Christian Hammers . + +MySQL is available at http://www.mysql.com/. +.\" end of man page diff --git a/debian/additions/mysql_convert_table_format.1 b/debian/additions/mysql_convert_table_format.1 new file mode 100644 index 00000000000..3c23581df43 --- /dev/null +++ b/debian/additions/mysql_convert_table_format.1 @@ -0,0 +1,17 @@ +.TH mysql 1 "17 March 2003" "MySQL 3.23" "MySQL database" +.SH NAME +mysql_convert_table_format \- MySQL table converter. +.SH SYNOPSIS +mysql_convert_table_format [options] +.SH DESCRIPTION +Conversion of a MySQL tables to other table types. +If no tables has been specifed, all tables in the database will be converted. + +For more information start the program with '--help'. +.SH "SEE ALSO" +mysql (1), mysqld (1) +.SH AUTHOR +This manpage was written by Christian Hammers . + +MySQL is available at http://www.mysql.com/. +.\" end of man page diff --git a/debian/additions/mysql_find_rows.1 b/debian/additions/mysql_find_rows.1 new file mode 100644 index 00000000000..35a70b1f960 --- /dev/null +++ b/debian/additions/mysql_find_rows.1 @@ -0,0 +1,18 @@ +.TH mysql 1 "17 March 2003" "MySQL 3.23" "MySQL database" +.SH NAME +mysql_find_rows \- MySQL shell skript for searching in update logs. +.SH SYNOPSIS +mysql_find_rows [options] +.SH DESCRIPTION +Prints all SQL queries that matches a regexp or contains a 'use +database' or 'set ..' command to stdout. A SQL query may contain +newlines. This is useful to find things in a MySQL update log. + +For more information start the program with '--help'. +.SH "SEE ALSO" +mysql (1), mysqld (1) +.SH AUTHOR +This manpage was written by Christian Hammers . + +MySQL is available at http://www.mysql.com/. +.\" end of man page diff --git a/debian/additions/mysql_fix_extensions.1 b/debian/additions/mysql_fix_extensions.1 new file mode 100644 index 00000000000..3f0a028ca3f --- /dev/null +++ b/debian/additions/mysql_fix_extensions.1 @@ -0,0 +1,18 @@ +.TH mysql 1 "17 March 2003" "MySQL 3.23" "MySQL database" +.SH NAME +mysql_fix_extensions \- Corrects MySQL database file names. +.SH SYNOPSIS +mysql_fix_extensions +.SH DESCRIPTION +Makes .frm lowercase and .MYI/MYD/ISM/ISD uppercase +useful when datafiles are copied from windows. +Does not work with RAID, with InnoDB or BDB tables. + +For more information start the program with '--help'. +.SH "SEE ALSO" +mysql (1), mysqld (8) +.SH AUTHOR +This manpage was written by Christian Hammers . + +MySQL is available at http://www.mysql.com/. +.\" end of man page diff --git a/debian/additions/mysql_install_db.1 b/debian/additions/mysql_install_db.1 new file mode 100644 index 00000000000..11f1f2967a2 --- /dev/null +++ b/debian/additions/mysql_install_db.1 @@ -0,0 +1,16 @@ +.TH mysql 1 "17 March 2003" "MySQL 3.23" "MySQL database" +.SH NAME +mysql_install_db \- MySQL helper program. +.SH SYNOPSIS +mysql_install_db [options] +.SH DESCRIPTION +This program is normally not needed by any user. + +For more information start the program with '--help'. +.SH "SEE ALSO" +mysql (1), mysqld (1) +.SH AUTHOR +This manpage was written by Christian Hammers . + +MySQL is available at http://www.mysql.com/. +.\" end of man page diff --git a/debian/additions/mysql_secure_installation.1 b/debian/additions/mysql_secure_installation.1 new file mode 100644 index 00000000000..d65b7f5d09d --- /dev/null +++ b/debian/additions/mysql_secure_installation.1 @@ -0,0 +1,17 @@ +.TH mysql 1 "17 March 2003" "MySQL 3.23" "MySQL database" +.SH NAME +mysql_secure_installation \- Secures the MySQL access control lists. +.SH SYNOPSIS +mysql_secure_installation [options] +.SH DESCRIPTION +This interactive programm suggests changes like removing anonymous users that +are supposed to make your installation more secure. + +For more information start the program with '--help'. +.SH "SEE ALSO" +mysql (1), mysqld (8) +.SH AUTHOR +This manpage was written by Christian Hammers . + +MySQL is available at http://www.mysql.com/. +.\" end of man page diff --git a/debian/additions/mysql_setpermission.1 b/debian/additions/mysql_setpermission.1 new file mode 100644 index 00000000000..77167e0d58f --- /dev/null +++ b/debian/additions/mysql_setpermission.1 @@ -0,0 +1,23 @@ +.TH mysql 1 "17 March 2003" "MySQL 3.23" "MySQL database" +.SH NAME +mysql_setpermission \- Adds MySQL users or changes passwords. +.SH SYNOPSIS +mysql_setpermission [options] +.SH DESCRIPTION +The permission setter is a little program which can help you add users +or databases or change passwords in MySQL. Keep in mind that we don't +check permissions which already been set in MySQL. So if you can't +connect to MySQL using the permission you just added, take a look at +the permissions which have already been set in MySQL. + +The permission setter first reads your .my.cnf file in your Home +directory if it exists. + +For more information start the program with '--help'. +.SH "SEE ALSO" +mysql (1), mysqld (1) +.SH AUTHOR +This manpage was written by Christian Hammers . + +MySQL is available at http://www.mysql.com/. +.\" end of man page diff --git a/debian/additions/mysql_tableinfo.1 b/debian/additions/mysql_tableinfo.1 new file mode 100644 index 00000000000..1de4f5d5943 --- /dev/null +++ b/debian/additions/mysql_tableinfo.1 @@ -0,0 +1,322 @@ +.\" Automatically generated by Pod::Man v1.34, Pod::Parser v1.13 +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sh \" Subsection heading +.br +.if t .Sp +.ne 5 +.PP +\fB\\$1\fR +.PP +.. +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. | will give a +.\" real vertical bar. \*(C+ will give a nicer C++. Capital omega is used to +.\" do unbreakable dashes and therefore won't be available. \*(C` and \*(C' +.\" expand to `' in nroff, nothing in troff, for use with C<>. +.tr \(*W-|\(bv\*(Tr +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.if \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.\" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.hy 0 +.if n .na +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "MYSQL_TABLEINFO 1" +.TH MYSQL_TABLEINFO 1 "2003-04-05" "perl v5.8.0" "User Contributed Perl Documentation" +.SH "NAME" +mysql_tableinfo \- creates and populates information tables with +the output of SHOW DATABASES, SHOW TABLES (or SHOW TABLE STATUS), +SHOW COLUMNS and SHOW INDEX. +.PP +This is version 1.1. +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +.Vb 1 +\& mysql_tableinfo [OPTIONS] database_to_write [database_like_wild] [table_like_wild] +.Ve +.PP +.Vb 2 +\& Do not backquote (``) database_to_write, +\& and do not quote ('') database_like_wild or table_like_wild +.Ve +.PP +.Vb 1 +\& Examples: +.Ve +.PP +.Vb 1 +\& mysql_tableinfo info +.Ve +.PP +.Vb 1 +\& mysql_tableinfo info this_db +.Ve +.PP +.Vb 1 +\& mysql_tableinfo info %a% b% +.Ve +.PP +.Vb 1 +\& mysql_tableinfo info --clear-only +.Ve +.PP +.Vb 1 +\& mysql_tableinfo info --col --idx --table-status +.Ve +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +mysql_tableinfo asks a MySQL server information about its +databases, tables, table columns and index, and stores this +in tables called `db`, `tbl` (or `tbl_status`), `col`, `idx` +(with an optional prefix specified with \-\-prefix). +After that, you can query these information tables, for example +to build your admin scripts with \s-1SQL\s0 queries, like +.PP +\&\s-1SELECT\s0 \s-1CONCAT\s0(\*(L"\s-1CHECK\s0 \s-1TABLE\s0 \*(R",`database`,\*(L".\*(R",`table`,\*(L" \s-1EXTENDED\s0;\*(R") +\&\s-1FROM\s0 info.tbl \s-1WHERE\s0 ... ; +.PP +as people usually do with some other \s-1RDBMS\s0 +(note: to increase the speed of your queries on the info tables, +you may add some index on them). +.PP +The database_like_wild and table_like_wild instructs the program +to gather information only about databases and tables +whose names match these patterns. If the info +tables already exist, their rows matching the patterns are simply +deleted and replaced by the new ones. That is, +old rows not matching the patterns are not touched. +If the database_like_wild and table_like_wild arguments +are not specified on the command-line they default to \*(L"%\*(R". +.PP +The program : +.PP +\&\- does \s-1CREATE\s0 \s-1DATABASE\s0 \s-1IF\s0 \s-1NOT\s0 \s-1EXISTS\s0 database_to_write +where database_to_write is the database name specified on the command\-line. +.PP +\&\- does \s-1CREATE\s0 \s-1TABLE\s0 \s-1IF\s0 \s-1NOT\s0 \s-1EXISTS\s0 database_to_write.`db` +.PP +\&\- fills database_to_write.`db` with the output of +\&\s-1SHOW\s0 \s-1DATABASES\s0 \s-1LIKE\s0 database_like_wild +.PP +\&\- does \s-1CREATE\s0 \s-1TABLE\s0 \s-1IF\s0 \s-1NOT\s0 \s-1EXISTS\s0 database_to_write.`tbl` +(respectively database_to_write.`tbl_status` +if the \-\-tbl\-status option is on) +.PP +\&\- for every found database, +fills database_to_write.`tbl` (respectively database_to_write.`tbl_status`) +with the output of +\&\s-1SHOW\s0 \s-1TABLES\s0 \s-1FROM\s0 found_db \s-1LIKE\s0 table_like_wild +(respectively \s-1SHOW\s0 \s-1TABLE\s0 \s-1STATUS\s0 \s-1FROM\s0 found_db \s-1LIKE\s0 table_like_wild) +.PP +\&\- if the \-\-col option is on, + * does \s-1CREATE\s0 \s-1TABLE\s0 \s-1IF\s0 \s-1NOT\s0 \s-1EXISTS\s0 database_to_write.`col` + * for every found table, + fills database_to_write.`col` with the output of + \s-1SHOW\s0 \s-1COLUMNS\s0 \s-1FROM\s0 found_tbl \s-1FROM\s0 found_db +.PP +\&\- if the \-\-idx option is on, + * does \s-1CREATE\s0 \s-1TABLE\s0 \s-1IF\s0 \s-1NOT\s0 \s-1EXISTS\s0 database_to_write.`idx` + * for every found table, + fills database_to_write.`idx` with the output of + \s-1SHOW\s0 \s-1INDEX\s0 \s-1FROM\s0 found_tbl \s-1FROM\s0 found_db +.PP +Some options may modify this general scheme (see below). +.PP +As mentioned, the contents of the info tables are the output of +\&\s-1SHOW\s0 commands. In fact the contents are slightly more complete : +.PP +\&\- the `tbl` (or `tbl_status`) info table + has an extra column which contains the database name, +.PP +\&\- the `col` info table + has an extra column which contains the table name, + and an extra column which contains, for each described column, + the number of this column in the table owning it (this extra column + is called `Seq_in_table`). `Seq_in_table` makes it possible for you + to retrieve your columns in sorted order, when you are querying + the `col` table. +.PP +\&\- the `index` info table + has an extra column which contains the database name. +.PP +Caution: info tables contain certain columns (e.g. +Database, Table, Null...) whose names, as they are MySQL reserved words, +need to be backquoted (`...`) when used in \s-1SQL\s0 statements. +.PP +Caution: as information fetching and info tables filling happen at the +same time, info tables may contain inaccurate information about +themselves. +.SH "OPTIONS" +.IX Header "OPTIONS" +.IP "\-\-clear" 4 +.IX Item "--clear" +Does \s-1DROP\s0 \s-1TABLE\s0 on the info tables (only those that the program is +going to fill, for example if you do not use \-\-col it won't drop +the `col` table) and processes normally. Does not drop database_to_write. +.IP "\-\-clear\-only" 4 +.IX Item "--clear-only" +Same as \-\-clear but exits after the DROPs. +.IP "\-\-col" 4 +.IX Item "--col" +Adds columns information (into table `col`). +.IP "\-\-idx" 4 +.IX Item "--idx" +Adds index information (into table `idx`). +.IP "\-\-prefix prefix" 4 +.IX Item "--prefix prefix" +The info tables are named from the concatenation of prefix and, +respectively, db, tbl (or tbl_status), col, idx. Do not quote ('') +or backquote (``) prefix. +.IP "\-q, \-\-quiet" 4 +.IX Item "-q, --quiet" +Does not warn you about what the script is going to do (\s-1DROP\s0 \s-1TABLE\s0 etc) +and does not ask for a confirmation before starting. +.IP "\-\-tbl\-status" 4 +.IX Item "--tbl-status" +Instead of using \s-1SHOW\s0 \s-1TABLES\s0, uses \s-1SHOW\s0 \s-1TABLE\s0 \s-1STATUS\s0 +(much more complete information, but slower). +.IP "\-\-help" 4 +.IX Item "--help" +Display helpscreen and exit +.IP "\-u, \-\-user=#" 4 +.IX Item "-u, --user=#" +user for database login if not current user. Give a user +who has sufficient privileges (\s-1CREATE\s0, ...). +.IP "\-p, \-\-password=# (INSECURE)" 4 +.IX Item "-p, --password=# (INSECURE)" +password to use when connecting to server. +WARNING: Providing a password on command line is insecure as it is visible through /proc to anyone for a short time. +.IP "\-h, \-\-host=#" 4 +.IX Item "-h, --host=#" +host to connect to +.IP "\-P, \-\-port=#" 4 +.IX Item "-P, --port=#" +port to use when connecting to server +.IP "\-S, \-\-socket=#" 4 +.IX Item "-S, --socket=#" +\&\s-1UNIX\s0 domain socket to use when connecting to server +.SH "WARRANTY" +.IX Header "WARRANTY" +This software is free and comes without warranty of any kind. You +should never trust backup software without studying the code yourself. +Study the code inside this script and only rely on it if \fIyou\fR believe +that it does the right thing for you. +.Sp +Patches adding bug fixes, documentation and new features are welcome. +.SH "TO DO" +.IX Header "TO DO" +Use extended inserts to be faster (for servers with many databases +or tables). But to do that, must care about net\-buffer\-length. +.SH "AUTHOR" +.IX Header "AUTHOR" +2002\-06\-18 Guilhem Bichot (guilhem.bichot@mines\-paris.org) +.Sp +And all the authors of mysqlhotcopy, which served as a model for +the structure of the program. diff --git a/debian/additions/mysql_waitpid.1 b/debian/additions/mysql_waitpid.1 new file mode 100644 index 00000000000..f6877865ba8 --- /dev/null +++ b/debian/additions/mysql_waitpid.1 @@ -0,0 +1,20 @@ +.TH mysql 1 "17 March 2003" "MySQL 3.23" "MySQL database" +.SH NAME +mysql_waitpid \- Waits a specified amount of seconds for a PID to terminate. +.SH SYNOPSIS +mysql_waitpid [options] +.SH DESCRIPTION +Description: Waits for a program, which program id is #pid, to +terminate within #time seconds. If the program terminates within +this time, or if the #pid no longer exists, value 0 is returned. +Otherwise 1 is returned. Both #pid and #time must be positive +integer arguments. + +See mysql_waitpid for options. +.SH "SEE ALSO" +mysql (1), mysqld (1) +.SH AUTHOR +This manpage was written by Christian Hammers . + +MySQL is available at http://www.mysql.com/. +.\" end of man page diff --git a/debian/additions/mysqlbinlog.1 b/debian/additions/mysqlbinlog.1 new file mode 100644 index 00000000000..fcdf2a083f4 --- /dev/null +++ b/debian/additions/mysqlbinlog.1 @@ -0,0 +1,17 @@ +.TH mysql 1 "17 March 2003" "MySQL 3.23" "MySQL database" +.SH NAME +mysqlbinlog \- Dumps MySQL binary logs. +.SH SYNOPSIS +mysqlbinlog [options] +.SH DESCRIPTION +Dumps a MySQL binary log in a format usable for viewing or for pipeing to +the mysql command line client + +For more information start the program with '--help'. +.SH "SEE ALSO" +mysql (1), mysqld (1) +.SH AUTHOR +This manpage was written by Christian Hammers . + +MySQL is available at http://www.mysql.com/. +.\" end of man page diff --git a/debian/additions/mysqlbug.1 b/debian/additions/mysqlbug.1 new file mode 100644 index 00000000000..133330dd897 --- /dev/null +++ b/debian/additions/mysqlbug.1 @@ -0,0 +1,14 @@ +.TH mysql 1 "17 March 2003" "MySQL 3.23" "MySQL database" +.SH NAME +mysqlbug \- MySQL bug reporting tool. +.SH SYNOPSIS +mysqlbug [options] +.SH DESCRIPTION +Interactive bug reporting tool. Use reportbug on Debian systems. +.SH "SEE ALSO" +mysql (1), mysqld (1) +.SH AUTHOR +This manpage was written by Christian Hammers . + +MySQL is available at http://www.mysql.com/. +.\" end of man page diff --git a/debian/additions/mysqlcheck.1 b/debian/additions/mysqlcheck.1 new file mode 100644 index 00000000000..b36ba2d1eb1 --- /dev/null +++ b/debian/additions/mysqlcheck.1 @@ -0,0 +1,28 @@ +.TH mysql 1 "17 March 2003" "MySQL 3.23" "MySQL database" +.SH NAME +mysqlcheck \- MySQL program for repairing, checking and optimizing tables. +.SH SYNOPSIS +mysqlcheck | mysqlanalyze | mysqloptimize [options] +.SH DESCRIPTION +This program can be used to CHECK (-c,-m,-C), REPAIR (-r), ANALYZE (-a) +or OPTIMIZE (-o) tables. Some of the options (like -e or -q) can be +used same time. It works on MyISAM and in some cases on BDB tables. +Please consult the MySQL manual for latest information about the +above. The options -c,-r,-a and -o are exclusive to each other, which +means that the last option will be used, if several was specified. + +The option -c will be used by default, if none was specified. You +can change the default behavior by making a symbolic link, or +copying this file somewhere with another name, the alternatives are: +mysqlrepair: The default option will be -r +mysqlanalyze: The default option will be -a +mysqloptimize: The default option will be -o + +For more information start the program with '--help'. +.SH "SEE ALSO" +mysql (1), mysqld (8) +.SH AUTHOR +This manpage was written by Christian Hammers . + +MySQL is available at http://www.mysql.com/. +.\" end of man page diff --git a/debian/additions/mysqld_safe_syslog.cnf b/debian/additions/mysqld_safe_syslog.cnf new file mode 100644 index 00000000000..3b0445d6bd8 --- /dev/null +++ b/debian/additions/mysqld_safe_syslog.cnf @@ -0,0 +1,2 @@ +[mysqld_safe] +syslog diff --git a/debian/additions/mysqldumpslow.1 b/debian/additions/mysqldumpslow.1 new file mode 100644 index 00000000000..0431ef04cbb --- /dev/null +++ b/debian/additions/mysqldumpslow.1 @@ -0,0 +1,50 @@ +.TH mysql 1 "17 March 2003" "MySQL 3.23" "MySQL database" +.SH NAME +mysqldumpslow \- Parse and summarize the MySQL slow query log. +.SH SYNOPSIS +mysqldumpslow [options] +.SH DESCRIPTION +This program parses and summarizes a 'slow query log'. + +.TP +\fB\-v\fR +verbose +.TP +\fB\-d\fR +debug +.TP +\fB\-s=WORD\fR +what to sort by (t, at, l, al, r, ar etc) +.TP +\fB\-r\fR +reverse the sort order (largest last instead of first) +.TP +\fB\-t=NUMBER\fR +just show the top n queries +.TP +\fB\-a\fR +don't abstract all numbers to N and strings to 'S' +.TP +\fB\-n=NUMBER\fR +abstract numbers with at least n digits within names +.TP +\fB\-g=WORD\fR +grep: only consider stmts that include this string +.TP +\fB\-h=WORD\fR +hostname of db server for *-slow.log filename (can be wildcard) +.TP +\fB\-i=WORD\fR +name of server instance (if using mysql.server startup script) +.TP +\fB\-l\fR +don't subtract lock time from total time + +.SH "SEE ALSO" +mysql (1), mysqld (1) +.SH AUTHOR +This manpage was written by Christian Hammers based on +the commends in the code. + +MySQL is available at http://www.mysql.com/. +.\" end of man page diff --git a/debian/additions/mysqlimport.1 b/debian/additions/mysqlimport.1 new file mode 100644 index 00000000000..9007307a328 --- /dev/null +++ b/debian/additions/mysqlimport.1 @@ -0,0 +1,20 @@ +.TH mysql 1 "17 March 2003" "MySQL 3.23" "MySQL database" +.SH NAME +mysqlimport \- Imports text files with MySQL database queries. +.SH SYNOPSIS +mysqlimport [options] +.SH DESCRIPTION +Loads tables from text files in various formats. The base name of the +text file must be the name of the table that should be used. +If one uses sockets to connect to the MySQL server, the server will open and +read the text file directly. In other cases the client will open the text +file. The SQL command 'LOAD DATA INFILE' is used to import the rows. + +For more information start the program with '--help'. +.SH "SEE ALSO" +mysql (1), mysqld (1) +.SH AUTHOR +This manpage was written by Christian Hammers . + +MySQL is available at http://www.mysql.com/. +.\" end of man page diff --git a/debian/additions/mysqlreport b/debian/additions/mysqlreport new file mode 100755 index 00000000000..402a5be835d --- /dev/null +++ b/debian/additions/mysqlreport @@ -0,0 +1,1298 @@ +#!/usr/bin/perl -w + +# mysqlreport v3.5 Apr 16 2008 +# http://hackmysql.com/mysqlreport + +# mysqlreport makes an easy-to-read report of important MySQL status values. +# Copyright 2006-2008 Daniel Nichter +# +# 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 Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# The GNU General Public License is available at: +# http://www.gnu.org/copyleft/gpl.html + +use strict; +use File::Temp qw(tempfile); +use DBI; +use Getopt::Long; +eval { require Term::ReadKey; }; +my $RK = ($@ ? 0 : 1); + +sub have_op; + +my $WIN = ($^O eq 'MSWin32' ? 1 : 0); +my %op; +my %mycnf; # ~/.my.cnf +my ($tmpfile_fh, $tmpfile); +my ($stat_name, $stat_val, $stat_label); +my $MySQL_version; +my (%stats, %vars); # SHOW STATUS, SHOW VARIABLES +my (%DMS_vals, %Com_vals, %ib_vals); +my ($dbh, $query); +my ($questions, $key_read_ratio, $key_write_ratio, $dms, $slow_query_t); +my ($key_cache_block_size, $key_buffer_used, $key_buffer_usage); +my ($qc_mem_used, $qc_hi_r, $qc_ip_r); # Query Cache +my $have_innodb_vals; +my ($ib_bp_used, $ib_bp_total, $ib_bp_read_ratio); +my ($relative_live, $relative_infiles); +my $real_uptime; +my (%stats_present, %stats_past); # For relative reports + +GetOptions ( + \%op, + "user=s", + "password:s", + "host=s", + "port=s", + "socket=s", + "no-mycnf", + "infile|in=s", + "outfile=s", + "flush-status", + "email=s", + "r|relative:i", + "c|report-count=i", + "detach", + "help|?", + "debug" +); + +show_help_and_exit() if $op{'help'}; + +get_user_mycnf() unless $op{'no-mycnf'}; + +# Command line options override ~/.my.cnf +$mycnf{'host'} = $op{'host'} if have_op 'host'; +$mycnf{'port'} = $op{'port'} if have_op 'port'; +$mycnf{'socket'} = $op{'socket'} if have_op 'socket'; +$mycnf{'user'} = $op{'user'} if have_op 'user'; + +$mycnf{'user'} ||= $ENV{'USER'}; + +if(exists $op{'password'}) +{ + if($op{'password'} eq '') # Prompt for password + { + Term::ReadKey::ReadMode(2) if $RK; + print "Password for database user $mycnf{'user'}: "; + chomp($mycnf{'pass'} = ); + Term::ReadKey::ReadMode(0), print "\n" if $RK; + } + else { $mycnf{'pass'} = $op{'password'}; } # Use password given on command line +} + +$op{'com'} ||= 3; +$op{'c'} ||= 1; # Used in collect_reports() if --r given integer value + +$relative_live = 0; +$relative_infiles = 0; + +if(defined $op{'r'}) +{ + if($op{r}) { $relative_live = 1; } # if -r was given an integer value + else { $relative_infiles = 1; } +} + +# The report is written to a tmp file first. +# Later it will be moved to $op{'outfile'} or emailed $op{'email'} if needed. +($tmpfile_fh, $tmpfile) = tempfile() or die "Cannot open temporary file for writing: $!\n"; + +if($op{'detach'}) +{ + $SIG{'TERM'} = 'sig_handler'; + + if(fork()) + { + print "mysqlreport has forked and detached.\n"; + print "While running detached, mysqlreport writes reports to '$tmpfile'.\n"; + + exit; + } + + open(STDIN, " $tmpfile") or die "Cannot dup STDOUT: $!\n"; + open(STDERR, "> $tmpfile") or die "Cannot dup STDERR: $!\n"; +} + +select $tmpfile_fh; +$| = 1 if ($op{'detach'} || $relative_live); + +print "tmp file: $tmpfile\n" if $op{debug}; + +# Connect to MySQL +if(!$op{'infile'} && !$relative_infiles) +{ + connect_to_MySQL(); +} + +$have_innodb_vals = 1; # This might be set to 0 later in get_MySQL_version() + +if(defined $op{'r'}) +{ + if($relative_live) + { + print STDERR "mysqlreport is writing relative reports to '$tmpfile'.\n" unless $op{'detach'}; + get_MySQL_version(); + collect_reports(); + } + + if($relative_infiles) { read_relative_infiles(); } +} +else +{ + if(!$op{'infile'}) + { + get_MySQL_version(); + get_vals(); + get_vars(); + } + else + { + read_infile($op{'infile'}); + } + + get_Com_values(); + + set_myisam_vals(); + set_ib_vals() if $have_innodb_vals; + + write_report(); +} + +exit_tasks_and_cleanup(); + +exit; + +# +# Subroutines +# +sub show_help_and_exit +{ + print <<"HELP"; +mysqlreport v3.5 Apr 16 2008 +mysqlreport makes an easy-to-read report of important MySQL status values. + +Command line options (abbreviations work): + --user USER Connect to MySQL as USER + --password PASS Use PASS or prompt for MySQL user's password + --host ADDRESS Connect to MySQL at ADDRESS + --port PORT Connect to MySQL at PORT + --socket SOCKET Connect to MySQL at SOCKET + --no-mycnf Don't read ~/.my.cnf + --infile FILE Read status values from FILE instead of MySQL + --outfile FILE Write report to FILE + --email ADDRESS Email report to ADDRESS (doesn't work on Windows) + --flush-status Issue FLUSH STATUS; after getting current values + --relative X Generate relative reports. If X is an integer, + reports are live from the MySQL server X seconds apart. + If X is a list of infiles (file1 file2 etc.), + reports are generated from the infiles in the order + that they are given. + --report-count N Collect N number of live relative reports (default 1) + --detach Fork and detach from terminal (run in background) + --help Prints this + --debug Print debugging information + +Visit http://hackmysql.com/mysqlreport for more information. +HELP + + exit; +} + +sub get_user_mycnf +{ + print "get_user_mycnf\n" if $op{debug}; + + return if $WIN; + open MYCNF, "$ENV{HOME}/.my.cnf" or return; + while() + { + if(/^(.+?)\s*=\s*"?(.+?)"?\s*$/) + { + $mycnf{$1} = $2; + print "get_user_mycnf: read '$1 = $2'\n" if $op{debug}; + } + } + $mycnf{'pass'} ||= $mycnf{'password'} if exists $mycnf{'password'}; + close MYCNF; +} + +sub connect_to_MySQL +{ + print "connect_to_MySQL\n" if $op{debug}; + + my $dsn; + + if($mycnf{'socket'} && -S $mycnf{'socket'}) + { + $dsn = "DBI:mysql:mysql_socket=$mycnf{socket}"; + } + elsif($mycnf{'host'}) + { + $dsn = "DBI:mysql:host=$mycnf{host}" . ($mycnf{port} ? ";port=$mycnf{port}" : ""); + } + else + { + $dsn = "DBI:mysql:host=localhost"; + } + + print "connect_to_MySQL: DBI DSN: $dsn\n" if $op{debug}; + + $dbh = DBI->connect($dsn, $mycnf{'user'}, $mycnf{'pass'}) or die; +} + +sub collect_reports +{ + print "collect_reports\n" if $op{debug}; + + my $i; + + get_vals(); + get_vars(); + + get_Com_values(); + + %stats_past = %stats; + + set_myisam_vals(); + set_ib_vals() if $have_innodb_vals; + + print "#\n# Beginning report, 0 0:0:0\n#\n"; + + write_report(); + + for($i = 0; $i < $op{'c'}; $i++) + { + $dbh->disconnect(); + + sleep($op{'r'}); + + connect_to_MySQL(); + + print "\n#\n# Interval report " , $i + 1 , ", +", sec_to_dhms(($i + 1) * $op{'r'}), "\n#\n"; + + get_vals(); + + write_relative_report(); + } +} + +sub read_relative_infiles +{ + print "read_relative_infiles\n" if $op{debug}; + + my $slurp; # Used to check infiles for multiple sets of status values + my $n_stats; # Number of multiple sets of status values in an infile + my $infile; + my $report_n; # Report number + + $report_n = 1; + + foreach $infile (@ARGV) + { + # Read all of infile into $slurp + open INFILE, "< $infile" or warn and next; + $slurp = do { local $/; }; + close INFILE; + + $n_stats = 0; + + # Count number of status value sets + $n_stats++ while $slurp =~ /Aborted_clients/g; + + print "read_relative_infiles: found $n_stats sets of status values in file '$infile'\n" + if $op{debug}; + + if($n_stats == 1) + { + read_infile($infile); + relative_infile_report($report_n++); + } + + if($n_stats > 1) + { + my @tmpfile_fh; + my @tmpfile_name; + my $i; + my $stat_n; # Status value set number + + # Create a tmp file for each set of status values + for($i = 0; $i < $n_stats; $i++) + { + my ($fh, $name) = tempfile() + or die "read_relative_infiles: cannot open temporary file for writing: $!\n"; + + push(@tmpfile_fh, $fh); + push(@tmpfile_name, $name); + + print "read_relative_infiles: created tmp file '$name' for set $i\n" if $op{debug}; + } + + $i = 0; + $stat_n = 0; + + select $tmpfile_fh[$i]; + + # Read infile again and copy each set of status values to seperate tmp files + open INFILE, "< $infile" or warn and next; + while() + { + next if /^\+/; + next if /^$/; + + # The infile must begin with the system variable values. + # Therefore, the first occurance of Aborted_clients indicates the beginning + # of the first set of status values if no sets have occured yet ($stat_n == 0). + # In this case, the following status values are printed to the current fh, + # along with the system variable values read thus far, until Aborted_clients + # occurs again. Then begins the second and subsequent sets of status values. + + if(/Aborted_clients/) + { + print and next if $stat_n++ == 0; + select $tmpfile_fh[++$i]; + } + + print; + } + close INFILE; + + # Re-select the main tmp file into which the reports are being written. + select $tmpfile_fh; + + for($i = 0; $i < $n_stats; $i++) + { + close $tmpfile_fh[$i]; + + print "read_relative_infiles: reading set $i tmp file '$tmpfile_name[$i]'\n" + if $op{debug}; + + read_infile($tmpfile_name[$i]); + relative_infile_report($report_n++); + + if($WIN) { `del $tmpfile_name[$i]`; } + else { `rm -f $tmpfile_name[$i]`; } + + print "read_relative_infiles: deleted set $i tmp file '$tmpfile_name[$i]'\n" + if $op{debug}; + } + + } # if($n_stats > 1) + } # foreach $infile (@files) +} + +sub relative_infile_report +{ + print "relative_infile_report\n" if $op{debug}; + + my $report_n = shift; + + if($report_n == 1) + { + get_Com_values(); + + %stats_past = %stats; + + set_myisam_vals(); + set_ib_vals() if $have_innodb_vals; + + print "#\n# Beginning report, 0 0:0:0\n#\n"; + + write_report(); + } + else + { + print "\n#\n# Interval report ", $report_n - 1, ", +", + sec_to_dhms($stats{Uptime} - $stats_past{Uptime}), + "\n#\n"; + + write_relative_report(); + } +} + +sub get_vals +{ + print "get_vals\n" if $op{debug}; + + my @row; + + # Get status values + if($MySQL_version >= 50002) + { + $query = $dbh->prepare("SHOW GLOBAL STATUS;"); + } + else + { + $query = $dbh->prepare("SHOW STATUS;"); + } + $query->execute(); + while(@row = $query->fetchrow_array()) { $stats{$row[0]} = $row[1]; } + + $real_uptime = $stats{'Uptime'}; +} + +sub get_vars +{ + print "get_vars\n" if $op{debug}; + + my @row; + + # Get server system variables + $query = $dbh->prepare("SHOW VARIABLES;"); + $query->execute(); + while(@row = $query->fetchrow_array()) { $vars{$row[0]} = $row[1]; } + + # table_cache was renamed to table_open_cache in MySQL 5.1.3 + if($MySQL_version >= 50103) + { + $vars{'table_cache'} = $vars{'table_open_cache'}; + } +} + +sub read_infile +{ + print "read_infile\n" if $op{debug}; + + my $infile = shift; + + # Default required system variable values if not set in INFILE. + # As of mysqlreport v3.5 the direct output from SHOW VARIABLES; + # can be put into INFILE instead. See http://hackmysql.com/mysqlreportdoc + # for details. + $vars{'version'} = "0.0.0" if !exists $vars{'version'}; + $vars{'table_cache'} = 64 if !exists $vars{'table_cache'}; + $vars{'max_connections'} = 100 if !exists $vars{'max_connections'}; + $vars{'key_buffer_size'} = 8388600 if !exists $vars{'key_buffer_size'}; # 8M + $vars{'thread_cache_size'} = 0 if !exists $vars{'thread_cache_size'}; + $vars{'tmp_table_size'} = 0 if !exists $vars{'tmp_table_size'}; + $vars{'long_query_time'} = '?' if !exists $vars{'long_query_time'}; + $vars{'log_slow_queries'} = '?' if !exists $vars{'log_slow_queries'}; + + # One should also add: + # key_cache_block_size + # query_cache_size + # to INFILE if needed. + + open INFILE, "< $infile" or die "Cannot open INFILE '$infile': $!\n"; + + while() + { + last if !defined $_; + + next if /^\+/; # skip divider lines + next if /^$/; # skip blank lines + + next until /(Aborted_clients|back_log|=)/; + + if($1 eq 'Aborted_clients') # status values + { + print "read_infile: start stats\n" if $op{debug}; + + while($_) + { + chomp; + if(/([A-Za-z_]+)[\s\t|]+(\d+)/) + { + $stats{$1} = $2; + print "read_infile: save $1 = $2\n" if $op{debug}; + } + else { print "read_infile: ignore '$_'\n" if $op{debug}; } + + last if $1 eq 'Uptime'; # exit while() if end of status values + $_ = ; # otherwise, read next line of status values + } + } + elsif($1 eq 'back_log') # system variable values + { + print "read_infile: start vars\n" if $op{debug}; + + while($_) + { + chomp; + if(/([A-Za-z_]+)[\s\t|]+([\w\.\-]+)/) # This will exclude some vars + { # like pid_file which we don't need + $vars{$1} = $2; + print "read_infile: save $1 = $2\n" if $op{debug}; + } + else { print "read_infile: ignore '$_'\n" if $op{debug}; } + + last if $1 eq 'wait_timeout'; # exit while() if end of vars + $_ = ; # otherwise, read next line of vars + } + } + elsif($1 eq '=') # old style, manually added system variable values + { + print "read_infile: start old vars\n" if $op{debug}; + + while($_ && $_ =~ /=/) + { + chomp; + if(/^\s*(\w+)\s*=\s*([0-9.]+)(M*)\s*$/) # e.g.: key_buffer_size = 128M + { + $vars{$1} = ($3 ? $2 * 1024 * 1024 : $2); + print "read_infile: read '$_' as $1 = $vars{$1}\n" if $op{debug}; + } + else { print "read_infile: ignore '$_'\n" if $op{debug}; } + + $_ = ; # otherwise, read next line of old vars + } + + redo; + } + else + { + print "read_infile: unrecognized line: '$_'\n" if $op{debug}; + } + } + + close INFILE; + + $real_uptime = $stats{'Uptime'}; + + $vars{'table_cache'} = $vars{'table_open_cache'} if exists $vars{'table_open_cache'}; + + get_MySQL_version(); +} + +sub get_MySQL_version +{ + print "get_MySQL_version\n" if $op{debug}; + + return if $MySQL_version; + + my ($major, $minor, $patch); + + if($op{'infile'} || $relative_infiles) + { + ($major, $minor, $patch) = ($vars{'version'} =~ /(\d{1,2})\.(\d{1,2})\.(\d{1,2})/); + } + else + { + my @row; + + $query = $dbh->prepare("SHOW VARIABLES LIKE 'version';"); + $query->execute(); + @row = $query->fetchrow_array(); + ($major, $minor, $patch) = ($row[1] =~ /(\d{1,2})\.(\d{1,2})\.(\d{1,2})/); + } + + $MySQL_version = sprintf("%d%02d%02d", $major, $minor, $patch); + + # Innodb_ status values were added in 5.0.2 + if($MySQL_version < 50002) + { + $have_innodb_vals = 0; + print "get_MySQL_version: no InnoDB reports because MySQL version is older than 5.0.2\n" if $op{debug}; + } +} + +sub set_myisam_vals +{ + print "set_myisam_vals\n" if $op{debug}; + + $questions = $stats{'Questions'}; + + $key_read_ratio = sprintf "%.2f", + ($stats{'Key_read_requests'} ? + 100 - ($stats{'Key_reads'} / $stats{'Key_read_requests'}) * 100 : + 0); + + $key_write_ratio = sprintf "%.2f", + ($stats{'Key_write_requests'} ? + 100 - ($stats{'Key_writes'} / $stats{'Key_write_requests'}) * 100 : + 0); + + $key_cache_block_size = (defined $vars{'key_cache_block_size'} ? + $vars{'key_cache_block_size'} : + 1024); + + $key_buffer_used = $stats{'Key_blocks_used'} * $key_cache_block_size; + + if(defined $stats{'Key_blocks_unused'}) # MySQL 4.1.2+ + { + $key_buffer_usage = $vars{'key_buffer_size'} - + ($stats{'Key_blocks_unused'} * $key_cache_block_size); + } + else { $key_buffer_usage = -1; } + + # Data Manipulation Statements: http://dev.mysql.com/doc/refman/5.0/en/data-manipulation.html + %DMS_vals = + ( + SELECT => $stats{'Com_select'}, + INSERT => $stats{'Com_insert'} + $stats{'Com_insert_select'}, + REPLACE => $stats{'Com_replace'} + $stats{'Com_replace_select'}, + UPDATE => $stats{'Com_update'} + + (exists $stats{'Com_update_multi'} ? $stats{'Com_update_multi'} : 0), + DELETE => $stats{'Com_delete'} + + (exists $stats{'Com_delete_multi'} ? $stats{'Com_delete_multi'} : 0) + ); + + $dms = $DMS_vals{SELECT} + $DMS_vals{INSERT} + $DMS_vals{REPLACE} + $DMS_vals{UPDATE} + $DMS_vals{DELETE}; + + $slow_query_t = format_u_time($vars{long_query_time}); + +} + +sub set_ib_vals +{ + print "set_ib_vals\n" if $op{debug}; + + $ib_bp_used = ($stats{'Innodb_buffer_pool_pages_total'} - + $stats{'Innodb_buffer_pool_pages_free'}) * + $stats{'Innodb_page_size'}; + + $ib_bp_total = $stats{'Innodb_buffer_pool_pages_total'} * $stats{'Innodb_page_size'}; + + $ib_bp_read_ratio = sprintf "%.2f", + ($stats{'Innodb_buffer_pool_read_requests'} ? + 100 - ($stats{'Innodb_buffer_pool_reads'} / + $stats{'Innodb_buffer_pool_read_requests'}) * 100 : + 0); +} + +sub write_relative_report +{ + print "write_relative_report\n" if $op{debug}; + + %stats_present = %stats; + + for(keys %stats) + { + if($stats_past{$_} =~ /\d+/) + { + if($stats_present{$_} >= $stats_past{$_}) # Avoid negative values + { + $stats{$_} = $stats_present{$_} - $stats_past{$_}; + } + } + } + + # These values are either "at present" or "high water marks". + # Therefore, it is more logical to not relativize these values. + # Doing otherwise causes strange and misleading values. + $stats{'Key_blocks_used'} = $stats_present{'Key_blocks_used'}; + $stats{'Open_tables'} = $stats_present{'Open_tables'}; + $stats{'Max_used_connections'} = $stats_present{'Max_used_connections'}; + $stats{'Threads_running'} = $stats_present{'Threads_running'}; + $stats{'Threads_connected'} = $stats_present{'Threads_connected'}; + $stats{'Threads_cached'} = $stats_present{'Threads_cached'}; + $stats{'Qcache_free_blocks'} = $stats_present{'Qcache_free_blocks'}; + $stats{'Qcache_total_blocks'} = $stats_present{'Qcache_total_blocks'}; + $stats{'Qcache_free_memory'} = $stats_present{'Qcache_free_memory'}; + if($have_innodb_vals) + { + $stats{'Innodb_page_size'} = $stats_present{'Innodb_page_size'}; + $stats{'Innodb_buffer_pool_pages_data'} = $stats_present{'Innodb_buffer_pool_pages_data'}; + $stats{'Innodb_buffer_pool_pages_dirty'} = $stats_present{'Innodb_buffer_pool_pages_dirty'}; + $stats{'Innodb_buffer_pool_pages_free'} = $stats_present{'Innodb_buffer_pool_pages_free'}; + $stats{'Innodb_buffer_pool_pages_latched'} = $stats_present{'Innodb_buffer_pool_pages_latched'}; + $stats{'Innodb_buffer_pool_pages_misc'} = $stats_present{'Innodb_buffer_pool_pages_misc'}; + $stats{'Innodb_buffer_pool_pages_total'} = $stats_present{'Innodb_buffer_pool_pages_total'}; + $stats{'Innodb_data_pending_fsyncs'} = $stats_present{'Innodb_data_pending_fsyncs'}; + $stats{'Innodb_data_pending_reads'} = $stats_present{'Innodb_data_pending_reads'}; + $stats{'Innodb_data_pending_writes'} = $stats_present{'Innodb_data_pending_writes'}; + + # Innodb_row_lock_ values were added in MySQL 5.0.3 + if($MySQL_version >= 50003) + { + $stats{'Innodb_row_lock_current_waits'} = $stats_present{'Innodb_row_lock_current_waits'}; + $stats{'Innodb_row_lock_time_avg'} = $stats_present{'Innodb_row_lock_time_avg'}; + $stats{'Innodb_row_lock_time_max'} = $stats_present{'Innodb_row_lock_time_max'}; + } + } + + get_Com_values(); + + %stats_past = %stats_present; + + set_myisam_vals(); + set_ib_vals() if $have_innodb_vals; + + write_report(); +} + +sub write_report +{ + print "write_report\n" if $op{debug}; + + $~ = 'MYSQL_TIME', write; + $~ = 'KEY_BUFF_MAX', write; + if($key_buffer_usage != -1) { $~ = 'KEY_BUFF_USAGE', write } + $~ = 'KEY_RATIOS', write; + write_DTQ(); + $~ = 'SLOW_DMS', write; + write_DMS(); + write_Com(); + $~ = 'SAS', write; + write_qcache(); + $~ = 'REPORT_END', write; + $~ = 'TAB', write; + + write_InnoDB() if $have_innodb_vals; +} + +sub sec_to_dhms # Seconds to days hours:minutes:seconds +{ + my $s = shift; + my ($d, $h, $m) = (0, 0, 0); + + return '0 0:0:0' if $s <= 0; + + if($s >= 86400) + { + $d = int $s / 86400; + $s -= $d * 86400; + } + + if($s >= 3600) + { + $h = int $s / 3600; + $s -= $h * 3600; + } + + $m = int $s / 60; + $s -= $m * 60; + + return "$d $h:$m:$s"; +} + +sub make_short +{ + my ($number, $kb, $d) = @_; + my $n = 0; + my $short; + + $d ||= 2; + + if($kb) { while ($number > 1023) { $number /= 1024; $n++; }; } + else { while ($number > 999) { $number /= 1000; $n++; }; } + + $short = sprintf "%.${d}f%s", $number, ('','k','M','G','T')[$n]; + if($short =~ /^(.+)\.(00)$/) { return $1; } # 12.00 -> 12 but not 12.00k -> 12k + + return $short; +} + +# What began as a simple but great idea has become the new standard: +# long_query_time in microseconds. For MySQL 5.1.21+ and 6.0.4+ this +# is now standard. For 4.1 and 5.0 patches, the architects of this +# idea provide: http://www.mysqlperformanceblog.com/mysql-patches/ +# Relevant notes in MySQL manual: +# http://dev.mysql.com/doc/refman/5.1/en/slow-query-log.html +# http://dev.mysql.com/doc/refman/6.0/en/slow-query-log.html +# +# The format_u_time sub simply beautifies long_query_time. + +sub format_u_time # format microsecond () time value +{ + # 0.000000 - 0.000999 = 0 - 999 + # 0.001000 - 0.999999 = 1 ms - 999.999 ms + # 1.000000 - n.nnnnnn = 1 s - n.nnnnn s + + my $t = shift; + my $f; # formatted time + my $u = chr(($WIN ? 230 : 181)); + + $t = 0 if $t < 0; + + if($t > 0 && $t <= 0.000999) + { + $f = ($t * 1000000) . " $u"; + } + elsif($t >= 0.001000 && $t <= 0.999999) + { + $f = ($t * 1000) . ' ms'; + } + elsif($t >= 1) + { + $f = ($t * 1) . ' s'; # * 1 to remove insignificant zeros + } + else + { + $f = 0; # $t should = 0 at this point + } + + return $f; +} + +sub perc # Percentage +{ + my($is, $of) = @_; + $is = 0 if (not defined $is); + return sprintf "%.2f", ($is * 100) / ($of ||= 1); +} + +sub t # Time average per second +{ + my $val = shift; + return 0 if !$val; + return(make_short($val / $stats{'Uptime'}, 0, 1)); +} + +sub email_report # Email given report to $op{'email'} +{ + print "email_report\n" if $op{debug}; + + return if $WIN; + + my $report = shift; + + open SENDMAIL, "|/usr/sbin/sendmail -t"; + print SENDMAIL "From: mysqlreport\n"; + print SENDMAIL "To: $op{email}\n"; + print SENDMAIL "Subject: MySQL status report on " . ($mycnf{'host'} || 'localhost') . "\n\n"; + print SENDMAIL `cat $report`; + close SENDMAIL; +} + +sub cat_report # Print given report to screen +{ + print "cat_report\n" if $op{debug}; + + my $report = shift; + my @report; + + open REPORT, "< $report"; + @report = ; + close REPORT; + print @report; +} + +sub get_Com_values +{ + print "get_Com_values\n" if $op{debug}; + + %Com_vals = (); + + # Make copy of just the Com_ values + for(keys %stats) + { + if(grep /^Com_/, $_ and $stats{$_} > 0) + { + /^Com_(.*)/; + $Com_vals{$1} = $stats{$_}; + } + } + + # Remove DMS values + delete $Com_vals{'select'}; + delete $Com_vals{'insert'}; + delete $Com_vals{'insert_select'}; + delete $Com_vals{'replace'}; + delete $Com_vals{'replace_select'}; + delete $Com_vals{'update'}; + delete $Com_vals{'update_multi'} if exists $Com_vals{'update_multi'}; + delete $Com_vals{'delete'}; + delete $Com_vals{'delete_multi'} if exists $Com_vals{'delete_multi'}; +} + +sub write_DTQ # Write DTQ report in descending order by values +{ + print "write_DTQ\n" if $op{debug}; + + $~ = 'DTQ'; + + my %DTQ; + my $first = 1; + + # Total Com values + $stat_val = 0; + for(values %Com_vals) { $stat_val += $_; } + $DTQ{'Com_'} = $stat_val; + + $DTQ{'DMS'} = $dms; + $DTQ{'QC Hits'} = $stats{'Qcache_hits'} if $stats{'Qcache_hits'} != 0; + $DTQ{'COM_QUIT'} = int (($stats{'Connections'} - 2) - ($stats{'Aborted_clients'} / 2)); + + $stat_val = 0; + for(values %DTQ) { $stat_val += $_; } + if($questions != $stat_val) + { + $DTQ{($questions > $stat_val ? '+Unknown' : '-Unknown')} = abs $questions - $stat_val; + } + + for(sort { $DTQ{$b} <=> $DTQ{$a} } keys(%DTQ)) + { + if($first) { $stat_label = '%Total:'; $first = 0; } + else { $stat_label = ''; } + + $stat_name = $_; + $stat_val = $DTQ{$_}; + write; + } +} + +sub write_DMS # Write DMS report in descending order by values +{ + print "write_DMS\n" if $op{debug}; + + $~ = 'DMS'; + + for(sort { $DMS_vals{$b} <=> $DMS_vals{$a} } keys(%DMS_vals)) + { + $stat_name = $_; + $stat_val = $DMS_vals{$_}; + write; + } +} + +sub write_Com # Write COM report in descending order by values +{ + print "write_Com\n" if $op{debug}; + + my $i = $op{'com'}; + + $~ = 'COM_1'; + + # Total Com values and write first line of COM report + $stat_label = '%Total:' unless $op{'dtq'}; + $stat_val = 0; + for(values %Com_vals) { $stat_val += $_; } + write; + + $~ = 'COM_2'; + + # Sort remaining Com values, print only the top $op{'com'} number of values + for(sort { $Com_vals{$b} <=> $Com_vals{$a} } keys(%Com_vals)) + { + $stat_name = $_; + $stat_val = $Com_vals{$_}; + write; + + last if !(--$i); + } +} + +sub write_qcache +{ + print "write_qcache\n" if $op{debug}; + + # Query cache was added in 4.0.1, but have_query_cache was added in 4.0.2, + # ergo this method is slightly more reliable + return if not exists $vars{'query_cache_size'}; + return if $vars{'query_cache_size'} == 0; + + $qc_mem_used = $vars{'query_cache_size'} - $stats{'Qcache_free_memory'}; + $qc_hi_r = sprintf "%.2f", $stats{'Qcache_hits'} / ($stats{'Qcache_inserts'} ||= 1); + $qc_ip_r = sprintf "%.2f", $stats{'Qcache_inserts'} / ($stats{'Qcache_lowmem_prunes'} ||= 1); + + $~ = 'QCACHE'; + write; +} + +sub write_InnoDB +{ + print "write_InnoDB\n" if $op{debug}; + + return if not defined $stats{'Innodb_page_size'}; + + $stats{'Innodb_buffer_pool_pages_latched'} = 0 if not defined $stats{'Innodb_buffer_pool_pages_latched'}; + + $~ = 'IB'; + write; + + # Innodb_row_lock_ values were added in MySQL 5.0.3 + if($MySQL_version >= 50003) + { + $~ = 'IB_LOCK'; + write; + } + + # Data, Pages, Rows + $~ = 'IB_DPR'; + write; +} + +sub have_op +{ + my $key = shift; + return 1 if (exists $op{$key} && $op{$key} ne ''); + return 0; +} + +sub sig_handler +{ + print "\nReceived signal at " , scalar localtime , "\n"; + exit_tasks_and_cleanup(); + exit; +} + +sub exit_tasks_and_cleanup +{ + print "exit_tasks_and_cleanup\n" if $op{debug}; + + close $tmpfile_fh; + select STDOUT unless $op{'detach'}; + + email_report($tmpfile) if $op{'email'}; + + cat_report($tmpfile) unless $op{'detach'}; + + if($op{'outfile'}) + { + if($WIN) { `move $tmpfile $op{outfile}`; } + else { `mv $tmpfile $op{outfile}`; } + } + else + { + if($WIN) { `del $tmpfile`; } + else { `rm -f $tmpfile`; } + } + + if(!$op{'infile'} && !$relative_infiles) + { + if($op{'flush-status'}) + { + $query = $dbh->prepare("FLUSH STATUS;"); + $query->execute(); + } + + $query->finish(); + $dbh->disconnect(); + } +} + +# +# Formats +# + +format MYSQL_TIME = +MySQL @<<<<<<<<<<<<<<<< uptime @<<<<<<<<<<< @>>>>>>>>>>>>>>>>>>>>>>>> +$vars{'version'}, sec_to_dhms($real_uptime), (($op{infile} || $relative_infiles) ? '' : scalar localtime) +. + +format KEY_BUFF_MAX = + +__ Key _________________________________________________________________ +Buffer used @>>>>>> of @>>>>>> %Used: @>>>>> +make_short($key_buffer_used, 1), make_short($vars{'key_buffer_size'}, 1), perc($key_buffer_used, $vars{'key_buffer_size'}) +. + +format KEY_BUFF_USAGE = + Current @>>>>>> %Usage: @>>>>> +make_short($key_buffer_usage, 1), perc($key_buffer_usage, $vars{'key_buffer_size'}) +. + +format KEY_RATIOS = +Write hit @>>>>>% +$key_write_ratio +Read hit @>>>>>% +$key_read_ratio + +__ Questions ___________________________________________________________ +Total @>>>>>>>> @>>>>>/s +make_short($questions), t($questions) +. + +format DTQ = + @<<<<<<< @>>>>>>>> @>>>>>/s @>>>>>> @>>>>> +$stat_name, make_short($stat_val), t($stat_val), $stat_label, perc($stat_val, $questions) +. + +format SLOW_DMS = +Slow @<<<<<<< @>>>>>> @>>>>>/s @>>>>> %DMS: @>>>>> Log: @>> +$slow_query_t, make_short($stats{'Slow_queries'}), t($stats{'Slow_queries'}), perc($stats{'Slow_queries'}, $questions), perc($stats{'Slow_queries'}, $dms), $vars{'log_slow_queries'} +DMS @>>>>>>>> @>>>>>/s @>>>>> +make_short($dms), t($dms), perc($dms, $questions) +. + +format DMS = + @<<<<<<< @>>>>>>>> @>>>>>/s @>>>>> @>>>>> +$stat_name, make_short($stat_val), t($stat_val), perc($stat_val, $questions), perc($stat_val, $dms) +. + +format COM_1 = +Com_ @>>>>>>>> @>>>>>/s @>>>>> +make_short($stat_val), t($stat_val), perc($stat_val, $questions) +. + +format COM_2 = + @<<<<<<<<<< @>>>>>> @>>>>>/s @>>>>> +$stat_name, make_short($stat_val), t($stat_val), perc($stat_val, $questions) +. + +format SAS = + +__ SELECT and Sort _____________________________________________________ +Scan @>>>>>> @>>>>/s %SELECT: @>>>>> +make_short($stats{'Select_scan'}), t($stats{'Select_scan'}), perc($stats{'Select_scan'}, $stats{'Com_select'}) +Range @>>>>>> @>>>>/s @>>>>> +make_short($stats{'Select_range'}), t($stats{'Select_range'}), perc($stats{'Select_range'}, $stats{'Com_select'}) +Full join @>>>>>> @>>>>/s @>>>>> +make_short($stats{'Select_full_join'}), t($stats{'Select_full_join'}), perc($stats{'Select_full_join'}, $stats{'Com_select'}) +Range check @>>>>>> @>>>>/s @>>>>> +make_short($stats{'Select_range_check'}), t($stats{'Select_range_check'}), perc($stats{'Select_range_check'}, $stats{'Com_select'}) +Full rng join @>>>>>> @>>>>/s @>>>>> +make_short($stats{'Select_full_range_join'}), t($stats{'Select_full_range_join'}), perc($stats{'Select_full_range_join'}, $stats{'Com_select'}) +Sort scan @>>>>>> @>>>>/s +make_short($stats{'Sort_scan'}), t($stats{'Sort_scan'}) +Sort range @>>>>>> @>>>>/s +make_short($stats{'Sort_range'}), t($stats{'Sort_range'}) +Sort mrg pass @>>>>>> @>>>>/s +make_short($stats{'Sort_merge_passes'}), t($stats{'Sort_merge_passes'}) +. + +format QCACHE = + +__ Query Cache _________________________________________________________ +Memory usage @>>>>>> of @>>>>>> %Used: @>>>>> +make_short($qc_mem_used, 1), make_short($vars{'query_cache_size'}, 1), perc($qc_mem_used, $vars{'query_cache_size'}) +Block Fragmnt @>>>>>% +perc($stats{'Qcache_free_blocks'}, $stats{'Qcache_total_blocks'}) +Hits @>>>>>> @>>>>/s +make_short($stats{'Qcache_hits'}), t($stats{'Qcache_hits'}) +Inserts @>>>>>> @>>>>/s +make_short($stats{'Qcache_inserts'}), t($stats{'Qcache_inserts'}) +Insrt:Prune @>>>>>>:1 @>>>>/s +make_short($qc_ip_r), t($stats{'Qcache_inserts'} - $stats{'Qcache_lowmem_prunes'}) +Hit:Insert @>>>>>>:1 +$qc_hi_r, t($qc_hi_r) +. + +# Not really the end... +format REPORT_END = + +__ Table Locks _________________________________________________________ +Waited @>>>>>>>> @>>>>>/s %Total: @>>>>> +make_short($stats{'Table_locks_waited'}), t($stats{'Table_locks_waited'}), perc($stats{'Table_locks_waited'}, $stats{'Table_locks_waited'} + $stats{'Table_locks_immediate'}); +Immediate @>>>>>>>> @>>>>>/s +make_short($stats{'Table_locks_immediate'}), t($stats{'Table_locks_immediate'}) + +__ Tables ______________________________________________________________ +Open @>>>>>>>> of @>>> %Cache: @>>>>> +$stats{'Open_tables'}, $vars{'table_cache'}, perc($stats{'Open_tables'}, $vars{'table_cache'}) +Opened @>>>>>>>> @>>>>>/s +make_short($stats{'Opened_tables'}), t($stats{'Opened_tables'}) + +__ Connections _________________________________________________________ +Max used @>>>>>>>> of @>>> %Max: @>>>>> +$stats{'Max_used_connections'}, $vars{'max_connections'}, perc($stats{'Max_used_connections'}, $vars{'max_connections'}) +Total @>>>>>>>> @>>>>>/s +make_short($stats{'Connections'}), t($stats{'Connections'}) + +__ Created Temp ________________________________________________________ +Disk table @>>>>>>>> @>>>>>/s +make_short($stats{'Created_tmp_disk_tables'}), t($stats{'Created_tmp_disk_tables'}) +Table @>>>>>>>> @>>>>>/s Size: @>>>>> +make_short($stats{'Created_tmp_tables'}), t($stats{'Created_tmp_tables'}), make_short($vars{'tmp_table_size'}, 1, 1) +File @>>>>>>>> @>>>>>/s +make_short($stats{'Created_tmp_files'}), t($stats{'Created_tmp_files'}) +. + +format TAB = + +__ Threads _____________________________________________________________ +Running @>>>>>>>> of @>>> +$stats{'Threads_running'}, $stats{'Threads_connected'} +Cached @>>>>>>>> of @>>> %Hit: @>>>>> +$stats{'Threads_cached'}, $vars{'thread_cache_size'}, make_short(100 - perc($stats{'Threads_created'}, $stats{'Connections'})) +Created @>>>>>>>> @>>>>>/s +make_short($stats{'Threads_created'}), t($stats{'Threads_created'}) +Slow @>>>>>>>> @>>>>>/s +$stats{'Slow_launch_threads'}, t($stats{'Slow_launch_threads'}) + +__ Aborted _____________________________________________________________ +Clients @>>>>>>>> @>>>>>/s +make_short($stats{'Aborted_clients'}), t($stats{'Aborted_clients'}) +Connects @>>>>>>>> @>>>>>/s +make_short($stats{'Aborted_connects'}), t($stats{'Aborted_connects'}) + +__ Bytes _______________________________________________________________ +Sent @>>>>>>>> @>>>>>/s +make_short($stats{'Bytes_sent'}), t($stats{'Bytes_sent'}) +Received @>>>>>>>> @>>>>>/s +make_short($stats{'Bytes_received'}), t($stats{'Bytes_received'}) +. + +format IB = + +__ InnoDB Buffer Pool __________________________________________________ +Usage @>>>>>> of @>>>>>> %Used: @>>>>> +make_short($ib_bp_used, 1), make_short($ib_bp_total, 1), perc($ib_bp_used, $ib_bp_total) +Read hit @>>>>>% +$ib_bp_read_ratio; +Pages + Free @>>>>>>>> %Total: @>>>>> +make_short($stats{'Innodb_buffer_pool_pages_free'}), perc($stats{'Innodb_buffer_pool_pages_free'}, $stats{'Innodb_buffer_pool_pages_total'}) + Data @>>>>>>>> @>>>>> %Drty: @>>>>> +make_short($stats{'Innodb_buffer_pool_pages_data'}), perc($stats{'Innodb_buffer_pool_pages_data'}, $stats{'Innodb_buffer_pool_pages_total'}), perc($stats{'Innodb_buffer_pool_pages_dirty'}, $stats{'Innodb_buffer_pool_pages_data'}) + Misc @>>>>>>>> @>>>>> + $stats{'Innodb_buffer_pool_pages_misc'}, perc($stats{'Innodb_buffer_pool_pages_misc'}, $stats{'Innodb_buffer_pool_pages_total'}) + Latched @>>>>>>>> @>>>>> +$stats{'Innodb_buffer_pool_pages_latched'}, perc($stats{'Innodb_buffer_pool_pages_latched'}, $stats{'Innodb_buffer_pool_pages_total'}) +Reads @>>>>>>>> @>>>>>/s +make_short($stats{'Innodb_buffer_pool_read_requests'}), t($stats{'Innodb_buffer_pool_read_requests'}) + From file @>>>>>>>> @>>>>>/s @>>>>> +make_short($stats{'Innodb_buffer_pool_reads'}), t($stats{'Innodb_buffer_pool_reads'}), perc($stats{'Innodb_buffer_pool_reads'}, $stats{'Innodb_buffer_pool_read_requests'}) + Ahead Rnd @>>>>>>>> @>>>>>/s +$stats{'Innodb_buffer_pool_read_ahead_rnd'}, t($stats{'Innodb_buffer_pool_read_ahead_rnd'}) + Ahead Sql @>>>>>>>> @>>>>>/s +$stats{'Innodb_buffer_pool_read_ahead_seq'}, t($stats{'Innodb_buffer_pool_read_ahead_seq'}) +Writes @>>>>>>>> @>>>>>/s +make_short($stats{'Innodb_buffer_pool_write_requests'}), t($stats{'Innodb_buffer_pool_write_requests'}) +Flushes @>>>>>>>> @>>>>>/s +make_short($stats{'Innodb_buffer_pool_pages_flushed'}), t($stats{'Innodb_buffer_pool_pages_flushed'}) +Wait Free @>>>>>>>> @>>>>>/s +$stats{'Innodb_buffer_pool_wait_free'}, t($stats{'Innodb_buffer_pool_wait_free'}) +. + +format IB_LOCK = + +__ InnoDB Lock _________________________________________________________ +Waits @>>>>>>>> @>>>>>/s +$stats{'Innodb_row_lock_waits'}, t($stats{'Innodb_row_lock_waits'}) +Current @>>>>>>>> +$stats{'Innodb_row_lock_current_waits'} +Time acquiring + Total @>>>>>>>> ms +$stats{'Innodb_row_lock_time'} + Average @>>>>>>>> ms +$stats{'Innodb_row_lock_time_avg'} + Max @>>>>>>>> ms +$stats{'Innodb_row_lock_time_max'} +. + +format IB_DPR = + +__ InnoDB Data, Pages, Rows ____________________________________________ +Data + Reads @>>>>>>>> @>>>>>/s +make_short($stats{'Innodb_data_reads'}), t($stats{'Innodb_data_reads'}) + Writes @>>>>>>>> @>>>>>/s +make_short($stats{'Innodb_data_writes'}), t($stats{'Innodb_data_writes'}) + fsync @>>>>>>>> @>>>>>/s +make_short($stats{'Innodb_data_fsyncs'}), t($stats{'Innodb_data_fsyncs'}) + Pending + Reads @>>>>>>>> +$stats{'Innodb_data_pending_reads'}, t($stats{'Innodb_data_pending_reads'}) + Writes @>>>>>>>> +$stats{'Innodb_data_pending_writes'}, t($stats{'Innodb_data_pending_writes'}) + fsync @>>>>>>>> +$stats{'Innodb_data_pending_fsyncs'}, t($stats{'Innodb_data_pending_fsyncs'}) + +Pages + Created @>>>>>>>> @>>>>>/s +make_short($stats{'Innodb_pages_created'}), t($stats{'Innodb_pages_created'}) + Read @>>>>>>>> @>>>>>/s +make_short($stats{'Innodb_pages_read'}), t($stats{'Innodb_pages_read'}) + Written @>>>>>>>> @>>>>>/s +make_short($stats{'Innodb_pages_written'}), t($stats{'Innodb_pages_written'}) + +Rows + Deleted @>>>>>>>> @>>>>>/s +make_short($stats{'Innodb_rows_deleted'}), t($stats{'Innodb_rows_deleted'}) + Inserted @>>>>>>>> @>>>>>/s +make_short($stats{'Innodb_rows_inserted'}), t($stats{'Innodb_rows_inserted'}) + Read @>>>>>>>> @>>>>>/s +make_short($stats{'Innodb_rows_read'}), t($stats{'Innodb_rows_read'}) + Updated @>>>>>>>> @>>>>>/s +make_short($stats{'Innodb_rows_updated'}), t($stats{'Innodb_rows_updated'}) +. diff --git a/debian/additions/mysqlreport.1 b/debian/additions/mysqlreport.1 new file mode 100644 index 00000000000..5ae6b9e3b92 --- /dev/null +++ b/debian/additions/mysqlreport.1 @@ -0,0 +1,180 @@ +.TH "mysqlreport" "1" "2.5 2006-09-01 (docrev 2006-05-19)" "Daniel Nichter" "MYSQL" +.SH "NAME" +.LP +mysqlreport \- Makes a friendly report of important MySQL status values +.SH "SYNTAX" +.LP +mysqlreport [\fIoptions\fP] +.SH "DESCRIPTION" +.LP +mysqlreport makes a friendly report of important MySQL status values. Actually, +it makes a friendly report of nearly every status value from SHOW STATUS. +Unlike SHOW STATUS which simply dumps over 100 values to screen in one long +list, mysqlreport interprets and formats the values and presents the basic +values and many more inferred values in a human\-readable format. Numerous +example reports are available at the mysqlreport web page at +http://hackmysql.com/mysqlreport. + +The benefit of mysqlreport is that it allows you to very quickly see a wide +array of performance indicators for your MySQL server which would otherwise +need to be calculated by hand from all the various SHOW STATUS values. For +example, the Index Read Ratio is an important value but it's not present in +SHOW STATUS; it's an inferred value (the ratio of Key_reads to +Key_read_requests). + +This documentation outlines all the command line options in mysqlreport, most +of which control which reports are printed. This document does not address +how to interpret these reports; that topic is covered in the document Guide +To Understanding mysqlreport at http://hackmysql.com/mysqlreportguide. + +.SH "OPTIONS" +Technically, command line options are in the form \-\-option, but \-option works +too. All options can be abbreviated if the abbreviation is unique. For example, +option \-\-host can be abbreviated \-\-ho but not \-\-h because \-\-h is ambiguous: it +could mean \-\-host or \-\-help. + +.LP + +.TP +\fB\-\-help\fR +Output help information and exit. + +.TP +\fB\-\-user USER\fR + +.TP +\fB\-\-password\fR +As of version 2.3 \-\-password can take the password on the +command line like "\-\-password FOO". Using \-\-password +alone without giving a password on the command line +causes mysqlreport to prompt for a password. + +.TP +\fB\-\-host ADDRESS\fR + +.TP +\fB\-\-port PORT\fR + +.TP +\fB\-\-socket SOCKET\fR + +.TP +\fB\-\-no\-mycnf\fR +\-\-no\-mycnf makes mysqlreport not read ~/.my.cnf which it does by default +otherwise. \-\-user and \-\-password always override values from ~/.my.cnf. + +.TP +\fB\-\-dtq\fR +Print Distribution of Total Queries (DTQ) report (under +Total in Questions report). Queries (or Questions) can +be divided into four main areas: DMS (see \-\-dms below), +Com_ (see \-\-com below), COM_QUIT (see COM_QUIT and +Questions at http://hackmysql.com/com_quit), and +Unknown. \-\-dtq lists the number of queries in each of +these areas in descending order. + +.TP +\fB\-\-dms\fR +Print Data Manipulation Statements (DMS) report (under +DMS in Questions report). DMS are those from the MySQL +manual section 13.2. Data Manipulation Statements. +(Currently, mysqlreport considers only SELECT, INSERT, +REPLACE, UPDATE, and DELETE.) Each DMS is listed in +descending order by count. + +.TP +\fB\-\-com N\fR +Print top N number of non\-DMS Com_ status values in +descending order (after DMS in Questions report). If N +is not given, default is 3. Such non\-DMS Com_ values +include Com_change_db, Com_show_tables, Com_rollback, +etc. + +.TP +\fB\-\-sas\fR +Print report for Select_ and Sort_ status values (after +Questions report). See MySQL Select and Sort Status +Variables at http://hackmysql.com/selectandsort. + +.TP +\fB\-\-tab\fR +Print Threads, Aborted, and Bytes status reports (after +Created temp report). As of mysqlreport v2.3 the +Threads report reports on all Threads_ status values. + +.TP +\fB\-\-qcache\fR +Print Query Cache report. +.TP +\fB\-\-all\fR +Equivalent to "\-\-dtq \-\-dms \-\-com 3 \-\-sas \-\-qcache". +(Notice \-\-tab is not invoked by \-\-all.) + +.TP +\fB\-\-infile FILE\fR +Instead of getting SHOW STATUS values from MySQL, read +values from FILE. FILE is often a copy of the output of +SHOW STATUS including formatting characters (|, +, \-). +mysqlreport expects FILE to have the format +" value number " where value is only alpha and +underscore characters (A\-Z and _) and number is a +positive integer. Anything before, between, or after +value and number is ignored. mysqlreport also needs +the following MySQL server variables: version, +table_cache, max_connections, key_buffer_size, +query_cache_size. These values can be specified in +INFILE in the format "name = value" where name is one +of the aforementioned server variables and value is a +positive integer with or without a trailing M and +possible periods (for version). For example, to specify +an 18M key_buffer_size: key_buffer_size = 18M. Or, a +256 table_cache: table_cache = 256. The M implies +Megabytes not million, so 18M means 18,874,368 not +18,000,000. If these server variables are not specified +the following defaults are used (respectively) which +may cause strange values to be reported: 0.0.0, 64, +100, 8M, 0. + +.TP +\fB\-\-outfile FILE\fR +After printing the report to screen, print the report +to FILE too. Internally, mysqlreport always writes the +report to a temp file first: /tmp/mysqlreport.PID on +*nix, c:\mysqlreport.PID on Windows (PID is the +script's process ID). Then it prints the temp file to +screen. Then if \-\-outfile is specified, the temp file +is copied to OUTFILE. After \-\-email (below), the temp +file is deleted. + +.TP +\fB\-\-email ADDRESS\fR +After printing the report to screen, email the report +to ADDRESS. This option requires sendmail in +/usr/sbin/, therefore it does not work on Windows. +/usr/sbin/sendmail can be a sym link to qmail, for +example, or any MTA that emulates sendmail's \-t +command line option and operation. The FROM: field is +"mysqlreport", SUBJECT: is "MySQL status report". + +.TP +\fB\-\-flush\-status\fR +Execute a "FLUSH STATUS;" after generating the reports. +If you do not have permissions in MySQL to do this an +error from DBD::mysql::st will be printed after the +reports. + +.SH "AUTHORS" +.LP +Daniel Nichter + +If mysqlreport breaks, send me a message from +http://hackmysql.com/feedback +with the error. + +.SH "SEE ALSO" +.LP +mytop(1) +.LP +The comprehensive Guide To Understanding mysqlreport at +http://hackmysql.com/mysqlreportguide. + diff --git a/debian/additions/mysqltest.1 b/debian/additions/mysqltest.1 new file mode 100644 index 00000000000..3469765fe3b --- /dev/null +++ b/debian/additions/mysqltest.1 @@ -0,0 +1,16 @@ +.TH mysql 1 "17 March 2003" "MySQL 3.23" "MySQL database" +.SH NAME +mysqltest \- Regressiontest program for MySQL. +.SH SYNOPSIS +mysqltest [options] +.SH DESCRIPTION +Runs a test against the mysql server and compares output with a results file. + +For more information start the program with '--help'. +.SH "SEE ALSO" +mysql (1), mysqld (1) +.SH AUTHOR +This manpage was written by Christian Hammers . + +MySQL is available at http://www.mysql.com/. +.\" end of man page diff --git a/debian/additions/pack_isam.1 b/debian/additions/pack_isam.1 new file mode 100644 index 00000000000..cad153eedee --- /dev/null +++ b/debian/additions/pack_isam.1 @@ -0,0 +1,19 @@ +.TH mysql 1 "17 March 2003" "MySQL 3.23" "MySQL database" +.SH NAME +myisampack \- Compresses MySQL database files. +.SH SYNOPSIS +myisampack [options] +.SH DESCRIPTION +Pack a ISAM-table to take much smaller space +Keys are not updated, so you must run isamchk -rq on any table +that has keys after you have compressed it +You should give the .ISM file as the filename argument + +For more information start the program with '--help'. +.SH "SEE ALSO" +mysql (1), mysqld (1) +.SH AUTHOR +This manpage was written by Christian Hammers . + +MySQL is available at http://www.mysql.com/. +.\" end of man page diff --git a/debian/additions/resolve_stack_dump.1 b/debian/additions/resolve_stack_dump.1 new file mode 100644 index 00000000000..2a1e2770275 --- /dev/null +++ b/debian/additions/resolve_stack_dump.1 @@ -0,0 +1,16 @@ +.TH mysql 1 "17 March 2003" "MySQL 3.23" "MySQL database" +.SH NAME +resolve_stack_dump \- MySQL helper program for reporting bugs. +.SH SYNOPSIS +resolve_stack_dump [options] +.SH DESCRIPTION +Resolve numeric stack strace dump into symbols. + +For more information start the program with '--help'. +.SH "SEE ALSO" +mysql (1), mysqld (1) +.SH AUTHOR +This manpage was written by Christian Hammers . + +MySQL is available at http://www.mysql.com/. +.\" end of man page diff --git a/debian/additions/resolveip.1 b/debian/additions/resolveip.1 new file mode 100644 index 00000000000..7aa9439394d --- /dev/null +++ b/debian/additions/resolveip.1 @@ -0,0 +1,16 @@ +.TH mysql 1 "17 March 2003" "MySQL 3.23" "MySQL database" +.SH NAME +resolveip \- MySQL helper program to retrive IP addresses. +.SH SYNOPSIS +resolveip [options] +.SH DESCRIPTION +Get hostname based on IP-address or IP-address based on hostname. + +For more information start the program with '--help'. +.SH "SEE ALSO" +mysql (1), mysqld (1) +.SH AUTHOR +This manpage was written by Christian Hammers . + +MySQL is available at http://www.mysql.com/. +.\" end of man page diff --git a/debian/autobake-deb.sh b/debian/autobake-deb.sh new file mode 100755 index 00000000000..51cda73ee89 --- /dev/null +++ b/debian/autobake-deb.sh @@ -0,0 +1,74 @@ +#!/bin/bash + +# Build MariaDB .deb packages. +# Based on OurDelta .deb packaging scripts, which are in turn based on Debian +# MySQL packages. + +# Exit immediately on any error +set -e + +# Debug script and command lines +#set -x + +# Don't run the mysql-test-run test suite as part of build. +# It takes a lot of time, and we will do a better test anyway in +# Buildbot, running the test suite from installed .debs on a clean VM. +export DEB_BUILD_OPTIONS="nocheck" + +# Find major.minor version. +# +source ./VERSION +UPSTREAM="${MYSQL_VERSION_MAJOR}.${MYSQL_VERSION_MINOR}.${MYSQL_VERSION_PATCH}" +RELEASE_EXTRA=${MYSQL_VERSION_EXTRA} + +RELEASE_NAME=mariadb +PATCHLEVEL="" +LOGSTRING="MariaDB build" + +# Look up distro-version specific stuff. +# +# Libreadline changed to GPLv3. Old GPLv2 version is available, but it +# is called different things on different versions. +CODENAME="$(lsb_release -sc)" +case "${CODENAME}" in + etch) LIBREADLINE_DEV=libreadline-dev ;; + lenny|hardy|intrepid|jaunty|karmic|lucid) LIBREADLINE_DEV='libreadline5-dev | libreadline-dev' ;; + squeeze|maverick|natty) LIBREADLINE_DEV=libreadline5-dev ;; + *) LIBREADLINE_DEV=libreadline-gplv2-dev ;; +esac + +# Clean up build file symlinks that are distro-specific. First remove all, then set +# new links. +DISTRODIRS="$(ls ./debian/dist)" +for distrodir in ${DISTRODIRS}; do + DISTROFILES="$(ls ./debian/dist/${distrodir})" + for distrofile in ${DISTROFILES}; do + rm -f "./debian/${distrofile}"; + done; +done; + +# Set no symlinks for build files in the debian dir, so we avoid adding AppArmor on Debian. +DISTRO="$(lsb_release -si)" +echo "Copying distribution specific build files for ${DISTRO}" +DISTROFILES="$(ls ./debian/dist/${DISTRO})" +for distrofile in ${DISTROFILES}; do + rm -f "./debian/${distrofile}" + sed -e "s/\\\${LIBREADLINE_DEV}/${LIBREADLINE_DEV}/g" < "./debian/dist/${DISTRO}/${distrofile}" > "./debian/${distrofile}" + chmod --reference="./debian/dist/${DISTRO}/${distrofile}" "./debian/${distrofile}" +done; + +# Adjust changelog, add new version. +# +echo "Incrementing changelog and starting build scripts" + +dch -b -D ${CODENAME} -v "${UPSTREAM}${PATCHLEVEL}-${RELEASE_NAME}${RELEASE_EXTRA:+-${RELEASE_EXTRA}}~${CODENAME}" "Automatic build with ${LOGSTRING}." + +echo "Creating package version ${UPSTREAM}${PATCHLEVEL}-${RELEASE_NAME}${RELEASE_EXTRA:+-${RELEASE_EXTRA}}~${CODENAME} ... " + +# Build the package. +# +fakeroot dpkg-buildpackage -us -uc + +echo "Build complete" + +# end of autobake script diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 00000000000..0af9e637bc0 --- /dev/null +++ b/debian/changelog @@ -0,0 +1,23 @@ +mariadb-5.5 (5.5.1) unstable; urgency=low + + * Initial release. + + -- Kristian Nielsen Fri, 6 Jan 2012 15:17:23 -0100 + +mariadb-5.3 (5.3.0) unstable; urgency=low + + * Initial release. + + -- Sergei Golubchik Mon, 1 Nov 2010 09:16:01 -0100 + +mariadb-5.2 (5.2.0) unstable; urgency=low + + * Initial release. + + -- Kristian Nielsen Wed, 17 Mar 2010 12:54:51 -0100 + +mariadb-5.1 (5.1.0) unstable; urgency=low + + * Initial release. + + -- Peter Lieverdink Tue, 29 Sep 2009 17:05:03 +1000 diff --git a/debian/compat b/debian/compat new file mode 100644 index 00000000000..7ed6ff82de6 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +5 diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 00000000000..9c98778b4f8 --- /dev/null +++ b/debian/copyright @@ -0,0 +1,61 @@ + +== MariaDB == + +The Debian package of MySQL was first debianzed on 1997-04-12 by Christian +Schwarz and ist maintained since 1999-04-20 by +Christian Hammers . + +The MariaDB packages were initally made by http://ourdelta.org/, and +are now managed by the MariaDB development team, +maria-developers@lists.launchpad.net + +MariaDB can be downloaded from http://downloads.askmonty.org/mariadb/ + +Copyright: + +According to the file "COPYING" all parts of this package are licenced +under the terms of the GNU GPL Version 2 of which a copy is available +in /usr/share/common-licenses. + +To allow free software with other licences than the GPL to link against the +shared library, special terms for "derived works" are granted in the README file of MySQL 5.5, as follows: + +> MySQL FOSS License Exception +> We want free and open source software applications under certain +> licenses to be able to use specified GPL-licensed MySQL client +> libraries despite the fact that not all such FOSS licenses are +> compatible with version 2 of the GNU General Public License. +> Therefore there are special exceptions to the terms and conditions +> of the GPLv2 as applied to these client libraries, which are +> identified and described in more detail in the FOSS License +> Exception at +> . + +The manual had to be removed as it is not free in the sense of the +Debian Free Software Guidelines (DFSG). + + +== innotop == + +Copyright 2006-2009, Baron Schwartz +URL: http://innotop.sourceforge.net + +License: +> This software is dual licensed, either GPL version 2 or Artistic License. +> +> This package 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 Foundation; either version 2 of the License, or +> (at your option) any later version. +> +> This package is distributed in the hope that it will be useful, +> but WITHOUT 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 package; if not, write to the Free Software +> Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +On Debian systems, the complete text of the GNU General Public License and the +Artistic License can be found in `/usr/share/common-licenses/'. diff --git a/debian/dist/Debian/control b/debian/dist/Debian/control new file mode 100644 index 00000000000..b36c0469ba5 --- /dev/null +++ b/debian/dist/Debian/control @@ -0,0 +1,227 @@ +Source: mariadb-5.5 +Section: misc +Priority: optional +Maintainer: MariaDB Developers +XSBC-Original-Maintainer: Maria Developers +Uploaders: MariaDB Developers +Build-Depends: libtool (>= 1.4.2-7), procps | hurd, debhelper, file (>= 3.28), libncurses5-dev (>= 5.0-6), perl (>= 5.6.0), libwrap0-dev (>= 7.6-8.3), zlib1g-dev (>= 1:1.1.3-5), ${LIBREADLINE_DEV}, libevent-dev, libssl-dev, libpam0g-dev, psmisc, po-debconf, chrpath, automake1.9, doxygen, texlive-latex-base, ghostscript | gs-gpl, dpatch, gawk, bison, lsb-release, hardening-wrapper +Standards-Version: 3.8.3 +Homepage: http://mariadb.org/ +Vcs-Browser: http://bazaar.launchpad.net/~maria-captains/maria/5.5/files +Vcs-Bzr: bzr://lp:maria + +Package: libmariadbclient18 +Section: libs +Architecture: any +Depends: mariadb-common, libmysqlclient18 (= ${source:Version}), ${shlibs:Depends}, ${misc:Depends} +Description: MariaDB database client library + MariaDB is a fast, stable and true multi-user, multi-threaded SQL database + server. SQL (Structured Query Language) is the most popular database query + language in the world. The main goals of MariaDB are speed, robustness and + ease of use. + . + This package includes the client library. + +Package: libmysqlclient18 +Section: libs +Architecture: any +Depends: libmariadbclient18 (= ${source:Version}) +Replaces: libmysqlclient18 (<< ${source:Version}) +Description: Virtual package to satisfy external depends + This is an empty package that provides an updated "best" version of + libmysqlclient18 that does not conflict with the libmariadbclient18 + package. + . + MariaDB is a fast, stable and true multi-user, multi-threaded SQL database + server. SQL (Structured Query Language) is the most popular database query + language in the world. The main goals of MariaDB are speed, robustness and + ease of use. + +Package: libmariadbd-dev +Architecture: any +Section: libdevel +Depends: libmariadbclient-dev (>= ${source:Version}), ${misc:Depends} +Provides: libmysqld-dev +Conflicts: libmysqld-dev +Replaces: libmysqld-dev +Description: MariaDB embedded database development files + MariaDB is a fast, stable and true multi-user, multi-threaded SQL database + server. SQL (Structured Query Language) is the most popular database query + language in the world. The main goals of MariaDB are speed, robustness and + ease of use. + . + This package includes the embedded server library and header files. + +Package: libmariadbclient-dev +Architecture: any +Section: libdevel +Depends: libmariadbclient18 (>= ${source:Version}), zlib1g-dev, , ${shlibs:Depends}, ${misc:Depends} +Replaces: libmariadbclient16-dev, libmysqlclient16-dev +Conflicts: libmysqlclient-dev, libmariadbclient16-dev, libmysqlclient14-dev, libmysqlclient12-dev, libmysqlclient10-dev, libmysqlclient15-dev, libmysqlclient16-dev +Provides: libmysqlclient-dev +Description: MariaDB database development files + MariaDB is a fast, stable and true multi-user, multi-threaded SQL database + server. SQL (Structured Query Language) is the most popular database query + language in the world. The main goals of MariaDB are speed, robustness and + ease of use. + . + This package includes development libraries and header files. + +Package: mysql-common +Section: database +Architecture: all +Depends: ${shlibs:Depends}, ${misc:Depends} +Provides: mariadb-common +Description: MariaDB database common files (e.g. /etc/mysql/my.cnf) + MariaDB is a fast, stable and true multi-user, multi-threaded SQL database + server. SQL (Structured Query Language) is the most popular database query + language in the world. The main goals of MariaDB are speed, robustness and + ease of use. + . + This package includes files needed by all versions of the client library + (e.g. /etc/mysql/my.cnf). + . + Due to libmysqlclient15off package depends, this package has not yet been + renamed to mariadb-common. It does, however, already contain a new my.cnf + file with mariadb-specific configuration options. + +Package: mariadb-client-core-5.5 +Architecture: any +Depends: mariadb-common, libmariadbclient18 (>= ${source:Version}), ${shlibs:Depends}, ${misc:Depends} +Provides: mysql-client-core, mysql-client-core-5.1, mysql-client-core-5.5 +Conflicts: mysql-client (<< 5.0.51), mysql-client-5.0, mysql-client-5.1, mysql-client-5.5, + mysql-client-core-5.1, mysql-client-core-5.5, + mariadb-client-5.1, mariadb-client-core-5.1, + mariadb-client-5.2, mariadb-client-core-5.2, + mariadb-client-5.3, mariadb-client-core-5.3 +Replaces: mysql-client (<< 5.0.51), mysql-client-5.0, mysql-client-5.1, mysql-client-5.5, + mysql-client-core-5.1, mysql-client-core-5.5, + mariadb-client-5.1, mariadb-client-core-5.1, + mariadb-client-5.2, mariadb-client-core-5.2, + mariadb-client-5.3, mariadb-client-core-5.3 +Description: MariaDB database core client binaries + MariaDB is a fast, stable and true multi-user, multi-threaded SQL database + server. SQL (Structured Query Language) is the most popular database query + language in the world. The main goals of MariaDB are speed, robustness and + ease of use. + . + This package includes the core client files, as used by Akonadi. + +Package: mariadb-client-5.5 +Architecture: any +Depends: debianutils (>=1.6), libdbi-perl, libdbd-mysql-perl (>= 1.2202), mariadb-common, libmariadbclient18 (>= ${source:Version}), mariadb-client-core-5.5 (>= ${source:Version}), ${perl:Depends}, ${shlibs:Depends}, ${misc:Depends} +Provides: virtual-mysql-client, mysql-client, + mysql-client-4.1, mysql-client-5.1, mysql-client-5.5 +Conflicts: mysql-client (<< 5.0.51), mysql-client-5.0, mysql-client-5.1, + mariadb-client (<< ${source:Version}), + mariadb-client-5.1, mariadb-client-5.2, mariadb-client-5.3 +Replaces: mysql-client (<< 5.0.51), mysql-client-5.0, mysql-client-5.1, + mariadb-client (<< ${source:Version}), + mariadb-client-5.1, mariadb-client-5.2, mariadb-client-5.3 +Description: MariaDB database client binaries + MariaDB is a fast, stable and true multi-user, multi-threaded SQL database + server. SQL (Structured Query Language) is the most popular database query + language in the world. The main goals of MariaDB are speed, robustness and + ease of use. + . + This package includes the client binaries and the additional tools + innotop and mysqlreport. + +Package: mariadb-server-core-5.5 +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, libmariadbclient18 (>= ${binary:Version}) +Provides: mysql-server-core, mysql-server-core-5.1, mysql-server-core-5.5 +Conflicts: mariadb-server-5.1 (<< 5.1.60), + mariadb-server-5.2 (<< 5.2.10), + mariadb-server-5.3 (<< 5.3.3), + mysql-server-5.0, + mysql-server-core-5.0, mysql-server-core-5.1, mysql-server-core-5.5, + mariadb-server-core-5.1, mariadb-server-core-5.2, mariadb-server-core-5.5 +Replaces: mariadb-server-5.1 (<< 5.1.60), + mariadb-server-5.2 (<< 5.2.10), + mariadb-server-5.3 (<< 5.3.3), + mysql-server-5.0, + mysql-server-core-5.0, mysql-server-core-5.1, mysql-server-core-5.5, + mariadb-server-core-5.1, mariadb-server-core-5.2, mariadb-server-core-5.5 +Description: MariaDB database core server files + MariaDB is a fast, stable and true multi-user, multi-threaded SQL database + server. SQL (Structured Query Language) is the most popular database query + language in the world. The main goals of MariaDB are speed, robustness and + ease of use. + . + This package includes the core server files, as used by Akonadi. + +Package: mariadb-test-5.5 +Section: database +Architecture: all +Depends: mariadb-server-5.5 (= ${source:Version}), mariadb-client-5.5 (= ${source:Version}) +Conflicts: mariadb-test (<< ${source:Version}), + mariadb-test-5.1, mariadb-test-5.2, mariadb-test-5.3 +Replaces: mariadb-test (<< ${source:Version}), + mariadb-test-5.1, mariadb-test-5.2, mariadb-test-5.3 +Description: MariaDB database regression test suite + MariaDB is a fast, stable and true multi-user, multi-threaded SQL database + server. SQL (Structured Query Language) is the most popular database query + language in the world. The main goals of MariaDB are speed, robustness and + ease of use. + . + This package includes the regression test suite. + +Package: mariadb-server-5.5 +Architecture: any +Suggests: tinyca, mailx, mariadb-test +Recommends: libhtml-template-perl +Pre-Depends: mariadb-common, adduser (>= 3.40), debconf +Depends: mariadb-client-5.5 (>= ${source:Version}), libdbi-perl, perl (>= 5.6), ${shlibs:Depends}, ${misc:Depends}, psmisc, passwd, lsb-base (>= 3.0-10), mariadb-server-core-5.5 (>= ${binary:Version}) +Provides: mariadb-server, mysql-server, virtual-mysql-server +Conflicts: mariadb-server (<< ${source:Version}), mysql-server (<< ${source:Version}), + mysql-server-4.1, mysql-server-5.0, mysql-server-5.1, + mariadb-server-5.1, mariadb-server-5.2, mariadb-server-5.3, + libmariadbclient16 (<< 5.3.4) +Replaces: mariadb-server (<< ${source:Version}), mysql-server (<< ${source:Version}), + mysql-server-4.1, mysql-server-5.0, mysql-server-5.1, + mariadb-server-5.1, mariadb-server-5.2, mariadb-server-5.3, + libmariadbclient16 (<< 5.3.4), + libmariadbclient-dev (<< 5.5.0) +Description: MariaDB database server binaries + MariaDB is a fast, stable and true multi-user, multi-threaded SQL database + server. SQL (Structured Query Language) is the most popular database query + language in the world. The main goals of MariaDB are speed, robustness and + ease of use. + . + This package includes the server binaries. + +Package: mariadb-server +Section: database +Architecture: all +Depends: mariadb-server-5.5, ${misc:Depends} +Description: MariaDB database server (metapackage depending on the latest version) + This is an empty package that depends on the current "best" version of + mariadb-server (currently mariadb-server-5.5), as determined by the MariaDB + maintainers. Install this package if in doubt about which MariaDB + version you need. That will install the version recommended by the + package maintainers. + . + MariaDB is a fast, stable and true multi-user, multi-threaded SQL database + server. SQL (Structured Query Language) is the most popular database query + language in the world. The main goals of MariaDB are speed, robustness and + ease of use. + +Package: mariadb-client +Section: database +Architecture: all +Depends: mariadb-client-5.5, ${misc:Depends} +Description: MariaDB database client (metapackage depending on the latest version) + This is an empty package that depends on the current "best" version of + mariadb-client (currently mariadb-client-5.5), as determined by the MariaDB + maintainers. Install this package if in doubt about which MariaDB version + you want, as this is the one we consider to be in the best shape. + +Package: mariadb-test +Section: database +Architecture: all +Depends: mariadb-test-5.5 +Description: MariaDB database regression test suite (metapackage depending on the latest version) + This is an empty package that depends on the current "best" version of + mariadb-test (currently mariadb-test-5.5), as determined by the MariaDB + maintainers. diff --git a/debian/dist/Debian/mariadb-server-5.5.README.Debian b/debian/dist/Debian/mariadb-server-5.5.README.Debian new file mode 100644 index 00000000000..f398f2fa236 --- /dev/null +++ b/debian/dist/Debian/mariadb-server-5.5.README.Debian @@ -0,0 +1,109 @@ +* MYSQL WON'T START OR STOP?: +============================= +You may never ever delete the special mysql user "debian-sys-maint". This +user together with the credentials in /etc/mysql/debian.cnf are used by the +init scripts to stop the server as they would require knowledge of the mysql +root users password else. +So in most of the times you can fix the situation by making sure that the +debian.cnf file contains the right password, e.g. by setting a new one +(remember to do a "flush privileges" then). + +* WHAT TO DO AFTER UPGRADES: +============================ +The privilege tables are automatically updated so all there is left is read +the changelogs on dev.mysql.com to see if any changes affect custom apps. + +* WHAT TO DO AFTER INSTALLATION: +================================ +The MySQL manual describes certain steps to do at this stage in a separate +chapter. They are not necessary as the Debian packages does them +automatically. + +The only thing that is left over for the admin is + - setting the passwords + - creating new users and databases + - read the rest of this text + +* DOWNGRADING TO 4.0 or 4.1: +============================ +Unsupported. Period. +But if you do and get problems or make interesting experiences, mail me, it +might help others. +Ok, if you really want, I would recommend to "mysqldump --opt" all tables, +then purge 4.1, delete /var/lib/mysql, install 4.0 and insert the dumps. Be +carefully, though, with the "mysql" table, you might not simply overwrite that +one as the password for the mysql "debian-sys-maint" user is stored in +/etc/mysql/debian.cnf and needed by /etc/init.d/ to start mysql and check if +it's alive. + +* SOME APPLICATION CAN NO LONGER CONNECT: +========================================= +This application is probably linked against libmysqlclient12 or below and +somebody has created a mysql user with new-style passwords. +The old_passwords=1 option in /etc/mysql/my.cnf might help. If not the +application that inserted the user has to be changed or the application that +tries to connect updated to libmysqlclient14 or -15. + +* NETWORKING: +============= +For security reasons, the Debian package has enabled networking only on the +loop-back device using "bind-address" in /etc/mysql/my.cnf. Check with +"netstat -tlnp" where it is listening. If your connection is aborted +immediately see if "mysqld: all" or similar is in /etc/hosts.allow and read +hosts_access(5). + +* WHERE IS THE DOCUMENTATION?: +============================== +Unfortunately due to licensing restrictions, debian currently not able +to provide the mysql-doc package in any format. For the most up to date +documentation, please go to http://dev.mysql.com/doc. + +* PASSWORDS: +============ +It is strongly recommended to set a password for the mysql root user (which + /usr/bin/mysql -u root -D mysql -e "update user set password=password('new-password') where user='root'" + /usr/bin/mysql -u root -e "flush privileges" +If you already had a password set add "-p" before "-u" to the lines above. + + +If you are tired to type the password in every time or want to automate your +scripts you can store it in the file $HOME/.my.cnf. It should be chmod 0600 +(-rw------- username username .my.cnf) to ensure that nobody else can read +it. Every other configuration parameter can be stored there, too. You will +find an example below and more information in the MySQL manual in +/usr/share/doc/mariadb-doc or www.mysql.com. + +ATTENTION: It is necessary, that a .my.cnf from root always contains a "user" +line wherever there is a "password" line, else, the Debian maintenance +scripts, that use /etc/mysql/debian.cnf, will use the username +"debian-sys-maint" but the password that is in root's .my.cnf. Also note, +that every change you make in the /root/.my.cnf will affect the mysql cron +script, too. + + # an example of $HOME/.my.cnf + [client] + user = your-mysql-username + password = enter-your-good-new-password-here + +* BIG_ROWS FOR EVEN MORE ROWS IN A TABLE: +========================================= +If you ever run out of rows in a table there is the possibility of building +the package with "-DBIG_ROWS" which, according to a MySQL employee on +packagers@lists.mysql.com should lead to a 64bit row index (I guess > 2^32 +rows) but also to an approx. 5% performance loss. + +* BerkeleyDB Storage Engine +=========================== +Support for BerkeleyDB has been removed in 5.1, and consequently both the +have-bdb and skip-bdb configuration options will cause the server to fail. +Removing the options from /etc/mysql/my.cnf will fix this problem. + +* FURTHER NOTES ON REPLICATION +=============================== +If the MySQL server is acting as a replication slave, you should not +set --tmpdir to point to a directory on a memory-based filesystem or to +a directory that is cleared when the server host restarts. A replication +slave needs some of its temporary files to survive a machine restart so +that it can replicate temporary tables or LOAD DATA INFILE operations. If +files in the temporary file directory are lost when the server restarts, +replication fails. diff --git a/debian/dist/Debian/mariadb-server-5.5.dirs b/debian/dist/Debian/mariadb-server-5.5.dirs new file mode 100644 index 00000000000..40b789231e0 --- /dev/null +++ b/debian/dist/Debian/mariadb-server-5.5.dirs @@ -0,0 +1,10 @@ +etc/init.d +etc/logrotate.d +etc/mysql/conf.d +usr/bin +usr/sbin +usr/share/man/man8 +usr/share/mysql +usr/share/doc/mariadb-server-5.3 +var/run/mysqld +var/lib/mysql-upgrade diff --git a/debian/dist/Debian/mariadb-server-5.5.files b/debian/dist/Debian/mariadb-server-5.5.files new file mode 100644 index 00000000000..2ea925fcaa7 --- /dev/null +++ b/debian/dist/Debian/mariadb-server-5.5.files @@ -0,0 +1,61 @@ +usr/lib/mysql/plugin/ +usr/lib/libhsclient.so.* +etc/mysql/debian-start +etc/mysql/conf.d/mysqld_safe_syslog.cnf +usr/bin/msql2mysql +usr/bin/my_print_defaults +usr/bin/myisamchk +usr/bin/myisam_ftdump +usr/bin/myisamlog +usr/bin/myisampack +usr/bin/aria_pack +usr/bin/aria_read_log +usr/bin/aria_ftdump +usr/bin/aria_chk +usr/bin/aria_dump_log +usr/bin/mysql_convert_table_format +usr/bin/mysql_install_db +usr/bin/mysql_secure_installation +usr/bin/mysql_setpermission +usr/bin/mysql_tzinfo_to_sql +usr/bin/mysql_upgrade +usr/bin/mysql_zap +usr/bin/mysqlbinlog +usr/bin/mysqld_multi +usr/bin/mysqld_safe +usr/bin/mysqlhotcopy +usr/bin/perror +usr/bin/replace +usr/bin/resolve_stack_dump +usr/bin/resolveip +usr/share/doc/mariadb-server-5.5/mysqld.sym.gz +usr/share/lintian/overrides/mariadb-server-5.5 +usr/share/man/man1/msql2mysql.1 +usr/share/man/man1/myisamchk.1 +usr/share/man/man1/myisam_ftdump.1 +usr/share/man/man1/myisamlog.1 +usr/share/man/man1/myisampack.1 +usr/share/man/man1/my_print_defaults.1 +usr/share/man/man1/mysqlbinlog.1 +usr/share/man/man1/mysql_convert_table_format.1 +usr/share/man/man1/mysqld_multi.1 +usr/share/man/man1/mysqld_safe.1 +usr/share/man/man1/mysqlhotcopy.1 +usr/share/man/man1/mysql_install_db.1 +usr/share/man/man1/mysql_secure_installation.1 +usr/share/man/man1/mysql_setpermission.1 +usr/share/man/man1/mysql_upgrade.1 +usr/share/man/man1/mysql_zap.1 +usr/share/man/man1/perror.1 +usr/share/man/man1/replace.1 +usr/share/man/man1/resolveip.1 +usr/share/man/man1/resolve_stack_dump.1 +usr/share/man/man1/innochecksum.1 +usr/share/man/man1/mysql_tzinfo_to_sql.1 +usr/share/mysql/debian-start.inc.sh +usr/share/mysql/echo_stderr +usr/share/mysql/errmsg-utf8.txt +usr/share/mysql/fill_help_tables.sql +usr/share/mysql/mysql_system_tables_data.sql +usr/share/mysql/mysql_system_tables.sql +usr/share/mysql/mysql_test_data_timezone.sql diff --git a/debian/dist/Debian/mariadb-server-5.5.postinst b/debian/dist/Debian/mariadb-server-5.5.postinst new file mode 100644 index 00000000000..60365711ebf --- /dev/null +++ b/debian/dist/Debian/mariadb-server-5.5.postinst @@ -0,0 +1,268 @@ +#!/bin/bash -e + +. /usr/share/debconf/confmodule + +if [ -n "$DEBIAN_SCRIPT_DEBUG" ]; then set -v -x; DEBIAN_SCRIPT_TRACE=1; fi +${DEBIAN_SCRIPT_TRACE:+ echo "#42#DEBUG# RUNNING $0 $*" 1>&2 } + +export PATH=$PATH:/sbin:/usr/sbin:/bin:/usr/bin + +# This command can be used as pipe to syslog. With "-s" it also logs to stderr. +ERR_LOGGER="logger -p daemon.err -t mysqld_safe -i" +# This will make an error in a logged command immediately apparent by aborting +# the install, rather than failing silently and leaving a broken install. +set -o pipefail + +invoke() { + if [ -x /usr/sbin/invoke-rc.d ]; then + invoke-rc.d mysql $1 + else + /etc/init.d/mysql $1 + fi +} + +MYSQL_BOOTSTRAP="/usr/sbin/mysqld --bootstrap --user=mysql --skip-grant-tables --innodb=OFF --pbxt=OFF --default-storage-engine=myisam" + +test_mysql_access() { + mysql --no-defaults -u root -h localhost /dev/null 2>&1 +} + +# call with $1 = "online" to connect to the server, otherwise it bootstraps +set_mysql_rootpw() { + # forget we ever saw the password. don't use reset to keep the seen status + db_set mysql-server/root_password "" + + tfile=`mktemp` + if [ ! -f "$tfile" ]; then + return 1 + fi + + # this avoids us having to call "test" or "[" on $rootpw + cat << EOF > $tfile +USE mysql; +UPDATE user SET password=PASSWORD("$rootpw") WHERE user='root'; +FLUSH PRIVILEGES; +EOF + if grep -q 'PASSWORD("")' $tfile; then + retval=0 + elif [ "$1" = "online" ]; then + mysql --no-defaults -u root -h localhost <$tfile >/dev/null + retval=$? + else + $MYSQL_BOOTSTRAP <$tfile + retval=$? + fi + rm -f $tfile + return $retval +} + +# This is necessary because mysql_install_db removes the pid file in /var/run +# and because changed configuration options should take effect immediately. +# In case the server wasn't running at all it should be ok if the stop +# script fails. I can't tell at this point because of the cleaned /var/run. +set +e; invoke stop; set -e + +case "$1" in + configure) + mysql_datadir=/usr/share/mysql + mysql_statedir=/var/lib/mysql + mysql_rundir=/var/run/mysqld + mysql_logdir=/var/log + mysql_cfgdir=/etc/mysql + mysql_newlogdir=/var/log/mysql + mysql_upgradedir=/var/lib/mysql-upgrade + + # first things first, if the following symlink exists, it is a preserved + # copy the old data dir from a mysql upgrade that would have otherwise + # been replaced by an empty mysql dir. this should restore it. + for dir in DATADIR LOGDIR; do + if [ "$dir" = "DATADIR" ]; then targetdir=$mysql_statedir; else targetdir=$mysql_newlogdir; fi + savelink="$mysql_upgradedir/$dir.link" + if [ -L "$savelink" ]; then + # If the targetdir was a symlink before we upgraded it is supposed + # to be either still be present or not existing anymore now. + if [ -L "$targetdir" ]; then + rm "$savelink" + elif [ ! -d "$targetdir" ]; then + mv "$savelink" "$targetdir" + else + # this should never even happen, but just in case... + mysql_tmp=`mktemp -d -t mysql-symlink-restore-XXXXXX` + echo "this is very strange! see $mysql_tmp/README..." >&2 + mv "$targetdir" "$mysql_tmp" + cat << EOF > "$mysql_tmp/README" + +if you're reading this, it's most likely because you had replaced /var/lib/mysql +with a symlink, then upgraded to a new version of mysql, and then dpkg +removed your symlink (see #182747 and others). the mysql packages noticed +that this happened, and as a workaround have restored it. however, because +/var/lib/mysql seems to have been re-created in the meantime, and because +we don't want to rm -rf something we don't know as much about, we're going +to leave this unexpected directory here. if your database looks normal, +and this is not a symlink to your database, you should be able to blow +this all away. + +EOF + fi + fi + rmdir $mysql_upgradedir 2>/dev/null || true + done + + # Ensure the existence and right permissions for the database and + # log files. + if [ ! -d "$mysql_statedir" -a ! -L "$mysql_statedir" ]; then mkdir "$mysql_statedir"; fi + if [ ! -d "$mysql_statedir/mysql" -a ! -L "$mysql_statedir/mysql" ]; then mkdir "$mysql_statedir/mysql"; fi + if [ ! -d "$mysql_newlogdir" -a ! -L "$mysql_newlogdir" ]; then mkdir "$mysql_newlogdir"; fi + # When creating an ext3 jounal on an already mounted filesystem like e.g. + # /var/lib/mysql, you get a .journal file that is not modifyable by chown. + # The mysql_datadir must not be writable by the mysql user under any + # circumstances as it contains scripts that are executed by root. + set +e + chown -R 0:0 $mysql_datadir + chown -R mysql $mysql_statedir + chown -R mysql $mysql_rundir + chown -R mysql:adm $mysql_newlogdir; chmod 2750 $mysql_newlogdir; + for i in log err; do + touch $mysql_logdir/mysql.$i + chown mysql:adm $mysql_logdir/mysql.$i + chmod 0640 $mysql_logdir/mysql.$i + done + set -e + + # This is important to avoid dataloss when there is a removed + # mysql-server version from Woody lying around which used the same + # data directory and then somewhen gets purged by the admin. + db_set mysql-server/postrm_remove_database false || true + + # To avoid downgrades. + touch $mysql_statedir/debian-5.5.flag + + # initiate databases. Output is not allowed by debconf :-( + # This will fail if we are upgrading an existing database; in this case + # mysql_upgrade, called from the /etc/init.d/mysql start script, will + # handle things. + # Debian: beware of the bashisms... + # Debian: can safely run on upgrades with existing databases + set +e + /bin/bash /usr/bin/mysql_install_db --rpm --user=mysql 2>&1 | $ERR_LOGGER + set -e + + ## On every reconfiguration the maintenance user is recreated. + # + # - It is easier to regenerate the password every time but as people + # use fancy rsync scripts and file alteration monitors, the existing + # password is used and existing files not touched. + # - The mysqld statement is like that in mysql_install_db because the + # server is not already running. This has some implications: + # - The amount of newlines and semicolons in the query is important! + # - GRANT is not possible with --skip-grant-tables and "INSERT + # (user,host..) VALUES" is not --ansi compliant + # - The echo is just for readability. ash's buildin has no "-e" so use /bin/echo. + # - The Super_priv, Show_db_priv, Create_tmp_table_priv and Lock_tables_priv + # may not be present as old Woody 3.23 databases did not have it and the + # admin might not already have run mysql_upgrade which adds them. + # As the binlog cron scripts to need at least the Super_priv, I do first + # the old query which always succeeds and then the new which may or may not. + + # recreate the credentials file if not present or without mysql_upgrade stanza + dc=$mysql_cfgdir/debian.cnf; + if [ -e "$dc" -a -n "`fgrep mysql_upgrade $dc 2>/dev/null`" ]; then + pass="`sed -n 's/^[ ]*password *= *// p' $dc | head -n 1`" + else + pass=`perl -e 'print map{("a".."z","A".."Z",0..9)[int(rand(62))]}(1..16)'`; + if [ ! -d "$mysql_cfgdir" ]; then install -o 0 -g 0 -m 0755 -d $mysql_cfgdir; fi + cat /dev/null > $dc + echo "# Automatically generated for Debian scripts. DO NOT TOUCH!" >>$dc + echo "[client]" >>$dc + echo "host = localhost" >>$dc + echo "user = debian-sys-maint" >>$dc + echo "password = $pass" >>$dc + echo "socket = $mysql_rundir/mysqld.sock" >>$dc + echo "[mysql_upgrade]" >>$dc + echo "host = localhost" >>$dc + echo "user = debian-sys-maint" >>$dc + echo "password = $pass" >>$dc + echo "socket = $mysql_rundir/mysqld.sock" >>$dc + echo "basedir = /usr" >>$dc + fi + # If this dir chmod go+w then the admin did it. But this file should not. + chown 0:0 $dc + chmod 0600 $dc + + # update privilege tables + password_column_fix_query=`/bin/echo -e \ + "USE mysql\n" \ + "ALTER TABLE user CHANGE Password Password char(41) character set latin1 collate latin1_bin DEFAULT '' NOT NULL"`; + replace_query=`/bin/echo -e \ + "USE mysql\n" \ + "SET sql_mode='';\n" \ + "REPLACE INTO user SET " \ + " host='localhost', user='debian-sys-maint', password=password('$pass'), " \ + " Select_priv='Y', Insert_priv='Y', Update_priv='Y', Delete_priv='Y', " \ + " Create_priv='Y', Drop_priv='Y', Reload_priv='Y', Shutdown_priv='Y', " \ + " Process_priv='Y', File_priv='Y', Grant_priv='Y', References_priv='Y', " \ + " Index_priv='Y', Alter_priv='Y', Super_priv='Y', Show_db_priv='Y', "\ + " Create_tmp_table_priv='Y', Lock_tables_priv='Y', Execute_priv='Y', "\ + " Repl_slave_priv='Y', Repl_client_priv='Y', Create_view_priv='Y', "\ + " Show_view_priv='Y', Create_routine_priv='Y', Alter_routine_priv='Y', "\ + " Create_user_priv='Y', Event_priv='Y', Trigger_priv='Y',"\ + " ssl_cipher='', x509_issuer='', x509_subject='';"`; + # Engines supported by etch should be installed per default. The query sequence is supposed + # to be aborted if the CREATE TABLE fails due to an already existent table in which case the + # admin might already have chosen to remove one or more plugins. Newlines are necessary. + install_plugins=`/bin/echo -e \ + "USE mysql;\n" \ + "CREATE TABLE plugin (name char(64) COLLATE utf8_bin NOT NULL DEFAULT '', " \ + " dl char(128) COLLATE utf8_bin NOT NULL DEFAULT '', " \ + " PRIMARY KEY (name)) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='MySQL plugins';" ` + + # Upgrade password column format before the root password gets set. + echo "$password_column_fix_query" | $MYSQL_BOOTSTRAP 2>&1 | $ERR_LOGGER + + db_get mysql-server/root_password && rootpw="$RET" + if ! set_mysql_rootpw; then + password_error="yes" + fi + + set +e + echo "$replace_query" | $MYSQL_BOOTSTRAP 2>&1 | $ERR_LOGGER + echo "$install_plugins" | $MYSQL_BOOTSTRAP 2>&1 | $ERR_LOGGER + set -e + ;; + + abort-upgrade|abort-remove|abort-configure) + ;; + + *) + echo "postinst called with unknown argument '$1'" 1>&2 + exit 1 + ;; +esac + +# here we check to see if we can connect as root without a password +# this should catch upgrades from previous versions where the root +# password wasn't set. if there is a password, or if the connection +# fails for any other reason, nothing happens. +if [ "$1" = "configure" ]; then + if test_mysql_access; then + db_input medium mysql-server/root_password || true + db_go + db_get mysql-server/root_password && rootpw="$RET" + + if ! set_mysql_rootpw "online"; then + password_error="yes" + fi + fi + + if [ "$password_error" = "yes" ]; then + db_input high mysql-server/error_setting_password || true + db_go + fi + +fi + +db_stop # in case invoke failes + +#DEBHELPER# + +exit 0 diff --git a/debian/dist/Debian/mariadb-server-5.5.postrm b/debian/dist/Debian/mariadb-server-5.5.postrm new file mode 100644 index 00000000000..469b1627aff --- /dev/null +++ b/debian/dist/Debian/mariadb-server-5.5.postrm @@ -0,0 +1,83 @@ +#!/bin/bash -e + +# It is possible that Debconf has already been removed, too. +if [ -f /usr/share/debconf/confmodule ]; then + . /usr/share/debconf/confmodule +fi + +if [ -n "$DEBIAN_SCRIPT_DEBUG" ]; then set -v -x; DEBIAN_SCRIPT_TRACE=1; fi +${DEBIAN_SCRIPT_TRACE:+ echo "#42#DEBUG# RUNNING $0 $*" 1>&2 } + +MYADMIN="/usr/bin/mysqladmin --defaults-file=/etc/mysql/debian.cnf" + +# Try to stop the server in a sane way. If it does not success let the admin +# do it himself. No database directories should be removed while the server +# is running! +stop_server() { + set +e + if [ -x /usr/sbin/invoke-rc.d ]; then + invoke-rc.d mysql stop + else + /etc/init.d/mysql stop + fi + errno=$? + set -e + + if [ "$?" != 0 ]; then + echo "Trying to stop the MySQL server resulted in exitcode $?." 1>&2 + echo "Stop it yourself and try again!" 1>&2 + exit 1 + fi +} + +case "$1" in + purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) + if [ -n "`$MYADMIN ping 2>/dev/null`" ]; then + stop_server + sleep 2 + fi + ;; + *) + echo "postrm called with unknown argument '$1'" 1>&2 + exit 1 + ;; +esac + +# +# - Do NOT purge logs or data if another mysql-sever* package is installed (#307473) +# - Remove the mysql user only after all his owned files are purged. +# +if [ "$1" = "purge" -a ! \( -x /usr/sbin/mysqld -o -L /usr/sbin/mysqld \) ]; then + # we remove the mysql user only after all his owned files are purged + rm -f /var/log/mysql.{log,err}{,.0,.[1234567].gz} + rm -rf /var/log/mysql + + db_input high mysql-server-5.1/postrm_remove_databases || true + db_go || true + db_get mysql-server-5.1/postrm_remove_databases || true + if [ "$RET" = "true" ]; then + # never remove the debian.cnf when the databases are still existing + # else we ran into big trouble on the next install! + rm -f /etc/mysql/debian.cnf + rm -rf /var/lib/mysql + rm -rf /var/run/mysqld + userdel mysql || true + fi + + # (normally) Automatically added by dh_installinit + if [ "$1" = "purge" ] ; then + update-rc.d mysql remove >/dev/null || exit 0 + fi + # (normally) End automatically added section +fi + +# (normally) Automatically added by dh_installdebconf +if [ "$1" = purge ] && [ -e /usr/share/debconf/confmodule ]; then + . /usr/share/debconf/confmodule + db_purge +fi +# (normally) End automatically added section + +# no DEBHELPER here, "update-rc.d remove" fails if mysql-server-5.1 is installed + +exit 0 diff --git a/debian/dist/Debian/rules b/debian/dist/Debian/rules new file mode 100755 index 00000000000..58d0c268ca3 --- /dev/null +++ b/debian/dist/Debian/rules @@ -0,0 +1,294 @@ +#!/usr/bin/make -f + +export DH_VERBOSE=1 +export DEB_BUILD_HARDENING=1 + +PACKAGE=mariadb-5.5 + +include /usr/share/dpatch/dpatch.make + +TMP=$(CURDIR)/debian/tmp/ + +ARCH = $(shell dpkg-architecture -qDEB_BUILD_ARCH) +ARCH_OS = $(shell dpkg-architecture -qDEB_BUILD_ARCH_OS) +DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE) +DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) +DEBVERSION = $(shell dpkg-parsechangelog | awk '/^Version: / { print $$2 }' | sed 's/^.*-//' ) + +DEB_SOURCE_PACKAGE ?= $(strip $(shell egrep '^Source: ' debian/control | cut -f 2 -d ':')) +DEB_VERSION ?= $(shell dpkg-parsechangelog | egrep '^Version:' | cut -f 2 -d ' ') +DEB_NOEPOCH_VERSION ?= $(shell echo $(DEB_VERSION) | cut -d: -f2-) +DEB_UPSTREAM_VERSION ?= $(shell echo $(DEB_NOEPOCH_VERSION) | sed 's/-[^-]*$$//') +DEB_UPSTREAM_VERSION_MAJOR_MINOR := $(shell echo $(DEB_UPSTREAM_VERSION) | sed -r -n 's/^([0-9]+\.[0-9]+).*/\1/p') + +DISTRIBUTION = $(shell lsb_release -i -s) +RELEASE = $(shell lsb_release -r -s | sed 's/\..*//' ) + +MAKE_J = -j$(shell if [ -f /proc/cpuinfo ] ; then grep -c processor.* /proc/cpuinfo ; else echo 1 ; fi) +ifeq (${MAKE_J}, -j0) + MAKE_J = -j1 +endif + +MAKE_TEST_TARGET=test-force +ifneq ($(findstring fulltest,$(DEB_BUILD_OPTIONS)),) +# make test-bt is the testsuite run by the MySQL build team +# before a release, but it is long + MAKE_TEST_TARGET=test-bt +endif + +USE_ASSEMBLER=--enable-assembler + +ifneq (,$(filter $(ARCH), amd64 i386 ia64 s390)) + TESTSUITE_FAIL_CMD=exit 1 +else + TESTSUITE_FAIL_CMD=true +endif + +BUILDDIR = builddir +builddir = $(BUILDDIR) + +# This causes seg11 crashes if LDAP is used for groups in /etc/nsswitch.conf +# so it is disabled by default although, according to MySQL, it brings >10% +# performance gain if enabled. See #299382. +ifeq ($(STATIC_MYSQLD), 1) + USE_STATIC_MYSQLD=--with-mysqld-ldflags=-all-static +endif + +configure: patch configure-stamp +configure-stamp: + @echo "RULES.$@" + dh_testdir + +ifneq ($(ARCH_OS),hurd) + if [ ! -d /proc/self ]; then echo "/proc IS NEEDED" 1>&2; exit 1; fi +endif + + ( test -d $(builddir) || mkdir $(builddir) ) && cd $(builddir) && \ + sh -c 'PATH=$${MYSQL_BUILD_PATH:-"/bin:/usr/bin"} \ + CC=$${MYSQL_BUILD_CC:-gcc} \ + CFLAGS=$${MYSQL_BUILD_CFLAGS:-"-O2 -fno-omit-frame-pointer -g -pipe -Wall -Wno-uninitialized"} \ + CXX=$${MYSQL_BUILD_CXX:-g++} \ + CXXFLAGS=$${MYSQL_BUILD_CXXFLAGS:-"-O2 -fno-omit-frame-pointer -g -pipe -Wall -Wno-uninitialized"} \ + cmake .. \ + -DCMAKE_INSTALL_PREFIX=/usr \ + -DINSTALL_SBINDIR=sbin \ + -DMYSQL_DATADIR=/var/lib/mysql \ + -DINSTALL_INCLUDEDIR=include \ + -DINSTALL_INFODIR=share/info \ + -DINSTALL_MANDIR=share/man \ + \ + -DMYSQL_SERVER_SUFFIX="-$(DEBVERSION)" \ + -DWITH_COMMENT="(MariaDB - http://mariadb.com/)" \ + -DSYSTEM_TYPE="debian-linux-gnu" \ + -DINSTALL_LAYOUT=DEB \ + \ + -DENABLED_LOCAL_INFILE=1 \ + -DWITH_FAST_MUTEXES=1 \ + \ + -DMYSQL_UNIX_ADDR=/var/run/mysqld/mysqld.sock \ + -DMYSQL_USER=mysql \ + \ + -DEXTRA_CHARSETS=all \ + -DWITH_LIBWRAP=1 \ + -DWITH_SSL=system \ + -DWITH_ZLIB=system \ + -DWITH_EMBEDDED_SERVER=1 \ + -DHAVE_EMBEDDED_PRIVILEGE_CONTROL=ON \ + -DWITH_MAX=1' + + touch $@ + +build: build-stamp + +build-stamp: configure + @echo "RULES.$@" + dh_testdir + + cd $(builddir) && $(MAKE) $(MAKE_J) + +ifeq ($(findstring nocheck,$(DEB_BUILD_OPTIONS)),) + # Don't know why the following is necessary... + cp unittest/unit.pl $(builddir)/unittest/ + cp -r mysql-test/* $(builddir)/mysql-test/ + cp -r sql/share/* $(builddir)/sql/share/ + cp -r scripts/*sql $(builddir)/scripts/ + if [ ! -f testsuite-stamp ] ; then \ + cd $(builddir) && $(MAKE) $(MAKE_TEST_TARGET) || $(TESTSUITE_FAIL_CMD) ; \ + fi +endif + + touch testsuite-stamp + + touch build-stamp + +clean: clean-patched unpatch + rm -rf debian/patched +clean-patched: + @echo "RULES.clean-patched" + dh_testdir + dh_testroot + rm -f configure-stamp* + rm -f build-stamp* + rm -f testsuite-stamp + # + [ ! -f Makefile ] || $(MAKE) clean + [ ! -d mysql-test/var ] || rm -rf mysql-test/var + # + rm -rf $(BUILDDIR) + + debconf-updatepo + dh_clean -v + + +install: build + @echo "RULES.$@" + dh_testdir + dh_testroot + dh_clean -k + dh_installdirs + + # some self written manpages which hopefully + # gets overwritten sooner or later with upstreams + mkdir -p $(TMP)/usr/share/man/man1/ + mkdir -p $(TMP)/usr/share/man/man8/ + cp debian/additions/*.1 $(TMP)/usr/share/man/man1/ + mkdir -p $(TMP)/etc/mysql/conf.d/ + cp debian/additions/mysqld_safe_syslog.cnf $(TMP)/etc/mysql/conf.d/ + + # make install (trailing slash needed for innobase) + cd $(builddir) && $(MAKE) install DESTDIR=$(TMP)/ + # + # After installing, remove rpath to make lintian happy. + set +e; \ + find ./debian/tmp/ -type f -print0 \ + | xargs -0 --no-run-if-empty chrpath -k 2>/dev/null \ + | fgrep RPATH= \ + | cut -d: -f 1 \ + | xargs --no-run-if-empty chrpath -d; \ + set -e + + # libmysqlclient-dev: forgotten header file since 3.23.25? + cp $(BUILDDIR)/include/my_config.h $(TMP)/usr/include/mysql/ + cp include/my_dir.h $(TMP)/usr/include/mysql/ + + # mysql-common: We now provide our own config file. + # can't be mariadb-common, other packages insist + install -d $(TMP)/etc/mysql + install -m 0644 debian/additions/my.cnf $(TMP)/etc/mysql/my.cnf + + # mariadb-client + install -m 0755 debian/additions/mysqlreport $(TMP)/usr/bin/ + install -m 0755 debian/additions/innotop/innotop $(TMP)/usr/bin/ + install -m 0644 debian/additions/innotop/innotop.1 $(TMP)/usr/share/man/man1/ + + # mariadb-server + install -m 0755 $(BUILDDIR)/scripts/mysqld_safe $(TMP)/usr/bin/mysqld_safe + mkdir -p $(TMP)/usr/share/doc/mariadb-server-5.5/examples + # We have a sane my.cnf, cruft not needed (remove my-*.cnf and config-*.cnf) + # $(TMP)/usr/share/mysql/*cnf $(TMP)/usr/share/doc/mariadb-server-5.3/examples/ + rm -vf $(TMP)/usr/share/mysql/my-*.cnf \ + $(TMP)/usr/share/mysql/config-*.cnf \ + $(TMP)/usr/share/mysql/mi_test_all* \ + $(TMP)/usr/share/mysql/mysql-log-rotate \ + $(TMP)/usr/share/mysql/mysql.server \ + $(TMP)/usr/share/mysql/binary-configure + nm -n $(BUILDDIR)/sql/mysqld |gzip -9 > $(TMP)/usr/share/doc/mariadb-server-5.5/mysqld.sym.gz + install -m 0755 debian/additions/echo_stderr $(TMP)/usr/share/mysql/ + install -m 0755 debian/additions/debian-start $(TMP)/etc/mysql/ + install -m 0755 debian/additions/debian-start.inc.sh $(TMP)/usr/share/mysql/ + + # mariadb-test + mv $(TMP)/usr/mysql-test $(TMP)/usr/share/mysql + + # lintian overrides + mkdir -p $(TMP)/usr/share/lintian/overrides/ + cp debian/mysql-common.lintian-overrides $(TMP)/usr/share/lintian/overrides/mysql-common + cp debian/mariadb-server-5.5.lintian-overrides $(TMP)/usr/share/lintian/overrides/mariadb-server-5.5 + cp debian/mariadb-client-5.5.lintian-overrides $(TMP)/usr/share/lintian/overrides/mariadb-client-5.5 + + # For 5.0 -> 5.5 transition + d=$(TMP)/usr/share/mysql-common/internal-use-only/; \ + mkdir -p $$d; \ + cp debian/mariadb-server-5.5.mysql.init $$d/_etc_init.d_mysql; \ + cp debian/mariadb-server-5.5.mysql-server.logrotate $$d/_etc_logrotate.d_mysql-server; \ + cp debian/additions/debian-start $$d/_etc_mysql_debian-start; + + dh_movefiles + +# Build architecture-independent files here. +binary-indep: build install + @echo "RULES.binary-indep" + dh_testdir -i + dh_testroot -i + dh_installdebconf -i + dh_installdocs -i + dh_installexamples -i + dh_installmenu -i + dh_installlogrotate -i + dh_installinit -i + dh_installcron -i + dh_installman -i + dh_installinfo -i + dh_installlogcheck -i + dh_installchangelogs -i + dh_link -i + dh_compress -i + dh_fixperms -i + dh_installdeb -i + dh_perl -i + dh_gencontrol -i + dh_md5sums -i + dh_builddeb -i + +# Build architecture-dependent files here. +binary-arch: build install + @echo "RULES.binary-arch" + dh_testdir + dh_testroot + + dh_installdebconf -a + dh_installdocs -a + dh_installexamples -a + dh_installmenu -a + dh_installlogrotate -a --name mysql-server + # Start mysql in runlevel 19 before 20 where apache, proftpd etc gets + # started which might depend on a running database server. + dh_installinit -a --name=mysql -- defaults 19 21 + dh_installcron -a --name mysql-server + dh_installman -a + dh_installinfo -a + dh_installlogcheck -a + dh_installchangelogs -a + dh_strip -a + dh_link -a # .so muss nach .so.1.2.3 installier werden! + dh_compress -a + dh_fixperms -a + dh_makeshlibs -a + dh_makeshlibs -plibmariadbclient18 -V'libmariadbclient18 (>= 5.5.1-1)' + dh_installdeb -a + dh_perl -a + dh_shlibdeps -a -l debian/libmariadbclient18/usr/lib -L libmariadbclient18 + dh_gencontrol -a + dh_md5sums -a + dh_builddeb -a + +source diff: + @echo >&2 'source and diff are obsolete - use dpkg-source -b'; false + +binary: binary-indep binary-arch + +get-orig-source: + @wget -nv -T10 -t3 \ + -O /tmp/mysql-$(DEB_UPSTREAM_VERSION).tar.gz \ + http://ftp.gwdg.de/pub/misc/mysql/Downloads/MySQL-$(DEB_UPSTREAM_VERSION_MAJOR_MINOR)/mysql-$(DEB_UPSTREAM_VERSION).tar.gz + @tar xfz /tmp/mysql-$(DEB_UPSTREAM_VERSION).tar.gz -C /tmp + @rm -rf /tmp/mysql-$(DEB_UPSTREAM_VERSION)/Docs + @rm -rf /tmp/mysql-$(DEB_UPSTREAM_VERSION)/debian + @mv /tmp/mysql-$(DEB_UPSTREAM_VERSION) /tmp/$(DEB_SOURCE_PACKAGE)-$(DEB_UPSTREAM_VERSION).orig + @cd /tmp ; tar czf $(DEB_SOURCE_PACKAGE)_$(DEB_UPSTREAM_VERSION).orig.tar.gz $(DEB_SOURCE_PACKAGE)-$(DEB_UPSTREAM_VERSION).orig + @rm -f /tmp/mysql-$(DEB_UPSTREAM_VERSION).tar.gz + @rm -rf /tmp/$(DEB_SOURCE_PACKAGE)-$(DEB_UPSTREAM_VERSION).orig + +.PHONY: clean clean-patched configure build binary binary-indep binary-arch install patch unpatch + +# vim: ts=8 diff --git a/debian/dist/Ubuntu/apparmor-profile b/debian/dist/Ubuntu/apparmor-profile new file mode 100644 index 00000000000..4ffb7eab550 --- /dev/null +++ b/debian/dist/Ubuntu/apparmor-profile @@ -0,0 +1,15 @@ +# This file is intensionally empty to disable apparmor by default for newer +# versions of MariaDB, while providing seamless upgrade from older versions +# and from mysql, where apparmor is used. +# +# By default, we do not want to have any apparmor profile for the MariaDB +# server. It does not provide much useful functionality/security, and causes +# several problems for users who often are not even aware that apparmor +# exists and runs on their system. +# +# Users can modify and maintain their own profile, and in this case it will +# be used. +# +# When upgrading from previous version, users who modified the profile +# will be promptet to keep or discard it, while for default installs +# we will automatically disable the profile. diff --git a/debian/dist/Ubuntu/control b/debian/dist/Ubuntu/control new file mode 100644 index 00000000000..c49d1581cb3 --- /dev/null +++ b/debian/dist/Ubuntu/control @@ -0,0 +1,221 @@ +Source: mariadb-5.5 +Section: misc +Priority: optional +Maintainer: MariaDB Developers +XSBC-Original-Maintainer: Maria Developers +Uploaders: MariaDB Developers +Build-Depends: libtool (>= 1.4.2-7), procps | hurd, debhelper, file (>= 3.28), libncurses5-dev (>= 5.0-6), perl (>= 5.6.0), libwrap0-dev (>= 7.6-8.3), zlib1g-dev (>= 1:1.1.3-5), ${LIBREADLINE_DEV}, libevent-dev, libssl-dev, libpam0g-dev, psmisc, po-debconf, chrpath, automake1.9, doxygen, texlive-latex-base, ghostscript | gs-gpl, dpatch, gawk, bison, lsb-release, hardening-wrapper +Standards-Version: 3.8.2 +Homepage: http://mariadb.org/ +Vcs-Browser: http://bazaar.launchpad.net/~maria-captains/maria/5.5/files +Vcs-Bzr: bzr://lp:maria + +Package: libmariadbclient18 +Section: libs +Architecture: any +Depends: mariadb-common, libmysqlclient18 (= ${source:Version}), ${shlibs:Depends}, ${misc:Depends} +Description: MariaDB database client library + MariaDB is a fast, stable and true multi-user, multi-threaded SQL database + server. SQL (Structured Query Language) is the most popular database query + language in the world. The main goals of MariaDB are speed, robustness and + ease of use. + . + This package includes the client library. + +Package: libmysqlclient18 +Section: libs +Architecture: any +Depends: libmariadbclient18 (= ${source:Version}) +Replaces: libmysqlclient18 (<< ${source:Version}) +Description: Virtual package to satisfy external depends + This is an empty package that provides an updated "best" version of + libmysqlclient18 that does not conflict with the libmariadbclient18 + package. + . + MariaDB is a fast, stable and true multi-user, multi-threaded SQL database + server. SQL (Structured Query Language) is the most popular database query + language in the world. The main goals of MariaDB are speed, robustness and + ease of use. + +Package: libmariadbd-dev +Architecture: any +Section: libdevel +Depends: libmariadbclient-dev (>= ${source:Version}), ${misc:Depends} +Provides: libmysqld-dev +Conflicts: libmysqld-dev +Replaces: libmysqld-dev +Description: MariaDB embedded database development files + MariaDB is a fast, stable and true multi-user, multi-threaded SQL database + server. SQL (Structured Query Language) is the most popular database query + language in the world. The main goals of MariaDB are speed, robustness and + ease of use. + . + This package includes the embedded server library and header files. + +Package: libmariadbclient-dev +Architecture: any +Section: libdevel +Depends: libmariadbclient18 (>= ${source:Version}), zlib1g-dev, , ${shlibs:Depends}, ${misc:Depends} +Replaces: libmariadbclient16-dev, libmysqlclient16-dev +Conflicts: libmysqlclient-dev, libmariadbclient16-dev, libmysqlclient14-dev, libmysqlclient12-dev, libmysqlclient10-dev, libmysqlclient15-dev, libmysqlclient16-dev +Provides: libmysqlclient-dev +Description: MariaDB database development files + MariaDB is a fast, stable and true multi-user, multi-threaded SQL database + server. SQL (Structured Query Language) is the most popular database query + language in the world. The main goals of MariaDB are speed, robustness and + ease of use. + . + This package includes development libraries and header files. + +Package: mysql-common +Section: database +Architecture: all +Depends: ${shlibs:Depends}, ${misc:Depends} +Provides: mariadb-common +Description: MariaDB database common files (e.g. /etc/mysql/my.cnf) + MariaDB is a fast, stable and true multi-user, multi-threaded SQL database + server. SQL (Structured Query Language) is the most popular database query + language in the world. The main goals of MariaDB are speed, robustness and + ease of use. + . + This package includes files needed by all versions of the client library + (e.g. /etc/mysql/my.cnf). + . + Due to libmysqlclient15off package depends, this package has not yet been + renamed to mariadb-common. It does, however, already contain a new my.cnf + file with mariadb-specific configuration options. + +Package: mariadb-client-core-5.5 +Architecture: any +Depends: mariadb-common, libmariadbclient18 (>= ${source:Version}), ${shlibs:Depends}, ${misc:Depends} +Provides: mysql-client-core, mysql-client-core-5.1, mysql-client-core-5.5 +Conflicts: mysql-client (<< 5.0.51), mysql-client-5.0, mysql-client-5.1, mysql-client-5.5, + mysql-client-core-5.1, mysql-client-core-5.5, + mariadb-client-5.1, mariadb-client-core-5.1, + mariadb-client-5.2, mariadb-client-core-5.2, + mariadb-client-5.3, mariadb-client-core-5.3 +Replaces: mysql-client (<< 5.0.51), mysql-client-5.0, mysql-client-5.1, mysql-client-5.5, + mysql-client-core-5.1, mysql-client-core-5.5, + mariadb-client-5.1, mariadb-client-core-5.1, + mariadb-client-5.2, mariadb-client-core-5.2, + mariadb-client-5.3, mariadb-client-core-5.3 +Description: MariaDB database core client binaries + MariaDB is a fast, stable and true multi-user, multi-threaded SQL database + server. SQL (Structured Query Language) is the most popular database query + language in the world. The main goals of MariaDB are speed, robustness and + ease of use. + . + This package includes the core client files, as used by Akonadi. + +Package: mariadb-client-5.5 +Architecture: any +Depends: debianutils (>=1.6), libdbi-perl, libdbd-mysql-perl (>= 1.2202), mariadb-common, libmariadbclient18 (>= ${source:Version}), mariadb-client-core-5.5 (>= ${source:Version}), ${perl:Depends}, ${shlibs:Depends}, ${misc:Depends} +Provides: virtual-mysql-client, mysql-client, + mysql-client-4.1, mysql-client-5.1, mysql-client-5.5 +Conflicts: mysql-client (<< 5.0.51), mysql-client-5.0, mysql-client-5.1, + mariadb-client (<< ${source:Version}), + mariadb-client-5.1, mariadb-client-5.2, mariadb-client-5.3 +Replaces: mysql-client (<< 5.0.51), mysql-client-5.0, mysql-client-5.1, + mariadb-client (<< ${source:Version}), + mariadb-client-5.1, mariadb-client-5.2, mariadb-client-5.3 +Description: MariaDB database client binaries + MariaDB is a fast, stable and true multi-user, multi-threaded SQL database + server. SQL (Structured Query Language) is the most popular database query + language in the world. The main goals of MariaDB are speed, robustness and + ease of use. + . + This package includes the client binaries and the additional tools + innotop and mysqlreport. + +Package: mariadb-server-core-5.5 +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, libmariadbclient18 (>= ${binary:Version}) +Provides: mysql-server-core, mysql-server-core-5.1, mysql-server-core-5.5 +Conflicts: mysql-server-5.0, + mysql-server-core-5.0, mysql-server-core-5.1, mysql-server-core-5.5, + mariadb-server-core-5.1, mariadb-server-core-5.2, mariadb-server-core-5.5 +Replaces: mysql-server-5.0, + mysql-server-core-5.0, mysql-server-core-5.1, mysql-server-core-5.5, + mariadb-server-core-5.1, mariadb-server-core-5.2, mariadb-server-core-5.5 +Description: MariaDB database core server files + MariaDB is a fast, stable and true multi-user, multi-threaded SQL database + server. SQL (Structured Query Language) is the most popular database query + language in the world. The main goals of MariaDB are speed, robustness and + ease of use. + . + This package includes the core server files, as used by Akonadi. + +Package: mariadb-test-5.5 +Section: database +Architecture: all +Depends: mariadb-server-5.5 (= ${source:Version}), mariadb-client-5.5 (= ${source:Version}) +Conflicts: mariadb-test (<< ${source:Version}), + mariadb-test-5.1, mariadb-test-5.2, mariadb-test-5.3 +Replaces: mariadb-test (<< ${source:Version}), + mariadb-test-5.1, mariadb-test-5.2, mariadb-test-5.3 +Description: MariaDB database regression test suite + MariaDB is a fast, stable and true multi-user, multi-threaded SQL database + server. SQL (Structured Query Language) is the most popular database query + language in the world. The main goals of MariaDB are speed, robustness and + ease of use. + . + This package includes the regression test suite. + +Package: mariadb-server-5.5 +Architecture: any +Suggests: tinyca, mailx, mariadb-test +Recommends: libhtml-template-perl +Pre-Depends: mariadb-common, adduser (>= 3.40), debconf +Depends: mariadb-client-5.5 (>= ${source:Version}), libdbi-perl, perl (>= 5.6), ${shlibs:Depends}, ${misc:Depends}, psmisc, passwd, lsb-base (>= 3.0-10), mariadb-server-core-5.5 (>= ${binary:Version}) +Provides: mariadb-server, mysql-server, virtual-mysql-server +Conflicts: mariadb-server (<< ${source:Version}), mysql-server (<< ${source:Version}), + mysql-server-4.1, mysql-server-5.0, mysql-server-5.1, + mariadb-server-5.1, mariadb-server-5.2, mariadb-server-5.3, + libmariadbclient16 (<< 5.3.4) +Replaces: mariadb-server (<< ${source:Version}), mysql-server (<< ${source:Version}), + mysql-server-4.1, mysql-server-5.0, mysql-server-5.1, + mariadb-server-5.1, mariadb-server-5.2, mariadb-server-5.3, + libmariadbclient16 (<< 5.3.4), + libmariadbclient-dev (<< 5.5.0) +Description: MariaDB database server binaries + MariaDB is a fast, stable and true multi-user, multi-threaded SQL database + server. SQL (Structured Query Language) is the most popular database query + language in the world. The main goals of MariaDB are speed, robustness and + ease of use. + . + This package includes the server binaries. + +Package: mariadb-server +Section: database +Architecture: all +Depends: mariadb-server-5.5, ${misc:Depends} +Description: MariaDB database server (metapackage depending on the latest version) + This is an empty package that depends on the current "best" version of + mariadb-server (currently mariadb-server-5.5), as determined by the MariaDB + maintainers. Install this package if in doubt about which MariaDB + version you need. That will install the version recommended by the + package maintainers. + . + MariaDB is a fast, stable and true multi-user, multi-threaded SQL database + server. SQL (Structured Query Language) is the most popular database query + language in the world. The main goals of MariaDB are speed, robustness and + ease of use. + +Package: mariadb-client +Section: database +Architecture: all +Depends: mariadb-client-5.5, ${misc:Depends} +Description: MariaDB database client (metapackage depending on the latest version) + This is an empty package that depends on the current "best" version of + mariadb-client (currently mariadb-client-5.5), as determined by the MariaDB + maintainers. Install this package if in doubt about which MariaDB version + you want, as this is the one we consider to be in the best shape. + +Package: mariadb-test +Section: database +Architecture: all +Depends: mariadb-test-5.5 +Description: MariaDB database regression test suite (metapackage depending on the latest version) + This is an empty package that depends on the current "best" version of + mariadb-test (currently mariadb-test-5.5), as determined by the MariaDB + maintainers. diff --git a/debian/dist/Ubuntu/mariadb-server-5.5.README.Debian b/debian/dist/Ubuntu/mariadb-server-5.5.README.Debian new file mode 100644 index 00000000000..741243f1ec3 --- /dev/null +++ b/debian/dist/Ubuntu/mariadb-server-5.5.README.Debian @@ -0,0 +1,109 @@ +* MYSQL WON'T START OR STOP?: +============================= +You may never ever delete the special mysql user "debian-sys-maint". This +user together with the credentials in /etc/mysql/debian.cnf are used by the +init scripts to stop the server as they would require knowledge of the mysql +root users password else. +So in most of the times you can fix the situation by making sure that the +debian.cnf file contains the right password, e.g. by setting a new one +(remember to do a "flush privileges" then). + +* WHAT TO DO AFTER UPGRADES: +============================ +The privilege tables are automatically updated so all there is left is read +the changelogs on dev.mysql.com to see if any changes affect custom apps. + +* WHAT TO DO AFTER INSTALLATION: +================================ +The MySQL manual describes certain steps to do at this stage in a separate +chapter. They are not necessary as the Debian packages does them +automatically. + +The only thing that is left over for the admin is + - setting the passwords + - creating new users and databases + - read the rest of this text + +* DOWNGRADING TO 4.0 or 4.1: +============================ +Unsupported. Period. +But if you do and get problems or make interesting experiences, mail me, it +might help others. +Ok, if you really want, I would recommend to "mysqldump --opt" all tables, +then purge 4.1, delete /var/lib/mysql, install 4.0 and insert the dumps. Be +carefully, though, with the "mysql" table, you might not simply overwrite that +one as the password for the mysql "debian-sys-maint" user is stored in +/etc/mysql/debian.cnf and needed by /etc/init.d/ to start mysql and check if +it's alive. + +* SOME APPLICATION CAN NO LONGER CONNECT: +========================================= +This application is probably linked against libmysqlclient12 or below and +somebody has created a mysql user with new-style passwords. +The old_passwords=1 option in /etc/mysql/my.cnf might help. If not the +application that inserted the user has to be changed or the application that +tries to connect updated to libmysqlclient14 or -15. + +* NETWORKING: +============= +For security reasons, the Debian package has enabled networking only on the +loop-back device using "bind-address" in /etc/mysql/my.cnf. Check with +"netstat -tlnp" where it is listening. If your connection is aborted +immediately see if "mysqld: all" or similar is in /etc/hosts.allow and read +hosts_access(5). + +* WHERE IS THE DOCUMENTATION?: +============================== +Unfortunately due to licensing restrictions, debian currently not able +to provide the mysql-doc package in any format. For the most up to date +documentation, please go to http://dev.mysql.com/doc. + +* PASSWORDS: +============ +It is strongly recommended to set a password for the mysql root user (which + /usr/bin/mysql -u root -D mysql -e "update user set password=password('new-password') where user='root'" + /usr/bin/mysql -u root -e "flush privileges" +If you already had a password set add "-p" before "-u" to the lines above. + + +If you are tired to type the password in every time or want to automate your +scripts you can store it in the file $HOME/.my.cnf. It should be chmod 0600 +(-rw------- username username .my.cnf) to ensure that nobody else can read +it. Every other configuration parameter can be stored there, too. You will +find an example below and more information in the MySQL manual in +/usr/share/doc/mysql-doc or www.mysql.com. + +ATTENTION: It is necessary, that a .my.cnf from root always contains a "user" +line wherever there is a "password" line, else, the Debian maintenance +scripts, that use /etc/mysql/debian.cnf, will use the username +"debian-sys-maint" but the password that is in root's .my.cnf. Also note, +that every change you make in the /root/.my.cnf will affect the mysql cron +script, too. + + # an example of $HOME/.my.cnf + [client] + user = your-mysql-username + password = enter-your-good-new-password-here + +* BIG_ROWS FOR EVEN MORE ROWS IN A TABLE: +========================================= +If you ever run out of rows in a table there is the possibility of building +the package with "-DBIG_ROWS" which, according to a MySQL employee on +packagers@lists.mysql.com should lead to a 64bit row index (I guess > 2^32 +rows) but also to an approx. 5% performance loss. + +* BerkeleyDB Storage Engine +=========================== +Support for BerkeleyDB has been removed in 5.1, and consequently both the +have-bdb and skip-bdb configuration options will cause the server to fail. +Removing the options from /etc/mysql/my.cnf will fix this problem. + +* FURTHER NOTES ON REPLICATION +=============================== +If the MySQL server is acting as a replication slave, you should not +set --tmpdir to point to a directory on a memory-based filesystem or to +a directory that is cleared when the server host restarts. A replication +slave needs some of its temporary files to survive a machine restart so +that it can replicate temporary tables or LOAD DATA INFILE operations. If +files in the temporary file directory are lost when the server restarts, +replication fails. diff --git a/debian/dist/Ubuntu/mariadb-server-5.5.dirs b/debian/dist/Ubuntu/mariadb-server-5.5.dirs new file mode 100644 index 00000000000..40b789231e0 --- /dev/null +++ b/debian/dist/Ubuntu/mariadb-server-5.5.dirs @@ -0,0 +1,10 @@ +etc/init.d +etc/logrotate.d +etc/mysql/conf.d +usr/bin +usr/sbin +usr/share/man/man8 +usr/share/mysql +usr/share/doc/mariadb-server-5.3 +var/run/mysqld +var/lib/mysql-upgrade diff --git a/debian/dist/Ubuntu/mariadb-server-5.5.files b/debian/dist/Ubuntu/mariadb-server-5.5.files new file mode 100644 index 00000000000..13d1dc074d0 --- /dev/null +++ b/debian/dist/Ubuntu/mariadb-server-5.5.files @@ -0,0 +1,63 @@ +usr/lib/mysql/plugin/ +usr/lib/libhsclient.so.* +etc/apparmor.d/usr.sbin.mysqld +usr/share/apport/package-hooks/source_mariadb-5.5.py +etc/mysql/debian-start +etc/mysql/conf.d/mysqld_safe_syslog.cnf +usr/bin/msql2mysql +usr/bin/my_print_defaults +usr/bin/myisamchk +usr/bin/myisam_ftdump +usr/bin/myisamlog +usr/bin/myisampack +usr/bin/aria_pack +usr/bin/aria_read_log +usr/bin/aria_ftdump +usr/bin/aria_chk +usr/bin/aria_dump_log +usr/bin/mysql_convert_table_format +usr/bin/mysql_install_db +usr/bin/mysql_secure_installation +usr/bin/mysql_setpermission +usr/bin/mysql_tzinfo_to_sql +usr/bin/mysql_upgrade +usr/bin/mysql_zap +usr/bin/mysqlbinlog +usr/bin/mysqld_multi +usr/bin/mysqld_safe +usr/bin/mysqlhotcopy +usr/bin/perror +usr/bin/replace +usr/bin/resolve_stack_dump +usr/bin/resolveip +usr/share/doc/mariadb-server-5.5/mysqld.sym.gz +usr/share/lintian/overrides/mariadb-server-5.5 +usr/share/man/man1/msql2mysql.1 +usr/share/man/man1/myisamchk.1 +usr/share/man/man1/myisam_ftdump.1 +usr/share/man/man1/myisamlog.1 +usr/share/man/man1/myisampack.1 +usr/share/man/man1/my_print_defaults.1 +usr/share/man/man1/mysqlbinlog.1 +usr/share/man/man1/mysql_convert_table_format.1 +usr/share/man/man1/mysqld_multi.1 +usr/share/man/man1/mysqld_safe.1 +usr/share/man/man1/mysqlhotcopy.1 +usr/share/man/man1/mysql_install_db.1 +usr/share/man/man1/mysql_secure_installation.1 +usr/share/man/man1/mysql_setpermission.1 +usr/share/man/man1/mysql_upgrade.1 +usr/share/man/man1/mysql_zap.1 +usr/share/man/man1/perror.1 +usr/share/man/man1/replace.1 +usr/share/man/man1/resolveip.1 +usr/share/man/man1/resolve_stack_dump.1 +usr/share/man/man1/innochecksum.1 +usr/share/man/man1/mysql_tzinfo_to_sql.1 +usr/share/mysql/debian-start.inc.sh +usr/share/mysql/echo_stderr +usr/share/mysql/errmsg.txt +usr/share/mysql/fill_help_tables.sql +usr/share/mysql/mysql_system_tables_data.sql +usr/share/mysql/mysql_system_tables.sql +usr/share/mysql/mysql_test_data_timezone.sql diff --git a/debian/dist/Ubuntu/mariadb-server-5.5.postinst b/debian/dist/Ubuntu/mariadb-server-5.5.postinst new file mode 100644 index 00000000000..68e24a2d833 --- /dev/null +++ b/debian/dist/Ubuntu/mariadb-server-5.5.postinst @@ -0,0 +1,284 @@ +#!/bin/bash -e + +. /usr/share/debconf/confmodule + +if [ -n "$DEBIAN_SCRIPT_DEBUG" ]; then set -v -x; DEBIAN_SCRIPT_TRACE=1; fi +${DEBIAN_SCRIPT_TRACE:+ echo "#42#DEBUG# RUNNING $0 $*" 1>&2 } + +export PATH=$PATH:/sbin:/usr/sbin:/bin:/usr/bin + +# This command can be used as pipe to syslog. With "-s" it also logs to stderr. +ERR_LOGGER="logger -p daemon.err -t mysqld_safe -i" +# This will make an error in a logged command immediately apparent by aborting +# the install, rather than failing silently and leaving a broken install. +set -o pipefail + +invoke() { + if [ -x /usr/sbin/invoke-rc.d ]; then + invoke-rc.d mysql $1 + else + /etc/init.d/mysql $1 + fi +} + +MYSQL_BOOTSTRAP="/usr/sbin/mysqld --bootstrap --user=mysql --skip-grant-tables --innodb=OFF --pbxt=OFF --default-storage-engine=myisam" + +test_mysql_access() { + mysql --no-defaults -u root -h localhost /dev/null 2>&1 +} + +# call with $1 = "online" to connect to the server, otherwise it bootstraps +set_mysql_rootpw() { + # forget we ever saw the password. don't use reset to keep the seen status + db_set mysql-server/root_password "" + db_set mysql-server/root_password_again "" + + tfile=`mktemp` + if [ ! -f "$tfile" ]; then + return 1 + fi + + # this avoids us having to call "test" or "[" on $rootpw + cat << EOF > $tfile +USE mysql; +UPDATE user SET password=PASSWORD("$rootpw") WHERE user='root'; +FLUSH PRIVILEGES; +EOF + if grep -q 'PASSWORD("")' $tfile; then + retval=0 + elif [ "$1" = "online" ]; then + mysql --no-defaults -u root -h localhost <$tfile >/dev/null + retval=$? + else + $MYSQL_BOOTSTRAP <$tfile + retval=$? + fi + rm -f $tfile + return $retval +} + +# This is necessary because mysql_install_db removes the pid file in /var/run +# and because changed configuration options should take effect immediately. +# In case the server wasn't running at all it should be ok if the stop +# script fails. I can't tell at this point because of the cleaned /var/run. +set +e; invoke stop; set -e + +case "$1" in + configure) + mysql_datadir=/usr/share/mysql + mysql_statedir=/var/lib/mysql + mysql_rundir=/var/run/mysqld + mysql_logdir=/var/log + mysql_cfgdir=/etc/mysql + mysql_newlogdir=/var/log/mysql + mysql_upgradedir=/var/lib/mysql-upgrade + + # first things first, if the following symlink exists, it is a preserved + # copy the old data dir from a mysql upgrade that would have otherwise + # been replaced by an empty mysql dir. this should restore it. + for dir in DATADIR LOGDIR; do + if [ "$dir" = "DATADIR" ]; then targetdir=$mysql_statedir; else targetdir=$mysql_newlogdir; fi + savelink="$mysql_upgradedir/$dir.link" + if [ -L "$savelink" ]; then + # If the targetdir was a symlink before we upgraded it is supposed + # to be either still be present or not existing anymore now. + if [ -L "$targetdir" ]; then + rm "$savelink" + elif [ ! -d "$targetdir" ]; then + mv "$savelink" "$targetdir" + else + # this should never even happen, but just in case... + mysql_tmp=`mktemp -d -t mysql-symlink-restore-XXXXXX` + echo "this is very strange! see $mysql_tmp/README..." >&2 + mv "$targetdir" "$mysql_tmp" + cat << EOF > "$mysql_tmp/README" + +if you're reading this, it's most likely because you had replaced /var/lib/mysql +with a symlink, then upgraded to a new version of mysql, and then dpkg +removed your symlink (see #182747 and others). the mysql packages noticed +that this happened, and as a workaround have restored it. however, because +/var/lib/mysql seems to have been re-created in the meantime, and because +we don't want to rm -rf something we don't know as much about, we're going +to leave this unexpected directory here. if your database looks normal, +and this is not a symlink to your database, you should be able to blow +this all away. + +EOF + fi + fi + rmdir $mysql_upgradedir 2>/dev/null || true + done + + # Ensure the existence and right permissions for the database and + # log files. + if [ ! -d "$mysql_statedir" -a ! -L "$mysql_statedir" ]; then mkdir "$mysql_statedir"; fi + if [ ! -d "$mysql_statedir/mysql" -a ! -L "$mysql_statedir/mysql" ]; then mkdir "$mysql_statedir/mysql"; fi + if [ ! -d "$mysql_newlogdir" -a ! -L "$mysql_newlogdir" ]; then mkdir "$mysql_newlogdir"; fi + # When creating an ext3 jounal on an already mounted filesystem like e.g. + # /var/lib/mysql, you get a .journal file that is not modifyable by chown. + # The mysql_datadir must not be writable by the mysql user under any + # circumstances as it contains scripts that are executed by root. + set +e + chown -R 0:0 $mysql_datadir + chown -R mysql $mysql_statedir + chown -R mysql $mysql_rundir + chown -R mysql:adm $mysql_newlogdir; chmod 2750 $mysql_newlogdir; + for i in log err; do + touch $mysql_logdir/mysql.$i + chown mysql:adm $mysql_logdir/mysql.$i + chmod 0640 $mysql_logdir/mysql.$i + done + set -e + + # This is important to avoid dataloss when there is a removed + # mysql-server version from Woody lying around which used the same + # data directory and then somewhen gets purged by the admin. + db_set mysql-server/postrm_remove_database false || true + + # To avoid downgrades. + touch $mysql_statedir/debian-5.5.flag + + # initiate databases. Output is not allowed by debconf :-( + # This will fail if we are upgrading an existing database; in this case + # mysql_upgrade, called from the /etc/init.d/mysql start script, will + # handle things. + # Debian: beware of the bashisms... + # Debian: can safely run on upgrades with existing databases + set +e + /bin/bash /usr/bin/mysql_install_db --rpm --user=mysql 2>&1 | $ERR_LOGGER + set -e + + ## On every reconfiguration the maintenance user is recreated. + # + # - It is easier to regenerate the password every time but as people + # use fancy rsync scripts and file alteration monitors, the existing + # password is used and existing files not touched. + # - The mysqld statement is like that in mysql_install_db because the + # server is not already running. This has some implications: + # - The amount of newlines and semicolons in the query is important! + # - GRANT is not possible with --skip-grant-tables and "INSERT + # (user,host..) VALUES" is not --ansi compliant + # - The echo is just for readability. ash's buildin has no "-e" so use /bin/echo. + # - The Super_priv, Show_db_priv, Create_tmp_table_priv and Lock_tables_priv + # may not be present as old Woody 3.23 databases did not have it and the + # admin might not already have run mysql_upgrade which adds them. + # As the binlog cron scripts to need at least the Super_priv, I do first + # the old query which always succeeds and then the new which may or may not. + + # recreate the credentials file if not present or without mysql_upgrade stanza + dc=$mysql_cfgdir/debian.cnf; + if [ -e "$dc" -a -n "`fgrep mysql_upgrade $dc 2>/dev/null`" ]; then + pass="`sed -n 's/^[ ]*password *= *// p' $dc | head -n 1`" + else + pass=`perl -e 'print map{("a".."z","A".."Z",0..9)[int(rand(62))]}(1..16)'`; + if [ ! -d "$mysql_cfgdir" ]; then install -o 0 -g 0 -m 0755 -d $mysql_cfgdir; fi + cat /dev/null > $dc + echo "# Automatically generated for Debian scripts. DO NOT TOUCH!" >>$dc + echo "[client]" >>$dc + echo "host = localhost" >>$dc + echo "user = debian-sys-maint" >>$dc + echo "password = $pass" >>$dc + echo "socket = $mysql_rundir/mysqld.sock" >>$dc + echo "[mysql_upgrade]" >>$dc + echo "host = localhost" >>$dc + echo "user = debian-sys-maint" >>$dc + echo "password = $pass" >>$dc + echo "socket = $mysql_rundir/mysqld.sock" >>$dc + echo "basedir = /usr" >>$dc + fi + # If this dir chmod go+w then the admin did it. But this file should not. + chown 0:0 $dc + chmod 0600 $dc + + # update privilege tables + password_column_fix_query=`/bin/echo -e \ + "USE mysql\n" \ + "ALTER TABLE user CHANGE Password Password char(41) character set latin1 collate latin1_bin DEFAULT '' NOT NULL"`; + replace_query=`/bin/echo -e \ + "USE mysql\n" \ + "SET sql_mode='';\n" \ + "REPLACE INTO user SET " \ + " host='localhost', user='debian-sys-maint', password=password('$pass'), " \ + " Select_priv='Y', Insert_priv='Y', Update_priv='Y', Delete_priv='Y', " \ + " Create_priv='Y', Drop_priv='Y', Reload_priv='Y', Shutdown_priv='Y', " \ + " Process_priv='Y', File_priv='Y', Grant_priv='Y', References_priv='Y', " \ + " Index_priv='Y', Alter_priv='Y', Super_priv='Y', Show_db_priv='Y', "\ + " Create_tmp_table_priv='Y', Lock_tables_priv='Y', Execute_priv='Y', "\ + " Repl_slave_priv='Y', Repl_client_priv='Y', Create_view_priv='Y', "\ + " Show_view_priv='Y', Create_routine_priv='Y', Alter_routine_priv='Y', "\ + " Create_user_priv='Y', Event_priv='Y', Trigger_priv='Y',"\ + " ssl_cipher='', x509_issuer='', x509_subject='';"`; + # Engines supported by etch should be installed per default. The query sequence is supposed + # to be aborted if the CREATE TABLE fails due to an already existent table in which case the + # admin might already have chosen to remove one or more plugins. Newlines are necessary. + install_plugins=`/bin/echo -e \ + "USE mysql;\n" \ + "CREATE TABLE plugin (name char(64) COLLATE utf8_bin NOT NULL DEFAULT '', " \ + " dl char(128) COLLATE utf8_bin NOT NULL DEFAULT '', " \ + " PRIMARY KEY (name)) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='MySQL plugins';" ` + + # Upgrade password column format before the root password gets set. + echo "$password_column_fix_query" | $MYSQL_BOOTSTRAP 2>&1 | $ERR_LOGGER + + db_get mysql-server/root_password && rootpw="$RET" + if ! set_mysql_rootpw; then + password_error="yes" + fi + + set +e + echo "$replace_query" | $MYSQL_BOOTSTRAP 2>&1 | $ERR_LOGGER + echo "$install_plugins" | $MYSQL_BOOTSTRAP 2>&1 | $ERR_LOGGER + set -e + + # If there is a real AppArmor profile, we reload it. + # If the default empty profile is installed, then we remove any old + # profile that may be loaded. + # This allows upgrade from old versions (that have an apparmor profile + # on by default) to work both to disable a default profile, and to keep + # any profile installed and maintained by users themselves. + profile="/etc/apparmor.d/usr.sbin.mysqld" + if [ -f "$profile" ] && aa-status --enabled 2>/dev/null; then + if grep -q /usr/sbin/mysqld "$profile" 2>/dev/null ; then + apparmor_parser -r "$profile" || true + else + echo "/usr/sbin/mysqld { }" | apparmor_parser --remove 2>/dev/null || true + fi + fi + ;; + + abort-upgrade|abort-remove|abort-configure) + ;; + + *) + echo "postinst called with unknown argument '$1'" 1>&2 + exit 1 + ;; +esac + +# here we check to see if we can connect as root without a password +# this should catch upgrades from previous versions where the root +# password wasn't set. if there is a password, or if the connection +# fails for any other reason, nothing happens. +if [ "$1" = "configure" ]; then + if test_mysql_access; then + db_input medium mysql-server/root_password || true + db_go + db_get mysql-server/root_password && rootpw="$RET" + + if ! set_mysql_rootpw "online"; then + password_error="yes" + fi + fi + + if [ "$password_error" = "yes" ]; then + db_input high mysql-server/error_setting_password || true + db_go + fi + +fi + +db_stop # in case invoke failes + +#DEBHELPER# + +exit 0 diff --git a/debian/dist/Ubuntu/mariadb-server-5.5.postrm b/debian/dist/Ubuntu/mariadb-server-5.5.postrm new file mode 100644 index 00000000000..7cee5150ef9 --- /dev/null +++ b/debian/dist/Ubuntu/mariadb-server-5.5.postrm @@ -0,0 +1,86 @@ +#!/bin/bash -e + +# It is possible that Debconf has already been removed, too. +if [ -f /usr/share/debconf/confmodule ]; then + . /usr/share/debconf/confmodule +fi + +if [ -n "$DEBIAN_SCRIPT_DEBUG" ]; then set -v -x; DEBIAN_SCRIPT_TRACE=1; fi +${DEBIAN_SCRIPT_TRACE:+ echo "#42#DEBUG# RUNNING $0 $*" 1>&2 } + +MYADMIN="/usr/bin/mysqladmin --defaults-file=/etc/mysql/debian.cnf" + +# Try to stop the server in a sane way. If it does not success let the admin +# do it himself. No database directories should be removed while the server +# is running! +stop_server() { + set +e + if [ -x /usr/sbin/invoke-rc.d ]; then + invoke-rc.d mysql stop + else + /etc/init.d/mysql stop + fi + errno=$? + set -e + + if [ "$?" != 0 ]; then + echo "Trying to stop the MySQL server resulted in exitcode $?." 1>&2 + echo "Stop it yourself and try again!" 1>&2 + exit 1 + fi +} + +case "$1" in + purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) + if [ -n "`$MYADMIN ping 2>/dev/null`" ]; then + stop_server + sleep 2 + fi + ;; + *) + echo "postrm called with unknown argument '$1'" 1>&2 + exit 1 + ;; +esac + +# +# - Do NOT purge logs or data if another mysql-sever* package is installed (#307473) +# - Remove the mysql user only after all his owned files are purged. +# +if [ "$1" = "purge" -a ! \( -x /usr/sbin/mysqld -o -L /usr/sbin/mysqld \) ]; then + # we remove the mysql user only after all his owned files are purged + rm -f /var/log/mysql.{log,err}{,.0,.[1234567].gz} + rm -rf /var/log/mysql + + db_input high mysql-server-5.1/postrm_remove_databases || true + db_go || true + db_get mysql-server-5.1/postrm_remove_databases || true + if [ "$RET" = "true" ]; then + # never remove the debian.cnf when the databases are still existing + # else we ran into big trouble on the next install! + rm -f /etc/mysql/debian.cnf + rm -rf /var/lib/mysql + rm -rf /var/run/mysqld + userdel mysql || true + fi + + # (normally) Automatically added by dh_installinit + if [ "$1" = "purge" ] ; then + update-rc.d mysql remove >/dev/null || exit 0 + fi + # (normally) End automatically added section +fi + +# (normally) Automatically added by dh_installdebconf +if [ "$1" = purge ] && [ -e /usr/share/debconf/confmodule ]; then + . /usr/share/debconf/confmodule + db_purge +fi +# (normally) End automatically added section + +if [ "$1" = "purge" ] ; then + rm -f /etc/apparmor.d/force-complain/usr.sbin.mysqld >/dev/null 2>&1 || true +fi +# no DEBHELPER here, "update-rc.d remove" fails if mysql-server-5.1 is installed + +exit 0 diff --git a/debian/dist/Ubuntu/mariadb-server-5.5.py b/debian/dist/Ubuntu/mariadb-server-5.5.py new file mode 100644 index 00000000000..e0c59c260e2 --- /dev/null +++ b/debian/dist/Ubuntu/mariadb-server-5.5.py @@ -0,0 +1,52 @@ +'''apport package hook for mariadb-5.3 + +(c) 2009 Canonical Ltd. +Author: Mathias Gug +''' + +import os, os.path + +from apport.hookutils import * + +def _add_my_conf_files(report, filename): + key = 'MySQLConf' + path_to_key(filename) + report[key] = "" + for line in read_file(filename).split('\n'): + try: + if 'password' in line.split('=')[0]: + line = "%s = @@APPORTREPLACED@@" % (line.split('=')[0]) + report[key] += line + '\n' + except IndexError: + continue + +def add_info(report): + attach_conffiles(report, 'mariadb-server-5.3', conffiles=None) + key = 'Logs' + path_to_key('/var/log/daemon.log') + report[key] = "" + for line in read_file('/var/log/daemon.log').split('\n'): + try: + if 'mysqld' in line.split()[4]: + report[key] += line + '\n' + except IndexError: + continue + key = 'Logs' + path_to_key('/var/log/kern.log') + report[key] = "" + for line in read_file('/var/log/kern.log').split('\n'): + try: + if '/usr/sbin/mysqld' in string.join(line.split()[4:]): + report[key] += line + '\n' + except IndexError: + continue + _add_my_conf_files(report, '/etc/mysql/my.cnf') + for f in os.listdir('/etc/mysql/conf.d'): + _add_my_conf_files(report, os.path.join('/etc/mysql/conf.d', f)) + try: + report['MySQLVarLibDirListing'] = unicode(os.listdir('/var/lib/mysql')) + except OSError: + report['MySQLVarLibDirListing'] = unicode(False) + +if __name__ == '__main__': + report = {} + add_info(report) + for key in report: + print '%s: %s' % (key, report[key].split('\n', 1)[0]) diff --git a/debian/dist/Ubuntu/rules b/debian/dist/Ubuntu/rules new file mode 100755 index 00000000000..0bb8837993e --- /dev/null +++ b/debian/dist/Ubuntu/rules @@ -0,0 +1,299 @@ +#!/usr/bin/make -f + +export DH_VERBOSE=1 +export DEB_BUILD_HARDENING=1 + +PACKAGE=mariadb-5.5 + +include /usr/share/dpatch/dpatch.make + +TMP=$(CURDIR)/debian/tmp/ + +ARCH = $(shell dpkg-architecture -qDEB_BUILD_ARCH) +ARCH_OS = $(shell dpkg-architecture -qDEB_BUILD_ARCH_OS) +DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE) +DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) +DEBVERSION = $(shell dpkg-parsechangelog | awk '/^Version: / { print $$2 }' | sed 's/^.*-//' ) + +DEB_SOURCE_PACKAGE ?= $(strip $(shell egrep '^Source: ' debian/control | cut -f 2 -d ':')) +DEB_VERSION ?= $(shell dpkg-parsechangelog | egrep '^Version:' | cut -f 2 -d ' ') +DEB_NOEPOCH_VERSION ?= $(shell echo $(DEB_VERSION) | cut -d: -f2-) +DEB_UPSTREAM_VERSION ?= $(shell echo $(DEB_NOEPOCH_VERSION) | sed 's/-[^-]*$$//') +DEB_UPSTREAM_VERSION_MAJOR_MINOR := $(shell echo $(DEB_UPSTREAM_VERSION) | sed -r -n 's/^([0-9]+\.[0-9]+).*/\1/p') + +DISTRIBUTION = $(shell lsb_release -i -s) +RELEASE = $(shell lsb_release -r -s) + +MAKE_J = -j$(shell if [ -f /proc/cpuinfo ] ; then grep -c processor.* /proc/cpuinfo ; else echo 1 ; fi) +ifeq (${MAKE_J}, -j0) + MAKE_J = -j1 +endif + +MAKE_TEST_TARGET=test-force +ifneq ($(findstring fulltest,$(DEB_BUILD_OPTIONS)),) +# make test-bt is the testsuite run by the MySQL build team +# before a release, but it is long + MAKE_TEST_TARGET=test-bt +endif + +USE_ASSEMBLER=--enable-assembler + +ifneq (,$(filter $(ARCH), amd64 i386 ia64 s390)) + TESTSUITE_FAIL_CMD=exit 1 +else + TESTSUITE_FAIL_CMD=true +endif + +BUILDDIR = builddir +builddir = $(BUILDDIR) + +# This causes seg11 crashes if LDAP is used for groups in /etc/nsswitch.conf +# so it is disabled by default although, according to MySQL, it brings >10% +# performance gain if enabled. See #299382. +ifeq ($(STATIC_MYSQLD), 1) + USE_STATIC_MYSQLD=--with-mysqld-ldflags=-all-static +endif + +configure: patch configure-stamp +configure-stamp: + @echo "RULES.$@" + dh_testdir + +ifneq ($(ARCH_OS),hurd) + if [ ! -d /proc/self ]; then echo "/proc IS NEEDED" 1>&2; exit 1; fi +endif + + ( test -d $(builddir) || mkdir $(builddir) ) && cd $(builddir) && \ + sh -c 'PATH=$${MYSQL_BUILD_PATH:-"/bin:/usr/bin"} \ + CC=$${MYSQL_BUILD_CC:-gcc} \ + CFLAGS=$${MYSQL_BUILD_CFLAGS:-"-O2 -fno-omit-frame-pointer -g -pipe -Wall -Wno-uninitialized"} \ + CXX=$${MYSQL_BUILD_CXX:-g++} \ + CXXFLAGS=$${MYSQL_BUILD_CXXFLAGS:-"-O2 -fno-omit-frame-pointer -g -pipe -Wall -Wno-uninitialized"} \ + cmake .. \ + -DCMAKE_INSTALL_PREFIX=/usr \ + -DINSTALL_SBINDIR=sbin \ + -DMYSQL_DATADIR=/var/lib/mysql \ + -DINSTALL_INCLUDEDIR=include \ + -DINSTALL_INFODIR=share/info \ + -DINSTALL_MANDIR=share/man \ + \ + -DMYSQL_SERVER_SUFFIX="-$(DEBVERSION)" \ + -DWITH_COMMENT="(MariaDB - http://mariadb.com/)" \ + -DSYSTEM_TYPE="debian-linux-gnu" \ + -DINSTALL_LAYOUT=DEB \ + \ + -DENABLED_LOCAL_INFILE=1 \ + -DWITH_FAST_MUTEXES=1 \ + \ + -DMYSQL_UNIX_ADDR=/var/run/mysqld/mysqld.sock \ + -DMYSQL_USER=mysql \ + \ + -DEXTRA_CHARSETS=all \ + -DWITH_LIBWRAP=1 \ + -DWITH_SSL=system \ + -DWITH_ZLIB=system \ + -DWITH_EMBEDDED_SERVER=1 \ + -DHAVE_EMBEDDED_PRIVILEGE_CONTROL=ON \ + -DWITH_MAX=1' + + touch $@ + +build: build-stamp + +build-stamp: configure + @echo "RULES.$@" + dh_testdir + + cd $(builddir) && $(MAKE) $(MAKE_J) + +ifeq ($(findstring nocheck,$(DEB_BUILD_OPTIONS)),) + # Don't know why the following is necessary... + cp unittest/unit.pl $(builddir)/unittest/ + cp -r mysql-test/* $(builddir)/mysql-test/ + cp -r sql/share/* $(builddir)/sql/share/ + cp -r scripts/*sql $(builddir)/scripts/ + if [ ! -f testsuite-stamp ] ; then \ + cd $(builddir) && $(MAKE) $(MAKE_TEST_TARGET) || $(TESTSUITE_FAIL_CMD) ; \ + fi +endif + + touch testsuite-stamp + + touch build-stamp + +clean: clean-patched unpatch + rm -rf debian/patched +clean-patched: + @echo "RULES.clean-patched" + dh_testdir + dh_testroot + rm -f configure-stamp* + rm -f build-stamp* + rm -f testsuite-stamp + # + [ ! -f Makefile ] || $(MAKE) clean + [ ! -d mysql-test/var ] || rm -rf mysql-test/var + # + rm -rf $(BUILDDIR) + + debconf-updatepo + dh_clean -v + + +install: build + @echo "RULES.$@" + dh_testdir + dh_testroot + dh_clean -k + dh_installdirs + + # some self written manpages which hopefully + # gets overwritten sooner or later with upstreams + mkdir -p $(TMP)/usr/share/man/man1/ + mkdir -p $(TMP)/usr/share/man/man8/ + cp debian/additions/*.1 $(TMP)/usr/share/man/man1/ + mkdir -p $(TMP)/etc/mysql/conf.d/ + cp debian/additions/mysqld_safe_syslog.cnf $(TMP)/etc/mysql/conf.d/ + + # make install (trailing slash needed for innobase) + cd $(builddir) && $(MAKE) install DESTDIR=$(TMP)/ + # + # After installing, remove rpath to make lintian happy. + set +e; \ + find ./debian/tmp/ -type f -print0 \ + | xargs -0 --no-run-if-empty chrpath -k 2>/dev/null \ + | fgrep RPATH= \ + | cut -d: -f 1 \ + | xargs --no-run-if-empty chrpath -d; \ + set -e + + # libmysqlclient-dev: forgotten header file since 3.23.25? + cp $(BUILDDIR)/include/my_config.h $(TMP)/usr/include/mysql/ + cp include/my_dir.h $(TMP)/usr/include/mysql/ + + # mysql-common: We now provide our own config file. + # can't be mariadb-common, other packages insist + install -d $(TMP)/etc/mysql + install -m 0644 debian/additions/my.cnf $(TMP)/etc/mysql/my.cnf + + # mariadb-client + install -m 0755 debian/additions/mysqlreport $(TMP)/usr/bin/ + install -m 0755 debian/additions/innotop/innotop $(TMP)/usr/bin/ + install -m 0644 debian/additions/innotop/innotop.1 $(TMP)/usr/share/man/man1/ + + # mariadb-server + install -m 0755 $(BUILDDIR)/scripts/mysqld_safe $(TMP)/usr/bin/mysqld_safe + mkdir -p $(TMP)/usr/share/doc/mariadb-server-5.5/examples + # We have a sane my.cnf, cruft not needed (remove my-*.cnf and config-*.cnf) + # $(TMP)/usr/share/mysql/*cnf $(TMP)/usr/share/doc/mariadb-server-5.3/examples/ + rm -vf $(TMP)/usr/share/mysql/my-*.cnf \ + $(TMP)/usr/share/mysql/config-*.cnf \ + $(TMP)/usr/share/mysql/mi_test_all* \ + $(TMP)/usr/share/mysql/mysql-log-rotate \ + $(TMP)/usr/share/mysql/mysql.server \ + $(TMP)/usr/share/mysql/binary-configure + nm -n $(BUILDDIR)/sql/mysqld |gzip -9 > $(TMP)/usr/share/doc/mariadb-server-5.5/mysqld.sym.gz + install -m 0755 debian/additions/echo_stderr $(TMP)/usr/share/mysql/ + install -m 0755 debian/additions/debian-start $(TMP)/etc/mysql/ + install -m 0755 debian/additions/debian-start.inc.sh $(TMP)/usr/share/mysql/ + + # mariadb-test + mv $(TMP)/usr/mysql-test $(TMP)/usr/share/mysql + + # lintian overrides + mkdir -p $(TMP)/usr/share/lintian/overrides/ + cp debian/mysql-common.lintian-overrides $(TMP)/usr/share/lintian/overrides/mysql-common + cp debian/mariadb-server-5.5.lintian-overrides $(TMP)/usr/share/lintian/overrides/mariadb-server-5.5 + cp debian/mariadb-client-5.5.lintian-overrides $(TMP)/usr/share/lintian/overrides/mariadb-client-5.5 + + # For 5.0 -> 5.5 transition + d=$(TMP)/usr/share/mysql-common/internal-use-only/; \ + mkdir -p $$d; \ + cp debian/mariadb-server-5.5.mysql.init $$d/_etc_init.d_mysql; \ + cp debian/mariadb-server-5.5.mysql-server.logrotate $$d/_etc_logrotate.d_mysql-server; \ + cp debian/additions/debian-start $$d/_etc_mysql_debian-start; + + # install AppArmor profile + install -D -m 644 debian/apparmor-profile $(TMP)/etc/apparmor.d/usr.sbin.mysqld + # install Apport hook + install -D -m 644 debian/mariadb-server-5.5.py $(TMP)/usr/share/apport/package-hooks/source_mariadb-5.5.py + + dh_movefiles + +# Build architecture-independent files here. +binary-indep: build install + @echo "RULES.binary-indep" + dh_testdir -i + dh_testroot -i + dh_installdebconf -i + dh_installdocs -i + dh_installexamples -i + dh_installmenu -i + dh_installlogrotate -i + dh_installinit -i + dh_installcron -i + dh_installman -i + dh_installinfo -i + dh_installlogcheck -i + dh_installchangelogs -i + dh_link -i + dh_compress -i + dh_fixperms -i + dh_installdeb -i + dh_perl -i + dh_gencontrol -i + dh_md5sums -i + dh_builddeb -i + +# Build architecture-dependent files here. +binary-arch: build install + @echo "RULES.binary-arch" + dh_testdir + dh_testroot + + dh_installdebconf -a + dh_installdocs -a + dh_installexamples -a + dh_installmenu -a + dh_installlogrotate -a --name mysql-server + # Start mysql in runlevel 19 before 20 where apache, proftpd etc gets + # started which might depend on a running database server. + dh_installinit -a --name=mysql -- defaults 19 21 + dh_installcron -a --name mysql-server + dh_installman -a + dh_installinfo -a + dh_installlogcheck -a + dh_installchangelogs -a + dh_strip -a + dh_link -a # .so muss nach .so.1.2.3 installier werden! + dh_compress -a + dh_fixperms -a + dh_makeshlibs -a + dh_makeshlibs -plibmariadbclient18 -V'libmariadbclient18 (>= 5.5.1-1)' + dh_installdeb -a + dh_perl -a + dh_shlibdeps -a -l debian/libmariadbclient18/usr/lib -L libmariadbclient18 + dh_gencontrol -a + dh_md5sums -a + dh_builddeb -a + +source diff: + @echo >&2 'source and diff are obsolete - use dpkg-source -b'; false + +binary: binary-indep binary-arch + +get-orig-source: + @wget -nv -T10 -t3 \ + -O /tmp/mysql-$(DEB_UPSTREAM_VERSION).tar.gz \ + http://ftp.gwdg.de/pub/misc/mysql/Downloads/MySQL-$(DEB_UPSTREAM_VERSION_MAJOR_MINOR)/mysql-$(DEB_UPSTREAM_VERSION).tar.gz + @tar xfz /tmp/mysql-$(DEB_UPSTREAM_VERSION).tar.gz -C /tmp + @rm -rf /tmp/mysql-$(DEB_UPSTREAM_VERSION)/Docs + @rm -rf /tmp/mysql-$(DEB_UPSTREAM_VERSION)/debian + @mv /tmp/mysql-$(DEB_UPSTREAM_VERSION) /tmp/$(DEB_SOURCE_PACKAGE)-$(DEB_UPSTREAM_VERSION).orig + @cd /tmp ; tar czf $(DEB_SOURCE_PACKAGE)_$(DEB_UPSTREAM_VERSION).orig.tar.gz $(DEB_SOURCE_PACKAGE)-$(DEB_UPSTREAM_VERSION).orig + @rm -f /tmp/mysql-$(DEB_UPSTREAM_VERSION).tar.gz + @rm -rf /tmp/$(DEB_SOURCE_PACKAGE)-$(DEB_UPSTREAM_VERSION).orig + +.PHONY: clean clean-patched configure build binary binary-indep binary-arch install patch unpatch + +# vim: ts=8 diff --git a/debian/libmariadbclient-dev.README.Maintainer b/debian/libmariadbclient-dev.README.Maintainer new file mode 100644 index 00000000000..f24cdcd519d --- /dev/null +++ b/debian/libmariadbclient-dev.README.Maintainer @@ -0,0 +1,4 @@ +The examples directory includes files that might be needed by some +developers: +- header files not installed by default +- the example file udf_example.c diff --git a/debian/libmariadbclient-dev.dirs b/debian/libmariadbclient-dev.dirs new file mode 100644 index 00000000000..f6ad2870431 --- /dev/null +++ b/debian/libmariadbclient-dev.dirs @@ -0,0 +1,2 @@ +usr/include/ +usr/lib/ diff --git a/debian/libmariadbclient-dev.examples b/debian/libmariadbclient-dev.examples new file mode 100644 index 00000000000..f1649c311c4 --- /dev/null +++ b/debian/libmariadbclient-dev.examples @@ -0,0 +1 @@ +sql/udf_example.c diff --git a/debian/libmariadbclient-dev.files b/debian/libmariadbclient-dev.files new file mode 100644 index 00000000000..42a6c748b88 --- /dev/null +++ b/debian/libmariadbclient-dev.files @@ -0,0 +1,6 @@ +usr/bin/mysql_config +usr/include/mysql/*.h +usr/lib/libmysqlclient.a +usr/lib/libmysqlclient_r.a +usr/share/aclocal/mysql.m4 +usr/share/man/man1/mysql_config.1 diff --git a/debian/libmariadbclient-dev.links b/debian/libmariadbclient-dev.links new file mode 100644 index 00000000000..0481d1a0020 --- /dev/null +++ b/debian/libmariadbclient-dev.links @@ -0,0 +1,2 @@ +usr/lib/libmysqlclient.so.16 usr/lib/libmysqlclient.so +usr/lib/libmysqlclient_r.so.16 usr/lib/libmysqlclient_r.so diff --git a/debian/libmariadbclient18.dirs b/debian/libmariadbclient18.dirs new file mode 100644 index 00000000000..2964de6141b --- /dev/null +++ b/debian/libmariadbclient18.dirs @@ -0,0 +1 @@ +usr/lib/ diff --git a/debian/libmariadbclient18.files b/debian/libmariadbclient18.files new file mode 100644 index 00000000000..5162b7b9639 --- /dev/null +++ b/debian/libmariadbclient18.files @@ -0,0 +1 @@ +usr/lib/libmysqlclient*.so.* diff --git a/debian/libmariadbclient18.postinst b/debian/libmariadbclient18.postinst new file mode 100644 index 00000000000..29d3b86f978 --- /dev/null +++ b/debian/libmariadbclient18.postinst @@ -0,0 +1,12 @@ +#!/bin/bash -e + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 + +# vim: ts=4 + + diff --git a/debian/libmariadbd-dev.files b/debian/libmariadbd-dev.files new file mode 100644 index 00000000000..26cb8d0a606 --- /dev/null +++ b/debian/libmariadbd-dev.files @@ -0,0 +1,2 @@ +usr/lib/mysql/*.a +usr/lib/mysql/*.la diff --git a/debian/mariadb-client-5.5.README.Debian b/debian/mariadb-client-5.5.README.Debian new file mode 100644 index 00000000000..b245638f9c9 --- /dev/null +++ b/debian/mariadb-client-5.5.README.Debian @@ -0,0 +1,4 @@ +FAQ: + +Q: My completition is gone, why? +A: You have "no-auto-rehash" in the "[mysql]" section of /etc/mysql/my.cnf! diff --git a/debian/mariadb-client-5.5.dirs b/debian/mariadb-client-5.5.dirs new file mode 100644 index 00000000000..ceda5922c5d --- /dev/null +++ b/debian/mariadb-client-5.5.dirs @@ -0,0 +1,3 @@ +usr/bin/ +usr/share/man/man1/ +usr/share/perl5/ diff --git a/debian/mariadb-client-5.5.docs b/debian/mariadb-client-5.5.docs new file mode 100644 index 00000000000..21446855f51 --- /dev/null +++ b/debian/mariadb-client-5.5.docs @@ -0,0 +1,2 @@ +debian/additions/innotop/changelog.innotop +README diff --git a/debian/mariadb-client-5.5.files b/debian/mariadb-client-5.5.files new file mode 100644 index 00000000000..9cb949ea53e --- /dev/null +++ b/debian/mariadb-client-5.5.files @@ -0,0 +1,31 @@ +usr/bin/innochecksum +usr/bin/innotop +usr/bin/mysqlaccess +usr/bin/mysqladmin +usr/bin/mysqlbug +usr/bin/mysqldump +usr/bin/mysqldumpslow +usr/bin/mysql_find_rows +usr/bin/mysql_fix_extensions +usr/bin/mysqlimport +usr/bin/mysqlreport +usr/bin/mysqlshow +usr/bin/mysqlslap +usr/bin/mysql_waitpid +usr/share/lintian/overrides/mariadb-client-5.5 +usr/share/man/man1/innotop.1 +usr/share/man/man1/mysqlaccess.1 +usr/share/man/man1/mysqladmin.1 +usr/share/man/man1/mysqlbug.1 +usr/share/man/man1/mysqldump.1 +usr/share/man/man1/mysqldumpslow.1 +usr/share/man/man1/mysql_find_rows.1 +usr/share/man/man1/mysql_fix_extensions.1 +usr/share/man/man1/mysqlimport.1 +usr/share/man/man1/mysqlman.1 +usr/share/man/man1/mysqlreport.1 +usr/share/man/man1/mysqlshow.1 +usr/share/man/man1/mysqlslap.1 +usr/share/man/man1/mysql_tableinfo.1 +usr/share/man/man1/mysql_waitpid.1 +usr/share/man/man8/mysqlmanager.8 diff --git a/debian/mariadb-client-5.5.links b/debian/mariadb-client-5.5.links new file mode 100644 index 00000000000..247369fa218 --- /dev/null +++ b/debian/mariadb-client-5.5.links @@ -0,0 +1,3 @@ +usr/bin/mysqlcheck usr/bin/mysqlrepair +usr/bin/mysqlcheck usr/bin/mysqlanalyze +usr/bin/mysqlcheck usr/bin/mysqloptimize diff --git a/debian/mariadb-client-5.5.lintian-overrides b/debian/mariadb-client-5.5.lintian-overrides new file mode 100644 index 00000000000..d4dc1a70b1e --- /dev/null +++ b/debian/mariadb-client-5.5.lintian-overrides @@ -0,0 +1,3 @@ +mariadb-client-5.3: package-has-a-duplicate-relation +mariadb-client-5.3: wrong-name-for-upstream-changelog usr/share/doc/mariadb-client-5.3/changelog.innotop.gz +mariadb-client-5.3: pkg-not-in-package-test innotop diff --git a/debian/mariadb-client-5.5.menu b/debian/mariadb-client-5.5.menu new file mode 100644 index 00000000000..1378555c423 --- /dev/null +++ b/debian/mariadb-client-5.5.menu @@ -0,0 +1,3 @@ +# According to /usr/share/menu/ policy 1.4, not /usr/share/doc/debian-policy/ +?package(innotop):needs="text" section="Applications/Data Management"\ + title="innotop" command="/usr/bin/innotop" diff --git a/debian/mariadb-client-core-5.5.files b/debian/mariadb-client-core-5.5.files new file mode 100644 index 00000000000..a2781309439 --- /dev/null +++ b/debian/mariadb-client-core-5.5.files @@ -0,0 +1,4 @@ +usr/bin/mysql +usr/bin/mysqlcheck +usr/share/man/man1/mysql.1 +usr/share/man/man1/mysqlcheck.1 diff --git a/debian/mariadb-server-5.5.NEWS b/debian/mariadb-server-5.5.NEWS new file mode 100644 index 00000000000..a3042dc2918 --- /dev/null +++ b/debian/mariadb-server-5.5.NEWS @@ -0,0 +1,34 @@ +mysql-dfsg-5.1 (5.1.38-1) unstable; urgency=low + + * Please read http://dev.mysql.com/doc/refman/5.1/en/upgrading-from-5-0.html + * Make sure to do a REPAIR TABLE on all tables that use UTF-8 and have a + FULLTEXT index. + + -- Christian Hammers Sat, 4 Jul 2009 02:31:21 +0200 + +mysql-dfsg-5.0 (5.1.14beta-2) unstable; urgency=low + + * The BerkeleyDB Storage Engine is no longer supported. If the options + have-bdb or skip-bdb are found, MySQL will not start. If you have BDB + tables, you should change them to use another storage engine before + upgrading to 5.1. + + -- Monty Taylor Thu, 18 Jan 2007 12:28:21 -0800 + +mysql-dfsg-5.0 (5.0.45-2) unstable; urgency=low + + * Binary logging is now disabled by default. If you really need it (e.g. on + a replication master), remove the comment from the log_bin line in my.cnf. + + -- Norbert Tretkowski Sat, 10 Nov 2007 16:26:35 +0100 + +mysql-dfsg-5.0 (5.0.18-9) unstable; urgency=low + + * Rotation of the binary logs is now configured in /etc/mysql/my.cnf with + "expire-logs-days" which defaults to 20 days. The old file + /etc/mysql/debian-log-rotate.conf should be removed together with + /etc/cron.daily/mysql-server after this value has been adjusted. Note that + the old variable defined the number of files whereas the new one defines + a time span in days. + + -- Christian Hammers Tue, 24 Jan 2006 22:18:21 +0100 diff --git a/debian/mariadb-server-5.5.config b/debian/mariadb-server-5.5.config new file mode 100644 index 00000000000..162017caf71 --- /dev/null +++ b/debian/mariadb-server-5.5.config @@ -0,0 +1,46 @@ +#!/bin/bash -e + +. /usr/share/debconf/confmodule + +if [ -n "$DEBIAN_SCRIPT_DEBUG" ]; then set -v -x; DEBIAN_SCRIPT_TRACE=1; fi +${DEBIAN_SCRIPT_TRACE:+ echo "#42#DEBUG# RUNNING $0 $*" 1>&2 } + +CNF=/etc/mysql/my.cnf + +# Beware that there are two ypwhich one of them needs the 2>/dev/null! +if test -n "`which ypwhich 2>/dev/null`" && ypwhich >/dev/null 2>&1; then + db_input high mysql-server-5.1/nis_warning || true + db_go +fi + +# only ask this question on fresh installs, during "reconfiguration" and when +# not upgrading from an existing 5.0 installation. +# there is also an additional check for empty root passwords in the +# postinst script when the tools are available for us to use. +if [ "$1" = "configure" ] && ([ -z "$2" ] && [ ! -e "/var/lib/mysql/debian-5.0.flag" ] ) || [ "$1" = "reconfigure" ]; then + while :; do + RET="" + db_input high mysql-server/root_password || true + db_go + db_get mysql-server/root_password + # if password isn't empty we ask for password verification + if [ -z "$RET" ]; then + db_fset mysql-server/root_password seen false + db_fset mysql-server/root_password_again seen false + break + fi + ROOT_PW="$RET" + db_input high mysql-server/root_password_again || true + db_go + db_get mysql-server/root_password_again + if [ "$RET" == "$ROOT_PW" ]; then + ROOT_PW='' + break + fi + db_fset mysql-server/password_mismatch seen false + db_input critical mysql-server/password_mismatch + db_set mysql-server/root_password "" + db_set mysql-server/root_password_again "" + db_go + done +fi diff --git a/debian/mariadb-server-5.5.lintian-overrides b/debian/mariadb-server-5.5.lintian-overrides new file mode 100644 index 00000000000..3a3dc20c563 --- /dev/null +++ b/debian/mariadb-server-5.5.lintian-overrides @@ -0,0 +1,5 @@ +mariadb-server-5.3: command-with-path-in-maintainer-script postinst +mariadb-server-5.3: possible-bashism-in-maintainer-script postinst:81 'p{("a".."z","A".."Z",0..9)[int(rand(62))]}' +mariadb-server-5.3: possible-bashism-in-maintainer-script preinst:33 '${cmd/ */}' +mariadb-server-5.3: statically-linked-binary ./usr/bin/mysql_tzinfo_to_sql +mariadb-server-5.3: statically-linked-binary ./usr/sbin/mysqld diff --git a/debian/mariadb-server-5.5.logcheck.ignore.paranoid b/debian/mariadb-server-5.5.logcheck.ignore.paranoid new file mode 100644 index 00000000000..00cc5c3e29d --- /dev/null +++ b/debian/mariadb-server-5.5.logcheck.ignore.paranoid @@ -0,0 +1,9 @@ +/etc/init.d/mysql\[[0-9]+\]: Check that mysqld is running and that the socket: '/var/run/mysqld/mysqld.sock' exists\!$ +/etc/init.d/mysql\[[0-9]+\]: '/usr/bin/mysqladmin --defaults-(extra-)?file=/etc/mysql/debian.cnf ping' resulted in$ +/etc/mysql/debian-start\[[0-9]+\]: Checking for crashed MySQL tables\.$ +mysqld\[[0-9]+\]: $ +mysqld\[[0-9]+\]: Version: .* socket: '/var/run/mysqld/mysqld.sock' port: 3306$ +mysqld\[[0-9]+\]: Warning: Ignoring user change to 'mysql' because the user was set to 'mysql' earlier on the command line$ +mysqld_safe\[[0-9]+\]: started$ +usermod\[[0-9]+\]: change user `mysql' GID from `([0-9]+)' to `\1'$ +usermod\[[0-9]+\]: change user `mysql' shell from `/bin/false' to `/bin/false'$ diff --git a/debian/mariadb-server-5.5.logcheck.ignore.server b/debian/mariadb-server-5.5.logcheck.ignore.server new file mode 100644 index 00000000000..37f25cb01ea --- /dev/null +++ b/debian/mariadb-server-5.5.logcheck.ignore.server @@ -0,0 +1,32 @@ +/etc/init.d/mysql\[[0-9]+\]: [0-9]+ processes alive and '/usr/bin/mysqladmin --defaults-(extra-)?file=/etc/mysql/debian.cnf ping' resulted in$ +/etc/init.d/mysql\[[0-9]+\]: Check that mysqld is running and that the socket: '/var/run/mysqld/mysqld.sock' exists\!$ +/etc/init.d/mysql\[[0-9]+\]: '/usr/bin/mysqladmin --defaults-(extra-)?file=/etc/mysql/debian.cnf ping' resulted in$ +/etc/mysql/debian-start\[[0-9]+\]: Checking for crashed MySQL tables\.$ +mysqld\[[0-9]+\]: ?$ +mysqld\[[0-9]+\]: .*InnoDB: Shutdown completed +mysqld\[[0-9]+\]: .*InnoDB: Started; +mysqld\[[0-9]+\]: .*InnoDB: Starting shutdown\.\.\.$ +mysqld\[[0-9]+\]: .*\[Note\] /usr/sbin/mysqld: Normal shutdown$ +mysqld\[[0-9]+\]: .*\[Note\] /usr/sbin/mysqld: ready for connections\.$ +mysqld\[[0-9]+\]: .*\[Note\] /usr/sbin/mysqld: Shutdown complete$ +mysqld\[[0-9]+\]: /usr/sbin/mysqld: ready for connections\.$ +mysqld\[[0-9]+\]: .*/usr/sbin/mysqld: Shutdown Complete$ +mysqld\[[0-9]+\]: Version: .* socket +mysqld\[[0-9]+\]: Warning: Ignoring user change to 'mysql' because the user was set to 'mysql' earlier on the command line$ +mysqld_safe\[[0-9]+\]: ?$ +mysqld_safe\[[0-9]+\]: able to use the new GRANT command!$ +mysqld_safe\[[0-9]+\]: ended$ +mysqld_safe\[[0-9]+\]: http://www.mysql.com$ +mysqld_safe\[[0-9]+\]: NOTE: If you are upgrading from a MySQL <= 3.22.10 you should run$ +mysqld_safe\[[0-9]+\]: PLEASE REMEMBER TO SET A PASSWORD FOR THE MySQL root USER !$ +mysqld_safe\[[0-9]+\]: Please report any problems with the /usr/bin/mysqlbug script!$ +mysqld_safe\[[0-9]+\]: See the manual for more instructions.$ +mysqld_safe\[[0-9]+\]: started$ +mysqld_safe\[[0-9]+\]: Support MySQL by buying support/licenses at https://order.mysql.com$ +mysqld_safe\[[0-9]+\]: The latest information about MySQL is available on the web at$ +mysqld_safe\[[0-9]+\]: the /usr/bin/mysql_fix_privilege_tables. Otherwise you will not be$ +mysqld_safe\[[0-9]+\]: To do so, start the server, then issue the following commands:$ +mysqld_safe\[[0-9]+\]: /usr/bin/mysqladmin -u root -h app109 password 'new-password'$ +mysqld_safe\[[0-9]+\]: /usr/bin/mysqladmin -u root password 'new-password'$ +usermod\[[0-9]+\]: change user `mysql' GID from `([0-9]+)' to `\1'$ +usermod\[[0-9]+\]: change user `mysql' shell from `/bin/false' to `/bin/false'$ diff --git a/debian/mariadb-server-5.5.logcheck.ignore.workstation b/debian/mariadb-server-5.5.logcheck.ignore.workstation new file mode 100644 index 00000000000..37f25cb01ea --- /dev/null +++ b/debian/mariadb-server-5.5.logcheck.ignore.workstation @@ -0,0 +1,32 @@ +/etc/init.d/mysql\[[0-9]+\]: [0-9]+ processes alive and '/usr/bin/mysqladmin --defaults-(extra-)?file=/etc/mysql/debian.cnf ping' resulted in$ +/etc/init.d/mysql\[[0-9]+\]: Check that mysqld is running and that the socket: '/var/run/mysqld/mysqld.sock' exists\!$ +/etc/init.d/mysql\[[0-9]+\]: '/usr/bin/mysqladmin --defaults-(extra-)?file=/etc/mysql/debian.cnf ping' resulted in$ +/etc/mysql/debian-start\[[0-9]+\]: Checking for crashed MySQL tables\.$ +mysqld\[[0-9]+\]: ?$ +mysqld\[[0-9]+\]: .*InnoDB: Shutdown completed +mysqld\[[0-9]+\]: .*InnoDB: Started; +mysqld\[[0-9]+\]: .*InnoDB: Starting shutdown\.\.\.$ +mysqld\[[0-9]+\]: .*\[Note\] /usr/sbin/mysqld: Normal shutdown$ +mysqld\[[0-9]+\]: .*\[Note\] /usr/sbin/mysqld: ready for connections\.$ +mysqld\[[0-9]+\]: .*\[Note\] /usr/sbin/mysqld: Shutdown complete$ +mysqld\[[0-9]+\]: /usr/sbin/mysqld: ready for connections\.$ +mysqld\[[0-9]+\]: .*/usr/sbin/mysqld: Shutdown Complete$ +mysqld\[[0-9]+\]: Version: .* socket +mysqld\[[0-9]+\]: Warning: Ignoring user change to 'mysql' because the user was set to 'mysql' earlier on the command line$ +mysqld_safe\[[0-9]+\]: ?$ +mysqld_safe\[[0-9]+\]: able to use the new GRANT command!$ +mysqld_safe\[[0-9]+\]: ended$ +mysqld_safe\[[0-9]+\]: http://www.mysql.com$ +mysqld_safe\[[0-9]+\]: NOTE: If you are upgrading from a MySQL <= 3.22.10 you should run$ +mysqld_safe\[[0-9]+\]: PLEASE REMEMBER TO SET A PASSWORD FOR THE MySQL root USER !$ +mysqld_safe\[[0-9]+\]: Please report any problems with the /usr/bin/mysqlbug script!$ +mysqld_safe\[[0-9]+\]: See the manual for more instructions.$ +mysqld_safe\[[0-9]+\]: started$ +mysqld_safe\[[0-9]+\]: Support MySQL by buying support/licenses at https://order.mysql.com$ +mysqld_safe\[[0-9]+\]: The latest information about MySQL is available on the web at$ +mysqld_safe\[[0-9]+\]: the /usr/bin/mysql_fix_privilege_tables. Otherwise you will not be$ +mysqld_safe\[[0-9]+\]: To do so, start the server, then issue the following commands:$ +mysqld_safe\[[0-9]+\]: /usr/bin/mysqladmin -u root -h app109 password 'new-password'$ +mysqld_safe\[[0-9]+\]: /usr/bin/mysqladmin -u root password 'new-password'$ +usermod\[[0-9]+\]: change user `mysql' GID from `([0-9]+)' to `\1'$ +usermod\[[0-9]+\]: change user `mysql' shell from `/bin/false' to `/bin/false'$ diff --git a/debian/mariadb-server-5.5.mysql-server.logrotate b/debian/mariadb-server-5.5.mysql-server.logrotate new file mode 100644 index 00000000000..0f0de516b13 --- /dev/null +++ b/debian/mariadb-server-5.5.mysql-server.logrotate @@ -0,0 +1,27 @@ +# - I put everything in one block and added sharedscripts, so that mysql gets +# flush-logs'd only once. +# Else the binary logs would automatically increase by n times every day. +# - The error log is obsolete, messages go to syslog now. +/var/log/mysql.log /var/log/mysql/mysql.log /var/log/mysql/mysql-slow.log { + daily + rotate 7 + missingok + create 640 mysql adm + compress + sharedscripts + postrotate + test -x /usr/bin/mysqladmin || exit 0 + + # If this fails, check debian.conf! + MYADMIN="/usr/bin/mysqladmin --defaults-file=/etc/mysql/debian.cnf" + if [ -z "`$MYADMIN ping 2>/dev/null`" ]; then + # Really no mysqld or rather a missing debian-sys-maint user? + # If this occurs and is not a error please report a bug. + if ps cax | grep -q mysqld; then + exit 1 + fi + else + $MYADMIN flush-logs + fi + endscript +} diff --git a/debian/mariadb-server-5.5.mysql.init b/debian/mariadb-server-5.5.mysql.init new file mode 100644 index 00000000000..e9dd08481c6 --- /dev/null +++ b/debian/mariadb-server-5.5.mysql.init @@ -0,0 +1,187 @@ +#!/bin/bash +# +### BEGIN INIT INFO +# Provides: mysql +# Required-Start: $remote_fs $syslog +# Required-Stop: $remote_fs $syslog +# Should-Start: $network $named $time +# Should-Stop: $network $named $time +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Start and stop the mysql database server daemon +# Description: Controls the main MariaDB database server daemon "mysqld" +# and its wrapper script "mysqld_safe". +### END INIT INFO +# +set -e +set -u +${DEBIAN_SCRIPT_DEBUG:+ set -v -x} + +test -x /usr/sbin/mysqld || exit 0 + +. /lib/lsb/init-functions + +SELF=$(cd $(dirname $0); pwd -P)/$(basename $0) +CONF=/etc/mysql/my.cnf +MYADMIN="/usr/bin/mysqladmin --defaults-file=/etc/mysql/debian.cnf" + +# priority can be overriden and "-s" adds output to stderr +ERR_LOGGER="logger -p daemon.err -t /etc/init.d/mysql -i" + +# Safeguard (relative paths, core dumps..) +cd / +umask 077 + +# mysqladmin likes to read /root/.my.cnf. This is usually not what I want +# as many admins e.g. only store a password without a username there and +# so break my scripts. +export HOME=/etc/mysql/ + +## Fetch a particular option from mysql's invocation. +# +# Usage: void mysqld_get_param option +mysqld_get_param() { + /usr/sbin/mysqld --print-defaults \ + | tr " " "\n" \ + | grep -- "--$1" \ + | tail -n 1 \ + | cut -d= -f2 +} + +## Do some sanity checks before even trying to start mysqld. +sanity_checks() { + # check for config file + if [ ! -r /etc/mysql/my.cnf ]; then + log_warning_msg "$0: WARNING: /etc/mysql/my.cnf cannot be read. See README.Debian.gz" + echo "WARNING: /etc/mysql/my.cnf cannot be read. See README.Debian.gz" | $ERR_LOGGER + fi + + # check for diskspace shortage + datadir=`mysqld_get_param datadir` + if LC_ALL=C BLOCKSIZE= df --portability $datadir/. | tail -n 1 | awk '{ exit ($4>4096) }'; then + log_failure_msg "$0: ERROR: The partition with $datadir is too full!" + echo "ERROR: The partition with $datadir is too full!" | $ERR_LOGGER + exit 1 + fi +} + +## Checks if there is a server running and if so if it is accessible. +# +# check_alive insists on a pingable server +# check_dead also fails if there is a lost mysqld in the process list +# +# Usage: boolean mysqld_status [check_alive|check_dead] [warn|nowarn] +mysqld_status () { + ping_output=`$MYADMIN ping 2>&1`; ping_alive=$(( ! $? )) + + ps_alive=0 + pidfile=`mysqld_get_param pid-file` + if [ -f "$pidfile" ] && ps `cat $pidfile` >/dev/null 2>&1; then ps_alive=1; fi + + if [ "$1" = "check_alive" -a $ping_alive = 1 ] || + [ "$1" = "check_dead" -a $ping_alive = 0 -a $ps_alive = 0 ]; then + return 0 # EXIT_SUCCESS + else + if [ "$2" = "warn" ]; then + echo -e "$ps_alive processes alive and '$MYADMIN ping' resulted in\n$ping_output\n" | $ERR_LOGGER -p daemon.debug + fi + return 1 # EXIT_FAILURE + fi +} + +# +# main() +# + +case "${1:-''}" in + 'start') + sanity_checks; + # Start daemon + log_daemon_msg "Starting MariaDB database server" "mysqld" + if mysqld_status check_alive nowarn; then + log_progress_msg "already running" + log_end_msg 0 + else + # Could be removed during boot + test -e /var/run/mysqld || install -m 755 -o mysql -g root -d /var/run/mysqld + + # Start MariaDB! + /usr/bin/mysqld_safe > /dev/null 2>&1 & + + # 6s was reported in #352070 to be too few when using ndbcluster + for i in $(seq 1 "${MYSQLD_STARTUP_TIMEOUT:-14}"); do + sleep 1 + if mysqld_status check_alive nowarn ; then break; fi + log_progress_msg "." + done + if mysqld_status check_alive warn; then + log_end_msg 0 + # Now start mysqlcheck or whatever the admin wants. + output=$(/etc/mysql/debian-start) + [ -n "$output" ] && log_action_msg "$output" + else + log_end_msg 1 + log_failure_msg "Please take a look at the syslog" + fi + fi + ;; + + 'stop') + # * As a passwordless mysqladmin (e.g. via ~/.my.cnf) must be possible + # at least for cron, we can rely on it here, too. (although we have + # to specify it explicit as e.g. sudo environments points to the normal + # users home and not /root) + log_daemon_msg "Stopping MariaDB database server" "mysqld" + if ! mysqld_status check_dead nowarn; then + set +e + shutdown_out=`$MYADMIN shutdown 2>&1`; r=$? + set -e + if [ "$r" -ne 0 ]; then + log_end_msg 1 + [ "$VERBOSE" != "no" ] && log_failure_msg "Error: $shutdown_out" + log_daemon_msg "Killing MariaDB database server by signal" "mysqld" + killall -15 mysqld + server_down= + for i in 1 2 3 4 5 6 7 8 9 10; do + sleep 1 + if mysqld_status check_dead nowarn; then server_down=1; break; fi + done + if test -z "$server_down"; then killall -9 mysqld; fi + fi + fi + + if ! mysqld_status check_dead warn; then + log_end_msg 1 + log_failure_msg "Please stop MariaDB manually and read /usr/share/doc/mariadb-server-5.3/README.Debian.gz!" + exit -1 + else + log_end_msg 0 + fi + ;; + + 'restart') + set +e; $SELF stop; set -e + $SELF start + ;; + + 'reload'|'force-reload') + log_daemon_msg "Reloading MariaDB database server" "mysqld" + $MYADMIN reload + log_end_msg 0 + ;; + + 'status') + if mysqld_status check_alive nowarn; then + log_action_msg "$($MYADMIN version)" + else + log_action_msg "MariaDB is stopped." + exit 3 + fi + ;; + + *) + echo "Usage: $SELF start|stop|restart|reload|force-reload|status" + exit 1 + ;; +esac + diff --git a/debian/mariadb-server-5.5.preinst b/debian/mariadb-server-5.5.preinst new file mode 100644 index 00000000000..9a7e337d168 --- /dev/null +++ b/debian/mariadb-server-5.5.preinst @@ -0,0 +1,182 @@ +#!/bin/bash -e +# +# summary of how this script can be called: +# * install +# * install +# * upgrade +# * abort-upgrade +# + +. /usr/share/debconf/confmodule + +if [ -n "$DEBIAN_SCRIPT_DEBUG" ]; then set -v -x; DEBIAN_SCRIPT_TRACE=1; fi +${DEBIAN_SCRIPT_TRACE:+ echo "#42#DEBUG# RUNNING $0 $*" 1>&2 } + +export PATH=$PATH:/sbin:/usr/sbin:/bin:/usr/bin +MYADMIN="/usr/bin/mysqladmin --defaults-file=/etc/mysql/debian.cnf" +DATADIR=/var/lib/mysql +LOGDIR=/var/log/mysql +UPGRADEDIR=/var/lib/mysql-upgrade + +# Try to stop the server in a sane way. If it does not success let the admin +# do it himself. No database directories should be removed while the server +# is running! Another mysqld in e.g. a different chroot is fine for us. +stop_server() { + if [ ! -x /etc/init.d/mysql ]; then return; fi + + set +e + if [ -x /usr/sbin/invoke-rc.d ]; then + cmd="invoke-rc.d mysql stop" + else + cmd="/etc/init.d/mysql stop" + fi + $cmd + errno=$? + set -e + + # 0=ok, 100=no init script (fresh install) + if [ "$errno" != 0 -a "$errno" != 100 ]; then + echo "${cmd/ */} returned $errno" 1>&2 + echo "There is a MySQL server running, but we failed in our attempts to stop it." 1>&2 + echo "Stop it yourself and try again!" 1>&2 + db_stop + exit 1 + fi +} + +################################ main() ########################## + +this_version=5.5 + +# Abort if an NDB cluster is in use. +if egrep -qi -r '^[^#]*ndb.connectstring|^[:space:]*\[[:space:]*ndb_mgmd' /etc/mysql/; then + db_fset mysql-server/no_upgrade_when_using_ndb seen false || true + db_input high mysql-server/no_upgrade_when_using_ndb || true + db_go + db_stop + exit 1 +fi + +# Abort if skip-bdb option is enabled, required for 5.0 -> 5.1 upgrades. +#TODO + +# Safe the user from stupidities. +show_downgrade_warning=0 +for i in `ls $DATADIR/debian-*.flag 2>/dev/null`; do + found_version=`echo $i | sed 's/.*debian-\([0-9\.]\+\).flag/\1/'` + if dpkg --compare-versions "$this_version" '<<' "$found_version"; then + show_downgrade_warning=1 + break; + fi +done +if [ "$show_downgrade_warning" = 1 ]; then + db_fset mariadb-server-$this_version/really_downgrade seen false || true + db_input medium mariadb-server-$this_version/really_downgrade || true + db_go + db_get mariadb-server-$this_version/really_downgrade || true + if [ "$RET" = "true" ]; then + rm -f $DATADIR/debian-*.flag + touch $DATADIR/debian-$this_version.flag + else + echo "Aborting downgrade from (at least) $found_version to $this_version." 1>&2 + echo "If are sure you want to downgrade to $this_version, remove the file" 1>&2 + echo "$DATADIR/debian-*.flag and try installing again." 1>&2 + db_stop + exit 1 + fi +fi + +# to be sure +stop_server + +# If we use NIS then errors should be tolerated. It's up to the +# user to ensure that the mysql user is correctly setup. +# Beware that there are two ypwhich one of them needs the 2>/dev/null! +if test -n "`which ypwhich 2>/dev/null`" && ypwhich >/dev/null 2>&1; then + set +e +fi + +# +# Now we have to ensure the following state: +# /etc/passwd: mysql:x:100:101:MySQL Server:/var/lib/mysql:/bin/false +# /etc/group: mysql:x:101: +# +# Sadly there could any state be present on the system so we have to +# modify everything carefully i.e. not doing a chown before creating +# the user etc... +# + +# creating mysql group if he isn't already there +if ! getent group mysql >/dev/null; then + # Adding system group: mysql. + addgroup --system mysql >/dev/null +fi + +# creating mysql user if he isn't already there +if ! getent passwd mysql >/dev/null; then + # Adding system user: mysql. + adduser \ + --system \ + --disabled-login \ + --ingroup mysql \ + --home $DATADIR \ + --gecos "MySQL Server" \ + --shell /bin/false \ + mysql >/dev/null +fi + +# end of NIS tolerance zone +set -e + +# if there's a symlink, let's store where it's pointing, because otherwise +# it's going to be lost in some situations +for dir in DATADIR LOGDIR; do + checkdir=`eval echo "$"$dir` + if [ -L "$checkdir" ]; then + mkdir -p "$UPGRADEDIR" + cp -d "$checkdir" "$UPGRADEDIR/$dir.link" + fi +done + +# creating mysql home directory +if [ ! -d $DATADIR -a ! -L $DATADIR ]; then + mkdir $DATADIR +fi + +# checking disc space +if LC_ALL=C BLOCKSIZE= df --portability $DATADIR/. | tail -n 1 | awk '{ exit ($4>1000) }'; then + echo "ERROR: There's not enough space in $DATADIR/" 1>&2 + db_stop + exit 1 +fi + +# Since the home directory was created before putting the user into +# the mysql group and moreover we cannot guarantee that the +# permissions were correctly *before* calling this script, we fix them now. +# In case we use NIS and no mysql user is present then this script should +# better fail now than later.. +# The "set +e" is necessary as e.g. a ".journal" of a ext3 partition is +# not chgrp'able (#318435). +set +e +chown mysql:mysql $DATADIR +find $DATADIR -follow -not -group mysql -print0 2>/dev/null \ + | xargs -0 --no-run-if-empty chgrp mysql +set -e + +# Some files below /etc/ were possibly in the mysql-server-5.0/etch package +# before. They get overwritten by current ones to avoid unnecessary dpkg questions. +while read md5 file; do + if [ "`md5sum $file 2>/dev/null`" = "$md5 $file" ]; then + cp /usr/share/mysql-common/internal-use-only/`echo $file | sed 's/_g'` $file + fi +done <&2 } + +#DEBHELPER# diff --git a/debian/mariadb-server-5.5.templates b/debian/mariadb-server-5.5.templates new file mode 100644 index 00000000000..436d599bde3 --- /dev/null +++ b/debian/mariadb-server-5.5.templates @@ -0,0 +1,89 @@ +# These templates have been reviewed by the debian-l10n-english +# team +# +# If modifications/additions/rewording are needed, please ask +# for an advice to debian-l10n-english@lists.debian.org +# +# Even minor modifications require translation updates and such +# changes should be coordinated with translators and reviewers. + +Template: mariadb-server-5.3/really_downgrade +Type: boolean +Default: false +_Description: Really proceed with downgrade? + A file named /var/lib/mysql/debian-*.flag exists on this system. + . + Such a file is an indication that a mariadb-server package with a higher + version has been installed previously. + . + There is no guarantee that the version you're currently installing + will be able to use the current databases. + +Template: mysql-server-5.1/nis_warning +Type: note +#flag:translate!:3,5 +_Description: Important note for NIS/YP users + Using MariaDB under NIS/YP requires a mysql user account to be added on + the local system with: + . + adduser --system --group --home /var/lib/mysql mysql + . + You should also check the permissions and ownership of the + /var/lib/mysql directory: + . + /var/lib/mysql: drwxr-xr-x mysql mysql + +Template: mysql-server-5.1/postrm_remove_databases +Type: boolean +Default: false +_Description: Remove all MariaDB databases? + The /var/lib/mysql directory which contains the MariaDB databases is about + to be removed. + . + If you're removing the MariaDB package in order to later install a more + recent version or if a different mariadb-server package is already + using it, the data should be kept. + +Template: mysql-server-5.1/start_on_boot +Type: boolean +Default: true +_Description: Start the MariaDB server on boot? + The MariaDB server can be launched automatically at boot time or manually + with the '/etc/init.d/mysql start' command. + +Template: mysql-server/root_password +Type: password +_Description: New password for the MariaDB "root" user: + While not mandatory, it is highly recommended that you set a password + for the MariaDB administrative "root" user. + . + If this field is left blank, the password will not be changed. + +Template: mysql-server/root_password_again +Type: password +_Description: Repeat password for the MariaDB "root" user: + +Template: mysql-server/error_setting_password +Type: error +_Description: Unable to set password for the MariaDB "root" user + An error occurred while setting the password for the MariaDB + administrative user. This may have happened because the account + already has a password, or because of a communication problem with + the MariaDB server. + . + You should check the account's password after the package installation. + . + Please read the /usr/share/doc/mariadb-server-5.3/README.Debian file + for more information. + +Template: mysql-server/password_mismatch +Type: error +_Description: Password input error + The two passwords you entered were not the same. Please try again. + +Template: mysql-server/no_upgrade_when_using_ndb +Type: error +_Description: NDB Cluster seems to be in use + MySQL-5.1 no longer provides NDB Cluster support. Please migrate to the new + mysql-cluster package and remove all lines starting with "ndb" from + all config files below /etc/mysql/. diff --git a/debian/mariadb-server-core-5.5.files b/debian/mariadb-server-core-5.5.files new file mode 100644 index 00000000000..5c60ca5ec67 --- /dev/null +++ b/debian/mariadb-server-core-5.5.files @@ -0,0 +1,26 @@ +usr/sbin/mysqld +usr/share/man/man8/mysqld.8 +usr/share/mysql/charsets +usr/share/mysql/czech +usr/share/mysql/danish +usr/share/mysql/dutch +usr/share/mysql/english +usr/share/mysql/estonian +usr/share/mysql/french +usr/share/mysql/german +usr/share/mysql/greek +usr/share/mysql/hungarian +usr/share/mysql/italian +usr/share/mysql/japanese +usr/share/mysql/korean +usr/share/mysql/norwegian +usr/share/mysql/norwegian-ny +usr/share/mysql/polish +usr/share/mysql/portuguese +usr/share/mysql/romanian +usr/share/mysql/russian +usr/share/mysql/serbian +usr/share/mysql/slovak +usr/share/mysql/spanish +usr/share/mysql/swedish +usr/share/mysql/ukrainian diff --git a/debian/mariadb-test-5.5.dirs b/debian/mariadb-test-5.5.dirs new file mode 100644 index 00000000000..2c10b45efba --- /dev/null +++ b/debian/mariadb-test-5.5.dirs @@ -0,0 +1,98 @@ +usr/bin +usr/share/man/man1 +usr/share/mysql/mysql-test +usr/share/mysql/mysql-test/extra +usr/share/mysql/mysql-test/extra/binlog_tests +usr/share/mysql/mysql-test/extra/rpl_tests +usr/share/mysql/mysql-test/lib +usr/share/mysql/mysql-test/lib/My +usr/share/mysql/mysql-test/lib/My/SafeProcess +usr/share/mysql/mysql-test/lib/My/File +usr/share/mysql/mysql-test/lib/v1 +usr/share/mysql/mysql-test/lib/v1/My +usr/share/mysql/mysql-test/collections +usr/share/mysql/mysql-test/t +usr/share/mysql/mysql-test/r +usr/share/mysql/mysql-test/include +usr/share/mysql/mysql-test/suite +usr/share/mysql/mysql-test/suite/parts +usr/share/mysql/mysql-test/suite/parts/inc +usr/share/mysql/mysql-test/suite/parts/t +usr/share/mysql/mysql-test/suite/parts/r +usr/share/mysql/mysql-test/suite/rpl_ndb +usr/share/mysql/mysql-test/suite/rpl_ndb/t +usr/share/mysql/mysql-test/suite/rpl_ndb/r +usr/share/mysql/mysql-test/suite/bugs +usr/share/mysql/mysql-test/suite/bugs/t +usr/share/mysql/mysql-test/suite/bugs/r +usr/share/mysql/mysql-test/suite/bugs/data +usr/share/mysql/mysql-test/suite/rpl +usr/share/mysql/mysql-test/suite/rpl/t +usr/share/mysql/mysql-test/suite/rpl/r +usr/share/mysql/mysql-test/suite/rpl/include +usr/share/mysql/mysql-test/suite/innodb +usr/share/mysql/mysql-test/suite/innodb/t +usr/share/mysql/mysql-test/suite/innodb/r +usr/share/mysql/mysql-test/suite/innodb/include +usr/share/mysql/mysql-test/suite/manual +usr/share/mysql/mysql-test/suite/manual/t +usr/share/mysql/mysql-test/suite/manual/r +usr/share/mysql/mysql-test/suite/stress +usr/share/mysql/mysql-test/suite/stress/t +usr/share/mysql/mysql-test/suite/stress/r +usr/share/mysql/mysql-test/suite/stress/include +usr/share/mysql/mysql-test/suite/jp +usr/share/mysql/mysql-test/suite/jp/t +usr/share/mysql/mysql-test/suite/jp/r +usr/share/mysql/mysql-test/suite/jp/include +usr/share/mysql/mysql-test/suite/jp/std_data +usr/share/mysql/mysql-test/suite/ndb +usr/share/mysql/mysql-test/suite/ndb/t +usr/share/mysql/mysql-test/suite/ndb/r +usr/share/mysql/mysql-test/suite/maria +usr/share/mysql/mysql-test/suite/maria/t +usr/share/mysql/mysql-test/suite/maria/r +usr/share/mysql/mysql-test/suite/funcs_2 +usr/share/mysql/mysql-test/suite/funcs_2/lib +usr/share/mysql/mysql-test/suite/funcs_2/t +usr/share/mysql/mysql-test/suite/funcs_2/charset +usr/share/mysql/mysql-test/suite/funcs_2/r +usr/share/mysql/mysql-test/suite/funcs_2/include +usr/share/mysql/mysql-test/suite/funcs_2/data +usr/share/mysql/mysql-test/suite/binlog +usr/share/mysql/mysql-test/suite/binlog/t +usr/share/mysql/mysql-test/suite/binlog/r +usr/share/mysql/mysql-test/suite/binlog/std_data +usr/share/mysql/mysql-test/suite/ndb_team +usr/share/mysql/mysql-test/suite/ndb_team/t +usr/share/mysql/mysql-test/suite/ndb_team/r +usr/share/mysql/mysql-test/suite/federated +usr/share/mysql/mysql-test/suite/pbxt +usr/share/mysql/mysql-test/suite/pbxt/t +usr/share/mysql/mysql-test/suite/pbxt/r +usr/share/mysql/mysql-test/suite/funcs_1 +usr/share/mysql/mysql-test/suite/funcs_1/cursors +usr/share/mysql/mysql-test/suite/funcs_1/bitdata +usr/share/mysql/mysql-test/suite/funcs_1/views +usr/share/mysql/mysql-test/suite/funcs_1/storedproc +usr/share/mysql/mysql-test/suite/funcs_1/triggers +usr/share/mysql/mysql-test/suite/funcs_1/lib +usr/share/mysql/mysql-test/suite/funcs_1/t +usr/share/mysql/mysql-test/suite/funcs_1/r +usr/share/mysql/mysql-test/suite/funcs_1/include +usr/share/mysql/mysql-test/suite/funcs_1/datadict +usr/share/mysql/mysql-test/suite/vcol +usr/share/mysql/mysql-test/suite/vcol/inc +usr/share/mysql/mysql-test/suite/vcol/t +usr/share/mysql/mysql-test/suite/vcol/r +usr/share/mysql/mysql-test/suite/oqgraph +usr/share/mysql/mysql-test/suite/oqgraph/t +usr/share/mysql/mysql-test/suite/oqgraph/r +usr/share/mysql/mysql-test/suite/oqgraph/include +usr/share/mysql/mysql-test/std_data +usr/share/mysql/mysql-test/std_data/ndb_backup50 +usr/share/mysql/mysql-test/std_data/parts +usr/share/mysql/mysql-test/std_data/ndb_backup51_data_le +usr/share/mysql/mysql-test/std_data/ndb_backup51_data_be +usr/share/mysql/mysql-test/std_data/ndb_backup51 +usr/share/mysql/mysql-test/std_data/funcs_1 diff --git a/debian/mariadb-test-5.5.files b/debian/mariadb-test-5.5.files new file mode 100644 index 00000000000..ac4fc1c4fca --- /dev/null +++ b/debian/mariadb-test-5.5.files @@ -0,0 +1,9 @@ +usr/bin/mysql_client_test +usr/bin/mysql_client_test_embedded +usr/bin/mysqltest_embedded +usr/share/man/man1/mysql_client_test.1 +usr/share/man/man1/mysql_client_test_embedded.1 +usr/bin/mysqltest +usr/share/man/man1/mysqltest.1 +usr/share/man/man1/mysqltest_embedded.1 +usr/share/mysql/mysql-test diff --git a/debian/mariadb-test-5.5.links b/debian/mariadb-test-5.5.links new file mode 100644 index 00000000000..082680fe5ed --- /dev/null +++ b/debian/mariadb-test-5.5.links @@ -0,0 +1,2 @@ +usr/share/mysql/mysql-test/mysql-test-run.pl usr/share/mysql/mysql-test/mysql-test-run +usr/share/mysql/mysql-test/mysql-test-run.pl usr/share/mysql/mysql-test/mtr diff --git a/debian/mysql-common.dirs b/debian/mysql-common.dirs new file mode 100644 index 00000000000..a5a88ede9c1 --- /dev/null +++ b/debian/mysql-common.dirs @@ -0,0 +1 @@ +etc/mysql/conf.d/ diff --git a/debian/mysql-common.files b/debian/mysql-common.files new file mode 100644 index 00000000000..d167569e892 --- /dev/null +++ b/debian/mysql-common.files @@ -0,0 +1,3 @@ +etc/mysql/my.cnf +usr/share/mysql-common/internal-use-only +usr/share/lintian/overrides/mysql-common diff --git a/debian/mysql-common.lintian-overrides b/debian/mysql-common.lintian-overrides new file mode 100644 index 00000000000..c6c60ccdc71 --- /dev/null +++ b/debian/mysql-common.lintian-overrides @@ -0,0 +1,2 @@ +script-not-executable ./usr/share/mysql-common/internal-use-only/_etc_init.d_mysql +script-not-executable ./usr/share/mysql-common/internal-use-only/_etc_mysql_debian-start diff --git a/debian/mysql-common.postrm b/debian/mysql-common.postrm new file mode 100644 index 00000000000..0d3f8aed83d --- /dev/null +++ b/debian/mysql-common.postrm @@ -0,0 +1,7 @@ +#!/bin/bash -e + +if [ "$1" = "purge" ]; then + rmdir /etc/mysql 2>/dev/null || true +fi + +#DEBHELPER# diff --git a/debian/patches/00list b/debian/patches/00list new file mode 100644 index 00000000000..77c159a17ed --- /dev/null +++ b/debian/patches/00list @@ -0,0 +1,11 @@ +# 01_MAKEFILES__Docs_Images_Makefile.in.dpatch +# 01_MAKEFILES__Docs_Makefile.in.dpatch +# 02_no_builtin_ndbcluster_plugin.dpatch +# 21_init__openquery_configtest.dpatch +33_scripts__mysql_create_system_tables__no_test.dpatch +38_scripts__mysqld_safe.sh__signals.dpatch +41_scripts__mysql_install_db.sh__no_test.dpatch +44_scripts__mysql_config__libs.dpatch +50_mysql-test__db_test.dpatch +# 60_zlib_innodb_workaround.dpatch +61_replace_dash_with_bash_mbug675185.dpatch diff --git a/debian/patches/01_MAKEFILES__Docs_Images_Makefile.in.dpatch b/debian/patches/01_MAKEFILES__Docs_Images_Makefile.in.dpatch new file mode 100755 index 00000000000..ca138afa746 --- /dev/null +++ b/debian/patches/01_MAKEFILES__Docs_Images_Makefile.in.dpatch @@ -0,0 +1,776 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01_MAKEFILES__Docs_Makefile.in.dpatch by +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Creates Docs/Makefile.in + +@DPATCH@ + +--- old/Docs/Images/Makefile.in 2005-03-01 02:08:01.877429040 +0100 ++++ new/Docs/Images/Makefile.in 2005-02-28 21:21:24.000000000 +0100 +@@ -0,0 +1,765 @@ ++# Makefile.in generated by automake 1.7.9 from Makefile.am. ++# @configure_input@ ++ ++# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 ++# Free Software Foundation, Inc. ++# This Makefile.in is free software; the Free Software Foundation ++# gives unlimited permission to copy and/or distribute it, ++# with or without modifications, as long as this notice is preserved. ++ ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY, to the extent permitted by law; without ++# even the implied warranty of MERCHANTABILITY or FITNESS FOR A ++# PARTICULAR PURPOSE. ++ ++@SET_MAKE@ ++ ++# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB ++# ++# 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 Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT 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 ++ ++# Process this file with automake to create Makefile.in ++ ++srcdir = @srcdir@ ++top_srcdir = @top_srcdir@ ++VPATH = @srcdir@ ++pkgdatadir = $(datadir)/@PACKAGE@ ++pkglibdir = $(libdir)/@PACKAGE@ ++pkgincludedir = $(includedir)/@PACKAGE@ ++top_builddir = . ++ ++am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd ++INSTALL = @INSTALL@ ++install_sh_DATA = $(install_sh) -c -m 644 ++install_sh_PROGRAM = $(install_sh) -c ++install_sh_SCRIPT = $(install_sh) -c ++INSTALL_HEADER = $(INSTALL_DATA) ++transform = $(program_transform_name) ++NORMAL_INSTALL = : ++PRE_INSTALL = : ++POST_INSTALL = : ++NORMAL_UNINSTALL = : ++PRE_UNINSTALL = : ++POST_UNINSTALL = : ++build_triplet = @build@ ++host_triplet = @host@ ++target_triplet = @target@ ++ACLOCAL = @ACLOCAL@ ++ALLOCA = @ALLOCA@ ++AMDEP_FALSE = @AMDEP_FALSE@ ++AMDEP_TRUE = @AMDEP_TRUE@ ++AMTAR = @AMTAR@ ++AR = @AR@ ++AS = @AS@ ++ASSEMBLER_FALSE = @ASSEMBLER_FALSE@ ++ASSEMBLER_TRUE = @ASSEMBLER_TRUE@ ++ASSEMBLER_sparc32_FALSE = @ASSEMBLER_sparc32_FALSE@ ++ASSEMBLER_sparc32_TRUE = @ASSEMBLER_sparc32_TRUE@ ++ASSEMBLER_sparc64_FALSE = @ASSEMBLER_sparc64_FALSE@ ++ASSEMBLER_sparc64_TRUE = @ASSEMBLER_sparc64_TRUE@ ++ASSEMBLER_x86_FALSE = @ASSEMBLER_x86_FALSE@ ++ASSEMBLER_x86_TRUE = @ASSEMBLER_x86_TRUE@ ++AUTOCONF = @AUTOCONF@ ++AUTOHEADER = @AUTOHEADER@ ++AUTOMAKE = @AUTOMAKE@ ++AVAILABLE_LANGUAGES = @AVAILABLE_LANGUAGES@ ++AVAILABLE_LANGUAGES_ERRORS = @AVAILABLE_LANGUAGES_ERRORS@ ++AWK = @AWK@ ++CC = @CC@ ++CCAS = @CCAS@ ++CCASFLAGS = @CCASFLAGS@ ++CCDEPMODE = @CCDEPMODE@ ++CC_VERSION = @CC_VERSION@ ++CFLAGS = @CFLAGS@ ++CHARSETS_NEED_SOURCE = @CHARSETS_NEED_SOURCE@ ++CHARSET_OBJS = @CHARSET_OBJS@ ++CHARSET_SRCS = @CHARSET_SRCS@ ++CHECK_PID = @CHECK_PID@ ++CHMOD = @CHMOD@ ++CLIENT_EXTRA_LDFLAGS = @CLIENT_EXTRA_LDFLAGS@ ++CLIENT_LIBS = @CLIENT_LIBS@ ++CMP = @CMP@ ++COMPILATION_COMMENT = @COMPILATION_COMMENT@ ++COMPILE_PSTACK_FALSE = @COMPILE_PSTACK_FALSE@ ++COMPILE_PSTACK_TRUE = @COMPILE_PSTACK_TRUE@ ++CONF_COMMAND = @CONF_COMMAND@ ++CP = @CP@ ++CPP = @CPP@ ++CPPFLAGS = @CPPFLAGS@ ++CXX = @CXX@ ++CXXCPP = @CXXCPP@ ++CXXDEPMODE = @CXXDEPMODE@ ++CXXFLAGS = @CXXFLAGS@ ++CXXLDFLAGS = @CXXLDFLAGS@ ++CXX_VERSION = @CXX_VERSION@ ++CYGPATH_W = @CYGPATH_W@ ++DEFS = @DEFS@ ++DEPDIR = @DEPDIR@ ++DOT_FRM_VERSION = @DOT_FRM_VERSION@ ++DVIS = @DVIS@ ++ECHO = @ECHO@ ++ECHO_C = @ECHO_C@ ++ECHO_N = @ECHO_N@ ++ECHO_T = @ECHO_T@ ++EGREP = @EGREP@ ++EXEEXT = @EXEEXT@ ++F77 = @F77@ ++FFLAGS = @FFLAGS@ ++FIND_PROC = @FIND_PROC@ ++GETCONF = @GETCONF@ ++GXX = @GXX@ ++HAVE_NETWARE_FALSE = @HAVE_NETWARE_FALSE@ ++HAVE_NETWARE_TRUE = @HAVE_NETWARE_TRUE@ ++HOSTNAME = @HOSTNAME@ ++INSTALL_DATA = @INSTALL_DATA@ ++INSTALL_PROGRAM = @INSTALL_PROGRAM@ ++INSTALL_SCRIPT = @INSTALL_SCRIPT@ ++INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ ++IS_LINUX = @IS_LINUX@ ++KILL = @KILL@ ++LD = @LD@ ++LDFLAGS = @LDFLAGS@ ++LIBDL = @LIBDL@ ++LIBOBJS = @LIBOBJS@ ++LIBS = @LIBS@ ++LIBTOOL = @LIBTOOL@ ++LIB_EXTRA_CCFLAGS = @LIB_EXTRA_CCFLAGS@ ++LM_CFLAGS = @LM_CFLAGS@ ++LN = @LN@ ++LN_CP_F = @LN_CP_F@ ++LN_S = @LN_S@ ++LOCAL_FALSE = @LOCAL_FALSE@ ++LOCAL_TRUE = @LOCAL_TRUE@ ++LTLIBOBJS = @LTLIBOBJS@ ++MACHINE_TYPE = @MACHINE_TYPE@ ++MAINT = @MAINT@ ++MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ ++MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ ++MAKEINFO = @MAKEINFO@ ++MAKE_BINARY_DISTRIBUTION_OPTIONS = @MAKE_BINARY_DISTRIBUTION_OPTIONS@ ++MAKE_SHELL = @MAKE_SHELL@ ++MT_INCLUDES = @MT_INCLUDES@ ++MT_LD_ADD = @MT_LD_ADD@ ++MV = @MV@ ++MYSQLD_DEFAULT_SWITCHES = @MYSQLD_DEFAULT_SWITCHES@ ++MYSQLD_EXTRA_LDFLAGS = @MYSQLD_EXTRA_LDFLAGS@ ++MYSQLD_USER = @MYSQLD_USER@ ++MYSQL_BASE_VERSION = @MYSQL_BASE_VERSION@ ++MYSQL_NO_DASH_VERSION = @MYSQL_NO_DASH_VERSION@ ++MYSQL_SERVER_SUFFIX = @MYSQL_SERVER_SUFFIX@ ++MYSQL_TCP_PORT = @MYSQL_TCP_PORT@ ++MYSQL_TCP_PORT_DEFAULT = @MYSQL_TCP_PORT_DEFAULT@ ++MYSQL_UNIX_ADDR = @MYSQL_UNIX_ADDR@ ++MYSQL_VERSION_ID = @MYSQL_VERSION_ID@ ++NOINST_LDFLAGS = @NOINST_LDFLAGS@ ++OBJEXT = @OBJEXT@ ++PACKAGE = @PACKAGE@ ++PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ ++PACKAGE_NAME = @PACKAGE_NAME@ ++PACKAGE_STRING = @PACKAGE_STRING@ ++PACKAGE_TARNAME = @PACKAGE_TARNAME@ ++PACKAGE_VERSION = @PACKAGE_VERSION@ ++PATH_SEPARATOR = @PATH_SEPARATOR@ ++PDFMANUAL = @PDFMANUAL@ ++PERL = @PERL@ ++PERL5 = @PERL5@ ++PROTOCOL_VERSION = @PROTOCOL_VERSION@ ++PS = @PS@ ++RANLIB = @RANLIB@ ++RM = @RM@ ++SAVE_ASFLAGS = @SAVE_ASFLAGS@ ++SAVE_CFLAGS = @SAVE_CFLAGS@ ++SAVE_CXXFLAGS = @SAVE_CXXFLAGS@ ++SAVE_CXXLDFLAGS = @SAVE_CXXLDFLAGS@ ++SAVE_LDFLAGS = @SAVE_LDFLAGS@ ++SED = @SED@ ++SET_MAKE = @SET_MAKE@ ++SHARED_LIB_VERSION = @SHARED_LIB_VERSION@ ++SHELL = @SHELL@ ++STRIP = @STRIP@ ++SYSTEM_TYPE = @SYSTEM_TYPE@ ++TAR = @TAR@ ++TERMCAP_LIB = @TERMCAP_LIB@ ++THREAD_LOBJECTS = @THREAD_LOBJECTS@ ++THREAD_LPROGRAMS = @THREAD_LPROGRAMS@ ++VERSION = @VERSION@ ++WRAPLIBS = @WRAPLIBS@ ++YACC = @YACC@ ++ac_ct_AR = @ac_ct_AR@ ++ac_ct_CC = @ac_ct_CC@ ++ac_ct_CXX = @ac_ct_CXX@ ++ac_ct_F77 = @ac_ct_F77@ ++ac_ct_GETCONF = @ac_ct_GETCONF@ ++ac_ct_RANLIB = @ac_ct_RANLIB@ ++ac_ct_STRIP = @ac_ct_STRIP@ ++am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ ++am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ ++am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ ++am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ ++am__include = @am__include@ ++am__leading_dot = @am__leading_dot@ ++am__quote = @am__quote@ ++bdb_includes = @bdb_includes@ ++bdb_libs = @bdb_libs@ ++bdb_libs_with_path = @bdb_libs_with_path@ ++bench_dirs = @bench_dirs@ ++bindir = @bindir@ ++build = @build@ ++build_alias = @build_alias@ ++build_cpu = @build_cpu@ ++build_os = @build_os@ ++build_vendor = @build_vendor@ ++datadir = @datadir@ ++default_charset = @default_charset@ ++docs_dirs = @docs_dirs@ ++exec_prefix = @exec_prefix@ ++host = @host@ ++host_alias = @host_alias@ ++host_cpu = @host_cpu@ ++host_os = @host_os@ ++host_vendor = @host_vendor@ ++includedir = @includedir@ ++infodir = @infodir@ ++innodb_includes = @innodb_includes@ ++innodb_libs = @innodb_libs@ ++innodb_system_libs = @innodb_system_libs@ ++install_sh = @install_sh@ ++isam_libs = @isam_libs@ ++libdir = @libdir@ ++libexecdir = @libexecdir@ ++libmysqld_dirs = @libmysqld_dirs@ ++linked_client_targets = @linked_client_targets@ ++linked_netware_sources = @linked_netware_sources@ ++localstatedir = @localstatedir@ ++man_dirs = @man_dirs@ ++mandir = @mandir@ ++netware_dir = @netware_dir@ ++oldincludedir = @oldincludedir@ ++openssl_includes = @openssl_includes@ ++openssl_libs = @openssl_libs@ ++orbit_idl = @orbit_idl@ ++orbit_includes = @orbit_includes@ ++orbit_libs = @orbit_libs@ ++prefix = @prefix@ ++program_transform_name = @program_transform_name@ ++pstack_dirs = @pstack_dirs@ ++pstack_libs = @pstack_libs@ ++readline_dir = @readline_dir@ ++readline_link = @readline_link@ ++sbindir = @sbindir@ ++server_scripts = @server_scripts@ ++sharedstatedir = @sharedstatedir@ ++sql_client_dirs = @sql_client_dirs@ ++sql_server_dirs = @sql_server_dirs@ ++sysconfdir = @sysconfdir@ ++target = @target@ ++target_alias = @target_alias@ ++target_cpu = @target_cpu@ ++target_os = @target_os@ ++target_vendor = @target_vendor@ ++thread_dirs = @thread_dirs@ ++tools_dirs = @tools_dirs@ ++uname_prog = @uname_prog@ ++vio_dir = @vio_dir@ ++vio_libs = @vio_libs@ ++ ++AUTOMAKE_OPTIONS = foreign ++ ++# These are built from source in the Docs directory ++EXTRA_DIST = INSTALL-SOURCE README COPYING EXCEPTIONS-CLIENT ++SUBDIRS = . include @docs_dirs@ @readline_dir@ \ ++ @thread_dirs@ pstack @sql_client_dirs@ \ ++ @sql_server_dirs@ scripts @man_dirs@ tests \ ++ BUILD netware os2 @libmysqld_dirs@ \ ++ @bench_dirs@ support-files @tools_dirs@ ++ ++ ++# Relink after clean ++linked_sources = linked_client_sources linked_server_sources \ ++ linked_libmysql_sources linked_libmysql_r_sources \ ++ linked_libmysqld_sources linked_libmysqldex_sources \ ++ linked_include_sources @linked_netware_sources@ ++ ++ ++CLEANFILES = $(linked_sources) ++subdir = . ++ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 ++mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs ++CONFIG_HEADER = config.h ++CONFIG_CLEAN_FILES = bdb/Makefile ++DIST_SOURCES = ++ ++RECURSIVE_TARGETS = info-recursive dvi-recursive pdf-recursive \ ++ ps-recursive install-info-recursive uninstall-info-recursive \ ++ all-recursive install-data-recursive install-exec-recursive \ ++ installdirs-recursive install-recursive uninstall-recursive \ ++ check-recursive installcheck-recursive ++DIST_COMMON = README $(srcdir)/Makefile.in $(srcdir)/configure COPYING \ ++ ChangeLog Makefile.am acconfig.h acinclude.m4 aclocal.m4 \ ++ config.guess config.h.in config.sub configure configure.in \ ++ depcomp install-sh ltconfig ltmain.sh missing mkinstalldirs ++DIST_SUBDIRS = $(SUBDIRS) ++all: config.h ++ $(MAKE) $(AM_MAKEFLAGS) all-recursive ++ ++.SUFFIXES: ++ ++am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ ++ configure.lineno ++$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) ++ cd $(top_srcdir) && \ ++ $(AUTOMAKE) --foreign Makefile ++Makefile: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.in $(top_builddir)/config.status ++ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe) ++ ++$(top_builddir)/config.status: $(srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) ++ $(SHELL) ./config.status --recheck ++$(srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES) ++ cd $(srcdir) && $(AUTOCONF) ++ ++$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ configure.in acinclude.m4 ++ cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) ++ ++stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status ++ @rm -f stamp-h1 ++ cd $(top_builddir) && $(SHELL) ./config.status config.h ++ ++$(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(top_srcdir)/configure.in $(ACLOCAL_M4) $(top_srcdir)/acconfig.h ++ cd $(top_srcdir) && $(AUTOHEADER) ++ touch $(srcdir)/config.h.in ++ ++distclean-hdr: ++ -rm -f config.h stamp-h1 ++bdb/Makefile: $(top_builddir)/config.status $(top_srcdir)/bdb/Makefile.in ++ cd $(top_builddir) && $(SHELL) ./config.status $@ ++ ++mostlyclean-libtool: ++ -rm -f *.lo ++ ++clean-libtool: ++ -rm -rf .libs _libs ++ ++distclean-libtool: ++ -rm -f libtool ++uninstall-info-am: ++ ++# This directory's subdirectories are mostly independent; you can cd ++# into them and run `make' without going through this Makefile. ++# To change the values of `make' variables: instead of editing Makefiles, ++# (1) if the variable is set in `config.status', edit `config.status' ++# (which will cause the Makefiles to be regenerated when you run `make'); ++# (2) otherwise, pass the desired values on the `make' command line. ++$(RECURSIVE_TARGETS): ++ @set fnord $$MAKEFLAGS; amf=$$2; \ ++ dot_seen=no; \ ++ target=`echo $@ | sed s/-recursive//`; \ ++ list='$(SUBDIRS)'; for subdir in $$list; do \ ++ echo "Making $$target in $$subdir"; \ ++ if test "$$subdir" = "."; then \ ++ dot_seen=yes; \ ++ local_target="$$target-am"; \ ++ else \ ++ local_target="$$target"; \ ++ fi; \ ++ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ ++ || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ ++ done; \ ++ if test "$$dot_seen" = "no"; then \ ++ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ ++ fi; test -z "$$fail" ++ ++mostlyclean-recursive clean-recursive distclean-recursive \ ++maintainer-clean-recursive: ++ @set fnord $$MAKEFLAGS; amf=$$2; \ ++ dot_seen=no; \ ++ case "$@" in \ ++ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ ++ *) list='$(SUBDIRS)' ;; \ ++ esac; \ ++ rev=''; for subdir in $$list; do \ ++ if test "$$subdir" = "."; then :; else \ ++ rev="$$subdir $$rev"; \ ++ fi; \ ++ done; \ ++ rev="$$rev ."; \ ++ target=`echo $@ | sed s/-recursive//`; \ ++ for subdir in $$rev; do \ ++ echo "Making $$target in $$subdir"; \ ++ if test "$$subdir" = "."; then \ ++ local_target="$$target-am"; \ ++ else \ ++ local_target="$$target"; \ ++ fi; \ ++ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ ++ || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ ++ done && test -z "$$fail" ++tags-recursive: ++ list='$(SUBDIRS)'; for subdir in $$list; do \ ++ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ ++ done ++ctags-recursive: ++ list='$(SUBDIRS)'; for subdir in $$list; do \ ++ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ ++ done ++ ++ETAGS = etags ++ETAGSFLAGS = ++ ++CTAGS = ctags ++CTAGSFLAGS = ++ ++ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) ++ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ ++ unique=`for i in $$list; do \ ++ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ ++ done | \ ++ $(AWK) ' { files[$$0] = 1; } \ ++ END { for (i in files) print i; }'`; \ ++ mkid -fID $$unique ++ ++TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ ++ $(TAGS_FILES) $(LISP) ++ tags=; \ ++ here=`pwd`; \ ++ if (etags --etags-include --version) >/dev/null 2>&1; then \ ++ include_option=--etags-include; \ ++ else \ ++ include_option=--include; \ ++ fi; \ ++ list='$(SUBDIRS)'; for subdir in $$list; do \ ++ if test "$$subdir" = .; then :; else \ ++ test -f $$subdir/TAGS && \ ++ tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \ ++ fi; \ ++ done; \ ++ list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ ++ unique=`for i in $$list; do \ ++ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ ++ done | \ ++ $(AWK) ' { files[$$0] = 1; } \ ++ END { for (i in files) print i; }'`; \ ++ test -z "$(ETAGS_ARGS)$$tags$$unique" \ ++ || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ ++ $$tags $$unique ++ ++ctags: CTAGS ++CTAGS: ctags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ ++ $(TAGS_FILES) $(LISP) ++ tags=; \ ++ here=`pwd`; \ ++ list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ ++ unique=`for i in $$list; do \ ++ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ ++ done | \ ++ $(AWK) ' { files[$$0] = 1; } \ ++ END { for (i in files) print i; }'`; \ ++ test -z "$(CTAGS_ARGS)$$tags$$unique" \ ++ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ ++ $$tags $$unique ++ ++GTAGS: ++ here=`$(am__cd) $(top_builddir) && pwd` \ ++ && cd $(top_srcdir) \ ++ && gtags -i $(GTAGS_ARGS) $$here ++ ++distclean-tags: ++ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags ++DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ++ ++top_distdir = . ++distdir = $(PACKAGE)-$(VERSION) ++ ++am__remove_distdir = \ ++ { test ! -d $(distdir) \ ++ || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \ ++ && rm -fr $(distdir); }; } ++ ++GZIP_ENV = --best ++distuninstallcheck_listfiles = find . -type f -print ++distcleancheck_listfiles = find . -type f -print ++ ++distdir: $(DISTFILES) ++ $(am__remove_distdir) ++ mkdir $(distdir) ++ $(mkinstalldirs) $(distdir)/bdb $(distdir)/include ++ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ ++ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ ++ list='$(DISTFILES)'; for file in $$list; do \ ++ case $$file in \ ++ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ ++ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ ++ esac; \ ++ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ ++ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ ++ if test "$$dir" != "$$file" && test "$$dir" != "."; then \ ++ dir="/$$dir"; \ ++ $(mkinstalldirs) "$(distdir)$$dir"; \ ++ else \ ++ dir=''; \ ++ fi; \ ++ if test -d $$d/$$file; then \ ++ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ ++ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ ++ fi; \ ++ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ ++ else \ ++ test -f $(distdir)/$$file \ ++ || cp -p $$d/$$file $(distdir)/$$file \ ++ || exit 1; \ ++ fi; \ ++ done ++ list='$(SUBDIRS)'; for subdir in $$list; do \ ++ if test "$$subdir" = .; then :; else \ ++ test -d $(distdir)/$$subdir \ ++ || mkdir $(distdir)/$$subdir \ ++ || exit 1; \ ++ (cd $$subdir && \ ++ $(MAKE) $(AM_MAKEFLAGS) \ ++ top_distdir="$(top_distdir)" \ ++ distdir=../$(distdir)/$$subdir \ ++ distdir) \ ++ || exit 1; \ ++ fi; \ ++ done ++ $(MAKE) $(AM_MAKEFLAGS) \ ++ top_distdir="$(top_distdir)" distdir="$(distdir)" \ ++ dist-hook ++ -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \ ++ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ++ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ++ ! -type d ! -perm -444 -exec $(SHELL) $(install_sh) -c -m a+r {} {} \; \ ++ || chmod -R a+r $(distdir) ++dist-gzip: distdir ++ $(AMTAR) chof - $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz ++ $(am__remove_distdir) ++ ++dist dist-all: distdir ++ $(AMTAR) chof - $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz ++ $(am__remove_distdir) ++ ++# This target untars the dist file and tries a VPATH configuration. Then ++# it guarantees that the distribution is self-contained by making another ++# tarfile. ++distcheck: dist ++ $(am__remove_distdir) ++ GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(AMTAR) xf - ++ chmod -R a-w $(distdir); chmod a+w $(distdir) ++ mkdir $(distdir)/_build ++ mkdir $(distdir)/_inst ++ chmod a-w $(distdir) ++ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ ++ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ ++ && cd $(distdir)/_build \ ++ && ../configure --srcdir=.. --prefix="$$dc_install_base" \ ++ $(DISTCHECK_CONFIGURE_FLAGS) \ ++ && $(MAKE) $(AM_MAKEFLAGS) \ ++ && $(MAKE) $(AM_MAKEFLAGS) dvi \ ++ && $(MAKE) $(AM_MAKEFLAGS) check \ ++ && $(MAKE) $(AM_MAKEFLAGS) install \ ++ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ ++ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ ++ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ ++ distuninstallcheck \ ++ && chmod -R a-w "$$dc_install_base" \ ++ && ({ \ ++ (cd ../.. && $(mkinstalldirs) "$$dc_destdir") \ ++ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ ++ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ ++ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ ++ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ ++ } || { rm -rf "$$dc_destdir"; exit 1; }) \ ++ && rm -rf "$$dc_destdir" \ ++ && $(MAKE) $(AM_MAKEFLAGS) dist-gzip \ ++ && rm -f $(distdir).tar.gz \ ++ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck ++ $(am__remove_distdir) ++ @echo "$(distdir).tar.gz is ready for distribution" | \ ++ sed 'h;s/./=/g;p;x;p;x' ++distuninstallcheck: ++ @cd $(distuninstallcheck_dir) \ ++ && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ ++ || { echo "ERROR: files left after uninstall:" ; \ ++ if test -n "$(DESTDIR)"; then \ ++ echo " (check DESTDIR support)"; \ ++ fi ; \ ++ $(distuninstallcheck_listfiles) ; \ ++ exit 1; } >&2 ++distcleancheck: distclean ++ @if test '$(srcdir)' = . ; then \ ++ echo "ERROR: distcleancheck can only run from a VPATH build" ; \ ++ exit 1 ; \ ++ fi ++ @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ ++ || { echo "ERROR: files left in build directory after distclean:" ; \ ++ $(distcleancheck_listfiles) ; \ ++ exit 1; } >&2 ++check-am: all-am ++check: check-recursive ++all-am: Makefile config.h ++installdirs: installdirs-recursive ++installdirs-am: ++ ++install: install-recursive ++install-exec: install-exec-recursive ++install-data: install-data-recursive ++uninstall: uninstall-recursive ++ ++install-am: all-am ++ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am ++ ++installcheck: installcheck-recursive ++install-strip: ++ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ ++ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ ++ `test -z '$(STRIP)' || \ ++ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install ++mostlyclean-generic: ++ ++clean-generic: ++ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) ++ ++distclean-generic: ++ -rm -f $(CONFIG_CLEAN_FILES) ++ ++maintainer-clean-generic: ++ @echo "This command is intended for maintainers to use" ++ @echo "it deletes files that may require special tools to rebuild." ++clean: clean-recursive ++ ++clean-am: clean-generic clean-libtool mostlyclean-am ++ ++distclean: distclean-recursive ++ -rm -f $(am__CONFIG_DISTCLEAN_FILES) ++ -rm -f Makefile ++distclean-am: clean-am distclean-generic distclean-hdr distclean-libtool \ ++ distclean-tags ++ ++dvi: dvi-recursive ++ ++dvi-am: ++ ++info: info-recursive ++ ++info-am: ++ ++install-data-am: ++ ++install-exec-am: ++ ++install-info: install-info-recursive ++ ++install-man: ++ ++installcheck-am: ++ ++maintainer-clean: maintainer-clean-recursive ++ -rm -f $(am__CONFIG_DISTCLEAN_FILES) ++ -rm -rf $(top_srcdir)/autom4te.cache ++ -rm -f Makefile ++maintainer-clean-am: distclean-am maintainer-clean-generic ++ ++mostlyclean: mostlyclean-recursive ++ ++mostlyclean-am: mostlyclean-generic mostlyclean-libtool ++ ++pdf: pdf-recursive ++ ++pdf-am: ++ ++ps: ps-recursive ++ ++ps-am: ++ ++uninstall-am: uninstall-info-am ++ ++uninstall-info: uninstall-info-recursive ++ ++.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am check check-am clean \ ++ clean-generic clean-libtool clean-recursive ctags \ ++ ctags-recursive dist dist-all dist-gzip distcheck distclean \ ++ distclean-generic distclean-hdr distclean-libtool \ ++ distclean-recursive distclean-tags distcleancheck distdir \ ++ distuninstallcheck dvi dvi-am dvi-recursive info info-am \ ++ info-recursive install install-am install-data install-data-am \ ++ install-data-recursive install-exec install-exec-am \ ++ install-exec-recursive install-info install-info-am \ ++ install-info-recursive install-man install-recursive \ ++ install-strip installcheck installcheck-am installdirs \ ++ installdirs-am installdirs-recursive maintainer-clean \ ++ maintainer-clean-generic maintainer-clean-recursive mostlyclean \ ++ mostlyclean-generic mostlyclean-libtool mostlyclean-recursive \ ++ pdf pdf-am pdf-recursive ps ps-am ps-recursive tags \ ++ tags-recursive uninstall uninstall-am uninstall-info-am \ ++ uninstall-info-recursive uninstall-recursive ++ ++ ++# This is just so that the linking is done early. ++config.h: $(linked_sources) ++ ++linked_include_sources: ++ cd include; $(MAKE) link_sources ++ echo timestamp > linked_include_sources ++ ++linked_client_sources: @linked_client_targets@ ++ cd client; $(MAKE) link_sources ++ echo timestamp > linked_client_sources ++ ++linked_libmysql_sources: ++ cd libmysql; $(MAKE) link_sources ++ echo timestamp > linked_libmysql_sources ++ ++linked_libmysql_r_sources: linked_libmysql_sources ++ cd libmysql_r; $(MAKE) link_sources ++ echo timestamp > linked_libmysql_r_sources ++ ++linked_libmysqld_sources: ++ cd libmysqld; $(MAKE) link_sources ++ echo timestamp > linked_libmysqld_sources ++ ++linked_libmysqldex_sources: ++ cd libmysqld/examples; $(MAKE) link_sources ++ echo timestamp > linked_libmysqldex_sources ++ ++linked_netware_sources: ++ cd @netware_dir@; $(MAKE) link_sources ++ echo timestamp > linked_netware_sources ++ ++#avoid recursive make calls in sql directory ++linked_server_sources: ++ cd sql; rm -f mini_client_errors.c;@LN_CP_F@ ../libmysql/errmsg.c mini_client_errors.c ++ echo timestamp > linked_server_sources ++ ++# Create permission databases ++init-db: all ++ $(top_builddir)/scripts/mysql_install_db ++ ++bin-dist: all ++ $(top_builddir)/scripts/make_binary_distribution @MAKE_BINARY_DISTRIBUTION_OPTIONS@ ++ ++# Remove BK's "SCCS" subdirectories from source distribution ++dist-hook: ++ rm -rf `find $(distdir) -type d -name SCCS` ++ ++tags: ++ support-files/build-tags ++.PHONY: init-db bin-dist ++ ++# Test installation ++ ++test: ++ cd mysql-test ; ./mysql-test-run ++# Tell versions [3.59,3.63) of GNU make to not export all variables. ++# Otherwise a system limit (for SysV at least) may be exceeded. ++.NOEXPORT: diff --git a/debian/patches/01_MAKEFILES__Docs_Makefile.in.dpatch b/debian/patches/01_MAKEFILES__Docs_Makefile.in.dpatch new file mode 100755 index 00000000000..6440697bc02 --- /dev/null +++ b/debian/patches/01_MAKEFILES__Docs_Makefile.in.dpatch @@ -0,0 +1,776 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01_MAKEFILES__Docs_Makefile.in.dpatch by +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Creates Docs/Makefile.in + +@DPATCH@ + +--- old/Docs/Makefile.in 2005-03-01 02:08:01.877429040 +0100 ++++ new/Docs/Makefile.in 2005-02-28 21:21:24.000000000 +0100 +@@ -0,0 +1,765 @@ ++# Makefile.in generated by automake 1.7.9 from Makefile.am. ++# @configure_input@ ++ ++# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 ++# Free Software Foundation, Inc. ++# This Makefile.in is free software; the Free Software Foundation ++# gives unlimited permission to copy and/or distribute it, ++# with or without modifications, as long as this notice is preserved. ++ ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY, to the extent permitted by law; without ++# even the implied warranty of MERCHANTABILITY or FITNESS FOR A ++# PARTICULAR PURPOSE. ++ ++@SET_MAKE@ ++ ++# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB ++# ++# 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 Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT 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 ++ ++# Process this file with automake to create Makefile.in ++ ++srcdir = @srcdir@ ++top_srcdir = @top_srcdir@ ++VPATH = @srcdir@ ++pkgdatadir = $(datadir)/@PACKAGE@ ++pkglibdir = $(libdir)/@PACKAGE@ ++pkgincludedir = $(includedir)/@PACKAGE@ ++top_builddir = . ++ ++am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd ++INSTALL = @INSTALL@ ++install_sh_DATA = $(install_sh) -c -m 644 ++install_sh_PROGRAM = $(install_sh) -c ++install_sh_SCRIPT = $(install_sh) -c ++INSTALL_HEADER = $(INSTALL_DATA) ++transform = $(program_transform_name) ++NORMAL_INSTALL = : ++PRE_INSTALL = : ++POST_INSTALL = : ++NORMAL_UNINSTALL = : ++PRE_UNINSTALL = : ++POST_UNINSTALL = : ++build_triplet = @build@ ++host_triplet = @host@ ++target_triplet = @target@ ++ACLOCAL = @ACLOCAL@ ++ALLOCA = @ALLOCA@ ++AMDEP_FALSE = @AMDEP_FALSE@ ++AMDEP_TRUE = @AMDEP_TRUE@ ++AMTAR = @AMTAR@ ++AR = @AR@ ++AS = @AS@ ++ASSEMBLER_FALSE = @ASSEMBLER_FALSE@ ++ASSEMBLER_TRUE = @ASSEMBLER_TRUE@ ++ASSEMBLER_sparc32_FALSE = @ASSEMBLER_sparc32_FALSE@ ++ASSEMBLER_sparc32_TRUE = @ASSEMBLER_sparc32_TRUE@ ++ASSEMBLER_sparc64_FALSE = @ASSEMBLER_sparc64_FALSE@ ++ASSEMBLER_sparc64_TRUE = @ASSEMBLER_sparc64_TRUE@ ++ASSEMBLER_x86_FALSE = @ASSEMBLER_x86_FALSE@ ++ASSEMBLER_x86_TRUE = @ASSEMBLER_x86_TRUE@ ++AUTOCONF = @AUTOCONF@ ++AUTOHEADER = @AUTOHEADER@ ++AUTOMAKE = @AUTOMAKE@ ++AVAILABLE_LANGUAGES = @AVAILABLE_LANGUAGES@ ++AVAILABLE_LANGUAGES_ERRORS = @AVAILABLE_LANGUAGES_ERRORS@ ++AWK = @AWK@ ++CC = @CC@ ++CCAS = @CCAS@ ++CCASFLAGS = @CCASFLAGS@ ++CCDEPMODE = @CCDEPMODE@ ++CC_VERSION = @CC_VERSION@ ++CFLAGS = @CFLAGS@ ++CHARSETS_NEED_SOURCE = @CHARSETS_NEED_SOURCE@ ++CHARSET_OBJS = @CHARSET_OBJS@ ++CHARSET_SRCS = @CHARSET_SRCS@ ++CHECK_PID = @CHECK_PID@ ++CHMOD = @CHMOD@ ++CLIENT_EXTRA_LDFLAGS = @CLIENT_EXTRA_LDFLAGS@ ++CLIENT_LIBS = @CLIENT_LIBS@ ++CMP = @CMP@ ++COMPILATION_COMMENT = @COMPILATION_COMMENT@ ++COMPILE_PSTACK_FALSE = @COMPILE_PSTACK_FALSE@ ++COMPILE_PSTACK_TRUE = @COMPILE_PSTACK_TRUE@ ++CONF_COMMAND = @CONF_COMMAND@ ++CP = @CP@ ++CPP = @CPP@ ++CPPFLAGS = @CPPFLAGS@ ++CXX = @CXX@ ++CXXCPP = @CXXCPP@ ++CXXDEPMODE = @CXXDEPMODE@ ++CXXFLAGS = @CXXFLAGS@ ++CXXLDFLAGS = @CXXLDFLAGS@ ++CXX_VERSION = @CXX_VERSION@ ++CYGPATH_W = @CYGPATH_W@ ++DEFS = @DEFS@ ++DEPDIR = @DEPDIR@ ++DOT_FRM_VERSION = @DOT_FRM_VERSION@ ++DVIS = @DVIS@ ++ECHO = @ECHO@ ++ECHO_C = @ECHO_C@ ++ECHO_N = @ECHO_N@ ++ECHO_T = @ECHO_T@ ++EGREP = @EGREP@ ++EXEEXT = @EXEEXT@ ++F77 = @F77@ ++FFLAGS = @FFLAGS@ ++FIND_PROC = @FIND_PROC@ ++GETCONF = @GETCONF@ ++GXX = @GXX@ ++HAVE_NETWARE_FALSE = @HAVE_NETWARE_FALSE@ ++HAVE_NETWARE_TRUE = @HAVE_NETWARE_TRUE@ ++HOSTNAME = @HOSTNAME@ ++INSTALL_DATA = @INSTALL_DATA@ ++INSTALL_PROGRAM = @INSTALL_PROGRAM@ ++INSTALL_SCRIPT = @INSTALL_SCRIPT@ ++INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ ++IS_LINUX = @IS_LINUX@ ++KILL = @KILL@ ++LD = @LD@ ++LDFLAGS = @LDFLAGS@ ++LIBDL = @LIBDL@ ++LIBOBJS = @LIBOBJS@ ++LIBS = @LIBS@ ++LIBTOOL = @LIBTOOL@ ++LIB_EXTRA_CCFLAGS = @LIB_EXTRA_CCFLAGS@ ++LM_CFLAGS = @LM_CFLAGS@ ++LN = @LN@ ++LN_CP_F = @LN_CP_F@ ++LN_S = @LN_S@ ++LOCAL_FALSE = @LOCAL_FALSE@ ++LOCAL_TRUE = @LOCAL_TRUE@ ++LTLIBOBJS = @LTLIBOBJS@ ++MACHINE_TYPE = @MACHINE_TYPE@ ++MAINT = @MAINT@ ++MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ ++MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ ++MAKEINFO = @MAKEINFO@ ++MAKE_BINARY_DISTRIBUTION_OPTIONS = @MAKE_BINARY_DISTRIBUTION_OPTIONS@ ++MAKE_SHELL = @MAKE_SHELL@ ++MT_INCLUDES = @MT_INCLUDES@ ++MT_LD_ADD = @MT_LD_ADD@ ++MV = @MV@ ++MYSQLD_DEFAULT_SWITCHES = @MYSQLD_DEFAULT_SWITCHES@ ++MYSQLD_EXTRA_LDFLAGS = @MYSQLD_EXTRA_LDFLAGS@ ++MYSQLD_USER = @MYSQLD_USER@ ++MYSQL_BASE_VERSION = @MYSQL_BASE_VERSION@ ++MYSQL_NO_DASH_VERSION = @MYSQL_NO_DASH_VERSION@ ++MYSQL_SERVER_SUFFIX = @MYSQL_SERVER_SUFFIX@ ++MYSQL_TCP_PORT = @MYSQL_TCP_PORT@ ++MYSQL_TCP_PORT_DEFAULT = @MYSQL_TCP_PORT_DEFAULT@ ++MYSQL_UNIX_ADDR = @MYSQL_UNIX_ADDR@ ++MYSQL_VERSION_ID = @MYSQL_VERSION_ID@ ++NOINST_LDFLAGS = @NOINST_LDFLAGS@ ++OBJEXT = @OBJEXT@ ++PACKAGE = @PACKAGE@ ++PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ ++PACKAGE_NAME = @PACKAGE_NAME@ ++PACKAGE_STRING = @PACKAGE_STRING@ ++PACKAGE_TARNAME = @PACKAGE_TARNAME@ ++PACKAGE_VERSION = @PACKAGE_VERSION@ ++PATH_SEPARATOR = @PATH_SEPARATOR@ ++PDFMANUAL = @PDFMANUAL@ ++PERL = @PERL@ ++PERL5 = @PERL5@ ++PROTOCOL_VERSION = @PROTOCOL_VERSION@ ++PS = @PS@ ++RANLIB = @RANLIB@ ++RM = @RM@ ++SAVE_ASFLAGS = @SAVE_ASFLAGS@ ++SAVE_CFLAGS = @SAVE_CFLAGS@ ++SAVE_CXXFLAGS = @SAVE_CXXFLAGS@ ++SAVE_CXXLDFLAGS = @SAVE_CXXLDFLAGS@ ++SAVE_LDFLAGS = @SAVE_LDFLAGS@ ++SED = @SED@ ++SET_MAKE = @SET_MAKE@ ++SHARED_LIB_VERSION = @SHARED_LIB_VERSION@ ++SHELL = @SHELL@ ++STRIP = @STRIP@ ++SYSTEM_TYPE = @SYSTEM_TYPE@ ++TAR = @TAR@ ++TERMCAP_LIB = @TERMCAP_LIB@ ++THREAD_LOBJECTS = @THREAD_LOBJECTS@ ++THREAD_LPROGRAMS = @THREAD_LPROGRAMS@ ++VERSION = @VERSION@ ++WRAPLIBS = @WRAPLIBS@ ++YACC = @YACC@ ++ac_ct_AR = @ac_ct_AR@ ++ac_ct_CC = @ac_ct_CC@ ++ac_ct_CXX = @ac_ct_CXX@ ++ac_ct_F77 = @ac_ct_F77@ ++ac_ct_GETCONF = @ac_ct_GETCONF@ ++ac_ct_RANLIB = @ac_ct_RANLIB@ ++ac_ct_STRIP = @ac_ct_STRIP@ ++am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ ++am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ ++am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ ++am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ ++am__include = @am__include@ ++am__leading_dot = @am__leading_dot@ ++am__quote = @am__quote@ ++bdb_includes = @bdb_includes@ ++bdb_libs = @bdb_libs@ ++bdb_libs_with_path = @bdb_libs_with_path@ ++bench_dirs = @bench_dirs@ ++bindir = @bindir@ ++build = @build@ ++build_alias = @build_alias@ ++build_cpu = @build_cpu@ ++build_os = @build_os@ ++build_vendor = @build_vendor@ ++datadir = @datadir@ ++default_charset = @default_charset@ ++docs_dirs = @docs_dirs@ ++exec_prefix = @exec_prefix@ ++host = @host@ ++host_alias = @host_alias@ ++host_cpu = @host_cpu@ ++host_os = @host_os@ ++host_vendor = @host_vendor@ ++includedir = @includedir@ ++infodir = @infodir@ ++innodb_includes = @innodb_includes@ ++innodb_libs = @innodb_libs@ ++innodb_system_libs = @innodb_system_libs@ ++install_sh = @install_sh@ ++isam_libs = @isam_libs@ ++libdir = @libdir@ ++libexecdir = @libexecdir@ ++libmysqld_dirs = @libmysqld_dirs@ ++linked_client_targets = @linked_client_targets@ ++linked_netware_sources = @linked_netware_sources@ ++localstatedir = @localstatedir@ ++man_dirs = @man_dirs@ ++mandir = @mandir@ ++netware_dir = @netware_dir@ ++oldincludedir = @oldincludedir@ ++openssl_includes = @openssl_includes@ ++openssl_libs = @openssl_libs@ ++orbit_idl = @orbit_idl@ ++orbit_includes = @orbit_includes@ ++orbit_libs = @orbit_libs@ ++prefix = @prefix@ ++program_transform_name = @program_transform_name@ ++pstack_dirs = @pstack_dirs@ ++pstack_libs = @pstack_libs@ ++readline_dir = @readline_dir@ ++readline_link = @readline_link@ ++sbindir = @sbindir@ ++server_scripts = @server_scripts@ ++sharedstatedir = @sharedstatedir@ ++sql_client_dirs = @sql_client_dirs@ ++sql_server_dirs = @sql_server_dirs@ ++sysconfdir = @sysconfdir@ ++target = @target@ ++target_alias = @target_alias@ ++target_cpu = @target_cpu@ ++target_os = @target_os@ ++target_vendor = @target_vendor@ ++thread_dirs = @thread_dirs@ ++tools_dirs = @tools_dirs@ ++uname_prog = @uname_prog@ ++vio_dir = @vio_dir@ ++vio_libs = @vio_libs@ ++ ++AUTOMAKE_OPTIONS = foreign ++ ++# These are built from source in the Docs directory ++EXTRA_DIST = INSTALL-SOURCE README COPYING EXCEPTIONS-CLIENT ++SUBDIRS = . include @docs_dirs@ @readline_dir@ \ ++ @thread_dirs@ pstack @sql_client_dirs@ \ ++ @sql_server_dirs@ scripts @man_dirs@ tests \ ++ BUILD netware os2 @libmysqld_dirs@ \ ++ @bench_dirs@ support-files @tools_dirs@ ++ ++ ++# Relink after clean ++linked_sources = linked_client_sources linked_server_sources \ ++ linked_libmysql_sources linked_libmysql_r_sources \ ++ linked_libmysqld_sources linked_libmysqldex_sources \ ++ linked_include_sources @linked_netware_sources@ ++ ++ ++CLEANFILES = $(linked_sources) ++subdir = . ++ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 ++mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs ++CONFIG_HEADER = config.h ++CONFIG_CLEAN_FILES = bdb/Makefile ++DIST_SOURCES = ++ ++RECURSIVE_TARGETS = info-recursive dvi-recursive pdf-recursive \ ++ ps-recursive install-info-recursive uninstall-info-recursive \ ++ all-recursive install-data-recursive install-exec-recursive \ ++ installdirs-recursive install-recursive uninstall-recursive \ ++ check-recursive installcheck-recursive ++DIST_COMMON = README $(srcdir)/Makefile.in $(srcdir)/configure COPYING \ ++ ChangeLog Makefile.am acconfig.h acinclude.m4 aclocal.m4 \ ++ config.guess config.h.in config.sub configure configure.in \ ++ depcomp install-sh ltconfig ltmain.sh missing mkinstalldirs ++DIST_SUBDIRS = $(SUBDIRS) ++all: config.h ++ $(MAKE) $(AM_MAKEFLAGS) all-recursive ++ ++.SUFFIXES: ++ ++am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ ++ configure.lineno ++$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) ++ cd $(top_srcdir) && \ ++ $(AUTOMAKE) --foreign Makefile ++Makefile: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.in $(top_builddir)/config.status ++ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe) ++ ++$(top_builddir)/config.status: $(srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) ++ $(SHELL) ./config.status --recheck ++$(srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES) ++ cd $(srcdir) && $(AUTOCONF) ++ ++$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ configure.in acinclude.m4 ++ cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) ++ ++stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status ++ @rm -f stamp-h1 ++ cd $(top_builddir) && $(SHELL) ./config.status config.h ++ ++$(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(top_srcdir)/configure.in $(ACLOCAL_M4) $(top_srcdir)/acconfig.h ++ cd $(top_srcdir) && $(AUTOHEADER) ++ touch $(srcdir)/config.h.in ++ ++distclean-hdr: ++ -rm -f config.h stamp-h1 ++bdb/Makefile: $(top_builddir)/config.status $(top_srcdir)/bdb/Makefile.in ++ cd $(top_builddir) && $(SHELL) ./config.status $@ ++ ++mostlyclean-libtool: ++ -rm -f *.lo ++ ++clean-libtool: ++ -rm -rf .libs _libs ++ ++distclean-libtool: ++ -rm -f libtool ++uninstall-info-am: ++ ++# This directory's subdirectories are mostly independent; you can cd ++# into them and run `make' without going through this Makefile. ++# To change the values of `make' variables: instead of editing Makefiles, ++# (1) if the variable is set in `config.status', edit `config.status' ++# (which will cause the Makefiles to be regenerated when you run `make'); ++# (2) otherwise, pass the desired values on the `make' command line. ++$(RECURSIVE_TARGETS): ++ @set fnord $$MAKEFLAGS; amf=$$2; \ ++ dot_seen=no; \ ++ target=`echo $@ | sed s/-recursive//`; \ ++ list='$(SUBDIRS)'; for subdir in $$list; do \ ++ echo "Making $$target in $$subdir"; \ ++ if test "$$subdir" = "."; then \ ++ dot_seen=yes; \ ++ local_target="$$target-am"; \ ++ else \ ++ local_target="$$target"; \ ++ fi; \ ++ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ ++ || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ ++ done; \ ++ if test "$$dot_seen" = "no"; then \ ++ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ ++ fi; test -z "$$fail" ++ ++mostlyclean-recursive clean-recursive distclean-recursive \ ++maintainer-clean-recursive: ++ @set fnord $$MAKEFLAGS; amf=$$2; \ ++ dot_seen=no; \ ++ case "$@" in \ ++ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ ++ *) list='$(SUBDIRS)' ;; \ ++ esac; \ ++ rev=''; for subdir in $$list; do \ ++ if test "$$subdir" = "."; then :; else \ ++ rev="$$subdir $$rev"; \ ++ fi; \ ++ done; \ ++ rev="$$rev ."; \ ++ target=`echo $@ | sed s/-recursive//`; \ ++ for subdir in $$rev; do \ ++ echo "Making $$target in $$subdir"; \ ++ if test "$$subdir" = "."; then \ ++ local_target="$$target-am"; \ ++ else \ ++ local_target="$$target"; \ ++ fi; \ ++ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ ++ || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ ++ done && test -z "$$fail" ++tags-recursive: ++ list='$(SUBDIRS)'; for subdir in $$list; do \ ++ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ ++ done ++ctags-recursive: ++ list='$(SUBDIRS)'; for subdir in $$list; do \ ++ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ ++ done ++ ++ETAGS = etags ++ETAGSFLAGS = ++ ++CTAGS = ctags ++CTAGSFLAGS = ++ ++ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) ++ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ ++ unique=`for i in $$list; do \ ++ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ ++ done | \ ++ $(AWK) ' { files[$$0] = 1; } \ ++ END { for (i in files) print i; }'`; \ ++ mkid -fID $$unique ++ ++TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ ++ $(TAGS_FILES) $(LISP) ++ tags=; \ ++ here=`pwd`; \ ++ if (etags --etags-include --version) >/dev/null 2>&1; then \ ++ include_option=--etags-include; \ ++ else \ ++ include_option=--include; \ ++ fi; \ ++ list='$(SUBDIRS)'; for subdir in $$list; do \ ++ if test "$$subdir" = .; then :; else \ ++ test -f $$subdir/TAGS && \ ++ tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \ ++ fi; \ ++ done; \ ++ list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ ++ unique=`for i in $$list; do \ ++ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ ++ done | \ ++ $(AWK) ' { files[$$0] = 1; } \ ++ END { for (i in files) print i; }'`; \ ++ test -z "$(ETAGS_ARGS)$$tags$$unique" \ ++ || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ ++ $$tags $$unique ++ ++ctags: CTAGS ++CTAGS: ctags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ ++ $(TAGS_FILES) $(LISP) ++ tags=; \ ++ here=`pwd`; \ ++ list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ ++ unique=`for i in $$list; do \ ++ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ ++ done | \ ++ $(AWK) ' { files[$$0] = 1; } \ ++ END { for (i in files) print i; }'`; \ ++ test -z "$(CTAGS_ARGS)$$tags$$unique" \ ++ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ ++ $$tags $$unique ++ ++GTAGS: ++ here=`$(am__cd) $(top_builddir) && pwd` \ ++ && cd $(top_srcdir) \ ++ && gtags -i $(GTAGS_ARGS) $$here ++ ++distclean-tags: ++ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags ++DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ++ ++top_distdir = . ++distdir = $(PACKAGE)-$(VERSION) ++ ++am__remove_distdir = \ ++ { test ! -d $(distdir) \ ++ || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \ ++ && rm -fr $(distdir); }; } ++ ++GZIP_ENV = --best ++distuninstallcheck_listfiles = find . -type f -print ++distcleancheck_listfiles = find . -type f -print ++ ++distdir: $(DISTFILES) ++ $(am__remove_distdir) ++ mkdir $(distdir) ++ $(mkinstalldirs) $(distdir)/bdb $(distdir)/include ++ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ ++ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ ++ list='$(DISTFILES)'; for file in $$list; do \ ++ case $$file in \ ++ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ ++ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ ++ esac; \ ++ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ ++ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ ++ if test "$$dir" != "$$file" && test "$$dir" != "."; then \ ++ dir="/$$dir"; \ ++ $(mkinstalldirs) "$(distdir)$$dir"; \ ++ else \ ++ dir=''; \ ++ fi; \ ++ if test -d $$d/$$file; then \ ++ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ ++ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ ++ fi; \ ++ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ ++ else \ ++ test -f $(distdir)/$$file \ ++ || cp -p $$d/$$file $(distdir)/$$file \ ++ || exit 1; \ ++ fi; \ ++ done ++ list='$(SUBDIRS)'; for subdir in $$list; do \ ++ if test "$$subdir" = .; then :; else \ ++ test -d $(distdir)/$$subdir \ ++ || mkdir $(distdir)/$$subdir \ ++ || exit 1; \ ++ (cd $$subdir && \ ++ $(MAKE) $(AM_MAKEFLAGS) \ ++ top_distdir="$(top_distdir)" \ ++ distdir=../$(distdir)/$$subdir \ ++ distdir) \ ++ || exit 1; \ ++ fi; \ ++ done ++ $(MAKE) $(AM_MAKEFLAGS) \ ++ top_distdir="$(top_distdir)" distdir="$(distdir)" \ ++ dist-hook ++ -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \ ++ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ++ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ++ ! -type d ! -perm -444 -exec $(SHELL) $(install_sh) -c -m a+r {} {} \; \ ++ || chmod -R a+r $(distdir) ++dist-gzip: distdir ++ $(AMTAR) chof - $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz ++ $(am__remove_distdir) ++ ++dist dist-all: distdir ++ $(AMTAR) chof - $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz ++ $(am__remove_distdir) ++ ++# This target untars the dist file and tries a VPATH configuration. Then ++# it guarantees that the distribution is self-contained by making another ++# tarfile. ++distcheck: dist ++ $(am__remove_distdir) ++ GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(AMTAR) xf - ++ chmod -R a-w $(distdir); chmod a+w $(distdir) ++ mkdir $(distdir)/_build ++ mkdir $(distdir)/_inst ++ chmod a-w $(distdir) ++ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ ++ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ ++ && cd $(distdir)/_build \ ++ && ../configure --srcdir=.. --prefix="$$dc_install_base" \ ++ $(DISTCHECK_CONFIGURE_FLAGS) \ ++ && $(MAKE) $(AM_MAKEFLAGS) \ ++ && $(MAKE) $(AM_MAKEFLAGS) dvi \ ++ && $(MAKE) $(AM_MAKEFLAGS) check \ ++ && $(MAKE) $(AM_MAKEFLAGS) install \ ++ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ ++ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ ++ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ ++ distuninstallcheck \ ++ && chmod -R a-w "$$dc_install_base" \ ++ && ({ \ ++ (cd ../.. && $(mkinstalldirs) "$$dc_destdir") \ ++ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ ++ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ ++ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ ++ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ ++ } || { rm -rf "$$dc_destdir"; exit 1; }) \ ++ && rm -rf "$$dc_destdir" \ ++ && $(MAKE) $(AM_MAKEFLAGS) dist-gzip \ ++ && rm -f $(distdir).tar.gz \ ++ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck ++ $(am__remove_distdir) ++ @echo "$(distdir).tar.gz is ready for distribution" | \ ++ sed 'h;s/./=/g;p;x;p;x' ++distuninstallcheck: ++ @cd $(distuninstallcheck_dir) \ ++ && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ ++ || { echo "ERROR: files left after uninstall:" ; \ ++ if test -n "$(DESTDIR)"; then \ ++ echo " (check DESTDIR support)"; \ ++ fi ; \ ++ $(distuninstallcheck_listfiles) ; \ ++ exit 1; } >&2 ++distcleancheck: distclean ++ @if test '$(srcdir)' = . ; then \ ++ echo "ERROR: distcleancheck can only run from a VPATH build" ; \ ++ exit 1 ; \ ++ fi ++ @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ ++ || { echo "ERROR: files left in build directory after distclean:" ; \ ++ $(distcleancheck_listfiles) ; \ ++ exit 1; } >&2 ++check-am: all-am ++check: check-recursive ++all-am: Makefile config.h ++installdirs: installdirs-recursive ++installdirs-am: ++ ++install: install-recursive ++install-exec: install-exec-recursive ++install-data: install-data-recursive ++uninstall: uninstall-recursive ++ ++install-am: all-am ++ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am ++ ++installcheck: installcheck-recursive ++install-strip: ++ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ ++ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ ++ `test -z '$(STRIP)' || \ ++ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install ++mostlyclean-generic: ++ ++clean-generic: ++ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) ++ ++distclean-generic: ++ -rm -f $(CONFIG_CLEAN_FILES) ++ ++maintainer-clean-generic: ++ @echo "This command is intended for maintainers to use" ++ @echo "it deletes files that may require special tools to rebuild." ++clean: clean-recursive ++ ++clean-am: clean-generic clean-libtool mostlyclean-am ++ ++distclean: distclean-recursive ++ -rm -f $(am__CONFIG_DISTCLEAN_FILES) ++ -rm -f Makefile ++distclean-am: clean-am distclean-generic distclean-hdr distclean-libtool \ ++ distclean-tags ++ ++dvi: dvi-recursive ++ ++dvi-am: ++ ++info: info-recursive ++ ++info-am: ++ ++install-data-am: ++ ++install-exec-am: ++ ++install-info: install-info-recursive ++ ++install-man: ++ ++installcheck-am: ++ ++maintainer-clean: maintainer-clean-recursive ++ -rm -f $(am__CONFIG_DISTCLEAN_FILES) ++ -rm -rf $(top_srcdir)/autom4te.cache ++ -rm -f Makefile ++maintainer-clean-am: distclean-am maintainer-clean-generic ++ ++mostlyclean: mostlyclean-recursive ++ ++mostlyclean-am: mostlyclean-generic mostlyclean-libtool ++ ++pdf: pdf-recursive ++ ++pdf-am: ++ ++ps: ps-recursive ++ ++ps-am: ++ ++uninstall-am: uninstall-info-am ++ ++uninstall-info: uninstall-info-recursive ++ ++.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am check check-am clean \ ++ clean-generic clean-libtool clean-recursive ctags \ ++ ctags-recursive dist dist-all dist-gzip distcheck distclean \ ++ distclean-generic distclean-hdr distclean-libtool \ ++ distclean-recursive distclean-tags distcleancheck distdir \ ++ distuninstallcheck dvi dvi-am dvi-recursive info info-am \ ++ info-recursive install install-am install-data install-data-am \ ++ install-data-recursive install-exec install-exec-am \ ++ install-exec-recursive install-info install-info-am \ ++ install-info-recursive install-man install-recursive \ ++ install-strip installcheck installcheck-am installdirs \ ++ installdirs-am installdirs-recursive maintainer-clean \ ++ maintainer-clean-generic maintainer-clean-recursive mostlyclean \ ++ mostlyclean-generic mostlyclean-libtool mostlyclean-recursive \ ++ pdf pdf-am pdf-recursive ps ps-am ps-recursive tags \ ++ tags-recursive uninstall uninstall-am uninstall-info-am \ ++ uninstall-info-recursive uninstall-recursive ++ ++ ++# This is just so that the linking is done early. ++config.h: $(linked_sources) ++ ++linked_include_sources: ++ cd include; $(MAKE) link_sources ++ echo timestamp > linked_include_sources ++ ++linked_client_sources: @linked_client_targets@ ++ cd client; $(MAKE) link_sources ++ echo timestamp > linked_client_sources ++ ++linked_libmysql_sources: ++ cd libmysql; $(MAKE) link_sources ++ echo timestamp > linked_libmysql_sources ++ ++linked_libmysql_r_sources: linked_libmysql_sources ++ cd libmysql_r; $(MAKE) link_sources ++ echo timestamp > linked_libmysql_r_sources ++ ++linked_libmysqld_sources: ++ cd libmysqld; $(MAKE) link_sources ++ echo timestamp > linked_libmysqld_sources ++ ++linked_libmysqldex_sources: ++ cd libmysqld/examples; $(MAKE) link_sources ++ echo timestamp > linked_libmysqldex_sources ++ ++linked_netware_sources: ++ cd @netware_dir@; $(MAKE) link_sources ++ echo timestamp > linked_netware_sources ++ ++#avoid recursive make calls in sql directory ++linked_server_sources: ++ cd sql; rm -f mini_client_errors.c;@LN_CP_F@ ../libmysql/errmsg.c mini_client_errors.c ++ echo timestamp > linked_server_sources ++ ++# Create permission databases ++init-db: all ++ $(top_builddir)/scripts/mysql_install_db ++ ++bin-dist: all ++ $(top_builddir)/scripts/make_binary_distribution @MAKE_BINARY_DISTRIBUTION_OPTIONS@ ++ ++# Remove BK's "SCCS" subdirectories from source distribution ++dist-hook: ++ rm -rf `find $(distdir) -type d -name SCCS` ++ ++tags: ++ support-files/build-tags ++.PHONY: init-db bin-dist ++ ++# Test installation ++ ++test: ++ cd mysql-test ; ./mysql-test-run ++# Tell versions [3.59,3.63) of GNU make to not export all variables. ++# Otherwise a system limit (for SysV at least) may be exceeded. ++.NOEXPORT: diff --git a/debian/patches/02_no_builtin_ndbcluster_plugin.dpatch b/debian/patches/02_no_builtin_ndbcluster_plugin.dpatch new file mode 100644 index 00000000000..dc881ccca10 --- /dev/null +++ b/debian/patches/02_no_builtin_ndbcluster_plugin.dpatch @@ -0,0 +1,18 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 02_no_builtin_ndbcluster_plugin.dpatch by +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: As we completely disabled ndbcluster + +@DPATCH@ + +--- old/sql/sql_builtin.cc ++++ new/sql/sql_builtin.cc +@@ -22,6 +22,6 @@ + + struct st_mysql_plugin *mysqld_builtins[]= + { +- builtin_binlog_plugin, builtin_partition_plugin, builtin_csv_plugin, builtin_heap_plugin, builtin_myisam_plugin, builtin_myisammrg_plugin, builtin_ndbcluster_plugin,(struct st_mysql_plugin *)0 ++ builtin_binlog_plugin, builtin_partition_plugin, builtin_csv_plugin, builtin_heap_plugin, builtin_myisam_plugin, builtin_myisammrg_plugin, (struct st_mysql_plugin *)0 + }; + diff --git a/debian/patches/21_init__openquery_configtest.dpatch b/debian/patches/21_init__openquery_configtest.dpatch new file mode 100644 index 00000000000..c76e98d6ee6 --- /dev/null +++ b/debian/patches/21_init__openquery_configtest.dpatch @@ -0,0 +1,33 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 35_init__openquery_configtest.dpatch by +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: init__openquery_configtest.dpatch + +@DPATCH@ + +--- old/debian/mysql-server-5.0.mysql.init.orig 2008-12-19 12:03:30.379898336 +1100 ++++ new/debian/mysql-server-5.0.mysql.init 2008-12-19 12:04:46.660451093 +1100 +@@ -182,8 +182,21 @@ + fi + ;; + ++ 'configtest') ++ log_daemon_msg "Testing MySQL configuration" "syntax" ++ set +e ++ help_out=`/usr/sbin/mysqld --help 2>&1`; r=$? ++ set -e ++ if [ "$r" -ne 0 ]; then ++ log_failure_msg "$help_out" ++ log_failure_msg "There are syntax errors in the server configuration. Please fix them!" ++ fi ++ log_end_msg $r ++ exit $r ++ ;; ++ + *) +- echo "Usage: $SELF start|stop|restart|reload|force-reload|status" ++ echo "Usage: $SELF start|stop|restart|reload|force-reload|status|configtest" + exit 1 + ;; + esac diff --git a/debian/patches/33_scripts__mysql_create_system_tables__no_test.dpatch b/debian/patches/33_scripts__mysql_create_system_tables__no_test.dpatch new file mode 100755 index 00000000000..4c84e14bf06 --- /dev/null +++ b/debian/patches/33_scripts__mysql_create_system_tables__no_test.dpatch @@ -0,0 +1,30 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 33_scripts__mysql_create_system_tables__no_test.dpatch by +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: scripts__mysql_create_system_tables__no_test +## DP: A user with no password prevents a normal user from login under certain +## DP: circumstances as it is checked first. See #301741. +## DP: http://bugs.mysql.com/bug.php?id=6901 + +@DPATCH@ +--- old/scripts/mysql_system_tables_data.sql 2008-12-04 22:59:44.000000000 +0100 ++++ new/scripts/mysql_system_tables_data.sql 2008-12-04 23:00:07.000000000 +0100 +@@ -26,8 +26,6 @@ + -- Fill "db" table with default grants for anyone to + -- access database 'test' and 'test_%' if "db" table didn't exist + CREATE TEMPORARY TABLE tmp_db LIKE db; +-INSERT INTO tmp_db VALUES ('%','test','','Y','Y','Y','Y','Y','Y','N','Y','Y','Y','Y','Y','Y','Y','Y','N','N','Y','Y'); +-INSERT INTO tmp_db VALUES ('%','test\_%','','Y','Y','Y','Y','Y','Y','N','Y','Y','Y','Y','Y','Y','Y','Y','N','N','Y','Y'); + INSERT INTO db SELECT * FROM tmp_db WHERE @had_db_table=0; + DROP TABLE tmp_db; + +@@ -40,8 +38,6 @@ + REPLACE INTO tmp_user SELECT @current_hostname,'root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'','' FROM dual WHERE LOWER( @current_hostname) != 'localhost'; + REPLACE INTO tmp_user VALUES ('127.0.0.1','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'',''); + REPLACE INTO tmp_user VALUES ('::1','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'',''); +-INSERT INTO tmp_user (host,user) VALUES ('localhost',''); +-INSERT INTO tmp_user (host,user) SELECT @current_hostname,'' FROM dual WHERE LOWER(@current_hostname ) != 'localhost'; + INSERT INTO user SELECT * FROM tmp_user WHERE @had_user_table=0; + DROP TABLE tmp_user; + diff --git a/debian/patches/38_scripts__mysqld_safe.sh__signals.dpatch b/debian/patches/38_scripts__mysqld_safe.sh__signals.dpatch new file mode 100755 index 00000000000..4a51eac8a45 --- /dev/null +++ b/debian/patches/38_scripts__mysqld_safe.sh__signals.dpatch @@ -0,0 +1,43 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 38_scripts__mysqld_safe.sh__signals.dpatch by +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Executes /etc/init.d/mysql on signals +## DP: Reported as http://bugs.mysql.com/bug.php?id=31361 + +@DPATCH@ + +--- old/scripts/mysqld_safe.sh 2006-07-29 13:12:34.000000000 +0200 ++++ old/scripts/mysqld_safe.sh 2006-07-29 13:14:08.000000000 +0200 +@@ -16,8 +16,6 @@ + # This command can be used as pipe to syslog. With "-s" it also logs to stderr. + ERR_LOGGER="logger -p daemon.err -t mysqld_safe -i" + +-trap '' 1 2 3 15 # we shouldn't let anyone kill us +- + umask 007 + + defaults= +@@ -122,7 +122,7 @@ + # sed buffers output (only GNU sed supports a -u (unbuffered) option) + # which means that messages may not get sent to syslog until the + # mysqld process quits. +- cmd="$cmd 2>&1 | logger -t '$syslog_tag_mysqld' -p daemon.error" ++ cmd="$cmd 2>&1 | logger -t '$syslog_tag_mysqld' -p daemon.error & wait" + ;; + *) + echo "Internal program error (non-fatal):" \ +@@ -352,6 +350,13 @@ + fi + + # ++# From now on, we catch signals to do a proper shutdown of mysqld ++# when signalled to do so. ++# ++trap '/usr/bin/mysqladmin --defaults-extra-file=/etc/mysql/debian.cnf refresh & wait' 1 # HUP ++trap '/usr/bin/mysqladmin --defaults-extra-file=/etc/mysql/debian.cnf shutdown' 2 3 15 # INT QUIT and TERM ++ ++# + # Uncomment the following lines if you want all tables to be automatically + # checked and repaired during startup. You should add sensible key_buffer + # and sort_buffer values to my.cnf to improve check performance or require diff --git a/debian/patches/41_scripts__mysql_install_db.sh__no_test.dpatch b/debian/patches/41_scripts__mysql_install_db.sh__no_test.dpatch new file mode 100755 index 00000000000..e79ac71cc7b --- /dev/null +++ b/debian/patches/41_scripts__mysql_install_db.sh__no_test.dpatch @@ -0,0 +1,20 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 41_scripts__mysql_install_db.sh__no_test.dpatch by +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: scripts__mysql_install_db.sh__no_test +## DP: http://bugs.mysql.com/bug.php?id=6901 + +@DPATCH@ + +--- mysql-dfsg-5.1-5.1.23rc.orig/scripts/mysql_install_db.sh 2008-01-29 22:41:20.000000000 +0100 ++++ mysql-dfsg-5.1-5.1.23rc/scripts/mysql_install_db.sh 2008-02-28 10:08:11.000000000 +0100 +@@ -306,7 +306,7 @@ + fi + + # Create database directories +-for dir in $ldata $ldata/mysql $ldata/test ++for dir in $ldata $ldata/mysql + do + if test ! -d $dir + then diff --git a/debian/patches/44_scripts__mysql_config__libs.dpatch b/debian/patches/44_scripts__mysql_config__libs.dpatch new file mode 100755 index 00000000000..1c15200aead --- /dev/null +++ b/debian/patches/44_scripts__mysql_config__libs.dpatch @@ -0,0 +1,24 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 99-unnamed.dpatch by +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Removes unnecessary library dependencies. See #390692 + +@DPATCH@ +diff -Nur mysql-dfsg-5.1-5.1.31.orig/scripts/mysql_config.sh mysql-dfsg-5.1-5.1.31/scripts/mysql_config.sh +--- mysql-dfsg-5.1-5.1.31.orig/scripts/mysql_config.sh 2009-01-19 17:30:55.000000000 +0100 ++++ mysql-dfsg-5.1-5.1.31/scripts/mysql_config.sh 2009-02-08 17:17:48.000000000 +0100 +@@ -110,10 +110,10 @@ + + # Create options + # We intentionally add a space to the beginning and end of lib strings, simplifies replace later +-libs=" $ldflags -L$pkglibdir -lmysqlclient @ZLIB_DEPS@ @NON_THREADED_LIBS@" ++libs=" $ldflags -L$pkglibdir -lmysqlclient" + libs="$libs @openssl_libs@ @STATIC_NSS_FLAGS@ " +-libs_r=" $ldflags -L$pkglibdir -lmysqlclient_r @ZLIB_DEPS@ @CLIENT_LIBS@ @openssl_libs@ " +-embedded_libs=" $ldflags -L$pkglibdir -lmysqld @LIBDL@ @ZLIB_DEPS@ @LIBS@ @WRAPLIBS@ @openssl_libs@ " ++libs_r=" $ldflags -L$pkglibdir -lmysqlclient_r @CLIENT_LIBS@ @openssl_libs@ " ++embedded_libs=" $ldflags -L$pkglibdir -lmysqld @LIBDL@ @WRAPLIBS@ @openssl_libs@ " + + if [ -r "$pkglibdir/libmygcc.a" ]; then + # When linking against the static library with a different version of GCC diff --git a/debian/patches/50_mysql-test__db_test.dpatch b/debian/patches/50_mysql-test__db_test.dpatch new file mode 100755 index 00000000000..6a5cab91c39 --- /dev/null +++ b/debian/patches/50_mysql-test__db_test.dpatch @@ -0,0 +1,23 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 50_mysql-test__db_test.dpatch by Christian Hammers +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Patch 33_scripts__mysql_create_system_tables__no_test removes the +## DP: rights for anybody to connect to the test database but the test +## DP: suite depends on them. + +@DPATCH@ + +--- old/mysql-test/mysql-test-run.pl 2009-06-16 14:24:09.000000000 +0200 ++++ new/mysql-test/mysql-test-run.pl 2009-07-04 00:03:34.000000000 +0200 +@@ -2717,6 +2717,10 @@ + mtr_appendfile_to_file("$sql_dir/mysql_system_tables_data.sql", + $bootstrap_sql_file); + ++ mtr_tofile($bootstrap_sql_file, "-- Debian removed the default privileges on the 'test' database\n"); ++ mtr_tofile($bootstrap_sql_file, "INSERT INTO mysql.db VALUES ('%','test','','Y','Y','Y','Y','Y','Y','N','Y','Y','Y','Y','Y','Y','Y','Y','N','N','Y','Y');\n"); ++ ++ + # Add test data for timezone - this is just a subset, on a real + # system these tables will be populated either by mysql_tzinfo_to_sql + # or by downloading the timezone table package from our website diff --git a/debian/patches/60_zlib_innodb_workaround.dpatch b/debian/patches/60_zlib_innodb_workaround.dpatch new file mode 100644 index 00000000000..e8a496a5866 --- /dev/null +++ b/debian/patches/60_zlib_innodb_workaround.dpatch @@ -0,0 +1,31 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 60_zlib_innodb_workaround.dpatch by Norbert Tretkowski +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: http://bugs.mysql.com/bug.php?id=47495 + +@DPATCH@ +diff -Nur mysql-dfsg-5.1-5.1.39.orig/mysql-test/suite/innodb/r/innodb-zip.result mysql-dfsg-5.1-5.1.39/mysql-test/suite/innodb/r/innodb-zip.result +--- mysql-dfsg-5.1-5.1.39.orig/mysql-test/suite/innodb/r/innodb-zip.result 2009-09-04 19:04:38.000000000 +0200 ++++ mysql-dfsg-5.1-5.1.39/mysql-test/suite/innodb/r/innodb-zip.result 2009-09-28 16:01:33.000000000 +0200 +@@ -141,7 +141,7 @@ + CREATE TABLE t1(c TEXT, PRIMARY KEY (c(440))) + ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII; + ERROR 42000: Row size too large. The maximum row size for the used table type, not counting BLOBs, is 8126. You have to change some columns to TEXT or BLOBs +-CREATE TABLE t1(c TEXT, PRIMARY KEY (c(439))) ++CREATE TABLE t1(c TEXT, PRIMARY KEY (c(438))) + ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII; + INSERT INTO t1 VALUES(REPEAT('A',512)),(REPEAT('B',512)); + DROP TABLE t1; +diff -Nur mysql-dfsg-5.1-5.1.39.orig/mysql-test/suite/innodb/t/innodb-zip.test mysql-dfsg-5.1-5.1.39/mysql-test/suite/innodb/t/innodb-zip.test +--- mysql-dfsg-5.1-5.1.39.orig/mysql-test/suite/innodb/t/innodb-zip.test 2009-09-04 19:04:37.000000000 +0200 ++++ mysql-dfsg-5.1-5.1.39/mysql-test/suite/innodb/t/innodb-zip.test 2009-09-28 16:01:22.000000000 +0200 +@@ -106,7 +106,7 @@ + --error ER_TOO_BIG_ROWSIZE + CREATE TABLE t1(c TEXT, PRIMARY KEY (c(440))) + ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII; +-CREATE TABLE t1(c TEXT, PRIMARY KEY (c(439))) ++CREATE TABLE t1(c TEXT, PRIMARY KEY (c(438))) + ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII; + INSERT INTO t1 VALUES(REPEAT('A',512)),(REPEAT('B',512)); + DROP TABLE t1; diff --git a/debian/patches/61_replace_dash_with_bash_mbug675185.dpatch b/debian/patches/61_replace_dash_with_bash_mbug675185.dpatch new file mode 100755 index 00000000000..2a4ee8cd648 --- /dev/null +++ b/debian/patches/61_replace_dash_with_bash_mbug675185.dpatch @@ -0,0 +1,20 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 61_replace_dash_with_bash_mbug675185.dpatch by +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: 61_replace_dash_with_bash_mbug675185 +## DP: A race in dash causes mysqld_safe to occasionally loop infinitely. +## DP: Fix by using bash instead. +## DP: https://bugs.launchpad.net/ubuntu/+source/mysql-dfsg-5.0/+bug/675185 + +@DPATCH@ +=== modified file 'scripts/mysqld_safe.sh' +--- old/scripts/mysqld_safe.sh 2010-04-09 11:47:18 +0000 ++++ new/scripts/mysqld_safe.sh 2010-11-21 09:40:50 +0000 +@@ -1,4 +1,4 @@ +-#!/bin/sh ++#!/bin/bash + # Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB + # This file is public domain and comes with NO WARRANTY of any kind + # + diff --git a/debian/po/POTFILES.in b/debian/po/POTFILES.in new file mode 100644 index 00000000000..8ca17f69cc1 --- /dev/null +++ b/debian/po/POTFILES.in @@ -0,0 +1 @@ +[type: gettext/rfc822deb] mariadb-server-5.5.templates diff --git a/debian/po/ar.po b/debian/po/ar.po new file mode 100644 index 00000000000..4ac2e393790 --- /dev/null +++ b/debian/po/ar.po @@ -0,0 +1,252 @@ +# translation of templates.po to Arabic +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Ossama M. Khayat , 2007. +msgid "" +msgstr "" +"Project-Id-Version: templates\n" +"Report-Msgid-Bugs-To: mariadb-5.5@packages.debian.org\n" +"POT-Creation-Date: 2012-01-12 13:08+0100\n" +"PO-Revision-Date: 2007-05-01 13:04+0300\n" +"Last-Translator: Ossama M. Khayat \n" +"Language-Team: Arabic \n" +"Language: ar\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: KBabel 1.11.4\n" +"Plural-Forms: nplurals=6; plural=n==1 ? 0 : n==0 ? 1 : n==2 ? 2: n%100>=3 && " +"n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5\n" +": n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5\n" +": n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5\n" +": n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5\n" +": n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5\n" +": n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5\n" +": n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5\n" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "Really proceed with downgrade?" +msgstr "هل فعلاً تريد التثبيط؟" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "A file named /var/lib/mysql/debian-*.flag exists on this system." +msgstr "هناك ملف مسمى /var/lib/mysql/debian-*.flag موجود على هذا النظام." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +#, fuzzy +#| msgid "" +#| "Such file is an indication that a mariadb-server package with a higher " +#| "version has been installed earlier." +msgid "" +"Such a file is an indication that a mariadb-server package with a higher " +"version has been installed previously." +msgstr "" +"هذا الملف دلالة على أن نسخة أحدث من حزمة mariadb-server تم تثبيتها مسبقاً." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "" +"There is no guarantee that the version you're currently installing will be " +"able to use the current databases." +msgstr "" +"ليست هناك أية ضمانة أن النسخة التي تقوم بتثبيتها ستكون قادرة على استخدام " +"قواعد البيانات الحالية." + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "Important note for NIS/YP users" +msgstr "ملاحظة هامة لمستخدمي NIS/YP" + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "" +"Using MariaDB under NIS/YP requires a mysql user account to be added on the " +"local system with:" +msgstr "" + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +#, fuzzy +#| msgid "" +#| "You should also check the permissions and the owner of the /var/lib/mysql " +#| "directory:" +msgid "" +"You should also check the permissions and ownership of the /var/lib/mysql " +"directory:" +msgstr "عليك أيضاً أن تقوم بالتأكد من صلاحيات مالك الملف /var/lib/mysql: " + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "Remove all MariaDB databases?" +msgstr "إزالة جميع قواعد بيانات MariaDB؟" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "" +"The /var/lib/mysql directory which contains the MariaDB databases is about " +"to be removed." +msgstr "الدليل /var/lib/mysql الذي يحتوي قواعد بيانات MariaDB ستتم إزالته." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "" +"If you're removing the MariaDB package in order to later install a more " +"recent version or if a different mariadb-server package is already using it, " +"the data should be kept." +msgstr "" +"إن كنت تقوم بإزالة حزمة MariaDB كي تقوم لاحقاً بتثبيت نسخة أحدث أو إن كانت " +"حزمة mariadb-server مختلفة تستخدمها، فيجب إبقاء البيانات." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:5001 +msgid "Start the MariaDB server on boot?" +msgstr "تشغيل خادم MariaDB عند الإقلاع؟" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:5001 +msgid "" +"The MariaDB server can be launched automatically at boot time or manually " +"with the '/etc/init.d/mysql start' command." +msgstr "" +"يمكن تشغيل خادم MariaDB آلياً وقت الإقلاع أو يدوياً باستخدام الأمر '/etc/init." +"d/mysql start'." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +msgid "New password for the MariaDB \"root\" user:" +msgstr "كلمة المرور الجديدة لمستخد \"root\" الخاص بـMariaDB:" + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +msgid "" +"While not mandatory, it is highly recommended that you set a password for " +"the MariaDB administrative \"root\" user." +msgstr "" +"مع أنه ليس إجبارياً، ولكن من المستحسن أن تقوم بتعيين كلمة مرور خاصة بمستخدم " +"MariaDB الإداري \"root\"." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +#, fuzzy +#| msgid "If that field is left blank, the password will not be changed." +msgid "If this field is left blank, the password will not be changed." +msgstr "إن ترك الحقل فارغاً، فلن يتم تغيير كلمة المرور." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:7001 +#, fuzzy +#| msgid "New password for the MariaDB \"root\" user:" +msgid "Repeat password for the MariaDB \"root\" user:" +msgstr "كلمة المرور الجديدة لمستخد \"root\" الخاص بـMariaDB:" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "Unable to set password for the MariaDB \"root\" user" +msgstr "تعذر تعيين كلمة مرور للمستخدم \"root\" الخاص بـMariaDB." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "" +"An error occurred while setting the password for the MariaDB administrative " +"user. This may have happened because the account already has a password, or " +"because of a communication problem with the MariaDB server." +msgstr "" +"حدث خطأ أثناء تعيين كلمة المرور لمستخدم MariaDB الإداري. قد يكون هذا حدث " +"بسبب أن حساب المستخدم له كلمة مرور معيّنة مسبقاً، أو بسبب مشكلة في الاتصال مع " +"خادم MariaDB." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +#, fuzzy +#| msgid "" +#| "You should check the account's password after tha package installation." +msgid "You should check the account's password after the package installation." +msgstr "يجب عليك التحقق من كلمة مرور الحساب عقب تثبيت الحزمة." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +#, fuzzy +#| msgid "" +#| "Please read the /usr/share/doc/mysql-server-5.1/README.Debian file for " +#| "more information." +msgid "" +"Please read the /usr/share/doc/mariadb-server-5.3/README.Debian file for " +"more information." +msgstr "" +"الرجاء قراءة الملف /usr/share/doc/mariadb-server-5.5/README.Debian للمزيد من " +"المعلومات." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:9001 +msgid "Password input error" +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:9001 +msgid "The two passwords you entered were not the same. Please try again." +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:10001 +msgid "NDB Cluster seems to be in use" +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:10001 +msgid "" +"MySQL-5.1 no longer provides NDB Cluster support. Please migrate to the new " +"mysql-cluster package and remove all lines starting with \"ndb\" from all " +"config files below /etc/mysql/." +msgstr "" + +#~ msgid "" +#~ "To use MariaDB, the following entries for users and groups should be " +#~ "added to the system:" +#~ msgstr "" +#~ "كي تستخدم MariaDB، يجب إضافة المُدخلات التالية الخاصة بالمستخدمين " +#~ "والمجموعات إلى النظام:" + +#~ msgid "" +#~ "Support MySQL connections from hosts running Debian \"sarge\" or older?" +#~ msgstr "" +#~ "هل تريد دعم اتصالات MySQL من الأجهزة التي تعمل على ديبيان \"sarge\" أو " +#~ "أقدم؟" + +#~ msgid "" +#~ "In old versions of MySQL clients on Debian, passwords were not stored " +#~ "securely. This has been improved since then, however clients (such as " +#~ "PHP) from hosts running Debian 3.1 Sarge will not be able to connect to " +#~ "recent accounts or accounts whose password have been changed." +#~ msgstr "" +#~ "في إصدارات عملاء MySQL القديمة من ديبيان، لم تكن كلمات المرور تحفظ بشكل " +#~ "آمن. ولقد حل هذه المشكلة بعدها، غير أن العملاء (مثل PHP) المتصلين من " +#~ "أجهزة تعمل على ديبيان Sarge 3.1 لن يكونوا قادرين على الاتصال باستخدام " +#~ "الحسابات الحديثة أو الحسابات التي تم تغيير كلمة مرورها." diff --git a/debian/po/ca.po b/debian/po/ca.po new file mode 100644 index 00000000000..2deeb98a08f --- /dev/null +++ b/debian/po/ca.po @@ -0,0 +1,342 @@ +# mysql-dfsg (debconf) translation to Catalan. +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. +# Aleix Badia i Bosch 2004 +# +msgid "" +msgstr "" +"Project-Id-Version: mysql-dfsg-4.1\n" +"Report-Msgid-Bugs-To: mariadb-5.5@packages.debian.org\n" +"POT-Creation-Date: 2012-01-12 13:08+0100\n" +"PO-Revision-Date: 2004-01-31 19:20GMT\n" +"Last-Translator: Aleix Badia i Bosch \n" +"Language-Team: Debian L10n Catalan \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=ISO-8859-1\n" +"Content-Transfer-Encoding: 8bit\n" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "Really proceed with downgrade?" +msgstr "" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "A file named /var/lib/mysql/debian-*.flag exists on this system." +msgstr "" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "" +"Such a file is an indication that a mariadb-server package with a higher " +"version has been installed previously." +msgstr "" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "" +"There is no guarantee that the version you're currently installing will be " +"able to use the current databases." +msgstr "" + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +#, fuzzy +#| msgid "Important note for NIS/YP users!" +msgid "Important note for NIS/YP users" +msgstr "Nota important pels usuaris de NIS/YP" + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "" +"Using MariaDB under NIS/YP requires a mysql user account to be added on the " +"local system with:" +msgstr "" + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "" +"You should also check the permissions and ownership of the /var/lib/mysql " +"directory:" +msgstr "" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "Remove all MariaDB databases?" +msgstr "" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "" +"The /var/lib/mysql directory which contains the MariaDB databases is about " +"to be removed." +msgstr "" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "" +"If you're removing the MariaDB package in order to later install a more " +"recent version or if a different mariadb-server package is already using it, " +"the data should be kept." +msgstr "" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:5001 +#, fuzzy +#| msgid "Should MySQL start on boot?" +msgid "Start the MariaDB server on boot?" +msgstr "Voleu que el MariaDB s'inici a l'arrencada ?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:5001 +#, fuzzy +msgid "" +"The MariaDB server can be launched automatically at boot time or manually " +"with the '/etc/init.d/mysql start' command." +msgstr "" +"El MariaDB es pot executar a l'arrencada o noms si executeu manualment '/" +"etc/init.d/mysql start'. Seleccioneu 's' si voleu que s'inicialitzi " +"automticament." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +msgid "New password for the MariaDB \"root\" user:" +msgstr "" + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +msgid "" +"While not mandatory, it is highly recommended that you set a password for " +"the MariaDB administrative \"root\" user." +msgstr "" + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +msgid "If this field is left blank, the password will not be changed." +msgstr "" + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:7001 +msgid "Repeat password for the MariaDB \"root\" user:" +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "Unable to set password for the MariaDB \"root\" user" +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "" +"An error occurred while setting the password for the MariaDB administrative " +"user. This may have happened because the account already has a password, or " +"because of a communication problem with the MariaDB server." +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "You should check the account's password after the package installation." +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "" +"Please read the /usr/share/doc/mariadb-server-5.3/README.Debian file for " +"more information." +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:9001 +msgid "Password input error" +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:9001 +msgid "The two passwords you entered were not the same. Please try again." +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:10001 +msgid "NDB Cluster seems to be in use" +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:10001 +msgid "" +"MySQL-5.1 no longer provides NDB Cluster support. Please migrate to the new " +"mysql-cluster package and remove all lines starting with \"ndb\" from all " +"config files below /etc/mysql/." +msgstr "" + +#, fuzzy +#~ msgid "" +#~ "To use mysql you must install an equivalent user and group to the " +#~ "following and ensure yourself that /var/lib/mysql has the right " +#~ "permissions (the uid/gid may be different)." +#~ msgstr "" +#~ "Per utilitzar la base de dades de MySQL heu d'afegir un usuari i grup " +#~ "equivalent al segent i assegurar-vos que el directori /var/lib/mysql " +#~ "tingui els permisos correctes." + +#~ msgid "" +#~ "/etc/passwd: mysql:x:100:101:MySQL Server:/var/lib/mysql:/bin/false" +#~ msgstr "" +#~ "/etc/passwd: mysql:x:100:101:MySQL Server:/var/lib/mysql:/bin/false" + +#~ msgid "/etc/group: mysql:x:101:" +#~ msgstr "/etc/group: mysql:x:101:" + +#~ msgid "/var/lib/mysql: drwxr-xr-x mysql mysql" +#~ msgstr "/var/lib/mysql: drwxr-xr-x mysql mysql" + +#, fuzzy +#~ msgid "Please also read http://www.mysql.com/doc/en/Upgrade.html" +#~ msgstr "" +#~ "Feu una ullada al document: http://www.mysql.com/doc/en/Upgrade.html" + +#, fuzzy +#~ msgid "" +#~ "MySQL will only install if you have a non-numeric hostname that is " +#~ "resolvable via the /etc/hosts file. E.g. if the \"hostname\" command " +#~ "returns \"myhostname\" then there must be a line like \"10.0.0.1 " +#~ "myhostname\"." +#~ msgstr "" +#~ "El MySQL noms s'installa en cas de tenir un nom d'ordinador central que " +#~ "no sigui numric i que es pugui resoldre a travs del fitxer /etc/hosts. " +#~ "Ex. si l'ordre \"hostname\" retorna \"myhostname\", llavors hi ha d'haver " +#~ "una lnia com la segent \"10.0.0.1 myhostname\"." + +#, fuzzy +#~ msgid "" +#~ "A new mysql user \"debian-sys-maint\" will be created. This mysql account " +#~ "is used in the start/stop and cron scripts. Don't delete." +#~ msgstr "" +#~ "Es crea un nou usuari de mysql \"debian-sys-maint\". S'utilitza per les " +#~ "seqncies d'inicialitzaci i aturada del cron, no el suprimiu." + +#, fuzzy +#~ msgid "" +#~ "Please remember to set a PASSWORD for the MySQL root user! If you use a /" +#~ "root/.my.cnf, always write the \"user\" and the \"password\" lines in " +#~ "there, never only the password!" +#~ msgstr "" +#~ "Recordeu posar una contrasenya al superusuari del MySQL. Si utilitzeu un " +#~ "fitxer /root/.my.cnf, escriviu sempre all les lnies \"user\" i " +#~ "\"password\".; mai noms la contrasenya. Per a ms informaci feu una " +#~ "ullada a /usr/share/doc/mysql-server/README.Debian." + +#, fuzzy +#~ msgid "" +#~ "Should I remove all databases below /var/lib/mysql as you are purging the " +#~ "mysql-server package?" +#~ msgstr "" +#~ "Voleu suprimir totes les bases de dades en purgar el paquet mysql-server ?" + +#~ msgid "" +#~ "Networking is disabled by default for security reasons. You can enable it " +#~ "by commenting out the skip-networking option in /etc/mysql/my.cnf." +#~ msgstr "" +#~ "La xarxa est inhabilitada per defecte per a raons de seguretat. La podeu " +#~ "habilitar descomentant l'opci de skip-networking del fitxer /etc/mysql/" +#~ "my.cnf." + +#~ msgid "security and update notice" +#~ msgstr "Avs de seguretat i actualitzaci" + +#~ msgid "Please run mysql_fix_privilege_tables !" +#~ msgstr "Executeu mysql_fix_privilege_tables" + +#~ msgid "" +#~ "I will ensure secure permissions of /var/lib/mysql by replacing GIDs " +#~ "other than root and mysql with mysql." +#~ msgstr "" +#~ "S'asseguren els permisos de seguretat de /var/lib/mysql canviant a mysql " +#~ "tots els GIDs diferents a root i mysql." + +#~ msgid "" +#~ "Instructions how to enable SSL support are in /usr/share/doc/mysql-server/" +#~ msgstr "" +#~ "Per habilitar el suport de SSL podeu seguir les instruccions de /usr/" +#~ "share/doc/mysql-server/" + +#~ msgid "mysql_fix_privileges_tables will be executed" +#~ msgstr "s'executa mysql_fix_privileges_tables" + +#~ msgid "" +#~ "The latest MySQL versions have an enhanced, more fine grained, privilege " +#~ "system. To make use of it, some new fields must be added to the tables " +#~ "in the \"mysql\" database. This is done by the " +#~ "mysql_fix_privilege_tables script during this upgrade regardless of if " +#~ "the server is currently running or not!" +#~ msgstr "" +#~ "Les ltimes versions de MySQL tenen un sistema de privilegis ms " +#~ "elaborat. Per utilitzar-lo cal afegir nous camps a les taules de la base " +#~ "de dades \"mysql\". Aquesta tasca la realitza la seqncia " +#~ "mysql_fix_privilege_tables durant l'actualitzaci independentment de si " +#~ "el servidor s'est executant o no!" + +#~ msgid "" +#~ "This script is not supposed to give any user more rights that he had " +#~ "before, if you encounter such a case, please contact me." +#~ msgstr "" +#~ "Aquesta seqncia no assigna privilegis d'usuari diferents als que ja " +#~ "tenia, en cas que us trobssiu en aquesta situaci, poseu-vos en contacte " +#~ "amb mi." + +#~ msgid "" +#~ "Should I remove everything below /var/lib/mysql when you purge the mysql-" +#~ "server package with the \"dpkg --purge mysql-server\" command (i.e. " +#~ "remove everything including the configuration) somewhen? (default is not)" +#~ msgstr "" +#~ "Voleu suprimir tots els continguts de /var/lib/mysql quan es purgui el " +#~ "paquet mysql-server amb l'ordre \"dpkg --purge mysql-server\". (ex. " +#~ "suprimir-ho tot incls la configuraci) ? (per defecte no)" + +#~ msgid "Make MySQL reachable via network?" +#~ msgstr "Voleu fer accessible el MySQL via xarxa ?" + +#~ msgid "" +#~ "Should MySQL listen on a network reachable TCP port? This is not " +#~ "necessary for use on a single computer and could be a security problem." +#~ msgstr "" +#~ "Voleu que el MySQL escolti a un port TCP accessible des de la xarxa ? " +#~ "Aquesta opci no s imprescindible en ordinadors allats i podria " +#~ "provocar un problema de seguretat." + +#~ msgid "Enable chroot mode?" +#~ msgstr "Permetre el mode chroot ?" + +#~ msgid "" +#~ "MySQL is able to jail itself into the /var/lib/mysql_jail directory so " +#~ "that users cannot modify any files outside this directory. This improves " +#~ "resistence against crackers, too, as they are not able to modify system " +#~ "files." +#~ msgstr "" +#~ "El MySQL es pot executar en una entorn tancat al directori /var/lib/" +#~ "mysql_jail perqu els usuaris no puguin modificar cap fitxer fora del " +#~ "directori.Aquesta opci tamb augmenta la seguretat envers els crackers, " +#~ "jaque no poden modificar els fitxers del sistema." diff --git a/debian/po/cs.po b/debian/po/cs.po new file mode 100644 index 00000000000..6016b8fcf5a --- /dev/null +++ b/debian/po/cs.po @@ -0,0 +1,348 @@ +# +# Translators, if you are not familiar with the PO format, gettext +# documentation is worth reading, especially sections dedicated to +# this format, e.g. by running: +# info -n '(gettext)PO Files' +# info -n '(gettext)Header Entry' +# +# Some information specific to po-debconf are available at +# /usr/share/doc/po-debconf/README-trans +# or http://www.debian.org/intl/l10n/po-debconf/README-trans +# +# Developers do not need to manually edit POT or PO files. +# +msgid "" +msgstr "" +"Project-Id-Version: mysql-dfsg-5.1\n" +"Report-Msgid-Bugs-To: mariadb-5.5@packages.debian.org\n" +"POT-Creation-Date: 2012-01-12 13:08+0100\n" +"PO-Revision-Date: 2007-05-01 13:01+0200\n" +"Last-Translator: Miroslav Kure \n" +"Language-Team: Czech \n" +"Language: cs\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "Really proceed with downgrade?" +msgstr "Opravdu pokračovat v degradaci?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "A file named /var/lib/mysql/debian-*.flag exists on this system." +msgstr "V systému existuje soubor /var/lib/mysql/debian-*.flag." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +#, fuzzy +#| msgid "" +#| "Such file is an indication that a mariadb-server package with a higher " +#| "version has been installed earlier." +msgid "" +"Such a file is an indication that a mariadb-server package with a higher " +"version has been installed previously." +msgstr "" +"To znamená, že již byl nainstalován balík mariadb-server s vyšší verzí." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "" +"There is no guarantee that the version you're currently installing will be " +"able to use the current databases." +msgstr "" +"Neexistuje žádná záruka, že momentálně instalovaná verze bude umět pracovat " +"se stávajícími databázemi." + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "Important note for NIS/YP users" +msgstr "Důležitá poznámka pro uživatele NIS/YP" + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "" +"Using MariaDB under NIS/YP requires a mysql user account to be added on the " +"local system with:" +msgstr "" + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +#, fuzzy +#| msgid "" +#| "You should also check the permissions and the owner of the /var/lib/mysql " +#| "directory:" +msgid "" +"You should also check the permissions and ownership of the /var/lib/mysql " +"directory:" +msgstr "" +"Také byste měli zkontrolovat vlastníka a oprávnění adresáře /var/lib/mysql:" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "Remove all MariaDB databases?" +msgstr "Odstranit všechny MariaDB databáze?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "" +"The /var/lib/mysql directory which contains the MariaDB databases is about " +"to be removed." +msgstr "" +"Adresář /var/lib/mysql, ve kterém se nachází MariaDB databáze, bude " +"odstraněn." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "" +"If you're removing the MariaDB package in order to later install a more " +"recent version or if a different mariadb-server package is already using it, " +"the data should be kept." +msgstr "" +"Jestliže odstraňujete balík MariaDB za účelem instalace novější verze " +"MariaDB, nebo pokud tato data souběžně využívá jiný balík mariadb-server, " +"měli byste data ponechat." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:5001 +msgid "Start the MariaDB server on boot?" +msgstr "Spustit MariaDB server při startu systému?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:5001 +msgid "" +"The MariaDB server can be launched automatically at boot time or manually " +"with the '/etc/init.d/mysql start' command." +msgstr "" +"MariaDB se může spouštět automaticky při startu systému, nebo ručně příkazem " +"'/etc/init.d/mysql start'." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +msgid "New password for the MariaDB \"root\" user:" +msgstr "Nové heslo MariaDB uživatele \"root\":" + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +msgid "" +"While not mandatory, it is highly recommended that you set a password for " +"the MariaDB administrative \"root\" user." +msgstr "" +"Přestože to není nezbytné, je silně doporučeno nastavit heslo u " +"správcovského MariaDB účtu \"root\"." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +#, fuzzy +#| msgid "If that field is left blank, the password will not be changed." +msgid "If this field is left blank, the password will not be changed." +msgstr "Ponecháte-li pole prázdné, heslo se nezmění." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:7001 +#, fuzzy +#| msgid "New password for the MySQL \"root\" user:" +msgid "Repeat password for the MariaDB \"root\" user:" +msgstr "Nové heslo MariaDB uživatele \"root\":" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "Unable to set password for the MariaDB \"root\" user" +msgstr "Nelze nastavit heslo MariaDB uživatele \"root\"" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "" +"An error occurred while setting the password for the MariaDB administrative " +"user. This may have happened because the account already has a password, or " +"because of a communication problem with the MariaDB server." +msgstr "" +"Během nastavování hesla pro správcovského uživatele MariaDB se vyskytla " +"chyba. To se mohlo stát třeba proto, protože uživatel již měl heslo " +"nastaveno, nebo protože nastal problém v komunikaci s MariaDB serverem." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +#, fuzzy +#| msgid "" +#| "You should check the account's password after tha package installation." +msgid "You should check the account's password after the package installation." +msgstr "Po instalaci balíku byste měli heslo ověřit." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +#, fuzzy +#| msgid "" +#| "Please read the /usr/share/doc/mysql-server-5.1/README.Debian file for " +#| "more information." +msgid "" +"Please read the /usr/share/doc/mariadb-server-5.3/README.Debian file for " +"more information." +msgstr "" +"Více informací naleznete v /usr/share/doc/mariadb-server-5.5/README.Debian." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:9001 +msgid "Password input error" +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:9001 +msgid "The two passwords you entered were not the same. Please try again." +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:10001 +msgid "NDB Cluster seems to be in use" +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:10001 +msgid "" +"MySQL-5.1 no longer provides NDB Cluster support. Please migrate to the new " +"mysql-cluster package and remove all lines starting with \"ndb\" from all " +"config files below /etc/mysql/." +msgstr "" + +#~ msgid "" +#~ "To use MariaDB, the following entries for users and groups should be " +#~ "added to the system:" +#~ msgstr "" +#~ "Abyste mohli MariaDB používat, musíte v systému založit následující " +#~ "uživatele a skupiny:" + +#~ msgid "Cannot upgrade if ISAM tables are present!" +#~ msgstr "Aktualizace nelze provést pokud jsou přítomny tabulky ISAM!" + +#~ msgid "" +#~ "Recent versions of MySQL can no longer use the old ISAM table format and " +#~ "it is necessary to convert your tables to e.g. MyISAM before upgrading by " +#~ "using \"mysql_convert_table_format\" or \"ALTER TABLE x ENGINE=MyISAM\". " +#~ "The installation of mysql-server-5.1 will now abort. In case your old " +#~ "mysql-server-4.1 gets removed nevertheless just reinstall it to convert " +#~ "those tables." +#~ msgstr "" +#~ "Poslední verze MySQL již nemohou používat starý formát tabulek ISAM a " +#~ "před aktualizací je nutné převést tyto tabulky např. do formátu MyISAM " +#~ "pomocí \"mysql_convert_table_format\" nebo \"ALTER TABLE x ENGINE=MyISAM" +#~ "\". Instalace mysql-server-5.1 se nyní přeruší. V případě, že se mezitím " +#~ "odinstaloval původní mysql-server-4.1, jednoduše jej znovu nainstalujte a " +#~ "tabulky převeďte." + +#~ msgid "" +#~ "Support MySQL connections from hosts running Debian \"sarge\" or older?" +#~ msgstr "" +#~ "Podporovat MySQL připojení z počítačů používajících Debian Sarge nebo " +#~ "starší?" + +#~ msgid "" +#~ "In old versions of MySQL clients on Debian, passwords were not stored " +#~ "securely. This has been improved since then, however clients (such as " +#~ "PHP) from hosts running Debian 3.1 Sarge will not be able to connect to " +#~ "recent accounts or accounts whose password have been changed." +#~ msgstr "" +#~ "Způsob, jakým se dříve ukládala hesla, nebyl příliš bezpečný. To se nyní " +#~ "zlepšilo, ale nevýhodou je, že se klienti z Debianu 3.1 Sarge (např. PHP) " +#~ "nebudou moci připojit na nové účty, nebo na účty, u nichž se heslo " +#~ "změnilo." + +#~ msgid "" +#~ "To use mysql you must install an equivalent user and group to the " +#~ "following and ensure yourself that /var/lib/mysql has the right " +#~ "permissions (the uid/gid may be different)." +#~ msgstr "" +#~ "Abyste mohli mysql používat, musíte do následujících souborů přidat " +#~ "ekvivalentního uživatele a skupinu a zajistit, že /var/lib/mysql má " +#~ "správná práva (uid/gid se mohou lišit)." + +#~ msgid "Remove the databases used by all MySQL versions?" +#~ msgstr "Odstranit databáze používané všemi verzemi MySQL?" + +#~ msgid "" +#~ "If you do not provide a password no changes will be made to the account." +#~ msgstr "Nezadáte-li heslo, žádné změny se s účtem neprovedou." + +#~ msgid "" +#~ "When installation finishes, you should verify that the account is " +#~ "properly protected with a password (see README.Debian for more " +#~ "information)." +#~ msgstr "" +#~ "Po skončení instalace byste měli ověřit, že je účet chráněn heslem (více " +#~ "informací naleznete v souboru README.Debian)." + +#~ msgid "Update Hints" +#~ msgstr "Poznámky k aktualizaci" + +#~ msgid "" +#~ "You have to run \"mysql_upgrade\" after the upgrade, else tables can be " +#~ "corrupted! This script also enhances the privilege tables but is not " +#~ "supposed to give any user more rights that he had before," +#~ msgstr "" +#~ "Po aktualizaci ještě musíte spustit \"mysql_upgrade\", protože jinak by " +#~ "se tabulky mohly narušit! Tento skript také rozšiřuje tabulky privilegií, " +#~ "ovšem neměl by uživatelům přidat více práv, než měli dosud." + +#~ msgid "Please also read http://www.mysql.com/doc/en/Upgrade.html" +#~ msgstr "Také si přečtěte http://www.mysql.com/doc/en/Upgrade.html" + +#~ msgid "" +#~ "MySQL will only install if you have a non-numeric hostname that is " +#~ "resolvable via the /etc/hosts file. E.g. if the \"hostname\" command " +#~ "returns \"myhostname\" then there must be a line like \"10.0.0.1 " +#~ "myhostname\"." +#~ msgstr "" +#~ "MySQL se nainstaluje pouze v případě, že používáte nenumerické jméno " +#~ "počítače, které se dá přeložit přes soubor /etc/hosts. Např. když příkaz " +#~ "\"hostname\" vrátí \"diamond\", tak v /etc/hosts musí existovat obdobný " +#~ "řádek jako \"10.0.0.1 diamond\"." + +#~ msgid "" +#~ "A new mysql user \"debian-sys-maint\" will be created. This mysql account " +#~ "is used in the start/stop and cron scripts. Don't delete." +#~ msgstr "" +#~ "Bude vytvořen nový mysql uživatel \"debian-sys-maint\". Tento mysql účet " +#~ "se používá ve startovacích, ukončovacích a cronových skriptech. Nemažte " +#~ "jej." + +#~ msgid "" +#~ "Please remember to set a PASSWORD for the MySQL root user! If you use a /" +#~ "root/.my.cnf, always write the \"user\" and the \"password\" lines in " +#~ "there, never only the password!" +#~ msgstr "" +#~ "Nezapomeňte nastavit heslo pro účet administrátora MySQL! Používáte-li /" +#~ "root/.my.cnf, vždy zde zadejte jak řádek \"user\", tak řádek \"password" +#~ "\". Nikdy zde nezadávejte jenom heslo!" + +#~ msgid "" +#~ "Should I remove the complete /var/lib/mysql directory tree which is used " +#~ "by all MySQL versions, not necessarily only the one you are about to " +#~ "purge?" +#~ msgstr "" +#~ "Mám odstranit kompletní adresářový strom /var/lib/mysql, který se používá " +#~ "pro všechny verze MySQL, tedy ne nutně pouze pro verzi, kterou se " +#~ "chystáte vyčistit?" diff --git a/debian/po/da.po b/debian/po/da.po new file mode 100644 index 00000000000..fa4b512a859 --- /dev/null +++ b/debian/po/da.po @@ -0,0 +1,382 @@ +# +# Translators, if you are not familiar with the PO format, gettext +# documentation is worth reading, especially sections dedicated to +# this format, e.g. by running: +# info -n '(gettext)PO Files' +# info -n '(gettext)Header Entry' +# Some information specific to po-debconf are available at +# /usr/share/doc/po-debconf/README-trans +# or http://www.debian.org/intl/l10n/po-debconf/README-trans# +# Developers do not need to manually edit POT or PO files. +# +# Claus Hindsgaul , 2005, 2006. +# Claus Hindsgaul , 2006, 2007. +msgid "" +msgstr "" +"Project-Id-Version: mysql-dfsg-4.1\n" +"Report-Msgid-Bugs-To: mariadb-5.5@packages.debian.org\n" +"POT-Creation-Date: 2012-01-12 13:08+0100\n" +"PO-Revision-Date: 2007-05-30 22:41+0200\n" +"Last-Translator: Claus Hindsgaul \n" +"Language-Team: Danish\n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=ISO-8859-1\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: KBabel 1.11.4\n" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "Really proceed with downgrade?" +msgstr "nsker du virkelig at fortstte nedgraderingen?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "A file named /var/lib/mysql/debian-*.flag exists on this system." +msgstr "" +"Der er en fil med navnet /var/lib/mysql/debian-*.flag p dette system." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +#, fuzzy +#| msgid "" +#| "Such file is an indication that a mariadb-server package with a higher " +#| "version has been installed earlier." +msgid "" +"Such a file is an indication that a mariadb-server package with a higher " +"version has been installed previously." +msgstr "" +"Sdan en fil tyder p at der tidligere har vret installeret en hjere " +"version af mariadb-server-pakken." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "" +"There is no guarantee that the version you're currently installing will be " +"able to use the current databases." +msgstr "" +"Det kan ikke garanteres at den version, du er ved at installere, kan benytte " +"data fra de eksisterende databaser." + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "Important note for NIS/YP users" +msgstr "Vigtig oplysning til NIS/YP-brugere" + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "" +"Using MariaDB under NIS/YP requires a mysql user account to be added on the " +"local system with:" +msgstr "" + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +#, fuzzy +#| msgid "" +#| "You should also check the permissions and the owner of the /var/lib/mysql " +#| "directory:" +msgid "" +"You should also check the permissions and ownership of the /var/lib/mysql " +"directory:" +msgstr "" +"Du br ogs tjekke filrettighederne og ejerskabet af mappen /var/lib/mysql:" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "Remove all MariaDB databases?" +msgstr "Fjern alle MariaDB-databaser?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "" +"The /var/lib/mysql directory which contains the MariaDB databases is about " +"to be removed." +msgstr "" +"Mappen /var/lib/mysql, der indeholder MariaDB-databaserne, er ved at blive " +"fjernet." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "" +"If you're removing the MariaDB package in order to later install a more " +"recent version or if a different mariadb-server package is already using it, " +"the data should be kept." +msgstr "" +"Hvis du fjerner MariaDB-pakken for senere at installere en nyere version, " +"eller hvis en anden mariadb-server-pakke allerede benytter den, br dataene " +"bevares." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:5001 +msgid "Start the MariaDB server on boot?" +msgstr "Start MariaDB-serveren under systemopstart?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:5001 +msgid "" +"The MariaDB server can be launched automatically at boot time or manually " +"with the '/etc/init.d/mysql start' command." +msgstr "" +"MariaDB-serveren kan enten startes op automatisk under systemopstarten, " +"eller manuelt med kommandoen '/etc/init.d/mysql start'." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +msgid "New password for the MariaDB \"root\" user:" +msgstr "Ny adgangskode for MariaDB's \"root\"-bruger:" + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +msgid "" +"While not mandatory, it is highly recommended that you set a password for " +"the MariaDB administrative \"root\" user." +msgstr "" +"Selvom det ikke krves, anbefales det kraftigt, at du stter en adgangskode " +"for MariaDB's administrationsbruger \"root\"." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +#, fuzzy +#| msgid "If that field is left blank, the password will not be changed." +msgid "If this field is left blank, the password will not be changed." +msgstr "Hvis du lader dette felt st tomt, vil adgangskoden ikke blive ndret." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:7001 +#, fuzzy +#| msgid "New password for the MySQL \"root\" user:" +msgid "Repeat password for the MariaDB \"root\" user:" +msgstr "Ny adgangskode for MariaDB's \"root\"-bruger:" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "Unable to set password for the MariaDB \"root\" user" +msgstr "Kunne ikke stte adgangskoden for MariaDB's \"root\"-bruger" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "" +"An error occurred while setting the password for the MariaDB administrative " +"user. This may have happened because the account already has a password, or " +"because of a communication problem with the MariaDB server." +msgstr "" +"Der opstod en fejl, da adgangskoden for MariaDB's administrationsbruger blev " +"forsgt ndret. Dette kan vre sket, fordi brugeren allerede har en " +"adgangskode, eller fordi der var problemer med at kommunikere med MariaDB-" +"serveren." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "You should check the account's password after the package installation." +msgstr "Du br tjekke kontoens adgangskode efter pakkeinstallationen." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +#, fuzzy +#| msgid "" +#| "Please read the /usr/share/doc/mysql-server-5.1/README.Debian file for " +#| "more information." +msgid "" +"Please read the /usr/share/doc/mariadb-server-5.3/README.Debian file for " +"more information." +msgstr "" +"Se filen /usr/share/doc/mariadb-server-5.5/README.Debian for yderligere " +"oplysninger." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:9001 +msgid "Password input error" +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:9001 +msgid "The two passwords you entered were not the same. Please try again." +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:10001 +msgid "NDB Cluster seems to be in use" +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:10001 +msgid "" +"MySQL-5.1 no longer provides NDB Cluster support. Please migrate to the new " +"mysql-cluster package and remove all lines starting with \"ndb\" from all " +"config files below /etc/mysql/." +msgstr "" + +#~ msgid "" +#~ "To use MariaDB, the following entries for users and groups should be " +#~ "added to the system:" +#~ msgstr "" +#~ "Nedenstende linjer for brugere og grupper skal tilfjes dette system for " +#~ "at benytte MariaDB:" + +#~ msgid "Cannot upgrade if ISAM tables are present!" +#~ msgstr "Kan ikke opgradere hvis der er ISAM-tabeller!" + +#~ msgid "" +#~ "Recent versions of MySQL can no longer use the old ISAM table format and " +#~ "it is necessary to convert your tables to e.g. MyISAM before upgrading by " +#~ "using \"mysql_convert_table_format\" or \"ALTER TABLE x ENGINE=MyISAM\". " +#~ "The installation of mysql-server-5.1 will now abort. In case your old " +#~ "mysql-server-4.1 gets removed nevertheless just reinstall it to convert " +#~ "those tables." +#~ msgstr "" +#~ "Nyere versioner af MySQL kan ikke lngere benytte det gamle ISAM-" +#~ "tabelformat, og det er derfor ndvendigt at konvertere dine tabeller til " +#~ "f.eks. MyISAM forud for opgraderingen med \"mysql_convert_table_format\" " +#~ "eller \"ALTER TABLE x ENGINE=MyISAM\". Installationen af mysql-server-5.1 " +#~ "afbrydes nu. Skulle din gamle mysql-server-4.1 alligevel bliver " +#~ "afinstalleret, s geninstallr den blot og konverter tabellerne." + +#~ msgid "" +#~ "Support MySQL connections from hosts running Debian \"sarge\" or older?" +#~ msgstr "" +#~ "Understt MySQL-forbindelser fra maskiner, der krer Debian \"Sarge\" " +#~ "eller ldre?" + +#~ msgid "" +#~ "In old versions of MySQL clients on Debian, passwords were not stored " +#~ "securely. This has been improved since then, however clients (such as " +#~ "PHP) from hosts running Debian 3.1 Sarge will not be able to connect to " +#~ "recent accounts or accounts whose password have been changed." +#~ msgstr "" +#~ "Gamle udgaver af MySQL-klienter p Debian gemte ikke adgangskoderne " +#~ "sikkert. Dette er blevet forbedret siden da, men klienter (f.eks. PHP) " +#~ "fra maskiner, der krer Debian 3.1 Sarge vil ikke kunne forbinde til " +#~ "nyere konti eller konti, hvis adgangskode er blevet ndret." + +#~ msgid "" +#~ "To use mysql you must install an equivalent user and group to the " +#~ "following and ensure yourself that /var/lib/mysql has the right " +#~ "permissions (the uid/gid may be different)." +#~ msgstr "" +#~ "For at kunne bruge mysql skal du installere en bruger og en gruppe, der " +#~ "svarer til nedenstende, og sikre dig at /var/lib/mysql har de rigtige " +#~ "adgangsrettigheder (uid/gid kan afvige)." + +#~ msgid "" +#~ "/etc/passwd: mysql:x:100:101:MySQL Server:/var/lib/mysql:/bin/false" +#~ msgstr "" +#~ "etc/passwd: mysql:x:100:101:MySQL Server:/var/lib/mysql:/bin/false" + +#~ msgid "/etc/group: mysql:x:101:" +#~ msgstr "/etc/group: mysql:x:101:" + +#~ msgid "/var/lib/mysql: drwxr-xr-x mysql mysql" +#~ msgstr "/var/lib/mysql: drwxr-xr-x mysql mysql" + +#~ msgid "Remove the databases used by all MySQL versions?" +#~ msgstr "Fjern de databaser, der benyttes af samtlige MySQL-versioner?" + +#~ msgid "" +#~ "If you do not provide a password no changes will be made to the account." +#~ msgstr "Hvis du ikke angiver en adgangskode, vil kontoen ikke blive ndret." + +#~ msgid "" +#~ "When installation finishes, you should verify that the account is " +#~ "properly protected with a password (see README.Debian for more " +#~ "information)." +#~ msgstr "" +#~ "Nr installationen afsluttes, br du tjekke at kontoen er ordentligt " +#~ "beskyttet med en adgangskode (se README.Debian for yderligere " +#~ "oplysninger)." + +#~ msgid "Update Hints" +#~ msgstr "Opdateringstips" + +#~ msgid "" +#~ "You have to run \"mysql_upgrade\" after the upgrade, else tables can be " +#~ "corrupted! This script also enhances the privilege tables but is not " +#~ "supposed to give any user more rights that he had before," +#~ msgstr "" +#~ "Du skal kre \"mysql_upgrade\" efter opgraderingen, da tabellerne eller " +#~ "kan blive delagt! Dette script forbedrer ogs rettighedstabellerne, men " +#~ "burde ikke give nogen bruger flere rettigheder, end han havde tidligere," + +#~ msgid "Please also read http://www.mysql.com/doc/en/Upgrade.html" +#~ msgstr "Ls ogs http://www.mysql.com/doc/en/Upgrade.html" + +#~ msgid "Install Hints" +#~ msgstr "Installationstips" + +#~ msgid "" +#~ "On upgrades from MySQL 3.23, as shipped with Debian Woody, symlinks in " +#~ "place of /var/lib/mysql or /var/log/mysql gets accidently removed and " +#~ "have manually be restored." +#~ msgstr "" +#~ "Ved opgraderinger fra MySQL 3.23, der fulgte med Debian Woody, kan de " +#~ "symbolske /var/lib/mysql or /var/log/mysql blive fjernet ved et uheld, og " +#~ "m genskabes manuelt." + +#~ msgid "" +#~ "MySQL will only install if you have a non-numeric hostname that is " +#~ "resolvable via the /etc/hosts file. E.g. if the \"hostname\" command " +#~ "returns \"myhostname\" then there must be a line like \"10.0.0.1 " +#~ "myhostname\"." +#~ msgstr "" +#~ "MySQL vil kun blive installeret, hvis du har et ikke-numerisk vrtsnavn, " +#~ "som kan sls op i filen /ets/hosts. Hvis f.eks. kommandoen \"hostname\" " +#~ "svarer med \"mitvaertsnavn\", skal du have en linje a'la \"10.0.0.1 " +#~ "mitvaertsnavn\" i /etc/hosts." + +#~ msgid "" +#~ "A new mysql user \"debian-sys-maint\" will be created. This mysql account " +#~ "is used in the start/stop and cron scripts. Don't delete." +#~ msgstr "" +#~ "Det vil blive oprettet en ny mysql-bruger, \"debian-sys-maint\". Denne " +#~ "mysql-konto bruges i start/stop-cron-scripterne. Slet den ikke." + +#~ msgid "" +#~ "Please remember to set a PASSWORD for the MySQL root user! If you use a /" +#~ "root/.my.cnf, always write the \"user\" and the \"password\" lines in " +#~ "there, never only the password!" +#~ msgstr "" +#~ "Husk at stte en ADGANGSKODE for MySQLs root-bruger! Hvis du bruger en /" +#~ "etc/.my.cnf, s skriv altid \"user\"- og \"password\"-linjer ind her, " +#~ "ikke kun adgangskoden!" + +#~ msgid "" +#~ "Should I remove the complete /var/lib/mysql directory tree which is used " +#~ "by all MySQL versions, not necessarily only the one you are about to " +#~ "purge?" +#~ msgstr "" +#~ "Skal jeg fjerne hele mappetret /var/lib/mysql, som benyttes af alle " +#~ "MySQL-versioner, ikke kun den version, du er ved at slette?" + +#~ msgid "" +#~ "Rarely, e.g. on new major versions, the privilege system is improved. To " +#~ "make use of it mysql_fix_privilege_tables must be executed manually. The " +#~ "script is not supposed to give any user more rights that he had before," +#~ msgstr "" +#~ "En sjlden gang imellem, f.eks. ved nye hovedversioner, sker det at " +#~ "rettighedssystemet forbedres. For at gre brug af dette, skal " +#~ "mysql_fix_privilege_tables kres manuelt. Scriptet vil ikke give nogen " +#~ "bruger flere rettigheder, end vedkommende havde tidligere," diff --git a/debian/po/de.po b/debian/po/de.po new file mode 100644 index 00000000000..6dd989c7ae6 --- /dev/null +++ b/debian/po/de.po @@ -0,0 +1,234 @@ +# translation of mysql-dfsg-5.1_5.1.37-1_de.po to Deutsch +# +# Translators, if you are not familiar with the PO format, gettext +# documentation is worth reading, especially sections dedicated to +# this format, e.g. by running: +# info -n '(gettext)PO Files' +# info -n '(gettext)Header Entry' +# Some information specific to po-debconf are available at +# /usr/share/doc/po-debconf/README-trans +# or http://www.debian.org/intl/l10n/po-debconf/README-trans# +# Developers do not need to manually edit POT or PO files. +# +# Alwin Meschede , 2006, 2007. +# Thomas Mueller , 2009. +msgid "" +msgstr "" +"Project-Id-Version: mysql-dfsg-5.1_5.1.37-1_de\n" +"Report-Msgid-Bugs-To: mariadb-5.5@packages.debian.org\n" +"POT-Creation-Date: 2012-01-12 13:08+0100\n" +"PO-Revision-Date: 2009-08-27 22:41+0200\n" +"Last-Translator: Thomas Mueller \n" +"Language-Team: german \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: KBabel 1.11.4\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "Really proceed with downgrade?" +msgstr "Möchten Sie wirklich eine ältere Version einspielen?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "A file named /var/lib/mysql/debian-*.flag exists on this system." +msgstr "" +"Auf diesem System existiert eine Datei mit dem Namen /var/lib/mysql/debian-*." +"flag" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "" +"Such a file is an indication that a mariadb-server package with a higher " +"version has been installed previously." +msgstr "" +"Diese Datei ist ein Hinweis darauf, dass früher ein MariaDB-Server-Paket mit " +"einer höheren Version installiert war." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "" +"There is no guarantee that the version you're currently installing will be " +"able to use the current databases." +msgstr "" +"Es kann nicht garantiert werden, dass die gegenwärtig zu installierende " +"Version dessen Daten benutzen kann." + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "Important note for NIS/YP users" +msgstr "Wichtige Anmerkung für NIS/YP-Benutzer!" + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "" +"Using MariaDB under NIS/YP requires a mysql user account to be added on the " +"local system with:" +msgstr "" +"Falls MariaDB mit NIS/YP genutzt wird, ist ein »mysql«-Benutzerkonto auf dem " +"lokalen System notwendig:" + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "" +"You should also check the permissions and ownership of the /var/lib/mysql " +"directory:" +msgstr "" +"Sie sollten außerdem Besitzer und Zugriffsrechte des Verzeichnisses /var/lib/" +"mysql überprüfen:" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "Remove all MariaDB databases?" +msgstr "Alle MariaDB-Datenbanken entfernen?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "" +"The /var/lib/mysql directory which contains the MariaDB databases is about " +"to be removed." +msgstr "" +"Das Verzeichnis /var/lib/mysql mit den MariaDB-Datenbanken soll entfernt " +"werden." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "" +"If you're removing the MariaDB package in order to later install a more " +"recent version or if a different mariadb-server package is already using it, " +"the data should be kept." +msgstr "" +"Falls geplant ist, nur eine höhere Version von MariaDB zu installieren oder " +"ein anderes mariadb-server-Paket dieses bereits benutzt, sollten die Daten " +"behalten werden." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:5001 +msgid "Start the MariaDB server on boot?" +msgstr "Soll der MariaDB-Server automatisch beim Booten starten?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:5001 +msgid "" +"The MariaDB server can be launched automatically at boot time or manually " +"with the '/etc/init.d/mysql start' command." +msgstr "" +"Der MariaDB-Dienst kann entweder automatisch beim Systemstart oder manuell " +"durch Eingabe des Befehls »/etc/init.d/mysql start« gestartet werden." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +msgid "New password for the MariaDB \"root\" user:" +msgstr "Neues Passwort für den MariaDB »root«-Benutzer:" + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +msgid "" +"While not mandatory, it is highly recommended that you set a password for " +"the MariaDB administrative \"root\" user." +msgstr "" +"Obwohl es nicht zwingend erforderlich ist, wird nachdrücklich empfohlen für " +"den administrativen MariaDB »root«-Benutzer ein Passwort zu setzen." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +msgid "If this field is left blank, the password will not be changed." +msgstr "Wenn dieses Feld freigelassen wird, wird das Passwort nicht geändert." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:7001 +msgid "Repeat password for the MariaDB \"root\" user:" +msgstr "Wiederholen Sie das Passwort für den MariaDB-»root«-Benutzer:" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "Unable to set password for the MariaDB \"root\" user" +msgstr "Konnte für den MariaDB-»root«-Benutzer kein Passwort setzen" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "" +"An error occurred while setting the password for the MariaDB administrative " +"user. This may have happened because the account already has a password, or " +"because of a communication problem with the MariaDB server." +msgstr "" +"Beim setzen des Passworts für den administrativen MariaDB-Benutzer ist ein " +"Fehler aufgetreten. Dies könnte daran liegen, dass der Benutzer bereits ein " +"Passwort hat oder dass es ein Problem mit der Kommunikation mit dem MariaDB-" +"Server gibt." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "You should check the account's password after the package installation." +msgstr "" +"Sie sollten das Passwort des administrativen Benutzers nach der " +"Paketinstallation prüfen." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +#, fuzzy +#| msgid "" +#| "Please read the /usr/share/doc/mariadb-server-5.1/README.Debian file for " +#| "more information." +msgid "" +"Please read the /usr/share/doc/mariadb-server-5.3/README.Debian file for " +"more information." +msgstr "" +"Für weitere Informationen lesen Sie /usr/share/doc/mariadb-server-5.1/README." +"Debian." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:9001 +msgid "Password input error" +msgstr "Passwort-Eingabefehler" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:9001 +msgid "The two passwords you entered were not the same. Please try again." +msgstr "" +"Die beiden von Ihnen eingegebenen Passwörter sind nicht identisch. Bitte " +"erneut versuchen." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:10001 +msgid "NDB Cluster seems to be in use" +msgstr "NDB-Cluster scheint gerade benutzt zu werden" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:10001 +msgid "" +"MySQL-5.1 no longer provides NDB Cluster support. Please migrate to the new " +"mysql-cluster package and remove all lines starting with \"ndb\" from all " +"config files below /etc/mysql/." +msgstr "" +"MySQL-5.1 bietet keine NDB-Clusterunterstützung mehr. Bitte migrieren Sie " +"Ihr System zum neuen »mysql-cluster«-Paket und entfernen Sie alle Zeilen, " +"die mit »ndb« beginnen aus allen Konfigurationsdateien im Verzeichnis /etc/" +"mysql/." diff --git a/debian/po/es.po b/debian/po/es.po new file mode 100644 index 00000000000..42efda1896a --- /dev/null +++ b/debian/po/es.po @@ -0,0 +1,391 @@ +# mysql-dfsg-5 translation to spanish +# Copyright (C) 2005-2007 Software in the Public Interest, SPI Inc. +# This file is distributed under the same license as the XXXX package. +# +# Changes: +# - Initial translation +# Jesus Aneiros, 2006 +# - Updated +# Javier Fernandez-Sanguino, 2006-2007 +# - Revision +# Nacho Barrientos Arias +# Fernando Cerezal +# David Martínez Moreno +# Ricardo Mones +# Carlos Galisteo +# Javier Fernandez-Sanguino +# +# +# Traductores, si no conoce el formato PO, merece la pena leer la +# documentación de gettext, especialmente las secciones dedicadas a este +# formato, por ejemplo ejecutando: +# info -n '(gettext)PO Files' +# info -n '(gettext)Header Entry' +# +# Equipo de traducción al español, por favor lean antes de traducir +# los siguientes documentos: +# +# - El proyecto de traducción de Debian al español +# http://www.debian.org/intl/spanish/ +# especialmente las notas y normas de traducción en +# http://www.debian.org/intl/spanish/notas +# +# - La guía de traducción de po's de debconf: +# /usr/share/doc/po-debconf/README-trans +# o http://www.debian.org/intl/l10n/po-debconf/README-trans +# +# Si tiene dudas o consultas sobre esta traducción consulte con el último +# traductor (campo Last-Translator) y ponga en copia a la lista de +# traducción de Debian al español () +msgid "" +msgstr "" +"Project-Id-Version: mysql-dfsg-5.1_5.0.24-3\n" +"Report-Msgid-Bugs-To: mariadb-5.5@packages.debian.org\n" +"POT-Creation-Date: 2012-01-12 13:08+0100\n" +"PO-Revision-Date: 2007-05-28 22:21+0200\n" +"Last-Translator: Javier Fernández-Sanguino \n" +"Language-Team: Debian l10 Spanish \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "Really proceed with downgrade?" +msgstr "¿Desea realmente continuar con la desactualización?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "A file named /var/lib/mysql/debian-*.flag exists on this system." +msgstr "" +"Existe un archivo con el nombre /var/lib/mysql/debian-*.flag en este sistema." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +#, fuzzy +#| msgid "" +#| "Such file is an indication that a mariadb-server package with a higher " +#| "version has been installed earlier." +msgid "" +"Such a file is an indication that a mariadb-server package with a higher " +"version has been installed previously." +msgstr "" +"Este fichero indica que se instaló previamente una versión superior del " +"paquete mariadb-server." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "" +"There is no guarantee that the version you're currently installing will be " +"able to use the current databases." +msgstr "" +"No se puede garantizar que la versión que está instalando pueda usar la base " +"de datos actual." + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "Important note for NIS/YP users" +msgstr "Nota importante para los usuarios de NIS/YP" + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "" +"Using MariaDB under NIS/YP requires a mysql user account to be added on the " +"local system with:" +msgstr "" + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +#, fuzzy +#| msgid "" +#| "You should also check the permissions and the owner of the /var/lib/mysql " +#| "directory:" +msgid "" +"You should also check the permissions and ownership of the /var/lib/mysql " +"directory:" +msgstr "" +"También debería comprobar los permisos y el propietario del directorio /var/" +"lib/mysql:" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "Remove all MariaDB databases?" +msgstr "¿Desea eliminar todas las bases de datos MariaDB?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "" +"The /var/lib/mysql directory which contains the MariaDB databases is about " +"to be removed." +msgstr "" +"El directorio /var/lib/mysql contiene bases de datos MariaDB que van a " +"eliminarse." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "" +"If you're removing the MariaDB package in order to later install a more " +"recent version or if a different mariadb-server package is already using it, " +"the data should be kept." +msgstr "" +"Debería mantener los datos si tiene planificado instalar una versión de " +"MariaDB más reciente o si hay un paquete «mariadb-server» distinto que los " +"está utilizando." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:5001 +msgid "Start the MariaDB server on boot?" +msgstr "¿Debería ejecutarse el servidor MariaDB al iniciarse el sistema?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:5001 +msgid "" +"The MariaDB server can be launched automatically at boot time or manually " +"with the '/etc/init.d/mysql start' command." +msgstr "" +"El servidor MariaDB puede iniciarse en el momento de arranque del sistema o " +"manualmente si escribe la orden «/etc/init.d/mysql start»." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +msgid "New password for the MariaDB \"root\" user:" +msgstr "Nueva contraseña para el usuario «root» de MariaDB:" + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +msgid "" +"While not mandatory, it is highly recommended that you set a password for " +"the MariaDB administrative \"root\" user." +msgstr "" +"Se recomienda que configure una contraseña para el usuario " +"«root» (administrador) de MariaDB, aunque no es obligatorio." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +#, fuzzy +#| msgid "If that field is left blank, the password will not be changed." +msgid "If this field is left blank, the password will not be changed." +msgstr "No se modificará la contraseña si deja el espacio en blanco." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:7001 +#, fuzzy +#| msgid "New password for the MySQL \"root\" user:" +msgid "Repeat password for the MariaDB \"root\" user:" +msgstr "Nueva contraseña para el usuario «root» de MariaDB:" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "Unable to set password for the MariaDB \"root\" user" +msgstr "No se pudo fijar la contraseña para el usuario «root» de MariaDB" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "" +"An error occurred while setting the password for the MariaDB administrative " +"user. This may have happened because the account already has a password, or " +"because of a communication problem with the MariaDB server." +msgstr "" +"Se produjo un error mientras intentaba fijar la contraseña para el usuario " +"administrador de MariaDB. Esto puede haber sucedido porque la cuenta ya " +"tenía una contraseña o porque se produjo un error de comunicación con el " +"servidor MariaDB." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "You should check the account's password after the package installation." +msgstr "" +"Debería comprobar la contraseña de la cuenta después de la instalación del " +"paquete." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +#, fuzzy +#| msgid "" +#| "Please read the /usr/share/doc/mysql-server-5.1/README.Debian file for " +#| "more information." +msgid "" +"Please read the /usr/share/doc/mariadb-server-5.3/README.Debian file for " +"more information." +msgstr "" +"Consulte /usr/share/doc/mariadb-server-5.5/README.Debian para más " +"información." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:9001 +msgid "Password input error" +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:9001 +msgid "The two passwords you entered were not the same. Please try again." +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:10001 +msgid "NDB Cluster seems to be in use" +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:10001 +msgid "" +"MySQL-5.1 no longer provides NDB Cluster support. Please migrate to the new " +"mysql-cluster package and remove all lines starting with \"ndb\" from all " +"config files below /etc/mysql/." +msgstr "" + +#~ msgid "" +#~ "To use MariaDB, the following entries for users and groups should be " +#~ "added to the system:" +#~ msgstr "" +#~ "Deben añadirse las siguientes entradas para usuarios y grupos en el " +#~ "sistema para poder utilizar MariaDB:" + +#~ msgid "Cannot upgrade if ISAM tables are present!" +#~ msgstr "¡No se puede actualizar si ya hay tablas ISAM!" + +#~ msgid "" +#~ "Recent versions of MySQL can no longer use the old ISAM table format and " +#~ "it is necessary to convert your tables to e.g. MyISAM before upgrading by " +#~ "using \"mysql_convert_table_format\" or \"ALTER TABLE x ENGINE=MyISAM\". " +#~ "The installation of mysql-server-5.1 will now abort. In case your old " +#~ "mysql-server-4.1 gets removed nevertheless just reinstall it to convert " +#~ "those tables." +#~ msgstr "" +#~ "Las versiones recientes de MySQL ya no soportan el antiguo formato de " +#~ "tabla ISAM. Antes de realizar la actualización es necesario convertir sus " +#~ "tablas a por ejemplo, MyISAM, usando «mysql_convert_table_format» o " +#~ "«ALTER TABLE x ENGINE=MyISAM». Se va a interrumpir ahora la instalación " +#~ "de mysql-server-5.1. Si aún así su mysql-server-4.1 se elimina aún así, " +#~ "puede reinstalarlo para convertir ese tipo de tablas." + +#~ msgid "" +#~ "Support MySQL connections from hosts running Debian \"sarge\" or older?" +#~ msgstr "" +#~ "¿Soportar las conexiones MySQL establecidadas desde sistemas que ejecutan " +#~ "Debian Sarge o versiones anteriores?" + +#~ msgid "" +#~ "In old versions of MySQL clients on Debian, passwords were not stored " +#~ "securely. This has been improved since then, however clients (such as " +#~ "PHP) from hosts running Debian 3.1 Sarge will not be able to connect to " +#~ "recent accounts or accounts whose password have been changed." +#~ msgstr "" +#~ "No era muy segura la forma en la que se almacenaban las contraseñas en " +#~ "versiones anteriores del cliente de MySQL en Debian. Este problema se ha " +#~ "mejorado posteriormente con el inconveniente, sin embargo, de que " +#~ "clientes (por ejemplo, PHP) en sistemas que ejecutan Debian 3.1 «Sarge» " +#~ "no podrán conectarse a cuentas que son nuevas o a las que se le haya " +#~ "cambiado la contraseña." + +#~ msgid "" +#~ "To use mysql you must install an equivalent user and group to the " +#~ "following and ensure yourself that /var/lib/mysql has the right " +#~ "permissions (the uid/gid may be different)." +#~ msgstr "" +#~ "Para utilizar mysql debe instalar un usuario y grupo equivalente al " +#~ "siguiente y asegurarse de que /var/lib/mysql tiene los permisos correctos " +#~ "(los valores del «uid» y del «gid» pueden ser diferentes)." + +#~ msgid "" +#~ "/etc/passwd: mysql:x:100:101:MySQL Server:/var/lib/mysql:/bin/false" +#~ msgstr "" +#~ "/etc/passwd: mysql:x:100:101:MySQL Server:/var/lib/mysql:/bin/false" + +#~ msgid "/etc/group: mysql:x:101:" +#~ msgstr "/etc/group: mysql:x:101:" + +#~ msgid "/var/lib/mysql: drwxr-xr-x mysql mysql" +#~ msgstr "/var/lib/mysql: drwxr-xr-x mysql mysql" + +#~ msgid "Remove the databases used by all MySQL versions?" +#~ msgstr "" +#~ "¿Eliminar las bases de datos utilizadas por todas las versiones de MySQL?" + +#~ msgid "" +#~ "If you do not provide a password no changes will be made to the account." +#~ msgstr "" +#~ "No se hará ningún cambio en la cuenta si no introduce una contraseña." + +#~ msgid "" +#~ "When installation finishes, you should verify that the account is " +#~ "properly protected with a password (see README.Debian for more " +#~ "information)." +#~ msgstr "" +#~ "Debería confirmar que la contraseña está correctamente protegida con una " +#~ "contraseña cuando termine la instalación (consulte el fichero README." +#~ "Debian si desea más información)." + +#~ msgid "Install Hints" +#~ msgstr "Sugerencias para la instalación" + +#~ msgid "" +#~ "On upgrades from MySQL 3.23, as shipped with Debian Woody, symlinks in " +#~ "place of /var/lib/mysql or /var/log/mysql gets accidently removed and " +#~ "have manually be restored." +#~ msgstr "" +#~ "Al actualizar a la versión de MySQL 3.23, la vrsión proporcionada en " +#~ "Debian Woody, se eliminan de manera accidental, los enlaces simbólicos a " +#~ "«/var/lib/mysql» o «/var/log/mysql» y tienen que restaurarse manualmente." + +#~ msgid "" +#~ "MySQL will only install if you have a non-numeric hostname that is " +#~ "resolvable via the /etc/hosts file. E.g. if the \"hostname\" command " +#~ "returns \"myhostname\" then there must be a line like \"10.0.0.1 " +#~ "myhostname\"." +#~ msgstr "" +#~ "Sólo se instalará MySQL si tiene un nombre de equipo que no sea una " +#~ "dirección IP y pueda resolverse a través del archivo /etc/hosts. Por " +#~ "ejemplo, si la orden «hostname» devuelve «MiNombreEquipo» entonces deberá " +#~ "existir una línea «10.0.0.1 MiNombreEquipo» en dicho archivo." + +#~ msgid "" +#~ "A new mysql user \"debian-sys-maint\" will be created. This mysql account " +#~ "is used in the start/stop and cron scripts. Don't delete." +#~ msgstr "" +#~ "Se creará un nuevo usuario «debian-sys-maint». Esta cuenta de mysql se " +#~ "utilizará en los scripts de inicio y parada y en los scripts «cron». No " +#~ "la elimine." + +#~ msgid "" +#~ "Please remember to set a PASSWORD for the MySQL root user! If you use a /" +#~ "root/.my.cnf, always write the \"user\" and the \"password\" lines in " +#~ "there, never only the password!" +#~ msgstr "" +#~ "¡Por favor, recuerde crear una CONTRASEÑA para el usuario «root» de " +#~ "MySQL! ¡Si utiliza /root/.my.cnf debe escribir las líneas «user» y " +#~ "«password» en dicho archivo, no incluya sólo la contraseña!" + +#~ msgid "" +#~ "Should I remove the complete /var/lib/mysql directory tree which is used " +#~ "by all MySQL versions, not necessarily only the one you are about to " +#~ "purge?" +#~ msgstr "" +#~ "¿Debería eliminar el árbol de directorio /var/lib/mysql completo? Tenga " +#~ "en cuenta que lo utilizan todas las versiones de MySQL y no sólo la que " +#~ "está a punto de purgar." diff --git a/debian/po/eu.po b/debian/po/eu.po new file mode 100644 index 00000000000..019fc5ce090 --- /dev/null +++ b/debian/po/eu.po @@ -0,0 +1,237 @@ +# translation of eu.po to Euskara +# Piarres BEobide , 2006. +# Piarres Beobide , 2009. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +msgid "" +msgstr "" +"Project-Id-Version: eu\n" +"Report-Msgid-Bugs-To: mariadb-5.5@packages.debian.org\n" +"POT-Creation-Date: 2012-01-12 13:08+0100\n" +"PO-Revision-Date: 2009-07-29 11:59+0200\n" +"Last-Translator: Piarres Beobide \n" +"Language-Team: Euskara \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: KBabel 1.11.4\n" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "Really proceed with downgrade?" +msgstr "Benetan bertsio zaharragora itzuli nahi duzu?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "A file named /var/lib/mysql/debian-*.flag exists on this system." +msgstr "Sisteman badago /var/lib/mysql/debian-*.flag izeneko fitxategi bat." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +#, fuzzy +#| msgid "" +#| "Such file is an indication that a mariadb-server package with a higher " +#| "version has been installed earlier." +msgid "" +"Such a file is an indication that a mariadb-server package with a higher " +"version has been installed previously." +msgstr "" +"Fitxategi honek aurretik bertsio berriagoko mysql-zerbitzari pakete bat " +"instalatu dela adierazten du." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "" +"There is no guarantee that the version you're currently installing will be " +"able to use the current databases." +msgstr "" +"Ezin da ziurtatu instalatzen ari zaren bertsio honek dauden datubaseak " +"erabili ahal izango dituenik." + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "Important note for NIS/YP users" +msgstr "NIS/YP erabiltzaileentzat ohar garrantzitsua" + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "" +"Using MariaDB under NIS/YP requires a mysql user account to be added on the " +"local system with:" +msgstr "" + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +#, fuzzy +#| msgid "" +#| "You should also check the permissions and the owner of the /var/lib/mysql " +#| "directory:" +msgid "" +"You should also check the permissions and ownership of the /var/lib/mysql " +"directory:" +msgstr "" +"Honetaz gain /var/lib/mysql direktorioaren jabea eta baimenak egiaztatu " +"beharko zenituzke:" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "Remove all MariaDB databases?" +msgstr "Ezabatu MariaDB datubase guztiak?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "" +"The /var/lib/mysql directory which contains the MariaDB databases is about " +"to be removed." +msgstr "" +"MariaDB datubaseak dituen /var/lib/mysql direktorioa ezabatua izango da." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "" +"If you're removing the MariaDB package in order to later install a more " +"recent version or if a different mariadb-server package is already using it, " +"the data should be kept." +msgstr "" +"MariaDB paketea beranduago bertsio berriago bat instalatzeko kentzen ari " +"bazara, edo beste mariadb-server pakete bat berau erabiltzen ari bada, " +"datuak mantendu egin beharko lirateke." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:5001 +msgid "Start the MariaDB server on boot?" +msgstr "Abioan MariaDB zerbitzaria abiarazi?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:5001 +msgid "" +"The MariaDB server can be launched automatically at boot time or manually " +"with the '/etc/init.d/mysql start' command." +msgstr "" +"Sistema abioan MariaDB automatikoki abiarazi daiteke edo eskuz '/etc/init.d/" +"mysql start' eginaz." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +msgid "New password for the MariaDB \"root\" user:" +msgstr "MariaDB \"root\" erabiltzailearen pasahitz berria:" + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +msgid "" +"While not mandatory, it is highly recommended that you set a password for " +"the MariaDB administrative \"root\" user." +msgstr "" +"Derrigorrezkoa ez denean, oso gomendagarria da MariaDB administratzaile " +"\"root\" erabiltzaileari pasahitz bat ezartzea." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +#, fuzzy +#| msgid "If that field is left blank, the password will not be changed." +msgid "If this field is left blank, the password will not be changed." +msgstr "Eremua hau zurian utziaz gero ez da pasahitza aldatuko." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:7001 +msgid "Repeat password for the MariaDB \"root\" user:" +msgstr "Errepikatu MariaDB \"root\" erabiltzailearen pasahitza:" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "Unable to set password for the MariaDB \"root\" user" +msgstr "Ezin da MariaDB \"root\" erabiltzailearen pasahitza ezarri" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "" +"An error occurred while setting the password for the MariaDB administrative " +"user. This may have happened because the account already has a password, or " +"because of a communication problem with the MariaDB server." +msgstr "" +"Errore bat gertatu da MariaDB administratzaile kontuaren pasahitza " +"ezartzean. Hau erabiltzaileak dagoeneko pasahitz bat duelako edo MariaDB " +"zerbitzariarekiko konexioan erroreak daudelako gertatu daiteke." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "You should check the account's password after the package installation." +msgstr "" +"Kontuaren pasahitza egiaztatu beharko zenuke paketea instalatu aurretik." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +#, fuzzy +#| msgid "" +#| "Please read the /usr/share/doc/mariadb-server-5.5/README.Debian file for " +#| "more information." +msgid "" +"Please read the /usr/share/doc/mariadb-server-5.3/README.Debian file for " +"more information." +msgstr "" +"Mesedez irakurri /usr/share/doc/mariadb-server-5.5/README.Debian fitxategia " +"xehetasun gehiagorako." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:9001 +msgid "Password input error" +msgstr "Pasahitz sarrera errorea" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:9001 +msgid "The two passwords you entered were not the same. Please try again." +msgstr "Idatzi dituzun bi pasahitzak ez dira berdina. Mesedez saiatu berriz." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:10001 +msgid "NDB Cluster seems to be in use" +msgstr "Dirudienez NDB Cluster-a erabilia dago" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:10001 +#, fuzzy +#| msgid "" +#| "MySQL-5.1 has orphaned NDB Cluster support. Please migrate to the new " +#| "mysql-cluster package and remove all lines starting with \"ndb\" from all " +#| "config files below /etc/mysql/." +msgid "" +"MySQL-5.1 no longer provides NDB Cluster support. Please migrate to the new " +"mysql-cluster package and remove all lines starting with \"ndb\" from all " +"config files below /etc/mysql/." +msgstr "" +"MySQL-5.1-ek NDB cluster euskarri umezurtz bat behar du. Mesedez migratu " +"mysql-cluster pakete berrira eta /etc/mysql/ azpiko konfigurazio fitxategi " +"guztietan \"ndb\"-ez hasten diren lerro guztiak ezabatu." + +#~ msgid "" +#~ "To use MariaDB, the following entries for users and groups should be " +#~ "added to the system:" +#~ msgstr "" +#~ "MariaDB erabili ahal izateko, hurrengo erabiltzaile eta taldeak gehitu " +#~ "behar dira sisteman:" diff --git a/debian/po/fr.po b/debian/po/fr.po new file mode 100644 index 00000000000..98690573a6b --- /dev/null +++ b/debian/po/fr.po @@ -0,0 +1,246 @@ +# Translation of mysql-dfsg-* debconf templates to French +# Copyright (C) 2004-2009 Debian French l10n team +# This file is distributed under the same license as the mysql-dfsg-* packages. +# +# Translators: +# Christian Perrier , 2004, 2006, 2007, 2009. +msgid "" +msgstr "" +"Project-Id-Version: fr\n" +"Report-Msgid-Bugs-To: mariadb-5.5@packages.debian.org\n" +"POT-Creation-Date: 2012-01-12 13:08+0100\n" +"PO-Revision-Date: 2009-08-08 14:56+0200\n" +"Last-Translator: Christian Perrier \n" +"Language-Team: French \n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"debian.org>\n" +"X-Generator: Lokalize 0.3\n" +"Plural-Forms: Plural-Forms: nplurals=2; plural=n>1;\n" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "Really proceed with downgrade?" +msgstr "Faut-il vraiment revenir à la version précédente ?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "A file named /var/lib/mysql/debian-*.flag exists on this system." +msgstr "Un fichier /var/lib/mysql/debian-*.flag est présent sur ce système." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "" +"Such a file is an indication that a mariadb-server package with a higher " +"version has been installed previously." +msgstr "" +"Cela indique qu'une version plus récente du paquet mariadb-server a été " +"précédemment installée." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "" +"There is no guarantee that the version you're currently installing will be " +"able to use the current databases." +msgstr "Il n'est pas garanti que cette version puisse en utiliser les données." + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "Important note for NIS/YP users" +msgstr "Note importante pour les utilisateurs NIS/YP" + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "" +"Using MariaDB under NIS/YP requires a mysql user account to be added on the " +"local system with:" +msgstr "" +"L'utilisation de MariaDB avec NIS/YP impose l'ajout d'un compte local " +"« mysql » avec la commande :" + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "" +"You should also check the permissions and ownership of the /var/lib/mysql " +"directory:" +msgstr "" +"Vous devez également vérifier le propriétaire et les permissions du " +"répertoire /var/lib/mysql :" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "Remove all MariaDB databases?" +msgstr "Faut-il supprimer toutes les bases de données MariaDB ?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "" +"The /var/lib/mysql directory which contains the MariaDB databases is about " +"to be removed." +msgstr "" +"Le répertoire /var/lib/mysql qui contient les bases de données de MariaDB va " +"être supprimé." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "" +"If you're removing the MariaDB package in order to later install a more " +"recent version or if a different mariadb-server package is already using it, " +"the data should be kept." +msgstr "" +"Si vous prévoyez d'installer une version plus récente de MariaDB ou si un " +"autre paquet mariadb-server les utilise déjà, vous devriez les conserver." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:5001 +msgid "Start the MariaDB server on boot?" +msgstr "Faut-il lancer MariaDB au démarrage ?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:5001 +msgid "" +"The MariaDB server can be launched automatically at boot time or manually " +"with the '/etc/init.d/mysql start' command." +msgstr "" +"MariaDB peut être lancé soit au démarrage, soit en entrant la commande « /" +"etc/init.d/mysql start »." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +msgid "New password for the MariaDB \"root\" user:" +msgstr "Nouveau mot de passe du superutilisateur de MariaDB :" + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +msgid "" +"While not mandatory, it is highly recommended that you set a password for " +"the MariaDB administrative \"root\" user." +msgstr "" +"Il est très fortement recommandé d'établir un mot de passe pour le compte " +"d'administration de MariaDB (« root »)." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +msgid "If this field is left blank, the password will not be changed." +msgstr "Si ce champ est laissé vide, le mot de passe ne sera pas changé." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:7001 +msgid "Repeat password for the MariaDB \"root\" user:" +msgstr "Confirmation du mot de passe du superutilisateur de MariaDB :" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "Unable to set password for the MariaDB \"root\" user" +msgstr "" +"Impossible de changer le mot de passe de l'utilisateur « root » de MariaDB" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "" +"An error occurred while setting the password for the MariaDB administrative " +"user. This may have happened because the account already has a password, or " +"because of a communication problem with the MariaDB server." +msgstr "" +"Une erreur s'est produite lors du changement de mot de passe du compte " +"d'administration. Un mot de passe existait peut-être déjà ou il n'a pas été " +"possible de communiquer avec le serveur MariaDB." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "You should check the account's password after the package installation." +msgstr "" +"Vous devriez vérifier le mot de passe de ce compte après l'installation du " +"paquet." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +#, fuzzy +#| msgid "" +#| "Please read the /usr/share/doc/mariadb-server-5.5/README.Debian file for " +#| "more information." +msgid "" +"Please read the /usr/share/doc/mariadb-server-5.3/README.Debian file for " +"more information." +msgstr "" +"Veuillez consulter le fichier /usr/share/doc/mysql-server-5.5/README.Debian " +"pour plus d'informations." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:9001 +msgid "Password input error" +msgstr "Erreur de saisie du mot de passe" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:9001 +msgid "The two passwords you entered were not the same. Please try again." +msgstr "" +"Le mot de passe et sa confirmation ne sont pas identiques. Veuillez " +"recommencer." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:10001 +msgid "NDB Cluster seems to be in use" +msgstr "Abandon de la gestion de NDB" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:10001 +msgid "" +"MySQL-5.1 no longer provides NDB Cluster support. Please migrate to the new " +"mysql-cluster package and remove all lines starting with \"ndb\" from all " +"config files below /etc/mysql/." +msgstr "" +"La version 5.1 de MySQL ne gère plus les grappes NDB. Vous devriez utiliser " +"le paquet mysql-cluster et supprimer toutes les lignes commençant par " +"« ndb » des fichiers de configuration situés dans /etc/mysql." + +#~ msgid "" +#~ "To use MySQL, the following entries for users and groups should be added " +#~ "to the system:" +#~ msgstr "" +#~ "Pour pouvoir utiliser MySQL, les utilisateurs et les groupes suivants " +#~ "doivent être ajoutés au système :" + +#~ msgid "" +#~ "Support MySQL connections from hosts running Debian \"sarge\" or older?" +#~ msgstr "" +#~ "Gérer les connexions d'hôtes qui utilisent les versions Debian « sarge » " +#~ "ou antérieures  ?" + +#~ msgid "" +#~ "In old versions of MySQL clients on Debian, passwords were not stored " +#~ "securely. This has been improved since then, however clients (such as " +#~ "PHP) from hosts running Debian 3.1 Sarge will not be able to connect to " +#~ "recent accounts or accounts whose password have been changed." +#~ msgstr "" +#~ "La méthode de stockage des mots de passe n'était pas très sûre dans les " +#~ "version précédentes de ce paquet. Cette méthode a été améliorée mais les " +#~ "modifications empêchent la connexion avec de nouveaux comptes ou des " +#~ "comptes dont le mot de passe a été modifié, pour les clients (p. ex. PHP) " +#~ "depuis des hôtes qui utilisent Debian 3.1 « sarge »." diff --git a/debian/po/gl.po b/debian/po/gl.po new file mode 100644 index 00000000000..7feb5944c02 --- /dev/null +++ b/debian/po/gl.po @@ -0,0 +1,249 @@ +# Galician translation of mysql-dfsg-5.1's debconf templates +# This file is distributed under the same license as the mysql-dfsg-5.1 package. +# Jacobo Tarrio , 2007. +# +msgid "" +msgstr "" +"Project-Id-Version: mysql-dfsg-5.1\n" +"Report-Msgid-Bugs-To: mariadb-5.5@packages.debian.org\n" +"POT-Creation-Date: 2012-01-12 13:08+0100\n" +"PO-Revision-Date: 2007-04-20 09:44+0200\n" +"Last-Translator: Jacobo Tarrio \n" +"Language-Team: Galician \n" +"Language: gl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "Really proceed with downgrade?" +msgstr "¿Quere pasar a unha versión anterior?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "A file named /var/lib/mysql/debian-*.flag exists on this system." +msgstr "Neste sistema hai un ficheiro chamado /var/lib/mysql/debian-*.flag." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +#, fuzzy +#| msgid "" +#| "Such file is an indication that a mariadb-server package with a higher " +#| "version has been installed earlier." +msgid "" +"Such a file is an indication that a mariadb-server package with a higher " +"version has been installed previously." +msgstr "" +"Este ficheiro indica que antes se instalou un paquete mariadb-server cunha " +"versión superior." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "" +"There is no guarantee that the version you're currently installing will be " +"able to use the current databases." +msgstr "" +"Non se pode garantir que a versión que está a instalar poida empregar as " +"bases de datos actuais." + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "Important note for NIS/YP users" +msgstr "Nota importante para os usuarios de NIS/YP" + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "" +"Using MariaDB under NIS/YP requires a mysql user account to be added on the " +"local system with:" +msgstr "" + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +#, fuzzy +#| msgid "" +#| "You should also check the permissions and the owner of the /var/lib/mysql " +#| "directory:" +msgid "" +"You should also check the permissions and ownership of the /var/lib/mysql " +"directory:" +msgstr "" +"Tamén debería comprobar os permisos e o propietario do directorio /var/lib/" +"mysql:" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "Remove all MariaDB databases?" +msgstr "¿Eliminar tódalas bases de datos de MariaDB?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "" +"The /var/lib/mysql directory which contains the MariaDB databases is about " +"to be removed." +msgstr "" +"Hase eliminar o directorio /var/lib/mysql, que contén as bases de datos de " +"MariaDB." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "" +"If you're removing the MariaDB package in order to later install a more " +"recent version or if a different mariadb-server package is already using it, " +"the data should be kept." +msgstr "" +"Se está a eliminar o paquete MariaDB para instalar despois unha versión máis " +"recente ou se xa hai un paquete mariadb-server diferente a empregalo, " +"debería conservar os datos." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:5001 +msgid "Start the MariaDB server on boot?" +msgstr "¿Iniciar o servidor MariaDB co ordenador?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:5001 +msgid "" +"The MariaDB server can be launched automatically at boot time or manually " +"with the '/etc/init.d/mysql start' command." +msgstr "" +"Pódese iniciar automaticamente o servidor MariaDB ao iniciar o ordenador, ou " +"manualmente coa orde \"/etc/init.d/mysql start\"." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +msgid "New password for the MariaDB \"root\" user:" +msgstr "Novo contrasinal para o usuario \"root\" de MariaDB:" + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +msgid "" +"While not mandatory, it is highly recommended that you set a password for " +"the MariaDB administrative \"root\" user." +msgstr "" +"Aínda que non é obrigatorio, recoméndase encarecidamente que estableza un " +"contrasinal para o usuario administrativo \"root\" de MariaDB." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +#, fuzzy +#| msgid "If that field is left blank, the password will not be changed." +msgid "If this field is left blank, the password will not be changed." +msgstr "Se deixa o campo en branco, non se ha cambiar o contrasinal." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:7001 +#, fuzzy +#| msgid "New password for the MySQL \"root\" user:" +msgid "Repeat password for the MariaDB \"root\" user:" +msgstr "Novo contrasinal para o usuario \"root\" de MariaDB:" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "Unable to set password for the MariaDB \"root\" user" +msgstr "Non se puido establecer o contrasinal do usuario \"root\" de MariaDB" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "" +"An error occurred while setting the password for the MariaDB administrative " +"user. This may have happened because the account already has a password, or " +"because of a communication problem with the MariaDB server." +msgstr "" +"Houbo un erro ao establecer o contrasinal do usuario administrativo de " +"MariaDB. Puido ocorrer porque o usuario xa teña un contrasinal ou debido a " +"un problema de comunicacións co servidor MariaDB." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +#, fuzzy +#| msgid "" +#| "You should check the account's password after tha package installation." +msgid "You should check the account's password after the package installation." +msgstr "Debería comprobar o contrasinal da conta trala instalación do paquete." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +#, fuzzy +#| msgid "" +#| "Please read the /usr/share/doc/mysql-server-5.1/README.Debian file for " +#| "more information." +msgid "" +"Please read the /usr/share/doc/mariadb-server-5.3/README.Debian file for " +"more information." +msgstr "" +"Consulte o ficheiro /usr/share/doc/mariadb-server-5.5/README.Debian para " +"máis información." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:9001 +msgid "Password input error" +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:9001 +msgid "The two passwords you entered were not the same. Please try again." +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:10001 +msgid "NDB Cluster seems to be in use" +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:10001 +msgid "" +"MySQL-5.1 no longer provides NDB Cluster support. Please migrate to the new " +"mysql-cluster package and remove all lines starting with \"ndb\" from all " +"config files below /etc/mysql/." +msgstr "" + +#~ msgid "" +#~ "To use MariaDB, the following entries for users and groups should be " +#~ "added to the system:" +#~ msgstr "" +#~ "Para empregar MariaDB deberían engadirse ao sistema as seguintes entradas " +#~ "de usuarios e grupos:" + +#~ msgid "" +#~ "Support MySQL connections from hosts running Debian \"sarge\" or older?" +#~ msgstr "" +#~ "¿Soportar as conexións a MySQL de máquinas que empreguen Debian \"sarge\" " +#~ "ou anterior?" + +#~ msgid "" +#~ "In old versions of MySQL clients on Debian, passwords were not stored " +#~ "securely. This has been improved since then, however clients (such as " +#~ "PHP) from hosts running Debian 3.1 Sarge will not be able to connect to " +#~ "recent accounts or accounts whose password have been changed." +#~ msgstr "" +#~ "Nas versións antigas dos clientes MySQL de Debian, os contrasinais non se " +#~ "armacenaban de xeito seguro. Isto mellorouse desde aquela; nembargantes, " +#~ "os clientes (tales coma PHP) das máquinas que executen Debian 3.1 Sarge " +#~ "non se han poder conectar a contas recentes ou a contas nas que se " +#~ "cambiara o contrasinal." diff --git a/debian/po/it.po b/debian/po/it.po new file mode 100644 index 00000000000..69ef4238c29 --- /dev/null +++ b/debian/po/it.po @@ -0,0 +1,218 @@ +# Italian (it) translation of debconf templates for mysql-dfsg-5.1 +# Copyright (C) 2009 Software in the Public Interest +# This file is distributed under the same license as the mysql-dfsg-5.1 package. +# Luca Monducci , 2006 - 2009. +# +msgid "" +msgstr "" +"Project-Id-Version: mysql-dfsg-5.1 5.1.37 italian debconf templates\n" +"Report-Msgid-Bugs-To: mariadb-5.5@packages.debian.org\n" +"POT-Creation-Date: 2012-01-12 13:08+0100\n" +"PO-Revision-Date: 2009-08-08 11:03+0200\n" +"Last-Translator: Luca Monducci \n" +"Language-Team: Italian \n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "Really proceed with downgrade?" +msgstr "Procedere realmente con l'abbassamento di versione?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "A file named /var/lib/mysql/debian-*.flag exists on this system." +msgstr "" +"Su questo sistema esiste un file con nome /var/lib/mysql/debian-*.flag." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "" +"Such a file is an indication that a mariadb-server package with a higher " +"version has been installed previously." +msgstr "" +"Quel file indica che in precedenza è stata installata una versione superiore " +"del pacchetto mariadb-server." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "" +"There is no guarantee that the version you're currently installing will be " +"able to use the current databases." +msgstr "" +"Non è garantito che la versione che si sta installando sia in grado di usare " +"i database presenti." + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "Important note for NIS/YP users" +msgstr "Nota importante per gli utenti NIS/YP" + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "" +"Using MariaDB under NIS/YP requires a mysql user account to be added on the " +"local system with:" +msgstr "" +"Per usare MariaDB con NIS/YP è necessario aggiungere al sistema locale un " +"account utente per mysql con:" + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "" +"You should also check the permissions and ownership of the /var/lib/mysql " +"directory:" +msgstr "" +"Inoltre si devono verificare i permessi e la proprietà della directory /var/" +"lib/mysql:" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "Remove all MariaDB databases?" +msgstr "Eliminare tutti i database MariaDB?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "" +"The /var/lib/mysql directory which contains the MariaDB databases is about " +"to be removed." +msgstr "" +"La directory /var/lib/mysql contenente i database di MariaDB sta per essere " +"eliminata." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "" +"If you're removing the MariaDB package in order to later install a more " +"recent version or if a different mariadb-server package is already using it, " +"the data should be kept." +msgstr "" +"Se si rimuove il pacchetto MariaDB per poi installare una versione più " +"recente oppure se sono già in uso da un altro pacchetto mariadb-server, i " +"dati non devono essere eliminati." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:5001 +msgid "Start the MariaDB server on boot?" +msgstr "Lanciare il server MariaDB all'avvio?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:5001 +msgid "" +"The MariaDB server can be launched automatically at boot time or manually " +"with the '/etc/init.d/mysql start' command." +msgstr "" +"Il server MariaDB può essere lanciato automaticamente all'avvio del sistema " +"oppure manualmente con il comando «/etc/init.d/mysql start»." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +msgid "New password for the MariaDB \"root\" user:" +msgstr "Nuova password per l'utente «root» di MariaDB:" + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +msgid "" +"While not mandatory, it is highly recommended that you set a password for " +"the MariaDB administrative \"root\" user." +msgstr "" +"Sebbene non sia obbligatoria, si raccomanda d'impostare una password per " +"l'utente d'amministrazione «root» di MariaDB." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +msgid "If this field is left blank, the password will not be changed." +msgstr "Se questo campo è lasciato vuoto, la password non viene cambiata." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:7001 +msgid "Repeat password for the MariaDB \"root\" user:" +msgstr "Ripetere la password per l'utente «root» di MariaDB:" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "Unable to set password for the MariaDB \"root\" user" +msgstr "Impossibile impostare la password per l'utente «root» di MariaDB" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "" +"An error occurred while setting the password for the MariaDB administrative " +"user. This may have happened because the account already has a password, or " +"because of a communication problem with the MariaDB server." +msgstr "" +"Si è verificato un errore durante l'impostazione della password per l'utente " +"d'amministrazione di MariaDB. Questo può essere accaduto perché l'utente ha " +"già una password oppure a causa di un problema di connessione con il server " +"MariaDB." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "You should check the account's password after the package installation." +msgstr "" +"Al termine dell'installazione si deve verificare la password dell'account." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +#, fuzzy +#| msgid "" +#| "Please read the /usr/share/doc/mariadb-server-5.5/README.Debian file for " +#| "more information." +msgid "" +"Please read the /usr/share/doc/mariadb-server-5.3/README.Debian file for " +"more information." +msgstr "" +"Per maggiori informazioni si consulti il file /usr/share/doc/mariadb-" +"server-5.5/README.Debian." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:9001 +msgid "Password input error" +msgstr "Errore di inserimento della password" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:9001 +msgid "The two passwords you entered were not the same. Please try again." +msgstr "Le due password inserite sono diverse. Riprovare." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:10001 +msgid "NDB Cluster seems to be in use" +msgstr "È in uso un cluster NDB" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:10001 +msgid "" +"MySQL-5.1 no longer provides NDB Cluster support. Please migrate to the new " +"mysql-cluster package and remove all lines starting with \"ndb\" from all " +"config files below /etc/mysql/." +msgstr "" +"MySQL-5.1 non fornisce più il supporto per i cluster NDB. Si dovrebbe " +"migrare al nuovo pacchetto mysql-cluster e rimuovere tutte le righe che " +"iniziano per \"ndb\" da tutti i file di configurazione sotto /etc/mysql/." diff --git a/debian/po/ja.po b/debian/po/ja.po new file mode 100644 index 00000000000..07a0172c8ca --- /dev/null +++ b/debian/po/ja.po @@ -0,0 +1,224 @@ +# +# Translators, if you are not familiar with the PO format, gettext +# documentation is worth reading, especially sections dedicated to +# this format, e.g. by running: +# info -n '(gettext)PO Files' +# info -n '(gettext)Header Entry' +# +# Some information specific to po-debconf are available at +# /usr/share/doc/po-debconf/README-trans +# or http://www.debian.org/intl/l10n/po-debconf/README-trans +# +# Developers do not need to manually edit POT or PO files. +# +# +msgid "" +msgstr "" +"Project-Id-Version: mysql-dfsg-5.1 5.1.37-1\n" +"Report-Msgid-Bugs-To: mariadb-5.5@packages.debian.org\n" +"POT-Creation-Date: 2012-01-12 13:08+0100\n" +"PO-Revision-Date: 2009-09-01 08:25+0900\n" +"Last-Translator: Hideki Yamane (Debian-JP) \n" +"Language-Team: Japanese \n" +"Language: ja\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "Really proceed with downgrade?" +msgstr "本当にダウングレードを実行しますか?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "A file named /var/lib/mysql/debian-*.flag exists on this system." +msgstr "" +"このシステムには /var/lib/mysql/debian-*.flag という名前のファイルが存在して" +"います。" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "" +"Such a file is an indication that a mariadb-server package with a higher " +"version has been installed previously." +msgstr "" +"このファイルが意味するのは、以前により新しいバージョンの mariadb-server パッ" +"ケージがインストールされていたことを示します。" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "" +"There is no guarantee that the version you're currently installing will be " +"able to use the current databases." +msgstr "" +"このデータベースを現在インストールしようとしているバージョンで使えるかどうか" +"は保証できません。" + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "Important note for NIS/YP users" +msgstr "NIS/YP ユーザへの重要な注意" + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "" +"Using MariaDB under NIS/YP requires a mysql user account to be added on the " +"local system with:" +msgstr "" +"NIS/YP 配下で MariaDB を使うにはローカルのシステムに mysql のユーザアカウント" +"を追加するのが必要です。" + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "" +"You should also check the permissions and ownership of the /var/lib/mysql " +"directory:" +msgstr "/var/lib/mysql の所有者権限をチェックする必要もあります。" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "Remove all MariaDB databases?" +msgstr "すべての MariaDB データベースを削除しますか?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "" +"The /var/lib/mysql directory which contains the MariaDB databases is about " +"to be removed." +msgstr "" +"MariaDB データベースを含んでいるディレクトリ /var/lib/mysql を削除しようとし" +"ています。" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "" +"If you're removing the MariaDB package in order to later install a more " +"recent version or if a different mariadb-server package is already using it, " +"the data should be kept." +msgstr "" +"後でより新しいバージョンのものをインストールしようとするために MariaDB パッ" +"ケージを削除しようとしている、あるいは別の mariadb-server パッケージを既に" +"使っている場合、データは保持する必要があります。" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:5001 +msgid "Start the MariaDB server on boot?" +msgstr "MariaDB をシステム起動時に開始しますか?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:5001 +msgid "" +"The MariaDB server can be launched automatically at boot time or manually " +"with the '/etc/init.d/mysql start' command." +msgstr "" +"MariaDB の起動方法について、システム起動時に自動的に開始するか、あるいは '/" +"etc/init.d/mysql start' と手で入力して起動するかを選べます。" + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +msgid "New password for the MariaDB \"root\" user:" +msgstr "MariaDB の \"root\" ユーザに対する新しいパスワード:" + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +msgid "" +"While not mandatory, it is highly recommended that you set a password for " +"the MariaDB administrative \"root\" user." +msgstr "" +"強制ではありませんが、MariaDB を管理する \"root\" ユーザのパスワードを設定す" +"ることを強くお勧めします。" + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +msgid "If this field is left blank, the password will not be changed." +msgstr "この値を空のままにしておいた場合は、パスワードは変更されません。" + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:7001 +msgid "Repeat password for the MariaDB \"root\" user:" +msgstr "MariaDB の \"root\" ユーザに対する新しいパスワード:" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "Unable to set password for the MariaDB \"root\" user" +msgstr "MariaDB の \"root\" ユーザのパスワードを設定できません" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "" +"An error occurred while setting the password for the MariaDB administrative " +"user. This may have happened because the account already has a password, or " +"because of a communication problem with the MariaDB server." +msgstr "" +"MariaDB の管理者ユーザに対してパスワードを設定しようとした際、エラーが発生し" +"ました。これは既に管理者ユーザにパスワードが設定されていたか、MariaDB サーバ" +"との接続に問題があったためだと思われます。" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "You should check the account's password after the package installation." +msgstr "" +"パッケージのインストール後、アカウントのパスワードを確認する必要があります。" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +#, fuzzy +#| msgid "" +#| "Please read the /usr/share/doc/mariadb-server-5.5/README.Debian file for " +#| "more information." +msgid "" +"Please read the /usr/share/doc/mariadb-server-5.3/README.Debian file for " +"more information." +msgstr "" +"詳細は /usr/share/doc/mariadb-server-5.5/README.Debian を参照してください。" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:9001 +msgid "Password input error" +msgstr "パスワード入力エラー" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:9001 +msgid "The two passwords you entered were not the same. Please try again." +msgstr "入力された二つのパスワードが一致しません。再入力してください。" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:10001 +msgid "NDB Cluster seems to be in use" +msgstr "NDB クラスタが利用されているようです" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:10001 +msgid "" +"MySQL-5.1 no longer provides NDB Cluster support. Please migrate to the new " +"mysql-cluster package and remove all lines starting with \"ndb\" from all " +"config files below /etc/mysql/." +msgstr "" +"MySQL-5.1 では NDB クラスタのサポートを提供しなくなっています。新たな mysql-" +"cluster パッケージに移行して、/etc/mysql 以下の設定ファイルすべてから「ndb」" +"で始まる行を削除してください。" diff --git a/debian/po/nb.po b/debian/po/nb.po new file mode 100644 index 00000000000..9f5b169a534 --- /dev/null +++ b/debian/po/nb.po @@ -0,0 +1,299 @@ +# translation of mysql_nb.po to Norwegian Bokmål +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Bjørn Steensrud , 2007. +msgid "" +msgstr "" +"Project-Id-Version: mysql_nb\n" +"Report-Msgid-Bugs-To: mariadb-5.5@packages.debian.org\n" +"POT-Creation-Date: 2012-01-12 13:08+0100\n" +"PO-Revision-Date: 2007-02-18 12:13+0100\n" +"Last-Translator: Bjørn Steensrud \n" +"Language-Team: Norwegian Bokmål \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: KBabel 1.11.2\n" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +#, fuzzy +#| msgid "Do you really want to downgrade?" +msgid "Really proceed with downgrade?" +msgstr "Er du sikker på at du vil nedgradere?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "A file named /var/lib/mysql/debian-*.flag exists on this system." +msgstr "" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +#, fuzzy +#| msgid "" +#| "WARNING: The file /var/lib/mysql/debian-*.flag exists. This indicates " +#| "that a mysql-server package with a higher version has been installed " +#| "before. It can not be guaranteed that this version can use its data." +msgid "" +"Such a file is an indication that a mariadb-server package with a higher " +"version has been installed previously." +msgstr "" +"ADVARSEL: Fila /var/lib/mysql/debian-*.flag finnes. Dette viser at en " +"mariadb-server-pakke med et høyere versjonsnummer har vært installert før. " +"Det kan ikke garanteres at denne versjonen kan bruke data fra den høyere " +"versjonen." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "" +"There is no guarantee that the version you're currently installing will be " +"able to use the current databases." +msgstr "" + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +#, fuzzy +#| msgid "Important note for NIS/YP users!" +msgid "Important note for NIS/YP users" +msgstr "Viktig merknad for NIS/YP-brukere!" + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "" +"Using MariaDB under NIS/YP requires a mysql user account to be added on the " +"local system with:" +msgstr "" + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "" +"You should also check the permissions and ownership of the /var/lib/mysql " +"directory:" +msgstr "" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "Remove all MariaDB databases?" +msgstr "" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "" +"The /var/lib/mysql directory which contains the MariaDB databases is about " +"to be removed." +msgstr "" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +#, fuzzy +#| msgid "" +#| "The script is about to remove the data directory /var/lib/mysql. If it is " +#| "planned to just install a higher MySQL version or if a different mysql-" +#| "server package is already using it, the data should be kept." +msgid "" +"If you're removing the MariaDB package in order to later install a more " +"recent version or if a different mariadb-server package is already using it, " +"the data should be kept." +msgstr "" +"Dette skriptet skal til å fjerne data-mappa /var/lib/mysql. Denne mappa bør " +"beholdes hvis det bare skal installeres en høyere MariaDB-versjon, eller " +"hvis en annen mariadb-server-pakke allerede bruker den." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:5001 +#, fuzzy +#| msgid "Should MySQL start on boot?" +msgid "Start the MariaDB server on boot?" +msgstr "Skal MariaDB startes ved maskinoppstart?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:5001 +#, fuzzy +#| msgid "" +#| "The MySQL can start automatically on boot time or only if you manually " +#| "type '/etc/init.d/mysql start'." +msgid "" +"The MariaDB server can be launched automatically at boot time or manually " +"with the '/etc/init.d/mysql start' command." +msgstr "" +"MariaDB kan startes automatisk når maskinen starter, eller bare hvis du " +"skriver «/etc/init.d/mysql start»." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +#, fuzzy +#| msgid "New password for MySQL \"root\" user:" +msgid "New password for the MariaDB \"root\" user:" +msgstr "Nytt passord for MariaDBs «root»-bruker:" + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +#, fuzzy +#| msgid "" +#| "It is highly recommended that you set a password for the MySQL " +#| "administrative \"root\" user." +msgid "" +"While not mandatory, it is highly recommended that you set a password for " +"the MariaDB administrative \"root\" user." +msgstr "" +"Det anbefales sterkt at du oppgir et passord for den administrative «root»-" +"brukeren i MariaDB." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +msgid "If this field is left blank, the password will not be changed." +msgstr "" + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:7001 +#, fuzzy +#| msgid "New password for MySQL \"root\" user:" +msgid "Repeat password for the MariaDB \"root\" user:" +msgstr "Nytt passord for MariaDBs «root»-bruker:" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +#, fuzzy +#| msgid "Unable to set password for MySQL \"root\" user" +msgid "Unable to set password for the MariaDB \"root\" user" +msgstr "Klarer ikke angi passord for MariaDBs «root»-bruker" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +#, fuzzy +#| msgid "" +#| "It seems an error occurred while setting the password for the MySQL " +#| "administrative user. This may have happened because the user already has " +#| "a password, or because there was a problem communicating with the MySQL " +#| "server." +msgid "" +"An error occurred while setting the password for the MariaDB administrative " +"user. This may have happened because the account already has a password, or " +"because of a communication problem with the MariaDB server." +msgstr "" +"Det ser ut til at det oppsto en feil mens det ble satt et passord for " +"MariaDBs administrative bruker. Dette kan være fordi brukeren allerede har " +"et passord, eller fordi det var et kommunikasjonsproblem med MariaDB-" +"tjeneren." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "You should check the account's password after the package installation." +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "" +"Please read the /usr/share/doc/mariadb-server-5.3/README.Debian file for " +"more information." +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:9001 +msgid "Password input error" +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:9001 +msgid "The two passwords you entered were not the same. Please try again." +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:10001 +msgid "NDB Cluster seems to be in use" +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:10001 +msgid "" +"MySQL-5.1 no longer provides NDB Cluster support. Please migrate to the new " +"mysql-cluster package and remove all lines starting with \"ndb\" from all " +"config files below /etc/mysql/." +msgstr "" + +#~ msgid "" +#~ "Support MySQL connections from hosts running Debian \"sarge\" or older?" +#~ msgstr "" +#~ "Skal MySQL-tilkoblinger støttes fra vertsmaskiner som kjører Debian " +#~ "«sarge» eller eldre?" + +#, fuzzy +#~| msgid "" +#~| "The way passwords were stored was not very secure. This has been " +#~| "improved with the drawback that clients (e.g. PHP) from hosts running " +#~| "Debian 3.1 Sarge will not be able to connect to account which are new or " +#~| "whose password have been changed. See /usr/share/doc/mysql-server-5.1/" +#~| "README.Debian." +#~ msgid "" +#~ "In old versions of MySQL clients on Debian, passwords were not stored " +#~ "securely. This has been improved since then, however clients (such as " +#~ "PHP) from hosts running Debian 3.1 Sarge will not be able to connect to " +#~ "recent accounts or accounts whose password have been changed." +#~ msgstr "" +#~ "Passord ble tidligere lagret på en lite sikker måte. Dette er nå " +#~ "forbedret, med den ulempen at klienter (f.eks. PHP) fra verter som kjører " +#~ "Debian 3.1 Sarge ikke vil kunne koble til en konto som er ny eller har " +#~ "fått endret passordet. Se /usr/share/doc/mysql-server-5.1/README.Debian." + +#~ msgid "" +#~ "To use mysql you must install an equivalent user and group to the " +#~ "following and ensure yourself that /var/lib/mysql has the right " +#~ "permissions (the uid/gid may be different)." +#~ msgstr "" +#~ "For å bruke MySQL må du installere en bruker og gruppe tilsvarende den " +#~ "nedenfor og se til at /var/lib/mysql har riktige rettigheter (uid/gid kan " +#~ "være forskjellig)." + +#~ msgid "" +#~ "/etc/passwd: mysql:x:100:101:MySQL Server:/var/lib/mysql:/bin/false" +#~ msgstr "" +#~ "/etc/passwd: mysql:x:100:101:MySQL Server:/var/lib/mysql:/bin/false" + +#~ msgid "/etc/group: mysql:x:101:" +#~ msgstr "/etc/group: mysql:x:101:" + +#~ msgid "/var/lib/mysql: drwxr-xr-x mysql mysql" +#~ msgstr "/var/lib/mysql: drwxr-xr-x mysql mysql" + +#~ msgid "Remove the databases used by all MySQL versions?" +#~ msgstr "Skal databasene brukt av alle MySQL-versjoner fjernes?" + +#~ msgid "" +#~ "If you do not provide a password no changes will be made to the account." +#~ msgstr "" +#~ "Hvis du ikke oppgir et passord blir det ikke gjort noen endringer med " +#~ "kontoen." + +#~ msgid "" +#~ "When installation finishes, you should verify that the account is " +#~ "properly protected with a password (see README.Debian for more " +#~ "information)." +#~ msgstr "" +#~ "Når installasjonen er ferdig bør det sjekkes at kontoen er ordentlig " +#~ "beskyttet med et passord (mer informasjon finnes i README.Debian)." diff --git a/debian/po/nl.po b/debian/po/nl.po new file mode 100644 index 00000000000..758ca85cabd --- /dev/null +++ b/debian/po/nl.po @@ -0,0 +1,302 @@ +# Dutch mysql-dfsg-5.1 po-debconf translation, +# Copyright (C) 2006 THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the mysql-dfsg-5.1 package. +# Vincent Zweije , 2006. +# +msgid "" +msgstr "" +"Project-Id-Version: mysql-dfsg-5.1 5.0.30-1\n" +"Report-Msgid-Bugs-To: mariadb-5.5@packages.debian.org\n" +"POT-Creation-Date: 2012-01-12 13:08+0100\n" +"PO-Revision-Date: 2006-02-19 10:20+0100\n" +"Last-Translator: Thijs Kinkhorst \n" +"Language-Team: Debian-Dutch \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +#, fuzzy +#| msgid "Do you really want to downgrade?" +msgid "Really proceed with downgrade?" +msgstr "Wilt u echt een oude versie herstellen?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "A file named /var/lib/mysql/debian-*.flag exists on this system." +msgstr "" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +#, fuzzy +#| msgid "" +#| "WARNING: The file /var/lib/mysql/debian-*.flag exists. This indicates " +#| "that a mysql-server package with a higher version has been installed " +#| "before. It can not be guaranteed that this version can use its data." +msgid "" +"Such a file is an indication that a mariadb-server package with a higher " +"version has been installed previously." +msgstr "" +"Waarschuwing: waarschijnlijk is een hogere versie van het mariadb-server " +"pakket geïnstalleerd geweest (het bestand /var/lib/mysql/debian-*.flag " +"bestaat). Er is geen garantie dat de gegevensbestanden, bewerkt met die " +"hogere versie, kunnen worden gebruikt met de versie van mysql die u nu " +"installeert." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "" +"There is no guarantee that the version you're currently installing will be " +"able to use the current databases." +msgstr "" + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +#, fuzzy +#| msgid "Important note for NIS/YP users!" +msgid "Important note for NIS/YP users" +msgstr "Belangrijke opmerking voor gebruikers van NIS/YP!" + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "" +"Using MariaDB under NIS/YP requires a mysql user account to be added on the " +"local system with:" +msgstr "" + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "" +"You should also check the permissions and ownership of the /var/lib/mysql " +"directory:" +msgstr "" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "Remove all MariaDB databases?" +msgstr "" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "" +"The /var/lib/mysql directory which contains the MariaDB databases is about " +"to be removed." +msgstr "" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +#, fuzzy +#| msgid "" +#| "The script is about to remove the data directory /var/lib/mysql. If it is " +#| "planned to just install a higher MySQL version or if a different mysql-" +#| "server package is already using it, the data should be kept." +msgid "" +"If you're removing the MariaDB package in order to later install a more " +"recent version or if a different mariadb-server package is already using it, " +"the data should be kept." +msgstr "" +"Het script staat op het punt de datamap /var/lib/mysql te verwijderen. Als " +"het plan alleen maar is om een hogere MariaDB versie te installeren, of als " +"een ander mariadb-serverpakket de datamap al gebruikt, dan zou de data " +"moeten worden behouden." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:5001 +#, fuzzy +#| msgid "Should MySQL start on boot?" +msgid "Start the MariaDB server on boot?" +msgstr "Moet MariaDB starten als de computer start?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:5001 +#, fuzzy +#| msgid "" +#| "The MySQL can start automatically on boot time or only if you manually " +#| "type '/etc/init.d/mysql start'." +msgid "" +"The MariaDB server can be launched automatically at boot time or manually " +"with the '/etc/init.d/mysql start' command." +msgstr "" +"MariaDB kan automatisch starten bij het starten van de computer, of slechts " +"wanneer u '/etc/init.d/mysql start' handmatig uitvoert." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +#, fuzzy +#| msgid "New password for MySQL \"root\" user:" +msgid "New password for the MariaDB \"root\" user:" +msgstr "Nieuw wachtwoord voor de MariaDB \"root\"-gebruiker:" + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +#, fuzzy +#| msgid "" +#| "It is highly recommended that you set a password for the MySQL " +#| "administrative \"root\" user." +msgid "" +"While not mandatory, it is highly recommended that you set a password for " +"the MariaDB administrative \"root\" user." +msgstr "" +"Het wordt sterk aangeraden een wachtwoord in te stellen voor de " +"administratieve MariaDB \"root\"-gebruiker." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +msgid "If this field is left blank, the password will not be changed." +msgstr "" + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:7001 +#, fuzzy +#| msgid "New password for MySQL \"root\" user:" +msgid "Repeat password for the MariaDB \"root\" user:" +msgstr "Nieuw wachtwoord voor de MariaDB \"root\"-gebruiker:" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +#, fuzzy +#| msgid "Unable to set password for MySQL \"root\" user" +msgid "Unable to set password for the MariaDB \"root\" user" +msgstr "Kan het wachtwoord voor de MariaDB \"root\"-gebruiker niet instellen" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +#, fuzzy +#| msgid "" +#| "It seems an error occurred while setting the password for the MySQL " +#| "administrative user. This may have happened because the user already has " +#| "a password, or because there was a problem communicating with the MySQL " +#| "server." +msgid "" +"An error occurred while setting the password for the MariaDB administrative " +"user. This may have happened because the account already has a password, or " +"because of a communication problem with the MariaDB server." +msgstr "" +"Er lijkt een fout te zijn opgetreden bij het instellen van het wachtwoord " +"van de MariaDB administratieve gebruiker. Dat kan komen doordat de gebruiker " +"al een wachtwoord heeft, of omdat er een probleem was bij het communiceren " +"met de MariaDB server." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "You should check the account's password after the package installation." +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "" +"Please read the /usr/share/doc/mariadb-server-5.3/README.Debian file for " +"more information." +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:9001 +msgid "Password input error" +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:9001 +msgid "The two passwords you entered were not the same. Please try again." +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:10001 +msgid "NDB Cluster seems to be in use" +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:10001 +msgid "" +"MySQL-5.1 no longer provides NDB Cluster support. Please migrate to the new " +"mysql-cluster package and remove all lines starting with \"ndb\" from all " +"config files below /etc/mysql/." +msgstr "" + +#~ msgid "" +#~ "Support MySQL connections from hosts running Debian \"sarge\" or older?" +#~ msgstr "" +#~ "Moet u MySQL-verbindingen accepteren van computers die Debian \"sarge\" " +#~ "of ouder draaien?" + +#, fuzzy +#~| msgid "" +#~| "The way passwords were stored was not very secure. This has been " +#~| "improved with the drawback that clients (e.g. PHP) from hosts running " +#~| "Debian 3.1 Sarge will not be able to connect to account which are new or " +#~| "whose password have been changed. See /usr/share/doc/mysql-server-5.1/" +#~| "README.Debian." +#~ msgid "" +#~ "In old versions of MySQL clients on Debian, passwords were not stored " +#~ "securely. This has been improved since then, however clients (such as " +#~ "PHP) from hosts running Debian 3.1 Sarge will not be able to connect to " +#~ "recent accounts or accounts whose password have been changed." +#~ msgstr "" +#~ "De wijze waarop wachtwoorden werden bewaard was niet erg veilig. Dit is " +#~ "verbeterd, maar helaas zullen programma's van computers die Debian 3.1 " +#~ "Sarge draaien, geen verbinding meer kunnen maken met accounts die nieuw " +#~ "zijn, of waarvan het wachtwoord is gewijzigd. Zie /usr/share/doc/mysql-" +#~ "server-5.1/README.Debian." + +#~ msgid "" +#~ "To use mysql you must install an equivalent user and group to the " +#~ "following and ensure yourself that /var/lib/mysql has the right " +#~ "permissions (the uid/gid may be different)." +#~ msgstr "" +#~ "Om mysql te gebruiken dient u een gebruiker en groep aan te maken, " +#~ "gelijkwaardig aan onderstaand voorbeeld, en u dient ervoor te zorgen dat /" +#~ "var/lib/mysql de bijbehorende toegangsrechten heeft (uid en gid mogen " +#~ "anders zijn)." + +#~ msgid "" +#~ "/etc/passwd: mysql:x:100:101:MySQL Server:/var/lib/mysql:/bin/false" +#~ msgstr "" +#~ "/etc/passwd: mysql:x:100:101:MySQL Server:/var/lib/mysql:/bin/false" + +#~ msgid "/etc/group: mysql:x:101:" +#~ msgstr "/etc/group: mysql:x:101:" + +#~ msgid "/var/lib/mysql: drwxr-xr-x mysql mysql" +#~ msgstr "/var/lib/mysql: drwxr-xr-x mysql mysql" + +#~ msgid "Remove the databases used by all MySQL versions?" +#~ msgstr "Databases verwijderen die door alle MySQL versies worden gebruikt?" + +#~ msgid "" +#~ "If you do not provide a password no changes will be made to the account." +#~ msgstr "" +#~ "Indien u geen wachtwoord opgeeft zal het account niet worden gewijzigd." + +#~ msgid "" +#~ "When installation finishes, you should verify that the account is " +#~ "properly protected with a password (see README.Debian for more " +#~ "information)." +#~ msgstr "" +#~ "Wanneer de installatie klaar is, dient u te verifiëren dat het account " +#~ "netjes beschermd is met een wachtwoord (zie README.Debian voor meer " +#~ "informatie)." diff --git a/debian/po/pt.po b/debian/po/pt.po new file mode 100644 index 00000000000..9ab2f36bdf1 --- /dev/null +++ b/debian/po/pt.po @@ -0,0 +1,308 @@ +# Portuguese translation for mysql-dfsg-5.1's debconf messages +# Copyright (C) 2006 Miguel Figueiredo +# This file is distributed under the same license as the mysql-dfsg-5.1 package. +# Miguel Figueiredo +# +msgid "" +msgstr "" +"Project-Id-Version: mysql-dfsg-5.1\n" +"Report-Msgid-Bugs-To: mariadb-5.5@packages.debian.org\n" +"POT-Creation-Date: 2012-01-12 13:08+0100\n" +"PO-Revision-Date: 2007-05-05 21:01+0100\n" +"Last-Translator: Miguel Figueiredo \n" +"Language-Team: Portuguese \n" +"Language: pt\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "Really proceed with downgrade?" +msgstr "Deseja mesmo fazer downgrade?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "A file named /var/lib/mysql/debian-*.flag exists on this system." +msgstr "Existe um ficheiro chamado /var/lib/mysql/debian-*.flag neste sistema." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +#, fuzzy +#| msgid "" +#| "Such file is an indication that a mariadb-server package with a higher " +#| "version has been installed earlier." +msgid "" +"Such a file is an indication that a mariadb-server package with a higher " +"version has been installed previously." +msgstr "" +"Tal ficheiro significa que anteriormente foi instalado um pacote mariadb-" +"server com um número de versão superior." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "" +"There is no guarantee that the version you're currently installing will be " +"able to use the current databases." +msgstr "" +"Não existe nenhuma garantia que a versão que está actualmente a instalar " +"seja capaz de utilizar as bases de dados actuais." + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "Important note for NIS/YP users" +msgstr "Nota importante para utilizadores de NIS/YP" + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "" +"Using MariaDB under NIS/YP requires a mysql user account to be added on the " +"local system with:" +msgstr "" + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +#, fuzzy +#| msgid "" +#| "You should also check the permissions and the owner of the /var/lib/mysql " +#| "directory:" +msgid "" +"You should also check the permissions and ownership of the /var/lib/mysql " +"directory:" +msgstr "" +"Deve também verificar as permissões e o dono do directório /var/lib/mysql :" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "Remove all MariaDB databases?" +msgstr "Remover todas as bases de dados MariaDB?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "" +"The /var/lib/mysql directory which contains the MariaDB databases is about " +"to be removed." +msgstr "" +"O directório /var/lib/mysql que contém as bases de dados MariaDB está " +"prestes a ser removido." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "" +"If you're removing the MariaDB package in order to later install a more " +"recent version or if a different mariadb-server package is already using it, " +"the data should be kept." +msgstr "" +"Se está a remover o pacote MariaDB de modo a posteriormente instalar uma " +"versão mais recente ou se um pacote mariadb-server já está os está a " +"utilizar, os dados devem ser mantidos." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:5001 +msgid "Start the MariaDB server on boot?" +msgstr "Iniciar o servidor MariaDB no arranque?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:5001 +msgid "" +"The MariaDB server can be launched automatically at boot time or manually " +"with the '/etc/init.d/mysql start' command." +msgstr "" +"O MariaDB pode ser automaticamente lançado no arranque ou manualmente " +"através do comando '/etc/init.d/mysql start'." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +msgid "New password for the MariaDB \"root\" user:" +msgstr "Nova palavra-passe para o utilizador \"root\" do MariaDB:" + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +msgid "" +"While not mandatory, it is highly recommended that you set a password for " +"the MariaDB administrative \"root\" user." +msgstr "" +"Embora não seja mandatório, É fortemente recomendado que defina uma palavra-" +"passe para o utilizador administrativo \"root\" do MariaDB." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +#, fuzzy +#| msgid "If that field is left blank, the password will not be changed." +msgid "If this field is left blank, the password will not be changed." +msgstr "" +"Se esse campo for deixado em branco, a palavra-passe não irá ser alterada." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:7001 +#, fuzzy +#| msgid "New password for the MySQL \"root\" user:" +msgid "Repeat password for the MariaDB \"root\" user:" +msgstr "Nova palavra-passe para o utilizador \"root\" do MariaDB:" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "Unable to set password for the MariaDB \"root\" user" +msgstr "" +"Não foi possível definir a palavra-passe para o utilizador \"root\" do " +"MariaDB" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "" +"An error occurred while setting the password for the MariaDB administrative " +"user. This may have happened because the account already has a password, or " +"because of a communication problem with the MariaDB server." +msgstr "" +"Ocorreu um erro enquanto era definida a palavra-passe para o utilizador " +"administrativo do MariaDB. Isto pode ter acontecido porque a cona já tem uma " +"palavra-passe, ou porque ocorreu um problema ao comunicação com o servidor " +"MariaDB." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +#, fuzzy +#| msgid "" +#| "You should check the account's password after tha package installation." +msgid "You should check the account's password after the package installation." +msgstr "" +"Você deve verificar a palavra-passe da conta após a instalação do pacote." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +#, fuzzy +#| msgid "" +#| "Please read the /usr/share/doc/mysql-server-5.1/README.Debian file for " +#| "more information." +msgid "" +"Please read the /usr/share/doc/mariadb-server-5.3/README.Debian file for " +"more information." +msgstr "" +"Para mais informação por favor leia o ficheiro /usr/share/doc/mariadb-" +"server-5.5/README.Debian." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:9001 +msgid "Password input error" +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:9001 +msgid "The two passwords you entered were not the same. Please try again." +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:10001 +msgid "NDB Cluster seems to be in use" +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:10001 +msgid "" +"MySQL-5.1 no longer provides NDB Cluster support. Please migrate to the new " +"mysql-cluster package and remove all lines starting with \"ndb\" from all " +"config files below /etc/mysql/." +msgstr "" + +#~ msgid "" +#~ "To use MariaDB, the following entries for users and groups should be " +#~ "added to the system:" +#~ msgstr "" +#~ "Para utilizar o MariaDB, têm de ser acrescentadas as seguintes entradas " +#~ "para os utilizadores e grupos:" + +#~ msgid "Cannot upgrade if ISAM tables are present!" +#~ msgstr "Não é possível actualizar se estiverem presentes tabelas ISAM!" + +#~ msgid "" +#~ "Recent versions of MySQL can no longer use the old ISAM table format and " +#~ "it is necessary to convert your tables to e.g. MyISAM before upgrading by " +#~ "using \"mysql_convert_table_format\" or \"ALTER TABLE x ENGINE=MyISAM\". " +#~ "The installation of mysql-server-5.1 will now abort. In case your old " +#~ "mysql-server-4.1 gets removed nevertheless just reinstall it to convert " +#~ "those tables." +#~ msgstr "" +#~ "As versões recentes de MySQL já não podem utilizar o antigo formato de " +#~ "tabelas ISAM e é por isso necessário converter as suas tabelas pra e.g. " +#~ "MyISAM antes da actualização, utilizando \"mysql_convert_table_format\" " +#~ "ou \"ALTER TABLE x ENGINE=MyISAM\". A instalação de mysql-server-5.1 irá " +#~ "agora ser cancelada. Se o seu antigo mysql-server-4.1 for removido apenas " +#~ "reinstale para converter essas tabelas." + +#~ msgid "" +#~ "Support MySQL connections from hosts running Debian \"sarge\" or older?" +#~ msgstr "" +#~ "Suportar ligações MySQL de máquinas que corram Debian \"sarge\" ou mais " +#~ "antigos?" + +#~ msgid "" +#~ "In old versions of MySQL clients on Debian, passwords were not stored " +#~ "securely. This has been improved since then, however clients (such as " +#~ "PHP) from hosts running Debian 3.1 Sarge will not be able to connect to " +#~ "recent accounts or accounts whose password have been changed." +#~ msgstr "" +#~ "Nas versões antigas de clientes de MySQL em Debian, as palavras-passe não " +#~ "eram guardadas de forma segura. Isto foi melhorado desde aí, no entanto " +#~ "os clientes (como o PHP) de máquinas que corram Debian 3.1 Sarge não irão " +#~ "conseguir ligar-se a contas novas ou cuja palavra-passe foi alterada." + +#~ msgid "" +#~ "To use mysql you must install an equivalent user and group to the " +#~ "following and ensure yourself that /var/lib/mysql has the right " +#~ "permissions (the uid/gid may be different)." +#~ msgstr "" +#~ "Para utilizar mysql e instalar um utilizador e grupo equivalentes para o " +#~ "seguinte e assegurar-se que /var/lib/mysql têm as permissões correctas (o " +#~ "uid/gid podem ser diferentes)." + +#~ msgid "" +#~ "/etc/passwd: mysql:x:100:101:MySQL Server:/var/lib/mysql:/bin/false" +#~ msgstr "" +#~ "/etc/passwd: mysql:x:100:101:MySQL Server:/var/lib/mysql:/bin/false" + +#~ msgid "/etc/group: mysql:x:101:" +#~ msgstr "/etc/group: mysql:x:101:" + +#~ msgid "/var/lib/mysql: drwxr-xr-x mysql mysql" +#~ msgstr "/var/lib/mysql: drwxr-xr-x mysql mysql" + +#~ msgid "Remove the databases used by all MySQL versions?" +#~ msgstr "Remover as bases de dados utilizadas por todas as versões de MySQL?" + +#~ msgid "" +#~ "If you do not provide a password no changes will be made to the account." +#~ msgstr "" +#~ "Se não disponibilizar uma password não serão feitas alterações nesta " +#~ "conta." + +#~ msgid "" +#~ "When installation finishes, you should verify that the account is " +#~ "properly protected with a password (see README.Debian for more " +#~ "information)." +#~ msgstr "" +#~ "Quando terminar a instalação, deve verificar se a conta está devidamente " +#~ "protegida com uma password (para mais informações veja README.Debian)." diff --git a/debian/po/pt_BR.po b/debian/po/pt_BR.po new file mode 100644 index 00000000000..8a538dfb8e4 --- /dev/null +++ b/debian/po/pt_BR.po @@ -0,0 +1,443 @@ +# Brazilian Portuguese (pt_BR) debconf template translation for +# Debian's mysql-dfsg source package. +# Debian-BR Project +# André Luís Lopes, , 2004 +# André Luís Lopes, , 2006 +# André Luís Lopes, , 2007 +# +msgid "" +msgstr "" +"Project-Id-Version: mysql-dfsg-5.1\n" +"Report-Msgid-Bugs-To: mariadb-5.5@packages.debian.org\n" +"POT-Creation-Date: 2012-01-12 13:08+0100\n" +"PO-Revision-Date: 2007-04-21 15:59-0300\n" +"Last-Translator: André Luís Lopes \n" +"Language-Team: Debian-BR Project \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"pt_BR utf-8\n" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "Really proceed with downgrade?" +msgstr "Realmente proceder com o rebaixamento de versão?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "A file named /var/lib/mysql/debian-*.flag exists on this system." +msgstr "Um arquivo de nome /var/lib/mysql/debian-*.flag existe no sistema." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +#, fuzzy +#| msgid "" +#| "Such file is an indication that a mariadb-server package with a higher " +#| "version has been installed earlier." +msgid "" +"Such a file is an indication that a mariadb-server package with a higher " +"version has been installed previously." +msgstr "" +"A presença de um arquivo como este é uma indicação de que um pacote mariadb-" +"server com um número de versão mais alto já foi instalado anteriormente." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "" +"There is no guarantee that the version you're currently installing will be " +"able to use the current databases." +msgstr "" +"Não há garantias de que a versão que você está instalando no momento " +"conseguirá utilizar as bases de dados existentes." + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "Important note for NIS/YP users" +msgstr "Aviso importante para usuários NIS/YP" + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "" +"Using MariaDB under NIS/YP requires a mysql user account to be added on the " +"local system with:" +msgstr "" + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +#, fuzzy +#| msgid "" +#| "You should also check the permissions and the owner of the /var/lib/mysql " +#| "directory:" +msgid "" +"You should also check the permissions and ownership of the /var/lib/mysql " +"directory:" +msgstr "" +"Você deverá também checar as permissões e o dono do diretório /var/lib/mysql:" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "Remove all MariaDB databases?" +msgstr "Remover todas as bases de dados do MariaDB?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "" +"The /var/lib/mysql directory which contains the MariaDB databases is about " +"to be removed." +msgstr "" +"O diretório /var/lib/mysql, o qual contém as bases de dados do MariaDB, está " +"prestes a ser removido." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "" +"If you're removing the MariaDB package in order to later install a more " +"recent version or if a different mariadb-server package is already using it, " +"the data should be kept." +msgstr "" +"Caso você esteja removendo o pacote MariaDB para posteriormente instalar uma " +"versão mais recente ou, caso uma versão diferente do pacote mariadb-server " +"esteja sendo utilizada, os dados deverão ser mantidos." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:5001 +msgid "Start the MariaDB server on boot?" +msgstr "Iniciar o servidor MariaDB junto a inicialização da máquina?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:5001 +msgid "" +"The MariaDB server can be launched automatically at boot time or manually " +"with the '/etc/init.d/mysql start' command." +msgstr "" +"O servidor MariaDB pode ser iniciado automaticamente junto a inicialização " +"da máquina ou manualmente com o comando '/etc/init.d/mysql start'." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +msgid "New password for the MariaDB \"root\" user:" +msgstr "Nova senha para o usuário \"root\" do MariaDB:" + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +msgid "" +"While not mandatory, it is highly recommended that you set a password for " +"the MariaDB administrative \"root\" user." +msgstr "" +"Apesar de não ser mandatório, é altamente recomendado que você defina uma " +"senha para o usuário administrativo \"root\" do MariaDB." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +#, fuzzy +#| msgid "If that field is left blank, the password will not be changed." +msgid "If this field is left blank, the password will not be changed." +msgstr "Caso este campo seja deixado em branco, a senha não sera mudada." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:7001 +#, fuzzy +#| msgid "New password for the MySQL \"root\" user:" +msgid "Repeat password for the MariaDB \"root\" user:" +msgstr "Nova senha para o usuário \"root\" do MariaDB:" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "Unable to set password for the MariaDB \"root\" user" +msgstr "Impossível definir senha para o usuário \"root\" do MariaDB" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "" +"An error occurred while setting the password for the MariaDB administrative " +"user. This may have happened because the account already has a password, or " +"because of a communication problem with the MariaDB server." +msgstr "" +"Um erro ocorreu durante a definição da senha para o usuário administrativo " +"do MariaDB. Isso pode ter acontecido devido a esse usuário já possuir uma " +"senha definida ou devido a ocorrência de um problema de comunicação com o " +"servidor MariaDB." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +#, fuzzy +#| msgid "" +#| "You should check the account's password after tha package installation." +msgid "You should check the account's password after the package installation." +msgstr "Você deverá checar a senha dessa conta após a instalação deste pacote." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +#, fuzzy +#| msgid "" +#| "Please read the /usr/share/doc/mysql-server-5.1/README.Debian file for " +#| "more information." +msgid "" +"Please read the /usr/share/doc/mariadb-server-5.3/README.Debian file for " +"more information." +msgstr "" +"Por favor, leia o arquivo /usr/share/doc/mariadb-server-5.5/README.Debian " +"para maiores informações." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:9001 +msgid "Password input error" +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:9001 +msgid "The two passwords you entered were not the same. Please try again." +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:10001 +msgid "NDB Cluster seems to be in use" +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:10001 +msgid "" +"MySQL-5.1 no longer provides NDB Cluster support. Please migrate to the new " +"mysql-cluster package and remove all lines starting with \"ndb\" from all " +"config files below /etc/mysql/." +msgstr "" + +#~ msgid "" +#~ "To use MariaDB, the following entries for users and groups should be " +#~ "added to the system:" +#~ msgstr "" +#~ "Para utilizar o MariaDB, as seguintes entradas para usuários e grupos " +#~ "devem ser adicionadas ao sistema:" + +#~ msgid "" +#~ "Support MySQL connections from hosts running Debian \"sarge\" or older?" +#~ msgstr "" +#~ "Suportar conexões MySQL originadas de hosts executando o Debian \"sarge\" " +#~ "ou mais antigos ?" + +#~ msgid "" +#~ "In old versions of MySQL clients on Debian, passwords were not stored " +#~ "securely. This has been improved since then, however clients (such as " +#~ "PHP) from hosts running Debian 3.1 Sarge will not be able to connect to " +#~ "recent accounts or accounts whose password have been changed." +#~ msgstr "" +#~ "Em versões antigas dos clientes MySQL no Debian, as senhas não eram " +#~ "armazenadas de forma segura. Isto foi corrigido desde então, porém, " +#~ "clientes (como o PHP) em hosts executando o Debian 3.1 Sarge não serão " +#~ "capazes de conectar em contas recentes ou contas as quais as senhas " +#~ "tenham sido modificadas." + +#~ msgid "" +#~ "To use mysql you must install an equivalent user and group to the " +#~ "following and ensure yourself that /var/lib/mysql has the right " +#~ "permissions (the uid/gid may be different)." +#~ msgstr "" +#~ "Para utilizar o MySQL, você deve instalar um usuário e um grupo " +#~ "equivalentes ao usuário e grupo a seguir para se certificar de que o " +#~ "diretório /var/lib/mysql possua as permissões correctas (o uid/gid podem " +#~ "ser diferentes)." + +#~ msgid "" +#~ "/etc/passwd: mysql:x:100:101:MySQL Server:/var/lib/mysql:/bin/false" +#~ msgstr "" +#~ "/etc/passwd: mysql:x:100:101:MySQL Server:/var/lib/mysql:/bin/false" + +#~ msgid "/etc/group: mysql:x:101:" +#~ msgstr "/etc/group: mysql:x:101:" + +#~ msgid "/var/lib/mysql: drwxr-xr-x mysql mysql" +#~ msgstr "/var/lib/mysql: drwxr-xr-x mysql mysql" + +#~ msgid "Remove the databases used by all MySQL versions?" +#~ msgstr "Remover as bases de dados utilizadas por todas as versões do MySQL?" + +#~ msgid "" +#~ "If you do not provide a password no changes will be made to the account." +#~ msgstr "" +#~ "Caso você não forneça uma senha, nenhuma mudança será feita na conta." + +#~ msgid "" +#~ "When installation finishes, you should verify that the account is " +#~ "properly protected with a password (see README.Debian for more " +#~ "information)." +#~ msgstr "" +#~ "Quando a instalação finalizar, você deverá verificar se a conta está " +#~ "apropriadamente protegida com uma senha (consulte o arquivo README.Debian " +#~ "para maiores informações)." + +#~ msgid "internal" +#~ msgstr "interno" + +#~ msgid "Only internally used." +#~ msgstr "Somente utilizado internamente." + +#, fuzzy +#~ msgid "Update Hints" +#~ msgstr "Dicas de atualização" + +#, fuzzy +#~ msgid "" +#~ "Rarely, e.g. on new major versions, the privilege system is improved. To " +#~ "make use of it mysql_fix_privilege_tables must be executed manually. The " +#~ "script is not supposed to give any user more rights that he had before," +#~ msgstr "" +#~ "Raramente, por exemplo, em novas versões maiores, o sistema de " +#~ "privilégios é melhorado. Para fazer uso disso, o script " +#~ "mysql_fix_privilege_tables deve ser executado manualmente. O script não " +#~ "atribuirá a nenhum usuário mais direitos do que os mesmos já possuíam " +#~ "anteriormente." + +#~ msgid "Please also read http://www.mysql.com/doc/en/Upgrade.html" +#~ msgstr "Por favor, leia http://www.mysql.com/doc/en/Upgrade.html" + +#, fuzzy +#~ msgid "Install Hints" +#~ msgstr "Dicas de instalação" + +#, fuzzy +#~ msgid "" +#~ "MySQL will only install if you have a non-numeric hostname that is " +#~ "resolvable via the /etc/hosts file. E.g. if the \"hostname\" command " +#~ "returns \"myhostname\" then there must be a line like \"10.0.0.1 " +#~ "myhostname\"." +#~ msgstr "" +#~ "O MySQL será instalado somente caso você possua um nome de host NÃO " +#~ "NUMÉRICO que possa ser resolvido através do arquivo /etc/hosts, ou seja, " +#~ "caso o comando \"hostname\" retorne \"myhostname\", uma linha como " +#~ "\"10.0.0.1 myhostname\" deverá existir no arquivo /etc/hosts." + +#~ msgid "" +#~ "A new mysql user \"debian-sys-maint\" will be created. This mysql account " +#~ "is used in the start/stop and cron scripts. Don't delete." +#~ msgstr "" +#~ "Um novo usuário MySQL de nome \"debian-sys-maint\" será criado. Essa " +#~ "conta MySQL é utilizada pelos scripts de inicialização/parada e pelos " +#~ "scripts cron. Não remova esse usuário." + +#, fuzzy +#~ msgid "" +#~ "Please remember to set a PASSWORD for the MySQL root user! If you use a /" +#~ "root/.my.cnf, always write the \"user\" and the \"password\" lines in " +#~ "there, never only the password!" +#~ msgstr "" +#~ "Por favor, lembre-se de definir uma SENHA para o usuário root do MySQL ! " +#~ "Caso você utilize um arquivo /root/.my.cnf, sempre inclua as linhas \"user" +#~ "\" e \"password\" nesse arquivo, nunca somente a senha ! Consulte o " +#~ "arquivo /usr/share/doc/mysql-server/README.Debian para mais informações." + +#~ msgid "" +#~ "Should I remove all databases below /var/lib/mysql as you are purging the " +#~ "mysql-server package?" +#~ msgstr "" +#~ "Todas as base de dados sob o diretório /var/lib/mysql devem ser removidas " +#~ "quando você remover o pacote pacote mysql-server ?" + +#~ msgid "" +#~ "Networking is disabled by default for security reasons. You can enable it " +#~ "by commenting out the skip-networking option in /etc/mysql/my.cnf." +#~ msgstr "" +#~ "O suporte ao funcionamento em rede está desativado por padrão por " +#~ "questões de segurança. Você poderá ativá-lo comentando a opção 'skip-" +#~ "networking' no arquivo /etc/mysql/my.cnf." + +#~ msgid "security and update notice" +#~ msgstr "aviso de segurança e actualização" + +#~ msgid "" +#~ "Should I remove everything below /var/lib/mysql when you purge the mysql-" +#~ "server package with the \"dpkg --purge mysql-server\" command (i.e. " +#~ "remove everything including the configuration) somewhen? (default is not)" +#~ msgstr "" +#~ "Devo remover tudo abaixo de /var/lib/mysql quando fizer o purge do pacote " +#~ "mysql-server com o comando \"dpkg --purge mysql-server\" (ou seja, " +#~ "remover tudo incluíndo a configuração)? (o padrão é não remover)" + +#~ msgid "Make MySQL reachable via network?" +#~ msgstr "Fazer com que o MySQL seja acessível via rede?" + +#~ msgid "" +#~ "Should MySQL listen on a network reachable TCP port? This is not " +#~ "necessary for use on a single computer and could be a security problem." +#~ msgstr "" +#~ "O MySQL deve aguardar ligações numa porta TCP acessível via rede? Isto " +#~ "não é necessário para uso num único computador e pode ser um problema de " +#~ "segurança." + +#~ msgid "Enable chroot mode?" +#~ msgstr "Activar o modo chroot?" + +#~ msgid "" +#~ "MySQL is able to jail itself into the /var/lib/mysql_jail directory so " +#~ "that users cannot modify any files outside this directory. This improves " +#~ "resistence against crackers, too, as they are not able to modify system " +#~ "files." +#~ msgstr "" +#~ "O MySQL é capaz de se prender no diretório /var/lib/mysql_jail, assim os " +#~ "utilizadores não poderão modificar ficheiros fora deste directório. Isto " +#~ "aumenta também a resistência contra crackers, pois eles não poderão " +#~ "modificar arquivos de sistema." + +#~ msgid "Please run mysql_fix_privilege_tables !" +#~ msgstr "Por favor execute mysql_fix_privilege_tables !" + +#~ msgid "" +#~ "I will ensure secure permissions of /var/lib/mysql by replacing GIDs " +#~ "other than root and mysql with mysql." +#~ msgstr "" +#~ "Permissões seguras para o diretório /var/lib/mysql serão asseguradas " +#~ "substituíndo GIDs diferentes de root e mysql por mysql." + +#~ msgid "" +#~ "Instructions how to enable SSL support are in /usr/share/doc/mysql-server/" +#~ msgstr "" +#~ "Instruções sobre como activar o suporte de SSL estão disponíveis no " +#~ "directório /usr/share/doc/mysql-server/." + +#, fuzzy +#~ msgid "mysql_fix_privileges_tables should be executed" +#~ msgstr "mysql_fix_privileges_tables será executado" + +#, fuzzy +#~ msgid "" +#~ "The latest MySQL versions have an enhanced, more fine grained, privilege " +#~ "system. To make use of it, some new fields must be added to the tables " +#~ "in the \"mysql\" database. This will not happen automatically." +#~ msgstr "" +#~ "As últimas versões do MySQL possuem um sistema de privilégios melhorado e " +#~ "mais refinado. Para utilizá-lo, alguns novos campos devem ser adicionados " +#~ "as tabelas na base de dados \"mysql\". Isto é feito pelo script " +#~ "mysql_fix_privileges_tables durante esta actualização independente do " +#~ "servidor estar a correr ou não !" + +#~ msgid "" +#~ "This script is not supposed to give any user more rights that he had " +#~ "before, if you encounter such a case, please contact me." +#~ msgstr "" +#~ "Este script não deverá fornecer mais direitos a um utilizador além dos " +#~ "quais ele já possua anteriormente. SE encontrar um caso desses, por favor " +#~ "entre em contacto com o mantainer deste pacote Debian." diff --git a/debian/po/ro.po b/debian/po/ro.po new file mode 100644 index 00000000000..41baba6e6f8 --- /dev/null +++ b/debian/po/ro.po @@ -0,0 +1,320 @@ +# Romanian translation of mysql-dfsg. +# Copyright (C) 2006 THE mysql-dfsg'S COPYRIGHT HOLDER +# This file is distributed under the same license as the mysql-dfsg package. +# +# Stan Ioan-Eugen , 2006. +msgid "" +msgstr "" +"Project-Id-Version: po-debconf://mysql-dfsg\n" +"Report-Msgid-Bugs-To: mariadb-5.5@packages.debian.org\n" +"POT-Creation-Date: 2012-01-12 13:08+0100\n" +"PO-Revision-Date: 2006-12-20 21:27+0200\n" +"Last-Translator: stan ioan-eugen \n" +"Language-Team: romanian \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: KBabel 1.11.4\n" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +#, fuzzy +#| msgid "Do you really want to downgrade?" +msgid "Really proceed with downgrade?" +msgstr "Sunteţi sigur că doriţi să instalaţi o versiune mai veche?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "A file named /var/lib/mysql/debian-*.flag exists on this system." +msgstr "" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +#, fuzzy +#| msgid "" +#| "WARNING: The file /var/lib/mysql/debian-*.flag exists. This indicates " +#| "that a mysql-server package with a higher version has been installed " +#| "before. It can not be guaranteed that this version can use its data." +msgid "" +"Such a file is an indication that a mariadb-server package with a higher " +"version has been installed previously." +msgstr "" +"AVERTISMENT: Fişierul /var/lib/mysql/debian-*.flag există. Acest lucru " +"indică faptul că anterior a fost instalată o versiune nouă a pachetului " +"mariadb-server. Nu se poate garanta că versiunea instalată acum poate folosi " +"datele versiunii instalate anterior." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "" +"There is no guarantee that the version you're currently installing will be " +"able to use the current databases." +msgstr "" + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +#, fuzzy +#| msgid "Important note for NIS/YP users!" +msgid "Important note for NIS/YP users" +msgstr "Notă importantă pentru utilizatorii NIS/YP!" + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "" +"Using MariaDB under NIS/YP requires a mysql user account to be added on the " +"local system with:" +msgstr "" + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "" +"You should also check the permissions and ownership of the /var/lib/mysql " +"directory:" +msgstr "" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "Remove all MariaDB databases?" +msgstr "" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "" +"The /var/lib/mysql directory which contains the MariaDB databases is about " +"to be removed." +msgstr "" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +#, fuzzy +#| msgid "" +#| "The script is about to remove the data directory /var/lib/mysql. If it is " +#| "planned to just install a higher MySQL version or if a different mysql-" +#| "server package is already using it, the data should be kept." +msgid "" +"If you're removing the MariaDB package in order to later install a more " +"recent version or if a different mariadb-server package is already using it, " +"the data should be kept." +msgstr "" +"Scriptul urmează să şteargă directorul de date /var/lib/mysql. Dacă plănuiţi " +"doar să instalaţi o versiune nouă MariaDB sau datele sunt folosite de către " +"un alt pachet mariadb-server, atunci ar trebui păstraţi datele." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:5001 +#, fuzzy +#| msgid "Should MySQL start on boot?" +msgid "Start the MariaDB server on boot?" +msgstr "Doriţi ca MariaDB să pornească la initializarea sistemului?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:5001 +#, fuzzy +#| msgid "" +#| "The MySQL can start automatically on boot time or only if you manually " +#| "type '/etc/init.d/mysql start'." +msgid "" +"The MariaDB server can be launched automatically at boot time or manually " +"with the '/etc/init.d/mysql start' command." +msgstr "" +"MariaDB poate porni automat la iniţializarea sistemului sau doar dacă rulaţi " +"comanda „/etc/init.d/mysql start”." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +#, fuzzy +#| msgid "New password for MySQL \"root\" user:" +msgid "New password for the MariaDB \"root\" user:" +msgstr "Noua parolă pentru utilizatorul „root” al MariaDB:" + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +#, fuzzy +#| msgid "" +#| "It is highly recommended that you set a password for the MySQL " +#| "administrative \"root\" user." +msgid "" +"While not mandatory, it is highly recommended that you set a password for " +"the MariaDB administrative \"root\" user." +msgstr "" +"Este recomandat să stabiliţi o parolă pentru utilizatorul administrativ " +"„root” al MariaDB." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +msgid "If this field is left blank, the password will not be changed." +msgstr "" + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:7001 +#, fuzzy +#| msgid "New password for MySQL \"root\" user:" +msgid "Repeat password for the MariaDB \"root\" user:" +msgstr "Noua parolă pentru utilizatorul „root” al MariaDB:" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +#, fuzzy +#| msgid "Unable to set password for MySQL \"root\" user" +msgid "Unable to set password for the MariaDB \"root\" user" +msgstr "Nu s-a putut stabili parola pentru utilizatorul „root” al MariaDB" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +#, fuzzy +#| msgid "" +#| "It seems an error occurred while setting the password for the MySQL " +#| "administrative user. This may have happened because the user already has " +#| "a password, or because there was a problem communicating with the MySQL " +#| "server." +msgid "" +"An error occurred while setting the password for the MariaDB administrative " +"user. This may have happened because the account already has a password, or " +"because of a communication problem with the MariaDB server." +msgstr "" +"Se pare că a intervenit o eroare în stabilirea parolei pentru utilizatorul " +"administrativ al MariaDB. Acest lucru se poate întâmpla dacă utilizatorul " +"are deja o parolă, sau a existat o problemă în comunicarea cu serverul " +"MariaDB." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "You should check the account's password after the package installation." +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "" +"Please read the /usr/share/doc/mariadb-server-5.3/README.Debian file for " +"more information." +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:9001 +msgid "Password input error" +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:9001 +msgid "The two passwords you entered were not the same. Please try again." +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:10001 +msgid "NDB Cluster seems to be in use" +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:10001 +msgid "" +"MySQL-5.1 no longer provides NDB Cluster support. Please migrate to the new " +"mysql-cluster package and remove all lines starting with \"ndb\" from all " +"config files below /etc/mysql/." +msgstr "" + +#~ msgid "Cannot upgrade if ISAM tables are present!" +#~ msgstr "Nu se poate face actualizarea dacă sunt prezente tabele ISAM!" + +#~ msgid "" +#~ "Recent versions of MySQL can no longer use the old ISAM table format and " +#~ "it is necessary to convert your tables to e.g. MyISAM before upgrading by " +#~ "using \"mysql_convert_table_format\" or \"ALTER TABLE x ENGINE=MyISAM\". " +#~ "The installation of mysql-server-5.1 will now abort. In case your old " +#~ "mysql-server-4.1 gets removed nevertheless just reinstall it to convert " +#~ "those tables." +#~ msgstr "" +#~ "Versiunile recente MySQL nu mai pot folosi vechiul format de tabele ISAM " +#~ "şieste necesar să convertiţi tabelele dumneavoastră de ex. la formatul " +#~ "MyISAM înainte de a face actualizarea folosind comanda " +#~ "„mysql_convert_table_format” sau „ALTER TABLE x ENGINE=MyISAM”. " +#~ "Instalarea mysql-server-5.1 va eşua. În caz că ştergeţiversiunea " +#~ "anterioară mysql-server-4.1 va trebui reinstalată pentru a converti " +#~ "tabelele." + +#~ msgid "" +#~ "Support MySQL connections from hosts running Debian \"sarge\" or older?" +#~ msgstr "" +#~ "Suportaţi conexiuni MySQL de la staţii ce rulează sistemul Debian „sarge” " +#~ "sau mai vechi?" + +#, fuzzy +#~| msgid "" +#~| "The way passwords were stored was not very secure. This has been " +#~| "improved with the drawback that clients (e.g. PHP) from hosts running " +#~| "Debian 3.1 Sarge will not be able to connect to account which are new or " +#~| "whose password have been changed. See /usr/share/doc/mysql-server-5.1/" +#~| "README.Debian." +#~ msgid "" +#~ "In old versions of MySQL clients on Debian, passwords were not stored " +#~ "securely. This has been improved since then, however clients (such as " +#~ "PHP) from hosts running Debian 3.1 Sarge will not be able to connect to " +#~ "recent accounts or accounts whose password have been changed." +#~ msgstr "" +#~ "Modul în care erau păstrate parolele nu era foarte sigur. Acest lucru a " +#~ "fost îmbunătăţitcu dezajantajul că clienţii (de ex. PHP) de pe staţii ce " +#~ "rulează sistemul Debian 3.1 Sargenu se vor putea conecta la conturi noi " +#~ "sau ale căror parole au fost schimbate. Citiţi /usr/share/doc/mysql-" +#~ "server-5.1/README.Debian." + +#~ msgid "" +#~ "To use mysql you must install an equivalent user and group to the " +#~ "following and ensure yourself that /var/lib/mysql has the right " +#~ "permissions (the uid/gid may be different)." +#~ msgstr "" +#~ "Pentru a folosi mysql trebuie să adăugaţi un utilizator şi grup " +#~ "echivalent şi să vă asiguraţi că /var/lib/mysql are permisiunile " +#~ "stabilite corect (uid/gid pot aveavalori diferite)." + +#~ msgid "" +#~ "/etc/passwd: mysql:x:100:101:MySQL Server:/var/lib/mysql:/bin/false" +#~ msgstr "" +#~ "/etc/passwd:\tmysql:x:100:101:MySQL Server:/var/lib/mysql:/bin/false" + +#~ msgid "/etc/group: mysql:x:101:" +#~ msgstr "/etc/group:\tmysql:x:101:" + +#~ msgid "/var/lib/mysql: drwxr-xr-x mysql mysql" +#~ msgstr "/var/lib/mysql:\tdrwxr-xr-x\tmysql\tmysql" + +#~ msgid "Remove the databases used by all MySQL versions?" +#~ msgstr "Doriţi să ştergeţi bazele de date folosite de toate versiune MySQL?" + +#~ msgid "" +#~ "If you do not provide a password no changes will be made to the account." +#~ msgstr "" +#~ "Dacă nu introduceţi nici o parolă, nici o schimbare nu va fi luată în " +#~ "considerare." + +#~ msgid "" +#~ "When installation finishes, you should verify that the account is " +#~ "properly protected with a password (see README.Debian for more " +#~ "information)." +#~ msgstr "" +#~ "După finalizarea instalării, ar trebui să verificaţi dacă contul este " +#~ "protejat cu o parolă (citiţi fişierul README.Debian pentru informaţii " +#~ "suplimentare)." diff --git a/debian/po/ru.po b/debian/po/ru.po new file mode 100644 index 00000000000..5349416a602 --- /dev/null +++ b/debian/po/ru.po @@ -0,0 +1,225 @@ +# translation of ru.po to Russian +# Russian messages: +# Translators, if you are not familiar with the PO format, gettext +# documentation is worth reading, especially sections dedicated to +# this format, e.g. by running: +# info -n '(gettext)PO Files' +# info -n '(gettext)Header Entry'# +# Some information specific to po-debconf are available at +# /usr/share/doc/po-debconf/README-trans +# or http://www.debian.org/intl/l10n/po-debconf/README-trans# +# Developers do not need to manually edit POT or PO files. +# +# Ilgiz Kalmetev , 2003. +# Yuriy Talakan' , 2005, 2006. +# Yuriy Talakan' , 2007. +# Yuri Kozlov , 2009. +msgid "" +msgstr "" +"Project-Id-Version: mysql-dfsg-5.1 5.1.37-1\n" +"Report-Msgid-Bugs-To: mariadb-5.5@packages.debian.org\n" +"POT-Creation-Date: 2012-01-12 13:08+0100\n" +"PO-Revision-Date: 2009-08-06 20:27+0400\n" +"Last-Translator: Yuri Kozlov \n" +"Language-Team: Russian \n" +"Language: ru\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: KBabel 1.11.4\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "Really proceed with downgrade?" +msgstr "Действительно установить более старую версию?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "A file named /var/lib/mysql/debian-*.flag exists on this system." +msgstr "В системе найден файл /var/lib/mysql/debian-*.flag." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "" +"Such a file is an indication that a mariadb-server package with a higher " +"version has been installed previously." +msgstr "" +"Это означает, что ранее уже был установлен пакет mariadb-server более новой " +"версии." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "" +"There is no guarantee that the version you're currently installing will be " +"able to use the current databases." +msgstr "" +"Нет гарантий, что версия, которая устанавливается сейчас, будет способна " +"работать с имеющимися базами данных." + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "Important note for NIS/YP users" +msgstr "Важное замечание для пользователей NIS/YP" + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "" +"Using MariaDB under NIS/YP requires a mysql user account to be added on the " +"local system with:" +msgstr "" +"Использование MariaDB в NIS/YP требует добавления учётной записи mysql в " +"локальную систему с:" + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "" +"You should also check the permissions and ownership of the /var/lib/mysql " +"directory:" +msgstr "Также проверьте права доступа и владельца каталога /var/lib/mysql:" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "Remove all MariaDB databases?" +msgstr "Удалить все базы данных MariaDB?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "" +"The /var/lib/mysql directory which contains the MariaDB databases is about " +"to be removed." +msgstr "" +"Запрос на удаление каталога /var/lib/mysql, содержащий базы данных MariaDB." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "" +"If you're removing the MariaDB package in order to later install a more " +"recent version or if a different mariadb-server package is already using it, " +"the data should be kept." +msgstr "" +"Если вы удаляете пакет MariaDB для установки более новой версии MariaDB, или " +"есть другие пакеты mariadb-server, использующие этот каталог, то данные " +"лучше сохранить." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:5001 +msgid "Start the MariaDB server on boot?" +msgstr "Запускать MariaDB при загрузке системы?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:5001 +msgid "" +"The MariaDB server can be launched automatically at boot time or manually " +"with the '/etc/init.d/mysql start' command." +msgstr "" +"Сервер MariaDB можно запускать автоматически при загрузке системы или " +"вручную по команде '/etc/init.d/mysql start'." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +msgid "New password for the MariaDB \"root\" user:" +msgstr "Новый пароль для MariaDB пользователя \"root\":" + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +msgid "" +"While not mandatory, it is highly recommended that you set a password for " +"the MariaDB administrative \"root\" user." +msgstr "" +"Хотя и необязательно, но настоятельно рекомендуется установить пароль для " +"административного пользователя MariaDB \"root\"." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +msgid "If this field is left blank, the password will not be changed." +msgstr "Если оставить поле пустым, то пароль изменён не будет." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:7001 +msgid "Repeat password for the MariaDB \"root\" user:" +msgstr "Повторите ввод пароля для MariaDB пользователя \"root\":" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "Unable to set password for the MariaDB \"root\" user" +msgstr "Невозможно задать пароль MariaDB пользователю \"root\"" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "" +"An error occurred while setting the password for the MariaDB administrative " +"user. This may have happened because the account already has a password, or " +"because of a communication problem with the MariaDB server." +msgstr "" +"В процессе задания пароля административного MariaDB пользователя произошла " +"ошибка. Это могло произойти, если у пользователя уже был задан пароль, или " +"из-за проблем соединения с сервером MariaDB." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "You should check the account's password after the package installation." +msgstr "Проверьте пароль учётной записи после установки пакета." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +#, fuzzy +#| msgid "" +#| "Please read the /usr/share/doc/mariadb-server-5.5/README.Debian file for " +#| "more information." +msgid "" +"Please read the /usr/share/doc/mariadb-server-5.3/README.Debian file for " +"more information." +msgstr "" +"Подробности см. в файле /usr/share/doc/mariadb-server-5.5/README.Debian." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:9001 +msgid "Password input error" +msgstr "Ошибка ввода пароля" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:9001 +msgid "The two passwords you entered were not the same. Please try again." +msgstr "Два введённых пароля не одинаковы. Повторите ввод." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:10001 +msgid "NDB Cluster seems to be in use" +msgstr "NDB Cluster уже используется" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:10001 +msgid "" +"MySQL-5.1 no longer provides NDB Cluster support. Please migrate to the new " +"mysql-cluster package and remove all lines starting with \"ndb\" from all " +"config files below /etc/mysql/." +msgstr "" +"MySQL-5.1 больше не поддерживает NDB Cluster. Переходите на новый пакет " +"mysql-cluster и удалите все строки, начинающиеся с \"ndb\", из всех файлов " +"настройки в каталоге /etc/mysql/." diff --git a/debian/po/sv.po b/debian/po/sv.po new file mode 100644 index 00000000000..0dd6008bc83 --- /dev/null +++ b/debian/po/sv.po @@ -0,0 +1,226 @@ +# Translation of mysql-dfsg-5.1 debconf template to Swedish +# Copyright (C) 2009 Martin Bagge +# This file is distributed under the same license as the mysql-dfsg-5.1 package. +# +# Andreas Henriksson , 2007 +# Martin Bagge , 2009 +msgid "" +msgstr "" +"Project-Id-Version: mysql-dfsg-5.1 5.0.21-3\n" +"Report-Msgid-Bugs-To: mariadb-5.5@packages.debian.org\n" +"POT-Creation-Date: 2012-01-12 13:08+0100\n" +"PO-Revision-Date: 2009-09-08 21:42+0100\n" +"Last-Translator: Martin Bagge \n" +"Language-Team: Swedish \n" +"Language: sv\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Poedit-Language: Swedish\n" +"X-Poedit-Country: Sweden\n" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "Really proceed with downgrade?" +msgstr "Vill du verkligen genomföra nedgraderingen?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "A file named /var/lib/mysql/debian-*.flag exists on this system." +msgstr "En fil med namnet /var/lib/mysql/debian-*.flag hittades i systemet." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "" +"Such a file is an indication that a mariadb-server package with a higher " +"version has been installed previously." +msgstr "" +"En sådan fil är en indikation på att paketet mariadb-server med ett högre " +"versionsnummer har installerats tidigare." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "" +"There is no guarantee that the version you're currently installing will be " +"able to use the current databases." +msgstr "" +"Det finns ingen garanti för att den version som du håller på att installera " +"kommer att kunna använda de aktuella databaserna." + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "Important note for NIS/YP users" +msgstr "Viktig information för NIS/YP-användare" + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "" +"Using MariaDB under NIS/YP requires a mysql user account to be added on the " +"local system with:" +msgstr "" +"För att kunna använda MariaDB under NIS/YP måste ett användarkonto för mysql " +"läggas till i systemet." + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "" +"You should also check the permissions and ownership of the /var/lib/mysql " +"directory:" +msgstr "" +"Du bör också kontrollera rättigheterna och ägaren av katalogen /var/lib/" +"mysql." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "Remove all MariaDB databases?" +msgstr "Ta bort alla MariaDB-databaser?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "" +"The /var/lib/mysql directory which contains the MariaDB databases is about " +"to be removed." +msgstr "" +"Katalogen /var/lib/mysql som innehåller MariaDB-databaser kommer att tas " +"bort." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "" +"If you're removing the MariaDB package in order to later install a more " +"recent version or if a different mariadb-server package is already using it, " +"the data should be kept." +msgstr "" +"Om avinstallationen av MariaDB-paketet görs för att senare kunna installera " +"en nyare version eller om en annan mariadb-server redan använder filerna ska " +"de inte raderas." + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:5001 +msgid "Start the MariaDB server on boot?" +msgstr "Ska MariaDB startas vid systemets uppstart?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:5001 +msgid "" +"The MariaDB server can be launched automatically at boot time or manually " +"with the '/etc/init.d/mysql start' command." +msgstr "" +"MariaDB-servern kan startas vid systemets uppstart eller manuellt med " +"kommandot \"/etc/init.d/mysql start\"." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +msgid "New password for the MariaDB \"root\" user:" +msgstr "Nytt lösenord för MariaDBs \"root\"-användare:" + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +msgid "" +"While not mandatory, it is highly recommended that you set a password for " +"the MariaDB administrative \"root\" user." +msgstr "" +"Det är inte obligatoriskt men starkt rekommenderat att du sätter ett " +"lösenord för MariaDBs administrativa \"root\"-användare." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +msgid "If this field is left blank, the password will not be changed." +msgstr "Om detta fält lämnas tom kommer lösenordet inte att ändras." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:7001 +msgid "Repeat password for the MariaDB \"root\" user:" +msgstr "Repetera lösenordet för MariaDBs \"root\"-användare:" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "Unable to set password for the MariaDB \"root\" user" +msgstr "Kunde inte sätta lösenord för MariaDBs \"root\"-användare" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "" +"An error occurred while setting the password for the MariaDB administrative " +"user. This may have happened because the account already has a password, or " +"because of a communication problem with the MariaDB server." +msgstr "" +"Ett fel uppstod när det skulle sättas ett lösenord för MariaDBs " +"administrativa användare (\"root\"). Detta kan ha skett för att användaren " +"redan har ett lösenord satt, eller på grund av problem med att kommunicera " +"med MariaDB-servern." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "You should check the account's password after the package installation." +msgstr "Du bör kontrollera kontots lösenord efter installationen av paketet." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +#, fuzzy +#| msgid "" +#| "Please read the /usr/share/doc/mariadb-server-5.5/README.Debian file for " +#| "more information." +msgid "" +"Please read the /usr/share/doc/mariadb-server-5.3/README.Debian file for " +"more information." +msgstr "" +"Läs filen /usr/share/doc/mariadb-server-5.5/README.Debian för mer " +"information." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:9001 +msgid "Password input error" +msgstr "Fel vid inmatning av lösenord" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:9001 +msgid "The two passwords you entered were not the same. Please try again." +msgstr "De två lösenorden du angav stämde inte överrens. Prova igen." + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:10001 +msgid "NDB Cluster seems to be in use" +msgstr "NDB-kluster används inte" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:10001 +msgid "" +"MySQL-5.1 no longer provides NDB Cluster support. Please migrate to the new " +"mysql-cluster package and remove all lines starting with \"ndb\" from all " +"config files below /etc/mysql/." +msgstr "" +"Stödet för NDB-kluster har tagits bort i MySQL-5.1. Migrera till det nya " +"paketet mysql-cluster och ta bort alla rader som inleds med \"ndb\" från " +"alla inställlningsfiler i /etc/mysql/." + +#~ msgid "" +#~ "To use MySQL, the following entries for users and groups should be added " +#~ "to the system:" +#~ msgstr "" +#~ "För att använda MySQL måste följande användare och grupper läggas till i " +#~ "systemet:" diff --git a/debian/po/templates.pot b/debian/po/templates.pot new file mode 100644 index 00000000000..f70ac168367 --- /dev/null +++ b/debian/po/templates.pot @@ -0,0 +1,187 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: mariadb-5.5@packages.debian.org\n" +"POT-Creation-Date: 2012-01-12 13:08+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "Really proceed with downgrade?" +msgstr "" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "A file named /var/lib/mysql/debian-*.flag exists on this system." +msgstr "" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "" +"Such a file is an indication that a mariadb-server package with a higher " +"version has been installed previously." +msgstr "" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "" +"There is no guarantee that the version you're currently installing will be " +"able to use the current databases." +msgstr "" + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "Important note for NIS/YP users" +msgstr "" + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "" +"Using MariaDB under NIS/YP requires a mysql user account to be added on the " +"local system with:" +msgstr "" + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "" +"You should also check the permissions and ownership of the /var/lib/mysql " +"directory:" +msgstr "" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "Remove all MariaDB databases?" +msgstr "" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "" +"The /var/lib/mysql directory which contains the MariaDB databases is about " +"to be removed." +msgstr "" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "" +"If you're removing the MariaDB package in order to later install a more " +"recent version or if a different mariadb-server package is already using it, " +"the data should be kept." +msgstr "" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:5001 +msgid "Start the MariaDB server on boot?" +msgstr "" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:5001 +msgid "" +"The MariaDB server can be launched automatically at boot time or manually " +"with the '/etc/init.d/mysql start' command." +msgstr "" + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +msgid "New password for the MariaDB \"root\" user:" +msgstr "" + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +msgid "" +"While not mandatory, it is highly recommended that you set a password for " +"the MariaDB administrative \"root\" user." +msgstr "" + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +msgid "If this field is left blank, the password will not be changed." +msgstr "" + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:7001 +msgid "Repeat password for the MariaDB \"root\" user:" +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "Unable to set password for the MariaDB \"root\" user" +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "" +"An error occurred while setting the password for the MariaDB administrative " +"user. This may have happened because the account already has a password, or " +"because of a communication problem with the MariaDB server." +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "You should check the account's password after the package installation." +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "" +"Please read the /usr/share/doc/mariadb-server-5.3/README.Debian file for " +"more information." +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:9001 +msgid "Password input error" +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:9001 +msgid "The two passwords you entered were not the same. Please try again." +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:10001 +msgid "NDB Cluster seems to be in use" +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:10001 +msgid "" +"MySQL-5.1 no longer provides NDB Cluster support. Please migrate to the new " +"mysql-cluster package and remove all lines starting with \"ndb\" from all " +"config files below /etc/mysql/." +msgstr "" diff --git a/debian/po/tr.po b/debian/po/tr.po new file mode 100644 index 00000000000..8fa4522d51e --- /dev/null +++ b/debian/po/tr.po @@ -0,0 +1,342 @@ +# Turkish translation of mariadb-server. +# This file is distributed under the same license as the mariadb-server package. +# Gürkan Aslan , 2004 +# +msgid "" +msgstr "" +"Project-Id-Version: mysql-dfsg-4.1\n" +"Report-Msgid-Bugs-To: mariadb-5.5@packages.debian.org\n" +"POT-Creation-Date: 2012-01-12 13:08+0100\n" +"PO-Revision-Date: 2004-06-05 08:53+0300\n" +"Last-Translator: Gürkan Aslan \n" +"Language-Team: Turkish \n" +"Language: tr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "Really proceed with downgrade?" +msgstr "" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "A file named /var/lib/mysql/debian-*.flag exists on this system." +msgstr "" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "" +"Such a file is an indication that a mariadb-server package with a higher " +"version has been installed previously." +msgstr "" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:2001 +msgid "" +"There is no guarantee that the version you're currently installing will be " +"able to use the current databases." +msgstr "" + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +#, fuzzy +#| msgid "Important note for NIS/YP users!" +msgid "Important note for NIS/YP users" +msgstr "NIS/YP kullanıcıları için önemli not!" + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "" +"Using MariaDB under NIS/YP requires a mysql user account to be added on the " +"local system with:" +msgstr "" + +#. Type: note +#. Description +#: ../mariadb-server-5.5.templates:3001 +msgid "" +"You should also check the permissions and ownership of the /var/lib/mysql " +"directory:" +msgstr "" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "Remove all MariaDB databases?" +msgstr "" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "" +"The /var/lib/mysql directory which contains the MariaDB databases is about " +"to be removed." +msgstr "" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:4001 +msgid "" +"If you're removing the MariaDB package in order to later install a more " +"recent version or if a different mariadb-server package is already using it, " +"the data should be kept." +msgstr "" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:5001 +#, fuzzy +#| msgid "Should MySQL start on boot?" +msgid "Start the MariaDB server on boot?" +msgstr "MariaDB açılış sırasında başlatılsın mı?" + +#. Type: boolean +#. Description +#: ../mariadb-server-5.5.templates:5001 +#, fuzzy +msgid "" +"The MariaDB server can be launched automatically at boot time or manually " +"with the '/etc/init.d/mysql start' command." +msgstr "" +"MariaDB açılış sırasında veya '/etc/init.d/mysql start' komutunu vermeniz " +"halinde elle başlatılabilir. Eğer açılışta otomatik olarak başlatılmasını " +"istiyorsanız burada 'evet'i seçin." + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +msgid "New password for the MariaDB \"root\" user:" +msgstr "" + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +msgid "" +"While not mandatory, it is highly recommended that you set a password for " +"the MariaDB administrative \"root\" user." +msgstr "" + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:6001 +msgid "If this field is left blank, the password will not be changed." +msgstr "" + +#. Type: password +#. Description +#: ../mariadb-server-5.5.templates:7001 +msgid "Repeat password for the MariaDB \"root\" user:" +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "Unable to set password for the MariaDB \"root\" user" +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "" +"An error occurred while setting the password for the MariaDB administrative " +"user. This may have happened because the account already has a password, or " +"because of a communication problem with the MariaDB server." +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "You should check the account's password after the package installation." +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:8001 +msgid "" +"Please read the /usr/share/doc/mariadb-server-5.3/README.Debian file for " +"more information." +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:9001 +msgid "Password input error" +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:9001 +msgid "The two passwords you entered were not the same. Please try again." +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:10001 +msgid "NDB Cluster seems to be in use" +msgstr "" + +#. Type: error +#. Description +#: ../mariadb-server-5.5.templates:10001 +msgid "" +"MySQL-5.1 no longer provides NDB Cluster support. Please migrate to the new " +"mysql-cluster package and remove all lines starting with \"ndb\" from all " +"config files below /etc/mysql/." +msgstr "" + +#~ msgid "" +#~ "To use mysql you must install an equivalent user and group to the " +#~ "following and ensure yourself that /var/lib/mysql has the right " +#~ "permissions (the uid/gid may be different)." +#~ msgstr "" +#~ "Mysql'i kullanmak için aşağıdakiyle eşdeğer bir kullanıcı ve grup " +#~ "tanımlamalı, ve /var/lib/mysql izinlerinin uygun şekilde ayarlandığından " +#~ "emin olmalısınız (uid/gid farklı olabilir)." + +#~ msgid "" +#~ "/etc/passwd: mysql:x:100:101:MySQL Server:/var/lib/mysql:/bin/false" +#~ msgstr "" +#~ "/etc/passwd: mysql:x:100:101:MySQL Server:/var/lib/mysql:/bin/false" + +#~ msgid "/etc/group: mysql:x:101:" +#~ msgstr "/etc/group: mysql:x:101:" + +#~ msgid "/var/lib/mysql: drwxr-xr-x mysql mysql" +#~ msgstr "/var/lib/mysql: drwxr-xr-x mysql mysql" + +#, fuzzy +#~ msgid "Please also read http://www.mysql.com/doc/en/Upgrade.html" +#~ msgstr "Lütfen http://www.mysql.com/doc/en/Upgrade.html belgesini okuyun" + +#, fuzzy +#~ msgid "" +#~ "MySQL will only install if you have a non-numeric hostname that is " +#~ "resolvable via the /etc/hosts file. E.g. if the \"hostname\" command " +#~ "returns \"myhostname\" then there must be a line like \"10.0.0.1 " +#~ "myhostname\"." +#~ msgstr "" +#~ "MySQL sadece /etc/hosts dosyası yoluyla çözülebilir NUMERİK OLMAYAN bir " +#~ "makine adına sahipseniz kurulacaktır. Örneğin, eğer \"hostname\" komutu " +#~ "\"makinem\" ismini döndürüyorsa, bu dosya içinde \"10.0.0.1 makinem\" " +#~ "gibi bir satır olmalıdır." + +#, fuzzy +#~ msgid "" +#~ "A new mysql user \"debian-sys-maint\" will be created. This mysql account " +#~ "is used in the start/stop and cron scripts. Don't delete." +#~ msgstr "" +#~ "Yeni mysql kullanıcısı \"debian-sys-maint\" yaratılacak. Bu hesap, " +#~ "başlangıç betiklerinde ve cron içinde kullanılıyor. Bu hesabı silmeyin." + +#, fuzzy +#~ msgid "" +#~ "Please remember to set a PASSWORD for the MySQL root user! If you use a /" +#~ "root/.my.cnf, always write the \"user\" and the \"password\" lines in " +#~ "there, never only the password!" +#~ msgstr "" +#~ "Lütfen MySQL root kullanıcısı için bir PAROLA girmeyi unutmayın! Eğer /" +#~ "root/.my.cnf kullanıyorsanız, \"user\" ve \"password\" satırlarını her " +#~ "zaman buraya ekleyin, sadece parolayı değil! Daha fazla bilgi için /usr/" +#~ "share/doc/mysql-server/README.Debian dosyasını okuyun." + +#, fuzzy +#~ msgid "" +#~ "Should I remove all databases below /var/lib/mysql as you are purging the " +#~ "mysql-server package?" +#~ msgstr "" +#~ "mysql-server paketi kaldırıldıktan sonra bütün veritabanları silinsin mi?" + +#~ msgid "" +#~ "Networking is disabled by default for security reasons. You can enable it " +#~ "by commenting out the skip-networking option in /etc/mysql/my.cnf." +#~ msgstr "" +#~ "Ağ, öntanımlı olarak güvenlik gerekçeleriyle devre dışı bırakıldı. Bu " +#~ "özelliği /etc/mysql/my.cnf dosyası içindeki \"skip-networking\" " +#~ "seçeneğini kaldırarak etkinleştirebilirsiniz." + +#~ msgid "security and update notice" +#~ msgstr "güvenlik ve güncelleme duyurusu" + +#~ msgid "" +#~ "Should I remove everything below /var/lib/mysql when you purge the mysql-" +#~ "server package with the \"dpkg --purge mysql-server\" command (i.e. " +#~ "remove everything including the configuration) somewhen? (default is not)" +#~ msgstr "" +#~ "mysql-server paketini temizlemek için \"dpkg --purge mysql-server\" " +#~ "komutunu kullandığınızda (yani yapılandırma dahil herşeyi silmek) /var/" +#~ "lib/mysql altındaki herşeyi sileyim mi? (öntanımlı cevap hayır'dır)." + +#~ msgid "Please run mysql_fix_privilege_tables !" +#~ msgstr "Lütfen mysql_fix_privilege_tables komutunu çalıştırın!" + +#~ msgid "" +#~ "I will ensure secure permissions of /var/lib/mysql by replacing GIDs " +#~ "other than root and mysql with mysql." +#~ msgstr "" +#~ "/var/lib/mysql'in izinlerinin güvenli olmasını sağlamak amacıyla, buna " +#~ "ait GID'leri root ve mysql'den farklı olacak şekilde değiştireceğim." + +#~ msgid "" +#~ "Instructions how to enable SSL support are in /usr/share/doc/mysql-server/" +#~ msgstr "" +#~ "SSL desteğini nasıl etkinleştirebileceğinize ilişkin talimatlar /usr/" +#~ "share/doc/mysql-server/ içinde." + +#~ msgid "mysql_fix_privileges_tables will be executed" +#~ msgstr "mysql_fix_privileges_tables çalıştırılacak" + +#~ msgid "" +#~ "The latest MySQL versions have an enhanced, more fine grained, privilege " +#~ "system. To make use of it, some new fields must be added to the tables " +#~ "in the \"mysql\" database. This is done by the " +#~ "mysql_fix_privilege_tables script during this upgrade regardless of if " +#~ "the server is currently running or not!" +#~ msgstr "" +#~ "En son MySQL sürümleri zenginleştirilmiş, daha ayrıntılandırılmış bir " +#~ "ayrıcalık (privilege) sistemine sahiptir. Yeni sistemi kullanmak için, " +#~ "\"mysql\" veritabanındaki tablolara bazı yeni alanlar eklenmelidir. Bu " +#~ "işlem, sunucunun çalışıp çalışmamasına bağlı olmaksızın " +#~ "mysql_fix_privilege_tables betiği tarafından bu yükseltme sırasında " +#~ "yapılır." + +#~ msgid "" +#~ "This script is not supposed to give any user more rights that he had " +#~ "before, if you encounter such a case, please contact me." +#~ msgstr "" +#~ "Bu betiğin hiç bir kullanıcıya öncekinden daha fazla hak kazandırmadığı " +#~ "varsayılıyor. Eğer bunun aksinde bir durumla karşılaşırsanız, lütfen " +#~ "benimle bağlantıya geçin." + +#~ msgid "Make MySQL reachable via network?" +#~ msgstr "MySQL network üzerinden ulaşılabilir olsun mu?" + +#~ msgid "" +#~ "Should MySQL listen on a network reachable TCP port? This is not " +#~ "necessary for use on a single computer and could be a security problem." +#~ msgstr "" +#~ "MySQL ağ üzerinde ulaşılabilen bir TCP portunu dinlesin mi? Tek olan bir " +#~ "bilgisayar için bu ayar gerekli değildir ve bir güvenlik sorunu " +#~ "oluşturabilir." + +#~ msgid "Enable chroot mode?" +#~ msgstr "chroot kipi etkinleştirilsin mi?" + +#~ msgid "" +#~ "MySQL is able to jail itself into the /var/lib/mysql_jail directory so " +#~ "that users cannot modify any files outside this directory. This improves " +#~ "resistence against crackers, too, as they are not able to modify system " +#~ "files." +#~ msgstr "" +#~ "MySQL kendini /var/lib/mysql_jail dizinine hapsederek kullanıcıların bu " +#~ "dizin dışındaki hiç bir dosyayı değiştirmemesini sağlayabilir. Bu " +#~ "düzenleme, sistem dosyalarını değiştirmelerini engelleyeceğinden, " +#~ "cracker'lara karşı dayanıklılığı arttırır." diff --git a/debian/source.lintian-overrides b/debian/source.lintian-overrides new file mode 100644 index 00000000000..75c4215bba5 --- /dev/null +++ b/debian/source.lintian-overrides @@ -0,0 +1,2 @@ +maintainer-script-lacks-debhelper-token debian/mariadb-server-5.3.postinst +maintainer-script-lacks-debhelper-token debian/mariadb-server-5.3.postrm diff --git a/debian/watch b/debian/watch new file mode 100644 index 00000000000..f6fdd67bd8d --- /dev/null +++ b/debian/watch @@ -0,0 +1,3 @@ +version=3 +opts="uversionmangle=s/-(rc|beta)/$1/" \ + ftp://sunsite.informatik.rwth-aachen.de/pub/mirror/www.mysql.com/Downloads/MySQL-5.1/mysql-([\d\.]*(?:-beta|-rc)?).tar.gz debian From aa2a2f83e3eac2fe95f4eb6bf9ff948a1c580242 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 23 Jan 2012 15:08:46 +0100 Subject: [PATCH 286/288] Buildbot VMs have cmake in /usr/local/, so we need to include that in the path. --- debian/dist/Debian/rules | 2 +- debian/dist/Ubuntu/rules | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/dist/Debian/rules b/debian/dist/Debian/rules index 58d0c268ca3..11347164ea0 100755 --- a/debian/dist/Debian/rules +++ b/debian/dist/Debian/rules @@ -64,7 +64,7 @@ ifneq ($(ARCH_OS),hurd) endif ( test -d $(builddir) || mkdir $(builddir) ) && cd $(builddir) && \ - sh -c 'PATH=$${MYSQL_BUILD_PATH:-"/bin:/usr/bin"} \ + sh -c 'PATH=$${MYSQL_BUILD_PATH:-"/bin:/usr/bin:/usr/local/bin"} \ CC=$${MYSQL_BUILD_CC:-gcc} \ CFLAGS=$${MYSQL_BUILD_CFLAGS:-"-O2 -fno-omit-frame-pointer -g -pipe -Wall -Wno-uninitialized"} \ CXX=$${MYSQL_BUILD_CXX:-g++} \ diff --git a/debian/dist/Ubuntu/rules b/debian/dist/Ubuntu/rules index 0bb8837993e..564dad01ac0 100755 --- a/debian/dist/Ubuntu/rules +++ b/debian/dist/Ubuntu/rules @@ -64,7 +64,7 @@ ifneq ($(ARCH_OS),hurd) endif ( test -d $(builddir) || mkdir $(builddir) ) && cd $(builddir) && \ - sh -c 'PATH=$${MYSQL_BUILD_PATH:-"/bin:/usr/bin"} \ + sh -c 'PATH=$${MYSQL_BUILD_PATH:-"/bin:/usr/bin:/usr/local/bin"} \ CC=$${MYSQL_BUILD_CC:-gcc} \ CFLAGS=$${MYSQL_BUILD_CFLAGS:-"-O2 -fno-omit-frame-pointer -g -pipe -Wall -Wno-uninitialized"} \ CXX=$${MYSQL_BUILD_CXX:-g++} \ From 7baa64fc6182ca2baf3da6888044ef5411b51727 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 23 Jan 2012 17:07:01 +0100 Subject: [PATCH 287/288] Fix typo in Ubuntu .deb packaging --- debian/dist/Ubuntu/mariadb-server-5.5.files | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/dist/Ubuntu/mariadb-server-5.5.files b/debian/dist/Ubuntu/mariadb-server-5.5.files index 13d1dc074d0..58da345b737 100644 --- a/debian/dist/Ubuntu/mariadb-server-5.5.files +++ b/debian/dist/Ubuntu/mariadb-server-5.5.files @@ -56,7 +56,7 @@ usr/share/man/man1/innochecksum.1 usr/share/man/man1/mysql_tzinfo_to_sql.1 usr/share/mysql/debian-start.inc.sh usr/share/mysql/echo_stderr -usr/share/mysql/errmsg.txt +usr/share/mysql/errmsg-utf8.txt usr/share/mysql/fill_help_tables.sql usr/share/mysql/mysql_system_tables_data.sql usr/share/mysql/mysql_system_tables.sql From 19d13a3b17d613c04acbcd8c7a0578a55e0c2938 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Mon, 23 Jan 2012 17:12:25 +0100 Subject: [PATCH 288/288] portability fixes for FreeBSD 8 and 9 --- configure.cmake | 1 - include/my_global.h | 5 +---- mysys/my_getsystime.c | 6 ++++-- storage/xtradb/log/log0recv.c | 2 +- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/configure.cmake b/configure.cmake index 35c2027b4e0..ea000ad69a0 100644 --- a/configure.cmake +++ b/configure.cmake @@ -238,7 +238,6 @@ CHECK_INCLUDE_FILES (sys/socket.h HAVE_SYS_SOCKET_H) CHECK_INCLUDE_FILES (sys/stat.h HAVE_SYS_STAT_H) CHECK_INCLUDE_FILES (sys/stream.h HAVE_SYS_STREAM_H) CHECK_INCLUDE_FILES (sys/termcap.h HAVE_SYS_TERMCAP_H) -CHECK_INCLUDE_FILES ("time.h;sys/timeb.h" HAVE_SYS_TIMEB_H) CHECK_INCLUDE_FILES ("curses.h;term.h" HAVE_TERM_H) CHECK_INCLUDE_FILES (asm/termbits.h HAVE_ASM_TERMBITS_H) CHECK_INCLUDE_FILES (termbits.h HAVE_TERMBITS_H) diff --git a/include/my_global.h b/include/my_global.h index 8d54448f477..26cba5b4ed7 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -372,9 +372,6 @@ C_MODE_END #ifdef HAVE_SYS_STAT_H #include #endif -#ifdef HAVE_SYS_TIMEB_H -#include /* Avoid warnings on SCO */ -#endif #if TIME_WITH_SYS_TIME # include # include @@ -858,7 +855,7 @@ static inline double my_isinf(double x) This will be slightly slower and perhaps a tiny bit less accurate than doing it the IEEE754 way but log2() should be available on C99 systems. */ -inline double log2(double x) +static inline double log2(double x) { return (log(x) / M_LN2); } diff --git a/mysys/my_getsystime.c b/mysys/my_getsystime.c index ece0c5fdd87..f1caea6d21a 100644 --- a/mysys/my_getsystime.c +++ b/mysys/my_getsystime.c @@ -118,6 +118,7 @@ void my_time_init() ulonglong my_getcputime() { +#ifdef CLOCK_THREAD_CPUTIME_ID #ifdef HAVE_CLOCK_GETTIME struct timespec tp; if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp)) @@ -128,7 +129,8 @@ ulonglong my_getcputime() if (syscall(__NR_clock_gettime, CLOCK_THREAD_CPUTIME_ID, &tp)) return 0; return (ulonglong)tp.tv_sec*10000000+(ulonglong)tp.tv_nsec/100; -#else - return 0; #endif /* HAVE_CLOCK_GETTIME */ +#else /* HAVE_THREAD_CPUTIME_ID */ + return 0; +#endif } diff --git a/storage/xtradb/log/log0recv.c b/storage/xtradb/log/log0recv.c index 9c48d06eb45..c4429af5112 100644 --- a/storage/xtradb/log/log0recv.c +++ b/storage/xtradb/log/log0recv.c @@ -32,7 +32,7 @@ Created 9/20/1997 Heikki Tuuri #include "config.h" #ifdef HAVE_ALLOCA_H #include "alloca.h" -#else +#elif defined(HAVE_MALLOC_H) #include "malloc.h" #endif