Bug#12713 "Error in a stored function called from a SELECT doesn't

cause ROLLBACK of statement", part 1. Review fixes.

Do not send OK/EOF packets to the client until we reached the end of 
the current statement.
This is a consolidation, to keep the functionality that is shared by all 
SQL statements in one place in the server.
Currently this functionality includes:
- close_thread_tables()
- log_slow_statement().

After this patch and the subsequent patch for Bug#12713, it shall also include:
- ha_autocommit_or_rollback()
- net_end_statement()
- query_cache_end_of_result().

In future it may also include:
- mysql_reset_thd_for_next_command().
This commit is contained in:
kostja@bodhi.(none) 2007-12-12 18:21:01 +03:00
parent aa5786eb0f
commit ebb9c5d983
51 changed files with 983 additions and 540 deletions

View File

@ -203,14 +203,10 @@ typedef struct st_net {
unsigned int *return_status;
unsigned char reading_or_writing;
char save_char;
my_bool no_send_ok; /* For SPs and other things that do multiple stmts */
my_bool unused0; /* Please remove with the next incompatible ABI change. */
my_bool unused; /* Please remove with the next incompatible ABI change */
my_bool compress;
/*
Set if OK packet is already sent, and we do not need to send error
messages
*/
my_bool no_send_error;
my_bool unused1; /* Please remove with the next incompatible ABI change. */
/*
Pointer to query object in query cache, do not equal NULL (0) for
queries in cache that have not stored its results yet
@ -221,11 +217,14 @@ typedef struct st_net {
functions and methods to maintain proper locking.
*/
unsigned char *query_cache_query;
unsigned int last_errno;
unsigned char error;
my_bool report_error; /* We should report error (we have unreported error) */
unsigned int client_last_errno;
unsigned char error;
my_bool unused2; /* Please remove with the next incompatible ABI change. */
my_bool return_errno;
char last_error[MYSQL_ERRMSG_SIZE], sqlstate[SQLSTATE_LENGTH+1];
/** Client library error message buffer. Actually belongs to struct MYSQL. */
char client_last_error[MYSQL_ERRMSG_SIZE];
/** Client library sqlstate buffer. Set along with the error message. */
char sqlstate[SQLSTATE_LENGTH+1];
void *extension;
} NET;

View File

@ -537,16 +537,16 @@ struct __attribute__((aligned(__alignof__(void *)), aligned(__alignof__(unsigned
unsigned int * return_status;
unsigned char reading_or_writing;
char save_char;
my_bool no_send_ok;
my_bool unused0;
my_bool unused;
my_bool compress;
my_bool no_send_error;
my_bool unused1;
unsigned char * query_cache_query;
unsigned int last_errno;
unsigned int client_last_errno;
unsigned char error;
my_bool report_error;
my_bool unused2;
my_bool return_errno;
char last_error[512];
char client_last_error[512];
char sqlstate[(5 + 1)];
void * extension;
};

View File

@ -440,11 +440,11 @@ static void expand_error(MYSQL* mysql, int error)
char tmp[MYSQL_ERRMSG_SIZE];
char *p;
uint err_length;
strmake(tmp, mysql->net.last_error, MYSQL_ERRMSG_SIZE-1);
p = strmake(mysql->net.last_error, ER(error), MYSQL_ERRMSG_SIZE-1);
err_length= (uint) (p - mysql->net.last_error);
strmake(tmp, mysql->net.client_last_error, MYSQL_ERRMSG_SIZE-1);
p = strmake(mysql->net.client_last_error, ER(error), MYSQL_ERRMSG_SIZE-1);
err_length= (uint) (p - mysql->net.client_last_error);
strmake(p, tmp, MYSQL_ERRMSG_SIZE-1 - err_length);
mysql->net.last_errno = error;
mysql->net.client_last_errno = error;
}
/*
@ -870,9 +870,10 @@ my_bool handle_local_infile(MYSQL *mysql, const char *net_filename)
VOID(my_net_write(net,(const uchar*) "",0)); /* Server needs one packet */
net_flush(net);
strmov(net->sqlstate, unknown_sqlstate);
net->last_errno= (*options->local_infile_error)(li_ptr,
net->last_error,
sizeof(net->last_error)-1);
net->client_last_errno=
(*options->local_infile_error)(li_ptr,
net->client_last_error,
sizeof(net->client_last_error)-1);
goto err;
}
@ -899,9 +900,10 @@ my_bool handle_local_infile(MYSQL *mysql, const char *net_filename)
if (readcount < 0)
{
net->last_errno= (*options->local_infile_error)(li_ptr,
net->last_error,
sizeof(net->last_error)-1);
net->client_last_errno=
(*options->local_infile_error)(li_ptr,
net->client_last_error,
sizeof(net->client_last_error)-1);
goto err;
}
@ -1395,7 +1397,7 @@ const char *cli_read_statistics(MYSQL *mysql)
if (!mysql->net.read_pos[0])
{
set_mysql_error(mysql, CR_WRONG_HOST_INFO, unknown_sqlstate);
return mysql->net.last_error;
return mysql->net.client_last_error;
}
return (char*) mysql->net.read_pos;
}
@ -1406,7 +1408,7 @@ mysql_stat(MYSQL *mysql)
{
DBUG_ENTER("mysql_stat");
if (simple_command(mysql,COM_STATISTICS,0,0,0))
DBUG_RETURN(mysql->net.last_error);
DBUG_RETURN(mysql->net.client_last_error);
DBUG_RETURN((*mysql->methods->read_statistics)(mysql));
}
@ -1771,7 +1773,7 @@ static my_bool my_realloc_str(NET *net, ulong length)
if (res)
{
strmov(net->sqlstate, unknown_sqlstate);
strmov(net->last_error, ER(net->last_errno));
strmov(net->client_last_error, ER(net->client_last_errno));
}
net->write_pos= net->buff+ buf_length;
}
@ -1822,13 +1824,15 @@ void set_stmt_error(MYSQL_STMT * stmt, int errcode,
void set_stmt_errmsg(MYSQL_STMT *stmt, NET *net)
{
DBUG_ENTER("set_stmt_errmsg");
DBUG_PRINT("enter", ("error: %d/%s '%s'", net->last_errno, net->sqlstate,
net->last_error));
DBUG_PRINT("enter", ("error: %d/%s '%s'",
net->client_last_errno,
net->sqlstate,
net->client_last_error));
DBUG_ASSERT(stmt != 0);
stmt->last_errno= net->last_errno;
if (net->last_error && net->last_error[0])
strmov(stmt->last_error, net->last_error);
stmt->last_errno= net->client_last_errno;
if (net->client_last_error && net->client_last_error[0])
strmov(stmt->last_error, net->client_last_error);
strmov(stmt->sqlstate, net->sqlstate);
DBUG_VOID_RETURN;

View File

@ -160,7 +160,7 @@ MYSQL_MANAGER* STDCALL mysql_manager_connect(MYSQL_MANAGER* con,
msg_len=strlen(msg_buf);
if (my_net_write(&con->net,(uchar*) msg_buf,msg_len) || net_flush(&con->net))
{
con->last_errno=con->net.last_errno;
con->last_errno=con->net.client_last_errno;
strmov(con->last_error,"Write error on socket");
goto err;
}

View File

@ -61,8 +61,8 @@ void embedded_get_error(MYSQL *mysql, MYSQL_DATA *data)
{
NET *net= &mysql->net;
struct embedded_query_result *ei= data->embedded_info;
net->last_errno= ei->last_errno;
strmake(net->last_error, ei->info, sizeof(net->last_error));
net->client_last_errno= ei->last_errno;
strmake(net->client_last_error, ei->info, sizeof(net->client_last_error)-1);
memcpy(net->sqlstate, ei->sqlstate, sizeof(net->sqlstate));
my_free(data, MYF(0));
}
@ -110,12 +110,11 @@ emb_advanced_command(MYSQL *mysql, enum enum_server_command command,
arg_length= header_length;
}
thd->net.no_send_error= 0;
result= dispatch_command(command, thd, (char *) arg, arg_length);
thd->cur_data= 0;
if (!skip_check)
result= thd->net.last_errno ? -1 : 0;
result= thd->is_error() ? -1 : 0;
return result;
}
@ -370,7 +369,7 @@ static void emb_free_embedded_thd(MYSQL *mysql)
static const char * emb_read_statistics(MYSQL *mysql)
{
THD *thd= (THD*)mysql->thd;
return thd->net.last_error;
return thd->is_error() ? thd->main_da.message() : "";
}
@ -675,8 +674,10 @@ int check_embedded_connection(MYSQL *mysql, const char *db)
err:
{
NET *net= &mysql->net;
memcpy(net->last_error, thd->net.last_error, sizeof(net->last_error));
memcpy(net->sqlstate, thd->net.sqlstate, sizeof(net->sqlstate));
strmake(net->client_last_error, thd->main_da.message(), sizeof(net->client_last_error)-1);
memcpy(net->sqlstate,
mysql_errno_to_sqlstate(thd->main_da.sql_errno()),
sizeof(net->sqlstate)-1);
}
return result;
}
@ -699,9 +700,8 @@ void THD::clear_data_list()
void THD::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();
}
static char *dup_str_aux(MEM_ROOT *root, const char *from, uint length,
@ -764,20 +764,18 @@ MYSQL_DATA *THD::alloc_new_dataset()
}
/*
stores server_status and warning_count in the current
query result structures
/**
Stores server_status and warning_count in the current
query result structures.
SYNOPSIS
write_eof_packet()
thd current thread
NOTES
should be called to after we get the recordset-result
@param thd current thread
@note Should be called after we get the recordset-result.
*/
static void write_eof_packet(THD *thd)
static
void
write_eof_packet(THD *thd, uint server_status, uint total_warn_count)
{
if (!thd->mysql) // bootstrap file handling
return;
@ -788,13 +786,13 @@ static void write_eof_packet(THD *thd)
*/
if (thd->is_fatal_error)
thd->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
thd->cur_data->embedded_info->server_status= thd->server_status;
thd->cur_data->embedded_info->server_status= server_status;
/*
Don't send warn count during SP execution, as the warn_list
is cleared between substatements, and mysqltest gets confused
*/
thd->cur_data->embedded_info->warning_count=
(thd->spcont ? 0 : min(thd->total_warn_count, 65535));
(thd->spcont ? 0 : min(total_warn_count, 65535));
}
@ -950,7 +948,7 @@ bool Protocol::send_fields(List<Item> *list, uint flags)
}
if (flags & SEND_EOF)
write_eof_packet(thd);
write_eof_packet(thd, thd->server_status, thd->total_warn_count);
DBUG_RETURN(prepare_for_send(list));
err:
@ -990,17 +988,35 @@ bool Protocol_binary::write()
return false;
}
/**
Embedded library implementation of OK response.
This function is used by the server to write 'OK' packet to
the "network" when the server is compiled as an embedded library.
Since there is no network in the embedded configuration,
a different implementation is necessary.
Instead of marshalling response parameters to a network representation
and then writing it to the socket, here we simply copy the data to the
corresponding client-side connection structures.
@sa Server implementation of net_send_ok in protocol.cc for
description of the arguments.
@return The function does not return errors.
*/
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)
{
DBUG_ENTER("send_ok");
DBUG_ENTER("emb_net_send_ok");
MYSQL_DATA *data;
MYSQL *mysql= thd->mysql;
if (!mysql) // bootstrap file handling
DBUG_VOID_RETURN;
if (thd->net.no_send_ok) // hack for re-parsing queries
DBUG_VOID_RETURN;
if (!(data= thd->alloc_new_dataset()))
return;
data->embedded_info->affected_rows= affected_rows;
@ -1009,15 +1025,24 @@ send_ok(THD *thd,ha_rows affected_rows,ulonglong id,const char *message)
strmake(data->embedded_info->info, message,
sizeof(data->embedded_info->info)-1);
write_eof_packet(thd);
write_eof_packet(thd, server_status, total_warn_count);
thd->cur_data= 0;
DBUG_VOID_RETURN;
}
/**
Embedded library implementation of EOF response.
@sa net_send_ok
@return This function does not return errors.
*/
void
send_eof(THD *thd)
net_send_eof(THD *thd, uint server_status, uint total_warn_count)
{
write_eof_packet(thd);
write_eof_packet(thd, server_status, total_warn_count);
thd->cur_data= 0;
}

View File

@ -209,8 +209,9 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
DBUG_RETURN(mysql);
error:
DBUG_PRINT("error",("message: %u (%s)", mysql->net.last_errno,
mysql->net.last_error));
DBUG_PRINT("error",("message: %u (%s)",
mysql->net.client_last_errno,
mysql->net.client_last_error));
{
/* Free alloced memory */
my_bool free_me=mysql->free_me;

View File

@ -403,9 +403,10 @@ ERROR 42S02: Table 'mysql.event' doesn't exist
DROP DATABASE IF EXISTS mysqltest_no_such_database;
Warnings:
Note 1008 Can't drop database 'mysqltest_no_such_database'; database doesn't exist
Error 1146 Table 'mysql.event' doesn't exist
CREATE DATABASE mysqltest_db2;
DROP DATABASE mysqltest_db2;
Warnings:
Error 1146 Table 'mysql.event' doesn't exist
OK, there is an unnecessary warning about the non-existent table
but it's not easy to fix and no one complained about it.
A similar warning is printed if mysql.proc is missing.

View File

@ -1229,9 +1229,7 @@ set names default;
FLUSH PRIVILEGES without procs_priv table.
RENAME TABLE mysql.procs_priv TO mysql.procs_gone;
FLUSH PRIVILEGES;
Warnings:
Error 1146 Table 'mysql.procs_priv' doesn't exist
Error 1548 Cannot load from mysql.mysql.procs_priv. The table is probably corrupted
ERROR 42S02: Table 'mysql.procs_priv' doesn't exist
Assigning privileges without procs_priv table.
CREATE DATABASE mysqltest1;
CREATE PROCEDURE mysqltest1.test() SQL SECURITY DEFINER

View File

@ -123,7 +123,7 @@ Replicate_Ignore_Table
Replicate_Wild_Do_Table
Replicate_Wild_Ignore_Table
Last_Errno 1364
Last_Error Error in Write_rows event: error during transaction execution on table test.t1_nodef.
Last_Error Error in Write_rows event: error during transaction execution on table test.t1_nodef. Field 'x' doesn't have a default value
Skip_Counter 0
Exec_Master_Log_Pos #
Relay_Log_Space #
@ -141,7 +141,7 @@ Master_SSL_Verify_Server_Cert No
Last_IO_Errno 0
Last_IO_Error
Last_SQL_Errno 1364
Last_SQL_Error Error in Write_rows event: error during transaction execution on table test.t1_nodef.
Last_SQL_Error Error in Write_rows event: error during transaction execution on table test.t1_nodef. Field 'x' doesn't have a default value
SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
START SLAVE;
INSERT INTO t9 VALUES (2);

View File

@ -123,7 +123,7 @@ Replicate_Ignore_Table
Replicate_Wild_Do_Table
Replicate_Wild_Ignore_Table
Last_Errno 1364
Last_Error Error in Write_rows event: error during transaction execution on table test.t1_nodef.
Last_Error Error in Write_rows event: error during transaction execution on table test.t1_nodef. Field 'x' doesn't have a default value
Skip_Counter 0
Exec_Master_Log_Pos #
Relay_Log_Space #
@ -141,7 +141,7 @@ Master_SSL_Verify_Server_Cert No
Last_IO_Errno 0
Last_IO_Error
Last_SQL_Errno 1364
Last_SQL_Error Error in Write_rows event: error during transaction execution on table test.t1_nodef.
Last_SQL_Error Error in Write_rows event: error during transaction execution on table test.t1_nodef. Field 'x' doesn't have a default value
SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
START SLAVE;
INSERT INTO t9 VALUES (2);

View File

@ -1284,6 +1284,7 @@ set names default;
#
--echo FLUSH PRIVILEGES without procs_priv table.
RENAME TABLE mysql.procs_priv TO mysql.procs_gone;
--error ER_NO_SUCH_TABLE
FLUSH PRIVILEGES;
--echo Assigning privileges without procs_priv table.
CREATE DATABASE mysqltest1;

View File

@ -257,7 +257,7 @@ int Mysql_connection::do_command()
return 1;
if (thread_registry->is_shutdown())
return 1;
net_send_error(&net, net.last_errno);
net_send_error(&net, net.client_last_errno);
net.error= 0;
return 0;
}

View File

@ -289,8 +289,8 @@ void set_mysql_error(MYSQL *mysql, int errcode, const char *sqlstate)
DBUG_ASSERT(mysql != 0);
net= &mysql->net;
net->last_errno= errcode;
strmov(net->last_error, ER(errcode));
net->client_last_errno= errcode;
strmov(net->client_last_error, ER(errcode));
strmov(net->sqlstate, sqlstate);
DBUG_VOID_RETURN;
@ -304,8 +304,8 @@ void set_mysql_error(MYSQL *mysql, int errcode, const char *sqlstate)
void net_clear_error(NET *net)
{
net->last_errno= 0;
net->last_error[0]= '\0';
net->client_last_errno= 0;
net->client_last_error[0]= '\0';
strmov(net->sqlstate, not_error_sqlstate);
}
@ -331,9 +331,9 @@ static void set_mysql_extended_error(MYSQL *mysql, int errcode,
DBUG_ASSERT(mysql != 0);
net= &mysql->net;
net->last_errno= errcode;
net->client_last_errno= errcode;
va_start(args, format);
my_vsnprintf(net->last_error, sizeof(net->last_error)-1,
my_vsnprintf(net->client_last_error, sizeof(net->client_last_error)-1,
format, args);
va_end(args);
strmov(net->sqlstate, sqlstate);
@ -667,7 +667,7 @@ cli_safe_read(MYSQL *mysql)
return (packet_error);
#endif /*MYSQL_SERVER*/
end_server(mysql);
set_mysql_error(mysql, net->last_errno == ER_NET_PACKET_TOO_LARGE ?
set_mysql_error(mysql, net->client_last_errno == ER_NET_PACKET_TOO_LARGE ?
CR_NET_PACKET_TOO_LARGE: CR_SERVER_LOST, unknown_sqlstate);
return (packet_error);
}
@ -676,7 +676,7 @@ cli_safe_read(MYSQL *mysql)
if (len > 3)
{
char *pos=(char*) net->read_pos+1;
net->last_errno=uint2korr(pos);
net->client_last_errno=uint2korr(pos);
pos+=2;
len-=2;
if (protocol_41(mysql) && pos[0] == '#')
@ -684,8 +684,8 @@ cli_safe_read(MYSQL *mysql)
strmake(net->sqlstate, pos+1, SQLSTATE_LENGTH);
pos+= SQLSTATE_LENGTH+1;
}
(void) strmake(net->last_error,(char*) pos,
min((uint) len,(uint) sizeof(net->last_error)-1));
(void) strmake(net->client_last_error,(char*) pos,
min((uint) len,(uint) sizeof(net->client_last_error)-1));
}
else
set_mysql_error(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate);
@ -701,7 +701,9 @@ cli_safe_read(MYSQL *mysql)
mysql->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
DBUG_PRINT("error",("Got error: %d/%s (%s)",
net->last_errno, net->sqlstate, net->last_error));
net->client_last_errno,
net->sqlstate,
net->client_last_error));
return(packet_error);
}
return len;
@ -744,7 +746,6 @@ cli_advanced_command(MYSQL *mysql, enum enum_server_command command,
}
net_clear_error(net);
net->report_error=0;
mysql->info=0;
mysql->affected_rows= ~(my_ulonglong) 0;
/*
@ -759,7 +760,7 @@ cli_advanced_command(MYSQL *mysql, enum enum_server_command command,
{
DBUG_PRINT("error",("Can't send command to server. Error: %d",
socket_errno));
if (net->last_errno == ER_NET_PACKET_TOO_LARGE)
if (net->client_last_errno == ER_NET_PACKET_TOO_LARGE)
{
set_mysql_error(mysql, CR_NET_PACKET_TOO_LARGE, unknown_sqlstate);
goto end;
@ -836,16 +837,15 @@ static my_bool is_NT(void)
#ifdef CHECK_LICENSE
/*
/**
Check server side variable 'license'.
If the variable does not exist or does not contain 'Commercial',
If the variable does not exist or does not contain 'Commercial',
we're talking to non-commercial server from commercial client.
SYNOPSIS
check_license()
RETURN VALUE
0 success
!0 network error or the server is not commercial.
Error code is saved in mysql->net.last_errno.
@retval 0 success
@retval !0 network error or the server is not commercial.
Error code is saved in mysql->net.client_last_errno.
*/
static int check_license(MYSQL *mysql)
@ -858,7 +858,7 @@ static int check_license(MYSQL *mysql)
if (mysql_real_query(mysql, query, sizeof(query)-1))
{
if (net->last_errno == ER_UNKNOWN_SYSTEM_VARIABLE)
if (net->client_last_errno == ER_UNKNOWN_SYSTEM_VARIABLE)
{
set_mysql_extended_error(mysql, CR_WRONG_LICENSE, unknown_sqlstate,
ER(CR_WRONG_LICENSE), required_license);
@ -873,7 +873,7 @@ static int check_license(MYSQL *mysql)
two is ever true for server variables now), or column value
mismatch, set wrong license error.
*/
if (!net->last_errno &&
if (!net->client_last_errno &&
(!row || !row[0] ||
strncmp(row[0], required_license, sizeof(required_license))))
{
@ -881,7 +881,7 @@ static int check_license(MYSQL *mysql)
ER(CR_WRONG_LICENSE), required_license);
}
mysql_free_result(res);
return net->last_errno;
return net->client_last_errno;
}
#endif /* CHECK_LICENSE */
@ -2090,7 +2090,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
if ((pkt_length=cli_safe_read(mysql)) == packet_error)
{
if (mysql->net.last_errno == CR_SERVER_LOST)
if (mysql->net.client_last_errno == CR_SERVER_LOST)
set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
ER(CR_SERVER_LOST_EXTENDED),
"reading initial communication packet",
@ -2324,7 +2324,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
if ((pkt_length=cli_safe_read(mysql)) == packet_error)
{
if (mysql->net.last_errno == CR_SERVER_LOST)
if (mysql->net.client_last_errno == CR_SERVER_LOST)
set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
ER(CR_SERVER_LOST_EXTENDED),
"reading authorization packet",
@ -2352,7 +2352,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
/* Read what server thinks about out new auth message report */
if (cli_safe_read(mysql) == packet_error)
{
if (mysql->net.last_errno == CR_SERVER_LOST)
if (mysql->net.client_last_errno == CR_SERVER_LOST)
set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
ER(CR_SERVER_LOST_EXTENDED),
"reading final connect information",
@ -2371,7 +2371,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
if (db && mysql_select_db(mysql, db))
{
if (mysql->net.last_errno == CR_SERVER_LOST)
if (mysql->net.client_last_errno == CR_SERVER_LOST)
set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
ER(CR_SERVER_LOST_EXTENDED),
"Setting intital database",
@ -2415,7 +2415,9 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
error:
reset_sigpipe(mysql);
DBUG_PRINT("error",("message: %u/%s (%s)",
net->last_errno, net->sqlstate, net->last_error));
net->client_last_errno,
net->sqlstate,
net->client_last_error));
{
/* Free alloced memory */
end_server(mysql);
@ -2473,8 +2475,8 @@ my_bool mysql_reconnect(MYSQL *mysql)
mysql->db, mysql->port, mysql->unix_socket,
mysql->client_flag | CLIENT_REMEMBER_OPTIONS))
{
mysql->net.last_errno= tmp_mysql.net.last_errno;
strmov(mysql->net.last_error, tmp_mysql.net.last_error);
mysql->net.client_last_errno= tmp_mysql.net.client_last_errno;
strmov(mysql->net.client_last_error, tmp_mysql.net.client_last_error);
strmov(mysql->net.sqlstate, tmp_mysql.net.sqlstate);
DBUG_RETURN(1);
}
@ -2483,8 +2485,8 @@ my_bool mysql_reconnect(MYSQL *mysql)
DBUG_PRINT("error", ("mysql_set_character_set() failed"));
bzero((char*) &tmp_mysql.options,sizeof(tmp_mysql.options));
mysql_close(&tmp_mysql);
mysql->net.last_errno= tmp_mysql.net.last_errno;
strmov(mysql->net.last_error, tmp_mysql.net.last_error);
mysql->net.client_last_errno= tmp_mysql.net.client_last_errno;
strmov(mysql->net.client_last_error, tmp_mysql.net.client_last_error);
strmov(mysql->net.sqlstate, tmp_mysql.net.sqlstate);
DBUG_RETURN(1);
}
@ -3077,13 +3079,13 @@ unsigned int STDCALL mysql_num_fields(MYSQL_RES *res)
uint STDCALL mysql_errno(MYSQL *mysql)
{
return mysql->net.last_errno;
return mysql->net.client_last_errno;
}
const char * STDCALL mysql_error(MYSQL *mysql)
{
return mysql->net.last_error;
return mysql->net.client_last_error;
}
@ -3152,7 +3154,7 @@ int STDCALL mysql_set_character_set(MYSQL *mysql, const char *cs_name)
ER(CR_CANT_READ_CHARSET), cs_name, cs_dir_name);
}
charsets_dir= save_csdir;
return mysql->net.last_errno;
return mysql->net.client_last_errno;
}

View File

@ -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;
}

View File

@ -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;
}

View File

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

View File

@ -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;
}

View File

@ -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

View File

@ -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)

View File

@ -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;
}

View File

@ -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 */
}

View File

@ -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;

View File

@ -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:

View File

@ -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);

View File

@ -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")) ||

View File

@ -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();

View File

@ -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;
}

View File

@ -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());
}
}

View File

@ -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);
}

View File

@ -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

View File

@ -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);

View File

@ -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();

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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;
};
@ -975,6 +974,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
@ -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 {

View File

@ -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;
}

View File

@ -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

View File

@ -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)

View File

@ -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,

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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)

View File

@ -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();

View File

@ -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;