Skip to content

Commit 555b603

Browse files
authored
mysqlnd: support ER_CLIENT_INTERACTION_TIMEOUT (#13618)
1 parent f61aad8 commit 555b603

File tree

6 files changed

+59
-2
lines changed

6 files changed

+59
-2
lines changed

NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ PHP NEWS
3434
. Fixed bug GH-15432 (Heap corruption when querying a vector). (cmb,
3535
Kamil Tekiela)
3636

37+
- PDO_MYSQL:
38+
. mysqlnd: support ER_CLIENT_INTERACTION_TIMEOUT. (Appla)
39+
3740
- Session:
3841
. Emit warnings for non-positive values of session.gc_divisor and negative values
3942
of session.gc_probability. (Jorg Sowa)

UPGRADING

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,10 @@ PHP 8.4 UPGRADE NOTES
126126
has changed. Consult https://github.com/PCRE2Project/pcre2/blob/master/NEWS
127127
for a full changelog.
128128

129+
- MySQLnd
130+
. The error code reported for MySQL server wait timeouts has been changed from 2006
131+
to 4031 for MySQL server versions 8.0.24 and above.
132+
129133
- PCNTL:
130134
. The functions pcntl_sigprocmask(), pcntl_sigwaitinfo() and
131135
pcntl_sigtimedwait() now throw:

ext/mysqli/tests/bug81335.phpt

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
--TEST--
2+
Bug #81335: Packets out of order after connection timeout
3+
--EXTENSIONS--
4+
mysqli
5+
--SKIPIF--
6+
<?php
7+
if (PHP_OS === 'WINNT') die('skip on windows');
8+
if (getenv("SKIP_SLOW_TESTS")) die("skip slow test");
9+
10+
require_once 'connect.inc';
11+
if (!$link = @my_mysqli_connect($host, $user, $passwd, $db, $port, $socket)) die("skip cannot connect");
12+
if (mysqli_get_server_version($link) < 80024 || str_contains(mysqli_get_server_info($link), 'MariaDB')) {
13+
die("skip: Due to many MySQL Server differences, the test requires >= 8.0.24");
14+
}
15+
?>
16+
--FILE--
17+
<?php
18+
19+
require_once 'connect.inc';
20+
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
21+
$mysqli = new my_mysqli($host, $user, $passwd, $db, $port, $socket);
22+
$mysqli->query('SET WAIT_TIMEOUT=1');
23+
usleep(1000000 * 1.1);
24+
try {
25+
$mysqli->query('SELECT 1 + 1');
26+
} catch(mysqli_sql_exception $e) {
27+
echo $e->getMessage();
28+
echo "\n";
29+
echo $e->getCode();
30+
}
31+
?>
32+
--EXPECTF--
33+
The client was disconnected by the server because of inactivity. See wait_timeout and interactive_timeout for configuring this behavior.
34+
4031

ext/mysqlnd/mysqlnd_enum_n_def.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@
130130
#define CR_INVALID_PARAMETER_NO 2034
131131
#define CR_INVALID_BUFFER_USE 2035
132132
#define CR_LOAD_DATA_LOCAL_INFILE_REJECTED 2068
133+
#define CR_CLIENT_INTERACTION_TIMEOUT 4031
133134

134135
#define MYSQLND_EE_FILENOTFOUND 7890
135136

ext/mysqlnd/mysqlnd_result.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ mysqlnd_query_read_result_set_header(MYSQLND_CONN_DATA * conn, MYSQLND_STMT * s)
183183
UPSERT_STATUS_SET_AFFECTED_ROWS_TO_ERROR(conn->upsert_status);
184184

185185
if (FAIL == (ret = PACKET_READ(conn, &rset_header))) {
186-
if (conn->error_info->error_no != CR_SERVER_GONE_ERROR) {
186+
if (conn->error_info->error_no != CR_SERVER_GONE_ERROR && conn->error_info->error_no != CR_CLIENT_INTERACTION_TIMEOUT) {
187187
php_error_docref(NULL, E_WARNING, "Error reading result set's header");
188188
}
189189
break;

ext/mysqlnd/mysqlnd_wireprotocol.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,19 @@ mysqlnd_read_header(MYSQLND_PFC * pfc, MYSQLND_VIO * vio, MYSQLND_PACKET_HEADER
267267
pfc->data->packet_no++;
268268
DBG_RETURN(PASS);
269269
}
270+
// @see https://dev.mysql.com/worklog/task/?id=12999
271+
if (header->size > 0) {
272+
zend_uchar *buf = mnd_emalloc(header->size);
273+
if ((PASS == pfc->data->m.receive(pfc, vio, buf, header->size, conn_stats, error_info)) && buf[0] == ERROR_MARKER) {
274+
php_mysqlnd_read_error_from_line(buf + 1, header->size - 1,
275+
error_info->error, sizeof(error_info->error),
276+
&error_info->error_no, error_info->sqlstate
277+
);
278+
mnd_efree(buf);
279+
DBG_RETURN(FAIL);
280+
}
281+
mnd_efree(buf);
282+
}
270283

271284
DBG_ERR_FMT("Logical link: packets out of order. Expected %u received %u. Packet size=%zu",
272285
pfc->data->packet_no, header->packet_no, header->size);
@@ -294,7 +307,9 @@ mysqlnd_read_packet_header_and_body(MYSQLND_PACKET_HEADER * packet_header,
294307
DBG_INF_FMT("buf=%p size=%zu", buf, buf_size);
295308
if (FAIL == mysqlnd_read_header(pfc, vio, packet_header, stats, error_info)) {
296309
SET_CONNECTION_STATE(connection_state, CONN_QUIT_SENT);
297-
SET_CLIENT_ERROR(error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
310+
if (error_info->error_no == 0) {
311+
SET_CLIENT_ERROR(error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
312+
}
298313
DBG_ERR_FMT("Can't read %s's header", packet_type_as_text);
299314
DBG_RETURN(FAIL);
300315
}

0 commit comments

Comments
 (0)