diff options
-rw-r--r-- | client/mysqlslap.c | 49 | ||||
-rw-r--r-- | mysql-test/r/myisam_recover.result (renamed from mysql-test/r/merge_recover.result) | 57 | ||||
-rw-r--r-- | mysql-test/r/view.result | 15 | ||||
-rw-r--r-- | mysql-test/suite/innodb/r/add_constraint.result | 13 | ||||
-rw-r--r-- | mysql-test/suite/innodb/t/add_constraint.test | 21 | ||||
-rw-r--r-- | mysql-test/suite/ndb/r/ndb_restore_discover.result | 33 | ||||
-rw-r--r-- | mysql-test/suite/ndb/t/ndb_restore_discover.test | 70 | ||||
-rw-r--r-- | mysql-test/t/myisam_recover-master.opt (renamed from mysql-test/t/merge_recover-master.opt) | 0 | ||||
-rw-r--r-- | mysql-test/t/myisam_recover.test (renamed from mysql-test/t/merge_recover.test) | 77 | ||||
-rw-r--r-- | mysql-test/t/view.test | 21 | ||||
-rw-r--r-- | mysys/ptr_cmp.c | 3 | ||||
-rw-r--r-- | sql/item_sum.cc | 5 | ||||
-rw-r--r-- | sql/sql_base.cc | 58 | ||||
-rw-r--r-- | sql/sql_parse.cc | 2 |
14 files changed, 396 insertions, 28 deletions
diff --git a/client/mysqlslap.c b/client/mysqlslap.c index b67e409ef0b..f12ea4c2086 100644 --- a/client/mysqlslap.c +++ b/client/mysqlslap.c @@ -1,5 +1,6 @@ /* - Copyright (c) 2005, 2012, Oracle and/or its affiliates. + Copyright (c) 2005, 2015, Oracle and/or its affiliates. + Copyright (c) 2010, 2015, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -242,7 +243,7 @@ void print_conclusions_csv(conclusions *con); void generate_stats(conclusions *con, option_string *eng, stats *sptr); uint parse_comma(const char *string, uint **range); uint parse_delimiter(const char *script, statement **stmt, char delm); -uint parse_option(const char *origin, option_string **stmt, char delm); +int parse_option(const char *origin, option_string **stmt, char delm); static int drop_schema(MYSQL *mysql, const char *db); uint get_random_string(char *buf); static statement *build_table_string(void); @@ -1264,7 +1265,13 @@ get_options(int *argc,char ***argv) if (num_int_cols_opt) { option_string *str; - parse_option(num_int_cols_opt, &str, ','); + if(parse_option(num_int_cols_opt, &str, ',') == -1) + { + fprintf(stderr, "Invalid value specified for the option " + "'number-int-cols'\n"); + option_cleanup(str); + return 1; + } num_int_cols= atoi(str->string); if (str->option) num_int_cols_index= atoi(str->option); @@ -1275,7 +1282,13 @@ get_options(int *argc,char ***argv) if (num_char_cols_opt) { option_string *str; - parse_option(num_char_cols_opt, &str, ','); + if(parse_option(num_char_cols_opt, &str, ',') == -1) + { + fprintf(stderr, "Invalid value specified for the option " + "'number-char-cols'\n"); + option_cleanup(str); + return 1; + } num_char_cols= atoi(str->string); if (str->option) num_char_cols_index= atoi(str->option); @@ -1512,7 +1525,13 @@ get_options(int *argc,char ***argv) printf("Parsing engines to use.\n"); if (default_engine) - parse_option(default_engine, &engine_options, ','); + { + if(parse_option(default_engine, &engine_options, ',') == -1) + { + fprintf(stderr, "Invalid value specified for the option 'engine'\n"); + return 1; + } + } if (tty_password) opt_password= get_tty_password(NullS); @@ -1989,7 +2008,7 @@ end: DBUG_RETURN(0); } -uint +int parse_option(const char *origin, option_string **stmt, char delm) { char *retstr; @@ -2014,6 +2033,13 @@ parse_option(const char *origin, option_string **stmt, char delm) char buffer[HUGE_STRING_LENGTH]= ""; char *buffer_ptr; + /* + Return an error if the length of the any of the comma seprated value + exceeds HUGE_STRING_LENGTH. + */ + if ((size_t)(retstr - ptr) > HUGE_STRING_LENGTH) + return -1; + count++; strncpy(buffer, ptr, (size_t)(retstr - ptr)); /* @@ -2053,6 +2079,13 @@ parse_option(const char *origin, option_string **stmt, char delm) { char *origin_ptr; + /* + Return an error if the length of the any of the comma seprated value + exceeds HUGE_STRING_LENGTH. + */ + if (strlen(ptr) > HUGE_STRING_LENGTH) + return -1; + if ((origin_ptr= strchr(ptr, ':'))) { char *option_ptr; @@ -2063,13 +2096,13 @@ parse_option(const char *origin, option_string **stmt, char delm) option_ptr= (char *)ptr + 1 + tmp->length; /* Move past the : and the first string */ - tmp->option_length= (size_t)((ptr + length) - option_ptr); + tmp->option_length= strlen(option_ptr); tmp->option= my_strndup(option_ptr, tmp->option_length, MYF(MY_FAE)); } else { - tmp->length= (size_t)((ptr + length) - ptr); + tmp->length= strlen(ptr); tmp->string= my_strndup(ptr, tmp->length, MYF(MY_FAE)); } diff --git a/mysql-test/r/merge_recover.result b/mysql-test/r/myisam_recover.result index 871c12ca4c0..0829c1e8b82 100644 --- a/mysql-test/r/merge_recover.result +++ b/mysql-test/r/myisam_recover.result @@ -1,5 +1,7 @@ # -# Test of MyISAM MRG tables with corrupted children. +# Tests for corrupted MyISAM tables and MyISAMMRG tables with corrupted +# children.. +# # Run with --myisam-recover=force option. # # Preparation: we need to make sure that the merge parent @@ -44,20 +46,20 @@ drop procedure p_create; # Switching to connection 'default' # # -# We have to disable the ps-protocol, to avoid +# We have to disable the ps-protocol, to avoid # "Prepared statement needs to be re-prepared" errors # -- table def versions change all the time with full table cache. -# +# drop table if exists t1, t1_mrg, t1_copy; # # Prepare a MERGE engine table, that refers to a corrupted # child. -# +# create table t1 (a int, key(a)) engine=myisam; create table t1_mrg (a int) union (t1) engine=merge; # # Create a table with a corrupted index file: -# save an old index file, insert more rows, +# save an old index file, insert more rows, # overwrite the new index file with the old one. # insert into t1 (a) values (1), (2), (3); @@ -101,3 +103,48 @@ execute stmt; deallocate prepare stmt; set @@global.table_definition_cache=default; set @@global.table_open_cache=default; +# +# 18075170 - sql node restart required to avoid deadlock after +# restore +# +# Check that auto-repair for MyISAM tables can now happen in the +# middle of transaction, without aborting it. +create table t1 (a int, key(a)) engine=myisam; +create table t2 (a int); +insert into t2 values (1); +# Create a table with a corrupted index file: +# save an old index file, insert more rows, +# overwrite the new index file with the old one. +insert into t1 (a) values (1); +flush table t1; +insert into t1 (a) values (4); +flush table t1; +# Check table is needed to mark the table as crashed. +check table t1; +Table Op Msg_type Msg_text +test.t1 check warning Size of datafile is: 14 Should be: 7 +test.t1 check error Record-count is not ok; is 2 Should be: 1 +test.t1 check warning Found 2 key parts. Should be: 1 +test.t1 check error Corrupt +# At this point we have a corrupt t1 +set autocommit = 0; +select * from t2; +a +1 +# Without fix select from t1 will break the transaction. After the fix +# transaction should be active and should hold lock on table t2. Alter +# table from con2 will wait only if the transaction is not broken. +select * from t1; +a +1 +4 +Warnings: +Error 145 Table 't1' is marked as crashed and should be repaired +Error 1194 Table 't1' is marked as crashed and should be repaired +Error 1034 Number of rows changed from 1 to 2 +ALTER TABLE t2 ADD val INT; +# With fix we should have alter table waiting for t2 lock here. +ROLLBACK; +SET autocommit = 1; +# Cleanup +drop table t1, t2; diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index d534cf4023a..2ddcaf54cc9 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -5427,6 +5427,21 @@ View Create View character_set_client collation_connection v2 CREATE ALGORITHM=MERGE DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v2` AS select (`t1`.`b` + 1) AS `c` from `t1` latin1 latin1_swedish_ci drop view v2; drop table t1; +# +# MDEV-8554: Server crashes in base_list_iterator::next_fast on 1st execution of PS with a multi-table update +# +CREATE TABLE t1 (a INT) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1),(2); +CREATE TABLE t2 (b INT) ENGINE=MyISAM; +INSERT INTO t2 VALUES (3),(4); +CREATE TABLE t3 (c INT) ENGINE=MyISAM; +INSERT INTO t3 VALUES (5),(6); +CREATE OR REPLACE ALGORITHM=MERGE VIEW v3 AS SELECT * FROM t3; +PREPARE stmt FROM 'UPDATE t1, t2 SET a = 1 WHERE a IN ( SELECT 0 FROM t3 )'; +UPDATE t1, t2 SET a = 1 WHERE a IN ( SELECT 0 FROM v3 ); +EXECUTE stmt; +DROP TABLE t1, t2, t3; +DROP VIEW v3; # ----------------------------------------------------------------- # -- End of 5.5 tests. # ----------------------------------------------------------------- diff --git a/mysql-test/suite/innodb/r/add_constraint.result b/mysql-test/suite/innodb/r/add_constraint.result new file mode 100644 index 00000000000..798e87a3761 --- /dev/null +++ b/mysql-test/suite/innodb/r/add_constraint.result @@ -0,0 +1,13 @@ +# +# Bug #20762798 FK DDL: CRASH IN DICT_FOREIGN_REMOVE_FROM_CACHE +# +create table t1(a int, b int, key(a),key(b))engine=innodb; +create table t2(a int, b int, key(a),key(b))engine=innodb; +alter table t2 add constraint b foreign key (b) references t1(a); +alter table t1 add constraint b1 foreign key (b) references t2(a); +alter table t2 add constraint b1 foreign key (b) references t1(a); +ERROR HY000: Can't create table `test`.`#sql-temporary` (errno: 121 "Duplicate key on write or update") +alter table t2 drop foreign key b; +alter table t1 drop foreign key b1; +drop table t2; +drop table t1; diff --git a/mysql-test/suite/innodb/t/add_constraint.test b/mysql-test/suite/innodb/t/add_constraint.test new file mode 100644 index 00000000000..7e86a7e5f97 --- /dev/null +++ b/mysql-test/suite/innodb/t/add_constraint.test @@ -0,0 +1,21 @@ +--source include/have_innodb.inc + +--echo # +--echo # Bug #20762798 FK DDL: CRASH IN DICT_FOREIGN_REMOVE_FROM_CACHE +--echo # + +create table t1(a int, b int, key(a),key(b))engine=innodb; +create table t2(a int, b int, key(a),key(b))engine=innodb; + +alter table t2 add constraint b foreign key (b) references t1(a); +alter table t1 add constraint b1 foreign key (b) references t2(a); + +--replace_regex /#sql-[0-9a-f_]*/#sql-temporary/ +--error ER_CANT_CREATE_TABLE +alter table t2 add constraint b1 foreign key (b) references t1(a); + +alter table t2 drop foreign key b; +alter table t1 drop foreign key b1; + +drop table t2; +drop table t1; diff --git a/mysql-test/suite/ndb/r/ndb_restore_discover.result b/mysql-test/suite/ndb/r/ndb_restore_discover.result new file mode 100644 index 00000000000..de10af87047 --- /dev/null +++ b/mysql-test/suite/ndb/r/ndb_restore_discover.result @@ -0,0 +1,33 @@ +# +# 18075170 - sql node restart required to avoid deadlock after +# restore +# +CREATE TABLE t1 (id INT) ENGINE=NDBCluster; +CREATE TABLE t2 (id INT) ENGINE=NDBCluster; +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (1); +DROP TABLE t1; +DROP TABLE t2; +SET autocommit = 0; +SELECT * FROM t1; +id +1 +SELECT * FROM t2; +id +1 +ROLLBACK; +SET autocommit = 1; +drop table t1; +drop table t2; +SET autocommit = 0; +SELECT * FROM t1; +id +1 +SELECT * FROM t2; +id +1 +ALTER TABLE t1 ADD val INT; +ROLLBACK; +SET autocommit = 1; +drop table t1; +drop table t2; diff --git a/mysql-test/suite/ndb/t/ndb_restore_discover.test b/mysql-test/suite/ndb/t/ndb_restore_discover.test new file mode 100644 index 00000000000..6631c74d5c8 --- /dev/null +++ b/mysql-test/suite/ndb/t/ndb_restore_discover.test @@ -0,0 +1,70 @@ +-- source include/have_ndb.inc +-- source include/count_sessions.inc + +--echo # +--echo # 18075170 - sql node restart required to avoid deadlock after +--echo # restore +--echo # +# Test Auto Discover option within a transaction +# and make sure the transaction is not broken. +CREATE TABLE t1 (id INT) ENGINE=NDBCluster; +CREATE TABLE t2 (id INT) ENGINE=NDBCluster; + +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (1); + +-- source include/ndb_backup.inc + +DROP TABLE t1; +DROP TABLE t2; + +-- source include/ndb_restore_master.inc + +SET autocommit = 0; +SELECT * FROM t1; + +# Without fix below select was resulting in DEADLOCK error. With fix select +# should succeed. +SELECT * FROM t2; +ROLLBACK; +SET autocommit = 1; + +drop table t1; +drop table t2; + +# +# Checking lock preservation in transaction +# +# Using existing backup to create the scenario. Tables are deleted as part of +# above test cleanup. Thus restoring the backup will bring the system to +# required state. +-- source include/ndb_restore_master.inc + +SET autocommit = 0; +SELECT * FROM t1; +SELECT * FROM t2; + +connect(con2, localhost, root); +--SEND ALTER TABLE t1 ADD val INT + +connection default; +# Alter from con2 will be in waiting state as there is a lock on t1 from +# default connection due to active transaction. We check for this condition +# then releasing the lock by rollbacking active transaction. +let $wait_condition= + SELECT count(*) = 1 FROM information_schema.processlist WHERE state + LIKE "Waiting%" AND info = "ALTER TABLE t1 ADD val INT"; +--source include/wait_condition.inc +ROLLBACK; +SET autocommit = 1; + +connection con2; +--REAP + +disconnect con2; +connection default; +drop table t1; +drop table t2; + +# Wait till all disconnects are completed +-- source include/wait_until_count_sessions.inc diff --git a/mysql-test/t/merge_recover-master.opt b/mysql-test/t/myisam_recover-master.opt index 875a25ad513..875a25ad513 100644 --- a/mysql-test/t/merge_recover-master.opt +++ b/mysql-test/t/myisam_recover-master.opt diff --git a/mysql-test/t/merge_recover.test b/mysql-test/t/myisam_recover.test index f2cb204eeb6..49fe9c33460 100644 --- a/mysql-test/t/merge_recover.test +++ b/mysql-test/t/myisam_recover.test @@ -1,5 +1,9 @@ +--source include/count_sessions.inc + +--echo # +--echo # Tests for corrupted MyISAM tables and MyISAMMRG tables with corrupted +--echo # children.. --echo # ---echo # Test of MyISAM MRG tables with corrupted children. --echo # Run with --myisam-recover=force option. --echo # --echo # Preparation: we need to make sure that the merge parent @@ -57,10 +61,10 @@ eval $lock; --echo # connection default; --echo # ---echo # We have to disable the ps-protocol, to avoid +--echo # We have to disable the ps-protocol, to avoid --echo # "Prepared statement needs to be re-prepared" errors --echo # -- table def versions change all the time with full table cache. ---echo # +--echo # --disable_ps_protocol --disable_warnings drop table if exists t1, t1_mrg, t1_copy; @@ -69,12 +73,12 @@ let $MYSQLD_DATADIR=`select @@datadir`; --echo # --echo # Prepare a MERGE engine table, that refers to a corrupted --echo # child. ---echo # +--echo # create table t1 (a int, key(a)) engine=myisam; create table t1_mrg (a int) union (t1) engine=merge; --echo # --echo # Create a table with a corrupted index file: ---echo # save an old index file, insert more rows, +--echo # save an old index file, insert more rows, --echo # overwrite the new index file with the old one. --echo # insert into t1 (a) values (1), (2), (3); @@ -111,3 +115,66 @@ set @@global.table_open_cache=default; disconnect con1; connection default; --enable_ps_protocol + +--echo # +--echo # 18075170 - sql node restart required to avoid deadlock after +--echo # restore +--echo # +--echo # Check that auto-repair for MyISAM tables can now happen in the +--echo # middle of transaction, without aborting it. +--enable_prepare_warnings + +connection default; + +create table t1 (a int, key(a)) engine=myisam; +create table t2 (a int); +insert into t2 values (1); + +--echo # Create a table with a corrupted index file: +--echo # save an old index file, insert more rows, +--echo # overwrite the new index file with the old one. +insert into t1 (a) values (1); +flush table t1; +--copy_file $MYSQLD_DATADIR/test/t1.MYI $MYSQLD_DATADIR/test/t1_copy.MYI +insert into t1 (a) values (4); +flush table t1; +--remove_file $MYSQLD_DATADIR/test/t1.MYI +--copy_file $MYSQLD_DATADIR/test/t1_copy.MYI $MYSQLD_DATADIR/test/t1.MYI +--remove_file $MYSQLD_DATADIR/test/t1_copy.MYI + +--echo # Check table is needed to mark the table as crashed. +check table t1; + +--echo # At this point we have a corrupt t1 +set autocommit = 0; +select * from t2; +--echo # Without fix select from t1 will break the transaction. After the fix +--echo # transaction should be active and should hold lock on table t2. Alter +--echo # table from con2 will wait only if the transaction is not broken. +--replace_regex /'.*[\/\\]/'/ +select * from t1; + +connect(con2, localhost, root); +--SEND ALTER TABLE t2 ADD val INT + +connection default; +--echo # With fix we should have alter table waiting for t2 lock here. +let $wait_condition= + SELECT count(*) = 1 FROM information_schema.processlist WHERE state + LIKE "Waiting%" AND info = "ALTER TABLE t2 ADD val INT"; + +--source include/wait_condition.inc +ROLLBACK; +SET autocommit = 1; + +connection con2; +--REAP + +connection default; +disconnect con2; + +--echo # Cleanup +drop table t1, t2; + +# Wait till all disconnects are completed +-- source include/wait_until_count_sessions.inc diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index e95194e3f2c..8c2a8ac8dc2 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -5380,6 +5380,27 @@ show create view v2; drop view v2; drop table t1; +--echo # +--echo # MDEV-8554: Server crashes in base_list_iterator::next_fast on 1st execution of PS with a multi-table update +--echo # +CREATE TABLE t1 (a INT) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1),(2); # Not necessary, the table can be empty + +CREATE TABLE t2 (b INT) ENGINE=MyISAM; +INSERT INTO t2 VALUES (3),(4); # Not necessary, the table can be empty + +CREATE TABLE t3 (c INT) ENGINE=MyISAM; +INSERT INTO t3 VALUES (5),(6); # Not necessary, the table can be empty + +CREATE OR REPLACE ALGORITHM=MERGE VIEW v3 AS SELECT * FROM t3; + +PREPARE stmt FROM 'UPDATE t1, t2 SET a = 1 WHERE a IN ( SELECT 0 FROM t3 )'; +UPDATE t1, t2 SET a = 1 WHERE a IN ( SELECT 0 FROM v3 ); +EXECUTE stmt; + +DROP TABLE t1, t2, t3; +DROP VIEW v3; + --echo # ----------------------------------------------------------------- --echo # -- End of 5.5 tests. --echo # ----------------------------------------------------------------- diff --git a/mysys/ptr_cmp.c b/mysys/ptr_cmp.c index a481b4d961c..6e373e98972 100644 --- a/mysys/ptr_cmp.c +++ b/mysys/ptr_cmp.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -91,6 +91,7 @@ static int ptr_compare(size_t *compare_length, uchar **a, uchar **b) reg3 int length= *compare_length; reg1 uchar *first,*last; + DBUG_ASSERT(length > 0); first= *a; last= *b; while (--length) { diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 29dc94eb5af..e9f52a8c27b 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -3531,9 +3531,10 @@ bool Item_func_group_concat::setup(THD *thd) { uint n_elems= arg_count_order + all_fields.elements; ref_pointer_array= static_cast<Item**>(thd->alloc(sizeof(Item*) * n_elems)); + if (!ref_pointer_array) + DBUG_RETURN(TRUE); memcpy(ref_pointer_array, args, arg_count * sizeof(Item*)); - if (!ref_pointer_array || - setup_order(thd, ref_pointer_array, context->table_list, list, + if (setup_order(thd, ref_pointer_array, context->table_list, list, all_fields, *order)) DBUG_RETURN(TRUE); } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 643ad4b41cb..12cd999d130 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -3409,10 +3409,11 @@ request_backoff_action(enum_open_table_action action_arg, * We met a broken table that needs repair, or a table that is not present on this MySQL server and needs re-discovery. To perform the action, we need an exclusive metadata lock on - the table. Acquiring an X lock while holding other shared - locks is very deadlock-prone. If this is a multi- statement - transaction that holds metadata locks for completed - statements, we don't do it, and report an error instead. + the table. Acquiring X lock while holding other shared + locks can easily lead to deadlocks. We rely on MDL deadlock + detector to discover them. If this is a multi-statement + transaction that holds metadata locks for completed statements, + we should keep these locks after discovery/repair. The action type in this case is OT_DISCOVER or OT_REPAIR. * Our attempt to acquire an MDL lock lead to a deadlock, detected by the MDL deadlock detector. The current @@ -3453,7 +3454,7 @@ request_backoff_action(enum_open_table_action action_arg, keep tables open between statements and a livelock is not possible. */ - if (action_arg != OT_REOPEN_TABLES && m_has_locks) + if (action_arg == OT_BACKOFF_AND_RETRY && m_has_locks) { my_error(ER_LOCK_DEADLOCK, MYF(0)); m_thd->mark_transaction_to_rollback(true); @@ -3482,6 +3483,32 @@ request_backoff_action(enum_open_table_action action_arg, /** + An error handler to mark transaction to rollback on DEADLOCK error + during DISCOVER / REPAIR. +*/ +class MDL_deadlock_discovery_repair_handler : public Internal_error_handler +{ +public: + virtual bool handle_condition(THD *thd, + uint sql_errno, + const char* sqlstate, + Sql_condition::enum_warning_level level, + const char* msg, + Sql_condition ** cond_hdl) + { + if (sql_errno == ER_LOCK_DEADLOCK) + { + thd->mark_transaction_to_rollback(true); + } + /* + We have marked this transaction to rollback. Return false to allow + error to be reported or handled by other handlers. + */ + return false; + } +}; + +/** Recover from failed attempt of open table by performing requested action. @pre This function should be called only with "action" != OT_NO_ACTION @@ -3495,6 +3522,12 @@ bool Open_table_context::recover_from_failed_open() { bool result= FALSE; + MDL_deadlock_discovery_repair_handler handler; + /* + Install error handler to mark transaction to rollback on DEADLOCK error. + */ + m_thd->push_internal_handler(&handler); + /* Execute the action. */ switch (m_action) { @@ -3530,7 +3563,12 @@ Open_table_context::recover_from_failed_open() result= FALSE; } - m_thd->mdl_context.release_transactional_locks(); + /* + Rollback to start of the current statement to release exclusive lock + on table which was discovered but preserve locks from previous statements + in current transaction. + */ + m_thd->mdl_context.rollback_to_savepoint(start_of_statement_svp()); break; } case OT_REPAIR: @@ -3543,12 +3581,18 @@ Open_table_context::recover_from_failed_open() m_failed_table->table_name, FALSE); result= auto_repair_table(m_thd, m_failed_table); - m_thd->mdl_context.release_transactional_locks(); + /* + Rollback to start of the current statement to release exclusive lock + on table which was discovered but preserve locks from previous statements + in current transaction. + */ + m_thd->mdl_context.rollback_to_savepoint(start_of_statement_svp()); break; } default: DBUG_ASSERT(0); } + m_thd->pop_internal_handler(); /* Reset the pointers to conflicting MDL request and the TABLE_LIST element, set when we need auto-discovery or repair, diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 5635e9ad4b7..e88f3b898e6 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -6269,6 +6269,8 @@ void THD::reset_for_next_command() thd->reset_current_stmt_binlog_format_row(); thd->binlog_unsafe_warning_flags= 0; + thd->save_prep_leaf_list= false; + DBUG_PRINT("debug", ("is_current_stmt_binlog_format_row(): %d", thd->is_current_stmt_binlog_format_row())); |