diff options
author | unknown <sergefp@mysql.com> | 2004-04-30 19:24:57 +0400 |
---|---|---|
committer | unknown <sergefp@mysql.com> | 2004-04-30 19:24:57 +0400 |
commit | 85f85a85480a9282219394032965e757632c14c2 (patch) | |
tree | 120c8f63c5a060b49e6a1a71ddaf88de49727407 /sql/sql_prepare.cc | |
parent | 541cef756834d1d1d4947b998d0befcb940f8945 (diff) | |
parent | 2902f9e8a57ca76cc52863d70d02dcf7693ce8cd (diff) | |
download | mariadb-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.cc | 257 |
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)); } |