Commit 5a7d224d authored by unknown's avatar unknown

Post-merge fixes for bug 35103

Don't signal errors for the COM_STMT_SEND_LONG_DATA
and COM_STMT_CLOSE commands.


sql/sql_prepare.cc:
  Move error signaling to the callers and out of the helper
  functions because some prepared statements commands
  don't signal errors (they won't send response packets).
parent 33dde6eb
...@@ -155,11 +155,11 @@ public: ...@@ -155,11 +155,11 @@ public:
virtual void cleanup_stmt(); virtual void cleanup_stmt();
bool set_name(LEX_STRING *name); bool set_name(LEX_STRING *name);
inline void close_cursor() { delete cursor; cursor= 0; } inline void close_cursor() { delete cursor; cursor= 0; }
inline bool is_in_use() { return flags & (uint) IS_IN_USE; }
bool prepare(const char *packet, uint packet_length); bool prepare(const char *packet, uint packet_length);
bool execute(String *expanded_query, bool open_cursor); bool execute(String *expanded_query, bool open_cursor);
/* Destroy this statement */ /* Destroy this statement */
bool deallocate(); void deallocate();
private: private:
/** /**
Store the parsed tree of a prepared statement here. Store the parsed tree of a prepared statement here.
...@@ -198,7 +198,7 @@ inline bool is_param_null(const uchar *pos, ulong param_no) ...@@ -198,7 +198,7 @@ inline bool is_param_null(const uchar *pos, ulong param_no)
*/ */
static Prepared_statement * static Prepared_statement *
find_prepared_statement(THD *thd, ulong id, const char *where) find_prepared_statement(THD *thd, ulong id)
{ {
/* /*
To strictly separate namespaces of SQL prepared statements and C API To strictly separate namespaces of SQL prepared statements and C API
...@@ -208,12 +208,8 @@ find_prepared_statement(THD *thd, ulong id, const char *where) ...@@ -208,12 +208,8 @@ find_prepared_statement(THD *thd, ulong id, const char *where)
Statement *stmt= thd->stmt_map.find(id); Statement *stmt= thd->stmt_map.find(id);
if (stmt == 0 || stmt->type() != Query_arena::PREPARED_STATEMENT) if (stmt == 0 || stmt->type() != Query_arena::PREPARED_STATEMENT)
{ return NULL;
char llbuf[22];
my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), sizeof(llbuf), llstr(id, llbuf),
where);
return 0;
}
return (Prepared_statement *) stmt; return (Prepared_statement *) stmt;
} }
...@@ -2121,10 +2117,15 @@ void mysql_sql_stmt_prepare(THD *thd) ...@@ -2121,10 +2117,15 @@ void mysql_sql_stmt_prepare(THD *thd)
If there is a statement with the same name, remove it. It is ok to If there is a statement with the same name, remove it. It is ok to
remove old and fail to insert a new one at the same time. remove old and fail to insert a new one at the same time.
*/ */
if (stmt->deallocate()) if (stmt->is_in_use())
{
my_error(ER_PS_NO_RECURSION, MYF(0));
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
stmt->deallocate();
}
if (! (query= get_dynamic_sql_string(lex, &query_len)) || if (! (query= get_dynamic_sql_string(lex, &query_len)) ||
! (stmt= new Prepared_statement(thd, &thd->protocol_text))) ! (stmt= new Prepared_statement(thd, &thd->protocol_text)))
{ {
...@@ -2320,8 +2321,13 @@ void mysql_stmt_execute(THD *thd, char *packet_arg, uint packet_length) ...@@ -2320,8 +2321,13 @@ void mysql_stmt_execute(THD *thd, char *packet_arg, uint packet_length)
/* First of all clear possible warnings from the previous command */ /* First of all clear possible warnings from the previous command */
mysql_reset_thd_for_next_command(thd); mysql_reset_thd_for_next_command(thd);
if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_execute"))) if (!(stmt= find_prepared_statement(thd, stmt_id)))
{
char llbuf[22];
my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), sizeof(llbuf),
llstr(stmt_id, llbuf), "mysql_stmt_execute");
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
}
#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) #if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
thd->profiling.set_query_source(stmt->query, stmt->query_length); thd->profiling.set_query_source(stmt->query, stmt->query_length);
...@@ -2458,8 +2464,13 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length) ...@@ -2458,8 +2464,13 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length)
/* First of all clear possible warnings from the previous command */ /* First of all clear possible warnings from the previous command */
mysql_reset_thd_for_next_command(thd); mysql_reset_thd_for_next_command(thd);
status_var_increment(thd->status_var.com_stmt_fetch); status_var_increment(thd->status_var.com_stmt_fetch);
if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_fetch"))) if (!(stmt= find_prepared_statement(thd, stmt_id)))
{
char llbuf[22];
my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), sizeof(llbuf),
llstr(stmt_id, llbuf), "mysql_stmt_fetch");
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
}
cursor= stmt->cursor; cursor= stmt->cursor;
if (!cursor) if (!cursor)
...@@ -2520,8 +2531,13 @@ void mysql_stmt_reset(THD *thd, char *packet) ...@@ -2520,8 +2531,13 @@ void mysql_stmt_reset(THD *thd, char *packet)
mysql_reset_thd_for_next_command(thd); mysql_reset_thd_for_next_command(thd);
status_var_increment(thd->status_var.com_stmt_reset); status_var_increment(thd->status_var.com_stmt_reset);
if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_reset"))) if (!(stmt= find_prepared_statement(thd, stmt_id)))
{
char llbuf[22];
my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), sizeof(llbuf),
llstr(stmt_id, llbuf), "mysql_stmt_reset");
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
}
stmt->close_cursor(); stmt->close_cursor();
...@@ -2557,15 +2573,15 @@ void mysql_stmt_close(THD *thd, char *packet) ...@@ -2557,15 +2573,15 @@ void mysql_stmt_close(THD *thd, char *packet)
thd->main_da.disable_status(); thd->main_da.disable_status();
if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_close"))) if (!(stmt= find_prepared_statement(thd, stmt_id)))
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
/* /*
The only way currently a statement can be deallocated when it's The only way currently a statement can be deallocated when it's
in use is from within Dynamic SQL. in use is from within Dynamic SQL.
*/ */
DBUG_ASSERT(! (stmt->flags & (uint) Prepared_statement::IS_IN_USE)); DBUG_ASSERT(! stmt->is_in_use());
(void) stmt->deallocate(); stmt->deallocate();
general_log_print(thd, thd->command, NullS); general_log_print(thd, thd->command, NullS);
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
...@@ -2592,14 +2608,15 @@ void mysql_sql_stmt_close(THD *thd) ...@@ -2592,14 +2608,15 @@ void mysql_sql_stmt_close(THD *thd)
name->str)); name->str));
if (! (stmt= (Prepared_statement*) thd->stmt_map.find_by_name(name))) if (! (stmt= (Prepared_statement*) thd->stmt_map.find_by_name(name)))
{
my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0),
name->length, name->str, "DEALLOCATE PREPARE"); name->length, name->str, "DEALLOCATE PREPARE");
return; else if (stmt->is_in_use())
} my_error(ER_PS_NO_RECURSION, MYF(0));
else
if (stmt->deallocate() == 0) {
stmt->deallocate();
my_ok(thd); my_ok(thd);
}
} }
/** /**
...@@ -2633,17 +2650,13 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length) ...@@ -2633,17 +2650,13 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length)
#ifndef EMBEDDED_LIBRARY #ifndef EMBEDDED_LIBRARY
/* Minimal size of long data packet is 6 bytes */ /* Minimal size of long data packet is 6 bytes */
if (packet_length < MYSQL_LONG_DATA_HEADER) if (packet_length < MYSQL_LONG_DATA_HEADER)
{
my_error(ER_WRONG_ARGUMENTS, MYF(0), "mysql_stmt_send_long_data");
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
}
#endif #endif
stmt_id= uint4korr(packet); stmt_id= uint4korr(packet);
packet+= 4; packet+= 4;
if (!(stmt=find_prepared_statement(thd, stmt_id, if (!(stmt=find_prepared_statement(thd, stmt_id)))
"mysql_stmt_send_long_data")))
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
param_number= uint2korr(packet); param_number= uint2korr(packet);
...@@ -3186,16 +3199,10 @@ error: ...@@ -3186,16 +3199,10 @@ error:
/** Common part of DEALLOCATE PREPARE and mysql_stmt_close. */ /** Common part of DEALLOCATE PREPARE and mysql_stmt_close. */
bool Prepared_statement::deallocate() void Prepared_statement::deallocate()
{ {
/* We account deallocate in the same manner as mysql_stmt_close */ /* We account deallocate in the same manner as mysql_stmt_close */
status_var_increment(thd->status_var.com_stmt_close); status_var_increment(thd->status_var.com_stmt_close);
if (flags & (uint) IS_IN_USE)
{
my_error(ER_PS_NO_RECURSION, MYF(0));
return TRUE;
}
/* Statement map calls delete stmt on erase */ /* Statement map calls delete stmt on erase */
thd->stmt_map.erase(this); thd->stmt_map.erase(this);
return FALSE;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment