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

Michael Moravec's avatar
Michael Moravec committed
3 4
declare(strict_types=1);

5 6
namespace Doctrine\Tests\DBAL\Functional\Schema;

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

romanb's avatar
romanb committed
25
class PostgreSqlSchemaManagerTest extends SchemaManagerFunctionalTestCase
26
{
27 28 29
    /** @var PostgreSqlSchemaManager */
    protected $schemaManager;

30
    protected function tearDown() : void
31 32
    {
        parent::tearDown();
33

34
        $this->connection->getConfiguration()->setSchemaAssetsFilter(null);
35
    }
36

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

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

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

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

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

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

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

Sergei Morozov's avatar
Sergei Morozov committed
74 75
        Type::addType('MyMoney', MoneyType::class);
        $this->connection->getDatabasePlatform()->registerDoctrineTypeMapping('MyMoney', 'MyMoney');
76

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

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

92
        self::assertTrue($autoincTable->getColumn('id')->getAutoincrement());
93 94 95 96 97
    }

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

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

Sergei Morozov's avatar
Sergei Morozov committed
110
        $c    = new Comparator();
111
        $diff = $c->diffTable($tableFrom, $tableTo);
112 113 114 115

        self::assertNotNull($diff);

        $sql = $this->connection->getDatabasePlatform()->getAlterTableSQL($diff);
Sergei Morozov's avatar
Sergei Morozov committed
116 117
        self::assertEquals([
            'CREATE SEQUENCE autoinc_table_add_id_seq',
118 119
            "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
120
        ], $sql);
121

Sergei Morozov's avatar
Sergei Morozov committed
122 123
        $this->schemaManager->alterTable($diff);
        $tableFinal = $this->schemaManager->listTableDetails('autoinc_table_add');
124
        self::assertTrue($tableFinal->getColumn('id')->getAutoincrement());
125 126 127 128 129
    }

    /**
     * @group DBAL-37
     */
130
    public function testAlterTableAutoIncrementDrop() : void
131
    {
Sergei Morozov's avatar
Sergei Morozov committed
132 133
        $tableFrom = new Table('autoinc_table_drop');
        $column    = $tableFrom->addColumn('id', 'integer');
134
        $column->setAutoincrement(true);
Sergei Morozov's avatar
Sergei Morozov committed
135 136
        $this->schemaManager->createTable($tableFrom);
        $tableFrom = $this->schemaManager->listTableDetails('autoinc_table_drop');
137
        self::assertTrue($tableFrom->getColumn('id')->getAutoincrement());
138

Sergei Morozov's avatar
Sergei Morozov committed
139 140
        $tableTo = new Table('autoinc_table_drop');
        $column  = $tableTo->addColumn('id', 'integer');
141

Sergei Morozov's avatar
Sergei Morozov committed
142
        $c    = new Comparator();
143
        $diff = $c->diffTable($tableFrom, $tableTo);
144 145 146

        self::assertNotNull($diff);

Sergei Morozov's avatar
Sergei Morozov committed
147 148
        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));
149

Sergei Morozov's avatar
Sergei Morozov committed
150 151
        $this->schemaManager->alterTable($diff);
        $tableFinal = $this->schemaManager->listTableDetails('autoinc_table_drop');
152
        self::assertFalse($tableFinal->getColumn('id')->getAutoincrement());
153
    }
154 155 156 157

    /**
     * @group DBAL-75
     */
158
    public function testTableWithSchema() : void
159
    {
Sergei Morozov's avatar
Sergei Morozov committed
160
        $this->connection->exec('CREATE SCHEMA nested');
161

Sergei Morozov's avatar
Sergei Morozov committed
162 163
        $nestedRelatedTable = new Table('nested.schemarelated');
        $column             = $nestedRelatedTable->addColumn('id', 'integer');
164
        $column->setAutoincrement(true);
Sergei Morozov's avatar
Sergei Morozov committed
165
        $nestedRelatedTable->setPrimaryKey(['id']);
166

Sergei Morozov's avatar
Sergei Morozov committed
167 168
        $nestedSchemaTable = new Table('nested.schematable');
        $column            = $nestedSchemaTable->addColumn('id', 'integer');
169
        $column->setAutoincrement(true);
Sergei Morozov's avatar
Sergei Morozov committed
170
        $nestedSchemaTable->setPrimaryKey(['id']);
171
        $nestedSchemaTable->addForeignKeyConstraint($nestedRelatedTable, ['id'], ['id']);
172

Sergei Morozov's avatar
Sergei Morozov committed
173 174
        $this->schemaManager->createTable($nestedRelatedTable);
        $this->schemaManager->createTable($nestedSchemaTable);
175

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

Sergei Morozov's avatar
Sergei Morozov committed
179
        $nestedSchemaTable = $this->schemaManager->listTableDetails('nested.schematable');
180
        self::assertTrue($nestedSchemaTable->hasColumn('id'));
Benjamin Morel's avatar
Benjamin Morel committed
181 182 183 184

        $primaryKey = $nestedSchemaTable->getPrimaryKey();
        self::assertNotNull($primaryKey);
        self::assertEquals(['id'], $primaryKey->getColumns());
185 186

        $relatedFks = $nestedSchemaTable->getForeignKeys();
Gabriel Caruso's avatar
Gabriel Caruso committed
187
        self::assertCount(1, $relatedFks);
188
        $relatedFk = array_pop($relatedFks);
Benjamin Morel's avatar
Benjamin Morel committed
189
        self::assertNotNull($relatedFk);
Sergei Morozov's avatar
Sergei Morozov committed
190
        self::assertEquals('nested.schemarelated', $relatedFk->getForeignTableName());
191
    }
192 193 194 195 196

    /**
     * @group DBAL-91
     * @group DBAL-88
     */
197
    public function testReturnQuotedAssets() : void
198 199
    {
        $sql = 'create table dbal91_something ( id integer  CONSTRAINT id_something PRIMARY KEY NOT NULL  ,"table"   integer );';
Sergei Morozov's avatar
Sergei Morozov committed
200
        $this->connection->exec($sql);
201 202

        $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
203
        $this->connection->exec($sql);
204

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

207
        self::assertEquals(
Sergei Morozov's avatar
Sergei Morozov committed
208 209 210 211
            [
                '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
212
            $this->connection->getDatabasePlatform()->getCreateTableSQL($table)
213 214
        );
    }
215 216 217 218

    /**
     * @group DBAL-204
     */
219
    public function testFilterSchemaExpression() : void
220
    {
Sergei Morozov's avatar
Sergei Morozov committed
221 222
        $testTable = new Table('dbal204_test_prefix');
        $column    = $testTable->addColumn('id', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
223
        $this->schemaManager->createTable($testTable);
Sergei Morozov's avatar
Sergei Morozov committed
224 225
        $testTable = new Table('dbal204_without_prefix');
        $column    = $testTable->addColumn('id', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
226
        $this->schemaManager->createTable($testTable);
227

228 229 230
        $this->connection->getConfiguration()->setSchemaAssetsFilter(static function (string $name) : bool {
            return preg_match('#^dbal204_#', $name) === 1;
        });
Sergei Morozov's avatar
Sergei Morozov committed
231
        $names = $this->schemaManager->listTableNames();
Gabriel Caruso's avatar
Gabriel Caruso committed
232
        self::assertCount(2, $names);
233

234 235 236
        $this->connection->getConfiguration()->setSchemaAssetsFilter(static function (string $name) : bool {
            return preg_match('#^dbal204_test#', $name) === 1;
        });
Sergei Morozov's avatar
Sergei Morozov committed
237
        $names = $this->schemaManager->listTableNames();
Gabriel Caruso's avatar
Gabriel Caruso committed
238
        self::assertCount(1, $names);
239
    }
240

241
    public function testListForeignKeys() : void
242
    {
Sergei Morozov's avatar
Sergei Morozov committed
243
        if (! $this->connection->getDatabasePlatform()->supportsForeignKeyConstraints()) {
244 245 246
            $this->markTestSkipped('Does not support foreign key constraints.');
        }

Sergei Morozov's avatar
Sergei Morozov committed
247 248 249 250
        $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
251
            $fkTable->addColumn('foreign_key_test' . $i, 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
252
            $foreignKeys[] = new ForeignKeyConstraint(
Sergei Morozov's avatar
Sergei Morozov committed
253
                ['foreign_key_test' . $i],
Sergei Morozov's avatar
Sergei Morozov committed
254 255
                'test_create_fk2',
                ['id'],
Sergei Morozov's avatar
Sergei Morozov committed
256
                'foreign_key_test' . $i . '_fk',
Sergei Morozov's avatar
Sergei Morozov committed
257 258
                ['onDelete' => $fkOptions[$i]]
            );
259
        }
Sergei Morozov's avatar
Sergei Morozov committed
260
        $this->schemaManager->dropAndCreateTable($fkTable);
261 262
        $this->createTestTable('test_create_fk2');

Sergei Morozov's avatar
Sergei Morozov committed
263
        foreach ($foreignKeys as $foreignKey) {
Sergei Morozov's avatar
Sergei Morozov committed
264
            $this->schemaManager->createForeignKey($foreignKey, 'test_create_fk1');
265
        }
Sergei Morozov's avatar
Sergei Morozov committed
266
        $fkeys = $this->schemaManager->listTableForeignKeys('test_create_fk1');
Sergei Morozov's avatar
Sergei Morozov committed
267
        self::assertEquals(count($foreignKeys), count($fkeys), "Table 'test_create_fk1' has to have " . count($foreignKeys) . ' foreign keys.');
268
        for ($i = 0; $i < count($fkeys); $i++) {
Sergei Morozov's avatar
Sergei Morozov committed
269
            self::assertEquals(['foreign_key_test' . $i], array_map('strtolower', $fkeys[$i]->getLocalColumns()));
Sergei Morozov's avatar
Sergei Morozov committed
270
            self::assertEquals(['id'], array_map('strtolower', $fkeys[$i]->getForeignColumns()));
271
            self::assertEquals('test_create_fk2', strtolower($fkeys[0]->getForeignTableName()));
Sergei Morozov's avatar
Sergei Morozov committed
272 273
            if ($foreignKeys[$i]->getOption('onDelete') === 'NO ACTION') {
                self::assertFalse($fkeys[$i]->hasOption('onDelete'), 'Unexpected option: ' . $fkeys[$i]->getOption('onDelete'));
274
            } else {
275
                self::assertEquals($foreignKeys[$i]->getOption('onDelete'), $fkeys[$i]->getOption('onDelete'));
276 277 278
            }
        }
    }
279 280 281 282

    /**
     * @group DBAL-511
     */
283
    public function testDefaultValueCharacterVarying() : void
284
    {
Sergei Morozov's avatar
Sergei Morozov committed
285
        $testTable = new Table('dbal511_default');
286
        $testTable->addColumn('id', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
287 288
        $testTable->addColumn('def', 'string', ['default' => 'foo']);
        $testTable->setPrimaryKey(['id']);
289

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

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

294
        self::assertEquals('foo', $databaseTable->getColumn('def')->getDefault());
295
    }
296 297 298 299

    /**
     * @group DDC-2843
     */
300
    public function testBooleanDefault() : void
301
    {
Sergei Morozov's avatar
Sergei Morozov committed
302
        $table = new Table('ddc2843_bools');
303
        $table->addColumn('id', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
304
        $table->addColumn('checked', 'boolean', ['default' => false]);
305

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

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

Sergei Morozov's avatar
Sergei Morozov committed
310
        $c    = new Comparator();
311 312
        $diff = $c->diffTable($table, $databaseTable);

313
        self::assertNull($diff);
314
    }
Steve Müller's avatar
Steve Müller committed
315

316
    public function testListTableWithBinary() : void
Steve Müller's avatar
Steve Müller committed
317 318 319
    {
        $tableName = 'test_binary_table';

Sergei Morozov's avatar
Sergei Morozov committed
320
        $table = new Table($tableName);
Steve Müller's avatar
Steve Müller committed
321
        $table->addColumn('id', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
322 323 324
        $table->addColumn('column_varbinary', 'binary', []);
        $table->addColumn('column_binary', 'binary', ['fixed' => true]);
        $table->setPrimaryKey(['id']);
Steve Müller's avatar
Steve Müller committed
325

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

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

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

Sergei Morozov's avatar
Sergei Morozov committed
333
        self::assertInstanceOf(BlobType::class, $table->getColumn('column_binary')->getType());
334
        self::assertFalse($table->getColumn('column_binary')->getFixed());
Steve Müller's avatar
Steve Müller committed
335
    }
336

337
    public function testListQuotedTable() : void
338 339 340
    {
        $offlineTable = new Schema\Table('user');
        $offlineTable->addColumn('id', 'integer');
341
        $offlineTable->addColumn('username', 'string');
342
        $offlineTable->addColumn('fk', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
343 344
        $offlineTable->setPrimaryKey(['id']);
        $offlineTable->addForeignKeyConstraint($offlineTable, ['fk'], ['id']);
345

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

Sergei Morozov's avatar
Sergei Morozov committed
348
        $onlineTable = $this->schemaManager->listTableDetails('"user"');
349 350 351

        $comparator = new Schema\Comparator();

352
        self::assertNull($comparator->diffTable($offlineTable, $onlineTable));
353
    }
354

355
    public function testListTablesExcludesViews() : void
356 357 358
    {
        $this->createTestTable('list_tables_excludes_views');

Sergei Morozov's avatar
Sergei Morozov committed
359 360
        $name = 'list_tables_excludes_views_test_view';
        $sql  = 'SELECT * from list_tables_excludes_views';
361 362 363

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

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

Sergei Morozov's avatar
Sergei Morozov committed
366
        $tables = $this->schemaManager->listTables();
367 368 369

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

            $foundTable = true;
376 377
        }

378
        self::assertFalse($foundTable, 'View "list_tables_excludes_views_test_view" must not be found in table list');
379
    }
380

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

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

Sergei Morozov's avatar
Sergei Morozov committed
394
        $onlineTable = $this->schemaManager->listTableDetails('person');
395 396 397

        $comparator = new Schema\Comparator();

398
        self::assertNull($comparator->diffTable($offlineTable, $onlineTable));
399 400 401
        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'));
402 403
    }

404
    public function testJsonbColumn() : void
405
    {
406
        if (! $this->schemaManager->getDatabasePlatform() instanceof PostgreSqlPlatform) {
Sergei Morozov's avatar
Sergei Morozov committed
407
            $this->markTestSkipped('Requires PostgresSQL 9.4+');
408

409 410 411 412
            return;
        }

        $table = new Schema\Table('test_jsonb');
413
        $table->addColumn('foo', Types::JSON)->setPlatformOption('jsonb', true);
Sergei Morozov's avatar
Sergei Morozov committed
414
        $this->schemaManager->dropAndCreateTable($table);
415

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

418
        self::assertSame(Types::JSON, $columns['foo']->getType()->getName());
Michael Moravec's avatar
Michael Moravec committed
419
        self::assertTrue($columns['foo']->getPlatformOption('jsonb'));
420 421
    }

422 423 424
    /**
     * @group DBAL-2427
     */
425
    public function testListNegativeColumnDefaultValue() : void
426 427
    {
        $table = new Schema\Table('test_default_negative');
Sergei Morozov's avatar
Sergei Morozov committed
428 429 430 431 432 433
        $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)']);
434

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

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

439 440 441 442 443 444
        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());
445
    }
446

Sergei Morozov's avatar
Sergei Morozov committed
447 448 449
    /**
     * @return mixed[][]
     */
450
    public static function serialTypes() : iterable
451 452 453 454 455 456 457 458 459 460 461 462 463
    {
        return [
            ['integer'],
            ['bigint'],
        ];
    }

    /**
     * @dataProvider serialTypes
     * @group 2906
     */
    public function testAutoIncrementCreatesSerialDataTypesWithoutADefaultValue(string $type) : void
    {
Sergei Morozov's avatar
Sergei Morozov committed
464
        $tableName = 'test_serial_type_' . $type;
465 466 467 468

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

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

Sergei Morozov's avatar
Sergei Morozov committed
471
        $columns = $this->schemaManager->listTableColumns($tableName);
472 473 474 475 476 477 478 479 480 481

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

    /**
     * @dataProvider serialTypes
     * @group 2906
     */
    public function testAutoIncrementCreatesSerialDataTypesWithoutADefaultValueEvenWhenDefaultIsSet(string $type) : void
    {
Sergei Morozov's avatar
Sergei Morozov committed
482
        $tableName = 'test_serial_type_with_default_' . $type;
483 484 485 486

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

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

Sergei Morozov's avatar
Sergei Morozov committed
489
        $columns = $this->schemaManager->listTableColumns($tableName);
490 491 492

        self::assertNull($columns['id']->getDefault());
    }
493 494 495 496 497 498 499 500

    /**
     * @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
501
        $column    = $tableFrom->addColumn('id', $from);
502
        $column->setAutoincrement(true);
Sergei Morozov's avatar
Sergei Morozov committed
503 504
        $this->schemaManager->dropAndCreateTable($tableFrom);
        $tableFrom = $this->schemaManager->listTableDetails('autoinc_type_modification');
505 506 507
        self::assertTrue($tableFrom->getColumn('id')->getAutoincrement());

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

Sergei Morozov's avatar
Sergei Morozov committed
511
        $c    = new Comparator();
512
        $diff = $c->diffTable($tableFrom, $tableTo);
Sergei Morozov's avatar
Sergei Morozov committed
513
        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
514
        self::assertSame(['ALTER TABLE autoinc_type_modification ALTER id TYPE ' . $expected], $this->connection->getDatabasePlatform()->getAlterTableSQL($diff));
515

Sergei Morozov's avatar
Sergei Morozov committed
516 517
        $this->schemaManager->alterTable($diff);
        $tableFinal = $this->schemaManager->listTableDetails('autoinc_type_modification');
518 519 520
        self::assertTrue($tableFinal->getColumn('id')->getAutoincrement());
    }

Sergei Morozov's avatar
Sergei Morozov committed
521 522 523
    /**
     * @return mixed[][]
     */
524
    public static function autoIncrementTypeMigrations() : iterable
525 526 527 528 529 530
    {
        return [
            'int->bigint' => ['integer', 'bigint', 'BIGINT'],
            'bigint->int' => ['bigint', 'integer', 'INT'],
        ];
    }
531 532 533 534
}

class MoneyType extends Type
{
535 536 537
    /**
     * {@inheritDoc}
     */
538
    public function getName() : string
539
    {
Sergei Morozov's avatar
Sergei Morozov committed
540
        return 'MyMoney';
541 542
    }

Sergei Morozov's avatar
Sergei Morozov committed
543 544 545
    /**
     * {@inheritDoc}
     */
546
    public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform) : string
547 548 549
    {
        return 'MyMoney';
    }
550
}