diff --git a/include/MySQL_Session.h b/include/MySQL_Session.h index 5cc91eb35..cfd965ade 100644 --- a/include/MySQL_Session.h +++ b/include/MySQL_Session.h @@ -338,6 +338,7 @@ class MySQL_Session bool has_any_backend(); void detected_broken_connection(const char *file, unsigned int line, const char *func, const char *action, MySQL_Connection *myconn, int myerr, const char *message, bool verbose=false); void generate_status_one_hostgroup(int hid, std::string& s); + friend void SQLite3_Server_session_handler(MySQL_Session *sess, void *_pa, PtrSize_t *pkt); }; #define KILL_QUERY 1 diff --git a/lib/MySQL_Session.cpp b/lib/MySQL_Session.cpp index 5d2721d34..c4e4c81b4 100644 --- a/lib/MySQL_Session.cpp +++ b/lib/MySQL_Session.cpp @@ -974,17 +974,25 @@ bool MySQL_Session::handler_SetAutocommit(PtrSize_t *pkt) { goto __ret_autocommit_OK; } __ret_autocommit_OK: - client_myds->DSS=STATE_QUERY_SENT_NET; - uint16_t setStatus = (nTrx ? SERVER_STATUS_IN_TRANS : 0 ); - if (autocommit) setStatus |= SERVER_STATUS_AUTOCOMMIT; - client_myds->myprot.generate_pkt_OK(true,NULL,NULL,1,0,0,setStatus,0,NULL); - client_myds->DSS=STATE_SLEEP; - status=WAITING_CLIENT_DATA; - if (mirror==false) { - RequestEnd(NULL); + if (session_type == PROXYSQL_SESSION_MYSQL) { // do not run this if PROXYSQL_SESSION_SQLITE + client_myds->DSS=STATE_QUERY_SENT_NET; + uint16_t setStatus = (nTrx ? SERVER_STATUS_IN_TRANS : 0 ); + if (autocommit) setStatus |= SERVER_STATUS_AUTOCOMMIT; + client_myds->myprot.generate_pkt_OK(true,NULL,NULL,1,0,0,setStatus,0,NULL); + client_myds->DSS=STATE_SLEEP; + status=WAITING_CLIENT_DATA; + if (mirror==false) { + RequestEnd(NULL); + } + __sync_fetch_and_add(&MyHGM->status.autocommit_cnt_filtered, 1); + } + if (session_type == PROXYSQL_SESSION_MYSQL) { + // free() only if session_type == PROXYSQL_SESSION_MYSQL + // because the packet will be freed in + // handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_COM_QUERY___not_mysql() + // for all session type other than PROXYSQL_SESSION_MYSQL + l_free(pkt->size,pkt->ptr); } - l_free(pkt->size,pkt->ptr); - __sync_fetch_and_add(&MyHGM->status.autocommit_cnt_filtered, 1); free(_new_pkt.ptr); return true; } @@ -3295,6 +3303,7 @@ void MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C // client_myds->DSS = STATE_SLEEP // enum_mysql_command = _MYSQL_COM_QUERY // it processes the session not MYSQL_SESSION +// Make sure that handler_function() doesn't free the packet void MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_COM_QUERY___not_mysql(PtrSize_t& pkt) { switch (session_type) { case PROXYSQL_SESSION_ADMIN: @@ -6893,13 +6902,19 @@ void MySQL_Session::SQLite3_to_MySQL(SQLite3_result *result, char *error, int af myds->DSS=STATE_COLUMN_DEFINITION; unsigned int nTrx = 0; uint16_t setStatus = 0; + if (autocommit) setStatus |= SERVER_STATUS_AUTOCOMMIT; if (in_transaction == false) { nTrx=NumActiveTransactions(); - setStatus = (nTrx ? SERVER_STATUS_IN_TRANS : 0 ); - if (autocommit) setStatus |= SERVER_STATUS_AUTOCOMMIT; + setStatus |= (nTrx ? SERVER_STATUS_IN_TRANS : 0 ); } else { // this is for SQLite3 Server - setStatus = SERVER_STATUS_AUTOCOMMIT; + if (session_type == PROXYSQL_SESSION_SQLITE) { + //if (autocommit) setStatus |= SERVER_STATUS_AUTOCOMMIT; + } else { + // for sessions that are not SQLITE . Admin and Clickhouse . + // default + setStatus |= SERVER_STATUS_AUTOCOMMIT; + } setStatus |= SERVER_STATUS_IN_TRANS; } if (!deprecate_eof_active) { @@ -6928,10 +6943,7 @@ void MySQL_Session::SQLite3_to_MySQL(SQLite3_result *result, char *error, int af if (deprecate_eof_active) { myprot->generate_pkt_OK(true, NULL, NULL, sid, 0, 0, setStatus, 0, NULL, true); sid++; } else { - // I think the 2 | setStatus here is a bug. the previous generate_pkt_EOF was changed from 2|setStatus to just - // setStatus a long time ago in c3e6fda7a47ecb94e97d4e191cdbd0f10fec7924 - // also 2 represents the SERVER_STATUS_IN_TRANS which is already set in setStatus - myprot->generate_pkt_EOF(true,NULL,NULL,sid,0, 2 | setStatus ); sid++; + myprot->generate_pkt_EOF(true,NULL,NULL, sid, 0, setStatus ); sid++; } myds->DSS=STATE_SLEEP; @@ -6956,7 +6968,13 @@ void MySQL_Session::SQLite3_to_MySQL(SQLite3_result *result, char *error, int af if (autocommit) setStatus |= SERVER_STATUS_AUTOCOMMIT; } else { // this is for SQLite3 Server - setStatus = SERVER_STATUS_AUTOCOMMIT; + if (session_type == PROXYSQL_SESSION_SQLITE) { + //if (autocommit) setStatus |= SERVER_STATUS_AUTOCOMMIT; + } else { + // for sessions that are not SQLITE . Admin and Clickhouse . + // default + setStatus |= SERVER_STATUS_AUTOCOMMIT; + } setStatus |= SERVER_STATUS_IN_TRANS; } myprot->generate_pkt_OK(true,NULL,NULL,sid,affected_rows,0,setStatus,0,NULL); diff --git a/src/SQLite3_Server.cpp b/src/SQLite3_Server.cpp index 7db5275f7..8f92fc02e 100644 --- a/src/SQLite3_Server.cpp +++ b/src/SQLite3_Server.cpp @@ -372,6 +372,100 @@ void SQLite3_Server_session_handler(MySQL_Session *sess, void *_pa, PtrSize_t *p query_no_space[query_no_space_length]=0; } + + { + SQLite3_Session *sqlite_sess = (SQLite3_Session *)sess->thread->gen_args; + sqlite3 *db = sqlite_sess->sessdb->get_db(); + char c=((char *)pkt->ptr)[5]; + bool ret=false; + if (c=='c' || c=='C') { + if (strncasecmp((char *)"commit",(char *)pkt->ptr+5,6)==0) { + if ((*proxy_sqlite3_get_autocommit)(db)==1) { + ret=true; + } + } + } else { + if (c=='r' || c=='R') { + if ( strncasecmp((char *)"rollback",(char *)pkt->ptr+5,8)==0 ) { + if ((*proxy_sqlite3_get_autocommit)(db)==1) { + ret=true; + } + } + } + } + // if there is no transactions we filter both commit and rollback + if (ret == true) { + uint16_t status=0; + if (sess->autocommit) status |= SERVER_STATUS_AUTOCOMMIT; + if ((*proxy_sqlite3_get_autocommit)(db)==0) { + status |= SERVER_STATUS_IN_TRANS; + } + GloSQLite3Server->send_MySQL_OK(&sess->client_myds->myprot, NULL, 0, status); + run_query=false; + goto __run_query; + } + } + + + + { + SQLite3_Session *sqlite_sess = (SQLite3_Session *)sess->thread->gen_args; + sqlite3 *db = sqlite_sess->sessdb->get_db(); + bool prev_autocommit = sess->autocommit; + bool autocommit_to_skip = sess->handler_SetAutocommit(pkt); + if (prev_autocommit == sess->autocommit) { + if (autocommit_to_skip==true) { + uint16_t status=0; + if (sess->autocommit) status |= SERVER_STATUS_AUTOCOMMIT; + if ((*proxy_sqlite3_get_autocommit)(db)==0) { + status |= SERVER_STATUS_IN_TRANS; + } + GloSQLite3Server->send_MySQL_OK(&sess->client_myds->myprot, NULL, 0, status); + run_query=false; + goto __run_query; + } + } else { + // autocommit changed + if (sess->autocommit == false) { + // we simply reply ok. We will create a transaction at the next query + // we defer the creation of the transaction to simulate how MySQL works + uint16_t status=0; + if (sess->autocommit) status |= SERVER_STATUS_AUTOCOMMIT; + if ((*proxy_sqlite3_get_autocommit)(db)==0) { + status |= SERVER_STATUS_IN_TRANS; + } + GloSQLite3Server->send_MySQL_OK(&sess->client_myds->myprot, NULL, 0, status); + run_query=false; + goto __run_query; +/* + l_free(query_length,query); + query = l_strdup((char *)"BEGIN IMMEDIATE"); + query_length=strlen(query)+1; + goto __run_query; +*/ + } else { + // setting autocommit=1 + if ((*proxy_sqlite3_get_autocommit)(db)==1) { + // there is no transaction + uint16_t status=0; + if (sess->autocommit) status |= SERVER_STATUS_AUTOCOMMIT; + if ((*proxy_sqlite3_get_autocommit)(db)==0) { + status |= SERVER_STATUS_IN_TRANS; + } + GloSQLite3Server->send_MySQL_OK(&sess->client_myds->myprot, NULL, 0, status); + run_query=false; + goto __run_query; + } else { + // there is a transaction, we run COMMIT + l_free(query_length,query); + query = l_strdup((char *)"COMMIT"); + query_length=strlen(query)+1; + goto __run_query; + } + } + } + } + // fix bug #1047 if ( /* @@ -390,8 +484,8 @@ void SQLite3_Server_session_handler(MySQL_Session *sess, void *_pa, PtrSize_t *p || (!strncasecmp("SET NAMES", query_no_space, strlen("SET NAMES"))) || - (!strncasecmp("SET AUTOCOMMIT", query_no_space, strlen("SET AUTOCOMMIT"))) - || + //(!strncasecmp("SET AUTOCOMMIT", query_no_space, strlen("SET AUTOCOMMIT"))) + //|| (!strncasecmp("/*!40100 SET @@SQL_MODE='' */", query_no_space, strlen("/*!40100 SET @@SQL_MODE='' */"))) || (!strncasecmp("/*!40103 SET TIME_ZONE=", query_no_space, strlen("/*!40103 SET TIME_ZONE="))) @@ -404,9 +498,10 @@ void SQLite3_Server_session_handler(MySQL_Session *sess, void *_pa, PtrSize_t *p ) { SQLite3_Session *sqlite_sess = (SQLite3_Session *)sess->thread->gen_args; sqlite3 *db = sqlite_sess->sessdb->get_db(); - uint16_t status=2; // autocommit + uint16_t status=0; + if (sess->autocommit) status |= SERVER_STATUS_AUTOCOMMIT; if ((*proxy_sqlite3_get_autocommit)(db)==0) { - status = 3; // autocommit + transaction + status |= SERVER_STATUS_IN_TRANS; } GloSQLite3Server->send_MySQL_OK(&sess->client_myds->myprot, NULL, 0, status); run_query=false; @@ -601,6 +696,20 @@ __end_show_commands: goto __run_query; } + if (query_length>20 && strncasecmp(query,"SELECT",6)==0) { + if (strncasecmp(query+query_length-12," FOR UPDATE",11)==0) { + char * query_new = strndup(query,query_length-12); + l_free(query_length,query); + query_length-=11; + query = query_new; + } else if (strncasecmp(query+query_length-20," LOCK IN SHARE MODE",19)==0) { + char * query_new = strndup(query,query_length-20); + l_free(query_length,query); + query_length-=11; + query = query_new; + } + } + if (sess->session_type == PROXYSQL_SESSION_SQLITE) { // no admin if ( (strncasecmp("PRAGMA",query_no_space,6)==0) @@ -679,6 +788,13 @@ __run_query: } #endif // TEST_AURORA || TEST_GALERA || TEST_GROUPREP SQLite3_Session *sqlite_sess = (SQLite3_Session *)sess->thread->gen_args; + if (sess->autocommit==false) { + sqlite3 *db = sqlite_sess->sessdb->get_db(); + if ((*proxy_sqlite3_get_autocommit)(db)==1) { + // we defer the creation of the transaction to simulate how MySQL works + sqlite_sess->sessdb->execute("BEGIN IMMEDIATE"); + } + } sqlite_sess->sessdb->execute_statement(query, &error , &cols , &affected_rows , &resultset); #if defined(TEST_AURORA) || defined(TEST_GALERA) || defined(TEST_GROUPREP) if (strncasecmp("SELECT",query_no_space,6)==0) { diff --git a/test/tap/tap/utils.cpp b/test/tap/tap/utils.cpp index a2b60ed6a..29349eded 100644 --- a/test/tap/tap/utils.cpp +++ b/test/tap/tap/utils.cpp @@ -124,7 +124,7 @@ int get_server_version(MYSQL *mysql, std::string& version) { return 0; } -int add_more_rows_test_sbtest1(int num_rows, MYSQL *mysql) { +int add_more_rows_test_sbtest1(int num_rows, MYSQL *mysql, bool sqlite) { std::random_device rd; std::mt19937 mt(rd()); std::uniform_int_distribution dist(0.0, 9.0); @@ -133,7 +133,11 @@ int add_more_rows_test_sbtest1(int num_rows, MYSQL *mysql) { while (num_rows) { std::stringstream q; + if (sqlite==false) { q << "INSERT INTO test.sbtest1 (k, c, pad) values "; + } else { + q << "INSERT INTO sbtest1 (k, c, pad) values "; + } bool put_comma = false; int i=0; unsigned int cnt=5+rand()%50; @@ -175,6 +179,14 @@ int create_table_test_sbtest1(int num_rows, MYSQL *mysql) { return add_more_rows_test_sbtest1(num_rows, mysql); } +int create_table_test_sqlite_sbtest1(int num_rows, MYSQL *mysql) { + MYSQL_QUERY(mysql, "DROP TABLE IF EXISTS sbtest1"); + MYSQL_QUERY(mysql, "CREATE TABLE if not exists sbtest1 (id INTEGER PRIMARY KEY AUTOINCREMENT, `k` int(10) NOT NULL DEFAULT '0', `c` char(120) NOT NULL DEFAULT '', `pad` char(60) NOT NULL DEFAULT '')"); + MYSQL_QUERY(mysql, "CREATE INDEX IF NOT EXISTS idx_sbtest1_k1 ON sbtest1 (k)"); + + return add_more_rows_test_sbtest1(num_rows, mysql, true); +} + int execvp(const std::string& cmd, const std::vector& argv, std::string& result) { // Pipes definition constexpr uint8_t NUM_PIPES = 3; diff --git a/test/tap/tap/utils.h b/test/tap/tap/utils.h index d6effc346..31143e5f1 100644 --- a/test/tap/tap/utils.h +++ b/test/tap/tap/utils.h @@ -61,7 +61,8 @@ int exec(const std::string& cmd, std::string& result); // create table test.sbtest1 with num_rows rows int create_table_test_sbtest1(int num_rows, MYSQL *mysql); -int add_more_rows_test_sbtest1(int num_rows, MYSQL *mysql); +int create_table_test_sqlite_sbtest1(int num_rows, MYSQL *mysql); // as above, but for SQLite3 server +int add_more_rows_test_sbtest1(int num_rows, MYSQL *mysql, bool sqlite=false); using mysql_res_row = std::vector; diff --git a/test/tap/tests/sqlite_autocommit-t.cpp b/test/tap/tests/sqlite_autocommit-t.cpp new file mode 100644 index 000000000..0fb858d56 --- /dev/null +++ b/test/tap/tests/sqlite_autocommit-t.cpp @@ -0,0 +1,143 @@ +#include +#include +#include +#include + +#include +#include +#include + +#include "tap.h" +#include "command_line.h" +#include "utils.h" + +/* +This test includes a lot of repetitive checks that could have been organized into functions. +But they have been left in this way to easily identify the failed check +*/ + + +int main(int argc, char** argv) { + CommandLine cl; + + if(cl.getEnv()) + return exit_status(); + + plan(48); + diag("Testing autocommit and transaction in SQLite3 Server"); + + MYSQL* mysql = mysql_init(NULL); + if (!mysql) + return exit_status(); + + if (!mysql_real_connect(mysql, cl.host, cl.username, cl.password, NULL, 6030, NULL, 0)) { + fprintf(stderr, "Failed to connect to database: Error: %s\n", + mysql_error(mysql)); + return exit_status(); + } + MYSQL_RES *res; + if (create_table_test_sqlite_sbtest1(100,mysql)) { + fprintf(stderr, "File %s, line %d, Error: create_table_test_sbtest1() failed\n", __FILE__, __LINE__); + return exit_status(); + } + + MYSQL_QUERY(mysql, "set autocommit=0"); + ok(((mysql->server_status & SERVER_STATUS_AUTOCOMMIT) == 0) , "Line: %d: server_status: %u , AUTOCOMMIT %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_AUTOCOMMIT); + ok(((mysql->server_status & SERVER_STATUS_IN_TRANS) == 0) , "Line: %d, server_status: %u , IN_TRANS = %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_IN_TRANS); + MYSQL_QUERY(mysql, "SELECT * FROM sbtest1 WHERE id=1"); + res = mysql_store_result(mysql); + ok(((mysql->server_status & SERVER_STATUS_AUTOCOMMIT) == 0) , "Line: %d: server_status: %u , AUTOCOMMIT %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_AUTOCOMMIT); + ok(((mysql->server_status & SERVER_STATUS_IN_TRANS) == 1) , "Line: %d, server_status: %u , IN_TRANS = %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_IN_TRANS); + mysql_free_result(res); + MYSQL_QUERY(mysql, "COMMIT"); + ok(((mysql->server_status & SERVER_STATUS_AUTOCOMMIT) == 0) , "Line: %d: server_status: %u , AUTOCOMMIT %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_AUTOCOMMIT); + ok(((mysql->server_status & SERVER_STATUS_IN_TRANS) == 0) , "Line: %d, server_status: %u , IN_TRANS = %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_IN_TRANS); + + MYSQL_QUERY(mysql, "set autocommit=0"); + ok(((mysql->server_status & SERVER_STATUS_AUTOCOMMIT) == 0) , "Line: %d: server_status: %u , AUTOCOMMIT %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_AUTOCOMMIT); + ok(((mysql->server_status & SERVER_STATUS_IN_TRANS) == 0) , "Line: %d, server_status: %u , IN_TRANS = %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_IN_TRANS); + MYSQL_QUERY(mysql, "SELECT * FROM sbtest1 WHERE id=2 FOR UPDATE"); + res = mysql_store_result(mysql); + ok(((mysql->server_status & SERVER_STATUS_AUTOCOMMIT) == 0) , "Line: %d: server_status: %u , AUTOCOMMIT %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_AUTOCOMMIT); + ok(((mysql->server_status & SERVER_STATUS_IN_TRANS) == 1) , "Line: %d, server_status: %u , IN_TRANS = %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_IN_TRANS); + mysql_free_result(res); + MYSQL_QUERY(mysql, "COMMIT"); + ok(((mysql->server_status & SERVER_STATUS_AUTOCOMMIT) == 0) , "Line: %d: server_status: %u , AUTOCOMMIT %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_AUTOCOMMIT); + ok(((mysql->server_status & SERVER_STATUS_IN_TRANS) == 0) , "Line: %d, server_status: %u , IN_TRANS = %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_IN_TRANS); + + MYSQL_QUERY(mysql, "set autocommit=0"); + ok(((mysql->server_status & SERVER_STATUS_AUTOCOMMIT) == 0) , "Line: %d: server_status: %u , AUTOCOMMIT %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_AUTOCOMMIT); + ok(((mysql->server_status & SERVER_STATUS_IN_TRANS) == 0) , "Line: %d, server_status: %u , IN_TRANS = %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_IN_TRANS); + MYSQL_QUERY(mysql, "SELECT * FROM sbtest1 WHERE id=2 LOCK IN SHARE MODE"); + res = mysql_store_result(mysql); + ok(((mysql->server_status & SERVER_STATUS_AUTOCOMMIT) == 0) , "Line: %d: server_status: %u , AUTOCOMMIT %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_AUTOCOMMIT); + ok(((mysql->server_status & SERVER_STATUS_IN_TRANS) == 1) , "Line: %d, server_status: %u , IN_TRANS = %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_IN_TRANS); + mysql_free_result(res); + MYSQL_QUERY(mysql, "COMMIT"); + ok(((mysql->server_status & SERVER_STATUS_AUTOCOMMIT) == 0) , "Line: %d: server_status: %u , AUTOCOMMIT %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_AUTOCOMMIT); + ok(((mysql->server_status & SERVER_STATUS_IN_TRANS) == 0) , "Line: %d, server_status: %u , IN_TRANS = %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_IN_TRANS); + MYSQL_QUERY(mysql, "set autocommit=1"); + ok(((mysql->server_status & SERVER_STATUS_AUTOCOMMIT) == 2) , "Line: %d: server_status: %u , AUTOCOMMIT %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_AUTOCOMMIT); + ok(((mysql->server_status & SERVER_STATUS_IN_TRANS) == 0) , "Line: %d, server_status: %u , IN_TRANS = %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_IN_TRANS); + MYSQL_QUERY(mysql, "SELECT * FROM sbtest1 WHERE id=1"); + res = mysql_store_result(mysql); + ok(((mysql->server_status & SERVER_STATUS_AUTOCOMMIT) == 2) , "Line: %d: server_status: %u , AUTOCOMMIT %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_AUTOCOMMIT); + ok(((mysql->server_status & SERVER_STATUS_IN_TRANS) == 0) , "Line: %d, server_status: %u , IN_TRANS = %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_IN_TRANS); + mysql_free_result(res); + MYSQL_QUERY(mysql, "COMMIT"); + ok(((mysql->server_status & SERVER_STATUS_AUTOCOMMIT) == 2) , "Line: %d: server_status: %u , AUTOCOMMIT %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_AUTOCOMMIT); + ok(((mysql->server_status & SERVER_STATUS_IN_TRANS) == 0) , "Line: %d, server_status: %u , IN_TRANS = %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_IN_TRANS); + + MYSQL_QUERY(mysql, "set autocommit=1"); + ok(((mysql->server_status & SERVER_STATUS_AUTOCOMMIT) == 2) , "Line: %d: server_status: %u , AUTOCOMMIT %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_AUTOCOMMIT); + ok(((mysql->server_status & SERVER_STATUS_IN_TRANS) == 0) , "Line: %d, server_status: %u , IN_TRANS = %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_IN_TRANS); + MYSQL_QUERY(mysql, "SELECT * FROM sbtest1 WHERE id=2 FOR UPDATE"); + res = mysql_store_result(mysql); + ok(((mysql->server_status & SERVER_STATUS_AUTOCOMMIT) == 2) , "Line: %d: server_status: %u , AUTOCOMMIT %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_AUTOCOMMIT); + ok(((mysql->server_status & SERVER_STATUS_IN_TRANS) == 0) , "Line: %d, server_status: %u , IN_TRANS = %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_IN_TRANS); + mysql_free_result(res); + MYSQL_QUERY(mysql, "COMMIT"); + ok(((mysql->server_status & SERVER_STATUS_AUTOCOMMIT) == 2) , "Line: %d: server_status: %u , AUTOCOMMIT %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_AUTOCOMMIT); + ok(((mysql->server_status & SERVER_STATUS_IN_TRANS) == 0) , "Line: %d, server_status: %u , IN_TRANS = %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_IN_TRANS); + + MYSQL_QUERY(mysql, "set autocommit=1"); + ok(((mysql->server_status & SERVER_STATUS_AUTOCOMMIT) == 2) , "Line: %d: server_status: %u , AUTOCOMMIT %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_AUTOCOMMIT); + ok(((mysql->server_status & SERVER_STATUS_IN_TRANS) == 0) , "Line: %d, server_status: %u , IN_TRANS = %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_IN_TRANS); + MYSQL_QUERY(mysql, "SELECT * FROM sbtest1 WHERE id=2 LOCK IN SHARE MODE"); + res = mysql_store_result(mysql); + ok(((mysql->server_status & SERVER_STATUS_AUTOCOMMIT) == 2) , "Line: %d: server_status: %u , AUTOCOMMIT %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_AUTOCOMMIT); + ok(((mysql->server_status & SERVER_STATUS_IN_TRANS) == 0) , "Line: %d, server_status: %u , IN_TRANS = %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_IN_TRANS); + mysql_free_result(res); + MYSQL_QUERY(mysql, "COMMIT"); + ok(((mysql->server_status & SERVER_STATUS_AUTOCOMMIT) == 2) , "Line: %d: server_status: %u , AUTOCOMMIT %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_AUTOCOMMIT); + ok(((mysql->server_status & SERVER_STATUS_IN_TRANS) == 0) , "Line: %d, server_status: %u , IN_TRANS = %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_IN_TRANS); + + MYSQL_QUERY(mysql, "set autocommit=0"); + ok(((mysql->server_status & SERVER_STATUS_AUTOCOMMIT) == 0) , "Line: %d: server_status: %u , AUTOCOMMIT %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_AUTOCOMMIT); + ok(((mysql->server_status & SERVER_STATUS_IN_TRANS) == 0) , "Line: %d, server_status: %u , IN_TRANS = %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_IN_TRANS); + MYSQL_QUERY(mysql, "UPDATE sbtest1 SET k=k+1 WHERE id=2"); + res = mysql_store_result(mysql); + ok(((mysql->server_status & SERVER_STATUS_AUTOCOMMIT) == 0) , "Line: %d: server_status: %u , AUTOCOMMIT %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_AUTOCOMMIT); + ok(((mysql->server_status & SERVER_STATUS_IN_TRANS) == 1) , "Line: %d, server_status: %u , IN_TRANS = %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_IN_TRANS); + mysql_free_result(res); + MYSQL_QUERY(mysql, "COMMIT"); + ok(((mysql->server_status & SERVER_STATUS_AUTOCOMMIT) == 0) , "Line: %d: server_status: %u , AUTOCOMMIT %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_AUTOCOMMIT); + ok(((mysql->server_status & SERVER_STATUS_IN_TRANS) == 0) , "Line: %d, server_status: %u , IN_TRANS = %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_IN_TRANS); + + MYSQL_QUERY(mysql, "set autocommit=1"); + ok(((mysql->server_status & SERVER_STATUS_AUTOCOMMIT) == 2) , "Line: %d: server_status: %u , AUTOCOMMIT %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_AUTOCOMMIT); + ok(((mysql->server_status & SERVER_STATUS_IN_TRANS) == 0) , "Line: %d, server_status: %u , IN_TRANS = %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_IN_TRANS); + MYSQL_QUERY(mysql, "UPDATE sbtest1 SET k=k+1 WHERE id=2"); + res = mysql_store_result(mysql); + ok(((mysql->server_status & SERVER_STATUS_AUTOCOMMIT) == 2) , "Line: %d: server_status: %u , AUTOCOMMIT %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_AUTOCOMMIT); + ok(((mysql->server_status & SERVER_STATUS_IN_TRANS) == 0) , "Line: %d, server_status: %u , IN_TRANS = %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_IN_TRANS); + mysql_free_result(res); + MYSQL_QUERY(mysql, "COMMIT"); + ok(((mysql->server_status & SERVER_STATUS_AUTOCOMMIT) == 2) , "Line: %d: server_status: %u , AUTOCOMMIT %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_AUTOCOMMIT); + ok(((mysql->server_status & SERVER_STATUS_IN_TRANS) == 0) , "Line: %d, server_status: %u , IN_TRANS = %d", __LINE__ , mysql->server_status, mysql->server_status & SERVER_STATUS_IN_TRANS); + + mysql_close(mysql); + + return exit_status(); +} +