#23576: ORM delete strategy can lead to race conditions inside a transaction -------------------------------------+------------------------------------- Reporter: jdufresne | Owner: nobody Type: Uncategorized | Status: new Component: Database layer | Version: 1.7 (models, ORM) | Resolution: Severity: Normal | Triage Stage: Keywords: | Unreviewed Has patch: 0 | Needs documentation: 0 Needs tests: 0 | Patch needs improvement: 0 Easy pickings: 0 | UI/UX: 0 -------------------------------------+-------------------------------------
Comment (by jdufresne): This looks specific to database backends that do not support `update_can_self_select`. From the list of database backends shipped with Django, this applies only to MySQL. This is the race free query generated for backends supporting `update_can_self_select`. {{{ DELETE FROM `myapp_c` WHERE `myapp_c`.`id` IN (SELECT U0.`id` AS `id` FROM `myapp_c` U0 INNER JOIN `myapp_a` U1 ON ( U0.`a_id` = U1.`id` ) INNER JOIN `myapp_b` U2 ON ( U0.`b_id` = U2.`id` ) WHERE (U1.`name` = 'foo' AND U2.`name` = 'bar')) }}} The problematic queries used by the MySQL: {{{ SELECT `myapp_c`.`id` FROM `myapp_c` INNER JOIN `myapp_a` ON ( `myapp_c`.`a_id` = `myapp_a`.`id` ) INNER JOIN `myapp_b` ON ( `myapp_c`.`b_id` = `myapp_b`.`id` ) WHERE (`myapp_a`.`name` = 'foo' AND `myapp_b`.`name` = 'bar') DELETE FROM `myapp_c` WHERE `myapp_c`.`id` IN ({ RESULT FROM PREVIOUS QUERY }) }}} The fact that this occurs across two queries allows rows to be inserted that would normally meet the criteria of the `WHERE` clause. One way to handle this would be to use MySQL's multiple table syntax http://dev.mysql.com/doc/refman/5.7/en/delete.html which allows joins. The query would be as simple as taking the `SELECT` query, removing the `SELECT` clause and replacing it with `DELETE myapp_c FROM myapp_c INNER JOIN ...`. I am interested in doing this, however, I'm not sure exactly where to start in order to build a better query. I see inside `DeleteQuery.delete_qs()` is where the check for feature `update_can_self_select` occurs. So perhaps a new feature check and branch should occur here. However, once the feature is checked, I'm not sure how to start building the alternative query. Any guidance would be appreciated. -- Ticket URL: <https://code.djangoproject.com/ticket/23576#comment:2> Django <https://code.djangoproject.com/> The Web framework for perfectionists with deadlines. -- You received this message because you are subscribed to the Google Groups "Django updates" group. To unsubscribe from this group and stop receiving emails from it, send an email to django-updates+unsubscr...@googlegroups.com. To post to this group, send email to django-updates@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/django-updates/067.3d7c803c3e6a9a457fbcfa62aa0133a5%40djangoproject.com. For more options, visit https://groups.google.com/d/optout.