activerecord-sqlserver-adapter 7.1.7 → 7.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.devcontainer/Dockerfile +3 -3
  3. data/.github/workflows/ci.yml +10 -4
  4. data/CHANGELOG.md +5 -99
  5. data/Gemfile +4 -4
  6. data/README.md +43 -19
  7. data/VERSION +1 -1
  8. data/activerecord-sqlserver-adapter.gemspec +2 -2
  9. data/lib/active_record/connection_adapters/sqlserver/core_ext/attribute_methods.rb +6 -4
  10. data/lib/active_record/connection_adapters/sqlserver/core_ext/calculations.rb +6 -5
  11. data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +7 -4
  12. data/lib/active_record/connection_adapters/sqlserver/core_ext/finder_methods.rb +6 -4
  13. data/lib/active_record/connection_adapters/sqlserver/core_ext/preloader.rb +14 -12
  14. data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +50 -32
  15. data/lib/active_record/connection_adapters/sqlserver/quoting.rb +44 -46
  16. data/lib/active_record/connection_adapters/sqlserver/savepoints.rb +2 -0
  17. data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +1 -1
  18. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +2 -5
  19. data/lib/active_record/tasks/sqlserver_database_tasks.rb +38 -32
  20. data/lib/arel/visitors/sqlserver.rb +57 -12
  21. data/test/cases/active_schema_test_sqlserver.rb +6 -6
  22. data/test/cases/adapter_test_sqlserver.rb +17 -18
  23. data/test/cases/coerced_tests.rb +279 -167
  24. data/test/cases/disconnected_test_sqlserver.rb +9 -3
  25. data/test/cases/eager_load_too_many_ids_test_sqlserver.rb +1 -1
  26. data/test/cases/enum_test_sqlserver.rb +1 -1
  27. data/test/cases/execute_procedure_test_sqlserver.rb +9 -5
  28. data/test/cases/helper_sqlserver.rb +11 -5
  29. data/test/cases/index_test_sqlserver.rb +8 -6
  30. data/test/cases/json_test_sqlserver.rb +1 -1
  31. data/test/cases/lateral_test_sqlserver.rb +2 -2
  32. data/test/cases/migration_test_sqlserver.rb +1 -1
  33. data/test/cases/optimizer_hints_test_sqlserver.rb +12 -12
  34. data/test/cases/pessimistic_locking_test_sqlserver.rb +8 -7
  35. data/test/cases/primary_keys_test_sqlserver.rb +2 -2
  36. data/test/cases/rake_test_sqlserver.rb +8 -4
  37. data/test/cases/schema_dumper_test_sqlserver.rb +4 -5
  38. data/test/cases/showplan_test_sqlserver.rb +7 -7
  39. data/test/cases/specific_schema_test_sqlserver.rb +17 -13
  40. data/test/cases/view_test_sqlserver.rb +1 -1
  41. data/test/schema/sqlserver_specific_schema.rb +4 -4
  42. data/test/support/connection_reflection.rb +1 -1
  43. data/test/support/core_ext/query_cache.rb +2 -2
  44. data/test/support/query_assertions.rb +49 -0
  45. data/test/support/table_definition_sqlserver.rb +24 -0
  46. data/test/support/test_in_memory_oltp.rb +2 -2
  47. metadata +12 -13
  48. data/lib/active_record/sqlserver_base.rb +0 -13
  49. data/test/cases/scratchpad_test_sqlserver.rb +0 -8
  50. data/test/support/sql_counter_sqlserver.rb +0 -14
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eb26ce0a56d756f8e9ba1d571ab3f3b6ce092ac3c86f8b37bce56942ec96c485
4
- data.tar.gz: efa5adca77b15a3c5b25c216b1b63d311a1fbfbc5ab79186d94f1b4f9a6ecedb
3
+ metadata.gz: b6356803690516019929168fed2c356f3250eb5ec8a9894b8117fc35db84b8c1
4
+ data.tar.gz: dbedbedb583e766c526d959459166edd195516700fb6f0b1be2769ea1d947233
5
5
  SHA512:
6
- metadata.gz: 6bfc66070966a026f6f1b42bf1c87e48ad9e0d044ce01755eeddbcbc71f2b5cabd8cd395dc9ebfa0aa1e92c5b8f4c524ead92d1abf017b907de774f224c0c02a
7
- data.tar.gz: 9ebcf4c64077e0fdfac80b7f5ca6fc5b6218251f378dd6f61c3fcbfd48e4196a93fc09a5de87048834f1e96f3b839ddd2e0ec61457da081bf3f20fd5d5fed08c
6
+ metadata.gz: 5079fd8e88a8e67b91f11de2f9ec158d686afe121461f2b2050ebdd1072f1ac0fc86356dd81da507e99b72b8f9266aa5a59031d886dcb8d119715cab4cbef1c8
7
+ data.tar.gz: d1a8f37563ba09c443242e83f75098b2cc74bd269c9b11b9c6834a5e2fa23c7791f93083c7884ec1d22acdeca3bdf75f752153bde565fa0d92c3988a6653565c
@@ -6,9 +6,9 @@ FROM mcr.microsoft.com/devcontainers/ruby:${VARIANT}
6
6
 
7
7
  # TinyTDS
8
8
  RUN apt-get -y install libc6-dev \
9
- && wget http://www.freetds.org/files/stable/freetds-1.1.32.tar.gz \
10
- && tar -xzf freetds-1.1.32.tar.gz \
11
- && cd freetds-1.1.32 \
9
+ && wget http://www.freetds.org/files/stable/freetds-1.4.14.tar.gz \
10
+ && tar -xzf freetds-1.4.14.tar.gz \
11
+ && cd freetds-1.4.14 \
12
12
  && ./configure --prefix=/usr/local --with-tdsver=7.3 \
13
13
  && make \
14
14
  && make install
@@ -1,6 +1,12 @@
1
1
  name: CI
2
2
 
3
- on: [push, pull_request]
3
+ on:
4
+ push:
5
+ branches: [ main ]
6
+ pull_request:
7
+ branches: [ main ]
8
+ schedule:
9
+ - cron: '0 18 * * *'
4
10
 
5
11
  jobs:
6
12
  test:
@@ -14,9 +20,9 @@ jobs:
14
20
  fail-fast: false
15
21
  matrix:
16
22
  ruby:
17
- - 3.0.6
18
- - 3.1.4
19
- - 3.2.2
23
+ - 3.1.6
24
+ - 3.2.4
25
+ - 3.3.2
20
26
 
21
27
  steps:
22
28
  - name: Checkout code
data/CHANGELOG.md CHANGED
@@ -1,106 +1,12 @@
1
- ## v7.1.7
2
-
3
- #### Fixed
4
-
5
- - [#1210](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1210) Handle blank SQL when parsing table name
6
-
7
- ## v7.1.6
8
-
9
- #### Fixed
10
-
11
- - [#1208](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1208) Exclude "guest" schema in schema dumper
12
-
13
- ## v7.1.5
1
+ ## Unreleased
14
2
 
15
3
  #### Added
16
4
 
17
- - [#1201](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1201) Support non-dbo schemas in schema dumper
18
- - [#1206](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1206) Support table names containing spaces
19
-
20
- ## v7.1.4
21
-
22
- #### Fixed
23
-
24
- - [#1164](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1164) Fix composite primary key with different data type with triggers
5
+ - [#1178](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1178) Support encrypting binary columns
25
6
 
26
7
  #### Changed
27
8
 
28
- - [#1199](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1199) Remove ActiveRecord::Relation#calculate patch
29
-
30
- ## v7.1.3
31
-
32
- #### Fixed
33
-
34
- - [#1152](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1152) Fix Composite Key Inserts with Triggers
35
-
36
- ## v7.1.2
37
-
38
- #### Fixed
39
-
40
- - [#1151](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1151) FROM subquery should work if order provided
41
-
42
- ## v7.1.1
43
-
44
- #### Fixed
45
-
46
- - [#1145](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1145) Ensure correct order of COLLATE and NOT NULL in CREATE TABLE statements
47
- - [#1144](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1144) Fix precision handling in time migration
48
- - [#1143](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1143) Fix precision handling for datetimeoffset migration
49
-
50
- ## v7.1.0
51
-
52
- #### Added
53
-
54
- - [#1141](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1141) Added support for check constraints.
55
-
56
- ## v7.1.0.rc2
57
-
58
- #### Added
59
-
60
- - [#1136](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1136) Prevent marking broken connections as verified
61
- - [#1138](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1138) Cache quoted names
62
-
63
- ## v7.1.0.rc1
64
-
65
- #### Added
66
-
67
- * Rails 7.1 Support
68
-
69
- The adapter supports new Rails 7.1 features such as composite primary keys. See the
70
- [Rails 7.1 release notes](https://guides.rubyonrails.org/7_1_release_notes.html) for more information.
71
-
72
- #### Changed
73
-
74
- * Configure Connection
75
-
76
- If you require additional connection configuration you now need to call `super` within the `configure_connection`
77
- method so that the default configuration is also applied.
78
-
79
- v7.1.x adapter:
80
- ```ruby
81
- module ActiveRecord
82
- module ConnectionAdapters
83
- class SQLServerAdapter < AbstractAdapter
84
- def configure_connection
85
- super
86
- raw_connection_do "SET TEXTSIZE #{64.megabytes}"
87
- end
88
- end
89
- end
90
- end
91
- ```
92
-
93
- v7.0.x adapter:
94
- ```ruby
95
- module ActiveRecord
96
- module ConnectionAdapters
97
- class SQLServerAdapter < AbstractAdapter
98
- def configure_connection
99
- raw_connection_do "SET TEXTSIZE #{64.megabytes}"
100
- end
101
- end
102
- end
103
- end
104
- ```
9
+ - [#1153](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1153) Only support Ruby v3.1+
10
+ - [#1196](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1196) Use default inspect for database adapter
105
11
 
106
- Please check [7-0-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/blob/7-0-stable/CHANGELOG.md) for previous changes.
12
+ Please check [7-1-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/blob/7-1-stable/CHANGELOG.md) for previous changes.
data/Gemfile CHANGED
@@ -8,16 +8,16 @@ gemspec
8
8
 
9
9
  gem "bcrypt"
10
10
  gem "pg", ">= 0.18.0"
11
- gem "sqlite3", "~> 1.4"
11
+ gem "sqlite3", ">= 1.6.6"
12
12
  gem "tzinfo-data", platforms: [:mingw, :mswin, :x64_mingw, :jruby]
13
13
  gem "benchmark-ips"
14
- gem "minitest", ">= 5.15.0", "< 5.16"
14
+ gem "minitest", ">= 5.15.0"
15
15
  gem "msgpack", ">= 1.7.0"
16
16
 
17
17
  if ENV["RAILS_SOURCE"]
18
18
  gemspec path: ENV["RAILS_SOURCE"]
19
- elsif ENV["RAILS_MAIN"]
20
- gem "rails", github: "rails/rails", branch: 'main'
19
+ elsif ENV["RAILS_BRANCH"]
20
+ gem "rails", github: "rails/rails", branch: ENV["RAILS_BRANCH"]
21
21
  else
22
22
  # Need to get rails source because the gem doesn't include tests
23
23
  version = ENV["RAILS_VERSION"] || begin
data/README.md CHANGED
@@ -1,7 +1,6 @@
1
1
  # ActiveRecord SQL Server Adapter. For SQL Server 2012 And Higher.
2
2
 
3
3
  * [![CI](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/actions/workflows/ci.yml/badge.svg)](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/actions/workflows/ci.yml) - CI
4
- * [![Build Status](https://ci.appveyor.com/api/projects/status/mtgbx8f57vr7k2qa/branch/master?svg=true)](https://ci.appveyor.com/project/rails-sqlserver/activerecord-sqlserver-adapter/branch/master) - Appveyor
5
4
  * [![Gem Version](http://img.shields.io/gem/v/activerecord-sqlserver-adapter.svg)](https://rubygems.org/gems/activerecord-sqlserver-adapter) - Gem Version
6
5
  * [![Gitter chat](https://img.shields.io/badge/%E2%8A%AA%20GITTER%20-JOIN%20CHAT%20%E2%86%92-brightgreen.svg?style=flat)](https://gitter.im/rails-sqlserver/activerecord-sqlserver-adapter) - Community
7
6
 
@@ -9,21 +8,25 @@
9
8
 
10
9
  The SQL Server adapter for ActiveRecord using SQL Server 2012 or higher.
11
10
 
12
- Interested in older versions? We follow a rational versioning policy that tracks Rails. That means that our 7.x version of the adapter is only for the latest 7.x version of Rails. If you need the adapter for SQL Server 2008 or 2005, you are still in the right spot. Just install the latest 3.2.x to 4.1.x version of the adapter that matches your Rails version. We also have stable branches for each major/minor release of ActiveRecord.
13
-
14
- | Adapter Version | Rails Version | Support | Branch |
15
- |-----------------|---------------|---------|--------------------------------------------------------------------------------------------------|
16
- | Unreleased | `7.2.x` | In Development | [main](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/main) |
17
- | `7.1.7` | `7.1.x` | Active | [7-1-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/7-1-stable) |
18
- | `7.0.7` | `7.0.x` | Active | [7-0-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/7-0-stable) |
19
- | `6.1.3.0` | `6.1.x` | Active | [6-1-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/6-1-stable) |
20
- | `6.0.3` | `6.0.x` | Ended | [6-0-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/6-0-stable) |
21
- | `5.2.1` | `5.2.x` | Ended | [5-2-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/5-2-stable) |
22
- | `5.1.6` | `5.1.x` | Ended | [5-1-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/5-1-stable) |
23
- | `4.2.18` | `4.2.x` | Ended | [4-2-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/4-2-stable) |
24
- | `4.1.8` | `4.1.x` | Ended | [4-1-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/4-1-stable) |
25
-
26
- For older versions, please check their stable branches.
11
+ Interested in older versions? We follow a rational versioning policy that tracks Rails. That means that our 7.x version
12
+ of the adapter is only for the latest 7.x version of Rails. If you need the adapter for SQL Server 2008 or 2005, you
13
+ are still in the right spot. Just install the latest 3.2.x to 4.1.x version of the adapter that matches your Rails
14
+ version. We also have stable branches for each major/minor release of ActiveRecord. For older versions, please check
15
+ their stable branches.
16
+
17
+ | Adapter Version | Rails Version | Support | Branch |
18
+ |-----------------|---------------|----------------|-------------------------------------------------------------------------------------------------|
19
+ | `7.2.x` | `7.2.x` | Active | [main](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/main) |
20
+ | `7.1.x` | `7.1.x` | Active | [7-1-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/7-1-stable) |
21
+ | `7.0.x` | `7.0.x` | Active | [7-0-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/7-0-stable) |
22
+ | `6.1.x` | `6.1.x` | Active | [6-1-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/6-1-stable) |
23
+ | `6.0.x` | `6.0.x` | Ended | [6-0-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/6-0-stable) |
24
+ | `5.2.x` | `5.2.x` | Ended | [5-2-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/5-2-stable) |
25
+ | `5.1.x` | `5.1.x` | Ended | [5-1-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/5-1-stable) |
26
+ | `4.2.x` | `4.2.x` | Ended | [4-2-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/4-2-stable) |
27
+ | `4.1.x` | `4.1.x` | Ended | [4-1-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/4-1-stable) |
28
+
29
+ See [Rubygems](https://rubygems.org/gems/activerecord-sqlserver-adapter/versions) for the latest version of the adapter for each Rails release.
27
30
 
28
31
  #### Native Data Type Support
29
32
 
@@ -168,14 +171,35 @@ ActiveRecord::ConnectionAdapters::SQLServerAdapter.showplan_option = 'SHOWPLAN_X
168
171
 
169
172
  ## New Rails Applications
170
173
 
171
- When creating a new Rails application you can specify that you want to use the SQL Server adapter using the `database` option:
174
+ When creating a new Rails application you need to perform the following steps to connect a Rails application to a
175
+ SQL Server instance.
172
176
 
177
+ 1. Create new Rails application, the database defaults to `sqlite`.
178
+
179
+ ```bash
180
+ rails new my_app
173
181
  ```
174
- rails new my_app --database=sqlserver
182
+
183
+ 2. Update the Gemfile to install the adapter instead of the SQLite adapter. Remove the `sqlite3` gem from the Gemfile.
184
+
185
+ ```ruby
186
+ gem 'activerecord-sqlserver-adapter'
175
187
  ```
176
188
 
177
- To then connect the application to your SQL Server instance edit the `config/database.yml` file with the username, password and host of your SQL Server instance.
189
+ 3. Connect the application to your SQL Server instance by editing the `config/database.yml` file with the username,
190
+ password and host of your SQL Server instance.
191
+
192
+ Example:
178
193
 
194
+ ```yaml
195
+ development:
196
+ adapter: sqlserver
197
+ host: 'localhost'
198
+ port: 1433
199
+ database: my_app_development
200
+ username: 'frank_castle'
201
+ password: 'secret'
202
+ ```
179
203
 
180
204
  ## Installation
181
205
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 7.1.7
1
+ 7.2.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 = ">= 2.7.0"
10
+ spec.required_ruby_version = ">= 3.1.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", "~> 7.1.1"
30
+ spec.add_dependency "activerecord", "~> 7.2.0"
31
31
  spec.add_dependency "tiny_tds"
32
32
  end
@@ -10,11 +10,13 @@ module ActiveRecord
10
10
  private
11
11
 
12
12
  def attributes_for_update(attribute_names)
13
- return super unless self.class.connection.adapter_name == "SQLServer"
13
+ self.class.with_connection do |connection|
14
+ return super(attribute_names) unless connection.sqlserver?
14
15
 
15
- super.reject do |name|
16
- column = self.class.columns_hash[name]
17
- column && column.respond_to?(:is_identity?) && column.is_identity?
16
+ super(attribute_names).reject do |name|
17
+ column = self.class.columns_hash[name]
18
+ column && column.respond_to?(:is_identity?) && column.is_identity?
19
+ end
18
20
  end
19
21
  end
20
22
  end
@@ -8,13 +8,14 @@ module ActiveRecord
8
8
  module SQLServer
9
9
  module CoreExt
10
10
  module Calculations
11
-
12
- private
13
11
 
12
+ private
13
+
14
14
  def build_count_subquery(relation, column_name, distinct)
15
- return super unless klass.connection.adapter_name == "SQLServer"
16
-
17
- super(relation.unscope(:order), 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
18
19
  end
19
20
  end
20
21
  end
@@ -9,12 +9,15 @@ module ActiveRecord
9
9
  SQLSERVER_STATEMENT_REGEXP = /N'(.+)', N'(.+)', (.+)/
10
10
 
11
11
  def exec_explain(queries, options = [])
12
- return super unless connection.adapter_name == "SQLServer"
12
+ with_connection do |connection|
13
+ return super(queries, options) unless connection.sqlserver?
13
14
 
14
- unprepared_queries = queries.map do |(sql, binds)|
15
- [unprepare_sqlserver_statement(sql, binds), binds]
15
+ unprepared_queries = queries.map do |(sql, binds)|
16
+ [unprepare_sqlserver_statement(sql, binds), binds]
17
+ end
18
+
19
+ super(unprepared_queries, options)
16
20
  end
17
- super(unprepared_queries, options)
18
21
  end
19
22
 
20
23
  private
@@ -11,10 +11,12 @@ module ActiveRecord
11
11
  private
12
12
 
13
13
  def construct_relation_for_exists(conditions)
14
- if klass.connection.sqlserver?
15
- _construct_relation_for_exists(conditions)
16
- else
17
- super
14
+ klass.with_connection do |connection|
15
+ if connection.sqlserver?
16
+ _construct_relation_for_exists(conditions)
17
+ else
18
+ super
19
+ end
18
20
  end
19
21
  end
20
22
 
@@ -8,23 +8,25 @@ module ActiveRecord
8
8
  module CoreExt
9
9
  module LoaderQuery
10
10
  def load_records_for_keys(keys, &block)
11
- return super unless scope.connection.sqlserver?
11
+ scope.with_connection do |connection|
12
+ return super unless connection.sqlserver?
12
13
 
13
- return [] if keys.empty?
14
+ return [] if keys.empty?
14
15
 
15
- if association_key_name.is_a?(Array)
16
- query_constraints = Hash.new { |hsh, key| hsh[key] = Set.new }
16
+ if association_key_name.is_a?(Array)
17
+ query_constraints = Hash.new { |hsh, key| hsh[key] = Set.new }
17
18
 
18
- keys.each_with_object(query_constraints) do |values_set, constraints|
19
- association_key_name.zip(values_set).each do |key_name, value|
20
- constraints[key_name] << value
19
+ keys.each_with_object(query_constraints) do |values_set, constraints|
20
+ association_key_name.zip(values_set).each do |key_name, value|
21
+ constraints[key_name] << value
22
+ end
21
23
  end
22
- end
23
24
 
24
- scope.where(query_constraints).load(&block)
25
- else
26
- keys.each_slice(in_clause_length).flat_map do |slice|
27
- scope.where(association_key_name => slice).load(&block).records
25
+ scope.where(query_constraints).load(&block)
26
+ else
27
+ keys.each_slice(in_clause_length).flat_map do |slice|
28
+ scope.where(association_key_name => slice).load(&block).records
29
+ end
28
30
  end
29
31
  end
30
32
  end
@@ -14,9 +14,7 @@ module ActiveRecord
14
14
  end
15
15
 
16
16
  def raw_execute(sql, name, async: false, allow_retry: false, materialize_transactions: true)
17
- result = nil
18
-
19
- log(sql, name, async: async) do
17
+ log(sql, name, async: async) do |notification_payload|
20
18
  with_raw_connection(allow_retry: allow_retry, materialize_transactions: materialize_transactions) do |conn|
21
19
  result = if id_insert_table_name = query_requires_identity_insert?(sql)
22
20
  with_identity_insert_enabled(id_insert_table_name, conn) { internal_raw_execute(sql, conn, perform_do: true) }
@@ -24,14 +22,13 @@ module ActiveRecord
24
22
  internal_raw_execute(sql, conn, perform_do: true)
25
23
  end
26
24
  verified!
25
+ notification_payload[:row_count] = result
26
+ result
27
27
  end
28
28
  end
29
-
30
- result
31
29
  end
32
30
 
33
- def internal_exec_query(sql, name = "SQL", binds = [], prepare: false, async: false)
34
- result = nil
31
+ def internal_exec_query(sql, name = "SQL", binds = [], prepare: false, async: false, allow_retry: false)
35
32
  sql = transform_query(sql)
36
33
 
37
34
  check_if_write_query(sql)
@@ -42,20 +39,21 @@ module ActiveRecord
42
39
  sql = sp_executesql_sql(sql, types, params, name)
43
40
  end
44
41
 
45
- log(sql, name, binds, async: async) do
42
+ log(sql, name, binds, async: async) do |notification_payload|
46
43
  with_raw_connection do |conn|
47
- if id_insert_table_name = query_requires_identity_insert?(sql)
48
- with_identity_insert_enabled(id_insert_table_name, conn) do
49
- result = internal_exec_sql_query(sql, conn)
50
- end
51
- else
52
- result = internal_exec_sql_query(sql, conn)
53
- end
44
+ result = if id_insert_table_name = query_requires_identity_insert?(sql)
45
+ with_identity_insert_enabled(id_insert_table_name, conn) do
46
+ internal_exec_sql_query(sql, conn)
47
+ end
48
+ else
49
+ internal_exec_sql_query(sql, conn)
50
+ end
51
+
54
52
  verified!
53
+ notification_payload[:row_count] = result.count
54
+ result
55
55
  end
56
56
  end
57
-
58
- result
59
57
  end
60
58
 
61
59
  def internal_exec_sql_query(sql, conn)
@@ -153,10 +151,10 @@ module ActiveRecord
153
151
 
154
152
  if returning = insert.send(:insert_all).returning
155
153
  returning_sql = if returning.is_a?(String)
156
- returning
157
- else
158
- returning.map { |column| "INSERTED.#{quote_column_name(column)}" }.join(", ")
159
- end
154
+ returning
155
+ else
156
+ returning.map { |column| "INSERTED.#{quote_column_name(column)}" }.join(", ")
157
+ end
160
158
  sql << " OUTPUT #{returning_sql}"
161
159
  end
162
160
 
@@ -174,7 +172,7 @@ module ActiveRecord
174
172
  end.join(", ")
175
173
  sql = "EXEC #{proc_name} #{vars}".strip
176
174
 
177
- log(sql, "Execute Procedure") do
175
+ log(sql, "Execute Procedure") do |notification_payload|
178
176
  with_raw_connection do |conn|
179
177
  result = internal_raw_execute(sql, conn)
180
178
  verified!
@@ -185,10 +183,11 @@ module ActiveRecord
185
183
  yield(r) if block_given?
186
184
  end
187
185
 
188
- result.each.map { |row| row.is_a?(Hash) ? row.with_indifferent_access : row }
186
+ result = result.each.map { |row| row.is_a?(Hash) ? row.with_indifferent_access : row }
187
+ notification_payload[:row_count] = result.count
188
+ result
189
189
  end
190
190
  end
191
-
192
191
  end
193
192
 
194
193
  def with_identity_insert_enabled(table_name, conn)
@@ -329,11 +328,17 @@ module ActiveRecord
329
328
  end
330
329
 
331
330
  def sp_executesql_sql_type(attr)
332
- return "nvarchar(max)".freeze if attr.is_a?(Symbol)
333
- return attr.type.sqlserver_type if attr.type.respond_to?(:sqlserver_type)
331
+ if attr.respond_to?(:type)
332
+ return attr.type.sqlserver_type if attr.type.respond_to?(:sqlserver_type)
334
333
 
335
- case value = attr.value_for_database
336
- when Numeric
334
+ if attr.type.is_a?(ActiveRecord::Encryption::EncryptedAttributeType) && attr.type.instance_variable_get(:@cast_type).respond_to?(:sqlserver_type)
335
+ return attr.type.instance_variable_get(:@cast_type).sqlserver_type
336
+ end
337
+ end
338
+
339
+ value = basic_attribute_type?(attr) ? attr : attr.value_for_database
340
+
341
+ if value.is_a?(Numeric)
337
342
  value > 2_147_483_647 ? "bigint".freeze : "int".freeze
338
343
  else
339
344
  "nvarchar(max)".freeze
@@ -341,17 +346,26 @@ module ActiveRecord
341
346
  end
342
347
 
343
348
  def sp_executesql_sql_param(attr)
344
- return quote(attr) if attr.is_a?(Symbol)
349
+ return quote(attr) if basic_attribute_type?(attr)
345
350
 
346
351
  case value = attr.value_for_database
347
- when Type::Binary::Data,
348
- ActiveRecord::Type::SQLServer::Data
352
+ when Type::Binary::Data, ActiveRecord::Type::SQLServer::Data
349
353
  quote(value)
350
354
  else
351
355
  quote(type_cast(value))
352
356
  end
353
357
  end
354
358
 
359
+ def basic_attribute_type?(type)
360
+ type.is_a?(Symbol) ||
361
+ type.is_a?(String) ||
362
+ type.is_a?(Numeric) ||
363
+ type.is_a?(Time) ||
364
+ type.is_a?(TrueClass) ||
365
+ type.is_a?(FalseClass) ||
366
+ type.is_a?(NilClass)
367
+ end
368
+
355
369
  def sp_executesql_sql(sql, types, params, name)
356
370
  if name == "EXPLAIN"
357
371
  params.each.with_index do |param, index|
@@ -424,7 +438,11 @@ module ActiveRecord
424
438
  qo[:as] = (options[:ar_result] || options[:fetch] == :rows) ? :array : :hash
425
439
  end
426
440
  results = handle.each(query_options)
427
- columns = lowercase_schema_reflection ? handle.fields.map { |c| c.downcase } : handle.fields
441
+
442
+ columns = handle.fields
443
+ # If query returns multiple result sets, only return the columns of the last one.
444
+ columns = columns.last if columns.any? && columns.all? { |e| e.is_a?(Array) }
445
+ columns = columns.map(&:downcase) if lowercase_schema_reflection
428
446
 
429
447
  options[:ar_result] ? ActiveRecord::Result.new(columns, results) : results
430
448
  end