mirror of
https://github.com/doctrine/orm.git
synced 2026-03-23 22:42:18 +01:00
Partial unique constraints should not be created as full unique constraints on MySQL #5998
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @BenjaminNolan on GitHub (Jun 22, 2018).
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
@Indexor a@UniqueConstrainton a@Table, you can provide awhereclause in theoptionsparameter 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 thewhereclause from the statement that it generates. For@Indexannotations, this is fine, as the fallback functionality is to create a full-table index rather than a partial one. However, for@UniqueConstraintannotations, dropping thewhereclause 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 intoemaillinked 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 forEmailto 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.
@Ocramius commented on GitHub (Jun 23, 2018):
@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?
@PowerKiKi commented on GitHub (Jun 23, 2018):
@BenjaminNolan, the doc clearly explains that
optionsand alsowhereis 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 ?
@PowerKiKi commented on GitHub (Jun 23, 2018):
For reference the original PR was #1027.
@BenjaminNolan commented on GitHub (Jun 25, 2018):
Whilst it does indeed explain that the
whereoption 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.
@PowerKiKi commented on GitHub (Jun 27, 2018):
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.
@Ocramius commented on GitHub (Jun 27, 2018):
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)
@BenjaminNolan commented on GitHub (Jun 29, 2018):
An exception would definitely be an improvement in this particular instance. :)
@PowerKiKi commented on GitHub (Jul 15, 2018):
According to
grep -rPoh ">getOption\('[^']*'\)" .|sort -uran 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.
@PowerKiKi commented on GitHub (Jul 28, 2018):
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.