Fixed #31030 -- Registered SQLite functions as deterministic on Python 3.8+.

This commit is contained in:
Sergey Fedoseev 2019-11-26 11:59:05 +05:00 committed by Mariusz Felisiak
parent 513948735b
commit 026719cf17
2 changed files with 55 additions and 43 deletions

View File

@ -24,6 +24,7 @@ from django.utils.asyncio import async_unsafe
from django.utils.dateparse import parse_datetime, parse_time from django.utils.dateparse import parse_datetime, parse_time
from django.utils.duration import duration_microseconds from django.utils.duration import duration_microseconds
from django.utils.regex_helper import _lazy_re_compile from django.utils.regex_helper import _lazy_re_compile
from django.utils.version import PY38
from .client import DatabaseClient # isort:skip from .client import DatabaseClient # isort:skip
from .creation import DatabaseCreation # isort:skip from .creation import DatabaseCreation # isort:skip
@ -202,49 +203,56 @@ class DatabaseWrapper(BaseDatabaseWrapper):
@async_unsafe @async_unsafe
def get_new_connection(self, conn_params): def get_new_connection(self, conn_params):
conn = Database.connect(**conn_params) conn = Database.connect(**conn_params)
conn.create_function("django_date_extract", 2, _sqlite_datetime_extract) if PY38:
conn.create_function("django_date_trunc", 2, _sqlite_date_trunc) create_deterministic_function = functools.partial(
conn.create_function('django_datetime_cast_date', 3, _sqlite_datetime_cast_date) conn.create_function,
conn.create_function('django_datetime_cast_time', 3, _sqlite_datetime_cast_time) deterministic=True,
conn.create_function('django_datetime_extract', 4, _sqlite_datetime_extract) )
conn.create_function('django_datetime_trunc', 4, _sqlite_datetime_trunc) else:
conn.create_function("django_time_extract", 2, _sqlite_time_extract) create_deterministic_function = conn.create_function
conn.create_function("django_time_trunc", 2, _sqlite_time_trunc) create_deterministic_function('django_date_extract', 2, _sqlite_datetime_extract)
conn.create_function("django_time_diff", 2, _sqlite_time_diff) create_deterministic_function('django_date_trunc', 2, _sqlite_date_trunc)
conn.create_function("django_timestamp_diff", 2, _sqlite_timestamp_diff) create_deterministic_function('django_datetime_cast_date', 3, _sqlite_datetime_cast_date)
conn.create_function("django_format_dtdelta", 3, _sqlite_format_dtdelta) create_deterministic_function('django_datetime_cast_time', 3, _sqlite_datetime_cast_time)
conn.create_function('regexp', 2, _sqlite_regexp) create_deterministic_function('django_datetime_extract', 4, _sqlite_datetime_extract)
conn.create_function('ACOS', 1, none_guard(math.acos)) create_deterministic_function('django_datetime_trunc', 4, _sqlite_datetime_trunc)
conn.create_function('ASIN', 1, none_guard(math.asin)) create_deterministic_function('django_time_extract', 2, _sqlite_time_extract)
conn.create_function('ATAN', 1, none_guard(math.atan)) create_deterministic_function('django_time_trunc', 2, _sqlite_time_trunc)
conn.create_function('ATAN2', 2, none_guard(math.atan2)) create_deterministic_function('django_time_diff', 2, _sqlite_time_diff)
conn.create_function('BITXOR', 2, none_guard(operator.xor)) create_deterministic_function('django_timestamp_diff', 2, _sqlite_timestamp_diff)
conn.create_function('CEILING', 1, none_guard(math.ceil)) create_deterministic_function('django_format_dtdelta', 3, _sqlite_format_dtdelta)
conn.create_function('COS', 1, none_guard(math.cos)) create_deterministic_function('regexp', 2, _sqlite_regexp)
conn.create_function('COT', 1, none_guard(lambda x: 1 / math.tan(x))) create_deterministic_function('ACOS', 1, none_guard(math.acos))
conn.create_function('DEGREES', 1, none_guard(math.degrees)) create_deterministic_function('ASIN', 1, none_guard(math.asin))
conn.create_function('EXP', 1, none_guard(math.exp)) create_deterministic_function('ATAN', 1, none_guard(math.atan))
conn.create_function('FLOOR', 1, none_guard(math.floor)) create_deterministic_function('ATAN2', 2, none_guard(math.atan2))
conn.create_function('LN', 1, none_guard(math.log)) create_deterministic_function('BITXOR', 2, none_guard(operator.xor))
conn.create_function('LOG', 2, none_guard(lambda x, y: math.log(y, x))) create_deterministic_function('CEILING', 1, none_guard(math.ceil))
conn.create_function('LPAD', 3, _sqlite_lpad) create_deterministic_function('COS', 1, none_guard(math.cos))
conn.create_function('MD5', 1, none_guard(lambda x: hashlib.md5(x.encode()).hexdigest())) create_deterministic_function('COT', 1, none_guard(lambda x: 1 / math.tan(x)))
conn.create_function('MOD', 2, none_guard(math.fmod)) create_deterministic_function('DEGREES', 1, none_guard(math.degrees))
conn.create_function('PI', 0, lambda: math.pi) create_deterministic_function('EXP', 1, none_guard(math.exp))
conn.create_function('POWER', 2, none_guard(operator.pow)) create_deterministic_function('FLOOR', 1, none_guard(math.floor))
conn.create_function('RADIANS', 1, none_guard(math.radians)) create_deterministic_function('LN', 1, none_guard(math.log))
conn.create_function('REPEAT', 2, none_guard(operator.mul)) create_deterministic_function('LOG', 2, none_guard(lambda x, y: math.log(y, x)))
conn.create_function('REVERSE', 1, none_guard(lambda x: x[::-1])) create_deterministic_function('LPAD', 3, _sqlite_lpad)
conn.create_function('RPAD', 3, _sqlite_rpad) create_deterministic_function('MD5', 1, none_guard(lambda x: hashlib.md5(x.encode()).hexdigest()))
conn.create_function('SHA1', 1, none_guard(lambda x: hashlib.sha1(x.encode()).hexdigest())) create_deterministic_function('MOD', 2, none_guard(math.fmod))
conn.create_function('SHA224', 1, none_guard(lambda x: hashlib.sha224(x.encode()).hexdigest())) create_deterministic_function('PI', 0, lambda: math.pi)
conn.create_function('SHA256', 1, none_guard(lambda x: hashlib.sha256(x.encode()).hexdigest())) create_deterministic_function('POWER', 2, none_guard(operator.pow))
conn.create_function('SHA384', 1, none_guard(lambda x: hashlib.sha384(x.encode()).hexdigest())) create_deterministic_function('RADIANS', 1, none_guard(math.radians))
conn.create_function('SHA512', 1, none_guard(lambda x: hashlib.sha512(x.encode()).hexdigest())) create_deterministic_function('REPEAT', 2, none_guard(operator.mul))
conn.create_function('SIGN', 1, none_guard(lambda x: (x > 0) - (x < 0))) create_deterministic_function('REVERSE', 1, none_guard(lambda x: x[::-1]))
conn.create_function('SIN', 1, none_guard(math.sin)) create_deterministic_function('RPAD', 3, _sqlite_rpad)
conn.create_function('SQRT', 1, none_guard(math.sqrt)) create_deterministic_function('SHA1', 1, none_guard(lambda x: hashlib.sha1(x.encode()).hexdigest()))
conn.create_function('TAN', 1, none_guard(math.tan)) 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_POP', 1, list_aggregate(statistics.pstdev))
conn.create_aggregate('STDDEV_SAMP', 1, list_aggregate(statistics.stdev)) conn.create_aggregate('STDDEV_SAMP', 1, list_aggregate(statistics.stdev))
conn.create_aggregate('VAR_POP', 1, list_aggregate(statistics.pvariance)) conn.create_aggregate('VAR_POP', 1, list_aggregate(statistics.pvariance))

View File

@ -351,6 +351,10 @@ Models
SQL on MySQL by using ``DELETE`` instead of ``TRUNCATE`` statements for SQL on MySQL by using ``DELETE`` instead of ``TRUNCATE`` statements for
tables which don't require resetting sequences. tables which don't require resetting sequences.
* SQLite functions are now marked as :py:meth:`deterministic
<sqlite3.Connection.create_function>` on Python 3.8+. This allows using them
in check constraints and partial indexes.
Pagination Pagination
~~~~~~~~~~ ~~~~~~~~~~