Skip to content

Commit 3f6d16e

Browse files
committed
Get complex counts for limit/offset working. Still have to make the count limit be the sum of it and the offset too.
1 parent aac9d92 commit 3f6d16e

File tree

2 files changed

+68
-10
lines changed

2 files changed

+68
-10
lines changed

lib/arel/visitors/sqlserver.rb

Lines changed: 67 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,28 @@
11
module Arel
2+
3+
module Nodes
4+
class LockWithSQLServer < Arel::Nodes::Unary
5+
end
6+
end
7+
8+
class SelectManager < Arel::TreeManager
9+
10+
alias :lock_without_sqlserver :lock
11+
12+
def lock(locking=true)
13+
if Arel::Visitors::SQLServer === @visitor
14+
@ast.lock = Nodes::LockWithSQLServer.new(locking)
15+
self
16+
else
17+
lock_without_sqlserver(locking)
18+
end
19+
end
20+
21+
end
22+
223
module Visitors
324
class SQLServer < Arel::Visitors::ToSql
425

5-
626
private
727

828
# SQLServer ToSql/Visitor (Overides)
@@ -25,6 +45,21 @@ def visit_Arel_Nodes_Limit(o)
2545
"TOP (#{visit o.expr})"
2646
end
2747

48+
def visit_Arel_Nodes_Lock o
49+
"WITH(HOLDLOCK, ROWLOCK)"
50+
end
51+
52+
def visit_Arel_Nodes_LockWithSQLServer o
53+
case o.expr
54+
when TrueClass
55+
"WITH(HOLDLOCK, ROWLOCK)"
56+
when String
57+
o.expr
58+
else
59+
""
60+
end
61+
end
62+
2863

2964
# SQLServer ToSql/Visitor (Additions)
3065

@@ -34,14 +69,14 @@ def visit_Arel_Nodes_SelectStatementWithOutOffset(o, windowed=false)
3469
if windowed && !function_select_statement?(o)
3570
projections = projections.map { |x| projection_without_expression(x) }
3671
elsif eager_limiting_select?(o)
37-
72+
# TODO visit_Arel_Nodes_SelectStatementWithOutOffset - eager_limiting_select
73+
raise 'visit_Arel_Nodes_SelectStatementWithOutOffset - eager_limiting_select'
3874
end
3975
[ ("SELECT" if !windowed),
4076
(visit(o.limit) if o.limit && !windowed),
4177
(projections.map{ |x| visit(x) }.join(', ')),
42-
("FROM #{visit core.froms}" if core.froms),
78+
visit(core.source),
4379
(visit(o.lock) if o.lock),
44-
# (joins unless joins.blank?),
4580
("WHERE #{core.wheres.map{ |x| visit(x) }.join ' AND ' }" unless core.wheres.empty?),
4681
("GROUP BY #{core.groups.map { |x| visit x }.join ', ' }" unless core.groups.empty?),
4782
(visit(core.having) if core.having),
@@ -58,12 +93,29 @@ def visit_Arel_Nodes_SelectStatementWithOffset(o)
5893
"SELECT ROW_NUMBER() OVER (ORDER BY #{orders.map{ |x| visit(x) }.uniq.join(', ')}) AS [__rn],",
5994
visit_Arel_Nodes_SelectStatementWithOutOffset(o,true),
6095
") AS [__rnt]",
61-
(visit(o.offset) if o.offset),
96+
visit(o.offset),
6297
].compact.join ' '
6398
end
6499

65100
def visit_Arel_Nodes_SelectStatementForComplexCount(o)
66-
101+
# joins = correlated_safe_joins
102+
core = o.cores.first
103+
orders = rowtable_orders(o)
104+
[ "SELECT COUNT([count]) AS [count_id]",
105+
"FROM (",
106+
"SELECT",
107+
(visit(o.limit) if o.limit),
108+
"ROW_NUMBER() OVER (ORDER BY #{orders.map{ |x| visit(x) }.uniq.join(', ')}) AS [__rn],",
109+
"1 AS [count]",
110+
visit(core.source),
111+
(visit(o.lock) if o.lock),
112+
("WHERE #{core.wheres.map{ |x| visit(x) }.join ' AND ' }" unless core.wheres.empty?),
113+
("GROUP BY #{core.groups.map { |x| visit x }.join ', ' }" unless core.groups.empty?),
114+
(visit(core.having) if core.having),
115+
("ORDER BY #{o.orders.map{ |x| visit(x) }.uniq.join(', ')}" if !o.orders.empty?),
116+
") AS [__rnt]",
117+
(visit(o.offset))
118+
].compact.join ' '
67119
end
68120

69121

@@ -89,10 +141,14 @@ def eager_limiting_select?(o)
89141
end
90142

91143
def complex_count_sql?(o)
92-
false
93-
# projections = relation.projections
94-
# projections.first.is_a?(Arel::Count) && projections.size == 1 &&
95-
# (relation.taken.present? || relation.wheres.present?) && relation.joins(self).blank?
144+
core = o.cores.first
145+
core.projections.size == 1 &&
146+
Arel::Nodes::Count === core.projections.first &&
147+
(o.limit || !core.wheres.empty?) &&
148+
true # TODO: This was - relation.joins(self).blank?
149+
# Consider visit(core.source)
150+
# Consider core.from
151+
# Consider core.froms
96152
end
97153

98154
def rowtable_projections(o)
@@ -140,6 +196,7 @@ def projection_without_expression(projection)
140196

141197
end
142198
end
199+
143200
end
144201

145202
Arel::Visitors::VISITORS['sqlserver'] = Arel::Visitors::SQLServer

test/cases/bbbbasic_test_sqlserver.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ class BBBBasicTestSqlserver < ActiveRecord::TestCase
1111

1212

1313
should 'pass limit' do
14+
# Book.first
1415
Book.count :limit => 3, :offset => 5, :lock => 'WITH (NOLOCK)'
1516
end
1617

0 commit comments

Comments
 (0)