From 68dcaa29d8a2d51f0fed5fde9f3543a1338bfe44 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Wed, 28 Oct 2020 11:58:07 +0100 Subject: [PATCH] Fixed bug #66528 Report errors in commit, rollback and autocommit handlers. --- NEWS | 6 ++++ ext/pdo/pdo_dbh.c | 4 +-- ext/pdo_mysql/mysql_driver.c | 22 ++++++++++--- ext/pdo_mysql/tests/bug66528.phpt | 51 +++++++++++++++++++++++++++++++ 4 files changed, 76 insertions(+), 7 deletions(-) create mode 100644 ext/pdo_mysql/tests/bug66528.phpt diff --git a/NEWS b/NEWS index 64968cb7dd..95de673b3f 100644 --- a/NEWS +++ b/NEWS @@ -34,6 +34,12 @@ PHP NEWS - MySQLi: . Fixed bug #79375 (mysqli_store_result does not report error from lock wait timeout). (Kamil Tekiela, Nikita) + . Fixed bug #76525 (mysqli::commit does not throw if MYSQLI_REPORT_ERROR + enabled and mysqlnd used). (Kamil Tekiela) + +- PDO MySQL: + . Fixed bug #66528 (No PDOException or errorCode if database becomes + unavailable before PDO::commit). (Nikita) 29 Oct 2020, PHP 7.4.12 diff --git a/ext/pdo/pdo_dbh.c b/ext/pdo/pdo_dbh.c index 1396816fe9..3067fcbf41 100644 --- a/ext/pdo/pdo_dbh.c +++ b/ext/pdo/pdo_dbh.c @@ -829,9 +829,7 @@ static int pdo_dbh_attribute_set(pdo_dbh_t *dbh, zend_long attr, zval *value) /* } fail: - if (attr == PDO_ATTR_AUTOCOMMIT) { - zend_throw_exception_ex(php_pdo_get_exception(), 0, "The auto-commit mode cannot be changed for this driver"); - } else if (!dbh->methods->set_attribute) { + if (!dbh->methods->set_attribute) { pdo_raise_impl_error(dbh, NULL, "IM001", "driver does not support setting attributes"); } else { PDO_HANDLE_DBH_ERR(); diff --git a/ext/pdo_mysql/mysql_driver.c b/ext/pdo_mysql/mysql_driver.c index 656c598758..344b6fe637 100644 --- a/ext/pdo_mysql/mysql_driver.c +++ b/ext/pdo_mysql/mysql_driver.c @@ -351,7 +351,11 @@ static int mysql_handle_commit(pdo_dbh_t *dbh) { PDO_DBG_ENTER("mysql_handle_commit"); PDO_DBG_INF_FMT("dbh=%p", dbh); - PDO_DBG_RETURN(0 == mysql_commit(((pdo_mysql_db_handle *)dbh->driver_data)->server)); + if (mysql_commit(((pdo_mysql_db_handle *)dbh->driver_data)->server)) { + pdo_mysql_error(dbh); + PDO_DBG_RETURN(0); + } + PDO_DBG_RETURN(1); } /* }}} */ @@ -360,7 +364,11 @@ static int mysql_handle_rollback(pdo_dbh_t *dbh) { PDO_DBG_ENTER("mysql_handle_rollback"); PDO_DBG_INF_FMT("dbh=%p", dbh); - PDO_DBG_RETURN(0 <= mysql_rollback(((pdo_mysql_db_handle *)dbh->driver_data)->server)); + if (mysql_rollback(((pdo_mysql_db_handle *)dbh->driver_data)->server)) { + pdo_mysql_error(dbh); + PDO_DBG_RETURN(0); + } + PDO_DBG_RETURN(1); } /* }}} */ @@ -370,7 +378,11 @@ static inline int mysql_handle_autocommit(pdo_dbh_t *dbh) PDO_DBG_ENTER("mysql_handle_autocommit"); PDO_DBG_INF_FMT("dbh=%p", dbh); PDO_DBG_INF_FMT("dbh->autocommit=%d", dbh->auto_commit); - PDO_DBG_RETURN(0 <= mysql_autocommit(((pdo_mysql_db_handle *)dbh->driver_data)->server, dbh->auto_commit)); + if (mysql_autocommit(((pdo_mysql_db_handle *)dbh->driver_data)->server, dbh->auto_commit)) { + pdo_mysql_error(dbh); + PDO_DBG_RETURN(0); + } + PDO_DBG_RETURN(1); } /* }}} */ @@ -387,7 +399,9 @@ static int pdo_mysql_set_attribute(pdo_dbh_t *dbh, zend_long attr, zval *val) /* ignore if the new value equals the old one */ if (dbh->auto_commit ^ bval) { dbh->auto_commit = bval; - mysql_handle_autocommit(dbh); + if (!mysql_handle_autocommit(dbh)) { + PDO_DBG_RETURN(0); + } } PDO_DBG_RETURN(1); diff --git a/ext/pdo_mysql/tests/bug66528.phpt b/ext/pdo_mysql/tests/bug66528.phpt new file mode 100644 index 0000000000..a5c79c12b3 --- /dev/null +++ b/ext/pdo_mysql/tests/bug66528.phpt @@ -0,0 +1,51 @@ +--TEST-- +Bug #66528: No PDOException or errorCode if database becomes unavailable before PDO::commit +--SKIPIF-- + +--FILE-- +setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); +$dbh->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false); + +$dbh->exec('DROP TABLE IF EXISTS test'); +$dbh->exec('CREATE TABLE test (a int) engine=innodb'); +$dbh->beginTransaction(); +$dbh->exec('INSERT INTO test (a) VALUES (1), (2)'); +$stmt = $dbh->query('SELECT * FROM test'); + +try { + $dbh->commit(); +} catch (PDOException $e) { + echo $e->getMessage(), "\n"; +} + +try { + $dbh->rollBack(); +} catch (PDOException $e) { + echo $e->getMessage(), "\n"; +} + +try { + $dbh->setAttribute(PDO::ATTR_AUTOCOMMIT, false); +} catch (PDOException $e) { + echo $e->getMessage(), "\n"; +} + +?> +--CLEAN-- + +--EXPECT-- +SQLSTATE[HY000]: General error: 2014 Cannot execute queries while other unbuffered queries are active. Consider using PDOStatement::fetchAll(). Alternatively, if your code is only ever going to run against mysql, you may enable query buffering by setting the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY attribute. +SQLSTATE[HY000]: General error: 2014 Cannot execute queries while other unbuffered queries are active. Consider using PDOStatement::fetchAll(). Alternatively, if your code is only ever going to run against mysql, you may enable query buffering by setting the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY attribute. +SQLSTATE[HY000]: General error: 2014 Cannot execute queries while other unbuffered queries are active. Consider using PDOStatement::fetchAll(). Alternatively, if your code is only ever going to run against mysql, you may enable query buffering by setting the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY attribute. -- 2.50.1