Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

improved exception messages when driver error occurs

  • Loading branch information...
commit 4cc70c177bfe4872f446b7de3f13e4df24ad9c8a 1 parent cb59d2b
@schmittjoh schmittjoh authored
View
9 UPGRADE
@@ -1,5 +1,14 @@
# Upgrade to 2.3
+## Doctrine\DBAL\Connection and Doctrine\DBAL\Statement
+
+The query related methods including but not limited to executeQuery, exec, query, and executeUpdate
+now wrap the driver exceptions such as PDOException with DBALException to add more debugging
+information such as the executed SQL statement, and any bound parameters.
+
+If you want to retrieve the driver specific exception, you can retrieve it by calling the
+``getPrevious()`` method on DBALException.
+
## Doctrine\DBAL\Connection#setCharsetSQL() removed
This method only worked on MySQL and it is considered unsafe on MySQL to use SET NAMES UTF-8 instead
View
113 lib/Doctrine/DBAL/Connection.php
@@ -594,7 +594,12 @@ public function prepare($statement)
{
$this->connect();
- $stmt = new Statement($statement, $this);
+ try {
+ $stmt = new Statement($statement, $this);
+ } catch (\Exception $ex) {
+ throw DBALException::driverExceptionDuringQuery($ex, $statement);
+ }
+
$stmt->setFetchMode($this->_defaultFetchMode);
return $stmt;
@@ -626,18 +631,22 @@ public function executeQuery($query, array $params = array(), $types = array(),
$logger->startQuery($query, $params, $types);
}
- if ($params) {
- list($query, $params, $types) = SQLParserUtils::expandListParameters($query, $params, $types);
+ try {
+ if ($params) {
+ list($query, $params, $types) = SQLParserUtils::expandListParameters($query, $params, $types);
- $stmt = $this->_conn->prepare($query);
- if ($types) {
- $this->_bindTypedValues($stmt, $params, $types);
- $stmt->execute();
+ $stmt = $this->_conn->prepare($query);
+ if ($types) {
+ $this->_bindTypedValues($stmt, $params, $types);
+ $stmt->execute();
+ } else {
+ $stmt->execute($params);
+ }
} else {
- $stmt->execute($params);
+ $stmt = $this->_conn->query($query);
}
- } else {
- $stmt = $this->_conn->query($query);
+ } catch (\Exception $ex) {
+ throw DBALException::driverExceptionDuringQuery($ex, $query, $this->resolveParams($params, $types));
}
$stmt->setFetchMode($this->_defaultFetchMode);
@@ -729,7 +738,12 @@ public function query()
$logger->startQuery($args[0]);
}
- $statement = call_user_func_array(array($this->_conn, 'query'), $args);
+ try {
+ $statement = call_user_func_array(array($this->_conn, 'query'), $args);
+ } catch (\Exception $ex) {
+ throw DBALException::driverExceptionDuringQuery($ex, func_get_arg(0));
+ }
+
$statement->setFetchMode($this->_defaultFetchMode);
if ($logger) {
@@ -760,19 +774,23 @@ public function executeUpdate($query, array $params = array(), array $types = ar
$logger->startQuery($query, $params, $types);
}
- if ($params) {
- list($query, $params, $types) = SQLParserUtils::expandListParameters($query, $params, $types);
+ try {
+ if ($params) {
+ list($query, $params, $types) = SQLParserUtils::expandListParameters($query, $params, $types);
- $stmt = $this->_conn->prepare($query);
- if ($types) {
- $this->_bindTypedValues($stmt, $params, $types);
- $stmt->execute();
+ $stmt = $this->_conn->prepare($query);
+ if ($types) {
+ $this->_bindTypedValues($stmt, $params, $types);
+ $stmt->execute();
+ } else {
+ $stmt->execute($params);
+ }
+ $result = $stmt->rowCount();
} else {
- $stmt->execute($params);
+ $result = $this->_conn->exec($query);
}
- $result = $stmt->rowCount();
- } else {
- $result = $this->_conn->exec($query);
+ } catch (\Exception $ex) {
+ throw DBALException::driverExceptionDuringQuery($ex, $query, $this->resolveParams($params, $types));
}
if ($logger) {
@@ -797,7 +815,11 @@ public function exec($statement)
$logger->startQuery($statement);
}
- $result = $this->_conn->exec($statement);
+ try {
+ $result = $this->_conn->exec($statement);
+ } catch (\Exception $ex) {
+ throw DBALException::driverExceptionDuringQuery($ex, $statement);
+ }
if ($logger) {
$logger->stopQuery();
@@ -1228,6 +1250,53 @@ private function getBindingInfo($value, $type)
}
/**
+ * Resolves the parameters to a format which can be displayed.
+ *
+ * @internal This is a purely internal method. If you rely on this method, you are advised to
+ * copy/paste the code as this method may change, or be removed without prior notice.
+ *
+ * @param array $params
+ * @param array $types
+ *
+ * @return array
+ */
+ public function resolveParams(array $params, array $types)
+ {
+ $resolvedParams = array();
+
+ // Check whether parameters are positional or named. Mixing is not allowed, just like in PDO.
+ if (is_int(key($params))) {
+ // Positional parameters
+ $typeOffset = array_key_exists(0, $types) ? -1 : 0;
+ $bindIndex = 1;
+ foreach ($params as $value) {
+ $typeIndex = $bindIndex + $typeOffset;
+ if (isset($types[$typeIndex])) {
+ $type = $types[$typeIndex];
+ list($value,) = $this->getBindingInfo($value, $type);
+ $resolvedParams[$bindIndex] = $value;
+ } else {
+ $resolvedParams[$bindIndex] = $value;
+ }
+ ++$bindIndex;
+ }
+ } else {
+ // Named parameters
+ foreach ($params as $name => $value) {
+ if (isset($types[$name])) {
+ $type = $types[$name];
+ list($value,) = $this->getBindingInfo($value, $type);
+ $resolvedParams[$name] = $value;
+ } else {
+ $resolvedParams[$name] = $value;
+ }
+ }
+ }
+
+ return $resolvedParams;
+ }
+
+ /**
* Create a new instance of a SQL query builder.
*
* @return \Doctrine\DBAL\Query\QueryBuilder
View
11 lib/Doctrine/DBAL/DBALException.php
@@ -36,6 +36,17 @@ public static function unknownDriver($unknownDriverName, array $knownDrivers)
"Doctrine currently supports only the following drivers: ".implode(", ", $knownDrivers));
}
+ public static function driverExceptionDuringQuery(\Exception $driverEx, $sql, array $params = array())
+ {
+ $msg = "An exception occurred while executing '".$sql."'";
+ if ($params) {
+ $msg .= " with params ".json_encode($params);
+ }
+ $msg .= ":\n\n".$driverEx->getMessage();
+
+ return new self($msg, 0, $driverEx);
+ }
+
public static function invalidWrapperClass($wrapperClass)
{
return new self("The given 'wrapperClass' ".$wrapperClass." has to be a ".
View
6 lib/Doctrine/DBAL/Statement.php
@@ -134,7 +134,11 @@ public function execute($params = null)
$logger->startQuery($this->sql, $this->params, $this->types);
}
- $stmt = $this->stmt->execute($params);
+ try {
+ $stmt = $this->stmt->execute($params);
+ } catch (\Exception $ex) {
+ throw DBALException::driverExceptionDuringQuery($ex, $this->sql, $this->conn->resolveParams($this->params, $this->types));
+ }
if ($logger) {
$logger->stopQuery();
View
29 tests/Doctrine/Tests/DBAL/ConnectionTest.php
@@ -123,6 +123,35 @@ public function testEventManagerPassedToPlatform()
}
/**
+ * @expectedException Doctrine\DBAL\DBALException
+ * @dataProvider getQueryMethods
+ */
+ public function testDriverExceptionIsWrapped($method)
+ {
+ $this->setExpectedException('Doctrine\DBAL\DBALException', "An exception occurred while executing 'MUUHAAAAHAAAA':
+
+SQLSTATE[HY000]: General error: 1 near \"MUUHAAAAHAAAA\"");
+
+ $con = \Doctrine\DBAL\DriverManager::getConnection(array(
+ 'driver' => 'pdo_sqlite',
+ 'memory' => true,
+ ));
+
+ $con->$method('MUUHAAAAHAAAA');
+ }
+
+ public function getQueryMethods()
+ {
+ return array(
+ array('exec'),
+ array('query'),
+ array('executeQuery'),
+ array('executeUpdate'),
+ array('prepare'),
+ );
+ }
+
+ /**
* Pretty dumb test, however we want to check that the EchoSQLLogger correctly implements the interface.
*
* @group DBAL-11
Please sign in to comment.
Something went wrong with that request. Please try again.