activerecord-sqlserver-adapter 7.1.7 → 7.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.devcontainer/Dockerfile +3 -3
- data/.github/workflows/ci.yml +4 -4
- data/CHANGELOG.md +7 -94
- data/Dockerfile.ci +1 -1
- data/Gemfile +4 -4
- data/README.md +43 -19
- data/VERSION +1 -1
- data/activerecord-sqlserver-adapter.gemspec +2 -2
- data/docker-compose.ci.yml +1 -0
- 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 +53 -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 +9 -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
|