summaryrefslogtreecommitdiff
path: root/sql/sql_prepare.cc
diff options
context:
space:
mode:
authorunknown <sergefp@mysql.com>2004-04-30 19:24:57 +0400
committerunknown <sergefp@mysql.com>2004-04-30 19:24:57 +0400
commit85f85a85480a9282219394032965e757632c14c2 (patch)
tree120c8f63c5a060b49e6a1a71ddaf88de49727407 /sql/sql_prepare.cc
parent541cef756834d1d1d4947b998d0befcb940f8945 (diff)
parent2902f9e8a57ca76cc52863d70d02dcf7693ce8cd (diff)
downloadmariadb-git-85f85a85480a9282219394032965e757632c14c2.tar.gz
Merge spetrunia@bk-internal.mysql.com:/home/bk/mysql-4.1
into mysql.com:/dbdata/psergey/mysql-4.1-ps-merge sql/item.cc: Auto merged sql/sql_parse.cc: Auto merged sql/sql_prepare.cc: Auto merged
Diffstat (limited to 'sql/sql_prepare.cc')
-rw-r--r--sql/sql_prepare.cc257
1 files changed, 219 insertions, 38 deletions
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 4630380967e..efc5b9bdbf8 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -99,12 +99,15 @@ 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();
virtual Statement::Type type() const;
};
+static void execute_stmt(THD *thd, Prepared_statement *stmt);
/******************************************************************************
Implementation
@@ -644,6 +647,116 @@ static bool emb_insert_params_withlog(Prepared_statement *stmt)
#endif /*!EMBEDDED_LIBRARY*/
+/*
+ Set prepared statement parameters from user variables.
+ 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->maybe_null= param->null_value= param->value_is_set= 1;
+ }
+ 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;
+ if (query.copy(stmt->query, stmt->query_length, default_charset_info))
+ DBUG_RETURN(1);
+
+ 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->maybe_null= param->null_value= param->value_is_set= 1;
+ 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 INSERT statement:
@@ -840,7 +953,7 @@ static int mysql_test_delete(Prepared_statement *stmt,
*/
static int mysql_test_select(Prepared_statement *stmt,
- TABLE_LIST *tables)
+ TABLE_LIST *tables, bool text_protocol)
{
THD *thd= stmt->thd;
LEX *lex= stmt->lex;
@@ -872,7 +985,7 @@ static int mysql_test_select(Prepared_statement *stmt,
if (lex->describe)
{
- if (send_prep_stmt(stmt, 0))
+ if (!text_protocol && send_prep_stmt(stmt, 0))
goto err;
}
else
@@ -886,14 +999,16 @@ static int mysql_test_select(Prepared_statement *stmt,
goto err_prep;
}
- if (send_prep_stmt(stmt, lex->select_lex.item_list.elements) ||
+ if (!text_protocol)
+ {
+ if (send_prep_stmt(stmt, lex->select_lex.item_list.elements) ||
thd->protocol_simple.send_fields(&lex->select_lex.item_list, 0)
#ifndef EMBEDDED_LIBRARY
- || net_flush(&thd->net)
+ || net_flush(&thd->net)
#endif
- )
- goto err_prep;
-
+ )
+ goto err_prep;
+ }
unit->cleanup();
}
thd->free_temporary_memory_pool_for_ps_preparing();
@@ -1171,7 +1286,7 @@ static int mysql_test_insert_select(Prepared_statement *stmt,
0 success
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;
@@ -1208,7 +1323,7 @@ static int send_prepare_results(Prepared_statement *stmt)
break;
case SQLCOM_SELECT:
- if ((res= mysql_test_select(stmt, tables)))
+ if ((res= mysql_test_select(stmt, tables, text_protocol)))
goto error;
/* Statement and field info has already been sent */
DBUG_RETURN(0);
@@ -1266,7 +1381,7 @@ static int send_prepare_results(Prepared_statement *stmt)
goto error;
}
if (res == 0)
- DBUG_RETURN(send_prep_stmt(stmt, 0));
+ DBUG_RETURN(text_protocol?0:send_prep_stmt(stmt, 0));
error:
if (res < 0)
send_error(thd, thd->killed ? ER_SERVER_SHUTDOWN : 0);
@@ -1307,6 +1422,14 @@ static bool init_param_array(Prepared_statement *stmt)
/*
+ SYNOPSIS
+ mysql_stmt_prepare()
+ packet Prepared query
+ packet_length query length, with ignored trailing NULL or quote char.
+ name NULL or statement name. For unnamed statements binary PS
+ protocol is used, for named statmenents text protocol is
+ used.
+
Parse the query and send the total number of parameters
and resultset metadata information back to client (if any),
without executing the query i.e. without any log/disk
@@ -1318,9 +1441,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)
+int mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
+ LEX_STRING *name)
{
LEX *lex;
Prepared_statement *stmt= new Prepared_statement(thd);
@@ -1332,14 +1457,26 @@ 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(1);
+ }
+
+ if (name)
+ {
+ stmt->name.length= name->length;
+ if (!(stmt->name.str= my_memdup((byte*)name->str, name->length,
+ MYF(MY_WME))))
+ {
+ delete stmt;
+ send_error(thd, ER_OUT_OF_RESOURCES);
+ DBUG_RETURN(1);
+ }
}
if (thd->stmt_map.insert(stmt))
{
delete stmt;
send_error(thd, ER_OUT_OF_RESOURCES);
- DBUG_VOID_RETURN;
+ DBUG_RETURN(1);
}
thd->stmt_backup.set_statement(thd);
@@ -1356,7 +1493,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(1);
}
mysql_log.write(thd, COM_PREPARE, "%s", packet);
@@ -1368,7 +1505,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, test(name));
/* restore to WAIT_PRIOR: QUERY_PRIOR is set inside alloc_query */
if (!(specialflag & SPECIAL_NO_PRIOR))
@@ -1384,6 +1521,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
@@ -1398,7 +1536,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 */
@@ -1451,6 +1589,7 @@ static void reset_stmt_for_execute(Prepared_statement *stmt)
}
}
+
/*
Executes previously prepared query.
If there is any parameters, then replace markers with the data supplied
@@ -1459,7 +1598,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);
@@ -1483,11 +1621,6 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
DBUG_VOID_RETURN;
}
- thd->stmt_backup.set_statement(thd);
- thd->set_statement(stmt);
-
- reset_stmt_for_execute(stmt);
-
#ifndef EMBEDDED_LIBRARY
if (stmt->param_count)
{
@@ -1505,21 +1638,68 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
if (stmt->param_count && stmt->set_params_data(stmt))
goto set_params_data_err;
#endif
+ thd->protocol= &thd->protocol_prep; // Switch to binary protocol
+ execute_stmt(thd, stmt);
+ thd->protocol= &thd->protocol_simple; // Use normal protocol
+ DBUG_VOID_RETURN;
+
+set_params_data_err:
+ my_error(ER_WRONG_ARGUMENTS, MYF(0), "mysql_execute");
+ send_error(thd);
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ 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, LEX_STRING *stmt_name)
+{
+ Prepared_statement *stmt;
+ DBUG_ENTER("mysql_stmt_execute");
+
+ if (!(stmt= (Prepared_statement*)thd->stmt_map.find_by_name(stmt_name)))
+ {
+ send_error(thd, ER_UNKNOWN_STMT_HANDLER,
+ "Undefined prepared statement");
+ DBUG_VOID_RETURN;
+ }
+
+ 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;
+ }
+ /* Item_param allows setting parameters in COM_EXECUTE only */
+ thd->command= COM_EXECUTE;
+
+ if (stmt->set_params_from_vars(stmt, thd->lex->prepared_stmt_params))
+ {
+ my_error(ER_WRONG_ARGUMENTS, MYF(0), "mysql_execute");
+ send_error(thd);
+ }
+ execute_stmt(thd, stmt);
+ DBUG_VOID_RETURN;
+}
+
+/*
+ Execute prepared statement.
+ Caller must set parameter values and thd::protocol.
+*/
+static void execute_stmt(THD *thd, Prepared_statement *stmt)
+{
+ DBUG_ENTER("execute_stmt");
+ thd->stmt_backup.set_statement(thd);
+ thd->set_statement(stmt);
+ reset_stmt_for_execute(stmt);
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(),QUERY_PRIOR);
-
- /*
- TODO:
- Also, have checks on basic executions such as mysql_insert(),
- mysql_delete(), mysql_update() and mysql_select() to not to
- have re-check on setup_* and other things ..
- */
- thd->protocol= &thd->protocol_prep; // Switch to binary protocol
mysql_execute_command(thd);
thd->lex->unit.cleanup();
- thd->protocol= &thd->protocol_simple; // Use normal protocol
-
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(), WAIT_PRIOR);
@@ -1527,15 +1707,10 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
close_thread_tables(thd); // to close derived tables
thd->set_statement(&thd->stmt_backup);
DBUG_VOID_RETURN;
-
-set_params_data_err:
- thd->set_statement(&thd->stmt_backup);
- my_error(ER_WRONG_ARGUMENTS, MYF(0), "mysql_execute");
- send_error(thd);
- 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.
@@ -1677,6 +1852,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
@@ -1684,17 +1860,22 @@ 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()
{
free_items(free_list);
+ if (name.str)
+ my_free(name.str, MYF(0));
}