diff options
author | Nikita Popov <nikita.ppv@gmail.com> | 2020-10-28 11:58:07 +0100 |
---|---|---|
committer | Nikita Popov <nikita.ppv@gmail.com> | 2020-10-28 12:18:02 +0100 |
commit | 68dcaa29d8a2d51f0fed5fde9f3543a1338bfe44 (patch) | |
tree | 21d33ac6e34583436d5c39ce03f27df919883c16 | |
parent | 68f80be9d1380de731930187250a7ed6b55ae196 (diff) | |
download | php-git-68dcaa29d8a2d51f0fed5fde9f3543a1338bfe44.tar.gz |
Fixed bug #66528
Report errors in commit, rollback and autocommit handlers.
-rw-r--r-- | NEWS | 6 | ||||
-rw-r--r-- | ext/pdo/pdo_dbh.c | 4 | ||||
-rw-r--r-- | ext/pdo_mysql/mysql_driver.c | 22 | ||||
-rw-r--r-- | ext/pdo_mysql/tests/bug66528.phpt | 51 |
4 files changed, 76 insertions, 7 deletions
@@ -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-- +<?php +if (!extension_loaded('pdo') || !extension_loaded('pdo_mysql')) die('skip not loaded'); +require_once(__DIR__ . DIRECTORY_SEPARATOR . 'skipif.inc'); +require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc'); +MySQLPDOTest::skip(); +?> +--FILE-- +<?php +require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc'); + +$dbh = MySQLPDOTest::factory(); +$dbh->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-- +<?php +require __DIR__ . '/mysql_pdo_test.inc'; +MySQLPDOTest::dropTestTable(); +?> +--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. |