PostgreSqlSchemaManagerTest.php 20.3 KB
Newer Older
1 2
<?php

3
namespace Doctrine\DBAL\Tests\Functional\Schema;
4

jeroendedauw's avatar
jeroendedauw committed
5
use Doctrine\DBAL\Platforms\AbstractPlatform;
6
use Doctrine\DBAL\Platforms\PostgreSQL94Platform;
7
use Doctrine\DBAL\Schema;
8
use Doctrine\DBAL\Schema\Comparator;
Sergei Morozov's avatar
Sergei Morozov committed
9
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
10 11
use Doctrine\DBAL\Schema\Table;
use Doctrine\DBAL\Schema\TableDiff;
Sergei Morozov's avatar
Sergei Morozov committed
12 13
use Doctrine\DBAL\Types\BlobType;
use Doctrine\DBAL\Types\DecimalType;
14
use Doctrine\DBAL\Types\Type;
15
use Doctrine\DBAL\Types\Types;
16 17 18 19
use function array_map;
use function array_pop;
use function count;
use function strtolower;
20

romanb's avatar
romanb committed
21
class PostgreSqlSchemaManagerTest extends SchemaManagerFunctionalTestCase
22
{
23
    protected function tearDown() : void
24 25
    {
        parent::tearDown();
26

Sergei Morozov's avatar
Sergei Morozov committed
27
        if (! $this->connection) {
28 29 30
            return;
        }

Sergei Morozov's avatar
Sergei Morozov committed
31
        $this->connection->getConfiguration()->setFilterSchemaAssetsExpression(null);
32
    }
33

34 35 36
    /**
     * @group DBAL-177
     */
37
    public function testGetSearchPath() : void
38
    {
Sergei Morozov's avatar
Sergei Morozov committed
39
        $params = $this->connection->getParams();
40

Sergei Morozov's avatar
Sergei Morozov committed
41
        $paths = $this->schemaManager->getSchemaSearchPaths();
42
        self::assertEquals([$params['user'], 'public'], $paths);
43 44
    }

45 46 47
    /**
     * @group DBAL-244
     */
48
    public function testGetSchemaNames() : void
49
    {
Sergei Morozov's avatar
Sergei Morozov committed
50
        $names = $this->schemaManager->getSchemaNames();
51

52
        self::assertIsArray($names);
Gabriel Caruso's avatar
Gabriel Caruso committed
53
        self::assertNotEmpty($names);
54
        self::assertContains('public', $names, 'The public schema should be found.');
55 56
    }

57 58 59
    /**
     * @group DBAL-21
     */
60
    public function testSupportDomainTypeFallback() : void
61
    {
Sergei Morozov's avatar
Sergei Morozov committed
62
        $createDomainTypeSQL = 'CREATE DOMAIN MyMoney AS DECIMAL(18,2)';
Sergei Morozov's avatar
Sergei Morozov committed
63
        $this->connection->exec($createDomainTypeSQL);
64

Sergei Morozov's avatar
Sergei Morozov committed
65
        $createTableSQL = 'CREATE TABLE domain_type_test (id INT PRIMARY KEY, value MyMoney)';
Sergei Morozov's avatar
Sergei Morozov committed
66
        $this->connection->exec($createTableSQL);
67

Sergei Morozov's avatar
Sergei Morozov committed
68 69
        $table = $this->connection->getSchemaManager()->listTableDetails('domain_type_test');
        self::assertInstanceOf(DecimalType::class, $table->getColumn('value')->getType());
70

Sergei Morozov's avatar
Sergei Morozov committed
71 72
        Type::addType('MyMoney', MoneyType::class);
        $this->connection->getDatabasePlatform()->registerDoctrineTypeMapping('MyMoney', 'MyMoney');
73

Sergei Morozov's avatar
Sergei Morozov committed
74 75
        $table = $this->connection->getSchemaManager()->listTableDetails('domain_type_test');
        self::assertInstanceOf(MoneyType::class, $table->getColumn('value')->getType());
76
    }
77 78 79 80

    /**
     * @group DBAL-37
     */
81
    public function testDetectsAutoIncrement() : void
82
    {
Sergei Morozov's avatar
Sergei Morozov committed
83 84
        $autoincTable = new Table('autoinc_table');
        $column       = $autoincTable->addColumn('id', 'integer');
85
        $column->setAutoincrement(true);
Sergei Morozov's avatar
Sergei Morozov committed
86 87
        $this->schemaManager->createTable($autoincTable);
        $autoincTable = $this->schemaManager->listTableDetails('autoinc_table');
88

89
        self::assertTrue($autoincTable->getColumn('id')->getAutoincrement());
90 91 92 93 94
    }

    /**
     * @group DBAL-37
     */
95
    public function testAlterTableAutoIncrementAdd() : void
96
    {
Sergei Morozov's avatar
Sergei Morozov committed
97 98
        $tableFrom = new Table('autoinc_table_add');
        $column    = $tableFrom->addColumn('id', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
99 100
        $this->schemaManager->createTable($tableFrom);
        $tableFrom = $this->schemaManager->listTableDetails('autoinc_table_add');
101
        self::assertFalse($tableFrom->getColumn('id')->getAutoincrement());
102

Sergei Morozov's avatar
Sergei Morozov committed
103 104
        $tableTo = new Table('autoinc_table_add');
        $column  = $tableTo->addColumn('id', 'integer');
105 106
        $column->setAutoincrement(true);

Sergei Morozov's avatar
Sergei Morozov committed
107
        $c    = new Comparator();
108
        $diff = $c->diffTable($tableFrom, $tableTo);
Sergei Morozov's avatar
Sergei Morozov committed
109
        $sql  = $this->connection->getDatabasePlatform()->getAlterTableSQL($diff);
Sergei Morozov's avatar
Sergei Morozov committed
110 111
        self::assertEquals([
            'CREATE SEQUENCE autoinc_table_add_id_seq',
112 113
            "SELECT setval('autoinc_table_add_id_seq', (SELECT MAX(id) FROM autoinc_table_add))",
            "ALTER TABLE autoinc_table_add ALTER id SET DEFAULT nextval('autoinc_table_add_id_seq')",
Sergei Morozov's avatar
Sergei Morozov committed
114
        ], $sql);
115

Sergei Morozov's avatar
Sergei Morozov committed
116 117
        $this->schemaManager->alterTable($diff);
        $tableFinal = $this->schemaManager->listTableDetails('autoinc_table_add');
118
        self::assertTrue($tableFinal->getColumn('id')->getAutoincrement());
119 120 121 122 123
    }

    /**
     * @group DBAL-37
     */
124
    public function testAlterTableAutoIncrementDrop() : void
125
    {
Sergei Morozov's avatar
Sergei Morozov committed
126 127
        $tableFrom = new Table('autoinc_table_drop');
        $column    = $tableFrom->addColumn('id', 'integer');
128
        $column->setAutoincrement(true);
Sergei Morozov's avatar
Sergei Morozov committed
129 130
        $this->schemaManager->createTable($tableFrom);
        $tableFrom = $this->schemaManager->listTableDetails('autoinc_table_drop');
131
        self::assertTrue($tableFrom->getColumn('id')->getAutoincrement());
132

Sergei Morozov's avatar
Sergei Morozov committed
133 134
        $tableTo = new Table('autoinc_table_drop');
        $column  = $tableTo->addColumn('id', 'integer');
135

Sergei Morozov's avatar
Sergei Morozov committed
136
        $c    = new Comparator();
137
        $diff = $c->diffTable($tableFrom, $tableTo);
Sergei Morozov's avatar
Sergei Morozov committed
138 139
        self::assertInstanceOf(TableDiff::class, $diff, 'There should be a difference and not false being returned from the table comparison');
        self::assertEquals(['ALTER TABLE autoinc_table_drop ALTER id DROP DEFAULT'], $this->connection->getDatabasePlatform()->getAlterTableSQL($diff));
140

Sergei Morozov's avatar
Sergei Morozov committed
141 142
        $this->schemaManager->alterTable($diff);
        $tableFinal = $this->schemaManager->listTableDetails('autoinc_table_drop');
143
        self::assertFalse($tableFinal->getColumn('id')->getAutoincrement());
144
    }
145 146 147 148

    /**
     * @group DBAL-75
     */
149
    public function testTableWithSchema() : void
150
    {
Sergei Morozov's avatar
Sergei Morozov committed
151
        $this->connection->exec('CREATE SCHEMA nested');
152

Sergei Morozov's avatar
Sergei Morozov committed
153 154
        $nestedRelatedTable = new Table('nested.schemarelated');
        $column             = $nestedRelatedTable->addColumn('id', 'integer');
155
        $column->setAutoincrement(true);
Sergei Morozov's avatar
Sergei Morozov committed
156
        $nestedRelatedTable->setPrimaryKey(['id']);
157

Sergei Morozov's avatar
Sergei Morozov committed
158 159
        $nestedSchemaTable = new Table('nested.schematable');
        $column            = $nestedSchemaTable->addColumn('id', 'integer');
160
        $column->setAutoincrement(true);
Sergei Morozov's avatar
Sergei Morozov committed
161 162
        $nestedSchemaTable->setPrimaryKey(['id']);
        $nestedSchemaTable->addUnnamedForeignKeyConstraint($nestedRelatedTable, ['id'], ['id']);
163

Sergei Morozov's avatar
Sergei Morozov committed
164 165
        $this->schemaManager->createTable($nestedRelatedTable);
        $this->schemaManager->createTable($nestedSchemaTable);
166

Sergei Morozov's avatar
Sergei Morozov committed
167
        $tables = $this->schemaManager->listTableNames();
Sergei Morozov's avatar
Sergei Morozov committed
168
        self::assertContains('nested.schematable', $tables, 'The table should be detected with its non-public schema.');
169

Sergei Morozov's avatar
Sergei Morozov committed
170
        $nestedSchemaTable = $this->schemaManager->listTableDetails('nested.schematable');
171
        self::assertTrue($nestedSchemaTable->hasColumn('id'));
Sergei Morozov's avatar
Sergei Morozov committed
172
        self::assertEquals(['id'], $nestedSchemaTable->getPrimaryKey()->getColumns());
173 174

        $relatedFks = $nestedSchemaTable->getForeignKeys();
Gabriel Caruso's avatar
Gabriel Caruso committed
175
        self::assertCount(1, $relatedFks);
176
        $relatedFk = array_pop($relatedFks);
Sergei Morozov's avatar
Sergei Morozov committed
177
        self::assertEquals('nested.schemarelated', $relatedFk->getForeignTableName());
178
    }
179 180 181 182 183

    /**
     * @group DBAL-91
     * @group DBAL-88
     */
184
    public function testReturnQuotedAssets() : void
185 186
    {
        $sql = 'create table dbal91_something ( id integer  CONSTRAINT id_something PRIMARY KEY NOT NULL  ,"table"   integer );';
Sergei Morozov's avatar
Sergei Morozov committed
187
        $this->connection->exec($sql);
188 189

        $sql = 'ALTER TABLE dbal91_something ADD CONSTRAINT something_input FOREIGN KEY( "table" ) REFERENCES dbal91_something ON UPDATE CASCADE;';
Sergei Morozov's avatar
Sergei Morozov committed
190
        $this->connection->exec($sql);
191

Sergei Morozov's avatar
Sergei Morozov committed
192
        $table = $this->schemaManager->listTableDetails('dbal91_something');
193

194
        self::assertEquals(
Sergei Morozov's avatar
Sergei Morozov committed
195 196 197 198
            [
                'CREATE TABLE dbal91_something (id INT NOT NULL, "table" INT DEFAULT NULL, PRIMARY KEY(id))',
                'CREATE INDEX IDX_A9401304ECA7352B ON dbal91_something ("table")',
            ],
Sergei Morozov's avatar
Sergei Morozov committed
199
            $this->connection->getDatabasePlatform()->getCreateTableSQL($table)
200 201
        );
    }
202 203 204 205

    /**
     * @group DBAL-204
     */
206
    public function testFilterSchemaExpression() : void
207
    {
Sergei Morozov's avatar
Sergei Morozov committed
208 209
        $testTable = new Table('dbal204_test_prefix');
        $column    = $testTable->addColumn('id', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
210
        $this->schemaManager->createTable($testTable);
Sergei Morozov's avatar
Sergei Morozov committed
211 212
        $testTable = new Table('dbal204_without_prefix');
        $column    = $testTable->addColumn('id', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
213
        $this->schemaManager->createTable($testTable);
214

Sergei Morozov's avatar
Sergei Morozov committed
215 216
        $this->connection->getConfiguration()->setFilterSchemaAssetsExpression('#^dbal204_#');
        $names = $this->schemaManager->listTableNames();
Gabriel Caruso's avatar
Gabriel Caruso committed
217
        self::assertCount(2, $names);
218

Sergei Morozov's avatar
Sergei Morozov committed
219 220
        $this->connection->getConfiguration()->setFilterSchemaAssetsExpression('#^dbal204_test#');
        $names = $this->schemaManager->listTableNames();
Gabriel Caruso's avatar
Gabriel Caruso committed
221
        self::assertCount(1, $names);
222
    }
223

224
    public function testListForeignKeys() : void
225
    {
Sergei Morozov's avatar
Sergei Morozov committed
226
        if (! $this->connection->getDatabasePlatform()->supportsForeignKeyConstraints()) {
227
            self::markTestSkipped('Does not support foreign key constraints.');
228 229
        }

Sergei Morozov's avatar
Sergei Morozov committed
230 231 232 233
        $fkOptions   = ['SET NULL', 'SET DEFAULT', 'NO ACTION','CASCADE', 'RESTRICT'];
        $foreignKeys = [];
        $fkTable     = $this->getTestTable('test_create_fk1');
        for ($i = 0; $i < count($fkOptions); $i++) {
Sergei Morozov's avatar
Sergei Morozov committed
234
            $fkTable->addColumn('foreign_key_test' . $i, 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
235
            $foreignKeys[] = new ForeignKeyConstraint(
Sergei Morozov's avatar
Sergei Morozov committed
236
                ['foreign_key_test' . $i],
Sergei Morozov's avatar
Sergei Morozov committed
237 238
                'test_create_fk2',
                ['id'],
Sergei Morozov's avatar
Sergei Morozov committed
239
                'foreign_key_test' . $i . '_fk',
Sergei Morozov's avatar
Sergei Morozov committed
240 241
                ['onDelete' => $fkOptions[$i]]
            );
242
        }
Sergei Morozov's avatar
Sergei Morozov committed
243
        $this->schemaManager->dropAndCreateTable($fkTable);
244 245
        $this->createTestTable('test_create_fk2');

Sergei Morozov's avatar
Sergei Morozov committed
246
        foreach ($foreignKeys as $foreignKey) {
Sergei Morozov's avatar
Sergei Morozov committed
247
            $this->schemaManager->createForeignKey($foreignKey, 'test_create_fk1');
248
        }
Sergei Morozov's avatar
Sergei Morozov committed
249
        $fkeys = $this->schemaManager->listTableForeignKeys('test_create_fk1');
Sergei Morozov's avatar
Sergei Morozov committed
250
        self::assertEquals(count($foreignKeys), count($fkeys), "Table 'test_create_fk1' has to have " . count($foreignKeys) . ' foreign keys.');
251
        for ($i = 0; $i < count($fkeys); $i++) {
Sergei Morozov's avatar
Sergei Morozov committed
252
            self::assertEquals(['foreign_key_test' . $i], array_map('strtolower', $fkeys[$i]->getLocalColumns()));
Sergei Morozov's avatar
Sergei Morozov committed
253
            self::assertEquals(['id'], array_map('strtolower', $fkeys[$i]->getForeignColumns()));
254
            self::assertEquals('test_create_fk2', strtolower($fkeys[0]->getForeignTableName()));
Sergei Morozov's avatar
Sergei Morozov committed
255 256
            if ($foreignKeys[$i]->getOption('onDelete') === 'NO ACTION') {
                self::assertFalse($fkeys[$i]->hasOption('onDelete'), 'Unexpected option: ' . $fkeys[$i]->getOption('onDelete'));
257
            } else {
258
                self::assertEquals($foreignKeys[$i]->getOption('onDelete'), $fkeys[$i]->getOption('onDelete'));
259 260 261
            }
        }
    }
262 263 264 265

    /**
     * @group DBAL-511
     */
266
    public function testDefaultValueCharacterVarying() : void
267
    {
Sergei Morozov's avatar
Sergei Morozov committed
268
        $testTable = new Table('dbal511_default');
269
        $testTable->addColumn('id', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
270 271
        $testTable->addColumn('def', 'string', ['default' => 'foo']);
        $testTable->setPrimaryKey(['id']);
272

Sergei Morozov's avatar
Sergei Morozov committed
273
        $this->schemaManager->createTable($testTable);
274

Sergei Morozov's avatar
Sergei Morozov committed
275
        $databaseTable = $this->schemaManager->listTableDetails($testTable->getName());
276

277
        self::assertEquals('foo', $databaseTable->getColumn('def')->getDefault());
278
    }
279 280 281 282

    /**
     * @group DDC-2843
     */
283
    public function testBooleanDefault() : void
284
    {
Sergei Morozov's avatar
Sergei Morozov committed
285
        $table = new Table('ddc2843_bools');
286
        $table->addColumn('id', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
287
        $table->addColumn('checked', 'boolean', ['default' => false]);
288

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

Sergei Morozov's avatar
Sergei Morozov committed
291
        $databaseTable = $this->schemaManager->listTableDetails($table->getName());
292

Sergei Morozov's avatar
Sergei Morozov committed
293
        $c    = new Comparator();
294 295
        $diff = $c->diffTable($table, $databaseTable);

296
        self::assertFalse($diff);
297
    }
Steve Müller's avatar
Steve Müller committed
298

299
    public function testListTableWithBinary() : void
Steve Müller's avatar
Steve Müller committed
300 301 302
    {
        $tableName = 'test_binary_table';

Sergei Morozov's avatar
Sergei Morozov committed
303
        $table = new Table($tableName);
Steve Müller's avatar
Steve Müller committed
304
        $table->addColumn('id', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
305 306 307
        $table->addColumn('column_varbinary', 'binary', []);
        $table->addColumn('column_binary', 'binary', ['fixed' => true]);
        $table->setPrimaryKey(['id']);
Steve Müller's avatar
Steve Müller committed
308

Sergei Morozov's avatar
Sergei Morozov committed
309
        $this->schemaManager->createTable($table);
Steve Müller's avatar
Steve Müller committed
310

Sergei Morozov's avatar
Sergei Morozov committed
311
        $table = $this->schemaManager->listTableDetails($tableName);
Steve Müller's avatar
Steve Müller committed
312

Sergei Morozov's avatar
Sergei Morozov committed
313
        self::assertInstanceOf(BlobType::class, $table->getColumn('column_varbinary')->getType());
314
        self::assertFalse($table->getColumn('column_varbinary')->getFixed());
Steve Müller's avatar
Steve Müller committed
315

Sergei Morozov's avatar
Sergei Morozov committed
316
        self::assertInstanceOf(BlobType::class, $table->getColumn('column_binary')->getType());
317
        self::assertFalse($table->getColumn('column_binary')->getFixed());
Steve Müller's avatar
Steve Müller committed
318
    }
319

320
    public function testListQuotedTable() : void
321 322 323
    {
        $offlineTable = new Schema\Table('user');
        $offlineTable->addColumn('id', 'integer');
324
        $offlineTable->addColumn('username', 'string');
325
        $offlineTable->addColumn('fk', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
326 327
        $offlineTable->setPrimaryKey(['id']);
        $offlineTable->addForeignKeyConstraint($offlineTable, ['fk'], ['id']);
328

Sergei Morozov's avatar
Sergei Morozov committed
329
        $this->schemaManager->dropAndCreateTable($offlineTable);
330

Sergei Morozov's avatar
Sergei Morozov committed
331
        $onlineTable = $this->schemaManager->listTableDetails('"user"');
332 333 334

        $comparator = new Schema\Comparator();

335
        self::assertFalse($comparator->diffTable($offlineTable, $onlineTable));
336
    }
337

338 339 340 341 342 343 344 345 346 347 348 349
    public function testListTableDetailsWhenCurrentSchemaNameQuoted() : void
    {
        $this->connection->exec('CREATE SCHEMA "001_test"');
        $this->connection->exec('SET search_path TO "001_test"');

        try {
            $this->testListQuotedTable();
        } finally {
            $this->connection->close();
        }
    }

350
    public function testListTablesExcludesViews() : void
351 352 353
    {
        $this->createTestTable('list_tables_excludes_views');

Sergei Morozov's avatar
Sergei Morozov committed
354 355
        $name = 'list_tables_excludes_views_test_view';
        $sql  = 'SELECT * from list_tables_excludes_views';
356 357 358

        $view = new Schema\View($name, $sql);

Sergei Morozov's avatar
Sergei Morozov committed
359
        $this->schemaManager->dropAndCreateView($view);
360

Sergei Morozov's avatar
Sergei Morozov committed
361
        $tables = $this->schemaManager->listTables();
362 363 364

        $foundTable = false;
        foreach ($tables as $table) {
Sergei Morozov's avatar
Sergei Morozov committed
365
            self::assertInstanceOf(Table::class, $table, 'No Table instance was found in tables array.');
Sergei Morozov's avatar
Sergei Morozov committed
366 367
            if (strtolower($table->getName()) !== 'list_tables_excludes_views_test_view') {
                continue;
368
            }
Sergei Morozov's avatar
Sergei Morozov committed
369 370

            $foundTable = true;
371 372
        }

373
        self::assertFalse($foundTable, 'View "list_tables_excludes_views_test_view" must not be found in table list');
374
    }
375

376 377 378
    /**
     * @group DBAL-1033
     */
379
    public function testPartialIndexes() : void
380 381 382 383 384
    {
        $offlineTable = new Schema\Table('person');
        $offlineTable->addColumn('id', 'integer');
        $offlineTable->addColumn('name', 'string');
        $offlineTable->addColumn('email', 'string');
Sergei Morozov's avatar
Sergei Morozov committed
385
        $offlineTable->addUniqueIndex(['id', 'name'], 'simple_partial_index', ['where' => '(id IS NULL)']);
386

Sergei Morozov's avatar
Sergei Morozov committed
387
        $this->schemaManager->dropAndCreateTable($offlineTable);
388

Sergei Morozov's avatar
Sergei Morozov committed
389
        $onlineTable = $this->schemaManager->listTableDetails('person');
390 391 392

        $comparator = new Schema\Comparator();

393 394 395 396
        self::assertFalse($comparator->diffTable($offlineTable, $onlineTable));
        self::assertTrue($onlineTable->hasIndex('simple_partial_index'));
        self::assertTrue($onlineTable->getIndex('simple_partial_index')->hasOption('where'));
        self::assertSame('(id IS NULL)', $onlineTable->getIndex('simple_partial_index')->getOption('where'));
397 398
    }

399 400 401
    /**
     * @dataProvider jsonbColumnTypeProvider
     */
Sergei Morozov's avatar
Sergei Morozov committed
402
    public function testJsonbColumn(string $type) : void
403
    {
404
        if (! $this->schemaManager->getDatabasePlatform() instanceof PostgreSQL94Platform) {
Sergei Morozov's avatar
Sergei Morozov committed
405
            $this->markTestSkipped('Requires PostgresSQL 9.4+');
406

407 408 409 410
            return;
        }

        $table = new Schema\Table('test_jsonb');
411
        $table->addColumn('foo', $type)->setPlatformOption('jsonb', true);
Sergei Morozov's avatar
Sergei Morozov committed
412
        $this->schemaManager->dropAndCreateTable($table);
413

Sergei Morozov's avatar
Sergei Morozov committed
414
        $columns = $this->schemaManager->listTableColumns('test_jsonb');
415

416
        self::assertSame($type, $columns['foo']->getType()->getName());
417
        self::assertTrue(true, $columns['foo']->getPlatformOption('jsonb'));
418 419
    }

Sergei Morozov's avatar
Sergei Morozov committed
420 421 422
    /**
     * @return mixed[][]
     */
Sergei Morozov's avatar
Sergei Morozov committed
423
    public function jsonbColumnTypeProvider() : array
424 425
    {
        return [
426 427
            [Types::JSON],
            [Types::JSON_ARRAY],
428
        ];
429
    }
430 431 432 433

    /**
     * @group DBAL-2427
     */
434
    public function testListNegativeColumnDefaultValue() : void
435 436
    {
        $table = new Schema\Table('test_default_negative');
Sergei Morozov's avatar
Sergei Morozov committed
437 438 439 440 441 442
        $table->addColumn('col_smallint', 'smallint', ['default' => -1]);
        $table->addColumn('col_integer', 'integer', ['default' => -1]);
        $table->addColumn('col_bigint', 'bigint', ['default' => -1]);
        $table->addColumn('col_float', 'float', ['default' => -1.1]);
        $table->addColumn('col_decimal', 'decimal', ['default' => -1.1]);
        $table->addColumn('col_string', 'string', ['default' => '(-1)']);
443

Sergei Morozov's avatar
Sergei Morozov committed
444
        $this->schemaManager->dropAndCreateTable($table);
445

Sergei Morozov's avatar
Sergei Morozov committed
446
        $columns = $this->schemaManager->listTableColumns('test_default_negative');
447

448 449 450 451 452 453
        self::assertEquals(-1, $columns['col_smallint']->getDefault());
        self::assertEquals(-1, $columns['col_integer']->getDefault());
        self::assertEquals(-1, $columns['col_bigint']->getDefault());
        self::assertEquals(-1.1, $columns['col_float']->getDefault());
        self::assertEquals(-1.1, $columns['col_decimal']->getDefault());
        self::assertEquals('(-1)', $columns['col_string']->getDefault());
454
    }
455

Sergei Morozov's avatar
Sergei Morozov committed
456 457 458
    /**
     * @return mixed[][]
     */
459
    public static function serialTypes() : iterable
460 461 462 463 464 465 466 467 468 469 470 471 472
    {
        return [
            ['integer'],
            ['bigint'],
        ];
    }

    /**
     * @dataProvider serialTypes
     * @group 2906
     */
    public function testAutoIncrementCreatesSerialDataTypesWithoutADefaultValue(string $type) : void
    {
Sergei Morozov's avatar
Sergei Morozov committed
473
        $tableName = 'test_serial_type_' . $type;
474 475 476 477

        $table = new Schema\Table($tableName);
        $table->addColumn('id', $type, ['autoincrement' => true, 'notnull' => false]);

Sergei Morozov's avatar
Sergei Morozov committed
478
        $this->schemaManager->dropAndCreateTable($table);
479

Sergei Morozov's avatar
Sergei Morozov committed
480
        $columns = $this->schemaManager->listTableColumns($tableName);
481 482 483 484 485 486 487 488 489 490

        self::assertNull($columns['id']->getDefault());
    }

    /**
     * @dataProvider serialTypes
     * @group 2906
     */
    public function testAutoIncrementCreatesSerialDataTypesWithoutADefaultValueEvenWhenDefaultIsSet(string $type) : void
    {
Sergei Morozov's avatar
Sergei Morozov committed
491
        $tableName = 'test_serial_type_with_default_' . $type;
492 493 494 495

        $table = new Schema\Table($tableName);
        $table->addColumn('id', $type, ['autoincrement' => true, 'notnull' => false, 'default' => 1]);

Sergei Morozov's avatar
Sergei Morozov committed
496
        $this->schemaManager->dropAndCreateTable($table);
497

Sergei Morozov's avatar
Sergei Morozov committed
498
        $columns = $this->schemaManager->listTableColumns($tableName);
499 500 501

        self::assertNull($columns['id']->getDefault());
    }
502 503 504 505 506 507 508 509

    /**
     * @group 2916
     * @dataProvider autoIncrementTypeMigrations
     */
    public function testAlterTableAutoIncrementIntToBigInt(string $from, string $to, string $expected) : void
    {
        $tableFrom = new Table('autoinc_type_modification');
Sergei Morozov's avatar
Sergei Morozov committed
510
        $column    = $tableFrom->addColumn('id', $from);
511
        $column->setAutoincrement(true);
Sergei Morozov's avatar
Sergei Morozov committed
512 513
        $this->schemaManager->dropAndCreateTable($tableFrom);
        $tableFrom = $this->schemaManager->listTableDetails('autoinc_type_modification');
514 515 516
        self::assertTrue($tableFrom->getColumn('id')->getAutoincrement());

        $tableTo = new Table('autoinc_type_modification');
Sergei Morozov's avatar
Sergei Morozov committed
517
        $column  = $tableTo->addColumn('id', $to);
518 519
        $column->setAutoincrement(true);

Sergei Morozov's avatar
Sergei Morozov committed
520
        $c    = new Comparator();
521
        $diff = $c->diffTable($tableFrom, $tableTo);
Sergei Morozov's avatar
Sergei Morozov committed
522
        self::assertInstanceOf(TableDiff::class, $diff, 'There should be a difference and not false being returned from the table comparison');
Sergei Morozov's avatar
Sergei Morozov committed
523
        self::assertSame(['ALTER TABLE autoinc_type_modification ALTER id TYPE ' . $expected], $this->connection->getDatabasePlatform()->getAlterTableSQL($diff));
524

Sergei Morozov's avatar
Sergei Morozov committed
525 526
        $this->schemaManager->alterTable($diff);
        $tableFinal = $this->schemaManager->listTableDetails('autoinc_type_modification');
527 528 529
        self::assertTrue($tableFinal->getColumn('id')->getAutoincrement());
    }

Sergei Morozov's avatar
Sergei Morozov committed
530 531 532
    /**
     * @return mixed[][]
     */
533
    public static function autoIncrementTypeMigrations() : iterable
534 535 536 537 538 539
    {
        return [
            'int->bigint' => ['integer', 'bigint', 'BIGINT'],
            'bigint->int' => ['bigint', 'integer', 'INT'],
        ];
    }
540 541 542 543
}

class MoneyType extends Type
{
544 545 546
    /**
     * {@inheritDoc}
     */
547 548
    public function getName()
    {
Sergei Morozov's avatar
Sergei Morozov committed
549
        return 'MyMoney';
550 551
    }

Sergei Morozov's avatar
Sergei Morozov committed
552 553 554
    /**
     * {@inheritDoc}
     */
555
    public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
556 557 558
    {
        return 'MyMoney';
    }
559
}