Skip to content

Commit 0349faa

Browse files
committed
Make add_limit_offset! only add locking hints (for tally) when the :lock option is present. Added tests to make sure tally SQL is augmented correctly and tests to make sure that add_lock! is doing what it needs for deep sub selects in paginated results.
1 parent 5fbe830 commit 0349faa

File tree

3 files changed

+25
-2
lines changed

3 files changed

+25
-2
lines changed

CHANGELOG

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11

22
MASTER
33

4+
* Make add_limit_offset! only add locking hints (for tally) when the :lock option is present. Added tests
5+
to make sure tally SQL is augmented correctly and tests to make sure that add_lock! is doing what it needs
6+
for deep sub selects in paginated results. [Ken Collins]
7+
48
* Add auto reconnect support utilizing a new #with_auto_reconnect block. By default each query run through
59
the adapter will automatically reconnect at standard intervals, logging attempts along the way, till success
610
or the original exception bubbles up. See docs for more details. Resolves ticket #18 [Ken Collins]

lib/active_record/connection_adapters/sqlserver_adapter.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,7 @@ def add_limit_offset!(sql, options)
437437
# The business of adding limit/offset
438438
if options[:limit] and options[:offset]
439439
tally_sql = "SELECT count(*) as TotalRows from (#{sql.sub(/\bSELECT(\s+DISTINCT)?\b/i, "SELECT#{$1} TOP 1000000000")}) tally"
440-
add_lock! tally_sql, :lock => 'WITH (NOLOCK)'
440+
add_lock! tally_sql, options
441441
total_rows = select_value(tally_sql).to_i
442442
if (options[:limit] + options[:offset]) >= total_rows
443443
options[:limit] = (total_rows - options[:offset] >= 0) ? (total_rows - options[:offset]) : 0

test/cases/offset_and_limit_test_sqlserver.rb

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,16 @@ def setup
6666

6767
should 'alter SQL to limit number of records returned offset by specified amount' do
6868
options = { :limit => 3, :offset => 5 }
69-
expected_sql = %&SELECT * FROM (SELECT TOP 3 * FROM (SELECT TOP 8 * FROM books) AS tmp1) AS tmp2&
69+
expected_sql = "SELECT * FROM (SELECT TOP 3 * FROM (SELECT TOP 8 * FROM books) AS tmp1) AS tmp2"
7070
assert_equal(expected_sql, @connection.add_limit_offset!(@select_sql, options))
7171
end
72+
73+
should 'add locks to deepest sub select in limit offset sql that has a limited tally' do
74+
options = { :limit => 3, :offset => 5, :lock => 'WITH (NOLOCK)' }
75+
expected_sql = "SELECT * FROM (SELECT TOP 3 * FROM (SELECT TOP 8 * FROM books WITH (NOLOCK)) AS tmp1) AS tmp2"
76+
@connection.add_limit_offset! @select_sql, options
77+
assert_equal expected_sql, @connection.add_lock!(@select_sql,options)
78+
end
7279

7380
# Not really sure what an offset sql injection might look like
7481
should 'not allow sql injection via offset' do
@@ -82,6 +89,18 @@ def setup
8289
assert_equal expected_sql, @connection.add_limit_offset!(@subquery_select_sql,options)
8390
end
8491

92+
should 'add lock hints to tally sql if :lock option is present' do
93+
assert_sql %r|SELECT TOP 1000000000 \* FROM \[people\] WITH \(NOLOCK\)| do
94+
Person.all :limit => 5, :offset => 1, :lock => 'WITH (NOLOCK)'
95+
end
96+
end
97+
98+
should 'not add lock hints to tally sql if there is no :lock option' do
99+
assert_sql %r|\(SELECT TOP 1000000000 \* FROM \[people\] \)| do
100+
Person.all :limit => 5, :offset => 1
101+
end
102+
end
103+
85104
end
86105

87106

0 commit comments

Comments
 (0)