Index: src/wp-includes/wp-db.php =================================================================== --- src/wp-includes/wp-db.php (revision 27061) +++ src/wp-includes/wp-db.php (working copy) @@ -158,6 +158,16 @@ var $queries; /** + * The number of times to retry reconnecting before dying. + * + * @since 3.9.0 + * @access protected + * @see wpdb::check_connection() + * @var int + */ + protected $reconnect_retries = 5; + + /** * WordPress table prefix * * You can set this to have multiple WordPress installations @@ -1130,8 +1140,12 @@ * Connect to and select database * * @since 3.0.0 + * + * @param bool $allow_bail Optional. Allows the function to bail, default true. If this is set to false, you will need to handle the lack of database connection manually. Available since 3.9.0. + * + * @return bool true on successful connection, false on unsuccessful connection */ - function db_connect() { + function db_connect( $allow_bail = true ) { $this->is_mysql = true; @@ -1152,7 +1166,7 @@ $this->dbh = @mysql_connect( $this->dbhost, $this->dbuser, $this->dbpassword, $new_link, $client_flags ); } - if ( !$this->dbh ) { + if ( ! $this->dbh && $allow_bail ) { wp_load_translations_early(); // Load custom DB error template, if present. @@ -1172,14 +1186,62 @@
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.
" ), htmlspecialchars( $this->dbhost, ENT_QUOTES ) ), 'db_connect_fail' ); - return; + return false; + } else if ( $this->dbh ) { + $this->set_charset( $this->dbh ); + $this->ready = true; + $this->select( $this->dbname, $this->dbh ); + + return true; } - $this->set_charset( $this->dbh ); + return false; + } - $this->ready = true; + /** + * Check that the connection to the database is still up. If not, try to reconnect. + * + * @since 3.9.0 + * + * @return bool true if the connection is up, false if it's down and we were unable to reconnect + */ + function check_connection() { + if ( @mysql_ping( $this->dbh ) ) { + return true; + } - $this->select( $this->dbname, $this->dbh ); + $error_reporting = false; + + for ( $tries = 1; $tries <= $this->reconnect_retries; $tries++ ) { + if ( $tries === 2 && WP_DEBUG ) { + $error_reporting = error_reporting(); + error_reporting( $error_reporting ^ E_WARNING ); + } + + if ( $this->db_connect( false ) ) { + if ( $error_reporting ) { + error_reporting( $error_reporting ); + } + + return true; + } + + sleep( 1 ); + } + + // We weren't able to reconnect, so we better bail + $this->bail( sprintf( __( " +This means that we lost our connection to the database server at %s
, your host's database server may be 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.
+" ), htmlspecialchars( $this->dbhost, ENT_QUOTES ) ), 'db_connect_fail' ); + + // If the bail didn't call wp_die, it's time to die, because the DB isn't coming back. + dead_db(); } /** @@ -1214,15 +1276,15 @@ // Keep track of the last query for debug.. $this->last_query = $query; - if ( defined( 'SAVEQUERIES' ) && SAVEQUERIES ) - $this->timer_start(); + $this->_do_query( $query ); - $this->result = @mysql_query( $query, $this->dbh ); - $this->num_queries++; + // MySQL server has gone away, try to reconnect + if ( empty( $this->dbh ) || 2006 == mysql_errno( $this->dbh ) ) { + if ( $this->check_connection() ) { + $this->_do_query( $query ); + } + } - 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 ) ) { // Clear insert_id on a subsequent failed insert. @@ -1260,6 +1322,29 @@ } /** + * Internal function to perform the mysql_query call + * + * @since 3.9.0 + * + * @access private + * @see wpdb::query() + * + * @param string $query The query to run + */ + private function _do_query( $query ) { + if ( defined( 'SAVEQUERIES' ) && SAVEQUERIES ) { + $this->timer_start(); + } + + $this->result = @mysql_query( $query, $this->dbh ); + $this->num_queries++; + + if ( defined( 'SAVEQUERIES' ) && SAVEQUERIES ) { + $this->queries[] = array( $query, $this->timer_stop(), $this->get_caller() ); + } + } + + /** * Insert a row into a table. * *
Index: tests/phpunit/tests/db.php
===================================================================
--- tests/phpunit/tests/db.php (revision 27061)
+++ tests/phpunit/tests/db.php (working copy)
@@ -41,6 +41,23 @@
}
/**
+ * Test that WPDB will reconnect when the DB link dies
+ * @ticket 5932
+ */
+ public function test_db_reconnect() {
+ global $wpdb;
+
+ $var = $wpdb->get_var( "SELECT ID FROM $wpdb->users LIMIT 1" );
+ $this->assertGreaterThan( 0, $var );
+
+ mysql_close( $wpdb->dbh );
+ unset( $wpdb->dbh );
+
+ $var = $wpdb->get_var( "SELECT ID FROM $wpdb->users LIMIT 1" );
+ $this->assertGreaterThan( 0, $var );
+ }
+
+ /**
* Test that floats formatted as "0,700" get sanitized properly by wpdb
* @global mixed $wpdb
*