diff --git a/core/lib/Drupal/Core/Database/Connection.php b/core/lib/Drupal/Core/Database/Connection.php index 358fa71..b7f1f32 100644 --- a/core/lib/Drupal/Core/Database/Connection.php +++ b/core/lib/Drupal/Core/Database/Connection.php @@ -529,12 +529,11 @@ protected function filterComment($comment = '') { * this method will return NULL and may throw an exception if * $options['throw_exception'] is TRUE. * - * @throws \PDOException + * @throws \Drupal\Core\Database\DatabaseExceptionWrapper * @throws \Drupal\Core\Database\IntegrityConstraintViolationException * @throws \InvalidArgumentException */ public function query($query, array $args = array(), $options = array()) { - // Use default values if not already set. $options += $this->defaultOptions(); @@ -562,32 +561,55 @@ public function query($query, array $args = array(), $options = array()) { $stmt->allowRowCount = TRUE; return $stmt->rowCount(); case Database::RETURN_INSERT_ID: - return $this->connection->lastInsertId(); + $sequence_name = isset($options['sequence_name']) ? $options['sequence_name'] : NULL; + return $this->connection->lastInsertId($sequence_name); case Database::RETURN_NULL: - return; + return NULL; default: throw new \PDOException('Invalid return directive: ' . $options['return']); } } catch (\PDOException $e) { - if ($options['throw_exception']) { - // 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 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') { - $exception = new IntegrityConstraintViolationException($message, $e->getCode(), $e); - } - else { - $exception = new DatabaseExceptionWrapper($message, 0, $e); - } + return $this->handleQueryException($e, $query, $args, $options); + } + } - throw $exception; + /** + * Wraps and re-throws any PDO exception thrown by static::query(). + * + * @param \PDOException $e + * The exception thrown by static::query(). + * @param $query + * The query executed by static::query(). + * @param array $args + * An array of arguments for the prepared statement. + * @param array $options + * An associative array of options to control how the query is run. + * + * @return null + * + * @throws \Drupal\Core\Database\DatabaseExceptionWrapper + * @throws \Drupal\Core\Database\IntegrityConstraintViolationException + */ + protected function handleQueryException(\PDOException $e, $query, array $args = array(), $options = array()) { + if ($options['throw_exception']) { + // 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 StatementInterface) ? $query->getQueryString() : $query; + $message = $e->getMessage() . ": " . $query_string . "; " . print_r($args, TRUE); + // Match all SQLSTATE 23xxx errors. + if (substr($e->getCode(), -6, -3) == '23') { + $exception = new IntegrityConstraintViolationException($message, $e->getCode(), $e); } - return NULL; + else { + $exception = new DatabaseExceptionWrapper($message, 0, $e); + } + + throw $exception; } + + return NULL; } /** diff --git a/core/lib/Drupal/Core/Database/Driver/pgsql/Connection.php b/core/lib/Drupal/Core/Database/Driver/pgsql/Connection.php index b888f14..3b5dbee 100644 --- a/core/lib/Drupal/Core/Database/Driver/pgsql/Connection.php +++ b/core/lib/Drupal/Core/Database/Driver/pgsql/Connection.php @@ -102,67 +102,22 @@ public static function open(array &$connection_options = array()) { return $pdo; } + /** + * {@inheritdoc} + */ public function query($query, array $args = array(), $options = array()) { - $options += $this->defaultOptions(); - // The PDO PostgreSQL driver has a bug which - // doesn't type cast booleans correctly when - // parameters are bound using associative - // arrays. - // See http://bugs.php.net/bug.php?id=48383 + // The PDO PostgreSQL driver has a bug which doesn't type cast booleans + // correctly when parameters are bound using associative arrays. + // @see http://bugs.php.net/bug.php?id=48383 foreach ($args as &$value) { if (is_bool($value)) { $value = (int) $value; } } - try { - if ($query instanceof StatementInterface) { - $stmt = $query; - $stmt->execute(NULL, $options); - } - else { - $this->expandArguments($query, $args); - $stmt = $this->prepareQuery($query); - $stmt->execute($args, $options); - } - - switch ($options['return']) { - case Database::RETURN_STATEMENT: - return $stmt; - case Database::RETURN_AFFECTED: - $stmt->allowRowCount = TRUE; - return $stmt->rowCount(); - case Database::RETURN_INSERT_ID: - return $this->connection->lastInsertId($options['sequence_name']); - case Database::RETURN_NULL: - return; - default: - throw new \PDOException('Invalid return directive: ' . $options['return']); - } - } - catch (\PDOException $e) { - if ($options['throw_exception']) { - // Match all SQLSTATE 23xxx errors. - if (substr($e->getCode(), -6, -3) == '23') { - $e = new IntegrityConstraintViolationException($e->getMessage(), $e->getCode(), $e); - } - else { - $e = new DatabaseExceptionWrapper($e->getMessage(), 0, $e); - } - // Add additional debug information. - if ($query instanceof StatementInterface) { - $e->query_string = $stmt->getQueryString(); - } - else { - $e->query_string = $query; - } - $e->args = $args; - throw $e; - } - return NULL; - } + return parent::query($query, $args, $options); } public function prepareQuery($query) { diff --git a/core/lib/Drupal/Core/Database/Driver/sqlite/Connection.php b/core/lib/Drupal/Core/Database/Driver/sqlite/Connection.php index 4c3f838..b499b5a 100644 --- a/core/lib/Drupal/Core/Database/Driver/sqlite/Connection.php +++ b/core/lib/Drupal/Core/Database/Driver/sqlite/Connection.php @@ -12,7 +12,6 @@ use Drupal\Core\Database\TransactionNoActiveException; use Drupal\Core\Database\TransactionNameNonUniqueException; use Drupal\Core\Database\TransactionCommitFailedException; -use Drupal\Core\Database\Driver\sqlite\Statement; use Drupal\Core\Database\Connection as DatabaseConnection; /** @@ -334,6 +333,23 @@ protected function expandArguments(&$query, &$args) { return $modified; } + /** + * {@inheritdoc} + */ + protected function handleQueryException(\PDOException $e, $query, array $args = array(), $options = array()) { + // The database schema might be changed by another process in between the + // time that the statement was prepared and the time the statement was run + // (e.g. usually happens when running tests). In this case, we need to + // re-run the query. + // @see http://www.sqlite.org/faq.html#q15 + // @see http://www.sqlite.org/rescode.html#schema + if (!empty($e->errorInfo[1]) && $e->errorInfo[1] === 17) { + return $this->query($query, $args, $options); + } + + parent::handleQueryException($e, $query, $args, $options); + } + public function queryRange($query, $from, $count, array $args = array(), array $options = array()) { return $this->query($query . ' LIMIT ' . (int) $from . ', ' . (int) $count, $args, $options); }