Completed
Push — master ( 8c1e51...0e8ad2 )
by Luís
15s
created

Functional/Schema/PostgreSqlSchemaManagerTest.php (1 issue)

1
<?php
2
3
namespace Doctrine\Tests\DBAL\Functional\Schema;
4
5
use Doctrine\DBAL\Platforms\AbstractPlatform;
6
use Doctrine\DBAL\Platforms\PostgreSQL94Platform;
7
use Doctrine\DBAL\Schema;
8
use Doctrine\DBAL\Types\Type;
9
10
class PostgreSqlSchemaManagerTest extends SchemaManagerFunctionalTestCase
11
{
12
    protected function tearDown()
13
    {
14
        parent::tearDown();
15
16
        if (!$this->_conn) {
17
            return;
18
        }
19
20
        $this->_conn->getConfiguration()->setFilterSchemaAssetsExpression(null);
21
    }
22
23
    /**
24
     * @group DBAL-177
25
     */
26
    public function testGetSearchPath()
27
    {
28
        $params = $this->_conn->getParams();
29
30
        $paths = $this->_sm->getSchemaSearchPaths();
31
        self::assertEquals([$params['user'], 'public'], $paths);
32
    }
33
34
    /**
35
     * @group DBAL-244
36
     */
37
    public function testGetSchemaNames()
38
    {
39
        $names = $this->_sm->getSchemaNames();
40
41
        self::assertInternalType('array', $names);
42
        self::assertTrue(count($names) > 0);
43
        self::assertContains('public', $names, 'The public schema should be found.');
44
    }
45
46
    /**
47
     * @group DBAL-21
48
     */
49
    public function testSupportDomainTypeFallback()
50
    {
51
        $createDomainTypeSQL = "CREATE DOMAIN MyMoney AS DECIMAL(18,2)";
52
        $this->_conn->exec($createDomainTypeSQL);
53
54
        $createTableSQL = "CREATE TABLE domain_type_test (id INT PRIMARY KEY, value MyMoney)";
55
        $this->_conn->exec($createTableSQL);
56
57
        $table = $this->_conn->getSchemaManager()->listTableDetails('domain_type_test');
58
        self::assertInstanceOf('Doctrine\DBAL\Types\DecimalType', $table->getColumn('value')->getType());
59
60
        Type::addType('MyMoney', 'Doctrine\Tests\DBAL\Functional\Schema\MoneyType');
61
        $this->_conn->getDatabasePlatform()->registerDoctrineTypeMapping('MyMoney', 'MyMoney');
62
63
        $table = $this->_conn->getSchemaManager()->listTableDetails('domain_type_test');
64
        self::assertInstanceOf('Doctrine\Tests\DBAL\Functional\Schema\MoneyType', $table->getColumn('value')->getType());
65
    }
66
67
    /**
68
     * @group DBAL-37
69
     */
70
    public function testDetectsAutoIncrement()
71
    {
72
        $autoincTable = new \Doctrine\DBAL\Schema\Table('autoinc_table');
73
        $column = $autoincTable->addColumn('id', 'integer');
74
        $column->setAutoincrement(true);
75
        $this->_sm->createTable($autoincTable);
76
        $autoincTable = $this->_sm->listTableDetails('autoinc_table');
77
78
        self::assertTrue($autoincTable->getColumn('id')->getAutoincrement());
79
    }
80
81
    /**
82
     * @group DBAL-37
83
     */
84 View Code Duplication
    public function testAlterTableAutoIncrementAdd()
85
    {
86
        $tableFrom = new \Doctrine\DBAL\Schema\Table('autoinc_table_add');
87
        $column = $tableFrom->addColumn('id', 'integer');
88
        $this->_sm->createTable($tableFrom);
89
        $tableFrom = $this->_sm->listTableDetails('autoinc_table_add');
90
        self::assertFalse($tableFrom->getColumn('id')->getAutoincrement());
91
92
        $tableTo = new \Doctrine\DBAL\Schema\Table('autoinc_table_add');
93
        $column = $tableTo->addColumn('id', 'integer');
94
        $column->setAutoincrement(true);
95
96
        $c = new \Doctrine\DBAL\Schema\Comparator();
97
        $diff = $c->diffTable($tableFrom, $tableTo);
98
        $sql = $this->_conn->getDatabasePlatform()->getAlterTableSQL($diff);
99
        self::assertEquals(array(
100
            "CREATE SEQUENCE autoinc_table_add_id_seq",
101
            "SELECT setval('autoinc_table_add_id_seq', (SELECT MAX(id) FROM autoinc_table_add))",
102
            "ALTER TABLE autoinc_table_add ALTER id SET DEFAULT nextval('autoinc_table_add_id_seq')",
103
        ), $sql);
104
105
        $this->_sm->alterTable($diff);
106
        $tableFinal = $this->_sm->listTableDetails('autoinc_table_add');
107
        self::assertTrue($tableFinal->getColumn('id')->getAutoincrement());
108
    }
109
110
    /**
111
     * @group DBAL-37
112
     */
113 View Code Duplication
    public function testAlterTableAutoIncrementDrop()
114
    {
115
        $tableFrom = new \Doctrine\DBAL\Schema\Table('autoinc_table_drop');
116
        $column = $tableFrom->addColumn('id', 'integer');
117
        $column->setAutoincrement(true);
118
        $this->_sm->createTable($tableFrom);
119
        $tableFrom = $this->_sm->listTableDetails('autoinc_table_drop');
120
        self::assertTrue($tableFrom->getColumn('id')->getAutoincrement());
121
122
        $tableTo = new \Doctrine\DBAL\Schema\Table('autoinc_table_drop');
123
        $column = $tableTo->addColumn('id', 'integer');
124
125
        $c = new \Doctrine\DBAL\Schema\Comparator();
126
        $diff = $c->diffTable($tableFrom, $tableTo);
127
        self::assertInstanceOf('Doctrine\DBAL\Schema\TableDiff', $diff, "There should be a difference and not false being returned from the table comparison");
128
        self::assertEquals(array("ALTER TABLE autoinc_table_drop ALTER id DROP DEFAULT"), $this->_conn->getDatabasePlatform()->getAlterTableSQL($diff));
129
130
        $this->_sm->alterTable($diff);
131
        $tableFinal = $this->_sm->listTableDetails('autoinc_table_drop');
132
        self::assertFalse($tableFinal->getColumn('id')->getAutoincrement());
133
    }
134
135
    /**
136
     * @group DBAL-75
137
     */
138
    public function testTableWithSchema()
139
    {
140
        $this->_conn->exec('CREATE SCHEMA nested');
141
142
        $nestedRelatedTable = new \Doctrine\DBAL\Schema\Table('nested.schemarelated');
143
        $column = $nestedRelatedTable->addColumn('id', 'integer');
144
        $column->setAutoincrement(true);
145
        $nestedRelatedTable->setPrimaryKey(array('id'));
146
147
        $nestedSchemaTable = new \Doctrine\DBAL\Schema\Table('nested.schematable');
148
        $column = $nestedSchemaTable->addColumn('id', 'integer');
149
        $column->setAutoincrement(true);
150
        $nestedSchemaTable->setPrimaryKey(array('id'));
151
        $nestedSchemaTable->addUnnamedForeignKeyConstraint($nestedRelatedTable, array('id'), array('id'));
152
153
        $this->_sm->createTable($nestedRelatedTable);
154
        $this->_sm->createTable($nestedSchemaTable);
155
156
        $tables = $this->_sm->listTableNames();
157
        self::assertContains('nested.schematable', $tables, "The table should be detected with its non-public schema.");
158
159
        $nestedSchemaTable = $this->_sm->listTableDetails('nested.schematable');
160
        self::assertTrue($nestedSchemaTable->hasColumn('id'));
161
        self::assertEquals(array('id'), $nestedSchemaTable->getPrimaryKey()->getColumns());
162
163
        $relatedFks = $nestedSchemaTable->getForeignKeys();
164
        self::assertEquals(1, count($relatedFks));
165
        $relatedFk = array_pop($relatedFks);
166
        self::assertEquals("nested.schemarelated", $relatedFk->getForeignTableName());
167
    }
168
169
    /**
170
     * @group DBAL-91
171
     * @group DBAL-88
172
     */
173
    public function testReturnQuotedAssets()
174
    {
175
        $sql = 'create table dbal91_something ( id integer  CONSTRAINT id_something PRIMARY KEY NOT NULL  ,"table"   integer );';
176
        $this->_conn->exec($sql);
177
178
        $sql = 'ALTER TABLE dbal91_something ADD CONSTRAINT something_input FOREIGN KEY( "table" ) REFERENCES dbal91_something ON UPDATE CASCADE;';
179
        $this->_conn->exec($sql);
180
181
        $table = $this->_sm->listTableDetails('dbal91_something');
182
183
        self::assertEquals(
184
            array(
185
                "CREATE TABLE dbal91_something (id INT NOT NULL, \"table\" INT DEFAULT NULL, PRIMARY KEY(id))",
186
                "CREATE INDEX IDX_A9401304ECA7352B ON dbal91_something (\"table\")",
187
            ),
188
            $this->_conn->getDatabasePlatform()->getCreateTableSQL($table)
189
        );
190
    }
191
192
    /**
193
     * @group DBAL-204
194
     */
195
    public function testFilterSchemaExpression()
196
    {
197
        $testTable = new \Doctrine\DBAL\Schema\Table('dbal204_test_prefix');
198
        $column = $testTable->addColumn('id', 'integer');
199
        $this->_sm->createTable($testTable);
200
        $testTable = new \Doctrine\DBAL\Schema\Table('dbal204_without_prefix');
201
        $column = $testTable->addColumn('id', 'integer');
202
        $this->_sm->createTable($testTable);
203
204
        $this->_conn->getConfiguration()->setFilterSchemaAssetsExpression('#^dbal204_#');
205
        $names = $this->_sm->listTableNames();
206
        self::assertEquals(2, count($names));
207
208
        $this->_conn->getConfiguration()->setFilterSchemaAssetsExpression('#^dbal204_test#');
209
        $names = $this->_sm->listTableNames();
210
        self::assertEquals(1, count($names));
211
    }
212
213
    public function testListForeignKeys()
214
    {
215
        if(!$this->_conn->getDatabasePlatform()->supportsForeignKeyConstraints()) {
216
            $this->markTestSkipped('Does not support foreign key constraints.');
217
        }
218
219
        $fkOptions = array('SET NULL', 'SET DEFAULT', 'NO ACTION','CASCADE', 'RESTRICT');
220
        $foreignKeys = array();
221
        $fkTable = $this->getTestTable('test_create_fk1');
222
        for($i = 0; $i < count($fkOptions); $i++) {
223
            $fkTable->addColumn("foreign_key_test$i", 'integer');
224
            $foreignKeys[] = new \Doctrine\DBAL\Schema\ForeignKeyConstraint(
225
                                 array("foreign_key_test$i"), 'test_create_fk2', array('id'), "foreign_key_test_$i"."_fk", array('onDelete' => $fkOptions[$i]));
226
        }
227
        $this->_sm->dropAndCreateTable($fkTable);
228
        $this->createTestTable('test_create_fk2');
229
230
        foreach($foreignKeys as $foreignKey) {
231
            $this->_sm->createForeignKey($foreignKey, 'test_create_fk1');
232
        }
233
        $fkeys = $this->_sm->listTableForeignKeys('test_create_fk1');
234
        self::assertEquals(count($foreignKeys), count($fkeys), "Table 'test_create_fk1' has to have " . count($foreignKeys) . " foreign keys.");
235
        for ($i = 0; $i < count($fkeys); $i++) {
236
            self::assertEquals(array("foreign_key_test$i"), array_map('strtolower', $fkeys[$i]->getLocalColumns()));
237
            self::assertEquals(array('id'), array_map('strtolower', $fkeys[$i]->getForeignColumns()));
238
            self::assertEquals('test_create_fk2', strtolower($fkeys[0]->getForeignTableName()));
239
            if ($foreignKeys[$i]->getOption('onDelete') == 'NO ACTION') {
240
                self::assertFalse($fkeys[$i]->hasOption('onDelete'), 'Unexpected option: '. $fkeys[$i]->getOption('onDelete'));
241
            } else {
242
                self::assertEquals($foreignKeys[$i]->getOption('onDelete'), $fkeys[$i]->getOption('onDelete'));
243
            }
244
        }
245
    }
246
247
    /**
248
     * @group DBAL-511
249
     */
250
    public function testDefaultValueCharacterVarying()
251
    {
252
        $testTable = new \Doctrine\DBAL\Schema\Table('dbal511_default');
253
        $testTable->addColumn('id', 'integer');
254
        $testTable->addColumn('def', 'string', array('default' => 'foo'));
255
        $testTable->setPrimaryKey(array('id'));
256
257
        $this->_sm->createTable($testTable);
258
259
        $databaseTable = $this->_sm->listTableDetails($testTable->getName());
260
261
        self::assertEquals('foo', $databaseTable->getColumn('def')->getDefault());
262
    }
263
264
    /**
265
     * @group DDC-2843
266
     */
267 View Code Duplication
    public function testBooleanDefault()
268
    {
269
        $table = new \Doctrine\DBAL\Schema\Table('ddc2843_bools');
270
        $table->addColumn('id', 'integer');
271
        $table->addColumn('checked', 'boolean', array('default' => false));
272
273
        $this->_sm->createTable($table);
274
275
        $databaseTable = $this->_sm->listTableDetails($table->getName());
276
277
        $c = new \Doctrine\DBAL\Schema\Comparator();
278
        $diff = $c->diffTable($table, $databaseTable);
279
280
        self::assertFalse($diff);
281
    }
282
283 View Code Duplication
    public function testListTableWithBinary()
284
    {
285
        $tableName = 'test_binary_table';
286
287
        $table = new \Doctrine\DBAL\Schema\Table($tableName);
288
        $table->addColumn('id', 'integer');
289
        $table->addColumn('column_varbinary', 'binary', array());
290
        $table->addColumn('column_binary', 'binary', array('fixed' => true));
291
        $table->setPrimaryKey(array('id'));
292
293
        $this->_sm->createTable($table);
294
295
        $table = $this->_sm->listTableDetails($tableName);
296
297
        self::assertInstanceOf('Doctrine\DBAL\Types\BlobType', $table->getColumn('column_varbinary')->getType());
298
        self::assertFalse($table->getColumn('column_varbinary')->getFixed());
299
300
        self::assertInstanceOf('Doctrine\DBAL\Types\BlobType', $table->getColumn('column_binary')->getType());
301
        self::assertFalse($table->getColumn('column_binary')->getFixed());
302
    }
303
304
    public function testListQuotedTable()
305
    {
306
        $offlineTable = new Schema\Table('user');
307
        $offlineTable->addColumn('id', 'integer');
308
        $offlineTable->addColumn('username', 'string', array('unique' => true));
309
        $offlineTable->addColumn('fk', 'integer');
310
        $offlineTable->setPrimaryKey(array('id'));
311
        $offlineTable->addForeignKeyConstraint($offlineTable, array('fk'), array('id'));
312
313
        $this->_sm->dropAndCreateTable($offlineTable);
314
315
        $onlineTable = $this->_sm->listTableDetails('"user"');
316
317
        $comparator = new Schema\Comparator();
318
319
        self::assertFalse($comparator->diffTable($offlineTable, $onlineTable));
320
    }
321
322
    public function testListTablesExcludesViews()
323
    {
324
        $this->createTestTable('list_tables_excludes_views');
325
326
        $name = "list_tables_excludes_views_test_view";
327
        $sql = "SELECT * from list_tables_excludes_views";
328
329
        $view = new Schema\View($name, $sql);
330
331
        $this->_sm->dropAndCreateView($view);
332
333
        $tables = $this->_sm->listTables();
334
335
        $foundTable = false;
336 View Code Duplication
        foreach ($tables as $table) {
337
            self::assertInstanceOf('Doctrine\DBAL\Schema\Table', $table, 'No Table instance was found in tables array.');
338
            if (strtolower($table->getName()) == 'list_tables_excludes_views_test_view') {
339
                $foundTable = true;
340
            }
341
        }
342
343
        self::assertFalse($foundTable, 'View "list_tables_excludes_views_test_view" must not be found in table list');
344
    }
345
346
    /**
347
     * @group DBAL-1033
348
     */
349
    public function testPartialIndexes()
350
    {
351
        $offlineTable = new Schema\Table('person');
352
        $offlineTable->addColumn('id', 'integer');
353
        $offlineTable->addColumn('name', 'string');
354
        $offlineTable->addColumn('email', 'string');
355
        $offlineTable->addUniqueIndex(array('id', 'name'), 'simple_partial_index', array('where' => '(id IS NULL)'));
356
357
        $this->_sm->dropAndCreateTable($offlineTable);
358
359
        $onlineTable = $this->_sm->listTableDetails('person');
360
361
        $comparator = new Schema\Comparator();
362
363
        self::assertFalse($comparator->diffTable($offlineTable, $onlineTable));
364
        self::assertTrue($onlineTable->hasIndex('simple_partial_index'));
365
        self::assertTrue($onlineTable->getIndex('simple_partial_index')->hasOption('where'));
366
        self::assertSame('(id IS NULL)', $onlineTable->getIndex('simple_partial_index')->getOption('where'));
367
    }
368
369
    /**
370
     * @dataProvider jsonbColumnTypeProvider
371
     */
372
    public function testJsonbColumn(string $type): void
373
    {
374
        if (!$this->_sm->getDatabasePlatform() instanceof PostgreSQL94Platform) {
375
            $this->markTestSkipped("Requires PostgresSQL 9.4+");
376
            return;
377
        }
378
379
        $table = new Schema\Table('test_jsonb');
380
        $table->addColumn('foo', $type)->setPlatformOption('jsonb', true);
381
        $this->_sm->dropAndCreateTable($table);
382
383
        /** @var Schema\Column[] $columns */
384
        $columns = $this->_sm->listTableColumns('test_jsonb');
385
386
        self::assertSame($type, $columns['foo']->getType()->getName());
387
        self::assertTrue(true, $columns['foo']->getPlatformOption('jsonb'));
388
    }
389
390
    public function jsonbColumnTypeProvider(): array
391
    {
392
        return [
393
            [Type::JSON],
394
            [Type::JSON_ARRAY],
395
        ];
396
    }
397
398
    /**
399
     * @group DBAL-2427
400
     */
401
    public function testListNegativeColumnDefaultValue()
402
    {
403
        $table = new Schema\Table('test_default_negative');
404
        $table->addColumn('col_smallint', 'smallint', array('default' => -1));
405
        $table->addColumn('col_integer', 'integer', array('default' => -1));
406
        $table->addColumn('col_bigint', 'bigint', array('default' => -1));
407
        $table->addColumn('col_float', 'float', array('default' => -1.1));
408
        $table->addColumn('col_decimal', 'decimal', array('default' => -1.1));
409
        $table->addColumn('col_string', 'string', array('default' => '(-1)'));
410
411
        $this->_sm->dropAndCreateTable($table);
412
413
        $columns = $this->_sm->listTableColumns('test_default_negative');
414
415
        self::assertEquals(-1, $columns['col_smallint']->getDefault());
416
        self::assertEquals(-1, $columns['col_integer']->getDefault());
417
        self::assertEquals(-1, $columns['col_bigint']->getDefault());
418
        self::assertEquals(-1.1, $columns['col_float']->getDefault());
419
        self::assertEquals(-1.1, $columns['col_decimal']->getDefault());
420
        self::assertEquals('(-1)', $columns['col_string']->getDefault());
421
    }
422
423
    public static function serialTypes() : array
424
    {
425
        return [
426
            ['integer'],
427
            ['bigint'],
428
        ];
429
    }
430
431
    /**
432
     * @dataProvider serialTypes
433
     * @group 2906
434
     */
435 View Code Duplication
    public function testAutoIncrementCreatesSerialDataTypesWithoutADefaultValue(string $type) : void
436
    {
437
        $tableName = "test_serial_type_$type";
438
439
        $table = new Schema\Table($tableName);
440
        $table->addColumn('id', $type, ['autoincrement' => true, 'notnull' => false]);
441
442
        $this->_sm->dropAndCreateTable($table);
443
444
        $columns = $this->_sm->listTableColumns($tableName);
445
446
        self::assertNull($columns['id']->getDefault());
447
    }
448
449
    /**
450
     * @dataProvider serialTypes
451
     * @group 2906
452
     */
453 View Code Duplication
    public function testAutoIncrementCreatesSerialDataTypesWithoutADefaultValueEvenWhenDefaultIsSet(string $type) : void
454
    {
455
        $tableName = "test_serial_type_with_default_$type";
456
457
        $table = new Schema\Table($tableName);
458
        $table->addColumn('id', $type, ['autoincrement' => true, 'notnull' => false, 'default' => 1]);
459
460
        $this->_sm->dropAndCreateTable($table);
461
462
        $columns = $this->_sm->listTableColumns($tableName);
463
464
        self::assertNull($columns['id']->getDefault());
465
    }
466
}
467
468
class MoneyType extends Type
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
469
{
470
471
    public function getName()
472
    {
473
        return "MyMoney";
474
    }
475
476
    public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
477
    {
478
        return 'MyMoney';
479
    }
480
481
}
482