From 14f6b0cdfd696ec0e4f24d914fc3123deaece2f6 Mon Sep 17 00:00:00 2001 From: Varun Gupta Date: Tue, 20 Nov 2018 20:12:29 +0530 Subject: [PATCH 01/14] MDEV-17734: AddressSanitizer: use-after-poison in create_key_parts_for_pseudo_indexes In this case we were trying to access memory for key_parts which we did not assign for a fields because it did not any EITS statistics. The check if EITS statistics for a column is avaialable or not was missing. --- sql/opt_range.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 3bcaa72e32f..a3943cbe3ff 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -3350,7 +3350,9 @@ bool create_key_parts_for_pseudo_indexes(RANGE_OPT_PARAM *param, if (bitmap_is_set(used_fields, (*field_ptr)->field_index)) { Field *field= *field_ptr; - if (field->type() == MYSQL_TYPE_GEOMETRY) + Column_statistics* col_stats= field->read_stats; + if (field->type() == MYSQL_TYPE_GEOMETRY || + !col_stats || col_stats->no_stat_values_provided()) continue; uint16 store_length; From 244cc35e7b929376e445adad8996de154ebc9c8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Thu, 22 Nov 2018 16:30:20 +0200 Subject: [PATCH 02/14] MDEV-17801: Galera test failure on galera_var_reject_queries Problem was that controlling connection i.e. connection that executed the query SET GLOBAL wsrep_reject_queries = ALL_KILL; was also killed but server would try to send result from that query to controlling connection resulting a assertion mysqld: /home/jan/mysql/10.2-sst/include/mysql/psi/mysql_socket.h:738: inline_mysql_socket_send: Assertion `mysql_socket.fd != -1' failed. as socket was closed when controlling connection was closed. wsrep_close_client_connections() Do not close controlling connection and instead of wsrep_close_thread() we do now soft kill by THD::awake wsrep_reject_queries_update() Call wsrep_close_client_connections using current thd. --- .../galera/r/galera_var_reject_queries.result | 1 - .../galera/t/galera_var_reject_queries.test | 7 ++++-- sql/wsrep_mysqld.cc | 22 ++++++++++++++++--- sql/wsrep_mysqld.h | 4 ++-- sql/wsrep_var.cc | 3 ++- 5 files changed, 28 insertions(+), 9 deletions(-) diff --git a/mysql-test/suite/galera/r/galera_var_reject_queries.result b/mysql-test/suite/galera/r/galera_var_reject_queries.result index 5958e6ae981..1c932eb5509 100644 --- a/mysql-test/suite/galera/r/galera_var_reject_queries.result +++ b/mysql-test/suite/galera/r/galera_var_reject_queries.result @@ -5,7 +5,6 @@ SET GLOBAL wsrep_reject_queries = ALL; SELECT * FROM t1; ERROR 08S01: WSREP has not yet prepared node for application use SET GLOBAL wsrep_reject_queries = ALL_KILL; -ERROR HY000: Lost connection to MySQL server during query SELECT * FROM t1; Got one of the listed errors SELECT * FROM t1; diff --git a/mysql-test/suite/galera/t/galera_var_reject_queries.test b/mysql-test/suite/galera/t/galera_var_reject_queries.test index 6859855c35f..8b80c04e3be 100644 --- a/mysql-test/suite/galera/t/galera_var_reject_queries.test +++ b/mysql-test/suite/galera/t/galera_var_reject_queries.test @@ -18,8 +18,11 @@ SET GLOBAL wsrep_reject_queries = ALL; --error ER_UNKNOWN_COM_ERROR SELECT * FROM t1; -# Lost connection ---error 2013 +# +# Original behavior was lost connection, +# but since 10.1, we allow controlling connection to remain alive +# +--error 0,2013 SET GLOBAL wsrep_reject_queries = ALL_KILL; --connection node_1a diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index c3f5dd1ce97..47aea6d3824 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -2229,7 +2229,7 @@ int wsrep_wait_committing_connections_close(int wait_time) } -void wsrep_close_client_connections(my_bool wait_to_end) +void wsrep_close_client_connections(my_bool wait_to_end, THD *except_caller_thd) { /* First signal all threads that it's time to die @@ -2251,6 +2251,12 @@ void wsrep_close_client_connections(my_bool wait_to_end) if (!is_client_connection(tmp)) continue; + if (tmp == except_caller_thd) + { + DBUG_ASSERT(is_client_connection(tmp)); + continue; + } + if (is_replaying_connection(tmp)) { tmp->set_killed(KILL_CONNECTION); @@ -2262,7 +2268,16 @@ void wsrep_close_client_connections(my_bool wait_to_end) continue; WSREP_DEBUG("closing connection %ld", tmp->thread_id); - wsrep_close_thread(tmp); + + /* + instead of wsrep_close_thread() we do now soft kill by THD::awake + */ + mysql_mutex_lock(&tmp->LOCK_thd_data); + + tmp->awake(KILL_CONNECTION); + + mysql_mutex_unlock(&tmp->LOCK_thd_data); + } mysql_mutex_unlock(&LOCK_thread_count); @@ -2280,7 +2295,8 @@ void wsrep_close_client_connections(my_bool wait_to_end) #ifndef __bsdi__ // Bug in BSDI kernel if (is_client_connection(tmp) && !abort_replicated(tmp) && - !is_replaying_connection(tmp)) + !is_replaying_connection(tmp) && + tmp != except_caller_thd) { WSREP_INFO("killing local connection: %ld",tmp->thread_id); close_connection(tmp,0); diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h index 43f0d53393d..2814f4013d8 100644 --- a/sql/wsrep_mysqld.h +++ b/sql/wsrep_mysqld.h @@ -161,7 +161,6 @@ extern "C" query_id_t wsrep_thd_query_id(THD *thd); extern "C" query_id_t wsrep_thd_wsrep_last_query_id(THD *thd); extern "C" void wsrep_thd_set_wsrep_last_query_id(THD *thd, query_id_t id); -extern void wsrep_close_client_connections(my_bool wait_to_end); extern int wsrep_wait_committing_connections_close(int wait_time); extern void wsrep_close_applier(THD *thd); extern void wsrep_wait_appliers_close(THD *thd); @@ -314,7 +313,8 @@ void thd_binlog_trx_reset(THD * thd); typedef void (*wsrep_thd_processor_fun)(THD *); pthread_handler_t start_wsrep_THD(void *arg); int wsrep_wait_committing_connections_close(int wait_time); -void wsrep_close_client_connections(my_bool wait_to_end); +extern void wsrep_close_client_connections(my_bool wait_to_end, + THD *except_caller_thd = NULL); void wsrep_close_applier(THD *thd); void wsrep_close_applier_threads(int count); void wsrep_wait_appliers_close(THD *thd); diff --git a/sql/wsrep_var.cc b/sql/wsrep_var.cc index 718676025f9..3959746156a 100644 --- a/sql/wsrep_var.cc +++ b/sql/wsrep_var.cc @@ -398,7 +398,8 @@ bool wsrep_reject_queries_update(sys_var *self, THD* thd, enum_var_type type) WSREP_INFO("Rejecting client queries due to manual setting"); break; case WSREP_REJECT_ALL_KILL: - wsrep_close_client_connections(FALSE); + /* close all client connections, but this one */ + wsrep_close_client_connections(FALSE, thd); WSREP_INFO("Rejecting client queries and killing connections due to manual setting"); break; default: From 1037edcb1140aa0bdf1d52f118d9008084f842b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Thu, 22 Nov 2018 16:33:20 +0200 Subject: [PATCH 03/14] MDEV-17804: Galera tests cause mysql_socket.h:738: inline_mysql_socket_send: Assertion `mysql_socket.fd != -1' failed. Do not do end of statement logic if thd is already killed as socket is already closed. --- .../galera/r/galera_ist_mysqldump,debug.rdiff | 19 +++++++++++++++---- sql/sql_parse.cc | 3 ++- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/mysql-test/suite/galera/r/galera_ist_mysqldump,debug.rdiff b/mysql-test/suite/galera/r/galera_ist_mysqldump,debug.rdiff index 74e6abd713f..141b1ebd25f 100644 --- a/mysql-test/suite/galera/r/galera_ist_mysqldump,debug.rdiff +++ b/mysql-test/suite/galera/r/galera_ist_mysqldump,debug.rdiff @@ -1,11 +1,12 @@ ---- r/galera_ist_mysqldump.result 2018-09-11 12:38:42.027479411 +0300 -+++ r/galera_ist_mysqldump.reject 2018-09-17 10:28:44.483441364 +0300 -@@ -180,6 +180,103 @@ +--- r/galera_ist_mysqldump.result 2018-11-22 14:25:28.551554055 +0200 ++++ r/galera_ist_mysqldump.reject 2018-11-22 15:46:33.119441931 +0200 +@@ -200,6 +200,114 @@ DROP TABLE t1; COMMIT; SET AUTOCOMMIT=ON; +Performing State Transfer on a server that has been killed and restarted +while a DDL was in progress on it ++connection node_1; +CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB; +SET AUTOCOMMIT=OFF; +START TRANSACTION; @@ -14,6 +15,7 @@ +INSERT INTO t1 VALUES ('node1_committed_before'); +INSERT INTO t1 VALUES ('node1_committed_before'); +INSERT INTO t1 VALUES ('node1_committed_before'); ++connection node_2; +START TRANSACTION; +INSERT INTO t1 VALUES ('node2_committed_before'); +INSERT INTO t1 VALUES ('node2_committed_before'); @@ -22,9 +24,12 @@ +INSERT INTO t1 VALUES ('node2_committed_before'); +COMMIT; +SET GLOBAL debug_dbug = 'd,sync.alter_opened_table'; ++connection node_1; +ALTER TABLE t1 ADD COLUMN f2 INTEGER; ++connection node_2; +SET wsrep_sync_wait = 0; +Killing server ... ++connection node_1; +SET AUTOCOMMIT=OFF; +START TRANSACTION; +INSERT INTO t1 (f1) VALUES ('node1_committed_during'); @@ -39,6 +44,7 @@ +INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); +INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); +INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); ++connect node_1a_galera_st_kill_slave_ddl, 127.0.0.1, root, , test, $NODE_MYPORT_1; +SET AUTOCOMMIT=OFF; +START TRANSACTION; +INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); @@ -46,7 +52,9 @@ +INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); +INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); +INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); ++connection node_2; +Performing --wsrep-recover ... ++connection node_2; +Starting server ... +Using --wsrep-start-position when starting mysqld ... +SET AUTOCOMMIT=OFF; @@ -57,6 +65,7 @@ +INSERT INTO t1 (f1) VALUES ('node2_committed_after'); +INSERT INTO t1 (f1) VALUES ('node2_committed_after'); +COMMIT; ++connection node_1; +INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); +INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); +INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); @@ -71,6 +80,7 @@ +INSERT INTO t1 (f1) VALUES ('node1_committed_after'); +INSERT INTO t1 (f1) VALUES ('node1_committed_after'); +COMMIT; ++connection node_1a_galera_st_kill_slave_ddl; +INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); +INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); +INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); @@ -88,6 +98,7 @@ +1 +COMMIT; +SET AUTOCOMMIT=ON; ++connection node_1; +SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1'; +COUNT(*) = 2 +1 @@ -101,6 +112,6 @@ +COMMIT; +SET AUTOCOMMIT=ON; +SET GLOBAL debug_dbug = $debug_orig; + connection node_1; CALL mtr.add_suppression("Slave SQL: Error 'The MySQL server is running with the --skip-grant-tables option so it cannot execute this statement' on query"); DROP USER sst; - CALL mtr.add_suppression("Slave SQL: Error 'The MySQL server is running with the --skip-grant-tables option so it cannot execute this statement' on query"); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index a76d9f0bbd3..a73c3c22ba8 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1940,7 +1940,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd, /* wsrep BF abort in query exec phase */ mysql_mutex_lock(&thd->LOCK_thd_data); do_end_of_statement= thd->wsrep_conflict_state != REPLAYING && - thd->wsrep_conflict_state != RETRY_AUTOCOMMIT; + thd->wsrep_conflict_state != RETRY_AUTOCOMMIT && + !thd->killed; mysql_mutex_unlock(&thd->LOCK_thd_data); } else From 328d7779bc1e5b88b7f72dde8465d0c58f38f42c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Mon, 26 Nov 2018 08:58:38 +0200 Subject: [PATCH 04/14] Fortify galera_sst_mariabackup_table_options test. --- .../galera/t/galera_sst_mariabackup_table_options.test | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/mysql-test/suite/galera/t/galera_sst_mariabackup_table_options.test b/mysql-test/suite/galera/t/galera_sst_mariabackup_table_options.test index 61cef44135b..03eef64facc 100644 --- a/mysql-test/suite/galera/t/galera_sst_mariabackup_table_options.test +++ b/mysql-test/suite/galera/t/galera_sst_mariabackup_table_options.test @@ -3,6 +3,11 @@ --source include/innodb_encrypt_tables.inc --source include/have_mariabackup.inc +# Save original auto_increment_offset values. +--let $node_1=node_1 +--let $node_2=node_2 +--source include/auto_increment_offset_save.inc + --echo Performing State Transfer on a server that starts from a clean var directory --echo This is accomplished by shutting down node #2 and removing its var directory before restarting it @@ -216,3 +221,6 @@ COMMIT; DROP TABLE t1,t2,t3,t4,t5,t6,t7,t8,t9; COMMIT; SET AUTOCOMMIT=ON; + +# Restore original auto_increment_offset values. +--source include/auto_increment_offset_restore.inc From 5ec9b88e11118c798ff2381771a72f76b2b72f9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 4 Dec 2018 15:29:49 +0200 Subject: [PATCH 05/14] Disable a frequently failing test --- mysql-test/suite/encryption/disabled.def | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/suite/encryption/disabled.def b/mysql-test/suite/encryption/disabled.def index d92d3495cb8..746faf49873 100644 --- a/mysql-test/suite/encryption/disabled.def +++ b/mysql-test/suite/encryption/disabled.def @@ -12,3 +12,4 @@ innodb_scrub : MDEV-8139 scrubbing does not work reliably innodb_scrub_background : MDEV-8139 scrubbing does not work reliably +innodb-redo-badkey : MDEV-13893/MDEV-12699 fix recovery of corrupted pages From 17e85702856775faad43beb8aedf3088e8f34da6 Mon Sep 17 00:00:00 2001 From: Varun Gupta Date: Wed, 5 Dec 2018 19:27:34 +0530 Subject: [PATCH 06/14] Added a testcase for mdev-17734 --- mysql-test/r/stat_tables.result | 19 +++++++++++++++++++ mysql-test/r/stat_tables_innodb.result | 19 +++++++++++++++++++ mysql-test/t/stat_tables.test | 17 +++++++++++++++++ 3 files changed, 55 insertions(+) diff --git a/mysql-test/r/stat_tables.result b/mysql-test/r/stat_tables.result index cd78d44462e..6266526a0d1 100644 --- a/mysql-test/r/stat_tables.result +++ b/mysql-test/r/stat_tables.result @@ -590,3 +590,22 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE user ALL NULL NULL NULL NULL 4 Using join buffer (flat, BNL join) set @@optimizer_use_condition_selectivity=@save_optimizer_use_condition_selectivity; set use_stat_tables=@save_use_stat_tables; +# +# MDEV-17734: AddressSanitizer: use-after-poison in create_key_parts_for_pseudo_indexes +# +set @@use_stat_tables= PREFERABLY; +set @save_optimizer_use_condition_selectivity= @@optimizer_use_condition_selectivity; +set @@optimizer_use_condition_selectivity=4; +set @save_use_stat_tables= @@use_stat_tables; +create table t1 (a int, b int); +insert into t1(a,b) values (1,2),(1,3),(1,4),(1,5),(2,6),(2,7),(3,8),(3,9),(3,9),(4,10); +analyze table t1 persistent for columns (a) indexes (); +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze status OK +select * from t1 where a=1 and b=3; +a b +1 3 +set @@optimizer_use_condition_selectivity= @save_optimizer_use_condition_selectivity; +set use_stat_tables=@save_use_stat_tables; +drop table t1; diff --git a/mysql-test/r/stat_tables_innodb.result b/mysql-test/r/stat_tables_innodb.result index 02a07fa8bbb..cc5354bf2d7 100644 --- a/mysql-test/r/stat_tables_innodb.result +++ b/mysql-test/r/stat_tables_innodb.result @@ -617,5 +617,24 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE user ALL NULL NULL NULL NULL 4 Using join buffer (flat, BNL join) set @@optimizer_use_condition_selectivity=@save_optimizer_use_condition_selectivity; set use_stat_tables=@save_use_stat_tables; +# +# MDEV-17734: AddressSanitizer: use-after-poison in create_key_parts_for_pseudo_indexes +# +set @@use_stat_tables= PREFERABLY; +set @save_optimizer_use_condition_selectivity= @@optimizer_use_condition_selectivity; +set @@optimizer_use_condition_selectivity=4; +set @save_use_stat_tables= @@use_stat_tables; +create table t1 (a int, b int); +insert into t1(a,b) values (1,2),(1,3),(1,4),(1,5),(2,6),(2,7),(3,8),(3,9),(3,9),(4,10); +analyze table t1 persistent for columns (a) indexes (); +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze status OK +select * from t1 where a=1 and b=3; +a b +1 3 +set @@optimizer_use_condition_selectivity= @save_optimizer_use_condition_selectivity; +set use_stat_tables=@save_use_stat_tables; +drop table t1; set optimizer_switch=@save_optimizer_switch_for_stat_tables_test; SET SESSION STORAGE_ENGINE=DEFAULT; diff --git a/mysql-test/t/stat_tables.test b/mysql-test/t/stat_tables.test index a0b2a22b946..37106f4ec7a 100644 --- a/mysql-test/t/stat_tables.test +++ b/mysql-test/t/stat_tables.test @@ -368,3 +368,20 @@ explain SELECT * FROM INFORMATION_SCHEMA.PROFILING, mysql.user; set @@optimizer_use_condition_selectivity=@save_optimizer_use_condition_selectivity; set use_stat_tables=@save_use_stat_tables; + +--echo # +--echo # MDEV-17734: AddressSanitizer: use-after-poison in create_key_parts_for_pseudo_indexes +--echo # + +set @@use_stat_tables= PREFERABLY; +set @save_optimizer_use_condition_selectivity= @@optimizer_use_condition_selectivity; +set @@optimizer_use_condition_selectivity=4; +set @save_use_stat_tables= @@use_stat_tables; +create table t1 (a int, b int); +insert into t1(a,b) values (1,2),(1,3),(1,4),(1,5),(2,6),(2,7),(3,8),(3,9),(3,9),(4,10); + +analyze table t1 persistent for columns (a) indexes (); +select * from t1 where a=1 and b=3; +set @@optimizer_use_condition_selectivity= @save_optimizer_use_condition_selectivity; +set use_stat_tables=@save_use_stat_tables; +drop table t1; From 8a37ce07672df44d06c0ea7b66e0c3136b1e6ab0 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 6 Dec 2018 00:48:00 +0100 Subject: [PATCH 07/14] cleanup: DYNAMIC_ARRAY -> Dynamic_array acl_dbs --- sql/sql_acl.cc | 77 ++++++++++++++++++++++++------------------------- sql/sql_array.h | 13 +++++++-- 2 files changed, 48 insertions(+), 42 deletions(-) diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 8eefddf57cc..d78d45c32af 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -714,7 +714,9 @@ bool ROLE_GRANT_PAIR::init(MEM_ROOT *mem, char *username, /* Flag to mark that on_node was already called for this role */ #define ROLE_OPENED (1L << 3) -static DYNAMIC_ARRAY acl_hosts, acl_users, acl_dbs, acl_proxy_users; +static DYNAMIC_ARRAY acl_hosts, acl_users, acl_proxy_users; +static Dynamic_array acl_dbs(0U,50U); +typedef Dynamic_array::CMP_FUNC acl_dbs_cmp; static HASH acl_roles; /* An hash containing mappings user <--> role @@ -1408,12 +1410,11 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables) db.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL; } #endif - (void) push_dynamic(&acl_dbs,(uchar*) &db); + acl_dbs.push(db); } - my_qsort((uchar*) dynamic_element(&acl_dbs,0,ACL_DB*),acl_dbs.elements, - sizeof(ACL_DB),(qsort_cmp) acl_compare); end_read_record(&read_record_info); - freeze_size(&acl_dbs); + acl_dbs.sort((acl_dbs_cmp)acl_compare); + acl_dbs.freeze(); if (tables[3].table) { @@ -1502,7 +1503,7 @@ void acl_free(bool end) free_root(&acl_memroot,MYF(0)); delete_dynamic(&acl_hosts); delete_dynamic_with_callback(&acl_users, (FREE_FUNC) free_acl_user); - delete_dynamic(&acl_dbs); + acl_dbs.free_memory(); delete_dynamic(&acl_wild_hosts); delete_dynamic(&acl_proxy_users); my_hash_free(&acl_check_hosts); @@ -1541,7 +1542,8 @@ void acl_free(bool end) my_bool acl_reload(THD *thd) { TABLE_LIST tables[5]; - DYNAMIC_ARRAY old_acl_hosts, old_acl_users, old_acl_dbs, old_acl_proxy_users; + DYNAMIC_ARRAY old_acl_hosts, old_acl_users, old_acl_proxy_users; + Dynamic_array old_acl_dbs(0U,0U); HASH old_acl_roles, old_acl_roles_mappings; MEM_ROOT old_mem; my_bool return_val= TRUE; @@ -1595,7 +1597,7 @@ my_bool acl_reload(THD *thd) old_acl_dbs= acl_dbs; my_init_dynamic_array(&acl_hosts, sizeof(ACL_HOST), 20, 50, MYF(0)); my_init_dynamic_array(&acl_users, sizeof(ACL_USER), 50, 100, MYF(0)); - my_init_dynamic_array(&acl_dbs, sizeof(ACL_DB), 50, 100, MYF(0)); + acl_dbs.init(50, 100); my_init_dynamic_array(&acl_proxy_users, sizeof(ACL_PROXY_USER), 50, 100, MYF(0)); my_hash_init2(&acl_roles,50, &my_charset_utf8_bin, 0, 0, 0, (my_hash_get_key) acl_role_get_key, 0, @@ -1616,6 +1618,7 @@ my_bool acl_reload(THD *thd) acl_roles_mappings= old_acl_roles_mappings; acl_proxy_users= old_acl_proxy_users; acl_dbs= old_acl_dbs; + old_acl_dbs.init(0,0); acl_memroot= old_mem; init_check_host(); } @@ -1626,7 +1629,6 @@ my_bool acl_reload(THD *thd) delete_dynamic(&old_acl_hosts); delete_dynamic_with_callback(&old_acl_users, (FREE_FUNC) free_acl_user); delete_dynamic(&old_acl_proxy_users); - delete_dynamic(&old_acl_dbs); my_hash_free(&old_acl_roles_mappings); } mysql_mutex_unlock(&acl_cache->lock); @@ -1809,9 +1811,9 @@ bool acl_getroot(Security_context *sctx, char *user, char *host, if (acl_user) { res= 0; - for (i=0 ; i < acl_dbs.elements ; i++) + for (i=0 ; i < acl_dbs.elements() ; i++) { - ACL_DB *acl_db= dynamic_element(&acl_dbs, i, ACL_DB*); + ACL_DB *acl_db= &acl_dbs.at(i); if (!acl_db->user || (user && user[0] && !strcmp(user, acl_db->user))) { @@ -1840,9 +1842,9 @@ bool acl_getroot(Security_context *sctx, char *user, char *host, if (acl_role) { res= 0; - for (i=0 ; i < acl_dbs.elements ; i++) + for (i=0 ; i < acl_dbs.elements() ; i++) { - ACL_DB *acl_db= dynamic_element(&acl_dbs, i, ACL_DB*); + ACL_DB *acl_db= &acl_dbs.at(i); if (!acl_db->user || (user && user[0] && !strcmp(user, acl_db->user))) { @@ -2136,9 +2138,9 @@ static bool acl_update_db(const char *user, const char *host, const char *db, bool updated= false; - for (uint i=0 ; i < acl_dbs.elements ; i++) + for (uint i=0 ; i < acl_dbs.elements() ; i++) { - ACL_DB *acl_db=dynamic_element(&acl_dbs,i,ACL_DB*); + ACL_DB *acl_db= &acl_dbs.at(i); if ((!acl_db->user && !user[0]) || (acl_db->user && !strcmp(user,acl_db->user))) @@ -2157,7 +2159,7 @@ static bool acl_update_db(const char *user, const char *host, const char *db, acl_db->initial_access= acl_db->access; } else - delete_dynamic_element(&acl_dbs,i); + acl_dbs.del(i); updated= true; } } @@ -2192,9 +2194,8 @@ static void acl_insert_db(const char *user, const char *host, const char *db, acl_db.db=strdup_root(&acl_memroot,db); acl_db.initial_access= acl_db.access= privileges; acl_db.sort=get_sort(3,acl_db.host.hostname,acl_db.db,acl_db.user); - (void) push_dynamic(&acl_dbs,(uchar*) &acl_db); - my_qsort((uchar*) dynamic_element(&acl_dbs,0,ACL_DB*),acl_dbs.elements, - sizeof(ACL_DB),(qsort_cmp) acl_compare); + acl_dbs.push(acl_db); + acl_dbs.sort((acl_dbs_cmp)acl_compare); } @@ -2240,9 +2241,9 @@ ulong acl_get(const char *host, const char *ip, /* Check if there are some access rights for database and user */ - for (i=0 ; i < acl_dbs.elements ; i++) + for (i=0 ; i < acl_dbs.elements() ; i++) { - ACL_DB *acl_db=dynamic_element(&acl_dbs,i,ACL_DB*); + ACL_DB *acl_db= &acl_dbs.at(i); if (!acl_db->user || !strcmp(user,acl_db->user)) { if (compare_hostname(&acl_db->host,host,ip)) @@ -4931,7 +4932,7 @@ static int update_role_db(ACL_DB *merged, ACL_DB **first, ulong access, char *ro acl_db.access= access; acl_db.initial_access= 0; acl_db.sort=get_sort(3, "", acl_db.db, role); - push_dynamic(&acl_dbs,(uchar*) &acl_db); + acl_dbs.push(acl_db); return 2; } else if (access == 0) @@ -4976,9 +4977,9 @@ static bool merge_role_db_privileges(ACL_ROLE *grantee, const char *dbname, Collect these applicable db grants. */ - for (uint i=0 ; i < acl_dbs.elements ; i++) + for (uint i=0 ; i < acl_dbs.elements() ; i++) { - ACL_DB *db= dynamic_element(&acl_dbs,i,ACL_DB*); + ACL_DB *db= &acl_dbs.at(i); if (db->host.hostname[0]) continue; if (dbname && strcmp(db->db, dbname)) @@ -5022,14 +5023,12 @@ static bool merge_role_db_privileges(ACL_ROLE *grantee, const char *dbname, */ if (update_flags & (2|4)) { // inserted or deleted, need to sort - my_qsort((uchar*) dynamic_element(&acl_dbs,0,ACL_DB*),acl_dbs.elements, - sizeof(ACL_DB),(qsort_cmp) acl_compare); + acl_dbs.sort((acl_dbs_cmp)acl_compare); } if (update_flags & 4) { // deleted, trim the end - while (acl_dbs.elements && - dynamic_element(&acl_dbs, acl_dbs.elements-1, ACL_DB*)->sort == 0) - acl_dbs.elements--; + while (acl_dbs.elements() && acl_dbs.back()->sort == 0) + acl_dbs.pop(); } return update_flags; } @@ -7911,16 +7910,14 @@ static bool show_database_privileges(THD *thd, const char *username, const char *hostname, char *buff, size_t buffsize) { - ACL_DB *acl_db; ulong want_access; - uint counter; Protocol *protocol= thd->protocol; - for (counter=0 ; counter < acl_dbs.elements ; counter++) + for (uint i=0 ; i < acl_dbs.elements() ; i++) { const char *user, *host; - acl_db=dynamic_element(&acl_dbs,counter,ACL_DB*); + ACL_DB *acl_db= &acl_dbs.at(i); user= safe_str(acl_db->user); host=acl_db->host.hostname; @@ -8798,7 +8795,7 @@ static int handle_grant_struct(enum enum_acl_lists struct_no, bool drop, elements= acl_users.elements; break; case DB_ACL: - elements= acl_dbs.elements; + elements= acl_dbs.elements(); break; case COLUMN_PRIVILEGES_HASH: grant_name_hash= &column_priv_hash; @@ -8842,7 +8839,7 @@ static int handle_grant_struct(enum enum_acl_lists struct_no, bool drop, break; case DB_ACL: - acl_db= dynamic_element(&acl_dbs, idx, ACL_DB*); + acl_db= &acl_dbs.at(idx); user= acl_db->user; host= acl_db->host.hostname; break; @@ -8926,7 +8923,7 @@ static int handle_grant_struct(enum enum_acl_lists struct_no, bool drop, break; case DB_ACL: - delete_dynamic_element(&acl_dbs, idx); + acl_dbs.del(idx); break; case COLUMN_PRIVILEGES_HASH: @@ -9614,11 +9611,11 @@ bool mysql_revoke_all(THD *thd, List &list) */ do { - for (counter= 0, revoked= 0 ; counter < acl_dbs.elements ; ) + for (counter= 0, revoked= 0 ; counter < acl_dbs.elements() ; ) { const char *user,*host; - acl_db=dynamic_element(&acl_dbs,counter,ACL_DB*); + acl_db=&acl_dbs.at(counter); user= safe_str(acl_db->user); host= safe_str(acl_db->host.hostname); @@ -10451,11 +10448,11 @@ int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond) DBUG_RETURN(0); mysql_mutex_lock(&acl_cache->lock); - for (counter=0 ; counter < acl_dbs.elements ; counter++) + for (counter=0 ; counter < acl_dbs.elements() ; counter++) { const char *user, *host, *is_grantable="YES"; - acl_db=dynamic_element(&acl_dbs,counter,ACL_DB*); + acl_db=&acl_dbs.at(counter); user= safe_str(acl_db->user); host= safe_str(acl_db->host.hostname); diff --git a/sql/sql_array.h b/sql/sql_array.h index 8202e94ce41..37e86008ef0 100644 --- a/sql/sql_array.h +++ b/sql/sql_array.h @@ -107,8 +107,7 @@ public: void init(uint prealloc=16, uint increment=16) { - my_init_dynamic_array(&array, sizeof(Elem), prealloc, increment, - MYF(0)); + init_dynamic_array2(&array, sizeof(Elem), 0, prealloc, increment, MYF(0)); } /** @@ -201,6 +200,11 @@ public: set_dynamic(&array, &el, idx); } + void freeze() + { + freeze_size(&array); + } + bool resize(size_t new_size, Elem default_val) { size_t old_size= elements(); @@ -223,6 +227,11 @@ public: delete_dynamic(&array); } + void free_memory() + { + delete_dynamic(&array); + } + typedef int (*CMP_FUNC)(const Elem *el1, const Elem *el2); void sort(CMP_FUNC cmp_func) From eed0013bedcf13b2f95acfa793626e758dd0489b Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 6 Dec 2018 00:48:41 +0100 Subject: [PATCH 08/14] correct order of arguments for Dynamic_array<>::CMP_FUNC2 --- sql/sql_array.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_array.h b/sql/sql_array.h index 37e86008ef0..c18bec1df52 100644 --- a/sql/sql_array.h +++ b/sql/sql_array.h @@ -239,7 +239,7 @@ public: my_qsort(array.buffer, array.elements, sizeof(Elem), (qsort_cmp)cmp_func); } - typedef int (*CMP_FUNC2)(const Elem *el1, const Elem *el2, void *); + typedef int (*CMP_FUNC2)(void *, const Elem *el1, const Elem *el2); void sort(CMP_FUNC2 cmp_func, void *data) { my_qsort2(array.buffer, array.elements, sizeof(Elem), (qsort2_cmp)cmp_func, data); From daca7e70d70cfc59b4139239bbd09b7c63912be9 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 6 Dec 2018 01:17:44 +0100 Subject: [PATCH 09/14] MDEV-17898 FLUSH PRIVILEGES crashes server with segfault merge_role_db_privileges() was remembering pointers into Dynamic_array acl_dbs, and later was using them, while pushing more elements into the array. But pushing can cause realloc, and it can invalidate all pointers. Fix: remember and use indexes of elements, not pointers. --- .../suite/roles/flush_roles-17898.result | 13 +++++++ mysql-test/suite/roles/flush_roles-17898.test | 11 ++++++ sql/sql_acl.cc | 38 +++++++++---------- 3 files changed, 43 insertions(+), 19 deletions(-) create mode 100644 mysql-test/suite/roles/flush_roles-17898.result create mode 100644 mysql-test/suite/roles/flush_roles-17898.test diff --git a/mysql-test/suite/roles/flush_roles-17898.result b/mysql-test/suite/roles/flush_roles-17898.result new file mode 100644 index 00000000000..c09fa166dc0 --- /dev/null +++ b/mysql-test/suite/roles/flush_roles-17898.result @@ -0,0 +1,13 @@ +use mysql; +insert db (db,user,select_priv) values ('foo','dwr_foo','Y'), ('bar','dwr_bar','Y'); +insert roles_mapping (user,role) values ('dwr_qux_dev','dwr_foo'),('dwr_qux_dev','dwr_bar'); +insert user (user,show_db_priv,is_role) values ('dwr_foo','N','Y'), ('dwr_bar','N','Y'), ('dwr_qux_dev','Y','Y'); +Warnings: +Warning 1364 Field 'ssl_cipher' doesn't have a default value +Warning 1364 Field 'x509_issuer' doesn't have a default value +Warning 1364 Field 'x509_subject' doesn't have a default value +Warning 1364 Field 'authentication_string' doesn't have a default value +flush privileges; +drop role dwr_foo; +drop role dwr_bar; +drop role dwr_qux_dev; diff --git a/mysql-test/suite/roles/flush_roles-17898.test b/mysql-test/suite/roles/flush_roles-17898.test new file mode 100644 index 00000000000..e94efc44dd0 --- /dev/null +++ b/mysql-test/suite/roles/flush_roles-17898.test @@ -0,0 +1,11 @@ +# +# MDEV-17898 FLUSH PRIVILEGES crashes server with segfault +# +use mysql; +insert db (db,user,select_priv) values ('foo','dwr_foo','Y'), ('bar','dwr_bar','Y'); +insert roles_mapping (user,role) values ('dwr_qux_dev','dwr_foo'),('dwr_qux_dev','dwr_bar'); +insert user (user,show_db_priv,is_role) values ('dwr_foo','N','Y'), ('dwr_bar','N','Y'), ('dwr_qux_dev','Y','Y'); +flush privileges; +drop role dwr_foo; +drop role dwr_bar; +drop role dwr_qux_dev; diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index d78d45c32af..fa4d5b27751 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -4888,9 +4888,9 @@ static bool merge_role_global_privileges(ACL_ROLE *grantee) return old != grantee->access; } -static int db_name_sort(ACL_DB * const *db1, ACL_DB * const *db2) +static int db_name_sort(const int *db1, const int *db2) { - return strcmp((*db1)->db, (*db2)->db); + return strcmp(acl_dbs.at(*db1).db, acl_dbs.at(*db2).db); } /** @@ -4906,14 +4906,14 @@ static int db_name_sort(ACL_DB * const *db1, ACL_DB * const *db2) 2 - ACL_DB was added 4 - ACL_DB was deleted */ -static int update_role_db(ACL_DB *merged, ACL_DB **first, ulong access, char *role) +static int update_role_db(int merged, int first, ulong access, char *role) { - if (!first) + if (first < 0) return 0; DBUG_EXECUTE_IF("role_merge_stats", role_db_merges++;); - if (merged == NULL) + if (merged < 0) { /* there's no ACL_DB for this role (all db grants come from granted roles) @@ -4928,7 +4928,7 @@ static int update_role_db(ACL_DB *merged, ACL_DB **first, ulong access, char *ro acl_db.user= role; acl_db.host.hostname= const_cast(""); acl_db.host.ip= acl_db.host.ip_mask= 0; - acl_db.db= first[0]->db; + acl_db.db= acl_dbs.at(first).db; acl_db.access= access; acl_db.initial_access= 0; acl_db.sort=get_sort(3, "", acl_db.db, role); @@ -4948,13 +4948,13 @@ static int update_role_db(ACL_DB *merged, ACL_DB **first, ulong access, char *ro 2. it's O(N) operation, and we may need many of them so we only mark elements deleted and will delete later. */ - merged->sort= 0; // lower than any valid ACL_DB sort value, will be sorted last + acl_dbs.at(merged).sort= 0; // lower than any valid ACL_DB sort value, will be sorted last return 4; } - else if (merged->access != access) + else if (acl_dbs.at(merged).access != access) { /* this is easy */ - merged->access= access; + acl_dbs.at(merged).access= access; return 1; } return 0; @@ -4969,7 +4969,7 @@ static int update_role_db(ACL_DB *merged, ACL_DB **first, ulong access, char *ro static bool merge_role_db_privileges(ACL_ROLE *grantee, const char *dbname, role_hash_t *rhash) { - Dynamic_array dbs; + Dynamic_array dbs; /* Supposedly acl_dbs can be huge, but only a handful of db grants @@ -4987,7 +4987,7 @@ static bool merge_role_db_privileges(ACL_ROLE *grantee, const char *dbname, ACL_ROLE *r= rhash->find(db->user, strlen(db->user)); if (!r) continue; - dbs.append(db); + dbs.append(i); } dbs.sort(db_name_sort); @@ -4996,21 +4996,21 @@ static bool merge_role_db_privileges(ACL_ROLE *grantee, const char *dbname, (that should be merged) are sorted together. The grantee's ACL_DB element is not necessarily the first and may be not present at all. */ - ACL_DB **first= NULL, *UNINIT_VAR(merged); + int first= -1, merged= -1; ulong UNINIT_VAR(access), update_flags= 0; - for (ACL_DB **cur= dbs.front(); cur <= dbs.back(); cur++) + for (int *p= dbs.front(); p <= dbs.back(); p++) { - if (!first || (!dbname && strcmp(cur[0]->db, cur[-1]->db))) + if (first<0 || (!dbname && strcmp(acl_dbs.at(*p).db, acl_dbs.at(*p-1).db))) { // new db name series update_flags|= update_role_db(merged, first, access, grantee->user.str); - merged= NULL; + merged= -1; access= 0; - first= cur; + first= *p; } - if (strcmp(cur[0]->user, grantee->user.str) == 0) - access|= (merged= cur[0])->initial_access; + if (strcmp(acl_dbs.at(*p).user, grantee->user.str) == 0) + access|= acl_dbs.at(merged= *p).initial_access; else - access|= cur[0]->access; + access|= acl_dbs.at(*p).access; } update_flags|= update_role_db(merged, first, access, grantee->user.str); From 2a2e8ea8fe9a3421e04e0a03f712083f6ddec63c Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Thu, 6 Dec 2018 19:26:00 +0100 Subject: [PATCH 10/14] MDEV-17917 MTR: fixed race conditions in perfschema.socket_connect, main.connect --- mysql-test/suite/perfschema/r/socket_connect.result | 13 ------------- mysql-test/suite/perfschema/t/socket_connect.test | 9 ++++++--- mysql-test/t/connect.test | 7 ++----- 3 files changed, 8 insertions(+), 21 deletions(-) diff --git a/mysql-test/suite/perfschema/r/socket_connect.result b/mysql-test/suite/perfschema/r/socket_connect.result index 10540fd3071..4b77b3e0a82 100644 --- a/mysql-test/suite/perfschema/r/socket_connect.result +++ b/mysql-test/suite/perfschema/r/socket_connect.result @@ -159,19 +159,6 @@ Expect 1 # 6.1 Verify that there are no TCP/IP connections in the socket instance table -SELECT COUNT(*) = 0 AS 'Expect 1' -FROM performance_schema.socket_instances -WHERE EVENT_NAME LIKE '%client_connection%' - AND OBJECT_INSTANCE_BEGIN <> @default_object_instance_begin -AND (IP LIKE '%127.0.0.1' OR IP LIKE '%::1'); -Expect 1 -1 # 6.2 Verify that there are no TCP/IP connections in the summary instance table -SELECT COUNT(*) = 0 AS 'Expect 1' -FROM performance_schema.socket_summary_by_instance -WHERE EVENT_NAME LIKE '%client_connection%' - AND OBJECT_INSTANCE_BEGIN <> @default_object_instance_begin; -Expect 1 -1 diff --git a/mysql-test/suite/perfschema/t/socket_connect.test b/mysql-test/suite/perfschema/t/socket_connect.test index 909840144ef..b4579605eb5 100644 --- a/mysql-test/suite/perfschema/t/socket_connect.test +++ b/mysql-test/suite/perfschema/t/socket_connect.test @@ -273,18 +273,21 @@ WHERE EVENT_NAME LIKE '%client_connection%' --echo --echo # 6.1 Verify that there are no TCP/IP connections in the socket instance table --echo -eval SELECT COUNT(*) = 0 AS 'Expect 1' +let $wait_condition= +SELECT COUNT(*) = 0 AS 'Expect 1' FROM performance_schema.socket_instances WHERE EVENT_NAME LIKE '%client_connection%' AND OBJECT_INSTANCE_BEGIN <> @default_object_instance_begin AND $ip_localhost; +--source include/wait_condition.inc --echo --echo # 6.2 Verify that there are no TCP/IP connections in the summary instance table --echo -eval SELECT COUNT(*) = 0 AS 'Expect 1' +let $wait_condition= +SELECT COUNT(*) = 0 AS 'Expect 1' FROM performance_schema.socket_summary_by_instance WHERE EVENT_NAME LIKE '%client_connection%' AND OBJECT_INSTANCE_BEGIN <> @default_object_instance_begin; - +--source include/wait_condition.inc exit; diff --git a/mysql-test/t/connect.test b/mysql-test/t/connect.test index c2d44c08e22..3a38ad88462 100644 --- a/mysql-test/t/connect.test +++ b/mysql-test/t/connect.test @@ -253,11 +253,8 @@ let $wait_condition = --echo --echo # -- Waiting for connections to close... -let $wait_condition = - SELECT COUNT(*) = 1 - FROM information_schema.processlist - WHERE db = 'test'; ---source include/wait_condition.inc +let $count_sessions=1; +--source include/wait_until_count_sessions.inc --echo DROP USER mysqltest_u1@localhost; From 49a50a19a1b71ad24dcc36ca9b5d83e73706d235 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 7 Dec 2018 11:54:03 +0200 Subject: [PATCH 11/14] MDEV-17923 Assertion failed in trx_undo_page_report_modify after CREATE FULLTEXT INDEX row_fts_merge_insert(): Correctly initialize DB_ROLL_PTR to a safe value that will not be dereferenced by MVCC. --- mysql-test/suite/innodb_fts/r/create.result | 16 ++++++++++++++++ mysql-test/suite/innodb_fts/t/create.test | 16 ++++++++++++++++ storage/innobase/row/row0ftsort.cc | 20 +++++++++----------- 3 files changed, 41 insertions(+), 11 deletions(-) diff --git a/mysql-test/suite/innodb_fts/r/create.result b/mysql-test/suite/innodb_fts/r/create.result index 615f0368599..4e21c080bbb 100644 --- a/mysql-test/suite/innodb_fts/r/create.result +++ b/mysql-test/suite/innodb_fts/r/create.result @@ -166,3 +166,19 @@ SELECT len,COUNT(*) FROM INFORMATION_SCHEMA.INNODB_SYS_COLUMNS where name='word' len COUNT(*) 84 6 DROP TABLE t; +# +# MDEV-17923 Assertion memcmp(field, field_ref_zero, 7) failed in +# trx_undo_page_report_modify upon optimizing table +# under innodb_optimize_fulltext_only +# +CREATE TABLE t1 (f1 TEXT, f2 TEXT, FULLTEXT KEY (f2)) ENGINE=InnoDB; +INSERT INTO t1 (f1) VALUES ('foo'),('bar'); +DELETE FROM t1 LIMIT 1; +ALTER TABLE t1 ADD FULLTEXT KEY (f1); +SET @optimize_fulltext.save= @@innodb_optimize_fulltext_only; +SET GLOBAL innodb_optimize_fulltext_only= 1; +OPTIMIZE TABLE t1; +Table Op Msg_type Msg_text +test.t1 optimize status OK +DROP TABLE t1; +SET GLOBAL innodb_optimize_fulltext_only= @optimize_fulltext.save; diff --git a/mysql-test/suite/innodb_fts/t/create.test b/mysql-test/suite/innodb_fts/t/create.test index fe0273af750..4e522994fcc 100644 --- a/mysql-test/suite/innodb_fts/t/create.test +++ b/mysql-test/suite/innodb_fts/t/create.test @@ -90,3 +90,19 @@ ENGINE=InnoDB; # The column length should be 84 bytes (84 characters * 1 byte/character). SELECT len,COUNT(*) FROM INFORMATION_SCHEMA.INNODB_SYS_COLUMNS where name='word' GROUP BY len; DROP TABLE t; + +--echo # +--echo # MDEV-17923 Assertion memcmp(field, field_ref_zero, 7) failed in +--echo # trx_undo_page_report_modify upon optimizing table +--echo # under innodb_optimize_fulltext_only +--echo # + +CREATE TABLE t1 (f1 TEXT, f2 TEXT, FULLTEXT KEY (f2)) ENGINE=InnoDB; +INSERT INTO t1 (f1) VALUES ('foo'),('bar'); +DELETE FROM t1 LIMIT 1; +ALTER TABLE t1 ADD FULLTEXT KEY (f1); +SET @optimize_fulltext.save= @@innodb_optimize_fulltext_only; +SET GLOBAL innodb_optimize_fulltext_only= 1; +OPTIMIZE TABLE t1; +DROP TABLE t1; +SET GLOBAL innodb_optimize_fulltext_only= @optimize_fulltext.save; diff --git a/storage/innobase/row/row0ftsort.cc b/storage/innobase/row/row0ftsort.cc index 810b5387aec..d5eee7e0727 100644 --- a/storage/innobase/row/row0ftsort.cc +++ b/storage/innobase/row/row0ftsort.cc @@ -1581,9 +1581,7 @@ row_fts_merge_insert( dict_table_t* aux_table; dict_index_t* aux_index; trx_t* trx; - byte trx_id_buf[6]; - roll_ptr_t roll_ptr = 0; - dfield_t* field; + byte sys_buf[DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN]; ut_ad(index); ut_ad(table); @@ -1689,16 +1687,16 @@ row_fts_merge_insert( dict_index_get_n_fields(aux_index)); /* Set TRX_ID and ROLL_PTR */ - trx_write_trx_id(trx_id_buf, trx->id); - field = dtuple_get_nth_field(ins_ctx.tuple, 2); - dfield_set_data(field, &trx_id_buf, 6); + trx_write_trx_id(sys_buf, trx->id); + trx_write_roll_ptr(sys_buf + DATA_TRX_ID_LEN, + 1ULL << ROLL_PTR_INSERT_FLAG_POS); + dfield_set_data(dtuple_get_nth_field(ins_ctx.tuple, 2), + &sys_buf, DATA_TRX_ID_LEN); + dfield_set_data(dtuple_get_nth_field(ins_ctx.tuple, 3), + &sys_buf + DATA_TRX_ID_LEN, DATA_ROLL_PTR_LEN); - field = dtuple_get_nth_field(ins_ctx.tuple, 3); - dfield_set_data(field, &roll_ptr, 7); + ut_d(ins_ctx.aux_index_id = id); -#ifdef UNIV_DEBUG - ins_ctx.aux_index_id = id; -#endif const ulint space = table->space; for (i = 0; i < fts_sort_pll_degree; i++) { From 12b1ba195cb0802053bc2fae3b507ec9721685f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 7 Dec 2018 12:54:02 +0200 Subject: [PATCH 12/14] MDEV-17904 Crash in fts_is_sync_needed() after failed ALTER or CREATE TABLE create_table_def(), ha_innobase::create(): Defer fts_optimize_add_table() until after the table has been successfully created. --- storage/innobase/handler/ha_innodb.cc | 8 ++++---- storage/xtradb/handler/ha_innodb.cc | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 85c5529a096..b1e37ea0fa4 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -9371,10 +9371,6 @@ err_col: : ER_TABLESPACE_EXISTS, MYF(0), display_name); } - if (err == DB_SUCCESS && (flags2 & DICT_TF2_FTS)) { - fts_optimize_add_table(table); - } - error_ret: DBUG_RETURN(convert_error_code_to_mysql(err, flags, thd)); } @@ -10441,6 +10437,10 @@ ha_innobase::create( trx_free_for_mysql(trx); DBUG_RETURN(-1); } + + mutex_enter(&dict_sys->mutex); + fts_optimize_add_table(innobase_table); + mutex_exit(&dict_sys->mutex); } /* Note: We can't call update_thd() as prebuilt will not be diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index 52ef0b01534..5eadc42f56e 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -10143,10 +10143,6 @@ err_col: : ER_TABLESPACE_EXISTS, MYF(0), display_name); } - if (err == DB_SUCCESS && (flags2 & DICT_TF2_FTS)) { - fts_optimize_add_table(table); - } - error_ret: DBUG_RETURN(convert_error_code_to_mysql(err, flags, thd)); } @@ -11218,6 +11214,10 @@ ha_innobase::create( trx_free_for_mysql(trx); DBUG_RETURN(-1); } + + mutex_enter(&dict_sys->mutex); + fts_optimize_add_table(innobase_table); + mutex_exit(&dict_sys->mutex); } /* Note: We can't call update_thd() as prebuilt will not be From 52778e2e3e69b8e0d1397ca34694e192c8e0f88c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 7 Dec 2018 15:13:39 +0200 Subject: [PATCH 13/14] After-merge fix --- mysql-test/suite/roles/flush_roles-17898.result | 2 +- mysql-test/suite/roles/flush_roles-17898.test | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/roles/flush_roles-17898.result b/mysql-test/suite/roles/flush_roles-17898.result index c09fa166dc0..dbe6ea24afd 100644 --- a/mysql-test/suite/roles/flush_roles-17898.result +++ b/mysql-test/suite/roles/flush_roles-17898.result @@ -1,7 +1,7 @@ use mysql; insert db (db,user,select_priv) values ('foo','dwr_foo','Y'), ('bar','dwr_bar','Y'); insert roles_mapping (user,role) values ('dwr_qux_dev','dwr_foo'),('dwr_qux_dev','dwr_bar'); -insert user (user,show_db_priv,is_role) values ('dwr_foo','N','Y'), ('dwr_bar','N','Y'), ('dwr_qux_dev','Y','Y'); +insert ignore user (user,show_db_priv,is_role) values ('dwr_foo','N','Y'), ('dwr_bar','N','Y'), ('dwr_qux_dev','Y','Y'); Warnings: Warning 1364 Field 'ssl_cipher' doesn't have a default value Warning 1364 Field 'x509_issuer' doesn't have a default value diff --git a/mysql-test/suite/roles/flush_roles-17898.test b/mysql-test/suite/roles/flush_roles-17898.test index e94efc44dd0..6a3b8d6f345 100644 --- a/mysql-test/suite/roles/flush_roles-17898.test +++ b/mysql-test/suite/roles/flush_roles-17898.test @@ -4,7 +4,7 @@ use mysql; insert db (db,user,select_priv) values ('foo','dwr_foo','Y'), ('bar','dwr_bar','Y'); insert roles_mapping (user,role) values ('dwr_qux_dev','dwr_foo'),('dwr_qux_dev','dwr_bar'); -insert user (user,show_db_priv,is_role) values ('dwr_foo','N','Y'), ('dwr_bar','N','Y'), ('dwr_qux_dev','Y','Y'); +insert ignore user (user,show_db_priv,is_role) values ('dwr_foo','N','Y'), ('dwr_bar','N','Y'), ('dwr_qux_dev','Y','Y'); flush privileges; drop role dwr_foo; drop role dwr_bar; From 53440e2dda8b3f2763914708e074c8e4ada9ec74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 7 Dec 2018 15:31:43 +0200 Subject: [PATCH 14/14] MDEV-17923: Fix the pointer arithmetics &sys_buf + DATA_TRX_ID_LEN is not &(sys_buf + DATA_TRX_ID_LEN). --- storage/innobase/row/row0ftsort.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/storage/innobase/row/row0ftsort.cc b/storage/innobase/row/row0ftsort.cc index d5eee7e0727..e87bd1c0261 100644 --- a/storage/innobase/row/row0ftsort.cc +++ b/storage/innobase/row/row0ftsort.cc @@ -1688,12 +1688,12 @@ row_fts_merge_insert( /* Set TRX_ID and ROLL_PTR */ trx_write_trx_id(sys_buf, trx->id); - trx_write_roll_ptr(sys_buf + DATA_TRX_ID_LEN, + trx_write_roll_ptr(&sys_buf[DATA_TRX_ID_LEN], 1ULL << ROLL_PTR_INSERT_FLAG_POS); dfield_set_data(dtuple_get_nth_field(ins_ctx.tuple, 2), - &sys_buf, DATA_TRX_ID_LEN); + sys_buf, DATA_TRX_ID_LEN); dfield_set_data(dtuple_get_nth_field(ins_ctx.tuple, 3), - &sys_buf + DATA_TRX_ID_LEN, DATA_ROLL_PTR_LEN); + &sys_buf[DATA_TRX_ID_LEN], DATA_ROLL_PTR_LEN); ut_d(ins_ctx.aux_index_id = id);