diff --git a/include/my_sys.h b/include/my_sys.h
index 3e34e1a9ac38d51d0930aad26d489e9bcf0659ad..41bd4ba5b2d711892eda8e6802dc26016bfc0577 100644
--- a/include/my_sys.h
+++ b/include/my_sys.h
@@ -714,6 +714,7 @@ extern void my_free_lock(byte *ptr,myf flags);
 #define my_free_lock(A,B) my_free((A),(B))
 #endif
 #define alloc_root_inited(A) ((A)->min_malloc != 0)
+#define clear_alloc_root(A) bzero((void *) (A), sizeof(MEM_ROOT))
 extern void init_alloc_root(MEM_ROOT *mem_root, uint block_size,
 			    uint pre_alloc_size);
 extern gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size);
diff --git a/sql/item.h b/sql/item.h
index fb93e0ef8abac077da5fcfd3d1bd83106c2117dc..59c030f3db57a1eaa2afbae87b175a2462bb1f4b 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -375,9 +375,9 @@ public:
   bool get_time(TIME *tm);
   void reset() {}
 #ifndef EMBEDDED_LIBRARY
-  void (*setup_param_func)(Item_param *param, uchar **pos);
+  void (*set_param_func)(Item_param *param, uchar **pos);
 #else
-  void (*setup_param_func)(Item_param *param, uchar **pos, ulong data_len);
+  void (*set_param_func)(Item_param *param, uchar **pos, ulong data_len);
 #endif
   enum Item_result result_type () const
   { return item_result_type; }
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 535c1cb16be75cee1afca9bddaaeb91b9567fc2d..2d22d9c5891c2a5f6f471ff3f9aba6c5368a872b 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -620,14 +620,13 @@ int mysqld_show_column_types(THD *thd);
 int mysqld_help (THD *thd, const char *text);
 
 /* sql_prepare.cc */
-bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length);
+void mysql_stmt_prepare(THD *thd, char *packet, uint packet_length);
 void mysql_stmt_execute(THD *thd, char *packet);
 void mysql_stmt_free(THD *thd, char *packet);
 void mysql_stmt_reset(THD *thd, char *packet);
 void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length);
 int check_insert_fields(THD *thd,TABLE *table,List<Item> &fields,
 			List<Item> &values, ulong counter);
-void setup_param_functions(Item_param *param, uchar param_type);
 
 /* sql_error.cc */
 MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, uint code,
diff --git a/sql/protocol.h b/sql/protocol.h
index 67ae4ed01b41b699d0cb1f0b12102f1024f8f4ff..17c8f0d321d54f0f035d5051a72da79dfb4f7368 100644
--- a/sql/protocol.h
+++ b/sql/protocol.h
@@ -178,8 +178,3 @@ char *net_store_data(char *to,const char *from, uint length);
 char *net_store_data(char *to,int32 from);
 char *net_store_data(char *to,longlong from);
 
-#ifdef EMBEDDED_LIBRARY
-bool setup_params_data(struct st_prep_stmt *stmt);
-bool setup_params_data_withlog(struct st_prep_stmt *stmt);
-#endif
-
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 6fe0521b07ad6d61a6c956d83c80237782d22dd8..95374b691c8a37d02c1cad5e8657ca59a2599b4f 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -145,8 +145,7 @@ THD::THD():user_time(0), current_statement(0), is_fatal_error(0),
 
   init();
   /* Initialize sub structures */
-  bzero((char*) &transaction.mem_root,sizeof(transaction.mem_root));
-  bzero((char*) &warn_root,sizeof(warn_root));
+  clear_alloc_root(&transaction.mem_root);
   init_alloc_root(&warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE);
   user_connect=(USER_CONN *)0;
   hash_init(&user_vars, &my_charset_bin, USER_VARS_HASH_SIZE, 0, 0,
@@ -331,7 +330,7 @@ THD::~THD()
   dbug_sentry = THD_SENTRY_GONE;
 #endif  
   /* Reset stmt_backup.mem_root to not double-free memory from thd.mem_root */
-  init_alloc_root(&stmt_backup.mem_root, 0, 0);
+  clear_alloc_root(&stmt_backup.mem_root);
   DBUG_VOID_RETURN;
 }
 
@@ -1185,10 +1184,8 @@ int select_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
 
 Statement::Statement(THD *thd)
   :id(++thd->statement_id_counter),
-  query_id(thd->query_id),
   set_query_id(1),
   allow_sum_func(0),
-  command(thd->command),
   lex(&main_lex),
   query(0),
   query_length(0),
@@ -1207,10 +1204,8 @@ Statement::Statement(THD *thd)
 
 Statement::Statement()
   :id(0),
-  query_id(0),                                  /* initialized later */
   set_query_id(1),
   allow_sum_func(0),                            /* initialized later */
-  command(COM_SLEEP),                           /* initialized later */ 
   lex(&main_lex),
   query(0),                                     /* these two are set */ 
   query_length(0),                              /* in alloc_query() */
@@ -1229,15 +1224,11 @@ Statement::Type Statement::type() const
 void Statement::set_statement(Statement *stmt)
 {
   id=             stmt->id;
-  query_id=       stmt->query_id;
   set_query_id=   stmt->set_query_id;
   allow_sum_func= stmt->allow_sum_func;
-  command=        stmt->command;
   lex=            stmt->lex;
   query=          stmt->query;
   query_length=   stmt->query_length;
-  free_list=      stmt->free_list;
-  mem_root=       stmt->mem_root;
 }
 
 
diff --git a/sql/sql_class.h b/sql/sql_class.h
index d0ad8a4e68111d4b996969e7d036a9ef41ae6099..567135b1378f1b3bb0c132ae808984c7162056b2 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -434,15 +434,6 @@ public:
   */
    ulong id;
 
-  /*
-    Id of current query. Statement can be reused to execute several queries
-    query_id is global in context of the whole MySQL server.
-    ID is automatically generated from mutex-protected counter.
-    It's used in handler code for various purposes: to check which columns
-    from table are necessary for this select, to check if it's necessary to
-    update auto-updatable fields (like auto_increment and timestamp).
-  */
-  ulong query_id;
   /*
     - if set_query_id=1, we set field->query_id for all fields. In that case 
     field list can not contain duplicates.
@@ -461,11 +452,6 @@ public:
     See item_sum.cc for details.
   */
   bool allow_sum_func;
-  /*
-    Type of current query: COM_PREPARE, COM_QUERY, etc. Set from 
-    first byte of the packet in do_command()
-  */
-  enum enum_server_command command;
 
   LEX *lex;                                     // parse tree descriptor
   /*
@@ -676,6 +662,11 @@ public:
   uint dbug_sentry; // watch out for memory corruption
 #endif
   struct st_my_thread_var *mysys_var;
+  /*
+    Type of current query: COM_PREPARE, COM_QUERY, etc. Set from 
+    first byte of the packet in do_command()
+  */
+  enum enum_server_command command;
   uint32     server_id;
   uint32     file_id;			// for LOAD DATA INFILE
   /*
@@ -751,6 +742,15 @@ public:
   List	     <MYSQL_ERROR> warn_list;
   uint	     warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_END];
   uint	     total_warn_count;
+  /*
+    Id of current query. Statement can be reused to execute several queries
+    query_id is global in context of the whole MySQL server.
+    ID is automatically generated from mutex-protected counter.
+    It's used in handler code for various purposes: to check which columns
+    from table are necessary for this select, to check if it's necessary to
+    update auto-updatable fields (like auto_increment and timestamp).
+  */
+  ulong	     query_id;
   ulong	     warn_id, version, options, thread_id, col_access;
 
   /* Statement id is thread-wide. This counter is used to generate ids */
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 17cccd75697ff04c8f1efca01e34f62fa1e33e05..ba8fe0d879293df4a68c7fb33128bdcdf3f08dc2 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -552,7 +552,7 @@ typedef struct st_lex
   List<Item>	      *insert_list,field_list,value_list;
   List<List_item>     many_values;
   List<set_var_base>  var_list;
-  List<Item>          param_list;
+  List<Item_param>    param_list;
   SQL_LIST	      proc_list, auxilliary_table_list, save_list;
   TYPELIB	      *interval;
   create_field	      *last_field;
@@ -577,7 +577,6 @@ typedef struct st_lex
   uint uint_geom_type;
   uint grant, grant_tot_col, which_columns;
   uint fk_delete_opt, fk_update_opt, fk_match_option;
-  uint param_count;
   uint slave_thd_opt;
   uint8 describe;
   bool drop_if_exists, drop_temporary, local_file;
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index a09f3d28a0f25c2a25fc3f937cb04faed30ac7a0..99a8a248d244fe183392e0dbefb3f67d323b998b 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1232,10 +1232,34 @@ bool do_command(THD *thd)
 		       command_name[command]));
   }
   net->read_timeout=old_timeout;		// restore it
+  /*
+    packet_length contains length of data, as it was stored in packet
+    header. In case of malformed header, packet_length can be zero.
+    If packet_length is not zero, my_net_read ensures that this number
+    of bytes was actually read from network. Additionally my_net_read
+    sets packet[packet_length]= 0 (thus if packet_length == 0,
+    command == packet[0] == COM_SLEEP).
+    In dispatch_command packet[packet_length] points beyond the end of packet.
+  */
   DBUG_RETURN(dispatch_command(command,thd, packet+1, (uint) packet_length));
 }
 #endif  /* EMBEDDED_LIBRARY */
 
+/*
+   Perform one connection-level (COM_XXXX) command.
+  SYNOPSIS
+    dispatch_command()
+    thd             connection handle
+    command         type of command to perform 
+    packet          data for the command, packet is always null-terminated
+    packet_length   length of packet + 1 (to show that data is
+                    null-terminated) except for COM_SLEEP, where it
+                    can be zero.
+  RETURN VALUE
+    0   ok
+    1   request of thread shutdown, i. e. if command is
+        COM_QUIT/COM_SHUTDOWN
+*/
 
 bool dispatch_command(enum enum_server_command command, THD *thd,
 		      char* packet, uint packet_length)
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 7c2913bc495976d81b690746d4ccb3697fd46886..ac5b7847647c96fe6fc877a457fd50ea004709f5 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -39,7 +39,7 @@ Prepare-execute:
 
   - Server gets the command 'COM_EXECUTE' to execute the 
     previously prepared query. If there is any param markers; then client
-    will send the data in the following format:    
+    will send the data in the following format:
     [COM_EXECUTE:1]
     [STMT_ID:4]
     [NULL_BITS:(param_count+7)/8)]
@@ -86,16 +86,17 @@ class Prepared_statement: public Statement
 {
 public:
   THD *thd;
-  Item_param **param;                           /* array of all placeholders */
+  Item_param **param_array;
   uint param_count;
   uint last_errno;
   char last_error[MYSQL_ERRMSG_SIZE];
-  bool error_in_prepare, long_data_used;
+  bool get_longdata_error;
+  bool long_data_used;
   bool log_full_query;
 #ifndef EMBEDDED_LIBRARY
-  bool (*setup_params)(Prepared_statement *st, uchar *pos, uchar *read_pos);
+  bool (*set_params)(Prepared_statement *st, uchar *pos, uchar *read_pos);
 #else
-  bool (*setup_params_data)(Prepared_statement *st);
+  bool (*set_params_data)(Prepared_statement *st);
 #endif
 public:
   Prepared_statement(THD *thd_arg);
@@ -117,13 +118,14 @@ inline bool is_param_null(const uchar *pos, ulong param_no)
 enum { STMT_QUERY_LOG_LENGTH= 8192 };
 
 #ifdef EMBEDDED_LIBRARY
-#define SETUP_PARAM_FUNCTION(fn_name) \
+#define SET_PARAM_FUNCTION(fn_name) \
 static void fn_name(Item_param *param, uchar **pos, ulong data_len)
 #else
-#define SETUP_PARAM_FUNCTION(fn_name) \
+#define SET_PARAM_FUNCTION(fn_name) \
 static void fn_name(Item_param *param, uchar **pos)
 #endif
 
+enum enum_send_error { DONT_SEND_ERROR= 0, SEND_ERROR };
 
 /*
   Seek prepared statement in statement map by id: returns zero if statement
@@ -131,14 +133,16 @@ static void fn_name(Item_param *param, uchar **pos)
 */
 
 static Prepared_statement *
-find_prepared_statement(THD *thd, ulong id, const char *where)
+find_prepared_statement(THD *thd, ulong id, const char *where,
+                        enum enum_send_error se)
 {
   Statement *stmt= thd->stmt_map.find(id);
 
   if (stmt == 0 || stmt->type() != Statement::PREPARED_STATEMENT)
   {
     my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), id, where);
-    send_error(thd);
+    if (se == SEND_ERROR)
+      send_error(thd);
     return 0;
   }
   return (Prepared_statement *) stmt;
@@ -154,11 +158,11 @@ static bool send_prep_stmt(Prepared_statement *stmt, uint columns)
 {
   NET *net= &stmt->thd->net;
   char buff[9];
-  buff[0]= 0;
+  buff[0]= 0;                                   /* OK packet indicator */
   int4store(buff+1, stmt->id);
   int2store(buff+5, columns);
   int2store(buff+7, stmt->param_count);
-  /* This should be fixed to work with prepared statements */
+  /* TODO: send types of placeholders here */
   return (my_net_write(net, buff, sizeof(buff)) || net_flush(net));
 }
 #else
@@ -177,8 +181,8 @@ static bool send_prep_stmt(Prepared_statement *stmt,
 
 
 /*
-  Read the length of the parameter data and retun back to   
-  caller by positing the pointer to param data              
+  Read the length of the parameter data and return back to
+  caller by positing the pointer to param data.
 */
 
 #ifndef EMBEDDED_LIBRARY
@@ -208,49 +212,49 @@ static ulong get_param_length(uchar **packet)
 #endif /*!EMBEDDED_LIBRARY*/
 
  /*
-  Setup param conversion routines
-
-  setup_param_xx()
-  param   Parameter Item
-  pos     Input data buffer
+   Data conversion routines
+   SYNOPSIS
+   set_param_xx()
+    param   parameter item
+    pos     input data buffer
+    len     length of data in the buffer
 
-  All these functions reads the data from pos and sets up that data
-  through 'param' and advances the buffer position to predifined
-  length position.
+  All these functions read the data from pos, convert it to requested type 
+  and assign to param; pos is advanced to predefined length.
 
   Make a note that the NULL handling is examined at first execution
   (i.e. when input types altered) and for all subsequent executions
   we don't read any values for this.
 
-  RETURN VALUES
-    
+  RETURN VALUE
+    none
 */
 
-SETUP_PARAM_FUNCTION(setup_param_tiny)
+SET_PARAM_FUNCTION(set_param_tiny)
 {
   param->set_int((longlong)(**pos));
   *pos+= 1;
 }
 
-SETUP_PARAM_FUNCTION(setup_param_short)
+SET_PARAM_FUNCTION(set_param_short)
 {
   param->set_int((longlong)sint2korr(*pos));
   *pos+= 2;
 }
 
-SETUP_PARAM_FUNCTION(setup_param_int32)
+SET_PARAM_FUNCTION(set_param_int32)
 {
   param->set_int((longlong)sint4korr(*pos));
   *pos+= 4;
 }
 
-SETUP_PARAM_FUNCTION(setup_param_int64)
+SET_PARAM_FUNCTION(set_param_int64)
 {
   param->set_int((longlong)sint8korr(*pos));
   *pos+= 8;
 }
 
-SETUP_PARAM_FUNCTION(setup_param_float)
+SET_PARAM_FUNCTION(set_param_float)
 {
   float data;
   float4get(data,*pos);
@@ -258,7 +262,7 @@ SETUP_PARAM_FUNCTION(setup_param_float)
   *pos+= 4;
 }
 
-SETUP_PARAM_FUNCTION(setup_param_double)
+SET_PARAM_FUNCTION(set_param_double)
 {
   double data;
   float8get(data,*pos);
@@ -266,14 +270,14 @@ SETUP_PARAM_FUNCTION(setup_param_double)
   *pos+= 8;
 }
 
-SETUP_PARAM_FUNCTION(setup_param_time)
+SET_PARAM_FUNCTION(set_param_time)
 {
   ulong length;
 
   if ((length= get_param_length(pos)))
   {
     uchar *to= *pos;
-    TIME  tm;   
+    TIME  tm;
     
     tm.second_part= (length > 8 ) ? (ulong) sint4korr(to+7): 0;
 
@@ -290,11 +294,11 @@ SETUP_PARAM_FUNCTION(setup_param_time)
   *pos+= length;
 }
 
-SETUP_PARAM_FUNCTION(setup_param_datetime)
+SET_PARAM_FUNCTION(set_param_datetime)
 {
-  uint length= get_param_length(pos);
+  uint length;
  
-  if (length)
+  if ((length= get_param_length(pos)))
   {
     uchar *to= *pos;
     TIME  tm;
@@ -320,7 +324,7 @@ SETUP_PARAM_FUNCTION(setup_param_datetime)
   *pos+= length;
 }
 
-SETUP_PARAM_FUNCTION(setup_param_date)
+SET_PARAM_FUNCTION(set_param_date)
 {
   ulong length;
  
@@ -342,55 +346,55 @@ SETUP_PARAM_FUNCTION(setup_param_date)
   *pos+= length;
 }
 
-SETUP_PARAM_FUNCTION(setup_param_str)
+SET_PARAM_FUNCTION(set_param_str)
 {
   ulong len= get_param_length(pos);
   param->set_value((const char *)*pos, len);
-  *pos+= len;        
+  *pos+= len;
 }
 
-void setup_param_functions(Item_param *param, uchar param_type)
+static void setup_one_conversion_function(Item_param *param, uchar param_type)
 {
   switch (param_type) {
   case FIELD_TYPE_TINY:
-    param->setup_param_func= setup_param_tiny;
+    param->set_param_func= set_param_tiny;
     param->item_result_type= INT_RESULT;
     break;
   case FIELD_TYPE_SHORT:
-    param->setup_param_func= setup_param_short;
+    param->set_param_func= set_param_short;
     param->item_result_type= INT_RESULT;
     break;
   case FIELD_TYPE_LONG:
-    param->setup_param_func= setup_param_int32;
+    param->set_param_func= set_param_int32;
     param->item_result_type= INT_RESULT;
     break;
   case FIELD_TYPE_LONGLONG:
-    param->setup_param_func= setup_param_int64;
+    param->set_param_func= set_param_int64;
     param->item_result_type= INT_RESULT;
     break;
   case FIELD_TYPE_FLOAT:
-    param->setup_param_func= setup_param_float;
+    param->set_param_func= set_param_float;
     param->item_result_type= REAL_RESULT;
     break;
   case FIELD_TYPE_DOUBLE:
-    param->setup_param_func= setup_param_double;
+    param->set_param_func= set_param_double;
     param->item_result_type= REAL_RESULT;
     break;
   case FIELD_TYPE_TIME:
-    param->setup_param_func= setup_param_time;
+    param->set_param_func= set_param_time;
     param->item_result_type= STRING_RESULT;
     break;
   case FIELD_TYPE_DATE:
-    param->setup_param_func= setup_param_date;
+    param->set_param_func= set_param_date;
     param->item_result_type= STRING_RESULT;
     break;
   case MYSQL_TYPE_DATETIME:
   case MYSQL_TYPE_TIMESTAMP:
-    param->setup_param_func= setup_param_datetime;
+    param->set_param_func= set_param_datetime;
     param->item_result_type= STRING_RESULT;
     break;
   default:
-    param->setup_param_func= setup_param_str;
+    param->set_param_func= set_param_str;
     param->item_result_type= STRING_RESULT;
   }
 }
@@ -404,11 +408,11 @@ void setup_param_functions(Item_param *param, uchar param_type)
 static bool insert_params_withlog(Prepared_statement *stmt, uchar *pos,
                                   uchar *read_pos)
 {
-  THD *thd= stmt->thd;
-  List<Item> &params= stmt->lex->param_list;
-  List_iterator<Item> param_iterator(params);
-  Item_param *param;
-  
+  THD  *thd= stmt->thd;
+  Item_param **begin= stmt->param_array;
+  Item_param **end= begin + stmt->param_count;
+  uint32 length= 0;
+
   String str, query;
   const String *res;
 
@@ -417,16 +421,14 @@ static bool insert_params_withlog(Prepared_statement *stmt, uchar *pos,
   if (query.copy(stmt->query, stmt->query_length, default_charset_info))
     DBUG_RETURN(1);
   
-  ulong param_no= 0;  
-  uint32 length= 0;
-  
-  while ((param= (Item_param *)param_iterator++))
+  for (Item_param **it= begin; it < end; ++it)
   {
+    Item_param *param= *it;
     if (param->long_data_supplied)
-      res= param->query_val_str(&str);       
+      res= param->query_val_str(&str);
     else
     {
-      if (is_param_null(pos,param_no))
+      if (is_param_null(pos, it - begin))
       {
         param->maybe_null= param->null_value= 1;
         res= &my_null_string;
@@ -434,7 +436,7 @@ static bool insert_params_withlog(Prepared_statement *stmt, uchar *pos,
       else
       {
         param->maybe_null= param->null_value= 0;
-        param->setup_param_func(param,&read_pos);
+        param->set_param_func(param, &read_pos);
         res= param->query_val_str(&str);
       }
     }
@@ -442,7 +444,6 @@ static bool insert_params_withlog(Prepared_statement *stmt, uchar *pos,
       DBUG_RETURN(1);
     
     length+= res->length()-1;
-    param_no++;
   }
   if (alloc_query(thd, (char *)query.ptr(), query.length()+1))
     DBUG_RETURN(1);
@@ -454,73 +455,68 @@ static bool insert_params_withlog(Prepared_statement *stmt, uchar *pos,
 static bool insert_params(Prepared_statement *stmt, uchar *pos,
                           uchar *read_pos)
 {
-  List<Item> &params= stmt->lex->param_list;
-  List_iterator<Item> param_iterator(params);
-  Item_param *param;
-  ulong param_no= 0;  
+  Item_param **begin= stmt->param_array;
+  Item_param **end= begin + stmt->param_count;
 
   DBUG_ENTER("insert_params"); 
 
-  while ((param= (Item_param *)param_iterator++))
+  for (Item_param **it= begin; it < end; ++it)
   {
-    if (!param->long_data_supplied)   
+    Item_param *param= *it;
+    if (!param->long_data_supplied)
     {
-      if (is_param_null(pos,param_no))
+      if (is_param_null(pos, it - begin))
         param->maybe_null= param->null_value= 1;
       else
       {
         param->maybe_null= param->null_value= 0;
-        param->setup_param_func(param,&read_pos);
+        param->set_param_func(param, &read_pos);
       }
     }
-    param_no++;
   }
   DBUG_RETURN(0);
 }
 
-static bool setup_params_data(Prepared_statement *stmt)
-{                                       
-  List<Item> &params= stmt->lex->param_list;
-  List_iterator<Item> param_iterator(params);
-  Item_param *param;
-
-  uchar *pos= (uchar*) stmt->thd->net.read_pos + 1 +
-              MYSQL_STMT_HEADER;                //skip header
-  uchar *read_pos= pos+(stmt->param_count+7) / 8; //skip null bits   
+static bool setup_conversion_functions(Prepared_statement *stmt,
+                                       uchar **data)
+{
+  /* skip null bits */
+  uchar *read_pos= *data + (stmt->param_count+7) / 8;
 
-  DBUG_ENTER("setup_params_data");
+  DBUG_ENTER("setup_conversion_functions");
 
   if (*read_pos++) //types supplied / first execute
-  {              
+  {
     /*
       First execute or types altered by the client, setup the 
       conversion routines for all parameters (one time)
     */
-    while ((param= (Item_param *)param_iterator++))
-    {       
-      setup_param_functions(param,*read_pos);
+    Item_param **it= stmt->param_array;
+    Item_param **end= it + stmt->param_count;
+    for (; it < end; ++it)
+    {
+      setup_one_conversion_function(*it, *read_pos);
       read_pos+= 2;
     }
-    param_iterator.rewind();
-  }    
-  stmt->setup_params(stmt,pos,read_pos);
+  }
+  *data= read_pos;
   DBUG_RETURN(0);
 }
 
 #else
 
-bool setup_params_data(Prepared_statement *stmt)
-{                                       
-  List<Item> &params= stmt->lex->param_list;
-  List_iterator<Item> param_iterator(params);
-  Item_param *param;
+static bool emb_insert_params(Prepared_statement *stmt)
+{
+  Item_param **it= stmt->param_array;
+  Item_param **end= it + stmt->param_count;
   MYSQL_BIND *client_param= stmt->thd->client_params;
 
-  DBUG_ENTER("setup_params_data");
+  DBUG_ENTER("emb_insert_params");
 
-  for (;(param= (Item_param *)param_iterator++); client_param++)
-  {       
-    setup_param_functions(param, client_param->buffer_type);
+  for (; it < end; ++it, ++client_param)
+  {
+    Item_param *param= *it;
+    setup_one_conversion_function(param, client_param->buffer_type);
     if (!param->long_data_supplied)
     {
       if (*client_param->is_null)
@@ -529,39 +525,39 @@ bool setup_params_data(Prepared_statement *stmt)
       {
 	uchar *buff= (uchar*)client_param->buffer;
         param->maybe_null= param->null_value= 0;
-        param->setup_param_func(param,&buff, 
-				client_param->length ? 
-				*client_param->length : 
-				client_param->buffer_length);
+        param->set_param_func(param, &buff,
+                              client_param->length ? 
+                              *client_param->length : 
+                              client_param->buffer_length);
       }
     }
   }
   DBUG_RETURN(0);
 }
 
-bool setup_params_data_withlog(Prepared_statement *stmt)
-{                                       
+
+static bool emb_insert_params_withlog(Prepared_statement *stmt)
+{
   THD *thd= stmt->thd;
-  List<Item> &params= stmt->lex->param_list;
-  List_iterator<Item> param_iterator(params);
-  Item_param *param;
+  Item_param **it= stmt->param_array;
+  Item_param **end= it + stmt->param_count;
   MYSQL_BIND *client_param= thd->client_params;
 
   String str, query;
   const String *res;
+  uint32 length= 0;
 
-  DBUG_ENTER("setup_params_data_withlog");
+  DBUG_ENTER("emb_insert_params_withlog");
 
   if (query.copy(stmt->query, stmt->query_length, default_charset_info))
     DBUG_RETURN(1);
   
-  uint32 length= 0;
-
-  for (;(param= (Item_param *)param_iterator++); client_param++)
-  {       
-    setup_param_functions(param, client_param->buffer_type);
+  for (; it < end; ++it, ++client_param)
+  {
+    Item_param *param= *it;
+    setup_one_conversion_function(param, client_param->buffer_type);
     if (param->long_data_supplied)
-      res= param->query_val_str(&str);       
+      res= param->query_val_str(&str);
     else
     {
       if (*client_param->is_null)
@@ -573,16 +569,15 @@ bool setup_params_data_withlog(Prepared_statement *stmt)
       {
 	uchar *buff= (uchar*)client_param->buffer;
         param->maybe_null= param->null_value= 0;
-        param->setup_param_func(param,&buff,
-				client_param->length ? 
-				*client_param->length : 
-				client_param->buffer_length);
+        param->set_param_func(param, &buff,
+                              client_param->length ? 
+                              *client_param->length : 
+                              client_param->buffer_length);
         res= param->query_val_str(&str);
       }
     }
     if (query.replace(param->pos_in_query+length, 1, *res))
       DBUG_RETURN(1);
-    
     length+= res->length()-1;
   }
   
@@ -595,15 +590,21 @@ bool setup_params_data_withlog(Prepared_statement *stmt)
 #endif /*!EMBEDDED_LIBRARY*/
 
 /*
-  Validate the following information for INSERT statement:                         
-    - field existance           
-    - fields count                          
+  Validate the following information for INSERT statement: 
+    - field existence
+    - fields count
+  SYNOPSIS
+    mysql_test_insert_fields()
+  RETURN VALUE
+    0   ok
+    1   error, sent to the client
+   -1   error, not sent to client
 */
 
-static bool mysql_test_insert_fields(Prepared_statement *stmt,
-				     TABLE_LIST *table_list,
-				     List<Item> &fields, 
-				     List<List_item> &values_list)
+static int mysql_test_insert_fields(Prepared_statement *stmt,
+                                    TABLE_LIST *table_list,
+                                    List<Item> &fields, 
+                                    List<List_item> &values_list)
 {
   THD *thd= stmt->thd;
   TABLE *table;
@@ -630,7 +631,7 @@ static bool mysql_test_insert_fields(Prepared_statement *stmt,
   if (open_and_lock_tables(thd, table_list))
   {
     thd->free_temporary_memory_pool_for_ps_preparing();
-    DBUG_RETURN(1);
+    DBUG_RETURN(-1);
   }
 
   table= table_list->table;
@@ -643,7 +644,7 @@ static bool mysql_test_insert_fields(Prepared_statement *stmt,
     if (check_insert_fields(thd,table,fields,*values,1))
     {
       thd->free_temporary_memory_pool_for_ps_preparing();
-      DBUG_RETURN(1);
+      DBUG_RETURN(-1);
     }
     thd->free_temporary_memory_pool_for_ps_preparing();
 
@@ -658,7 +659,7 @@ static bool mysql_test_insert_fields(Prepared_statement *stmt,
         my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW,
 			ER(ER_WRONG_VALUE_COUNT_ON_ROW),
 			MYF(0), counter);
-        DBUG_RETURN(1);
+        DBUG_RETURN(-1);
       }
     }
   }
@@ -666,25 +667,26 @@ static bool mysql_test_insert_fields(Prepared_statement *stmt,
   {
     thd->free_temporary_memory_pool_for_ps_preparing();
   }
-  if (send_prep_stmt(stmt, 0))
-    DBUG_RETURN(1);
   DBUG_RETURN(0);
 }
 
 
 /*
-  Validate the following information                         
-    UPDATE - set and where clause    DELETE - where clause                                             
-                                                             
-  And send update-set clause column list fields info 
-  back to client. For DELETE, just validate where clause 
-  and return no fields information back to client.
+  Validate the following information:
+    UPDATE - set and where clause
+    DELETE - where clause
+  SYNOPSIS
+    mysql_test_upd_fields()
+  RETURN VALUE
+    0   success
+    1   error, sent to client
+   -1   error, not sent to client
 */
 
-static bool mysql_test_upd_fields(Prepared_statement *stmt,
-                                  TABLE_LIST *table_list,
-				  List<Item> &fields, List<Item> &values,
-				  COND *conds)
+static int mysql_test_upd_fields(Prepared_statement *stmt,
+                                 TABLE_LIST *table_list,
+                                 List<Item> &fields, List<Item> &values,
+                                 COND *conds)
 {
   THD *thd= stmt->thd;
 
@@ -711,44 +713,43 @@ static bool mysql_test_upd_fields(Prepared_statement *stmt,
 
   thd->free_temporary_memory_pool_for_ps_preparing();
 
-  /* 
-     Currently return only column list info only, and we are not
-     sending any info on where clause.
-  */
-  if (send_prep_stmt(stmt, 0))
-    DBUG_RETURN(1);
+  /* TODO: here we should send types of placeholders to the client. */
   DBUG_RETURN(0);
 err:
   thd->free_temporary_memory_pool_for_ps_preparing();
-  DBUG_RETURN(1);
+  DBUG_RETURN(-1);
 }
 
 /*
-  Validate the following information:                         
-
+  Validate the following information:
     SELECT - column list 
            - where clause
            - order clause
            - having clause
            - group by clause
            - if no column spec i.e. '*', then setup all fields
-                                                           
-  And send column list fields info back to client. 
+  In case of success, if this query is not EXPLAIN, send column list info
+  back to client. 
+  SYNOPSIS
+    mysql_test_select_fields()
+  RETURN VALUE
+    0   success
+    1   error, sent to client
+   -1   error, not sent to client
 */
 
-static bool mysql_test_select_fields(Prepared_statement *stmt,
-                                     TABLE_LIST *tables,
-				     uint wild_num,
-                                     List<Item> &fields, COND *conds, 
-                                     uint og_num, ORDER *order, ORDER *group,
-                                     Item *having, ORDER *proc,
-                                     ulong select_options, 
-                                     SELECT_LEX_UNIT *unit,
-                                     SELECT_LEX *select_lex)
+static int mysql_test_select_fields(Prepared_statement *stmt,
+                                    TABLE_LIST *tables,
+                                    uint wild_num,
+                                    List<Item> &fields, COND *conds, 
+                                    uint og_num, ORDER *order, ORDER *group,
+                                    Item *having, ORDER *proc,
+                                    ulong select_options, 
+                                    SELECT_LEX_UNIT *unit,
+                                    SELECT_LEX *select_lex)
 {
   THD *thd= stmt->thd;
   LEX *lex= stmt->lex;
-  select_result *result= lex->result;
 
   DBUG_ENTER("mysql_test_select_fields");
 
@@ -772,7 +773,10 @@ static bool mysql_test_select_fields(Prepared_statement *stmt,
   */
   thd->allocate_temporary_memory_pool_for_ps_preparing();
   if (open_and_lock_tables(thd, tables))
+  {
+    send_error(thd);
     goto err;
+  }
 
   if (lex->describe)
   {
@@ -781,23 +785,27 @@ static bool mysql_test_select_fields(Prepared_statement *stmt,
   }
   else 
   {
+    select_result *result= lex->result;
     if (!result && !(result= new select_send()))
     {
       send_error(thd, ER_OUT_OF_RESOURCES);
       goto err;
     }
 
-    thd->used_tables= 0;	// Updated by setup_fields  
+    thd->used_tables= 0;                        // Updated by setup_fields
 
     if (unit->prepare(thd, result, 0))
+    {
+      send_error(thd);
       goto err_prep;
+    }
 
     if (send_prep_stmt(stmt, fields.elements) ||
         thd->protocol_simple.send_fields(&fields, 0)
 #ifndef EMBEDDED_LIBRARY
-	|| net_flush(&thd->net)
+        || net_flush(&thd->net)
 #endif
-	)
+       )
       goto err_prep;
 
     unit->cleanup();
@@ -814,97 +822,104 @@ err:
 
 
 /*
-  Send the prepare query results back to client              
+  Send the prepare query results back to client
+  SYNOPSIS
+  send_prepare_results()
+    stmt prepared statement
+  RETURN VALUE
+    0   success
+    1   error, sent to client
 */
                      
-static bool send_prepare_results(Prepared_statement *stmt)     
+static int send_prepare_results(Prepared_statement *stmt)
 {   
   THD *thd= stmt->thd;
   LEX *lex= stmt->lex;
+  SELECT_LEX *select_lex= &lex->select_lex;
+  TABLE_LIST *tables=(TABLE_LIST*) select_lex->table_list.first;
   enum enum_sql_command sql_command= lex->sql_command;
+  int res;
 
   DBUG_ENTER("send_prepare_results");
   DBUG_PRINT("enter",("command: %d, param_count: %ld",
-                      sql_command, lex->param_count));
-  
-  /* Setup prepared stmt */
-  stmt->param_count= lex->param_count;
-
-  SELECT_LEX *select_lex= &lex->select_lex;
-  TABLE_LIST *tables=(TABLE_LIST*) select_lex->table_list.first;
+                      sql_command, stmt->param_count));
   
   switch (sql_command) {
 
   case SQLCOM_INSERT:
-    if (mysql_test_insert_fields(stmt, tables, lex->field_list,
-				 lex->many_values))
-      goto abort;    
+    if ((res= mysql_test_insert_fields(stmt, tables, lex->field_list,
+                                       lex->many_values)))
+      goto error;
     break;
 
   case SQLCOM_UPDATE:
-    if (mysql_test_upd_fields(stmt, tables, select_lex->item_list,
-			      lex->value_list, select_lex->where))
-      goto abort;
-    break;
-
+    /* XXX: fallthrough */
   case SQLCOM_DELETE:
-    if (mysql_test_upd_fields(stmt, tables, select_lex->item_list,
-			      lex->value_list, select_lex->where))
-      goto abort;
+    if ((res= mysql_test_upd_fields(stmt, tables, select_lex->item_list,
+                                    lex->value_list, select_lex->where)))
+      goto error;
     break;
 
   case SQLCOM_SELECT:
-    if (mysql_test_select_fields(stmt, tables, select_lex->with_wild,
-                                 select_lex->item_list,
-                                 select_lex->where,
-				 select_lex->order_list.elements +
-				 select_lex->group_list.elements,
-                                 (ORDER*) select_lex->order_list.first,
-                                 (ORDER*) select_lex->group_list.first, 
-                                 select_lex->having,
-                                 (ORDER*)lex->proc_list.first,
-                                 select_lex->options | thd->options,
-                                 &(lex->unit), select_lex))
-      goto abort;
-    break;
+    if ((res= mysql_test_select_fields(stmt, tables, select_lex->with_wild,
+                                       select_lex->item_list,
+                                       select_lex->where,
+                                       select_lex->order_list.elements +
+                                       select_lex->group_list.elements,
+                                       (ORDER*) select_lex->order_list.first,
+                                       (ORDER*) select_lex->group_list.first, 
+                                       select_lex->having,
+                                       (ORDER*)lex->proc_list.first,
+                                       select_lex->options | thd->options,
+                                       &(lex->unit), select_lex)))
+      goto error;
+    /* Statement and field info has already been sent */
+    DBUG_RETURN(0);
 
   default:
-    {
-      /* 
-         Rest fall through to default category, no parsing 
-         for non-DML statements 
-      */
-      if (send_prep_stmt(stmt, 0))
-        goto abort;
-    }
+    /* 
+      Rest fall through to default category, no parsing 
+      for non-DML statements 
+    */
+    break;
   }
-  DBUG_RETURN(0);
+  DBUG_RETURN(send_prep_stmt(stmt, 0));
 
-abort:
-  send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0);
+error:
+  if (res < 0)
+    send_error(thd, thd->killed ? ER_SERVER_SHUTDOWN : 0);
   DBUG_RETURN(1);
 }
 
 /*
-  Initialize parameter items in statement
+  Initialize array of parametes in statement from LEX.
+  (We need to have quick access to items by number in mysql_send_longdata).
+  This is to avoid using malloc/realloc in the parser.
 */
 
-static bool init_param_items(Prepared_statement *stmt)
+static bool init_param_array(Prepared_statement *stmt)
 {
-  Item_param **to;
- 
-  if (!stmt->param_count)
-    stmt->param= (Item_param **)0;
-  else
-  {    
-    if (!(stmt->param= to= (Item_param **)
-          my_malloc(sizeof(Item_param *)*(stmt->param_count+1), 
-                    MYF(MY_WME))))
+  LEX *lex= stmt->lex;
+  if ((stmt->param_count= lex->param_list.elements))
+  {
+    Item_param **to;
+    List_iterator<Item_param> param_iterator(lex->param_list);
+    /* Use thd->mem_root as it points at statement mem_root */
+    stmt->param_array= (Item_param **)
+                       alloc_root(&stmt->thd->mem_root,
+                                  sizeof(Item_param*) * stmt->param_count);
+    if (!stmt->param_array)
+    {
+      send_error(stmt->thd, ER_OUT_OF_RESOURCES);
       return 1;
-
-    List_iterator<Item> param_iterator(stmt->lex->param_list);
-    while ((*(to++)= (Item_param *)param_iterator++));
-  }  
+    }
+    for (to= stmt->param_array;
+         to < stmt->param_array + stmt->param_count;
+         ++to)
+    {
+      *to= param_iterator++;
+    }
+  }
   return 0;
 }
 
@@ -912,137 +927,104 @@ static bool init_param_items(Prepared_statement *stmt)
 /*
   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. with out any log/disk 
+  without executing the query i.e. without any log/disk 
   writes. This will allow the queries to be re-executed 
-  without re-parsing during execute.          
-                                                              
-  If parameter markers are found in the query, then store    
-  the information using Item_param along with maintaining a  
-  list in lex->param_list, so that a fast and direct         
-  retrieval can be made without going through all field     
-  items.                                                     
+  without re-parsing during execute. 
+
+  If parameter markers are found in the query, then store 
+  the information using Item_param along with maintaining a
+  list in lex->param_array, so that a fast and direct
+  retrieval can be made without going through all field
+  items.
 */
 
-bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length)
+void mysql_stmt_prepare(THD *thd, char *packet, uint packet_length)
 {
   LEX *lex;
   Prepared_statement *stmt= new Prepared_statement(thd);
-  SELECT_LEX *sl;
+  int error;
   DBUG_ENTER("mysql_stmt_prepare");
 
   if (stmt == 0)
-    DBUG_RETURN(0);
+  {
+    send_error(thd, ER_OUT_OF_RESOURCES);
+    DBUG_VOID_RETURN;
+  }
 
   if (thd->stmt_map.insert(stmt))
-    goto insert_stmt_err;
+  {
+    delete stmt;
+    send_error(thd, ER_OUT_OF_RESOURCES);
+    DBUG_VOID_RETURN;
+  }
 
   thd->stmt_backup.set_statement(thd);
+  thd->stmt_backup.set_item_arena(thd);
   thd->set_statement(stmt);
-  thd->current_statement= stmt;
+  thd->set_item_arena(stmt);
 
   if (alloc_query(thd, packet, packet_length))
-    goto alloc_query_err;
+  {
+    stmt->set_statement(thd);
+    stmt->set_item_arena(thd);
+    thd->set_statement(&thd->stmt_backup);
+    thd->set_item_arena(&thd->stmt_backup);
+    /* Statement map deletes statement on erase */
+    thd->stmt_map.erase(stmt);
+    send_error(thd, ER_OUT_OF_RESOURCES);
+    DBUG_VOID_RETURN;
+  }
 
-  mysql_log.write(thd, COM_PREPARE, "%s", packet);       
+  mysql_log.write(thd, COM_PREPARE, "%s", packet);
 
+  thd->current_statement= stmt;
   lex= lex_start(thd, (uchar *) thd->query, thd->query_length);
   mysql_init_query(thd);
   lex->safe_to_cache_query= 0;
-  lex->param_count= 0;
 
-  if (yyparse((void *)thd) || thd->is_fatal_error || send_prepare_results(stmt))
-    goto yyparse_err;
-
-  lex_end(lex);
+  error= yyparse((void *)thd) || thd->is_fatal_error ||
+         init_param_array(stmt) ||
+         send_prepare_results(stmt);
 
+  /* restore to WAIT_PRIOR: QUERY_PRIOR is set inside alloc_query */
   if (!(specialflag & SPECIAL_NO_PRIOR))
     my_pthread_setprio(pthread_self(),WAIT_PRIOR);
-
-  // save WHERE clause pointers to avoid damaging they by optimisation
-  for (sl= thd->lex->all_selects_list;
-       sl;
-       sl= sl->next_select_in_list())
-  {
-    sl->prep_where= sl->where;
-  }
-
-  stmt->set_statement(thd);
-  thd->set_statement(&thd->stmt_backup);
-  thd->current_statement= 0;
-
-  if (init_param_items(stmt))
-    goto init_param_err;
-
-  stmt->command= COM_EXECUTE;                   // set it only once here 
-
-  DBUG_RETURN(0);
-
-yyparse_err:
   lex_end(lex);
   stmt->set_statement(thd);
+  stmt->set_item_arena(thd);
   thd->set_statement(&thd->stmt_backup);
-init_param_err:
-alloc_query_err:
-  /* Statement map deletes statement on erase */
-  thd->stmt_map.erase(stmt);
-  thd->current_statement= 0;
-  DBUG_RETURN(1);
-insert_stmt_err:
-  stmt->set_statement(thd);
-  thd->set_statement(&thd->stmt_backup);
-  /* Statement map deletes statement on erase */
-  thd->stmt_map.erase(stmt);
+  thd->set_item_arena(&thd->stmt_backup);
   thd->current_statement= 0;
-  delete stmt;
-  DBUG_RETURN(1);
-}
-
-
-/*
-  Executes previously prepared query
 
-  If there is any parameters (stmt->param_count), then replace 
-  markers with the data supplied from client, and then       
-  execute the query                                            
-*/
-
-void mysql_stmt_execute(THD *thd, char *packet)
-{
-  ulong stmt_id= uint4korr(packet);
-  Prepared_statement *stmt;
-
-  DBUG_ENTER("mysql_stmt_execute");
-  
-  if (!(stmt= find_prepared_statement(thd, stmt_id, "execute")))
-    DBUG_VOID_RETURN;
-
-  /* Check if we got an error when sending long data */
-  if (stmt->error_in_prepare)
+  if (error)
   {
-    send_error(thd, stmt->last_errno, stmt->last_error);
-    DBUG_VOID_RETURN;
+    /* Statement map deletes statement on erase */
+    thd->stmt_map.erase(stmt);
+    /* error is sent inside yyparse/send_prepare_results */
   }
+  else
+  {
+    SELECT_LEX *sl= stmt->lex->all_selects_list;
+    /*
+      Save WHERE clause pointers, because they may be changed during query
+      optimisation.
+    */
+    for (; sl; sl= sl->next_select_in_list())
+    {
+      sl->prep_where= sl->where;
+    }
+  }
+  DBUG_VOID_RETURN;
+}
 
-  stmt->query_id= thd->query_id;
-  thd->stmt_backup.set_statement(thd);
-  thd->set_statement(stmt);
-  thd->free_list= 0;
-
-  /*
-    To make sure that all runtime data is stored in its own memory root and 
-    does not interfere with data possibly present in thd->mem_root.
-    This root is cleaned up in the end of execution.
-    FIXME: to be replaced with more efficient approach, and verified why we
-    can not use thd->mem_root safely.
-  */
-  init_sql_alloc(&thd->mem_root,
-                 thd->variables.query_alloc_block_size,
-                 thd->variables.query_prealloc_size);
+/* Reinit statement before execution */
 
+static void reset_stmt_for_execute(Prepared_statement *stmt)
+{
+  THD *thd= stmt->thd;
+  SELECT_LEX *sl= stmt->lex->all_selects_list;
 
-  for (SELECT_LEX *sl= stmt->lex->all_selects_list;
-       sl;
-       sl= sl->next_select_in_list())
+  for (; sl; sl= sl->next_select_in_list())
   {
     /*
       Copy WHERE clause pointers to avoid damaging they by optimisation
@@ -1075,58 +1057,104 @@ void mysql_stmt_execute(THD *thd, char *packet)
       SELECT_LEX_UNIT *unit= sl->master_unit();
       unit->unclean();
       unit->types.empty();
-      // for derived tables & PS (which can't be reset by Item_subquery)
+      /* for derived tables & PS (which can't be reset by Item_subquery) */
       unit->reinit_exec_mechanism();
     }
   }
+}
+
+/*
+  Executes previously prepared query.
+  If there is any parameters, then replace markers with the data supplied
+  from client, and then execute the query.
+  SYNOPSYS
+    mysql_stmt_execute()
+*/
+
+
+void mysql_stmt_execute(THD *thd, char *packet)
+{
+  ulong stmt_id= uint4korr(packet);
+  Prepared_statement *stmt;
+
+  DBUG_ENTER("mysql_stmt_execute");
+  
+  if (!(stmt= find_prepared_statement(thd, stmt_id, "execute", SEND_ERROR)))
+    DBUG_VOID_RETURN;
+
+  /* Check if we got an error when sending long data */
+  if (stmt->get_longdata_error)
+  {
+    send_error(thd, stmt->last_errno, stmt->last_error);
+    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 && setup_params_data(stmt))
-    goto end;
+  if (stmt->param_count)
+  {
+    packet+= 4;
+    uchar *null_array= (uchar *) packet;
+    if (setup_conversion_functions(stmt, (uchar **) &packet) ||
+        stmt->set_params(stmt, null_array, (uchar *) packet)) 
+      goto set_params_data_err;
+  }
 #else
-  if (stmt->param_count && (*stmt->setup_params_data)(stmt))
-    goto end;
+  /*
+    In embedded library we re-install conversion routines each time 
+    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))
+    goto set_params_data_err;
 #endif
 
   if (!(specialflag & SPECIAL_NO_PRIOR))
-    my_pthread_setprio(pthread_self(),QUERY_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
+  */
+  thd->protocol= &thd->protocol_prep;           // Switch to binary protocol
   mysql_execute_command(thd);
-  thd->protocol= &thd->protocol_simple;	// Use normal protocol
+  thd->protocol= &thd->protocol_simple;         // Use normal protocol
 
   if (!(specialflag & SPECIAL_NO_PRIOR))
     my_pthread_setprio(pthread_self(), WAIT_PRIOR);
 
-  free_items(thd->free_list);
   cleanup_items(stmt->free_list);
   close_thread_tables(thd); // to close derived tables
-  free_root(&thd->mem_root, MYF(0));
   thd->set_statement(&thd->stmt_backup);
-end:
+  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
-  
+    Reset a prepared statement, in case there was an error in send_longdata.
+    Note: we don't send any reply to that command.
   SYNOPSIS
     mysql_stmt_reset()
     thd		Thread handle
-    packet	Packet with stmt handle
+    packet	Packet with stmt id 
 
   DESCRIPTION
     This function is useful when one gets an error after calling
-    mysql_stmt_getlongdata() and one wants to reset the handle
+    mysql_stmt_getlongdata() and wants to reset the handle
     so that one can call execute again.
+    See also bug #1664
 */
 
 void mysql_stmt_reset(THD *thd, char *packet)
@@ -1136,25 +1164,27 @@ void mysql_stmt_reset(THD *thd, char *packet)
   
   DBUG_ENTER("mysql_stmt_reset");
 
-  if (!(stmt= find_prepared_statement(thd, stmt_id, "reset")))
+  if (!(stmt= find_prepared_statement(thd, stmt_id, "reset", DONT_SEND_ERROR)))
     DBUG_VOID_RETURN;
 
-  stmt->error_in_prepare= 0;
-  Item_param *item= *stmt->param, *end= item + stmt->param_count;
+  stmt->get_longdata_error= 0;
 
   /* Free long data if used */
   if (stmt->long_data_used)
   {
+    Item_param **item= stmt->param_array;
+    Item_param **end= item + stmt->param_count;
     stmt->long_data_used= 0;
     for (; item < end ; item++)
-      item->reset();
+      (**item).reset();
   }
   DBUG_VOID_RETURN;
 }
 
 
 /*
-  Delete a prepared statement from memory
+  Delete a prepared statement from memory.
+  Note: we don't send any reply to that command. 
 */
 
 void mysql_stmt_free(THD *thd, char *packet)
@@ -1164,7 +1194,7 @@ void mysql_stmt_free(THD *thd, char *packet)
 
   DBUG_ENTER("mysql_stmt_free");
 
-  if (!(stmt= find_prepared_statement(thd, stmt_id, "close")))
+  if (!(stmt= find_prepared_statement(thd, stmt_id, "close", DONT_SEND_ERROR)))
     DBUG_VOID_RETURN;
 
   /* Statement map deletes statement on erase */
@@ -1174,7 +1204,7 @@ void mysql_stmt_free(THD *thd, char *packet)
 
 
 /*
-  Long data in pieces from client                            
+  Long data in pieces from client
 
   SYNOPSIS
     mysql_stmt_get_longdata()
@@ -1210,14 +1240,15 @@ void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length)
   ulong stmt_id=     uint4korr(pos);
   uint param_number= uint2korr(pos+4);
 
-  if (!(stmt=find_prepared_statement(thd, stmt_id, "get_longdata")))
+  if (!(stmt=find_prepared_statement(thd, stmt_id, "get_longdata",
+                                     DONT_SEND_ERROR)))
     DBUG_VOID_RETURN;
 
 #ifndef EMBEDDED_LIBRARY
   if (param_number >= stmt->param_count)
   {
     /* Error will be sent in execute call */
-    stmt->error_in_prepare= 1;
+    stmt->get_longdata_error= 1;
     stmt->last_errno= ER_WRONG_ARGUMENTS;
     sprintf(stmt->last_error, ER(ER_WRONG_ARGUMENTS), "get_longdata");
     DBUG_VOID_RETURN;
@@ -1225,7 +1256,7 @@ void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length)
   pos+= MYSQL_LONG_DATA_HEADER;	// Point to data
 #endif
 
-  Item_param *param= *(stmt->param+param_number);
+  Item_param *param= stmt->param_array[param_number];
 #ifndef EMBEDDED_LIBRARY
   param->set_longdata(pos, packet_length-MYSQL_LONG_DATA_HEADER-1);
 #else
@@ -1239,10 +1270,10 @@ void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length)
 Prepared_statement::Prepared_statement(THD *thd_arg)
   :Statement(thd_arg),
   thd(thd_arg),
-  param(0),
+  param_array(0),
   param_count(0),
   last_errno(0),
-  error_in_prepare(0),
+  get_longdata_error(0),
   long_data_used(0),
   log_full_query(0)
 {
@@ -1251,23 +1282,22 @@ Prepared_statement::Prepared_statement(THD *thd_arg)
   {
     log_full_query= 1;
 #ifndef EMBEDDED_LIBRARY
-    setup_params= insert_params_withlog;
+    set_params= insert_params_withlog;
 #else
-    setup_params_data= setup_params_data_withlog;
+    set_params_data= emb_insert_params_withlog;
 #endif
   }
   else
 #ifndef EMBEDDED_LIBRARY
-    setup_params= insert_params; // not fully qualified query
+    set_params= insert_params;
 #else
-    setup_params_data= ::setup_params_data;
+    set_params_data= emb_insert_params;
 #endif
 }
 
 
 Prepared_statement::~Prepared_statement()
 {
-  my_free((char *) param, MYF(MY_ALLOW_ZERO_PTR));
   free_items(free_list);
 }
 
@@ -1277,4 +1307,3 @@ Statement::Type Prepared_statement::type() const
   return PREPARED_STATEMENT;
 }
 
-
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 4a098cc6fc04ca0444849b1fc409b8aa40ca657a..7df1973132a2de378eb90663a7340b13b6c94c9a 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -4478,11 +4478,17 @@ text_string:
 param_marker:
         '?'
         {
-	  LEX *lex=Lex;
-          if (YYTHD->command == COM_PREPARE)
+          THD *thd=YYTHD;
+	  LEX *lex= thd->lex;
+          if (thd->command == COM_PREPARE)
           {
-            lex->param_list.push_back($$=new Item_param((uint)(lex->tok_start-(uchar *)YYTHD->query)));
-            lex->param_count++;
+            Item_param *item= new Item_param((uint) (lex->tok_start -
+                                                     (uchar *) thd->query));
+            if (!($$= item) || lex->param_list.push_back(item))
+            {
+	      send_error(thd, ER_OUT_OF_RESOURCES);
+	      YYABORT;
+            }
           }
           else
           {
diff --git a/tests/client_test.c b/tests/client_test.c
index 3b9aefc6ec211b33bd0389c2d295c6feb3ec08f2..fa0b65c2928a41c4e1a03ea982622fdfd9258a5f 100644
--- a/tests/client_test.c
+++ b/tests/client_test.c
@@ -8470,8 +8470,6 @@ int main(int argc, char **argv)
    
     start_time= time((time_t *)0);
 
-    test_subqueries();
-
     client_query();         /* simple client query test */
 #if NOT_YET_WORKING
     /* Used for internal new development debugging */