Compare commits

..

No commits in common. "master" and "1.0.0" have entirely different histories.

15 changed files with 224 additions and 435 deletions

View File

@ -19,7 +19,6 @@ before_test:
- echo extension=php_curl.dll >> php.ini
- echo extension=php_gd2.dll >> php.ini
- echo extension=php_tidy.dll >> php.ini
- echo extension=php_fileinfo.dll >> php.ini
- php -r "readfile('http://getcomposer.org/installer');" | php
- php -r "readfile('https://dl.dropboxusercontent.com/u/7129062/sqlsrv_unofficial_3.0.2.2.zip');" > sqlsrv.zip
- unzip sqlsrv.zip
@ -41,4 +40,4 @@ test_script:
environment:
DB: MSSQL
CORE_RELEASE: master
CORE_RELEASE: 3

View File

@ -1,8 +0,0 @@
mappings:
MSSQLAzureDatabase: SilverStripe\MSSQL\MSSQLAzureDatabase
MSSQLDatabase: SilverStripe\MSSQL\MSSQLDatabase
MSSQLDatabaseConfigurationHelper: SilverStripe\MSSQL\MSSQLDatabaseConfigurationHelper
MSSQLQueryBuilder: SilverStripe\MSSQL\MSSQLQueryBuilder
MSSQLSchemaManager: SilverStripe\MSSQL\MSSQLSchemaManager
SQLServerConnector: SilverStripe\MSSQL\SQLServerConnector
SQLServerQuery: SilverStripe\MSSQL\SQLServerQuery

29
LICENSE
View File

@ -1,29 +0,0 @@
BSD 3-Clause License
Copyright (c) 2018, SilverStripe Ltd.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -9,26 +9,18 @@ Allows SilverStripe to use SQL Server databases.
* Sean Harvey (Nickname: halkyon)
<sean (at) silverstripe (dot) com>
* Damian Mooyman (@tractorcow)
## Requirements
* SilverStripe 4+
* SilverStripe 3.0+
* SQL Server 2008, 2008 R2, or 2012.
`mssql` PHP api is no longer supported as of 2.0
### *nix
Linux support is only available via the PDO extension. This requires:
* [dblib](http://www.php.net/manual/en/ref.pdo-dblib.php)
* [FreeTDS](http://freetds.org)
* PHP with mssql extension and [FreeTDS](http://freetds.org)
### Windows
On windows you can either connect via PDO or `sqlsrv`. Both options require the
[SQL Server Driver for PHP](https://msdn.microsoft.com/library/dn865013.aspx?f=255&MSPPError=-2147217396). "sqlsrv" 3.0+
* PHP with [SQL Server Driver for PHP](http://www.microsoft.com/en-us/download/details.aspx?id=20098) "sqlsrv" 3.0+
Note: [SQL Server Express](http://www.microsoft.com/express/Database/) can also be used which is provided free by Microsoft. However, it has limitations such as 10GB maximum database storage.
@ -37,7 +29,7 @@ Note: [SQL Server Express](http://www.microsoft.com/express/Database/) can also
These steps will install the latest SilverStripe stable, along with this module using [Composer](http://getcomposer.org/):
* Install SilverStripe: `composer create-project silverstripe/installer /my/website/folder`
* Install module: `cd /my/website/folder && composer require silverstripe/mssql ^2`
* Install module: `cd /my/website/folder && composer require silverstripe/mssql "*"`
* Open the SilverStripe installer by browsing to install.php, e.g. **http://localhost/silverstripe/install.php**
* Select **SQL Server 2008+** in the database list and enter your SQL Server database details

View File

@ -1,32 +1,25 @@
---
name: mssqlconnectors
---
SilverStripe\Core\Injector\Injector:
Injector:
# Connect using PDO
MSSQLPDODatabase:
class: 'SilverStripe\MSSQL\MSSQLDatabase'
class: 'MSSQLDatabase'
properties:
connector: %$PDOConnector
schemaManager: %$MSSQLSchemaManager
queryBuilder: %$MSSQLQueryBuilder
# Uses sqlsrv_connect
MSSQLDatabase:
class: 'SilverStripe\MSSQL\MSSQLDatabase'
class: 'MSSQLDatabase'
properties:
connector: %$SQLServerConnector
schemaManager: %$MSSQLSchemaManager
queryBuilder: %$MSSQLQueryBuilder
# Uses sqlsrv_connect to connect to a MS Azure Database
MSSQLAzureDatabase:
class: 'SilverStripe\MSSQL\MSSQLAzureDatabase'
class: 'MSSQLAzureDatabase'
properties:
connector: %$SQLServerConnector
schemaManager: %$MSSQLSchemaManager
queryBuilder: %$MSSQLQueryBuilder
SQLServerConnector:
class: 'SilverStripe\MSSQL\SQLServerConnector'
type: prototype
MSSQLSchemaManager:
class: 'SilverStripe\MSSQL\MSSQLSchemaManager'
MSSQLQueryBuilder:
class: 'SilverStripe\MSSQL\MSSQLQueryBuilder'

View File

@ -1,17 +1,11 @@
<?php
use SilverStripe\Dev\Install\DatabaseAdapterRegistry;
use SilverStripe\MSSQL\MSSQLDatabaseConfigurationHelper;
// PDO connector for MS SQL Server
/** @skipUpgrade */
DatabaseAdapterRegistry::register(array(
'class' => 'MSSQLPDODatabase',
'module' => 'mssql',
'title' => 'SQL Server 2008 (using PDO)',
'helperPath' => __DIR__.'/code/MSSQLDatabaseConfigurationHelper.php',
'helperClass' => MSSQLDatabaseConfigurationHelper::class,
'supported' => !!MSSQLDatabaseConfigurationHelper::getPDODriver(),
'helperPath' => dirname(__FILE__).'/code/MSSQLDatabaseConfigurationHelper.php',
'supported' => (class_exists('PDO') && in_array('sqlsrv', PDO::getAvailableDrivers())),
'missingExtensionText' =>
'Either the <a href="http://www.php.net/manual/en/book.pdo.php">PDO Extension</a> or
the <a href="http://www.php.net/manual/en/ref.pdo-sqlsrv.php">SQL Server PDO Driver</a>
@ -19,13 +13,10 @@ DatabaseAdapterRegistry::register(array(
));
// Basic driver using sqlsrv connector
/** @skipUpgrade */
DatabaseAdapterRegistry::register(array(
'class' => 'MSSQLDatabase',
'module' => 'mssql',
'title' => 'SQL Server 2008 (using sqlsrv)',
'helperPath' => __DIR__.'/code/MSSQLDatabaseConfigurationHelper.php',
'helperClass' => MSSQLDatabaseConfigurationHelper::class,
'helperPath' => dirname(__FILE__).'/code/MSSQLDatabaseConfigurationHelper.php',
'supported' => function_exists('sqlsrv_connect'),
'missingExtensionText' =>
'The <a href="http://www.microsoft.com/sqlserver/2005/en/us/PHP-Driver.aspx">sqlsrv</a>
@ -40,13 +31,10 @@ DatabaseAdapterRegistry::register(array(
));
// MS Azure uses an online database
/** @skipUpgrade */
DatabaseAdapterRegistry::register(array(
'class' => 'MSSQLAzureDatabase',
'module' => 'mssql',
'title' => 'MS Azure Database (using sqlsrv)',
'helperPath' => __DIR__.'/code/MSSQLDatabaseConfigurationHelper.php',
'helperClass' => MSSQLDatabaseConfigurationHelper::class,
'helperPath' => dirname(__FILE__).'/code/MSSQLDatabaseConfigurationHelper.php',
'supported' => function_exists('sqlsrv_connect'),
'missingExtensionText' =>
'The <a href="http://www.microsoft.com/sqlserver/2005/en/us/PHP-Driver.aspx">sqlsrv</a>

View File

@ -1,7 +1,5 @@
<?php
namespace SilverStripe\MSSQL;
/**
* Specific support for SQL Azure databases running on Windows Azure.
* Currently only supports the SQLSRV driver from Microsoft.
@ -18,6 +16,7 @@ namespace SilverStripe\MSSQL;
* Fulltext indexes are not supported.
*
* @author Sean Harvey <sean at silverstripe dot com>
* @package mssql
*/
class MSSQLAzureDatabase extends MSSQLDatabase
{
@ -48,7 +47,7 @@ class MSSQLAzureDatabase extends MSSQLDatabase
* - database: The database to connect to
* - windowsauthentication: Not supported for Azure
*/
public function connect($parameters)
protected function connect($parameters)
{
$this->parameters = $parameters;
$this->connectDatabase($parameters['database']);
@ -87,10 +86,9 @@ class MSSQLAzureDatabase extends MSSQLDatabase
* database name.
* @see http://msdn.microsoft.com/en-us/library/windowsazure/ee336288.aspx
*
* @param string $name The database name to switch to
* @param bool $create
* @param bool|int $errorLevel
* @return bool
* @param type $name The database name to switch to
* @param type $create
* @param type $errorLevel
*/
public function selectDatabase($name, $create = false, $errorLevel = E_USER_ERROR)
{

View File

@ -1,18 +1,4 @@
<?php
namespace SilverStripe\MSSQL;
use SilverStripe\Core\Config\Configurable;
use SilverStripe\Core\Injector\Injectable;
use SilverStripe\Core\ClassInfo;
use SilverStripe\ORM\ArrayList;
use SilverStripe\ORM\Connect\Database;
use SilverStripe\ORM\DataList;
use SilverStripe\ORM\DB;
use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\PaginatedList;
use SilverStripe\ORM\Queries\SQLSelect;
/**
* Microsoft SQL Server 2008+ connector class.
*
@ -49,11 +35,11 @@ use SilverStripe\ORM\Queries\SQLSelect;
*
* References:
* @see http://freetds.org
*
* @package mssql
*/
class MSSQLDatabase extends Database
class MSSQLDatabase extends SS_Database
{
use Configurable;
use Injectable;
/**
* Words that will trigger an error if passed to a SQL Server fulltext search
@ -78,11 +64,6 @@ class MSSQLDatabase extends Database
*/
protected $fullTextEnabled = null;
/**
* @var bool
*/
protected $transactionNesting = 0;
/**
* Set the default collation of the MSSQL nvarchar fields that we create.
* We don't apply this to the database as a whole, so that we can use unicode collations.
@ -91,7 +72,7 @@ class MSSQLDatabase extends Database
*/
public static function set_collation($collation)
{
static::config()->set('collation', $collation);
Config::inst()->update('MSSQLDatabase', 'collation', $collation);
}
/**
@ -103,7 +84,7 @@ class MSSQLDatabase extends Database
*/
public static function get_collation()
{
return static::config()->get('collation');
return Config::inst()->get('MSSQLDatabase', 'collation');
}
/**
@ -210,25 +191,20 @@ class MSSQLDatabase extends Database
* Picks up the fulltext-indexed tables from the database and executes search on all of them.
* Results are obtained as ID-ClassName pairs which is later used to reconstruct the DataObjectSet.
*
* @param array $classesToSearch computes all descendants and includes them. Check is done via WHERE clause.
* @param array classesToSearch computes all descendants and includes them. Check is done via WHERE clause.
* @param string $keywords Keywords as a space separated string
* @param int $start
* @param int $pageLength
* @param string $sortBy
* @param string $extraFilter
* @param bool $booleanSearch
* @param string $alternativeFileFilter
* @param bool $invertedMatch
* @return PaginatedList DataObjectSet of result pages
* @return object DataObjectSet of result pages
*/
public function searchEngine($classesToSearch, $keywords, $start, $pageLength, $sortBy = "Relevance DESC", $extraFilter = "", $booleanSearch = false, $alternativeFileFilter = "", $invertedMatch = false)
{
$start = (int)$start;
$pageLength = (int)$pageLength;
if (isset($objects)) {
$results = new ArrayList($objects);
} else {
$results = new ArrayList();
}
if (!$this->fullTextEnabled()) {
return new PaginatedList($results);
return $results;
}
if (!in_array(substr($sortBy, 0, 9), array('"Relevanc', 'Relevance'))) {
user_error("Non-relevance sort not supported.", E_USER_ERROR);
@ -263,33 +239,34 @@ class MSSQLDatabase extends Database
// Create one query per each table, $columns not used. We want just the ID and the ClassName of the object from this query.
foreach ($tables as $tableName => $columns) {
$class = DataObject::getSchema()->tableClass($tableName);
$baseClass = ClassInfo::baseDataClass($tableName);
$join = $this->fullTextSearchMSSQL($tableName, $keywords);
if (!$join) {
return new PaginatedList($results);
return $results;
} // avoid "Null or empty full-text predicate"
// Check if we need to add ShowInSearch
$where = null;
if ($class === 'SilverStripe\\CMS\\Model\\SiteTree') {
if (strpos($tableName, 'SiteTree') === 0) {
$where = array("\"$tableName\".\"ShowInSearch\"!=0");
} elseif ($class === 'SilverStripe\\Assets\\File') {
} elseif (strpos($tableName, 'File') === 0) {
// File.ShowInSearch was added later, keep the database driver backwards compatible
// by checking for its existence first
$fields = $this->getSchemaManager()->fieldList($tableName);
$fields = $this->fieldList($tableName);
if (array_key_exists('ShowInSearch', $fields)) {
$where = array("\"$tableName\".\"ShowInSearch\"!=0");
}
}
$queries[$tableName] = DataList::create($class)->where($where)->dataQuery()->query();
$queries[$tableName] = DataList::create($tableName)->where($where, '')->dataQuery()->query();
$queries[$tableName]->setOrderBy(array());
// Join with CONTAINSTABLE, a full text searcher that includes relevance factor
$queries[$tableName]->setFrom(array("\"$tableName\" INNER JOIN $join AS \"ft\" ON \"$tableName\".\"ID\"=\"ft\".\"KEY\""));
// Join with the base class if needed, as we want to test agains the ClassName
if ($tableName != $tableName) {
$queries[$tableName]->setFrom("INNER JOIN \"$tableName\" ON \"$tableName\".\"ID\"=\"$tableName\".\"ID\"");
if ($tableName != $baseClass) {
$queries[$tableName]->setFrom("INNER JOIN \"$baseClass\" ON \"$baseClass\".\"ID\"=\"$tableName\".\"ID\"");
}
$queries[$tableName]->setSelect(array("\"$tableName\".\"ID\""));
@ -301,7 +278,7 @@ class MSSQLDatabase extends Database
if (count($allClassesToSearch)) {
$classesPlaceholder = DB::placeholders($allClassesToSearch);
$queries[$tableName]->addWhere(array(
"\"$tableName\".\"ClassName\" IN ($classesPlaceholder)" =>
"\"$baseClass\".\"ClassName\" IN ($classesPlaceholder)" =>
$allClassesToSearch
));
}
@ -312,7 +289,6 @@ class MSSQLDatabase extends Database
$querySQLs = array();
$queryParameters = array();
foreach ($queries as $query) {
/** @var SQLSelect $query */
$querySQLs[] = $query->sql($parameters);
$queryParameters = array_merge($queryParameters, $parameters);
}
@ -351,8 +327,8 @@ class MSSQLDatabase extends Database
* Allow auto-increment primary key editing on the given table.
* Some databases need to enable this specially.
*
* @param string $table The name of the table to have PK editing allowed on
* @param bool $allow True to start, false to finish
* @param $table The name of the table to have PK editing allowed on
* @param $allow True to start, false to finish
*/
public function allowPrimaryKeyEditing($table, $allow = true)
{
@ -362,10 +338,11 @@ class MSSQLDatabase extends Database
/**
* Returns a SQL fragment for querying a fulltext search index
*
* @param string $tableName specific - table name
* @param string $keywords The search query
* @param array $fields The list of field names to search on, or null to include all
* @return string Clause, or null if keyword set is empty or the string with JOIN clause to be added to SQL query
* @param $tableName specific - table name
* @param $keywords string The search query
* @param $fields array The list of field names to search on, or null to include all
*
* @returns null if keyword set is empty or the string with JOIN clause to be added to SQL query
*/
public function fullTextSearchMSSQL($tableName, $keywords, $fields = null)
{
@ -452,20 +429,14 @@ class MSSQLDatabase extends Database
/**
* Start transaction. READ ONLY not supported.
*
* @param bool $transactionMode
* @param bool $sessionCharacteristics
*/
public function transactionStart($transactionMode = false, $sessionCharacteristics = false)
{
if ($this->transactionNesting > 0) {
$this->transactionSavepoint('NESTEDTRANSACTION' . $this->transactionNesting);
} elseif ($this->connector instanceof SQLServerConnector) {
if ($this->connector instanceof SQLServerConnector) {
$this->connector->transactionStart();
} else {
$this->query('BEGIN TRANSACTION');
}
++$this->transactionNesting;
}
public function transactionSavepoint($savepoint)
@ -475,73 +446,23 @@ class MSSQLDatabase extends Database
public function transactionRollback($savepoint = false)
{
// Named transaction
if ($savepoint) {
$this->query("ROLLBACK TRANSACTION \"$savepoint\"");
return true;
}
// Fail if transaction isn't available
if (!$this->transactionNesting) {
return false;
}
--$this->transactionNesting;
if ($this->transactionNesting > 0) {
$this->transactionRollback('NESTEDTRANSACTION' . $this->transactionNesting);
} elseif ($this->connector instanceof SQLServerConnector) {
$this->connector->transactionRollback();
} else {
$this->query('ROLLBACK TRANSACTION');
}
return true;
}
public function transactionEnd($chain = false)
{
// Fail if transaction isn't available
if (!$this->transactionNesting) {
return false;
}
--$this->transactionNesting;
if ($this->transactionNesting <= 0) {
$this->transactionNesting = 0;
if ($this->connector instanceof SQLServerConnector) {
$this->connector->transactionEnd();
} else {
$this->query('COMMIT TRANSACTION');
}
}
return true;
}
/**
* In error condition, set transactionNesting to zero
*/
protected function resetTransactionNesting()
{
$this->transactionNesting = 0;
}
public function query($sql, $errorLevel = E_USER_ERROR)
{
$this->inspectQuery($sql);
return parent::query($sql, $errorLevel);
}
public function preparedQuery($sql, $parameters, $errorLevel = E_USER_ERROR)
{
$this->inspectQuery($sql);
return parent::preparedQuery($sql, $parameters, $errorLevel);
}
protected function inspectQuery($sql)
{
// Any DDL discards transactions.
$isDDL = $this->getConnector()->isQueryDDL($sql);
if ($isDDL) {
$this->resetTransactionNesting();
}
}
public function comparisonClause($field, $value, $exact = false, $negate = false, $caseSensitive = null, $parameterised = false)
{

View File

@ -1,31 +1,24 @@
<?php
namespace SilverStripe\MSSQL;
use SilverStripe\Dev\Install\DatabaseAdapterRegistry;
use SilverStripe\Dev\Install\DatabaseConfigurationHelper;
use PDO;
use Exception;
/**
* This is a helper class for the SS installer.
*
* It does all the specific checking for MSSQLDatabase
* to ensure that the configuration is setup correctly.
*
* @package mssql
*/
class MSSQLDatabaseConfigurationHelper implements DatabaseConfigurationHelper
{
protected function isAzure($databaseConfig)
{
/** @skipUpgrade */
return $databaseConfig['type'] === 'MSSQLAzureDatabase';
}
/**
* Create a connection of the appropriate type
*
* @skipUpgrade
* @param array $databaseConfig
* @param string $error Error message passed by value
* @return mixed|null Either the connection object, or null if error
@ -63,14 +56,8 @@ class MSSQLDatabaseConfigurationHelper implements DatabaseConfigurationHelper
}
return null;
case 'MSSQLPDODatabase':
$driver = $this->getPDODriver();
if (!$driver) {
$error = 'No supported PDO driver';
return null;
}
// May throw a PDOException if fails
$conn = @new PDO($driver.':Server='.$databaseConfig['server'], $databaseConfig['username'], $databaseConfig['password']);
$conn = @new PDO('sqlsrv:Server='.$databaseConfig['server'], $databaseConfig['username'], $databaseConfig['password']);
if ($conn) {
return $conn;
} else {
@ -78,7 +65,7 @@ class MSSQLDatabaseConfigurationHelper implements DatabaseConfigurationHelper
return null;
}
default:
$error = 'Invalid connection type: ' . $databaseConfig['type'];
$error = 'Invalid connection type';
return null;
}
} catch (Exception $ex) {
@ -87,29 +74,12 @@ class MSSQLDatabaseConfigurationHelper implements DatabaseConfigurationHelper
}
}
/**
* Get supported PDO driver
*
* @return null
*/
public static function getPDODriver() {
if (!class_exists('PDO')) {
return null;
}
foreach(PDO::getAvailableDrivers() as $driver) {
if(in_array($driver, array('sqlsrv', 'dblib'))) {
return $driver;
}
}
return null;
}
/**
* Helper function to quote a string value
*
* @param mixed $conn Connection object/resource
* @param string $value Value to quote
* @return string Quoted string
* @return string Quoted strieng
*/
protected function quote($conn, $value)
{
@ -122,7 +92,6 @@ class MSSQLDatabaseConfigurationHelper implements DatabaseConfigurationHelper
} else {
user_error('Invalid database connection', E_USER_ERROR);
}
return null;
}
/**
@ -220,7 +189,6 @@ class MSSQLDatabaseConfigurationHelper implements DatabaseConfigurationHelper
public function requireDatabaseOrCreatePermissions($databaseConfig)
{
$conn = $this->createConnection($databaseConfig, $error);
/** @skipUpgrade */
if (empty($conn)) {
$success = false;
$alreadyExists = false;

View File

@ -1,13 +1,9 @@
<?php
namespace SilverStripe\MSSQL;
use InvalidArgumentException;
use SilverStripe\ORM\Queries\SQLSelect;
use SilverStripe\ORM\Connect\DBQueryBuilder;
/**
* Builds a SQL query string from a SQLExpression object
*
* @package mssql
*/
class MSSQLQueryBuilder extends DBQueryBuilder
{

View File

@ -1,11 +1,9 @@
<?php
namespace SilverStripe\MSSQL;
use SilverStripe\ORM\Connect\DBSchemaManager;
/**
* Represents and handles all schema management for a MS SQL database
*
* @package mssql
*/
class MSSQLSchemaManager extends DBSchemaManager
{
@ -184,14 +182,13 @@ class MSSQLSchemaManager extends DBSchemaManager
/**
* Create a new table.
* @param string $tableName The name of the table
* @param array $fields A map of field names to field types
* @param array $indexes A map of indexes
* @param array $options An map of additional options. The available keys are as follows:
* @param $tableName The name of the table
* @param $fields A map of field names to field types
* @param $indexes A map of indexes
* @param $options An map of additional options. The available keys are as follows:
* - 'MSSQLDatabase'/'MySQLDatabase'/'PostgreSQLDatabase' - database-specific options such as "engine" for MySQL.
* - 'temporary' - If true, then a temporary table will be created
* @param array $advancedOptions
* @return string The table name generated. This may be different from the table name, for example with temporary tables.
* @return The table name generated. This may be different from the table name, for example with temporary tables.
*/
public function createTable($tableName, $fields = null, $indexes = null, $options = null, $advancedOptions = null)
{
@ -230,20 +227,18 @@ class MSSQLSchemaManager extends DBSchemaManager
/**
* Alter a table's schema.
* @param string $tableName The name of the table to alter
* @param array $newFields New fields, a map of field name => field schema
* @param array $newIndexes New indexes, a map of index name => index type
* @param array $alteredFields Updated fields, a map of field name => field schema
* @param array $alteredIndexes Updated indexes, a map of index name => index type
* @param array $alteredOptions
* @param array $advancedOptions
* @param $table The name of the table to alter
* @param $newFields New fields, a map of field name => field schema
* @param $newIndexes New indexes, a map of index name => index type
* @param $alteredFields Updated fields, a map of field name => field schema
* @param $alteredIndexes Updated indexes, a map of index name => index type
*/
public function alterTable($tableName, $newFields = null, $newIndexes = null, $alteredFields = null, $alteredIndexes = null, $alteredOptions=null, $advancedOptions=null)
{
$alterList = array();
// drop any fulltext indexes that exist on the table before altering the structure
if ($this->fulltextIndexExists($tableName)) {
if ($this->fullTextIndexExists($tableName)) {
$alterList[] = "\nDROP FULLTEXT INDEX ON \"$tableName\";";
}
@ -400,10 +395,8 @@ class MSSQLSchemaManager extends DBSchemaManager
// drop *ALL* indexes on a table before proceeding
// this won't drop primary keys, though
$indexes = $this->indexNames($tableName);
$indexes = array_filter($indexes);
foreach ($indexes as $indexName) {
$alterQueries[] = "IF EXISTS (SELECT name FROM sys.indexes WHERE name = '$indexName' AND object_id = object_id(SCHEMA_NAME() + '.$tableName')) DROP INDEX \"$indexName\" ON \"$tableName\";";
$alterQueries[] = "DROP INDEX \"$indexName\" ON \"$tableName\";";
}
$prefix = "ALTER TABLE \"$tableName\" ";
@ -609,13 +602,10 @@ class MSSQLSchemaManager extends DBSchemaManager
// Consolidate/Cleanup spec into array format
$indexSpec = $this->parseIndexSpec($indexName, $indexSpec);
$drop = "IF EXISTS (SELECT name FROM sys.indexes WHERE name = '$index' AND object_id = object_id(SCHEMA_NAME() + '.$tableName')) DROP INDEX $index ON \"$tableName\";";
$drop = "IF EXISTS (SELECT name FROM sys.indexes WHERE name = '$index') DROP INDEX $index ON \"$tableName\";";
// create a type-specific index
if ($indexSpec['type'] == 'fulltext') {
if(!$this->database->fullTextEnabled()) {
return '';
}
if ($indexSpec['type'] == 'fulltext' && $this->database->fullTextEnabled()) {
// enable fulltext on this table
$this->createFullTextCatalog();
$primary_key = $this->getPrimaryKey($tableName);
@ -697,7 +687,6 @@ class MSSQLSchemaManager extends DBSchemaManager
* For a given table name, get all the internal index names,
* except for those that are primary keys and fulltext indexes.
*
* @param string $tableName
* @return array
*/
public function indexNames($tableName)
@ -705,7 +694,7 @@ class MSSQLSchemaManager extends DBSchemaManager
return $this->preparedQuery('
SELECT ind.name FROM sys.indexes ind
INNER JOIN sys.tables t ON ind.object_id = t.object_id
WHERE is_primary_key = 0 AND t.name = ? AND ind.name IS NOT NULL',
WHERE is_primary_key = 0 AND t.name = ?',
array($tableName)
)->column();
}
@ -723,7 +712,7 @@ class MSSQLSchemaManager extends DBSchemaManager
* Return a boolean type-formatted string
* We use 'bit' so that we can do numeric-based comparisons
*
* @param array $values Contains a tokenised list of info about this data type
* @params array $values Contains a tokenised list of info about this data type
* @return string
*/
public function boolean($values)
@ -735,7 +724,7 @@ class MSSQLSchemaManager extends DBSchemaManager
/**
* Return a date type-formatted string.
*
* @param array $values Contains a tokenised list of info about this data type
* @params array $values Contains a tokenised list of info about this data type
* @return string
*/
public function date($values)
@ -746,7 +735,7 @@ class MSSQLSchemaManager extends DBSchemaManager
/**
* Return a decimal type-formatted string
*
* @param array $values Contains a tokenised list of info about this data type
* @params array $values Contains a tokenised list of info about this data type
* @return string
*/
public function decimal($values)
@ -769,7 +758,7 @@ class MSSQLSchemaManager extends DBSchemaManager
/**
* Return a enum type-formatted string
*
* @param array $values Contains a tokenised list of info about this data type
* @params array $values Contains a tokenised list of info about this data type
* @return string
*/
public function enum($values)
@ -787,9 +776,6 @@ class MSSQLSchemaManager extends DBSchemaManager
/**
* @todo Make this work like {@link MySQLDatabase::set()}
*
* @param array $values
* @return string
*/
public function set($values)
{
@ -799,7 +785,7 @@ class MSSQLSchemaManager extends DBSchemaManager
/**
* Return a float type-formatted string.
*
* @param array $values Contains a tokenised list of info about this data type
* @params array $values Contains a tokenised list of info about this data type
* @return string
*/
public function float($values)
@ -810,7 +796,7 @@ class MSSQLSchemaManager extends DBSchemaManager
/**
* Return a int type-formatted string
*
* @param array $values Contains a tokenised list of info about this data type
* @params array $values Contains a tokenised list of info about this data type
* @return string
*/
public function int($values)
@ -821,7 +807,7 @@ class MSSQLSchemaManager extends DBSchemaManager
/**
* Return a bigint type-formatted string
*
* @param array $values Contains a tokenised list of info about this data type
* @params array $values Contains a tokenised list of info about this data type
* @return string
*/
public function bigint($values)
@ -833,10 +819,10 @@ class MSSQLSchemaManager extends DBSchemaManager
* Return a datetime type-formatted string
* For MS SQL, we simply return the word 'timestamp', no other parameters are necessary
*
* @param array $values Contains a tokenised list of info about this data type
* @params array $values Contains a tokenised list of info about this data type
* @return string
*/
public function datetime($values)
public function ss_datetime($values)
{
return 'datetime null';
}
@ -844,7 +830,7 @@ class MSSQLSchemaManager extends DBSchemaManager
/**
* Return a text type-formatted string
*
* @param array $values Contains a tokenised list of info about this data type
* @params array $values Contains a tokenised list of info about this data type
* @return string
*/
public function text($values)
@ -857,7 +843,7 @@ class MSSQLSchemaManager extends DBSchemaManager
/**
* Return a time type-formatted string.
*
* @param array $values Contains a tokenised list of info about this data type
* @params array $values Contains a tokenised list of info about this data type
* @return string
*/
public function time($values)
@ -868,7 +854,7 @@ class MSSQLSchemaManager extends DBSchemaManager
/**
* Return a varchar type-formatted string
*
* @param array $values Contains a tokenised list of info about this data type
* @params array $values Contains a tokenised list of info about this data type
* @return string
*/
public function varchar($values)
@ -880,8 +866,6 @@ class MSSQLSchemaManager extends DBSchemaManager
/**
* Return a 4 digit numeric type.
*
* @param array $values
* @return string
*/
public function year($values)
@ -891,9 +875,6 @@ class MSSQLSchemaManager extends DBSchemaManager
/**
* This returns the column which is the primary key for each table
*
* @param bool $asDbValue
* @param bool $hasAutoIncPK
* @return string
*/
public function IdColumn($asDbValue = false, $hasAutoIncPK = true)
@ -918,10 +899,6 @@ class MSSQLSchemaManager extends DBSchemaManager
/**
* Returns the values of the given enum field
* NOTE: Experimental; introduced for db-abstraction and may changed before 2.4 is released.
*
* @param string $tableName
* @param string $fieldName
* @return array
*/
public function enumValuesForField($tableName, $fieldName)
{
@ -941,9 +918,6 @@ class MSSQLSchemaManager extends DBSchemaManager
*
* For instance, MSSQL uses 'BIGINT', while MySQL uses 'UNSIGNED'
* and PostgreSQL uses 'INT'.
*
* @param string $type
* @return string
*/
public function dbDataType($type)
{

View File

@ -1,11 +1,9 @@
<?php
namespace SilverStripe\MSSQL;
use SilverStripe\ORM\Connect\DBConnector;
/**
* Database connector driver for sqlsrv_ library
*
* @package mssql
*/
class SQLServerConnector extends DBConnector
{
@ -197,7 +195,7 @@ class SQLServerConnector extends DBConnector
* Quotes a string, including the "N" prefix so unicode
* strings are saved to the database correctly.
*
* @param string $value String to be encoded
* @param string $string String to be encoded
* @return string Processed string ready for DB
*/
public function quoteString($value)

View File

@ -1,14 +1,11 @@
<?php
namespace SilverStripe\MSSQL;
use DateTime;
use SilverStripe\ORM\Connect\Query;
/**
* A result-set from a MSSQL database.
*
* @package mssql
*/
class SQLServerQuery extends Query
class SQLServerQuery extends SS_Query
{
/**
@ -43,21 +40,13 @@ class SQLServerQuery extends Query
}
}
public function getIterator()
public function seek($row)
{
if (is_resource($this->handle)) {
while ($data = sqlsrv_fetch_array($this->handle, SQLSRV_FETCH_ASSOC)) {
// special case for sqlsrv - date values are DateTime coming out of the sqlsrv drivers,
// so we convert to the usual Y-m-d H:i:s value!
foreach ($data as $name => $value) {
if ($value instanceof DateTime) {
$data[$name] = $value->format('Y-m-d H:i:s');
}
if (!is_resource($this->handle)) {
return false;
}
yield $data;
}
}
user_error('MSSQLQuery::seek() not supported in sqlsrv', E_USER_WARNING);
}
public function numRecords()
@ -73,4 +62,28 @@ class SQLServerQuery extends Query
user_error('MSSQLQuery::numRecords() not supported in this version of sqlsrv', E_USER_WARNING);
}
}
public function nextRecord()
{
if (!is_resource($this->handle)) {
return false;
}
if ($data = sqlsrv_fetch_array($this->handle, SQLSRV_FETCH_ASSOC)) {
// special case for sqlsrv - date values are DateTime coming out of the sqlsrv drivers,
// so we convert to the usual Y-m-d H:i:s value!
foreach ($data as $name => $value) {
if ($value instanceof DateTime) {
$data[$name] = $value->format('Y-m-d H:i:s');
}
}
return $data;
} else {
// Free the handle if there are no more results - sqlsrv crashes if there are too many handles
sqlsrv_free_stmt($this->handle);
$this->handle = null;
}
return false;
}
}

View File

@ -1,7 +1,7 @@
{
"name": "silverstripe/mssql",
"description": "Adds MSSQL support to SilverStripe",
"type": "silverstripe-vendormodule",
"type": "silverstripe-module",
"keywords": ["silverstripe", "mssql", "database"],
"authors": [
{
@ -14,20 +14,11 @@
}
],
"require": {
"silverstripe/framework": "^4"
},
"suggest": {
"ext-sqlsrv": "Required to support MSSQLDatabase as the server type",
"ext-pdo_sqlsrv": "Required to support MSSQLPDODatabase as the server type"
"silverstripe/framework": "^3.2"
},
"extra": {
"branch-alias": {
"dev-master": "3.x-dev"
}
},
"autoload": {
"psr-4": {
"SilverStripe\\MSSQL\\": "code/"
"dev-master": "1.0.x-dev"
}
},
"prefer-stable": true,

View File

@ -1,9 +1,4 @@
<?php
use SilverStripe\ORM\DataObject;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\Dev\TestOnly;
class MSSQLDatabaseQueryTest extends SapphireTest
{
@ -28,8 +23,8 @@ class MSSQLDatabaseQueryTest extends SapphireTest
class MSSQLDatabaseQueryTestDataObject extends DataObject implements TestOnly
{
private static $db = array(
public static $db = array(
'TestDate' => 'Date',
'TestDatetime' => 'Datetime'
'TestDatetime' => 'SS_Datetime'
);
}