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()
 {