namespace Wikimedia\Rdbms;
-use Wikimedia;
use Exception;
+use RuntimeException;
use stdClass;
+use Wikimedia\AtEase\AtEase;
/**
* @ingroup Database
}
protected function open( $server, $user, $password, $dbName, $schema, $tablePrefix ) {
- # Test for driver support, to avoid suppressed fatal error
+ // Test for driver support, to avoid suppressed fatal error
if ( !function_exists( 'sqlsrv_connect' ) ) {
throw new DBConnectionError(
$this,
);
}
- # e.g. the class is being loaded
- if ( !strlen( $user ) ) {
- return null;
- }
-
$this->close();
$this->server = $server;
$this->user = $user;
$connectionInfo['PWD'] = $password;
}
- Wikimedia\suppressWarnings();
+ AtEase::suppressWarnings();
$this->conn = sqlsrv_connect( $server, $connectionInfo );
- Wikimedia\restoreWarnings();
+ AtEase::restoreWarnings();
if ( $this->conn === false ) {
- throw new DBConnectionError( $this, $this->lastError() );
+ $error = $this->lastError();
+ $this->connLogger->error(
+ "Error connecting to {db_server}: {error}",
+ $this->getLogContext( [ 'method' => __METHOD__, 'error' => $error ] )
+ );
+ throw new DBConnectionError( $this, $error );
}
- $this->opened = true;
$this->currentDomain = new DatabaseDomain(
( $dbName != '' ) ? $dbName : null,
null,
return $statementOnly;
}
+ public function serverIsReadOnly() {
+ $encDatabase = $this->addQuotes( $this->getDBname() );
+ $res = $this->query(
+ "SELECT IS_READ_ONLY FROM SYS.DATABASES WHERE NAME = $encDatabase",
+ __METHOD__
+ );
+ $row = $this->fetchObject( $res );
+
+ return $row ? (bool)$row->IS_READ_ONLY : false;
+ }
+
/**
* @return int
*/
$this->query( 'ROLLBACK TRANSACTION ' . $this->addIdentifierQuotes( $identifier ), $fname );
}
- /**
- * Begin a transaction, committing any previously open transaction
- * @param string $fname
- */
protected function doBegin( $fname = __METHOD__ ) {
- sqlsrv_begin_transaction( $this->conn );
- $this->trxLevel = 1;
+ if ( !sqlsrv_begin_transaction( $this->conn ) ) {
+ $this->reportQueryError( $this->lastError(), $this->lastErrno(), 'BEGIN', $fname );
+ }
}
/**
* @param string $fname
*/
protected function doCommit( $fname = __METHOD__ ) {
- sqlsrv_commit( $this->conn );
- $this->trxLevel = 0;
+ if ( !sqlsrv_commit( $this->conn ) ) {
+ $this->reportQueryError( $this->lastError(), $this->lastErrno(), 'COMMIT', $fname );
+ }
}
/**
* @param string $fname
*/
protected function doRollback( $fname = __METHOD__ ) {
- sqlsrv_rollback( $this->conn );
- $this->trxLevel = 0;
+ if ( !sqlsrv_rollback( $this->conn ) ) {
+ $this->queryLogger->error(
+ "{fname}\t{db_server}\t{errno}\t{error}\t",
+ $this->getLogContext( [
+ 'errno' => $this->lastErrno(),
+ 'error' => $this->lastError(),
+ 'fname' => $fname,
+ 'trace' => ( new RuntimeException() )->getTraceAsString()
+ ] )
+ );
+ }
}
/**
$database = $domain->getDatabase();
if ( $database !== $this->getDBname() ) {
- $encDatabase = $this->addIdentifierQuotes( $database );
- $res = $this->doQuery( "USE $encDatabase" );
- if ( !$res ) {
- throw new DBExpectedError( $this, "Could not select database '$database'." );
+ $sql = 'USE ' . $this->addIdentifierQuotes( $database );
+ list( $res, $err, $errno ) =
+ $this->executeQuery( $sql, __METHOD__, self::QUERY_IGNORE_DBO_TRX );
+
+ if ( $res === false ) {
+ $this->reportQueryError( $err, $errno, $sql, __METHOD__ );
+ return false; // unreachable
}
}
// Update that domain fields on success (no exception thrown)