diff --git a/autoload.php b/autoload.php index 61fd192f0d5..4dd5f128766 100644 --- a/autoload.php +++ b/autoload.php @@ -1636,6 +1636,7 @@ $wgAutoloadLocalClasses = [ 'Wikimedia\\Rdbms\\DBExpectedError' => __DIR__ . '/includes/libs/rdbms/exception/DBExpectedError.php', 'Wikimedia\\Rdbms\\DBMasterPos' => __DIR__ . '/includes/libs/rdbms/database/position/DBMasterPos.php', 'Wikimedia\\Rdbms\\DBQueryError' => __DIR__ . '/includes/libs/rdbms/exception/DBQueryError.php', + 'Wikimedia\\Rdbms\\DBQueryTimeoutError' => __DIR__ . '/includes/libs/rdbms/exception/DBQueryTimeoutError.php', 'Wikimedia\\Rdbms\\DBReadOnlyError' => __DIR__ . '/includes/libs/rdbms/exception/DBReadOnlyError.php', 'Wikimedia\\Rdbms\\DBReplicationWaitError' => __DIR__ . '/includes/libs/rdbms/exception/DBReplicationWaitError.php', 'Wikimedia\\Rdbms\\DBTransactionError' => __DIR__ . '/includes/libs/rdbms/exception/DBTransactionError.php', diff --git a/includes/libs/rdbms/database/Database.php b/includes/libs/rdbms/database/Database.php index c9040928b0a..e7417eb84a2 100644 --- a/includes/libs/rdbms/database/Database.php +++ b/includes/libs/rdbms/database/Database.php @@ -1130,6 +1130,19 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware } } + /** + * Checks whether the cause of the error is detected to be a timeout. + * + * It returns false by default, and not all engines support detecting this yet. + * If this returns false, it will be treated as a generic query error. + * + * @param string $error Error text + * @param int $errno Error number + */ + protected function wasQueryTimeout( $error, $errno ) { + return false; + } + public function reportQueryError( $error, $errno, $sql, $fname, $tempIgnore = false ) { if ( $this->ignoreErrors() || $tempIgnore ) { $this->queryLogger->debug( "SQL ERROR (ignored): $error\n" ); @@ -1146,7 +1159,12 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware ] ) ); $this->queryLogger->debug( "SQL ERROR: " . $error . "\n" ); - throw new DBQueryError( $this, $error, $errno, $sql, $fname ); + $wasQueryTimeout = $this->wasQueryTimeout( $error, $errno ); + if ( $wasQueryTimeout ) { + throw new DBQueryTimeoutError( $this, $error, $errno, $sql, $fname ); + } else { + throw new DBQueryError( $this, $error, $errno, $sql, $fname ); + } } } diff --git a/includes/libs/rdbms/database/DatabaseMysqlBase.php b/includes/libs/rdbms/database/DatabaseMysqlBase.php index 3c4cda55525..5312a3d0325 100644 --- a/includes/libs/rdbms/database/DatabaseMysqlBase.php +++ b/includes/libs/rdbms/database/DatabaseMysqlBase.php @@ -486,6 +486,10 @@ abstract class DatabaseMysqlBase extends Database { */ abstract protected function mysqlError( $conn = null ); + protected function wasQueryTimeout( $error, $errno ) { + return $errno == 2062; + } + /** * @param string $table * @param array $uniqueIndexes diff --git a/includes/libs/rdbms/exception/DBQueryError.php b/includes/libs/rdbms/exception/DBQueryError.php index a8ea3ade421..e6870a7e2e2 100644 --- a/includes/libs/rdbms/exception/DBQueryError.php +++ b/includes/libs/rdbms/exception/DBQueryError.php @@ -40,19 +40,22 @@ class DBQueryError extends DBExpectedError { * @param int|string $errno * @param string $sql * @param string $fname + * @param string $message Optional message, intended for subclases (optional) */ - public function __construct( IDatabase $db, $error, $errno, $sql, $fname ) { - if ( $db instanceof Database && $db->wasConnectionError( $errno ) ) { - $message = "A connection error occured. \n" . - "Query: $sql\n" . - "Function: $fname\n" . - "Error: $errno $error\n"; - } else { - $message = "A database query error has occurred. Did you forget to run " . - "your application's database schema updater after upgrading? \n" . - "Query: $sql\n" . - "Function: $fname\n" . - "Error: $errno $error\n"; + public function __construct( IDatabase $db, $error, $errno, $sql, $fname, $message = null ) { + if ( $message === null ) { + if ( $db instanceof Database && $db->wasConnectionError( $errno ) ) { + $message = "A connection error occured. \n" . + "Query: $sql\n" . + "Function: $fname\n" . + "Error: $errno $error\n"; + } else { + $message = "A database query error has occurred. Did you forget to run " . + "your application's database schema updater after upgrading? \n" . + "Query: $sql\n" . + "Function: $fname\n" . + "Error: $errno $error\n"; + } } parent::__construct( $db, $message ); diff --git a/includes/libs/rdbms/exception/DBQueryTimeoutError.php b/includes/libs/rdbms/exception/DBQueryTimeoutError.php new file mode 100644 index 00000000000..ea91d9550ea --- /dev/null +++ b/includes/libs/rdbms/exception/DBQueryTimeoutError.php @@ -0,0 +1,38 @@ +