summaryrefslogtreecommitdiff
path: root/sql/sql_prepare.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_prepare.cc')
-rw-r--r--sql/sql_prepare.cc60
1 files changed, 47 insertions, 13 deletions
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 982e00391ef..a9a81ed7b06 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -899,10 +899,9 @@ static int mysql_test_insert(Prepared_statement *stmt,
List_iterator_fast<List_item> its(values_list);
List_item *values;
int res;
- my_bool update= (lex->value_list.elements ? UPDATE_ACL : 0);
DBUG_ENTER("mysql_test_insert");
- if ((res= insert_precheck(thd, table_list, update)))
+ if ((res= insert_precheck(thd, table_list)))
DBUG_RETURN(res);
/*
@@ -1071,6 +1070,12 @@ static int mysql_test_select(Prepared_statement *stmt,
DBUG_RETURN(1);
#endif
+ if (!lex->result && !(lex->result= new (&stmt->mem_root) select_send))
+ {
+ send_error(thd);
+ goto err;
+ }
+
if ((result= open_and_lock_tables(thd, tables)))
{
result= 1; // Error sent
@@ -1096,9 +1101,21 @@ static int mysql_test_select(Prepared_statement *stmt,
}
else
{
- if (send_prep_stmt(stmt, lex->select_lex.item_list.elements) ||
- thd->protocol_simple.send_fields(&lex->select_lex.item_list,
- Protocol::SEND_EOF)
+ /* Make copy of item list, as change_columns may change it */
+ List<Item> fields(lex->select_lex.item_list);
+
+ /* Change columns if a procedure like analyse() */
+ if (unit->last_procedure &&
+ unit->last_procedure->change_columns(fields))
+ goto err_prep;
+
+ /*
+ We can use lex->result as it should've been
+ prepared in unit->prepare call above.
+ */
+ if (send_prep_stmt(stmt, lex->result->field_count(fields)) ||
+ thd->protocol_simple.send_fields(fields,
+ Protocol::SEND_EOF)
#ifndef EMBEDDED_LIBRARY
|| net_flush(&thd->net)
#endif
@@ -1398,8 +1415,7 @@ static int send_prepare_results(Prepared_statement *stmt, bool text_protocol)
res= mysql_test_insert(stmt, tables, lex->field_list,
lex->many_values,
select_lex->item_list, lex->value_list,
- (lex->value_list.elements ?
- DUP_UPDATE : lex->duplicates));
+ lex->duplicates);
break;
case SQLCOM_UPDATE:
@@ -1491,8 +1507,16 @@ error:
static bool init_param_array(Prepared_statement *stmt)
{
LEX *lex= stmt->lex;
+ THD *thd= stmt->thd;
if ((stmt->param_count= lex->param_list.elements))
{
+ if (stmt->param_count > (uint) UINT_MAX16)
+ {
+ /* Error code to be defined in 5.0 */
+ send_error(thd, ER_UNKNOWN_ERROR,
+ "Prepared statement contains too many placeholders.");
+ return 1;
+ }
Item_param **to;
List_iterator<Item_param> param_iterator(lex->param_list);
/* Use thd->mem_root as it points at statement mem_root */
@@ -1501,7 +1525,7 @@ static bool init_param_array(Prepared_statement *stmt)
sizeof(Item_param*) * stmt->param_count);
if (!stmt->param_array)
{
- send_error(stmt->thd, ER_OUT_OF_RESOURCES);
+ send_error(thd, ER_OUT_OF_RESOURCES);
return 1;
}
for (to= stmt->param_array;
@@ -1596,11 +1620,13 @@ int mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
thd->current_arena= stmt;
mysql_init_query(thd, (uchar *) thd->query, thd->query_length);
+ /* Reset warnings from previous command */
+ mysql_reset_errors(thd);
lex= thd->lex;
lex->safe_to_cache_query= 0;
error= yyparse((void *)thd) || thd->is_fatal_error ||
- init_param_array(stmt);
+ thd->net.report_error || init_param_array(stmt);
/*
While doing context analysis of the query (in send_prepare_results) we
allocate a lot of additional memory: for open tables, JOINs, derived
@@ -1628,6 +1654,7 @@ int mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
thd->restore_backup_statement(stmt, &thd->stmt_backup);
cleanup_items(stmt->free_list);
close_thread_tables(thd);
+ thd->rollback_item_tree_changes();
thd->cleanup_after_query();
thd->current_arena= thd;
@@ -1636,7 +1663,9 @@ int 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 */
+ if (thd->net.report_error)
+ send_error(thd);
+ /* otherwise the error is sent inside yyparse/send_prepare_results */
}
else
{
@@ -1781,6 +1810,8 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
DBUG_VOID_RETURN;
}
+ DBUG_ASSERT(thd->free_list == NULL);
+ mysql_reset_thd_for_next_command(thd);
if (flags & (ulong) CURSOR_TYPE_READ_ONLY)
{
if (stmt->lex->result)
@@ -1821,7 +1852,6 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
if (stmt->param_count && stmt->set_params_data(stmt, &expanded_query))
goto set_params_data_err;
#endif
- DBUG_ASSERT(thd->free_list == NULL);
thd->stmt_backup.set_statement(thd);
thd->set_statement(stmt);
thd->current_arena= stmt;
@@ -1903,6 +1933,8 @@ void mysql_sql_stmt_execute(THD *thd, LEX_STRING *stmt_name)
DBUG_VOID_RETURN;
}
+ /* Must go before setting variables, as it clears thd->user_var_events */
+ mysql_reset_thd_for_next_command(thd);
thd->set_n_backup_statement(stmt, &thd->stmt_backup);
thd->set_statement(stmt);
if (stmt->set_params_from_vars(stmt,
@@ -1949,8 +1981,7 @@ static void execute_stmt(THD *thd, Prepared_statement *stmt,
transformations of the query tree (i.e. negations elimination).
This should be done permanently on the parse tree of this statement.
*/
- if (stmt->state == Item_arena::PREPARED)
- thd->current_arena= stmt;
+ thd->current_arena= stmt;
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(),QUERY_PRIOR);
@@ -1959,7 +1990,9 @@ static void execute_stmt(THD *thd, Prepared_statement *stmt,
my_pthread_setprio(pthread_self(), WAIT_PRIOR);
thd->lex->unit.cleanup();
+ thd->current_arena= thd;
cleanup_items(stmt->free_list);
+ thd->rollback_item_tree_changes();
reset_stmt_params(stmt);
close_thread_tables(thd); // to close derived tables
thd->set_statement(&thd->stmt_backup);
@@ -2062,6 +2095,7 @@ void mysql_stmt_reset(THD *thd, char *packet)
*/
reset_stmt_params(stmt);
+ mysql_reset_thd_for_next_command(thd);
send_ok(thd);
DBUG_VOID_RETURN;