mirror of
https://github.com/django/django.git
synced 2025-10-26 15:16:09 +00:00
Fixed #17027 -- Added support for the power operator in F expressions.
Thanks dan at dlo.me for the initial patch. - Added __pow__ and __rpow__ to ExpressionNode - Added oracle and mysql specific power expressions - Added used-defined power function for sqlite
This commit is contained in:
@@ -386,6 +386,14 @@ class DatabaseOperations(BaseDatabaseOperations):
|
||||
items_sql = "(%s)" % ", ".join(["%s"] * len(fields))
|
||||
return "VALUES " + ", ".join([items_sql] * num_values)
|
||||
|
||||
def combine_expression(self, connector, sub_expressions):
|
||||
"""
|
||||
MySQL requires special cases for ^ operators in query expressions
|
||||
"""
|
||||
if connector == '^':
|
||||
return 'POW(%s)' % ','.join(sub_expressions)
|
||||
return super(DatabaseOperations, self).combine_expression(connector, sub_expressions)
|
||||
|
||||
|
||||
class DatabaseWrapper(BaseDatabaseWrapper):
|
||||
vendor = 'mysql'
|
||||
|
||||
@@ -482,6 +482,8 @@ WHEN (new.%(col_name)s IS NULL)
|
||||
return 'BITAND(%s)' % ','.join(sub_expressions)
|
||||
elif connector == '|':
|
||||
raise NotImplementedError("Bit-wise or is not supported in Oracle.")
|
||||
elif connector == '^':
|
||||
return 'POWER(%s)' % ','.join(sub_expressions)
|
||||
return super(DatabaseOperations, self).combine_expression(connector, sub_expressions)
|
||||
|
||||
def _get_sequence_name(self, table):
|
||||
|
||||
@@ -304,6 +304,13 @@ class DatabaseOperations(BaseDatabaseOperations):
|
||||
res.extend(["UNION ALL SELECT %s" % ", ".join(["%s"] * len(fields))] * (num_values - 1))
|
||||
return " ".join(res)
|
||||
|
||||
def combine_expression(self, connector, sub_expressions):
|
||||
# SQLite doesn't have a power function, so we fake it with a
|
||||
# user-defined function django_power that's registered in connect().
|
||||
if connector == '^':
|
||||
return 'django_power(%s)' % ','.join(sub_expressions)
|
||||
return super(DatabaseOperations, self).combine_expression(connector, sub_expressions)
|
||||
|
||||
|
||||
class DatabaseWrapper(BaseDatabaseWrapper):
|
||||
vendor = 'sqlite'
|
||||
@@ -376,6 +383,7 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
||||
conn.create_function("django_datetime_trunc", 3, _sqlite_datetime_trunc)
|
||||
conn.create_function("regexp", 2, _sqlite_regexp)
|
||||
conn.create_function("django_format_dtdelta", 5, _sqlite_format_dtdelta)
|
||||
conn.create_function("django_power", 2, _sqlite_power)
|
||||
return conn
|
||||
|
||||
def init_connection_state(self):
|
||||
@@ -567,3 +575,7 @@ def _sqlite_format_dtdelta(dt, conn, days, secs, usecs):
|
||||
|
||||
def _sqlite_regexp(re_pattern, re_string):
|
||||
return bool(re.search(re_pattern, force_text(re_string))) if re_string is not None else False
|
||||
|
||||
|
||||
def _sqlite_power(x, y):
|
||||
return x ** y
|
||||
|
||||
@@ -14,6 +14,7 @@ class ExpressionNode(tree.Node):
|
||||
SUB = '-'
|
||||
MUL = '*'
|
||||
DIV = '/'
|
||||
POW = '^'
|
||||
MOD = '%%' # This is a quoted % operator - it is quoted
|
||||
# because it can be used in strings that also
|
||||
# have parameter substitution.
|
||||
@@ -85,6 +86,9 @@ class ExpressionNode(tree.Node):
|
||||
def __mod__(self, other):
|
||||
return self._combine(other, self.MOD, False)
|
||||
|
||||
def __pow__(self, other):
|
||||
return self._combine(other, self.POW, False)
|
||||
|
||||
def __and__(self, other):
|
||||
raise NotImplementedError(
|
||||
"Use .bitand() and .bitor() for bitwise logical operations."
|
||||
@@ -119,6 +123,9 @@ class ExpressionNode(tree.Node):
|
||||
def __rmod__(self, other):
|
||||
return self._combine(other, self.MOD, True)
|
||||
|
||||
def __rpow__(self, other):
|
||||
return self._combine(other, self.POW, True)
|
||||
|
||||
def __rand__(self, other):
|
||||
raise NotImplementedError(
|
||||
"Use .bitand() and .bitor() for bitwise logical operations."
|
||||
|
||||
Reference in New Issue
Block a user