diff --git a/include/ProxySQL_Cluster.hpp b/include/ProxySQL_Cluster.hpp index 86739af32f..cbdbcc5efb 100644 --- a/include/ProxySQL_Cluster.hpp +++ b/include/ProxySQL_Cluster.hpp @@ -14,6 +14,12 @@ #define CLUSTER_QUERY_MYSQL_SERVERS "SELECT hostgroup_id, hostname, port, gtid_port, status, weight, compression, max_connections, max_replication_lag, use_ssl, max_latency_ms, comment FROM runtime_mysql_servers WHERE status<>'OFFLINE_HARD'" #define CLUSTER_QUERY_MYSQL_REPLICATION_HOSTGROUPS "SELECT writer_hostgroup, reader_hostgroup, comment FROM runtime_mysql_replication_hostgroups" +// the following two queries are the same used in ProxySQL_Admin::load_mysql_query_rules_to_runtime() , but on runtime_ tables. +// It is important to note that the queries in ProxySQL_Admin::load_mysql_query_rules_to_runtime() are used to compute the checksum, +// and are the same resultset saved. Therefore it Cluster can retrieve the same resultset saved it can easily compute the checksum before loading. +#define CLUSTER_QUERY_MYSQL_QUERY_RULES "SELECT rule_id, username, schemaname, flagIN, client_addr, proxy_addr, proxy_port, digest, match_digest, match_pattern, negate_match_pattern, re_modifiers, flagOUT, replace_pattern, destination_hostgroup, cache_ttl, cache_empty_result, cache_timeout, reconnect, timeout, retries, delay, next_query_flagIN, mirror_flagOUT, mirror_hostgroup, error_msg, ok_msg, sticky_conn, multiplex, gtid_from_hostgroup, log, apply, attributes, comment FROM runtime_mysql_query_rules ORDER BY rule_id" +#define CLUSTER_QUERY_MYSQL_QUERY_RULES_FAST_ROUTING "SELECT username, schemaname, flagIN, destination_hostgroup, comment FROM runtime_mysql_query_rules_fast_routing ORDER BY username, schemaname, flagIN" + class ProxySQL_Checksum_Value_2: public ProxySQL_Checksum_Value { public: time_t last_updated; @@ -368,7 +374,7 @@ class ProxySQL_Cluster { void p_update_metrics(); void thread_ending(pthread_t); void join_term_thread(); - void pull_mysql_query_rules_from_peer(); + void pull_mysql_query_rules_from_peer(const char *expected_checksum); void pull_mysql_servers_from_peer(); void pull_mysql_users_from_peer(); /** diff --git a/include/gen_utils.h b/include/gen_utils.h index 21b5b977e2..9db05eb6ac 100644 --- a/include/gen_utils.h +++ b/include/gen_utils.h @@ -1,6 +1,10 @@ #ifndef __CLASS_PTR_ARRAY_H #define __CLASS_PTR_ARRAY_H + +#include + #include "proxysql.h" +#include "sqlite3db.h" #define MIN_ARRAY_LEN 8 #define MIN_ARRAY_DELETE_RATIO 8 @@ -240,3 +244,10 @@ int remove_spaces(const char *); char *trim_spaces_in_place(char *str); char *trim_spaces_and_quotes_in_place(char *str); bool mywildcmp(const char *p, const char *str); + +/** + * @brief Helper function that converts a MYSQL_RES into a 'SQLite3_result'. + * @param resultset The resultset to be converted into a 'SQLite3_result'. + * @return the resulting 'SQLite3_result'. + */ +SQLite3_result * get_SQLite3_resulset(MYSQL_RES* resultset); diff --git a/include/khash.h b/include/khash.h index f75f3474c1..7931ee68d6 100644 --- a/include/khash.h +++ b/include/khash.h @@ -117,6 +117,7 @@ int main() { #ifndef __AC_KHASH_H #define __AC_KHASH_H +#include "../deps/cityhash/cityhash/src/city.h" /*! @header @@ -398,12 +399,23 @@ static kh_inline khint_t __ac_X31_hash_string(const char *s) if (h) for (++s ; *s; ++s) h = (h << 5) - h + (khint_t)*s; return h; } +/*! @function + @abstract const char* hash function + @param s Pointer to a null terminated string + @return The hash value + */ +static kh_inline khint_t __cityhash_hash_string(const char *s) +{ + size_t l = strlen(s); + return CityHash32(s,l); +} /*! @function @abstract Another interface to const char* hash function @param key Pointer to a null terminated string [const char*] @return The hash value [khint_t] */ -#define kh_str_hash_func(key) __ac_X31_hash_string(key) +//#define kh_str_hash_func(key) __ac_X31_hash_string(key) +#define kh_str_hash_func(key) __cityhash_hash_string(key) /*! @function @abstract Const char* comparison function */ diff --git a/include/proxysql_admin.h b/include/proxysql_admin.h index 28b9c76293..5860bdb39e 100644 --- a/include/proxysql_admin.h +++ b/include/proxysql_admin.h @@ -341,7 +341,7 @@ class ProxySQL_Admin { void flush_ldap_variables__from_memory_to_disk(); void load_mysql_servers_to_runtime(); void save_mysql_servers_from_runtime(); - char * load_mysql_query_rules_to_runtime(); + char * load_mysql_query_rules_to_runtime(SQLite3_result *SQLite3_query_rules_resultset=NULL, SQLite3_result *SQLite3_query_rules_fast_routing_resultset=NULL); void save_mysql_query_rules_from_runtime(bool); void save_mysql_query_rules_fast_routing_from_runtime(bool); char * load_mysql_firewall_to_runtime(); diff --git a/include/query_processor.h b/include/query_processor.h index 720616e61b..15f4ceeca8 100644 --- a/include/query_processor.h +++ b/include/query_processor.h @@ -328,10 +328,15 @@ class Query_Processor { unsigned long long get_rules_mem_used(); unsigned long long get_new_req_conns_count(); + SQLite3_result * query_rules_resultset; // here we save a copy of resultset for query rules + void save_query_rules(SQLite3_result *resultset); + SQLite3_result * get_current_query_rules_inner(); + // fast routing - SQLite3_result * fast_routing_resultset; + SQLite3_result * fast_routing_resultset; // here we save a copy of resultset for query rules fast routing void load_fast_routing(SQLite3_result *resultset); SQLite3_result * get_current_query_rules_fast_routing(); + SQLite3_result * get_current_query_rules_fast_routing_inner(); int get_current_query_rules_fast_routing_count(); int testing___find_HG_in_mysql_query_rules_fast_routing(char *username, char *schemaname, int flagIN); int testing___find_HG_in_mysql_query_rules_fast_routing_dual(char *username, char *schemaname, int flagIN); diff --git a/lib/ProxySQL_Admin.cpp b/lib/ProxySQL_Admin.cpp index 42be363242..b982a280b9 100644 --- a/lib/ProxySQL_Admin.cpp +++ b/lib/ProxySQL_Admin.cpp @@ -57,6 +57,11 @@ extern "C" void __gcov_dump(); extern "C" void __gcov_reset(); #endif + +#ifdef DEBUG +//#define BENCHMARK_FASTROUTING_LOAD +#endif // DEBUG + //#define MYSQL_THREAD_IMPLEMENTATION #define SELECT_VERSION_COMMENT "select @@version_comment limit 1" @@ -3717,6 +3722,49 @@ void admin_session_handler(MySQL_Session *sess, void *_pa, PtrSize_t *pkt) { } } + if (sess->session_type == PROXYSQL_SESSION_ADMIN) { // no stats + if (!strncasecmp(CLUSTER_QUERY_MYSQL_QUERY_RULES, query_no_space, strlen(CLUSTER_QUERY_MYSQL_QUERY_RULES))) { + GloQPro->wrlock(); + resultset = GloQPro->get_current_query_rules_inner(); + if (resultset == NULL) { + GloQPro->wrunlock(); // unlock first + resultset = GloQPro->get_current_query_rules(); + if (resultset) { + sess->SQLite3_to_MySQL(resultset, error, affected_rows, &sess->client_myds->myprot); + delete resultset; + run_query=false; + goto __run_query; + } + } else { + sess->SQLite3_to_MySQL(resultset, error, affected_rows, &sess->client_myds->myprot); + //delete resultset; // DO NOT DELETE . This is the inner resultset of Query_Processor + GloQPro->wrunlock(); + run_query=false; + goto __run_query; + } + } + if (!strncasecmp(CLUSTER_QUERY_MYSQL_QUERY_RULES_FAST_ROUTING, query_no_space, strlen(CLUSTER_QUERY_MYSQL_QUERY_RULES_FAST_ROUTING))) { + GloQPro->wrlock(); + resultset = GloQPro->get_current_query_rules_fast_routing_inner(); + if (resultset == NULL) { + GloQPro->wrunlock(); // unlock first + resultset = GloQPro->get_current_query_rules_fast_routing(); + if (resultset) { + sess->SQLite3_to_MySQL(resultset, error, affected_rows, &sess->client_myds->myprot); + delete resultset; + run_query=false; + goto __run_query; + } + } else { + sess->SQLite3_to_MySQL(resultset, error, affected_rows, &sess->client_myds->myprot); + //delete resultset; // DO NOT DELETE . This is the inner resultset of Query_Processor + GloQPro->wrunlock(); + run_query=false; + goto __run_query; + } + } + } + // if the client simply executes: // SELECT COUNT(*) FROM runtime_mysql_query_rules_fast_routing // we just return the count @@ -5779,6 +5827,7 @@ bool ProxySQL_Admin::init() { admindb=new SQLite3DB(); admindb->open((char *)"file:mem_admindb?mode=memory&cache=shared", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX); + admindb->execute("PRAGMA cache_size = -50000"); //sqlite3_enable_load_extension(admindb->get_db(),1); //sqlite3_auto_extension( (void(*)(void))sqlite3_json_init); statsdb=new SQLite3DB(); @@ -11833,26 +11882,43 @@ char * ProxySQL_Admin::load_mysql_firewall_to_runtime() { return NULL; } -char * ProxySQL_Admin::load_mysql_query_rules_to_runtime() { +char * ProxySQL_Admin::load_mysql_query_rules_to_runtime(SQLite3_result *SQLite3_query_rules_resultset, SQLite3_result *SQLite3_query_rules_fast_routing_resultset) { + // About the queries used here, see notes about CLUSTER_QUERY_MYSQL_QUERY_RULES and + // CLUSTER_QUERY_MYSQL_QUERY_RULES_FAST_ROUTING in ProxySQL_Cluster.hpp char *error=NULL; int cols=0; int affected_rows=0; if (GloQPro==NULL) return (char *)"Global Query Processor not started: command impossible to run"; SQLite3_result *resultset=NULL; char *query=(char *)"SELECT rule_id, username, schemaname, flagIN, client_addr, proxy_addr, proxy_port, digest, match_digest, match_pattern, negate_match_pattern, re_modifiers, flagOUT, replace_pattern, destination_hostgroup, cache_ttl, cache_empty_result, cache_timeout, reconnect, timeout, retries, delay, next_query_flagIN, mirror_flagOUT, mirror_hostgroup, error_msg, ok_msg, sticky_conn, multiplex, gtid_from_hostgroup, log, apply, attributes, comment FROM main.mysql_query_rules WHERE active=1 ORDER BY rule_id"; - admindb->execute_statement(query, &error , &cols , &affected_rows , &resultset); + if (SQLite3_query_rules_resultset==NULL) { + admindb->execute_statement(query, &error , &cols , &affected_rows , &resultset); + } else { + // Cluster can pass SQLite3_query_rules_resultset , to absolutely speed up + // the process and therefore there is no need to run any query + resultset = SQLite3_query_rules_resultset; + } char *error2 = NULL; int cols2 = 0; int affected_rows2 = 0; SQLite3_result *resultset2 = NULL; char *query2=(char *)"SELECT username, schemaname, flagIN, destination_hostgroup, comment FROM main.mysql_query_rules_fast_routing ORDER BY username, schemaname, flagIN"; - admindb->execute_statement(query2, &error2 , &cols2 , &affected_rows2 , &resultset2); + if (SQLite3_query_rules_fast_routing_resultset==NULL) { + admindb->execute_statement(query2, &error2 , &cols2 , &affected_rows2 , &resultset2); + } else { + // Cluster can pass SQLite3_query_rules_fast_routing_resultset , to absolutely speed up + // the process and therefore there is no need to run any query + resultset2 = SQLite3_query_rules_fast_routing_resultset; + } if (error) { proxy_error("Error on %s : %s\n", query, error); } else if (error2) { proxy_error("Error on %s : %s\n", query2, error2); } else { GloQPro->wrlock(); +#ifdef BENCHMARK_FASTROUTING_LOAD + for (int i=0; i<10; i++) { +#endif // BENCHMARK_FASTROUTING_LOAD if (checksum_variables.checksum_mysql_query_rules) { pthread_mutex_lock(&GloVars.checksum_mutex); uint64_t hash1 = resultset->raw_checksum(); @@ -11931,11 +11997,24 @@ char * ProxySQL_Admin::load_mysql_query_rules_to_runtime() { GloQPro->insert(nqpr, false); } GloQPro->sort(false); +#ifdef BENCHMARK_FASTROUTING_LOAD + // load a copy of resultset and resultset2 + SQLite3_result *resultset3 = new SQLite3_result(resultset); + GloQPro->save_query_rules(resultset3); + SQLite3_result *resultset4 = new SQLite3_result(resultset2); + GloQPro->load_fast_routing(resultset4); +#else + // load the original resultset and resultset2 + GloQPro->save_query_rules(resultset); GloQPro->load_fast_routing(resultset2); +#endif // BENCHMARK_FASTROUTING_LOAD GloQPro->commit(); +#ifdef BENCHMARK_FASTROUTING_LOAD + } +#endif // BENCHMARK_FASTROUTING_LOAD GloQPro->wrunlock(); } - if (resultset) delete resultset; + // if (resultset) delete resultset; // never delete it. GloQPro saves it // if (resultset2) delete resultset2; // never delete it. GloQPro saves it return NULL; } diff --git a/lib/ProxySQL_Cluster.cpp b/lib/ProxySQL_Cluster.cpp index 270edf1eeb..e0fbbef423 100644 --- a/lib/ProxySQL_Cluster.cpp +++ b/lib/ProxySQL_Cluster.cpp @@ -598,6 +598,7 @@ void ProxySQL_Node_Entry::set_checksums(MYSQL_RES *_r) { unsigned long long own_epoch = __sync_fetch_and_add(&GloVars.checksums_values.mysql_query_rules.epoch,0); char* own_checksum = __sync_fetch_and_add(&GloVars.checksums_values.mysql_query_rules.checksum,0); v = &checksums_values.mysql_query_rules; + char* v_exp_checksum = strdup(v->checksum); if (v->version > 1) { if ( (own_version == 1) // we just booted @@ -606,7 +607,7 @@ void ProxySQL_Node_Entry::set_checksums(MYSQL_RES *_r) { ) { if (v->diff_check >= diff_mqr) { proxy_info("Cluster: detected a peer %s:%d with mysql_query_rules version %llu, epoch %llu, diff_check %u. Own version: %llu, epoch: %llu. Proceeding with remote sync\n", hostname, port, v->version, v->epoch, v->diff_check, own_version, own_epoch); - GloProxyCluster->pull_mysql_query_rules_from_peer(); + GloProxyCluster->pull_mysql_query_rules_from_peer((const char *)v_exp_checksum); if (strncmp(v->checksum, GloVars.checksums_values.mysql_query_rules.checksum, 20)==0) { // we copied from the remote server, let's also copy the same epoch GloVars.checksums_values.mysql_query_rules.epoch = v->epoch; @@ -826,7 +827,7 @@ void ProxySQL_Node_Entry::set_checksums(MYSQL_RES *_r) { } } -void ProxySQL_Cluster::pull_mysql_query_rules_from_peer() { +void ProxySQL_Cluster::pull_mysql_query_rules_from_peer(const char *expected_checksum) { char * hostname = NULL; uint16_t port = 0; pthread_mutex_lock(&GloProxyCluster->update_mysql_query_rules_mutex); @@ -851,20 +852,38 @@ void ProxySQL_Cluster::pull_mysql_query_rules_from_peer() { //mysql_options(conn, MYSQL_OPT_READ_TIMEOUT, &timeout_long); //mysql_options(conn, MYSQL_OPT_WRITE_TIMEOUT, &timeout); { unsigned char val = 1; mysql_options(conn, MYSQL_OPT_SSL_ENFORCE, &val); } - proxy_info("Cluster: Fetching MySQL Query Rules from peer %s:%d started\n", hostname, port); + proxy_info("Cluster: Fetching MySQL Query Rules from peer %s:%d started. Expected checksum: %s\n", hostname, port, expected_checksum); rc_conn = mysql_real_connect(conn, hostname, username, password, NULL, port, NULL, 0); if (rc_conn) { MYSQL_RES *result1 = NULL; MYSQL_RES *result2 = NULL; - rc_query = mysql_query(conn,"SELECT rule_id, username, schemaname, flagIN, client_addr, proxy_addr, proxy_port, digest, match_digest, match_pattern, negate_match_pattern, re_modifiers, flagOUT, replace_pattern, destination_hostgroup, cache_ttl, cache_empty_result, cache_timeout, reconnect, timeout, retries, delay, next_query_flagIN, mirror_flagOUT, mirror_hostgroup, error_msg, ok_msg, sticky_conn, multiplex, gtid_from_hostgroup, log, apply, attributes, comment FROM runtime_mysql_query_rules"); + //rc_query = mysql_query(conn,"SELECT rule_id, username, schemaname, flagIN, client_addr, proxy_addr, proxy_port, digest, match_digest, match_pattern, negate_match_pattern, re_modifiers, flagOUT, replace_pattern, destination_hostgroup, cache_ttl, cache_empty_result, cache_timeout, reconnect, timeout, retries, delay, next_query_flagIN, mirror_flagOUT, mirror_hostgroup, error_msg, ok_msg, sticky_conn, multiplex, gtid_from_hostgroup, log, apply, attributes, comment FROM runtime_mysql_query_rules"); + rc_query = mysql_query(conn,CLUSTER_QUERY_MYSQL_QUERY_RULES); if ( rc_query == 0 ) { MYSQL_RES *result1 = mysql_store_result(conn); - rc_query = mysql_query(conn,"SELECT username, schemaname, flagIN, destination_hostgroup, comment FROM runtime_mysql_query_rules_fast_routing"); + rc_query = mysql_query(conn,CLUSTER_QUERY_MYSQL_QUERY_RULES_FAST_ROUTING); if ( rc_query == 0) { result2 = mysql_store_result(conn); - proxy_info("Cluster: Fetching MySQL Query Rules from peer %s:%d completed\n", hostname, port); + + // we pass these to load_mysql_query_rules_to_runtime() + // do not delete them + SQLite3_result * SQLite3_query_rules_resultset = get_SQLite3_resulset(result1); + SQLite3_result * SQLite3_query_rules_fast_routing_resultset = get_SQLite3_resulset(result2); + + uint64_t hash1 = SQLite3_query_rules_resultset->raw_checksum(); + uint64_t hash2 = SQLite3_query_rules_fast_routing_resultset->raw_checksum(); + hash1 += hash2; + uint32_t d32[2]; + char buf[20] = { 0 }; + memcpy(&d32, &hash1, sizeof(hash1)); + sprintf(buf,"0x%0X%0X", d32[0], d32[1]); + replace_checksum_zeros(buf); + proxy_info("Cluster: Fetching MySQL Query Rules from peer %s:%d completed. Computed checksum: %s\n", hostname, port, buf); + if (strcmp(buf, expected_checksum)==0) { + proxy_info("Cluster: Loading to runtime MySQL Query Rules from peer %s:%d\n", hostname, port); pthread_mutex_lock(&GloAdmin->sql_query_global_mutex); + //GloAdmin->admindb->execute("PRAGMA quick_check"); GloAdmin->admindb->execute("DELETE FROM mysql_query_rules"); GloAdmin->admindb->execute("DELETE FROM mysql_query_rules_fast_routing"); MYSQL_ROW row; @@ -874,6 +893,7 @@ void ProxySQL_Cluster::pull_mysql_query_rules_from_peer() { //rc=(*proxy_sqlite3_prepare_v2)(mydb3, q, -1, &statement1, 0); rc = GloAdmin->admindb->prepare_v2(q, &statement1); ASSERT_SQLITE_OK(rc, GloAdmin->admindb); + GloAdmin->admindb->execute("BEGIN TRANSACTION"); while ((row = mysql_fetch_row(result1))) { rc=(*proxy_sqlite3_bind_int64)(statement1, 1, atoll(row[0])); ASSERT_SQLITE_OK(rc, GloAdmin->admindb); // rule_id rc=(*proxy_sqlite3_bind_int64)(statement1, 2, 1); ASSERT_SQLITE_OK(rc, GloAdmin->admindb); // active @@ -914,6 +934,9 @@ void ProxySQL_Cluster::pull_mysql_query_rules_from_peer() { rc=(*proxy_sqlite3_clear_bindings)(statement1); ASSERT_SQLITE_OK(rc, GloAdmin->admindb); rc=(*proxy_sqlite3_reset)(statement1); ASSERT_SQLITE_OK(rc, GloAdmin->admindb); } + GloAdmin->admindb->execute("COMMIT"); + + std::string query32frs = "INSERT INTO mysql_query_rules_fast_routing(username, schemaname, flagIN, destination_hostgroup, comment) VALUES " + generate_multi_rows_query(32,5); char *q1fr = (char *)"INSERT INTO mysql_query_rules_fast_routing(username, schemaname, flagIN, destination_hostgroup, comment) VALUES (?1, ?2, ?3, ?4, ?5)"; char *q32fr = (char *)query32frs.c_str(); @@ -928,6 +951,7 @@ void ProxySQL_Cluster::pull_mysql_query_rules_from_peer() { int row_idx=0; int max_bulk_row_idx=mysql_num_rows(result2)/32; max_bulk_row_idx=max_bulk_row_idx*32; + GloAdmin->admindb->execute("BEGIN TRANSACTION"); while ((row = mysql_fetch_row(result2))) { int idx=row_idx%32; if (row_idxload_mysql_query_rules_to_runtime(); + //GloAdmin->admindb->execute("PRAGMA integrity_check"); + GloAdmin->admindb->execute("COMMIT"); + GloAdmin->load_mysql_query_rules_to_runtime(SQLite3_query_rules_resultset, SQLite3_query_rules_fast_routing_resultset); if (GloProxyCluster->cluster_mysql_query_rules_save_to_disk == true) { proxy_info("Cluster: Saving to disk MySQL Query Rules from peer %s:%d\n", hostname, port); GloAdmin->flush_mysql_query_rules__from_memory_to_disk(); @@ -962,6 +988,13 @@ void ProxySQL_Cluster::pull_mysql_query_rules_from_peer() { } pthread_mutex_unlock(&GloAdmin->sql_query_global_mutex); metrics.p_counter_array[p_cluster_counter::pulled_mysql_query_rules_success]->Increment(); + } else { + proxy_info("Cluster: Fetching MySQL Query Rules from peer %s:%d failed because of mismatching checksum. Expected: %s , Computed: %s\n", hostname, port, expected_checksum, buf); + metrics.p_counter_array[p_cluster_counter::pulled_mysql_query_rules_failure]->Increment(); + // only in this case we delete these resultset, otherwise they are just passed to Query Processor + delete SQLite3_query_rules_resultset; + delete SQLite3_query_rules_fast_routing_resultset; + } } else { proxy_info("Cluster: Fetching MySQL Query Rules from peer %s:%d failed: %s\n", hostname, port, mysql_error(conn)); metrics.p_counter_array[p_cluster_counter::pulled_mysql_query_rules_failure]->Increment(); diff --git a/lib/Query_Processor.cpp b/lib/Query_Processor.cpp index 89b4351e7e..51898fa460 100644 --- a/lib/Query_Processor.cpp +++ b/lib/Query_Processor.cpp @@ -521,6 +521,7 @@ Query_Processor::Query_Processor() { rand_del[13] = '-'; rand_del[14] = 0; } + query_rules_resultset = NULL; fast_routing_resultset = NULL; rules_fast_routing = kh_init(khStrInt); // create a hashtable rules_fast_routing___keys_values = NULL; @@ -546,6 +547,10 @@ Query_Processor::~Query_Processor() { } digest_umap.erase(digest_umap.begin(),digest_umap.end()); digest_text_umap.erase(digest_text_umap.begin(),digest_text_umap.end()); + if (query_rules_resultset) { + delete query_rules_resultset; + query_rules_resultset = NULL; + } if (fast_routing_resultset) { delete fast_routing_resultset; fast_routing_resultset = NULL; @@ -848,6 +853,17 @@ int Query_Processor::get_current_query_rules_fast_routing_count() { return result; } +// we return the resultset fast_routing_resultset +// the caller of this function must lock Query Processor +SQLite3_result * Query_Processor::get_current_query_rules_fast_routing_inner() { + return fast_routing_resultset; +} +// we return the resultset query_rules_resultset +// the caller of this function must lock Query Processor +SQLite3_result * Query_Processor::get_current_query_rules_inner() { + return query_rules_resultset; +} + SQLite3_result * Query_Processor::get_current_query_rules_fast_routing() { proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 4, "Dumping current query rules fast_routing, using Global version %d\n", version); SQLite3_result *result=new SQLite3_result(5); @@ -2729,6 +2745,11 @@ void Query_Processor::load_mysql_firewall_rules(SQLite3_result *resultset) { global_mysql_firewall_whitelist_rules_map___size = tot_size; } +void Query_Processor::save_query_rules(SQLite3_result *resultset) { + delete query_rules_resultset; + query_rules_resultset = resultset; // save it +} + void Query_Processor::load_fast_routing(SQLite3_result *resultset) { unsigned long long tot_size = 0; size_t rand_del_size = strlen(rand_del); diff --git a/lib/gen_utils.cpp b/lib/gen_utils.cpp index 0f7edf8c53..32b7c826dd 100644 --- a/lib/gen_utils.cpp +++ b/lib/gen_utils.cpp @@ -1,5 +1,10 @@ +#include + #include "gen_utils.h" + +using std::vector; + char *escape_string_single_quotes(char *input, bool free_it) { int i,j,l; char *o=NULL; // output string, if any @@ -220,3 +225,30 @@ bool Proxy_file_regular(const char *path) { return false; } +SQLite3_result * get_SQLite3_resulset(MYSQL_RES* resultset) { + if (resultset == nullptr) { + return nullptr; + } + + uint32_t num_fields = mysql_num_fields(resultset); + MYSQL_FIELD* fields = mysql_fetch_fields(resultset); + + SQLite3_result * sqlite_result { new SQLite3_result(num_fields) }; + + for (uint32_t i = 0; i < num_fields; i++) { + sqlite_result->add_column_definition(SQLITE_TEXT, fields[i].name); + } + + vector pta(static_cast(num_fields)); + while (MYSQL_ROW row = mysql_fetch_row(resultset)) { + for (uint32_t i = 0; i < num_fields; i++) { + pta[i] = row[i]; + } + sqlite_result->add_row(&pta[0]); + } + + // restore the initial resulset index + mysql_data_seek(resultset, 0); + + return sqlite_result; +} diff --git a/test/tap/test_enforce_autocommit_on_reads-t.cpp b/test/tap/test_enforce_autocommit_on_reads-t.cpp new file mode 100644 index 0000000000..1dbc62af7c --- /dev/null +++ b/test/tap/test_enforce_autocommit_on_reads-t.cpp @@ -0,0 +1,267 @@ +#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(96); + diag("Testing mysql-enforce_autocommit_on_reads"); + + MYSQL* mysqladmin = mysql_init(NULL); + if (!mysqladmin) + return exit_status(); + + if (!mysql_real_connect(mysqladmin, cl.host, cl.admin_username, cl.admin_password, NULL, cl.admin_port, NULL, 0)) { + fprintf(stderr, "File %s, line %d, Error: %s\n", + __FILE__, __LINE__, mysql_error(mysqladmin)); + return exit_status(); + } + + MYSQL_QUERY(mysqladmin, "SET mysql-enforce_autocommit_on_reads=0"); + MYSQL_QUERY(mysqladmin, "load mysql variables to runtime"); + + MYSQL* mysql = mysql_init(NULL); + if (!mysql) + return exit_status(); + + if (!mysql_real_connect(mysql, cl.host, cl.username, cl.password, NULL, cl.port, 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_sbtest1(100,mysql)) { + fprintf(stderr, "File %s, line %d, Error: create_table_test_sbtest1() failed\n", __FILE__, __LINE__); + return exit_status(); + } + diag("Waiting few seconds for replication..."); + sleep(2); + MYSQL_QUERY(mysql, "USE test"); + + + 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) == 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) == 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_QUERY(mysqladmin, "SET mysql-enforce_autocommit_on_reads=1"); + MYSQL_QUERY(mysqladmin, "load mysql variables to runtime"); + + 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_QUERY(mysqladmin, "SET mysql-enforce_autocommit_on_reads=0"); + MYSQL_QUERY(mysqladmin, "load mysql variables to runtime"); + + mysql_close(mysql); + mysql_close(mysqladmin); + + return exit_status(); +} + diff --git a/test/tap/tests/clickhouse_php_conn-t b/test/tap/tests/clickhouse_php_conn-t old mode 100755 new mode 100644