activerecord-sqlserver-adapter 5.2.1 → 6.0.0

Sign up to get free protection for your applications and to get access to all the features.
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"