diff --git a/client/mysqldump.c b/client/mysqldump.c index fa5c06786d2ea..a0222f370b308 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -4004,7 +4004,13 @@ static int dump_tablespaces(char* ts_where) char *ubs; char *endsemi; DBUG_ENTER("dump_tablespaces"); - + + /* + Try to turn off semi-join optimization (if that fails, this is a + pre-optimizer_switch server, and the old query plan is ok for us. + */ + mysql_query(mysql, "set optimizer_switch='semijoin=off'"); + init_dynamic_string_checked(&sqlbuf, "SELECT LOGFILE_GROUP_NAME," " FILE_NAME," @@ -4164,6 +4170,8 @@ static int dump_tablespaces(char* ts_where) mysql_free_result(tableres); dynstr_free(&sqlbuf); + mysql_query(mysql, "set optimizer_switch=default"); + DBUG_RETURN(0); } diff --git a/client/mysqltest.cc b/client/mysqltest.cc index d6158f471fd13..3304af3981d24 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -8945,7 +8945,7 @@ int main(int argc, char **argv) my_init_dynamic_array(&q_lines, sizeof(struct st_command*), 1024, 1024, MYF(0)); if (my_hash_init2(&var_hash, 64, charset_info, - 128, 0, 0, get_var_key, var_free, MYF(0))) + 128, 0, 0, get_var_key, 0, var_free, MYF(0))) die("Variable hash initialization failed"); var_set_string("MYSQL_SERVER_VERSION", MYSQL_SERVER_VERSION); diff --git a/include/hash.h b/include/hash.h index f014c44c7eccc..ba36df23f58be 100644 --- a/include/hash.h +++ b/include/hash.h @@ -44,6 +44,8 @@ extern "C" { typedef uint my_hash_value_type; typedef uchar *(*my_hash_get_key)(const uchar *,size_t*,my_bool); +typedef my_hash_value_type (*my_hash_function)(const CHARSET_INFO *, + const uchar *, size_t); typedef void (*my_hash_free_key)(void *); typedef my_bool (*my_hash_walk_action)(void *,void *); @@ -54,6 +56,7 @@ typedef struct st_hash { uint flags; DYNAMIC_ARRAY array; /* Place for hash_keys */ my_hash_get_key get_key; + my_hash_function hash_function; void (*free)(void *); CHARSET_INFO *charset; } HASH; @@ -61,10 +64,11 @@ typedef struct st_hash { /* A search iterator state */ typedef uint HASH_SEARCH_STATE; -#define my_hash_init(A,B,C,D,E,F,G,H) my_hash_init2(A,0,B,C,D,E,F,G,H) +#define my_hash_init(A,B,C,D,E,F,G,H) my_hash_init2(A,0,B,C,D,E,F,0,G,H) my_bool my_hash_init2(HASH *hash, uint growth_size, CHARSET_INFO *charset, ulong default_array_elements, size_t key_offset, size_t key_length, my_hash_get_key get_key, + my_hash_function hash_function, void (*free_element)(void*), uint flags); void my_hash_free(HASH *tree); @@ -74,8 +78,9 @@ uchar *my_hash_search(const HASH *info, const uchar *key, size_t length); uchar *my_hash_search_using_hash_value(const HASH *info, my_hash_value_type hash_value, const uchar *key, size_t length); -my_hash_value_type my_calc_hash(const HASH *info, +my_hash_value_type my_hash_sort(const CHARSET_INFO *cs, const uchar *key, size_t length); +#define my_calc_hash(A, B, C) my_hash_sort((A)->charset, B, C) uchar *my_hash_first(const HASH *info, const uchar *key, size_t length, HASH_SEARCH_STATE *state); uchar *my_hash_first_from_hash_value(const HASH *info, diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index e992c862537e3..3d8a2bebc7584 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -1273,6 +1273,7 @@ static my_bool setup_one_fetch_function(MYSQL_BIND *, MYSQL_FIELD *field); #define RESET_LONG_DATA 2 #define RESET_STORE_RESULT 4 #define RESET_CLEAR_ERROR 8 +#define RESET_ALL_BUFFERS 16 static my_bool reset_stmt_handle(MYSQL_STMT *stmt, uint flags); @@ -4615,6 +4616,14 @@ static my_bool reset_stmt_handle(MYSQL_STMT *stmt, uint flags) *mysql->unbuffered_fetch_owner= TRUE; mysql->status= MYSQL_STATUS_READY; } + if (flags & RESET_ALL_BUFFERS) + { + /* mysql_stmt_next_result will flush all pending + result sets + */ + while (mysql_more_results(mysql) && + mysql_stmt_next_result(stmt) == 0); + } } if (flags & RESET_SERVER_SIDE) { @@ -4679,27 +4688,18 @@ my_bool STDCALL mysql_stmt_close(MYSQL_STMT *stmt) { mysql->stmts= list_delete(mysql->stmts, &stmt->list); /* - Clear NET error state: if the following commands come through - successfully, connection will still be usable for other commands. + Clear NET error state: if the following commands come through + successfully, connection will still be usable for other commands. */ net_clear_error(&mysql->net); + if ((int) stmt->state > (int) MYSQL_STMT_INIT_DONE) { uchar buff[MYSQL_STMT_HEADER]; /* 4 bytes - stmt id */ - if (mysql->unbuffered_fetch_owner == &stmt->unbuffered_fetch_cancelled) - mysql->unbuffered_fetch_owner= 0; - if (mysql->status != MYSQL_STATUS_READY) - { - /* - Flush result set of the connection. If it does not belong - to this statement, set a warning. - */ - (*mysql->methods->flush_use_result)(mysql, TRUE); - if (mysql->unbuffered_fetch_owner) - *mysql->unbuffered_fetch_owner= TRUE; - mysql->status= MYSQL_STATUS_READY; - } + if ((rc= reset_stmt_handle(stmt, RESET_ALL_BUFFERS | RESET_CLEAR_ERROR))) + return rc; + int4store(buff, stmt->stmt_id); if ((rc= stmt_command(mysql, COM_STMT_CLOSE, buff, 4, stmt))) { @@ -4731,7 +4731,7 @@ my_bool STDCALL mysql_stmt_reset(MYSQL_STMT *stmt) /* Reset the client and server sides of the prepared statement */ DBUG_RETURN(reset_stmt_handle(stmt, RESET_SERVER_SIDE | RESET_LONG_DATA | - RESET_CLEAR_ERROR)); + RESET_ALL_BUFFERS | RESET_CLEAR_ERROR)); } /* @@ -4843,7 +4843,6 @@ int STDCALL mysql_next_result(MYSQL *mysql) DBUG_RETURN(-1); /* No more results */ } - int STDCALL mysql_stmt_next_result(MYSQL_STMT *stmt) { MYSQL *mysql= stmt->mysql; diff --git a/mysql-test/r/create_or_replace.result b/mysql-test/r/create_or_replace.result index 228086bd62ce1..8f6ca01d34b66 100644 --- a/mysql-test/r/create_or_replace.result +++ b/mysql-test/r/create_or_replace.result @@ -333,29 +333,29 @@ lock table t1 write, t2 read; select * from information_schema.metadata_lock_info; THREAD_ID LOCK_MODE LOCK_DURATION LOCK_TYPE TABLE_SCHEMA TABLE_NAME # MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Global read lock -# MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Schema metadata lock test # MDL_SHARED_NO_READ_WRITE MDL_EXPLICIT Table metadata lock test t1 +# MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Schema metadata lock test # MDL_SHARED_READ MDL_EXPLICIT Table metadata lock test t2 create or replace table t1 (i int); select * from information_schema.metadata_lock_info; THREAD_ID LOCK_MODE LOCK_DURATION LOCK_TYPE TABLE_SCHEMA TABLE_NAME # MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Global read lock -# MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Schema metadata lock test # MDL_SHARED_NO_READ_WRITE MDL_EXPLICIT Table metadata lock test t1 +# MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Schema metadata lock test # MDL_SHARED_READ MDL_EXPLICIT Table metadata lock test t2 create or replace table t1 like t2; select * from information_schema.metadata_lock_info; THREAD_ID LOCK_MODE LOCK_DURATION LOCK_TYPE TABLE_SCHEMA TABLE_NAME # MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Global read lock -# MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Schema metadata lock test # MDL_SHARED_NO_READ_WRITE MDL_EXPLICIT Table metadata lock test t1 +# MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Schema metadata lock test # MDL_SHARED_READ MDL_EXPLICIT Table metadata lock test t2 create or replace table t1 select 1 as f1; select * from information_schema.metadata_lock_info; THREAD_ID LOCK_MODE LOCK_DURATION LOCK_TYPE TABLE_SCHEMA TABLE_NAME # MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Global read lock -# MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Schema metadata lock test # MDL_SHARED_NO_READ_WRITE MDL_EXPLICIT Table metadata lock test t1 +# MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Schema metadata lock test # MDL_SHARED_READ MDL_EXPLICIT Table metadata lock test t2 drop table t1; unlock tables; diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index d27b03e85d3cc..a070c5c10d589 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -1985,3 +1985,45 @@ drop database mysqltest; # # End of 5.5 tests # +# +# MDEV-5723: mysqldump -uroot unusable for multi-database operations, checks all databases +# +drop database if exists db1; +create database db1; +use db1; +create table t1 (a int); +create table t2 (a int); +create table t3 (a int); +create database mysqltest; +use mysqltest; +create table t1 (a int); +create table t2 (a int); +create table t3 (a int); +flush tables; +flush status; +SELECT +LOGFILE_GROUP_NAME, FILE_NAME, TOTAL_EXTENTS, INITIAL_SIZE, ENGINE, EXTRA +FROM +INFORMATION_SCHEMA.FILES +WHERE +FILE_TYPE = 'UNDO LOG' AND FILE_NAME IS NOT NULL AND +LOGFILE_GROUP_NAME IN (SELECT DISTINCT LOGFILE_GROUP_NAME +FROM INFORMATION_SCHEMA.FILES +WHERE +FILE_TYPE = 'DATAFILE' AND +TABLESPACE_NAME IN (SELECT DISTINCT TABLESPACE_NAME +FROM INFORMATION_SCHEMA.PARTITIONS +WHERE TABLE_SCHEMA IN ('db1') +) +) +GROUP BY +LOGFILE_GROUP_NAME, FILE_NAME, ENGINE +ORDER BY +LOGFILE_GROUP_NAME; +LOGFILE_GROUP_NAME FILE_NAME TOTAL_EXTENTS INITIAL_SIZE ENGINE EXTRA +# This must have Opened_tables=3, not 6. +show status like 'Opened_tables'; +Variable_name Value +Opened_tables 3 +drop database mysqltest; +drop database db1; diff --git a/mysql-test/r/innodb_ext_key.result b/mysql-test/r/innodb_ext_key.result index 9ef28e1ce54a9..9140f306f77cb 100644 --- a/mysql-test/r/innodb_ext_key.result +++ b/mysql-test/r/innodb_ext_key.result @@ -327,7 +327,7 @@ from lineitem use index (i_l_shipdate, i_l_receiptdate) where l_shipdate='1992-07-01' and l_orderkey=130 or l_receiptdate='1992-07-01' and l_orderkey=5603; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE lineitem index_merge i_l_shipdate,i_l_receiptdate i_l_shipdate,i_l_receiptdate 8,8 NULL 2 Using sort_union(i_l_shipdate,i_l_receiptdate); Using where +1 SIMPLE lineitem index_merge i_l_shipdate,i_l_receiptdate i_l_shipdate,i_l_receiptdate 8,8 NULL 2 Using union(i_l_shipdate,i_l_receiptdate); Using where flush status; select l_orderkey, l_linenumber from lineitem use index (i_l_shipdate, i_l_receiptdate) diff --git a/mysql-test/r/join.result b/mysql-test/r/join.result index 0f798f7ba1a8f..e7292e8ddce18 100644 --- a/mysql-test/r/join.result +++ b/mysql-test/r/join.result @@ -1538,3 +1538,14 @@ a 3 4 DROP TABLE t1,t2; +# +# MDEV-5635: join of a const table with non-const tables +# +CREATE TABLE t1 (a varchar(3) NOT NULL) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('foo'); +CREATE TABLE t2 (b varchar(3), c varchar(3), INDEX(b)) ENGINE=MyISAM; +INSERT INTO t2 VALUES ('bar', 'bar'),( 'qux', 'qux'); +SELECT STRAIGHT_JOIN * FROM t1, t2 AS t2_1, t2 AS t2_2 +WHERE t2_2.c = t2_1.c AND t2_2.b = t2_1.b AND ( a IS NULL OR t2_1.c = a ); +a b c b c +DROP TABLE t1,t2; diff --git a/mysql-test/suite/rpl/t/rpl_heartbeat_basic.test b/mysql-test/suite/rpl/t/rpl_heartbeat_basic.test index 27dce9cd6522a..a1e52cf23da20 100644 --- a/mysql-test/suite/rpl/t/rpl_heartbeat_basic.test +++ b/mysql-test/suite/rpl/t/rpl_heartbeat_basic.test @@ -367,7 +367,7 @@ DROP EVENT e1; - +--sync_slave_with_master # Check received heartbeat events while logs flushed on slave --connection slave --echo *** Flush logs on slave *** diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test index 8c88be5c603cc..f6422a0aae72e 100644 --- a/mysql-test/t/information_schema.test +++ b/mysql-test/t/information_schema.test @@ -1816,5 +1816,61 @@ drop database mysqltest; --echo # End of 5.5 tests --echo # +--echo # +--echo # MDEV-5723: mysqldump -uroot unusable for multi-database operations, checks all databases +--echo # + +--disable_warnings +drop database if exists db1; +--enable_warnings + +connect (con1,localhost,root,,); +connection con1; + +create database db1; +use db1; +create table t1 (a int); +create table t2 (a int); +create table t3 (a int); + +create database mysqltest; +use mysqltest; +create table t1 (a int); +create table t2 (a int); +create table t3 (a int); + +flush tables; +flush status; + +SELECT + LOGFILE_GROUP_NAME, FILE_NAME, TOTAL_EXTENTS, INITIAL_SIZE, ENGINE, EXTRA +FROM + INFORMATION_SCHEMA.FILES +WHERE + FILE_TYPE = 'UNDO LOG' AND FILE_NAME IS NOT NULL AND + LOGFILE_GROUP_NAME IN (SELECT DISTINCT LOGFILE_GROUP_NAME + FROM INFORMATION_SCHEMA.FILES + WHERE + FILE_TYPE = 'DATAFILE' AND + TABLESPACE_NAME IN (SELECT DISTINCT TABLESPACE_NAME + FROM INFORMATION_SCHEMA.PARTITIONS + WHERE TABLE_SCHEMA IN ('db1') + ) + ) +GROUP BY + LOGFILE_GROUP_NAME, FILE_NAME, ENGINE +ORDER BY + LOGFILE_GROUP_NAME; + +--echo # This must have Opened_tables=3, not 6. +show status like 'Opened_tables'; + +drop database mysqltest; +drop database db1; + +connection default; +disconnect con1; + # Wait till all disconnects are completed --source include/wait_until_count_sessions.inc + diff --git a/mysql-test/t/join.test b/mysql-test/t/join.test index 54b2a3c82ea0c..e07a3665920d3 100644 --- a/mysql-test/t/join.test +++ b/mysql-test/t/join.test @@ -1185,3 +1185,18 @@ SELECT t1.a FROM t1 NATURAL STRAIGHT_JOIN t2 ORDER BY t1.a; SELECT t1.a FROM t1 NATURAL STRAIGHT_JOIN t2 ORDER BY t1.a; DROP TABLE t1,t2; + +--echo # +--echo # MDEV-5635: join of a const table with non-const tables +--echo # + +CREATE TABLE t1 (a varchar(3) NOT NULL) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('foo'); + +CREATE TABLE t2 (b varchar(3), c varchar(3), INDEX(b)) ENGINE=MyISAM; +INSERT INTO t2 VALUES ('bar', 'bar'),( 'qux', 'qux'); + +SELECT STRAIGHT_JOIN * FROM t1, t2 AS t2_1, t2 AS t2_2 + WHERE t2_2.c = t2_1.c AND t2_2.b = t2_1.b AND ( a IS NULL OR t2_1.c = a ); + +DROP TABLE t1,t2; diff --git a/mysys/hash.c b/mysys/hash.c index 25210d3fcfe21..4ef731cde1527 100644 --- a/mysys/hash.c +++ b/mysys/hash.c @@ -40,12 +40,12 @@ static void movelink(HASH_LINK *array,uint pos,uint next_link,uint newlink); static int hashcmp(const HASH *hash, HASH_LINK *pos, const uchar *key, size_t length); -static my_hash_value_type calc_hash(const HASH *hash, - const uchar *key, size_t length) +my_hash_value_type my_hash_sort(const CHARSET_INFO *cs, const uchar *key, + size_t length) { - ulong nr1=1, nr2=4; - hash->charset->coll->hash_sort(hash->charset,(uchar*) key,length,&nr1,&nr2); - return (my_hash_value_type)nr1; + ulong nr1= 1, nr2= 4; + cs->coll->hash_sort(cs, (uchar*) key, length, &nr1, &nr2); + return (my_hash_value_type) nr1; } /** @@ -78,6 +78,7 @@ my_bool my_hash_init2(HASH *hash, uint growth_size, CHARSET_INFO *charset, ulong size, size_t key_offset, size_t key_length, my_hash_get_key get_key, + my_hash_function hash_function, void (*free_element)(void*), uint flags) { my_bool res; @@ -89,6 +90,7 @@ my_hash_init2(HASH *hash, uint growth_size, CHARSET_INFO *charset, hash->key_length=key_length; hash->blength=1; hash->get_key=get_key; + hash->hash_function= hash_function ? hash_function : my_hash_sort; hash->free=free_element; hash->flags=flags; hash->charset=charset; @@ -200,7 +202,8 @@ static uint my_hash_rec_mask(const HASH *hash, HASH_LINK *pos, { size_t length; uchar *key= (uchar*) my_hash_key(hash, pos->data, &length, 0); - return my_hash_mask(calc_hash(hash, key, length), buffmax, maxlength); + return my_hash_mask(hash->hash_function(hash->charset, key, length), buffmax, + maxlength); } @@ -214,7 +217,7 @@ my_hash_value_type rec_hashnr(HASH *hash,const uchar *record) { size_t length; uchar *key= (uchar*) my_hash_key(hash, record, &length, 0); - return calc_hash(hash,key,length); + return hash->hash_function(hash->charset, key, length); } @@ -234,12 +237,6 @@ uchar* my_hash_search_using_hash_value(const HASH *hash, key, length, &state); } -my_hash_value_type my_calc_hash(const HASH *hash, - const uchar *key, size_t length) -{ - return calc_hash(hash, key, length ? length : hash->key_length); -} - /* Search after a record based on a key @@ -254,7 +251,8 @@ uchar* my_hash_first(const HASH *hash, const uchar *key, size_t length, uchar *res; if (my_hash_inited(hash)) res= my_hash_first_from_hash_value(hash, - calc_hash(hash, key, length ? length : hash->key_length), + hash->hash_function(hash->charset, key, + length ? length : hash->key_length), key, length, current_record); else res= 0; @@ -644,9 +642,9 @@ my_bool my_hash_update(HASH *hash, uchar *record, uchar *old_key, /* Search after record with key */ - idx= my_hash_mask(calc_hash(hash, old_key, (old_key_length ? - old_key_length : - hash->key_length)), + idx= my_hash_mask(hash->hash_function(hash->charset, old_key, + (old_key_length ? old_key_length : + hash->key_length)), blength, records); new_index= my_hash_mask(rec_hashnr(hash, record), blength, records); if (idx == new_index) diff --git a/mysys/thr_mutex.c b/mysys/thr_mutex.c index c70aa34280243..18af5f47b1064 100644 --- a/mysys/thr_mutex.c +++ b/mysys/thr_mutex.c @@ -174,12 +174,12 @@ static int safe_mutex_lazy_init_deadlock_detection(safe_mutex_t *mp) 128, offsetof(safe_mutex_deadlock_t, id), sizeof(mp->id), - 0, 0, HASH_UNIQUE); + 0, 0, 0, HASH_UNIQUE); my_hash_init2(mp->used_mutex, 64, &my_charset_bin, 128, offsetof(safe_mutex_t, id), sizeof(mp->id), - 0, 0, HASH_UNIQUE); + 0, 0, 0, HASH_UNIQUE); return 0; } diff --git a/sql/log_event.cc b/sql/log_event.cc index 1e69d5bf1cc8d..f3f6d7a5d3861 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -6518,24 +6518,22 @@ Gtid_log_event::do_apply_event(rpl_group_info *rgi) return 0; /* Execute this like a BEGIN query event. */ - thd->variables.option_bits|= OPTION_BEGIN | OPTION_GTID_BEGIN; + thd->variables.option_bits|= OPTION_GTID_BEGIN; DBUG_PRINT("info", ("Set OPTION_GTID_BEGIN")); - trans_begin(thd, 0); - thd->set_query_and_id(gtid_begin_string, sizeof(gtid_begin_string)-1, &my_charset_bin, next_query_id()); - Parser_state parser_state; - if (!parser_state.init(thd, thd->query(), thd->query_length())) - { - mysql_parse(thd, thd->query(), thd->query_length(), &parser_state); - /* Finalize server status flags after executing a statement. */ - thd->update_server_status(); - log_slow_statement(thd); - if (unlikely(thd->is_fatal_error)) - thd->is_slave_error= 1; - else if (likely(!thd->is_slave_error)) - general_log_write(thd, COM_QUERY, thd->query(), thd->query_length()); + thd->lex->sql_command= SQLCOM_BEGIN; + thd->is_slave_error= 0; + status_var_increment(thd->status_var.com_stat[thd->lex->sql_command]); + if (trans_begin(thd, 0)) + { + DBUG_PRINT("error", ("trans_begin() failed")); + thd->is_slave_error= 1; } + thd->update_stats(); + + if (likely(!thd->is_slave_error)) + general_log_write(thd, COM_QUERY, thd->query(), thd->query_length()); thd->reset_query(); free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC)); diff --git a/sql/mdl.cc b/sql/mdl.cc index d8aa6e1d1b41d..ce2483a8d8ce0 100644 --- a/sql/mdl.cc +++ b/sql/mdl.cc @@ -124,15 +124,9 @@ class MDL_map_partition public: MDL_map_partition(); ~MDL_map_partition(); - inline MDL_lock *find_or_insert(const MDL_key *mdl_key, - my_hash_value_type hash_value); - unsigned long get_lock_owner(const MDL_key *key, - my_hash_value_type hash_value); + inline MDL_lock *find_or_insert(const MDL_key *mdl_key); + unsigned long get_lock_owner(const MDL_key *key); inline void remove(MDL_lock *lock); - my_hash_value_type get_key_hash(const MDL_key *mdl_key) const - { - return my_calc_hash(&m_locks, mdl_key->ptr(), mdl_key->length()); - } private: bool move_from_hash_to_lock_mutex(MDL_lock *lock); /** A partition of all acquired locks in the server. */ @@ -766,13 +760,21 @@ void MDL_map::init() } +my_hash_value_type mdl_hash_function(const CHARSET_INFO *cs, + const uchar *key, size_t length) +{ + MDL_key *mdl_key= (MDL_key*) (key - offsetof(MDL_key, m_ptr)); + return mdl_key->hash_value(); +} + + /** Initialize the partition in the container with all MDL locks. */ MDL_map_partition::MDL_map_partition() { mysql_mutex_init(key_MDL_map_mutex, &m_mutex, NULL); - my_hash_init(&m_locks, &my_charset_bin, 16 /* FIXME */, 0, 0, - mdl_locks_key, 0, 0); + my_hash_init2(&m_locks, 0, &my_charset_bin, 16 /* FIXME */, 0, 0, + mdl_locks_key, mdl_hash_function, 0, 0); }; @@ -846,11 +848,10 @@ MDL_lock* MDL_map::find_or_insert(const MDL_key *mdl_key) return lock; } - my_hash_value_type hash_value= m_partitions.at(0)->get_key_hash(mdl_key); - uint part_id= hash_value % mdl_locks_hash_partitions; + uint part_id= mdl_key->hash_value() % mdl_locks_hash_partitions; MDL_map_partition *part= m_partitions.at(part_id); - return part->find_or_insert(mdl_key, hash_value); + return part->find_or_insert(mdl_key); } @@ -863,15 +864,14 @@ MDL_lock* MDL_map::find_or_insert(const MDL_key *mdl_key) @retval NULL - Failure (OOM). */ -MDL_lock* MDL_map_partition::find_or_insert(const MDL_key *mdl_key, - my_hash_value_type hash_value) +MDL_lock* MDL_map_partition::find_or_insert(const MDL_key *mdl_key) { MDL_lock *lock; retry: mysql_mutex_lock(&m_mutex); if (!(lock= (MDL_lock*) my_hash_search_using_hash_value(&m_locks, - hash_value, + mdl_key->hash_value(), mdl_key->ptr(), mdl_key->length()))) { @@ -1023,10 +1023,9 @@ MDL_map::get_lock_owner(const MDL_key *mdl_key) } else { - my_hash_value_type hash_value= m_partitions.at(0)->get_key_hash(mdl_key); - uint part_id= hash_value % mdl_locks_hash_partitions; + uint part_id= mdl_key->hash_value() % mdl_locks_hash_partitions; MDL_map_partition *part= m_partitions.at(part_id); - res= part->get_lock_owner(mdl_key, hash_value); + res= part->get_lock_owner(mdl_key); } return res; } @@ -1034,15 +1033,14 @@ MDL_map::get_lock_owner(const MDL_key *mdl_key) unsigned long -MDL_map_partition::get_lock_owner(const MDL_key *mdl_key, - my_hash_value_type hash_value) +MDL_map_partition::get_lock_owner(const MDL_key *mdl_key) { MDL_lock *lock; unsigned long res= 0; mysql_mutex_lock(&m_mutex); lock= (MDL_lock*) my_hash_search_using_hash_value(&m_locks, - hash_value, + mdl_key->hash_value(), mdl_key->ptr(), mdl_key->length()); if (lock) diff --git a/sql/mdl.h b/sql/mdl.h index c7c445c75e173..6f31b46f17fbc 100644 --- a/sql/mdl.h +++ b/sql/mdl.h @@ -28,6 +28,7 @@ #include #include #include +#include #include @@ -347,12 +348,15 @@ class MDL_key m_ptr - 1); m_length= static_cast(strmake(m_ptr + m_db_name_length + 2, name, NAME_LEN) - m_ptr + 1); + m_hash_value= my_hash_sort(&my_charset_bin, (uchar*) m_ptr + 1, + m_length - 1); } void mdl_key_init(const MDL_key *rhs) { memcpy(m_ptr, rhs->m_ptr, rhs->m_length); m_length= rhs->m_length; m_db_name_length= rhs->m_db_name_length; + m_hash_value= rhs->m_hash_value; } bool is_equal(const MDL_key *rhs) const { @@ -392,15 +396,26 @@ class MDL_key { return & m_namespace_to_wait_state_name[(int)mdl_namespace()]; } + my_hash_value_type hash_value() const + { + return m_hash_value + mdl_namespace(); + } + my_hash_value_type tc_hash_value() const + { + return m_hash_value; + } private: uint16 m_length; uint16 m_db_name_length; + my_hash_value_type m_hash_value; char m_ptr[MAX_MDLKEY_LENGTH]; static PSI_stage_info m_namespace_to_wait_state_name[NAMESPACE_END]; private: MDL_key(const MDL_key &); /* not implemented */ MDL_key &operator=(const MDL_key &); /* not implemented */ + friend my_hash_value_type mdl_hash_function(const CHARSET_INFO *, + const uchar *, size_t); }; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 30d796c76884d..b08ecc399bf0e 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -7967,7 +7967,8 @@ static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param,COND *cond) value= cond_func->arg_count > 1 ? cond_func->arguments()[1] : NULL; if (value && value->is_expensive()) DBUG_RETURN(0); - ftree= get_full_func_mm_tree(param, cond_func, field_item, value, inv); + if (!cond_func->arguments()[0]->real_item()->const_item()) + ftree= get_full_func_mm_tree(param, cond_func, field_item, value, inv); } /* Even if get_full_func_mm_tree() was executed above and did not @@ -7992,7 +7993,8 @@ static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param,COND *cond) value= cond_func->arguments()[0]; if (value && value->is_expensive()) DBUG_RETURN(0); - ftree= get_full_func_mm_tree(param, cond_func, field_item, value, inv); + if (!cond_func->arguments()[1]->real_item()->const_item()) + ftree= get_full_func_mm_tree(param, cond_func, field_item, value, inv); } } @@ -10629,8 +10631,13 @@ static bool is_key_scan_ror(PARAM *param, uint keynr, uint8 nparts) if (param->table->field[fieldnr]->key_length() != kp->length) return FALSE; } - - if (key_part == key_part_end) + + /* + If there are equalities for all key parts, it is a ROR scan. If there are + equalities all keyparts and even some of key parts from "Extended Key" + index suffix, it is a ROR-scan, too. + */ + if (key_part >= key_part_end) return TRUE; key_part= table_key->key_part + nparts; diff --git a/sql/slave.cc b/sql/slave.cc index 8482924ef870f..74955c09cedcb 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1343,6 +1343,7 @@ bool is_network_error(uint errorno) errorno == ER_CON_COUNT_ERROR || errorno == ER_CONNECTION_KILLED || errorno == ER_NEW_ABORTING_CONNECTION || + errorno == ER_NET_READ_INTERRUPTED || errorno == ER_SERVER_SHUTDOWN) return TRUE; diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index fdb32233d9275..8d9989cd748d4 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1085,7 +1085,7 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables) table->use_all_columns(); (void) my_init_dynamic_array(&acl_users,sizeof(ACL_USER), 50, 100, MYF(0)); (void) my_hash_init2(&acl_roles,50, &my_charset_utf8_bin, - 0,0,0, (my_hash_get_key) acl_role_get_key, + 0, 0, 0, (my_hash_get_key) acl_role_get_key, 0, (void (*)(void *))free_acl_role, 0); username_char_length= MY_MIN(table->field[1]->char_length(), @@ -1427,8 +1427,8 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables) table->use_all_columns(); /* account for every role mapping */ - (void) my_hash_init2(&acl_roles_mappings, 50, system_charset_info, - 0,0,0, (my_hash_get_key) acl_role_map_get_key, 0,0); + (void) my_hash_init2(&acl_roles_mappings, 50, system_charset_info, 0, 0, 0, + (my_hash_get_key) acl_role_map_get_key, 0, 0, 0); MEM_ROOT temp_root; init_alloc_root(&temp_root, ACL_ALLOC_BLOCK_SIZE, 0, MYF(0)); while (!(read_record_info.read_record(&read_record_info))) @@ -3734,8 +3734,8 @@ class GRANT_TABLE :public GRANT_NAME bool ok() { return privs != 0 || cols != 0; } void init_hash() { - my_hash_init2(&hash_columns, 4, system_charset_info, - 0, 0, 0, (my_hash_get_key) get_key_column, 0, 0); + my_hash_init2(&hash_columns, 4, system_charset_info, 0, 0, 0, + (my_hash_get_key) get_key_column, 0, 0, 0); } }; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 8cfb7850ae3ca..82f98e0604b75 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2296,7 +2296,9 @@ bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, retry_share: share= tdc_acquire_share(thd, table_list->db, table_list->table_name, - key, key_length, gts_flags, &table); + key, key_length, + table_list->mdl_request.key.tc_hash_value(), + gts_flags, &table); if (!share) { diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 06a48d9157b01..cfef5eafa275c 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -19476,7 +19476,7 @@ 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) + if (key_part >= key_part_end) { /* We are at the end of the key. Check if the engine has the primary diff --git a/sql/sql_show.cc b/sql/sql_show.cc index a640e44ebe1e1..aa23f01ab7d38 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -8062,8 +8062,20 @@ static bool do_fill_table(THD *thd, da->push_warning_info(&wi_tmp); - bool res= table_list->schema_table->fill_table( - thd, table_list, join_table->select_cond); + Item *item= join_table->select_cond; + if (join_table->cache_select && + join_table->cache_select->cond) + { + /* + If join buffering is used, we should use the condition that is attached + to the join cache. Cache condition has a part of WHERE that can be + checked when we're populating this table. + join_tab->select_cond is of no interest, because it only has conditions + that depend on both this table and previous tables in the join order. + */ + item= join_table->cache_select->cond; + } + bool res= table_list->schema_table->fill_table(thd, table_list, item); da->pop_warning_info(); diff --git a/sql/table_cache.cc b/sql/table_cache.cc index ac6621226ef52..fbafd8e0c9fc6 100644 --- a/sql/table_cache.cc +++ b/sql/table_cache.cc @@ -664,16 +664,14 @@ void tdc_unlock_share(TABLE_SHARE *share) */ TABLE_SHARE *tdc_acquire_share(THD *thd, const char *db, const char *table_name, - const char *key, uint key_length, uint flags, + const char *key, uint key_length, + my_hash_value_type hash_value, uint flags, TABLE **out_table) { TABLE_SHARE *share; bool was_unused; - my_hash_value_type hash_value; DBUG_ENTER("tdc_acquire_share"); - hash_value= my_calc_hash(&tdc_hash, (uchar*) key, key_length); - mysql_rwlock_rdlock(&LOCK_tdc); share= (TABLE_SHARE*) my_hash_search_using_hash_value(&tdc_hash, hash_value, (uchar*) key, diff --git a/sql/table_cache.h b/sql/table_cache.h index a30a07b835789..6da6a6677926f 100644 --- a/sql/table_cache.h +++ b/sql/table_cache.h @@ -40,6 +40,7 @@ extern void tdc_unlock_share(TABLE_SHARE *share); extern TABLE_SHARE *tdc_acquire_share(THD *thd, const char *db, const char *table_name, const char *key, uint key_length, + my_hash_value_type hash_value, uint flags, TABLE **out_table); extern void tdc_release_share(TABLE_SHARE *share); extern bool tdc_remove_table(THD *thd, enum_tdc_remove_table_type remove_type, @@ -88,7 +89,9 @@ static inline TABLE_SHARE *tdc_acquire_share(THD *thd, const char *db, const char *key, uint key_length, uint flags) { - return tdc_acquire_share(thd, db, table_name, key, key_length, flags, 0); + return tdc_acquire_share(thd, db, table_name, key, key_length, + my_hash_sort(&my_charset_bin, (uchar*) key, + key_length), flags, 0); } @@ -120,7 +123,8 @@ static inline TABLE_SHARE *tdc_acquire_share_shortlived(THD *thd, TABLE_LIST *tl { const char *key; uint key_length= get_table_def_key(tl, &key); - return tdc_acquire_share(thd, tl->db, tl->table_name, key, key_length, flags); + return tdc_acquire_share(thd, tl->db, tl->table_name, key, key_length, + tl->mdl_request.key.tc_hash_value(), flags, 0); } diff --git a/storage/maria/maria_read_log.c b/storage/maria/maria_read_log.c index d9393399da408..f5b91f9628fc0 100644 --- a/storage/maria/maria_read_log.c +++ b/storage/maria/maria_read_log.c @@ -301,7 +301,7 @@ get_one_option(int optid __attribute__((unused)), if (!my_hash_inited(&tables_to_redo)) { my_hash_init2(&tables_to_redo, 16, &my_charset_bin, - 16, 0, 0, my_hash_get_string, 0, HASH_UNIQUE); + 16, 0, 0, my_hash_get_string, 0, 0, HASH_UNIQUE); } do { diff --git a/storage/xtradb/os/os0file.cc b/storage/xtradb/os/os0file.cc index 1b094bfa1f3a1..38be419e2adf0 100644 --- a/storage/xtradb/os/os0file.cc +++ b/storage/xtradb/os/os0file.cc @@ -1934,6 +1934,9 @@ os_file_create_func( } else { *success = TRUE; retry = FALSE; + if (srv_use_native_aio && ((attributes & FILE_FLAG_OVERLAPPED) != 0)) { + ut_a(CreateIoCompletionPort(file, completion_port, 0, 0)); + } } } while (retry); diff --git a/strings/ctype-bin.c b/strings/ctype-bin.c index 71dc78d759352..6e861f38ae4c2 100644 --- a/strings/ctype-bin.c +++ b/strings/ctype-bin.c @@ -276,7 +276,9 @@ void my_hash_sort_8bit_bin(CHARSET_INFO *cs __attribute__((unused)), const uchar *key, size_t len, ulong *nr1, ulong *nr2) { - + ulong tmp1= *nr1; + ulong tmp2= *nr2; + /* Remove trailing spaces. We have to do this to be able to compare 'A ' and 'A' as identical @@ -285,10 +287,13 @@ void my_hash_sort_8bit_bin(CHARSET_INFO *cs __attribute__((unused)), for (; key < end ; key++) { - nr1[0]^=(ulong) ((((uint) nr1[0] & 63)+nr2[0]) * - ((uint)*key)) + (nr1[0] << 8); - nr2[0]+=3; + tmp1^= (ulong) ((((uint) tmp1 & 63) + tmp2) * + ((uint) *key)) + (tmp1 << 8); + tmp2+= 3; } + + *nr1= tmp1; + *nr2= tmp2; } @@ -296,13 +301,18 @@ void my_hash_sort_bin(CHARSET_INFO *cs __attribute__((unused)), const uchar *key, size_t len,ulong *nr1, ulong *nr2) { const uchar *end = key + len; - + ulong tmp1= *nr1; + ulong tmp2= *nr2; + for (; key < end ; key++) { - nr1[0]^=(ulong) ((((uint) nr1[0] & 63)+nr2[0]) * - ((uint)*key)) + (nr1[0] << 8); - nr2[0]+=3; + tmp1^= (ulong) ((((uint) tmp1 & 63) + tmp2) * + ((uint) *key)) + (tmp1 << 8); + tmp2+= 3; } + + *nr1= tmp1; + *nr2= tmp2; } diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 509e0e7377727..b3bbebb243390 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -18749,6 +18749,109 @@ static void test_bug12337762() DBUG_VOID_RETURN; } +/* + MDEV-4603: mysql_stmt_reset doesn't clear + all result sets (from stored procedures). + This test requires also fix for MDEV-4604 +*/ +static void test_mdev4603() +{ + MYSQL *my; + MYSQL_STMT *stmt; + int i, rc; + int a[] = {10,20,30}; + MYSQL_BIND bind[3]; + + myheader("test_mdev4603"); + my= mysql_client_init(NULL); + + if (!mysql_real_connect(my, opt_host, opt_user, + opt_password, current_db, opt_port, + opt_unix_socket, CLIENT_MULTI_RESULTS)) + DIE("mysql_real_connect failed"); + + /* 1st test: + use a procedure with out param + */ + rc= mysql_query(my, "DROP PROCEDURE IF EXISTS p1"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE PROCEDURE p1(OUT p_out VARCHAR(19), IN p_in INT, INOUT p_inout INT)" + "BEGIN " + " SET p_in = 300, p_out := 'This is OUT param', p_inout = 200; " + " SELECT p_inout, p_in, substring(p_out, 9);" + "END"); + myquery(rc); + + stmt= mysql_stmt_init(mysql); + DIE_UNLESS(stmt != NULL); + + rc= mysql_stmt_prepare(stmt, "CALL P1(?,?,?)", 14); + DIE_UNLESS(rc == 0); + + DIE_UNLESS(mysql_stmt_param_count(stmt) == 3); + + memset(bind, 0, sizeof(MYSQL_BIND) * 3); + for (i=0; i < 3; i++) + { + bind[i].buffer= &a[i]; + bind[i].buffer_type= MYSQL_TYPE_LONG; + } + bind[0].buffer_type= MYSQL_TYPE_NULL; + rc= mysql_stmt_bind_param(stmt, bind); + DIE_UNLESS(rc == 0); + + rc= mysql_stmt_execute(stmt); + DIE_UNLESS(rc == 0); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == 0); + + rc= mysql_stmt_reset(stmt); + DIE_UNLESS(rc == 0); + + /*connection shouldn't be blocked now */ + + rc= mysql_query(mysql, "DROP PROCEDURE p1"); + myquery(rc); + + /* 2nd test: + reset all result sets */ + rc= mysql_query(my, "CREATE PROCEDURE p1() " + "BEGIN" + " SELECT 1,2,3 FROM DUAL;" + " SELECT 'foo' FROM DUAL;" + "END"); + myquery(rc); + + rc= mysql_stmt_prepare(stmt, "CALL P1()", 9); + DIE_UNLESS(rc == 0); + + rc= mysql_stmt_execute(stmt); + DIE_UNLESS(rc == 0); + + rc= mysql_stmt_reset(stmt); + DIE_UNLESS(rc == 0); + + /* 3rd test: + mysql_stmt_close should also flush all pending + result sets + */ + + rc= mysql_stmt_prepare(stmt, "CALL P1()", 9); + DIE_UNLESS(rc == 0); + + rc= mysql_stmt_execute(stmt); + DIE_UNLESS(rc == 0); + + rc= mysql_stmt_close(stmt); + DIE_UNLESS(rc == 0); + + rc= mysql_query(my, "DROP PROCEDURE p1"); + myquery(rc); + + mysql_close(my); +} /* BUG 11754979 - 46675: ON DUPLICATE KEY UPDATE AND UPDATECOUNT() POSSIBLY WRONG @@ -19289,6 +19392,7 @@ static struct my_tests_st my_tests[]= { { "test_bug57058", test_bug57058 }, { "test_bug56976", test_bug56976 }, { "test_mdev3885", test_mdev3885 }, + { "test_mdev4603", test_mdev4603 }, { "test_bug11766854", test_bug11766854 }, { "test_bug12337762", test_bug12337762 }, { "test_progress_reporting", test_progress_reporting },