activerecord-sqlserver-adapter-odbc-extended 8.0.10
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.
- checksums.yaml +7 -0
- data/.github/issue_template.md +22 -0
- data/.github/workflows/ci.yml +32 -0
- data/.gitignore +9 -0
- data/.rubocop.yml +69 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/Dockerfile.ci +14 -0
- data/Gemfile +26 -0
- data/LICENSE.txt +21 -0
- data/README.md +104 -0
- data/RUNNING_UNIT_TESTS.md +38 -0
- data/Rakefile +45 -0
- data/VERSION +1 -0
- data/activerecord-sqlserver-adapter-odbc-extended.gemspec +34 -0
- data/compose.ci.yaml +15 -0
- data/lib/active_record/connection_adapters/extended_sqlserver_adapter.rb +204 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/odbc.rb +41 -0
- data/lib/active_record/connection_adapters/sqlserver/odbc_database_statements.rb +234 -0
- data/lib/active_record/connection_adapters/sqlserver/type/binary_ext.rb +25 -0
- data/lib/activerecord-sqlserver-adapter-odbc-extended.rb +12 -0
- data/test/appveyor/dbsetup.ps1 +27 -0
- data/test/appveyor/dbsetup.sql +11 -0
- data/test/cases/active_schema_test_sqlserver.rb +127 -0
- data/test/cases/adapter_test_sqlserver.rb +648 -0
- data/test/cases/change_column_collation_test_sqlserver.rb +33 -0
- data/test/cases/change_column_null_test_sqlserver.rb +44 -0
- data/test/cases/coerced_tests.rb +2796 -0
- data/test/cases/column_test_sqlserver.rb +848 -0
- data/test/cases/connection_test_sqlserver.rb +138 -0
- data/test/cases/dbconsole.rb +19 -0
- data/test/cases/disconnected_test_sqlserver.rb +42 -0
- data/test/cases/eager_load_too_many_ids_test_sqlserver.rb +18 -0
- data/test/cases/enum_test_sqlserver.rb +49 -0
- data/test/cases/execute_procedure_test_sqlserver.rb +57 -0
- data/test/cases/fetch_test_sqlserver.rb +88 -0
- data/test/cases/fully_qualified_identifier_test_sqlserver.rb +72 -0
- data/test/cases/helper_sqlserver.rb +61 -0
- data/test/cases/migration_test_sqlserver.rb +144 -0
- data/test/cases/order_test_sqlserver.rb +153 -0
- data/test/cases/pessimistic_locking_test_sqlserver.rb +102 -0
- data/test/cases/primary_keys_test_sqlserver.rb +103 -0
- data/test/cases/rake_test_sqlserver.rb +198 -0
- data/test/cases/schema_dumper_test_sqlserver.rb +296 -0
- data/test/cases/schema_test_sqlserver.rb +111 -0
- data/test/cases/trigger_test_sqlserver.rb +51 -0
- data/test/cases/utils_test_sqlserver.rb +129 -0
- data/test/cases/uuid_test_sqlserver.rb +54 -0
- data/test/cases/view_test_sqlserver.rb +58 -0
- data/test/config.yml +38 -0
- data/test/debug.rb +16 -0
- data/test/fixtures/1px.gif +0 -0
- data/test/migrations/create_clients_and_change_column_collation.rb +19 -0
- data/test/migrations/create_clients_and_change_column_null.rb +25 -0
- data/test/migrations/transaction_table/1_table_will_never_be_created.rb +11 -0
- data/test/models/sqlserver/alien.rb +5 -0
- data/test/models/sqlserver/booking.rb +5 -0
- data/test/models/sqlserver/composite_pk.rb +9 -0
- data/test/models/sqlserver/customers_view.rb +5 -0
- data/test/models/sqlserver/datatype.rb +5 -0
- data/test/models/sqlserver/datatype_migration.rb +10 -0
- data/test/models/sqlserver/dollar_table_name.rb +5 -0
- data/test/models/sqlserver/edge_schema.rb +13 -0
- data/test/models/sqlserver/fk_has_fk.rb +5 -0
- data/test/models/sqlserver/fk_has_pk.rb +5 -0
- data/test/models/sqlserver/natural_pk_data.rb +6 -0
- data/test/models/sqlserver/natural_pk_int_data.rb +5 -0
- data/test/models/sqlserver/no_pk_data.rb +5 -0
- data/test/models/sqlserver/object_default.rb +5 -0
- data/test/models/sqlserver/quoted_table.rb +9 -0
- data/test/models/sqlserver/quoted_view_1.rb +5 -0
- data/test/models/sqlserver/quoted_view_2.rb +5 -0
- data/test/models/sqlserver/sst_memory.rb +5 -0
- data/test/models/sqlserver/sst_string_collation.rb +3 -0
- data/test/models/sqlserver/string_default.rb +5 -0
- data/test/models/sqlserver/string_defaults_big_view.rb +5 -0
- data/test/models/sqlserver/string_defaults_view.rb +5 -0
- data/test/models/sqlserver/table_with_spaces.rb +5 -0
- data/test/models/sqlserver/tinyint_pk.rb +5 -0
- data/test/models/sqlserver/trigger.rb +17 -0
- data/test/models/sqlserver/trigger_history.rb +5 -0
- data/test/models/sqlserver/upper.rb +5 -0
- data/test/models/sqlserver/uppered.rb +5 -0
- data/test/models/sqlserver/uuid.rb +5 -0
- data/test/schema/datatypes/2012.sql +56 -0
- data/test/schema/enable-in-memory-oltp.sql +81 -0
- data/test/schema/sqlserver_specific_schema.rb +363 -0
- data/test/support/coerceable_test_sqlserver.rb +55 -0
- data/test/support/connection_reflection.rb +32 -0
- data/test/support/core_ext/query_cache.rb +38 -0
- data/test/support/load_schema_sqlserver.rb +29 -0
- data/test/support/marshal_compatibility_fixtures/SQLServer/rails_6_1_topic.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/SQLServer/rails_6_1_topic_associations.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/SQLServer/rails_7_1_topic.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/SQLServer/rails_7_1_topic_associations.dump +0 -0
- data/test/support/minitest_sqlserver.rb +3 -0
- data/test/support/paths_sqlserver.rb +50 -0
- data/test/support/query_assertions.rb +49 -0
- data/test/support/rake_helpers.rb +46 -0
- data/test/support/table_definition_sqlserver.rb +24 -0
- data/test/support/test_in_memory_oltp.rb +17 -0
- metadata +240 -0
|
@@ -0,0 +1,648 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "cases/helper_sqlserver"
|
|
4
|
+
require "models/topic"
|
|
5
|
+
require "models/task"
|
|
6
|
+
require "models/post"
|
|
7
|
+
require "models/subscriber"
|
|
8
|
+
require "models/minimalistic"
|
|
9
|
+
require "models/college"
|
|
10
|
+
require "models/discount"
|
|
11
|
+
|
|
12
|
+
class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
13
|
+
fixtures :tasks
|
|
14
|
+
|
|
15
|
+
let(:basic_insert_sql) { "INSERT INTO [funny_jokes] ([name]) VALUES('Knock knock')" }
|
|
16
|
+
let(:basic_update_sql) { "UPDATE [customers] SET [address_street] = NULL WHERE [id] = 2" }
|
|
17
|
+
let(:basic_select_sql) { "SELECT * FROM [customers] WHERE ([customers].[id] = 1)" }
|
|
18
|
+
|
|
19
|
+
it "has basic and non-sensitive information in the adapters inspect method" do
|
|
20
|
+
string = connection.inspect
|
|
21
|
+
_(string).must_match %r{ActiveRecord::ConnectionAdapters::SQLServerAdapter}
|
|
22
|
+
_(string).must_match %r{mode: (dblib|odbc)}
|
|
23
|
+
_(string).wont_match %r{host}
|
|
24
|
+
_(string).wont_match %r{password}
|
|
25
|
+
_(string).wont_match %r{username}
|
|
26
|
+
_(string).wont_match %r{port}
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "has a 128 max #table_alias_length" do
|
|
30
|
+
assert connection.table_alias_length <= 128
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "raises invalid statement error for bad SQL" do
|
|
34
|
+
assert_raise(ActiveRecord::StatementInvalid) { Topic.lease_connection.update("UPDATE XXX") }
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "is has our adapter_name" do
|
|
38
|
+
assert_equal "SQLServer", connection.adapter_name
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "support DDL in transactions" do
|
|
42
|
+
assert connection.supports_ddl_transactions?
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "table exists works if table name prefixed by schema and owner" do
|
|
46
|
+
begin
|
|
47
|
+
assert_equal "topics", Topic.table_name
|
|
48
|
+
assert Topic.table_exists?
|
|
49
|
+
|
|
50
|
+
# Test when owner included in table name.
|
|
51
|
+
Topic.table_name = "dbo.topics"
|
|
52
|
+
assert Topic.table_exists?, "Topics table name of 'dbo.topics' should return true for exists."
|
|
53
|
+
|
|
54
|
+
# Test when database and owner included in table name.
|
|
55
|
+
db_config = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", name: "primary")
|
|
56
|
+
Topic.table_name = "#{db_config.database}.dbo.topics"
|
|
57
|
+
assert Topic.table_exists?, "Topics table name of '[DATABASE].dbo.topics' should return true for exists."
|
|
58
|
+
ensure
|
|
59
|
+
Topic.table_name = "topics"
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it "test table existence across database schemas" do
|
|
64
|
+
arunit_connection = Topic.lease_connection
|
|
65
|
+
arunit2_connection = College.lease_connection
|
|
66
|
+
|
|
67
|
+
arunit_database = arunit_connection.pool.db_config.database
|
|
68
|
+
arunit2_database = arunit2_connection.pool.db_config.database
|
|
69
|
+
|
|
70
|
+
# Assert that connections use different default databases schemas.
|
|
71
|
+
assert_not_equal arunit_database, arunit2_database
|
|
72
|
+
|
|
73
|
+
# Assert that the Topics table exists when using the Topics connection.
|
|
74
|
+
assert arunit_connection.table_exists?('topics'), 'Topics table exists using table name'
|
|
75
|
+
assert arunit_connection.table_exists?('dbo.topics'), 'Topics table exists using owner and table name'
|
|
76
|
+
assert arunit_connection.table_exists?("#{arunit_database}.dbo.topics"), 'Topics table exists using database, owner and table name'
|
|
77
|
+
|
|
78
|
+
# Assert that the Colleges table exists when using the Colleges connection.
|
|
79
|
+
assert arunit2_connection.table_exists?('colleges'), 'College table exists using table name'
|
|
80
|
+
assert arunit2_connection.table_exists?('dbo.colleges'), 'College table exists using owner and table name'
|
|
81
|
+
assert arunit2_connection.table_exists?("#{arunit2_database}.dbo.colleges"), 'College table exists using database, owner and table name'
|
|
82
|
+
|
|
83
|
+
# Assert that the tables exist when using each others connection.
|
|
84
|
+
assert arunit_connection.table_exists?("#{arunit2_database}.dbo.colleges"), 'Colleges table exists using Topics connection'
|
|
85
|
+
assert arunit2_connection.table_exists?("#{arunit_database}.dbo.topics"), 'Topics table exists using Colleges connection'
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
it "return true to insert sql query for inserts only" do
|
|
89
|
+
assert connection.send(:insert_sql?, "INSERT...")
|
|
90
|
+
assert connection.send(:insert_sql?, "EXEC sp_executesql N'INSERT INTO [fk_test_has_fks] ([fk_id]) VALUES (@0); SELECT CAST(SCOPE_IDENTITY() AS bigint) AS Ident', N'@0 int', @0 = 0")
|
|
91
|
+
assert !connection.send(:insert_sql?, "UPDATE...")
|
|
92
|
+
assert !connection.send(:insert_sql?, "SELECT...")
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
it "return unquoted table name object from basic INSERT UPDATE and SELECT statements" do
|
|
96
|
+
assert_equal "funny_jokes", connection.send(:get_table_name, basic_insert_sql)
|
|
97
|
+
assert_equal "customers", connection.send(:get_table_name, basic_update_sql)
|
|
98
|
+
assert_equal "customers", connection.send(:get_table_name, basic_select_sql)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
it "test bad connection" do
|
|
102
|
+
assert_raise ActiveRecord::NoDatabaseError do
|
|
103
|
+
db_config = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", name: "primary")
|
|
104
|
+
configuration = db_config.configuration_hash.merge(database: "nonexistent_activerecord_unittest")
|
|
105
|
+
connection = ActiveRecord::ConnectionAdapters::SQLServerAdapter.new(configuration)
|
|
106
|
+
connection.exec_query("SELECT 1")
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
it "test database exists returns false if database does not exist" do
|
|
111
|
+
db_config = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", name: "primary")
|
|
112
|
+
configuration = db_config.configuration_hash.merge(database: "nonexistent_activerecord_unittest")
|
|
113
|
+
assert_not ActiveRecord::ConnectionAdapters::SQLServerAdapter.database_exists?(configuration),
|
|
114
|
+
"expected database #{configuration[:database]} to not exist"
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
it "test database exists returns true when the database exists" do
|
|
118
|
+
db_config = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", name: "primary")
|
|
119
|
+
assert ActiveRecord::ConnectionAdapters::SQLServerAdapter.database_exists?(db_config.configuration_hash),
|
|
120
|
+
"expected database #{db_config.database} to exist"
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
it "test primary key violation" do
|
|
124
|
+
Post.create!(id: 0, title: 'Setup', body: 'Create post with primary key of zero')
|
|
125
|
+
|
|
126
|
+
assert_raise ActiveRecord::RecordNotUnique do
|
|
127
|
+
Post.create!(id: 0, title: 'Test', body: 'Try to create another post with primary key of zero')
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
describe "with different language" do
|
|
132
|
+
before do
|
|
133
|
+
@default_language = connection.user_options_language
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
after do
|
|
137
|
+
connection.execute("SET LANGUAGE #{@default_language}") rescue nil
|
|
138
|
+
connection.send :initialize_dateformatter
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
it "memos users dateformat" do
|
|
142
|
+
connection.execute("SET LANGUAGE us_english") rescue nil
|
|
143
|
+
dateformat = connection.instance_variable_get(:@database_dateformat)
|
|
144
|
+
assert_equal "mdy", dateformat
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
it "has a dateformatter" do
|
|
148
|
+
assert Date::DATE_FORMATS[:_sqlserver_dateformat]
|
|
149
|
+
assert Time::DATE_FORMATS[:_sqlserver_dateformat]
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
it "does a datetime insertion when language is german" do
|
|
153
|
+
connection.execute("SET LANGUAGE deutsch")
|
|
154
|
+
connection.send :initialize_dateformatter
|
|
155
|
+
assert_nothing_raised do
|
|
156
|
+
starting = Time.utc(2000, 1, 31, 5, 42, 0)
|
|
157
|
+
ending = Time.new(2006, 12, 31)
|
|
158
|
+
Task.create! starting: starting, ending: ending
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
describe "testing #lowercase_schema_reflection" do
|
|
164
|
+
before do
|
|
165
|
+
SSTestUpper.delete_all
|
|
166
|
+
SSTestUpper.create COLUMN1: "Got a minute?", COLUMN2: 419
|
|
167
|
+
SSTestUpper.create COLUMN1: "Favorite number?", COLUMN2: 69
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
after do
|
|
171
|
+
connection.lowercase_schema_reflection = false
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
it "not lowercase schema reflection by default" do
|
|
175
|
+
assert SSTestUpper.columns_hash["COLUMN1"]
|
|
176
|
+
assert_equal "Got a minute?", SSTestUpper.first.COLUMN1
|
|
177
|
+
assert_equal "Favorite number?", SSTestUpper.last.COLUMN1
|
|
178
|
+
assert SSTestUpper.columns_hash["COLUMN2"]
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
it "lowercase schema reflection when set" do
|
|
182
|
+
connection.lowercase_schema_reflection = true
|
|
183
|
+
assert SSTestUppered.columns_hash["column1"]
|
|
184
|
+
assert_equal "Got a minute?", SSTestUppered.first.column1
|
|
185
|
+
assert_equal "Favorite number?", SSTestUppered.last.column1
|
|
186
|
+
assert SSTestUppered.columns_hash["column2"]
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
it "destroys model with no associations" do
|
|
190
|
+
connection.lowercase_schema_reflection = true
|
|
191
|
+
|
|
192
|
+
assert_nothing_raised do
|
|
193
|
+
discount = Discount.create!
|
|
194
|
+
discount.destroy!
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
it "destroys model with association" do
|
|
199
|
+
connection.lowercase_schema_reflection = true
|
|
200
|
+
|
|
201
|
+
assert_nothing_raised do
|
|
202
|
+
post = Post.create!(title: 'Setup', body: 'Record to be deleted')
|
|
203
|
+
post.destroy!
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
describe "identity inserts" do
|
|
209
|
+
before do
|
|
210
|
+
@identity_insert_sql = "INSERT INTO [funny_jokes] ([id],[name]) VALUES(420,'Knock knock')"
|
|
211
|
+
@identity_insert_sql_unquoted = "INSERT INTO funny_jokes (id, name) VALUES(420, 'Knock knock')"
|
|
212
|
+
@identity_insert_sql_unordered = "INSERT INTO [funny_jokes] ([name],[id]) VALUES('Knock knock',420)"
|
|
213
|
+
@identity_insert_sql_sp = "EXEC sp_executesql N'INSERT INTO [funny_jokes] ([id],[name]) VALUES (@0, @1)', N'@0 int, @1 nvarchar(255)', @0 = 420, @1 = N'Knock knock'"
|
|
214
|
+
@identity_insert_sql_unquoted_sp = "EXEC sp_executesql N'INSERT INTO funny_jokes (id, name) VALUES (@0, @1)', N'@0 int, @1 nvarchar(255)', @0 = 420, @1 = N'Knock knock'"
|
|
215
|
+
@identity_insert_sql_unordered_sp = "EXEC sp_executesql N'INSERT INTO [funny_jokes] ([name],[id]) VALUES (@0, @1)', N'@0 nvarchar(255), @1 int', @0 = N'Knock knock', @1 = 420"
|
|
216
|
+
|
|
217
|
+
@identity_insert_sql_non_dbo = "INSERT INTO [test].[aliens] ([id],[name]) VALUES(420,'Mork')"
|
|
218
|
+
@identity_insert_sql_non_dbo_unquoted = "INSERT INTO test.aliens ([id],[name]) VALUES(420,'Mork')"
|
|
219
|
+
@identity_insert_sql_non_dbo_unordered = "INSERT INTO [test].[aliens] ([name],[id]) VALUES('Mork',420)"
|
|
220
|
+
@identity_insert_sql_non_dbo_sp = "EXEC sp_executesql N'INSERT INTO [test].[aliens] ([id],[name]) VALUES (@0, @1)', N'@0 int, @1 nvarchar(255)', @0 = 420, @1 = N'Mork'"
|
|
221
|
+
@identity_insert_sql_non_dbo_unquoted_sp = "EXEC sp_executesql N'INSERT INTO test.aliens (id, name) VALUES (@0, @1)', N'@0 int, @1 nvarchar(255)', @0 = 420, @1 = N'Mork'"
|
|
222
|
+
@identity_insert_sql_non_dbo_unordered_sp = "EXEC sp_executesql N'INSERT INTO [test].[aliens] ([name],[id]) VALUES (@0, @1)', N'@0 nvarchar(255), @1 int', @0 = N'Mork', @1 = 420"
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
it "return quoted table_name to #query_requires_identity_insert? when INSERT sql contains id column" do
|
|
226
|
+
assert_equal "[funny_jokes]", connection.send(:query_requires_identity_insert?, @identity_insert_sql)
|
|
227
|
+
assert_equal "[funny_jokes]", connection.send(:query_requires_identity_insert?, @identity_insert_sql_unquoted)
|
|
228
|
+
assert_equal "[funny_jokes]", connection.send(:query_requires_identity_insert?, @identity_insert_sql_unordered)
|
|
229
|
+
assert_equal "[funny_jokes]", connection.send(:query_requires_identity_insert?, @identity_insert_sql_sp)
|
|
230
|
+
assert_equal "[funny_jokes]", connection.send(:query_requires_identity_insert?, @identity_insert_sql_unquoted_sp)
|
|
231
|
+
assert_equal "[funny_jokes]", connection.send(:query_requires_identity_insert?, @identity_insert_sql_unordered_sp)
|
|
232
|
+
|
|
233
|
+
assert_equal "[test].[aliens]", connection.send(:query_requires_identity_insert?, @identity_insert_sql_non_dbo)
|
|
234
|
+
assert_equal "[test].[aliens]", connection.send(:query_requires_identity_insert?, @identity_insert_sql_non_dbo_unquoted)
|
|
235
|
+
assert_equal "[test].[aliens]", connection.send(:query_requires_identity_insert?, @identity_insert_sql_non_dbo_unordered)
|
|
236
|
+
assert_equal "[test].[aliens]", connection.send(:query_requires_identity_insert?, @identity_insert_sql_non_dbo_sp)
|
|
237
|
+
assert_equal "[test].[aliens]", connection.send(:query_requires_identity_insert?, @identity_insert_sql_non_dbo_unquoted_sp)
|
|
238
|
+
assert_equal "[test].[aliens]", connection.send(:query_requires_identity_insert?, @identity_insert_sql_non_dbo_unordered_sp)
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
it "return false to #query_requires_identity_insert? for normal SQL" do
|
|
242
|
+
[basic_insert_sql, basic_update_sql, basic_select_sql].each do |sql|
|
|
243
|
+
assert !connection.send(:query_requires_identity_insert?, sql), "SQL was #{sql}"
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
it "find identity column using #identity_columns" do
|
|
248
|
+
task_id_column = Task.columns_hash["id"]
|
|
249
|
+
assert_equal task_id_column.name, connection.send(:identity_columns, Task.table_name).first.name
|
|
250
|
+
assert_equal task_id_column.sql_type, connection.send(:identity_columns, Task.table_name).first.sql_type
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
it "return an empty array when calling #identity_columns for a table_name with no identity" do
|
|
254
|
+
_(connection.send(:identity_columns, Subscriber.table_name)).must_equal []
|
|
255
|
+
end
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
describe "quoting" do
|
|
259
|
+
it "return 1 for #quoted_true" do
|
|
260
|
+
assert_equal "1", connection.quoted_true
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
it "return 0 for #quoted_false" do
|
|
264
|
+
assert_equal "0", connection.quoted_false
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
it "not escape backslash characters like abstract adapter" do
|
|
268
|
+
string_with_backslashs = "\\n"
|
|
269
|
+
assert_equal string_with_backslashs, connection.quote_string(string_with_backslashs)
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
it "quote column names with brackets" do
|
|
273
|
+
assert_equal "[foo]", connection.quote_column_name(:foo)
|
|
274
|
+
assert_equal "[foo]", connection.quote_column_name("foo")
|
|
275
|
+
assert_equal "[foo].[bar]", connection.quote_column_name("foo.bar")
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
it "not quote already quoted column names with brackets" do
|
|
279
|
+
assert_equal "[foo]", connection.quote_column_name("[foo]")
|
|
280
|
+
assert_equal "[foo].[bar]", connection.quote_column_name("[foo].[bar]")
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
it "quote table names like columns" do
|
|
284
|
+
assert_equal "[foo].[bar]", connection.quote_column_name("foo.bar")
|
|
285
|
+
assert_equal "[foo].[bar].[baz]", connection.quote_column_name("foo.bar.baz")
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
it "surround string with national prefix" do
|
|
289
|
+
assert_equal "N'foo'", connection.quote("foo")
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
it "escape all single quotes by repeating them" do
|
|
293
|
+
assert_equal "N'''quotation''s'''", connection.quote("'quotation's'")
|
|
294
|
+
end
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
describe "disabling referential integrity" do
|
|
298
|
+
before do
|
|
299
|
+
connection.disable_referential_integrity { SSTestHasPk.delete_all; SSTestHasFk.delete_all }
|
|
300
|
+
@parent = SSTestHasPk.create!
|
|
301
|
+
@member = SSTestHasFk.create!(fk_id: @parent.id)
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
it "NOT ALLOW by default the deletion of a referenced parent" do
|
|
305
|
+
SSTestHasPk.lease_connection.disable_referential_integrity {}
|
|
306
|
+
assert_raise(ActiveRecord::StatementInvalid) { @parent.destroy }
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
it "ALLOW deletion of referenced parent using #disable_referential_integrity block" do
|
|
310
|
+
assert_difference("SSTestHasPk.count", -1) do
|
|
311
|
+
SSTestHasPk.lease_connection.disable_referential_integrity { @parent.destroy }
|
|
312
|
+
end
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
it "again NOT ALLOW deletion of referenced parent after #disable_referential_integrity block" do
|
|
316
|
+
assert_raise(ActiveRecord::StatementInvalid) do
|
|
317
|
+
SSTestHasPk.lease_connection.disable_referential_integrity {}
|
|
318
|
+
@parent.destroy
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
it "not disable referential integrity for the same table twice" do
|
|
323
|
+
tables = SSTestHasPk.lease_connection.tables_with_referential_integrity
|
|
324
|
+
assert_equal tables.size, tables.uniq.size
|
|
325
|
+
end
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
describe "database statements" do
|
|
329
|
+
it "run the database consistency checker 'user_options' command" do
|
|
330
|
+
skip "on azure" if connection_sqlserver_azure?
|
|
331
|
+
keys = [:textsize, :language, :isolation_level, :dateformat]
|
|
332
|
+
user_options = connection.user_options
|
|
333
|
+
keys.each do |key|
|
|
334
|
+
msg = "Expected key:#{key} in user_options:#{user_options.inspect}"
|
|
335
|
+
assert user_options.key?(key), msg
|
|
336
|
+
end
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
it "return a underscored key hash with indifferent access of the results" do
|
|
340
|
+
skip "on azure" if connection_sqlserver_azure?
|
|
341
|
+
user_options = connection.user_options
|
|
342
|
+
assert_equal "read committed", user_options["isolation_level"]
|
|
343
|
+
assert_equal "read committed", user_options[:isolation_level]
|
|
344
|
+
end
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
describe "schema statements" do
|
|
348
|
+
it "create integers when no limit supplied" do
|
|
349
|
+
assert_equal "integer", connection.type_to_sql(:integer)
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
it "create integers when limit is 4" do
|
|
353
|
+
assert_equal "integer", connection.type_to_sql(:integer, limit: 4)
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
it "create integers when limit is 3" do
|
|
357
|
+
assert_equal "integer", connection.type_to_sql(:integer, limit: 3)
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
it "create smallints when limit is 2" do
|
|
361
|
+
assert_equal "smallint", connection.type_to_sql(:integer, limit: 2)
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
it "create tinyints when limit is 1" do
|
|
365
|
+
assert_equal "tinyint", connection.type_to_sql(:integer, limit: 1)
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
it "create bigints when limit is greater than 4" do
|
|
369
|
+
assert_equal "bigint", connection.type_to_sql(:integer, limit: 5)
|
|
370
|
+
assert_equal "bigint", connection.type_to_sql(:integer, limit: 6)
|
|
371
|
+
assert_equal "bigint", connection.type_to_sql(:integer, limit: 7)
|
|
372
|
+
assert_equal "bigint", connection.type_to_sql(:integer, limit: 8)
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
it "create floats when no limit supplied" do
|
|
376
|
+
assert_equal "float", connection.type_to_sql(:float)
|
|
377
|
+
end
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
describe "views" do
|
|
381
|
+
# Using connection.views
|
|
382
|
+
|
|
383
|
+
it "return an array" do
|
|
384
|
+
assert_instance_of Array, connection.views
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
it "find SSTestCustomersView table name" do
|
|
388
|
+
_(connection.views).must_include "sst_customers_view"
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
it "work with dynamic finders" do
|
|
392
|
+
name = "MetaSkills"
|
|
393
|
+
customer = SSTestCustomersView.create! name: name
|
|
394
|
+
assert_equal customer, SSTestCustomersView.find_by_name(name)
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
it "not contain system views" do
|
|
398
|
+
systables = ["sysconstraints", "syssegments"]
|
|
399
|
+
systables.each do |systable|
|
|
400
|
+
assert !connection.views.include?(systable), "This systable #{systable} should not be in the views array."
|
|
401
|
+
end
|
|
402
|
+
end
|
|
403
|
+
|
|
404
|
+
it "allow the connection#view_information method to return meta data on the view" do
|
|
405
|
+
view_info = connection.send(:view_information, "sst_customers_view")
|
|
406
|
+
assert_equal("sst_customers_view", view_info["TABLE_NAME"])
|
|
407
|
+
assert_match(/CREATE VIEW sst_customers_view/, view_info["VIEW_DEFINITION"])
|
|
408
|
+
end
|
|
409
|
+
|
|
410
|
+
it "allows connection#view_information to work with qualified object names" do
|
|
411
|
+
view_info = connection.send(:view_information, "[activerecord_unittest].[dbo].[sst_customers_view]")
|
|
412
|
+
assert_equal("sst_customers_view", view_info["TABLE_NAME"])
|
|
413
|
+
assert_match(/CREATE VIEW sst_customers_view/, view_info["VIEW_DEFINITION"])
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
it "allows connection#view_information to work across databases when using qualified object names" do
|
|
417
|
+
# College is defined in activerecord_unittest2 database.
|
|
418
|
+
view_info = College.lease_connection.send(:view_information, "[activerecord_unittest].[dbo].[sst_customers_view]")
|
|
419
|
+
assert_equal("sst_customers_view", view_info["TABLE_NAME"])
|
|
420
|
+
assert_match(/CREATE VIEW sst_customers_view/, view_info["VIEW_DEFINITION"])
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
it "allow the connection#view_table_name method to return true table_name for the view" do
|
|
424
|
+
assert_equal "customers", connection.send(:view_table_name, "sst_customers_view")
|
|
425
|
+
assert_equal "topics", connection.send(:view_table_name, "topics"), "No view here, the same table name should come back."
|
|
426
|
+
end
|
|
427
|
+
|
|
428
|
+
it "allow the connection#view_table_name method to return true table_name for the view for other connections" do
|
|
429
|
+
assert_equal "customers", College.lease_connection.send(:view_table_name, "[activerecord_unittest].[dbo].[sst_customers_view]")
|
|
430
|
+
assert_equal "topics", College.lease_connection.send(:view_table_name, "topics"), "No view here, the same table name should come back."
|
|
431
|
+
end
|
|
432
|
+
# With same column names
|
|
433
|
+
|
|
434
|
+
it "have matching column objects" do
|
|
435
|
+
columns = ["id", "name", "balance"]
|
|
436
|
+
assert !SSTestCustomersView.columns.blank?
|
|
437
|
+
assert_equal columns.size, SSTestCustomersView.columns.size
|
|
438
|
+
columns.each do |colname|
|
|
439
|
+
assert_instance_of ActiveRecord::ConnectionAdapters::SQLServer::Column,
|
|
440
|
+
SSTestCustomersView.columns_hash[colname],
|
|
441
|
+
"Column name #{colname.inspect} was not found in these columns #{SSTestCustomersView.columns.map(&:name).inspect}"
|
|
442
|
+
end
|
|
443
|
+
end
|
|
444
|
+
|
|
445
|
+
it "find identity column" do
|
|
446
|
+
_(SSTestCustomersView.primary_key).must_equal "id"
|
|
447
|
+
_(connection.primary_key(SSTestCustomersView.table_name)).must_equal "id"
|
|
448
|
+
_(SSTestCustomersView.columns_hash["id"]).must_be :is_identity?
|
|
449
|
+
end
|
|
450
|
+
|
|
451
|
+
it "find default values" do
|
|
452
|
+
assert_equal 0, SSTestCustomersView.new.balance
|
|
453
|
+
end
|
|
454
|
+
|
|
455
|
+
it "respond true to data_source_exists?" do
|
|
456
|
+
assert SSTestCustomersView.lease_connection.data_source_exists?(SSTestCustomersView.table_name)
|
|
457
|
+
end
|
|
458
|
+
|
|
459
|
+
# With aliased column names
|
|
460
|
+
|
|
461
|
+
it "have matching column objects" do
|
|
462
|
+
columns = ["id", "pretend_null"]
|
|
463
|
+
assert !SSTestStringDefaultsView.columns.blank?
|
|
464
|
+
assert_equal columns.size, SSTestStringDefaultsView.columns.size
|
|
465
|
+
columns.each do |colname|
|
|
466
|
+
assert_instance_of ActiveRecord::ConnectionAdapters::SQLServer::Column,
|
|
467
|
+
SSTestStringDefaultsView.columns_hash[colname],
|
|
468
|
+
"Column name #{colname.inspect} was not found in these columns #{SSTestStringDefaultsView.columns.map(&:name).inspect}"
|
|
469
|
+
end
|
|
470
|
+
end
|
|
471
|
+
|
|
472
|
+
it "find identity column" do
|
|
473
|
+
_(SSTestStringDefaultsView.primary_key).must_equal "id"
|
|
474
|
+
_(connection.primary_key(SSTestStringDefaultsView.table_name)).must_equal "id"
|
|
475
|
+
_(SSTestStringDefaultsView.columns_hash["id"]).must_be :is_identity?
|
|
476
|
+
end
|
|
477
|
+
|
|
478
|
+
it "find default values" do
|
|
479
|
+
assert_equal "null", SSTestStringDefaultsView.new.pretend_null,
|
|
480
|
+
SSTestStringDefaultsView.columns_hash["pretend_null"].inspect
|
|
481
|
+
end
|
|
482
|
+
|
|
483
|
+
it "respond true to data_source_exists?" do
|
|
484
|
+
assert SSTestStringDefaultsView.lease_connection.data_source_exists?(SSTestStringDefaultsView.table_name)
|
|
485
|
+
end
|
|
486
|
+
|
|
487
|
+
# That have more than 4000 chars for their definition
|
|
488
|
+
|
|
489
|
+
it "cope with null returned for the definition" do
|
|
490
|
+
assert_nothing_raised() { SSTestStringDefaultsBigView.columns }
|
|
491
|
+
end
|
|
492
|
+
|
|
493
|
+
it "using alternate view definition still be able to find real default" do
|
|
494
|
+
assert_equal "null", SSTestStringDefaultsBigView.new.pretend_null,
|
|
495
|
+
SSTestStringDefaultsBigView.columns_hash["pretend_null"].inspect
|
|
496
|
+
end
|
|
497
|
+
end
|
|
498
|
+
|
|
499
|
+
describe "database_prefix_remote_server?" do
|
|
500
|
+
after do
|
|
501
|
+
connection_options.delete(:database_prefix)
|
|
502
|
+
end
|
|
503
|
+
|
|
504
|
+
it "returns false if database_prefix is not configured" do
|
|
505
|
+
assert_equal false, connection.database_prefix_remote_server?
|
|
506
|
+
end
|
|
507
|
+
|
|
508
|
+
it "returns true if database_prefix has been set" do
|
|
509
|
+
connection_options[:database_prefix] = "server.database.schema."
|
|
510
|
+
assert_equal true, connection.database_prefix_remote_server?
|
|
511
|
+
end
|
|
512
|
+
|
|
513
|
+
it "returns false if database_prefix has been set incorrectly" do
|
|
514
|
+
connection_options[:database_prefix] = "server.database.schema"
|
|
515
|
+
assert_equal false, connection.database_prefix_remote_server?
|
|
516
|
+
end
|
|
517
|
+
end
|
|
518
|
+
|
|
519
|
+
it "in_memory_oltp" do
|
|
520
|
+
if ENV["IN_MEMORY_OLTP"] && connection.supports_in_memory_oltp?
|
|
521
|
+
_(SSTMemory.primary_key).must_equal "id"
|
|
522
|
+
_(SSTMemory.columns_hash["id"]).must_be :is_identity?
|
|
523
|
+
else
|
|
524
|
+
skip "supports_in_memory_oltp? => false"
|
|
525
|
+
end
|
|
526
|
+
end
|
|
527
|
+
|
|
528
|
+
describe "block writes to a database" do
|
|
529
|
+
def setup
|
|
530
|
+
@conn = ActiveRecord::Base.lease_connection
|
|
531
|
+
end
|
|
532
|
+
|
|
533
|
+
def test_errors_when_an_insert_query_is_called_while_preventing_writes
|
|
534
|
+
assert_raises(ActiveRecord::ReadOnlyError) do
|
|
535
|
+
ActiveRecord::Base.while_preventing_writes do
|
|
536
|
+
@conn.insert("INSERT INTO [subscribers] ([nick]) VALUES ('aido')")
|
|
537
|
+
end
|
|
538
|
+
end
|
|
539
|
+
end
|
|
540
|
+
|
|
541
|
+
def test_errors_when_an_update_query_is_called_while_preventing_writes
|
|
542
|
+
@conn.insert("INSERT INTO [subscribers] ([nick]) VALUES ('aido')")
|
|
543
|
+
|
|
544
|
+
assert_raises(ActiveRecord::ReadOnlyError) do
|
|
545
|
+
ActiveRecord::Base.while_preventing_writes do
|
|
546
|
+
@conn.update("UPDATE [subscribers] SET [subscribers].[name] = 'Aidan' WHERE [subscribers].[nick] = 'aido'")
|
|
547
|
+
end
|
|
548
|
+
end
|
|
549
|
+
end
|
|
550
|
+
|
|
551
|
+
def test_errors_when_a_delete_query_is_called_while_preventing_writes
|
|
552
|
+
@conn.execute("INSERT INTO [subscribers] ([nick]) VALUES ('aido')")
|
|
553
|
+
|
|
554
|
+
assert_raises(ActiveRecord::ReadOnlyError) do
|
|
555
|
+
ActiveRecord::Base.while_preventing_writes do
|
|
556
|
+
@conn.execute("DELETE FROM [subscribers] WHERE [subscribers].[nick] = 'aido'")
|
|
557
|
+
end
|
|
558
|
+
end
|
|
559
|
+
end
|
|
560
|
+
|
|
561
|
+
def test_doesnt_error_when_a_select_query_is_called_while_preventing_writes
|
|
562
|
+
@conn.execute("INSERT INTO [subscribers] ([nick]) VALUES ('aido')")
|
|
563
|
+
|
|
564
|
+
ActiveRecord::Base.while_preventing_writes do
|
|
565
|
+
assert_equal 1, @conn.execute("SELECT * FROM [subscribers] WHERE [subscribers].[nick] = 'aido'").count
|
|
566
|
+
end
|
|
567
|
+
end
|
|
568
|
+
end
|
|
569
|
+
|
|
570
|
+
describe 'table is in non-dbo schema' do
|
|
571
|
+
it "records can be created successfully" do
|
|
572
|
+
assert_difference("Alien.count", 1) do
|
|
573
|
+
Alien.create!(name: 'Trisolarans')
|
|
574
|
+
end
|
|
575
|
+
end
|
|
576
|
+
|
|
577
|
+
it 'records can be inserted using SQL' do
|
|
578
|
+
assert_difference("Alien.count", 2) do
|
|
579
|
+
Alien.lease_connection.exec_insert("insert into [test].[aliens] (id, name) VALUES(1, 'Trisolarans'), (2, 'Xenomorph')")
|
|
580
|
+
end
|
|
581
|
+
end
|
|
582
|
+
end
|
|
583
|
+
|
|
584
|
+
describe 'table names contains spaces' do
|
|
585
|
+
it 'records can be created successfully' do
|
|
586
|
+
assert_difference("TableWithSpaces.count", 1) do
|
|
587
|
+
TableWithSpaces.create!(name: 'Bob')
|
|
588
|
+
end
|
|
589
|
+
end
|
|
590
|
+
end
|
|
591
|
+
|
|
592
|
+
describe "exec_insert" do
|
|
593
|
+
it 'values clause should be case-insensitive' do
|
|
594
|
+
assert_difference("Post.count", 4) do
|
|
595
|
+
first_insert = connection.exec_insert("INSERT INTO [posts] ([id],[title],[body]) VALUES(100, 'Title', 'Body'), (102, 'Title', 'Body')")
|
|
596
|
+
second_insert = connection.exec_insert("INSERT INTO [posts] ([id],[title],[body]) values(113, 'Body', 'Body'), (114, 'Body', 'Body')")
|
|
597
|
+
|
|
598
|
+
assert_equal first_insert.rows.map(&:first), [100, 102]
|
|
599
|
+
assert_equal second_insert.rows.map(&:first), [113, 114]
|
|
600
|
+
end
|
|
601
|
+
end
|
|
602
|
+
end
|
|
603
|
+
|
|
604
|
+
describe "mismatched foreign keys error" do
|
|
605
|
+
def setup
|
|
606
|
+
@conn = ActiveRecord::Base.lease_connection
|
|
607
|
+
end
|
|
608
|
+
|
|
609
|
+
it 'raises an error when the foreign key is mismatched' do
|
|
610
|
+
error = assert_raises(ActiveRecord::MismatchedForeignKey) do
|
|
611
|
+
@conn.add_reference :engines, :old_car
|
|
612
|
+
@conn.add_foreign_key :engines, :old_cars
|
|
613
|
+
end
|
|
614
|
+
|
|
615
|
+
assert_match(
|
|
616
|
+
%r/Column 'old_cars\.id' is not the same data type as referencing column 'engines\.old_car_id' in foreign key '.*'/,
|
|
617
|
+
error.message
|
|
618
|
+
)
|
|
619
|
+
assert_not_nil error.cause
|
|
620
|
+
assert_equal @conn.pool, error.connection_pool
|
|
621
|
+
ensure
|
|
622
|
+
@conn.execute("ALTER TABLE engines DROP COLUMN old_car_id") rescue nil
|
|
623
|
+
end
|
|
624
|
+
end
|
|
625
|
+
|
|
626
|
+
describe "placeholder conditions" do
|
|
627
|
+
it 'using time placeholder' do
|
|
628
|
+
assert_equal Task.where("starting < ?", Time.now).count, 1
|
|
629
|
+
end
|
|
630
|
+
|
|
631
|
+
it 'using date placeholder' do
|
|
632
|
+
assert_equal Task.where("starting < ?", Date.today).count, 1
|
|
633
|
+
end
|
|
634
|
+
|
|
635
|
+
it 'using date-time placeholder' do
|
|
636
|
+
assert_equal Task.where("starting < ?", DateTime.current).count, 1
|
|
637
|
+
end
|
|
638
|
+
end
|
|
639
|
+
|
|
640
|
+
describe "distinct select query" do
|
|
641
|
+
it "generated SQL does not contain unnecessary alias projection" do
|
|
642
|
+
sqls = capture_sql do
|
|
643
|
+
Post.includes(:comments).joins(:comments).first
|
|
644
|
+
end
|
|
645
|
+
assert_no_match(/AS alias_0/, sqls.first)
|
|
646
|
+
end
|
|
647
|
+
end
|
|
648
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "cases/helper_sqlserver"
|
|
4
|
+
require "migrations/create_clients_and_change_column_collation"
|
|
5
|
+
|
|
6
|
+
class ChangeColumnCollationTestSqlServer < ActiveRecord::TestCase
|
|
7
|
+
before do
|
|
8
|
+
@old_verbose = ActiveRecord::Migration.verbose
|
|
9
|
+
ActiveRecord::Migration.verbose = false
|
|
10
|
+
CreateClientsAndChangeColumnCollation.new.up
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
after do
|
|
14
|
+
CreateClientsAndChangeColumnCollation.new.down
|
|
15
|
+
ActiveRecord::Migration.verbose = @old_verbose
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def find_column(table, name)
|
|
19
|
+
table.find { |column| column.name == name }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
let(:clients_table) { connection.columns("clients") }
|
|
23
|
+
let(:name_column) { find_column(clients_table, "name") }
|
|
24
|
+
let(:code_column) { find_column(clients_table, "code") }
|
|
25
|
+
|
|
26
|
+
it "change column collation to other than default" do
|
|
27
|
+
_(name_column.collation).must_equal "SQL_Latin1_General_CP1_CS_AS"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "change column collation to default" do
|
|
31
|
+
_(code_column.collation).must_equal "SQL_Latin1_General_CP1_CI_AS"
|
|
32
|
+
end
|
|
33
|
+
end
|