Commit 84ca5ac4 authored by Benjamin Eberlei's avatar Benjamin Eberlei

Merge branch 'sqlsrv'

parents 173d7ec1 8b29ffe5
<?php
/*
* $Id$
*
* 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
......@@ -33,6 +31,7 @@ namespace Doctrine\DBAL\Schema;
*/
class MsSqlSchemaManager extends AbstractSchemaManager
{
/**
* @override
*/
......@@ -40,130 +39,60 @@ class MsSqlSchemaManager extends AbstractSchemaManager
{
$dbType = strtolower($tableColumn['TYPE_NAME']);
$autoincrement = false;
$autoincrement = false;
if (stripos($dbType, 'identity')) {
$dbType = trim(str_ireplace('identity', '', $dbType));
$autoincrement = true;
$autoincrement = true;
}
$type = array();
$unsigned = $fixed = null;
if ( ! isset($tableColumn['name'])) {
if (!isset($tableColumn['name'])) {
$tableColumn['name'] = '';
}
// Map db type to Doctrine mapping type
switch ($dbType) {
case 'tinyint':
$type = 'boolean';
break;
case 'smallint':
$type = 'smallint';
break;
case 'mediumint':
$type = 'integer';
break;
case 'int':
case 'integer':
$type = 'integer';
break;
case 'bigint':
$type = 'bigint';
break;
case 'tinytext':
case 'mediumtext':
case 'longtext':
case 'text':
$type = 'text';
$fixed = false;
break;
case 'varchar':
$fixed = false;
case 'string':
$default = $tableColumn['COLUMN_DEF'];
while ($default != ($default2 = preg_replace("/^\((.*)\)$/", '$1', $default))) {
$default = $default2;
}
$length = (int) $tableColumn['LENGTH'];
$type = $this->_platform->getDoctrineTypeMapping($dbType);
switch ($type) {
case 'char':
$type = 'string';
if ($tableColumn['LENGTH'] == '1') {
$type = 'boolean';
if (preg_match('/^(is|has)/', $tableColumn['name'])) {
$type = array_reverse($type);
}
} else if (strstr($dbType, 'text')) {
$type = 'text';
if ($decimal == 'binary') {
$type = 'blob';
}
}
if ($fixed !== false) {
$fixed = true;
}
$fixed = true;
break;
case 'set':
case 'text':
$fixed = false;
$type = 'text';
$type = 'integer'; //FIXME:???
break;
case 'date':
$type = 'date';
break;
case 'datetime':
case 'datetime2':
case 'timestamp':
case 'smalldatettime':
$type = 'datetime';
break;
case 'time':
$type = 'time';
break;
case 'float':
case 'double':
case 'real':
case 'numeric':
case 'decimal':
$type = 'decimal';
break;
case 'tinyblob':
case 'mediumblob':
case 'longblob':
case 'blob':
case 'binary':
case 'varbinary':
$type = 'blob';
break;
case 'year':
$type = 'integer';
$type = 'date';
break;
case 'geometry':
case 'geometrycollection':
case 'point':
case 'multipoint':
case 'linestring':
case 'multilinestring':
case 'polygon':
case 'multipolygon':
$type = 'blob';
break;
default:
$type = 'string';
}
$default = $tableColumn['COLUMN_DEF'];
while($default != ($default2 = preg_replace("/^\((.*)\)$/", '$1', $default))) {
$default = $default2;
switch ($dbType) {
case 'nchar':
case 'nvarchar':
case 'ntext':
// Unicode data requires 2 bytes per character
$length = $length / 2;
break;
}
$options = array(
'length' => ((int) $tableColumn['LENGTH'] == 0 || !in_array($type, array('text', 'string'))) ? null : (int) $tableColumn['LENGTH'],
'unsigned' => (bool)$unsigned,
'fixed' => (bool)$fixed,
'default' => $default !== 'NULL' ? $default : null,
'notnull' => (bool) ($tableColumn['IS_NULLABLE'] != 'YES'),
'scale' => $tableColumn['SCALE'],
'precision' => $tableColumn['PRECISION'],
'unique' => false, // @todo
'autoincrement' => $autoincrement,
'length' => ($length == 0 || !in_array($type, array('text', 'string'))) ? null : $length,
'unsigned' => (bool) $unsigned,
'fixed' => (bool) $fixed,
'default' => $default !== 'NULL' ? $default : null,
'notnull' => (bool) ($tableColumn['IS_NULLABLE'] != 'YES'),
'scale' => $tableColumn['SCALE'],
'precision' => $tableColumn['PRECISION'],
'autoincrement' => $autoincrement,
);
return new Column($tableColumn['COLUMN_NAME'], \Doctrine\DBAL\Types\Type::getType($type), $options);
......@@ -175,9 +104,9 @@ class MsSqlSchemaManager extends AbstractSchemaManager
protected function _getPortableTableIndexesList($tableIndexRows, $tableName=null)
{
$result = array();
foreach($tableIndexRows AS $tableIndex) {
foreach ($tableIndexRows AS $tableIndex) {
$indexName = $keyName = $tableIndex['index_name'];
if(strpos($tableIndex['index_description'], 'primary key') !== false) {
if (strpos($tableIndex['index_description'], 'primary key') !== false) {
$keyName = 'primary';
}
$keyName = strtolower($keyName);
......@@ -191,7 +120,7 @@ class MsSqlSchemaManager extends AbstractSchemaManager
}
$indexes = array();
foreach($result AS $indexKey => $data) {
foreach ($result AS $indexKey => $data) {
$indexes[$indexKey] = new Index($data['name'], $data['columns'], $data['unique'], $data['primary']);
}
......@@ -204,14 +133,14 @@ class MsSqlSchemaManager extends AbstractSchemaManager
public function _getPortableTableForeignKeyDefinition($tableForeignKey)
{
return new ForeignKeyConstraint(
(array)$tableForeignKey['ColumnName'],
$tableForeignKey['ReferenceTableName'],
(array)$tableForeignKey['ReferenceColumnName'],
$tableForeignKey['ForeignKey'],
array(
'onUpdate' => str_replace('_', ' ', $tableForeignKey['update_referential_action_desc']),
'onDelete' => str_replace('_', ' ', $tableForeignKey['delete_referential_action_desc']),
)
(array) $tableForeignKey['ColumnName'],
$tableForeignKey['ReferenceTableName'],
(array) $tableForeignKey['ReferenceColumnName'],
$tableForeignKey['ForeignKey'],
array(
'onUpdate' => str_replace('_', ' ', $tableForeignKey['update_referential_action_desc']),
'onDelete' => str_replace('_', ' ', $tableForeignKey['delete_referential_action_desc']),
)
);
}
......@@ -222,21 +151,22 @@ class MsSqlSchemaManager extends AbstractSchemaManager
{
return $table['name'];
}
/**
/**
* @override
*/
protected function _getPortableDatabaseDefinition($database)
protected function _getPortableDatabaseDefinition($database)
{
return $database['name'];
}
/**
/**
* @override
*/
protected function _getPortableViewDefinition($view)
protected function _getPortableViewDefinition($view)
{
// @todo
// @todo
return new View($view['name'], null);
}
}
\ No newline at end of file
......@@ -6,9 +6,10 @@ use Doctrine\DBAL\Platforms\MsSqlPlatform;
use Doctrine\DBAL\Types\Type;
require_once __DIR__ . '/../../TestInit.php';
class MsSqlPlatformTest extends AbstractPlatformTestCase
{
public function createPlatform()
{
return new MsSqlPlatform;
......@@ -16,13 +17,13 @@ class MsSqlPlatformTest extends AbstractPlatformTestCase
public function getGenerateTableSql()
{
return 'CREATE TABLE test (id INT IDENTITY NOT NULL, test VARCHAR(255) DEFAULT NULL, PRIMARY KEY(id))';
return 'CREATE TABLE test (id INT IDENTITY NOT NULL, test NVARCHAR(255) DEFAULT NULL, PRIMARY KEY(id))';
}
public function getGenerateTableWithMultiColumnUniqueIndexSql()
{
return array(
'CREATE TABLE test (foo VARCHAR(255) DEFAULT NULL, bar VARCHAR(255) DEFAULT NULL)',
'CREATE TABLE test (foo NVARCHAR(255) DEFAULT NULL, bar NVARCHAR(255) DEFAULT NULL)',
'CREATE UNIQUE INDEX test_foo_bar_uniq ON test (foo, bar)'
);
}
......@@ -33,7 +34,7 @@ class MsSqlPlatformTest extends AbstractPlatformTestCase
'ALTER TABLE mytable RENAME TO userlist',
'ALTER TABLE mytable ADD quota INT DEFAULT NULL',
'ALTER TABLE mytable DROP COLUMN foo',
'ALTER TABLE mytable CHANGE bar baz VARCHAR(255) DEFAULT \'def\' NOT NULL',
'ALTER TABLE mytable CHANGE bar baz NVARCHAR(255) DEFAULT \'def\' NOT NULL',
);
}
......@@ -47,29 +48,26 @@ class MsSqlPlatformTest extends AbstractPlatformTestCase
public function testGeneratesTransactionsCommands()
{
$this->assertEquals(
'SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED',
$this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Connection::TRANSACTION_READ_UNCOMMITTED)
'SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED',
$this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Connection::TRANSACTION_READ_UNCOMMITTED)
);
$this->assertEquals(
'SET TRANSACTION ISOLATION LEVEL READ COMMITTED',
$this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Connection::TRANSACTION_READ_COMMITTED)
'SET TRANSACTION ISOLATION LEVEL READ COMMITTED',
$this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Connection::TRANSACTION_READ_COMMITTED)
);
$this->assertEquals(
'SET TRANSACTION ISOLATION LEVEL REPEATABLE READ',
$this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Connection::TRANSACTION_REPEATABLE_READ)
'SET TRANSACTION ISOLATION LEVEL REPEATABLE READ',
$this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Connection::TRANSACTION_REPEATABLE_READ)
);
$this->assertEquals(
'SET TRANSACTION ISOLATION LEVEL SERIALIZABLE',
$this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Connection::TRANSACTION_SERIALIZABLE)
'SET TRANSACTION ISOLATION LEVEL SERIALIZABLE',
$this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Connection::TRANSACTION_SERIALIZABLE)
);
}
public function testGeneratesDDLSnippets()
{
$dropDatabaseExpectation = <<<DDB
ALTER DATABASE [foobar]
SET SINGLE_USER --or RESTRICTED_USER
WITH ROLLBACK IMMEDIATE;
DROP DATABASE foobar;
DDB;
......@@ -82,36 +80,36 @@ DDB;
public function testGeneratesTypeDeclarationForIntegers()
{
$this->assertEquals(
'INT',
$this->_platform->getIntegerTypeDeclarationSQL(array())
'INT',
$this->_platform->getIntegerTypeDeclarationSQL(array())
);
$this->assertEquals(
'INT IDENTITY',
$this->_platform->getIntegerTypeDeclarationSQL(array('autoincrement' => true)
'INT IDENTITY',
$this->_platform->getIntegerTypeDeclarationSQL(array('autoincrement' => true)
));
$this->assertEquals(
'INT IDENTITY',
$this->_platform->getIntegerTypeDeclarationSQL(
array('autoincrement' => true, 'primary' => true)
'INT IDENTITY',
$this->_platform->getIntegerTypeDeclarationSQL(
array('autoincrement' => true, 'primary' => true)
));
}
public function testGeneratesTypeDeclarationsForStrings()
{
$this->assertEquals(
'CHAR(10)',
$this->_platform->getVarcharTypeDeclarationSQL(
array('length' => 10, 'fixed' => true)
'NCHAR(10)',
$this->_platform->getVarcharTypeDeclarationSQL(
array('length' => 10, 'fixed' => true)
));
$this->assertEquals(
'VARCHAR(50)',
$this->_platform->getVarcharTypeDeclarationSQL(array('length' => 50)),
'Variable string declaration is not correct'
'NVARCHAR(50)',
$this->_platform->getVarcharTypeDeclarationSQL(array('length' => 50)),
'Variable string declaration is not correct'
);
$this->assertEquals(
'TEXT',
$this->_platform->getVarcharTypeDeclarationSQL(array()),
'Long string declaration is not correct'
'NTEXT',
$this->_platform->getVarcharTypeDeclarationSQL(array()),
'Long string declaration is not correct'
);
}
......@@ -127,7 +125,7 @@ DDB;
public function testDoesNotSupportSavePoints()
{
$this->assertTrue($this->_platform->supportsSavepoints());
$this->assertTrue($this->_platform->supportsSavepoints());
}
public function getGenerateIndexSql()
......@@ -142,30 +140,37 @@ DDB;
public function getGenerateForeignKeySql()
{
return 'ALTER TABLE test ADD FOREIGN KEY (fk_name_id) REFERENCES other_table(id)';
return 'ALTER TABLE test ADD FOREIGN KEY (fk_name_id) REFERENCES other_table(id)';
}
public function testModifyLimitQuery()
{
$sql = $this->_platform->modifyLimitQuery('SELECT * FROM user', 10, 0);
$this->assertEquals('SELECT * FROM (SELECT TOP 10 * FROM (SELECT TOP 10 * FROM user) AS inner_tbl) AS outer_tbl', $sql);
$this->assertEquals('SELECT TOP 10 * FROM user', $sql);
}
public function testModifyLimitQueryWithEmptyOffset()
{
$sql = $this->_platform->modifyLimitQuery('SELECT * FROM user', 10);
$this->assertEquals('SELECT * FROM (SELECT TOP 10 * FROM (SELECT TOP 10 * FROM user) AS inner_tbl) AS outer_tbl', $sql);
$this->assertEquals('SELECT TOP 10 * FROM user', $sql);
}
public function testModifyLimitQueryWithOffset()
{
$sql = $this->_platform->modifyLimitQuery('SELECT * FROM user ORDER BY username DESC', 10, 5);
$this->assertEquals('WITH outer_tbl AS (SELECT ROW_NUMBER() OVER (ORDER BY username DESC) AS "doctrine_rownum", * FROM (SELECT * FROM user) AS inner_tbl) SELECT * FROM outer_tbl WHERE "doctrine_rownum" BETWEEN 6 AND 15', $sql);
}
public function testModifyLimitQueryWithAscOrderBy()
{
$sql = $this->_platform->modifyLimitQuery('SELECT * FROM user ORDER BY username ASC', 10);
$this->assertEquals('SELECT * FROM (SELECT TOP 10 * FROM (SELECT TOP 10 * FROM user ORDER BY username ASC) AS inner_tbl ORDER BY inner_tbl.u DESC) AS outer_tbl ORDER BY outer_tbl.u ASC', $sql);
$this->assertEquals('SELECT TOP 10 * FROM user ORDER BY username ASC', $sql);
}
public function testModifyLimitQueryWithDescOrderBy()
{
$sql = $this->_platform->modifyLimitQuery('SELECT * FROM user ORDER BY username DESC', 10);
$this->assertEquals('SELECT * FROM (SELECT TOP 10 * FROM (SELECT TOP 10 * FROM user ORDER BY username DESC) AS inner_tbl ORDER BY inner_tbl.u ASC) AS outer_tbl ORDER BY outer_tbl.u DESC', $sql);
$this->assertEquals('SELECT TOP 10 * FROM user ORDER BY username DESC', $sql);
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment