List:Commits« Previous MessageNext Message »
From:Konstantin Osipov Date:December 6 2008 12:48am
Subject:bzr commit into mysql-6.0-runtime branch (kostja:2767) WL#4264
View as plain text  
#At file:///opt/local/work/mysql-6.0-ed2/

 2767 Konstantin Osipov	2008-12-06
      WL#4264 "Backup: Stabilize Service Interface", the final part
      of review fixes.
      Change the way result set data is collected: implement Ed_connection,
      execute direct connection. 
modified:
  sql/backup/backup_test.cc
  sql/backup/kernel.cc
  sql/protocol.cc
  sql/protocol.h
  sql/si_objects.cc
  sql/sql_class.cc
  sql/sql_class.h
  sql/sql_error.cc
  sql/sql_error.h
  sql/sql_prepare.cc
  sql/sql_prepare.h

per-file messages:
  sql/backup/backup_test.cc
    Remove a call that is no longer needed.
    si_objects.cc implementation no longer touches the main diagnostics
    area of the thread.
  sql/backup/kernel.cc
    Remove calls that are no longer needed.
    si_objects.cc no longer touches the diagnostics area of the thread,
    and closes the tables that it used.
  sql/protocol.cc
    Ed_*  (execute direct) implementation was moved to sql_prepare.cc.
  sql/protocol.h
    Ed_* declarations were moved to sql_prepare.h. The advantage
    of using sql_prepare.h is that it's a stand-alone header with header
    guards, unlike protocol.h.
  sql/si_objects.cc
    Use the modified interface to work with execute direct results.
    Coding style fixes (declare variables in the beginning of a function
    or block).
  sql/sql_class.cc
    Move Diagnostics_area implementation to sql_error.cc
  sql/sql_class.h
    Move Diagnostics_area declaration to sql_error.h.
    This groups all error-related classes into one, independent header.
  sql/sql_error.cc
    Diagnostics_area implementation added.
  sql/sql_error.h
    Diagnostics_area declaration added.
  sql/sql_prepare.cc
    Implement Ed_connection - a way to execute queries within the server.
    Derives heavily on the original implementation, however:
    - we no longer need to grab messages or warnings from THD, since
    Warning_info and Diagnostics_area are members of Ed_connection
    and can be used directly.
    Add comments.
  sql/sql_prepare.h
    Move declarations of Ed_* classes (execute direct interface)
    to this header. This allows usage of execute direct without
    having to include mysql_priv.h.
=== modified file 'sql/backup/backup_test.cc'
--- a/sql/backup/backup_test.cc	2008-12-04 16:50:07 +0000
+++ b/sql/backup/backup_test.cc	2008-12-05 23:47:51 +0000
@@ -261,7 +261,6 @@ int execute_backup_test_command(THD *thd
       }
     }
   }
-  thd->stmt_da->reset_diagnostics_area();
   my_eof(thd);
   DBUG_RETURN(res);
 }

=== modified file 'sql/backup/kernel.cc'
--- a/sql/backup/kernel.cc	2008-12-04 23:14:30 +0000
+++ b/sql/backup/kernel.cc	2008-12-05 23:47:51 +0000
@@ -1263,15 +1263,6 @@ int Backup_restore_ctx::do_restore(bool 
 
   DBUG_PRINT("restore",("Restoring table data"));
 
-  /* 
-    FIXME: this call is here because object services doesn't clean the
-    statement execution context properly, which leads to assertion failure.
-    It should be fixed inside object services implementation and then the
-    following line should be removed.
-   */
-  close_thread_tables(m_thd);                   // Never errors
-  m_thd->stmt_da->reset_diagnostics_area();      // Never errors  
-
   if (lock_tables_for_restore())                // logs errors
     DBUG_RETURN(m_error);
 
@@ -1301,15 +1292,6 @@ int Backup_restore_ctx::do_restore(bool 
     DBUG_RETURN(m_error);
   }
 
-  /* 
-    FIXME: this call is here because object services doesn't clean the
-    statement execution context properly, which leads to assertion failure.
-    It should be fixed inside object services implementation and then the
-    following line should be removed.
-   */
-  close_thread_tables(m_thd);                   // Never errors
-  m_thd->stmt_da->reset_diagnostics_area();      // Never errors
-
   /*
     Report validity point time and binlog position stored in the backup image
     (in the summary section).

=== modified file 'sql/protocol.cc'
--- a/sql/protocol.cc	2008-12-04 16:50:07 +0000
+++ b/sql/protocol.cc	2008-12-05 23:47:51 +0000
@@ -1475,476 +1475,3 @@ bool Protocol_binary::send_out_parameter
   return FALSE;
 }
 
-///////////////////////////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////////////////
-
-Ed_result::Ed_result() :
-  m_current_result_set(NULL),
-  m_status(Diagnostics_area::DA_EMPTY),
-  m_server_status(0),
-  m_affected_rows(0),
-  m_last_insert_id(0),
-  m_sql_errno(0),
-  m_warning_info(0),
-  m_warning_info_saved(NULL)
-{
-  init_sql_alloc(&m_mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0);
-
-  m_message[0]= 0;
-}
-
-///////////////////////////////////////////////////////////////////////////
-
-Ed_result::~Ed_result()
-{
-  free_root(&m_mem_root, MYF(0));
-}
-
-///////////////////////////////////////////////////////////////////////////
-
-bool Ed_result::add_result_set(List<Item> *col_metadata)
-{
-  Ed_result_set *rs= Ed_result_set::create(&m_mem_root, col_metadata);
-
-  if (!rs)
-    return TRUE;
-
-  m_current_result_set= rs;
-
-  return push_back(rs, &m_mem_root) ? TRUE : FALSE;
-}
-
-///////////////////////////////////////////////////////////////////////////
-
-void Ed_result::send_ok(THD *thd,
-                        uint server_status, uint statement_warn_count,
-                        ha_rows affected_rows, ulonglong last_insert_id,
-                        const char *message)
-{
-  DBUG_ENTER("Ed_result::send_ok()");
-  DBUG_ASSERT(m_status == Diagnostics_area::DA_EMPTY);
-
-  m_status= thd->stmt_da->status();
-  DBUG_ASSERT(m_status == Diagnostics_area::DA_OK);
-
-  DBUG_ASSERT(m_warning_info.statement_warn_count() == statement_warn_count);
-
-  m_server_status= server_status;
-  m_affected_rows= affected_rows;
-  m_last_insert_id= last_insert_id;
-
-  strmake(m_message, message, sizeof (m_message) - 1);
-
-  DBUG_VOID_RETURN;
-}
-
-///////////////////////////////////////////////////////////////////////////
-
-void Ed_result::send_eof(THD *thd, uint server_status,
-                         uint statement_warn_count)
-{
-  DBUG_ENTER("Ed_result::send_eof");
-  DBUG_ASSERT(m_status == Diagnostics_area::DA_EMPTY);
-
-  m_status= thd->stmt_da->status();
-  DBUG_ASSERT(m_status == Diagnostics_area::DA_EOF);
-
-  DBUG_ASSERT(m_warning_info.statement_warn_count() == statement_warn_count);
-
-  m_server_status= server_status;
-
-  DBUG_VOID_RETURN;
-}
-
-///////////////////////////////////////////////////////////////////////////
-
-void Ed_result::send_error(THD *thd, uint sql_errno, const char *err_msg)
-{
-  DBUG_ENTER("Ed_result::send_error()");
-  DBUG_ASSERT(m_status == Diagnostics_area::DA_EMPTY);
-
-  m_status= thd->stmt_da->status();
-  DBUG_ASSERT(m_status == Diagnostics_area::DA_ERROR);
-
-  m_sql_errno= sql_errno;
-  strmake(m_message, err_msg, sizeof (m_message) - 1);
-
-  DBUG_VOID_RETURN;
-}
-
-///////////////////////////////////////////////////////////////////////////
-
-void Ed_result::begin_statement(THD *thd)
-{
-  DBUG_ASSERT(!m_warning_info_saved);
-
-  m_warning_info_saved= thd->warning_info;
-  thd->warning_info= &m_warning_info;
-}
-
-///////////////////////////////////////////////////////////////////////////
-
-void Ed_result::end_statement(THD *thd)
-{
-  DBUG_ASSERT(m_warning_info_saved);
-  thd->warning_info= m_warning_info_saved;
-}
-
-///////////////////////////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////////////////
-
-Ed_result_set *
-Ed_result_set::create(MEM_ROOT *mem_root, List<Item> *col_metadata)
-{
-  Ed_result_set *rs= new (mem_root) Ed_result_set(mem_root);
-
-  if (!rs || rs->init(col_metadata))
-    return NULL;
-
-  return rs;
-}
-
-///////////////////////////////////////////////////////////////////////////
-
-bool Ed_result_set::init(List<Item> *col_metadata)
-{
-  m_metadata= Ed_result_set_metadata::create(m_mem_root, col_metadata);
-
-  return m_metadata == NULL;
-}
-
-///////////////////////////////////////////////////////////////////////////
-
-Ed_row *Ed_result_set::add_row()
-{
-  Ed_row *row= Ed_row::create(m_mem_root, m_metadata);
-
-  if (!row)
-    return NULL;
-
-  m_current_row= row;
-
-  return m_data.push_back(row, m_mem_root) ? NULL : row;
-}
-
-///////////////////////////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////////////////
-
-Ed_result_set_metadata *
-Ed_result_set_metadata::create(MEM_ROOT *mem_root,
-                               List<Item> *col_metadata)
-{
-  Ed_result_set_metadata *md= new (mem_root) Ed_result_set_metadata();
-
-  if (!md || md->init(mem_root, col_metadata))
-    return NULL;
-
-  return md;
-}
-
-///////////////////////////////////////////////////////////////////////////
-
-bool Ed_result_set_metadata::init(MEM_ROOT *mem_root, List<Item> *col_metadata)
-{
-  if (!col_metadata)
-    return FALSE;
-
-  m_metadata= new (mem_root) Send_field[col_metadata->elements];
-
-  if (!m_metadata)
-    return TRUE;
-
-  m_num_columns= col_metadata->elements;
-
-  List_iterator_fast<Item> it(*col_metadata);
-
-  int i= 0;
-  for (Item *column= it++; column; column= it++)
-    column->make_field(&m_metadata[i]);
-
-  return FALSE;
-}
-
-///////////////////////////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////////////////
-
-Ed_row *Ed_row::create(MEM_ROOT *mem_root,
-                       const Ed_result_set_metadata *metadata)
-{
-  DBUG_ASSERT(metadata);
-
-  Ed_row *row= new (mem_root) Ed_row(mem_root, metadata);
-
-  if (!row || row->init())
-    return NULL;
-
-  return row;
-}
-
-///////////////////////////////////////////////////////////////////////////
-
-bool Ed_row::init()
-{
-  m_columns= new (m_mem_root) Ed_column[m_metadata->get_num_columns()];
-
-  return m_columns == NULL;
-}
-
-///////////////////////////////////////////////////////////////////////////
-
-bool Ed_row::add_null()
-{
-  if (m_current_column_index >= m_metadata->get_num_columns())
-    return TRUE;
-
-  ++m_current_column_index;
-
-  return FALSE;
-}
-
-///////////////////////////////////////////////////////////////////////////
-
-bool Ed_row::add_column(const void *data_ptr, int data_length)
-{
-  if (m_current_column_index >= m_metadata->get_num_columns())
-    return TRUE;
-
-  m_columns[m_current_column_index++].set_data(m_mem_root,
-                                               data_ptr, data_length);
-
-  return FALSE;
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// Protocol_local: a protocol for retrieving result sets from the server
-// locally.
-//
-///////////////////////////////////////////////////////////////////////////
-
-void Protocol_local::prepare_for_resend()
-{
-  DBUG_ASSERT(m_result);
-
-  Ed_result_set *rs= m_result->get_cur_result_set();
-
-  DBUG_ASSERT(rs);
-
-  rs->add_row();
-}
-
-bool Protocol_local::write()
-{
-  return FALSE;
-}
-
-bool Protocol_local::store_null()
-{
-  DBUG_ASSERT(m_result);
-
-  Ed_result_set *rs= m_result->get_cur_result_set();
-  Ed_row *row= rs->get_cur_row();
-  DBUG_ASSERT(row);
-
-  return row->add_null();
-}
-
-bool Protocol_local::store_string(const char *str,
-                                  int length,
-                                  CHARSET_INFO *src_cs,
-                                  CHARSET_INFO *dst_cs)
-{
-  DBUG_ASSERT(m_result);
-
-  Ed_result_set *rs= m_result->get_cur_result_set();
-  Ed_row *row= rs->get_cur_row();
-  DBUG_ASSERT(row);
-
-  /* 'dst_cs' is set 0 when client issued SET character_set_results = NULL */
-
-  if (!dst_cs ||
-      my_charset_same(src_cs, dst_cs) ||
-      src_cs == &my_charset_bin ||
-      dst_cs == &my_charset_bin)
-  {
-    return row->add_column(str, length);
-  }
-
-  /* Store with conversion */
-  uint dummy_errors;
-
-  if (convert->copy(str, length, src_cs, dst_cs, &dummy_errors))
-    return TRUE;
-
-  return row->add_column(convert->ptr(), convert->length());
-}
-
-bool Protocol_local::store_tiny(longlong value)
-{
-  Ed_result_set *rs= m_result->get_cur_result_set();
-  Ed_row *row= rs->get_cur_row();
-
-  /* TODO: check medata type. */
-
-  char v= (char) value;
-
-  return row->add_column(&v, 1);
-}
-
-bool Protocol_local::store_short(longlong value)
-{
-  Ed_result_set *rs= m_result->get_cur_result_set();
-  Ed_row *row= rs->get_cur_row();
-
-  /* TODO: check medata type. */
-
-  int16 v= (int16) value;
-
-  return row->add_column(&v, 2);
-}
-
-bool Protocol_local::store_long(longlong value)
-{
-  Ed_result_set *rs= m_result->get_cur_result_set();
-  Ed_row *row= rs->get_cur_row();
-
-  /* TODO: check medata type. */
-
-  int32 v= (int32) value;
-
-  return row->add_column(&v, 4);
-}
-
-bool Protocol_local::store_longlong(longlong value, bool unsigned_flag)
-{
-  Ed_result_set *rs= m_result->get_cur_result_set();
-  Ed_row *row= rs->get_cur_row();
-
-  /* TODO: check medata type. */
-
-  int64 v= (int64) value;
-
-  return row->add_column(&v, 8);
-}
-
-bool Protocol_local::store_decimal(const my_decimal *value)
-{
-  Ed_result_set *rs= m_result->get_cur_result_set();
-  Ed_row *row= rs->get_cur_row();
-
-  /* TODO: check medata type. */
-
-  char buf[DECIMAL_MAX_STR_LENGTH];
-  String str(buf, sizeof (buf), &my_charset_bin);
-  my_decimal2string(E_DEC_FATAL_ERROR, value, 0, 0, 0, &str);
-
-  return row->add_column(str.ptr(), str.length());
-}
-
-bool Protocol_local::store(const char *str,
-                           size_t length,
-                           CHARSET_INFO *src_cs)
-{
-  CHARSET_INFO *dst_cs= this->thd->variables.character_set_results;
-  return store_string(str, length, src_cs, dst_cs);
-}
-
-bool Protocol_local::store(const char *str,
-                           size_t length,
-                           CHARSET_INFO *src_cs,
-                           CHARSET_INFO *dst_cs)
-{
-  return store_string(str, length, src_cs, dst_cs);
-}
-
-bool Protocol_local::store(MYSQL_TIME *time)
-{
-  Ed_result_set *rs= m_result->get_cur_result_set();
-  Ed_row *row= rs->get_cur_row();
-
-  /* TODO: check medata type. */
-
-  return row->add_column(time, sizeof (MYSQL_TIME));
-}
-
-bool Protocol_local::store_date(MYSQL_TIME *time)
-{
-  Ed_result_set *rs= m_result->get_cur_result_set();
-  Ed_row *row= rs->get_cur_row();
-
-  /* TODO: check medata type. */
-
-  return row->add_column(time, sizeof (MYSQL_TIME));
-}
-
-bool Protocol_local::store_time(MYSQL_TIME *time)
-{
-  Ed_result_set *rs= m_result->get_cur_result_set();
-  Ed_row *row= rs->get_cur_row();
-
-  /* TODO: check medata type. */
-
-  return row->add_column(time, sizeof (MYSQL_TIME));
-}
-
-bool Protocol_local::store(float value, uint32 decimals, String *buffer)
-{
-  Ed_result_set *rs= m_result->get_cur_result_set();
-  Ed_row *row= rs->get_cur_row();
-
-  /* TODO: check medata type. */
-
-  return row->add_column(&value, sizeof (float));
-}
-
-bool Protocol_local::store(double value, uint32 decimals, String *buffer)
-{
-  Ed_result_set *rs= m_result->get_cur_result_set();
-  Ed_row *row= rs->get_cur_row();
-
-  /* TODO: check medata type. */
-
-  return row->add_column(&value, sizeof (double));
-}
-
-bool Protocol_local::store(Field *field)
-{
-  if (field->is_null())
-    return store_null();
-  return field->send_binary(this);
-}
-
-bool Protocol_local::send_result_set_metadata(List<Item> *columns, uint)
-{
-  DBUG_ASSERT(m_result);
-
-  return m_result->add_result_set(columns);
-}
-
-bool Protocol_local::send_out_parameters(List<Item_param> *sp_params)
-{
-  return FALSE;
-}
-
-void Protocol_local::send_ok(uint server_status, uint statement_warn_count,
-                             ha_rows affected_rows, ulonglong last_insert_id,
-                             const char *message)
-{
-  m_result->send_ok(thd, server_status, statement_warn_count,
-                    affected_rows, last_insert_id, message);
-}
-
-void Protocol_local::send_eof(uint server_status, uint statement_warn_count)
-{
-  m_result->send_eof(thd, server_status, statement_warn_count);
-}
-
-void Protocol_local::send_error(uint sql_errno, const char *err_msg)
-{
-  m_result->send_error(thd, sql_errno, err_msg);
-}
-
-#ifdef EMBEDDED_LIBRARY
-void Protocol_local::remove_last_row()
-{ }
-#endif

=== modified file 'sql/protocol.h'
--- a/sql/protocol.h	2008-11-27 18:31:59 +0000
+++ b/sql/protocol.h	2008-12-05 23:47:51 +0000
@@ -204,264 +204,3 @@ uchar *net_store_data(uchar *to,longlong
 
 ///////////////////////////////////////////////////////////////////////////
 
-/**
-  Protocol_local: a protocol to retrieve and store
-  a result set.
-*/
-
-class Ed_result;
-
-class Protocol_local :public Protocol
-{
-public:
-  inline Protocol_local(THD *thd, Ed_result *result)
-    :Protocol(thd), m_result(result)
-  {}
-
-public:
-  virtual void prepare_for_resend();
-  virtual bool write();
-  virtual bool store_null();
-  virtual bool store_tiny(longlong from);
-  virtual bool store_short(longlong from);
-  virtual bool store_long(longlong from);
-  virtual bool store_longlong(longlong from, bool unsigned_flag);
-  virtual bool store_decimal(const my_decimal *);
-  virtual bool store(const char *from, size_t length, CHARSET_INFO *cs);
-  virtual bool store(const char *from, size_t length,
-                     CHARSET_INFO *fromcs, CHARSET_INFO *tocs);
-  virtual bool store(MYSQL_TIME *time);
-  virtual bool store_date(MYSQL_TIME *time);
-  virtual bool store_time(MYSQL_TIME *time);
-  virtual bool store(float value, uint32 decimals, String *buffer);
-  virtual bool store(double value, uint32 decimals, String *buffer);
-  virtual bool store(Field *field);
-
-  virtual bool send_result_set_metadata(List<Item> *list, uint flags);
-  virtual bool send_out_parameters(List<Item_param> *sp_params);
-#ifdef EMBEDDED_LIBRARY
-  void remove_last_row();
-#endif
-  virtual enum enum_protocol_type type() { return PROTOCOL_LOCAL; };
-
-protected:
-  virtual void send_ok(uint server_status, uint statement_warn_count,
-                       ha_rows affected_rows, ulonglong last_insert_id,
-                       const char *message);
-
-  virtual void send_eof(uint server_status, uint statement_warn_count);
-
-  virtual void send_error(uint sql_errno, const char *err_msg);
-
-private:
-  bool store_string(const char *str, int length,
-                    CHARSET_INFO *src_cs, CHARSET_INFO *dst_cs);
-
-private:
-  Ed_result *m_result;
-};
-
-
-/**
-  Ed_column -- a class representing a column data in a row. Used with
-  Ed_row and Protocol_local.
-*/
-
-class Ed_column : public LEX_STRING, public Sql_alloc
-{
-public:
-  inline Ed_column()
-  {
-    str= NULL;
-    length= 0;
-  }
-
-  inline void set_data(MEM_ROOT *mem_root, const void *p_str, int p_length)
-  {
-    str= (char *) memdup_root(mem_root, p_str, p_length);
-    length= p_length;
-  }
-};
-
-///////////////////////////////////////////////////////////////////////////
-
-/**
-  Ed_result_set_metadata -- a class representing result set metadata. Used
-  with Ed_result_set and Protocol_local.
-*/
-
-class Ed_result_set_metadata : public Sql_alloc
-{
-public:
-  static Ed_result_set_metadata *create(MEM_ROOT *mem_root,
-                                        List<Item> *col_metadata);
-
-public:
-  inline int get_num_columns() const { return m_num_columns; }
-
-  inline const Send_field *get_column(int idx) const
-  { return &m_metadata[idx]; }
-
-private:
-  inline Ed_result_set_metadata() :
-    m_num_columns(0),
-    m_metadata(NULL)
-  { }
-
-private:
-  bool init(MEM_ROOT *mem_root, List<Item> *col_metadata);
-
-private:
-  int m_num_columns;
-  Send_field *m_metadata;
-};
-
-///////////////////////////////////////////////////////////////////////////
-
-/**
-  Ed_row -- a class representing a row in a result set. Used with
-  Ed_result_set and Protocol_local.
-*/
-class Ed_row : public Sql_alloc
-{
-public:
-  static Ed_row *create(MEM_ROOT *mem_root,
-                        const Ed_result_set_metadata *metadata);
-
-public:
-  bool add_null();
-  bool add_column(const void *data_ptr, int data_length);
-
-public:
-  inline const Ed_result_set_metadata *get_metadata() const
-  { return m_metadata; }
-
-  inline const Ed_column *get_column(int idx) const
-  { return &m_columns[idx]; }
-
-  inline const Ed_column &operator [](int idx) const
-  { return *get_column(idx); }
-
-  inline int get_current_column_index() const
-  { return m_current_column_index; }
-
-private:
-  inline Ed_row(MEM_ROOT *mem_root,
-                const Ed_result_set_metadata *metadata) :
-    m_mem_root(mem_root),
-    m_metadata(metadata),
-    m_current_column_index(0)
-  { }
-
-  bool init();
-
-private:
-  MEM_ROOT *m_mem_root;
-  const Ed_result_set_metadata *m_metadata;
-  Ed_column *m_columns;
-  int m_current_column_index;
-};
-
-///////////////////////////////////////////////////////////////////////////
-
-/**
-  Ed_result_set -- a class representing one result set. Used with Ed_result
-  and Protocol_local.
-*/
-class Ed_result_set : public Sql_alloc
-{
-public:
-  static Ed_result_set *create(MEM_ROOT *mem_root,
-                               List<Item> *col_metadata);
-
-private:
-  inline Ed_result_set(MEM_ROOT *mem_root) :
-    m_mem_root(mem_root),
-    m_metadata(NULL),
-    m_current_row(NULL)
-  { }
-
-private:
-  bool init(List<Item> *col_metadata);
-
-public:
-  inline const Ed_result_set_metadata *get_metadata() const
-  { return m_metadata; }
-
-  inline List<Ed_row> *data()
-  { return &m_data; }
-
-  inline Ed_row *get_cur_row()
-  { return m_current_row; }
-
-  Ed_row *add_row();
-
-private:
-  MEM_ROOT *m_mem_root;
-
-  Ed_result_set_metadata *m_metadata;
-  List<Ed_row> m_data;
-
-  Ed_row *m_current_row;
-};
-
-///////////////////////////////////////////////////////////////////////////
-
-/*
-  Ed_result -- a class representing results for an SQL statement execution.
-  Used with Protocol_local.
-*/
-class Ed_result : public List<Ed_result_set>
-{
-public:
-  Ed_result();
-  ~Ed_result();
-
-public:
-  inline Ed_result_set *get_cur_result_set()
-  { return m_current_result_set; }
-
-  bool add_result_set(List<Item> *col_metadata);
-
-public:
-  void send_ok(THD *thd, uint server_status, uint statement_warn_count,
-               ha_rows affected_rows, ulonglong last_insert_id,
-               const char *message);
-
-  void send_eof(THD *thd, uint server_status, uint statement_warn_count);
-
-  void send_error(THD *thd, uint sql_errno, const char *err_msg);
-
-  void begin_statement(THD *thd);
-  void end_statement(THD *thd);
-
-public:
-  inline uint get_status() const { return m_status; }
-  inline uint get_server_status() const { return m_server_status; }
-  inline ha_rows get_affected_rows() const { return m_affected_rows; }
-  inline ulonglong get_last_insert_id() const { return m_last_insert_id; }
-  inline uint get_sql_errno() const { return m_sql_errno; }
-  inline const char *get_message() const { return m_message; }
-
-  inline uint get_statement_warn_count() const
-  { return m_warning_info.statement_warn_count(); }
-
-  inline List<MYSQL_ERROR> &get_warnings()
-  { return m_warning_info.warn_list(); }
-
-private:
-  MEM_ROOT m_mem_root;
-  Ed_result_set *m_current_result_set;
-
-private:
-  uint m_status;
-  uint m_server_status;
-  ha_rows m_affected_rows;
-  ulonglong m_last_insert_id;
-  uint m_sql_errno;
-  char m_message[MYSQL_ERRMSG_SIZE];
-
-  Warning_info m_warning_info;
-  Warning_info *m_warning_info_saved;
-};
-

=== modified file 'sql/si_objects.cc'
--- a/sql/si_objects.cc	2008-12-04 23:14:30 +0000
+++ b/sql/si_objects.cc	2008-12-05 23:47:51 +0000
@@ -176,8 +176,8 @@ void Si_session_context::restore_si_ctx(
 */
 
 bool
-run_service_interface_sql(THD *thd, const LEX_STRING *query,
-                          Ed_result *ed_result)
+run_service_interface_sql(THD *thd, Ed_connection *ed_connection,
+                          const LEX_STRING *query)
 {
   Si_session_context session_context;
 
@@ -189,7 +189,7 @@ run_service_interface_sql(THD *thd, cons
   session_context.save_si_ctx(thd);
   session_context.reset_si_ctx(thd);
 
-  bool rc= mysql_execute_direct(thd, *query, ed_result);
+  bool rc= ed_connection->execute_direct(*query);
 
   session_context.restore_si_ctx(thd);
 
@@ -769,12 +769,12 @@ bool Abstract_obj::create(THD *thd)
   /* Run queries from the serialization image. */
   while ((sql_text= it++))
   {
-    Ed_result ed_result;
+    Ed_connection ed_connection(thd);
 
-    rc= mysql_execute_direct(thd, *sql_text, &ed_result);
+    rc= ed_connection.execute_direct(*sql_text);
 
     /* Push warnings on the THD error stack. */
-    copy_warnings(thd, &ed_result.get_warnings());
+    copy_warnings(thd, ed_connection.get_warn_list());
 
     if (rc)
       break;
@@ -804,6 +804,8 @@ bool Abstract_obj::drop(THD *thd)
 {
   String_stream s_stream;
   const LEX_STRING *sql_text;
+  Ed_connection ed_connection(thd);
+  bool rc;
 
   DBUG_ENTER("Abstract_obj::drop");
 
@@ -821,10 +823,8 @@ bool Abstract_obj::drop(THD *thd)
   /* Allow to execute DDL operations. */
   ::obs::ddl_blocker_exception_on(thd);
 
-  Ed_result ed_result;
-
   /* Execute DDL operation. */
-  bool rc= mysql_execute_direct(thd, *sql_text, &ed_result);
+  rc= ed_connection.execute_direct(*sql_text);
 
   /* Disable further DDL execution. */
   ::obs::ddl_blocker_exception_off(thd);
@@ -1281,27 +1281,25 @@ private:
 template <typename Iterator>
 Iterator *create_row_set_iterator(THD *thd, const LEX_STRING *query)
 {
-  Ed_result *ed_result= new Ed_result();
-
-  if (!ed_result)
-    return NULL;
+  Ed_connection ed_connection(thd);
+  Ed_result_set *ed_result_set;
+  Iterator *it;
 
-  if (run_service_interface_sql(thd, query, ed_result) ||
-      ed_result->get_warnings().elements > 0)
+  if (run_service_interface_sql(thd, &ed_connection, query) ||
+      ed_connection.get_warn_count())
   {
     /* There should be no warnings. */
-    delete ed_result;
     return NULL;
   }
 
-  /* The result must contain only one result-set. */
-  DBUG_ASSERT(ed_result->elements == 1);
+  DBUG_ASSERT(ed_connection.get_field_count());
 
-  Iterator *it= new Iterator(ed_result);
+  /* Use store_result to get ownership of result memory */
+  ed_result_set= ed_connection.store_result_set();
 
-  if (!it)
+  if (! (it= new Iterator(ed_result_set)))
   {
-    delete ed_result;
+    delete ed_result_set;
     return NULL;
   }
 
@@ -1322,14 +1320,14 @@ template <typename Obj_type>
 class Ed_result_set_iterator : public Obj_iterator
 {
 public:
-  inline Ed_result_set_iterator(Ed_result *ed_result);
+  inline Ed_result_set_iterator(Ed_result_set *ed_result_set);
   inline ~Ed_result_set_iterator();
 
 public:
   virtual Obj *next();
 
 private:
-  Ed_result *m_ed_result;
+  Ed_result_set *m_ed_result_set;
   List_iterator_fast<Ed_row> m_row_it;
 };
 
@@ -1338,9 +1336,9 @@ private:
 template <typename Obj_type>
 inline
 Ed_result_set_iterator<Obj_type>::
-Ed_result_set_iterator(Ed_result *ed_result)
-  : m_ed_result(ed_result),
-    m_row_it(*ed_result->get_cur_result_set()->data())
+Ed_result_set_iterator(Ed_result_set *ed_result_set)
+  : m_ed_result_set(ed_result_set),
+   m_row_it(*ed_result_set)
 { }
 
 ///////////////////////////////////////////////////////////////////////////
@@ -1349,7 +1347,7 @@ template <typename Obj_type>
 inline
 Ed_result_set_iterator<Obj_type>::~Ed_result_set_iterator()
 {
-  delete m_ed_result;
+  delete m_ed_result_set;
 }
 
 
@@ -1620,11 +1618,9 @@ bool View_base_obj_iterator::init(THD *t
 {
   Find_view_underlying_tables find_tables(this, &m_table_names,
                                           db_name, view_name);
-  Ed_result ed_result; /* Just to grab OK or ERROR */
-
-  /* The table list is filled with unique underlying table names. */
+  Ed_connection ed_connection(thd); /* Just to grab OK or ERROR */
 
-  return mysql_execute_direct(thd, &find_tables, &ed_result);
+  return ed_connection.execute_direct(&find_tables);
 }
 
 ///////////////////////////////////////////////////////////////////////////
@@ -1736,6 +1732,9 @@ create<View_base_view_iterator>(THD *thd
 
 bool Database_obj::do_serialize(THD *thd, Out_stream &out_stream)
 {
+  Ed_connection ed_connection(thd);
+  Ed_result_set *ed_result_set;
+
   DBUG_ENTER("Database_obj::do_serialize");
   DBUG_PRINT("Database_obj::do_serialize",
              ("name: %.*s", STR(*get_name())));
@@ -1750,15 +1749,13 @@ bool Database_obj::do_serialize(THD *thd
 
   /* Run 'SHOW CREATE' query. */
 
-  Ed_result ed_result;
-
   {
     String_stream s_stream;
     s_stream <<
       "SHOW CREATE DATABASE `" << get_name() << "`";
 
-    if (run_service_interface_sql(thd, s_stream.lex_string(), &ed_result) ||
-        ed_result.get_warnings().elements > 0)
+    if (run_service_interface_sql(thd, &ed_connection, s_stream.lex_string()) ||
+        ed_connection.get_warn_count())
     {
       /*
         There should be no warnings. A warning means that serialization has
@@ -1771,27 +1768,17 @@ bool Database_obj::do_serialize(THD *thd
   /* Check result. */
 
   /* The result must contain only one result-set... */
-  DBUG_ASSERT(ed_result.elements == 1);
-
-  Ed_result_set *ed_result_set= ed_result.get_cur_result_set();
+  DBUG_ASSERT(ed_connection.get_field_count());
 
-  /* ... which is not NULL. */
-  DBUG_ASSERT(ed_result_set);
+  ed_result_set= ed_connection.use_result_set();
 
-  if (ed_result_set->data()->elements == 0)
+  if (ed_result_set->size() != 1)
     DBUG_RETURN(TRUE);
 
-  /* There must be one row. */
-  DBUG_ASSERT(ed_result_set->data()->elements == 1);
-
-  List_iterator_fast<Ed_row> row_it(*ed_result_set->data());
+  List_iterator_fast<Ed_row> row_it(*ed_result_set);
   Ed_row *row= row_it++;
 
-  /* There must be two columns: database name and create statement. */
-  DBUG_ASSERT(row->get_metadata()->get_num_columns() == 2);
-
   /* Generate image. */
-
   out_stream << row->get_column(1);
 
   DBUG_RETURN(FALSE);
@@ -1824,19 +1811,20 @@ void Database_obj::build_drop_statement(
 
 bool Table_obj::do_serialize(THD *thd, Out_stream &out_stream)
 {
+  Ed_connection ed_connection(thd);
+  String_stream s_stream;
+  Ed_result_set *ed_result_set;
+
   DBUG_ENTER("Table_obj::do_serialize");
   DBUG_PRINT("Table_obj::do_serialize",
              ("name: %.*s.%.*s",
               STR(m_db_name), STR(m_id)));
 
-  Ed_result ed_result;
-  String_stream s_stream;
-
   s_stream <<
     "SHOW CREATE TABLE `" << &m_db_name << "`.`" << &m_id
<< "`";
 
-  if (run_service_interface_sql(thd, s_stream.lex_string(), &ed_result) ||
-      ed_result.get_warnings().elements > 0)
+  if (run_service_interface_sql(thd, &ed_connection, s_stream.lex_string()) ||
+      ed_connection.get_warn_count())
   {
     /*
       There should be no warnings. A warning means that serialization has
@@ -1847,25 +1835,16 @@ bool Table_obj::do_serialize(THD *thd, O
 
   /* Check result. */
 
-  /* The result must contain only one result-set... */
-  DBUG_ASSERT(ed_result.elements == 1);
-
-  Ed_result_set *ed_result_set= ed_result.get_cur_result_set();
+  ed_result_set= ed_connection.use_result_set();
 
-  /* ... which is not NULL. */
-  DBUG_ASSERT(ed_result_set);
-
-  if (ed_result_set->data()->elements == 0)
+  if (ed_result_set->size() != 1)
     DBUG_RETURN(TRUE);
 
-  /* There must be one row. */
-  DBUG_ASSERT(ed_result_set->data()->elements == 1);
-
-  List_iterator_fast<Ed_row> row_it(*ed_result_set->data());
+  List_iterator_fast<Ed_row> row_it(*ed_result_set);
   Ed_row *row= row_it++;
 
   /* There must be two columns: database name and create statement. */
-  DBUG_ASSERT(row->get_metadata()->get_num_columns() == 2);
+  DBUG_ASSERT(row->size() == 2);
 
   /* Generate serialization image. */
 
@@ -1891,15 +1870,16 @@ get_view_create_stmt(THD *thd,
                      LEX_STRING *connection_cl_name)
 {
   /* Get a create statement for a view. */
-  Ed_result ed_result;
+  Ed_connection ed_connection(thd);
+  Ed_result_set *ed_result_set;
   String_stream s_stream;
 
   s_stream <<
     "SHOW CREATE VIEW `" << view->get_db_name() << "`."
     "`" << view->get_name() << "`";
 
-  if (run_service_interface_sql(thd, s_stream.lex_string(), &ed_result) ||
-      ed_result.get_warnings().elements > 0)
+  if (run_service_interface_sql(thd, &ed_connection, s_stream.lex_string()) ||
+      ed_connection.get_warn_count())
   {
     /*
       There should be no warnings. A warning means that serialization has
@@ -1908,25 +1888,19 @@ get_view_create_stmt(THD *thd,
     return TRUE;
   }
 
-  /* The result must contain only one result-set... */
-  DBUG_ASSERT(ed_result.elements == 1);
 
-  Ed_result_set *ed_result_set= ed_result.get_cur_result_set();
+  /* The result must contain only one result-set... */
 
-  /* ... which is not NULL. */
-  DBUG_ASSERT(ed_result_set);
+  ed_result_set= ed_connection.use_result_set();
 
-  if (ed_result_set->data()->elements == 0)
+  if (ed_result_set->size() != 1)
     return TRUE;
 
-  /* There must be one row. */
-  DBUG_ASSERT(ed_result_set->data()->elements == 1);
-
-  List_iterator_fast<Ed_row> row_it(*ed_result_set->data());
+  List_iterator_fast<Ed_row> row_it(*ed_result_set);
   Ed_row *row= row_it++;
 
   /* There must be four columns. */
-  DBUG_ASSERT(row->get_metadata()->get_num_columns() == 4);
+  DBUG_ASSERT(row->size() == 4);
 
   const LEX_STRING *c1= row->get_column(1);
   const LEX_STRING *c2= row->get_column(2);
@@ -1999,6 +1973,10 @@ bool View_obj::do_serialize(THD *thd, Ou
 
 bool Stored_program_obj::do_serialize(THD *thd, Out_stream &out_stream)
 {
+  String_stream s_stream;
+  Ed_connection ed_connection(thd);
+  Ed_result_set *ed_result_set;
+
   DBUG_ENTER("Stored_program_obj::do_serialize");
   DBUG_PRINT("Stored_program_obj::do_serialize",
              ("name: %.*s.%.*s",
@@ -2006,15 +1984,12 @@ bool Stored_program_obj::do_serialize(TH
 
   DBUG_EXECUTE_IF("backup_fail_add_trigger", DBUG_RETURN(TRUE););
 
-  String_stream s_stream;
-  Ed_result ed_result;
-
   s_stream <<
     "SHOW CREATE " << get_type_name() <<
     " `" << &m_db_name << "`.`" << &m_id << "`";
 
-  if (run_service_interface_sql(thd, s_stream.lex_string(), &ed_result) ||
-      ed_result.get_warnings().elements > 0)
+  if (run_service_interface_sql(thd, &ed_connection, s_stream.lex_string()) ||
+      ed_connection.get_warn_count())
   {
     /*
       There should be no warnings. A warning means that serialization has
@@ -2023,21 +1998,12 @@ bool Stored_program_obj::do_serialize(TH
     DBUG_RETURN(TRUE);
   }
 
-  /* The result must contain only one result-set... */
-  DBUG_ASSERT(ed_result.elements == 1);
-
-  Ed_result_set *ed_result_set= ed_result.get_cur_result_set();
-
-  /* ... which is not NULL. */
-  DBUG_ASSERT(ed_result_set);
+  ed_result_set= ed_connection.use_result_set();
 
-  if (ed_result_set->data()->elements == 0)
+  if (ed_result_set->size() != 1)
     DBUG_RETURN(TRUE);
 
-  /* There must be one row. */
-  DBUG_ASSERT(ed_result_set->data()->elements == 1);
-
-  List_iterator_fast<Ed_row> row_it(*ed_result_set->data());
+  List_iterator_fast<Ed_row> row_it(*ed_result_set);
   Ed_row *row= row_it++;
 
   s_stream.reset();
@@ -2675,8 +2641,8 @@ bool check_db_existence(THD *thd, const 
 
   s_stream << "SHOW CREATE DATABASE `" << db_name << "`";
 
-  Ed_result ed_result;
-  rc= run_service_interface_sql(thd, s_stream.lex_string(), &ed_result);
+  Ed_connection ed_connection(thd);
+  rc= run_service_interface_sql(thd, &ed_connection, s_stream.lex_string());
 
   /* We're not interested in warnings/errors here. */
 
@@ -2691,7 +2657,8 @@ bool check_user_existence(THD *thd, cons
   return TRUE;
 #else
   Grant_obj *grant_obj= (Grant_obj *) obj;
-  Ed_result ed_result;
+  Ed_connection ed_connection(thd);
+  Ed_result_set *ed_result_set;
   String_stream s_stream;
 
   s_stream <<
@@ -2700,19 +2667,16 @@ bool check_user_existence(THD *thd, cons
     "WHERE grantee = \"" << grant_obj->get_user_name() << "\"";
 
 
-  if (run_service_interface_sql(thd, s_stream.lex_string(), &ed_result) ||
-      ed_result.get_warnings().elements > 0)
+  if (run_service_interface_sql(thd, &ed_connection, s_stream.lex_string()) ||
+      ed_connection.get_warn_count())
   {
     /* Should be no warnings. */
     return FALSE;
   }
 
-  Ed_result_set *ed_result_set= ed_result.get_cur_result_set();
+  ed_result_set= ed_connection.use_result_set();
 
-  if (!ed_result_set)
-    return FALSE;
-
-  return ed_result_set->data()->elements > 0;
+  return ed_result_set->size() > 0;
 #endif
 }
 
@@ -2734,8 +2698,9 @@ const String *grant_get_grant_info(const
 
 Obj *find_tablespace(THD *thd, const String *ts_name)
 {
-  Ed_result ed_result;
+  Ed_connection ed_connection(thd);
   String_stream s_stream;
+  Ed_result_set *ed_result_set;
 
   s_stream <<
     "SELECT t1.tablespace_comment, t2.file_name, t1.engine "
@@ -2745,25 +2710,22 @@ Obj *find_tablespace(THD *thd, const Str
     "t1.tablespace_name = '" << ts_name << "'";
 
 
-  if (run_service_interface_sql(thd, s_stream.lex_string(), &ed_result) ||
-      ed_result.get_warnings().elements > 0)
+  if (run_service_interface_sql(thd, &ed_connection, s_stream.lex_string()) ||
+      ed_connection.get_warn_count())
   {
     /* Should be no warnings. */
     return NULL;
   }
 
-  if (!ed_result.elements)
-    return NULL;
-
-  Ed_result_set *ed_result_set= ed_result.get_cur_result_set();
+  ed_result_set= ed_connection.use_result_set();
 
-  /* The result must contain only one result-set. */
-  DBUG_ASSERT(ed_result_set->data()->elements == 1);
+  DBUG_ASSERT(ed_result_set->size() == 1);
 
-  Ed_row *row= ed_result_set->get_cur_row();
+  List_iterator_fast<Ed_row> row_it(*ed_result_set);
+  Ed_row *row= row_it++;
 
   /* There must be 3 columns. */
-  DBUG_ASSERT(row->get_metadata()->get_num_columns() == 3);
+  DBUG_ASSERT(row->size() == 3);
 
   const LEX_STRING *comment= row->get_column(0);
   const LEX_STRING *data_file_name= row->get_column(1);
@@ -2771,6 +2733,7 @@ Obj *find_tablespace(THD *thd, const Str
 
   return new Tablespace_obj(ts_name->lex_string(),
                             *comment, *data_file_name, *engine);
+  return 0;
 }
 
 ///////////////////////////////////////////////////////////////////////////
@@ -2795,8 +2758,9 @@ Obj *find_tablespace_for_table(THD *thd,
                                const String *db_name,
                                const String *table_name)
 {
-  Ed_result ed_result;
+  Ed_connection ed_connection(thd);
   String_stream s_stream;
+  Ed_result_set *ed_result_set;
 
   s_stream <<
     "SELECT t1.tablespace_name, t1.engine, t1.tablespace_comment, t2.file_name "
@@ -2809,28 +2773,24 @@ Obj *find_tablespace_for_table(THD *thd,
     "t3.table_name = '" << table_name << "'";
 
 
-  if (run_service_interface_sql(thd, s_stream.lex_string(), &ed_result) ||
-      ed_result.get_warnings().elements > 0)
+  if (run_service_interface_sql(thd, &ed_connection, s_stream.lex_string()) ||
+      ed_connection.get_warn_count())
   {
     /* Should be no warnings. */
     return NULL;
   }
 
-  if (!ed_result.elements)
-    return NULL;
+  ed_result_set= ed_connection.use_result_set();
 
-  Ed_result_set *ed_result_set= ed_result.get_cur_result_set();
-
-  if (!ed_result_set->data()->elements)
+  /* The result must contain only one row. */
+  if (ed_result_set->size() != 1)
     return NULL;
 
-  /* The result must contain only one result-set. */
-  DBUG_ASSERT(ed_result_set->data()->elements == 1);
-
-  Ed_row *row= ed_result_set->get_cur_row();
+  List_iterator_fast<Ed_row> row_it(*ed_result_set);
+  Ed_row *row= row_it++;
 
   /* There must be 4 columns. */
-  DBUG_ASSERT(row->get_metadata()->get_num_columns() == 4);
+  DBUG_ASSERT(row->size() == 4);
 
   const LEX_STRING *ts_name= row->get_column(0);
   const LEX_STRING *engine= row->get_column(1);

=== modified file 'sql/sql_class.cc'
--- a/sql/sql_class.cc	2008-12-04 16:50:07 +0000
+++ b/sql/sql_class.cc	2008-12-05 23:47:51 +0000
@@ -376,142 +376,6 @@ char *thd_security_context(THD *thd, cha
   return thd->strmake(str.ptr(), str.length());
 }
 
-/**
-  Clear this diagnostics area. 
-
-  Normally called at the end of a statement.
-*/
-
-void
-Diagnostics_area::reset_diagnostics_area()
-{
-  DBUG_ENTER("reset_diagnostics_area");
-#ifdef DBUG_OFF
-  can_overwrite_status= FALSE;
-  /** Don't take chances in production */
-  m_message[0]= '\0';
-  m_sql_errno= 0;
-  m_server_status= 0;
-  m_affected_rows= 0;
-  m_last_insert_id= 0;
-  m_statement_warn_count= 0;
-#endif
-  is_sent= FALSE;
-  /** Tiny reset in debug mode to see garbage right away */
-  m_status= DA_EMPTY;
-  DBUG_VOID_RETURN;
-}
-
-
-/**
-  Set OK status -- ends commands that do not return a
-  result set, e.g. INSERT/UPDATE/DELETE.
-*/
-
-void
-Diagnostics_area::set_ok_status(THD *thd, ha_rows affected_rows_arg,
-                                ulonglong last_insert_id_arg,
-                                const char *message_arg)
-{
-  DBUG_ENTER("set_ok_status");
-  DBUG_ASSERT(! is_set());
-  /*
-    In production, refuse to overwrite an error or a custom response
-    with an OK packet.
-  */
-  if (is_error() || is_disabled())
-    return;
-
-  m_server_status= thd->server_status;
-  m_statement_warn_count= thd->warning_info->statement_warn_count();
-  m_affected_rows= affected_rows_arg;
-  m_last_insert_id= last_insert_id_arg;
-  if (message_arg)
-    strmake(m_message, message_arg, sizeof(m_message) - 1);
-  else
-    m_message[0]= '\0';
-  m_status= DA_OK;
-  DBUG_VOID_RETURN;
-}
-
-
-/**
-  Set EOF status.
-*/
-
-void
-Diagnostics_area::set_eof_status(THD *thd)
-{
-  DBUG_ENTER("set_eof_status");
-  /* Only allowed to report eof if has not yet reported an error */
-  DBUG_ASSERT(! is_set());
-  /*
-    In production, refuse to overwrite an error or a custom response
-    with an EOF packet.
-  */
-  if (is_error() || is_disabled())
-    return;
-
-  m_server_status= thd->server_status;
-  /*
-    If inside a stored procedure, do not return the total
-    number of warnings, since they are not available to the client
-    anyway.
-  */
-  m_statement_warn_count= (thd->spcont ?
-                           0 : thd->warning_info->statement_warn_count());
-
-  m_status= DA_EOF;
-  DBUG_VOID_RETURN;
-}
-
-/**
-  Set ERROR status.
-*/
-
-void
-Diagnostics_area::set_error_status(THD *thd, uint sql_errno_arg,
-                                   const char *message_arg)
-{
-  DBUG_ENTER("set_error_status");
-  /*
-    Only allowed to report error if has not yet reported a success
-    The only exception is when we flush the message to the client,
-    an error can happen during the flush.
-  */
-  DBUG_ASSERT(! is_set() || can_overwrite_status);
-#ifdef DBUG_OFF
-  /*
-    In production, refuse to overwrite a custom response with an
-    ERROR packet.
-  */
-  if (is_disabled())
-    return;
-#endif
-
-  m_sql_errno= sql_errno_arg;
-  strmake(m_message, message_arg, sizeof(m_message)-1);
-
-  m_status= DA_ERROR;
-  DBUG_VOID_RETURN;
-}
-
-
-/**
-  Mark the diagnostics area as 'DISABLED'.
-
-  This is used in rare cases when the COM_ command at hand sends a response
-  in a custom format. One example is the query cache, another is
-  COM_STMT_PREPARE.
-*/
-
-void
-Diagnostics_area::disable_status()
-{
-  DBUG_ASSERT(! is_set());
-  m_status= DA_DISABLED;
-}
-
 
 THD::THD()
    :Statement(&main_lex, &main_mem_root, CONVENTIONAL_EXECUTION,

=== modified file 'sql/sql_class.h'
--- a/sql/sql_class.h	2008-12-04 16:50:07 +0000
+++ b/sql/sql_class.h	2008-12-05 23:47:51 +0000
@@ -1097,128 +1097,6 @@ public:
                             const char *message) = 0;
 };
 
-
-/**
-  Stores status of the currently executed statement.
-  Cleared at the beginning of the statement, and then
-  can hold either OK, ERROR, or EOF status.
-  Can not be assigned twice per statement.
-*/
-
-class Diagnostics_area
-{
-public:
-  enum enum_diagnostics_status
-  {
-    /** The area is cleared at start of a statement. */
-    DA_EMPTY= 0,
-    /** Set whenever one calls my_ok(). */
-    DA_OK,
-    /** Set whenever one calls my_eof(). */
-    DA_EOF,
-    /** Set whenever one calls my_error() or my_message(). */
-    DA_ERROR,
-    /** Set in case of a custom response, such as one from COM_STMT_PREPARE. */
-    DA_DISABLED
-  };
-  /** True if status information is sent to the client. */
-  bool is_sent;
-  /** Set to make set_error_status after set_{ok,eof}_status possible. */
-  bool can_overwrite_status;
-
-  void set_ok_status(THD *thd, ha_rows affected_rows_arg,
-                     ulonglong last_insert_id_arg,
-                     const char *message);
-  void set_eof_status(THD *thd);
-  void set_error_status(THD *thd, uint sql_errno_arg, const char *message_arg);
-
-  void disable_status();
-
-  void reset_diagnostics_area();
-
-  bool is_set() const { return m_status != DA_EMPTY; }
-  bool is_error() const { return m_status == DA_ERROR; }
-  bool is_eof() const { return m_status == DA_EOF; }
-  bool is_ok() const { return m_status == DA_OK; }
-  bool is_disabled() const { return m_status == DA_DISABLED; }
-  enum_diagnostics_status status() const { return m_status; }
-
-  const char *message() const
-  { DBUG_ASSERT(m_status == DA_ERROR || m_status == DA_OK); return m_message; }
-
-  uint sql_errno() const
-  { DBUG_ASSERT(m_status == DA_ERROR); return m_sql_errno; }
-
-  uint server_status() const
-  {
-    DBUG_ASSERT(m_status == DA_OK || m_status == DA_EOF);
-    return m_server_status;
-  }
-
-  ha_rows affected_rows() const
-  { DBUG_ASSERT(m_status == DA_OK); return m_affected_rows; }
-
-  ulonglong last_insert_id() const
-  { DBUG_ASSERT(m_status == DA_OK); return m_last_insert_id; }
-
-  uint statement_warn_count() const
-  {
-    DBUG_ASSERT(m_status == DA_OK || m_status == DA_EOF);
-    return m_statement_warn_count;
-  }
-
-  Diagnostics_area() { reset_diagnostics_area(); }
-
-private:
-  /** Message buffer. Can be used by OK or ERROR status. */
-  char m_message[MYSQL_ERRMSG_SIZE];
-  /**
-    SQL error number. One of ER_ codes from share/errmsg.txt.
-    Set by set_error_status.
-  */
-  uint m_sql_errno;
-
-  /**
-    Copied from thd->server_status when the diagnostics area is assigned.
-    We need this member as some places in the code use the following pattern:
-    thd->server_status|= ...
-    my_eof(thd);
-    thd->server_status&= ~...
-    Assigned by OK, EOF or ERROR.
-  */
-  uint m_server_status;
-  /**
-    The number of rows affected by the last statement. This is
-    semantically close to thd->row_count_func, but has a different
-    life cycle. thd->row_count_func stores the value returned by
-    function ROW_COUNT() and is cleared only by statements that
-    update its value, such as INSERT, UPDATE, DELETE and few others.
-    This member is cleared at the beginning of the next statement.
-
-    We could possibly merge the two, but life cycle of thd->row_count_func
-    can not be changed.
-  */
-  ha_rows    m_affected_rows;
-  /**
-    Similarly to the previous member, this is a replacement of
-    thd->first_successful_insert_id_in_prev_stmt, which is used
-    to implement LAST_INSERT_ID().
-  */
-  ulonglong   m_last_insert_id;
-  /**
-    Number of warnings of this last statement. May differ from
-    the number of warnings returned by SHOW WARNINGS e.g. in case
-    the statement doesn't clear the warnings, and doesn't generate
-    them.
-  */
-  uint	     m_statement_warn_count;
-  enum_diagnostics_status m_status;
-  /**
-    @todo: the following THD members belong here:
-    - warn_list, warn_count,
-  */
-};
-
 /**
   Tables that were locked with LOCK TABLES statement.
 

=== modified file 'sql/sql_error.cc'
--- a/sql/sql_error.cc	2008-11-18 22:30:59 +0000
+++ b/sql/sql_error.cc	2008-12-05 23:47:51 +0000
@@ -45,6 +45,143 @@ This file contains the implementation of
 #include "mysql_priv.h"
 #include "sp_rcontext.h"
 
+/**
+  Clear this diagnostics area.
+
+  Normally called at the end of a statement.
+*/
+
+void
+Diagnostics_area::reset_diagnostics_area()
+{
+  DBUG_ENTER("reset_diagnostics_area");
+#ifdef DBUG_OFF
+  can_overwrite_status= FALSE;
+  /** Don't take chances in production */
+  m_message[0]= '\0';
+  m_sql_errno= 0;
+  m_server_status= 0;
+  m_affected_rows= 0;
+  m_last_insert_id= 0;
+  m_statement_warn_count= 0;
+#endif
+  is_sent= FALSE;
+  /** Tiny reset in debug mode to see garbage right away */
+  m_status= DA_EMPTY;
+  DBUG_VOID_RETURN;
+}
+
+
+/**
+  Set OK status -- ends commands that do not return a
+  result set, e.g. INSERT/UPDATE/DELETE.
+*/
+
+void
+Diagnostics_area::set_ok_status(THD *thd, ha_rows affected_rows_arg,
+                                ulonglong last_insert_id_arg,
+                                const char *message_arg)
+{
+  DBUG_ENTER("set_ok_status");
+  DBUG_ASSERT(! is_set());
+  /*
+    In production, refuse to overwrite an error or a custom response
+    with an OK packet.
+  */
+  if (is_error() || is_disabled())
+    return;
+
+  m_server_status= thd->server_status;
+  m_statement_warn_count= thd->warning_info->statement_warn_count();
+  m_affected_rows= affected_rows_arg;
+  m_last_insert_id= last_insert_id_arg;
+  if (message_arg)
+    strmake(m_message, message_arg, sizeof(m_message) - 1);
+  else
+    m_message[0]= '\0';
+  m_status= DA_OK;
+  DBUG_VOID_RETURN;
+}
+
+
+/**
+  Set EOF status.
+*/
+
+void
+Diagnostics_area::set_eof_status(THD *thd)
+{
+  DBUG_ENTER("set_eof_status");
+  /* Only allowed to report eof if has not yet reported an error */
+  DBUG_ASSERT(! is_set());
+  /*
+    In production, refuse to overwrite an error or a custom response
+    with an EOF packet.
+  */
+  if (is_error() || is_disabled())
+    return;
+
+  m_server_status= thd->server_status;
+  /*
+    If inside a stored procedure, do not return the total
+    number of warnings, since they are not available to the client
+    anyway.
+  */
+  m_statement_warn_count= (thd->spcont ?
+                           0 : thd->warning_info->statement_warn_count());
+
+  m_status= DA_EOF;
+  DBUG_VOID_RETURN;
+}
+
+/**
+  Set ERROR status.
+*/
+
+void
+Diagnostics_area::set_error_status(THD *thd, uint sql_errno_arg,
+                                   const char *message_arg)
+{
+  DBUG_ENTER("set_error_status");
+  /*
+    Only allowed to report error if has not yet reported a success
+    The only exception is when we flush the message to the client,
+    an error can happen during the flush.
+  */
+  DBUG_ASSERT(! is_set() || can_overwrite_status);
+#ifdef DBUG_OFF
+  /*
+    In production, refuse to overwrite a custom response with an
+    ERROR packet.
+  */
+  if (is_disabled())
+    return;
+#endif
+
+  m_sql_errno= sql_errno_arg;
+  strmake(m_message, message_arg, sizeof(m_message)-1);
+
+  m_status= DA_ERROR;
+  DBUG_VOID_RETURN;
+}
+
+
+/**
+  Mark the diagnostics area as 'DISABLED'.
+
+  This is used in rare cases when the COM_ command at hand sends a response
+  in a custom format. One example is the query cache, another is
+  COM_STMT_PREPARE.
+*/
+
+void
+Diagnostics_area::disable_status()
+{
+  DBUG_ASSERT(! is_set());
+  m_status= DA_DISABLED;
+}
+
+
 /* Store a new message in an error object. */
 
 void MYSQL_ERROR::set_msg(MEM_ROOT *warn_root, const char *msg_arg)

=== modified file 'sql/sql_error.h'
--- a/sql/sql_error.h	2008-11-19 19:20:47 +0000
+++ b/sql/sql_error.h	2008-12-05 23:47:51 +0000
@@ -18,9 +18,130 @@
 
 #include "sql_list.h" /* Sql_alloc, MEM_ROOT */
 #include "m_string.h" /* LEX_STRING */
+#include "mysql_com.h" /* MYSQL_ERRMSG_SIZE */
 
 class THD;
 
+/**
+  Stores status of the currently executed statement.
+  Cleared at the beginning of the statement, and then
+  can hold either OK, ERROR, or EOF status.
+  Can not be assigned twice per statement.
+*/
+
+class Diagnostics_area
+{
+public:
+  enum enum_diagnostics_status
+  {
+    /** The area is cleared at start of a statement. */
+    DA_EMPTY= 0,
+    /** Set whenever one calls my_ok(). */
+    DA_OK,
+    /** Set whenever one calls my_eof(). */
+    DA_EOF,
+    /** Set whenever one calls my_error() or my_message(). */
+    DA_ERROR,
+    /** Set in case of a custom response, such as one from COM_STMT_PREPARE. */
+    DA_DISABLED
+  };
+  /** True if status information is sent to the client. */
+  bool is_sent;
+  /** Set to make set_error_status after set_{ok,eof}_status possible. */
+  bool can_overwrite_status;
+
+  void set_ok_status(THD *thd, ulonglong affected_rows_arg,
+                     ulonglong last_insert_id_arg,
+                     const char *message);
+  void set_eof_status(THD *thd);
+  void set_error_status(THD *thd, uint sql_errno_arg, const char *message_arg);
+
+  void disable_status();
+
+  void reset_diagnostics_area();
+
+  bool is_set() const { return m_status != DA_EMPTY; }
+  bool is_error() const { return m_status == DA_ERROR; }
+  bool is_eof() const { return m_status == DA_EOF; }
+  bool is_ok() const { return m_status == DA_OK; }
+  bool is_disabled() const { return m_status == DA_DISABLED; }
+  enum_diagnostics_status status() const { return m_status; }
+
+  const char *message() const
+  { DBUG_ASSERT(m_status == DA_ERROR || m_status == DA_OK); return m_message; }
+
+  uint sql_errno() const
+  { DBUG_ASSERT(m_status == DA_ERROR); return m_sql_errno; }
+
+  uint server_status() const
+  {
+    DBUG_ASSERT(m_status == DA_OK || m_status == DA_EOF);
+    return m_server_status;
+  }
+
+  ulonglong affected_rows() const
+  { DBUG_ASSERT(m_status == DA_OK); return m_affected_rows; }
+
+  ulonglong last_insert_id() const
+  { DBUG_ASSERT(m_status == DA_OK); return m_last_insert_id; }
+
+  uint statement_warn_count() const
+  {
+    DBUG_ASSERT(m_status == DA_OK || m_status == DA_EOF);
+    return m_statement_warn_count;
+  }
+
+  Diagnostics_area() { reset_diagnostics_area(); }
+
+private:
+  /** Message buffer. Can be used by OK or ERROR status. */
+  char m_message[MYSQL_ERRMSG_SIZE];
+  /**
+    SQL error number. One of ER_ codes from share/errmsg.txt.
+    Set by set_error_status.
+  */
+  uint m_sql_errno;
+
+  /**
+    Copied from thd->server_status when the diagnostics area is assigned.
+    We need this member as some places in the code use the following pattern:
+    thd->server_status|= ...
+    my_eof(thd);
+    thd->server_status&= ~...
+    Assigned by OK, EOF or ERROR.
+  */
+  uint m_server_status;
+  /**
+    The number of rows affected by the last statement. This is
+    semantically close to thd->row_count_func, but has a different
+    life cycle. thd->row_count_func stores the value returned by
+    function ROW_COUNT() and is cleared only by statements that
+    update its value, such as INSERT, UPDATE, DELETE and few others.
+    This member is cleared at the beginning of the next statement.
+
+    We could possibly merge the two, but life cycle of thd->row_count_func
+    can not be changed.
+  */
+  ulonglong    m_affected_rows;
+  /**
+    Similarly to the previous member, this is a replacement of
+    thd->first_successful_insert_id_in_prev_stmt, which is used
+    to implement LAST_INSERT_ID().
+  */
+  ulonglong   m_last_insert_id;
+  /**
+    Number of warnings of this last statement. May differ from
+    the number of warnings returned by SHOW WARNINGS e.g. in case
+    the statement doesn't clear the warnings, and doesn't generate
+    them.
+  */
+  uint	     m_statement_warn_count;
+  enum_diagnostics_status m_status;
+  /**
+    @todo: the following THD members belong here:
+    - warn_list, warn_count,
+  */
+};
 ///////////////////////////////////////////////////////////////////////////
 
 class MYSQL_ERROR: public Sql_alloc

=== modified file 'sql/sql_prepare.cc'
--- a/sql/sql_prepare.cc	2008-12-04 16:50:07 +0000
+++ b/sql/sql_prepare.cc	2008-12-05 23:47:51 +0000
@@ -197,6 +197,66 @@ private:
   LEX_STRING m_sql_text;
 };
 
+
+class Ed_connection;
+
+/**
+  Protocol_local: a helper class to intercept the result
+  of the data written to the network. 
+*/
+
+class Protocol_local :public Protocol
+{
+public:
+  Protocol_local(THD *thd, Ed_connection *ed_connection);
+  ~Protocol_local() { free_root(&m_rset_root, MYF(0)); }
+protected:
+  virtual void prepare_for_resend();
+  virtual bool write();
+  virtual bool store_null();
+  virtual bool store_tiny(longlong from);
+  virtual bool store_short(longlong from);
+  virtual bool store_long(longlong from);
+  virtual bool store_longlong(longlong from, bool unsigned_flag);
+  virtual bool store_decimal(const my_decimal *);
+  virtual bool store(const char *from, size_t length, CHARSET_INFO *cs);
+  virtual bool store(const char *from, size_t length,
+                     CHARSET_INFO *fromcs, CHARSET_INFO *tocs);
+  virtual bool store(MYSQL_TIME *time);
+  virtual bool store_date(MYSQL_TIME *time);
+  virtual bool store_time(MYSQL_TIME *time);
+  virtual bool store(float value, uint32 decimals, String *buffer);
+  virtual bool store(double value, uint32 decimals, String *buffer);
+  virtual bool store(Field *field);
+
+  virtual bool send_result_set_metadata(List<Item> *list, uint flags);
+  virtual bool send_out_parameters(List<Item_param> *sp_params);
+#ifdef EMBEDDED_LIBRARY
+  void remove_last_row();
+#endif
+  virtual enum enum_protocol_type type() { return PROTOCOL_LOCAL; };
+
+  virtual void send_ok(uint server_status, uint statement_warn_count,
+                       ha_rows affected_rows, ulonglong last_insert_id,
+                       const char *message);
+
+  virtual void send_eof(uint server_status, uint statement_warn_count);
+  virtual void send_error(uint sql_errno, const char *err_msg);
+private:
+  bool store_string(const char *str, size_t length,
+                    CHARSET_INFO *src_cs, CHARSET_INFO *dst_cs);
+
+  bool store_column(const void *data, size_t length);
+  void opt_add_row_to_rset();
+private:
+  Ed_connection *m_connection;
+  MEM_ROOT m_rset_root;
+  List<Ed_row> *m_rset;
+  size_t m_column_count;
+  Ed_column *m_current_row;
+  Ed_column *m_current_column;
+};
+
 /******************************************************************************
   Implementation
 ******************************************************************************/
@@ -2777,54 +2837,6 @@ void mysql_stmt_get_longdata(THD *thd, c
 }
 
 
-bool
-mysql_execute_direct(THD *thd, LEX_STRING query, Ed_result *ed_result)
-{
-  Execute_sql_statement execute_sql_statement(query);
-
-  return mysql_execute_direct(thd, &execute_sql_statement, ed_result);
-}
-
-
-/**
-  Execute a fragment of server functionality without an effect on
-  thd, and store results in Ed_result.
-
-  @param thd         Thread handle.
-  @param server_runnable A code fragment to execute.
-  @param ed_result   Result interceptor
-*/
-
-bool
-mysql_execute_direct(THD *thd, Server_runnable *server_runnable,
-                     Ed_result *ed_result)
-{
-  Protocol_local protocol_local(thd, ed_result);
-  Prepared_statement stmt(thd);
-
-  DBUG_ENTER("mysql_execute_direct");
-
-  DBUG_ASSERT(ed_result);
-
-  Protocol *protocol_saved= thd->protocol;
-
-  thd->protocol= &protocol_local;
-
-  ed_result->begin_statement(thd);
-  bool rc= stmt.execute_server_runnable(server_runnable);
-  ed_result->end_statement(thd);
-
-  thd->protocol->end_statement();
-
-  thd->protocol= protocol_saved;
-
-  thd->stmt_da->reset_diagnostics_area();
-
-  DBUG_RETURN(rc);
-}
-
-
-
 /***************************************************************************
  Select_fetch_protocol_binary
 ****************************************************************************/
@@ -3811,3 +3823,569 @@ void Prepared_statement::deallocate()
   /* Statement map calls delete stmt on erase */
   thd->stmt_map.erase(this);
 }
+
+
+/***************************************************************************
+* Ed_result_set
+***************************************************************************/
+/**
+  Use operator delete to free memory of Ed_result_set.
+  Accessing members of a class after the class has been destroyed
+  is a violation of the C++ standard but is commonly used in the
+  server code.
+*/
+
+void Ed_result_set::operator delete(void *ptr, size_t size) throw ()
+{
+  if (ptr)
+  {
+    /*
+      Make a stack copy, otherwise free_root() will attempt to
+      write to freed memory.
+    */
+    MEM_ROOT own_root= ((Ed_result_set*) ptr)->m_mem_root;
+    free_root(&own_root, MYF(0));
+  }
+}
+
+
+/**
+  Initialize an instance of Ed_result_set.
+
+  Instances of the class, as well as all result set rows, are
+  always allocated in the memory root passed over as the second
+  argument. In the constructor, we take over ownership of the
+  memory root. It will be freed when the class is destroyed.
+
+  sic: Ed_result_est is not designed to be allocated on stack.
+*/
+
+Ed_result_set::Ed_result_set(List<Ed_row> *rows_arg,
+                             size_t column_count_arg,
+                             MEM_ROOT *mem_root_arg)
+  :m_mem_root(*mem_root_arg),
+  m_column_count(column_count_arg),
+  m_rows(rows_arg),
+  m_next_rset(NULL)
+{
+  /* Take over responsibility for the memory */
+  clear_alloc_root(mem_root_arg);
+}
+
+/***************************************************************************
+* Ed_result_set
+***************************************************************************/
+
+/**
+  Create a new "execute direct" connection.
+*/
+
+Ed_connection::Ed_connection(THD *thd)
+  :m_warning_info(thd->query_id),
+  m_thd(thd),
+  m_rsets(0),
+  m_current_rset(0)
+{
+}
+
+
+/**
+  Free all result sets of the previous statement, if any,
+  and reset warnings and errors.
+
+  Called before execution of the next query.
+*/
+
+void
+Ed_connection::free_old_result()
+{
+  while (m_rsets)
+  {
+    Ed_result_set *rset= m_rsets->m_next_rset;
+    delete m_rsets;
+    m_rsets= rset;
+  }
+  m_current_rset= m_rsets;
+  m_diagnostics_area.reset_diagnostics_area();
+  m_warning_info.clear_warning_info(m_thd->query_id);
+}
+
+
+/**
+  A simple wrapper that uses a helper class to execute SQL statements.
+*/
+
+bool
+Ed_connection::execute_direct(LEX_STRING sql_text)
+{
+  Execute_sql_statement execute_sql_statement(sql_text);
+
+  return execute_direct(&execute_sql_statement);
+}
+
+
+/**
+  Execute a fragment of server functionality without an effect on
+  thd, and store results in memory.
+
+  Conventions:
+  - the code fragment must finish with OK, EOF or ERROR.
+  - the code fragment doesn't have to close thread tables,
+  free memory, commit statement transaction or do any other
+  cleanup that is normally done in the end of dispatch_command().
+
+  @param server_runnable A code fragment to execute.
+*/
+
+bool Ed_connection::execute_direct(Server_runnable *server_runnable)
+{
+  bool rc= FALSE;
+  Protocol_local protocol_local(m_thd, this);
+  Prepared_statement stmt(m_thd);
+  Protocol *save_protocol= m_thd->protocol;
+  Diagnostics_area *save_diagnostics_area= m_thd->stmt_da;
+  Warning_info *save_warning_info= m_thd->warning_info;
+
+  DBUG_ENTER("Ed_connection::execute_direct");
+
+  free_old_result(); /* Delete all data from previous execution, if any */
+
+  m_thd->protocol= &protocol_local;
+  m_thd->stmt_da= &m_diagnostics_area;
+  m_thd->warning_info= &m_warning_info;
+
+  rc= stmt.execute_server_runnable(server_runnable);
+  m_thd->protocol->end_statement();
+
+  m_thd->protocol= save_protocol;
+  m_thd->stmt_da= save_diagnostics_area;
+  m_thd->warning_info= save_warning_info;
+  /*
+    Protocol_local makes use of m_current_rset to keep
+    track of the last result set, while adding result sets to the end.
+    Reset it to point to the first result set instead.
+  */
+  m_current_rset= m_rsets;
+
+  DBUG_RETURN(rc);
+}
+
+
+/**
+  A helper method that is called only during execution.
+
+  Although Ed_connection doesn't support multi-statements,
+  a statement may generate many result sets. All subsequent
+  result sets are appended to the end.
+
+  @pre This is called only by Protocol_local.
+*/
+
+void
+Ed_connection::add_result_set(Ed_result_set *ed_result_set)
+{
+  if (m_rsets)
+  {
+    m_current_rset->m_next_rset= ed_result_set;
+    /* While appending, use m_current_rset as a pointer to the tail. */
+    m_current_rset= ed_result_set;
+  }
+  else
+    m_current_rset= m_rsets= ed_result_set;
+}
+
+
+/**
+  Release ownership of the current result set to the client.
+
+  Since we use a simple linked list for result sets,
+  this method uses a linear search of the previous result
+  set to exclude the released instance from the list.
+
+  @todo Use double-linked list, when this is really used.
+
+  XXX: This has never been tested with more than one result set!
+
+  @pre There must be a result set.
+*/
+
+Ed_result_set *
+Ed_connection::store_result_set()
+{
+  Ed_result_set *ed_result_set;
+
+  DBUG_ASSERT(m_current_rset);
+
+  if (m_current_rset == m_rsets)
+  {
+    /* Assign the return value */
+    ed_result_set= m_current_rset;
+    /* Exclude the return value from the list. */
+    m_current_rset= m_rsets= m_rsets->m_next_rset;
+  }
+  else
+  {
+    Ed_result_set *prev_rset= m_rsets;
+    /* Assign the return value. */
+    ed_result_set= m_current_rset;
+
+    /* Exclude the return value from the list */
+    while (prev_rset->m_next_rset != m_current_rset)
+      prev_rset= ed_result_set->m_next_rset;
+    m_current_rset= prev_rset->m_next_rset= m_current_rset->m_next_rset;
+  }
+  ed_result_set->m_next_rset= NULL; /* safety */
+
+  return ed_result_set;
+}
+
+/*************************************************************************
+* Protocol_local
+**************************************************************************/
+
+Protocol_local::Protocol_local(THD *thd, Ed_connection *ed_connection)
+  :Protocol(thd),
+  m_connection(ed_connection),
+  m_rset(NULL),
+  m_column_count(0),
+  m_current_row(NULL),
+  m_current_column(NULL)
+{
+  clear_alloc_root(&m_rset_root);
+}
+
+/**
+  Called between two result set rows.
+
+  Prepare structures to fill result set rows.
+  Unfortunately, we can't return an error here. If memory allocation
+  fails, we'll have to return an error later. And so is done
+  in methods such as @sa store_column().
+*/
+
+void Protocol_local::prepare_for_resend()
+{
+  DBUG_ASSERT(alloc_root_inited(&m_rset_root));
+
+  opt_add_row_to_rset();
+  /* Start a new row. */
+  m_current_row= (Ed_column *) alloc_root(&m_rset_root,
+                                          sizeof(Ed_column) * m_column_count);
+  m_current_column= m_current_row;
+}
+
+
+/**
+  In "real" protocols this is called to finish a result set row.
+  Unused in the local implementation.
+*/
+
+bool Protocol_local::write()
+{
+  return FALSE;
+}
+
+/**
+  A helper function to add the current row to the current result
+  set. Called in @sa prepare_for_resend(), when a new row is started,
+  and in send_eof(), when the result set is finished.
+*/
+
+void Protocol_local::opt_add_row_to_rset()
+{
+  if (m_current_row)
+  {
+    /* Add the old row to the result set */
+    Ed_row *ed_row= new (&m_rset_root) Ed_row(m_current_row, m_column_count);
+    if (ed_row)
+      m_rset->push_back(ed_row, &m_rset_root);
+  }
+}
+
+
+/**
+  Add a NULL column to the current row.
+*/
+
+bool Protocol_local::store_null()
+{
+  if (m_current_column == NULL)
+    return TRUE; /* prepare_for_resend() failed to allocate memory. */
+
+  bzero(m_current_column, sizeof(*m_current_column));
+  ++m_current_column;
+  return FALSE;
+}
+
+
+/**
+  A helper method to add any column to the current row
+  in its binary form.
+
+  Allocates memory for the data in the result set memory root.
+*/
+
+bool Protocol_local::store_column(const void *data, size_t length)
+{
+  if (m_current_column == NULL)
+    return TRUE; /* prepare_for_resend() failed to allocate memory. */
+  /*
+    alloc_root() automatically aligns memory, so we don't need to
+    do any extra alignment if we're pointing to, say, an integer.
+  */
+  m_current_column->str= (char*) memdup_root(&m_rset_root,
+                                             data,
+                                             length + 1 /* Safety */);
+  if (! m_current_column->str)
+    return TRUE;
+  m_current_column->str[length]= '\0'; /* Safety */
+  m_current_column->length= length;
+  ++m_current_column;
+  return FALSE;
+}
+
+
+/**
+  Store a string value in a result set column, optionally
+  having converted it to character_set_results.
+*/
+
+bool
+Protocol_local::store_string(const char *str, size_t length,
+                             CHARSET_INFO *src_cs, CHARSET_INFO *dst_cs)
+{
+  /* Store with conversion */
+  uint error_unused;
+
+  if (dst_cs && !my_charset_same(src_cs, dst_cs) &&
+      src_cs != &my_charset_bin &&
+      dst_cs != &my_charset_bin)
+  {
+    if (convert->copy(str, length, src_cs, dst_cs, &error_unused))
+      return TRUE;
+    str= convert->ptr();
+    length= convert->length();
+  }
+  return store_column(str, length);
+}
+
+
+/** Store a tiny int as is (1 byte) in a result set column. */
+
+bool Protocol_local::store_tiny(longlong value)
+{
+  char v= (char) value;
+  return store_column(&v, 1);
+}
+
+
+/** Store a short as is (2 bytes, host order) in a result set column. */
+
+bool Protocol_local::store_short(longlong value)
+{
+  int16 v= (int16) value;
+  return store_column(&v, 2);
+}
+
+
+/** Store a "long" as is (4 bytes, host order) in a result set column.  */
+
+bool Protocol_local::store_long(longlong value)
+{
+  int32 v= (int32) value;
+  return store_column(&v, 4);
+}
+
+
+/** Store a "longlong" as is (8 bytes, host order) in a result set column. */
+
+bool Protocol_local::store_longlong(longlong value, bool unsigned_flag)
+{
+  int64 v= (int64) value;
+  return store_column(&v, 8);
+}
+
+
+/** Store a decimal in string format in a result set column */
+
+bool Protocol_local::store_decimal(const my_decimal *value)
+{
+  char buf[DECIMAL_MAX_STR_LENGTH];
+  String str(buf, sizeof (buf), &my_charset_bin);
+  int rc;
+
+  rc= my_decimal2string(E_DEC_FATAL_ERROR, value, 0, 0, 0, &str);
+
+  if (rc)
+    return TRUE;
+
+  return store_column(str.ptr(), str.length());
+}
+
+
+/** Convert to cs_results and store a string. */
+
+bool Protocol_local::store(const char *str, size_t length,
+                           CHARSET_INFO *src_cs)
+{
+  CHARSET_INFO *dst_cs;
+
+  dst_cs= m_connection->m_thd->variables.character_set_results;
+  return store_string(str, length, src_cs, dst_cs);
+}
+
+
+/** Store a string. */
+
+bool Protocol_local::store(const char *str, size_t length,
+                           CHARSET_INFO *src_cs, CHARSET_INFO *dst_cs)
+{
+  return store_string(str, length, src_cs, dst_cs);
+}
+
+
+/* Store MYSQL_TIME (in binary format) */
+
+bool Protocol_local::store(MYSQL_TIME *time)
+{
+  return store_column(time, sizeof(MYSQL_TIME));
+}
+
+
+/** Store MYSQL_TIME (in binary format) */
+
+bool Protocol_local::store_date(MYSQL_TIME *time)
+{
+  return store_column(time, sizeof(MYSQL_TIME));
+}
+
+
+/** Store MYSQL_TIME (in binary format) */
+
+bool Protocol_local::store_time(MYSQL_TIME *time)
+{
+  return store_column(time, sizeof(MYSQL_TIME));
+}
+
+
+/* Store a floating point number, as is. */
+
+bool Protocol_local::store(float value, uint32 decimals, String *buffer)
+{
+  return store_column(&value, sizeof(float));
+}
+
+
+/* Store a double precision number, as is. */
+
+bool Protocol_local::store(double value, uint32 decimals, String *buffer)
+{
+  return store_column(&value, sizeof (double));
+}
+
+
+/* Store a Field. */
+
+bool Protocol_local::store(Field *field)
+{
+  if (field->is_null())
+    return store_null();
+  return field->send_binary(this);
+}
+
+
+/** Called to start a new result set. */
+
+bool Protocol_local::send_result_set_metadata(List<Item> *columns, uint)
+{
+  DBUG_ASSERT(m_rset == 0 && !alloc_root_inited(&m_rset_root));
+
+  init_sql_alloc(&m_rset_root, MEM_ROOT_BLOCK_SIZE, 0);
+
+  if (! (m_rset= new (&m_rset_root) List<Ed_row>))
+    return TRUE;
+
+  m_column_count= columns->elements;
+
+  return FALSE;
+}
+
+
+/**
+  Normally this is a separate result set with OUT parameters
+  of stored procedures. Currently unsupported for the local
+  version.
+*/
+
+bool Protocol_local::send_out_parameters(List<Item_param> *sp_params)
+{
+  return FALSE;
+}
+
+
+/** Called for statements that don't have a result set, at statement end. */
+
+void
+Protocol_local::send_ok(uint server_status, uint statement_warn_count,
+                        ha_rows affected_rows, ulonglong last_insert_id,
+                        const char *message)
+{
+  /*
+    Just make sure nothing is sent to the client, we have grabbed
+    the status information in the connection diagnostics area.
+  */
+}
+
+
+/**
+  Called at the end of a result set. Append a complete
+  result set to the list in Ed_connection.
+
+  Don't send anything to the client, but instead finish
+  building of the result set at hand.
+*/
+
+void Protocol_local::send_eof(uint server_status, uint statement_warn_count)
+{
+  Ed_result_set *ed_result_set;
+
+  DBUG_ASSERT(m_rset);
+
+  opt_add_row_to_rset();
+  m_current_row= 0;
+
+  ed_result_set= new (&m_rset_root) Ed_result_set(m_rset, m_column_count,
+                                                  &m_rset_root);
+
+  m_rset= NULL;
+
+  if (! ed_result_set)
+    return;
+
+  /* In case of successful allocation memory ownership was transferred. */
+  DBUG_ASSERT(!alloc_root_inited(&m_rset_root));
+
+  /*
+    Link the created Ed_result_set instance into the list of connection
+    result sets. Never fails.
+  */
+  m_connection->add_result_set(ed_result_set);
+}
+
+
+/** Called to send an error to the client at the end of a statement. */
+
+void
+Protocol_local::send_error(uint sql_errno, const char *err_msg)
+{
+  /*
+    Just make sure that nothing is sent to the client (default
+    implementation).
+  */
+}
+
+
+#ifdef EMBEDDED_LIBRARY
+void Protocol_local::remove_last_row()
+{ }
+#endif

=== modified file 'sql/sql_prepare.h'
--- a/sql/sql_prepare.h	2008-12-04 20:02:32 +0000
+++ b/sql/sql_prepare.h	2008-12-05 23:47:51 +0000
@@ -15,12 +15,10 @@
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA */
 
-#include "my_global.h"
-#include "m_string.h"
+#include "sql_error.h"
 
 class THD;
 struct LEX;
-template <typename T> class List;
 
 /**
   An interface that is used to take an action when
@@ -92,12 +90,277 @@ public:
   virtual ~Server_runnable();
 };
 
-class Ed_result;
 
-bool
-mysql_execute_direct(THD *thd, LEX_STRING query, Ed_result *ed_result);
-bool
-mysql_execute_direct(THD *thd, Server_runnable *server_runnable,
-                     Ed_result *ed_result);
+/**
+  Execute direct interface.
+
+  @todo Implement support for prelocked mode.
+*/
+
+class Ed_row;
+
+/**
+  Ed_result_set -- a container with result set rows.
+  @todo Implement support for result set metadata and
+  automatic type conversion.
+*/
+
+class Ed_result_set: public Sql_alloc
+{
+public:
+  operator List<Ed_row>&() { return *m_rows; }
+  unsigned int size() const { return m_rows->elements; }
+
+  Ed_result_set(List<Ed_row> *rows_arg, size_t column_count,
+                MEM_ROOT *mem_root_arg);
+
+  /** We don't call member destructors, they all are POD types. */
+  ~Ed_result_set() {}
+
+  size_t get_field_count() const { return m_column_count; }
+
+  static void operator delete(void *ptr, size_t size) throw ();
+private:
+  Ed_result_set(const Ed_result_set &);        /* not implemented */
+  Ed_result_set &operator=(Ed_result_set &);   /* not implemented */
+private:
+  MEM_ROOT m_mem_root;
+  size_t m_column_count;
+  List<Ed_row> *m_rows;
+  Ed_result_set *m_next_rset;
+  friend class Ed_connection;
+};
+
+
+class Ed_connection
+{
+public:
+  /**
+    Construct a new "execute direct" connection.
+
+    The connection can be used to execute SQL statements.
+    If the connection failed to initialize, the error
+    will be returned on the attempt to execute a statement.
+
+    @pre thd  must have no open tables
+              while the connection is used. However,
+              Ed_connection works okay in LOCK TABLES mode.
+              Other properties of THD, such as the current warning
+              information, errors, etc. do not matter and are
+              preserved by Ed_connection. One thread may have many
+              Ed_connections created for it.
+  */
+  Ed_connection(THD *thd);
+
+  /**
+    Execute one SQL statement.
+
+    Until this method is executed, no other methods of
+    Ed_connection can be used. Life cycle of Ed_connection is:
+
+    Initialized -> a statement has been executed ->
+    look at result, move to next result ->
+    look at result, move to next result ->
+    ...
+    moved beyond the last result == Initialized.
+
+    This method can be called repeatedly. Once it's invoked,
+    results of the previous execution are lost.
+
+    A result of execute_direct() can be either:
+
+    - success, no result set rows. In this case get_field_count()
+    returns 0. This happens after execution of INSERT, UPDATE,
+    DELETE, DROP and similar statements. Some other methods, such
+    as get_affected_rows() can be used to retrieve additional
+    result information.
+
+    - success, there are some result set rows (maybe 0). E.g.
+    happens after SELECT. In this case get_field_count() returns
+    the number of columns in a result set and store_result()
+    can be used to retrieve a result set..
+
+    - an error, methods to retrieve error information can
+    be used.
+
+    @return execution status
+    @retval FALSE  success, use get_field_count()
+                   to determine what to do next.
+    @retval TRUE   error, use get_last_error()
+                   to see the error number.
+  */
+  bool execute_direct(LEX_STRING sql_text);
+
+  /**
+    Same as the previous, but takes an instance of Server_runnable
+    instead of SQL statement text.
+
+    @return execution status
+      
+    @retval  FALSE  success, use get_field_count() 
+                    if your code fragment is supposed to
+                    return a result set
+    @retval  TRUE   failure
+  */
+  bool execute_direct(Server_runnable *server_runnable);
+
+  /**
+    Get the number of result set fields.
+
+    This method is valid only if we have a result:
+    execute_direct() has been called. Otherwise
+    the returned value is undefined.
+
+    @sa Documentation for C API function
+    mysql_field_count()
+  */
+  ulong get_field_count() const
+  {
+    return m_current_rset ? m_current_rset->get_field_count() : 0;
+  }
+
+  /**
+    Get the number of affected (deleted, updated)
+    rows for the current statement. Can be
+    used for statements with get_field_count() == 0.
+
+    @sa Documentation for C API function
+    mysql_affected_rows().
+  */
+  ulonglong get_affected_rows() const
+  {
+    return m_diagnostics_area.affected_rows();
+  }
+
+  /**
+    Get the last insert id, if any.
+
+    @sa Documentation for mysql_insert_id().
+  */
+  ulonglong get_last_insert_id() const
+  {
+    return m_diagnostics_area.last_insert_id();
+  }
+
+  /**
+    Get the total number of warnings for the last executed
+    statement. Note, that there is only one warning list even
+    if a statement returns multiple results.
+
+    @sa Documentation for C API function
+    mysql_num_warnings().
+  */
+  ulong get_warn_count() const
+  {
+    return m_warning_info.warn_count();
+  }
+  /**
+    Get the server warnings as a result set.
+    The result set has fixed metadata:
+    The first column is the level.
+    The second is a numeric code.
+    The third is warning text.
+  */
+  List<MYSQL_ERROR> *get_warn_list() { return &m_warning_info.warn_list(); }
+  /**
+    The following members are only valid if execute_direct()
+    or move_to_next_result() returned an error.
+    They never fail, but if they are called when there is no
+    result, or no error, the result is not defined.
+  */
+  const char *get_last_error() const { return m_diagnostics_area.message(); }
+  unsigned int get_last_errno() const { return m_diagnostics_area.sql_errno(); }
+
+  /**
+    Provided get_field_count() is not 0, this never fails. You don't
+    need to free the result set, this is done automatically when
+    you advance to the next result set or destroy the connection.
+    Not returning const because of List iterator not accepting
+    Should be used when you would like Ed_connection to manage
+    result set memory for you.
+  */
+  Ed_result_set *use_result_set() { return m_current_rset; }
+  /**
+    Provided get_field_count() is not 0, this never fails. You
+    must free the returned result set. This can be called only
+    once after execute_direct().
+    Should be used when you would like to get the results
+    and destroy the connection.
+  */
+  Ed_result_set *store_result_set();
+
+  /**
+    If the query returns multiple results, this method
+    can be checked if there is another result beyond the next
+    one.
+    Never fails.
+  */
+  bool has_next_result() const { return test(m_current_rset->m_next_rset); }
+  /**
+    Only valid to call if has_next_result() returned true.
+    Otherwise the result is undefined.
+  */
+  bool move_to_next_result()
+  {
+    m_current_rset= m_current_rset->m_next_rset;
+    return test(m_current_rset);
+  }
+
+  ~Ed_connection() { free_old_result(); }
+private:
+  Diagnostics_area m_diagnostics_area;
+  Warning_info m_warning_info;
+  /**
+    Execute direct interface does not support multi-statements, only
+    multi-results. So we never have a situation when we have
+    a mix of result sets and OK or error packets. We either
+    have a single result set, a single error, or a single OK,
+    or we have a series of result sets, followed by an OK or error.
+  */
+  THD *m_thd;
+  Ed_result_set *m_rsets;
+  Ed_result_set *m_current_rset;
+  friend class Protocol_local;
+private:
+  void free_old_result();
+  void add_result_set(Ed_result_set *ed_result_set);
+private:
+  Ed_connection(const Ed_connection &);        /* not implemented */
+  Ed_connection &operator=(Ed_connection &);   /* not implemented */
+};
+
+
+/** One result set column. */
+
+struct Ed_column: public LEX_STRING
+{
+  /** Implementation note: destructor for this class is never called. */
+};
+
+
+/** One result set record. */
+
+class Ed_row: public Sql_alloc
+{
+public:
+  const Ed_column &operator[](const unsigned int column_index) const
+  {
+    return *get_column(column_index);
+  }
+  const Ed_column *get_column(const unsigned int column_index) const
+  {
+    DBUG_ASSERT(column_index < size());
+    return m_column_array + column_index;
+  }
+  size_t size() const { return m_column_count; }
+
+  Ed_row(Ed_column *column_array_arg, size_t column_count_arg)
+    :m_column_array(column_array_arg),
+    m_column_count(column_count_arg)
+  {}
+private:
+  Ed_column *m_column_array;
+  size_t m_column_count; /* TODO: change to point to metadata */
+};
 
 #endif // SQL_PREPARE_H

Thread
bzr commit into mysql-6.0-runtime branch (kostja:2767) WL#4264Konstantin Osipov6 Dec