Refs #13312 -- Simplified handling of nulls ordering on MySQL.
MySQL & MariaDB support the standard IS NULL and IS NOT NULL so the same workaround used for NULLS FIRST and NULLS LAST that is used for SQLite < 3.30.0 can be used. Thanks Simon Charette for the discussion.
This commit is contained in:
parent
e0e88ceaaa
commit
7286eaf681
|
@ -88,6 +88,9 @@ class BaseDatabaseFeatures:
|
||||||
# Does the backend order NULL values as largest or smallest?
|
# Does the backend order NULL values as largest or smallest?
|
||||||
nulls_order_largest = False
|
nulls_order_largest = False
|
||||||
|
|
||||||
|
# Does the backend support NULLS FIRST and NULLS LAST in ORDER BY?
|
||||||
|
supports_order_by_nulls_modifier = True
|
||||||
|
|
||||||
# The database's limit on the number of query parameters.
|
# The database's limit on the number of query parameters.
|
||||||
max_query_params = None
|
max_query_params = None
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
||||||
db_functions_convert_bytes_to_str = True
|
db_functions_convert_bytes_to_str = True
|
||||||
# Neither MySQL nor MariaDB support partial indexes.
|
# Neither MySQL nor MariaDB support partial indexes.
|
||||||
supports_partial_indexes = False
|
supports_partial_indexes = False
|
||||||
|
supports_order_by_nulls_modifier = False
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def _mysql_storage_engine(self):
|
def _mysql_storage_engine(self):
|
||||||
|
|
|
@ -44,3 +44,4 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
||||||
supports_over_clause = Database.sqlite_version_info >= (3, 25, 0)
|
supports_over_clause = Database.sqlite_version_info >= (3, 25, 0)
|
||||||
supports_frame_range_fixed_distance = Database.sqlite_version_info >= (3, 28, 0)
|
supports_frame_range_fixed_distance = Database.sqlite_version_info >= (3, 28, 0)
|
||||||
supports_aggregate_filter_clause = Database.sqlite_version_info >= (3, 30, 1)
|
supports_aggregate_filter_clause = Database.sqlite_version_info >= (3, 30, 1)
|
||||||
|
supports_order_by_nulls_modifier = Database.sqlite_version_info >= (3, 30, 0)
|
||||||
|
|
|
@ -1128,11 +1128,17 @@ class OrderBy(BaseExpression):
|
||||||
return [self.expression]
|
return [self.expression]
|
||||||
|
|
||||||
def as_sql(self, compiler, connection, template=None, **extra_context):
|
def as_sql(self, compiler, connection, template=None, **extra_context):
|
||||||
if not template:
|
template = template or self.template
|
||||||
|
if connection.features.supports_order_by_nulls_modifier:
|
||||||
if self.nulls_last:
|
if self.nulls_last:
|
||||||
template = '%s NULLS LAST' % self.template
|
template = '%s NULLS LAST' % template
|
||||||
elif self.nulls_first:
|
elif self.nulls_first:
|
||||||
template = '%s NULLS FIRST' % self.template
|
template = '%s NULLS FIRST' % template
|
||||||
|
else:
|
||||||
|
if self.nulls_last:
|
||||||
|
template = '%%(expression)s IS NULL, %s' % template
|
||||||
|
elif self.nulls_first:
|
||||||
|
template = '%%(expression)s IS NOT NULL, %s' % template
|
||||||
connection.ops.check_expression_support(self)
|
connection.ops.check_expression_support(self)
|
||||||
expression_sql, params = compiler.compile(self.expression)
|
expression_sql, params = compiler.compile(self.expression)
|
||||||
placeholders = {
|
placeholders = {
|
||||||
|
@ -1144,23 +1150,6 @@ class OrderBy(BaseExpression):
|
||||||
params *= template.count('%(expression)s')
|
params *= template.count('%(expression)s')
|
||||||
return (template % placeholders).rstrip(), params
|
return (template % placeholders).rstrip(), params
|
||||||
|
|
||||||
def as_sqlite(self, compiler, connection):
|
|
||||||
template = None
|
|
||||||
if connection.Database.sqlite_version_info < (3, 30, 0):
|
|
||||||
if self.nulls_last:
|
|
||||||
template = '%(expression)s IS NULL, %(expression)s %(ordering)s'
|
|
||||||
elif self.nulls_first:
|
|
||||||
template = '%(expression)s IS NOT NULL, %(expression)s %(ordering)s'
|
|
||||||
return self.as_sql(compiler, connection, template=template)
|
|
||||||
|
|
||||||
def as_mysql(self, compiler, connection):
|
|
||||||
template = None
|
|
||||||
if self.nulls_last:
|
|
||||||
template = 'ISNULL(%(expression)s), %(expression)s %(ordering)s '
|
|
||||||
elif self.nulls_first:
|
|
||||||
template = 'IF(ISNULL(%(expression)s),0,1), %(expression)s %(ordering)s '
|
|
||||||
return self.as_sql(compiler, connection, template=template)
|
|
||||||
|
|
||||||
def as_oracle(self, compiler, connection):
|
def as_oracle(self, compiler, connection):
|
||||||
# Oracle doesn't allow ORDER BY EXISTS() unless it's wrapped in
|
# Oracle doesn't allow ORDER BY EXISTS() unless it's wrapped in
|
||||||
# a CASE WHEN.
|
# a CASE WHEN.
|
||||||
|
|
Loading…
Reference in New Issue