Skip to content
Browse files

Get complex counts for limit/offset working. Still have to make the c…

…ount limit be the sum of it and the offset too.
  • Loading branch information...
1 parent aac9d92 commit 3f6d16ecf785e957b8d283985ed0dae2f0079931 @metaskills metaskills committed Jan 13, 2011
Showing with 68 additions and 10 deletions.
  1. +67 −10 lib/arel/visitors/sqlserver.rb
  2. +1 −0 test/cases/bbbbasic_test_sqlserver.rb
View
77 lib/arel/visitors/sqlserver.rb
@@ -1,8 +1,28 @@
module Arel
+
+ module Nodes
+ class LockWithSQLServer < Arel::Nodes::Unary
+ end
+ end
+
+ class SelectManager < Arel::TreeManager
+
+ alias :lock_without_sqlserver :lock
+
+ def lock(locking=true)
+ if Arel::Visitors::SQLServer === @visitor
+ @ast.lock = Nodes::LockWithSQLServer.new(locking)
+ self
+ else
+ lock_without_sqlserver(locking)
+ end
+ end
+
+ end
+
module Visitors
class SQLServer < Arel::Visitors::ToSql
-
private
# SQLServer ToSql/Visitor (Overides)
@@ -25,6 +45,21 @@ def visit_Arel_Nodes_Limit(o)
"TOP (#{visit o.expr})"
end
+ def visit_Arel_Nodes_Lock o
+ "WITH(HOLDLOCK, ROWLOCK)"
+ end
+
+ def visit_Arel_Nodes_LockWithSQLServer o
+ case o.expr
+ when TrueClass
+ "WITH(HOLDLOCK, ROWLOCK)"
+ when String
+ o.expr
+ else
+ ""
+ end
+ end
+
# SQLServer ToSql/Visitor (Additions)
@@ -34,14 +69,14 @@ def visit_Arel_Nodes_SelectStatementWithOutOffset(o, windowed=false)
if windowed && !function_select_statement?(o)
projections = projections.map { |x| projection_without_expression(x) }
elsif eager_limiting_select?(o)
-
+ # TODO visit_Arel_Nodes_SelectStatementWithOutOffset - eager_limiting_select
+ raise 'visit_Arel_Nodes_SelectStatementWithOutOffset - eager_limiting_select'
end
[ ("SELECT" if !windowed),
(visit(o.limit) if o.limit && !windowed),
(projections.map{ |x| visit(x) }.join(', ')),
- ("FROM #{visit core.froms}" if core.froms),
+ visit(core.source),
(visit(o.lock) if o.lock),
- # (joins unless joins.blank?),
("WHERE #{core.wheres.map{ |x| visit(x) }.join ' AND ' }" unless core.wheres.empty?),
("GROUP BY #{core.groups.map { |x| visit x }.join ', ' }" unless core.groups.empty?),
(visit(core.having) if core.having),
@@ -58,12 +93,29 @@ def visit_Arel_Nodes_SelectStatementWithOffset(o)
"SELECT ROW_NUMBER() OVER (ORDER BY #{orders.map{ |x| visit(x) }.uniq.join(', ')}) AS [__rn],",
visit_Arel_Nodes_SelectStatementWithOutOffset(o,true),
") AS [__rnt]",
- (visit(o.offset) if o.offset),
+ visit(o.offset),
].compact.join ' '
end
def visit_Arel_Nodes_SelectStatementForComplexCount(o)
-
+ # joins = correlated_safe_joins
+ core = o.cores.first
+ orders = rowtable_orders(o)
+ [ "SELECT COUNT([count]) AS [count_id]",
+ "FROM (",
+ "SELECT",
+ (visit(o.limit) if o.limit),
+ "ROW_NUMBER() OVER (ORDER BY #{orders.map{ |x| visit(x) }.uniq.join(', ')}) AS [__rn],",
+ "1 AS [count]",
+ visit(core.source),
+ (visit(o.lock) if o.lock),
+ ("WHERE #{core.wheres.map{ |x| visit(x) }.join ' AND ' }" unless core.wheres.empty?),
+ ("GROUP BY #{core.groups.map { |x| visit x }.join ', ' }" unless core.groups.empty?),
+ (visit(core.having) if core.having),
+ ("ORDER BY #{o.orders.map{ |x| visit(x) }.uniq.join(', ')}" if !o.orders.empty?),
+ ") AS [__rnt]",
+ (visit(o.offset))
+ ].compact.join ' '
end
@@ -89,10 +141,14 @@ def eager_limiting_select?(o)
end
def complex_count_sql?(o)
- false
- # projections = relation.projections
- # projections.first.is_a?(Arel::Count) && projections.size == 1 &&
- # (relation.taken.present? || relation.wheres.present?) && relation.joins(self).blank?
+ core = o.cores.first
+ core.projections.size == 1 &&
+ Arel::Nodes::Count === core.projections.first &&
+ (o.limit || !core.wheres.empty?) &&
+ true # TODO: This was - relation.joins(self).blank?
+ # Consider visit(core.source)
+ # Consider core.from
+ # Consider core.froms
end
def rowtable_projections(o)
@@ -140,6 +196,7 @@ def projection_without_expression(projection)
end
end
+
end
Arel::Visitors::VISITORS['sqlserver'] = Arel::Visitors::SQLServer
View
1 test/cases/bbbbasic_test_sqlserver.rb
@@ -11,6 +11,7 @@ class BBBBasicTestSqlserver < ActiveRecord::TestCase
should 'pass limit' do
+ # Book.first
Book.count :limit => 3, :offset => 5, :lock => 'WITH (NOLOCK)'
end

0 comments on commit 3f6d16e

Please sign in to comment.
Something went wrong with that request. Please try again.