activerecord-sqlserver-adapter 6.0.0.rc2 → 6.1.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/.github/workflows/ci.yml +26 -0
- data/CHANGELOG.md +20 -41
- data/README.md +32 -3
- data/RUNNING_UNIT_TESTS.md +1 -1
- data/VERSION +1 -1
- data/activerecord-sqlserver-adapter.gemspec +1 -1
- data/lib/active_record/connection_adapters/sqlserver/core_ext/calculations.rb +0 -9
- data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +7 -2
- data/lib/active_record/connection_adapters/sqlserver/database_limits.rb +0 -4
- data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +28 -16
- data/lib/active_record/connection_adapters/sqlserver/quoting.rb +7 -7
- data/lib/active_record/connection_adapters/sqlserver/schema_creation.rb +22 -1
- data/lib/active_record/connection_adapters/sqlserver/schema_dumper.rb +9 -3
- data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +31 -8
- data/lib/active_record/connection_adapters/sqlserver/sql_type_metadata.rb +27 -7
- data/lib/active_record/connection_adapters/sqlserver/table_definition.rb +0 -1
- data/lib/active_record/connection_adapters/sqlserver/transaction.rb +2 -2
- data/lib/active_record/connection_adapters/sqlserver/type.rb +1 -0
- data/lib/active_record/connection_adapters/sqlserver/type/decimal_without_scale.rb +22 -0
- data/lib/active_record/connection_adapters/sqlserver/utils.rb +1 -1
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +100 -68
- data/lib/active_record/connection_adapters/sqlserver_column.rb +17 -0
- data/lib/active_record/sqlserver_base.rb +9 -15
- data/lib/active_record/tasks/sqlserver_database_tasks.rb +17 -14
- data/lib/arel/visitors/sqlserver.rb +111 -39
- data/test/cases/adapter_test_sqlserver.rb +48 -14
- data/test/cases/change_column_collation_test_sqlserver.rb +33 -0
- data/test/cases/coerced_tests.rb +598 -78
- data/test/cases/column_test_sqlserver.rb +5 -2
- data/test/cases/disconnected_test_sqlserver.rb +39 -0
- data/test/cases/execute_procedure_test_sqlserver.rb +9 -0
- data/test/cases/in_clause_test_sqlserver.rb +27 -0
- data/test/cases/lateral_test_sqlserver.rb +35 -0
- data/test/cases/migration_test_sqlserver.rb +51 -0
- data/test/cases/optimizer_hints_test_sqlserver.rb +72 -0
- data/test/cases/order_test_sqlserver.rb +7 -0
- data/test/cases/primary_keys_test_sqlserver.rb +103 -0
- data/test/cases/rake_test_sqlserver.rb +3 -2
- data/test/cases/schema_dumper_test_sqlserver.rb +20 -3
- data/test/migrations/create_clients_and_change_column_collation.rb +19 -0
- data/test/models/sqlserver/sst_string_collation.rb +3 -0
- data/test/schema/sqlserver_specific_schema.rb +17 -0
- data/test/support/marshal_compatibility_fixtures/SQLServer/rails_6_0_topic.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/SQLServer/rails_6_0_topic_associations.dump +0 -0
- data/test/support/sql_counter_sqlserver.rb +14 -12
- metadata +32 -13
- data/.travis.yml +0 -23
@@ -27,6 +27,23 @@ module ActiveRecord
|
|
27
27
|
def case_sensitive?
|
28
28
|
collation && collation.match(/_CS/)
|
29
29
|
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
# In the Rails version of this method there is an assumption that the `default` value will always be a
|
34
|
+
# `String` class, which must be true for the MySQL/PostgreSQL/SQLite adapters. However, in the SQL Server
|
35
|
+
# adapter the `default` value can also be Boolean/Date/Time/etc. Changed the implementation of this method
|
36
|
+
# to handle non-String `default` objects.
|
37
|
+
def deduplicated
|
38
|
+
@name = -name
|
39
|
+
@sql_type_metadata = sql_type_metadata.deduplicate if sql_type_metadata
|
40
|
+
@default = (default.is_a?(String) ? -default : default.dup.freeze) if default
|
41
|
+
@default_function = -default_function if default_function
|
42
|
+
@collation = -collation if collation
|
43
|
+
@comment = -comment if comment
|
44
|
+
|
45
|
+
freeze
|
46
|
+
end
|
30
47
|
end
|
31
48
|
end
|
32
49
|
end
|
@@ -4,21 +4,15 @@ module ActiveRecord
|
|
4
4
|
module ConnectionHandling
|
5
5
|
def sqlserver_connection(config) #:nodoc:
|
6
6
|
config = config.symbolize_keys
|
7
|
-
config.reverse_merge!
|
8
|
-
mode = config[:mode].to_s.downcase.underscore.to_sym
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
rescue TinyTds::Error => e
|
17
|
-
if e.message.match(/database .* does not exist/i)
|
18
|
-
raise ActiveRecord::NoDatabaseError
|
19
|
-
else
|
20
|
-
raise
|
21
|
-
end
|
7
|
+
config.reverse_merge!(mode: :dblib)
|
8
|
+
config[:mode] = config[:mode].to_s.downcase.underscore.to_sym
|
9
|
+
|
10
|
+
ConnectionAdapters::SQLServerAdapter.new(
|
11
|
+
ConnectionAdapters::SQLServerAdapter.new_client(config),
|
12
|
+
logger,
|
13
|
+
nil,
|
14
|
+
config
|
15
|
+
)
|
22
16
|
end
|
23
17
|
end
|
24
18
|
end
|
@@ -13,13 +13,18 @@ module ActiveRecord
|
|
13
13
|
delegate :connection, :establish_connection, :clear_active_connections!,
|
14
14
|
to: ActiveRecord::Base
|
15
15
|
|
16
|
+
def self.using_database_configurations?
|
17
|
+
true
|
18
|
+
end
|
19
|
+
|
16
20
|
def initialize(configuration)
|
17
21
|
@configuration = configuration
|
22
|
+
@configuration_hash = @configuration.configuration_hash
|
18
23
|
end
|
19
24
|
|
20
25
|
def create(master_established = false)
|
21
26
|
establish_master_connection unless master_established
|
22
|
-
connection.create_database configuration
|
27
|
+
connection.create_database configuration.database, configuration_hash.merge(collation: default_collation)
|
23
28
|
establish_connection configuration
|
24
29
|
rescue ActiveRecord::StatementInvalid => e
|
25
30
|
if /database .* already exists/i === e.message
|
@@ -31,7 +36,7 @@ module ActiveRecord
|
|
31
36
|
|
32
37
|
def drop
|
33
38
|
establish_master_connection
|
34
|
-
connection.drop_database configuration
|
39
|
+
connection.drop_database configuration.database
|
35
40
|
end
|
36
41
|
|
37
42
|
def charset
|
@@ -49,14 +54,14 @@ module ActiveRecord
|
|
49
54
|
end
|
50
55
|
|
51
56
|
def structure_dump(filename, extra_flags)
|
52
|
-
server_arg = "-S #{Shellwords.escape(
|
53
|
-
server_arg += ":#{Shellwords.escape(
|
57
|
+
server_arg = "-S #{Shellwords.escape(configuration_hash[:host])}"
|
58
|
+
server_arg += ":#{Shellwords.escape(configuration_hash[:port])}" if configuration_hash[:port]
|
54
59
|
command = [
|
55
60
|
"defncopy-ttds",
|
56
61
|
server_arg,
|
57
|
-
"-D #{Shellwords.escape(
|
58
|
-
"-U #{Shellwords.escape(
|
59
|
-
"-P #{Shellwords.escape(
|
62
|
+
"-D #{Shellwords.escape(configuration_hash[:database])}",
|
63
|
+
"-U #{Shellwords.escape(configuration_hash[:username])}",
|
64
|
+
"-P #{Shellwords.escape(configuration_hash[:password])}",
|
60
65
|
"-o #{Shellwords.escape(filename)}",
|
61
66
|
]
|
62
67
|
table_args = connection.tables.map { |t| Shellwords.escape(t) }
|
@@ -80,16 +85,14 @@ module ActiveRecord
|
|
80
85
|
|
81
86
|
private
|
82
87
|
|
83
|
-
|
84
|
-
@configuration
|
85
|
-
end
|
88
|
+
attr_reader :configuration, :configuration_hash
|
86
89
|
|
87
90
|
def default_collation
|
88
|
-
|
91
|
+
configuration_hash[:collation] || DEFAULT_COLLATION
|
89
92
|
end
|
90
93
|
|
91
94
|
def establish_master_connection
|
92
|
-
establish_connection
|
95
|
+
establish_connection configuration_hash.merge(database: "master")
|
93
96
|
end
|
94
97
|
end
|
95
98
|
|
@@ -110,9 +113,9 @@ module ActiveRecord
|
|
110
113
|
end
|
111
114
|
|
112
115
|
def configuration_host_ip(configuration)
|
113
|
-
return nil unless configuration
|
116
|
+
return nil unless configuration.host
|
114
117
|
|
115
|
-
Socket::getaddrinfo(configuration
|
118
|
+
Socket::getaddrinfo(configuration.host, "echo", Socket::AF_INET)[0][3]
|
116
119
|
end
|
117
120
|
|
118
121
|
def local_ipaddr?(host_ip)
|
@@ -11,13 +11,14 @@ module Arel
|
|
11
11
|
|
12
12
|
private
|
13
13
|
|
14
|
-
# SQLServer ToSql/Visitor (
|
14
|
+
# SQLServer ToSql/Visitor (Overrides)
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
BIND_BLOCK = proc { |i| "@#{i - 1}" }
|
17
|
+
private_constant :BIND_BLOCK
|
18
|
+
|
19
|
+
def bind_block; BIND_BLOCK; end
|
19
20
|
|
20
|
-
def visit_Arel_Nodes_Bin
|
21
|
+
def visit_Arel_Nodes_Bin(o, collector)
|
21
22
|
visit o.expr, collector
|
22
23
|
collector << " #{ActiveRecord::ConnectionAdapters::SQLServerAdapter.cs_equality_operator} "
|
23
24
|
end
|
@@ -28,26 +29,26 @@ module Arel
|
|
28
29
|
visit o.right, collector
|
29
30
|
end
|
30
31
|
|
31
|
-
def visit_Arel_Nodes_UpdateStatement(o,
|
32
|
+
def visit_Arel_Nodes_UpdateStatement(o, collector)
|
32
33
|
if o.orders.any? && o.limit.nil?
|
33
34
|
o.limit = Nodes::Limit.new(9_223_372_036_854_775_807)
|
34
35
|
end
|
35
36
|
super
|
36
37
|
end
|
37
38
|
|
38
|
-
def visit_Arel_Nodes_Lock
|
39
|
+
def visit_Arel_Nodes_Lock(o, collector)
|
39
40
|
o.expr = Arel.sql("WITH(UPDLOCK)") if o.expr.to_s =~ /FOR UPDATE/
|
40
41
|
collector << " "
|
41
42
|
visit o.expr, collector
|
42
43
|
end
|
43
44
|
|
44
|
-
def visit_Arel_Nodes_Offset
|
45
|
+
def visit_Arel_Nodes_Offset(o, collector)
|
45
46
|
collector << OFFSET
|
46
47
|
visit o.expr, collector
|
47
48
|
collector << ROWS
|
48
49
|
end
|
49
50
|
|
50
|
-
def visit_Arel_Nodes_Limit
|
51
|
+
def visit_Arel_Nodes_Limit(o, collector)
|
51
52
|
if node_value(o) == 0
|
52
53
|
collector << FETCH0
|
53
54
|
collector << ROWS_ONLY
|
@@ -63,7 +64,38 @@ module Arel
|
|
63
64
|
super
|
64
65
|
end
|
65
66
|
|
66
|
-
def
|
67
|
+
def visit_Arel_Nodes_HomogeneousIn(o, collector)
|
68
|
+
collector.preparable = false
|
69
|
+
|
70
|
+
collector << quote_table_name(o.table_name) << "." << quote_column_name(o.column_name)
|
71
|
+
|
72
|
+
if o.type == :in
|
73
|
+
collector << " IN ("
|
74
|
+
else
|
75
|
+
collector << " NOT IN ("
|
76
|
+
end
|
77
|
+
|
78
|
+
values = o.casted_values
|
79
|
+
|
80
|
+
if values.empty?
|
81
|
+
collector << @connection.quote(nil)
|
82
|
+
elsif @connection.prepared_statements
|
83
|
+
# Monkey-patch start. Add query attribute bindings rather than just values.
|
84
|
+
column_name = o.column_name
|
85
|
+
column_type = o.attribute.relation.type_for_attribute(o.column_name)
|
86
|
+
attrs = values.map { |value| ActiveRecord::Relation::QueryAttribute.new(column_name, value, column_type) }
|
87
|
+
|
88
|
+
collector.add_binds(attrs, &bind_block)
|
89
|
+
# Monkey-patch end.
|
90
|
+
else
|
91
|
+
collector.add_binds(values, &bind_block)
|
92
|
+
end
|
93
|
+
|
94
|
+
collector << ")"
|
95
|
+
collector
|
96
|
+
end
|
97
|
+
|
98
|
+
def visit_Arel_Nodes_SelectStatement(o, collector)
|
67
99
|
@select_statement = o
|
68
100
|
distinct_One_As_One_Is_So_Not_Fetch o
|
69
101
|
if o.with
|
@@ -80,7 +112,17 @@ module Arel
|
|
80
112
|
@select_statement = nil
|
81
113
|
end
|
82
114
|
|
83
|
-
def
|
115
|
+
def visit_Arel_Nodes_SelectCore(o, collector)
|
116
|
+
collector = super
|
117
|
+
maybe_visit o.optimizer_hints, collector
|
118
|
+
end
|
119
|
+
|
120
|
+
def visit_Arel_Nodes_OptimizerHints(o, collector)
|
121
|
+
hints = o.expr.map { |v| sanitize_as_option_clause(v) }.join(", ")
|
122
|
+
collector << "OPTION (#{hints})"
|
123
|
+
end
|
124
|
+
|
125
|
+
def visit_Arel_Table(o, collector)
|
84
126
|
# Apparently, o.engine.connection can actually be a different adapter
|
85
127
|
# than sqlserver. Can be removed if fixed in ActiveRecord. See:
|
86
128
|
# github.com/rails-sqlserver/activerecord-sqlserver-adapter/issues/450
|
@@ -102,7 +144,7 @@ module Arel
|
|
102
144
|
end
|
103
145
|
end
|
104
146
|
|
105
|
-
def visit_Arel_Nodes_JoinSource
|
147
|
+
def visit_Arel_Nodes_JoinSource(o, collector)
|
106
148
|
if o.left
|
107
149
|
collector = visit o.left, collector
|
108
150
|
collector = visit_Arel_Nodes_SelectStatement_SQLServer_Lock collector
|
@@ -114,39 +156,53 @@ module Arel
|
|
114
156
|
collector
|
115
157
|
end
|
116
158
|
|
117
|
-
def visit_Arel_Nodes_InnerJoin
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
if o.right
|
122
|
-
collector << " "
|
123
|
-
visit(o.right, collector)
|
159
|
+
def visit_Arel_Nodes_InnerJoin(o, collector)
|
160
|
+
if o.left.is_a?(Arel::Nodes::As) && o.left.left.is_a?(Arel::Nodes::Lateral)
|
161
|
+
collector << "CROSS "
|
162
|
+
visit o.left, collector
|
124
163
|
else
|
125
|
-
collector
|
164
|
+
collector << "INNER JOIN "
|
165
|
+
collector = visit o.left, collector
|
166
|
+
collector = visit_Arel_Nodes_SelectStatement_SQLServer_Lock collector, space: true
|
167
|
+
if o.right
|
168
|
+
collector << " "
|
169
|
+
visit(o.right, collector)
|
170
|
+
else
|
171
|
+
collector
|
172
|
+
end
|
126
173
|
end
|
127
174
|
end
|
128
175
|
|
129
|
-
def visit_Arel_Nodes_OuterJoin
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
176
|
+
def visit_Arel_Nodes_OuterJoin(o, collector)
|
177
|
+
if o.left.is_a?(Arel::Nodes::As) && o.left.left.is_a?(Arel::Nodes::Lateral)
|
178
|
+
collector << "OUTER "
|
179
|
+
visit o.left, collector
|
180
|
+
else
|
181
|
+
collector << "LEFT OUTER JOIN "
|
182
|
+
collector = visit o.left, collector
|
183
|
+
collector = visit_Arel_Nodes_SelectStatement_SQLServer_Lock collector, space: true
|
184
|
+
collector << " "
|
185
|
+
visit o.right, collector
|
186
|
+
end
|
135
187
|
end
|
136
188
|
|
137
|
-
def
|
138
|
-
if Array === right
|
139
|
-
right.each { |node| remove_invalid_ordering_from_select_statement(node) }
|
189
|
+
def visit_Arel_Nodes_In(o, collector)
|
190
|
+
if Array === o.right
|
191
|
+
o.right.each { |node| remove_invalid_ordering_from_select_statement(node) }
|
140
192
|
else
|
141
|
-
remove_invalid_ordering_from_select_statement(right)
|
193
|
+
remove_invalid_ordering_from_select_statement(o.right)
|
142
194
|
end
|
143
195
|
|
144
196
|
super
|
145
197
|
end
|
146
198
|
|
199
|
+
def collect_optimizer_hints(o, collector)
|
200
|
+
collector
|
201
|
+
end
|
202
|
+
|
147
203
|
# SQLServer ToSql/Visitor (Additions)
|
148
204
|
|
149
|
-
def visit_Arel_Nodes_SelectStatement_SQLServer_Lock
|
205
|
+
def visit_Arel_Nodes_SelectStatement_SQLServer_Lock(collector, options = {})
|
150
206
|
if select_statement_lock?
|
151
207
|
collector = visit @select_statement.lock, collector
|
152
208
|
collector << " " if options[:space]
|
@@ -154,7 +210,7 @@ module Arel
|
|
154
210
|
collector
|
155
211
|
end
|
156
212
|
|
157
|
-
def visit_Orders_And_Let_Fetch_Happen
|
213
|
+
def visit_Orders_And_Let_Fetch_Happen(o, collector)
|
158
214
|
make_Fetch_Possible_And_Deterministic o
|
159
215
|
unless o.orders.empty?
|
160
216
|
collector << " ORDER BY "
|
@@ -167,13 +223,25 @@ module Arel
|
|
167
223
|
collector
|
168
224
|
end
|
169
225
|
|
170
|
-
def visit_Make_Fetch_Happen
|
226
|
+
def visit_Make_Fetch_Happen(o, collector)
|
171
227
|
o.offset = Nodes::Offset.new(0) if o.limit && !o.offset
|
172
228
|
collector = visit o.offset, collector if o.offset
|
173
229
|
collector = visit o.limit, collector if o.limit
|
174
230
|
collector
|
175
231
|
end
|
176
232
|
|
233
|
+
def visit_Arel_Nodes_Lateral(o, collector)
|
234
|
+
collector << "APPLY"
|
235
|
+
collector << " "
|
236
|
+
if o.expr.is_a?(Arel::Nodes::SelectStatement)
|
237
|
+
collector << "("
|
238
|
+
visit(o.expr, collector)
|
239
|
+
collector << ")"
|
240
|
+
else
|
241
|
+
visit(o.expr, collector)
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
177
245
|
# SQLServer Helpers
|
178
246
|
|
179
247
|
def node_value(node)
|
@@ -190,7 +258,7 @@ module Arel
|
|
190
258
|
@select_statement && @select_statement.lock
|
191
259
|
end
|
192
260
|
|
193
|
-
def make_Fetch_Possible_And_Deterministic
|
261
|
+
def make_Fetch_Possible_And_Deterministic(o)
|
194
262
|
return if o.limit.nil? && o.offset.nil?
|
195
263
|
|
196
264
|
t = table_From_Statement o
|
@@ -203,7 +271,7 @@ module Arel
|
|
203
271
|
end
|
204
272
|
end
|
205
273
|
|
206
|
-
def distinct_One_As_One_Is_So_Not_Fetch
|
274
|
+
def distinct_One_As_One_Is_So_Not_Fetch(o)
|
207
275
|
core = o.cores.first
|
208
276
|
distinct = Nodes::Distinct === core.set_quantifier
|
209
277
|
oneasone = core.projections.all? { |x| x == ActiveRecord::FinderMethods::ONE_AS_ONE }
|
@@ -214,7 +282,7 @@ module Arel
|
|
214
282
|
end
|
215
283
|
end
|
216
284
|
|
217
|
-
def table_From_Statement
|
285
|
+
def table_From_Statement(o)
|
218
286
|
core = o.cores.first
|
219
287
|
if Arel::Table === core.from
|
220
288
|
core.from
|
@@ -225,15 +293,15 @@ module Arel
|
|
225
293
|
end
|
226
294
|
end
|
227
295
|
|
228
|
-
def primary_Key_From_Table
|
296
|
+
def primary_Key_From_Table(t)
|
229
297
|
return unless t
|
230
298
|
|
231
299
|
column_name = @connection.schema_cache.primary_keys(t.name) ||
|
232
|
-
|
300
|
+
@connection.schema_cache.columns_hash(t.name).first.try(:second).try(:name)
|
233
301
|
column_name ? t[column_name] : nil
|
234
302
|
end
|
235
303
|
|
236
|
-
def remote_server_table_name
|
304
|
+
def remote_server_table_name(o)
|
237
305
|
ActiveRecord::ConnectionAdapters::SQLServer::Utils.extract_identifiers(
|
238
306
|
"#{o.class.engine.connection.database_prefix}#{o.name}"
|
239
307
|
).quoted
|
@@ -247,6 +315,10 @@ module Arel
|
|
247
315
|
|
248
316
|
node.orders = [] unless node.offset || node.limit
|
249
317
|
end
|
318
|
+
|
319
|
+
def sanitize_as_option_clause(value)
|
320
|
+
value.gsub(%r{OPTION \s* \( (.+) \)}xi, "\\1")
|
321
|
+
end
|
250
322
|
end
|
251
323
|
end
|
252
324
|
end
|
@@ -6,6 +6,7 @@ require "models/task"
|
|
6
6
|
require "models/post"
|
7
7
|
require "models/subscriber"
|
8
8
|
require "models/minimalistic"
|
9
|
+
require "models/college"
|
9
10
|
|
10
11
|
class AdapterTestSQLServer < ActiveRecord::TestCase
|
11
12
|
fixtures :tasks
|
@@ -42,17 +43,49 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
42
43
|
assert connection.supports_ddl_transactions?
|
43
44
|
end
|
44
45
|
|
45
|
-
it "
|
46
|
+
it "table exists works if table name prefixed by schema and owner" do
|
46
47
|
begin
|
47
48
|
assert_equal "topics", Topic.table_name
|
48
49
|
assert Topic.table_exists?
|
50
|
+
|
51
|
+
# Test when owner included in table name.
|
49
52
|
Topic.table_name = "dbo.topics"
|
50
|
-
assert Topic.table_exists?, "
|
53
|
+
assert Topic.table_exists?, "Topics table name of 'dbo.topics' should return true for exists."
|
54
|
+
|
55
|
+
# Test when database and owner included in table name.
|
56
|
+
db_config = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", name: "primary")
|
57
|
+
Topic.table_name = "#{db_config.database}.dbo.topics"
|
58
|
+
assert Topic.table_exists?, "Topics table name of '[DATABASE].dbo.topics' should return true for exists."
|
51
59
|
ensure
|
52
60
|
Topic.table_name = "topics"
|
53
61
|
end
|
54
62
|
end
|
55
63
|
|
64
|
+
it "test table existence across database schemas" do
|
65
|
+
arunit_connection = Topic.connection
|
66
|
+
arunit2_connection = College.connection
|
67
|
+
|
68
|
+
arunit_database = arunit_connection.pool.db_config.database
|
69
|
+
arunit2_database = arunit2_connection.pool.db_config.database
|
70
|
+
|
71
|
+
# Assert that connections use different default databases schemas.
|
72
|
+
assert_not_equal arunit_database, arunit2_database
|
73
|
+
|
74
|
+
# Assert that the Topics table exists when using the Topics connection.
|
75
|
+
assert arunit_connection.table_exists?('topics'), 'Topics table exists using table name'
|
76
|
+
assert arunit_connection.table_exists?('dbo.topics'), 'Topics table exists using owner and table name'
|
77
|
+
assert arunit_connection.table_exists?("#{arunit_database}.dbo.topics"), 'Topics table exists using database, owner and table name'
|
78
|
+
|
79
|
+
# Assert that the Colleges table exists when using the Colleges connection.
|
80
|
+
assert arunit2_connection.table_exists?('colleges'), 'College table exists using table name'
|
81
|
+
assert arunit2_connection.table_exists?('dbo.colleges'), 'College table exists using owner and table name'
|
82
|
+
assert arunit2_connection.table_exists?("#{arunit2_database}.dbo.colleges"), 'College table exists using database, owner and table name'
|
83
|
+
|
84
|
+
# Assert that the tables exist when using each others connection.
|
85
|
+
assert arunit_connection.table_exists?("#{arunit2_database}.dbo.colleges"), 'Colleges table exists using Topics connection'
|
86
|
+
assert arunit2_connection.table_exists?("#{arunit_database}.dbo.topics"), 'Topics table exists using Colleges connection'
|
87
|
+
end
|
88
|
+
|
56
89
|
it "return true to insert sql query for inserts only" do
|
57
90
|
assert connection.send(:insert_sql?, "INSERT...")
|
58
91
|
assert connection.send(:insert_sql?, "EXEC sp_executesql N'INSERT INTO [fk_test_has_fks] ([fk_id]) VALUES (@0); SELECT CAST(SCOPE_IDENTITY() AS bigint) AS Ident', N'@0 int', @0 = 0")
|
@@ -68,21 +101,23 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
68
101
|
|
69
102
|
it "test bad connection" do
|
70
103
|
assert_raise ActiveRecord::NoDatabaseError do
|
71
|
-
|
72
|
-
|
104
|
+
db_config = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", name: "primary")
|
105
|
+
configuration = db_config.configuration_hash.merge(database: "inexistent_activerecord_unittest")
|
106
|
+
ActiveRecord::Base.sqlserver_connection configuration
|
73
107
|
end
|
74
108
|
end
|
75
109
|
|
76
110
|
it "test database exists returns false if database does not exist" do
|
77
|
-
|
78
|
-
|
111
|
+
db_config = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", name: "primary")
|
112
|
+
configuration = db_config.configuration_hash.merge(database: "inexistent_activerecord_unittest")
|
113
|
+
assert_not ActiveRecord::ConnectionAdapters::SQLServerAdapter.database_exists?(configuration),
|
79
114
|
"expected database to not exist"
|
80
115
|
end
|
81
116
|
|
82
117
|
it "test database exists returns true when the database exists" do
|
83
|
-
|
84
|
-
assert ActiveRecord::ConnectionAdapters::SQLServerAdapter.database_exists?(
|
85
|
-
"expected database #{
|
118
|
+
db_config = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", name: "primary")
|
119
|
+
assert ActiveRecord::ConnectionAdapters::SQLServerAdapter.database_exists?(db_config.configuration_hash),
|
120
|
+
"expected database #{db_config.database} to exist"
|
86
121
|
end
|
87
122
|
|
88
123
|
describe "with different language" do
|
@@ -434,12 +469,11 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
434
469
|
describe "block writes to a database" do
|
435
470
|
def setup
|
436
471
|
@conn = ActiveRecord::Base.connection
|
437
|
-
@connection_handler = ActiveRecord::Base.connection_handler
|
438
472
|
end
|
439
473
|
|
440
474
|
def test_errors_when_an_insert_query_is_called_while_preventing_writes
|
441
475
|
assert_raises(ActiveRecord::ReadOnlyError) do
|
442
|
-
|
476
|
+
ActiveRecord::Base.while_preventing_writes do
|
443
477
|
@conn.insert("INSERT INTO [subscribers] ([nick]) VALUES ('aido')")
|
444
478
|
end
|
445
479
|
end
|
@@ -449,7 +483,7 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
449
483
|
@conn.insert("INSERT INTO [subscribers] ([nick]) VALUES ('aido')")
|
450
484
|
|
451
485
|
assert_raises(ActiveRecord::ReadOnlyError) do
|
452
|
-
|
486
|
+
ActiveRecord::Base.while_preventing_writes do
|
453
487
|
@conn.update("UPDATE [subscribers] SET [subscribers].[name] = 'Aidan' WHERE [subscribers].[nick] = 'aido'")
|
454
488
|
end
|
455
489
|
end
|
@@ -459,7 +493,7 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
459
493
|
@conn.execute("INSERT INTO [subscribers] ([nick]) VALUES ('aido')")
|
460
494
|
|
461
495
|
assert_raises(ActiveRecord::ReadOnlyError) do
|
462
|
-
|
496
|
+
ActiveRecord::Base.while_preventing_writes do
|
463
497
|
@conn.execute("DELETE FROM [subscribers] WHERE [subscribers].[nick] = 'aido'")
|
464
498
|
end
|
465
499
|
end
|
@@ -468,7 +502,7 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
468
502
|
def test_doesnt_error_when_a_select_query_is_called_while_preventing_writes
|
469
503
|
@conn.execute("INSERT INTO [subscribers] ([nick]) VALUES ('aido')")
|
470
504
|
|
471
|
-
|
505
|
+
ActiveRecord::Base.while_preventing_writes do
|
472
506
|
assert_equal 1, @conn.execute("SELECT * FROM [subscribers] WHERE [subscribers].[nick] = 'aido'")
|
473
507
|
end
|
474
508
|
end
|