diff --git a/libmariadb/libmariadb.c b/libmariadb/libmariadb.c index 8049259c..973c45fa 100644 --- a/libmariadb/libmariadb.c +++ b/libmariadb/libmariadb.c @@ -1994,23 +1994,31 @@ static my_bool mysql_reconnect(MYSQL *mysql) tmp_mysql.net.last_error); DBUG_RETURN(1); } - mysql->free_me=0; - mysql_close(mysql); - memset(&mysql->options, 0, sizeof(mysql->options)); - *mysql=tmp_mysql; - mysql->reconnect= 1; - net_clear(&mysql->net); - mysql->affected_rows= ~(my_ulonglong) 0; /* reset the connection in all active statements todo: check stmt->mysql in mysql_stmt* functions ! */ for (;li_stmt;li_stmt= li_stmt->next) { MYSQL_STMT *stmt= (MYSQL_STMT *)li_stmt->data; - stmt->mysql= NULL; - stmt->state= MYSQL_STMT_INITTED; - SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0); + + if (stmt->state != MYSQL_STMT_INITTED) + { + stmt->mysql= NULL; + stmt->state= MYSQL_STMT_INITTED; + SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0); + } + else + tmp_mysql.stmts= list_add(tmp_mysql.stmts, &stmt->list); } + + mysql->free_me=0; + mysql->stmts= NULL; + mysql_close(mysql); + memset(&mysql->options, 0, sizeof(mysql->options)); + *mysql=tmp_mysql; + mysql->reconnect= 1; + net_clear(&mysql->net); + mysql->affected_rows= ~(my_ulonglong) 0; DBUG_RETURN(0); } diff --git a/libmariadb/libmariadb_exports.def b/libmariadb/libmariadb_exports.def index 900e5aec..f3e4c713 100644 --- a/libmariadb/libmariadb_exports.def +++ b/libmariadb/libmariadb_exports.def @@ -54,6 +54,7 @@ EXPORTS mysql_num_rows mysql_options mysql_options4 + mysql_optionsv mysql_stmt_param_count mysql_stmt_param_metadata mysql_ping diff --git a/libmariadb/my_stmt.c b/libmariadb/my_stmt.c index dcba785b..636f573c 100644 --- a/libmariadb/my_stmt.c +++ b/libmariadb/my_stmt.c @@ -1223,6 +1223,7 @@ my_bool mthd_stmt_get_result_metadata(MYSQL_STMT *stmt) int STDCALL mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, unsigned long length) { + MYSQL *mysql= stmt->mysql; int rc= 1; DBUG_ENTER("mysql_stmt_prepare"); @@ -1235,7 +1236,7 @@ int STDCALL mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, unsigned lon /* clear flags */ CLEAR_CLIENT_STMT_ERROR(stmt); CLEAR_CLIENT_ERROR(stmt->mysql); - stmt->upsert_status.affected_rows= stmt->mysql->affected_rows= (my_ulonglong) ~0; + stmt->upsert_status.affected_rows= mysql->affected_rows= (my_ulonglong) ~0; /* check if we have to clear results */ if (stmt->state > MYSQL_STMT_INITTED) @@ -1245,7 +1246,8 @@ int STDCALL mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, unsigned lon on server side. Statment handle will get a new stmt_id */ char stmt_id[STMT_ID_LENGTH]; - mysql_stmt_reset(stmt); + if (mysql_stmt_reset(stmt)) + goto fail; free_root(&stmt->mem_root, MYF(MY_KEEP_PREALLOC)); free_root(&((MADB_STMT_EXTENSION *)stmt->extension)->fields_alloc_root, MYF(0)); @@ -1254,10 +1256,10 @@ int STDCALL mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, unsigned lon stmt->field_count= 0; int4store(stmt_id, stmt->stmt_id); - if (simple_command(stmt->mysql, MYSQL_COM_STMT_CLOSE, stmt_id, sizeof(stmt_id), 1, stmt)) + if (simple_command(mysql, MYSQL_COM_STMT_CLOSE, stmt_id, sizeof(stmt_id), 1, stmt)) goto fail; } - if (simple_command(stmt->mysql, MYSQL_COM_STMT_PREPARE, query, length, 1, stmt)) + if (simple_command(mysql, MYSQL_COM_STMT_PREPARE, query, length, 1, stmt)) goto fail; if (stmt->mysql->methods->db_read_prepare_response && @@ -1302,8 +1304,8 @@ int STDCALL mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, unsigned lon fail: stmt->state= MYSQL_STMT_INITTED; - SET_CLIENT_STMT_ERROR(stmt, stmt->mysql->net.last_errno, stmt->mysql->net.sqlstate, - stmt->mysql->net.last_error); + SET_CLIENT_STMT_ERROR(stmt, mysql->net.last_errno, mysql->net.sqlstate, + mysql->net.last_error); DBUG_RETURN(rc); } @@ -1436,6 +1438,7 @@ static int madb_alloc_stmt_fields(MYSQL_STMT *stmt) int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt) { + MYSQL *mysql= stmt->mysql; char *request; int ret; size_t request_len= 0; @@ -1451,7 +1454,7 @@ int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt) if (stmt->state < MYSQL_STMT_PREPARED) { - SET_CLIENT_ERROR(stmt->mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); + SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); SET_CLIENT_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); DBUG_RETURN(1); } @@ -1469,7 +1472,7 @@ int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt) } if (stmt->state > MYSQL_STMT_WAITING_USE_OR_STORE && stmt->state < MYSQL_STMT_FETCH_DONE && !stmt->result.data) { - stmt->mysql->methods->db_stmt_flush_unbuffered(stmt); + mysql->methods->db_stmt_flush_unbuffered(stmt); stmt->state= MYSQL_STMT_PREPARED; stmt->mysql->status= MYSQL_STATUS_READY; } @@ -1484,8 +1487,8 @@ int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt) request= (char *)mysql_stmt_execute_generate_request(stmt, &request_len); DBUG_PRINT("info",("request_len=%ld", request_len)); - ret= test(simple_command(stmt->mysql, MYSQL_COM_STMT_EXECUTE, request, request_len, 1, stmt) || - (stmt->mysql && stmt->mysql->methods->db_read_stmt_result && stmt->mysql->methods->db_read_stmt_result(stmt->mysql))); + ret= test(simple_command(mysql, MYSQL_COM_STMT_EXECUTE, request, request_len, 1, stmt) || + (mysql && mysql->methods->db_read_stmt_result && mysql->methods->db_read_stmt_result(mysql))); if (request) my_free(request, MYF(0)); @@ -1498,16 +1501,16 @@ int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt) if (ret) { - SET_CLIENT_STMT_ERROR(stmt, stmt->mysql->net.last_errno, stmt->mysql->net.sqlstate, - stmt->mysql->net.last_error); + SET_CLIENT_STMT_ERROR(stmt, mysql->net.last_errno, mysql->net.sqlstate, + mysql->net.last_error); stmt->state= MYSQL_STMT_PREPARED; DBUG_RETURN(1); } - stmt->upsert_status.last_insert_id= stmt->mysql->insert_id; - stmt->upsert_status.server_status= stmt->mysql->server_status; - stmt->upsert_status.warning_count= stmt->mysql->warning_count; + stmt->upsert_status.last_insert_id= mysql->insert_id; + stmt->upsert_status.server_status= mysql->server_status; + stmt->upsert_status.warning_count= mysql->warning_count; - CLEAR_CLIENT_ERROR(stmt->mysql); + CLEAR_CLIENT_ERROR(mysql); CLEAR_CLIENT_STMT_ERROR(stmt); stmt->execute_count++; @@ -1515,10 +1518,10 @@ int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt) stmt->state= MYSQL_STMT_EXECUTED; - if (stmt->mysql->field_count) + if (mysql->field_count) { if (!stmt->field_count || - stmt->mysql->server_status & SERVER_MORE_RESULTS_EXIST) /* fix for ps_bug: test_misc */ + mysql->server_status & SERVER_MORE_RESULTS_EXIST) /* fix for ps_bug: test_misc */ { MEM_ROOT *fields_alloc_root= &((MADB_STMT_EXTENSION *)stmt->extension)->fields_alloc_root; @@ -1526,37 +1529,37 @@ int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt) free_root(fields_alloc_root, MYF(0)); if (!(stmt->bind= (MYSQL_BIND *)alloc_root(fields_alloc_root, - sizeof(MYSQL_BIND) * stmt->mysql->field_count)) || + sizeof(MYSQL_BIND) * mysql->field_count)) || !(stmt->fields= (MYSQL_FIELD *)alloc_root(fields_alloc_root, - sizeof(MYSQL_FIELD) * stmt->mysql->field_count))) + sizeof(MYSQL_FIELD) * mysql->field_count))) { SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); DBUG_RETURN(1); } - stmt->field_count= stmt->mysql->field_count; + stmt->field_count= mysql->field_count; for (i=0; i < stmt->field_count; i++) { - if (stmt->mysql->fields[i].db) - stmt->fields[i].db= strdup_root(fields_alloc_root, stmt->mysql->fields[i].db); - if (stmt->mysql->fields[i].table) - stmt->fields[i].table= strdup_root(fields_alloc_root, stmt->mysql->fields[i].table); - if (stmt->mysql->fields[i].org_table) - stmt->fields[i].org_table= strdup_root(fields_alloc_root, stmt->mysql->fields[i].org_table); - if (stmt->mysql->fields[i].name) - stmt->fields[i].name= strdup_root(fields_alloc_root, stmt->mysql->fields[i].name); - if (stmt->mysql->fields[i].org_name) - stmt->fields[i].org_name= strdup_root(fields_alloc_root, stmt->mysql->fields[i].org_name); - if (stmt->mysql->fields[i].catalog) - stmt->fields[i].catalog= strdup_root(fields_alloc_root, stmt->mysql->fields[i].catalog); - stmt->fields[i].def= stmt->mysql->fields[i].def ? strdup_root(fields_alloc_root, stmt->mysql->fields[i].def) : NULL; + if (mysql->fields[i].db) + stmt->fields[i].db= strdup_root(fields_alloc_root, mysql->fields[i].db); + if (mysql->fields[i].table) + stmt->fields[i].table= strdup_root(fields_alloc_root, mysql->fields[i].table); + if (mysql->fields[i].org_table) + stmt->fields[i].org_table= strdup_root(fields_alloc_root, mysql->fields[i].org_table); + if (mysql->fields[i].name) + stmt->fields[i].name= strdup_root(fields_alloc_root, mysql->fields[i].name); + if (mysql->fields[i].org_name) + stmt->fields[i].org_name= strdup_root(fields_alloc_root, mysql->fields[i].org_name); + if (mysql->fields[i].catalog) + stmt->fields[i].catalog= strdup_root(fields_alloc_root, mysql->fields[i].catalog); + stmt->fields[i].def= mysql->fields[i].def ? strdup_root(fields_alloc_root, mysql->fields[i].def) : NULL; } } if (stmt->upsert_status.server_status & SERVER_STATUS_CURSOR_EXISTS) { stmt->cursor_exists = TRUE; - stmt->mysql->status = MYSQL_STATUS_READY; + mysql->status = MYSQL_STATUS_READY; /* Only cursor read */ stmt->default_rset_handler = _mysql_stmt_use_result; @@ -1583,17 +1586,17 @@ int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt) stmt->state= MYSQL_STMT_WAITING_USE_OR_STORE; /* in certain cases parameter types can change: For example see bug 4026 (SELECT ?), so we need to update field information */ - if (stmt->mysql->field_count == stmt->field_count) + if (mysql->field_count == stmt->field_count) { uint i; for (i=0; i < stmt->field_count; i++) { - stmt->fields[i].type= stmt->mysql->fields[i].type; - stmt->fields[i].length= stmt->mysql->fields[i].length; - stmt->fields[i].flags= stmt->mysql->fields[i].flags; - stmt->fields[i].decimals= stmt->mysql->fields[i].decimals; - stmt->fields[i].charsetnr= stmt->mysql->fields[i].charsetnr; - stmt->fields[i].max_length= stmt->mysql->fields[i].max_length; + stmt->fields[i].type= mysql->fields[i].type; + stmt->fields[i].length= mysql->fields[i].length; + stmt->fields[i].flags= mysql->fields[i].flags; + stmt->fields[i].decimals= mysql->fields[i].decimals; + stmt->fields[i].charsetnr= mysql->fields[i].charsetnr; + stmt->fields[i].max_length= mysql->fields[i].max_length; } } else { @@ -1607,6 +1610,7 @@ int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt) static my_bool madb_reset_stmt(MYSQL_STMT *stmt, unsigned int flags) { + MYSQL *mysql= stmt->mysql; my_bool ret= 0; DBUG_ENTER("madb_stmt_reset"); @@ -1649,8 +1653,8 @@ static my_bool madb_reset_stmt(MYSQL_STMT *stmt, unsigned int flags) if (stmt->mysql->status!= MYSQL_STATUS_READY && stmt->field_count) { - stmt->mysql->methods->db_stmt_flush_unbuffered(stmt); - stmt->mysql->status= MYSQL_STATUS_READY; + mysql->methods->db_stmt_flush_unbuffered(stmt); + mysql->status= MYSQL_STATUS_READY; } } @@ -1662,10 +1666,10 @@ static my_bool madb_reset_stmt(MYSQL_STMT *stmt, unsigned int flags) { unsigned char cmd_buf[STMT_ID_LENGTH]; int4store(cmd_buf, stmt->stmt_id); - if ((ret= simple_command(stmt->mysql,MYSQL_COM_STMT_RESET, (char *)cmd_buf, sizeof(cmd_buf), 0, stmt))) + if ((ret= simple_command(mysql,MYSQL_COM_STMT_RESET, (char *)cmd_buf, sizeof(cmd_buf), 0, stmt))) { - SET_CLIENT_STMT_ERROR(stmt, stmt->mysql->net.last_errno, stmt->mysql->net.sqlstate, - stmt->mysql->net.last_error); + SET_CLIENT_STMT_ERROR(stmt, mysql->net.last_errno, mysql->net.sqlstate, + mysql->net.last_error); DBUG_RETURN(ret); } } @@ -1688,6 +1692,7 @@ static my_bool madb_reset_stmt(MYSQL_STMT *stmt, unsigned int flags) my_bool STDCALL mysql_stmt_reset(MYSQL_STMT *stmt) { + MYSQL *mysql= stmt->mysql; my_bool ret= 1; unsigned int flags= MADB_RESET_LONGDATA | MADB_RESET_BUFFER | MADB_RESET_ERROR; @@ -1721,11 +1726,11 @@ my_bool STDCALL mysql_stmt_reset(MYSQL_STMT *stmt) ret= madb_reset_stmt(stmt, MADB_RESET_SERVER); } stmt->state= MYSQL_STMT_PREPARED; - stmt->upsert_status.affected_rows= stmt->mysql->affected_rows; - stmt->upsert_status.last_insert_id= stmt->mysql->insert_id; - stmt->upsert_status.server_status= stmt->mysql->server_status; - stmt->upsert_status.warning_count= stmt->mysql->warning_count; - stmt->mysql->status= MYSQL_STATUS_READY; + stmt->upsert_status.affected_rows= mysql->affected_rows; + stmt->upsert_status.last_insert_id= mysql->insert_id; + stmt->upsert_status.server_status= mysql->server_status; + stmt->upsert_status.warning_count= mysql->warning_count; + mysql->status= MYSQL_STATUS_READY; DBUG_RETURN(ret); } diff --git a/libmariadb/version_script.txt b/libmariadb/version_script.txt index 06052c03..421a3840 100644 --- a/libmariadb/version_script.txt +++ b/libmariadb/version_script.txt @@ -54,6 +54,8 @@ global: mysql_num_fields; mysql_num_rows; mysql_options; + mysql_optionsv; + mysql_options4; mysql_stmt_param_count; mysql_ping; mysql_stmt_result_metadata; diff --git a/unittest/libmariadb/ps.c b/unittest/libmariadb/ps.c index 62a08f75..7bf3d5ef 100644 --- a/unittest/libmariadb/ps.c +++ b/unittest/libmariadb/ps.c @@ -25,6 +25,36 @@ with this program; if not, write to the Free Software Foundation, Inc., /* Utility function to verify the field members */ +static int test_conc83(MYSQL *mysql) +{ + MYSQL_STMT *stmt; + int rc; + + char *query= "SELECT 1,2,3 FROM DUAL"; + + stmt= mysql_stmt_init(mysql); + + mysql->reconnect= 1; + + /* 1. Status is inited, so prepare should work */ + + rc= mysql_kill(mysql, mysql_thread_id(mysql)); + + rc= mysql_stmt_prepare(stmt, query, strlen(query)); + check_stmt_rc(rc, stmt); + diag("Ok"); + + /* 2. Status is prepared, second prepare should fail */ + rc= mysql_kill(mysql, mysql_thread_id(mysql)); + + rc= mysql_stmt_prepare(stmt, query, strlen(query)); + FAIL_IF(!rc, "Error expected"); + + mysql_stmt_close(stmt); + mysql_close(mysql); + return OK; +} + static int test_conc60(MYSQL *mysql) { @@ -40,6 +70,7 @@ static int test_conc60(MYSQL *mysql) rc= mysql_stmt_prepare(stmt, query, strlen(query)); if (rc && mysql_stmt_errno(stmt) == 1146) { diag("Internal test - customer data not available"); + mysql_stmt_close(stmt); return SKIP; } check_stmt_rc(rc, stmt); @@ -403,7 +434,6 @@ static int test_prepare_syntax(MYSQL *mysql) FAIL_IF(!rc, "error expected"); strcpy(query, "SELECT id, name FROM test_prepare_syntax WHERE id=? AND WHERE"); - stmt= mysql_stmt_init(mysql); FAIL_IF(!stmt, mysql_error(mysql)); rc= mysql_stmt_prepare(stmt, query, strlen(query)); FAIL_IF(!rc, "error expected"); @@ -964,7 +994,6 @@ static int test_select_show(MYSQL *mysql) FAIL_IF(!rc, "Error expected"); strcpy(query, "show tables like \'test_show\'"); - stmt= mysql_stmt_init(mysql); FAIL_IF(!stmt, mysql_error(mysql)); rc= mysql_stmt_prepare(stmt, query, strlen(query)); check_stmt_rc(rc, stmt); @@ -4813,6 +4842,7 @@ int test_notrunc(MYSQL *mysql) } struct my_tests_st my_tests[] = { + {"test_conc83", test_conc83, TEST_CONNECTION_NEW, 0, NULL, NULL}, {"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},