diff options
| author | Nick Pope <nick.pope@flightdataservices.com> | 2019-03-20 18:30:43 +0000 |
|---|---|---|
| committer | Mariusz Felisiak <felisiak.mariusz@gmail.com> | 2019-03-20 19:30:43 +0100 |
| commit | 0b70985f42da7a8eb2e206e6780681b7849564ef (patch) | |
| tree | 5bd1eef1e638abde2a36646a3e769fc83536fb74 /django | |
| parent | 0193bf874f08f21cdec628b8d80d261471bfe5fc (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.py | 5 | ||||
| -rw-r--r-- | django/db/models/functions/__init__.py | 13 | ||||
| -rw-r--r-- | django/db/models/functions/text.py | 76 |
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 |
