summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMonty <monty@mariadb.org>2020-03-30 20:12:02 +0300
committerMonty <monty@mariadb.org>2020-04-19 17:33:51 +0300
commitf9f33b85be6b5006f0ecd0de7961c71d415a9d73 (patch)
treeae547acc02c05876ccc9f54a3c7be614af206425
parent7866b723048d1d0f4a202d5a1e5475420b1dda64 (diff)
downloadmariadb-git-f9f33b85be6b5006f0ecd0de7961c71d415a9d73.tar.gz
Handle errors from external_unlock & mysql_unlock_tables
Other things: - Handler errors from ha_maria::implict_commit - Disable DBUG in safe_mutex_lock to get trace file easier to read
-rw-r--r--mysql-test/main/myisam_debug.result4
-rw-r--r--mysql-test/main/myisam_debug.test2
-rw-r--r--mysys/thr_mutex.c8
-rw-r--r--sql/handler.cc8
-rw-r--r--sql/lock.cc53
-rw-r--r--sql/lock.h10
-rw-r--r--sql/sql_base.cc26
-rw-r--r--sql/sql_base.h2
-rw-r--r--sql/sql_class.h4
-rw-r--r--sql/sql_parse.cc6
-rw-r--r--sql/sql_partition.cc9
-rw-r--r--sql/sql_select.cc7
-rw-r--r--sql/sql_table.cc12
-rw-r--r--sql/transaction.cc3
-rw-r--r--sql/wsrep_client_service.cc3
15 files changed, 101 insertions, 56 deletions
diff --git a/mysql-test/main/myisam_debug.result b/mysql-test/main/myisam_debug.result
index 650a3bcb787..10208a936a0 100644
--- a/mysql-test/main/myisam_debug.result
+++ b/mysql-test/main/myisam_debug.result
@@ -38,7 +38,9 @@ insert t1 values (1),(2),(1);
set @old_dbug=@@debug_dbug;
SET debug_dbug='+d,mi_lock_database_failure';
unlock tables;
-Warnings:
+ERROR HY000: Index for table './test/t1.MYI' is corrupt; try to repair it
+SHOW WARNINGS;
+Level Code Message
Error 126 Index for table './test/t1.MYI' is corrupt; try to repair it
Error 1030 Got error 22 "Invalid argument" from storage engine MyISAM
SET debug_dbug=@old_dbug;
diff --git a/mysql-test/main/myisam_debug.test b/mysql-test/main/myisam_debug.test
index 2861c344b10..fcb134c0400 100644
--- a/mysql-test/main/myisam_debug.test
+++ b/mysql-test/main/myisam_debug.test
@@ -67,6 +67,8 @@ lock tables t1 write;
insert t1 values (1),(2),(1);
set @old_dbug=@@debug_dbug;
SET debug_dbug='+d,mi_lock_database_failure';
+--error HA_ERR_CRASHED
unlock tables;
+SHOW WARNINGS;
SET debug_dbug=@old_dbug;
drop table t1;
diff --git a/mysys/thr_mutex.c b/mysys/thr_mutex.c
index 4f495048f63..9db1e0efabf 100644
--- a/mysys/thr_mutex.c
+++ b/mysys/thr_mutex.c
@@ -233,6 +233,7 @@ int safe_mutex_lock(safe_mutex_t *mp, myf my_flags, const char *file,
int error;
DBUG_PRINT("mutex", ("%s (0x%lx) locking", mp->name ? mp->name : "Null",
(ulong) mp));
+ DBUG_PUSH("");
pthread_mutex_lock(&mp->global);
if (!mp->file)
@@ -283,7 +284,7 @@ int safe_mutex_lock(safe_mutex_t *mp, myf my_flags, const char *file,
{
error= pthread_mutex_trylock(&mp->mutex);
if (error == EBUSY)
- return error;
+ goto end;
}
else
error= pthread_mutex_lock(&mp->mutex);
@@ -393,7 +394,10 @@ int safe_mutex_lock(safe_mutex_t *mp, myf my_flags, const char *file,
}
}
- DBUG_PRINT("mutex", ("%s (0x%lx) locked", mp->name, (ulong) mp));
+end:
+ DBUG_POP();
+ if (!error)
+ DBUG_PRINT("mutex", ("%s (0x%lx) locked", mp->name, (ulong) mp));
return error;
}
diff --git a/sql/handler.cc b/sql/handler.cc
index 5156ef6bb8e..2d3f64a7d2b 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -1532,7 +1532,13 @@ int ha_commit_trans(THD *thd, bool all)
}
#ifdef WITH_ARIA_STORAGE_ENGINE
- ha_maria::implicit_commit(thd, TRUE);
+ if ((error= ha_maria::implicit_commit(thd, TRUE)))
+ {
+ my_error(ER_ERROR_DURING_COMMIT, MYF(0), error);
+ ha_rollback_trans(thd, all);
+ DBUG_RETURN(1);
+ }
+
#endif
if (!ha_info)
diff --git a/sql/lock.cc b/sql/lock.cc
index 7f69946c35e..487f2c3115f 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -409,17 +409,18 @@ static int lock_external(THD *thd, TABLE **tables, uint count)
}
-void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock)
+int mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock)
{
- mysql_unlock_tables(thd, sql_lock,
- (thd->variables.option_bits & OPTION_TABLE_LOCK) ||
- !(sql_lock->flags & GET_LOCK_ON_THD));
+ return mysql_unlock_tables(thd, sql_lock,
+ (thd->variables.option_bits & OPTION_TABLE_LOCK) ||
+ !(sql_lock->flags & GET_LOCK_ON_THD));
}
-void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock, bool free_lock)
+int mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock, bool free_lock)
{
bool errors= thd->is_error();
+ int error= 0;
PSI_stage_info org_stage;
DBUG_ENTER("mysql_unlock_tables");
@@ -427,7 +428,7 @@ void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock, bool free_lock)
THD_STAGE_INFO(thd, stage_unlocking_tables);
if (sql_lock->table_count)
- unlock_external(thd, sql_lock->table, sql_lock->table_count);
+ error= unlock_external(thd, sql_lock->table, sql_lock->table_count);
if (sql_lock->lock_count)
thr_multi_unlock(sql_lock->locks, sql_lock->lock_count, 0);
if (free_lock)
@@ -435,10 +436,12 @@ void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock, bool free_lock)
DBUG_ASSERT(!(sql_lock->flags & GET_LOCK_ON_THD));
my_free(sql_lock);
}
- if (likely(!errors))
+ if (likely(!errors && !error))
thd->clear_error();
THD_STAGE_INFO(thd, org_stage);
- DBUG_VOID_RETURN;
+ if (error)
+ DBUG_PRINT("exit", ("error: %d", error));
+ DBUG_RETURN(error);
}
/**
@@ -447,12 +450,16 @@ void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock, bool free_lock)
This will work even if get_lock_data fails (next unlock will free all)
*/
-void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count, uint flag)
+int mysql_unlock_some_tables(THD *thd, TABLE **table,uint count, uint flag)
{
- MYSQL_LOCK *sql_lock=
- get_lock_data(thd, table, count, GET_LOCK_UNLOCK | GET_LOCK_ON_THD | flag);
- if (sql_lock)
- mysql_unlock_tables(thd, sql_lock, 0);
+ int error;
+ MYSQL_LOCK *sql_lock;
+ if (!(sql_lock= get_lock_data(thd, table, count,
+ GET_LOCK_UNLOCK | GET_LOCK_ON_THD | flag)))
+ error= ER_OUTOFMEMORY;
+ else
+ error= mysql_unlock_tables(thd, sql_lock, 0);
+ return error;
}
@@ -460,9 +467,10 @@ void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count, uint flag)
unlock all tables locked for read.
*/
-void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock)
+int mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock)
{
uint i,found;
+ int error= 0;
DBUG_ENTER("mysql_unlock_read_tables");
/* Call external lock for all tables to be unlocked */
@@ -482,7 +490,7 @@ void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock)
/* Unlock all read locked tables */
if (i != found)
{
- (void) unlock_external(thd,table,i-found);
+ error= unlock_external(thd,table,i-found);
sql_lock->table_count=found;
}
@@ -517,7 +525,7 @@ void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock)
found+= tbl->lock_count;
table++;
}
- DBUG_VOID_RETURN;
+ DBUG_RETURN(error);
}
@@ -531,8 +539,9 @@ void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock)
@param table the table to unlock
*/
-void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table)
+int mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table)
{
+ int error= 0;
if (locked)
{
uint i;
@@ -541,13 +550,20 @@ void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table)
if (locked->table[i] == table)
{
uint j, removed_locks, old_tables;
+ int tmp_error;
TABLE *tbl;
uint lock_data_end;
DBUG_ASSERT(table->lock_position == i);
/* Unlock the table. */
- mysql_unlock_some_tables(thd, &table, /* table count */ 1, 0);
+ if ((tmp_error= mysql_unlock_some_tables(thd, &table,
+ /* table count */ 1, 0)))
+ {
+ table->file->print_error(tmp_error, MYF(0));
+ if (!error)
+ error= tmp_error;
+ }
/* Decrement table_count in advance, making below expressions easier */
old_tables= --locked->table_count;
@@ -589,6 +605,7 @@ void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table)
}
}
}
+ return error;
}
diff --git a/sql/lock.h b/sql/lock.h
index e5036ea032c..0b23ddd3846 100644
--- a/sql/lock.h
+++ b/sql/lock.h
@@ -28,11 +28,11 @@ typedef struct st_mysql_lock MYSQL_LOCK;
MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **table, uint count, uint flags);
bool mysql_lock_tables(THD *thd, MYSQL_LOCK *sql_lock, uint flags);
-void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock, bool free_lock);
-void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock);
-void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock);
-void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count, uint flag);
-void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table);
+int mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock, bool free_lock);
+int mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock);
+int mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock);
+int mysql_unlock_some_tables(THD *thd, TABLE **table,uint count, uint flag);
+int mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table);
bool mysql_lock_abort_for_thread(THD *thd, TABLE *table);
MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b);
/* Lock based on name */
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 31e8fe45a5a..1b6d8834e7e 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -772,9 +772,10 @@ close_all_tables_for_name(THD *thd, TABLE_SHARE *share,
leave prelocked mode if needed.
*/
-void close_thread_tables(THD *thd)
+int close_thread_tables(THD *thd)
{
TABLE *table;
+ int error= 0;
DBUG_ENTER("close_thread_tables");
THD_STAGE_INFO(thd, stage_closing_tables);
@@ -874,7 +875,7 @@ void close_thread_tables(THD *thd)
we will exit this function a few lines below.
*/
if (! thd->lex->requires_prelocking())
- DBUG_VOID_RETURN;
+ DBUG_RETURN(0);
/*
We are in the top-level statement of a prelocked statement,
@@ -885,7 +886,7 @@ void close_thread_tables(THD *thd)
thd->locked_tables_mode= LTM_LOCK_TABLES;
if (thd->locked_tables_mode == LTM_LOCK_TABLES)
- DBUG_VOID_RETURN;
+ DBUG_RETURN(0);
thd->leave_locked_tables_mode();
@@ -904,7 +905,7 @@ void close_thread_tables(THD *thd)
binlog_query()) or when preparing a pending event.
*/
(void)thd->binlog_flush_pending_rows_event(TRUE);
- mysql_unlock_tables(thd, thd->lock);
+ error= mysql_unlock_tables(thd, thd->lock);
thd->lock=0;
}
/*
@@ -914,7 +915,7 @@ void close_thread_tables(THD *thd)
while (thd->open_tables)
(void) close_thread_table(thd, &thd->open_tables);
- DBUG_VOID_RETURN;
+ DBUG_RETURN(error);
}
@@ -2320,9 +2321,10 @@ Locked_tables_list::init_locked_tables(THD *thd)
@note This function is a no-op if we're not in LOCK TABLES.
*/
-void
+int
Locked_tables_list::unlock_locked_tables(THD *thd)
{
+ int error;
DBUG_ASSERT(!thd->in_sub_stmt &&
!(thd->state_flags & Open_tables_state::BACKUPS_AVAIL));
/*
@@ -2332,7 +2334,7 @@ Locked_tables_list::unlock_locked_tables(THD *thd)
open tables, e.g. from begin_trans().
*/
if (thd->locked_tables_mode != LTM_LOCK_TABLES)
- return;
+ return 0;
for (TABLE_LIST *table_list= m_locked_tables;
table_list; table_list= table_list->next_global)
@@ -2349,7 +2351,7 @@ Locked_tables_list::unlock_locked_tables(THD *thd)
TRANSACT_TRACKER(clear_trx_state(thd, TX_LOCKED_TABLES));
DBUG_ASSERT(thd->transaction.stmt.is_empty());
- close_thread_tables(thd);
+ error= close_thread_tables(thd);
/*
We rely on the caller to implicitly commit the
@@ -2361,6 +2363,7 @@ Locked_tables_list::unlock_locked_tables(THD *thd)
request for metadata locks and TABLE_LIST elements.
*/
reset();
+ return error;
}
@@ -2369,7 +2372,7 @@ Locked_tables_list::unlock_locked_tables(THD *thd)
table mode if there is no locked tables anymore
*/
-void
+int
Locked_tables_list::unlock_locked_table(THD *thd, MDL_ticket *mdl_ticket)
{
/*
@@ -2378,7 +2381,7 @@ Locked_tables_list::unlock_locked_table(THD *thd, MDL_ticket *mdl_ticket)
to check this condition here than in the caller.
*/
if (thd->locked_tables_mode != LTM_LOCK_TABLES)
- return;
+ return 0;
if (mdl_ticket)
{
@@ -2391,7 +2394,8 @@ Locked_tables_list::unlock_locked_table(THD *thd, MDL_ticket *mdl_ticket)
}
if (thd->lock->table_count == 0)
- unlock_locked_tables(thd);
+ return unlock_locked_tables(thd);
+ return 0;
}
diff --git a/sql/sql_base.h b/sql/sql_base.h
index 773b95b8317..0fdb2599ce4 100644
--- a/sql/sql_base.h
+++ b/sql/sql_base.h
@@ -160,7 +160,7 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table,
TABLE_LIST *TABLE_LIST::*link,
const LEX_CSTRING *db_name,
const LEX_CSTRING *table_name);
-void close_thread_tables(THD *thd);
+int close_thread_tables(THD *thd);
void switch_to_nullable_trigger_fields(List<Item> &items, TABLE *);
void switch_defaults_to_nullable_trigger_fields(TABLE *table);
bool fill_record_n_invoke_before_triggers(THD *thd, TABLE *table,
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 72a4722afbf..816935ba2ce 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1969,8 +1969,8 @@ public:
init_sql_alloc(key_memory_locked_table_list, &m_locked_tables_root,
MEM_ROOT_BLOCK_SIZE, 0, MYF(MY_THREAD_SPECIFIC));
}
- void unlock_locked_tables(THD *thd);
- void unlock_locked_table(THD *thd, MDL_ticket *mdl_ticket);
+ int unlock_locked_tables(THD *thd);
+ int unlock_locked_table(THD *thd, MDL_ticket *mdl_ticket);
~Locked_tables_list()
{
reset();
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index fb7002f701a..53ccdb5d4c3 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -5003,7 +5003,8 @@ mysql_execute_command(THD *thd)
if (thd->variables.option_bits & OPTION_TABLE_LOCK)
{
res= trans_commit_implicit(thd);
- thd->locked_tables_list.unlock_locked_tables(thd);
+ if (thd->locked_tables_list.unlock_locked_tables(thd))
+ res= 1;
thd->mdl_context.release_transactional_locks();
thd->variables.option_bits&= ~(OPTION_TABLE_LOCK);
}
@@ -5017,7 +5018,8 @@ mysql_execute_command(THD *thd)
case SQLCOM_LOCK_TABLES:
/* We must end the transaction first, regardless of anything */
res= trans_commit_implicit(thd);
- thd->locked_tables_list.unlock_locked_tables(thd);
+ if (thd->locked_tables_list.unlock_locked_tables(thd))
+ res= 1;
/* Release transactional metadata locks. */
thd->mdl_context.release_transactional_locks();
if (res)
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index ff1ddd200d0..d5915f65998 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -6778,20 +6778,21 @@ static bool alter_partition_lock_handling(ALTER_PARTITION_PARAM_TYPE *lpt)
@param lpt Struct carrying parameters
- @return Always 0.
+ @return error code if external_unlock fails
*/
static int alter_close_table(ALTER_PARTITION_PARAM_TYPE *lpt)
{
+ int error;
DBUG_ENTER("alter_close_table");
if (lpt->table->db_stat)
{
- mysql_lock_remove(lpt->thd, lpt->thd->lock, lpt->table);
- lpt->table->file->ha_close();
+ error= mysql_lock_remove(lpt->thd, lpt->thd->lock, lpt->table);
+ error= lpt->table->file->ha_close();
lpt->table->db_stat= 0; // Mark file closed
}
- DBUG_RETURN(0);
+ DBUG_RETURN(error);
}
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 1f05156b96f..da30fda40f7 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -2359,10 +2359,11 @@ int JOIN::optimize_stage2()
{
/*
Unlock all tables, except sequences, as accessing these may still
- require table updates
+ require table updates. It's safe to ignore result code as all
+ tables where opened for read only.
*/
- mysql_unlock_some_tables(thd, table, const_tables,
- GET_LOCK_SKIP_SEQUENCES);
+ (void) mysql_unlock_some_tables(thd, table, const_tables,
+ GET_LOCK_SKIP_SEQUENCES);
}
if (!conds && outer_join)
{
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 7c2875acda3..10f5e1f397e 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -2699,7 +2699,8 @@ err:
if (thd->lock && thd->lock->table_count == 0 &&
non_temp_tables_count > 0 && !dont_free_locks)
{
- thd->locked_tables_list.unlock_locked_tables(thd);
+ if (thd->locked_tables_list.unlock_locked_tables(thd))
+ error= 1;
goto end;
}
for (table= tables; table; table= table->next_local)
@@ -5406,7 +5407,7 @@ err:
Possible locked table was dropped. We should remove meta data locks
associated with it and do UNLOCK_TABLES if no more locked tables.
*/
- thd->locked_tables_list.unlock_locked_table(thd, mdl_ticket);
+ (void) thd->locked_tables_list.unlock_locked_table(thd, mdl_ticket);
}
else if (likely(!result) && create_info->table)
{
@@ -10608,8 +10609,10 @@ do_continue:;
if (thd->locked_tables_mode != LTM_LOCK_TABLES &&
thd->locked_tables_mode != LTM_PRELOCKED_UNDER_LOCK_TABLES)
{
- mysql_unlock_tables(thd, thd->lock);
+ int tmp_error= mysql_unlock_tables(thd, thd->lock);
thd->lock= NULL;
+ if (tmp_error)
+ goto err_new_table_cleanup;
}
else
{
@@ -10617,7 +10620,8 @@ do_continue:;
If LOCK TABLES list is not empty and contains this table,
unlock the table and remove the table from this list.
*/
- mysql_lock_remove(thd, thd->lock, table);
+ if (mysql_lock_remove(thd, thd->lock, table))
+ goto err_new_table_cleanup;
}
}
new_table->s->table_creation_was_logged=
diff --git a/sql/transaction.cc b/sql/transaction.cc
index db40bd6177b..c9fd211c1f8 100644
--- a/sql/transaction.cc
+++ b/sql/transaction.cc
@@ -103,7 +103,8 @@ bool trans_begin(THD *thd, uint flags)
if (trans_check(thd))
DBUG_RETURN(TRUE);
- thd->locked_tables_list.unlock_locked_tables(thd);
+ if (thd->locked_tables_list.unlock_locked_tables(thd))
+ DBUG_RETURN(true);
DBUG_ASSERT(!thd->locked_tables_mode);
diff --git a/sql/wsrep_client_service.cc b/sql/wsrep_client_service.cc
index 696a097db21..b9c59623e6c 100644
--- a/sql/wsrep_client_service.cc
+++ b/sql/wsrep_client_service.cc
@@ -320,7 +320,8 @@ int Wsrep_client_service::bf_rollback()
int ret= (trans_rollback_stmt(m_thd) || trans_rollback(m_thd));
if (m_thd->locked_tables_mode && m_thd->lock)
{
- m_thd->locked_tables_list.unlock_locked_tables(m_thd);
+ if (m_thd->locked_tables_list.unlock_locked_tables(m_thd))
+ ret= 1;
m_thd->variables.option_bits&= ~OPTION_TABLE_LOCK;
}
if (m_thd->global_read_lock.is_acquired())