From fd2f7e47671239dcff98cfb922221ab170aa6461 Mon Sep 17 00:00:00 2001 From: Mariusz Felisiak Date: Tue, 3 Jan 2017 07:13:12 +0100 Subject: [PATCH] Fixed #27681 -- Fixed binary &/| operators for negative values on MySQL. --- django/db/backends/mysql/operations.py | 7 ++++--- tests/expressions/tests.py | 11 ++++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/django/db/backends/mysql/operations.py b/django/db/backends/mysql/operations.py index dd9f56e88d..a9c39b5363 100644 --- a/django/db/backends/mysql/operations.py +++ b/django/db/backends/mysql/operations.py @@ -199,11 +199,12 @@ class DatabaseOperations(BaseDatabaseOperations): return "VALUES " + values_sql def combine_expression(self, connector, sub_expressions): - """ - MySQL requires special cases for ^ operators in query expressions - """ if connector == '^': return 'POW(%s)' % ','.join(sub_expressions) + # Convert the result to a signed integer since MySQL's binary operators + # return an unsigned integer. + elif connector in ('&', '|'): + return 'CONVERT(%s, SIGNED)' % connector.join(sub_expressions) return super(DatabaseOperations, self).combine_expression(connector, sub_expressions) def get_db_converters(self, expression): diff --git a/tests/expressions/tests.py b/tests/expressions/tests.py index 120bf81d1a..ff9f7278c5 100644 --- a/tests/expressions/tests.py +++ b/tests/expressions/tests.py @@ -693,8 +693,10 @@ class ExpressionsNumericTests(TestCase): class ExpressionOperatorTests(TestCase): - def setUp(self): - self.n = Number.objects.create(integer=42, float=15.5) + @classmethod + def setUpTestData(cls): + cls.n = Number.objects.create(integer=42, float=15.5) + cls.n1 = Number.objects.create(integer=-42, float=-15.5) def test_lefthand_addition(self): # LH Addition of floats and integers @@ -737,15 +739,18 @@ class ExpressionOperatorTests(TestCase): def test_lefthand_bitwise_and(self): # LH Bitwise ands on integers Number.objects.filter(pk=self.n.pk).update(integer=F('integer').bitand(56)) + Number.objects.filter(pk=self.n1.pk).update(integer=F('integer').bitand(-56)) self.assertEqual(Number.objects.get(pk=self.n.pk).integer, 40) + self.assertEqual(Number.objects.get(pk=self.n1.pk).integer, -64) self.assertEqual(Number.objects.get(pk=self.n.pk).float, Approximate(15.500, places=3)) def test_lefthand_bitwise_or(self): # LH Bitwise or on integers - Number.objects.filter(pk=self.n.pk).update(integer=F('integer').bitor(48)) + Number.objects.update(integer=F('integer').bitor(48)) self.assertEqual(Number.objects.get(pk=self.n.pk).integer, 58) + self.assertEqual(Number.objects.get(pk=self.n1.pk).integer, -10) self.assertEqual(Number.objects.get(pk=self.n.pk).float, Approximate(15.500, places=3)) def test_lefthand_power(self):