diff --git a/libmariadb/my_compress.c b/libmariadb/my_compress.c index 24d902ec..82934044 100644 --- a/libmariadb/my_compress.c +++ b/libmariadb/my_compress.c @@ -83,6 +83,7 @@ my_bool my_uncompress (unsigned char *packet, size_t *len, size_t *complen) memcpy(packet,compbuf,*len); my_free((gptr)compbuf,MYF(MY_WME)); } + else *complen= *len; return 0; } #endif /* HAVE_COMPRESS */ diff --git a/libmariadb/net.c b/libmariadb/net.c index 134322e0..b393ff29 100644 --- a/libmariadb/net.c +++ b/libmariadb/net.c @@ -37,7 +37,7 @@ #define MAX_PACKET_LENGTH (256L*256L*256L-1) -/* net_buffer_length and max_allowec_packet are defined in mysql.h +/* net_buffer_length and max_allowed_packet are defined in mysql.h See bug conc-57 */ #undef net_buffer_length @@ -713,54 +713,120 @@ ulong my_net_read(NET *net) } else { - if (net->remain_in_buf) + /* + compressed protocol: + + -------------------------------------- + packet_lengt h 3 + sequence_id 1 + uncompressed_length 3 + -------------------------------------- + compressed data packet_length - 7 + -------------------------------------- + + Another packet will follow if: + packet_length == MAX_PACKET_LENGTH + + Last package will be identified by + - packet_length is zero (special case) + - packet_length < MAX_PACKET_LENGTH + */ + + size_t packet_length, + buffer_length; + size_t current= 0, start= 0; + my_bool is_multi_packet= 0; + + /* check if buffer is empty */ + if (!net->remain_in_buf) { - /* restore 0 character */ + buffer_length= 0; + } + else + { + /* save position and restore \0 character */ + buffer_length= net->buf_length; + current= net->buf_length - net->remain_in_buf; + start= current; net->buff[net->buf_length - net->remain_in_buf]=net->save_char; } for (;;) { - if (net->remain_in_buf) + if (buffer_length - current >= 4) { - uchar *pos = net->buff + net->buf_length - net->remain_in_buf; - if (net->remain_in_buf >= 4) + uchar *pos= net->buff + current; + packet_length= uint3korr(pos); + + /* check if we have last package (special case: zero length) */ + if (!packet_length) { - net->length = uint3korr(pos); - if (net->length <= net->remain_in_buf - 4) + current+= 4; /* length + sequence_id, + no more data will follow */ + break; + } + if (packet_length + 4 <= buffer_length - current) + { + if (!is_multi_packet) { - /* We have a full packet */ - len=net->length; - net->remain_in_buf -= net->length + 4; - net->read_pos=pos + 4; - break; /* We have a full packet */ + current= current + packet_length + 4; } + else + { + /* remove packet_header */ + memmove(net->buff + current, + net->buff + current + 4, + buffer_length - current); + buffer_length-= 4; + current+= packet_length; + } + /* do we have last packet ? */ + if (packet_length != MAX_PACKET_LENGTH) + { + is_multi_packet= 0; + break; + } + else + is_multi_packet= 1; + if (start) + { + memmove(net->buff, net->buff + start, + buffer_length - start); + /* decrease buflen*/ + buffer_length-= start; + start= 0; + } + continue; } - /* Move data down to read next data packet after current one */ - if (net->buf_length != net->remain_in_buf) - { - memmove(net->buff,pos,net->remain_in_buf); - net->buf_length=net->remain_in_buf; - } - net->where_b=net->buf_length; } - else - { - net->where_b=0; - net->buf_length=0; + if (start) + { + memmove(net->buff, net->buff + start, buffer_length - start); + /* decrease buflen and current */ + current -= start; + buffer_length-= start; + start= 0; } - if ((len = my_real_read(net,(size_t *)&complen)) == packet_error) + net->where_b=buffer_length; + + if ((packet_length = my_real_read(net,(size_t *)&complen)) == packet_error) break; - if (my_uncompress((unsigned char*) net->buff + net->where_b, &len, &complen)) + if (my_uncompress((unsigned char*) net->buff + net->where_b, &packet_length, &complen)) { len= packet_error; net->error=2; /* caller will close socket */ net->last_errno=ER_NET_UNCOMPRESS_ERROR; break; } - net->buf_length+=(unsigned long)len; - net->remain_in_buf+=(unsigned long)len; + buffer_length+= complen; } + /* set values */ + net->buf_length= buffer_length; + net->remain_in_buf= buffer_length - current; + net->read_pos= net->buff + start + 4; + len= current - start - 4; + if (is_multi_packet) + len-= 4; if (len != packet_error) { net->save_char= net->read_pos[len]; /* Must be saved */ diff --git a/unittest/libmariadb/basic-t.c b/unittest/libmariadb/basic-t.c index c3c08f8a..a27ab9d0 100644 --- a/unittest/libmariadb/basic-t.c +++ b/unittest/libmariadb/basic-t.c @@ -30,11 +30,21 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "my_test.h" #include "ma_common.h" -static int test_conc68(MYSQL *mysql) +static int test_conc70(MYSQL *my) { int rc; MYSQL_RES *res; MYSQL_ROW row; + MYSQL *mysql= mysql_init(NULL); + + mysql_query(my, "SET @a:=@@max_allowed_packet"); + check_mysql_rc(rc, my); + + mysql_query(my, "SET global max_allowed_packet=1024*1024*22"); + + mysql_options(mysql, MYSQL_OPT_COMPRESS, (void *)1); + FAIL_IF(!mysql_real_connect(mysql, hostname, username, password, schema, + port, socketname, 0), mysql_error(my)); rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); check_mysql_rc(rc, mysql); @@ -43,7 +53,7 @@ static int test_conc68(MYSQL *mysql) check_mysql_rc(rc, mysql); rc= mysql_query(mysql, "INSERT INTO t1 VALUES (REPEAT('A', 1024 * 1024 * 20))"); - check_mysql_rc(rc, mysql); + check_mysql_rc(rc, mysql); rc= mysql_query(mysql, "SELECT a FROM t1"); check_mysql_rc(rc, mysql); @@ -55,47 +65,65 @@ static int test_conc68(MYSQL *mysql) } row= mysql_fetch_row(res); + diag("Length: %ld", strlen(row[0])); FAIL_IF(strlen(row[0]) != 1024 * 1024 * 20, "Wrong length"); + mysql_free_result(res); + mysql_close(mysql); + + rc= mysql_query(my, "SET global max_allowed_packet=@a"); + check_mysql_rc(rc, my); return OK; } -static int test_conc66(MYSQL *my) +static int test_conc68(MYSQL *my) { - MYSQL *mysql= mysql_init(NULL); int rc; - FILE *fp; + MYSQL_RES *res; + MYSQL_ROW row; + MYSQL *mysql= mysql_init(NULL); - fp= fopen("./my.cnf", "w"); - fprintf(fp, "[conc-66]\nuser=conc-66\npassword=\"my#pass;word\""); - fclose(fp); + mysql_query(my, "SET @a:=@@max_allowed_packet"); + check_mysql_rc(rc, my); - rc= mysql_query(my, "GRANT ALL ON test.* to 'conc-66'@'%' identified by 'my#pass;word'"); - check_mysql_rc(rc, mysql); - rc= mysql_query(my, "FLUSH PRIVILEGES"); + mysql_query(my, "SET global max_allowed_packet=1024*1024*22"); + + FAIL_IF(!mysql_real_connect(mysql, hostname, username, password, schema, + port, socketname, 0), mysql_error(my)); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); check_mysql_rc(rc, mysql); - rc= mysql_options(mysql, MYSQL_READ_DEFAULT_GROUP, "conc-66"); - check_mysql_rc(rc, mysql); - rc= mysql_options(mysql, MYSQL_READ_DEFAULT_FILE, "./my.cnf"); + rc= mysql_query(mysql, "CREATE TABLE t1 (a LONGBLOB)"); check_mysql_rc(rc, mysql); - rc= mysql_real_connect(mysql, hostname, NULL, NULL, schema, - port, socketname, 0); - if (!rc) { - diag("Error: %s\n", mysql_error(mysql)); - mysql_close(mysql); + rc= mysql_query(mysql, "INSERT INTO t1 VALUES (REPEAT('A', 1024 * 1024 * 20))"); + check_mysql_rc(rc, mysql); + + rc= mysql_query(mysql, "SELECT a FROM t1"); + check_mysql_rc(rc, mysql); + + if (!(res= mysql_store_result(mysql))) + { + diag("Error: %s", mysql_error(mysql)); return FAIL; } + + row= mysql_fetch_row(res); + diag("Length: %ld", strlen(row[0])); + FAIL_IF(strlen(row[0]) != 1024 * 1024 * 20, "Wrong length"); + + mysql_free_result(res); mysql_close(mysql); - rc= mysql_query(my, "DROP USER 'conc-66'"); - check_mysql_rc(rc, mysql); + rc= mysql_query(my, "SET global max_allowed_packet=@a"); + check_mysql_rc(rc, my); - return OK; + return OK; } + static int basic_connect(MYSQL *mysql) { MYSQL_ROW row; @@ -572,7 +600,6 @@ static int test_reconnect_maxpackage(MYSQL *my) memset(query + 8, 'A', max_packet); strcat(query, "' FROM DUAL"); - rc= mysql_query(mysql, query); free(query); if (!rc) @@ -621,8 +648,8 @@ static int test_compressed(MYSQL *my) } struct my_tests_st my_tests[] = { + {"test_conc70", test_conc70, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_conc68", test_conc68, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, - {"test_conc66", test_conc66, TEST_CONNECTION_NEW, 0, NULL, NULL}, {"test_compressed", test_compressed, TEST_CONNECTION_NONE, 0, NULL, NULL}, {"test_reconnect_maxpackage", test_reconnect_maxpackage, TEST_CONNECTION_NONE, 0, NULL, NULL}, {"basic_connect", basic_connect, TEST_CONNECTION_NONE, 0, NULL, NULL}, diff --git a/unittest/libmariadb/connection.c b/unittest/libmariadb/connection.c index 00077105..716e041b 100644 --- a/unittest/libmariadb/connection.c +++ b/unittest/libmariadb/connection.c @@ -57,7 +57,8 @@ static int test_conc66(MYSQL *my) diag("Error: %s", mysql_error(mysql)); return FAIL; } - rc= mysql_query(my, "DROP USER conc66"); + rc= mysql_query(my, "DROP USER conc66@localhost"); + check_mysql_rc(rc, my); mysql_close(mysql); return OK; diff --git a/unittest/libmariadb/misc.c b/unittest/libmariadb/misc.c index e2192eeb..462d8f06 100644 --- a/unittest/libmariadb/misc.c +++ b/unittest/libmariadb/misc.c @@ -25,29 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "ma_common.h" -static int test_conc60(MYSQL *mysql) -{ - MYSQL_STMT *stmt= mysql_stmt_init(mysql); - char *stmtstr= "SELECT * FROM agendas"; - int rc; - - rc= mysql_stmt_prepare(stmt, stmtstr, strlen(stmtstr)); - check_stmt_rc(rc, stmt); - rc= mysql_stmt_execute(stmt); - check_stmt_rc(rc, stmt); - - rc= mysql_stmt_store_result(stmt); - check_stmt_rc(rc, stmt); - - diag("rows: %u", mysql_stmt_num_rows(stmt)); - - while (mysql_stmt_fetch(stmt)); - - mysql_stmt_close(stmt); - - return(OK); -} /* Bug#28075 "COM_DEBUG crashes mysqld" @@ -984,7 +962,6 @@ static int test_connect_attrs(MYSQL *my) struct my_tests_st my_tests[] = { {"test_connect_attrs", test_connect_attrs, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, - {"test_conc60", test_conc60, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_conc49", test_conc49, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_bug28075", test_bug28075, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_bug28505", test_bug28505, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},