diff --git a/cmake/BuildMariaDBConnector.cmake b/cmake/BuildMariaDBConnector.cmake index f9ea57ea2..cf7b2ea93 100644 --- a/cmake/BuildMariaDBConnector.cmake +++ b/cmake/BuildMariaDBConnector.cmake @@ -8,7 +8,6 @@ set(MARIADB_CONNECTOR_C_REPO "https://github.com/MariaDB/mariadb-connector-c.git" CACHE STRING "MariaDB Connector-C Git repository") - # Connector-C tag to use set(MARIADB_CONNECTOR_C_TAG "v3.0.3" CACHE STRING "MariaDB Connector-C Git tag") diff --git a/include/maxscale/protocol/mysql.h b/include/maxscale/protocol/mysql.h index b6c84acc3..d29c3785b 100644 --- a/include/maxscale/protocol/mysql.h +++ b/include/maxscale/protocol/mysql.h @@ -353,6 +353,7 @@ typedef struct int ignore_replies; /*< How many replies should be discarded */ GWBUF* stored_query; /*< Temporarily stored queries */ bool collect_result; /*< Collect the next result set as one buffer */ + int num_eof_packets; /*< Signal number to indicate is current packet is ok packet*/ #if defined(SS_DEBUG) skygw_chk_t protocol_chk_tail; #endif @@ -492,7 +493,7 @@ char* create_auth_fail_str(char *username, char *hostaddr, bool password, char * void init_response_status(GWBUF* buf, uint8_t cmd, int* npackets, size_t* nbytes); bool read_complete_packet(DCB *dcb, GWBUF **readbuf); bool gw_get_shared_session_auth_info(DCB* dcb, MYSQL_session* session); -void mxs_mysql_get_session_track_info(GWBUF *buff, uint32_t server_capabilities); +void mxs_mysql_get_session_track_info(GWBUF *buff, MySQLProtocol *proto); mysql_tx_state_t parse_trx_state(const char *str); /** diff --git a/server/core/test/test_session_track.cc b/server/core/test/test_session_track.cc index 6b30bbb33..d8ab2f88f 100644 --- a/server/core/test/test_session_track.cc +++ b/server/core/test/test_session_track.cc @@ -7,6 +7,8 @@ #include #include +MySQLProtocol proto; + static const uint8_t resultset1[] = { /* BEGIN;*/ @@ -117,52 +119,98 @@ static const uint8_t resultset2[] = 0xFE, 0x00, 0x00, 0x21, 0x40 }; +/** + * SET AUTOCOMMIT=0; + * CREATE TABLE t1(a VARCHAR(20), b INT, c INT, d INT); + * INSERT INTO t1 VALUES ('', 100, 200, 300); + * SELECT * FROM t1; + **/ +static const uint8_t resultset3[] = +{ + 0x28, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x40, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x0F, 0x0A, + 0x61, 0x75, 0x74, 0x6F, 0x63, 0x6F, 0x6D, 0x6D, + 0x69, 0x74, 0x03, 0x4F, 0x46, 0x46, 0x02, 0x01, + 0x31, 0x05, 0x09, 0x08, 0x49, 0x5F, 0x52, 0x5F, + 0x5F, 0x5F, 0x53, 0x5F, 0x1D, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x0F, 0x0A, 0x61, 0x75, 0x74, 0x6F, + 0x63, 0x6F, 0x6D, 0x6D, 0x69, 0x74, 0x03, 0x4F, + 0x46, 0x46, 0x02, 0x01, 0x31, 0x07, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, + 0x40, 0x00, 0x00, 0x00, 0x0B, 0x05, 0x09, 0x08, + 0x49, 0x5F, 0x5F, 0x5F, 0x57, 0x5F, 0x5F, 0x5F, + 0x01, 0x00, 0x00, 0x01, 0x04, 0x20, 0x00, 0x00, + 0x02, 0x03, 0x64, 0x65, 0x66, 0x04, 0x74, 0x65, + 0x73, 0x74, 0x02, 0x74, 0x31, 0x02, 0x74, 0x31, + 0x01, 0x61, 0x01, 0x61, 0x0C, 0x21, 0x00, 0x3C, + 0x00, 0x00, 0x00, 0xFD, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x03, 0x03, 0x64, 0x65, + 0x66, 0x04, 0x74, 0x65, 0x73, 0x74, 0x02, 0x74, + 0x31, 0x02, 0x74, 0x31, 0x01, 0x62, 0x01, 0x62, + 0x0C, 0x3F, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x04, 0x03, 0x64, 0x65, 0x66, 0x04, 0x74, 0x65, + 0x73, 0x74, 0x02, 0x74, 0x31, 0x02, 0x74, 0x31, + 0x01, 0x63, 0x01, 0x63, 0x0C, 0x3F, 0x00, 0x0B, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x05, 0x03, 0x64, 0x65, + 0x66, 0x04, 0x74, 0x65, 0x73, 0x74, 0x02, 0x74, + 0x31, 0x02, 0x74, 0x31, 0x01, 0x64, 0x01, 0x64, + 0x0C, 0x3F, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, + 0x06, 0xFE, 0x00, 0x00, 0x21, 0x00, 0x05, 0x00, + 0x00, 0x07, 0xFE, 0x00, 0x00, 0x21, 0x00 +}; + /* functional test , test packet by packet */ void test1() { GWBUF *buffer; - uint32_t server_capabilities = GW_MYSQL_CAPABILITIES_SESSION_TRACK; + proto.server_capabilities = GW_MYSQL_CAPABILITIES_SESSION_TRACK; + proto.num_eof_packets = 0; ss_dfprintf(stderr,"test_session_track : Functional tests.\n"); //BEGIN buffer = gwbuf_alloc_and_load(PACKET_1_LEN, resultset1+PACKET_1_IDX); - mxs_mysql_get_session_track_info(buffer, server_capabilities); + mxs_mysql_get_session_track_info(buffer, &proto); ss_dassert(strncmp(gwbuf_get_property(buffer, (char *)"trx_state"), "T_______", 8) == 0); gwbuf_free(buffer); //COMMIT buffer = gwbuf_alloc_and_load(PACKET_2_LEN, resultset1+PACKET_2_IDX); - mxs_mysql_get_session_track_info(buffer, server_capabilities); + mxs_mysql_get_session_track_info(buffer, &proto); ss_dassert(strncmp(gwbuf_get_property(buffer, (char *)"trx_state"), "________", 8) == 0); gwbuf_free(buffer); //START TRANSACTION buffer = gwbuf_alloc_and_load(PACKET_3_LEN, resultset1+PACKET_3_IDX); - mxs_mysql_get_session_track_info(buffer, server_capabilities); + mxs_mysql_get_session_track_info(buffer, &proto); ss_dassert(strncmp(gwbuf_get_property(buffer, (char *)"trx_state"), "T_______", 8) == 0); gwbuf_free(buffer); //START TRANSACTION READ ONLY buffer = gwbuf_alloc_and_load(PACKET_4_LEN, resultset1+PACKET_4_IDX); - mxs_mysql_get_session_track_info(buffer, server_capabilities); + mxs_mysql_get_session_track_info(buffer, &proto); ss_dassert(strncmp(gwbuf_get_property(buffer, (char *)"trx_characteristics"), "START TRANSACTION READ ONLY;", 28) == 0); gwbuf_free(buffer); //COMMIT buffer = gwbuf_alloc_and_load(PACKET_5_LEN, resultset1+PACKET_5_IDX); - mxs_mysql_get_session_track_info(buffer, server_capabilities); + mxs_mysql_get_session_track_info(buffer, &proto); ss_dassert(gwbuf_get_property(buffer, (char *)"trx_characteristics") == NULL); ss_dassert(gwbuf_get_property(buffer, (char *)"trx_state") == NULL); gwbuf_free(buffer); //SET AUTOCOMMIT=0; buffer = gwbuf_alloc_and_load(PACKET_6_LEN, resultset1+PACKET_6_IDX); - mxs_mysql_get_session_track_info(buffer, server_capabilities); + mxs_mysql_get_session_track_info(buffer, &proto); ss_dassert(strncmp(gwbuf_get_property(buffer, (char *)"autocommit"), "OFF", 3) == 0); gwbuf_free(buffer); //INSERT INTO t1 VALUES(1); buffer = gwbuf_alloc_and_load(PACKET_7_LEN, resultset1+PACKET_7_IDX); - mxs_mysql_get_session_track_info(buffer, server_capabilities); + mxs_mysql_get_session_track_info(buffer, &proto); ss_dassert(strncmp(gwbuf_get_property(buffer, (char *)"trx_state"), "I___W___", 8) == 0); gwbuf_free(buffer); //COMMIT buffer = gwbuf_alloc_and_load(PACKET_8_LEN, resultset1+PACKET_8_IDX); - mxs_mysql_get_session_track_info(buffer, server_capabilities); + mxs_mysql_get_session_track_info(buffer, &proto); ss_dassert(strncmp(gwbuf_get_property(buffer, (char *)"trx_state"), "________", 8) == 0); gwbuf_free(buffer); } @@ -171,10 +219,23 @@ void test1() void test2() { GWBUF *buffer; - uint32_t server_capabilities = GW_MYSQL_CAPABILITIES_SESSION_TRACK; - ss_dfprintf(stderr, "test_session_track : multi results test\n"); + ss_dfprintf(stderr, "test_session_track: multi results test\n"); + proto.server_capabilities = GW_MYSQL_CAPABILITIES_SESSION_TRACK; + proto.num_eof_packets = 0; buffer = gwbuf_alloc_and_load(sizeof(resultset2), resultset2); - mxs_mysql_get_session_track_info(buffer, server_capabilities); + mxs_mysql_get_session_track_info(buffer, &proto); + ss_dassert(strncmp(gwbuf_get_property(buffer, (char *)"trx_state"), "I_R_W___", 8) == 0); + gwbuf_free(buffer); +} + +void test3() +{ + GWBUF *buffer; + proto.server_capabilities = GW_MYSQL_CAPABILITIES_SESSION_TRACK; + proto.num_eof_packets = 0; + ss_dfprintf(stderr, "test_session_track: protocol state test\n"); + buffer = gwbuf_alloc_and_load(sizeof(resultset2), resultset2); + mxs_mysql_get_session_track_info(buffer, &proto); ss_dassert(strncmp(gwbuf_get_property(buffer, (char *)"trx_state"), "I_R_W___", 8) == 0); gwbuf_free(buffer); } @@ -183,5 +244,6 @@ int main(int argc, char **argv) { test1(); test2(); + test3(); return 0; } \ No newline at end of file diff --git a/server/modules/protocol/MySQL/mariadbbackend/mysql_backend.c b/server/modules/protocol/MySQL/mariadbbackend/mysql_backend.c index 1be3b7cc3..77a3f7957 100644 --- a/server/modules/protocol/MySQL/mariadbbackend/mysql_backend.c +++ b/server/modules/protocol/MySQL/mariadbbackend/mysql_backend.c @@ -771,7 +771,7 @@ gw_read_and_write(DCB *dcb) } /** Get sesion track info from ok packet and save it to gwbuf properties */ - mxs_mysql_get_session_track_info(tmp, proto->server_capabilities); + mxs_mysql_get_session_track_info(tmp, proto); read_buffer = tmp; diff --git a/server/modules/protocol/MySQL/mysql_common.cc b/server/modules/protocol/MySQL/mysql_common.cc index daea29fa8..420c7fc86 100644 --- a/server/modules/protocol/MySQL/mysql_common.cc +++ b/server/modules/protocol/MySQL/mysql_common.cc @@ -71,6 +71,7 @@ MySQLProtocol* mysql_protocol_init(DCB* dcb, int fd) p->extra_capabilities = 0; p->ignore_replies = 0; p->collect_result = false; + p->num_eof_packets = 0; #if defined(SS_DEBUG) p->protocol_chk_top = CHK_NUM_PROTOCOL; p->protocol_chk_tail = CHK_NUM_PROTOCOL; @@ -1774,10 +1775,7 @@ void mxs_mysql_execute_kill_user(MXS_SESSION* issuer, const char* user, kill_typ * @param packet_offset Ok packet offset in this buff * @param packet_len Ok packet lengh */ -void mxs_mysql_parse_ok_packet(GWBUF *buff, - size_t packet_offset, - size_t packet_len, - uint32_t server_capabilities) +void mxs_mysql_parse_ok_packet(GWBUF *buff, size_t packet_offset, size_t packet_len) { uint8_t local_buf[packet_len]; uint8_t *ptr = local_buf; @@ -1791,56 +1789,53 @@ void mxs_mysql_parse_ok_packet(GWBUF *buff, ptr += 2; // status ptr += 2; // number of warnings - if (server_capabilities & GW_MYSQL_CAPABILITIES_SESSION_TRACK) + if (ptr < (local_buf + packet_len)) { - if (ptr < (local_buf + packet_len)) + ptr += mxs_leint_consume(&ptr); // info + if (server_status & SERVER_SESSION_STATE_CHANGED) { - ptr += mxs_leint_consume(&ptr); // info - if (server_status & SERVER_SESSION_STATE_CHANGED) + mxs_leint_consume(&ptr); // total SERVER_SESSION_STATE_CHANGED length + while (ptr < (local_buf + packet_len)) { - mxs_leint_consume(&ptr); // total SERVER_SESSION_STATE_CHANGED length - while (ptr < (local_buf + packet_len)) - { - enum_session_state_type type = - (enum enum_session_state_type)mxs_leint_consume(&ptr); + enum_session_state_type type = + (enum enum_session_state_type)mxs_leint_consume(&ptr); #if defined(SS_DEBUG) - ss_dassert(type <= SESSION_TRACK_TRANSACTION_TYPE); + ss_dassert(type <= SESSION_TRACK_TRANSACTION_TYPE); #endif - switch (type) - { - case SESSION_TRACK_STATE_CHANGE: - case SESSION_TRACK_SCHEMA: - case SESSION_TRACK_GTIDS: - ptr += mxs_leint_consume(&ptr); - break; - case SESSION_TRACK_TRANSACTION_CHARACTERISTICS: - mxs_leint_consume(&ptr); //length - var_value = mxs_lestr_consume_dup(&ptr); - gwbuf_add_property(buff, (char *)"trx_characteristics", var_value); - MXS_FREE(var_value); - break; - case SESSION_TRACK_SYSTEM_VARIABLES: - mxs_leint_consume(&ptr); //lenth - // system variables like autocommit, schema, charset ... - var_name = mxs_lestr_consume_dup(&ptr); - var_value = mxs_lestr_consume_dup(&ptr); - gwbuf_add_property(buff, var_name, var_value); - MXS_DEBUG("SESSION_TRACK_SYSTEM_VARIABLES, name:%s, value:%s", var_name, var_value); - MXS_FREE(var_name); - MXS_FREE(var_value); - break; - case SESSION_TRACK_TRANSACTION_TYPE: - mxs_leint_consume(&ptr); // length - trx_info = mxs_lestr_consume_dup(&ptr); - MXS_DEBUG("get trx_info:%s", trx_info); - gwbuf_add_property(buff, (char *)"trx_state", trx_info); - MXS_FREE(trx_info); - break; - default: - ptr += mxs_leint_consume(&ptr); - MXS_WARNING("recieved unexpecting session track type:%d", type); - break; - } + switch (type) + { + case SESSION_TRACK_STATE_CHANGE: + case SESSION_TRACK_SCHEMA: + case SESSION_TRACK_GTIDS: + ptr += mxs_leint_consume(&ptr); + break; + case SESSION_TRACK_TRANSACTION_CHARACTERISTICS: + mxs_leint_consume(&ptr); //length + var_value = mxs_lestr_consume_dup(&ptr); + gwbuf_add_property(buff, (char *)"trx_characteristics", var_value); + MXS_FREE(var_value); + break; + case SESSION_TRACK_SYSTEM_VARIABLES: + mxs_leint_consume(&ptr); //lenth + // system variables like autocommit, schema, charset ... + var_name = mxs_lestr_consume_dup(&ptr); + var_value = mxs_lestr_consume_dup(&ptr); + gwbuf_add_property(buff, var_name, var_value); + MXS_DEBUG("SESSION_TRACK_SYSTEM_VARIABLES, name:%s, value:%s", var_name, var_value); + MXS_FREE(var_name); + MXS_FREE(var_value); + break; + case SESSION_TRACK_TRANSACTION_TYPE: + mxs_leint_consume(&ptr); // length + trx_info = mxs_lestr_consume_dup(&ptr); + MXS_DEBUG("get trx_info:%s", trx_info); + gwbuf_add_property(buff, (char *)"trx_state", trx_info); + MXS_FREE(trx_info); + break; + default: + ptr += mxs_leint_consume(&ptr); + MXS_WARNING("recieved unexpecting session track type:%d", type); + break; } } } @@ -1852,21 +1847,39 @@ void mxs_mysql_parse_ok_packet(GWBUF *buff, * @param buff Buffer contain multi compelte packets * @param server_capabilities Server capabilities */ -void mxs_mysql_get_session_track_info(GWBUF *buff, uint32_t server_capabilities) +void mxs_mysql_get_session_track_info(GWBUF *buff, MySQLProtocol *proto) { size_t offset = 0; uint8_t header_and_command[MYSQL_HEADER_LEN+1]; - - while(gwbuf_copy_data(buff, offset, MYSQL_HEADER_LEN+1, header_and_command) == (MYSQL_HEADER_LEN+1)) + if (proto->server_capabilities & GW_MYSQL_CAPABILITIES_SESSION_TRACK) { - size_t packet_len = gw_mysql_get_byte3(header_and_command) + MYSQL_HEADER_LEN; - uint8_t cmd = header_and_command[MYSQL_COM_OFFSET]; - if (packet_len > MYSQL_OK_PACKET_MIN_LEN && cmd == MYSQL_REPLY_OK) + while (gwbuf_copy_data(buff, offset, MYSQL_HEADER_LEN+1, header_and_command) == (MYSQL_HEADER_LEN+1)) { - buff->gwbuf_type |= GWBUF_TYPE_REPLY_OK; - mxs_mysql_parse_ok_packet(buff, offset, packet_len, server_capabilities); + size_t packet_len = gw_mysql_get_byte3(header_and_command) + MYSQL_HEADER_LEN; + uint8_t cmd = header_and_command[MYSQL_COM_OFFSET]; + if (packet_len > MYSQL_OK_PACKET_MIN_LEN && cmd == MYSQL_REPLY_OK && proto->num_eof_packets == 0) + { + buff->gwbuf_type |= GWBUF_TYPE_REPLY_OK; + mxs_mysql_parse_ok_packet(buff, offset, packet_len); + } + offset += packet_len; + + /* first packet of result set */ + if ((proto->current_command == MXS_COM_QUERY || + proto->current_command == MXS_COM_STMT_FETCH || + proto->current_command == MXS_COM_STMT_EXECUTE) && + proto->num_eof_packets == 0 && + cmd > MYSQL_REPLY_OK && + cmd < MYSQL_REPLY_LOCAL_INFILE) + { + proto->num_eof_packets = 2; + } + + if (cmd == MYSQL_REPLY_EOF && proto->num_eof_packets > 0) + { + proto->num_eof_packets--; + } } - offset += packet_len; } }