mirror of
https://github.com/MariaDB/server.git
synced 2025-07-27 18:02:13 +03:00
Merge spetrunia@bk-internal.mysql.com:/home/bk/mysql-4.1
into mysql.com:/dbdata/psergey/mysql-4.1-ps-merge
This commit is contained in:
86
mysql-test/r/ps.result
Normal file
86
mysql-test/r/ps.result
Normal file
@ -0,0 +1,86 @@
|
||||
drop table if exists t1,t2;
|
||||
create table t1
|
||||
(
|
||||
a int primary key,
|
||||
b char(10),
|
||||
);
|
||||
insert into t1 values (1,'one');
|
||||
insert into t1 values (2,'two');
|
||||
insert into t1 values (3,'three');
|
||||
insert into t1 values (4,'four');
|
||||
set @a=2;
|
||||
prepare stmt1 from 'select * from t1 where a <= ?';
|
||||
execute stmt1 using @a;
|
||||
a b
|
||||
1 one
|
||||
2 two
|
||||
set @a=3;
|
||||
execute stmt1 using @a;
|
||||
a b
|
||||
1 one
|
||||
2 two
|
||||
3 three
|
||||
deallocate prepare no_such_statement;
|
||||
ERROR HY000: Undefined prepared statement
|
||||
execute stmt1;
|
||||
ERROR HY000: Wrong arguments to mysql_execute
|
||||
prepare stmt2 from 'prepare nested_stmt from "select 1"';
|
||||
ERROR 42000: You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near '"select 1"' at line 1
|
||||
prepare stmt2 from 'execute stmt1';
|
||||
ERROR 42000: You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near 'stmt1' at line 1
|
||||
prepare stmt2 from 'deallocate prepare z';
|
||||
ERROR 42000: You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near 'z' at line 1
|
||||
prepare stmt3 from 'insert into t1 values (?,?)';
|
||||
set @arg1=5, @arg2='five';
|
||||
execute stmt3 using @arg1, @arg2;
|
||||
select * from t1 where a>3;
|
||||
a b
|
||||
4 four
|
||||
5 five
|
||||
prepare stmt4 from 'update t1 set a=? where b=?';
|
||||
set @arg1=55, @arg2='five';
|
||||
execute stmt4 using @arg1, @arg2;
|
||||
select * from t1 where a>3;
|
||||
a b
|
||||
4 four
|
||||
55 five
|
||||
prepare stmt4 from 'create table t2 (a int)';
|
||||
execute stmt4;
|
||||
prepare stmt4 from 'drop table t2';
|
||||
execute stmt4;
|
||||
execute stmt4;
|
||||
ERROR 42S02: Unknown table 't2'
|
||||
prepare stmt5 from 'select ? + a from t1';
|
||||
set @a=1;
|
||||
execute stmt5 using @a;
|
||||
? + a
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
56
|
||||
execute stmt5 using @no_such_var;
|
||||
? + a
|
||||
NULL
|
||||
NULL
|
||||
NULL
|
||||
NULL
|
||||
NULL
|
||||
set @nullvar=1;
|
||||
set @nullvar=NULL;
|
||||
execute stmt5 using @nullvar;
|
||||
? + a
|
||||
NULL
|
||||
NULL
|
||||
NULL
|
||||
NULL
|
||||
NULL
|
||||
set @nullvar2=NULL;
|
||||
execute stmt5 using @nullvar2;
|
||||
? + a
|
||||
NULL
|
||||
NULL
|
||||
NULL
|
||||
NULL
|
||||
NULL
|
||||
drop table t1;
|
79
mysql-test/t/ps.test
Normal file
79
mysql-test/t/ps.test
Normal file
@ -0,0 +1,79 @@
|
||||
#
|
||||
# SQL Syntax for Prepared Statements test
|
||||
#
|
||||
--disable_warnings
|
||||
drop table if exists t1,t2;
|
||||
--enable_warnings
|
||||
|
||||
create table t1
|
||||
(
|
||||
a int primary key,
|
||||
b char(10),
|
||||
);
|
||||
insert into t1 values (1,'one');
|
||||
insert into t1 values (2,'two');
|
||||
insert into t1 values (3,'three');
|
||||
insert into t1 values (4,'four');
|
||||
|
||||
# basic functionality
|
||||
set @a=2;
|
||||
prepare stmt1 from 'select * from t1 where a <= ?';
|
||||
execute stmt1 using @a;
|
||||
set @a=3;
|
||||
execute stmt1 using @a;
|
||||
|
||||
# non-existant statement
|
||||
--error 1243
|
||||
deallocate prepare no_such_statement;
|
||||
|
||||
--error 1210
|
||||
execute stmt1;
|
||||
|
||||
# Nesting ps commands is not allowed:
|
||||
--error 1064
|
||||
prepare stmt2 from 'prepare nested_stmt from "select 1"';
|
||||
|
||||
--error 1064
|
||||
prepare stmt2 from 'execute stmt1';
|
||||
|
||||
--error 1064
|
||||
prepare stmt2 from 'deallocate prepare z';
|
||||
|
||||
# PS insert
|
||||
prepare stmt3 from 'insert into t1 values (?,?)';
|
||||
set @arg1=5, @arg2='five';
|
||||
execute stmt3 using @arg1, @arg2;
|
||||
select * from t1 where a>3;
|
||||
|
||||
# PS update
|
||||
prepare stmt4 from 'update t1 set a=? where b=?';
|
||||
set @arg1=55, @arg2='five';
|
||||
execute stmt4 using @arg1, @arg2;
|
||||
select * from t1 where a>3;
|
||||
|
||||
# PS create/delete
|
||||
prepare stmt4 from 'create table t2 (a int)';
|
||||
execute stmt4;
|
||||
prepare stmt4 from 'drop table t2';
|
||||
execute stmt4;
|
||||
|
||||
# Do something that will cause error
|
||||
--error 1051
|
||||
execute stmt4;
|
||||
|
||||
# placeholders in result field names.
|
||||
prepare stmt5 from 'select ? + a from t1';
|
||||
set @a=1;
|
||||
execute stmt5 using @a;
|
||||
|
||||
execute stmt5 using @no_such_var;
|
||||
|
||||
set @nullvar=1;
|
||||
set @nullvar=NULL;
|
||||
execute stmt5 using @nullvar;
|
||||
|
||||
set @nullvar2=NULL;
|
||||
execute stmt5 using @nullvar2;
|
||||
|
||||
drop table t1;
|
||||
|
@ -635,16 +635,21 @@ void Item_param::set_double(double value)
|
||||
}
|
||||
|
||||
|
||||
void Item_param::set_value(const char *str, uint length)
|
||||
void Item_param::set_value(const char *str, uint length, CHARSET_INFO *ci)
|
||||
{
|
||||
DBUG_ENTER("Item_param::set_value");
|
||||
str_value.copy(str,length,default_charset());
|
||||
str_value.copy(str,length,ci);
|
||||
item_type= STRING_ITEM;
|
||||
value_is_set= 1;
|
||||
DBUG_PRINT("info", ("string: %s", str_value.ptr()));
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
void Item_param::set_value(const char *str, uint length)
|
||||
{
|
||||
set_value(str, length, default_charset());
|
||||
}
|
||||
|
||||
|
||||
void Item_param::set_time(TIME *tm, timestamp_type type)
|
||||
{
|
||||
|
@ -412,6 +412,7 @@ public:
|
||||
void set_int(longlong i);
|
||||
void set_double(double i);
|
||||
void set_value(const char *str, uint length);
|
||||
void set_value(const char *str, uint length, CHARSET_INFO *ci);
|
||||
void set_long_str(const char *str, ulong length);
|
||||
void set_long_binary(const char *str, ulong length);
|
||||
void set_longdata(const char *str, ulong length);
|
||||
|
@ -133,6 +133,7 @@ static SYMBOL symbols[] = {
|
||||
{ "DAY_MICROSECOND", SYM(DAY_MICROSECOND_SYM)},
|
||||
{ "DAY_MINUTE", SYM(DAY_MINUTE_SYM)},
|
||||
{ "DAY_SECOND", SYM(DAY_SECOND_SYM)},
|
||||
{ "DEALLOCATE", SYM(DEALLOCATE_SYM)},
|
||||
{ "DEC", SYM(DECIMAL_SYM)},
|
||||
{ "DECIMAL", SYM(DECIMAL_SYM)},
|
||||
{ "DEFAULT", SYM(DEFAULT)},
|
||||
@ -322,6 +323,7 @@ static SYMBOL symbols[] = {
|
||||
{ "POINT", SYM(POINT_SYM)},
|
||||
{ "POLYGON", SYM(POLYGON)},
|
||||
{ "PRECISION", SYM(PRECISION)},
|
||||
{ "PREPARE", SYM(PREPARE_SYM)},
|
||||
{ "PREV", SYM(PREV_SYM)},
|
||||
{ "PRIMARY", SYM(PRIMARY_SYM)},
|
||||
{ "PRIVILEGES", SYM(PRIVILEGES)},
|
||||
|
@ -613,8 +613,11 @@ int mysqld_show_column_types(THD *thd);
|
||||
int mysqld_help (THD *thd, const char *text);
|
||||
|
||||
/* sql_prepare.cc */
|
||||
void mysql_stmt_prepare(THD *thd, char *packet, uint packet_length);
|
||||
class Prepared_statement;
|
||||
Prepared_statement *mysql_stmt_prepare(THD *thd, char *packet,
|
||||
uint packet_length, bool text_protocol=false);
|
||||
void mysql_stmt_execute(THD *thd, char *packet, uint packet_length);
|
||||
void mysql_sql_stmt_execute(THD *thd, Prepared_statement *stmt);
|
||||
void mysql_stmt_free(THD *thd, char *packet);
|
||||
void mysql_stmt_reset(THD *thd, char *packet);
|
||||
void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length);
|
||||
|
@ -4809,6 +4809,9 @@ struct show_var_st status_vars[]= {
|
||||
{"Com_unlock_tables", (char*) (com_stat+(uint) SQLCOM_UNLOCK_TABLES),SHOW_LONG},
|
||||
{"Com_update", (char*) (com_stat+(uint) SQLCOM_UPDATE),SHOW_LONG},
|
||||
{"Com_update_multi", (char*) (com_stat+(uint) SQLCOM_UPDATE_MULTI),SHOW_LONG},
|
||||
{"Com_prepare_sql", (char*) (com_stat+(uint) SQLCOM_PREPARE), SHOW_LONG},
|
||||
{"Com_execute_sql", (char*) (com_stat+(uint) SQLCOM_EXECUTE), SHOW_LONG},
|
||||
{"Com_dealloc_sql", (char*) (com_stat+(uint) SQLCOM_DEALLOCATE_PREPARE), SHOW_LONG},
|
||||
{"Connections", (char*) &thread_id, SHOW_LONG_CONST},
|
||||
{"Created_tmp_disk_tables", (char*) &created_tmp_disk_tables,SHOW_LONG},
|
||||
{"Created_tmp_files", (char*) &my_tmp_file_created, SHOW_LONG},
|
||||
|
@ -78,6 +78,23 @@ extern "C" void free_user_var(user_var_entry *entry)
|
||||
my_free((char*) entry,MYF(0));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
** SQL syntax names for Prepared Statements
|
||||
****************************************************************************/
|
||||
|
||||
extern "C" byte *get_stmt_key(SQL_PREP_STMT_ENTRY *entry, uint *length,
|
||||
my_bool not_used __attribute__((unused)))
|
||||
{
|
||||
*length=(uint) entry->name.length;
|
||||
return (byte*) entry->name.str;
|
||||
}
|
||||
|
||||
extern "C" void free_sql_stmt(SQL_PREP_STMT_ENTRY *entry)
|
||||
{
|
||||
char *pos= (char*) entry+ALIGN_SIZE(sizeof(*entry));
|
||||
my_free((char*) entry,MYF(0));
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
** Thread specific functions
|
||||
@ -161,6 +178,9 @@ THD::THD():user_time(0), current_statement(0), is_fatal_error(0),
|
||||
else
|
||||
bzero((char*) &user_var_events, sizeof(user_var_events));
|
||||
|
||||
hash_init(&sql_prepared_stmts, &my_charset_bin, USER_VARS_HASH_SIZE, 0, 0,
|
||||
(hash_get_key) get_stmt_key,
|
||||
(hash_free_key) free_sql_stmt,0);
|
||||
/* Protocol */
|
||||
protocol= &protocol_simple; // Default protocol
|
||||
protocol_simple.init(this);
|
||||
@ -279,6 +299,7 @@ void THD::cleanup(void)
|
||||
my_free((char*) variables.datetime_format, MYF(MY_ALLOW_ZERO_PTR));
|
||||
delete_dynamic(&user_var_events);
|
||||
hash_free(&user_vars);
|
||||
hash_free(&sql_prepared_stmts);
|
||||
if (global_read_lock)
|
||||
unlock_global_read_lock(this);
|
||||
if (ull)
|
||||
|
@ -594,6 +594,12 @@ public:
|
||||
struct system_variables variables; // Changeable local variables
|
||||
pthread_mutex_t LOCK_delete; // Locked before thd is deleted
|
||||
|
||||
/*
|
||||
statement_name -> (Statement*) map of statements prepared using SQL syntax.
|
||||
Hash element is SQL_PREP_STMT_ENTRY.
|
||||
*/
|
||||
HASH sql_prepared_stmts;
|
||||
|
||||
/* all prepared statements and cursors of this connection */
|
||||
Statement_map stmt_map;
|
||||
/*
|
||||
@ -1270,6 +1276,14 @@ class user_var_entry
|
||||
DTCollation collation;
|
||||
};
|
||||
|
||||
class Prepared_statement;
|
||||
/* Needed by THD::sql_prepared_stmts */
|
||||
typedef struct st_sql_prep_stmt_entry
|
||||
{
|
||||
public:
|
||||
LEX_STRING name;
|
||||
Prepared_statement *stmt;
|
||||
}SQL_PREP_STMT_ENTRY;
|
||||
|
||||
/* Class for unique (removing of duplicates) */
|
||||
|
||||
|
@ -76,6 +76,7 @@ enum enum_sql_command {
|
||||
SQLCOM_SHOW_COLUMN_TYPES, SQLCOM_SHOW_STORAGE_ENGINES, SQLCOM_SHOW_PRIVILEGES,
|
||||
SQLCOM_HELP, SQLCOM_DROP_USER, SQLCOM_REVOKE_ALL, SQLCOM_CHECKSUM,
|
||||
|
||||
SQLCOM_PREPARE, SQLCOM_EXECUTE, SQLCOM_DEALLOCATE_PREPARE,
|
||||
/* This should be the last !!! */
|
||||
SQLCOM_END
|
||||
};
|
||||
@ -592,6 +593,11 @@ typedef struct st_lex
|
||||
bool in_comment, ignore_space, verbose, simple_alter, no_write_to_binlog;
|
||||
bool derived_tables;
|
||||
bool safe_to_cache_query;
|
||||
/* Prepared statements SQL syntax:*/
|
||||
LEX_STRING prepared_stmt_name; /* Statement name (in all queries) */
|
||||
LEX_STRING prepared_stmt_code; /* Statement query (in PREPARE )*/
|
||||
/* Names of user variables holding parameters (in EXECUTE) */
|
||||
List<LEX_STRING> prepared_stmt_params;
|
||||
st_lex() {}
|
||||
inline void uncacheable(uint8 cause)
|
||||
{
|
||||
|
@ -1959,7 +1959,91 @@ mysql_execute_command(THD *thd)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SQLCOM_PREPARE:
|
||||
{
|
||||
char *stmt_name= lex->prepared_stmt_name.str;
|
||||
uint name_len= lex->prepared_stmt_name.length;
|
||||
Prepared_statement *stmt;
|
||||
SQL_PREP_STMT_ENTRY *entry;
|
||||
DBUG_PRINT("info", ("PREPARE: %.*s FROM '%.*s' \n", name_len, stmt_name,
|
||||
lex->prepared_stmt_code.length,
|
||||
lex->prepared_stmt_code.str));
|
||||
if ((entry=(SQL_PREP_STMT_ENTRY*)hash_search(&thd->sql_prepared_stmts,
|
||||
(byte*)stmt_name, name_len)))
|
||||
{
|
||||
/* Free the statement with the same name and reuse hash entry */
|
||||
thd->stmt_map.erase((Statement*)entry->stmt);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint size=ALIGN_SIZE(sizeof(SQL_PREP_STMT_ENTRY))+name_len+1;
|
||||
if (!hash_inited(&thd->sql_prepared_stmts) ||
|
||||
!(entry= (SQL_PREP_STMT_ENTRY*)my_malloc(size,MYF(MY_WME))))
|
||||
{
|
||||
send_error(thd, ER_OUT_OF_RESOURCES);
|
||||
break;
|
||||
}
|
||||
entry->name.str= (char*)entry + ALIGN_SIZE(sizeof(SQL_PREP_STMT_ENTRY));
|
||||
entry->name.length= name_len;
|
||||
memcpy(entry->name.str, stmt_name, name_len+1);
|
||||
if (my_hash_insert(&thd->sql_prepared_stmts, (byte*)entry))
|
||||
{
|
||||
my_free((char*)entry,MYF(0));
|
||||
send_error(thd, ER_OUT_OF_RESOURCES);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Pretend this is a COM_PREPARE query so parser allows placeholders etc*/
|
||||
thd->command= COM_PREPARE;
|
||||
/* 'length+1' is for alloc_query that strips the last character */
|
||||
stmt= mysql_stmt_prepare(thd, lex->prepared_stmt_code.str,
|
||||
lex->prepared_stmt_code.length + 1, true);
|
||||
if (stmt)
|
||||
{
|
||||
entry->stmt= stmt;
|
||||
send_ok(thd, 0L, 0L, "Statement prepared");
|
||||
}
|
||||
else
|
||||
hash_delete(&thd->sql_prepared_stmts, (byte*)entry);
|
||||
break;
|
||||
}
|
||||
case SQLCOM_EXECUTE:
|
||||
{
|
||||
char *stmt_name= lex->prepared_stmt_name.str;
|
||||
uint name_len= lex->prepared_stmt_name.length;
|
||||
SQL_PREP_STMT_ENTRY *entry;
|
||||
DBUG_PRINT("info", ("EXECUTE: %.*s\n", name_len, stmt_name));
|
||||
|
||||
if (!(entry= (SQL_PREP_STMT_ENTRY*)hash_search(&thd->sql_prepared_stmts,
|
||||
(byte*)stmt_name,
|
||||
name_len)))
|
||||
{
|
||||
send_error(thd, ER_UNKNOWN_STMT_HANDLER, "Undefined prepared statement");
|
||||
lex->prepared_stmt_params.empty();
|
||||
break;
|
||||
}
|
||||
mysql_sql_stmt_execute(thd, entry->stmt);
|
||||
lex->prepared_stmt_params.empty();
|
||||
break;
|
||||
}
|
||||
case SQLCOM_DEALLOCATE_PREPARE:
|
||||
{
|
||||
char *stmt_name= lex->prepared_stmt_name.str;
|
||||
uint name_len= lex->prepared_stmt_name.length;
|
||||
SQL_PREP_STMT_ENTRY *entry;
|
||||
DBUG_PRINT("info", ("DEALLOCATE PREPARE: %.*s\n", name_len, stmt_name));
|
||||
if (!(entry= (SQL_PREP_STMT_ENTRY*)hash_search(&thd->sql_prepared_stmts,
|
||||
(byte*)stmt_name,
|
||||
name_len)))
|
||||
{
|
||||
send_error(thd, ER_UNKNOWN_STMT_HANDLER, "Undefined prepared statement");
|
||||
break;
|
||||
}
|
||||
thd->stmt_map.erase((Statement*)entry->stmt);
|
||||
hash_delete(&thd->sql_prepared_stmts, (byte*)entry);
|
||||
send_ok(thd);
|
||||
break;
|
||||
}
|
||||
case SQLCOM_DO:
|
||||
if (tables && ((res= check_table_access(thd, SELECT_ACL, tables,0)) ||
|
||||
(res= open_and_lock_tables(thd,tables))))
|
||||
|
@ -99,6 +99,8 @@ public:
|
||||
#else
|
||||
bool (*set_params_data)(Prepared_statement *st);
|
||||
#endif
|
||||
bool (*set_params_from_vars)(Prepared_statement *stmt,
|
||||
List<LEX_STRING>& varnames);
|
||||
public:
|
||||
Prepared_statement(THD *thd_arg);
|
||||
virtual ~Prepared_statement();
|
||||
@ -631,6 +633,122 @@ static bool emb_insert_params_withlog(Prepared_statement *stmt)
|
||||
|
||||
#endif /*!EMBEDDED_LIBRARY*/
|
||||
|
||||
|
||||
/*
|
||||
Set prepared statement parameters from user variables.
|
||||
Also replace '?' marks with values in thd->query if binary logging is on.
|
||||
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
|
||||
|
||||
*/
|
||||
|
||||
static bool insert_params_from_vars(Prepared_statement *stmt,
|
||||
List<LEX_STRING>& varnames)
|
||||
{
|
||||
Item_param **begin= stmt->param_array;
|
||||
Item_param **end= begin + stmt->param_count;
|
||||
user_var_entry *entry;
|
||||
LEX_STRING *varname;
|
||||
DBUG_ENTER("insert_params_from_vars");
|
||||
|
||||
List_iterator<LEX_STRING> var_it(varnames);
|
||||
for (Item_param **it= begin; it < end; ++it)
|
||||
{
|
||||
Item_param *param= *it;
|
||||
varname= var_it++;
|
||||
if ((entry= (user_var_entry*)hash_search(&stmt->thd->user_vars,
|
||||
(byte*) varname->str,
|
||||
varname->length))
|
||||
&& entry->value)
|
||||
{
|
||||
param->item_result_type= entry->type;
|
||||
switch (entry->type)
|
||||
{
|
||||
case REAL_RESULT:
|
||||
param->set_double(*(double*)entry->value);
|
||||
break;
|
||||
case INT_RESULT:
|
||||
param->set_int(*(longlong*)entry->value);
|
||||
break;
|
||||
case STRING_RESULT:
|
||||
param->set_value(entry->value, entry->length,
|
||||
entry->collation.collation);
|
||||
break;
|
||||
default:
|
||||
DBUG_ASSERT(0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
param->item_result_type= INT_RESULT;
|
||||
param->maybe_null= param->null_value= 1;
|
||||
param->value_is_set= 0;
|
||||
}
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
static bool insert_params_from_vars_with_log(Prepared_statement *stmt,
|
||||
List<LEX_STRING>& varnames)
|
||||
{
|
||||
Item_param **begin= stmt->param_array;
|
||||
Item_param **end= begin + stmt->param_count;
|
||||
user_var_entry *entry;
|
||||
LEX_STRING *varname;
|
||||
DBUG_ENTER("insert_params_from_vars");
|
||||
|
||||
List_iterator<LEX_STRING> var_it(varnames);
|
||||
String str, query;
|
||||
const String *res;
|
||||
uint32 length= 0;
|
||||
|
||||
for (Item_param **it= begin; it < end; ++it)
|
||||
{
|
||||
Item_param *param= *it;
|
||||
varname= var_it++;
|
||||
if ((entry= (user_var_entry*)hash_search(&stmt->thd->user_vars,
|
||||
(byte*) varname->str,
|
||||
varname->length))
|
||||
&& entry->value)
|
||||
{
|
||||
param->item_result_type= entry->type;
|
||||
switch (entry->type)
|
||||
{
|
||||
case REAL_RESULT:
|
||||
param->set_double(*(double*)entry->value);
|
||||
break;
|
||||
case INT_RESULT:
|
||||
param->set_int(*(longlong*)entry->value);
|
||||
break;
|
||||
case STRING_RESULT:
|
||||
param->set_value(entry->value, entry->length,
|
||||
entry->collation.collation);
|
||||
break;
|
||||
default:
|
||||
DBUG_ASSERT(0);
|
||||
}
|
||||
res= param->query_val_str(&str);
|
||||
}
|
||||
else
|
||||
{
|
||||
param->item_result_type= INT_RESULT;
|
||||
param->maybe_null= param->null_value= 1;
|
||||
param->value_is_set= 0;
|
||||
res= &my_null_string;
|
||||
}
|
||||
|
||||
if (query.replace(param->pos_in_query+length, 1, *res))
|
||||
DBUG_RETURN(1);
|
||||
length+= res->length()-1;
|
||||
}
|
||||
if (alloc_query(stmt->thd, (char *) query.ptr(), query.length()+1))
|
||||
DBUG_RETURN(1);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
/*
|
||||
Validate the following information for INSERT statement:
|
||||
- field existence
|
||||
@ -788,7 +906,8 @@ static int mysql_test_select_fields(Prepared_statement *stmt,
|
||||
Item *having, ORDER *proc,
|
||||
ulong select_options,
|
||||
SELECT_LEX_UNIT *unit,
|
||||
SELECT_LEX *select_lex)
|
||||
SELECT_LEX *select_lex,
|
||||
bool text_protocol)
|
||||
{
|
||||
THD *thd= stmt->thd;
|
||||
LEX *lex= stmt->lex;
|
||||
@ -822,7 +941,7 @@ static int mysql_test_select_fields(Prepared_statement *stmt,
|
||||
|
||||
if (lex->describe)
|
||||
{
|
||||
if (send_prep_stmt(stmt, 0))
|
||||
if (!text_protocol && send_prep_stmt(stmt, 0))
|
||||
goto err;
|
||||
}
|
||||
else
|
||||
@ -842,6 +961,8 @@ static int mysql_test_select_fields(Prepared_statement *stmt,
|
||||
goto err_prep;
|
||||
}
|
||||
|
||||
if (!text_protocol)
|
||||
{
|
||||
if (send_prep_stmt(stmt, fields.elements) ||
|
||||
thd->protocol_simple.send_fields(&fields, 0)
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
@ -849,7 +970,7 @@ static int mysql_test_select_fields(Prepared_statement *stmt,
|
||||
#endif
|
||||
)
|
||||
goto err_prep;
|
||||
|
||||
}
|
||||
unit->cleanup();
|
||||
}
|
||||
thd->free_temporary_memory_pool_for_ps_preparing();
|
||||
@ -873,7 +994,7 @@ err:
|
||||
1 error, sent to client
|
||||
*/
|
||||
|
||||
static int send_prepare_results(Prepared_statement *stmt)
|
||||
static int send_prepare_results(Prepared_statement *stmt, bool text_protocol)
|
||||
{
|
||||
THD *thd= stmt->thd;
|
||||
LEX *lex= stmt->lex;
|
||||
@ -913,7 +1034,8 @@ static int send_prepare_results(Prepared_statement *stmt)
|
||||
select_lex->having,
|
||||
(ORDER*)lex->proc_list.first,
|
||||
select_lex->options | thd->options,
|
||||
&(lex->unit), select_lex)))
|
||||
&(lex->unit), select_lex,
|
||||
text_protocol)))
|
||||
goto error;
|
||||
/* Statement and field info has already been sent */
|
||||
DBUG_RETURN(0);
|
||||
@ -925,7 +1047,7 @@ static int send_prepare_results(Prepared_statement *stmt)
|
||||
*/
|
||||
break;
|
||||
}
|
||||
DBUG_RETURN(send_prep_stmt(stmt, 0));
|
||||
DBUG_RETURN(text_protocol? 0: send_prep_stmt(stmt, 0));
|
||||
|
||||
error:
|
||||
if (res < 0)
|
||||
@ -978,9 +1100,11 @@ static bool init_param_array(Prepared_statement *stmt)
|
||||
list in lex->param_array, so that a fast and direct
|
||||
retrieval can be made without going through all field
|
||||
items.
|
||||
|
||||
*/
|
||||
|
||||
void mysql_stmt_prepare(THD *thd, char *packet, uint packet_length)
|
||||
Prepared_statement *mysql_stmt_prepare(THD *thd, char *packet,
|
||||
uint packet_length, bool text_protocol)
|
||||
{
|
||||
LEX *lex;
|
||||
Prepared_statement *stmt= new Prepared_statement(thd);
|
||||
@ -992,14 +1116,14 @@ void mysql_stmt_prepare(THD *thd, char *packet, uint packet_length)
|
||||
if (stmt == 0)
|
||||
{
|
||||
send_error(thd, ER_OUT_OF_RESOURCES);
|
||||
DBUG_VOID_RETURN;
|
||||
DBUG_RETURN(NULL);
|
||||
}
|
||||
|
||||
if (thd->stmt_map.insert(stmt))
|
||||
{
|
||||
delete stmt;
|
||||
send_error(thd, ER_OUT_OF_RESOURCES);
|
||||
DBUG_VOID_RETURN;
|
||||
DBUG_RETURN(NULL);
|
||||
}
|
||||
|
||||
thd->stmt_backup.set_statement(thd);
|
||||
@ -1016,7 +1140,7 @@ void mysql_stmt_prepare(THD *thd, char *packet, uint packet_length)
|
||||
/* Statement map deletes statement on erase */
|
||||
thd->stmt_map.erase(stmt);
|
||||
send_error(thd, ER_OUT_OF_RESOURCES);
|
||||
DBUG_VOID_RETURN;
|
||||
DBUG_RETURN(NULL);
|
||||
}
|
||||
|
||||
mysql_log.write(thd, COM_PREPARE, "%s", packet);
|
||||
@ -1028,7 +1152,7 @@ void mysql_stmt_prepare(THD *thd, char *packet, uint packet_length)
|
||||
|
||||
error= yyparse((void *)thd) || thd->is_fatal_error ||
|
||||
init_param_array(stmt) ||
|
||||
send_prepare_results(stmt);
|
||||
send_prepare_results(stmt, text_protocol);
|
||||
|
||||
/* restore to WAIT_PRIOR: QUERY_PRIOR is set inside alloc_query */
|
||||
if (!(specialflag & SPECIAL_NO_PRIOR))
|
||||
@ -1044,6 +1168,7 @@ void mysql_stmt_prepare(THD *thd, char *packet, uint packet_length)
|
||||
{
|
||||
/* Statement map deletes statement on erase */
|
||||
thd->stmt_map.erase(stmt);
|
||||
stmt= NULL;
|
||||
/* error is sent inside yyparse/send_prepare_results */
|
||||
}
|
||||
else
|
||||
@ -1058,7 +1183,7 @@ void mysql_stmt_prepare(THD *thd, char *packet, uint packet_length)
|
||||
sl->prep_where= sl->where;
|
||||
}
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
DBUG_RETURN(stmt);
|
||||
}
|
||||
|
||||
/* Reinit statement before execution */
|
||||
@ -1119,7 +1244,6 @@ static void reset_stmt_for_execute(Prepared_statement *stmt)
|
||||
mysql_stmt_execute()
|
||||
*/
|
||||
|
||||
|
||||
void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
|
||||
{
|
||||
ulong stmt_id= uint4korr(packet);
|
||||
@ -1195,6 +1319,46 @@ set_params_data_err:
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Execute prepared statement using parameter values from
|
||||
lex->prepared_stmt_params and send result to the client using text protocol.
|
||||
*/
|
||||
|
||||
void mysql_sql_stmt_execute(THD *thd, Prepared_statement *stmt)
|
||||
{
|
||||
DBUG_ENTER("mysql_stmt_execute");
|
||||
if (stmt->param_count != thd->lex->prepared_stmt_params.elements)
|
||||
{
|
||||
my_error(ER_WRONG_ARGUMENTS, MYF(0), "mysql_execute");
|
||||
send_error(thd);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
thd->stmt_backup.set_statement(thd);
|
||||
thd->set_statement(stmt);
|
||||
reset_stmt_for_execute(stmt);
|
||||
thd->command= COM_EXECUTE;
|
||||
|
||||
if (stmt->set_params_from_vars(stmt, thd->stmt_backup.lex->
|
||||
prepared_stmt_params))
|
||||
{
|
||||
thd->set_statement(&thd->stmt_backup);
|
||||
my_error(ER_WRONG_ARGUMENTS, MYF(0), "mysql_execute");
|
||||
send_error(thd);
|
||||
}
|
||||
|
||||
if (!(specialflag & SPECIAL_NO_PRIOR))
|
||||
my_pthread_setprio(pthread_self(),QUERY_PRIOR);
|
||||
mysql_execute_command(thd);
|
||||
if (!(specialflag & SPECIAL_NO_PRIOR))
|
||||
my_pthread_setprio(pthread_self(), WAIT_PRIOR);
|
||||
|
||||
cleanup_items(stmt->free_list);
|
||||
close_thread_tables(thd); // to close derived tables
|
||||
thd->set_statement(&thd->stmt_backup);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Reset a prepared statement, in case there was an error in send_longdata.
|
||||
Note: we don't send any reply to that command.
|
||||
@ -1336,6 +1500,7 @@ Prepared_statement::Prepared_statement(THD *thd_arg)
|
||||
if (mysql_bin_log.is_open())
|
||||
{
|
||||
log_full_query= 1;
|
||||
set_params_from_vars= insert_params_from_vars_with_log;
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
set_params= insert_params_withlog;
|
||||
#else
|
||||
@ -1343,12 +1508,15 @@ Prepared_statement::Prepared_statement(THD *thd_arg)
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
set_params_from_vars= insert_params_from_vars;
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
set_params= insert_params;
|
||||
#else
|
||||
set_params_data= emb_insert_params;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Prepared_statement::~Prepared_statement()
|
||||
|
@ -431,6 +431,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
|
||||
%token MEDIUMTEXT
|
||||
%token NUMERIC_SYM
|
||||
%token PRECISION
|
||||
%token PREPARE_SYM
|
||||
%token DEALLOCATE_SYM
|
||||
%token QUICK
|
||||
%token REAL
|
||||
%token SIGNED_SYM
|
||||
@ -723,6 +725,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
|
||||
precision subselect_start opt_and charset
|
||||
subselect_end select_var_list select_var_list_init help opt_len
|
||||
opt_extended_describe
|
||||
prepare execute deallocate
|
||||
END_OF_INPUT
|
||||
|
||||
%type <NONE>
|
||||
@ -759,10 +762,12 @@ verb_clause:
|
||||
| checksum
|
||||
| commit
|
||||
| create
|
||||
| deallocate
|
||||
| delete
|
||||
| describe
|
||||
| do
|
||||
| drop
|
||||
| execute
|
||||
| flush
|
||||
| grant
|
||||
| handler
|
||||
@ -774,6 +779,7 @@ verb_clause:
|
||||
| optimize
|
||||
| keycache
|
||||
| preload
|
||||
| prepare
|
||||
| purge
|
||||
| rename
|
||||
| repair
|
||||
@ -794,6 +800,72 @@ verb_clause:
|
||||
| use
|
||||
;
|
||||
|
||||
deallocate:
|
||||
DEALLOCATE_SYM PREPARE_SYM ident
|
||||
{
|
||||
THD *thd=YYTHD;
|
||||
LEX *lex= thd->lex;
|
||||
if (thd->command == COM_PREPARE)
|
||||
{
|
||||
yyerror(ER(ER_SYNTAX_ERROR));
|
||||
YYABORT;
|
||||
}
|
||||
lex->sql_command= SQLCOM_DEALLOCATE_PREPARE;
|
||||
lex->prepared_stmt_name= $3;
|
||||
};
|
||||
|
||||
prepare:
|
||||
PREPARE_SYM ident FROM TEXT_STRING_sys
|
||||
{
|
||||
THD *thd=YYTHD;
|
||||
LEX *lex= thd->lex;
|
||||
if (thd->command == COM_PREPARE)
|
||||
{
|
||||
yyerror(ER(ER_SYNTAX_ERROR));
|
||||
YYABORT;
|
||||
}
|
||||
lex->sql_command= SQLCOM_PREPARE;
|
||||
lex->prepared_stmt_name= $2;
|
||||
lex->prepared_stmt_code= $4;
|
||||
};
|
||||
|
||||
|
||||
execute:
|
||||
EXECUTE_SYM ident
|
||||
{
|
||||
THD *thd=YYTHD;
|
||||
LEX *lex= thd->lex;
|
||||
if (thd->command == COM_PREPARE)
|
||||
{
|
||||
yyerror(ER(ER_SYNTAX_ERROR));
|
||||
YYABORT;
|
||||
}
|
||||
lex->sql_command= SQLCOM_EXECUTE;
|
||||
lex->prepared_stmt_name= $2;
|
||||
}
|
||||
execute_using
|
||||
{}
|
||||
;
|
||||
|
||||
execute_using:
|
||||
/* nothing */
|
||||
| USING execute_var_list
|
||||
;
|
||||
|
||||
execute_var_list:
|
||||
execute_var_list ',' execute_var_ident
|
||||
| execute_var_ident
|
||||
;
|
||||
|
||||
execute_var_ident: '@' ident_or_text
|
||||
{
|
||||
LEX *lex=Lex;
|
||||
LEX_STRING *lexstr= (LEX_STRING*)sql_memdup(&$2, sizeof(LEX_STRING));
|
||||
if (!lexstr || lex->prepared_stmt_params.push_back(lexstr))
|
||||
YYABORT;
|
||||
}
|
||||
;
|
||||
|
||||
/* help */
|
||||
|
||||
help:
|
||||
@ -4899,6 +4971,7 @@ keyword:
|
||||
| DATETIME {}
|
||||
| DATE_SYM {}
|
||||
| DAY_SYM {}
|
||||
| DEALLOCATE_SYM {}
|
||||
| DELAY_KEY_WRITE_SYM {}
|
||||
| DES_KEY_FILE {}
|
||||
| DIRECTORY_SYM {}
|
||||
@ -4996,6 +5069,7 @@ keyword:
|
||||
| PASSWORD {}
|
||||
| POINT_SYM {}
|
||||
| POLYGON {}
|
||||
| PREPARE_SYM {}
|
||||
| PREV_SYM {}
|
||||
| PROCESS {}
|
||||
| PROCESSLIST_SYM {}
|
||||
|
Reference in New Issue
Block a user