diff --git a/libmariadb/mariadb_lib.c b/libmariadb/mariadb_lib.c index 49eff309..ff47829c 100644 --- a/libmariadb/mariadb_lib.c +++ b/libmariadb/mariadb_lib.c @@ -1967,67 +1967,84 @@ mysql_send_query(MYSQL* mysql, const char* query, unsigned long length) return ma_simple_command(mysql, COM_QUERY, query, length, 1,0); } -int mthd_my_read_query_result(MYSQL *mysql) +int ma_read_ok_packet(MYSQL *mysql, uchar *pos, ulong length) { - uchar *pos; - ulong field_count; - MYSQL_DATA *fields; - ulong length; + size_t item_len; + mysql->affected_rows= net_field_length_ll(&pos); + mysql->insert_id= net_field_length_ll(&pos); + mysql->server_status=uint2korr(pos); + pos+=2; + mysql->warning_count=uint2korr(pos); + pos+=2; + if (pos < mysql->net.read_pos+length) + { + if ((item_len= net_field_length(&pos))) + mysql->info=(char*) pos; - if (!mysql || (length = ma_net_safe_read(mysql)) == packet_error) - { - return(1); - } - free_old_query(mysql); /* Free old result */ -get_info: - pos=(uchar*) mysql->net.read_pos; - if ((field_count= net_field_length(&pos)) == 0) - { - size_t item_len; - mysql->affected_rows= net_field_length_ll(&pos); - mysql->insert_id= net_field_length_ll(&pos); - mysql->server_status=uint2korr(pos); - pos+=2; - mysql->warning_count=uint2korr(pos); - pos+=2; - if (pos < mysql->net.read_pos+length) + /* check if server supports session tracking */ + if (mysql->server_capabilities & CLIENT_SESSION_TRACKING) { - if ((item_len= net_field_length(&pos))) - mysql->info=(char*) pos; + ma_clear_session_state(mysql); + pos+= item_len; - /* check if server supports session tracking */ - if (mysql->server_capabilities & CLIENT_SESSION_TRACKING) + if (mysql->server_status & SERVER_SESSION_STATE_CHANGED) { - ma_clear_session_state(mysql); - pos+= item_len; - - if (mysql->server_status & SERVER_SESSION_STATE_CHANGED) + int i; + if (pos < mysql->net.read_pos + length) { - int i; - if (pos < mysql->net.read_pos + length) + LIST *session_item; + MYSQL_LEX_STRING *str= NULL; + enum enum_session_state_type si_type; + uchar *old_pos= pos; + size_t item_len= net_field_length(&pos); /* length for all items */ + + /* length was already set, so make sure that info will be zero terminated */ + if (mysql->info) + *old_pos= 0; + + while (item_len > 0) { - LIST *session_item; - MYSQL_LEX_STRING *str= NULL; - enum enum_session_state_type si_type; - uchar *old_pos= pos; - size_t item_len= net_field_length(&pos); /* length for all items */ + size_t plen; + char *data; + old_pos= pos; + si_type= (enum enum_session_state_type)net_field_length(&pos); + switch(si_type) { + case SESSION_TRACK_SCHEMA: + case SESSION_TRACK_STATE_CHANGE: + case SESSION_TRACK_TRANSACTION_CHARACTERISTICS: + case SESSION_TRACK_SYSTEM_VARIABLES: + net_field_length(&pos); /* ignore total length, item length will follow next */ + plen= net_field_length(&pos); + if (!ma_multi_malloc(0, + &session_item, sizeof(LIST), + &str, sizeof(MYSQL_LEX_STRING), + &data, plen, + NULL)) + { + SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); + return -1; + } + str->length= plen; + str->str= data; + memcpy(str->str, (char *)pos, plen); + pos+= plen; + session_item->data= str; + mysql->extension->session_state[si_type].list= list_add(mysql->extension->session_state[si_type].list, session_item); - /* length was already set, so make sure that info will be zero terminated */ - if (mysql->info) - *old_pos= 0; - - while (item_len > 0) - { - size_t plen; - char *data; - old_pos= pos; - si_type= (enum enum_session_state_type)net_field_length(&pos); - switch(si_type) { - case SESSION_TRACK_SCHEMA: - case SESSION_TRACK_STATE_CHANGE: - case SESSION_TRACK_TRANSACTION_CHARACTERISTICS: - case SESSION_TRACK_SYSTEM_VARIABLES: - net_field_length(&pos); /* ignore total length, item length will follow next */ + /* in case schema has changed, we have to update mysql->db */ + if (si_type == SESSION_TRACK_SCHEMA) + { + free(mysql->db); + mysql->db= malloc(plen + 1); + memcpy(mysql->db, str->str, plen); + mysql->db[plen]= 0; + } + else if (si_type == SESSION_TRACK_SYSTEM_VARIABLES) + { + my_bool set_charset= 0; + /* make sure that we update charset in case it has changed */ + if (!strncmp(str->str, "character_set_client", str->length)) + set_charset= 1; plen= net_field_length(&pos); if (!ma_multi_malloc(0, &session_item, sizeof(LIST), @@ -2044,68 +2061,54 @@ get_info: pos+= plen; session_item->data= str; mysql->extension->session_state[si_type].list= list_add(mysql->extension->session_state[si_type].list, session_item); - - /* in case schema has changed, we have to update mysql->db */ - if (si_type == SESSION_TRACK_SCHEMA) + if (set_charset && + strncmp(mysql->charset->csname, str->str, str->length) != 0) { - free(mysql->db); - mysql->db= malloc(plen + 1); - memcpy(mysql->db, str->str, plen); - mysql->db[plen]= 0; + char cs_name[64]; + MARIADB_CHARSET_INFO *cs_info; + memcpy(cs_name, str->str, str->length); + cs_name[str->length]= 0; + if ((cs_info = (MARIADB_CHARSET_INFO *)mysql_find_charset_name(cs_name))) + mysql->charset= cs_info; } - else if (si_type == SESSION_TRACK_SYSTEM_VARIABLES) - { - my_bool set_charset= 0; - /* make sure that we update charset in case it has changed */ - if (!strncmp(str->str, "character_set_client", str->length)) - set_charset= 1; - plen= net_field_length(&pos); - if (!ma_multi_malloc(0, - &session_item, sizeof(LIST), - &str, sizeof(MYSQL_LEX_STRING), - &data, plen, - NULL)) - { - SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); - return -1; - } - str->length= plen; - str->str= data; - memcpy(str->str, (char *)pos, plen); - pos+= plen; - session_item->data= str; - mysql->extension->session_state[si_type].list= list_add(mysql->extension->session_state[si_type].list, session_item); - if (set_charset && - strncmp(mysql->charset->csname, str->str, str->length) != 0) - { - char cs_name[64]; - MARIADB_CHARSET_INFO *cs_info; - memcpy(cs_name, str->str, str->length); - cs_name[str->length]= 0; - if ((cs_info = (MARIADB_CHARSET_INFO *)mysql_find_charset_name(cs_name))) - mysql->charset= cs_info; - } - } - break; - default: - /* not supported yet */ - plen= net_field_length(&pos); - pos+= plen; - break; } - item_len-= (pos - old_pos); + break; + default: + /* not supported yet */ + plen= net_field_length(&pos); + pos+= plen; + break; } + item_len-= (pos - old_pos); } - for (i= SESSION_TRACK_BEGIN; i <= SESSION_TRACK_END; i++) - { - mysql->extension->session_state[i].list= list_reverse(mysql->extension->session_state[i].list); - mysql->extension->session_state[i].current= mysql->extension->session_state[i].list; - } + } + for (i= SESSION_TRACK_BEGIN; i <= SESSION_TRACK_END; i++) + { + mysql->extension->session_state[i].list= list_reverse(mysql->extension->session_state[i].list); + mysql->extension->session_state[i].current= mysql->extension->session_state[i].list; } } } - return(0); } + return(0); +} + +int mthd_my_read_query_result(MYSQL *mysql) +{ + uchar *pos; + ulong field_count; + MYSQL_DATA *fields; + ulong length; + + if (!mysql || (length = ma_net_safe_read(mysql)) == packet_error) + { + return(1); + } + free_old_query(mysql); /* Free old result */ +get_info: + pos=(uchar*) mysql->net.read_pos; + if ((field_count= net_field_length(&pos)) == 0) + return ma_read_ok_packet(mysql, pos, length); if (field_count == NULL_LENGTH) /* LOAD DATA LOCAL INFILE */ { int error=mysql_handle_local_infile(mysql, (char *)pos); diff --git a/plugins/auth/my_auth.c b/plugins/auth/my_auth.c index 8db6e04e..aeea9d00 100644 --- a/plugins/auth/my_auth.c +++ b/plugins/auth/my_auth.c @@ -10,6 +10,7 @@ static int client_mpvio_write_packet(struct st_plugin_vio*, const uchar*, size_t static int native_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql); extern void read_user_name(char *name); extern char *ma_send_connect_attr(MYSQL *mysql, unsigned char *buffer); +extern int ma_read_ok_packet(MYSQL *mysql, uchar *pos, ulong length); typedef struct { int (*read_packet)(struct st_plugin_vio *vio, uchar **buf); @@ -577,7 +578,6 @@ int run_plugin_auth(MYSQL *mysql, char *data, uint data_len, errno); return 1; } - if (mysql->net.read_pos[0] == 254) { /* The server asked to use a different authentication plugin */ @@ -632,6 +632,8 @@ int run_plugin_auth(MYSQL *mysql, char *data, uint data_len, net->read_pos[0] should always be 0 here if the server implements the protocol correctly */ - return mysql->net.read_pos[0] != 0; + if (mysql->net.read_pos[0] == 0) + return ma_read_ok_packet(mysql, mysql->net.read_pos + 1, pkt_length); + return 1; } diff --git a/unittest/libmariadb/connection.c b/unittest/libmariadb/connection.c index a2108270..c3f444a0 100644 --- a/unittest/libmariadb/connection.c +++ b/unittest/libmariadb/connection.c @@ -1486,7 +1486,45 @@ static int test_conc327(MYSQL *unused __attribute__((unused))) } #endif +static int test_conc332(MYSQL *unused __attribute__((unused))) +{ + int rc; + MYSQL *mysql= mysql_init(NULL); + int server_status1, server_status2; + + my_test_connect(mysql, hostname, username, password, schema, + port, socketname, 0); + + FAIL_IF(mysql_errno(mysql), "Error during connect"); + + mariadb_get_infov(mysql, MARIADB_CONNECTION_SERVER_STATUS, &server_status1); + diag("server_status: %d", server_status1); + + if (server_status1 & SERVER_STATUS_AUTOCOMMIT) + rc= mysql_query(mysql, "SET autocommit= 0"); + else + rc= mysql_query(mysql, "SET autocommit= 1"); + check_mysql_rc(rc, mysql); + mariadb_get_infov(mysql, MARIADB_CONNECTION_SERVER_STATUS, &server_status2); + diag("server_status after changing autocommit: %d", server_status2); + + rc= mysql_change_user(mysql, username, password, schema); + check_mysql_rc(rc, mysql); + + mariadb_get_infov(mysql, MARIADB_CONNECTION_SERVER_STATUS, &server_status2); + diag("server_status after mysql_change_user: %d", server_status2); + if (server_status1 != server_status2) + { + diag("Expected server_status %d instead of %d", server_status1, server_status2); + mysql_close(mysql); + return FAIL; + } + mysql_close(mysql); + return OK; +} + struct my_tests_st my_tests[] = { + {"test_conc332", test_conc332, TEST_CONNECTION_NONE, 0, NULL, NULL}, #ifndef WIN32 {"test_conc327", test_conc327, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_conc317", test_conc317, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},