PDO::ERRMODE_WARNING, // Leave column names as returned by the database driver. PDO::ATTR_CASE => PDO::CASE_NATURAL, ); try { $connection = new PDO($dsn, $username, $password, $driver_options); } catch (PDOExecption $e) { _db_error_page($e->getMessage()); } 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. Instead of a variable number of query arguments, * you may also pass a single array containing the query arguments. * * Valid %-modifiers are: %s, %d, %f and %b (binary data, do not enclose * in ''). * * 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. */ function db_query($query) { $args = func_get_args(); array_shift($args); $query = db_prefix_tables($query); $query = db_escape_quote($query); if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax $args = $args[0]; } _db_query_callback(array('query' => $query, 'args' => $args), TRUE); $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query); $args = _db_query_callback(NULL, TRUE); return _db_query(array('query' => $query, 'args' => $args)); } /** * Helper function for db_query(). */ function _db_query($query, $debug = 0) { global $active_db, $last_result, $queries, $user; // Expand $query if it is in array format. $args = array(); if (is_array($query)) { $args = $query['args']; $query = $query['query']; // Check if locator exists in query, or else unset it. foreach ($args as $key => $value) { if (!is_array($args[$key]) || !isset($args[$key]['locator']) || !strstr($query, $args[$key]['locator'])) { unset($args[$key]); } } } if (variable_get('dev_query', 0)) { list($usec, $sec) = explode(' ', microtime()); $timer = (float)$usec + (float)$sec; // If devel.module query logging is enabled, prepend a comment with the username and calling function // to the SQL string. This is useful when running mysql's SHOW PROCESSLIST to learn what exact // code is issueing the slow query. $bt = debug_backtrace(); // t() may not be available yet so we don't wrap 'Anonymous'. $name = $user->uid ? $user->name : variable_get('anonymous', 'Anonymous'); // str_replace() to prevent SQL injection via username or anonymous name. $name = str_replace(array('*', '/'), '', $name); $query = '/* '. $name .' : '. $bt[2]['function'] .' */ '. $query; } $stmt = $active_db->prepare($query); if ($stmt === FALSE) { $error = $active_db->errorInfo(); if (is_array($error) && $error[0] != 0 && isset($error[2])) { // Indicate to drupal_error_handler that this is a database error. ${DB_ERROR} = TRUE; trigger_error(check_plain($error[2] ."\nquery: ". $query), E_USER_WARNING); } return FALSE; } if (count($args)) { foreach ($args as $key => $value) { if (isset($args[$key]['type'])) { $stmt->bindValue($args[$key]['locator'], $args[$key]['data'], $args[$key]['type']); } else { $stmt->bindValue($args[$key]['locator'], $args[$key]['data']); } } } // Execute the statement. $result = $stmt->execute(); if ($result === FALSE) { $error = $stmt->errorInfo(); if (is_array($error) && $error[0] != 0 && isset($error[2])) { // Indicate to drupal_error_handler that this is a database error. ${DB_ERROR} = TRUE; trigger_error(check_plain($error[2] ."\nquery: ". $query), E_USER_WARNING); } return FALSE; } if (variable_get('dev_query', 0)) { $query = $bt[2]['function'] ."\n". $query; list($usec, $sec) = explode(' ', microtime()); $stop = (float)$usec + (float)$sec; $diff = $stop - $timer; $queries[] = array($query, $diff); } if ($debug) { $error = $active_db->errorInfo(); print '

query: '. $query .'
error:'. $error[2] .'

'; } $last_result = $stmt; return $last_result; } /** * 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, or FALSE. The attributes * of this object are the table fields selected by the query. */ function db_fetch_object($result) { if ($result) { $object = $result->fetch(PDO::FETCH_OBJ); return isset($object) ? $object : FALSE; } return FALSE; } /** * 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, or FALSE. * 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) { $array = $result->fetch(PDO::FETCH_ASSOC); return isset($array) ? $array : FALSE; } return FALSE; } /** * 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(). * @return * The resulting field or FALSE. */ function db_result($result) { if ($result) { $array = $result->fetch(PDO::FETCH_NUM); return isset($array[0]) ? $array[0] : FALSE; } return FALSE; } /** * Determine whether the previous query caused an error. */ function db_error() { global $last_result; $error = $last_result->errorInfo(); if (is_array($error) && isset($error[2])) { return $error[2]; } } /** * Determine the number of rows changed by the preceding query. */ function db_affected_rows() { global $last_result; return $last_result->rowCount(); } /* * Prepare user input for use in a database query, preventing SQL injection attacks. * * @param $data * Data to encode. Return with processed array pattern for variable binding. * @param $locator * Locator for variable binding. * @return * Locator for variable binding. */ function db_escape_decimal(&$data, $locator) { $data = array( 'locator' => $locator, 'data' => (int) $data, ); return $locator; } /** * Prepare user input for use in a database query, preventing SQL injection attacks. * * @param $data * Data to encode. Return with processed array pattern for variable binding. * @param $locator * Locator for variable binding. * @return * Locator for variable binding. */ function db_escape_float(&$data, $locator) { $data = array( 'locator' => $locator, 'data' => (float) $data, ); return $locator; } /** * Prepare user input for use in a database query, preventing SQL injection attacks. * * @param $data * Data to encode. Return with processed array pattern for variable binding. * @param $locator * Locator for variable binding. * @return * Locator for variable binding. */ function db_escape_string(&$data, $locator) { $data = array( 'locator' => $locator, 'data' => $data, 'type' => PDO::PARAM_STR, ); return $locator; } /** * Returns a properly formatted Binary Large OBject value. * * @param $data * Data to encode. Return with processed array pattern for variable binding. * @param $locator * Locator for variable binding. * @return * Locator for variable binding. */ function db_encode_blob(&$data, $locator) { // LOB for PgSQL must define by PDO::PARAM_LOB, or else will case error // during INSER/UPDATE. So we need to use Oracle style locator-data-type // variable binding for pdo_pgsql. $data = array( 'locator' => $locator, 'data' => $data, 'type' => PDO::PARAM_LOB, ); return $locator; } /** * Returns text from a Binary Large OBject value. * * @param $data * Data to decode. * @return * Decoded data. */ function db_decode_blob($data) { // pdo_pgsql return bytea as stream, so we just need to use Streams API. // Check http://bugs.php.net/bug.php?id=37124 for more information. return stream_get_contents($data); } /** * @} End of "ingroup database". */