AbstractMySQLPlatformTestCase.php 36.5 KB
Newer Older
1 2
<?php

3
namespace Doctrine\DBAL\Tests\Platforms;
4 5

use Doctrine\DBAL\Platforms\AbstractPlatform;
6
use Doctrine\DBAL\Platforms\MySqlPlatform;
7 8
use Doctrine\DBAL\Schema\Comparator;
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
jeroendedauw's avatar
jeroendedauw committed
9
use Doctrine\DBAL\Schema\Index;
10 11
use Doctrine\DBAL\Schema\Table;
use Doctrine\DBAL\Schema\TableDiff;
12
use Doctrine\DBAL\TransactionIsolationLevel;
13

14
use function array_shift;
15 16 17

abstract class AbstractMySQLPlatformTestCase extends AbstractPlatformTestCase
{
18 19 20
    /** @var MySqlPlatform */
    protected $platform;

21
    public function testModifyLimitQueryWitoutLimit(): void
22
    {
Sergei Morozov's avatar
Sergei Morozov committed
23
        $sql = $this->platform->modifyLimitQuery('SELECT n FROM Foo', null, 10);
Sergei Morozov's avatar
Sergei Morozov committed
24
        self::assertEquals('SELECT n FROM Foo LIMIT 18446744073709551615 OFFSET 10', $sql);
25 26
    }

27
    public function testGenerateMixedCaseTableCreate(): void
28
    {
Sergei Morozov's avatar
Sergei Morozov committed
29 30
        $table = new Table('Foo');
        $table->addColumn('Bar', 'integer');
31

Sergei Morozov's avatar
Sergei Morozov committed
32
        $sql = $this->platform->getCreateTableSQL($table);
33
        self::assertEquals('CREATE TABLE Foo (Bar INT NOT NULL) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB', array_shift($sql));
34 35
    }

36
    public function getGenerateTableSql(): string
37
    {
38
        return 'CREATE TABLE test (id INT AUTO_INCREMENT NOT NULL, test VARCHAR(255) DEFAULT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB';
39 40
    }

41 42 43
    /**
     * @return string[]
     */
44
    public function getGenerateTableWithMultiColumnUniqueIndexSql(): array
45
    {
46
        return ['CREATE TABLE test (foo VARCHAR(255) DEFAULT NULL, bar VARCHAR(255) DEFAULT NULL, UNIQUE INDEX UNIQ_D87F7E0C8C73652176FF8CAA (foo, bar)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB'];
47 48
    }

49 50 51
    /**
     * {@inheritDoc}
     */
52
    public function getGenerateAlterTableSql(): array
53
    {
Sergei Morozov's avatar
Sergei Morozov committed
54
        return ["ALTER TABLE mytable RENAME TO userlist, ADD quota INT DEFAULT NULL, DROP foo, CHANGE bar baz VARCHAR(255) DEFAULT 'def' NOT NULL, CHANGE bloo bloo TINYINT(1) DEFAULT '0' NOT NULL"];
55 56
    }

57
    public function testGeneratesSqlSnippets(): void
58
    {
Sergei Morozov's avatar
Sergei Morozov committed
59 60 61
        self::assertEquals('RLIKE', $this->platform->getRegexpExpression(), 'Regular expression operator is not correct');
        self::assertEquals('`', $this->platform->getIdentifierQuoteCharacter(), 'Quote character is not correct');
        self::assertEquals('CONCAT(column1, column2, column3)', $this->platform->getConcatExpression('column1', 'column2', 'column3'), 'Concatenation function is not correct');
62 63
    }

64
    public function testGeneratesTransactionsCommands(): void
65
    {
66
        self::assertEquals(
67
            'SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED',
Sergei Morozov's avatar
Sergei Morozov committed
68
            $this->platform->getSetTransactionIsolationSQL(TransactionIsolationLevel::READ_UNCOMMITTED),
69 70
            ''
        );
71
        self::assertEquals(
72
            'SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED',
Sergei Morozov's avatar
Sergei Morozov committed
73
            $this->platform->getSetTransactionIsolationSQL(TransactionIsolationLevel::READ_COMMITTED)
74
        );
75
        self::assertEquals(
76
            'SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ',
Sergei Morozov's avatar
Sergei Morozov committed
77
            $this->platform->getSetTransactionIsolationSQL(TransactionIsolationLevel::REPEATABLE_READ)
78
        );
79
        self::assertEquals(
80
            'SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE',
Sergei Morozov's avatar
Sergei Morozov committed
81
            $this->platform->getSetTransactionIsolationSQL(TransactionIsolationLevel::SERIALIZABLE)
82 83 84
        );
    }

85
    public function testGeneratesDDLSnippets(): void
86
    {
Sergei Morozov's avatar
Sergei Morozov committed
87 88 89 90
        self::assertEquals('SHOW DATABASES', $this->platform->getListDatabasesSQL());
        self::assertEquals('CREATE DATABASE foobar', $this->platform->getCreateDatabaseSQL('foobar'));
        self::assertEquals('DROP DATABASE foobar', $this->platform->getDropDatabaseSQL('foobar'));
        self::assertEquals('DROP TABLE foobar', $this->platform->getDropTableSQL('foobar'));
91 92
    }

93
    public function testGeneratesTypeDeclarationForIntegers(): void
94
    {
95
        self::assertEquals(
96
            'INT',
Sergei Morozov's avatar
Sergei Morozov committed
97
            $this->platform->getIntegerTypeDeclarationSQL([])
98
        );
99
        self::assertEquals(
100
            'INT AUTO_INCREMENT',
Sergei Morozov's avatar
Sergei Morozov committed
101
            $this->platform->getIntegerTypeDeclarationSQL(['autoincrement' => true])
Sergei Morozov's avatar
Sergei Morozov committed
102
        );
103
        self::assertEquals(
104
            'INT AUTO_INCREMENT',
Sergei Morozov's avatar
Sergei Morozov committed
105
            $this->platform->getIntegerTypeDeclarationSQL(
Sergei Morozov's avatar
Sergei Morozov committed
106 107 108
                ['autoincrement' => true, 'primary' => true]
            )
        );
109 110
    }

111
    public function testGeneratesTypeDeclarationForStrings(): void
112
    {
113
        self::assertEquals(
114
            'CHAR(10)',
Sergei Morozov's avatar
Sergei Morozov committed
115
            $this->platform->getVarcharTypeDeclarationSQL(
Sergei Morozov's avatar
Sergei Morozov committed
116 117 118
                ['length' => 10, 'fixed' => true]
            )
        );
119
        self::assertEquals(
120
            'VARCHAR(50)',
Sergei Morozov's avatar
Sergei Morozov committed
121
            $this->platform->getVarcharTypeDeclarationSQL(['length' => 50]),
122 123
            'Variable string declaration is not correct'
        );
124
        self::assertEquals(
125
            'VARCHAR(255)',
Sergei Morozov's avatar
Sergei Morozov committed
126
            $this->platform->getVarcharTypeDeclarationSQL([]),
127 128 129 130
            'Long string declaration is not correct'
        );
    }

131
    public function testPrefersIdentityColumns(): void
132
    {
Sergei Morozov's avatar
Sergei Morozov committed
133
        self::assertTrue($this->platform->prefersIdentityColumns());
134 135
    }

136
    public function testSupportsIdentityColumns(): void
137
    {
Sergei Morozov's avatar
Sergei Morozov committed
138
        self::assertTrue($this->platform->supportsIdentityColumns());
139 140
    }

141
    public function testDoesSupportSavePoints(): void
142
    {
Sergei Morozov's avatar
Sergei Morozov committed
143
        self::assertTrue($this->platform->supportsSavepoints());
144 145
    }

146
    public function getGenerateIndexSql(): string
147 148 149 150
    {
        return 'CREATE INDEX my_idx ON mytable (user_name, last_login)';
    }

151
    public function getGenerateUniqueIndexSql(): string
152 153 154 155
    {
        return 'CREATE UNIQUE INDEX index_name ON test (test, test2)';
    }

156
    protected function getGenerateForeignKeySql(): string
157 158 159 160 161 162 163
    {
        return 'ALTER TABLE test ADD FOREIGN KEY (fk_name_id) REFERENCES other_table (id)';
    }

    /**
     * @group DBAL-126
     */
164
    public function testUniquePrimaryKey(): void
165
    {
Sergei Morozov's avatar
Sergei Morozov committed
166 167 168 169 170
        $keyTable = new Table('foo');
        $keyTable->addColumn('bar', 'integer');
        $keyTable->addColumn('baz', 'string');
        $keyTable->setPrimaryKey(['bar']);
        $keyTable->addUniqueIndex(['baz']);
171

Sergei Morozov's avatar
Sergei Morozov committed
172 173 174
        $oldTable = new Table('foo');
        $oldTable->addColumn('bar', 'integer');
        $oldTable->addColumn('baz', 'string');
175

Sergei Morozov's avatar
Sergei Morozov committed
176
        $c    = new Comparator();
177 178
        $diff = $c->diffTable($oldTable, $keyTable);

Sergei Morozov's avatar
Sergei Morozov committed
179
        $sql = $this->platform->getAlterTableSQL($diff);
180

Sergei Morozov's avatar
Sergei Morozov committed
181 182 183 184
        self::assertEquals([
            'ALTER TABLE foo ADD PRIMARY KEY (bar)',
            'CREATE UNIQUE INDEX UNIQ_8C73652178240498 ON foo (baz)',
        ], $sql);
185 186
    }

187
    public function testModifyLimitQuery(): void
188
    {
Sergei Morozov's avatar
Sergei Morozov committed
189
        $sql = $this->platform->modifyLimitQuery('SELECT * FROM user', 10, 0);
190
        self::assertEquals('SELECT * FROM user LIMIT 10', $sql);
191 192
    }

193
    public function testModifyLimitQueryWithEmptyOffset(): void
194
    {
Sergei Morozov's avatar
Sergei Morozov committed
195
        $sql = $this->platform->modifyLimitQuery('SELECT * FROM user', 10);
196
        self::assertEquals('SELECT * FROM user LIMIT 10', $sql);
197 198 199 200 201
    }

    /**
     * @group DDC-118
     */
202
    public function testGetDateTimeTypeDeclarationSql(): void
203
    {
Sergei Morozov's avatar
Sergei Morozov committed
204 205 206
        self::assertEquals('DATETIME', $this->platform->getDateTimeTypeDeclarationSQL(['version' => false]));
        self::assertEquals('TIMESTAMP', $this->platform->getDateTimeTypeDeclarationSQL(['version' => true]));
        self::assertEquals('DATETIME', $this->platform->getDateTimeTypeDeclarationSQL([]));
207 208
    }

209 210 211
    /**
     * {@inheritDoc}
     */
212
    public function getCreateTableColumnCommentsSQL(): array
213
    {
214
        return ["CREATE TABLE test (id INT NOT NULL COMMENT 'This is a comment', PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB"];
215 216
    }

217 218 219
    /**
     * {@inheritDoc}
     */
220
    public function getAlterTableColumnCommentsSQL(): array
221
    {
Sergei Morozov's avatar
Sergei Morozov committed
222
        return ["ALTER TABLE mytable ADD quota INT NOT NULL COMMENT 'A comment', CHANGE foo foo VARCHAR(255) NOT NULL, CHANGE bar baz VARCHAR(255) NOT NULL COMMENT 'B comment'"];
223 224
    }

225 226 227
    /**
     * {@inheritDoc}
     */
228
    public function getCreateTableColumnTypeCommentsSQL(): array
229
    {
230
        return ["CREATE TABLE test (id INT NOT NULL, data LONGTEXT NOT NULL COMMENT '(DC2Type:array)', PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB"];
231 232 233 234 235
    }

    /**
     * @group DBAL-237
     */
236
    public function testChangeIndexWithForeignKeys(): void
237
    {
Sergei Morozov's avatar
Sergei Morozov committed
238 239
        $index  = new Index('idx', ['col'], false);
        $unique = new Index('uniq', ['col'], true);
240

Sergei Morozov's avatar
Sergei Morozov committed
241
        $diff = new TableDiff('test', [], [], [], [$unique], [], [$index]);
Sergei Morozov's avatar
Sergei Morozov committed
242
        $sql  = $this->platform->getAlterTableSQL($diff);
Sergei Morozov's avatar
Sergei Morozov committed
243
        self::assertEquals(['ALTER TABLE test DROP INDEX idx, ADD UNIQUE INDEX uniq (col)'], $sql);
244

Sergei Morozov's avatar
Sergei Morozov committed
245
        $diff = new TableDiff('test', [], [], [], [$index], [], [$unique]);
Sergei Morozov's avatar
Sergei Morozov committed
246
        $sql  = $this->platform->getAlterTableSQL($diff);
Sergei Morozov's avatar
Sergei Morozov committed
247
        self::assertEquals(['ALTER TABLE test DROP INDEX uniq, ADD INDEX idx (col)'], $sql);
248 249
    }

250 251 252
    /**
     * @return string[]
     */
253
    protected function getQuotedColumnInPrimaryKeySQL(): array
254
    {
255
        return ['CREATE TABLE `quoted` (`create` VARCHAR(255) NOT NULL, PRIMARY KEY(`create`)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB'];
256 257
    }

258 259 260
    /**
     * @return string[]
     */
261
    protected function getQuotedColumnInIndexSQL(): array
262
    {
263
        return ['CREATE TABLE `quoted` (`create` VARCHAR(255) NOT NULL, INDEX IDX_22660D028FD6E0FB (`create`)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB'];
264 265
    }

266 267 268
    /**
     * @return string[]
     */
269
    protected function getQuotedNameInIndexSQL(): array
Markus Fasselt's avatar
Markus Fasselt committed
270
    {
271
        return ['CREATE TABLE test (column1 VARCHAR(255) NOT NULL, INDEX `key` (column1)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB'];
Markus Fasselt's avatar
Markus Fasselt committed
272 273
    }

274 275 276
    /**
     * @return string[]
     */
277
    protected function getQuotedColumnInForeignKeySQL(): array
278
    {
Sergei Morozov's avatar
Sergei Morozov committed
279
        return [
280
            'CREATE TABLE `quoted` (`create` VARCHAR(255) NOT NULL, foo VARCHAR(255) NOT NULL, `bar` VARCHAR(255) NOT NULL) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB',
281 282 283
            'ALTER TABLE `quoted` ADD CONSTRAINT FK_WITH_RESERVED_KEYWORD FOREIGN KEY (`create`, foo, `bar`) REFERENCES `foreign` (`create`, bar, `foo-bar`)',
            'ALTER TABLE `quoted` ADD CONSTRAINT FK_WITH_NON_RESERVED_KEYWORD FOREIGN KEY (`create`, foo, `bar`) REFERENCES foo (`create`, bar, `foo-bar`)',
            'ALTER TABLE `quoted` ADD CONSTRAINT FK_WITH_INTENDED_QUOTATION FOREIGN KEY (`create`, foo, `bar`) REFERENCES `foo-bar` (`create`, bar, `foo-bar`)',
Sergei Morozov's avatar
Sergei Morozov committed
284
        ];
285 286
    }

287
    public function testCreateTableWithFulltextIndex(): void
288 289 290 291
    {
        $table = new Table('fulltext_table');
        $table->addOption('engine', 'MyISAM');
        $table->addColumn('text', 'text');
Sergei Morozov's avatar
Sergei Morozov committed
292
        $table->addIndex(['text'], 'fulltext_text');
293 294 295 296

        $index = $table->getIndex('fulltext_text');
        $index->addFlag('fulltext');

Sergei Morozov's avatar
Sergei Morozov committed
297
        $sql = $this->platform->getCreateTableSQL($table);
298
        self::assertEquals(['CREATE TABLE fulltext_table (text LONGTEXT NOT NULL, FULLTEXT INDEX fulltext_text (text)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = MyISAM'], $sql);
299 300
    }

301
    public function testCreateTableWithSpatialIndex(): void
302 303 304 305
    {
        $table = new Table('spatial_table');
        $table->addOption('engine', 'MyISAM');
        $table->addColumn('point', 'text'); // This should be a point type
Sergei Morozov's avatar
Sergei Morozov committed
306
        $table->addIndex(['point'], 'spatial_text');
307 308 309 310

        $index = $table->getIndex('spatial_text');
        $index->addFlag('spatial');

Sergei Morozov's avatar
Sergei Morozov committed
311
        $sql = $this->platform->getCreateTableSQL($table);
312
        self::assertEquals(['CREATE TABLE spatial_table (point LONGTEXT NOT NULL, SPATIAL INDEX spatial_text (point)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = MyISAM'], $sql);
313 314
    }

315
    public function testClobTypeDeclarationSQL(): void
316
    {
Sergei Morozov's avatar
Sergei Morozov committed
317 318 319 320 321 322 323 324
        self::assertEquals('TINYTEXT', $this->platform->getClobTypeDeclarationSQL(['length' => 1]));
        self::assertEquals('TINYTEXT', $this->platform->getClobTypeDeclarationSQL(['length' => 255]));
        self::assertEquals('TEXT', $this->platform->getClobTypeDeclarationSQL(['length' => 256]));
        self::assertEquals('TEXT', $this->platform->getClobTypeDeclarationSQL(['length' => 65535]));
        self::assertEquals('MEDIUMTEXT', $this->platform->getClobTypeDeclarationSQL(['length' => 65536]));
        self::assertEquals('MEDIUMTEXT', $this->platform->getClobTypeDeclarationSQL(['length' => 16777215]));
        self::assertEquals('LONGTEXT', $this->platform->getClobTypeDeclarationSQL(['length' => 16777216]));
        self::assertEquals('LONGTEXT', $this->platform->getClobTypeDeclarationSQL([]));
325 326
    }

327
    public function testBlobTypeDeclarationSQL(): void
328
    {
Sergei Morozov's avatar
Sergei Morozov committed
329 330 331 332 333 334 335 336
        self::assertEquals('TINYBLOB', $this->platform->getBlobTypeDeclarationSQL(['length' => 1]));
        self::assertEquals('TINYBLOB', $this->platform->getBlobTypeDeclarationSQL(['length' => 255]));
        self::assertEquals('BLOB', $this->platform->getBlobTypeDeclarationSQL(['length' => 256]));
        self::assertEquals('BLOB', $this->platform->getBlobTypeDeclarationSQL(['length' => 65535]));
        self::assertEquals('MEDIUMBLOB', $this->platform->getBlobTypeDeclarationSQL(['length' => 65536]));
        self::assertEquals('MEDIUMBLOB', $this->platform->getBlobTypeDeclarationSQL(['length' => 16777215]));
        self::assertEquals('LONGBLOB', $this->platform->getBlobTypeDeclarationSQL(['length' => 16777216]));
        self::assertEquals('LONGBLOB', $this->platform->getBlobTypeDeclarationSQL([]));
337 338 339 340 341
    }

    /**
     * @group DBAL-400
     */
342
    public function testAlterTableAddPrimaryKey(): void
343 344 345 346
    {
        $table = new Table('alter_table_add_pk');
        $table->addColumn('id', 'integer');
        $table->addColumn('foo', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
347
        $table->addIndex(['id'], 'idx_id');
348 349 350 351 352

        $comparator = new Comparator();
        $diffTable  = clone $table;

        $diffTable->dropIndex('idx_id');
Sergei Morozov's avatar
Sergei Morozov committed
353
        $diffTable->setPrimaryKey(['id']);
354

355
        self::assertEquals(
Sergei Morozov's avatar
Sergei Morozov committed
356
            ['DROP INDEX idx_id ON alter_table_add_pk', 'ALTER TABLE alter_table_add_pk ADD PRIMARY KEY (id)'],
Sergei Morozov's avatar
Sergei Morozov committed
357
            $this->platform->getAlterTableSQL($comparator->diffTable($table, $diffTable))
358 359 360
        );
    }

361
    /**
362
     * @group DBAL-1132
363
     */
364
    public function testAlterPrimaryKeyWithAutoincrementColumn(): void
365
    {
Sergei Morozov's avatar
Sergei Morozov committed
366 367
        $table = new Table('alter_primary_key');
        $table->addColumn('id', 'integer', ['autoincrement' => true]);
368
        $table->addColumn('foo', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
369
        $table->setPrimaryKey(['id']);
370 371

        $comparator = new Comparator();
Sergei Morozov's avatar
Sergei Morozov committed
372
        $diffTable  = clone $table;
373 374

        $diffTable->dropPrimaryKey();
Sergei Morozov's avatar
Sergei Morozov committed
375
        $diffTable->setPrimaryKey(['foo']);
376

377
        self::assertEquals(
Sergei Morozov's avatar
Sergei Morozov committed
378
            [
Steve Müller's avatar
Steve Müller committed
379 380
                'ALTER TABLE alter_primary_key MODIFY id INT NOT NULL',
                'ALTER TABLE alter_primary_key DROP PRIMARY KEY',
Sergei Morozov's avatar
Sergei Morozov committed
381 382
                'ALTER TABLE alter_primary_key ADD PRIMARY KEY (foo)',
            ],
Sergei Morozov's avatar
Sergei Morozov committed
383
            $this->platform->getAlterTableSQL($comparator->diffTable($table, $diffTable))
384 385 386
        );
    }

387 388 389
    /**
     * @group DBAL-464
     */
390
    public function testDropPrimaryKeyWithAutoincrementColumn(): void
391
    {
Sergei Morozov's avatar
Sergei Morozov committed
392 393
        $table = new Table('drop_primary_key');
        $table->addColumn('id', 'integer', ['autoincrement' => true]);
andig's avatar
andig committed
394
        $table->addColumn('foo', 'integer');
395
        $table->addColumn('bar', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
396
        $table->setPrimaryKey(['id', 'foo']);
397 398

        $comparator = new Comparator();
Sergei Morozov's avatar
Sergei Morozov committed
399
        $diffTable  = clone $table;
400 401 402

        $diffTable->dropPrimaryKey();

403
        self::assertEquals(
Sergei Morozov's avatar
Sergei Morozov committed
404
            [
405
                'ALTER TABLE drop_primary_key MODIFY id INT NOT NULL',
Sergei Morozov's avatar
Sergei Morozov committed
406 407
                'ALTER TABLE drop_primary_key DROP PRIMARY KEY',
            ],
Sergei Morozov's avatar
Sergei Morozov committed
408
            $this->platform->getAlterTableSQL($comparator->diffTable($table, $diffTable))
409 410 411
        );
    }

412 413 414
    /**
     * @group DBAL-2302
     */
415
    public function testDropNonAutoincrementColumnFromCompositePrimaryKeyWithAutoincrementColumn(): void
416
    {
Sergei Morozov's avatar
Sergei Morozov committed
417 418
        $table = new Table('tbl');
        $table->addColumn('id', 'integer', ['autoincrement' => true]);
419 420
        $table->addColumn('foo', 'integer');
        $table->addColumn('bar', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
421
        $table->setPrimaryKey(['id', 'foo']);
422 423

        $comparator = new Comparator();
Sergei Morozov's avatar
Sergei Morozov committed
424
        $diffTable  = clone $table;
425 426

        $diffTable->dropPrimaryKey();
Sergei Morozov's avatar
Sergei Morozov committed
427
        $diffTable->setPrimaryKey(['id']);
428

429
        self::assertSame(
Sergei Morozov's avatar
Sergei Morozov committed
430
            [
431 432 433
                'ALTER TABLE tbl MODIFY id INT NOT NULL',
                'ALTER TABLE tbl DROP PRIMARY KEY',
                'ALTER TABLE tbl ADD PRIMARY KEY (id)',
Sergei Morozov's avatar
Sergei Morozov committed
434
            ],
Sergei Morozov's avatar
Sergei Morozov committed
435
            $this->platform->getAlterTableSQL($comparator->diffTable($table, $diffTable))
436 437 438
        );
    }

439 440 441
    /**
     * @group DBAL-2302
     */
442
    public function testAddNonAutoincrementColumnToPrimaryKeyWithAutoincrementColumn(): void
443
    {
Sergei Morozov's avatar
Sergei Morozov committed
444 445
        $table = new Table('tbl');
        $table->addColumn('id', 'integer', ['autoincrement' => true]);
446 447
        $table->addColumn('foo', 'integer');
        $table->addColumn('bar', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
448
        $table->setPrimaryKey(['id']);
449 450

        $comparator = new Comparator();
Sergei Morozov's avatar
Sergei Morozov committed
451
        $diffTable  = clone $table;
452 453

        $diffTable->dropPrimaryKey();
Sergei Morozov's avatar
Sergei Morozov committed
454
        $diffTable->setPrimaryKey(['id', 'foo']);
455

456
        self::assertSame(
Sergei Morozov's avatar
Sergei Morozov committed
457
            [
458 459 460
                'ALTER TABLE tbl MODIFY id INT NOT NULL',
                'ALTER TABLE tbl DROP PRIMARY KEY',
                'ALTER TABLE tbl ADD PRIMARY KEY (id, foo)',
Sergei Morozov's avatar
Sergei Morozov committed
461
            ],
Sergei Morozov's avatar
Sergei Morozov committed
462
            $this->platform->getAlterTableSQL($comparator->diffTable($table, $diffTable))
463 464 465
        );
    }

466 467 468
    /**
     * @group DBAL-586
     */
469
    public function testAddAutoIncrementPrimaryKey(): void
470
    {
Sergei Morozov's avatar
Sergei Morozov committed
471 472 473 474
        $keyTable = new Table('foo');
        $keyTable->addColumn('id', 'integer', ['autoincrement' => true]);
        $keyTable->addColumn('baz', 'string');
        $keyTable->setPrimaryKey(['id']);
475

Sergei Morozov's avatar
Sergei Morozov committed
476 477
        $oldTable = new Table('foo');
        $oldTable->addColumn('baz', 'string');
478

Sergei Morozov's avatar
Sergei Morozov committed
479
        $c    = new Comparator();
480 481
        $diff = $c->diffTable($oldTable, $keyTable);

Sergei Morozov's avatar
Sergei Morozov committed
482
        $sql = $this->platform->getAlterTableSQL($diff);
483

Sergei Morozov's avatar
Sergei Morozov committed
484
        self::assertEquals(['ALTER TABLE foo ADD id INT AUTO_INCREMENT NOT NULL, ADD PRIMARY KEY (id)'], $sql);
485 486
    }

487
    public function testNamedPrimaryKey(): void
488
    {
Sergei Morozov's avatar
Sergei Morozov committed
489 490
        $diff                              = new TableDiff('mytable');
        $diff->changedIndexes['foo_index'] = new Index('foo_index', ['foo'], true, true);
491

Sergei Morozov's avatar
Sergei Morozov committed
492
        $sql = $this->platform->getAlterTableSQL($diff);
493

Sergei Morozov's avatar
Sergei Morozov committed
494 495 496 497
        self::assertEquals([
            'ALTER TABLE mytable DROP PRIMARY KEY',
            'ALTER TABLE mytable ADD PRIMARY KEY (foo)',
        ], $sql);
498
    }
499

500
    public function testAlterPrimaryKeyWithNewColumn(): void
501
    {
Sergei Morozov's avatar
Sergei Morozov committed
502
        $table = new Table('yolo');
503 504
        $table->addColumn('pkc1', 'integer');
        $table->addColumn('col_a', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
505
        $table->setPrimaryKey(['pkc1']);
506 507

        $comparator = new Comparator();
Sergei Morozov's avatar
Sergei Morozov committed
508
        $diffTable  = clone $table;
509

510 511
        $diffTable->addColumn('pkc2', 'integer');
        $diffTable->dropPrimaryKey();
Sergei Morozov's avatar
Sergei Morozov committed
512
        $diffTable->setPrimaryKey(['pkc1', 'pkc2']);
513

514
        self::assertSame(
Sergei Morozov's avatar
Sergei Morozov committed
515
            [
516 517 518
                'ALTER TABLE yolo DROP PRIMARY KEY',
                'ALTER TABLE yolo ADD pkc2 INT NOT NULL',
                'ALTER TABLE yolo ADD PRIMARY KEY (pkc1, pkc2)',
Sergei Morozov's avatar
Sergei Morozov committed
519
            ],
Sergei Morozov's avatar
Sergei Morozov committed
520
            $this->platform->getAlterTableSQL($comparator->diffTable($table, $diffTable))
521
        );
522
    }
523

524
    public function testInitializesDoctrineTypeMappings(): void
525
    {
Sergei Morozov's avatar
Sergei Morozov committed
526 527
        self::assertTrue($this->platform->hasDoctrineTypeMappingFor('binary'));
        self::assertSame('binary', $this->platform->getDoctrineTypeMapping('binary'));
528

Sergei Morozov's avatar
Sergei Morozov committed
529 530
        self::assertTrue($this->platform->hasDoctrineTypeMappingFor('varbinary'));
        self::assertSame('binary', $this->platform->getDoctrineTypeMapping('varbinary'));
531 532
    }

533
    protected function getBinaryMaxLength(): int
534 535 536 537
    {
        return 65535;
    }

538
    public function testReturnsBinaryTypeDeclarationSQL(): void
539
    {
Sergei Morozov's avatar
Sergei Morozov committed
540 541 542
        self::assertSame('VARBINARY(255)', $this->platform->getBinaryTypeDeclarationSQL([]));
        self::assertSame('VARBINARY(255)', $this->platform->getBinaryTypeDeclarationSQL(['length' => 0]));
        self::assertSame('VARBINARY(65535)', $this->platform->getBinaryTypeDeclarationSQL(['length' => 65535]));
543

Sergei Morozov's avatar
Sergei Morozov committed
544 545 546
        self::assertSame('BINARY(255)', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true]));
        self::assertSame('BINARY(255)', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 0]));
        self::assertSame('BINARY(65535)', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 65535]));
547 548 549 550
    }

    /**
     * @group legacy
551 552 553
     * @expectedDeprecation Binary field length 65536 is greater than supported by the platform (65535). Reduce the field length or use a BLOB field instead.
     * @expectedDeprecation Binary field length 16777215 is greater than supported by the platform (65535). Reduce the field length or use a BLOB field instead.
     * @expectedDeprecation Binary field length 16777216 is greater than supported by the platform (65535). Reduce the field length or use a BLOB field instead.
554
     */
555
    public function testReturnsBinaryTypeLongerThanMaxDeclarationSQL(): void
556
    {
Sergei Morozov's avatar
Sergei Morozov committed
557 558 559
        self::assertSame('MEDIUMBLOB', $this->platform->getBinaryTypeDeclarationSQL(['length' => 65536]));
        self::assertSame('MEDIUMBLOB', $this->platform->getBinaryTypeDeclarationSQL(['length' => 16777215]));
        self::assertSame('LONGBLOB', $this->platform->getBinaryTypeDeclarationSQL(['length' => 16777216]));
560

Sergei Morozov's avatar
Sergei Morozov committed
561 562 563
        self::assertSame('MEDIUMBLOB', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 65536]));
        self::assertSame('MEDIUMBLOB', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 16777215]));
        self::assertSame('LONGBLOB', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 16777216]));
564 565
    }

566
    public function testDoesNotPropagateForeignKeyCreationForNonSupportingEngines(): void
567
    {
Sergei Morozov's avatar
Sergei Morozov committed
568
        $table = new Table('foreign_table');
569 570
        $table->addColumn('id', 'integer');
        $table->addColumn('fk_id', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
571 572
        $table->addForeignKeyConstraint('foreign_table', ['fk_id'], ['id']);
        $table->setPrimaryKey(['id']);
573 574
        $table->addOption('engine', 'MyISAM');

575
        self::assertSame(
576
            ['CREATE TABLE foreign_table (id INT NOT NULL, fk_id INT NOT NULL, INDEX IDX_5690FFE2A57719D0 (fk_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = MyISAM'],
Sergei Morozov's avatar
Sergei Morozov committed
577
            $this->platform->getCreateTableSQL(
578
                $table,
579
                AbstractPlatform::CREATE_INDEXES | AbstractPlatform::CREATE_FOREIGNKEYS
580 581 582 583 584 585
            )
        );

        $table = clone $table;
        $table->addOption('engine', 'InnoDB');

586
        self::assertSame(
Sergei Morozov's avatar
Sergei Morozov committed
587
            [
588
                'CREATE TABLE foreign_table (id INT NOT NULL, fk_id INT NOT NULL, INDEX IDX_5690FFE2A57719D0 (fk_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB',
Sergei Morozov's avatar
Sergei Morozov committed
589 590
                'ALTER TABLE foreign_table ADD CONSTRAINT FK_5690FFE2A57719D0 FOREIGN KEY (fk_id) REFERENCES foreign_table (id)',
            ],
Sergei Morozov's avatar
Sergei Morozov committed
591
            $this->platform->getCreateTableSQL(
592
                $table,
593
                AbstractPlatform::CREATE_INDEXES | AbstractPlatform::CREATE_FOREIGNKEYS
594 595 596 597
            )
        );
    }

598
    public function testDoesNotPropagateForeignKeyAlterationForNonSupportingEngines(): void
599
    {
Sergei Morozov's avatar
Sergei Morozov committed
600
        $table = new Table('foreign_table');
601 602
        $table->addColumn('id', 'integer');
        $table->addColumn('fk_id', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
603 604
        $table->addForeignKeyConstraint('foreign_table', ['fk_id'], ['id']);
        $table->setPrimaryKey(['id']);
605 606
        $table->addOption('engine', 'MyISAM');

Sergei Morozov's avatar
Sergei Morozov committed
607 608 609
        $addedForeignKeys   = [new ForeignKeyConstraint(['fk_id'], 'foo', ['id'], 'fk_add')];
        $changedForeignKeys = [new ForeignKeyConstraint(['fk_id'], 'bar', ['id'], 'fk_change')];
        $removedForeignKeys = [new ForeignKeyConstraint(['fk_id'], 'baz', ['id'], 'fk_remove')];
610

Sergei Morozov's avatar
Sergei Morozov committed
611 612 613
        $tableDiff                     = new TableDiff('foreign_table');
        $tableDiff->fromTable          = $table;
        $tableDiff->addedForeignKeys   = $addedForeignKeys;
614 615 616
        $tableDiff->changedForeignKeys = $changedForeignKeys;
        $tableDiff->removedForeignKeys = $removedForeignKeys;

Sergei Morozov's avatar
Sergei Morozov committed
617
        self::assertEmpty($this->platform->getAlterTableSQL($tableDiff));
618 619 620

        $table->addOption('engine', 'InnoDB');

Sergei Morozov's avatar
Sergei Morozov committed
621 622 623
        $tableDiff                     = new TableDiff('foreign_table');
        $tableDiff->fromTable          = $table;
        $tableDiff->addedForeignKeys   = $addedForeignKeys;
624 625 626
        $tableDiff->changedForeignKeys = $changedForeignKeys;
        $tableDiff->removedForeignKeys = $removedForeignKeys;

627
        self::assertSame(
Sergei Morozov's avatar
Sergei Morozov committed
628
            [
629 630 631 632
                'ALTER TABLE foreign_table DROP FOREIGN KEY fk_remove',
                'ALTER TABLE foreign_table DROP FOREIGN KEY fk_change',
                'ALTER TABLE foreign_table ADD CONSTRAINT fk_add FOREIGN KEY (fk_id) REFERENCES foo (id)',
                'ALTER TABLE foreign_table ADD CONSTRAINT fk_change FOREIGN KEY (fk_id) REFERENCES bar (id)',
Sergei Morozov's avatar
Sergei Morozov committed
633
            ],
Sergei Morozov's avatar
Sergei Morozov committed
634
            $this->platform->getAlterTableSQL($tableDiff)
635 636 637 638
        );
    }

    /**
639 640
     * @return string[]
     *
641 642
     * @group DBAL-234
     */
643
    protected function getAlterTableRenameIndexSQL(): array
644
    {
Sergei Morozov's avatar
Sergei Morozov committed
645
        return [
646 647
            'DROP INDEX idx_foo ON mytable',
            'CREATE INDEX idx_bar ON mytable (id)',
Sergei Morozov's avatar
Sergei Morozov committed
648
        ];
649 650 651
    }

    /**
652 653
     * @return string[]
     *
654 655
     * @group DBAL-234
     */
656
    protected function getQuotedAlterTableRenameIndexSQL(): array
657
    {
Sergei Morozov's avatar
Sergei Morozov committed
658
        return [
659 660 661 662
            'DROP INDEX `create` ON `table`',
            'CREATE INDEX `select` ON `table` (id)',
            'DROP INDEX `foo` ON `table`',
            'CREATE INDEX `bar` ON `table` (id)',
Sergei Morozov's avatar
Sergei Morozov committed
663
        ];
664
    }
665

666
    /**
667 668
     * @return string[]
     *
669 670
     * @group DBAL-807
     */
671
    protected function getAlterTableRenameIndexInSchemaSQL(): array
672
    {
Sergei Morozov's avatar
Sergei Morozov committed
673
        return [
674 675
            'DROP INDEX idx_foo ON myschema.mytable',
            'CREATE INDEX idx_bar ON myschema.mytable (id)',
Sergei Morozov's avatar
Sergei Morozov committed
676
        ];
677 678 679
    }

    /**
680 681
     * @return string[]
     *
682 683
     * @group DBAL-807
     */
684
    protected function getQuotedAlterTableRenameIndexInSchemaSQL(): array
685
    {
Sergei Morozov's avatar
Sergei Morozov committed
686
        return [
687 688 689 690
            'DROP INDEX `create` ON `schema`.`table`',
            'CREATE INDEX `select` ON `schema`.`table` (id)',
            'DROP INDEX `foo` ON `schema`.`table`',
            'CREATE INDEX `bar` ON `schema`.`table` (id)',
Sergei Morozov's avatar
Sergei Morozov committed
691
        ];
692 693
    }

694
    protected function getQuotesDropForeignKeySQL(): string
695 696 697 698
    {
        return 'ALTER TABLE `table` DROP FOREIGN KEY `select`';
    }

699
    protected function getQuotesDropConstraintSQL(): string
700 701 702 703
    {
        return 'ALTER TABLE `table` DROP CONSTRAINT `select`';
    }

704
    public function testDoesNotPropagateDefaultValuesForUnsupportedColumnTypes(): void
705
    {
Sergei Morozov's avatar
Sergei Morozov committed
706 707 708 709 710
        $table = new Table('text_blob_default_value');
        $table->addColumn('def_text', 'text', ['default' => 'def']);
        $table->addColumn('def_text_null', 'text', ['notnull' => false, 'default' => 'def']);
        $table->addColumn('def_blob', 'blob', ['default' => 'def']);
        $table->addColumn('def_blob_null', 'blob', ['notnull' => false, 'default' => 'def']);
711

712
        self::assertSame(
713
            ['CREATE TABLE text_blob_default_value (def_text LONGTEXT NOT NULL, def_text_null LONGTEXT DEFAULT NULL, def_blob LONGBLOB NOT NULL, def_blob_null LONGBLOB DEFAULT NULL) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB'],
Sergei Morozov's avatar
Sergei Morozov committed
714
            $this->platform->getCreateTableSQL($table)
715 716 717
        );

        $diffTable = clone $table;
Sergei Morozov's avatar
Sergei Morozov committed
718 719 720 721
        $diffTable->changeColumn('def_text', ['default' => null]);
        $diffTable->changeColumn('def_text_null', ['default' => null]);
        $diffTable->changeColumn('def_blob', ['default' => null]);
        $diffTable->changeColumn('def_blob_null', ['default' => null]);
722 723 724

        $comparator = new Comparator();

Sergei Morozov's avatar
Sergei Morozov committed
725
        self::assertEmpty($this->platform->getAlterTableSQL($comparator->diffTable($table, $diffTable)));
726
    }
727 728 729 730

    /**
     * {@inheritdoc}
     */
731
    protected function getQuotedAlterTableRenameColumnSQL(): array
732
    {
Sergei Morozov's avatar
Sergei Morozov committed
733
        return ['ALTER TABLE mytable ' .
734 735 736 737 738 739 740 741
            "CHANGE unquoted1 unquoted INT NOT NULL COMMENT 'Unquoted 1', " .
            "CHANGE unquoted2 `where` INT NOT NULL COMMENT 'Unquoted 2', " .
            "CHANGE unquoted3 `foo` INT NOT NULL COMMENT 'Unquoted 3', " .
            "CHANGE `create` reserved_keyword INT NOT NULL COMMENT 'Reserved keyword 1', " .
            "CHANGE `table` `from` INT NOT NULL COMMENT 'Reserved keyword 2', " .
            "CHANGE `select` `bar` INT NOT NULL COMMENT 'Reserved keyword 3', " .
            "CHANGE quoted1 quoted INT NOT NULL COMMENT 'Quoted 1', " .
            "CHANGE quoted2 `and` INT NOT NULL COMMENT 'Quoted 2', " .
Sergei Morozov's avatar
Sergei Morozov committed
742 743
            "CHANGE quoted3 `baz` INT NOT NULL COMMENT 'Quoted 3'",
        ];
744
    }
745 746 747 748

    /**
     * {@inheritdoc}
     */
749
    protected function getQuotedAlterTableChangeColumnLengthSQL(): array
750
    {
Sergei Morozov's avatar
Sergei Morozov committed
751
        return ['ALTER TABLE mytable ' .
752 753 754 755 756
            "CHANGE unquoted1 unquoted1 VARCHAR(255) NOT NULL COMMENT 'Unquoted 1', " .
            "CHANGE unquoted2 unquoted2 VARCHAR(255) NOT NULL COMMENT 'Unquoted 2', " .
            "CHANGE unquoted3 unquoted3 VARCHAR(255) NOT NULL COMMENT 'Unquoted 3', " .
            "CHANGE `create` `create` VARCHAR(255) NOT NULL COMMENT 'Reserved keyword 1', " .
            "CHANGE `table` `table` VARCHAR(255) NOT NULL COMMENT 'Reserved keyword 2', " .
Sergei Morozov's avatar
Sergei Morozov committed
757 758
            "CHANGE `select` `select` VARCHAR(255) NOT NULL COMMENT 'Reserved keyword 3'",
        ];
759
    }
760 761 762 763

    /**
     * @group DBAL-423
     */
764
    public function testReturnsGuidTypeDeclarationSQL(): void
765
    {
Sergei Morozov's avatar
Sergei Morozov committed
766
        self::assertSame('CHAR(36)', $this->platform->getGuidTypeDeclarationSQL([]));
767
    }
768 769 770 771

    /**
     * {@inheritdoc}
     */
772
    public function getAlterTableRenameColumnSQL(): array
773
    {
Sergei Morozov's avatar
Sergei Morozov committed
774
        return ["ALTER TABLE foo CHANGE bar baz INT DEFAULT 666 NOT NULL COMMENT 'rename test'"];
775
    }
776 777 778 779

    /**
     * {@inheritdoc}
     */
780
    protected function getQuotesTableIdentifiersInAlterTableSQL(): array
781
    {
Sergei Morozov's avatar
Sergei Morozov committed
782
        return [
783 784 785 786 787 788
            'ALTER TABLE `foo` DROP FOREIGN KEY fk1',
            'ALTER TABLE `foo` DROP FOREIGN KEY fk2',
            'ALTER TABLE `foo` RENAME TO `table`, ADD bloo INT NOT NULL, DROP baz, CHANGE bar bar INT DEFAULT NULL, ' .
            'CHANGE id war INT NOT NULL',
            'ALTER TABLE `table` ADD CONSTRAINT fk_add FOREIGN KEY (fk3) REFERENCES fk_table (id)',
            'ALTER TABLE `table` ADD CONSTRAINT fk2 FOREIGN KEY (fk2) REFERENCES fk_table2 (id)',
Sergei Morozov's avatar
Sergei Morozov committed
789
        ];
790
    }
791 792 793 794

    /**
     * {@inheritdoc}
     */
795
    protected function getCommentOnColumnSQL(): array
796
    {
Sergei Morozov's avatar
Sergei Morozov committed
797
        return [
798 799 800
            "COMMENT ON COLUMN foo.bar IS 'comment'",
            "COMMENT ON COLUMN `Foo`.`BAR` IS 'comment'",
            "COMMENT ON COLUMN `select`.`from` IS 'comment'",
Sergei Morozov's avatar
Sergei Morozov committed
801
        ];
802
    }
803

804
    protected function getQuotesReservedKeywordInUniqueConstraintDeclarationSQL(): string
805 806 807 808
    {
        return 'CONSTRAINT `select` UNIQUE (foo)';
    }

809
    protected function getQuotesReservedKeywordInIndexDeclarationSQL(): string
810 811 812
    {
        return 'INDEX `select` (foo)';
    }
813

814
    protected function getQuotesReservedKeywordInTruncateTableSQL(): string
815 816 817 818
    {
        return 'TRUNCATE `select`';
    }

819 820 821
    /**
     * {@inheritdoc}
     */
822
    protected function getAlterStringToFixedStringSQL(): array
823
    {
Sergei Morozov's avatar
Sergei Morozov committed
824
        return ['ALTER TABLE mytable CHANGE name name CHAR(2) NOT NULL'];
825
    }
826 827 828 829

    /**
     * {@inheritdoc}
     */
830
    protected function getGeneratesAlterTableRenameIndexUsedByForeignKeySQL(): array
831
    {
Sergei Morozov's avatar
Sergei Morozov committed
832
        return [
833 834 835 836
            'ALTER TABLE mytable DROP FOREIGN KEY fk_foo',
            'DROP INDEX idx_foo ON mytable',
            'CREATE INDEX idx_foo_renamed ON mytable (foo)',
            'ALTER TABLE mytable ADD CONSTRAINT fk_foo FOREIGN KEY (foo) REFERENCES foreign_table (id)',
Sergei Morozov's avatar
Sergei Morozov committed
837
        ];
838
    }
839 840 841 842

    /**
     * {@inheritdoc}
     */
843
    public static function getGeneratesDecimalTypeDeclarationSQL(): iterable
844
    {
Sergei Morozov's avatar
Sergei Morozov committed
845 846 847 848 849 850 851 852
        return [
            [[], 'NUMERIC(10, 0)'],
            [['unsigned' => true], 'NUMERIC(10, 0) UNSIGNED'],
            [['unsigned' => false], 'NUMERIC(10, 0)'],
            [['precision' => 5], 'NUMERIC(5, 0)'],
            [['scale' => 5], 'NUMERIC(10, 5)'],
            [['precision' => 8, 'scale' => 2], 'NUMERIC(8, 2)'],
        ];
853 854 855 856 857
    }

    /**
     * {@inheritdoc}
     */
858
    public static function getGeneratesFloatDeclarationSQL(): iterable
859
    {
Sergei Morozov's avatar
Sergei Morozov committed
860 861 862 863 864 865 866 867
        return [
            [[], 'DOUBLE PRECISION'],
            [['unsigned' => true], 'DOUBLE PRECISION UNSIGNED'],
            [['unsigned' => false], 'DOUBLE PRECISION'],
            [['precision' => 5], 'DOUBLE PRECISION'],
            [['scale' => 5], 'DOUBLE PRECISION'],
            [['precision' => 8, 'scale' => 2], 'DOUBLE PRECISION'],
        ];
868
    }
869 870 871 872

    /**
     * @group DBAL-2436
     */
873
    public function testQuotesTableNameInListTableIndexesSQL(): void
874
    {
875 876 877 878
        self::assertStringContainsStringIgnoringCase(
            "'Foo''Bar\\\\'",
            $this->platform->getListTableIndexesSQL("Foo'Bar\\", 'foo_db')
        );
879 880 881 882 883
    }

    /**
     * @group DBAL-2436
     */
884
    public function testQuotesDatabaseNameInListTableIndexesSQL(): void
885
    {
886 887 888 889
        self::assertStringContainsStringIgnoringCase(
            "'Foo''Bar\\\\'",
            $this->platform->getListTableIndexesSQL('foo_table', "Foo'Bar\\")
        );
890 891 892 893 894
    }

    /**
     * @group DBAL-2436
     */
895
    public function testQuotesDatabaseNameInListViewsSQL(): void
896
    {
897 898 899 900
        self::assertStringContainsStringIgnoringCase(
            "'Foo''Bar\\\\'",
            $this->platform->getListViewsSQL("Foo'Bar\\")
        );
901 902 903 904 905
    }

    /**
     * @group DBAL-2436
     */
906
    public function testQuotesTableNameInListTableForeignKeysSQL(): void
907
    {
908 909 910 911
        self::assertStringContainsStringIgnoringCase(
            "'Foo''Bar\\\\'",
            $this->platform->getListTableForeignKeysSQL("Foo'Bar\\")
        );
912 913 914 915 916
    }

    /**
     * @group DBAL-2436
     */
917
    public function testQuotesDatabaseNameInListTableForeignKeysSQL(): void
918
    {
919 920 921 922
        self::assertStringContainsStringIgnoringCase(
            "'Foo''Bar\\\\'",
            $this->platform->getListTableForeignKeysSQL('foo_table', "Foo'Bar\\")
        );
923 924 925 926 927
    }

    /**
     * @group DBAL-2436
     */
928
    public function testQuotesTableNameInListTableColumnsSQL(): void
929
    {
930 931 932 933
        self::assertStringContainsStringIgnoringCase(
            "'Foo''Bar\\\\'",
            $this->platform->getListTableColumnsSQL("Foo'Bar\\")
        );
934 935 936 937 938
    }

    /**
     * @group DBAL-2436
     */
939
    public function testQuotesDatabaseNameInListTableColumnsSQL(): void
940
    {
941 942 943 944
        self::assertStringContainsStringIgnoringCase(
            "'Foo''Bar\\\\'",
            $this->platform->getListTableColumnsSQL('foo_table', "Foo'Bar\\")
        );
945
    }
946

947
    public function testListTableForeignKeysSQLEvaluatesDatabase(): void
948
    {
Sergei Morozov's avatar
Sergei Morozov committed
949
        $sql = $this->platform->getListTableForeignKeysSQL('foo');
950

951
        self::assertStringContainsString('DATABASE()', $sql);
952

Sergei Morozov's avatar
Sergei Morozov committed
953
        $sql = $this->platform->getListTableForeignKeysSQL('foo', 'bar');
954

955 956
        self::assertStringContainsString('bar', $sql);
        self::assertStringNotContainsString('DATABASE()', $sql);
957
    }
958

959
    public function testColumnCharsetDeclarationSQL(): void
960 961 962 963 964 965 966
    {
        self::assertSame(
            'CHARACTER SET ascii',
            $this->platform->getColumnCharsetDeclarationSQL('ascii')
        );
    }

967
    public function testSupportsColumnCollation(): void
968
    {
Sergei Morozov's avatar
Sergei Morozov committed
969
        self::assertTrue($this->platform->supportsColumnCollation());
970 971
    }

972
    public function testColumnCollationDeclarationSQL(): void
973 974
    {
        self::assertSame(
975
            'COLLATE `ascii_general_ci`',
Sergei Morozov's avatar
Sergei Morozov committed
976
            $this->platform->getColumnCollationDeclarationSQL('ascii_general_ci')
977 978 979
        );
    }

980
    public function testGetCreateTableSQLWithColumnCollation(): void
981 982 983 984 985 986
    {
        $table = new Table('foo');
        $table->addColumn('no_collation', 'string');
        $table->addColumn('column_collation', 'string')->setPlatformOption('collation', 'ascii_general_ci');

        self::assertSame(
987
            ['CREATE TABLE foo (no_collation VARCHAR(255) NOT NULL, column_collation VARCHAR(255) NOT NULL COLLATE `ascii_general_ci`) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB'],
Sergei Morozov's avatar
Sergei Morozov committed
988
            $this->platform->getCreateTableSQL($table),
989 990 991
            'Column "no_collation" will use the default collation from the table/database and "column_collation" overwrites the collation on this column'
        );
    }
992
}