activerecord-sqlserver-adapter 4.1.8 → 4.2.0.pre

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.
Files changed (122) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +15 -0
  3. data/CHANGELOG.md +60 -0
  4. data/Gemfile +45 -0
  5. data/Guardfile +29 -0
  6. data/MIT-LICENSE +5 -5
  7. data/README.md +193 -0
  8. data/RUNNING_UNIT_TESTS.md +95 -0
  9. data/Rakefile +48 -0
  10. data/activerecord-sqlserver-adapter.gemspec +28 -0
  11. data/lib/active_record/connection_adapters/sqlserver/core_ext/active_record.rb +5 -15
  12. data/lib/active_record/connection_adapters/sqlserver/core_ext/attribute_methods.rb +25 -0
  13. data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +6 -4
  14. data/lib/active_record/connection_adapters/sqlserver/core_ext/odbc.rb +9 -3
  15. data/lib/active_record/connection_adapters/sqlserver/database_limits.rb +3 -1
  16. data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +130 -151
  17. data/lib/active_record/connection_adapters/sqlserver/errors.rb +0 -25
  18. data/lib/active_record/connection_adapters/sqlserver/quoting.rb +39 -78
  19. data/lib/active_record/connection_adapters/sqlserver/schema_cache.rb +71 -47
  20. data/lib/active_record/connection_adapters/sqlserver/schema_creation.rb +14 -30
  21. data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +112 -108
  22. data/lib/active_record/connection_adapters/sqlserver/showplan.rb +4 -2
  23. data/lib/active_record/connection_adapters/sqlserver/showplan/printer_table.rb +1 -1
  24. data/lib/active_record/connection_adapters/sqlserver/showplan/printer_xml.rb +1 -1
  25. data/lib/active_record/connection_adapters/sqlserver/table_definition.rb +52 -7
  26. data/lib/active_record/connection_adapters/sqlserver/transaction.rb +52 -0
  27. data/lib/active_record/connection_adapters/sqlserver/type.rb +46 -0
  28. data/lib/active_record/connection_adapters/sqlserver/type/big_integer.rb +15 -0
  29. data/lib/active_record/connection_adapters/sqlserver/type/binary.rb +15 -0
  30. data/lib/active_record/connection_adapters/sqlserver/type/boolean.rb +13 -0
  31. data/lib/active_record/connection_adapters/sqlserver/type/castable.rb +15 -0
  32. data/lib/active_record/connection_adapters/sqlserver/type/char.rb +15 -0
  33. data/lib/active_record/connection_adapters/sqlserver/type/core_ext/value.rb +39 -0
  34. data/lib/active_record/connection_adapters/sqlserver/type/date.rb +14 -0
  35. data/lib/active_record/connection_adapters/sqlserver/type/datetime.rb +37 -0
  36. data/lib/active_record/connection_adapters/sqlserver/type/decimal.rb +13 -0
  37. data/lib/active_record/connection_adapters/sqlserver/type/float.rb +17 -0
  38. data/lib/active_record/connection_adapters/sqlserver/type/integer.rb +13 -0
  39. data/lib/active_record/connection_adapters/sqlserver/type/money.rb +21 -0
  40. data/lib/active_record/connection_adapters/sqlserver/type/quoter.rb +32 -0
  41. data/lib/active_record/connection_adapters/sqlserver/type/real.rb +17 -0
  42. data/lib/active_record/connection_adapters/sqlserver/type/small_integer.rb +13 -0
  43. data/lib/active_record/connection_adapters/sqlserver/type/small_money.rb +21 -0
  44. data/lib/active_record/connection_adapters/sqlserver/type/smalldatetime.rb +24 -0
  45. data/lib/active_record/connection_adapters/sqlserver/type/string.rb +12 -0
  46. data/lib/active_record/connection_adapters/sqlserver/type/text.rb +15 -0
  47. data/lib/active_record/connection_adapters/sqlserver/type/time.rb +59 -0
  48. data/lib/active_record/connection_adapters/sqlserver/type/timestamp.rb +15 -0
  49. data/lib/active_record/connection_adapters/sqlserver/type/tiny_integer.rb +22 -0
  50. data/lib/active_record/connection_adapters/sqlserver/type/unicode_char.rb +15 -0
  51. data/lib/active_record/connection_adapters/sqlserver/type/unicode_string.rb +12 -0
  52. data/lib/active_record/connection_adapters/sqlserver/type/unicode_text.rb +15 -0
  53. data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar.rb +20 -0
  54. data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar_max.rb +20 -0
  55. data/lib/active_record/connection_adapters/sqlserver/type/uuid.rb +23 -0
  56. data/lib/active_record/connection_adapters/sqlserver/type/varbinary.rb +20 -0
  57. data/lib/active_record/connection_adapters/sqlserver/type/varbinary_max.rb +20 -0
  58. data/lib/active_record/connection_adapters/sqlserver/type/varchar.rb +20 -0
  59. data/lib/active_record/connection_adapters/sqlserver/type/varchar_max.rb +20 -0
  60. data/lib/active_record/connection_adapters/sqlserver/utils.rb +118 -12
  61. data/lib/active_record/connection_adapters/sqlserver/version.rb +11 -0
  62. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +133 -198
  63. data/lib/active_record/connection_adapters/sqlserver_column.rb +15 -86
  64. data/lib/active_record/sqlserver_base.rb +2 -0
  65. data/lib/arel/visitors/sqlserver.rb +120 -393
  66. data/lib/{arel/arel_sqlserver.rb → arel_sqlserver.rb} +1 -3
  67. data/test/cases/adapter_test_sqlserver.rb +420 -0
  68. data/test/cases/coerced_tests.rb +642 -0
  69. data/test/cases/column_test_sqlserver.rb +703 -0
  70. data/test/cases/connection_test_sqlserver.rb +216 -0
  71. data/test/cases/database_statements_test_sqlserver.rb +57 -0
  72. data/test/cases/execute_procedure_test_sqlserver.rb +38 -0
  73. data/test/cases/helper_sqlserver.rb +36 -0
  74. data/test/cases/migration_test_sqlserver.rb +66 -0
  75. data/test/cases/order_test_sqlserver.rb +147 -0
  76. data/test/cases/pessimistic_locking_test_sqlserver.rb +90 -0
  77. data/test/cases/schema_dumper_test_sqlserver.rb +175 -0
  78. data/test/cases/schema_test_sqlserver.rb +54 -0
  79. data/test/cases/scratchpad_test_sqlserver.rb +9 -0
  80. data/test/cases/showplan_test_sqlserver.rb +65 -0
  81. data/test/cases/specific_schema_test_sqlserver.rb +118 -0
  82. data/test/cases/transaction_test_sqlserver.rb +61 -0
  83. data/test/cases/utils_test_sqlserver.rb +91 -0
  84. data/test/cases/uuid_test_sqlserver.rb +41 -0
  85. data/test/config.yml +35 -0
  86. data/test/fixtures/1px.gif +0 -0
  87. data/test/migrations/transaction_table/1_table_will_never_be_created.rb +11 -0
  88. data/test/models/sqlserver/customers_view.rb +3 -0
  89. data/test/models/sqlserver/datatype.rb +3 -0
  90. data/test/models/sqlserver/datatype_migration.rb +3 -0
  91. data/test/models/sqlserver/dollar_table_name.rb +3 -0
  92. data/test/models/sqlserver/edge_schema.rb +13 -0
  93. data/test/models/sqlserver/fk_has_fk.rb +3 -0
  94. data/test/models/sqlserver/fk_has_pk.rb +3 -0
  95. data/test/models/sqlserver/natural_pk_data.rb +4 -0
  96. data/test/models/sqlserver/natural_pk_int_data.rb +3 -0
  97. data/test/models/sqlserver/no_pk_data.rb +3 -0
  98. data/test/models/sqlserver/quoted_table.rb +7 -0
  99. data/test/models/sqlserver/quoted_view_1.rb +3 -0
  100. data/test/models/sqlserver/quoted_view_2.rb +3 -0
  101. data/test/models/sqlserver/string_default.rb +3 -0
  102. data/test/models/sqlserver/string_defaults_big_view.rb +3 -0
  103. data/test/models/sqlserver/string_defaults_view.rb +3 -0
  104. data/test/models/sqlserver/tinyint_pk.rb +3 -0
  105. data/test/models/sqlserver/upper.rb +3 -0
  106. data/test/models/sqlserver/uppered.rb +3 -0
  107. data/test/models/sqlserver/uuid.rb +3 -0
  108. data/test/schema/datatypes/2012.sql +64 -0
  109. data/test/schema/sqlserver_specific_schema.rb +181 -0
  110. data/test/support/coerceable_test_sqlserver.rb +45 -0
  111. data/test/support/load_schema_sqlserver.rb +29 -0
  112. data/test/support/minitest_sqlserver.rb +1 -0
  113. data/test/support/paths_sqlserver.rb +48 -0
  114. data/test/support/rake_helpers.rb +41 -0
  115. data/test/support/sql_counter_sqlserver.rb +32 -0
  116. metadata +271 -21
  117. data/CHANGELOG +0 -39
  118. data/VERSION +0 -1
  119. data/lib/active_record/connection_adapters/sqlserver/core_ext/relation.rb +0 -17
  120. data/lib/active_record/sqlserver_test_case.rb +0 -17
  121. data/lib/arel/nodes_sqlserver.rb +0 -14
  122. data/lib/arel/select_manager_sqlserver.rb +0 -62
@@ -0,0 +1,216 @@
1
+ require 'cases/helper_sqlserver'
2
+ require 'models/reply'
3
+ require 'models/topic'
4
+
5
+ class ConnectionTestSQLServer < ActiveRecord::TestCase
6
+
7
+ self.use_transactional_fixtures = false
8
+
9
+ fixtures :topics, :accounts
10
+
11
+ before { assert connection.active? }
12
+ after { connection.reconnect! }
13
+
14
+ it 'affect rows' do
15
+ topic_data = { 1 => { "content" => "1 updated" }, 2 => { "content" => "2 updated" } }
16
+ updated = Topic.update(topic_data.keys, topic_data.values)
17
+ assert_equal 2, updated.size
18
+ assert_equal "1 updated", Topic.find(1).content
19
+ assert_equal "2 updated", Topic.find(2).content
20
+ assert_equal 2, Topic.delete([1, 2])
21
+ end
22
+
23
+ it 'allow usage of :database connection option to remove setting from dsn' do
24
+ assert_equal 'activerecord_unittest', connection.current_database
25
+ begin
26
+ connection.use_database('activerecord_unittest2')
27
+ assert_equal 'activerecord_unittest2', connection.current_database
28
+ ensure
29
+ connection.use_database
30
+ assert_equal 'activerecord_unittest', connection.current_database, 'Would default back to connection options'
31
+ end
32
+ end unless sqlserver_azure?
33
+
34
+ describe 'ODBC connection management' do
35
+
36
+ it 'return finished ODBC statement handle from #execute without block' do
37
+ assert_all_odbc_statements_used_are_closed do
38
+ connection.execute('SELECT * FROM [topics]')
39
+ end
40
+ end
41
+
42
+ it 'finish ODBC statement handle from #execute with block' do
43
+ assert_all_odbc_statements_used_are_closed do
44
+ connection.execute('SELECT * FROM [topics]') { }
45
+ end
46
+ end
47
+
48
+ it 'finish connection from #raw_select' do
49
+ assert_all_odbc_statements_used_are_closed do
50
+ connection.send(:raw_select,'SELECT * FROM [topics]')
51
+ end
52
+ end
53
+
54
+ it 'execute without block closes statement' do
55
+ assert_all_odbc_statements_used_are_closed do
56
+ connection.execute("SELECT 1")
57
+ end
58
+ end
59
+
60
+ it 'execute with block closes statement' do
61
+ assert_all_odbc_statements_used_are_closed do
62
+ connection.execute("SELECT 1") do |sth|
63
+ assert !sth.finished?, "Statement should still be alive within block"
64
+ end
65
+ end
66
+ end
67
+
68
+ it 'insert with identity closes statement' do
69
+ assert_all_odbc_statements_used_are_closed do
70
+ connection.exec_insert "INSERT INTO accounts ([id],[firm_id],[credit_limit]) VALUES (999, 1, 50)", "SQL", []
71
+ end
72
+ end
73
+
74
+ it 'insert without identity closes statement' do
75
+ assert_all_odbc_statements_used_are_closed do
76
+ connection.exec_insert "INSERT INTO accounts ([firm_id],[credit_limit]) VALUES (1, 50)", "SQL", []
77
+ end
78
+ end
79
+
80
+ it 'active closes statement' do
81
+ assert_all_odbc_statements_used_are_closed do
82
+ connection.active?
83
+ end
84
+ end
85
+
86
+ end if connection_mode_odbc?
87
+
88
+
89
+ describe 'Connection management' do
90
+
91
+ it 'set spid on connect' do
92
+ assert_instance_of Fixnum, connection.spid
93
+ end
94
+
95
+ it 'reset spid on disconnect!' do
96
+ connection.disconnect!
97
+ assert connection.spid.nil?
98
+ end
99
+
100
+ it 'reset the connection' do
101
+ connection.disconnect!
102
+ connection.raw_connection.must_be_nil
103
+ end
104
+
105
+ it 'be able to disconnect and reconnect at will' do
106
+ disconnect_raw_connection!
107
+ assert !connection.active?
108
+ connection.reconnect!
109
+ assert connection.active?
110
+ end
111
+
112
+ describe 'with a deadlock victim exception 1205' do
113
+
114
+ describe 'outside a transaction' do
115
+
116
+ before do
117
+ @query = "SELECT 1 as [one]"
118
+ @expected = connection.execute(@query)
119
+ # Execute the query to get a handle of the expected result, which
120
+ # will be returned after a simulated deadlock victim (1205).
121
+ raw_conn = connection.raw_connection
122
+ stubbed_handle = raw_conn.execute(@query)
123
+ connection.send(:finish_statement_handle, stubbed_handle)
124
+ raw_conn.stubs(:execute).raises(deadlock_victim_exception(@query)).then.returns(stubbed_handle)
125
+ end
126
+
127
+ it 'raise ActiveRecord::DeadlockVictim' do
128
+ assert_raise(ActiveRecord::DeadlockVictim) do
129
+ assert_equal @expected, connection.execute(@query)
130
+ end
131
+ end
132
+
133
+ end
134
+
135
+ describe 'within a transaction' do
136
+
137
+ before do
138
+ @query = "SELECT 1 as [one]"
139
+ @expected = connection.execute(@query)
140
+ # We "stub" the execute method to simulate raising a deadlock victim exception once.
141
+ connection.class.class_eval do
142
+ def execute_with_deadlock_exception(sql, *args)
143
+ if !@raised_deadlock_exception && sql == "SELECT 1 as [one]"
144
+ sql = "RAISERROR('Transaction (Process ID #{Process.pid}) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.: #{sql}', 13, 1)"
145
+ @raised_deadlock_exception = true
146
+ elsif @raised_deadlock_exception == true && sql =~ /RAISERROR\('Transaction \(Process ID \d+\) was deadlocked on lock resources with another process and has been chosen as the deadlock victim\. Rerun the transaction\.: SELECT 1 as \[one\]', 13, 1\)/
147
+ sql = "SELECT 1 as [one]"
148
+ end
149
+ execute_without_deadlock_exception(sql, *args)
150
+ end
151
+ alias :execute_without_deadlock_exception :execute
152
+ alias :execute :execute_with_deadlock_exception
153
+ end
154
+ end
155
+
156
+ after do
157
+ # Cleanup the "stubbed" execute method.
158
+ connection.class.class_eval do
159
+ alias :execute :execute_without_deadlock_exception
160
+ remove_method :execute_with_deadlock_exception
161
+ remove_method :execute_without_deadlock_exception
162
+ end
163
+ connection.send(:remove_instance_variable, :@raised_deadlock_exception)
164
+ end
165
+
166
+ it 'raise ActiveRecord::DeadlockVictim if retry disabled' do
167
+ assert_raise(ActiveRecord::DeadlockVictim) do
168
+ ActiveRecord::Base.transaction do
169
+ assert_equal @expected, connection.execute(@query)
170
+ end
171
+ end
172
+ end
173
+
174
+ end
175
+
176
+ end if connection_mode_dblib? # Since it is easier to test, but feature should work in ODBC too.
177
+
178
+ end
179
+
180
+
181
+ private
182
+
183
+ def disconnect_raw_connection!
184
+ case connection.instance_variable_get(:@connection_options)[:mode]
185
+ when :dblib
186
+ connection.raw_connection.close rescue nil
187
+ when :odbc
188
+ connection.raw_connection.disconnect rescue nil
189
+ end
190
+ end
191
+
192
+ def assert_all_odbc_statements_used_are_closed(&block)
193
+ odbc = connection.raw_connection.class.parent
194
+ existing_handles = []
195
+ ObjectSpace.each_object(odbc::Statement) { |h| existing_handles << h }
196
+ existing_handle_ids = existing_handles.map(&:object_id)
197
+ assert existing_handles.all?(&:finished?), "Somewhere before the block some statements were not closed"
198
+ GC.disable
199
+ yield
200
+ used_handles = []
201
+ ObjectSpace.each_object(odbc::Statement) { |h| used_handles << h unless existing_handle_ids.include?(h.object_id) }
202
+ assert used_handles.size > 0, "No statements were used within given block"
203
+ assert used_handles.all?(&:finished?), "Statement should have been closed within given block"
204
+ ensure
205
+ GC.enable
206
+ end
207
+
208
+ def deadlock_victim_exception(sql)
209
+ require 'tiny_tds/error'
210
+ error = TinyTds::Error.new("Transaction (Process ID #{Process.pid}) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.: #{sql}")
211
+ error.severity = 13
212
+ error.db_error_number = 1205
213
+ error
214
+ end
215
+
216
+ end
@@ -0,0 +1,57 @@
1
+ require 'cases/helper_sqlserver'
2
+
3
+ class DatabaseStatementsTestSQLServer < ActiveRecord::TestCase
4
+
5
+ self.use_transactional_fixtures = false
6
+
7
+ after { connection.use_database }
8
+
9
+ it 'create database' do
10
+ connection.create_database 'activerecord_unittest3'
11
+ database_name = connection.select_value "SELECT name FROM master.dbo.sysdatabases WHERE name = 'activerecord_unittest3'"
12
+ assert_equal 'activerecord_unittest3', database_name
13
+ end
14
+
15
+ it 'drop database' do
16
+ connection.drop_database 'activerecord_unittest3'
17
+ database_name = connection.select_value "SELECT name FROM master.dbo.sysdatabases WHERE name = 'activerecord_unittest3'"
18
+ assert_equal nil, database_name
19
+ end
20
+
21
+ it 'create/use/drop database with name with dots' do
22
+ connection.drop_database '[activerecord.unittest]' rescue nil
23
+ connection.create_database '[activerecord.unittest]'
24
+ database_name = connection.select_value "SELECT name FROM master.dbo.sysdatabases WHERE name = 'activerecord.unittest'"
25
+ assert_equal 'activerecord.unittest', database_name
26
+ connection.use_database '[activerecord.unittest]'
27
+ connection.use_database
28
+ connection.drop_database '[activerecord.unittest]'
29
+ end
30
+
31
+ describe 'with collation' do
32
+
33
+ after { connection.drop_database 'activerecord_unittest3' }
34
+
35
+ it 'create database with default collation for the server' do
36
+ connection.create_database 'activerecord_unittest3'
37
+ default_collation = connection.select_value "SELECT SERVERPROPERTY('Collation')"
38
+ database_collation = connection.select_value "SELECT DATABASEPROPERTYEX('activerecord_unittest3', 'Collation') SQLCollation"
39
+ assert_equal default_collation, database_collation
40
+ end
41
+
42
+ it 'create database with collation set by the method' do
43
+ connection.create_database 'activerecord_unittest3', collation: 'SQL_Latin1_General_CP1_CI_AS'
44
+ collation = connection.select_value "SELECT DATABASEPROPERTYEX('activerecord_unittest3', 'Collation') SQLCollation"
45
+ assert_equal 'SQL_Latin1_General_CP1_CI_AS', collation
46
+ end
47
+
48
+ it 'create database with collation set by the config' do
49
+ connection.instance_variable_get(:@connection_options)[:collation] = 'SQL_Latin1_General_CP1_CI_AS'
50
+ connection.create_database 'activerecord_unittest3'
51
+ collation = connection.select_value "SELECT DATABASEPROPERTYEX('activerecord_unittest3', 'Collation') SQLCollation"
52
+ assert_equal 'SQL_Latin1_General_CP1_CI_AS', collation
53
+ end
54
+
55
+ end
56
+
57
+ end
@@ -0,0 +1,38 @@
1
+ require 'cases/helper_sqlserver'
2
+
3
+ class ExecuteProcedureTestSQLServer < ActiveRecord::TestCase
4
+
5
+ it 'execute a simple procedure' do
6
+ tables = ActiveRecord::Base.execute_procedure :sp_tables
7
+ assert_instance_of Array, tables
8
+ assert tables.first.respond_to?(:keys)
9
+ end
10
+
11
+ it 'take parameter arguments' do
12
+ tables = ActiveRecord::Base.execute_procedure :sp_tables, 'sst_datatypes'
13
+ table_info = tables.first
14
+ assert_equal 1, tables.size
15
+ assert_equal (ENV['ARUNIT_DB_NAME'] || 'activerecord_unittest'), table_info['TABLE_QUALIFIER'], "Table Info: #{table_info.inspect}"
16
+ assert_equal 'TABLE', table_info['TABLE_TYPE'], "Table Info: #{table_info.inspect}"
17
+ end
18
+
19
+ it 'allow multiple result sets to be returned' do
20
+ results1, results2 = ActiveRecord::Base.execute_procedure('sp_helpconstraint','accounts')
21
+ assert_instance_of Array, results1
22
+ assert results1.first.respond_to?(:keys)
23
+ assert results1.first['Object Name']
24
+ assert_instance_of Array, results2
25
+ assert results2.first.respond_to?(:keys)
26
+ assert results2.first['constraint_name']
27
+ assert results2.first['constraint_type']
28
+ end
29
+
30
+ it 'take named parameter arguments' do
31
+ tables = ActiveRecord::Base.execute_procedure :sp_tables, table_name: 'tables', table_owner: 'sys'
32
+ table_info = tables.first
33
+ assert_equal 1, tables.size
34
+ assert_equal (ENV['ARUNIT_DB_NAME'] || 'activerecord_unittest'), table_info['TABLE_QUALIFIER'], "Table Info: #{table_info.inspect}"
35
+ assert_equal 'VIEW', table_info['TABLE_TYPE'], "Table Info: #{table_info.inspect}"
36
+ end
37
+
38
+ end
@@ -0,0 +1,36 @@
1
+ require 'bundler' ; Bundler.require :default, :development, :test
2
+ require 'support/paths_sqlserver'
3
+ require 'support/minitest_sqlserver'
4
+ require 'cases/helper'
5
+ require 'support/load_schema_sqlserver'
6
+ require 'support/coerceable_test_sqlserver'
7
+ require 'support/sql_counter_sqlserver'
8
+ require 'mocha/mini_test'
9
+
10
+ module ActiveRecord
11
+ class TestCase < ActiveSupport::TestCase
12
+
13
+ SQLServer = ActiveRecord::ConnectionAdapters::SQLServer
14
+
15
+ include ARTest::SQLServer::CoerceableTest
16
+
17
+ let(:logger) { ActiveRecord::Base.logger }
18
+ let(:connection) { ActiveRecord::Base.connection }
19
+
20
+ class << self
21
+ def connection_mode_dblib? ; ActiveRecord::Base.connection.instance_variable_get(:@connection_options)[:mode] == :dblib ; end
22
+ def connection_mode_odbc? ; ActiveRecord::Base.connection.instance_variable_get(:@connection_options)[:mode] == :odbc ; end
23
+ def sqlserver_azure? ; ActiveRecord::Base.connection.sqlserver_azure? ; end
24
+ end
25
+
26
+
27
+ private
28
+
29
+ def connection_mode_dblib? ; self.class.connection_mode_dblib? ; end
30
+ def connection_mode_odbc? ; self.class.connection_mode_odbc? ; end
31
+ def sqlserver_azure? ; self.class.sqlserver_azure? ; end
32
+
33
+ end
34
+ end
35
+
36
+ Dir["#{ARTest::SQLServer.test_root_sqlserver}/models/**/*.rb"].each { |f| require f }
@@ -0,0 +1,66 @@
1
+ require 'cases/helper_sqlserver'
2
+ require 'models/person'
3
+
4
+ class MigrationTestSQLServer < ActiveRecord::TestCase
5
+
6
+ describe 'For transactions' do
7
+
8
+ before do
9
+ @trans_test_table1 = 'sqlserver_trans_table1'
10
+ @trans_test_table2 = 'sqlserver_trans_table2'
11
+ @trans_tables = [@trans_test_table1,@trans_test_table2]
12
+ end
13
+
14
+ after do
15
+ @trans_tables.each do |table_name|
16
+ ActiveRecord::Migration.drop_table(table_name) if connection.tables.include?(table_name)
17
+ end
18
+ end
19
+
20
+ it 'not create a tables if error in migrations' do
21
+ begin
22
+ migrations_dir = File.join ARTest::SQLServer.migrations_root, 'transaction_table'
23
+ quietly { ActiveRecord::Migrator.up(migrations_dir) }
24
+ rescue Exception => e
25
+ assert_match %r|this and all later migrations canceled|, e.message
26
+ end
27
+ connection.tables.wont_include @trans_test_table1
28
+ connection.tables.wont_include @trans_test_table2
29
+ end
30
+
31
+ end
32
+
33
+ describe 'For changing column' do
34
+
35
+ it 'not raise exception when column contains default constraint' do
36
+ lock_version_column = Person.columns_hash['lock_version']
37
+ assert_equal :integer, lock_version_column.type
38
+ assert lock_version_column.default.present?
39
+ assert_nothing_raised { connection.change_column 'people', 'lock_version', :string }
40
+ Person.reset_column_information
41
+ lock_version_column = Person.columns_hash['lock_version']
42
+ assert_equal :string, lock_version_column.type
43
+ assert lock_version_column.default.nil?
44
+ end
45
+
46
+ it 'not drop the default contraint if just renaming' do
47
+ find_default = lambda do
48
+ connection.execute_procedure(:sp_helpconstraint, 'sst_string_defaults', 'nomsg').select do |row|
49
+ row['constraint_type'] == "DEFAULT on column string_with_pretend_paren_three"
50
+ end.last
51
+ end
52
+ default_before = find_default.call
53
+ connection.change_column :sst_string_defaults, :string_with_pretend_paren_three, :string, limit: 255
54
+ default_after = find_default.call
55
+ assert default_after
56
+ assert_equal default_before['constraint_keys'], default_after['constraint_keys']
57
+ end
58
+
59
+ end
60
+
61
+
62
+ def quietly
63
+ silence_stream(STDOUT) { silence_stream(STDERR) { yield } }
64
+ end
65
+
66
+ end
@@ -0,0 +1,147 @@
1
+ require 'cases/helper_sqlserver'
2
+ require 'models/post'
3
+
4
+ class OrderTestSQLServer < ActiveRecord::TestCase
5
+
6
+ fixtures :posts
7
+
8
+ it 'not mangel complex order clauses' do
9
+ xyz_order = "CASE WHEN [title] LIKE N'XYZ%' THEN 0 ELSE 1 END"
10
+ xyz_post = Post.create title: 'XYZ Post', body: 'Test cased orders.'
11
+ assert_equal xyz_post, Post.order(Arel.sql(xyz_order)).first
12
+ end
13
+
14
+ it 'support column' do
15
+ order = "title"
16
+ post1 = Post.create title: 'AAA Post', body: 'Test cased orders.'
17
+ assert_equal post1, Post.order(order).first
18
+ end
19
+
20
+ it 'support column ASC' do
21
+ order = "title ASC"
22
+ post1 = Post.create title: 'AAA Post', body: 'Test cased orders.'
23
+ assert_equal post1, Post.order(order).first
24
+ end
25
+
26
+ it 'support column DESC' do
27
+ order = "title DESC"
28
+ post1 = Post.create title: 'ZZZ Post', body: 'Test cased orders.'
29
+ assert_equal post1, Post.order(order).first
30
+ end
31
+
32
+ it 'support column as symbol' do
33
+ order = :title
34
+ post1 = Post.create title: 'AAA Post', body: 'Test cased orders.'
35
+ assert_equal post1, Post.order(order).first
36
+ end
37
+
38
+ it 'support table and column' do
39
+ order = "posts.title"
40
+ post1 = Post.create title: 'AAA Post', body: 'Test cased orders.'
41
+ assert_equal post1, Post.order(order).first
42
+ end
43
+
44
+ it 'support quoted column' do
45
+ order = "[title]"
46
+ post1 = Post.create title: 'AAA Post', body: 'Test cased orders.'
47
+ assert_equal post1, Post.order(order).first
48
+ end
49
+
50
+ it 'support quoted table and column' do
51
+ order = "[posts].[title]"
52
+ post1 = Post.create title: 'AAA Post', body: 'Test cased orders.'
53
+ assert_equal post1, Post.order(order).first
54
+ end
55
+
56
+ it 'support primary: column, secondary: column' do
57
+ order = "title DESC, body"
58
+ post1 = Post.create title: 'ZZZ Post', body: 'Test cased orders.'
59
+ post2 = Post.create title: 'ZZZ Post', body: 'ZZZ Test cased orders.'
60
+ assert_equal post1, Post.order(order).first
61
+ assert_equal post2, Post.order(order).second
62
+ end
63
+
64
+ it 'support primary: table and column, secondary: column' do
65
+ order = "posts.title DESC, body"
66
+ post1 = Post.create title: 'ZZZ Post', body: 'Test cased orders.'
67
+ post2 = Post.create title: 'ZZZ Post', body: 'ZZZ Test cased orders.'
68
+ assert_equal post1, Post.order(order).first
69
+ assert_equal post2, Post.order(order).second
70
+ end
71
+
72
+ it 'support primary: case expression, secondary: column' do
73
+ order = "(CASE WHEN [title] LIKE N'ZZZ%' THEN title ELSE '' END) DESC, body"
74
+ post1 = Post.create title: 'ZZZ Post', body: 'Test cased orders.'
75
+ post2 = Post.create title: 'ZZZ Post', body: 'ZZZ Test cased orders.'
76
+ assert_equal post1, Post.order(order).first
77
+ assert_equal post2, Post.order(order).second
78
+ end
79
+
80
+ it 'support primary: quoted table and column, secondary: case expresion' do
81
+ order = "[posts].[body] DESC, (CASE WHEN [title] LIKE N'ZZZ%' THEN title ELSE '' END) DESC"
82
+ post1 = Post.create title: 'ZZZ Post', body: 'ZZZ Test cased orders.'
83
+ post2 = Post.create title: 'ZZY Post', body: 'ZZZ Test cased orders.'
84
+ assert_equal post1, Post.order(order).first
85
+ assert_equal post2, Post.order(order).second
86
+ end
87
+
88
+ it 'support inline function' do
89
+ order = "LEN(title)"
90
+ post1 = Post.create title: 'A', body: 'AAA Test cased orders.'
91
+ assert_equal post1, Post.order(order).first
92
+ end
93
+
94
+ it 'support inline function with parameters' do
95
+ order = "SUBSTRING(title, 1, 3)"
96
+ post1 = Post.create title: 'AAA Post', body: 'Test cased orders.'
97
+ assert_equal post1, Post.order(order).first
98
+ end
99
+
100
+ it 'support inline function with parameters DESC' do
101
+ order = "SUBSTRING(title, 1, 3) DESC"
102
+ post1 = Post.create title: 'ZZZ Post', body: 'Test cased orders.'
103
+ assert_equal post1, Post.order(order).first
104
+ end
105
+
106
+ it 'support primary: inline function, secondary: column' do
107
+ order = "LEN(title), body"
108
+ post1 = Post.create title: 'A', body: 'AAA Test cased orders.'
109
+ post2 = Post.create title: 'A', body: 'Test cased orders.'
110
+ assert_equal post1, Post.order(order).first
111
+ assert_equal post2, Post.order(order).second
112
+ end
113
+
114
+ it 'support primary: inline function, secondary: column with direction' do
115
+ order = "LEN(title) ASC, body DESC"
116
+ post1 = Post.create title: 'A', body: 'ZZZ Test cased orders.'
117
+ post2 = Post.create title: 'A', body: 'Test cased orders.'
118
+ assert_equal post1, Post.order(order).first
119
+ assert_equal post2, Post.order(order).second
120
+ end
121
+
122
+ it 'support primary: column, secondary: inline function' do
123
+ order = "body DESC, LEN(title)"
124
+ post1 = Post.create title: 'Post', body: 'ZZZ Test cased orders.'
125
+ post2 = Post.create title: 'Longer Post', body: 'ZZZ Test cased orders.'
126
+ assert_equal post1, Post.order(order).first
127
+ assert_equal post2, Post.order(order).second
128
+ end
129
+
130
+ it 'support primary: case expression, secondary: inline function' do
131
+ order = "CASE WHEN [title] LIKE N'ZZZ%' THEN title ELSE '' END DESC, LEN(body) ASC"
132
+ post1 = Post.create title: 'ZZZ Post', body: 'Z'
133
+ post2 = Post.create title: 'ZZZ Post', body: 'Test cased orders.'
134
+ assert_equal post1, Post.order(order).first
135
+ assert_equal post2, Post.order(order).second
136
+ end
137
+
138
+ it 'support primary: inline function, secondary: case expression' do
139
+ order = "LEN(body), CASE WHEN [title] LIKE N'ZZZ%' THEN title ELSE '' END DESC"
140
+ post1 = Post.create title: 'ZZZ Post', body: 'Z'
141
+ post2 = Post.create title: 'Post', body: 'Z'
142
+ assert_equal post1, Post.order(order).first
143
+ assert_equal post2, Post.order(order).second
144
+ end
145
+
146
+
147
+ end