From c9c78d0c3189dc681e6608c249cc0b9fe8ef215c Mon Sep 17 00:00:00 2001 From: "holzboote@googlemail.com" <> Date: Wed, 20 Nov 2013 20:37:30 +0100 Subject: [PATCH] Fix for CONC-60: crash when STMT_ATTR_UPDATE_MAX_LENGTH attribute was set and new date formats are used. Special thanks to Lionel Elie Mamane and Daniel Bart for their tremendous help. --- libmariadb/my_stmt.c | 39 +++++++++++++++++++++-------------- libmariadb/my_stmt_codec.c | 8 +++---- unittest/libmariadb/ps.c | 38 ++++++++++++++++++++++++++++++++-- unittest/libmariadb/ps_bugs.c | 1 + 4 files changed, 65 insertions(+), 21 deletions(-) diff --git a/libmariadb/my_stmt.c b/libmariadb/my_stmt.c index c4888e74..aebcee88 100644 --- a/libmariadb/my_stmt.c +++ b/libmariadb/my_stmt.c @@ -194,39 +194,48 @@ int mthd_stmt_read_all_rows(MYSQL_STMT *stmt) { uchar *null_ptr, bit_offset= 4; uchar *cp= p; - uint i; + unsigned int i; cp++; /* skip first byte */ null_ptr= cp; cp+= (stmt->field_count + 9) / 8; - + for (i=0; i < stmt->field_count; i++) { if (!(*null_ptr & bit_offset)) { - switch(mysql_ps_fetch_functions[stmt->fields[i].type].max_len) { - case -1: + if (mysql_ps_fetch_functions[stmt->fields[i].type].pack_len < 0) { + /* We need to calculate the sizes for date and time types */ size_t len= net_field_length(&cp); + switch(stmt->fields[i].type) { + case MYSQL_TYPE_TIME: + case MYSQL_TYPE_DATE: + case MYSQL_TYPE_DATETIME: + case MYSQL_TYPE_TIMESTAMP: + stmt->fields[i].max_length= mysql_ps_fetch_functions[stmt->fields[i].type].max_len; + break; + default: + if (len > stmt->fields[i].max_length) + stmt->fields[i].max_length= (ulong)len; + break; + } cp+= len; - if (len > stmt->fields[i].max_length) - stmt->fields[i].max_length= (ulong)len; - break; } - default: + else + { if (!stmt->fields[i].max_length) stmt->fields[i].max_length= mysql_ps_fetch_functions[stmt->fields[i].type].max_len; cp+= mysql_ps_fetch_functions[stmt->fields[i].type].pack_len; - break; + } + } + if (!((bit_offset <<=1) & 255)) + { + bit_offset= 1; /* To next byte */ + null_ptr++; } } - if (!((bit_offset <<=1) & 255)) - { - bit_offset= 1; /* To next byte */ - null_ptr++; - } } - } current->length= packet_len; diff --git a/libmariadb/my_stmt_codec.c b/libmariadb/my_stmt_codec.c index cef9a8be..0261195c 100644 --- a/libmariadb/my_stmt_codec.c +++ b/libmariadb/my_stmt_codec.c @@ -863,11 +863,11 @@ void mysql_init_ps_subsystem(void) mysql_ps_fetch_functions[MYSQL_TYPE_DOUBLE].max_len = MAX_DOUBLE_STRING_REP_LENGTH; mysql_ps_fetch_functions[MYSQL_TYPE_TIME].func = ps_fetch_datetime; - mysql_ps_fetch_functions[MYSQL_TYPE_TIME].pack_len = 13; + mysql_ps_fetch_functions[MYSQL_TYPE_TIME].pack_len = MYSQL_PS_SKIP_RESULT_W_LEN; mysql_ps_fetch_functions[MYSQL_TYPE_TIME].max_len = 15; mysql_ps_fetch_functions[MYSQL_TYPE_DATE].func = ps_fetch_datetime; - mysql_ps_fetch_functions[MYSQL_TYPE_DATE].pack_len = 5; + mysql_ps_fetch_functions[MYSQL_TYPE_DATE].pack_len = MYSQL_PS_SKIP_RESULT_W_LEN; mysql_ps_fetch_functions[MYSQL_TYPE_DATE].max_len = 10; mysql_ps_fetch_functions[MYSQL_TYPE_NEWDATE].func = ps_fetch_string; @@ -875,11 +875,11 @@ void mysql_init_ps_subsystem(void) mysql_ps_fetch_functions[MYSQL_TYPE_NEWDATE].max_len = -1; mysql_ps_fetch_functions[MYSQL_TYPE_DATETIME].func = ps_fetch_datetime; - mysql_ps_fetch_functions[MYSQL_TYPE_DATETIME].pack_len= 12; + mysql_ps_fetch_functions[MYSQL_TYPE_DATETIME].pack_len= MYSQL_PS_SKIP_RESULT_W_LEN; mysql_ps_fetch_functions[MYSQL_TYPE_DATETIME].max_len = 30; mysql_ps_fetch_functions[MYSQL_TYPE_TIMESTAMP].func = ps_fetch_datetime; - mysql_ps_fetch_functions[MYSQL_TYPE_TIMESTAMP].pack_len= 12; + mysql_ps_fetch_functions[MYSQL_TYPE_TIMESTAMP].pack_len= MYSQL_PS_SKIP_RESULT_W_LEN; mysql_ps_fetch_functions[MYSQL_TYPE_TIMESTAMP].max_len = 30; mysql_ps_fetch_functions[MYSQL_TYPE_TINY_BLOB].func = ps_fetch_bin; diff --git a/unittest/libmariadb/ps.c b/unittest/libmariadb/ps.c index 251af6da..cea84753 100644 --- a/unittest/libmariadb/ps.c +++ b/unittest/libmariadb/ps.c @@ -26,6 +26,38 @@ with this program; if not, write to the Free Software Foundation, Inc., /* Utility function to verify the field members */ +static int test_conc60(MYSQL *mysql) +{ + MYSQL_STMT *stmt; + int rc; + char *query= "SELECT * FROM agendas"; + my_bool x= 1; + + stmt= mysql_stmt_init(mysql); + + rc= mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (void *)&x); + + rc= mysql_stmt_prepare(stmt, query, strlen(query)); + if (rc && mysql_stmt_errno(stmt) == 1146) { + diag("Internal test - customer data not available"); + return SKIP; + } + 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); + + rc= mysql_stmt_free_result(stmt); + check_stmt_rc(rc, stmt); + + mysql_stmt_close(stmt); + + return OK; +} + static int test_prepare_insert_update(MYSQL *mysql) { MYSQL_STMT *stmt; @@ -1267,7 +1299,7 @@ static int test_long_data_str1(MYSQL *mysql) int rc, i, rowcount= 0; char data[255]; long length; - ulong max_blob_length, blob_length, length1; + size_t max_blob_length, blob_length, length1; my_bool true_value; MYSQL_RES *result; MYSQL_BIND my_bind[2]; @@ -1386,6 +1418,7 @@ static int test_long_data_str1(MYSQL *mysql) result= mysql_stmt_result_metadata(stmt); field= mysql_fetch_fields(result); + diag("max_length: %lu max_blob_length: %lu", field->max_length, max_blob_length); FAIL_UNLESS(field->max_length == max_blob_length, "field->max_length != max_blob_length"); /* Fetch results into a data buffer that is smaller than data */ @@ -4738,7 +4771,7 @@ int test_notrunc(MYSQL *mysql) char buffer[5], buffer2[5]; int rc; my_bool error= 0; - unsigned long len= 1, len2; + unsigned long len= 1; char *query= "SELECT '1234567890', 'foo' FROM DUAL"; @@ -4780,6 +4813,7 @@ int test_notrunc(MYSQL *mysql) } struct my_tests_st my_tests[] = { + {"test_conc60", test_conc60, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_notrunc", test_notrunc, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_fracseconds", test_fracseconds, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_blob_9000", test_blob_9000, TEST_CONNECTION_DEFAULT, 0, NULL , NULL}, diff --git a/unittest/libmariadb/ps_bugs.c b/unittest/libmariadb/ps_bugs.c index 3c0637cc..6031ca92 100644 --- a/unittest/libmariadb/ps_bugs.c +++ b/unittest/libmariadb/ps_bugs.c @@ -2914,6 +2914,7 @@ static int test_bug6096(MYSQL *mysql) } mysql_stmt_bind_result(stmt, my_bind); rc= mysql_stmt_fetch(stmt); + diag("rc=%d", rc); check_stmt_rc(rc, stmt); rc= mysql_stmt_fetch(stmt); FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");