Skip to content

Commit ebb9c5d

Browse files
author
kostja@bodhi.(none)
committed
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().
1 parent aa5786e commit ebb9c5d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+983
-540
lines changed

include/mysql_com.h

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -203,14 +203,10 @@ typedef struct st_net {
203203
unsigned int *return_status;
204204
unsigned char reading_or_writing;
205205
char save_char;
206-
my_bool no_send_ok; /* For SPs and other things that do multiple stmts */
206+
my_bool unused0; /* Please remove with the next incompatible ABI change. */
207207
my_bool unused; /* Please remove with the next incompatible ABI change */
208208
my_bool compress;
209-
/*
210-
Set if OK packet is already sent, and we do not need to send error
211-
messages
212-
*/
213-
my_bool no_send_error;
209+
my_bool unused1; /* Please remove with the next incompatible ABI change. */
214210
/*
215211
Pointer to query object in query cache, do not equal NULL (0) for
216212
queries in cache that have not stored its results yet
@@ -221,11 +217,14 @@ typedef struct st_net {
221217
functions and methods to maintain proper locking.
222218
*/
223219
unsigned char *query_cache_query;
224-
unsigned int last_errno;
225-
unsigned char error;
226-
my_bool report_error; /* We should report error (we have unreported error) */
220+
unsigned int client_last_errno;
221+
unsigned char error;
222+
my_bool unused2; /* Please remove with the next incompatible ABI change. */
227223
my_bool return_errno;
228-
char last_error[MYSQL_ERRMSG_SIZE], sqlstate[SQLSTATE_LENGTH+1];
224+
/** Client library error message buffer. Actually belongs to struct MYSQL. */
225+
char client_last_error[MYSQL_ERRMSG_SIZE];
226+
/** Client library sqlstate buffer. Set along with the error message. */
227+
char sqlstate[SQLSTATE_LENGTH+1];
229228
void *extension;
230229
} NET;
231230

include/mysql_h.ic

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -537,16 +537,16 @@ struct __attribute__((aligned(__alignof__(void *)), aligned(__alignof__(unsigned
537537
unsigned int * return_status;
538538
unsigned char reading_or_writing;
539539
char save_char;
540-
my_bool no_send_ok;
540+
my_bool unused0;
541541
my_bool unused;
542542
my_bool compress;
543-
my_bool no_send_error;
543+
my_bool unused1;
544544
unsigned char * query_cache_query;
545-
unsigned int last_errno;
545+
unsigned int client_last_errno;
546546
unsigned char error;
547-
my_bool report_error;
547+
my_bool unused2;
548548
my_bool return_errno;
549-
char last_error[512];
549+
char client_last_error[512];
550550
char sqlstate[(5 + 1)];
551551
void * extension;
552552
};

libmysql/libmysql.c

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -440,11 +440,11 @@ static void expand_error(MYSQL* mysql, int error)
440440
char tmp[MYSQL_ERRMSG_SIZE];
441441
char *p;
442442
uint err_length;
443-
strmake(tmp, mysql->net.last_error, MYSQL_ERRMSG_SIZE-1);
444-
p = strmake(mysql->net.last_error, ER(error), MYSQL_ERRMSG_SIZE-1);
445-
err_length= (uint) (p - mysql->net.last_error);
443+
strmake(tmp, mysql->net.client_last_error, MYSQL_ERRMSG_SIZE-1);
444+
p = strmake(mysql->net.client_last_error, ER(error), MYSQL_ERRMSG_SIZE-1);
445+
err_length= (uint) (p - mysql->net.client_last_error);
446446
strmake(p, tmp, MYSQL_ERRMSG_SIZE-1 - err_length);
447-
mysql->net.last_errno = error;
447+
mysql->net.client_last_errno = error;
448448
}
449449

450450
/*
@@ -870,9 +870,10 @@ my_bool handle_local_infile(MYSQL *mysql, const char *net_filename)
870870
VOID(my_net_write(net,(const uchar*) "",0)); /* Server needs one packet */
871871
net_flush(net);
872872
strmov(net->sqlstate, unknown_sqlstate);
873-
net->last_errno= (*options->local_infile_error)(li_ptr,
874-
net->last_error,
875-
sizeof(net->last_error)-1);
873+
net->client_last_errno=
874+
(*options->local_infile_error)(li_ptr,
875+
net->client_last_error,
876+
sizeof(net->client_last_error)-1);
876877
goto err;
877878
}
878879

@@ -899,9 +900,10 @@ my_bool handle_local_infile(MYSQL *mysql, const char *net_filename)
899900

900901
if (readcount < 0)
901902
{
902-
net->last_errno= (*options->local_infile_error)(li_ptr,
903-
net->last_error,
904-
sizeof(net->last_error)-1);
903+
net->client_last_errno=
904+
(*options->local_infile_error)(li_ptr,
905+
net->client_last_error,
906+
sizeof(net->client_last_error)-1);
905907
goto err;
906908
}
907909

@@ -1395,7 +1397,7 @@ const char *cli_read_statistics(MYSQL *mysql)
13951397
if (!mysql->net.read_pos[0])
13961398
{
13971399
set_mysql_error(mysql, CR_WRONG_HOST_INFO, unknown_sqlstate);
1398-
return mysql->net.last_error;
1400+
return mysql->net.client_last_error;
13991401
}
14001402
return (char*) mysql->net.read_pos;
14011403
}
@@ -1406,7 +1408,7 @@ mysql_stat(MYSQL *mysql)
14061408
{
14071409
DBUG_ENTER("mysql_stat");
14081410
if (simple_command(mysql,COM_STATISTICS,0,0,0))
1409-
DBUG_RETURN(mysql->net.last_error);
1411+
DBUG_RETURN(mysql->net.client_last_error);
14101412
DBUG_RETURN((*mysql->methods->read_statistics)(mysql));
14111413
}
14121414

@@ -1771,7 +1773,7 @@ static my_bool my_realloc_str(NET *net, ulong length)
17711773
if (res)
17721774
{
17731775
strmov(net->sqlstate, unknown_sqlstate);
1774-
strmov(net->last_error, ER(net->last_errno));
1776+
strmov(net->client_last_error, ER(net->client_last_errno));
17751777
}
17761778
net->write_pos= net->buff+ buf_length;
17771779
}
@@ -1822,13 +1824,15 @@ void set_stmt_error(MYSQL_STMT * stmt, int errcode,
18221824
void set_stmt_errmsg(MYSQL_STMT *stmt, NET *net)
18231825
{
18241826
DBUG_ENTER("set_stmt_errmsg");
1825-
DBUG_PRINT("enter", ("error: %d/%s '%s'", net->last_errno, net->sqlstate,
1826-
net->last_error));
1827+
DBUG_PRINT("enter", ("error: %d/%s '%s'",
1828+
net->client_last_errno,
1829+
net->sqlstate,
1830+
net->client_last_error));
18271831
DBUG_ASSERT(stmt != 0);
18281832

1829-
stmt->last_errno= net->last_errno;
1830-
if (net->last_error && net->last_error[0])
1831-
strmov(stmt->last_error, net->last_error);
1833+
stmt->last_errno= net->client_last_errno;
1834+
if (net->client_last_error && net->client_last_error[0])
1835+
strmov(stmt->last_error, net->client_last_error);
18321836
strmov(stmt->sqlstate, net->sqlstate);
18331837

18341838
DBUG_VOID_RETURN;

libmysql/manager.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ MYSQL_MANAGER* STDCALL mysql_manager_connect(MYSQL_MANAGER* con,
160160
msg_len=strlen(msg_buf);
161161
if (my_net_write(&con->net,(uchar*) msg_buf,msg_len) || net_flush(&con->net))
162162
{
163-
con->last_errno=con->net.last_errno;
163+
con->last_errno=con->net.client_last_errno;
164164
strmov(con->last_error,"Write error on socket");
165165
goto err;
166166
}

libmysqld/lib_sql.cc

Lines changed: 56 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@ void embedded_get_error(MYSQL *mysql, MYSQL_DATA *data)
6161
{
6262
NET *net= &mysql->net;
6363
struct embedded_query_result *ei= data->embedded_info;
64-
net->last_errno= ei->last_errno;
65-
strmake(net->last_error, ei->info, sizeof(net->last_error));
64+
net->client_last_errno= ei->last_errno;
65+
strmake(net->client_last_error, ei->info, sizeof(net->client_last_error)-1);
6666
memcpy(net->sqlstate, ei->sqlstate, sizeof(net->sqlstate));
6767
my_free(data, MYF(0));
6868
}
@@ -110,12 +110,11 @@ emb_advanced_command(MYSQL *mysql, enum enum_server_command command,
110110
arg_length= header_length;
111111
}
112112

113-
thd->net.no_send_error= 0;
114113
result= dispatch_command(command, thd, (char *) arg, arg_length);
115114
thd->cur_data= 0;
116115

117116
if (!skip_check)
118-
result= thd->net.last_errno ? -1 : 0;
117+
result= thd->is_error() ? -1 : 0;
119118

120119
return result;
121120
}
@@ -370,7 +369,7 @@ static void emb_free_embedded_thd(MYSQL *mysql)
370369
static const char * emb_read_statistics(MYSQL *mysql)
371370
{
372371
THD *thd= (THD*)mysql->thd;
373-
return thd->net.last_error;
372+
return thd->is_error() ? thd->main_da.message() : "";
374373
}
375374

376375

@@ -675,8 +674,10 @@ int check_embedded_connection(MYSQL *mysql, const char *db)
675674
err:
676675
{
677676
NET *net= &mysql->net;
678-
memcpy(net->last_error, thd->net.last_error, sizeof(net->last_error));
679-
memcpy(net->sqlstate, thd->net.sqlstate, sizeof(net->sqlstate));
677+
strmake(net->client_last_error, thd->main_da.message(), sizeof(net->client_last_error)-1);
678+
memcpy(net->sqlstate,
679+
mysql_errno_to_sqlstate(thd->main_da.sql_errno()),
680+
sizeof(net->sqlstate)-1);
680681
}
681682
return result;
682683
}
@@ -699,9 +700,8 @@ void THD::clear_data_list()
699700

700701
void THD::clear_error()
701702
{
702-
net.last_error[0]= 0;
703-
net.last_errno= 0;
704-
net.report_error= 0;
703+
if (main_da.is_error())
704+
main_da.reset_diagnostics_area();
705705
}
706706

707707
static char *dup_str_aux(MEM_ROOT *root, const char *from, uint length,
@@ -764,20 +764,18 @@ MYSQL_DATA *THD::alloc_new_dataset()
764764
}
765765

766766

767-
/*
768-
stores server_status and warning_count in the current
769-
query result structures
770-
771-
SYNOPSIS
772-
write_eof_packet()
773-
thd current thread
767+
/**
768+
Stores server_status and warning_count in the current
769+
query result structures.
774770
775-
NOTES
776-
should be called to after we get the recordset-result
771+
@param thd current thread
777772
773+
@note Should be called after we get the recordset-result.
778774
*/
779775

780-
static void write_eof_packet(THD *thd)
776+
static
777+
void
778+
write_eof_packet(THD *thd, uint server_status, uint total_warn_count)
781779
{
782780
if (!thd->mysql) // bootstrap file handling
783781
return;
@@ -788,13 +786,13 @@ static void write_eof_packet(THD *thd)
788786
*/
789787
if (thd->is_fatal_error)
790788
thd->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
791-
thd->cur_data->embedded_info->server_status= thd->server_status;
789+
thd->cur_data->embedded_info->server_status= server_status;
792790
/*
793791
Don't send warn count during SP execution, as the warn_list
794792
is cleared between substatements, and mysqltest gets confused
795793
*/
796794
thd->cur_data->embedded_info->warning_count=
797-
(thd->spcont ? 0 : min(thd->total_warn_count, 65535));
795+
(thd->spcont ? 0 : min(total_warn_count, 65535));
798796
}
799797

800798

@@ -950,7 +948,7 @@ bool Protocol::send_fields(List<Item> *list, uint flags)
950948
}
951949

952950
if (flags & SEND_EOF)
953-
write_eof_packet(thd);
951+
write_eof_packet(thd, thd->server_status, thd->total_warn_count);
954952

955953
DBUG_RETURN(prepare_for_send(list));
956954
err:
@@ -990,17 +988,35 @@ bool Protocol_binary::write()
990988
return false;
991989
}
992990

991+
992+
/**
993+
Embedded library implementation of OK response.
994+
995+
This function is used by the server to write 'OK' packet to
996+
the "network" when the server is compiled as an embedded library.
997+
Since there is no network in the embedded configuration,
998+
a different implementation is necessary.
999+
Instead of marshalling response parameters to a network representation
1000+
and then writing it to the socket, here we simply copy the data to the
1001+
corresponding client-side connection structures.
1002+
1003+
@sa Server implementation of net_send_ok in protocol.cc for
1004+
description of the arguments.
1005+
1006+
@return The function does not return errors.
1007+
*/
1008+
9931009
void
994-
send_ok(THD *thd,ha_rows affected_rows,ulonglong id,const char *message)
1010+
net_send_ok(THD *thd,
1011+
uint server_status, uint total_warn_count,
1012+
ha_rows affected_rows, ulonglong id, const char *message)
9951013
{
996-
DBUG_ENTER("send_ok");
1014+
DBUG_ENTER("emb_net_send_ok");
9971015
MYSQL_DATA *data;
9981016
MYSQL *mysql= thd->mysql;
999-
1017+
10001018
if (!mysql) // bootstrap file handling
10011019
DBUG_VOID_RETURN;
1002-
if (thd->net.no_send_ok) // hack for re-parsing queries
1003-
DBUG_VOID_RETURN;
10041020
if (!(data= thd->alloc_new_dataset()))
10051021
return;
10061022
data->embedded_info->affected_rows= affected_rows;
@@ -1009,15 +1025,24 @@ send_ok(THD *thd,ha_rows affected_rows,ulonglong id,const char *message)
10091025
strmake(data->embedded_info->info, message,
10101026
sizeof(data->embedded_info->info)-1);
10111027

1012-
write_eof_packet(thd);
1028+
write_eof_packet(thd, server_status, total_warn_count);
10131029
thd->cur_data= 0;
10141030
DBUG_VOID_RETURN;
10151031
}
10161032

1033+
1034+
/**
1035+
Embedded library implementation of EOF response.
1036+
1037+
@sa net_send_ok
1038+
1039+
@return This function does not return errors.
1040+
*/
1041+
10171042
void
1018-
send_eof(THD *thd)
1043+
net_send_eof(THD *thd, uint server_status, uint total_warn_count)
10191044
{
1020-
write_eof_packet(thd);
1045+
write_eof_packet(thd, server_status, total_warn_count);
10211046
thd->cur_data= 0;
10221047
}
10231048

libmysqld/libmysqld.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -209,8 +209,9 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
209209
DBUG_RETURN(mysql);
210210

211211
error:
212-
DBUG_PRINT("error",("message: %u (%s)", mysql->net.last_errno,
213-
mysql->net.last_error));
212+
DBUG_PRINT("error",("message: %u (%s)",
213+
mysql->net.client_last_errno,
214+
mysql->net.client_last_error));
214215
{
215216
/* Free alloced memory */
216217
my_bool free_me=mysql->free_me;

mysql-test/r/events.result

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -403,9 +403,10 @@ ERROR 42S02: Table 'mysql.event' doesn't exist
403403
DROP DATABASE IF EXISTS mysqltest_no_such_database;
404404
Warnings:
405405
Note 1008 Can't drop database 'mysqltest_no_such_database'; database doesn't exist
406-
Error 1146 Table 'mysql.event' doesn't exist
407406
CREATE DATABASE mysqltest_db2;
408407
DROP DATABASE mysqltest_db2;
408+
Warnings:
409+
Error 1146 Table 'mysql.event' doesn't exist
409410
OK, there is an unnecessary warning about the non-existent table
410411
but it's not easy to fix and no one complained about it.
411412
A similar warning is printed if mysql.proc is missing.

mysql-test/r/grant.result

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1229,9 +1229,7 @@ set names default;
12291229
FLUSH PRIVILEGES without procs_priv table.
12301230
RENAME TABLE mysql.procs_priv TO mysql.procs_gone;
12311231
FLUSH PRIVILEGES;
1232-
Warnings:
1233-
Error 1146 Table 'mysql.procs_priv' doesn't exist
1234-
Error 1548 Cannot load from mysql.mysql.procs_priv. The table is probably corrupted
1232+
ERROR 42S02: Table 'mysql.procs_priv' doesn't exist
12351233
Assigning privileges without procs_priv table.
12361234
CREATE DATABASE mysqltest1;
12371235
CREATE PROCEDURE mysqltest1.test() SQL SECURITY DEFINER

mysql-test/suite/rpl/r/rpl_row_tabledefs_2myisam.result

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ Replicate_Ignore_Table
123123
Replicate_Wild_Do_Table
124124
Replicate_Wild_Ignore_Table
125125
Last_Errno 1364
126-
Last_Error Error in Write_rows event: error during transaction execution on table test.t1_nodef.
126+
Last_Error Error in Write_rows event: error during transaction execution on table test.t1_nodef. Field 'x' doesn't have a default value
127127
Skip_Counter 0
128128
Exec_Master_Log_Pos #
129129
Relay_Log_Space #
@@ -141,7 +141,7 @@ Master_SSL_Verify_Server_Cert No
141141
Last_IO_Errno 0
142142
Last_IO_Error
143143
Last_SQL_Errno 1364
144-
Last_SQL_Error Error in Write_rows event: error during transaction execution on table test.t1_nodef.
144+
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
145145
SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
146146
START SLAVE;
147147
INSERT INTO t9 VALUES (2);

0 commit comments

Comments
 (0)