1
0
mirror of https://github.com/mariadb-corporation/mariadb-connector-c.git synced 2025-08-08 14:02:17 +03:00

Fix for CONC-332:

After calling mysql_real_connect or mysql_change_user the server_status was
not updated, since run_plugin_auth didn't read the entire OK packet.
This commit is contained in:
Georg Richter
2018-05-17 07:10:15 +02:00
parent bb8655d97e
commit 0c29fdbbb3
3 changed files with 151 additions and 108 deletions

View File

@@ -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); 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; size_t item_len;
ulong field_count; mysql->affected_rows= net_field_length_ll(&pos);
MYSQL_DATA *fields; mysql->insert_id= net_field_length_ll(&pos);
ulong length; 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) /* check if server supports session tracking */
{ if (mysql->server_capabilities & CLIENT_SESSION_TRACKING)
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)
{ {
if ((item_len= net_field_length(&pos))) ma_clear_session_state(mysql);
mysql->info=(char*) pos; pos+= item_len;
/* check if server supports session tracking */ if (mysql->server_status & SERVER_SESSION_STATE_CHANGED)
if (mysql->server_capabilities & CLIENT_SESSION_TRACKING)
{ {
ma_clear_session_state(mysql); int i;
pos+= item_len; if (pos < mysql->net.read_pos + length)
if (mysql->server_status & SERVER_SESSION_STATE_CHANGED)
{ {
int i; LIST *session_item;
if (pos < mysql->net.read_pos + length) 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; size_t plen;
MYSQL_LEX_STRING *str= NULL; char *data;
enum enum_session_state_type si_type; old_pos= pos;
uchar *old_pos= pos; si_type= (enum enum_session_state_type)net_field_length(&pos);
size_t item_len= net_field_length(&pos); /* length for all items */ 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 */ /* in case schema has changed, we have to update mysql->db */
if (mysql->info) if (si_type == SESSION_TRACK_SCHEMA)
*old_pos= 0; {
free(mysql->db);
while (item_len > 0) mysql->db= malloc(plen + 1);
{ memcpy(mysql->db, str->str, plen);
size_t plen; mysql->db[plen]= 0;
char *data; }
old_pos= pos; else if (si_type == SESSION_TRACK_SYSTEM_VARIABLES)
si_type= (enum enum_session_state_type)net_field_length(&pos); {
switch(si_type) { my_bool set_charset= 0;
case SESSION_TRACK_SCHEMA: /* make sure that we update charset in case it has changed */
case SESSION_TRACK_STATE_CHANGE: if (!strncmp(str->str, "character_set_client", str->length))
case SESSION_TRACK_TRANSACTION_CHARACTERISTICS: set_charset= 1;
case SESSION_TRACK_SYSTEM_VARIABLES:
net_field_length(&pos); /* ignore total length, item length will follow next */
plen= net_field_length(&pos); plen= net_field_length(&pos);
if (!ma_multi_malloc(0, if (!ma_multi_malloc(0,
&session_item, sizeof(LIST), &session_item, sizeof(LIST),
@@ -2044,68 +2061,54 @@ get_info:
pos+= plen; pos+= plen;
session_item->data= str; session_item->data= str;
mysql->extension->session_state[si_type].list= list_add(mysql->extension->session_state[si_type].list, session_item); mysql->extension->session_state[si_type].list= list_add(mysql->extension->session_state[si_type].list, session_item);
if (set_charset &&
/* in case schema has changed, we have to update mysql->db */ strncmp(mysql->charset->csname, str->str, str->length) != 0)
if (si_type == SESSION_TRACK_SCHEMA)
{ {
free(mysql->db); char cs_name[64];
mysql->db= malloc(plen + 1); MARIADB_CHARSET_INFO *cs_info;
memcpy(mysql->db, str->str, plen); memcpy(cs_name, str->str, str->length);
mysql->db[plen]= 0; 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++) }
{ 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; 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 */ if (field_count == NULL_LENGTH) /* LOAD DATA LOCAL INFILE */
{ {
int error=mysql_handle_local_infile(mysql, (char *)pos); int error=mysql_handle_local_infile(mysql, (char *)pos);

View File

@@ -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); static int native_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql);
extern void read_user_name(char *name); extern void read_user_name(char *name);
extern char *ma_send_connect_attr(MYSQL *mysql, unsigned char *buffer); 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 { typedef struct {
int (*read_packet)(struct st_plugin_vio *vio, uchar **buf); 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); errno);
return 1; return 1;
} }
if (mysql->net.read_pos[0] == 254) if (mysql->net.read_pos[0] == 254)
{ {
/* The server asked to use a different authentication plugin */ /* 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 net->read_pos[0] should always be 0 here if the server implements
the protocol correctly 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;
} }

View File

@@ -1486,7 +1486,45 @@ static int test_conc327(MYSQL *unused __attribute__((unused)))
} }
#endif #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[] = { struct my_tests_st my_tests[] = {
{"test_conc332", test_conc332, TEST_CONNECTION_NONE, 0, NULL, NULL},
#ifndef WIN32 #ifndef WIN32
{"test_conc327", test_conc327, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_conc327", test_conc327, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
{"test_conc317", test_conc317, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_conc317", test_conc317, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},