diff --git a/CMakeLists.txt b/CMakeLists.txt index 820f295a..32f258f0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ # This is the LGPL libmariadb project. -CMAKE_MINIMUM_REQUIRED(VERSION 2.8.12 FATAL_ERROR) +CMAKE_MINIMUM_REQUIRED(VERSION 3.5.1 FATAL_ERROR) INCLUDE(CheckFunctionExists) IF(COMMAND CMAKE_POLICY) SET(NEW_POLICIES CMP0003 CMP0022 CMP0023 CMP0057 CMP0077 CMP0069 CMP0075) diff --git a/include/mariadb_com.h b/include/mariadb_com.h index 63185dbe..dc429527 100644 --- a/include/mariadb_com.h +++ b/include/mariadb_com.h @@ -427,30 +427,6 @@ struct rand_struct { double max_value_dbl; }; - /* The following is for user defined functions */ - -enum Item_result {STRING_RESULT,REAL_RESULT,INT_RESULT,ROW_RESULT,DECIMAL_RESULT}; - -typedef struct st_udf_args -{ - unsigned int arg_count; /* Number of arguments */ - enum Item_result *arg_type; /* Pointer to item_results */ - char **args; /* Pointer to argument */ - unsigned long *lengths; /* Length of string arguments */ - char *maybe_null; /* Set to 1 for all maybe_null args */ -} UDF_ARGS; - - /* This holds information about the result */ - -typedef struct st_udf_init -{ - my_bool maybe_null; /* 1 if function can return NULL */ - unsigned int decimals; /* for real functions */ - unsigned int max_length; /* For string functions */ - char *ptr; /* free pointer for function data */ - my_bool const_item; /* 0 if result is independent of arguments */ -} UDF_INIT; - /* Connection types */ #define MARIADB_CONNECTION_UNIXSOCKET 0 #define MARIADB_CONNECTION_TCP 1 diff --git a/include/mariadb_rpl.h b/include/mariadb_rpl.h index f12fdfa1..0d0adf41 100644 --- a/include/mariadb_rpl.h +++ b/include/mariadb_rpl.h @@ -73,6 +73,8 @@ extern "C" { #define SEMI_SYNC_INDICATOR 0xEF #define SEMI_SYNC_ACK_REQ 0x01 +enum Item_result {STRING_RESULT,REAL_RESULT,INT_RESULT,ROW_RESULT,DECIMAL_RESULT}; + /* Options */ enum mariadb_rpl_option { MARIADB_RPL_FILENAME, /* Filename and length */ diff --git a/libmariadb/ma_stmt_codec.c b/libmariadb/ma_stmt_codec.c index afb46b25..ab3ec1ed 100644 --- a/libmariadb/ma_stmt_codec.c +++ b/libmariadb/ma_stmt_codec.c @@ -50,6 +50,7 @@ #include "mysql.h" #include /* ceil() */ #include +#include #ifdef WIN32 #include @@ -1145,29 +1146,25 @@ void ps_fetch_datetime(MYSQL_BIND *r_param, const MYSQL_FIELD * field, length= sprintf(dtbuffer, "%04u-%02u-%02u", tm.year, tm.month, tm.day); break; case MYSQL_TYPE_TIME: - length= sprintf(dtbuffer, "%s%02u:%02u:%02u", (tm.neg ? "-" : ""), tm.hour, tm.minute, tm.second); - if (field->decimals && field->decimals <= 6) + if (field->decimals && (field->decimals <= SEC_PART_DIGITS || + (field->decimals == AUTO_SEC_PART_DIGITS && tm.second_part))) { - char ms[8]; - sprintf(ms, ".%06lu", tm.second_part); - if (field->decimals < 6) - ms[field->decimals + 1]= 0; - length+= strlen(ms); - strcat(dtbuffer, ms); - } + uint8_t decimals= (field->decimals == AUTO_SEC_PART_DIGITS) ? SEC_PART_DIGITS : field->decimals; + length= sprintf(dtbuffer, "%s%02u:%02u:%02u.%0*u", (tm.neg ? "-" : ""), tm.hour, tm.minute, tm.second, + decimals, (uint32_t)(tm.second_part / pow(10, 6 - decimals))); + } else + length= sprintf(dtbuffer, "%s%02u:%02u:%02u", (tm.neg ? "-" : ""), tm.hour, tm.minute, tm.second); break; case MYSQL_TYPE_DATETIME: case MYSQL_TYPE_TIMESTAMP: - length= sprintf(dtbuffer, "%04u-%02u-%02u %02u:%02u:%02u", tm.year, tm.month, tm.day, tm.hour, tm.minute, tm.second); - if (field->decimals && field->decimals <= 6) + if (field->decimals && (field->decimals <= SEC_PART_DIGITS || + (field->decimals == AUTO_SEC_PART_DIGITS && tm.second_part))) { - char ms[8]; - sprintf(ms, ".%06lu", tm.second_part); - if (field->decimals < 6) - ms[field->decimals + 1]= 0; - length+= strlen(ms); - strcat(dtbuffer, ms); - } + uint8_t decimals= (field->decimals == AUTO_SEC_PART_DIGITS) ? SEC_PART_DIGITS : field->decimals; + length= sprintf(dtbuffer, "%04u-%02u-%02u %02u:%02u:%02u.%0*u", tm.year, tm.month, tm.day, tm.hour, tm.minute, tm.second, + decimals, (uint32_t)(tm.second_part / pow(10, 6 - decimals))); + } else + length= sprintf(dtbuffer, "%04u-%02u-%02u %02u:%02u:%02u", tm.year, tm.month, tm.day, tm.hour, tm.minute, tm.second); break; default: dtbuffer[0]= 0; diff --git a/libmariadb/mariadb_lib.c b/libmariadb/mariadb_lib.c index 8c1ef0b4..16f6ee8b 100644 --- a/libmariadb/mariadb_lib.c +++ b/libmariadb/mariadb_lib.c @@ -2054,6 +2054,12 @@ error: if (!(client_flag & CLIENT_REMEMBER_OPTIONS) && !(IS_MYSQL_ASYNC(mysql))) mysql_close_options(mysql); + + /* CONC-703: If no error was set, we set CR_SERVER_LOST by default */ + if (!mysql_errno(mysql)) + my_set_error(mysql, CR_SERVER_LOST, SQLSTATE_UNKNOWN, + "Can't connect to server (%d).", + errno); return(0); } diff --git a/libmariadb/mariadb_stmt.c b/libmariadb/mariadb_stmt.c index cb37359e..ee489dab 100644 --- a/libmariadb/mariadb_stmt.c +++ b/libmariadb/mariadb_stmt.c @@ -2543,6 +2543,8 @@ int STDCALL mysql_stmt_next_result(MYSQL_STMT *stmt) stmt->upsert_status.server_status= stmt->mysql->server_status; ma_status_callback(stmt->mysql, last_status); stmt->upsert_status.warning_count= stmt->mysql->warning_count; + if (!mysql_stmt_more_results(stmt)) + stmt->state= MYSQL_STMT_FETCH_DONE; } stmt->field_count= stmt->mysql->field_count; diff --git a/unittest/libmariadb/ps_bugs.c b/unittest/libmariadb/ps_bugs.c index 7a581ad8..6fae4c1b 100644 --- a/unittest/libmariadb/ps_bugs.c +++ b/unittest/libmariadb/ps_bugs.c @@ -5809,9 +5809,124 @@ static int test_conc683(MYSQL *mysql) return OK; } +static int test_conc702(MYSQL *ma) +{ + MYSQL_STMT *stmt, *stmt2; + + diag("Server info %s\nClient info: %s", + mysql_get_server_info(ma), mysql_get_client_info()); + + mysql_query(ma, "DROP PROCEDURE IF EXISTS p1"); + + mysql_query(ma, "CREATE PROCEDURE p1() BEGIN" + " SELECT 1 FROM DUAL; " + "END"); + + stmt= mysql_stmt_init(ma); + + FAIL_IF(!stmt, "Could not allocate stmt"); + + mysql_stmt_prepare(stmt, "CALL p1()", -1); + mysql_stmt_execute(stmt); + + + mysql_stmt_store_result(stmt); + + // We've done everything w/ result and skip everything else + + while (mysql_stmt_more_results(stmt)) { + + mysql_stmt_next_result(stmt); + // state at this moment is MYSQL_STMT_WAITING_USE_OR_STORE. But there is no result, + // we can't store it. And there is no way to change it + + } + // Now we are not closing it, for later use. For example it's been put to the cache + // Using connection freely - we haven't done anything wrong, "nothing is out of sync" + + mysql_query(ma, "DROP PROCEDURE p1"); + mysql_query(ma, "DROP PROCEDURE IF EXISTS p2"); + mysql_query(ma, "CREATE PROCEDURE p2() " + "BEGIN " + " SELECT 'Marten' FROM DUAL; " + " SELECT 'Zack' FROM DUAL; " + "END"); + + stmt2= mysql_stmt_init(ma); + + mysql_stmt_prepare(stmt2, "CALL p2()", -1); + + mysql_stmt_execute(stmt2); + + mysql_stmt_store_result(stmt2); + + // I was initially wrong, this goes thru + check_stmt_rc(mysql_stmt_next_result(stmt2), stmt2); + + // But we get error"Out of sync" set, if check + // check_stmt_rc(mysql_stmt_next_result(stmt2), stmt2); + + check_stmt_rc(mysql_stmt_store_result(stmt2), stmt2); + + mysql_stmt_close(stmt2); + + mysql_stmt_close(stmt); + return OK; +} + +static int test_conc739(MYSQL *mysql) +{ + MYSQL_STMT *stmt; + int rc; + MYSQL_BIND bind[2]; + char buffer[2][100]; + MYSQL_ROW row; + MYSQL_RES *result; + uint8 i; + + rc= mysql_query(mysql, "SELECT FROM_UNIXTIME('1922.1'), FROM_UNIXTIME('1922.0')"); + check_mysql_rc(rc, mysql); + result= mysql_store_result(mysql); + row= mysql_fetch_row(result); + + stmt= mysql_stmt_init(mysql); + + rc= mysql_stmt_prepare(stmt, SL("SELECT FROM_UNIXTIME('1922.1'), FROM_UNIXTIME('1922.0')")); + check_stmt_rc(rc, stmt); + + memset(bind, 0, 2 * sizeof(MYSQL_BIND)); + for (i=0; i < 2; i++) + { + bind[i].buffer_type= MYSQL_TYPE_STRING; + bind[i].buffer= &buffer[i]; + bind[i].buffer_length= 100; + } + + rc= mysql_stmt_execute(stmt); + check_stmt_rc(rc, stmt); + + rc= mysql_stmt_bind_result(stmt, bind); + check_stmt_rc(rc, stmt); + + rc= mysql_stmt_fetch(stmt); + check_stmt_rc(rc, stmt); + + for (i=0; i < 2; i++) + { + diag("text: %s binary: %s", row[i], buffer[i]); + FAIL_IF(strcmp(buffer[i], row[i]), "Different results (text/binary protocol)"); + } + + mysql_stmt_close(stmt); + mysql_free_result(result); + return OK; +} + struct my_tests_st my_tests[] = { {"test_conc683", test_conc683, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_conc667", test_conc667, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, + {"test_conc702", test_conc702, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, + {"test_conc739", test_conc739, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_conc633", test_conc633, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_conc623", test_conc623, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_conc627", test_conc627, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},