From 0bd2b802546c09361fe7823624e09bde16c976ac Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Mon, 7 May 2018 17:42:55 +0200 Subject: [PATCH 01/25] MDEV-15347: Valgrind or ASAN errors in mysql_make_view on query from information_schema Make each lex pointing to statement lex instead of global pointer in THD (no need store and restore the global pointer and put it on SP stack). --- mysql-test/r/sp.result | 11 +++++++++++ mysql-test/t/sp.test | 15 +++++++++++++++ sql/sp_head.cc | 10 ++++------ sql/sql_class.cc | 2 +- sql/sql_class.h | 15 --------------- sql/sql_lex.cc | 5 +++-- sql/sql_lex.h | 17 ++++++++++++++++- sql/sql_parse.cc | 7 ++++--- sql/sql_prepare.cc | 2 +- sql/sql_trigger.cc | 6 ++---- sql/sql_view.cc | 4 +++- 11 files changed, 60 insertions(+), 34 deletions(-) diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index ad5bddda035..bc33c08d9d8 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -8242,4 +8242,15 @@ DROP PROCEDURE proc_13; DROP PROCEDURE proc_select; DROP TABLE t1, t2; SET max_sp_recursion_depth=default; +# +# MDEV-15347: Valgrind or ASAN errors in mysql_make_view on query +# from information_schema +# +CREATE VIEW v AS SELECT 1; +CREATE FUNCTION f() RETURNS INT RETURN 1; +SELECT * FROM INFORMATION_SCHEMA.TABLES JOIN INFORMATION_SCHEMA.PARAMETERS +UNION +SELECT * FROM INFORMATION_SCHEMA.TABLES JOIN INFORMATION_SCHEMA.PARAMETERS; +DROP FUNCTION f; +DROP VIEW v; #End of 10.1 tests diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index eeabb0486ca..467d3b5a7d4 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -9754,4 +9754,19 @@ DROP TABLE t1, t2; SET max_sp_recursion_depth=default; +--echo # +--echo # MDEV-15347: Valgrind or ASAN errors in mysql_make_view on query +--echo # from information_schema +--echo # + +CREATE VIEW v AS SELECT 1; +CREATE FUNCTION f() RETURNS INT RETURN 1; +--disable_result_log +SELECT * FROM INFORMATION_SCHEMA.TABLES JOIN INFORMATION_SCHEMA.PARAMETERS +UNION +SELECT * FROM INFORMATION_SCHEMA.TABLES JOIN INFORMATION_SCHEMA.PARAMETERS; +--enable_result_log +DROP FUNCTION f; +DROP VIEW v; + --echo #End of 10.1 tests diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 8bf78d97670..0d24ed04eae 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -840,7 +840,7 @@ sp_head::~sp_head() thd->lex->sphead= NULL; lex_end(thd->lex); delete thd->lex; - thd->lex= thd->stmt_lex= lex; + thd->lex= lex; } my_hash_free(&m_sptabs); @@ -1121,7 +1121,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success) backup_arena; query_id_t old_query_id; TABLE *old_derived_tables; - LEX *old_lex, *old_stmt_lex; + LEX *old_lex; Item_change_list old_change_list; String old_packet; uint old_server_status; @@ -1224,7 +1224,6 @@ sp_head::execute(THD *thd, bool merge_da_on_success) do it in each instruction */ old_lex= thd->lex; - old_stmt_lex= thd->stmt_lex; /* We should also save Item tree change list to avoid rollback something too early in the calling query. @@ -1372,7 +1371,6 @@ sp_head::execute(THD *thd, bool merge_da_on_success) DBUG_ASSERT(thd->change_list.is_empty()); old_change_list.move_elements_to(&thd->change_list); thd->lex= old_lex; - thd->stmt_lex= old_stmt_lex; thd->set_query_id(old_query_id); DBUG_ASSERT(!thd->derived_tables); thd->derived_tables= old_derived_tables; @@ -2207,7 +2205,7 @@ sp_head::reset_lex(THD *thd) if (sublex == 0) DBUG_RETURN(TRUE); - thd->lex= thd->stmt_lex= sublex; + thd->lex= sublex; (void)m_lex.push_front(oldlex); /* Reset most stuff. */ @@ -2953,7 +2951,7 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp, We should not save old value since it is saved/restored in sp_head::execute() when we are entering/leaving routine. */ - thd->lex= thd->stmt_lex= m_lex; + thd->lex= m_lex; thd->set_query_id(next_query_id()); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 2ab1cd3a61a..24140246b96 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -3654,7 +3654,7 @@ void Statement::set_statement(Statement *stmt) { id= stmt->id; mark_used_columns= stmt->mark_used_columns; - stmt_lex= lex= stmt->lex; + lex= stmt->lex; query_string= stmt->query_string; } diff --git a/sql/sql_class.h b/sql/sql_class.h index 341f2e571d8..ca6155ec93f 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1027,21 +1027,6 @@ public: LEX_STRING name; /* name for named prepared statements */ LEX *lex; // parse tree descriptor - /* - LEX which represents current statement (conventional, SP or PS) - - For example during view parsing THD::lex will point to the views LEX and - THD::stmt_lex will point to LEX of the statement where the view will be - included - - Currently it is used to have always correct select numbering inside - statement (LEX::current_select_number) without storing and restoring a - global counter which was THD::select_number. - - TODO: make some unified statement representation (now SP has different) - to store such data like LEX::current_select_number. - */ - LEX *stmt_lex; /* Points to the query associated with this statement. It's const, but we need to declare it char * because all table handlers are written diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 3fa5ec71aeb..085ad1a4b3b 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -657,10 +657,11 @@ void lex_start(THD *thd) { LEX *lex= thd->lex; DBUG_ENTER("lex_start"); - DBUG_PRINT("info", ("Lex %p stmt_lex: %p", thd->lex, thd->stmt_lex)); + DBUG_PRINT("info", ("Lex %p", thd->lex)); lex->thd= lex->unit.thd= thd; - + + lex->stmt_lex= lex; // default, should be rewritten for VIEWs And CTEs DBUG_ASSERT(!lex->explain); lex->context_stack.empty(); diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 4fcd090e1f5..3b47b1d25c9 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -730,7 +730,7 @@ public: /* Point to the LEX in which it was created, used in view subquery detection. - TODO: make also st_select_lex::parent_stmt_lex (see THD::stmt_lex) + TODO: make also st_select_lex::parent_stmt_lex (see LEX::stmt_lex) and use st_select_lex::parent_lex & st_select_lex::parent_stmt_lex instead of global (from THD) references where it is possible. */ @@ -2435,6 +2435,21 @@ struct LEX: public Query_tables_list // type information char *length,*dec; CHARSET_INFO *charset; + /* + LEX which represents current statement (conventional, SP or PS) + + For example during view parsing THD::lex will point to the views LEX and + lex::stmt_lex will point to LEX of the statement where the view will be + included + + Currently it is used to have always correct select numbering inside + statement (LEX::current_select_number) without storing and restoring a + global counter which was THD::select_number. + + TODO: make some unified statement representation (now SP has different) + to store such data like LEX::current_select_number. + */ + LEX *stmt_lex; LEX_STRING name; char *help_arg; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index f83e51409ab..e082155ce1e 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -6927,8 +6927,9 @@ void THD::reset_for_next_command(bool do_clear_error) We also assign thd->stmt_lex in lex_start(), but during bootstrap this code is executed first. */ - thd->stmt_lex= &main_lex; thd->stmt_lex->current_select_number= 1; - DBUG_PRINT("info", ("Lex %p stmt_lex: %p", thd->lex, thd->stmt_lex)); + DBUG_ASSERT(lex == &main_lex); + main_lex.stmt_lex= &main_lex; main_lex.current_select_number= 1; + DBUG_PRINT("info", ("Lex and stmt_lex: %p", &main_lex)); /* Those two lines below are theoretically unneeded as THD::cleanup_after_query() should take care of this already. @@ -7046,7 +7047,7 @@ mysql_new_select(LEX *lex, bool move_down) if (!(select_lex= new (thd->mem_root) SELECT_LEX())) DBUG_RETURN(1); - select_lex->select_number= ++thd->stmt_lex->current_select_number; + select_lex->select_number= ++thd->lex->stmt_lex->current_select_number; select_lex->parent_lex= lex; /* Used in init_query. */ select_lex->init_query(); select_lex->init_select(); diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 6e14ddc2afb..d39ed6aa637 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -3635,7 +3635,7 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) if (! (lex= new (mem_root) st_lex_local)) DBUG_RETURN(TRUE); - stmt_lex= lex; + lex->stmt_lex= lex; if (set_db(thd->db, thd->db_length)) DBUG_RETURN(TRUE); diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index e14d19c7369..293a4c17156 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -1374,13 +1374,13 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, List_iterator_fast it_client_cs_name(triggers->client_cs_names); List_iterator_fast it_connection_cl_name(triggers->connection_cl_names); List_iterator_fast it_db_cl_name(triggers->db_cl_names); - LEX *old_lex= thd->lex, *old_stmt_lex= thd->stmt_lex; + LEX *old_lex= thd->lex; LEX lex; sp_rcontext *save_spcont= thd->spcont; ulonglong save_sql_mode= thd->variables.sql_mode; LEX_STRING *on_table_name; - thd->lex= thd->stmt_lex= &lex; + thd->lex= &lex; save_db.str= thd->db; save_db.length= thd->db_length; @@ -1579,7 +1579,6 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, } thd->reset_db(save_db.str, save_db.length); thd->lex= old_lex; - thd->stmt_lex= old_stmt_lex; thd->spcont= save_spcont; thd->variables.sql_mode= save_sql_mode; @@ -1592,7 +1591,6 @@ err_with_lex_cleanup: // QQ: anything else ? lex_end(&lex); thd->lex= old_lex; - thd->stmt_lex= old_stmt_lex; thd->spcont= save_spcont; thd->variables.sql_mode= save_sql_mode; thd->reset_db(save_db.str, save_db.length); diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 1bdc76a66ea..6d7a8e1cc9d 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -1315,6 +1315,7 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table, now Lex placed in statement memory */ + table->view= lex= thd->lex= (LEX*) new(thd->mem_root) st_lex_local; if (!table->view) { @@ -1340,8 +1341,9 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table, goto end; lex_start(thd); + lex->stmt_lex= old_lex; view_select= &lex->select_lex; - view_select->select_number= ++thd->stmt_lex->current_select_number; + view_select->select_number= ++thd->lex->stmt_lex->current_select_number; ulonglong saved_mode= thd->variables.sql_mode; /* switch off modes which can prevent normal parsing of VIEW From 2b749a7bf4f6a6d70f05e8e4b42d088b397adea8 Mon Sep 17 00:00:00 2001 From: Monty Date: Tue, 15 May 2018 11:46:55 +0300 Subject: [PATCH 02/25] MDEV-654 Assertion `share->now_transactional' failed in flush_log_for_bitmap on concurrent workload with Aria tables Problem was that we the bitmap needs to be flushed before disabling logging of redo entires, as writing the bitmap to disk by background checkpoint may cause redo entries. --- storage/maria/ha_maria.cc | 1 + storage/maria/ma_recovery.c | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/storage/maria/ha_maria.cc b/storage/maria/ha_maria.cc index 0c41037f33e..ca2d050ddfe 100644 --- a/storage/maria/ha_maria.cc +++ b/storage/maria/ha_maria.cc @@ -1312,6 +1312,7 @@ int ha_maria::check(THD * thd, HA_CHECK_OPT * check_opt) old_proc_info= thd_proc_info(thd, "Checking status"); thd_progress_init(thd, 3); error= maria_chk_status(param, file); // Not fatal + /* maria_chk_size() will flush the page cache for this file */ if (maria_chk_size(param, file)) error= 1; if (!error) diff --git a/storage/maria/ma_recovery.c b/storage/maria/ma_recovery.c index 75a8f4f4559..af0d9476f2a 100644 --- a/storage/maria/ma_recovery.c +++ b/storage/maria/ma_recovery.c @@ -3521,6 +3521,14 @@ void _ma_tmp_disable_logging_for_table(MARIA_HA *info, { MARIA_SHARE *share= info->s; DBUG_ENTER("_ma_tmp_disable_logging_for_table"); + + /* + We have to ensure that bitmap is flushed, as it's checking + that share->now_transactional is set + */ + if (share->now_transactional && share->data_file_type == BLOCK_RECORD) + _ma_bitmap_flush_all(share); + if (log_incomplete) { uchar log_data[FILEID_STORE_SIZE]; From b050df4fd3ee5f2377a814fd24ac3774d1458f99 Mon Sep 17 00:00:00 2001 From: Monty Date: Tue, 15 May 2018 12:30:32 +0300 Subject: [PATCH 03/25] MDEV-14943 Alter table ORDER BY bug Problem was that if copy_data_between_tables() didn't do proper clean up in case of failures: - copy object was not properly freed - end_bulk_insert() was not called - mysql_trans_prepare_alter_copy_data() set THD->transaction.on to false which was not properly restored The last part caused a crash in Aria as Aria depends on that THD is correct. Other things: - Reset info->switched_transactional after usage (safety) - Reset bulk_insert_single_undo (safety) --- mysql-test/suite/maria/alter.result | 16 +++++++++++++++ mysql-test/suite/maria/alter.test | 17 +++++++++++++++ sql/sql_table.cc | 32 +++++++++++++++++++++-------- storage/maria/ha_maria.cc | 1 + storage/maria/ma_recovery.c | 3 +++ 5 files changed, 61 insertions(+), 8 deletions(-) diff --git a/mysql-test/suite/maria/alter.result b/mysql-test/suite/maria/alter.result index 1a7daf5a1ee..c63688dddd6 100644 --- a/mysql-test/suite/maria/alter.result +++ b/mysql-test/suite/maria/alter.result @@ -31,3 +31,19 @@ pk i 8 88 9 99 DROP TABLE t1; +CREATE TABLE t1 (f INT) ENGINE=Aria transactional=1; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `f` int(11) DEFAULT NULL +) ENGINE=Aria DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 TRANSACTIONAL=1 +INSERT INTO t1 VALUES (1),(2); +ALTER TABLE t1 ORDER BY unknown_column; +ERROR 42S22: Unknown column 'unknown_column' in 'order clause' +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `f` int(11) DEFAULT NULL +) ENGINE=Aria DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 TRANSACTIONAL=1 +CREATE TABLE t2 SELECT * FROM t1; +DROP TABLE t1, t2; diff --git a/mysql-test/suite/maria/alter.test b/mysql-test/suite/maria/alter.test index abca4865688..09672cdfa3b 100644 --- a/mysql-test/suite/maria/alter.test +++ b/mysql-test/suite/maria/alter.test @@ -25,3 +25,20 @@ INSERT INTO t1 VALUES (2,0),(3,33),(4,0),(5,55),(6,66),(7,0),(8,88),(9,99); ALTER TABLE t1 ENABLE KEYS; SELECT * FROM t1 WHERE i = 0 OR pk BETWEEN 6 AND 10; DROP TABLE t1; + +# +# MDEV-14943 +# Assertion `block->type == PAGECACHE_EMPTY_PAGE || block->type == type || +# type == PAGECACHE_LSN_PAGE || type == PAGECACHE_READ_UNKNOWN_PAGE || +# block->type == PAGECACHE_READ_UNKNOWN_PAGE' failed in pagecache_read upon +# CREATE ... SELECT from Aria table +# + +CREATE TABLE t1 (f INT) ENGINE=Aria transactional=1; +SHOW CREATE TABLE t1; +INSERT INTO t1 VALUES (1),(2); +--error ER_BAD_FIELD_ERROR +ALTER TABLE t1 ORDER BY unknown_column; +SHOW CREATE TABLE t1; +CREATE TABLE t2 SELECT * FROM t1; +DROP TABLE t1, t2; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 8f3468a44db..27d579a6b19 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -9356,9 +9356,7 @@ bool mysql_trans_prepare_alter_copy_data(THD *thd) This needs to be done before external_lock. */ - if (ha_enable_transaction(thd, FALSE)) - DBUG_RETURN(TRUE); - DBUG_RETURN(FALSE); + DBUG_RETURN(ha_enable_transaction(thd, FALSE) != 0); } @@ -9409,6 +9407,7 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, ha_rows examined_rows; ha_rows found_rows; bool auto_increment_field_copied= 0; + bool cleanup_done= 0; ulonglong save_sql_mode= thd->variables.sql_mode; ulonglong prev_insert_id, time_to_report_progress; Field **dfield_ptr= to->default_field; @@ -9417,15 +9416,23 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, /* Two or 3 stages; Sorting, copying data and update indexes */ thd_progress_init(thd, 2 + MY_TEST(order)); - if (mysql_trans_prepare_alter_copy_data(thd)) - DBUG_RETURN(-1); - if (!(copy= new Copy_field[to->s->fields])) DBUG_RETURN(-1); /* purecov: inspected */ + if (mysql_trans_prepare_alter_copy_data(thd)) + { + delete [] copy; + DBUG_RETURN(-1); + } + /* We need external lock before we can disable/enable keys */ if (to->file->ha_external_lock(thd, F_WRLCK)) + { + /* Undo call to mysql_trans_prepare_alter_copy_data() */ + ha_enable_transaction(thd, TRUE); + delete [] copy; DBUG_RETURN(-1); + } alter_table_manage_keys(to, from->file->indexes_are_disabled(), keys_onoff); @@ -9435,7 +9442,6 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, from->file->info(HA_STATUS_VARIABLE); to->file->ha_start_bulk_insert(from->file->stats.records, ignore ? 0 : HA_CREATE_UNIQUE_INDEX_BY_SORT); - List_iterator it(create); Create_field *def; copy_end=copy; @@ -9637,7 +9643,6 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, } end_read_record(&info); free_io_cache(from); - delete [] copy; THD_STAGE_INFO(thd, stage_enabling_keys); thd_progress_next_stage(thd); @@ -9652,6 +9657,7 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, to->file->print_error(my_errno,MYF(0)); error= 1; } + cleanup_done= 1; to->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); if (mysql_trans_commit_alter_copy_data(thd)) @@ -9663,6 +9669,16 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, *copied= found_count; *deleted=delete_count; to->file->ha_release_auto_increment(); + delete [] copy; + + if (!cleanup_done) + { + /* This happens if we get an error during initialzation of data */ + DBUG_ASSERT(error); + to->file->ha_end_bulk_insert(); + ha_enable_transaction(thd, TRUE); + } + if (to->file->ha_external_lock(thd,F_UNLCK)) error=1; if (error < 0 && to->file->extra(HA_EXTRA_PREPARE_FOR_RENAME)) diff --git a/storage/maria/ha_maria.cc b/storage/maria/ha_maria.cc index f52336de9d0..80f278ab2eb 100644 --- a/storage/maria/ha_maria.cc +++ b/storage/maria/ha_maria.cc @@ -2224,6 +2224,7 @@ end: _ma_reenable_logging_for_table(file, bulk_insert_single_undo == BULK_INSERT_SINGLE_UNDO_AND_NO_REPAIR); + bulk_insert_single_undo= BULK_INSERT_NONE; // Safety } DBUG_RETURN(err); } diff --git a/storage/maria/ma_recovery.c b/storage/maria/ma_recovery.c index 4c3310c68c5..b0c38e9f24d 100644 --- a/storage/maria/ma_recovery.c +++ b/storage/maria/ma_recovery.c @@ -3583,7 +3583,10 @@ my_bool _ma_reenable_logging_for_table(MARIA_HA *info, my_bool flush_pages) if (share->now_transactional == share->base.born_transactional || !info->switched_transactional) + { + info->switched_transactional= FALSE; DBUG_RETURN(0); + } info->switched_transactional= FALSE; if ((share->now_transactional= share->base.born_transactional)) From d703e09cd6706673fbb127f540d3917068b40755 Mon Sep 17 00:00:00 2001 From: Monty Date: Thu, 21 Sep 2017 16:30:24 +0300 Subject: [PATCH 04/25] Fix that FLUSH TABLES FOR EXPORT also works for Aria tables. - Added missing test case for MyISAM --- mysql-test/r/myisam.result | 8 ++++++++ mysql-test/suite/maria/maria.result | 8 ++++++++ mysql-test/suite/maria/maria.test | 13 +++++++++++++ mysql-test/t/myisam.test | 13 +++++++++++++ storage/maria/ha_maria.cc | 2 +- 5 files changed, 43 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result index 6b23aefd73b..bedfa413b55 100644 --- a/mysql-test/r/myisam.result +++ b/mysql-test/r/myisam.result @@ -2545,6 +2545,14 @@ OPTIMIZE TABLE t1; Table Op Msg_type Msg_text test.t1 optimize status OK DROP TABLE t1; +CREATE TABLE t1(a INT, b CHAR(10), KEY(a), KEY(b)) engine=myisam; +INSERT INTO t1 VALUES(1,'0'),(2,'0'),(3,'0'),(4,'0'),(5,'0'), +(6,'0'),(7,'0'); +flush tables test.t1 for export; +insert into t1 values (8,'0'); +ERROR HY000: Table 't1' was locked with a READ lock and can't be updated +unlock tables; +drop table t1; show variables like 'myisam_block_size'; Variable_name Value myisam_block_size 1024 diff --git a/mysql-test/suite/maria/maria.result b/mysql-test/suite/maria/maria.result index 8078687dad5..f4d7f3d32c6 100644 --- a/mysql-test/suite/maria/maria.result +++ b/mysql-test/suite/maria/maria.result @@ -2771,3 +2771,11 @@ test.t1 check status OK SET aria_repair_threads=@@global.aria_repair_threads; SET aria_sort_buffer_size=@@global.aria_sort_buffer_size; DROP TABLE t1; +CREATE TABLE t1(a INT, b CHAR(10), KEY(a), KEY(b)); +INSERT INTO t1 VALUES(1,'0'),(2,'0'),(3,'0'),(4,'0'),(5,'0'), +(6,'0'),(7,'0'); +flush tables test.t1 for export; +insert into t1 values (8,'0'); +ERROR HY000: Table 't1' was locked with a READ lock and can't be updated +unlock tables; +drop table t1; diff --git a/mysql-test/suite/maria/maria.test b/mysql-test/suite/maria/maria.test index 27e9a45fda7..17dfb803328 100644 --- a/mysql-test/suite/maria/maria.test +++ b/mysql-test/suite/maria/maria.test @@ -2028,6 +2028,19 @@ SET aria_repair_threads=@@global.aria_repair_threads; SET aria_sort_buffer_size=@@global.aria_sort_buffer_size; DROP TABLE t1; +# +# Check FLUSH FOR EXPORT +# + +CREATE TABLE t1(a INT, b CHAR(10), KEY(a), KEY(b)); +INSERT INTO t1 VALUES(1,'0'),(2,'0'),(3,'0'),(4,'0'),(5,'0'), + (6,'0'),(7,'0'); +flush tables test.t1 for export; +--error ER_TABLE_NOT_LOCKED_FOR_WRITE +insert into t1 values (8,'0'); +unlock tables; +drop table t1; + # # End of test # diff --git a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test index 62260ba43aa..796083c0622 100644 --- a/mysql-test/t/myisam.test +++ b/mysql-test/t/myisam.test @@ -1762,6 +1762,19 @@ ALTER TABLE t1 DISABLE KEYS; OPTIMIZE TABLE t1; DROP TABLE t1; +# +# Check FLUSH FOR EXPORT +# + +CREATE TABLE t1(a INT, b CHAR(10), KEY(a), KEY(b)) engine=myisam; +INSERT INTO t1 VALUES(1,'0'),(2,'0'),(3,'0'),(4,'0'),(5,'0'), + (6,'0'),(7,'0'); +flush tables test.t1 for export; +--error ER_TABLE_NOT_LOCKED_FOR_WRITE +insert into t1 values (8,'0'); +unlock tables; +drop table t1; + # # Check some variables # diff --git a/storage/maria/ha_maria.cc b/storage/maria/ha_maria.cc index 80f278ab2eb..748300e48b8 100644 --- a/storage/maria/ha_maria.cc +++ b/storage/maria/ha_maria.cc @@ -980,7 +980,7 @@ int_table_flags(HA_NULL_IN_KEY | HA_CAN_FULLTEXT | HA_CAN_SQL_HANDLER | HA_DUPLICATE_POS | HA_CAN_INDEX_BLOBS | HA_AUTO_PART_KEY | HA_FILE_BASED | HA_CAN_GEOMETRY | CANNOT_ROLLBACK_FLAG | HA_CAN_BIT_FIELD | HA_CAN_RTREEKEYS | HA_CAN_REPAIR | - HA_CAN_VIRTUAL_COLUMNS | + HA_CAN_VIRTUAL_COLUMNS | HA_CAN_EXPORT | HA_HAS_RECORDS | HA_STATS_RECORDS_IS_EXACT), can_enable_indexes(1), bulk_insert_single_undo(BULK_INSERT_NONE) {} From aa2e1ade17e656446c534c02e9cb0adab50b46e1 Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Wed, 16 May 2018 21:01:26 +0400 Subject: [PATCH 05/25] (almost) sane core handling in mtr Analyze core independently of max-save-datadir and max-save-core setting. Increment $num_saved_cores only if core was actually saved. "Move any core files from e.g. mysqltest" independently of max-save-datadir setting. Note: it may overwrite core from mysqld, which might not be desired (it did work this way even before). --- mysql-test/mysql-test-run.pl | 81 ++++++++++++++++++++---------------- 1 file changed, 45 insertions(+), 36 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 0f915a8777a..de1871cbf03 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -637,50 +637,59 @@ sub run_test_server ($$$) { my $worker_savename= basename($worker_savedir); my $savedir= "$opt_vardir/log/$worker_savename"; + # Move any core files from e.g. mysqltest + foreach my $coref (glob("core*"), glob("*.dmp")) + { + mtr_report(" - found '$coref', moving it to '$worker_savedir'"); + move($coref, $worker_savedir); + } + + find( + { + no_chdir => 1, + wanted => sub + { + my $core_file= $File::Find::name; + my $core_name= basename($core_file); + + # Name beginning with core, not ending in .gz + if (($core_name =~ /^core/ and $core_name !~ /\.gz$/) + or (IS_WINDOWS and $core_name =~ /\.dmp$/)) + { + # Ending with .dmp + mtr_report(" - found '$core_name'", + "($num_saved_cores/$opt_max_save_core)"); + + My::CoreDump->show($core_file, $exe_mysqld, $opt_parallel); + + # Limit number of core files saved + if ($opt_max_save_core > 0 && + $num_saved_cores >= $opt_max_save_core) + { + mtr_report(" - deleting it, already saved", + "$opt_max_save_core"); + unlink("$core_file"); + } + else + { + mtr_compress_file($core_file) unless @opt_cases; + ++$num_saved_cores; + } + } + } + }, + $worker_savedir); + if ($opt_max_save_datadir > 0 && $num_saved_datadir >= $opt_max_save_datadir) { mtr_report(" - skipping '$worker_savedir/'"); rmtree($worker_savedir); } - else { + else + { mtr_report(" - saving '$worker_savedir/' to '$savedir/'"); rename($worker_savedir, $savedir); - # Move any core files from e.g. mysqltest - foreach my $coref (glob("core*"), glob("*.dmp")) - { - mtr_report(" - found '$coref', moving it to '$savedir'"); - move($coref, $savedir); - } - if ($opt_max_save_core > 0) { - # Limit number of core files saved - find({ no_chdir => 1, - wanted => sub { - my $core_file= $File::Find::name; - my $core_name= basename($core_file); - - # Name beginning with core, not ending in .gz - if (($core_name =~ /^core/ and $core_name !~ /\.gz$/) - or (IS_WINDOWS and $core_name =~ /\.dmp$/)){ - # Ending with .dmp - mtr_report(" - found '$core_name'", - "($num_saved_cores/$opt_max_save_core)"); - - My::CoreDump->show($core_file, $exe_mysqld, $opt_parallel); - - if ($num_saved_cores >= $opt_max_save_core) { - mtr_report(" - deleting it, already saved", - "$opt_max_save_core"); - unlink("$core_file"); - } else { - mtr_compress_file($core_file) unless @opt_cases; - } - ++$num_saved_cores; - } - } - }, - $savedir); - } } resfile_print_test(); $num_saved_datadir++; From ef295c31e3d50a99a90beccfb4deb9d9d36ac1e3 Mon Sep 17 00:00:00 2001 From: Monty Date: Wed, 16 May 2018 21:51:46 +0300 Subject: [PATCH 06/25] MDEV-11129 CREATE OR REPLACE TABLE t1 AS SELECT spfunc() crashes if spfunc() references t1 Fixed by extending unique_table() with a flag to not allow usage of the replaced table. I also cleaned up find_dup_table() to not use goto next. I also added more comments to the code in find_dup_table() --- mysql-test/r/create_or_replace.result | 20 ++++++++++++ mysql-test/t/create_or_replace.test | 25 +++++++++++++++ sql/sql_base.cc | 46 ++++++++++++++++----------- sql/sql_base.h | 6 +++- sql/sql_delete.cc | 2 +- sql/sql_insert.cc | 3 +- sql/sql_parse.cc | 2 +- 7 files changed, 82 insertions(+), 22 deletions(-) diff --git a/mysql-test/r/create_or_replace.result b/mysql-test/r/create_or_replace.result index a43dc2eaca4..0d171f9f87a 100644 --- a/mysql-test/r/create_or_replace.result +++ b/mysql-test/r/create_or_replace.result @@ -453,3 +453,23 @@ CREATE OR REPLACE TABLE t1 AS SELECT f1(); UNLOCK TABLES; DROP FUNCTION f1; DROP TABLE t1; +# +# MDEV-11129 +# CREATE OR REPLACE TABLE t1 AS SELECT spfunc() crashes if spfunc() +# references t1 +# +CREATE OR REPLACE TABLE t1(a INT); +CREATE FUNCTION f1() RETURNS VARCHAR(16383) +BEGIN +INSERT INTO t1 VALUES(1); +RETURN 'test'; +END; +$$ +CREATE OR REPLACE TABLE t1 AS SELECT f1(); +ERROR HY000: Table 't1' is specified twice, both as a target for 'CREATE' and as a separate source for data +LOCK TABLE t1 WRITE; +CREATE OR REPLACE TABLE t1 AS SELECT f1(); +ERROR HY000: Table 't1' was not locked with LOCK TABLES +UNLOCK TABLES; +DROP FUNCTION f1; +DROP TABLE t1; diff --git a/mysql-test/t/create_or_replace.test b/mysql-test/t/create_or_replace.test index b37417f39d0..5ebb3031be3 100644 --- a/mysql-test/t/create_or_replace.test +++ b/mysql-test/t/create_or_replace.test @@ -398,3 +398,28 @@ CREATE OR REPLACE TABLE t1 AS SELECT f1(); UNLOCK TABLES; DROP FUNCTION f1; DROP TABLE t1; + +--echo # +--echo # MDEV-11129 +--echo # CREATE OR REPLACE TABLE t1 AS SELECT spfunc() crashes if spfunc() +--echo # references t1 +--echo # + +CREATE OR REPLACE TABLE t1(a INT); +DELIMITER $$; +CREATE FUNCTION f1() RETURNS VARCHAR(16383) +BEGIN + INSERT INTO t1 VALUES(1); + RETURN 'test'; +END; +$$ +DELIMITER ;$$ +--error ER_UPDATE_TABLE_USED +CREATE OR REPLACE TABLE t1 AS SELECT f1(); +LOCK TABLE t1 WRITE; +--error ER_TABLE_NOT_LOCKED +CREATE OR REPLACE TABLE t1 AS SELECT f1(); +UNLOCK TABLES; + +DROP FUNCTION f1; +DROP TABLE t1; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 554c8cffeaf..bdde123f18c 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1278,7 +1278,8 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table, @param thd thread handle @param table table which should be checked @param table_list list of tables - @param check_alias whether to check tables' aliases + @param check_flag whether to check tables' aliases + Currently this is only used by INSERT NOTE: to exclude derived tables from check we use following mechanism: a) during derived table processing set THD::derived_tables_processing @@ -1307,9 +1308,9 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table, static TABLE_LIST* find_dup_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list, - bool check_alias) + uint check_flag) { - TABLE_LIST *res; + TABLE_LIST *res= 0; const char *d_name, *t_name, *t_alias; DBUG_ENTER("find_dup_table"); DBUG_PRINT("enter", ("table alias: %s", table->alias)); @@ -1345,17 +1346,15 @@ TABLE_LIST* find_dup_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list, retry: DBUG_PRINT("info", ("real table: %s.%s", d_name, t_name)); - for (TABLE_LIST *tl= table_list;;) + for (TABLE_LIST *tl= table_list; tl ; tl= tl->next_global, res= 0) { - if (tl && - tl->select_lex && tl->select_lex->master_unit() && + if (tl->select_lex && tl->select_lex->master_unit() && tl->select_lex->master_unit()->executed) { /* There is no sense to check tables of already executed parts of the query */ - tl= tl->next_global; continue; } /* @@ -1364,21 +1363,29 @@ retry: */ if (! (res= find_table_in_global_list(tl, d_name, t_name))) break; + tl= res; // We can continue search after this table /* Skip if same underlying table. */ if (res->table && (res->table == table->table)) - goto next; + continue; + + if (check_flag & CHECK_DUP_FOR_CREATE) + DBUG_RETURN(res); /* Skip if table alias does not match. */ - if (check_alias) + if (check_flag & CHECK_DUP_FOR_CREATE) { if (my_strcasecmp(table_alias_charset, t_alias, res->alias)) - goto next; + continue; } /* - Skip if marked to be excluded (could be a derived table) or if - entry is a prelocking placeholder. + If table is not excluded (could be a derived table) and table is not + a prelocking placeholder then we found either a duplicate entry + or a table that is part of a derived table (handled below). + Examples are: + INSERT INTO t1 SELECT * FROM t1; + INSERT INTO t1 SELECT * FROM view_containing_t1; */ if (res->select_lex && !res->select_lex->exclude_from_table_unique_test && @@ -1390,14 +1397,17 @@ retry: processed in derived table or top select of multi-update/multi-delete (exclude_from_table_unique_test) or prelocking placeholder. */ -next: - tl= res->next_global; DBUG_PRINT("info", ("found same copy of table or table which we should skip")); } if (res && res->belong_to_derived) { - /* Try to fix */ + /* + We come here for queries of type: + INSERT INTO t1 (SELECT tmp.a FROM (select * FROM t1) as tmp); + + Try to fix by materializing the derived table + */ TABLE_LIST *derived= res->belong_to_derived; if (derived->is_merged_derived()) { @@ -1429,7 +1439,7 @@ next: TABLE_LIST* unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list, - bool check_alias) + uint check_flag) { TABLE_LIST *dup; @@ -1443,12 +1453,12 @@ unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list, for (child= table->next_global; child && child->parent_l == table; child= child->next_global) { - if ((dup= find_dup_table(thd, child, child->next_global, check_alias))) + if ((dup= find_dup_table(thd, child, child->next_global, check_flag))) break; } } else - dup= find_dup_table(thd, table, table_list, check_alias); + dup= find_dup_table(thd, table, table_list, check_flag); return dup; } /* diff --git a/sql/sql_base.h b/sql/sql_base.h index 04f132ac936..af42a15ab29 100644 --- a/sql/sql_base.h +++ b/sql/sql_base.h @@ -61,6 +61,10 @@ enum find_item_error_report_type {REPORT_ALL_ERRORS, REPORT_EXCEPT_NOT_FOUND, IGNORE_ERRORS, REPORT_EXCEPT_NON_UNIQUE, IGNORE_EXCEPT_NON_UNIQUE}; +/* Flag bits for unique_table() */ +#define CHECK_DUP_ALLOW_DIFFERENT_ALIAS 1 +#define CHECK_DUP_FOR_CREATE 2 + uint create_tmp_table_def_key(THD *thd, char *key, const char *db, const char *table_name); uint get_table_def_key(const TABLE_LIST *table_list, const char **key); @@ -254,7 +258,7 @@ void kill_delayed_threads_for_table(TABLE_SHARE *share); void close_thread_table(THD *thd, TABLE **table_ptr); bool close_temporary_tables(THD *thd); TABLE_LIST *unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list, - bool check_alias); + uint check_flag); int drop_temporary_table(THD *thd, TABLE *table, bool *is_trans); void close_temporary_table(THD *thd, TABLE *table, bool free_share, bool delete_table); diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 0780f418c80..609e5472ba6 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -903,7 +903,7 @@ multi_delete::initialize_tables(JOIN *join) TABLE_LIST *tbl= walk->correspondent_table->find_table_for_update(); tables_to_delete_from|= tbl->table->map; if (delete_while_scanning && - unique_table(thd, tbl, join->tables_list, false)) + unique_table(thd, tbl, join->tables_list, 0)) { /* If the table we are going to delete from appears diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 6036bbeb8b1..8b03c722898 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1483,7 +1483,8 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, { Item *fake_conds= 0; TABLE_LIST *duplicate; - if ((duplicate= unique_table(thd, table_list, table_list->next_global, 1))) + if ((duplicate= unique_table(thd, table_list, table_list->next_global, + CHECK_DUP_ALLOW_DIFFERENT_ALIAS))) { update_non_unique_table_error(table_list, "INSERT", duplicate); DBUG_RETURN(TRUE); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 87edf93bb4a..1162aa901d1 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2970,7 +2970,7 @@ case SQLCOM_PREPARE: TABLE_LIST *duplicate; if ((duplicate= unique_table(thd, lex->query_tables, lex->query_tables->next_global, - 0))) + CHECK_DUP_FOR_CREATE))) { update_non_unique_table_error(lex->query_tables, "CREATE", duplicate); From cb21e117baba0e2007b9863d0916df6dd2863d38 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 16 May 2018 18:03:06 +0200 Subject: [PATCH 07/25] MDEV-16187 Ubuntu Bionic MariaDB has epoch version that makes 10.1 and 10.2 installs fail --- debian/autobake-deb.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/debian/autobake-deb.sh b/debian/autobake-deb.sh index 157f33eb298..c26fcaa4e85 100755 --- a/debian/autobake-deb.sh +++ b/debian/autobake-deb.sh @@ -99,10 +99,13 @@ UPSTREAM="${MYSQL_VERSION_MAJOR}.${MYSQL_VERSION_MINOR}.${MYSQL_VERSION_PATCH}${ PATCHLEVEL="+maria" LOGSTRING="MariaDB build" CODENAME="$(lsb_release -sc)" +if [[ "$CODENAME" == bionic ]]; then + EPOCH="1:" +fi -dch -b -D ${CODENAME} -v "${UPSTREAM}${PATCHLEVEL}~${CODENAME}" "Automatic build with ${LOGSTRING}." +dch -b -D ${CODENAME} -v "${EPOCH}${UPSTREAM}${PATCHLEVEL}~${CODENAME}" "Automatic build with ${LOGSTRING}." -echo "Creating package version ${UPSTREAM}${PATCHLEVEL}~${CODENAME} ... " +echo "Creating package version ${EPOCH}${UPSTREAM}${PATCHLEVEL}~${CODENAME} ... " # Build the package # Pass -I so that .git and other unnecessary temporary and source control files From bb045e7931c451b228ffc5bcdb1791a31eb0c852 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 16 May 2018 11:15:08 +0200 Subject: [PATCH 08/25] MDEV-16183 TokuDB tests fail on Fedora 28 jemalloc > 5.0.0 doesn't like to be linked with a dlopen-ed module. Don't link tokudb with jemalloc on Fedora 28, LD_PRELOAD it instead with mysqld_safe and with systemd. --- storage/tokudb/CMakeLists.txt | 29 +++++++++++++++++++- storage/tokudb/{tokudb.cnf => tokudb.cnf.in} | 3 ++ storage/tokudb/tokudb.conf.in | 3 ++ 3 files changed, 34 insertions(+), 1 deletion(-) rename storage/tokudb/{tokudb.cnf => tokudb.cnf.in} (62%) create mode 100644 storage/tokudb/tokudb.conf.in diff --git a/storage/tokudb/CMakeLists.txt b/storage/tokudb/CMakeLists.txt index a0abee09727..16f7ab4ce75 100644 --- a/storage/tokudb/CMakeLists.txt +++ b/storage/tokudb/CMakeLists.txt @@ -35,7 +35,7 @@ SET(TOKUDB_SOURCES tokudb_thread.cc tokudb_dir_cmd.cc) MYSQL_ADD_PLUGIN(tokudb ${TOKUDB_SOURCES} STORAGE_ENGINE MODULE_ONLY - COMPONENT tokudb-engine CONFIG tokudb.cnf) + COMPONENT tokudb-engine CONFIG ${CMAKE_CURRENT_BINARY_DIR}/tokudb.cnf) IF(NOT TARGET tokudb) RETURN() @@ -46,6 +46,33 @@ CHECK_JEMALLOC() IF(NOT LIBJEMALLOC) MESSAGE(WARNING "TokuDB is enabled, but jemalloc is not. This configuration is not supported") +ELSEIF(LIBJEMALLOC STREQUAL jemalloc) + FIND_LIBRARY(LIBJEMALLOC_SO jemalloc) + IF(NOT LIBJEMALLOC_SO) + MESSAGE(FATAL_ERROR "jemalloc is present, but cannot be found?") + ENDIF() + GET_FILENAME_COMPONENT(LIBJEMALLOC_PATH ${LIBJEMALLOC_SO} REALPATH CACHE) +ENDIF() + +IF(LIBJEMALLOC_PATH AND RPM MATCHES fedora28) # TODO check for jemalloc version + UNSET(LIBJEMALLOC) + GET_DIRECTORY_PROPERTY(V DIRECTORY ${CMAKE_SOURCE_DIR} DEFINITION CPACK_RPM_tokudb-engine_PACKAGE_REQUIRES) + SET(CPACK_RPM_tokudb-engine_PACKAGE_REQUIRES "${V} jemalloc" PARENT_SCOPE) + SET(systemd_env "Environment=\"LD_PRELOAD=${LIBJEMALLOC_PATH}\"") #" + SET(cnf_malloc_lib "malloc-lib=${LIBJEMALLOC_PATH}") +ELSEIF(LIBJEMALLOC_PATH) + SET(systemd_env "#Environment=\"LD_PRELOAD=${LIBJEMALLOC_PATH}\"") #" + SET(cnf_malloc_lib "#malloc-lib=${LIBJEMALLOC_PATH}") +ELSE() + SET(systemd_env "#Environment=\"LD_PRELOAD=/path/to/libjemalloc.so\"") #" + SET(cnf_malloc_lib "#malloc-lib=/path/to/libjemalloc.so") +ENDIF() +CONFIGURE_FILE(tokudb.cnf.in tokudb.cnf @ONLY) +CONFIGURE_FILE(tokudb.conf.in tokudb.conf @ONLY) +IF(INSTALL_SYSCONFDIR) + INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/tokudb.conf + DESTINATION ${INSTALL_SYSCONFDIR}/systemd/system/mariadb.service.d/ + COMPONENT tokudb-engine) ENDIF() MY_CHECK_AND_SET_COMPILER_FLAG("-Wno-vla" DEBUG) diff --git a/storage/tokudb/tokudb.cnf b/storage/tokudb/tokudb.cnf.in similarity index 62% rename from storage/tokudb/tokudb.cnf rename to storage/tokudb/tokudb.cnf.in index 4def635ddf0..de9b5b711ee 100644 --- a/storage/tokudb/tokudb.cnf +++ b/storage/tokudb/tokudb.cnf.in @@ -4,3 +4,6 @@ plugin-load-add=ha_tokudb.so +[mysqld_safe] +# it might be necessary to uncomment the following line if jemalloc >= 5.0.0 +@cnf_malloc_lib@ diff --git a/storage/tokudb/tokudb.conf.in b/storage/tokudb/tokudb.conf.in new file mode 100644 index 00000000000..d22f6686d91 --- /dev/null +++ b/storage/tokudb/tokudb.conf.in @@ -0,0 +1,3 @@ +[Service] +# it might be necessary to uncomment the following line if jemalloc >= 5.0.0 +@systemd_env@ From 1b2078b4d8aa64bad8bc2b3a201e0cf8c075e6a6 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 15 May 2018 17:34:47 +0200 Subject: [PATCH 09/25] MDEV-15318 CREATE .. SELECT VALUES produces invalid table structure When Item_insert_value needs a dummy field, use zero-length Field_string, not Field_null. The latter isn't compatible with CREATE ... SELECT. --- mysql-test/r/insert_select.result | 9 +++++++++ mysql-test/t/insert_select.test | 10 ++++++++++ sql/item.cc | 8 ++++---- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/insert_select.result b/mysql-test/r/insert_select.result index 8bfc4e9215e..157cc677d85 100644 --- a/mysql-test/r/insert_select.result +++ b/mysql-test/r/insert_select.result @@ -853,3 +853,12 @@ INSERT IGNORE INTO t1 SELECT t1.a FROM t1,t1 t2,t1 t3,t1 t4,t1 t5,t1 t6,t1 t7; SET GLOBAL myisam_data_pointer_size = @old_myisam_data_pointer_size; DROP TABLE t1; End of 5.1 tests +create table t1 (i int); +create table t2 as select values(i) as a from t1; +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` binary(0) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1, t2; +End of 5.5 tests diff --git a/mysql-test/t/insert_select.test b/mysql-test/t/insert_select.test index bcd87c2688d..385e372bc3b 100644 --- a/mysql-test/t/insert_select.test +++ b/mysql-test/t/insert_select.test @@ -423,3 +423,13 @@ SET GLOBAL myisam_data_pointer_size = @old_myisam_data_pointer_size; DROP TABLE t1; --echo End of 5.1 tests + +# +# MDEV-15318 CREATE .. SELECT VALUES produces invalid table structure +# +create table t1 (i int); +create table t2 as select values(i) as a from t1; +show create table t2; +drop table t1, t2; + +--echo End of 5.5 tests diff --git a/sql/item.cc b/sql/item.cc index c5c6df0ec48..135255ee21e 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -8541,10 +8541,10 @@ bool Item_insert_value::fix_fields(THD *thd, Item **items) } else { - Field *tmp_field= field_arg->field; - /* charset doesn't matter here, it's to avoid sigsegv only */ - tmp_field= new Field_null(0, 0, Field::NONE, field_arg->field->field_name, - &my_charset_bin); + static uchar null_bit=1; + /* charset doesn't matter here */ + Field *tmp_field= new Field_string(0, 0, &null_bit, 1, Field::NONE, + field_arg->field->field_name, &my_charset_bin); if (tmp_field) { tmp_field->init(field_arg->field->table); From ab9d420df37d76a1ff68e6fd2d5bf53a797c4102 Mon Sep 17 00:00:00 2001 From: Jacob Mathew Date: Thu, 17 May 2018 11:21:13 -0700 Subject: [PATCH 10/25] MDEV-7914: spider/bg.ha, spider/bg.ha_part crash server sporadically in buildbot The crash occurs when a thread that is closing its connection attempts to access Spider transaction information when another thread has freed that memory while processing Spider plugin deinit. This occurs because Spider does not adjust the plugin's reference count when it sets a transaction information pointer for the plugin. The fix I implemented changes the way Spider sets the transaction information pointer to use thd_set_ha_data() so that Spider's plugin reference counter is adjusted as well. Author: Jacob Mathew. Reviewer: Kentoku Shiba. Merged From: Commit eabfadc on branch bb-10.3-MDEV-7914 --- storage/spider/ha_spider.cc | 2 +- storage/spider/spd_malloc.h | 2 +- storage/spider/spd_table.cc | 66 +++++++++++++++++++++++++++++-------- storage/spider/spd_trx.cc | 42 +++++++++++------------ 4 files changed, 76 insertions(+), 36 deletions(-) diff --git a/storage/spider/ha_spider.cc b/storage/spider/ha_spider.cc index 7363a69f49f..3ee1d6114ea 100644 --- a/storage/spider/ha_spider.cc +++ b/storage/spider/ha_spider.cc @@ -712,7 +712,7 @@ int ha_spider::close() } } - if (!thd || !*thd_ha_data(thd, spider_hton_ptr)) + if (!thd || !thd_get_ha_data(thd, spider_hton_ptr)) { for (roop_count = 0; roop_count < (int) share->link_count; roop_count++) conns[roop_count] = NULL; diff --git a/storage/spider/spd_malloc.h b/storage/spider/spd_malloc.h index 3c5c6e67c2a..697595edeb6 100644 --- a/storage/spider/spd_malloc.h +++ b/storage/spider/spd_malloc.h @@ -19,7 +19,7 @@ #define spider_bulk_malloc(A,B,C,...) \ spider_bulk_alloc_mem(A,B,__func__,__FILE__,__LINE__,C,__VA_ARGS__) #define spider_current_trx \ - (current_thd ? ((SPIDER_TRX *) *thd_ha_data(current_thd, spider_hton_ptr)) : NULL) + (current_thd ? ((SPIDER_TRX *) thd_get_ha_data(current_thd, spider_hton_ptr)) : NULL) #define init_calc_mem(A) init_mem_calc(A,__func__,__FILE__,__LINE__) diff --git a/storage/spider/spd_table.cc b/storage/spider/spd_table.cc index b05ea1a2229..a5ca0b724eb 100644 --- a/storage/spider/spd_table.cc +++ b/storage/spider/spd_table.cc @@ -41,6 +41,27 @@ #include "spd_direct_sql.h" #include "spd_malloc.h" +inline MYSQL_THD spider_create_thd() +{ + THD *thd; + my_thread_init(); + if (!(thd = new THD(next_thread_id()))) + my_thread_end(); + else + { +#ifdef HAVE_PSI_INTERFACE + mysql_thread_set_psi_id(thd->thread_id); +#endif + thd->thread_stack = (char *) &thd; + thd->store_globals(); + } + return thd; +} +inline void spider_destroy_thd(MYSQL_THD thd) +{ + delete thd; +} + #ifdef SPIDER_XID_USES_xid_cache_iterate #else #ifdef XID_CACHE_IS_SPLITTED @@ -6000,7 +6021,7 @@ int spider_close_connection( SPIDER_CONN *conn; SPIDER_TRX *trx; DBUG_ENTER("spider_close_connection"); - if (!(trx = (SPIDER_TRX*) *thd_ha_data(thd, spider_hton_ptr))) + if (!(trx = (SPIDER_TRX*) thd_get_ha_data(thd, spider_hton_ptr))) DBUG_RETURN(0); /* transaction is not started */ trx->tmp_spider->conns = &conn; @@ -6055,6 +6076,7 @@ int spider_db_done( void *p ) { int roop_count; + bool do_delete_thd; THD *thd = current_thd, *tmp_thd; SPIDER_CONN *conn; SPIDER_INIT_ERROR_TABLE *spider_init_error_table; @@ -6062,6 +6084,18 @@ int spider_db_done( SPIDER_LGTM_TBLHND_SHARE *lgtm_tblhnd_share; DBUG_ENTER("spider_db_done"); + /* Begin Spider plugin deinit */ + if (thd) + do_delete_thd = FALSE; + else + { + /* Create a thread for Spider plugin deinit */ + thd = spider_create_thd(); + if (!thd) + DBUG_RETURN(HA_ERR_OUT_OF_MEM); + do_delete_thd = TRUE; + } + #ifndef WITHOUT_SPIDER_BG_SEARCH spider_free_trx(spider_global_trx, TRUE); #endif @@ -6104,21 +6138,22 @@ int spider_db_done( pthread_mutex_destroy(&spider_udf_table_mon_mutexes[roop_count]); spider_free(NULL, spider_udf_table_mon_mutexes, MYF(0)); - if (thd && thd_sql_command(thd) == SQLCOM_UNINSTALL_PLUGIN) { - pthread_mutex_lock(&spider_allocated_thds_mutex); - while ((tmp_thd = (THD *) my_hash_element(&spider_allocated_thds, 0))) + pthread_mutex_lock(&spider_allocated_thds_mutex); + while ((tmp_thd = (THD *) my_hash_element(&spider_allocated_thds, 0))) + { + SPIDER_TRX *trx = (SPIDER_TRX *) + thd_get_ha_data(tmp_thd, spider_hton_ptr); + if (trx) { - SPIDER_TRX *trx = (SPIDER_TRX *) *thd_ha_data(tmp_thd, spider_hton_ptr); - if (trx) - { - DBUG_ASSERT(tmp_thd == trx->thd); - spider_free_trx(trx, FALSE); - *thd_ha_data(tmp_thd, spider_hton_ptr) = (void *) NULL; - } else - my_hash_delete(&spider_allocated_thds, (uchar *) tmp_thd); + DBUG_ASSERT(tmp_thd == trx->thd); + spider_free_trx(trx, FALSE); + thd_set_ha_data(tmp_thd, spider_hton_ptr, NULL); } - pthread_mutex_unlock(&spider_allocated_thds_mutex); + else + my_hash_delete(&spider_allocated_thds, (uchar *) tmp_thd); } + pthread_mutex_unlock(&spider_allocated_thds_mutex); + #if defined(HS_HAS_SQLCOM) && defined(HAVE_HANDLERSOCKET) pthread_mutex_lock(&spider_hs_w_conn_mutex); while ((conn = (SPIDER_CONN*) my_hash_element(&spider_hs_w_conn_hash, 0))) @@ -6267,6 +6302,11 @@ int spider_db_done( spider_current_alloc_mem[roop_count] ? "NG" : "OK" )); } + + /* End Spider plugin deinit */ + if (do_delete_thd) + spider_destroy_thd(thd); + /* DBUG_ASSERT(0); */ diff --git a/storage/spider/spd_trx.cc b/storage/spider/spd_trx.cc index 63d9e096fa7..6435e2be72c 100644 --- a/storage/spider/spd_trx.cc +++ b/storage/spider/spd_trx.cc @@ -1147,7 +1147,7 @@ SPIDER_TRX *spider_get_trx( if ( !thd || - !(trx = (SPIDER_TRX*) *thd_ha_data(thd, spider_hton_ptr)) + !(trx = (SPIDER_TRX*) thd_get_ha_data(thd, spider_hton_ptr)) ) { DBUG_PRINT("info",("spider create new trx")); if (!(trx = (SPIDER_TRX *) @@ -1185,7 +1185,7 @@ SPIDER_TRX *spider_get_trx( goto error_init_hash; spider_alloc_calc_mem_init(trx->trx_conn_hash, 151); spider_alloc_calc_mem( - thd ? ((SPIDER_TRX *) *thd_ha_data(thd, spider_hton_ptr)) : NULL, + thd ? ((SPIDER_TRX *) thd_get_ha_data(thd, spider_hton_ptr)) : NULL, trx->trx_conn_hash, trx->trx_conn_hash.array.max_element * trx->trx_conn_hash.array.size_of_element); @@ -1197,7 +1197,7 @@ SPIDER_TRX *spider_get_trx( goto error_init_another_hash; spider_alloc_calc_mem_init(trx->trx_another_conn_hash, 152); spider_alloc_calc_mem( - thd ? ((SPIDER_TRX *) *thd_ha_data(thd, spider_hton_ptr)) : NULL, + thd ? ((SPIDER_TRX *) thd_get_ha_data(thd, spider_hton_ptr)) : NULL, trx->trx_another_conn_hash, trx->trx_another_conn_hash.array.max_element * trx->trx_another_conn_hash.array.size_of_element); @@ -1210,7 +1210,7 @@ SPIDER_TRX *spider_get_trx( goto error_hs_r_init_hash; spider_alloc_calc_mem_init(trx->trx_hs_r_conn_hash, 153); spider_alloc_calc_mem( - thd ? ((SPIDER_TRX *) *thd_ha_data(thd, spider_hton_ptr)) : NULL, + thd ? ((SPIDER_TRX *) thd_get_ha_data(thd, spider_hton_ptr)) : NULL, trx->trx_hs_r_conn_hash, trx->trx_hs_r_conn_hash.array.max_element * trx->trx_hs_r_conn_hash.array.size_of_element); @@ -1222,7 +1222,7 @@ SPIDER_TRX *spider_get_trx( goto error_hs_w_init_hash; spider_alloc_calc_mem_init(trx->trx_hs_w_conn_hash, 154); spider_alloc_calc_mem( - thd ? ((SPIDER_TRX *) *thd_ha_data(thd, spider_hton_ptr)) : NULL, + thd ? ((SPIDER_TRX *) thd_get_ha_data(thd, spider_hton_ptr)) : NULL, trx->trx_hs_w_conn_hash, trx->trx_hs_w_conn_hash.array.max_element * trx->trx_hs_w_conn_hash.array.size_of_element); @@ -1236,7 +1236,7 @@ SPIDER_TRX *spider_get_trx( goto error_direct_hs_r_init_hash; spider_alloc_calc_mem_init(trx->trx_direct_hs_r_conn_hash, 155); spider_alloc_calc_mem( - thd ? ((SPIDER_TRX *) *thd_ha_data(thd, spider_hton_ptr)) : NULL, + thd ? ((SPIDER_TRX *) thd_get_ha_data(thd, spider_hton_ptr)) : NULL, trx->trx_direct_hs_r_conn_hash, trx->trx_direct_hs_r_conn_hash.array.max_element * trx->trx_direct_hs_r_conn_hash.array.size_of_element); @@ -1248,7 +1248,7 @@ SPIDER_TRX *spider_get_trx( goto error_direct_hs_w_init_hash; spider_alloc_calc_mem_init(trx->trx_direct_hs_w_conn_hash, 156); spider_alloc_calc_mem( - thd ? ((SPIDER_TRX *) *thd_ha_data(thd, spider_hton_ptr)) : NULL, + thd ? ((SPIDER_TRX *) thd_get_ha_data(thd, spider_hton_ptr)) : NULL, trx->trx_direct_hs_w_conn_hash, trx->trx_direct_hs_w_conn_hash.array.max_element * trx->trx_direct_hs_w_conn_hash.array.size_of_element); @@ -1261,7 +1261,7 @@ SPIDER_TRX *spider_get_trx( goto error_init_alter_hash; spider_alloc_calc_mem_init(trx->trx_alter_table_hash, 157); spider_alloc_calc_mem( - thd ? ((SPIDER_TRX *) *thd_ha_data(thd, spider_hton_ptr)) : NULL, + thd ? ((SPIDER_TRX *) thd_get_ha_data(thd, spider_hton_ptr)) : NULL, trx->trx_alter_table_hash, trx->trx_alter_table_hash.array.max_element * trx->trx_alter_table_hash.array.size_of_element); @@ -1273,7 +1273,7 @@ SPIDER_TRX *spider_get_trx( goto error_init_trx_ha_hash; spider_alloc_calc_mem_init(trx->trx_ha_hash, 158); spider_alloc_calc_mem( - thd ? ((SPIDER_TRX *) *thd_ha_data(thd, spider_hton_ptr)) : NULL, + thd ? ((SPIDER_TRX *) thd_get_ha_data(thd, spider_hton_ptr)) : NULL, trx->trx_ha_hash, trx->trx_ha_hash.array.max_element * trx->trx_ha_hash.array.size_of_element); @@ -1395,7 +1395,7 @@ SPIDER_TRX *spider_get_trx( pthread_mutex_unlock(&spider_allocated_thds_mutex); trx->registed_allocated_thds = TRUE; } - *thd_ha_data(thd, spider_hton_ptr) = (void *) trx; + thd_set_ha_data(thd, spider_hton_ptr, trx); } } @@ -1441,7 +1441,7 @@ error_set_connect_info_default: my_hash_free(&trx->trx_ha_hash); error_init_trx_ha_hash: spider_free_mem_calc( - thd ? ((SPIDER_TRX *) *thd_ha_data(thd, spider_hton_ptr)) : NULL, + thd ? ((SPIDER_TRX *) thd_get_ha_data(thd, spider_hton_ptr)) : NULL, trx->trx_alter_table_hash_id, trx->trx_alter_table_hash.array.max_element * trx->trx_alter_table_hash.array.size_of_element); @@ -1449,14 +1449,14 @@ error_init_trx_ha_hash: error_init_alter_hash: #if defined(HS_HAS_SQLCOM) && defined(HAVE_HANDLERSOCKET) spider_free_mem_calc( - thd ? ((SPIDER_TRX *) *thd_ha_data(thd, spider_hton_ptr)) : NULL, + thd ? ((SPIDER_TRX *) thd_get_ha_data(thd, spider_hton_ptr)) : NULL, trx->trx_direct_hs_w_conn_hash_id, trx->trx_direct_hs_w_conn_hash.array.max_element * trx->trx_direct_hs_w_conn_hash.array.size_of_element); my_hash_free(&trx->trx_direct_hs_w_conn_hash); error_direct_hs_w_init_hash: spider_free_mem_calc( - thd ? ((SPIDER_TRX *) *thd_ha_data(thd, spider_hton_ptr)) : NULL, + thd ? ((SPIDER_TRX *) thd_get_ha_data(thd, spider_hton_ptr)) : NULL, trx->trx_direct_hs_r_conn_hash_id, trx->trx_direct_hs_r_conn_hash.array.max_element * trx->trx_direct_hs_r_conn_hash.array.size_of_element); @@ -1465,14 +1465,14 @@ error_direct_hs_r_init_hash: #endif #if defined(HS_HAS_SQLCOM) && defined(HAVE_HANDLERSOCKET) spider_free_mem_calc( - thd ? ((SPIDER_TRX *) *thd_ha_data(thd, spider_hton_ptr)) : NULL, + thd ? ((SPIDER_TRX *) thd_get_ha_data(thd, spider_hton_ptr)) : NULL, trx->trx_hs_w_conn_hash_id, trx->trx_hs_w_conn_hash.array.max_element * trx->trx_hs_w_conn_hash.array.size_of_element); my_hash_free(&trx->trx_hs_w_conn_hash); error_hs_w_init_hash: spider_free_mem_calc( - thd ? ((SPIDER_TRX *) *thd_ha_data(thd, spider_hton_ptr)) : NULL, + thd ? ((SPIDER_TRX *) thd_get_ha_data(thd, spider_hton_ptr)) : NULL, trx->trx_hs_r_conn_hash_id, trx->trx_hs_r_conn_hash.array.max_element * trx->trx_hs_r_conn_hash.array.size_of_element); @@ -1480,14 +1480,14 @@ error_hs_w_init_hash: error_hs_r_init_hash: #endif spider_free_mem_calc( - thd ? ((SPIDER_TRX *) *thd_ha_data(thd, spider_hton_ptr)) : NULL, + thd ? ((SPIDER_TRX *) thd_get_ha_data(thd, spider_hton_ptr)) : NULL, trx->trx_another_conn_hash_id, trx->trx_another_conn_hash.array.max_element * trx->trx_another_conn_hash.array.size_of_element); my_hash_free(&trx->trx_another_conn_hash); error_init_another_hash: spider_free_mem_calc( - thd ? ((SPIDER_TRX *) *thd_ha_data(thd, spider_hton_ptr)) : NULL, + thd ? ((SPIDER_TRX *) thd_get_ha_data(thd, spider_hton_ptr)) : NULL, trx->trx_conn_hash_id, trx->trx_conn_hash.array.max_element * trx->trx_conn_hash.array.size_of_element); @@ -1526,7 +1526,7 @@ int spider_free_trx( if (need_lock) pthread_mutex_unlock(&spider_allocated_thds_mutex); } - *thd_ha_data(trx->thd, spider_hton_ptr) = (void *) NULL; + thd_set_ha_data(trx->thd, spider_hton_ptr, NULL); } spider_free_trx_alloc(trx); spider_merge_mem_calc(trx, TRUE); @@ -3304,7 +3304,7 @@ int spider_commit( SPIDER_CONN *conn; DBUG_ENTER("spider_commit"); - if (!(trx = (SPIDER_TRX*) *thd_ha_data(thd, spider_hton_ptr))) + if (!(trx = (SPIDER_TRX*) thd_get_ha_data(thd, spider_hton_ptr))) DBUG_RETURN(0); /* transaction is not started */ #ifdef HA_CAN_BULK_ACCESS @@ -3394,7 +3394,7 @@ int spider_rollback( SPIDER_CONN *conn; DBUG_ENTER("spider_rollback"); - if (!(trx = (SPIDER_TRX*) *thd_ha_data(thd, spider_hton_ptr))) + if (!(trx = (SPIDER_TRX*) thd_get_ha_data(thd, spider_hton_ptr))) DBUG_RETURN(0); /* transaction is not started */ #ifdef HA_CAN_BULK_ACCESS @@ -3469,7 +3469,7 @@ int spider_xa_prepare( if (all || (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) { - if (!(trx = (SPIDER_TRX*) *thd_ha_data(thd, spider_hton_ptr))) + if (!(trx = (SPIDER_TRX*) thd_get_ha_data(thd, spider_hton_ptr))) DBUG_RETURN(0); /* transaction is not started */ DBUG_PRINT("info",("spider trx_start=%s", From d309c2fc885a5d50645ca9b43da2fda09f8b4418 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Thu, 17 May 2018 15:47:17 -0700 Subject: [PATCH 11/25] MDEV-16212 Memory leak with recursive CTE that uses global ORDER BY with recursive subquery There were two problems: 1. The code did not report that usage of global ORDER BY / LIMIT clauses was not supported yet. 2. The code just reset fake_select_lex of the the unit specifying a recursive CTE to NULL and that caused memory leaks in some cases. --- mysql-test/r/cte_recursive.result | 10 ++++++++++ mysql-test/t/cte_recursive.test | 12 ++++++++++++ sql/sql_union.cc | 13 ++++++++++++- 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/cte_recursive.result b/mysql-test/r/cte_recursive.result index d6dfdf1ec6a..b7516b88f9a 100644 --- a/mysql-test/r/cte_recursive.result +++ b/mysql-test/r/cte_recursive.result @@ -3233,3 +3233,13 @@ Parent Child Path 654 987 987, 321 654 987,654, DROP TABLE t1; +# +# MDEV-16212: recursive CTE with global ORDER BY +# +set statement max_recursive_iterations = 2 for +WITH RECURSIVE qn AS ( +SELECT 1 FROM dual UNION ALL +SELECT 1 FROM qn +ORDER BY (SELECT * FROM qn)) +SELECT count(*) FROM qn; +ERROR 42000: This version of MariaDB doesn't yet support 'global ORDER_BY/LIMIT in recursive CTE spec' diff --git a/mysql-test/t/cte_recursive.test b/mysql-test/t/cte_recursive.test index 3a8795e114a..b3276475fa4 100644 --- a/mysql-test/t/cte_recursive.test +++ b/mysql-test/t/cte_recursive.test @@ -2246,3 +2246,15 @@ FROM cte ORDER BY Path; DROP TABLE t1; + +--echo # +--echo # MDEV-16212: recursive CTE with global ORDER BY +--echo # + +--error ER_NOT_SUPPORTED_YET +set statement max_recursive_iterations = 2 for +WITH RECURSIVE qn AS ( +SELECT 1 FROM dual UNION ALL +SELECT 1 FROM qn +ORDER BY (SELECT * FROM qn)) +SELECT count(*) FROM qn; diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 3fe90564000..39e7bcdf051 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -521,7 +521,18 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, with_element->rec_result= new (thd_arg->mem_root) select_union_recursive(thd_arg); union_result= with_element->rec_result; - fake_select_lex= NULL; + if (fake_select_lex) + { + if (fake_select_lex->order_list.first || + fake_select_lex->explicit_limit) + { + my_error(ER_NOT_SUPPORTED_YET, MYF(0), + "global ORDER_BY/LIMIT in recursive CTE spec"); + goto err; + } + fake_select_lex->cleanup(); + fake_select_lex= NULL; + } } if (!(tmp_result= union_result)) goto err; /* purecov: inspected */ From 52c98bf830cc14948f6a950961c77d64d20677a6 Mon Sep 17 00:00:00 2001 From: Daniel Bartholomew Date: Fri, 18 May 2018 00:35:59 -0400 Subject: [PATCH 12/25] bump the VERSION --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index f9cc24a17b8..390743d6cd3 100644 --- a/VERSION +++ b/VERSION @@ -1,3 +1,3 @@ MYSQL_VERSION_MAJOR=10 MYSQL_VERSION_MINOR=2 -MYSQL_VERSION_PATCH=15 +MYSQL_VERSION_PATCH=16 From de86997160ea5e02e7fc6eb877d5823e96b64523 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Thu, 17 May 2018 22:56:27 -0700 Subject: [PATCH 13/25] MDEV-15581 Incorrect result (missing row) with UNION DISTINCT in anchor parts The current code does not support recursive CTEs whose specifications contain a mix of ALL UNION and DISTINCT UNION operations. This patch catches such specifications and reports errors for them. --- mysql-test/r/cte_recursive.result | 20 ++++++++++++++++++++ mysql-test/t/cte_recursive.test | 24 ++++++++++++++++++++++++ sql/sql_cte.cc | 12 ++++++++---- sql/sql_lex.cc | 1 + sql/sql_lex.h | 1 + sql/sql_union.cc | 17 +++++++++++++++++ sql/sql_yacc.yy | 1 + 7 files changed, 72 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/cte_recursive.result b/mysql-test/r/cte_recursive.result index b7516b88f9a..2e93e9f6ff8 100644 --- a/mysql-test/r/cte_recursive.result +++ b/mysql-test/r/cte_recursive.result @@ -3243,3 +3243,23 @@ SELECT 1 FROM qn ORDER BY (SELECT * FROM qn)) SELECT count(*) FROM qn; ERROR 42000: This version of MariaDB doesn't yet support 'global ORDER_BY/LIMIT in recursive CTE spec' +# +# MDEV-15581: mix of ALL and DISTINCT UNION in recursive CTE +# +create table t1(a int); +insert into t1 values(1),(2); +insert into t1 values(1),(2); +set @c=0, @d=0; +WITH RECURSIVE qn AS +( +select 1,0 as col from t1 +union distinct +select 1,0 from t1 +union all +select 3, 0*(@c:=@c+1) from qn where @c<1 +union all +select 3, 0*(@d:=@d+1) from qn where @d<1 +) +select * from qn; +ERROR 42000: This version of MariaDB doesn't yet support 'mix of ALL and DISTINCT UNION operations in recursive CTE spec' +drop table t1; diff --git a/mysql-test/t/cte_recursive.test b/mysql-test/t/cte_recursive.test index b3276475fa4..32a82c494e0 100644 --- a/mysql-test/t/cte_recursive.test +++ b/mysql-test/t/cte_recursive.test @@ -2258,3 +2258,27 @@ SELECT 1 FROM dual UNION ALL SELECT 1 FROM qn ORDER BY (SELECT * FROM qn)) SELECT count(*) FROM qn; + +--echo # +--echo # MDEV-15581: mix of ALL and DISTINCT UNION in recursive CTE +--echo # + +create table t1(a int); +insert into t1 values(1),(2); +insert into t1 values(1),(2); + +set @c=0, @d=0; +--error ER_NOT_SUPPORTED_YET +WITH RECURSIVE qn AS +( +select 1,0 as col from t1 +union distinct +select 1,0 from t1 +union all +select 3, 0*(@c:=@c+1) from qn where @c<1 +union all +select 3, 0*(@d:=@d+1) from qn where @d<1 +) +select * from qn; + +drop table t1; diff --git a/sql/sql_cte.cc b/sql/sql_cte.cc index cd2516c2beb..fdd6943af93 100644 --- a/sql/sql_cte.cc +++ b/sql/sql_cte.cc @@ -665,7 +665,6 @@ void With_element::move_anchors_ahead() { st_select_lex *next_sl; st_select_lex *new_pos= spec->first_select(); - st_select_lex *UNINIT_VAR(last_sl); new_pos->linkage= UNION_TYPE; for (st_select_lex *sl= new_pos; sl; sl= next_sl) { @@ -673,6 +672,14 @@ void With_element::move_anchors_ahead() if (is_anchor(sl)) { sl->move_node(new_pos); + if (new_pos == spec->first_select()) + { + enum sub_select_type type= new_pos->linkage; + new_pos->linkage= sl->linkage; + sl->linkage= type; + new_pos->with_all_modifier= sl->with_all_modifier; + sl->with_all_modifier= false; + } new_pos= sl->next_select(); } else if (!sq_rec_ref && no_rec_ref_on_top_level()) @@ -680,10 +687,7 @@ void With_element::move_anchors_ahead() sq_rec_ref= find_first_sq_rec_ref_in_select(sl); DBUG_ASSERT(sq_rec_ref != NULL); } - last_sl= sl; } - if (spec->union_distinct) - spec->union_distinct= last_sl; first_recursive= new_pos; } diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 1752689b385..7c963be695a 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -2171,6 +2171,7 @@ void st_select_lex::init_select() select_limit= 0; /* denotes the default limit = HA_POS_ERROR */ offset_limit= 0; /* denotes the default offset = 0 */ with_sum_func= 0; + with_all_modifier= 0; is_correlated= 0; cur_pos_in_select_list= UNDEF_POS; cond_value= having_value= Item::COND_UNDEF; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 68e1885f5e9..4acb1e441c1 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -907,6 +907,7 @@ public: */ bool subquery_in_having; /* TRUE <=> this SELECT is correlated w.r.t. some ancestor select */ + bool with_all_modifier; /* used for selects in union */ bool is_correlated; /* This variable is required to ensure proper work of subqueries and diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 39e7bcdf051..13c19dae342 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -453,6 +453,23 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, DBUG_ASSERT(thd == thd_arg); DBUG_ASSERT(thd == current_thd); + if (is_recursive && (sl= first_sl->next_select())) + { + SELECT_LEX *next_sl; + for ( ; ; sl= next_sl) + { + next_sl= sl->next_select(); + if (!next_sl) + break; + if (next_sl->with_all_modifier != sl->with_all_modifier) + { + my_error(ER_NOT_SUPPORTED_YET, MYF(0), + "mix of ALL and DISTINCT UNION operations in recursive CTE spec"); + DBUG_RETURN(TRUE); + } + } + } + describe= additional_options & SELECT_DESCRIBE; /* diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index b2088b0e640..47e5f2f9402 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -707,6 +707,7 @@ bool add_select_to_union_list(LEX *lex, bool is_union_distinct, return TRUE; mysql_init_select(lex); lex->current_select->linkage=UNION_TYPE; + lex->current_select->with_all_modifier= !is_union_distinct; if (is_union_distinct) /* UNION DISTINCT - remember position */ lex->current_select->master_unit()->union_distinct= lex->current_select; From 727d0d4f9bd0d5df04ebca3c67cb33405f221c38 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Fri, 18 May 2018 17:26:12 +0300 Subject: [PATCH 14/25] MDEV-15304: Server crash in print_keydup_error / key_unpack or unexpected ER_DUP_KEY Fix two issues: 1. Rdb_ddl_manager::rename() loses the value of m_hidden_pk_val. new object used to get 0, which means "not loaded from the db yet". 2. ha_rocksdb::load_hidden_pk_value() uses current transaction (and its snapshot) when loading hidden PK value from disk. This may cause it to load an out-of-date value. --- storage/rocksdb/ha_rocksdb.cc | 23 +++++++++----- .../rocksdb/r/allow_no_primary_key.result | 31 +++++++++++++++++++ .../rocksdb/t/allow_no_primary_key.test | 28 +++++++++++++++++ storage/rocksdb/rdb_datadic.cc | 3 ++ 4 files changed, 77 insertions(+), 8 deletions(-) diff --git a/storage/rocksdb/ha_rocksdb.cc b/storage/rocksdb/ha_rocksdb.cc index a637a9b0525..96bc7dad3e6 100644 --- a/storage/rocksdb/ha_rocksdb.cc +++ b/storage/rocksdb/ha_rocksdb.cc @@ -5235,8 +5235,17 @@ int ha_rocksdb::load_hidden_pk_value() { active_index = m_tbl_def->m_key_count - 1; const uint8 save_table_status = table->status; - Rdb_transaction *const tx = get_or_create_tx(table->in_use); - const bool is_new_snapshot = !tx->has_snapshot(); + /* + We should read the latest committed value in the database. + That is, if we have an open transaction with a snapshot, we should not use + it as we may get old data. Start a new transaction to read the latest + value. + */ + Rdb_transaction *const temp_tx = new Rdb_transaction_impl(table->in_use); + temp_tx->start_tx(); + Rdb_transaction *&tx = get_tx_from_thd(table->in_use); + Rdb_transaction *save_tx= tx; + tx= temp_tx; longlong hidden_pk_id = 1; // Do a lookup. @@ -5246,9 +5255,8 @@ int ha_rocksdb::load_hidden_pk_value() { */ auto err = read_hidden_pk_id_from_rowkey(&hidden_pk_id); if (err) { - if (is_new_snapshot) { - tx->release_snapshot(); - } + delete tx; + tx= save_tx; return err; } @@ -5260,9 +5268,8 @@ int ha_rocksdb::load_hidden_pk_value() { !m_tbl_def->m_hidden_pk_val.compare_exchange_weak(old, hidden_pk_id)) { } - if (is_new_snapshot) { - tx->release_snapshot(); - } + delete tx; + tx= save_tx; table->status = save_table_status; active_index = save_active_index; diff --git a/storage/rocksdb/mysql-test/rocksdb/r/allow_no_primary_key.result b/storage/rocksdb/mysql-test/rocksdb/r/allow_no_primary_key.result index 5bffab74917..a8d5c07072c 100644 --- a/storage/rocksdb/mysql-test/rocksdb/r/allow_no_primary_key.result +++ b/storage/rocksdb/mysql-test/rocksdb/r/allow_no_primary_key.result @@ -262,3 +262,34 @@ SELECT * FROM t1; a b 36 foo DROP TABLE t1; +# +# Issue #834/MDEV-15304 ALTER TABLE table_with_hidden_pk causes Can't +# write; duplicate key in table error and/or crash +# +CREATE TABLE t1 (a INT, KEY(a)) ENGINE=RocksDB; +INSERT INTO t1 VALUES (1),(1+1); +create table t2 (a int); +insert into t2 values (10),(20),(30); +BEGIN; +select * from t2; +a +10 +20 +30 +connect con1,localhost,root,,; +connection con1; +alter table t1 force; +connection default; +select * from t1; +a +connection con1; +insert into t1 values (100); +select * from t1; +a +1 +2 +100 +disconnect con1; +connection default; +rollback; +drop table t1,t2; diff --git a/storage/rocksdb/mysql-test/rocksdb/t/allow_no_primary_key.test b/storage/rocksdb/mysql-test/rocksdb/t/allow_no_primary_key.test index 2a064dc3b00..5f2a37f235a 100644 --- a/storage/rocksdb/mysql-test/rocksdb/t/allow_no_primary_key.test +++ b/storage/rocksdb/mysql-test/rocksdb/t/allow_no_primary_key.test @@ -96,3 +96,31 @@ DELETE FROM t1 WHERE a = 35 AND b = 'foo'; --sorted_result SELECT * FROM t1; DROP TABLE t1; + +--echo # +--echo # Issue #834/MDEV-15304 ALTER TABLE table_with_hidden_pk causes Can't +--echo # write; duplicate key in table error and/or crash +--echo # +CREATE TABLE t1 (a INT, KEY(a)) ENGINE=RocksDB; +INSERT INTO t1 VALUES (1),(1+1); +create table t2 (a int); +insert into t2 values (10),(20),(30); + +BEGIN; +select * from t2; + +connect (con1,localhost,root,,); +connection con1; +alter table t1 force; + +connection default; +select * from t1; + +connection con1; +insert into t1 values (100); +select * from t1; + +disconnect con1; +connection default; +rollback; +drop table t1,t2; diff --git a/storage/rocksdb/rdb_datadic.cc b/storage/rocksdb/rdb_datadic.cc index a38711e6c6b..33c30ebb71a 100644 --- a/storage/rocksdb/rdb_datadic.cc +++ b/storage/rocksdb/rdb_datadic.cc @@ -4271,6 +4271,9 @@ bool Rdb_ddl_manager::rename(const std::string &from, const std::string &to, rec->m_auto_incr_val.load(std::memory_order_relaxed); new_rec->m_key_descr_arr = rec->m_key_descr_arr; + new_rec->m_hidden_pk_val = + rec->m_hidden_pk_val.load(std::memory_order_relaxed); + // so that it's not free'd when deleting the old rec rec->m_key_descr_arr = nullptr; From f76a17e355f4ee031f3cabbbd679643d85347834 Mon Sep 17 00:00:00 2001 From: Jacob Mathew Date: Fri, 18 May 2018 11:14:26 -0700 Subject: [PATCH 15/25] MDEV-7914: spider/bg.ha, spider/bg.ha_part crash server sporadically in buildbot The crash occurs when a thread that is closing its connection attempts to access Spider transaction information when another thread has freed that memory while processing Spider plugin deinit. This occurs because Spider does not adjust the plugin's reference count when it sets a transaction information pointer for the plugin. The fix I implemented changes the way Spider sets the transaction information pointer to use thd_set_ha_data() so that Spider's plugin reference counter is adjusted as well. Author: Jacob Mathew. Reviewer: Kentoku Shiba. Merged From: Commit ab9d420 on branch 10.2 --- storage/spider/ha_spider.cc | 2 +- storage/spider/spd_malloc.h | 2 +- storage/spider/spd_table.cc | 66 +++++++++++++++++++++++++++++-------- storage/spider/spd_trx.cc | 42 +++++++++++------------ 4 files changed, 76 insertions(+), 36 deletions(-) diff --git a/storage/spider/ha_spider.cc b/storage/spider/ha_spider.cc index 7d2924ce872..c559f562e98 100644 --- a/storage/spider/ha_spider.cc +++ b/storage/spider/ha_spider.cc @@ -712,7 +712,7 @@ int ha_spider::close() } } - if (!thd || !*thd_ha_data(thd, spider_hton_ptr)) + if (!thd || !thd_get_ha_data(thd, spider_hton_ptr)) { for (roop_count = 0; roop_count < (int) share->link_count; roop_count++) conns[roop_count] = NULL; diff --git a/storage/spider/spd_malloc.h b/storage/spider/spd_malloc.h index 3c5c6e67c2a..697595edeb6 100644 --- a/storage/spider/spd_malloc.h +++ b/storage/spider/spd_malloc.h @@ -19,7 +19,7 @@ #define spider_bulk_malloc(A,B,C,...) \ spider_bulk_alloc_mem(A,B,__func__,__FILE__,__LINE__,C,__VA_ARGS__) #define spider_current_trx \ - (current_thd ? ((SPIDER_TRX *) *thd_ha_data(current_thd, spider_hton_ptr)) : NULL) + (current_thd ? ((SPIDER_TRX *) thd_get_ha_data(current_thd, spider_hton_ptr)) : NULL) #define init_calc_mem(A) init_mem_calc(A,__func__,__FILE__,__LINE__) diff --git a/storage/spider/spd_table.cc b/storage/spider/spd_table.cc index 94d9f2257e1..2f666fef2f4 100644 --- a/storage/spider/spd_table.cc +++ b/storage/spider/spd_table.cc @@ -41,6 +41,27 @@ #include "spd_direct_sql.h" #include "spd_malloc.h" +inline MYSQL_THD spider_create_thd() +{ + THD *thd; + my_thread_init(); + if (!(thd = new THD())) + my_thread_end(); + else + { +#ifdef HAVE_PSI_INTERFACE + mysql_thread_set_psi_id(thd->thread_id); +#endif + thd->thread_stack = (char *) &thd; + thd->store_globals(); + } + return thd; +} +inline void spider_destroy_thd(MYSQL_THD thd) +{ + delete thd; +} + ulong *spd_db_att_thread_id; #ifdef SPIDER_XID_USES_xid_cache_iterate #else @@ -5994,7 +6015,7 @@ int spider_close_connection( SPIDER_CONN *conn; SPIDER_TRX *trx; DBUG_ENTER("spider_close_connection"); - if (!(trx = (SPIDER_TRX*) *thd_ha_data(thd, spider_hton_ptr))) + if (!(trx = (SPIDER_TRX*) thd_get_ha_data(thd, spider_hton_ptr))) DBUG_RETURN(0); /* transaction is not started */ trx->tmp_spider->conns = &conn; @@ -6049,6 +6070,7 @@ int spider_db_done( void *p ) { int roop_count; + bool do_delete_thd; THD *thd = current_thd, *tmp_thd; SPIDER_CONN *conn; SPIDER_INIT_ERROR_TABLE *spider_init_error_table; @@ -6056,6 +6078,18 @@ int spider_db_done( SPIDER_LGTM_TBLHND_SHARE *lgtm_tblhnd_share; DBUG_ENTER("spider_db_done"); + /* Begin Spider plugin deinit */ + if (thd) + do_delete_thd = FALSE; + else + { + /* Create a thread for Spider plugin deinit */ + thd = spider_create_thd(); + if (!thd) + DBUG_RETURN(HA_ERR_OUT_OF_MEM); + do_delete_thd = TRUE; + } + #ifndef WITHOUT_SPIDER_BG_SEARCH spider_free_trx(spider_global_trx, TRUE); #endif @@ -6098,21 +6132,22 @@ int spider_db_done( pthread_mutex_destroy(&spider_udf_table_mon_mutexes[roop_count]); spider_free(NULL, spider_udf_table_mon_mutexes, MYF(0)); - if (thd && thd_sql_command(thd) == SQLCOM_UNINSTALL_PLUGIN) { - pthread_mutex_lock(&spider_allocated_thds_mutex); - while ((tmp_thd = (THD *) my_hash_element(&spider_allocated_thds, 0))) + pthread_mutex_lock(&spider_allocated_thds_mutex); + while ((tmp_thd = (THD *) my_hash_element(&spider_allocated_thds, 0))) + { + SPIDER_TRX *trx = (SPIDER_TRX *) + thd_get_ha_data(tmp_thd, spider_hton_ptr); + if (trx) { - SPIDER_TRX *trx = (SPIDER_TRX *) *thd_ha_data(tmp_thd, spider_hton_ptr); - if (trx) - { - DBUG_ASSERT(tmp_thd == trx->thd); - spider_free_trx(trx, FALSE); - *thd_ha_data(tmp_thd, spider_hton_ptr) = (void *) NULL; - } else - my_hash_delete(&spider_allocated_thds, (uchar *) tmp_thd); + DBUG_ASSERT(tmp_thd == trx->thd); + spider_free_trx(trx, FALSE); + thd_set_ha_data(tmp_thd, spider_hton_ptr, NULL); } - pthread_mutex_unlock(&spider_allocated_thds_mutex); + else + my_hash_delete(&spider_allocated_thds, (uchar *) tmp_thd); } + pthread_mutex_unlock(&spider_allocated_thds_mutex); + #if defined(HS_HAS_SQLCOM) && defined(HAVE_HANDLERSOCKET) pthread_mutex_lock(&spider_hs_w_conn_mutex); while ((conn = (SPIDER_CONN*) my_hash_element(&spider_hs_w_conn_hash, 0))) @@ -6261,6 +6296,11 @@ int spider_db_done( spider_current_alloc_mem[roop_count] ? "NG" : "OK" )); } + + /* End Spider plugin deinit */ + if (do_delete_thd) + spider_destroy_thd(thd); + /* DBUG_ASSERT(0); */ diff --git a/storage/spider/spd_trx.cc b/storage/spider/spd_trx.cc index 26c9662e084..f6bf39b813e 100644 --- a/storage/spider/spd_trx.cc +++ b/storage/spider/spd_trx.cc @@ -1147,7 +1147,7 @@ SPIDER_TRX *spider_get_trx( if ( !thd || - !(trx = (SPIDER_TRX*) *thd_ha_data(thd, spider_hton_ptr)) + !(trx = (SPIDER_TRX*) thd_get_ha_data(thd, spider_hton_ptr)) ) { DBUG_PRINT("info",("spider create new trx")); if (!(trx = (SPIDER_TRX *) @@ -1185,7 +1185,7 @@ SPIDER_TRX *spider_get_trx( goto error_init_hash; spider_alloc_calc_mem_init(trx->trx_conn_hash, 151); spider_alloc_calc_mem( - thd ? ((SPIDER_TRX *) *thd_ha_data(thd, spider_hton_ptr)) : NULL, + thd ? ((SPIDER_TRX *) thd_get_ha_data(thd, spider_hton_ptr)) : NULL, trx->trx_conn_hash, trx->trx_conn_hash.array.max_element * trx->trx_conn_hash.array.size_of_element); @@ -1197,7 +1197,7 @@ SPIDER_TRX *spider_get_trx( goto error_init_another_hash; spider_alloc_calc_mem_init(trx->trx_another_conn_hash, 152); spider_alloc_calc_mem( - thd ? ((SPIDER_TRX *) *thd_ha_data(thd, spider_hton_ptr)) : NULL, + thd ? ((SPIDER_TRX *) thd_get_ha_data(thd, spider_hton_ptr)) : NULL, trx->trx_another_conn_hash, trx->trx_another_conn_hash.array.max_element * trx->trx_another_conn_hash.array.size_of_element); @@ -1210,7 +1210,7 @@ SPIDER_TRX *spider_get_trx( goto error_hs_r_init_hash; spider_alloc_calc_mem_init(trx->trx_hs_r_conn_hash, 153); spider_alloc_calc_mem( - thd ? ((SPIDER_TRX *) *thd_ha_data(thd, spider_hton_ptr)) : NULL, + thd ? ((SPIDER_TRX *) thd_get_ha_data(thd, spider_hton_ptr)) : NULL, trx->trx_hs_r_conn_hash, trx->trx_hs_r_conn_hash.array.max_element * trx->trx_hs_r_conn_hash.array.size_of_element); @@ -1222,7 +1222,7 @@ SPIDER_TRX *spider_get_trx( goto error_hs_w_init_hash; spider_alloc_calc_mem_init(trx->trx_hs_w_conn_hash, 154); spider_alloc_calc_mem( - thd ? ((SPIDER_TRX *) *thd_ha_data(thd, spider_hton_ptr)) : NULL, + thd ? ((SPIDER_TRX *) thd_get_ha_data(thd, spider_hton_ptr)) : NULL, trx->trx_hs_w_conn_hash, trx->trx_hs_w_conn_hash.array.max_element * trx->trx_hs_w_conn_hash.array.size_of_element); @@ -1236,7 +1236,7 @@ SPIDER_TRX *spider_get_trx( goto error_direct_hs_r_init_hash; spider_alloc_calc_mem_init(trx->trx_direct_hs_r_conn_hash, 155); spider_alloc_calc_mem( - thd ? ((SPIDER_TRX *) *thd_ha_data(thd, spider_hton_ptr)) : NULL, + thd ? ((SPIDER_TRX *) thd_get_ha_data(thd, spider_hton_ptr)) : NULL, trx->trx_direct_hs_r_conn_hash, trx->trx_direct_hs_r_conn_hash.array.max_element * trx->trx_direct_hs_r_conn_hash.array.size_of_element); @@ -1248,7 +1248,7 @@ SPIDER_TRX *spider_get_trx( goto error_direct_hs_w_init_hash; spider_alloc_calc_mem_init(trx->trx_direct_hs_w_conn_hash, 156); spider_alloc_calc_mem( - thd ? ((SPIDER_TRX *) *thd_ha_data(thd, spider_hton_ptr)) : NULL, + thd ? ((SPIDER_TRX *) thd_get_ha_data(thd, spider_hton_ptr)) : NULL, trx->trx_direct_hs_w_conn_hash, trx->trx_direct_hs_w_conn_hash.array.max_element * trx->trx_direct_hs_w_conn_hash.array.size_of_element); @@ -1261,7 +1261,7 @@ SPIDER_TRX *spider_get_trx( goto error_init_alter_hash; spider_alloc_calc_mem_init(trx->trx_alter_table_hash, 157); spider_alloc_calc_mem( - thd ? ((SPIDER_TRX *) *thd_ha_data(thd, spider_hton_ptr)) : NULL, + thd ? ((SPIDER_TRX *) thd_get_ha_data(thd, spider_hton_ptr)) : NULL, trx->trx_alter_table_hash, trx->trx_alter_table_hash.array.max_element * trx->trx_alter_table_hash.array.size_of_element); @@ -1273,7 +1273,7 @@ SPIDER_TRX *spider_get_trx( goto error_init_trx_ha_hash; spider_alloc_calc_mem_init(trx->trx_ha_hash, 158); spider_alloc_calc_mem( - thd ? ((SPIDER_TRX *) *thd_ha_data(thd, spider_hton_ptr)) : NULL, + thd ? ((SPIDER_TRX *) thd_get_ha_data(thd, spider_hton_ptr)) : NULL, trx->trx_ha_hash, trx->trx_ha_hash.array.max_element * trx->trx_ha_hash.array.size_of_element); @@ -1395,7 +1395,7 @@ SPIDER_TRX *spider_get_trx( pthread_mutex_unlock(&spider_allocated_thds_mutex); trx->registed_allocated_thds = TRUE; } - *thd_ha_data(thd, spider_hton_ptr) = (void *) trx; + thd_set_ha_data(thd, spider_hton_ptr, trx); } } @@ -1441,7 +1441,7 @@ error_set_connect_info_default: my_hash_free(&trx->trx_ha_hash); error_init_trx_ha_hash: spider_free_mem_calc( - thd ? ((SPIDER_TRX *) *thd_ha_data(thd, spider_hton_ptr)) : NULL, + thd ? ((SPIDER_TRX *) thd_get_ha_data(thd, spider_hton_ptr)) : NULL, trx->trx_alter_table_hash_id, trx->trx_alter_table_hash.array.max_element * trx->trx_alter_table_hash.array.size_of_element); @@ -1449,14 +1449,14 @@ error_init_trx_ha_hash: error_init_alter_hash: #if defined(HS_HAS_SQLCOM) && defined(HAVE_HANDLERSOCKET) spider_free_mem_calc( - thd ? ((SPIDER_TRX *) *thd_ha_data(thd, spider_hton_ptr)) : NULL, + thd ? ((SPIDER_TRX *) thd_get_ha_data(thd, spider_hton_ptr)) : NULL, trx->trx_direct_hs_w_conn_hash_id, trx->trx_direct_hs_w_conn_hash.array.max_element * trx->trx_direct_hs_w_conn_hash.array.size_of_element); my_hash_free(&trx->trx_direct_hs_w_conn_hash); error_direct_hs_w_init_hash: spider_free_mem_calc( - thd ? ((SPIDER_TRX *) *thd_ha_data(thd, spider_hton_ptr)) : NULL, + thd ? ((SPIDER_TRX *) thd_get_ha_data(thd, spider_hton_ptr)) : NULL, trx->trx_direct_hs_r_conn_hash_id, trx->trx_direct_hs_r_conn_hash.array.max_element * trx->trx_direct_hs_r_conn_hash.array.size_of_element); @@ -1465,14 +1465,14 @@ error_direct_hs_r_init_hash: #endif #if defined(HS_HAS_SQLCOM) && defined(HAVE_HANDLERSOCKET) spider_free_mem_calc( - thd ? ((SPIDER_TRX *) *thd_ha_data(thd, spider_hton_ptr)) : NULL, + thd ? ((SPIDER_TRX *) thd_get_ha_data(thd, spider_hton_ptr)) : NULL, trx->trx_hs_w_conn_hash_id, trx->trx_hs_w_conn_hash.array.max_element * trx->trx_hs_w_conn_hash.array.size_of_element); my_hash_free(&trx->trx_hs_w_conn_hash); error_hs_w_init_hash: spider_free_mem_calc( - thd ? ((SPIDER_TRX *) *thd_ha_data(thd, spider_hton_ptr)) : NULL, + thd ? ((SPIDER_TRX *) thd_get_ha_data(thd, spider_hton_ptr)) : NULL, trx->trx_hs_r_conn_hash_id, trx->trx_hs_r_conn_hash.array.max_element * trx->trx_hs_r_conn_hash.array.size_of_element); @@ -1480,14 +1480,14 @@ error_hs_w_init_hash: error_hs_r_init_hash: #endif spider_free_mem_calc( - thd ? ((SPIDER_TRX *) *thd_ha_data(thd, spider_hton_ptr)) : NULL, + thd ? ((SPIDER_TRX *) thd_get_ha_data(thd, spider_hton_ptr)) : NULL, trx->trx_another_conn_hash_id, trx->trx_another_conn_hash.array.max_element * trx->trx_another_conn_hash.array.size_of_element); my_hash_free(&trx->trx_another_conn_hash); error_init_another_hash: spider_free_mem_calc( - thd ? ((SPIDER_TRX *) *thd_ha_data(thd, spider_hton_ptr)) : NULL, + thd ? ((SPIDER_TRX *) thd_get_ha_data(thd, spider_hton_ptr)) : NULL, trx->trx_conn_hash_id, trx->trx_conn_hash.array.max_element * trx->trx_conn_hash.array.size_of_element); @@ -1526,7 +1526,7 @@ int spider_free_trx( if (need_lock) pthread_mutex_unlock(&spider_allocated_thds_mutex); } - *thd_ha_data(trx->thd, spider_hton_ptr) = (void *) NULL; + thd_set_ha_data(trx->thd, spider_hton_ptr, NULL); } spider_free_trx_alloc(trx); spider_merge_mem_calc(trx, TRUE); @@ -3298,7 +3298,7 @@ int spider_commit( SPIDER_CONN *conn; DBUG_ENTER("spider_commit"); - if (!(trx = (SPIDER_TRX*) *thd_ha_data(thd, spider_hton_ptr))) + if (!(trx = (SPIDER_TRX*) thd_get_ha_data(thd, spider_hton_ptr))) DBUG_RETURN(0); /* transaction is not started */ #ifdef HA_CAN_BULK_ACCESS @@ -3388,7 +3388,7 @@ int spider_rollback( SPIDER_CONN *conn; DBUG_ENTER("spider_rollback"); - if (!(trx = (SPIDER_TRX*) *thd_ha_data(thd, spider_hton_ptr))) + if (!(trx = (SPIDER_TRX*) thd_get_ha_data(thd, spider_hton_ptr))) DBUG_RETURN(0); /* transaction is not started */ #ifdef HA_CAN_BULK_ACCESS @@ -3463,7 +3463,7 @@ int spider_xa_prepare( if (all || (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) { - if (!(trx = (SPIDER_TRX*) *thd_ha_data(thd, spider_hton_ptr))) + if (!(trx = (SPIDER_TRX*) thd_get_ha_data(thd, spider_hton_ptr))) DBUG_RETURN(0); /* transaction is not started */ DBUG_PRINT("info",("spider trx_start=%s", From 27a7365f42ce0184a004e09b3bb1cadb868c8f64 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Fri, 18 May 2018 00:23:15 +0100 Subject: [PATCH 16/25] MDEV-16220 MTR - do not pass UTF8 on the command line for mysql client. It should work ok on all Unixes, but on Windows ,only worked by accident in the past, with client not being Unicode safe. It stopped working with Visual Studio 2017 15.7 update now. --- mysql-test/r/grant.result | 5 ---- mysql-test/r/grant_not_windows.result | 7 +++++ mysql-test/t/grant.test | 8 ----- mysql-test/t/grant_not_windows.test | 13 +++++++++ mysql-test/t/mysql.test | 16 +++++++--- mysql-test/t/mysql_cp932.test | 42 +++++++++++++++++++++++---- 6 files changed, 68 insertions(+), 23 deletions(-) create mode 100644 mysql-test/r/grant_not_windows.result create mode 100644 mysql-test/t/grant_not_windows.test diff --git a/mysql-test/r/grant.result b/mysql-test/r/grant.result index 94087393489..66cf6d35758 100644 --- a/mysql-test/r/grant.result +++ b/mysql-test/r/grant.result @@ -1647,11 +1647,6 @@ drop user mysqluser11@localhost; drop database mysqltest1; End of 5.0 tests set names utf8; -grant select on test.* to юзер_юзер@localhost; -user() -юзер_юзер@localhost -revoke all on test.* from юзер_юзер@localhost; -drop user юзер_юзер@localhost; grant select on test.* to очень_длинный_юзер@localhost; ERROR HY000: String 'очень_длинный_юзер' is too long for user name (should be no longer than 16) set names default; diff --git a/mysql-test/r/grant_not_windows.result b/mysql-test/r/grant_not_windows.result new file mode 100644 index 00000000000..5cf0c1deb32 --- /dev/null +++ b/mysql-test/r/grant_not_windows.result @@ -0,0 +1,7 @@ +set names utf8; +grant select on test.* to юзер_юзер@localhost; +user() +юзер_юзер@localhost +revoke all on test.* from юзер_юзер@localhost; +drop user юзер_юзер@localhost; +set names default; diff --git a/mysql-test/t/grant.test b/mysql-test/t/grant.test index efa79c5b768..2a8961e46a9 100644 --- a/mysql-test/t/grant.test +++ b/mysql-test/t/grant.test @@ -1574,15 +1574,7 @@ drop database mysqltest1; --echo End of 5.0 tests - -# -# Bug#21432 Database/Table name limited to 64 bytes, not chars, problems with multi-byte -# set names utf8; -grant select on test.* to юзер_юзер@localhost; ---exec $MYSQL --default-character-set=utf8 --user=юзер_юзер -e "select user()" -revoke all on test.* from юзер_юзер@localhost; -drop user юзер_юзер@localhost; --error ER_WRONG_STRING_LENGTH grant select on test.* to очень_длинный_юзер@localhost; set names default; diff --git a/mysql-test/t/grant_not_windows.test b/mysql-test/t/grant_not_windows.test new file mode 100644 index 00000000000..575516c409b --- /dev/null +++ b/mysql-test/t/grant_not_windows.test @@ -0,0 +1,13 @@ + # UTF8 parameters to mysql client do not work on Windows +--source include/not_windows.inc +--source include/not_embedded.inc + +# +# Bug#21432 Database/Table name limited to 64 bytes, not chars, problems with multi-byte +# +set names utf8; +grant select on test.* to юзер_юзер@localhost; +--exec $MYSQL --default-character-set=utf8 --user=юзер_юзер -e "select user()" +revoke all on test.* from юзер_юзер@localhost; +drop user юзер_юзер@localhost; +set names default; diff --git a/mysql-test/t/mysql.test b/mysql-test/t/mysql.test index dd964c46420..87756768c7f 100644 --- a/mysql-test/t/mysql.test +++ b/mysql-test/t/mysql.test @@ -51,14 +51,22 @@ drop table t1; # # Bug#17939 Wrong table format when using UTF8 strings -# ---exec $MYSQL --default-character-set=utf8 --table -e "SELECT 'John Doe' as '__tañgè Ñãmé'" 2>&1 ---exec $MYSQL --default-character-set=utf8 --table -e "SELECT '__tañgè Ñãmé' as 'John Doe'" 2>&1 +write_file $MYSQL_TMP_DIR/mysql_in; +SELECT 'John Doe' as '__tañgè Ñãmé'; +SELECT '__tañgè Ñãmé' as 'John Doe'; +EOF +--exec $MYSQL --default-character-set=utf8 --table < $MYSQL_TMP_DIR/mysql_in 2>&1 +remove_file $MYSQL_TMP_DIR/mysql_in; # # Bug#18265 -- mysql client: No longer right-justifies numeric columns # ---exec $MYSQL -t --default-character-set utf8 test -e "create table t1 (i int, j int, k char(25) charset utf8); insert into t1 (i) values (1); insert into t1 (k) values ('<----------------------->'); insert into t1 (k) values ('<-----'); insert into t1 (k) values ('Τη γλώσσα'); insert into t1 (k) values ('ᛖᚴ ᚷᛖᛏ'); select * from t1; DROP TABLE t1;" +write_file $MYSQL_TMP_DIR/mysql_in; +create table t1 (i int, j int, k char(25) charset utf8); insert into t1 (i) values (1); insert into t1 (k) values ('<----------------------->'); insert into t1 (k) values ('<-----'); insert into t1 (k) values ('Τη γλώσσα'); insert into t1 (k) values ('ᛖᚴ ᚷᛖᛏ'); select * from t1; DROP TABLE t1; +EOF +--exec $MYSQL -t --default-character-set utf8 test < $MYSQL_TMP_DIR/mysql_in +remove_file $MYSQL_TMP_DIR/mysql_in; + # # "DESCRIBE" commands may return strange NULLness flags. diff --git a/mysql-test/t/mysql_cp932.test b/mysql-test/t/mysql_cp932.test index 60a129c3805..8fba5750d89 100644 --- a/mysql-test/t/mysql_cp932.test +++ b/mysql-test/t/mysql_cp932.test @@ -10,13 +10,43 @@ # BUG#16217 - MySQL client misinterprets multi-byte char as escape `\' # +let $mysql_in= $MYSQL_TMP_DIR/mysql_in; + # new command \C or charset ---exec $MYSQL --default-character-set=utf8 test -e "\C cp932 \g" ---exec $MYSQL --default-character-set=cp932 test -e "charset utf8;" +write_file $mysql_in; +\C cp932 \g +EOF +--exec $MYSQL --default-character-set=utf8 test < $mysql_in +remove_file $mysql_in; + +write_file $mysql_in; +charset utf8; +EOF +--exec $MYSQL --default-character-set=cp932 test < $mysql_in +remove_file $mysql_in; # its usage to switch internally in mysql to requested charset ---exec $MYSQL --default-character-set=utf8 test -e "charset cp932; select '\'; create table t1 (c_cp932 TEXT CHARACTER SET cp932); insert into t1 values('\'); select * from t1; drop table t1;" ---exec $MYSQL --default-character-set=utf8 test -e "charset cp932; select '\'" ---exec $MYSQL --default-character-set=utf8 test -e "/*charset cp932 */; set character_set_client= cp932; select '\'" ---exec $MYSQL --default-character-set=utf8 test -e "/*!\C cp932 */; set character_set_client= cp932; select '\'" +write_file $mysql_in; +charset cp932; select '\'; create table t1 (c_cp932 TEXT CHARACTER SET cp932); insert into t1 values('\'); select * from t1; drop table t1; +EOF +--exec $MYSQL --default-character-set=utf8 test < $mysql_in +remove_file $mysql_in; + +write_file $mysql_in; +charset cp932; select '\' +EOF +--exec $MYSQL --default-character-set=utf8 test < $mysql_in +remove_file $mysql_in; + +write_file $mysql_in; +/*charset cp932 */; set character_set_client= cp932; select '\' +EOF +--exec $MYSQL --default-character-set=utf8 test < $mysql_in +remove_file $mysql_in; + +write_file $mysql_in; +/*!\C cp932 */; set character_set_client= cp932; select '\' +EOF +--exec $MYSQL --default-character-set=utf8 test < $mysql_in +remove_file $mysql_in; From 06aaaef51a90cf21f9361ca6901cfc1ab854e5b9 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Fri, 18 May 2018 23:58:24 +0300 Subject: [PATCH 17/25] MDEV-16200: -DPLUGIN_ROCKSDB=YES leads to errors during build Mark the plugin as dynamic-only. --- storage/rocksdb/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/rocksdb/CMakeLists.txt b/storage/rocksdb/CMakeLists.txt index 7156150b042..2821b74c2fa 100644 --- a/storage/rocksdb/CMakeLists.txt +++ b/storage/rocksdb/CMakeLists.txt @@ -104,7 +104,7 @@ SET(ROCKSDB_SE_SOURCES #ADD_DEFINITIONS(-DROCKSDB_PLATFORM_POSIX -DROCKSDB_LIB_IO_POSIX #) -MYSQL_ADD_PLUGIN(rocksdb ${ROCKSDB_SE_SOURCES} STORAGE_ENGINE +MYSQL_ADD_PLUGIN(rocksdb ${ROCKSDB_SE_SOURCES} MODULE_ONLY STORAGE_ENGINE MODULE_OUTPUT_NAME ha_rocksdb COMPONENT rocksdb-engine) From dd51082eca82fe7b61ee2e62f75b84c39f180450 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Sat, 19 May 2018 00:26:35 +0300 Subject: [PATCH 18/25] MDEV-12465: Server crashes in my_scan_weight_utf8_bin upon collecting stats for RocksDB table Apply patch by Oleksandr Byelkin: Do not use "only index read" in analyzing indices if there is a field which present in the index only partially. --- sql/sql_statistics.cc | 14 ++++++++-- .../mysql-test/rocksdb/r/analyze_table.result | 26 +++++++++++++++++++ .../mysql-test/rocksdb/t/analyze_table.test | 26 +++++++++++++++++++ 3 files changed, 64 insertions(+), 2 deletions(-) diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc index 01947462cce..903ebb91d01 100644 --- a/sql/sql_statistics.cc +++ b/sql/sql_statistics.cc @@ -1801,6 +1801,7 @@ private: public: bool is_single_comp_pk; + bool is_partial_fields_present; Index_prefix_calc(THD *thd, TABLE *table, KEY *key_info) : index_table(table), index_info(key_info) @@ -1812,7 +1813,7 @@ public: prefixes= 0; LINT_INIT_STRUCT(calc_state); - is_single_comp_pk= FALSE; + is_partial_fields_present= is_single_comp_pk= FALSE; uint pk= table->s->primary_key; if ((uint) (table->key_info - key_info) == pk && table->key_info[pk].user_defined_key_parts == 1) @@ -1834,7 +1835,10 @@ public: calculating the values of 'avg_frequency' for prefixes. */ if (!key_info->key_part[i].field->part_of_key.is_set(keyno)) + { + is_partial_fields_present= TRUE; break; + } if (!(state->last_prefix= new (thd->mem_root) Cached_item_field(thd, @@ -2633,7 +2637,13 @@ int collect_statistics_for_index(THD *thd, TABLE *table, uint index) DBUG_RETURN(rc); } - table->file->ha_start_keyread(index); + /* + Request "only index read" in case of absence of fields which are + partially in the index to avoid problems with partitioning (for example) + which want to get whole field value. + */ + if (!index_prefix_calc.is_partial_fields_present) + table->file->ha_start_keyread(index); table->file->ha_index_init(index, TRUE); rc= table->file->ha_index_first(table->record[0]); while (rc != HA_ERR_END_OF_FILE) diff --git a/storage/rocksdb/mysql-test/rocksdb/r/analyze_table.result b/storage/rocksdb/mysql-test/rocksdb/r/analyze_table.result index ff2973230db..b666a17c81c 100644 --- a/storage/rocksdb/mysql-test/rocksdb/r/analyze_table.result +++ b/storage/rocksdb/mysql-test/rocksdb/r/analyze_table.result @@ -27,3 +27,29 @@ ANALYZE TABLE t1; Table Op Msg_type Msg_text test.t1 analyze status OK DROP TABLE t1; +# +# MDEV-12465: Server crashes in my_scan_weight_utf8_bin upon +# collecting stats for RocksDB table +# +CREATE TABLE t1 ( +pk INT, +f1 CHAR(255), +f2 TEXT, +f3 VARCHAR(255), +f4 TEXT, +PRIMARY KEY (pk), +KEY (f4(255)) +) ENGINE=RocksDB +CHARSET utf8 +COLLATE utf8_bin +PARTITION BY KEY (pk) PARTITIONS 2; +INSERT INTO t1 VALUES +(1,'foo','bar','foo','bar'), (2,'bar','foo','bar','foo'); +ANALYZE TABLE t1 PERSISTENT FOR ALL; +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze Warning Engine-independent statistics are not collected for column 'f2' +test.t1 analyze Warning Engine-independent statistics are not collected for column 'f4' +test.t1 analyze status OK +drop table t1; +# End of 10.2 tests diff --git a/storage/rocksdb/mysql-test/rocksdb/t/analyze_table.test b/storage/rocksdb/mysql-test/rocksdb/t/analyze_table.test index 10722194121..b24398b1fe2 100644 --- a/storage/rocksdb/mysql-test/rocksdb/t/analyze_table.test +++ b/storage/rocksdb/mysql-test/rocksdb/t/analyze_table.test @@ -1,4 +1,5 @@ --source include/have_rocksdb.inc +--source include/have_partition.inc # # ANALYZE TABLE statements @@ -29,3 +30,28 @@ INSERT INTO t1 VALUES (5,8),(6,10),(7,11),(8,12); ANALYZE TABLE t1; DROP TABLE t1; +--echo # +--echo # MDEV-12465: Server crashes in my_scan_weight_utf8_bin upon +--echo # collecting stats for RocksDB table +--echo # + +CREATE TABLE t1 ( + pk INT, + f1 CHAR(255), + f2 TEXT, + f3 VARCHAR(255), + f4 TEXT, + PRIMARY KEY (pk), + KEY (f4(255)) +) ENGINE=RocksDB + CHARSET utf8 + COLLATE utf8_bin + PARTITION BY KEY (pk) PARTITIONS 2; +INSERT INTO t1 VALUES +(1,'foo','bar','foo','bar'), (2,'bar','foo','bar','foo'); + +ANALYZE TABLE t1 PERSISTENT FOR ALL; + +drop table t1; + +--echo # End of 10.2 tests From cf5226174bcb41611e9650ac04104a9b16f368be Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 19 May 2018 15:34:17 +0200 Subject: [PATCH 19/25] MDEV-11129 CREATE OR REPLACE TABLE t1 AS SELECT spfunc() crashes if spfunc() references t1 fix a typo that broke the main.view test followup for ef295c31e3d --- sql/sql_base.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_base.cc b/sql/sql_base.cc index bdde123f18c..dc61f396605 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1373,7 +1373,7 @@ retry: DBUG_RETURN(res); /* Skip if table alias does not match. */ - if (check_flag & CHECK_DUP_FOR_CREATE) + if (check_flag & CHECK_DUP_ALLOW_DIFFERENT_ALIAS) { if (my_strcasecmp(table_alias_charset, t_alias, res->alias)) continue; From 207e5ba3167f4d5d4d2e522ed7e2231204f4420f Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Sat, 19 May 2018 17:04:47 +0000 Subject: [PATCH 20/25] mariabackup : Fix race condition when killing query waiting for MDL Itcan happen that the connection is already gone during the window between quering I_S.PROCESSLIST and KILL QUERY. Fix is to tolerate ER_NO_SUCH_THREAD returned from KILL QUERY. Add small improvement in message "Killing MDL query " to actually output the query. Also do not try to kill queries that are already in Killed state. --- extra/mariabackup/backup_mysql.cc | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/extra/mariabackup/backup_mysql.cc b/extra/mariabackup/backup_mysql.cc index 3cfbf5c20fc..d287dcf181d 100644 --- a/extra/mariabackup/backup_mysql.cc +++ b/extra/mariabackup/backup_mysql.cc @@ -897,16 +897,23 @@ DECLARE_THREAD(kill_mdl_waiters_thread(void *)) break; MYSQL_RES *result = xb_mysql_query(mysql, - "SELECT ID, COMMAND FROM INFORMATION_SCHEMA.PROCESSLIST " + "SELECT ID, COMMAND, INFO FROM INFORMATION_SCHEMA.PROCESSLIST " " WHERE State='Waiting for table metadata lock'", true, true); while (MYSQL_ROW row = mysql_fetch_row(result)) { char query[64]; - msg_ts("Killing MDL waiting query '%s' on connection '%s'\n", - row[1], row[0]); + + if (row[1] && !strcmp(row[1], "Killed")) + continue; + + msg_ts("Killing MDL waiting %s ('%s') on connection %s\n", + row[1], row[2], row[0]); snprintf(query, sizeof(query), "KILL QUERY %s", row[0]); - xb_mysql_query(mysql, query, true); + if (mysql_query(mysql, query) && (mysql_errno(mysql) != ER_NO_SUCH_THREAD)) { + msg("Error: failed to execute query %s: %s\n", query,mysql_error(mysql)); + exit(EXIT_FAILURE); + } } } From 1cc67e090ebca36f04fdd6fa91e27a9c10d764d2 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 18 May 2018 19:12:35 +0200 Subject: [PATCH 21/25] MDEV-16153 Server crashes in Apc_target::disable, ASAN heap-use-after-free in Explain_query::~Explain_query upon/after EXECUTE IMMEDIATE Explain_query must be created in the execution arena. But JOIN::optimize_inner temporarily switches to the statement arena under `if (sel->first_cond_optimization)`. This might cause Explain_query to be allocated in the statement arena. Usually it is harmless (although technically incorrect and a waste of memory), but in case of EXECUTE IMMEDIATE, Prepared_statement object and its statement arena are destroyed before log_slow_statement() call, which uses Explain_query. Fix: 1. Create Explain_query before switching arenas. 2. Before filling earlier-created Explain_query with data, set thd->mem_root from the Explain_query::mem_root --- mysql-test/r/explain_slowquerylog.result | 4 ++++ mysql-test/t/explain_slowquerylog.test | 6 ++++++ sql/sql_select.cc | 17 ++++++++++++++++- 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/explain_slowquerylog.result b/mysql-test/r/explain_slowquerylog.result index 2b350cf04ff..63da82b5288 100644 --- a/mysql-test/r/explain_slowquerylog.result +++ b/mysql-test/r/explain_slowquerylog.result @@ -54,3 +54,7 @@ SELECT 1; 1 SET log_slow_rate_limit=@save1; SET long_query_time=@save2; +create table t1 (a int); +execute immediate "select * from t1 join t1 t2 on (t1.a>5) where exists (select 1)"; +a a +drop table t1; diff --git a/mysql-test/t/explain_slowquerylog.test b/mysql-test/t/explain_slowquerylog.test index 6503a326eb8..ee90fbac4e6 100644 --- a/mysql-test/t/explain_slowquerylog.test +++ b/mysql-test/t/explain_slowquerylog.test @@ -61,3 +61,9 @@ SELECT 1; SET log_slow_rate_limit=@save1; SET long_query_time=@save2; +# +# MDEV-16153 Server crashes in Apc_target::disable, ASAN heap-use-after-free in Explain_query::~Explain_query upon/after EXECUTE IMMEDIATE +# +create table t1 (a int); +execute immediate "select * from t1 join t1 t2 on (t1.a>5) where exists (select 1)"; +drop table t1; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 1d5abd6a36f..abbfd1f6ea9 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1117,10 +1117,21 @@ int JOIN::optimize() { create_explain_query_if_not_exists(thd->lex, thd->mem_root); have_query_plan= QEP_AVAILABLE; + + /* + explain data must be created on the Explain_query::mem_root. Because it's + just a memroot, not an arena, explain data must not contain any Items + */ + MEM_ROOT *old_mem_root= thd->mem_root; + Item *old_free_list __attribute__((unused))= thd->free_list; + thd->mem_root= thd->lex->explain->mem_root; save_explain_data(thd->lex->explain, false /* can overwrite */, need_tmp, !skip_sort_order && !no_order && (order || group_list), select_distinct); + thd->mem_root= old_mem_root; + DBUG_ASSERT(thd->free_list == old_free_list); // no Items were created + uint select_nr= select_lex->select_number; JOIN_TAB *curr_tab= join_tab + exec_join_tab_cnt(); for (uint i= 0; i < aggr_tables; i++, curr_tab++) @@ -1294,7 +1305,11 @@ JOIN::optimize_inner() /* The following code will allocate the new items in a permanent MEMROOT for prepared statements and stored procedures. + + But first we need to ensure that thd->lex->explain is allocated + in the execution arena */ + create_explain_query_if_not_exists(thd->lex, thd->mem_root); Query_arena *arena, backup; arena= thd->activate_stmt_arena_if_needed(&backup); @@ -24330,7 +24345,7 @@ void JOIN_TAB::save_explain_data(Explain_table_access *eta, if (filesort) { - eta->pre_join_sort= new Explain_aggr_filesort(thd->mem_root, + eta->pre_join_sort= new (thd->mem_root) Explain_aggr_filesort(thd->mem_root, thd->lex->analyze_stmt, filesort); } From 6f530c63cd90a86e3acb5e5e6bf81c6d666025eb Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 19 May 2018 09:06:04 +0200 Subject: [PATCH 22/25] cleanup: specify memroot explicitly in `new Explain_xxx` --- sql/sql_select.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index abbfd1f6ea9..72096804a24 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -24771,7 +24771,7 @@ void save_agg_explain_data(JOIN *join, Explain_select *xpl_sel) { // Each aggregate means a temp.table prev_node= node; - node= new Explain_aggr_tmp_table; + node= new (thd->mem_root) Explain_aggr_tmp_table; node->child= prev_node; if (join_tab->window_funcs_step) @@ -24791,14 +24791,14 @@ void save_agg_explain_data(JOIN *join, Explain_select *xpl_sel) if (join_tab->distinct) { prev_node= node; - node= new Explain_aggr_remove_dups; + node= new (thd->mem_root) Explain_aggr_remove_dups; node->child= prev_node; } if (join_tab->filesort) { Explain_aggr_filesort *eaf = - new Explain_aggr_filesort(thd->mem_root, is_analyze, join_tab->filesort); + new (thd->mem_root) Explain_aggr_filesort(thd->mem_root, is_analyze, join_tab->filesort); prev_node= node; node= eaf; node->child= prev_node; From 36043c58f518be7ace35bd2e2c00a8d769f9c4c5 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sun, 20 May 2018 20:26:40 +0200 Subject: [PATCH 23/25] .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index c8b6e22078d..c40a3c4800b 100644 --- a/.gitignore +++ b/.gitignore @@ -217,6 +217,8 @@ storage/tokudb/PerconaFT/tools/tokudb_load storage/tokudb/PerconaFT/tools/tokuftdump storage/tokudb/PerconaFT/tools/tokuft_logprint storage/tokudb/PerconaFT/xz/ +storage/tokudb/tokudb.cnf +storage/tokudb/tokudb.conf strings/conf_to_src support-files/MySQL-shared-compat.spec support-files/binary-configure From 31584c8bb8204b27626fae0127eff4889b8f4383 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Mon, 21 May 2018 13:43:50 +0300 Subject: [PATCH 24/25] Set MyRocks plugin version to Stable --- storage/rocksdb/ha_rocksdb.h | 2 +- .../rocksdb/r/mariadb_port_fixes.result | 26 +++++++++---------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/storage/rocksdb/ha_rocksdb.h b/storage/rocksdb/ha_rocksdb.h index 5f3d97918fe..739a2c8cdd6 100644 --- a/storage/rocksdb/ha_rocksdb.h +++ b/storage/rocksdb/ha_rocksdb.h @@ -1473,7 +1473,7 @@ private: // file name indicating RocksDB data corruption std::string rdb_corruption_marker_file_name(); -const int MYROCKS_MARIADB_PLUGIN_MATURITY_LEVEL= MariaDB_PLUGIN_MATURITY_GAMMA; +const int MYROCKS_MARIADB_PLUGIN_MATURITY_LEVEL= MariaDB_PLUGIN_MATURITY_STABLE; extern bool prevent_myrocks_loading; diff --git a/storage/rocksdb/mysql-test/rocksdb/r/mariadb_port_fixes.result b/storage/rocksdb/mysql-test/rocksdb/r/mariadb_port_fixes.result index e9fe026120a..d9e2bf5eea5 100644 --- a/storage/rocksdb/mysql-test/rocksdb/r/mariadb_port_fixes.result +++ b/storage/rocksdb/mysql-test/rocksdb/r/mariadb_port_fixes.result @@ -69,19 +69,19 @@ set global rocksdb_strict_collation_check=@tmp_rscc; # select plugin_name, plugin_maturity from information_schema.plugins where plugin_name like '%rocksdb%'; plugin_name plugin_maturity -ROCKSDB Gamma -ROCKSDB_CFSTATS Gamma -ROCKSDB_DBSTATS Gamma -ROCKSDB_PERF_CONTEXT Gamma -ROCKSDB_PERF_CONTEXT_GLOBAL Gamma -ROCKSDB_CF_OPTIONS Gamma -ROCKSDB_COMPACTION_STATS Gamma -ROCKSDB_GLOBAL_INFO Gamma -ROCKSDB_DDL Gamma -ROCKSDB_INDEX_FILE_MAP Gamma -ROCKSDB_LOCKS Gamma -ROCKSDB_TRX Gamma -ROCKSDB_DEADLOCK Gamma +ROCKSDB Stable +ROCKSDB_CFSTATS Stable +ROCKSDB_DBSTATS Stable +ROCKSDB_PERF_CONTEXT Stable +ROCKSDB_PERF_CONTEXT_GLOBAL Stable +ROCKSDB_CF_OPTIONS Stable +ROCKSDB_COMPACTION_STATS Stable +ROCKSDB_GLOBAL_INFO Stable +ROCKSDB_DDL Stable +ROCKSDB_INDEX_FILE_MAP Stable +ROCKSDB_LOCKS Stable +ROCKSDB_TRX Stable +ROCKSDB_DEADLOCK Stable # # MDEV-12466 : Assertion `thd->transaction.stmt.is_empty() || thd->in_sub_stmt || ... # From afe5a51c2df95aa282e4459afeb7f037563def92 Mon Sep 17 00:00:00 2001 From: Jacob Mathew Date: Mon, 21 May 2018 18:16:03 -0700 Subject: [PATCH 25/25] MDEV-12900: spider tests failed in buildbot with valgrind The failures with valgrind occur as a result of Spider sometimes using the wrong transaction for operations in background threads that send requests to the data nodes. The use of the wrong transaction caused the networking to the data nodes to use the wrong thread in some cases. Valgrind eventually detects this when such a thread is destroyed before it is used to disconnect from the data node by that wrong transaction when it is freed. I have fixed the problem by correcting the transaction used in each of these cases. Author: Jacob Mathew. Reviewer: Kentoku Shiba. Merged: Commit 4d576d9 on branch bb-10.3-MDEV-12900 --- storage/spider/spd_conn.cc | 29 ++++++------------------ storage/spider/spd_ping_table.cc | 22 ------------------ storage/spider/spd_table.cc | 39 -------------------------------- 3 files changed, 7 insertions(+), 83 deletions(-) diff --git a/storage/spider/spd_conn.cc b/storage/spider/spd_conn.cc index 5c96fe321bd..dda8dcefc1a 100644 --- a/storage/spider/spd_conn.cc +++ b/storage/spider/spd_conn.cc @@ -67,9 +67,6 @@ extern PSI_thread_key spd_key_thd_bg_crd; extern PSI_thread_key spd_key_thd_bg_mon; #endif #endif - -extern pthread_mutex_t spider_global_trx_mutex; -extern SPIDER_TRX *spider_global_trx; #endif HASH spider_open_connections; @@ -2799,9 +2796,6 @@ void *spider_bg_sts_action( DBUG_RETURN(NULL); } share->bg_sts_thd = thd; -/* - spider.trx = spider_global_trx; -*/ spider.trx = trx; spider.share = share; spider.conns = conns; @@ -2914,13 +2908,11 @@ void *spider_bg_sts_action( { if (!conns[spider.search_link_idx]) { - pthread_mutex_lock(&spider_global_trx_mutex); spider_get_conn(share, spider.search_link_idx, share->conn_keys[spider.search_link_idx], - spider_global_trx, &spider, FALSE, FALSE, SPIDER_CONN_KIND_MYSQL, + trx, &spider, FALSE, FALSE, SPIDER_CONN_KIND_MYSQL, &error_num); conns[spider.search_link_idx]->error_mode = 0; - pthread_mutex_unlock(&spider_global_trx_mutex); /* if ( error_num && @@ -2929,7 +2921,7 @@ void *spider_bg_sts_action( ) { lex_start(thd); error_num = spider_ping_table_mon_from_table( - spider_global_trx, + trx, thd, share, (uint32) share->monitoring_sid[spider.search_link_idx], @@ -2950,7 +2942,6 @@ void *spider_bg_sts_action( } if (spider.search_link_idx != -1 && conns[spider.search_link_idx]) { - DBUG_ASSERT(!conns[spider.search_link_idx]->thd); #ifdef WITH_PARTITION_STORAGE_ENGINE if (spider_get_sts(share, spider.search_link_idx, share->bg_sts_try_time, &spider, @@ -2971,7 +2962,7 @@ void *spider_bg_sts_action( ) { lex_start(thd); error_num = spider_ping_table_mon_from_table( - spider_global_trx, + trx, thd, share, (uint32) share->monitoring_sid[spider.search_link_idx], @@ -3181,9 +3172,6 @@ void *spider_bg_crd_action( table.s = share->table_share; table.field = share->table_share->field; table.key_info = share->table_share->key_info; -/* - spider.trx = spider_global_trx; -*/ spider.trx = trx; spider.change_table_ptr(&table, share->table_share); spider.share = share; @@ -3297,13 +3285,11 @@ void *spider_bg_crd_action( { if (!conns[spider.search_link_idx]) { - pthread_mutex_lock(&spider_global_trx_mutex); spider_get_conn(share, spider.search_link_idx, share->conn_keys[spider.search_link_idx], - spider_global_trx, &spider, FALSE, FALSE, SPIDER_CONN_KIND_MYSQL, + trx, &spider, FALSE, FALSE, SPIDER_CONN_KIND_MYSQL, &error_num); conns[spider.search_link_idx]->error_mode = 0; - pthread_mutex_unlock(&spider_global_trx_mutex); /* if ( error_num && @@ -3312,7 +3298,7 @@ void *spider_bg_crd_action( ) { lex_start(thd); error_num = spider_ping_table_mon_from_table( - spider_global_trx, + trx, thd, share, (uint32) share->monitoring_sid[spider.search_link_idx], @@ -3333,7 +3319,6 @@ void *spider_bg_crd_action( } if (spider.search_link_idx != -1 && conns[spider.search_link_idx]) { - DBUG_ASSERT(!conns[spider.search_link_idx]->thd); #ifdef WITH_PARTITION_STORAGE_ENGINE if (spider_get_crd(share, spider.search_link_idx, share->bg_crd_try_time, &spider, &table, @@ -3354,7 +3339,7 @@ void *spider_bg_crd_action( ) { lex_start(thd); error_num = spider_ping_table_mon_from_table( - spider_global_trx, + trx, thd, share, (uint32) share->monitoring_sid[spider.search_link_idx], @@ -3703,7 +3688,7 @@ void *spider_bg_mon_action( { lex_start(thd); error_num = spider_ping_table_mon_from_table( - spider_global_trx, + trx, thd, share, (uint32) share->monitoring_sid[link_idx], diff --git a/storage/spider/spd_ping_table.cc b/storage/spider/spd_ping_table.cc index 77a2969d061..6f04e08dc93 100644 --- a/storage/spider/spd_ping_table.cc +++ b/storage/spider/spd_ping_table.cc @@ -52,11 +52,6 @@ extern PSI_mutex_key spd_key_mutex_mon_list_update_status; extern PSI_mutex_key spd_key_mutex_mon_table_cache; #endif -#ifndef WITHOUT_SPIDER_BG_SEARCH -extern pthread_mutex_t spider_global_trx_mutex; -extern SPIDER_TRX *spider_global_trx; -#endif - HASH *spider_udf_table_mon_list_hash; uint spider_udf_table_mon_list_hash_id; const char *spider_udf_table_mon_list_hash_func_name; @@ -130,7 +125,6 @@ SPIDER_TABLE_MON_LIST *spider_get_ping_table_mon_list( ) #endif { - DBUG_ASSERT(trx != spider_global_trx); if ( table_mon_list && table_mon_list->mon_table_cache_version != mon_table_cache_version @@ -608,29 +602,17 @@ SPIDER_CONN *spider_get_ping_table_tgt_conn( ) { SPIDER_CONN *conn; DBUG_ENTER("spider_get_ping_table_tgt_conn"); -#ifndef WITHOUT_SPIDER_BG_SEARCH - if (trx == spider_global_trx) - pthread_mutex_lock(&spider_global_trx_mutex); -#endif if ( !(conn = spider_get_conn( share, 0, share->conn_keys[0], trx, NULL, FALSE, FALSE, SPIDER_CONN_KIND_MYSQL, error_num)) ) { -#ifndef WITHOUT_SPIDER_BG_SEARCH - if (trx == spider_global_trx) - pthread_mutex_unlock(&spider_global_trx_mutex); -#endif my_error(ER_CONNECT_TO_FOREIGN_DATA_SOURCE, MYF(0), share->server_names[0]); *error_num = ER_CONNECT_TO_FOREIGN_DATA_SOURCE; goto error; } #ifndef DBUG_OFF - if (trx == spider_global_trx) - { - DBUG_ASSERT(!conn->thd); - } DBUG_PRINT("info",("spider conn->thd=%p", conn->thd)); if (conn->thd) { @@ -638,10 +620,6 @@ SPIDER_CONN *spider_get_ping_table_tgt_conn( } #endif conn->error_mode = 0; -#ifndef WITHOUT_SPIDER_BG_SEARCH - if (trx == spider_global_trx) - pthread_mutex_unlock(&spider_global_trx_mutex); -#endif DBUG_RETURN(conn); error: diff --git a/storage/spider/spd_table.cc b/storage/spider/spd_table.cc index a5ca0b724eb..1c5d7903145 100644 --- a/storage/spider/spd_table.cc +++ b/storage/spider/spd_table.cc @@ -97,9 +97,6 @@ PSI_mutex_key spd_key_mutex_conn; PSI_mutex_key spd_key_mutex_hs_r_conn; PSI_mutex_key spd_key_mutex_hs_w_conn; #endif -#ifndef WITHOUT_SPIDER_BG_SEARCH -PSI_mutex_key spd_key_mutex_global_trx; -#endif PSI_mutex_key spd_key_mutex_open_conn; PSI_mutex_key spd_key_mutex_allocated_thds; PSI_mutex_key spd_key_mutex_mon_table_cache; @@ -143,9 +140,6 @@ static PSI_mutex_info all_spider_mutexes[]= #if defined(HS_HAS_SQLCOM) && defined(HAVE_HANDLERSOCKET) { &spd_key_mutex_hs_r_conn, "hs_r_conn", PSI_FLAG_GLOBAL}, { &spd_key_mutex_hs_w_conn, "hs_w_conn", PSI_FLAG_GLOBAL}, -#endif -#ifndef WITHOUT_SPIDER_BG_SEARCH - { &spd_key_mutex_global_trx, "global_trx", PSI_FLAG_GLOBAL}, #endif { &spd_key_mutex_open_conn, "open_conn", PSI_FLAG_GLOBAL}, { &spd_key_mutex_allocated_thds, "allocated_thds", PSI_FLAG_GLOBAL}, @@ -300,9 +294,6 @@ pthread_mutex_t spider_allocated_thds_mutex; #ifndef WITHOUT_SPIDER_BG_SEARCH pthread_attr_t spider_pt_attr; - -pthread_mutex_t spider_global_trx_mutex; -SPIDER_TRX *spider_global_trx; #endif extern pthread_mutex_t spider_mem_calc_mutex; @@ -6096,10 +6087,6 @@ int spider_db_done( do_delete_thd = TRUE; } -#ifndef WITHOUT_SPIDER_BG_SEARCH - spider_free_trx(spider_global_trx, TRUE); -#endif - for (roop_count = SPIDER_DBTON_SIZE - 1; roop_count >= 0; roop_count--) { if (spider_dbton[roop_count].deinit) @@ -6267,9 +6254,6 @@ int spider_db_done( pthread_mutex_destroy(&spider_mon_table_cache_mutex); pthread_mutex_destroy(&spider_allocated_thds_mutex); pthread_mutex_destroy(&spider_open_conn_mutex); -#ifndef WITHOUT_SPIDER_BG_SEARCH - pthread_mutex_destroy(&spider_global_trx_mutex); -#endif #if defined(HS_HAS_SQLCOM) && defined(HAVE_HANDLERSOCKET) pthread_mutex_destroy(&spider_hs_w_conn_mutex); pthread_mutex_destroy(&spider_hs_r_conn_mutex); @@ -6513,18 +6497,6 @@ int spider_db_init( error_num = HA_ERR_OUT_OF_MEM; goto error_conn_mutex_init; } -#ifndef WITHOUT_SPIDER_BG_SEARCH -#if MYSQL_VERSION_ID < 50500 - if (pthread_mutex_init(&spider_global_trx_mutex, MY_MUTEX_INIT_FAST)) -#else - if (mysql_mutex_init(spd_key_mutex_global_trx, - &spider_global_trx_mutex, MY_MUTEX_INIT_FAST)) -#endif - { - error_num = HA_ERR_OUT_OF_MEM; - goto error_global_trx_mutex_init; - } -#endif #if MYSQL_VERSION_ID < 50500 if (pthread_mutex_init(&spider_open_conn_mutex, MY_MUTEX_INIT_FAST)) #else @@ -6789,16 +6761,9 @@ int spider_db_init( } } -#ifndef WITHOUT_SPIDER_BG_SEARCH - if (!(spider_global_trx = spider_get_trx(NULL, FALSE, &error_num))) - goto error; -#endif - DBUG_RETURN(0); #ifndef WITHOUT_SPIDER_BG_SEARCH -error: - roop_count = SPIDER_DBTON_SIZE; error_init_dbton: for (roop_count--; roop_count >= 0; roop_count--) { @@ -6900,10 +6865,6 @@ error_hs_r_conn_mutex_init: #endif pthread_mutex_destroy(&spider_open_conn_mutex); error_open_conn_mutex_init: -#ifndef WITHOUT_SPIDER_BG_SEARCH - pthread_mutex_destroy(&spider_global_trx_mutex); -error_global_trx_mutex_init: -#endif pthread_mutex_destroy(&spider_conn_mutex); error_conn_mutex_init: pthread_mutex_destroy(&spider_lgtm_tblhnd_share_mutex);