]> granicus.if.org Git - php/commitdiff
Fixed bug #65825
authorNikita Popov <nikita.ppv@gmail.com>
Wed, 28 Oct 2020 16:12:35 +0000 (17:12 +0100)
committerNikita Popov <nikita.ppv@gmail.com>
Wed, 28 Oct 2020 16:15:27 +0000 (17:15 +0100)
Set error_info when we fail to read a packet, instead of throwing
a warning. Additionally we also need to populate the right
error_info in rowp_read -- we'll later take the error from the
packet, not the connection.

No test case, as this is hard to reliably test. I'm using the
test case from:
https://github.com/php/php-src/pull/2131#issuecomment-538374838

NEWS
ext/mysqlnd/mysqlnd_wireprotocol.c

diff --git a/NEWS b/NEWS
index 017896befac85033f54af34a43fd5b7038626be7..d2d4047d1178c664f2854a37f67a393b8cca9db2 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -44,6 +44,8 @@ PHP                                                                        NEWS
 - PDO MySQL:
   . Fixed bug #66528 (No PDOException or errorCode if database becomes
     unavailable before PDO::commit). (Nikita)
+  . Fixed bug #65825 (PDOStatement::fetch() does not throw exception on broken
+    server connection). (Nikita)
 
 29 Oct 2020, PHP 7.4.12
 
index b9a91c900e7e4aff8f59f78cc55f436c6a6e75b4..786ba2a2e9c3937c920cb58f6eaea44718b9da43 100644 (file)
@@ -1354,6 +1354,15 @@ premature_end:
 }
 /* }}} */
 
+/* Like SET_CLIENT_ERROR, but for packet error_info. The type is the same,
+ * but only some parts of it are used. */
+static void set_packet_error(
+               MYSQLND_ERROR_INFO *info, unsigned err_no, const char *sqlstate, const char *error)
+{
+       info->error_no = err_no;
+       strlcpy(info->sqlstate, sqlstate, sizeof(info->sqlstate));
+       strlcpy(info->error, error, sizeof(info->error));
+}
 
 /* {{{ php_mysqlnd_read_row_ex */
 static enum_func_status
@@ -1396,7 +1405,7 @@ php_mysqlnd_read_row_ex(MYSQLND_PFC * pfc,
 
                if (UNEXPECTED(PASS != (ret = pfc->data->m.receive(pfc, vio, p, header.size, stats, error_info)))) {
                        DBG_ERR("Empty row packet body");
-                       php_error(E_WARNING, "Empty row packet body");
+                       set_packet_error(error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
                } else {
                        while (header.size >= MYSQLND_MAX_PACKET_SIZE) {
                                if (FAIL == mysqlnd_read_header(pfc, vio, &header, stats, error_info)) {
@@ -1425,7 +1434,7 @@ php_mysqlnd_read_row_ex(MYSQLND_PFC * pfc,
 
                                if (PASS != (ret = pfc->data->m.receive(pfc, vio, p, header.size, stats, error_info))) {
                                        DBG_ERR("Empty row packet body");
-                                       php_error(E_WARNING, "Empty row packet body");
+                                       set_packet_error(error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
                                        break;
                                }
                        }
@@ -1720,8 +1729,8 @@ php_mysqlnd_rowp_read_text_protocol_c(MYSQLND_ROW_BUFFER * row_buffer, zval * fi
 static enum_func_status
 php_mysqlnd_rowp_read(MYSQLND_CONN_DATA * conn, void * _packet)
 {
-       MYSQLND_PACKET_ROW *packet= (MYSQLND_PACKET_ROW *) _packet;
-       MYSQLND_ERROR_INFO * error_info = conn->error_info;
+       MYSQLND_PACKET_ROW *packet = (MYSQLND_PACKET_ROW *) _packet;
+       MYSQLND_ERROR_INFO * error_info = &packet->error_info;
        MYSQLND_PFC * pfc = conn->protocol_frame_codec;
        MYSQLND_VIO * vio = conn->vio;
        MYSQLND_STATS * stats = conn->stats;