SQLServerSchemaManagerTest.php 17.8 KB
Newer Older
1 2 3 4
<?php

namespace Doctrine\Tests\DBAL\Functional\Schema;

jeroendedauw's avatar
jeroendedauw committed
5 6
use Doctrine\DBAL\Schema\Column;
use Doctrine\DBAL\Schema\ColumnDiff;
7 8 9
use Doctrine\DBAL\Schema\Table;
use Doctrine\DBAL\Schema\TableDiff;
use Doctrine\DBAL\Types\Type;
10
use function current;
11 12 13

class SQLServerSchemaManagerTest extends SchemaManagerFunctionalTestCase
{
14
    protected function getPlatformName() : string
15
    {
Sergei Morozov's avatar
Sergei Morozov committed
16
        return 'mssql';
17
    }
18 19 20 21

    /**
     * @group DBAL-255
     */
22
    public function testDropColumnConstraints() : void
23 24 25
    {
        $table = new Table('sqlsrv_drop_column');
        $table->addColumn('id', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
26
        $table->addColumn('todrop', 'decimal', ['default' => 10.2]);
27

Sergei Morozov's avatar
Sergei Morozov committed
28
        $this->schemaManager->createTable($table);
29

Sergei Morozov's avatar
Sergei Morozov committed
30
        $diff = new TableDiff('sqlsrv_drop_column', [], [], [new Column('todrop', Type::getType('decimal'))]);
Sergei Morozov's avatar
Sergei Morozov committed
31
        $this->schemaManager->alterTable($diff);
32

Sergei Morozov's avatar
Sergei Morozov committed
33
        $columns = $this->schemaManager->listTableColumns('sqlsrv_drop_column');
Gabriel Caruso's avatar
Gabriel Caruso committed
34
        self::assertCount(1, $columns);
35
    }
36

37
    public function testColumnCollation() : void
38
    {
Sergei Morozov's avatar
Sergei Morozov committed
39
        $table  = new Table($tableName = 'test_collation');
40 41
        $column = $table->addColumn($columnName = 'test', 'string');

Sergei Morozov's avatar
Sergei Morozov committed
42 43
        $this->schemaManager->dropAndCreateTable($table);
        $columns = $this->schemaManager->listTableColumns($tableName);
44

45
        self::assertTrue($columns[$columnName]->hasPlatformOption('collation')); // SQL Server should report a default collation on the column
46

47
        $column->setPlatformOption('collation', $collation = 'Icelandic_CS_AS');
48

Sergei Morozov's avatar
Sergei Morozov committed
49 50
        $this->schemaManager->dropAndCreateTable($table);
        $columns = $this->schemaManager->listTableColumns($tableName);
51

52
        self::assertEquals($collation, $columns[$columnName]->getPlatformOption('collation'));
53
    }
54

55
    public function testDefaultConstraints() : void
56
    {
57
        $table = new Table('sqlsrv_default_constraints');
58
        $table->addColumn('no_default', 'string');
Sergei Morozov's avatar
Sergei Morozov committed
59 60 61 62 63 64
        $table->addColumn('df_integer', 'integer', ['default' => 666]);
        $table->addColumn('df_string_1', 'string', ['default' => 'foobar']);
        $table->addColumn('df_string_2', 'string', ['default' => 'Doctrine rocks!!!']);
        $table->addColumn('df_string_3', 'string', ['default' => 'another default value']);
        $table->addColumn('df_string_4', 'string', ['default' => 'column to rename']);
        $table->addColumn('df_boolean', 'boolean', ['default' => true]);
65

Sergei Morozov's avatar
Sergei Morozov committed
66 67
        $this->schemaManager->createTable($table);
        $columns = $this->schemaManager->listTableColumns('sqlsrv_default_constraints');
68

69 70 71 72 73 74
        self::assertNull($columns['no_default']->getDefault());
        self::assertEquals(666, $columns['df_integer']->getDefault());
        self::assertEquals('foobar', $columns['df_string_1']->getDefault());
        self::assertEquals('Doctrine rocks!!!', $columns['df_string_2']->getDefault());
        self::assertEquals('another default value', $columns['df_string_3']->getDefault());
        self::assertEquals(1, $columns['df_boolean']->getDefault());
75

Sergei Morozov's avatar
Sergei Morozov committed
76
        $diff                                = new TableDiff(
77
            'sqlsrv_default_constraints',
78
            [],
Sergei Morozov's avatar
Sergei Morozov committed
79
            [
80 81
                'df_integer' => new ColumnDiff(
                    'df_integer',
Sergei Morozov's avatar
Sergei Morozov committed
82 83 84
                    new Column('df_integer', Type::getType('integer'), ['default' => 0]),
                    ['default'],
                    new Column('df_integer', Type::getType('integer'), ['default' => 666])
85 86 87 88
                ),
                'df_string_2' => new ColumnDiff(
                    'df_string_2',
                    new Column('df_string_2', Type::getType('string')),
Sergei Morozov's avatar
Sergei Morozov committed
89 90
                    ['default'],
                    new Column('df_string_2', Type::getType('string'), ['default' => 'Doctrine rocks!!!'])
91 92 93
                ),
                'df_string_3' => new ColumnDiff(
                    'df_string_3',
Sergei Morozov's avatar
Sergei Morozov committed
94 95 96
                    new Column('df_string_3', Type::getType('string'), ['length' => 50, 'default' => 'another default value']),
                    ['length'],
                    new Column('df_string_3', Type::getType('string'), ['length' => 50, 'default' => 'another default value'])
97 98 99
                ),
                'df_boolean' => new ColumnDiff(
                    'df_boolean',
Sergei Morozov's avatar
Sergei Morozov committed
100 101 102 103 104 105 106 107 108 109 110
                    new Column('df_boolean', Type::getType('boolean'), ['default' => false]),
                    ['default'],
                    new Column('df_boolean', Type::getType('boolean'), ['default' => true])
                ),
            ],
            [
                'df_string_1' => new Column('df_string_1', Type::getType('string')),
            ],
            [],
            [],
            [],
111 112
            $table
        );
Sergei Morozov's avatar
Sergei Morozov committed
113
        $diff->newName                       = 'sqlsrv_default_constraints';
114 115 116
        $diff->renamedColumns['df_string_4'] = new Column(
            'df_string_renamed',
            Type::getType('string'),
Sergei Morozov's avatar
Sergei Morozov committed
117
            ['default' => 'column to rename']
118 119
        );

Sergei Morozov's avatar
Sergei Morozov committed
120 121
        $this->schemaManager->alterTable($diff);
        $columns = $this->schemaManager->listTableColumns('sqlsrv_default_constraints');
122

123 124 125 126 127 128
        self::assertNull($columns['no_default']->getDefault());
        self::assertEquals(0, $columns['df_integer']->getDefault());
        self::assertNull($columns['df_string_2']->getDefault());
        self::assertEquals('another default value', $columns['df_string_3']->getDefault());
        self::assertEquals(0, $columns['df_boolean']->getDefault());
        self::assertEquals('column to rename', $columns['df_string_renamed']->getDefault());
129 130 131 132 133 134

        /**
         * Test that column default constraints can still be referenced after table rename
         */
        $diff = new TableDiff(
            'sqlsrv_default_constraints',
Sergei Morozov's avatar
Sergei Morozov committed
135 136
            [],
            [
137 138
                'df_integer' => new ColumnDiff(
                    'df_integer',
Sergei Morozov's avatar
Sergei Morozov committed
139 140 141 142 143 144 145 146 147
                    new Column('df_integer', Type::getType('integer'), ['default' => 666]),
                    ['default'],
                    new Column('df_integer', Type::getType('integer'), ['default' => 0])
                ),
            ],
            [],
            [],
            [],
            [],
148 149 150
            $table
        );

Sergei Morozov's avatar
Sergei Morozov committed
151 152
        $this->schemaManager->alterTable($diff);
        $columns = $this->schemaManager->listTableColumns('sqlsrv_default_constraints');
153

154
        self::assertEquals(666, $columns['df_integer']->getDefault());
155
    }
156 157 158 159

    /**
     * @group DBAL-543
     */
160
    public function testColumnComments() : void
161 162
    {
        $table = new Table('sqlsrv_column_comment');
Sergei Morozov's avatar
Sergei Morozov committed
163 164 165 166 167 168 169 170 171 172
        $table->addColumn('id', 'integer', ['autoincrement' => true]);
        $table->addColumn('comment_null', 'integer', ['comment' => null]);
        $table->addColumn('comment_false', 'integer', ['comment' => false]);
        $table->addColumn('comment_empty_string', 'integer', ['comment' => '']);
        $table->addColumn('comment_integer_0', 'integer', ['comment' => 0]);
        $table->addColumn('comment_float_0', 'integer', ['comment' => 0.0]);
        $table->addColumn('comment_string_0', 'integer', ['comment' => '0']);
        $table->addColumn('comment', 'integer', ['comment' => 'Doctrine 0wnz you!']);
        $table->addColumn('`comment_quoted`', 'integer', ['comment' => 'Doctrine 0wnz comments for explicitly quoted columns!']);
        $table->addColumn('create', 'integer', ['comment' => 'Doctrine 0wnz comments for reserved keyword columns!']);
173
        $table->addColumn('commented_type', 'object');
Sergei Morozov's avatar
Sergei Morozov committed
174 175
        $table->addColumn('commented_type_with_comment', 'array', ['comment' => 'Doctrine array type.']);
        $table->setPrimaryKey(['id']);
176

Sergei Morozov's avatar
Sergei Morozov committed
177
        $this->schemaManager->createTable($table);
178

Sergei Morozov's avatar
Sergei Morozov committed
179
        $columns = $this->schemaManager->listTableColumns('sqlsrv_column_comment');
Gabriel Caruso's avatar
Gabriel Caruso committed
180
        self::assertCount(12, $columns);
181 182 183 184 185 186 187 188 189 190 191 192
        self::assertNull($columns['id']->getComment());
        self::assertNull($columns['comment_null']->getComment());
        self::assertNull($columns['comment_false']->getComment());
        self::assertNull($columns['comment_empty_string']->getComment());
        self::assertEquals('0', $columns['comment_integer_0']->getComment());
        self::assertEquals('0', $columns['comment_float_0']->getComment());
        self::assertEquals('0', $columns['comment_string_0']->getComment());
        self::assertEquals('Doctrine 0wnz you!', $columns['comment']->getComment());
        self::assertEquals('Doctrine 0wnz comments for explicitly quoted columns!', $columns['comment_quoted']->getComment());
        self::assertEquals('Doctrine 0wnz comments for reserved keyword columns!', $columns['[create]']->getComment());
        self::assertNull($columns['commented_type']->getComment());
        self::assertEquals('Doctrine array type.', $columns['commented_type_with_comment']->getComment());
193

Sergei Morozov's avatar
Sergei Morozov committed
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
        $tableDiff                                                    = new TableDiff('sqlsrv_column_comment');
        $tableDiff->fromTable                                         = $table;
        $tableDiff->addedColumns['added_comment_none']                = new Column('added_comment_none', Type::getType('integer'));
        $tableDiff->addedColumns['added_comment_null']                = new Column('added_comment_null', Type::getType('integer'), ['comment' => null]);
        $tableDiff->addedColumns['added_comment_false']               = new Column('added_comment_false', Type::getType('integer'), ['comment' => false]);
        $tableDiff->addedColumns['added_comment_empty_string']        = new Column('added_comment_empty_string', Type::getType('integer'), ['comment' => '']);
        $tableDiff->addedColumns['added_comment_integer_0']           = new Column('added_comment_integer_0', Type::getType('integer'), ['comment' => 0]);
        $tableDiff->addedColumns['added_comment_float_0']             = new Column('added_comment_float_0', Type::getType('integer'), ['comment' => 0.0]);
        $tableDiff->addedColumns['added_comment_string_0']            = new Column('added_comment_string_0', Type::getType('integer'), ['comment' => '0']);
        $tableDiff->addedColumns['added_comment']                     = new Column('added_comment', Type::getType('integer'), ['comment' => 'Doctrine']);
        $tableDiff->addedColumns['`added_comment_quoted`']            = new Column('`added_comment_quoted`', Type::getType('integer'), ['comment' => 'rulez']);
        $tableDiff->addedColumns['select']                            = new Column('select', Type::getType('integer'), ['comment' => '666']);
        $tableDiff->addedColumns['added_commented_type']              = new Column('added_commented_type', Type::getType('object'));
        $tableDiff->addedColumns['added_commented_type_with_comment'] = new Column('added_commented_type_with_comment', Type::getType('array'), ['comment' => '666']);

        $tableDiff->renamedColumns['comment_float_0'] = new Column('comment_double_0', Type::getType('decimal'), ['comment' => 'Double for real!']);
210 211 212 213

        // Add comment to non-commented column.
        $tableDiff->changedColumns['id'] = new ColumnDiff(
            'id',
Sergei Morozov's avatar
Sergei Morozov committed
214 215 216
            new Column('id', Type::getType('integer'), ['autoincrement' => true, 'comment' => 'primary']),
            ['comment'],
            new Column('id', Type::getType('integer'), ['autoincrement' => true])
217 218 219 220 221 222
        );

        // Remove comment from null-commented column.
        $tableDiff->changedColumns['comment_null'] = new ColumnDiff(
            'comment_null',
            new Column('comment_null', Type::getType('string')),
Sergei Morozov's avatar
Sergei Morozov committed
223 224
            ['type'],
            new Column('comment_null', Type::getType('integer'), ['comment' => null])
225 226 227 228 229
        );

        // Add comment to false-commented column.
        $tableDiff->changedColumns['comment_false'] = new ColumnDiff(
            'comment_false',
Sergei Morozov's avatar
Sergei Morozov committed
230 231 232
            new Column('comment_false', Type::getType('integer'), ['comment' => 'false']),
            ['comment'],
            new Column('comment_false', Type::getType('integer'), ['comment' => false])
233 234 235 236 237 238
        );

        // Change type to custom type from empty string commented column.
        $tableDiff->changedColumns['comment_empty_string'] = new ColumnDiff(
            'comment_empty_string',
            new Column('comment_empty_string', Type::getType('object')),
Sergei Morozov's avatar
Sergei Morozov committed
239 240
            ['type'],
            new Column('comment_empty_string', Type::getType('integer'), ['comment' => ''])
241 242 243 244 245
        );

        // Change comment to false-comment from zero-string commented column.
        $tableDiff->changedColumns['comment_string_0'] = new ColumnDiff(
            'comment_string_0',
Sergei Morozov's avatar
Sergei Morozov committed
246 247 248
            new Column('comment_string_0', Type::getType('integer'), ['comment' => false]),
            ['comment'],
            new Column('comment_string_0', Type::getType('integer'), ['comment' => '0'])
249 250 251 252 253 254
        );

        // Remove comment from regular commented column.
        $tableDiff->changedColumns['comment'] = new ColumnDiff(
            'comment',
            new Column('comment', Type::getType('integer')),
Sergei Morozov's avatar
Sergei Morozov committed
255 256
            ['comment'],
            new Column('comment', Type::getType('integer'), ['comment' => 'Doctrine 0wnz you!'])
257 258 259 260 261
        );

        // Change comment and change type to custom type from regular commented column.
        $tableDiff->changedColumns['`comment_quoted`'] = new ColumnDiff(
            '`comment_quoted`',
Sergei Morozov's avatar
Sergei Morozov committed
262 263 264
            new Column('`comment_quoted`', Type::getType('array'), ['comment' => 'Doctrine array.']),
            ['comment', 'type'],
            new Column('`comment_quoted`', Type::getType('integer'), ['comment' => 'Doctrine 0wnz you!'])
265 266 267 268 269 270
        );

        // Remove comment and change type to custom type from regular commented column.
        $tableDiff->changedColumns['create'] = new ColumnDiff(
            'create',
            new Column('create', Type::getType('object')),
Sergei Morozov's avatar
Sergei Morozov committed
271 272
            ['comment', 'type'],
            new Column('create', Type::getType('integer'), ['comment' => 'Doctrine 0wnz comments for reserved keyword columns!'])
273 274 275 276 277
        );

        // Add comment and change custom type to regular type from non-commented column.
        $tableDiff->changedColumns['commented_type'] = new ColumnDiff(
            'commented_type',
Sergei Morozov's avatar
Sergei Morozov committed
278 279
            new Column('commented_type', Type::getType('integer'), ['comment' => 'foo']),
            ['comment', 'type'],
280 281 282 283 284 285 286
            new Column('commented_type', Type::getType('object'))
        );

        // Remove comment from commented custom type column.
        $tableDiff->changedColumns['commented_type_with_comment'] = new ColumnDiff(
            'commented_type_with_comment',
            new Column('commented_type_with_comment', Type::getType('array')),
Sergei Morozov's avatar
Sergei Morozov committed
287 288
            ['comment'],
            new Column('commented_type_with_comment', Type::getType('array'), ['comment' => 'Doctrine array type.'])
289 290
        );

Sergei Morozov's avatar
Sergei Morozov committed
291
        $tableDiff->removedColumns['comment_integer_0'] = new Column('comment_integer_0', Type::getType('integer'), ['comment' => 0]);
292

Sergei Morozov's avatar
Sergei Morozov committed
293
        $this->schemaManager->alterTable($tableDiff);
294

Sergei Morozov's avatar
Sergei Morozov committed
295
        $columns = $this->schemaManager->listTableColumns('sqlsrv_column_comment');
Gabriel Caruso's avatar
Gabriel Caruso committed
296
        self::assertCount(23, $columns);
297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319
        self::assertEquals('primary', $columns['id']->getComment());
        self::assertNull($columns['comment_null']->getComment());
        self::assertEquals('false', $columns['comment_false']->getComment());
        self::assertNull($columns['comment_empty_string']->getComment());
        self::assertEquals('0', $columns['comment_double_0']->getComment());
        self::assertNull($columns['comment_string_0']->getComment());
        self::assertNull($columns['comment']->getComment());
        self::assertEquals('Doctrine array.', $columns['comment_quoted']->getComment());
        self::assertNull($columns['[create]']->getComment());
        self::assertEquals('foo', $columns['commented_type']->getComment());
        self::assertNull($columns['commented_type_with_comment']->getComment());
        self::assertNull($columns['added_comment_none']->getComment());
        self::assertNull($columns['added_comment_null']->getComment());
        self::assertNull($columns['added_comment_false']->getComment());
        self::assertNull($columns['added_comment_empty_string']->getComment());
        self::assertEquals('0', $columns['added_comment_integer_0']->getComment());
        self::assertEquals('0', $columns['added_comment_float_0']->getComment());
        self::assertEquals('0', $columns['added_comment_string_0']->getComment());
        self::assertEquals('Doctrine', $columns['added_comment']->getComment());
        self::assertEquals('rulez', $columns['added_comment_quoted']->getComment());
        self::assertEquals('666', $columns['[select]']->getComment());
        self::assertNull($columns['added_commented_type']->getComment());
        self::assertEquals('666', $columns['added_commented_type_with_comment']->getComment());
320
    }
321

322
    public function testPkOrdering() : void
323 324 325 326 327 328 329 330 331
    {
        // SQL Server stores index column information in a system table with two
        // columns that almost always have the same value: index_column_id and key_ordinal.
        // The only situation when the two values doesn't match up is when a clustered index
        // is declared that references columns in a different order from which they are
        // declared in the table. In that case, key_ordinal != index_column_id.
        // key_ordinal holds the index ordering. index_column_id is just a unique identifier
        // for index columns within the given index.
        $table = new Table('sqlsrv_pk_ordering');
Sergei Morozov's avatar
Sergei Morozov committed
332 333 334
        $table->addColumn('colA', 'integer', ['notnull' => true]);
        $table->addColumn('colB', 'integer', ['notnull' => true]);
        $table->setPrimaryKey(['colB', 'colA']);
Sergei Morozov's avatar
Sergei Morozov committed
335
        $this->schemaManager->createTable($table);
336

Sergei Morozov's avatar
Sergei Morozov committed
337
        $indexes = $this->schemaManager->listTableIndexes('sqlsrv_pk_ordering');
338

339
        self::assertCount(1, $indexes);
340 341

        $firstIndex = current($indexes);
Sergei Morozov's avatar
Sergei Morozov committed
342
        $columns    = $firstIndex->getColumns();
343 344 345
        self::assertCount(2, $columns);
        self::assertEquals('colB', $columns[0]);
        self::assertEquals('colA', $columns[1]);
346
    }
347
}