summaryrefslogtreecommitdiff
path: root/django
diff options
context:
space:
mode:
authorNick Pope <nick.pope@flightdataservices.com>2019-03-20 18:30:43 +0000
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2019-03-20 19:30:43 +0100
commit0b70985f42da7a8eb2e206e6780681b7849564ef (patch)
tree5bd1eef1e638abde2a36646a3e769fc83536fb74 /django
parent0193bf874f08f21cdec628b8d80d261471bfe5fc (diff)
Fixed #30240 -- Added SHA1, SHA224, SHA256, SHA384, and SHA512 database functions.
Thanks Mariusz Felisiak and Tim Graham for reviews.
Diffstat (limited to 'django')
-rw-r--r--django/db/backends/sqlite3/base.py5
-rw-r--r--django/db/models/functions/__init__.py13
-rw-r--r--django/db/models/functions/text.py76
3 files changed, 76 insertions, 18 deletions
diff --git a/django/db/backends/sqlite3/base.py b/django/db/backends/sqlite3/base.py
index 9f30b75e6a..7552956cd9 100644
--- a/django/db/backends/sqlite3/base.py
+++ b/django/db/backends/sqlite3/base.py
@@ -226,6 +226,11 @@ class DatabaseWrapper(BaseDatabaseWrapper):
conn.create_function('REPEAT', 2, none_guard(operator.mul))
conn.create_function('REVERSE', 1, none_guard(lambda x: x[::-1]))
conn.create_function('RPAD', 3, _sqlite_rpad)
+ conn.create_function('SHA1', 1, none_guard(lambda x: hashlib.sha1(x.encode()).hexdigest()))
+ conn.create_function('SHA224', 1, none_guard(lambda x: hashlib.sha224(x.encode()).hexdigest()))
+ conn.create_function('SHA256', 1, none_guard(lambda x: hashlib.sha256(x.encode()).hexdigest()))
+ conn.create_function('SHA384', 1, none_guard(lambda x: hashlib.sha384(x.encode()).hexdigest()))
+ conn.create_function('SHA512', 1, none_guard(lambda x: hashlib.sha512(x.encode()).hexdigest()))
conn.create_function('SIN', 1, none_guard(math.sin))
conn.create_function('SQRT', 1, none_guard(math.sqrt))
conn.create_function('TAN', 1, none_guard(math.tan))
diff --git a/django/db/models/functions/__init__.py b/django/db/models/functions/__init__.py
index 88bc43431a..fb899127d2 100644
--- a/django/db/models/functions/__init__.py
+++ b/django/db/models/functions/__init__.py
@@ -10,9 +10,9 @@ from .math import (
Mod, Pi, Power, Radians, Round, Sin, Sqrt, Tan,
)
from .text import (
- MD5, Chr, Concat, ConcatPair, Left, Length, Lower, LPad, LTrim, Ord,
- Repeat, Replace, Reverse, Right, RPad, RTrim, StrIndex, Substr, Trim,
- Upper,
+ MD5, SHA1, SHA224, SHA256, SHA384, SHA512, Chr, Concat, ConcatPair, Left,
+ Length, Lower, LPad, LTrim, Ord, Repeat, Replace, Reverse, Right, RPad,
+ RTrim, StrIndex, Substr, Trim, Upper,
)
from .window import (
CumeDist, DenseRank, FirstValue, Lag, LastValue, Lead, NthValue, Ntile,
@@ -34,9 +34,10 @@ __all__ = [
'Exp', 'Floor', 'Ln', 'Log', 'Mod', 'Pi', 'Power', 'Radians', 'Round',
'Sin', 'Sqrt', 'Tan',
# text
- 'MD5', 'Chr', 'Concat', 'ConcatPair', 'Left', 'Length', 'Lower', 'LPad',
- 'LTrim', 'Ord', 'Repeat', 'Replace', 'Reverse', 'Right', 'RPad', 'RTrim',
- 'StrIndex', 'Substr', 'Trim', 'Upper',
+ 'MD5', 'SHA1', 'SHA224', 'SHA256', 'SHA384', 'SHA512', 'Chr', 'Concat',
+ 'ConcatPair', 'Left', 'Length', 'Lower', 'LPad', 'LTrim', 'Ord', 'Repeat',
+ 'Replace', 'Reverse', 'Right', 'RPad', 'RTrim', 'StrIndex', 'Substr',
+ 'Trim', 'Upper',
# window
'CumeDist', 'DenseRank', 'FirstValue', 'Lag', 'LastValue', 'Lead',
'NthValue', 'Ntile', 'PercentRank', 'Rank', 'RowNumber',
diff --git a/django/db/models/functions/text.py b/django/db/models/functions/text.py
index 58f920082b..2b2495c5c4 100644
--- a/django/db/models/functions/text.py
+++ b/django/db/models/functions/text.py
@@ -2,6 +2,7 @@ from django.db.models.expressions import Func, Value
from django.db.models.fields import IntegerField
from django.db.models.functions import Coalesce
from django.db.models.lookups import Transform
+from django.db.utils import NotSupportedError
class BytesToCharFieldConversionMixin:
@@ -20,6 +21,40 @@ class BytesToCharFieldConversionMixin:
return super().convert_value(value, expression, connection)
+class MySQLSHA2Mixin:
+ def as_mysql(self, compiler, connection, **extra_content):
+ return super().as_sql(
+ compiler,
+ connection,
+ template='SHA2(%%(expressions)s, %s)' % self.function[3:],
+ **extra_content,
+ )
+
+
+class OracleHashMixin:
+ def as_oracle(self, compiler, connection, **extra_context):
+ return super().as_sql(
+ compiler,
+ connection,
+ template=(
+ "LOWER(RAWTOHEX(STANDARD_HASH(UTL_I18N.STRING_TO_RAW("
+ "%(expressions)s, 'AL32UTF8'), '%(function)s')))"
+ ),
+ **extra_context,
+ )
+
+
+class PostgreSQLSHAMixin:
+ def as_postgresql(self, compiler, connection, **extra_content):
+ return super().as_sql(
+ compiler,
+ connection,
+ template="ENCODE(DIGEST(%(expressions)s, '%(function)s'), 'hex')",
+ function=self.function.lower(),
+ **extra_content,
+ )
+
+
class Chr(Transform):
function = 'CHR'
lookup_name = 'chr'
@@ -150,21 +185,10 @@ class LTrim(Transform):
lookup_name = 'ltrim'
-class MD5(Transform):
+class MD5(OracleHashMixin, Transform):
function = 'MD5'
lookup_name = 'md5'
- def as_oracle(self, compiler, connection, **extra_context):
- return super().as_sql(
- compiler,
- connection,
- template=(
- "LOWER(RAWTOHEX(STANDARD_HASH(UTL_I18N.STRING_TO_RAW("
- "%(expressions)s, 'AL32UTF8'), '%(function)s')))"
- ),
- **extra_context,
- )
-
class Ord(Transform):
function = 'ASCII'
@@ -235,6 +259,34 @@ class RTrim(Transform):
lookup_name = 'rtrim'
+class SHA1(OracleHashMixin, PostgreSQLSHAMixin, Transform):
+ function = 'SHA1'
+ lookup_name = 'sha1'
+
+
+class SHA224(MySQLSHA2Mixin, PostgreSQLSHAMixin, Transform):
+ function = 'SHA224'
+ lookup_name = 'sha224'
+
+ def as_oracle(self, compiler, connection, **extra_context):
+ raise NotSupportedError('SHA224 is not supported on Oracle.')
+
+
+class SHA256(MySQLSHA2Mixin, OracleHashMixin, PostgreSQLSHAMixin, Transform):
+ function = 'SHA256'
+ lookup_name = 'sha256'
+
+
+class SHA384(MySQLSHA2Mixin, OracleHashMixin, PostgreSQLSHAMixin, Transform):
+ function = 'SHA384'
+ lookup_name = 'sha384'
+
+
+class SHA512(MySQLSHA2Mixin, OracleHashMixin, PostgreSQLSHAMixin, Transform):
+ function = 'SHA512'
+ lookup_name = 'sha512'
+
+
class StrIndex(Func):
"""
Return a positive integer corresponding to the 1-indexed position of the