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.cc335
1 files changed, 198 insertions, 137 deletions
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index af3da834a7a..a97bd908468 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -34,6 +34,12 @@ When one prepares a statement:
[Params meta info (stubs only for now)] (if Param_count > 0)
[Columns meta info] (if Column_count > 0)
+ During prepare the tables used in a statement are opened, but no
+ locks are acquired. Table opening will block any DDL during the
+ operation, and we do not need any locks as we neither read nor
+ modify any data during prepare. Tables are closed after prepare
+ finishes.
+
When one executes a statement:
- Server gets the command 'COM_STMT_EXECUTE' to execute the
@@ -53,6 +59,10 @@ When one executes a statement:
- Execute the query without re-parsing and send back the results
to client
+ During execution of prepared statement tables are opened and locked
+ the same way they would for normal (non-prepared) statement
+ execution. Tables are unlocked and closed after the execution.
+
When one supplies long data for a placeholder:
- Server gets the long data in pieces with command type
@@ -83,11 +93,11 @@ When one supplies long data for a placeholder:
/* A result class used to send cursor rows using the binary protocol. */
-class Select_fetch_protocol_prep: public select_send
+class Select_fetch_protocol_binary: public select_send
{
- Protocol_prep protocol;
+ Protocol_binary protocol;
public:
- Select_fetch_protocol_prep(THD *thd);
+ Select_fetch_protocol_binary(THD *thd);
virtual bool send_fields(List<Item> &list, uint flags);
virtual bool send_data(List<Item> &items);
virtual bool send_eof();
@@ -115,7 +125,7 @@ public:
};
THD *thd;
- Select_fetch_protocol_prep result;
+ Select_fetch_protocol_binary result;
Protocol *protocol;
Item_param **param_array;
uint param_count;
@@ -219,7 +229,7 @@ find_prepared_statement(THD *thd, ulong id, const char *where)
static bool send_prep_stmt(Prepared_statement *stmt, uint columns)
{
NET *net= &stmt->thd->net;
- char buff[12];
+ uchar buff[12];
uint tmp;
DBUG_ENTER("send_prep_stmt");
@@ -237,9 +247,9 @@ static bool send_prep_stmt(Prepared_statement *stmt, uint columns)
*/
DBUG_RETURN(my_net_write(net, buff, sizeof(buff)) ||
(stmt->param_count &&
- stmt->thd->protocol_simple.send_fields((List<Item> *)
- &stmt->lex->param_list,
- Protocol::SEND_EOF)));
+ stmt->thd->protocol_text.send_fields((List<Item> *)
+ &stmt->lex->param_list,
+ Protocol::SEND_EOF)));
}
#else
static bool send_prep_stmt(Prepared_statement *stmt,
@@ -635,6 +645,7 @@ static void setup_one_conversion_function(THD *thd, Item_param *param,
param->value.cs_info.character_set_of_placeholder= &my_charset_bin;
param->value.cs_info.character_set_client=
thd->variables.character_set_client;
+ DBUG_ASSERT(thd->variables.character_set_client);
param->value.cs_info.final_character_set_of_str_value= &my_charset_bin;
param->item_type= Item::STRING_ITEM;
param->item_result_type= STRING_RESULT;
@@ -682,7 +693,7 @@ static void setup_one_conversion_function(THD *thd, Item_param *param,
and generate a valid query for logging.
NOTES
- This function, along with other _withlog functions is called when one of
+ This function, along with other _with_log functions is called when one of
binary, slow or general logs is open. Logging of prepared statements in
all cases is performed by means of conventional queries: if parameter
data was supplied from C API, each placeholder in the query is
@@ -706,9 +717,9 @@ static void setup_one_conversion_function(THD *thd, Item_param *param,
0 if success, 1 otherwise
*/
-static bool insert_params_withlog(Prepared_statement *stmt, uchar *null_array,
- uchar *read_pos, uchar *data_end,
- String *query)
+static bool insert_params_with_log(Prepared_statement *stmt, uchar *null_array,
+ uchar *read_pos, uchar *data_end,
+ String *query)
{
THD *thd= stmt->thd;
Item_param **begin= stmt->param_array;
@@ -716,7 +727,7 @@ static bool insert_params_withlog(Prepared_statement *stmt, uchar *null_array,
uint32 length= 0;
String str;
const String *res;
- DBUG_ENTER("insert_params_withlog");
+ DBUG_ENTER("insert_params_with_log");
if (query->copy(stmt->query, stmt->query_length, default_charset_info))
DBUG_RETURN(1);
@@ -866,7 +877,8 @@ static bool emb_insert_params(Prepared_statement *stmt, String *expanded_query)
}
-static bool emb_insert_params_withlog(Prepared_statement *stmt, String *query)
+static bool emb_insert_params_with_log(Prepared_statement *stmt,
+ String *query)
{
THD *thd= stmt->thd;
Item_param **it= stmt->param_array;
@@ -877,7 +889,7 @@ static bool emb_insert_params_withlog(Prepared_statement *stmt, String *query)
const String *res;
uint32 length= 0;
- DBUG_ENTER("emb_insert_params_withlog");
+ DBUG_ENTER("emb_insert_params_with_log");
if (query->copy(stmt->query, stmt->query_length, default_charset_info))
DBUG_RETURN(1);
@@ -944,7 +956,7 @@ static bool insert_params_from_vars(Prepared_statement *stmt,
Item_param *param= *it;
varname= var_it++;
entry= (user_var_entry*)hash_search(&stmt->thd->user_vars,
- (byte*) varname->str,
+ (uchar*) varname->str,
varname->length);
if (param->set_from_user_var(stmt->thd, entry) ||
param->convert_str_value(stmt->thd))
@@ -991,7 +1003,7 @@ static bool insert_params_from_vars_with_log(Prepared_statement *stmt,
Item_param *param= *it;
varname= var_it++;
- entry= (user_var_entry *) hash_search(&thd->user_vars, (byte*) varname->str,
+ entry= (user_var_entry *) hash_search(&thd->user_vars, (uchar*) varname->str,
varname->length);
/*
We have to call the setup_one_conversion_function() here to set
@@ -1062,7 +1074,7 @@ static bool mysql_test_insert(Prepared_statement *stmt,
if (table_list->table)
{
// don't allocate insert_values
- table_list->table->insert_values=(byte *)1;
+ table_list->table->insert_values=(uchar *)1;
}
if (mysql_prepare_insert(thd, table_list, table_list->table,
@@ -1074,7 +1086,7 @@ static bool mysql_test_insert(Prepared_statement *stmt,
its.rewind();
if (table_list->lock_type == TL_WRITE_DELAYED &&
- !(table_list->table->file->table_flags() & HA_CAN_INSERT_DELAYED))
+ !(table_list->table->file->ha_table_flags() & HA_CAN_INSERT_DELAYED))
{
my_error(ER_ILLEGAL_HA, MYF(0), (table_list->view ?
table_list->view_name.str :
@@ -1089,7 +1101,7 @@ static bool mysql_test_insert(Prepared_statement *stmt,
my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), counter);
goto error;
}
- if (setup_fields(thd, 0, *values, 0, 0, 0))
+ if (setup_fields(thd, 0, *values, MARK_COLUMNS_NONE, 0, 0))
goto error;
}
}
@@ -1125,32 +1137,20 @@ static int mysql_test_update(Prepared_statement *stmt,
#ifndef NO_EMBEDDED_ACCESS_CHECKS
uint want_privilege;
#endif
- bool need_reopen;
DBUG_ENTER("mysql_test_update");
- if (update_precheck(thd, table_list))
+ if (update_precheck(thd, table_list) ||
+ open_tables(thd, &table_list, &table_count, 0))
goto error;
- for ( ; ; )
+ if (table_list->multitable_view)
{
- if (open_tables(thd, &table_list, &table_count, 0))
- goto error;
-
- if (table_list->multitable_view)
- {
- DBUG_ASSERT(table_list->view != 0);
- DBUG_PRINT("info", ("Switch to multi-update"));
- /* pass counter value */
- thd->lex->table_count= table_count;
- /* convert to multiupdate */
- DBUG_RETURN(2);
- }
-
- if (!lock_tables(thd, table_list, table_count, &need_reopen))
- break;
- if (!need_reopen)
- goto error;
- close_tables_for_reopen(thd, &table_list);
+ DBUG_ASSERT(table_list->view != 0);
+ DBUG_PRINT("info", ("Switch to multi-update"));
+ /* pass counter value */
+ thd->lex->table_count= table_count;
+ /* convert to multiupdate */
+ DBUG_RETURN(2);
}
/*
@@ -1177,7 +1177,7 @@ static int mysql_test_update(Prepared_statement *stmt,
table_list->register_want_access(want_privilege);
#endif
thd->lex->select_lex.no_wrap_view_item= TRUE;
- res= setup_fields(thd, 0, select->item_list, 1, 0, 0);
+ res= setup_fields(thd, 0, select->item_list, MARK_COLUMNS_READ, 0, 0);
thd->lex->select_lex.no_wrap_view_item= FALSE;
if (res)
goto error;
@@ -1188,7 +1188,7 @@ static int mysql_test_update(Prepared_statement *stmt,
(SELECT_ACL & ~table_list->table->grant.privilege);
table_list->register_want_access(SELECT_ACL);
#endif
- if (setup_fields(thd, 0, stmt->lex->value_list, 0, 0, 0))
+ if (setup_fields(thd, 0, stmt->lex->value_list, MARK_COLUMNS_NONE, 0, 0))
goto error;
/* TODO: here we should send types of placeholders to the client. */
DBUG_RETURN(0);
@@ -1218,7 +1218,7 @@ static bool mysql_test_delete(Prepared_statement *stmt,
DBUG_ENTER("mysql_test_delete");
if (delete_precheck(thd, table_list) ||
- open_and_lock_tables(thd, table_list))
+ open_normal_and_derived_tables(thd, table_list, 0))
goto error;
if (!table_list->table)
@@ -1277,7 +1277,7 @@ static int mysql_test_select(Prepared_statement *stmt,
goto error;
}
- if (open_and_lock_tables(thd, tables))
+ if (open_normal_and_derived_tables(thd, tables, 0))
goto error;
thd->used_tables= 0; // Updated by setup_fields
@@ -1338,9 +1338,9 @@ static bool mysql_test_do_fields(Prepared_statement *stmt,
if (tables && check_table_access(thd, SELECT_ACL, tables, 0))
DBUG_RETURN(TRUE);
- if (open_and_lock_tables(thd, tables))
+ if (open_normal_and_derived_tables(thd, tables, 0))
DBUG_RETURN(TRUE);
- DBUG_RETURN(setup_fields(thd, 0, *values, 0, 0, 0));
+ DBUG_RETURN(setup_fields(thd, 0, *values, MARK_COLUMNS_NONE, 0, 0));
}
@@ -1368,7 +1368,7 @@ static bool mysql_test_set_fields(Prepared_statement *stmt,
set_var_base *var;
if (tables && check_table_access(thd, SELECT_ACL, tables, 0) ||
- open_and_lock_tables(thd, tables))
+ open_normal_and_derived_tables(thd, tables, 0))
goto error;
while ((var= it++))
@@ -1394,7 +1394,7 @@ error:
NOTE
This function won't directly open tables used in select. They should
be opened either by calling function (and in this case you probably
- should use select_like_stmt_test_with_open_n_lock()) or by
+ should use select_like_stmt_test_with_open()) or by
"specific_prepare" call (like this happens in case of multi-update).
RETURN VALUE
@@ -1422,14 +1422,14 @@ static bool select_like_stmt_test(Prepared_statement *stmt,
}
/*
- Check internal SELECT of the prepared command (with opening and
- locking of used tables).
+ Check internal SELECT of the prepared command (with opening of used
+ tables).
SYNOPSIS
- select_like_stmt_test_with_open_n_lock()
+ select_like_stmt_test_with_open()
stmt prepared statement
- tables list of tables to be opened and locked
- before calling specific_prepare function
+ tables list of tables to be opened before calling
+ specific_prepare function
specific_prepare function of command specific prepare
setup_tables_done_option options to be passed to LEX::unit.prepare()
@@ -1439,19 +1439,20 @@ static bool select_like_stmt_test(Prepared_statement *stmt,
*/
static bool
-select_like_stmt_test_with_open_n_lock(Prepared_statement *stmt,
- TABLE_LIST *tables,
- bool (*specific_prepare)(THD *thd),
- ulong setup_tables_done_option)
+select_like_stmt_test_with_open(Prepared_statement *stmt,
+ TABLE_LIST *tables,
+ bool (*specific_prepare)(THD *thd),
+ ulong setup_tables_done_option)
{
- DBUG_ENTER("select_like_stmt_test_with_open_n_lock");
+ DBUG_ENTER("select_like_stmt_test_with_open");
/*
- We should not call LEX::unit.cleanup() after this open_and_lock_tables()
- call because we don't allow prepared EXPLAIN yet so derived tables will
- clean up after themself.
+ We should not call LEX::unit.cleanup() after this
+ open_normal_and_derived_tables() call because we don't allow
+ prepared EXPLAIN yet so derived tables will clean up after
+ themself.
*/
- if (open_and_lock_tables(stmt->thd, tables))
+ if (open_normal_and_derived_tables(stmt->thd, tables, 0))
DBUG_RETURN(TRUE);
DBUG_RETURN(select_like_stmt_test(stmt, specific_prepare,
@@ -1495,7 +1496,7 @@ static bool mysql_test_create_table(Prepared_statement *stmt)
create_table->create= TRUE;
}
- if (open_and_lock_tables(stmt->thd, lex->query_tables))
+ if (open_normal_and_derived_tables(stmt->thd, lex->query_tables, 0))
DBUG_RETURN(TRUE);
if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
@@ -1563,9 +1564,9 @@ static bool mysql_test_multidelete(Prepared_statement *stmt,
}
if (multi_delete_precheck(stmt->thd, tables) ||
- select_like_stmt_test_with_open_n_lock(stmt, tables,
- &mysql_multi_delete_prepare,
- OPTION_SETUP_TABLES_DONE))
+ select_like_stmt_test_with_open(stmt, tables,
+ &mysql_multi_delete_prepare,
+ OPTION_SETUP_TABLES_DONE))
goto error;
if (!tables->table)
{
@@ -1581,15 +1582,16 @@ error:
/*
Wrapper for mysql_insert_select_prepare, to make change of local tables
- after open_and_lock_tables() call.
+ after open_normal_and_derived_tables() call.
SYNOPSIS
mysql_insert_select_prepare_tester()
thd thread handle
NOTE
- We need to remove the first local table after open_and_lock_tables,
- because mysql_handle_derived uses local tables lists.
+ We need to remove the first local table after
+ open_normal_and_derived_tables(), because mysql_handle_derived
+ uses local tables lists.
*/
static bool mysql_insert_select_prepare_tester(THD *thd)
@@ -1599,7 +1601,7 @@ static bool mysql_insert_select_prepare_tester(THD *thd)
next_local;
/* Skip first table, which is the table we are inserting in */
- first_select->table_list.first= (byte *) second_table;
+ first_select->table_list.first= (uchar *) second_table;
thd->lex->select_lex.context.table_list=
thd->lex->select_lex.context.first_name_resolution_table= second_table;
@@ -1630,7 +1632,7 @@ static bool mysql_test_insert_select(Prepared_statement *stmt,
if (tables->table)
{
// don't allocate insert_values
- tables->table->insert_values=(byte *)1;
+ tables->table->insert_values=(uchar *)1;
}
if (insert_precheck(stmt->thd, tables))
@@ -1641,11 +1643,11 @@ static bool mysql_test_insert_select(Prepared_statement *stmt,
DBUG_ASSERT(first_local_table != 0);
res=
- select_like_stmt_test_with_open_n_lock(stmt, tables,
- &mysql_insert_select_prepare_tester,
- OPTION_SETUP_TABLES_DONE);
+ select_like_stmt_test_with_open(stmt, tables,
+ &mysql_insert_select_prepare_tester,
+ OPTION_SETUP_TABLES_DONE);
/* revert changes made by mysql_insert_select_prepare_tester */
- lex->select_lex.table_list.first= (byte*) first_local_table;
+ lex->select_lex.table_list.first= (uchar*) first_local_table;
return res;
}
@@ -1748,22 +1750,34 @@ static bool check_prepared_statement(Prepared_statement *stmt,
res= mysql_test_insert_select(stmt, tables);
break;
- case SQLCOM_SHOW_DATABASES:
+ /*
+ Note that we don't need to have cases in this list if they are
+ marked with CF_STATUS_COMMAND in sql_command_flags
+ */
case SQLCOM_SHOW_PROCESSLIST:
case SQLCOM_SHOW_STORAGE_ENGINES:
case SQLCOM_SHOW_PRIVILEGES:
case SQLCOM_SHOW_COLUMN_TYPES:
- case SQLCOM_SHOW_STATUS:
- case SQLCOM_SHOW_VARIABLES:
- case SQLCOM_SHOW_LOGS:
- case SQLCOM_SHOW_TABLES:
- case SQLCOM_SHOW_OPEN_TABLES:
- case SQLCOM_SHOW_CHARSETS:
- case SQLCOM_SHOW_COLLATIONS:
- case SQLCOM_SHOW_FIELDS:
- case SQLCOM_SHOW_KEYS:
+ case SQLCOM_SHOW_ENGINE_LOGS:
+ case SQLCOM_SHOW_ENGINE_STATUS:
+ case SQLCOM_SHOW_ENGINE_MUTEX:
case SQLCOM_SHOW_CREATE_DB:
case SQLCOM_SHOW_GRANTS:
+ case SQLCOM_SHOW_BINLOG_EVENTS:
+ case SQLCOM_SHOW_MASTER_STAT:
+ case SQLCOM_SHOW_SLAVE_STAT:
+ case SQLCOM_SHOW_CREATE_PROC:
+ case SQLCOM_SHOW_CREATE_FUNC:
+ case SQLCOM_SHOW_CREATE_EVENT:
+ case SQLCOM_SHOW_CREATE_TRIGGER:
+ case SQLCOM_SHOW_CREATE:
+ case SQLCOM_SHOW_PROC_CODE:
+ case SQLCOM_SHOW_FUNC_CODE:
+ case SQLCOM_SHOW_AUTHORS:
+ case SQLCOM_SHOW_CONTRIBUTORS:
+ case SQLCOM_SHOW_WARNS:
+ case SQLCOM_SHOW_ERRORS:
+ case SQLCOM_SHOW_BINLOGS:
case SQLCOM_DROP_TABLE:
case SQLCOM_RENAME_TABLE:
case SQLCOM_ALTER_TABLE:
@@ -1777,15 +1791,42 @@ static bool check_prepared_statement(Prepared_statement *stmt,
case SQLCOM_REPAIR:
case SQLCOM_ANALYZE:
case SQLCOM_OPTIMIZE:
+ case SQLCOM_CHANGE_MASTER:
+ case SQLCOM_RESET:
+ case SQLCOM_FLUSH:
+ case SQLCOM_SLAVE_START:
+ case SQLCOM_SLAVE_STOP:
+ case SQLCOM_INSTALL_PLUGIN:
+ case SQLCOM_UNINSTALL_PLUGIN:
+ case SQLCOM_CREATE_DB:
+ case SQLCOM_DROP_DB:
+ case SQLCOM_RENAME_DB:
+ case SQLCOM_CHECKSUM:
+ case SQLCOM_CREATE_USER:
+ case SQLCOM_RENAME_USER:
+ case SQLCOM_DROP_USER:
+ case SQLCOM_ASSIGN_TO_KEYCACHE:
+ case SQLCOM_PRELOAD_KEYS:
+ case SQLCOM_GRANT:
+ case SQLCOM_REVOKE:
+ case SQLCOM_KILL:
break;
case SQLCOM_PREPARE:
case SQLCOM_EXECUTE:
case SQLCOM_DEALLOCATE_PREPARE:
default:
- /* All other statements are not supported yet. */
- my_message(ER_UNSUPPORTED_PS, ER(ER_UNSUPPORTED_PS), MYF(0));
- goto error;
+ /*
+ Trivial check of all status commands. This is easier than having
+ things in the above case list, as it's less chance for mistakes.
+ */
+ if (!(sql_command_flags[sql_command] & CF_STATUS_COMMAND))
+ {
+ /* All other statements are not supported yet. */
+ my_message(ER_UNSUPPORTED_PS, ER(ER_UNSUPPORTED_PS), MYF(0));
+ goto error;
+ }
+ break;
}
if (res == 0)
DBUG_RETURN(text_protocol? FALSE : (send_prep_stmt(stmt, 0) ||
@@ -1870,7 +1911,7 @@ void mysql_stmt_prepare(THD *thd, const char *packet, uint packet_length)
/* First of all clear possible warnings from the previous command */
mysql_reset_thd_for_next_command(thd);
- if (! (stmt= new Prepared_statement(thd, &thd->protocol_prep)))
+ if (! (stmt= new Prepared_statement(thd, &thd->protocol_binary)))
DBUG_VOID_RETURN; /* out of memory: error is set in Sql_alloc */
if (thd->stmt_map.insert(thd, stmt))
@@ -1943,7 +1984,7 @@ static const char *get_dynamic_sql_string(LEX *lex, uint *query_len)
*/
if ((entry=
(user_var_entry*)hash_search(&thd->user_vars,
- (byte*)lex->prepared_stmt_code.str,
+ (uchar*)lex->prepared_stmt_code.str,
lex->prepared_stmt_code.length))
&& entry->value)
{
@@ -1972,7 +2013,7 @@ static const char *get_dynamic_sql_string(LEX *lex, uint *query_len)
len= (needs_conversion ? var_value->length() * to_cs->mbmaxlen :
var_value->length());
- if (!(query_str= alloc_root(thd->mem_root, len+1)))
+ if (!(query_str= (char*) alloc_root(thd->mem_root, len+1)))
goto end;
if (needs_conversion)
@@ -2035,8 +2076,8 @@ void mysql_sql_stmt_prepare(THD *thd)
const char *query;
uint query_len;
DBUG_ENTER("mysql_sql_stmt_prepare");
- DBUG_ASSERT(thd->protocol == &thd->protocol_simple);
LINT_INIT(query_len);
+ DBUG_ASSERT(thd->protocol == &thd->protocol_text);
if ((stmt= (Prepared_statement*) thd->stmt_map.find_by_name(name)))
{
@@ -2049,7 +2090,7 @@ void mysql_sql_stmt_prepare(THD *thd)
}
if (! (query= get_dynamic_sql_string(lex, &query_len)) ||
- ! (stmt= new Prepared_statement(thd, &thd->protocol_simple)))
+ ! (stmt= new Prepared_statement(thd, &thd->protocol_text)))
{
DBUG_VOID_RETURN; /* out of memory */
}
@@ -2245,7 +2286,7 @@ void mysql_stmt_execute(THD *thd, char *packet_arg, uint packet_length)
DBUG_VOID_RETURN;
DBUG_PRINT("exec_query", ("%s", stmt->query));
- DBUG_PRINT("info",("stmt: %p", stmt));
+ DBUG_PRINT("info",("stmt: 0x%lx", (long) stmt));
sp_cache_flush_obsolete(&thd->sp_proc_cache);
sp_cache_flush_obsolete(&thd->sp_func_cache);
@@ -2319,7 +2360,7 @@ void mysql_sql_stmt_execute(THD *thd)
/* Query text for binary, general or slow log, if any of them is open */
String expanded_query;
DBUG_ENTER("mysql_sql_stmt_execute");
- DBUG_PRINT("info", ("EXECUTE: %.*s\n", name->length, name->str));
+ DBUG_PRINT("info", ("EXECUTE: %.*s\n", (int) name->length, name->str));
if (!(stmt= (Prepared_statement*) thd->stmt_map.find_by_name(name)))
{
@@ -2334,7 +2375,7 @@ void mysql_sql_stmt_execute(THD *thd)
DBUG_VOID_RETURN;
}
- DBUG_PRINT("info",("stmt: %p", stmt));
+ DBUG_PRINT("info",("stmt: 0x%lx", (long) stmt));
/*
If the free_list is not empty, we'll wrongly free some externally
@@ -2380,7 +2421,7 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length)
/* First of all clear possible warnings from the previous command */
mysql_reset_thd_for_next_command(thd);
- statistic_increment(thd->status_var.com_stmt_fetch, &LOCK_status);
+ status_var_increment(thd->status_var.com_stmt_fetch);
if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_fetch")))
DBUG_VOID_RETURN;
@@ -2444,7 +2485,7 @@ void mysql_stmt_reset(THD *thd, char *packet)
/* First of all clear possible warnings from the previous command */
mysql_reset_thd_for_next_command(thd);
- statistic_increment(thd->status_var.com_stmt_reset, &LOCK_status);
+ status_var_increment(thd->status_var.com_stmt_reset);
if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_reset")))
DBUG_VOID_RETURN;
@@ -2507,7 +2548,8 @@ void mysql_sql_stmt_close(THD *thd)
{
Prepared_statement* stmt;
LEX_STRING *name= &thd->lex->prepared_stmt_name;
- DBUG_PRINT("info", ("DEALLOCATE PREPARE: %.*s\n", name->length, name->str));
+ DBUG_PRINT("info", ("DEALLOCATE PREPARE: %.*s\n", (int) name->length,
+ name->str));
if (! (stmt= (Prepared_statement*) thd->stmt_map.find_by_name(name)))
{
@@ -2548,7 +2590,7 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length)
#endif
DBUG_ENTER("mysql_stmt_get_longdata");
- statistic_increment(thd->status_var.com_stmt_send_long_data, &LOCK_status);
+ status_var_increment(thd->status_var.com_stmt_send_long_data);
#ifndef EMBEDDED_LIBRARY
/* Minimal size of long data packet is 6 bytes */
if (packet_length <= MYSQL_LONG_DATA_HEADER)
@@ -2596,14 +2638,14 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length)
/***************************************************************************
- Select_fetch_protocol_prep
+ Select_fetch_protocol_binary
****************************************************************************/
-Select_fetch_protocol_prep::Select_fetch_protocol_prep(THD *thd_arg)
+Select_fetch_protocol_binary::Select_fetch_protocol_binary(THD *thd_arg)
:protocol(thd_arg)
{}
-bool Select_fetch_protocol_prep::send_fields(List<Item> &list, uint flags)
+bool Select_fetch_protocol_binary::send_fields(List<Item> &list, uint flags)
{
bool rc;
Protocol *save_protocol= thd->protocol;
@@ -2621,7 +2663,7 @@ bool Select_fetch_protocol_prep::send_fields(List<Item> &list, uint flags)
return rc;
}
-bool Select_fetch_protocol_prep::send_eof()
+bool Select_fetch_protocol_binary::send_eof()
{
Protocol *save_protocol= thd->protocol;
@@ -2633,7 +2675,7 @@ bool Select_fetch_protocol_prep::send_eof()
bool
-Select_fetch_protocol_prep::send_data(List<Item> &fields)
+Select_fetch_protocol_binary::send_data(List<Item> &fields)
{
Protocol *save_protocol= thd->protocol;
bool rc;
@@ -2667,15 +2709,26 @@ Prepared_statement::Prepared_statement(THD *thd_arg, Protocol *protocol_arg)
void Prepared_statement::setup_set_params()
{
- /* Setup binary logging */
+ /*
+ Note: BUG#25843 applies here too (query cache lookup uses thd->db, not
+ db from "prepare" time).
+ */
+ if (query_cache_maybe_disabled(thd)) // we won't expand the query
+ lex->safe_to_cache_query= FALSE; // so don't cache it at Execution
+
+ /*
+ Decide if we have to expand the query (because we must write it to logs or
+ because we want to look it up in the query cache) or not.
+ */
if (mysql_bin_log.is_open() && is_update_query(lex->sql_command) ||
- mysql_log.is_open() || mysql_slow_log.is_open())
+ opt_log || opt_slow_log ||
+ query_cache_is_cacheable_query(lex))
{
set_params_from_vars= insert_params_from_vars_with_log;
#ifndef EMBEDDED_LIBRARY
- set_params= insert_params_withlog;
+ set_params= insert_params_with_log;
#else
- set_params_data= emb_insert_params_withlog;
+ set_params_data= emb_insert_params_with_log;
#endif
}
else
@@ -2701,7 +2754,8 @@ void Prepared_statement::setup_set_params()
Prepared_statement::~Prepared_statement()
{
DBUG_ENTER("Prepared_statement::~Prepared_statement");
- DBUG_PRINT("enter",("stmt: %p cursor: %p", this, cursor));
+ DBUG_PRINT("enter",("stmt: 0x%lx cursor: 0x%lx",
+ (long) this, (long) cursor));
delete cursor;
/*
We have to call free on the items even if cleanup is called as some items,
@@ -2723,7 +2777,7 @@ Query_arena::Type Prepared_statement::type() const
void Prepared_statement::cleanup_stmt()
{
DBUG_ENTER("Prepared_statement::cleanup_stmt");
- DBUG_PRINT("enter",("stmt: %p", this));
+ DBUG_PRINT("enter",("stmt: 0x%lx", (long) this));
DBUG_ASSERT(lex->sphead == 0);
/* The order is important */
@@ -2740,7 +2794,7 @@ void Prepared_statement::cleanup_stmt()
bool Prepared_statement::set_name(LEX_STRING *name_arg)
{
name.length= name_arg->length;
- name.str= memdup_root(mem_root, (char*) name_arg->str, name_arg->length);
+ name.str= (char*) memdup_root(mem_root, name_arg->str, name_arg->length);
return name.str == 0;
}
@@ -2787,7 +2841,7 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
However, it seems handy if com_stmt_prepare is increased always,
no matter what kind of prepare is processed.
*/
- statistic_increment(thd->status_var.com_stmt_prepare, &LOCK_status);
+ status_var_increment(thd->status_var.com_stmt_prepare);
/*
alloc_query() uses thd->memroot && thd->query, so we should call
@@ -2808,14 +2862,12 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
Lex_input_stream lip(thd, thd->query, thd->query_length);
lip.stmt_prepare_mode= TRUE;
- thd->m_lip= &lip;
lex_start(thd);
- lex->safe_to_cache_query= FALSE;
- int err= MYSQLparse((void *)thd);
- lex->set_trg_event_type_for_tables();
- error= err || thd->is_fatal_error ||
- thd->net.report_error || init_param_array(this);
+ error= parse_sql(thd, &lip, NULL) ||
+ thd->net.report_error ||
+ init_param_array(this);
+ lex->set_trg_event_type_for_tables();
/*
While doing context analysis of the query (in check_prepared_statement)
@@ -2884,8 +2936,8 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
if (thd->spcont == NULL)
{
const char *format= "[%lu] %.*b";
- mysql_log.write(thd, COM_STMT_PREPARE, format, id,
- query_length, query);
+ general_log_print(thd, COM_STMT_PREPARE, format, id,
+ query_length, query);
}
}
@@ -2923,7 +2975,7 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
Query_arena *old_stmt_arena;
bool error= TRUE;
- statistic_increment(thd->status_var.com_stmt_execute, &LOCK_status);
+ status_var_increment(thd->status_var.com_stmt_execute);
/* Check if we got an error when sending long data */
if (state == Query_arena::ERROR)
@@ -2987,12 +3039,6 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
stmt_backup.query_length= thd->query_length;
/*
- Save orig_sql_command as we use it to disable slow logging for SHOW
- commands (see log_slow_statement()).
- */
- stmt_backup.lex->orig_sql_command= thd->lex->orig_sql_command;
-
- /*
At first execution of prepared statement we may perform logical
transformations of the query tree. Such changes should be performed
on the parse tree of current prepared statement and new items should
@@ -3004,11 +3050,26 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
reinit_stmt_before_use(thd, lex);
thd->protocol= protocol; /* activate stmt protocol */
- error= (open_cursor ?
- mysql_open_cursor(thd, (uint) ALWAYS_MATERIALIZED_CURSOR,
- &result, &cursor) :
- mysql_execute_command(thd));
- thd->protocol= &thd->protocol_simple; /* use normal protocol */
+
+ if (open_cursor)
+ error= mysql_open_cursor(thd, (uint) ALWAYS_MATERIALIZED_CURSOR,
+ &result, &cursor);
+ else
+ {
+ /*
+ Try to find it in the query cache, if not, execute it.
+ Note that multi-statements cannot exist here (they are not supported in
+ prepared statements).
+ */
+ if (query_cache_send_result_to_client(thd, thd->query,
+ thd->query_length) <= 0)
+ {
+ error= mysql_execute_command(thd);
+ query_cache_end_of_result(thd);
+ }
+ }
+
+ thd->protocol= &thd->protocol_text; /* use normal protocol */
/* Assert that if an error, no cursor is open */
DBUG_ASSERT(! (error && cursor));
@@ -3043,8 +3104,8 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
if (error == 0 && thd->spcont == NULL)
{
const char *format= "[%lu] %.*b";
- mysql_log.write(thd, COM_STMT_EXECUTE, format, id,
- thd->query_length, thd->query);
+ general_log_print(thd, COM_STMT_EXECUTE, format, id,
+ thd->query_length, thd->query);
}
error:
@@ -3058,7 +3119,7 @@ error:
bool Prepared_statement::deallocate()
{
/* We account deallocate in the same manner as mysql_stmt_close */
- statistic_increment(thd->status_var.com_stmt_close, &LOCK_status);
+ status_var_increment(thd->status_var.com_stmt_close);
if (flags & (uint) IS_IN_USE)
{
my_error(ER_PS_NO_RECURSION, MYF(0));