summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <sergefp@mysql.com>2004-06-01 17:27:40 +0400
committerunknown <sergefp@mysql.com>2004-06-01 17:27:40 +0400
commit9626b4d073ed62746e23e2b04afbeb184bc57f40 (patch)
tree9bf807ca71cac6f589e237f3959254a8a35768e7
parent4cca7db74676837f260938df000d06a82f6d9314 (diff)
downloadmariadb-git-9626b4d073ed62746e23e2b04afbeb184bc57f40.tar.gz
* New, binlog-aware character sets support in SQL Syntax for Prepared statements.
* The prepared statement query is put into binary log on execution only if it is an update query. sql/item_func.cc: New, binlog-aware character sets support in SQL Syntax for Prepared statements. sql/mysql_priv.h: New, binlog-aware character sets support in SQL Syntax for Prepared statements.
-rw-r--r--sql/item_func.cc78
-rw-r--r--sql/mysql_priv.h3
-rw-r--r--sql/sql_prepare.cc158
3 files changed, 190 insertions, 49 deletions
diff --git a/sql/item_func.cc b/sql/item_func.cc
index f221e0dcc5c..2fc1f68b49c 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -2583,27 +2583,39 @@ longlong Item_func_get_user_var::val_int()
/*
+ Get variable by name and, if necessary, put the record of variable
+ use into the binary log.
+
+ SYNOPSIS
+ get_var_with_binlog()
+ thd Current thread
+ name Variable name
+ out_entry [out] variable structure or NULL. The pointer is set
+ regardless of whether function succeeded or not.
+
When a user variable is invoked from an update query (INSERT, UPDATE etc),
stores this variable and its value in thd->user_var_events, so that it can be
written to the binlog (will be written just before the query is written, see
log.cc).
+
+ RETURN
+ 0 OK
+ 1 Failed to put appropiate record into binary log
+
*/
-void Item_func_get_user_var::fix_length_and_dec()
+int get_var_with_binlog(THD *thd, LEX_STRING &name,
+ user_var_entry **out_entry)
{
- THD *thd=current_thd;
BINLOG_USER_VAR_EVENT *user_var_event;
- maybe_null=1;
- decimals=NOT_FIXED_DEC;
- max_length=MAX_BLOB_WIDTH;
-
- if (!(var_entry= get_variable(&thd->user_vars, name, 0)))
- null_value= 1;
- else
- collation.set(var_entry->collation);
+ user_var_entry *var_entry;
+ var_entry= get_variable(&thd->user_vars, name, 0);
if (!(opt_bin_log && is_update_query(thd->lex->sql_command)))
- return;
+ {
+ *out_entry= var_entry;
+ return 0;
+ }
if (!var_entry)
{
@@ -2630,13 +2642,16 @@ void Item_func_get_user_var::fix_length_and_dec()
if (!(var_entry= get_variable(&thd->user_vars, name, 0)))
goto err;
}
- /*
- If this variable was already stored in user_var_events by this query
- (because it's used in more than one place in the query), don't store
- it.
- */
else if (var_entry->used_query_id == thd->query_id)
- return;
+ {
+ /*
+ If this variable was already stored in user_var_events by this query
+ (because it's used in more than one place in the query), don't store
+ it.
+ */
+ *out_entry= var_entry;
+ return 0;
+ }
uint size;
/*
@@ -2671,11 +2686,34 @@ void Item_func_get_user_var::fix_length_and_dec()
var_entry->used_query_id= thd->query_id;
if (insert_dynamic(&thd->user_var_events, (gptr) &user_var_event))
goto err;
-
- return;
+
+ *out_entry= var_entry;
+ return 0;
err:
- thd->fatal_error();
+ *out_entry= var_entry;
+ return 1;
+}
+
+
+void Item_func_get_user_var::fix_length_and_dec()
+{
+ THD *thd=current_thd;
+ int error;
+ maybe_null=1;
+ decimals=NOT_FIXED_DEC;
+ max_length=MAX_BLOB_WIDTH;
+
+ error= get_var_with_binlog(thd, name, &var_entry);
+
+ if (!var_entry)
+ null_value= 1;
+ else
+ collation.set(var_entry->collation);
+
+ if (error)
+ thd->fatal_error();
+
return;
}
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index fe3efd720f0..2a88f6843fc 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -1069,6 +1069,9 @@ Item *get_system_var(THD *thd, enum_var_type var_type, LEX_STRING name,
LEX_STRING component);
Item *get_system_var(THD *thd, enum_var_type var_type, const char *var_name,
uint length, const char *item_name);
+/* item_func.cc */
+int get_var_with_binlog(THD *thd, LEX_STRING &name,
+ user_var_entry **out_entry);
/* log.cc */
bool flush_error_log(void);
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 1224d1da194..70b6a9de006 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -101,11 +101,12 @@ public:
public:
Prepared_statement(THD *thd_arg);
virtual ~Prepared_statement();
+ void setup_set_params();
virtual Statement::Type type() const;
};
static void execute_stmt(THD *thd, Prepared_statement *stmt,
- String *expanded_query);
+ String *expanded_query, bool set_context=false);
/******************************************************************************
Implementation
@@ -769,12 +770,14 @@ static bool emb_insert_params_withlog(Prepared_statement *stmt, String *query)
*client_param->length :
client_param->buffer_length);
}
- res= param->query_val_str(&str);
- if (param->convert_str_value(thd))
- DBUG_RETURN(1); /* out of memory */
}
+ res= param->query_val_str(&str);
+ if (param->convert_str_value(thd))
+ DBUG_RETURN(1); /* out of memory */
+
if (query->replace(param->pos_in_query+length, 1, *res))
DBUG_RETURN(1);
+
length+= res->length()-1;
}
DBUG_RETURN(0);
@@ -820,18 +823,45 @@ static bool insert_params_from_vars(Prepared_statement *stmt,
param->set_double(*(double*)entry->value);
break;
case INT_RESULT:
- param->set_int(*(longlong*)entry->value);
+ param->set_int(*(longlong*)entry->value, 21);
break;
case STRING_RESULT:
- param->set_value(entry->value, entry->length,
- entry->collation.collation);
+ {
+ CHARSET_INFO *fromcs= entry->collation.collation;
+ CHARSET_INFO *tocs= stmt->thd->variables.collation_connection;
+ uint32 dummy_offset;
+
+ param->value.cs_info.character_set_client= fromcs;
+
+ /*
+ Setup source and destination character sets so that they
+ are different only if conversion is necessary: this will
+ make later checks easier.
+ */
+ param->value.cs_info.final_character_set_of_str_value=
+ String::needs_conversion(0, fromcs, tocs, &dummy_offset) ?
+ tocs : fromcs;
+ /*
+ Exact value of max_length is not known unless data is converted to
+ charset of connection, so we have to set it later.
+ */
+ param->item_type= Item::STRING_ITEM;
+ param->item_result_type= STRING_RESULT;
+
+ if (param->set_str((const char *)entry->value, entry->length))
+ DBUG_RETURN(1);
+ }
break;
default:
DBUG_ASSERT(0);
+ param->set_null();
}
}
else
- param->maybe_null= param->null_value= param->value_is_set= 1;
+ param->set_null();
+
+ if (param->convert_str_value(stmt->thd))
+ DBUG_RETURN(1); /* out of memory */
}
DBUG_RETURN(0);
}
@@ -869,10 +899,10 @@ static bool insert_params_from_vars_with_log(Prepared_statement *stmt,
{
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)
+ if (get_var_with_binlog(stmt->thd, *varname, &entry))
+ DBUG_RETURN(1);
+ DBUG_ASSERT(entry);
+ if (entry->value)
{
param->item_result_type= entry->type;
switch (entry->type)
@@ -881,26 +911,65 @@ static bool insert_params_from_vars_with_log(Prepared_statement *stmt,
param->set_double(*(double*)entry->value);
break;
case INT_RESULT:
- param->set_int(*(longlong*)entry->value);
+ param->set_int(*(longlong*)entry->value, 21);
break;
case STRING_RESULT:
- param->set_value(entry->value, entry->length,
- entry->collation.collation);
+ {
+ CHARSET_INFO *fromcs= entry->collation.collation;
+ CHARSET_INFO *tocs= stmt->thd->variables.collation_connection;
+ uint32 dummy_offset;
+
+ param->value.cs_info.character_set_client= fromcs;
+
+ /*
+ Setup source and destination character sets so that they
+ are different only if conversion is necessary: this will
+ make later checks easier.
+ */
+ param->value.cs_info.final_character_set_of_str_value=
+ String::needs_conversion(0, fromcs, tocs, &dummy_offset) ?
+ tocs : fromcs;
+ /*
+ Exact value of max_length is not known unless data is converted to
+ charset of connection, so we have to set it later.
+ */
+ param->item_type= Item::STRING_ITEM;
+ param->item_result_type= STRING_RESULT;
+
+ if (param->set_str((const char *)entry->value, entry->length))
+ DBUG_RETURN(1);
+ }
break;
default:
DBUG_ASSERT(0);
+ param->set_null();
}
- res= param->query_val_str(&str);
}
else
- {
- param->maybe_null= param->null_value= param->value_is_set= 1;
- res= &my_null_string;
- }
+ param->set_null();
- if (query->replace(param->pos_in_query+length, 1, *res))
+ /* Insert @'escaped-varname' instead of parameter in the query */
+ char *buf, *ptr;
+ str.length(0);
+ if (str.reserve(entry->name.length*2+3))
DBUG_RETURN(1);
- length+= res->length()-1;
+
+ buf= str.c_ptr_quick();
+ ptr= buf;
+ *ptr++= '@';
+ *ptr++= '\'';
+ ptr+=
+ escape_string_for_mysql(&my_charset_utf8_general_ci,
+ ptr, entry->name.str, entry->name.length);
+ *ptr++= '\'';
+ str.length(ptr - buf);
+
+ if (param->convert_str_value(stmt->thd))
+ DBUG_RETURN(1); /* out of memory */
+
+ if (query->replace(param->pos_in_query+length, 1, str))
+ DBUG_RETURN(1);
+ length+= str.length()-1;
}
DBUG_RETURN(0);
}
@@ -1680,6 +1749,7 @@ int mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
}
else
{
+ stmt->setup_set_params();
SELECT_LEX *sl= stmt->lex->all_selects_list;
/*
Save WHERE clause pointers, because they may be changed during query
@@ -1689,7 +1759,9 @@ int mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
{
sl->prep_where= sl->where;
}
+
}
+
DBUG_RETURN(!stmt);
}
@@ -1809,7 +1881,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
we set params, and also we don't need to parse packet.
So we do it in one function.
*/
- if (stmt->param_count && stmt->set_params_data(stmt))
+ if (stmt->param_count && stmt->set_params_data(stmt, &expanded_query))
goto set_params_data_err;
#endif
thd->protocol= &thd->protocol_prep; // Switch to binary protocol
@@ -1853,7 +1925,10 @@ void mysql_sql_stmt_execute(THD *thd, LEX_STRING *stmt_name)
/* 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,
+ thd->free_list= NULL;
+ thd->stmt_backup.set_statement(thd);
+ thd->set_statement(stmt);
+ if (stmt->set_params_from_vars(stmt, thd->stmt_backup.lex->prepared_stmt_params,
&expanded_query))
{
my_error(ER_WRONG_ARGUMENTS, MYF(0), "mysql_execute");
@@ -1879,12 +1954,15 @@ void mysql_sql_stmt_execute(THD *thd, LEX_STRING *stmt_name)
*/
static void execute_stmt(THD *thd, Prepared_statement *stmt,
- String *expanded_query)
+ String *expanded_query, bool set_context)
{
DBUG_ENTER("execute_stmt");
- thd->free_list= NULL;
- thd->stmt_backup.set_statement(thd);
- thd->set_statement(stmt);
+ if (set_context)
+ {
+ thd->free_list= NULL;
+ thd->stmt_backup.set_statement(thd);
+ thd->set_statement(stmt);
+ }
reset_stmt_for_execute(stmt);
if (expanded_query->length() &&
@@ -2060,7 +2138,7 @@ Prepared_statement::Prepared_statement(THD *thd_arg)
get_longdata_error(0)
{
*last_error= '\0';
- if (mysql_bin_log.is_open())
+ if (mysql_bin_log.is_open()) //psergey-todo: remove this!
{
set_params_from_vars= insert_params_from_vars_with_log;
#ifndef EMBEDDED_LIBRARY
@@ -2080,6 +2158,28 @@ Prepared_statement::Prepared_statement(THD *thd_arg)
}
}
+void Prepared_statement::setup_set_params()
+{
+ /* Setup binary logging */
+ if (mysql_bin_log.is_open() && is_update_query(lex->sql_command))
+ {
+ set_params_from_vars= insert_params_from_vars_with_log;
+#ifndef EMBEDDED_LIBRARY
+ set_params= insert_params_withlog;
+#else
+ set_params_data= emb_insert_params_withlog;
+#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()
{