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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -223
- data/Gemfile +18 -17
- data/RAILS5-TODO.md +36 -0
- data/README.md +27 -8
- data/RUNNING_UNIT_TESTS.md +0 -17
- data/Rakefile +2 -7
- data/VERSION +1 -1
- data/activerecord-sqlserver-adapter.gemspec +1 -1
- data/appveyor.yml +0 -2
- data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +15 -8
- data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +45 -97
- data/lib/active_record/connection_adapters/sqlserver/database_tasks.rb +1 -2
- data/lib/active_record/connection_adapters/sqlserver/quoting.rb +31 -10
- data/lib/active_record/connection_adapters/sqlserver/schema_creation.rb +0 -18
- data/lib/active_record/connection_adapters/sqlserver/schema_dumper.rb +16 -0
- data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +101 -58
- data/lib/active_record/connection_adapters/sqlserver/showplan.rb +7 -7
- data/lib/active_record/connection_adapters/sqlserver/sql_type_metadata.rb +20 -0
- data/lib/active_record/connection_adapters/sqlserver/table_definition.rb +56 -32
- data/lib/active_record/connection_adapters/sqlserver/transaction.rb +1 -1
- data/lib/active_record/connection_adapters/sqlserver/type.rb +34 -32
- data/lib/active_record/connection_adapters/sqlserver/type/big_integer.rb +4 -0
- data/lib/active_record/connection_adapters/sqlserver/type/binary.rb +6 -0
- data/lib/active_record/connection_adapters/sqlserver/type/boolean.rb +3 -0
- data/lib/active_record/connection_adapters/sqlserver/type/char.rb +9 -20
- data/lib/active_record/connection_adapters/sqlserver/type/data.rb +30 -0
- data/lib/active_record/connection_adapters/sqlserver/type/date.rb +28 -4
- data/lib/active_record/connection_adapters/sqlserver/type/datetime.rb +28 -14
- data/lib/active_record/connection_adapters/sqlserver/type/datetime2.rb +2 -2
- data/lib/active_record/connection_adapters/sqlserver/type/datetimeoffset.rb +4 -16
- data/lib/active_record/connection_adapters/sqlserver/type/decimal.rb +9 -0
- data/lib/active_record/connection_adapters/sqlserver/type/float.rb +4 -0
- data/lib/active_record/connection_adapters/sqlserver/type/integer.rb +3 -0
- data/lib/active_record/connection_adapters/sqlserver/type/money.rb +5 -1
- data/lib/active_record/connection_adapters/sqlserver/type/real.rb +4 -0
- data/lib/active_record/connection_adapters/sqlserver/type/small_integer.rb +3 -1
- data/lib/active_record/connection_adapters/sqlserver/type/small_money.rb +5 -1
- data/lib/active_record/connection_adapters/sqlserver/type/smalldatetime.rb +8 -1
- data/lib/active_record/connection_adapters/sqlserver/type/text.rb +4 -0
- data/lib/active_record/connection_adapters/sqlserver/type/time.rb +20 -8
- data/lib/active_record/connection_adapters/sqlserver/type/time_value_fractional.rb +25 -10
- data/lib/active_record/connection_adapters/sqlserver/type/timestamp.rb +4 -0
- data/lib/active_record/connection_adapters/sqlserver/type/tiny_integer.rb +3 -0
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_char.rb +6 -0
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_text.rb +4 -0
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar.rb +7 -1
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar_max.rb +5 -1
- data/lib/active_record/connection_adapters/sqlserver/type/uuid.rb +15 -2
- data/lib/active_record/connection_adapters/sqlserver/type/varbinary.rb +7 -1
- data/lib/active_record/connection_adapters/sqlserver/type/varbinary_max.rb +5 -1
- data/lib/active_record/connection_adapters/sqlserver/type/varchar.rb +7 -1
- data/lib/active_record/connection_adapters/sqlserver/type/varchar_max.rb +5 -1
- data/lib/active_record/connection_adapters/sqlserver/utils.rb +10 -0
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +71 -57
- data/lib/active_record/connection_adapters/sqlserver_column.rb +5 -30
- data/lib/active_record/sqlserver_base.rb +1 -5
- data/lib/arel/visitors/sqlserver.rb +11 -20
- data/test/bin/setup.sh +4 -6
- data/test/cases/adapter_test_sqlserver.rb +11 -20
- data/test/cases/coerced_tests.rb +233 -138
- data/test/cases/column_test_sqlserver.rb +244 -227
- data/test/cases/connection_test_sqlserver.rb +5 -76
- data/test/cases/fully_qualified_identifier_test_sqlserver.rb +7 -7
- data/test/cases/helper_sqlserver.rb +4 -15
- data/test/cases/pessimistic_locking_test_sqlserver.rb +1 -1
- data/test/cases/rake_test_sqlserver.rb +20 -14
- data/test/cases/schema_dumper_test_sqlserver.rb +94 -63
- data/test/cases/schema_test_sqlserver.rb +2 -2
- data/test/cases/showplan_test_sqlserver.rb +1 -1
- data/test/cases/specific_schema_test_sqlserver.rb +7 -14
- data/test/cases/transaction_test_sqlserver.rb +1 -1
- data/test/cases/uuid_test_sqlserver.rb +0 -1
- data/test/config.yml +0 -10
- data/test/migrations/transaction_table/1_table_will_never_be_created.rb +1 -1
- data/test/schema/sqlserver_specific_schema.rb +0 -16
- data/test/support/coerceable_test_sqlserver.rb +6 -2
- data/test/support/connection_reflection.rb +0 -4
- data/test/support/sql_counter_sqlserver.rb +17 -21
- metadata +9 -7
- data/lib/active_record/connection_adapters/sqlserver/core_ext/odbc.rb +0 -34
- 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
|
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
|
|
@@ -6,27 +6,39 @@ module ActiveRecord
|
|
6
6
|
|
7
7
|
include TimeValueFractional2
|
8
8
|
|
9
|
-
def
|
10
|
-
|
11
|
-
|
12
|
-
|
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}"
|
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
|
-
|
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 =
|
38
|
+
value = super
|
27
39
|
return if value.blank?
|
28
40
|
value = value.change year: 2000, month: 01, day: 01
|
29
|
-
|
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
|
10
|
+
def apply_seconds_precision(value)
|
11
11
|
return value if !value.respond_to?(fractional_property) || value.send(fractional_property).zero?
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
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
|
-
|
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
|
@@ -4,7 +4,7 @@ module ActiveRecord
|
|
4
4
|
module Type
|
5
5
|
class UnicodeVarchar < UnicodeChar
|
6
6
|
|
7
|
-
def initialize(
|
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(
|
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 :
|
9
|
+
alias_method :serialize, :deserialize
|
10
10
|
|
11
11
|
def type
|
12
12
|
:uuid
|
13
13
|
end
|
14
14
|
|
15
|
-
def
|
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(
|
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(
|
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(
|
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(
|
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 :
|
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
|
51
|
-
super(connection, logger,
|
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
|
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
|
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
|
-
|
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
|
319
|
+
RecordNotUnique.new(message)
|
285
320
|
when /conflicted with the foreign key constraint/i
|
286
|
-
InvalidForeignKey.new(message
|
321
|
+
InvalidForeignKey.new(message)
|
287
322
|
when /has been chosen as the deadlock victim/i
|
288
|
-
DeadlockVictim.new(message
|
323
|
+
DeadlockVictim.new(message)
|
289
324
|
when /database .* does not exist/i
|
290
|
-
NoDatabaseError.new(message
|
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
|