#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#4264 | Konstantin Osipov | 6 Dec |