From 7135589c89f7110a40c64af801ccc13f71075d77 Mon Sep 17 00:00:00 2001 From: catch Date: Mon, 28 Nov 2011 23:58:50 +0900 Subject: [PATCH] Issue #1309278 by basic, Niklas Fiekas: Added Make PDO connection options configurable. --- core/includes/database/mysql/database.inc | 34 +++++++++++++++------- core/includes/database/pgsql/database.inc | 15 ++++++++-- core/includes/database/sqlite/database.inc | 14 +++++++-- sites/default/default.settings.php | 23 +++++++++++++++ 4 files changed, 72 insertions(+), 14 deletions(-) diff --git a/core/includes/database/mysql/database.inc b/core/includes/database/mysql/database.inc index 7d5d85998db..a57f7dd0228 100644 --- a/core/includes/database/mysql/database.inc +++ b/core/includes/database/mysql/database.inc @@ -37,14 +37,20 @@ class DatabaseConnection_mysql extends DatabaseConnection { $dsn = 'mysql:host=' . $connection_options['host'] . ';port=' . (empty($connection_options['port']) ? 3306 : $connection_options['port']); } $dsn .= ';dbname=' . $connection_options['database']; - parent::__construct($dsn, $connection_options['username'], $connection_options['password'], array( + // Allow PDO options to be overridden. + $connection_options += array( + 'pdo' => array(), + ); + $connection_options['pdo'] += array( // So we don't have to mess around with cursors and unbuffered queries by default. PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => TRUE, // Because MySQL's prepared statements skip the query cache, because it's dumb. PDO::ATTR_EMULATE_PREPARES => TRUE, // Force column names to lower case. PDO::ATTR_CASE => PDO::CASE_LOWER, - )); + ); + + parent::__construct($dsn, $connection_options['username'], $connection_options['password'], $connection_options['pdo']); // Force MySQL to use the UTF-8 character set. Also set the collation, if a // certain one has been set; otherwise, MySQL defaults to 'utf8_general_ci' @@ -56,14 +62,22 @@ class DatabaseConnection_mysql extends DatabaseConnection { $this->exec('SET NAMES utf8'); } - // Force MySQL's behavior to conform more closely to SQL standards. - // This allows Drupal to run almost seamlessly on many different - // kinds of database systems. These settings force MySQL to behave - // the same as postgresql, or sqlite in regards to syntax interpretation - // and invalid data handling. See http://drupal.org/node/344575 for - // further discussion. Also, as MySQL 5.5 changed the meaning of - // TRADITIONAL we need to spell out the modes one by one. - $this->exec("SET sql_mode='ANSI,STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER'"); + // Set MySQL init_commands if not already defined. Default Drupal's MySQL + // behavior to conform more closely to SQL standards. This allows Drupal + // to run almost seamlessly on many different kinds of database systems. + // These settings force MySQL to behave the same as postgresql, or sqlite + // in regards to syntax interpretation and invalid data handling. See + // http://drupal.org/node/344575 for further discussion. Also, as MySQL 5.5 + // changed the meaning of TRADITIONAL we need to spell out the modes one by + // one. + $connection_options += array( + 'init_commands' => array(), + ); + $connection_options['init_commands'] += array( + 'sql_mode' => "SET sql_mode = 'ANSI,STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER'", + ); + // Set connection options. + $this->exec(implode('; ', $connection_options['init_commands'])); } public function queryRange($query, $from, $count, array $args = array(), array $options = array()) { diff --git a/core/includes/database/pgsql/database.inc b/core/includes/database/pgsql/database.inc index 39b4e9b6960..d42a1cc3c63 100644 --- a/core/includes/database/pgsql/database.inc +++ b/core/includes/database/pgsql/database.inc @@ -47,7 +47,12 @@ class DatabaseConnection_pgsql extends DatabaseConnection { $this->connectionOptions = $connection_options; $dsn = 'pgsql:host=' . $connection_options['host'] . ' dbname=' . $connection_options['database'] . ' port=' . $connection_options['port']; - parent::__construct($dsn, $connection_options['username'], $connection_options['password'], array( + + // Allow PDO options to be overridden. + $connection_options += array( + 'pdo' => array(), + ); + $connection_options['pdo'] += array( // Prepared statements are most effective for performance when queries // are recycled (used several times). However, if they are not re-used, // prepared statements become ineffecient. Since most of Drupal's @@ -59,10 +64,16 @@ class DatabaseConnection_pgsql extends DatabaseConnection { PDO::ATTR_STRINGIFY_FETCHES => TRUE, // Force column names to lower case. PDO::ATTR_CASE => PDO::CASE_LOWER, - )); + ); + parent::__construct($dsn, $connection_options['username'], $connection_options['password'], $connection_options['pdo']); // Force PostgreSQL to use the UTF-8 character set by default. $this->exec("SET NAMES 'UTF8'"); + + // Execute PostgreSQL init_commands. + if (isset($connection_options['init_commands'])) { + $this->exec(implode('; ', $connection_options['init_commands'])); + } } public function query($query, array $args = array(), $options = array()) { diff --git a/core/includes/database/sqlite/database.inc b/core/includes/database/sqlite/database.inc index 4cef1641673..98b35a26070 100644 --- a/core/includes/database/sqlite/database.inc +++ b/core/includes/database/sqlite/database.inc @@ -63,12 +63,17 @@ class DatabaseConnection_sqlite extends DatabaseConnection { $this->connectionOptions = $connection_options; - parent::__construct('sqlite:' . $connection_options['database'], '', '', array( + // Allow PDO options to be overridden. + $connection_options += array( + 'pdo' => array(), + ); + $connection_options['pdo'] += array( // Force column names to lower case. PDO::ATTR_CASE => PDO::CASE_LOWER, // Convert numeric values to strings when fetching. PDO::ATTR_STRINGIFY_FETCHES => TRUE, - )); + ); + parent::__construct('sqlite:' . $connection_options['database'], '', '', $connection_options['pdo']); // Attach one database for each registered prefix. $prefixes = $this->prefixes; @@ -103,6 +108,11 @@ class DatabaseConnection_sqlite extends DatabaseConnection { $this->sqliteCreateFunction('substring', array($this, 'sqlFunctionSubstring'), 3); $this->sqliteCreateFunction('substring_index', array($this, 'sqlFunctionSubstringIndex'), 3); $this->sqliteCreateFunction('rand', array($this, 'sqlFunctionRand')); + + // Execute sqlite init_commands. + if (isset($connection_options['init_commands'])) { + $this->exec(implode('; ', $connection_options['init_commands'])); + } } /** diff --git a/sites/default/default.settings.php b/sites/default/default.settings.php index 330ebcc9671..360e556ffd4 100644 --- a/sites/default/default.settings.php +++ b/sites/default/default.settings.php @@ -153,6 +153,29 @@ * @endcode * NOTE: MySQL and SQLite's definition of a schema is a database. * + * Advanced users can add or override initial commands to execute when + * connecting to the database server, as well as PDO connection settings. For + * example, to enable MySQL SELECT queries to exceed the max_join_size system + * variable, and to reduce the database connection timeout to 5 seconds: + * + * @code + * $databases['default']['default'] = array( + * 'init_commands' => array( + * 'big_selects' => 'SET SQL_BIG_SELECTS=1', + * ), + * 'pdo' => array( + * PDO::ATTR_TIMEOUT => 5, + * ), + * ); + * @endcode + * + * WARNING: These defaults are designed for database portability. Changing them + * may cause unexpected behavior, including potential data loss. + * + * @see DatabaseConnection_mysql::__construct + * @see DatabaseConnection_pgsql::__construct + * @see DatabaseConnection_sqlite::__construct + * * Database configuration format: * @code * $databases['default']['default'] = array(