SqlitePlatformTest.php 28.2 KB
Newer Older
1 2 3 4
<?php

namespace Doctrine\Tests\DBAL\Platforms;

jeroendedauw's avatar
jeroendedauw committed
5 6
use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\Platforms\SqlitePlatform;
7
use Doctrine\DBAL\Schema\Column;
jeroendedauw's avatar
jeroendedauw committed
8
use Doctrine\DBAL\Schema\Table;
9
use Doctrine\DBAL\Schema\TableDiff;
10
use Doctrine\DBAL\TransactionIsolationLevel;
11
use Doctrine\DBAL\Types\Type;
12

13
class SqlitePlatformTest extends AbstractPlatformTestCase
14
{
15
    public function createPlatform()
16
    {
Sergei Morozov's avatar
Sergei Morozov committed
17
        return new SqlitePlatform();
18 19
    }

20
    public function getGenerateTableSql()
21
    {
Timo Bakx's avatar
Timo Bakx committed
22
        return 'CREATE TABLE test (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, test VARCHAR(255) DEFAULT NULL)';
23 24
    }

25 26
    public function getGenerateTableWithMultiColumnUniqueIndexSql()
    {
Sergei Morozov's avatar
Sergei Morozov committed
27
        return [
28
            'CREATE TABLE test (foo VARCHAR(255) DEFAULT NULL, bar VARCHAR(255) DEFAULT NULL)',
29
            'CREATE UNIQUE INDEX UNIQ_D87F7E0C8C73652176FF8CAA ON test (foo, bar)',
Sergei Morozov's avatar
Sergei Morozov committed
30
        ];
31 32
    }

33
    public function testGeneratesSqlSnippets()
34
    {
Sergei Morozov's avatar
Sergei Morozov committed
35 36 37
        self::assertEquals('REGEXP', $this->platform->getRegexpExpression(), 'Regular expression operator is not correct');
        self::assertEquals('SUBSTR(column, 5, LENGTH(column))', $this->platform->getSubstringExpression('column', 5), 'Substring expression without length is not correct');
        self::assertEquals('SUBSTR(column, 0, 5)', $this->platform->getSubstringExpression('column', 0, 5), 'Substring expression with length is not correct');
38 39
    }

40
    public function testGeneratesTransactionCommands()
41
    {
42
        self::assertEquals(
43
            'PRAGMA read_uncommitted = 0',
Sergei Morozov's avatar
Sergei Morozov committed
44
            $this->platform->getSetTransactionIsolationSQL(TransactionIsolationLevel::READ_UNCOMMITTED)
45
        );
46
        self::assertEquals(
47
            'PRAGMA read_uncommitted = 1',
Sergei Morozov's avatar
Sergei Morozov committed
48
            $this->platform->getSetTransactionIsolationSQL(TransactionIsolationLevel::READ_COMMITTED)
49
        );
50
        self::assertEquals(
51
            'PRAGMA read_uncommitted = 1',
Sergei Morozov's avatar
Sergei Morozov committed
52
            $this->platform->getSetTransactionIsolationSQL(TransactionIsolationLevel::REPEATABLE_READ)
53
        );
54
        self::assertEquals(
55
            'PRAGMA read_uncommitted = 1',
Sergei Morozov's avatar
Sergei Morozov committed
56
            $this->platform->getSetTransactionIsolationSQL(TransactionIsolationLevel::SERIALIZABLE)
57
        );
58 59
    }

60
    public function testPrefersIdentityColumns()
61
    {
Sergei Morozov's avatar
Sergei Morozov committed
62
        self::assertTrue($this->platform->prefersIdentityColumns());
63 64
    }

65 66
    public function testIgnoresUnsignedIntegerDeclarationForAutoIncrementalIntegers()
    {
67
        self::assertSame(
Timo Bakx's avatar
Timo Bakx committed
68
            'INTEGER PRIMARY KEY AUTOINCREMENT',
Sergei Morozov's avatar
Sergei Morozov committed
69
            $this->platform->getIntegerTypeDeclarationSQL(['autoincrement' => true, 'unsigned' => true])
70 71 72
        );
    }

73 74
    /**
     * @group DBAL-752
75
     * @group DBAL-924
76 77 78
     */
    public function testGeneratesTypeDeclarationForTinyIntegers()
    {
79
        self::assertEquals(
80
            'TINYINT',
Sergei Morozov's avatar
Sergei Morozov committed
81
            $this->platform->getTinyIntTypeDeclarationSQL([])
82
        );
83
        self::assertEquals(
Timo Bakx's avatar
Timo Bakx committed
84
            'INTEGER PRIMARY KEY AUTOINCREMENT',
Sergei Morozov's avatar
Sergei Morozov committed
85
            $this->platform->getTinyIntTypeDeclarationSQL(['autoincrement' => true])
86
        );
87
        self::assertEquals(
Timo Bakx's avatar
Timo Bakx committed
88
            'INTEGER PRIMARY KEY AUTOINCREMENT',
Sergei Morozov's avatar
Sergei Morozov committed
89
            $this->platform->getTinyIntTypeDeclarationSQL(
Sergei Morozov's avatar
Sergei Morozov committed
90 91
                ['autoincrement' => true, 'primary' => true]
            )
92
        );
93
        self::assertEquals(
94
            'TINYINT',
Sergei Morozov's avatar
Sergei Morozov committed
95
            $this->platform->getTinyIntTypeDeclarationSQL(['unsigned' => false])
96
        );
97
        self::assertEquals(
98
            'TINYINT UNSIGNED',
Sergei Morozov's avatar
Sergei Morozov committed
99
            $this->platform->getTinyIntTypeDeclarationSQL(['unsigned' => true])
100 101 102 103 104
        );
    }

    /**
     * @group DBAL-752
105
     * @group DBAL-924
106 107 108
     */
    public function testGeneratesTypeDeclarationForSmallIntegers()
    {
109
        self::assertEquals(
110
            'SMALLINT',
Sergei Morozov's avatar
Sergei Morozov committed
111
            $this->platform->getSmallIntTypeDeclarationSQL([])
112
        );
113
        self::assertEquals(
Timo Bakx's avatar
Timo Bakx committed
114
            'INTEGER PRIMARY KEY AUTOINCREMENT',
Sergei Morozov's avatar
Sergei Morozov committed
115
            $this->platform->getSmallIntTypeDeclarationSQL(['autoincrement' => true])
116
        );
117
        self::assertEquals(
Timo Bakx's avatar
Timo Bakx committed
118
            'INTEGER PRIMARY KEY AUTOINCREMENT',
Sergei Morozov's avatar
Sergei Morozov committed
119
            $this->platform->getTinyIntTypeDeclarationSQL(['autoincrement' => true, 'unsigned' => true])
120
        );
121
        self::assertEquals(
Timo Bakx's avatar
Timo Bakx committed
122
            'INTEGER PRIMARY KEY AUTOINCREMENT',
Sergei Morozov's avatar
Sergei Morozov committed
123
            $this->platform->getSmallIntTypeDeclarationSQL(
Sergei Morozov's avatar
Sergei Morozov committed
124 125
                ['autoincrement' => true, 'primary' => true]
            )
126
        );
127
        self::assertEquals(
128
            'SMALLINT',
Sergei Morozov's avatar
Sergei Morozov committed
129
            $this->platform->getSmallIntTypeDeclarationSQL(['unsigned' => false])
130
        );
131
        self::assertEquals(
132
            'SMALLINT UNSIGNED',
Sergei Morozov's avatar
Sergei Morozov committed
133
            $this->platform->getSmallIntTypeDeclarationSQL(['unsigned' => true])
134 135 136 137 138
        );
    }

    /**
     * @group DBAL-752
139
     * @group DBAL-924
140 141 142
     */
    public function testGeneratesTypeDeclarationForMediumIntegers()
    {
143
        self::assertEquals(
144
            'MEDIUMINT',
Sergei Morozov's avatar
Sergei Morozov committed
145
            $this->platform->getMediumIntTypeDeclarationSQL([])
146
        );
147
        self::assertEquals(
Timo Bakx's avatar
Timo Bakx committed
148
            'INTEGER PRIMARY KEY AUTOINCREMENT',
Sergei Morozov's avatar
Sergei Morozov committed
149
            $this->platform->getMediumIntTypeDeclarationSQL(['autoincrement' => true])
150
        );
151
        self::assertEquals(
Timo Bakx's avatar
Timo Bakx committed
152
            'INTEGER PRIMARY KEY AUTOINCREMENT',
Sergei Morozov's avatar
Sergei Morozov committed
153
            $this->platform->getMediumIntTypeDeclarationSQL(['autoincrement' => true, 'unsigned' => true])
154
        );
155
        self::assertEquals(
Timo Bakx's avatar
Timo Bakx committed
156
            'INTEGER PRIMARY KEY AUTOINCREMENT',
Sergei Morozov's avatar
Sergei Morozov committed
157
            $this->platform->getMediumIntTypeDeclarationSQL(
Sergei Morozov's avatar
Sergei Morozov committed
158 159
                ['autoincrement' => true, 'primary' => true]
            )
160
        );
161
        self::assertEquals(
162
            'MEDIUMINT',
Sergei Morozov's avatar
Sergei Morozov committed
163
            $this->platform->getMediumIntTypeDeclarationSQL(['unsigned' => false])
164
        );
165
        self::assertEquals(
166
            'MEDIUMINT UNSIGNED',
Sergei Morozov's avatar
Sergei Morozov committed
167
            $this->platform->getMediumIntTypeDeclarationSQL(['unsigned' => true])
168 169 170
        );
    }

171
    public function testGeneratesTypeDeclarationForIntegers()
172
    {
173
        self::assertEquals(
174
            'INTEGER',
Sergei Morozov's avatar
Sergei Morozov committed
175
            $this->platform->getIntegerTypeDeclarationSQL([])
176
        );
177
        self::assertEquals(
Timo Bakx's avatar
Timo Bakx committed
178
            'INTEGER PRIMARY KEY AUTOINCREMENT',
Sergei Morozov's avatar
Sergei Morozov committed
179
            $this->platform->getIntegerTypeDeclarationSQL(['autoincrement' => true])
180
        );
181
        self::assertEquals(
Timo Bakx's avatar
Timo Bakx committed
182
            'INTEGER PRIMARY KEY AUTOINCREMENT',
Sergei Morozov's avatar
Sergei Morozov committed
183
            $this->platform->getIntegerTypeDeclarationSQL(['autoincrement' => true, 'unsigned' => true])
184
        );
185
        self::assertEquals(
Timo Bakx's avatar
Timo Bakx committed
186
            'INTEGER PRIMARY KEY AUTOINCREMENT',
Sergei Morozov's avatar
Sergei Morozov committed
187
            $this->platform->getIntegerTypeDeclarationSQL(
Sergei Morozov's avatar
Sergei Morozov committed
188 189
                ['autoincrement' => true, 'primary' => true]
            )
190
        );
191
        self::assertEquals(
192
            'INTEGER',
Sergei Morozov's avatar
Sergei Morozov committed
193
            $this->platform->getIntegerTypeDeclarationSQL(['unsigned' => false])
194
        );
195
        self::assertEquals(
196
            'INTEGER UNSIGNED',
Sergei Morozov's avatar
Sergei Morozov committed
197
            $this->platform->getIntegerTypeDeclarationSQL(['unsigned' => true])
198 199 200 201 202
        );
    }

    /**
     * @group DBAL-752
203
     * @group DBAL-924
204 205 206
     */
    public function testGeneratesTypeDeclarationForBigIntegers()
    {
207
        self::assertEquals(
208
            'BIGINT',
Sergei Morozov's avatar
Sergei Morozov committed
209
            $this->platform->getBigIntTypeDeclarationSQL([])
210
        );
211
        self::assertEquals(
Timo Bakx's avatar
Timo Bakx committed
212
            'INTEGER PRIMARY KEY AUTOINCREMENT',
Sergei Morozov's avatar
Sergei Morozov committed
213
            $this->platform->getBigIntTypeDeclarationSQL(['autoincrement' => true])
214
        );
215
        self::assertEquals(
Timo Bakx's avatar
Timo Bakx committed
216
            'INTEGER PRIMARY KEY AUTOINCREMENT',
Sergei Morozov's avatar
Sergei Morozov committed
217
            $this->platform->getBigIntTypeDeclarationSQL(['autoincrement' => true, 'unsigned' => true])
218
        );
219
        self::assertEquals(
Timo Bakx's avatar
Timo Bakx committed
220
            'INTEGER PRIMARY KEY AUTOINCREMENT',
Sergei Morozov's avatar
Sergei Morozov committed
221
            $this->platform->getBigIntTypeDeclarationSQL(
Sergei Morozov's avatar
Sergei Morozov committed
222 223
                ['autoincrement' => true, 'primary' => true]
            )
224
        );
225
        self::assertEquals(
226
            'BIGINT',
Sergei Morozov's avatar
Sergei Morozov committed
227
            $this->platform->getBigIntTypeDeclarationSQL(['unsigned' => false])
228
        );
229
        self::assertEquals(
230
            'BIGINT UNSIGNED',
Sergei Morozov's avatar
Sergei Morozov committed
231
            $this->platform->getBigIntTypeDeclarationSQL(['unsigned' => true])
232
        );
233 234 235 236
    }

    public function testGeneratesTypeDeclarationForStrings()
    {
237
        self::assertEquals(
238
            'CHAR(10)',
Sergei Morozov's avatar
Sergei Morozov committed
239
            $this->platform->getVarcharTypeDeclarationSQL(
Sergei Morozov's avatar
Sergei Morozov committed
240 241
                ['length' => 10, 'fixed' => true]
            )
242
        );
243
        self::assertEquals(
244
            'VARCHAR(50)',
Sergei Morozov's avatar
Sergei Morozov committed
245
            $this->platform->getVarcharTypeDeclarationSQL(['length' => 50]),
246
            'Variable string declaration is not correct'
247
        );
248
        self::assertEquals(
249
            'VARCHAR(255)',
Sergei Morozov's avatar
Sergei Morozov committed
250
            $this->platform->getVarcharTypeDeclarationSQL([]),
251
            'Long string declaration is not correct'
252
        );
253
    }
254

255 256 257 258 259 260
    public function getGenerateIndexSql()
    {
        return 'CREATE INDEX my_idx ON mytable (user_name, last_login)';
    }

    public function getGenerateUniqueIndexSql()
261
    {
262
        return 'CREATE UNIQUE INDEX index_name ON test (test, test2)';
263 264
    }

265 266 267 268 269 270 271 272
    /**
     * @expectedException \Doctrine\DBAL\DBALException
     */
    public function testGeneratesForeignKeyCreationSql()
    {
        parent::testGeneratesForeignKeyCreationSql();
    }

273 274 275 276 277 278 279 280
    /**
     * @expectedException \Doctrine\DBAL\DBALException
     */
    public function testGeneratesConstraintCreationSql()
    {
        parent::testGeneratesConstraintCreationSql();
    }

281
    public function getGenerateForeignKeySql()
282
    {
283
        return null;
284
    }
285 286 287

    public function testModifyLimitQuery()
    {
Sergei Morozov's avatar
Sergei Morozov committed
288
        $sql = $this->platform->modifyLimitQuery('SELECT * FROM user', 10, 0);
289
        self::assertEquals('SELECT * FROM user LIMIT 10', $sql);
290 291 292 293
    }

    public function testModifyLimitQueryWithEmptyOffset()
    {
Sergei Morozov's avatar
Sergei Morozov committed
294
        $sql = $this->platform->modifyLimitQuery('SELECT * FROM user', 10);
295
        self::assertEquals('SELECT * FROM user LIMIT 10', $sql);
296
    }
297

298 299
    public function testModifyLimitQueryWithOffsetAndEmptyLimit()
    {
Sergei Morozov's avatar
Sergei Morozov committed
300
        $sql = $this->platform->modifyLimitQuery('SELECT * FROM user', null, 10);
301
        self::assertEquals('SELECT * FROM user LIMIT -1 OFFSET 10', $sql);
302 303
    }

304 305
    public function getGenerateAlterTableSql()
    {
Sergei Morozov's avatar
Sergei Morozov committed
306 307 308
        return [
            'CREATE TEMPORARY TABLE __temp__mytable AS SELECT id, bar, bloo FROM mytable',
            'DROP TABLE mytable',
Timo Bakx's avatar
Timo Bakx committed
309
            "CREATE TABLE mytable (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, baz VARCHAR(255) DEFAULT 'def' NOT NULL, bloo BOOLEAN DEFAULT '0' NOT NULL, quota INTEGER DEFAULT NULL)",
Sergei Morozov's avatar
Sergei Morozov committed
310 311 312 313
            'INSERT INTO mytable (id, baz, bloo) SELECT id, bar, bloo FROM __temp__mytable',
            'DROP TABLE __temp__mytable',
            'ALTER TABLE mytable RENAME TO userlist',
        ];
314
    }
Fabio B. Silva's avatar
Fabio B. Silva committed
315 316 317 318 319 320

    /**
     * @group DDC-1845
     */
    public function testGenerateTableSqlShouldNotAutoQuotePrimaryKey()
    {
Sergei Morozov's avatar
Sergei Morozov committed
321 322 323
        $table = new Table('test');
        $table->addColumn('"like"', 'integer', ['notnull' => true, 'autoincrement' => true]);
        $table->setPrimaryKey(['"like"']);
Fabio B. Silva's avatar
Fabio B. Silva committed
324

Sergei Morozov's avatar
Sergei Morozov committed
325
        $createTableSQL = $this->platform->getCreateTableSQL($table);
326
        self::assertEquals(
Timo Bakx's avatar
Timo Bakx committed
327
            'CREATE TABLE test ("like" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)',
Fabio B. Silva's avatar
Fabio B. Silva committed
328 329 330
            $createTableSQL[0]
        );
    }
331

332 333
    public function testAlterTableAddColumns()
    {
Sergei Morozov's avatar
Sergei Morozov committed
334 335 336
        $diff                        = new TableDiff('user');
        $diff->addedColumns['foo']   = new Column('foo', Type::getType('string'));
        $diff->addedColumns['count'] = new Column('count', Type::getType('integer'), ['notnull' => false, 'default' => 1]);
337

Sergei Morozov's avatar
Sergei Morozov committed
338
        $expected = [
339 340
            'ALTER TABLE user ADD COLUMN foo VARCHAR(255) NOT NULL',
            'ALTER TABLE user ADD COLUMN count INTEGER DEFAULT 1',
Sergei Morozov's avatar
Sergei Morozov committed
341
        ];
342

Sergei Morozov's avatar
Sergei Morozov committed
343
        self::assertEquals($expected, $this->platform->getAlterTableSQL($diff));
344 345
    }

Luís Cobucci's avatar
Luís Cobucci committed
346 347 348 349
    /**
     * @dataProvider complexDiffProvider
     */
    public function testAlterTableAddComplexColumns(TableDiff $diff) : void
350
    {
Luís Cobucci's avatar
Luís Cobucci committed
351 352
        $this->expectException(DBALException::class);

Sergei Morozov's avatar
Sergei Morozov committed
353
        $this->platform->getAlterTableSQL($diff);
Luís Cobucci's avatar
Luís Cobucci committed
354 355
    }

Sergei Morozov's avatar
Sergei Morozov committed
356
    /** @return mixed[] */
Luís Cobucci's avatar
Luís Cobucci committed
357 358
    public function complexDiffProvider() : array
    {
Sergei Morozov's avatar
Sergei Morozov committed
359 360
        $date                       = new TableDiff('user');
        $date->addedColumns['time'] = new Column('time', Type::getType('date'), ['default' => 'CURRENT_DATE']);
361

Sergei Morozov's avatar
Sergei Morozov committed
362 363
        $id                     = new TableDiff('user');
        $id->addedColumns['id'] = new Column('id', Type::getType('integer'), ['autoincrement' => true]);
364

Luís Cobucci's avatar
Luís Cobucci committed
365 366 367 368
        return [
            'date column with default value' => [$date],
            'id column with auto increment'  => [$id],
        ];
369 370
    }

371 372 373 374 375 376 377
    public function testCreateTableWithDeferredForeignKeys()
    {
        $table = new Table('user');
        $table->addColumn('id', 'integer');
        $table->addColumn('article', 'integer');
        $table->addColumn('post', 'integer');
        $table->addColumn('parent', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
378 379 380 381
        $table->setPrimaryKey(['id']);
        $table->addForeignKeyConstraint('article', ['article'], ['id'], ['deferrable' => true]);
        $table->addForeignKeyConstraint('post', ['post'], ['id'], ['deferred' => true]);
        $table->addForeignKeyConstraint('user', ['parent'], ['id'], ['deferrable' => true, 'deferred' => true]);
382

Sergei Morozov's avatar
Sergei Morozov committed
383
        $sql = [
384
            'CREATE TABLE user ('
385 386
                . 'id INTEGER NOT NULL, article INTEGER NOT NULL, post INTEGER NOT NULL, parent INTEGER NOT NULL'
                . ', PRIMARY KEY(id)'
387 388 389 390 391 392 393
                . ', CONSTRAINT FK_8D93D64923A0E66 FOREIGN KEY (article) REFERENCES article (id) DEFERRABLE INITIALLY IMMEDIATE'
                . ', CONSTRAINT FK_8D93D6495A8A6C8D FOREIGN KEY (post) REFERENCES post (id) NOT DEFERRABLE INITIALLY DEFERRED'
                . ', CONSTRAINT FK_8D93D6493D8E604F FOREIGN KEY (parent) REFERENCES user (id) DEFERRABLE INITIALLY DEFERRED'
                . ')',
            'CREATE INDEX IDX_8D93D64923A0E66 ON user (article)',
            'CREATE INDEX IDX_8D93D6495A8A6C8D ON user (post)',
            'CREATE INDEX IDX_8D93D6493D8E604F ON user (parent)',
Sergei Morozov's avatar
Sergei Morozov committed
394
        ];
395

Sergei Morozov's avatar
Sergei Morozov committed
396
        self::assertEquals($sql, $this->platform->getCreateTableSQL($table));
397 398
    }

399 400 401 402 403 404 405
    public function testAlterTable()
    {
        $table = new Table('user');
        $table->addColumn('id', 'integer');
        $table->addColumn('article', 'integer');
        $table->addColumn('post', 'integer');
        $table->addColumn('parent', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
406 407 408 409 410 411 412 413 414 415 416 417
        $table->setPrimaryKey(['id']);
        $table->addForeignKeyConstraint('article', ['article'], ['id'], ['deferrable' => true]);
        $table->addForeignKeyConstraint('post', ['post'], ['id'], ['deferred' => true]);
        $table->addForeignKeyConstraint('user', ['parent'], ['id'], ['deferrable' => true, 'deferred' => true]);
        $table->addIndex(['article', 'post'], 'index1');

        $diff                           = new TableDiff('user');
        $diff->fromTable                = $table;
        $diff->newName                  = 'client';
        $diff->renamedColumns['id']     = new Column('key', Type::getType('integer'), []);
        $diff->renamedColumns['post']   = new Column('comment', Type::getType('integer'), []);
        $diff->removedColumns['parent'] = new Column('comment', Type::getType('integer'), []);
418 419
        $diff->removedIndexes['index1'] = $table->getIndex('index1');

Sergei Morozov's avatar
Sergei Morozov committed
420
        $sql = [
421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437
            'DROP INDEX IDX_8D93D64923A0E66',
            'DROP INDEX IDX_8D93D6495A8A6C8D',
            'DROP INDEX IDX_8D93D6493D8E604F',
            'DROP INDEX index1',
            'CREATE TEMPORARY TABLE __temp__user AS SELECT id, article, post FROM user',
            'DROP TABLE user',
            'CREATE TABLE user ('
                . '"key" INTEGER NOT NULL, article INTEGER NOT NULL, comment INTEGER NOT NULL'
                . ', PRIMARY KEY("key")'
                . ', CONSTRAINT FK_8D93D64923A0E66 FOREIGN KEY (article) REFERENCES article (id) DEFERRABLE INITIALLY IMMEDIATE'
                . ', CONSTRAINT FK_8D93D6495A8A6C8D FOREIGN KEY (comment) REFERENCES post (id) NOT DEFERRABLE INITIALLY DEFERRED'
                . ')',
            'INSERT INTO user ("key", article, comment) SELECT id, article, post FROM __temp__user',
            'DROP TABLE __temp__user',
            'ALTER TABLE user RENAME TO client',
            'CREATE INDEX IDX_8D93D64923A0E66 ON client (article)',
            'CREATE INDEX IDX_8D93D6495A8A6C8D ON client (comment)',
Sergei Morozov's avatar
Sergei Morozov committed
438
        ];
439

Sergei Morozov's avatar
Sergei Morozov committed
440
        self::assertEquals($sql, $this->platform->getAlterTableSQL($diff));
441 442
    }

443 444
    protected function getQuotedColumnInPrimaryKeySQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
445
        return ['CREATE TABLE "quoted" ("create" VARCHAR(255) NOT NULL, PRIMARY KEY("create"))'];
446 447 448 449
    }

    protected function getQuotedColumnInIndexSQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
450
        return [
451 452
            'CREATE TABLE "quoted" ("create" VARCHAR(255) NOT NULL)',
            'CREATE INDEX IDX_22660D028FD6E0FB ON "quoted" ("create")',
Sergei Morozov's avatar
Sergei Morozov committed
453
        ];
454 455
    }

Markus Fasselt's avatar
Markus Fasselt committed
456 457
    protected function getQuotedNameInIndexSQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
458
        return [
Markus Fasselt's avatar
Markus Fasselt committed
459 460
            'CREATE TABLE test (column1 VARCHAR(255) NOT NULL)',
            'CREATE INDEX "key" ON test (column1)',
Sergei Morozov's avatar
Sergei Morozov committed
461
        ];
Markus Fasselt's avatar
Markus Fasselt committed
462 463
    }

464 465
    protected function getQuotedColumnInForeignKeySQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
466
        return [
467 468 469 470 471
            'CREATE TABLE "quoted" (' .
            '"create" VARCHAR(255) NOT NULL, foo VARCHAR(255) NOT NULL, "bar" VARCHAR(255) NOT NULL, ' .
            'CONSTRAINT FK_WITH_RESERVED_KEYWORD FOREIGN KEY ("create", foo, "bar") REFERENCES "foreign" ("create", bar, "foo-bar") NOT DEFERRABLE INITIALLY IMMEDIATE, ' .
            'CONSTRAINT FK_WITH_NON_RESERVED_KEYWORD FOREIGN KEY ("create", foo, "bar") REFERENCES foo ("create", bar, "foo-bar") NOT DEFERRABLE INITIALLY IMMEDIATE, ' .
            'CONSTRAINT FK_WITH_INTENDED_QUOTATION FOREIGN KEY ("create", foo, "bar") REFERENCES "foo-bar" ("create", bar, "foo-bar") NOT DEFERRABLE INITIALLY IMMEDIATE)',
Sergei Morozov's avatar
Sergei Morozov committed
472
        ];
473
    }
Steve Müller's avatar
Steve Müller committed
474 475 476 477 478 479 480 481 482 483 484 485 486

    protected function getBinaryDefaultLength()
    {
        return 0;
    }

    protected function getBinaryMaxLength()
    {
        return 0;
    }

    public function testReturnsBinaryTypeDeclarationSQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
487 488 489
        self::assertSame('BLOB', $this->platform->getBinaryTypeDeclarationSQL([]));
        self::assertSame('BLOB', $this->platform->getBinaryTypeDeclarationSQL(['length' => 0]));
        self::assertSame('BLOB', $this->platform->getBinaryTypeDeclarationSQL(['length' => 9999999]));
Steve Müller's avatar
Steve Müller committed
490

Sergei Morozov's avatar
Sergei Morozov committed
491 492 493
        self::assertSame('BLOB', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true]));
        self::assertSame('BLOB', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 0]));
        self::assertSame('BLOB', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 9999999]));
Steve Müller's avatar
Steve Müller committed
494
    }
495 496 497 498 499 500

    /**
     * @group DBAL-234
     */
    protected function getAlterTableRenameIndexSQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
501
        return [
502 503 504 505 506 507
            'CREATE TEMPORARY TABLE __temp__mytable AS SELECT id FROM mytable',
            'DROP TABLE mytable',
            'CREATE TABLE mytable (id INTEGER NOT NULL, PRIMARY KEY(id))',
            'INSERT INTO mytable (id) SELECT id FROM __temp__mytable',
            'DROP TABLE __temp__mytable',
            'CREATE INDEX idx_bar ON mytable (id)',
Sergei Morozov's avatar
Sergei Morozov committed
508
        ];
509 510 511 512 513 514 515
    }

    /**
     * @group DBAL-234
     */
    protected function getQuotedAlterTableRenameIndexSQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
516
        return [
517 518 519 520 521
            'CREATE TEMPORARY TABLE __temp__table AS SELECT id FROM "table"',
            'DROP TABLE "table"',
            'CREATE TABLE "table" (id INTEGER NOT NULL, PRIMARY KEY(id))',
            'INSERT INTO "table" (id) SELECT id FROM __temp__table',
            'DROP TABLE __temp__table',
522 523
            'CREATE INDEX "select" ON "table" (id)',
            'CREATE INDEX "bar" ON "table" (id)',
Sergei Morozov's avatar
Sergei Morozov committed
524
        ];
525
    }
526 527 528 529 530 531

    /**
     * {@inheritdoc}
     */
    protected function getQuotedAlterTableRenameColumnSQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
532
        return [
533 534
            'CREATE TEMPORARY TABLE __temp__mytable AS SELECT unquoted1, unquoted2, unquoted3, "create", "table", "select", "quoted1", "quoted2", "quoted3" FROM mytable',
            'DROP TABLE mytable',
535 536 537 538 539 540 541 542 543 544
            'CREATE TABLE mytable (unquoted INTEGER NOT NULL --Unquoted 1
, "where" INTEGER NOT NULL --Unquoted 2
, "foo" INTEGER NOT NULL --Unquoted 3
, reserved_keyword INTEGER NOT NULL --Reserved keyword 1
, "from" INTEGER NOT NULL --Reserved keyword 2
, "bar" INTEGER NOT NULL --Reserved keyword 3
, quoted INTEGER NOT NULL --Quoted 1
, "and" INTEGER NOT NULL --Quoted 2
, "baz" INTEGER NOT NULL --Quoted 3
)',
545 546
            'INSERT INTO mytable (unquoted, "where", "foo", reserved_keyword, "from", "bar", quoted, "and", "baz") SELECT unquoted1, unquoted2, unquoted3, "create", "table", "select", "quoted1", "quoted2", "quoted3" FROM __temp__mytable',
            'DROP TABLE __temp__mytable',
Sergei Morozov's avatar
Sergei Morozov committed
547
        ];
548
    }
549 550 551 552 553 554

    /**
     * {@inheritdoc}
     */
    protected function getQuotedAlterTableChangeColumnLengthSQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
555
        return [
556 557
            'CREATE TEMPORARY TABLE __temp__mytable AS SELECT unquoted1, unquoted2, unquoted3, "create", "table", "select" FROM mytable',
            'DROP TABLE mytable',
558 559 560 561 562 563 564
            'CREATE TABLE mytable (unquoted1 VARCHAR(255) NOT NULL --Unquoted 1
, unquoted2 VARCHAR(255) NOT NULL --Unquoted 2
, unquoted3 VARCHAR(255) NOT NULL --Unquoted 3
, "create" VARCHAR(255) NOT NULL --Reserved keyword 1
, "table" VARCHAR(255) NOT NULL --Reserved keyword 2
, "select" VARCHAR(255) NOT NULL --Reserved keyword 3
)',
565 566
            'INSERT INTO mytable (unquoted1, unquoted2, unquoted3, "create", "table", "select") SELECT unquoted1, unquoted2, unquoted3, "create", "table", "select" FROM __temp__mytable',
            'DROP TABLE __temp__mytable',
Sergei Morozov's avatar
Sergei Morozov committed
567
        ];
568
    }
569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590

    /**
     * @group DBAL-807
     */
    public function testAlterTableRenameIndexInSchema()
    {
        $this->markTestIncomplete(
            'Test currently produces broken SQL due to SQLLitePlatform::getAlterTable being broken ' .
            'when used with schemas.'
        );
    }

    /**
     * @group DBAL-807
     */
    public function testQuotesAlterTableRenameIndexInSchema()
    {
        $this->markTestIncomplete(
            'Test currently produces broken SQL due to SQLLitePlatform::getAlterTable being broken ' .
            'when used with schemas.'
        );
    }
591 592 593 594 595 596

    /**
     * @group DBAL-423
     */
    public function testReturnsGuidTypeDeclarationSQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
597
        self::assertSame('CHAR(36)', $this->platform->getGuidTypeDeclarationSQL([]));
598
    }
599 600 601 602 603 604

    /**
     * {@inheritdoc}
     */
    public function getAlterTableRenameColumnSQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
605
        return [
606 607
            'CREATE TEMPORARY TABLE __temp__foo AS SELECT bar FROM foo',
            'DROP TABLE foo',
608 609
            'CREATE TABLE foo (baz INTEGER DEFAULT 666 NOT NULL --rename test
)',
610 611
            'INSERT INTO foo (baz) SELECT bar FROM __temp__foo',
            'DROP TABLE __temp__foo',
Sergei Morozov's avatar
Sergei Morozov committed
612
        ];
613
    }
614 615 616 617 618 619

    /**
     * {@inheritdoc}
     */
    protected function getQuotesTableIdentifiersInAlterTableSQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
620
        return [
621 622 623 624 625 626 627 628 629 630 631 632 633
            'DROP INDEX IDX_8C736521A81E660E',
            'DROP INDEX IDX_8C736521FDC58D6C',
            'CREATE TEMPORARY TABLE __temp__foo AS SELECT fk, fk2, id, fk3, bar FROM "foo"',
            'DROP TABLE "foo"',
            'CREATE TABLE "foo" (fk2 INTEGER NOT NULL, fk3 INTEGER NOT NULL, fk INTEGER NOT NULL, war INTEGER NOT NULL, ' .
            'bar INTEGER DEFAULT NULL, bloo INTEGER NOT NULL, ' .
            'CONSTRAINT fk2 FOREIGN KEY (fk2) REFERENCES fk_table2 (id) NOT DEFERRABLE INITIALLY IMMEDIATE, ' .
            'CONSTRAINT fk_add FOREIGN KEY (fk3) REFERENCES fk_table (id) NOT DEFERRABLE INITIALLY IMMEDIATE)',
            'INSERT INTO "foo" (fk, fk2, war, fk3, bar) SELECT fk, fk2, id, fk3, bar FROM __temp__foo',
            'DROP TABLE __temp__foo',
            'ALTER TABLE "foo" RENAME TO "table"',
            'CREATE INDEX IDX_8C736521A81E660E ON "table" (fk)',
            'CREATE INDEX IDX_8C736521FDC58D6C ON "table" (fk2)',
Sergei Morozov's avatar
Sergei Morozov committed
634
        ];
635
    }
636 637 638 639 640 641

    /**
     * {@inheritdoc}
     */
    protected function getCommentOnColumnSQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
642
        return [
643 644 645
            '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
646
        ];
647
    }
648

649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668
    protected function getInlineColumnCommentDelimiter()
    {
        return "\n";
    }

    protected function getInlineColumnRegularCommentSQL()
    {
        return "--Regular comment\n";
    }

    protected function getInlineColumnCommentRequiringEscapingSQL()
    {
        return "--Using inline comment delimiter \n-- works\n";
    }

    protected function getInlineColumnEmptyCommentSQL()
    {
        return "--\n";
    }

669 670 671 672 673 674 675 676 677 678 679 680 681 682 683
    /**
     * {@inheritdoc}
     */
    protected function getQuotesReservedKeywordInUniqueConstraintDeclarationSQL()
    {
        return 'CONSTRAINT "select" UNIQUE (foo)';
    }

    /**
     * {@inheritdoc}
     */
    protected function getQuotesReservedKeywordInIndexDeclarationSQL()
    {
        return 'INDEX "select" (foo)';
    }
684

685 686 687 688 689 690 691 692
    /**
     * {@inheritdoc}
     */
    protected function getQuotesReservedKeywordInTruncateTableSQL()
    {
        return 'DELETE FROM "select"';
    }

693 694 695 696 697
    /**
     * {@inheritdoc}
     */
    protected function getAlterStringToFixedStringSQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
698
        return [
699 700 701 702 703
            'CREATE TEMPORARY TABLE __temp__mytable AS SELECT name FROM mytable',
            'DROP TABLE mytable',
            'CREATE TABLE mytable (name CHAR(2) NOT NULL)',
            'INSERT INTO mytable (name) SELECT name FROM __temp__mytable',
            'DROP TABLE __temp__mytable',
Sergei Morozov's avatar
Sergei Morozov committed
704
        ];
705
    }
706 707 708 709 710 711

    /**
     * {@inheritdoc}
     */
    protected function getGeneratesAlterTableRenameIndexUsedByForeignKeySQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
712
        return [
713 714 715 716 717 718 719 720 721
            'DROP INDEX idx_foo',
            'DROP INDEX idx_bar',
            'CREATE TEMPORARY TABLE __temp__mytable AS SELECT foo, bar, baz FROM mytable',
            'DROP TABLE mytable',
            'CREATE TABLE mytable (foo INTEGER NOT NULL, bar INTEGER NOT NULL, baz INTEGER NOT NULL, CONSTRAINT fk_foo FOREIGN KEY (foo) REFERENCES foreign_table (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT fk_bar FOREIGN KEY (bar) REFERENCES foreign_table (id) NOT DEFERRABLE INITIALLY IMMEDIATE)',
            'INSERT INTO mytable (foo, bar, baz) SELECT foo, bar, baz FROM __temp__mytable',
            'DROP TABLE __temp__mytable',
            'CREATE INDEX idx_bar ON mytable (bar)',
            'CREATE INDEX idx_foo_renamed ON mytable (foo)',
Sergei Morozov's avatar
Sergei Morozov committed
722
        ];
723
    }
724 725 726 727 728 729

    /**
     * @group DBAL-2436
     */
    public function testQuotesTableNameInListTableConstraintsSQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
730
        self::assertContains("'Foo''Bar\\'", $this->platform->getListTableConstraintsSQL("Foo'Bar\\"), '', true);
731 732 733 734 735 736 737
    }

    /**
     * @group DBAL-2436
     */
    public function testQuotesTableNameInListTableColumnsSQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
738
        self::assertContains("'Foo''Bar\\'", $this->platform->getListTableColumnsSQL("Foo'Bar\\"), '', true);
739 740 741 742 743 744 745
    }

    /**
     * @group DBAL-2436
     */
    public function testQuotesTableNameInListTableIndexesSQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
746
        self::assertContains("'Foo''Bar\\'", $this->platform->getListTableIndexesSQL("Foo'Bar\\"), '', true);
747 748 749 750 751 752 753
    }

    /**
     * @group DBAL-2436
     */
    public function testQuotesTableNameInListTableForeignKeysSQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
754
        self::assertContains("'Foo''Bar\\'", $this->platform->getListTableForeignKeysSQL("Foo'Bar\\"), '', true);
755
    }
756 757 758

    public function testDateAddStaticNumberOfDays()
    {
Sergei Morozov's avatar
Sergei Morozov committed
759
        self::assertSame("DATE(rentalBeginsOn,'+12 DAY')", $this->platform->getDateAddDaysExpression('rentalBeginsOn', 12));
760 761 762 763
    }

    public function testDateAddNumberOfDaysFromColumn()
    {
Sergei Morozov's avatar
Sergei Morozov committed
764
        self::assertSame("DATE(rentalBeginsOn,'+' || duration || ' DAY')", $this->platform->getDateAddDaysExpression('rentalBeginsOn', 'duration'));
765
    }
766 767 768

    public function testSupportsColumnCollation() : void
    {
Sergei Morozov's avatar
Sergei Morozov committed
769
        self::assertTrue($this->platform->supportsColumnCollation());
770 771 772 773 774 775
    }

    public function testColumnCollationDeclarationSQL() : void
    {
        self::assertSame(
            'COLLATE NOCASE',
Sergei Morozov's avatar
Sergei Morozov committed
776
            $this->platform->getColumnCollationDeclarationSQL('NOCASE')
777 778 779 780 781 782 783 784 785 786 787
        );
    }

    public function testGetCreateTableSQLWithColumnCollation() : void
    {
        $table = new Table('foo');
        $table->addColumn('no_collation', 'string');
        $table->addColumn('column_collation', 'string')->setPlatformOption('collation', 'NOCASE');

        self::assertSame(
            ['CREATE TABLE foo (no_collation VARCHAR(255) NOT NULL, column_collation VARCHAR(255) NOT NULL COLLATE NOCASE)'],
Sergei Morozov's avatar
Sergei Morozov committed
788
            $this->platform->getCreateTableSQL($table),
789 790 791
            'Column "no_collation" will use the default collation (BINARY) and "column_collation" overwrites the collation on this column'
        );
    }
792
}