2013-04-03 06:19:26 +02:00
|
|
|
<?php
|
|
|
|
|
2016-07-15 03:57:54 +02:00
|
|
|
namespace SilverStripe\MSSQL;
|
|
|
|
|
|
|
|
use SilverStripe\ORM\Connect\DBConnector;
|
|
|
|
|
2013-04-03 06:19:26 +02:00
|
|
|
/**
|
|
|
|
* Database connector driver for sqlsrv_ library
|
|
|
|
*/
|
2015-12-17 19:50:59 +01:00
|
|
|
class SQLServerConnector extends DBConnector
|
|
|
|
{
|
2016-07-15 03:57:54 +02:00
|
|
|
|
2015-12-17 19:50:59 +01:00
|
|
|
/**
|
|
|
|
* Connection to the DBMS.
|
2016-07-15 03:57:54 +02:00
|
|
|
*
|
2015-12-17 19:50:59 +01:00
|
|
|
* @var resource
|
|
|
|
*/
|
|
|
|
protected $dbConn = null;
|
2013-04-03 06:19:26 +02:00
|
|
|
|
2015-12-17 19:50:59 +01:00
|
|
|
/**
|
|
|
|
* Stores the affected rows of the last query.
|
|
|
|
* Used by sqlsrv functions only, as sqlsrv_rows_affected
|
|
|
|
* accepts a result instead of a database handle.
|
2016-07-15 03:57:54 +02:00
|
|
|
*
|
2015-12-17 19:50:59 +01:00
|
|
|
* @var integer
|
|
|
|
*/
|
|
|
|
protected $lastAffectedRows;
|
2016-07-15 03:57:54 +02:00
|
|
|
|
2015-12-17 19:50:59 +01:00
|
|
|
/**
|
|
|
|
* Name of the currently selected database
|
|
|
|
*
|
|
|
|
* @var string
|
|
|
|
*/
|
|
|
|
protected $selectedDatabase = null;
|
2013-04-03 06:19:26 +02:00
|
|
|
|
2015-12-17 19:50:59 +01:00
|
|
|
public function connect($parameters, $selectDB = false)
|
|
|
|
{
|
|
|
|
// Disable default warnings as errors behaviour for sqlsrv to keep it in line with mssql functions
|
|
|
|
if (ini_get('sqlsrv.WarningsReturnAsErrors')) {
|
|
|
|
ini_set('sqlsrv.WarningsReturnAsErrors', 'Off');
|
|
|
|
}
|
2013-04-03 06:19:26 +02:00
|
|
|
|
2015-12-17 19:50:59 +01:00
|
|
|
$charset = isset($parameters['charset']) ? $parameters : 'UTF-8';
|
|
|
|
$multiResultSets = isset($parameters['multipleactiveresultsets'])
|
|
|
|
? $parameters['multipleactiveresultsets']
|
|
|
|
: true;
|
|
|
|
$options = array(
|
|
|
|
'CharacterSet' => $charset,
|
|
|
|
'MultipleActiveResultSets' => $multiResultSets
|
|
|
|
);
|
2016-07-15 03:57:54 +02:00
|
|
|
|
2015-12-17 19:50:59 +01:00
|
|
|
if (!(defined('MSSQL_USE_WINDOWS_AUTHENTICATION') && MSSQL_USE_WINDOWS_AUTHENTICATION == true)
|
|
|
|
&& empty($parameters['windowsauthentication'])
|
|
|
|
) {
|
|
|
|
$options['UID'] = $parameters['username'];
|
|
|
|
$options['PWD'] = $parameters['password'];
|
|
|
|
}
|
2016-07-15 03:57:54 +02:00
|
|
|
|
2015-12-17 19:50:59 +01:00
|
|
|
// Required by MS Azure database
|
|
|
|
if ($selectDB && !empty($parameters['database'])) {
|
|
|
|
$options['Database'] = $parameters['database'];
|
|
|
|
}
|
2013-04-03 06:19:26 +02:00
|
|
|
|
2015-12-17 19:50:59 +01:00
|
|
|
$this->dbConn = sqlsrv_connect($parameters['server'], $options);
|
2016-07-15 03:57:54 +02:00
|
|
|
|
2015-12-17 19:50:59 +01:00
|
|
|
if (empty($this->dbConn)) {
|
|
|
|
$this->databaseError("Couldn't connect to SQL Server database");
|
|
|
|
} elseif ($selectDB && !empty($parameters['database'])) {
|
|
|
|
// Check selected database (Azure)
|
|
|
|
$this->selectedDatabase = $parameters['database'];
|
|
|
|
}
|
|
|
|
}
|
2016-07-15 03:57:54 +02:00
|
|
|
|
2015-12-17 19:50:59 +01:00
|
|
|
/**
|
|
|
|
* Start transaction. READ ONLY not supported.
|
|
|
|
*/
|
|
|
|
public function transactionStart()
|
|
|
|
{
|
|
|
|
$result = sqlsrv_begin_transaction($this->dbConn);
|
|
|
|
if (!$result) {
|
|
|
|
$this->databaseError("Couldn't start the transaction.");
|
|
|
|
}
|
|
|
|
}
|
2016-07-15 03:57:54 +02:00
|
|
|
|
2015-12-17 19:50:59 +01:00
|
|
|
/**
|
|
|
|
* Commit everything inside this transaction so far
|
|
|
|
*/
|
|
|
|
public function transactionEnd()
|
|
|
|
{
|
|
|
|
$result = sqlsrv_commit($this->dbConn);
|
|
|
|
if (!$result) {
|
|
|
|
$this->databaseError("Couldn't commit the transaction.");
|
|
|
|
}
|
|
|
|
}
|
2016-07-15 03:57:54 +02:00
|
|
|
|
2015-12-17 19:50:59 +01:00
|
|
|
/**
|
|
|
|
* Rollback or revert to a savepoint if your queries encounter problems
|
|
|
|
* If you encounter a problem at any point during a transaction, you may
|
|
|
|
* need to rollback that particular query, or return to a savepoint
|
|
|
|
*/
|
|
|
|
public function transactionRollback()
|
|
|
|
{
|
|
|
|
$result = sqlsrv_rollback($this->dbConn);
|
|
|
|
if (!$result) {
|
|
|
|
$this->databaseError("Couldn't rollback the transaction.");
|
|
|
|
}
|
|
|
|
}
|
2013-04-03 06:19:26 +02:00
|
|
|
|
2015-12-17 19:50:59 +01:00
|
|
|
public function affectedRows()
|
|
|
|
{
|
|
|
|
return $this->lastAffectedRows;
|
|
|
|
}
|
2016-07-15 03:57:54 +02:00
|
|
|
|
2015-12-17 19:50:59 +01:00
|
|
|
public function getLastError()
|
|
|
|
{
|
|
|
|
$errorMessages = array();
|
|
|
|
$errors = sqlsrv_errors();
|
|
|
|
if ($errors) {
|
|
|
|
foreach ($errors as $info) {
|
|
|
|
$errorMessages[] = implode(', ', array($info['SQLSTATE'], $info['code'], $info['message']));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return implode('; ', $errorMessages);
|
|
|
|
}
|
2013-04-03 06:19:26 +02:00
|
|
|
|
2015-12-17 19:50:59 +01:00
|
|
|
public function isActive()
|
|
|
|
{
|
|
|
|
return $this->dbConn && $this->selectedDatabase;
|
|
|
|
}
|
2013-04-03 06:19:26 +02:00
|
|
|
|
2015-12-17 19:50:59 +01:00
|
|
|
public function preparedQuery($sql, $parameters, $errorLevel = E_USER_ERROR)
|
|
|
|
{
|
|
|
|
// Reset state
|
|
|
|
$this->lastAffectedRows = 0;
|
2016-07-15 03:57:54 +02:00
|
|
|
|
2015-12-17 19:50:59 +01:00
|
|
|
// Run query
|
|
|
|
$parsedParameters = $this->parameterValues($parameters);
|
|
|
|
if (empty($parsedParameters)) {
|
|
|
|
$handle = sqlsrv_query($this->dbConn, $sql);
|
|
|
|
} else {
|
|
|
|
$handle = sqlsrv_query($this->dbConn, $sql, $parsedParameters);
|
|
|
|
}
|
2016-07-15 03:57:54 +02:00
|
|
|
|
2015-12-17 19:50:59 +01:00
|
|
|
// Check for error
|
|
|
|
if (!$handle) {
|
|
|
|
$this->databaseError($this->getLastError(), $errorLevel, $sql, $parsedParameters);
|
|
|
|
return null;
|
|
|
|
}
|
2016-07-15 03:57:54 +02:00
|
|
|
|
2015-12-17 19:50:59 +01:00
|
|
|
// Report result
|
|
|
|
$this->lastAffectedRows = sqlsrv_rows_affected($handle);
|
|
|
|
return new SQLServerQuery($this, $handle);
|
|
|
|
}
|
2013-04-03 06:19:26 +02:00
|
|
|
|
2015-12-17 19:50:59 +01:00
|
|
|
public function query($sql, $errorLevel = E_USER_ERROR)
|
|
|
|
{
|
|
|
|
return $this->preparedQuery($sql, array(), $errorLevel);
|
|
|
|
}
|
2013-04-03 06:19:26 +02:00
|
|
|
|
2015-12-17 19:50:59 +01:00
|
|
|
public function selectDatabase($name)
|
|
|
|
{
|
|
|
|
$this->query("USE \"$name\"");
|
|
|
|
$this->selectedDatabase = $name;
|
|
|
|
return true;
|
|
|
|
}
|
2013-04-03 06:19:26 +02:00
|
|
|
|
2015-12-17 19:50:59 +01:00
|
|
|
public function __destruct()
|
|
|
|
{
|
|
|
|
if (is_resource($this->dbConn)) {
|
|
|
|
sqlsrv_close($this->dbConn);
|
|
|
|
}
|
|
|
|
}
|
2013-04-03 06:19:26 +02:00
|
|
|
|
2015-12-17 19:50:59 +01:00
|
|
|
public function getVersion()
|
|
|
|
{
|
|
|
|
// @todo - use sqlsrv_server_info?
|
|
|
|
return trim($this->query("SELECT CONVERT(char(15), SERVERPROPERTY('ProductVersion'))")->value());
|
|
|
|
}
|
2013-04-03 06:19:26 +02:00
|
|
|
|
2015-12-17 19:50:59 +01:00
|
|
|
public function getGeneratedID($table)
|
|
|
|
{
|
|
|
|
return $this->query("SELECT IDENT_CURRENT('$table')")->value();
|
|
|
|
}
|
2013-04-03 06:19:26 +02:00
|
|
|
|
2015-12-17 19:50:59 +01:00
|
|
|
public function getSelectedDatabase()
|
|
|
|
{
|
|
|
|
return $this->selectedDatabase;
|
|
|
|
}
|
2013-04-03 06:19:26 +02:00
|
|
|
|
2015-12-17 19:50:59 +01:00
|
|
|
public function unloadDatabase()
|
|
|
|
{
|
|
|
|
$this->selectDatabase('Master');
|
|
|
|
$this->selectedDatabase = null;
|
|
|
|
}
|
2016-07-15 03:57:54 +02:00
|
|
|
|
2015-12-17 19:50:59 +01:00
|
|
|
/**
|
|
|
|
* Quotes a string, including the "N" prefix so unicode
|
|
|
|
* strings are saved to the database correctly.
|
|
|
|
*
|
2016-07-15 03:57:54 +02:00
|
|
|
* @param string $value String to be encoded
|
2015-12-17 19:50:59 +01:00
|
|
|
* @return string Processed string ready for DB
|
|
|
|
*/
|
|
|
|
public function quoteString($value)
|
|
|
|
{
|
|
|
|
return "N'" . $this->escapeString($value) . "'";
|
|
|
|
}
|
2016-07-15 03:57:54 +02:00
|
|
|
|
2015-12-17 19:50:59 +01:00
|
|
|
public function escapeString($value)
|
|
|
|
{
|
|
|
|
$value = str_replace("'", "''", $value);
|
|
|
|
$value = str_replace("\0", "[NULL]", $value);
|
|
|
|
return $value;
|
|
|
|
}
|
2013-04-03 06:19:26 +02:00
|
|
|
}
|