activerecord-jdbcsqlserver-adapter 50.1.0 → 51.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +3 -1
- data/.travis.yml +4 -5
- data/BACKERS.md +32 -0
- data/CHANGELOG.md +21 -87
- data/README.md +2 -3
- data/VERSION +1 -1
- data/activerecord-jdbcsqlserver-adapter.gemspec +3 -2
- data/appveyor.yml +1 -1
- data/lib/active_record/connection_adapters/sqlserver/core_ext/active_record.rb +3 -1
- data/lib/active_record/connection_adapters/sqlserver/core_ext/attribute_methods.rb +3 -1
- data/lib/active_record/connection_adapters/sqlserver/core_ext/calculations.rb +55 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +4 -2
- data/lib/active_record/connection_adapters/sqlserver/core_ext/explain_subscriber.rb +5 -3
- data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +41 -18
- data/lib/active_record/connection_adapters/sqlserver/jdbc_overrides.rb +2 -12
- data/lib/active_record/connection_adapters/sqlserver/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlserver/schema_dumper.rb +21 -0
- data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +72 -52
- data/lib/active_record/connection_adapters/sqlserver/table_definition.rb +15 -7
- data/lib/active_record/connection_adapters/sqlserver/type/big_integer.rb +0 -4
- data/lib/active_record/connection_adapters/sqlserver/type/data.rb +5 -0
- data/lib/active_record/connection_adapters/sqlserver/type/datetime.rb +3 -6
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +27 -10
- data/lib/active_record/tasks/sqlserver_database_tasks.rb +2 -2
- data/lib/activerecord-jdbcsqlserver-adapter.rb +1 -1
- data/lib/arel/visitors/sqlserver.rb +16 -3
- data/test/bin/setup.sh +19 -0
- data/test/cases/adapter_test_sqlserver.rb +17 -20
- data/test/cases/coerced_tests.rb +117 -11
- data/test/cases/column_test_sqlserver.rb +1 -1
- data/test/cases/helper_sqlserver.rb +6 -1
- data/test/cases/pessimistic_locking_test_sqlserver.rb +28 -11
- data/test/cases/schema_dumper_test_sqlserver.rb +10 -10
- data/test/cases/specific_schema_test_sqlserver.rb +0 -6
- data/test/cases/trigger_test_sqlserver.rb +31 -0
- data/test/config.yml +2 -2
- data/test/models/sqlserver/trigger.rb +7 -0
- data/test/models/sqlserver/trigger_history.rb +3 -0
- data/test/schema/sqlserver_specific_schema.rb +39 -5
- data/test/support/sql_counter_sqlserver.rb +3 -2
- metadata +23 -16
- data/RAILS5-TODO.md +0 -5
- data/lib/jdbc_mssql_driver_loader.rb +0 -22
- data/test/models/sqlserver/dot_table_name.rb +0 -3
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'pry'
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module ConnectionAdapters
|
3
5
|
module SQLServer
|
@@ -90,18 +92,6 @@ module ActiveRecord
|
|
90
92
|
@connection.configure_connection
|
91
93
|
end
|
92
94
|
|
93
|
-
# @Overwrite
|
94
|
-
# Had some special logic and skipped using gem's internal query methods
|
95
|
-
def select_rows(sql, name = nil, binds = [])
|
96
|
-
|
97
|
-
# In some cases the limit is converted to a `TOP(1)` but the bind parameter is still in the array
|
98
|
-
if !binds.empty? && sql.include?('TOP(1)')
|
99
|
-
binds = binds.delete_if {|b| b.name == 'LIMIT' }
|
100
|
-
end
|
101
|
-
|
102
|
-
exec_query(sql, name, binds).rows
|
103
|
-
end
|
104
|
-
|
105
95
|
# Have to reset this because the default arjdbc functionality is to return false unless a level is passed in
|
106
96
|
def supports_transaction_isolation?
|
107
97
|
true
|
@@ -16,6 +16,20 @@ module ActiveRecord
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
+
def add_column_options!(sql, options)
|
20
|
+
sql << " DEFAULT #{quote_default_expression(options[:default], options[:column])}" if options_include_default?(options)
|
21
|
+
if options[:null] == false
|
22
|
+
sql << " NOT NULL"
|
23
|
+
end
|
24
|
+
if options[:is_identity] == true
|
25
|
+
sql << " IDENTITY(1,1)"
|
26
|
+
end
|
27
|
+
if options[:primary_key] == true
|
28
|
+
sql << " PRIMARY KEY"
|
29
|
+
end
|
30
|
+
sql
|
31
|
+
end
|
32
|
+
|
19
33
|
def action_sql(action, dependency)
|
20
34
|
case dependency
|
21
35
|
when :restrict
|
@@ -28,6 +42,14 @@ module ActiveRecord
|
|
28
42
|
end
|
29
43
|
end
|
30
44
|
|
45
|
+
def options_include_default?(options)
|
46
|
+
super || options_primary_key_with_nil_default?(options)
|
47
|
+
end
|
48
|
+
|
49
|
+
def options_primary_key_with_nil_default?(options)
|
50
|
+
options[:primary_key] && options.include?(:default) && options[:default].nil?
|
51
|
+
end
|
52
|
+
|
31
53
|
end
|
32
54
|
end
|
33
55
|
end
|
@@ -3,13 +3,34 @@ module ActiveRecord
|
|
3
3
|
module SQLServer
|
4
4
|
module SchemaDumper
|
5
5
|
|
6
|
+
SQLSEVER_NO_LIMIT_TYPES = [
|
7
|
+
'text',
|
8
|
+
'ntext',
|
9
|
+
'varchar(max)',
|
10
|
+
'nvarchar(max)',
|
11
|
+
'varbinary(max)'
|
12
|
+
].freeze
|
13
|
+
|
6
14
|
private
|
7
15
|
|
16
|
+
def explicit_primary_key_default?(column)
|
17
|
+
column.is_primary? && !column.is_identity?
|
18
|
+
end
|
19
|
+
|
20
|
+
def schema_limit(column)
|
21
|
+
return if SQLSEVER_NO_LIMIT_TYPES.include?(column.sql_type)
|
22
|
+
super
|
23
|
+
end
|
24
|
+
|
8
25
|
def schema_collation(column)
|
9
26
|
return unless column.collation
|
10
27
|
column.collation if column.collation != collation
|
11
28
|
end
|
12
29
|
|
30
|
+
def default_primary_key?(column)
|
31
|
+
super && column.is_primary? && column.is_identity?
|
32
|
+
end
|
33
|
+
|
13
34
|
end
|
14
35
|
end
|
15
36
|
end
|
@@ -7,35 +7,6 @@ module ActiveRecord
|
|
7
7
|
@native_database_types ||= initialize_native_database_types.freeze
|
8
8
|
end
|
9
9
|
|
10
|
-
def tables(name = nil)
|
11
|
-
ActiveSupport::Deprecation.warn 'Passing arguments to #tables is deprecated without replacement.' if name
|
12
|
-
tables_sql('BASE TABLE')
|
13
|
-
end
|
14
|
-
|
15
|
-
def table_exists?(table_name)
|
16
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
17
|
-
#table_exists? currently checks both tables and views.
|
18
|
-
This behavior is deprecated and will be changed with Rails 5.1 to only check tables.
|
19
|
-
Use #data_source_exists? instead.
|
20
|
-
MSG
|
21
|
-
data_source_exists?(table_name)
|
22
|
-
end
|
23
|
-
|
24
|
-
def data_source_exists?(table_name)
|
25
|
-
return false if table_name.blank?
|
26
|
-
unquoted_table_name = SQLServer::Utils.extract_identifiers(table_name).object
|
27
|
-
super(unquoted_table_name)
|
28
|
-
end
|
29
|
-
|
30
|
-
def views
|
31
|
-
tables_sql('VIEW')
|
32
|
-
end
|
33
|
-
|
34
|
-
def view_exists?(table_name)
|
35
|
-
identifier = SQLServer::Utils.extract_identifiers(table_name)
|
36
|
-
super(identifier.object)
|
37
|
-
end
|
38
|
-
|
39
10
|
def create_table(table_name, comment: nil, **options)
|
40
11
|
res = super
|
41
12
|
clear_cache!
|
@@ -43,7 +14,18 @@ module ActiveRecord
|
|
43
14
|
end
|
44
15
|
|
45
16
|
def drop_table(table_name, options = {})
|
46
|
-
|
17
|
+
# Mimic CASCADE option as best we can.
|
18
|
+
if options[:force] == :cascade
|
19
|
+
execute_procedure(:sp_fkeys, pktable_name: table_name).each do |fkdata|
|
20
|
+
fktable = fkdata['FKTABLE_NAME']
|
21
|
+
fkcolmn = fkdata['FKCOLUMN_NAME']
|
22
|
+
pktable = fkdata['PKTABLE_NAME']
|
23
|
+
pkcolmn = fkdata['PKCOLUMN_NAME']
|
24
|
+
remove_foreign_key fktable, name: fkdata['FK_NAME']
|
25
|
+
do_execute "DELETE FROM #{quote_table_name(fktable)} WHERE #{quote_column_name(fkcolmn)} IN ( SELECT #{quote_column_name(pkcolmn)} FROM #{quote_table_name(pktable)} )"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
if options[:if_exists] && @version_year < 2016
|
47
29
|
execute "IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = #{quote(table_name)}) DROP TABLE #{quote_table_name(table_name)}"
|
48
30
|
else
|
49
31
|
super
|
@@ -103,10 +85,36 @@ module ActiveRecord
|
|
103
85
|
end
|
104
86
|
|
105
87
|
def primary_keys(table_name)
|
106
|
-
primaries =
|
88
|
+
primaries = primary_keys_select(table_name)
|
107
89
|
primaries.present? ? primaries : identity_columns(table_name).map(&:name)
|
108
90
|
end
|
109
91
|
|
92
|
+
def primary_keys_select(table_name)
|
93
|
+
identifier = database_prefix_identifier(table_name)
|
94
|
+
database = identifier.fully_qualified_database_quoted
|
95
|
+
sql = %{
|
96
|
+
SELECT KCU.COLUMN_NAME AS [name]
|
97
|
+
FROM #{database}.INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS KCU
|
98
|
+
LEFT OUTER JOIN #{database}.INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS TC
|
99
|
+
ON KCU.CONSTRAINT_NAME = TC.CONSTRAINT_NAME
|
100
|
+
AND KCU.CONSTRAINT_NAME = TC.CONSTRAINT_NAME
|
101
|
+
AND KCU.CONSTRAINT_CATALOG = TC.CONSTRAINT_CATALOG
|
102
|
+
AND KCU.CONSTRAINT_SCHEMA = TC.CONSTRAINT_SCHEMA
|
103
|
+
AND TC.CONSTRAINT_TYPE = N'PRIMARY KEY'
|
104
|
+
WHERE KCU.TABLE_NAME = #{prepared_statements ? COLUMN_DEFINITION_BIND_STRING_0 : quote(identifier.object)}
|
105
|
+
AND KCU.TABLE_SCHEMA = #{identifier.schema.blank? ? 'schema_name()' : (prepared_statements ? COLUMN_DEFINITION_BIND_STRING_1 : quote(identifier.schema))}
|
106
|
+
AND TC.CONSTRAINT_TYPE = N'PRIMARY KEY'
|
107
|
+
ORDER BY KCU.ORDINAL_POSITION ASC
|
108
|
+
}.gsub(/[[:space:]]/, ' ')
|
109
|
+
binds = []
|
110
|
+
if prepared_statements
|
111
|
+
nv128 = SQLServer::Type::UnicodeVarchar.new limit: 128
|
112
|
+
binds << Relation::QueryAttribute.new('TABLE_NAME', identifier.object, nv128)
|
113
|
+
binds << Relation::QueryAttribute.new('TABLE_SCHEMA', identifier.schema, nv128) unless identifier.schema.blank?
|
114
|
+
end
|
115
|
+
sp_executesql(sql, 'SCHEMA', binds).map { |r| r['name'] }
|
116
|
+
end
|
117
|
+
|
110
118
|
def rename_table(table_name, new_name)
|
111
119
|
do_execute "EXEC sp_rename '#{table_name}', '#{new_name}'"
|
112
120
|
rename_table_indexes(table_name, new_name)
|
@@ -130,9 +138,11 @@ module ActiveRecord
|
|
130
138
|
remove_indexes(table_name, column_name)
|
131
139
|
end
|
132
140
|
sql_commands << "UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote_default_expression(options[:default], column_object)} WHERE #{quote_column_name(column_name)} IS NULL" if !options[:null].nil? && options[:null] == false && !options[:default].nil?
|
133
|
-
sql_commands << "ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
|
134
|
-
sql_commands
|
135
|
-
if
|
141
|
+
sql_commands << "ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN #{quote_column_name(column_name)} #{type_to_sql(type, limit: options[:limit], precision: options[:precision], scale: options[:scale])}"
|
142
|
+
sql_commands.last << ' NOT NULL' if !options[:null].nil? && options[:null] == false
|
143
|
+
if options.key?(:default) && default_constraint_name(table_name, column_name).present?
|
144
|
+
change_column_default(table_name, column_name, options[:default])
|
145
|
+
elsif options_include_default?(options)
|
136
146
|
sql_commands << "ALTER TABLE #{quote_table_name(table_name)} ADD CONSTRAINT #{default_constraint_name(table_name, column_name)} DEFAULT #{quote_default_expression(options[:default], column_object)} FOR #{quote_column_name(column_name)}"
|
137
147
|
end
|
138
148
|
# Add any removed indexes back
|
@@ -140,6 +150,7 @@ module ActiveRecord
|
|
140
150
|
sql_commands << "CREATE INDEX #{quote_table_name(index.name)} ON #{quote_table_name(table_name)} (#{index.columns.map { |c| quote_column_name(c) }.join(', ')})"
|
141
151
|
end
|
142
152
|
sql_commands.each { |c| do_execute(c) }
|
153
|
+
clear_cache!
|
143
154
|
end
|
144
155
|
|
145
156
|
def change_column_default(table_name, column_name, default_or_changes)
|
@@ -194,7 +205,7 @@ module ActiveRecord
|
|
194
205
|
end
|
195
206
|
end
|
196
207
|
|
197
|
-
def type_to_sql(type, limit
|
208
|
+
def type_to_sql(type, limit: nil, precision: nil, scale: nil, **)
|
198
209
|
type_limitable = %w(string integer float char nchar varchar nvarchar).include?(type.to_s)
|
199
210
|
limit = nil unless type_limitable
|
200
211
|
case type.to_s
|
@@ -240,19 +251,40 @@ module ActiveRecord
|
|
240
251
|
if !allow_null.nil? && allow_null == false && !default.nil?
|
241
252
|
do_execute("UPDATE #{table_id} SET #{column_id}=#{quote(default)} WHERE #{column_id} IS NULL")
|
242
253
|
end
|
243
|
-
sql = "ALTER TABLE #{table_id} ALTER COLUMN #{column_id} #{type_to_sql column.type, column.limit, column.precision, column.scale}"
|
254
|
+
sql = "ALTER TABLE #{table_id} ALTER COLUMN #{column_id} #{type_to_sql column.type, limit: column.limit, precision: column.precision, scale: column.scale}"
|
244
255
|
sql << ' NOT NULL' if !allow_null.nil? && allow_null == false
|
245
256
|
do_execute sql
|
246
257
|
end
|
247
258
|
|
259
|
+
private
|
248
260
|
|
249
|
-
|
261
|
+
def data_source_sql(name = nil, type: nil)
|
262
|
+
scope = quoted_scope name, type: type
|
263
|
+
table_name = lowercase_schema_reflection_sql 'TABLE_NAME'
|
264
|
+
sql = "SELECT #{table_name}"
|
265
|
+
sql << ' FROM INFORMATION_SCHEMA.TABLES'
|
266
|
+
sql << ' WHERE TABLE_CATALOG = DB_NAME()'
|
267
|
+
sql << " AND TABLE_SCHEMA = #{quote(scope[:schema])}"
|
268
|
+
sql << " AND TABLE_NAME = #{quote(scope[:name])}" if scope[:name]
|
269
|
+
sql << " AND TABLE_TYPE = #{quote(scope[:type])}" if scope[:type]
|
270
|
+
sql << " ORDER BY #{table_name}"
|
271
|
+
sql
|
272
|
+
end
|
273
|
+
|
274
|
+
def quoted_scope(name = nil, type: nil)
|
275
|
+
identifier = SQLServer::Utils.extract_identifiers(name)
|
276
|
+
{}.tap do |scope|
|
277
|
+
scope[:schema] = identifier.schema || 'dbo'
|
278
|
+
scope[:name] = identifier.object if identifier.object
|
279
|
+
scope[:type] = type if type
|
280
|
+
end
|
281
|
+
end
|
250
282
|
|
251
283
|
# === SQLServer Specific ======================================== #
|
252
284
|
|
253
285
|
def initialize_native_database_types
|
254
286
|
{
|
255
|
-
primary_key: '
|
287
|
+
primary_key: 'bigint NOT NULL IDENTITY(1,1) PRIMARY KEY',
|
256
288
|
primary_key_nonclustered: 'int NOT NULL IDENTITY(1,1) PRIMARY KEY NONCLUSTERED',
|
257
289
|
integer: { name: 'int', limit: 4 },
|
258
290
|
bigint: { name: 'bigint' },
|
@@ -286,21 +318,11 @@ module ActiveRecord
|
|
286
318
|
}
|
287
319
|
end
|
288
320
|
|
289
|
-
def tables_sql(type)
|
290
|
-
tn = lowercase_schema_reflection_sql 'TABLE_NAME'
|
291
|
-
sql = "SELECT #{tn} FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = '#{type}' ORDER BY TABLE_NAME"
|
292
|
-
select_values sql, 'SCHEMA'
|
293
|
-
end
|
294
|
-
|
295
321
|
COLUMN_DEFINITION_BIND_STRING_0 = defined?(JRUBY_VERSION) ? '?' : '@0'
|
296
322
|
COLUMN_DEFINITION_BIND_STRING_1 = defined?(JRUBY_VERSION) ? '?' : '@1'
|
297
323
|
|
298
324
|
def column_definitions(table_name)
|
299
|
-
identifier
|
300
|
-
SQLServer::Utils.extract_identifiers("#{database_prefix}#{table_name}")
|
301
|
-
else
|
302
|
-
SQLServer::Utils.extract_identifiers(table_name)
|
303
|
-
end
|
325
|
+
identifier = database_prefix_identifier(table_name)
|
304
326
|
database = identifier.fully_qualified_database_quoted
|
305
327
|
view_exists = view_exists?(table_name)
|
306
328
|
view_tblnm = view_table_name(table_name) if view_exists
|
@@ -482,7 +504,7 @@ module ActiveRecord
|
|
482
504
|
@view_information ||= {}
|
483
505
|
@view_information[table_name] ||= begin
|
484
506
|
identifier = SQLServer::Utils.extract_identifiers(table_name)
|
485
|
-
view_info = select_one "SELECT * FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_NAME =
|
507
|
+
view_info = select_one "SELECT * FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_NAME = #{quote(identifier.object)}", 'SCHEMA'
|
486
508
|
if view_info
|
487
509
|
view_info = view_info.with_indifferent_access
|
488
510
|
if view_info[:VIEW_DEFINITION].blank? || view_info[:VIEW_DEFINITION].length == 4000
|
@@ -505,8 +527,6 @@ module ActiveRecord
|
|
505
527
|
match_data ? match_data[1] : column_name
|
506
528
|
end
|
507
529
|
|
508
|
-
private
|
509
|
-
|
510
530
|
def create_table_definition(*args)
|
511
531
|
SQLServer::TableDefinition.new(*args)
|
512
532
|
end
|
@@ -5,10 +5,13 @@ module ActiveRecord
|
|
5
5
|
module ColumnMethods
|
6
6
|
|
7
7
|
def primary_key(name, type = :primary_key, **options)
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
if [:integer, :bigint].include?(type)
|
9
|
+
options[:is_identity] = true unless options.key?(:default)
|
10
|
+
elsif type == :uuid
|
11
|
+
options[:default] = options.fetch(:default, 'NEWID()')
|
12
|
+
options[:primary_key] = true
|
13
|
+
end
|
14
|
+
super
|
12
15
|
end
|
13
16
|
|
14
17
|
def primary_key_nonclustered(*args, **options)
|
@@ -98,9 +101,14 @@ module ActiveRecord
|
|
98
101
|
class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
|
99
102
|
include ColumnMethods
|
100
103
|
|
101
|
-
def new_column_definition(name, type, options)
|
102
|
-
|
103
|
-
|
104
|
+
def new_column_definition(name, type, **options)
|
105
|
+
case type
|
106
|
+
when :datetime
|
107
|
+
type = :datetime2 if options[:precision]
|
108
|
+
when :primary_key
|
109
|
+
options[:is_identity] = true
|
110
|
+
end
|
111
|
+
super
|
104
112
|
end
|
105
113
|
end
|
106
114
|
|
@@ -51,7 +51,9 @@ module ActiveRecord
|
|
51
51
|
private
|
52
52
|
|
53
53
|
def fast_string_to_time(string)
|
54
|
-
|
54
|
+
time = ActiveSupport::TimeZone['UTC'].strptime(string, fast_string_to_time_format)
|
55
|
+
new_time(time.year, time.month, time.day, time.hour,
|
56
|
+
time.min, time.sec, Rational(time.nsec, 1_000))
|
55
57
|
rescue ArgumentError
|
56
58
|
super
|
57
59
|
end
|
@@ -59,11 +61,6 @@ module ActiveRecord
|
|
59
61
|
def fast_string_to_time_format
|
60
62
|
"#{::Time::DATE_FORMATS[:_sqlserver_datetime]}.%N".freeze
|
61
63
|
end
|
62
|
-
|
63
|
-
def fast_string_to_time_zone
|
64
|
-
::Time.zone || ActiveSupport::TimeZone['UTC']
|
65
|
-
end
|
66
|
-
|
67
64
|
end
|
68
65
|
end
|
69
66
|
end
|
@@ -3,6 +3,7 @@ require 'active_record'
|
|
3
3
|
require 'arel_sqlserver'
|
4
4
|
require 'active_record/connection_adapters/abstract_adapter'
|
5
5
|
require 'active_record/connection_adapters/sqlserver/core_ext/active_record'
|
6
|
+
require 'active_record/connection_adapters/sqlserver/core_ext/calculations'
|
6
7
|
require 'active_record/connection_adapters/sqlserver/core_ext/explain' unless defined? JRUBY_VERSION
|
7
8
|
require 'active_record/connection_adapters/sqlserver/core_ext/explain_subscriber'
|
8
9
|
require 'active_record/connection_adapters/sqlserver/core_ext/attribute_methods'
|
@@ -56,11 +57,13 @@ module ActiveRecord
|
|
56
57
|
|
57
58
|
cattr_accessor :cs_equality_operator, instance_accessor: false
|
58
59
|
cattr_accessor :use_output_inserted, instance_accessor: false
|
60
|
+
cattr_accessor :exclude_output_inserted_table_names, instance_accessor: false
|
59
61
|
cattr_accessor :showplan_option, instance_accessor: false
|
60
62
|
cattr_accessor :lowercase_schema_reflection
|
61
63
|
|
62
64
|
self.cs_equality_operator = 'COLLATE Latin1_General_CS_AS_WS'
|
63
65
|
self.use_output_inserted = true
|
66
|
+
self.exclude_output_inserted_table_names = Concurrent::Map.new { false }
|
64
67
|
|
65
68
|
def initialize(connection, logger = nil, config = {})
|
66
69
|
super(connection, logger, config)
|
@@ -85,14 +88,6 @@ module ActiveRecord
|
|
85
88
|
SQLServer::SchemaCreation.new self
|
86
89
|
end
|
87
90
|
|
88
|
-
def supports_migrations?
|
89
|
-
true
|
90
|
-
end
|
91
|
-
|
92
|
-
def supports_primary_key?
|
93
|
-
true
|
94
|
-
end
|
95
|
-
|
96
91
|
def supports_ddl_transactions?
|
97
92
|
true
|
98
93
|
end
|
@@ -159,10 +154,10 @@ module ActiveRecord
|
|
159
154
|
|
160
155
|
def disable_referential_integrity
|
161
156
|
tables = tables_with_referential_integrity
|
162
|
-
tables.each { |t| do_execute "ALTER TABLE #{t} NOCHECK CONSTRAINT ALL" }
|
157
|
+
tables.each { |t| do_execute "ALTER TABLE #{quote_table_name(t)} NOCHECK CONSTRAINT ALL" }
|
163
158
|
yield
|
164
159
|
ensure
|
165
|
-
tables.each { |t| do_execute "ALTER TABLE #{t} CHECK CONSTRAINT ALL" }
|
160
|
+
tables.each { |t| do_execute "ALTER TABLE #{quote_table_name(t)} CHECK CONSTRAINT ALL" }
|
166
161
|
end
|
167
162
|
|
168
163
|
# === Abstract Adapter (Connection Management) ================== #
|
@@ -242,6 +237,14 @@ module ActiveRecord
|
|
242
237
|
@connection_options[:database_prefix]
|
243
238
|
end
|
244
239
|
|
240
|
+
def database_prefix_identifier(name)
|
241
|
+
if database_prefix_remote_server?
|
242
|
+
SQLServer::Utils.extract_identifiers("#{database_prefix}#{name}")
|
243
|
+
else
|
244
|
+
SQLServer::Utils.extract_identifiers(name)
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
245
248
|
def version
|
246
249
|
self.class::VERSION
|
247
250
|
end
|
@@ -339,6 +342,20 @@ module ActiveRecord
|
|
339
342
|
NoDatabaseError.new(message)
|
340
343
|
when /data would be truncated/
|
341
344
|
ValueTooLong.new(message)
|
345
|
+
when /Column '(.*)' is not the same data type as referencing column '(.*)' in foreign key/
|
346
|
+
pk_id, fk_id = SQLServer::Utils.extract_identifiers($1), SQLServer::Utils.extract_identifiers($2)
|
347
|
+
MismatchedForeignKey.new(
|
348
|
+
self,
|
349
|
+
message: message,
|
350
|
+
table: fk_id.schema,
|
351
|
+
foreign_key: fk_id.object,
|
352
|
+
target_table: pk_id.schema,
|
353
|
+
primary_key: pk_id.object
|
354
|
+
)
|
355
|
+
when /Cannot insert the value NULL into column.*does not allow nulls/
|
356
|
+
NotNullViolation.new(message)
|
357
|
+
when /Arithmetic overflow error/
|
358
|
+
RangeError.new(message)
|
342
359
|
else
|
343
360
|
super
|
344
361
|
end
|