summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/ha_ndbcluster_binlog.cc25
-rw-r--r--sql/ha_partition.cc1
-rw-r--r--sql/item_func.cc1
-rw-r--r--sql/log_event.cc52
-rw-r--r--sql/log_event_old.cc16
-rw-r--r--sql/mysqld.cc50
-rw-r--r--sql/net_serv.cc58
-rw-r--r--sql/opt_range.cc2
-rw-r--r--sql/opt_sum.cc2
-rw-r--r--sql/protocol.cc227
-rw-r--r--sql/protocol.h5
-rw-r--r--sql/repl_failsafe.cc4
-rw-r--r--sql/rpl_record.cc5
-rw-r--r--sql/rpl_rli.cc4
-rw-r--r--sql/slave.cc60
-rw-r--r--sql/sp_head.cc16
-rw-r--r--sql/sp_rcontext.cc22
-rw-r--r--sql/sql_acl.cc9
-rw-r--r--sql/sql_base.cc33
-rw-r--r--sql/sql_binlog.cc16
-rw-r--r--sql/sql_cache.cc1
-rw-r--r--sql/sql_class.cc155
-rw-r--r--sql/sql_class.h159
-rw-r--r--sql/sql_connect.cc33
-rw-r--r--sql/sql_db.cc5
-rw-r--r--sql/sql_delete.cc8
-rw-r--r--sql/sql_derived.cc5
-rw-r--r--sql/sql_insert.cc16
-rw-r--r--sql/sql_parse.cc126
-rw-r--r--sql/sql_partition.cc1
-rw-r--r--sql/sql_prepare.cc27
-rw-r--r--sql/sql_select.cc2
-rw-r--r--sql/sql_servers.cc2
-rw-r--r--sql/sql_show.cc55
-rw-r--r--sql/sql_table.cc32
-rw-r--r--sql/sql_update.cc4
-rw-r--r--sql/table.cc27
-rw-r--r--sql/tztime.cc2
38 files changed, 840 insertions, 428 deletions
diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc
index be75eff2575..d6e8df9f0ff 100644
--- a/sql/ha_ndbcluster_binlog.cc
+++ b/sql/ha_ndbcluster_binlog.cc
@@ -257,6 +257,10 @@ static void run_query(THD *thd, char *buf, char *end,
thd->options&= ~OPTION_BIN_LOG;
DBUG_PRINT("query", ("%s", thd->query));
+
+ DBUG_ASSERT(!thd->in_sub_stmt);
+ DBUG_ASSERT(!thd->prelocked_mode);
+
mysql_parse(thd, thd->query, thd->query_length, &found_semicolon);
if (no_print_error && thd->is_slave_error)
@@ -265,14 +269,27 @@ static void run_query(THD *thd, char *buf, char *end,
Thd_ndb *thd_ndb= get_thd_ndb(thd);
for (i= 0; no_print_error[i]; i++)
if ((thd_ndb->m_error_code == no_print_error[i]) ||
- (thd->net.last_errno == (unsigned)no_print_error[i]))
+ (thd->main_da.sql_errno() == (unsigned) no_print_error[i]))
break;
if (!no_print_error[i])
sql_print_error("NDB: %s: error %s %d(ndb: %d) %d %d",
- buf, thd->net.last_error, thd->net.last_errno,
+ buf,
+ thd->main_da.message(),
+ thd->main_da.sql_errno(),
thd_ndb->m_error_code,
(int) thd->is_error(), thd->is_slave_error);
}
+ /*
+ XXX: this code is broken. mysql_parse()/mysql_reset_thd_for_next_command()
+ can not be called from within a statement, and
+ run_query() can be called from anywhere, including from within
+ a sub-statement.
+ This particular reset is a temporary hack to avoid an assert
+ for double assignment of the diagnostics area when run_query()
+ is called from ndbcluster_reset_logs(), which is called from
+ mysql_flush().
+ */
+ thd->main_da.reset_diagnostics_area();
thd->options= save_thd_options;
thd->query_length= save_query_length;
@@ -2301,8 +2318,8 @@ static int open_ndb_binlog_index(THD *thd, TABLE_LIST *tables,
if (open_tables(thd, &tables, &counter, MYSQL_LOCK_IGNORE_FLUSH))
{
sql_print_error("NDB Binlog: Opening ndb_binlog_index: %d, '%s'",
- thd->net.last_errno,
- thd->net.last_error ? thd->net.last_error : "");
+ thd->main_da.sql_errno(),
+ thd->main_da.message());
thd->proc_info= save_proc_info;
return -1;
}
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index 1400d9da753..eca577cb6c8 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -1753,6 +1753,7 @@ partition_element *ha_partition::find_partition_element(uint part_id)
return part_elem;
}
DBUG_ASSERT(0);
+ my_error(ER_OUT_OF_RESOURCES, MYF(0));
current_thd->fatal_error(); // Abort
return NULL;
}
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 101832b58a9..d219987e46b 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -2949,7 +2949,6 @@ udf_handler::fix_fields(THD *thd, Item_result_field *func,
}
}
}
- thd->net.last_error[0]=0;
Udf_func_init init= u_d->func_init;
if ((error=(uchar) init(&initid, &f_args, init_msg_buff)))
{
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 2b3037aedcc..00e3dc89f6b 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -1611,7 +1611,8 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
if (killed_status_arg == THD::KILLED_NO_VALUE)
killed_status_arg= thd_arg->killed;
error_code=
- (killed_status_arg == THD::NOT_KILLED) ? thd_arg->net.last_errno :
+ (killed_status_arg == THD::NOT_KILLED) ?
+ (thd_arg->is_error() ? thd_arg->main_da.sql_errno() : 0) :
((thd_arg->system_thread & SYSTEM_THREAD_DELAYED_INSERT) ? 0 :
thd_arg->killed_errno());
@@ -2332,7 +2333,7 @@ START SLAVE; . Query: '%s'", expected_error, thd->query);
}
/* If the query was not ignored, it is printed to the general log */
- if (thd->net.last_errno != ER_SLAVE_IGNORED_TABLE)
+ if (!thd->is_error() || thd->main_da.sql_errno() != ER_SLAVE_IGNORED_TABLE)
general_log_write(thd, COM_QUERY, thd->query, thd->query_length);
compare_errors:
@@ -2341,9 +2342,10 @@ compare_errors:
If we expected a non-zero error code, and we don't get the same error
code, and none of them should be ignored.
*/
- DBUG_PRINT("info",("expected_error: %d last_errno: %d",
- expected_error, thd->net.last_errno));
- if ((expected_error != (actual_error= thd->net.last_errno)) &&
+ actual_error= thd->is_error() ? thd->main_da.sql_errno() : 0;
+ DBUG_PRINT("info",("expected_error: %d sql_errno: %d",
+ expected_error, actual_error));
+ if ((expected_error != actual_error) &&
expected_error &&
!ignored_error_code(actual_error) &&
!ignored_error_code(expected_error))
@@ -2355,7 +2357,7 @@ Error on master: '%s' (%d), Error on slave: '%s' (%d). \
Default database: '%s'. Query: '%s'",
ER_SAFE(expected_error),
expected_error,
- actual_error ? thd->net.last_error: "no error",
+ actual_error ? thd->main_da.message() : "no error",
actual_error,
print_slave_db_safe(db), query_arg);
thd->is_slave_error= 1;
@@ -2377,7 +2379,7 @@ Default database: '%s'. Query: '%s'",
{
rli->report(ERROR_LEVEL, actual_error,
"Error '%s' on query. Default database: '%s'. Query: '%s'",
- (actual_error ? thd->net.last_error :
+ (actual_error ? thd->main_da.message() :
"unexpected success or fatal error"),
print_slave_db_safe(thd->db), query_arg);
thd->is_slave_error= 1;
@@ -3720,8 +3722,11 @@ error:
/* this err/sql_errno code is copy-paste from net_send_error() */
const char *err;
int sql_errno;
- if ((err=thd->net.last_error)[0])
- sql_errno=thd->net.last_errno;
+ if (thd->is_error())
+ {
+ err= thd->main_da.message();
+ sql_errno= thd->main_da.sql_errno();
+ }
else
{
sql_errno=ER_UNKNOWN_ERROR;
@@ -6222,10 +6227,10 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
Error reporting borrowed from Query_log_event with many excessive
simplifications (we don't honour --slave-skip-errors)
*/
- uint actual_error= thd->net.last_errno;
+ uint actual_error= thd->main_da.sql_errno();
rli->report(ERROR_LEVEL, actual_error,
"Error '%s' in %s event: when locking tables",
- (actual_error ? thd->net.last_error :
+ (actual_error ? thd->main_da.message():
"unexpected success or fatal error"),
get_type_str());
thd->is_fatal_error= 1;
@@ -6266,10 +6271,10 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
Error reporting borrowed from Query_log_event with many excessive
simplifications (we don't honour --slave-skip-errors)
*/
- uint actual_error= thd->net.last_errno;
+ uint actual_error= thd->main_da.sql_errno();
rli->report(ERROR_LEVEL, actual_error,
"Error '%s' on reopening tables",
- (actual_error ? thd->net.last_error :
+ (actual_error ? thd->main_da.message() :
"unexpected success or fatal error"));
thd->is_slave_error= 1;
}
@@ -6425,10 +6430,11 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
break;
default:
- rli->report(ERROR_LEVEL, thd->net.last_errno,
+ rli->report(ERROR_LEVEL,
+ thd->is_error() ? thd->main_da.sql_errno() : 0,
"Error in %s event: row application failed. %s",
get_type_str(),
- thd->net.last_error ? thd->net.last_error : "");
+ thd->is_error() ? thd->main_da.message() : "");
thd->is_slave_error= 1;
break;
}
@@ -6475,12 +6481,13 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
if (error)
{ /* error has occured during the transaction */
- rli->report(ERROR_LEVEL, thd->net.last_errno,
+ rli->report(ERROR_LEVEL,
+ thd->is_error() ? thd->main_da.sql_errno() : 0,
"Error in %s event: error during transaction execution "
"on table %s.%s. %s",
get_type_str(), table->s->db.str,
table->s->table_name.str,
- thd->net.last_error ? thd->net.last_error : "");
+ thd->is_error() ? thd->main_da.message() : "");
/*
If one day we honour --skip-slave-errors in row-based replication, and
@@ -7094,10 +7101,10 @@ int Table_map_log_event::do_apply_event(Relay_log_info const *rli)
Error reporting borrowed from Query_log_event with many excessive
simplifications (we don't honour --slave-skip-errors)
*/
- uint actual_error= thd->net.last_errno;
+ uint actual_error= thd->main_da.sql_errno();
rli->report(ERROR_LEVEL, actual_error,
"Error '%s' on opening table `%s`.`%s`",
- (actual_error ? thd->net.last_error :
+ (actual_error ? thd->main_da.message() :
"unexpected success or fatal error"),
table_list->db, table_list->table_name);
thd->is_slave_error= 1;
@@ -7625,8 +7632,11 @@ Write_rows_log_event::do_exec_row(const Relay_log_info *const rli)
DBUG_ASSERT(m_table != NULL);
int error= write_row(rli, TRUE /* overwrite */);
- if (error && !thd->net.last_errno)
- thd->net.last_errno= error;
+ if (error && !thd->is_error())
+ {
+ DBUG_ASSERT(0);
+ my_error(ER_UNKNOWN_ERROR, MYF(0));
+ }
return error;
}
diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc
index c6b691ec010..6d5d86e42fe 100644
--- a/sql/log_event_old.cc
+++ b/sql/log_event_old.cc
@@ -74,10 +74,10 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const Relay_log_info *rli
Error reporting borrowed from Query_log_event with many excessive
simplifications (we don't honour --slave-skip-errors)
*/
- uint actual_error= thd->net.last_errno;
+ uint actual_error= thd->main_da.sql_errno();
rli->report(ERROR_LEVEL, actual_error,
"Error '%s' in %s event: when locking tables",
- (actual_error ? thd->net.last_error :
+ (actual_error ? thd->main_da.message() :
"unexpected success or fatal error"),
ev->get_type_str());
thd->is_fatal_error= 1;
@@ -118,10 +118,10 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const Relay_log_info *rli
Error reporting borrowed from Query_log_event with many excessive
simplifications (we don't honour --slave-skip-errors)
*/
- uint actual_error= thd->net.last_errno;
+ uint actual_error= thd->main_da.sql_errno();
rli->report(ERROR_LEVEL, actual_error,
"Error '%s' on reopening tables",
- (actual_error ? thd->net.last_error :
+ (actual_error ? thd->main_da.message() :
"unexpected success or fatal error"));
thd->is_slave_error= 1;
}
@@ -251,10 +251,10 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const Relay_log_info *rli
break;
default:
- rli->report(ERROR_LEVEL, thd->net.last_errno,
+ rli->report(ERROR_LEVEL, thd->main_da.sql_errno(),
"Error in %s event: row application failed. %s",
ev->get_type_str(),
- thd->net.last_error ? thd->net.last_error : "");
+ thd->is_error() ? thd->main_da.message() : "");
thd->is_slave_error= 1;
break;
}
@@ -280,12 +280,12 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const Relay_log_info *rli
if (error)
{ /* error has occured during the transaction */
- rli->report(ERROR_LEVEL, thd->net.last_errno,
+ rli->report(ERROR_LEVEL, thd->main_da.sql_errno(),
"Error in %s event: error during transaction execution "
"on table %s.%s. %s",
ev->get_type_str(), table->s->db.str,
table->s->table_name.str,
- thd->net.last_error ? thd->net.last_error : "");
+ thd->is_error() ? thd->main_da.message() : "");
/*
If one day we honour --skip-slave-errors in row-based replication, and
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index fad2e5dcd22..1938602f372 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -2587,21 +2587,8 @@ int my_message_sql(uint error, const char *str, myf MyFlags)
MYSQL_ERROR::WARN_LEVEL_ERROR))
DBUG_RETURN(0);
- if (thd->spcont &&
- thd->spcont->handle_error(error, MYSQL_ERROR::WARN_LEVEL_ERROR, thd))
- {
- DBUG_RETURN(0);
- }
-
thd->is_slave_error= 1; // needed to catch query errors during replication
- if (!thd->no_warnings_for_error)
- {
- thd->no_warnings_for_error= TRUE;
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, error, str);
- thd->no_warnings_for_error= FALSE;
- }
-
/*
thd->lex->current_select == 0 if lex structure is not inited
(not query command (COM_QUERY))
@@ -2618,14 +2605,39 @@ int my_message_sql(uint error, const char *str, myf MyFlags)
}
else
{
- NET *net= &thd->net;
- net->report_error= 1;
- query_cache_abort(net);
- if (!net->last_error[0]) // Return only first message
+ if (! thd->main_da.is_error()) // Return only first message
{
- strmake(net->last_error, str, sizeof(net->last_error)-1);
- net->last_errno= error ? error : ER_UNKNOWN_ERROR;
+ if (error == 0)
+ error= ER_UNKNOWN_ERROR;
+ if (str == NULL)
+ str= ER(error);
+ thd->main_da.set_error_status(thd, error, str);
}
+ query_cache_abort(&thd->net);
+ }
+ /*
+ If a continue handler is found, the error message will be cleared
+ by the stored procedures code.
+ */
+ if (thd->spcont &&
+ thd->spcont->handle_error(error, MYSQL_ERROR::WARN_LEVEL_ERROR, thd))
+ {
+ /*
+ Do not push any warnings, a handled error must be completely
+ silenced.
+ */
+ DBUG_RETURN(0);
+ }
+
+ if (!thd->no_warnings_for_error)
+ {
+ /*
+ Suppress infinite recursion if there a memory allocation error
+ inside push_warning.
+ */
+ thd->no_warnings_for_error= TRUE;
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, error, str);
+ thd->no_warnings_for_error= FALSE;
}
}
if (!thd || MyFlags & ME_NOREFRESH)
diff --git a/sql/net_serv.cc b/sql/net_serv.cc
index 18cf1ebae5b..73eb340fbc0 100644
--- a/sql/net_serv.cc
+++ b/sql/net_serv.cc
@@ -123,20 +123,18 @@ my_bool my_net_init(NET *net, Vio* vio)
MYF(MY_WME))))
DBUG_RETURN(1);
net->buff_end=net->buff+net->max_packet;
- net->no_send_ok= net->no_send_error= 0;
net->error=0; net->return_errno=0; net->return_status=0;
net->pkt_nr=net->compress_pkt_nr=0;
net->write_pos=net->read_pos = net->buff;
- net->last_error[0]=0;
+ net->client_last_error[0]=0;
net->compress=0; net->reading_or_writing=0;
net->where_b = net->remain_in_buf=0;
- net->last_errno=0;
+ net->client_last_errno=0;
#ifdef USE_QUERY_CACHE
query_cache_init_query(net);
#else
net->query_cache_query= 0;
#endif
- net->report_error= 0;
if (vio != 0) /* If real connection */
{
@@ -176,9 +174,12 @@ my_bool net_realloc(NET *net, size_t length)
{
DBUG_PRINT("error", ("Packet too large. Max size: %lu",
net->max_packet_size));
+ /* @todo: 1 and 2 codes are identical. */
net->error= 1;
- net->report_error= 1;
- net->last_errno= ER_NET_PACKET_TOO_LARGE;
+ net->client_last_errno= ER_NET_PACKET_TOO_LARGE;
+#ifdef MYSQL_SERVER
+ my_error(ER_NET_PACKET_TOO_LARGE, MYF(0));
+#endif
DBUG_RETURN(1);
}
pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1);
@@ -190,9 +191,10 @@ my_bool net_realloc(NET *net, size_t length)
NET_HEADER_SIZE + COMP_HEADER_SIZE,
MYF(MY_WME))))
{
+ /* @todo: 1 and 2 codes are identical. */
net->error= 1;
- net->report_error= 1;
- net->last_errno= ER_OUT_OF_RESOURCES;
+ net->client_last_errno= ER_OUT_OF_RESOURCES;
+ /* In the server the error is reported by MY_WME flag. */
DBUG_RETURN(1);
}
net->buff=net->write_pos=buff;
@@ -582,12 +584,9 @@ net_real_write(NET *net,const uchar *packet, size_t len)
if (!(b= (uchar*) my_malloc(len + NET_HEADER_SIZE +
COMP_HEADER_SIZE, MYF(MY_WME))))
{
-#ifdef MYSQL_SERVER
- net->last_errno= ER_OUT_OF_RESOURCES;
net->error= 2;
- /* TODO is it needed to set this variable if we have no socket */
- net->report_error= 1;
-#endif
+ net->client_last_errno= ER_OUT_OF_RESOURCES;
+ /* In the server, the error is reported by MY_WME flag. */
net->reading_or_writing= 0;
DBUG_RETURN(1);
}
@@ -638,11 +637,11 @@ net_real_write(NET *net,const uchar *packet, size_t len)
"%s: my_net_write: fcntl returned error %d, aborting thread\n",
my_progname,vio_errno(net->vio));
#endif /* EXTRA_DEBUG */
-#ifdef MYSQL_SERVER
- net->last_errno= ER_NET_ERROR_ON_WRITE;
-#endif
net->error= 2; /* Close socket */
- net->report_error= 1;
+ net->client_last_errno= ER_NET_PACKET_TOO_LARGE;
+#ifdef MYSQL_SERVER
+ my_error(ER_NET_PACKET_TOO_LARGE, MYF(0));
+#endif
goto end;
}
retry_count=0;
@@ -669,10 +668,10 @@ net_real_write(NET *net,const uchar *packet, size_t len)
}
#endif /* defined(THREAD_SAFE_CLIENT) && !defined(MYSQL_SERVER) */
net->error= 2; /* Close socket */
- net->report_error= 1;
+ net->client_last_errno= (interrupted ? ER_NET_WRITE_INTERRUPTED :
+ ER_NET_ERROR_ON_WRITE);
#ifdef MYSQL_SERVER
- net->last_errno= (interrupted ? ER_NET_WRITE_INTERRUPTED :
- ER_NET_ERROR_ON_WRITE);
+ my_error(net->client_last_errno, MYF(0));
#endif /* MYSQL_SERVER */
break;
}
@@ -849,9 +848,9 @@ my_real_read(NET *net, size_t *complen)
#endif /* EXTRA_DEBUG */
len= packet_error;
net->error= 2; /* Close socket */
- net->report_error= 1;
+ net->client_last_errno= ER_NET_FCNTL_ERROR;
#ifdef MYSQL_SERVER
- net->last_errno= ER_NET_FCNTL_ERROR;
+ my_error(ER_NET_FCNTL_ERROR, MYF(0));
#endif
goto end;
}
@@ -881,10 +880,11 @@ my_real_read(NET *net, size_t *complen)
remain, vio_errno(net->vio), (long) length));
len= packet_error;
net->error= 2; /* Close socket */
- net->report_error= 1;
+ net->client_last_errno= (vio_was_interrupted(net->vio) ?
+ ER_NET_READ_INTERRUPTED :
+ ER_NET_READ_ERROR);
#ifdef MYSQL_SERVER
- net->last_errno= (vio_was_interrupted(net->vio) ? ER_NET_READ_INTERRUPTED :
- ER_NET_READ_ERROR);
+ my_error(net->client_last_errno, MYF(0));
#endif
goto end;
}
@@ -915,9 +915,9 @@ my_real_read(NET *net, size_t *complen)
#endif
}
len= packet_error;
- net->report_error= 1;
+ /* Not a NET error on the client. XXX: why? */
#ifdef MYSQL_SERVER
- net->last_errno=ER_NET_PACKETS_OUT_OF_ORDER;
+ my_error(ER_NET_PACKETS_OUT_OF_ORDER, MYF(0));
#endif
goto end;
}
@@ -1101,9 +1101,9 @@ my_net_read(NET *net)
&complen))
{
net->error= 2; /* caller will close socket */
- net->report_error= 1;
+ net->client_last_errno= ER_NET_UNCOMPRESS_ERROR;
#ifdef MYSQL_SERVER
- net->last_errno=ER_NET_UNCOMPRESS_ERROR;
+ my_error(ER_NET_UNCOMPRESS_ERROR, MYF(0));
#endif
return packet_error;
}
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index c67687b2bde..9b169bc8739 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -1271,7 +1271,7 @@ int QUICK_RANGE_SELECT::init_ror_merged_scan(bool reuse_handler)
the storage engine calls in question happen to never fail with the
existing storage engines.
*/
- thd->net.report_error= 1; /* purecov: inspected */
+ my_error(ER_OUT_OF_RESOURCES, MYF(0)); /* purecov: inspected */
/* Caller will free the memory */
goto failure; /* purecov: inspected */
}
diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc
index 12ad504d738..91786ff3f4b 100644
--- a/sql/opt_sum.cc
+++ b/sql/opt_sum.cc
@@ -170,6 +170,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
if(error)
{
tl->table->file->print_error(error, MYF(0));
+ tl->table->in_use->fatal_error();
return error;
}
count*= tl->table->file->stats.records;
@@ -418,6 +419,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
return HA_ERR_KEY_NOT_FOUND; // No rows matching WHERE
/* HA_ERR_LOCK_DEADLOCK or some other error */
table->file->print_error(error, MYF(0));
+ table->in_use->fatal_error();
return(error);
}
removed_tables|= table->map;
diff --git a/sql/protocol.cc b/sql/protocol.cc
index 713f4ed3d25..f7b3a496447 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -23,13 +23,20 @@
#endif
#include "mysql_priv.h"
-#include "sp_rcontext.h"
#include <stdarg.h>
static const unsigned int PACKET_BUFFER_EXTRA_ALLOC= 1024;
+/* Declared non-static only because of the embedded library. */
void net_send_error_packet(THD *thd, uint sql_errno, const char *err);
+void
+net_send_ok(THD *thd,
+ uint server_status, uint total_warn_count,
+ ha_rows affected_rows, ulonglong id, const char *message);
+void
+net_send_eof(THD *thd, uint server_status, uint total_warn_count);
#ifndef EMBEDDED_LIBRARY
-static void write_eof_packet(THD *thd, NET *net);
+static void write_eof_packet(THD *thd, NET *net,
+ uint server_status, uint total_warn_count);
#endif
#ifndef EMBEDDED_LIBRARY
@@ -68,58 +75,23 @@ bool Protocol_binary::net_store_data(const uchar *from, size_t length)
void net_send_error(THD *thd, uint sql_errno, const char *err)
{
NET *net= &thd->net;
- bool generate_warning= thd->killed != THD::KILL_CONNECTION;
DBUG_ENTER("net_send_error");
- DBUG_PRINT("enter",("sql_errno: %d err: %s", sql_errno,
- err ? err : net->last_error[0] ?
- net->last_error : "NULL"));
DBUG_ASSERT(!thd->spcont);
+ DBUG_ASSERT(sql_errno);
+ DBUG_ASSERT(err && err[0]);
- if (thd->killed == THD::KILL_QUERY || thd->killed == THD::KILL_BAD_DATA)
- {
- thd->killed= THD::NOT_KILLED;
- thd->mysys_var->abort= 0;
- }
+ DBUG_PRINT("enter",("sql_errno: %d err: %s", sql_errno, err));
- if (net && net->no_send_error)
- {
- thd->clear_error();
- thd->is_fatal_error= 0; // Error message is given
- DBUG_PRINT("info", ("sending error messages prohibited"));
- DBUG_VOID_RETURN;
- }
-
- thd->is_slave_error= 1; // needed to catch query errors during replication
- if (!err)
- {
- if (sql_errno)
- err=ER(sql_errno);
- else
- {
- if ((err=net->last_error)[0])
- {
- sql_errno=net->last_errno;
- generate_warning= 0; // This warning has already been given
- }
- else
- {
- sql_errno=ER_UNKNOWN_ERROR;
- err=ER(sql_errno); /* purecov: inspected */
- }
- }
- }
-
- if (generate_warning)
- {
- /* Error that we have not got with my_error() */
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, sql_errno, err);
- }
+ /*
+ It's one case when we can push an error even though there
+ is an OK or EOF already.
+ */
+ thd->main_da.can_overwrite_status= TRUE;
net_send_error_packet(thd, sql_errno, err);
- thd->is_fatal_error= 0; // Error message is given
- thd->net.report_error= 0;
+ thd->main_da.can_overwrite_status= FALSE;
/* Abort multi-result sets */
thd->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
@@ -149,23 +121,21 @@ void net_send_error(THD *thd, uint sql_errno, const char *err)
warning_count Stored in 2 bytes; New in 4.1 protocol
message Stored as packed length (1-9 bytes) + message
Is not stored if no message
-
- If net->no_send_ok return without sending packet
*/
#ifndef EMBEDDED_LIBRARY
void
-send_ok(THD *thd, ha_rows affected_rows, ulonglong id, const char *message)
+net_send_ok(THD *thd,
+ uint server_status, uint total_warn_count,
+ ha_rows affected_rows, ulonglong id, const char *message)
{
NET *net= &thd->net;
uchar buff[MYSQL_ERRMSG_SIZE+10],*pos;
DBUG_ENTER("send_ok");
- if (net->no_send_ok || !net->vio) // hack for re-parsing queries
+ if (! net->vio) // hack for re-parsing queries
{
- DBUG_PRINT("info", ("no send ok: %s, vio present: %s",
- (net->no_send_ok ? "YES" : "NO"),
- (net->vio ? "YES" : "NO")));
+ DBUG_PRINT("info", ("vio present: NO"));
DBUG_VOID_RETURN;
}
@@ -178,28 +148,29 @@ send_ok(THD *thd, ha_rows affected_rows, ulonglong id, const char *message)
("affected_rows: %lu id: %lu status: %u warning_count: %u",
(ulong) affected_rows,
(ulong) id,
- (uint) (thd->server_status & 0xffff),
- (uint) thd->total_warn_count));
- int2store(pos,thd->server_status);
+ (uint) (server_status & 0xffff),
+ (uint) total_warn_count));
+ int2store(pos, server_status);
pos+=2;
/* We can only return up to 65535 warnings in two bytes */
- uint tmp= min(thd->total_warn_count, 65535);
+ uint tmp= min(total_warn_count, 65535);
int2store(pos, tmp);
pos+= 2;
}
else if (net->return_status) // For 4.0 protocol
{
- int2store(pos,thd->server_status);
+ int2store(pos, server_status);
pos+=2;
}
- if (message)
+ thd->main_da.can_overwrite_status= TRUE;
+
+ if (message && message[0])
pos= net_store_data(pos, (uchar*) message, strlen(message));
VOID(my_net_write(net, buff, (size_t) (pos-buff)));
VOID(net_flush(net));
- /* We can't anymore send an error to the client */
- thd->net.report_error= 0;
- thd->net.no_send_error= 1;
+
+ thd->main_da.can_overwrite_status= FALSE;
DBUG_PRINT("info", ("OK sent, so no more error sending allowed"));
DBUG_VOID_RETURN;
@@ -211,7 +182,7 @@ static uchar eof_buff[1]= { (uchar) 254 }; /* Marker for end of fields */
Send eof (= end of result set) to the client
SYNOPSIS
- send_eof()
+ net_send_eof()
thd Thread handler
no_flush Set to 1 if there will be more data to the client,
like in send_fields().
@@ -230,15 +201,17 @@ static uchar eof_buff[1]= { (uchar) 254 }; /* Marker for end of fields */
*/
void
-send_eof(THD *thd)
+net_send_eof(THD *thd, uint server_status, uint total_warn_count)
{
NET *net= &thd->net;
- DBUG_ENTER("send_eof");
+ DBUG_ENTER("net_send_eof");
+ /* Set to TRUE if no active vio, to work well in case of --init-file */
if (net->vio != 0)
{
- write_eof_packet(thd, net);
+ thd->main_da.can_overwrite_status= TRUE;
+ write_eof_packet(thd, net, server_status, total_warn_count);
VOID(net_flush(net));
- thd->net.no_send_error= 1;
+ thd->main_da.can_overwrite_status= FALSE;
DBUG_PRINT("info", ("EOF sent, so no more error sending allowed"));
}
DBUG_VOID_RETURN;
@@ -250,7 +223,9 @@ send_eof(THD *thd)
write it to the network output buffer.
*/
-static void write_eof_packet(THD *thd, NET *net)
+static void write_eof_packet(THD *thd, NET *net,
+ uint server_status,
+ uint total_warn_count)
{
if (thd->client_capabilities & CLIENT_PROTOCOL_41)
{
@@ -259,7 +234,7 @@ static void write_eof_packet(THD *thd, NET *net)
Don't send warn count during SP execution, as the warn_list
is cleared between substatements, and mysqltest gets confused
*/
- uint tmp= (thd->spcont ? 0 : min(thd->total_warn_count, 65535));
+ uint tmp= min(total_warn_count, 65535);
buff[0]= 254;
int2store(buff+1, tmp);
/*
@@ -268,8 +243,8 @@ static void write_eof_packet(THD *thd, NET *net)
other queries (see the if test in dispatch_command / COM_QUERY)
*/
if (thd->is_fatal_error)
- thd->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
- int2store(buff+3, thd->server_status);
+ server_status&= ~SERVER_MORE_RESULTS_EXISTS;
+ int2store(buff + 3, server_status);
VOID(my_net_write(net, buff, 5));
}
else
@@ -360,6 +335,96 @@ static uchar *net_store_length_fast(uchar *packet, uint length)
return packet+2;
}
+/**
+ Send the status of the current statement execution over network.
+
+ @param thd in fact, carries two parameters, NET for the transport and
+ Diagnostics_area as the source of status information.
+
+ In MySQL, there are two types of SQL statements: those that return
+ a result set and those that return status information only.
+
+ If a statement returns a result set, it consists of 3 parts:
+ - result set meta-data
+ - variable number of result set rows (can be 0)
+ - followed and terminated by EOF or ERROR packet
+
+ Once the client has seen the meta-data information, it always
+ expects an EOF or ERROR to terminate the result set. If ERROR is
+ received, the result set rows are normally discarded (this is up
+ to the client implementation, libmysql at least does discard them).
+ EOF, on the contrary, means "successfully evaluated the entire
+ result set". Since we don't know how many rows belong to a result
+ set until it's evaluated, EOF/ERROR is the indicator of the end
+ of the row stream. Note, that we can not buffer result set rows
+ on the server -- there may be an arbitrary number of rows. But
+ we do buffer the last packet (EOF/ERROR) in the Diagnostics_area and
+ delay sending it till the very end of execution (here), to be able to
+ change EOF to an ERROR if commit failed or some other error occurred
+ during the last cleanup steps taken after execution.
+
+ A statement that does not return a result set doesn't send result
+ set meta-data either. Instead it returns one of:
+ - OK packet
+ - ERROR packet.
+ Similarly to the EOF/ERROR of the previous statement type, OK/ERROR
+ packet is "buffered" in the diagnostics area and sent to the client
+ in the end of statement.
+
+ @pre The diagnostics area is assigned or disabled. It can not be empty
+ -- we assume that every SQL statement or COM_* command
+ generates OK, ERROR, or EOF status.
+
+ @post The status information is encoded to protocol format and sent to the
+ client.
+
+ @return We conventionally return void, since the only type of error
+ that can happen here is a NET (transport) error, and that one
+ will become visible when we attempt to read from the NET the
+ next command.
+ Diagnostics_area::is_sent is set for debugging purposes only.
+*/
+
+void net_end_statement(THD *thd)
+{
+ DBUG_ASSERT(! thd->main_da.is_sent);
+
+ /* Can not be true, but do not take chances in production. */
+ if (thd->main_da.is_sent)
+ return;
+
+ switch (thd->main_da.status()) {
+ case Diagnostics_area::DA_ERROR:
+ /* The query failed, send error to log and abort bootstrap. */
+ net_send_error(thd,
+ thd->main_da.sql_errno(),
+ thd->main_da.message());
+ break;
+ case Diagnostics_area::DA_EOF:
+ net_send_eof(thd,
+ thd->main_da.server_status(),
+ thd->main_da.total_warn_count());
+ break;
+ case Diagnostics_area::DA_OK:
+ net_send_ok(thd,
+ thd->main_da.server_status(),
+ thd->main_da.total_warn_count(),
+ thd->main_da.affected_rows(),
+ thd->main_da.last_insert_id(),
+ thd->main_da.message());
+ break;
+ case Diagnostics_area::DA_DISABLED:
+ break;
+ case Diagnostics_area::DA_EMPTY:
+ default:
+ DBUG_ASSERT(0);
+ net_send_ok(thd, thd->server_status, thd->total_warn_count,
+ 0, 0, NULL);
+ break;
+ }
+ thd->main_da.is_sent= TRUE;
+}
+
/****************************************************************************
Functions used by the protocol functions (like send_ok) to store strings
@@ -408,6 +473,17 @@ void Protocol::init(THD *thd_arg)
#endif
}
+/**
+ Finish the result set with EOF packet, as is expected by the client,
+ if there is an error evaluating the next row and a continue handler
+ for the error.
+*/
+
+void Protocol::end_partial_result_set(THD *thd)
+{
+ net_send_eof(thd, thd->server_status, 0 /* no warnings, we're inside SP */);
+}
+
bool Protocol::flush()
{
@@ -573,7 +649,14 @@ bool Protocol::send_fields(List<Item> *list, uint flags)
}
if (flags & SEND_EOF)
- write_eof_packet(thd, &thd->net);
+ {
+ /*
+ Mark the end of meta-data result set, and store thd->server_status,
+ to show that there is no cursor.
+ Send no warning information, as it will be sent at statement end.
+ */
+ write_eof_packet(thd, &thd->net, thd->server_status, thd->total_warn_count);
+ }
DBUG_RETURN(prepare_for_send(list));
err:
diff --git a/sql/protocol.h b/sql/protocol.h
index 53584326f03..cd58ec93bbb 100644
--- a/sql/protocol.h
+++ b/sql/protocol.h
@@ -75,6 +75,7 @@ public:
return 0;
}
virtual bool flush();
+ virtual void end_partial_result_set(THD *thd);
virtual void prepare_for_resend()=0;
virtual bool store_null()=0;
@@ -173,9 +174,7 @@ public:
void send_warning(THD *thd, uint sql_errno, const char *err=0);
void net_send_error(THD *thd, uint sql_errno=0, const char *err=0);
-void send_ok(THD *thd, ha_rows affected_rows=0L, ulonglong id=0L,
- const char *info=0);
-void send_eof(THD *thd);
+void net_end_statement(THD *thd);
bool send_old_password_request(THD *thd);
uchar *net_store_data(uchar *to,const uchar *from, size_t length);
uchar *net_store_data(uchar *to,int32 from);
diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc
index 834d87532af..e294cf8ae2d 100644
--- a/sql/repl_failsafe.cc
+++ b/sql/repl_failsafe.cc
@@ -685,7 +685,7 @@ int connect_to_master(THD *thd, MYSQL* mysql, Master_info* mi)
if (!mi->host || !*mi->host) /* empty host */
{
- strmov(mysql->net.last_error, "Master is not configured");
+ strmov(mysql->net.client_last_error, "Master is not configured");
DBUG_RETURN(1);
}
mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, (char *) &slave_net_timeout);
@@ -880,6 +880,8 @@ bool load_master_data(THD* thd)
cleanup_mysql_results(db_res, cur_table_res - 1, table_res);
goto err;
}
+ /* Clear the result of mysql_create_db(). */
+ thd->main_da.reset_diagnostics_area();
if (mysql_select_db(&mysql, db) ||
mysql_real_query(&mysql, STRING_WITH_LEN("SHOW TABLES")) ||
diff --git a/sql/rpl_record.cc b/sql/rpl_record.cc
index ed0dc82cf01..eb32897f937 100644
--- a/sql/rpl_record.cc
+++ b/sql/rpl_record.cc
@@ -338,12 +338,13 @@ int prepare_record(const Slave_reporting_capability *const log,
if (check && ((f->flags & mask) == mask))
{
DBUG_ASSERT(log);
- log->report(ERROR_LEVEL, ER_NO_DEFAULT_FOR_FIELD,
+ error= ER_NO_DEFAULT_FOR_FIELD;
+ log->report(ERROR_LEVEL, error,
"Field `%s` of table `%s`.`%s` "
"has no default value and cannot be NULL",
f->field_name, table->s->db.str,
table->s->table_name.str);
- error = ER_NO_DEFAULT_FOR_FIELD;
+ my_error(error, MYF(0), f->field_name);
}
else
f->set_default();
diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc
index 15d7d97affd..3467f6fd67c 100644
--- a/sql/rpl_rli.cc
+++ b/sql/rpl_rli.cc
@@ -166,7 +166,7 @@ int init_relay_log_info(Relay_log_info* rli,
{
sql_print_error("Failed to create a new relay log info file (\
file '%s', errno %d)", fname, my_errno);
- msg= current_thd->net.last_error;
+ msg= current_thd->main_da.message();
goto err;
}
if (init_io_cache(&rli->info_file, info_fd, IO_SIZE*2, READ_CACHE, 0L,0,
@@ -174,7 +174,7 @@ file '%s', errno %d)", fname, my_errno);
{
sql_print_error("Failed to create a cache on relay log info file '%s'",
fname);
- msg= current_thd->net.last_error;
+ msg= current_thd->main_da.message();
goto err;
}
diff --git a/sql/slave.cc b/sql/slave.cc
index 0421c567c65..b1f25ee58da 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -981,17 +981,24 @@ static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db,
}
thd->query= query;
thd->is_slave_error = 0;
- thd->net.no_send_ok = 1;
bzero((char*) &tables,sizeof(tables));
tables.db = (char*)db;
tables.alias= tables.table_name= (char*)table_name;
/* Drop the table if 'overwrite' is true */
- if (overwrite && mysql_rm_table(thd,&tables,1,0)) /* drop if exists */
+ if (overwrite)
{
- sql_print_error("create_table_from_dump: failed to drop the table");
- goto err;
+ if (mysql_rm_table(thd,&tables,1,0)) /* drop if exists */
+ {
+ sql_print_error("create_table_from_dump: failed to drop the table");
+ goto err;
+ }
+ else
+ {
+ /* Clear the OK result of mysql_rm_table(). */
+ thd->main_da.reset_diagnostics_area();
+ }
}
/* Create the table. We do not want to log the "create table" statement */
@@ -1012,6 +1019,7 @@ static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db,
if (thd->is_slave_error)
goto err; // mysql_parse took care of the error send
+ thd->main_da.reset_diagnostics_area(); /* cleanup from CREATE_TABLE */
thd->proc_info = "Opening master dump table";
/*
Note: If this function starts to fail for MERGE tables,
@@ -1055,7 +1063,6 @@ static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db,
err:
close_thread_tables(thd);
- thd->net.no_send_ok = 0;
DBUG_RETURN(error);
}
@@ -1107,7 +1114,6 @@ int fetch_master_table(THD *thd, const char *db_name, const char *table_name,
error = 0;
err:
- thd->net.no_send_ok = 0; // Clear up garbage after create_table_from_dump
if (!called_connected)
mysql_close(mysql);
if (errmsg && thd->vio_ok())
@@ -1721,26 +1727,31 @@ static int has_temporary_error(THD *thd)
DBUG_ENTER("has_temporary_error");
if (thd->is_fatal_error)
- {
- DBUG_PRINT("info", ("thd->net.last_errno: %s", ER(thd->net.last_errno)));
DBUG_RETURN(0);
- }
DBUG_EXECUTE_IF("all_errors_are_temporary_errors",
- if (thd->net.last_errno)
- thd->net.last_errno= ER_LOCK_DEADLOCK;);
+ if (thd->main_da.is_error())
+ {
+ thd->clear_error();
+ my_error(ER_LOCK_DEADLOCK, MYF(0));
+ });
+
+ /*
+ If there is no message in THD, we can't say if it's a temporary
+ error or not. This is currently the case for Incident_log_event,
+ which sets no message. Return FALSE.
+ */
+ if (!thd->is_error())
+ DBUG_RETURN(0);
/*
Temporary error codes:
currently, InnoDB deadlock detected by InnoDB or lock
wait timeout (innodb_lock_wait_timeout exceeded
*/
- if (thd->net.last_errno == ER_LOCK_DEADLOCK ||
- thd->net.last_errno == ER_LOCK_WAIT_TIMEOUT)
- {
- DBUG_PRINT("info", ("thd->net.last_errno: %s", ER(thd->net.last_errno)));
+ if (thd->main_da.sql_errno() == ER_LOCK_DEADLOCK ||
+ thd->main_da.sql_errno() == ER_LOCK_WAIT_TIMEOUT)
DBUG_RETURN(1);
- }
#ifdef HAVE_NDB_BINLOG
/*
@@ -2551,20 +2562,21 @@ Slave SQL thread aborted. Can't execute init_slave query");
*/
uint32 const last_errno= rli->last_error().number;
- DBUG_PRINT("info", ("thd->net.last_errno=%d; rli->last_error.number=%d",
- thd->net.last_errno, last_errno));
- if (thd->net.last_errno != 0)
+ if (thd->is_error())
{
- char const *const errmsg=
- thd->net.last_error ? thd->net.last_error : "<no message>";
+ char const *const errmsg= thd->main_da.message();
+
+ DBUG_PRINT("info",
+ ("thd->main_da.sql_errno()=%d; rli->last_error.number=%d",
+ thd->main_da.sql_errno(), last_errno));
if (last_errno == 0)
{
- rli->report(ERROR_LEVEL, thd->net.last_errno, errmsg);
+ rli->report(ERROR_LEVEL, thd->main_da.sql_errno(), errmsg);
}
- else if (last_errno != thd->net.last_errno)
+ else if (last_errno != thd->main_da.sql_errno())
{
sql_print_error("Slave (additional info): %s Error_code: %d",
- errmsg, thd->net.last_errno);
+ errmsg, thd->main_da.sql_errno());
}
}
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 4b432cef5cd..2e36593a126 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -1202,12 +1202,6 @@ sp_head::execute(THD *thd)
err_status= i->execute(thd, &ip);
- /*
- If this SP instruction have sent eof, it has caused no_send_error to be
- set. Clear it back to allow the next instruction to send error. (multi-
- statement execution code clears no_send_error between statements too)
- */
- thd->net.no_send_error= 0;
if (i->free_list)
cleanup_items(i->free_list);
@@ -2762,14 +2756,22 @@ sp_instr_stmt::execute(THD *thd, uint *nextp)
thd->query, thd->query_length) <= 0)
{
res= m_lex_keeper.reset_lex_and_exec_core(thd, nextp, FALSE, this);
+
+ if (thd->main_da.is_eof())
+ net_end_statement(thd);
+
+ query_cache_end_of_result(thd);
+
if (!res && unlikely(thd->enable_slow_log))
log_slow_statement(thd);
- query_cache_end_of_result(thd);
}
else
*nextp= m_ip+1;
thd->query= query;
thd->query_length= query_length;
+
+ if (!thd->is_error())
+ thd->main_da.reset_diagnostics_area();
}
DBUG_RETURN(res);
}
diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc
index 70a043c4fac..8395648689b 100644
--- a/sql/sp_rcontext.cc
+++ b/sql/sp_rcontext.cc
@@ -287,7 +287,6 @@ sp_rcontext::find_handler(THD *thd, uint sql_errno,
sql_errno The error code
level Warning level
thd The current thread
- - thd->net.report_error is an optional output.
RETURN
TRUE if a handler was found.
@@ -298,7 +297,6 @@ sp_rcontext::handle_error(uint sql_errno,
MYSQL_ERROR::enum_warning_level level,
THD *thd)
{
- bool handled= FALSE;
MYSQL_ERROR::enum_warning_level elevated_level= level;
@@ -310,25 +308,7 @@ sp_rcontext::handle_error(uint sql_errno,
elevated_level= MYSQL_ERROR::WARN_LEVEL_ERROR;
}
- if (find_handler(thd, sql_errno, elevated_level))
- {
- if (elevated_level == MYSQL_ERROR::WARN_LEVEL_ERROR)
- {
- /*
- Forces to abort the current instruction execution.
- NOTE: This code is altering the original meaning of
- the net.report_error flag (send an error to the client).
- In the context of stored procedures with error handlers,
- the flag is reused to cause error propagation,
- until the error handler is reached.
- No messages will be sent to the client in that context.
- */
- thd->net.report_error= 1;
- }
- handled= TRUE;
- }
-
- return handled;
+ return find_handler(thd, sql_errno, elevated_level);
}
void
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 519ca429aa6..9f6442d5c49 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -695,7 +695,7 @@ my_bool acl_reload(THD *thd)
if (simple_open_n_lock_tables(thd, tables))
{
sql_print_error("Fatal error: Can't open and lock privilege tables: %s",
- thd->net.last_error);
+ thd->main_da.message());
goto end;
}
@@ -3800,11 +3800,11 @@ my_bool grant_reload(THD *thd)
close_thread_tables(thd);
/*
- It is ok failing to load procs_priv table because we may be
+ It is OK failing to load procs_priv table because we may be
working with 4.1 privilege tables.
*/
if (grant_reload_procs_priv(thd))
- my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0), "mysql.procs_priv");
+ return_val= 1;
rw_wrlock(&LOCK_grant);
grant_version++;
@@ -5693,9 +5693,6 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list)
if (result)
my_error(ER_CANNOT_USER, MYF(0), "DROP USER", wrong_users.c_ptr_safe());
- DBUG_PRINT("info", ("thd->net.last_errno: %d", thd->net.last_errno));
- DBUG_PRINT("info", ("thd->net.last_error: %s", thd->net.last_error));
-
write_bin_log(thd, FALSE, thd->query, thd->query_length);
rw_unlock(&LOCK_grant);
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index ba8b7fc1330..b15082f1f6c 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -491,9 +491,28 @@ static TABLE_SHARE
int tmp;
DBUG_ENTER("get_table_share_with_create");
- if ((share= get_table_share(thd, table_list, key, key_length,
- db_flags, error)) ||
- thd->net.last_errno != ER_NO_SUCH_TABLE)
+ share= get_table_share(thd, table_list, key, key_length, db_flags, error);
+ /*
+ If share is not NULL, we found an existing share.
+
+ If share is NULL, and there is no error, we're inside
+ pre-locking, which silences 'ER_NO_SUCH_TABLE' errors
+ with the intention to silently drop non-existing tables
+ from the pre-locking list. In this case we still need to try
+ auto-discover before returning a NULL share.
+
+ If share is NULL and the error is ER_NO_SUCH_TABLE, this is
+ the same as above, only that the error was not silenced by
+ pre-locking. Once again, we need to try to auto-discover
+ the share.
+
+ Finally, if share is still NULL, it's a real error and we need
+ to abort.
+
+ @todo Rework alternative ways to deal with ER_NO_SUCH TABLE.
+ */
+ if (share || thd->is_error() && thd->main_da.sql_errno() != ER_NO_SUCH_TABLE)
+
DBUG_RETURN(share);
/* Table didn't exist. Check if some engine can provide it */
@@ -502,9 +521,13 @@ static TABLE_SHARE
{
/*
No such table in any engine.
- Hide "Table doesn't exist" errors if table belong to view
+ Hide "Table doesn't exist" errors if the table belongs to a view.
+ The check for thd->is_error() is necessary to not push an
+ unwanted error in case of pre-locking, which silences
+ "no such table" errors.
+ @todo Rework the alternative ways to deal with ER_NO_SUCH TABLE.
*/
- if (table_list->belong_to_view)
+ if (thd->is_error() && table_list->belong_to_view)
{
TABLE_LIST *view= table_list->belong_to_view;
thd->clear_error();
diff --git a/sql/sql_binlog.cc b/sql/sql_binlog.cc
index fa6aa8f5881..77c5155b41b 100644
--- a/sql/sql_binlog.cc
+++ b/sql/sql_binlog.cc
@@ -40,13 +40,6 @@ void mysql_client_binlog_statement(THD* thd)
if (check_global_access(thd, SUPER_ACL))
DBUG_VOID_RETURN;
- /*
- Temporarily turn off send_ok, since different events handle this
- differently
- */
- my_bool nsok= thd->net.no_send_ok;
- thd->net.no_send_ok= TRUE;
-
size_t coded_len= thd->lex->comment.length + 1;
size_t decoded_len= base64_needed_decoded_length(coded_len);
DBUG_ASSERT(coded_len > 0);
@@ -193,20 +186,11 @@ void mysql_client_binlog_statement(THD* thd)
}
}
- /*
- Restore setting of no_send_ok
- */
- thd->net.no_send_ok= nsok;
DBUG_PRINT("info",("binlog base64 execution finished successfully"));
send_ok(thd);
end:
- /*
- Restore setting of no_send_ok
- */
- thd->net.no_send_ok= nsok;
-
delete desc;
my_free(buf, MYF(MY_ALLOW_ZERO_PTR));
DBUG_VOID_RETURN;
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index 56b048a4f9d..f1803a329c5 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -1403,6 +1403,7 @@ def_week_frmt: %lu",
thd->limit_found_rows = query->found_rows();
thd->status_var.last_query_cost= 0.0;
+ thd->main_da.disable_status();
BLOCK_UNLOCK_RD(query_block);
DBUG_RETURN(1); // Result sent to client
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index f59a848a242..b68a532a2dc 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -351,6 +351,124 @@ char *thd_security_context(THD *thd, char *buffer, unsigned int length,
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()
+{
+#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_total_warn_count= 0;
+#endif
+ is_sent= FALSE;
+ /** Tiny reset in debug mode to see garbage right away */
+ m_status= DA_EMPTY;
+}
+
+
+/**
+ 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,
+ ulong last_insert_id_arg,
+ const char *message_arg)
+{
+ DBUG_ASSERT(! is_set());
+#ifdef DBUG_OFF
+ /* In production, refuse to overwrite an error with an OK packet. */
+ if (is_error())
+ return;
+#endif
+ /** Only allowed to report success if has not yet reported an error */
+
+ m_server_status= thd->server_status;
+ m_total_warn_count= thd->total_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));
+ else
+ m_message[0]= '\0';
+ m_status= DA_OK;
+}
+
+
+/**
+ Set EOF status.
+*/
+
+void
+Diagnostics_area::set_eof_status(THD *thd)
+{
+ /** Only allowed to report eof if has not yet reported an error */
+
+ DBUG_ASSERT(! is_set());
+#ifdef DBUG_OFF
+ /* In production, refuse to overwrite an error with an EOF packet. */
+ if (is_error())
+ return;
+#endif
+
+ 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_total_warn_count= thd->spcont ? 0 : thd->total_warn_count;
+
+ m_status= DA_EOF;
+}
+
+/**
+ Set ERROR status.
+*/
+
+void
+Diagnostics_area::set_error_status(THD *thd, uint sql_errno_arg,
+ const char *message_arg)
+{
+ /*
+ 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);
+
+ m_sql_errno= sql_errno_arg;
+ strmake(m_message, message_arg, sizeof(m_message));
+
+ m_status= DA_ERROR;
+}
+
+
+/**
+ 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()
@@ -431,7 +549,6 @@ THD::THD()
net.vio=0;
#endif
client_capabilities= 0; // minimalistic client
- net.last_error[0]=0; // If error on boot
#ifdef HAVE_QUERY_CACHE
query_cache_init_query(&net); // If error on boot
#endif
@@ -1324,12 +1441,12 @@ void select_send::abort()
{
DBUG_ENTER("select_send::abort");
if (is_result_set_started && thd->spcont &&
- thd->spcont->find_handler(thd, thd->net.last_errno,
+ thd->spcont->find_handler(thd, thd->main_da.sql_errno(),
MYSQL_ERROR::WARN_LEVEL_ERROR))
{
/*
We're executing a stored procedure, have an open result
- set, an SQL exception conditiona and a handler for it.
+ set, an SQL exception condition and a handler for it.
In this situation we must abort the current statement,
silence the error and start executing the continue/exit
handler.
@@ -1337,9 +1454,7 @@ void select_send::abort()
otherwise the client will hang due to the violation of the
client/server protocol.
*/
- thd->net.report_error= 0;
- send_eof();
- thd->net.report_error= 1; // Abort SP
+ thd->protocol->end_partial_result_set(thd);
}
DBUG_VOID_RETURN;
}
@@ -1391,12 +1506,14 @@ bool select_send::send_data(List<Item> &items)
}
}
thd->sent_row_count++;
- if (!thd->vio_ok())
- DBUG_RETURN(0);
- if (! thd->is_error())
+ if (thd->is_error())
+ {
+ protocol->remove_last_row();
+ DBUG_RETURN(1);
+ }
+ if (thd->vio_ok())
DBUG_RETURN(protocol->write());
- protocol->remove_last_row();
- DBUG_RETURN(1);
+ DBUG_RETURN(0);
}
bool select_send::send_eof()
@@ -1414,14 +1531,9 @@ bool select_send::send_eof()
mysql_unlock_tables(thd, thd->lock);
thd->lock=0;
}
- if (! thd->is_error())
- {
- ::send_eof(thd);
- is_result_set_started= 0;
- return 0;
- }
- else
- return 1;
+ ::send_eof(thd);
+ is_result_set_started= 0;
+ return FALSE;
}
@@ -2701,7 +2813,6 @@ void THD::reset_sub_statement_state(Sub_statement_state *backup,
{
backup->options= options;
backup->in_sub_stmt= in_sub_stmt;
- backup->no_send_ok= net.no_send_ok;
backup->enable_slow_log= enable_slow_log;
backup->limit_found_rows= limit_found_rows;
backup->examined_row_count= examined_row_count;
@@ -2732,9 +2843,6 @@ void THD::reset_sub_statement_state(Sub_statement_state *backup,
cuted_fields= 0;
transaction.savepoints= 0;
first_successful_insert_id_in_cur_stmt= 0;
-
- /* Surpress OK packets in case if we will execute statements */
- net.no_send_ok= TRUE;
}
@@ -2757,7 +2865,6 @@ void THD::restore_sub_statement_state(Sub_statement_state *backup)
transaction.savepoints= backup->savepoints;
options= backup->options;
in_sub_stmt= backup->in_sub_stmt;
- net.no_send_ok= backup->no_send_ok;
enable_slow_log= backup->enable_slow_log;
first_successful_insert_id_in_prev_stmt=
backup->first_successful_insert_id_in_prev_stmt;
diff --git a/sql/sql_class.h b/sql/sql_class.h
index c5b70cfa687..d46557acb4c 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -913,7 +913,6 @@ public:
uint in_sub_stmt;
bool enable_slow_log;
bool last_insert_id_used;
- my_bool no_send_ok;
SAVEPOINT *savepoints;
};
@@ -976,6 +975,123 @@ public:
/**
+ 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 send_ok(). */
+ DA_OK,
+ /** Set whenever one calls send_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,
+ ulong 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; }
+
+ ulong last_insert_id() const
+ { DBUG_ASSERT(m_status == DA_OK); return m_last_insert_id; }
+
+ uint total_warn_count() const
+ {
+ DBUG_ASSERT(m_status == DA_OK || m_status == DA_EOF);
+ return m_total_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|= ...
+ send_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().
+ */
+ ulong m_last_insert_id;
+ /** The total number of warnings. */
+ uint m_total_warn_count;
+ enum_diagnostics_status m_status;
+ /**
+ @todo: the following THD members belong here:
+ - warn_list, warn_count,
+ */
+};
+
+
+/**
@class THD
For each client connection we create a separate thread with THD serving as
a thread/connection descriptor
@@ -1400,6 +1516,7 @@ public:
List <MYSQL_ERROR> warn_list;
uint warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_END];
uint total_warn_count;
+ Diagnostics_area main_da;
/*
Id of current query. Statement can be reused to execute several queries
query_id is global in context of the whole MySQL server.
@@ -1714,12 +1831,18 @@ public:
CHANGED_TABLE_LIST * changed_table_dup(const char *key, long key_length);
int send_explain_fields(select_result *result);
#ifndef EMBEDDED_LIBRARY
+ /**
+ Clear the current error, if any.
+ We do not clear is_fatal_error or is_fatal_sub_stmt_error since we
+ assume this is never called if the fatal error is set.
+ @todo: To silence an error, one should use Internal_error_handler
+ mechanism. In future this function will be removed.
+ */
inline void clear_error()
{
DBUG_ENTER("clear_error");
- net.last_error[0]= 0;
- net.last_errno= 0;
- net.report_error= 0;
+ if (main_da.is_error())
+ main_da.reset_diagnostics_area();
is_slave_error= 0;
DBUG_VOID_RETURN;
}
@@ -1728,10 +1851,14 @@ public:
void clear_error();
inline bool vio_ok() const { return true; }
#endif
+ /**
+ Mark the current error as fatal. Warning: this does not
+ set any error, it sets a property of the error, so must be
+ followed or prefixed with my_error().
+ */
inline void fatal_error()
{
is_fatal_error= 1;
- net.report_error= 1;
DBUG_PRINT("error",("Fatal error set"));
}
/**
@@ -1747,7 +1874,7 @@ public:
To raise this flag, use my_error().
*/
- inline bool is_error() const { return net.report_error; }
+ inline bool is_error() const { return main_da.is_error(); }
inline CHARSET_INFO *charset() { return variables.character_set_client; }
void update_charset();
@@ -1971,6 +2098,24 @@ private:
};
+/** A short cut for thd->main_da.set_ok_status(). */
+
+inline void
+send_ok(THD *thd, ha_rows affected_rows= 0, ulonglong id= 0,
+ const char *message= NULL)
+{
+ thd->main_da.set_ok_status(thd, affected_rows, id, message);
+}
+
+
+/** A short cut for thd->main_da.set_eof_status(). */
+
+inline void
+send_eof(THD *thd)
+{
+ thd->main_da.set_eof_status(thd);
+}
+
#define tmp_disable_binlog(A) \
{ulonglong tmp_disable_binlog__save_options= (A)->options; \
(A)->options&= ~OPTION_BIN_LOG
@@ -2508,6 +2653,7 @@ public:
void send_error(uint errcode,const char *err);
int do_deletes();
bool send_eof();
+ virtual void abort();
};
@@ -2550,6 +2696,7 @@ public:
void send_error(uint errcode,const char *err);
int do_updates (bool from_send_error);
bool send_eof();
+ virtual void abort();
};
class my_var : public Sql_alloc {
diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc
index 76237576764..309a1c7ab5d 100644
--- a/sql/sql_connect.cc
+++ b/sql/sql_connect.cc
@@ -948,19 +948,20 @@ bool setup_connection_thread_globals(THD *thd)
bool login_connection(THD *thd)
{
NET *net= &thd->net;
+ int error;
DBUG_ENTER("login_connection");
DBUG_PRINT("info", ("login_connection called by thread %lu",
thd->thread_id));
- net->no_send_error= 0;
-
/* Use "connect_timeout" value during connection phase */
my_net_set_read_timeout(net, connect_timeout);
my_net_set_write_timeout(net, connect_timeout);
- if (check_connection(thd))
+ error= check_connection(thd);
+ net_end_statement(thd);
+
+ if (error)
{ // Wrong permissions
- net_send_error(thd);
#ifdef __NT__
if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE)
my_sleep(1000); /* must wait after eof() */
@@ -989,13 +990,12 @@ void end_connection(THD *thd)
if (thd->user_connect)
decrease_user_connections(thd->user_connect);
- if (thd->killed ||
- net->error && net->vio != 0 && thd->is_error())
+ if (thd->killed || net->error && net->vio != 0)
{
statistic_increment(aborted_threads,&LOCK_status);
}
- if (net->error && net->vio != 0 && thd->is_error())
+ if (net->error && net->vio != 0)
{
if (!thd->killed && thd->variables.log_warnings > 1)
{
@@ -1005,11 +1005,9 @@ void end_connection(THD *thd)
thd->thread_id,(thd->db ? thd->db : "unconnected"),
sctx->user ? sctx->user : "unauthenticated",
sctx->host_or_ip,
- (net->last_errno ? ER(net->last_errno) :
+ (thd->main_da.is_error() ? thd->main_da.message() :
ER(ER_UNKNOWN_ERROR)));
}
-
- net_send_error(thd, net->last_errno, NullS);
}
}
@@ -1045,24 +1043,14 @@ static void prepare_new_connection_state(THD* thd)
if (sys_init_connect.value_length && !(sctx->master_access & SUPER_ACL))
{
execute_init_command(thd, &sys_init_connect, &LOCK_sys_init_connect);
- /*
- execute_init_command calls net_send_error.
- If there was an error during execution of the init statements,
- the error at this moment is present in thd->net.last_error and also
- thd->is_slave_error and thd->net.report_error are set.
- net_send_error sends the contents of thd->net.last_error and
- clears thd->net.report_error. It doesn't, however, clean
- thd->is_slave_error or thd->net.last_error. Here we make use of this
- fact.
- */
- if (thd->is_slave_error)
+ if (thd->is_error())
{
thd->killed= THD::KILL_CONNECTION;
sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION),
thd->thread_id,(thd->db ? thd->db : "unconnected"),
sctx->user ? sctx->user : "unauthenticated",
sctx->host_or_ip, "init_connect command failed");
- sql_print_warning("%s", thd->net.last_error);
+ sql_print_warning("%s", thd->main_da.message());
}
thd->proc_info=0;
thd->set_time();
@@ -1129,7 +1117,6 @@ pthread_handler_t handle_one_connection(void *arg)
while (!net->error && net->vio != 0 &&
!(thd->killed == THD::KILL_CONNECTION))
{
- net->no_send_error= 0;
if (do_command(thd))
break;
}
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index ad4e0d803eb..d425510320e 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -921,6 +921,8 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
{
ha_drop_database(path);
query_cache_invalidate1(db);
+ (void) sp_drop_db_routines(thd, db); /* @todo Do not ignore errors */
+ Events::drop_schema_events(thd, db);
error = 0;
}
}
@@ -956,6 +958,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
/* These DDL methods and logging protected with LOCK_mysql_create_db */
mysql_bin_log.write(&qinfo);
}
+ thd->clear_error();
thd->server_status|= SERVER_STATUS_DB_DROPPED;
send_ok(thd, (ulong) deleted);
thd->server_status&= ~SERVER_STATUS_DB_DROPPED;
@@ -999,8 +1002,6 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
}
exit:
- (void)sp_drop_db_routines(thd, db); /* QQ Ignore errors for now */
- Events::drop_schema_events(thd, db);
/*
If this database was the client's selected database, we silently
change the client's selected database to nothing (to have an empty
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 509e736f6e7..a73963d7f86 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -728,6 +728,14 @@ void multi_delete::send_error(uint errcode,const char *err)
/* First send error what ever it is ... */
my_message(errcode, err, MYF(0));
+ DBUG_VOID_RETURN;
+}
+
+
+void multi_delete::abort()
+{
+ DBUG_ENTER("multi_delete::abort");
+
/* the error was handled or nothing deleted and no side effects return */
if (error_handled ||
!thd->transaction.stmt.modified_non_trans_table && !deleted)
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index ea7545fe5cb..10b42e11b26 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -147,8 +147,9 @@ exit:
/* Hide "Unknown column" or "Unknown function" error */
if (orig_table_list->view)
{
- if (thd->net.last_errno == ER_BAD_FIELD_ERROR ||
- thd->net.last_errno == ER_SP_DOES_NOT_EXIST)
+ if (thd->is_error() &&
+ (thd->main_da.sql_errno() == ER_BAD_FIELD_ERROR ||
+ thd->main_da.sql_errno() == ER_SP_DOES_NOT_EXIST))
{
thd->clear_error();
my_error(ER_VIEW_INVALID, MYF(0), orig_table_list->db,
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 425c5a33329..051950a0974 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -1916,7 +1916,7 @@ bool delayed_get_table(THD *thd, TABLE_LIST *table_list)
main thread. Use of my_message will enable stored
procedures continue handlers.
*/
- my_message(di->thd.net.last_errno, di->thd.net.last_error,
+ my_message(di->thd.main_da.sql_errno(), di->thd.main_da.message(),
MYF(0));
}
di->unlock();
@@ -1993,7 +1993,7 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd)
goto error;
if (dead)
{
- my_message(thd.net.last_errno, thd.net.last_error, MYF(0));
+ my_message(thd.main_da.sql_errno(), thd.main_da.message(), MYF(0));
goto error;
}
}
@@ -2252,7 +2252,9 @@ pthread_handler_t handle_delayed_insert(void *arg)
#if !defined( __WIN__) /* Win32 calls this in pthread_create */
if (my_thread_init())
{
- strmov(thd->net.last_error,ER(thd->net.last_errno=ER_OUT_OF_RESOURCES));
+ /* Can't use my_error since store_globals has not yet been called */
+ thd->main_da.set_error_status(thd, ER_OUT_OF_RESOURCES,
+ ER(ER_OUT_OF_RESOURCES));
goto end;
}
#endif
@@ -2261,8 +2263,10 @@ pthread_handler_t handle_delayed_insert(void *arg)
thd->thread_stack= (char*) &thd;
if (init_thr_lock() || thd->store_globals())
{
+ /* Can't use my_error since store_globals has perhaps failed */
+ thd->main_da.set_error_status(thd, ER_OUT_OF_RESOURCES,
+ ER(ER_OUT_OF_RESOURCES));
thd->fatal_error();
- strmov(thd->net.last_error,ER(thd->net.last_errno=ER_OUT_OF_RESOURCES));
goto err;
}
@@ -2665,7 +2669,7 @@ bool Delayed_insert::handle_inserts(void)
{
/* This should never happen */
table->file->print_error(error,MYF(0));
- sql_print_error("%s",thd.net.last_error);
+ sql_print_error("%s", thd.main_da.message());
DBUG_PRINT("error", ("HA_EXTRA_NO_CACHE failed in loop"));
goto err;
}
@@ -2706,7 +2710,7 @@ bool Delayed_insert::handle_inserts(void)
if ((error=table->file->extra(HA_EXTRA_NO_CACHE)))
{ // This shouldn't happen
table->file->print_error(error,MYF(0));
- sql_print_error("%s",thd.net.last_error);
+ sql_print_error("%s", thd.main_da.message());
DBUG_PRINT("error", ("HA_EXTRA_NO_CACHE failed after loop"));
goto err;
}
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index df425557bdf..58084bdd067 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -328,7 +328,6 @@ void execute_init_command(THD *thd, sys_var_str *init_command_var,
*/
save_vio= thd->net.vio;
thd->net.vio= 0;
- thd->net.no_send_error= 0;
dispatch_command(COM_QUERY, thd,
init_command_var->value,
init_command_var->value_length);
@@ -397,8 +396,8 @@ pthread_handler_t handle_bootstrap(void *arg)
/* purecov: begin tested */
if (net_realloc(&(thd->net), 2 * thd->net.max_packet))
{
- net_send_error(thd, ER_NET_PACKET_TOO_LARGE, NullS);
- thd->fatal_error();
+ net_end_statement(thd);
+ bootstrap_error= 1;
break;
}
buff= (char*) thd->net.buff;
@@ -406,7 +405,7 @@ pthread_handler_t handle_bootstrap(void *arg)
length+= (ulong) strlen(buff + length);
/* purecov: end */
}
- if (thd->is_fatal_error)
+ if (bootstrap_error)
break; /* purecov: inspected */
while (length && (my_isspace(thd->charset(), buff[length-1]) ||
@@ -433,16 +432,11 @@ pthread_handler_t handle_bootstrap(void *arg)
mysql_parse(thd, thd->query, length, & found_semicolon);
close_thread_tables(thd); // Free tables
- if (thd->is_fatal_error)
- break;
+ bootstrap_error= thd->is_error();
+ net_end_statement(thd);
- if (thd->is_error())
- {
- /* The query failed, send error to log and abort bootstrap */
- net_send_error(thd);
- thd->fatal_error();
+ if (bootstrap_error)
break;
- }
free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
#ifdef USING_TRANSACTIONS
@@ -451,9 +445,6 @@ pthread_handler_t handle_bootstrap(void *arg)
}
end:
- /* Remember the exit code of bootstrap */
- bootstrap_error= thd->is_fatal_error;
-
net_end(&thd->net);
thd->cleanup();
delete thd;
@@ -712,7 +703,12 @@ bool do_command(THD *thd)
*/
my_net_set_read_timeout(net, thd->variables.net_wait_timeout);
+ /*
+ XXX: this code is here only to clear possible errors of init_connect.
+ Consider moving to init_connect() instead.
+ */
thd->clear_error(); // Clear error message
+ thd->main_da.reset_diagnostics_area();
net_new_transaction(net);
if ((packet_length=my_net_read(net)) == packet_error)
@@ -723,10 +719,13 @@ bool do_command(THD *thd)
/* Check if we can continue without closing the connection */
+ /* The error must be set. */
+ DBUG_ASSERT(thd->is_error());
+ net_end_statement(thd);
+
if (net->error != 3)
DBUG_RETURN(TRUE); // We have to close it.
- net_send_error(thd, net->last_errno, NullS);
net->error= 0;
DBUG_RETURN(FALSE);
}
@@ -860,7 +859,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
db.length= db_len;
tbl_name= strmake(db.str, packet + 1, db_len)+1;
strmake(tbl_name, packet + db_len + 2, tbl_len);
- mysql_table_dump(thd, &db, tbl_name);
+ if (mysql_table_dump(thd, &db, tbl_name) == 0)
+ thd->main_da.disable_status();
break;
}
case COM_CHANGE_USER:
@@ -1024,7 +1024,9 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
while (!thd->killed && found_semicolon && ! thd->is_error())
{
char *next_packet= (char*) found_semicolon;
- net->no_send_error= 0;
+
+ net_end_statement(thd);
+ query_cache_end_of_result(thd);
/*
Multiple queries exits, execute them individually
*/
@@ -1125,6 +1127,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
/* We don't calculate statistics for this command */
general_log_print(thd, command, NullS);
net->error=0; // Don't give 'abort' message
+ thd->main_da.disable_status(); // Don't send anything back
error=TRUE; // End server
break;
@@ -1241,16 +1244,6 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
DBUG_PRINT("quit",("Got shutdown command for level %u", level));
general_log_print(thd, command, NullS);
send_eof(thd);
-#ifdef __WIN__
- sleep(1); // must wait after eof()
-#endif
- /*
- The client is next going to send a COM_QUIT request (as part of
- mysql_close()). Make the life simpler for the client by sending
- the response for the coming COM_QUIT in advance
- */
- send_eof(thd);
- close_connection(thd, 0, 1);
close_thread_tables(thd); // Free before kill
kill_mysql();
error=TRUE;
@@ -1263,13 +1256,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
ulong uptime;
uint length;
ulonglong queries_per_second1000;
-#ifndef EMBEDDED_LIBRARY
char buff[250];
uint buff_len= sizeof(buff);
-#else
- char *buff= thd->net.last_error;
- uint buff_len= sizeof(thd->net.last_error);
-#endif
general_log_print(thd, command, NullS);
status_var_increment(thd->status_var.com_stat[SQLCOM_SHOW_STATUS]);
@@ -1291,6 +1279,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
cached_open_tables(),
(uint) (queries_per_second1000 / 1000),
(uint) (queries_per_second1000 % 1000));
+#ifdef EMBEDDED_LIBRARY
+ /* Store the buffer in permanent memory */
+ send_ok(thd, 0, 0, buff);
+#endif
#ifdef SAFEMALLOC
if (sf_malloc_cur_memory) // Using SAFEMALLOC
{
@@ -1303,7 +1295,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
#endif
#ifndef EMBEDDED_LIBRARY
VOID(my_net_write(net, (uchar*) buff, length));
- VOID(net_flush(net));
+ VOID(net_flush(net));
+ thd->main_da.disable_status();
#endif
break;
}
@@ -1383,10 +1376,19 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
thd->transaction.xid_state.xid.null();
/* report error issued during command execution */
- if (thd->killed_errno() && ! thd->is_error())
- thd->send_kill_message();
- if (thd->is_error())
- net_send_error(thd);
+ if (thd->killed_errno())
+ {
+ if (! thd->main_da.is_set())
+ thd->send_kill_message();
+ }
+ if (thd->killed == THD::KILL_QUERY || thd->killed == THD::KILL_BAD_DATA)
+ {
+ thd->killed= THD::NOT_KILLED;
+ thd->mysys_var->abort= 0;
+ }
+
+ net_end_statement(thd);
+ query_cache_end_of_result(thd);
log_slow_statement(thd);
@@ -1756,7 +1758,6 @@ mysql_execute_command(THD *thd)
SELECT_LEX_UNIT *unit= &lex->unit;
/* Saved variable value */
DBUG_ENTER("mysql_execute_command");
- thd->net.no_send_error= 0;
#ifdef WITH_PARTITION_STORAGE_ENGINE
thd->work_part_info= 0;
#endif
@@ -2992,13 +2993,9 @@ end_with_restore_list:
SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK |
OPTION_SETUP_TABLES_DONE,
del_result, unit, select_lex);
- res|= thd->net.report_error;
- if (unlikely(res))
- {
- /* If we had a another error reported earlier then this will be ignored */
- del_result->send_error(ER_UNKNOWN_ERROR, "Execution of the query failed");
+ res|= thd->is_error();
+ if (res)
del_result->abort();
- }
delete del_result;
}
else
@@ -3931,8 +3928,6 @@ create_sp_error:
goto error;
}
- my_bool save_no_send_ok= thd->net.no_send_ok;
- thd->net.no_send_ok= TRUE;
if (sp->m_flags & sp_head::MULTI_RESULTS)
{
if (! (thd->client_capabilities & CLIENT_MULTI_RESULTS))
@@ -3942,7 +3937,6 @@ create_sp_error:
back
*/
my_error(ER_SP_BADSELECT, MYF(0), sp->m_qname.str);
- thd->net.no_send_ok= save_no_send_ok;
goto error;
}
/*
@@ -3958,7 +3952,6 @@ create_sp_error:
if (check_routine_access(thd, EXECUTE_ACL,
sp->m_db.str, sp->m_name.str, TRUE, FALSE))
{
- thd->net.no_send_ok= save_no_send_ok;
goto error;
}
#endif
@@ -3983,7 +3976,6 @@ create_sp_error:
thd->variables.select_limit= select_limit;
- thd->net.no_send_ok= save_no_send_ok;
thd->server_status&= ~bits_to_be_cleared;
if (!res)
@@ -4624,7 +4616,10 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables)
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_YES, str.ptr());
}
- result->send_eof();
+ if (res)
+ result->abort();
+ else
+ result->send_eof();
delete result;
}
else
@@ -5251,6 +5246,7 @@ void mysql_reset_thd_for_next_command(THD *thd)
{
DBUG_ENTER("mysql_reset_thd_for_next_command");
DBUG_ASSERT(!thd->spcont); /* not for substatements of routines */
+ DBUG_ASSERT(! thd->in_sub_stmt);
thd->free_list= 0;
thd->select_number= 1;
/*
@@ -5277,18 +5273,18 @@ void mysql_reset_thd_for_next_command(THD *thd)
}
DBUG_ASSERT(thd->security_ctx== &thd->main_security_ctx);
thd->thread_specific_used= FALSE;
- if (!thd->in_sub_stmt)
+
+ if (opt_bin_log)
{
- if (opt_bin_log)
- {
- reset_dynamic(&thd->user_var_events);
- thd->user_var_events_alloc= thd->mem_root;
- }
- thd->clear_error();
- thd->total_warn_count=0; // Warnings for this query
- thd->rand_used= 0;
- thd->sent_row_count= thd->examined_row_count= 0;
+ reset_dynamic(&thd->user_var_events);
+ thd->user_var_events_alloc= thd->mem_root;
}
+ thd->clear_error();
+ thd->main_da.reset_diagnostics_area();
+ thd->total_warn_count=0; // Warnings for this query
+ thd->rand_used= 0;
+ thd->sent_row_count= thd->examined_row_count= 0;
+
/*
Because we come here only for start of top-statements, binlog format is
constant inside a complex statement (using stored functions) etc.
@@ -5526,7 +5522,6 @@ void mysql_parse(THD *thd, const char *inBuf, uint length,
/* Actually execute the query */
lex->set_trg_event_type_for_tables();
mysql_execute_command(thd);
- query_cache_end_of_result(thd);
}
}
}
@@ -6378,8 +6373,10 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
}
if (thd)
{
- (void)acl_reload(thd);
- (void)grant_reload(thd);
+ if (acl_reload(thd))
+ result= 1;
+ if (grant_reload(thd))
+ result= 1;
}
if (tmp_thd)
{
@@ -6496,7 +6493,6 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
if (reset_master(thd))
{
result=1;
- thd->fatal_error(); // Ensure client get error
}
}
#endif
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index 64f96f342df..8ded0cacd77 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -2068,6 +2068,7 @@ char *generate_partition_syntax(partition_info *part_info,
default:
DBUG_ASSERT(0);
/* We really shouldn't get here, no use in continuing from here */
+ my_error(ER_OUT_OF_RESOURCES, MYF(0));
current_thd->fatal_error();
DBUG_RETURN(NULL);
}
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 9d4d62e57b6..52e6fcc5d58 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -230,6 +230,8 @@ static bool send_prep_stmt(Prepared_statement *stmt, uint columns)
NET *net= &stmt->thd->net;
uchar buff[12];
uint tmp;
+ int error;
+ THD *thd= stmt->thd;
DBUG_ENTER("send_prep_stmt");
buff[0]= 0; /* OK packet indicator */
@@ -244,11 +246,16 @@ static bool send_prep_stmt(Prepared_statement *stmt, uint columns)
Send types and names of placeholders to the client
XXX: fix this nasty upcast from List<Item_param> to List<Item>
*/
- DBUG_RETURN(my_net_write(net, buff, sizeof(buff)) ||
- (stmt->param_count &&
- stmt->thd->protocol_text.send_fields((List<Item> *)
- &stmt->lex->param_list,
- Protocol::SEND_EOF)));
+ error= my_net_write(net, buff, sizeof(buff));
+ if (stmt->param_count && ! error)
+ {
+ error= thd->protocol_text.send_fields((List<Item> *)
+ &stmt->lex->param_list,
+ Protocol::SEND_EOF);
+ }
+ /* Flag that a response has already been sent */
+ thd->main_da.disable_status();
+ DBUG_RETURN(error);
}
#else
static bool send_prep_stmt(Prepared_statement *stmt,
@@ -259,6 +266,7 @@ static bool send_prep_stmt(Prepared_statement *stmt,
thd->client_stmt_id= stmt->id;
thd->client_param_count= stmt->param_count;
thd->clear_error();
+ thd->main_da.disable_status();
return 0;
}
@@ -2526,6 +2534,8 @@ void mysql_stmt_close(THD *thd, char *packet)
DBUG_ASSERT(! (stmt->flags & (uint) Prepared_statement::IS_IN_USE));
(void) stmt->deallocate();
+ thd->main_da.disable_status();
+
DBUG_VOID_RETURN;
}
@@ -2590,6 +2600,8 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length)
DBUG_ENTER("mysql_stmt_get_longdata");
status_var_increment(thd->status_var.com_stmt_send_long_data);
+
+ thd->main_da.disable_status();
#ifndef EMBEDDED_LIBRARY
/* Minimal size of long data packet is 6 bytes */
if (packet_length < MYSQL_LONG_DATA_HEADER)
@@ -2664,11 +2676,7 @@ bool Select_fetch_protocol_binary::send_fields(List<Item> &list, uint flags)
bool Select_fetch_protocol_binary::send_eof()
{
- Protocol *save_protocol= thd->protocol;
-
- thd->protocol= &protocol;
::send_eof(thd);
- thd->protocol= save_protocol;
return FALSE;
}
@@ -3097,7 +3105,6 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
thd->query_length) <= 0)
{
error= mysql_execute_command(thd);
- query_cache_end_of_result(thd);
}
}
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 952b94e6b6d..cadc27638bd 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -898,7 +898,6 @@ JOIN::optimize()
}
if (res > 1)
{
- thd->fatal_error();
error= res;
DBUG_PRINT("error",("Error from opt_sum_query"));
DBUG_RETURN(1);
@@ -14454,6 +14453,7 @@ calc_group_buffer(JOIN *join,ORDER *group)
default:
/* This case should never be choosen */
DBUG_ASSERT(0);
+ my_error(ER_OUT_OF_RESOURCES, MYF(0));
join->thd->fatal_error();
}
}
diff --git a/sql/sql_servers.cc b/sql/sql_servers.cc
index 602c289a605..8203ca92eed 100644
--- a/sql/sql_servers.cc
+++ b/sql/sql_servers.cc
@@ -239,7 +239,7 @@ bool servers_reload(THD *thd)
if (simple_open_n_lock_tables(thd, tables))
{
sql_print_error("Can't open and lock privilege tables: %s",
- thd->net.last_error);
+ thd->main_da.message());
goto end;
}
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 9a7d7c59af3..36f9cc780bd 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -578,7 +578,8 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
/* Only one table for now, but VIEW can involve several tables */
if (open_normal_and_derived_tables(thd, table_list, 0))
{
- if (!table_list->view || thd->net.last_errno != ER_VIEW_INVALID)
+ if (!table_list->view ||
+ thd->is_error() && thd->main_da.sql_errno() != ER_VIEW_INVALID)
DBUG_RETURN(TRUE);
/*
@@ -786,10 +787,9 @@ mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild)
}
restore_record(table, s->default_values); // Get empty record
table->use_all_columns();
- if (thd->protocol->send_fields(&field_list, Protocol::SEND_DEFAULTS |
- Protocol::SEND_EOF))
+ if (thd->protocol->send_fields(&field_list, Protocol::SEND_DEFAULTS))
DBUG_VOID_RETURN;
- thd->protocol->flush();
+ send_eof(thd);
DBUG_VOID_RETURN;
}
@@ -2919,7 +2919,7 @@ static int fill_schema_table_names(THD *thd, TABLE *table,
default:
DBUG_ASSERT(0);
}
- if (thd->net.last_errno == ER_NO_SUCH_TABLE)
+ if (thd->is_error() && thd->main_da.sql_errno() == ER_NO_SUCH_TABLE)
{
thd->clear_error();
return 0;
@@ -3267,8 +3267,16 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
res= open_normal_and_derived_tables(thd, show_table_list,
MYSQL_LOCK_IGNORE_FLUSH);
lex->sql_command= save_sql_command;
-
- if (thd->net.last_errno == ER_NO_SUCH_TABLE)
+ /*
+ XXX: show_table_list has a flag i_is_requested,
+ and when it's set, open_normal_and_derived_tables()
+ can return an error without setting an error message
+ in THD, which is a hack. This is why we have to
+ check for res, then for thd->is_error() only then
+ for thd->main_da.sql_errno().
+ */
+ if (res && thd->is_error() &&
+ thd->main_da.sql_errno() == ER_NO_SUCH_TABLE)
{
/*
Hide error for not existing table.
@@ -3422,7 +3430,7 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables,
/*
there was errors during opening tables
*/
- const char *error= thd->net.last_error;
+ const char *error= thd->main_da.message();
if (tables->view)
table->field[3]->store(STRING_WITH_LEN("VIEW"), cs);
else if (tables->schema_table)
@@ -3624,7 +3632,7 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables,
rather than in SHOW COLUMNS
*/
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- thd->net.last_errno, thd->net.last_error);
+ thd->main_da.sql_errno(), thd->main_da.message());
thd->clear_error();
res= 0;
}
@@ -4098,9 +4106,9 @@ static int get_schema_stat_record(THD *thd, TABLE_LIST *tables,
I.e. we are in SELECT FROM INFORMATION_SCHEMA.STATISTICS
rather than in SHOW KEYS
*/
- if (thd->net.last_errno)
+ if (thd->is_error())
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- thd->net.last_errno, thd->net.last_error);
+ thd->main_da.sql_errno(), thd->main_da.message());
thd->clear_error();
res= 0;
}
@@ -4290,9 +4298,9 @@ static int get_schema_views_record(THD *thd, TABLE_LIST *tables,
if (schema_table_store_record(thd, table))
DBUG_RETURN(1);
- if (res && thd->net.last_errno)
+ if (res && thd->is_error())
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- thd->net.last_errno, thd->net.last_error);
+ thd->main_da.sql_errno(), thd->main_da.message());
}
if (res)
thd->clear_error();
@@ -4323,9 +4331,9 @@ static int get_schema_constraints_record(THD *thd, TABLE_LIST *tables,
DBUG_ENTER("get_schema_constraints_record");
if (res)
{
- if (thd->net.last_errno)
+ if (thd->is_error())
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- thd->net.last_errno, thd->net.last_error);
+ thd->main_da.sql_errno(), thd->main_da.message());
thd->clear_error();
DBUG_RETURN(0);
}
@@ -4428,9 +4436,9 @@ static int get_schema_triggers_record(THD *thd, TABLE_LIST *tables,
*/
if (res)
{
- if (thd->net.last_errno)
+ if (thd->is_error())
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- thd->net.last_errno, thd->net.last_error);
+ thd->main_da.sql_errno(), thd->main_da.message());
thd->clear_error();
DBUG_RETURN(0);
}
@@ -4511,9 +4519,9 @@ static int get_schema_key_column_usage_record(THD *thd,
DBUG_ENTER("get_schema_key_column_usage_record");
if (res)
{
- if (thd->net.last_errno)
+ if (thd->is_error())
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- thd->net.last_errno, thd->net.last_error);
+ thd->main_da.sql_errno(), thd->main_da.message());
thd->clear_error();
DBUG_RETURN(0);
}
@@ -4706,9 +4714,9 @@ static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables,
if (res)
{
- if (thd->net.last_errno)
+ if (thd->is_error())
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- thd->net.last_errno, thd->net.last_error);
+ thd->main_da.sql_errno(), thd->main_da.message());
thd->clear_error();
DBUG_RETURN(0);
}
@@ -4751,6 +4759,7 @@ static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables,
break;
default:
DBUG_ASSERT(0);
+ my_error(ER_OUT_OF_RESOURCES, MYF(0));
current_thd->fatal_error();
DBUG_RETURN(1);
}
@@ -5243,9 +5252,9 @@ get_referential_constraints_record(THD *thd, TABLE_LIST *tables,
if (res)
{
- if (thd->net.last_errno)
+ if (thd->is_error())
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- thd->net.last_errno, thd->net.last_error);
+ thd->main_da.sql_errno(), thd->main_da.message());
thd->clear_error();
DBUG_RETURN(0);
}
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index c618d170fb7..7bcb79f8429 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -1662,7 +1662,10 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
!dont_log_query);
if ((error == ENOENT || error == HA_ERR_NO_SUCH_TABLE) &&
(if_exists || table_type == NULL))
+ {
error= 0;
+ thd->clear_error();
+ }
if (error == HA_ERR_ROW_IS_REFERENCED)
{
/* the table is referenced by a foreign key constraint */
@@ -4191,18 +4194,22 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
(table->table->file->ha_check_for_upgrade(check_opt) ==
HA_ADMIN_NEEDS_ALTER))
{
- my_bool save_no_send_ok= thd->net.no_send_ok;
DBUG_PRINT("admin", ("recreating table"));
ha_autocommit_or_rollback(thd, 1);
close_thread_tables(thd);
tmp_disable_binlog(thd); // binlogging is done by caller if wanted
- thd->net.no_send_ok= TRUE;
result_code= mysql_recreate_table(thd, table);
- thd->net.no_send_ok= save_no_send_ok;
reenable_binlog(thd);
+ /*
+ mysql_recreate_table() can push OK or ERROR.
+ Clear 'OK' status. If there is an error, keep it:
+ we will store the error message in a result set row
+ and then clear.
+ */
+ if (thd->main_da.is_ok())
+ thd->main_da.reset_diagnostics_area();
goto send_result;
}
-
}
DBUG_PRINT("admin", ("calling operator_func '%s'", operator_name));
@@ -4296,7 +4303,6 @@ send_result_message:
case HA_ADMIN_TRY_ALTER:
{
- my_bool save_no_send_ok= thd->net.no_send_ok;
/*
This is currently used only by InnoDB. ha_innobase::optimize() answers
"try with alter", so here we close the table, do an ALTER TABLE,
@@ -4308,10 +4314,16 @@ send_result_message:
*save_next_global= table->next_global;
table->next_local= table->next_global= 0;
tmp_disable_binlog(thd); // binlogging is done by caller if wanted
- thd->net.no_send_ok= TRUE;
result_code= mysql_recreate_table(thd, table);
- thd->net.no_send_ok= save_no_send_ok;
reenable_binlog(thd);
+ /*
+ mysql_recreate_table() can push OK or ERROR.
+ Clear 'OK' status. If there is an error, keep it:
+ we will store the error message in a result set row
+ and then clear.
+ */
+ if (thd->main_da.is_ok())
+ thd->main_da.reset_diagnostics_area();
ha_autocommit_or_rollback(thd, 0);
close_thread_tables(thd);
if (!result_code) // recreation went ok
@@ -4322,9 +4334,10 @@ send_result_message:
}
if (result_code) // either mysql_recreate_table or analyze failed
{
- const char *err_msg;
- if ((err_msg= thd->net.last_error))
+ DBUG_ASSERT(thd->is_error());
+ if (thd->is_error())
{
+ const char *err_msg= thd->main_da.message();
if (!thd->vio_ok())
{
sql_print_error(err_msg);
@@ -4340,6 +4353,7 @@ send_result_message:
protocol->store(table_name, system_charset_info);
protocol->store(operator_name, system_charset_info);
}
+ thd->clear_error();
}
}
result_code= result_code ? HA_ADMIN_FAILED : HA_ADMIN_OK;
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index ecb7acda61b..1e9b7da1c81 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -1696,7 +1696,11 @@ void multi_update::send_error(uint errcode,const char *err)
{
/* First send error what ever it is ... */
my_error(errcode, MYF(0), err);
+}
+
+void multi_update::abort()
+{
/* the error was handled or nothing deleted and no side effects return */
if (error_handled ||
!thd->transaction.stmt.modified_non_trans_table && !updated)
diff --git a/sql/table.cc b/sql/table.cc
index 2143faaff5c..133b08ba703 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -3275,31 +3275,32 @@ bool TABLE_LIST::prep_check_option(THD *thd, uint8 check_opt_type)
}
-/*
+/**
Hide errors which show view underlying table information
- SYNOPSIS
- TABLE_LIST::hide_view_error()
- thd thread handler
+ @param[in,out] thd thread handler
+ @pre This method can be called only if there is an error.
*/
void TABLE_LIST::hide_view_error(THD *thd)
{
/* Hide "Unknown column" or "Unknown function" error */
- if (thd->net.last_errno == ER_BAD_FIELD_ERROR ||
- thd->net.last_errno == ER_SP_DOES_NOT_EXIST ||
- thd->net.last_errno == ER_PROCACCESS_DENIED_ERROR ||
- thd->net.last_errno == ER_COLUMNACCESS_DENIED_ERROR ||
- thd->net.last_errno == ER_TABLEACCESS_DENIED_ERROR ||
- thd->net.last_errno == ER_TABLE_NOT_LOCKED ||
- thd->net.last_errno == ER_NO_SUCH_TABLE)
+ DBUG_ASSERT(thd->is_error());
+
+ if (thd->main_da.sql_errno() == ER_BAD_FIELD_ERROR ||
+ thd->main_da.sql_errno() == ER_SP_DOES_NOT_EXIST ||
+ thd->main_da.sql_errno() == ER_PROCACCESS_DENIED_ERROR ||
+ thd->main_da.sql_errno() == ER_COLUMNACCESS_DENIED_ERROR ||
+ thd->main_da.sql_errno() == ER_TABLEACCESS_DENIED_ERROR ||
+ thd->main_da.sql_errno() == ER_TABLE_NOT_LOCKED ||
+ thd->main_da.sql_errno() == ER_NO_SUCH_TABLE)
{
TABLE_LIST *top= top_table();
- thd->clear_error();
+ thd->clear_error();
my_error(ER_VIEW_INVALID, MYF(0), top->view_db.str, top->view_name.str);
}
- else if (thd->net.last_errno == ER_NO_DEFAULT_FOR_FIELD)
+ else if (thd->main_da.sql_errno() == ER_NO_DEFAULT_FOR_FIELD)
{
TABLE_LIST *top= top_table();
thd->clear_error();
diff --git a/sql/tztime.cc b/sql/tztime.cc
index 920f8e87d13..f080c61e243 100644
--- a/sql/tztime.cc
+++ b/sql/tztime.cc
@@ -1642,7 +1642,7 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
if (open_system_tables_for_read(thd, tz_tables, &open_tables_state_backup))
{
sql_print_warning("Can't open and lock time zone table: %s "
- "trying to live without them", thd->net.last_error);
+ "trying to live without them", thd->main_da.message());
/* We will try emulate that everything is ok */
return_val= time_zone_tables_exist= 0;
goto end_with_setting_default_tz;