summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorevgen@moonbone.local <>2007-07-30 18:10:34 +0400
committerevgen@moonbone.local <>2007-07-30 18:10:34 +0400
commit002696b64856d0895f6d6e9d396896fb06eb6ed8 (patch)
tree92ec199d176c507c6baabcd0d08b943fca421c55 /sql
parentb6bb988d12f7df7033cbb9cebc58036d264ad26e (diff)
parent8de5603d1d4678c9c6fbe0381674fd916fb2baef (diff)
downloadmariadb-git-002696b64856d0895f6d6e9d396896fb06eb6ed8.tar.gz
Merge epotemkin@bk-internal.mysql.com:/home/bk/mysql-5.0-opt
into moonbone.local:/mnt/gentoo64/work/24989-bug-5.0-opt-mysql
Diffstat (limited to 'sql')
-rw-r--r--sql/ha_innodb.cc12
-rw-r--r--sql/handler.cc5
-rw-r--r--sql/sp_rcontext.cc18
-rw-r--r--sql/sp_rcontext.h6
-rw-r--r--sql/sql_class.cc22
-rw-r--r--sql/sql_class.h30
6 files changed, 78 insertions, 15 deletions
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index 1c952f490da..585c825c710 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -455,9 +455,7 @@ convert_error_code_to_mysql(
tell it also to MySQL so that MySQL knows to empty the
cached binlog for this transaction */
- if (thd) {
- ha_rollback(thd);
- }
+ mark_transaction_to_rollback(thd, TRUE);
return(HA_ERR_LOCK_DEADLOCK);
@@ -467,9 +465,7 @@ convert_error_code_to_mysql(
latest SQL statement in a lock wait timeout. Previously, we
rolled back the whole transaction. */
- if (thd && row_rollback_on_timeout) {
- ha_rollback(thd);
- }
+ mark_transaction_to_rollback(thd, row_rollback_on_timeout);
return(HA_ERR_LOCK_WAIT_TIMEOUT);
@@ -521,9 +517,7 @@ convert_error_code_to_mysql(
tell it also to MySQL so that MySQL knows to empty the
cached binlog for this transaction */
- if (thd) {
- ha_rollback(thd);
- }
+ mark_transaction_to_rollback(thd, TRUE);
return(HA_ERR_LOCK_TABLE_FULL);
} else {
diff --git a/sql/handler.cc b/sql/handler.cc
index dcc9fde8b76..2285a190c8e 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -821,6 +821,9 @@ int ha_rollback_trans(THD *thd, bool all)
}
}
#endif /* USING_TRANSACTIONS */
+ if (all)
+ thd->transaction_rollback_request= FALSE;
+
/*
If a non-transactional table was updated, warn; don't warn if this is a
slave thread (because when a slave thread executes a ROLLBACK, it has
@@ -858,6 +861,8 @@ int ha_autocommit_or_rollback(THD *thd, int error)
if (ha_commit_stmt(thd))
error=1;
}
+ else if (thd->transaction_rollback_request && !thd->in_sub_stmt)
+ (void) ha_rollback(thd);
else
(void) ha_rollback_stmt(thd);
diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc
index e49c4eb1240..ac7c46c9fe5 100644
--- a/sql/sp_rcontext.cc
+++ b/sql/sp_rcontext.cc
@@ -37,6 +37,7 @@ sp_rcontext::sp_rcontext(sp_pcontext *root_parsing_ctx,
m_var_items(0),
m_return_value_fld(return_value_fld),
m_return_value_set(FALSE),
+ in_sub_stmt(FALSE),
m_hcount(0),
m_hsp(0),
m_ihsp(0),
@@ -67,6 +68,8 @@ sp_rcontext::~sp_rcontext()
bool sp_rcontext::init(THD *thd)
{
+ in_sub_stmt= thd->in_sub_stmt;
+
if (init_var_table(thd) || init_var_items())
return TRUE;
@@ -191,7 +194,7 @@ sp_rcontext::set_return_value(THD *thd, Item **return_value_item)
*/
bool
-sp_rcontext::find_handler(uint sql_errno,
+sp_rcontext::find_handler(THD *thd, uint sql_errno,
MYSQL_ERROR::enum_warning_level level)
{
if (m_hfound >= 0)
@@ -200,6 +203,15 @@ sp_rcontext::find_handler(uint sql_errno,
const char *sqlstate= mysql_errno_to_sqlstate(sql_errno);
int i= m_hcount, found= -1;
+ /*
+ If this is a fatal sub-statement error, and this runtime
+ context corresponds to a sub-statement, no CONTINUE/EXIT
+ handlers from this context are applicable: try to locate one
+ in the outer scope.
+ */
+ if (thd->is_fatal_sub_stmt_error && in_sub_stmt)
+ i= 0;
+
/* Search handlers from the latest (innermost) to the oldest (outermost) */
while (i--)
{
@@ -252,7 +264,7 @@ sp_rcontext::find_handler(uint sql_errno,
*/
if (m_prev_runtime_ctx && IS_EXCEPTION_CONDITION(sqlstate) &&
level == MYSQL_ERROR::WARN_LEVEL_ERROR)
- return m_prev_runtime_ctx->find_handler(sql_errno, level);
+ return m_prev_runtime_ctx->find_handler(thd, sql_errno, level);
return FALSE;
}
m_hfound= found;
@@ -298,7 +310,7 @@ sp_rcontext::handle_error(uint sql_errno,
elevated_level= MYSQL_ERROR::WARN_LEVEL_ERROR;
}
- if (find_handler(sql_errno, elevated_level))
+ if (find_handler(thd, sql_errno, elevated_level))
{
if (elevated_level == MYSQL_ERROR::WARN_LEVEL_ERROR)
{
diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h
index fbf479f52aa..0104b71a648 100644
--- a/sql/sp_rcontext.h
+++ b/sql/sp_rcontext.h
@@ -125,7 +125,7 @@ class sp_rcontext : public Sql_alloc
// Returns 1 if a handler was found, 0 otherwise.
bool
- find_handler(uint sql_errno,MYSQL_ERROR::enum_warning_level level);
+ find_handler(THD *thd, uint sql_errno,MYSQL_ERROR::enum_warning_level level);
// If there is an error handler for this error, handle it and return TRUE.
bool
@@ -236,6 +236,10 @@ private:
during execution.
*/
bool m_return_value_set;
+ /**
+ TRUE if the context is created for a sub-statement.
+ */
+ bool in_sub_stmt;
sp_handler_t *m_handler; // Visible handlers
uint m_hcount; // Stack pointer for m_handler
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index ee4e1ea149c..0650d4ba8c9 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -173,6 +173,7 @@ THD::THD()
Open_tables_state(refresh_version),
lock_id(&main_lock_id),
user_time(0), in_sub_stmt(0), global_read_lock(0), is_fatal_error(0),
+ transaction_rollback_request(0), is_fatal_sub_stmt_error(0),
rand_used(0), time_zone_used(0),
last_insert_id_used(0), last_insert_id_used_bin_log(0), insert_id_used(0),
clear_next_insert_id(0), in_lock_tables(0), bootstrap(0),
@@ -976,7 +977,7 @@ void select_send::abort()
{
DBUG_ENTER("select_send::abort");
if (status && thd->spcont &&
- thd->spcont->find_handler(thd->net.last_errno,
+ thd->spcont->find_handler(thd, thd->net.last_errno,
MYSQL_ERROR::WARN_LEVEL_ERROR))
{
/*
@@ -2211,6 +2212,13 @@ void THD::restore_sub_statement_state(Sub_statement_state *backup)
limit_found_rows= backup->limit_found_rows;
sent_row_count= backup->sent_row_count;
client_capabilities= backup->client_capabilities;
+ /*
+ If we've left sub-statement mode, reset the fatal error flag.
+ Otherwise keep the current value, to propagate it up the sub-statement
+ stack.
+ */
+ if (!in_sub_stmt)
+ is_fatal_sub_stmt_error= FALSE;
if ((options & OPTION_BIN_LOG) && is_update_query(lex->sql_command))
mysql_bin_log.stop_union_events(this);
@@ -2224,6 +2232,18 @@ void THD::restore_sub_statement_state(Sub_statement_state *backup)
}
+/**
+ Mark transaction to rollback and mark error as fatal to a sub-statement.
+
+ @param thd Thread handle
+ @param all TRUE <=> rollback main transaction.
+*/
+
+void mark_transaction_to_rollback(THD *thd, bool all)
+{
+ thd->is_fatal_sub_stmt_error= TRUE;
+ thd->transaction_rollback_request= all;
+}
/***************************************************************************
Handling of XA id cacheing
***************************************************************************/
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 058f130d4e7..ef719cdded7 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1421,7 +1421,33 @@ public:
bool slave_thread, one_shot_set;
bool locked, some_tables_deleted;
bool last_cuted_field;
- bool no_errors, password, is_fatal_error;
+ bool no_errors, password;
+ /**
+ Set to TRUE if execution of the current compound statement
+ can not continue. In particular, disables activation of
+ CONTINUE or EXIT handlers of stored routines.
+ Reset in the end of processing of the current user request, in
+ @see mysql_reset_thd_for_next_command().
+ */
+ bool is_fatal_error;
+ /**
+ Set by a storage engine to request the entire
+ transaction (that possibly spans multiple engines) to
+ rollback. Reset in ha_rollback.
+ */
+ bool transaction_rollback_request;
+ /**
+ TRUE if we are in a sub-statement and the current error can
+ not be safely recovered until we left the sub-statement mode.
+ In particular, disables activation of CONTINUE and EXIT
+ handlers inside sub-statements. E.g. if it is a deadlock
+ error and requires a transaction-wide rollback, this flag is
+ raised (traditionally, MySQL first has to close all the reads
+ via @see handler::ha_index_or_rnd_end() and only then perform
+ the rollback).
+ Reset to FALSE when we leave the sub-statement mode.
+ */
+ bool is_fatal_sub_stmt_error;
bool query_start_used, rand_used, time_zone_used;
/*
@@ -2397,3 +2423,5 @@ public:
/* Functions in sql_class.cc */
void add_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var);
+void mark_transaction_to_rollback(THD *thd, bool all);
+