From a16a838a301753e4bcc68b3d87d6e0cf6c11e2f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Vo=C5=99=C3=AD=C5=A1ek?= Date: Fri, 5 Apr 2024 18:23:42 +0200 Subject: [PATCH 1/2] Fix unwanted SQLite schema emulation in SqliteSchemaManager --- psalm.xml.dist | 3 ++ src/Platforms/SqlitePlatform.php | 2 +- src/Schema/SqliteSchemaManager.php | 12 +++-- .../Schema/SqliteSchemaManagerTest.php | 53 +++++++++++++++++++ 4 files changed, 66 insertions(+), 4 deletions(-) diff --git a/psalm.xml.dist b/psalm.xml.dist index 31e4a8b6638..d685b545c1a 100644 --- a/psalm.xml.dist +++ b/psalm.xml.dist @@ -519,6 +519,9 @@ + + + diff --git a/src/Platforms/SqlitePlatform.php b/src/Platforms/SqlitePlatform.php index 48c692fdb45..dd69688fbb8 100644 --- a/src/Platforms/SqlitePlatform.php +++ b/src/Platforms/SqlitePlatform.php @@ -908,7 +908,7 @@ public function getTemporaryTableName($tableName) */ public function canEmulateSchemas() { - Deprecation::trigger( + Deprecation::triggerIfCalledFromOutside( 'doctrine/dbal', 'https://github.com/doctrine/dbal/pull/4805', 'SqlitePlatform::canEmulateSchemas() is deprecated.', diff --git a/src/Schema/SqliteSchemaManager.php b/src/Schema/SqliteSchemaManager.php index 3b464f21add..4b96739e16f 100644 --- a/src/Schema/SqliteSchemaManager.php +++ b/src/Schema/SqliteSchemaManager.php @@ -715,7 +715,9 @@ protected function selectTableColumns(string $databaseName, ?string $tableName = if ($tableName !== null) { $conditions[] = 't.name = ?'; - $params[] = str_replace('.', '__', $tableName); + $params[] = $this->_platform->canEmulateSchemas() + ? str_replace('.', '__', $tableName) + : $tableName; } $sql .= ' WHERE ' . implode(' AND ', $conditions) . ' ORDER BY t.name, c.cid'; @@ -740,7 +742,9 @@ protected function selectIndexColumns(string $databaseName, ?string $tableName = if ($tableName !== null) { $conditions[] = 't.name = ?'; - $params[] = str_replace('.', '__', $tableName); + $params[] = $this->_platform->canEmulateSchemas() + ? str_replace('.', '__', $tableName) + : $tableName; } $sql .= ' WHERE ' . implode(' AND ', $conditions) . ' ORDER BY t.name, i.seq'; @@ -766,7 +770,9 @@ protected function selectForeignKeyColumns(string $databaseName, ?string $tableN if ($tableName !== null) { $conditions[] = 't.name = ?'; - $params[] = str_replace('.', '__', $tableName); + $params[] = $this->_platform->canEmulateSchemas() + ? str_replace('.', '__', $tableName) + : $tableName; } $sql .= ' WHERE ' . implode(' AND ', $conditions) . ' ORDER BY t.name, p.id DESC, p.seq'; diff --git a/tests/Functional/Schema/SqliteSchemaManagerTest.php b/tests/Functional/Schema/SqliteSchemaManagerTest.php index a8d5ca6b3cf..63606a6ed9b 100644 --- a/tests/Functional/Schema/SqliteSchemaManagerTest.php +++ b/tests/Functional/Schema/SqliteSchemaManagerTest.php @@ -12,8 +12,10 @@ use Doctrine\DBAL\Types\BlobType; use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\Types\Types; +use ReflectionMethod; use function array_keys; +use function array_map; use function array_shift; use function assert; use function dirname; @@ -398,6 +400,57 @@ public function testShorthandInForeignKeyReferenceWithMultipleColumns(): void ); } + public function testListTableNoSchemaEmulation(): void + { + $databasePlatform = $this->connection->getDatabasePlatform(); + assert($databasePlatform instanceof SqlitePlatform); + $databasePlatform->disableSchemaEmulation(); + + $this->dropTableIfExists('`list_table_no_schema_emulation.test`'); + + $this->connection->executeStatement(<<<'DDL' + CREATE TABLE `list_table_no_schema_emulation.test` ( + id INTEGER, + parent_id INTEGER, + PRIMARY KEY (id), + FOREIGN KEY (parent_id) REFERENCES `list_table_no_schema_emulation.test` (id) + ); + DDL); + + $this->connection->executeStatement(<<<'DDL' + CREATE INDEX i ON `list_table_no_schema_emulation.test` (parent_id); + DDL); + + $schemaManager = $this->schemaManager; + $refl = new ReflectionMethod($schemaManager, 'selectTableColumns'); + $refl->setAccessible(true); + $res = $refl->invoke($schemaManager, 'main', 'list_table_no_schema_emulation.test') + ->fetchAllAssociative(); + + self::assertSame([ + ['list_table_no_schema_emulation.test', 'id'], + ['list_table_no_schema_emulation.test', 'parent_id'], + ], array_map(static fn (array $row) => [$row['table_name'], $row['name']], $res)); + + $refl = new ReflectionMethod($schemaManager, 'selectIndexColumns'); + $refl->setAccessible(true); + $res = $refl->invoke($schemaManager, 'main', 'list_table_no_schema_emulation.test') + ->fetchAllAssociative(); + + self::assertSame([ + ['list_table_no_schema_emulation.test', 'i'], + ], array_map(static fn (array $row) => [$row['table_name'], $row['name']], $res)); + + $refl = new ReflectionMethod($schemaManager, 'selectForeignKeyColumns'); + $refl->setAccessible(true); + $res = $refl->invoke($schemaManager, 'main', 'list_table_no_schema_emulation.test') + ->fetchAllAssociative(); + + self::assertSame([ + ['list_table_no_schema_emulation.test', 'parent_id', 'id'], + ], array_map(static fn (array $row) => [$row['table_name'], $row['from'], $row['to']], $res)); + } + /** * This test duplicates {@see parent::testCommentInTable()} with the only difference that the name of the table * being created is quoted. It is only meant to cover the logic of parsing the SQLite CREATE TABLE statement From a13e983cc7e5899c332459248ae6ce6f7426af88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Vo=C5=99=C3=AD=C5=A1ek?= Date: Tue, 1 Oct 2024 14:41:35 +0200 Subject: [PATCH 2/2] rewrite test without reflection --- .../Schema/SqliteSchemaManagerTest.php | 83 ++++++++++++------- 1 file changed, 54 insertions(+), 29 deletions(-) diff --git a/tests/Functional/Schema/SqliteSchemaManagerTest.php b/tests/Functional/Schema/SqliteSchemaManagerTest.php index 63606a6ed9b..c2da909ebb2 100644 --- a/tests/Functional/Schema/SqliteSchemaManagerTest.php +++ b/tests/Functional/Schema/SqliteSchemaManagerTest.php @@ -7,12 +7,12 @@ use Doctrine\DBAL\Platforms\SqlitePlatform; use Doctrine\DBAL\Schema\Column; use Doctrine\DBAL\Schema\ForeignKeyConstraint; +use Doctrine\DBAL\Schema\SqliteSchemaManager; use Doctrine\DBAL\Schema\Table; use Doctrine\DBAL\Schema\TableDiff; use Doctrine\DBAL\Types\BlobType; use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\Types\Types; -use ReflectionMethod; use function array_keys; use function array_map; @@ -421,34 +421,59 @@ public function testListTableNoSchemaEmulation(): void CREATE INDEX i ON `list_table_no_schema_emulation.test` (parent_id); DDL); - $schemaManager = $this->schemaManager; - $refl = new ReflectionMethod($schemaManager, 'selectTableColumns'); - $refl->setAccessible(true); - $res = $refl->invoke($schemaManager, 'main', 'list_table_no_schema_emulation.test') - ->fetchAllAssociative(); - - self::assertSame([ - ['list_table_no_schema_emulation.test', 'id'], - ['list_table_no_schema_emulation.test', 'parent_id'], - ], array_map(static fn (array $row) => [$row['table_name'], $row['name']], $res)); - - $refl = new ReflectionMethod($schemaManager, 'selectIndexColumns'); - $refl->setAccessible(true); - $res = $refl->invoke($schemaManager, 'main', 'list_table_no_schema_emulation.test') - ->fetchAllAssociative(); - - self::assertSame([ - ['list_table_no_schema_emulation.test', 'i'], - ], array_map(static fn (array $row) => [$row['table_name'], $row['name']], $res)); - - $refl = new ReflectionMethod($schemaManager, 'selectForeignKeyColumns'); - $refl->setAccessible(true); - $res = $refl->invoke($schemaManager, 'main', 'list_table_no_schema_emulation.test') - ->fetchAllAssociative(); - - self::assertSame([ - ['list_table_no_schema_emulation.test', 'parent_id', 'id'], - ], array_map(static fn (array $row) => [$row['table_name'], $row['from'], $row['to']], $res)); + $customSqliteSchemaManager = new class ($this->connection, $databasePlatform) extends SqliteSchemaManager { + /** @return list> */ + public function selectTableColumnsWithSchema(): array + { + return $this->selectTableColumns('main', 'list_table_no_schema_emulation.test') + ->fetchAllAssociative(); + } + + /** @return list> */ + public function selectIndexColumnsWithSchema(): array + { + return $this->selectIndexColumns('main', 'list_table_no_schema_emulation.test') + ->fetchAllAssociative(); + } + + /** @return list> */ + public function selectForeignKeyColumnsWithSchema(): array + { + return $this->selectForeignKeyColumns('main', 'list_table_no_schema_emulation.test') + ->fetchAllAssociative(); + } + }; + + self::assertSame( + [ + ['list_table_no_schema_emulation.test', 'id'], + ['list_table_no_schema_emulation.test', 'parent_id'], + ], + array_map( + static fn (array $row) => [$row['table_name'], $row['name']], + $customSqliteSchemaManager->selectTableColumnsWithSchema(), + ), + ); + + self::assertSame( + [ + ['list_table_no_schema_emulation.test', 'i'], + ], + array_map( + static fn (array $row) => [$row['table_name'], $row['name']], + $customSqliteSchemaManager->selectIndexColumnsWithSchema(), + ), + ); + + self::assertSame( + [ + ['list_table_no_schema_emulation.test', 'parent_id', 'id'], + ], + array_map( + static fn (array $row) => [$row['table_name'], $row['from'], $row['to']], + $customSqliteSchemaManager->selectForeignKeyColumnsWithSchema(), + ), + ); } /**