? sites/default/files ? sites/default/settings.php Index: includes/session.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/session.inc,v retrieving revision 1.53 diff -u -p -r1.53 session.inc --- includes/session.inc 31 Aug 2008 12:50:45 -0000 1.53 +++ includes/session.inc 1 Sep 2008 07:15:50 -0000 @@ -29,7 +29,7 @@ function sess_read($key) { } // Otherwise, if the session is still active, we have a record of the client's session in the database. - $user = db_fetch_object(db_query("SELECT u.*, s.* FROM {users} u INNER JOIN {sessions} s ON u.uid = s.uid WHERE s.sid = '%s'", $key)); + $user = db_fetch_object(db_query("SELECT u.*, s.* FROM [{users}] u INNER JOIN [{sessions}] s ON u.[uid] = s.[uid] WHERE s.[sid] = '%s'", $key)); // We found the client's session record and they are an authenticated user if ($user && $user->uid > 0) { @@ -39,7 +39,7 @@ function sess_read($key) { // Add roles element to $user $user->roles = array(); $user->roles[DRUPAL_AUTHENTICATED_RID] = 'authenticated user'; - $result = db_query("SELECT r.rid, r.name FROM {role} r INNER JOIN {users_roles} ur ON ur.rid = r.rid WHERE ur.uid = %d", $user->uid); + $result = db_query("SELECT r.[rid], r.[name] FROM [{role}] r INNER JOIN [{users_roles}] ur ON ur.[rid] = r.[rid] WHERE ur.[uid] = %d", $user->uid); while ($role = db_fetch_object($result)) { $user->roles[$role->rid] = $role->name; } @@ -65,7 +65,7 @@ function sess_write($key, $value) { return TRUE; } - $result = db_result(db_query("SELECT COUNT(*) FROM {sessions} WHERE sid = '%s'", $key)); + $result = db_result(db_query("SELECT COUNT(*) FROM [{sessions}] WHERE [sid] = '%s'", $key)); if (!$result) { // Only save session data when when the browser sends a cookie. This keeps @@ -73,17 +73,17 @@ function sess_write($key, $value) { // and gives more useful statistics. We can't eliminate anonymous session // table rows without breaking "Who's Online" block. if ($user->uid || $value || count($_COOKIE)) { - db_query("INSERT INTO {sessions} (sid, uid, cache, hostname, session, timestamp) VALUES ('%s', %d, %d, '%s', '%s', %d)", $key, $user->uid, isset($user->cache) ? $user->cache : 0, ip_address(), $value, time()); + db_query("INSERT INTO [{sessions}] ([sid], [uid], [cache], [hostname], [session], [timestamp]) VALUES ('%s', %d, %d, '%s', '%s', %d)", $key, $user->uid, isset($user->cache) ? $user->cache : 0, ip_address(), $value, time()); } } else { - db_query("UPDATE {sessions} SET uid = %d, cache = %d, hostname = '%s', session = '%s', timestamp = %d WHERE sid = '%s'", $user->uid, isset($user->cache) ? $user->cache : 0, ip_address(), $value, time(), $key); + db_query("UPDATE [{sessions}] SET [uid] = %d, [cache] = %d, [hostname] = '%s', [session] = '%s', [timestamp] = %d WHERE [sid] = '%s'", $user->uid, isset($user->cache) ? $user->cache : 0, ip_address(), $value, time(), $key); if (db_affected_rows()) { // Last access time is updated no more frequently than once every 180 seconds. // This reduces contention in the users table. if ($user->uid && time() - $user->access > variable_get('session_write_interval', 180)) { - db_query("UPDATE {users} SET access = %d WHERE uid = %d", time(), $user->uid); + db_query("UPDATE [{users}] SET [access] = %d WHERE [uid] = %d", time(), $user->uid); } } } @@ -97,7 +97,7 @@ function sess_write($key, $value) { function sess_regenerate() { $old_session_id = session_id(); session_regenerate_id(); - db_query("UPDATE {sessions} SET sid = '%s' WHERE sid = '%s'", session_id(), $old_session_id); + db_query("UPDATE [{sessions}] SET [sid] = '%s' WHERE [sid] = '%s'", session_id(), $old_session_id); } /** @@ -113,8 +113,8 @@ function sess_regenerate() { * The number of users with sessions. */ function sess_count($timestamp = 0, $anonymous = true) { - $query = $anonymous ? ' AND uid = 0' : ' AND uid > 0'; - return db_result(db_query('SELECT COUNT(sid) AS count FROM {sessions} WHERE timestamp >= %d' . $query, $timestamp)); + $query = $anonymous ? ' AND [uid] = 0' : ' AND [uid] > 0'; + return db_result(db_query('SELECT COUNT([sid]) AS [count] FROM [{sessions}] WHERE [timestamp] >= %d' . $query, $timestamp)); } /** @@ -124,7 +124,7 @@ function sess_count($timestamp = 0, $ano * the session id */ function sess_destroy_sid($sid) { - db_query("DELETE FROM {sessions} WHERE sid = '%s'", $sid); + db_query("DELETE FROM [{sessions}] WHERE [sid] = '%s'", $sid); } /** @@ -134,7 +134,7 @@ function sess_destroy_sid($sid) { * the user id */ function sess_destroy_uid($uid) { - db_query('DELETE FROM {sessions} WHERE uid = %d', $uid); + db_query('DELETE FROM [{sessions}] WHERE [uid] = %d', $uid); } function sess_gc($lifetime) { @@ -143,7 +143,7 @@ function sess_gc($lifetime) { // for three weeks before deleting them, you need to set gc_maxlifetime // to '1814400'. At that value, only after a user doesn't log in after // three weeks (1814400 seconds) will his/her session be removed. - db_query("DELETE FROM {sessions} WHERE timestamp < %d", time() - $lifetime); + db_query("DELETE FROM [{sessions}] WHERE [timestamp] < %d", time() - $lifetime); return TRUE; } Index: includes/database/database.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/database/database.inc,v retrieving revision 1.2 diff -u -p -r1.2 database.inc --- includes/database/database.inc 31 Aug 2008 09:12:35 -0000 1.2 +++ includes/database/database.inc 1 Sep 2008 07:15:51 -0000 @@ -146,6 +146,11 @@ abstract class DatabaseConnection extend */ public $lastStatement; + /** + * String to use to quote identifiers and names. + */ + protected $nameQuote = '"'; + function __construct($dsn, $username, $password, $driver_options = array()) { $driver_options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION; // Because the other methods don't seem to work right. parent::__construct($dsn, $username, $password, $driver_options); @@ -226,28 +231,59 @@ abstract class DatabaseConnection extend */ protected function prefixTables($sql) { global $db_prefix; + static $_db_prefix = NULL; - if (is_array($db_prefix)) { - if (array_key_exists('default', $db_prefix)) { - $tmp = $db_prefix; + // #302327: Exceptional case if "." exists in $db_prefix. + // NOTE: preg_replace() can function with both string and array. + if (!$_db_prefix) { + $_db_prefix = preg_replace('/\./', '].[', $db_prefix); + } + + if (is_array($_db_prefix)) { + if (array_key_exists('default', $_db_prefix)) { + $tmp = $_db_prefix; unset($tmp['default']); foreach ($tmp as $key => $val) { $sql = strtr($sql, array('{' . $key . '}' => $val . $key)); } - return strtr($sql, array('{' => $db_prefix['default'] , '}' => '')); + return strtr($sql, array('{' => $_db_prefix['default'] , '}' => '')); } else { - foreach ($db_prefix as $key => $val) { + foreach ($_db_prefix as $key => $val) { $sql = strtr($sql, array('{' . $key . '}' => $val . $key)); } return strtr($sql, array('{' => '' , '}' => '')); } } else { - return strtr($sql, array('{' => $db_prefix , '}' => '')); + return strtr($sql, array('{' => $_db_prefix , '}' => '')); } } + /** + * Escape all constraints in a query for reserved word conflict safe. + * + * Queries sent to Drupal should wrap all identifiers and names in square + * brackets. This function will search for this syntax and replace it as + * corresponding escape characters, based on the database engine specific + * requirement. + * + * @param $sql + * A string containing a partial or entire SQL query. + * @return + * The properly-escaped string. + */ + protected function escapeConstraints($sql) { + // #302327: Exceptional case if "." exists in $db_prefix. + // TODO: Queries may come with "].[" syntax which need special concern. + // Replace as below when all core queries are well escaped. + // @code + // return strtr($sql, array('[' => $this->nameQuote , ']' => $this->nameQuote)); + // @endcode + $sql = preg_replace('/\[([A-Za-z0-9_]+)\]/', $this->nameQuote .'\1'. $this->nameQuote, $sql); + return strtr($sql, array('[' => '' , ']' => '')); + } + /** * Prepare a query string and return the prepared statement. * @@ -263,6 +299,7 @@ abstract class DatabaseConnection extend protected function prepareQuery($query) { static $statements = array(); $query = self::prefixTables($query); + $query = self::escapeConstraints($query); if (empty($statements[$query])) { $statements[$query] = parent::prepare($query); } Index: includes/database/mysql/database.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/database/mysql/database.inc,v retrieving revision 1.1 diff -u -p -r1.1 database.inc --- includes/database/mysql/database.inc 21 Aug 2008 19:36:36 -0000 1.1 +++ includes/database/mysql/database.inc 1 Sep 2008 07:15:51 -0000 @@ -14,6 +14,7 @@ class DatabaseConnection_mysql extends DatabaseConnection { protected $transactionSupport; + protected $nameQuote = '`'; public function __construct(Array $connection_options = array()) {