SQLServerPlatform.php 23 KB

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