mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	Fixed #33759 -- Avoided unnecessary subquery in QuerySet.delete() with self-referential subqueries if supported.
This commit is contained in:
		
				
					committed by
					
						 Mariusz Felisiak
						Mariusz Felisiak
					
				
			
			
				
	
			
			
			
						parent
						
							5a6d4d3bfd
						
					
				
				
					commit
					0b0998dc15
				
			| @@ -12,6 +12,9 @@ class BaseDatabaseFeatures: | ||||
|     allows_group_by_select_index = True | ||||
|     empty_fetchmany_value = [] | ||||
|     update_can_self_select = True | ||||
|     # Does the backend support self-reference subqueries in the DELETE | ||||
|     # statement? | ||||
|     delete_can_self_reference_subquery = True | ||||
|  | ||||
|     # Does the backend distinguish between '' and None? | ||||
|     interprets_empty_strings_as_nulls = False | ||||
|   | ||||
| @@ -24,6 +24,7 @@ class DatabaseFeatures(BaseDatabaseFeatures): | ||||
|     supports_slicing_ordering_in_compound = True | ||||
|     supports_index_on_text_field = False | ||||
|     supports_update_conflicts = True | ||||
|     delete_can_self_reference_subquery = False | ||||
|     create_test_procedure_without_params_sql = """ | ||||
|         CREATE PROCEDURE test_procedure () | ||||
|         BEGIN | ||||
|   | ||||
| @@ -1890,7 +1890,10 @@ class SQLDeleteCompiler(SQLCompiler): | ||||
|         Create the SQL for this query. Return the SQL string and list of | ||||
|         parameters. | ||||
|         """ | ||||
|         if self.single_alias and not self.contains_self_reference_subquery: | ||||
|         if self.single_alias and ( | ||||
|             self.connection.features.delete_can_self_reference_subquery | ||||
|             or not self.contains_self_reference_subquery | ||||
|         ): | ||||
|             return self._as_sql(self.query) | ||||
|         innerq = self.query.clone() | ||||
|         innerq.__class__ = Query | ||||
|   | ||||
| @@ -379,15 +379,20 @@ class DeleteTests(TestCase): | ||||
|         child = Child.objects.create(name="Juan") | ||||
|         Book.objects.create(pagecount=500, owner=child) | ||||
|         PlayedWith.objects.create(child=child, toy=toy, date=datetime.date.today()) | ||||
|         Book.objects.filter( | ||||
|             Exists( | ||||
|                 Book.objects.filter( | ||||
|                     pk=OuterRef("pk"), | ||||
|                     owner__toys=toy.pk, | ||||
|                 ), | ||||
|             ) | ||||
|         ).delete() | ||||
|         with self.assertNumQueries(1) as ctx: | ||||
|             Book.objects.filter( | ||||
|                 Exists( | ||||
|                     Book.objects.filter( | ||||
|                         pk=OuterRef("pk"), | ||||
|                         owner__toys=toy.pk, | ||||
|                     ), | ||||
|                 ) | ||||
|             ).delete() | ||||
|  | ||||
|         self.assertIs(Book.objects.exists(), False) | ||||
|         sql = ctx.captured_queries[0]["sql"].lower() | ||||
|         if connection.features.delete_can_self_reference_subquery: | ||||
|             self.assertEqual(sql.count("select"), 1) | ||||
|  | ||||
|  | ||||
| class DeleteDistinct(SimpleTestCase): | ||||
|   | ||||
		Reference in New Issue
	
	Block a user