diff options
69 files changed, 1609 insertions, 383 deletions
diff --git a/client/client_priv.h b/client/client_priv.h index 25241cc8c59..8bc8ef692de 100644 --- a/client/client_priv.h +++ b/client/client_priv.h @@ -73,6 +73,10 @@ enum options_client OPT_SLAP_AUTO_GENERATE_UNIQUE_QUERY_NUM, OPT_SLAP_PRE_QUERY, OPT_SLAP_POST_QUERY, + OPT_SLAP_PRE_SYSTEM, + OPT_SLAP_POST_SYSTEM, + OPT_SLAP_COMMIT, + OPT_SLAP_DETACH, OPT_MYSQL_REPLACE_INTO, OPT_BASE64_OUTPUT, OPT_SERVER_ID, OPT_FIX_TABLE_NAMES, OPT_FIX_DB_NAMES, OPT_SSL_VERIFY_SERVER_CERT, OPT_DEBUG_INFO, OPT_COLUMN_TYPES, OPT_ERROR_LOG_FILE, OPT_WRITE_BINLOG, diff --git a/client/mysqlslap.c b/client/mysqlslap.c index 546b9dee3f5..aa15141bfdc 100644 --- a/client/mysqlslap.c +++ b/client/mysqlslap.c @@ -81,6 +81,7 @@ TODO: #define UPDATE_TYPE_REQUIRES_PREFIX 3 #define CREATE_TABLE_TYPE 4 #define SELECT_TYPE_REQUIRES_PREFIX 5 +#define DELETE_TYPE_REQUIRES_PREFIX 6 #include "client_priv.h" #include <mysqld_error.h> @@ -122,6 +123,8 @@ static char *host= NULL, *opt_password= NULL, *user= NULL, *user_supplied_pre_statements= NULL, *user_supplied_post_statements= NULL, *default_engine= NULL, + *pre_system= NULL, + *post_system= NULL, *opt_mysql_unix_port= NULL; const char *delimiter= "\n"; @@ -142,6 +145,8 @@ const char *auto_generate_sql_type= "mixed"; static unsigned long connect_flags= CLIENT_MULTI_RESULTS; static int verbose, delimiter_length; +static uint commit_rate; +static uint detach_rate; const char *num_int_cols_opt; const char *num_char_cols_opt; /* Yes, we do set defaults here */ @@ -254,6 +259,8 @@ void statement_cleanup(statement *stmt); void option_cleanup(option_string *stmt); void concurrency_loop(MYSQL *mysql, uint current, option_string *eptr); static int run_statements(MYSQL *mysql, statement *stmt); +int slap_connect(MYSQL *mysql); +static int run_query(MYSQL *mysql, const char *query, int len); static const char ALPHANUMERICS[]= "0123456789ABCDEFGHIJKLMNOPQRSTWXYZabcdefghijklmnopqrstuvwxyz"; @@ -451,6 +458,16 @@ void concurrency_loop(MYSQL *mysql, uint current, option_string *eptr) if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary) generate_primary_key_list(mysql, eptr); + if (commit_rate) + run_query(mysql, "SET AUTOCOMMIT=0", strlen("SET AUTOCOMMIT=0")); + + if (pre_system) + system(pre_system); + + /* + Pre statements are always run after all other logic so they can + correct/adjust any item that they want. + */ if (pre_statements) run_statements(mysql, pre_statements); @@ -459,6 +476,9 @@ void concurrency_loop(MYSQL *mysql, uint current, option_string *eptr) if (post_statements) run_statements(mysql, post_statements); + if (post_system) + system(post_system); + /* We are finished with this run */ if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary) drop_primary_key_list(); @@ -527,6 +547,9 @@ static struct my_option my_long_options[] = "Number of rows to insert to used in read and write loads (default is 100).\n", (uchar**) &auto_generate_sql_number, (uchar**) &auto_generate_sql_number, 0, GET_ULL, REQUIRED_ARG, 100, 0, 0, 0, 0, 0}, + {"commit", OPT_SLAP_COMMIT, "Commit records after X number of statements.", + (uchar**) &commit_rate, (uchar**) &commit_rate, 0, GET_UINT, REQUIRED_ARG, + 0, 0, 0, 0, 0, 0}, {"compress", 'C', "Use compression in server/client protocol.", (uchar**) &opt_compress, (uchar**) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -550,6 +573,9 @@ static struct my_option my_long_options[] = "Delimiter to use in SQL statements supplied in file or command line.", (uchar**) &delimiter, (uchar**) &delimiter, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"detach", OPT_SLAP_DETACH, "Detach connections after X number of requests.", + (uchar**) &detach_rate, (uchar**) &detach_rate, 0, GET_UINT, REQUIRED_ARG, + 0, 0, 0, 0, 0, 0}, {"engine", 'e', "Storage engine to use for creating the table.", (uchar**) &default_engine, (uchar**) &default_engine, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -589,11 +615,21 @@ static struct my_option my_long_options[] = (uchar**) &user_supplied_post_statements, (uchar**) &user_supplied_post_statements, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"post-system", OPT_SLAP_POST_SYSTEM, + "System() string to run after the load has completed.", + (uchar**) &post_system, + (uchar**) &post_system, + 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"pre-query", OPT_SLAP_PRE_QUERY, "Query to run or file containing query to run before executing.", (uchar**) &user_supplied_pre_statements, (uchar**) &user_supplied_pre_statements, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"pre-system", OPT_SLAP_PRE_SYSTEM, + "System() string to before load has completed.", + (uchar**) &pre_system, + (uchar**) &pre_system, + 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"preserve-schema", OPT_MYSQL_PRESERVE_SCHEMA, "Preserve the schema from the mysqlslap run, this happens unless " "--auto-generate-sql or --create are used.", @@ -1715,6 +1751,7 @@ run_scheduler(stats *sptr, statement *stmts, uint concur, ulonglong limit) pthread_handler_t run_task(void *p) { ulonglong counter= 0, queries; + ulonglong trans_counter; MYSQL *mysql; MYSQL_RES *result; MYSQL_ROW row; @@ -1749,38 +1786,28 @@ pthread_handler_t run_task(void *p) if (!opt_only_print) { - /* Connect to server */ - static ulong connection_retry_sleep= 100000; /* Microseconds */ - int i, connect_error= 1; - for (i= 0; i < 10; i++) - { - if (mysql_real_connect(mysql, host, user, opt_password, - create_schema_string, - opt_mysql_port, - opt_mysql_unix_port, - connect_flags)) - { - /* Connect suceeded */ - connect_error= 0; - break; - } - my_sleep(connection_retry_sleep); - } - if (connect_error) - { - fprintf(stderr,"%s: Error when connecting to server: %d %s\n", - my_progname, mysql_errno(mysql), mysql_error(mysql)); + if (slap_connect(mysql)) goto end; - } } + DBUG_PRINT("info", ("connected.")); if (verbose >= 3) printf("connected!\n"); queries= 0; limit_not_met: - for (ptr= con->stmt; ptr && ptr->length; ptr= ptr->next) + for (ptr= con->stmt, trans_counter= 0; + ptr && ptr->length; + ptr= ptr->next, trans_counter++) { + if (!opt_only_print && detach_rate && !(trans_counter % detach_rate)) + { + mysql_close(mysql); + + if (slap_connect(mysql)) + goto end; + } + /* We have to execute differently based on query type. This should become a function. */ @@ -1837,6 +1864,9 @@ limit_not_met: } queries++; + if (commit_rate && commit_rate <= trans_counter) + run_query(mysql, "COMMIT", strlen("COMMIT")); + if (con->limit && queries == con->limit) goto end; } @@ -1845,6 +1875,8 @@ limit_not_met: goto limit_not_met; end: + if (commit_rate) + run_query(mysql, "COMMIT", strlen("COMMIT")); if (!opt_only_print) mysql_close(mysql); @@ -2104,3 +2136,34 @@ statement_cleanup(statement *stmt) my_free(ptr, MYF(0)); } } + + +int +slap_connect(MYSQL *mysql) +{ + /* Connect to server */ + static ulong connection_retry_sleep= 100000; /* Microseconds */ + int x, connect_error= 1; + for (x= 0; x < 10; x++) + { + if (mysql_real_connect(mysql, host, user, opt_password, + create_schema_string, + opt_mysql_port, + opt_mysql_unix_port, + connect_flags)) + { + /* Connect suceeded */ + connect_error= 0; + break; + } + my_sleep(connection_retry_sleep); + } + if (connect_error) + { + fprintf(stderr,"%s: Error when connecting to server: %d %s\n", + my_progname, mysql_errno(mysql), mysql_error(mysql)); + return 1; + } + + return 0; +} diff --git a/mysql-test/include/have_bug25714.inc b/mysql-test/include/have_bug25714.inc new file mode 100644 index 00000000000..0c995cd0d4c --- /dev/null +++ b/mysql-test/include/have_bug25714.inc @@ -0,0 +1,7 @@ +# +# Check if the variable MYSQL_BUG25714 is set +# +--require r/have_bug25714.require +disable_query_log; +eval select LENGTH("MYSQL_BUG25714") > 0 as "have_bug25714_exe"; +enable_query_log; diff --git a/mysql-test/include/mix1.inc b/mysql-test/include/mix1.inc index bffb748dd6b..d8bc4c40bf3 100644 --- a/mysql-test/include/mix1.inc +++ b/mysql-test/include/mix1.inc @@ -815,6 +815,90 @@ alter table t1 alter a set default 1; drop table t1; # +# Bug #28591: MySQL need not sort the records in case of ORDER BY +# primary_key on InnoDB table +# + +CREATE TABLE t1 (a int, b int, PRIMARY KEY (a), KEY bkey (b)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1,2),(3,2),(2,2),(4,2),(5,2),(6,2),(7,2),(8,2); +INSERT INTO t1 SELECT a + 8, 2 FROM t1; +INSERT INTO t1 SELECT a + 16, 1 FROM t1; +query_vertical EXPLAIN SELECT * FROM t1 WHERE b=2 ORDER BY a; +SELECT * FROM t1 WHERE b=2 ORDER BY a; +query_vertical EXPLAIN SELECT * FROM t1 WHERE b BETWEEN 1 AND 2 ORDER BY a; +SELECT * FROM t1 WHERE b BETWEEN 1 AND 2 ORDER BY a; +query_vertical EXPLAIN SELECT * FROM t1 WHERE b BETWEEN 1 AND 2 ORDER BY b,a; +SELECT * FROM t1 WHERE b BETWEEN 1 AND 2 ORDER BY b,a; + +CREATE TABLE t2 (a int, b int, c int, PRIMARY KEY (a), KEY bkey (b,c)) + ENGINE=InnoDB; +INSERT INTO t2 VALUES (1,1,1),(3,1,1),(2,1,1),(4,1,1); +INSERT INTO t2 SELECT a + 4, 1, 1 FROM t2; +INSERT INTO t2 SELECT a + 8, 1, 1 FROM t2; + +query_vertical EXPLAIN SELECT * FROM t2 WHERE b=1 ORDER BY a; +SELECT * FROM t2 WHERE b=1 ORDER BY a; +query_vertical EXPLAIN SELECT * FROM t2 WHERE b=1 AND c=1 ORDER BY a; +SELECT * FROM t2 WHERE b=1 AND c=1 ORDER BY a; +query_vertical EXPLAIN SELECT * FROM t2 WHERE b=1 AND c=1 ORDER BY b,c,a; +SELECT * FROM t2 WHERE b=1 AND c=1 ORDER BY b,c,a; +query_vertical EXPLAIN SELECT * FROM t2 WHERE b=1 AND c=1 ORDER BY c,a; +SELECT * FROM t2 WHERE b=1 AND c=1 ORDER BY c,a; + +DROP TABLE t1,t2; + + +# +# Bug #29644: alter table hangs if records locked in share mode by long +# running transaction +# + +CREATE TABLE t1 (a INT, PRIMARY KEY (a)) ENGINE=InnoDB; + +INSERT INTO t1 VALUES (1),(2),(3),(4),(5),(6),(7),(8); +INSERT INTO t1 SELECT a + 8 FROM t1; +INSERT INTO t1 SELECT a + 16 FROM t1; + +DELIMITER |; +CREATE PROCEDURE p1 () +BEGIN + DECLARE i INT DEFAULT 50; + DECLARE cnt INT; + START TRANSACTION; + ALTER TABLE t1 ENGINE=InnoDB; + COMMIT; + START TRANSACTION; + WHILE (i > 0) DO + SET i = i - 1; + SELECT COUNT(*) INTO cnt FROM t1 LOCK IN SHARE MODE; + END WHILE; + COMMIT; +END;| + +DELIMITER ;| + +CONNECT (con1,localhost,root,,); +CONNECT (con2,localhost,root,,); + +CONNECTION con1; +SEND CALL p1(); +CONNECTION con2; +SEND CALL p1(); +CONNECTION default; +CALL p1(); + +CONNECTION con1; +REAP; +CONNECTION con2; +REAP; +CONNECTION default; +DISCONNECT con1; +DISCONNECT con2; + +DROP PROCEDURE p1; +DROP TABLE t1; + +# # Bug #28125: ERROR 2013 when adding index. # create table t1(a text) engine=innodb default charset=utf8; diff --git a/mysql-test/lib/mtr_report.pl b/mysql-test/lib/mtr_report.pl index 306a0fe5d9d..fa38e8507f8 100644 --- a/mysql-test/lib/mtr_report.pl +++ b/mysql-test/lib/mtr_report.pl @@ -362,7 +362,11 @@ sub mtr_report_stats ($) { # BUG#29807 - innodb_mysql.test: Cannot find table test/t2 # from the internal data dictionary - /Cannot find table test\/bug29807 from the internal data dictionary/ + /Cannot find table test\/bug29807 from the internal data dictionary/ or + + # BUG#29839 - lowercase_table3.test: Cannot find table test/T1 + # from the internal data dictiona + /Cannot find table test\/BUG29839 from the internal data dictionary/ ) { next; # Skip these lines diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 6ec4045bb43..1effa7c878d 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -143,6 +143,7 @@ our $exe_mysqladmin; our $exe_mysql_upgrade; our $exe_mysqlbinlog; our $exe_mysql_client_test; +our $exe_bug25714; our $exe_mysqld; our $exe_mysqlcheck; our $exe_mysqldump; @@ -1648,6 +1649,12 @@ sub executable_setup () { "$glob_basedir/tests/mysql_client_test", "$glob_basedir/bin/mysql_client_test"); } + + # Look for bug25714 executable which may _not_ exist in + # some versions, test using it should be skipped + $exe_bug25714= + mtr_exe_maybe_exists(vs_config_dirs('tests', 'bug25714'), + "$glob_basedir/tests/bug25714"); } @@ -2019,6 +2026,11 @@ sub environment_setup () { $ENV{'MYSQL'}= $cmdline_mysql; # ---------------------------------------------------- + # Setup env so childs can execute bug25714 + # ---------------------------------------------------- + $ENV{'MYSQL_BUG25714'}= $exe_bug25714; + + # ---------------------------------------------------- # Setup env so childs can execute mysql_client_test # ---------------------------------------------------- $ENV{'MYSQL_CLIENT_TEST'}= mysql_client_test_arguments(); diff --git a/mysql-test/r/alter_table.result b/mysql-test/r/alter_table.result index a9c01f308f7..7c0ac177cb5 100644 --- a/mysql-test/r/alter_table.result +++ b/mysql-test/r/alter_table.result @@ -1030,6 +1030,7 @@ select * from t2; c NULL 1 +Two Three lock table t2 write, t3 read; alter table t2 change c vc varchar(100) default "Four", rename to t1; @@ -1046,6 +1047,7 @@ select * from t1; vc NULL 1 +Two Three Four drop tables t1, t3; @@ -1170,3 +1172,15 @@ SELECT * FROM t1; f1 f2 f3 1 2 NULL DROP TABLE t1; +create table t1 (c char(10) default "Two"); +lock table t1 write; +insert into t1 values (); +alter table t1 modify c char(10) default "Three"; +unlock tables; +select * from t1; +c +Two +check table t1; +Table Op Msg_type Msg_text +test.t1 check status OK +drop table t1; diff --git a/mysql-test/r/check.result b/mysql-test/r/check.result index 739eab2ed76..0bff34dba20 100644 --- a/mysql-test/r/check.result +++ b/mysql-test/r/check.result @@ -15,3 +15,11 @@ test.v1 check status OK test.t2 check status OK drop view v1; drop table t1, t2; +CREATE TEMPORARY TABLE t1(a INT); +CHECK TABLE t1; +Table Op Msg_type Msg_text +test.t1 check status OK +REPAIR TABLE t1; +Table Op Msg_type Msg_text +test.t1 repair status OK +DROP TABLE t1; diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index cdbb767dd9f..84a620336dc 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -1516,6 +1516,35 @@ t1 CREATE TABLE `t1` ( `c17` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; + +Bug #26104 Bug on foreign key class constructor + +Check that ref_columns is initalized correctly in the constructor +and semantic checks in mysql_prepare_table work. + +We do not need a storage engine that supports foreign keys +for this test, as the checks are purely syntax-based, and the +syntax is supported for all engines. + +drop table if exists t1,t2; +create table t1(a int not null, b int not null, primary key (a, b)); +create table t2(a int not null, b int not null, c int not null, primary key (a), +foreign key fk_bug26104 (b,c) references t1(a)); +ERROR 42000: Incorrect foreign key definition for 'fk_bug26104': Key reference and table reference don't match +drop table t1; +create table t1(f1 int,f2 int); +insert into t1 value(1,1),(1,2),(1,3),(2,1),(2,2),(2,3); +flush status; +create table t2 select sql_big_result f1,count(f2) from t1 group by f1; +show status like 'handler_read%'; +Variable_name Value +Handler_read_first 0 +Handler_read_key 0 +Handler_read_next 0 +Handler_read_prev 0 +Handler_read_rnd 0 +Handler_read_rnd_next 7 +drop table t1,t2; End of 5.0 tests CREATE TABLE t1 (a int, b int); insert into t1 values (1,1),(1,2); diff --git a/mysql-test/r/federated.result b/mysql-test/r/federated.result index 5c5cb7eaa79..ca936cd5fde 100644 --- a/mysql-test/r/federated.result +++ b/mysql-test/r/federated.result @@ -40,17 +40,18 @@ CREATE TABLE federated.t1 ( ) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t3'; -ERROR HY000: Can't create federated table. Foreign data src error: error: 1146 'Table 'federated.t3' doesn't exist' +SELECT * FROM federated.t1; +ERROR HY000: The foreign data source you are trying to reference does not exist. Data source error: error: 1146 'Table 'federated.t3' doesn't exist' +DROP TABLE federated.t1; CREATE TABLE federated.t1 ( `id` int(20) NOT NULL, `name` varchar(32) NOT NULL default '' ) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 CONNECTION='mysql://user:pass@127.0.0.1:SLAVE_PORT/federated/t1'; -ERROR HY000: Unable to connect to foreign data source: database: 'federated' username: 'user' hostname: '127.0.0.1' -DROP TABLE IF EXISTS federated.t1; -Warnings: -Note 1051 Unknown table 't1' +SELECT * FROM federated.t1; +ERROR HY000: Unable to connect to foreign data source: Access denied for user 'user'@'localhost' (using password: YES) +DROP TABLE federated.t1; CREATE TABLE federated.t1 ( `id` int(20) NOT NULL, `name` varchar(32) NOT NULL default '' @@ -1919,6 +1920,28 @@ a b 2 Curly drop table federated.t1; drop table federated.t1; +CREATE TABLE federated.t1 (a INT PRIMARY KEY) DEFAULT CHARSET=utf8; +CREATE TABLE federated.t1 (a INT PRIMARY KEY) +ENGINE=FEDERATED +CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1' + DEFAULT CHARSET=utf8; +SELECT transactions FROM information_schema.engines WHERE engine="FEDERATED"; +transactions +NO +INSERT INTO federated.t1 VALUES (1); +SET autocommit=0; +INSERT INTO federated.t1 VALUES (2); +ROLLBACK; +Warnings: +Warning 1196 Some non-transactional changed tables couldn't be rolled back +SET autocommit=1; +SELECT * FROM federated.t1; +a +1 +2 +DROP TABLE federated.t1; +DROP TABLE federated.t1; +End of 5.1 tests DROP TABLE IF EXISTS federated.t1; DROP DATABASE IF EXISTS federated; DROP TABLE IF EXISTS federated.t1; diff --git a/mysql-test/r/federated_bug_25714.result b/mysql-test/r/federated_bug_25714.result new file mode 100644 index 00000000000..12554f7af3a --- /dev/null +++ b/mysql-test/r/federated_bug_25714.result @@ -0,0 +1,56 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +stop slave; +DROP DATABASE IF EXISTS federated; +CREATE DATABASE federated; +DROP DATABASE IF EXISTS federated; +CREATE DATABASE federated; +DROP TABLE IF EXISTS federated.bug_13118_table; +CREATE TABLE federated.t1 ( +`id` int auto_increment primary key, +`value` int +) ENGINE=MyISAM; +INSERT INTO federated.t1 SET value=1; +INSERT INTO federated.t1 SET value=2; +INSERT INTO federated.t1 SET value=2; +DROP TABLE IF EXISTS federated.t1; +CREATE TABLE federated.t1 ( +`id` int auto_increment primary key, +`value` int +) ENGINE=FEDERATED +CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; +SELECT * from federated.t1; +id value +1 1 +2 2 +3 2 +INSERT INTO federated.t1 SET value=4; +SELECT LAST_INSERT_ID(); +LAST_INSERT_ID() +4 + +5 inserted +6 inserted + +7 inserted +8 inserted +SELECT * from federated.t1; +id value +1 1 +2 2 +3 2 +4 4 +5 54 +6 55 +7 54 +8 55 +DROP TABLE federated.t1; +DROP TABLE federated.t1; +DROP TABLE IF EXISTS federated.t1; +DROP DATABASE IF EXISTS federated; +DROP TABLE IF EXISTS federated.t1; +DROP DATABASE IF EXISTS federated; diff --git a/mysql-test/r/have_bug25714.require b/mysql-test/r/have_bug25714.require new file mode 100644 index 00000000000..5acc378dcf7 --- /dev/null +++ b/mysql-test/r/have_bug25714.require @@ -0,0 +1,2 @@ +have_bug25714_exe +1 diff --git a/mysql-test/r/having.result b/mysql-test/r/having.result index 149391396b6..a5a96fd4958 100644 --- a/mysql-test/r/having.result +++ b/mysql-test/r/having.result @@ -158,6 +158,25 @@ EXPLAIN SELECT 0 AS x, a FROM t1 GROUP BY x,a HAVING x=1 AND a > 1; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible HAVING DROP table t1; +CREATE TABLE t1 (a int PRIMARY KEY); +CREATE TABLE t2 (b int PRIMARY KEY, a int); +CREATE TABLE t3 (b int, flag int); +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (1,1), (2,1), (3,1); +INSERT INTO t3(b,flag) VALUES (2, 1); +SELECT t1.a +FROM t1 INNER JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t2.b=t3.b +GROUP BY t1.a, t2.b HAVING MAX(t3.flag)=0; +a +SELECT DISTINCT t1.a, MAX(t3.flag) +FROM t1 INNER JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t2.b=t3.b +GROUP BY t1.a, t2.b HAVING MAX(t3.flag)=0; +a MAX(t3.flag) +SELECT DISTINCT t1.a +FROM t1 INNER JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t2.b=t3.b +GROUP BY t1.a, t2.b HAVING MAX(t3.flag)=0; +a +DROP TABLE t1,t2,t3; create table t1 (col1 int, col2 varchar(5), col_t1 int); create table t2 (col1 int, col2 varchar(5), col_t2 int); create table t3 (col1 int, col2 varchar(5), col_t3 int); diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index 9a96145ef06..804c4b81c17 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -1640,7 +1640,7 @@ t2 CREATE TABLE `t2` ( ) ENGINE=InnoDB DEFAULT CHARSET=latin1 drop table t2; create table t2 (id int(11) not null, id2 int(11) not null, constraint t1_id_fk foreign key (id2,id) references t1 (id)) engine = innodb; -ERROR HY000: Can't create table 'test.t2' (errno: 150) +ERROR 42000: Incorrect foreign key definition for 't1_id_fk': Key reference and table reference don't match create table t2 (a int auto_increment primary key, b int, index(b), foreign key (b) references t1(id), unique(b)) engine=innodb; show create table t2; Table Create Table diff --git a/mysql-test/r/innodb_mysql.result b/mysql-test/r/innodb_mysql.result index 1dd82d2dd88..4beb818c1eb 100644 --- a/mysql-test/r/innodb_mysql.result +++ b/mysql-test/r/innodb_mysql.result @@ -814,6 +814,274 @@ drop table if exists t1; create table t1 (a int) engine=innodb; alter table t1 alter a set default 1; drop table t1; +CREATE TABLE t1 (a int, b int, PRIMARY KEY (a), KEY bkey (b)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1,2),(3,2),(2,2),(4,2),(5,2),(6,2),(7,2),(8,2); +INSERT INTO t1 SELECT a + 8, 2 FROM t1; +INSERT INTO t1 SELECT a + 16, 1 FROM t1; +EXPLAIN SELECT * FROM t1 WHERE b=2 ORDER BY a; +id 1 +select_type SIMPLE +table t1 +type ref +possible_keys bkey +key bkey +key_len 5 +ref const +rows 16 +Extra Using where; Using index +SELECT * FROM t1 WHERE b=2 ORDER BY a; +a b +1 2 +2 2 +3 2 +4 2 +5 2 +6 2 +7 2 +8 2 +9 2 +10 2 +11 2 +12 2 +13 2 +14 2 +15 2 +16 2 +EXPLAIN SELECT * FROM t1 WHERE b BETWEEN 1 AND 2 ORDER BY a; +id 1 +select_type SIMPLE +table t1 +type range +possible_keys bkey +key bkey +key_len 5 +ref NULL +rows 16 +Extra Using where; Using index; Using filesort +SELECT * FROM t1 WHERE b BETWEEN 1 AND 2 ORDER BY a; +a b +1 2 +2 2 +3 2 +4 2 +5 2 +6 2 +7 2 +8 2 +9 2 +10 2 +11 2 +12 2 +13 2 +14 2 +15 2 +16 2 +17 1 +18 1 +19 1 +20 1 +21 1 +22 1 +23 1 +24 1 +25 1 +26 1 +27 1 +28 1 +29 1 +30 1 +31 1 +32 1 +EXPLAIN SELECT * FROM t1 WHERE b BETWEEN 1 AND 2 ORDER BY b,a; +id 1 +select_type SIMPLE +table t1 +type range +possible_keys bkey +key bkey +key_len 5 +ref NULL +rows 16 +Extra Using where; Using index +SELECT * FROM t1 WHERE b BETWEEN 1 AND 2 ORDER BY b,a; +a b +17 1 +18 1 +19 1 +20 1 +21 1 +22 1 +23 1 +24 1 +25 1 +26 1 +27 1 +28 1 +29 1 +30 1 +31 1 +32 1 +1 2 +2 2 +3 2 +4 2 +5 2 +6 2 +7 2 +8 2 +9 2 +10 2 +11 2 +12 2 +13 2 +14 2 +15 2 +16 2 +CREATE TABLE t2 (a int, b int, c int, PRIMARY KEY (a), KEY bkey (b,c)) +ENGINE=InnoDB; +INSERT INTO t2 VALUES (1,1,1),(3,1,1),(2,1,1),(4,1,1); +INSERT INTO t2 SELECT a + 4, 1, 1 FROM t2; +INSERT INTO t2 SELECT a + 8, 1, 1 FROM t2; +EXPLAIN SELECT * FROM t2 WHERE b=1 ORDER BY a; +id 1 +select_type SIMPLE +table t2 +type ref +possible_keys bkey +key bkey +key_len 5 +ref const +rows 8 +Extra Using where; Using index; Using filesort +SELECT * FROM t2 WHERE b=1 ORDER BY a; +a b c +1 1 1 +2 1 1 +3 1 1 +4 1 1 +5 1 1 +6 1 1 +7 1 1 +8 1 1 +9 1 1 +10 1 1 +11 1 1 +12 1 1 +13 1 1 +14 1 1 +15 1 1 +16 1 1 +EXPLAIN SELECT * FROM t2 WHERE b=1 AND c=1 ORDER BY a; +id 1 +select_type SIMPLE +table t2 +type ref +possible_keys bkey +key bkey +key_len 10 +ref const,const +rows 8 +Extra Using where; Using index +SELECT * FROM t2 WHERE b=1 AND c=1 ORDER BY a; +a b c +1 1 1 +2 1 1 +3 1 1 +4 1 1 +5 1 1 +6 1 1 +7 1 1 +8 1 1 +9 1 1 +10 1 1 +11 1 1 +12 1 1 +13 1 1 +14 1 1 +15 1 1 +16 1 1 +EXPLAIN SELECT * FROM t2 WHERE b=1 AND c=1 ORDER BY b,c,a; +id 1 +select_type SIMPLE +table t2 +type ref +possible_keys bkey +key bkey +key_len 10 +ref const,const +rows 8 +Extra Using where; Using index +SELECT * FROM t2 WHERE b=1 AND c=1 ORDER BY b,c,a; +a b c +1 1 1 +2 1 1 +3 1 1 +4 1 1 +5 1 1 +6 1 1 +7 1 1 +8 1 1 +9 1 1 +10 1 1 +11 1 1 +12 1 1 +13 1 1 +14 1 1 +15 1 1 +16 1 1 +EXPLAIN SELECT * FROM t2 WHERE b=1 AND c=1 ORDER BY c,a; +id 1 +select_type SIMPLE +table t2 +type ref +possible_keys bkey +key bkey +key_len 10 +ref const,const +rows 8 +Extra Using where; Using index +SELECT * FROM t2 WHERE b=1 AND c=1 ORDER BY c,a; +a b c +1 1 1 +2 1 1 +3 1 1 +4 1 1 +5 1 1 +6 1 1 +7 1 1 +8 1 1 +9 1 1 +10 1 1 +11 1 1 +12 1 1 +13 1 1 +14 1 1 +15 1 1 +16 1 1 +DROP TABLE t1,t2; +CREATE TABLE t1 (a INT, PRIMARY KEY (a)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1),(2),(3),(4),(5),(6),(7),(8); +INSERT INTO t1 SELECT a + 8 FROM t1; +INSERT INTO t1 SELECT a + 16 FROM t1; +CREATE PROCEDURE p1 () +BEGIN +DECLARE i INT DEFAULT 50; +DECLARE cnt INT; +START TRANSACTION; +ALTER TABLE t1 ENGINE=InnoDB; +COMMIT; +START TRANSACTION; +WHILE (i > 0) DO +SET i = i - 1; +SELECT COUNT(*) INTO cnt FROM t1 LOCK IN SHARE MODE; +END WHILE; +COMMIT; +END;| +CALL p1(); +CALL p1(); +CALL p1(); +DROP PROCEDURE p1; +DROP TABLE t1; create table t1(a text) engine=innodb default charset=utf8; insert into t1 values('aaa'); alter table t1 add index(a(1024)); diff --git a/mysql-test/r/log_state.result b/mysql-test/r/log_state.result index 946797aeec7..38b3ebd6e98 100644 --- a/mysql-test/r/log_state.result +++ b/mysql-test/r/log_state.result @@ -131,7 +131,7 @@ set global general_log=ON; set global log_output=default; show variables like 'log_output'; Variable_name Value -log_output TABLE +log_output FILE set global general_log=OFF; set global log_output=FILE; truncate table mysql.general_log; diff --git a/mysql-test/r/lowercase_table3.result b/mysql-test/r/lowercase_table3.result index 995a2c0d08a..14cff4f98c9 100644 --- a/mysql-test/r/lowercase_table3.result +++ b/mysql-test/r/lowercase_table3.result @@ -4,7 +4,7 @@ SELECT * from T1; a drop table t1; flush tables; -CREATE TABLE t1 (a int) ENGINE=INNODB; -SELECT * from T1; -ERROR 42S02: Table 'test.T1' doesn't exist -drop table t1; +CREATE TABLE bug29839 (a int) ENGINE=INNODB; +SELECT * from BUG29839; +ERROR 42S02: Table 'test.BUG29839' doesn't exist +drop table bug29839; diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index e8c971a41bc..1fa18482b9c 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -3573,6 +3573,28 @@ SELECT * FROM v1; 1 DROP VIEW v1; # +# Bug #29788: mysqldump discards the NO_AUTO_VALUE_ON_ZERO value of +# the SQL_MODE variable after the dumping of triggers. +# +CREATE TABLE t1 (c1 INT); +CREATE TRIGGER t1bd BEFORE DELETE ON t1 FOR EACH ROW BEGIN END; +CREATE TABLE t2 (c1 INT NOT NULL AUTO_INCREMENT PRIMARY KEY); +SET @TMP_SQL_MODE = @@SQL_MODE; +SET SQL_MODE = 'NO_AUTO_VALUE_ON_ZERO'; +INSERT INTO t2 VALUES (0), (1), (2); +SET SQL_MODE = @TMP_SQL_MODE; +SELECT * FROM t2; +c1 +0 +1 +2 +SELECT * FROM t2; +c1 +0 +1 +2 +DROP TABLE t1,t2; +# # End of 5.0 tests # drop table if exists t1; diff --git a/mysql-test/r/mysqlslap.result b/mysql-test/r/mysqlslap.result index bca7919d78c..cc8bc3dac31 100644 --- a/mysql-test/r/mysqlslap.result +++ b/mysql-test/r/mysqlslap.result @@ -167,3 +167,47 @@ SHOW TABLES; select * from t1; SHOW TABLES; DROP SCHEMA IF EXISTS `mysqlslap`; +DROP SCHEMA IF EXISTS `mysqlslap`; +CREATE SCHEMA `mysqlslap`; +use mysqlslap; +set storage_engine=`heap`; +CREATE TABLE t1 (id int, name varchar(64)); +create table t2(foo1 varchar(32), foo2 varchar(32)); +INSERT INTO t1 VALUES (1, 'This is a test'); +insert into t2 values ('test', 'test2'); +SET AUTOCOMMIT=0; +SHOW TABLES; +select * from t1; +select * from t2; +COMMIT; +select * from t1; +select * from t2; +COMMIT; +select * from t1; +select * from t2; +COMMIT; +COMMIT; +SHOW TABLES; +DROP SCHEMA IF EXISTS `mysqlslap`; +DROP SCHEMA IF EXISTS `mysqlslap`; +CREATE SCHEMA `mysqlslap`; +use mysqlslap; +set storage_engine=`myisam`; +CREATE TABLE t1 (id int, name varchar(64)); +create table t2(foo1 varchar(32), foo2 varchar(32)); +INSERT INTO t1 VALUES (1, 'This is a test'); +insert into t2 values ('test', 'test2'); +SET AUTOCOMMIT=0; +SHOW TABLES; +select * from t1; +select * from t2; +COMMIT; +select * from t1; +select * from t2; +COMMIT; +select * from t1; +select * from t2; +COMMIT; +COMMIT; +SHOW TABLES; +DROP SCHEMA IF EXISTS `mysqlslap`; diff --git a/mysql-test/r/sp-prelocking.result b/mysql-test/r/sp-prelocking.result index 5eac54803f0..c19bd1abd26 100644 --- a/mysql-test/r/sp-prelocking.result +++ b/mysql-test/r/sp-prelocking.result @@ -267,4 +267,26 @@ drop table bug_27907_logs; insert into bug_27907_t1(a) values (1); ERROR 42S02: Table 'test.bug_27907_logs' doesn't exist drop table bug_27907_t1; + +Bug#22427 create table if not exists + stored function results in +inconsistent behavior + +Add a test case, the bug itself was fixed by the patch for +Bug#20662 + +drop table if exists t1; +drop function if exists f_bug22427; +create table t1 (i int); +insert into t1 values (1); +create function f_bug22427() returns int return (select max(i) from t1); +select f_bug22427(); +f_bug22427() +1 +create table if not exists t1 select f_bug22427() as i; +Warnings: +Note 1050 Table 't1' already exists +create table t1 select f_bug22427() as i; +ERROR 42S01: Table 't1' already exists +drop table t1; +drop function f_bug22427; End of 5.0 tests diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 273c60110b3..07661f9ae54 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -1,5 +1,7 @@ use test; drop table if exists t1,t2,t3,t4; +drop function if exists f1; +drop function if exists f2; create table t1 ( id char(16) not null default '', data int not null @@ -6249,7 +6251,7 @@ drop table t1,t2; CREATE TABLE t1 (a int auto_increment primary key) engine=MyISAM; CREATE TABLE t2 (a int auto_increment primary key, b int) engine=innodb; set @a=0; -CREATE function bug27354() RETURNS int deterministic +CREATE function bug27354() RETURNS int not deterministic begin insert into t1 values (null); set @a=@a+1; @@ -6433,3 +6435,34 @@ where ROUTINE_NAME = "proc_26302"; ROUTINE_NAME ROUTINE_DEFINITION proc_26302 select 1 /* testing */ drop procedure proc_26302; +CREATE FUNCTION f1() RETURNS INT DETERMINISTIC RETURN 2; +CREATE FUNCTION f2(I INT) RETURNS INT DETERMINISTIC RETURN 3; +CREATE TABLE t1 (c1 INT, INDEX(c1)); +INSERT INTO t1 VALUES (1), (2), (3), (4), (5); +CREATE VIEW v1 AS SELECT c1 FROM t1; +EXPLAIN SELECT * FROM t1 WHERE c1=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref c1 c1 5 const 1 Using where; Using index +EXPLAIN SELECT * FROM t1 WHERE c1=f1(); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref c1 c1 5 const 1 Using where; Using index +EXPLAIN SELECT * FROM v1 WHERE c1=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref c1 c1 5 const 1 Using where; Using index +EXPLAIN SELECT * FROM v1 WHERE c1=f1(); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref c1 c1 5 const 1 Using where; Using index +EXPLAIN SELECT * FROM t1 WHERE c1=f2(10); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref c1 c1 5 const 1 Using where; Using index +EXPLAIN SELECT * FROM t1 WHERE c1=f2(c1); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL c1 5 NULL 5 Using where; Using index +EXPLAIN SELECT * FROM t1 WHERE c1=f2(rand()); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL c1 5 NULL 5 Using where; Using index +DROP VIEW v1; +DROP FUNCTION f1; +DROP FUNCTION f2; +DROP TABLE t1; +End of 5.0 tests diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result index 5d41d60c37a..189722bfe9b 100644 --- a/mysql-test/r/trigger.result +++ b/mysql-test/r/trigger.result @@ -1933,6 +1933,34 @@ Before UPDATE, new=multi-UPDATE, SET for t2, but the trigger is fired, old=multi After UPDATE, new=multi-UPDATE, SET for t2, but the trigger is fired, old=multi-UPDATE drop view v1; drop table t1, t2, t1_op_log; + +Bug#27248 Triggers: error if insert affects temporary table + +The bug was fixed by the fix for Bug#26141 + +drop table if exists t1; +drop temporary table if exists t2; +create table t1 (s1 int); +create temporary table t2 (s1 int); +create trigger t1_bi before insert on t1 for each row insert into t2 values (0); +create trigger t1_bd before delete on t1 for each row delete from t2; +insert into t1 values (0); +insert into t1 values (0); +select * from t1; +s1 +0 +0 +select * from t2; +s1 +0 +0 +delete from t1; +select * from t1; +s1 +select * from t2; +s1 +drop table t1; +drop temporary table t2; End of 5.0 tests drop table if exists table_25411_a; drop table if exists table_25411_b; diff --git a/mysql-test/r/type_enum.result b/mysql-test/r/type_enum.result index ec72a6eb995..051cfe61384 100644 --- a/mysql-test/r/type_enum.result +++ b/mysql-test/r/type_enum.result @@ -1829,4 +1829,28 @@ c1 + 0 0 2 DROP TABLE t1,t2; +CREATE TABLE t1(a enum('a','b','c','d')); +INSERT INTO t1 VALUES (4),(1),(0),(3); +Warnings: +Warning 1265 Data truncated for column 'a' at row 3 +SELECT a FROM t1; +a +d +a + +c +EXPLAIN SELECT a FROM t1 WHERE a=0; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using where +SELECT a FROM t1 WHERE a=0; +a + +ALTER TABLE t1 ADD PRIMARY KEY (a); +EXPLAIN SELECT a FROM t1 WHERE a=0; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 const PRIMARY PRIMARY 1 const 1 Using index +SELECT a FROM t1 WHERE a=0; +a + +DROP TABLE t1; End of 5.1 tests diff --git a/mysql-test/suite/binlog/t/disabled.def b/mysql-test/suite/binlog/t/disabled.def index 76eeb5b00ef..888298bbb09 100644 --- a/mysql-test/suite/binlog/t/disabled.def +++ b/mysql-test/suite/binlog/t/disabled.def @@ -9,6 +9,3 @@ # Do not use any TAB characters for whitespace. # ############################################################################## - -binlog_innodb : Bug#29806 2007-07-15 ingo master.err: InnoDB: Error: MySQL is freeing a thd -binlog_killed : Bug#29806 2007-07-17 ingo master.err: InnoDB: Error: MySQL is freeing a thd diff --git a/mysql-test/t/alter_table.test b/mysql-test/t/alter_table.test index fa50d75b8d2..99c9ae23801 100644 --- a/mysql-test/t/alter_table.test +++ b/mysql-test/t/alter_table.test @@ -902,3 +902,15 @@ SELECT * FROM t1; ALTER TABLE t1 MODIFY COLUMN f3 INT AFTER f2; SELECT * FROM t1; DROP TABLE t1; + +# +# BUG#29957 - alter_table.test fails +# +create table t1 (c char(10) default "Two"); +lock table t1 write; +insert into t1 values (); +alter table t1 modify c char(10) default "Three"; +unlock tables; +select * from t1; +check table t1; +drop table t1; diff --git a/mysql-test/t/check.test b/mysql-test/t/check.test index eb72d75da3c..363f9d419d6 100644 --- a/mysql-test/t/check.test +++ b/mysql-test/t/check.test @@ -37,3 +37,12 @@ Create view v1 as Select * from t1; Check Table v1,t2; drop view v1; drop table t1, t2; + +# +# BUG#26325 - TEMPORARY TABLE "corrupt" after first read, according to CHECK +# TABLE +# +CREATE TEMPORARY TABLE t1(a INT); +CHECK TABLE t1; +REPAIR TABLE t1; +DROP TABLE t1; diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test index dd3037ce88d..341c019af6e 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -1122,6 +1122,35 @@ show create table t1; drop table t1; +--echo +--echo Bug #26104 Bug on foreign key class constructor +--echo +--echo Check that ref_columns is initalized correctly in the constructor +--echo and semantic checks in mysql_prepare_table work. +--echo +--echo We do not need a storage engine that supports foreign keys +--echo for this test, as the checks are purely syntax-based, and the +--echo syntax is supported for all engines. +--echo +--disable_warnings +drop table if exists t1,t2; +--enable_warnings + +create table t1(a int not null, b int not null, primary key (a, b)); +--error ER_WRONG_FK_DEF +create table t2(a int not null, b int not null, c int not null, primary key (a), +foreign key fk_bug26104 (b,c) references t1(a)); +drop table t1; + +# +# Bug#15130:CREATE .. SELECT was denied to use advantages of the SQL_BIG_RESULT. +# +create table t1(f1 int,f2 int); +insert into t1 value(1,1),(1,2),(1,3),(2,1),(2,2),(2,3); +flush status; +create table t2 select sql_big_result f1,count(f2) from t1 group by f1; +show status like 'handler_read%'; +drop table t1,t2; --echo End of 5.0 tests diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index 07c5b4d56a3..368a659d939 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -24,5 +24,4 @@ ctype_big5 : BUG#26711 2007-06-21 Lars Test has never worked on Do mysql_upgrade : Bug#28560 test links to /usr/local/mysql/lib libraries, causes non-determinism and failures on ABI breakage -federated_innodb : Bug#29522 failed assertion in binlog_close_connection() -lowercase_table3 : Bug#29839 2007-07-17 ingo Cannot find table test/T1 from the internal data dictionary +federated_transactions : Bug#29523 Transactions do not work diff --git a/mysql-test/t/federated.test b/mysql-test/t/federated.test index a75eae8f8a0..6597c77e798 100644 --- a/mysql-test/t/federated.test +++ b/mysql-test/t/federated.test @@ -32,25 +32,28 @@ CREATE TABLE federated.t1 ( # test non-existant table --replace_result $SLAVE_MYPORT SLAVE_PORT ---error 1434 eval CREATE TABLE federated.t1 ( `id` int(20) NOT NULL, `name` varchar(32) NOT NULL default '' ) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t3'; +--error 1431 +SELECT * FROM federated.t1; +DROP TABLE federated.t1; # test bad user/password --replace_result $SLAVE_MYPORT SLAVE_PORT ---error 1429 eval CREATE TABLE federated.t1 ( `id` int(20) NOT NULL, `name` varchar(32) NOT NULL default '' ) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 CONNECTION='mysql://user:pass@127.0.0.1:$SLAVE_MYPORT/federated/t1'; +--error 1429 +SELECT * FROM federated.t1; +DROP TABLE federated.t1; -DROP TABLE IF EXISTS federated.t1; # # correct connection, same named tables --replace_result $SLAVE_MYPORT SLAVE_PORT eval CREATE TABLE federated.t1 ( @@ -1723,4 +1726,30 @@ connection slave; drop table federated.t1; +# +# BUG#29875 Disable support for transactions +# +connection slave; +CREATE TABLE federated.t1 (a INT PRIMARY KEY) DEFAULT CHARSET=utf8; +connection master; +--replace_result $SLAVE_MYPORT SLAVE_PORT +eval CREATE TABLE federated.t1 (a INT PRIMARY KEY) + ENGINE=FEDERATED + CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1' + DEFAULT CHARSET=utf8; + +SELECT transactions FROM information_schema.engines WHERE engine="FEDERATED"; +INSERT INTO federated.t1 VALUES (1); +SET autocommit=0; +INSERT INTO federated.t1 VALUES (2); +ROLLBACK; +SET autocommit=1; +SELECT * FROM federated.t1; + +DROP TABLE federated.t1; +connection slave; +DROP TABLE federated.t1; + +--echo End of 5.1 tests + source include/federated_cleanup.inc; diff --git a/mysql-test/t/federated_bug_25714.test b/mysql-test/t/federated_bug_25714.test new file mode 100644 index 00000000000..9c185181511 --- /dev/null +++ b/mysql-test/t/federated_bug_25714.test @@ -0,0 +1,47 @@ +--source include/have_bug25714.inc +source include/federated.inc; + + +connection slave; +--disable_warnings +DROP TABLE IF EXISTS federated.bug_13118_table; +--enable_warnings + +CREATE TABLE federated.t1 ( + `id` int auto_increment primary key, + `value` int + ) ENGINE=MyISAM; +INSERT INTO federated.t1 SET value=1; +INSERT INTO federated.t1 SET value=2; +INSERT INTO federated.t1 SET value=2; + +connection master; +--disable_warnings +DROP TABLE IF EXISTS federated.t1; +--enable_warnings + +--replace_result $SLAVE_MYPORT SLAVE_PORT +eval CREATE TABLE federated.t1 ( + `id` int auto_increment primary key, + `value` int + ) ENGINE=FEDERATED + CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; + +SELECT * from federated.t1; + +INSERT INTO federated.t1 SET value=4; + +SELECT LAST_INSERT_ID(); + +--exec $MYSQL_BUG25714 $SLAVE_MYPORT +--exec $MYSQL_BUG25714 $MASTER_MYPORT + +SELECT * from federated.t1; + +DROP TABLE federated.t1; +connection slave; +DROP TABLE federated.t1; + + +source include/federated_cleanup.inc; + diff --git a/mysql-test/t/having.test b/mysql-test/t/having.test index 41266cc6d32..683abfd3783 100644 --- a/mysql-test/t/having.test +++ b/mysql-test/t/having.test @@ -151,6 +151,32 @@ EXPLAIN SELECT 0 AS x, a FROM t1 GROUP BY x,a HAVING x=1 AND a > 1; DROP table t1; +# +# Bug #29911: HAVING clause depending on constant table and evaluated to false +# + +CREATE TABLE t1 (a int PRIMARY KEY); +CREATE TABLE t2 (b int PRIMARY KEY, a int); +CREATE TABLE t3 (b int, flag int); + +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (1,1), (2,1), (3,1); +INSERT INTO t3(b,flag) VALUES (2, 1); + +SELECT t1.a + FROM t1 INNER JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t2.b=t3.b + GROUP BY t1.a, t2.b HAVING MAX(t3.flag)=0; + +SELECT DISTINCT t1.a, MAX(t3.flag) + FROM t1 INNER JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t2.b=t3.b + GROUP BY t1.a, t2.b HAVING MAX(t3.flag)=0; + +SELECT DISTINCT t1.a + FROM t1 INNER JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t2.b=t3.b + GROUP BY t1.a, t2.b HAVING MAX(t3.flag)=0; + +DROP TABLE t1,t2,t3; + # End of 4.1 tests # diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index 96b2ffda7d6..140aac3b9c3 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -1178,7 +1178,7 @@ drop table t2; # Clean up filename -- embedded server reports whole path without .frm, # regular server reports relative path with .frm (argh!) --replace_result \\ / $MYSQL_TEST_DIR . /var/master-data/ / t2.frm t2 ---error 1005 +--error ER_WRONG_FK_DEF create table t2 (id int(11) not null, id2 int(11) not null, constraint t1_id_fk foreign key (id2,id) references t1 (id)) engine = innodb; # bug#3749 diff --git a/mysql-test/t/lowercase_table3.test b/mysql-test/t/lowercase_table3.test index 75f6e5188c5..51385b4b178 100644 --- a/mysql-test/t/lowercase_table3.test +++ b/mysql-test/t/lowercase_table3.test @@ -27,9 +27,9 @@ flush tables; # storing things in lower case. # -CREATE TABLE t1 (a int) ENGINE=INNODB; +CREATE TABLE bug29839 (a int) ENGINE=INNODB; --error 1146 -SELECT * from T1; -drop table t1; +SELECT * from BUG29839; +drop table bug29839; # End of 4.1 tests diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test index 38d8a07fe48..4e8d3ae916e 100644 --- a/mysql-test/t/mysqldump.test +++ b/mysql-test/t/mysqldump.test @@ -1555,6 +1555,28 @@ SELECT * FROM v1; DROP VIEW v1; --echo # +--echo # Bug #29788: mysqldump discards the NO_AUTO_VALUE_ON_ZERO value of +--echo # the SQL_MODE variable after the dumping of triggers. +--echo # + +CREATE TABLE t1 (c1 INT); +CREATE TRIGGER t1bd BEFORE DELETE ON t1 FOR EACH ROW BEGIN END; + +CREATE TABLE t2 (c1 INT NOT NULL AUTO_INCREMENT PRIMARY KEY); + +SET @TMP_SQL_MODE = @@SQL_MODE; +SET SQL_MODE = 'NO_AUTO_VALUE_ON_ZERO'; +INSERT INTO t2 VALUES (0), (1), (2); +SET SQL_MODE = @TMP_SQL_MODE; +SELECT * FROM t2; + +--exec $MYSQL_DUMP --routines test >$MYSQLTEST_VARDIR/tmp/bug29788.sql +--exec $MYSQL test < $MYSQLTEST_VARDIR/tmp/bug29788.sql +SELECT * FROM t2; + +DROP TABLE t1,t2; + +--echo # --echo # End of 5.0 tests --echo # diff --git a/mysql-test/t/mysqlslap.test b/mysql-test/t/mysqlslap.test index 2a7bbfed932..192aefb0e03 100644 --- a/mysql-test/t/mysqlslap.test +++ b/mysql-test/t/mysqlslap.test @@ -36,3 +36,5 @@ --exec $MYSQL_SLAP --silent --concurrency=5 --iterations=1 --number-int-cols=2 --number-char-cols=3 --auto-generate-sql --auto-generate-sql-guid-primary --auto-generate-sql-load-type=key --auto-generate-sql-execute-number=5 --auto-generate-sql-secondary-indexes=3 --exec $MYSQL_SLAP --only-print --delimiter=";" --query="select * from t1;select * from t2" --create="CREATE TABLE t1 (id int, name varchar(64)); create table t2(foo1 varchar(32), foo2 varchar(32)); INSERT INTO t1 VALUES (1, 'This is a test'); insert into t2 values ('test', 'test2')" --engine="heap,myisam" --post-query="SHOW TABLES" --pre-query="SHOW TABLES"; + + --exec $MYSQL_SLAP --only-print --delimiter=";" --query="select * from t1;select * from t2" --create="CREATE TABLE t1 (id int, name varchar(64)); create table t2(foo1 varchar(32), foo2 varchar(32)); INSERT INTO t1 VALUES (1, 'This is a test'); insert into t2 values ('test', 'test2')" --engine="heap,myisam" --post-query="SHOW TABLES" --pre-query="SHOW TABLES" --number-of-queries=6 --commit=1; diff --git a/mysql-test/t/sp-prelocking.test b/mysql-test/t/sp-prelocking.test index ec5b7fbad7c..60e97260839 100644 --- a/mysql-test/t/sp-prelocking.test +++ b/mysql-test/t/sp-prelocking.test @@ -333,4 +333,27 @@ insert into bug_27907_t1(a) values (1); drop table bug_27907_t1; +--echo +--echo Bug#22427 create table if not exists + stored function results in +--echo inconsistent behavior +--echo +--echo Add a test case, the bug itself was fixed by the patch for +--echo Bug#20662 +--echo +--disable_warnings +drop table if exists t1; +drop function if exists f_bug22427; +--enable_warnings +create table t1 (i int); +insert into t1 values (1); +create function f_bug22427() returns int return (select max(i) from t1); +select f_bug22427(); +# Until this bug was fixed, the following emitted error +# ERROR 1213: Deadlock found when trying to get lock +create table if not exists t1 select f_bug22427() as i; +--error ER_TABLE_EXISTS_ERROR +create table t1 select f_bug22427() as i; +drop table t1; +drop function f_bug22427; + --echo End of 5.0 tests diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 7bd20d226c2..dfda1b7a6ab 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -24,6 +24,8 @@ use test; # --disable_warnings drop table if exists t1,t2,t3,t4; +drop function if exists f1; +drop function if exists f2; --enable_warnings create table t1 ( id char(16) not null default '', @@ -7214,7 +7216,7 @@ CREATE TABLE t2 (a int auto_increment primary key, b int) engine=innodb; set @a=0; delimiter |; -CREATE function bug27354() RETURNS int deterministic +CREATE function bug27354() RETURNS int not deterministic begin insert into t1 values (null); set @a=@a+1; @@ -7368,3 +7370,33 @@ where ROUTINE_NAME = "proc_26302"; drop procedure proc_26302; +# Bug #29338: no optimization for stored functions with a trivial body +# always returning constant. +# + +CREATE FUNCTION f1() RETURNS INT DETERMINISTIC RETURN 2; +CREATE FUNCTION f2(I INT) RETURNS INT DETERMINISTIC RETURN 3; + +CREATE TABLE t1 (c1 INT, INDEX(c1)); + +INSERT INTO t1 VALUES (1), (2), (3), (4), (5); + +CREATE VIEW v1 AS SELECT c1 FROM t1; + +EXPLAIN SELECT * FROM t1 WHERE c1=1; +EXPLAIN SELECT * FROM t1 WHERE c1=f1(); + +EXPLAIN SELECT * FROM v1 WHERE c1=1; +EXPLAIN SELECT * FROM v1 WHERE c1=f1(); + +EXPLAIN SELECT * FROM t1 WHERE c1=f2(10); +EXPLAIN SELECT * FROM t1 WHERE c1=f2(c1); +EXPLAIN SELECT * FROM t1 WHERE c1=f2(rand()); + + +DROP VIEW v1; +DROP FUNCTION f1; +DROP FUNCTION f2; +DROP TABLE t1; + +--echo End of 5.0 tests diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test index 8db432b27c3..c7251040544 100644 --- a/mysql-test/t/trigger.test +++ b/mysql-test/t/trigger.test @@ -2194,6 +2194,29 @@ drop table t1, t2, t1_op_log; # # TODO: test LOAD DATA INFILE +# +--echo +--echo Bug#27248 Triggers: error if insert affects temporary table +--echo +--echo The bug was fixed by the fix for Bug#26141 +--echo +--disable_warnings +drop table if exists t1; +drop temporary table if exists t2; +--enable_warnings +create table t1 (s1 int); +create temporary table t2 (s1 int); +create trigger t1_bi before insert on t1 for each row insert into t2 values (0); +create trigger t1_bd before delete on t1 for each row delete from t2; +insert into t1 values (0); +insert into t1 values (0); +select * from t1; +select * from t2; +delete from t1; +select * from t1; +select * from t2; +drop table t1; +drop temporary table t2; --echo End of 5.0 tests # diff --git a/mysql-test/t/type_enum.test b/mysql-test/t/type_enum.test index 4d5d5ec8a86..2043342e2c8 100644 --- a/mysql-test/t/type_enum.test +++ b/mysql-test/t/type_enum.test @@ -200,4 +200,24 @@ CREATE TABLE t2 SELECT * FROM t1; SELECT c1 + 0 FROM t2; DROP TABLE t1,t2; + +# +# Bug#29661: Lookup by 0 for a primary index over a enum type +# + +CREATE TABLE t1(a enum('a','b','c','d')); +INSERT INTO t1 VALUES (4),(1),(0),(3); + +SELECT a FROM t1; + +EXPLAIN SELECT a FROM t1 WHERE a=0; +SELECT a FROM t1 WHERE a=0; + +ALTER TABLE t1 ADD PRIMARY KEY (a); + +EXPLAIN SELECT a FROM t1 WHERE a=0; +SELECT a FROM t1 WHERE a=0; + +DROP TABLE t1; + --echo End of 5.1 tests diff --git a/sql-common/client.c b/sql-common/client.c index 6d63c457390..cdf9eed8574 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -1226,12 +1226,12 @@ unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields, /* fields count may be wrong */ DBUG_ASSERT((uint) (field - result) < fields); cli_fetch_lengths(&lengths[0], row->data, default_value ? 8 : 7); - field->catalog = strdup_root(alloc,(char*) row->data[0]); - field->db = strdup_root(alloc,(char*) row->data[1]); - field->table = strdup_root(alloc,(char*) row->data[2]); - field->org_table= strdup_root(alloc,(char*) row->data[3]); - field->name = strdup_root(alloc,(char*) row->data[4]); - field->org_name = strdup_root(alloc,(char*) row->data[5]); + field->catalog= strmake_root(alloc,(char*) row->data[0], lengths[0]); + field->db= strmake_root(alloc,(char*) row->data[1], lengths[1]); + field->table= strmake_root(alloc,(char*) row->data[2], lengths[2]); + field->org_table= strmake_root(alloc,(char*) row->data[3], lengths[3]); + field->name= strmake_root(alloc,(char*) row->data[4], lengths[4]); + field->org_name= strmake_root(alloc,(char*) row->data[5], lengths[5]); field->catalog_length= lengths[0]; field->db_length= lengths[1]; @@ -1252,7 +1252,7 @@ unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields, field->flags|= NUM_FLAG; if (default_value && row->data[7]) { - field->def=strdup_root(alloc,(char*) row->data[7]); + field->def=strmake_root(alloc,(char*) row->data[7], lengths[7]); field->def_length= lengths[7]; } else diff --git a/sql/field.cc b/sql/field.cc index a970a6e4318..3213f84ee3e 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -7901,8 +7901,11 @@ int Field_enum::store(longlong nr, bool unsigned_val) if ((ulonglong) nr > typelib->count || nr == 0) { set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1); - nr=0; - error=1; + if (nr != 0 || table->in_use->count_cuted_fields) + { + nr= 0; + error= 1; + } } store_type((ulonglong) (uint) nr); return error; diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 0b8ffd4a2fb..dd29eb17059 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -4383,7 +4383,10 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type) trans= ndb->startTransaction(); if (trans == NULL) + { + thd_ndb->lock_count= 0; ERR_RETURN(ndb->getNdbError()); + } thd_ndb->init_open_tables(); thd_ndb->stmt= trans; thd_ndb->query_state&= NDB_QUERY_NORMAL; @@ -4409,7 +4412,10 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type) trans= ndb->startTransaction(); if (trans == NULL) + { + thd_ndb->lock_count= 0; ERR_RETURN(ndb->getNdbError()); + } thd_ndb->init_open_tables(); thd_ndb->all= trans; thd_ndb->query_state&= NDB_QUERY_NORMAL; diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index e4924e8e8f2..d46b3a3bb08 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -1142,6 +1142,12 @@ int ha_partition::prepare_new_partition(TABLE *table, create_flag= TRUE; if ((error= file->ha_open(table, part_name, m_mode, m_open_test_lock))) goto error; + /* + Note: if you plan to add another call that may return failure, + better to do it before external_lock() as cleanup_new_partition() + assumes that external_lock() is last call that may fail here. + Otherwise see description for cleanup_new_partition(). + */ if ((error= file->external_lock(current_thd, m_lock_type))) goto error; @@ -1164,6 +1170,14 @@ error: NONE DESCRIPTION + This function is called immediately after prepare_new_partition() in + case the latter fails. + + In prepare_new_partition() last call that may return failure is + external_lock(). That means if prepare_new_partition() fails, + partition does not have external lock. Thus no need to call + external_lock(F_UNLCK) here. + TODO: We must ensure that in the case that we get an error during the process that we call external_lock with F_UNLCK, close the table and delete the @@ -1182,7 +1196,6 @@ void ha_partition::cleanup_new_partition(uint part_count) m_file= m_added_file; m_added_file= NULL; - external_lock(current_thd, F_UNLCK); /* delete_table also needed, a bit more complex */ close(); diff --git a/sql/handler.cc b/sql/handler.cc index 2d836b30862..55e2e478027 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -2355,7 +2355,13 @@ static bool update_frm_version(TABLE *table) int result= 1; DBUG_ENTER("update_frm_version"); - if (table->s->mysql_version != MYSQL_VERSION_ID) + /* + No need to update frm version in case table was created or checked + by server with the same version. This also ensures that we do not + update frm version for temporary tables as this code doesn't support + temporary tables. + */ + if (table->s->mysql_version == MYSQL_VERSION_ID) DBUG_RETURN(0); strxmov(path, table->s->normalized_path.str, reg_ext, NullS); diff --git a/sql/item_func.cc b/sql/item_func.cc index f14091b4592..4012371bedb 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -5599,10 +5599,20 @@ Item_func_sp::fix_fields(THD *thd, Item **ref) #endif /* ! NO_EMBEDDED_ACCESS_CHECKS */ } + if (!m_sp->m_chistics->detistic) + used_tables_cache |= RAND_TABLE_BIT; DBUG_RETURN(res); } +void Item_func_sp::update_used_tables() +{ + Item_func::update_used_tables(); + if (!m_sp->m_chistics->detistic) + used_tables_cache |= RAND_TABLE_BIT; +} + + /* uuid_short handling. diff --git a/sql/item_func.h b/sql/item_func.h index 568effb2f63..ea22e35773d 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -1472,7 +1472,7 @@ public: virtual ~Item_func_sp() {} - table_map used_tables() const { return RAND_TABLE_BIT; } + void update_used_tables(); void cleanup(); diff --git a/sql/lock.cc b/sql/lock.cc index 4260a031def..63d0807b975 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -60,6 +60,11 @@ - When calling UNLOCK TABLES we call mysql_unlock_tables() for all tables used in LOCK TABLES + If table_handler->external_lock(thd, locktype) fails, we call + table_handler->external_lock(thd, F_UNLCK) for each table that was locked, + excluding one that caused failure. That means handler must cleanup itself + in case external_lock() fails. + TODO: Change to use my_malloc() ONLY when using LOCK TABLES command or when we are forced to use mysql_lock_merge. @@ -269,8 +274,9 @@ static int lock_external(THD *thd, TABLE **tables, uint count) if ((error=(*tables)->file->ha_external_lock(thd,lock_type))) { print_lock_error(error, (*tables)->file->table_type()); - for (; i-- ; tables--) + while (--i) { + tables--; (*tables)->file->ha_external_lock(thd, F_UNLCK); (*tables)->current_lock=F_UNLCK; } diff --git a/sql/set_var.cc b/sql/set_var.cc index bd5234b42be..7f3e808090d 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -2220,9 +2220,9 @@ void sys_var_log_output::set_default(THD *thd, enum_var_type type) { pthread_mutex_lock(&LOCK_global_system_variables); logger.lock(); - logger.init_slow_log(LOG_TABLE); - logger.init_general_log(LOG_TABLE); - *value= LOG_TABLE; + logger.init_slow_log(LOG_FILE); + logger.init_general_log(LOG_FILE); + *value= LOG_FILE; logger.unlock(); pthread_mutex_unlock(&LOCK_global_system_variables); } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 6fd57c5a428..f1319010270 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -64,11 +64,11 @@ Prelock_error_handler::handle_error(uint sql_errno, if (sql_errno == ER_NO_SUCH_TABLE) { m_handled_errors++; - return TRUE; // 'TRUE', as per coding style + return TRUE; } m_unhandled_errors++; - return FALSE; // 'FALSE', as per coding style + return FALSE; } @@ -3533,7 +3533,7 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags) */ for (tables= *start; tables ;tables= tables->next_global) { - safe_to_ignore_table= FALSE; // 'FALSE', as per coding style + safe_to_ignore_table= FALSE; if (tables->lock_type == TL_WRITE_DEFAULT) { @@ -3797,13 +3797,6 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type) if (table) { -#if defined( __WIN__) - /* Win32 can't drop a file that is open */ - if (lock_type == TL_WRITE_ALLOW_READ) - { - lock_type= TL_WRITE; - } -#endif /* __WIN__ */ table_list->lock_type= lock_type; table_list->table= table; table->grant= table_list->grant; diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index cab9ef94d6d..39a7aebcc5d 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -878,10 +878,14 @@ ulong Query_cache::resize(ulong query_cache_size_arg) query_cache_size= query_cache_size_arg; ulong new_query_cache_size= init_cache(); - DBUG_EXECUTE("check_querycache",check_integrity(0);); - STRUCT_LOCK(&structure_guard_mutex); m_cache_status= Query_cache::NO_FLUSH_IN_PROGRESS; + /* + Must not call check_integrity() with + m_cache_status != Query_cache::NO_FLUSH_IN_PROGRESS. + It would wait forever. + */ + DBUG_EXECUTE("check_querycache",check_integrity(1);); pthread_cond_signal(&COND_cache_status_changed); STRUCT_UNLOCK(&structure_guard_mutex); @@ -4025,6 +4029,10 @@ my_bool Query_cache::check_integrity(bool locked) Query_cache_block * block = first_block; do { + /* When checking at system start, there is no block. */ + if (!block) + break; + DBUG_PRINT("qcache", ("block 0x%lx, type %u...", (ulong) block, (uint) block->type)); // Check allignment diff --git a/sql/sql_class.h b/sql/sql_class.h index 7fa66893f69..71c13e001ee 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -189,7 +189,7 @@ public: Table_ident *table, List<Key_part_spec> &ref_cols, uint delete_opt_arg, uint update_opt_arg, uint match_opt_arg) :Key(FOREIGN_KEY, name_arg, &default_key_create_info, 0, cols), - ref_table(table), ref_columns(cols), + ref_table(table), ref_columns(ref_cols), delete_opt(delete_opt_arg), update_opt(update_opt_arg), match_opt(match_opt_arg) {} diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index b14241bbef3..b747c706f75 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1763,18 +1763,18 @@ Delayed_insert *find_handler(THD *thd, TABLE_LIST *table_list) thd->proc_info="waiting for delay_list"; pthread_mutex_lock(&LOCK_delayed_insert); // Protect master list I_List_iterator<Delayed_insert> it(delayed_threads); - Delayed_insert *tmp; - while ((tmp=it++)) + Delayed_insert *di; + while ((di= it++)) { - if (!strcmp(tmp->thd.db, table_list->db) && - !strcmp(table_list->table_name, tmp->table->s->table_name.str)) + if (!strcmp(table_list->db, di->table_list.db) && + !strcmp(table_list->table_name, di->table_list.table_name)) { - tmp->lock(); + di->lock(); break; } } pthread_mutex_unlock(&LOCK_delayed_insert); // For unlink from list - return tmp; + return di; } @@ -1800,21 +1800,41 @@ Delayed_insert *find_handler(THD *thd, TABLE_LIST *table_list) Two latter cases indicate a request for lock upgrade. XXX: why do we regard INSERT DELAYED into a view as an error and - do not simply a lock upgrade? + do not simply perform a lock upgrade? + + TODO: The approach with using two mutexes to work with the + delayed thread list -- LOCK_delayed_insert and + LOCK_delayed_create -- is redundant, and we only need one of + them to protect the list. The reason we have two locks is that + we do not want to block look-ups in the list while we're waiting + for the newly created thread to open the delayed table. However, + this wait itself is redundant -- we always call get_local_table + later on, and there wait again until the created thread acquires + a table lock. + + As is redundant the concept of locks_in_memory, since we already + have another counter with similar semantics - tables_in_use, + both of them are devoted to counting the number of producers for + a given consumer (delayed insert thread), only at different + stages of producer-consumer relationship. + + 'dead' and 'status' variables in Delayed_insert are redundant + too, since there is already 'di->thd.killed' and + di->stacked_inserts. */ static bool delayed_get_table(THD *thd, TABLE_LIST *table_list) { int error; - Delayed_insert *tmp; + Delayed_insert *di; DBUG_ENTER("delayed_get_table"); /* Must be set in the parser */ DBUG_ASSERT(table_list->db); /* Find the thread which handles this table. */ - if (!(tmp=find_handler(thd,table_list))) + if (!(di= find_handler(thd, table_list))) { /* No match. Create a new thread to handle the table, but @@ -1828,9 +1848,9 @@ bool delayed_get_table(THD *thd, TABLE_LIST *table_list) The first search above was done without LOCK_delayed_create. Another thread might have created the handler in between. Search again. */ - if (! (tmp= find_handler(thd, table_list))) + if (! (di= find_handler(thd, table_list))) { - if (!(tmp=new Delayed_insert())) + if (!(di= new Delayed_insert())) { my_error(ER_OUTOFMEMORY,MYF(0),sizeof(Delayed_insert)); thd->fatal_error(); @@ -1839,28 +1859,30 @@ bool delayed_get_table(THD *thd, TABLE_LIST *table_list) pthread_mutex_lock(&LOCK_thread_count); thread_count++; pthread_mutex_unlock(&LOCK_thread_count); - tmp->thd.set_db(table_list->db, strlen(table_list->db)); - tmp->thd.query= my_strdup(table_list->table_name,MYF(MY_WME)); - if (tmp->thd.db == NULL || tmp->thd.query == NULL) + di->thd.set_db(table_list->db, strlen(table_list->db)); + di->thd.query= my_strdup(table_list->table_name, MYF(MY_WME)); + if (di->thd.db == NULL || di->thd.query == NULL) { /* The error is reported */ - delete tmp; + delete di; thd->fatal_error(); goto end_create; } - tmp->table_list= *table_list; // Needed to open table - tmp->table_list.alias= tmp->table_list.table_name= tmp->thd.query; - tmp->lock(); - pthread_mutex_lock(&tmp->mutex); - if ((error=pthread_create(&tmp->thd.real_id,&connection_attrib, - handle_delayed_insert,(void*) tmp))) + di->table_list= *table_list; // Needed to open table + /* Replace volatile strings with local copies */ + di->table_list.alias= di->table_list.table_name= di->thd.query; + di->table_list.db= di->thd.db; + di->lock(); + pthread_mutex_lock(&di->mutex); + if ((error= pthread_create(&di->thd.real_id, &connection_attrib, + handle_delayed_insert, (void*) di))) { DBUG_PRINT("error", ("Can't create thread to handle delayed insert (error %d)", error)); - pthread_mutex_unlock(&tmp->mutex); - tmp->unlock(); - delete tmp; + pthread_mutex_unlock(&di->mutex); + di->unlock(); + delete di; my_error(ER_CANT_CREATE_THREAD, MYF(0), error); thd->fatal_error(); goto end_create; @@ -1868,15 +1890,15 @@ bool delayed_get_table(THD *thd, TABLE_LIST *table_list) /* Wait until table is open */ thd->proc_info="waiting for handler open"; - while (!tmp->thd.killed && !tmp->table && !thd->killed) + while (!di->thd.killed && !di->table && !thd->killed) { - pthread_cond_wait(&tmp->cond_client,&tmp->mutex); + pthread_cond_wait(&di->cond_client, &di->mutex); } - pthread_mutex_unlock(&tmp->mutex); + pthread_mutex_unlock(&di->mutex); thd->proc_info="got old table"; - if (tmp->thd.killed) + if (di->thd.killed) { - if (tmp->thd.net.report_error) + if (di->thd.net.report_error) { /* Copy the error message. Note that we don't treat fatal @@ -1884,31 +1906,34 @@ bool delayed_get_table(THD *thd, TABLE_LIST *table_list) main thread. Use of my_message will enable stored procedures continue handlers. */ - my_message(tmp->thd.net.last_errno, tmp->thd.net.last_error, + my_message(di->thd.net.last_errno, di->thd.net.last_error, MYF(0)); } - tmp->unlock(); + di->unlock(); goto end_create; } if (thd->killed) { - tmp->unlock(); + di->unlock(); goto end_create; } + pthread_mutex_lock(&LOCK_delayed_insert); + delayed_threads.append(di); + pthread_mutex_unlock(&LOCK_delayed_insert); } pthread_mutex_unlock(&LOCK_delayed_create); } - pthread_mutex_lock(&tmp->mutex); - table_list->table= tmp->get_local_table(thd); - pthread_mutex_unlock(&tmp->mutex); + pthread_mutex_lock(&di->mutex); + table_list->table= di->get_local_table(thd); + pthread_mutex_unlock(&di->mutex); if (table_list->table) { DBUG_ASSERT(thd->net.report_error == 0); - thd->di=tmp; + thd->di= di; } /* Unlock the delayed insert object after its last access. */ - tmp->unlock(); + di->unlock(); DBUG_RETURN((table_list->table == NULL)); end_create: @@ -1938,7 +1963,7 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd) my_ptrdiff_t adjust_ptrs; Field **field,**org_field, *found_next_number_field; TABLE *copy; - TABLE_SHARE *share= table->s; + TABLE_SHARE *share; uchar *bitmap; DBUG_ENTER("Delayed_insert::get_local_table"); @@ -1962,6 +1987,7 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd) goto error; } } + share= table->s; /* Allocate memory for the TABLE object, the field pointers array, and @@ -2157,26 +2183,26 @@ void kill_delayed_threads(void) VOID(pthread_mutex_lock(&LOCK_delayed_insert)); // For unlink from list I_List_iterator<Delayed_insert> it(delayed_threads); - Delayed_insert *tmp; - while ((tmp=it++)) + Delayed_insert *di; + while ((di= it++)) { - tmp->thd.killed= THD::KILL_CONNECTION; - if (tmp->thd.mysys_var) + di->thd.killed= THD::KILL_CONNECTION; + if (di->thd.mysys_var) { - pthread_mutex_lock(&tmp->thd.mysys_var->mutex); - if (tmp->thd.mysys_var->current_cond) + pthread_mutex_lock(&di->thd.mysys_var->mutex); + if (di->thd.mysys_var->current_cond) { /* We need the following test because the main mutex may be locked in handle_delayed_insert() */ - if (&tmp->mutex != tmp->thd.mysys_var->current_mutex) - pthread_mutex_lock(tmp->thd.mysys_var->current_mutex); - pthread_cond_broadcast(tmp->thd.mysys_var->current_cond); - if (&tmp->mutex != tmp->thd.mysys_var->current_mutex) - pthread_mutex_unlock(tmp->thd.mysys_var->current_mutex); + if (&di->mutex != di->thd.mysys_var->current_mutex) + pthread_mutex_lock(di->thd.mysys_var->current_mutex); + pthread_cond_broadcast(di->thd.mysys_var->current_cond); + if (&di->mutex != di->thd.mysys_var->current_mutex) + pthread_mutex_unlock(di->thd.mysys_var->current_mutex); } - pthread_mutex_unlock(&tmp->thd.mysys_var->mutex); + pthread_mutex_unlock(&di->thd.mysys_var->mutex); } } VOID(pthread_mutex_unlock(&LOCK_delayed_insert)); // For unlink from list @@ -2250,11 +2276,6 @@ pthread_handler_t handle_delayed_insert(void *arg) } di->table->copy_blobs=1; - /* One can now use this */ - pthread_mutex_lock(&LOCK_delayed_insert); - delayed_threads.append(di); - pthread_mutex_unlock(&LOCK_delayed_insert); - /* Tell client that the thread is initialized */ pthread_cond_signal(&di->cond_client); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 9f69e7dee05..8ab4dee12ac 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -124,7 +124,7 @@ Lex_input_stream::Lex_input_stream(THD *thd, m_tok_start_prev(NULL), m_buf(buffer), m_buf_length(length), - m_echo(true), + m_echo(TRUE), m_cpp_tok_start(NULL), m_cpp_tok_start_prev(NULL), m_cpp_tok_end(NULL), @@ -1200,7 +1200,7 @@ int MYSQLlex(void *arg, void *yythd) { lip->in_comment= DISCARD_COMMENT; /* Accept '/' '*' '!', but do not keep this marker. */ - lip->set_echo(false); + lip->set_echo(FALSE); lip->yySkip(); lip->yySkip(); lip->yySkip(); @@ -1233,7 +1233,7 @@ int MYSQLlex(void *arg, void *yythd) if (version <= MYSQL_VERSION_ID) { /* Expand the content of the special comment as real code */ - lip->set_echo(true); + lip->set_echo(TRUE); state=MY_LEX_START; break; } @@ -1241,7 +1241,7 @@ int MYSQLlex(void *arg, void *yythd) else { state=MY_LEX_START; - lip->set_echo(true); + lip->set_echo(TRUE); break; } } @@ -1261,7 +1261,7 @@ int MYSQLlex(void *arg, void *yythd) if (! lip->eof()) lip->yySkip(); // remove last '/' state = MY_LEX_START; // Try again - lip->set_echo(true); + lip->set_echo(TRUE); break; case MY_LEX_END_LONG_COMMENT: if ((lip->in_comment != NO_COMMENT) && lip->yyPeek() == '/') @@ -1272,7 +1272,7 @@ int MYSQLlex(void *arg, void *yythd) lip->set_echo(lip->in_comment == PRESERVE_COMMENT); lip->yySkipn(2); /* And start recording the tokens again */ - lip->set_echo(true); + lip->set_echo(TRUE); lip->in_comment=NO_COMMENT; state=MY_LEX_START; } @@ -1297,7 +1297,7 @@ int MYSQLlex(void *arg, void *yythd) lip->found_semicolon= lip->get_ptr(); thd->server_status|= SERVER_MORE_RESULTS_EXISTS; lip->next_state= MY_LEX_END; - lip->set_echo(true); + lip->set_echo(TRUE); return (END_OF_INPUT); } state= MY_LEX_CHAR; // Return ';' @@ -1309,9 +1309,9 @@ int MYSQLlex(void *arg, void *yythd) if (lip->eof()) { lip->yyUnget(); // Reject the last '\0' - lip->set_echo(false); + lip->set_echo(FALSE); lip->yySkip(); - lip->set_echo(true); + lip->set_echo(TRUE); lip->next_state=MY_LEX_END; // Mark for next loop return(END_OF_INPUT); } @@ -1770,7 +1770,7 @@ TABLE_LIST *st_select_lex_node::add_table_to_list (THD *thd, Table_ident *table, LEX_STRING *alias, ulong table_join_options, thr_lock_type flags, - List<index_hint> *hints, + List<Index_hint> *hints, LEX_STRING *option) { return 0; @@ -2723,7 +2723,7 @@ void st_select_lex::set_index_hint_type(enum index_hint_type type, void st_select_lex::alloc_index_hints (THD *thd) { - index_hints= new (thd->mem_root) List<index_hint>(); + index_hints= new (thd->mem_root) List<Index_hint>(); } @@ -2744,7 +2744,7 @@ void st_select_lex::alloc_index_hints (THD *thd) bool st_select_lex::add_index_hint (THD *thd, char *str, uint length) { return index_hints->push_front (new (thd->mem_root) - index_hint(current_index_hint_type, + Index_hint(current_index_hint_type, current_index_hint_clause, str, length)); } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 4ac59fbacde..b769930958e 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -236,7 +236,7 @@ typedef uchar index_clause_map; INDEX_HINT_MASK_ORDER) /* Single element of an USE/FORCE/IGNORE INDEX list specified as a SQL hint */ -class index_hint : public Sql_alloc +class Index_hint : public Sql_alloc { public: /* The type of the hint : USE/FORCE/IGNORE */ @@ -249,7 +249,7 @@ public: */ LEX_STRING key_name; - index_hint (enum index_hint_type type_arg, index_clause_map clause_arg, + Index_hint (enum index_hint_type type_arg, index_clause_map clause_arg, char *str, uint length) : type(type_arg), clause(clause_arg) { @@ -441,7 +441,7 @@ public: LEX_STRING *alias, ulong table_options, thr_lock_type flags= TL_UNLOCK, - List<index_hint> *hints= 0, + List<Index_hint> *hints= 0, LEX_STRING *option= 0); virtual void set_lock_for_tables(thr_lock_type lock_type) {} @@ -719,7 +719,7 @@ public: LEX_STRING *alias, ulong table_options, thr_lock_type flags= TL_UNLOCK, - List<index_hint> *hints= 0, + List<Index_hint> *hints= 0, LEX_STRING *option= 0); TABLE_LIST* get_table_list(); bool init_nested_join(THD *thd); @@ -779,9 +779,9 @@ public: /* make a list to hold index hints */ void alloc_index_hints (THD *thd); /* read and clear the index hints */ - List<index_hint>* pop_index_hints(void) + List<Index_hint>* pop_index_hints(void) { - List<index_hint> *hints= index_hints; + List<Index_hint> *hints= index_hints; index_hints= NULL; return hints; } @@ -793,7 +793,7 @@ private: enum index_hint_type current_index_hint_type; index_clause_map current_index_hint_clause; /* a list of USE/FORCE/IGNORE INDEX */ - List<index_hint> *index_hints; + List<Index_hint> *index_hints; }; typedef class st_select_lex SELECT_LEX; @@ -1239,19 +1239,19 @@ public: } /** Get the raw query buffer. */ - const char* get_buf() + const char *get_buf() { return m_buf; } /** Get the pre-processed query buffer. */ - const char* get_cpp_buf() + const char *get_cpp_buf() { return m_cpp_buf; } /** Get the end of the raw query buffer. */ - const char* get_end_of_query() + const char *get_end_of_query() { return m_end_of_query; } @@ -1279,43 +1279,43 @@ public: } /** Get the token start position, in the raw buffer. */ - const char* get_tok_start() + const char *get_tok_start() { return m_tok_start; } /** Get the token start position, in the pre-processed buffer. */ - const char* get_cpp_tok_start() + const char *get_cpp_tok_start() { return m_cpp_tok_start; } /** Get the token end position, in the raw buffer. */ - const char* get_tok_end() + const char *get_tok_end() { return m_tok_end; } /** Get the token end position, in the pre-processed buffer. */ - const char* get_cpp_tok_end() + const char *get_cpp_tok_end() { return m_cpp_tok_end; } /** Get the previous token start position, in the raw buffer. */ - const char* get_tok_start_prev() + const char *get_tok_start_prev() { return m_tok_start_prev; } /** Get the current stream pointer, in the raw buffer. */ - const char* get_ptr() + const char *get_ptr() { return m_ptr; } /** Get the current stream pointer, in the pre-processed buffer. */ - const char* get_cpp_ptr() + const char *get_cpp_ptr() { return m_cpp_ptr; } @@ -1365,22 +1365,22 @@ public: private: /** Pointer to the current position in the raw input stream. */ - const char* m_ptr; + const char *m_ptr; /** Starting position of the last token parsed, in the raw buffer. */ - const char* m_tok_start; + const char *m_tok_start; /** Ending position of the previous token parsed, in the raw buffer. */ - const char* m_tok_end; + const char *m_tok_end; /** End of the query text in the input stream, in the raw buffer. */ - const char* m_end_of_query; + const char *m_end_of_query; /** Starting position of the previous token parsed, in the raw buffer. */ - const char* m_tok_start_prev; + const char *m_tok_start_prev; /** Begining of the query text in the input stream, in the raw buffer. */ - const char* m_buf; + const char *m_buf; /** Length of the raw buffer. */ uint m_buf_length; @@ -1389,28 +1389,28 @@ private: bool m_echo; /** Pre-processed buffer. */ - char* m_cpp_buf; + char *m_cpp_buf; /** Pointer to the current position in the pre-processed input stream. */ - char* m_cpp_ptr; + char *m_cpp_ptr; /** Starting position of the last token parsed, in the pre-processed buffer. */ - const char* m_cpp_tok_start; + const char *m_cpp_tok_start; /** Starting position of the previous token parsed, in the pre-procedded buffer. */ - const char* m_cpp_tok_start_prev; + const char *m_cpp_tok_start_prev; /** Ending position of the previous token parsed, in the pre-processed buffer. */ - const char* m_cpp_tok_end; + const char *m_cpp_tok_end; /** UTF8-body buffer created during parsing. */ char *m_body_utf8; @@ -1433,7 +1433,7 @@ public: Position of ';' in the stream, to delimit multiple queries. This delimiter is in the raw buffer. */ - const char* found_semicolon; + const char *found_semicolon; /** SQL_MODE = IGNORE_SPACE. */ bool ignore_space; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index f2a61b7f7c5..93887db88e1 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -5636,7 +5636,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, LEX_STRING *alias, ulong table_options, thr_lock_type lock_type, - List<index_hint> *index_hints_arg, + List<Index_hint> *index_hints_arg, LEX_STRING *option) { register TABLE_LIST *ptr; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 4c48c70dcca..b7757d3e5fc 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -12289,6 +12289,7 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx, key_part_end=key_part+table->key_info[idx].key_parts; key_part_map const_key_parts=table->const_key_parts[idx]; int reverse=0; + my_bool on_primary_key= FALSE; DBUG_ENTER("test_if_order_by_key"); for (; order ; order=order->next, const_key_parts>>=1) @@ -12303,7 +12304,31 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx, for (; const_key_parts & 1 ; const_key_parts>>= 1) key_part++; - if (key_part == key_part_end || key_part->field != field) + if (key_part == key_part_end) + { + /* + We are at the end of the key. Check if the engine has the primary + key as a suffix to the secondary keys. If it has continue to check + the primary key as a suffix. + */ + if (!on_primary_key && + (table->file->ha_table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX) && + ha_legacy_type(table->s->db_type()) == DB_TYPE_INNODB && + table->s->primary_key != MAX_KEY) + { + on_primary_key= TRUE; + key_part= table->key_info[table->s->primary_key].key_part; + key_part_end=key_part+table->key_info[table->s->primary_key].key_parts; + const_key_parts=table->const_key_parts[table->s->primary_key]; + + for (; const_key_parts & 1 ; const_key_parts>>= 1) + key_part++; + } + else + DBUG_RETURN(0); + } + + if (key_part->field != field) DBUG_RETURN(0); /* set flag to 1 if we can use read-next on key, else to -1 */ @@ -12314,7 +12339,8 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx, reverse=flag; // Remember if reverse key_part++; } - *used_key_parts= (uint) (key_part - table->key_info[idx].key_part); + *used_key_parts= on_primary_key ? table->key_info[idx].key_parts : + (uint) (key_part - table->key_info[idx].key_part); if (reverse == -1 && !(table->file->index_flags(idx, *used_key_parts-1, 1) & HA_READ_PREV)) reverse= 0; // Index can't be used @@ -13030,7 +13056,7 @@ remove_duplicates(JOIN *join, TABLE *entry,List<Item> &fields, Item *having) field_count++; } - if (!field_count && !(join->select_options & OPTION_FOUND_ROWS)) + if (!field_count && !(join->select_options & OPTION_FOUND_ROWS) && !having) { // only const items with no OPTION_FOUND_ROWS join->unit->select_limit_cnt= 1; // Only send first row DBUG_RETURN(0); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 31828617c14..33448ea3c5f 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -6336,11 +6336,9 @@ view_err: { VOID(pthread_mutex_lock(&LOCK_open)); wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN); - table->file->ha_external_lock(thd, F_WRLCK); + VOID(pthread_mutex_unlock(&LOCK_open)); alter_table_manage_keys(table, table->file->indexes_are_disabled(), alter_info->keys_onoff); - table->file->ha_external_lock(thd, F_UNLCK); - VOID(pthread_mutex_unlock(&LOCK_open)); error= ha_commit_stmt(thd); if (ha_commit(thd)) error= 1; diff --git a/sql/table.cc b/sql/table.cc index a58f59d3a75..e6f9b1086c7 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1349,7 +1349,12 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, the primary key, then we can use any key to find this column */ if (ha_option & HA_PRIMARY_KEY_IN_READ_INDEX) + { field->part_of_key= share->keys_in_use; + if (ha_legacy_type(share->db_type()) == DB_TYPE_INNODB && + field->part_of_sortkey.is_set(key)) + field->part_of_sortkey= share->keys_in_use; + } } if (field->key_length() != key_part->length) { @@ -4642,11 +4647,11 @@ bool TABLE_LIST::process_index_hints(TABLE *table) key_map index_join[INDEX_HINT_FORCE + 1]; key_map index_order[INDEX_HINT_FORCE + 1]; key_map index_group[INDEX_HINT_FORCE + 1]; - index_hint *hint; + Index_hint *hint; int type; bool have_empty_use_join= FALSE, have_empty_use_order= FALSE, have_empty_use_group= FALSE; - List_iterator <index_hint> iter(*index_hints); + List_iterator <Index_hint> iter(*index_hints); /* initialize temporary variables used to collect hints of each kind */ for (type= INDEX_HINT_IGNORE; type <= INDEX_HINT_FORCE; type++) diff --git a/sql/table.h b/sql/table.h index 494b74d564c..a276a9f32fd 100644 --- a/sql/table.h +++ b/sql/table.h @@ -754,7 +754,7 @@ public: (TABLE_LIST::join_using_fields != NULL) */ -class index_hint; +class Index_hint; struct TABLE_LIST { TABLE_LIST() {} /* Remove gcc warning */ @@ -826,7 +826,7 @@ struct TABLE_LIST */ TABLE_LIST *next_name_resolution_table; /* Index names in a "... JOIN ... USE/IGNORE INDEX ..." clause. */ - List<index_hint> *index_hints; + List<Index_hint> *index_hints; TABLE *table; /* opened table */ uint table_id; /* table id (from binlog) for opened table */ /* diff --git a/storage/archive/ha_archive.cc b/storage/archive/ha_archive.cc index bdc59cbe795..6696eac2fbb 100644 --- a/storage/archive/ha_archive.cc +++ b/storage/archive/ha_archive.cc @@ -436,6 +436,9 @@ int ha_archive::init_archive_writer() } +/* + No locks are required because it is associated with just one handler instance +*/ int ha_archive::init_archive_reader() { DBUG_ENTER("ha_archive::init_archive_reader"); @@ -794,15 +797,16 @@ int ha_archive::write_row(uchar *buf) if (share->crashed) DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE); - if (!share->archive_write_open) - if (init_archive_writer()) - DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE); - ha_statistic_increment(&SSV::ha_write_count); if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT) table->timestamp_field->set_time(); pthread_mutex_lock(&share->mutex); + if (!share->archive_write_open) + if (init_archive_writer()) + DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE); + + if (table->next_number_field && record == table->record[0]) { KEY *mkey= &table->s->key_info[0]; // We only support one key right now @@ -992,24 +996,6 @@ int ha_archive::rnd_init(bool scan) { DBUG_PRINT("info", ("archive will retrieve %llu rows", (unsigned long long) scan_rows)); - stats.records= 0; - - /* - If dirty, we lock, and then reset/flush the data. - I found that just calling azflush() doesn't always work. - */ - pthread_mutex_lock(&share->mutex); - scan_rows= share->rows_recorded; - if (share->dirty == TRUE) - { - if (share->dirty == TRUE) - { - DBUG_PRINT("ha_archive", ("archive flushing out rows for scan")); - azflush(&(share->archive_write), Z_SYNC_FLUSH); - share->dirty= FALSE; - } - } - pthread_mutex_unlock(&share->mutex); if (read_data_header(&archive)) DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE); @@ -1223,9 +1209,7 @@ int ha_archive::rnd_next(uchar *buf) current_position= aztell(&archive); rc= get_row(&archive, buf); - - if (rc != HA_ERR_END_OF_FILE) - stats.records++; + table->status=rc ? STATUS_NOT_FOUND: 0; DBUG_RETURN(rc); } @@ -1461,12 +1445,33 @@ void ha_archive::update_create_info(HA_CREATE_INFO *create_info) int ha_archive::info(uint flag) { DBUG_ENTER("ha_archive::info"); + + /* + If dirty, we lock, and then reset/flush the data. + I found that just calling azflush() doesn't always work. + */ + pthread_mutex_lock(&share->mutex); + if (share->dirty == TRUE) + { + if (share->dirty == TRUE) + { + DBUG_PRINT("ha_archive", ("archive flushing out rows for scan")); + azflush(&(share->archive_write), Z_SYNC_FLUSH); + share->dirty= FALSE; + } + } + /* This should be an accurate number now, though bulk and delayed inserts can cause the number to be inaccurate. */ stats.records= share->rows_recorded; + pthread_mutex_unlock(&share->mutex); + + scan_rows= stats.records; stats.deleted= 0; + + DBUG_PRINT("ha_archive", ("Stats rows is %d\n", (int)stats.records)); /* Costs quite a bit more to get all information */ if (flag & HA_STATUS_TIME) { @@ -1486,7 +1491,9 @@ int ha_archive::info(uint flag) if (flag & HA_STATUS_AUTO) { init_archive_reader(); + pthread_mutex_lock(&share->mutex); azflush(&archive, Z_SYNC_FLUSH); + pthread_mutex_unlock(&share->mutex); stats.auto_increment_value= archive.auto_increment; } @@ -1554,7 +1561,9 @@ int ha_archive::check(THD* thd, HA_CHECK_OPT* check_opt) 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); + pthread_mutex_unlock(&share->mutex); /* Now we will rewind the archive file so that we are positioned at the diff --git a/storage/archive/ha_archive.h b/storage/archive/ha_archive.h index 22fb57b0cc7..ab630ed22fd 100644 --- a/storage/archive/ha_archive.h +++ b/storage/archive/ha_archive.h @@ -88,6 +88,8 @@ public: { return (HA_NO_TRANSACTIONS | HA_REC_NOT_IN_SEQ | HA_CAN_BIT_FIELD | HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE | + HA_STATS_RECORDS_IS_EXACT | + HA_HAS_RECORDS | HA_FILE_BASED | HA_CAN_INSERT_DELAYED | HA_CAN_GEOMETRY); } ulong index_flags(uint idx, uint part, bool all_parts) const @@ -101,6 +103,7 @@ public: uint max_supported_keys() const { return 1; } uint max_supported_key_length() const { return sizeof(ulonglong); } uint max_supported_key_part_length() const { return sizeof(ulonglong); } + ha_rows records() { return share->rows_recorded; } int index_init(uint keynr, bool sorted); virtual int index_read(uchar * buf, const uchar * key, uint key_len, enum ha_rkey_function find_flag); diff --git a/storage/federated/ha_federated.cc b/storage/federated/ha_federated.cc index 635a6fa79e0..ded0ce88484 100644 --- a/storage/federated/ha_federated.cc +++ b/storage/federated/ha_federated.cc @@ -449,6 +449,13 @@ int federated_db_init(void *p) federated_hton->create= federated_create_handler; federated_hton->flags= HTON_ALTER_NOT_SUPPORTED | HTON_NO_PARTITION; + /* + Support for transactions disabled until WL#2952 fixes it. + We do it like this to avoid "defined but not used" compiler warnings. + */ + federated_hton->commit= 0; + federated_hton->rollback= 0; + if (pthread_mutex_init(&federated_mutex, MY_MUTEX_INIT_FAST)) goto error; if (!hash_init(&federated_open_tables, &my_charset_bin, 32, 0, 0, @@ -533,102 +540,6 @@ err: } -/* - Check (in create) whether the tables exists, and that it can be connected to - - SYNOPSIS - check_foreign_data_source() - share pointer to FEDERATED share - table_create_flag tells us that ::create is the caller, - therefore, return CANT_CREATE_FEDERATED_TABLE - - DESCRIPTION - This method first checks that the connection information that parse url - has populated into the share will be sufficient to connect to the foreign - table, and if so, does the foreign table exist. -*/ - -static int check_foreign_data_source(FEDERATED_SHARE *share, - bool table_create_flag) -{ - char query_buffer[FEDERATED_QUERY_BUFFER_SIZE]; - char error_buffer[FEDERATED_QUERY_BUFFER_SIZE]; - uint error_code; - String query(query_buffer, sizeof(query_buffer), &my_charset_bin); - MYSQL *mysql; - DBUG_ENTER("ha_federated::check_foreign_data_source"); - - /* Zero the length, otherwise the string will have misc chars */ - query.length(0); - - /* error out if we can't alloc memory for mysql_init(NULL) (per Georg) */ - if (!(mysql= mysql_init(NULL))) - DBUG_RETURN(HA_ERR_OUT_OF_MEM); - /* check if we can connect */ - if (!mysql_real_connect(mysql, - share->hostname, - share->username, - share->password, - share->database, - share->port, - share->socket, 0)) - { - /* - we want the correct error message, but it to return - ER_CANT_CREATE_FEDERATED_TABLE if called by ::create - */ - error_code= (table_create_flag ? - ER_CANT_CREATE_FEDERATED_TABLE : - ER_CONNECT_TO_FOREIGN_DATA_SOURCE); - - my_sprintf(error_buffer, - (error_buffer, - "database: '%s' username: '%s' hostname: '%s'", - share->database, share->username, share->hostname)); - - my_error(ER_CONNECT_TO_FOREIGN_DATA_SOURCE, MYF(0), error_buffer); - goto error; - } - else - { - /* - Since we do not support transactions at this version, we can let the - client API silently reconnect. For future versions, we will need more - logic to deal with transactions - */ - mysql->reconnect= 1; - /* - Note: I am not using INORMATION_SCHEMA because this needs to work with - versions prior to 5.0 - - if we can connect, then make sure the table exists - - the query will be: SELECT * FROM `tablename` WHERE 1=0 - */ - query.append(STRING_WITH_LEN("SELECT * FROM ")); - append_ident(&query, share->table_name, share->table_name_length, - ident_quote_char); - query.append(STRING_WITH_LEN(" WHERE 1=0")); - - if (mysql_real_query(mysql, query.ptr(), query.length())) - { - error_code= table_create_flag ? - ER_CANT_CREATE_FEDERATED_TABLE : ER_FOREIGN_DATA_SOURCE_DOESNT_EXIST; - my_sprintf(error_buffer, (error_buffer, "error: %d '%s'", - mysql_errno(mysql), mysql_error(mysql))); - - my_error(error_code, MYF(0), error_buffer); - goto error; - } - } - error_code=0; - -error: - mysql_close(mysql); - DBUG_RETURN(error_code); -} - - static int parse_url_error(FEDERATED_SHARE *share, TABLE *table, int error_num) { char buf[FEDERATED_QUERY_BUFFER_SIZE]; @@ -1681,38 +1592,7 @@ int ha_federated::open(const char *name, int mode, uint test_if_locked) DBUG_RETURN(1); thr_lock_data_init(&share->lock, &lock, NULL); - /* Connect to foreign database mysql_real_connect() */ - mysql= mysql_init(0); - - /* - BUG# 17044 Federated Storage Engine is not UTF8 clean - Add set names to whatever charset the table is at open - of table - */ - /* this sets the csname like 'set names utf8' */ - mysql_options(mysql,MYSQL_SET_CHARSET_NAME, - this->table->s->table_charset->csname); - - DBUG_PRINT("info", ("calling mysql_real_connect hostname %s user %s", - share->hostname, share->username)); - if (!mysql || !mysql_real_connect(mysql, - share->hostname, - share->username, - share->password, - share->database, - share->port, - share->socket, 0)) - { - free_share(share); - DBUG_RETURN(stash_remote_error()); - } - /* - Since we do not support transactions at this version, we can let the client - API silently reconnect. For future versions, we will need more logic to - deal with transactions - */ - - mysql->reconnect= 1; + DBUG_ASSERT(mysql == NULL); ref_length= (table->s->primary_key != MAX_KEY ? table->key_info[table->s->primary_key].key_length : @@ -1748,8 +1628,8 @@ int ha_federated::close(void) stored_result= 0; } /* Disconnect from mysql */ - if (mysql) // QQ is this really needed - mysql_close(mysql); + mysql_close(mysql); + mysql= NULL; retval= free_share(share); DBUG_RETURN(retval); @@ -1981,7 +1861,7 @@ int ha_federated::write_row(uchar *buf) if (bulk_insert.length + values_string.length() + bulk_padding > mysql->net.max_packet_size && bulk_insert.length) { - error= mysql_real_query(mysql, bulk_insert.str, bulk_insert.length); + error= real_query(bulk_insert.str, bulk_insert.length); bulk_insert.length= 0; } else @@ -2005,8 +1885,7 @@ int ha_federated::write_row(uchar *buf) } else { - error= mysql_real_query(mysql, values_string.ptr(), - values_string.length()); + error= real_query(values_string.ptr(), values_string.length()); } if (error) @@ -2018,8 +1897,13 @@ int ha_federated::write_row(uchar *buf) field, then store the last_insert_id() value from the foreign server */ if (auto_increment_update_required) + { update_auto_increment(); + /* mysql_insert() uses this for protocol return value */ + table->next_number_field->store(stats.auto_increment_value, 1); + } + DBUG_RETURN(0); } @@ -2049,6 +1933,13 @@ void ha_federated::start_bulk_insert(ha_rows rows) if (rows == 1) DBUG_VOID_RETURN; + /* + Make sure we have an open connection so that we know the + maximum packet size. + */ + if (!mysql && real_connect()) + DBUG_VOID_RETURN; + page_size= (uint) my_getpagesize(); if (init_dynamic_string(&bulk_insert, NULL, page_size, page_size)) @@ -2077,7 +1968,7 @@ int ha_federated::end_bulk_insert() if (bulk_insert.str && bulk_insert.length) { - if (mysql_real_query(mysql, bulk_insert.str, bulk_insert.length)) + if (real_query(bulk_insert.str, bulk_insert.length)) error= stash_remote_error(); else if (table->next_number_field) @@ -2103,8 +1994,9 @@ void ha_federated::update_auto_increment(void) THD *thd= current_thd; DBUG_ENTER("ha_federated::update_auto_increment"); + ha_federated::info(HA_STATUS_AUTO); thd->first_successful_insert_id_in_cur_stmt= - mysql->last_used_con->insert_id; + stats.auto_increment_value; DBUG_PRINT("info",("last_insert_id: %ld", (long) stats.auto_increment_value)); DBUG_VOID_RETURN; @@ -2123,7 +2015,7 @@ int ha_federated::optimize(THD* thd, HA_CHECK_OPT* check_opt) append_ident(&query, share->table_name, share->table_name_length, ident_quote_char); - if (mysql_real_query(mysql, query.ptr(), query.length())) + if (real_query(query.ptr(), query.length())) { DBUG_RETURN(stash_remote_error()); } @@ -2151,7 +2043,7 @@ int ha_federated::repair(THD* thd, HA_CHECK_OPT* check_opt) if (check_opt->sql_flags & TT_USEFRM) query.append(STRING_WITH_LEN(" USE_FRM")); - if (mysql_real_query(mysql, query.ptr(), query.length())) + if (real_query(query.ptr(), query.length())) { DBUG_RETURN(stash_remote_error()); } @@ -2308,7 +2200,7 @@ int ha_federated::update_row(const uchar *old_data, uchar *new_data) if (!has_a_primary_key) update_string.append(STRING_WITH_LEN(" LIMIT 1")); - if (mysql_real_query(mysql, update_string.ptr(), update_string.length())) + if (real_query(update_string.ptr(), update_string.length())) { DBUG_RETURN(stash_remote_error()); } @@ -2381,7 +2273,7 @@ int ha_federated::delete_row(const uchar *buf) delete_string.append(STRING_WITH_LEN(" LIMIT 1")); DBUG_PRINT("info", ("Delete sql: %s", delete_string.c_ptr_quick())); - if (mysql_real_query(mysql, delete_string.ptr(), delete_string.length())) + if (real_query(delete_string.ptr(), delete_string.length())) { DBUG_RETURN(stash_remote_error()); } @@ -2489,7 +2381,7 @@ int ha_federated::index_read_idx_with_result_set(uchar *buf, uint index, NULL, 0, 0); sql_query.append(index_string); - if (mysql_real_query(mysql, sql_query.ptr(), sql_query.length())) + if (real_query(sql_query.ptr(), sql_query.length())) { my_sprintf(error_buffer, (error_buffer, "error: %d '%s'", mysql_errno(mysql), mysql_error(mysql))); @@ -2555,7 +2447,7 @@ int ha_federated::read_range_first(const key_range *start_key, mysql_free_result(stored_result); stored_result= 0; } - if (mysql_real_query(mysql, sql_query.ptr(), sql_query.length())) + if (real_query(sql_query.ptr(), sql_query.length())) { retval= ER_QUERY_ON_FOREIGN_DATA_SOURCE; goto error; @@ -2654,9 +2546,7 @@ int ha_federated::rnd_init(bool scan) stored_result= 0; } - if (mysql_real_query(mysql, - share->select_query, - strlen(share->select_query))) + if (real_query(share->select_query, strlen(share->select_query))) goto error; stored_result= mysql_store_result(mysql); @@ -2873,8 +2763,7 @@ int ha_federated::info(uint flag) append_ident(&status_query_string, share->table_name, share->table_name_length, value_quote_char); - if (mysql_real_query(mysql, status_query_string.ptr(), - status_query_string.length())) + if (real_query(status_query_string.ptr(), status_query_string.length())) goto error; status_query_string.length(0); @@ -2926,18 +2815,27 @@ int ha_federated::info(uint flag) } - if (result) - mysql_free_result(result); + if (flag & HA_STATUS_AUTO) + stats.auto_increment_value= mysql->last_used_con->insert_id; + + mysql_free_result(result); DBUG_RETURN(0); error: - if (result) - mysql_free_result(result); - - my_sprintf(error_buffer, (error_buffer, ": %d : %s", - mysql_errno(mysql), mysql_error(mysql))); - my_error(error_code, MYF(0), error_buffer); + mysql_free_result(result); + if (mysql) + { + my_sprintf(error_buffer, (error_buffer, ": %d : %s", + mysql_errno(mysql), mysql_error(mysql))); + my_error(error_code, MYF(0), error_buffer); + } + else + if (remote_error_number != -1 /* error already reported */) + { + error_code= remote_error_number; + my_error(error_code, MYF(0), ER(error_code)); + } DBUG_RETURN(error_code); } @@ -3029,7 +2927,7 @@ int ha_federated::delete_all_rows() /* TRUNCATE won't return anything in mysql_affected_rows */ - if (mysql_real_query(mysql, query.ptr(), query.length())) + if (real_query(query.ptr(), query.length())) { DBUG_RETURN(stash_remote_error()); } @@ -3119,17 +3017,120 @@ int ha_federated::create(const char *name, TABLE *table_arg, FEDERATED_SHARE tmp_share; // Only a temporary share, to test the url DBUG_ENTER("ha_federated::create"); - if (!(retval= parse_url(thd->mem_root, &tmp_share, table_arg, 1))) - retval= check_foreign_data_source(&tmp_share, 1); + retval= parse_url(thd->mem_root, &tmp_share, table_arg, 1); DBUG_RETURN(retval); } +int ha_federated::real_connect() +{ + char buffer[FEDERATED_QUERY_BUFFER_SIZE]; + String sql_query(buffer, sizeof(buffer), &my_charset_bin); + DBUG_ENTER("ha_federated::real_connect"); + + /* + Bug#25679 + Ensure that we do not hold the LOCK_open mutex while attempting + to establish Federated connection to guard against a trivial + Denial of Service scenerio. + */ + safe_mutex_assert_not_owner(&LOCK_open); + + DBUG_ASSERT(mysql == NULL); + + if (!(mysql= mysql_init(NULL))) + { + remote_error_number= HA_ERR_OUT_OF_MEM; + DBUG_RETURN(-1); + } + + /* + BUG# 17044 Federated Storage Engine is not UTF8 clean + Add set names to whatever charset the table is at open + of table + */ + /* this sets the csname like 'set names utf8' */ + mysql_options(mysql,MYSQL_SET_CHARSET_NAME, + this->table->s->table_charset->csname); + + sql_query.length(0); + + if (!mysql_real_connect(mysql, + share->hostname, + share->username, + share->password, + share->database, + share->port, + share->socket, 0)) + { + stash_remote_error(); + mysql_close(mysql); + mysql= NULL; + my_error(ER_CONNECT_TO_FOREIGN_DATA_SOURCE, MYF(0), remote_error_buf); + remote_error_number= -1; + DBUG_RETURN(-1); + } + + /* + We have established a connection, lets try a simple dummy query just + to check that the table and expected columns are present. + */ + sql_query.append(share->select_query); + sql_query.append(STRING_WITH_LEN(" WHERE 1=0")); + if (mysql_real_query(mysql, sql_query.ptr(), sql_query.length())) + { + sql_query.length(0); + sql_query.append("error: "); + sql_query.qs_append(mysql_errno(mysql)); + sql_query.append(" '"); + sql_query.append(mysql_error(mysql)); + sql_query.append("'"); + mysql_close(mysql); + mysql= NULL; + my_error(ER_FOREIGN_DATA_SOURCE_DOESNT_EXIST, MYF(0), sql_query.ptr()); + remote_error_number= -1; + DBUG_RETURN(-1); + } + + /* Just throw away the result, no rows anyways but need to keep in sync */ + mysql_free_result(mysql_store_result(mysql)); + + /* + Since we do not support transactions at this version, we can let the client + API silently reconnect. For future versions, we will need more logic to + deal with transactions + */ + + mysql->reconnect= 1; + DBUG_RETURN(0); +} + + +int ha_federated::real_query(const char *query, uint length) +{ + int rc= 0; + DBUG_ENTER("ha_federated::real_query"); + + if (!mysql && (rc= real_connect())) + goto end; + + if (!query || !length) + goto end; + + rc= mysql_real_query(mysql, query, length); + +end: + DBUG_RETURN(rc); +} + + int ha_federated::stash_remote_error() { DBUG_ENTER("ha_federated::stash_remote_error()"); + if (!mysql) + DBUG_RETURN(remote_error_number); remote_error_number= mysql_errno(mysql); strmake(remote_error_buf, mysql_error(mysql), sizeof(remote_error_buf)-1); if (remote_error_number == ER_DUP_ENTRY || @@ -3160,11 +3161,16 @@ bool ha_federated::get_error_message(int error, String* buf) int ha_federated::external_lock(THD *thd, int lock_type) { int error= 0; - ha_federated *trx= (ha_federated *)thd->ha_data[ht->slot]; DBUG_ENTER("ha_federated::external_lock"); + /* + Support for transactions disabled until WL#2952 fixes it. + */ +#ifdef XXX_SUPERCEDED_BY_WL2952 if (lock_type != F_UNLCK) { + ha_federated *trx= (ha_federated *)thd->ha_data[ht->slot]; + DBUG_PRINT("info",("federated not lock F_UNLCK")); if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) { @@ -3216,7 +3222,8 @@ int ha_federated::external_lock(THD *thd, int lock_type) } } } - DBUG_RETURN(0); +#endif /* XXX_SUPERCEDED_BY_WL2952 */ + DBUG_RETURN(error); } diff --git a/storage/federated/ha_federated.h b/storage/federated/ha_federated.h index 5f0f1cec2a2..40bcf9cc402 100644 --- a/storage/federated/ha_federated.h +++ b/storage/federated/ha_federated.h @@ -113,6 +113,8 @@ private: uint key_len, ha_rkey_function find_flag, MYSQL_RES **result); + int real_query(const char *query, uint length); + int real_connect(); public: ha_federated(handlerton *hton, TABLE_SHARE *table_arg); ~ha_federated() {} @@ -141,6 +143,7 @@ public: | HA_REC_NOT_IN_SEQ | HA_AUTO_PART_KEY | HA_CAN_INDEX_BLOBS | HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE | HA_NO_PREFIX_CHAR_KEYS | HA_PRIMARY_KEY_REQUIRED_FOR_DELETE | + HA_NO_TRANSACTIONS /* until fixed by WL#2952 */ | HA_PARTIAL_COLUMN_READ | HA_NULL_IN_KEY); } /* diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index c2e230d2087..ca566f1300e 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -7039,18 +7039,6 @@ ha_innobase::store_lock( && !thd_tablespace_op(thd) && sql_command != SQLCOM_TRUNCATE && sql_command != SQLCOM_OPTIMIZE - -#ifdef __WIN__ - /* For alter table on win32 for successful - operation completion it is used TL_WRITE(=10) lock - instead of TL_WRITE_ALLOW_READ(=6), however here - in innodb handler TL_WRITE is lifted to - TL_WRITE_ALLOW_WRITE, which causes race condition - when several clients do alter table simultaneously - (bug #17264). This fix avoids the problem. */ - && sql_command != SQLCOM_ALTER_TABLE -#endif - && sql_command != SQLCOM_CREATE_TABLE) { lock_type = TL_WRITE_ALLOW_WRITE; diff --git a/storage/myisam/mi_extra.c b/storage/myisam/mi_extra.c index 72c40741a22..30802a50513 100644 --- a/storage/myisam/mi_extra.c +++ b/storage/myisam/mi_extra.c @@ -258,7 +258,7 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function, void *extra_arg) case HA_EXTRA_PREPARE_FOR_DELETE: pthread_mutex_lock(&THR_LOCK_myisam); share->last_version= 0L; /* Impossible version */ -#ifdef __WIN__ +#ifdef __WIN__REMOVE_OBSOLETE_WORKAROUND /* Close the isam and data files as Win32 can't drop an open table */ pthread_mutex_lock(&share->intern_lock); if (flush_key_blocks(share->key_cache, share->kfile, diff --git a/storage/myisammrg/myrg_locking.c b/storage/myisammrg/myrg_locking.c index a07833bc829..4f1e3f844a1 100644 --- a/storage/myisammrg/myrg_locking.c +++ b/storage/myisammrg/myrg_locking.c @@ -37,7 +37,15 @@ int myrg_lock_database(MYRG_INFO *info, int lock_type) (file->table)->owned_by_merge = TRUE; #endif if ((new_error=mi_lock_database(file->table,lock_type))) + { error=new_error; + if (lock_type != F_UNLCK) + { + while (--file >= info->open_tables) + mi_lock_database(file->table, F_UNLCK); + break; + } + } } return(error); } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 5eade93621b..7559ca9ec6b 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -22,3 +22,6 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include) ADD_EXECUTABLE(mysql_client_test mysql_client_test.c) TARGET_LINK_LIBRARIES(mysql_client_test dbug mysys mysqlclient yassl taocrypt zlib wsock32) + +ADD_EXECUTABLE(bug25714 bug25714.c) +TARGET_LINK_LIBRARIES(bug25714 dbug mysys mysqlclient yassl taocrypt zlib wsock32) diff --git a/tests/Makefile.am b/tests/Makefile.am index 5f34def19bd..fbd58b88b9c 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -35,7 +35,7 @@ EXTRA_DIST = auto_increment.res auto_increment.tst \ CMakeLists.txt bin_PROGRAMS = mysql_client_test -noinst_PROGRAMS = insert_test select_test thread_test +noinst_PROGRAMS = insert_test select_test thread_test bug25714 INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include \ $(openssl_includes) @@ -52,6 +52,9 @@ select_test_SOURCES= select_test.c insert_test_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES) select_test_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES) +bug25714_SOURCES= bug25714.c +bug25714_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES) + # Fix for mit-threads DEFS = -DUNDEF_THREADS_HACK diff --git a/tests/bug25714.c b/tests/bug25714.c new file mode 100644 index 00000000000..e9b2be44209 --- /dev/null +++ b/tests/bug25714.c @@ -0,0 +1,71 @@ +/* Copyright (C) 2007 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include <my_global.h> +#include <my_sys.h> +#include <mysql.h> +#include <m_string.h> +#include <assert.h> + +int main (int argc, char **argv) +{ + MYSQL conn; + int OK; + + const char* query4= "INSERT INTO federated.t1 SET Value=54"; + const char* query5= "INSERT INTO federated.t1 SET Value=55"; + + MY_INIT(argv[0]); + + if (argc != 2) + return -1; + + mysql_init(&conn); + if (!mysql_real_connect( + &conn, + "127.0.0.1", + "root", + "", + "test", + atoi(argv[1]), + NULL, + CLIENT_FOUND_ROWS)) + { + fprintf(stderr, "Failed to connect to database: Error: %s\n", + mysql_error(&conn)); + return 1; + } else { + printf("%s\n", mysql_error(&conn)); + } + + OK = mysql_real_query (&conn, query4, strlen(query4)); + + assert(0 == OK); + + printf("%ld inserted\n", + (long) mysql_insert_id(&conn)); + + OK = mysql_real_query (&conn, query5, strlen(query5)); + + assert(0 == OK); + + printf("%ld inserted\n", + (long) mysql_insert_id(&conn)); + + mysql_close(&conn); + my_end(0); + + return 0; +}; |