Index: includes/tablesort.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/tablesort.inc,v
retrieving revision 1.48
diff -u -p -r1.48 tablesort.inc
--- includes/tablesort.inc	14 Apr 2008 17:48:33 -0000	1.48
+++ includes/tablesort.inc	28 Sep 2008 16:44:06 -0000
@@ -40,7 +40,7 @@ function tablesort_sql($header, $before 
   $ts = tablesort_init($header);
   if ($ts['sql']) {
     // Based on code from db_escape_table(), but this can also contain a dot.
-    $field = preg_replace('/[^A-Za-z0-9_.]+/', '', $ts['sql']);
+    $field = preg_replace('/[^A-Za-z0-9_.\[\]]+/', '', db_escape_constraint($ts['sql']));
 
     // Sort order can only be ASC or DESC.
     $sort = drupal_strtoupper($ts['sort']);
Index: includes/database/database.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/database/database.inc,v
retrieving revision 1.9
diff -u -p -r1.9 database.inc
--- includes/database/database.inc	28 Sep 2008 00:03:33 -0000	1.9
+++ includes/database/database.inc	28 Sep 2008 16:44:06 -0000
@@ -162,6 +162,59 @@ abstract class DatabaseConnection extend
    */
   protected $logger = NULL;
 
+  /**
+   * Drupal provides the following functions for portably generating SQL
+   * functions as strings to be merged into your SQL statements.
+   *
+   * Most implementation reference from ADOdb
+   *
+   * @link http://phplens.com/lens/adodb/tips_portable_sql.htm
+   */
+
+  /**
+   * String to use to quote identifiers and names.
+   */
+  protected $nameQuote = '"';
+
+  /**
+   * Default concat operator. Change to || for Oracle/Interbase.
+   */
+  protected $concat_operator = '+';
+
+  /**
+   * Uppercase function.
+   */
+  public $upperCase = 'UPPER';
+
+  /**
+   * Random function.
+   */
+  public $random = 'RAND()';
+
+  /**
+   * String length operator.
+   */
+  public $length = 'LENGTH';
+
+  /**
+   * Substring operator.
+   */
+  public $substr = 'SUBSTR';
+
+  /**
+   * 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()) {
     $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);
@@ -265,6 +318,23 @@ abstract class DatabaseConnection extend
   }
 
   /**
+   * Replace all quote characters in a query.
+   *
+   * 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 replaceQuotes($sql) {
+    return strtr($sql, array('[' => $this->nameQuote, ']' => $this->nameQuote));
+  }
+
+  /**
    * Prepare a query string and return the prepared statement.
    *
    * This method statically caches prepared statements, reusing them when
@@ -279,6 +349,7 @@ abstract class DatabaseConnection extend
   protected function prepareQuery($query) {
     static $statements = array();
     $query = self::prefixTables($query);
+    $query = self::replaceQuotes($query);
     if (empty($statements[$query])) {
       $statements[$query] = parent::prepare($query);
     }
@@ -417,6 +488,11 @@ abstract class DatabaseConnection extend
       }
     }
     catch (PDOException $e) {
+      // TODO: remove debug
+      openlog("siren", LOG_PID | LOG_PERROR, LOG_LOCAL0);
+      syslog(LOG_ERR, "PDOException: " . $query);
+      closelog();
+
       if (!function_exists('module_implements')) {
         _db_need_install();
       }
@@ -571,6 +647,30 @@ abstract class DatabaseConnection extend
   }
 
   /**
+   * Escapes a constraint name string.
+   *
+   * Force all constraint names as reserved word safe with quote characters.
+   * The generic quote characters will further more replace as
+   * database-specific quote characters.
+   *
+   * @return
+   *   The sanitized constraint name string.
+   */
+  public function escapeConstraint($field) {
+    // Check if already come with [], or else escape it.
+    if (!strstr($field, '[') && !strstr($field, ']')) {
+      if (strstr($field, '.')) {
+        $field = preg_replace('/(.*)\.([A-Za-z0-9_]+)/', '\1.[\2]', $field);
+      }
+      else {
+        $field = preg_replace('/([A-Za-z0-9_]+)/', '[\1]', $field);
+      }
+    }
+
+    return $field;
+  }
+
+  /**
    * Returns a new DatabaseTransaction object on this connection.
    *
    * @param $required
@@ -1326,6 +1426,58 @@ class DatabaseStatement extends PDOState
  */
 
 /**
+ * Return the name of the SQL strtoupper function.
+ */
+function db_strtoupper() {
+  return Database::getActiveConnection()->upperCase;
+}
+
+/**
+ * Return the SQL to generate a random number between 0.00 and 1.00.
+ */
+function db_rand() {
+  return Database::getActiveConnection()->random;
+}
+
+/**
+ * Return the name of the SQL strlen function.
+ */
+function db_strlen() {
+  return Database::getActiveConnection()->length;
+}
+
+/**
+ * Return the name of the SQL substr function.
+ */
+function db_substr() {
+  return Database::getActiveConnection()->substr;
+}
+
+/**
+ * Different SQL databases used different methods to combine strings together.
+ * This function provides a wrapper.
+ *
+ * @param ...
+ *   Variable number of string parameters.
+ * @return
+ *   Portably concatenate strings.
+ */
+function db_strcat() {
+  $args = func_get_args();
+  return Database::getActiveConnection()->concat($args);
+}
+
+/**
+ * Returns a string that is the equivalent of MySQL IFNULL or Oracle NVL.
+ *
+ * @return
+ *   If $expr1 is not NULL, returns $expr1; otherwise it returns $expr2.
+ */
+function db_if_null($expr1, $expr2) {
+  return Database::getActiveConnection()->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
@@ -1548,6 +1700,18 @@ function db_escape_table($table) {
 }
 
 /**
+ * Restrict a dynamic table, column or constraint name as reserved word safe.
+ *
+ * @param $field
+ *   The field name to escape.
+ * @return
+ *   The escaped field name as a string.
+ */
+function db_escape_constraint($field) {
+  return Database::getActiveConnection()->escapeConstraint($field);
+}
+
+/**
  * Perform an SQL query and return success or failure.
  *
  * @param $sql
@@ -1683,7 +1847,7 @@ function db_type_placeholder($type) {
     case 'char':
     case 'text':
     case 'datetime':
-      return '\'%s\'';
+      return '%s';
 
     case 'numeric':
       // Numeric values are arbitrary precision numbers.  Syntacically, numerics
@@ -2033,6 +2197,22 @@ function _db_query_process_args($query, 
     $options['target'] = 'default';
   }
 
+  // TODO: remove debug
+  openlog("siren", LOG_PID | LOG_PERROR, LOG_LOCAL0);
+  if (preg_match('/[^\[\'{a-z0-9_:]([a-z0-9_{}]{3,})[^\]\'}a-z0-9_]/Ds', $query, $matches) && !preg_match('/[0-9]/', $matches[1])) {
+    syslog(LOG_ERR, "No []: " . $query);
+  }
+  if (preg_match("/'%s'/", $query)) {
+    syslog(LOG_ERR, "OLD '%s': " . $query);
+  }
+  if (preg_match("/!=/", $query)) {
+    syslog(LOG_ERR, "OLD !=: " . $query);
+  }
+  if (preg_match("/[ ,]''[ ,]/", $query)) {
+    syslog(LOG_ERR, "EMPTY STRING '': " . $query);
+  }
+  closelog();
+
   // Temporary backward-compatibliity hacks.  Remove later.
   $old_query = $query;
   $query = str_replace(array('%n', '%d', '%f', '%b', "'%s'", '%s'), '?', $old_query);
Index: includes/database/query.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/database/query.inc,v
retrieving revision 1.3
diff -u -p -r1.3 query.inc
--- includes/database/query.inc	15 Sep 2008 05:00:48 -0000	1.3
+++ includes/database/query.inc	28 Sep 2008 16:44:06 -0000
@@ -416,7 +416,7 @@ class InsertQuery extends Query {
     $placeholders = array_pad($placeholders, count($this->defaultFields), 'default');
     $placeholders = array_pad($placeholders, count($this->insertFields), '?');
 
-    return 'INSERT INTO {'. $this->table .'} ('. implode(', ', $insert_fields) .') VALUES ('. implode(', ', $placeholders) .')';
+    return 'INSERT INTO [{' . $this->table . '}] ([' . implode('], [', $insert_fields) . ']) VALUES (' . implode(', ', $placeholders) . ')';
   }
 }
 
@@ -751,7 +751,7 @@ class DeleteQuery extends Query implemen
   }
 
   public function __toString() {
-    $query = 'DELETE FROM {' . $this->connection->escapeTable($this->table) . '} ';
+    $query = 'DELETE FROM [{' . $this->connection->escapeTable($this->table) . '}] ';
 
     if (count($this->condition)) {
       $this->condition->compile($this->connection);
@@ -919,16 +919,16 @@ class UpdateQuery extends Query implemen
     $fields = $this->fields;
     $update_fields = array();
     foreach ($this->expressionFields as $field => $data) {
-      $update_fields[] = $field . '=' . $data['expression'];
+      $update_fields[] = '[' . $field . '] = ' . $data['expression'];
       unset($fields[$field]);
     }
 
     $max_placeholder = 0;
     foreach ($fields as $field => $value) {
-      $update_fields[] = $field . '=:db_update_placeholder_' . ($max_placeholder++);
+      $update_fields[] = '[' . $field . '] = :db_update_placeholder_' . ($max_placeholder++);
     }
 
-    $query = 'UPDATE {' . $this->connection->escapeTable($this->table) . '} SET ' . implode(', ', $update_fields);
+    $query = 'UPDATE [{' . $this->connection->escapeTable($this->table) . '}] SET ' . implode(', ', $update_fields);
 
     if (count($this->condition)) {
       $this->condition->compile($this->connection);
@@ -1060,7 +1060,7 @@ class DatabaseCondition implements Query
               $arguments[$placeholder] = $value;
               $placeholders[] = $placeholder;
             }
-            $condition_fragments[] = ' (' . $condition['field'] . ' ' . $operator['operator'] . ' ' . $operator['prefix'] . implode($operator['delimiter'], $placeholders) . $operator['postfix'] . ') ';
+            $condition_fragments[] = ' (' . db_escape_constraint($condition['field']) . ' ' . $operator['operator'] . ' ' . $operator['prefix'] . implode($operator['delimiter'], $placeholders) . $operator['postfix'] . ') ';
 
           }
         }
Index: includes/database/select.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/database/select.inc,v
retrieving revision 1.4
diff -u -p -r1.4 select.inc
--- includes/database/select.inc	15 Sep 2008 05:00:48 -0000	1.4
+++ includes/database/select.inc	28 Sep 2008 16:44:06 -0000
@@ -628,10 +628,10 @@ class SelectQuery extends Query implemen
     // FIELDS and EXPRESSIONS
     $fields = array();
     foreach ($this->fields as $alias => $field) {
-      $fields[] = (isset($field['table']) ? $field['table'] . '.' : '') . $field['field'] . ' AS ' . $field['alias'];
+      $fields[] = (isset($field['table']) ? '[' . $field['table'] . '].' : '') . '[' . $field['field'] . '] AS [' . $field['alias'] . ']';
     }
     foreach ($this->expressions as $alias => $expression) {
-      $fields[] = $expression['expression'] . ' AS ' . $expression['alias'];
+      $fields[] = $expression['expression'] . ' AS [' . $expression['alias'] . ']';
     }
     $query .= implode(', ', $fields);
 
@@ -642,7 +642,7 @@ class SelectQuery extends Query implemen
       if (isset($table['join type'])) {
         $query .= $table['join type'] . ' JOIN ';
       }
-      $query .= '{' . $this->connection->escapeTable($table['table']) . '} AS ' . $table['alias'];
+      $query .= '[{' . $this->connection->escapeTable($table['table']) . '}] AS [' . $table['alias'] . ']';
       if (!empty($table['condition'])) {
         $query .= ' ON ' . $table['condition'];
       }
Index: includes/database/mysql/database.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/database/mysql/database.inc,v
retrieving revision 1.3
diff -u -p -r1.3 database.inc
--- includes/database/mysql/database.inc	21 Sep 2008 15:27:20 -0000	1.3
+++ includes/database/mysql/database.inc	28 Sep 2008 16:44:06 -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()) {
 
@@ -36,12 +46,12 @@ class DatabaseConnection_mysql extends D
 
     // Enable MySQL's "strict mode", which removes most of MySQL's
     // "just be lazy" behaviors that end up causing more trouble than they're worth.
-    $this->exec('SET sql_mode=STRICT_ALL_TABLES');
+    $this->exec('SET SQL_MODE = STRICT_ALL_TABLES');
   }
 
   public function queryRange($query, Array $args, $from, $count, Array $options) {
     // Backward compatibility hack, temporary.
-    $query = str_replace(array('%d' , '%f' , '%b' , "'%s'"), '?', $query);
+    $query = str_replace(array('%n', '%d', '%f', '%b', "'%s'", '%s'), '?', $query);
 
     return $this->query($query . ' LIMIT ' . $from . ', ' . $count, $args, $options);
   }
@@ -83,7 +93,6 @@ class DatabaseConnection_mysql extends D
   }
 }
 
-
 /**
  * @} End of "ingroup database".
  */
Index: includes/database/mysql/query.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/database/mysql/query.inc,v
retrieving revision 1.3
diff -u -p -r1.3 query.inc
--- includes/database/mysql/query.inc	27 Sep 2008 20:10:26 -0000	1.3
+++ includes/database/mysql/query.inc	28 Sep 2008 16:44:06 -0000
@@ -41,7 +41,7 @@ class InsertQuery_mysql extends InsertQu
     // Default fields are always placed first for consistency.
     $insert_fields = array_merge($this->defaultFields, $this->insertFields);
 
-    $query = "INSERT $delay INTO {" . $this->table . '} (' . implode(', ', $insert_fields) . ') VALUES ';
+    $query = "INSERT $delay INTO [{" . $this->table . '}] ([' . implode('], [', $insert_fields) . ']) VALUES ';
 
     $max_placeholder = 0;
     $values = array();
@@ -135,7 +135,7 @@ class MergeQuery_mysql extends MergeQuer
 
     $insert_fields = $this->insertFields + $this->keyFields;
 
-    $query = "INSERT INTO {" . $this->table . '} (' . implode(', ', array_keys($insert_fields)) . ') VALUES ';
+    $query = "INSERT INTO [{" . $this->table . '}] ([' . implode('], [', array_keys($insert_fields)) . ']) VALUES ';
 
     $max_placeholder = 0;
     $values = array();
@@ -151,7 +151,7 @@ class MergeQuery_mysql extends MergeQuer
     $max_placeholder = 0;
     $update = array();
     foreach ($this->expressionFields as $field => $data) {
-      $update[] = $field . '=' . $data['expression'];
+      $update[] = '[' . $field . '] = ' . $data['expression'];
       unset($update_fields[$field]);
     }
 
@@ -159,10 +159,10 @@ class MergeQuery_mysql extends MergeQuer
     // from insert supplied values using the VALUES(col_name) function.
     foreach ($update_fields as $field => $value) {
       if ($this->updateFields) {
-        $update[] = ($field . '=:db_update_placeholder_' . $max_placeholder++);
+        $update[] = ('[' . $field . '] = :db_update_placeholder_' . $max_placeholder++);
       }
       else {
-        $update[] = ($field . '=VALUES(' . $field . ')');
+        $update[] = ('[' . $field . '] = VALUES([' . $field . '])');
       }
     }
 
Index: includes/database/mysql/schema.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/database/mysql/schema.inc,v
retrieving revision 1.3
diff -u -p -r1.3 schema.inc
--- includes/database/mysql/schema.inc	19 Sep 2008 20:30:32 -0000	1.3
+++ includes/database/mysql/schema.inc	28 Sep 2008 16:44:06 -0000
@@ -6,7 +6,6 @@
  * Database schema code for MySQL database servers.
  */
 
-
 /**
  * @ingroup schemaapi
  * @{
@@ -22,7 +21,6 @@ class DatabaseSchema_mysql extends Datab
     return (bool) $this->connection->query("SHOW COLUMNS FROM {" . $this->connection->escapeTable($table) . "} LIKE '" . $this->connection->escapeTable($column) . "'", array(), array())->fetchField();
   }
 
-
   /**
    * Generate SQL to create a new table from a Drupal schema definition.
    *
@@ -38,7 +36,7 @@ class DatabaseSchema_mysql extends Datab
       $table['mysql_suffix'] = "/*!40100 DEFAULT CHARACTER SET UTF8 */";
     }
 
-    $sql = "CREATE TABLE {" . $name . "} (\n";
+    $sql = "CREATE TABLE [{" . $name . "}] (\n";
 
     // Add the SQL statement for each field.
     foreach ($table['fields'] as $field_name => $field) {
@@ -71,7 +69,11 @@ class DatabaseSchema_mysql extends Datab
    *   The field specification, as per the schema data structure format.
    */
   protected function createFieldSql($name, $spec) {
-    $sql = "`" . $name . "` " . $spec['mysql_type'];
+    $sql = "[" . $name . "] " . $spec['mysql_type'];
+
+    if (($spec['type'] == 'text') || ($spec['type'] == 'blob')) {
+      unset($spec['default']);
+    }
 
     if (isset($spec['length'])) {
       $sql .= '(' . $spec['length'] . ')';
@@ -81,7 +83,7 @@ class DatabaseSchema_mysql extends Datab
     }
 
     if (!empty($spec['unsigned'])) {
-      $sql .= ' unsigned';
+      $sql .= ' UNSIGNED';
     }
 
     if (!empty($spec['not null'])) {
@@ -89,7 +91,7 @@ class DatabaseSchema_mysql extends Datab
     }
 
     if (!empty($spec['auto_increment'])) {
-      $sql .= ' auto_increment';
+      $sql .= ' AUTO_INCREMENT';
     }
 
     if (isset($spec['default'])) {
@@ -173,23 +175,20 @@ class DatabaseSchema_mysql extends Datab
     return $map;
   }
 
-
-
-
   protected function createKeysSql($spec) {
     $keys = array();
 
     if (!empty($spec['primary key'])) {
-      $keys[] = 'PRIMARY KEY (' . $this->createKeysSqlHelper($spec['primary key']) . ')';
+      $keys[] = 'PRIMARY KEY (' . $this->createKeySql($spec['primary key']) . ')';
     }
     if (!empty($spec['unique keys'])) {
       foreach ($spec['unique keys'] as $key => $fields) {
-        $keys[] = 'UNIQUE KEY ' . $key .' ('. $this->createKeysSqlHelper($fields) . ')';
+        $keys[] = 'UNIQUE KEY [' . $key . '] (' . $this->createKeySql($fields) . ')';
       }
     }
     if (!empty($spec['indexes'])) {
       foreach ($spec['indexes'] as $index => $fields) {
-        $keys[] = 'INDEX ' . $index . ' (' . $this->createKeysSqlHelper($fields) . ')';
+        $keys[] = 'INDEX [' . $index . '] (' . $this->createKeySql($fields) . ')';
       }
     }
 
@@ -200,34 +199,21 @@ class DatabaseSchema_mysql extends Datab
     $ret = array();
     foreach ($fields as $field) {
       if (is_array($field)) {
-        $ret[] = $field[0] . '(' . $field[1] . ')';
-      }
-      else {
-        $ret[] = $field;
-      }
-    }
-    return implode(', ', $ret);
-  }
-
-  protected function createKeysSqlHelper($fields) {
-    $ret = array();
-    foreach ($fields as $field) {
-      if (is_array($field)) {
-        $ret[] = $field[0] . '(' . $field[1] . ')';
+        $ret[] = '[' . $field[0] . '] (' . $field[1] . ')';
       }
       else {
-        $ret[] = $field;
+        $ret[] = '[' . $field . ']';
       }
     }
     return implode(', ', $ret);
   }
 
   public function renameTable(&$ret, $table, $new_name) {
-    $ret[] = update_sql('ALTER TABLE {' . $table . '} RENAME TO {' . $new_name . '}');
+    $ret[] = update_sql('ALTER TABLE [{' . $table . '}] RENAME TO [{' . $new_name . '}]');
   }
 
   public function dropTable(&$ret, $table) {
-    $ret[] = update_sql('DROP TABLE {' . $table . '}');
+    $ret[] = update_sql('DROP TABLE [{' . $table . '}]');
   }
 
   public function addField(&$ret, $table, $field, $spec, $keys_new = array()) {
@@ -236,7 +222,7 @@ class DatabaseSchema_mysql extends Datab
       $fixnull = TRUE;
       $spec['not null'] = FALSE;
     }
-    $query = 'ALTER TABLE {' . $table . '} ADD ';
+    $query = 'ALTER TABLE [{' . $table . '}] ADD ';
     $query .= $this->createFieldSql($field, $this->processField($spec));
     if (count($keys_new)) {
       $query .= ', ADD ' . implode(', ADD ', $this->createKeysSql($keys_new));
@@ -244,7 +230,7 @@ class DatabaseSchema_mysql extends Datab
     $ret[] = update_sql($query);
     if (isset($spec['initial'])) {
       // All this because update_sql does not support %-placeholders.
-      $sql = 'UPDATE {' . $table . '} SET ' . $field . ' = ' . db_type_placeholder($spec['type']);
+      $sql = 'UPDATE [{' . $table . '}] SET [' . $field . '] = ' . db_type_placeholder($spec['type']);
       $result = db_query($sql, $spec['initial']);
       $ret[] = array('success' => $result !== FALSE, 'query' => check_plain($sql . ' (' . $spec['initial'] . ')'));
     }
@@ -255,7 +241,7 @@ class DatabaseSchema_mysql extends Datab
   }
 
   public function dropField(&$ret, $table, $field) {
-    $ret[] = update_sql('ALTER TABLE {' . $table . '} DROP ' . $field);
+    $ret[] = update_sql('ALTER TABLE [{' . $table . '}] DROP [' . $field . ']');
   }
 
   public function fieldSetDefault(&$ret, $table, $field, $default) {
@@ -266,40 +252,40 @@ class DatabaseSchema_mysql extends Datab
       $default = is_string($default) ? "'$default'" : $default;
     }
 
-    $ret[] = update_sql('ALTER TABLE {' . $table . '} ALTER COLUMN ' . $field . ' SET DEFAULT ' . $default);
+    $ret[] = update_sql('ALTER TABLE [{' . $table . '}] ALTER COLUMN [' . $field . '] SET DEFAULT ' . $default);
   }
 
   public function fieldSetNoDefault(&$ret, $table, $field) {
-    $ret[] = update_sql('ALTER TABLE {' . $table . '} ALTER COLUMN ' . $field . ' DROP DEFAULT');
+    $ret[] = update_sql('ALTER TABLE [{' . $table . '}] ALTER COLUMN [' . $field . '] DROP DEFAULT');
   }
 
   public function addPrimaryKey(&$ret, $table, $fields) {
-    $ret[] = update_sql('ALTER TABLE {' . $table . '} ADD PRIMARY KEY (' . $this->createKeySql($fields) . ')');
+    $ret[] = update_sql('ALTER TABLE [{' . $table . '}] ADD PRIMARY KEY (' . $this->createKeySql($fields) . ')');
   }
 
   public function dropPrimaryKey(&$ret, $table) {
-    $ret[] = update_sql('ALTER TABLE {' . $table . '} DROP PRIMARY KEY');
+    $ret[] = update_sql('ALTER TABLE [{' . $table . '}] DROP PRIMARY KEY');
   }
 
   public function addUniqueKey(&$ret, $table, $name, $fields) {
-    $ret[] = update_sql('ALTER TABLE {' . $table . '} ADD UNIQUE KEY ' . $name . ' (' . $this->createKeySql($fields) . ')');
+    $ret[] = update_sql('ALTER TABLE [{' . $table . '}] ADD UNIQUE KEY [' . $name . '] (' . $this->createKeySql($fields) . ')');
   }
 
   public function dropUniqueKey(&$ret, $table, $name) {
-    $ret[] = update_sql('ALTER TABLE {' . $table . '} DROP KEY ' . $name);
+    $ret[] = update_sql('ALTER TABLE [{' . $table . '}] DROP KEY [' . $name . ']');
   }
 
   public function addIndex(&$ret, $table, $name, $fields) {
-    $query = 'ALTER TABLE {' . $table . '} ADD INDEX ' . $name . ' (' . $this->createKeySql($fields) . ')';
+    $query = 'ALTER TABLE [{' . $table . '}] ADD INDEX [' . $name . '] (' . $this->createKeySql($fields) . ')';
     $ret[] = update_sql($query);
   }
 
   public function dropIndex(&$ret, $table, $name) {
-    $ret[] = update_sql('ALTER TABLE {' . $table . '} DROP INDEX ' . $name);
+    $ret[] = update_sql('ALTER TABLE [{' . $table . '}] DROP INDEX [' . $name . ']');
   }
 
   public function changeField(&$ret, $table, $field, $field_new, $spec, $keys_new = array()) {
-    $sql = 'ALTER TABLE {' . $table . '} CHANGE ' . $field . ' ' . $this->createFieldSql($field_new, $this->processField($spec));
+    $sql = 'ALTER TABLE [{' . $table . '}] CHANGE [' . $field . '] ' . $this->createFieldSql($field_new, $this->processField($spec));
     if (count($keys_new)) {
       $sql .= ', ADD ' . implode(', ADD ', $this->createKeysSql($keys_new));
     }
Index: includes/database/pgsql/database.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/database/pgsql/database.inc,v
retrieving revision 1.3
diff -u -p -r1.3 database.inc
--- includes/database/pgsql/database.inc	15 Sep 2008 20:48:07 -0000	1.3
+++ includes/database/pgsql/database.inc	28 Sep 2008 16:44:06 -0000
@@ -14,6 +14,13 @@
 class DatabaseConnection_pgsql extends DatabaseConnection {
 
   protected $transactionSupport;
+  protected $concat_operator = '||';
+  public $random = 'RANDOM()';
+  public $substr = 'SUBSTRING';
+
+  public function ifNull($expr1, $expr2) {
+    return " COALESCE($expr1, $expr2) ";
+  }
 
   public function __construct(Array $connection_options = array()) {
 
@@ -27,7 +34,10 @@ class DatabaseConnection_pgsql extends D
       $dsn .= ' port=' . $connection_options['port'];
     }
 
-    parent::__construct($dsn, $connection_options['username'], $connection_options['password'], array(PDO::ATTR_STRINGIFY_FETCHES => TRUE));
+    parent::__construct($dsn, $connection_options['username'], $connection_options['password'], array(
+      // Convert numeric values to strings when fetching.
+      PDO::ATTR_STRINGIFY_FETCHES => TRUE,
+    ));
   }
 
   public function query($query, Array $args = array(), $options = array()) {
@@ -77,7 +87,7 @@ class DatabaseConnection_pgsql extends D
 
   public function queryRange($query, Array $args, $from, $count, Array $options) {
     // Backward compatibility hack, temporary.
-    $query = str_replace(array('%d' , '%f' , '%b' , "'%s'"), '?', $query);
+    $query = str_replace(array('%n', '%d', '%f', '%b', "'%s'", '%s'), '?', $query);
 
     return $this->query($query . ' LIMIT ' . $count . ' OFFSET ' . $from, $args, $options);
   }
Index: includes/database/pgsql/query.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/database/pgsql/query.inc,v
retrieving revision 1.2
diff -u -p -r1.2 query.inc
--- includes/database/pgsql/query.inc	15 Sep 2008 20:48:07 -0000	1.2
+++ includes/database/pgsql/query.inc	28 Sep 2008 16:44:06 -0000
@@ -71,7 +71,7 @@ class InsertQuery_pgsql extends InsertQu
     // Default fields are always placed first for consistency.
     $insert_fields = array_merge($this->defaultFields, $this->insertFields);
 
-    $query = "INSERT INTO {" . $this->table . '} (' . implode(', ', $insert_fields) . ') VALUES ';
+    $query = "INSERT INTO [{" . $this->table . '}] ([' . implode('], [', $insert_fields) . ']) VALUES ';
 
     $max_placeholder = 0;
     $values = array();
Index: includes/database/pgsql/schema.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/database/pgsql/schema.inc,v
retrieving revision 1.2
diff -u -p -r1.2 schema.inc
--- includes/database/pgsql/schema.inc	15 Sep 2008 20:48:07 -0000	1.2
+++ includes/database/pgsql/schema.inc	28 Sep 2008 16:44:06 -0000
@@ -39,15 +39,15 @@ class DatabaseSchema_pgsql extends Datab
 
     $sql_keys = array();
     if (isset($table['primary key']) && is_array($table['primary key'])) {
-      $sql_keys[] = 'PRIMARY KEY (' . implode(', ', $table['primary key']) . ')';
+      $sql_keys[] = 'PRIMARY KEY ([' . implode('], [', $table['primary key']) . '])';
     }
     if (isset($table['unique keys']) && is_array($table['unique keys'])) {
       foreach ($table['unique keys'] as $key_name => $key) {
-        $sql_keys[] = 'CONSTRAINT {' . $name . '}_' . $key_name . '_key UNIQUE (' . implode(', ', $key) . ')';
+        $sql_keys[] = 'CONSTRAINT [{' . $name . '}_' . $key_name . '_key] UNIQUE ([' . implode('], [', $key) . '])';
       }
     }
 
-    $sql = "CREATE TABLE {" . $name . "} (\n\t";
+    $sql = "CREATE TABLE [{" . $name . "}] (\n\t";
     $sql .= implode(",\n\t", $sql_fields);
     if (count($sql_keys) > 0) {
       $sql .= ",\n\t";
@@ -78,17 +78,33 @@ class DatabaseSchema_pgsql extends Datab
    *    The field specification, as per the schema data structure format.
    */
   protected function createFieldSql($name, $spec) {
-    $sql = $name . ' ' . $spec['pgsql_type'];
+    $sql = '[' . $name . '] ' . $spec['pgsql_type'];
 
     if ($spec['type'] == 'serial') {
       unset($spec['not null']);
     }
+
+    // pgsql does not have unsigned types but supports constraints to
+    // restricted a signed field to be non-negative (e.g. CHECK (VALUE
+    // >= 0)).  system.module defines {,small,big}int_unsigned as the
+    // corresponding integer type with this constraint but does not do
+    // so for serial or numeric types.  It probably would have been
+    // cleaner to unify unsigned handling but, for now, we use the
+    // *int_unsigned types for int and otherwise apply a column
+    // constraint explicitly.
     if (!empty($spec['unsigned'])) {
-      if ($spec['type'] == 'serial') {
-        $sql .= " CHECK ($name >= 0)";
-      }
-      else {
-        $sql .= '_unsigned';
+      switch ($spec['type']) {
+        case 'int':
+        case 'serial':
+        case 'float':
+          $sql .= " CHECK ([$name] >= 0)";
+          break;
+        case 'numeric':
+          // handled below
+          break;
+        default:
+          // unsigned is not supported on other column types
+          break;
       }
     }
 
@@ -99,12 +115,17 @@ class DatabaseSchema_pgsql extends Datab
       $sql .= '(' . $spec['precision'] . ', ' . $spec['scale'] . ')';
     }
 
+    // For numeric columns this has to come after (precision,scale).
+    if ($spec['type'] == 'numeric' && !empty($spec['unsigned'])) {
+      $sql .= " CHECK ([$name] >= 0)";
+    }
+
     if (isset($spec['not null']) && $spec['not null']) {
       $sql .= ' NOT NULL';
     }
     if (isset($spec['default'])) {
       $default = is_string($spec['default']) ? "'" . $spec['default'] . "'" : $spec['default'];
-      $sql .= " default $default";
+      $sql .= " DEFAULT $default";
     }
 
     return $sql;
@@ -141,40 +162,40 @@ class DatabaseSchema_pgsql extends Datab
     // it much easier for modules (such as schema.module) to map
     // database types back into schema types.
     $map = array(
-      'varchar:normal' => 'varchar',
-      'char:normal' => 'character',
+      'varchar:normal'  => 'VARCHAR',
+      'char:normal'     => 'CHARACTER',
+
+      'text:tiny'       => 'TEXT',
+      'text:small'      => 'TEXT',
+      'text:medium'     => 'TEXT',
+      'text:big'        => 'TEXT',
+      'text:normal'     => 'TEXT',
+
+      'serial:tiny'     => 'SERIAL',
+      'serial:small'    => 'SERIAL',
+      'serial:medium'   => 'SERIAL',
+      'serial:big'      => 'BIGSERIAL',
+      'serial:normal'   => 'SERIAL',
+
+      'int:tiny'        => 'SMALLINT',
+      'int:small'       => 'SMALLINT',
+      'int:medium'      => 'INT',
+      'int:big'         => 'BIGINT',
+      'int:normal'      => 'INT',
+
+      'float:tiny'      => 'REAL',
+      'float:small'     => 'REAL',
+      'float:medium'    => 'REAL',
+      'float:big'       => 'DOUBLE PRECISION',
+      'float:normal'    => 'REAL',
+
+      'numeric:normal'  => 'NUMERIC',
+
+      'blob:big'        => 'BYTEA',
+      'blob:normal'     => 'BYTEA',
 
-      'text:tiny' => 'text',
-      'text:small' => 'text',
-      'text:medium' => 'text',
-      'text:big' => 'text',
-      'text:normal' => 'text',
-
-      'int:tiny' => 'smallint',
-      'int:small' => 'smallint',
-      'int:medium' => 'int',
-      'int:big' => 'bigint',
-      'int:normal' => 'int',
-
-      'float:tiny' => 'real',
-      'float:small' => 'real',
-      'float:medium' => 'real',
-      'float:big' => 'double precision',
-      'float:normal' => 'real',
-
-      'numeric:normal' => 'numeric',
-
-      'blob:big' => 'bytea',
-      'blob:normal' => 'bytea',
-
-      'datetime:normal' => 'timestamp',
-
-      'serial:tiny' => 'serial',
-      'serial:small' => 'serial',
-      'serial:medium' => 'serial',
-      'serial:big' => 'bigserial',
-      'serial:normal' => 'serial',
-      );
+      'datetime:normal' => 'TIMESTAMP',
+    );
     return $map;
   }
 
@@ -182,10 +203,10 @@ class DatabaseSchema_pgsql extends Datab
     $ret = array();
     foreach ($fields as $field) {
       if (is_array($field)) {
-        $ret[] = 'substr(' . $field[0] . ', 1, ' . $field[1] . ')';
+        $ret[] = 'SUBSTRING([' . $field[0] . '], 1, ' . $field[1] . ')';
       }
       else {
-        $ret[] = $field;
+        $ret[] = '[' . $field . ']';
       }
     }
     return implode(', ', $ret);
@@ -202,7 +223,7 @@ class DatabaseSchema_pgsql extends Datab
    *   The new name for the table.
    */
   function renameTable(&$ret, $table, $new_name) {
-    $ret[] = update_sql('ALTER TABLE {' . $table . '} RENAME TO {' . $new_name . '}');
+    $ret[] = update_sql('ALTER TABLE [{' . $table . '}] RENAME TO [{' . $new_name . '}]');
   }
 
   /**
@@ -214,7 +235,7 @@ class DatabaseSchema_pgsql extends Datab
    *   The table to be dropped.
    */
   public function dropTable(&$ret, $table) {
-    $ret[] = update_sql('DROP TABLE {' . $table . '}');
+    $ret[] = update_sql('DROP TABLE [{' . $table . '}]');
   }
 
   /**
@@ -246,17 +267,17 @@ class DatabaseSchema_pgsql extends Datab
       $fixnull = TRUE;
       $spec['not null'] = FALSE;
     }
-    $query = 'ALTER TABLE {' . $table . '} ADD COLUMN ';
+    $query = 'ALTER TABLE [{' . $table . '}] ADD COLUMN ';
     $query .= $this->_createFieldSql($field, $this->_processField($spec));
     $ret[] = update_sql($query);
     if (isset($spec['initial'])) {
       // All this because update_sql does not support %-placeholders.
-      $sql = 'UPDATE {' . $table . '} SET ' . $field . ' = ' . db_type_placeholder($spec['type']);
+      $sql = 'UPDATE [{' . $table . '}] SET [' . $field . '] = ' . db_type_placeholder($spec['type']);
       $result = db_query($sql, $spec['initial']);
       $ret[] = array('success' => $result !== FALSE, 'query' => check_plain($sql . ' (' . $spec['initial'] . ')'));
     }
     if ($fixnull) {
-      $ret[] = update_sql("ALTER TABLE {" . $table . "} ALTER $field SET NOT NULL");
+      $ret[] = update_sql("ALTER TABLE [{" . $table . "}] ALTER [$field] SET NOT NULL");
     }
     if (isset($new_keys)) {
       $this->_createKeys($ret, $table, $new_keys);
@@ -274,7 +295,7 @@ class DatabaseSchema_pgsql extends Datab
    *   The field to be dropped.
    */
   public function dropField(&$ret, $table, $field) {
-    $ret[] = update_sql('ALTER TABLE {' . $table . '} DROP COLUMN ' . $field);
+    $ret[] = update_sql('ALTER TABLE [{' . $table . '}] DROP COLUMN [' . $field . ']');
   }
 
   /**
@@ -297,7 +318,7 @@ class DatabaseSchema_pgsql extends Datab
       $default = is_string($default) ? "'$default'" : $default;
     }
 
-    $ret[] = update_sql('ALTER TABLE {' . $table . '} ALTER COLUMN ' . $field . ' SET DEFAULT ' . $default);
+    $ret[] = update_sql('ALTER TABLE [{' . $table . '}] ALTER COLUMN [' . $field . '] SET DEFAULT ' . $default);
   }
 
   /**
@@ -311,7 +332,7 @@ class DatabaseSchema_pgsql extends Datab
    *   The field to be altered.
    */
   public function fieldSetNoDefault(&$ret, $table, $field) {
-    $ret[] = update_sql('ALTER TABLE {' . $table . '} ALTER COLUMN ' . $field . ' DROP DEFAULT');
+    $ret[] = update_sql('ALTER TABLE [{' . $table . '}] ALTER COLUMN [' . $field . '] DROP DEFAULT');
   }
 
   /**
@@ -325,7 +346,7 @@ class DatabaseSchema_pgsql extends Datab
    *   Fields for the primary key.
    */
   public function addPrimaryKey(&$ret, $table, $fields) {
-    $ret[] = update_sql('ALTER TABLE {' . $table . '} ADD PRIMARY KEY (' . implode(',', $fields) . ')');
+    $ret[] = update_sql('ALTER TABLE [{' . $table . '}] ADD PRIMARY KEY ([' . implode('], [', $fields) . ')]');
   }
 
   /**
@@ -337,7 +358,7 @@ class DatabaseSchema_pgsql extends Datab
    *   The table to be altered.
    */
   public function dropPrimaryKey(&$ret, $table) {
-    $ret[] = update_sql('ALTER TABLE {' . $table . '} DROP CONSTRAINT {' . $table . '}_pkey');
+    $ret[] = update_sql('ALTER TABLE [{' . $table . '}] DROP CONSTRAINT [{' . $table . '}_pkey]');
   }
 
   /**
@@ -354,7 +375,7 @@ class DatabaseSchema_pgsql extends Datab
    */
   function addUniqueKey(&$ret, $table, $name, $fields) {
     $name = '{' . $table . '}_' . $name . '_key';
-    $ret[] = update_sql('ALTER TABLE {' . $table . '} ADD CONSTRAINT ' . $name . ' UNIQUE (' . implode(',', $fields) . ')');
+    $ret[] = update_sql('ALTER TABLE [{' . $table . '}] ADD CONSTRAINT [' . $name . '] UNIQUE ([' . implode('], [', $fields) . '])');
   }
 
   /**
@@ -369,7 +390,7 @@ class DatabaseSchema_pgsql extends Datab
    */
   public function dropUniqueKey(&$ret, $table, $name) {
     $name = '{' . $table . '}_' . $name . '_key';
-    $ret[] = update_sql('ALTER TABLE {' . $table . '} DROP CONSTRAINT ' . $name);
+    $ret[] = update_sql('ALTER TABLE [{' . $table . '}] DROP CONSTRAINT [' . $name . ']');
   }
 
   /**
@@ -400,7 +421,7 @@ class DatabaseSchema_pgsql extends Datab
    */
   public function dropIndex(&$ret, $table, $name) {
     $name = '{' . $table . '}_' . $name . '_idx';
-    $ret[] = update_sql('DROP INDEX ' . $name);
+    $ret[] = update_sql('DROP INDEX [' . $name . ']');
   }
 
   /**
@@ -466,16 +487,16 @@ class DatabaseSchema_pgsql extends Datab
    *   table specification but without the 'fields' element.
    */
   public function changeField(&$ret, $table, $field, $field_new, $spec, $new_keys = array()) {
-    $ret[] = update_sql("ALTER TABLE {" . $table . "} RENAME $field TO " . $field . "_old");
+    $ret[] = update_sql("ALTER TABLE [{" . $table . "}] RENAME [$field] TO [" . $field . "_old]");
     $not_null = isset($spec['not null']) ? $spec['not null'] : FALSE;
     unset($spec['not null']);
 
     $this->addField($ret, $table, "$field_new", $spec);
 
-    $ret[] = update_sql("UPDATE {" . $table . "} SET $field_new = " . $field . "_old");
+    $ret[] = update_sql("UPDATE [{" . $table . "}] SET [$field_new] = [" . $field . "_old]");
 
     if ($not_null) {
-      $ret[] = update_sql("ALTER TABLE {" . $table . "} ALTER $field_new SET NOT NULL");
+      $ret[] = update_sql("ALTER TABLE [{" . $table . "}] ALTER [$field_new] SET NOT NULL");
     }
 
     $this->dropField($ret, $table, $field . '_old');
@@ -486,7 +507,7 @@ class DatabaseSchema_pgsql extends Datab
   }
 
   protected function _createIndexSql($table, $name, $fields) {
-    $query = 'CREATE INDEX {' . $table . '}_' . $name . '_idx ON {' . $table . '} (';
+    $query = 'CREATE INDEX [{' . $table . '}_' . $name . '_idx] ON [{' . $table . '}] (';
     $query .= $this->_createKeySql($fields) . ')';
     return $query;
   }
