activerecord-sqlserver-adapter 5.2.1 → 6.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.
Files changed (149) hide show
  1. checksums.yaml +4 -4
  2. data/.editorconfig +9 -0
  3. data/.github/issue_template.md +23 -0
  4. data/.gitignore +1 -0
  5. data/.rubocop.yml +29 -0
  6. data/.travis.yml +6 -8
  7. data/CHANGELOG.md +38 -24
  8. data/{Dockerfile → Dockerfile.ci} +1 -1
  9. data/Gemfile +48 -41
  10. data/Guardfile +9 -8
  11. data/README.md +9 -30
  12. data/RUNNING_UNIT_TESTS.md +3 -0
  13. data/Rakefile +14 -16
  14. data/VERSION +1 -1
  15. data/activerecord-sqlserver-adapter.gemspec +25 -14
  16. data/appveyor.yml +24 -17
  17. data/docker-compose.ci.yml +7 -5
  18. data/guides/RELEASING.md +11 -0
  19. data/lib/active_record/connection_adapters/sqlserver/core_ext/active_record.rb +2 -4
  20. data/lib/active_record/connection_adapters/sqlserver/core_ext/attribute_methods.rb +3 -4
  21. data/lib/active_record/connection_adapters/sqlserver/core_ext/calculations.rb +5 -4
  22. data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +3 -3
  23. data/lib/active_record/connection_adapters/sqlserver/core_ext/explain_subscriber.rb +2 -0
  24. data/lib/active_record/connection_adapters/sqlserver/core_ext/finder_methods.rb +8 -7
  25. data/lib/active_record/connection_adapters/sqlserver/core_ext/preloader.rb +36 -0
  26. data/lib/active_record/connection_adapters/sqlserver/core_ext/query_methods.rb +6 -4
  27. data/lib/active_record/connection_adapters/sqlserver/database_limits.rb +9 -0
  28. data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +88 -44
  29. data/lib/active_record/connection_adapters/sqlserver/database_tasks.rb +9 -12
  30. data/lib/active_record/connection_adapters/sqlserver/errors.rb +2 -3
  31. data/lib/active_record/connection_adapters/sqlserver/quoting.rb +46 -8
  32. data/lib/active_record/connection_adapters/sqlserver/schema_creation.rb +16 -5
  33. data/lib/active_record/connection_adapters/sqlserver/schema_dumper.rb +9 -7
  34. data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +190 -164
  35. data/lib/active_record/connection_adapters/sqlserver/showplan/printer_table.rb +4 -2
  36. data/lib/active_record/connection_adapters/sqlserver/showplan/printer_xml.rb +3 -1
  37. data/lib/active_record/connection_adapters/sqlserver/showplan.rb +8 -8
  38. data/lib/active_record/connection_adapters/sqlserver/sql_type_metadata.rb +2 -2
  39. data/lib/active_record/connection_adapters/sqlserver/table_definition.rb +43 -44
  40. data/lib/active_record/connection_adapters/sqlserver/transaction.rb +7 -9
  41. data/lib/active_record/connection_adapters/sqlserver/type/big_integer.rb +3 -3
  42. data/lib/active_record/connection_adapters/sqlserver/type/binary.rb +5 -4
  43. data/lib/active_record/connection_adapters/sqlserver/type/boolean.rb +3 -3
  44. data/lib/active_record/connection_adapters/sqlserver/type/char.rb +7 -4
  45. data/lib/active_record/connection_adapters/sqlserver/type/data.rb +2 -2
  46. data/lib/active_record/connection_adapters/sqlserver/type/date.rb +4 -3
  47. data/lib/active_record/connection_adapters/sqlserver/type/datetime.rb +8 -8
  48. data/lib/active_record/connection_adapters/sqlserver/type/datetime2.rb +2 -2
  49. data/lib/active_record/connection_adapters/sqlserver/type/datetimeoffset.rb +2 -2
  50. data/lib/active_record/connection_adapters/sqlserver/type/decimal.rb +5 -4
  51. data/lib/active_record/connection_adapters/sqlserver/type/float.rb +3 -3
  52. data/lib/active_record/connection_adapters/sqlserver/type/integer.rb +3 -3
  53. data/lib/active_record/connection_adapters/sqlserver/type/json.rb +2 -1
  54. data/lib/active_record/connection_adapters/sqlserver/type/money.rb +4 -4
  55. data/lib/active_record/connection_adapters/sqlserver/type/real.rb +3 -3
  56. data/lib/active_record/connection_adapters/sqlserver/type/small_integer.rb +3 -3
  57. data/lib/active_record/connection_adapters/sqlserver/type/small_money.rb +4 -4
  58. data/lib/active_record/connection_adapters/sqlserver/type/smalldatetime.rb +3 -3
  59. data/lib/active_record/connection_adapters/sqlserver/type/string.rb +2 -2
  60. data/lib/active_record/connection_adapters/sqlserver/type/text.rb +3 -3
  61. data/lib/active_record/connection_adapters/sqlserver/type/time.rb +6 -6
  62. data/lib/active_record/connection_adapters/sqlserver/type/time_value_fractional.rb +8 -9
  63. data/lib/active_record/connection_adapters/sqlserver/type/timestamp.rb +3 -3
  64. data/lib/active_record/connection_adapters/sqlserver/type/tiny_integer.rb +3 -3
  65. data/lib/active_record/connection_adapters/sqlserver/type/unicode_char.rb +5 -4
  66. data/lib/active_record/connection_adapters/sqlserver/type/unicode_string.rb +2 -2
  67. data/lib/active_record/connection_adapters/sqlserver/type/unicode_text.rb +3 -3
  68. data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar.rb +6 -5
  69. data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar_max.rb +4 -4
  70. data/lib/active_record/connection_adapters/sqlserver/type/uuid.rb +4 -3
  71. data/lib/active_record/connection_adapters/sqlserver/type/varbinary.rb +6 -5
  72. data/lib/active_record/connection_adapters/sqlserver/type/varbinary_max.rb +4 -4
  73. data/lib/active_record/connection_adapters/sqlserver/type/varchar.rb +6 -5
  74. data/lib/active_record/connection_adapters/sqlserver/type/varchar_max.rb +4 -4
  75. data/lib/active_record/connection_adapters/sqlserver/type.rb +37 -35
  76. data/lib/active_record/connection_adapters/sqlserver/utils.rb +10 -11
  77. data/lib/active_record/connection_adapters/sqlserver/version.rb +2 -2
  78. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +128 -92
  79. data/lib/active_record/connection_adapters/sqlserver_column.rb +9 -5
  80. data/lib/active_record/sqlserver_base.rb +9 -1
  81. data/lib/active_record/tasks/sqlserver_database_tasks.rb +28 -32
  82. data/lib/activerecord-sqlserver-adapter.rb +3 -1
  83. data/lib/arel/visitors/sqlserver.rb +58 -24
  84. data/lib/arel_sqlserver.rb +4 -2
  85. data/test/appveyor/dbsetup.ps1 +4 -4
  86. data/test/cases/adapter_test_sqlserver.rb +214 -171
  87. data/test/cases/change_column_null_test_sqlserver.rb +14 -12
  88. data/test/cases/coerced_tests.rb +631 -356
  89. data/test/cases/column_test_sqlserver.rb +283 -284
  90. data/test/cases/connection_test_sqlserver.rb +17 -20
  91. data/test/cases/execute_procedure_test_sqlserver.rb +20 -20
  92. data/test/cases/fetch_test_sqlserver.rb +16 -22
  93. data/test/cases/fully_qualified_identifier_test_sqlserver.rb +15 -19
  94. data/test/cases/helper_sqlserver.rb +15 -15
  95. data/test/cases/in_clause_test_sqlserver.rb +36 -0
  96. data/test/cases/index_test_sqlserver.rb +15 -15
  97. data/test/cases/json_test_sqlserver.rb +25 -25
  98. data/test/cases/migration_test_sqlserver.rb +25 -29
  99. data/test/cases/order_test_sqlserver.rb +53 -54
  100. data/test/cases/pessimistic_locking_test_sqlserver.rb +27 -33
  101. data/test/cases/rake_test_sqlserver.rb +33 -45
  102. data/test/cases/schema_dumper_test_sqlserver.rb +107 -109
  103. data/test/cases/schema_test_sqlserver.rb +20 -26
  104. data/test/cases/scratchpad_test_sqlserver.rb +4 -4
  105. data/test/cases/showplan_test_sqlserver.rb +28 -35
  106. data/test/cases/specific_schema_test_sqlserver.rb +68 -65
  107. data/test/cases/transaction_test_sqlserver.rb +18 -20
  108. data/test/cases/trigger_test_sqlserver.rb +14 -13
  109. data/test/cases/utils_test_sqlserver.rb +70 -70
  110. data/test/cases/uuid_test_sqlserver.rb +13 -14
  111. data/test/debug.rb +8 -6
  112. data/test/migrations/create_clients_and_change_column_null.rb +3 -1
  113. data/test/migrations/transaction_table/1_table_will_never_be_created.rb +4 -4
  114. data/test/models/sqlserver/booking.rb +3 -1
  115. data/test/models/sqlserver/customers_view.rb +3 -1
  116. data/test/models/sqlserver/datatype.rb +2 -0
  117. data/test/models/sqlserver/datatype_migration.rb +2 -0
  118. data/test/models/sqlserver/dollar_table_name.rb +3 -1
  119. data/test/models/sqlserver/edge_schema.rb +3 -3
  120. data/test/models/sqlserver/fk_has_fk.rb +3 -1
  121. data/test/models/sqlserver/fk_has_pk.rb +3 -1
  122. data/test/models/sqlserver/natural_pk_data.rb +4 -2
  123. data/test/models/sqlserver/natural_pk_int_data.rb +3 -1
  124. data/test/models/sqlserver/no_pk_data.rb +3 -1
  125. data/test/models/sqlserver/object_default.rb +3 -1
  126. data/test/models/sqlserver/quoted_table.rb +4 -2
  127. data/test/models/sqlserver/quoted_view_1.rb +3 -1
  128. data/test/models/sqlserver/quoted_view_2.rb +3 -1
  129. data/test/models/sqlserver/sst_memory.rb +3 -1
  130. data/test/models/sqlserver/string_default.rb +3 -1
  131. data/test/models/sqlserver/string_defaults_big_view.rb +3 -1
  132. data/test/models/sqlserver/string_defaults_view.rb +3 -1
  133. data/test/models/sqlserver/tinyint_pk.rb +3 -1
  134. data/test/models/sqlserver/trigger.rb +4 -2
  135. data/test/models/sqlserver/trigger_history.rb +3 -1
  136. data/test/models/sqlserver/upper.rb +3 -1
  137. data/test/models/sqlserver/uppered.rb +3 -1
  138. data/test/models/sqlserver/uuid.rb +3 -1
  139. data/test/schema/sqlserver_specific_schema.rb +22 -22
  140. data/test/support/coerceable_test_sqlserver.rb +15 -9
  141. data/test/support/connection_reflection.rb +3 -2
  142. data/test/support/core_ext/query_cache.rb +4 -1
  143. data/test/support/load_schema_sqlserver.rb +5 -5
  144. data/test/support/minitest_sqlserver.rb +3 -1
  145. data/test/support/paths_sqlserver.rb +11 -11
  146. data/test/support/rake_helpers.rb +13 -10
  147. data/test/support/sql_counter_sqlserver.rb +3 -4
  148. data/test/support/test_in_memory_oltp.rb +9 -7
  149. metadata +17 -7
@@ -1,19 +1,20 @@
1
- require 'cases/helper_sqlserver'
2
- require 'models/topic'
3
- require 'models/task'
4
- require 'models/post'
5
- require 'models/subscriber'
6
- require 'models/minimalistic'
1
+ # frozen_string_literal: true
7
2
 
8
- class AdapterTestSQLServer < ActiveRecord::TestCase
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
9
 
10
+ class AdapterTestSQLServer < ActiveRecord::TestCase
10
11
  fixtures :tasks
11
12
 
12
13
  let(:basic_insert_sql) { "INSERT INTO [funny_jokes] ([name]) VALUES('Knock knock')" }
13
14
  let(:basic_update_sql) { "UPDATE [customers] SET [address_street] = NULL WHERE [id] = 2" }
14
15
  let(:basic_select_sql) { "SELECT * FROM [customers] WHERE ([customers].[id] = 1)" }
15
16
 
16
- it 'has basic and non-senstive information in the adpaters inspect method' do
17
+ it "has basic and non-sensitive information in the adapters inspect method" do
17
18
  string = connection.inspect
18
19
  _(string).must_match %r{ActiveRecord::ConnectionAdapters::SQLServerAdapter}
19
20
  _(string).must_match %r{version\: \d.\d}
@@ -25,48 +26,66 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
25
26
  _(string).wont_match %r{port}
26
27
  end
27
28
 
28
- it 'has a 128 max #table_alias_length' do
29
+ it "has a 128 max #table_alias_length" do
29
30
  assert connection.table_alias_length <= 128
30
31
  end
31
32
 
32
- it 'raises invalid statement error for bad SQL' do
33
+ it "raises invalid statement error for bad SQL" do
33
34
  assert_raise(ActiveRecord::StatementInvalid) { Topic.connection.update("UPDATE XXX") }
34
35
  end
35
36
 
36
- it 'is has our adapter_name' do
37
- assert_equal 'SQLServer', connection.adapter_name
37
+ it "is has our adapter_name" do
38
+ assert_equal "SQLServer", connection.adapter_name
38
39
  end
39
40
 
40
- it 'support DDL in transactions' do
41
+ it "support DDL in transactions" do
41
42
  assert connection.supports_ddl_transactions?
42
43
  end
43
44
 
44
- it 'allow owner table name prefixs like dbo to still allow table exists to return true' do
45
+ it "allow owner table name prefixs like dbo to still allow table exists to return true" do
45
46
  begin
46
- assert_equal 'topics', Topic.table_name
47
+ assert_equal "topics", Topic.table_name
47
48
  assert Topic.table_exists?
48
- Topic.table_name = 'dbo.topics'
49
- assert Topic.table_exists?, 'Tasks table name of dbo.topics should return true for exists.'
49
+ Topic.table_name = "dbo.topics"
50
+ assert Topic.table_exists?, "Tasks table name of dbo.topics should return true for exists."
50
51
  ensure
51
- Topic.table_name = 'topics'
52
+ Topic.table_name = "topics"
52
53
  end
53
54
  end
54
55
 
55
- it 'return true to insert sql query for inserts only' do
56
- assert connection.send(:insert_sql?,'INSERT...')
56
+ it "return true to insert sql query for inserts only" do
57
+ assert connection.send(:insert_sql?, "INSERT...")
57
58
  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")
58
- assert !connection.send(:insert_sql?,'UPDATE...')
59
- assert !connection.send(:insert_sql?,'SELECT...')
59
+ assert !connection.send(:insert_sql?, "UPDATE...")
60
+ assert !connection.send(:insert_sql?, "SELECT...")
61
+ end
62
+
63
+ it "return unquoted table name object from basic INSERT UPDATE and SELECT statements" do
64
+ assert_equal "funny_jokes", connection.send(:get_table_name, basic_insert_sql)
65
+ assert_equal "customers", connection.send(:get_table_name, basic_update_sql)
66
+ assert_equal "customers", connection.send(:get_table_name, basic_select_sql)
60
67
  end
61
68
 
62
- it 'return unquoted table name object from basic INSERT UPDATE and SELECT statements' do
63
- assert_equal 'funny_jokes', connection.send(:get_table_name, basic_insert_sql)
64
- assert_equal 'customers', connection.send(:get_table_name, basic_update_sql)
65
- assert_equal 'customers', connection.send(:get_table_name, basic_select_sql)
69
+ it "test bad connection" do
70
+ assert_raise ActiveRecord::NoDatabaseError do
71
+ config = ActiveRecord::Base.configurations["arunit"].merge(database: "inexistent_activerecord_unittest")
72
+ ActiveRecord::Base.sqlserver_connection config
73
+ end
66
74
  end
67
75
 
68
- describe 'with different language' do
76
+ it "test database exists returns false if database does not exist" do
77
+ config = ActiveRecord::Base.configurations["arunit"].merge(database: "inexistent_activerecord_unittest")
78
+ assert_not ActiveRecord::ConnectionAdapters::SQLServerAdapter.database_exists?(config),
79
+ "expected database to not exist"
80
+ end
69
81
 
82
+ it "test database exists returns true when the database exists" do
83
+ config = ActiveRecord::Base.configurations["arunit"]
84
+ assert ActiveRecord::ConnectionAdapters::SQLServerAdapter.database_exists?(config),
85
+ "expected database #{config[:database]} to exist"
86
+ end
87
+
88
+ describe "with different language" do
70
89
  before do
71
90
  @default_language = connection.user_options_language
72
91
  end
@@ -76,18 +95,18 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
76
95
  connection.send :initialize_dateformatter
77
96
  end
78
97
 
79
- it 'memos users dateformat' do
98
+ it "memos users dateformat" do
80
99
  connection.execute("SET LANGUAGE us_english") rescue nil
81
100
  dateformat = connection.instance_variable_get(:@database_dateformat)
82
- assert_equal 'mdy', dateformat
101
+ assert_equal "mdy", dateformat
83
102
  end
84
103
 
85
- it 'has a dateformatter' do
104
+ it "has a dateformatter" do
86
105
  assert Date::DATE_FORMATS[:_sqlserver_dateformat]
87
106
  assert Time::DATE_FORMATS[:_sqlserver_dateformat]
88
107
  end
89
108
 
90
- it 'does a datetime insertion when language is german' do
109
+ it "does a datetime insertion when language is german" do
91
110
  connection.execute("SET LANGUAGE deutsch")
92
111
  connection.send :initialize_dateformatter
93
112
  assert_nothing_raised do
@@ -96,40 +115,36 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
96
115
  Task.create! starting: starting, ending: ending
97
116
  end
98
117
  end
99
-
100
118
  end
101
119
 
102
- describe 'testing #lowercase_schema_reflection' do
103
-
120
+ describe "testing #lowercase_schema_reflection" do
104
121
  before do
105
122
  SSTestUpper.delete_all
106
- SSTestUpper.create COLUMN1: 'Got a minute?', COLUMN2: 419
107
- SSTestUpper.create COLUMN1: 'Favorite number?', COLUMN2: 69
123
+ SSTestUpper.create COLUMN1: "Got a minute?", COLUMN2: 419
124
+ SSTestUpper.create COLUMN1: "Favorite number?", COLUMN2: 69
108
125
  end
109
126
 
110
127
  after do
111
128
  connection.lowercase_schema_reflection = false
112
129
  end
113
130
 
114
- it 'not lowercase schema reflection by default' do
115
- assert SSTestUpper.columns_hash['COLUMN1']
116
- assert_equal 'Got a minute?', SSTestUpper.first.COLUMN1
117
- assert_equal 'Favorite number?', SSTestUpper.last.COLUMN1
118
- assert SSTestUpper.columns_hash['COLUMN2']
131
+ it "not lowercase schema reflection by default" do
132
+ assert SSTestUpper.columns_hash["COLUMN1"]
133
+ assert_equal "Got a minute?", SSTestUpper.first.COLUMN1
134
+ assert_equal "Favorite number?", SSTestUpper.last.COLUMN1
135
+ assert SSTestUpper.columns_hash["COLUMN2"]
119
136
  end
120
137
 
121
- it 'lowercase schema reflection when set' do
138
+ it "lowercase schema reflection when set" do
122
139
  connection.lowercase_schema_reflection = true
123
- assert SSTestUppered.columns_hash['column1']
124
- assert_equal 'Got a minute?', SSTestUppered.first.column1
125
- assert_equal 'Favorite number?', SSTestUppered.last.column1
126
- assert SSTestUppered.columns_hash['column2']
140
+ assert SSTestUppered.columns_hash["column1"]
141
+ assert_equal "Got a minute?", SSTestUppered.first.column1
142
+ assert_equal "Favorite number?", SSTestUppered.last.column1
143
+ assert SSTestUppered.columns_hash["column2"]
127
144
  end
128
-
129
145
  end
130
146
 
131
- describe 'identity inserts' do
132
-
147
+ describe "identity inserts" do
133
148
  before do
134
149
  @identity_insert_sql = "INSERT INTO [funny_jokes] ([id],[name]) VALUES(420,'Knock knock')"
135
150
  @identity_insert_sql_unquoted = "INSERT INTO funny_jokes (id, name) VALUES(420, 'Knock knock')"
@@ -139,62 +154,60 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
139
154
  @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"
140
155
  end
141
156
 
142
- it 'return quoted table_name to #query_requires_identity_insert? when INSERT sql contains id column' do
143
- assert_equal 'funny_jokes', connection.send(:query_requires_identity_insert?,@identity_insert_sql)
144
- assert_equal 'funny_jokes', connection.send(:query_requires_identity_insert?,@identity_insert_sql_unquoted)
145
- assert_equal 'funny_jokes', connection.send(:query_requires_identity_insert?,@identity_insert_sql_unordered)
146
- assert_equal 'funny_jokes', connection.send(:query_requires_identity_insert?,@identity_insert_sql_sp)
147
- assert_equal 'funny_jokes', connection.send(:query_requires_identity_insert?,@identity_insert_sql_unquoted_sp)
148
- assert_equal 'funny_jokes', connection.send(:query_requires_identity_insert?,@identity_insert_sql_unordered_sp)
157
+ it "return quoted table_name to #query_requires_identity_insert? when INSERT sql contains id column" do
158
+ assert_equal "funny_jokes", connection.send(:query_requires_identity_insert?, @identity_insert_sql)
159
+ assert_equal "funny_jokes", connection.send(:query_requires_identity_insert?, @identity_insert_sql_unquoted)
160
+ assert_equal "funny_jokes", connection.send(:query_requires_identity_insert?, @identity_insert_sql_unordered)
161
+ assert_equal "funny_jokes", connection.send(:query_requires_identity_insert?, @identity_insert_sql_sp)
162
+ assert_equal "funny_jokes", connection.send(:query_requires_identity_insert?, @identity_insert_sql_unquoted_sp)
163
+ assert_equal "funny_jokes", connection.send(:query_requires_identity_insert?, @identity_insert_sql_unordered_sp)
149
164
  end
150
165
 
151
- it 'return false to #query_requires_identity_insert? for normal SQL' do
166
+ it "return false to #query_requires_identity_insert? for normal SQL" do
152
167
  [basic_insert_sql, basic_update_sql, basic_select_sql].each do |sql|
153
- assert !connection.send(:query_requires_identity_insert?,sql), "SQL was #{sql}"
168
+ assert !connection.send(:query_requires_identity_insert?, sql), "SQL was #{sql}"
154
169
  end
155
170
  end
156
171
 
157
- it 'find identity column using #identity_columns' do
158
- task_id_column = Task.columns_hash['id']
172
+ it "find identity column using #identity_columns" do
173
+ task_id_column = Task.columns_hash["id"]
159
174
  assert_equal task_id_column.name, connection.send(:identity_columns, Task.table_name).first.name
160
175
  assert_equal task_id_column.sql_type, connection.send(:identity_columns, Task.table_name).first.sql_type
161
176
  end
162
177
 
163
- it 'return an empty array when calling #identity_columns for a table_name with no identity' do
178
+ it "return an empty array when calling #identity_columns for a table_name with no identity" do
164
179
  _(connection.send(:identity_columns, Subscriber.table_name)).must_equal []
165
180
  end
166
-
167
181
  end
168
182
 
169
- describe 'quoting' do
170
-
171
- it 'return 1 for #quoted_true' do
172
- assert_equal '1', connection.quoted_true
183
+ describe "quoting" do
184
+ it "return 1 for #quoted_true" do
185
+ assert_equal "1", connection.quoted_true
173
186
  end
174
187
 
175
- it 'return 0 for #quoted_false' do
176
- assert_equal '0', connection.quoted_false
188
+ it "return 0 for #quoted_false" do
189
+ assert_equal "0", connection.quoted_false
177
190
  end
178
191
 
179
- it 'not escape backslash characters like abstract adapter' do
192
+ it "not escape backslash characters like abstract adapter" do
180
193
  string_with_backslashs = "\\n"
181
194
  assert_equal string_with_backslashs, connection.quote_string(string_with_backslashs)
182
195
  end
183
196
 
184
- it 'quote column names with brackets' do
185
- assert_equal '[foo]', connection.quote_column_name(:foo)
186
- assert_equal '[foo]', connection.quote_column_name('foo')
187
- assert_equal '[foo].[bar]', connection.quote_column_name('foo.bar')
197
+ it "quote column names with brackets" do
198
+ assert_equal "[foo]", connection.quote_column_name(:foo)
199
+ assert_equal "[foo]", connection.quote_column_name("foo")
200
+ assert_equal "[foo].[bar]", connection.quote_column_name("foo.bar")
188
201
  end
189
202
 
190
- it 'not quote already quoted column names with brackets' do
191
- assert_equal '[foo]', connection.quote_column_name('[foo]')
192
- assert_equal '[foo].[bar]', connection.quote_column_name('[foo].[bar]')
203
+ it "not quote already quoted column names with brackets" do
204
+ assert_equal "[foo]", connection.quote_column_name("[foo]")
205
+ assert_equal "[foo].[bar]", connection.quote_column_name("[foo].[bar]")
193
206
  end
194
207
 
195
- it 'quote table names like columns' do
196
- assert_equal '[foo].[bar]', connection.quote_column_name('foo.bar')
197
- assert_equal '[foo].[bar].[baz]', connection.quote_column_name('foo.bar.baz')
208
+ it "quote table names like columns" do
209
+ assert_equal "[foo].[bar]", connection.quote_column_name("foo.bar")
210
+ assert_equal "[foo].[bar].[baz]", connection.quote_column_name("foo.bar.baz")
198
211
  end
199
212
 
200
213
  it "surround string with national prefix" do
@@ -204,44 +217,40 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
204
217
  it "escape all single quotes by repeating them" do
205
218
  assert_equal "N'''quotation''s'''", connection.quote("'quotation's'")
206
219
  end
207
-
208
220
  end
209
221
 
210
- describe 'disabling referential integrity' do
211
-
222
+ describe "disabling referential integrity" do
212
223
  before do
213
224
  connection.disable_referential_integrity { SSTestHasPk.delete_all; SSTestHasFk.delete_all }
214
225
  @parent = SSTestHasPk.create!
215
226
  @member = SSTestHasFk.create!(fk_id: @parent.id)
216
227
  end
217
228
 
218
- it 'NOT ALLOW by default the deletion of a referenced parent' do
219
- SSTestHasPk.connection.disable_referential_integrity { }
229
+ it "NOT ALLOW by default the deletion of a referenced parent" do
230
+ SSTestHasPk.connection.disable_referential_integrity {}
220
231
  assert_raise(ActiveRecord::StatementInvalid) { @parent.destroy }
221
232
  end
222
233
 
223
- it 'ALLOW deletion of referenced parent using #disable_referential_integrity block' do
234
+ it "ALLOW deletion of referenced parent using #disable_referential_integrity block" do
224
235
  SSTestHasPk.connection.disable_referential_integrity { @parent.destroy }
225
236
  end
226
237
 
227
- it 'again NOT ALLOW deletion of referenced parent after #disable_referential_integrity block' do
238
+ it "again NOT ALLOW deletion of referenced parent after #disable_referential_integrity block" do
228
239
  assert_raise(ActiveRecord::StatementInvalid) do
229
- SSTestHasPk.connection.disable_referential_integrity { }
240
+ SSTestHasPk.connection.disable_referential_integrity {}
230
241
  @parent.destroy
231
242
  end
232
243
  end
233
244
 
234
- it 'not disable referential integrity for the same table twice' do
245
+ it "not disable referential integrity for the same table twice" do
235
246
  tables = SSTestHasPk.connection.tables_with_referential_integrity
236
247
  assert_equal tables.size, tables.uniq.size
237
248
  end
238
-
239
249
  end
240
250
 
241
- describe 'database statements' do
242
-
251
+ describe "database statements" do
243
252
  it "run the database consistency checker useroptions command" do
244
- skip 'on azure' if connection_sqlserver_azure?
253
+ skip "on azure" if connection_sqlserver_azure?
245
254
  keys = [:textsize, :language, :isolation_level, :dateformat]
246
255
  user_options = connection.user_options
247
256
  keys.each do |key|
@@ -251,183 +260,217 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
251
260
  end
252
261
 
253
262
  it "return a underscored key hash with indifferent access of the results" do
254
- skip 'on azure' if connection_sqlserver_azure?
263
+ skip "on azure" if connection_sqlserver_azure?
255
264
  user_options = connection.user_options
256
- assert_equal 'read committed', user_options['isolation_level']
257
- assert_equal 'read committed', user_options[:isolation_level]
265
+ assert_equal "read committed", user_options["isolation_level"]
266
+ assert_equal "read committed", user_options[:isolation_level]
258
267
  end
259
-
260
268
  end
261
269
 
262
- describe 'schema statements' do
263
-
264
- it 'create integers when no limit supplied' do
265
- assert_equal 'integer', connection.type_to_sql(:integer)
270
+ describe "schema statements" do
271
+ it "create integers when no limit supplied" do
272
+ assert_equal "integer", connection.type_to_sql(:integer)
266
273
  end
267
274
 
268
- it 'create integers when limit is 4' do
269
- assert_equal 'integer', connection.type_to_sql(:integer, limit: 4)
275
+ it "create integers when limit is 4" do
276
+ assert_equal "integer", connection.type_to_sql(:integer, limit: 4)
270
277
  end
271
278
 
272
- it 'create integers when limit is 3' do
273
- assert_equal 'integer', connection.type_to_sql(:integer, limit: 3)
279
+ it "create integers when limit is 3" do
280
+ assert_equal "integer", connection.type_to_sql(:integer, limit: 3)
274
281
  end
275
282
 
276
- it 'create smallints when limit is 2' do
277
- assert_equal 'smallint', connection.type_to_sql(:integer, limit: 2)
283
+ it "create smallints when limit is 2" do
284
+ assert_equal "smallint", connection.type_to_sql(:integer, limit: 2)
278
285
  end
279
286
 
280
- it 'create tinyints when limit is 1' do
281
- assert_equal 'tinyint', connection.type_to_sql(:integer, limit: 1)
287
+ it "create tinyints when limit is 1" do
288
+ assert_equal "tinyint", connection.type_to_sql(:integer, limit: 1)
282
289
  end
283
290
 
284
- it 'create bigints when limit is greateer than 4' do
285
- assert_equal 'bigint', connection.type_to_sql(:integer, limit: 5)
286
- assert_equal 'bigint', connection.type_to_sql(:integer, limit: 6)
287
- assert_equal 'bigint', connection.type_to_sql(:integer, limit: 7)
288
- assert_equal 'bigint', connection.type_to_sql(:integer, limit: 8)
291
+ it "create bigints when limit is greateer than 4" do
292
+ assert_equal "bigint", connection.type_to_sql(:integer, limit: 5)
293
+ assert_equal "bigint", connection.type_to_sql(:integer, limit: 6)
294
+ assert_equal "bigint", connection.type_to_sql(:integer, limit: 7)
295
+ assert_equal "bigint", connection.type_to_sql(:integer, limit: 8)
289
296
  end
290
297
 
291
- it 'create floats when no limit supplied' do
292
- assert_equal 'float', connection.type_to_sql(:float)
298
+ it "create floats when no limit supplied" do
299
+ assert_equal "float", connection.type_to_sql(:float)
293
300
  end
294
-
295
301
  end
296
302
 
297
- describe 'views' do
298
-
303
+ describe "views" do
299
304
  # Using connection.views
300
305
 
301
- it 'return an array' do
306
+ it "return an array" do
302
307
  assert_instance_of Array, connection.views
303
308
  end
304
309
 
305
- it 'find SSTestCustomersView table name' do
306
- _(connection.views).must_include 'sst_customers_view'
310
+ it "find SSTestCustomersView table name" do
311
+ _(connection.views).must_include "sst_customers_view"
307
312
  end
308
313
 
309
- it 'work with dynamic finders' do
310
- name = 'MetaSkills'
314
+ it "work with dynamic finders" do
315
+ name = "MetaSkills"
311
316
  customer = SSTestCustomersView.create! name: name
312
317
  assert_equal customer, SSTestCustomersView.find_by_name(name)
313
318
  end
314
319
 
315
- it 'not contain system views' do
316
- systables = ['sysconstraints','syssegments']
320
+ it "not contain system views" do
321
+ systables = ["sysconstraints", "syssegments"]
317
322
  systables.each do |systable|
318
323
  assert !connection.views.include?(systable), "This systable #{systable} should not be in the views array."
319
324
  end
320
325
  end
321
326
 
322
- it 'allow the connection#view_information method to return meta data on the view' do
323
- view_info = connection.send(:view_information,'sst_customers_view')
324
- assert_equal('sst_customers_view', view_info['TABLE_NAME'])
325
- assert_match(/CREATE VIEW sst_customers_view/, view_info['VIEW_DEFINITION'])
327
+ it "allow the connection#view_information method to return meta data on the view" do
328
+ view_info = connection.send(:view_information, "sst_customers_view")
329
+ assert_equal("sst_customers_view", view_info["TABLE_NAME"])
330
+ assert_match(/CREATE VIEW sst_customers_view/, view_info["VIEW_DEFINITION"])
326
331
  end
327
332
 
328
- it 'allow the connection#view_table_name method to return true table_name for the view' do
329
- assert_equal 'customers', connection.send(:view_table_name,'sst_customers_view')
330
- assert_equal 'topics', connection.send(:view_table_name,'topics'), 'No view here, the same table name should come back.'
333
+ it "allow the connection#view_table_name method to return true table_name for the view" do
334
+ assert_equal "customers", connection.send(:view_table_name, "sst_customers_view")
335
+ assert_equal "topics", connection.send(:view_table_name, "topics"), "No view here, the same table name should come back."
331
336
  end
332
337
 
333
338
  # With same column names
334
339
 
335
- it 'have matching column objects' do
336
- columns = ['id','name','balance']
340
+ it "have matching column objects" do
341
+ columns = ["id", "name", "balance"]
337
342
  assert !SSTestCustomersView.columns.blank?
338
343
  assert_equal columns.size, SSTestCustomersView.columns.size
339
344
  columns.each do |colname|
340
345
  assert_instance_of ActiveRecord::ConnectionAdapters::SQLServerColumn,
341
- SSTestCustomersView.columns_hash[colname],
342
- "Column name #{colname.inspect} was not found in these columns #{SSTestCustomersView.columns.map(&:name).inspect}"
346
+ SSTestCustomersView.columns_hash[colname],
347
+ "Column name #{colname.inspect} was not found in these columns #{SSTestCustomersView.columns.map(&:name).inspect}"
343
348
  end
344
349
  end
345
350
 
346
- it 'find identity column' do
347
- _(SSTestCustomersView.primary_key).must_equal 'id'
348
- _(connection.primary_key(SSTestCustomersView.table_name)).must_equal 'id'
349
- _(SSTestCustomersView.columns_hash['id']).must_be :is_identity?
351
+ it "find identity column" do
352
+ _(SSTestCustomersView.primary_key).must_equal "id"
353
+ _(connection.primary_key(SSTestCustomersView.table_name)).must_equal "id"
354
+ _(SSTestCustomersView.columns_hash["id"]).must_be :is_identity?
350
355
  end
351
356
 
352
- it 'find default values' do
357
+ it "find default values" do
353
358
  assert_equal 0, SSTestCustomersView.new.balance
354
359
  end
355
360
 
356
- it 'respond true to data_source_exists?' do
361
+ it "respond true to data_source_exists?" do
357
362
  assert SSTestCustomersView.connection.data_source_exists?(SSTestCustomersView.table_name)
358
363
  end
359
364
 
360
365
  # With aliased column names
361
366
 
362
- it 'have matching column objects' do
363
- columns = ['id','pretend_null']
367
+ it "have matching column objects" do
368
+ columns = ["id", "pretend_null"]
364
369
  assert !SSTestStringDefaultsView.columns.blank?
365
370
  assert_equal columns.size, SSTestStringDefaultsView.columns.size
366
371
  columns.each do |colname|
367
372
  assert_instance_of ActiveRecord::ConnectionAdapters::SQLServerColumn,
368
- SSTestStringDefaultsView.columns_hash[colname],
369
- "Column name #{colname.inspect} was not found in these columns #{SSTestStringDefaultsView.columns.map(&:name).inspect}"
373
+ SSTestStringDefaultsView.columns_hash[colname],
374
+ "Column name #{colname.inspect} was not found in these columns #{SSTestStringDefaultsView.columns.map(&:name).inspect}"
370
375
  end
371
376
  end
372
377
 
373
- it 'find identity column' do
374
- _(SSTestStringDefaultsView.primary_key).must_equal 'id'
375
- _(connection.primary_key(SSTestStringDefaultsView.table_name)).must_equal 'id'
376
- _(SSTestStringDefaultsView.columns_hash['id']).must_be :is_identity?
378
+ it "find identity column" do
379
+ _(SSTestStringDefaultsView.primary_key).must_equal "id"
380
+ _(connection.primary_key(SSTestStringDefaultsView.table_name)).must_equal "id"
381
+ _(SSTestStringDefaultsView.columns_hash["id"]).must_be :is_identity?
377
382
  end
378
383
 
379
- it 'find default values' do
380
- assert_equal 'null', SSTestStringDefaultsView.new.pretend_null,
381
- SSTestStringDefaultsView.columns_hash['pretend_null'].inspect
384
+ it "find default values" do
385
+ assert_equal "null", SSTestStringDefaultsView.new.pretend_null,
386
+ SSTestStringDefaultsView.columns_hash["pretend_null"].inspect
382
387
  end
383
388
 
384
- it 'respond true to data_source_exists?' do
389
+ it "respond true to data_source_exists?" do
385
390
  assert SSTestStringDefaultsView.connection.data_source_exists?(SSTestStringDefaultsView.table_name)
386
391
  end
387
392
 
388
393
  # That have more than 4000 chars for their defintion
389
394
 
390
- it 'cope with null returned for the defintion' do
395
+ it "cope with null returned for the defintion" do
391
396
  assert_nothing_raised() { SSTestStringDefaultsBigView.columns }
392
397
  end
393
398
 
394
- it 'using alternate view defintion still be able to find real default' do
395
- assert_equal 'null', SSTestStringDefaultsBigView.new.pretend_null,
396
- SSTestStringDefaultsBigView.columns_hash['pretend_null'].inspect
399
+ it "using alternate view defintion still be able to find real default" do
400
+ assert_equal "null", SSTestStringDefaultsBigView.new.pretend_null,
401
+ SSTestStringDefaultsBigView.columns_hash["pretend_null"].inspect
397
402
  end
398
-
399
403
  end
400
404
 
401
- describe 'database_prefix_remote_server?' do
402
-
405
+ describe "database_prefix_remote_server?" do
403
406
  after do
404
407
  connection_options.delete(:database_prefix)
405
408
  end
406
409
 
407
- it 'returns false if database_prefix is not configured' do
410
+ it "returns false if database_prefix is not configured" do
408
411
  assert_equal false, connection.database_prefix_remote_server?
409
412
  end
410
413
 
411
- it 'returns true if database_prefix has been set' do
414
+ it "returns true if database_prefix has been set" do
412
415
  connection_options[:database_prefix] = "server.database.schema."
413
416
  assert_equal true, connection.database_prefix_remote_server?
414
417
  end
415
418
 
416
- it 'returns false if database_prefix has been set incorrectly' do
419
+ it "returns false if database_prefix has been set incorrectly" do
417
420
  connection_options[:database_prefix] = "server.database.schema"
418
421
  assert_equal false, connection.database_prefix_remote_server?
419
422
  end
420
-
421
423
  end
422
424
 
423
- it 'in_memory_oltp' do
424
- if ENV['IN_MEMORY_OLTP'] && connection.supports_in_memory_oltp?
425
- _(SSTMemory.primary_key).must_equal 'id'
426
- _(SSTMemory.columns_hash['id']).must_be :is_identity?
425
+ it "in_memory_oltp" do
426
+ if ENV["IN_MEMORY_OLTP"] && connection.supports_in_memory_oltp?
427
+ _(SSTMemory.primary_key).must_equal "id"
428
+ _(SSTMemory.columns_hash["id"]).must_be :is_identity?
427
429
  else
428
- skip 'supports_in_memory_oltp? => false'
430
+ skip "supports_in_memory_oltp? => false"
429
431
  end
430
432
  end
431
433
 
432
- end
434
+ describe "block writes to a database" do
435
+ def setup
436
+ @conn = ActiveRecord::Base.connection
437
+ @connection_handler = ActiveRecord::Base.connection_handler
438
+ end
433
439
 
440
+ def test_errors_when_an_insert_query_is_called_while_preventing_writes
441
+ assert_raises(ActiveRecord::ReadOnlyError) do
442
+ @connection_handler.while_preventing_writes do
443
+ @conn.insert("INSERT INTO [subscribers] ([nick]) VALUES ('aido')")
444
+ end
445
+ end
446
+ end
447
+
448
+ def test_errors_when_an_update_query_is_called_while_preventing_writes
449
+ @conn.insert("INSERT INTO [subscribers] ([nick]) VALUES ('aido')")
450
+
451
+ assert_raises(ActiveRecord::ReadOnlyError) do
452
+ @connection_handler.while_preventing_writes do
453
+ @conn.update("UPDATE [subscribers] SET [subscribers].[name] = 'Aidan' WHERE [subscribers].[nick] = 'aido'")
454
+ end
455
+ end
456
+ end
457
+
458
+ def test_errors_when_a_delete_query_is_called_while_preventing_writes
459
+ @conn.execute("INSERT INTO [subscribers] ([nick]) VALUES ('aido')")
460
+
461
+ assert_raises(ActiveRecord::ReadOnlyError) do
462
+ @connection_handler.while_preventing_writes do
463
+ @conn.execute("DELETE FROM [subscribers] WHERE [subscribers].[nick] = 'aido'")
464
+ end
465
+ end
466
+ end
467
+
468
+ def test_doesnt_error_when_a_select_query_is_called_while_preventing_writes
469
+ @conn.execute("INSERT INTO [subscribers] ([nick]) VALUES ('aido')")
470
+
471
+ @connection_handler.while_preventing_writes do
472
+ assert_equal 1, @conn.execute("SELECT * FROM [subscribers] WHERE [subscribers].[nick] = 'aido'")
473
+ end
474
+ end
475
+ end
476
+ end