PageRenderTime 51ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/Doctrine/DBAL/Platforms/MsSqlPlatform.php

http://github.com/doctrine/dbal
PHP | 853 lines | 486 code | 111 blank | 256 comment | 66 complexity | 326be52f99dd83755ceedc46d9b901be MD5 | raw file
Possible License(s): Unlicense
  1. <?php
  2. /*
  3. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  4. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  5. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  6. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  7. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  8. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  9. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  10. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  11. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  12. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  13. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  14. *
  15. * This software consists of voluntary contributions made by many individuals
  16. * and is licensed under the LGPL. For more information, see
  17. * <http://www.doctrine-project.org>.
  18. */
  19. namespace Doctrine\DBAL\Platforms;
  20. use Doctrine\DBAL\Schema\TableDiff;
  21. use Doctrine\DBAL\DBALException;
  22. use Doctrine\DBAL\Schema\Index,
  23. Doctrine\DBAL\Schema\Table;
  24. /**
  25. * The MsSqlPlatform provides the behavior, features and SQL dialect of the
  26. * MySQL database platform.
  27. *
  28. * @since 2.0
  29. * @author Roman Borschel <roman@code-factory.org>
  30. * @author Jonathan H. Wage <jonwage@gmail.com>
  31. * @author Benjamin Eberlei <kontakt@beberlei.de>
  32. * @todo Rename: MsSQLPlatform
  33. */
  34. class MsSqlPlatform extends AbstractPlatform
  35. {
  36. /**
  37. * {@inheritDoc}
  38. */
  39. public function getDateDiffExpression($date1, $date2)
  40. {
  41. return 'DATEDIFF(day, ' . $date2 . ',' . $date1 . ')';
  42. }
  43. public function getDateAddDaysExpression($date, $days)
  44. {
  45. return 'DATEADD(day, ' . $days . ', ' . $date . ')';
  46. }
  47. public function getDateSubDaysExpression($date, $days)
  48. {
  49. return 'DATEADD(day, -1 * ' . $days . ', ' . $date . ')';
  50. }
  51. public function getDateAddMonthExpression($date, $months)
  52. {
  53. return 'DATEADD(month, ' . $months . ', ' . $date . ')';
  54. }
  55. public function getDateSubMonthExpression($date, $months)
  56. {
  57. return 'DATEADD(month, -1 * ' . $months . ', ' . $date . ')';
  58. }
  59. /**
  60. * Whether the platform prefers identity columns for ID generation.
  61. * MsSql prefers "autoincrement" identity columns since sequences can only
  62. * be emulated with a table.
  63. *
  64. * @return boolean
  65. * @override
  66. */
  67. public function prefersIdentityColumns()
  68. {
  69. return true;
  70. }
  71. /**
  72. * Whether the platform supports identity columns.
  73. * MsSql supports this through AUTO_INCREMENT columns.
  74. *
  75. * @return boolean
  76. * @override
  77. */
  78. public function supportsIdentityColumns()
  79. {
  80. return true;
  81. }
  82. /**
  83. * Whether the platform supports releasing savepoints.
  84. *
  85. * @return boolean
  86. */
  87. public function supportsReleaseSavepoints()
  88. {
  89. return false;
  90. }
  91. /**
  92. * create a new database
  93. *
  94. * @param string $name name of the database that should be created
  95. * @return string
  96. * @override
  97. */
  98. public function getCreateDatabaseSQL($name)
  99. {
  100. return 'CREATE DATABASE ' . $name;
  101. }
  102. /**
  103. * drop an existing database
  104. *
  105. * @param string $name name of the database that should be dropped
  106. * @return string
  107. * @override
  108. */
  109. public function getDropDatabaseSQL($name)
  110. {
  111. return 'DROP DATABASE ' . $name;
  112. }
  113. /**
  114. * @override
  115. */
  116. public function supportsCreateDropDatabase()
  117. {
  118. return false;
  119. }
  120. /**
  121. * @override
  122. */
  123. public function getDropForeignKeySQL($foreignKey, $table)
  124. {
  125. if ($foreignKey instanceof \Doctrine\DBAL\Schema\ForeignKeyConstraint) {
  126. $foreignKey = $foreignKey->getQuotedName($this);
  127. }
  128. if ($table instanceof \Doctrine\DBAL\Schema\Table) {
  129. $table = $table->getQuotedName($this);
  130. }
  131. return 'ALTER TABLE ' . $table . ' DROP CONSTRAINT ' . $foreignKey;
  132. }
  133. /**
  134. * @override
  135. */
  136. public function getDropIndexSQL($index, $table=null)
  137. {
  138. if ($index instanceof \Doctrine\DBAL\Schema\Index) {
  139. $index_ = $index;
  140. $index = $index->getQuotedName($this);
  141. } else if (!is_string($index)) {
  142. throw new \InvalidArgumentException('AbstractPlatform::getDropIndexSQL() expects $index parameter to be string or \Doctrine\DBAL\Schema\Index.');
  143. }
  144. if (!isset($table)) {
  145. return 'DROP INDEX ' . $index;
  146. } else {
  147. if ($table instanceof \Doctrine\DBAL\Schema\Table) {
  148. $table = $table->getQuotedName($this);
  149. }
  150. return "IF EXISTS (SELECT * FROM sysobjects WHERE name = '$index')
  151. ALTER TABLE " . $table . " DROP CONSTRAINT " . $index . "
  152. ELSE
  153. DROP INDEX " . $index . " ON " . $table;
  154. }
  155. }
  156. /**
  157. * @override
  158. */
  159. protected function _getCreateTableSQL($tableName, array $columns, array $options = array())
  160. {
  161. // @todo does other code breaks because of this?
  162. // foce primary keys to be not null
  163. foreach ($columns as &$column) {
  164. if (isset($column['primary']) && $column['primary']) {
  165. $column['notnull'] = true;
  166. }
  167. }
  168. $columnListSql = $this->getColumnDeclarationListSQL($columns);
  169. if (isset($options['uniqueConstraints']) && !empty($options['uniqueConstraints'])) {
  170. foreach ($options['uniqueConstraints'] as $name => $definition) {
  171. $columnListSql .= ', ' . $this->getUniqueConstraintDeclarationSQL($name, $definition);
  172. }
  173. }
  174. if (isset($options['primary']) && !empty($options['primary'])) {
  175. $columnListSql .= ', PRIMARY KEY(' . implode(', ', array_unique(array_values($options['primary']))) . ')';
  176. }
  177. $query = 'CREATE TABLE ' . $tableName . ' (' . $columnListSql;
  178. $check = $this->getCheckDeclarationSQL($columns);
  179. if (!empty($check)) {
  180. $query .= ', ' . $check;
  181. }
  182. $query .= ')';
  183. $sql[] = $query;
  184. if (isset($options['indexes']) && !empty($options['indexes'])) {
  185. foreach ($options['indexes'] AS $index) {
  186. $sql[] = $this->getCreateIndexSQL($index, $tableName);
  187. }
  188. }
  189. if (isset($options['foreignKeys'])) {
  190. foreach ((array) $options['foreignKeys'] AS $definition) {
  191. $sql[] = $this->getCreateForeignKeySQL($definition, $tableName);
  192. }
  193. }
  194. return $sql;
  195. }
  196. /**
  197. * @override
  198. */
  199. public function getUniqueConstraintDeclarationSQL($name, Index $index)
  200. {
  201. $constraint = parent::getUniqueConstraintDeclarationSQL($name, $index);
  202. $constraint = $this->_appendUniqueConstraintDefinition($constraint, $index);
  203. return $constraint;
  204. }
  205. /**
  206. * @override
  207. */
  208. public function getCreateIndexSQL(Index $index, $table)
  209. {
  210. $constraint = parent::getCreateIndexSQL($index, $table);
  211. if ($index->isUnique()) {
  212. $constraint = $this->_appendUniqueConstraintDefinition($constraint, $index);
  213. }
  214. return $constraint;
  215. }
  216. /**
  217. * Extend unique key constraint with required filters
  218. *
  219. * @param string $sql
  220. * @param Index $index
  221. * @return string
  222. */
  223. private function _appendUniqueConstraintDefinition($sql, Index $index)
  224. {
  225. $fields = array();
  226. foreach ($index->getColumns() as $field => $definition) {
  227. if (!is_array($definition)) {
  228. $field = $definition;
  229. }
  230. $fields[] = $field . ' IS NOT NULL';
  231. }
  232. return $sql . ' WHERE ' . implode(' AND ', $fields);
  233. }
  234. /**
  235. * @override
  236. */
  237. public function getAlterTableSQL(TableDiff $diff)
  238. {
  239. $queryParts = array();
  240. $sql = array();
  241. $columnSql = array();
  242. if ($diff->newName !== false) {
  243. $queryParts[] = 'RENAME TO ' . $diff->newName;
  244. }
  245. foreach ($diff->addedColumns AS $fieldName => $column) {
  246. if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) {
  247. continue;
  248. }
  249. $queryParts[] = 'ADD ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $column->toArray());
  250. }
  251. foreach ($diff->removedColumns AS $column) {
  252. if ($this->onSchemaAlterTableRemoveColumn($column, $diff, $columnSql)) {
  253. continue;
  254. }
  255. $queryParts[] = 'DROP COLUMN ' . $column->getQuotedName($this);
  256. }
  257. foreach ($diff->changedColumns AS $columnDiff) {
  258. if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) {
  259. continue;
  260. }
  261. /* @var $columnDiff Doctrine\DBAL\Schema\ColumnDiff */
  262. $column = $columnDiff->column;
  263. $queryParts[] = 'ALTER COLUMN ' .
  264. $this->getColumnDeclarationSQL($column->getQuotedName($this), $column->toArray());
  265. }
  266. foreach ($diff->renamedColumns AS $oldColumnName => $column) {
  267. if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) {
  268. continue;
  269. }
  270. $sql[] = "sp_RENAME '". $diff->name. ".". $oldColumnName . "' , '".$column->getQuotedName($this)."', 'COLUMN'";
  271. $queryParts[] = 'ALTER COLUMN ' .
  272. $this->getColumnDeclarationSQL($column->getQuotedName($this), $column->toArray());
  273. }
  274. $tableSql = array();
  275. if ($this->onSchemaAlterTable($diff, $tableSql)) {
  276. return array_merge($tableSql, $columnSql);
  277. }
  278. foreach ($queryParts as $query) {
  279. $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . $query;
  280. }
  281. $sql = array_merge($sql, $this->_getAlterTableIndexForeignKeySQL($diff));
  282. return array_merge($sql, $tableSql, $columnSql);
  283. }
  284. /**
  285. * @override
  286. */
  287. public function getEmptyIdentityInsertSQL($quotedTableName, $quotedIdentifierColumnName)
  288. {
  289. return 'INSERT INTO ' . $quotedTableName . ' DEFAULT VALUES';
  290. }
  291. /**
  292. * @override
  293. */
  294. public function getShowDatabasesSQL()
  295. {
  296. return 'SHOW DATABASES';
  297. }
  298. /**
  299. * @override
  300. */
  301. public function getListTablesSQL()
  302. {
  303. // "sysdiagrams" table must be ignored as it's internal SQL Server table for Database Diagrams
  304. return "SELECT name FROM sysobjects WHERE type = 'U' AND name != 'sysdiagrams' ORDER BY name";
  305. }
  306. /**
  307. * @override
  308. */
  309. public function getListTableColumnsSQL($table, $database = null)
  310. {
  311. return "exec sp_columns @table_name = '" . $table . "'";
  312. }
  313. /**
  314. * @override
  315. */
  316. public function getListTableForeignKeysSQL($table, $database = null)
  317. {
  318. return "SELECT f.name AS ForeignKey,
  319. SCHEMA_NAME (f.SCHEMA_ID) AS SchemaName,
  320. OBJECT_NAME (f.parent_object_id) AS TableName,
  321. COL_NAME (fc.parent_object_id,fc.parent_column_id) AS ColumnName,
  322. SCHEMA_NAME (o.SCHEMA_ID) ReferenceSchemaName,
  323. OBJECT_NAME (f.referenced_object_id) AS ReferenceTableName,
  324. COL_NAME(fc.referenced_object_id,fc.referenced_column_id) AS ReferenceColumnName,
  325. f.delete_referential_action_desc,
  326. f.update_referential_action_desc
  327. FROM sys.foreign_keys AS f
  328. INNER JOIN sys.foreign_key_columns AS fc
  329. INNER JOIN sys.objects AS o ON o.OBJECT_ID = fc.referenced_object_id
  330. ON f.OBJECT_ID = fc.constraint_object_id
  331. WHERE OBJECT_NAME (f.parent_object_id) = '" . $table . "'";
  332. }
  333. /**
  334. * @override
  335. */
  336. public function getListTableIndexesSQL($table, $currentDatabase = null)
  337. {
  338. return "exec sp_helpindex '" . $table . "'";
  339. }
  340. /**
  341. * @override
  342. */
  343. public function getCreateViewSQL($name, $sql)
  344. {
  345. return 'CREATE VIEW ' . $name . ' AS ' . $sql;
  346. }
  347. /**
  348. * @override
  349. */
  350. public function getListViewsSQL($database)
  351. {
  352. return "SELECT name FROM sysobjects WHERE type = 'V' ORDER BY name";
  353. }
  354. /**
  355. * @override
  356. */
  357. public function getDropViewSQL($name)
  358. {
  359. return 'DROP VIEW ' . $name;
  360. }
  361. /**
  362. * Returns the regular expression operator.
  363. *
  364. * @return string
  365. * @override
  366. */
  367. public function getRegexpExpression()
  368. {
  369. return 'RLIKE';
  370. }
  371. /**
  372. * Returns global unique identifier
  373. *
  374. * @return string to get global unique identifier
  375. * @override
  376. */
  377. public function getGuidExpression()
  378. {
  379. return 'UUID()';
  380. }
  381. /**
  382. * @override
  383. */
  384. public function getLocateExpression($str, $substr, $startPos = false)
  385. {
  386. if ($startPos == false) {
  387. return 'CHARINDEX(' . $substr . ', ' . $str . ')';
  388. } else {
  389. return 'CHARINDEX(' . $substr . ', ' . $str . ', ' . $startPos . ')';
  390. }
  391. }
  392. /**
  393. * @override
  394. */
  395. public function getModExpression($expression1, $expression2)
  396. {
  397. return $expression1 . ' % ' . $expression2;
  398. }
  399. /**
  400. * @override
  401. */
  402. public function getTrimExpression($str, $pos = self::TRIM_UNSPECIFIED, $char = false)
  403. {
  404. $trimFn = '';
  405. if (!$char) {
  406. if ($pos == self::TRIM_LEADING) {
  407. $trimFn = 'LTRIM';
  408. } else if ($pos == self::TRIM_TRAILING) {
  409. $trimFn = 'RTRIM';
  410. } else {
  411. return 'LTRIM(RTRIM(' . $str . '))';
  412. }
  413. return $trimFn . '(' . $str . ')';
  414. } else {
  415. /** Original query used to get those expressions
  416. declare @c varchar(100) = 'xxxBarxxx', @trim_char char(1) = 'x';
  417. declare @pat varchar(10) = '%[^' + @trim_char + ']%';
  418. select @c as string
  419. , @trim_char as trim_char
  420. , stuff(@c, 1, patindex(@pat, @c) - 1, null) as trim_leading
  421. , reverse(stuff(reverse(@c), 1, patindex(@pat, reverse(@c)) - 1, null)) as trim_trailing
  422. , reverse(stuff(reverse(stuff(@c, 1, patindex(@pat, @c) - 1, null)), 1, patindex(@pat, reverse(stuff(@c, 1, patindex(@pat, @c) - 1, null))) - 1, null)) as trim_both;
  423. */
  424. $pattern = "'%[^' + $char + ']%'";
  425. if ($pos == self::TRIM_LEADING) {
  426. return 'stuff(' . $str . ', 1, patindex(' . $pattern . ', ' . $str . ') - 1, null)';
  427. } else if ($pos == self::TRIM_TRAILING) {
  428. return 'reverse(stuff(reverse(' . $str . '), 1, patindex(' . $pattern . ', reverse(' . $str . ')) - 1, null))';
  429. } else {
  430. return 'reverse(stuff(reverse(stuff(' . $str . ', 1, patindex(' . $pattern . ', ' . $str . ') - 1, null)), 1, patindex(' . $pattern . ', reverse(stuff(' . $str . ', 1, patindex(' . $pattern . ', ' . $str . ') - 1, null))) - 1, null))';
  431. }
  432. }
  433. }
  434. /**
  435. * @override
  436. */
  437. public function getConcatExpression()
  438. {
  439. $args = func_get_args();
  440. return '(' . implode(' + ', $args) . ')';
  441. }
  442. public function getListDatabasesSQL()
  443. {
  444. return 'SELECT * FROM SYS.DATABASES';
  445. }
  446. /**
  447. * @override
  448. */
  449. public function getSubstringExpression($value, $from, $len = null)
  450. {
  451. if (!is_null($len)) {
  452. return 'SUBSTRING(' . $value . ', ' . $from . ', ' . $len . ')';
  453. }
  454. return 'SUBSTRING(' . $value . ', ' . $from . ', LEN(' . $value . ') - ' . $from . ' + 1)';
  455. }
  456. /**
  457. * @override
  458. */
  459. public function getLengthExpression($column)
  460. {
  461. return 'LEN(' . $column . ')';
  462. }
  463. /**
  464. * @override
  465. */
  466. public function getSetTransactionIsolationSQL($level)
  467. {
  468. return 'SET TRANSACTION ISOLATION LEVEL ' . $this->_getTransactionIsolationLevelSQL($level);
  469. }
  470. /**
  471. * @override
  472. */
  473. public function getIntegerTypeDeclarationSQL(array $field)
  474. {
  475. return 'INT' . $this->_getCommonIntegerTypeDeclarationSQL($field);
  476. }
  477. /**
  478. * @override
  479. */
  480. public function getBigIntTypeDeclarationSQL(array $field)
  481. {
  482. return 'BIGINT' . $this->_getCommonIntegerTypeDeclarationSQL($field);
  483. }
  484. /**
  485. * @override
  486. */
  487. public function getSmallIntTypeDeclarationSQL(array $field)
  488. {
  489. return 'SMALLINT' . $this->_getCommonIntegerTypeDeclarationSQL($field);
  490. }
  491. /** @override */
  492. protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed)
  493. {
  494. return $fixed ? ($length ? 'NCHAR(' . $length . ')' : 'CHAR(255)') : ($length ? 'NVARCHAR(' . $length . ')' : 'NVARCHAR(255)');
  495. }
  496. /** @override */
  497. public function getClobTypeDeclarationSQL(array $field)
  498. {
  499. return 'TEXT';
  500. }
  501. /**
  502. * @override
  503. */
  504. protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef)
  505. {
  506. $autoinc = '';
  507. if (!empty($columnDef['autoincrement'])) {
  508. $autoinc = ' IDENTITY';
  509. }
  510. $unsigned = (isset($columnDef['unsigned']) && $columnDef['unsigned']) ? ' UNSIGNED' : '';
  511. return $unsigned . $autoinc;
  512. }
  513. /**
  514. * @override
  515. */
  516. public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration)
  517. {
  518. // 6 - microseconds precision length
  519. return 'DATETIME2(6)';
  520. }
  521. /**
  522. * @override
  523. */
  524. public function getDateTypeDeclarationSQL(array $fieldDeclaration)
  525. {
  526. return 'DATE';
  527. }
  528. /**
  529. * @override
  530. */
  531. public function getTimeTypeDeclarationSQL(array $fieldDeclaration)
  532. {
  533. return 'TIME(0)';
  534. }
  535. /**
  536. * @override
  537. */
  538. public function getBooleanTypeDeclarationSQL(array $field)
  539. {
  540. return 'BIT';
  541. }
  542. /**
  543. * Adds an adapter-specific LIMIT clause to the SELECT statement.
  544. *
  545. * @param string $query
  546. * @param mixed $limit
  547. * @param mixed $offset
  548. * @link http://lists.bestpractical.com/pipermail/rt-devel/2005-June/007339.html
  549. * @return string
  550. */
  551. protected function doModifyLimitQuery($query, $limit, $offset = null)
  552. {
  553. if ($limit > 0) {
  554. $count = intval($limit);
  555. $offset = intval($offset);
  556. if ($offset < 0) {
  557. throw new DBALException("LIMIT argument offset=$offset is not valid");
  558. }
  559. if ($offset == 0) {
  560. $query = preg_replace('/^SELECT\s/i', 'SELECT TOP ' . $count . ' ', $query);
  561. } else {
  562. $orderby = stristr($query, 'ORDER BY');
  563. if (!$orderby) {
  564. $over = 'ORDER BY (SELECT 0)';
  565. } else {
  566. $over = preg_replace('/\"[^,]*\".\"([^,]*)\"/i', '"inner_tbl"."$1"', $orderby);
  567. }
  568. // Remove ORDER BY clause from $query
  569. $query = preg_replace('/\s+ORDER BY(.*)/', '', $query);
  570. $query = preg_replace('/^SELECT\s/', '', $query);
  571. $start = $offset + 1;
  572. $end = $offset + $count;
  573. $query = "SELECT * FROM (SELECT ROW_NUMBER() OVER ($over) AS \"doctrine_rownum\", $query) AS doctrine_tbl WHERE \"doctrine_rownum\" BETWEEN $start AND $end";
  574. }
  575. }
  576. return $query;
  577. }
  578. /**
  579. * @override
  580. */
  581. public function convertBooleans($item)
  582. {
  583. if (is_array($item)) {
  584. foreach ($item as $key => $value) {
  585. if (is_bool($value) || is_numeric($item)) {
  586. $item[$key] = ($value) ? 1 : 0;
  587. }
  588. }
  589. } else {
  590. if (is_bool($item) || is_numeric($item)) {
  591. $item = ($item) ? 1 : 0;
  592. }
  593. }
  594. return $item;
  595. }
  596. /**
  597. * @override
  598. */
  599. public function getCreateTemporaryTableSnippetSQL()
  600. {
  601. return "CREATE TABLE";
  602. }
  603. /**
  604. * @override
  605. */
  606. public function getTemporaryTableName($tableName)
  607. {
  608. return '#' . $tableName;
  609. }
  610. /**
  611. * @override
  612. */
  613. public function getDateTimeFormatString()
  614. {
  615. return 'Y-m-d H:i:s.u';
  616. }
  617. /**
  618. * @override
  619. */
  620. public function getDateTimeTzFormatString()
  621. {
  622. return $this->getDateTimeFormatString();
  623. }
  624. /**
  625. * Get the platform name for this instance
  626. *
  627. * @return string
  628. */
  629. public function getName()
  630. {
  631. return 'mssql';
  632. }
  633. /**
  634. * @override
  635. */
  636. protected function initializeDoctrineTypeMappings()
  637. {
  638. $this->doctrineTypeMapping = array(
  639. 'bigint' => 'bigint',
  640. 'numeric' => 'decimal',
  641. 'bit' => 'boolean',
  642. 'smallint' => 'smallint',
  643. 'decimal' => 'decimal',
  644. 'smallmoney' => 'integer',
  645. 'int' => 'integer',
  646. 'tinyint' => 'smallint',
  647. 'money' => 'integer',
  648. 'float' => 'float',
  649. 'real' => 'float',
  650. 'double' => 'float',
  651. 'double precision' => 'float',
  652. 'date' => 'date',
  653. 'datetimeoffset' => 'datetimetz',
  654. 'datetime2' => 'datetime',
  655. 'smalldatetime' => 'datetime',
  656. 'datetime' => 'datetime',
  657. 'time' => 'time',
  658. 'char' => 'string',
  659. 'varchar' => 'string',
  660. 'text' => 'text',
  661. 'nchar' => 'string',
  662. 'nvarchar' => 'string',
  663. 'ntext' => 'text',
  664. 'binary' => 'text',
  665. 'varbinary' => 'text',
  666. 'image' => 'text',
  667. );
  668. }
  669. /**
  670. * Generate SQL to create a new savepoint
  671. *
  672. * @param string $savepoint
  673. * @return string
  674. */
  675. public function createSavePoint($savepoint)
  676. {
  677. return 'SAVE TRANSACTION ' . $savepoint;
  678. }
  679. /**
  680. * Generate SQL to release a savepoint
  681. *
  682. * @param string $savepoint
  683. * @return string
  684. */
  685. public function releaseSavePoint($savepoint)
  686. {
  687. return '';
  688. }
  689. /**
  690. * Generate SQL to rollback a savepoint
  691. *
  692. * @param string $savepoint
  693. * @return string
  694. */
  695. public function rollbackSavePoint($savepoint)
  696. {
  697. return 'ROLLBACK TRANSACTION ' . $savepoint;
  698. }
  699. /**
  700. * @override
  701. */
  702. public function appendLockHint($fromClause, $lockMode)
  703. {
  704. // @todo coorect
  705. if ($lockMode == \Doctrine\DBAL\LockMode::PESSIMISTIC_READ) {
  706. return $fromClause . ' WITH (tablockx)';
  707. } else if ($lockMode == \Doctrine\DBAL\LockMode::PESSIMISTIC_WRITE) {
  708. return $fromClause . ' WITH (tablockx)';
  709. } else {
  710. return $fromClause;
  711. }
  712. }
  713. /**
  714. * @override
  715. */
  716. public function getForUpdateSQL()
  717. {
  718. return ' ';
  719. }
  720. protected function getReservedKeywordsClass()
  721. {
  722. return 'Doctrine\DBAL\Platforms\Keywords\MsSQLKeywords';
  723. }
  724. /**
  725. * {@inheritDoc}
  726. */
  727. public function quoteSingleIdentifier($str)
  728. {
  729. return "[" . str_replace("]", "][", $str) . "]";
  730. }
  731. public function getTruncateTableSQL($tableName, $cascade = false)
  732. {
  733. return 'TRUNCATE TABLE '.$tableName;
  734. }
  735. /**
  736. * Gets the SQL Snippet used to declare a BLOB column type.
  737. */
  738. public function getBlobTypeDeclarationSQL(array $field)
  739. {
  740. return 'VARBINARY(MAX)';
  741. }
  742. }