From e450621f5e0a9490c287c8c71650f8b4d5ebbc2b Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Thu, 10 Dec 2020 11:21:06 +0100 Subject: [PATCH] Fixed bug #76815 When we receive an error while reading a result set, we should assume that no more result sets are available. libmysqlclient implements the same behavior. --- NEWS | 2 ++ ext/mysqlnd/mysqlnd_result.c | 7 +++++++ ext/pdo_mysql/tests/bug76815.phpt | 33 +++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+) create mode 100644 ext/pdo_mysql/tests/bug76815.phpt diff --git a/NEWS b/NEWS index 7eeea0c4002..20f7da0f02a 100644 --- a/NEWS +++ b/NEWS @@ -40,6 +40,8 @@ PHP NEWS queries"). (Nikita) . Fixed bug #71145 (Multiple statements in init command triggers unbuffered query error). (Nikita) + . Fixed bug #76815 (PDOStatement cannot be GCed/closeCursor-ed when a + PROCEDURE resultset SIGNAL). (Nikita) - Phpdbg: . Fixed bug #76813 (Access violation near NULL on source operand). (cmb) diff --git a/ext/mysqlnd/mysqlnd_result.c b/ext/mysqlnd/mysqlnd_result.c index 46d308d1f9b..8a3ebb53a77 100644 --- a/ext/mysqlnd/mysqlnd_result.c +++ b/ext/mysqlnd/mysqlnd_result.c @@ -1359,6 +1359,13 @@ MYSQLND_METHOD(mysqlnd_res, store_result_fetch_data)(MYSQLND_CONN_DATA * const c UPSERT_STATUS_SET_SERVER_STATUS(conn->upsert_status, row_packet.server_status); } + if (ret == FAIL) { + /* Error packets do not contain server status information. However, we know that after + * an error there will be no further result sets. */ + UPSERT_STATUS_SET_SERVER_STATUS(conn->upsert_status, + UPSERT_STATUS_GET_SERVER_STATUS(conn->upsert_status) & ~SERVER_MORE_RESULTS_EXISTS); + } + /* save some memory */ if (free_rows) { /* don't try to allocate more than possible - mnd_XXalloc expects size_t, and it can have narrower range than uint64_t */ diff --git a/ext/pdo_mysql/tests/bug76815.phpt b/ext/pdo_mysql/tests/bug76815.phpt new file mode 100644 index 00000000000..b5c8577b07c --- /dev/null +++ b/ext/pdo_mysql/tests/bug76815.phpt @@ -0,0 +1,33 @@ +--TEST-- +Bug #76815: PDOStatement cannot be GCed/closeCursor-ed when a PROCEDURE resultset SIGNAL +--SKIPIF-- + +--FILE-- +setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + +$pdo->query('DROP FUNCTION IF EXISTS tst'); +$pdo->query('DROP PROCEDURE IF EXISTS tst2'); +$pdo->query('CREATE FUNCTION tst() RETURNS VARCHAR(5) DETERMINISTIC BEGIN RETURN \'x12345\'; END'); +$pdo->query('CREATE PROCEDURE tst2() BEGIN SELECT tst(); END'); + +$st = $pdo->prepare('CALL tst2()'); +try { + $st->execute(); +} catch (PDOException $ex) { + echo $ex->getMessage(), "\n"; +} +unset($st); +echo "Ok.\n"; + +?> +--EXPECT-- +SQLSTATE[22001]: String data, right truncated: 1406 Data too long for column 'tst()' at row 1 +Ok.