Skip to content
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

fixes incorrect database migration for quoted columns #3395

Closed
wants to merge 6 commits into from

Conversation

svycka
Copy link
Contributor

@svycka svycka commented Dec 7, 2018

Q A
Type bug
BC Break no
Fixed issues #3387

Summary

I think this should accept as the same column if one is quoted and other is not

…nother is not

I am not sure this is correct just testing if other tests will not fail
foreach ($this->_localColumnNames as $localColumn) {
if (strtolower($indexColumn) === strtolower($localColumn->getName())) {
if (strtolower($indexColumn) === strtolower($localColumn->trimQuotes($localColumn->getName()))) {
Copy link
Contributor Author

@svycka svycka Dec 7, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure that I have to trim quotes for $localColumn->getName() this should already be unquoted?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't really help with that due to my unfamiliarity with this code area. @deeky666 @morozov can you check this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm unfamiliar with this either but it feels bad. An unquoted column name is the value itself, a quoted column name is a SQL expression representing this value. Why would we want to mix them and compare by trimming quotes?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@morozov maybe I did not understand you. I need them to ignore escaping because of #3387 while debugging I noticed that for up and down migrations it compares escaped or unescaped values and generates or not gerenates migration. This place checks if the column name is included in the foreign constraint and it should not matter if it is escaped or not should say it is in both cases. I just not sure about this $localColumn->trimQuotes($localColumn->getName()).

Also I am not sure this will not break other parts but tests looks green so maybe ok?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's a valid case for DBAL. Right now there's no difference between quoted and unquoted identifiers in the DBAL type system but it doesn't mean it should handle them transparently. Most likely, there's a lot of other cases where mixing quoted and unquoted identifiers will cause unexpected behavior.

Instead of changing the comparison logic in DBAL, I'd try to fix the inconsistency on the calling side.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this a valid case where a database allows reserved words when they are quoted?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SenseException this is the case where I spotted this with migration for this did not work becouse "`group`" is escaped with `

     * @ORM\ManyToOne(targetEntity="Group")
     * @ORM\JoinColumn(name="`group`", referencedColumnName="id")

@morozov I can find only one place where this method is called https://github.com/doctrine/dbal/blob/master/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php#L829
so you suggest create one more method for same problem and don't use old one(witch I think is buggy)?

anyway, feel free to close this if you think this is a bad fix for #3387 and create better one. But this worked for my use case.

@@ -16,14 +16,9 @@ class ForeignKeyConstraintTest extends TestCase
*/
public function testIntersectsIndexColumns(array $indexColumns, $expectedResult)
{
$foreignKey = new ForeignKeyConstraint(['foo', 'bar'], 'foreign_table', ['fk_foo', 'fk_bar']);
$foreignKey = new ForeignKeyConstraint(['foo', '`bar`'], 'foreign_table', ['fk_foo', 'fk_bar']);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please design a new test: don't modify existing ones.

If an existing test is being modified out of necessity, we will likely hit a BC break scenario.

foreach ($this->_localColumnNames as $localColumn) {
if (strtolower($indexColumn) === strtolower($localColumn->getName())) {
if (strtolower($indexColumn) === strtolower($localColumn->trimQuotes($localColumn->getName()))) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't really help with that due to my unfamiliarity with this code area. @deeky666 @morozov can you check this?

@svycka
Copy link
Contributor Author

svycka commented Dec 10, 2018

@deeky666 would be nice if you could review as this is your code :) implemented with #756

foreach ($this->_localColumnNames as $localColumn) {
if (strtolower($indexColumn) === strtolower($localColumn->getName())) {
if (strtolower($indexColumn) === strtolower($localColumn->trimQuotes($localColumn->getName()))) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's a valid case for DBAL. Right now there's no difference between quoted and unquoted identifiers in the DBAL type system but it doesn't mean it should handle them transparently. Most likely, there's a lot of other cases where mixing quoted and unquoted identifiers will cause unexpected behavior.

Instead of changing the comparison logic in DBAL, I'd try to fix the inconsistency on the calling side.

@svycka svycka changed the title does't intersect columns if one is quoted and another is not fixes incorrect database migration for quoted columns Mar 25, 2019
@svycka
Copy link
Contributor Author

svycka commented May 17, 2019

@Ocramius I have created a new test, is it ok now?

*
* @dataProvider getIntersectsIndexColumnsData
*/
public function testIntersectsIndexEscapedColumns(array $indexColumns, $expectedResult)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's $expectedResult? Needs type documentation here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess I could add bool type hint here. Is that would be ok? or I have to update doc block?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding a type declaration would be best (instead of docblock)

$index->expects($this->once())
->method('getColumns')
->will($this->returnValue($indexColumns));
$index = new Index('INDEX_NAME', $indexColumns);
Copy link
Member

@Ocramius Ocramius May 17, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm vary of test changes here: what was broken that required getting rid of the mock?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing, just thought maybe better to use an actual object instead of mock no?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the previous code works without changes, let's avoid changing it at all. Let's put test refactoring in separate patches, to avoid hiding potential BC breaks

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Ocramius as you can see tests fail and now I remember why. Because I use getUnquotedColumns instead of getColumns and I added some columns with quotes into data provider. And if I mock here can't test quoted names. I mean this:

$index->expects($this->once())
            ->method('getUnquotedColumns')
            ->will($this->returnValue($indexColumns));

should always return unquoted names and I can't add quoted names in data provider but maybe I don't have to?
I still think actual implementation would be better here and anyway I have to change mocked method anyway.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Ocramius if you want I can still leave this mock but will have to change mocked method and will also have to duplicate this test and test data to actually test quoted names.

@@ -366,7 +366,7 @@ public function intersectsIndexColumns(Index $index)
{
foreach ($index->getUnquotedColumns() as $indexColumn) {
foreach ($this->_localColumnNames as $localColumn) {
if (strtolower($indexColumn) === strtolower($localColumn->trimQuotes($localColumn->getName()))) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it seems this was not required testIntersectsIndexEscapedColumns should cover this

@svycka svycka requested review from Ocramius and morozov February 26, 2020 09:09
@morozov
Copy link
Member

morozov commented Feb 26, 2020

Given that this is a cross-platform change, we need a new functional test that reproduces the problem. Just a unit test that covers some implementation details doesn't tell anyone anything.

@svycka
Copy link
Contributor Author

svycka commented Feb 27, 2020

Given that this is a cross-platform change, we need a new functional test that reproduces the problem. Just a unit test that covers some implementation details doesn't tell anyone anything.

maybe you are right. But I think this is just a bug I don't know database with could say they are different columns just because it is quoted for example column1 and `column1` do you know databases with allows to have those booths? So I think if we check if it exists we should check both at least in this case when we actually mean to check if the column exists.

And about a test, I am not sure how to test this it does not treat it as the same column and you say it is not a bug as I understand. You can see an example here #3387 but I don't know how to write a test for this. Maybe someone could help or write a test for this. Or at least some kind of similar example I could write a test if this is a bug.

@morozov
Copy link
Member

morozov commented Feb 28, 2020

Given that this is a cross-platform change, we need a new functional test that reproduces the problem. Just a unit test that covers some implementation details doesn't tell anyone anything.

maybe you are right.

I usually am.

But I think this is just a bug I don't know database with could say they are different columns just because it is quoted for example column1 and `column1` do you know databases with allows to have those booths?

No.

And about a test, I am not sure how to test this it does not treat it as the same column and you say it is not a bug as I understand.

I’m not saying it's not a bug. I’m saying that the unit test doesn't represent the bug.

You can see an example here #3387 but I don't know how to write a test for this. Maybe someone could help or write a test for this. Or at least some kind of similar example I could write a test if this is a bug.

As for the high-level “what the expected test should look like”, please look at DateExpressionTest.php and DefaultExpressionTest.php. The test should deploy the initial schema to a real DB, make the needed changes to it and assert that the changes have been applied correctly.

@morozov morozov removed their request for review October 23, 2020 16:43
Base automatically changed from master to 4.0.x January 22, 2021 07:44
@morozov morozov closed this Oct 26, 2021
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Oct 27, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants