From 026719cf17ae2b088f7553321f2ca6b45efa8cb4 Mon Sep 17 00:00:00 2001 From: Sergey Fedoseev Date: Tue, 26 Nov 2019 11:59:05 +0500 Subject: [PATCH] Fixed #31030 -- Registered SQLite functions as deterministic on Python 3.8+. --- django/db/backends/sqlite3/base.py | 94 ++++++++++++++++-------------- docs/releases/3.1.txt | 4 ++ 2 files changed, 55 insertions(+), 43 deletions(-) diff --git a/django/db/backends/sqlite3/base.py b/django/db/backends/sqlite3/base.py index fcc9d31b37d..26968475bf7 100644 --- a/django/db/backends/sqlite3/base.py +++ b/django/db/backends/sqlite3/base.py @@ -24,6 +24,7 @@ from django.utils.asyncio import async_unsafe from django.utils.dateparse import parse_datetime, parse_time from django.utils.duration import duration_microseconds from django.utils.regex_helper import _lazy_re_compile +from django.utils.version import PY38 from .client import DatabaseClient # isort:skip from .creation import DatabaseCreation # isort:skip @@ -202,49 +203,56 @@ class DatabaseWrapper(BaseDatabaseWrapper): @async_unsafe def get_new_connection(self, conn_params): conn = Database.connect(**conn_params) - conn.create_function("django_date_extract", 2, _sqlite_datetime_extract) - conn.create_function("django_date_trunc", 2, _sqlite_date_trunc) - conn.create_function('django_datetime_cast_date', 3, _sqlite_datetime_cast_date) - conn.create_function('django_datetime_cast_time', 3, _sqlite_datetime_cast_time) - conn.create_function('django_datetime_extract', 4, _sqlite_datetime_extract) - conn.create_function('django_datetime_trunc', 4, _sqlite_datetime_trunc) - conn.create_function("django_time_extract", 2, _sqlite_time_extract) - conn.create_function("django_time_trunc", 2, _sqlite_time_trunc) - conn.create_function("django_time_diff", 2, _sqlite_time_diff) - conn.create_function("django_timestamp_diff", 2, _sqlite_timestamp_diff) - conn.create_function("django_format_dtdelta", 3, _sqlite_format_dtdelta) - conn.create_function('regexp', 2, _sqlite_regexp) - conn.create_function('ACOS', 1, none_guard(math.acos)) - 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))) - conn.create_function('DEGREES', 1, none_guard(math.degrees)) - conn.create_function('EXP', 1, none_guard(math.exp)) - conn.create_function('FLOOR', 1, none_guard(math.floor)) - conn.create_function('LN', 1, none_guard(math.log)) - conn.create_function('LOG', 2, none_guard(lambda x, y: math.log(y, x))) - conn.create_function('LPAD', 3, _sqlite_lpad) - conn.create_function('MD5', 1, none_guard(lambda x: hashlib.md5(x.encode()).hexdigest())) - conn.create_function('MOD', 2, none_guard(math.fmod)) - conn.create_function('PI', 0, lambda: math.pi) - conn.create_function('POWER', 2, none_guard(operator.pow)) - conn.create_function('RADIANS', 1, none_guard(math.radians)) - 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('SIGN', 1, none_guard(lambda x: (x > 0) - (x < 0))) - 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)) + if PY38: + create_deterministic_function = functools.partial( + conn.create_function, + deterministic=True, + ) + else: + create_deterministic_function = conn.create_function + create_deterministic_function('django_date_extract', 2, _sqlite_datetime_extract) + create_deterministic_function('django_date_trunc', 2, _sqlite_date_trunc) + create_deterministic_function('django_datetime_cast_date', 3, _sqlite_datetime_cast_date) + create_deterministic_function('django_datetime_cast_time', 3, _sqlite_datetime_cast_time) + create_deterministic_function('django_datetime_extract', 4, _sqlite_datetime_extract) + create_deterministic_function('django_datetime_trunc', 4, _sqlite_datetime_trunc) + create_deterministic_function('django_time_extract', 2, _sqlite_time_extract) + create_deterministic_function('django_time_trunc', 2, _sqlite_time_trunc) + create_deterministic_function('django_time_diff', 2, _sqlite_time_diff) + create_deterministic_function('django_timestamp_diff', 2, _sqlite_timestamp_diff) + create_deterministic_function('django_format_dtdelta', 3, _sqlite_format_dtdelta) + create_deterministic_function('regexp', 2, _sqlite_regexp) + create_deterministic_function('ACOS', 1, none_guard(math.acos)) + create_deterministic_function('ASIN', 1, none_guard(math.asin)) + create_deterministic_function('ATAN', 1, none_guard(math.atan)) + create_deterministic_function('ATAN2', 2, none_guard(math.atan2)) + create_deterministic_function('BITXOR', 2, none_guard(operator.xor)) + create_deterministic_function('CEILING', 1, none_guard(math.ceil)) + create_deterministic_function('COS', 1, none_guard(math.cos)) + create_deterministic_function('COT', 1, none_guard(lambda x: 1 / math.tan(x))) + create_deterministic_function('DEGREES', 1, none_guard(math.degrees)) + create_deterministic_function('EXP', 1, none_guard(math.exp)) + create_deterministic_function('FLOOR', 1, none_guard(math.floor)) + create_deterministic_function('LN', 1, none_guard(math.log)) + create_deterministic_function('LOG', 2, none_guard(lambda x, y: math.log(y, x))) + create_deterministic_function('LPAD', 3, _sqlite_lpad) + create_deterministic_function('MD5', 1, none_guard(lambda x: hashlib.md5(x.encode()).hexdigest())) + create_deterministic_function('MOD', 2, none_guard(math.fmod)) + create_deterministic_function('PI', 0, lambda: math.pi) + create_deterministic_function('POWER', 2, none_guard(operator.pow)) + create_deterministic_function('RADIANS', 1, none_guard(math.radians)) + create_deterministic_function('REPEAT', 2, none_guard(operator.mul)) + create_deterministic_function('REVERSE', 1, none_guard(lambda x: x[::-1])) + create_deterministic_function('RPAD', 3, _sqlite_rpad) + create_deterministic_function('SHA1', 1, none_guard(lambda x: hashlib.sha1(x.encode()).hexdigest())) + create_deterministic_function('SHA224', 1, none_guard(lambda x: hashlib.sha224(x.encode()).hexdigest())) + create_deterministic_function('SHA256', 1, none_guard(lambda x: hashlib.sha256(x.encode()).hexdigest())) + create_deterministic_function('SHA384', 1, none_guard(lambda x: hashlib.sha384(x.encode()).hexdigest())) + create_deterministic_function('SHA512', 1, none_guard(lambda x: hashlib.sha512(x.encode()).hexdigest())) + create_deterministic_function('SIGN', 1, none_guard(lambda x: (x > 0) - (x < 0))) + create_deterministic_function('SIN', 1, none_guard(math.sin)) + create_deterministic_function('SQRT', 1, none_guard(math.sqrt)) + create_deterministic_function('TAN', 1, none_guard(math.tan)) conn.create_aggregate('STDDEV_POP', 1, list_aggregate(statistics.pstdev)) conn.create_aggregate('STDDEV_SAMP', 1, list_aggregate(statistics.stdev)) conn.create_aggregate('VAR_POP', 1, list_aggregate(statistics.pvariance)) diff --git a/docs/releases/3.1.txt b/docs/releases/3.1.txt index 45cd858f0fe..fd1bd4f40c1 100644 --- a/docs/releases/3.1.txt +++ b/docs/releases/3.1.txt @@ -351,6 +351,10 @@ Models SQL on MySQL by using ``DELETE`` instead of ``TRUNCATE`` statements for tables which don't require resetting sequences. +* SQLite functions are now marked as :py:meth:`deterministic + ` on Python 3.8+. This allows using them + in check constraints and partial indexes. + Pagination ~~~~~~~~~~