Commit faa3d22c authored by Benjamin Eberlei's avatar Benjamin Eberlei

Merge pull request #494 from deeky666/refactor-driver-exception-conversion

Refactor, consolidate and extend driver exception conversion
parents 6adc9ee1 0acd5335
......@@ -19,22 +19,11 @@
namespace Doctrine\DBAL;
use Doctrine\DBAL\Driver\DriverException;
use Doctrine\DBAL\Driver\ExceptionConverterDriver;
class DBALException extends \Exception
{
const ERROR_DUPLICATE_KEY = 1;
const ERROR_UNKNOWN_TABLE = 2;
const ERROR_TABLE_ALREADY_EXISTS = 3;
const ERROR_FOREIGN_KEY_CONSTRAINT = 4;
const ERROR_NOT_NULL = 5;
const ERROR_BAD_FIELD_NAME = 6;
const ERROR_NON_UNIQUE_FIELD_NAME = 7;
const ERROR_SYNTAX = 9;
const ERROR_UNABLE_TO_OPEN = 10;
const ERROR_WRITE_READONLY = 11;
const ERROR_ACCESS_DENIED = 12;
/**
* @param string $method
*
......@@ -103,11 +92,11 @@ class DBALException extends \Exception
}
$msg .= ":\n\n".$driverEx->getMessage();
$code = ($driver instanceof ExceptionConverterDriver)
? $driver->convertExceptionCode($driverEx)
: 0;
if ($driver instanceof ExceptionConverterDriver && $driverEx instanceof DriverException) {
return $driver->convertException($msg, $driverEx);
}
return self::createDriverException($msg, $code, $driverEx);
return new self($msg, 0, $driverEx);
}
/**
......@@ -120,61 +109,11 @@ class DBALException extends \Exception
{
$msg = "An exception occured in driver: " . $driverEx->getMessage();
$code = ($driver instanceof ExceptionConverterDriver)
? $driver->convertExceptionCode($driverEx)
: 0;
return self::createDriverException($msg, $code, $driverEx);
if ($driver instanceof ExceptionConverterDriver && $driverEx instanceof DriverException) {
return $driver->convertException($msg, $driverEx);
}
/**
* Factory method for subclasses of DBALException based on exception code.
*
* @param string $msg The driver error message.
* @param integer $code The DBAL driver error code. One of the DBALException::ERROR_* constants.
* @param \Exception $driverEx The underlying driver exception to wrap.
*
* @return \Doctrine\DBAL\DBALException
*/
private static function createDriverException($msg, $code, $driverEx)
{
switch ($code) {
case self::ERROR_NOT_NULL:
return new Exception\NotNullableException($msg, $code, $driverEx);
case self::ERROR_DUPLICATE_KEY:
return new Exception\DuplicateKeyException($msg, $code, $driverEx);
case self::ERROR_FOREIGN_KEY_CONSTRAINT:
return new Exception\ForeignKeyConstraintViolationException($msg, $code, $driverEx);
case self::ERROR_ACCESS_DENIED:
return new Exception\AccessDeniedException($msg, $code, $driverEx);
case self::ERROR_BAD_FIELD_NAME:
return new Exception\InvalidFieldNameException($msg, $code, $driverEx);
case self::ERROR_NON_UNIQUE_FIELD_NAME:
return new Exception\NonUniqueFieldNameException($msg, $code, $driverEx);
case self::ERROR_SYNTAX:
return new Exception\SyntaxErrorException($msg, $code, $driverEx);
case self::ERROR_TABLE_ALREADY_EXISTS:
return new Exception\TableExistsException($msg, $code, $driverEx);
case self::ERROR_UNABLE_TO_OPEN:
return new Exception\FailedToOpenException($msg, $code, $driverEx);
case self::ERROR_UNKNOWN_TABLE:
return new Exception\TableNotFoundException($msg, $code, $driverEx);
case self::ERROR_WRITE_READONLY:
return new Exception\ReadOnlyException($msg, $code, $driverEx);
default:
return new self($msg, $code, $driverEx);
}
return new self($msg, 0, $driverEx);
}
/**
......
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\DBAL\Driver;
/**
* Abstract base implementation of the {@link DriverException} interface.
*
* @author Steve Müller <st.mueller@dzh-online.de>
* @link www.doctrine-project.org
* @since 2.5
*/
abstract class AbstractDriverException extends \Exception implements DriverException
{
/**
* The driver specific error code.
*
* @var integer|string|null
*/
private $errorCode;
/**
* The SQLSTATE of the driver.
*
* @var string|null
*/
private $sqlState;
/**
* Constructor.
*
* @param string $message The driver error message.
* @param string|null $sqlState The SQLSTATE the driver is in at the time the error occured, if any.
* @param integer|string|null $errorCode The driver specific error code if any.
*/
public function __construct($message, $sqlState = null, $errorCode = null)
{
parent::__construct($message);
$this->errorCode = $errorCode;
$this->sqlState = $sqlState;
}
/**
* {@inheritdoc}
*/
public function getErrorCode()
{
return $this->errorCode;
}
/**
* {@inheritdoc}
*/
public function getSQLState()
{
return $this->sqlState;
}
}
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\DBAL\Driver;
/**
* Contract for a driver exception.
*
* Driver exceptions provide the SQLSTATE of the driver
* and the driver specific error code at the time the error occurred.
*
* @author Steve Müller <st.mueller@dzh-online.de>
* @link www.doctrine-project.org
* @since 2.5
*/
interface DriverException
{
/**
* Returns the driver specific error code if available.
*
* Returns null if no driver specific error code is available
* for the error raised by the driver.
*
* @return integer|string|null
*/
public function getErrorCode();
/**
* Returns the driver error message.
*
* @return string
*/
public function getMessage();
/**
* Returns the SQLSTATE the driver was in at the time the error occurred.
*
* Returns null if the driver does not provide a SQLSTATE for the error occurred.
*
* @return string|null
*/
public function getSQLState();
}
......@@ -19,8 +19,9 @@
namespace Doctrine\DBAL\Driver\DrizzlePDOMySql;
use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\Driver\DriverException;
use Doctrine\DBAL\Driver\ExceptionConverterDriver;
use Doctrine\DBAL\Exception;
use Doctrine\DBAL\Platforms\DrizzlePlatform;
use Doctrine\DBAL\Schema\DrizzleSchemaManager;
......@@ -42,6 +43,7 @@ class Driver implements \Doctrine\DBAL\Driver, ExceptionConverterDriver
$password,
$driverOptions
);
return $conn;
}
......@@ -107,41 +109,79 @@ class Driver implements \Doctrine\DBAL\Driver, ExceptionConverterDriver
/**
* {@inheritdoc}
*
* @link http://dev.mysql.com/doc/refman/5.7/en/error-messages-client.html
* @link http://dev.mysql.com/doc/refman/5.7/en/error-messages-server.html
*/
public function convertExceptionCode(\Exception $exception)
public function convertException($message, DriverException $exception)
{
switch ($exception->getCode()) {
case "42000":
return DBALException::ERROR_SYNTAX;
case "42S02":
return DBALException::ERROR_UNKNOWN_TABLE;
case "42S01":
return DBALException::ERROR_TABLE_ALREADY_EXISTS;
case "42S22":
return DBALException::ERROR_BAD_FIELD_NAME;
case "23000":
if (strpos($exception->getMessage(), 'Duplicate entry') !== false) {
return DBALException::ERROR_DUPLICATE_KEY;
}
if (strpos($exception->getMessage(), 'Cannot delete or update a parent row: a foreign key constraint fails') !== false) {
return DBALException::ERROR_FOREIGN_KEY_CONSTRAINT;
}
if (strpos($exception->getMessage(), ' cannot be null')) {
return DBALException::ERROR_NOT_NULL;
}
if (strpos($exception->getMessage(), 'in field list is ambiguous') !== false) {
return DBALException::ERROR_NON_UNIQUE_FIELD_NAME;
}
break;
}
return 0;
switch ($exception->getErrorCode()) {
case '1050':
return new Exception\TableExistsException($message, $exception);
case '1051':
case '1146':
return new Exception\TableNotFoundException($message, $exception);
case '1216':
case '1217':
case '1451':
case '1452':
return new Exception\ForeignKeyConstraintViolationException($message, $exception);
case '1062':
case '1557':
case '1569':
case '1586':
return new Exception\UniqueConstraintViolationException($message, $exception);
case '1054':
case '1166':
case '1611':
return new Exception\InvalidFieldNameException($message, $exception);
case '1052':
case '1060':
case '1110':
return new Exception\NonUniqueFieldNameException($message, $exception);
case '1064':
case '1149':
case '1287':
case '1341':
case '1342':
case '1343':
case '1344':
case '1382':
case '1479':
case '1541':
case '1554':
case '1626':
return new Exception\SyntaxErrorException($message, $exception);
case '1044':
case '1045':
case '1046':
case '1049':
case '1095':
case '1142':
case '1143':
case '1227':
case '1370':
case '2002':
case '2005':
return new Exception\ConnectionException($message, $exception);
case '1048':
case '1121':
case '1138':
case '1171':
case '1252':
case '1263':
case '1566':
return new Exception\NotNullConstraintViolationException($message, $exception);
}
return new Exception\DriverException($message, $exception);
}
}
......@@ -19,25 +19,26 @@
namespace Doctrine\DBAL\Driver;
use Exception;
/**
* Drivers marked as ExceptionConverters can convert to standardized codes.
* Contract for a driver that is capable of converting DBAL driver exceptions into standardized DBAL driver exceptions.
*
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @author Steve Müller <st.mueller@dzh-online.de>
* @link www.doctrine-project.org
* @since 2.5
*/
interface ExceptionConverterDriver
{
/**
* Method converts driver exceptions to standard error codes from
* {@see Doctrine\DBAL\DBALException}.
* Converts a given DBAL driver exception into a standardized DBAL driver exception.
*
* The DBALException error codes are returned from this method
* and the DBAL decides how to convert them into a common exception.
* It evaluates the vendor specific error code and SQLSTATE and transforms
* it into a unified {@link Doctrine\DBAL\Exception\DriverException} subclass.
*
* @param \Exception $exception
* @param string $message The DBAL exception message to use.
* @param \Doctrine\DBAL\Driver\DriverException $exception The DBAL driver exception to convert.
*
* @return int
* @return \Doctrine\DBAL\Exception\DriverException An instance of one of the DriverException subclasses.
*/
public function convertExceptionCode(Exception $exception);
public function convertException($message, DriverException $exception);
}
......@@ -23,6 +23,7 @@ use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Driver as DriverInterface;
use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\Driver\ExceptionConverterDriver;
use Doctrine\DBAL\Exception;
use Doctrine\DBAL\Platforms\MySqlPlatform;
/**
......@@ -82,37 +83,37 @@ class Driver implements DriverInterface, ExceptionConverterDriver
* @link http://dev.mysql.com/doc/refman/5.7/en/error-messages-client.html
* @link http://dev.mysql.com/doc/refman/5.7/en/error-messages-server.html
*/
public function convertExceptionCode(\Exception $exception)
public function convertException($message, DriverInterface\DriverException $exception)
{
switch ($exception->getCode()) {
switch ($exception->getErrorCode()) {
case '1050':
return DBALException::ERROR_TABLE_ALREADY_EXISTS;
return new Exception\TableExistsException($message, $exception);
case '1051':
case '1146':
return DBALException::ERROR_UNKNOWN_TABLE;
return new Exception\TableNotFoundException($message, $exception);
case '1216':
case '1217':
case '1451':
case '1452':
return DBALException::ERROR_FOREIGN_KEY_CONSTRAINT;
return new Exception\ForeignKeyConstraintViolationException($message, $exception);
case '1062':
case '1557':
case '1569':
case '1586':
return DBALException::ERROR_DUPLICATE_KEY;
return new Exception\UniqueConstraintViolationException($message, $exception);
case '1054':
case '1166':
case '1611':
return DBALException::ERROR_BAD_FIELD_NAME;
return new Exception\InvalidFieldNameException($message, $exception);
case '1052':
case '1060':
case '1110':
return DBALException::ERROR_NON_UNIQUE_FIELD_NAME;
return new Exception\NonUniqueFieldNameException($message, $exception);
case '1064':
case '1149':
......@@ -126,7 +127,7 @@ class Driver implements DriverInterface, ExceptionConverterDriver
case '1541':
case '1554':
case '1626':
return DBALException::ERROR_SYNTAX;
return new Exception\SyntaxErrorException($message, $exception);
case '1044':
case '1045':
......@@ -139,7 +140,7 @@ class Driver implements DriverInterface, ExceptionConverterDriver
case '1370':
case '2002':
case '2005':
return DBALException::ERROR_ACCESS_DENIED;
return new Exception\ConnectionException($message, $exception);
case '1048':
case '1121':
......@@ -148,9 +149,9 @@ class Driver implements DriverInterface, ExceptionConverterDriver
case '1252':
case '1263':
case '1566':
return DBALException::ERROR_NOT_NULL;
return new Exception\NotNullConstraintViolationException($message, $exception);
}
return 0;
return new Exception\DriverException($message, $exception);
}
}
......@@ -56,7 +56,7 @@ class MysqliConnection implements Connection, PingableConnection
if ( ! $this->_conn->real_connect($params['host'], $username, $password, $params['dbname'], $port, $socket)) {
set_error_handler($previousHandler);
throw new MysqliException($this->_conn->connect_error, $this->_conn->connect_errno);
throw new MysqliException($this->_conn->connect_error, $this->_conn->sqlstate, $this->_conn->connect_errno);
}
set_error_handler($previousHandler);
......@@ -205,7 +205,8 @@ class MysqliConnection implements Connection, PingableConnection
throw new MysqliException(
$msg,
mysqli_errno($this->_conn)
$this->_conn->sqlstate,
$this->_conn->errno
);
}
}
......
......@@ -19,11 +19,14 @@
namespace Doctrine\DBAL\Driver\Mysqli;
use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\Driver\AbstractDriverException;
/**
* Exception thrown in case the mysqli driver errors.
*
* @author Kim Hemsø Rasmussen <kimhemsoe@gmail.com>
* @author Steve Müller <st.mueller@dzh-online.de>
*/
class MysqliException extends DBALException
class MysqliException extends AbstractDriverException
{
}
......@@ -91,7 +91,7 @@ class MysqliStatement implements \IteratorAggregate, Statement
$this->_conn = $conn;
$this->_stmt = $conn->prepare($prepareString);
if (false === $this->_stmt) {
throw new MysqliException($this->_conn->error, $this->_conn->errno);
throw new MysqliException($this->_conn->error, $this->_conn->sqlstate, $this->_conn->errno);
}
$paramCount = $this->_stmt->param_count;
......@@ -156,13 +156,13 @@ class MysqliStatement implements \IteratorAggregate, Statement
}
} else {
if (!call_user_func_array(array($this->_stmt, 'bind_param'), array($this->types) + $this->_bindedValues)) {
throw new MysqliException($this->_stmt->error, $this->_stmt->errno);
throw new MysqliException($this->_stmt->error, $this->_stmt->sqlstate, $this->_stmt->errno);
}
}
}
if ( ! $this->_stmt->execute()) {
throw new MysqliException($this->_stmt->error, $this->_stmt->errno);
throw new MysqliException($this->_stmt->error, $this->_stmt->sqlstate, $this->_stmt->errno);
}
if (null === $this->_columnNames) {
......@@ -186,7 +186,7 @@ class MysqliStatement implements \IteratorAggregate, Statement
}
if (!call_user_func_array(array($this->_stmt, 'bind_result'), $refs)) {
throw new MysqliException($this->_stmt->error, $this->_stmt->errno);
throw new MysqliException($this->_stmt->error, $this->_stmt->sqlstate, $this->_stmt->errno);
}
} else {
$this->_columnNames = false;
......@@ -245,7 +245,7 @@ class MysqliStatement implements \IteratorAggregate, Statement
}
if (false === $values) {
throw new MysqliException($this->_stmt->error, $this->_stmt->errno);
throw new MysqliException($this->_stmt->error, $this->_stmt->sqlstate, $this->_stmt->errno);
}
$fetchMode = $fetchMode ?: $this->_defaultFetchMode;
......
......@@ -21,7 +21,9 @@ namespace Doctrine\DBAL\Driver\OCI8;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\Driver\DriverException;
use Doctrine\DBAL\Driver\ExceptionConverterDriver;
use Doctrine\DBAL\Exception;
use Doctrine\DBAL\Platforms\OraclePlatform;
use Doctrine\DBAL\Schema\OracleSchemaManager;
......@@ -134,41 +136,41 @@ class Driver implements \Doctrine\DBAL\Driver, ExceptionConverterDriver
/**
* {@inheritdoc}
*/
public function convertExceptionCode(\Exception $exception)
public function convertException($message, DriverException $exception)
{
switch ($exception->getCode()) {
switch ($exception->getErrorCode()) {
case '1':
case '2299':
case '38911':
return DBALException::ERROR_DUPLICATE_KEY;
return new Exception\UniqueConstraintViolationException($message, $exception);
case '904':
return DBALException::ERROR_BAD_FIELD_NAME;
return new Exception\InvalidFieldNameException($message, $exception);
case '918':
case '960':
return DBALException::ERROR_NON_UNIQUE_FIELD_NAME;
return new Exception\NonUniqueFieldNameException($message, $exception);
case '923':
return DBALException::ERROR_SYNTAX;
return new Exception\SyntaxErrorException($message, $exception);
case '942':
return DBALException::ERROR_UNKNOWN_TABLE;
return new Exception\TableNotFoundException($message, $exception);
case '955':
return DBALException::ERROR_TABLE_ALREADY_EXISTS;
return new Exception\TableExistsException($message, $exception);
case '1017':
case '12545':
return DBALException::ERROR_ACCESS_DENIED;
return new Exception\ConnectionException($message, $exception);
case '1400':
return DBALException::ERROR_NOT_NULL;
return new Exception\NotNullConstraintViolationException($message, $exception);
case '2292':
return DBALException::ERROR_FOREIGN_KEY_CONSTRAINT;
return new Exception\ForeignKeyConstraintViolationException($message, $exception);
}
return 0;
return new Exception\DriverException($message, $exception);
}
}
......@@ -19,15 +19,17 @@
namespace Doctrine\DBAL\Driver\OCI8;
class OCI8Exception extends \Exception
use Doctrine\DBAL\Driver\AbstractDriverException;
class OCI8Exception extends AbstractDriverException
{
/**
* @param array $error
*
* @return \Doctrine\DBAL\Driver\OCI8\OCI8Exception
*/
static public function fromErrorInfo($error)
public static function fromErrorInfo($error)
{
return new self($error['message'], $error['code']);
return new self($error['message'], null, $error['code']);
}
}
......@@ -34,12 +34,18 @@ class PDOConnection extends PDO implements Connection
* @param string|null $user
* @param string|null $password
* @param array|null $options
*
* @throws PDOException in case of an error.
*/
public function __construct($dsn, $user = null, $password = null, array $options = null)
{
try {
parent::__construct($dsn, $user, $password, $options);
$this->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('Doctrine\DBAL\Driver\PDOStatement', array()));
$this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (\PDOException $exception) {
throw new PDOException($exception);
}
}
/**
......@@ -47,7 +53,11 @@ class PDOConnection extends PDO implements Connection
*/
public function prepare($prepareString, $driverOptions = array())
{
try {
return parent::prepare($prepareString, $driverOptions);
} catch (\PDOException $exception) {
throw new PDOException($exception);
}
}
/**
......@@ -58,6 +68,7 @@ class PDOConnection extends PDO implements Connection
$args = func_get_args();
$argsCount = count($args);
try {
if ($argsCount == 4) {
return parent::query($args[0], $args[1], $args[2], $args[3]);
}
......@@ -71,6 +82,9 @@ class PDOConnection extends PDO implements Connection
}
return parent::query($args[0]);
} catch (\PDOException $exception) {
throw new PDOException($exception);
}
}
/**
......@@ -78,7 +92,11 @@ class PDOConnection extends PDO implements Connection
*/
public function quote($input, $type = \PDO::PARAM_STR)
{
try {
return parent::quote($input, $type);
} catch (\PDOException $exception) {
throw new PDOException($exception);
}
}
/**
......@@ -86,6 +104,10 @@ class PDOConnection extends PDO implements Connection
*/
public function lastInsertId($name = null)
{
try {
return parent::lastInsertId($name);
} catch (\PDOException $exception) {
throw new PDOException($exception);
}
}
}
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\DBAL\Driver;
/**
* Tiny wrapper for PDOException instances to implement the {@link DriverException} interface.
*
* @author Steve Müller <st.mueller@dzh-online.de>
* @link www.doctrine-project.org
* @since 2.5
*/
class PDOException extends \PDOException implements DriverException
{
/**
* The driver specific error code.
*
* @var integer|string|null
*/
private $errorCode;
/**
* The SQLSTATE of the driver.
*
* @var string|null
*/
private $sqlState;
/**
* Constructor.
*
* @param \PDOException $exception The PDO exception to wrap.
*/
public function __construct(\PDOException $exception)
{
parent::__construct($exception->getMessage(), 0, $exception->getPrevious());
$this->errorCode = isset($exception->errorInfo[1]) ? $exception->errorInfo[1] : $exception->getCode();
$this->sqlState = isset($exception->errorInfo[0]) ? $exception->errorInfo[0] : $exception->getCode();
}
/**
* {@inheritdoc}
*/
public function getErrorCode()
{
return $this->errorCode;
}
/**
* {@inheritdoc}
*/
public function getSQLState()
{
return $this->sqlState;
}
}
......@@ -21,8 +21,10 @@ namespace Doctrine\DBAL\Driver\PDOMySql;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\Driver\DriverException;
use Doctrine\DBAL\Driver\ExceptionConverterDriver;
use Doctrine\DBAL\Driver\PDOConnection;
use Doctrine\DBAL\Exception;
use Doctrine\DBAL\Platforms\MySqlPlatform;
use Doctrine\DBAL\Schema\MySqlSchemaManager;
use PDOException;
......@@ -125,44 +127,37 @@ class Driver implements \Doctrine\DBAL\Driver, ExceptionConverterDriver
* @link http://dev.mysql.com/doc/refman/5.7/en/error-messages-client.html
* @link http://dev.mysql.com/doc/refman/5.7/en/error-messages-server.html
*/
public function convertExceptionCode(\Exception $exception)
public function convertException($message, DriverException $exception)
{
$errorCode = $exception->getCode();
// Use driver-specific error code instead of SQLSTATE for PDO exceptions if available.
if ($exception instanceof \PDOException && null !== $exception->errorInfo[1]) {
$errorCode = $exception->errorInfo[1];
}
switch ($errorCode) {
switch ($exception->getErrorCode()) {
case '1050':
return DBALException::ERROR_TABLE_ALREADY_EXISTS;
return new Exception\TableExistsException($message, $exception);
case '1051':
case '1146':
return DBALException::ERROR_UNKNOWN_TABLE;
return new Exception\TableNotFoundException($message, $exception);
case '1216':
case '1217':
case '1451':
case '1452':
return DBALException::ERROR_FOREIGN_KEY_CONSTRAINT;
return new Exception\ForeignKeyConstraintViolationException($message, $exception);
case '1062':
case '1557':
case '1569':
case '1586':
return DBALException::ERROR_DUPLICATE_KEY;
return new Exception\UniqueConstraintViolationException($message, $exception);
case '1054':
case '1166':
case '1611':
return DBALException::ERROR_BAD_FIELD_NAME;
return new Exception\InvalidFieldNameException($message, $exception);
case '1052':
case '1060':
case '1110':
return DBALException::ERROR_NON_UNIQUE_FIELD_NAME;
return new Exception\NonUniqueFieldNameException($message, $exception);
case '1064':
case '1149':
......@@ -176,7 +171,7 @@ class Driver implements \Doctrine\DBAL\Driver, ExceptionConverterDriver
case '1541':
case '1554':
case '1626':
return DBALException::ERROR_SYNTAX;
return new Exception\SyntaxErrorException($message, $exception);
case '1044':
case '1045':
......@@ -189,7 +184,7 @@ class Driver implements \Doctrine\DBAL\Driver, ExceptionConverterDriver
case '1370':
case '2002':
case '2005':
return DBALException::ERROR_ACCESS_DENIED;
return new Exception\ConnectionException($message, $exception);
case '1048':
case '1121':
......@@ -198,9 +193,9 @@ class Driver implements \Doctrine\DBAL\Driver, ExceptionConverterDriver
case '1252':
case '1263':
case '1566':
return DBALException::ERROR_NOT_NULL;
return new Exception\NotNullConstraintViolationException($message, $exception);
}
return 0;
return new Exception\DriverException($message, $exception);
}
}
......@@ -21,8 +21,10 @@ namespace Doctrine\DBAL\Driver\PDOOracle;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\Driver\DriverException;
use Doctrine\DBAL\Driver\ExceptionConverterDriver;
use Doctrine\DBAL\Driver\PDOConnection;
use Doctrine\DBAL\Exception;
use Doctrine\DBAL\Platforms\OraclePlatform;
use Doctrine\DBAL\Schema\OracleSchemaManager;
......@@ -140,48 +142,41 @@ class Driver implements \Doctrine\DBAL\Driver, ExceptionConverterDriver
/**
* {@inheritdoc}
*/
public function convertExceptionCode(\Exception $exception)
public function convertException($message, DriverException $exception)
{
$errorCode = $exception->getCode();
// Use driver-specific error code instead of SQLSTATE for PDO exceptions if available.
if ($exception instanceof \PDOException && null !== $exception->errorInfo[1]) {
$errorCode = $exception->errorInfo[1];
}
switch ($errorCode) {
switch ($exception->getErrorCode()) {
case '1':
case '2299':
case '38911':
return DBALException::ERROR_DUPLICATE_KEY;
return new Exception\UniqueConstraintViolationException($message, $exception);
case '904':
return DBALException::ERROR_BAD_FIELD_NAME;
return new Exception\InvalidFieldNameException($message, $exception);
case '918':
case '960':
return DBALException::ERROR_NON_UNIQUE_FIELD_NAME;
return new Exception\NonUniqueFieldNameException($message, $exception);
case '923':
return DBALException::ERROR_SYNTAX;
return new Exception\SyntaxErrorException($message, $exception);
case '942':
return DBALException::ERROR_UNKNOWN_TABLE;
return new Exception\TableNotFoundException($message, $exception);
case '955':
return DBALException::ERROR_TABLE_ALREADY_EXISTS;
return new Exception\TableExistsException($message, $exception);
case '1017':
case '12545':
return DBALException::ERROR_ACCESS_DENIED;
return new Exception\ConnectionException($message, $exception);
case '1400':
return DBALException::ERROR_NOT_NULL;
return new Exception\NotNullConstraintViolationException($message, $exception);
case '2292':
return DBALException::ERROR_FOREIGN_KEY_CONSTRAINT;
return new Exception\ForeignKeyConstraintViolationException($message, $exception);
}
return 0;
return new Exception\DriverException($message, $exception);
}
}
......@@ -20,7 +20,9 @@
namespace Doctrine\DBAL\Driver\PDOPgSql;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Driver\DriverException;
use Doctrine\DBAL\Driver\PDOConnection;
use Doctrine\DBAL\Exception;
use Doctrine\DBAL\Platforms\PostgreSqlPlatform;
use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\Schema\PostgreSqlSchemaManager;
......@@ -126,43 +128,43 @@ class Driver implements \Doctrine\DBAL\Driver, ExceptionConverterDriver
*
* @link http://www.postgresql.org/docs/9.3/static/errcodes-appendix.html
*/
public function convertExceptionCode(\Exception $exception)
public function convertException($message, DriverException $exception)
{
switch ($exception->getCode()) {
switch ($exception->getSQLState()) {
case '23502':
return DBALException::ERROR_NOT_NULL;
return new Exception\NotNullConstraintViolationException($message, $exception);
case '23503':
return DBALException::ERROR_FOREIGN_KEY_CONSTRAINT;
return new Exception\ForeignKeyConstraintViolationException($message, $exception);
case '23505':
return DBALException::ERROR_DUPLICATE_KEY;
return new Exception\UniqueConstraintViolationException($message, $exception);
case '42601':
return DBALException::ERROR_SYNTAX;
return new Exception\SyntaxErrorException($message, $exception);
case '42702':
return DBALException::ERROR_NON_UNIQUE_FIELD_NAME;
return new Exception\NonUniqueFieldNameException($message, $exception);
case '42703':
return DBALException::ERROR_BAD_FIELD_NAME;
return new Exception\InvalidFieldNameException($message, $exception);
case '42P01':
return DBALException::ERROR_UNKNOWN_TABLE;
return new Exception\TableNotFoundException($message, $exception);
case '42P07':
return DBALException::ERROR_TABLE_ALREADY_EXISTS;
return new Exception\TableExistsException($message, $exception);
case '7':
// In some case (mainly connection errors) the PDO exception does not provide a SQLSTATE via its code.
// The exception code is always set to 7 here.
// We have to match against the SQLSTATE in the error message in these cases.
if (strpos($exception->getMessage(), 'SQLSTATE[08006]') !== false) {
return DBALException::ERROR_ACCESS_DENIED;
return new Exception\ConnectionException($message, $exception);
}
break;
}
return 0;
return new Exception\DriverException($message, $exception);
}
}
......@@ -21,8 +21,10 @@ namespace Doctrine\DBAL\Driver\PDOSqlite;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\Driver\DriverException;
use Doctrine\DBAL\Driver\ExceptionConverterDriver;
use Doctrine\DBAL\Driver\PDOConnection;
use Doctrine\DBAL\Exception;
use Doctrine\DBAL\Platforms\SqlitePlatform;
use Doctrine\DBAL\Schema\SqliteSchemaManager;
use PDOException;
......@@ -130,48 +132,48 @@ class Driver implements \Doctrine\DBAL\Driver, ExceptionConverterDriver
*
* @link http://www.sqlite.org/c3ref/c_abort.html
*/
public function convertExceptionCode(\Exception $exception)
public function convertException($message, DriverException $exception)
{
if (strpos($exception->getMessage(), 'must be unique') !== false) {
return DBALException::ERROR_DUPLICATE_KEY;
return new Exception\UniqueConstraintViolationException($message, $exception);
}
if (strpos($exception->getMessage(), 'may not be NULL') !== false) {
return DBALException::ERROR_NOT_NULL;
return new Exception\NotNullConstraintViolationException($message, $exception);
}
if (strpos($exception->getMessage(), 'is not unique') !== false) {
return DBALException::ERROR_DUPLICATE_KEY;
return new Exception\UniqueConstraintViolationException($message, $exception);
}
if (strpos($exception->getMessage(), 'no such table:') !== false) {
return DBALException::ERROR_UNKNOWN_TABLE;
return new Exception\TableNotFoundException($message, $exception);
}
if (strpos($exception->getMessage(), 'already exists') !== false) {
return DBALException::ERROR_TABLE_ALREADY_EXISTS;
return new Exception\TableExistsException($message, $exception);
}
if (strpos($exception->getMessage(), 'has no column named') !== false) {
return DBALException::ERROR_BAD_FIELD_NAME;
return new Exception\InvalidFieldNameException($message, $exception);
}
if (strpos($exception->getMessage(), 'ambiguous column name') !== false) {
return DBALException::ERROR_NON_UNIQUE_FIELD_NAME;
return new Exception\NonUniqueFieldNameException($message, $exception);
}
if (strpos($exception->getMessage(), 'syntax error') !== false) {
return DBALException::ERROR_SYNTAX;
return new Exception\SyntaxErrorException($message, $exception);
}
if (strpos($exception->getMessage(), 'attempt to write a readonly database') !== false) {
return DBALException::ERROR_WRITE_READONLY;
return new Exception\ReadOnlyException($message, $exception);
}
if (strpos($exception->getMessage(), 'unable to open database file') !== false) {
return DBALException::ERROR_UNABLE_TO_OPEN;
return new Exception\ConnectionException($message, $exception);
}
return 0;
return new Exception\DriverException($message, $exception);
}
}
......@@ -43,6 +43,7 @@ class PDOStatement extends \PDOStatement implements Statement
// of PDOStatement::setFetchMode(): even if the second and third
// parameters are optional, PHP will not let us remove it from this
// declaration.
try {
if ($arg2 === null && $arg3 === null) {
return parent::setFetchMode($fetchMode);
}
......@@ -52,6 +53,9 @@ class PDOStatement extends \PDOStatement implements Statement
}
return parent::setFetchMode($fetchMode, $arg2, $arg3);
} catch (\PDOException $exception) {
throw new PDOException($exception);
}
}
/**
......@@ -59,7 +63,11 @@ class PDOStatement extends \PDOStatement implements Statement
*/
public function bindValue($param, $value, $type = \PDO::PARAM_STR)
{
try {
return parent::bindValue($param, $value, $type);
} catch (\PDOException $exception) {
throw new PDOException($exception);
}
}
/**
......@@ -67,7 +75,11 @@ class PDOStatement extends \PDOStatement implements Statement
*/
public function bindParam($column, &$variable, $type = \PDO::PARAM_STR, $length = null, $driverOptions = null)
{
try {
return parent::bindParam($column, $variable, $type, $length, $driverOptions);
} catch (\PDOException $exception) {
throw new PDOException($exception);
}
}
/**
......@@ -75,7 +87,11 @@ class PDOStatement extends \PDOStatement implements Statement
*/
public function execute($params = null)
{
try {
return parent::execute($params);
} catch (\PDOException $exception) {
throw new PDOException($exception);
}
}
/**
......@@ -83,6 +99,7 @@ class PDOStatement extends \PDOStatement implements Statement
*/
public function fetch($fetchMode = null, $cursorOrientation = null, $cursorOffset = null)
{
try {
if ($fetchMode === null && $cursorOrientation === null && $cursorOffset === null) {
return parent::fetch();
}
......@@ -96,6 +113,9 @@ class PDOStatement extends \PDOStatement implements Statement
}
return parent::fetch($fetchMode, $cursorOrientation, $cursorOffset);
} catch (\PDOException $exception) {
throw new PDOException($exception);
}
}
/**
......@@ -103,6 +123,7 @@ class PDOStatement extends \PDOStatement implements Statement
*/
public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null)
{
try {
if ($fetchMode === null && $fetchArgument === null && $ctorArgs === null) {
return parent::fetchAll();
}
......@@ -116,6 +137,9 @@ class PDOStatement extends \PDOStatement implements Statement
}
return parent::fetchAll($fetchMode, $fetchArgument, $ctorArgs);
} catch (\PDOException $exception) {
throw new PDOException($exception);
}
}
/**
......@@ -123,6 +147,10 @@ class PDOStatement extends \PDOStatement implements Statement
*/
public function fetchColumn($columnIndex = 0)
{
try {
return parent::fetchColumn($columnIndex);
} catch (\PDOException $exception) {
throw new PDOException($exception);
}
}
}
......@@ -21,7 +21,9 @@ namespace Doctrine\DBAL\Driver\SQLAnywhere;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\Driver\DriverException;
use Doctrine\DBAL\Driver\ExceptionConverterDriver;
use Doctrine\DBAL\Exception;
use Doctrine\DBAL\Platforms\SQLAnywhere12Platform;
use Doctrine\DBAL\Schema\SQLAnywhereSchemaManager;
......@@ -77,35 +79,35 @@ class Driver implements \Doctrine\DBAL\Driver, ExceptionConverterDriver
*
* @link http://dcx.sybase.com/index.html#sa160/en/saerrors/sqlerror.html
*/
public function convertExceptionCode(\Exception $exception)
public function convertException($message, DriverException $exception)
{
switch ($exception->getCode()) {
switch ($exception->getErrorCode()) {
case '-100':
case '-103':
case '-832':
return DBALException::ERROR_ACCESS_DENIED;
return new Exception\ConnectionException($message, $exception);
case '-143':
return DBALException::ERROR_BAD_FIELD_NAME;
return new Exception\InvalidFieldNameException($message, $exception);
case '-193':
case '-196':
return DBALException::ERROR_DUPLICATE_KEY;
return new Exception\UniqueConstraintViolationException($message, $exception);
case '-198':
return DBALException::ERROR_FOREIGN_KEY_CONSTRAINT;
return new Exception\ForeignKeyConstraintViolationException($message, $exception);
case '-144':
return DBALException::ERROR_NON_UNIQUE_FIELD_NAME;
return new Exception\NonUniqueFieldNameException($message, $exception);
case '-184':
case '-195':
return DBALException::ERROR_NOT_NULL;
return new Exception\NotNullConstraintViolationException($message, $exception);
case '-131':
return DBALException::ERROR_SYNTAX;
return new Exception\SyntaxErrorException($message, $exception);
case '-110':
return DBALException::ERROR_TABLE_ALREADY_EXISTS;
return new Exception\TableExistsException($message, $exception);
case '-141':
case '-1041':
return DBALException::ERROR_UNKNOWN_TABLE;
return new Exception\TableNotFoundException($message, $exception);
}
return 0;
return new Exception\DriverException($message, $exception);
}
/**
......
......@@ -19,7 +19,7 @@
namespace Doctrine\DBAL\Driver\SQLAnywhere;
use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\Driver\AbstractDriverException;
/**
* SAP Sybase SQL Anywhere driver exception.
......@@ -28,7 +28,7 @@ use Doctrine\DBAL\DBALException;
* @link www.doctrine-project.org
* @since 2.5
*/
class SQLAnywhereException extends DBALException
class SQLAnywhereException extends AbstractDriverException
{
/**
* Helper method to turn SQL Anywhere error into exception.
......@@ -86,9 +86,9 @@ class SQLAnywhereException extends DBALException
}
if ($message) {
return new self('SQLSTATE [' . $state . '] [' . $code . '] ' . $message, $code);
return new self('SQLSTATE [' . $state . '] [' . $code . '] ' . $message, $state, $code);
}
return new self('SQL Anywhere error occurred but no error message was retrieved from driver.', $code);
return new self('SQL Anywhere error occurred but no error message was retrieved from driver.', $state, $code);
}
}
......@@ -19,15 +19,13 @@
namespace Doctrine\DBAL\Exception;
use Doctrine\DBAL\DBALException;
/**
* Thrown when {@link DBALException::ERROR_ACCESS_DENIED} is detected in driver.
* Base class for all connection related errors detected in the driver.
*
* @author Steve Müller <st.mueller@dzh-online.de>
* @link www.doctrine-project.org
* @since 2.5
*/
class AccessDeniedException extends DBALException
class ConnectionException extends DriverException
{
}
......@@ -19,15 +19,13 @@
namespace Doctrine\DBAL\Exception;
use Doctrine\DBAL\DBALException;
/**
* Thrown when {@link DBALException::ERROR_UNABLE_TO_OPEN} is detected in driver.
* Base class for all constraint violation related errors detected in the driver.
*
* @author Steve Müller <st.mueller@dzh-online.de>
* @link www.doctrine-project.org
* @since 2.5
*/
class FailedToOpenException extends DBALException
class ConstraintViolationException extends ServerException
{
}
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\DBAL\Exception;
/**
* Base class for all already existing database object related errors detected in the driver.
*
* A database object is considered any asset that can be created in a database
* such as schemas, tables, views, sequences, triggers, constraints, indexes,
* functions, stored procedures etc.
*
* @author Steve Müller <st.mueller@dzh-online.de>
* @link www.doctrine-project.org
* @since 2.5
*/
class DatabaseObjectExistsException extends ServerException
{
}
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\DBAL\Exception;
/**
* Base class for all unknown database object related errors detected in the driver.
*
* A database object is considered any asset that can be created in a database
* such as schemas, tables, views, sequences, triggers, constraints, indexes,
* functions, stored procedures etc.
*
* @author Steve Müller <st.mueller@dzh-online.de>
* @link www.doctrine-project.org
* @since 2.5
*/
class DatabaseObjectNotFoundException extends ServerException
{
}
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\DBAL\Exception;
use Doctrine\DBAL\DBALException;
/**
* Base class for all errors detected in the driver.
*
* @author Steve Müller <st.mueller@dzh-online.de>
* @link www.doctrine-project.org
* @since 2.5
*/
class DriverException extends DBALException
{
/**
* The previous DBAL driver exception.
*
* @var \Doctrine\DBAL\Driver\DriverException
*/
private $driverException;
/**
* Constructor.
*
* @param string $message The exception message.
* @param \Doctrine\DBAL\Driver\DriverException $driverException The DBAL driver exception to chain.
*/
public function __construct($message, \Doctrine\DBAL\Driver\DriverException $driverException)
{
$exception = null;
if ($driverException instanceof \Exception) {
$exception = $driverException;
}
parent::__construct($message, 0, $exception);
$this->driverException = $driverException;
}
/**
* Returns the driver specific error code if given.
*
* Returns null if no error code was given by the driver.
*
* @return integer|string|null
*/
public function getErrorCode()
{
return $this->driverException->getErrorCode();
}
/**
* Returns the SQLSTATE the driver was in at the time the error occurred, if given.
*
* Returns null if no SQLSTATE was given by the driver.
*
* @return string|null
*/
public function getSQLState()
{
return $this->driverException->getSQLState();
}
}
......@@ -19,13 +19,14 @@
namespace Doctrine\DBAL\Exception;
use Doctrine\DBAL\DBALException;
/**
* Thrown when {@link DBALException::ERROR_FOREIGN_KEY_CONSTRAINT} is detected in driver
* Exception for a foreign key constraint violation detected in the driver.
*
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @author Steve Müller <st.mueller@dzh-online.de>
* @link www.doctrine-project.org
* @since 2.5
*/
class ForeignKeyConstraintViolationException extends DBALException
class ForeignKeyConstraintViolationException extends ConstraintViolationException
{
}
......@@ -19,15 +19,13 @@
namespace Doctrine\DBAL\Exception;
use Doctrine\DBAL\DBALException;
/**
* Thrown when {@link DBALException::ERROR_BAD_FIELD_NAME} is detected in driver.
* Exception for an invalid specified field name in a statement detected in the driver.
*
* @author Steve Müller <st.mueller@dzh-online.de>
* @link www.doctrine-project.org
* @since 2.5
*/
class InvalidFieldNameException extends DBALException
class InvalidFieldNameException extends ServerException
{
}
......@@ -19,15 +19,13 @@
namespace Doctrine\DBAL\Exception;
use Doctrine\DBAL\DBALException;
/**
* Thrown when {@link DBALException::ERROR_NON_UNIQUE_FIELD_NAME} is detected in driver.
* Exception for a non-unique/ambiguous specified field name in a statement detected in the driver.
*
* @author Steve Müller <st.mueller@dzh-online.de>
* @link www.doctrine-project.org
* @since 2.5
*/
class NonUniqueFieldNameException extends DBALException
class NonUniqueFieldNameException extends ServerException
{
}
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\DBAL\Exception;
/**
* Exception for a NOT NULL constraint violation detected in the driver.
*
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @author Steve Müller <st.mueller@dzh-online.de>
* @link www.doctrine-project.org
* @since 2.5
*/
class NotNullConstraintViolationException extends ConstraintViolationException
{
}
......@@ -19,15 +19,13 @@
namespace Doctrine\DBAL\Exception;
use Doctrine\DBAL\DBALException;
/**
* Thrown when {@link DBALException::ERROR_WRITE_READONLY} is detected in driver.
* Exception for a write operation attempt on a read-only database element detected in the driver.
*
* @author Steve Müller <st.mueller@dzh-online.de>
* @link www.doctrine-project.org
* @since 2.5
*/
class ReadOnlyException extends DBALException
class ReadOnlyException extends ServerException
{
}
......@@ -19,13 +19,13 @@
namespace Doctrine\DBAL\Exception;
use Doctrine\DBAL\DBALException;
/**
* Thrown when {@link DBALException::ERROR_DUPLICATE_KEY} is detected in driver
* Base class for all server related errors detected in the driver.
*
* @author Steve Müller <st.mueller@dzh-online.de>
* @link www.doctrine-project.org
* @since 2.5
*/
class DuplicateKeyException extends DBALException
class ServerException extends DriverException
{
}
......@@ -19,15 +19,13 @@
namespace Doctrine\DBAL\Exception;
use Doctrine\DBAL\DBALException;
/**
* Thrown when {@link DBALException::ERROR_SYNTAX} is detected in driver.
* Exception for a syntax error in a statement detected in the driver.
*
* @author Steve Müller <st.mueller@dzh-online.de>
* @link www.doctrine-project.org
* @since 2.5
*/
class SyntaxErrorException extends DBALException
class SyntaxErrorException extends ServerException
{
}
......@@ -19,15 +19,13 @@
namespace Doctrine\DBAL\Exception;
use Doctrine\DBAL\DBALException;
/**
* Thrown when {@link DBALException::ERROR_TABLE_ALREADY_EXISTS} is detected in driver.
* Exception for an already existing table referenced in a statement detected in the driver.
*
* @author Steve Müller <st.mueller@dzh-online.de>
* @link www.doctrine-project.org
* @since 2.5
*/
class TableExistsException extends DBALException
class TableExistsException extends DatabaseObjectExistsException
{
}
......@@ -19,15 +19,13 @@
namespace Doctrine\DBAL\Exception;
use Doctrine\DBAL\DBALException;
/**
* Thrown when {@link DBALException::ERROR_UNKNOWN_TABLE} is detected in driver.
* Exception for an unknown table referenced in a statement detected in the driver.
*
* @author Steve Müller <st.mueller@dzh-online.de>
* @link www.doctrine-project.org
* @since 2.5
*/
class TableNotFoundException extends DBALException
class TableNotFoundException extends DatabaseObjectNotFoundException
{
}
......@@ -19,13 +19,14 @@
namespace Doctrine\DBAL\Exception;
use Doctrine\DBAL\DBALException;
/**
* Thrown when {@link DBALException::ERROR_NOT_NULL} is detected in driver
* Exception for a unique constraint violation detected in the driver.
*
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @author Steve Müller <st.mueller@dzh-online.de>
* @link www.doctrine-project.org
* @since 2.5
*/
class NotNullableException extends DBALException
class UniqueConstraintViolationException extends ConstraintViolationException
{
}
......@@ -15,7 +15,7 @@ class ExceptionTest extends \Doctrine\Tests\DbalFunctionalTestCase
}
}
public function testDuplicateKeyException()
public function testPrimaryConstraintViolationException()
{
$table = new \Doctrine\DBAL\Schema\Table("duplicatekey_table");
$table->addColumn('id', 'integer', array());
......@@ -27,25 +27,26 @@ class ExceptionTest extends \Doctrine\Tests\DbalFunctionalTestCase
$this->_conn->insert("duplicatekey_table", array('id' => 1));
$this->setExpectedException('\Doctrine\DBAL\Exception\DuplicateKeyException', null, DBALException::ERROR_DUPLICATE_KEY);
$this->setExpectedException(
'\Doctrine\DBAL\Exception\UniqueConstraintViolationException');
$this->_conn->insert("duplicatekey_table", array('id' => 1));
}
public function testUnknownTableException()
public function testTableNotFoundException()
{
$sql = "SELECT * FROM unknown_table";
$this->setExpectedException('\Doctrine\DBAL\Exception\TableNotFoundException', null, DBALException::ERROR_UNKNOWN_TABLE);
$this->setExpectedException('\Doctrine\DBAL\Exception\TableNotFoundException');
$this->_conn->executeQuery($sql);
}
public function testTableAlreadyExistsException()
public function testTableExistsException()
{
$table = new \Doctrine\DBAL\Schema\Table("alreadyexist_table");
$table->addColumn('id', 'integer', array());
$table->setPrimaryKey(array('id'));
$this->setExpectedException('\Doctrine\DBAL\Exception\TableExistsException', null, DBALException::ERROR_TABLE_ALREADY_EXISTS);
$this->setExpectedException('\Doctrine\DBAL\Exception\TableExistsException');
foreach ($this->_conn->getDatabasePlatform()->getCreateTableSQL($table) AS $sql) {
$this->_conn->executeQuery($sql);
}
......@@ -54,7 +55,7 @@ class ExceptionTest extends \Doctrine\Tests\DbalFunctionalTestCase
}
}
public function testForeignKeyContraintException()
public function testForeignKeyContraintViolationException()
{
if ( ! $this->_conn->getDatabasePlatform()->supportsForeignKeyConstraints()) {
$this->markTestSkipped("Only fails on platforms with foreign key constraints.");
......@@ -79,11 +80,11 @@ class ExceptionTest extends \Doctrine\Tests\DbalFunctionalTestCase
$this->_conn->insert("constraint_error_table", array('id' => 1));
$this->_conn->insert("owning_table", array('id' => 1, 'constraint_id' => 1));
$this->setExpectedException('\Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException', null, DBALException::ERROR_FOREIGN_KEY_CONSTRAINT);
$this->setExpectedException('\Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException');
$this->_conn->delete('constraint_error_table', array('id' => 1));
}
public function testNotNullException()
public function testNotNullConstraintViolationException()
{
$schema = new \Doctrine\DBAL\Schema\Schema();
......@@ -96,11 +97,11 @@ class ExceptionTest extends \Doctrine\Tests\DbalFunctionalTestCase
$this->_conn->executeQuery($sql);
}
$this->setExpectedException('\Doctrine\DBAL\Exception\NotNullableException', null, DBALException::ERROR_NOT_NULL);
$this->setExpectedException('\Doctrine\DBAL\Exception\NotNullConstraintViolationException');
$this->_conn->insert("notnull_table", array('id' => 1, 'value' => null));
}
public function testBadFieldNameException()
public function testInvalidFieldNameException()
{
$schema = new \Doctrine\DBAL\Schema\Schema();
......@@ -111,7 +112,7 @@ class ExceptionTest extends \Doctrine\Tests\DbalFunctionalTestCase
$this->_conn->executeQuery($sql);
}
$this->setExpectedException('\Doctrine\DBAL\Exception\InvalidFieldNameException', null, DBALException::ERROR_BAD_FIELD_NAME);
$this->setExpectedException('\Doctrine\DBAL\Exception\InvalidFieldNameException');
$this->_conn->insert("bad_fieldname_table", array('name' => 5));
}
......@@ -130,11 +131,11 @@ class ExceptionTest extends \Doctrine\Tests\DbalFunctionalTestCase
}
$sql = 'SELECT id FROM ambiguous_list_table, ambiguous_list_table_2';
$this->setExpectedException('\Doctrine\DBAL\Exception\NonUniqueFieldNameException', null, DBALException::ERROR_NON_UNIQUE_FIELD_NAME);
$this->setExpectedException('\Doctrine\DBAL\Exception\NonUniqueFieldNameException');
$this->_conn->executeQuery($sql);
}
public function testNotUniqueException()
public function testUniqueConstraintViolationException()
{
$schema = new \Doctrine\DBAL\Schema\Schema();
......@@ -147,7 +148,7 @@ class ExceptionTest extends \Doctrine\Tests\DbalFunctionalTestCase
}
$this->_conn->insert("unique_field_table", array('id' => 5));
$this->setExpectedException('\Doctrine\DBAL\Exception\DuplicateKeyException', null, DBALException::ERROR_DUPLICATE_KEY);
$this->setExpectedException('\Doctrine\DBAL\Exception\UniqueConstraintViolationException');
$this->_conn->insert("unique_field_table", array('id' => 5));
}
......@@ -162,14 +163,14 @@ class ExceptionTest extends \Doctrine\Tests\DbalFunctionalTestCase
}
$sql = 'SELECT id FRO syntax_error_table';
$this->setExpectedException('\Doctrine\DBAL\Exception\SyntaxErrorException', null, DBALException::ERROR_SYNTAX);
$this->setExpectedException('\Doctrine\DBAL\Exception\SyntaxErrorException');
$this->_conn->executeQuery($sql);
}
/**
* @dataProvider getSqLiteOpenConnection
*/
public function testConnectionExceptionSqLite($mode, $exceptionClass, $exceptionCode)
public function testConnectionExceptionSqLite($mode, $exceptionClass)
{
if ($this->_conn->getDatabasePlatform()->getName() != 'sqlite') {
$this->markTestSkipped("Only fails this way on sqlite");
......@@ -194,7 +195,7 @@ class ExceptionTest extends \Doctrine\Tests\DbalFunctionalTestCase
$table = $schema->createTable("no_connection");
$table->addColumn('id', 'integer');
$this->setExpectedException($exceptionClass, null, $exceptionCode);
$this->setExpectedException($exceptionClass);
foreach ($schema->toSql($conn->getDatabasePlatform()) AS $sql) {
$conn->executeQuery($sql);
}
......@@ -203,15 +204,15 @@ class ExceptionTest extends \Doctrine\Tests\DbalFunctionalTestCase
public function getSqLiteOpenConnection()
{
return array(
array(0000, '\Doctrine\DBAL\Exception\FailedToOpenException', DBALException::ERROR_UNABLE_TO_OPEN),
array(0444, '\Doctrine\DBAL\Exception\ReadOnlyException', DBALException::ERROR_WRITE_READONLY),
array(0000, '\Doctrine\DBAL\Exception\ConnectionException'),
array(0444, '\Doctrine\DBAL\Exception\ReadOnlyException'),
);
}
/**
* @dataProvider getConnectionParams
*/
public function testConnectionException($params, $exceptionCode)
public function testConnectionException($params)
{
if ($this->_conn->getDatabasePlatform()->getName() == 'sqlite') {
$this->markTestSkipped("Only skipped if platform is not sqlite");
......@@ -234,7 +235,7 @@ class ExceptionTest extends \Doctrine\Tests\DbalFunctionalTestCase
$table = $schema->createTable("no_connection");
$table->addColumn('id', 'integer');
$this->setExpectedException('Doctrine\DBAL\Exception\AccessDeniedException', null, $exceptionCode);
$this->setExpectedException('Doctrine\DBAL\Exception\ConnectionException');
foreach ($schema->toSql($conn->getDatabasePlatform()) AS $sql) {
$conn->executeQuery($sql);
......@@ -244,9 +245,9 @@ class ExceptionTest extends \Doctrine\Tests\DbalFunctionalTestCase
public function getConnectionParams()
{
return array(
array(array('user' => 'not_existing'), DBALException::ERROR_ACCESS_DENIED),
array(array('password' => 'really_not'), DBALException::ERROR_ACCESS_DENIED),
array(array('host' => 'localnope'), DBALException::ERROR_ACCESS_DENIED),
array(array('user' => 'not_existing')),
array(array('password' => 'really_not')),
array(array('host' => 'localnope')),
);
}
}
......
......@@ -2,7 +2,7 @@
namespace Doctrine\Tests\DBAL\Functional\Ticket;
use Doctrine\DBAL\Exception\TableExistsException;
use Doctrine\DBAL\DBALException;
use PDO;
/**
......@@ -22,11 +22,9 @@ class DBAL630Test extends \Doctrine\Tests\DbalFunctionalTestCase
$this->markTestSkipped('Currently restricted to PostgreSQL');
}
$sm = $this->_conn->getSchemaManager();
try {
$this->_conn->exec('CREATE TABLE dbal630 (id SERIAL, bool_col BOOLEAN NOT NULL);');
} catch (TableExistsException $e) {
} catch (DBALException $e) {
}
$this->running = true;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment