diff options
-rw-r--r-- | include/mysql.h.pp | 2 | ||||
-rw-r--r-- | include/mysql_com.h | 2 | ||||
-rw-r--r-- | mysql-test/include/wait_until_connected_again.inc | 2 | ||||
-rw-r--r-- | mysql-test/include/wait_until_disconnected.inc | 2 | ||||
-rw-r--r-- | sql/net_serv.cc | 97 | ||||
-rw-r--r-- | sql/protocol.cc | 15 |
6 files changed, 84 insertions, 36 deletions
diff --git a/include/mysql.h.pp b/include/mysql.h.pp index 2c8e47b454f..a593f526c6e 100644 --- a/include/mysql.h.pp +++ b/include/mysql.h.pp @@ -27,7 +27,7 @@ typedef struct st_net { char save_char; char net_skip_rest_factor; my_bool thread_specific_malloc; - my_bool compress; + unsigned char compress; my_bool unused3; unsigned char *unused; unsigned int last_errno; diff --git a/include/mysql_com.h b/include/mysql_com.h index 8fdac38dd66..96514a28310 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -386,7 +386,7 @@ typedef struct st_net { char save_char; char net_skip_rest_factor; my_bool thread_specific_malloc; - my_bool compress; + unsigned char compress; my_bool unused3; /* Please remove with the next incompatible ABI change. */ /* Pointer to query object in query cache, do not equal NULL (0) for diff --git a/mysql-test/include/wait_until_connected_again.inc b/mysql-test/include/wait_until_connected_again.inc index 96240e36db7..6f64ef45440 100644 --- a/mysql-test/include/wait_until_connected_again.inc +++ b/mysql-test/include/wait_until_connected_again.inc @@ -14,7 +14,7 @@ while ($mysql_errno) # Strangely enough, the server might return "Too many connections" # while being shutdown, thus 1040 is an "allowed" error # See BUG#36228 - --error 0,1040,1053,2002,2003,2005,2006,2013 + --error 0,1040,1053,2002,2003,2005,2006,2013,1927 show status; dec $counter; diff --git a/mysql-test/include/wait_until_disconnected.inc b/mysql-test/include/wait_until_disconnected.inc index 71361682442..658bf0be739 100644 --- a/mysql-test/include/wait_until_disconnected.inc +++ b/mysql-test/include/wait_until_disconnected.inc @@ -12,7 +12,7 @@ while (!$mysql_errno) # Strangely enough, the server might return "Too many connections" # while being shutdown, thus 1040 is an "allowed" error. # See BUG#36228. - --error 0,1040,1053,2002,2003,2005,2006,2013 + --error 0,1040,1053,2002,2003,2005,2006,2013,1927 show status; dec $counter; diff --git a/sql/net_serv.cc b/sql/net_serv.cc index 91a17606d68..b48d36700c6 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -540,7 +540,7 @@ net_write_buff(NET *net, const uchar *packet, ulong len) left_length= (ulong) (net->buff_end - net->write_pos); #ifdef DEBUG_DATA_PACKETS - DBUG_DUMP("data", packet, len); + DBUG_DUMP("data_written", packet, len); #endif if (len > left_length) { @@ -629,7 +629,8 @@ net_real_write(NET *net,const uchar *packet, size_t len) } memcpy(b+header_length,packet,len); - if (my_compress(b+header_length, &len, &complen)) + /* Don't compress error packets (compress == 2) */ + if (net->compress == 2 || my_compress(b+header_length, &len, &complen)) complen=0; int3store(&b[NET_HEADER_SIZE],complen); int3store(b,len); @@ -640,7 +641,7 @@ net_real_write(NET *net,const uchar *packet, size_t len) #endif /* HAVE_COMPRESS */ #ifdef DEBUG_DATA_PACKETS - DBUG_DUMP("data", packet, len); + DBUG_DUMP("data_written", packet, len); #endif #ifndef NO_ALARM @@ -830,6 +831,7 @@ my_real_read(NET *net, size_t *complen, size_t length; uint i,retry_count=0; ulong len=packet_error; + my_bool expect_error_packet __attribute((unused))= 0; thr_alarm_t alarmed; #ifndef NO_ALARM ALARM alarm_buff; @@ -878,6 +880,7 @@ my_real_read(NET *net, size_t *complen, if (i== 0 && thd_net_is_killed()) { + DBUG_PRINT("info", ("thd is killed")); len= packet_error; net->error= 0; net->last_errno= ER_CONNECTION_KILLED; @@ -947,39 +950,34 @@ my_real_read(NET *net, size_t *complen, pos+= length; update_statistics(thd_increment_bytes_received(length)); } + +#ifdef DEBUG_DATA_PACKETS + DBUG_DUMP("data_read", net->buff+net->where_b, length); +#endif if (i == 0) { /* First parts is packet length */ ulong helping; +#ifndef DEBUG_DATA_PACKETS DBUG_DUMP("packet_header", net->buff+net->where_b, NET_HEADER_SIZE); +#endif if (net->buff[net->where_b + 3] != (uchar) net->pkt_nr) - { - if (net->buff[net->where_b] != (uchar) 255) - { - DBUG_PRINT("error", - ("Packets out of order (Found: %d, expected %u)", - (int) net->buff[net->where_b + 3], - net->pkt_nr)); - /* - We don't make noise server side, since the client is expected - to break the protocol for e.g. --send LOAD DATA .. LOCAL where - the server expects the client to send a file, but the client - may reply with a new command instead. - */ + { #ifndef MYSQL_SERVER - EXTRA_DEBUG_fflush(stdout); - EXTRA_DEBUG_fprintf(stderr,"Error: Packets out of order (Found: %d, expected %d)\n", - (int) net->buff[net->where_b + 3], - (uint) (uchar) net->pkt_nr); - EXTRA_DEBUG_fflush(stderr); + if (net->buff[net->where_b + 3] == (uchar) (net->pkt_nr -1)) + { + /* + If the server was killed then the server may have missed the + last sent client packet and the packet numbering may be one off. + */ + DBUG_PRINT("warning", ("Found possible out of order packets")); + expect_error_packet= 1; + } + else #endif - } - len= packet_error; - /* Not a NET error on the client. XXX: why? */ - MYSQL_SERVER_my_error(ER_NET_PACKETS_OUT_OF_ORDER, MYF(0)); - goto end; - } - net->compress_pkt_nr= ++net->pkt_nr; + goto packets_out_of_order; + } + net->compress_pkt_nr= ++net->pkt_nr; #ifdef HAVE_COMPRESS if (net->compress) { @@ -1027,6 +1025,21 @@ my_real_read(NET *net, size_t *complen, } #endif } +#ifndef MYSQL_SERVER + else if (expect_error_packet) + { + /* + This check is safe both for compressed and not compressed protocol + as for the compressed protocol errors are not compressed anymore. + */ + if (net->buff[net->where_b] != (uchar) 255) + { + /* Restore pkt_nr to original value */ + net->pkt_nr--; + goto packets_out_of_order; + } + } +#endif } end: @@ -1040,7 +1053,7 @@ end: net->reading_or_writing=0; #ifdef DEBUG_DATA_PACKETS if (len != packet_error) - DBUG_DUMP("data", net->buff+net->where_b, len); + DBUG_DUMP("data_read", net->buff+net->where_b, len); #endif #ifdef MYSQL_SERVER if (server_extension != NULL) @@ -1051,9 +1064,35 @@ end: } #endif return(len); + +packets_out_of_order: + { + DBUG_PRINT("error", + ("Packets out of order (Found: %d, expected %u)", + (int) net->buff[net->where_b + 3], + net->pkt_nr)); + DBUG_ASSERT(0); + /* + We don't make noise server side, since the client is expected + to break the protocol for e.g. --send LOAD DATA .. LOCAL where + the server expects the client to send a file, but the client + may reply with a new command instead. + */ +#ifndef MYSQL_SERVER + EXTRA_DEBUG_fflush(stdout); + EXTRA_DEBUG_fprintf(stderr,"Error: Packets out of order (Found: %d, expected %d)\n", + (int) net->buff[net->where_b + 3], + (uint) (uchar) net->pkt_nr); + EXTRA_DEBUG_fflush(stderr); +#endif + len= packet_error; + MYSQL_SERVER_my_error(ER_NET_PACKETS_OUT_OF_ORDER, MYF(0)); + goto end; + } } + /* Old interface. See my_net_read_packet() for function description */ #undef my_net_read diff --git a/sql/protocol.cc b/sql/protocol.cc index c1614f4e7e4..777f124f502 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -373,7 +373,8 @@ bool net_send_error_packet(THD *thd, uint sql_errno, const char *err, uint error; char converted_err[MYSQL_ERRMSG_SIZE]; char buff[2+1+SQLSTATE_LENGTH+MYSQL_ERRMSG_SIZE], *pos; - + my_bool ret; + uint8 save_compress; DBUG_ENTER("send_error_packet"); if (net->vio == 0) @@ -401,8 +402,16 @@ bool net_send_error_packet(THD *thd, uint sql_errno, const char *err, /* Converted error message is always null-terminated. */ length= (uint) (strmake(pos, converted_err, MYSQL_ERRMSG_SIZE - 1) - buff); - DBUG_RETURN(net_write_command(net,(uchar) 255, (uchar*) "", 0, (uchar*) buff, - length)); + /* + Ensure that errors are not compressed. This is to ensure we can + detect out of bands error messages in the client + */ + if ((save_compress= net->compress)) + net->compress= 2; + ret= net_write_command(net,(uchar) 255, (uchar*) "", 0, (uchar*) buff, + length); + net->compress= save_compress; + DBUG_RETURN(ret); } #endif /* EMBEDDED_LIBRARY */ |