Skip to content

Commit 68dcaa2

Browse files
committed
Fixed bug #66528
Report errors in commit, rollback and autocommit handlers.
1 parent 68f80be commit 68dcaa2

File tree

4 files changed

+76
-7
lines changed

4 files changed

+76
-7
lines changed

NEWS

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@ PHP NEWS
3434
- MySQLi:
3535
. Fixed bug #79375 (mysqli_store_result does not report error from lock wait
3636
timeout). (Kamil Tekiela, Nikita)
37+
. Fixed bug #76525 (mysqli::commit does not throw if MYSQLI_REPORT_ERROR
38+
enabled and mysqlnd used). (Kamil Tekiela)
39+
40+
- PDO MySQL:
41+
. Fixed bug #66528 (No PDOException or errorCode if database becomes
42+
unavailable before PDO::commit). (Nikita)
3743

3844
29 Oct 2020, PHP 7.4.12
3945

ext/pdo/pdo_dbh.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -829,9 +829,7 @@ static int pdo_dbh_attribute_set(pdo_dbh_t *dbh, zend_long attr, zval *value) /*
829829
}
830830

831831
fail:
832-
if (attr == PDO_ATTR_AUTOCOMMIT) {
833-
zend_throw_exception_ex(php_pdo_get_exception(), 0, "The auto-commit mode cannot be changed for this driver");
834-
} else if (!dbh->methods->set_attribute) {
832+
if (!dbh->methods->set_attribute) {
835833
pdo_raise_impl_error(dbh, NULL, "IM001", "driver does not support setting attributes");
836834
} else {
837835
PDO_HANDLE_DBH_ERR();

ext/pdo_mysql/mysql_driver.c

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,11 @@ static int mysql_handle_commit(pdo_dbh_t *dbh)
351351
{
352352
PDO_DBG_ENTER("mysql_handle_commit");
353353
PDO_DBG_INF_FMT("dbh=%p", dbh);
354-
PDO_DBG_RETURN(0 == mysql_commit(((pdo_mysql_db_handle *)dbh->driver_data)->server));
354+
if (mysql_commit(((pdo_mysql_db_handle *)dbh->driver_data)->server)) {
355+
pdo_mysql_error(dbh);
356+
PDO_DBG_RETURN(0);
357+
}
358+
PDO_DBG_RETURN(1);
355359
}
356360
/* }}} */
357361

@@ -360,7 +364,11 @@ static int mysql_handle_rollback(pdo_dbh_t *dbh)
360364
{
361365
PDO_DBG_ENTER("mysql_handle_rollback");
362366
PDO_DBG_INF_FMT("dbh=%p", dbh);
363-
PDO_DBG_RETURN(0 <= mysql_rollback(((pdo_mysql_db_handle *)dbh->driver_data)->server));
367+
if (mysql_rollback(((pdo_mysql_db_handle *)dbh->driver_data)->server)) {
368+
pdo_mysql_error(dbh);
369+
PDO_DBG_RETURN(0);
370+
}
371+
PDO_DBG_RETURN(1);
364372
}
365373
/* }}} */
366374

@@ -370,7 +378,11 @@ static inline int mysql_handle_autocommit(pdo_dbh_t *dbh)
370378
PDO_DBG_ENTER("mysql_handle_autocommit");
371379
PDO_DBG_INF_FMT("dbh=%p", dbh);
372380
PDO_DBG_INF_FMT("dbh->autocommit=%d", dbh->auto_commit);
373-
PDO_DBG_RETURN(0 <= mysql_autocommit(((pdo_mysql_db_handle *)dbh->driver_data)->server, dbh->auto_commit));
381+
if (mysql_autocommit(((pdo_mysql_db_handle *)dbh->driver_data)->server, dbh->auto_commit)) {
382+
pdo_mysql_error(dbh);
383+
PDO_DBG_RETURN(0);
384+
}
385+
PDO_DBG_RETURN(1);
374386
}
375387
/* }}} */
376388

@@ -387,7 +399,9 @@ static int pdo_mysql_set_attribute(pdo_dbh_t *dbh, zend_long attr, zval *val)
387399
/* ignore if the new value equals the old one */
388400
if (dbh->auto_commit ^ bval) {
389401
dbh->auto_commit = bval;
390-
mysql_handle_autocommit(dbh);
402+
if (!mysql_handle_autocommit(dbh)) {
403+
PDO_DBG_RETURN(0);
404+
}
391405
}
392406
PDO_DBG_RETURN(1);
393407

ext/pdo_mysql/tests/bug66528.phpt

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
--TEST--
2+
Bug #66528: No PDOException or errorCode if database becomes unavailable before PDO::commit
3+
--SKIPIF--
4+
<?php
5+
if (!extension_loaded('pdo') || !extension_loaded('pdo_mysql')) die('skip not loaded');
6+
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'skipif.inc');
7+
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
8+
MySQLPDOTest::skip();
9+
?>
10+
--FILE--
11+
<?php
12+
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
13+
14+
$dbh = MySQLPDOTest::factory();
15+
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
16+
$dbh->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
17+
18+
$dbh->exec('DROP TABLE IF EXISTS test');
19+
$dbh->exec('CREATE TABLE test (a int) engine=innodb');
20+
$dbh->beginTransaction();
21+
$dbh->exec('INSERT INTO test (a) VALUES (1), (2)');
22+
$stmt = $dbh->query('SELECT * FROM test');
23+
24+
try {
25+
$dbh->commit();
26+
} catch (PDOException $e) {
27+
echo $e->getMessage(), "\n";
28+
}
29+
30+
try {
31+
$dbh->rollBack();
32+
} catch (PDOException $e) {
33+
echo $e->getMessage(), "\n";
34+
}
35+
36+
try {
37+
$dbh->setAttribute(PDO::ATTR_AUTOCOMMIT, false);
38+
} catch (PDOException $e) {
39+
echo $e->getMessage(), "\n";
40+
}
41+
42+
?>
43+
--CLEAN--
44+
<?php
45+
require __DIR__ . '/mysql_pdo_test.inc';
46+
MySQLPDOTest::dropTestTable();
47+
?>
48+
--EXPECT--
49+
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.
50+
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.
51+
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.

0 commit comments

Comments
 (0)