summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJon Olav Hauglid <jon.hauglid@oracle.com>2012-10-04 16:15:13 +0200
committerJon Olav Hauglid <jon.hauglid@oracle.com>2012-10-04 16:15:13 +0200
commitbfba296d4084eab4b580cddc04e889ad2abdaeb2 (patch)
treecfc04b7846d4672b0ec88a3d9e95830cfc41ff31
parent30d35590a3bce929679cdc38d36fc67f7923a39e (diff)
downloadmariadb-git-bfba296d4084eab4b580cddc04e889ad2abdaeb2.tar.gz
Bug#14640599 MEMORY LEAK WHEN EXECUTING STORED ROUTINE EXCEPTION HANDLER
When a SP handler is activated, memory is allocated to hold the MESSAGE_TEXT for the condition that caused the activation. The problem was that this memory was allocated on the MEM_ROOT belonging to the stored program. Since this MEM_ROOT is not freed until the stored program ends, a stored program that causes lots of handler activations can start using lots of memory. In 5.1 and earlier the problem did not exist as no MESSAGE_TEXT was allocated if a condition was raised with a handler present. However, this behavior lead to a number of other issues such as Bug#23032. This patch fixes the problem by allocating enough memory for the necessary MESSAGE_TEXTs in the SP MEM_ROOT when the SP starts and then re-using this memory each time a handler is activated. This is the 5.5 version of the patch.
-rw-r--r--sql/sp_rcontext.cc11
-rw-r--r--sql/sp_rcontext.h45
-rw-r--r--sql/sql_signal.cc12
3 files changed, 54 insertions, 14 deletions
diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc
index fba6a56b37c..09f48d824b0 100644
--- a/sql/sp_rcontext.cc
+++ b/sql/sp_rcontext.cc
@@ -67,19 +67,15 @@ sp_rcontext::~sp_rcontext()
bool sp_rcontext::init(THD *thd)
{
uint handler_count= m_root_parsing_ctx->max_handler_index();
- uint i;
in_sub_stmt= thd->in_sub_stmt;
if (init_var_table(thd) || init_var_items())
return TRUE;
- if (!(m_raised_conditions= new (thd->mem_root) MYSQL_ERROR[handler_count]))
+ if (!(m_raised_conditions= new (thd->mem_root) Sql_condition_info[handler_count]))
return TRUE;
- for (i= 0; i<handler_count; i++)
- m_raised_conditions[i].init(thd->mem_root);
-
return
!(m_handler=
(sp_handler_t*)thd->alloc(handler_count * sizeof(sp_handler_t))) ||
@@ -446,13 +442,12 @@ sp_rcontext::exit_handler()
DBUG_VOID_RETURN;
}
-MYSQL_ERROR*
-sp_rcontext::raised_condition() const
+Sql_condition_info* sp_rcontext::raised_condition() const
{
if (m_ihsp > 0)
{
uint hindex= m_in_handler[m_ihsp - 1].index;
- MYSQL_ERROR *raised= & m_raised_conditions[hindex];
+ Sql_condition_info *raised= & m_raised_conditions[hindex];
return raised;
}
diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h
index 84d5a1227fe..c89ada3f3c8 100644
--- a/sql/sp_rcontext.h
+++ b/sql/sp_rcontext.h
@@ -58,6 +58,46 @@ typedef struct
uint index;
} sp_active_handler_t;
+
+class Sql_condition_info : public Sql_alloc
+{
+public:
+ /** SQL error code. */
+ uint m_sql_errno;
+
+ /** Error level. */
+ MYSQL_ERROR::enum_warning_level m_level;
+
+ /** SQLSTATE. */
+ char m_sql_state[SQLSTATE_LENGTH + 1];
+
+ /** Text message. */
+ char m_message[MYSQL_ERRMSG_SIZE];
+
+ void set(uint sql_errno, const char* sqlstate,
+ MYSQL_ERROR::enum_warning_level level,
+ const char* msg)
+ {
+ m_sql_errno= sql_errno;
+ m_level= level;
+
+ memcpy(m_sql_state, sqlstate, SQLSTATE_LENGTH);
+ m_sql_state[SQLSTATE_LENGTH]= '\0';
+
+ strncpy(m_message, msg, MYSQL_ERRMSG_SIZE);
+ }
+
+ void clear()
+ {
+ m_sql_errno= 0;
+ m_level= MYSQL_ERROR::WARN_LEVEL_ERROR;
+
+ m_sql_state[0]= '\0';
+ m_message[0]= '\0';
+ }
+};
+
+
/*
This class is a runtime context of a Stored Routine. It is used in an
execution and is intended to contain all dynamic objects (i.e. objects, which
@@ -146,8 +186,7 @@ class sp_rcontext : public Sql_alloc
MYSQL_ERROR::enum_warning_level level,
const char *msg);
- MYSQL_ERROR *
- raised_condition() const;
+ Sql_condition_info *raised_condition() const;
void
push_hstack(uint h);
@@ -232,7 +271,7 @@ private:
SQL conditions caught by each handler.
This is an array indexed by handler index.
*/
- MYSQL_ERROR *m_raised_conditions;
+ Sql_condition_info *m_raised_conditions;
uint m_hcount; // Stack pointer for m_handler
uint *m_hstack; // Return stack for continue handlers
diff --git a/sql/sql_signal.cc b/sql/sql_signal.cc
index 9910dfc924e..e0c2a96ac84 100644
--- a/sql/sql_signal.cc
+++ b/sql/sql_signal.cc
@@ -478,7 +478,7 @@ bool Signal_statement::execute(THD *thd)
bool Resignal_statement::execute(THD *thd)
{
- MYSQL_ERROR *signaled;
+ Sql_condition_info *signaled;
int result= TRUE;
DBUG_ENTER("Resignal_statement::execute");
@@ -491,15 +491,21 @@ bool Resignal_statement::execute(THD *thd)
DBUG_RETURN(result);
}
+ MYSQL_ERROR signaled_err(thd->mem_root);
+ signaled_err.set(signaled->m_sql_errno,
+ signaled->m_sql_state,
+ signaled->m_level,
+ signaled->m_message);
+
if (m_cond == NULL)
{
/* RESIGNAL without signal_value */
- result= raise_condition(thd, signaled);
+ result= raise_condition(thd, &signaled_err);
DBUG_RETURN(result);
}
/* RESIGNAL with signal_value */
- result= raise_condition(thd, signaled);
+ result= raise_condition(thd, &signaled_err);
DBUG_RETURN(result);
}