Bug #45184 mysql_insert_id not reset after CHANGE_USER
Submitted: 29 May 2009 10:00 Modified: 26 Jul 2009 13:10
Reporter: Ulf Wendel Email Updates:
Status: Verified Impact on me:
None 
Category:MySQL Server: C API (client library) Severity:S4 (Feature request)
Version:5.1.35, 5.1.38-bzr OS:Any
Assigned to: CPU Architecture:Any

[29 May 2009 10:00] Ulf Wendel
Description:
mysql_insert_id() is not reset after mysql_change_user(). 

I tend to say it is a bug because its a way to access session information that should have been reset by COM_CHANGE_USER. The purpose of COM_CHANGE_USER is to provide a session as if its a new connect. Neither the C-API nor any SQL function should return data from the previous session. That is against the idea of COM_CHANGE_USER.

If its not regarded as a bug, I'd like to see this detail documented.

FYI - currently the MySQL native driver for PHP (mysqlnd) and libmysql differ. mysqlnd will reset the mysql_insert_id() whereas libmysql does not.

How to repeat:
Compile and run the test program below

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include <my_global.h>
#include <my_sys.h>
#include <mysql.h>

int exit_failure(const char *msg, MYSQL *mysql, MYSQL_RES *res);

/* Connection parameter - change */
const char *con_host = "localhost";
const char *con_user = "root";
const char *con_pass = "root";
const char *con_db = "test";
unsigned int con_port = 3306;
const char *con_socket = "/tmp/mysql.sock";
unsigned long con_flags = 0;

MYSQL *conn;
MYSQL_RES *res;
MYSQL_ROW row;

my_ulonglong insert_id;

int main(void) {

	printf("\n");
	printf("Connecting...\n");

	conn = mysql_init(NULL);
	if (conn == NULL)
		exit_failure("mysql_init() failed", NULL, NULL);

	if (mysql_real_connect(conn, con_host, con_user, con_pass, con_db, con_port, con_socket, con_flags) == NULL)
		exit_failure("mysql_real_connect() failed", conn, NULL);

	printf("Server: 	%s\n", mysql_get_server_info(conn));
	printf("Protocol: 	%u\n", mysql_get_proto_info(conn));
	printf("Client: 	%s\n\n", mysql_get_client_info());

	printf("Inserting 1 row in an auto_increment column...\n");

	if (mysql_query(conn, "DROP TABLE IF EXISTS test") != 0)
		exit_failure("DROP TABLE IF EXISTS failed", conn, NULL);

	if (mysql_query(conn, "CREATE TABLE test(id INT AUTO_INCREMENT PRIMARY KEY, label CHAR(10))") != 0)
		exit_failure("CREATE TABLE test(id INT AUTO_INCREMENT PRIMARY KEY, label CHAR(10)) failed", conn, NULL);

	if (mysql_query(conn, "INSERT INTO test(id, label) VALUES (100, 'z')") != 0)
		exit_failure("INSERT INTO test(id, label) VALUES (100, 'z') failed", conn, NULL);

	insert_id = mysql_insert_id(conn);
	printf("mysqli_insert_id() returns '%llu'...\n", insert_id);

	printf("Calling change_user() ...\n");
	if (mysql_change_user(conn, con_user, con_pass, con_db) != 0)
		exit_failure("mysql_change_user() failed", conn, NULL);

	printf("Checking if change_user() has reset LAST_INSERT_ID()...\n");
	if (mysql_query(conn, "SELECT LAST_INSERT_ID()") != 0)
		exit_failure("SELECT LAST_INSERT_ID()", conn, NULL);

	res = mysql_store_result(conn);
	if (res == NULL)
		exit_failure("mysql_store_result() failed", conn, NULL);

	if ((row = mysql_fetch_row(res)) == NULL)
		exit_failure("mysql_fetch_row() failed", conn, res);

	printf("SELECT LAST_INSERT_ID() returns '%s'...\n", row[0]);
	mysql_free_result(res);

	insert_id = mysql_insert_id(conn);
        printf("mysqli_insert_id() returns '%llu'...\n", insert_id);

	mysql_close(conn);

	return EXIT_SUCCESS;
}

int exit_failure(const char *msg, MYSQL *mysql, MYSQL_RES *res) {
	printf("ERROR: %s\n", msg);
	if (mysql) {
		printf("[%u] %s\n", mysql_errno(mysql), mysql_error(mysql));
		if (res)
			mysql_free_result(res);
		mysql_close(mysql);
	}
	printf("\n");
	exit(EXIT_FAILURE);
}
[29 May 2009 10:06] Ulf Wendel
Regression bug :-( ? http://bugs.mysql.com/bug.php?id=30472
[26 Jul 2009 13:10] Valeriy Kravchuk
Verified just as described with recent 5.1.38 from bzr on Linux:

openxs@suse:/home2/openxs/dbs/5.1> ./bug45184

Connecting...
Server:         5.1.38-debug
Protocol:       10
Client:         5.1.38

Inserting 1 row in an auto_increment column...
mysqli_insert_id() returns '100'...
Calling change_user() ...
Checking if change_user() has reset LAST_INSERT_ID()...
SELECT LAST_INSERT_ID() returns '0'...
mysqli_insert_id() returns '100'...