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++) { |
||
0 ignored issues
–
show
|
|||
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++) { |
||
0 ignored issues
–
show
It seems like you are calling the size function
count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.
If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration: for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}
// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
|
|||
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 | |||
424 | class MoneyType extends Type |
||
425 | { |
||
426 | |||
427 | public function getName() |
||
428 | { |
||
429 | return "MyMoney"; |
||
430 | } |
||
431 | |||
432 | public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform) |
||
433 | { |
||
434 | return 'MyMoney'; |
||
435 | } |
||
436 | |||
437 | } |
||
438 |
If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration: