summaryrefslogtreecommitdiff
path: root/django/db
diff options
context:
space:
mode:
authorHannes Ljungberg <hannes@5monkeys.se>2020-03-20 23:08:32 +0100
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2020-03-25 10:16:30 +0100
commitf3da09df0f4147223ab76a00a841586ccf11005d (patch)
treee36e8116a5b7abaa453791545a65e3febe3adc87 /django/db
parent39e1c88de67ea2035d5ad89cfe00bcd892c0d163 (diff)
Fixed #31396 -- Added binary XOR operator to F expressions.
Diffstat (limited to 'django/db')
-rw-r--r--django/db/backends/mysql/operations.py3
-rw-r--r--django/db/backends/oracle/operations.py4
-rw-r--r--django/db/backends/sqlite3/base.py1
-rw-r--r--django/db/backends/sqlite3/operations.py2
-rw-r--r--django/db/models/expressions.py4
5 files changed, 12 insertions, 2 deletions
diff --git a/django/db/backends/mysql/operations.py b/django/db/backends/mysql/operations.py
index 6aaf5c6295..e9306f03fc 100644
--- a/django/db/backends/mysql/operations.py
+++ b/django/db/backends/mysql/operations.py
@@ -240,7 +240,8 @@ class DatabaseOperations(BaseDatabaseOperations):
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 ('&', '|', '<<'):
+ elif connector in ('&', '|', '<<', '#'):
+ connector = '^' if connector == '#' else connector
return 'CONVERT(%s, SIGNED)' % connector.join(sub_expressions)
elif connector == '>>':
lhs, rhs = sub_expressions
diff --git a/django/db/backends/oracle/operations.py b/django/db/backends/oracle/operations.py
index 1e59323655..b0b50f7868 100644
--- a/django/db/backends/oracle/operations.py
+++ b/django/db/backends/oracle/operations.py
@@ -3,7 +3,7 @@ import uuid
from functools import lru_cache
from django.conf import settings
-from django.db import DatabaseError
+from django.db import DatabaseError, NotSupportedError
from django.db.backends.base.operations import BaseDatabaseOperations
from django.db.backends.utils import strip_quotes, truncate_name
from django.db.models import AutoField, Exists, ExpressionWrapper
@@ -575,6 +575,8 @@ END;
return 'FLOOR(%(lhs)s / POWER(2, %(rhs)s))' % {'lhs': lhs, 'rhs': rhs}
elif connector == '^':
return 'POWER(%s)' % ','.join(sub_expressions)
+ elif connector == '#':
+ raise NotSupportedError('Bitwise XOR is not supported in Oracle.')
return super().combine_expression(connector, sub_expressions)
def _get_no_autofield_sequence_name(self, table):
diff --git a/django/db/backends/sqlite3/base.py b/django/db/backends/sqlite3/base.py
index 7b3f90a2fd..fcc9d31b37 100644
--- a/django/db/backends/sqlite3/base.py
+++ b/django/db/backends/sqlite3/base.py
@@ -218,6 +218,7 @@ class DatabaseWrapper(BaseDatabaseWrapper):
conn.create_function('ASIN', 1, none_guard(math.asin))
conn.create_function('ATAN', 1, none_guard(math.atan))
conn.create_function('ATAN2', 2, none_guard(math.atan2))
+ conn.create_function('BITXOR', 2, none_guard(operator.xor))
conn.create_function('CEILING', 1, none_guard(math.ceil))
conn.create_function('COS', 1, none_guard(math.cos))
conn.create_function('COT', 1, none_guard(lambda x: 1 / math.tan(x)))
diff --git a/django/db/backends/sqlite3/operations.py b/django/db/backends/sqlite3/operations.py
index 80c32f6fcd..fcc2a06d7a 100644
--- a/django/db/backends/sqlite3/operations.py
+++ b/django/db/backends/sqlite3/operations.py
@@ -312,6 +312,8 @@ class DatabaseOperations(BaseDatabaseOperations):
# function that's registered in connect().
if connector == '^':
return 'POWER(%s)' % ','.join(sub_expressions)
+ elif connector == '#':
+ return 'BITXOR(%s)' % ','.join(sub_expressions)
return super().combine_expression(connector, sub_expressions)
def combine_duration_expression(self, connector, sub_expressions):
diff --git a/django/db/models/expressions.py b/django/db/models/expressions.py
index 84960d77e1..4753a258f9 100644
--- a/django/db/models/expressions.py
+++ b/django/db/models/expressions.py
@@ -51,6 +51,7 @@ class Combinable:
BITOR = '|'
BITLEFTSHIFT = '<<'
BITRIGHTSHIFT = '>>'
+ BITXOR = '#'
def _combine(self, other, connector, reversed):
if not hasattr(other, 'resolve_expression'):
@@ -105,6 +106,9 @@ class Combinable:
def bitrightshift(self, other):
return self._combine(other, self.BITRIGHTSHIFT, False)
+ def bitxor(self, other):
+ return self._combine(other, self.BITXOR, False)
+
def __or__(self, other):
if getattr(self, 'conditional', False) and getattr(other, 'conditional', False):
return Q(self) | Q(other)