diff options
author | Dries Buytaert <dries@buytaert.net> | 2004-07-14 19:15:25 +0000 |
---|---|---|
committer | Dries Buytaert <dries@buytaert.net> | 2004-07-14 19:15:25 +0000 |
commit | 63a327db97c72b14c17609250f736b762668a533 (patch) | |
tree | 2156d32e51ec7648f9507e3c77360726b9ba9373 /includes | |
parent | ce8e2643823724dc0b263704313be9917759479f (diff) | |
download | brdo-63a327db97c72b14c17609250f736b762668a533.tar.gz brdo-63a327db97c72b14c17609250f736b762668a533.tar.bz2 |
- Patch #9287 by JonBob: made the code style in the three database include files consistent with Drupal standards, and adds a wealth of Doxygen-style comments to aid developers in writing solid database access code using the API.
Diffstat (limited to 'includes')
-rw-r--r-- | includes/database.inc | 111 | ||||
-rw-r--r-- | includes/database.mysql.inc | 181 | ||||
-rw-r--r-- | includes/database.pear.inc | 150 |
3 files changed, 339 insertions, 103 deletions
diff --git a/includes/database.inc b/includes/database.inc index a7943a1f3..b0e98fcdf 100644 --- a/includes/database.inc +++ b/includes/database.inc @@ -1,69 +1,128 @@ <?php // $Id$ +/** + * @file + * Wrapper for database interface code. + */ + +/** + * @defgroup database Database abstraction layer + * @{ + * + * Drupal provides a slim database abstraction layer to provide developers with + * the ability to support multiple database servers easily. The intent of this + * layer is to preserve the syntax and power of SQL as much as possible, while + * letting Drupal control the pieces of queries that need to be written + * differently for different servers and provide basic security checks. + * + * Most Drupal database queries are performed by a call to db_query() or + * db_query_range(). Module authors should also consider using pager_query() for + * queries that return results that need to be presented on multiple pages, and + * tablesort_sql() for generating appropriate queries for sortable tables. + * + * For example, one might wish to return a list of the most recent 10 nodes + * authored by a given user. Instead of directly issuing the SQL query + * @code + * SELECT n.title, n.body, n.created FROM node n WHERE n.uid = $uid LIMIT 0, 10; + * @endcode + * one would instead call the Drupal functions: + * @code + * $result = db_query_range('SELECT n.title, n.body, n.created + * FROM {node} n WHERE n.uid = %d', $uid, 0, 10); + * while ($node = db_fetch_object($result)) { + * // Perform operations on $node->body, etc. here. + * } + * @endcode + * Curly braces are used around "node" to provide table prefixing via + * db_prefix_tables(). The explicit use of a user ID is pulled out into an + * argument passed to db_query() so that SQL injection attacks from user input + * can be caught and nullified. The LIMIT syntax varies between database servers, + * so that is abstracted into db_query_range() arguments. Finally, note the + * common pattern of iterating over the result set using db_fetch_object(). + */ + +/** + * Append a database prefix to all tables in a query. + * + * Queries sent to Drupal should wrap all table names in curly brackets. This + * function searches for this syntax and adds Drupal's table prefix to all + * tables, allowing Drupal to coexist with other systems in the same database if + * necessary. + * + * @param $sql + * A string containing a partial or entire SQL query. + * @return + * The properly-prefixed string. + */ function db_prefix_tables($sql) { global $db_prefix; if (is_array($db_prefix)) { - $prefix = $db_prefix["default"]; + $prefix = $db_prefix['default']; foreach ($db_prefix as $key => $val) { - if ($key !== "default") { - $sql = strtr($sql, array("{". $key. "}" => $val. $key)); + if ($key !== 'default') { + $sql = strtr($sql, array('{'. $key. '}' => $val. $key)); } } } else { $prefix = $db_prefix; } - return strtr($sql, array("{" => $prefix, "}" => "")); + return strtr($sql, array('{' => $prefix, '}' => '')); } - /** -* Use the specified database connection for queries. Initialize the connection if it does not already exist, -* and if no such member exists, a duplicate of the default connection is made. -* Be very careful to switch the connection back to the default connection, so as to avoid errors. As the $name -* parameter defaults to 'default', you only need to run db_set_active() without any arguments to use -* the default database -* -* @param $name The named connection specified in the $db_url variable. -*/ + * Activate a database for future queries. + * + * If it is necessary to use external databases in a project, this function can + * be used to change where database queries are sent. If the database has not + * yet been used, it is initialized using the URL specified for that name in + * Drupal's configuration file. If this name is not defined, a duplicate of the + * default connection is made instead. + * + * Be sure to change the connection back to the default when done with custom + * code. + * + * @param $name + * The name assigned to the newly active database connection. If omitted, the + * default connection will be made active. + */ function db_set_active($name = 'default') { global $db_url, $db_type, $active_db; static $db_conns; if (!isset($db_conns[$name])) { - //Initiate a new connection, using the named db url specified + // Initiate a new connection, using the named DB URL specified. if (is_array($db_url)) { - $connect_url = ($db_url[$name]) ? $db_url[$name] : $db_url['default']; + $connect_url = array_key_exists($name, $db_url) ? $db_url[$name] : $db_url['default']; } else { $connect_url = $db_url; } + $db_type = substr($connect_url, 0, strpos($connect_url, '://')); - $db_type = substr($connect_url, 0, strpos($connect_url, "://")); - - //TODO : Allow more than one database api to be present. ie: pgsl and mysql - if ($db_type == "mysql") { - include_once "includes/database.mysql.inc"; + // TODO: Allow more than one database API to be present. + if ($db_type == 'mysql') { + include_once 'includes/database.mysql.inc'; } else { - include_once "includes/database.pear.inc"; + include_once 'includes/database.pear.inc'; } $db_conns[$name] = db_connect($connect_url); } - //set the active connection + // Set the active connection. $active_db = $db_conns[$name]; - - } +/** + * @} end of defgroup database + */ -// initialize the default db_url +// Initialize the default database. db_set_active(); - ?> diff --git a/includes/database.mysql.inc b/includes/database.mysql.inc index aeb31828a..698ec1ce3 100644 --- a/includes/database.mysql.inc +++ b/includes/database.mysql.inc @@ -1,34 +1,53 @@ <?php // $Id$ +/** + * @file + * Database interface code for MySQL database servers. + */ + +/** + * @addtogroup database + * @{ + */ + +/** + * Initialize a database connection. + * + * Note that you can change the mysql_connect() call to mysql_pconnect() if you + * want to use persistent connections. This is not recommended on shared hosts, + * and might require additional database/webserver tuning. It can increase + * performance, however, when the overhead to connect to your database is high + * (e.g. your database and web server live on different machines). + */ function db_connect($url) { $url = parse_url($url); // Allow for non-standard MySQL port. - if (isset($url["port"])) { - $url["host"] = $url["host"] . ":" . $url["port"]; + if (isset($url['port'])) { + $url['host'] = $url['host'] .':'. $url['port']; } - $connection = mysql_connect($url["host"], $url["user"], $url["pass"]) or die(mysql_error()); - mysql_select_db(substr($url["path"], 1)) or die("unable to select database"); + $connection = mysql_connect($url['host'], $url['user'], $url['pass']) or die(mysql_error()); + mysql_select_db(substr($url['path'], 1)) or die('unable to select database'); return $connection; - - /* - ** Note that you can change the 'mysql_connect' statement to 'mysql_pconnect' - ** if you want to use persistent connections. This is not recommended on - ** shared hosts, might require additional database/webserver tuning but - ** increases performance when the overhead to connect to your database is - ** high (eg. your database and webserver live on different machines). - */ } /** - * Runs a query in the database. + * 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 SQL query, followed by a variable number of arguments which - * are substituted into query by sprintf. - * @return a MySQL result or FALSE if the query was not executed correctly. + * @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(); @@ -36,61 +55,67 @@ function db_query($query) { $query = db_prefix_tables($query); if (count($args) > 1) { if(is_array($args[1])){ - $args1 = array_map("check_query", $args[1]); + $args1 = array_map('check_query', $args[1]); $nargs = array_merge(array($query), $args1); } else { - $nargs = array_map("check_query", $args); + $nargs = array_map('check_query', $args); $nargs[0] = $query; } - return _db_query(call_user_func_array("sprintf", $nargs)); + return _db_query(call_user_func_array('sprintf', $nargs)); } else { return _db_query($query); } } -// debug version +/** + * 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("check_query", $args[1]); + $args1 = array_map('check_query', $args[1]); $nargs = array_merge(array($query), $args1); } else { - $nargs = array_map("check_query", $args); + $nargs = array_map('check_query', $args); $nargs[0] = $query; } - return _db_query(call_user_func_array("sprintf", $nargs), 1); + return _db_query(call_user_func_array('sprintf', $nargs), 1); } else { return _db_query($query, 1); } } -// private +/** + * Helper function for db_query(). + */ function _db_query($query, $debug = 0) { global $active_db; global $queries; - if (variable_get("dev_query", 0)) { - list($usec, $sec) = explode(" ", microtime()); + if (variable_get('dev_query', 0)) { + list($usec, $sec) = explode(' ', microtime()); $timer = (float)$usec + (float)$sec; } $result = mysql_query($query, $active_db); - if (variable_get("dev_query", 0)) { - list($usec, $sec) = explode(" ", microtime()); + if (variable_get('dev_query', 0)) { + list($usec, $sec) = explode(' ', microtime()); $stop = (float)$usec + (float)$sec; $diff = $stop - $timer; $queries[] = array($query, $diff); } if ($debug) { - print "<p>query: $query<br />error:". mysql_error() ."</p>"; + print '<p>query: '. $query .'<br />error:'. mysql_error() .'</p>'; } if (!mysql_errno()) { @@ -101,79 +126,143 @@ function _db_query($query, $debug = 0) { } } +/** + * Fetch one result row from the previous query as an object. + * + * @param $result + * A database query result resource, as returned from db_query(). + * @return + * An object representing the next row of the result. The attributes of this + * object are the table fields selected by the query. + */ function db_fetch_object($result) { if ($result) { return mysql_fetch_object($result); } } +/** + * Fetch one result row from the previous query as an array. + * + * @param $result + * A database query result resource, as returned from db_query(). + * @return + * An associative array representing the next row of the result. The keys of + * this object are the names of the table fields selected by the query, and + * the values are the field values for this result row. + */ function db_fetch_array($result) { if ($result) { return mysql_fetch_array($result, MYSQL_ASSOC); } } +/** + * Determine how many result rows were found by the preceding query. + * + * @param $result + * A database query result resource, as returned from db_query(). + * @return + * The number of result rows. + */ function db_num_rows($result) { if ($result) { return mysql_num_rows($result); } } +/** + * Return an individual result field from the previous query. + * + * Only use this function if exactly one field is being selected; otherwise, + * use db_fetch_object() or db_fetch_array(). + * + * @param $result + * A database query result resource, as returned from db_query(). + * @param $row + * The index of the row whose result is needed. + * @return + * The resulting field. + */ function db_result($result, $row = 0) { if ($result && mysql_num_rows($result) > $row) { return mysql_result($result, $row); } } +/** + * Determine whether the previous query caused an error. + */ function db_error() { return mysql_errno(); } +/** + * Return a new unique ID in the given sequence. + * + * For compatibility reasons, Drupal does not use auto-numbered fields in its + * database tables. Instead, this function is used to return a new unique ID + * of the type requested. If necessary, a new sequence with the given name + * will be created. + */ function db_next_id($name) { - - /* - ** Note that REPLACE query below correctly creates a new sequence - ** when needed - */ - $name = db_prefix_tables($name); - db_query("LOCK TABLES {sequences} WRITE"); + db_query('LOCK TABLES {sequences} WRITE'); $id = db_result(db_query("SELECT id FROM {sequences} WHERE name = '%s'", $name)) + 1; db_query("REPLACE INTO {sequences} VALUES ('%s', %d)", $name, $id); - db_query("UNLOCK TABLES"); + db_query('UNLOCK TABLES'); return $id; } +/** + * Determine the number of rows changed by the preceding query. + */ function db_affected_rows() { return mysql_affected_rows(); } /** - * Runs a LIMIT query in the database. + * Runs a limited-range query in the active database. + * + * Use this as a substitute for db_query() when a subset of the query is to be + * returned. + * 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 SQL query, followed by a variable number of arguments which - * are substituted into query by sprintf, followed by 'from' and 'count' - * parameters. 'from' is the row to start fetching, 'count' the numbers of - * rows to fetch. - * @return a MySQL result or FALSE if the query was not executed correctly. + * @param $query + * A string containing an SQL query. + * @param ... + * A variable number of arguments which are substituted into the query using + * printf() syntax. + * @param $from + * The first result row to return. + * @param $count + * The maximum number of result rows to return. + * @return + * A database query result resource, or FALSE if the query was not executed + * correctly. */ function db_query_range($query) { $args = func_get_args(); $count = array_pop($args); $from = array_pop($args); if (count(func_get_args()) > 3) { - $args = array_map("check_query", $args); + $args = array_map('check_query', $args); $query = db_prefix_tables($query); $args[0] = $query; - $query = call_user_func_array("sprintf", $args); + $query = call_user_func_array('sprintf', $args); } else { $query = func_get_arg(0); $query = db_prefix_tables($query); } - $query .= " LIMIT $from, $count"; + $query .= ' LIMIT '. $from .', '. $count; return _db_query($query); } +/** + * @} end of addtogroup database + */ + ?> diff --git a/includes/database.pear.inc b/includes/database.pear.inc index 860b51dad..529cb0afa 100644 --- a/includes/database.pear.inc +++ b/includes/database.pear.inc @@ -1,13 +1,21 @@ <?php // $Id$ +/** + * @file + * Database interface code for database servers using PEAR, including PostgreSQL. + */ + require_once 'DB.php'; +/** + * Initialize a database connection. + */ function db_connect($url) { $db_handle = DB::connect($url); if (DB::isError($db_handle)) { - die("Database problem: ". $db_handle->getMessage()); + die('Database problem: '. $db_handle->getMessage()); } $db_handle->setFetchMode(DB_FETCHMODE_ASSOC); @@ -16,11 +24,19 @@ function db_connect($url) { } /** - * Runs a query in the database. + * 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 SQL query, followed by a variable number of arguments which - * are substituted into query by sprintf. - * @return a DB_Result object or a DB_Error + * @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) { @@ -29,60 +45,66 @@ function db_query($query) { $query = db_prefix_tables($query); if (count($args) > 1) { if(is_array($args[1])){ - $args1 = array_map("check_query", $args[1]); + $args1 = array_map('check_query', $args[1]); $nargs = array_merge(array($query), $args1); } else { - $nargs = array_map("check_query", $args); + $nargs = array_map('check_query', $args); $nargs[0] = $query; } - return _db_query(call_user_func_array("sprintf", $nargs)); + return _db_query(call_user_func_array('sprintf', $nargs)); } else { return _db_query($query); } } -// debug version +/** + * 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("check_query", $args[1]); + $args1 = array_map('check_query', $args[1]); $nargs = array_merge(array($query), $args1); } else { - $nargs = array_map("check_query", $args); + $nargs = array_map('check_query', $args); $nargs[0] = $query; } - return _db_query(call_user_func_array("sprintf", $nargs), 1); + return _db_query(call_user_func_array('sprintf', $nargs), 1); } else { return _db_query($query, 1); } } -// private +/** + * Helper function for db_query(). + */ function _db_query($query, $debug = 0) { global $active_db, $queries; - if (variable_get("dev_query", 0)) { - list($usec, $sec) = explode(" ", microtime()); + if (variable_get('dev_query', 0)) { + list($usec, $sec) = explode(' ', microtime()); $timer = (float)$usec + (float)$sec; } $result = $active_db->query($query); - if (variable_get("dev_query", 0)) { - list($usec, $sec) = explode(" ", microtime()); + if (variable_get('dev_query', 0)) { + list($usec, $sec) = explode(' ', microtime()); $stop = (float)$usec + (float)$sec; $diff = $stop - $timer; $queries[] = array($query, $diff); } if ($debug) { - print "<p>query: $query</p>"; + print '<p>query: '. $query .'</p>'; } if (DB::isError($result)) { @@ -93,24 +115,64 @@ function _db_query($query, $debug = 0) { } } +/** + * Fetch one result row from the previous query as an object. + * + * @param $result + * A database query result resource, as returned from db_query(). + * @return + * An object representing the next row of the result. The attributes of this + * object are the table fields selected by the query. + */ function db_fetch_object($result) { if ($result) { return $result->fetchRow(DB_FETCHMODE_OBJECT); } } +/** + * Fetch one result row from the previous query as an array. + * + * @param $result + * A database query result resource, as returned from db_query(). + * @return + * An associative array representing the next row of the result. The keys of + * this object are the names of the table fields selected by the query, and + * the values are the field values for this result row. + */ function db_fetch_array($result) { if ($result) { return $result->fetchRow(DB_FETCHMODE_ASSOC); } } +/** + * Determine how many result rows were found by the preceding query. + * + * @param $result + * A database query result resource, as returned from db_query(). + * @return + * The number of result rows. + */ function db_num_rows($result) { if ($result) { return $result->numRows($result); } } +/** + * Return an individual result field from the previous query. + * + * Only use this function if exactly one field is being selected; otherwise, + * use db_fetch_object() or db_fetch_array(). + * + * @param $result + * A database query result resource, as returned from db_query(). + * @param $row + * The index of the row whose result is needed. + * @return + * The resulting field. + */ function db_result($result, $row = 0) { if ($result && $result->numRows($result) > $row) { $tmp = $result->fetchRow(DB_FETCHMODE_ORDERED); @@ -118,12 +180,23 @@ function db_result($result, $row = 0) { } } +/** + * Determine whether the previous query caused an error. + */ function db_error() { global $active_db; return DB::isError($active_db); } +/** + * Return a new unique ID in the given sequence. + * + * For compatibility reasons, Drupal does not use auto-numbered fields in its + * database tables. Instead, this function is used to return a new unique ID + * of the type requested. If necessary, a new sequence with the given name + * will be created. + */ function db_next_id($name) { global $active_db; @@ -137,6 +210,9 @@ function db_next_id($name) { } } +/** + * Determine the number of rows changed by the preceding query. + */ function db_affected_rows() { global $active_db; @@ -144,19 +220,31 @@ function db_affected_rows() { } /** - * Runs a LIMIT query in the database. + * Runs a limited-range query in the active database. + * + * Use this as a substitute for db_query() when a subset of the query is to be + * returned. + * 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 SQL query followed by a variable number of arguments which - * are substituted into query by sprintf, followed by 'from' and 'count' - * parameters. 'from' is the row to start fetching, 'count' the numbers of - * rows to fetch. - * @return a DB_Result object or a DB_Error + * @param $query + * A string containing an SQL query. + * @param ... + * A variable number of arguments which are substituted into the query using + * printf() syntax. + * @param $from + * The first result row to return. + * @param $count + * The maximum number of result rows to return. + * @return + * A database query result resource, or FALSE if the query was not executed + * correctly. */ function db_query_range($query) { global $active_db, $queries; - if (variable_get("dev_query", 0)) { - list($usec, $sec) = explode(" ", microtime()); + if (variable_get('dev_query', 0)) { + list($usec, $sec) = explode(' ', microtime()); $timer = (float)$usec + (float)$sec; } @@ -164,10 +252,10 @@ function db_query_range($query) { $count = array_pop($args); $from = array_pop($args); if (count(func_get_args()) > 3) { - $args = array_map("check_query", $args); + $args = array_map('check_query', $args); $query = db_prefix_tables($query); $args[0] = $query; - $result = $active_db->limitQuery(call_user_func_array("sprintf", $args), $from, $count); + $result = $active_db->limitQuery(call_user_func_array('sprintf', $args), $from, $count); } else { $query = func_get_arg(0); @@ -175,11 +263,11 @@ function db_query_range($query) { $result = $active_db->limitQuery( $query, $from, $count); } - if (variable_get("dev_query", 0)) { - list($usec, $sec) = explode(" ", microtime()); + if (variable_get('dev_query', 0)) { + list($usec, $sec) = explode(' ', microtime()); $stop = (float)$usec + (float)$sec; $diff = $stop - $timer; - $queries[] = array($query. " [LIMIT $from, $count]", $diff); + $queries[] = array($query. ' [LIMIT '. $from .', '. $count .']', $diff); } if (DB::isError($result)) { |