activerecord-sqlserver-adapter 4.2.18 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -223
  3. data/Gemfile +18 -17
  4. data/RAILS5-TODO.md +36 -0
  5. data/README.md +27 -8
  6. data/RUNNING_UNIT_TESTS.md +0 -17
  7. data/Rakefile +2 -7
  8. data/VERSION +1 -1
  9. data/activerecord-sqlserver-adapter.gemspec +1 -1
  10. data/appveyor.yml +0 -2
  11. data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +15 -8
  12. data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +45 -97
  13. data/lib/active_record/connection_adapters/sqlserver/database_tasks.rb +1 -2
  14. data/lib/active_record/connection_adapters/sqlserver/quoting.rb +31 -10
  15. data/lib/active_record/connection_adapters/sqlserver/schema_creation.rb +0 -18
  16. data/lib/active_record/connection_adapters/sqlserver/schema_dumper.rb +16 -0
  17. data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +101 -58
  18. data/lib/active_record/connection_adapters/sqlserver/showplan.rb +7 -7
  19. data/lib/active_record/connection_adapters/sqlserver/sql_type_metadata.rb +20 -0
  20. data/lib/active_record/connection_adapters/sqlserver/table_definition.rb +56 -32
  21. data/lib/active_record/connection_adapters/sqlserver/transaction.rb +1 -1
  22. data/lib/active_record/connection_adapters/sqlserver/type.rb +34 -32
  23. data/lib/active_record/connection_adapters/sqlserver/type/big_integer.rb +4 -0
  24. data/lib/active_record/connection_adapters/sqlserver/type/binary.rb +6 -0
  25. data/lib/active_record/connection_adapters/sqlserver/type/boolean.rb +3 -0
  26. data/lib/active_record/connection_adapters/sqlserver/type/char.rb +9 -20
  27. data/lib/active_record/connection_adapters/sqlserver/type/data.rb +30 -0
  28. data/lib/active_record/connection_adapters/sqlserver/type/date.rb +28 -4
  29. data/lib/active_record/connection_adapters/sqlserver/type/datetime.rb +28 -14
  30. data/lib/active_record/connection_adapters/sqlserver/type/datetime2.rb +2 -2
  31. data/lib/active_record/connection_adapters/sqlserver/type/datetimeoffset.rb +4 -16
  32. data/lib/active_record/connection_adapters/sqlserver/type/decimal.rb +9 -0
  33. data/lib/active_record/connection_adapters/sqlserver/type/float.rb +4 -0
  34. data/lib/active_record/connection_adapters/sqlserver/type/integer.rb +3 -0
  35. data/lib/active_record/connection_adapters/sqlserver/type/money.rb +5 -1
  36. data/lib/active_record/connection_adapters/sqlserver/type/real.rb +4 -0
  37. data/lib/active_record/connection_adapters/sqlserver/type/small_integer.rb +3 -1
  38. data/lib/active_record/connection_adapters/sqlserver/type/small_money.rb +5 -1
  39. data/lib/active_record/connection_adapters/sqlserver/type/smalldatetime.rb +8 -1
  40. data/lib/active_record/connection_adapters/sqlserver/type/text.rb +4 -0
  41. data/lib/active_record/connection_adapters/sqlserver/type/time.rb +20 -8
  42. data/lib/active_record/connection_adapters/sqlserver/type/time_value_fractional.rb +25 -10
  43. data/lib/active_record/connection_adapters/sqlserver/type/timestamp.rb +4 -0
  44. data/lib/active_record/connection_adapters/sqlserver/type/tiny_integer.rb +3 -0
  45. data/lib/active_record/connection_adapters/sqlserver/type/unicode_char.rb +6 -0
  46. data/lib/active_record/connection_adapters/sqlserver/type/unicode_text.rb +4 -0
  47. data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar.rb +7 -1
  48. data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar_max.rb +5 -1
  49. data/lib/active_record/connection_adapters/sqlserver/type/uuid.rb +15 -2
  50. data/lib/active_record/connection_adapters/sqlserver/type/varbinary.rb +7 -1
  51. data/lib/active_record/connection_adapters/sqlserver/type/varbinary_max.rb +5 -1
  52. data/lib/active_record/connection_adapters/sqlserver/type/varchar.rb +7 -1
  53. data/lib/active_record/connection_adapters/sqlserver/type/varchar_max.rb +5 -1
  54. data/lib/active_record/connection_adapters/sqlserver/utils.rb +10 -0
  55. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +71 -57
  56. data/lib/active_record/connection_adapters/sqlserver_column.rb +5 -30
  57. data/lib/active_record/sqlserver_base.rb +1 -5
  58. data/lib/arel/visitors/sqlserver.rb +11 -20
  59. data/test/bin/setup.sh +4 -6
  60. data/test/cases/adapter_test_sqlserver.rb +11 -20
  61. data/test/cases/coerced_tests.rb +233 -138
  62. data/test/cases/column_test_sqlserver.rb +244 -227
  63. data/test/cases/connection_test_sqlserver.rb +5 -76
  64. data/test/cases/fully_qualified_identifier_test_sqlserver.rb +7 -7
  65. data/test/cases/helper_sqlserver.rb +4 -15
  66. data/test/cases/pessimistic_locking_test_sqlserver.rb +1 -1
  67. data/test/cases/rake_test_sqlserver.rb +20 -14
  68. data/test/cases/schema_dumper_test_sqlserver.rb +94 -63
  69. data/test/cases/schema_test_sqlserver.rb +2 -2
  70. data/test/cases/showplan_test_sqlserver.rb +1 -1
  71. data/test/cases/specific_schema_test_sqlserver.rb +7 -14
  72. data/test/cases/transaction_test_sqlserver.rb +1 -1
  73. data/test/cases/uuid_test_sqlserver.rb +0 -1
  74. data/test/config.yml +0 -10
  75. data/test/migrations/transaction_table/1_table_will_never_be_created.rb +1 -1
  76. data/test/schema/sqlserver_specific_schema.rb +0 -16
  77. data/test/support/coerceable_test_sqlserver.rb +6 -2
  78. data/test/support/connection_reflection.rb +0 -4
  79. data/test/support/sql_counter_sqlserver.rb +17 -21
  80. metadata +9 -7
  81. data/lib/active_record/connection_adapters/sqlserver/core_ext/odbc.rb +0 -34
  82. data/lib/active_record/connection_adapters/sqlserver/schema_cache.rb +0 -114
@@ -8,10 +8,17 @@ module ActiveRecord
8
8
  :smalldatetime
9
9
  end
10
10
 
11
+ def sqlserver_type
12
+ 'smalldatetime'.freeze
13
+ end
11
14
 
12
15
  private
13
16
 
14
- def cast_fractional(value)
17
+ def fast_string_to_time_format
18
+ ::Time::DATE_FORMATS[:_sqlserver_datetime]
19
+ end
20
+
21
+ def apply_seconds_precision(value)
15
22
  value.change usec: 0
16
23
  end
17
24
 
@@ -8,6 +8,10 @@ module ActiveRecord
8
8
  :text_basic
9
9
  end
10
10
 
11
+ def sqlserver_type
12
+ 'text'.freeze
13
+ end
14
+
11
15
  end
12
16
  end
13
17
  end
@@ -6,27 +6,39 @@ module ActiveRecord
6
6
 
7
7
  include TimeValueFractional2
8
8
 
9
- def type_cast_for_database(value)
10
- return super unless value.acts_like?(:time)
11
- time = value.to_s(:_sqlserver_time)
12
- "#{time}".tap do |v|
9
+ def serialize(value)
10
+ value = super
11
+ return value unless value.acts_like?(:time)
12
+ time = value.to_s(:_sqlserver_time).tap do |v|
13
13
  fraction = quote_fractional(value)
14
- v << ".#{fraction}" unless fraction.to_i.zero?
14
+ v << ".#{fraction}"
15
15
  end
16
+ Data.new time, self
17
+ end
18
+
19
+ def deserialize(value)
20
+ value.is_a?(Data) ? super(value.value) : super
16
21
  end
17
22
 
18
23
  def type_cast_for_schema(value)
19
- type_cast_for_database(value).inspect
24
+ serialize(value).quoted
20
25
  end
21
26
 
27
+ def sqlserver_type
28
+ "time(#{precision.to_i})"
29
+ end
30
+
31
+ def quoted(value)
32
+ Utils.quote_string_single(value)
33
+ end
22
34
 
23
35
  private
24
36
 
25
37
  def cast_value(value)
26
- value = value.acts_like?(:time) ? value : super
38
+ value = super
27
39
  return if value.blank?
28
40
  value = value.change year: 2000, month: 01, day: 01
29
- cast_fractional(value)
41
+ apply_seconds_precision(value)
30
42
  end
31
43
 
32
44
  def fractional_scale
@@ -7,20 +7,22 @@ module ActiveRecord
7
7
 
8
8
  private
9
9
 
10
- def cast_fractional(value)
10
+ def apply_seconds_precision(value)
11
11
  return value if !value.respond_to?(fractional_property) || value.send(fractional_property).zero?
12
- frac_seconds = if fractional_scale == 0
13
- 0
14
- else
15
- seconds = value.send(fractional_property).to_f / fractional_operator.to_f
16
- seconds = ((seconds * (1 / fractional_precision)).round / (1 / fractional_precision)).round(fractional_scale)
17
- (seconds * fractional_operator).to_i
18
- end
19
- value.change fractional_property => frac_seconds
12
+ value.change fractional_property => seconds_precision(value)
13
+ end
14
+
15
+ def seconds_precision(value)
16
+ return 0 if fractional_scale == 0
17
+ seconds = value.send(fractional_property).to_f / fractional_operator.to_f
18
+ seconds = ((seconds * (1 / fractional_precision)).round / (1 / fractional_precision)).round(fractional_scale)
19
+ (seconds * fractional_operator).round(0).to_i
20
20
  end
21
21
 
22
22
  def quote_fractional(value)
23
- seconds = (value.send(fractional_property).to_f / fractional_operator.to_f).round(fractional_scale)
23
+ return 0 if fractional_scale == 0
24
+ frac_seconds = seconds_precision(value)
25
+ seconds = (frac_seconds.to_f / fractional_operator.to_f).round(fractional_scale)
24
26
  seconds.to_d.to_s.split('.').last.to(fractional_scale-1)
25
27
  end
26
28
 
@@ -52,6 +54,11 @@ module ActiveRecord
52
54
 
53
55
  private
54
56
 
57
+ def seconds_precision(value)
58
+ seconds = super
59
+ seconds > fractional_max ? fractional_scale_max : seconds
60
+ end
61
+
55
62
  def fractional_property
56
63
  :nsec
57
64
  end
@@ -68,6 +75,14 @@ module ActiveRecord
68
75
  precision
69
76
  end
70
77
 
78
+ def fractional_max
79
+ 999999999
80
+ end
81
+
82
+ def fractional_scale_max
83
+ ('9' * fractional_scale) + ('0' * (fractional_digits - fractional_scale))
84
+ end
85
+
71
86
  end
72
87
 
73
88
  end
@@ -8,6 +8,10 @@ module ActiveRecord
8
8
  :ss_timestamp
9
9
  end
10
10
 
11
+ def sqlserver_type
12
+ 'timestamp'.freeze
13
+ end
14
+
11
15
  end
12
16
  end
13
17
  end
@@ -4,6 +4,9 @@ module ActiveRecord
4
4
  module Type
5
5
  class TinyInteger < Integer
6
6
 
7
+ def sqlserver_type
8
+ 'tinyint'.freeze
9
+ end
7
10
 
8
11
  private
9
12
 
@@ -8,6 +8,12 @@ module ActiveRecord
8
8
  :nchar
9
9
  end
10
10
 
11
+ def sqlserver_type
12
+ 'nchar'.tap do |type|
13
+ type << "(#{limit})" if limit
14
+ end
15
+ end
16
+
11
17
  end
12
18
  end
13
19
  end
@@ -8,6 +8,10 @@ module ActiveRecord
8
8
  :ntext
9
9
  end
10
10
 
11
+ def sqlserver_type
12
+ 'ntext'.freeze
13
+ end
14
+
11
15
  end
12
16
  end
13
17
  end
@@ -4,7 +4,7 @@ module ActiveRecord
4
4
  module Type
5
5
  class UnicodeVarchar < UnicodeChar
6
6
 
7
- def initialize(options = {})
7
+ def initialize(*args)
8
8
  super
9
9
  @limit = 4000 if @limit.to_i == 0
10
10
  end
@@ -13,6 +13,12 @@ module ActiveRecord
13
13
  :string
14
14
  end
15
15
 
16
+ def sqlserver_type
17
+ 'nvarchar'.tap do |type|
18
+ type << "(#{limit})" if limit
19
+ end
20
+ end
21
+
16
22
  end
17
23
  end
18
24
  end
@@ -4,7 +4,7 @@ module ActiveRecord
4
4
  module Type
5
5
  class UnicodeVarcharMax < UnicodeVarchar
6
6
 
7
- def initialize(options = {})
7
+ def initialize(*args)
8
8
  super
9
9
  @limit = 2_147_483_647
10
10
  end
@@ -13,6 +13,10 @@ module ActiveRecord
13
13
  :text
14
14
  end
15
15
 
16
+ def sqlserver_type
17
+ 'nvarchar(max)'.freeze
18
+ end
19
+
16
20
  end
17
21
  end
18
22
  end
@@ -6,16 +6,29 @@ module ActiveRecord
6
6
 
7
7
  ACCEPTABLE_UUID = %r{\A\{?([a-fA-F0-9]{4}-?){8}\}?\z}x
8
8
 
9
- alias_method :type_cast_for_database, :type_cast_from_database
9
+ alias_method :serialize, :deserialize
10
10
 
11
11
  def type
12
12
  :uuid
13
13
  end
14
14
 
15
- def type_cast(value)
15
+ def sqlserver_type
16
+ 'uniqueidentifier'.freeze
17
+ end
18
+
19
+ def serialize(value)
20
+ return unless value
21
+ Data.new super, self
22
+ end
23
+
24
+ def cast(value)
16
25
  value.to_s[ACCEPTABLE_UUID, 0]
17
26
  end
18
27
 
28
+ def quoted(value)
29
+ Utils.quote_string_single(value) if value
30
+ end
31
+
19
32
  end
20
33
  end
21
34
  end
@@ -4,7 +4,7 @@ module ActiveRecord
4
4
  module Type
5
5
  class Varbinary < Binary
6
6
 
7
- def initialize(options = {})
7
+ def initialize(*args)
8
8
  super
9
9
  @limit = 8000 if @limit.to_i == 0
10
10
  end
@@ -13,6 +13,12 @@ module ActiveRecord
13
13
  :varbinary
14
14
  end
15
15
 
16
+ def sqlserver_type
17
+ 'varbinary'.tap do |type|
18
+ type << "(#{limit})" if limit
19
+ end
20
+ end
21
+
16
22
  end
17
23
  end
18
24
  end
@@ -4,7 +4,7 @@ module ActiveRecord
4
4
  module Type
5
5
  class VarbinaryMax < Varbinary
6
6
 
7
- def initialize(options = {})
7
+ def initialize(*args)
8
8
  super
9
9
  @limit = 2_147_483_647
10
10
  end
@@ -13,6 +13,10 @@ module ActiveRecord
13
13
  :binary
14
14
  end
15
15
 
16
+ def sqlserver_type
17
+ 'varbinary(max)'.freeze
18
+ end
19
+
16
20
  end
17
21
  end
18
22
  end
@@ -4,7 +4,7 @@ module ActiveRecord
4
4
  module Type
5
5
  class Varchar < Char
6
6
 
7
- def initialize(options = {})
7
+ def initialize(*args)
8
8
  super
9
9
  @limit = 8000 if @limit.to_i == 0
10
10
  end
@@ -13,6 +13,12 @@ module ActiveRecord
13
13
  :varchar
14
14
  end
15
15
 
16
+ def sqlserver_type
17
+ 'varchar'.tap do |type|
18
+ type << "(#{limit})" if limit
19
+ end
20
+ end
21
+
16
22
  end
17
23
  end
18
24
  end
@@ -4,7 +4,7 @@ module ActiveRecord
4
4
  module Type
5
5
  class VarcharMax < Varchar
6
6
 
7
- def initialize(options = {})
7
+ def initialize(*args)
8
8
  super
9
9
  @limit = 2_147_483_647
10
10
  end
@@ -13,6 +13,10 @@ module ActiveRecord
13
13
  :varchar_max
14
14
  end
15
15
 
16
+ def sqlserver_type
17
+ 'varchar(max)'.freeze
18
+ end
19
+
16
20
  end
17
21
  end
18
22
  end
@@ -5,6 +5,8 @@ module ActiveRecord
5
5
  module SQLServer
6
6
  module Utils
7
7
 
8
+ QUOTED_STRING_PREFIX = 'N'
9
+
8
10
  # Value object to return identifiers from SQL Server names http://bit.ly/1CZ3EiL
9
11
  # Inspiried from Rails PostgreSQL::Name adapter object in their own Utils.
10
12
  #
@@ -118,6 +120,14 @@ module ActiveRecord
118
120
  s.to_s.gsub /\'/, "''"
119
121
  end
120
122
 
123
+ def quote_string_single(s)
124
+ "'#{quote_string(s)}'"
125
+ end
126
+
127
+ def quote_string_single_national(s)
128
+ "#{QUOTED_STRING_PREFIX}'#{quote_string(s)}'"
129
+ end
130
+
121
131
  def quoted_raw(name)
122
132
  SQLServer::Utils::Name.new(name).quoted_raw
123
133
  end
@@ -13,9 +13,10 @@ require 'active_record/connection_adapters/sqlserver/database_statements'
13
13
  require 'active_record/connection_adapters/sqlserver/database_tasks'
14
14
  require 'active_record/connection_adapters/sqlserver/transaction'
15
15
  require 'active_record/connection_adapters/sqlserver/errors'
16
- require 'active_record/connection_adapters/sqlserver/schema_cache'
17
16
  require 'active_record/connection_adapters/sqlserver/schema_creation'
17
+ require 'active_record/connection_adapters/sqlserver/schema_dumper'
18
18
  require 'active_record/connection_adapters/sqlserver/schema_statements'
19
+ require 'active_record/connection_adapters/sqlserver/sql_type_metadata'
19
20
  require 'active_record/connection_adapters/sqlserver/showplan'
20
21
  require 'active_record/connection_adapters/sqlserver/table_definition'
21
22
  require 'active_record/connection_adapters/sqlserver/quoting'
@@ -32,6 +33,7 @@ module ActiveRecord
32
33
  SQLServer::Quoting,
33
34
  SQLServer::DatabaseStatements,
34
35
  SQLServer::Showplan,
36
+ SQLServer::SchemaDumper,
35
37
  SQLServer::SchemaStatements,
36
38
  SQLServer::DatabaseLimits,
37
39
  SQLServer::DatabaseTasks
@@ -42,27 +44,27 @@ module ActiveRecord
42
44
 
43
45
  cattr_accessor :cs_equality_operator, instance_accessor: false
44
46
  cattr_accessor :use_output_inserted, instance_accessor: false
45
- cattr_accessor :lowercase_schema_reflection, :showplan_option
47
+ cattr_accessor :showplan_option, instance_accessor: false
48
+ cattr_accessor :lowercase_schema_reflection
46
49
 
47
50
  self.cs_equality_operator = 'COLLATE Latin1_General_CS_AS_WS'
48
51
  self.use_output_inserted = true
49
52
 
50
- def initialize(connection, logger, pool, config)
51
- super(connection, logger, pool)
52
- # AbstractAdapter Responsibility
53
- @schema_cache = SQLServer::SchemaCache.new self
54
- @visitor = Arel::Visitors::SQLServer.new self
55
- @prepared_statements = true
53
+ def initialize(connection, logger = nil, config = {})
54
+ super(connection, logger, config)
56
55
  # Our Responsibility
57
56
  @connection_options = config
58
57
  connect
59
- @sqlserver_azure = !!(select_value('SELECT @@version', 'SCHEMA') =~ /Azure/i)
60
58
  initialize_dateformatter
61
59
  use_database
62
60
  end
63
61
 
64
62
  # === Abstract Adapter ========================================== #
65
63
 
64
+ def arel_visitor
65
+ Arel::Visitors::SQLServer.new self
66
+ end
67
+
66
68
  def valid_type?(type)
67
69
  !native_database_types[type].nil?
68
70
  end
@@ -71,10 +73,6 @@ module ActiveRecord
71
73
  SQLServer::SchemaCreation.new self
72
74
  end
73
75
 
74
- def adapter_name
75
- ADAPTER_NAME
76
- end
77
-
78
76
  def supports_migrations?
79
77
  true
80
78
  end
@@ -83,10 +81,6 @@ module ActiveRecord
83
81
  true
84
82
  end
85
83
 
86
- def supports_count_distinct?
87
- true
88
- end
89
-
90
84
  def supports_ddl_transactions?
91
85
  true
92
86
  end
@@ -95,14 +89,26 @@ module ActiveRecord
95
89
  false
96
90
  end
97
91
 
92
+ def supports_advisory_locks?
93
+ false
94
+ end
95
+
98
96
  def supports_index_sort_order?
99
97
  true
100
98
  end
101
99
 
100
+ def supports_index_sort_order?
101
+ false
102
+ end
103
+
102
104
  def supports_partial_index?
103
105
  true
104
106
  end
105
107
 
108
+ def supports_expression_index?
109
+ false
110
+ end
111
+
106
112
  def supports_explain?
107
113
  true
108
114
  end
@@ -111,14 +117,34 @@ module ActiveRecord
111
117
  true
112
118
  end
113
119
 
120
+ def supports_indexes_in_create?
121
+ false
122
+ end
123
+
124
+ def supports_foreign_keys?
125
+ true
126
+ end
127
+
114
128
  def supports_views?
115
129
  true
116
130
  end
117
131
 
118
- def supports_foreign_keys?
132
+ def supports_datetime_with_precision?
119
133
  true
120
134
  end
121
135
 
136
+ def supports_json?
137
+ true
138
+ end
139
+
140
+ def supports_comments?
141
+ false
142
+ end
143
+
144
+ def supports_comments_in_create?
145
+ false
146
+ end
147
+
122
148
  def disable_referential_integrity
123
149
  tables = tables_with_referential_integrity
124
150
  tables.each { |t| do_execute "ALTER TABLE #{t} NOCHECK CONSTRAINT ALL" }
@@ -145,16 +171,19 @@ module ActiveRecord
145
171
 
146
172
  def disconnect!
147
173
  super
148
- @spid = nil
149
174
  case @connection_options[:mode]
150
175
  when :dblib
151
176
  @connection.close rescue nil
152
- when :odbc
153
- @connection.disconnect rescue nil
154
177
  end
155
178
  @connection = nil
156
179
  end
157
180
 
181
+ def clear_cache!
182
+ @spid = nil
183
+ @collation = nil
184
+ super
185
+ end
186
+
158
187
  def reset!
159
188
  reset_transaction
160
189
  do_execute 'IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION'
@@ -180,10 +209,6 @@ module ActiveRecord
180
209
  pk ? [pk, nil] : nil
181
210
  end
182
211
 
183
- def primary_key(table_name)
184
- schema_cache.columns(table_name).find(&:is_primary?).try(:name) || identity_column(table_name).try(:name)
185
- end
186
-
187
212
  # === SQLServer Specific (DB Reflection) ======================== #
188
213
 
189
214
  def sqlserver?
@@ -191,7 +216,7 @@ module ActiveRecord
191
216
  end
192
217
 
193
218
  def sqlserver_azure?
194
- @sqlserver_azure
219
+ @sqlserver_azure ||= !!(select_value('SELECT @@version', 'SCHEMA') =~ /Azure/i)
195
220
  end
196
221
 
197
222
  def database_prefix_remote_server?
@@ -212,6 +237,13 @@ module ActiveRecord
212
237
  "#<#{self.class} version: #{version}, mode: #{@connection_options[:mode]}, azure: #{sqlserver_azure?.inspect}>"
213
238
  end
214
239
 
240
+ def combine_bind_parameters(from_clause: [], join_clause: [], where_clause: [], having_clause: [], limit: nil, offset: nil)
241
+ result = from_clause + join_clause + where_clause + having_clause
242
+ result << offset if offset
243
+ result << limit if limit
244
+ result
245
+ end
246
+
215
247
 
216
248
  protected
217
249
 
@@ -243,10 +275,13 @@ module ActiveRecord
243
275
  m.register_type 'real', SQLServer::Type::Real.new
244
276
  # Date and Time
245
277
  m.register_type 'date', SQLServer::Type::Date.new
246
- m.register_type 'datetime', SQLServer::Type::DateTime.new
247
- m.register_type %r{\Adatetime2}i do |sql_type|
278
+ m.register_type %r{\Adatetime} do |sql_type|
248
279
  precision = extract_precision(sql_type)
249
- SQLServer::Type::DateTime2.new precision: precision
280
+ if precision
281
+ SQLServer::Type::DateTime2.new precision: precision
282
+ else
283
+ SQLServer::Type::DateTime.new
284
+ end
250
285
  end
251
286
  m.register_type %r{\Adatetimeoffset}i do |sql_type|
252
287
  precision = extract_precision(sql_type)
@@ -281,13 +316,15 @@ module ActiveRecord
281
316
  def translate_exception(e, message)
282
317
  case message
283
318
  when /(cannot insert duplicate key .* with unique index) | (violation of unique key constraint)/i
284
- RecordNotUnique.new(message, e)
319
+ RecordNotUnique.new(message)
285
320
  when /conflicted with the foreign key constraint/i
286
- InvalidForeignKey.new(message, e)
321
+ InvalidForeignKey.new(message)
287
322
  when /has been chosen as the deadlock victim/i
288
- DeadlockVictim.new(message, e)
323
+ DeadlockVictim.new(message)
289
324
  when /database .* does not exist/i
290
- NoDatabaseError.new(message, e)
325
+ NoDatabaseError.new(message)
326
+ when /data would be truncated/
327
+ ValueTooLong.new(message)
291
328
  else
292
329
  super
293
330
  end
@@ -300,8 +337,6 @@ module ActiveRecord
300
337
  @connection = case config[:mode]
301
338
  when :dblib
302
339
  dblib_connect(config)
303
- when :odbc
304
- odbc_connect(config)
305
340
  end
306
341
  @spid = _raw_select('SELECT @@SPID', fetch: :rows).first.first
307
342
  configure_connection
@@ -310,7 +345,6 @@ module ActiveRecord
310
345
  def connection_errors
311
346
  @connection_errors ||= [].tap do |errors|
312
347
  errors << TinyTds::Error if defined?(TinyTds::Error)
313
- errors << ODBC::Error if defined?(ODBC::Error)
314
348
  end
315
349
  end
316
350
 
@@ -327,8 +361,7 @@ module ActiveRecord
327
361
  login_timeout: config_login_timeout(config),
328
362
  timeout: config_timeout(config),
329
363
  encoding: config_encoding(config),
330
- azure: config[:azure],
331
- contained: config[:contained]
364
+ azure: config[:azure]
332
365
  ).tap do |client|
333
366
  if config[:azure]
334
367
  client.execute('SET ANSI_NULLS ON').do
@@ -348,25 +381,6 @@ module ActiveRecord
348
381
  end
349
382
  end
350
383
 
351
- def odbc_connect(config)
352
- if config[:dsn].include?(';')
353
- driver = ODBC::Driver.new.tap do |d|
354
- d.name = config[:dsn_name] || 'Driver1'
355
- d.attrs = config[:dsn].split(';').map { |atr| atr.split('=') }.reject { |kv| kv.size != 2 }.reduce({}) { |a, e| k, v = e ; a[k] = v ; a }
356
- end
357
- ODBC::Database.new.drvconnect(driver)
358
- else
359
- ODBC.connect config[:dsn], config[:username], config[:password]
360
- end.tap do |c|
361
- begin
362
- c.use_time = true
363
- c.use_utc = ActiveRecord::Base.default_timezone == :utc
364
- rescue Exception
365
- warn 'Ruby ODBC v0.99992 or higher is required.'
366
- end
367
- end
368
- end
369
-
370
384
  def config_appname(config)
371
385
  config[:appname] || configure_application_name || Rails.application.class.name.split('::').first rescue nil
372
386
  end