activerecord-sqlserver-adapter 7.2.2 → 8.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 +9 -4
- data/CHANGELOG.md +6 -22
- data/Dockerfile.ci +1 -1
- data/Gemfile +2 -0
- data/README.md +16 -17
- data/VERSION +1 -1
- data/activerecord-sqlserver-adapter.gemspec +2 -2
- data/docker-compose.ci.yml +0 -1
- data/lib/active_record/connection_adapters/sqlserver/core_ext/finder_methods.rb +1 -1
- data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +43 -48
- data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +119 -97
- data/lib/active_record/connection_adapters/sqlserver/showplan.rb +1 -0
- data/lib/active_record/connection_adapters/sqlserver/type/time.rb +3 -2
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +11 -21
- data/test/cases/adapter_test_sqlserver.rb +26 -4
- data/test/cases/coerced_tests.rb +56 -23
- data/test/cases/optimizer_hints_test_sqlserver.rb +0 -1
- metadata +7 -8
- data/lib/active_record/connection_adapters/sqlserver/core_ext/calculations.rb +0 -29
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 926f65915d98bb3c271370883fa89891fc575b5c6801cd8c235386c078d34bf5
|
4
|
+
data.tar.gz: 0a932a9d5edf0d3932e3f0ba44328ed77a033a1223f05699e8f4caa79116ac56
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ee45540a8d2ae57dc69a35048f4ccfbf01bcfc91e177e57405b19ccb8a3279eef7b752c22dee20c4171c8bb4e2cb0fcaadb99cd6c25d139fd2ef53577a5cb23a
|
7
|
+
data.tar.gz: 9184a7041e5de445103bcd47832352614897865f0ef49e83067b553786d089be73eb73c34dfaf3f102e02804ee7d8d40803d5582430ebfeecbe95f568b0b7cb7
|
data/.github/workflows/ci.yml
CHANGED
@@ -1,6 +1,12 @@
|
|
1
1
|
name: CI
|
2
2
|
|
3
|
-
on:
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches: [ main ]
|
6
|
+
pull_request:
|
7
|
+
branches: [ main ]
|
8
|
+
schedule:
|
9
|
+
- cron: '0 4 * * 1'
|
4
10
|
|
5
11
|
jobs:
|
6
12
|
test:
|
@@ -14,9 +20,8 @@ jobs:
|
|
14
20
|
fail-fast: false
|
15
21
|
matrix:
|
16
22
|
ruby:
|
17
|
-
- 3.
|
18
|
-
- 3.2.
|
19
|
-
- 3.3.2
|
23
|
+
- 3.3.4
|
24
|
+
- 3.2.5
|
20
25
|
|
21
26
|
steps:
|
22
27
|
- name: Checkout code
|
data/CHANGELOG.md
CHANGED
@@ -1,28 +1,12 @@
|
|
1
|
-
##
|
1
|
+
## v8.0.0
|
2
2
|
|
3
|
-
####
|
4
|
-
|
5
|
-
- [#1244](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1244) Allow INSERT statements with SELECT notation
|
6
|
-
- [#1247](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1247) Fix queries with date and date-time placeholder conditions
|
7
|
-
- [#1249](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1249) Binary basic columns should be limitable
|
8
|
-
- [#1255](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1255) Fixed the ordering of optimizer hints in the generated SQL
|
3
|
+
#### Changed
|
9
4
|
|
10
|
-
|
5
|
+
- [#1216](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1216) Refactor adapter interface to match abstract adapter
|
6
|
+
- [#1225](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1225) Drop support to Ruby 3.1
|
11
7
|
|
12
8
|
#### Fixed
|
13
9
|
|
14
|
-
- [#
|
15
|
-
|
16
|
-
## v7.2.0
|
17
|
-
|
18
|
-
#### Added
|
19
|
-
|
20
|
-
- [#1178](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1178) Support encrypting binary columns
|
21
|
-
|
22
|
-
#### Changed
|
23
|
-
|
24
|
-
- [#1153](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1153) Only support Ruby v3.1+
|
25
|
-
- [#1196](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1196) Use default inspect for database adapter
|
26
|
-
|
10
|
+
- [#1215](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1215) Fix mismatched foreign key errors
|
27
11
|
|
28
|
-
Please check [7-
|
12
|
+
Please check [7-2-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/blob/7-2-stable/CHANGELOG.md) for previous changes.
|
data/Dockerfile.ci
CHANGED
@@ -9,6 +9,6 @@ WORKDIR $WORKDIR
|
|
9
9
|
|
10
10
|
COPY . $WORKDIR
|
11
11
|
|
12
|
-
RUN
|
12
|
+
RUN bundle install --jobs `expr $(cat /proc/cpuinfo | grep -c "cpu cores") - 1` --retry 3
|
13
13
|
|
14
14
|
CMD ["sh"]
|
data/Gemfile
CHANGED
@@ -18,6 +18,8 @@ if ENV["RAILS_SOURCE"]
|
|
18
18
|
gemspec path: ENV["RAILS_SOURCE"]
|
19
19
|
elsif ENV["RAILS_BRANCH"]
|
20
20
|
gem "rails", github: "rails/rails", branch: ENV["RAILS_BRANCH"]
|
21
|
+
elsif ENV["RAILS_COMMIT"]
|
22
|
+
gem "rails", github: "rails/rails", ref: ENV["RAILS_COMMIT"]
|
21
23
|
else
|
22
24
|
# Need to get rails source because the gem doesn't include tests
|
23
25
|
version = ENV["RAILS_VERSION"] || begin
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# ActiveRecord SQL Server Adapter
|
1
|
+
# ActiveRecord SQL Server Adapter
|
2
2
|
|
3
3
|
* [](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/actions/workflows/ci.yml) - CI
|
4
4
|
* [](https://rubygems.org/gems/activerecord-sqlserver-adapter) - Gem Version
|
@@ -8,15 +8,18 @@
|
|
8
8
|
|
9
9
|
The SQL Server adapter for ActiveRecord using SQL Server 2012 or higher.
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
11
|
+
We follow a rational versioning policy that tracks Rails. That means that our 7.x version of the adapter is only
|
12
|
+
for the latest 7.x version of Rails. We also have stable branches for each major/minor release of ActiveRecord.
|
13
|
+
|
14
|
+
We support the versions of the adapter that are in the Rails [Bug Fixes](https://rubyonrails.org/maintenance)
|
15
|
+
maintenance group.
|
16
|
+
|
17
|
+
See [Rubygems](https://rubygems.org/gems/activerecord-sqlserver-adapter/versions) for the latest version of the adapter for each Rails release.
|
16
18
|
|
17
19
|
| Adapter Version | Rails Version | Support | Branch |
|
18
20
|
|-----------------|---------------|----------------|-------------------------------------------------------------------------------------------------|
|
19
|
-
| `
|
21
|
+
| `8.0.0` | `8.0.x` | Active | [main](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/main) |
|
22
|
+
| `7.2.x` | `7.2.x` | Active | [7-2-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/7-2-stable) |
|
20
23
|
| `7.1.x` | `7.1.x` | Active | [7-1-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/7-1-stable) |
|
21
24
|
| `7.0.x` | `7.0.x` | Ended | [7-0-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/7-0-stable) |
|
22
25
|
| `6.1.x` | `6.1.x` | Ended | [6-1-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/6-1-stable) |
|
@@ -26,7 +29,6 @@ their stable branches.
|
|
26
29
|
| `4.2.x` | `4.2.x` | Ended | [4-2-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/4-2-stable) |
|
27
30
|
| `4.1.x` | `4.1.x` | Ended | [4-1-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/4-1-stable) |
|
28
31
|
|
29
|
-
See [Rubygems](https://rubygems.org/gems/activerecord-sqlserver-adapter/versions) for the latest version of the adapter for each Rails release.
|
30
32
|
|
31
33
|
#### Native Data Type Support
|
32
34
|
|
@@ -103,16 +105,14 @@ configuration then implement the `configure_connection` method in an initializer
|
|
103
105
|
example we are setting the `TEXTSIZE` to 64 megabytes.
|
104
106
|
|
105
107
|
```ruby
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
@raw_connection.execute("SET TEXTSIZE #{64.megabytes}").do
|
112
|
-
end
|
108
|
+
ActiveRecord::ConnectionAdapters::SQLServerAdapter.prepend(
|
109
|
+
Module.new do
|
110
|
+
def configure_connection
|
111
|
+
super
|
112
|
+
@raw_connection.execute("SET TEXTSIZE #{64.megabytes}").do
|
113
113
|
end
|
114
114
|
end
|
115
|
-
|
115
|
+
)
|
116
116
|
```
|
117
117
|
|
118
118
|
#### Configure Application Name
|
@@ -262,7 +262,6 @@ Many many people have contributed. If you do not see your name here and it shoul
|
|
262
262
|
|
263
263
|
You can see an up-to-date list of contributors here: http://github.com/rails-sqlserver/activerecord-sqlserver-adapter/contributors
|
264
264
|
|
265
|
-
|
266
265
|
## License
|
267
266
|
|
268
267
|
ActiveRecord SQL Server Adapter is released under the [MIT License](https://opensource.org/licenses/MIT).
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
8.0.0
|
@@ -7,7 +7,7 @@ Gem::Specification.new do |spec|
|
|
7
7
|
spec.platform = Gem::Platform::RUBY
|
8
8
|
spec.version = version
|
9
9
|
|
10
|
-
spec.required_ruby_version = ">= 3.
|
10
|
+
spec.required_ruby_version = ">= 3.2.0"
|
11
11
|
|
12
12
|
spec.license = "MIT"
|
13
13
|
spec.authors = ["Ken Collins", "Anna Carey", "Will Bond", "Murray Steele", "Shawn Balestracci", "Joe Rafaniello", "Tom Ward", "Aidan Haran"]
|
@@ -27,6 +27,6 @@ Gem::Specification.new do |spec|
|
|
27
27
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
28
28
|
spec.require_paths = ["lib"]
|
29
29
|
|
30
|
-
spec.add_dependency "activerecord", "~>
|
30
|
+
spec.add_dependency "activerecord", "~> 8.0.0"
|
31
31
|
spec.add_dependency "tiny_tds"
|
32
32
|
end
|
data/docker-compose.ci.yml
CHANGED
@@ -13,50 +13,42 @@ module ActiveRecord
|
|
13
13
|
!READ_QUERY.match?(sql.b)
|
14
14
|
end
|
15
15
|
|
16
|
-
def
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
16
|
+
def perform_query(raw_connection, sql, binds, type_casted_binds, prepare:, notification_payload:, batch:)
|
17
|
+
result = if id_insert_table_name = query_requires_identity_insert?(sql)
|
18
|
+
# If the table name is a view, we need to get the base table name for enabling identity insert.
|
19
|
+
id_insert_table_name = view_table_name(id_insert_table_name) if view_exists?(id_insert_table_name)
|
20
|
+
|
21
|
+
with_identity_insert_enabled(id_insert_table_name, raw_connection) do
|
22
|
+
internal_exec_sql_query(sql, raw_connection)
|
23
|
+
end
|
24
|
+
else
|
25
|
+
internal_exec_sql_query(sql, raw_connection)
|
26
|
+
end
|
27
|
+
|
28
|
+
verified!
|
29
|
+
notification_payload[:row_count] = result.count
|
30
|
+
result
|
31
|
+
end
|
32
|
+
|
33
|
+
def cast_result(raw_result)
|
34
|
+
if raw_result.columns.empty?
|
35
|
+
ActiveRecord::Result.empty
|
36
|
+
else
|
37
|
+
ActiveRecord::Result.new(raw_result.columns, raw_result.rows)
|
28
38
|
end
|
29
39
|
end
|
30
40
|
|
31
|
-
def
|
32
|
-
|
33
|
-
|
34
|
-
check_if_write_query(sql)
|
35
|
-
mark_transaction_written_if_write(sql)
|
41
|
+
def affected_rows(raw_result)
|
42
|
+
raw_result.first['AffectedRows']
|
43
|
+
end
|
36
44
|
|
37
|
-
|
45
|
+
def raw_execute(sql, name = nil, binds = [], prepare: false, async: false, allow_retry: false, materialize_transactions: true, batch: false)
|
46
|
+
unless binds.nil? || binds.empty?
|
38
47
|
types, params = sp_executesql_types_and_parameters(binds)
|
39
48
|
sql = sp_executesql_sql(sql, types, params, name)
|
40
49
|
end
|
41
50
|
|
42
|
-
|
43
|
-
with_raw_connection do |conn|
|
44
|
-
result = if id_insert_table_name = query_requires_identity_insert?(sql)
|
45
|
-
# If the table name is a view, we need to get the base table name for enabling identity insert.
|
46
|
-
id_insert_table_name = view_table_name(id_insert_table_name) if view_exists?(id_insert_table_name)
|
47
|
-
|
48
|
-
with_identity_insert_enabled(id_insert_table_name, conn) do
|
49
|
-
internal_exec_sql_query(sql, conn)
|
50
|
-
end
|
51
|
-
else
|
52
|
-
internal_exec_sql_query(sql, conn)
|
53
|
-
end
|
54
|
-
|
55
|
-
verified!
|
56
|
-
notification_payload[:row_count] = result.count
|
57
|
-
result
|
58
|
-
end
|
59
|
-
end
|
51
|
+
super
|
60
52
|
end
|
61
53
|
|
62
54
|
def internal_exec_sql_query(sql, conn)
|
@@ -66,14 +58,14 @@ module ActiveRecord
|
|
66
58
|
finish_statement_handle(handle)
|
67
59
|
end
|
68
60
|
|
69
|
-
def exec_delete(sql, name, binds)
|
61
|
+
def exec_delete(sql, name = nil, binds = [])
|
70
62
|
sql = sql.dup << "; SELECT @@ROWCOUNT AS AffectedRows"
|
71
|
-
super(sql, name, binds)
|
63
|
+
super(sql, name, binds)
|
72
64
|
end
|
73
65
|
|
74
|
-
def exec_update(sql, name, binds)
|
66
|
+
def exec_update(sql, name = nil, binds = [])
|
75
67
|
sql = sql.dup << "; SELECT @@ROWCOUNT AS AffectedRows"
|
76
|
-
super(sql, name, binds)
|
68
|
+
super(sql, name, binds)
|
77
69
|
end
|
78
70
|
|
79
71
|
def begin_db_transaction
|
@@ -156,7 +148,7 @@ module ActiveRecord
|
|
156
148
|
returning_sql = if returning.is_a?(String)
|
157
149
|
returning
|
158
150
|
else
|
159
|
-
returning.map { |column| "INSERTED.#{quote_column_name(column)}" }.join(", ")
|
151
|
+
Array(returning).map { |column| "INSERTED.#{quote_column_name(column)}" }.join(", ")
|
160
152
|
end
|
161
153
|
sql << " OUTPUT #{returning_sql}"
|
162
154
|
end
|
@@ -332,10 +324,13 @@ module ActiveRecord
|
|
332
324
|
|
333
325
|
def sp_executesql_sql_type(attr)
|
334
326
|
if attr.respond_to?(:type)
|
335
|
-
|
327
|
+
type = attr.type.is_a?(ActiveRecord::Normalization::NormalizedValueType) ? attr.type.cast_type : attr.type
|
328
|
+
type = type.subtype if type.serialized?
|
329
|
+
|
330
|
+
return type.sqlserver_type if type.respond_to?(:sqlserver_type)
|
336
331
|
|
337
|
-
if
|
338
|
-
return
|
332
|
+
if type.is_a?(ActiveRecord::Encryption::EncryptedAttributeType) && type.instance_variable_get(:@cast_type).respond_to?(:sqlserver_type)
|
333
|
+
return type.instance_variable_get(:@cast_type).sqlserver_type
|
339
334
|
end
|
340
335
|
end
|
341
336
|
|
@@ -375,6 +370,7 @@ module ActiveRecord
|
|
375
370
|
sql = "EXEC sp_executesql #{quote(sql)}"
|
376
371
|
sql += ", #{types}, #{params}" unless params.empty?
|
377
372
|
end
|
373
|
+
|
378
374
|
sql.freeze
|
379
375
|
end
|
380
376
|
|
@@ -452,10 +448,9 @@ module ActiveRecord
|
|
452
448
|
# TinyTDS returns false instead of raising an exception if connection fails.
|
453
449
|
# Getting around this by raising an exception ourselves while PR
|
454
450
|
# https://github.com/rails-sqlserver/tiny_tds/pull/469 is not released.
|
455
|
-
def internal_raw_execute(sql,
|
456
|
-
result =
|
457
|
-
|
458
|
-
end
|
451
|
+
def internal_raw_execute(sql, raw_connection, perform_do: false)
|
452
|
+
result = raw_connection.execute(sql)
|
453
|
+
raise TinyTds::Error, "failed to execute statement" if result.is_a?(FalseClass)
|
459
454
|
|
460
455
|
perform_do ? result.do : result
|
461
456
|
end
|
@@ -14,22 +14,24 @@ module ActiveRecord
|
|
14
14
|
res
|
15
15
|
end
|
16
16
|
|
17
|
-
def drop_table(
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
17
|
+
def drop_table(*table_names, **options)
|
18
|
+
table_names.each do |table_name|
|
19
|
+
# Mimic CASCADE option as best we can.
|
20
|
+
if options[:force] == :cascade
|
21
|
+
execute_procedure(:sp_fkeys, pktable_name: table_name).each do |fkdata|
|
22
|
+
fktable = fkdata["FKTABLE_NAME"]
|
23
|
+
fkcolmn = fkdata["FKCOLUMN_NAME"]
|
24
|
+
pktable = fkdata["PKTABLE_NAME"]
|
25
|
+
pkcolmn = fkdata["PKCOLUMN_NAME"]
|
26
|
+
remove_foreign_key fktable, name: fkdata["FK_NAME"]
|
27
|
+
execute "DELETE FROM #{quote_table_name(fktable)} WHERE #{quote_column_name(fkcolmn)} IN ( SELECT #{quote_column_name(pkcolmn)} FROM #{quote_table_name(pktable)} )"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
if options[:if_exists] && version_year < 2016
|
31
|
+
execute "IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = #{quote(table_name)}) DROP TABLE #{quote_table_name(table_name)}", "SCHEMA"
|
32
|
+
else
|
33
|
+
super
|
27
34
|
end
|
28
|
-
end
|
29
|
-
if options[:if_exists] && version_year < 2016
|
30
|
-
execute "IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = #{quote(table_name)}) DROP TABLE #{quote_table_name(table_name)}", "SCHEMA"
|
31
|
-
else
|
32
|
-
super
|
33
35
|
end
|
34
36
|
end
|
35
37
|
|
@@ -37,18 +39,16 @@ module ActiveRecord
|
|
37
39
|
data = select("EXEC sp_helpindex #{quote(table_name)}", "SCHEMA") rescue []
|
38
40
|
|
39
41
|
data.reduce([]) do |indexes, index|
|
40
|
-
|
41
|
-
|
42
|
-
if index[:index_description].match?(/primary key/)
|
42
|
+
if index['index_description'].match?(/primary key/)
|
43
43
|
indexes
|
44
44
|
else
|
45
|
-
name = index[
|
46
|
-
unique = index[
|
45
|
+
name = index['index_name']
|
46
|
+
unique = index['index_description'].match?(/unique/)
|
47
47
|
where = select_value("SELECT [filter_definition] FROM sys.indexes WHERE name = #{quote(name)}", "SCHEMA")
|
48
48
|
orders = {}
|
49
49
|
columns = []
|
50
50
|
|
51
|
-
index[
|
51
|
+
index['index_keys'].split(",").each do |column|
|
52
52
|
column.strip!
|
53
53
|
|
54
54
|
if column.end_with?("(-)")
|
@@ -480,16 +480,15 @@ module ActiveRecord
|
|
480
480
|
end
|
481
481
|
|
482
482
|
def column_definitions(table_name)
|
483
|
-
identifier
|
484
|
-
database
|
485
|
-
view_exists
|
486
|
-
view_tblnm = view_table_name(table_name) if view_exists
|
483
|
+
identifier = database_prefix_identifier(table_name)
|
484
|
+
database = identifier.fully_qualified_database_quoted
|
485
|
+
view_exists = view_exists?(table_name)
|
487
486
|
|
488
487
|
if view_exists
|
489
488
|
sql = <<~SQL
|
490
489
|
SELECT LOWER(c.COLUMN_NAME) AS [name], c.COLUMN_DEFAULT AS [default]
|
491
490
|
FROM #{database}.INFORMATION_SCHEMA.COLUMNS c
|
492
|
-
WHERE c.TABLE_NAME = #{quote(
|
491
|
+
WHERE c.TABLE_NAME = #{quote(view_table_name(table_name))}
|
493
492
|
SQL
|
494
493
|
results = internal_exec_query(sql, "SCHEMA")
|
495
494
|
default_functions = results.each.with_object({}) { |row, out| out[row["name"]] = row["default"] }.compact
|
@@ -498,71 +497,93 @@ module ActiveRecord
|
|
498
497
|
sql = column_definitions_sql(database, identifier)
|
499
498
|
|
500
499
|
binds = []
|
501
|
-
nv128 = SQLServer::Type::UnicodeVarchar.new
|
500
|
+
nv128 = SQLServer::Type::UnicodeVarchar.new(limit: 128)
|
502
501
|
binds << Relation::QueryAttribute.new("TABLE_NAME", identifier.object, nv128)
|
503
502
|
binds << Relation::QueryAttribute.new("TABLE_SCHEMA", identifier.schema, nv128) unless identifier.schema.blank?
|
503
|
+
|
504
504
|
results = internal_exec_query(sql, "SCHEMA", binds)
|
505
|
+
raise ActiveRecord::StatementInvalid, "Table '#{table_name}' doesn't exist" if results.empty?
|
505
506
|
|
506
507
|
columns = results.map do |ci|
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
when nil
|
535
|
-
[nil, nil]
|
536
|
-
when /\A\((\w+\(\))\)\Z/
|
537
|
-
default_function = Regexp.last_match[1]
|
538
|
-
[nil, default_function]
|
539
|
-
when /\A\(N'(.*)'\)\Z/m
|
540
|
-
string_literal = SQLServer::Utils.unquote_string(Regexp.last_match[1])
|
541
|
-
[string_literal, nil]
|
542
|
-
when /CREATE DEFAULT/mi
|
543
|
-
[nil, nil]
|
544
|
-
else
|
545
|
-
type = case ci[:type]
|
546
|
-
when /smallint|int|bigint/ then ci[:_type]
|
547
|
-
else ci[:type]
|
548
|
-
end
|
549
|
-
value = default.match(/\A\((.*)\)\Z/m)[1]
|
550
|
-
value = select_value("SELECT CAST(#{value} AS #{type}) AS value", "SCHEMA")
|
551
|
-
[value, nil]
|
552
|
-
end
|
508
|
+
col = {
|
509
|
+
name: ci["name"],
|
510
|
+
numeric_scale: ci["numeric_scale"],
|
511
|
+
numeric_precision: ci["numeric_precision"],
|
512
|
+
datetime_precision: ci["datetime_precision"],
|
513
|
+
collation: ci["collation"],
|
514
|
+
ordinal_position: ci["ordinal_position"],
|
515
|
+
length: ci["length"]
|
516
|
+
}
|
517
|
+
|
518
|
+
col[:table_name] = view_exists ? view_table_name(table_name) : table_name
|
519
|
+
col[:type] = column_type(ci: ci)
|
520
|
+
col[:default_value], col[:default_function] = default_value_and_function(default: ci['default_value'],
|
521
|
+
name: ci['name'],
|
522
|
+
type: col[:type],
|
523
|
+
original_type: ci['type'],
|
524
|
+
view_exists: view_exists,
|
525
|
+
table_name: table_name,
|
526
|
+
default_functions: default_functions)
|
527
|
+
|
528
|
+
col[:null] = ci['is_nullable'].to_i == 1
|
529
|
+
col[:is_primary] = ci['is_primary'].to_i == 1
|
530
|
+
|
531
|
+
if [true, false].include?(ci['is_identity'])
|
532
|
+
col[:is_identity] = ci['is_identity']
|
533
|
+
else
|
534
|
+
col[:is_identity] = ci['is_identity'].to_i == 1
|
553
535
|
end
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
536
|
+
|
537
|
+
col
|
538
|
+
end
|
539
|
+
|
540
|
+
columns
|
541
|
+
end
|
542
|
+
|
543
|
+
def default_value_and_function(default:, name:, type:, original_type:, view_exists:, table_name:, default_functions:)
|
544
|
+
if default.nil? && view_exists
|
545
|
+
view_column = views_real_column_name(table_name, name).downcase
|
546
|
+
default = default_functions[view_column] if view_column.present?
|
559
547
|
end
|
560
548
|
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
549
|
+
case default
|
550
|
+
when nil
|
551
|
+
[nil, nil]
|
552
|
+
when /\A\((\w+\(\))\)\Z/
|
553
|
+
default_function = Regexp.last_match[1]
|
554
|
+
[nil, default_function]
|
555
|
+
when /\A\(N'(.*)'\)\Z/m
|
556
|
+
string_literal = SQLServer::Utils.unquote_string(Regexp.last_match[1])
|
557
|
+
[string_literal, nil]
|
558
|
+
when /CREATE DEFAULT/mi
|
559
|
+
[nil, nil]
|
560
|
+
else
|
561
|
+
type = case type
|
562
|
+
when /smallint|int|bigint/ then original_type
|
563
|
+
else type
|
564
|
+
end
|
565
|
+
value = default.match(/\A\((.*)\)\Z/m)[1]
|
566
|
+
value = select_value("SELECT CAST(#{value} AS #{type}) AS value", "SCHEMA")
|
567
|
+
[value, nil]
|
568
|
+
end
|
569
|
+
end
|
570
|
+
|
571
|
+
def column_type(ci:)
|
572
|
+
case ci['type']
|
573
|
+
when /^bit|image|text|ntext|datetime$/
|
574
|
+
ci['type']
|
575
|
+
when /^datetime2|datetimeoffset$/i
|
576
|
+
"#{ci['type']}(#{ci['datetime_precision']})"
|
577
|
+
when /^time$/i
|
578
|
+
"#{ci['type']}(#{ci['datetime_precision']})"
|
579
|
+
when /^numeric|decimal$/i
|
580
|
+
"#{ci['type']}(#{ci['numeric_precision']},#{ci['numeric_scale']})"
|
581
|
+
when /^float|real$/i
|
582
|
+
"#{ci['type']}"
|
583
|
+
when /^char|nchar|varchar|nvarchar|binary|varbinary|bigint|int|smallint$/
|
584
|
+
ci['length'].to_i == -1 ? "#{ci['type']}(max)" : "#{ci['type']}(#{ci['length']})"
|
585
|
+
else
|
586
|
+
ci['type']
|
566
587
|
end
|
567
588
|
end
|
568
589
|
|
@@ -702,25 +723,26 @@ module ActiveRecord
|
|
702
723
|
|
703
724
|
def view_table_name(table_name)
|
704
725
|
view_info = view_information(table_name)
|
705
|
-
view_info ? get_table_name(view_info["VIEW_DEFINITION"]) : table_name
|
726
|
+
view_info.present? ? get_table_name(view_info["VIEW_DEFINITION"]) : table_name
|
706
727
|
end
|
707
728
|
|
708
729
|
def view_information(table_name)
|
709
730
|
@view_information ||= {}
|
731
|
+
|
710
732
|
@view_information[table_name] ||= begin
|
711
733
|
identifier = SQLServer::Utils.extract_identifiers(table_name)
|
712
734
|
information_query_table = identifier.database.present? ? "[#{identifier.database}].[INFORMATION_SCHEMA].[VIEWS]" : "[INFORMATION_SCHEMA].[VIEWS]"
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
if view_info[
|
718
|
-
view_info[
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
735
|
+
|
736
|
+
view_info = select_one("SELECT * FROM #{information_query_table} WITH (NOLOCK) WHERE TABLE_NAME = #{quote(identifier.object)}", "SCHEMA").to_h
|
737
|
+
|
738
|
+
if view_info.present?
|
739
|
+
if view_info['VIEW_DEFINITION'].blank? || view_info['VIEW_DEFINITION'].length == 4000
|
740
|
+
view_info['VIEW_DEFINITION'] = begin
|
741
|
+
select_values("EXEC sp_helptext #{identifier.object_quoted}", "SCHEMA").join
|
742
|
+
rescue
|
743
|
+
warn "No view definition found, possible permissions problem.\nPlease run GRANT VIEW DEFINITION TO your_user;"
|
744
|
+
nil
|
745
|
+
end
|
724
746
|
end
|
725
747
|
end
|
726
748
|
|
@@ -729,8 +751,8 @@ module ActiveRecord
|
|
729
751
|
end
|
730
752
|
|
731
753
|
def views_real_column_name(table_name, column_name)
|
732
|
-
view_definition = view_information(table_name)[
|
733
|
-
return column_name
|
754
|
+
view_definition = view_information(table_name)['VIEW_DEFINITION']
|
755
|
+
return column_name if view_definition.blank?
|
734
756
|
|
735
757
|
# Remove "CREATE VIEW ... AS SELECT ..." and then match the column name.
|
736
758
|
match_data = view_definition.sub(/CREATE\s+VIEW.*AS\s+SELECT\s/, '').match(/([\w-]*)\s+AS\s+#{column_name}\W/im)
|
@@ -36,9 +36,10 @@ module ActiveRecord
|
|
36
36
|
|
37
37
|
def cast_value(value)
|
38
38
|
value = super
|
39
|
-
return if value.blank?
|
40
39
|
|
41
|
-
value
|
40
|
+
return value unless value.is_a?(::Time)
|
41
|
+
|
42
|
+
value = value.change(year: 2000, month: 01, day: 01)
|
42
43
|
apply_seconds_precision(value)
|
43
44
|
end
|
44
45
|
|
@@ -4,9 +4,7 @@ require "tiny_tds"
|
|
4
4
|
require "base64"
|
5
5
|
require "active_record"
|
6
6
|
require "arel_sqlserver"
|
7
|
-
require "active_record/connection_adapters/abstract_adapter"
|
8
7
|
require "active_record/connection_adapters/sqlserver/core_ext/active_record"
|
9
|
-
require "active_record/connection_adapters/sqlserver/core_ext/calculations"
|
10
8
|
require "active_record/connection_adapters/sqlserver/core_ext/explain"
|
11
9
|
require "active_record/connection_adapters/sqlserver/core_ext/explain_subscriber"
|
12
10
|
require "active_record/connection_adapters/sqlserver/core_ext/attribute_methods"
|
@@ -431,36 +429,28 @@ module ActiveRecord
|
|
431
429
|
TYPE_MAP
|
432
430
|
end
|
433
431
|
|
434
|
-
def translate_exception(
|
432
|
+
def translate_exception(exception, message:, sql:, binds:)
|
435
433
|
case message
|
436
434
|
when /(SQL Server client is not connected)|(failed to execute statement)/i
|
437
|
-
ConnectionNotEstablished.new(message)
|
435
|
+
ConnectionNotEstablished.new(message, connection_pool: @pool)
|
438
436
|
when /(cannot insert duplicate key .* with unique index) | (violation of (unique|primary) key constraint)/i
|
439
|
-
RecordNotUnique.new(message, sql: sql, binds: binds)
|
437
|
+
RecordNotUnique.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
440
438
|
when /(conflicted with the foreign key constraint) | (The DELETE statement conflicted with the REFERENCE constraint)/i
|
441
|
-
InvalidForeignKey.new(message, sql: sql, binds: binds)
|
439
|
+
InvalidForeignKey.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
442
440
|
when /has been chosen as the deadlock victim/i
|
443
|
-
DeadlockVictim.new(message, sql: sql, binds: binds)
|
441
|
+
DeadlockVictim.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
444
442
|
when /database .* does not exist/i
|
445
|
-
NoDatabaseError.new(message)
|
443
|
+
NoDatabaseError.new(message, connection_pool: @pool)
|
446
444
|
when /data would be truncated/
|
447
|
-
ValueTooLong.new(message, sql: sql, binds: binds)
|
445
|
+
ValueTooLong.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
448
446
|
when /connection timed out/
|
449
|
-
StatementTimeout.new(message, sql: sql, binds: binds)
|
447
|
+
StatementTimeout.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
450
448
|
when /Column '(.*)' is not the same data type as referencing column '(.*)' in foreign key/
|
451
|
-
|
452
|
-
MismatchedForeignKey.new(
|
453
|
-
self,
|
454
|
-
message: message,
|
455
|
-
table: fk_id.schema,
|
456
|
-
foreign_key: fk_id.object,
|
457
|
-
target_table: pk_id.schema,
|
458
|
-
primary_key: pk_id.object
|
459
|
-
)
|
449
|
+
MismatchedForeignKey.new(message: message, connection_pool: @pool)
|
460
450
|
when /Cannot insert the value NULL into column.*does not allow nulls/
|
461
|
-
NotNullViolation.new(message, sql: sql, binds: binds)
|
451
|
+
NotNullViolation.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
462
452
|
when /Arithmetic overflow error/
|
463
|
-
RangeError.new(message, sql: sql, binds: binds)
|
453
|
+
RangeError.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
464
454
|
else
|
465
455
|
super
|
466
456
|
end
|
@@ -464,13 +464,13 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
464
464
|
assert SSTestStringDefaultsView.lease_connection.data_source_exists?(SSTestStringDefaultsView.table_name)
|
465
465
|
end
|
466
466
|
|
467
|
-
# That have more than 4000 chars for their
|
467
|
+
# That have more than 4000 chars for their definition
|
468
468
|
|
469
|
-
it "cope with null returned for the
|
469
|
+
it "cope with null returned for the definition" do
|
470
470
|
assert_nothing_raised() { SSTestStringDefaultsBigView.columns }
|
471
471
|
end
|
472
472
|
|
473
|
-
it "using alternate view
|
473
|
+
it "using alternate view definition still be able to find real default" do
|
474
474
|
assert_equal "null", SSTestStringDefaultsBigView.new.pretend_null,
|
475
475
|
SSTestStringDefaultsBigView.columns_hash["pretend_null"].inspect
|
476
476
|
end
|
@@ -542,7 +542,7 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
542
542
|
@conn.execute("INSERT INTO [subscribers] ([nick]) VALUES ('aido')")
|
543
543
|
|
544
544
|
ActiveRecord::Base.while_preventing_writes do
|
545
|
-
assert_equal 1, @conn.execute("SELECT * FROM [subscribers] WHERE [subscribers].[nick] = 'aido'")
|
545
|
+
assert_equal 1, @conn.execute("SELECT * FROM [subscribers] WHERE [subscribers].[nick] = 'aido'").count
|
546
546
|
end
|
547
547
|
end
|
548
548
|
end
|
@@ -581,6 +581,28 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
581
581
|
end
|
582
582
|
end
|
583
583
|
|
584
|
+
describe "mismatched foreign keys error" do
|
585
|
+
def setup
|
586
|
+
@conn = ActiveRecord::Base.lease_connection
|
587
|
+
end
|
588
|
+
|
589
|
+
it 'raises an error when the foreign key is mismatched' do
|
590
|
+
error = assert_raises(ActiveRecord::MismatchedForeignKey) do
|
591
|
+
@conn.add_reference :engines, :old_car
|
592
|
+
@conn.add_foreign_key :engines, :old_cars
|
593
|
+
end
|
594
|
+
|
595
|
+
assert_match(
|
596
|
+
%r/Column 'old_cars\.id' is not the same data type as referencing column 'engines\.old_car_id' in foreign key '.*'/,
|
597
|
+
error.message
|
598
|
+
)
|
599
|
+
assert_not_nil error.cause
|
600
|
+
assert_equal @conn.pool, error.connection_pool
|
601
|
+
ensure
|
602
|
+
@conn.execute("ALTER TABLE engines DROP COLUMN old_car_id") rescue nil
|
603
|
+
end
|
604
|
+
end
|
605
|
+
|
584
606
|
describe "placeholder conditions" do
|
585
607
|
it 'using time placeholder' do
|
586
608
|
assert_equal Task.where("starting < ?", Time.now).count, 1
|
data/test/cases/coerced_tests.rb
CHANGED
@@ -520,6 +520,9 @@ class CalculationsTest < ActiveRecord::TestCase
|
|
520
520
|
|
521
521
|
# SELECT columns must be in the GROUP clause. Since since `ids` only selects the primary key you cannot perform this query in SQL Server.
|
522
522
|
coerce_tests! :test_ids_with_includes_and_non_primary_key_order
|
523
|
+
|
524
|
+
# To limit the results in SQL Server we use `FETCH NEXT @0 ROWS ONLY` instead of `LIMIT @0`. To use `FETCH NEXT` an order must be provided.
|
525
|
+
coerce_tests! :test_no_order_by_when_counting_all
|
523
526
|
end
|
524
527
|
|
525
528
|
module ActiveRecord
|
@@ -1337,6 +1340,20 @@ module ActiveRecord
|
|
1337
1340
|
def test_registering_new_handlers_for_association_coerced
|
1338
1341
|
assert_match %r{#{Regexp.escape(topic_title)} ~ N'rails'}i, Reply.joins(:topic).where(topics: { title: /rails/ }).to_sql
|
1339
1342
|
end
|
1343
|
+
|
1344
|
+
# Same as original test except string has `N` prefix to indicate unicode string.
|
1345
|
+
coerce_tests! :test_registering_new_handlers_for_joins
|
1346
|
+
def test_registering_new_handlers_for_joins_coerced
|
1347
|
+
Reply.belongs_to :regexp_topic, -> { where(title: /rails/) }, class_name: "Topic", foreign_key: "parent_id"
|
1348
|
+
|
1349
|
+
assert_match %r{#{Regexp.escape(quote_table_name("regexp_topic.title"))} ~ N'rails'}i, Reply.joins(:regexp_topic).references(Arel.sql("regexp_topic")).to_sql
|
1350
|
+
end
|
1351
|
+
|
1352
|
+
private
|
1353
|
+
|
1354
|
+
def topic_title
|
1355
|
+
Topic.lease_connection.quote_table_name("topics.title")
|
1356
|
+
end
|
1340
1357
|
end
|
1341
1358
|
end
|
1342
1359
|
|
@@ -2168,17 +2185,6 @@ class EnumTest < ActiveRecord::TestCase
|
|
2168
2185
|
Book.lease_connection.add_index(:books, [:author_id, :name], unique: true)
|
2169
2186
|
end
|
2170
2187
|
|
2171
|
-
# Need to remove index as SQL Server considers NULLs on a unique-index to be equal unlike PostgreSQL/MySQL/SQLite.
|
2172
|
-
coerce_tests! %r{declare multiple enums at a time}
|
2173
|
-
test "declare multiple enums at a time coerced" do
|
2174
|
-
Book.lease_connection.remove_index(:books, column: [:author_id, :name])
|
2175
|
-
|
2176
|
-
send(:'original_declare multiple enums at a time')
|
2177
|
-
ensure
|
2178
|
-
Book.where(author_id: nil, name: nil).delete_all
|
2179
|
-
Book.lease_connection.add_index(:books, [:author_id, :name], unique: true)
|
2180
|
-
end
|
2181
|
-
|
2182
2188
|
# Need to remove index as SQL Server considers NULLs on a unique-index to be equal unlike PostgreSQL/MySQL/SQLite.
|
2183
2189
|
coerce_tests! %r{serializable\? with large number label}
|
2184
2190
|
test "serializable? with large number label coerced" do
|
@@ -2250,14 +2256,6 @@ class LogSubscriberTest < ActiveRecord::TestCase
|
|
2250
2256
|
def test_verbose_query_logs_coerced
|
2251
2257
|
original_test_verbose_query_logs
|
2252
2258
|
end
|
2253
|
-
|
2254
|
-
# Bindings logged slightly differently.
|
2255
|
-
coerce_tests! :test_where_in_binds_logging_include_attribute_names
|
2256
|
-
def test_where_in_binds_logging_include_attribute_names_coerced
|
2257
|
-
Developer.where(id: [1, 2, 3, 4, 5]).load
|
2258
|
-
wait
|
2259
|
-
assert_match(%{@0 = 1, @1 = 2, @2 = 3, @3 = 4, @4 = 5 [["id", nil], ["id", nil], ["id", nil], ["id", nil], ["id", nil]]}, @logger.logged(:debug).last)
|
2260
|
-
end
|
2261
2259
|
end
|
2262
2260
|
|
2263
2261
|
class ReloadModelsTest < ActiveRecord::TestCase
|
@@ -2419,7 +2417,9 @@ class QueryLogsTest < ActiveRecord::TestCase
|
|
2419
2417
|
# SQL requires double single-quotes.
|
2420
2418
|
coerce_tests! :test_sql_commenter_format
|
2421
2419
|
def test_sql_commenter_format_coerced
|
2422
|
-
ActiveRecord::QueryLogs.
|
2420
|
+
ActiveRecord::QueryLogs.tags_formatter = :sqlcommenter
|
2421
|
+
ActiveRecord::QueryLogs.tags = [:application]
|
2422
|
+
|
2423
2423
|
assert_queries_match(%r{/\*application=''active_record''\*/}) do
|
2424
2424
|
Dashboard.first
|
2425
2425
|
end
|
@@ -2428,7 +2428,7 @@ class QueryLogsTest < ActiveRecord::TestCase
|
|
2428
2428
|
# SQL requires double single-quotes.
|
2429
2429
|
coerce_tests! :test_sqlcommenter_format_value
|
2430
2430
|
def test_sqlcommenter_format_value_coerced
|
2431
|
-
ActiveRecord::QueryLogs.
|
2431
|
+
ActiveRecord::QueryLogs.tags_formatter = :sqlcommenter
|
2432
2432
|
|
2433
2433
|
ActiveRecord::QueryLogs.tags = [
|
2434
2434
|
:application,
|
@@ -2443,7 +2443,7 @@ class QueryLogsTest < ActiveRecord::TestCase
|
|
2443
2443
|
# SQL requires double single-quotes.
|
2444
2444
|
coerce_tests! :test_sqlcommenter_format_value_string_coercible
|
2445
2445
|
def test_sqlcommenter_format_value_string_coercible_coerced
|
2446
|
-
ActiveRecord::QueryLogs.
|
2446
|
+
ActiveRecord::QueryLogs.tags_formatter = :sqlcommenter
|
2447
2447
|
|
2448
2448
|
ActiveRecord::QueryLogs.tags = [
|
2449
2449
|
:application,
|
@@ -2458,7 +2458,7 @@ class QueryLogsTest < ActiveRecord::TestCase
|
|
2458
2458
|
# SQL requires double single-quotes.
|
2459
2459
|
coerce_tests! :test_sqlcommenter_format_allows_string_keys
|
2460
2460
|
def test_sqlcommenter_format_allows_string_keys_coerced
|
2461
|
-
ActiveRecord::QueryLogs.
|
2461
|
+
ActiveRecord::QueryLogs.tags_formatter = :sqlcommenter
|
2462
2462
|
|
2463
2463
|
ActiveRecord::QueryLogs.tags = [
|
2464
2464
|
:application,
|
@@ -2493,6 +2493,17 @@ class InsertAllTest < ActiveRecord::TestCase
|
|
2493
2493
|
result = Book.insert_all! [{ name: "Rework", author_id: 1 }], returning: Arel.sql("UPPER(INSERTED.name) as name")
|
2494
2494
|
assert_equal %w[ REWORK ], result.pluck("name")
|
2495
2495
|
end
|
2496
|
+
|
2497
|
+
# Need to remove index as SQL Server considers NULLs on a unique-index to be equal unlike PostgreSQL/MySQL/SQLite.
|
2498
|
+
coerce_tests! :test_insert_with_type_casting_and_serialize_is_consistent
|
2499
|
+
def test_insert_with_type_casting_and_serialize_is_consistent_coerced
|
2500
|
+
connection.remove_index(:books, column: [:author_id, :name])
|
2501
|
+
|
2502
|
+
original_test_insert_with_type_casting_and_serialize_is_consistent
|
2503
|
+
ensure
|
2504
|
+
Book.where(author_id: nil, name: '["Array"]').delete_all
|
2505
|
+
Book.lease_connection.add_index(:books, [:author_id, :name], unique: true)
|
2506
|
+
end
|
2496
2507
|
end
|
2497
2508
|
|
2498
2509
|
module ActiveRecord
|
@@ -2655,6 +2666,28 @@ module ActiveRecord
|
|
2655
2666
|
end
|
2656
2667
|
end
|
2657
2668
|
|
2669
|
+
module ActiveRecord
|
2670
|
+
module ConnectionAdapters
|
2671
|
+
class RegistrationIsolatedTest < ActiveRecord::TestCase
|
2672
|
+
# SQL Server was not included in the list of available adapters in the error message.
|
2673
|
+
coerce_tests! %r{resolve raises if the adapter is using the pre 7.2 adapter registration API}
|
2674
|
+
def resolve_raises_if_the_adapter_is_using_the_pre_7_2_adapter_registration_API
|
2675
|
+
exception = assert_raises(ActiveRecord::AdapterNotFound) do
|
2676
|
+
ActiveRecord::ConnectionAdapters.resolve("fake_legacy")
|
2677
|
+
end
|
2678
|
+
|
2679
|
+
assert_equal(
|
2680
|
+
"Database configuration specifies nonexistent 'ridiculous' adapter. Available adapters are: abstract, fake, mysql2, postgresql, sqlite3, sqlserver, trilogy. Ensure that the adapter is spelled correctly in config/database.yml and that you've added the necessary adapter gem to your Gemfile if it's not in the list of available adapters.",
|
2681
|
+
exception.message
|
2682
|
+
)
|
2683
|
+
ensure
|
2684
|
+
ActiveRecord::ConnectionAdapters.instance_variable_get(:@adapters).delete("fake_legacy")
|
2685
|
+
end
|
2686
|
+
end
|
2687
|
+
end
|
2688
|
+
end
|
2689
|
+
|
2690
|
+
|
2658
2691
|
module ActiveRecord
|
2659
2692
|
class TableMetadataTest < ActiveSupport::TestCase
|
2660
2693
|
# Adapter returns an object that is subclass of what is expected in the original test.
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord-sqlserver-adapter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 8.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ken Collins
|
@@ -15,7 +15,7 @@ authors:
|
|
15
15
|
autorequire:
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
|
-
date: 2024-11-
|
18
|
+
date: 2024-11-11 00:00:00.000000000 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: activerecord
|
@@ -23,14 +23,14 @@ dependencies:
|
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 8.0.0
|
27
27
|
type: :runtime
|
28
28
|
prerelease: false
|
29
29
|
version_requirements: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 8.0.0
|
34
34
|
- !ruby/object:Gem::Dependency
|
35
35
|
name: tiny_tds
|
36
36
|
requirement: !ruby/object:Gem::Requirement
|
@@ -79,7 +79,6 @@ files:
|
|
79
79
|
- lib/active_record/connection_adapters/sqlserver/core_ext/abstract_adapter.rb
|
80
80
|
- lib/active_record/connection_adapters/sqlserver/core_ext/active_record.rb
|
81
81
|
- lib/active_record/connection_adapters/sqlserver/core_ext/attribute_methods.rb
|
82
|
-
- lib/active_record/connection_adapters/sqlserver/core_ext/calculations.rb
|
83
82
|
- lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb
|
84
83
|
- lib/active_record/connection_adapters/sqlserver/core_ext/explain_subscriber.rb
|
85
84
|
- lib/active_record/connection_adapters/sqlserver/core_ext/finder_methods.rb
|
@@ -239,8 +238,8 @@ licenses:
|
|
239
238
|
- MIT
|
240
239
|
metadata:
|
241
240
|
bug_tracker_uri: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/issues
|
242
|
-
changelog_uri: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/blob/
|
243
|
-
source_code_uri: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/
|
241
|
+
changelog_uri: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/blob/v8.0.0/CHANGELOG.md
|
242
|
+
source_code_uri: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/v8.0.0
|
244
243
|
post_install_message:
|
245
244
|
rdoc_options: []
|
246
245
|
require_paths:
|
@@ -249,7 +248,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
249
248
|
requirements:
|
250
249
|
- - ">="
|
251
250
|
- !ruby/object:Gem::Version
|
252
|
-
version: 3.
|
251
|
+
version: 3.2.0
|
253
252
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
254
253
|
requirements:
|
255
254
|
- - ">="
|
@@ -1,29 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "active_record/relation"
|
4
|
-
require "active_record/version"
|
5
|
-
|
6
|
-
module ActiveRecord
|
7
|
-
module ConnectionAdapters
|
8
|
-
module SQLServer
|
9
|
-
module CoreExt
|
10
|
-
module Calculations
|
11
|
-
|
12
|
-
private
|
13
|
-
|
14
|
-
def build_count_subquery(relation, column_name, distinct)
|
15
|
-
klass.with_connection do |connection|
|
16
|
-
relation = relation.unscope(:order) if connection.sqlserver?
|
17
|
-
super(relation, column_name, distinct)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
ActiveSupport.on_load(:active_record) do
|
27
|
-
mod = ActiveRecord::ConnectionAdapters::SQLServer::CoreExt::Calculations
|
28
|
-
ActiveRecord::Relation.include(mod)
|
29
|
-
end
|