=== modified file 'ChangeLog' --- ChangeLog 2013-07-19 21:26:38 +0000 +++ ChangeLog 2013-07-25 13:13:34 +0000 @@ -20,6 +20,8 @@ specifying mysqlclient library (libmysql.*, mysqlclient.*, libmysqlclient_r.*, libmysqlclient.*) to be used. Mysql CPP linkage for mysql version >= 5.6.4 (wl#6738) + * INSERT ON DUPLICATE KEY UPDATE does regularly report "-1" + (Bug# 17197053/69718) ---- === modified file 'driver/handle.c' --- driver/handle.c 2012-12-13 23:31:25 +0000 +++ driver/handle.c 2013-07-25 12:25:54 +0000 @@ -544,12 +544,15 @@ { if (clearAllResults) { + /* Without locking we are in trouble (see bug 69718) */ + pthread_mutex_lock(&stmt->dbc->lock); /* We seiously CLOSEing statement for preparing handle object for new query */ while (!next_result(stmt)) { get_result_metadata(stmt, TRUE); } + pthread_mutex_unlock(&stmt->dbc->lock); } } else === modified file 'test/my_basics.c' --- test/my_basics.c 2013-04-17 10:01:25 +0000 +++ test/my_basics.c 2013-07-25 13:09:32 +0000 @@ -1131,6 +1131,116 @@ return res; } + +#define stmt_max 25 +SQLHSTMT stmt_pool[stmt_max]; +static int stmt_num= -1; +int iters_remain= 10000; + +#ifdef _WIN32 +#define sleep_wait Sleep(1) +#define thread_type HANDLE +#define create_test_thread thread= CreateThread(NULL, 0, t_bug69718_deallocate_stmt, NULL, 0, NULL); +#define do_thread_join(A) WaitForSingleObject(A, 1000) +DWORD WINAPI t_bug69718_deallocate_stmt(LPVOID arg) +#else +#define sleep_wait usleep(1000) +#define thread_type pthread_t +void *t_bug69718_deallocate_stmt(void *arg) +#define create_test_thread pthread_create(&thread, NULL, t_bug69718_deallocate_stmt, NULL); +#define do_thread_join(A) pthread_join(A, NULL) +#endif +{ + int local_stmt_num= 0; + while(iters_remain > 0) + { + local_stmt_num= stmt_num; + if(local_stmt_num < 0 || stmt_pool[local_stmt_num] == NULL) + { + /* go and wait till stmt becomes inited or available */ + sleep_wait; + continue; + } + /* We don't check the result of the operation */ + SQLFreeStmt(stmt_pool[local_stmt_num], SQL_CLOSE); + SQLFreeStmt(stmt_pool[local_stmt_num], SQL_DROP); + stmt_pool[local_stmt_num]= NULL; + } + return 0; +} + + +/* + Bug#69718 INSERT ON DUPLICATE KEY UPDATE does regularly report "-1" +*/ +DECLARE_TEST(t_bug69718) +{ + thread_type thread; + char qbuf[1000000] = {0}; + char *insert_query = qbuf; + int i= 0; + HSTMT hstmt2; + SQLLEN row_count= 0; + + for (i= 0; i < stmt_max; i++) + { + stmt_pool[i]= NULL; + } + + ok_con(hdbc, SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &stmt_pool[0])); + hstmt2= stmt_pool[0]; + + ok_sql(hstmt2, "drop table if exists bug69718"); + ok_sql(hstmt2, "create table bug69718 (id int primary key, vc varchar(32))"); + + strcat(insert_query, "insert into bug69718 (id,vc) VALUES (1, 'abc 1')"); + + for(i= 2; i <= iters_remain; i++) + { + char tmp[50] = {0}; + sprintf(tmp, ",(%d, 'abc %d')", i, i); + strcat(insert_query, tmp); + } + + ok_stmt(hstmt2, SQLExecDirect(hstmt2, insert_query, SQL_NTS)); + + create_test_thread; + + /* Element 0 in the stmt pool can be freed */ + stmt_num= 0; + + for(i= 0; iters_remain; iters_remain--) + { + char tmp2[200] = {0}; + int local_stmt_num= stmt_num + 1 >= stmt_max ? 0 : stmt_num + 1; + + row_count= 0; + i++; + + sprintf(tmp2, "insert into bug69718 (id,vc) VALUES (%d, 'abc') ON DUPLICATE KEY UPDATE vc='updated'", i); + + if(!stmt_pool[local_stmt_num]) + { + /* Allocate a new stmt only if the cleaner thread did not clean it */ + ok_con(hdbc, SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &stmt_pool[local_stmt_num])); + } + + hstmt2= stmt_pool[local_stmt_num]; + + ok_stmt(hstmt2, SQLExecDirect(hstmt2, tmp2, SQL_NTS)); + + ok_stmt(hstmt2, SQLRowCount(hstmt2, &row_count)); + is(row_count == 2); + + stmt_num= local_stmt_num; + } + + do_thread_join(thread); + + ok_sql(hstmt, "drop table if exists bug69718"); + return OK; +} + BEGIN_TESTS ADD_TEST(my_basics) @@ -1162,6 +1272,7 @@ ADD_TEST(t_bug45378) ADD_TEST(t_bug63844) ADD_TEST(t_bug52996) + ADD_TEST(t_bug69718) END_TESTS