parent::__construct( $params );
}
- /**
- * Usually aborts on failure
- * @param string $server
- * @param string $user
- * @param string $password
- * @param string $dbName
- * @throws DBConnectionError
- * @return bool|resource|null
- */
- public function open( $server, $user, $password, $dbName ) {
+ protected function open( $server, $user, $password, $dbName, $schema, $tablePrefix ) {
# Test for driver support, to avoid suppressed fatal error
if ( !function_exists( 'sqlsrv_connect' ) ) {
throw new DBConnectionError(
$this->server = $server;
$this->user = $user;
$this->password = $password;
- $this->dbName = $dbName;
$connectionInfo = [];
- if ( $dbName ) {
+ if ( $dbName != '' ) {
$connectionInfo['Database'] = $dbName;
}
}
$this->opened = true;
+ $this->currentDomain = new DatabaseDomain(
+ ( $dbName != '' ) ? $dbName : null,
+ null,
+ $tablePrefix
+ );
- return $this->conn;
+ return (bool)$this->conn;
}
/**
}
/**
- * @param MssqlResultWrapper $res
+ * @param IResultWrapper $res
* @return stdClass
*/
public function fetchObject( $res ) {
}
/**
- * @param MssqlResultWrapper $res
+ * @param IResultWrapper $res
* @return array
*/
public function fetchRow( $res ) {
}
}
+ protected function wasKnownStatementRollbackError() {
+ $errors = sqlsrv_errors( SQLSRV_ERR_ALL );
+ if ( !$errors ) {
+ return false;
+ }
+ // The transaction vs statement rollback behavior depends on XACT_ABORT, so make sure
+ // that the "statement has been terminated" error (3621) is specifically present.
+ // https://docs.microsoft.com/en-us/sql/t-sql/statements/set-xact-abort-transact-sql
+ $statementOnly = false;
+ $codeWhitelist = [ '2601', '2627', '547' ];
+ foreach ( $errors as $error ) {
+ if ( $error['code'] == '3621' ) {
+ $statementOnly = true;
+ } elseif ( !in_array( $error['code'], $codeWhitelist ) ) {
+ $statementOnly = false;
+ break;
+ }
+ }
+
+ return $statementOnly;
+ }
+
/**
* @return int
*/
}
if ( $schema === false ) {
- $schema = $this->schema;
+ $schema = $this->dbSchema();
}
$res = $this->query( "SELECT 1 FROM INFORMATION_SCHEMA.TABLES
return false;
}
+ protected function doSavepoint( $identifier, $fname ) {
+ $this->query( 'SAVE TRANSACTION ' . $this->addIdentifierQuotes( $identifier ), $fname );
+ }
+
+ protected function doReleaseSavepoint( $identifier, $fname ) {
+ // Not supported. Also not really needed, a new doSavepoint() for the
+ // same identifier will overwrite the old.
+ }
+
+ protected function doRollbackToSavepoint( $identifier, $fname ) {
+ $this->query( 'ROLLBACK TRANSACTION ' . $this->addIdentifierQuotes( $identifier ), $fname );
+ }
+
/**
* Begin a transaction, committing any previously open transaction
* @param string $fname
$s );
}
- /**
- * @param string $db
- * @return bool
- */
- public function selectDB( $db ) {
- try {
- $this->dbName = $db;
- $this->query( "USE $db" );
- return true;
- } catch ( Exception $e ) {
- return false;
- }
+ protected function doSelectDomain( DatabaseDomain $domain ) {
+ $encDatabase = $this->addIdentifierQuotes( $domain->getDatabase() );
+ $this->query( "USE $encDatabase" );
+ // Update that domain fields on success (no exception thrown)
+ $this->currentDomain = $domain;
+
+ return true;
}
/**
$this->populateColumnCaches();
}
- return isset( $this->binaryColumnCache[$tableRaw] )
- ? $this->binaryColumnCache[$tableRaw]
- : [];
+ return $this->binaryColumnCache[$tableRaw] ?? [];
}
/**
$this->populateColumnCaches();
}
- return isset( $this->bitColumnCache[$tableRaw] )
- ? $this->bitColumnCache[$tableRaw]
- : [];
+ return $this->bitColumnCache[$tableRaw] ?? [];
}
private function populateColumnCaches() {
$res = $this->select( 'INFORMATION_SCHEMA.COLUMNS', '*',
[
- 'TABLE_CATALOG' => $this->dbName,
- 'TABLE_SCHEMA' => $this->schema,
+ 'TABLE_CATALOG' => $this->getDBname(),
+ 'TABLE_SCHEMA' => $this->dbSchema(),
'DATA_TYPE' => [ 'varbinary', 'binary', 'image', 'bit' ]
] );
}
}
+/**
+ * @deprecated since 1.29
+ */
class_alias( DatabaseMssql::class, 'DatabaseMssql' );