소스 검색

Fixed #30412 -- Fixed crash when adding check constraints with OR'ed condition on Oracle and SQLite.

can 5 년 전
부모
커밋
719b746620
4개의 변경된 파일42개의 추가작업 그리고 1개의 파일을 삭제
  1. 1 1
      django/db/models/sql/query.py
  2. 3 0
      docs/releases/2.2.1.txt
  3. 23 0
      tests/migrations/test_operations.py
  4. 15 0
      tests/queries/test_query.py

+ 1 - 1
django/db/models/sql/query.py

@@ -1338,7 +1338,7 @@ class Query(BaseExpression):
             if isinstance(child, Node):
                 child_clause, needed_inner = self._add_q(
                     child, used_aliases, branch_negated,
-                    current_negated, allow_joins, split_subq)
+                    current_negated, allow_joins, split_subq, simple_col)
                 joinpromoter.add_votes(needed_inner)
             else:
                 child_clause, needed_inner = self.build_filter(

+ 3 - 0
docs/releases/2.2.1.txt

@@ -74,3 +74,6 @@ Bugfixes
 * Fixed a migration crash on Oracle and PostgreSQL when adding a check
   constraint with a ``contains``, ``startswith``, or ``endswith`` lookup (or
   their case-insensitive variant) (:ticket:`30408`).
+
+* Fixed a migration crash on Oracle and SQLite when adding a check constraint
+  with ``condition`` contains ``|`` (``OR``) operator (:ticket:`30412`).

+ 23 - 0
tests/migrations/test_operations.py

@@ -1898,6 +1898,29 @@ class OperationTests(OperationTestBase):
         author = Author.objects.create(name='Albert', rebate='10%')
         self.assertEqual(Author.objects.get(), author)
 
+    @skipUnlessDBFeature('supports_table_check_constraints')
+    def test_add_or_constraint(self):
+        app_label = 'test_addorconstraint'
+        constraint_name = 'add_constraint_or'
+        from_state = self.set_up_test_model(app_label)
+        check = models.Q(pink__gt=2, weight__gt=2) | models.Q(weight__lt=0)
+        constraint = models.CheckConstraint(check=check, name=constraint_name)
+        operation = migrations.AddConstraint('Pony', constraint)
+        to_state = from_state.clone()
+        operation.state_forwards(app_label, to_state)
+        with connection.schema_editor() as editor:
+            operation.database_forwards(app_label, editor, from_state, to_state)
+        Pony = to_state.apps.get_model(app_label, 'Pony')
+        with self.assertRaises(IntegrityError), transaction.atomic():
+            Pony.objects.create(pink=2, weight=3.0)
+        with self.assertRaises(IntegrityError), transaction.atomic():
+            Pony.objects.create(pink=3, weight=1.0)
+        Pony.objects.bulk_create([
+            Pony(pink=3, weight=-1.0),
+            Pony(pink=1, weight=-1.0),
+            Pony(pink=3, weight=3.0),
+        ])
+
     @skipUnlessDBFeature('supports_table_check_constraints')
     def test_remove_constraint(self):
         project_state = self.set_up_test_model("test_removeconstraint", constraints=[

+ 15 - 0
tests/queries/test_query.py

@@ -23,6 +23,21 @@ class TestQuery(SimpleTestCase):
         self.assertEqual(lookup.rhs, 2)
         self.assertEqual(lookup.lhs.target, Author._meta.get_field('num'))
 
+    def test_simplecol_query(self):
+        query = Query(Author)
+        where = query.build_where(Q(num__gt=2, name__isnull=False) | Q(num__lt=F('id')))
+
+        name_isnull_lookup, num_gt_lookup = where.children[0].children
+        self.assertIsInstance(num_gt_lookup, GreaterThan)
+        self.assertIsInstance(num_gt_lookup.lhs, SimpleCol)
+        self.assertIsInstance(name_isnull_lookup, IsNull)
+        self.assertIsInstance(name_isnull_lookup.lhs, SimpleCol)
+
+        num_lt_lookup = where.children[1]
+        self.assertIsInstance(num_lt_lookup, LessThan)
+        self.assertIsInstance(num_lt_lookup.rhs, SimpleCol)
+        self.assertIsInstance(num_lt_lookup.lhs, SimpleCol)
+
     def test_complex_query(self):
         query = Query(Author)
         where = query.build_where(Q(num__gt=2) | Q(num__lt=0))