activerecord-sqlserver-adapter 4.2.18 → 5.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 (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