Index: includes/database.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/database.inc,v retrieving revision 1.39 diff -u -r1.39 database.inc --- includes/database.inc 19 Feb 2005 22:24:23 -0000 1.39 +++ includes/database.inc 27 Mar 2005 03:59:15 -0000 @@ -82,27 +82,34 @@ * 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. + * Due to the advanced nature of this function, it is recommended to use a custom + * error handler when switching to a database that does not have a drupal install. + * This is because the default drupal error handler inserts errors into the database + * via the watchdog() function, and the required tables might not be present. + * + * Be sure to change the connection, and the custom error handler, back to the default + * settings when done with the custom connection. * * @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; + global $db_url, $db_type, $active_db, $active_db_name; static $db_conns; + if (is_array($db_url)) { + $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, '://')); + $active_db_name = $name; + if (!isset($db_conns[$name])) { // Initiate a new connection, using the named DB URL specified. - if (is_array($db_url)) { - $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, '://')); $handler = "includes/database.$db_type.inc"; if (is_file($handler)) { @@ -115,10 +122,39 @@ $db_conns[$name] = db_connect($connect_url); } + // Set the active connection. $active_db = $db_conns[$name]; } + +/** + * Acts as a redirection layer to execute a db api function for a database type. + * + * Allows the use of multiple databases (such as Postgres and MySQL) from within + * the same site by executing the database api function for the currently active + * database type. + * + * @param $function + * The database api function to execute. + * @param ... + * The arguments to pass to the database api function. + * + * @return + * The data returned from the relevant function. + */ +function db_invoke($function) { + global $db_type; + + $args = func_get_args(); + $function = array_shift($args); + + if (function_exists('db_'. $db_type . '_' . $function)){ + // call Drupal function + return call_user_func_array('db_'. $db_type . '_' . $function, $args); + } +} + /** * Runs a basic query in the active database. * @@ -146,7 +182,8 @@ $args[0] = $query; $query = call_user_func_array('sprintf', $args); } - return _db_query($query); + + return db_invoke('query', $query); } /** @@ -165,7 +202,153 @@ $args[0] = $query; $query = call_user_func_array('sprintf', $args); } - return _db_query($query, 1); + return db_invoke('query', $query, 1); +} + +/** + * Initialize a database connection. + */ +function db_connect($url) { + return db_invoke('connect', $url); +} + +/** + * 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) { + return db_invoke('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) { + return db_invoke('fetch_array', $result); +} + +/** + * 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) { + return db_invoke('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) { + return db_invoke('result', $result, $row); +} + +/** + * Determine whether the previous query caused an error. + */ +function db_error() { + return db_invoke('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) { + return db_invoke('next_id', $name); +} + +/** + * Determine the number of rows changed by the preceding query. + */ +function db_affected_rows() { + return db_invoke('affected_rows'); +} + +/** + * 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 + * 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(); + return call_user_func_array('db_invoke', array_merge(array('query_range'), $args)); +} + +/** + * Returns a properly formatted Binary Large OBject value. + * + * @param $data + * Data to encode. + * @return + * Encoded data. + */ +function db_encode_blob($data) { + return db_invoke('encode_blob', $data); +} + +/** + * Returns text from a Binary Large OBject value. + * + * @param $data + * Data to decode. + * @return + * Decoded data. + */ +function db_decode_blob($data) { + return db_invoke('decode_blob', $data); +} + +/** + * Prepare user input for use in a database query, preventing SQL injection attacks. + */ +function db_escape_string($text) { + return db_invoke('escape_string', $text); } /** Index: includes/database.mysql.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/database.mysql.inc,v retrieving revision 1.27 diff -u -r1.27 database.mysql.inc --- includes/database.mysql.inc 29 Nov 2004 13:10:43 -0000 1.27 +++ includes/database.mysql.inc 27 Mar 2005 03:59:15 -0000 @@ -20,7 +20,7 @@ * 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) { +function db_mysql_connect($url) { $url = parse_url($url); // Allow for non-standard MySQL port. @@ -37,7 +37,7 @@ /** * Helper function for db_query(). */ -function _db_query($query, $debug = 0) { +function db_mysql_query($query, $debug = 0) { global $active_db; global $queries; @@ -76,7 +76,7 @@ * 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) { +function db_mysql_fetch_object($result) { if ($result) { return mysql_fetch_object($result); } @@ -92,7 +92,7 @@ * 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) { +function db_mysql_fetch_array($result) { if ($result) { return mysql_fetch_array($result, MYSQL_ASSOC); } @@ -106,7 +106,7 @@ * @return * The number of result rows. */ -function db_num_rows($result) { +function db_mysql_num_rows($result) { if ($result) { return mysql_num_rows($result); } @@ -125,7 +125,7 @@ * @return * The resulting field. */ -function db_result($result, $row = 0) { +function db_mysql_result($result, $row = 0) { if ($result && mysql_num_rows($result) > $row) { return mysql_result($result, $row); } @@ -134,7 +134,7 @@ /** * Determine whether the previous query caused an error. */ -function db_error() { +function db_mysql_error() { return mysql_errno(); } @@ -146,7 +146,7 @@ * of the type requested. If necessary, a new sequence with the given name * will be created. */ -function db_next_id($name) { +function db_mysql_next_id($name) { $name = db_prefix_tables($name); db_query('LOCK TABLES {sequences} WRITE'); $id = db_result(db_query("SELECT id FROM {sequences} WHERE name = '%s'", $name)) + 1; @@ -159,7 +159,7 @@ /** * Determine the number of rows changed by the preceding query. */ -function db_affected_rows() { +function db_mysql_affected_rows() { return mysql_affected_rows(); } @@ -185,7 +185,7 @@ * A database query result resource, or FALSE if the query was not executed * correctly. */ -function db_query_range($query) { +function db_mysql_query_range($query) { $args = func_get_args(); $count = array_pop($args); $from = array_pop($args); @@ -201,7 +201,7 @@ $query = call_user_func_array('sprintf', $args); } $query .= ' LIMIT '. $from .', '. $count; - return _db_query($query); + return db_query($query); } /** @@ -212,7 +212,7 @@ * @return * Encoded data. */ -function db_encode_blob($data) { +function db_mysql_encode_blob($data) { return $data; } @@ -224,14 +224,14 @@ * @return * Decoded data. */ -function db_decode_blob($data) { +function db_mysql_decode_blob($data) { return $data; } /** * Prepare user input for use in a database query, preventing SQL injection attacks. */ -function db_escape_string($text) { +function db_mysql_escape_string($text) { return addslashes($text); } @@ -239,4 +239,4 @@ * @} End of "ingroup database". */ -?> \ No newline at end of file +?> Index: includes/database.pgsql.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/database.pgsql.inc,v retrieving revision 1.6 diff -u -r1.6 database.pgsql.inc --- includes/database.pgsql.inc 7 Jan 2005 19:18:05 -0000 1.6 +++ includes/database.pgsql.inc 27 Mar 2005 03:59:16 -0000 @@ -20,7 +20,7 @@ * 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) { +function db_pgsql_connect($url) { $url = parse_url($url); $conn_string = ' user='. $url['user'] .' dbname='. substr($url['path'], 1) .' password='. $url['pass'] . ' host=' . $url['host']; @@ -33,7 +33,7 @@ /** * Helper function for db_query(). */ -function _db_query($query, $debug = 0) { +function db_pgsql_query($query, $debug = 0) { global $active_db, $last_result; global $queries; @@ -72,7 +72,7 @@ * 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) { +function db_pgsql_fetch_object($result) { if ($result) { return pg_fetch_object($result); } @@ -88,7 +88,7 @@ * 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) { +function db_pgsql_fetch_array($result) { if ($result) { return pg_fetch_assoc($result); } @@ -102,7 +102,7 @@ * @return * The number of result rows. */ -function db_num_rows($result) { +function db_pgsql_num_rows($result) { if ($result) { return pg_num_rows($result); } @@ -121,7 +121,7 @@ * @return * The resulting field. */ -function db_result($result, $row = 0) { +function db_pgsql_result($result, $row = 0) { if ($result && pg_num_rows($result) > $row) { $res = pg_fetch_row($result, $row); @@ -132,7 +132,7 @@ /** * Determine whether the previous query caused an error. */ -function db_error() { +function db_pgsql_error() { return pg_last_error(); } @@ -144,7 +144,7 @@ * of the type requested. If necessary, a new sequence with the given name * will be created. */ -function db_next_id($name) { +function db_pgsql_next_id($name) { $id = db_result(db_query("SELECT nextval('%s_seq')", db_prefix_tables($name))); return $id; } @@ -152,7 +152,7 @@ /** * Determine the number of rows changed by the preceding query. */ -function db_affected_rows() { +function db_pgsql_affected_rows() { global $last_result; return pg_affected_rows($last_result); } @@ -179,7 +179,7 @@ * A database query result resource, or FALSE if the query was not executed * correctly. */ -function db_query_range($query) { +function db_pgsql_query_range($query) { $args = func_get_args(); $count = array_pop($args); $from = array_pop($args); @@ -195,7 +195,7 @@ $query = call_user_func_array('sprintf', $args); } $query .= ' LIMIT '. $count .' OFFSET '. $from; - return _db_query($query); + return db_query($query); } /** @@ -206,7 +206,7 @@ * @return * Encoded data. */ -function db_encode_blob($data) { +function db_pgsql_encode_blob($data) { return addcslashes($data, "\0..\37\\"); } @@ -218,7 +218,7 @@ * @return * Decoded data. */ -function db_decode_blob($data) { +function db_pgsql_decode_blob($data) { return stripcslashes($data); } @@ -226,7 +226,7 @@ * Prepare user input for use in a database query, preventing SQL injection attacks. * Note: This function requires PostgreSQL 7.2 or later. */ -function db_escape_string($text) { +function db_pgsql_escape_string($text) { return pg_escape_string($text); }