summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/item.cc15
-rw-r--r--sql/item.h123
-rw-r--r--sql/sp_head.cc102
-rw-r--r--sql/sql_prepare.cc72
4 files changed, 156 insertions, 156 deletions
diff --git a/sql/item.cc b/sql/item.cc
index ef426a87a62..0fefa54d849 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -1579,9 +1579,8 @@ Item_splocal::Item_splocal(const LEX_STRING &sp_var_name,
enum_field_types sp_var_type,
uint pos_in_q, uint len_in_q)
:Item_sp_variable(sp_var_name.str, sp_var_name.length),
- m_var_idx(sp_var_idx),
- limit_clause_param(FALSE),
- pos_in_query(pos_in_q), len_in_query(len_in_q)
+ Rewritable_query_parameter(pos_in_q, len_in_q),
+ m_var_idx(sp_var_idx)
{
maybe_null= TRUE;
@@ -3230,14 +3229,13 @@ default_set_param_func(Item_param *param,
Item_param::Item_param(uint pos_in_query_arg) :
+ Rewritable_query_parameter(pos_in_query_arg, 1),
state(NO_VALUE), inout(IN_PARAM),
item_result_type(STRING_RESULT),
/* Don't pretend to be a literal unless value for this item is set. */
item_type(PARAM_ITEM),
param_type(MYSQL_TYPE_VARCHAR),
- pos_in_query(pos_in_query_arg),
set_param_func(default_set_param_func),
- limit_clause_param(FALSE),
m_out_param_info(NULL)
{
name= (char*) "?";
@@ -4102,6 +4100,13 @@ void Item_param::make_field(Send_field *field)
field->type= m_out_param_info->type;
}
+bool Item_param::append_for_log(THD *thd, String *str)
+{
+ StringBuffer<STRING_BUFFER_USUAL_SIZE> buf;
+ const String *val= query_val_str(thd, &buf);
+ return str->append(*val);
+}
+
/****************************************************************************
Item_copy
****************************************************************************/
diff --git a/sql/item.h b/sql/item.h
index 1cef9b75fdd..59c30737a10 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -528,6 +528,70 @@ public:
{ return NULL; }
};
+/**
+ This is used for items in the query that needs to be rewritten
+ before binlogging
+
+ At the moment this applies to Item_param and Item_splocal
+*/
+class Rewritable_query_parameter
+{
+ public:
+ /*
+ Offset inside the query text.
+ Value of 0 means that this object doesn't have to be replaced
+ (for example SP variables in control statements)
+ */
+ uint pos_in_query;
+
+ /*
+ Byte length of parameter name in the statement. This is not
+ Item::name_length because name_length contains byte length of UTF8-encoded
+ name, but the query string is in the client charset.
+ */
+ uint len_in_query;
+
+ bool limit_clause_param;
+
+ Rewritable_query_parameter(uint pos_in_q= 0, uint len_in_q= 0)
+ : pos_in_query(pos_in_q), len_in_query(len_in_q),
+ limit_clause_param(false)
+ { }
+
+ virtual ~Rewritable_query_parameter() { }
+
+ virtual bool append_for_log(THD *thd, String *str) = 0;
+};
+
+class Copy_query_with_rewrite
+{
+ THD *thd;
+ const char *src;
+ size_t src_len, from;
+ String *dst;
+
+ bool copy_up_to(size_t bytes)
+ {
+ DBUG_ASSERT(bytes >= from);
+ return dst->append(src + from, bytes - from);
+ }
+
+public:
+
+ Copy_query_with_rewrite(THD *t, const char *s, size_t l, String *d)
+ :thd(t), src(s), src_len(l), from(0), dst(d) { }
+
+ bool append(Rewritable_query_parameter *p)
+ {
+ if (copy_up_to(p->pos_in_query) || p->append_for_log(thd, dst))
+ return true;
+ from= p->pos_in_query + p->len_in_query;
+ return false;
+ }
+
+ bool finalize()
+ { return copy_up_to(src_len); }
+};
struct st_dyncall_create_def
{
@@ -1433,6 +1497,8 @@ public:
}
virtual Item_splocal *get_item_splocal() { return 0; }
+ virtual Rewritable_query_parameter *get_rewritable_query_parameter()
+ { return 0; }
/*
Return Settable_routine_parameter interface of the Item. Return 0
@@ -1691,7 +1757,8 @@ inline bool Item_sp_variable::send(Protocol *protocol, String *str)
*****************************************************************************/
class Item_splocal :public Item_sp_variable,
- private Settable_routine_parameter
+ private Settable_routine_parameter,
+ public Rewritable_query_parameter
{
uint m_var_idx;
@@ -1699,33 +1766,6 @@ class Item_splocal :public Item_sp_variable,
Item_result m_result_type;
enum_field_types m_field_type;
public:
- /*
- If this variable is a parameter in LIMIT clause.
- Used only during NAME_CONST substitution, to not append
- NAME_CONST to the resulting query and thus not break
- the slave.
- */
- bool limit_clause_param;
- /*
- Position of this reference to SP variable in the statement (the
- statement itself is in sp_instr_stmt::m_query).
- This is valid only for references to SP variables in statements,
- excluding DECLARE CURSOR statement. It is used to replace references to SP
- variables with NAME_CONST calls when putting statements into the binary
- log.
- Value of 0 means that this object doesn't corresponding to reference to
- SP variable in query text.
- */
- uint pos_in_query;
- /*
- Byte length of SP variable name in the statement (see pos_in_query).
- The value of this field may differ from the name_length value because
- name_length contains byte length of UTF8-encoded item name, but
- the query string (see sp_instr_stmt::m_query) is currently stored with
- a charset from the SET NAMES statement.
- */
- uint len_in_query;
-
Item_splocal(const LEX_STRING &sp_var_name, uint sp_var_idx,
enum_field_types sp_var_type,
uint pos_in_q= 0, uint len_in_q= 0);
@@ -1751,10 +1791,13 @@ private:
public:
Item_splocal *get_item_splocal() { return this; }
+ Rewritable_query_parameter *get_rewritable_query_parameter()
+ { return this; }
+
Settable_routine_parameter *get_settable_routine_parameter()
- {
- return this;
- }
+ { return this; }
+
+ bool append_for_log(THD *thd, String *str);
};
/*****************************************************************************
@@ -2229,7 +2272,8 @@ public:
/* Item represents one placeholder ('?') of prepared statement */
class Item_param :public Item,
- private Settable_routine_parameter
+ private Settable_routine_parameter,
+ public Rewritable_query_parameter
{
char cnvbuf[MAX_FIELD_WIDTH];
String cnvstr;
@@ -2294,11 +2338,6 @@ public:
supply for this placeholder in mysql_stmt_execute.
*/
enum enum_field_types param_type;
- /*
- Offset of placeholder inside statement text. Used to create
- no-placeholders version of this statement for the binary log.
- */
- uint pos_in_query;
Item_param(uint pos_in_query_arg);
@@ -2364,14 +2403,14 @@ public:
Otherwise return FALSE.
*/
bool eq(const Item *item, bool binary_cmp) const;
- /** Item is a argument to a limit clause. */
- bool limit_clause_param;
void set_param_type_and_swap_value(Item_param *from);
+ Rewritable_query_parameter *get_rewritable_query_parameter()
+ { return this; }
Settable_routine_parameter *get_settable_routine_parameter()
- {
- return this;
- }
+ { return this; }
+
+ bool append_for_log(THD *thd, String *str);
private:
virtual bool set_value(THD *thd, sp_rcontext *ctx, Item **it);
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 3d1b7b662db..35abe4e51b5 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -149,13 +149,9 @@ sp_get_item_value(THD *thd, Item *item, String *str)
return NULL;
{
- char buf_holder[STRING_BUFFER_USUAL_SIZE];
- String buf(buf_holder, sizeof(buf_holder), result->charset());
+ StringBuffer<STRING_BUFFER_USUAL_SIZE> buf(result->charset());
CHARSET_INFO *cs= thd->variables.character_set_client;
- /* We must reset length of the buffer, because of String specificity. */
- buf.length(0);
-
buf.append('_');
buf.append(result->charset()->csname);
if (cs->escape_with_backslash_is_dangerous)
@@ -178,6 +174,28 @@ sp_get_item_value(THD *thd, Item *item, String *str)
}
+bool Item_splocal::append_for_log(THD *thd, String *str)
+{
+ if (fix_fields(thd, NULL))
+ return true;
+
+ if (limit_clause_param)
+ return str->append_ulonglong(val_uint());
+
+ if (str->append(STRING_WITH_LEN(" NAME_CONST('")) ||
+ str->append(&m_name) ||
+ str->append(STRING_WITH_LEN("',")))
+ return true;
+
+ StringBuffer<STRING_BUFFER_USUAL_SIZE> str_value_holder(&my_charset_latin1);
+ String *str_value= sp_get_item_value(thd, this_item(), &str_value_holder);
+ if (str_value)
+ return str->append(*str_value) || str->append(')');
+ else
+ return str->append(STRING_WITH_LEN("NULL)"));
+}
+
+
/**
Returns a combination of:
- sp_head::MULTI_RESULTS: added if the 'cmd' is a command that might
@@ -979,19 +997,16 @@ subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str)
DBUG_ENTER("subst_spvars");
Dynamic_array<Item_splocal*> sp_vars_uses;
- char *pbuf, *cur, buffer[512];
- String qbuf(buffer, sizeof(buffer), &my_charset_bin);
- int prev_pos, res, buf_len;
+ char *pbuf;
+ StringBuffer<512> qbuf;
+ Copy_query_with_rewrite acc(thd, query_str->str, query_str->length, &qbuf);
/* Find all instances of Item_splocal used in this statement */
for (Item *item= instr->free_list; item; item= item->next)
{
Item_splocal *item_spl= item->get_item_splocal();
- if (item_spl)
- {
- if (item_spl->pos_in_query)
- sp_vars_uses.append(item_spl);
- }
+ if (item_spl && item_spl->pos_in_query)
+ sp_vars_uses.append(item_spl);
}
if (!sp_vars_uses.elements())
DBUG_RETURN(FALSE);
@@ -999,64 +1014,15 @@ subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str)
/* Sort SP var refs by their occurences in the query */
sp_vars_uses.sort(cmp_splocal_locations);
- /*
- Construct a statement string where SP local var refs are replaced
- with "NAME_CONST(name, value)"
- */
- qbuf.length(0);
- cur= query_str->str;
- prev_pos= res= 0;
- thd->query_name_consts= 0;
+ thd->query_name_consts= sp_vars_uses.elements();
for (Item_splocal **splocal= sp_vars_uses.front();
splocal <= sp_vars_uses.back(); splocal++)
{
- Item *val;
-
- char str_buffer[STRING_BUFFER_USUAL_SIZE];
- String str_value_holder(str_buffer, sizeof(str_buffer),
- &my_charset_latin1);
- String *str_value;
-
- /* append the text between sp ref occurences */
- res|= qbuf.append(cur + prev_pos, (*splocal)->pos_in_query - prev_pos);
- prev_pos= (*splocal)->pos_in_query + (*splocal)->len_in_query;
-
- res|= (*splocal)->fix_fields(thd, (Item **) splocal);
- if (res)
- break;
-
- if ((*splocal)->limit_clause_param)
- {
- res|= qbuf.append_ulonglong((*splocal)->val_uint());
- if (res)
- break;
- continue;
- }
-
- /* append the spvar substitute */
- res|= qbuf.append(STRING_WITH_LEN(" NAME_CONST('"));
- res|= qbuf.append((*splocal)->m_name.str, (*splocal)->m_name.length);
- res|= qbuf.append(STRING_WITH_LEN("',"));
-
- if (res)
- break;
-
- val= (*splocal)->this_item();
- DBUG_PRINT("info", ("print 0x%lx", (long) val));
- str_value= sp_get_item_value(thd, val, &str_value_holder);
- if (str_value)
- res|= qbuf.append(*str_value);
- else
- res|= qbuf.append(STRING_WITH_LEN("NULL"));
- res|= qbuf.append(')');
- if (res)
- break;
-
- thd->query_name_consts++;
+ if (acc.append(*splocal))
+ DBUG_RETURN(TRUE);
}
- if (res ||
- qbuf.append(cur + prev_pos, query_str->length - prev_pos))
+ if (acc.finalize())
DBUG_RETURN(TRUE);
/*
@@ -1071,8 +1037,8 @@ subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str)
<db_name> Name of current database
<flags> Flags struct
*/
- buf_len= (qbuf.length() + 1 + QUERY_CACHE_DB_LENGTH_SIZE + thd->db_length +
- QUERY_CACHE_FLAGS_SIZE + 1);
+ int buf_len= (qbuf.length() + 1 + QUERY_CACHE_DB_LENGTH_SIZE +
+ thd->db_length + QUERY_CACHE_FLAGS_SIZE + 1);
if ((pbuf= (char *) alloc_root(thd->mem_root, buf_len)))
{
char *ptr= pbuf + qbuf.length();
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 7c51bbf6426..c602ec7441a 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -873,14 +873,9 @@ static bool insert_params_with_log(Prepared_statement *stmt, uchar *null_array,
THD *thd= stmt->thd;
Item_param **begin= stmt->param_array;
Item_param **end= begin + stmt->param_count;
- uint32 length= 0;
- String str;
- const String *res;
+ Copy_query_with_rewrite acc(thd, stmt->query(), stmt->query_length(), query);
DBUG_ENTER("insert_params_with_log");
- 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;
@@ -913,15 +908,16 @@ static bool insert_params_with_log(Prepared_statement *stmt, uchar *null_array,
*/
else if (! is_param_long_data_type(param))
DBUG_RETURN(1);
- res= param->query_val_str(thd, &str);
- if (param->convert_str_value(thd))
- DBUG_RETURN(1); /* out of memory */
- if (query->replace(param->pos_in_query+length, 1, *res))
+ if (acc.append(param))
DBUG_RETURN(1);
- length+= res->length()-1;
+ if (param->convert_str_value(thd))
+ DBUG_RETURN(1); /* out of memory */
}
+ if (acc.finalize())
+ DBUG_RETURN(1);
+
DBUG_RETURN(0);
}
@@ -1050,23 +1046,15 @@ static bool emb_insert_params(Prepared_statement *stmt, String *expanded_query)
}
-static bool emb_insert_params_with_log(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;
Item_param **end= it + stmt->param_count;
MYSQL_BIND *client_param= thd->client_params;
-
- String str;
- const String *res;
- uint32 length= 0;
-
+ Copy_query_with_rewrite acc(thd, stmt->query(), stmt->query_length(), query);
DBUG_ENTER("emb_insert_params_with_log");
- if (query->copy(stmt->query(), stmt->query_length(), default_charset_info))
- DBUG_RETURN(1);
-
for (; it < end; ++it, ++client_param)
{
Item_param *param= *it;
@@ -1087,15 +1075,15 @@ static bool emb_insert_params_with_log(Prepared_statement *stmt,
DBUG_RETURN(1);
}
}
- res= param->query_val_str(thd, &str);
- if (param->convert_str_value(thd))
- DBUG_RETURN(1); /* out of memory */
-
- if (query->replace(param->pos_in_query+length, 1, *res))
+ if (acc.append(param))
DBUG_RETURN(1);
- length+= res->length()-1;
+ if (param->convert_str_value(thd))
+ DBUG_RETURN(1); /* out of memory */
}
+ if (acc.finalize())
+ DBUG_RETURN(1);
+
DBUG_RETURN(0);
}
@@ -1232,16 +1220,11 @@ static bool insert_params_from_vars_with_log(Prepared_statement *stmt,
user_var_entry *entry;
LEX_STRING *varname;
List_iterator<LEX_STRING> var_it(varnames);
- String buf;
- const String *val;
- uint32 length= 0;
THD *thd= stmt->thd;
+ Copy_query_with_rewrite acc(thd, stmt->query(), stmt->query_length(), query);
DBUG_ENTER("insert_params_from_vars_with_log");
- 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;
@@ -1257,15 +1240,16 @@ static bool insert_params_from_vars_with_log(Prepared_statement *stmt,
setup_one_conversion_function(thd, param, param->param_type);
if (param->set_from_user_var(thd, entry))
DBUG_RETURN(1);
- val= param->query_val_str(thd, &buf);
- if (param->convert_str_value(thd))
- DBUG_RETURN(1); /* out of memory */
+ if (acc.append(param))
+ DBUG_RETURN(1);
- if (query->replace(param->pos_in_query+length, 1, *val))
+ if (param->convert_str_value(thd))
DBUG_RETURN(1);
- length+= val->length()-1;
}
+ if (acc.finalize())
+ DBUG_RETURN(1);
+
DBUG_RETURN(0);
}
@@ -3244,9 +3228,15 @@ void Prepared_statement::setup_set_params()
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)) ||
- opt_log || thd->variables.sql_log_slow ||
- query_cache_is_cacheable_query(lex))
+ bool replace_params_with_values= false;
+ // binlog
+ replace_params_with_values|= mysql_bin_log.is_open() && is_update_query(lex->sql_command);
+ // general or slow log
+ replace_params_with_values|= opt_log || thd->variables.sql_log_slow;
+ // query cache
+ replace_params_with_values|= query_cache_is_cacheable_query(lex);
+
+ if (replace_params_with_values)
{
set_params_from_vars= insert_params_from_vars_with_log;
#ifndef EMBEDDED_LIBRARY