From 8cf7e3459d7309ce122824146260c4aecfa6ca77 Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Thu, 6 Dec 2018 19:23:24 +0400 Subject: [PATCH] Moved early check for table existance to mysql_execute_command() MDEV-17772 - 3 way lock : ALTER, MDL, BACKUP STAGE BLOCK_DDL While waiting for a (potentially long) RO transaction or SELECT, DDL and LOCK TABLES ... WRITE hold protection against FTWRL and BACKUP STAGE. This effectively makes FTWRL/BACKUP STAGE indirectly wait for this RO transaction or SELECT to finish. Which is not great, as otherwise we could do something useful meanwhile. With this patch BACKUP lock is attempted to be acquired after TABLE/SCHEMA locks. If this attempt fails, TABLE/SCHEMA locks gets released and we start waiting for BACKUP lock. When wait finishes, BACKUP lock is released (to avoid deadlocks) and we attempt to acquire all locks once again. Other changes: - Take MDL lock before testing if table exists as part of CREATE TABLE ... IF EXISTS. This change was an effect of changes in lock_table_name and removes an inconsistency where one could get different error messages from CREATE TABLE .. IF EXISTS depending on active mdl locks. One effect of this change is that we don't binary log CREATE TABLE IF EXISTS if the table exists. This was done because old code was sometimes behaving inconsistenly (it was logged some time and not other times) and sending the query to the slave could make the slave even more inconsistent as there is not guarantee that the new table will have the same definition as the old table on the master. --- mysql-test/main/backup_lock.result | 6 +- mysql-test/main/backup_lock.test | 10 +- mysql-test/main/backup_lock_debug.result | 28 ++++ mysql-test/main/backup_lock_debug.test | 40 ++++++ mysql-test/main/create_drop_binlog.result | 4 - mysql-test/main/flush_read_lock.result | 30 +++- mysql-test/main/flush_read_lock.test | 41 +++++- mysql-test/main/mdl_sync.result | 69 --------- mysql-test/main/mdl_sync.test | 85 ------------ .../rpl/r/rpl_create_if_not_exists.result | 2 - sql/sql_base.cc | 131 +++++++++--------- sql/sql_yacc.yy | 2 +- sql/sql_yacc_ora.yy | 2 +- 13 files changed, 206 insertions(+), 244 deletions(-) create mode 100644 mysql-test/main/backup_lock_debug.result create mode 100644 mysql-test/main/backup_lock_debug.test diff --git a/mysql-test/main/backup_lock.result b/mysql-test/main/backup_lock.result index 40072aa0684..95b2f520d90 100644 --- a/mysql-test/main/backup_lock.result +++ b/mysql-test/main/backup_lock.result @@ -107,12 +107,10 @@ backup stage start; backup stage flush; SET STATEMENT lock_wait_timeout=0 FOR SELECT * FROM t1; ERROR HY000: Lock wait timeout exceeded; try restarting transaction -SET STATEMENT lock_wait_timeout=0 FOR backup stage block_ddl; -ERROR HY000: Lock wait timeout exceeded; try restarting transaction +backup stage block_ddl; SELECT LOCK_MODE, LOCK_TYPE, TABLE_SCHEMA, TABLE_NAME FROM information_schema.metadata_lock_info; LOCK_MODE LOCK_TYPE TABLE_SCHEMA TABLE_NAME -MDL_BACKUP_DDL Backup lock -MDL_BACKUP_FLUSH Backup lock +MDL_BACKUP_WAIT_DDL Backup lock MDL_SHARED_WRITE Table metadata lock test t1 MDL_INTENTION_EXCLUSIVE Schema metadata lock test backup stage end; diff --git a/mysql-test/main/backup_lock.test b/mysql-test/main/backup_lock.test index aafeb3a2d4b..d6db7a6364e 100644 --- a/mysql-test/main/backup_lock.test +++ b/mysql-test/main/backup_lock.test @@ -142,8 +142,7 @@ let $wait_condition= --error ER_LOCK_WAIT_TIMEOUT SET STATEMENT lock_wait_timeout=0 FOR SELECT * FROM t1; ---error ER_LOCK_WAIT_TIMEOUT -SET STATEMENT lock_wait_timeout=0 FOR backup stage block_ddl; +backup stage block_ddl; SELECT LOCK_MODE, LOCK_TYPE, TABLE_SCHEMA, TABLE_NAME FROM information_schema.metadata_lock_info; backup stage end; @@ -195,15 +194,10 @@ SET STATEMENT lock_wait_timeout=0 FOR DROP TABLE t1; connection con2; backup stage start; backup stage flush; ---send backup stage block_ddl +backup stage block_ddl; connection default; -let $wait_condition= - select count(*) = 1 from information_schema.processlist - where state = "Waiting for backup lock"; ---source include/wait_condition.inc commit; connection con2; ---reap backup stage end; connection con1; --reap # DROP TABLE diff --git a/mysql-test/main/backup_lock_debug.result b/mysql-test/main/backup_lock_debug.result new file mode 100644 index 00000000000..8832d9cd3e7 --- /dev/null +++ b/mysql-test/main/backup_lock_debug.result @@ -0,0 +1,28 @@ +# +# Make sure pending LOCK TABLES doesn't block BACKUP STAGE +# +CREATE TABLE t1(a INT); +LOCK TABLE t1 READ; +# +connect con1,localhost,root,,; +SET DEBUG_SYNC= 'mdl_acquire_lock_wait SIGNAL ready'; +LOCK TABLE t1 WRITE; +# +connect con2,localhost,root,,; +SET DEBUG_SYNC= 'now WAIT_FOR ready'; +BACKUP STAGE START; +BACKUP STAGE FLUSH; +BACKUP STAGE BLOCK_DDL; +BACKUP STAGE END; +disconnect con2; +# +connection default; +UNLOCK TABLES; +# +connection con1; +UNLOCK TABLES; +disconnect con1; +# +connection default; +DROP TABLE t1; +SET DEBUG_SYNC= 'RESET'; diff --git a/mysql-test/main/backup_lock_debug.test b/mysql-test/main/backup_lock_debug.test new file mode 100644 index 00000000000..8cf492b3404 --- /dev/null +++ b/mysql-test/main/backup_lock_debug.test @@ -0,0 +1,40 @@ +######################################################################## +# Tests for BACKUP STAGE locking that requires debug. +######################################################################## + +--source include/have_debug_sync.inc + +--echo # +--echo # Make sure pending LOCK TABLES doesn't block BACKUP STAGE +--echo # +CREATE TABLE t1(a INT); +LOCK TABLE t1 READ; + +--echo # +connect (con1,localhost,root,,); +SET DEBUG_SYNC= 'mdl_acquire_lock_wait SIGNAL ready'; +--send LOCK TABLE t1 WRITE + +--echo # +connect (con2,localhost,root,,); +SET DEBUG_SYNC= 'now WAIT_FOR ready'; +BACKUP STAGE START; +BACKUP STAGE FLUSH; +BACKUP STAGE BLOCK_DDL; +BACKUP STAGE END; +disconnect con2; + +--echo # +connection default; +UNLOCK TABLES; + +--echo # +connection con1; +reap; +UNLOCK TABLES; +disconnect con1; + +--echo # +connection default; +DROP TABLE t1; +SET DEBUG_SYNC= 'RESET'; diff --git a/mysql-test/main/create_drop_binlog.result b/mysql-test/main/create_drop_binlog.result index be40fcc140a..b8f8b61c359 100644 --- a/mysql-test/main/create_drop_binlog.result +++ b/mysql-test/main/create_drop_binlog.result @@ -322,8 +322,6 @@ Log_name Pos Event_type Server_id End_log_pos Info # # Gtid 1 # GTID #-#-# # # Query 1 # use `test`; CREATE TABLE t1(a INT, b INT) # # Gtid 1 # GTID #-#-# -# # Query 1 # use `test`; CREATE TABLE IF NOT EXISTS t1(a INT, b INT) -# # Gtid 1 # GTID #-#-# # # Query 1 # use `test`; CREATE OR REPLACE INDEX i1 ON t1(a) # # Gtid 1 # GTID #-#-# # # Query 1 # use `test`; CREATE OR REPLACE INDEX i1 ON t1(a) @@ -377,8 +375,6 @@ Log_name Pos Event_type Server_id End_log_pos Info # # Gtid 1 # GTID #-#-# # # Query 1 # use `test`; CREATE TABLE t1(a INT, b INT) # # Gtid 1 # GTID #-#-# -# # Query 1 # use `test`; CREATE TABLE IF NOT EXISTS t1(a INT, b INT) -# # Gtid 1 # GTID #-#-# # # Query 1 # use `test`; CREATE INDEX IF NOT EXISTS i1 ON t1(a) # # Gtid 1 # GTID #-#-# # # Query 1 # use `test`; CREATE INDEX IF NOT EXISTS i1 ON t1(a) diff --git a/mysql-test/main/flush_read_lock.result b/mysql-test/main/flush_read_lock.result index aa67ccdce55..33dc1092190 100644 --- a/mysql-test/main/flush_read_lock.result +++ b/mysql-test/main/flush_read_lock.result @@ -1693,13 +1693,39 @@ disconnect con2; # connection default; FLUSH TABLES WITH READ LOCK; +UNLOCK TABLES; +HANDLER t1 CLOSE; +# +connection con1; +UNLOCK TABLES; +disconnect con1; +# +connection default; +DROP TABLE t1; +SET DEBUG_SYNC= 'RESET'; +# +# Make sure pending LOCK TABLES doesn't block FTWRL +# +CREATE TABLE t1(a INT); +LOCK TABLE t1 READ; +# +connect con1,localhost,root,,; +SET DEBUG_SYNC= 'mdl_acquire_lock_wait SIGNAL ready'; +LOCK TABLE t1 WRITE; +# +connect con2,localhost,root,,; +SET DEBUG_SYNC= 'now WAIT_FOR ready'; +FLUSH TABLES WITH READ LOCK; +UNLOCK TABLES; +disconnect con2; +# +connection default; +UNLOCK TABLES; # connection con1; UNLOCK TABLES; disconnect con1; # connection default; -UNLOCK TABLES; -HANDLER t1 CLOSE; DROP TABLE t1; SET DEBUG_SYNC= 'RESET'; diff --git a/mysql-test/main/flush_read_lock.test b/mysql-test/main/flush_read_lock.test index 4fd79f42990..f39dbecf4a9 100644 --- a/mysql-test/main/flush_read_lock.test +++ b/mysql-test/main/flush_read_lock.test @@ -2037,7 +2037,43 @@ disconnect con2; --echo # connection default; ---send FLUSH TABLES WITH READ LOCK +FLUSH TABLES WITH READ LOCK; +UNLOCK TABLES; +HANDLER t1 CLOSE; + +--echo # +connection con1; +reap; +UNLOCK TABLES; +disconnect con1; + +--echo # +connection default; +DROP TABLE t1; +SET DEBUG_SYNC= 'RESET'; + + +--echo # +--echo # Make sure pending LOCK TABLES doesn't block FTWRL +--echo # +CREATE TABLE t1(a INT); +LOCK TABLE t1 READ; + +--echo # +connect (con1,localhost,root,,); +SET DEBUG_SYNC= 'mdl_acquire_lock_wait SIGNAL ready'; +--send LOCK TABLE t1 WRITE + +--echo # +connect (con2,localhost,root,,); +SET DEBUG_SYNC= 'now WAIT_FOR ready'; +FLUSH TABLES WITH READ LOCK; +UNLOCK TABLES; +disconnect con2; + +--echo # +connection default; +UNLOCK TABLES; --echo # connection con1; @@ -2047,8 +2083,5 @@ disconnect con1; --echo # connection default; -reap; -UNLOCK TABLES; -HANDLER t1 CLOSE; DROP TABLE t1; SET DEBUG_SYNC= 'RESET'; diff --git a/mysql-test/main/mdl_sync.result b/mysql-test/main/mdl_sync.result index 917b97d0295..5203fdddb2d 100644 --- a/mysql-test/main/mdl_sync.result +++ b/mysql-test/main/mdl_sync.result @@ -3124,72 +3124,3 @@ connection default; SET debug_sync='RESET'; DROP TABLE t1; disconnect con1; -# -# MDEV-5336 - Implement LOCK FOR BACKUP -# -# Make sure deadlock detector prefers FTWRL connection as a victim -# and FTWRL retries lock attempt. This deadlock was present before -# MDEV-5336. -CREATE TABLE t1(a INT) ENGINE=InnoDB; -CREATE TABLE t2(a INT) ENGINE=InnoDB; -BEGIN; -SELECT * FROM t2; -a -# -connect con1,localhost,root,,; -SET DEBUG_SYNC='mdl_acquire_lock_wait SIGNAL waiting'; -LOCK TABLES t2 WRITE; -# -connect con2,localhost,root,,; -SET DEBUG_SYNC='now WAIT_FOR waiting'; -SET DEBUG_SYNC='mdl_acquire_lock_wait SIGNAL waiting'; -FLUSH TABLES WITH READ LOCK; -# -connection default; -SET DEBUG_SYNC='now WAIT_FOR waiting'; -INSERT INTO t1 VALUES(1); -COMMIT; -connection con1; -UNLOCK TABLES; -connection con2; -UNLOCK TABLES; -connection default; -DROP TABLE t1, t2; -SET DEBUG_SYNC='RESET'; -disconnect con1; -disconnect con2; -# Make sure deadlock detector prefers FTWRL connection as a victim -# and FTWRL retries lock attempt. This deadlock was found during -# MDEV-5336 review. -CREATE TABLE t1(a INT) ENGINE=InnoDB; -CREATE TABLE t2(a INT) ENGINE=InnoDB; -BEGIN; -INSERT INTO t2 VALUES(1); -SET DEBUG_SYNC='after_open_table_mdl_shared SIGNAL table_opened WAIT_FOR go'; -INSERT INTO t1 VALUES(1); -# -connect con1,localhost,root,,; -SET DEBUG_SYNC='now WAIT_FOR table_opened'; -SET DEBUG_SYNC='mdl_acquire_lock_wait SIGNAL waiting'; -LOCK TABLES t1 WRITE; -# -connect con2,localhost,root,,; -SET DEBUG_SYNC='now WAIT_FOR waiting'; -SET DEBUG_SYNC='mdl_acquire_lock_wait SIGNAL waiting'; -FLUSH TABLES WITH READ LOCK; -# -connect con3,localhost,root,,; -SET DEBUG_SYNC='now WAIT_FOR waiting'; -SET DEBUG_SYNC='now SIGNAL go'; -connection default; -COMMIT; -connection con1; -UNLOCK TABLES; -connection con2; -UNLOCK TABLES; -connection default; -DROP TABLE t1, t2; -SET DEBUG_SYNC='RESET'; -disconnect con1; -disconnect con2; -disconnect con3; diff --git a/mysql-test/main/mdl_sync.test b/mysql-test/main/mdl_sync.test index a794dbf4a7a..185aedc0e9c 100644 --- a/mysql-test/main/mdl_sync.test +++ b/mysql-test/main/mdl_sync.test @@ -4168,91 +4168,6 @@ DROP TABLE t1; disconnect con1; - ---echo # ---echo # MDEV-5336 - Implement LOCK FOR BACKUP ---echo # - ---echo # Make sure deadlock detector prefers FTWRL connection as a victim ---echo # and FTWRL retries lock attempt. This deadlock was present before ---echo # MDEV-5336. -CREATE TABLE t1(a INT) ENGINE=InnoDB; -CREATE TABLE t2(a INT) ENGINE=InnoDB; -BEGIN; -SELECT * FROM t2; - ---echo # -connect(con1,localhost,root,,); -SET DEBUG_SYNC='mdl_acquire_lock_wait SIGNAL waiting'; -send LOCK TABLES t2 WRITE; - ---echo # -connect(con2,localhost,root,,); -SET DEBUG_SYNC='now WAIT_FOR waiting'; -SET DEBUG_SYNC='mdl_acquire_lock_wait SIGNAL waiting'; -send FLUSH TABLES WITH READ LOCK; - ---echo # -connection default; -SET DEBUG_SYNC='now WAIT_FOR waiting'; -INSERT INTO t1 VALUES(1); -COMMIT; - -connection con1; -reap; -UNLOCK TABLES; -connection con2; -reap; -UNLOCK TABLES; -connection default; -DROP TABLE t1, t2; -SET DEBUG_SYNC='RESET'; -disconnect con1; -disconnect con2; - ---echo # Make sure deadlock detector prefers FTWRL connection as a victim ---echo # and FTWRL retries lock attempt. This deadlock was found during ---echo # MDEV-5336 review. -CREATE TABLE t1(a INT) ENGINE=InnoDB; -CREATE TABLE t2(a INT) ENGINE=InnoDB; -BEGIN; -INSERT INTO t2 VALUES(1); -SET DEBUG_SYNC='after_open_table_mdl_shared SIGNAL table_opened WAIT_FOR go'; -send INSERT INTO t1 VALUES(1); - ---echo # -connect(con1,localhost,root,,); -SET DEBUG_SYNC='now WAIT_FOR table_opened'; -SET DEBUG_SYNC='mdl_acquire_lock_wait SIGNAL waiting'; -send LOCK TABLES t1 WRITE; - ---echo # -connect(con2,localhost,root,,); -SET DEBUG_SYNC='now WAIT_FOR waiting'; -SET DEBUG_SYNC='mdl_acquire_lock_wait SIGNAL waiting'; -send FLUSH TABLES WITH READ LOCK; - ---echo # -connect(con3,localhost,root,,); -SET DEBUG_SYNC='now WAIT_FOR waiting'; -SET DEBUG_SYNC='now SIGNAL go'; - -connection default; -reap; -COMMIT; -connection con1; -reap; -UNLOCK TABLES; -connection con2; -reap; -UNLOCK TABLES; -connection default; -DROP TABLE t1, t2; -SET DEBUG_SYNC='RESET'; -disconnect con1; -disconnect con2; -disconnect con3; - # Check that all connections opened by test cases in this file are really # gone so execution of other tests won't be affected by their presence. --source include/wait_until_count_sessions.inc diff --git a/mysql-test/suite/rpl/r/rpl_create_if_not_exists.result b/mysql-test/suite/rpl/r/rpl_create_if_not_exists.result index d74fd07189c..b31eacfc236 100644 --- a/mysql-test/suite/rpl/r/rpl_create_if_not_exists.result +++ b/mysql-test/suite/rpl/r/rpl_create_if_not_exists.result @@ -25,8 +25,6 @@ connection slave; connection slave; SHOW TABLES in mysqltest; Tables_in_mysqltest -t -t1 SHOW EVENTS in mysqltest; Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status Originator character_set_client collation_connection Database Collation mysqltest e root@localhost SYSTEM ONE TIME # NULL NULL NULL NULL SLAVESIDE_DISABLED 1 latin1 latin1_swedish_ci latin1_swedish_ci diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 45dea349af4..ccff8568973 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -3883,6 +3883,39 @@ end: } +static bool upgrade_lock_if_not_exists(THD *thd, + const DDL_options_st &create_info, + TABLE_LIST *create_table, + ulong lock_wait_timeout) +{ + DBUG_ENTER("upgrade_lock_if_not_exists"); + + if (thd->lex->sql_command == SQLCOM_CREATE_TABLE || + thd->lex->sql_command == SQLCOM_CREATE_SEQUENCE) + { + if (!create_info.or_replace() && + ha_table_exists(thd, &create_table->db, &create_table->table_name)) + { + if (create_info.if_not_exists()) + { + push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, + ER_TABLE_EXISTS_ERROR, + ER_THD(thd, ER_TABLE_EXISTS_ERROR), + create_table->table_name.str); + } + else + my_error(ER_TABLE_EXISTS_ERROR, MYF(0), create_table->table_name.str); + DBUG_RETURN(true); + } + DBUG_RETURN(thd->mdl_context.upgrade_shared_lock( + create_table->mdl_request.ticket, + MDL_EXCLUSIVE, + lock_wait_timeout)); + } + DBUG_RETURN(false); +} + + /** Acquire upgradable (SNW, SNRW) metadata locks on tables used by LOCK TABLES or by a DDL statement. Under LOCK TABLES, we can't take @@ -3920,10 +3953,7 @@ lock_table_names(THD *thd, const DDL_options_st &options, MDL_request_list mdl_requests; TABLE_LIST *table; MDL_request global_request; - ulong org_lock_wait_timeout= lock_wait_timeout; - /* Check if we are using CREATE TABLE ... IF NOT EXISTS */ - bool create_table; - Dummy_error_handler error_handler; + MDL_savepoint mdl_savepoint; DBUG_ENTER("lock_table_names"); DBUG_ASSERT(!thd->locked_tables_mode); @@ -3966,75 +3996,48 @@ lock_table_names(THD *thd, const DDL_options_st &options, if (mdl_requests.is_empty()) DBUG_RETURN(FALSE); - /* Check if CREATE TABLE without REPLACE was used */ - create_table= ((thd->lex->sql_command == SQLCOM_CREATE_TABLE || - thd->lex->sql_command == SQLCOM_CREATE_SEQUENCE) && - !options.or_replace()); - - if (!(flags & MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK)) + if (flags & MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK) { - /* - Protect this statement against concurrent global read lock - by acquiring global intention exclusive lock with statement - duration. - */ - if (thd->has_read_only_protection()) - DBUG_RETURN(TRUE); - global_request.init(MDL_key::BACKUP, "", "", MDL_BACKUP_DDL, - MDL_STATEMENT); - mdl_requests.push_front(&global_request); - - if (create_table) -#ifdef WITH_WSREP - if (thd->lex->sql_command != SQLCOM_CREATE_TABLE && - thd->wsrep_exec_mode != REPL_RECV) -#endif - lock_wait_timeout= 0; // Don't wait for timeout + DBUG_RETURN(thd->mdl_context.acquire_locks(&mdl_requests, + lock_wait_timeout) || + upgrade_lock_if_not_exists(thd, options, tables_start, + lock_wait_timeout)); } - for (;;) + /* Protect this statement against concurrent BACKUP STAGE or FTWRL. */ + if (thd->has_read_only_protection()) + DBUG_RETURN(true); + + global_request.init(MDL_key::BACKUP, "", "", MDL_BACKUP_DDL, MDL_STATEMENT); + mdl_savepoint= thd->mdl_context.mdl_savepoint(); + + while (!thd->mdl_context.acquire_locks(&mdl_requests, lock_wait_timeout) && + !upgrade_lock_if_not_exists(thd, options, tables_start, + lock_wait_timeout) && + !thd->mdl_context.try_acquire_lock(&global_request)) { - if (create_table) - thd->push_internal_handler(&error_handler); // Avoid warnings & errors - bool res= thd->mdl_context.acquire_locks(&mdl_requests, lock_wait_timeout); - if (!(flags & MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK)) - thd->mdl_backup_ticket= global_request.ticket; - if (create_table) - thd->pop_internal_handler(); - if (!res) - DBUG_RETURN(FALSE); // Got locks - - if (!create_table) - DBUG_RETURN(TRUE); // Return original error - - /* - We come here in the case of lock timeout when executing CREATE TABLE. - Verify that table does exist (it usually does, as we got a lock conflict) - */ - if (ha_table_exists(thd, &tables_start->db, &tables_start->table_name)) + if (global_request.ticket) { - if (options.if_not_exists()) - { - push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, - ER_TABLE_EXISTS_ERROR, - ER_THD(thd, ER_TABLE_EXISTS_ERROR), - tables_start->table_name.str); - } - else - my_error(ER_TABLE_EXISTS_ERROR, MYF(0), tables_start->table_name.str); - DBUG_RETURN(TRUE); + thd->mdl_backup_ticket= global_request.ticket; + DBUG_RETURN(false); } + /* - We got error from acquire_locks, but the table didn't exists. - This could happen if another connection runs a statement - involving this non-existent table, and this statement took the mdl, - but didn't error out with ER_NO_SUCH_TABLE yet (yes, a race condition). - We play safe and restart the original acquire_locks with the - original timeout. + There is ongoing or pending BACKUP STAGE or FTWRL. + Wait until it finishes and re-try. */ - create_table= 0; - lock_wait_timeout= org_lock_wait_timeout; + thd->mdl_context.rollback_to_savepoint(mdl_savepoint); + if (thd->mdl_context.acquire_lock(&global_request, lock_wait_timeout)) + break; + thd->mdl_context.rollback_to_savepoint(mdl_savepoint); + + /* Reset tickets for all acquired locks */ + global_request.ticket= 0; + MDL_request_list::Iterator it(mdl_requests); + while (auto mdl_request= it++) + mdl_request->ticket= 0; } + DBUG_RETURN(true); } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 3f416bc3445..fa8c15ac7e1 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -2648,7 +2648,7 @@ create: LEX *lex= thd->lex; if (!lex->first_select_lex()-> add_table_to_list(thd, $6, NULL, TL_OPTION_UPDATING, - TL_WRITE, MDL_EXCLUSIVE)) + TL_WRITE, MDL_SHARED_UPGRADABLE)) MYSQL_YYABORT; lex->alter_info.reset(); /* diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy index f3401f7e42d..27d3132be0d 100644 --- a/sql/sql_yacc_ora.yy +++ b/sql/sql_yacc_ora.yy @@ -2165,7 +2165,7 @@ create: LEX *lex= thd->lex; if (!lex->first_select_lex()-> add_table_to_list(thd, $6, NULL, TL_OPTION_UPDATING, - TL_WRITE, MDL_EXCLUSIVE)) + TL_WRITE, MDL_SHARED_UPGRADABLE)) MYSQL_YYABORT; lex->alter_info.reset(); /*