From f010c90807da68487b1ce4c952588c6c3def2afd Mon Sep 17 00:00:00 2001 From: Monty Date: Mon, 11 Mar 2019 20:03:27 +0200 Subject: [PATCH 01/10] Fixed memory leak in mysqltest read_command_buf was not freed at exit, which could cause a warning from valgrind --- client/mysqltest.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/mysqltest.cc b/client/mysqltest.cc index 82aa73939ac22..051a1cffeac57 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -193,6 +193,7 @@ static char TMPDIR[FN_REFLEN]; static char global_subst_from[200]; static char global_subst_to[200]; static char *global_subst= NULL; +static char *read_command_buf= NULL; static MEM_ROOT require_file_root; static const my_bool my_true= 1; static const my_bool my_false= 0; @@ -1532,6 +1533,7 @@ void free_used_memory() free_defaults(default_argv); free_root(&require_file_root, MYF(0)); free_re(); + my_free(read_command_buf); #ifdef _WIN32 free_tmp_sh_file(); free_win_path_patterns(); @@ -6583,7 +6585,6 @@ static inline bool is_escape_char(char c, char in_string) */ -static char *read_command_buf= NULL; static size_t read_command_buflen= 0; static const size_t max_multibyte_length= 6; From 149b75476837fb96c28739d5368e977e39fd671b Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Thu, 7 Mar 2019 13:43:53 +0400 Subject: [PATCH 02/10] MDEV-17595 - ALTER TABLE ADD FOREIGN KEY crash ALTER TABLE ... ADD FOREIGN KEY may trigger assertion failure when it has LOCK=EXCLUSIVE clause or concurrent FLUSH TABLES is being executed. In both cases being altered table is marked as flushed, which forces subsequent attempt to open parent table to re-open. Which in turn is not allowed while transaction is running. Rather than opening parent table, just take appropriate MDL lock. Also removed table_already_fk_prelocked() check: MDL itself has much better methods to handle duplicate locks. E.g. the former won't acquire MDL_SHARED_NO_WRITE if it already has MDL_SHARED_READ. --- mysql-test/suite/innodb/r/foreign-keys.result | 13 ++++++++++++ mysql-test/suite/innodb/t/foreign-keys.test | 15 ++++++++++++++ sql/sql_table.cc | 20 ++++++++----------- 3 files changed, 36 insertions(+), 12 deletions(-) diff --git a/mysql-test/suite/innodb/r/foreign-keys.result b/mysql-test/suite/innodb/r/foreign-keys.result index 66fc00e34d08b..68528521fb6ff 100644 --- a/mysql-test/suite/innodb/r/foreign-keys.result +++ b/mysql-test/suite/innodb/r/foreign-keys.result @@ -87,3 +87,16 @@ drop table t3; drop table t2; drop table t1; set debug_sync='reset'; +# +# MDEV-17595 - Server crashes in copy_data_between_tables or +# Assertion `thd->transaction.stmt.is_empty() || +# (thd->state_flags & Open_tables_state::BACKUPS_AVAIL)' +# fails in close_tables_for_reopen upon concurrent +# ALTER TABLE and FLUSH +# +CREATE TABLE t1 (a INT, KEY(a)) ENGINE=InnoDB; +INSERT INTO t1 VALUES(1),(2); +CREATE TABLE t2 (b INT, KEY(b)) ENGINE=InnoDB; +INSERT INTO t2 VALUES(2); +ALTER TABLE t2 ADD FOREIGN KEY(b) REFERENCES t1(a), LOCK=EXCLUSIVE; +DROP TABLE t2, t1; diff --git a/mysql-test/suite/innodb/t/foreign-keys.test b/mysql-test/suite/innodb/t/foreign-keys.test index 7ef440b260b9a..ced44a89d7c54 100644 --- a/mysql-test/suite/innodb/t/foreign-keys.test +++ b/mysql-test/suite/innodb/t/foreign-keys.test @@ -111,3 +111,18 @@ drop table t3; drop table t2; drop table t1; set debug_sync='reset'; + + +--echo # +--echo # MDEV-17595 - Server crashes in copy_data_between_tables or +--echo # Assertion `thd->transaction.stmt.is_empty() || +--echo # (thd->state_flags & Open_tables_state::BACKUPS_AVAIL)' +--echo # fails in close_tables_for_reopen upon concurrent +--echo # ALTER TABLE and FLUSH +--echo # +CREATE TABLE t1 (a INT, KEY(a)) ENGINE=InnoDB; +INSERT INTO t1 VALUES(1),(2); +CREATE TABLE t2 (b INT, KEY(b)) ENGINE=InnoDB; +INSERT INTO t2 VALUES(2); +ALTER TABLE t2 ADD FOREIGN KEY(b) REFERENCES t1(a), LOCK=EXCLUSIVE; +DROP TABLE t2, t1; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 8a4c6e025fb9c..3b4ba72b1f13e 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -9074,6 +9074,8 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, new_table->file->get_foreign_key_list(thd, &fk_list); while ((fk= fk_list_it++)) { + MDL_request mdl_request; + if (lower_case_table_names) { char buf[NAME_LEN]; @@ -9085,20 +9087,14 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, len = my_casedn_str(files_charset_info, buf); thd->make_lex_string(fk->referenced_table, buf, len); } - if (table_already_fk_prelocked(table_list, fk->referenced_db, - fk->referenced_table, TL_READ_NO_INSERT)) - continue; - TABLE_LIST *tl= (TABLE_LIST *) thd->alloc(sizeof(TABLE_LIST)); - tl->init_one_table_for_prelocking(fk->referenced_db->str, fk->referenced_db->length, - fk->referenced_table->str, fk->referenced_table->length, - NULL, TL_READ_NO_INSERT, false, NULL, 0, - &thd->lex->query_tables_last); + mdl_request.init(MDL_key::TABLE, + fk->referenced_db->str, fk->referenced_table->str, + MDL_SHARED_NO_WRITE, MDL_TRANSACTION); + if (thd->mdl_context.acquire_lock(&mdl_request, + thd->variables.lock_wait_timeout)) + goto err_new_table_cleanup; } - - if (open_tables(thd, &table_list->next_global, &tables_opened, 0, - &alter_prelocking_strategy)) - goto err_new_table_cleanup; } } /* From acb4a872049e0ac23a1fdf7a1aaf12ed2bf858a2 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Tue, 12 Mar 2019 01:09:55 +0400 Subject: [PATCH 03/10] MDEV-18886 JSON_ARRAY() does not recognise JSON argument. JSON_ARRAY and JSON_OBJECT functions with no arguments now get the connection charset. Item_func_convert_charset returns the correct is_json() flag. --- mysql-test/r/func_json.result | 12 ++++++++++++ mysql-test/t/func_json.test | 7 +++++++ sql/item_jsonfunc.cc | 5 +++-- sql/item_strfunc.h | 1 + 4 files changed, 23 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/func_json.result b/mysql-test/r/func_json.result index 74798b13e3a0b..e74d629247649 100644 --- a/mysql-test/r/func_json.result +++ b/mysql-test/r/func_json.result @@ -830,3 +830,15 @@ SET sql_mode=default; select JSON_VALID( '{"a":1]' ); JSON_VALID( '{"a":1]' ) 0 +# +# MDEV-18886 JSON_ARRAY() does not recognise JSON argument. +# +SELECT JSON_ARRAY(_UTF8 'str', JSON_OBJECT(_LATIN1 'plugin', _LATIN1'unix_socket')); +JSON_ARRAY(_UTF8 'str', JSON_OBJECT(_LATIN1 'plugin', _LATIN1'unix_socket')) +["str", {"plugin": "unix_socket"}] +SELECT CHARSET(JSON_ARRAY()); +CHARSET(JSON_ARRAY()) +latin1 +SELECT CHARSET(JSON_OBJECT()); +CHARSET(JSON_OBJECT()) +latin1 diff --git a/mysql-test/t/func_json.test b/mysql-test/t/func_json.test index 43bd19801d518..ef3fdc685fe5e 100644 --- a/mysql-test/t/func_json.test +++ b/mysql-test/t/func_json.test @@ -487,3 +487,10 @@ SET sql_mode=default; select JSON_VALID( '{"a":1]' ); +--echo # +--echo # MDEV-18886 JSON_ARRAY() does not recognise JSON argument. +--echo # +SELECT JSON_ARRAY(_UTF8 'str', JSON_OBJECT(_LATIN1 'plugin', _LATIN1'unix_socket')); +SELECT CHARSET(JSON_ARRAY()); +SELECT CHARSET(JSON_OBJECT()); + diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc index 27bc97f4c5e19..78eb58506ffe7 100644 --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@ -1488,9 +1488,10 @@ bool Item_func_json_array::fix_length_and_dec() if (arg_count == 0) { - collation.set(&my_charset_utf8_general_ci, + THD* thd= current_thd; + collation.set(thd->variables.collation_connection, DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII); - tmp_val.set_charset(&my_charset_utf8_general_ci); + tmp_val.set_charset(thd->variables.collation_connection); max_length= 2; return FALSE; } diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index a908aba2d2f9a..b3baae99c1550 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -1192,6 +1192,7 @@ class Item_func_conv_charset :public Item_str_func (cs->state & MY_CS_UNICODE)); } } + bool is_json_type() { return args[0]->is_json_type(); } String *val_str(String *); longlong val_int() { From 7025a51a7b85376b2f01b1f32e737278e9aa659b Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 8 Mar 2019 18:14:03 +0100 Subject: [PATCH 04/10] fix the typo OPTION_NO_CHECK_CONSTRAINT_CHECKS --- mysql-test/r/check_constraint.result | 13 +++++++++++++ mysql-test/r/mysqlbinlog.result | 16 ++++++++-------- .../suite/binlog/r/binlog_base64_flag.result | 2 +- mysql-test/t/check_constraint.test | 14 ++++++++++++++ sql/sql_priv.h | 2 +- 5 files changed, 37 insertions(+), 10 deletions(-) diff --git a/mysql-test/r/check_constraint.result b/mysql-test/r/check_constraint.result index 8cb1066ba9a99..3511af841666a 100644 --- a/mysql-test/r/check_constraint.result +++ b/mysql-test/r/check_constraint.result @@ -222,3 +222,16 @@ ERROR 23000: CONSTRAINT `t.b` failed for `test`.`t` insert into t values (1,1); ERROR 23000: CONSTRAINT `b` failed for `test`.`t` drop table t; +create table t1 (a int auto_increment primary key, b int, check (b > 5)); +insert t1 (b) values (1); +ERROR 23000: CONSTRAINT `CONSTRAINT_1` failed for `test`.`t1` +insert t1 (b) values (10); +select * from t1 where a is null; +a b +set sql_auto_is_null=1; +select * from t1 where a is null; +a b +1 10 +insert t1 (b) values (1); +ERROR 23000: CONSTRAINT `CONSTRAINT_1` failed for `test`.`t1` +drop table t1; diff --git a/mysql-test/r/mysqlbinlog.result b/mysql-test/r/mysqlbinlog.result index bac33753d4c7b..35ab4a5b54fab 100644 --- a/mysql-test/r/mysqlbinlog.result +++ b/mysql-test/r/mysqlbinlog.result @@ -724,7 +724,7 @@ ROLLBACK/*!*/; use `test`/*!*/; SET TIMESTAMP=1253783037/*!*/; SET @@session.pseudo_thread_id=999999999/*!*/; -SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=0/*!*/; +SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=1/*!*/; SET @@session.sql_mode=0/*!*/; SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/; /*!\C latin1 *//*!*/; @@ -778,7 +778,7 @@ DELIMITER /*!*/; ROLLBACK/*!*/; SET TIMESTAMP=1253783037/*!*/; SET @@session.pseudo_thread_id=999999999/*!*/; -SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=0/*!*/; +SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=1/*!*/; SET @@session.sql_mode=0/*!*/; SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/; /*!\C latin1 *//*!*/; @@ -813,7 +813,7 @@ ROLLBACK /* added by mysqlbinlog */; DELIMITER /*!*/; SET TIMESTAMP=1266652094/*!*/; SET @@session.pseudo_thread_id=999999999/*!*/; -SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=0/*!*/; +SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=1/*!*/; SET @@session.sql_mode=0/*!*/; SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/; /*!\C latin1 *//*!*/; @@ -855,7 +855,7 @@ ROLLBACK /* added by mysqlbinlog */; DELIMITER /*!*/; SET TIMESTAMP=1266652094/*!*/; SET @@session.pseudo_thread_id=999999999/*!*/; -SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=0/*!*/; +SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=1/*!*/; SET @@session.sql_mode=0/*!*/; SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/; /*!\C latin1 *//*!*/; @@ -964,7 +964,7 @@ AAAAAAAAAAAAAAAAAAAgrgJSFzgNAAgAEgAEBAQEEgAAUwAEGggAAAAICAgC # Event: Query thread_id=1 exec_time=0 error_code=0 SET TIMESTAMP=1375907364/*!*/; SET @@session.pseudo_thread_id=1/*!*/; -SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=0/*!*/; +SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=1/*!*/; SET @@session.sql_mode=0/*!*/; SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/; /*!\C latin1 *//*!*/; @@ -1047,7 +1047,7 @@ AAAAAAAAAAAAAAAAAAA/rQJSGzgNAAgAEgAEBAQEEgAAUwAEGggAAAAICAgC # Event: Query thread_id=1 exec_time=1 error_code=0 SET TIMESTAMP=1375907141/*!*/; SET @@session.pseudo_thread_id=1/*!*/; -SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=0/*!*/; +SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=1/*!*/; SET @@session.sql_mode=0/*!*/; SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/; /*!\C latin1 *//*!*/; @@ -1130,7 +1130,7 @@ AAAAAAAAAAAAAAAAAAAnrAJSHzgNAAgAEgAEBAQEEgAAUwAEGggAAAAICAgC # Event: Query thread_id=1 exec_time=0 error_code=0 SET TIMESTAMP=1375906879/*!*/; SET @@session.pseudo_thread_id=1/*!*/; -SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=0/*!*/; +SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=1/*!*/; SET @@session.sql_mode=0/*!*/; SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/; /*!\C latin1 *//*!*/; @@ -1213,7 +1213,7 @@ AAAAAAAAAAAAAAAAAABbsAJSEzgNAAgAEgAEBAQEEgAAUwAEGggAAAAICAgC # Event: Query thread_id=1 exec_time=0 error_code=0 SET TIMESTAMP=1375907933/*!*/; SET @@session.pseudo_thread_id=1/*!*/; -SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=0/*!*/; +SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=1/*!*/; SET @@session.sql_mode=0/*!*/; SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/; /*!\C latin1 *//*!*/; diff --git a/mysql-test/suite/binlog/r/binlog_base64_flag.result b/mysql-test/suite/binlog/r/binlog_base64_flag.result index 255f2b3b09b0f..553206cab8687 100644 --- a/mysql-test/suite/binlog/r/binlog_base64_flag.result +++ b/mysql-test/suite/binlog/r/binlog_base64_flag.result @@ -57,7 +57,7 @@ DELIMITER /*!*/; # at 102 <#>use `test`/*!*/; SET TIMESTAMP=1196959712/*!*/; -<#>SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=0/*!*/; +<#>SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=1/*!*/; SET @@session.sql_mode=0/*!*/; SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/; /*!\C latin1 *//*!*/; diff --git a/mysql-test/t/check_constraint.test b/mysql-test/t/check_constraint.test index 37fdc7203b1b4..93538fd166635 100644 --- a/mysql-test/t/check_constraint.test +++ b/mysql-test/t/check_constraint.test @@ -162,3 +162,17 @@ insert into t values (-1, 0); insert into t values (1,1); drop table t; + +# +# check constraints and auto_is_null typo +# +create table t1 (a int auto_increment primary key, b int, check (b > 5)); +--error ER_CONSTRAINT_FAILED +insert t1 (b) values (1); +insert t1 (b) values (10); +select * from t1 where a is null; +set sql_auto_is_null=1; +select * from t1 where a is null; +--error ER_CONSTRAINT_FAILED +insert t1 (b) values (1); +drop table t1; diff --git a/sql/sql_priv.h b/sql/sql_priv.h index f34148d4fe679..55148167b3260 100644 --- a/sql/sql_priv.h +++ b/sql/sql_priv.h @@ -126,7 +126,7 @@ #define TMP_TABLE_ALL_COLUMNS (1ULL << 12) // SELECT, intern #define OPTION_WARNINGS (1ULL << 13) // THD, user #define OPTION_AUTO_IS_NULL (1ULL << 14) // THD, user, binlog -#define OPTION_NO_CHECK_CONSTRAINT_CHECKS (1ULL << 14) +#define OPTION_NO_CHECK_CONSTRAINT_CHECKS (1ULL << 15) #define OPTION_SAFE_UPDATES (1ULL << 16) // THD, user #define OPTION_BUFFER_RESULT (1ULL << 17) // SELECT, user #define OPTION_BIN_LOG (1ULL << 18) // THD, user From 69abd43703fcf68c4cf1056bf5bd56c690de5b4e Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sun, 10 Mar 2019 18:55:35 +0100 Subject: [PATCH 05/10] MDEV-17070 Table corruption or Assertion `table->file->stats.records > 0 || error' or Assertion `!is_set() || (m_status == DA_OK_BULK && is_bulk_op())' failed upon actions on temporary table This was caused by a combination of factors: * MyISAM/Aria temporary tables historically never saved the state to disk (MYI/MAI), because the state never needed to persist * certain ALTER TABLE operations modify the original TABLE structure and if they fail, the original table has to be reopened to revert all changes (m_needs_reopen=1) as a result, when ALTER fails and MyISAM/Aria temp table gets reopened, it reads the stale state from the disk. As a fix, MyISAM/Aria tables now *always* write the state to disk on close, *unless* HA_EXTRA_PREPARE_FOR_DROP was done first. And the server now always does HA_EXTRA_PREPARE_FOR_DROP before dropping a temporary table. --- mysql-test/r/reopen_temp_table.result | 53 +++++++++++++++++++++++++++ mysql-test/t/reopen_temp_table.test | 40 ++++++++++++++++++++ sql/temporary_tables.cc | 11 +++--- storage/maria/ma_blockrec.c | 4 +- storage/maria/ma_close.c | 17 ++------- storage/maria/ma_extra.c | 2 + storage/maria/ma_open.c | 2 +- storage/myisam/mi_close.c | 17 +++++---- storage/myisam/mi_extra.c | 4 +- 9 files changed, 117 insertions(+), 33 deletions(-) diff --git a/mysql-test/r/reopen_temp_table.result b/mysql-test/r/reopen_temp_table.result index 217aa3c8bad55..ef215366db7ae 100644 --- a/mysql-test/r/reopen_temp_table.result +++ b/mysql-test/r/reopen_temp_table.result @@ -190,3 +190,56 @@ NULL NULL DROP TABLE t; # Cleanup DROP DATABASE temp_db; +USE test; +create temporary table t1 (f char(255), b int, index(b)) engine=MyISAM; +replace into t1 values (null,1),(null,2); +alter table t1 add fulltext key(f); +alter table t1 change if exists a b int, algorithm=inplace; +ERROR 0A000: ALGORITHM=INPLACE is not supported for this operation. Try ALGORITHM=COPY +check table t1; +Table Op Msg_type Msg_text +test.t1 check status OK +select * from t1; +f b +NULL 1 +NULL 2 +drop table t1; +create temporary table t1 (f char(255), b int, index(b)) engine=aria transactional=1; +replace into t1 values (null,1),(null,2); +alter table t1 add fulltext key(f); +alter table t1 change if exists a b int, algorithm=inplace; +ERROR 0A000: ALGORITHM=INPLACE is not supported for this operation. Try ALGORITHM=COPY +check table t1; +Table Op Msg_type Msg_text +test.t1 check status OK +select * from t1; +f b +NULL 1 +NULL 2 +drop table t1; +create temporary table t1 (f char(255), b int, index(b)) engine=aria transactional=0 row_format=page; +replace into t1 values (null,1),(null,2); +alter table t1 add fulltext key(f); +alter table t1 change if exists a b int, algorithm=inplace; +ERROR 0A000: ALGORITHM=INPLACE is not supported for this operation. Try ALGORITHM=COPY +check table t1; +Table Op Msg_type Msg_text +test.t1 check status OK +select * from t1; +f b +NULL 1 +NULL 2 +drop table t1; +create temporary table t1 (f char(255), b int, index(b)) engine=aria transactional=0 row_format=dynamic; +replace into t1 values (null,1),(null,2); +alter table t1 add fulltext key(f); +alter table t1 change if exists a b int, algorithm=inplace; +ERROR 0A000: ALGORITHM=INPLACE is not supported for this operation. Try ALGORITHM=COPY +check table t1; +Table Op Msg_type Msg_text +test.t1 check status OK +select * from t1; +f b +NULL 1 +NULL 2 +drop table t1; diff --git a/mysql-test/t/reopen_temp_table.test b/mysql-test/t/reopen_temp_table.test index 2aa6caa165527..2b3ff3bab5ebc 100644 --- a/mysql-test/t/reopen_temp_table.test +++ b/mysql-test/t/reopen_temp_table.test @@ -182,3 +182,43 @@ DROP TABLE t; --echo # Cleanup DROP DATABASE temp_db; +USE test; + +# +# MDEV-17070 Table corruption or Assertion `table->file->stats.records > 0 || error' or Assertion `!is_set() || (m_status == DA_OK_BULK && is_bulk_op())' failed upon actions on temporary table +# +create temporary table t1 (f char(255), b int, index(b)) engine=MyISAM; +replace into t1 values (null,1),(null,2); +alter table t1 add fulltext key(f); +--error ER_ALTER_OPERATION_NOT_SUPPORTED +alter table t1 change if exists a b int, algorithm=inplace; +check table t1; +select * from t1; +drop table t1; + +create temporary table t1 (f char(255), b int, index(b)) engine=aria transactional=1; +replace into t1 values (null,1),(null,2); +alter table t1 add fulltext key(f); +--error ER_ALTER_OPERATION_NOT_SUPPORTED +alter table t1 change if exists a b int, algorithm=inplace; +check table t1; +select * from t1; +drop table t1; + +create temporary table t1 (f char(255), b int, index(b)) engine=aria transactional=0 row_format=page; +replace into t1 values (null,1),(null,2); +alter table t1 add fulltext key(f); +--error ER_ALTER_OPERATION_NOT_SUPPORTED +alter table t1 change if exists a b int, algorithm=inplace; +check table t1; +select * from t1; +drop table t1; + +create temporary table t1 (f char(255), b int, index(b)) engine=aria transactional=0 row_format=dynamic; +replace into t1 values (null,1),(null,2); +alter table t1 add fulltext key(f); +--error ER_ALTER_OPERATION_NOT_SUPPORTED +alter table t1 change if exists a b int, algorithm=inplace; +check table t1; +select * from t1; +drop table t1; diff --git a/sql/temporary_tables.cc b/sql/temporary_tables.cc index 29c9910f33236..ed23dae06d257 100644 --- a/sql/temporary_tables.cc +++ b/sql/temporary_tables.cc @@ -491,6 +491,7 @@ bool THD::close_temporary_tables() /* Traverse the table list. */ while ((table= share->all_tmp_tables.pop_front())) { + table->file->extra(HA_EXTRA_PREPARE_FOR_DROP); free_temporary_table(table); } } @@ -579,9 +580,7 @@ bool THD::rename_temporary_table(TABLE *table, @return false Table was dropped true Error */ -bool THD::drop_temporary_table(TABLE *table, - bool *is_trans, - bool delete_table) +bool THD::drop_temporary_table(TABLE *table, bool *is_trans, bool delete_table) { DBUG_ENTER("THD::drop_temporary_table"); @@ -624,7 +623,8 @@ bool THD::drop_temporary_table(TABLE *table, parallel replication */ tab->in_use= this; - + if (delete_table) + tab->file->extra(HA_EXTRA_PREPARE_FOR_DROP); free_temporary_table(tab); } @@ -1419,8 +1419,7 @@ bool THD::log_events_and_free_tmp_shares() @return void */ -void THD::free_tmp_table_share(TMP_TABLE_SHARE *share, - bool delete_table) +void THD::free_tmp_table_share(TMP_TABLE_SHARE *share, bool delete_table) { DBUG_ENTER("THD::free_tmp_table_share"); diff --git a/storage/maria/ma_blockrec.c b/storage/maria/ma_blockrec.c index 0b55a03f90297..4395613862e82 100644 --- a/storage/maria/ma_blockrec.c +++ b/storage/maria/ma_blockrec.c @@ -449,9 +449,7 @@ my_bool _ma_once_end_block_record(MARIA_SHARE *share) if (share->bitmap.file.file >= 0) { if (flush_pagecache_blocks(share->pagecache, &share->bitmap.file, - ((share->temporary || share->deleting) ? - FLUSH_IGNORE_CHANGED : - FLUSH_RELEASE))) + share->deleting ? FLUSH_IGNORE_CHANGED : FLUSH_RELEASE)) res= 1; /* File must be synced as it is going out of the maria_open_list and so diff --git a/storage/maria/ma_close.c b/storage/maria/ma_close.c index 6e85551c24f1f..08bb7cee138de 100644 --- a/storage/maria/ma_close.c +++ b/storage/maria/ma_close.c @@ -47,9 +47,7 @@ int maria_close(register MARIA_HA *info) a global mutex */ if (flush_pagecache_blocks(share->pagecache, &share->kfile, - ((share->temporary || share->deleting) ? - FLUSH_IGNORE_CHANGED : - FLUSH_RELEASE))) + share->deleting ? FLUSH_IGNORE_CHANGED : FLUSH_RELEASE)) error= my_errno; } @@ -113,23 +111,14 @@ int maria_close(register MARIA_HA *info) since the start of the function (very unlikely) */ if (flush_pagecache_blocks(share->pagecache, &share->kfile, - ((share->temporary || share->deleting) ? - FLUSH_IGNORE_CHANGED : - FLUSH_RELEASE))) + share->deleting ? FLUSH_IGNORE_CHANGED : FLUSH_RELEASE)) error= my_errno; #ifdef HAVE_MMAP if (share->file_map) _ma_unmap_file(info); #endif - /* - If we are crashed, we can safely flush the current state as it will - not change the crashed state. - We can NOT write the state in other cases as other threads - may be using the file at this point - IF using --external-locking, which does not apply to Maria. - */ if (((share->changed && share->base.born_transactional) || - maria_is_crashed(info))) + maria_is_crashed(info) || (share->temporary && !share->deleting))) { if (save_global_changed) { diff --git a/storage/maria/ma_extra.c b/storage/maria/ma_extra.c index 9feead42cf739..47c796daab388 100644 --- a/storage/maria/ma_extra.c +++ b/storage/maria/ma_extra.c @@ -314,6 +314,8 @@ int maria_extra(MARIA_HA *info, enum ha_extra_function function, share->state.open_count= 1; share->changed= 1; _ma_mark_file_changed_now(share); + if (share->temporary) + break; /* fall through */ case HA_EXTRA_PREPARE_FOR_RENAME: { diff --git a/storage/maria/ma_open.c b/storage/maria/ma_open.c index a781b7e00d32e..6d507cee7d8f1 100644 --- a/storage/maria/ma_open.c +++ b/storage/maria/ma_open.c @@ -1374,7 +1374,7 @@ uint _ma_state_info_write(MARIA_SHARE *share, uint pWrite) if (pWrite & MA_STATE_INFO_WRITE_LOCK) mysql_mutex_lock(&share->intern_lock); - else if (maria_multi_threaded) + else if (maria_multi_threaded && !share->temporary) mysql_mutex_assert_owner(&share->intern_lock); if (share->base.born_transactional && translog_status == TRANSLOG_OK && !maria_in_recovery) diff --git a/storage/myisam/mi_close.c b/storage/myisam/mi_close.c index ad1d3074a27b4..5f2154534ae7d 100644 --- a/storage/myisam/mi_close.c +++ b/storage/myisam/mi_close.c @@ -65,11 +65,8 @@ int mi_close(register MI_INFO *info) DBUG_EXECUTE_IF("crash_before_flush_keys", if (share->kfile >= 0) DBUG_ABORT();); if (share->kfile >= 0 && - flush_key_blocks(share->key_cache, share->kfile, - &share->dirty_part_map, - ((share->temporary || share->deleting) ? - FLUSH_IGNORE_CHANGED : - FLUSH_RELEASE))) + flush_key_blocks(share->key_cache, share->kfile, &share->dirty_part_map, + share->deleting ? FLUSH_IGNORE_CHANGED : FLUSH_RELEASE)) error=my_errno; if (share->kfile >= 0) { @@ -77,10 +74,14 @@ int mi_close(register MI_INFO *info) If we are crashed, we can safely flush the current state as it will not change the crashed state. We can NOT write the state in other cases as other threads - may be using the file at this point - IF using --external-locking. + may be using the file at this point IF using --external-locking. + + Also, write the state if a temporary table is not being dropped + (the server might want to reopen it, and mi_lock_database() only + writes the state for non-temp ones) */ - if (share->mode != O_RDONLY && mi_is_crashed(info)) + if (share->mode != O_RDONLY && + (mi_is_crashed(info) || (share->temporary && !share->deleting))) mi_state_info_write(share->kfile, &share->state, 1); /* Decrement open count must be last I/O on this file. */ _mi_decrement_open_count(info); diff --git a/storage/myisam/mi_extra.c b/storage/myisam/mi_extra.c index 39b28d957598e..dcb79a8dc3ea6 100644 --- a/storage/myisam/mi_extra.c +++ b/storage/myisam/mi_extra.c @@ -260,9 +260,11 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function, void *extra_arg) break; case HA_EXTRA_PREPARE_FOR_DROP: /* Signals about intent to delete this table */ - //share->deleting= TRUE; + share->deleting= TRUE; share->global_changed= FALSE; /* force writing changed flag */ _mi_mark_file_changed(info); + if (share->temporary) + break; /* fall through */ case HA_EXTRA_PREPARE_FOR_RENAME: DBUG_ASSERT(!share->temporary); From 32de60bb2e9f06b24c76fc41bef81e35c14ca528 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 12 Mar 2019 12:55:38 +0200 Subject: [PATCH 06/10] MDEV-18749: Fix GCC -flifetime-dse row_merge_create_fts_sort_index(): Initialize dict_col_t in an unambiguous way. GCC 6 and later appear to be able to optimize away the memset() that is part of mem_heap_zalloc() in the placement new call. Let us avoid using placement new in order to ensure that the objects will actually be initialized. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71388 https://gcc.gnu.org/ml/gcc/2016-02/msg00207.html While the latter reference hints that the optimization is only applicable to non-POD types (and dict_col_t does not define any member functions before 10.2), it is most consistent to use the same initialization across all versions. --- storage/innobase/row/row0ftsort.cc | 12 ++++++------ storage/xtradb/row/row0ftsort.cc | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/storage/innobase/row/row0ftsort.cc b/storage/innobase/row/row0ftsort.cc index 6167fdc63d639..e3ac4e77f0ff4 100644 --- a/storage/innobase/row/row0ftsort.cc +++ b/storage/innobase/row/row0ftsort.cc @@ -98,8 +98,8 @@ row_merge_create_fts_sort_index( field = dict_index_get_nth_field(new_index, 0); field->name = NULL; field->prefix_len = 0; - field->col = new(mem_heap_zalloc(new_index->heap, sizeof(dict_col_t))) - dict_col_t(); + field->col = static_cast( + mem_heap_zalloc(new_index->heap, sizeof(dict_col_t))); field->col->prtype = idx_field->col->prtype | DATA_NOT_NULL; field->col->mtype = charset == &my_charset_latin1 ? DATA_VARCHAR : DATA_VARMYSQL; @@ -113,8 +113,8 @@ row_merge_create_fts_sort_index( field = dict_index_get_nth_field(new_index, 1); field->name = NULL; field->prefix_len = 0; - field->col = new(mem_heap_zalloc(new_index->heap, sizeof(dict_col_t))) - dict_col_t(); + field->col = static_cast( + mem_heap_zalloc(new_index->heap, sizeof(dict_col_t))); field->col->mtype = DATA_INT; *opt_doc_id_size = FALSE; @@ -152,8 +152,8 @@ row_merge_create_fts_sort_index( field = dict_index_get_nth_field(new_index, 2); field->name = NULL; field->prefix_len = 0; - field->col = new(mem_heap_zalloc(new_index->heap, sizeof(dict_col_t))) - dict_col_t(); + field->col = static_cast( + mem_heap_zalloc(new_index->heap, sizeof(dict_col_t))); field->col->mtype = DATA_INT; field->col->len = 4 ; field->fixed_len = 4; diff --git a/storage/xtradb/row/row0ftsort.cc b/storage/xtradb/row/row0ftsort.cc index 1798f99703350..fb30f867f8746 100644 --- a/storage/xtradb/row/row0ftsort.cc +++ b/storage/xtradb/row/row0ftsort.cc @@ -101,8 +101,8 @@ row_merge_create_fts_sort_index( field = dict_index_get_nth_field(new_index, 0); field->name = NULL; field->prefix_len = 0; - field->col = new(mem_heap_zalloc(new_index->heap, sizeof(dict_col_t))) - dict_col_t(); + field->col = static_cast( + mem_heap_zalloc(new_index->heap, sizeof(dict_col_t))); field->col->prtype = idx_field->col->prtype | DATA_NOT_NULL; field->col->mtype = charset == &my_charset_latin1 ? DATA_VARCHAR : DATA_VARMYSQL; @@ -116,8 +116,8 @@ row_merge_create_fts_sort_index( field = dict_index_get_nth_field(new_index, 1); field->name = NULL; field->prefix_len = 0; - field->col = new(mem_heap_zalloc(new_index->heap, sizeof(dict_col_t))) - dict_col_t(); + field->col = static_cast( + mem_heap_zalloc(new_index->heap, sizeof(dict_col_t))); field->col->mtype = DATA_INT; *opt_doc_id_size = FALSE; @@ -155,8 +155,8 @@ row_merge_create_fts_sort_index( field = dict_index_get_nth_field(new_index, 2); field->name = NULL; field->prefix_len = 0; - field->col = new(mem_heap_zalloc(new_index->heap, sizeof(dict_col_t))) - dict_col_t(); + field->col = static_cast( + mem_heap_zalloc(new_index->heap, sizeof(dict_col_t))); field->col->mtype = DATA_INT; field->col->len = 4 ; field->fixed_len = 4; From e070cfe398072b6020193f7eac5c3a1f7281979b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 12 Mar 2019 13:56:58 +0200 Subject: [PATCH 07/10] MDEV-18878: Fix GCC -flifetime-dse GCC 6 and later can optimize away the memset() that is part of mem_heap_zalloc() in a placement new call. So, instead of relying on that kind of initialization, explicitly initialize the necessary fields in the constructors. que_common_t::que_common_t(): Initialize more fields in the default constructor. purge_vcol_info_t::purge_vcol_info_t(): Initialize all fields in the default constructor. purge_node_t::purge_node_t(): Initialize all necessary fields. Reference: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71388 https://gcc.gnu.org/ml/gcc/2016-02/msg00207.html --- storage/innobase/include/que0types.h | 5 +++-- storage/innobase/include/row0purge.h | 9 ++++++++- storage/innobase/include/row0types.h | 5 +++++ storage/innobase/trx/trx0purge.cc | 2 +- 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/storage/innobase/include/que0types.h b/storage/innobase/include/que0types.h index 2b5a04811b3be..29134145c3585 100644 --- a/storage/innobase/include/que0types.h +++ b/storage/innobase/include/que0types.h @@ -87,8 +87,9 @@ struct que_common_t{ explicitly */ /** Constructor */ - que_common_t(ulint type, que_node_t* parent) - : type(type), parent(parent), brother(), val(), val_buf_size() + que_common_t(ulint type, que_node_t* parent) : + type(type), parent(parent), brother(NULL), + val(), val_buf_size(0) {} }; diff --git a/storage/innobase/include/row0purge.h b/storage/innobase/include/row0purge.h index 83babd183901e..97296831211ab 100644 --- a/storage/innobase/include/row0purge.h +++ b/storage/innobase/include/row0purge.h @@ -133,7 +133,14 @@ struct purge_node_t{ /** Constructor */ explicit purge_node_t(que_thr_t* parent) : - common(QUE_NODE_PURGE, parent), heap(mem_heap_create(256)) + common(QUE_NODE_PURGE, parent), + undo_recs(NULL), + unavailable_table_id(0), + heap(mem_heap_create(256)), +#ifdef UNIV_DEBUG + in_progress(false), +#endif + vcol_info() {} #ifdef UNIV_DEBUG diff --git a/storage/innobase/include/row0types.h b/storage/innobase/include/row0types.h index d2aef89f69598..84afbbc3ec715 100644 --- a/storage/innobase/include/row0types.h +++ b/storage/innobase/include/row0types.h @@ -69,6 +69,11 @@ struct purge_vcol_info_t TABLE* mariadb_table; public: + /** Default constructor */ + purge_vcol_info_t() : + requested(false), used(false), first_use(false), + mariadb_table(NULL) + {} /** Reset the state. */ void reset() { diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc index 18ebbc4aeee13..6c963003e05db 100644 --- a/storage/innobase/trx/trx0purge.cc +++ b/storage/innobase/trx/trx0purge.cc @@ -182,7 +182,7 @@ purge_graph_build() for (ulint i = 0; i < srv_n_purge_threads; ++i) { que_thr_t* thr = que_thr_create(fork, heap, NULL); - thr->child = new(mem_heap_zalloc(heap, sizeof(purge_node_t))) + thr->child = new(mem_heap_alloc(heap, sizeof(purge_node_t))) purge_node_t(thr); } From bef947b4c90b8af584690f27cc468a31c9afc564 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 12 Mar 2019 14:03:10 +0200 Subject: [PATCH 08/10] MDEV-18902 Uninitialized variable in recv_parse_log_recs() recv_parse_log_recs(): Do not compare type if ptr==end_ptr (we have reached the end of the redo log parsing buffer), because it will not have been correctly initialized in that case. --- storage/innobase/log/log0recv.cc | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index 0c0046da989f7..97befbe5580fb 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -2697,16 +2697,20 @@ bool recv_parse_log_recs(lsn_t checkpoint_lsn, store_t store, bool apply) &type, ptr, end_ptr, &space, &page_no, false, &body); - if (recv_sys->found_corrupt_log - || type == MLOG_CHECKPOINT - || (ptr != end_ptr - && (*ptr & MLOG_SINGLE_REC_FLAG))) { - recv_sys->found_corrupt_log = true; + if (recv_sys->found_corrupt_log) { +corrupted_log: recv_report_corrupt_log( ptr, type, space, page_no); return(true); } + if (ptr == end_ptr) { + } else if (type == MLOG_CHECKPOINT + || (*ptr & MLOG_SINGLE_REC_FLAG)) { + recv_sys->found_corrupt_log = true; + goto corrupted_log; + } + if (recv_sys->found_corrupt_fs) { return(true); } From f72760df3390407c3cbe876e827818bc52849b71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 12 Mar 2019 14:20:01 +0200 Subject: [PATCH 09/10] Add an end-of-tests marker to ease merges --- mysql-test/r/func_json.result | 3 +++ mysql-test/t/func_json.test | 3 +++ 2 files changed, 6 insertions(+) diff --git a/mysql-test/r/func_json.result b/mysql-test/r/func_json.result index e74d629247649..752a745b3b49b 100644 --- a/mysql-test/r/func_json.result +++ b/mysql-test/r/func_json.result @@ -842,3 +842,6 @@ latin1 SELECT CHARSET(JSON_OBJECT()); CHARSET(JSON_OBJECT()) latin1 +# +# End of 10.2 tests +# diff --git a/mysql-test/t/func_json.test b/mysql-test/t/func_json.test index ef3fdc685fe5e..8e924fb7f9ea8 100644 --- a/mysql-test/t/func_json.test +++ b/mysql-test/t/func_json.test @@ -494,3 +494,6 @@ SELECT JSON_ARRAY(_UTF8 'str', JSON_OBJECT(_LATIN1 'plugin', _LATIN1'unix_socket SELECT CHARSET(JSON_ARRAY()); SELECT CHARSET(JSON_OBJECT()); +--echo # +--echo # End of 10.2 tests +--echo # From 69b33fca8cce0912b7fecc79cbef895a119f3017 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 12 Mar 2019 16:02:34 +0200 Subject: [PATCH 10/10] MDEV-18878: After-merge fixes In 10.3, all records will be processed by purge due to MDEV-12288. But, the insert undo records do not contain a transaction identifier. row_purge_parse_undo_rec(): Use node->trx_id=TRX_ID_MAX for the insert undo records. We cannot skip table lookups for these records after DISCARD TABLESPACE other than by 'detaching' the table from the undo logs by updating SYS_TABLES.ID on both DISCARD TABLESPACE and IMPORT TABLESPACE. Also, remove a redundant condition that was introduced in the merge commit 814205f306cad8a4b3e55785616ea69a027fef9d. --- storage/innobase/row/row0purge.cc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/storage/innobase/row/row0purge.cc b/storage/innobase/row/row0purge.cc index 7854901cfa885..af53a3bc1539d 100644 --- a/storage/innobase/row/row0purge.cc +++ b/storage/innobase/row/row0purge.cc @@ -1027,6 +1027,11 @@ row_purge_parse_undo_rec( return false; case TRX_UNDO_INSERT_METADATA: case TRX_UNDO_INSERT_REC: + /* These records do not store any transaction identifier. + + FIXME: Update SYS_TABLES.ID on both DISCARD TABLESPACE + and IMPORT TABLESPACE to get rid of the repeated lookups! */ + node->trx_id = TRX_ID_MAX; break; default: #ifdef UNIV_DEBUG @@ -1112,9 +1117,7 @@ row_purge_parse_undo_rec( node->table = NULL; err_exit: rw_lock_s_unlock(dict_operation_lock); - if (table_id) { - node->skip(table_id, trx_id); - } + node->skip(table_id, trx_id); return(false); }