Skip to content

Commit

Permalink
BUG#22028117 - MYSQLCLIENT DOES NOT RETURN CORRECT
Browse files Browse the repository at this point in the history
               MYSQL_INSERT_ID VIA DATABASE HANDLE

DESCRIPTION
===========
mysql_insert_id() does not return correct values after
performing inserts in a table containing an AUTO_INCREMENT
field and then performing a SELECT operation.
The value of insert_id is getting reset to 0 after
performing SELECT. However, LAST_INSERT_ID() gives the
correct value.

ANALYSIS
========
An OK packet is sent from the server to the client to
signal successful completion of a command.
As of MySQL 5.7.5, OK packes are also used to indicate EOF,
as EOF packets are deprecated. The packet identifier 0x00
represents an OK packet whereas the packet identifier OxFE
represents an EOF packet. The EOF packet has valid values
for the following fields: packet header, warnings and
server status. The fields affected_rows and insert_id will
have valid values only if it was an OK packet and not for
an EOF packet. Reading the values of the above two fields
for an EOF packet will result in inconsistent values being
assigned to the connection handle.

FIX
====
The fix is to assign the affected_rows and insert_id fields
to the connection handle only if they were read from an OK
packet. In case of an EOF packet, skip the assignment and
proceed to the next valid fields. This way we can make sure
that they don't get wrongly updated in the connection
handle.
  • Loading branch information
Anushree Prakash B committed Feb 20, 2017
1 parent 1202cdb commit 06484ed
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 7 deletions.
29 changes: 22 additions & 7 deletions sql-common/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -717,6 +717,7 @@ void read_ok_ex(MYSQL *mysql, ulong length)
{
size_t total_len, len;
uchar *pos, *saved_pos;
my_ulonglong affected_rows, insert_id;
char *db;

struct charset_info_st *saved_cs;
Expand All @@ -730,15 +731,29 @@ void read_ok_ex(MYSQL *mysql, ulong length)

pos= mysql->net.read_pos + 1;

/* affected rows */
mysql->affected_rows= net_field_length_ll(&pos);
/* insert id */
mysql->insert_id= net_field_length_ll(&pos);
affected_rows = net_field_length_ll(&pos); /* affected rows */
insert_id = net_field_length_ll(&pos); /* insert id */

DBUG_PRINT("info",("affected_rows: %lu insert_id: %lu",
(ulong) mysql->affected_rows,
(ulong) mysql->insert_id));
/*
The following check ensures that we skip the assignment for the
above read fields (i.e. affected_rows and insert_id) wherein the
EOF packets are deprecated and the server sends OK packet instead
with a packet header of 0xFE (254) to identify it as an EOF packet.
We ignore this assignment as the valid contents of EOF packet include
packet marker, server status and warning count only. However, we would
assign these values to the connection handle if it was an OK packet
with a packet header of 0x00.
*/
if (!((mysql->server_capabilities & CLIENT_DEPRECATE_EOF) &&
mysql->net.read_pos[0] == 254))
{
mysql->affected_rows= affected_rows;
mysql->insert_id= insert_id;

DBUG_PRINT("info",("affected_rows: %lu insert_id: %lu",
(ulong) mysql->affected_rows,
(ulong) mysql->insert_id));
}
/* server status */
mysql->server_status= uint2korr(pos);
pos += 2;
Expand Down
71 changes: 71 additions & 0 deletions testclients/mysql_client_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -15724,6 +15724,76 @@ static void test_mysql_insert_id()
myquery(rc);
}

/*
Test for bug#22028117: MYSQLCLIENT DOES NOT RETURN CORRECT
MYSQL_INSERT_ID VIA DATABASE HANDLE
*/

static void test_bug22028117()
{
my_ulonglong res;
int rc;
MYSQL_STMT *stmt;

myheader("test_bug22028117");

rc = mysql_query(mysql, "USE test");
myquery(rc);
rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
myquery(rc);
rc= mysql_query(mysql, "CREATE TABLE t1 ("
"f1 INT NOT NULL PRIMARY KEY AUTO_INCREMENT,"
"f2 VARCHAR(255))");
myquery(rc);
res= mysql_insert_id(mysql);
DIE_UNLESS(res == 0);

rc= mysql_query(mysql, "INSERT INTO t1 (f2) VALUES ('a')");
myquery(rc);
res= mysql_insert_id(mysql);
DIE_UNLESS(res == 1);

rc= mysql_query(mysql, "INSERT INTO t1 (f2) VALUES ('b')");
myquery(rc);
res= mysql_insert_id(mysql);
DIE_UNLESS(res == 2);

/* Make sure that the value of insert_id is not lost after SELECT */
stmt= mysql_simple_prepare(mysql, "SELECT MAX(f1) FROM t1");
check_stmt(stmt);
rc= mysql_stmt_execute(stmt);
check_execute(stmt, rc);
rc= my_process_stmt_result(stmt);
DIE_UNLESS(rc == 1);
mysql_stmt_close(stmt);

res= mysql_insert_id(mysql);
DIE_UNLESS(res == 2);

/* insert_id will be reset to 0 after a new table is created */
rc= mysql_query(mysql, "DROP TABLE IF EXISTS t2");
myquery(rc);

rc= mysql_query(mysql, "CREATE TABLE t2 ("
"f1 INT NOT NULL PRIMARY KEY AUTO_INCREMENT,"
"f2 VARCHAR(255))");
myquery(rc);
res= mysql_insert_id(mysql);
DIE_UNLESS(res == 0);

/*
mysql_insert_id() should return expr when the INSERT query contains
last_insert_id(expr)
*/
rc= mysql_query(mysql, "INSERT INTO t1 (f1) VALUES (last_insert_id(100))");
myquery(rc);
res= mysql_insert_id(mysql);
DIE_UNLESS(res == 100);

rc= mysql_query(mysql, "DROP TABLE t1,t2");
myquery(rc);
}

/*
Bug#20152: mysql_stmt_execute() writes to MYSQL_TYPE_DATE buffer
*/
Expand Down Expand Up @@ -21164,6 +21234,7 @@ static struct my_tests_st my_tests[]= {
{ "test_bug17883203", test_bug17883203 },
{ "test_bug22559575", test_bug22559575 },
{ "test_bug19894382", test_bug19894382 },
{ "test_bug22028117", test_bug22028117 },
{ 0, 0 }
};

Expand Down

0 comments on commit 06484ed

Please sign in to comment.