activerecord-sqlserver-adapter 2.3.24 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +5 -108
- data/MIT-LICENSE +1 -1
- data/README.rdoc +33 -61
- data/lib/active_record/connection_adapters/sqlserver/core_ext/active_record.rb +57 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/odbc.rb +57 -0
- data/lib/active_record/connection_adapters/sqlserver/database_limits.rb +49 -0
- data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +336 -0
- data/lib/active_record/connection_adapters/sqlserver/errors.rb +33 -0
- data/lib/active_record/connection_adapters/sqlserver/query_cache.rb +17 -0
- data/lib/active_record/connection_adapters/sqlserver/quoting.rb +61 -0
- data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +373 -0
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +131 -1121
- data/lib/arel/engines/sql/compilers/sqlserver_compiler.rb +267 -0
- metadata +26 -76
- data/RUNNING_UNIT_TESTS +0 -31
- data/Rakefile +0 -60
- data/lib/active_record/connection_adapters/sqlserver_adapter/core_ext/active_record.rb +0 -151
- data/lib/active_record/connection_adapters/sqlserver_adapter/core_ext/odbc.rb +0 -40
- data/test/cases/aaaa_create_tables_test_sqlserver.rb +0 -19
- data/test/cases/adapter_test_sqlserver.rb +0 -755
- data/test/cases/attribute_methods_test_sqlserver.rb +0 -33
- data/test/cases/basics_test_sqlserver.rb +0 -86
- data/test/cases/calculations_test_sqlserver.rb +0 -20
- data/test/cases/column_test_sqlserver.rb +0 -354
- data/test/cases/connection_test_sqlserver.rb +0 -148
- data/test/cases/eager_association_test_sqlserver.rb +0 -42
- data/test/cases/execute_procedure_test_sqlserver.rb +0 -35
- data/test/cases/inheritance_test_sqlserver.rb +0 -28
- data/test/cases/method_scoping_test_sqlserver.rb +0 -28
- data/test/cases/migration_test_sqlserver.rb +0 -108
- data/test/cases/named_scope_test_sqlserver.rb +0 -21
- data/test/cases/offset_and_limit_test_sqlserver.rb +0 -108
- data/test/cases/pessimistic_locking_test_sqlserver.rb +0 -125
- data/test/cases/query_cache_test_sqlserver.rb +0 -24
- data/test/cases/schema_dumper_test_sqlserver.rb +0 -72
- data/test/cases/specific_schema_test_sqlserver.rb +0 -154
- data/test/cases/sqlserver_helper.rb +0 -140
- data/test/cases/table_name_test_sqlserver.rb +0 -38
- data/test/cases/transaction_test_sqlserver.rb +0 -93
- data/test/cases/unicode_test_sqlserver.rb +0 -54
- data/test/cases/validations_test_sqlserver.rb +0 -18
- data/test/connections/native_sqlserver/connection.rb +0 -26
- data/test/connections/native_sqlserver_odbc/connection.rb +0 -28
- data/test/migrations/transaction_table/1_table_will_never_be_created.rb +0 -11
- data/test/schema/sqlserver_specific_schema.rb +0 -113
@@ -1,148 +0,0 @@
|
|
1
|
-
require 'cases/sqlserver_helper'
|
2
|
-
require 'models/reply'
|
3
|
-
|
4
|
-
class ConnectionTestSqlserver < ActiveRecord::TestCase
|
5
|
-
|
6
|
-
self.use_transactional_fixtures = false
|
7
|
-
|
8
|
-
fixtures :topics, :accounts
|
9
|
-
|
10
|
-
def setup
|
11
|
-
@connection = ActiveRecord::Base.connection
|
12
|
-
end
|
13
|
-
|
14
|
-
|
15
|
-
should 'affect rows' do
|
16
|
-
topic_data = { 1 => { "content" => "1 updated" }, 2 => { "content" => "2 updated" } }
|
17
|
-
updated = Topic.update(topic_data.keys, topic_data.values)
|
18
|
-
assert_equal 2, updated.size
|
19
|
-
assert_equal "1 updated", Topic.find(1).content
|
20
|
-
assert_equal "2 updated", Topic.find(2).content
|
21
|
-
assert_equal 2, Topic.delete([1, 2])
|
22
|
-
end
|
23
|
-
|
24
|
-
should 'allow usage of :database connection option to remove setting from dsn' do
|
25
|
-
assert_equal 'activerecord_unittest', @connection.current_database
|
26
|
-
begin
|
27
|
-
@connection.use_database('activerecord_unittest2')
|
28
|
-
assert_equal 'activerecord_unittest2', @connection.current_database
|
29
|
-
ensure
|
30
|
-
@connection.use_database
|
31
|
-
assert_equal 'activerecord_unittest', @connection.current_database, 'Would default back to connection options'
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
context 'ODBC connection management' do
|
36
|
-
|
37
|
-
should 'return finished ODBC statement handle from #execute without block' do
|
38
|
-
assert_all_odbc_statements_used_are_closed do
|
39
|
-
@connection.execute('SELECT * FROM [topics]')
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
should 'finish ODBC statement handle from #execute with block' do
|
44
|
-
assert_all_odbc_statements_used_are_closed do
|
45
|
-
@connection.execute('SELECT * FROM [topics]') { }
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
should 'finish connection from #raw_select' do
|
50
|
-
assert_all_odbc_statements_used_are_closed do
|
51
|
-
@connection.send(:raw_select,'SELECT * FROM [topics]')
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
should 'execute without block closes statement' do
|
56
|
-
assert_all_odbc_statements_used_are_closed do
|
57
|
-
@connection.execute("SELECT 1")
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
should 'execute with block closes statement' do
|
62
|
-
assert_all_odbc_statements_used_are_closed do
|
63
|
-
@connection.execute("SELECT 1") do |sth|
|
64
|
-
assert !sth.finished?, "Statement should still be alive within block"
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
should 'insert with identity closes statement' do
|
70
|
-
assert_all_odbc_statements_used_are_closed do
|
71
|
-
@connection.insert("INSERT INTO accounts ([id], [firm_id],[credit_limit]) values (999, 1, 50)")
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
should 'insert without identity closes statement' do
|
76
|
-
assert_all_odbc_statements_used_are_closed do
|
77
|
-
@connection.insert("INSERT INTO accounts ([firm_id],[credit_limit]) values (1, 50)")
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
should 'active closes statement' do
|
82
|
-
assert_all_odbc_statements_used_are_closed do
|
83
|
-
@connection.active?
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
end if connection_mode_odbc?
|
88
|
-
|
89
|
-
|
90
|
-
context 'Connection management' do
|
91
|
-
|
92
|
-
setup do
|
93
|
-
assert @connection.active?
|
94
|
-
end
|
95
|
-
|
96
|
-
should 'be able to disconnect and reconnect at will' do
|
97
|
-
@connection.disconnect!
|
98
|
-
assert !@connection.active?
|
99
|
-
@connection.reconnect!
|
100
|
-
assert @connection.active?
|
101
|
-
end
|
102
|
-
|
103
|
-
should 'auto reconnect when setting is on' do
|
104
|
-
with_auto_connect(true) do
|
105
|
-
@connection.disconnect!
|
106
|
-
assert_nothing_raised() { Topic.count }
|
107
|
-
assert @connection.active?
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
should 'not auto reconnect when setting is off' do
|
112
|
-
with_auto_connect(false) do
|
113
|
-
@connection.disconnect!
|
114
|
-
assert_raise(ActiveRecord::StatementInvalid) { Topic.count }
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
end
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
private
|
123
|
-
|
124
|
-
def assert_all_odbc_statements_used_are_closed(&block)
|
125
|
-
odbc = @connection.raw_connection.class.parent
|
126
|
-
existing_handles = []
|
127
|
-
ObjectSpace.each_object(odbc::Statement) { |h| existing_handles << h }
|
128
|
-
existing_handle_ids = existing_handles.map(&:object_id)
|
129
|
-
assert existing_handles.all?(&:finished?), "Somewhere before the block some statements were not closed"
|
130
|
-
GC.disable
|
131
|
-
yield
|
132
|
-
used_handles = []
|
133
|
-
ObjectSpace.each_object(odbc::Statement) { |h| used_handles << h unless existing_handle_ids.include?(h.object_id) }
|
134
|
-
assert used_handles.size > 0, "No statements were used within given block"
|
135
|
-
assert used_handles.all?(&:finished?), "Statement should have been closed within given block"
|
136
|
-
ensure
|
137
|
-
GC.enable
|
138
|
-
end
|
139
|
-
|
140
|
-
def with_auto_connect(boolean)
|
141
|
-
existing = ActiveRecord::ConnectionAdapters::SQLServerAdapter.auto_connect
|
142
|
-
ActiveRecord::ConnectionAdapters::SQLServerAdapter.auto_connect = boolean
|
143
|
-
yield
|
144
|
-
ensure
|
145
|
-
ActiveRecord::ConnectionAdapters::SQLServerAdapter.auto_connect = existing
|
146
|
-
end
|
147
|
-
|
148
|
-
end
|
@@ -1,42 +0,0 @@
|
|
1
|
-
require 'cases/sqlserver_helper'
|
2
|
-
require 'models/post'
|
3
|
-
require 'models/author'
|
4
|
-
require 'models/comment'
|
5
|
-
|
6
|
-
class EagerAssociationTestSqlserver < ActiveRecord::TestCase
|
7
|
-
end
|
8
|
-
|
9
|
-
class EagerAssociationTest < ActiveRecord::TestCase
|
10
|
-
|
11
|
-
COERCED_TESTS = [
|
12
|
-
:test_count_with_include,
|
13
|
-
:test_eager_with_has_many_and_limit_and_high_offset_and_multiple_array_conditions,
|
14
|
-
:test_eager_with_has_many_and_limit_and_high_offset_and_multiple_hash_conditions
|
15
|
-
]
|
16
|
-
|
17
|
-
include SqlserverCoercedTest
|
18
|
-
|
19
|
-
fixtures :authors, :posts, :comments
|
20
|
-
|
21
|
-
def test_coerced_test_count_with_include
|
22
|
-
assert_equal 3, authors(:david).posts_with_comments.count(:conditions => "len(comments.body) > 15")
|
23
|
-
end
|
24
|
-
|
25
|
-
def test_coerced_eager_with_has_many_and_limit_and_high_offset_and_multiple_array_conditions
|
26
|
-
assert_queries(2) do
|
27
|
-
posts = Post.find(:all, :include => [ :author, :comments ], :limit => 2, :offset => 10,
|
28
|
-
:conditions => [ "authors.name = ? and comments.body = ?", 'David', 'go crazy' ])
|
29
|
-
assert_equal 0, posts.size
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
def test_coerced_eager_with_has_many_and_limit_and_high_offset_and_multiple_hash_conditions
|
34
|
-
assert_queries(2) do
|
35
|
-
posts = Post.find(:all, :include => [ :author, :comments ], :limit => 2, :offset => 10,
|
36
|
-
:conditions => { 'authors.name' => 'David', 'comments.body' => 'go crazy' })
|
37
|
-
assert_equal 0, posts.size
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
|
42
|
-
end
|
@@ -1,35 +0,0 @@
|
|
1
|
-
require 'cases/sqlserver_helper'
|
2
|
-
|
3
|
-
class ExecuteProcedureTestSqlserver < ActiveRecord::TestCase
|
4
|
-
|
5
|
-
def setup
|
6
|
-
@klass = ActiveRecord::Base
|
7
|
-
end
|
8
|
-
|
9
|
-
should 'execute a simple procedure' do
|
10
|
-
tables = @klass.execute_procedure :sp_tables
|
11
|
-
assert_instance_of Array, tables
|
12
|
-
assert tables.first.respond_to?(:keys)
|
13
|
-
end
|
14
|
-
|
15
|
-
should 'take parameter arguments' do
|
16
|
-
tables = @klass.execute_procedure :sp_tables, 'sql_server_chronics'
|
17
|
-
table_info = tables.first
|
18
|
-
assert_equal 1, tables.size
|
19
|
-
assert_equal (ENV['ARUNIT_DB_NAME'] || 'activerecord_unittest'), table_info['TABLE_QUALIFIER'], "Table Info: #{table_info.inspect}"
|
20
|
-
assert_equal 'TABLE', table_info['TABLE_TYPE'], "Table Info: #{table_info.inspect}"
|
21
|
-
end
|
22
|
-
|
23
|
-
should 'allow multiple result sets to be returned' do
|
24
|
-
results1, results2 = @klass.execute_procedure('sp_helpconstraint','accounts')
|
25
|
-
assert_instance_of Array, results1
|
26
|
-
assert results1.first.respond_to?(:keys)
|
27
|
-
assert results1.first['Object Name']
|
28
|
-
assert_instance_of Array, results2
|
29
|
-
assert results2.first.respond_to?(:keys)
|
30
|
-
assert results2.first['constraint_name']
|
31
|
-
assert results2.first['constraint_type']
|
32
|
-
end
|
33
|
-
|
34
|
-
|
35
|
-
end
|
@@ -1,28 +0,0 @@
|
|
1
|
-
require 'cases/sqlserver_helper'
|
2
|
-
require 'models/company'
|
3
|
-
|
4
|
-
class InheritanceTestSqlserver < ActiveRecord::TestCase
|
5
|
-
end
|
6
|
-
|
7
|
-
class InheritanceTest < ActiveRecord::TestCase
|
8
|
-
|
9
|
-
COERCED_TESTS = [
|
10
|
-
:test_eager_load_belongs_to_primary_key_quoting,
|
11
|
-
:test_a_bad_type_column
|
12
|
-
]
|
13
|
-
|
14
|
-
include SqlserverCoercedTest
|
15
|
-
|
16
|
-
def test_coerced_test_eager_load_belongs_to_primary_key_quoting
|
17
|
-
assert_sql(/\(\[companies\].\[id\] = 1\)/) do
|
18
|
-
Account.find(1, :include => :firm)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def test_coerced_test_a_bad_type_column
|
23
|
-
Company.connection.insert "INSERT INTO [companies] ([id], #{QUOTED_TYPE}, [name]) VALUES(100, 'bad_class!', 'Not happening')"
|
24
|
-
assert_raises(ActiveRecord::SubclassNotFound) { Company.find(100) }
|
25
|
-
end
|
26
|
-
|
27
|
-
|
28
|
-
end
|
@@ -1,28 +0,0 @@
|
|
1
|
-
require 'cases/sqlserver_helper'
|
2
|
-
require 'models/developer'
|
3
|
-
|
4
|
-
class MethodScopingTestSqlServer < ActiveRecord::TestCase
|
5
|
-
end
|
6
|
-
|
7
|
-
class NestedScopingTest < ActiveRecord::TestCase
|
8
|
-
|
9
|
-
COERCED_TESTS = [:test_merged_scoped_find]
|
10
|
-
|
11
|
-
include SqlserverCoercedTest
|
12
|
-
|
13
|
-
fixtures :developers
|
14
|
-
|
15
|
-
def test_coerced_test_merged_scoped_find
|
16
|
-
poor_jamis = developers(:poor_jamis)
|
17
|
-
Developer.with_scope(:find => { :conditions => "salary < 100000" }) do
|
18
|
-
Developer.with_scope(:find => { :offset => 1, :order => 'id asc' }) do
|
19
|
-
assert_sql /ORDER BY id ASC/ do
|
20
|
-
assert_equal(poor_jamis, Developer.find(:first, :order => 'id asc'))
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
end
|
27
|
-
|
28
|
-
|
@@ -1,108 +0,0 @@
|
|
1
|
-
require 'cases/sqlserver_helper'
|
2
|
-
require 'models/person'
|
3
|
-
|
4
|
-
class MigrationTestSqlserver < ActiveRecord::TestCase
|
5
|
-
|
6
|
-
def setup
|
7
|
-
@connection = ActiveRecord::Base.connection
|
8
|
-
end
|
9
|
-
|
10
|
-
context 'For transactions' do
|
11
|
-
|
12
|
-
setup do
|
13
|
-
@trans_test_table1 = 'sqlserver_trans_table1'
|
14
|
-
@trans_test_table2 = 'sqlserver_trans_table2'
|
15
|
-
@trans_tables = [@trans_test_table1,@trans_test_table2]
|
16
|
-
end
|
17
|
-
|
18
|
-
teardown do
|
19
|
-
@trans_tables.each do |table_name|
|
20
|
-
ActiveRecord::Migration.drop_table(table_name) if @connection.tables.include?(table_name)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
should 'not create a tables if error in migrations' do
|
25
|
-
begin
|
26
|
-
ActiveRecord::Migrator.up(SQLSERVER_MIGRATIONS_ROOT+'/transaction_table')
|
27
|
-
rescue Exception => e
|
28
|
-
assert_match %r|this and all later migrations canceled|, e.message
|
29
|
-
end
|
30
|
-
assert_does_not_contain @trans_test_table1, @connection.tables
|
31
|
-
assert_does_not_contain @trans_test_table2, @connection.tables
|
32
|
-
end
|
33
|
-
|
34
|
-
end
|
35
|
-
|
36
|
-
context 'For changing column' do
|
37
|
-
|
38
|
-
should 'not raise exception when column contains default constraint' do
|
39
|
-
lock_version_column = Person.columns_hash['lock_version']
|
40
|
-
assert_equal :integer, lock_version_column.type
|
41
|
-
assert lock_version_column.default.present?
|
42
|
-
assert_nothing_raised { @connection.change_column 'people', 'lock_version', :string }
|
43
|
-
Person.reset_column_information
|
44
|
-
lock_version_column = Person.columns_hash['lock_version']
|
45
|
-
assert_equal :string, lock_version_column.type
|
46
|
-
assert lock_version_column.default.nil?
|
47
|
-
end
|
48
|
-
|
49
|
-
should 'not drop the default contraint if just renaming' do
|
50
|
-
find_default = lambda do
|
51
|
-
@connection.select_all("EXEC sp_helpconstraint 'defaults','nomsg'").select do |row|
|
52
|
-
row['constraint_type'] == "DEFAULT on column decimal_number"
|
53
|
-
end.last
|
54
|
-
end
|
55
|
-
default_before = find_default.call
|
56
|
-
@connection.change_column :defaults, :decimal_number, :decimal, :precision => 4
|
57
|
-
default_after = find_default.call
|
58
|
-
assert default_after
|
59
|
-
assert_equal default_before['constraint_keys'], default_after['constraint_keys']
|
60
|
-
end
|
61
|
-
|
62
|
-
end
|
63
|
-
|
64
|
-
end
|
65
|
-
|
66
|
-
|
67
|
-
class MigrationTest < ActiveRecord::TestCase
|
68
|
-
|
69
|
-
COERCED_TESTS = [:test_add_column_not_null_without_default]
|
70
|
-
|
71
|
-
include SqlserverCoercedTest
|
72
|
-
|
73
|
-
def test_coerced_test_add_column_not_null_without_default
|
74
|
-
Person.connection.create_table :testings do |t|
|
75
|
-
t.column :foo, :string
|
76
|
-
t.column :bar, :string, :null => false
|
77
|
-
end
|
78
|
-
assert_raises(ActiveRecord::StatementInvalid) do
|
79
|
-
Person.connection.execute "INSERT INTO [testings] ([foo], [bar]) VALUES ('hello', NULL)"
|
80
|
-
end
|
81
|
-
ensure
|
82
|
-
Person.connection.drop_table :testings rescue nil
|
83
|
-
end
|
84
|
-
|
85
|
-
end
|
86
|
-
|
87
|
-
|
88
|
-
class ChangeTableMigrationsTest < ActiveRecord::TestCase
|
89
|
-
|
90
|
-
COERCED_TESTS = [:test_string_creates_string_column]
|
91
|
-
|
92
|
-
include SqlserverCoercedTest
|
93
|
-
|
94
|
-
def test_coerced_string_creates_string_column
|
95
|
-
with_change_table do |t|
|
96
|
-
@connection.expects(:add_column).with(:delete_me, :foo, coerced_string_column, {})
|
97
|
-
@connection.expects(:add_column).with(:delete_me, :bar, coerced_string_column, {})
|
98
|
-
t.string :foo, :bar
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
def coerced_string_column
|
103
|
-
"#{Person.connection.native_string_database_type}(255)"
|
104
|
-
end
|
105
|
-
|
106
|
-
end
|
107
|
-
|
108
|
-
|
@@ -1,21 +0,0 @@
|
|
1
|
-
require 'cases/sqlserver_helper'
|
2
|
-
|
3
|
-
class NamedScopeTestSqlserver < ActiveRecord::TestCase
|
4
|
-
end
|
5
|
-
|
6
|
-
class NamedScopeTest < ActiveRecord::TestCase
|
7
|
-
|
8
|
-
COERCED_TESTS = [:test_named_scopes_honor_current_scopes_from_when_defined]
|
9
|
-
|
10
|
-
include SqlserverCoercedTest
|
11
|
-
|
12
|
-
# See: http://github.com/rails/rails/commit/0dd2f96f5c90f8abacb0fe0757ef7e5db4a4d501#comment_37025
|
13
|
-
# The orig test is a little brittle and fails on other adapters that do not explicitly fall back to a secondary
|
14
|
-
# sort of id ASC. Since there are duplicate records with comments_count equal to one another. I have found that
|
15
|
-
# named_scope :ranked_by_comments, :order => "comments_count DESC, id ASC" fixes the ambiguity.
|
16
|
-
def test_coerced_test_named_scopes_honor_current_scopes_from_when_defined
|
17
|
-
assert true
|
18
|
-
end
|
19
|
-
|
20
|
-
|
21
|
-
end
|
@@ -1,108 +0,0 @@
|
|
1
|
-
require 'cases/sqlserver_helper'
|
2
|
-
require 'models/book'
|
3
|
-
|
4
|
-
class OffsetAndLimitTestSqlserver < ActiveRecord::TestCase
|
5
|
-
|
6
|
-
class Account < ActiveRecord::Base; end
|
7
|
-
|
8
|
-
def setup
|
9
|
-
@connection = ActiveRecord::Base.connection
|
10
|
-
end
|
11
|
-
|
12
|
-
context 'When selecting with limit' do
|
13
|
-
|
14
|
-
setup do
|
15
|
-
@select_sql = 'SELECT * FROM schema'
|
16
|
-
end
|
17
|
-
|
18
|
-
should 'alter SQL to limit number of records returned' do
|
19
|
-
options = { :limit => 10 }
|
20
|
-
assert_equal('SELECT TOP 10 * FROM schema', @connection.add_limit_offset!(@select_sql, options))
|
21
|
-
end
|
22
|
-
|
23
|
-
should 'only allow integers for limit' do
|
24
|
-
options = { :limit => 'ten' }
|
25
|
-
assert_raise(ArgumentError) {@connection.add_limit_offset!(@select_sql, options) }
|
26
|
-
end
|
27
|
-
|
28
|
-
should 'convert strings which look like integers to integers' do
|
29
|
-
options = { :limit => '42' }
|
30
|
-
assert_nothing_raised(ArgumentError) {@connection.add_limit_offset!(@select_sql, options)}
|
31
|
-
end
|
32
|
-
|
33
|
-
should 'not allow sql injection via limit' do
|
34
|
-
options = { :limit => '1 * FROM schema; DELETE * FROM table; SELECT TOP 10 *'}
|
35
|
-
assert_raise(ArgumentError) { @connection.add_limit_offset!(@select_sql, options) }
|
36
|
-
end
|
37
|
-
|
38
|
-
end
|
39
|
-
|
40
|
-
context 'When selecting with limit and offset' do
|
41
|
-
|
42
|
-
setup do
|
43
|
-
@select_sql = 'SELECT * FROM books'
|
44
|
-
@subquery_select_sql = 'SELECT *, (SELECT TOP 1 id FROM books) AS book_id FROM books'
|
45
|
-
@books = (1..10).map {|i| Book.create!}
|
46
|
-
end
|
47
|
-
|
48
|
-
teardown do
|
49
|
-
@books.each {|b| b.destroy}
|
50
|
-
end
|
51
|
-
|
52
|
-
should 'have limit if offset is passed' do
|
53
|
-
options = { :offset => 1 }
|
54
|
-
assert_raise(ArgumentError) { @connection.add_limit_offset!(@select_sql, options) }
|
55
|
-
end
|
56
|
-
|
57
|
-
should 'only allow integers for offset' do
|
58
|
-
options = { :limit => 10, :offset => 'five' }
|
59
|
-
assert_raise(ArgumentError) { @connection.add_limit_offset!(@select_sql, options)}
|
60
|
-
end
|
61
|
-
|
62
|
-
should 'convert strings which look like integers to integers' do
|
63
|
-
options = { :limit => 10, :offset => '5' }
|
64
|
-
assert_nothing_raised(ArgumentError) {@connection.add_limit_offset!(@select_sql, options)}
|
65
|
-
end
|
66
|
-
|
67
|
-
should 'alter SQL to limit number of records returned offset by specified amount' do
|
68
|
-
options = { :limit => 3, :offset => 5 }
|
69
|
-
expected_sql = "SELECT * FROM (SELECT TOP 3 * FROM (SELECT TOP 8 * FROM books) AS tmp1) AS tmp2"
|
70
|
-
assert_equal(expected_sql, @connection.add_limit_offset!(@select_sql, options))
|
71
|
-
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
|
79
|
-
|
80
|
-
# Not really sure what an offset sql injection might look like
|
81
|
-
should 'not allow sql injection via offset' do
|
82
|
-
options = { :limit => 10, :offset => '1 * FROM schema; DELETE * FROM table; SELECT TOP 10 *'}
|
83
|
-
assert_raise(ArgumentError) { @connection.add_limit_offset!(@select_sql, options) }
|
84
|
-
end
|
85
|
-
|
86
|
-
should 'not create invalid SQL with subquery SELECTs with TOP' do
|
87
|
-
options = { :limit => 5, :offset => 1 }
|
88
|
-
expected_sql = "SELECT * FROM (SELECT TOP 5 * FROM (SELECT TOP 6 *, (SELECT TOP 1 id FROM books) AS book_id FROM books) AS tmp1) AS tmp2"
|
89
|
-
assert_equal expected_sql, @connection.add_limit_offset!(@subquery_select_sql,options)
|
90
|
-
end
|
91
|
-
|
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
|
-
|
104
|
-
end
|
105
|
-
|
106
|
-
|
107
|
-
end
|
108
|
-
|