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,37 +1,39 @@
1
- require 'base64'
2
- require 'active_record'
3
- require 'arel_sqlserver'
4
- require 'active_record/connection_adapters/abstract_adapter'
5
- require 'active_record/connection_adapters/sqlserver/core_ext/active_record'
6
- require 'active_record/connection_adapters/sqlserver/core_ext/calculations'
7
- require 'active_record/connection_adapters/sqlserver/core_ext/explain'
8
- require 'active_record/connection_adapters/sqlserver/core_ext/explain_subscriber'
9
- require 'active_record/connection_adapters/sqlserver/core_ext/attribute_methods'
10
- require 'active_record/connection_adapters/sqlserver/core_ext/finder_methods'
11
- require 'active_record/connection_adapters/sqlserver/core_ext/query_methods'
12
- require 'active_record/connection_adapters/sqlserver/version'
13
- require 'active_record/connection_adapters/sqlserver/type'
14
- require 'active_record/connection_adapters/sqlserver/database_limits'
15
- require 'active_record/connection_adapters/sqlserver/database_statements'
16
- require 'active_record/connection_adapters/sqlserver/database_tasks'
17
- require 'active_record/connection_adapters/sqlserver/transaction'
18
- require 'active_record/connection_adapters/sqlserver/errors'
19
- require 'active_record/connection_adapters/sqlserver/schema_creation'
20
- require 'active_record/connection_adapters/sqlserver/schema_dumper'
21
- require 'active_record/connection_adapters/sqlserver/schema_statements'
22
- require 'active_record/connection_adapters/sqlserver/sql_type_metadata'
23
- require 'active_record/connection_adapters/sqlserver/showplan'
24
- require 'active_record/connection_adapters/sqlserver/table_definition'
25
- require 'active_record/connection_adapters/sqlserver/quoting'
26
- require 'active_record/connection_adapters/sqlserver/utils'
27
- require 'active_record/sqlserver_base'
28
- require 'active_record/connection_adapters/sqlserver_column'
29
- require 'active_record/tasks/sqlserver_database_tasks'
1
+ # frozen_string_literal: true
2
+
3
+ require "base64"
4
+ require "active_record"
5
+ require "arel_sqlserver"
6
+ require "active_record/connection_adapters/abstract_adapter"
7
+ require "active_record/connection_adapters/sqlserver/core_ext/active_record"
8
+ require "active_record/connection_adapters/sqlserver/core_ext/calculations"
9
+ require "active_record/connection_adapters/sqlserver/core_ext/explain"
10
+ require "active_record/connection_adapters/sqlserver/core_ext/explain_subscriber"
11
+ require "active_record/connection_adapters/sqlserver/core_ext/attribute_methods"
12
+ require "active_record/connection_adapters/sqlserver/core_ext/finder_methods"
13
+ require "active_record/connection_adapters/sqlserver/core_ext/query_methods"
14
+ require "active_record/connection_adapters/sqlserver/core_ext/preloader"
15
+ require "active_record/connection_adapters/sqlserver/version"
16
+ require "active_record/connection_adapters/sqlserver/type"
17
+ require "active_record/connection_adapters/sqlserver/database_limits"
18
+ require "active_record/connection_adapters/sqlserver/database_statements"
19
+ require "active_record/connection_adapters/sqlserver/database_tasks"
20
+ require "active_record/connection_adapters/sqlserver/transaction"
21
+ require "active_record/connection_adapters/sqlserver/errors"
22
+ require "active_record/connection_adapters/sqlserver/schema_creation"
23
+ require "active_record/connection_adapters/sqlserver/schema_dumper"
24
+ require "active_record/connection_adapters/sqlserver/schema_statements"
25
+ require "active_record/connection_adapters/sqlserver/sql_type_metadata"
26
+ require "active_record/connection_adapters/sqlserver/showplan"
27
+ require "active_record/connection_adapters/sqlserver/table_definition"
28
+ require "active_record/connection_adapters/sqlserver/quoting"
29
+ require "active_record/connection_adapters/sqlserver/utils"
30
+ require "active_record/sqlserver_base"
31
+ require "active_record/connection_adapters/sqlserver_column"
32
+ require "active_record/tasks/sqlserver_database_tasks"
30
33
 
31
34
  module ActiveRecord
32
35
  module ConnectionAdapters
33
36
  class SQLServerAdapter < AbstractAdapter
34
-
35
37
  include SQLServer::Version,
36
38
  SQLServer::Quoting,
37
39
  SQLServer::DatabaseStatements,
@@ -40,7 +42,7 @@ module ActiveRecord
40
42
  SQLServer::DatabaseLimits,
41
43
  SQLServer::DatabaseTasks
42
44
 
43
- ADAPTER_NAME = 'SQLServer'.freeze
45
+ ADAPTER_NAME = "SQLServer".freeze
44
46
 
45
47
  # Default precision for 'time' (See https://docs.microsoft.com/en-us/sql/t-sql/data-types/time-transact-sql)
46
48
  DEFAULT_TIME_PRECISION = 7
@@ -53,7 +55,7 @@ module ActiveRecord
53
55
  cattr_accessor :showplan_option, instance_accessor: false
54
56
  cattr_accessor :lowercase_schema_reflection
55
57
 
56
- self.cs_equality_operator = 'COLLATE Latin1_General_CS_AS_WS'
58
+ self.cs_equality_operator = "COLLATE Latin1_General_CS_AS_WS"
57
59
  self.use_output_inserted = true
58
60
  self.exclude_output_inserted_table_names = Concurrent::Map.new { false }
59
61
 
@@ -80,6 +82,12 @@ module ActiveRecord
80
82
  SQLServer::SchemaCreation.new self
81
83
  end
82
84
 
85
+ def self.database_exists?(config)
86
+ !!ActiveRecord::Base.sqlserver_connection(config)
87
+ rescue ActiveRecord::NoDatabaseError
88
+ false
89
+ end
90
+
83
91
  def supports_ddl_transactions?
84
92
  true
85
93
  end
@@ -144,10 +152,30 @@ module ActiveRecord
144
152
  true
145
153
  end
146
154
 
155
+ def supports_lazy_transactions?
156
+ true
157
+ end
158
+
147
159
  def supports_in_memory_oltp?
148
160
  @version_year >= 2014
149
161
  end
150
162
 
163
+ def supports_insert_returning?
164
+ true
165
+ end
166
+
167
+ def supports_insert_on_duplicate_skip?
168
+ false
169
+ end
170
+
171
+ def supports_insert_on_duplicate_update?
172
+ false
173
+ end
174
+
175
+ def supports_insert_conflict_target?
176
+ false
177
+ end
178
+
151
179
  def disable_referential_integrity
152
180
  tables = tables_with_referential_integrity
153
181
  tables.each { |t| do_execute "ALTER TABLE #{quote_table_name(t)} NOCHECK CONSTRAINT ALL" }
@@ -160,7 +188,8 @@ module ActiveRecord
160
188
 
161
189
  def active?
162
190
  return false unless @connection
163
- raw_connection_do 'SELECT 1'
191
+
192
+ raw_connection_do "SELECT 1"
164
193
  true
165
194
  rescue *connection_errors
166
195
  false
@@ -190,13 +219,13 @@ module ActiveRecord
190
219
 
191
220
  def reset!
192
221
  reset_transaction
193
- do_execute 'IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION'
222
+ do_execute "IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION"
194
223
  end
195
224
 
196
225
  # === Abstract Adapter (Misc Support) =========================== #
197
226
 
198
227
  def tables_with_referential_integrity
199
- schemas_and_tables = select_rows <<-SQL.strip_heredoc
228
+ schemas_and_tables = select_rows <<~SQL.squish
200
229
  SELECT DISTINCT s.name, o.name
201
230
  FROM sys.foreign_keys i
202
231
  INNER JOIN sys.objects o ON i.parent_object_id = o.OBJECT_ID
@@ -225,6 +254,7 @@ module ActiveRecord
225
254
 
226
255
  def database_prefix_remote_server?
227
256
  return false if database_prefix.blank?
257
+
228
258
  name = SQLServer::Utils.extract_identifiers(database_prefix)
229
259
  name.fully_qualified? && name.object.blank?
230
260
  end
@@ -256,37 +286,40 @@ module ActiveRecord
256
286
  result
257
287
  end
258
288
 
289
+ def get_database_version # :nodoc:
290
+ version_year
291
+ end
259
292
 
260
293
  protected
261
294
 
262
295
  # === Abstract Adapter (Misc Support) =========================== #
263
296
 
264
297
  def initialize_type_map(m = type_map)
265
- m.register_type %r{.*}, SQLServer::Type::UnicodeString.new
298
+ m.register_type %r{.*}, SQLServer::Type::UnicodeString.new
266
299
  # Exact Numerics
267
- register_class_with_limit m, 'bigint(8)', SQLServer::Type::BigInteger
268
- m.alias_type 'bigint', 'bigint(8)'
269
- register_class_with_limit m, 'int(4)', SQLServer::Type::Integer
270
- m.alias_type 'integer', 'int(4)'
271
- m.alias_type 'int', 'int(4)'
272
- register_class_with_limit m, 'smallint(2)', SQLServer::Type::SmallInteger
273
- m.alias_type 'smallint', 'smallint(2)'
274
- register_class_with_limit m, 'tinyint(1)', SQLServer::Type::TinyInteger
275
- m.alias_type 'tinyint', 'tinyint(1)'
276
- m.register_type 'bit', SQLServer::Type::Boolean.new
300
+ register_class_with_limit m, "bigint(8)", SQLServer::Type::BigInteger
301
+ m.alias_type "bigint", "bigint(8)"
302
+ register_class_with_limit m, "int(4)", SQLServer::Type::Integer
303
+ m.alias_type "integer", "int(4)"
304
+ m.alias_type "int", "int(4)"
305
+ register_class_with_limit m, "smallint(2)", SQLServer::Type::SmallInteger
306
+ m.alias_type "smallint", "smallint(2)"
307
+ register_class_with_limit m, "tinyint(1)", SQLServer::Type::TinyInteger
308
+ m.alias_type "tinyint", "tinyint(1)"
309
+ m.register_type "bit", SQLServer::Type::Boolean.new
277
310
  m.register_type %r{\Adecimal}i do |sql_type|
278
311
  scale = extract_scale(sql_type)
279
312
  precision = extract_precision(sql_type)
280
313
  SQLServer::Type::Decimal.new precision: precision, scale: scale
281
314
  end
282
- m.alias_type %r{\Anumeric}i, 'decimal'
283
- m.register_type 'money', SQLServer::Type::Money.new
284
- m.register_type 'smallmoney', SQLServer::Type::SmallMoney.new
315
+ m.alias_type %r{\Anumeric}i, "decimal"
316
+ m.register_type "money", SQLServer::Type::Money.new
317
+ m.register_type "smallmoney", SQLServer::Type::SmallMoney.new
285
318
  # Approximate Numerics
286
- m.register_type 'float', SQLServer::Type::Float.new
287
- m.register_type 'real', SQLServer::Type::Real.new
319
+ m.register_type "float", SQLServer::Type::Float.new
320
+ m.register_type "real", SQLServer::Type::Real.new
288
321
  # Date and Time
289
- m.register_type 'date', SQLServer::Type::Date.new
322
+ m.register_type "date", SQLServer::Type::Date.new
290
323
  m.register_type %r{\Adatetime} do |sql_type|
291
324
  precision = extract_precision(sql_type)
292
325
  if precision
@@ -295,11 +328,11 @@ module ActiveRecord
295
328
  SQLServer::Type::DateTime.new
296
329
  end
297
330
  end
298
- m.register_type %r{\Adatetimeoffset}i do |sql_type|
331
+ m.register_type %r{\Adatetimeoffset}i do |sql_type|
299
332
  precision = extract_precision(sql_type)
300
333
  SQLServer::Type::DateTimeOffset.new precision: precision
301
334
  end
302
- m.register_type 'smalldatetime', SQLServer::Type::SmallDateTime.new
335
+ m.register_type "smalldatetime", SQLServer::Type::SmallDateTime.new
303
336
  m.register_type %r{\Atime}i do |sql_type|
304
337
  precision = extract_precision(sql_type) || DEFAULT_TIME_PRECISION
305
338
  SQLServer::Type::Time.new precision: precision
@@ -307,36 +340,38 @@ module ActiveRecord
307
340
  # Character Strings
308
341
  register_class_with_limit m, %r{\Achar}i, SQLServer::Type::Char
309
342
  register_class_with_limit m, %r{\Avarchar}i, SQLServer::Type::Varchar
310
- m.register_type 'varchar(max)', SQLServer::Type::VarcharMax.new
311
- m.register_type 'text', SQLServer::Type::Text.new
343
+ m.register_type "varchar(max)", SQLServer::Type::VarcharMax.new
344
+ m.register_type "text", SQLServer::Type::Text.new
312
345
  # Unicode Character Strings
313
346
  register_class_with_limit m, %r{\Anchar}i, SQLServer::Type::UnicodeChar
314
347
  register_class_with_limit m, %r{\Anvarchar}i, SQLServer::Type::UnicodeVarchar
315
- m.alias_type 'string', 'nvarchar(4000)'
316
- m.register_type 'nvarchar(max)', SQLServer::Type::UnicodeVarcharMax.new
317
- m.register_type 'nvarchar(max)', SQLServer::Type::UnicodeVarcharMax.new
318
- m.register_type 'ntext', SQLServer::Type::UnicodeText.new
348
+ m.alias_type "string", "nvarchar(4000)"
349
+ m.register_type "nvarchar(max)", SQLServer::Type::UnicodeVarcharMax.new
350
+ m.register_type "nvarchar(max)", SQLServer::Type::UnicodeVarcharMax.new
351
+ m.register_type "ntext", SQLServer::Type::UnicodeText.new
319
352
  # Binary Strings
320
353
  register_class_with_limit m, %r{\Abinary}i, SQLServer::Type::Binary
321
354
  register_class_with_limit m, %r{\Avarbinary}i, SQLServer::Type::Varbinary
322
- m.register_type 'varbinary(max)', SQLServer::Type::VarbinaryMax.new
355
+ m.register_type "varbinary(max)", SQLServer::Type::VarbinaryMax.new
323
356
  # Other Data Types
324
- m.register_type 'uniqueidentifier', SQLServer::Type::Uuid.new
325
- m.register_type 'timestamp', SQLServer::Type::Timestamp.new
357
+ m.register_type "uniqueidentifier", SQLServer::Type::Uuid.new
358
+ m.register_type "timestamp", SQLServer::Type::Timestamp.new
326
359
  end
327
360
 
328
- def translate_exception(e, message)
361
+ def translate_exception(e, message:, sql:, binds:)
329
362
  case message
330
363
  when /(cannot insert duplicate key .* with unique index) | (violation of unique key constraint)/i
331
- RecordNotUnique.new(message)
332
- when /conflicted with the foreign key constraint/i
333
- InvalidForeignKey.new(message)
364
+ RecordNotUnique.new(message, sql: sql, binds: binds)
365
+ when /(conflicted with the foreign key constraint) | (The DELETE statement conflicted with the REFERENCE constraint)/i
366
+ InvalidForeignKey.new(message, sql: sql, binds: binds)
334
367
  when /has been chosen as the deadlock victim/i
335
- DeadlockVictim.new(message)
368
+ DeadlockVictim.new(message, sql: sql, binds: binds)
336
369
  when /database .* does not exist/i
337
- NoDatabaseError.new(message)
370
+ NoDatabaseError.new(message, sql: sql, binds: binds)
338
371
  when /data would be truncated/
339
- ValueTooLong.new(message)
372
+ ValueTooLong.new(message, sql: sql, binds: binds)
373
+ when /connection timed out/
374
+ StatementTimeout.new(message, sql: sql, binds: binds)
340
375
  when /Column '(.*)' is not the same data type as referencing column '(.*)' in foreign key/
341
376
  pk_id, fk_id = SQLServer::Utils.extract_identifiers($1), SQLServer::Utils.extract_identifiers($2)
342
377
  MismatchedForeignKey.new(
@@ -348,9 +383,9 @@ module ActiveRecord
348
383
  primary_key: pk_id.object
349
384
  )
350
385
  when /Cannot insert the value NULL into column.*does not allow nulls/
351
- NotNullViolation.new(message)
386
+ NotNullViolation.new(message, sql: sql, binds: binds)
352
387
  when /Arithmetic overflow error/
353
- RangeError.new(message)
388
+ RangeError.new(message, sql: sql, binds: binds)
354
389
  else
355
390
  super
356
391
  end
@@ -364,7 +399,7 @@ module ActiveRecord
364
399
  when :dblib
365
400
  dblib_connect(config)
366
401
  end
367
- @spid = _raw_select('SELECT @@SPID', fetch: :rows).first.first
402
+ @spid = _raw_select("SELECT @@SPID", fetch: :rows).first.first
368
403
  @version_year = version_year
369
404
  configure_connection
370
405
  end
@@ -383,32 +418,32 @@ module ActiveRecord
383
418
  username: config[:username],
384
419
  password: config[:password],
385
420
  database: config[:database],
386
- tds_version: config[:tds_version] || '7.3',
421
+ tds_version: config[:tds_version] || "7.3",
387
422
  appname: config_appname(config),
388
423
  login_timeout: config_login_timeout(config),
389
424
  timeout: config_timeout(config),
390
- encoding: config_encoding(config),
425
+ encoding: config_encoding(config),
391
426
  azure: config[:azure],
392
427
  contained: config[:contained]
393
428
  ).tap do |client|
394
429
  if config[:azure]
395
- client.execute('SET ANSI_NULLS ON').do
396
- client.execute('SET ANSI_NULL_DFLT_ON ON').do
397
- client.execute('SET ANSI_PADDING ON').do
398
- client.execute('SET ANSI_WARNINGS ON').do
430
+ client.execute("SET ANSI_NULLS ON").do
431
+ client.execute("SET ANSI_NULL_DFLT_ON ON").do
432
+ client.execute("SET ANSI_PADDING ON").do
433
+ client.execute("SET ANSI_WARNINGS ON").do
399
434
  else
400
- client.execute('SET ANSI_DEFAULTS ON').do
435
+ client.execute("SET ANSI_DEFAULTS ON").do
401
436
  end
402
- client.execute('SET QUOTED_IDENTIFIER ON').do
403
- client.execute('SET CURSOR_CLOSE_ON_COMMIT OFF').do
404
- client.execute('SET IMPLICIT_TRANSACTIONS OFF').do
405
- client.execute('SET TEXTSIZE 2147483647').do
406
- client.execute('SET CONCAT_NULL_YIELDS_NULL ON').do
437
+ client.execute("SET QUOTED_IDENTIFIER ON").do
438
+ client.execute("SET CURSOR_CLOSE_ON_COMMIT OFF").do
439
+ client.execute("SET IMPLICIT_TRANSACTIONS OFF").do
440
+ client.execute("SET TEXTSIZE 2147483647").do
441
+ client.execute("SET CONCAT_NULL_YIELDS_NULL ON").do
407
442
  end
408
443
  end
409
444
 
410
445
  def config_appname(config)
411
- config[:appname] || configure_application_name || Rails.application.class.name.split('::').first rescue nil
446
+ config[:appname] || configure_application_name || Rails.application.class.name.split("::").first rescue nil
412
447
  end
413
448
 
414
449
  def config_login_timeout(config)
@@ -423,18 +458,18 @@ module ActiveRecord
423
458
  config[:encoding].present? ? config[:encoding] : nil
424
459
  end
425
460
 
426
- def configure_connection ; end
461
+ def configure_connection; end
427
462
 
428
- def configure_application_name ; end
463
+ def configure_application_name; end
429
464
 
430
465
  def initialize_dateformatter
431
466
  @database_dateformat = user_options_dateformat
432
467
  a, b, c = @database_dateformat.each_char.to_a
433
- [a, b, c].each { |f| f.upcase! if f == 'y' }
468
+ [a, b, c].each { |f| f.upcase! if f == "y" }
434
469
  dateformat = "%#{a}-%#{b}-%#{c}"
435
470
  ::Date::DATE_FORMATS[:_sqlserver_dateformat] = dateformat
436
471
  ::Time::DATE_FORMATS[:_sqlserver_dateformat] = dateformat
437
- ::Time::DATE_FORMATS[:_sqlserver_time] = '%H:%M:%S'
472
+ ::Time::DATE_FORMATS[:_sqlserver_time] = "%H:%M:%S"
438
473
  ::Time::DATE_FORMATS[:_sqlserver_datetime] = "#{dateformat} %H:%M:%S"
439
474
  ::Time::DATE_FORMATS[:_sqlserver_datetimeoffset] = lambda { |time|
440
475
  time.strftime "#{dateformat} %H:%M:%S.%9N #{time.formatted_offset}"
@@ -443,13 +478,14 @@ module ActiveRecord
443
478
 
444
479
  def version_year
445
480
  return 2016 if sqlserver_version =~ /vNext/
481
+
446
482
  /SQL Server (\d+)/.match(sqlserver_version).to_a.last.to_s.to_i
447
- rescue StandardError => e
483
+ rescue StandardError
448
484
  2016
449
485
  end
450
486
 
451
487
  def sqlserver_version
452
- @sqlserver_version ||= _raw_select('SELECT @@version', fetch: :rows).first.first.to_s
488
+ @sqlserver_version ||= _raw_select("SELECT @@version", fetch: :rows).first.first.to_s
453
489
  end
454
490
  end
455
491
  end
@@ -1,10 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters
3
5
  class SQLServerColumn < Column
4
-
5
- def initialize(name, default, sql_type_metadata = nil, null = true, table_name = nil, default_function = nil, collation = nil, comment = nil, sqlserver_options = {})
6
- @sqlserver_options = sqlserver_options || {}
7
- super(name, default, sql_type_metadata, null, table_name, default_function, collation, comment: comment)
6
+ def initialize(name, default, sql_type_metadata = nil, null = true, default_function = nil, collation: nil, comment: nil, **sqlserver_options)
7
+ @sqlserver_options = sqlserver_options
8
+ super
8
9
  end
9
10
 
10
11
  def is_identity?
@@ -15,6 +16,10 @@ module ActiveRecord
15
16
  @sqlserver_options[:is_primary]
16
17
  end
17
18
 
19
+ def table_name
20
+ @sqlserver_options[:table_name]
21
+ end
22
+
18
23
  def is_utf8?
19
24
  sql_type =~ /nvarchar|ntext|nchar/i
20
25
  end
@@ -22,7 +27,6 @@ module ActiveRecord
22
27
  def case_sensitive?
23
28
  collation && collation.match(/_CS/)
24
29
  end
25
-
26
30
  end
27
31
  end
28
32
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionHandling
3
5
  def sqlserver_connection(config) #:nodoc:
@@ -6,11 +8,17 @@ module ActiveRecord
6
8
  mode = config[:mode].to_s.downcase.underscore.to_sym
7
9
  case mode
8
10
  when :dblib
9
- require 'tiny_tds'
11
+ require "tiny_tds"
10
12
  else
11
13
  raise ArgumentError, "Unknown connection mode in #{config.inspect}."
12
14
  end
13
15
  ConnectionAdapters::SQLServerAdapter.new(nil, nil, config.merge(mode: mode))
16
+ rescue TinyTds::Error => e
17
+ if e.message.match(/database .* does not exist/i)
18
+ raise ActiveRecord::NoDatabaseError
19
+ else
20
+ raise
21
+ end
14
22
  end
15
23
  end
16
24
  end
@@ -1,14 +1,14 @@
1
- require 'active_record/tasks/database_tasks'
2
- require 'shellwords'
3
- require 'ipaddr'
4
- require 'socket'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_record/tasks/database_tasks"
4
+ require "shellwords"
5
+ require "ipaddr"
6
+ require "socket"
5
7
 
6
8
  module ActiveRecord
7
9
  module Tasks
8
-
9
10
  class SQLServerDatabaseTasks
10
-
11
- DEFAULT_COLLATION = 'SQL_Latin1_General_CP1_CI_AS'
11
+ DEFAULT_COLLATION = "SQL_Latin1_General_CP1_CI_AS"
12
12
 
13
13
  delegate :connection, :establish_connection, :clear_active_connections!,
14
14
  to: ActiveRecord::Base
@@ -19,10 +19,10 @@ module ActiveRecord
19
19
 
20
20
  def create(master_established = false)
21
21
  establish_master_connection unless master_established
22
- connection.create_database configuration['database'], configuration.merge('collation' => default_collation)
22
+ connection.create_database configuration["database"], configuration.merge("collation" => default_collation)
23
23
  establish_connection configuration
24
- rescue ActiveRecord::StatementInvalid => error
25
- if /database .* already exists/i === error.message
24
+ rescue ActiveRecord::StatementInvalid => e
25
+ if /database .* already exists/i === e.message
26
26
  raise DatabaseAlreadyExists
27
27
  else
28
28
  raise
@@ -31,7 +31,7 @@ module ActiveRecord
31
31
 
32
32
  def drop
33
33
  establish_master_connection
34
- connection.drop_database configuration['database']
34
+ connection.drop_database configuration["database"]
35
35
  end
36
36
 
37
37
  def charset
@@ -50,7 +50,7 @@ module ActiveRecord
50
50
 
51
51
  def structure_dump(filename, extra_flags)
52
52
  server_arg = "-S #{Shellwords.escape(configuration['host'])}"
53
- server_arg += ":#{Shellwords.escape(configuration['port'])}" if configuration['port']
53
+ server_arg += ":#{Shellwords.escape(configuration['port'])}" if configuration["port"]
54
54
  command = [
55
55
  "defncopy-ttds",
56
56
  server_arg,
@@ -63,13 +63,14 @@ module ActiveRecord
63
63
  command.concat(table_args)
64
64
  view_args = connection.views.map { |v| Shellwords.escape(v) }
65
65
  command.concat(view_args)
66
- raise 'Error dumping database' unless Kernel.system(command.join(' '))
66
+ raise "Error dumping database" unless Kernel.system(command.join(" "))
67
+
67
68
  dump = File.read(filename)
68
- dump.gsub!(/^USE .*$\nGO\n/, '') # Strip db USE statements
69
- dump.gsub!(/^GO\n/, '') # Strip db GO statements
70
- dump.gsub!(/nvarchar\(8000\)/, 'nvarchar(4000)') # Fix nvarchar(8000) column defs
71
- dump.gsub!(/nvarchar\(-1\)/, 'nvarchar(max)') # Fix nvarchar(-1) column defs
72
- dump.gsub!(/text\(\d+\)/, 'text') # Fix text(16) column defs
69
+ dump.gsub!(/^USE .*$\nGO\n/, "") # Strip db USE statements
70
+ dump.gsub!(/^GO\n/, "") # Strip db GO statements
71
+ dump.gsub!(/nvarchar\(8000\)/, "nvarchar(4000)") # Fix nvarchar(8000) column defs
72
+ dump.gsub!(/nvarchar\(-1\)/, "nvarchar(max)") # Fix nvarchar(-1) column defs
73
+ dump.gsub!(/text\(\d+\)/, "text") # Fix text(16) column defs
73
74
  File.open(filename, "w") { |file| file.puts dump }
74
75
  end
75
76
 
@@ -77,7 +78,6 @@ module ActiveRecord
77
78
  connection.execute File.read(filename)
78
79
  end
79
80
 
80
-
81
81
  private
82
82
 
83
83
  def configuration
@@ -85,25 +85,22 @@ module ActiveRecord
85
85
  end
86
86
 
87
87
  def default_collation
88
- configuration['collation'] || DEFAULT_COLLATION
88
+ configuration["collation"] || DEFAULT_COLLATION
89
89
  end
90
90
 
91
91
  def establish_master_connection
92
- establish_connection configuration.merge('database' => 'master')
92
+ establish_connection configuration.merge("database" => "master")
93
93
  end
94
-
95
94
  end
96
95
 
97
96
  module DatabaseTasksSQLServer
98
-
99
97
  extend ActiveSupport::Concern
100
98
 
101
99
  module ClassMethods
102
-
103
100
  LOCAL_IPADDR = [
104
- IPAddr.new('192.168.0.0/16'),
105
- IPAddr.new('10.0.0.0/8'),
106
- IPAddr.new('172.16.0.0/12')
101
+ IPAddr.new("192.168.0.0/16"),
102
+ IPAddr.new("10.0.0.0/8"),
103
+ IPAddr.new("172.16.0.0/12")
107
104
  ]
108
105
 
109
106
  private
@@ -113,21 +110,20 @@ module ActiveRecord
113
110
  end
114
111
 
115
112
  def configuration_host_ip(configuration)
116
- return nil unless configuration['host']
117
- Socket::getaddrinfo(configuration['host'], 'echo', Socket::AF_INET)[0][3]
113
+ return nil unless configuration["host"]
114
+
115
+ Socket::getaddrinfo(configuration["host"], "echo", Socket::AF_INET)[0][3]
118
116
  end
119
117
 
120
118
  def local_ipaddr?(host_ip)
121
119
  return false unless host_ip
120
+
122
121
  LOCAL_IPADDR.any? { |ip| ip.include?(host_ip) }
123
122
  end
124
-
125
123
  end
126
-
127
124
  end
128
125
 
129
126
  DatabaseTasks.register_task %r{sqlserver}, SQLServerDatabaseTasks
130
127
  DatabaseTasks.send :include, DatabaseTasksSQLServer
131
-
132
128
  end
133
129
  end
@@ -1 +1,3 @@
1
- require 'active_record/connection_adapters/sqlserver_adapter'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_record/connection_adapters/sqlserver_adapter"