Skip to content

Commit 5b4fb86

Browse files
committed
use bound methods to customize SQL functions
1 parent edca9ad commit 5b4fb86

File tree

1 file changed

+75
-30
lines changed

1 file changed

+75
-30
lines changed

sql_server/pyodbc/compiler.py

Lines changed: 75 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,63 @@
1+
from django.db.models.aggregates import Avg, Count, StdDev, Variance
12
from django.db.models.expressions import Ref, Value
3+
from django.db.models.functions import ConcatPair, Greatest, Least, Length, Substr
24
from django.db.models.sql import compiler
35
from django.db.transaction import TransactionManagementError
46
from django.db.utils import DatabaseError
57
from django.utils import six
68

79

10+
def _as_sql_agv(self, compiler, connection):
11+
return self.as_sql(compiler, connection, template='%(function)s(CONVERT(float, %(field)s))')
12+
13+
def _as_sql_concatpair(self, compiler, connection):
14+
if connection.sql_server_version < 2012:
15+
node = self.coalesce()
16+
node.arg_joiner = ' + '
17+
return node.as_sql(compiler, connection, template='%(expressions)s')
18+
else:
19+
return self.as_sql(compiler, connection)
20+
21+
def _as_sql_count(self, compiler, connection):
22+
return self.as_sql(compiler, connection, function='COUNT_BIG')
23+
24+
def _as_sql_greatest(self, compiler, connection):
25+
# SQL Server does not provide GREATEST function,
26+
# so we emulate it with a table value constructor
27+
# https://msdn.microsoft.com/en-us/library/dd776382.aspx
28+
self.arg_joiner = '), ('
29+
template='(SELECT MAX(value) FROM (VALUES (%(expressions)s)) AS _%(function)s(value))'
30+
return self.as_sql(compiler, connection, template=template)
31+
32+
def _as_sql_least(self, compiler, connection):
33+
# SQL Server does not provide LEAST function,
34+
# so we emulate it with a table value constructor
35+
# https://msdn.microsoft.com/en-us/library/dd776382.aspx
36+
self.arg_joiner = '), ('
37+
template='(SELECT MIN(value) FROM (VALUES (%(expressions)s)) AS _%(function)s(value))'
38+
return self.as_sql(compiler, connection, template=template)
39+
40+
def _as_sql_length(self, compiler, connection):
41+
return self.as_sql(compiler, connection, function='LEN')
42+
43+
def _as_sql_stddev(self, compiler, connection):
44+
function = 'STDEV'
45+
if self.function == 'STDDEV_POP':
46+
function = '%sP' % function
47+
return self.as_sql(compiler, connection, function=function)
48+
49+
def _as_sql_substr(self, compiler, connection):
50+
if len(self.get_source_expressions()) < 3:
51+
self.get_source_expressions().append(Value(2**31-1))
52+
return self.as_sql(compiler, connection)
53+
54+
def _as_sql_variance(self, compiler, connection):
55+
function = 'VAR'
56+
if self.function == 'VAR_POP':
57+
function = '%sP' % function
58+
return self.as_sql(compiler, connection, function=function)
59+
60+
861
class SQLCompiler(compiler.SQLCompiler):
962

1063
def as_sql(self, with_limits=True, with_col_aliases=False, subquery=False):
@@ -161,36 +214,28 @@ def compile(self, node, select_format=False):
161214
return super(SQLCompiler, self).compile(node, select_format)
162215

163216
def _as_microsoft(self, node):
164-
if hasattr(node, 'function'):
165-
if node.function == 'AVG':
166-
node.template = '%(function)s(CONVERT(float, %(field)s))'
167-
elif node.function == 'CONCAT':
168-
if self.connection.sql_server_version < 2012:
169-
node.arg_joiner = ' + '
170-
node.template = '%(expressions)s'
171-
node = node.coalesce()
172-
# SQL Server does not provide GREATEST/LEAST functions,
173-
# so we emulate them with table value constructors
174-
# https://msdn.microsoft.com/en-us/library/dd776382.aspx
175-
elif node.function == 'GREATEST':
176-
node.arg_joiner = '), ('
177-
node.template = '(SELECT MAX(value) FROM (VALUES (%(expressions)s)) AS _%(function)s(value))'
178-
elif node.function == 'LEAST':
179-
node.arg_joiner = '), ('
180-
node.template = '(SELECT MIN(value) FROM (VALUES (%(expressions)s)) AS _%(function)s(value))'
181-
elif node.function == 'LENGTH':
182-
node.function = 'LEN'
183-
elif node.function == 'STDDEV_SAMP':
184-
node.function = 'STDEV'
185-
elif node.function == 'STDDEV_POP':
186-
node.function = 'STDEVP'
187-
elif node.function == 'SUBSTRING':
188-
if len(node.get_source_expressions()) < 3:
189-
node.get_source_expressions().append(Value(2**31-1))
190-
elif node.function == 'VAR_SAMP':
191-
node.function = 'VAR'
192-
elif node.function == 'VAR_POP':
193-
node.function = 'VARP'
217+
as_microsoft = None
218+
if isinstance(node, Avg):
219+
as_microsoft = _as_sql_agv
220+
elif isinstance(node, ConcatPair):
221+
as_microsoft = _as_sql_concatpair
222+
elif isinstance(node, Count):
223+
as_microsoft = _as_sql_count
224+
elif isinstance(node, Greatest):
225+
as_microsoft = _as_sql_greatest
226+
elif isinstance(node, Least):
227+
as_microsoft = _as_sql_least
228+
elif isinstance(node, Length):
229+
as_microsoft = _as_sql_length
230+
elif isinstance(node, StdDev):
231+
as_microsoft = _as_sql_stddev
232+
elif isinstance(node, Substr):
233+
as_microsoft = _as_sql_substr
234+
elif isinstance(node, Variance):
235+
as_microsoft = _as_sql_variance
236+
if as_microsoft:
237+
node = node.copy()
238+
node.as_microsoft = six.create_bound_method(as_microsoft, node)
194239
return node
195240

196241

0 commit comments

Comments
 (0)