TableTest.php 29 KB
Newer Older
1 2 3 4
<?php

namespace Doctrine\Tests\DBAL\Schema;

Luís Cobucci's avatar
Luís Cobucci committed
5
use Doctrine\DBAL\DBALException;
Sergei Morozov's avatar
Sergei Morozov committed
6 7
use Doctrine\DBAL\Platforms\MySqlPlatform;
use Doctrine\DBAL\Platforms\SqlitePlatform;
8 9
use Doctrine\DBAL\Schema\Column;
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
jeroendedauw's avatar
jeroendedauw committed
10
use Doctrine\DBAL\Schema\Index;
Sergei Morozov's avatar
Sergei Morozov committed
11
use Doctrine\DBAL\Schema\SchemaException;
jeroendedauw's avatar
jeroendedauw committed
12
use Doctrine\DBAL\Schema\Table;
13
use Doctrine\DBAL\Types\Type;
Sergei Morozov's avatar
Sergei Morozov committed
14
use Doctrine\Tests\DbalTestCase;
15 16
use function array_shift;
use function current;
17

Sergei Morozov's avatar
Sergei Morozov committed
18
class TableTest extends DbalTestCase
19
{
20 21
    public function testCreateWithInvalidTableName()
    {
Luís Cobucci's avatar
Luís Cobucci committed
22 23
        $this->expectException(DBALException::class);

Sergei Morozov's avatar
Sergei Morozov committed
24
        new Table('');
25 26
    }

27 28
    public function testGetName()
    {
Sergei Morozov's avatar
Sergei Morozov committed
29 30
        $table =  new Table('foo', [], [], []);
        self::assertEquals('foo', $table->getName());
31 32 33 34
    }

    public function testColumns()
    {
Sergei Morozov's avatar
Sergei Morozov committed
35 36 37 38 39
        $type      = Type::getType('integer');
        $columns   = [];
        $columns[] = new Column('foo', $type);
        $columns[] = new Column('bar', $type);
        $table     = new Table('foo', $columns, [], []);
40

Sergei Morozov's avatar
Sergei Morozov committed
41 42 43
        self::assertTrue($table->hasColumn('foo'));
        self::assertTrue($table->hasColumn('bar'));
        self::assertFalse($table->hasColumn('baz'));
44

Sergei Morozov's avatar
Sergei Morozov committed
45 46
        self::assertInstanceOf(Column::class, $table->getColumn('foo'));
        self::assertInstanceOf(Column::class, $table->getColumn('bar'));
47

Gabriel Caruso's avatar
Gabriel Caruso committed
48
        self::assertCount(2, $table->getColumns());
49 50
    }

51 52
    public function testColumnsCaseInsensitive()
    {
Sergei Morozov's avatar
Sergei Morozov committed
53
        $table  = new Table('foo');
54
        $column = $table->addColumn('Foo', 'integer');
55

56 57 58
        self::assertTrue($table->hasColumn('Foo'));
        self::assertTrue($table->hasColumn('foo'));
        self::assertTrue($table->hasColumn('FOO'));
59

60 61 62
        self::assertSame($column, $table->getColumn('Foo'));
        self::assertSame($column, $table->getColumn('foo'));
        self::assertSame($column, $table->getColumn('FOO'));
63 64
    }

65 66 67 68
    public function testCreateColumn()
    {
        $type = Type::getType('integer');

Sergei Morozov's avatar
Sergei Morozov committed
69
        $table = new Table('foo');
70

Sergei Morozov's avatar
Sergei Morozov committed
71 72 73 74
        self::assertFalse($table->hasColumn('bar'));
        $table->addColumn('bar', 'integer');
        self::assertTrue($table->hasColumn('bar'));
        self::assertSame($type, $table->getColumn('bar')->getType());
75 76 77 78
    }

    public function testDropColumn()
    {
Sergei Morozov's avatar
Sergei Morozov committed
79 80 81 82 83
        $type      = Type::getType('integer');
        $columns   = [];
        $columns[] = new Column('foo', $type);
        $columns[] = new Column('bar', $type);
        $table     = new Table('foo', $columns, [], []);
84

Sergei Morozov's avatar
Sergei Morozov committed
85 86
        self::assertTrue($table->hasColumn('foo'));
        self::assertTrue($table->hasColumn('bar'));
87

Sergei Morozov's avatar
Sergei Morozov committed
88
        $table->dropColumn('foo')->dropColumn('bar');
89

Sergei Morozov's avatar
Sergei Morozov committed
90 91
        self::assertFalse($table->hasColumn('foo'));
        self::assertFalse($table->hasColumn('bar'));
92 93 94 95
    }

    public function testGetUnknownColumnThrowsException()
    {
Sergei Morozov's avatar
Sergei Morozov committed
96
        $this->expectException(SchemaException::class);
97

Sergei Morozov's avatar
Sergei Morozov committed
98
        $table = new Table('foo', [], [], []);
99 100 101 102 103
        $table->getColumn('unknown');
    }

    public function testAddColumnTwiceThrowsException()
    {
Sergei Morozov's avatar
Sergei Morozov committed
104
        $this->expectException(SchemaException::class);
105

Sergei Morozov's avatar
Sergei Morozov committed
106 107 108 109 110
        $type      = Type::getType('integer');
        $columns   = [];
        $columns[] = new Column('foo', $type);
        $columns[] = new Column('foo', $type);
        $table     = new Table('foo', $columns, [], []);
111 112
    }

113 114
    public function testCreateIndex()
    {
Sergei Morozov's avatar
Sergei Morozov committed
115 116 117
        $type    = Type::getType('integer');
        $columns = [new Column('foo', $type), new Column('bar', $type), new Column('baz', $type)];
        $table   = new Table('foo', $columns);
118

Sergei Morozov's avatar
Sergei Morozov committed
119 120
        $table->addIndex(['foo', 'bar'], 'foo_foo_bar_idx');
        $table->addUniqueIndex(['bar', 'baz'], 'foo_bar_baz_uniq');
121

Sergei Morozov's avatar
Sergei Morozov committed
122 123
        self::assertTrue($table->hasIndex('foo_foo_bar_idx'));
        self::assertTrue($table->hasIndex('foo_bar_baz_uniq'));
124 125
    }

126 127
    public function testIndexCaseInsensitive()
    {
Sergei Morozov's avatar
Sergei Morozov committed
128 129 130 131 132 133 134
        $type    = Type::getType('integer');
        $columns = [
            new Column('foo', $type),
            new Column('bar', $type),
            new Column('baz', $type),
        ];
        $table   = new Table('foo', $columns);
135

Sergei Morozov's avatar
Sergei Morozov committed
136
        $table->addIndex(['foo', 'bar', 'baz'], 'Foo_Idx');
137

138 139 140
        self::assertTrue($table->hasIndex('foo_idx'));
        self::assertTrue($table->hasIndex('Foo_Idx'));
        self::assertTrue($table->hasIndex('FOO_IDX'));
141 142
    }

143 144
    public function testAddIndexes()
    {
Sergei Morozov's avatar
Sergei Morozov committed
145 146 147 148 149 150 151 152 153 154 155 156 157 158
        $type    = Type::getType('integer');
        $columns = [
            new Column('foo', $type),
            new Column('bar', $type),
        ];
        $indexes = [
            new Index('the_primary', ['foo'], true, true),
            new Index('bar_idx', ['bar'], false, false),
        ];
        $table   = new Table('foo', $columns, $indexes, []);

        self::assertTrue($table->hasIndex('the_primary'));
        self::assertTrue($table->hasIndex('bar_idx'));
        self::assertFalse($table->hasIndex('some_idx'));
159

Sergei Morozov's avatar
Sergei Morozov committed
160 161 162
        self::assertInstanceOf(Index::class, $table->getPrimaryKey());
        self::assertInstanceOf(Index::class, $table->getIndex('the_primary'));
        self::assertInstanceOf(Index::class, $table->getIndex('bar_idx'));
163 164 165 166
    }

    public function testGetUnknownIndexThrowsException()
    {
Sergei Morozov's avatar
Sergei Morozov committed
167
        $this->expectException(SchemaException::class);
168

Sergei Morozov's avatar
Sergei Morozov committed
169 170
        $table = new Table('foo', [], [], []);
        $table->getIndex('unknownIndex');
171 172 173 174
    }

    public function testAddTwoPrimaryThrowsException()
    {
Sergei Morozov's avatar
Sergei Morozov committed
175
        $this->expectException(SchemaException::class);
176

Sergei Morozov's avatar
Sergei Morozov committed
177 178 179 180 181 182 183
        $type    = Type::getType('integer');
        $columns = [new Column('foo', $type), new Column('bar', $type)];
        $indexes = [
            new Index('the_primary', ['foo'], true, true),
            new Index('other_primary', ['bar'], true, true),
        ];
        $table   = new Table('foo', $columns, $indexes, []);
184 185 186 187
    }

    public function testAddTwoIndexesWithSameNameThrowsException()
    {
Sergei Morozov's avatar
Sergei Morozov committed
188
        $this->expectException(SchemaException::class);
189

Sergei Morozov's avatar
Sergei Morozov committed
190 191 192 193 194 195 196
        $type    = Type::getType('integer');
        $columns = [new Column('foo', $type), new Column('bar', $type)];
        $indexes = [
            new Index('an_idx', ['foo'], false, false),
            new Index('an_idx', ['bar'], false, false),
        ];
        $table   = new Table('foo', $columns, $indexes, []);
197 198 199 200
    }

    public function testConstraints()
    {
Sergei Morozov's avatar
Sergei Morozov committed
201
        $constraint = new ForeignKeyConstraint([], 'foo', []);
202

Sergei Morozov's avatar
Sergei Morozov committed
203
        $tableA      = new Table('foo', [], [], [$constraint]);
204
        $constraints = $tableA->getForeignKeys();
205

Gabriel Caruso's avatar
Gabriel Caruso committed
206
        self::assertCount(1, $constraints);
207
        self::assertSame($constraint, array_shift($constraints));
208 209 210 211
    }

    public function testOptions()
    {
Sergei Morozov's avatar
Sergei Morozov committed
212
        $table = new Table('foo', [], [], [], false, ['foo' => 'bar']);
213

Sergei Morozov's avatar
Sergei Morozov committed
214 215
        self::assertTrue($table->hasOption('foo'));
        self::assertEquals('bar', $table->getOption('foo'));
216 217 218 219
    }

    public function testBuilderSetPrimaryKey()
    {
Sergei Morozov's avatar
Sergei Morozov committed
220
        $table = new Table('foo');
221

Sergei Morozov's avatar
Sergei Morozov committed
222 223
        $table->addColumn('bar', 'integer');
        $table->setPrimaryKey(['bar']);
224

Sergei Morozov's avatar
Sergei Morozov committed
225
        self::assertTrue($table->hasIndex('primary'));
Sergei Morozov's avatar
Sergei Morozov committed
226
        self::assertInstanceOf(Index::class, $table->getPrimaryKey());
Sergei Morozov's avatar
Sergei Morozov committed
227 228
        self::assertTrue($table->getIndex('primary')->isUnique());
        self::assertTrue($table->getIndex('primary')->isPrimary());
229 230 231 232
    }

    public function testBuilderAddUniqueIndex()
    {
Sergei Morozov's avatar
Sergei Morozov committed
233
        $table = new Table('foo');
234

Sergei Morozov's avatar
Sergei Morozov committed
235 236
        $table->addColumn('bar', 'integer');
        $table->addUniqueIndex(['bar'], 'my_idx');
237

Sergei Morozov's avatar
Sergei Morozov committed
238 239 240
        self::assertTrue($table->hasIndex('my_idx'));
        self::assertTrue($table->getIndex('my_idx')->isUnique());
        self::assertFalse($table->getIndex('my_idx')->isPrimary());
241 242 243 244
    }

    public function testBuilderAddIndex()
    {
Sergei Morozov's avatar
Sergei Morozov committed
245
        $table = new Table('foo');
246

Sergei Morozov's avatar
Sergei Morozov committed
247 248
        $table->addColumn('bar', 'integer');
        $table->addIndex(['bar'], 'my_idx');
249

Sergei Morozov's avatar
Sergei Morozov committed
250 251 252
        self::assertTrue($table->hasIndex('my_idx'));
        self::assertFalse($table->getIndex('my_idx')->isUnique());
        self::assertFalse($table->getIndex('my_idx')->isPrimary());
253 254 255 256
    }

    public function testBuilderAddIndexWithInvalidNameThrowsException()
    {
Sergei Morozov's avatar
Sergei Morozov committed
257
        $this->expectException(SchemaException::class);
258

Sergei Morozov's avatar
Sergei Morozov committed
259 260 261
        $table = new Table('foo');
        $table->addColumn('bar', 'integer');
        $table->addIndex(['bar'], 'invalid name %&/');
262 263 264 265
    }

    public function testBuilderAddIndexWithUnknownColumnThrowsException()
    {
Sergei Morozov's avatar
Sergei Morozov committed
266
        $this->expectException(SchemaException::class);
267

Sergei Morozov's avatar
Sergei Morozov committed
268 269
        $table = new Table('foo');
        $table->addIndex(['bar'], 'invalidName');
270 271 272 273
    }

    public function testBuilderOptions()
    {
Sergei Morozov's avatar
Sergei Morozov committed
274 275 276 277
        $table = new Table('foo');
        $table->addOption('foo', 'bar');
        self::assertTrue($table->hasOption('foo'));
        self::assertEquals('bar', $table->getOption('foo'));
278 279
    }

Sergei Morozov's avatar
Sergei Morozov committed
280
    public function testAddForeignKeyConstraintUnknownLocalColumnThrowsException()
281
    {
Sergei Morozov's avatar
Sergei Morozov committed
282
        $this->expectException(SchemaException::class);
283

Sergei Morozov's avatar
Sergei Morozov committed
284 285
        $table = new Table('foo');
        $table->addColumn('id', 'integer');
286

Sergei Morozov's avatar
Sergei Morozov committed
287 288
        $foreignTable = new Table('bar');
        $foreignTable->addColumn('id', 'integer');
289

Sergei Morozov's avatar
Sergei Morozov committed
290
        $table->addForeignKeyConstraint($foreignTable, ['foo'], ['id']);
291 292
    }

Sergei Morozov's avatar
Sergei Morozov committed
293
    public function testAddForeignKeyConstraintUnknownForeignColumnThrowsException()
294
    {
Sergei Morozov's avatar
Sergei Morozov committed
295
        $this->expectException(SchemaException::class);
296

Sergei Morozov's avatar
Sergei Morozov committed
297 298
        $table = new Table('foo');
        $table->addColumn('id', 'integer');
299

Sergei Morozov's avatar
Sergei Morozov committed
300 301
        $foreignTable = new Table('bar');
        $foreignTable->addColumn('id', 'integer');
302

Sergei Morozov's avatar
Sergei Morozov committed
303
        $table->addForeignKeyConstraint($foreignTable, ['id'], ['foo']);
304 305 306 307
    }

    public function testAddForeignKeyConstraint()
    {
Sergei Morozov's avatar
Sergei Morozov committed
308 309
        $table = new Table('foo');
        $table->addColumn('id', 'integer');
310

Sergei Morozov's avatar
Sergei Morozov committed
311 312
        $foreignTable = new Table('bar');
        $foreignTable->addColumn('id', 'integer');
313

Sergei Morozov's avatar
Sergei Morozov committed
314
        $table->addForeignKeyConstraint($foreignTable, ['id'], ['id'], ['foo' => 'bar']);
315

316
        $constraints = $table->getForeignKeys();
Gabriel Caruso's avatar
Gabriel Caruso committed
317
        self::assertCount(1, $constraints);
318
        $constraint = current($constraints);
319

Sergei Morozov's avatar
Sergei Morozov committed
320
        self::assertInstanceOf(ForeignKeyConstraint::class, $constraint);
321

Sergei Morozov's avatar
Sergei Morozov committed
322 323
        self::assertTrue($constraint->hasOption('foo'));
        self::assertEquals('bar', $constraint->getOption('foo'));
324
    }
325 326 327

    public function testAddIndexWithCaseSensitiveColumnProblem()
    {
Sergei Morozov's avatar
Sergei Morozov committed
328 329
        $table = new Table('foo');
        $table->addColumn('id', 'integer');
330

Sergei Morozov's avatar
Sergei Morozov committed
331
        $table->addIndex(['ID'], 'my_idx');
332

333
        self::assertTrue($table->hasIndex('my_idx'));
Sergei Morozov's avatar
Sergei Morozov committed
334 335
        self::assertEquals(['ID'], $table->getIndex('my_idx')->getColumns());
        self::assertTrue($table->getIndex('my_idx')->spansColumns(['id']));
336
    }
337

Sergei Morozov's avatar
Sergei Morozov committed
338
    public function testAddPrimaryKeyColumnsAreExplicitlySetToNotNull()
339
    {
Sergei Morozov's avatar
Sergei Morozov committed
340 341
        $table  = new Table('foo');
        $column = $table->addColumn('id', 'integer', ['notnull' => false]);
342

343
        self::assertFalse($column->getNotnull());
344

Sergei Morozov's avatar
Sergei Morozov committed
345
        $table->setPrimaryKey(['id']);
346

347
        self::assertTrue($column->getNotnull());
348
    }
349 350 351 352 353 354

    /**
     * @group DDC-133
     */
    public function testAllowImplicitSchemaTableInAutogeneratedIndexNames()
    {
Sergei Morozov's avatar
Sergei Morozov committed
355 356 357
        $table = new Table('foo.bar');
        $table->addColumn('baz', 'integer', []);
        $table->addIndex(['baz']);
358

Gabriel Caruso's avatar
Gabriel Caruso committed
359
        self::assertCount(1, $table->getIndexes());
360
    }
361 362 363 364 365 366

    /**
     * @group DBAL-50
     */
    public function testAddForeignKeyIndexImplicitly()
    {
Sergei Morozov's avatar
Sergei Morozov committed
367 368
        $table = new Table('foo');
        $table->addColumn('id', 'integer');
369

Sergei Morozov's avatar
Sergei Morozov committed
370 371
        $foreignTable = new Table('bar');
        $foreignTable->addColumn('id', 'integer');
372

Sergei Morozov's avatar
Sergei Morozov committed
373
        $table->addForeignKeyConstraint($foreignTable, ['id'], ['id'], ['foo' => 'bar']);
374

375
        $indexes = $table->getIndexes();
Gabriel Caruso's avatar
Gabriel Caruso committed
376
        self::assertCount(1, $indexes);
377 378
        $index = current($indexes);

379
        self::assertTrue($table->hasIndex($index->getName()));
Sergei Morozov's avatar
Sergei Morozov committed
380
        self::assertEquals(['id'], $index->getColumns());
381 382
    }

383 384 385 386 387 388 389
    /**
     * @group DBAL-1063
     */
    public function testAddForeignKeyDoesNotCreateDuplicateIndex()
    {
        $table = new Table('foo');
        $table->addColumn('bar', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
390
        $table->addIndex(['bar'], 'bar_idx');
391 392 393 394

        $foreignTable = new Table('bar');
        $foreignTable->addColumn('foo', 'integer');

Sergei Morozov's avatar
Sergei Morozov committed
395
        $table->addForeignKeyConstraint($foreignTable, ['bar'], ['foo']);
396

397 398
        self::assertCount(1, $table->getIndexes());
        self::assertTrue($table->hasIndex('bar_idx'));
Sergei Morozov's avatar
Sergei Morozov committed
399
        self::assertSame(['bar'], $table->getIndex('bar_idx')->getColumns());
400 401 402 403 404 405 406 407 408 409 410
    }

    /**
     * @group DBAL-1063
     */
    public function testAddForeignKeyAddsImplicitIndexIfIndexColumnsDoNotSpan()
    {
        $table = new Table('foo');
        $table->addColumn('bar', 'integer');
        $table->addColumn('baz', 'string');
        $table->addColumn('bloo', 'string');
Sergei Morozov's avatar
Sergei Morozov committed
411 412
        $table->addIndex(['baz', 'bar'], 'composite_idx');
        $table->addIndex(['bar', 'baz', 'bloo'], 'full_idx');
413 414 415 416 417

        $foreignTable = new Table('bar');
        $foreignTable->addColumn('foo', 'integer');
        $foreignTable->addColumn('baz', 'string');

Sergei Morozov's avatar
Sergei Morozov committed
418
        $table->addForeignKeyConstraint($foreignTable, ['bar', 'baz'], ['foo', 'baz']);
419

420 421 422 423
        self::assertCount(3, $table->getIndexes());
        self::assertTrue($table->hasIndex('composite_idx'));
        self::assertTrue($table->hasIndex('full_idx'));
        self::assertTrue($table->hasIndex('idx_8c73652176ff8caa78240498'));
Sergei Morozov's avatar
Sergei Morozov committed
424 425 426
        self::assertSame(['baz', 'bar'], $table->getIndex('composite_idx')->getColumns());
        self::assertSame(['bar', 'baz', 'bloo'], $table->getIndex('full_idx')->getColumns());
        self::assertSame(['bar', 'baz'], $table->getIndex('idx_8c73652176ff8caa78240498')->getColumns());
427 428
    }

429 430
    /**
     * @group DBAL-50
431
     * @group DBAL-1063
432
     */
433
    public function testOverrulingIndexDoesNotDropOverruledIndex()
434
    {
Sergei Morozov's avatar
Sergei Morozov committed
435 436 437
        $table = new Table('bar');
        $table->addColumn('baz', 'integer', []);
        $table->addIndex(['baz']);
438 439

        $indexes = $table->getIndexes();
Gabriel Caruso's avatar
Gabriel Caruso committed
440
        self::assertCount(1, $indexes);
441
        $index = current($indexes);
442

Sergei Morozov's avatar
Sergei Morozov committed
443
        $table->addUniqueIndex(['baz']);
Gabriel Caruso's avatar
Gabriel Caruso committed
444
        self::assertCount(2, $table->getIndexes());
445
        self::assertTrue($table->hasIndex($index->getName()));
446 447 448 449 450 451 452 453 454
    }

    /**
     * @group DBAL-1063
     */
    public function testAllowsAddingDuplicateIndexesBasedOnColumns()
    {
        $table = new Table('foo');
        $table->addColumn('bar', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
455 456
        $table->addIndex(['bar'], 'bar_idx');
        $table->addIndex(['bar'], 'duplicate_idx');
457

458 459 460
        self::assertCount(2, $table->getIndexes());
        self::assertTrue($table->hasIndex('bar_idx'));
        self::assertTrue($table->hasIndex('duplicate_idx'));
Sergei Morozov's avatar
Sergei Morozov committed
461 462
        self::assertSame(['bar'], $table->getIndex('bar_idx')->getColumns());
        self::assertSame(['bar'], $table->getIndex('duplicate_idx')->getColumns());
463
    }
464

465 466 467 468 469 470 471 472
    /**
     * @group DBAL-1063
     */
    public function testAllowsAddingFulfillingIndexesBasedOnColumns()
    {
        $table = new Table('foo');
        $table->addColumn('bar', 'integer');
        $table->addColumn('baz', 'string');
Sergei Morozov's avatar
Sergei Morozov committed
473 474
        $table->addIndex(['bar'], 'bar_idx');
        $table->addIndex(['bar', 'baz'], 'fulfilling_idx');
475

476 477 478
        self::assertCount(2, $table->getIndexes());
        self::assertTrue($table->hasIndex('bar_idx'));
        self::assertTrue($table->hasIndex('fulfilling_idx'));
Sergei Morozov's avatar
Sergei Morozov committed
479 480
        self::assertSame(['bar'], $table->getIndex('bar_idx')->getColumns());
        self::assertSame(['bar', 'baz'], $table->getIndex('fulfilling_idx')->getColumns());
481 482 483 484 485 486 487
    }

    /**
     * @group DBAL-50
     * @group DBAL-1063
     */
    public function testPrimaryKeyOverrulingUniqueIndexDoesNotDropUniqueIndex()
488
    {
Sergei Morozov's avatar
Sergei Morozov committed
489 490 491
        $table = new Table('bar');
        $table->addColumn('baz', 'integer', []);
        $table->addUniqueIndex(['baz'], 'idx_unique');
492

Sergei Morozov's avatar
Sergei Morozov committed
493
        $table->setPrimaryKey(['baz']);
494 495

        $indexes = $table->getIndexes();
Sergei Morozov's avatar
Sergei Morozov committed
496
        self::assertCount(2, $indexes, 'Table should only contain both the primary key table index and the unique one, even though it was overruled.');
497

498 499
        self::assertTrue($table->hasPrimaryKey());
        self::assertTrue($table->hasIndex('idx_unique'));
500
    }
501

502 503 504 505 506 507 508
    public function testAddingFulfillingRegularIndexOverridesImplicitForeignKeyConstraintIndex()
    {
        $foreignTable = new Table('foreign');
        $foreignTable->addColumn('id', 'integer');

        $localTable = new Table('local');
        $localTable->addColumn('id', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
509
        $localTable->addForeignKeyConstraint($foreignTable, ['id'], ['id']);
510

511
        self::assertCount(1, $localTable->getIndexes());
512

Sergei Morozov's avatar
Sergei Morozov committed
513
        $localTable->addIndex(['id'], 'explicit_idx');
514

515 516
        self::assertCount(1, $localTable->getIndexes());
        self::assertTrue($localTable->hasIndex('explicit_idx'));
517 518 519 520 521 522 523 524 525
    }

    public function testAddingFulfillingUniqueIndexOverridesImplicitForeignKeyConstraintIndex()
    {
        $foreignTable = new Table('foreign');
        $foreignTable->addColumn('id', 'integer');

        $localTable = new Table('local');
        $localTable->addColumn('id', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
526
        $localTable->addForeignKeyConstraint($foreignTable, ['id'], ['id']);
527

528
        self::assertCount(1, $localTable->getIndexes());
529

Sergei Morozov's avatar
Sergei Morozov committed
530
        $localTable->addUniqueIndex(['id'], 'explicit_idx');
531

532 533
        self::assertCount(1, $localTable->getIndexes());
        self::assertTrue($localTable->hasIndex('explicit_idx'));
534 535 536 537 538 539 540 541 542
    }

    public function testAddingFulfillingPrimaryKeyOverridesImplicitForeignKeyConstraintIndex()
    {
        $foreignTable = new Table('foreign');
        $foreignTable->addColumn('id', 'integer');

        $localTable = new Table('local');
        $localTable->addColumn('id', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
543
        $localTable->addForeignKeyConstraint($foreignTable, ['id'], ['id']);
544

545
        self::assertCount(1, $localTable->getIndexes());
546

Sergei Morozov's avatar
Sergei Morozov committed
547
        $localTable->setPrimaryKey(['id'], 'explicit_idx');
548

549 550
        self::assertCount(1, $localTable->getIndexes());
        self::assertTrue($localTable->hasIndex('explicit_idx'));
551 552 553 554 555 556 557 558 559
    }

    public function testAddingFulfillingExplicitIndexOverridingImplicitForeignKeyConstraintIndexWithSameNameDoesNotThrowException()
    {
        $foreignTable = new Table('foreign');
        $foreignTable->addColumn('id', 'integer');

        $localTable = new Table('local');
        $localTable->addColumn('id', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
560
        $localTable->addForeignKeyConstraint($foreignTable, ['id'], ['id']);
561

562 563
        self::assertCount(1, $localTable->getIndexes());
        self::assertTrue($localTable->hasIndex('IDX_8BD688E8BF396750'));
564 565 566

        $implicitIndex = $localTable->getIndex('IDX_8BD688E8BF396750');

Sergei Morozov's avatar
Sergei Morozov committed
567
        $localTable->addIndex(['id'], 'IDX_8BD688E8BF396750');
568

569 570 571
        self::assertCount(1, $localTable->getIndexes());
        self::assertTrue($localTable->hasIndex('IDX_8BD688E8BF396750'));
        self::assertNotSame($implicitIndex, $localTable->getIndex('IDX_8BD688E8BF396750'));
572 573
    }

574 575 576 577 578
    /**
     * @group DBAL-64
     */
    public function testQuotedTableName()
    {
Sergei Morozov's avatar
Sergei Morozov committed
579
        $table = new Table('`bar`');
580

Sergei Morozov's avatar
Sergei Morozov committed
581 582
        $mysqlPlatform  = new MySqlPlatform();
        $sqlitePlatform = new SqlitePlatform();
583

584 585 586
        self::assertEquals('bar', $table->getName());
        self::assertEquals('`bar`', $table->getQuotedName($mysqlPlatform));
        self::assertEquals('"bar"', $table->getQuotedName($sqlitePlatform));
587
    }
588 589 590 591 592 593

    /**
     * @group DBAL-79
     */
    public function testTableHasPrimaryKey()
    {
Sergei Morozov's avatar
Sergei Morozov committed
594
        $table = new Table('test');
595

596
        self::assertFalse($table->hasPrimaryKey());
597

Sergei Morozov's avatar
Sergei Morozov committed
598 599
        $table->addColumn('foo', 'integer');
        $table->setPrimaryKey(['foo']);
600

601
        self::assertTrue($table->hasPrimaryKey());
602
    }
603 604 605 606 607 608

    /**
     * @group DBAL-91
     */
    public function testAddIndexWithQuotedColumns()
    {
Sergei Morozov's avatar
Sergei Morozov committed
609
        $table = new Table('test');
610 611
        $table->addColumn('"foo"', 'integer');
        $table->addColumn('bar', 'integer');
Luís Cobucci's avatar
Luís Cobucci committed
612 613 614
        $table->addIndex(['"foo"', '"bar"']);

        self::assertTrue($table->columnsAreIndexed(['"foo"', '"bar"']));
615 616 617 618 619 620 621
    }

    /**
     * @group DBAL-91
     */
    public function testAddForeignKeyWithQuotedColumnsAndTable()
    {
Sergei Morozov's avatar
Sergei Morozov committed
622
        $table = new Table('test');
623 624
        $table->addColumn('"foo"', 'integer');
        $table->addColumn('bar', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
625
        $table->addForeignKeyConstraint('"boing"', ['"foo"', '"bar"'], ['id']);
Luís Cobucci's avatar
Luís Cobucci committed
626 627

        self::assertCount(1, $table->getForeignKeys());
628
    }
629 630 631 632 633 634

    /**
     * @group DBAL-177
     */
    public function testQuoteSchemaPrefixed()
    {
Sergei Morozov's avatar
Sergei Morozov committed
635 636 637
        $table = new Table('`test`.`test`');
        self::assertEquals('test.test', $table->getName());
        self::assertEquals('`test`.`test`', $table->getQuotedName(new MySqlPlatform()));
638
    }
639 640 641 642 643 644

    /**
     * @group DBAL-204
     */
    public function testFullQualifiedTableName()
    {
Sergei Morozov's avatar
Sergei Morozov committed
645 646 647
        $table = new Table('`test`.`test`');
        self::assertEquals('test.test', $table->getFullQualifiedName('test'));
        self::assertEquals('test.test', $table->getFullQualifiedName('other'));
648

Sergei Morozov's avatar
Sergei Morozov committed
649 650 651
        $table = new Table('test');
        self::assertEquals('test.test', $table->getFullQualifiedName('test'));
        self::assertEquals('other.test', $table->getFullQualifiedName('other'));
652
    }
653 654 655 656 657 658

    /**
     * @group DBAL-224
     */
    public function testDropIndex()
    {
Sergei Morozov's avatar
Sergei Morozov committed
659
        $table = new Table('test');
660
        $table->addColumn('id', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
661
        $table->addIndex(['id'], 'idx');
662

663
        self::assertTrue($table->hasIndex('idx'));
664 665

        $table->dropIndex('idx');
666
        self::assertFalse($table->hasIndex('idx'));
667 668 669 670 671 672 673
    }

    /**
     * @group DBAL-224
     */
    public function testDropPrimaryKey()
    {
Sergei Morozov's avatar
Sergei Morozov committed
674
        $table = new Table('test');
675
        $table->addColumn('id', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
676
        $table->setPrimaryKey(['id']);
677

678
        self::assertTrue($table->hasPrimaryKey());
679 680

        $table->dropPrimaryKey();
681
        self::assertFalse($table->hasPrimaryKey());
682
    }
683 684 685 686 687 688

    /**
     * @group DBAL-234
     */
    public function testRenameIndex()
    {
Sergei Morozov's avatar
Sergei Morozov committed
689
        $table = new Table('test');
690 691 692 693
        $table->addColumn('id', 'integer');
        $table->addColumn('foo', 'integer');
        $table->addColumn('bar', 'integer');
        $table->addColumn('baz', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
694 695 696
        $table->setPrimaryKey(['id'], 'pk');
        $table->addIndex(['foo'], 'idx', ['flag']);
        $table->addUniqueIndex(['bar', 'baz'], 'uniq');
697 698

        // Rename to custom name.
699 700 701 702 703 704 705 706 707 708 709 710 711
        self::assertSame($table, $table->renameIndex('pk', 'pk_new'));
        self::assertSame($table, $table->renameIndex('idx', 'idx_new'));
        self::assertSame($table, $table->renameIndex('uniq', 'uniq_new'));

        self::assertTrue($table->hasPrimaryKey());
        self::assertTrue($table->hasIndex('pk_new'));
        self::assertTrue($table->hasIndex('idx_new'));
        self::assertTrue($table->hasIndex('uniq_new'));

        self::assertFalse($table->hasIndex('pk'));
        self::assertFalse($table->hasIndex('idx'));
        self::assertFalse($table->hasIndex('uniq'));

Sergei Morozov's avatar
Sergei Morozov committed
712 713
        self::assertEquals(new Index('pk_new', ['id'], true, true), $table->getPrimaryKey());
        self::assertEquals(new Index('pk_new', ['id'], true, true), $table->getIndex('pk_new'));
714
        self::assertEquals(
Sergei Morozov's avatar
Sergei Morozov committed
715
            new Index('idx_new', ['foo'], false, false, ['flag']),
716 717
            $table->getIndex('idx_new')
        );
Sergei Morozov's avatar
Sergei Morozov committed
718
        self::assertEquals(new Index('uniq_new', ['bar', 'baz'], true), $table->getIndex('uniq_new'));
719 720

        // Rename to auto-generated name.
721 722 723 724 725 726 727 728 729 730 731 732 733
        self::assertSame($table, $table->renameIndex('pk_new', null));
        self::assertSame($table, $table->renameIndex('idx_new', null));
        self::assertSame($table, $table->renameIndex('uniq_new', null));

        self::assertTrue($table->hasPrimaryKey());
        self::assertTrue($table->hasIndex('primary'));
        self::assertTrue($table->hasIndex('IDX_D87F7E0C8C736521'));
        self::assertTrue($table->hasIndex('UNIQ_D87F7E0C76FF8CAA78240498'));

        self::assertFalse($table->hasIndex('pk_new'));
        self::assertFalse($table->hasIndex('idx_new'));
        self::assertFalse($table->hasIndex('uniq_new'));

Sergei Morozov's avatar
Sergei Morozov committed
734 735
        self::assertEquals(new Index('primary', ['id'], true, true), $table->getPrimaryKey());
        self::assertEquals(new Index('primary', ['id'], true, true), $table->getIndex('primary'));
736
        self::assertEquals(
Sergei Morozov's avatar
Sergei Morozov committed
737
            new Index('IDX_D87F7E0C8C736521', ['foo'], false, false, ['flag']),
738 739
            $table->getIndex('IDX_D87F7E0C8C736521')
        );
740
        self::assertEquals(
Sergei Morozov's avatar
Sergei Morozov committed
741
            new Index('UNIQ_D87F7E0C76FF8CAA78240498', ['bar', 'baz'], true),
742 743 744 745
            $table->getIndex('UNIQ_D87F7E0C76FF8CAA78240498')
        );

        // Rename to same name (changed case).
746 747 748
        self::assertSame($table, $table->renameIndex('primary', 'PRIMARY'));
        self::assertSame($table, $table->renameIndex('IDX_D87F7E0C8C736521', 'idx_D87F7E0C8C736521'));
        self::assertSame($table, $table->renameIndex('UNIQ_D87F7E0C76FF8CAA78240498', 'uniq_D87F7E0C76FF8CAA78240498'));
749

750 751 752 753
        self::assertTrue($table->hasPrimaryKey());
        self::assertTrue($table->hasIndex('primary'));
        self::assertTrue($table->hasIndex('IDX_D87F7E0C8C736521'));
        self::assertTrue($table->hasIndex('UNIQ_D87F7E0C76FF8CAA78240498'));
754 755
    }

756 757 758 759 760 761 762
    /**
     * @group DBAL-2508
     */
    public function testKeepsIndexOptionsOnRenamingRegularIndex()
    {
        $table = new Table('foo');
        $table->addColumn('id', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
763
        $table->addIndex(['id'], 'idx_bar', [], ['where' => '1 = 1']);
764 765 766

        $table->renameIndex('idx_bar', 'idx_baz');

Sergei Morozov's avatar
Sergei Morozov committed
767
        self::assertSame(['where' => '1 = 1'], $table->getIndex('idx_baz')->getOptions());
768 769 770 771 772 773 774 775 776
    }

    /**
     * @group DBAL-2508
     */
    public function testKeepsIndexOptionsOnRenamingUniqueIndex()
    {
        $table = new Table('foo');
        $table->addColumn('id', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
777
        $table->addUniqueIndex(['id'], 'idx_bar', ['where' => '1 = 1']);
778 779 780

        $table->renameIndex('idx_bar', 'idx_baz');

Sergei Morozov's avatar
Sergei Morozov committed
781
        self::assertSame(['where' => '1 = 1'], $table->getIndex('idx_baz')->getOptions());
782 783
    }

784 785 786 787 788 789
    /**
     * @group DBAL-234
     * @expectedException \Doctrine\DBAL\Schema\SchemaException
     */
    public function testThrowsExceptionOnRenamingNonExistingIndex()
    {
Sergei Morozov's avatar
Sergei Morozov committed
790
        $table = new Table('test');
791
        $table->addColumn('id', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
792
        $table->addIndex(['id'], 'idx');
793 794 795 796 797 798 799 800 801 802

        $table->renameIndex('foo', 'bar');
    }

    /**
     * @group DBAL-234
     * @expectedException \Doctrine\DBAL\Schema\SchemaException
     */
    public function testThrowsExceptionOnRenamingToAlreadyExistingIndex()
    {
Sergei Morozov's avatar
Sergei Morozov committed
803
        $table = new Table('test');
804 805
        $table->addColumn('id', 'integer');
        $table->addColumn('foo', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
806 807
        $table->addIndex(['id'], 'idx_id');
        $table->addIndex(['foo'], 'idx_foo');
808 809 810

        $table->renameIndex('idx_id', 'idx_foo');
    }
811 812 813 814 815 816 817 818 819 820

    /**
     * @dataProvider getNormalizesAssetNames
     * @group DBAL-831
     */
    public function testNormalizesColumnNames($assetName)
    {
        $table = new Table('test');

        $table->addColumn($assetName, 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
821 822
        $table->addIndex([$assetName], $assetName);
        $table->addForeignKeyConstraint('test', [$assetName], [$assetName], [], $assetName);
823

824 825
        self::assertTrue($table->hasColumn($assetName));
        self::assertTrue($table->hasColumn('foo'));
Sergei Morozov's avatar
Sergei Morozov committed
826 827
        self::assertInstanceOf(Column::class, $table->getColumn($assetName));
        self::assertInstanceOf(Column::class, $table->getColumn('foo'));
828

829 830
        self::assertTrue($table->hasIndex($assetName));
        self::assertTrue($table->hasIndex('foo'));
Sergei Morozov's avatar
Sergei Morozov committed
831 832
        self::assertInstanceOf(Index::class, $table->getIndex($assetName));
        self::assertInstanceOf(Index::class, $table->getIndex('foo'));
833

834 835
        self::assertTrue($table->hasForeignKey($assetName));
        self::assertTrue($table->hasForeignKey('foo'));
Sergei Morozov's avatar
Sergei Morozov committed
836 837
        self::assertInstanceOf(ForeignKeyConstraint::class, $table->getForeignKey($assetName));
        self::assertInstanceOf(ForeignKeyConstraint::class, $table->getForeignKey('foo'));
838 839

        $table->renameIndex($assetName, $assetName);
840 841
        self::assertTrue($table->hasIndex($assetName));
        self::assertTrue($table->hasIndex('foo'));
842 843

        $table->renameIndex($assetName, 'foo');
844 845
        self::assertTrue($table->hasIndex($assetName));
        self::assertTrue($table->hasIndex('foo'));
846 847

        $table->renameIndex('foo', $assetName);
848 849
        self::assertTrue($table->hasIndex($assetName));
        self::assertTrue($table->hasIndex('foo'));
850 851

        $table->renameIndex($assetName, 'bar');
852 853 854
        self::assertFalse($table->hasIndex($assetName));
        self::assertFalse($table->hasIndex('foo'));
        self::assertTrue($table->hasIndex('bar'));
855 856 857 858 859 860 861

        $table->renameIndex('bar', $assetName);

        $table->dropColumn($assetName);
        $table->dropIndex($assetName);
        $table->removeForeignKey($assetName);

862 863 864 865 866 867
        self::assertFalse($table->hasColumn($assetName));
        self::assertFalse($table->hasColumn('foo'));
        self::assertFalse($table->hasIndex($assetName));
        self::assertFalse($table->hasIndex('foo'));
        self::assertFalse($table->hasForeignKey($assetName));
        self::assertFalse($table->hasForeignKey('foo'));
868 869 870 871
    }

    public function getNormalizesAssetNames()
    {
Sergei Morozov's avatar
Sergei Morozov committed
872 873 874 875 876 877 878 879 880 881
        return [
            ['foo'],
            ['FOO'],
            ['`foo`'],
            ['`FOO`'],
            ['"foo"'],
            ['"FOO"'],
            ['"foo"'],
            ['"FOO"'],
        ];
882
    }
883
}