? profiles/simpletest ? sites/default/modules ? sites/default/settings.php Index: includes/database/database.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/database/database.inc,v retrieving revision 1.29 diff -u -p -r1.29 database.inc --- includes/database/database.inc 22 Nov 2008 13:51:38 -0000 1.29 +++ includes/database/database.inc 27 Nov 2008 07:45:33 -0000 @@ -217,6 +217,58 @@ abstract class DatabaseConnection extend */ protected $schema = NULL; + /** + * String to use to quote identifiers and names. + */ + protected $nameQuote = '"'; + + /** + * Default concat operator. Change to || for Oracle/Interbase. + */ + protected $concat_operator = '+'; + + /** + * Uppercase function. + */ + public function upperCase($field) { + return 'UPPER(' . $field . ')'; + } + + /** + * Random function. + */ + public function random() { + return 'RAND()'; + } + + /** + * String length operator. + */ + public function length($field) { + return 'LENGTH(' . $field . ')'; + } + + /** + * Substring operator. + */ + public function substr($field, $start, $length = NULL) { + return 'SUBSTR(' . implode(', ', array($field, $start, $length)) . ')'; + } + + /** + * Portably concatenate strings. + */ + public function Concat($args) { + return implode($this->concat_operator, $args); + } + + /** + * Returns a string that is the equivalent of MySQL IFNULL or Oracle NVL. + */ + public function IfNull($expr1, $expr2) { + return " CASE WHEN $expr1 IS NULL THEN $expr2 ELSE $expr1 END "; + } + function __construct($dsn, $username, $password, $driver_options = array()) { // Fallback to DatabaseStatementBase if the driver has not specified one. $statement_class = isset($driver_options['statement_class']) ? $driver_options['statement_class'] : 'DatabaseStatementBase'; @@ -1509,6 +1561,154 @@ class DatabaseStatementBase extends PDOS */ /** + * Return the portably concatenate strings of the SQL strtoupper function. + * + * Use this function with following syntax: + * @code + * db_query("SELECT " . db_strtoupper('name') . " FROM {system}"); + * @endcode + * + * @param $field + * Field for apply abstraction. + * @param $options + * An array of options to control how the query operates. + * @return + * Portably concatenate strings of the SQL strtoupper function. + */ +function db_strtoupper($field, $options = array()) { + if (empty($options['target'])) { + $options['target'] = 'default'; + } + return Database::getActiveConnection($options['target'])->upperCase($field); +} + +/** + * Return the SQL to generate a random number between 0.00 and 1.00. + * + * Use this function with following syntax: + * @code + * db_query("SELECT " . db_rand() . " AS num FROM {system}"); + * @endcode + * + * @param $options + * An array of options to control how the query operates. + * @return + * The SQL to generate a random number between 0.00 and 1.00. + */ +function db_rand($options = array()) { + if (empty($options['target'])) { + $options['target'] = 'default'; + } + return Database::getActiveConnection($options['target'])->random(); +} + +/** + * Return the portably concatenate strings of the SQL strlen function. + * + * Use this function with following syntax: + * @code + * db_query("SELECT " . db_strlen('name') . " FROM {system}"); + * @endcode + * + * @param $field + * Field for apply abstraction. + * @param $options + * An array of options to control how the query operates. + * @return + * Portably concatenate strings of the SQL strlen function. + */ +function db_strlen($field, $options = array()) { + if (empty($options['target'])) { + $options['target'] = 'default'; + } + return Database::getActiveConnection($options['target'])->length($field); +} + +/** + * Return the portably concatenate strings of the SQL substr function. + * + * Use this function with following syntax: + * @code + * db_query("SELECT " . db_substr('name', 1, 3) . " FROM {system}"); + * @endcode + * + * Be ware: both $start and $length should input as string in order to keep + * its formatting, as db_substr() will bypass it directly. For example, to + * handle the following SQL with db_substr(): + * @code + * SUBSTRING(thread, 1, (LENGTH(thread) - 1)) + * @endcode + * + * We should use the following syntax: + * @code + * db_substr('thread', 1, db_strlen('thread') . ' - 1') + * @endcode + * + * @param $field + * Field for apply abstraction. + * @param $start + * Starting position. + * @param $length + * Length of characters return. + * @param $options + * An array of options to control how the query operates. + * @return + * Portably concatenate strings of the SQL substr function. + */ +function db_substr($field, $start, $length = NULL, $options = array()) { + if (empty($options['target'])) { + $options['target'] = 'default'; + } + return Database::getActiveConnection($options['target'])->substr($field, $start, $length); +} + +/** + * Return the portably concatenate strings of the SQL strcat function. + * + * Use this function with following syntax: + * @code + * db_query("SELECT " . db_strcat("name", "module") . " FROM {system}"); + * @endcode + * + * @param $args + * An array of string parameters. + * @param $options + * An array of options to control how the query operates. + * @return + * Portably concatenate strings of the SQL strcat function. + */ +function db_strcat($args = array(), $options = array()) { + if (!is_array($args)) { + $args = func_get_args(); + $options = array(); + } + if (empty($options['target'])) { + $options['target'] = 'default'; + } + return Database::getActiveConnection($options['target'])->Concat($args); +} + +/** + * Returns a string that is the equivalent of MySQL IFNULL or Oracle NVL. + * + * Use this function with following syntax: + * @code + * db_query("SELECT " . db_if_null("name", "module") . " FROM {system}"); + * @endcode + * + * @param $options + * An array of options to control how the query operates. + * @return + * If $expr1 is not NULL, returns $expr1; otherwise it returns $expr2. + */ +function db_if_null($expr1, $expr2, $options = array()) { + if (empty($options['target'])) { + $options['target'] = 'default'; + } + return Database::getActiveConnection($options['target'])->IfNull($expr1, $expr2); +} + +/** * Execute an arbitrary query string against the active database. * * Do not use this function for INSERT, UPDATE, or DELETE queries. Those should Index: includes/database/mysql/database.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/database/mysql/database.inc,v retrieving revision 1.7 diff -u -p -r1.7 database.inc --- includes/database/mysql/database.inc 13 Nov 2008 21:02:09 -0000 1.7 +++ includes/database/mysql/database.inc 27 Nov 2008 07:45:33 -0000 @@ -14,6 +14,16 @@ class DatabaseConnection_mysql extends DatabaseConnection { protected $transactionSupport; + protected $nameQuote = '`'; + + public function Concat($args) { + $return = implode(', ', $args); + return (strlen($return) > 0) ? "CONCAT($return)" : ''; + } + + public function IfNull($expr1, $expr2) { + return " IFNULL($expr1, $expr2) "; + } public function __construct(Array $connection_options = array()) { Index: includes/database/pgsql/database.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/database/pgsql/database.inc,v retrieving revision 1.9 diff -u -p -r1.9 database.inc --- includes/database/pgsql/database.inc 13 Nov 2008 21:02:10 -0000 1.9 +++ includes/database/pgsql/database.inc 27 Nov 2008 07:45:33 -0000 @@ -14,6 +14,19 @@ class DatabaseConnection_pgsql extends DatabaseConnection { protected $transactionSupport; + protected $concat_operator = '||'; + + public function random() { + return 'RANDOM()'; + } + + public function substr($field, $start, $length = NULL) { + return 'SUBSTRING(' . implode(', ', array($field, $start, $length)) . ')'; + } + + public function IfNull($expr1, $expr2) { + return " COALESCE($expr1, $expr2) "; + } public function __construct(Array $connection_options = array()) { Index: modules/comment/comment.module =================================================================== RCS file: /cvs/drupal/drupal/modules/comment/comment.module,v retrieving revision 1.666 diff -u -p -r1.666 comment.module --- modules/comment/comment.module 23 Nov 2008 16:04:41 -0000 1.666 +++ modules/comment/comment.module 27 Nov 2008 07:45:34 -0000 @@ -375,10 +375,10 @@ function comment_new_page_count($num_com WHERE nid = :nid AND status = 0 ORDER BY timestamp DESC) - ORDER BY SUBSTRING(thread, 1, (LENGTH(thread) - 1))', array(':nid' => $node->nid), 0, $new_replies) + ORDER BY ' . db_substr('thread', 1, db_strlen('thread') . ' - 1'), array(':nid' => $node->nid), 0, $new_replies) ->fetchField(); $thread = substr($result, 0, -1); - $count = db_query('SELECT COUNT(*) FROM {comments} WHERE nid = :nid AND status = 0 AND SUBSTRING(thread, 1, (LENGTH(thread) - 1)) < :thread', array( + $count = db_query('SELECT COUNT(*) FROM {comments} WHERE nid = :nid AND status = 0 AND ' . db_substr('thread', 1, db_strlen('thread') . ' - 1') . '< :thread', array( ':nid' => $node->nid, ':thread' => $thread)) ->fetchField(); @@ -1028,7 +1028,8 @@ function comment_render($node, $cid = 0) // See comment above. Analysis reveals that this doesn't cost too // much. It scales much much better than having the whole comment // structure. - $query .= ' ORDER BY SUBSTRING(c.thread, 1, (LENGTH(c.thread) - 1))'; + // @todo: Revamp with DBTNG syntax. + $query .= ' ORDER BY ' . db_substr('c.thread', 1, db_strlen('c.thread') . ' - 1'); } $query = db_rewrite_sql($query, 'c', 'cid'); Index: modules/forum/forum.module =================================================================== RCS file: /cvs/drupal/drupal/modules/forum/forum.module,v retrieving revision 1.473 diff -u -p -r1.473 forum.module --- modules/forum/forum.module 11 Nov 2008 16:49:37 -0000 1.473 +++ modules/forum/forum.module 27 Nov 2008 07:45:34 -0000 @@ -586,7 +586,8 @@ function forum_get_forums($tid = 0) { // This query does not use full ANSI syntax since MySQL 3.x does not support // table1 INNER JOIN table2 INNER JOIN table3 ON table2_criteria ON table3_criteria // used to join node_comment_statistics to users. - $sql = "SELECT ncs.last_comment_timestamp, IF (ncs.last_comment_uid != 0, u2.name, ncs.last_comment_name) AS last_comment_name, ncs.last_comment_uid FROM {node} n INNER JOIN {users} u1 ON n.uid = u1.uid INNER JOIN {term_node} tn ON n.vid = tn.vid INNER JOIN {node_comment_statistics} ncs ON n.nid = ncs.nid INNER JOIN {users} u2 ON ncs.last_comment_uid=u2.uid WHERE n.status = 1 AND tn.tid = %d ORDER BY ncs.last_comment_timestamp DESC"; + // @todo: Revamp with DBTNG syntax. + $sql = "SELECT ncs.last_comment_timestamp, " . db_if_null("ncs.last_comment_name", "u2.name") . " AS last_comment_name, ncs.last_comment_uid FROM {node} n INNER JOIN {users} u1 ON n.uid = u1.uid INNER JOIN {term_node} tn ON n.vid = tn.vid INNER JOIN {node_comment_statistics} ncs ON n.nid = ncs.nid INNER JOIN {users} u2 ON ncs.last_comment_uid=u2.uid WHERE n.status = 1 AND tn.tid = %d ORDER BY ncs.last_comment_timestamp DESC"; $sql = db_rewrite_sql($sql); $topic = db_fetch_object(db_query_range($sql, $forum->tid, 0, 1)); @@ -632,7 +633,8 @@ function forum_get_topics($tid, $sortby, } } - $sql = db_rewrite_sql("SELECT n.nid, r.tid, n.title, n.type, n.sticky, u.name, u.uid, n.created AS timestamp, n.comment AS comment_mode, l.last_comment_timestamp, IF(l.last_comment_uid != 0, cu.name, l.last_comment_name) AS last_comment_name, l.last_comment_uid, l.comment_count AS num_comments, f.tid AS forum_tid FROM {node_comment_statistics} l INNER JOIN {node} n ON n.nid = l.nid INNER JOIN {users} cu ON l.last_comment_uid = cu.uid INNER JOIN {term_node} r ON n.vid = r.vid INNER JOIN {users} u ON n.uid = u.uid INNER JOIN {forum} f ON n.vid = f.vid WHERE n.status = 1 AND r.tid = %d"); + // @todo: Revamp with DBTNG syntax. + $sql = db_rewrite_sql("SELECT n.nid, r.tid, n.title, n.type, n.sticky, u.name, u.uid, n.created AS timestamp, n.comment AS comment_mode, l.last_comment_timestamp, " . db_if_null("l.last_comment_name", "cu.name") . " AS last_comment_name, l.last_comment_uid, l.comment_count AS num_comments, f.tid AS forum_tid FROM {node_comment_statistics} l INNER JOIN {node} n ON n.nid = l.nid INNER JOIN {users} cu ON l.last_comment_uid = cu.uid INNER JOIN {term_node} r ON n.vid = r.vid INNER JOIN {users} u ON n.uid = u.uid INNER JOIN {forum} f ON n.vid = f.vid WHERE n.status = 1 AND r.tid = %d"); $sql .= tablesort_sql($forum_topic_list_header, 'n.sticky DESC,'); $sql .= ', n.created DESC'; // Always add a secondary sort order so that the news forum topics are on top. Index: modules/locale/locale.module =================================================================== RCS file: /cvs/drupal/drupal/modules/locale/locale.module,v retrieving revision 1.232 diff -u -p -r1.232 locale.module --- modules/locale/locale.module 23 Nov 2008 16:00:06 -0000 1.232 +++ modules/locale/locale.module 27 Nov 2008 07:45:34 -0000 @@ -377,8 +377,15 @@ function locale($string = NULL, $langcod // Refresh database stored cache of translations for given language. // We only store short strings used in current version, to improve // performance and consume less memory. - $result = db_query("SELECT s.source, t.translation, t.language FROM {locales_source} s LEFT JOIN {locales_target} t ON s.lid = t.lid AND t.language = '%s' WHERE s.textgroup = 'default' AND s.version = '%s' AND LENGTH(s.source) < 75", $langcode, VERSION); - while ($data = db_fetch_object($result)) { + $query = db_select('locales_source', 's'); + $query->leftJoin('locales_target', 't', 's.lid = t.lid AND t.language = :language', array(':language' => $langcode)); + $query->fields('s', array('source')); + $query->fields('t', array('translation', 'language')); + $query->condition('s.textgroup', 'DEFAULT'); + $query->condition('s.version', VERSION); + $query->condition(db_strlen('s.source'), '75', '<'); + $result = $query->execute(); + foreach ($result as $data) { $locale_t[$langcode][$data->source] = (empty($data->translation) ? TRUE : $data->translation); } cache_set('locale:' . $langcode, $locale_t[$langcode]); Index: modules/statistics/statistics.admin.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/statistics/statistics.admin.inc,v retrieving revision 1.14 diff -u -p -r1.14 statistics.admin.inc --- modules/statistics/statistics.admin.inc 13 Oct 2008 00:33:04 -0000 1.14 +++ modules/statistics/statistics.admin.inc 27 Nov 2008 07:45:34 -0000 @@ -83,7 +83,8 @@ function statistics_top_visitors() { ); $sql = "SELECT COUNT(a.uid) AS hits, a.uid, u.name, a.hostname, SUM(a.timer) AS total, bl.iid FROM {accesslog} a LEFT JOIN {blocked_ips} bl ON a.hostname = bl.ip LEFT JOIN {users} u ON a.uid = u.uid GROUP BY a.hostname, a.uid, u.name, bl.iid" . tablesort_sql($header); - $sql_cnt = "SELECT COUNT(DISTINCT(CONCAT(uid, hostname))) FROM {accesslog}"; + // @todo: Revamp with DBTNG syntax. + $sql_cnt = "SELECT COUNT(DISTINCT(" . db_strcat('uid', 'hostname') . ")) FROM {accesslog}"; $result = pager_query($sql, 30, 0, $sql_cnt); $rows = array(); Index: modules/system/system.install =================================================================== RCS file: /cvs/drupal/drupal/modules/system/system.install,v retrieving revision 1.288 diff -u -p -r1.288 system.install --- modules/system/system.install 25 Nov 2008 13:16:39 -0000 1.288 +++ modules/system/system.install 27 Nov 2008 07:45:34 -0000 @@ -305,37 +305,6 @@ function system_install() { if (!db_result(db_query("SELECT COUNT(*) FROM pg_constraint WHERE conname = 'bigint_unsigned_check'"))) { db_query("CREATE DOMAIN bigint_unsigned bigint CHECK (VALUE >= 0)"); } - - // Create functions. - db_query('CREATE OR REPLACE FUNCTION "greatest"(numeric, numeric) RETURNS numeric AS - \'SELECT CASE WHEN (($1 > $2) OR ($2 IS NULL)) THEN $1 ELSE $2 END;\' - LANGUAGE \'sql\'' - ); - db_query('CREATE OR REPLACE FUNCTION "greatest"(numeric, numeric, numeric) RETURNS numeric AS - \'SELECT greatest($1, greatest($2, $3));\' - LANGUAGE \'sql\'' - ); - if (!db_result(db_query("SELECT COUNT(*) FROM pg_proc WHERE proname = 'rand'"))) { - db_query('CREATE OR REPLACE FUNCTION "rand"() RETURNS float AS - \'SELECT random();\' - LANGUAGE \'sql\'' - ); - } - - if (!db_result(db_query("SELECT COUNT(*) FROM pg_proc WHERE proname = 'concat'"))) { - db_query('CREATE OR REPLACE FUNCTION "concat"(text, text) RETURNS text AS - \'SELECT $1 || $2;\' - LANGUAGE \'sql\'' - ); - } - db_query('CREATE OR REPLACE FUNCTION "if"(boolean, text, text) RETURNS text AS - \'SELECT CASE WHEN $1 THEN $2 ELSE $3 END;\' - LANGUAGE \'sql\'' - ); - db_query('CREATE OR REPLACE FUNCTION "if"(boolean, integer, integer) RETURNS integer AS - \'SELECT CASE WHEN $1 THEN $2 ELSE $3 END;\' - LANGUAGE \'sql\'' - ); } // Create tables. @@ -3143,6 +3112,27 @@ function system_update_7015() { } /** + * Discontinue some legacy PostgreSQL custom function abstraction. + */ +function system_update_7016() { + $ret = array(); + if (db_driver() == 'pgsql') { + // GREATEST is build-in supported since PostgreSQL 8.1 (our minimal + // requirement). + $ret[] = update_sql('DROP FUNCTION IF EXISTS "greatest"(numeric, numeric)'); + $ret[] = update_sql('DROP FUNCTION IF EXISTS "greatest"(numeric, numeric, numeric)'); + // RAND() is now abstract with db_rand(). + $ret[] = update_sql('DROP FUNCTION IF EXISTS "rand"()'); + // CONCAT() is now abstract with db_strcat(). + $ret[] = update_sql('DROP FUNCTION IF EXISTS "concat"(text, text)'); + // IF() is now replace with db_if_null. + $ret[] = update_sql('DROP FUNCTION IF EXISTS "if"(boolean, text, text)'); + $ret[] = update_sql('DROP FUNCTION IF EXISTS "if"(boolean, integer, integer)'); + } + return $ret; +} + +/** * @} End of "defgroup updates-6.x-to-7.x" * The next series of updates should start at 8000. */