forked from jruby/activerecord-jdbc-adapter
-
Notifications
You must be signed in to change notification settings - Fork 1
/
limit_helpers.rb
98 lines (92 loc) · 3.69 KB
/
limit_helpers.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
module ::ArJdbc
module MsSQL
module LimitHelpers
module_function
def get_table_name(sql)
if sql =~ /^\s*insert\s+into\s+([^\(\s,]+)\s*|^\s*update\s+([^\(\s,]+)\s*/i
$1
elsif sql =~ /\bfrom\s+([^\(\s,]+)\s*/i
$1
else
nil
end
end
module SqlServer2000ReplaceLimitOffset
module_function
def replace_limit_offset!(sql, limit, offset, order)
if limit
offset ||= 0
start_row = offset + 1
end_row = offset + limit.to_i
find_select = /\b(SELECT(?:\s+DISTINCT)?)\b(.*)/im
whole, select, rest_of_query = find_select.match(sql).to_a
if (start_row == 1) && (end_row ==1)
new_sql = "#{select} TOP 1 #{rest_of_query}"
sql.replace(new_sql)
else
#UGLY
#KLUDGY?
#removing out stuff before the FROM...
rest = rest_of_query[/FROM/i=~ rest_of_query.. -1]
#need the table name for avoiding amiguity
table_name = LimitHelpers.get_table_name(sql)
primary_key = order[/(\w*id\w*)/i]
#I am not sure this will cover all bases. but all the tests pass
new_order = "ORDER BY #{order}, #{table_name}.#{primary_key}" if order.index("#{table_name}.#{primary_key}").nil?
new_order ||= order
if (rest_of_query.match(/WHERE/).nil?)
new_sql = "#{select} TOP #{limit} #{rest_of_query} WHERE #{table_name}.#{primary_key} NOT IN (#{select} TOP #{offset} #{table_name}.#{primary_key} #{rest} #{new_order}) #{order} "
else
new_sql = "#{select} TOP #{limit} #{rest_of_query} AND #{table_name}.#{primary_key} NOT IN (#{select} TOP #{offset} #{table_name}.#{primary_key} #{rest} #{new_order}) #{order} "
end
sql.replace(new_sql)
end
end
sql
end
end
module SqlServer2000AddLimitOffset
def add_limit_offset!(sql, options)
if options[:limit]
order = "ORDER BY #{options[:order] || determine_order_clause(sql)}"
sql.sub!(/ ORDER BY.*$/i, '')
SqlServerReplaceLimitOffset.replace_limit_offset!(sql, options[:limit], options[:offset], order)
end
end
end
module SqlServerReplaceLimitOffset
module_function
def replace_limit_offset!(sql, limit, offset, order)
if limit
offset ||= 0
start_row = offset + 1
end_row = offset + limit.to_i
find_select = /\b(SELECT(?:\s+DISTINCT)?)\b(.*)/im
whole, select, rest_of_query = find_select.match(sql).to_a
rest_of_query.strip!
if rest_of_query[0] == "1"
rest_of_query[0] = "*"
end
if rest_of_query[0] == "*"
from_table = LimitHelpers.get_table_name(rest_of_query)
rest_of_query = from_table + '.' + rest_of_query
end
new_sql = "#{select} t.* FROM (SELECT ROW_NUMBER() OVER(#{order}) AS _row_num, #{rest_of_query}"
new_sql << ") AS t WHERE t._row_num BETWEEN #{start_row.to_s} AND #{end_row.to_s}"
sql.replace(new_sql)
end
sql
end
end
module SqlServerAddLimitOffset
def add_limit_offset!(sql, options)
if options[:limit]
order = "ORDER BY #{options[:order] || determine_order_clause(sql)}"
sql.sub!(/ ORDER BY.*$/i, '')
SqlServerReplaceLimitOffset.replace_limit_offset!(sql, options[:limit], options[:offset], order)
end
end
end
end
end
end