activerecord-jdbcsqlserver-adapter 50.1.0 → 51.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/.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
|