? cvs_get_vanilla.sh
Index: database/database.pgsql
===================================================================
RCS file: /cvs/drupal/drupal/database/database.pgsql,v
retrieving revision 1.146
diff -u -p -r1.146 database.pgsql
--- database/database.pgsql	14 Nov 2005 22:23:11 -0000	1.146
+++ database/database.pgsql	24 Nov 2005 13:46:25 -0000
@@ -161,7 +161,7 @@ CREATE TABLE boxes (
 
 CREATE TABLE cache (
   cid varchar(255) NOT NULL default '',
-  data text default '',
+  data bytea default '',
   expire integer NOT NULL default '0',
   created integer NOT NULL default '0',
   headers text default '',
Index: database/updates.inc
===================================================================
RCS file: /cvs/drupal/drupal/database/updates.inc,v
retrieving revision 1.148
diff -u -p -r1.148 updates.inc
--- database/updates.inc	18 Nov 2005 14:05:38 -0000	1.148
+++ database/updates.inc	24 Nov 2005 13:46:26 -0000
@@ -104,8 +104,9 @@ $sql_updates = array(
   "2005-10-23" => "update_151",
   "2005-10-28" => "update_152",
   "2005-11-03" => "update_153",
-  "2005-11-14" => "update_154"
-);
+  "2005-11-14" => "update_154",
+  "2005-11-23" => "update_155",
+); // Please leave trailing , in the last line
 
 function update_110() {
   $ret = array();
@@ -1159,6 +1160,30 @@ function update_154() {
   return $ret;
 }
 
+function update_155() {
+  $ret = array();
+
+  // Postgresql only update
+  switch ($GLOBALS['db_type']) {
+    case 'pgsql':
+      $ret[] = update_sql("DROP TABLE {cache}");
+      $ret[] = update_sql("CREATE TABLE {cache} (
+        cid varchar(255) NOT NULL default '',
+        data bytea default '',
+        expire integer NOT NULL default '0',
+        created integer NOT NULL default '0',
+        headers text default '',
+        PRIMARY KEY (cid)
+        )");
+      $ret[] = update_sql("CREATE INDEX {cache}_expire_idx ON {cache}(expire)");
+      break;
+    case 'mysql':
+    case 'mysqli':
+      break;
+  }
+
+  return $ret;
+}
 
 
 /**
Index: includes/bootstrap.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/bootstrap.inc,v
retrieving revision 1.72
diff -u -p -r1.72 bootstrap.inc
--- includes/bootstrap.inc	21 Nov 2005 21:33:44 -0000	1.72
+++ includes/bootstrap.inc	24 Nov 2005 13:46:26 -0000
@@ -321,12 +321,10 @@ function cache_get($key) {
  *   A string containing HTTP header information for cached pages.
  */
 function cache_set($cid, $data, $expire = CACHE_PERMANENT, $headers = NULL) {
-  $data = db_encode_blob($data);
-
   db_lock_table('cache');
-  db_query("UPDATE {cache} SET data = '%s', created = %d, expire = %d, headers = '%s' WHERE cid = '%s'", $data, time(), $expire, $headers, $cid);
+  db_query("UPDATE {cache} SET data = %b, created = %d, expire = %d, headers = '%s' WHERE cid = '%s'", $data, time(), $expire, $headers, $cid);
   if (!db_affected_rows()) {
-    @db_query("INSERT INTO {cache} (cid, data, created, expire, headers) VALUES ('%s', '%s', %d, %d, '%s')", $cid, $data, time(), $expire, $headers);
+    @db_query("INSERT INTO {cache} (cid, data, created, expire, headers) VALUES ('%s', %b, %d, %d, '%s')", $cid, $data, time(), $expire, $headers);
   }
   db_unlock_tables();
 }
Index: includes/database.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/database.inc,v
retrieving revision 1.45
diff -u -p -r1.45 database.inc
--- includes/database.inc	12 Sep 2005 20:13:04 -0000	1.45
+++ includes/database.inc	24 Nov 2005 13:46:26 -0000
@@ -131,33 +131,62 @@ function db_set_active($name = 'default'
 }
 
 /**
+ * Helper function for db_query().
+ */
+function _db_query_callback($match, $init = FALSE) {
+  static $args = NULL;
+  if ($init) { 
+    $args = $match; 
+    return;
+  }
+  
+  switch ($match[1]) {
+    case '%%':
+      return '%'; 
+    case '%s': 
+      return db_escape_string(array_shift($args)); 
+    case '%d': // We must use type casting to int to convert false/null/(true?) 
+      return (int) array_shift($args); // We don't need db_escape_string as numbers are db-safe
+    case '%f': 
+      return (float) array_shift($args); 
+    case '%b': // binary data
+      return db_encode_blob(array_shift($args)); 
+  }
+}
+
+/**
  * Runs a basic query in the active database.
  *
- * User-supplied arguments to the query should be passed in as separate parameters
- * so that they can be properly escaped to avoid SQL injection attacks.
+ * User-supplied arguments to the query should be passed in as separate 
+ * parameters so that they can be properly escaped to avoid SQL injection 
+ * attacks.
  *
  * @param $query
  *   A string containing an SQL query.
  * @param ...
- *   A variable number of arguments which are substituted into the query using
- *   printf() syntax. Instead of a variable number of query arguments, you may
- *   also pass a single array containing the query arguments.
+ *   A variable number of arguments which are substituted into the query 
+ *   using printf() syntax. The query arguments can be enclosed in one 
+ *   array instead.
+ *   Valid %-modifiers are: %s, %d, %f, %b (binary data, do not enclose 
+ *   in '') and %%.
+ *
+ *   NOTE: Using this syntax will cast NULL and FALSE values to decimal 0,
+ *   and TRUE values to decimal 1.
+ *
  * @return
- *   A database query result resource, or FALSE if the query was not executed
- *   correctly.
+ *   A database query result resource, or FALSE if the query was not 
+ *   executed correctly.
  */
 function db_query($query) {
   $args = func_get_args();
+  array_shift($args); 
   $query = db_prefix_tables($query);
-  if (count($args) > 1) {
-    if (is_array($args[1])) {
-      $args = array_merge(array($query), $args[1]);
-    }
-    $args = array_map('db_escape_string', $args);
-    $args[0] = $query;
-    $query = call_user_func_array('sprintf', $args);
+  if (count($args) > 0) {
+    if (is_array($args[0])) { $args = $args[0]; }
   }
-  return _db_query($query);
+  _db_query_callback($args, TRUE);
+  $query = preg_replace_callback("/(%%|%s|%d|%f|%b)/", '_db_query_callback', $query);
+  return _db_query($query); 
 }
 
 /**
@@ -167,15 +196,13 @@ function db_query($query) {
  */
 function db_queryd($query) {
   $args = func_get_args();
+  array_shift($args); 
   $query = db_prefix_tables($query);
-  if (count($args) > 1) {
-    if (is_array($args[1])) {
-      $args = array_merge(array($query), $args[1]);
-    }
-    $args = array_map('db_escape_string', $args);
-    $args[0] = $query;
-    $query = call_user_func_array('sprintf', $args);
+  if (count($args) > 0) {
+    if (is_array($args[0])) { $args = $args[0]; }
   }
+  _db_query_callback($args, TRUE);
+  $query = preg_replace_callback("/(%%|%s|%d|%f|%b)/", '_db_query_callback', $query);
   return _db_query($query, 1);
 }
 
Index: includes/database.mysql.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/database.mysql.inc,v
retrieving revision 1.41
diff -u -p -r1.41 database.mysql.inc
--- includes/database.mysql.inc	21 Nov 2005 15:54:58 -0000	1.41
+++ includes/database.mysql.inc	24 Nov 2005 13:46:26 -0000
@@ -214,12 +214,23 @@ function db_affected_rows() {
  * User-supplied arguments to the query should be passed in as separate parameters
  * so that they can be properly escaped to avoid SQL injection attacks.
  *
+ * Note that if you need to know how many results were returned, you should do
+ * a SELECT COUNT(*) on the temporary table afterwards. db_num_rows() and
+ * db_affected_rows() do not give consistent result across different database
+ * types in this case.
+ *
  * @param $query
  *   A string containing an SQL query.
  * @param ...
- *   A variable number of arguments which are substituted into the query using
- *   printf() syntax. Instead of a variable number of query arguments, you may
- *   also pass a single array containing the query arguments.
+ *   A variable number of arguments which are substituted into the query 
+ *   using printf() syntax. The query arguments can be enclosed in one 
+ *   array instead.
+ *   Valid %-modifiers are: %s, %d, %f, %b (binary data, do not enclose 
+ *   in '') and %%.
+ *
+ *   NOTE: Using this syntax will cast NULL and FALSE values to decimal 0,
+ *   and TRUE values to decimal 1.
+ *
  * @param $from
  *   The first result row to return.
  * @param $count
@@ -232,17 +243,14 @@ function db_query_range($query) {
   $args = func_get_args();
   $count = array_pop($args);
   $from = array_pop($args);
+  array_shift($args);
 
   $query = db_prefix_tables($query);
-  if (count($args) > 1) {
-    // Check for array (alternative syntax).
-    if (is_array($args[1])) {
-      $args = array_merge(array($query), $args[1]);
-    }
-    $args = array_map('db_escape_string', $args);
-    $args[0] = $query;
-    $query = call_user_func_array('sprintf', $args);
+  if (count($args) > 0) {
+    if (is_array($args[0])) { $args = $args[0]; }
   }
+  _db_query_callback($args, TRUE);
+  $query = preg_replace_callback("/(%%|%s|%d|%f|%b)/", '_db_query_callback', $query);
   $query .= ' LIMIT '. $from .', '. $count;
   return _db_query($query);
 }
@@ -264,9 +272,15 @@ function db_query_range($query) {
  * @param $query
  *   A string containing a normal SELECT SQL query.
  * @param ...
- *   A variable number of arguments which are substituted into the query using
- *   printf() syntax. Instead of a variable number of query arguments, you may
- *   also pass a single array containing the query arguments.
+ *   A variable number of arguments which are substituted into the query 
+ *   using printf() syntax. The query arguments can be enclosed in one 
+ *   array instead.
+ *   Valid %-modifiers are: %s, %d, %f, %b (binary data, do not enclose 
+ *   in '') and %%.
+ *
+ *   NOTE: Using this syntax will cast NULL and FALSE values to decimal 0,
+ *   and TRUE values to decimal 1.
+ *
  * @param $table
  *   The name of the temporary table to select into. This name will not be
  *   prefixed as there is no risk of collision.
@@ -277,17 +291,14 @@ function db_query_range($query) {
 function db_query_temporary($query) {
   $args = func_get_args();
   $tablename = array_pop($args);
+  array_shift($args);
 
   $query = preg_replace('/^SELECT/i', 'CREATE TEMPORARY TABLE '. $tablename .' SELECT', db_prefix_tables($query));
-  if (count($args) > 1) {
-    // Check for array (alternative syntax).
-    if (is_array($args[1])) {
-      $args = array_merge(array($query), $args[1]);
-    }
-    $args = array_map('db_escape_string', $args);
-    $args[0] = $query;
-    $query = call_user_func_array('sprintf', $args);
+  if (count($args) > 0) {
+    if (is_array($args[0])) { $args = $args[0]; }
   }
+  _db_query_callback($args, TRUE);
+  $query = preg_replace_callback("/(%%|%s|%d|%f|%b)/", '_db_query_callback', $query);
   return _db_query($query);
 }
 
@@ -300,7 +311,7 @@ function db_query_temporary($query) {
  *  Encoded data.
  */
 function db_encode_blob($data) {
-  return $data;
+  return "'". mysql_real_escape_string($data) ."'";
 }
 
 /**
@@ -336,7 +347,6 @@ function db_unlock_tables() {
   db_query('UNLOCK TABLES');
 }
 
-
 /**
  * @} End of "ingroup database".
  */
Index: includes/database.mysqli.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/database.mysqli.inc,v
retrieving revision 1.5
diff -u -p -r1.5 database.mysqli.inc
--- includes/database.mysqli.inc	18 Nov 2005 14:03:55 -0000	1.5
+++ includes/database.mysqli.inc	24 Nov 2005 13:46:26 -0000
@@ -233,9 +233,15 @@ function db_affected_rows() {
  * @param $query
  *   A string containing an SQL query.
  * @param ...
- *   A variable number of arguments which are substituted into the query using
- *   printf() syntax. Instead of a variable number of query arguments, you may
- *   also pass a single array containing the query arguments.
+ *   A variable number of arguments which are substituted into the query 
+ *   using printf() syntax. The query arguments can be enclosed in one 
+ *   array instead.
+ *   Valid %-modifiers are: %s, %d, %f, %b (binary data, do not enclose 
+ *   in '') and %%.
+ *
+ *   NOTE: Using this syntax will cast NULL and FALSE values to decimal 0,
+ *   and TRUE values to decimal 1.
+ *
  * @param $from
  *   The first result row to return.
  * @param $count
@@ -248,17 +254,14 @@ function db_query_range($query) {
   $args = func_get_args();
   $count = array_pop($args);
   $from = array_pop($args);
+  array_shift($args);
 
   $query = db_prefix_tables($query);
-  if (count($args) > 1) {
-    // Check for array (alternative syntax).
-    if (is_array($args[1])) {
-      $args = array_merge(array($query), $args[1]);
-    }
-    $args = array_map('db_escape_string', $args);
-    $args[0] = $query;
-    $query = call_user_func_array('sprintf', $args);
+  if (count($args) > 0) {
+    if (is_array($args[0])) { $args = $args[0]; }
   }
+  _db_query_callback($args, TRUE);
+  $query = preg_replace_callback("/(%%|%s|%d|%f|%b)/", '_db_query_callback', $query);
   $query .= ' LIMIT '. $from .', '. $count;
   return _db_query($query);
 }
@@ -275,14 +278,20 @@ function db_query_range($query) {
  * Note that if you need to know how many results were returned, you should do
  * a SELECT COUNT(*) on the temporary table afterwards. db_num_rows() and
  * db_affected_rows() do not give consistent result across different database
- * types.
+ * types in this case.
  *
  * @param $query
  *   A string containing a normal SELECT SQL query.
  * @param ...
- *   A variable number of arguments which are substituted into the query using
- *   printf() syntax. Instead of a variable number of query arguments, you may
- *   also pass a single array containing the query arguments.
+ *   A variable number of arguments which are substituted into the query 
+ *   using printf() syntax. The query arguments can be enclosed in one 
+ *   array instead.
+ *   Valid %-modifiers are: %s, %d, %f, %b (binary data, do not enclose 
+ *   in '') and %%.
+ *
+ *   NOTE: Using this syntax will cast NULL and FALSE values to decimal 0,
+ *   and TRUE values to decimal 1.
+ *
  * @param $table
  *   The name of the temporary table to select into. This name will not be
  *   prefixed as there is no risk of collision.
@@ -293,17 +302,14 @@ function db_query_range($query) {
 function db_query_temporary($query) {
   $args = func_get_args();
   $tablename = array_pop($args);
+  array_shift($args);
 
   $query = preg_replace('/^SELECT/i', 'CREATE TEMPORARY TABLE '. $tablename .' SELECT', db_prefix_tables($query));
-  if (count($args) > 1) {
-    // Check for array (alternative syntax).
-    if (is_array($args[1])) {
-      $args = array_merge(array($query), $args[1]);
-    }
-    $args = array_map('db_escape_string', $args);
-    $args[0] = $query;
-    $query = call_user_func_array('sprintf', $args);
+  if (count($args) > 0) {
+    if (is_array($args[0])) { $args = $args[0]; }
   }
+  _db_query_callback($args, TRUE);
+  $query = preg_replace_callback("/(%%|%s|%d|%f|%b)/", '_db_query_callback', $query);
   return _db_query($query);
 }
 
@@ -316,7 +322,7 @@ function db_query_temporary($query) {
  *  Encoded data.
  */
 function db_encode_blob($data) {
-  return $data;
+  return "'". mysql_real_escape_string($data) ."'";
 }
 
 /**
@@ -339,7 +345,6 @@ function db_escape_string($text) {
   return mysqli_real_escape_string($active_db, $text);
 }
 
-
 /**
  * Lock a table.
  */
Index: includes/database.pgsql.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/database.pgsql.inc,v
retrieving revision 1.18
diff -u -p -r1.18 database.pgsql.inc
--- includes/database.pgsql.inc	21 Nov 2005 15:54:58 -0000	1.18
+++ includes/database.pgsql.inc	24 Nov 2005 13:46:26 -0000
@@ -202,9 +202,15 @@ function db_affected_rows() {
  * @param $query
  *   A string containing an SQL query.
  * @param ...
- *   A variable number of arguments which are substituted into the query using
- *   printf() syntax. Instead of a variable number of query arguments, you may
- *   also pass a single array containing the query arguments.
+ *   A variable number of arguments which are substituted into the query 
+ *   using printf() syntax. The query arguments can be enclosed in one 
+ *   array instead.
+ *   Valid %-modifiers are: %s, %d, %f, %b (binary data, do not enclose 
+ *   in '') and %%.
+ *
+ *   NOTE: Using this syntax will cast NULL and FALSE values to decimal 0,
+ *   and TRUE values to decimal 1.
+ *
  * @param $from
  *   The first result row to return.
  * @param $count
@@ -217,17 +223,14 @@ function db_query_range($query) {
   $args = func_get_args();
   $count = array_pop($args);
   $from = array_pop($args);
+  array_shift($args);
 
   $query = db_prefix_tables($query);
-  if (count($args) > 1) {
-    // Check for array (alternative syntax).
-    if (is_array($args[1])) {
-      $args = array_merge(array($query), $args[1]);
-    }
-    $args = array_map('db_escape_string', $args);
-    $args[0] = $query;
-    $query = call_user_func_array('sprintf', $args);
+  if (count($args) > 0) {
+    if (is_array($args[0])) { $args = $args[0]; }
   }
+  _db_query_callback($args, TRUE);
+  $query = preg_replace_callback("/(%%|%s|%d|%f|%b)/", '_db_query_callback', $query);
   $query .= ' LIMIT '. $count .' OFFSET '. $from;
   return _db_query($query);
 }
@@ -249,9 +252,15 @@ function db_query_range($query) {
  * @param $query
  *   A string containing a normal SELECT SQL query.
  * @param ...
- *   A variable number of arguments which are substituted into the query using
- *   printf() syntax. Instead of a variable number of query arguments, you may
- *   also pass a single array containing the query arguments.
+ *   A variable number of arguments which are substituted into the query 
+ *   using printf() syntax. The query arguments can be enclosed in one 
+ *   array instead.
+ *   Valid %-modifiers are: %s, %d, %f, %b (binary data, do not enclose 
+ *   in '') and %%.
+ *
+ *   NOTE: Using this syntax will cast NULL and FALSE values to decimal 0,
+ *   and TRUE values to decimal 1.
+ *
  * @param $table
  *   The name of the temporary table to select into. This name will not be
  *   prefixed as there is no risk of collision.
@@ -262,22 +271,20 @@ function db_query_range($query) {
 function db_query_temporary($query) {
   $args = func_get_args();
   $tablename = array_pop($args);
+  array_shift($args);
 
   $query = preg_replace('/^SELECT/i', 'CREATE TEMPORARY TABLE '. $tablename .' AS SELECT', db_prefix_tables($query));
-  if (count($args) > 1) {
-    // Check for array (alternative syntax).
-    if (is_array($args[1])) {
-      $args = array_merge(array($query), $args[1]);
-    }
-    $args = array_map('db_escape_string', $args);
-    $args[0] = $query;
-    $query = call_user_func_array('sprintf', $args);
+  if (count($args) > 0) {
+    if (is_array($args[0])) { $args = $args[0]; }
   }
+  _db_query_callback($args, TRUE);
+  $query = preg_replace_callback("/(%%|%s|%d|%f|%b)/", '_db_query_callback', $query);
   return _db_query($query);
 }
 
 /**
  * Returns a properly formatted Binary Large OBject value.
+ * In case of PostgreSQL encodes data for insert into bytea field.
  *
  * @param $data
  *   Data to encode.
@@ -285,11 +292,12 @@ function db_query_temporary($query) {
  *  Encoded data.
  */
 function db_encode_blob($data) {
-  return addcslashes($data, "\0..\37\\");
+  return "'". pg_escape_bytea($data) ."'";
 }
 
 /**
  * Returns text from a Binary Large OBject value.
+ * In case of PostgreSQL decodes data after select from bytea field.
  *
  * @param $data
  *   Data to decode.
@@ -297,7 +305,7 @@ function db_encode_blob($data) {
  *  Decoded data.
  */
 function db_decode_blob($data) {
-  return stripcslashes($data);
+  return pg_unescape_bytea($data);
 }
 
 /**
