X-Git-Url: https://scripts.mit.edu/gitweb/autoinstalls/wordpress.git/blobdiff_plain/76aea3697c6043c1613370f172395b4f65ee71f0..a01a150d87a096c70b6ec80332b7ce89c943eefe:/wp-includes/wp-db.php diff --git a/wp-includes/wp-db.php b/wp-includes/wp-db.php index db44afe5..61f6d9aa 100644 --- a/wp-includes/wp-db.php +++ b/wp-includes/wp-db.php @@ -12,33 +12,33 @@ /** * @since 0.71 */ -define('EZSQL_VERSION', 'WP1.25'); +define( 'EZSQL_VERSION', 'WP1.25' ); /** * @since 0.71 */ -define('OBJECT', 'OBJECT', true); +define( 'OBJECT', 'OBJECT', true ); /** - * @since {@internal Version Unknown}} + * @since 2.5.0 */ -define('OBJECT_K', 'OBJECT_K', false); +define( 'OBJECT_K', 'OBJECT_K' ); /** * @since 0.71 */ -define('ARRAY_A', 'ARRAY_A', false); +define( 'ARRAY_A', 'ARRAY_A' ); /** * @since 0.71 */ -define('ARRAY_N', 'ARRAY_N', false); +define( 'ARRAY_N', 'ARRAY_N' ); /** * WordPress Database Access Abstraction Object * * It is possible to replace this class with your own - * by setting the $wpdb global variable in wp-content/wpdb.php + * by setting the $wpdb global variable in wp-content/db.php * file with your class. You can name it wpdb also, since * this file will not be included, if the other file is * available. @@ -65,7 +65,7 @@ class wpdb { * Whether to suppress errors during the DB bootstrapping. * * @access private - * @since {@internal Version Unknown}} + * @since 2.5 * @var bool */ var $suppress_errors = false; @@ -73,7 +73,9 @@ class wpdb { /** * The last error during query. * - * @since {@internal Version Unknown}} + * @see get_last_error() + * @since 2.5 + * @access private * @var string */ var $last_error = ''; @@ -87,6 +89,33 @@ class wpdb { */ var $num_queries = 0; + /** + * Count of rows returned by previous query + * + * @since 1.2 + * @access private + * @var int + */ + var $num_rows = 0; + + /** + * Count of affected rows by previous query + * + * @since 0.71 + * @access private + * @var int + */ + var $rows_affected = 0; + + /** + * The ID generated for an AUTO_INCREMENT column by the previous query (usually INSERT). + * + * @since 0.71 + * @access public + * @var int + */ + var $insert_id = 0; + /** * Saved result of the last query made * @@ -96,6 +125,15 @@ class wpdb { */ var $last_query; + /** + * Results of the last query made + * + * @since 1.0.0 + * @access private + * @var array|null + */ + var $last_result; + /** * Saved info on the table column * @@ -137,40 +175,66 @@ class wpdb { var $ready = false; /** - * WordPress Posts table + * {@internal Missing Description}} * - * @since 1.5.0 + * @since 3.0.0 * @access public - * @var string + * @var int */ - var $posts; + var $blogid = 0; /** - * WordPress Users table + * {@internal Missing Description}} * - * @since 1.5.0 + * @since 3.0.0 * @access public - * @var string + * @var int */ - var $users; + var $siteid = 0; /** - * WordPress Categories table + * List of WordPress per-blog tables * - * @since 1.5.0 - * @access public - * @var string + * @since 2.5.0 + * @access private + * @see wpdb::tables() + * @var array */ - var $categories; + var $tables = array( 'posts', 'comments', 'links', 'options', 'postmeta', + 'terms', 'term_taxonomy', 'term_relationships', 'commentmeta' ); /** - * WordPress Post to Category table + * List of deprecated WordPress tables * - * @since 1.5.0 - * @access public - * @var string + * categories, post2cat, and link2cat were deprecated in 2.3.0, db version 5539 + * + * @since 2.9.0 + * @access private + * @see wpdb::tables() + * @var array */ - var $post2cat; + var $old_tables = array( 'categories', 'post2cat', 'link2cat' ); + + /** + * List of WordPress global tables + * + * @since 3.0.0 + * @access private + * @see wpdb::tables() + * @var array + */ + var $global_tables = array( 'users', 'usermeta' ); + + /** + * List of Multisite global tables + * + * @since 3.0.0 + * @access private + * @see wpdb::tables() + * @var array + */ + var $ms_global_tables = array( 'blogs', 'signups', 'site', 'sitemeta', + 'sitecategories', 'registration_log', 'blog_versions' ); /** * WordPress Comments table @@ -181,6 +245,15 @@ class wpdb { */ var $comments; + /** + * WordPress Comment Metadata table + * + * @since 2.9.0 + * @access public + * @var string + */ + var $commentmeta; + /** * WordPress Links table * @@ -202,20 +275,20 @@ class wpdb { /** * WordPress Post Metadata table * - * @since {@internal Version Unknown}} + * @since 1.5.0 * @access public * @var string */ var $postmeta; /** - * WordPress User Metadata table + * WordPress Posts table * - * @since 2.3.0 + * @since 1.5.0 * @access public * @var string */ - var $usermeta; + var $posts; /** * WordPress Terms table @@ -226,6 +299,15 @@ class wpdb { */ var $terms; + /** + * WordPress Term Relationships table + * + * @since 2.3.0 + * @access public + * @var string + */ + var $term_relationships; + /** * WordPress Term Taxonomy table * @@ -235,24 +317,105 @@ class wpdb { */ var $term_taxonomy; + /* + * Global and Multisite tables + */ + /** - * WordPress Term Relationships table + * WordPress User Metadata table * * @since 2.3.0 * @access public * @var string */ - var $term_relationships; + var $usermeta; /** - * List of WordPress tables + * WordPress Users table * - * @since {@internal Version Unknown}} - * @access private + * @since 1.5.0 + * @access public + * @var string + */ + var $users; + + /** + * Multisite Blogs table + * + * @since 3.0.0 + * @access public + * @var string + */ + var $blogs; + + /** + * Multisite Blog Versions table + * + * @since 3.0.0 + * @access public + * @var string + */ + var $blog_versions; + + /** + * Multisite Registration Log table + * + * @since 3.0.0 + * @access public + * @var string + */ + var $registration_log; + + /** + * Multisite Signups table + * + * @since 3.0.0 + * @access public + * @var string + */ + var $signups; + + /** + * Multisite Sites table + * + * @since 3.0.0 + * @access public + * @var string + */ + var $site; + + /** + * Multisite Sitewide Terms table + * + * @since 3.0.0 + * @access public + * @var string + */ + var $sitecategories; + + /** + * Multisite Site Metadata table + * + * @since 3.0.0 + * @access public + * @var string + */ + var $sitemeta; + + /** + * Format specifiers for DB columns. Columns not listed here default to %s. Initialized during WP load. + * + * Keys are column names, values are format types: 'ID' => '%d' + * + * @since 2.8.0 + * @see wpdb:prepare() + * @see wpdb:insert() + * @see wpdb:update() + * @see wp_set_wpdb_vars() + * @access public * @var array */ - var $tables = array('users', 'usermeta', 'posts', 'categories', 'post2cat', 'comments', 'links', 'link2cat', 'options', - 'postmeta', 'terms', 'term_taxonomy', 'term_relationships'); + var $field_types = array(); /** * Database table columns charset @@ -272,6 +435,33 @@ class wpdb { */ var $collate; + /** + * Whether to use mysql_real_escape_string + * + * @since 2.8.0 + * @access public + * @var bool + */ + var $real_escape = false; + + /** + * Database Username + * + * @since 2.9.0 + * @access private + * @var string + */ + var $dbuser; + + /** + * A textual description of the last query/get_row/get_var call + * + * @since unknown + * @access public + * @var string + */ + var $func_call; + /** * Connects to the database server and selects a database * @@ -285,8 +475,10 @@ class wpdb { * @param string $dbname MySQL database name * @param string $dbhost MySQL database host */ - function wpdb($dbuser, $dbpassword, $dbname, $dbhost) { - return $this->__construct($dbuser, $dbpassword, $dbname, $dbhost); + function wpdb( $dbuser, $dbpassword, $dbname, $dbhost ) { + if( defined( 'WP_USE_MULTIPLE_DB' ) && WP_USE_MULTIPLE_DB ) + $this->db_connect(); + return $this->__construct( $dbuser, $dbpassword, $dbname, $dbhost ); } /** @@ -296,6 +488,7 @@ class wpdb { * the actual setting up of the class properties and connection * to the database. * + * @link http://core.trac.wordpress.org/ticket/3354 * @since 2.0.8 * * @param string $dbuser MySQL database user @@ -303,21 +496,30 @@ class wpdb { * @param string $dbname MySQL database name * @param string $dbhost MySQL database host */ - function __construct($dbuser, $dbpassword, $dbname, $dbhost) { - register_shutdown_function(array(&$this, "__destruct")); + function __construct( $dbuser, $dbpassword, $dbname, $dbhost ) { + register_shutdown_function( array( &$this, '__destruct' ) ); - if ( defined('WP_DEBUG') and WP_DEBUG == true ) + if ( WP_DEBUG ) $this->show_errors(); - if ( defined('DB_CHARSET') ) + if ( is_multisite() ) { + $this->charset = 'utf8'; + if ( defined( 'DB_COLLATE' ) && DB_COLLATE ) + $this->collate = DB_COLLATE; + else + $this->collate = 'utf8_general_ci'; + } elseif ( defined( 'DB_COLLATE' ) ) { + $this->collate = DB_COLLATE; + } + + if ( defined( 'DB_CHARSET' ) ) $this->charset = DB_CHARSET; - if ( defined('DB_COLLATE') ) - $this->collate = DB_COLLATE; + $this->dbuser = $dbuser; - $this->dbh = @mysql_connect($dbhost, $dbuser, $dbpassword, true); - if (!$this->dbh) { - $this->bail(sprintf(/*WP_I18N_DB_CONN_ERROR*/" + $this->dbh = @mysql_connect( $dbhost, $dbuser, $dbpassword, true ); + if ( !$this->dbh ) { + $this->bail( sprintf( /*WP_I18N_DB_CONN_ERROR*/"

Error establishing a database connection

This either means that the username and password information in your wp-config.php file is incorrect or we can't contact the database server at %s. This could mean your host's database server is down.

If you're unsure what these terms mean you should probably contact your host. If you still need help you can always visit the WordPress Support Forums.

-"/*/WP_I18N_DB_CONN_ERROR*/, $dbhost)); +"/*/WP_I18N_DB_CONN_ERROR*/, $dbhost ), 'db_connect_fail' ); return; } $this->ready = true; - if ( $this->supports_collation() ) { - $collation_query = ''; - if ( !empty($this->charset) ) { - $collation_query = "SET NAMES '{$this->charset}'"; - if (!empty($this->collate) ) - $collation_query .= " COLLATE '{$this->collate}'"; + if ( $this->has_cap( 'collation' ) && !empty( $this->charset ) ) { + if ( function_exists( 'mysql_set_charset' ) ) { + mysql_set_charset( $this->charset, $this->dbh ); + $this->real_escape = true; + } else { + $query = $this->prepare( 'SET NAMES %s', $this->charset ); + if ( ! empty( $this->collate ) ) + $query .= $this->prepare( ' COLLATE %s', $this->collate ); + $this->query( $query ); } - - if ( !empty($collation_query) ) - $this->query($collation_query); - } - - $this->select($dbname); + + $this->select( $dbname, $this->dbh ); } /** * PHP5 style destructor and will run when database object is destroyed. * + * @see wpdb::__construct() * @since 2.0.8 - * - * @return bool Always true + * @return bool true */ function __destruct() { return true; @@ -362,34 +563,167 @@ class wpdb { /** * Sets the table prefix for the WordPress tables. * - * Also allows for the CUSTOM_USER_TABLE and CUSTOM_USER_META_TABLE to - * override the WordPress users and usersmeta tables. - * * @since 2.5.0 * * @param string $prefix Alphanumeric name for the new prefix. - * @return string Old prefix + * @return string|WP_Error Old prefix or WP_Error on error */ - function set_prefix($prefix) { + function set_prefix( $prefix, $set_table_names = true ) { - if ( preg_match('|[^a-z0-9_]|i', $prefix) ) + if ( preg_match( '|[^a-z0-9_]|i', $prefix ) ) return new WP_Error('invalid_db_prefix', /*WP_I18N_DB_BAD_PREFIX*/'Invalid database prefix'/*/WP_I18N_DB_BAD_PREFIX*/); - $old_prefix = $this->prefix; - $this->prefix = $prefix; + $old_prefix = is_multisite() ? '' : $prefix; - foreach ( $this->tables as $table ) - $this->$table = $this->prefix . $table; + if ( isset( $this->base_prefix ) ) + $old_prefix = $this->base_prefix; - if ( defined('CUSTOM_USER_TABLE') ) - $this->users = CUSTOM_USER_TABLE; + $this->base_prefix = $prefix; - if ( defined('CUSTOM_USER_META_TABLE') ) - $this->usermeta = CUSTOM_USER_META_TABLE; + if ( $set_table_names ) { + foreach ( $this->tables( 'global' ) as $table => $prefixed_table ) + $this->$table = $prefixed_table; + if ( is_multisite() && empty( $this->blogid ) ) + return $old_prefix; + + $this->prefix = $this->get_blog_prefix(); + + foreach ( $this->tables( 'blog' ) as $table => $prefixed_table ) + $this->$table = $prefixed_table; + + foreach ( $this->tables( 'old' ) as $table => $prefixed_table ) + $this->$table = $prefixed_table; + } return $old_prefix; } + /** + * Sets blog id. + * + * @since 3.0.0 + * @access public + * @param int $blog_id + * @param int $site_id Optional. + * @return string previous blog id + */ + function set_blog_id( $blog_id, $site_id = 0 ) { + if ( ! empty( $site_id ) ) + $this->siteid = $site_id; + + $old_blog_id = $this->blogid; + $this->blogid = $blog_id; + + $this->prefix = $this->get_blog_prefix(); + + foreach ( $this->tables( 'blog' ) as $table => $prefixed_table ) + $this->$table = $prefixed_table; + + foreach ( $this->tables( 'old' ) as $table => $prefixed_table ) + $this->$table = $prefixed_table; + + return $old_blog_id; + } + + /** + * Gets blog prefix. + * + * @uses is_multisite() + * @since 3.0.0 + * @param int $blog_id Optional. + * @return string Blog prefix. + */ + function get_blog_prefix( $blog_id = null ) { + if ( is_multisite() ) { + if ( null === $blog_id ) + $blog_id = $this->blogid; + if ( defined( 'MULTISITE' ) && ( 0 == $blog_id || 1 == $blog_id ) ) + return $this->base_prefix; + else + return $this->base_prefix . $blog_id . '_'; + } else { + return $this->base_prefix; + } + } + + /** + * Returns an array of WordPress tables. + * + * Also allows for the CUSTOM_USER_TABLE and CUSTOM_USER_META_TABLE to + * override the WordPress users and usersmeta tables that would otherwise + * be determined by the prefix. + * + * The scope argument can take one of the following: + * + * 'all' - returns 'all' and 'global' tables. No old tables are returned. + * 'blog' - returns the blog-level tables for the queried blog. + * 'global' - returns the global tables for the installation, returning multisite tables only if running multisite. + * 'ms_global' - returns the multisite global tables, regardless if current installation is multisite. + * 'old' - returns tables which are deprecated. + * + * @since 3.0.0 + * @uses wpdb::$tables + * @uses wpdb::$old_tables + * @uses wpdb::$global_tables + * @uses wpdb::$ms_global_tables + * @uses is_multisite() + * + * @param string $scope Optional. Can be all, global, ms_global, blog, or old tables. Defaults to all. + * @param bool $prefix Optional. Whether to include table prefixes. Default true. If blog + * prefix is requested, then the custom users and usermeta tables will be mapped. + * @param int $blog_id Optional. The blog_id to prefix. Defaults to wpdb::$blogid. Used only when prefix is requested. + * @return array Table names. When a prefix is requested, the key is the unprefixed table name. + */ + function tables( $scope = 'all', $prefix = true, $blog_id = 0 ) { + switch ( $scope ) { + case 'all' : + $tables = array_merge( $this->global_tables, $this->tables ); + if ( is_multisite() ) + $tables = array_merge( $tables, $this->ms_global_tables ); + break; + case 'blog' : + $tables = $this->tables; + break; + case 'global' : + $tables = $this->global_tables; + if ( is_multisite() ) + $tables = array_merge( $tables, $this->ms_global_tables ); + break; + case 'ms_global' : + $tables = $this->ms_global_tables; + break; + case 'old' : + $tables = $this->old_tables; + break; + default : + return array(); + break; + } + + if ( $prefix ) { + if ( ! $blog_id ) + $blog_id = $this->blogid; + $blog_prefix = $this->get_blog_prefix( $blog_id ); + $base_prefix = $this->base_prefix; + $global_tables = array_merge( $this->global_tables, $this->ms_global_tables ); + foreach ( $tables as $k => $table ) { + if ( in_array( $table, $global_tables ) ) + $tables[ $table ] = $base_prefix . $table; + else + $tables[ $table ] = $blog_prefix . $table; + unset( $tables[ $k ] ); + } + + if ( isset( $tables['users'] ) && defined( 'CUSTOM_USER_TABLE' ) ) + $tables['users'] = CUSTOM_USER_TABLE; + + if ( isset( $tables['usermeta'] ) && defined( 'CUSTOM_USER_META_TABLE' ) ) + $tables['usermeta'] = CUSTOM_USER_META_TABLE; + } + + return $tables; + } + /** * Selects a database using the current database connection. * @@ -399,74 +733,172 @@ class wpdb { * @since 0.71 * * @param string $db MySQL database name + * @param resource $dbh Optional link identifier. * @return null Always null. */ - function select($db) { - if (!@mysql_select_db($db, $this->dbh)) { + function select( $db, $dbh = null) { + if ( is_null($dbh) ) + $dbh = $this->dbh; + + if ( !@mysql_select_db( $db, $dbh ) ) { $this->ready = false; - $this->bail(sprintf(/*WP_I18N_DB_SELECT_DB*/' + $this->bail( sprintf( /*WP_I18N_DB_SELECT_DB*/'

Can’t select database

We were able to connect to the database server (which means your username and password is okay) but not able to select the %1$s database.

-

If you don\'t know how to setup a database you should contact your host. If all else fails you may find help at the WordPress Support Forums.

'/*/WP_I18N_DB_SELECT_DB*/, $db, DB_USER)); +

If you don\'t know how to set up a database you should contact your host. If all else fails you may find help at the WordPress Support Forums.

'/*/WP_I18N_DB_SELECT_DB*/, $db, $this->dbuser ), 'db_select_fail' ); return; } } /** - * Escapes content for insertion into the database, for security + * Weak escape, using addslashes() * - * @since 0.71 + * @see addslashes() + * @since 2.8.0 + * @access private * * @param string $string - * @return string query safe string + * @return string */ - function escape($string) { + function _weak_escape( $string ) { return addslashes( $string ); - // Disable rest for now, causing problems - /* - if( !$this->dbh || version_compare( phpversion(), '4.3.0' ) == '-1' ) - return mysql_escape_string( $string ); - else + } + + /** + * Real escape, using mysql_real_escape_string() or addslashes() + * + * @see mysql_real_escape_string() + * @see addslashes() + * @since 2.8 + * @access private + * + * @param string $string to escape + * @return string escaped + */ + function _real_escape( $string ) { + if ( $this->dbh && $this->real_escape ) return mysql_real_escape_string( $string, $this->dbh ); - */ + else + return addslashes( $string ); + } + + /** + * Escape data. Works on arrays. + * + * @uses wpdb::_escape() + * @uses wpdb::_real_escape() + * @since 2.8 + * @access private + * + * @param string|array $data + * @return string|array escaped + */ + function _escape( $data ) { + if ( is_array( $data ) ) { + foreach ( (array) $data as $k => $v ) { + if ( is_array($v) ) + $data[$k] = $this->_escape( $v ); + else + $data[$k] = $this->_real_escape( $v ); + } + } else { + $data = $this->_real_escape( $data ); + } + + return $data; + } + + /** + * Escapes content for insertion into the database using addslashes(), for security. + * + * Works on arrays. + * + * @since 0.71 + * @param string|array $data to escape + * @return string|array escaped as query safe string + */ + function escape( $data ) { + if ( is_array( $data ) ) { + foreach ( (array) $data as $k => $v ) { + if ( is_array( $v ) ) + $data[$k] = $this->escape( $v ); + else + $data[$k] = $this->_weak_escape( $v ); + } + } else { + $data = $this->_weak_escape( $data ); + } + + return $data; } /** * Escapes content by reference for insertion into the database, for security * + * @uses wpdb::_real_escape() * @since 2.3.0 - * - * @param string $s + * @param string $string to escape + * @return void */ - function escape_by_ref(&$s) { - $s = $this->escape($s); + function escape_by_ref( &$string ) { + $string = $this->_real_escape( $string ); } /** - * Prepares a SQL query for safe use, using sprintf() syntax. + * Prepares a SQL query for safe execution. Uses sprintf()-like syntax. + * + * The following directives can be used in the query format string: + * %d (decimal number) + * %s (string) + * %% (literal percentage sign - no argument needed) + * + * Both %d and %s are to be left unquoted in the query string and they need an argument passed for them. + * Literals (%) as parts of the query must be properly written as %%. + * + * This function only supports a small subset of the sprintf syntax; it only supports %d (decimal number), %s (string). + * Does not support sign, padding, alignment, width or precision specifiers. + * Does not support argument numbering/swapping. + * + * May be called like {@link http://php.net/sprintf sprintf()} or like {@link http://php.net/vsprintf vsprintf()}. + * + * Both %d and %s should be left unquoted in the query string. * - * @link http://php.net/sprintf See for syntax to use for query string. + * + * wpdb::prepare( "SELECT * FROM `table` WHERE `column` = %s AND `field` = %d", 'foo', 1337 ) + * wpdb::prepare( "SELECT DATE_FORMAT(`field`, '%%c') FROM `table` WHERE `column` = %s", 'foo' ); + * + * + * @link http://php.net/sprintf Description of syntax. * @since 2.3.0 * - * @param null|string $args If string, first parameter must be query statement - * @param mixed $args,... If additional parameters, they will be set inserted into the query. - * @return null|string Sanitized query string + * @param string $query Query statement with sprintf()-like placeholders + * @param array|mixed $args The array of variables to substitute into the query's placeholders if being called like + * {@link http://php.net/vsprintf vsprintf()}, or the first variable to substitute into the query's placeholders if + * being called like {@link http://php.net/sprintf sprintf()}. + * @param mixed $args,... further variables to substitute into the query's placeholders if being called like + * {@link http://php.net/sprintf sprintf()}. + * @return null|false|string Sanitized query string, null if there is no query, false if there is an error and string + * if there was something to prepare */ - function prepare($args=null) { - if ( is_null( $args ) ) + function prepare( $query = null ) { // ( $query, *$args ) + if ( is_null( $query ) ) return; + $args = func_get_args(); - $query = array_shift($args); - $query = str_replace("'%s'", '%s', $query); // in case someone mistakenly already singlequoted it - $query = str_replace('"%s"', '%s', $query); // doublequote unquoting - $query = str_replace('%s', "'%s'", $query); // quote the strings - array_walk($args, array(&$this, 'escape_by_ref')); - return @vsprintf($query, $args); + array_shift( $args ); + // If args were passed as an array (as in vsprintf), move them up + if ( isset( $args[0] ) && is_array($args[0]) ) + $args = $args[0]; + $query = str_replace( "'%s'", '%s', $query ); // in case someone mistakenly already singlequoted it + $query = str_replace( '"%s"', '%s', $query ); // doublequote unquoting + $query = preg_replace( '|(?dbh); - $EZSQL_ERROR[] = array ('query' => $this->last_query, 'error_str' => $str); + if ( !$str ) + $str = mysql_error( $this->dbh ); + $EZSQL_ERROR[] = array( 'query' => $this->last_query, 'error_str' => $str ); if ( $this->suppress_errors ) return false; if ( $caller = $this->get_caller() ) - $error_str = sprintf(/*WP_I18N_DB_QUERY_ERROR_FULL*/'WordPress database error %1$s for query %2$s made by %3$s'/*/WP_I18N_DB_QUERY_ERROR_FULL*/, $str, $this->last_query, $caller); + $error_str = sprintf( /*WP_I18N_DB_QUERY_ERROR_FULL*/'WordPress database error %1$s for query %2$s made by %3$s'/*/WP_I18N_DB_QUERY_ERROR_FULL*/, $str, $this->last_query, $caller ); else - $error_str = sprintf(/*WP_I18N_DB_QUERY_ERROR*/'WordPress database error %1$s for query %2$s'/*/WP_I18N_DB_QUERY_ERROR*/, $str, $this->last_query); - - $log_error = true; - if ( ! function_exists('error_log') ) - $log_error = false; + $error_str = sprintf( /*WP_I18N_DB_QUERY_ERROR*/'WordPress database error %1$s for query %2$s'/*/WP_I18N_DB_QUERY_ERROR*/, $str, $this->last_query ); - $log_file = @ini_get('error_log'); - if ( !empty($log_file) && ('syslog' != $log_file) && !is_writable($log_file) ) - $log_error = false; + if ( function_exists( 'error_log' ) + && ( $log_file = @ini_get( 'error_log' ) ) + && ( 'syslog' == $log_file || @is_writable( $log_file ) ) + ) + @error_log( $error_str ); - if ( $log_error ) - @error_log($error_str, 0); - - // Is error output turned on or not.. - if ( !$this->show_errors ) + // Are we showing errors? + if ( ! $this->show_errors ) return false; - $str = htmlspecialchars($str, ENT_QUOTES); - $query = htmlspecialchars($this->last_query, ENT_QUOTES); - // If there is an error then take note of it - print "
-

WordPress database error: [$str]
- $query

-
"; + if ( is_multisite() ) { + $msg = "WordPress database error: [$str]\n{$this->last_query}\n"; + if ( defined( 'ERRORLOGFILE' ) ) + error_log( $msg, 3, ERRORLOGFILE ); + if ( defined( 'DIEONDBERROR' ) ) + wp_die( $msg ); + } else { + $str = htmlspecialchars( $str, ENT_QUOTES ); + $query = htmlspecialchars( $this->last_query, ENT_QUOTES ); + + print "
+

WordPress database error: [$str]
+ $query

+
"; + } } /** @@ -526,6 +962,7 @@ class wpdb { * errors. * * @since 0.71 + * @see wpdb::hide_errors() * * @param bool $show Whether to show or hide errors * @return bool Old value for showing errors. @@ -539,9 +976,12 @@ class wpdb { /** * Disables showing of database errors. * + * By default database errors are not shown. + * * @since 0.71 + * @see wpdb::show_errors() * - * @return bool Whether showing of errors was active or not + * @return bool Whether showing of errors was active */ function hide_errors() { $show = $this->show_errors; @@ -552,12 +992,17 @@ class wpdb { /** * Whether to suppress database errors. * - * @param unknown_type $suppress - * @return unknown + * By default database errors are suppressed, with a simple + * call to this function they can be enabled. + * + * @since 2.5 + * @see wpdb::hide_errors() + * @param bool $suppress Optional. New value. Defaults to true. + * @return bool Old value */ function suppress_errors( $suppress = true ) { $errors = $this->suppress_errors; - $this->suppress_errors = $suppress; + $this->suppress_errors = (bool) $suppress; return $errors; } @@ -565,11 +1010,48 @@ class wpdb { * Kill cached query results. * * @since 0.71 + * @return void */ function flush() { $this->last_result = array(); - $this->col_info = null; - $this->last_query = null; + $this->col_info = null; + $this->last_query = null; + } + + function db_connect( $query = "SELECT" ) { + global $db_list, $global_db_list; + if ( ! is_array( $db_list ) ) + return true; + + if ( $this->blogs != '' && preg_match("/(" . $this->blogs . "|" . $this->users . "|" . $this->usermeta . "|" . $this->site . "|" . $this->sitemeta . "|" . $this->sitecategories . ")/i",$query) ) { + $action = 'global'; + $details = $global_db_list[ mt_rand( 0, count( $global_db_list ) -1 ) ]; + $this->db_global = $details; + } elseif ( preg_match("/^\\s*(alter table|create|insert|delete|update|replace) /i",$query) ) { + $action = 'write'; + $details = $db_list[ 'write' ][ mt_rand( 0, count( $db_list[ 'write' ] ) -1 ) ]; + $this->db_write = $details; + } else { + $action = ''; + $details = $db_list[ 'read' ][ mt_rand( 0, count( $db_list[ 'read' ] ) -1 ) ]; + $this->db_read = $details; + } + + $dbhname = "dbh" . $action; + $this->$dbhname = @mysql_connect( $details[ 'db_host' ], $details[ 'db_user' ], $details[ 'db_password' ] ); + if (!$this->$dbhname ) { + $this->bail( sprintf( /*WP_I18N_DB_CONN_ERROR*/" +

Error establishing a database connection

+

This either means that the username and password information in your wp-config.php file is incorrect or we can't contact the database server at %s. This could mean your host's database server is down.

+ +

If you're unsure what these terms mean you should probably contact your host. If you still need help you can always visit the WordPress Support Forums.

+"/*/WP_I18N_DB_CONN_ERROR*/, $details['db_host'] ), 'db_connect_fail' ); + } + $this->select( $details[ 'db_name' ], $this->$dbhname ); } /** @@ -579,19 +1061,17 @@ class wpdb { * * @since 0.71 * - * @param string $query - * @return unknown + * @param string $query Database query + * @return int|false Number of rows affected/selected or false on error */ - function query($query) { + function query( $query ) { if ( ! $this->ready ) return false; - // filter the query, if filters are available - // NOTE: some queries are made before the plugins have been loaded, and thus cannot be filtered with this method - if ( function_exists('apply_filters') ) - $query = apply_filters('query', $query); + // some queries are made before the plugins have been loaded, and thus cannot be filtered with this method + if ( function_exists( 'apply_filters' ) ) + $query = apply_filters( 'query', $query ); - // initialise return $return_val = 0; $this->flush(); @@ -601,151 +1081,268 @@ class wpdb { // Keep track of the last query for debug.. $this->last_query = $query; - // Perform the query via std mysql_query function.. - if ( defined('SAVEQUERIES') && SAVEQUERIES ) + if ( defined( 'SAVEQUERIES' ) && SAVEQUERIES ) $this->timer_start(); - $this->result = @mysql_query($query, $this->dbh); - ++$this->num_queries; + // use $this->dbh for read ops, and $this->dbhwrite for write ops + // use $this->dbhglobal for gloal table ops + unset( $dbh ); + if( defined( 'WP_USE_MULTIPLE_DB' ) && WP_USE_MULTIPLE_DB ) { + if( $this->blogs != '' && preg_match("/(" . $this->blogs . "|" . $this->users . "|" . $this->usermeta . "|" . $this->site . "|" . $this->sitemeta . "|" . $this->sitecategories . ")/i",$query) ) { + if( false == isset( $this->dbhglobal ) ) { + $this->db_connect( $query ); + } + $dbh =& $this->dbhglobal; + $this->last_db_used = "global"; + } elseif ( preg_match("/^\\s*(alter table|create|insert|delete|update|replace) /i",$query) ) { + if( false == isset( $this->dbhwrite ) ) { + $this->db_connect( $query ); + } + $dbh =& $this->dbhwrite; + $this->last_db_used = "write"; + } else { + $dbh =& $this->dbh; + $this->last_db_used = "read"; + } + } else { + $dbh =& $this->dbh; + $this->last_db_used = "other/read"; + } + + $this->result = @mysql_query( $query, $dbh ); + $this->num_queries++; - if ( defined('SAVEQUERIES') && SAVEQUERIES ) + if ( defined( 'SAVEQUERIES' ) && SAVEQUERIES ) $this->queries[] = array( $query, $this->timer_stop(), $this->get_caller() ); // If there is an error then take note of it.. - if ( $this->last_error = mysql_error($this->dbh) ) { + if ( $this->last_error = mysql_error( $dbh ) ) { $this->print_error(); return false; } - if ( preg_match("/^\\s*(insert|delete|update|replace) /i",$query) ) { - $this->rows_affected = mysql_affected_rows($this->dbh); + if ( preg_match( "/^\\s*(insert|delete|update|replace|alter) /i", $query ) ) { + $this->rows_affected = mysql_affected_rows( $dbh ); // Take note of the insert_id - if ( preg_match("/^\\s*(insert|replace) /i",$query) ) { - $this->insert_id = mysql_insert_id($this->dbh); + if ( preg_match( "/^\\s*(insert|replace) /i", $query ) ) { + $this->insert_id = mysql_insert_id($dbh); } // Return number of rows affected $return_val = $this->rows_affected; } else { $i = 0; - while ($i < @mysql_num_fields($this->result)) { - $this->col_info[$i] = @mysql_fetch_field($this->result); + while ( $i < @mysql_num_fields( $this->result ) ) { + $this->col_info[$i] = @mysql_fetch_field( $this->result ); $i++; } $num_rows = 0; - while ( $row = @mysql_fetch_object($this->result) ) { + while ( $row = @mysql_fetch_object( $this->result ) ) { $this->last_result[$num_rows] = $row; $num_rows++; } - @mysql_free_result($this->result); + @mysql_free_result( $this->result ); // Log number of rows the query returned + // and return number of rows selected $this->num_rows = $num_rows; - - // Return number of rows selected - $return_val = $this->num_rows; + $return_val = $num_rows; } return $return_val; } /** - * Insert an array of data into a table. + * Insert a row into a table. + * + * + * wpdb::insert( 'table', array( 'column' => 'foo', 'field' => 'bar' ) ) + * wpdb::insert( 'table', array( 'column' => 'foo', 'field' => 1337 ), array( '%s', '%d' ) ) + * * * @since 2.5.0 + * @see wpdb::prepare() + * @see wpdb::$field_types + * @see wp_set_wpdb_vars() + * + * @param string $table table name + * @param array $data Data to insert (in column => value pairs). Both $data columns and $data values should be "raw" (neither should be SQL escaped). + * @param array|string $format Optional. An array of formats to be mapped to each of the value in $data. If string, that format will be used for all of the values in $data. + * A format is one of '%d', '%s' (decimal number, string). If omitted, all values in $data will be treated as strings unless otherwise specified in wpdb::$field_types. + * @return int|false The number of rows inserted, or false on error. + */ + function insert( $table, $data, $format = null ) { + return $this->_insert_replace_helper( $table, $data, $format, 'INSERT' ); + } + + /** + * Replace a row into a table. + * + * + * wpdb::replace( 'table', array( 'column' => 'foo', 'field' => 'bar' ) ) + * wpdb::replace( 'table', array( 'column' => 'foo', 'field' => 1337 ), array( '%s', '%d' ) ) + * + * + * @since 3.0.0 + * @see wpdb::prepare() + * @see wpdb::$field_types + * @see wp_set_wpdb_vars() + * + * @param string $table table name + * @param array $data Data to insert (in column => value pairs). Both $data columns and $data values should be "raw" (neither should be SQL escaped). + * @param array|string $format Optional. An array of formats to be mapped to each of the value in $data. If string, that format will be used for all of the values in $data. + * A format is one of '%d', '%s' (decimal number, string). If omitted, all values in $data will be treated as strings unless otherwise specified in wpdb::$field_types. + * @return int|false The number of rows affected, or false on error. + */ + function replace( $table, $data, $format = null ) { + return $this->_insert_replace_helper( $table, $data, $format, 'REPLACE' ); + } + + /** + * Helper function for insert and replace. * - * @param string $table WARNING: not sanitized! - * @param array $data Should not already be SQL-escaped - * @return mixed Results of $this->query() + * Runs an insert or replace query based on $type argument. + * + * @access private + * @since 3.0.0 + * @see wpdb::prepare() + * @see wpdb::$field_types + * @see wp_set_wpdb_vars() + * + * @param string $table table name + * @param array $data Data to insert (in column => value pairs). Both $data columns and $data values should be "raw" (neither should be SQL escaped). + * @param array|string $format Optional. An array of formats to be mapped to each of the value in $data. If string, that format will be used for all of the values in $data. + * A format is one of '%d', '%s' (decimal number, string). If omitted, all values in $data will be treated as strings unless otherwise specified in wpdb::$field_types. + * @return int|false The number of rows affected, or false on error. */ - function insert($table, $data) { - $data = add_magic_quotes($data); - $fields = array_keys($data); - return $this->query("INSERT INTO $table (`" . implode('`,`',$fields) . "`) VALUES ('".implode("','",$data)."')"); + function _insert_replace_helper( $table, $data, $format = null, $type = 'INSERT' ) { + if ( ! in_array( strtoupper( $type ), array( 'REPLACE', 'INSERT' ) ) ) + return false; + $formats = $format = (array) $format; + $fields = array_keys( $data ); + $formatted_fields = array(); + foreach ( $fields as $field ) { + if ( !empty( $format ) ) + $form = ( $form = array_shift( $formats ) ) ? $form : $format[0]; + elseif ( isset( $this->field_types[$field] ) ) + $form = $this->field_types[$field]; + else + $form = '%s'; + $formatted_fields[] = $form; + } + $sql = "{$type} INTO `$table` (`" . implode( '`,`', $fields ) . "`) VALUES ('" . implode( "','", $formatted_fields ) . "')"; + return $this->query( $this->prepare( $sql, $data ) ); } /** - * Update a row in the table with an array of data. + * Update a row in the table * - * @since 2.5.0 + * + * wpdb::update( 'table', array( 'column' => 'foo', 'field' => 'bar' ), array( 'ID' => 1 ) ) + * wpdb::update( 'table', array( 'column' => 'foo', 'field' => 1337 ), array( 'ID' => 1 ), array( '%s', '%d' ), array( '%d' ) ) + * * - * @param string $table WARNING: not sanitized! - * @param array $data Should not already be SQL-escaped - * @param array $where A named array of WHERE column => value relationships. Multiple member pairs will be joined with ANDs. WARNING: the column names are not currently sanitized! - * @return mixed Results of $this->query() + * @since 2.5.0 + * @see wpdb::prepare() + * @see wpdb::$field_types + * @see wp_set_wpdb_vars() + * + * @param string $table table name + * @param array $data Data to update (in column => value pairs). Both $data columns and $data values should be "raw" (neither should be SQL escaped). + * @param array $where A named array of WHERE clauses (in column => value pairs). Multiple clauses will be joined with ANDs. Both $where columns and $where values should be "raw". + * @param array|string $format Optional. An array of formats to be mapped to each of the values in $data. If string, that format will be used for all of the values in $data. + * A format is one of '%d', '%s' (decimal number, string). If omitted, all values in $data will be treated as strings unless otherwise specified in wpdb::$field_types. + * @param array|string $format_where Optional. An array of formats to be mapped to each of the values in $where. If string, that format will be used for all of the items in $where. A format is one of '%d', '%s' (decimal number, string). If omitted, all values in $where will be treated as strings. + * @return int|false The number of rows updated, or false on error. */ - function update($table, $data, $where){ - $data = add_magic_quotes($data); + function update( $table, $data, $where, $format = null, $where_format = null ) { + if ( ! is_array( $data ) || ! is_array( $where ) ) + return false; + + $formats = $format = (array) $format; $bits = $wheres = array(); - foreach ( array_keys($data) as $k ) - $bits[] = "`$k` = '$data[$k]'"; + foreach ( (array) array_keys( $data ) as $field ) { + if ( !empty( $format ) ) + $form = ( $form = array_shift( $formats ) ) ? $form : $format[0]; + elseif ( isset($this->field_types[$field]) ) + $form = $this->field_types[$field]; + else + $form = '%s'; + $bits[] = "`$field` = {$form}"; + } - if ( is_array( $where ) ) - foreach ( $where as $c => $v ) - $wheres[] = "$c = '" . $this->escape( $v ) . "'"; - else - return false; - - return $this->query( "UPDATE $table SET " . implode( ', ', $bits ) . ' WHERE ' . implode( ' AND ', $wheres ) ); + $where_formats = $where_format = (array) $where_format; + foreach ( (array) array_keys( $where ) as $field ) { + if ( !empty( $where_format ) ) + $form = ( $form = array_shift( $where_formats ) ) ? $form : $where_format[0]; + elseif ( isset( $this->field_types[$field] ) ) + $form = $this->field_types[$field]; + else + $form = '%s'; + $wheres[] = "`$field` = {$form}"; + } + + $sql = "UPDATE `$table` SET " . implode( ', ', $bits ) . ' WHERE ' . implode( ' AND ', $wheres ); + return $this->query( $this->prepare( $sql, array_merge( array_values( $data ), array_values( $where ) ) ) ); } /** * Retrieve one variable from the database. * - * This combines the functionality of wpdb::get_row() and wpdb::get_col(), - * so both the column and row can be picked. - * - * It is possible to use this function without executing more queries. If - * you already made a query, you can set the $query to 'null' value and just - * retrieve either the column and row of the last query result. + * Executes a SQL query and returns the value from the SQL result. + * If the SQL result contains more than one column and/or more than one row, this function returns the value in the column and row specified. + * If $query is null, this function returns the value in the specified column and row from the previous SQL result. * * @since 0.71 * - * @param string $query Can be null as well, for caching - * @param int $x Column num to return - * @param int $y Row num to return - * @return mixed Database query results + * @param string|null $query Optional. SQL query. Defaults to null, use the result from the previous query. + * @param int $x Optional. Column of value to return. Indexed from 0. + * @param int $y Optional. Row of value to return. Indexed from 0. + * @return string|null Database query result (as string), or null on failure */ - function get_var($query=null, $x = 0, $y = 0) { - $this->func_call = "\$db->get_var(\"$query\",$x,$y)"; + function get_var( $query = null, $x = 0, $y = 0 ) { + $this->func_call = "\$db->get_var(\"$query\", $x, $y)"; if ( $query ) - $this->query($query); + $this->query( $query ); // Extract var out of cached results based x,y vals if ( !empty( $this->last_result[$y] ) ) { - $values = array_values(get_object_vars($this->last_result[$y])); + $values = array_values( get_object_vars( $this->last_result[$y] ) ); } // If there is a value return it else return null - return (isset($values[$x]) && $values[$x]!=='') ? $values[$x] : null; + return ( isset( $values[$x] ) && $values[$x] !== '' ) ? $values[$x] : null; } /** * Retrieve one row from the database. * + * Executes a SQL query and returns the row from the SQL result. + * * @since 0.71 * - * @param string $query SQL query - * @param string $output ARRAY_A | ARRAY_N | OBJECT - * @param int $y Row num to return - * @return mixed Database query results + * @param string|null $query SQL query. + * @param string $output Optional. one of ARRAY_A | ARRAY_N | OBJECT constants. Return an associative array (column => value, ...), + * a numerically indexed array (0 => value, ...) or an object ( ->column = value ), respectively. + * @param int $y Optional. Row to return. Indexed from 0. + * @return mixed Database query result in format specifed by $output or null on failure */ - function get_row($query = null, $output = OBJECT, $y = 0) { + function get_row( $query = null, $output = OBJECT, $y = 0 ) { $this->func_call = "\$db->get_row(\"$query\",$output,$y)"; if ( $query ) - $this->query($query); + $this->query( $query ); else return null; - if ( !isset($this->last_result[$y]) ) + if ( !isset( $this->last_result[$y] ) ) return null; if ( $output == OBJECT ) { return $this->last_result[$y] ? $this->last_result[$y] : null; } elseif ( $output == ARRAY_A ) { - return $this->last_result[$y] ? get_object_vars($this->last_result[$y]) : null; + return $this->last_result[$y] ? get_object_vars( $this->last_result[$y] ) : null; } elseif ( $output == ARRAY_N ) { - return $this->last_result[$y] ? array_values(get_object_vars($this->last_result[$y])) : null; + return $this->last_result[$y] ? array_values( get_object_vars( $this->last_result[$y] ) ) : null; } else { $this->print_error(/*WP_I18N_DB_GETROW_ERROR*/" \$db->get_row(string query, output type, int offset) -- Output type must be one of: OBJECT, ARRAY_A, ARRAY_N"/*/WP_I18N_DB_GETROW_ERROR*/); } @@ -754,41 +1351,50 @@ class wpdb { /** * Retrieve one column from the database. * + * Executes a SQL query and returns the column from the SQL result. + * If the SQL result contains more than one column, this function returns the column specified. + * If $query is null, this function returns the specified column from the previous SQL result. + * * @since 0.71 * - * @param string $query Can be null as well, for caching - * @param int $x Col num to return. Starts from 0. - * @return array Column results + * @param string|null $query Optional. SQL query. Defaults to previous query. + * @param int $x Optional. Column to return. Indexed from 0. + * @return array Database query result. Array indexed from 0 by SQL result row number. */ - function get_col($query = null , $x = 0) { + function get_col( $query = null , $x = 0 ) { if ( $query ) - $this->query($query); + $this->query( $query ); $new_array = array(); // Extract the column values - for ( $i=0; $i < count($this->last_result); $i++ ) { - $new_array[$i] = $this->get_var(null, $x, $i); + for ( $i = 0, $j = count( $this->last_result ); $i < $j; $i++ ) { + $new_array[$i] = $this->get_var( null, $x, $i ); } return $new_array; } /** - * Retrieve an entire result set from the database. + * Retrieve an entire SQL result set from the database (i.e., many rows) + * + * Executes a SQL query and returns the entire SQL result. * * @since 0.71 * - * @param string|null $query Can also be null to pull from the cache - * @param string $output ARRAY_A | ARRAY_N | OBJECT_K | OBJECT + * @param string $query SQL query. + * @param string $output Optional. Any of ARRAY_A | ARRAY_N | OBJECT | OBJECT_K constants. With one of the first three, return an array of rows indexed from 0 by SQL result row number. + * Each row is an associative array (column => value, ...), a numerically indexed array (0 => value, ...), or an object. ( ->column = value ), respectively. + * With OBJECT_K, return an associative array of row objects keyed by the value of each row's first column's value. Duplicate keys are discarded. * @return mixed Database query results */ - function get_results($query = null, $output = OBJECT) { + function get_results( $query = null, $output = OBJECT ) { $this->func_call = "\$db->get_results(\"$query\", $output)"; if ( $query ) - $this->query($query); + $this->query( $query ); else return null; + $new_array = array(); if ( $output == OBJECT ) { // Return an integer-keyed array of row objects return $this->last_result; @@ -796,28 +1402,27 @@ class wpdb { // Return an array of row objects with keys from column 1 // (Duplicates are discarded) foreach ( $this->last_result as $row ) { - $key = array_shift( get_object_vars( $row ) ); - if ( !isset( $new_array[ $key ] ) ) + $key = array_shift( $var_by_ref = get_object_vars( $row ) ); + if ( ! isset( $new_array[ $key ] ) ) $new_array[ $key ] = $row; } return $new_array; } elseif ( $output == ARRAY_A || $output == ARRAY_N ) { // Return an integer-keyed array of... if ( $this->last_result ) { - $i = 0; - foreach( $this->last_result as $row ) { + foreach( (array) $this->last_result as $row ) { if ( $output == ARRAY_N ) { // ...integer-keyed row arrays - $new_array[$i] = array_values( get_object_vars( $row ) ); + $new_array[] = array_values( get_object_vars( $row ) ); } else { // ...column name-keyed row arrays - $new_array[$i] = get_object_vars( $row ); + $new_array[] = get_object_vars( $row ); } - ++$i; } - return $new_array; } + return $new_array; } + return null; } /** @@ -825,15 +1430,16 @@ class wpdb { * * @since 0.71 * - * @param string $info_type one of name, table, def, max_length, not_null, primary_key, multiple_key, unique_key, numeric, blob, type, unsigned, zerofill - * @param int $col_offset 0: col name. 1: which table the col's in. 2: col's max length. 3: if the col is numeric. 4: col's type + * @param string $info_type Optional. Type one of name, table, def, max_length, not_null, primary_key, multiple_key, unique_key, numeric, blob, type, unsigned, zerofill + * @param int $col_offset Optional. 0: col name. 1: which table the col's in. 2: col's max length. 3: if the col is numeric. 4: col's type * @return mixed Column Results */ - function get_col_info($info_type = 'name', $col_offset = -1) { + function get_col_info( $info_type = 'name', $col_offset = -1 ) { if ( $this->col_info ) { if ( $col_offset == -1 ) { $i = 0; - foreach($this->col_info as $col ) { + $new_array = array(); + foreach( (array) $this->col_info as $col ) { $new_array[$i] = $col->{$info_type}; $i++; } @@ -849,11 +1455,10 @@ class wpdb { * * @since 1.5.0 * - * @return bool Always returns true + * @return true */ function timer_start() { - $mtime = microtime(); - $mtime = explode(' ', $mtime); + $mtime = explode( ' ', microtime() ); $this->time_start = $mtime[1] + $mtime[0]; return true; } @@ -866,25 +1471,27 @@ class wpdb { * @return int Total time spent on the query, in milliseconds */ function timer_stop() { - $mtime = microtime(); - $mtime = explode(' ', $mtime); - $time_end = $mtime[1] + $mtime[0]; + $mtime = explode( ' ', microtime() ); + $time_end = $mtime[1] + $mtime[0]; $time_total = $time_end - $this->time_start; return $time_total; } /** - * Wraps fatal errors in a nice header and footer and dies. + * Wraps errors in a nice header and footer and dies. + * + * Will not die if wpdb::$show_errors is true * * @since 1.5.0 * - * @param string $message - * @return unknown + * @param string $message The Error message + * @param string $error_code Optional. A Computer readable string to identify the error. + * @return false|void */ - function bail($message) { + function bail( $message, $error_code = '500' ) { if ( !$this->show_errors ) { - if ( class_exists('WP_Error') ) - $this->error = new WP_Error('500', $message); + if ( class_exists( 'WP_Error' ) ) + $this->error = new WP_Error($error_code, $message); else $this->error = $message; return false; @@ -893,24 +1500,23 @@ class wpdb { } /** - * Whether or not MySQL database is minimal required version. + * Whether MySQL database is at least the required minimum version. * * @since 2.5.0 * @uses $wp_version + * @uses $required_mysql_version * * @return WP_Error */ - function check_database_version() - { - global $wp_version; - // Make sure the server has MySQL 4.0 - $mysql_version = preg_replace('|[^0-9\.]|', '', @mysql_get_server_info($this->dbh)); - if ( version_compare($mysql_version, '4.0.0', '<') ) - return new WP_Error('database_version',sprintf(__('ERROR: WordPress %s requires MySQL 4.0.0 or higher'), $wp_version)); + function check_database_version() { + global $wp_version, $required_mysql_version; + // Make sure the server has the required MySQL version + if ( version_compare($this->db_version(), $required_mysql_version, '<') ) + return new WP_Error('database_version', sprintf( __( 'ERROR: WordPress %1$s requires MySQL %2$s or higher' ), $wp_version, $required_mysql_version )); } /** - * Whether of not the database version supports collation. + * Whether the database supports collation. * * Called when WordPress is generating the table scheme. * @@ -918,15 +1524,36 @@ class wpdb { * * @return bool True if collation is supported, false if version does not */ - function supports_collation() - { - return ( version_compare(mysql_get_server_info($this->dbh), '4.1.0', '>=') ); + function supports_collation() { + return $this->has_cap( 'collation' ); + } + + /** + * Determine if a database supports a particular feature + * + * @since 2.7 + * @see wpdb::db_version() + * + * @param string $db_cap the feature + * @return bool + */ + function has_cap( $db_cap ) { + $version = $this->db_version(); + + switch ( strtolower( $db_cap ) ) { + case 'collation' : // @since 2.5.0 + case 'group_concat' : // @since 2.7 + case 'subqueries' : // @since 2.7 + return version_compare( $version, '4.1', '>=' ); + }; + + return false; } /** * Retrieve the name of the function that called wpdb. * - * Requires PHP 4.3 and searches up the list of functions until it reaches + * Searches up the list of functions until it reaches * the one that would most logically had called this method. * * @since 2.5.0 @@ -934,37 +1561,34 @@ class wpdb { * @return string The name of the calling function */ function get_caller() { - // requires PHP 4.3+ - if ( !is_callable('debug_backtrace') ) - return ''; - - $bt = debug_backtrace(); - $caller = ''; - - foreach ( $bt as $trace ) { - if ( @$trace['class'] == __CLASS__ ) - continue; - elseif ( strtolower(@$trace['function']) == 'call_user_func_array' ) - continue; - elseif ( strtolower(@$trace['function']) == 'apply_filters' ) - continue; - elseif ( strtolower(@$trace['function']) == 'do_action' ) - continue; - - $caller = $trace['function']; - break; + $trace = array_reverse( debug_backtrace() ); + $caller = array(); + + foreach ( $trace as $call ) { + if ( isset( $call['class'] ) && __CLASS__ == $call['class'] ) + continue; // Filter out wpdb calls. + $caller[] = isset( $call['class'] ) ? "{$call['class']}->{$call['function']}" : $call['function']; } - return $caller; + + return join( ', ', $caller ); } + /** + * The database version number. + * + * @return false|string false on failure, version number on success + */ + function db_version() { + return preg_replace( '/[^0-9.].*/', '', mysql_get_server_info( $this->dbh ) ); + } } -if ( ! isset($wpdb) ) { +if ( ! isset( $wpdb ) ) { /** - * WordPress Database Object, if it isn't set already in wp-content/wpdb.php + * WordPress Database Object, if it isn't set already in wp-content/db.php * @global object $wpdb Creates a new wpdb object based on wp-config.php Constants for the database * @since 0.71 */ - $wpdb = new wpdb(DB_USER, DB_PASSWORD, DB_NAME, DB_HOST); + $wpdb = new wpdb( DB_USER, DB_PASSWORD, DB_NAME, DB_HOST ); } ?>