Open BenjaminNolan opened 6 years ago
On DBMSes which don't support partial indices, such as MySQL, Doctrine simply drops the
where
clause
@powerkiki this feature was built by you some time ago, and I don't know if it is a good idea to have it in ORM anymore (sorry!): Could you advise on how to move forward?
@BenjaminNolan, the doc clearly explains that options
and also where
is platform specific. IMHO you should not expect platform specific things to work for all platforms.
@Ocramius why would you think this should no longer be part or ORM ? AFAIK it is not the only thing that is platform specific, and it exposes useful features that would not have any workaround if we remove it ?
For reference the original PR was #1027.
Whilst it does indeed explain that the where
option is platform specific, the fallback behaviour for normal partial indices is fine, whereas the fallback behaviour for unique partial constraints results in potentially application-breaking behaviour. It's for this reason that I brought it up, as, generally, Doctrine tries to fail safe.
Perhaps we could add an additional option to indicate that Doctrine should drop the constraint entirely on platforms that don't support partial indices? But feel free to close this if you'd rather, I just wanted mainly to raise the fact that the fallback behaviour for one particular case can be problematic.
Unfortunately I think your expectations are too high. "fallback behaviour" is a nice way to say "don't do anything at all, because it's not even aware of the option potential existence".
I'd have to double check, but I'm pretty sure it's exactly the same behavior for other non supported, platform specific options. Meaning that they are entirely and silently ignored. Calling that a fallback is a bit generous.
I suppose we could technically throw exceptions in non supported platforms. But then it should be done for every single features, and I'm not sure if it's a direction doctrine would want to go.
For now, I wouldn't touch anything, or at most improve the docs. But I don't see a strong case for removing a working, tested and useful feature. And I don't really see a strong case either to change something in non supported platforms.
I suppose we could technically throw exceptions in non supported platforms. But then it should be done for every single features, and I'm not sure if it's a direction doctrine would want to go.
Currently, such indexes can lead to incorrect/misleading behaviour if silently skipped, so an exception is preferable over a silent skip.
Unsure about which other features get silently skipped, but that's dangerous and probably to be prevented by stopping execution (exception)
An exception would definitely be an improvement in this particular instance. :)
According to grep -rPoh ">getOption\('[^']*'\)" .|sort -u
ran on DBAL master, we have the following options that are platform specifics and that would need to throw exceptions in non-supported platforms:
So while we could probably hardcode a whitelist of options (and their values) for table, foreignKey and index for each platforms, it feels like a lot of maintenance work for something that is clearly documented as "fragile" to begin with.
While I understand that the current situation is not perfect, it is a documented, widespread and consistent pattern in the project. My opinion is still to do nothing about it.
Today I stumbled upon a feature request for partial indexes in MariaDB (and MySQL too). This might one day also land in their codebase. So that's one more reason to not remove our support for it.
Bug Report
We've been weighing up whether to report this one, but I've decided to go ahead with it as the behaviour is unexpected at the very least.
Summary
When declaring an
@Index
or a@UniqueConstraint
on a@Table
, you can provide awhere
clause in theoptions
parameter which will convert the index from a full index to a partial one. On DBMSes which don't support partial indices, such as MySQL, Doctrine simply drops thewhere
clause from the statement that it generates. For@Index
annotations, this is fine, as the fallback functionality is to create a full-table index rather than a partial one. However, for@UniqueConstraint
annotations, dropping thewhere
clause can cause incorrect behaviour in an application, and, in our case, errors when executing the statement.In our application, a user has one or more email addresses linked to their account, one of which is marked as their primary address. They can have several non-primary addresses. We currently enforce this constraint in our code, however in the future we are likely to move to a DBMS which has support for partial indices and want to add the partial constraint annotation now. Unfortunately, when we do add this, it generates a query which would limit the user to a maximum of two addresses, one primary, and one secondary.
How to reproduce
The following two entities are simplified versions of the ones from our application.
Inserting a row into
user
, and then several rows intoemail
linked to this user id where one only is marked as primary and at least two are marked as not-primary works correctly. Now modify the annotation forEmail
to this and rundoctrine:schema:update --dump-sql
:When we dump the SQL from the schema tool on MySQL, it generates this UNIQUE query:
Running this query with the data described above would result in an error.
Expected behavior
We believe that Doctrine should actually omit this query entirely on DBMSes which do not support partial unique constraints, as the query that is generated does not enforce the same logic as the partial constraint, and the fallback for omitting it entirely is less problematic than adding it.
Apologies for this being a bit rambly. I am very tired. :) Please let me know if you need any additional information.