diff --git a/core/lib/Drupal/Core/Database/DatabaseNotFoundException.php b/core/lib/Drupal/Core/Database/DatabaseAccessDeniedException.php similarity index 52% copy from core/lib/Drupal/Core/Database/DatabaseNotFoundException.php copy to core/lib/Drupal/Core/Database/DatabaseAccessDeniedException.php index 63eb9a3..a797fea 100644 --- a/core/lib/Drupal/Core/Database/DatabaseNotFoundException.php +++ b/core/lib/Drupal/Core/Database/DatabaseAccessDeniedException.php @@ -5,4 +5,4 @@ /** * Exception thrown if specified database is not found. */ -class DatabaseNotFoundException extends \RuntimeException {} +class DatabaseAccessDeniedException extends \RuntimeException implements DatabaseException {} diff --git a/core/lib/Drupal/Core/Database/DatabaseNotFoundException.php b/core/lib/Drupal/Core/Database/DatabaseNotFoundException.php index 63eb9a3..1c5b5eb 100644 --- a/core/lib/Drupal/Core/Database/DatabaseNotFoundException.php +++ b/core/lib/Drupal/Core/Database/DatabaseNotFoundException.php @@ -5,4 +5,4 @@ /** * Exception thrown if specified database is not found. */ -class DatabaseNotFoundException extends \RuntimeException {} +class DatabaseNotFoundException extends \RuntimeException implements DatabaseException {} diff --git a/core/lib/Drupal/Core/Database/Driver/mysql/Connection.php b/core/lib/Drupal/Core/Database/Driver/mysql/Connection.php index df51067..fd46438 100644 --- a/core/lib/Drupal/Core/Database/Driver/mysql/Connection.php +++ b/core/lib/Drupal/Core/Database/Driver/mysql/Connection.php @@ -2,6 +2,7 @@ namespace Drupal\Core\Database\Driver\mysql; +use Drupal\Core\Database\DatabaseAccessDeniedException; use Drupal\Core\Database\DatabaseExceptionWrapper; use Drupal\Core\Database\Database; @@ -27,6 +28,11 @@ class Connection extends DatabaseConnection { const DATABASE_NOT_FOUND = 1049; /** + * Error code for "Access denied" error. + */ + const ACCESS_DENIED = 1045; + + /** * Error code for "Can't initialize character set" error. */ const UNSUPPORTED_CHARSET = 2019; @@ -139,7 +145,18 @@ public static function open(array &$connection_options = array()) { $connection_options['pdo'] += [\PDO::MYSQL_ATTR_MULTI_STATEMENTS => FALSE]; } - $pdo = new \PDO($dsn, $connection_options['username'], $connection_options['password'], $connection_options['pdo']); + try { + $pdo = new \PDO($dsn, $connection_options['username'], $connection_options['password'], $connection_options['pdo']); + } + catch (\PDOException $e) { + if ($e->getCode() == static::DATABASE_NOT_FOUND) { + throw new DatabaseNotFoundException($e->getMessage(), $e->getCode(), $e); + } + if ($e->getCode() == static::ACCESS_DENIED) { + throw new DatabaseAccessDeniedException($e->getMessage(), $e->getCode(), $e); + } + throw $e; + } // Force MySQL to use the UTF-8 character set. Also set the collation, if a // certain one has been set; otherwise, MySQL defaults to diff --git a/core/lib/Drupal/Core/Database/Driver/pgsql/Connection.php b/core/lib/Drupal/Core/Database/Driver/pgsql/Connection.php index 4688cde..042c221 100644 --- a/core/lib/Drupal/Core/Database/Driver/pgsql/Connection.php +++ b/core/lib/Drupal/Core/Database/Driver/pgsql/Connection.php @@ -4,6 +4,7 @@ use Drupal\Core\Database\Database; use Drupal\Core\Database\Connection as DatabaseConnection; +use Drupal\Core\Database\DatabaseAccessDeniedException; use Drupal\Core\Database\DatabaseNotFoundException; /** @@ -27,6 +28,13 @@ class Connection extends DatabaseConnection { const DATABASE_NOT_FOUND = 7; /** + * Error code for "Access denied" error. + * + * Technically the error message is "insufficient_privilege". + */ + const ACCESS_DENIED = '42501'; + + /** * The list of PostgreSQL reserved key words. * * @see http://www.postgresql.org/docs/9.4/static/sql-keywords-appendix.html @@ -113,7 +121,19 @@ public static function open(array &$connection_options = array()) { // Convert numeric values to strings when fetching. \PDO::ATTR_STRINGIFY_FETCHES => TRUE, ); - $pdo = new \PDO($dsn, $connection_options['username'], $connection_options['password'], $connection_options['pdo']); + + try { + $pdo = new \PDO($dsn, $connection_options['username'], $connection_options['password'], $connection_options['pdo']); + } + catch (\PDOException $e) { + if ($e->getCode() == static::DATABASE_NOT_FOUND) { + throw new DatabaseNotFoundException($e->getMessage(), $e->getCode(), $e); + } + if ($e->getCode() == static::ACCESS_DENIED) { + throw new DatabaseAccessDeniedException($e->getMessage(), $e->getCode(), $e); + } + throw $e; + } return $pdo; } diff --git a/core/lib/Drupal/Core/Database/Driver/sqlite/Connection.php b/core/lib/Drupal/Core/Database/Driver/sqlite/Connection.php index 2f5374b..10c63e8 100644 --- a/core/lib/Drupal/Core/Database/Driver/sqlite/Connection.php +++ b/core/lib/Drupal/Core/Database/Driver/sqlite/Connection.php @@ -99,7 +99,19 @@ public static function open(array &$connection_options = array()) { // Convert numeric values to strings when fetching. \PDO::ATTR_STRINGIFY_FETCHES => TRUE, ); - $pdo = new \PDO('sqlite:' . $connection_options['database'], '', '', $connection_options['pdo']); + + try { + $pdo = new \PDO('sqlite:' . $connection_options['database'], '', '', $connection_options['pdo']); + } + catch (\PDOException $e) { + if ($e->getCode() == static::DATABASE_NOT_FOUND) { + throw new DatabaseNotFoundException($e->getMessage(), $e->getCode(), $e); + } + // SQLite doesn't have a distinct error code for access denied, so don't + // deal with that case. + throw $e; + } + // Create functions needed by SQLite. $pdo->sqliteCreateFunction('if', array(__CLASS__, 'sqlFunctionIf')); diff --git a/core/lib/Drupal/Core/Installer/CheckInstalledTrait.php b/core/lib/Drupal/Core/Installer/CheckInstalledTrait.php index 8bbef6a..4fe8af8 100644 --- a/core/lib/Drupal/Core/Installer/CheckInstalledTrait.php +++ b/core/lib/Drupal/Core/Installer/CheckInstalledTrait.php @@ -4,7 +4,9 @@ use Drupal\Core\Database\Connection; use Drupal\Core\Database\Database; +use Drupal\Core\Database\DatabaseAccessDeniedException; use Drupal\Core\Database\DatabaseException; +use Drupal\Core\Database\DatabaseNotFoundException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** @@ -41,6 +43,12 @@ protected function shouldRedirectToInstaller(\Exception $exception, Connection $ return FALSE; } + // If the database wasn't found, assume the user hasn't entered it properly + // and redirect to the installer. + if ($exception instanceof DatabaseNotFoundException) { + return TRUE; + } + // Never redirect if we're already in the installer. if (drupal_installation_attempted()) { return FALSE; @@ -52,12 +60,6 @@ protected function shouldRedirectToInstaller(\Exception $exception, Connection $ return TRUE; } - // A database error with code 1049 means "missing database", and it should - // be safe to redirect in that case. - if (($exception instanceof \PDOException || $exception instanceof DatabaseException) && $exception->getCode() == 1049) { - return TRUE; - } - // Redirect if the database is empty. if ($connection) { try { @@ -65,15 +67,14 @@ protected function shouldRedirectToInstaller(\Exception $exception, Connection $ } catch (\Exception $e) { // If we still have an exception at this point, we need to be careful - // since we should not redirect if the exception represents an error on an - // already-installed site (for example, if the database server went down). - // Assume we shouldn't redirect, just in case. + // since we should not redirect if the exception represents an error on + // an already-installed site (for example, if the database server went + // down). Assume we shouldn't redirect, just in case. return FALSE; } } - // Default to FALSE to minimize the chance of overwriting an installed - // database. + // When in doubt, don't redirect. return FALSE; } }