summaryrefslogtreecommitdiff
path: root/sql/sql_handler.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_handler.cc')
-rw-r--r--sql/sql_handler.cc102
1 files changed, 50 insertions, 52 deletions
diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc
index 7dcc6fa0e95..e117aa593b5 100644
--- a/sql/sql_handler.cc
+++ b/sql/sql_handler.cc
@@ -488,56 +488,6 @@ bool mysql_ha_close(THD *thd, TABLE_LIST *tables)
/**
- A helper class to process an error from mysql_lock_tables().
- HANDLER READ statement's attempt to lock the subject table
- may get aborted if there is a pending DDL. In that case
- we close the table, reopen it, and try to read again.
- This is implicit and obscure, since HANDLER position
- is lost in the process, but it's the legacy server
- behaviour we should preserve.
-*/
-
-class Sql_handler_lock_error_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);
-
- bool need_reopen() const { return m_need_reopen; };
- void init() { m_need_reopen= FALSE; };
-private:
- bool m_need_reopen;
-};
-
-
-/**
- Handle an error from mysql_lock_tables().
- Ignore ER_LOCK_ABORTED errors.
-*/
-
-bool
-Sql_handler_lock_error_handler::
-handle_condition(THD *thd,
- uint sql_errno,
- const char *sqlstate,
- Sql_condition::enum_warning_level level,
- const char* msg,
- Sql_condition **cond_hdl)
-{
- *cond_hdl= NULL;
- if (sql_errno == ER_LOCK_ABORTED)
- m_need_reopen= TRUE;
-
- return m_need_reopen;
-}
-
-
-/**
Finds an open HANDLER table.
@params name Name of handler to open
@@ -733,7 +683,8 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
int error, keyno;
uint num_rows;
uchar *UNINIT_VAR(key);
- Sql_handler_lock_error_handler sql_handler_lock_error;
+ MDL_deadlock_and_lock_abort_error_handler sql_handler_lock_error;
+ MDL_savepoint mdl_savepoint;
DBUG_ENTER("mysql_ha_read");
DBUG_PRINT("enter",("'%s'.'%s' as '%s'",
tables->db, tables->table_name, tables->alias));
@@ -752,6 +703,48 @@ retry:
tables->table= table; // This is used by fix_fields
table->pos_in_table_list= tables;
+ sql_handler_lock_error.init();
+
+ /*
+ For non-temporary tables we need to acquire SR lock in order to ensure
+ that HANDLER READ is blocked by LOCK TABLES WRITE in other connections
+ for storage engines which don't use THR_LOCK locks (e.g. InnoDB).
+
+ To simplify clean-up code we take MDL_savepoint even for temporary tables.
+ */
+ mdl_savepoint= thd->mdl_context.mdl_savepoint();
+
+ if (table->s->tmp_table == NO_TMP_TABLE)
+ {
+ MDL_request read_request;
+
+ read_request.init(&handler->mdl_request.key, MDL_SHARED_READ,
+ MDL_TRANSACTION);
+
+ thd->push_internal_handler(&sql_handler_lock_error);
+
+ error= thd->mdl_context.acquire_lock(&read_request,
+ thd->variables.lock_wait_timeout);
+ thd->pop_internal_handler();
+
+ if (sql_handler_lock_error.need_reopen())
+ {
+ /*
+ HANDLER READ statement's attempt to upgrade lock on the subject table
+ may get aborted if there is a pending DDL. In that case we close the
+ table, reopen it, and try to read again.
+ This is implicit and obscure, since HANDLER position is lost in the
+ process, but it's the legacy server behaviour we should preserve.
+ */
+ DBUG_ASSERT(error && !thd->is_error());
+ mysql_ha_close_table(handler);
+ goto retry;
+ }
+
+ if (error)
+ goto err0;
+ }
+
if (handler->lock->lock_count > 0)
{
int lock_error;
@@ -768,7 +761,7 @@ retry:
*/
thd->set_open_tables(table);
- sql_handler_lock_error.init();
+ /* Re-use Sql_handler_lock_error instance which was initialized earlier. */
thd->push_internal_handler(&sql_handler_lock_error);
lock_error= mysql_lock_tables(thd, handler->lock,
@@ -797,6 +790,7 @@ retry:
*/
DBUG_ASSERT(! thd->transaction_rollback_request);
trans_rollback_stmt(thd);
+ thd->mdl_context.rollback_to_savepoint(mdl_savepoint);
mysql_ha_close_table(handler);
if (thd->stmt_arena->is_stmt_execute())
{
@@ -812,7 +806,10 @@ retry:
}
if (lock_error)
+ {
+ thd->mdl_context.rollback_to_savepoint(mdl_savepoint);
goto err0; // mysql_lock_tables() printed error message already
+ }
}
if (mysql_ha_fix_cond_and_key(handler, mode, keyname, key_expr, cond, 0))
@@ -957,6 +954,7 @@ ok:
*/
trans_commit_stmt(thd);
mysql_unlock_tables(thd, handler->lock, 0);
+ thd->mdl_context.rollback_to_savepoint(mdl_savepoint);
my_eof(thd);
DBUG_PRINT("exit",("OK"));
DBUG_RETURN(FALSE);