diff --git a/core/lib/Drupal/Core/Database/Connection.php b/core/lib/Drupal/Core/Database/Connection.php index 234af008734..51efaf46bf0 100644 --- a/core/lib/Drupal/Core/Database/Connection.php +++ b/core/lib/Drupal/Core/Database/Connection.php @@ -478,9 +478,9 @@ abstract class Connection extends PDO { * @param $query * The query to execute. In most cases this will be a string containing * an SQL query with placeholders. An already-prepared instance of - * DatabaseStatementInterface may also be passed in order to allow calling + * StatementInterface may also be passed in order to allow calling * code to manually bind variables to a query. If a - * DatabaseStatementInterface is passed, the $args array will be ignored. + * StatementInterface is passed, the $args array will be ignored. * It is extremely rare that module code will need to pass a statement * object to this method. It is used primarily for database drivers for * databases that require special LOB field handling. @@ -492,7 +492,7 @@ abstract class Connection extends PDO { * An associative array of options to control how the query is run. See * the documentation for DatabaseConnection::defaultOptions() for details. * - * @return Drupal\Core\Database\StatementInterface + * @return \Drupal\Core\Database\StatementInterface * This method will return one of: the executed statement, the number of * rows affected by the query (not the number matched), or the generated * insert ID of the last query, depending on the value of @@ -502,7 +502,7 @@ abstract class Connection extends PDO { * $options['throw_exception'] is TRUE. * * @throws PDOException - * @throws Drupal\Core\Database\IntegrityConstraintViolationException + * @throws \Drupal\Core\Database\IntegrityConstraintViolationException */ public function query($query, array $args = array(), $options = array()) { @@ -513,7 +513,7 @@ abstract class Connection extends PDO { // We allow either a pre-bound statement object or a literal string. // In either case, we want to end up with an executed statement object, // which we pass to PDOStatement::execute. - if ($query instanceof DatabaseStatementInterface) { + if ($query instanceof StatementInterface) { $stmt = $query; $stmt->execute(NULL, $options); } @@ -544,7 +544,7 @@ abstract class Connection extends PDO { // Wrap the exception in another exception, because PHP does not allow // overriding Exception::getMessage(). Its message is the extra database // debug information. - $query_string = ($query instanceof DatabaseStatementInterface) ? $stmt->getQueryString() : $query; + $query_string = ($query instanceof StatementInterface) ? $stmt->getQueryString() : $query; $message = $e->getMessage() . ": " . $query_string . "; " . print_r($args, TRUE); // Match all SQLSTATE 23xxx errors. if (substr($e->getCode(), -6, -3) == '23') { diff --git a/core/lib/Drupal/Core/Database/Statement.php b/core/lib/Drupal/Core/Database/Statement.php index c5b1735e33c..120fac6c1c7 100644 --- a/core/lib/Drupal/Core/Database/Statement.php +++ b/core/lib/Drupal/Core/Database/Statement.php @@ -11,7 +11,7 @@ use PDO; use PDOStatement; /** - * Default implementation of DatabaseStatementInterface. + * Default implementation of StatementInterface. * * PDO allows us to extend the PDOStatement class to provide additional * functionality beyond that offered by default. We do need extra @@ -32,7 +32,7 @@ class Statement extends PDOStatement implements StatementInterface { */ public $dbh; - protected function __construct($dbh) { + protected function __construct(Connection $dbh) { $this->dbh = $dbh; $this->setFetchMode(PDO::FETCH_OBJ); } diff --git a/core/lib/Drupal/Core/Database/StatementInterface.php b/core/lib/Drupal/Core/Database/StatementInterface.php index 7f1ca4a0917..b3d356c5740 100644 --- a/core/lib/Drupal/Core/Database/StatementInterface.php +++ b/core/lib/Drupal/Core/Database/StatementInterface.php @@ -30,6 +30,25 @@ use Traversable; */ interface StatementInterface extends Traversable { + /** + * Constructs a new PDOStatement object. + * + * The PDO manual does not document this constructor, but when overriding the + * PDOStatement class with a custom without this constructor, PDO will throw + * the internal exception/warning: + * + * "PDO::query(): SQLSTATE[HY000]: General error: user-supplied statement does + * not accept constructor arguments" + * + * PDO enforces that the access type of this constructor must be protected, + * and lastly, it also enforces that a custom PDOStatement interface (like + * this) omits the constructor (declaring it results in fatal errors + * complaining about "the access type must not be public" if it is public, and + * "the access type must be omitted" if it is protected; i.e., conflicting + * statements). The access type has to be protected. + */ + //protected function __construct(Connection $dbh); + /** * Executes a prepared statement * @@ -113,7 +132,7 @@ interface StatementInterface extends Traversable { /** * Fetches the next row and returns it as an object. * - * The object will be of the class specified by DatabaseStatementInterface::setFetchMode() + * The object will be of the class specified by StatementInterface::setFetchMode() * or stdClass if not specified. */ // public function fetchObject(); diff --git a/core/lib/Drupal/Core/Database/StatementPrefetch.php b/core/lib/Drupal/Core/Database/StatementPrefetch.php index 18dd5826a66..e01f03adafc 100644 --- a/core/lib/Drupal/Core/Database/StatementPrefetch.php +++ b/core/lib/Drupal/Core/Database/StatementPrefetch.php @@ -13,7 +13,7 @@ use PDO; use PDOException; /** - * An implementation of DatabaseStatementInterface that prefetches all data. + * An implementation of StatementInterface that prefetches all data. * * This class behaves very similar to a PDOStatement but as it always fetches * every row it is possible to manipulate those results. @@ -342,7 +342,7 @@ class StatementPrefetch implements Iterator, StatementInterface { return isset($this->currentRow); } - /* Implementations of DatabaseStatementInterface. */ + /* Implementations of StatementInterface. */ public function rowCount() { return $this->rowCount; diff --git a/core/modules/system/lib/Drupal/system/Tests/Database/DatabaseExceptionWrapperTest.php b/core/modules/system/lib/Drupal/system/Tests/Database/DatabaseExceptionWrapperTest.php new file mode 100644 index 00000000000..9d34e9ac6c7 --- /dev/null +++ b/core/modules/system/lib/Drupal/system/Tests/Database/DatabaseExceptionWrapperTest.php @@ -0,0 +1,38 @@ + 'Database exceptiontests', + 'description' => 'Tests exceptions thrown by queries.', + 'group' => 'Database', + ); + } + + function testDatabaseExceptionWrapper() { + $connection = Database::getConnection(); + $query = $connection->prepare('bananas'); + try { + $connection->query($query); + $this->fail('The expected exception is not thrown.'); + } + catch (DatabaseExceptionWrapper $e) { + $this->pass('The expected exception has been thrown.'); + } + } + +}