Fix collection filtering API for IN/NOT IN comparisons that require type conversions#12190
Conversation
f6d4c47 to
bd86a47
Compare
morozov
left a comment
There was a problem hiding this comment.
Looks good from the DBAL perspective 👍
|
The commits would need to be squashed either by you or the person who merges. |
tests/Tests/ORM/Functional/ValueConversionType/ManyToManyCriteriaMatchingTest.php
Outdated
Show resolved
Hide resolved
tests/Tests/ORM/Functional/ValueConversionType/ManyToManyCriteriaMatchingTest.php
Outdated
Show resolved
Hide resolved
…ype conversions This PR fixes the `Criteria` matching API for `IN` and `NIN` conditions with values that are arrays, by making sure that type information for the matched field is passed to the DBAL level correctly. Passing the right parameter type to DBAL is important to make sure parameter conversions are applied before matching at the database level. Memory-based collections (`ArrayCollection`s or initialized collection fields) would perform matching on the objects in memory where no type conversion to the database representation is required, giving correct results. But uninitialized collections that have their conditions evaluated at the database level need to convert parameter values to the database representation before performing the comparison. One extra challenge is that the DBAL type system does currently not support array-valued parameters for custom types. Only a [limited list of types](https://www.doctrine-project.org/projects/doctrine-dbal/en/4.2/reference/data-retrieval-and-manipulation.html#list-of-parameters-conversion) is supported. I discussed this with @morozov at the Doctrine Hackathon and came to the conclusion that it would be best to work around this limitation at the ORM level. Thus, this fix recognizes array-valued parameters and creates multiple placeholders (like `?, ?, ?`) for them, flattening out the arrays in the parameter list and repeating the type information for each one of them. Previous stalled attempt to fix this was in doctrine#11897.
0d93196 to
7a59281
Compare
|
Thanks @mpdude |
|
Hi, In version 2.20.6 it generates the following SQL But 2.20.7 generates invalid SQL This may be very surprising after update to a patch version, especially when the value is passed as a variable from another part of the application. |
|
Hm, seems this was not covered by the existing test suite
So, should passing an empty array mean that we want a false condition (like |
|
Yes, IN (NULL) is always false. public function getByIds(array $ids): array
{
return $this->getRepository()->findBy(['id' => $ids]);
}I would expect this code to return no results (as it's not changing the existing behavior).
Yes, that summarizes it very well 💚 |
This is definitely a breaking change. We have a few cases where we use that and a patch version should not introduce a breaking change. Changing from 3.5.2 to 3.5.3 breaks out projects badly because of this. It means we have to go in every case where we use IN() and add a if ([] === $argument) {...} because if this. |
|
This breaks a custom type on the This is when doing a Any pointers on how to fix this would be appreciated 🙏🏼 . For now I've reverted to 3.5.2 |
This PR fixes the
Criteriamatching API forINandNINconditions with values that are arrays, by making sure that type information for the matched field is passed to the DBAL level correctly.Passing the right parameter type to DBAL is important to make sure parameter conversions are applied before matching at the database level.
Memory-based collections (
ArrayCollections or initialized collection fields) would perform matching on the objects in memory where no type conversion to the database representation is required, giving correct results.But uninitialized collections that have their conditions evaluated at the database level need to convert parameter values to the database representation before performing the comparison.
One extra challenge is that the DBAL type system does currently not support array-valued parameters for custom types. Only a limited list of types is supported.
I discussed this with @morozov at the Doctrine Hackathon and came to the conclusion that it would be best to work around this limitation at the ORM level. Thus, this fix recognizes array-valued parameters and creates multiple placeholders (like
?, ?, ?) for them, flattening out the arrays in the parameter list and repeating the type information for each one of them.Previous stalled attempt to fix this was in #11897.