Skip to content

Commit 5e230e2

Browse files
committed
pagination support
1 parent 058e881 commit 5e230e2

File tree

3 files changed

+172
-3
lines changed

3 files changed

+172
-3
lines changed

django_iris/compiler.py

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
from django.core.exceptions import EmptyResultSet
2+
from django.db.models.expressions import Col
3+
from django.db.models.sql import compiler
4+
5+
class SQLCompiler(compiler.SQLCompiler):
6+
def as_sql(self, with_limits=True, with_col_aliases=False):
7+
with_limit_offset = with_limits and (
8+
self.query.high_mark is not None or self.query.low_mark
9+
)
10+
print('LIMIT - ' + str(self.query.low_mark) + ':' + str(self.query.high_mark))
11+
if self.query.select_for_update or not with_limit_offset:
12+
return super().as_sql(with_limits, with_col_aliases)
13+
try:
14+
extra_select, order_by, group_by = self.pre_sql_setup()
15+
16+
limit, offset = self.connection.ops._get_limit_offset_params(self.query.low_mark, self.query.high_mark)
17+
18+
distinct_fields, distinct_params = self.get_distinct()
19+
# This must come after 'select', 'ordering', and 'distinct'
20+
# (see docstring of get_from_clause() for details).
21+
from_, f_params = self.get_from_clause()
22+
try:
23+
where, w_params = (
24+
self.compile(self.where) if self.where is not None else ("", [])
25+
)
26+
except EmptyResultSet:
27+
if self.elide_empty:
28+
raise
29+
# Use a predicate that's always False.
30+
where, w_params = "0 = 1", []
31+
having, h_params = (
32+
self.compile(self.having) if self.having is not None else ("", [])
33+
)
34+
result = ["SELECT"]
35+
params = []
36+
37+
if not offset:
38+
result.append("TOP %d" % limit)
39+
40+
if self.query.distinct:
41+
distinct_result, distinct_params = self.connection.ops.distinct_sql(
42+
distinct_fields,
43+
distinct_params,
44+
)
45+
result += distinct_result
46+
params += distinct_params
47+
48+
out_cols = []
49+
col_idx = 1
50+
for _, (s_sql, s_params), alias in self.select + extra_select:
51+
if alias:
52+
s_sql = "%s AS %s" % (
53+
s_sql,
54+
self.connection.ops.quote_name(alias),
55+
)
56+
elif with_col_aliases:
57+
s_sql = "%s AS %s" % (
58+
s_sql,
59+
self.connection.ops.quote_name("col%d" % col_idx),
60+
)
61+
col_idx += 1
62+
params.extend(s_params)
63+
out_cols.append(s_sql)
64+
65+
order_by_result = ""
66+
if order_by:
67+
ordering = []
68+
for _, (o_sql, o_params, _) in order_by:
69+
ordering.append(o_sql)
70+
params.extend(o_params)
71+
order_by_result = "ORDER BY %s" % ", ".join(ordering)
72+
if offset:
73+
out_cols.append("ROW_NUMBER() OVER (%s) AS row_number" % order_by_result)
74+
75+
result += [", ".join(out_cols), "FROM", *from_]
76+
params.extend(f_params)
77+
78+
if where:
79+
result.append("WHERE %s" % where)
80+
params.extend(w_params)
81+
82+
grouping = []
83+
for g_sql, g_params in group_by:
84+
grouping.append(g_sql)
85+
params.extend(g_params)
86+
if grouping:
87+
if distinct_fields:
88+
raise NotImplementedError(
89+
"annotate() + distinct(fields) is not implemented."
90+
)
91+
order_by = order_by or self.connection.ops.force_no_ordering()
92+
result.append("GROUP BY %s" % ", ".join(grouping))
93+
if self._meta_ordering:
94+
order_by = None
95+
if having:
96+
result.append("HAVING %s" % having)
97+
params.extend(h_params)
98+
99+
if self.query.explain_info:
100+
result.insert(
101+
0,
102+
self.connection.ops.explain_query_prefix(
103+
self.query.explain_info.format,
104+
**self.query.explain_info.options,
105+
),
106+
)
107+
108+
if order_by_result and not offset:
109+
result.append(order_by_result)
110+
111+
query = " ".join(result)
112+
113+
if self.query.subquery and extra_select:
114+
# If the query is used as a subquery, the extra selects would
115+
# result in more columns than the left-hand side expression is
116+
# expecting. This can happen when a subquery uses a combination
117+
# of order_by() and distinct(), forcing the ordering expressions
118+
# to be selected as well. Wrap the query in another subquery
119+
# to exclude extraneous selects.
120+
sub_selects = []
121+
sub_params = []
122+
for index, (select, _, alias) in enumerate(self.select, start=1):
123+
if not alias and with_col_aliases:
124+
alias = "col%d" % index
125+
if alias:
126+
sub_selects.append(
127+
"%s.%s"
128+
% (
129+
self.connection.ops.quote_name("subquery"),
130+
self.connection.ops.quote_name(alias),
131+
)
132+
)
133+
else:
134+
select_clone = select.relabeled_clone(
135+
{select.alias: "subquery"}
136+
)
137+
subselect, subparams = select_clone.as_sql(
138+
self, self.connection
139+
)
140+
sub_selects.append(subselect)
141+
sub_params.extend(subparams)
142+
query = "SELECT %s FROM (%s) subquery" % (
143+
", ".join(sub_selects),
144+
query,
145+
), tuple(sub_params + params)
146+
147+
if offset:
148+
query = "SELECT * FROM (%s) WHERE row_number between %d AND %d ORDER BY row_number" % (
149+
query,
150+
limit,
151+
offset,
152+
)
153+
return query, tuple(params)
154+
except:
155+
return super().as_sql(with_limits, with_col_aliases)
156+
157+
158+
class SQLInsertCompiler(compiler.SQLInsertCompiler, SQLCompiler):
159+
pass
160+
161+
162+
class SQLDeleteCompiler(compiler.SQLDeleteCompiler, SQLCompiler):
163+
pass
164+
165+
166+
class SQLUpdateCompiler(compiler.SQLUpdateCompiler, SQLCompiler):
167+
pass
168+
169+
170+
class SQLAggregateCompiler(compiler.SQLAggregateCompiler, SQLCompiler):
171+
pass

django_iris/introspection.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,6 @@ def get_table_description(self, cursor, table_name):
8787
)
8888

8989
description = [
90-
# name type_code display_size internal_size precision scale null_ok default collation
91-
# auto_increment
9290
FieldInfo(
9391
name,
9492
'longvarchar'

django_iris/operations.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
class DatabaseOperations(BaseDatabaseOperations):
1212

13-
# compiler_module = "django_iris.compiler"
13+
compiler_module = "django_iris.compiler"
1414

1515
def quote_name(self, name):
1616
if name.startswith('"') and name.endswith('"'):

0 commit comments

Comments
 (0)