summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorKonstantin Osipov <kostja@sun.com>2010-08-09 18:33:17 +0400
committerKonstantin Osipov <kostja@sun.com>2010-08-09 18:33:17 +0400
commitb1207bf1b83270e7440755d75fa549b480b56f82 (patch)
tree2e81c30f897a3775a6b130101a9c1ea96e97afbe /sql
parent8d0dc9b58bcb5f1cf13618eebe3fc6f60b8f2926 (diff)
parent7b7efa1261720e6c6ad76cbe9a5d922ba2dd7fc2 (diff)
downloadmariadb-git-b1207bf1b83270e7440755d75fa549b480b56f82.tar.gz
Merge 5.5-bugfixing -> 5.5-runtime.
Diffstat (limited to 'sql')
-rw-r--r--sql/CMakeLists.txt11
-rw-r--r--sql/item.cc4
-rw-r--r--sql/sp_head.cc193
-rw-r--r--sql/sp_pcontext.h7
-rw-r--r--sql/sp_rcontext.cc239
-rw-r--r--sql/sp_rcontext.h69
-rw-r--r--sql/sql_class.cc34
-rw-r--r--sql/sql_class.h29
-rw-r--r--sql/sql_delete.cc4
-rw-r--r--sql/sql_error.cc8
-rw-r--r--sql/sql_error.h16
-rw-r--r--sql/sql_insert.cc10
-rw-r--r--sql/sql_parse.cc4
-rw-r--r--sql/sql_select.cc2
-rw-r--r--sql/sql_signal.cc12
-rw-r--r--sql/sql_update.cc4
16 files changed, 305 insertions, 341 deletions
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt
index e8a594c4d8b..879e1bbed90 100644
--- a/sql/CMakeLists.txt
+++ b/sql/CMakeLists.txt
@@ -42,7 +42,6 @@ SET (SQL_SOURCE
../sql-common/client.c derror.cc des_key_file.cc
discover.cc ../libmysql/errmsg.c field.cc field_conv.cc
filesort.cc gstream.cc sha2.cc
- ha_partition.cc
handler.cc hash_filo.h sql_plugin_services.h
hostname.cc init.cc item.cc item_buff.cc item_cmpfunc.cc
item_create.cc item_func.cc item_geofunc.cc item_row.cc
@@ -266,18 +265,20 @@ IF(WIN32 AND MYSQLD_EXECUTABLE)
ENDIF()
MAKE_DIRECTORY(${CMAKE_CURRENT_BINARY_DIR}/data)
ADD_CUSTOM_COMMAND(
- OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/data/mysql/user.frm
+ OUTPUT initdb.dep
COMMAND ${CMAKE_COMMAND}
${CONFIG_PARAM} -P ${CMAKE_CURRENT_BINARY_DIR}/create_initial_db.cmake
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/data
+ COMMAND ${CMAKE_COMMAND} -E touch initdb.dep
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
DEPENDS mysqld
)
ADD_CUSTOM_TARGET(initial_database
ALL
- DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/data/mysql/user.frm
+ DEPENDS initdb.dep
)
- INSTALL(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/data DESTINATION . COMPONENT DataFiles
- PATTERN "bootstrap.sql" EXCLUDE)
+ INSTALL(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/data DESTINATION .
+ COMPONENT DataFiles PATTERN "initdb.dep" EXCLUDE PATTERN "bootstrap.sql" EXCLUDE)
ELSE()
# Not windows or cross compiling, just install an empty directory
INSTALL(FILES ${DUMMY_FILE} DESTINATION data/mysql)
diff --git a/sql/item.cc b/sql/item.cc
index 8210f4e6caf..1decb5ec426 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -7510,13 +7510,13 @@ String *Item_cache_datetime::val_str(String *str)
if (cached_field_type == MYSQL_TYPE_TIME)
{
ulonglong time= int_value;
- DBUG_ASSERT(time < TIME_MAX_VALUE);
+ DBUG_ASSERT(time <= TIME_MAX_VALUE);
set_zero_time(&ltime, MYSQL_TIMESTAMP_TIME);
ltime.second= time % 100;
time/= 100;
ltime.minute= time % 100;
time/= 100;
- ltime.hour= time % 100;
+ ltime.hour= time;
}
else
{
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 11f138e67be..2d3a32c7f7f 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -1076,6 +1076,104 @@ void sp_head::recursion_level_error(THD *thd)
/**
+ Find an SQL handler for any condition (warning or error) after execution
+ of a stored routine instruction. Basically, this function looks for an
+ appropriate SQL handler in RT-contexts. If an SQL handler is found, it is
+ remembered in the RT-context for future activation (the context can be
+ inactive at the moment).
+
+ If there is no pending condition, the function just returns.
+
+ If there was an error during the execution, an SQL handler for it will be
+ searched within the current and outer scopes.
+
+ There might be several errors in the Warning Info (that's possible by using
+ SIGNAL/RESIGNAL in nested scopes) -- the function is looking for an SQL
+ handler for the latest (current) error only.
+
+ If there was a warning during the execution, an SQL handler for it will be
+ searched within the current scope only.
+
+ If several warnings were thrown during the execution and there are different
+ SQL handlers for them, it is not determined which SQL handler will be chosen.
+ Only one SQL handler will be executed.
+
+ If warnings and errors were thrown during the execution, the error takes
+ precedence. I.e. error handler will be executed. If there is no handler
+ for that error, condition will remain unhandled.
+
+ Once a warning or an error has been handled it is not removed from
+ Warning Info.
+
+ According to The Standard (quoting PeterG):
+
+ An SQL procedure statement works like this ...
+ SQL/Foundation 13.5 <SQL procedure statement>
+ (General Rules) (greatly summarized) says:
+ (1) Empty diagnostics area, thus clearing the condition.
+ (2) Execute statement.
+ During execution, if Exception Condition occurs,
+ set Condition Area = Exception Condition and stop
+ statement.
+ During execution, if No Data occurs,
+ set Condition Area = No Data Condition and continue
+ statement.
+ During execution, if Warning occurs,
+ and Condition Area is not already full due to
+ an earlier No Data condition, set Condition Area
+ = Warning and continue statement.
+ (3) Finish statement.
+ At end of execution, if Condition Area is not
+ already full due to an earlier No Data or Warning,
+ set Condition Area = Successful Completion.
+ In effect, this system means there is a precedence:
+ Exception trumps No Data, No Data trumps Warning,
+ Warning trumps Successful Completion.
+
+ NB: "Procedure statements" include any DDL or DML or
+ control statements. So CREATE and DELETE and WHILE
+ and CALL and RETURN are procedure statements. But
+ DECLARE and END are not procedure statements.
+
+ @param thd thread handle
+ @param ctx runtime context of the stored routine
+*/
+
+static void
+find_handler_after_execution(THD *thd, sp_rcontext *ctx)
+{
+ if (thd->is_error())
+ {
+ ctx->find_handler(thd,
+ thd->stmt_da->sql_errno(),
+ thd->stmt_da->get_sqlstate(),
+ MYSQL_ERROR::WARN_LEVEL_ERROR,
+ thd->stmt_da->message());
+ }
+ else if (thd->warning_info->statement_warn_count())
+ {
+ List_iterator<MYSQL_ERROR> it(thd->warning_info->warn_list());
+ MYSQL_ERROR *err;
+ while ((err= it++))
+ {
+ if (err->get_level() != MYSQL_ERROR::WARN_LEVEL_WARN &&
+ err->get_level() != MYSQL_ERROR::WARN_LEVEL_NOTE)
+ continue;
+
+ if (ctx->find_handler(thd,
+ err->get_sql_errno(),
+ err->get_sqlstate(),
+ err->get_level(),
+ err->get_message_text()))
+ {
+ break;
+ }
+ }
+ }
+}
+
+
+/**
Execute the routine. The main instruction jump loop is there.
Assume the parameters already set.
@todo
@@ -1096,7 +1194,7 @@ sp_head::execute(THD *thd)
LEX_STRING saved_cur_db_name=
{ saved_cur_db_name_buf, sizeof(saved_cur_db_name_buf) };
bool cur_db_changed= FALSE;
- sp_rcontext *ctx;
+ sp_rcontext *ctx= thd->spcont;
bool err_status= FALSE;
uint ip= 0;
ulong save_sql_mode;
@@ -1157,8 +1255,6 @@ sp_head::execute(THD *thd)
goto done;
}
- if ((ctx= thd->spcont))
- ctx->clear_handler();
thd->is_slave_error= 0;
old_arena= thd->stmt_arena;
@@ -1243,7 +1339,6 @@ sp_head::execute(THD *thd)
do
{
sp_instr *i;
- uint hip;
#if defined(ENABLED_PROFILING)
/*
@@ -1265,6 +1360,9 @@ sp_head::execute(THD *thd)
break;
}
+ /* Reset number of warnings for this query. */
+ thd->warning_info->reset_for_next_command();
+
DBUG_PRINT("execute", ("Instruction %u", ip));
/*
@@ -1309,40 +1407,28 @@ sp_head::execute(THD *thd)
free_root(&execute_mem_root, MYF(0));
/*
- Check if an exception has occurred and a handler has been found
- Note: We have to check even if err_status == FALSE, since warnings (and
- some errors) don't return a non-zero value. We also have to check even
- if thd->killed != 0, since some errors return with this even when a
- handler has been found (e.g. "bad data").
+ Find and process SQL handlers unless it is a fatal error (fatal
+ errors are not catchable by SQL handlers) or the connection has been
+ killed during execution.
*/
- if (ctx)
+ if (!thd->is_fatal_error && !thd->killed_errno())
{
- uint handler_index;
+ /*
+ Find SQL handler in the appropriate RT-contexts:
+ - warnings can be handled by SQL handlers within
+ the current scope only;
+ - errors can be handled by any SQL handler from outer scope.
+ */
+ find_handler_after_execution(thd, ctx);
- switch (ctx->found_handler(& hip, & handler_index)) {
- case SP_HANDLER_NONE:
- break;
- case SP_HANDLER_CONTINUE:
- thd->restore_active_arena(&execute_arena, &backup_arena);
- thd->set_n_backup_active_arena(&execute_arena, &backup_arena);
- ctx->push_hstack(i->get_cont_dest());
- /* Fall through */
- default:
- if (ctx->end_partial_result_set)
- thd->protocol->end_partial_result_set(thd);
- ip= hip;
+ /* If found, activate handler for the current scope. */
+ if (ctx->activate_handler(thd, &ip, i, &execute_arena, &backup_arena))
err_status= FALSE;
- ctx->clear_handler();
- ctx->enter_handler(hip, handler_index);
- thd->clear_error();
- thd->is_fatal_error= 0;
- thd->killed= THD::NOT_KILLED;
- thd->mysys_var->abort= 0;
- continue;
- }
-
- ctx->end_partial_result_set= FALSE;
}
+
+ /* Reset sp_rcontext::end_partial_result_set flag. */
+ ctx->end_partial_result_set= FALSE;
+
} while (!err_status && !thd->killed && !thd->is_fatal_error);
#if defined(ENABLED_PROFILING)
@@ -3037,23 +3123,14 @@ sp_instr_set::exec_core(THD *thd, uint *nextp)
{
int res= thd->spcont->set_variable(thd, m_offset, &m_value);
- if (res && thd->spcont->found_handler_here())
+ if (res)
{
- /*
- Failed to evaluate the value, and a handler has been found. Reset the
- variable to NULL.
- */
+ /* Failed to evaluate the value. Reset the variable to NULL. */
if (thd->spcont->set_variable(thd, m_offset, 0))
{
/* If this also failed, let's abort. */
-
- sp_rcontext *spcont= thd->spcont;
-
- thd->spcont= NULL; /* Avoid handlers */
- my_error(ER_OUT_OF_RESOURCES, MYF(0));
- spcont->clear_handler();
- thd->spcont= spcont;
+ my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR));
}
}
@@ -3586,18 +3663,6 @@ sp_instr_copen::execute(THD *thd, uint *nextp)
if (thd->stmt_arena->free_list)
cleanup_items(thd->stmt_arena->free_list);
thd->stmt_arena= old_arena;
- /*
- Work around the fact that errors in selects are not returned properly
- (but instead converted into a warning), so if a condition handler
- caught, we have lost the result code.
- */
- if (!res)
- {
- uint dummy1, dummy2;
-
- if (thd->spcont->found_handler(&dummy1, &dummy2))
- res= -1;
- }
/* TODO: Assert here that we either have an error or a cursor */
}
DBUG_RETURN(res);
@@ -3773,13 +3838,11 @@ sp_instr_set_case_expr::exec_core(THD *thd, uint *nextp)
{
int res= thd->spcont->set_case_expr(thd, m_case_expr_id, &m_case_expr);
- if (res &&
- !thd->spcont->get_case_expr(m_case_expr_id) &&
- thd->spcont->found_handler_here())
+ if (res && !thd->spcont->get_case_expr(m_case_expr_id))
{
/*
Failed to evaluate the value, the case expression is still not
- initialized, and a handler has been found. Set to NULL so we can continue.
+ initialized. Set to NULL so we can continue.
*/
Item *null_item= new Item_null();
@@ -3788,13 +3851,7 @@ sp_instr_set_case_expr::exec_core(THD *thd, uint *nextp)
thd->spcont->set_case_expr(thd, m_case_expr_id, &null_item))
{
/* If this also failed, we have to abort. */
-
- sp_rcontext *spcont= thd->spcont;
-
- thd->spcont= NULL; /* Avoid handlers */
- my_error(ER_OUT_OF_RESOURCES, MYF(0));
- spcont->clear_handler();
- thd->spcont= spcont;
+ my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR));
}
}
else
diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h
index b12d5362c6b..c27c7d22da2 100644
--- a/sql/sp_pcontext.h
+++ b/sql/sp_pcontext.h
@@ -332,13 +332,6 @@ public:
int
push_cond(LEX_STRING *name, sp_cond_type_t *val);
- inline void
- pop_cond(uint num)
- {
- while (num--)
- pop_dynamic(&m_conds);
- }
-
sp_cond_type_t *
find_cond(LEX_STRING *name, my_bool scoped=0);
diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc
index b08f8008b59..e76a5e9ebde 100644
--- a/sql/sp_rcontext.cc
+++ b/sql/sp_rcontext.cc
@@ -171,48 +171,50 @@ sp_rcontext::set_return_value(THD *thd, Item **return_value_item)
#define IS_NOT_FOUND_CONDITION(S) ((S)[0] == '0' && (S)[1] == '2')
#define IS_EXCEPTION_CONDITION(S) ((S)[0] != '0' || (S)[1] > '2')
-/*
- Find a handler for the given errno.
- This is called from all error message functions (e.g. push_warning,
- net_send_error, et al) when a sp_rcontext is in effect. If a handler
- is found, no error is sent, and the the SP execution loop will instead
- invoke the found handler.
- This might be called several times before we get back to the execution
- loop, so m_hfound can be >= 0 if a handler has already been found.
- (In which case we don't search again - the first found handler will
- be used.)
- Handlers are pushed on the stack m_handler, with the latest/innermost
+/**
+ Find an SQL handler for the given error.
+
+ SQL handlers are pushed on the stack m_handler, with the latest/innermost
one on the top; we then search for matching handlers from the top and
down.
+
We search through all the handlers, looking for the most specific one
(sql_errno more specific than sqlstate more specific than the rest).
Note that mysql error code handlers is a MySQL extension, not part of
the standard.
- SYNOPSIS
- sql_errno The error code
- level Warning level
+ SQL handlers for warnings are searched in the current scope only.
- RETURN
- 1 if a handler was found, m_hfound is set to its index (>= 0)
- 0 if not found, m_hfound is -1
+ SQL handlers for errors are searched in the current and in outer scopes.
+ That's why finding and activation of handler must be separated: an errror
+ handler might be located in the outer scope, which is not active at the
+ moment. Before such handler can be activated, execution flow should
+ unwind to that scope.
+
+ Found SQL handler is remembered in m_hfound for future activation.
+ If no handler is found, m_hfound is -1.
+
+ @param thd Thread handle
+ @param sql_errno The error code
+ @param sqlstate The error SQL state
+ @param level The error level
+ @param msg The error message
+
+ @retval TRUE if an SQL handler was found
+ @retval FALSE otherwise
*/
bool
sp_rcontext::find_handler(THD *thd,
uint sql_errno,
- const char* sqlstate,
+ const char *sqlstate,
MYSQL_ERROR::enum_warning_level level,
- const char* msg,
- MYSQL_ERROR ** cond_hdl)
+ const char *msg)
{
- if (m_hfound >= 0)
- {
- *cond_hdl= NULL;
- return TRUE; // Already got one
- }
+ int i= m_hcount;
- int i= m_hcount, found= -1;
+ /* Reset previously found handler. */
+ m_hfound= -1;
/*
If this is a fatal sub-statement error, and this runtime
@@ -240,105 +242,56 @@ sp_rcontext::find_handler(THD *thd,
{
case sp_cond_type_t::number:
if (sql_errno == cond->mysqlerr &&
- (found < 0 || m_handler[found].cond->type > sp_cond_type_t::number))
- found= i; // Always the most specific
+ (m_hfound < 0 || m_handler[m_hfound].cond->type > sp_cond_type_t::number))
+ m_hfound= i; // Always the most specific
break;
case sp_cond_type_t::state:
if (strcmp(sqlstate, cond->sqlstate) == 0 &&
- (found < 0 || m_handler[found].cond->type > sp_cond_type_t::state))
- found= i;
+ (m_hfound < 0 || m_handler[m_hfound].cond->type > sp_cond_type_t::state))
+ m_hfound= i;
break;
case sp_cond_type_t::warning:
if ((IS_WARNING_CONDITION(sqlstate) ||
level == MYSQL_ERROR::WARN_LEVEL_WARN) &&
- found < 0)
- found= i;
+ m_hfound < 0)
+ m_hfound= i;
break;
case sp_cond_type_t::notfound:
- if (IS_NOT_FOUND_CONDITION(sqlstate) && found < 0)
- found= i;
+ if (IS_NOT_FOUND_CONDITION(sqlstate) && m_hfound < 0)
+ m_hfound= i;
break;
case sp_cond_type_t::exception:
if (IS_EXCEPTION_CONDITION(sqlstate) &&
level == MYSQL_ERROR::WARN_LEVEL_ERROR &&
- found < 0)
- found= i;
+ m_hfound < 0)
+ m_hfound= i;
break;
}
}
- if (found < 0)
- {
- /*
- Only "exception conditions" are propagated to handlers in calling
- contexts. If no handler is found locally for a "completion condition"
- (warning or "not found") we will simply resume execution.
- */
- if (m_prev_runtime_ctx && IS_EXCEPTION_CONDITION(sqlstate) &&
- level == MYSQL_ERROR::WARN_LEVEL_ERROR)
- return m_prev_runtime_ctx->find_handler(thd,
- sql_errno,
- sqlstate,
- level,
- msg,
- cond_hdl);
- *cond_hdl= NULL;
- return FALSE;
- }
-
- m_hfound= found;
- MYSQL_ERROR *raised= NULL;
- DBUG_ASSERT(m_hfound >= 0);
- DBUG_ASSERT((uint) m_hfound < m_root_parsing_ctx->max_handler_index());
- raised= & m_raised_conditions[m_hfound];
- raised->clear();
- raised->set(sql_errno, sqlstate, level, msg);
-
- *cond_hdl= raised;
- return TRUE;
-}
-
-/*
- Handle the error for a given errno.
- The severity of the error is adjusted depending of the current sql_mode.
- If an handler is present for the error (see find_handler()),
- this function will return true.
- If a handler is found and if the severity of the error indicate
- that the current instruction executed should abort,
- the flag thd->net.report_error is also set.
- This will cause the execution of the current instruction in a
- sp_instr* to fail, and give control to the handler code itself
- in the sp_head::execute() loop.
-
- SYNOPSIS
- sql_errno The error code
- level Warning level
- thd The current thread
+ if (m_hfound >= 0)
+ {
+ DBUG_ASSERT((uint) m_hfound < m_root_parsing_ctx->max_handler_index());
- RETURN
- TRUE if a handler was found.
- FALSE if no handler was found.
-*/
-bool
-sp_rcontext::handle_condition(THD *thd,
- uint sql_errno,
- const char* sqlstate,
- MYSQL_ERROR::enum_warning_level level,
- const char* msg,
- MYSQL_ERROR ** cond_hdl)
-{
- MYSQL_ERROR::enum_warning_level elevated_level= level;
+ m_raised_conditions[m_hfound].clear();
+ m_raised_conditions[m_hfound].set(sql_errno, sqlstate, level, msg);
+ return TRUE;
+ }
- /* Depending on the sql_mode of execution,
- warnings may be considered errors */
- if ((level == MYSQL_ERROR::WARN_LEVEL_WARN) &&
- thd->really_abort_on_warning())
+ /*
+ Only "exception conditions" are propagated to handlers in calling
+ contexts. If no handler is found locally for a "completion condition"
+ (warning or "not found") we will simply resume execution.
+ */
+ if (m_prev_runtime_ctx && IS_EXCEPTION_CONDITION(sqlstate) &&
+ level == MYSQL_ERROR::WARN_LEVEL_ERROR)
{
- elevated_level= MYSQL_ERROR::WARN_LEVEL_ERROR;
+ return m_prev_runtime_ctx->find_handler(thd, sql_errno, sqlstate,
+ level, msg);
}
- return find_handler(thd, sql_errno, sqlstate, elevated_level, msg, cond_hdl);
+ return FALSE;
}
void
@@ -384,7 +337,9 @@ sp_rcontext::pop_handlers(uint count)
{
DBUG_ENTER("sp_rcontext::pop_handlers");
DBUG_ASSERT(m_hcount >= count);
+
m_hcount-= count;
+
DBUG_PRINT("info", ("m_hcount: %d", m_hcount));
DBUG_VOID_RETURN;
}
@@ -394,7 +349,9 @@ sp_rcontext::push_hstack(uint h)
{
DBUG_ENTER("sp_rcontext::push_hstack");
DBUG_ASSERT(m_hsp < m_root_parsing_ctx->max_handler_index());
+
m_hstack[m_hsp++]= h;
+
DBUG_PRINT("info", ("m_hsp: %d", m_hsp));
DBUG_VOID_RETURN;
}
@@ -405,21 +362,74 @@ sp_rcontext::pop_hstack()
uint handler;
DBUG_ENTER("sp_rcontext::pop_hstack");
DBUG_ASSERT(m_hsp);
+
handler= m_hstack[--m_hsp];
+
DBUG_PRINT("info", ("m_hsp: %d", m_hsp));
DBUG_RETURN(handler);
}
-void
-sp_rcontext::enter_handler(uint hip, uint hindex)
+/**
+ Prepare found handler to be executed.
+
+ @retval TRUE if an SQL handler is activated (was found) and IP of the
+ first handler instruction.
+ @retval FALSE if there is no active handler
+*/
+
+bool
+sp_rcontext::activate_handler(THD *thd,
+ uint *ip,
+ sp_instr *instr,
+ Query_arena *execute_arena,
+ Query_arena *backup_arena)
{
- DBUG_ENTER("sp_rcontext::enter_handler");
- DBUG_ASSERT(m_ihsp < m_root_parsing_ctx->max_handler_index());
- m_in_handler[m_ihsp].ip= hip;
- m_in_handler[m_ihsp].index= hindex;
- m_ihsp++;
- DBUG_PRINT("info", ("m_ihsp: %d", m_ihsp));
- DBUG_VOID_RETURN;
+ if (m_hfound < 0)
+ return FALSE;
+
+ switch (m_handler[m_hfound].type) {
+ case SP_HANDLER_NONE:
+ break;
+
+ case SP_HANDLER_CONTINUE:
+ thd->restore_active_arena(execute_arena, backup_arena);
+ thd->set_n_backup_active_arena(execute_arena, backup_arena);
+ push_hstack(instr->get_cont_dest());
+
+ /* Fall through */
+
+ default:
+ /* End aborted result set. */
+
+ if (end_partial_result_set)
+ thd->protocol->end_partial_result_set(thd);
+
+ /* Enter handler. */
+
+ DBUG_ASSERT(m_ihsp < m_root_parsing_ctx->max_handler_index());
+ DBUG_ASSERT(m_hfound >= 0);
+
+ m_in_handler[m_ihsp].ip= m_handler[m_hfound].handler;
+ m_in_handler[m_ihsp].index= m_hfound;
+ m_ihsp++;
+
+ DBUG_PRINT("info", ("Entering handler..."));
+ DBUG_PRINT("info", ("m_ihsp: %d", m_ihsp));
+
+ /* Reset error state. */
+
+ thd->clear_error();
+ thd->killed= THD::NOT_KILLED; // Some errors set thd->killed
+ // (e.g. "bad data").
+
+ /* Return IP of the activated SQL handler. */
+ *ip= m_handler[m_hfound].handler;
+
+ /* Reset found handler. */
+ m_hfound= -1;
+ }
+
+ return TRUE;
}
void
@@ -427,9 +437,11 @@ sp_rcontext::exit_handler()
{
DBUG_ENTER("sp_rcontext::exit_handler");
DBUG_ASSERT(m_ihsp);
+
uint hindex= m_in_handler[m_ihsp-1].index;
m_raised_conditions[hindex].clear();
m_ihsp-= 1;
+
DBUG_PRINT("info", ("m_ihsp: %d", m_ihsp));
DBUG_VOID_RETURN;
}
@@ -567,6 +579,11 @@ sp_cursor::fetch(THD *thd, List<struct sp_variable> *vars)
return -1;
}
+ DBUG_EXECUTE_IF("bug23032_emit_warning",
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_UNKNOWN_ERROR,
+ ER(ER_UNKNOWN_ERROR)););
+
result.set_spvar_list(vars);
/* Attempt to fetch one row */
diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h
index fad253706cb..1af758ed0af 100644
--- a/sql/sp_rcontext.h
+++ b/sql/sp_rcontext.h
@@ -131,67 +131,40 @@ class sp_rcontext : public Sql_alloc
return m_return_value_set;
}
+ /*
+ SQL handlers support.
+ */
+
void push_handler(struct sp_cond_type *cond, uint h, int type);
void pop_handlers(uint count);
- // Returns 1 if a handler was found, 0 otherwise.
bool
find_handler(THD *thd,
uint sql_errno,
- const char* sqlstate,
+ const char *sqlstate,
MYSQL_ERROR::enum_warning_level level,
- const char* msg,
- MYSQL_ERROR ** cond_hdl);
+ const char *msg);
- // If there is an error handler for this error, handle it and return TRUE.
- bool
- handle_condition(THD *thd,
- uint sql_errno,
- const char* sqlstate,
- MYSQL_ERROR::enum_warning_level level,
- const char* msg,
- MYSQL_ERROR ** cond_hdl);
-
- // Returns handler type and sets *ip to location if one was found
- inline int
- found_handler(uint *ip, uint *index)
- {
- if (m_hfound < 0)
- return SP_HANDLER_NONE;
- *ip= m_handler[m_hfound].handler;
- *index= m_hfound;
- return m_handler[m_hfound].type;
- }
-
- MYSQL_ERROR* raised_condition() const;
-
- // Returns true if we found a handler in this context
- inline bool
- found_handler_here()
- {
- return (m_hfound >= 0);
- }
+ MYSQL_ERROR *
+ raised_condition() const;
- // Clears the handler find state
- inline void
- clear_handler()
- {
- m_hfound= -1;
- }
+ void
+ push_hstack(uint h);
- void push_hstack(uint h);
+ uint
+ pop_hstack();
- uint pop_hstack();
+ bool
+ activate_handler(THD *thd,
+ uint *ip,
+ sp_instr *instr,
+ Query_arena *execute_arena,
+ Query_arena *backup_arena);
- /**
- Enter a SQL exception handler.
- @param hip the handler instruction pointer
- @param index the handler index
- */
- void enter_handler(uint hip, uint index);
- void exit_handler();
+ void
+ exit_handler();
void
push_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i);
@@ -199,7 +172,7 @@ class sp_rcontext : public Sql_alloc
void
pop_cursors(uint count);
- void
+ inline void
pop_all_cursors()
{
pop_cursors(m_ccount);
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 1ff2ba59093..60a871e9e88 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -845,35 +845,6 @@ MYSQL_ERROR* THD::raise_condition(uint sql_errno,
}
}
- /*
- If a continue handler is found, the error message will be cleared
- by the stored procedures code.
- */
- if (!is_fatal_error && spcont &&
- spcont->handle_condition(this, sql_errno, sqlstate, level, msg, &cond))
- {
- /*
- Do not push any warnings, a handled error must be completely
- silenced.
- */
- DBUG_RETURN(cond);
- }
-
- /* Un-handled conditions */
-
- cond= raise_condition_no_handler(sql_errno, sqlstate, level, msg);
- DBUG_RETURN(cond);
-}
-
-MYSQL_ERROR*
-THD::raise_condition_no_handler(uint sql_errno,
- const char* sqlstate,
- MYSQL_ERROR::enum_warning_level level,
- const char* msg)
-{
- MYSQL_ERROR *cond= NULL;
- DBUG_ENTER("THD::raise_condition_no_handler");
-
query_cache_abort(&query_cache_tls);
/* FIXME: broken special case */
@@ -886,6 +857,7 @@ THD::raise_condition_no_handler(uint sql_errno,
cond= warning_info->push_warning(this, sql_errno, sqlstate, level, msg);
DBUG_RETURN(cond);
}
+
extern "C"
void *thd_alloc(MYSQL_THD thd, unsigned int size)
{
@@ -1737,9 +1709,9 @@ bool select_send::send_result_set_metadata(List<Item> &list, uint flags)
return res;
}
-void select_send::abort()
+void select_send::abort_result_set()
{
- DBUG_ENTER("select_send::abort");
+ DBUG_ENTER("select_send::abort_result_set");
if (is_result_set_started && thd->spcont)
{
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 8a54e7069b1..b23b65dae2f 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -2800,23 +2800,6 @@ private:
MYSQL_ERROR::enum_warning_level level,
const char* msg);
- /**
- Raise a generic SQL condition, without activation any SQL condition
- handlers.
- This method is necessary to support the RESIGNAL statement,
- which is allowed to bypass SQL exception handlers.
- @param sql_errno the condition error number
- @param sqlstate the condition SQLSTATE
- @param level the condition level
- @param msg the condition message text
- @return The condition raised, or NULL
- */
- MYSQL_ERROR*
- raise_condition_no_handler(uint sql_errno,
- const char* sqlstate,
- MYSQL_ERROR::enum_warning_level level,
- const char* msg);
-
public:
/** Overloaded to guard query/query_length fields */
virtual void set_statement(Statement *stmt);
@@ -2987,7 +2970,7 @@ public:
@retval TRUE error, an error message is set
*/
virtual bool check_simple_select() const;
- virtual void abort() {}
+ virtual void abort_result_set() {}
/*
Cleanup instance of this class for next execution of a prepared
statement/stored procedure.
@@ -3030,7 +3013,7 @@ public:
bool send_data(List<Item> &items);
bool send_eof();
virtual bool check_simple_select() const { return FALSE; }
- void abort();
+ void abort_result_set();
virtual void cleanup();
};
@@ -3122,7 +3105,7 @@ class select_insert :public select_result_interceptor {
virtual bool can_rollback_data() { return 0; }
void send_error(uint errcode,const char *err);
bool send_eof();
- void abort();
+ virtual void abort_result_set();
/* not implemented: select_insert is never re-used in prepared statements */
void cleanup();
};
@@ -3158,7 +3141,7 @@ public:
void store_values(List<Item> &values);
void send_error(uint errcode,const char *err);
bool send_eof();
- void abort();
+ virtual void abort_result_set();
virtual bool can_rollback_data() { return 1; }
// Needed for access from local class MY_HOOKS in prepare(), since thd is proteted.
@@ -3492,7 +3475,7 @@ public:
{
return deleted;
}
- virtual void abort();
+ virtual void abort_result_set();
};
@@ -3543,7 +3526,7 @@ public:
{
return updated;
}
- virtual void abort();
+ virtual void abort_result_set();
};
class my_var : public Sql_alloc {
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 00666bc85b4..2f69bac917e 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -770,9 +770,9 @@ void multi_delete::send_error(uint errcode,const char *err)
}
-void multi_delete::abort()
+void multi_delete::abort_result_set()
{
- DBUG_ENTER("multi_delete::abort");
+ DBUG_ENTER("multi_delete::abort_result_set");
/* the error was handled or nothing deleted and no side effects return */
if (error_handled ||
diff --git a/sql/sql_error.cc b/sql/sql_error.cc
index e5d0f79b2d7..8c038e10a1f 100644
--- a/sql/sql_error.cc
+++ b/sql/sql_error.cc
@@ -494,14 +494,6 @@ void Warning_info::clear_warning_info(ulonglong warn_id_arg)
m_current_row_for_warning= 1; /* Start counting from the first row */
}
-void Warning_info::reserve_space(THD *thd, uint count)
-{
- /* Make room for count conditions */
- while ((m_warn_list.elements > 0) &&
- ((m_warn_list.elements + count) > thd->variables.max_error_count))
- m_warn_list.pop();
-}
-
/**
Append warnings only if the original contents of the routine
warning info was replaced.
diff --git a/sql/sql_error.h b/sql/sql_error.h
index 9e649a004df..87e98e27673 100644
--- a/sql/sql_error.h
+++ b/sql/sql_error.h
@@ -153,8 +153,8 @@ private:
Representation of a SQL condition.
A SQL condition can be a completion condition (note, warning),
or an exception condition (error, not found).
- @note This class is named MYSQL_ERROR instead of SQL_condition for historical reasons,
- to facilitate merging code with previous releases.
+ @note This class is named MYSQL_ERROR instead of SQL_condition for
+ historical reasons, to facilitate merging code with previous releases.
*/
class MYSQL_ERROR : public Sql_alloc
{
@@ -471,18 +471,6 @@ public:
ulong statement_warn_count() const { return m_statement_warn_count; }
- /**
- Reserve some space in the condition area.
- This is a privileged operation, reserved for the RESIGNAL implementation,
- as only the RESIGNAL statement is allowed to remove conditions from
- the condition area.
- For other statements, new conditions are not added to the condition
- area once the condition area is full.
- @param thd The current thread
- @param count The number of slots to reserve
- */
- void reserve_space(THD *thd, uint count);
-
/** Add a new condition to the current list. */
MYSQL_ERROR *push_warning(THD *thd,
uint sql_errno, const char* sqlstate,
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index cc0b6ba3a2d..a0d347f48de 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -3399,9 +3399,9 @@ bool select_insert::send_eof()
DBUG_RETURN(0);
}
-void select_insert::abort() {
+void select_insert::abort_result_set() {
- DBUG_ENTER("select_insert::abort");
+ DBUG_ENTER("select_insert::abort_result_set");
/*
If the creation of the table failed (due to a syntax error, for
example), no table will have been opened and therefore 'table'
@@ -3938,9 +3938,9 @@ bool select_create::send_eof()
}
-void select_create::abort()
+void select_create::abort_result_set()
{
- DBUG_ENTER("select_create::abort");
+ DBUG_ENTER("select_create::abort_result_set");
/*
In select_insert::abort() we roll back the statement, including
@@ -3958,7 +3958,7 @@ void select_create::abort()
log state.
*/
tmp_disable_binlog(thd);
- select_insert::abort();
+ select_insert::abort_result_set();
thd->transaction.stmt.modified_non_trans_table= FALSE;
reenable_binlog(thd);
/* possible error of writing binary log is ignored deliberately */
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 4c6a822d4c3..2ef8e9761b1 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -3391,7 +3391,7 @@ end_with_restore_list:
res|= thd->is_error();
MYSQL_MULTI_DELETE_DONE(res, del_result->num_deleted());
if (res)
- del_result->abort();
+ del_result->abort_result_set();
delete del_result;
}
else
@@ -4861,7 +4861,7 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables)
ER_YES, str.ptr());
}
if (res)
- result->abort();
+ result->abort_result_set();
else
result->send_eof();
delete result;
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 93c3e76c047..ccfd93a1bc8 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -299,7 +299,7 @@ bool handle_select(THD *thd, LEX *lex, select_result *result,
thd->is_error()));
res|= thd->is_error();
if (unlikely(res))
- result->abort();
+ result->abort_result_set();
MYSQL_SELECT_DONE((int) res, (ulong) thd->limit_found_rows);
DBUG_RETURN(res);
diff --git a/sql/sql_signal.cc b/sql/sql_signal.cc
index f340da373e8..09e9a828fa1 100644
--- a/sql/sql_signal.cc
+++ b/sql/sql_signal.cc
@@ -499,18 +499,6 @@ bool Resignal_statement::execute(THD *thd)
}
/* RESIGNAL with signal_value */
-
- /* Make room for 2 conditions */
- thd->warning_info->reserve_space(thd, 2);
-
- MYSQL_ERROR *raised= NULL;
- raised= thd->raise_condition_no_handler(signaled->get_sql_errno(),
- signaled->get_sqlstate(),
- signaled->get_level(),
- signaled->get_message_text());
- if (raised)
- raised->copy_opt_attributes(signaled);
-
result= raise_condition(thd, signaled);
DBUG_RETURN(result);
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index c52467531a9..35478e28520 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -1261,7 +1261,7 @@ bool mysql_multi_update(THD *thd,
{
/* If we had a another error reported earlier then this will be ignored */
(*result)->send_error(ER_UNKNOWN_ERROR, ER(ER_UNKNOWN_ERROR));
- (*result)->abort();
+ (*result)->abort_result_set();
}
thd->abort_on_warning= 0;
DBUG_RETURN(res);
@@ -1861,7 +1861,7 @@ void multi_update::send_error(uint errcode,const char *err)
}
-void multi_update::abort()
+void multi_update::abort_result_set()
{
/* the error was handled or nothing deleted and no side effects return */
if (error_handled ||