From f580f0a27960df0424ce5645b2e4e1b151b5b69c Mon Sep 17 00:00:00 2001 From: Juozas Kaziukenas Date: Sun, 30 May 2010 21:36:41 +0100 Subject: [PATCH] Added pdo_sqlsrv, sqlsrv drivers and mssql updates Signed-off-by: Juozas Kaziukenas --- .../DBAL/Driver/PDOMsSql/Connection.php | 29 +- .../DBAL/Driver/PDOSqlsrv/Connection.php | 60 +++ lib/Doctrine/DBAL/Driver/PDOSqlsrv/Driver.php | 95 ++++ lib/Doctrine/DBAL/Driver/Sqlsrv/Driver.php | 81 +++ .../DBAL/Driver/Sqlsrv/SqlsrvConnection.php | 130 +++++ .../DBAL/Driver/Sqlsrv/SqlsrvException.php | 30 ++ .../DBAL/Driver/Sqlsrv/SqlsrvStatement.php | 249 +++++++++ lib/Doctrine/DBAL/DriverManager.php | 2 + lib/Doctrine/DBAL/Platforms/MsSqlPlatform.php | 395 +++++++------- .../DBAL/Platforms/SqlsrvPlatform.php | 45 ++ .../DBAL/Schema/MsSqlSchemaManager.php | 492 ++++++------------ .../DBAL/Schema/SqlsrvSchemaManager.php | 35 ++ .../DBAL/Platforms/MsSqlPlatformTest.php | 8 +- 13 files changed, 1128 insertions(+), 523 deletions(-) create mode 100644 lib/Doctrine/DBAL/Driver/PDOSqlsrv/Connection.php create mode 100644 lib/Doctrine/DBAL/Driver/PDOSqlsrv/Driver.php create mode 100644 lib/Doctrine/DBAL/Driver/Sqlsrv/Driver.php create mode 100644 lib/Doctrine/DBAL/Driver/Sqlsrv/SqlsrvConnection.php create mode 100644 lib/Doctrine/DBAL/Driver/Sqlsrv/SqlsrvException.php create mode 100644 lib/Doctrine/DBAL/Driver/Sqlsrv/SqlsrvStatement.php create mode 100644 lib/Doctrine/DBAL/Platforms/SqlsrvPlatform.php create mode 100644 lib/Doctrine/DBAL/Schema/SqlsrvSchemaManager.php diff --git a/lib/Doctrine/DBAL/Driver/PDOMsSql/Connection.php b/lib/Doctrine/DBAL/Driver/PDOMsSql/Connection.php index b9ff3889934..1b5fb4efc6e 100644 --- a/lib/Doctrine/DBAL/Driver/PDOMsSql/Connection.php +++ b/lib/Doctrine/DBAL/Driver/PDOMsSql/Connection.php @@ -1,5 +1,7 @@ exec('BEGIN TRANSACTION'); } - - /** - * {@inheritdoc} - */ - public function lastInsertId($name = null) - { - $stmt = $this->query('SELECT SCOPE_IDENTITY()'); - $id = $stmt->fetchColumn(); - $stmt->closeCursor(); - return $id; - } } \ No newline at end of file diff --git a/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Connection.php b/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Connection.php new file mode 100644 index 00000000000..7285bb48451 --- /dev/null +++ b/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Connection.php @@ -0,0 +1,60 @@ +. + */ + +namespace Doctrine\DBAL\Driver\PDOSqlsrv; + +/** + * Sqlsrv Connection implementation. + * + * @since 2.0 + */ +class Connection extends \PDO implements \Doctrine\DBAL\Driver\Connection +{ + /** + * Performs the rollback. + * + * @override + */ + public function rollback() + { + $this->exec('ROLLBACK TRANSACTION'); + } + + /** + * Performs the commit. + * + * @override + */ + public function commit() + { + $this->exec('COMMIT TRANSACTION'); + } + + /** + * Begins a database transaction. + * + * @override + */ + public function beginTransaction() + { + $this->exec('BEGIN TRANSACTION'); + } +} \ No newline at end of file diff --git a/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Driver.php b/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Driver.php new file mode 100644 index 00000000000..442c5c189f2 --- /dev/null +++ b/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Driver.php @@ -0,0 +1,95 @@ +. + */ + +namespace Doctrine\DBAL\Driver\PDOSqlsrv; + +/** + * The PDO-based Sqlsrv driver. + * + * @since 2.0 + */ +class Driver implements \Doctrine\DBAL\Driver +{ + public function connect(array $params, $username = null, $password = null, array $driverOptions = array()) + { + if (isset($params['dbname'])) { + $driverOptions['Database'] = $params['dbname']; + } + + return new Connection( + $this->_constructPdoDsn($params), + $username, + $password, + $driverOptions + ); + } + + /** + * Constructs the Sqlsrv PDO DSN. + * + * @return string The DSN. + */ + private function _constructPdoDsn(array $params) + { + // TODO: This might need to be revisted once we have access to a sql server + $dsn = 'sqlsrv:('; + if (isset($params['host'])) { + $dsn .= $params['host']; + } + $dsn .= ')'; + + if (stripos($dsn, '\sqlexpress') !== false) + { + $dsn = str_ireplace('\sqlexpress', '', $dsn); + $dsn .= '\sqlexpress'; + } + + $dsn = str_ireplace('localhost', 'local', $dsn); + + if (isset($params['port']) && !empty($params['port'])) { + $dsn .= ',' . $params['port']; + } + + return $dsn; + } + + + public function getDatabasePlatform() + { + return new \Doctrine\DBAL\Platforms\SqlsrvPlatform(); + } + + public function getSchemaManager(\Doctrine\DBAL\Connection $conn) + { + return new \Doctrine\DBAL\Schema\SqlsrvSchemaManager($conn); + } + + public function getName() + { + return 'pdo_sqlsrv'; + } + + public function getDatabase(\Doctrine\DBAL\Connection $conn) + { + $params = $conn->getParams(); + return $params['dbname']; + } +} \ No newline at end of file diff --git a/lib/Doctrine/DBAL/Driver/Sqlsrv/Driver.php b/lib/Doctrine/DBAL/Driver/Sqlsrv/Driver.php new file mode 100644 index 00000000000..2e32b774b2d --- /dev/null +++ b/lib/Doctrine/DBAL/Driver/Sqlsrv/Driver.php @@ -0,0 +1,81 @@ +. + */ + +namespace Doctrine\DBAL\Driver\Sqlsrv; + +use Doctrine\DBAL\Platforms; + +/** + * A Doctrine DBAL driver for the Microsoft SQL Native Client PHP extension. + * + * @since 2.0 + * @author Juozas Kaziukenas + */ +class Driver implements \Doctrine\DBAL\Driver +{ + public function connect(array $params, $username = null, $password = null, array $driverOptions = array()) + { + $serverName = ''; + // construct server name + $serverName = $params['host']; + if (isset($params['port']) && !empty($params['port'])) { + $port = (integer) $params['port']; + $serverName .= ', ' . $port; + } + + $connectionInfo = array( + 'Database' => $params['dbname'], + ); + + if (isset($username) && !empty($username) && isset($password) && !empty($password)) + { + $connectionInfo += array( + 'UID' => $username, + 'PWD' => $password, + ); + } + + $connectionInfo += array('ReturnDatesAsStrings' => true); + + return new SqlsrvConnection($serverName, $connectionInfo); + } + + public function getDatabasePlatform() + { + return new \Doctrine\DBAL\Platforms\SqlsrvPlatform(); + } + + public function getSchemaManager(\Doctrine\DBAL\Connection $conn) + { + return new \Doctrine\DBAL\Schema\SqlsrvSchemaManager($conn); + } + + public function getName() + { + return 'sqlsrv'; + } + + public function getDatabase(\Doctrine\DBAL\Connection $conn) + { + $params = $conn->getParams(); + return $params['dbname']; + } +} \ No newline at end of file diff --git a/lib/Doctrine/DBAL/Driver/Sqlsrv/SqlsrvConnection.php b/lib/Doctrine/DBAL/Driver/Sqlsrv/SqlsrvConnection.php new file mode 100644 index 00000000000..75b841a704c --- /dev/null +++ b/lib/Doctrine/DBAL/Driver/Sqlsrv/SqlsrvConnection.php @@ -0,0 +1,130 @@ +. + */ + +namespace Doctrine\DBAL\Driver\Sqlsrv; + +/** + * Sqlsrv implementation of the Connection interface. + * + * @since 2.0 + * @author Juozas Kaziukenas + */ +class SqlsrvConnection implements \Doctrine\DBAL\Driver\Connection +{ + private $_dbh; + + public function __construct($serverName, array $connectionInfo) + { + $this->_dbh = @sqlsrv_connect($serverName, $connectionInfo); + if (!is_resource($this->_dbh)) { + throw SqlsrvException::fromErrorInfo($this->errorInfo()); + } + } + + public function prepare($prepareString) + { + return new SqlsrvStatement($this->_dbh, $prepareString); + } + + public function query() + { + $args = func_get_args(); + $sql = $args[0]; + //$fetchMode = $args[1]; + $stmt = $this->prepare($sql); + $stmt->execute(); + return $stmt; + } + + public function quote($input, $type=\PDO::PARAM_STR) + { + return is_numeric($input) ? $input : "'" . str_replace("'", "''", $input) . "'"; + } + + public function exec($statement) + { + $stmt = $this->prepare($statement); + $stmt->execute(); + return $stmt->rowCount(); + } + + public function lastInsertId($name = null) + { + $id = $this->query('SELECT @@IDENTITY')->fetchColumn(); + + if (!$id) { + return 1; + } + + return $id; + } + + public function beginTransaction() + { + if (!sqlsrv_begin_transaction($this->_dbh)) { + throw SqlsrvException::fromErrorInfo($this->errorInfo()); + } + return true; + } + + public function commit() + { + if (!sqlsrv_commit($this->_dbh)) { + throw SqlsrvException::fromErrorInfo($this->errorInfo()); + } + return true; + } + + public function rollBack() + { + if (!sqlsrv_rollback($this->_dbh)) { + throw SqlsrvException::fromErrorInfo($this->errorInfo()); + } + return true; + } + + public function errorCode() + { + $errors = sqlsrv_errors(); + + if (false === isset($errors[0]['code'])) + { + return null; + } + + $error = $errors[0]; + + return $error['code']; + } + + public function errorInfo() + { + $errors = sqlsrv_errors(); + + if (false === isset($errors[0]['message'])) + { + return null; + } + + return $errors[0]; + } + +} \ No newline at end of file diff --git a/lib/Doctrine/DBAL/Driver/Sqlsrv/SqlsrvException.php b/lib/Doctrine/DBAL/Driver/Sqlsrv/SqlsrvException.php new file mode 100644 index 00000000000..57c84f130c9 --- /dev/null +++ b/lib/Doctrine/DBAL/Driver/Sqlsrv/SqlsrvException.php @@ -0,0 +1,30 @@ +. +*/ + +namespace Doctrine\DBAL\Driver\Sqlsrv; + +class SqlsrvException extends \Exception +{ + static public function fromErrorInfo($error) + { + return new self($error['message'], $error['code']); + } +} diff --git a/lib/Doctrine/DBAL/Driver/Sqlsrv/SqlsrvStatement.php b/lib/Doctrine/DBAL/Driver/Sqlsrv/SqlsrvStatement.php new file mode 100644 index 00000000000..f2199824f01 --- /dev/null +++ b/lib/Doctrine/DBAL/Driver/Sqlsrv/SqlsrvStatement.php @@ -0,0 +1,249 @@ +. + */ + +namespace Doctrine\DBAL\Driver\Sqlsrv; + +use \PDO; + +/** + * The Sql server implementation of the Statement interface. + * + * @since 2.0 + * @author Juozas Kaziukenas + */ +class SqlsrvStatement implements \Doctrine\DBAL\Driver\Statement +{ + /** Statement handle. */ + private $_sth; + private $_dbh = null; + private $_query = null; + private static $fetchStyleMap = array( + PDO::FETCH_BOTH => SQLSRV_FETCH_BOTH, + PDO::FETCH_ASSOC => SQLSRV_FETCH_ASSOC, + PDO::FETCH_NUM => SQLSRV_FETCH_NUMERIC + ); + private $_paramMap = array(); + private $_bindParams = array(); + + /** + * Creates a new SqlsrvStatement that uses the given connection handle and SQL statement. + * + * @param resource $dbh The connection handle. + * @param string $statement The SQL statement. + */ + public function __construct($dbh, $statement) + { + $this->_dbh = $dbh; + $this->_query = $this->_convertPositionalToNamedPlaceholders($statement); + } + + /** + * Sqlsrv doesnt support bamed params and these should be replaced + * to question marks + * + * @param string $statement The SQL statement to convert. + */ + private function _convertPositionalToNamedPlaceholders($statement) + { + // reset bind params + $this->bindParams = array(); + + // get params count + $param_count = substr_count($statement,'?'); + + // prepare bind params + if($param_count > 0) { + + for ($i = 0; $i < $param_count; $i++) + { + // preapre bind param for later usage + $this->_bindParams[$i] = null; + } + } + else + { + // parse statement and get named bind params + if(preg_match_all('/[= ]:([a-z]+)\b/', $statement, $matches)) + { + for($i=0, $c = count($matches[1]); $i < $c; $i++) + { + // preapre bind param for later usage + $this->_bindParams[$i] = null; + + // save name for later usage + $this->_paramMap[$matches[1][$i]] = $i + 1; + + // replace to question mark (:name => ?) + $statement = str_replace(':' . $matches[1][$i], '?',$statement); + } + } + } + + return $statement; + } + + /** + * {@inheritdoc} + */ + public function bindValue($param, $value, $type = null) + { + return $this->bindParam($param, $value, $type); + } + + /** + * {@inheritdoc} + */ + public function bindParam($column, &$variable, $type = null) + { + $column = isset($this->_paramMap[$column]) ? $this->_paramMap[$column] : $column; + + if($column > 0 && $column <= count($this->_bindParams)) { + $this->_bindParams[$column-1] = &$variable; + } else { + throw SqlsrvException::fromErrorInfo(array('message' => "Parameter out of bounds")); + } + } + + /** + * Closes the cursor, enabling the statement to be executed again. + * + * @return boolean Returns TRUE on success or FALSE on failure. + */ + public function closeCursor() + { + return sqlsrv_free_stmt($this->_sth); + } + + /** + * {@inheritdoc} + */ + public function columnCount() + { + return sqlsrv_num_fields($this->_sth); + } + + /** + * {@inheritdoc} + */ + public function errorCode() + { + $errors = sqlsrv_errors(); + + if (false === isset($errors[0]['code'])) + { + return null; + } + + $error = $errors[0]; + + return $error['code']; + } + + /** + * {@inheritdoc} + */ + public function errorInfo() + { + $errors = sqlsrv_errors(); + + if (false === isset($errors[0]['message'])) + { + return null; + } + + return $errors[0]; + } + + /** + * {@inheritdoc} + */ + public function execute($params = null) + { + if ($params) { + $hasZeroIndex = isset($params[0]); + foreach ($params as $key => $val) { + if ($hasZeroIndex && is_numeric($key)) { + $this->bindValue($key + 1, $val); + } else { + $this->bindValue($key, $val); + } + } + } + + // prepare statement + $this->_sth = sqlsrv_prepare($this->_dbh, $this->_query, $this->_bindParams); + + if ( ! $this->_sth) { + throw SqlsrvException::fromErrorInfo($this->errorInfo()); + } + + $ret = @sqlsrv_execute($this->_sth); + if ( ! $ret) { + throw SqlsrvException::fromErrorInfo($this->errorInfo()); + } + return $ret; + } + + /** + * {@inheritdoc} + */ + public function fetch($fetchStyle = PDO::FETCH_BOTH) + { + if ( ! isset(self::$fetchStyleMap[$fetchStyle])) { + throw new \InvalidArgumentException("Invalid fetch style: " . $fetchStyle); + } + + return sqlsrv_fetch_array($this->_sth, self::$fetchStyleMap[$fetchStyle]); + } + + /** + * {@inheritdoc} + */ + public function fetchAll($fetchStyle = PDO::FETCH_BOTH) + { + if ( ! isset(self::$fetchStyleMap[$fetchStyle])) { + throw new \InvalidArgumentException("Invalid fetch style: " . $fetchStyle); + } + + $result = array(); + while ($row = $this->fetch($fetchStyle)) { + $result[] = $row; + } + + return $result; + } + + /** + * {@inheritdoc} + */ + public function fetchColumn($columnIndex = 0) + { + return sqlsrv_get_field($this->_sth, $columnIndex); + } + + /** + * {@inheritdoc} + */ + public function rowCount() + { + return sqlsrv_num_rows($this->_sth); + } +} \ No newline at end of file diff --git a/lib/Doctrine/DBAL/DriverManager.php b/lib/Doctrine/DBAL/DriverManager.php index db91f1d374e..c446bae2673 100644 --- a/lib/Doctrine/DBAL/DriverManager.php +++ b/lib/Doctrine/DBAL/DriverManager.php @@ -44,6 +44,8 @@ final class DriverManager 'oci8' => 'Doctrine\DBAL\Driver\OCI8\Driver', 'ibm_db2' => 'Doctrine\DBAL\Driver\IBMDB2\DB2Driver', 'pdo_ibm' => 'Doctrine\DBAL\Driver\PDOIbm\Driver', + 'pdo_sqlsrv' => 'Doctrine\DBAL\Driver\PDOSqlsrv\Driver', + 'sqlsrv' => 'Doctrine\DBAL\Driver\Sqlsrv\Driver', ); /** Private constructor. This class cannot be instantiated. */ diff --git a/lib/Doctrine/DBAL/Platforms/MsSqlPlatform.php b/lib/Doctrine/DBAL/Platforms/MsSqlPlatform.php index d11229da2c5..f539ced53be 100644 --- a/lib/Doctrine/DBAL/Platforms/MsSqlPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/MsSqlPlatform.php @@ -21,6 +21,7 @@ use Doctrine\DBAL\Schema\TableDiff; use Doctrine\DBAL\DBALException; +use Doctrine\DBAL\Schema\Index; /** * The MsSqlPlatform provides the behavior, features and SQL dialect of the @@ -35,50 +36,79 @@ class MsSqlPlatform extends AbstractPlatform { /** - * Adds an adapter-specific LIMIT clause to the SELECT statement. - * [ borrowed from Zend Framework ] + * Whether the platform prefers identity columns for ID generation. + * MsSql prefers "autoincrement" identity columns since sequences can only + * be emulated with a table. * - * @param string $query - * @param mixed $limit - * @param mixed $offset - * @link http://lists.bestpractical.com/pipermail/rt-devel/2005-June/007339.html - * @return string + * @return boolean * @override */ - public function writeLimitClause($query, $limit = false, $offset = false) + public function prefersIdentityColumns() { - if ($limit > 0) { - $count = intval($limit); + return true; + } - $offset = intval($offset); - if ($offset < 0) { - throw DBALException::limitOffsetInvalid($offset); - } - - $orderby = stristr($query, 'ORDER BY'); - if ($orderby !== false) { - $sort = (stripos($orderby, 'desc') !== false) ? 'desc' : 'asc'; - $order = str_ireplace('ORDER BY', '', $orderby); - $order = trim(preg_replace('/ASC|DESC/i', '', $order)); - } - - $query = preg_replace('/^SELECT\s/i', 'SELECT TOP ' . ($count+$offset) . ' ', $query); - - $query = 'SELECT * FROM (SELECT TOP ' . $count . ' * FROM (' . $query . ') AS inner_tbl'; - if ($orderby !== false) { - $query .= ' ORDER BY ' . $order . ' '; - $query .= (stripos($sort, 'asc') !== false) ? 'DESC' : 'ASC'; - } - $query .= ') AS outer_tbl'; - if ($orderby !== false) { - $query .= ' ORDER BY ' . $order . ' ' . $sort; - } + /** + * Whether the platform supports identity columns. + * MsSql supports this through AUTO_INCREMENT columns. + * + * @return boolean + * @override + */ + public function supportsIdentityColumns() + { + return true; + } + + /** + * Whether the platform supports savepoints. MsSql does not. + * + * @return boolean + * @override + */ + public function supportsSavepoints() + { + return false; + } - return $query; + /** + * create a new database + * + * @param string $name name of the database that should be created + * @return string + * @override + */ + public function getCreateDatabaseSQL($name) + { + return 'CREATE DATABASE ' . $name; + } + /** + * drop an existing database + * + * @param string $name name of the database that should be dropped + * @return string + * @override + */ + public function getDropDatabaseSQL($name) + { + return 'DROP DATABASE ' . $name; + } + + /** + * @override + */ + public function getDropForeignKeySQL($foreignKey, $table) + { + if ($foreignKey instanceof \Doctrine\DBAL\Schema\ForeignKeyConstraint) { + $foreignKey = $foreignKey->getName(); } - return $query; + if ($table instanceof \Doctrine\DBAL\Schema\Table) { + $table = $table->getName(); + } + + return 'ALTER TABLE ' . $table . ' DROP CONSTRAINT ' . $foreignKey; } /** @@ -123,66 +153,77 @@ public function getAlterTableSQL(TableDiff $diff) $sql = array_merge($sql, $this->_getAlterTableIndexForeignKeySQL($diff)); return $sql; } - + /** - * Returns the regular expression operator. - * - * @return string * @override */ - public function getRegexpExpression() + public function getEmptyIdentityInsertSQL($quotedTableName, $quotedIdentifierColumnName) { - return 'RLIKE'; + return 'INSERT INTO ' . $quotedTableName . ' DEFAULT VALUES'; } /** - * Return string to call a variable with the current timestamp inside an SQL statement - * There are three special variables for current date and time: - * - CURRENT_TIMESTAMP (date and time, TIMESTAMP type) - * - CURRENT_DATE (date, DATE type) - * - CURRENT_TIME (time, TIME type) - * - * @return string to call a variable with the current timestamp * @override */ - public function getNowExpression($type = 'timestamp') + public function getShowDatabasesSQL() { - switch ($type) { - case 'time': - case 'date': - case 'timestamp': - default: - return 'GETDATE()'; - } + return 'SHOW DATABASES'; } /** - * return string to call a function to get a substring inside an SQL statement - * - * @return string to call a function to get a substring * @override */ - public function getSubstringExpression($value, $position, $length = null) + public function getListTablesSQL() { - if ( ! is_null($length)) { - return 'SUBSTRING(' . $value . ', ' . $position . ', ' . $length . ')'; - } - return 'SUBSTRING(' . $value . ', ' . $position . ', LEN(' . $value . ') - ' . $position . ' + 1)'; + return "SELECT name FROM sysobjects WHERE type = 'U' ORDER BY name"; + } + + /** + * @override + */ + public function getListTableColumnsSQL($table) + { + return 'exec sp_columns @table_name = ' . $table; + } + + /** + * @override + */ + public function getListTableForeignKeysSQL($table, $database = null) + { + return "SELECT f.name AS ForeignKey, + SCHEMA_NAME (f.SCHEMA_ID) AS SchemaName, + OBJECT_NAME (f.parent_object_id) AS TableName, + COL_NAME (fc.parent_object_id,fc.parent_column_id) AS ColumnName, + SCHEMA_NAME (o.SCHEMA_ID) ReferenceSchemaName, + OBJECT_NAME (f.referenced_object_id) AS ReferenceTableName, + COL_NAME(fc.referenced_object_id,fc.referenced_column_id) AS ReferenceColumnName, + f.delete_referential_action_desc, + f.update_referential_action_desc + FROM sys.foreign_keys AS f + INNER JOIN sys.foreign_key_columns AS fc + INNER JOIN sys.objects AS o ON o.OBJECT_ID = fc.referenced_object_id + ON f.OBJECT_ID = fc.constraint_object_id + WHERE OBJECT_NAME (f.parent_object_id) = '" . $table . "'"; + } + + /** + * @override + */ + public function getListTableIndexesSQL($table) + { + return "exec sp_helpindex '" . $table . "'"; } /** - * Returns string to concatenate two or more string parameters + * Returns the regular expression operator. * - * @param string $arg1 - * @param string $arg2 - * @param string $values... - * @return string to concatenate two strings + * @return string * @override */ - public function getConcatExpression() + public function getRegexpExpression() { - $args = func_get_args(); - return '(' . implode(' + ', $args) . ')'; + return 'RLIKE'; } /** @@ -193,86 +234,87 @@ public function getConcatExpression() */ public function getGuidExpression() { - return 'NEWID()'; + return 'UUID()'; } /** - * Whether the platform prefers identity columns for ID generation. - * MsSql prefers "autoincrement" identity columns since sequences can only - * be emulated with a table. - * - * @return boolean * @override */ - public function prefersIdentityColumns() + public function getLocateExpression($str, $substr, $startPos = false) { - return true; + if ($startPos == false) { + return 'CHARINDEX(' . $substr . ', ' . $str . ')'; + } else { + return 'CHARINDEX(' . $substr . ', ' . $str . ', '.$startPos.')'; + } } - + /** - * Whether the platform supports identity columns. - * MsSql supports this through AUTO_INCREMENT columns. - * - * @return boolean * @override */ - public function supportsIdentityColumns() + public function getModExpression($expression1, $expression2) { - return true; + return $expression1 . ' % ' . $expression2; } - + /** - * Whether the platform supports savepoints. MsSql does not. - * - * @return boolean * @override */ - public function supportsSavepoints() + public function getTrimExpression($str, $pos = self::TRIM_UNSPECIFIED, $char = false) { - return false; - } + // @todo + $trimFn = ''; + $trimChar = ($char != false) ? (', ' . $char) : ''; - public function getShowDatabasesSQL() - { - return 'SHOW DATABASES'; + if ($pos == self::TRIM_LEADING) { + $trimFn = 'LTRIM'; + } else if($pos == self::TRIM_TRAILING) { + $trimFn = 'RTRIM'; + } else { + return 'LTRIM(RTRIM(' . $str . '))'; + } + + return $trimFn . '(' . $str . ')'; } - public function getListTablesSQL() + /** + * @override + */ + public function getConcatExpression() { - return 'SHOW TABLES'; + $args = func_get_args(); + return '(' . implode(' + ', $args) . ')'; } - + /** - * create a new database - * - * @param string $name name of the database that should be created - * @return string * @override */ - public function getCreateDatabaseSQL($name) + public function getSubstringExpression($value, $from, $len = null) { - return 'CREATE DATABASE ' . $name; + if ( ! is_null($len)) { + return 'SUBSTRING(' . $value . ', ' . $from . ', ' . $len . ')'; + } + return 'SUBSTRING(' . $value . ', ' . $from . ', LEN(' . $value . ') - ' . $from . ' + 1)'; } - + /** - * drop an existing database - * - * @param string $name name of the database that should be dropped - * @return string * @override */ - public function getDropDatabaseSQL($name) + public function getLengthExpression($column) { - return 'DROP DATABASE ' . $name; + return 'LEN(' . $column . ')'; } + /** + * @override + */ public function getSetTransactionIsolationSQL($level) { return 'SET TRANSACTION ISOLATION LEVEL ' . $this->_getTransactionIsolationLevelSQL($level); } - /** - * @override + /** + * @override */ public function getIntegerTypeDeclarationSQL(array $field) { @@ -280,21 +322,22 @@ public function getIntegerTypeDeclarationSQL(array $field) } /** - * @override + * @override */ public function getBigIntTypeDeclarationSQL(array $field) { return 'BIGINT' . $this->_getCommonIntegerTypeDeclarationSQL($field); } - /** - * @override + /** + * @override */ public function getSmallIntTypeDeclarationSQL(array $field) { return 'SMALLINT' . $this->_getCommonIntegerTypeDeclarationSQL($field); } + /** @override */ public function getVarcharTypeDeclarationSQL(array $field) { if ( ! isset($field['length'])) { @@ -311,33 +354,34 @@ public function getVarcharTypeDeclarationSQL(array $field) return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(255)') : ($length ? 'VARCHAR(' . $length . ')' : 'TEXT'); } - + /** @override */ public function getClobTypeDeclarationSQL(array $field) { return 'TEXT'; } - /** - * @override + /** + * @override */ protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) { $autoinc = ''; if ( ! empty($columnDef['autoincrement'])) { - $autoinc = ' AUTO_INCREMENT'; + $autoinc = ' IDENTITY'; } $unsigned = (isset($columnDef['unsigned']) && $columnDef['unsigned']) ? ' UNSIGNED' : ''; return $unsigned . $autoinc; } - + /** * @override */ public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) { - return 'CHAR(' . strlen('YYYY-MM-DD HH:MM:SS') . ')'; + // 6 - microseconds precision length + return 'DATETIME2(6)'; } /** @@ -345,17 +389,17 @@ public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) */ public function getDateTypeDeclarationSQL(array $fieldDeclaration) { - return 'CHAR(' . strlen('YYYY-MM-DD') . ')'; - } + return 'DATE'; + } /** * @override */ - public function getTimeTypeDeclarationSQL(array $fieldDeclaration) + public function getTimeTypeDeclarationSQL(array $fieldDeclaration) { - return 'CHAR(' . strlen('HH:MM:SS') . ')'; + return 'TIME'; } - + /** * @override */ @@ -364,16 +408,6 @@ public function getBooleanTypeDeclarationSQL(array $field) return 'BIT'; } - /** - * Get the platform name for this instance - * - * @return string - */ - public function getName() - { - return 'mssql'; - } - /** * Adds an adapter-specific LIMIT clause to the SELECT statement. * @@ -432,14 +466,14 @@ public function modifyLimitQuery($query, $limit, $offset = null) $query = 'SELECT * FROM (SELECT TOP ' . $count . ' * FROM (' . $query . ') AS ' . 'inner_tbl'; if ($orderby !== false) { - $query .= ' ORDER BY '; + $query .= ' ORDER BY '; - for ($i = 0, $l = count($orders); $i < $l; $i++) { - if ($i > 0) { // not first order clause - $query .= ', '; - } + for ($i = 0, $l = count($orders); $i < $l; $i++) { + if ($i > 0) { // not first order clause + $query .= ', '; + } - $query .= 'inner_tbl' . '.' . $aliases[$i] . ' '; + $query .= 'inner_tbl' . '.' . $aliases[$i] . ' '; $query .= (stripos($sorts[$i], 'ASC') !== false) ? 'DESC' : 'ASC'; } } @@ -447,12 +481,12 @@ public function modifyLimitQuery($query, $limit, $offset = null) $query .= ') AS ' . 'outer_tbl'; if ($orderby !== false) { - $query .= ' ORDER BY '; + $query .= ' ORDER BY '; - for ($i = 0, $l = count($orders); $i < $l; $i++) { - if ($i > 0) { // not first order clause - $query .= ', '; - } + for ($i = 0, $l = count($orders); $i < $l; $i++) { + if ($i > 0) { // not first order clause + $query .= ', '; + } $query .= 'outer_tbl' . '.' . $aliases[$i] . ' ' . $sorts[$i]; } @@ -463,51 +497,58 @@ public function modifyLimitQuery($query, $limit, $offset = null) } /** - * Get the insert sql for an empty insert statement - * - * @param string $tableName - * @param string $identifierColumnName - * @return string $sql + * @override */ - public function getEmptyIdentityInsertSQL($quotedTableName, $quotedIdentifierColumnName) + public function convertBooleans($item) { - return 'INSERT INTO ' . $quotedTableName . ' DEFAULT VALUES'; + if (is_array($item)) { + foreach ($item as $key => $value) { + if (is_bool($value) || is_numeric($item)) { + $item[$key] = ($value) ? 'TRUE' : 'FALSE'; + } + } + } else { + if (is_bool($item) || is_numeric($item)) { + $item = ($item) ? 'TRUE' : 'FALSE'; + } + } + return $item; } /** - * @inheritdoc + * @override */ - public function getTruncateTableSQL($tableName, $cascade = false) + public function getCreateTemporaryTableSnippetSQL() { - return 'TRUNCATE TABLE '.$tableName; + // @todo change to be a real temporary table + return "CREATE TABLE"; } /** - * MsSql uses Table Hints for locking strategies instead of the ANSI SQL FOR UPDATE like hints. - * - * @return string + * @override + */ + public function getDateTimeFormatString() + { + return 'Y-m-d H:i:s.u'; + } + + /** + * @override */ - public function getForUpdateSQL() + public function getIndexDeclarationSQL($name, Index $index) { - return ''; + // @todo + return $this->getUniqueConstraintDeclarationSQL($name, $index); } /** - * @license LGPL - * @author Hibernate - * @param string $fromClause - * @param int $lockMode + * Get the platform name for this instance + * * @return string */ - public function appendLockHint($fromClause, $lockMode) + public function getName() { - if ($lockMode == \Doctrine\DBAL\LockMode::PESSIMISTIC_WRITE) { - return $fromClause . " WITH (UPDLOCK, ROWLOCK)"; - } else if ( $lockMode == \Doctrine\DBAL\LockMode::PESSIMISTIC_READ ) { - return $fromClause . " WITH (HOLDLOCK, ROWLOCK)"; - } else { - return $fromClause; - } + return 'mssql'; } protected function initializeDoctrineTypeMappings() diff --git a/lib/Doctrine/DBAL/Platforms/SqlsrvPlatform.php b/lib/Doctrine/DBAL/Platforms/SqlsrvPlatform.php new file mode 100644 index 00000000000..16d62d92d17 --- /dev/null +++ b/lib/Doctrine/DBAL/Platforms/SqlsrvPlatform.php @@ -0,0 +1,45 @@ +. + */ + +namespace Doctrine\DBAL\Platforms; + +use Doctrine\DBAL\Schema\TableDiff; +use Doctrine\DBAL\DBALException; + +/** + * The SqlsrvPlatform provides the behavior, features and SQL dialect of the + * Microsoft SQL database platform. + * + * @since 2.0 + * @author Juozas Kaziukenas + */ +class SqlsrvPlatform extends MsSqlPlatform +{ + /** + * Get the platform name for this instance + * + * @return string + */ + public function getName() + { + return 'sqlsrv'; + } +} diff --git a/lib/Doctrine/DBAL/Schema/MsSqlSchemaManager.php b/lib/Doctrine/DBAL/Schema/MsSqlSchemaManager.php index 953f8caa554..830fb111e4c 100644 --- a/lib/Doctrine/DBAL/Schema/MsSqlSchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/MsSqlSchemaManager.php @@ -27,373 +27,215 @@ * @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @author Konsta Vesterinen * @author Lukas Smith (PEAR MDB2 library) + * @author Juozas Kaziukenas * @version $Revision$ * @since 2.0 */ class MsSqlSchemaManager extends AbstractSchemaManager { /** - * create a new database - * - * @param string $name name of the database that should be created - * @return void + * @override */ - public function createDatabase($name) + protected function _getPortableTableColumnDefinition($tableColumn) { - $query = "CREATE DATABASE $name"; - if ($this->conn->options['database_device']) { - $query.= ' ON '.$this->conn->options['database_device']; - $query.= $this->conn->options['database_size'] ? '=' . - $this->conn->options['database_size'] : ''; + $dbType = strtolower($tableColumn['TYPE_NAME']); + + if (stripos($dbType, 'identity')) { + $dbType = trim(str_ireplace('identity', '', $dbType)); } - return $this->conn->standaloneQuery($query, null, true); - } - /** - * drop an existing database - * - * @param string $name name of the database that should be dropped - * @return void - */ - public function dropDatabase($name) - { - return $this->conn->standaloneQuery('DROP DATABASE ' . $name, null, true); - } + $type = array(); + $unsigned = $fixed = null; - /** - * alter an existing table - * - * @param string $name name of the table that is intended to be changed. - * @param array $changes associative array that contains the details of each type - * of change that is intended to be performed. The types of - * changes that are currently supported are defined as follows: - * - * name - * - * New name for the table. - * - * add - * - * Associative array with the names of fields to be added as - * indexes of the array. The value of each entry of the array - * should be set to another associative array with the properties - * of the fields to be added. The properties of the fields should - * be the same as defined by the Metabase parser. - * - * - * remove - * - * Associative array with the names of fields to be removed as indexes - * of the array. Currently the values assigned to each entry are ignored. - * An empty array should be used for future compatibility. - * - * rename - * - * Associative array with the names of fields to be renamed as indexes - * of the array. The value of each entry of the array should be set to - * another associative array with the entry named name with the new - * field name and the entry named Declaration that is expected to contain - * the portion of the field declaration already in DBMS specific SQL code - * as it is used in the CREATE TABLE statement. - * - * change - * - * Associative array with the names of the fields to be changed as indexes - * of the array. Keep in mind that if it is intended to change either the - * name of a field and any other properties, the change array entries - * should have the new names of the fields as array indexes. - * - * The value of each entry of the array should be set to another associative - * array with the properties of the fields to that are meant to be changed as - * array entries. These entries should be assigned to the new values of the - * respective properties. The properties of the fields should be the same - * as defined by the Metabase parser. - * - * Example - * array( - * 'name' => 'userlist', - * 'add' => array( - * 'quota' => array( - * 'type' => 'integer', - * 'unsigned' => 1 - * ) - * ), - * 'remove' => array( - * 'file_limit' => array(), - * 'time_limit' => array() - * ), - * 'change' => array( - * 'name' => array( - * 'length' => '20', - * 'definition' => array( - * 'type' => 'text', - * 'length' => 20, - * ), - * ) - * ), - * 'rename' => array( - * 'sex' => array( - * 'name' => 'gender', - * 'definition' => array( - * 'type' => 'text', - * 'length' => 1, - * 'default' => 'M', - * ), - * ) - * ) - * ) - * - * @param boolean $check indicates whether the function should just check if the DBMS driver - * can perform the requested table alterations if the value is true or - * actually perform them otherwise. - * @return void - */ - public function alterTable($name, array $changes, $check = false) - { - foreach ($changes as $changeName => $change) { - switch ($changeName) { - case 'add': - break; - case 'remove': - break; - case 'name': - case 'rename': - case 'change': - default: - throw SchemaException::alterTableChangeNotSupported($changeName); - } + if ( ! isset($tableColumn['name'])) { + $tableColumn['name'] = ''; } - - $query = ''; - if ( ! empty($changes['add']) && is_array($changes['add'])) { - foreach ($changes['add'] as $fieldName => $field) { - if ($query) { - $query .= ', '; + + // 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': + 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'; + } } - $query .= 'ADD ' . $this->getDeclaration($fieldName, $field); - } - } - - if ( ! empty($changes['remove']) && is_array($changes['remove'])) { - foreach ($changes['remove'] as $fieldName => $field) { - if ($query) { - $query .= ', '; + if ($fixed !== false) { + $fixed = true; } - $query .= 'DROP COLUMN ' . $fieldName; - } - } - - if ( ! $query) { - return false; + break; + case 'set': + $fixed = false; + $type = 'text'; + $type = 'integer'; //FIXME:??? + break; + case 'date': + $type = 'date'; + break; + case 'datetime': + case 'timestamp': + $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'; } - - return $this->conn->exec('ALTER TABLE ' . $name . ' ' . $query); - } - - /** - * {@inheritdoc} - */ - public function createSequence($seqName, $start = 1, $allocationSize = 1) - { - $seqcolName = 'seq_col'; - $query = 'CREATE TABLE ' . $seqName . ' (' . $seqcolName . - ' INT PRIMARY KEY CLUSTERED IDENTITY(' . $start . ', 1) NOT NULL)'; - - $res = $this->conn->exec($query); - - if ($start == 1) { - return true; - } - - try { - $query = 'SET IDENTITY_INSERT ' . $sequenceName . ' ON ' . - 'INSERT INTO ' . $sequenceName . ' (' . $seqcolName . ') VALUES ( ' . $start . ')'; - $res = $this->conn->exec($query); - } catch (Exception $e) { - $result = $this->conn->exec('DROP TABLE ' . $sequenceName); - } - return true; - } - - /** - * This function drops an existing sequence - * - * @param string $seqName name of the sequence to be dropped - * @return void - */ - public function dropSequenceSql($seqName) - { - return 'DROP TABLE ' . $seqName; - } - - /** - * lists all database sequences - * - * @param string|null $database - * @return array - */ - public function listSequences($database = null) - { - $query = "SELECT name FROM sysobjects WHERE xtype = 'U'"; - $tableNames = $this->conn->fetchColumn($query); - - return array_map(array($this->conn->formatter, 'fixSequenceName'), $tableNames); + + $def = array( + 'type' => $type, + 'length' => ((int) $tableColumn['LENGTH'] == 0) ? null : (int) $tableColumn['LENGTH'], + 'unsigned' => (bool) $unsigned, + 'fixed' => (bool) $fixed + ); + + // @todo + $options = array( + 'length' => ((int) $tableColumn['LENGTH'] == 0) ? null : (int) $tableColumn['LENGTH'], + 'unsigned' => (bool)$unsigned, + 'fixed' => (bool)$fixed, + 'default' => $tableColumn['COLUMN_DEF'] !== '(NULL)' ? $tableColumn['COLUMN_DEF'] : null, + 'notnull' => (bool) ($tableColumn['IS_NULLABLE'] != 'YES'), + 'scale' => $tableColumn['SCALE'], + 'precision' => $tableColumn['PRECISION'], + 'platformOptions' => array( + 'primary' => false, + 'unique' => false, + 'autoincrement' => false, + ), + ); + + return new Column($tableColumn['COLUMN_NAME'], \Doctrine\DBAL\Types\Type::getType($type), $options); } /** - * lists table constraints - * - * @param string $table database table name - * @return array + * @override */ - public function listTableColumns($table) + protected function _getPortableTableIndexesList($tableIndexRows, $tableName=null) { - $sql = 'EXEC sp_columns @table_name = ' . $table; - $result = $this->conn->fetchAssoc($sql); - $columns = array(); - - foreach ($result as $key => $val) { - $val = array_change_key_case($val, CASE_LOWER); - - if (strstr($val['type_name'], ' ')) { - list($type, $identity) = explode(' ', $val['type_name']); - } else { - $type = $val['type_name']; - $identity = ''; - } - - if ($type == 'varchar') { - $type .= '(' . $val['length'] . ')'; + $result = array(); + foreach($tableIndexRows AS $tableIndex) { + $indexName = $keyName = $tableIndex['index_name']; + if(strpos($tableIndex['index_description'], 'primary key') !== false) { + $keyName = 'primary'; } + $keyName = strtolower($keyName); - $val['type'] = $type; - $val['identity'] = $identity; - $decl = $this->conn->getDatabasePlatform()->getPortableDeclaration($val); - - $description = array( - 'name' => $val['column_name'], - 'ntype' => $type, - 'type' => $decl['type'][0], - 'alltypes' => $decl['type'], - 'length' => $decl['length'], - 'fixed' => $decl['fixed'], - 'unsigned' => $decl['unsigned'], - 'notnull' => (bool) (trim($val['is_nullable']) === 'NO'), - 'default' => $val['column_def'], - 'primary' => (strtolower($identity) == 'identity'), + $result[$keyName] = array( + 'name' => $indexName, + 'columns' => explode(', ', $tableIndex['index_keys']), + 'unique' => strpos($tableIndex['index_description'], 'unique') !== false, + 'primary' => strpos($tableIndex['index_description'], 'primary key') !== false, ); - $columns[$val['column_name']] = $description; } - return $columns; - } - - /** - * lists table constraints - * - * @param string $table database table name - * @return array - */ - public function listTableIndexes($table) - { - - } - - /** - * lists tables - * - * @param string|null $database - * @return array - */ - public function listTables($database = null) - { - $sql = "SELECT name FROM sysobjects WHERE type = 'U' AND name <> 'dtproperties' ORDER BY name"; + $indexes = array(); + foreach($result AS $indexKey => $data) { + $indexes[$indexKey] = new Index($data['name'], $data['columns'], $data['unique'], $data['primary']); + } - return $this->conn->fetchColumn($sql); + return $indexes; } /** - * lists all triggers - * - * @return array + * @override */ - public function listTriggers($database = null) + public function _getPortableTableForeignKeyDefinition($tableForeignKey) { - $query = "SELECT name FROM sysobjects WHERE xtype = 'TR'"; - - $result = $this->conn->fetchColumn($query); - - return $result; + 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']), + ) + ); } /** - * lists table triggers - * - * @param string $table database table name - * @return array + * @override */ - public function listTableTriggers($table) + protected function _getPortableTableDefinition($table) { - $table = $this->conn->quote($table, 'text'); - $query = "SELECT name FROM sysobjects WHERE xtype = 'TR' AND object_name(parent_obj) = " . $table; - - $result = $this->conn->fetchColumn($query); - - return $result; + return $table['name']; } /** - * lists table views - * - * @param string $table database table name - * @return array + * @override */ - public function listTableViews($table) + public function dropDatabase($name) { - $keyName = 'INDEX_NAME'; - $pkName = 'PK_NAME'; - if ($this->conn->getAttribute(Doctrine::ATTR_PORTABILITY) & Doctrine::PORTABILITY_FIX_CASE) { - if ($this->conn->getAttribute(Doctrine::ATTR_FIELD_CASE) == CASE_LOWER) { - $keyName = strtolower($keyName); - $pkName = strtolower($pkName); - } else { - $keyName = strtoupper($keyName); - $pkName = strtoupper($pkName); - } + try + { + return parent::dropDatabase($name); } - $table = $this->conn->quote($table, 'text'); - $query = 'EXEC sp_statistics @table_name = ' . $table; - $indexes = $this->conn->fetchColumn($query, $keyName); - - $query = 'EXEC sp_pkeys @table_name = ' . $table; - $pkAll = $this->conn->fetchColumn($query, $pkName); - - $result = array(); - - foreach ($indexes as $index) { - if ( ! in_array($index, $pkAll) && $index != null) { - $result[] = $this->conn->formatter->fixIndexName($index); - } + catch (\Exception $e) + { + print $e->getMessage(); } - - return $result; - } - - /** - * lists database views - * - * @param string|null $database - * @return array - */ - public function listViews($database = null) - { - $query = "SELECT name FROM sysobjects WHERE xtype = 'V'"; - - return $this->conn->fetchColumn($query); - } - - protected function _getPortableTableColumnDefinition($tableColumn) - { - return $column; } } \ No newline at end of file diff --git a/lib/Doctrine/DBAL/Schema/SqlsrvSchemaManager.php b/lib/Doctrine/DBAL/Schema/SqlsrvSchemaManager.php new file mode 100644 index 00000000000..fcddf1f7c02 --- /dev/null +++ b/lib/Doctrine/DBAL/Schema/SqlsrvSchemaManager.php @@ -0,0 +1,35 @@ +. + */ + +namespace Doctrine\DBAL\Schema; + +/** + * xxx + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @author Juozas Kaziukenas + * @version $Revision$ + * @since 2.0 + */ +class SqlsrvSchemaManager extends MsSqlSchemaManager +{ + +} \ No newline at end of file diff --git a/tests/Doctrine/Tests/DBAL/Platforms/MsSqlPlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/MsSqlPlatformTest.php index 1302be035a3..dcb2e0e58af 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/MsSqlPlatformTest.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/MsSqlPlatformTest.php @@ -16,13 +16,13 @@ public function createPlatform() public function getGenerateTableSql() { - return 'CREATE TABLE test (id INT AUTO_INCREMENT NOT NULL, test VARCHAR(255) DEFAULT NULL, PRIMARY KEY(id))'; + return 'CREATE TABLE test (id INT IDENTITY NOT NULL, test VARCHAR(255) DEFAULT NULL, PRIMARY KEY(id))'; } public function getGenerateTableWithMultiColumnUniqueIndexSql() { return array( - 'CREATE TABLE test (foo VARCHAR(255) DEFAULT NULL, bar VARCHAR(255) DEFAULT NULL, UNIQUE INDEX test_foo_bar_uniq (foo, bar))' + 'CREATE TABLE test (foo VARCHAR(255) DEFAULT NULL, bar VARCHAR(255) DEFAULT NULL, CONSTRAINT test_foo_bar_uniq UNIQUE (foo, bar))' ); } @@ -75,11 +75,11 @@ public function testGeneratesTypeDeclarationForIntegers() $this->_platform->getIntegerTypeDeclarationSQL(array()) ); $this->assertEquals( - 'INT AUTO_INCREMENT', + 'INT IDENTITY', $this->_platform->getIntegerTypeDeclarationSQL(array('autoincrement' => true) )); $this->assertEquals( - 'INT AUTO_INCREMENT', + 'INT IDENTITY', $this->_platform->getIntegerTypeDeclarationSQL( array('autoincrement' => true, 'primary' => true) ));