summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/mysql.h1
-rw-r--r--include/mysql_com.h16
-rw-r--r--libmysql/libmysql.c14
-rw-r--r--mysql-test/r/packet.result25
-rw-r--r--mysql-test/t/packet.test31
-rw-r--r--mysys/my_compress.c41
-rw-r--r--sql/net_pkg.cc2
-rw-r--r--sql/net_serv.cc233
-rw-r--r--sql/sql_class.h2
-rw-r--r--sql/sql_parse.cc24
-rwxr-xr-xtests/big_record.pl57
11 files changed, 299 insertions, 147 deletions
diff --git a/include/mysql.h b/include/mysql.h
index d581df91f64..8d497720a23 100644
--- a/include/mysql.h
+++ b/include/mysql.h
@@ -119,6 +119,7 @@ struct st_mysql_options {
char *ssl_ca; /* PEM CA file */
char *ssl_capath; /* PEM directory of CA-s? */
char *ssl_cipher; /* cipher to use */
+ unsigned long max_allowed_packet;
my_bool use_ssl; /* if to use SSL or not */
my_bool compress,named_pipe;
/*
diff --git a/include/mysql_com.h b/include/mysql_com.h
index a7e73405ac0..963c1212794 100644
--- a/include/mysql_com.h
+++ b/include/mysql_com.h
@@ -34,14 +34,14 @@
#define MYSQL_SERVICENAME "MySql"
#endif /* __WIN__ */
-enum enum_server_command {COM_SLEEP,COM_QUIT,COM_INIT_DB,COM_QUERY,
- COM_FIELD_LIST,COM_CREATE_DB,COM_DROP_DB,COM_REFRESH,
- COM_SHUTDOWN,COM_STATISTICS,
- COM_PROCESS_INFO,COM_CONNECT,COM_PROCESS_KILL,
- COM_DEBUG,COM_PING,COM_TIME,COM_DELAYED_INSERT,
- COM_CHANGE_USER, COM_BINLOG_DUMP,
- COM_TABLE_DUMP, COM_CONNECT_OUT,
- COM_REGISTER_SLAVE};
+enum enum_server_command {
+ COM_SLEEP, COM_QUIT, COM_INIT_DB, COM_QUERY, COM_FIELD_LIST,
+ COM_CREATE_DB, COM_DROP_DB, COM_REFRESH, COM_SHUTDOWN, COM_STATISTICS,
+ COM_PROCESS_INFO, COM_CONNECT, COM_PROCESS_KILL, COM_DEBUG, COM_PING,
+ COM_TIME, COM_DELAYED_INSERT, COM_CHANGE_USER, COM_BINLOG_DUMP,
+ COM_TABLE_DUMP, COM_CONNECT_OUT, COM_REGISTER_SLAVE,
+ COM_END /* Must be last! */
+};
#define NOT_NULL_FLAG 1 /* Field can't be NULL */
#define PRI_KEY_FLAG 2 /* Field is part of a primary key */
diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c
index 49c110c738d..152177c0fbe 100644
--- a/libmysql/libmysql.c
+++ b/libmysql/libmysql.c
@@ -60,7 +60,7 @@ static my_bool mysql_client_init=0;
uint mysql_port=0;
my_string mysql_unix_port=0;
ulong net_buffer_length=8192;
-ulong max_allowed_packet=16*1024*1024L;
+ulong max_allowed_packet= 1024L*1024L*1024L;
ulong net_read_timeout= NET_READ_TIMEOUT;
ulong net_write_timeout= NET_WRITE_TIMEOUT;
@@ -713,8 +713,8 @@ static const char *default_options[]=
"character-sets-dir", "default-character-set", "interactive-timeout",
"connect-timeout", "local-infile", "disable-local-infile",
"replication-probe", "enable-reads-from-master", "repl-parse-query",
- "ssl-cipher",
- NullS
+ "ssl-cipher", "max-allowed-packet",
+ NullS
};
static TYPELIB option_types={array_elements(default_options)-1,
@@ -868,6 +868,9 @@ static void mysql_read_default_options(struct st_mysql_options *options,
case 25: /* repl-parse-query */
options->rpl_parse= 1;
break;
+ case 27:
+ options->max_allowed_packet= atoi(opt_arg);
+ break;
default:
DBUG_PRINT("warning",("unknown option: %s",option[0]));
}
@@ -1908,6 +1911,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
mysql->server_version,mysql->server_capabilities,
mysql->server_status, client_flag));
+ /* This needs to be changed as it's not useful with big packets */
int3store(buff+2,max_allowed_packet);
if (user && user[0])
strmake(buff+5,user,32); /* Max user name */
@@ -1935,6 +1939,8 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
goto error;
if (client_flag & CLIENT_COMPRESS) /* We will use compression */
net->compress=1;
+ if (mysql->options.max_allowed_packet)
+ net->max_packet_size= mysql->options.max_allowed_packet;
if (db && mysql_select_db(mysql,db))
goto error;
if (mysql->options.init_command)
@@ -2302,7 +2308,7 @@ mysql_real_query(MYSQL *mysql, const char *query, ulong length)
{
DBUG_ENTER("mysql_real_query");
DBUG_PRINT("enter",("handle: %lx",mysql));
- DBUG_PRINT("query",("Query = \"%s\"",query));
+ DBUG_PRINT("query",("Query = '%-.4096s'",query));
if (mysql_send_query(mysql,query,length))
DBUG_RETURN(-1);
diff --git a/mysql-test/r/packet.result b/mysql-test/r/packet.result
new file mode 100644
index 00000000000..e994e4d63da
--- /dev/null
+++ b/mysql-test/r/packet.result
@@ -0,0 +1,25 @@
+set global max_allowed_packet=100;
+set max_allowed_packet=100;
+set global net_buffer_length=100;
+set net_buffer_length=100;
+SELECT length("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") as len;
+len
+1024
+select repeat('a',200);
+repeat('a',200)
+NULL
+select @@net_buffer_length, @@max_allowed_packet;
+@@net_buffer_length @@max_allowed_packet
+1024 80
+SELECT length("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") as len;
+Got a packet bigger than 'max_allowed_packet'
+set global max_allowed_packet=default;
+set max_allowed_packet=default;
+set global net_buffer_length=default;
+set net_buffer_length=default;
+SELECT length("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") as len;
+len
+100
+select length(repeat('a',200));
+length(repeat('a',200))
+200
diff --git a/mysql-test/t/packet.test b/mysql-test/t/packet.test
new file mode 100644
index 00000000000..5c4e7efcaf3
--- /dev/null
+++ b/mysql-test/t/packet.test
@@ -0,0 +1,31 @@
+
+#
+# Check protocol handling
+#
+
+connect (con1,localhost,root,,);
+
+connection con1;
+set global max_allowed_packet=100;
+set max_allowed_packet=100;
+set global net_buffer_length=100;
+set net_buffer_length=100;
+# Have to be > 1024 as min value of net_buffer_length is 1024
+SELECT length("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") as len;
+# Should return NULL as 200 is bigger than max_allowed_packet
+select repeat('a',200);
+
+#
+# Connection 2 should get error for too big packets
+#
+connect (con2,localhost,root,,);
+connection con2;
+select @@net_buffer_length, @@max_allowed_packet;
+--error 1153
+SELECT length("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") as len;
+set global max_allowed_packet=default;
+set max_allowed_packet=default;
+set global net_buffer_length=default;
+set net_buffer_length=default;
+SELECT length("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") as len;
+select length(repeat('a',200));
diff --git a/mysys/my_compress.c b/mysys/my_compress.c
index 1e46584d525..dd076311188 100644
--- a/mysys/my_compress.c
+++ b/mysys/my_compress.c
@@ -32,24 +32,28 @@
my_bool my_compress(byte *packet, ulong *len, ulong *complen)
{
+ DBUG_ENTER("my_compress");
if (*len < MIN_COMPRESS_LENGTH)
+ {
*complen=0;
+ DBUG_PRINT("note",("Packet too short: Not compressed"));
+ }
else
{
byte *compbuf=my_compress_alloc(packet,len,complen);
if (!compbuf)
- return *complen ? 0 : 1;
+ DBUG_RETURN(*complen ? 0 : 1);
memcpy(packet,compbuf,*len);
my_free(compbuf,MYF(MY_WME)); }
- return 0;
+ DBUG_RETURN(0);
}
byte *my_compress_alloc(const byte *packet, ulong *len, ulong *complen)
{
byte *compbuf;
- *complen = *len * 120 / 100 + 12;
- if (!(compbuf = (byte *) my_malloc(*complen,MYF(MY_WME))))
+ *complen= *len * 120 / 100 + 12;
+ if (!(compbuf= (byte *) my_malloc(*complen,MYF(MY_WME))))
return 0; /* Not enough memory */
if (compress((Bytef*) compbuf,(ulong *) complen, (Bytef*) packet,
(uLong) *len ) != Z_OK)
@@ -59,31 +63,36 @@ byte *my_compress_alloc(const byte *packet, ulong *len, ulong *complen)
}
if (*complen >= *len)
{
- *complen=0;
- my_free(compbuf,MYF(MY_WME));
+ *complen= 0;
+ my_free(compbuf, MYF(MY_WME));
+ DBUG_PRINT("note",("Packet got longer on compression; Not compressed"));
return 0;
}
- swap(ulong,*len,*complen); /* *len is now packet length */
+ swap(ulong, *len, *complen); /* *len is now packet length */
return compbuf;
}
my_bool my_uncompress (byte *packet, ulong *len, ulong *complen)
{
+ DBUG_ENTER("my_uncompress");
if (*complen) /* If compressed */
{
- byte *compbuf = (byte *) my_malloc (*complen,MYF(MY_WME));
+ byte *compbuf= (byte *) my_malloc(*complen,MYF(MY_WME));
+ int error;
if (!compbuf)
- return 1; /* Not enough memory */
- if (uncompress((Bytef*) compbuf, complen, (Bytef*) packet, *len) != Z_OK)
+ DBUG_RETURN(1); /* Not enough memory */
+ if ((error=uncompress((Bytef*) compbuf, complen, (Bytef*) packet, *len))
+ != Z_OK)
{ /* Probably wrong packet */
- my_free (compbuf,MYF(MY_WME));
- return 1;
+ DBUG_PRINT("error",("Can't uncompress packet, error: %d",error));
+ my_free(compbuf, MYF(MY_WME));
+ DBUG_RETURN(1);
}
- *len = *complen;
- memcpy(packet,compbuf,*len);
- my_free(compbuf,MYF(MY_WME));
+ *len= *complen;
+ memcpy(packet, compbuf, *len);
+ my_free(compbuf, MYF(MY_WME));
}
- return 0;
+ DBUG_RETURN(0);
}
#endif /* HAVE_COMPRESS */
diff --git a/sql/net_pkg.cc b/sql/net_pkg.cc
index 8bb601cebcf..afedba6a259 100644
--- a/sql/net_pkg.cc
+++ b/sql/net_pkg.cc
@@ -222,7 +222,7 @@ net_store_length(char *pkg, ulonglong length)
}
*packet++=254;
int8store(packet,length);
- return (char*) packet+9;
+ return (char*) packet+8;
}
char *
diff --git a/sql/net_serv.cc b/sql/net_serv.cc
index 49454c9df2c..19f68e0b631 100644
--- a/sql/net_serv.cc
+++ b/sql/net_serv.cc
@@ -73,9 +73,9 @@ extern pthread_mutex_t LOCK_bytes_sent , LOCK_bytes_received;
#include "thr_alarm.h"
#define TEST_BLOCKING 8
-#define MAX_THREE_BYTES (256L*256L*256L-1)
+#define MAX_PACKET_LENGTH (256L*256L*256L-1)
-static int net_write_buff(NET *net,const char *packet,ulong len);
+static my_bool net_write_buff(NET *net,const char *packet,ulong len);
/* Init with packet info */
@@ -131,12 +131,16 @@ static my_bool net_realloc(NET *net, ulong length)
{
uchar *buff;
ulong pkt_length;
+ DBUG_ENTER("net_realloc");
+ DBUG_PRINT("enter",("length: %lu", length));
+
if (length >= net->max_packet_size)
{
- DBUG_PRINT("error",("Packet too large (%lu)", length));
+ DBUG_PRINT("error",("Packet too large. Max sixe: %lu",
+ net->max_packet_size));
net->error=1;
net->last_errno=ER_NET_PACKET_TOO_LARGE;
- return 1;
+ DBUG_RETURN(1);
}
pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1);
/*
@@ -151,11 +155,11 @@ static my_bool net_realloc(NET *net, ulong length)
#ifdef MYSQL_SERVER
net->last_errno=ER_OUT_OF_RESOURCES;
#endif
- return 1;
+ DBUG_RETURN(1);
}
net->buff=net->write_pos=buff;
net->buff_end=buff+(net->max_packet=pkt_length);
- return 0;
+ DBUG_RETURN(0);
}
/* Remove unwanted characters from connection */
@@ -217,13 +221,13 @@ my_net_write(NET *net,const char *packet,ulong len)
{
uchar buff[NET_HEADER_SIZE];
/*
- Big packets are handled by splitting them in packets of MAX_THREE_BYTES
- length. The last packet is always a packet that is < MAX_THREE_BYTES.
- (The last packet may even have a lengt of 0)
+ Big packets are handled by splitting them in packets of MAX_PACKET_LENGTH
+ length. The last packet is always a packet that is < MAX_PACKET_LENGTH.
+ (The last packet may even have a length of 0)
*/
- while (len >= MAX_THREE_BYTES)
+ while (len >= MAX_PACKET_LENGTH)
{
- const ulong z_size = MAX_THREE_BYTES;
+ const ulong z_size = MAX_PACKET_LENGTH;
int3store(buff, z_size);
buff[3]= (uchar) net->pkt_nr++;
if (net_write_buff(net, (char*) buff, NET_HEADER_SIZE) ||
@@ -238,7 +242,7 @@ my_net_write(NET *net,const char *packet,ulong len)
if (net_write_buff(net,(char*) buff,NET_HEADER_SIZE))
return 1;
DBUG_DUMP("packet_header",(char*) buff,NET_HEADER_SIZE);
- return net_write_buff(net,packet,len);
+ return test(net_write_buff(net,packet,len));
}
/*
@@ -256,64 +260,107 @@ net_write_command(NET *net,uchar command,const char *packet,ulong len)
ulong length=len+1; /* 1 extra byte for command */
uchar buff[NET_HEADER_SIZE+1];
uint header_size=NET_HEADER_SIZE+1;
+ DBUG_ENTER("net_write_command");
+ DBUG_PRINT("enter",("length: %lu", len));
+
buff[4]=command; /* For first packet */
- if (length >= MAX_THREE_BYTES)
+ if (length >= MAX_PACKET_LENGTH)
{
/* Take into account that we have the command in the first header */
- len= MAX_THREE_BYTES -1;
+ len= MAX_PACKET_LENGTH -1;
do
{
- int3store(buff, MAX_THREE_BYTES);
+ int3store(buff, MAX_PACKET_LENGTH);
buff[3]= (uchar) net->pkt_nr++;
if (net_write_buff(net,(char*) buff, header_size) ||
net_write_buff(net,packet,len))
- return 1;
+ DBUG_RETURN(1);
packet+= len;
- length-= MAX_THREE_BYTES;
- len=MAX_THREE_BYTES;
- header_size=NET_HEADER_SIZE;
- } while (length >= MAX_THREE_BYTES);
+ length-= MAX_PACKET_LENGTH;
+ len= MAX_PACKET_LENGTH;
+ header_size= NET_HEADER_SIZE;
+ } while (length >= MAX_PACKET_LENGTH);
len=length; /* Data left to be written */
}
int3store(buff,length);
buff[3]= (uchar) net->pkt_nr++;
- return test(net_write_buff(net,(char*) buff,header_size) ||
- net_write_buff(net,packet,len) || net_flush(net));
+ DBUG_RETURN(test(net_write_buff(net,(char*) buff,header_size) ||
+ net_write_buff(net,packet,len) || net_flush(net)));
}
/*
Caching the data in a local buffer before sending it.
- One can force the buffer to be flushed with 'net_flush'.
+ SYNOPSIS
+ net_write_buff()
+ net Network handler
+ packet Packet to send
+ len Length of packet
+
+ DESCRIPTION
+ Fill up net->buffer and send it to the client when full.
+
+ If the rest of the to-be-sent-packet is bigger than buffer,
+ send it in one big block (to avoid copying to internal buffer).
+ If not, copy the rest of the data to the buffer and return without
+ sending data.
+
+ NOTES
+ The cached buffer can be sent as it is with 'net_flush()'.
+
+ In this code we have to be careful to not send a packet longer than
+ MAX_PACKET_LENGTH to net_real_write() if we are using the compressed protocol
+ as we store the length of the compressed packet in 3 bytes.
+
+ RETURN
+ 0 ok
+ 1
*/
-static int
+static my_bool
net_write_buff(NET *net,const char *packet,ulong len)
{
- ulong left_length=(ulong) (net->buff_end - net->write_pos);
+ ulong left_length;
+ if (net->compress && net->max_packet > MAX_PACKET_LENGTH)
+ left_length= MAX_PACKET_LENGTH - (net->write_pos - net->buff);
+ else
+ left_length= (ulong) (net->buff_end - net->write_pos);
if (len > left_length)
{
- memcpy((char*) net->write_pos,packet,left_length);
- if (net_real_write(net,(char*) net->buff,net->max_packet))
- return 1;
- net->write_pos=net->buff;
- packet+=left_length;
- len-= left_length;
- left_length= net->max_packet;
-
- /* Send out rest of the blocks as full sized blocks */
- while (len > left_length)
+ if (net->write_pos != net->buff)
{
- if (net_real_write(net, packet, left_length))
+ /* Fill up already used packet and write it */
+ memcpy((char*) net->write_pos,packet,left_length);
+ if (net_real_write(net,(char*) net->buff,
+ (ulong) (net->write_pos - net->buff) + left_length))
return 1;
+ net->write_pos= net->buff;
packet+= left_length;
len-= left_length;
}
+ if (net->compress)
+ {
+ /*
+ We can't have bigger packets than 16M with compression
+ Because the uncompressed length is stored in 3 bytes
+ */
+ left_length= MAX_PACKET_LENGTH;
+ while (len > left_length)
+ {
+ if (net_real_write(net, packet, left_length))
+ return 1;
+ packet+= left_length;
+ len-= left_length;
+ }
+ }
+ if (len > net->max_packet)
+ return net_real_write(net, packet, len) ? 1 : 0;
+ /* Send out rest of the blocks as full sized blocks */
}
memcpy((char*) net->write_pos,packet,len);
- net->write_pos+=len;
+ net->write_pos+= len;
return 0;
}
@@ -364,11 +411,7 @@ net_real_write(NET *net,const char *packet,ulong len)
memcpy(b+header_length,packet,len);
if (my_compress((byte*) b+header_length,&len,&complen))
- {
- DBUG_PRINT("warning",
- ("Compression error; Continuing without compression"));
complen=0;
- }
int3store(&b[NET_HEADER_SIZE],complen);
int3store(b,len);
b[3]=(uchar) (net->compress_pkt_nr++);
@@ -469,28 +512,15 @@ net_real_write(NET *net,const char *packet,ulong len)
*****************************************************************************/
#ifndef NO_ALARM
-/*
- Help function to clear the commuication buffer when we get a too
- big packet
-*/
-static void my_net_skip_rest(NET *net, uint32 remain, thr_alarm_t *alarmed)
+static my_bool net_safe_read(NET *net, char *buff, uint32 length,
+ thr_alarm_t *alarmed)
{
- ALARM alarm_buff;
uint retry_count=0;
- my_bool old_mode;
- uint32 old=remain;
-
- if (!thr_alarm_in_use(&alarmed))
- {
- if (!thr_alarm(alarmed,net->read_timeout,&alarm_buff) ||
- vio_blocking(net->vio, TRUE, &old_mode) < 0)
- return; /* Can't setup, abort */
- }
- while (remain > 0)
+ while (length > 0)
{
- ulong length;
- if ((int) (length=vio_read(net->vio,(char*) net->buff,remain)) <= 0L)
+ int tmp;
+ if ((tmp=vio_read(net->vio,(char*) net->buff, length)) <= 0)
{
my_bool interrupted = vio_should_retry(net->vio);
if (!thr_got_alarm(&alarmed) && interrupted)
@@ -498,17 +528,60 @@ static void my_net_skip_rest(NET *net, uint32 remain, thr_alarm_t *alarmed)
if (retry_count++ < net->retry_count)
continue;
}
- return;
+ return 1;
}
- remain -= (uint32) length;
- if (!remain && old==MAX_THREE_BYTES &&
- (length=vio_read(net->vio,(char*) net->buff,NET_HEADER_SIZE)))
+ length-= tmp;
+ }
+ return 0;
+}
+
+/*
+ Help function to clear the commuication buffer when we get a too big packet.
+
+ SYNOPSIS
+ my_net_skip_rest()
+ net Communication handle
+ remain Bytes to read
+ alarmed Parameter for thr_alarm()
+ alarm_buff Parameter for thr_alarm()
+
+ RETURN VALUES
+ 0 Was able to read the whole packet
+ 1 Got mailformed packet from client
+*/
+
+static my_bool my_net_skip_rest(NET *net, uint32 remain, thr_alarm_t *alarmed,
+ ALARM *alarm_buff)
+{
+ uint32 old=remain;
+ DBUG_ENTER("my_net_skip_rest");
+ DBUG_PRINT("enter",("bytes_to_skip: %u", (uint) remain));
+
+ if (!thr_alarm_in_use(&alarmed))
+ {
+ my_bool old_mode;
+ if (!thr_alarm(alarmed,net->read_timeout, alarm_buff) ||
+ vio_blocking(net->vio, TRUE, &old_mode) < 0)
+ DBUG_RETURN(1); /* Can't setup, abort */
+ }
+ for (;;)
+ {
+ while (remain > 0)
{
- old=remain= uint3korr(net->buff);
- net->pkt_nr++;
+ uint length= min(remain, net->max_packet);
+ if (net_safe_read(net, (char*) net->buff, length, alarmed))
+ DBUG_RETURN(1);
+ statistic_add(bytes_received, length, &LOCK_bytes_received);
+ remain -= (uint32) length;
}
- statistic_add(bytes_received,length,&LOCK_bytes_received);
+ if (old != MAX_PACKET_LENGTH)
+ break;
+ if (net_safe_read(net, (char*) net->buff, NET_HEADER_SIZE, alarmed))
+ DBUG_RETURN(1);
+ old=remain= uint3korr(net->buff);
+ net->pkt_nr++;
}
+ DBUG_RETURN(0);
}
#endif /* NO_ALARM */
@@ -607,9 +680,8 @@ my_real_read(NET *net, ulong *complen)
continue;
}
#endif
- DBUG_PRINT("error",("Couldn't read packet: remain: %lu errno: %d length: %ld alarmed: %d",
- remain,vio_errno(net->vio), length,
- thr_got_alarm(&alarmed)));
+ DBUG_PRINT("error",("Couldn't read packet: remain: %u errno: %d length: %ld",
+ remain, vio_errno(net->vio), length));
len= packet_error;
net->error=2; /* Close socket */
#ifdef MYSQL_SERVER
@@ -667,19 +739,12 @@ my_real_read(NET *net, ulong *complen)
{
if (net_realloc(net,helping))
{
-#ifdef MYSQL_SERVER
-#ifndef NO_ALARM
- if (net->compress)
- {
- len= packet_error;
- goto end;
- }
- my_net_skip_rest(net, (uint32) len, &alarmed);
- len=0;
-#endif
-#else
- len= packet_error; /* Return error */
+#if defined(MYSQL_SERVER) && !defined(NO_ALARM)
+ if (!net->compress &&
+ !my_net_skip_rest(net, (uint32) len, &alarmed, &alarm_buff))
+ net->error= 3; /* Successfully skiped packet */
#endif
+ len= packet_error; /* Return error and close connection */
goto end;
}
}
@@ -723,7 +788,7 @@ my_net_read(NET *net)
{
#endif
len = my_real_read(net,&complen);
- if (len == MAX_THREE_BYTES)
+ if (len == MAX_PACKET_LENGTH)
{
/* First packet of a multi-packet. Concatenate the packets */
ulong save_pos = net->where_b;
@@ -733,7 +798,7 @@ my_net_read(NET *net)
net->where_b += len;
total_length += len;
len = my_real_read(net,&complen);
- } while (len == MAX_THREE_BYTES);
+ } while (len == MAX_PACKET_LENGTH);
if (len != packet_error)
len+= total_length;
net->where_b = save_pos;
@@ -791,7 +856,7 @@ my_net_read(NET *net)
else
start_of_packet+= read_length + NET_HEADER_SIZE;
- if (read_length != MAX_THREE_BYTES) /* last package */
+ if (read_length != MAX_PACKET_LENGTH) /* last package */
{
multi_byte_packet= 0; /* No last zero len packet */
break;
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 8c4a7b83ebf..af80c3e31ac 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -358,7 +358,7 @@ public:
uint client_capabilities; /* What the client supports */
/* Determines if which non-standard SQL behaviour should be enabled */
uint sql_mode;
- uint max_client_packet_length;
+ ulong max_client_packet_length;
ulong master_access; /* Global privileges from mysql.user */
ulong db_access; /* Privileges for current db */
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 0f072a73ac6..599c31d43ca 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -75,7 +75,8 @@ const char *command_name[]={
"Sleep", "Quit", "Init DB", "Query", "Field List", "Create DB",
"Drop DB", "Refresh", "Shutdown", "Statistics", "Processlist",
"Connect","Kill","Debug","Ping","Time","Delayed_insert","Change user",
- "Binlog Dump","Table Dump", "Connect Out", "Register Slave"
+ "Binlog Dump","Table Dump", "Connect Out", "Register Slave",
+ "Error" // Last command number
};
bool volatile abort_slave = 0;
@@ -209,7 +210,7 @@ static bool check_user(THD *thd,enum_server_command command, const char *user,
!(thd->client_capabilities &
CLIENT_LONG_PASSWORD),&ur);
DBUG_PRINT("info",
- ("Capabilities: %d packet_length: %d Host: '%s' User: '%s' Using password: %s Access: %u db: '%s'",
+ ("Capabilities: %d packet_length: %ld Host: '%s' User: '%s' Using password: %s Access: %u db: '%s'",
thd->client_capabilities, thd->max_client_packet_length,
thd->host_or_ip, thd->priv_user,
passwd[0] ? "yes": "no",
@@ -882,20 +883,22 @@ bool do_command(THD *thd)
net_new_transaction(net);
if ((packet_length=my_net_read(net)) == packet_error)
{
- DBUG_PRINT("info",("Got error reading command from socket %s",
- vio_description(net->vio) ));
- return TRUE;
- }
- else if (!packet_length)
- {
+ DBUG_PRINT("info",("Got error %d reading command from socket %s",
+ net->error,
+ vio_description(net->vio)));
+ /* Check if we can continue without closing the connection */
+ if (net->error != 3)
+ DBUG_RETURN(TRUE); // We have to close it.
send_error(net,net->last_errno,NullS);
- net->error=0;
+ net->error= 0;
DBUG_RETURN(FALSE);
}
else
{
packet=(char*) net->read_pos;
command = (enum enum_server_command) (uchar) packet[0];
+ if (command >= COM_END)
+ command= COM_END; // Wrong command
DBUG_PRINT("info",("Command on %s = %d (%s)",
vio_description(net->vio), command,
command_name[command]));
@@ -1025,7 +1028,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(),QUERY_PRIOR);
mysql_log.write(thd,command,"%s",thd->query);
- DBUG_PRINT("query",("%s",thd->query));
+ DBUG_PRINT("query",("%-.4096s",thd->query));
/* thd->query_length is set by mysql_parse() */
mysql_parse(thd,thd->query,packet_length);
if (!(specialflag & SPECIAL_NO_PRIOR))
@@ -1223,6 +1226,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
case COM_CONNECT: // Impossible here
case COM_TIME: // Impossible from client
case COM_DELAYED_INSERT:
+ case COM_END:
default:
send_error(net, ER_UNKNOWN_COM_ERROR);
break;
diff --git a/tests/big_record.pl b/tests/big_record.pl
index 52d3dca5f7b..08547b50823 100755
--- a/tests/big_record.pl
+++ b/tests/big_record.pl
@@ -1,58 +1,69 @@
#!/usr/bin/perl
-# This is a test with stores big records in a blob
+# This is a test with stores big records in a blob.
# Note that for the default test the mysql server should have been
-# started with at least 'mysqld -O max_allowed_packet=200k'
-
-$host= shift || "";
-$test_db="test";
-$opt_user=$opt_password="";
+# started with at least 'mysqld -O max_allowed_packet=30M' and you should have
+# at least 256M memory in your computer.
use DBI;
-$|= 1; # Autoflush
+use Getopt::Long;
+
+$opt_host="";
+$opt_user=$opt_password="";
+$opt_db="test";
+$opt_rows=200; # Test of blobs up to ($rows-1)*100000+1 bytes
+$opt_compress=0;
+$opt_table="test_big_record";
-$table="test_big_record";
-$rows=20; # Test of blobs up to ($rows-1)*10000+1 bytes
+GetOptions("host=s","db=s","user=s", "password=s", "table=s", "rows=i",
+ "compress") || die "Aborted";
print "Connection to database $test_db\n";
-$dbh = DBI->connect("DBI:mysql:$test_db:$host",$opt_user,$opt_password) || die "Can't connect: $DBI::errstr\n";
+$extra_options="";
+$extra_options.=":mysql_compression=1" if ($opt_compress);
-$dbh->do("drop table if exists $table");
+$dbh = DBI->connect("DBI:mysql:$opt_db:$host$extra_options",$opt_user,$opt_password) || die "Can't connect: $DBI::errstr\n";
-print "Creating table $table\n";
+$dbh->do("drop table if exists $opt_table");
+
+print "Creating table $opt_table\n";
($dbh->do("\
-CREATE TABLE $table (
+CREATE TABLE $opt_table (
auto int(5) unsigned NOT NULL DEFAULT '0' auto_increment,
- test mediumblob,
+ test longblob,
PRIMARY KEY (auto))")) or die $DBI::errstr;
-print "Inserting $rows records\n";
+print "Inserting $opt_rows records\n";
+
+$|=1; # Flush output to stdout to be able to monitor process
-for ($i=0 ; $i < $rows ; $i++)
+for ($i=0 ; $i < $opt_rows ; $i++)
{
- $tmp= chr(65+$i) x ($i*10000+1);
+ $tmp= chr(65+($i % 16)) x ($i*100000+1);
+ print $i," ",length($tmp),"\n";
$tmp= $dbh->quote($tmp);
- $dbh->do("insert into $table (test) values ($tmp)") or die $DBI::errstr;
+ $dbh->do("insert into $opt_table (test) values ($tmp)") or die $DBI::errstr;
}
-print "Testing records\n";
+print "Reading records\n";
+
+$sth=$dbh->prepare("select * from $opt_table", { "mysql_use_result" => 1}) or die $dbh->errstr;
-$sth=$dbh->prepare("select * from $table") or die $dbh->errstr;
$sth->execute() or die $sth->errstr;
$i=0;
while (($row = $sth->fetchrow_arrayref))
{
print $row->[0]," ",length($row->[1]),"\n";
- die "Record $i had wrong data in blob" if ($row->[1] ne (chr(65+$i)) x ($i*10000+1));
+ die "Record $i had wrong data in blob" if ($row->[1] ne (chr(65+($i % 16)) x ($i*100000+1)));
$i++;
}
-die "Didn't get all rows from server" if ($i != $rows);
+die "Didn't get all rows from server" if ($i != $opt_rows);
-$dbh->do("drop table $table") or die $DBI::errstr;
+$dbh->do("drop table $opt_table") or die $DBI::errstr;
print "Test ok\n";
exit 0;