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