-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Schema diff changes since version 3.3.1 #5223
Comments
It's related to the new platform-aware schema comparison. Currently it seems to be impossible to have a custom Repro<?php
$connection->executeStatement('DROP TABLE IF EXISTS `repro`');
$connection->executeStatement(<<<'SQL'
CREATE TABLE `repro` (
`product` enum('hotel','homes') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'hotel' COMMENT 'Embeddable: Product'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
SQL);
$desiredTable = new Table('repro', [
new Column(
'product',
new StringType(),
[
'length' => 0,
'notnull' => true,
'default' => 'hotel',
'comment' => 'Embeddable: Product',
'columnDefinition' => <<<'DEF'
enum('hotel','homes') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'hotel' COMMENT 'Embeddable: Product'
DEF,
]
),
]);
$sm = $connection->createSchemaManager();
$actualTable = $sm->listTableDetails('repro');
if (method_exists($sm, 'createComparator')) {
$comparator = $sm->createComparator();
} else {
$comparator = new Comparator();
}
$diff = $comparator->diffTable($actualTable, $desiredTable);
if ($diff !== false) {
$schemaDiff = new SchemaDiff([], [$diff]);
var_dump(
$schemaDiff->toSql($connection->getDatabasePlatform())
);
} else {
var_dump("no diff");
} I was able to trace it down to if (
$this->getColumnDeclarationSQL('', $this->columnToArray($column1))
!== $this->getColumnDeclarationSQL('', $this->columnToArray($column2))
) {
return false;
} The |
If I understood correctly, you're saying that the buggy part is The SQL executed to retrieve the list of columns is here I think: dbal/src/Platforms/AbstractMySQLPlatform.php Lines 338 to 346 in 5b6eb6c
A great next step my be to open a PR with a failing test, and |
@bcremer I must have understood wrong then, because you don't seem to be fixing |
I'm not yet positive if that's really a road to go for the fix. We might need an extra options field like |
@morozov hi! Maybe you have some insight to provide about this? I'm afraid I'm too unfamiliar with how this works to give a good piece of advice on this. |
I don't believe schema migrations could ever work correctly when the column definition is specified manually. See #3647 (comment). When I run the above example on top of bare DBAL, I get the following error:
I assume it's the ORM that defines the If, for the sake of testing, I replace - VARCHAR(32) CHARACTER SET utf8mb4 DEFAULT 'hotel' NOT NULL COLLATE `utf8mb4_unicode_ci` COMMENT 'Embeddable: Product'
+ varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'hotel' COMMENT 'Embeddable: Product' While both definitions are equal semantically, there are differences in their syntax:
If I take the DDL that the comparator expects and put it into the column definition, the diff disappears. If I understand the issue correctly, I don't believe there will be a better solution than to tweak the column definition to the comparator's expectations. |
The $conn->getDatabasePlatform()->registerDoctrineTypeMapping('enum', 'string');
That's what is not possible anymore right now due to the following condition in if (
$this->getColumnDeclarationSQL('', $this->columnToArray($column1))
!== $this->getColumnDeclarationSQL('', $this->columnToArray($column2))
) {
return false;
}
$sm = $connection->createSchemaManager();
$actualTable = $sm->listTableDetails('repro');
$actualTable->getColumn('product')->getColumnDefinition(); // null
$desiredTable->getColumn('product')->getColumnDefinition(); // string(126) "enum('hotel','homes')[...] So the comparison will always fail when a |
Since I updated to 3.3.1 I get some weird migrations when using diff command. The final class Version20220201154458 extends AbstractMigration
{
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('
ALTER TABLE Account
CHANGE name name VARCHAR(100) DEFAULT NULL COLLATE `utf8mb4_0900_ai_ci`,
CHANGE email email VARCHAR(100) DEFAULT NULL COLLATE `utf8mb4_0900_ai_ci`
');
} This is just an example, but I get the My database is already using
Using mysql 8.0.26 Edit: found what was the problem! There's a config name mismatch, for the table default collation, I think. Documentation for DoctrineBundle says that config name is And AbstractMySqlPlatform also uses this name. src/Platforms/AbstractMySQLPlatform.php:456 But, MySQL comparator uses So, which is the correct one? default_table_options:
charset: utf8mb4
collation: utf8mb4_0900_ai_ci
engine: InnoDB PS: I'm using these options until DBAL v4, where if I'm not mistaken, charset and collation will not forced. (#4644) |
Exactly! That's a better explanation of what I exposed. Sorry, should have searched a bit more... But, this only happened to my when updated to 3.3.1. When at 3.2.1 it worked 🤷♂️ |
I'm currently using #5224 to workaround this. In my opinion there are two possible solutions to handle a
|
Potential fix @ #5234 In practice, killing platform-aware schema diffing works wonders there :D |
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
Bug Report
Summary
SInce 3.3.1 I have schema changes that I did not have before.
Current behaviour
Running
app/console doctrine:schema:update --dump-sql
mostly shows changes related toENUM
column definitions likeHowever: the generated SQL is identical with the actual column definition in MySQL. So I cannot get rid of the diff.
Might be related to #5220 ?
How to reproduce
Add an ORM entity with a
ENUM
columnDefinition likeAnd map
enum
to string likeSee https://www.doctrine-project.org/projects/doctrine-orm/en/2.11/cookbook/mysql-enums.html#solution-1-mapping-to-varchars
Expected behaviour
There should not be any schema diff.
The text was updated successfully, but these errors were encountered: