mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
Added support for PREPARE stmt1 FROM @var,
Fixed the problem of previous patch with replication, More post-review fixes sql/sql_parse.cc: Added support for PREPARE stmt1 FROM @var sql/sql_prepare.cc: Added support for PREPARE stmt1 FROM @var, Fixed the problem of previous patch with replication Post-review fixes.
This commit is contained in:
@ -1978,17 +1978,21 @@ mysql_execute_command(THD *thd)
|
|||||||
uint query_len;
|
uint query_len;
|
||||||
if (lex->prepared_stmt_code_is_varref)
|
if (lex->prepared_stmt_code_is_varref)
|
||||||
{
|
{
|
||||||
/* This is PREPARE stmt FROM @var*/
|
/* This is PREPARE stmt FROM @var. */
|
||||||
String str;
|
String str;
|
||||||
CHARSET_INFO *to_cs= thd->variables.collation_connection;
|
CHARSET_INFO *to_cs= thd->variables.collation_connection;
|
||||||
CHARSET_INFO *from_cs;
|
CHARSET_INFO *from_cs;
|
||||||
const char *buf;
|
const char *buf;
|
||||||
uint buf_len;
|
uint buf_len;
|
||||||
bool need_conversion;
|
bool need_conversion;
|
||||||
//// psergey: find the variable and convert it.
|
LINT_INIT(from_cs); /* protected by need_conversion */
|
||||||
LINT_INIT(from_cs);
|
|
||||||
user_var_entry *entry;
|
user_var_entry *entry;
|
||||||
uint32 unused;
|
uint32 unused;
|
||||||
|
/*
|
||||||
|
Convert @var contents to string in connection character set. Although
|
||||||
|
it is known that int/real/NULL value cannot be a valid query we still
|
||||||
|
convert it for error messages to uniform.
|
||||||
|
*/
|
||||||
if ((entry=
|
if ((entry=
|
||||||
(user_var_entry*)hash_search(&thd->user_vars,
|
(user_var_entry*)hash_search(&thd->user_vars,
|
||||||
(byte*)lex->prepared_stmt_code.str,
|
(byte*)lex->prepared_stmt_code.str,
|
||||||
@ -2033,32 +2037,29 @@ mysql_execute_command(THD *thd)
|
|||||||
to_cs, &unused);
|
to_cs, &unused);
|
||||||
}
|
}
|
||||||
|
|
||||||
query_len = need_conversion? (buf_len* to_cs->mbmaxlen) : buf_len;
|
query_len = need_conversion? (buf_len * to_cs->mbmaxlen) : buf_len;
|
||||||
if (!(query_str= alloc_root(&thd->mem_root, query_len+1)))
|
if (!(query_str= alloc_root(&thd->mem_root, query_len+1)))
|
||||||
{
|
|
||||||
send_error(thd, ER_OUT_OF_RESOURCES);
|
send_error(thd, ER_OUT_OF_RESOURCES);
|
||||||
}
|
|
||||||
|
|
||||||
if (need_conversion)
|
if (need_conversion)
|
||||||
query_len= copy_and_convert(query_str, query_len, to_cs, buf, buf_len,
|
query_len= copy_and_convert(query_str, query_len, to_cs, buf, buf_len,
|
||||||
from_cs);
|
from_cs);
|
||||||
else
|
else
|
||||||
memcpy(query_str, buf, query_len);
|
memcpy(query_str, buf, query_len);
|
||||||
query_str[query_len] = 0;
|
query_str[query_len]= 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
query_str= lex->prepared_stmt_code.str;
|
||||||
|
query_len= lex->prepared_stmt_code.length;
|
||||||
DBUG_PRINT("info", ("PREPARE: %.*s FROM '%.*s' \n",
|
DBUG_PRINT("info", ("PREPARE: %.*s FROM '%.*s' \n",
|
||||||
lex->prepared_stmt_name.length,
|
lex->prepared_stmt_name.length,
|
||||||
lex->prepared_stmt_name.str,
|
lex->prepared_stmt_name.str,
|
||||||
lex->prepared_stmt_code.length,
|
query_len, query_str));
|
||||||
lex->prepared_stmt_code.str));
|
|
||||||
query_str= lex->prepared_stmt_code.str;
|
|
||||||
query_len= lex->prepared_stmt_code.length + 1;
|
|
||||||
}
|
}
|
||||||
thd->command= COM_PREPARE;
|
thd->command= COM_PREPARE;
|
||||||
if (!mysql_stmt_prepare(thd, query_str, query_len + 1,
|
if (!mysql_stmt_prepare(thd, query_str, query_len + 1,
|
||||||
&lex->prepared_stmt_name))
|
&lex->prepared_stmt_name))
|
||||||
send_ok(thd, 0L, 0L, "Statement prepared");
|
send_ok(thd, 0L, 0L, "Statement prepared");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -94,19 +94,21 @@ public:
|
|||||||
bool log_full_query;
|
bool log_full_query;
|
||||||
#ifndef EMBEDDED_LIBRARY
|
#ifndef EMBEDDED_LIBRARY
|
||||||
bool (*set_params)(Prepared_statement *st, uchar *data, uchar *data_end,
|
bool (*set_params)(Prepared_statement *st, uchar *data, uchar *data_end,
|
||||||
uchar *read_pos);
|
uchar *read_pos, String *expanded_query);
|
||||||
#else
|
#else
|
||||||
bool (*set_params_data)(Prepared_statement *st);
|
bool (*set_params_data)(Prepared_statement *st, String *expanded_query);
|
||||||
#endif
|
#endif
|
||||||
bool (*set_params_from_vars)(Prepared_statement *stmt,
|
bool (*set_params_from_vars)(Prepared_statement *stmt,
|
||||||
List<LEX_STRING>& varnames);
|
List<LEX_STRING>& varnames,
|
||||||
|
String *expanded_query);
|
||||||
public:
|
public:
|
||||||
Prepared_statement(THD *thd_arg);
|
Prepared_statement(THD *thd_arg);
|
||||||
virtual ~Prepared_statement();
|
virtual ~Prepared_statement();
|
||||||
virtual Statement::Type type() const;
|
virtual Statement::Type type() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void execute_stmt(THD *thd, Prepared_statement *stmt);
|
static void execute_stmt(THD *thd, Prepared_statement *stmt,
|
||||||
|
String *expanded_query);
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
Implementation
|
Implementation
|
||||||
@ -517,19 +519,20 @@ static void setup_one_conversion_function(Item_param *param, uchar param_type)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
static bool insert_params_withlog(Prepared_statement *stmt, uchar *null_array,
|
static bool insert_params_withlog(Prepared_statement *stmt, uchar *null_array,
|
||||||
uchar *read_pos, uchar *data_end)
|
uchar *read_pos, uchar *data_end,
|
||||||
|
String *query)
|
||||||
{
|
{
|
||||||
THD *thd= stmt->thd;
|
THD *thd= stmt->thd;
|
||||||
Item_param **begin= stmt->param_array;
|
Item_param **begin= stmt->param_array;
|
||||||
Item_param **end= begin + stmt->param_count;
|
Item_param **end= begin + stmt->param_count;
|
||||||
uint32 length= 0;
|
uint32 length= 0;
|
||||||
|
|
||||||
String str, query;
|
String str;
|
||||||
const String *res;
|
const String *res;
|
||||||
|
|
||||||
DBUG_ENTER("insert_params_withlog");
|
DBUG_ENTER("insert_params_withlog");
|
||||||
|
|
||||||
if (query.copy(stmt->query, stmt->query_length, default_charset_info))
|
if (query->copy(stmt->query, stmt->query_length, default_charset_info))
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
for (Item_param **it= begin; it < end; ++it)
|
for (Item_param **it= begin; it < end; ++it)
|
||||||
@ -552,20 +555,18 @@ static bool insert_params_withlog(Prepared_statement *stmt, uchar *null_array,
|
|||||||
res= param->query_val_str(&str);
|
res= param->query_val_str(&str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (query.replace(param->pos_in_query+length, 1, *res))
|
if (query->replace(param->pos_in_query+length, 1, *res))
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
length+= res->length()-1;
|
length+= res->length()-1;
|
||||||
}
|
}
|
||||||
if (alloc_query(thd, (char *)query.ptr(), query.length()+1))
|
|
||||||
DBUG_RETURN(1);
|
|
||||||
|
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool insert_params(Prepared_statement *stmt, uchar *null_array,
|
static bool insert_params(Prepared_statement *stmt, uchar *null_array,
|
||||||
uchar *read_pos, uchar *data_end)
|
uchar *read_pos, uchar *data_end,
|
||||||
|
String *expanded_query)
|
||||||
{
|
{
|
||||||
Item_param **begin= stmt->param_array;
|
Item_param **begin= stmt->param_array;
|
||||||
Item_param **end= begin + stmt->param_count;
|
Item_param **end= begin + stmt->param_count;
|
||||||
@ -627,7 +628,7 @@ static bool setup_conversion_functions(Prepared_statement *stmt,
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
static bool emb_insert_params(Prepared_statement *stmt)
|
static bool emb_insert_params(Prepared_statement *stmt, String *expanded_query)
|
||||||
{
|
{
|
||||||
Item_param **it= stmt->param_array;
|
Item_param **it= stmt->param_array;
|
||||||
Item_param **end= it + stmt->param_count;
|
Item_param **end= it + stmt->param_count;
|
||||||
@ -658,20 +659,20 @@ static bool emb_insert_params(Prepared_statement *stmt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool emb_insert_params_withlog(Prepared_statement *stmt)
|
static bool emb_insert_params_withlog(Prepared_statement *stmt, String *query)
|
||||||
{
|
{
|
||||||
THD *thd= stmt->thd;
|
THD *thd= stmt->thd;
|
||||||
Item_param **it= stmt->param_array;
|
Item_param **it= stmt->param_array;
|
||||||
Item_param **end= it + stmt->param_count;
|
Item_param **end= it + stmt->param_count;
|
||||||
MYSQL_BIND *client_param= thd->client_params;
|
MYSQL_BIND *client_param= thd->client_params;
|
||||||
|
|
||||||
String str, query;
|
String str;
|
||||||
const String *res;
|
const String *res;
|
||||||
uint32 length= 0;
|
uint32 length= 0;
|
||||||
|
|
||||||
DBUG_ENTER("emb_insert_params_withlog");
|
DBUG_ENTER("emb_insert_params_withlog");
|
||||||
|
|
||||||
if (query.copy(stmt->query, stmt->query_length, default_charset_info))
|
if (query->copy(stmt->query, stmt->query_length, default_charset_info))
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
for (; it < end; ++it, ++client_param)
|
for (; it < end; ++it, ++client_param)
|
||||||
@ -697,14 +698,10 @@ static bool emb_insert_params_withlog(Prepared_statement *stmt)
|
|||||||
res= param->query_val_str(&str);
|
res= param->query_val_str(&str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (query.replace(param->pos_in_query+length, 1, *res))
|
if (query->replace(param->pos_in_query+length, 1, *res))
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
length+= res->length()-1;
|
length+= res->length()-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (alloc_query(thd, (char *) query.ptr(), query.length()+1))
|
|
||||||
DBUG_RETURN(1);
|
|
||||||
|
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -718,11 +715,12 @@ static bool emb_insert_params_withlog(Prepared_statement *stmt)
|
|||||||
stmt Statement
|
stmt Statement
|
||||||
varnames List of variables. Caller must ensure that number of variables
|
varnames List of variables. Caller must ensure that number of variables
|
||||||
in the list is equal to number of statement parameters
|
in the list is equal to number of statement parameters
|
||||||
|
query Ignored
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static bool insert_params_from_vars(Prepared_statement *stmt,
|
static bool insert_params_from_vars(Prepared_statement *stmt,
|
||||||
List<LEX_STRING>& varnames)
|
List<LEX_STRING>& varnames,
|
||||||
|
String *query __attribute__((unused)))
|
||||||
{
|
{
|
||||||
Item_param **begin= stmt->param_array;
|
Item_param **begin= stmt->param_array;
|
||||||
Item_param **end= begin + stmt->param_count;
|
Item_param **end= begin + stmt->param_count;
|
||||||
@ -763,8 +761,21 @@ static bool insert_params_from_vars(Prepared_statement *stmt,
|
|||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Do the same as insert_params_from_vars but also construct query text for
|
||||||
|
binary log.
|
||||||
|
SYNOPSIS
|
||||||
|
insert_params_from_vars()
|
||||||
|
stmt Statement
|
||||||
|
varnames List of variables. Caller must ensure that number of variables
|
||||||
|
in the list is equal to number of statement parameters
|
||||||
|
query The query with parameter markers replaced with their values
|
||||||
|
*/
|
||||||
|
|
||||||
static bool insert_params_from_vars_with_log(Prepared_statement *stmt,
|
static bool insert_params_from_vars_with_log(Prepared_statement *stmt,
|
||||||
List<LEX_STRING>& varnames)
|
List<LEX_STRING>& varnames,
|
||||||
|
String *query)
|
||||||
{
|
{
|
||||||
Item_param **begin= stmt->param_array;
|
Item_param **begin= stmt->param_array;
|
||||||
Item_param **end= begin + stmt->param_count;
|
Item_param **end= begin + stmt->param_count;
|
||||||
@ -773,10 +784,10 @@ static bool insert_params_from_vars_with_log(Prepared_statement *stmt,
|
|||||||
DBUG_ENTER("insert_params_from_vars");
|
DBUG_ENTER("insert_params_from_vars");
|
||||||
|
|
||||||
List_iterator<LEX_STRING> var_it(varnames);
|
List_iterator<LEX_STRING> var_it(varnames);
|
||||||
String str, query;
|
String str;
|
||||||
const String *res;
|
const String *res;
|
||||||
uint32 length= 0;
|
uint32 length= 0;
|
||||||
if (query.copy(stmt->query, stmt->query_length, default_charset_info))
|
if (query->copy(stmt->query, stmt->query_length, default_charset_info))
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
for (Item_param **it= begin; it < end; ++it)
|
for (Item_param **it= begin; it < end; ++it)
|
||||||
@ -812,12 +823,10 @@ static bool insert_params_from_vars_with_log(Prepared_statement *stmt,
|
|||||||
res= &my_null_string;
|
res= &my_null_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (query.replace(param->pos_in_query+length, 1, *res))
|
if (query->replace(param->pos_in_query+length, 1, *res))
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
length+= res->length()-1;
|
length+= res->length()-1;
|
||||||
}
|
}
|
||||||
if (alloc_query(stmt->thd, (char *) query.ptr(), query.length()+1))
|
|
||||||
DBUG_RETURN(1);
|
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1708,13 +1717,14 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
|
|||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String expanded_query;
|
||||||
#ifndef EMBEDDED_LIBRARY
|
#ifndef EMBEDDED_LIBRARY
|
||||||
if (stmt->param_count)
|
if (stmt->param_count)
|
||||||
{
|
{
|
||||||
uchar *null_array= (uchar *) packet;
|
uchar *null_array= (uchar *) packet;
|
||||||
if (setup_conversion_functions(stmt, (uchar **) &packet, packet_end) ||
|
if (setup_conversion_functions(stmt, (uchar **) &packet, packet_end) ||
|
||||||
stmt->set_params(stmt, null_array, (uchar *) packet, packet_end))
|
stmt->set_params(stmt, null_array, (uchar *) packet, packet_end,
|
||||||
|
&expanded_query))
|
||||||
goto set_params_data_err;
|
goto set_params_data_err;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@ -1727,7 +1737,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
|
|||||||
goto set_params_data_err;
|
goto set_params_data_err;
|
||||||
#endif
|
#endif
|
||||||
thd->protocol= &thd->protocol_prep; // Switch to binary protocol
|
thd->protocol= &thd->protocol_prep; // Switch to binary protocol
|
||||||
execute_stmt(thd, stmt);
|
execute_stmt(thd, stmt, &expanded_query);
|
||||||
thd->protocol= &thd->protocol_simple; // Use normal protocol
|
thd->protocol= &thd->protocol_simple; // Use normal protocol
|
||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
|
|
||||||
@ -1747,6 +1757,7 @@ set_params_data_err:
|
|||||||
void mysql_sql_stmt_execute(THD *thd, LEX_STRING *stmt_name)
|
void mysql_sql_stmt_execute(THD *thd, LEX_STRING *stmt_name)
|
||||||
{
|
{
|
||||||
Prepared_statement *stmt;
|
Prepared_statement *stmt;
|
||||||
|
String expanded_query;
|
||||||
DBUG_ENTER("mysql_sql_stmt_execute");
|
DBUG_ENTER("mysql_sql_stmt_execute");
|
||||||
|
|
||||||
if (!(stmt= (Prepared_statement*)thd->stmt_map.find_by_name(stmt_name)))
|
if (!(stmt= (Prepared_statement*)thd->stmt_map.find_by_name(stmt_name)))
|
||||||
@ -1766,27 +1777,47 @@ void mysql_sql_stmt_execute(THD *thd, LEX_STRING *stmt_name)
|
|||||||
/* Item_param allows setting parameters in COM_EXECUTE only */
|
/* Item_param allows setting parameters in COM_EXECUTE only */
|
||||||
thd->command= COM_EXECUTE;
|
thd->command= COM_EXECUTE;
|
||||||
|
|
||||||
if (stmt->set_params_from_vars(stmt, thd->lex->prepared_stmt_params))
|
if (stmt->set_params_from_vars(stmt, thd->lex->prepared_stmt_params,
|
||||||
|
&expanded_query))
|
||||||
{
|
{
|
||||||
my_error(ER_WRONG_ARGUMENTS, MYF(0), "mysql_execute");
|
my_error(ER_WRONG_ARGUMENTS, MYF(0), "mysql_execute");
|
||||||
send_error(thd);
|
send_error(thd);
|
||||||
}
|
}
|
||||||
execute_stmt(thd, stmt);
|
execute_stmt(thd, stmt, &expanded_query);
|
||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Execute prepared statement.
|
Execute prepared statement.
|
||||||
|
SYNOPSIS
|
||||||
|
execute_stmt()
|
||||||
|
thd Current thread
|
||||||
|
stmt Statement to execute
|
||||||
|
expanded_query If binary log is enabled, query string with parameter
|
||||||
|
placeholders replaced with actual values. Otherwise empty
|
||||||
|
string.
|
||||||
|
NOTES
|
||||||
Caller must set parameter values and thd::protocol.
|
Caller must set parameter values and thd::protocol.
|
||||||
thd->free_list is assumed to be garbage.
|
thd->free_list is assumed to be garbage.
|
||||||
*/
|
*/
|
||||||
static void execute_stmt(THD *thd, Prepared_statement *stmt)
|
|
||||||
|
static void execute_stmt(THD *thd, Prepared_statement *stmt,
|
||||||
|
String *expanded_query)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("execute_stmt");
|
DBUG_ENTER("execute_stmt");
|
||||||
thd->free_list= NULL;
|
thd->free_list= NULL;
|
||||||
thd->stmt_backup.set_statement(thd);
|
thd->stmt_backup.set_statement(thd);
|
||||||
thd->set_statement(stmt);
|
thd->set_statement(stmt);
|
||||||
reset_stmt_for_execute(stmt);
|
reset_stmt_for_execute(stmt);
|
||||||
|
|
||||||
|
if (expanded_query->length() &&
|
||||||
|
alloc_query(thd, (char *)expanded_query->ptr(),
|
||||||
|
expanded_query->length()+1))
|
||||||
|
{
|
||||||
|
my_error(ER_OUTOFMEMORY, 0, expanded_query->length());
|
||||||
|
DBUG_VOID_RETURN;
|
||||||
|
}
|
||||||
|
|
||||||
if (!(specialflag & SPECIAL_NO_PRIOR))
|
if (!(specialflag & SPECIAL_NO_PRIOR))
|
||||||
my_pthread_setprio(pthread_self(),QUERY_PRIOR);
|
my_pthread_setprio(pthread_self(),QUERY_PRIOR);
|
||||||
@ -1808,13 +1839,12 @@ static void execute_stmt(THD *thd, Prepared_statement *stmt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Reset a prepared statement in case there was a recoverable error.
|
Reset a prepared statement in case there was a recoverable error.
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
mysql_stmt_reset()
|
mysql_stmt_reset()
|
||||||
thd Thread handle
|
thd Thread handle
|
||||||
packet Packet with stmt id
|
packet Packet with stmt id
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
This function resets statement to the state it was right after prepare.
|
This function resets statement to the state it was right after prepare.
|
||||||
|
Reference in New Issue
Block a user