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,125 +0,0 @@
|
|
1
|
-
require 'cases/sqlserver_helper'
|
2
|
-
require 'models/person'
|
3
|
-
require 'models/reader'
|
4
|
-
|
5
|
-
class PessimisticLockingTestSqlserver < ActiveRecord::TestCase
|
6
|
-
|
7
|
-
self.use_transactional_fixtures = false
|
8
|
-
fixtures :people, :readers
|
9
|
-
|
10
|
-
def setup
|
11
|
-
Person.columns; Reader.columns # Avoid introspection queries during tests.
|
12
|
-
end
|
13
|
-
|
14
|
-
context 'For simple finds with default lock option' do
|
15
|
-
|
16
|
-
should 'lock with simple find' do
|
17
|
-
assert_nothing_raised do
|
18
|
-
Person.transaction do
|
19
|
-
Person.find 1, :lock => true
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
should 'lock with scoped find' do
|
25
|
-
assert_nothing_raised do
|
26
|
-
Person.transaction do
|
27
|
-
Person.with_scope(:find => { :lock => true }) do
|
28
|
-
Person.find 1
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
should 'lock with eager find' do
|
35
|
-
assert_nothing_raised do
|
36
|
-
Person.transaction do
|
37
|
-
Person.find 1, :include => :readers, :lock => true
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
should 'reload with lock when #lock! called' do
|
43
|
-
assert_nothing_raised do
|
44
|
-
Person.transaction do
|
45
|
-
person = Person.find 1
|
46
|
-
old, person.first_name = person.first_name, 'fooman'
|
47
|
-
person.lock!
|
48
|
-
assert_equal old, person.first_name
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
should 'simply add lock to find all' do
|
54
|
-
assert_sql %r|SELECT \* FROM \[people\] WITH \(NOLOCK\)| do
|
55
|
-
Person.all(:lock => 'WITH (NOLOCK)')
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
end
|
60
|
-
|
61
|
-
context 'For paginated finds' do
|
62
|
-
|
63
|
-
setup do
|
64
|
-
20.times { |n| Person.create!(:first_name => "Thing_#{n}") }
|
65
|
-
end
|
66
|
-
|
67
|
-
should 'cope with un-locked paginated results' do
|
68
|
-
tally_not_locked = %r|SELECT count\(\*\) as TotalRows from \(SELECT TOP 1000000000 \* FROM \[people\]\s+WITH \(NOLOCK\) \) tally|
|
69
|
-
inner_tmp_not_locked = %r|SELECT TOP 15 \* FROM \[people\] WITH \(NOLOCK\)|
|
70
|
-
# Currently association limiting is not locked like the parent.
|
71
|
-
association_limiting_not_locked = %r|SELECT \[readers\]\.\* FROM \[readers\] WITH \(NOLOCK\) WHERE \(\[readers\]\.person_id IN \(1,2,3,4,5\)\)|
|
72
|
-
assert_sql(tally_not_locked,inner_tmp_not_locked) do
|
73
|
-
Person.all(:include => :readers, :lock => 'WITH (NOLOCK)', :limit => 5, :offset => 10)
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
end
|
78
|
-
|
79
|
-
|
80
|
-
context 'For dueling concurrent connections' do
|
81
|
-
|
82
|
-
use_concurrent_connections
|
83
|
-
|
84
|
-
should 'no locks does not wait' do
|
85
|
-
first, second = duel { Person.find 1 }
|
86
|
-
assert first.end > second.end
|
87
|
-
end
|
88
|
-
|
89
|
-
should 'that second lock waits' do
|
90
|
-
assert [0.2, 1, 5].any? { |zzz|
|
91
|
-
first, second = duel(zzz) { Person.find 1, :lock => true }
|
92
|
-
second.end > first.end
|
93
|
-
}
|
94
|
-
end
|
95
|
-
|
96
|
-
end
|
97
|
-
|
98
|
-
|
99
|
-
protected
|
100
|
-
|
101
|
-
def duel(zzz = 5)
|
102
|
-
t0, t1, t2, t3 = nil, nil, nil, nil
|
103
|
-
a = Thread.new do
|
104
|
-
t0 = Time.now
|
105
|
-
Person.transaction do
|
106
|
-
yield
|
107
|
-
sleep zzz # block thread 2 for zzz seconds
|
108
|
-
end
|
109
|
-
t1 = Time.now
|
110
|
-
end
|
111
|
-
b = Thread.new do
|
112
|
-
sleep zzz / 2.0 # ensure thread 1 tx starts first
|
113
|
-
t2 = Time.now
|
114
|
-
Person.transaction { yield }
|
115
|
-
t3 = Time.now
|
116
|
-
end
|
117
|
-
a.join
|
118
|
-
b.join
|
119
|
-
assert t1 > t0 + zzz
|
120
|
-
assert t2 > t0
|
121
|
-
assert t3 > t2
|
122
|
-
[t0.to_f..t1.to_f, t2.to_f..t3.to_f]
|
123
|
-
end
|
124
|
-
|
125
|
-
end
|
@@ -1,24 +0,0 @@
|
|
1
|
-
require 'cases/sqlserver_helper'
|
2
|
-
require 'models/task'
|
3
|
-
|
4
|
-
class QueryCacheTestSqlserver < ActiveRecord::TestCase
|
5
|
-
end
|
6
|
-
|
7
|
-
class QueryCacheTest < ActiveRecord::TestCase
|
8
|
-
|
9
|
-
COERCED_TESTS = [:test_cache_does_not_wrap_string_results_in_arrays]
|
10
|
-
|
11
|
-
include SqlserverCoercedTest
|
12
|
-
|
13
|
-
fixtures :tasks
|
14
|
-
|
15
|
-
|
16
|
-
def test_coerced_test_cache_does_not_wrap_string_results_in_arrays
|
17
|
-
Task.cache do
|
18
|
-
assert_instance_of Fixnum, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks")
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
end
|
23
|
-
|
24
|
-
|
@@ -1,72 +0,0 @@
|
|
1
|
-
require 'cases/sqlserver_helper'
|
2
|
-
|
3
|
-
class SchemaDumperTestSqlserver < ActiveRecord::TestCase
|
4
|
-
|
5
|
-
setup :find_all_tables
|
6
|
-
|
7
|
-
context 'For primary keys' do
|
8
|
-
|
9
|
-
should 'honor nonstandards' do
|
10
|
-
table_dump('movies') do |output|
|
11
|
-
match = output.match(%r{create_table "movies"(.*)do})
|
12
|
-
assert_not_nil(match, "nonstandardpk table not found")
|
13
|
-
assert_match %r(:primary_key => "movieid"), match[1], "non-standard primary key not preserved"
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
end
|
18
|
-
|
19
|
-
context 'For integers' do
|
20
|
-
|
21
|
-
should 'include limit constraint that match logic for smallint and bigint in #extract_limit' do
|
22
|
-
table_dump('integer_limits') do |output|
|
23
|
-
assert_match %r{c_int_1.*:limit => 2}, output
|
24
|
-
assert_match %r{c_int_2.*:limit => 2}, output
|
25
|
-
assert_match %r{c_int_3.*}, output
|
26
|
-
assert_match %r{c_int_4.*}, output
|
27
|
-
assert_no_match %r{c_int_3.*:limit}, output
|
28
|
-
assert_no_match %r{c_int_4.*:limit}, output
|
29
|
-
assert_match %r{c_int_5.*:limit => 8}, output
|
30
|
-
assert_match %r{c_int_6.*:limit => 8}, output
|
31
|
-
assert_match %r{c_int_7.*:limit => 8}, output
|
32
|
-
assert_match %r{c_int_8.*:limit => 8}, output
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
end
|
37
|
-
|
38
|
-
context 'For strings' do
|
39
|
-
|
40
|
-
should 'have varchar(max) dumped as text' do
|
41
|
-
table_dump('sql_server_strings') do |output|
|
42
|
-
assert_match %r{t.text.*varchar_max}, output
|
43
|
-
end
|
44
|
-
end if sqlserver_2005? || sqlserver_2008?
|
45
|
-
|
46
|
-
end
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
private
|
52
|
-
|
53
|
-
def find_all_tables
|
54
|
-
@all_tables ||= ActiveRecord::Base.connection.tables
|
55
|
-
end
|
56
|
-
|
57
|
-
def standard_dump(ignore_tables = [])
|
58
|
-
stream = StringIO.new
|
59
|
-
ActiveRecord::SchemaDumper.ignore_tables = [*ignore_tables]
|
60
|
-
ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
|
61
|
-
stream.string
|
62
|
-
end
|
63
|
-
|
64
|
-
def table_dump(*table_names)
|
65
|
-
stream = StringIO.new
|
66
|
-
ActiveRecord::SchemaDumper.ignore_tables = @all_tables-table_names
|
67
|
-
ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
|
68
|
-
yield stream.string
|
69
|
-
stream.string
|
70
|
-
end
|
71
|
-
|
72
|
-
end
|
@@ -1,154 +0,0 @@
|
|
1
|
-
require 'cases/sqlserver_helper'
|
2
|
-
|
3
|
-
class StringDefault < ActiveRecord::Base; end;
|
4
|
-
class SqlServerEdgeSchema < ActiveRecord::Base
|
5
|
-
attr_accessor :new_id_setting
|
6
|
-
before_create :set_new_id
|
7
|
-
protected
|
8
|
-
def set_new_id
|
9
|
-
self[:guid_newid] ||= connection.newid_function if new_id_setting
|
10
|
-
true
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
class SpecificSchemaTestSqlserver < ActiveRecord::TestCase
|
15
|
-
|
16
|
-
should 'quote table names properly even when they are views' do
|
17
|
-
obj = SqlServerQuotedTable.create!
|
18
|
-
assert_nothing_raised { SqlServerQuotedTable.first }
|
19
|
-
obj = SqlServerQuotedView1.create!
|
20
|
-
assert_nothing_raised { SqlServerQuotedView1.first }
|
21
|
-
obj = SqlServerQuotedView2.create!
|
22
|
-
assert_nothing_raised { SqlServerQuotedView2.first }
|
23
|
-
end
|
24
|
-
|
25
|
-
should 'cope with multi line defaults' do
|
26
|
-
default = StringDefault.new
|
27
|
-
assert_equal "Some long default with a\nnew line.", default.string_with_multiline_default
|
28
|
-
end
|
29
|
-
|
30
|
-
should 'default strings before save' do
|
31
|
-
default = StringDefault.new
|
32
|
-
assert_equal nil, default.string_with_null_default
|
33
|
-
assert_equal 'null', default.string_with_pretend_null_one
|
34
|
-
assert_equal '(null)', default.string_with_pretend_null_two
|
35
|
-
assert_equal 'NULL', default.string_with_pretend_null_three
|
36
|
-
assert_equal '(NULL)', default.string_with_pretend_null_four
|
37
|
-
assert_equal '(3)', default.string_with_pretend_paren_three
|
38
|
-
end
|
39
|
-
|
40
|
-
should 'default strings after save' do
|
41
|
-
default = StringDefault.create
|
42
|
-
assert_equal nil, default.string_with_null_default
|
43
|
-
assert_equal 'null', default.string_with_pretend_null_one
|
44
|
-
assert_equal '(null)', default.string_with_pretend_null_two
|
45
|
-
assert_equal 'NULL', default.string_with_pretend_null_three
|
46
|
-
assert_equal '(NULL)', default.string_with_pretend_null_four
|
47
|
-
end
|
48
|
-
|
49
|
-
context 'Testing edge case schemas' do
|
50
|
-
|
51
|
-
setup do
|
52
|
-
@edge_class = SqlServerEdgeSchema
|
53
|
-
end
|
54
|
-
|
55
|
-
context 'with description column' do
|
56
|
-
|
57
|
-
setup do
|
58
|
-
@da = @edge_class.create! :description => 'A'
|
59
|
-
@db = @edge_class.create! :description => 'B'
|
60
|
-
@dc = @edge_class.create! :description => 'C'
|
61
|
-
end
|
62
|
-
|
63
|
-
teardown { @edge_class.delete_all }
|
64
|
-
|
65
|
-
should 'allow all sorts of ordering without adapter munging it up' do
|
66
|
-
assert_equal ['A','B','C'], @edge_class.all(:order => 'description').map(&:description)
|
67
|
-
assert_equal ['A','B','C'], @edge_class.all(:order => 'description asc').map(&:description)
|
68
|
-
assert_equal ['A','B','C'], @edge_class.all(:order => 'description ASC').map(&:description)
|
69
|
-
assert_equal ['C','B','A'], @edge_class.all(:order => 'description desc').map(&:description)
|
70
|
-
assert_equal ['C','B','A'], @edge_class.all(:order => 'description DESC').map(&:description)
|
71
|
-
end
|
72
|
-
|
73
|
-
end
|
74
|
-
|
75
|
-
context 'with bigint column' do
|
76
|
-
|
77
|
-
setup do
|
78
|
-
@b5k = 5000
|
79
|
-
@bi5k = @edge_class.create! :bigint => @b5k, :description => 'Five Thousand'
|
80
|
-
@bnum = 9_000_000_000_000_000_000
|
81
|
-
@bimjr = @edge_class.create! :bigint => @bnum, :description => 'Close to max bignum'
|
82
|
-
end
|
83
|
-
|
84
|
-
should 'can find by biginit' do
|
85
|
-
assert_equal @bi5k, @edge_class.find_by_bigint(@b5k)
|
86
|
-
assert_equal @b5k, @edge_class.find(:first, :select => 'bigint', :conditions => {:bigint => @b5k}).bigint
|
87
|
-
assert_equal @bimjr, @edge_class.find_by_bigint(@bnum)
|
88
|
-
assert_equal @bnum, @edge_class.find(:first, :select => 'bigint', :conditions => {:bigint => @bnum}).bigint
|
89
|
-
end
|
90
|
-
|
91
|
-
end
|
92
|
-
|
93
|
-
context 'with tinyint column' do
|
94
|
-
|
95
|
-
setup do
|
96
|
-
@tiny1 = @edge_class.create! :tinyint => 1
|
97
|
-
@tiny255 = @edge_class.create! :tinyint => 255
|
98
|
-
end
|
99
|
-
|
100
|
-
should 'not treat tinyint like boolean as mysql does' do
|
101
|
-
assert_equal 1, @edge_class.find_by_tinyint(1).tinyint
|
102
|
-
assert_equal 255, @edge_class.find_by_tinyint(255).tinyint
|
103
|
-
end
|
104
|
-
|
105
|
-
should 'throw an error when going out of our tiny int bounds' do
|
106
|
-
assert_raise(ActiveRecord::StatementInvalid) { @edge_class.create! :tinyint => 256 }
|
107
|
-
end
|
108
|
-
|
109
|
-
end
|
110
|
-
|
111
|
-
context 'with uniqueidentifier column' do
|
112
|
-
|
113
|
-
setup do
|
114
|
-
@newid = ActiveRecord::Base.connection.newid_function
|
115
|
-
assert_guid @newid
|
116
|
-
end
|
117
|
-
|
118
|
-
should 'allow a simple insert and read of a column without a default function' do
|
119
|
-
obj = @edge_class.create! :guid => @newid
|
120
|
-
assert_equal @newid, @edge_class.find(obj.id).guid
|
121
|
-
end
|
122
|
-
|
123
|
-
should 'record the default function name in the column definition but still show a nil real default, will use one day for insert/update' do
|
124
|
-
newid_column = @edge_class.columns_hash['guid_newid']
|
125
|
-
assert newid_column.default_function.present?
|
126
|
-
assert_nil newid_column.default
|
127
|
-
assert_equal 'newid()', newid_column.default_function
|
128
|
-
unless ActiveRecord::Base.connection.sqlserver_2000?
|
129
|
-
newseqid_column = @edge_class.columns_hash['guid_newseqid']
|
130
|
-
assert newseqid_column.default_function.present?
|
131
|
-
assert_nil newseqid_column.default
|
132
|
-
assert_equal 'newsequentialid()', newseqid_column.default_function
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
should 'use model callback to set get a new guid' do
|
137
|
-
obj = @edge_class.new
|
138
|
-
obj.new_id_setting = true
|
139
|
-
obj.save!
|
140
|
-
assert_guid obj.guid_newid
|
141
|
-
end
|
142
|
-
|
143
|
-
end
|
144
|
-
|
145
|
-
end
|
146
|
-
|
147
|
-
|
148
|
-
protected
|
149
|
-
|
150
|
-
def assert_guid(guid)
|
151
|
-
assert_match %r|\w{8}-\w{4}-\w{4}-\w{4}-\w{12}|, guid
|
152
|
-
end
|
153
|
-
|
154
|
-
end
|
@@ -1,140 +0,0 @@
|
|
1
|
-
|
2
|
-
SQLSERVER_TEST_ROOT = File.expand_path(File.join(File.dirname(__FILE__),'..'))
|
3
|
-
SQLSERVER_ASSETS_ROOT = File.expand_path(File.join(SQLSERVER_TEST_ROOT,'assets'))
|
4
|
-
SQLSERVER_FIXTURES_ROOT = File.expand_path(File.join(SQLSERVER_TEST_ROOT,'fixtures'))
|
5
|
-
SQLSERVER_MIGRATIONS_ROOT = File.expand_path(File.join(SQLSERVER_TEST_ROOT,'migrations'))
|
6
|
-
SQLSERVER_SCHEMA_ROOT = File.expand_path(File.join(SQLSERVER_TEST_ROOT,'schema'))
|
7
|
-
ACTIVERECORD_TEST_ROOT = File.expand_path(File.join(ENV['RAILS_SOURCE'],'activerecord','test'))
|
8
|
-
|
9
|
-
require 'rubygems'
|
10
|
-
require 'bundler'
|
11
|
-
Bundler.setup
|
12
|
-
require 'shoulda'
|
13
|
-
require 'mocha'
|
14
|
-
begin ; require 'ruby-debug' ; rescue LoadError ; end
|
15
|
-
[ File.expand_path(File.join(File.dirname(__FILE__),'..','..','test')),
|
16
|
-
File.expand_path(File.join(File.dirname(__FILE__),'..','..','test','connections','native_sqlserver_odbc')),
|
17
|
-
File.expand_path(File.join(ENV['RAILS_SOURCE'],'activerecord','test'))
|
18
|
-
].each{ |lib| $:.unshift(lib) unless $:.include?(lib) } if ENV['TM_DIRECTORY']
|
19
|
-
require 'cases/helper'
|
20
|
-
require 'models/topic'
|
21
|
-
require 'active_record/version'
|
22
|
-
|
23
|
-
GC.copy_on_write_friendly = true if GC.respond_to?(:copy_on_write_friendly?)
|
24
|
-
|
25
|
-
ActiveRecord::Migration.verbose = false
|
26
|
-
ActiveRecord::ConnectionAdapters::SQLServerAdapter.log_info_schema_queries = true
|
27
|
-
|
28
|
-
# Defining our classes in one place as well as soem core tests that need coercing date/time types.
|
29
|
-
|
30
|
-
class TableWithRealColumn < ActiveRecord::Base; end
|
31
|
-
class FkTestHasFk < ActiveRecord::Base ; end
|
32
|
-
class FkTestHasPk < ActiveRecord::Base ; end
|
33
|
-
class NumericData < ActiveRecord::Base ; self.table_name = 'numeric_data' ; end
|
34
|
-
class FloatData < ActiveRecord::Base ; self.table_name = 'float_data' ; end
|
35
|
-
class CustomersView < ActiveRecord::Base ; self.table_name = 'customers_view' ; end
|
36
|
-
class StringDefaultsView < ActiveRecord::Base ; self.table_name = 'string_defaults_view' ; end
|
37
|
-
class StringDefaultsBigView < ActiveRecord::Base ; self.table_name = 'string_defaults_big_view' ; end
|
38
|
-
class SqlServerQuotedTable < ActiveRecord::Base ; self.table_name = 'quoted-table' ; end
|
39
|
-
class SqlServerQuotedView1 < ActiveRecord::Base ; self.table_name = 'quoted-view1' ; end
|
40
|
-
class SqlServerQuotedView2 < ActiveRecord::Base ; self.table_name = 'quoted-view2' ; end
|
41
|
-
class SqlServerUnicode < ActiveRecord::Base ; end
|
42
|
-
class SqlServerString < ActiveRecord::Base ; end
|
43
|
-
class SqlServerChronic < ActiveRecord::Base
|
44
|
-
coerce_sqlserver_date :date
|
45
|
-
coerce_sqlserver_time :time
|
46
|
-
default_timezone = :utc
|
47
|
-
end
|
48
|
-
class Topic < ActiveRecord::Base
|
49
|
-
coerce_sqlserver_date :last_read
|
50
|
-
coerce_sqlserver_time :bonus_time
|
51
|
-
end
|
52
|
-
class Person < ActiveRecord::Base
|
53
|
-
coerce_sqlserver_date :favorite_day
|
54
|
-
end
|
55
|
-
|
56
|
-
# A module that we can include in classes where we want to override an active record test.
|
57
|
-
|
58
|
-
module SqlserverCoercedTest
|
59
|
-
def self.included(base)
|
60
|
-
base.extend ClassMethods
|
61
|
-
end
|
62
|
-
module ClassMethods
|
63
|
-
def coerced_tests
|
64
|
-
self.const_get(:COERCED_TESTS) rescue nil
|
65
|
-
end
|
66
|
-
def method_added(method)
|
67
|
-
if coerced_tests && coerced_tests.include?(method)
|
68
|
-
undef_method(method)
|
69
|
-
STDOUT.puts("Undefined coerced test: #{self.name}##{method}")
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
# Set weather to test unicode string defaults or not. Used from rake task.
|
76
|
-
|
77
|
-
if ENV['ENABLE_DEFAULT_UNICODE_TYPES'] != 'false'
|
78
|
-
puts "With enabled unicode string types"
|
79
|
-
ActiveRecord::ConnectionAdapters::SQLServerAdapter.enable_default_unicode_types = true
|
80
|
-
end
|
81
|
-
|
82
|
-
# Change the text database type to support ActiveRecord's tests for = on text columns which
|
83
|
-
# is not supported in SQL Server text columns, so use varchar(8000) instead.
|
84
|
-
|
85
|
-
if ActiveRecord::Base.connection.sqlserver_2000?
|
86
|
-
if ActiveRecord::ConnectionAdapters::SQLServerAdapter.enable_default_unicode_types
|
87
|
-
ActiveRecord::ConnectionAdapters::SQLServerAdapter.native_text_database_type = 'nvarchar(4000)'
|
88
|
-
else
|
89
|
-
ActiveRecord::ConnectionAdapters::SQLServerAdapter.native_text_database_type = 'varchar(8000)'
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
# Our changes/additions to ActiveRecord test helpers specific for SQL Server.
|
94
|
-
|
95
|
-
ActiveRecord::Base.connection.class.class_eval do
|
96
|
-
IGNORED_SQL << %r|SELECT SCOPE_IDENTITY| << %r{INFORMATION_SCHEMA\.(TABLES|VIEWS|COLUMNS)}
|
97
|
-
IGNORED_SQL << %r|SELECT @@IDENTITY| << %r|SELECT @@ROWCOUNT| << %r|SELECT @@version| << %r|SELECT @@TRANCOUNT|
|
98
|
-
end
|
99
|
-
|
100
|
-
ActiveRecord::ConnectionAdapters::SQLServerAdapter.class_eval do
|
101
|
-
def raw_select_with_query_record(sql, name=nil, options={})
|
102
|
-
$queries_executed ||= []
|
103
|
-
$queries_executed << sql unless IGNORED_SQL.any? { |r| sql =~ r }
|
104
|
-
raw_select_without_query_record(sql,name,options)
|
105
|
-
end
|
106
|
-
alias_method_chain :raw_select, :query_record
|
107
|
-
end
|
108
|
-
|
109
|
-
module ActiveRecord
|
110
|
-
class TestCase < ActiveSupport::TestCase
|
111
|
-
class << self
|
112
|
-
def connection_mode_dblib? ; ActiveRecord::Base.connection.instance_variable_get(:@connection_options)[:mode] == :dblib ; end
|
113
|
-
def connection_mode_odbc? ; ActiveRecord::Base.connection.instance_variable_get(:@connection_options)[:mode] == :odbc ; end
|
114
|
-
def connection_mode_adonet? ; ActiveRecord::Base.connection.instance_variable_get(:@connection_options)[:mode] == :adonet ; end
|
115
|
-
def sqlserver_2000? ; ActiveRecord::Base.connection.sqlserver_2000? ; end
|
116
|
-
def sqlserver_2005? ; ActiveRecord::Base.connection.sqlserver_2005? ; end
|
117
|
-
def sqlserver_2008? ; ActiveRecord::Base.connection.sqlserver_2008? ; end
|
118
|
-
def ruby_19? ; RUBY_VERSION >= '1.9' ; end
|
119
|
-
end
|
120
|
-
def assert_sql(*patterns_to_match)
|
121
|
-
$queries_executed = []
|
122
|
-
yield
|
123
|
-
ensure
|
124
|
-
failed_patterns = []
|
125
|
-
patterns_to_match.each do |pattern|
|
126
|
-
failed_patterns << pattern unless $queries_executed.any?{ |sql| pattern === sql }
|
127
|
-
end
|
128
|
-
assert failed_patterns.empty?, "Query pattern(s) #{failed_patterns.map(&:inspect).join(', ')} not found in:\n#{$queries_executed.inspect}"
|
129
|
-
end
|
130
|
-
def connection_mode_dblib? ; self.class.connection_mode_dblib? ; end
|
131
|
-
def connection_mode_odbc? ; self.class.connection_mode_odbc? ; end
|
132
|
-
def connection_mode_adonet? ; self.class.connection_mode_adonet? ; end
|
133
|
-
def sqlserver_2000? ; self.class.sqlserver_2000? ; end
|
134
|
-
def sqlserver_2005? ; self.class.sqlserver_2005? ; end
|
135
|
-
def sqlserver_2008? ; self.class.sqlserver_2008? ; end
|
136
|
-
def ruby_19? ; self.class.ruby_19? ; end
|
137
|
-
end
|
138
|
-
end
|
139
|
-
|
140
|
-
|