Skip to content

Commit 2fe2e5b

Browse files
Ahmed Abdounikic
Ahmed Abdou
authored andcommitted
Fix #64705 errorInfo property of PDOException is null when PDO::__construct() fails
PDO driver constructors are throwing PdoException without setting errorInfo, so create a new reusable function that throws exceptions for PDO and will also set the errorInfo. Use this function in pdo_mysql, pdo_sqlite, and pdo_pgsql.
1 parent 2fa4ca9 commit 2fe2e5b

File tree

9 files changed

+86
-6
lines changed

9 files changed

+86
-6
lines changed

NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ PHP NEWS
3131
. Fixed bug #73060 (php failed with error after temp folder cleaned up).
3232
(cmb)
3333

34+
- PDO:
35+
. Fixed bug #64705 (errorInfo property of PDOException is null when
36+
PDO::__construct() fails). (Ahmed Abdou)
37+
3438
- Standard:
3539
. Fixed bug #79930 (array_merge_recursive() crashes when called with array
3640
with single reference). (Nikita)

ext/pdo/pdo_dbh.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,33 @@
3636

3737
static int pdo_dbh_attribute_set(pdo_dbh_t *dbh, zend_long attr, zval *value);
3838

39+
void pdo_throw_exception(unsigned int driver_errcode, char *driver_errmsg, pdo_error_type *pdo_error)
40+
{
41+
zval error_info,pdo_exception;
42+
char *pdo_exception_message;
43+
44+
object_init_ex(&pdo_exception, php_pdo_get_exception());
45+
array_init(&error_info);
46+
47+
add_next_index_string(&error_info, *pdo_error);
48+
add_next_index_long(&error_info, driver_errcode);
49+
add_next_index_string(&error_info, driver_errmsg);
50+
51+
spprintf(&pdo_exception_message, 0,"SQLSTATE[%s] [%d] %s",*pdo_error, driver_errcode, driver_errmsg);
52+
zend_update_property(php_pdo_get_exception(), &pdo_exception, "errorInfo", sizeof("errorInfo")-1, &error_info);
53+
zend_update_property_long(php_pdo_get_exception(), &pdo_exception, "code", sizeof("code")-1, driver_errcode);
54+
zend_update_property_string(
55+
php_pdo_get_exception(),
56+
&pdo_exception,
57+
"message",
58+
sizeof("message")-1,
59+
pdo_exception_message
60+
);
61+
efree(pdo_exception_message);
62+
zval_ptr_dtor(&error_info);
63+
zend_throw_exception_object(&pdo_exception);
64+
}
65+
3966
void pdo_raise_impl_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, const char *sqlstate, const char *supp) /* {{{ */
4067
{
4168
pdo_error_type *pdo_err = &dbh->error_code;

ext/pdo/php_pdo_driver.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -691,6 +691,7 @@ PDO_API void php_pdo_dbh_delref(pdo_dbh_t *dbh);
691691
PDO_API void php_pdo_free_statement(pdo_stmt_t *stmt);
692692

693693

694+
PDO_API void pdo_throw_exception(unsigned int driver_errcode, char *driver_errmsg, pdo_error_type *pdo_error);
694695
#endif /* PHP_PDO_DRIVER_H */
695696
/*
696697
* Local variables:

ext/pdo_mysql/mysql_driver.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,7 @@ int _pdo_mysql_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, const char *file, int lin
103103

104104
if (!dbh->methods) {
105105
PDO_DBG_INF("Throwing exception");
106-
zend_throw_exception_ex(php_pdo_get_exception(), einfo->errcode, "SQLSTATE[%s] [%d] %s",
107-
*pdo_err, einfo->errcode, einfo->errmsg);
106+
pdo_throw_exception(einfo->errcode, einfo->errmsg, pdo_err);
108107
}
109108

110109
PDO_DBG_RETURN(einfo->errcode);

ext/pdo_mysql/tests/bug_64705.phpt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
--TEST--
2+
Bug #64705 errorInfo property of PDOException is null when PDO::__construct() fails
3+
--SKIPIF--
4+
<?php
5+
if (!extension_loaded('pdo_mysql')) print 'skip not loaded';
6+
?>
7+
--FILE--
8+
<?php
9+
$dsn = 'mysql:host=DonotExistsHost;dbname=test;user=foo;password=wrongpass';
10+
try {
11+
$pdo = new \PDO($dsn, null, null);
12+
} catch (\PDOException $e) {
13+
var_dump(!empty($e->errorInfo) && is_array($e->errorInfo));
14+
}
15+
?>
16+
--EXPECTF--
17+
bool(true)

ext/pdo_pgsql/pgsql_driver.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,7 @@ int _pdo_pgsql_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, int errcode, const char *
101101
}
102102

103103
if (!dbh->methods) {
104-
zend_throw_exception_ex(php_pdo_get_exception(), einfo->errcode, "SQLSTATE[%s] [%d] %s",
105-
*pdo_err, einfo->errcode, einfo->errmsg);
104+
pdo_throw_exception(einfo->errcode, einfo->errmsg, pdo_err);
106105
}
107106

108107
return errcode;

ext/pdo_pgsql/tests/bug_64705.phpt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
--TEST--
2+
Bug #64705 errorInfo property of PDOException is null when PDO::__construct() fails
3+
--SKIPIF--
4+
<?php
5+
if (!extension_loaded('pdo_pgsql')) print 'skip not loaded';
6+
?>
7+
--FILE--
8+
<?php
9+
$dsn = 'pgsql:host=DonotExistsHost;dbname=test;user=foo;password=wrongpass';
10+
try {
11+
$pdo = new \PDO($dsn, null, null);
12+
} catch (\PDOException $e) {
13+
var_dump(!empty($e->errorInfo) && is_array($e->errorInfo));
14+
}
15+
?>
16+
--EXPECTF--
17+
bool(true)

ext/pdo_sqlite/sqlite_driver.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,7 @@ int _pdo_sqlite_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, const char *file, int li
7676
}
7777

7878
if (!dbh->methods) {
79-
zend_throw_exception_ex(php_pdo_get_exception(), einfo->errcode, "SQLSTATE[%s] [%d] %s",
80-
*pdo_err, einfo->errcode, einfo->errmsg);
79+
pdo_throw_exception(einfo->errcode, einfo->errmsg, pdo_err);
8180
}
8281

8382
return einfo->errcode;

ext/pdo_sqlite/tests/bug_64705.phpt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
--TEST--
2+
Bug #64705 errorInfo property of PDOException is null when PDO::__construct() fails
3+
--SKIPIF--
4+
<?php
5+
if (!extension_loaded('pdo_sqlite')) print 'skip not loaded';
6+
?>
7+
--FILE--
8+
<?php
9+
$dsn = 'sqlite:./bug64705NonExistingDir/bug64705NonExistingDb';
10+
try {
11+
$pdo = new \PDO($dsn, null, null);
12+
} catch (\PDOException $e) {
13+
var_dump(!empty($e->errorInfo) && is_array($e->errorInfo));
14+
}
15+
?>
16+
--EXPECTF--
17+
bool(true)

0 commit comments

Comments
 (0)