From 29337ad8bbcf9388cf41e88193764cc2cb8b87f2 Mon Sep 17 00:00:00 2001
From: Dries Buytaert <dries@buytaert.net>
Date: Mon, 29 Nov 2004 13:13:29 +0000
Subject: [PATCH] - Patch #13581 by Steven: Db_query() allows a variable amount
 of parameters so you can pass the query arguments in. There is however an
 alternative syntax: instead of passing the query arguments as function
 arguments, you can also pass a single array with the query arguments in it.
 For example the following two statements are equivalent:

db_query($query, $a, $b, $c);
db_query($query, array($a, $b, $c));

This usage is particularly interesting when the query is constructed dynamically, and the amount of arguments to pass varies. In that case we use the second method to avoid using call_user_func_array(). This behaviour is not documented explicitly, but it is used in several places.

However, db_query_range() and pager_query() do not support this syntax properly, which means there are several pieces of code which still revert to the ugly call_user_func_array() call.

This patch updates db_query_range() and pager_query() so they support the array-passing method. I also added documentation about this method to each of the db functions.

I also cleaned up the code for db_query (it was weird and hard to understand) and moved db_query() and db_queryd() from database.xxxxx.inc to database.inc: it was the same between both mysql and pgsql, as it doesn't do anything database specific. It just prefixes the tables and inserts the arguments. The actual db query is performed in _db_query(), which is still in database.xxxxx.inc.

Finally, I updated several places with the new syntax, and the code is a lot cleaner. For example:
- array_unshift($params, "SELECT u.* FROM {users} u WHERE $query u.status < 3");
- $params[] = 0;
- $params[] = 1;
- $result = call_user_func_array('db_query_range', $params);
+ $result = db_query_range("SELECT u.* FROM {users} u WHERE $query u.status < 3", $params, 0, 1);

and

- return call_user_func_array('db_query_range', array_merge(array($query), $args, array((int)$pager_from_array[$element], (int)$limit)));
+ return db_query_range($query, $args, (int)$pager_from_array[$element], (int)$limit);

I've tested it on mysql. I didn't alter the actual db behaviour, so pgsql should be okay too.

This patch is important because many people avoid the call_user_func_array() method and put data directly into the db query.  This is very, very bad because the database prefix will be applied to it, and strip out braces. It's also generally bad form as you have to call check_query() yourself.  With the new, documented syntax, there is no more excuse to put data directly in the query.
---
 includes/database.inc        | 51 +++++++++++++++++++++++-
 includes/database.mysql.inc  | 75 +++++-------------------------------
 includes/database.pgsql.inc  | 75 +++++-------------------------------
 includes/pager.inc           | 10 +++--
 modules/filter.module        | 12 +++---
 modules/filter/filter.module | 12 +++---
 modules/search.module        |  5 +--
 modules/search/search.module |  5 +--
 modules/user.module          |  7 +---
 modules/user/user.module     |  7 +---
 10 files changed, 94 insertions(+), 165 deletions(-)

diff --git a/includes/database.inc b/includes/database.inc
index 7728611495b0..9b6d9b647da8 100644
--- a/includes/database.inc
+++ b/includes/database.inc
@@ -119,6 +119,55 @@ function db_set_active($name = 'default') {
   $active_db = $db_conns[$name];
 }
 
+/**
+ * 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.
+ *
+ * @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.
+ * @return
+ *   A database query result resource, or FALSE if the query was not executed
+ *   correctly.
+ */
+function db_query($query) {
+  $args = func_get_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);
+  }
+  return _db_query($query);
+}
+
+/**
+ * Debugging version of db_query().
+ *
+ * Echoes the query to the browser.
+ */
+function db_queryd($query) {
+  $args = func_get_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);
+  }
+  return _db_query($query, 1);
+}
+
 /**
  * @} End of "defgroup database".
  */
@@ -126,4 +175,4 @@ function db_set_active($name = 'default') {
 // Initialize the default database.
 db_set_active();
 
-?>
+?>
\ No newline at end of file
diff --git a/includes/database.mysql.inc b/includes/database.mysql.inc
index dbae5254d2f6..6b6a16399405 100644
--- a/includes/database.mysql.inc
+++ b/includes/database.mysql.inc
@@ -34,65 +34,6 @@ function db_connect($url) {
   return $connection;
 }
 
-/**
- * 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.
- *
- * @param $query
- *   A string containing an SQL query.
- * @param ...
- *   A variable number of arguments which are substituted into the query using
- *   printf() syntax.
- * @return
- *   A database query result resource, or FALSE if the query was not executed
- *   correctly.
- */
-function db_query($query) {
-  $args = func_get_args();
-
-  $query = db_prefix_tables($query);
-  if (count($args) > 1) {
-    if(is_array($args[1])){
-      $args1 = array_map('db_escape_string', $args[1]);
-      $nargs = array_merge(array($query), $args1);
-    }
-    else {
-      $nargs = array_map('db_escape_string', $args);
-      $nargs[0] = $query;
-    }
-    return _db_query(call_user_func_array('sprintf', $nargs));
-  }
-  else {
-    return _db_query($query);
-  }
-}
-
-/**
- * Debugging version of db_query().
- *
- * Echoes the query to the browser.
- */
-function db_queryd($query) {
-  $args = func_get_args();
-  $query = db_prefix_tables($query);
-  if (count($args) > 1) {
-    if(is_array($args[1])){
-      $args1 = array_map('db_escape_string', $args[1]);
-      $nargs = array_merge(array($query), $args1);
-    }
-    else {
-      $nargs = array_map('db_escape_string', $args);
-      $nargs[0] = $query;
-    }
-    return _db_query(call_user_func_array('sprintf', $nargs), 1);
-  }
-  else {
-    return _db_query($query, 1);
-  }
-}
-
 /**
  * Helper function for db_query().
  */
@@ -234,7 +175,8 @@ function db_affected_rows() {
  *   A string containing an SQL query.
  * @param ...
  *   A variable number of arguments which are substituted into the query using
- *   printf() syntax.
+ *   printf() syntax. Instead of a variable number of query arguments, you may
+ *   also pass a single array containing the query arguments.
  * @param $from
  *   The first result row to return.
  * @param $count
@@ -247,16 +189,17 @@ function db_query_range($query) {
   $args = func_get_args();
   $count = array_pop($args);
   $from = array_pop($args);
+
+  $query = db_prefix_tables($query);
   if (count(func_get_args()) > 3) {
+    // Check for array (alternative syntax).
+    if (is_array($args[1])) {
+      $args = array_merge(array($query), $args[1]);
+    }
     $args = array_map('db_escape_string', $args);
-    $query = db_prefix_tables($query);
     $args[0] = $query;
     $query = call_user_func_array('sprintf', $args);
   }
-  else {
-    $query = func_get_arg(0);
-    $query = db_prefix_tables($query);
-  }
   $query .= ' LIMIT '. $from .', '. $count;
   return _db_query($query);
 }
@@ -296,4 +239,4 @@ function db_escape_string($text) {
  * @} End of "ingroup database".
  */
 
-?>
+?>
\ No newline at end of file
diff --git a/includes/database.pgsql.inc b/includes/database.pgsql.inc
index 2d5399018ae2..a5c11cedd55d 100644
--- a/includes/database.pgsql.inc
+++ b/includes/database.pgsql.inc
@@ -30,65 +30,6 @@ function db_connect($url) {
   return $connection;
 }
 
-/**
- * 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.
- *
- * @param $query
- *   A string containing an SQL query.
- * @param ...
- *   A variable number of arguments which are substituted into the query using
- *   printf() syntax.
- * @return
- *   A database query result resource, or FALSE if the query was not executed
- *   correctly.
- */
-function db_query($query) {
-  $args = func_get_args();
-
-  $query = db_prefix_tables($query);
-  if (count($args) > 1) {
-    if(is_array($args[1])){
-      $args1 = array_map('db_escape_string', $args[1]);
-      $nargs = array_merge(array($query), $args1);
-    }
-    else {
-      $nargs = array_map('db_escape_string', $args);
-      $nargs[0] = $query;
-    }
-    return _db_query(call_user_func_array('sprintf', $nargs));
-  }
-  else {
-    return _db_query($query);
-  }
-}
-
-/**
- * Debugging version of db_query().
- *
- * Echoes the query to the browser.
- */
-function db_queryd($query) {
-  $args = func_get_args();
-  $query = db_prefix_tables($query);
-  if (count($args) > 1) {
-    if(is_array($args[1])){
-      $args1 = array_map('db_escape_string', $args[1]);
-      $nargs = array_merge(array($query), $args1);
-    }
-    else {
-      $nargs = array_map('db_escape_string', $args);
-      $nargs[0] = $query;
-    }
-    return _db_query(call_user_func_array('sprintf', $nargs), 1);
-  }
-  else {
-    return _db_query($query, 1);
-  }
-}
-
 /**
  * Helper function for db_query().
  */
@@ -228,7 +169,8 @@ function db_affected_rows() {
  *   A string containing an SQL query.
  * @param ...
  *   A variable number of arguments which are substituted into the query using
- *   printf() syntax.
+ *   printf() syntax. Instead of a variable number of query arguments, you may
+ *   also pass a single array containing the query arguments.
  * @param $from
  *   The first result row to return.
  * @param $count
@@ -241,16 +183,17 @@ function db_query_range($query) {
   $args = func_get_args();
   $count = array_pop($args);
   $from = array_pop($args);
+
+  $query = db_prefix_tables($query);
   if (count(func_get_args()) > 3) {
+    // Check for array (alternative syntax).
+    if (is_array($args[1])) {
+      $args = array_merge(array($query), $args[1]);
+    }
     $args = array_map('db_escape_string', $args);
-    $query = db_prefix_tables($query);
     $args[0] = $query;
     $query = call_user_func_array('sprintf', $args);
   }
-  else {
-    $query = func_get_arg(0);
-    $query = db_prefix_tables($query);
-  }
   $query .= ' LIMIT '. $count .' OFFSET '. $from;
   return _db_query($query);
 }
@@ -291,4 +234,4 @@ function db_escape_string($text) {
  * @} End of "ingroup database".
  */
 
-?>
+?>
\ No newline at end of file
diff --git a/includes/pager.inc b/includes/pager.inc
index 279dd3d61e10..855a913a5e66 100644
--- a/includes/pager.inc
+++ b/includes/pager.inc
@@ -39,7 +39,9 @@
  *   An SQL query used to count matching records.
  * @param ...
  *   A variable number of arguments which are substituted into the query (and
- *   also the count query) using printf() syntax.
+ *   the count query) using printf() syntax. Instead of a variable number of
+ *   query arguments, you may also pass a single array containing the query
+ *   arguments.
  * @return
  *   A database query result resource, or FALSE if the query was not executed
  *   correctly.
@@ -58,12 +60,12 @@ function pager_query($query, $limit = 10, $element = 0, $count_query = NULL) {
   if (!isset($count_query)) {
     $count_query = preg_replace(array('/SELECT.*?FROM/As', '/ORDER BY .*/'), array('SELECT COUNT(*) FROM', ''), $query);
   }
-  $pager_total[$element] = db_result(call_user_func_array('db_query', array_merge(array($count_query), $args)));
+  $pager_total[$element] = db_result(db_query($count_query, $args));
 
   // Convert comma-separated $from to an array, used by other functions.
   $pager_from_array = explode(',', $from);
 
-  return call_user_func_array('db_query_range', array_merge(array($query), $args, array((int)$pager_from_array[$element], (int)$limit)));
+  return db_query_range($query, $args, (int)$pager_from_array[$element], (int)$limit);
 }
 
 /**
@@ -369,4 +371,4 @@ function pager_load_array($value, $element, $old_array) {
   return $new_array;
 }
 
-?>
+?>
\ No newline at end of file
diff --git a/modules/filter.module b/modules/filter.module
index 96287c911583..cc4ccfbcfe8c 100644
--- a/modules/filter.module
+++ b/modules/filter.module
@@ -467,20 +467,20 @@ function filter_formats() {
   if (!isset($formats)) {
     $formats = array();
 
-    $query = array('SELECT * FROM {filter_formats}');
+    $query = 'SELECT * FROM {filter_formats}';
 
     // Build query for selecting the format(s) based on the user's roles.
     if (!$all) {
       $where = array();
       foreach ($user->roles as $rid => $role) {
         $where[] = "roles LIKE '%%,%d,%%'";
-        $query[] = $rid;
+        $args[] = $rid;
       }
-      $query[0] .= ' WHERE '. implode(' OR ', $where) . ' OR format = %d';
-      $query[] = variable_get('filter_default_format', 1);
+      $query .= ' WHERE '. implode(' OR ', $where) . ' OR format = %d';
+      $args[] = variable_get('filter_default_format', 1);
     }
 
-    $result = call_user_func_array('db_query', $query);
+    $result = db_query($query, $args);
     while ($format = db_fetch_object($result)) {
       $formats[$format->format] = $format;
     }
@@ -867,4 +867,4 @@ function _filter_autop($text) {
  * @} End of "Standard filters".
  */
 
-?>
+?>
\ No newline at end of file
diff --git a/modules/filter/filter.module b/modules/filter/filter.module
index 96287c911583..cc4ccfbcfe8c 100644
--- a/modules/filter/filter.module
+++ b/modules/filter/filter.module
@@ -467,20 +467,20 @@ function filter_formats() {
   if (!isset($formats)) {
     $formats = array();
 
-    $query = array('SELECT * FROM {filter_formats}');
+    $query = 'SELECT * FROM {filter_formats}';
 
     // Build query for selecting the format(s) based on the user's roles.
     if (!$all) {
       $where = array();
       foreach ($user->roles as $rid => $role) {
         $where[] = "roles LIKE '%%,%d,%%'";
-        $query[] = $rid;
+        $args[] = $rid;
       }
-      $query[0] .= ' WHERE '. implode(' OR ', $where) . ' OR format = %d';
-      $query[] = variable_get('filter_default_format', 1);
+      $query .= ' WHERE '. implode(' OR ', $where) . ' OR format = %d';
+      $args[] = variable_get('filter_default_format', 1);
     }
 
-    $result = call_user_func_array('db_query', $query);
+    $result = db_query($query, $args);
     while ($format = db_fetch_object($result)) {
       $formats[$format->format] = $format;
     }
@@ -867,4 +867,4 @@ function _filter_autop($text) {
  * @} End of "Standard filters".
  */
 
-?>
+?>
\ No newline at end of file
diff --git a/modules/search.module b/modules/search.module
index 69714827d154..7e02865d2c30 100644
--- a/modules/search.module
+++ b/modules/search.module
@@ -454,8 +454,7 @@ function do_search($keys, $type, $join = '', $where = '1') {
 
   // Do pager query
   $query = "SELECT i.type, i.sid, i.word, SUM(i.score/t.count) AS score FROM {search_index} i $join INNER JOIN {search_total} t ON i.word = t.word WHERE $where GROUP BY i.type, i.sid ORDER BY score DESC";
-  $arguments = array_merge(array($query, 15, 0, $count_query), $arguments);
-  $result = call_user_func_array('pager_query', $arguments);
+  $result = pager_query($query, 15, 0, $count_query, $arguments);
 
   $results = array();
   while ($item = db_fetch_object($result)) {
@@ -754,4 +753,4 @@ function theme_search_item($item, $type) {
 }
 
 
-?>
+?>
\ No newline at end of file
diff --git a/modules/search/search.module b/modules/search/search.module
index 69714827d154..7e02865d2c30 100644
--- a/modules/search/search.module
+++ b/modules/search/search.module
@@ -454,8 +454,7 @@ function do_search($keys, $type, $join = '', $where = '1') {
 
   // Do pager query
   $query = "SELECT i.type, i.sid, i.word, SUM(i.score/t.count) AS score FROM {search_index} i $join INNER JOIN {search_total} t ON i.word = t.word WHERE $where GROUP BY i.type, i.sid ORDER BY score DESC";
-  $arguments = array_merge(array($query, 15, 0, $count_query), $arguments);
-  $result = call_user_func_array('pager_query', $arguments);
+  $result = pager_query($query, 15, 0, $count_query, $arguments);
 
   $results = array();
   while ($item = db_fetch_object($result)) {
@@ -754,4 +753,4 @@ function theme_search_item($item, $type) {
 }
 
 
-?>
+?>
\ No newline at end of file
diff --git a/modules/user.module b/modules/user.module
index 54364b3edc31..cabb5b7734a1 100644
--- a/modules/user.module
+++ b/modules/user.module
@@ -61,10 +61,7 @@ function user_load($array = array()) {
       $params[] = strtolower($value);
     }
   }
-  array_unshift($params, "SELECT u.* FROM {users} u WHERE $query u.status < 3");
-  $params[] = 0;
-  $params[] = 1;
-  $result = call_user_func_array('db_query_range', $params);
+  $result = db_query_range("SELECT u.* FROM {users} u WHERE $query u.status < 3", $params, 0, 1);
 
   if (db_num_rows($result)) {
     $user = db_fetch_object($result);
@@ -1737,4 +1734,4 @@ function _user_forms(&$edit, $account, $category, $hook = 'form') {
   return $output;
 }
 
-?>
+?>
\ No newline at end of file
diff --git a/modules/user/user.module b/modules/user/user.module
index 54364b3edc31..cabb5b7734a1 100644
--- a/modules/user/user.module
+++ b/modules/user/user.module
@@ -61,10 +61,7 @@ function user_load($array = array()) {
       $params[] = strtolower($value);
     }
   }
-  array_unshift($params, "SELECT u.* FROM {users} u WHERE $query u.status < 3");
-  $params[] = 0;
-  $params[] = 1;
-  $result = call_user_func_array('db_query_range', $params);
+  $result = db_query_range("SELECT u.* FROM {users} u WHERE $query u.status < 3", $params, 0, 1);
 
   if (db_num_rows($result)) {
     $user = db_fetch_object($result);
@@ -1737,4 +1734,4 @@ function _user_forms(&$edit, $account, $category, $hook = 'form') {
   return $output;
 }
 
-?>
+?>
\ No newline at end of file
-- 
GitLab