mirror of
https://github.com/php/php-src.git
synced 2024-09-23 02:47:26 +00:00
Fix #46285 (lastInsertId() returns "0" when a deferenced PDOStatement is
executed)
This commit is contained in:
parent
0b77134114
commit
96b3cd0a64
92
ext/mysqli/tests/mysqli_insert_id_variation.phpt
Normal file
92
ext/mysqli/tests/mysqli_insert_id_variation.phpt
Normal file
@ -0,0 +1,92 @@
|
||||
--TEST--
|
||||
Checking last_insert_id after different operations
|
||||
--SKIPIF--
|
||||
<?php
|
||||
require_once('skipif.inc');
|
||||
require_once('skipifconnectfailure.inc');
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
include "connect.inc";
|
||||
|
||||
if (!$link = mysqli_connect($host, $user, $passwd, $db, $port, $socket))
|
||||
printf("[001] Cannot connect to the server using host=%s, user=%s, passwd=***, dbname=%s, port=%s, socket=%s\n",
|
||||
$host, $user, $db, $port, $socket);
|
||||
|
||||
$link->query("DROP TABLE IF EXISTS test_insert_id_var");
|
||||
$link->query("CREATE TABLE test_insert_id_var (id INT auto_increment, PRIMARY KEY (id))");
|
||||
$link->query("INSERT INTO test_insert_id_var VALUES (null)");
|
||||
$i = $link->insert_id;
|
||||
|
||||
if (!$i) {
|
||||
printf("[001] Got no valid insert id: %s", var_export($i, true));
|
||||
die();
|
||||
}
|
||||
|
||||
|
||||
$link->options(MYSQLI_OPT_LOCAL_INFILE, false);
|
||||
if ($i != $link->insert_id || $i != mysqli_insert_id($link)) {
|
||||
printf("[002] mysqli_option changes insert_id: %s", var_export($link->insert_id, true));
|
||||
die();
|
||||
}
|
||||
|
||||
/*
|
||||
$link->dump_debug_info();
|
||||
if ($i != $link->insert_id || $i != mysqli_insert_id($link)) {
|
||||
printf("[003] mysqli_debug_info changes insert_id: %s", var_export($link->insert_id, true));
|
||||
die();
|
||||
}
|
||||
*/
|
||||
|
||||
$link->stat();
|
||||
if ($i != $link->insert_id || $i != mysqli_insert_id($link)) {
|
||||
printf("[004] mysqli_stat changes insert_id: %s", var_export($link->insert_id, true));
|
||||
die();
|
||||
}
|
||||
|
||||
/*$link->kill($link->thread_id);
|
||||
if ($i != $link->insert_id || $i != mysqli_insert_id($link)) {
|
||||
printf("[005] mysqli_kill changes insert_id: %s", var_export($link->insert_id, true));
|
||||
die();
|
||||
}*/
|
||||
|
||||
$link->ping();
|
||||
if ($i != $link->insert_id || $i != mysqli_insert_id($link)) {
|
||||
printf("[006] mysqli_ping changes insert_id: %s", var_export($link->insert_id, true));
|
||||
die();
|
||||
}
|
||||
|
||||
/*
|
||||
mysqlnd resets the IDE to 0
|
||||
libmysql doesn't
|
||||
|
||||
$link->change_user ($user, $passwd, $db);
|
||||
if (0 != $link->insert_id || 0 != mysqli_insert_id($link)) {
|
||||
printf("[007] mysqli_change_user changes insert_id: %s", var_export($link->insert_id, true));
|
||||
die();
|
||||
}
|
||||
*/
|
||||
|
||||
$stmt = $link->prepare("SELECT 1");
|
||||
if ($i != $link->insert_id || $i != mysqli_insert_id($link)) {
|
||||
printf("[008a] mysqli_prepare changes insert_id: %s", var_export($link->insert_id, true));
|
||||
die();
|
||||
}
|
||||
echo mysqli_error($link);
|
||||
if (0 != $stmt->insert_id || 0 != mysqli_stmt_insert_id($stmt)) {
|
||||
printf("[008b] mysqli_stmt doesn't initialise insert_id: %s", var_export($stmt->insert_id, true));
|
||||
die();
|
||||
}
|
||||
|
||||
unset($stmt);
|
||||
if ($i != $link->insert_id || $i != mysqli_insert_id($link)) {
|
||||
printf("[009] stmt free changes insert_id: %s", var_export($link->insert_id, true));
|
||||
die();
|
||||
}
|
||||
|
||||
$link->query("DROP TABLE IF EXISTS test_insert_id_var");
|
||||
|
||||
echo "DONE";
|
||||
--EXPECTF--
|
||||
DONE
|
||||
|
@ -268,7 +268,8 @@ MYSQLND_METHOD_PRIVATE(mysqlnd_conn, dtor)(MYSQLND *conn TSRMLS_DC)
|
||||
/* {{{ mysqlnd_simple_command_handle_response */
|
||||
enum_func_status
|
||||
mysqlnd_simple_command_handle_response(MYSQLND *conn, enum php_mysql_packet_type ok_packet,
|
||||
zend_bool silent, enum php_mysqlnd_server_command command
|
||||
zend_bool silent, enum php_mysqlnd_server_command command,
|
||||
zend_bool ignore_upsert_status
|
||||
TSRMLS_DC)
|
||||
{
|
||||
enum_func_status ret;
|
||||
@ -309,10 +310,12 @@ mysqlnd_simple_command_handle_response(MYSQLND *conn, enum php_mysql_packet_type
|
||||
ok_response.message, ok_response.message_len,
|
||||
conn->persistent);
|
||||
|
||||
conn->upsert_status.warning_count = ok_response.warning_count;
|
||||
conn->upsert_status.server_status = ok_response.server_status;
|
||||
conn->upsert_status.affected_rows = ok_response.affected_rows;
|
||||
conn->upsert_status.last_insert_id = ok_response.last_insert_id;
|
||||
if (!ignore_upsert_status) {
|
||||
conn->upsert_status.warning_count = ok_response.warning_count;
|
||||
conn->upsert_status.server_status = ok_response.server_status;
|
||||
conn->upsert_status.affected_rows = ok_response.affected_rows;
|
||||
conn->upsert_status.last_insert_id = ok_response.last_insert_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
PACKET_FREE_ALLOCA(ok_response);
|
||||
@ -367,7 +370,8 @@ mysqlnd_simple_command_handle_response(MYSQLND *conn, enum php_mysql_packet_type
|
||||
enum_func_status
|
||||
mysqlnd_simple_command(MYSQLND *conn, enum php_mysqlnd_server_command command,
|
||||
const char * const arg, size_t arg_len,
|
||||
enum php_mysql_packet_type ok_packet, zend_bool silent TSRMLS_DC)
|
||||
enum php_mysql_packet_type ok_packet, zend_bool silent,
|
||||
zend_bool ignore_upsert_status TSRMLS_DC)
|
||||
{
|
||||
enum_func_status ret = PASS;
|
||||
php_mysql_packet_command cmd_packet;
|
||||
@ -390,7 +394,9 @@ mysqlnd_simple_command(MYSQLND *conn, enum php_mysqlnd_server_command command,
|
||||
}
|
||||
|
||||
/* clean UPSERT info */
|
||||
memset(&conn->upsert_status, 0, sizeof(conn->upsert_status));
|
||||
if (!ignore_upsert_status) {
|
||||
memset(&conn->upsert_status, 0, sizeof(conn->upsert_status));
|
||||
}
|
||||
SET_ERROR_AFF_ROWS(conn);
|
||||
SET_EMPTY_ERROR(conn->error_info);
|
||||
|
||||
@ -409,7 +415,7 @@ mysqlnd_simple_command(MYSQLND *conn, enum php_mysqlnd_server_command command,
|
||||
DBG_ERR("Server is gone");
|
||||
ret = FAIL;
|
||||
} else if (ok_packet != PROT_LAST) {
|
||||
ret = mysqlnd_simple_command_handle_response(conn, ok_packet, silent, command TSRMLS_CC);
|
||||
ret = mysqlnd_simple_command_handle_response(conn, ok_packet, silent, command, ignore_upsert_status TSRMLS_CC);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -435,7 +441,7 @@ MYSQLND_METHOD(mysqlnd_conn, set_server_option)(MYSQLND * const conn,
|
||||
|
||||
int2store(buffer, (uint) option);
|
||||
ret = mysqlnd_simple_command(conn, COM_SET_OPTION, buffer, sizeof(buffer),
|
||||
PROT_EOF_PACKET, FALSE TSRMLS_CC);
|
||||
PROT_EOF_PACKET, FALSE, TRUE TSRMLS_CC);
|
||||
DBG_RETURN(ret);
|
||||
}
|
||||
/* }}} */
|
||||
@ -850,7 +856,7 @@ MYSQLND_METHOD(mysqlnd_conn, query)(MYSQLND *conn, const char *query, unsigned i
|
||||
|
||||
if (PASS != mysqlnd_simple_command(conn, COM_QUERY, query, query_len,
|
||||
PROT_LAST /* we will handle the OK packet*/,
|
||||
FALSE TSRMLS_CC)) {
|
||||
FALSE, FALSE TSRMLS_CC)) {
|
||||
DBG_RETURN(FAIL);
|
||||
}
|
||||
CONN_SET_STATE(conn, CONN_QUERY_SENT);
|
||||
@ -897,7 +903,7 @@ MYSQLND_METHOD(mysqlnd_conn, list_fields)(MYSQLND *conn, const char *table, cons
|
||||
|
||||
if (PASS != mysqlnd_simple_command(conn, COM_FIELD_LIST, buff, p - buff,
|
||||
PROT_LAST /* we will handle the OK packet*/,
|
||||
FALSE TSRMLS_CC)) {
|
||||
FALSE, TRUE TSRMLS_CC)) {
|
||||
DBG_RETURN(NULL);
|
||||
}
|
||||
/*
|
||||
@ -1018,7 +1024,7 @@ MYSQLND_METHOD(mysqlnd_conn, dump_debug_info)(MYSQLND * const conn TSRMLS_DC)
|
||||
{
|
||||
DBG_ENTER("mysqlnd_conn::dump_debug_info");
|
||||
DBG_INF_FMT("conn=%llu", conn->thread_id);
|
||||
DBG_RETURN(mysqlnd_simple_command(conn, COM_DEBUG, NULL, 0, PROT_EOF_PACKET, FALSE TSRMLS_CC));
|
||||
DBG_RETURN(mysqlnd_simple_command(conn, COM_DEBUG, NULL, 0, PROT_EOF_PACKET, FALSE, TRUE TSRMLS_CC));
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@ -1034,7 +1040,7 @@ MYSQLND_METHOD(mysqlnd_conn, select_db)(MYSQLND * const conn,
|
||||
DBG_ENTER("mysqlnd_conn::select_db");
|
||||
DBG_INF_FMT("conn=%llu db=%s", conn->thread_id, db);
|
||||
|
||||
ret = mysqlnd_simple_command(conn, COM_INIT_DB, db, db_len, PROT_OK_PACKET, FALSE TSRMLS_CC);
|
||||
ret = mysqlnd_simple_command(conn, COM_INIT_DB, db, db_len, PROT_OK_PACKET, FALSE, TRUE TSRMLS_CC);
|
||||
/*
|
||||
The server sends 0 but libmysql doesn't read it and has established
|
||||
a protocol of giving back -1. Thus we have to follow it :(
|
||||
@ -1055,7 +1061,7 @@ MYSQLND_METHOD(mysqlnd_conn, ping)(MYSQLND * const conn TSRMLS_DC)
|
||||
DBG_ENTER("mysqlnd_conn::ping");
|
||||
DBG_INF_FMT("conn=%llu", conn->thread_id);
|
||||
|
||||
ret = mysqlnd_simple_command(conn, COM_PING, NULL, 0, PROT_OK_PACKET, TRUE TSRMLS_CC);
|
||||
ret = mysqlnd_simple_command(conn, COM_PING, NULL, 0, PROT_OK_PACKET, TRUE, TRUE TSRMLS_CC);
|
||||
/*
|
||||
The server sends 0 but libmysql doesn't read it and has established
|
||||
a protocol of giving back -1. Thus we have to follow it :(
|
||||
@ -1078,7 +1084,7 @@ MYSQLND_METHOD(mysqlnd_conn, stat)(MYSQLND *conn, char **message, unsigned int *
|
||||
DBG_ENTER("mysqlnd_conn::stat");
|
||||
DBG_INF_FMT("conn=%llu", conn->thread_id);
|
||||
|
||||
ret = mysqlnd_simple_command(conn, COM_STATISTICS, NULL, 0, PROT_LAST, FALSE TSRMLS_CC);
|
||||
ret = mysqlnd_simple_command(conn, COM_STATISTICS, NULL, 0, PROT_LAST, FALSE, TRUE TSRMLS_CC);
|
||||
if (FAIL == ret) {
|
||||
DBG_RETURN(FAIL);
|
||||
}
|
||||
@ -1112,14 +1118,14 @@ MYSQLND_METHOD(mysqlnd_conn, kill)(MYSQLND *conn, unsigned int pid TSRMLS_DC)
|
||||
|
||||
/* If we kill ourselves don't expect OK packet, PROT_LAST will skip it */
|
||||
if (pid != conn->thread_id) {
|
||||
ret = mysqlnd_simple_command(conn, COM_PROCESS_KILL, buff, 4, PROT_OK_PACKET, FALSE TSRMLS_CC);
|
||||
ret = mysqlnd_simple_command(conn, COM_PROCESS_KILL, buff, 4, PROT_OK_PACKET, FALSE, TRUE TSRMLS_CC);
|
||||
/*
|
||||
The server sends 0 but libmysql doesn't read it and has established
|
||||
a protocol of giving back -1. Thus we have to follow it :(
|
||||
*/
|
||||
SET_ERROR_AFF_ROWS(conn);
|
||||
} else if (PASS == (ret = mysqlnd_simple_command(conn, COM_PROCESS_KILL, buff,
|
||||
4, PROT_LAST, FALSE TSRMLS_CC))) {
|
||||
4, PROT_LAST, FALSE, TRUE TSRMLS_CC))) {
|
||||
CONN_SET_STATE(conn, CONN_QUIT_SENT);
|
||||
}
|
||||
DBG_RETURN(ret);
|
||||
@ -1172,7 +1178,7 @@ MYSQLND_METHOD(mysqlnd_conn, refresh)(MYSQLND * const conn, unsigned long option
|
||||
|
||||
int1store(bits, options);
|
||||
|
||||
DBG_RETURN(mysqlnd_simple_command(conn, COM_REFRESH, (char *)bits, 1, PROT_OK_PACKET, FALSE TSRMLS_CC));
|
||||
DBG_RETURN(mysqlnd_simple_command(conn, COM_REFRESH, (char *)bits, 1, PROT_OK_PACKET, FALSE, TRUE TSRMLS_CC));
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@ -1187,7 +1193,7 @@ MYSQLND_METHOD(mysqlnd_conn, shutdown)(MYSQLND * const conn, unsigned long level
|
||||
|
||||
int1store(bits, level);
|
||||
|
||||
DBG_RETURN(mysqlnd_simple_command(conn, COM_SHUTDOWN, (char *)bits, 1, PROT_OK_PACKET, FALSE TSRMLS_CC));
|
||||
DBG_RETURN(mysqlnd_simple_command(conn, COM_SHUTDOWN, (char *)bits, 1, PROT_OK_PACKET, FALSE, TRUE TSRMLS_CC));
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@ -1206,7 +1212,7 @@ mysqlnd_send_close(MYSQLND * conn TSRMLS_DC)
|
||||
case CONN_READY:
|
||||
DBG_INF("Connection clean, sending COM_QUIT");
|
||||
ret = mysqlnd_simple_command(conn, COM_QUIT, NULL, 0, PROT_LAST,
|
||||
TRUE TSRMLS_CC);
|
||||
TRUE, TRUE TSRMLS_CC);
|
||||
/* Do nothing */
|
||||
break;
|
||||
case CONN_SENDING_LOAD_DATA:
|
||||
@ -1633,7 +1639,7 @@ MYSQLND_METHOD(mysqlnd_conn, change_user)(MYSQLND * const conn,
|
||||
|
||||
if (PASS != mysqlnd_simple_command(conn, COM_CHANGE_USER, buffer, p - buffer,
|
||||
PROT_LAST /* we will handle the OK packet*/,
|
||||
FALSE TSRMLS_CC)) {
|
||||
FALSE, TRUE TSRMLS_CC)) {
|
||||
DBG_RETURN(FAIL);
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,8 @@
|
||||
|
||||
enum_func_status mysqlnd_simple_command_handle_response(MYSQLND *conn,
|
||||
enum php_mysql_packet_type ok_packet,
|
||||
zend_bool silent, enum php_mysqlnd_server_command command
|
||||
zend_bool silent, enum php_mysqlnd_server_command command,
|
||||
zend_bool ignore_upsert_status
|
||||
TSRMLS_DC);
|
||||
|
||||
|
||||
@ -241,7 +242,7 @@ mysqlnd_handle_local_infile(MYSQLND *conn, const char *filename, zend_bool *is_w
|
||||
|
||||
infile_error:
|
||||
/* get response from server and update upsert values */
|
||||
if (FAIL == mysqlnd_simple_command_handle_response(conn, PROT_OK_PACKET, FALSE, COM_QUERY TSRMLS_CC)) {
|
||||
if (FAIL == mysqlnd_simple_command_handle_response(conn, PROT_OK_PACKET, FALSE, COM_QUERY, FALSE TSRMLS_CC)) {
|
||||
result = FAIL;
|
||||
goto infile_error;
|
||||
}
|
||||
|
@ -39,7 +39,8 @@ const char * const mysqlnd_stmt_not_prepared = "Statement not prepared";
|
||||
enum_func_status mysqlnd_simple_command(MYSQLND *conn, enum php_mysqlnd_server_command command,
|
||||
const char * const arg, size_t arg_len,
|
||||
enum php_mysql_packet_type ok_packet,
|
||||
zend_bool silent TSRMLS_DC);
|
||||
zend_bool silent, zend_bool ignore_upsert_status
|
||||
TSRMLS_DC);
|
||||
|
||||
/* Exported by mysqlnd_ps_codec.c */
|
||||
zend_uchar* mysqlnd_stmt_execute_generate_request(MYSQLND_STMT *stmt, size_t *request_len,
|
||||
@ -420,7 +421,7 @@ MYSQLND_METHOD(mysqlnd_stmt, prepare)(MYSQLND_STMT * const stmt, const char * co
|
||||
}
|
||||
|
||||
if (FAIL == mysqlnd_simple_command(stmt_to_prepare->conn, COM_STMT_PREPARE, query,
|
||||
query_len, PROT_LAST, FALSE TSRMLS_CC) ||
|
||||
query_len, PROT_LAST, FALSE, TRUE TSRMLS_CC) ||
|
||||
FAIL == mysqlnd_stmt_read_prepare_response(stmt_to_prepare TSRMLS_CC)) {
|
||||
goto fail;
|
||||
}
|
||||
@ -682,7 +683,7 @@ MYSQLND_METHOD(mysqlnd_stmt, execute)(MYSQLND_STMT * const stmt TSRMLS_DC)
|
||||
|
||||
ret = mysqlnd_simple_command(stmt->conn, COM_STMT_EXECUTE, (char *)request, request_len,
|
||||
PROT_LAST /* we will handle the response packet*/,
|
||||
FALSE TSRMLS_CC);
|
||||
FALSE, FALSE TSRMLS_CC);
|
||||
|
||||
if (free_request) {
|
||||
mnd_efree(request);
|
||||
@ -990,7 +991,7 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, void *param, unsigned int fla
|
||||
|
||||
if (FAIL == mysqlnd_simple_command(stmt->conn, COM_STMT_FETCH, (char *)buf, sizeof(buf),
|
||||
PROT_LAST /* we will handle the response packet*/,
|
||||
FALSE TSRMLS_CC)) {
|
||||
FALSE, TRUE TSRMLS_CC)) {
|
||||
stmt->error_info = stmt->conn->error_info;
|
||||
DBG_RETURN(FAIL);
|
||||
}
|
||||
@ -1182,7 +1183,7 @@ MYSQLND_METHOD(mysqlnd_stmt, reset)(MYSQLND_STMT * const stmt TSRMLS_DC)
|
||||
if (CONN_GET_STATE(conn) == CONN_READY &&
|
||||
FAIL == (ret = mysqlnd_simple_command(conn, COM_STMT_RESET, (char *)cmd_buf,
|
||||
sizeof(cmd_buf), PROT_OK_PACKET,
|
||||
FALSE TSRMLS_CC))) {
|
||||
FALSE, TRUE TSRMLS_CC))) {
|
||||
stmt->error_info = conn->error_info;
|
||||
}
|
||||
stmt->upsert_status = conn->upsert_status;
|
||||
@ -1254,7 +1255,7 @@ MYSQLND_METHOD(mysqlnd_stmt, send_long_data)(MYSQLND_STMT * const stmt, unsigned
|
||||
|
||||
/* COM_STMT_SEND_LONG_DATA doesn't send an OK packet*/
|
||||
ret = mysqlnd_simple_command(conn, cmd, (char *)cmd_buf, packet_len,
|
||||
PROT_LAST , FALSE TSRMLS_CC);
|
||||
PROT_LAST , FALSE, TRUE TSRMLS_CC);
|
||||
mnd_efree(cmd_buf);
|
||||
if (FAIL == ret) {
|
||||
stmt->error_info = conn->error_info;
|
||||
@ -2023,7 +2024,7 @@ MYSQLND_METHOD_PRIVATE(mysqlnd_stmt, net_close)(MYSQLND_STMT * const stmt, zend_
|
||||
if (CONN_GET_STATE(conn) == CONN_READY &&
|
||||
FAIL == mysqlnd_simple_command(conn, COM_STMT_CLOSE, (char *)cmd_buf, sizeof(cmd_buf),
|
||||
PROT_LAST /* COM_STMT_CLOSE doesn't send an OK packet*/,
|
||||
FALSE TSRMLS_CC)) {
|
||||
FALSE, TRUE TSRMLS_CC)) {
|
||||
stmt->error_info = conn->error_info;
|
||||
DBG_RETURN(FAIL);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user