-
-
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
Migration generates unnecessary queries #5369
Comments
@Rixafy please provide the steps to reproduce the issue using only the DBAL APIs. |
@morozov, I have found the root cause. 3.3.0...3.3.1#diff-3a87a8ea798d5188662020a7cfc091da8595a6ccfff91b074deec8ac7801f349L60 (see highlighted line in files) Before, there was comparator created with I checked the columns passed to that method and dumped both of them. First column is from database, second is from schema The difference is that column from the DB has So I dumped a table schema - https://gist.github.com/Rixafy/35da79ee11f17c8840c2775e8804f0c6 In create table SQL there is `slug` varchar(15) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL It has utf8 charset (other columns don't), but when I execute generated diff ALTER TABLE product_badge CHANGE slug slug VARCHAR(15) NOT NULL COLLATE `utf8_bin` It still has So I found how to fix it, when I add When I run ALTER TABLE product_badge CHANGE slug slug VARCHAR(15) CHARACTER SET utf8mb4 NOT NULL COLLATE `utf8mb4_bin` and I edit entity schema to collation When I run ALTER TABLE product_badge CHANGE slug slug VARCHAR(15) CHARACTER SET utf8 NOT NULL COLLATE `utf8_bin` I need to add |
Could you please provide the steps to reproduce the problem first? |
Hi, I don't know exactly how reproduce this issue, but this is an annoying issue. The migration process always try to alter columns without any reasons. In my case, the issue occurs with datetime, when I define: /**
* @var \Datetime $created_at
*/
#[Column(name: 'created_at', type: 'datetime', precision: 3)]
private $created_at;
/**
* @var \Datetime $updated_at
*/
#[Column(name: 'updated_at', type: 'datetime', precision: 3)]
private $updated_at; The migration always generate: $this->addSql('ALTER TABLE table_name CHANGE created_at created_at DATETIME(3) NOT NULL, CHANGE updated_at updated_at DATETIME(3) NOT NULL'); Apply it doesn't change anything. Any idea ? EDIT: Columns are already NOT NULL, but not displayed on the screenshot |
Hi @Dallas62, I explained how I get rid of the problem, I didn't have Later I had similar issue when I used php enum as property, and I had php property nullable and also What SQLs do you have as additional? |
Hi @Rixafy, I wrote it on my previous comment. |
It was okay on the version 3.3.0. |
Ah, I see, that may be the same issue, there is a diff if you want to search deeper 3.3.0...3.3.1, but I think I figured it out what is a cause.
in 3.3.0, some code in comparator was not aware of platform type, with that change I think they fixed another bugs, but it seems like it caused some more. |
No. It would be nice if somebody built a minimal reproducer script (not an application). |
@morozov Hi, there is/was a issue which describes the same problem with discussion where someone describes and explains the problem with a low level reproduction. Someone else has written that the bug will be fixed in the 3.3.8 version. Today I update doctrine/dbal to 3.4.0 and the problem still remains. |
just chiming in to say I've hit the same issue. If I instantiate For now, I've added this workaround in my clientside code: foreach ($changed_table->changedColumns as $name => $col_diff) {
if (!$comparator->diffColumn($col_diff->column, $col_diff->fromColumn)) {
unset($changed_table->changedColumns[$name]);
}
} I'd love to work on a minimal reproducer script, but I'm not sure I know how to bootstrap Doctrine without writing at least 2000 lines of code :-) Maybe I'll try to bastardize one of the unit tests when I have time.. |
@morozov it's quite old, but you think something like this could be a viable approach for creating a reproducer script? doctrine/orm#6487 |
It could be a code snippet like #5582 (comment) or a failing test. Anything that doesn't require external dependencies and could be run as code. |
@morozov ok, I've cobbled something together with which I can reproduce locally: $table = new Table('"tester"');
$table->addColumn('"id"', Types::INTEGER);
$table->addColumn('"name"', Types::STRING);
class testclass {}
$cm = new ClassMetadata(testclass::class);
$cm->setTableName('tester');
$cm->setIdentifier(['id']);
$cm->mapField([
'fieldName' => 'id',
'type' => Types::INTEGER
]);
$cm->mapField([
'fieldName' => 'name',
'type' => Types::STRING
]);
$schemaManager = $conn->createSchemaManager();
$schemaManager->dropAndCreateTable($table);
$current_schema = $schemaManager->createSchema();
$to_schema = (new SchemaTool($em))->getSchemaFromMetadata([$cm]);
$schema_diff = (new Comparator())->compareSchemas($current_schema, $to_schema);
echo "Without \$platform:\n";
dump($schema_diff->changedTables['tester']->changedColumns);
$schema_diff = (new Comparator($conn->getDatabasePlatform()))->compareSchemas($current_schema, $to_schema);
echo "With \$platform:\n";
dump($schema_diff->changedTables['tester']->changedColumns); This shows the following output (against MySQL 8.0.30, if that is important): |
@flack thank you for the example. Unfortunately, the |
@morozov try this: $table = new Table('"tester"');
$table->addColumn('"id"', Types::INTEGER);
$table->addColumn('"name"', Types::STRING);
$schemaManager = $conn->createSchemaManager();
$schemaManager->dropAndCreateTable($table);
$current_schema = $schemaManager->createSchema();
$to_schema = new Schema();
$t2 = $to_schema->createTable('tester');
$t2->addColumn('"id"', Types::INTEGER);
$t2->addColumn('"name"', Types::STRING);
$schema_diff = (new Comparator())->compareSchemas($current_schema, $to_schema);
echo "Without \$platform:\n";
dump($schema_diff->changedTables['tester']->changedColumns ?? 'no diff detected');
$schema_diff = (new Comparator($conn->getDatabasePlatform()))->compareSchemas($current_schema, $to_schema);
echo "With \$platform:\n";
dump($schema_diff->changedTables['tester']->changedColumns); Output: |
Thanks. It's reproducible on 3.4.x and 4.0.x. |
This code example looks not entirely correct since it uses an internal DBAL API in the second case: dbal/src/Schema/Comparator.php Lines 32 to 35 in c60fd26
This prevents the DBAL from being able to use MySQL-specific schema comparison logic. This bug likely was fixed in #5471 (3.3.8). The diff in the second case is not reproducible if the comparator is instantiated properly: $comparator = $schemaManager->createComparator(); See the upgrade notes: Lines 538 to 539 in ca2160d
Please try instantiating the comparator as recommended and see if the issue is still reproducible. |
Hi, that nette extension just integrates dbal into the nette framework - https://github.com/nettrine/dbal/blob/master/src/DI/DbalExtension.php, I don't know what can affect it from there, there is no comparator registration. I tried it with 3.4.0 dbal and the issue still remains: #[ORM\Column(length: 15, unique: true, options: ['collation' => 'utf8_bin'])]
private string $slug; my default doctrine charset is utf8mb4 and collation utf8mb4_unicode_ci, and when I have this as a column definition in entity, orm schema update will generate this SQL: ALTER TABLE product CHANGE slug slug VARCHAR(15) NOT NULL COLLATE `utf8_bin`; which is odd, since slug in database has already collation utf8_bin, I would expect that it would want to change charset instead, but I don't know how my default utf8mb4 charset would work with utf8_bin (in DB, there is utf8_bin collation and utf8 charset in that column). When I change definition and add a charset to it #[ORM\Column(length: 15, unique: true, options: ['collation' => 'utf8_bin', 'charset' => 'utf8'])]
private string $slug; then the problem disappears and no SQL is generated, I understand this may be the edge case, since I switched collations from utf8 to utb8mb4 in database and code, and I left some binary columns in utf8, so if no one is experiencing the problem, this issue may be closed. |
@Rixafy as you may see from the above comments, the problem is not necessarily about the model definitions but may be caused by the code that performs the comparison. Without the code reproducing the issue, there isn't much we can do on the DBAL side to address your issue. |
btw, I guess the dbal docs also needs to be updated, e.g. here it still says
|
@Rixafy there must be code in your application that instantiates the comparator: it's either your code or one of the dependencies. To track what instantiates the comparator, you can do either of the following:
|
Closing due to the lack of feedback. |
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
After upgrading from DBAL 2.x and to latest 3.x version, I have ran a diff command and a weird migration was generated. Same output is generated in
o:s:u --dump-sql
In my code there is
and database structure match the parameters, even when I execute the statements, next migration will be the same.
I'm using PHP 8.1, MariaDB 10.3.34
In version 3.3.0 it works just fine, but it will generate me only this query, because I guess there was some bug with enums, because name is a enum, it disappears when I use type
SystemMetaName|string
, so I locked my project to that version for now. It is no longer in 3.3.1+, but there are that queries with utf8_bin collation.There is a diff 3.3.0...3.3.1 but I can't see the probable cause of this bug.
My dbal settings are:
Settings are from nettrine implementation in Nette Framework https://contributte.org/packages/nettrine/dbal.html.
The text was updated successfully, but these errors were encountered: