activerecord-sqlserver-adapter 7.1.7 → 7.2.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/.devcontainer/Dockerfile +3 -3
- data/.github/workflows/ci.yml +10 -4
- data/CHANGELOG.md +5 -99
- data/Gemfile +4 -4
- data/README.md +43 -19
- data/VERSION +1 -1
- data/activerecord-sqlserver-adapter.gemspec +2 -2
- data/lib/active_record/connection_adapters/sqlserver/core_ext/attribute_methods.rb +6 -4
- data/lib/active_record/connection_adapters/sqlserver/core_ext/calculations.rb +6 -5
- data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +7 -4
- data/lib/active_record/connection_adapters/sqlserver/core_ext/finder_methods.rb +6 -4
- data/lib/active_record/connection_adapters/sqlserver/core_ext/preloader.rb +14 -12
- data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +50 -32
- data/lib/active_record/connection_adapters/sqlserver/quoting.rb +44 -46
- data/lib/active_record/connection_adapters/sqlserver/savepoints.rb +2 -0
- data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +1 -1
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +2 -5
- data/lib/active_record/tasks/sqlserver_database_tasks.rb +38 -32
- data/lib/arel/visitors/sqlserver.rb +57 -12
- data/test/cases/active_schema_test_sqlserver.rb +6 -6
- data/test/cases/adapter_test_sqlserver.rb +17 -18
- data/test/cases/coerced_tests.rb +279 -167
- data/test/cases/disconnected_test_sqlserver.rb +9 -3
- data/test/cases/eager_load_too_many_ids_test_sqlserver.rb +1 -1
- data/test/cases/enum_test_sqlserver.rb +1 -1
- data/test/cases/execute_procedure_test_sqlserver.rb +9 -5
- data/test/cases/helper_sqlserver.rb +11 -5
- data/test/cases/index_test_sqlserver.rb +8 -6
- data/test/cases/json_test_sqlserver.rb +1 -1
- data/test/cases/lateral_test_sqlserver.rb +2 -2
- data/test/cases/migration_test_sqlserver.rb +1 -1
- data/test/cases/optimizer_hints_test_sqlserver.rb +12 -12
- data/test/cases/pessimistic_locking_test_sqlserver.rb +8 -7
- data/test/cases/primary_keys_test_sqlserver.rb +2 -2
- data/test/cases/rake_test_sqlserver.rb +8 -4
- data/test/cases/schema_dumper_test_sqlserver.rb +4 -5
- data/test/cases/showplan_test_sqlserver.rb +7 -7
- data/test/cases/specific_schema_test_sqlserver.rb +17 -13
- data/test/cases/view_test_sqlserver.rb +1 -1
- data/test/schema/sqlserver_specific_schema.rb +4 -4
- data/test/support/connection_reflection.rb +1 -1
- data/test/support/core_ext/query_cache.rb +2 -2
- data/test/support/query_assertions.rb +49 -0
- data/test/support/table_definition_sqlserver.rb +24 -0
- data/test/support/test_in_memory_oltp.rb +2 -2
- metadata +12 -13
- data/lib/active_record/sqlserver_base.rb +0 -13
- data/test/cases/scratchpad_test_sqlserver.rb +0 -8
- data/test/support/sql_counter_sqlserver.rb +0 -14
@@ -4,9 +4,53 @@ module ActiveRecord
|
|
4
4
|
module ConnectionAdapters
|
5
5
|
module SQLServer
|
6
6
|
module Quoting
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
7
9
|
QUOTED_COLUMN_NAMES = Concurrent::Map.new # :nodoc:
|
8
10
|
QUOTED_TABLE_NAMES = Concurrent::Map.new # :nodoc:
|
9
11
|
|
12
|
+
module ClassMethods
|
13
|
+
def column_name_matcher
|
14
|
+
/
|
15
|
+
\A
|
16
|
+
(
|
17
|
+
(?:
|
18
|
+
# [database_name].[database_owner].[table_name].[column_name] | function(one or no argument)
|
19
|
+
((?:\w+\.|\[\w+\]\.)?(?:\w+\.|\[\w+\]\.)?(?:\w+\.|\[\w+\]\.)?(?:\w+|\[\w+\]) | \w+\((?:|\g<2>)\))
|
20
|
+
)
|
21
|
+
(?:\s+AS\s+(?:\w+|\[\w+\]))?
|
22
|
+
)
|
23
|
+
(?:\s*,\s*\g<1>)*
|
24
|
+
\z
|
25
|
+
/ix
|
26
|
+
end
|
27
|
+
|
28
|
+
def column_name_with_order_matcher
|
29
|
+
/
|
30
|
+
\A
|
31
|
+
(
|
32
|
+
(?:
|
33
|
+
# [database_name].[database_owner].[table_name].[column_name] | function(one or no argument)
|
34
|
+
((?:\w+\.|\[\w+\]\.)?(?:\w+\.|\[\w+\]\.)?(?:\w+\.|\[\w+\]\.)?(?:\w+|\[\w+\]) | \w+\((?:|\g<2>)\))
|
35
|
+
)
|
36
|
+
(?:\s+COLLATE\s+\w+)?
|
37
|
+
(?:\s+ASC|\s+DESC)?
|
38
|
+
(?:\s+NULLS\s+(?:FIRST|LAST))?
|
39
|
+
)
|
40
|
+
(?:\s*,\s*\g<1>)*
|
41
|
+
\z
|
42
|
+
/ix
|
43
|
+
end
|
44
|
+
|
45
|
+
def quote_column_name(name)
|
46
|
+
QUOTED_COLUMN_NAMES[name] ||= SQLServer::Utils.extract_identifiers(name).quoted
|
47
|
+
end
|
48
|
+
|
49
|
+
def quote_table_name(name)
|
50
|
+
QUOTED_TABLE_NAMES[name] ||= SQLServer::Utils.extract_identifiers(name).quoted
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
10
54
|
def fetch_type_metadata(sql_type, sqlserver_options = {})
|
11
55
|
cast_type = lookup_cast_type(sql_type)
|
12
56
|
|
@@ -33,14 +77,6 @@ module ActiveRecord
|
|
33
77
|
SQLServer::Utils.quote_string_single_national(s)
|
34
78
|
end
|
35
79
|
|
36
|
-
def quote_column_name(name)
|
37
|
-
QUOTED_COLUMN_NAMES[name] ||= SQLServer::Utils.extract_identifiers(name).quoted
|
38
|
-
end
|
39
|
-
|
40
|
-
def quote_table_name(name)
|
41
|
-
QUOTED_TABLE_NAMES[name] ||= SQLServer::Utils.extract_identifiers(name).quoted
|
42
|
-
end
|
43
|
-
|
44
80
|
def quote_default_expression(value, column)
|
45
81
|
cast_type = lookup_cast_type(column.sql_type)
|
46
82
|
if cast_type.type == :uuid && value.is_a?(String) && value.include?('()')
|
@@ -76,44 +112,6 @@ module ActiveRecord
|
|
76
112
|
end
|
77
113
|
end
|
78
114
|
|
79
|
-
def column_name_matcher
|
80
|
-
COLUMN_NAME
|
81
|
-
end
|
82
|
-
|
83
|
-
def column_name_with_order_matcher
|
84
|
-
COLUMN_NAME_WITH_ORDER
|
85
|
-
end
|
86
|
-
|
87
|
-
COLUMN_NAME = /
|
88
|
-
\A
|
89
|
-
(
|
90
|
-
(?:
|
91
|
-
# [database_name].[database_owner].[table_name].[column_name] | function(one or no argument)
|
92
|
-
((?:\w+\.|\[\w+\]\.)?(?:\w+\.|\[\w+\]\.)?(?:\w+\.|\[\w+\]\.)?(?:\w+|\[\w+\]) | \w+\((?:|\g<2>)\))
|
93
|
-
)
|
94
|
-
(?:\s+AS\s+(?:\w+|\[\w+\]))?
|
95
|
-
)
|
96
|
-
(?:\s*,\s*\g<1>)*
|
97
|
-
\z
|
98
|
-
/ix
|
99
|
-
|
100
|
-
COLUMN_NAME_WITH_ORDER = /
|
101
|
-
\A
|
102
|
-
(
|
103
|
-
(?:
|
104
|
-
# [database_name].[database_owner].[table_name].[column_name] | function(one or no argument)
|
105
|
-
((?:\w+\.|\[\w+\]\.)?(?:\w+\.|\[\w+\]\.)?(?:\w+\.|\[\w+\]\.)?(?:\w+|\[\w+\]) | \w+\((?:|\g<2>)\))
|
106
|
-
)
|
107
|
-
(?:\s+COLLATE\s+\w+)?
|
108
|
-
(?:\s+ASC|\s+DESC)?
|
109
|
-
(?:\s+NULLS\s+(?:FIRST|LAST))?
|
110
|
-
)
|
111
|
-
(?:\s*,\s*\g<1>)*
|
112
|
-
\z
|
113
|
-
/ix
|
114
|
-
|
115
|
-
private_constant :COLUMN_NAME, :COLUMN_NAME_WITH_ORDER
|
116
|
-
|
117
115
|
def quote(value)
|
118
116
|
case value
|
119
117
|
when Type::Binary::Data
|
@@ -16,6 +16,8 @@ module ActiveRecord
|
|
16
16
|
internal_execute("ROLLBACK TRANSACTION #{name}", "TRANSACTION")
|
17
17
|
end
|
18
18
|
|
19
|
+
# SQL Server does require save-points to be explicitly released.
|
20
|
+
# See https://stackoverflow.com/questions/3101312/sql-server-2008-no-release-savepoint-for-current-transaction
|
19
21
|
def release_savepoint(_name)
|
20
22
|
end
|
21
23
|
end
|
@@ -132,7 +132,7 @@ module ActiveRecord
|
|
132
132
|
schema_cache.clear_data_source_cache!(table_name.to_s)
|
133
133
|
schema_cache.clear_data_source_cache!(new_name.to_s)
|
134
134
|
execute "EXEC sp_rename '#{table_name}', '#{new_name}'"
|
135
|
-
rename_table_indexes(table_name, new_name)
|
135
|
+
rename_table_indexes(table_name, new_name, **options)
|
136
136
|
end
|
137
137
|
|
138
138
|
def remove_column(table_name, column_name, type = nil, **options)
|
@@ -29,12 +29,13 @@ require "active_record/connection_adapters/sqlserver/showplan"
|
|
29
29
|
require "active_record/connection_adapters/sqlserver/table_definition"
|
30
30
|
require "active_record/connection_adapters/sqlserver/quoting"
|
31
31
|
require "active_record/connection_adapters/sqlserver/utils"
|
32
|
-
require "active_record/sqlserver_base"
|
33
32
|
require "active_record/connection_adapters/sqlserver_column"
|
34
33
|
require "active_record/tasks/sqlserver_database_tasks"
|
35
34
|
|
36
35
|
module ActiveRecord
|
37
36
|
module ConnectionAdapters
|
37
|
+
register "sqlserver", "ActiveRecord::ConnectionAdapters::SQLServerAdapter", "active_record/connection_adapters/sqlserver_adapter"
|
38
|
+
|
38
39
|
class SQLServerAdapter < AbstractAdapter
|
39
40
|
include SQLServer::Version,
|
40
41
|
SQLServer::Quoting,
|
@@ -324,10 +325,6 @@ module ActiveRecord
|
|
324
325
|
self.class::VERSION
|
325
326
|
end
|
326
327
|
|
327
|
-
def inspect
|
328
|
-
"#<#{self.class} version: #{version}, azure: #{sqlserver_azure?.inspect}>"
|
329
|
-
end
|
330
|
-
|
331
328
|
def combine_bind_parameters(from_clause: [], join_clause: [], where_clause: [], having_clause: [], limit: nil, offset: nil)
|
332
329
|
result = from_clause + join_clause + where_clause + having_clause
|
333
330
|
result << offset if offset
|
@@ -10,7 +10,7 @@ module ActiveRecord
|
|
10
10
|
class SQLServerDatabaseTasks
|
11
11
|
DEFAULT_COLLATION = "SQL_Latin1_General_CP1_CI_AS"
|
12
12
|
|
13
|
-
delegate :
|
13
|
+
delegate :with_connection, :establish_connection, to: ActiveRecord::Base
|
14
14
|
|
15
15
|
def self.using_database_configurations?
|
16
16
|
true
|
@@ -23,8 +23,10 @@ module ActiveRecord
|
|
23
23
|
|
24
24
|
def create(master_established = false)
|
25
25
|
establish_master_connection unless master_established
|
26
|
-
|
27
|
-
|
26
|
+
with_connection do |connection|
|
27
|
+
connection.create_database(configuration.database, configuration_hash.merge(collation: default_collation))
|
28
|
+
end
|
29
|
+
establish_connection(configuration)
|
28
30
|
rescue ActiveRecord::StatementInvalid => e
|
29
31
|
if /database .* already exists/i === e.message
|
30
32
|
raise DatabaseAlreadyExists
|
@@ -35,15 +37,15 @@ module ActiveRecord
|
|
35
37
|
|
36
38
|
def drop
|
37
39
|
establish_master_connection
|
38
|
-
connection.drop_database
|
40
|
+
with_connection { |connection| connection.drop_database(configuration.database) }
|
39
41
|
end
|
40
42
|
|
41
43
|
def charset
|
42
|
-
connection.charset
|
44
|
+
with_connection { |connection| connection.charset }
|
43
45
|
end
|
44
46
|
|
45
47
|
def collation
|
46
|
-
connection.collation
|
48
|
+
with_connection { |connection| connection.collation }
|
47
49
|
end
|
48
50
|
|
49
51
|
def purge
|
@@ -56,34 +58,38 @@ module ActiveRecord
|
|
56
58
|
ActiveRecord::Base.connection_handler.clear_active_connections!(:all)
|
57
59
|
end
|
58
60
|
|
59
|
-
def structure_dump(filename,
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
61
|
+
def structure_dump(filename, _extra_flags)
|
62
|
+
with_connection do |connection|
|
63
|
+
server_arg = "-S #{Shellwords.escape(configuration_hash[:host])}"
|
64
|
+
server_arg += ":#{Shellwords.escape(configuration_hash[:port])}" if configuration_hash[:port]
|
65
|
+
command = [
|
66
|
+
"defncopy-ttds",
|
67
|
+
server_arg,
|
68
|
+
"-D #{Shellwords.escape(configuration_hash[:database])}",
|
69
|
+
"-U #{Shellwords.escape(configuration_hash[:username])}",
|
70
|
+
"-P #{Shellwords.escape(configuration_hash[:password])}",
|
71
|
+
"-o #{Shellwords.escape(filename)}",
|
72
|
+
]
|
73
|
+
table_args = connection.tables.map { |t| Shellwords.escape(t) }
|
74
|
+
command.concat(table_args)
|
75
|
+
view_args = connection.views.map { |v| Shellwords.escape(v) }
|
76
|
+
command.concat(view_args)
|
77
|
+
raise "Error dumping database" unless Kernel.system(command.join(" "))
|
78
|
+
|
79
|
+
dump = File.read(filename)
|
80
|
+
dump.gsub!(/^USE .*$\nGO\n/, "") # Strip db USE statements
|
81
|
+
dump.gsub!(/^GO\n/, "") # Strip db GO statements
|
82
|
+
dump.gsub!(/nvarchar\(8000\)/, "nvarchar(4000)") # Fix nvarchar(8000) column defs
|
83
|
+
dump.gsub!(/nvarchar\(-1\)/, "nvarchar(max)") # Fix nvarchar(-1) column defs
|
84
|
+
dump.gsub!(/text\(\d+\)/, "text") # Fix text(16) column defs
|
85
|
+
File.open(filename, "w") { |file| file.puts dump }
|
86
|
+
end
|
83
87
|
end
|
84
88
|
|
85
|
-
def structure_load(filename,
|
86
|
-
connection
|
89
|
+
def structure_load(filename, _extra_flags)
|
90
|
+
with_connection do |connection|
|
91
|
+
connection.execute File.read(filename)
|
92
|
+
end
|
87
93
|
end
|
88
94
|
|
89
95
|
private
|
@@ -30,10 +30,46 @@ module Arel
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def visit_Arel_Nodes_UpdateStatement(o, collector)
|
33
|
-
if
|
34
|
-
o
|
33
|
+
if has_join_and_composite_primary_key?(o)
|
34
|
+
update_statement_using_join(o, collector)
|
35
|
+
else
|
36
|
+
o.limit = Nodes::Limit.new(9_223_372_036_854_775_807) if o.orders.any? && o.limit.nil?
|
37
|
+
|
38
|
+
super
|
35
39
|
end
|
36
|
-
|
40
|
+
end
|
41
|
+
|
42
|
+
def visit_Arel_Nodes_DeleteStatement(o, collector)
|
43
|
+
if has_join_and_composite_primary_key?(o)
|
44
|
+
delete_statement_using_join(o, collector)
|
45
|
+
else
|
46
|
+
super
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def has_join_and_composite_primary_key?(o)
|
51
|
+
has_join_sources?(o) && o.relation.left.instance_variable_get(:@klass).composite_primary_key?
|
52
|
+
end
|
53
|
+
|
54
|
+
def delete_statement_using_join(o, collector)
|
55
|
+
collector.retryable = false
|
56
|
+
|
57
|
+
collector << "DELETE "
|
58
|
+
visit o.relation.left, collector
|
59
|
+
collector << " FROM "
|
60
|
+
visit o.relation, collector
|
61
|
+
collect_nodes_for o.wheres, collector, " WHERE ", " AND "
|
62
|
+
end
|
63
|
+
|
64
|
+
def update_statement_using_join(o, collector)
|
65
|
+
collector.retryable = false
|
66
|
+
|
67
|
+
collector << "UPDATE "
|
68
|
+
visit o.relation.left, collector
|
69
|
+
collect_nodes_for o.values, collector, " SET "
|
70
|
+
collector << " FROM "
|
71
|
+
visit o.relation, collector
|
72
|
+
collect_nodes_for o.wheres, collector, " WHERE ", " AND "
|
37
73
|
end
|
38
74
|
|
39
75
|
def visit_Arel_Nodes_Lock(o, collector)
|
@@ -129,10 +165,12 @@ module Arel
|
|
129
165
|
# github.com/rails-sqlserver/activerecord-sqlserver-adapter/issues/450
|
130
166
|
table_name =
|
131
167
|
begin
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
168
|
+
o.class.engine.with_connection do |connection|
|
169
|
+
if connection.respond_to?(:sqlserver?) && connection.database_prefix_remote_server?
|
170
|
+
remote_server_table_name(o)
|
171
|
+
else
|
172
|
+
quote_table_name(o.name)
|
173
|
+
end
|
136
174
|
end
|
137
175
|
rescue Exception
|
138
176
|
quote_table_name(o.name)
|
@@ -201,6 +239,11 @@ module Arel
|
|
201
239
|
collector
|
202
240
|
end
|
203
241
|
|
242
|
+
def visit_Arel_Nodes_WithRecursive(o, collector)
|
243
|
+
collector << "WITH "
|
244
|
+
collect_ctes(o.children, collector)
|
245
|
+
end
|
246
|
+
|
204
247
|
# SQLServer ToSql/Visitor (Additions)
|
205
248
|
|
206
249
|
def visit_Arel_Nodes_SelectStatement_SQLServer_Lock(collector, options = {})
|
@@ -315,14 +358,16 @@ module Arel
|
|
315
358
|
end
|
316
359
|
|
317
360
|
def remote_server_table_name(o)
|
318
|
-
|
319
|
-
|
320
|
-
|
361
|
+
o.class.engine.with_connection do |connection|
|
362
|
+
ActiveRecord::ConnectionAdapters::SQLServer::Utils.extract_identifiers(
|
363
|
+
"#{connection.database_prefix}#{o.name}"
|
364
|
+
).quoted
|
365
|
+
end
|
321
366
|
end
|
322
367
|
|
323
|
-
# Need to remove ordering from
|
368
|
+
# Need to remove ordering from sub-queries unless TOP/OFFSET also used. Otherwise, SQLServer
|
324
369
|
# returns error "The ORDER BY clause is invalid in views, inline functions, derived tables,
|
325
|
-
#
|
370
|
+
# sub-queries, and common table expressions, unless TOP, OFFSET or FOR XML is also specified."
|
326
371
|
def remove_invalid_ordering_from_select_statement(node)
|
327
372
|
return unless Arel::Nodes::SelectStatement === node
|
328
373
|
|
@@ -16,38 +16,38 @@ class ActiveSchemaTestSQLServer < ActiveRecord::TestCase
|
|
16
16
|
end
|
17
17
|
|
18
18
|
it 'default index' do
|
19
|
-
|
19
|
+
assert_queries_match('CREATE INDEX [index_schema_test_table_on_foo] ON [schema_test_table] ([foo])') do
|
20
20
|
connection.add_index :schema_test_table, "foo"
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
24
|
it 'unique index' do
|
25
|
-
|
25
|
+
assert_queries_match('CREATE UNIQUE INDEX [index_schema_test_table_on_foo] ON [schema_test_table] ([foo])') do
|
26
26
|
connection.add_index :schema_test_table, "foo", unique: true
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
30
|
it 'where condition on index' do
|
31
|
-
|
31
|
+
assert_queries_match("CREATE INDEX [index_schema_test_table_on_foo] ON [schema_test_table] ([foo]) WHERE state = 'active'") do
|
32
32
|
connection.add_index :schema_test_table, "foo", where: "state = 'active'"
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
36
|
it 'if index does not exist' do
|
37
|
-
|
37
|
+
assert_queries_match("IF NOT EXISTS (SELECT name FROM sysindexes WHERE name = 'index_schema_test_table_on_foo') " \
|
38
38
|
"CREATE INDEX [index_schema_test_table_on_foo] ON [schema_test_table] ([foo])") do
|
39
39
|
connection.add_index :schema_test_table, "foo", if_not_exists: true
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
43
|
it 'clustered index' do
|
44
|
-
|
44
|
+
assert_queries_match('CREATE CLUSTERED INDEX [index_schema_test_table_on_foo] ON [schema_test_table] ([foo])') do
|
45
45
|
connection.add_index :schema_test_table, "foo", type: :clustered
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
49
|
it 'nonclustered index' do
|
50
|
-
|
50
|
+
assert_queries_match('CREATE NONCLUSTERED INDEX [index_schema_test_table_on_foo] ON [schema_test_table] ([foo])') do
|
51
51
|
connection.add_index :schema_test_table, "foo", type: :nonclustered
|
52
52
|
end
|
53
53
|
end
|
@@ -18,8 +18,6 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
18
18
|
it "has basic and non-sensitive information in the adapters inspect method" do
|
19
19
|
string = connection.inspect
|
20
20
|
_(string).must_match %r{ActiveRecord::ConnectionAdapters::SQLServerAdapter}
|
21
|
-
_(string).must_match %r{version\: \d.\d}
|
22
|
-
_(string).must_match %r{azure: (true|false)}
|
23
21
|
_(string).wont_match %r{host}
|
24
22
|
_(string).wont_match %r{password}
|
25
23
|
_(string).wont_match %r{username}
|
@@ -31,7 +29,7 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
31
29
|
end
|
32
30
|
|
33
31
|
it "raises invalid statement error for bad SQL" do
|
34
|
-
assert_raise(ActiveRecord::StatementInvalid) { Topic.
|
32
|
+
assert_raise(ActiveRecord::StatementInvalid) { Topic.lease_connection.update("UPDATE XXX") }
|
35
33
|
end
|
36
34
|
|
37
35
|
it "is has our adapter_name" do
|
@@ -61,8 +59,8 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
61
59
|
end
|
62
60
|
|
63
61
|
it "test table existence across database schemas" do
|
64
|
-
arunit_connection = Topic.
|
65
|
-
arunit2_connection = College.
|
62
|
+
arunit_connection = Topic.lease_connection
|
63
|
+
arunit2_connection = College.lease_connection
|
66
64
|
|
67
65
|
arunit_database = arunit_connection.pool.db_config.database
|
68
66
|
arunit2_database = arunit2_connection.pool.db_config.database
|
@@ -102,8 +100,7 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
102
100
|
assert_raise ActiveRecord::NoDatabaseError do
|
103
101
|
db_config = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", name: "primary")
|
104
102
|
configuration = db_config.configuration_hash.merge(database: "nonexistent_activerecord_unittest")
|
105
|
-
|
106
|
-
connection = ActiveRecord::Base.sqlserver_connection configuration
|
103
|
+
connection = ActiveRecord::ConnectionAdapters::SQLServerAdapter.new(configuration)
|
107
104
|
connection.exec_query("SELECT 1")
|
108
105
|
end
|
109
106
|
end
|
@@ -285,23 +282,25 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
285
282
|
end
|
286
283
|
|
287
284
|
it "NOT ALLOW by default the deletion of a referenced parent" do
|
288
|
-
SSTestHasPk.
|
285
|
+
SSTestHasPk.lease_connection.disable_referential_integrity {}
|
289
286
|
assert_raise(ActiveRecord::StatementInvalid) { @parent.destroy }
|
290
287
|
end
|
291
288
|
|
292
289
|
it "ALLOW deletion of referenced parent using #disable_referential_integrity block" do
|
293
|
-
SSTestHasPk.
|
290
|
+
assert_difference("SSTestHasPk.count", -1) do
|
291
|
+
SSTestHasPk.lease_connection.disable_referential_integrity { @parent.destroy }
|
292
|
+
end
|
294
293
|
end
|
295
294
|
|
296
295
|
it "again NOT ALLOW deletion of referenced parent after #disable_referential_integrity block" do
|
297
296
|
assert_raise(ActiveRecord::StatementInvalid) do
|
298
|
-
SSTestHasPk.
|
297
|
+
SSTestHasPk.lease_connection.disable_referential_integrity {}
|
299
298
|
@parent.destroy
|
300
299
|
end
|
301
300
|
end
|
302
301
|
|
303
302
|
it "not disable referential integrity for the same table twice" do
|
304
|
-
tables = SSTestHasPk.
|
303
|
+
tables = SSTestHasPk.lease_connection.tables_with_referential_integrity
|
305
304
|
assert_equal tables.size, tables.uniq.size
|
306
305
|
end
|
307
306
|
end
|
@@ -396,7 +395,7 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
396
395
|
|
397
396
|
it "allows connection#view_information to work across databases when using qualified object names" do
|
398
397
|
# College is defined in activerecord_unittest2 database.
|
399
|
-
view_info = College.
|
398
|
+
view_info = College.lease_connection.send(:view_information, "[activerecord_unittest].[dbo].[sst_customers_view]")
|
400
399
|
assert_equal("sst_customers_view", view_info["TABLE_NAME"])
|
401
400
|
assert_match(/CREATE VIEW sst_customers_view/, view_info["VIEW_DEFINITION"])
|
402
401
|
end
|
@@ -407,8 +406,8 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
407
406
|
end
|
408
407
|
|
409
408
|
it "allow the connection#view_table_name method to return true table_name for the view for other connections" do
|
410
|
-
assert_equal "customers", College.
|
411
|
-
assert_equal "topics", College.
|
409
|
+
assert_equal "customers", College.lease_connection.send(:view_table_name, "[activerecord_unittest].[dbo].[sst_customers_view]")
|
410
|
+
assert_equal "topics", College.lease_connection.send(:view_table_name, "topics"), "No view here, the same table name should come back."
|
412
411
|
end
|
413
412
|
# With same column names
|
414
413
|
|
@@ -434,7 +433,7 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
434
433
|
end
|
435
434
|
|
436
435
|
it "respond true to data_source_exists?" do
|
437
|
-
assert SSTestCustomersView.
|
436
|
+
assert SSTestCustomersView.lease_connection.data_source_exists?(SSTestCustomersView.table_name)
|
438
437
|
end
|
439
438
|
|
440
439
|
# With aliased column names
|
@@ -462,7 +461,7 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
462
461
|
end
|
463
462
|
|
464
463
|
it "respond true to data_source_exists?" do
|
465
|
-
assert SSTestStringDefaultsView.
|
464
|
+
assert SSTestStringDefaultsView.lease_connection.data_source_exists?(SSTestStringDefaultsView.table_name)
|
466
465
|
end
|
467
466
|
|
468
467
|
# That have more than 4000 chars for their defintion
|
@@ -508,7 +507,7 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
508
507
|
|
509
508
|
describe "block writes to a database" do
|
510
509
|
def setup
|
511
|
-
@conn = ActiveRecord::Base.
|
510
|
+
@conn = ActiveRecord::Base.lease_connection
|
512
511
|
end
|
513
512
|
|
514
513
|
def test_errors_when_an_insert_query_is_called_while_preventing_writes
|
@@ -557,7 +556,7 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
557
556
|
|
558
557
|
it 'records can be inserted using SQL' do
|
559
558
|
assert_difference("Alien.count", 2) do
|
560
|
-
Alien.
|
559
|
+
Alien.lease_connection.exec_insert("insert into [test].[aliens] (id, name) VALUES(1, 'Trisolarans'), (2, 'Xenomorph')")
|
561
560
|
end
|
562
561
|
end
|
563
562
|
end
|