activerecord-sqlserver-adapter 6.1.2.1 → 7.2.4

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 (97) hide show
  1. checksums.yaml +4 -4
  2. data/.devcontainer/Dockerfile +30 -0
  3. data/.devcontainer/boot.sh +22 -0
  4. data/.devcontainer/devcontainer.json +38 -0
  5. data/.devcontainer/docker-compose.yml +42 -0
  6. data/.github/workflows/ci.yml +7 -4
  7. data/.gitignore +3 -1
  8. data/CHANGELOG.md +19 -42
  9. data/Dockerfile.ci +3 -3
  10. data/Gemfile +6 -1
  11. data/MIT-LICENSE +1 -1
  12. data/README.md +113 -27
  13. data/RUNNING_UNIT_TESTS.md +27 -14
  14. data/Rakefile +2 -6
  15. data/VERSION +1 -1
  16. data/activerecord-sqlserver-adapter.gemspec +3 -3
  17. data/appveyor.yml +4 -6
  18. data/docker-compose.ci.yml +2 -1
  19. data/lib/active_record/connection_adapters/sqlserver/core_ext/abstract_adapter.rb +20 -0
  20. data/lib/active_record/connection_adapters/sqlserver/core_ext/attribute_methods.rb +6 -4
  21. data/lib/active_record/connection_adapters/sqlserver/core_ext/calculations.rb +5 -23
  22. data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +10 -7
  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 +12 -2
  25. data/lib/active_record/connection_adapters/sqlserver/core_ext/preloader.rb +24 -16
  26. data/lib/active_record/connection_adapters/sqlserver/database_limits.rb +0 -31
  27. data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +143 -155
  28. data/lib/active_record/connection_adapters/sqlserver/database_tasks.rb +5 -5
  29. data/lib/active_record/connection_adapters/sqlserver/quoting.rb +57 -56
  30. data/lib/active_record/connection_adapters/sqlserver/savepoints.rb +26 -0
  31. data/lib/active_record/connection_adapters/sqlserver/schema_creation.rb +14 -12
  32. data/lib/active_record/connection_adapters/sqlserver/schema_dumper.rb +11 -0
  33. data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +213 -57
  34. data/lib/active_record/connection_adapters/sqlserver/showplan.rb +3 -3
  35. data/lib/active_record/connection_adapters/sqlserver/table_definition.rb +13 -2
  36. data/lib/active_record/connection_adapters/sqlserver/transaction.rb +4 -6
  37. data/lib/active_record/connection_adapters/sqlserver/type/data.rb +19 -1
  38. data/lib/active_record/connection_adapters/sqlserver/type/date.rb +1 -1
  39. data/lib/active_record/connection_adapters/sqlserver/type/datetime.rb +1 -1
  40. data/lib/active_record/connection_adapters/sqlserver/type/time.rb +1 -1
  41. data/lib/active_record/connection_adapters/sqlserver/utils.rb +21 -10
  42. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +187 -187
  43. data/lib/active_record/connection_adapters/sqlserver_column.rb +1 -0
  44. data/lib/active_record/tasks/sqlserver_database_tasks.rb +42 -33
  45. data/lib/arel/visitors/sqlserver.rb +77 -34
  46. data/test/cases/active_schema_test_sqlserver.rb +127 -0
  47. data/test/cases/adapter_test_sqlserver.rb +114 -26
  48. data/test/cases/coerced_tests.rb +1121 -340
  49. data/test/cases/column_test_sqlserver.rb +67 -64
  50. data/test/cases/connection_test_sqlserver.rb +3 -6
  51. data/test/cases/dbconsole.rb +19 -0
  52. data/test/cases/disconnected_test_sqlserver.rb +8 -5
  53. data/test/cases/eager_load_too_many_ids_test_sqlserver.rb +18 -0
  54. data/test/cases/enum_test_sqlserver.rb +49 -0
  55. data/test/cases/execute_procedure_test_sqlserver.rb +9 -5
  56. data/test/cases/fetch_test_sqlserver.rb +19 -0
  57. data/test/cases/helper_sqlserver.rb +11 -5
  58. data/test/cases/index_test_sqlserver.rb +8 -6
  59. data/test/cases/json_test_sqlserver.rb +1 -1
  60. data/test/cases/lateral_test_sqlserver.rb +2 -2
  61. data/test/cases/migration_test_sqlserver.rb +19 -1
  62. data/test/cases/optimizer_hints_test_sqlserver.rb +21 -12
  63. data/test/cases/pessimistic_locking_test_sqlserver.rb +8 -7
  64. data/test/cases/primary_keys_test_sqlserver.rb +2 -2
  65. data/test/cases/rake_test_sqlserver.rb +10 -5
  66. data/test/cases/schema_dumper_test_sqlserver.rb +155 -109
  67. data/test/cases/schema_test_sqlserver.rb +64 -1
  68. data/test/cases/showplan_test_sqlserver.rb +7 -7
  69. data/test/cases/specific_schema_test_sqlserver.rb +17 -13
  70. data/test/cases/transaction_test_sqlserver.rb +13 -8
  71. data/test/cases/trigger_test_sqlserver.rb +20 -0
  72. data/test/cases/utils_test_sqlserver.rb +2 -2
  73. data/test/cases/uuid_test_sqlserver.rb +8 -0
  74. data/test/cases/view_test_sqlserver.rb +58 -0
  75. data/test/config.yml +1 -2
  76. data/test/migrations/transaction_table/1_table_will_never_be_created.rb +1 -1
  77. data/test/models/sqlserver/alien.rb +5 -0
  78. data/test/models/sqlserver/table_with_spaces.rb +5 -0
  79. data/test/models/sqlserver/trigger.rb +8 -0
  80. data/test/schema/sqlserver_specific_schema.rb +54 -6
  81. data/test/support/coerceable_test_sqlserver.rb +4 -4
  82. data/test/support/connection_reflection.rb +3 -9
  83. data/test/support/core_ext/query_cache.rb +7 -1
  84. data/test/support/marshal_compatibility_fixtures/SQLServer/rails_6_1_topic.dump +0 -0
  85. data/test/support/marshal_compatibility_fixtures/SQLServer/rails_6_1_topic_associations.dump +0 -0
  86. data/test/support/marshal_compatibility_fixtures/SQLServer/rails_7_1_topic.dump +0 -0
  87. data/test/support/marshal_compatibility_fixtures/SQLServer/rails_7_1_topic_associations.dump +0 -0
  88. data/test/support/query_assertions.rb +49 -0
  89. data/test/support/rake_helpers.rb +3 -1
  90. data/test/support/table_definition_sqlserver.rb +24 -0
  91. data/test/support/test_in_memory_oltp.rb +2 -2
  92. metadata +41 -17
  93. data/lib/active_record/sqlserver_base.rb +0 -18
  94. data/test/cases/scratchpad_test_sqlserver.rb +0 -8
  95. data/test/support/marshal_compatibility_fixtures/SQLServer/rails_6_0_topic.dump +0 -0
  96. data/test/support/marshal_compatibility_fixtures/SQLServer/rails_6_0_topic_associations.dump +0 -0
  97. data/test/support/sql_counter_sqlserver.rb +0 -29
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "tiny_tds"
3
4
  require "base64"
4
5
  require "active_record"
5
6
  require "arel_sqlserver"
@@ -11,11 +12,13 @@ require "active_record/connection_adapters/sqlserver/core_ext/explain_subscriber
11
12
  require "active_record/connection_adapters/sqlserver/core_ext/attribute_methods"
12
13
  require "active_record/connection_adapters/sqlserver/core_ext/finder_methods"
13
14
  require "active_record/connection_adapters/sqlserver/core_ext/preloader"
15
+ require "active_record/connection_adapters/sqlserver/core_ext/abstract_adapter"
14
16
  require "active_record/connection_adapters/sqlserver/version"
15
17
  require "active_record/connection_adapters/sqlserver/type"
16
18
  require "active_record/connection_adapters/sqlserver/database_limits"
17
19
  require "active_record/connection_adapters/sqlserver/database_statements"
18
20
  require "active_record/connection_adapters/sqlserver/database_tasks"
21
+ require "active_record/connection_adapters/sqlserver/savepoints"
19
22
  require "active_record/connection_adapters/sqlserver/transaction"
20
23
  require "active_record/connection_adapters/sqlserver/errors"
21
24
  require "active_record/connection_adapters/sqlserver/schema_creation"
@@ -26,12 +29,13 @@ require "active_record/connection_adapters/sqlserver/showplan"
26
29
  require "active_record/connection_adapters/sqlserver/table_definition"
27
30
  require "active_record/connection_adapters/sqlserver/quoting"
28
31
  require "active_record/connection_adapters/sqlserver/utils"
29
- require "active_record/sqlserver_base"
30
32
  require "active_record/connection_adapters/sqlserver_column"
31
33
  require "active_record/tasks/sqlserver_database_tasks"
32
34
 
33
35
  module ActiveRecord
34
36
  module ConnectionAdapters
37
+ register "sqlserver", "ActiveRecord::ConnectionAdapters::SQLServerAdapter", "active_record/connection_adapters/sqlserver_adapter"
38
+
35
39
  class SQLServerAdapter < AbstractAdapter
36
40
  include SQLServer::Version,
37
41
  SQLServer::Quoting,
@@ -39,7 +43,8 @@ module ActiveRecord
39
43
  SQLServer::Showplan,
40
44
  SQLServer::SchemaStatements,
41
45
  SQLServer::DatabaseLimits,
42
- SQLServer::DatabaseTasks
46
+ SQLServer::DatabaseTasks,
47
+ SQLServer::Savepoints
43
48
 
44
49
  ADAPTER_NAME = "SQLServer".freeze
45
50
 
@@ -59,63 +64,31 @@ module ActiveRecord
59
64
  self.exclude_output_inserted_table_names = Concurrent::Map.new { false }
60
65
 
61
66
  class << self
62
- def new_client(config)
63
- case config[:mode]
64
- when :dblib
65
- require "tiny_tds"
66
- dblib_connect(config)
67
- else
68
- raise ArgumentError, "Unknown connection mode in #{config.inspect}."
67
+ def dbconsole(config, options = {})
68
+ sqlserver_config = config.configuration_hash
69
+ args = []
70
+
71
+ args += ["-d", "#{config.database}"] if config.database
72
+ args += ["-U", "#{sqlserver_config[:username]}"] if sqlserver_config[:username]
73
+ args += ["-P", "#{sqlserver_config[:password]}"] if sqlserver_config[:password]
74
+
75
+ if sqlserver_config[:host]
76
+ host_arg = +"tcp:#{sqlserver_config[:host]}"
77
+ host_arg << ",#{sqlserver_config[:port]}" if sqlserver_config[:port]
78
+ args += ["-S", host_arg]
69
79
  end
70
- end
71
80
 
72
- def dblib_connect(config)
73
- TinyTds::Client.new(
74
- dataserver: config[:dataserver],
75
- host: config[:host],
76
- port: config[:port],
77
- username: config[:username],
78
- password: config[:password],
79
- database: config[:database],
80
- tds_version: config[:tds_version] || "7.3",
81
- appname: config_appname(config),
82
- login_timeout: config_login_timeout(config),
83
- timeout: config_timeout(config),
84
- encoding: config_encoding(config),
85
- azure: config[:azure],
86
- contained: config[:contained]
87
- ).tap do |client|
88
- if config[:azure]
89
- client.execute("SET ANSI_NULLS ON").do
90
- client.execute("SET ANSI_NULL_DFLT_ON ON").do
91
- client.execute("SET ANSI_PADDING ON").do
92
- client.execute("SET ANSI_WARNINGS ON").do
93
- else
94
- client.execute("SET ANSI_DEFAULTS ON").do
95
- end
96
- client.execute("SET QUOTED_IDENTIFIER ON").do
97
- client.execute("SET CURSOR_CLOSE_ON_COMMIT OFF").do
98
- client.execute("SET IMPLICIT_TRANSACTIONS OFF").do
99
- client.execute("SET TEXTSIZE 2147483647").do
100
- client.execute("SET CONCAT_NULL_YIELDS_NULL ON").do
101
- end
102
- rescue TinyTds::Error => e
103
- raise ActiveRecord::NoDatabaseError if e.message.match(/database .* does not exist/i)
104
- raise e
81
+ find_cmd_and_exec("sqlcmd", *args)
105
82
  end
106
83
 
107
- def config_appname(config)
108
- if self.instance_methods.include?(:configure_application_name)
109
- ActiveSupport::Deprecation.warn <<~MSG.squish
110
- Configuring the application name used by TinyTDS by overriding the
111
- `ActiveRecord::ConnectionAdapters::SQLServerAdapter#configure_application_name`
112
- instance method is no longer supported. The application name should configured
113
- using the `appname` setting in the `database.yml` file instead. Consult the
114
- README for further information."
115
- MSG
84
+ def new_client(config)
85
+ TinyTds::Client.new(config)
86
+ rescue TinyTds::Error => error
87
+ if error.message.match(/database .* does not exist/i)
88
+ raise ActiveRecord::NoDatabaseError
89
+ else
90
+ raise
116
91
  end
117
-
118
- config[:appname] || rails_application_name
119
92
  end
120
93
 
121
94
  def rails_application_name
@@ -123,30 +96,24 @@ module ActiveRecord
123
96
  rescue
124
97
  nil # Might not be in a Rails context so we fallback to `nil`.
125
98
  end
99
+ end
126
100
 
127
- def config_login_timeout(config)
128
- config[:login_timeout].present? ? config[:login_timeout].to_i : nil
129
- end
130
-
131
- def config_timeout(config)
132
- config[:timeout].present? ? config[:timeout].to_i / 1000 : nil
133
- end
101
+ def initialize(...)
102
+ super
134
103
 
135
- def config_encoding(config)
136
- config[:encoding].present? ? config[:encoding] : nil
137
- end
138
- end
104
+ @config[:tds_version] = "7.3" unless @config[:tds_version]
105
+ @config[:appname] = self.class.rails_application_name unless @config[:appname]
106
+ @config[:login_timeout] = @config[:login_timeout].present? ? @config[:login_timeout].to_i : nil
107
+ @config[:timeout] = @config[:timeout].present? ? @config[:timeout].to_i / 1000 : nil
108
+ @config[:encoding] = @config[:encoding].present? ? @config[:encoding] : nil
139
109
 
140
- def initialize(connection, logger, _connection_options, config)
141
- super(connection, logger, config)
142
- @connection_options = config
143
- configure_connection
110
+ @connection_parameters ||= @config
144
111
  end
145
112
 
146
113
  # === Abstract Adapter ========================================== #
147
114
 
148
115
  def arel_visitor
149
- Arel::Visitors::SQLServer.new self
116
+ Arel::Visitors::SQLServer.new(self)
150
117
  end
151
118
 
152
119
  def valid_type?(type)
@@ -154,13 +121,7 @@ module ActiveRecord
154
121
  end
155
122
 
156
123
  def schema_creation
157
- SQLServer::SchemaCreation.new self
158
- end
159
-
160
- def self.database_exists?(config)
161
- !!ActiveRecord::Base.sqlserver_connection(config)
162
- rescue ActiveRecord::NoDatabaseError
163
- false
124
+ SQLServer::SchemaCreation.new(self)
164
125
  end
165
126
 
166
127
  def supports_ddl_transactions?
@@ -211,8 +172,12 @@ module ActiveRecord
211
172
  true
212
173
  end
213
174
 
175
+ def supports_check_constraints?
176
+ true
177
+ end
178
+
214
179
  def supports_json?
215
- @version_year >= 2016
180
+ version_year >= 2016
216
181
  end
217
182
 
218
183
  def supports_comments?
@@ -231,12 +196,16 @@ module ActiveRecord
231
196
  true
232
197
  end
233
198
 
199
+ def supports_common_table_expressions?
200
+ true
201
+ end
202
+
234
203
  def supports_lazy_transactions?
235
204
  true
236
205
  end
237
206
 
238
207
  def supports_in_memory_oltp?
239
- @version_year >= 2014
208
+ version_year >= 2014
240
209
  end
241
210
 
242
211
  def supports_insert_returning?
@@ -255,58 +224,52 @@ module ActiveRecord
255
224
  false
256
225
  end
257
226
 
227
+ def return_value_after_insert?(column) # :nodoc:
228
+ column.is_primary? || column.is_identity?
229
+ end
230
+
258
231
  def disable_referential_integrity
259
232
  tables = tables_with_referential_integrity
260
- tables.each { |t| do_execute "ALTER TABLE #{quote_table_name(t)} NOCHECK CONSTRAINT ALL" }
233
+ tables.each { |t| execute "ALTER TABLE #{quote_table_name(t)} NOCHECK CONSTRAINT ALL" }
261
234
  yield
262
235
  ensure
263
- tables.each { |t| do_execute "ALTER TABLE #{quote_table_name(t)} CHECK CONSTRAINT ALL" }
236
+ tables.each { |t| execute "ALTER TABLE #{quote_table_name(t)} CHECK CONSTRAINT ALL" }
264
237
  end
265
238
 
266
239
  # === Abstract Adapter (Connection Management) ================== #
267
240
 
268
241
  def active?
269
- return false unless @connection
270
-
271
- raw_connection_do "SELECT 1"
272
- true
242
+ @raw_connection&.active?
273
243
  rescue *connection_errors
274
244
  false
275
245
  end
276
246
 
277
- def reconnect!
278
- super
279
- disconnect!
247
+ def reconnect
248
+ @raw_connection&.close rescue nil
249
+ @raw_connection = nil
250
+ @spid = nil
251
+ @collation = nil
252
+
280
253
  connect
281
254
  end
282
255
 
283
256
  def disconnect!
284
257
  super
285
- case @connection_options[:mode]
286
- when :dblib
287
- @connection.close rescue nil
288
- end
289
- @connection = nil
258
+
259
+ @raw_connection&.close rescue nil
260
+ @raw_connection = nil
290
261
  @spid = nil
291
262
  @collation = nil
292
263
  end
293
264
 
294
- def clear_cache!
265
+ def clear_cache!(...)
295
266
  @view_information = nil
296
267
  super
297
268
  end
298
269
 
299
270
  def reset!
300
271
  reset_transaction
301
- do_execute "IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION"
302
- end
303
-
304
- def configure_connection
305
- @spid = _raw_select("SELECT @@SPID", fetch: :rows).first.first
306
- @version_year = version_year
307
-
308
- initialize_dateformatter
309
- use_database
272
+ execute "IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION"
310
273
  end
311
274
 
312
275
  # === Abstract Adapter (Misc Support) =========================== #
@@ -347,7 +310,7 @@ module ActiveRecord
347
310
  end
348
311
 
349
312
  def database_prefix
350
- @connection_options[:database_prefix]
313
+ @connection_parameters[:database_prefix]
351
314
  end
352
315
 
353
316
  def database_prefix_identifier(name)
@@ -362,10 +325,6 @@ module ActiveRecord
362
325
  self.class::VERSION
363
326
  end
364
327
 
365
- def inspect
366
- "#<#{self.class} version: #{version}, mode: #{@connection_options[:mode]}, azure: #{sqlserver_azure?.inspect}>"
367
- end
368
-
369
328
  def combine_bind_parameters(from_clause: [], join_clause: [], where_clause: [], having_clause: [], limit: nil, offset: nil)
370
329
  result = from_clause + join_clause + where_clause + having_clause
371
330
  result << offset if offset
@@ -377,83 +336,99 @@ module ActiveRecord
377
336
  version_year
378
337
  end
379
338
 
380
- protected
381
-
382
- # === Abstract Adapter (Misc Support) =========================== #
339
+ def check_version # :nodoc:
340
+ if schema_cache.database_version < 2012
341
+ raise "Your version of SQL Server (#{database_version}) is too old. SQL Server Active Record supports 2012 or higher."
342
+ end
343
+ end
383
344
 
384
- def initialize_type_map(m = type_map)
385
- m.register_type %r{.*}, SQLServer::Type::UnicodeString.new
386
-
387
- # Exact Numerics
388
- register_class_with_limit m, "bigint(8)", SQLServer::Type::BigInteger
389
- m.alias_type "bigint", "bigint(8)"
390
- register_class_with_limit m, "int(4)", SQLServer::Type::Integer
391
- m.alias_type "integer", "int(4)"
392
- m.alias_type "int", "int(4)"
393
- register_class_with_limit m, "smallint(2)", SQLServer::Type::SmallInteger
394
- m.alias_type "smallint", "smallint(2)"
395
- register_class_with_limit m, "tinyint(1)", SQLServer::Type::TinyInteger
396
- m.alias_type "tinyint", "tinyint(1)"
397
- m.register_type "bit", SQLServer::Type::Boolean.new
398
- m.register_type %r{\Adecimal}i do |sql_type|
399
- scale = extract_scale(sql_type)
400
- precision = extract_precision(sql_type)
401
- if scale == 0
402
- SQLServer::Type::DecimalWithoutScale.new(precision: precision)
403
- else
404
- SQLServer::Type::Decimal.new(precision: precision, scale: scale)
345
+ class << self
346
+ protected
347
+
348
+ def initialize_type_map(m)
349
+ m.register_type %r{.*}, SQLServer::Type::UnicodeString.new
350
+
351
+ # Exact Numerics
352
+ register_class_with_limit m, "bigint(8)", SQLServer::Type::BigInteger
353
+ m.alias_type "bigint", "bigint(8)"
354
+ register_class_with_limit m, "int(4)", SQLServer::Type::Integer
355
+ m.alias_type "integer", "int(4)"
356
+ m.alias_type "int", "int(4)"
357
+ register_class_with_limit m, "smallint(2)", SQLServer::Type::SmallInteger
358
+ m.alias_type "smallint", "smallint(2)"
359
+ register_class_with_limit m, "tinyint(1)", SQLServer::Type::TinyInteger
360
+ m.alias_type "tinyint", "tinyint(1)"
361
+ m.register_type "bit", SQLServer::Type::Boolean.new
362
+ m.register_type %r{\Adecimal}i do |sql_type|
363
+ scale = extract_scale(sql_type)
364
+ precision = extract_precision(sql_type)
365
+ if scale == 0
366
+ SQLServer::Type::DecimalWithoutScale.new(precision: precision)
367
+ else
368
+ SQLServer::Type::Decimal.new(precision: precision, scale: scale)
369
+ end
405
370
  end
406
- end
407
- m.alias_type %r{\Anumeric}i, "decimal"
408
- m.register_type "money", SQLServer::Type::Money.new
409
- m.register_type "smallmoney", SQLServer::Type::SmallMoney.new
410
-
411
- # Approximate Numerics
412
- m.register_type "float", SQLServer::Type::Float.new
413
- m.register_type "real", SQLServer::Type::Real.new
414
-
415
- # Date and Time
416
- m.register_type "date", SQLServer::Type::Date.new
417
- m.register_type %r{\Adatetime} do |sql_type|
418
- precision = extract_precision(sql_type)
419
- if precision
420
- SQLServer::Type::DateTime2.new precision: precision
421
- else
422
- SQLServer::Type::DateTime.new
371
+ m.alias_type %r{\Anumeric}i, "decimal"
372
+ m.register_type "money", SQLServer::Type::Money.new
373
+ m.register_type "smallmoney", SQLServer::Type::SmallMoney.new
374
+
375
+ # Approximate Numerics
376
+ m.register_type "float", SQLServer::Type::Float.new
377
+ m.register_type "real", SQLServer::Type::Real.new
378
+
379
+ # Date and Time
380
+ m.register_type "date", SQLServer::Type::Date.new
381
+ m.register_type %r{\Adatetime} do |sql_type|
382
+ precision = extract_precision(sql_type)
383
+ if precision
384
+ SQLServer::Type::DateTime2.new precision: precision
385
+ else
386
+ SQLServer::Type::DateTime.new
387
+ end
423
388
  end
389
+ m.register_type %r{\Adatetimeoffset}i do |sql_type|
390
+ precision = extract_precision(sql_type)
391
+ SQLServer::Type::DateTimeOffset.new precision: precision
392
+ end
393
+ m.register_type "smalldatetime", SQLServer::Type::SmallDateTime.new
394
+ m.register_type %r{\Atime}i do |sql_type|
395
+ precision = extract_precision(sql_type) || DEFAULT_TIME_PRECISION
396
+ SQLServer::Type::Time.new precision: precision
397
+ end
398
+
399
+ # Character Strings
400
+ register_class_with_limit m, %r{\Achar}i, SQLServer::Type::Char
401
+ register_class_with_limit m, %r{\Avarchar}i, SQLServer::Type::Varchar
402
+ m.register_type "varchar(max)", SQLServer::Type::VarcharMax.new
403
+ m.register_type "text", SQLServer::Type::Text.new
404
+
405
+ # Unicode Character Strings
406
+ register_class_with_limit m, %r{\Anchar}i, SQLServer::Type::UnicodeChar
407
+ register_class_with_limit m, %r{\Anvarchar}i, SQLServer::Type::UnicodeVarchar
408
+ m.alias_type "string", "nvarchar(4000)"
409
+ m.register_type "nvarchar(max)", SQLServer::Type::UnicodeVarcharMax.new
410
+ m.register_type "nvarchar(max)", SQLServer::Type::UnicodeVarcharMax.new
411
+ m.register_type "ntext", SQLServer::Type::UnicodeText.new
412
+
413
+ # Binary Strings
414
+ register_class_with_limit m, %r{\Abinary}i, SQLServer::Type::Binary
415
+ register_class_with_limit m, %r{\Avarbinary}i, SQLServer::Type::Varbinary
416
+ m.register_type "varbinary(max)", SQLServer::Type::VarbinaryMax.new
417
+
418
+ # Other Data Types
419
+ m.register_type "uniqueidentifier", SQLServer::Type::Uuid.new
420
+ m.register_type "timestamp", SQLServer::Type::Timestamp.new
424
421
  end
425
- m.register_type %r{\Adatetimeoffset}i do |sql_type|
426
- precision = extract_precision(sql_type)
427
- SQLServer::Type::DateTimeOffset.new precision: precision
428
- end
429
- m.register_type "smalldatetime", SQLServer::Type::SmallDateTime.new
430
- m.register_type %r{\Atime}i do |sql_type|
431
- precision = extract_precision(sql_type) || DEFAULT_TIME_PRECISION
432
- SQLServer::Type::Time.new precision: precision
433
- end
422
+ end
434
423
 
435
- # Character Strings
436
- register_class_with_limit m, %r{\Achar}i, SQLServer::Type::Char
437
- register_class_with_limit m, %r{\Avarchar}i, SQLServer::Type::Varchar
438
- m.register_type "varchar(max)", SQLServer::Type::VarcharMax.new
439
- m.register_type "text", SQLServer::Type::Text.new
424
+ TYPE_MAP = Type::TypeMap.new.tap { |m| initialize_type_map(m) }
440
425
 
441
- # Unicode Character Strings
442
- register_class_with_limit m, %r{\Anchar}i, SQLServer::Type::UnicodeChar
443
- register_class_with_limit m, %r{\Anvarchar}i, SQLServer::Type::UnicodeVarchar
444
- m.alias_type "string", "nvarchar(4000)"
445
- m.register_type "nvarchar(max)", SQLServer::Type::UnicodeVarcharMax.new
446
- m.register_type "nvarchar(max)", SQLServer::Type::UnicodeVarcharMax.new
447
- m.register_type "ntext", SQLServer::Type::UnicodeText.new
426
+ protected
448
427
 
449
- # Binary Strings
450
- register_class_with_limit m, %r{\Abinary}i, SQLServer::Type::Binary
451
- register_class_with_limit m, %r{\Avarbinary}i, SQLServer::Type::Varbinary
452
- m.register_type "varbinary(max)", SQLServer::Type::VarbinaryMax.new
428
+ # === Abstract Adapter (Misc Support) =========================== #
453
429
 
454
- # Other Data Types
455
- m.register_type "uniqueidentifier", SQLServer::Type::Uuid.new
456
- m.register_type "timestamp", SQLServer::Type::Timestamp.new
430
+ def type_map
431
+ TYPE_MAP
457
432
  end
458
433
 
459
434
  def translate_exception(e, message:, sql:, binds:)
@@ -467,7 +442,7 @@ module ActiveRecord
467
442
  when /has been chosen as the deadlock victim/i
468
443
  DeadlockVictim.new(message, sql: sql, binds: binds)
469
444
  when /database .* does not exist/i
470
- NoDatabaseError.new(message, sql: sql, binds: binds)
445
+ NoDatabaseError.new(message)
471
446
  when /data would be truncated/
472
447
  ValueTooLong.new(message, sql: sql, binds: binds)
473
448
  when /connection timed out/
@@ -494,7 +469,7 @@ module ActiveRecord
494
469
  # === SQLServer Specific (Connection Management) ================ #
495
470
 
496
471
  def connection_errors
497
- @connection_errors ||= [].tap do |errors|
472
+ @raw_connection_errors ||= [].tap do |errors|
498
473
  errors << TinyTds::Error if defined?(TinyTds::Error)
499
474
  end
500
475
  end
@@ -515,22 +490,47 @@ module ActiveRecord
515
490
  end
516
491
 
517
492
  def version_year
518
- return 2016 if sqlserver_version =~ /vNext/
519
-
520
- /SQL Server (\d+)/.match(sqlserver_version).to_a.last.to_s.to_i
521
- rescue StandardError
522
- 2016
493
+ @version_year ||= begin
494
+ if sqlserver_version =~ /vNext/
495
+ 2016
496
+ else
497
+ /SQL Server (\d+)/.match(sqlserver_version).to_a.last.to_s.to_i
498
+ end
499
+ rescue StandardError
500
+ 2016
501
+ end
523
502
  end
524
503
 
525
504
  def sqlserver_version
526
- @sqlserver_version ||= _raw_select("SELECT @@version", fetch: :rows).first.first.to_s
505
+ @sqlserver_version ||= _raw_select("SELECT @@version", @raw_connection).first.first.to_s
527
506
  end
528
507
 
529
508
  private
530
509
 
531
510
  def connect
532
- @connection = self.class.new_client(@connection_options)
533
- configure_connection
511
+ @raw_connection = self.class.new_client(@connection_parameters)
512
+ end
513
+
514
+ def configure_connection
515
+ if @config[:azure]
516
+ @raw_connection.execute("SET ANSI_NULLS ON").do
517
+ @raw_connection.execute("SET ANSI_NULL_DFLT_ON ON").do
518
+ @raw_connection.execute("SET ANSI_PADDING ON").do
519
+ @raw_connection.execute("SET ANSI_WARNINGS ON").do
520
+ else
521
+ @raw_connection.execute("SET ANSI_DEFAULTS ON").do
522
+ end
523
+
524
+ @raw_connection.execute("SET QUOTED_IDENTIFIER ON").do
525
+ @raw_connection.execute("SET CURSOR_CLOSE_ON_COMMIT OFF").do
526
+ @raw_connection.execute("SET IMPLICIT_TRANSACTIONS OFF").do
527
+ @raw_connection.execute("SET TEXTSIZE 2147483647").do
528
+ @raw_connection.execute("SET CONCAT_NULL_YIELDS_NULL ON").do
529
+
530
+ @spid = _raw_select("SELECT @@SPID", @raw_connection).first.first
531
+
532
+ initialize_dateformatter
533
+ use_database
534
534
  end
535
535
  end
536
536
  end
@@ -17,6 +17,7 @@ module ActiveRecord
17
17
  def is_identity?
18
18
  is_identity
19
19
  end
20
+ alias_method :auto_incremented_by_db?, :is_identity?
20
21
 
21
22
  def is_primary?
22
23
  is_primary