]> granicus.if.org Git - php/commitdiff
Fixed bug #66528
authorNikita Popov <nikita.ppv@gmail.com>
Wed, 28 Oct 2020 10:58:07 +0000 (11:58 +0100)
committerNikita Popov <nikita.ppv@gmail.com>
Wed, 28 Oct 2020 11:18:02 +0000 (12:18 +0100)
Report errors in commit, rollback and autocommit handlers.

NEWS
ext/pdo/pdo_dbh.c
ext/pdo_mysql/mysql_driver.c
ext/pdo_mysql/tests/bug66528.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index 64968cb7ddc6e90de1fdb05646ddcd0f440f437e..95de673b3f9f3ee9e6f1ef45c68d4d41dffe5d51 100644 (file)
--- 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
 
index 1396816fe903b4c614d018e8cac1eb96ccd7a082..3067fcbf4142bc81aac174b9c3f8b8e36c9a39a9 100644 (file)
@@ -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();
index 656c5987581e75d4f610a6ad2b4aa39220647949..344b6fe6372aa6f134b92eb7353a61fbba179df7 100644 (file)
@@ -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 (file)
index 0000000..a5c79c1
--- /dev/null
@@ -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.