artpop-2000-2005-adapter 2.2.15

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. data/CHANGELOG +142 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +157 -0
  4. data/RUNNING_UNIT_TESTS +60 -0
  5. data/Rakefile +52 -0
  6. data/autotest/discover.rb +4 -0
  7. data/autotest/railssqlserver.rb +16 -0
  8. data/autotest/sqlserver.rb +54 -0
  9. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +1014 -0
  10. data/lib/core_ext/active_record.rb +133 -0
  11. data/lib/core_ext/dbi.rb +85 -0
  12. data/lib/rails-sqlserver-2000-2005-adapter.rb +1 -0
  13. data/test/cases/aaaa_create_tables_test_sqlserver.rb +19 -0
  14. data/test/cases/adapter_test_sqlserver.rb +627 -0
  15. data/test/cases/attribute_methods_test_sqlserver.rb +33 -0
  16. data/test/cases/basics_test_sqlserver.rb +21 -0
  17. data/test/cases/calculations_test_sqlserver.rb +20 -0
  18. data/test/cases/column_test_sqlserver.rb +264 -0
  19. data/test/cases/connection_test_sqlserver.rb +103 -0
  20. data/test/cases/eager_association_test_sqlserver.rb +42 -0
  21. data/test/cases/execute_procedure_test_sqlserver.rb +33 -0
  22. data/test/cases/inheritance_test_sqlserver.rb +28 -0
  23. data/test/cases/method_scoping_test_sqlserver.rb +28 -0
  24. data/test/cases/migration_test_sqlserver.rb +93 -0
  25. data/test/cases/offset_and_limit_test_sqlserver.rb +89 -0
  26. data/test/cases/pessimistic_locking_test_sqlserver.rb +125 -0
  27. data/test/cases/query_cache_test_sqlserver.rb +24 -0
  28. data/test/cases/schema_dumper_test_sqlserver.rb +61 -0
  29. data/test/cases/specific_schema_test_sqlserver.rb +26 -0
  30. data/test/cases/sqlserver_helper.rb +119 -0
  31. data/test/cases/table_name_test_sqlserver.rb +22 -0
  32. data/test/cases/transaction_test_sqlserver.rb +93 -0
  33. data/test/cases/unicode_test_sqlserver.rb +44 -0
  34. data/test/connections/native_sqlserver/connection.rb +23 -0
  35. data/test/connections/native_sqlserver_odbc/connection.rb +25 -0
  36. data/test/migrations/transaction_table/1_table_will_never_be_created.rb +11 -0
  37. data/test/schema/sqlserver_specific_schema.rb +88 -0
  38. metadata +96 -0
@@ -0,0 +1,33 @@
1
+ require 'cases/sqlserver_helper'
2
+ require 'models/topic'
3
+
4
+ class AttributeMethodsTestSqlserver < ActiveRecord::TestCase
5
+ end
6
+
7
+ class AttributeMethodsTest < ActiveRecord::TestCase
8
+
9
+ COERCED_TESTS = [
10
+ :test_typecast_attribute_from_select_to_false,
11
+ :test_typecast_attribute_from_select_to_true
12
+ ]
13
+
14
+ include SqlserverCoercedTest
15
+
16
+ fixtures :topics
17
+
18
+
19
+ def test_coerced_typecast_attribute_from_select_to_false
20
+ topic = Topic.create(:title => 'Budget')
21
+ topic = Topic.find(:first, :select => "topics.*, CASE WHEN 1=2 THEN 1 ELSE 0 END as is_test")
22
+ assert !topic.is_test?
23
+ end
24
+
25
+ def test_coerced_typecast_attribute_from_select_to_true
26
+ topic = Topic.create(:title => 'Budget')
27
+ topic = Topic.find(:first, :select => "topics.*, CASE WHEN 2=2 THEN 1 ELSE 0 END as is_test")
28
+ assert topic.is_test?
29
+ end
30
+
31
+
32
+ end
33
+
@@ -0,0 +1,21 @@
1
+ require 'cases/sqlserver_helper'
2
+ require 'models/developer'
3
+
4
+ class BasicsTestSqlserver < ActiveRecord::TestCase
5
+ end
6
+
7
+ class BasicsTest < ActiveRecord::TestCase
8
+
9
+ COERCED_TESTS = [:test_read_attributes_before_type_cast_on_datetime]
10
+
11
+ include SqlserverCoercedTest
12
+
13
+ fixtures :developers
14
+
15
+ def test_coerced_test_read_attributes_before_type_cast_on_datetime
16
+ developer = Developer.find(:first)
17
+ assert_equal developer.created_at.to_s(:db)+'.000' , developer.attributes_before_type_cast["created_at"]
18
+ end
19
+
20
+
21
+ end
@@ -0,0 +1,20 @@
1
+ require 'cases/sqlserver_helper'
2
+ require 'models/company'
3
+
4
+ class CalculationsTestSqlserver < ActiveRecord::TestCase
5
+ end
6
+
7
+ class CalculationsTest < ActiveRecord::TestCase
8
+
9
+ COERCED_TESTS = [:test_should_sum_expression]
10
+
11
+ include SqlserverCoercedTest
12
+
13
+ fixtures :accounts
14
+
15
+ def test_coerced_test_should_sum_expression
16
+ assert_equal 636, Account.sum("2 * credit_limit")
17
+ end
18
+
19
+
20
+ end
@@ -0,0 +1,264 @@
1
+ require 'cases/sqlserver_helper'
2
+ require 'models/binary'
3
+
4
+ class ColumnTestSqlserver < ActiveRecord::TestCase
5
+
6
+ def setup
7
+ @connection = ActiveRecord::Base.connection
8
+ @column_klass = ActiveRecord::ConnectionAdapters::SQLServerColumn
9
+ end
10
+
11
+ should 'return real_number as float' do
12
+ assert_equal :float, TableWithRealColumn.columns_hash["real_number"].type
13
+ end
14
+
15
+ should 'know its #table_name and #table_klass' do
16
+ Topic.columns.each do |column|
17
+ assert_equal 'topics', column.table_name, "This column #{column.inspect} did not know it's #table_name"
18
+ assert_equal Topic, column.table_klass, "This column #{column.inspect} did not know it's #table_klass"
19
+ end
20
+ end
21
+
22
+ should 'return correct null, limit, and default for Topic' do
23
+ tch = Topic.columns_hash
24
+ assert_equal false, tch['id'].null
25
+ assert_equal true, tch['title'].null
26
+ assert_equal 255, tch['author_name'].limit
27
+ assert_equal true, tch['approved'].default
28
+ assert_equal 0, tch['replies_count'].default
29
+ end
30
+
31
+ context 'For binary columns' do
32
+
33
+ setup do
34
+ @binary_string = "GIF89a\001\000\001\000\200\000\000\377\377\377\000\000\000!\371\004\000\000\000\000\000,\000\000\000\000\001\000\001\000\000\002\002D\001\000;"
35
+ @saved_bdata = Binary.create!(:data => @binary_string)
36
+ end
37
+
38
+ should 'read and write binary data equally' do
39
+ assert_equal @binary_string, Binary.find(@saved_bdata).data
40
+ end
41
+
42
+ should 'have correct attributes' do
43
+ column = Binary.columns_hash['data']
44
+ assert_equal :binary, column.type
45
+ assert_equal @connection.native_binary_database_type, column.sql_type
46
+ assert_equal nil, column.limit
47
+ end
48
+
49
+ should 'quote data for sqlserver with literal 0x prefix' do
50
+ # See the output of the stored procedure: 'exec sp_datatype_info'
51
+ sqlserver_encoded_bdata = "0x47494638396101000100800000ffffff00000021f90400000000002c00000000010001000002024401003b"
52
+ assert_equal sqlserver_encoded_bdata, @column_klass.string_to_binary(@binary_string)
53
+ end
54
+
55
+ end
56
+
57
+ context 'For string columns' do
58
+
59
+ setup do
60
+ @char = SqlServerString.columns_hash['char']
61
+ @char10 = SqlServerString.columns_hash['char_10']
62
+ @varcharmax = SqlServerString.columns_hash['varchar_max']
63
+ @varcharmax10 = SqlServerString.columns_hash['varchar_max_10']
64
+ end
65
+
66
+ should 'have correct simplified types' do
67
+ assert_equal :string, @char.type
68
+ assert_equal :string, @char10.type
69
+ if sqlserver_2005?
70
+ assert_equal :string, @varcharmax.type
71
+ assert_equal :string, @varcharmax10.type
72
+ end
73
+ end
74
+
75
+ should 'have correct #sql_type per schema definition' do
76
+ assert_equal 'char(1)', @char.sql_type, 'Specifing a char type with no limit is 1 by SQL Server standards.'
77
+ assert_equal 'char(10)', @char10.sql_type, @char10.inspect
78
+ if sqlserver_2005?
79
+ assert_equal 'varchar(max)', @varcharmax.sql_type, 'A -1 limit should be converted to max (max) type.'
80
+ assert_equal 'varchar(max)', @varcharmax10.sql_type, 'A -1 limit should be converted to max (max) type.'
81
+ end
82
+ end
83
+
84
+ should 'have correct #limit per schema definition' do
85
+ assert_equal 1, @char.limit
86
+ assert_equal 10, @char10.limit
87
+ if sqlserver_2005?
88
+ assert_equal nil, @varcharmax.limit, 'Limits on max types are moot and we should let rails know that.'
89
+ assert_equal nil, @varcharmax10.limit, 'Limits on max types are moot and we should let rails know that.'
90
+ end
91
+ end
92
+
93
+ end
94
+
95
+
96
+ context 'For all national/unicode columns' do
97
+
98
+ setup do
99
+ @nchar = SqlServerUnicode.columns_hash['nchar']
100
+ @nvarchar = SqlServerUnicode.columns_hash['nvarchar']
101
+ @ntext = SqlServerUnicode.columns_hash['ntext']
102
+ @ntext10 = SqlServerUnicode.columns_hash['ntext_10']
103
+ @nchar10 = SqlServerUnicode.columns_hash['nchar_10']
104
+ @nvarchar100 = SqlServerUnicode.columns_hash['nvarchar_100']
105
+ @nvarcharmax = SqlServerUnicode.columns_hash['nvarchar_max']
106
+ @nvarcharmax10 = SqlServerUnicode.columns_hash['nvarchar_max_10']
107
+ end
108
+
109
+ should 'all respond true to #is_utf8?' do
110
+ SqlServerUnicode.columns_hash.except('id').values.each do |column|
111
+ assert column.is_utf8?, "This column #{column.inspect} should have been a unicode column."
112
+ end
113
+ end
114
+
115
+ should 'have correct simplified types' do
116
+ assert_equal :string, @nchar.type
117
+ assert_equal :string, @nvarchar.type
118
+ assert_equal :text, @ntext.type
119
+ assert_equal :text, @ntext10.type
120
+ assert_equal :string, @nchar10.type
121
+ assert_equal :string, @nvarchar100.type
122
+ if sqlserver_2005?
123
+ assert_equal :string, @nvarcharmax.type
124
+ assert_equal :string, @nvarcharmax10.type
125
+ end
126
+ end
127
+
128
+ should 'have correct #sql_type per schema definition' do
129
+ assert_equal 'nchar(1)', @nchar.sql_type, 'Specifing a nchar type with no limit is 1 by SQL Server standards.'
130
+ assert_equal 'nvarchar(255)', @nvarchar.sql_type, 'Default nvarchar limit is 255.'
131
+ assert_equal 'ntext', @ntext.sql_type, 'Nice and clean ntext, limit means nothing here.'
132
+ assert_equal 'ntext', @ntext10.sql_type, 'Even a next with a limit of 10 specified will mean nothing.'
133
+ assert_equal 'nchar(10)', @nchar10.sql_type, 'An nchar with a limit of 10 needs to have it show up here.'
134
+ assert_equal 'nvarchar(100)', @nvarchar100.sql_type, 'An nvarchar with a specified limit of 100 needs to show it.'
135
+ if sqlserver_2005?
136
+ assert_equal 'nvarchar(max)', @nvarcharmax.sql_type, 'A -1 limit should be converted to max (max) type.'
137
+ assert_equal 'nvarchar(max)', @nvarcharmax10.sql_type, 'A -1 limit should be converted to max (max) type.'
138
+ end
139
+ end
140
+
141
+ should 'have correct #limit per schema definition' do
142
+ assert_equal 1, @nchar.limit
143
+ assert_equal 255, @nvarchar.limit
144
+ assert_equal nil, @ntext.limit, 'An ntext column limit is moot, it is a fixed variable length'
145
+ assert_equal 10, @nchar10.limit
146
+ assert_equal 100, @nvarchar100.limit
147
+ if sqlserver_2005?
148
+ assert_equal nil, @nvarcharmax.limit, 'Limits on max types are moot and we should let rails know that.'
149
+ assert_equal nil, @nvarcharmax10.limit, 'Limits on max types are moot and we should let rails know that.'
150
+ end
151
+ end
152
+
153
+ end
154
+
155
+ context 'For datetime columns' do
156
+
157
+ setup do
158
+ @date = SqlServerChronic.columns_hash['date']
159
+ @time = SqlServerChronic.columns_hash['time']
160
+ @datetime = SqlServerChronic.columns_hash['datetime']
161
+ @smalldatetime = SqlServerChronic.columns_hash['smalldatetime']
162
+ end
163
+
164
+ should 'have correct simplified type for uncast datetime' do
165
+ assert_equal :datetime, @datetime.type
166
+ end
167
+
168
+ should 'all be a datetime #sql_type' do
169
+ assert_equal 'datetime', @date.sql_type
170
+ assert_equal 'datetime', @time.sql_type
171
+ assert_equal 'datetime', @datetime.sql_type
172
+ end
173
+
174
+ should 'all be have nil #limit' do
175
+ assert_equal nil, @date.limit
176
+ assert_equal nil, @time.limit
177
+ assert_equal nil, @datetime.limit
178
+ end
179
+
180
+ context 'For smalldatetime types' do
181
+
182
+ should 'have created that type using rails migrations' do
183
+ assert_equal 'smalldatetime', @smalldatetime.sql_type
184
+ end
185
+
186
+ should 'be able to insert column without truncation warnings or the like' do
187
+ SqlServerChronic.create! :smalldatetime => Time.now
188
+ end
189
+
190
+ should 'be able to update column without truncation warnings or the like' do
191
+ ssc = SqlServerChronic.create! :smalldatetime => 2.days.ago
192
+ ssc.update_attributes! :smalldatetime => Time.now
193
+ end
194
+
195
+ end
196
+
197
+ context 'which have coerced types' do
198
+
199
+ setup do
200
+ christmas_08 = "2008-12-25".to_time
201
+ christmas_08_afternoon = "2008-12-25 12:00".to_time
202
+ @chronic_date = SqlServerChronic.create!(:date => christmas_08).reload
203
+ @chronic_time = SqlServerChronic.create!(:time => christmas_08_afternoon).reload
204
+ end
205
+
206
+ should 'have an inheritable attribute ' do
207
+ assert SqlServerChronic.coerced_sqlserver_date_columns.include?('date')
208
+ end
209
+
210
+ should 'have column and objects cast to date' do
211
+ assert_equal :date, @date.type, "This column: \n#{@date.inspect}"
212
+ assert_instance_of Date, @chronic_date.date
213
+ end
214
+
215
+ should 'have column objects cast to time' do
216
+ assert_equal :time, @time.type, "This column: \n#{@time.inspect}"
217
+ assert_instance_of Time, @chronic_time.time
218
+ end
219
+
220
+ end
221
+
222
+ end
223
+
224
+ context 'For decimal and numeric columns' do
225
+
226
+ setup do
227
+ @bank_balance = NumericData.columns_hash['bank_balance']
228
+ @big_bank_balance = NumericData.columns_hash['big_bank_balance']
229
+ @world_population = NumericData.columns_hash['world_population']
230
+ @my_house_population = NumericData.columns_hash['my_house_population']
231
+ end
232
+
233
+ should 'have correct simplified types' do
234
+ assert_equal :decimal, @bank_balance.type
235
+ assert_equal :decimal, @big_bank_balance.type
236
+ assert_equal :integer, @world_population.type, 'Since #extract_scale == 0'
237
+ assert_equal :integer, @my_house_population.type, 'Since #extract_scale == 0'
238
+ end
239
+
240
+ should 'have correct #sql_type' do
241
+ assert_equal 'decimal(10,2)', @bank_balance.sql_type
242
+ assert_equal 'decimal(15,2)', @big_bank_balance.sql_type
243
+ assert_equal 'decimal(10,0)', @world_population.sql_type
244
+ assert_equal 'decimal(2,0)', @my_house_population.sql_type
245
+ end
246
+
247
+ should 'have correct #limit' do
248
+ assert_equal nil, @bank_balance.limit
249
+ assert_equal nil, @big_bank_balance.limit
250
+ assert_equal nil, @world_population.limit
251
+ assert_equal nil, @my_house_population.limit
252
+ end
253
+
254
+ should 'return correct precisions and scales' do
255
+ assert_equal [10,2], [@bank_balance.precision, @bank_balance.scale]
256
+ assert_equal [15,2], [@big_bank_balance.precision, @big_bank_balance.scale]
257
+ assert_equal [10,0], [@world_population.precision, @world_population.scale]
258
+ assert_equal [2,0], [@my_house_population.precision, @my_house_population.scale]
259
+ end
260
+
261
+ end
262
+
263
+
264
+ end
@@ -0,0 +1,103 @@
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 'return finished DBI statment handle from #execute without block' do
16
+ handle = @connection.execute('SELECT * FROM [topics]')
17
+ assert_instance_of DBI::StatementHandle, handle
18
+ assert handle.finished?
19
+ end
20
+
21
+ should 'finish DBI statment handle from #execute with block' do
22
+ assert_all_statements_used_are_closed do
23
+ @connection.execute('SELECT * FROM [topics]') { }
24
+ end
25
+ end
26
+
27
+ should 'return an unfinished DBI statement handler from #raw_execute' do
28
+ handle = @connection.send(:raw_execute,'SELECT * FROM [topics]')
29
+ assert_instance_of DBI::StatementHandle, handle
30
+ assert !handle.finished?
31
+ end
32
+
33
+ should 'finish connection from #raw_select' do
34
+ assert_all_statements_used_are_closed do
35
+ @connection.send(:raw_select,'SELECT * FROM [topics]')
36
+ end
37
+ end
38
+
39
+ should 'affect rows' do
40
+ assert Topic.connection.instance_variable_get("@connection")["AutoCommit"]
41
+ topic_data = { 1 => { "content" => "1 updated" }, 2 => { "content" => "2 updated" } }
42
+ updated = Topic.update(topic_data.keys, topic_data.values)
43
+ assert_equal 2, updated.size
44
+ assert_equal "1 updated", Topic.find(1).content
45
+ assert_equal "2 updated", Topic.find(2).content
46
+ assert_equal 2, Topic.delete([1, 2])
47
+ end
48
+
49
+ should 'execute without block closes statement' do
50
+ assert_all_statements_used_are_closed do
51
+ @connection.execute("SELECT 1")
52
+ end
53
+ end
54
+
55
+ should 'execute with block closes statement' do
56
+ assert_all_statements_used_are_closed do
57
+ @connection.execute("SELECT 1") do |sth|
58
+ assert !sth.finished?, "Statement should still be alive within block"
59
+ end
60
+ end
61
+ end
62
+
63
+ should 'insert with identity closes statement' do
64
+ assert_all_statements_used_are_closed do
65
+ @connection.insert("INSERT INTO accounts ([id], [firm_id],[credit_limit]) values (999, 1, 50)")
66
+ end
67
+ end
68
+
69
+ should 'insert without identity closes statement' do
70
+ assert_all_statements_used_are_closed do
71
+ @connection.insert("INSERT INTO accounts ([firm_id],[credit_limit]) values (1, 50)")
72
+ end
73
+ end
74
+
75
+ should 'active closes statement' do
76
+ assert_all_statements_used_are_closed do
77
+ @connection.active?
78
+ end
79
+ end
80
+
81
+
82
+ private
83
+
84
+ def assert_all_statements_used_are_closed(&block)
85
+ existing_handles = []
86
+ ObjectSpace.each_object(DBI::StatementHandle) {|handle| existing_handles << handle}
87
+ GC.disable
88
+ yield
89
+ used_handles = []
90
+ ObjectSpace.each_object(DBI::StatementHandle) {|handle| used_handles << handle unless existing_handles.include? handle}
91
+ assert_block "No statements were used within given block" do
92
+ used_handles.size > 0
93
+ end
94
+ ObjectSpace.each_object(DBI::StatementHandle) do |handle|
95
+ assert_block "Statement should have been closed within given block" do
96
+ handle.finished?
97
+ end
98
+ end
99
+ ensure
100
+ GC.enable
101
+ end
102
+
103
+ end
@@ -0,0 +1,42 @@
1
+ require 'cases/sqlserver_helper'
2
+ require 'models/author'
3
+ require 'models/post'
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 unless active_record_2_point_2?
40
+
41
+
42
+ end