activerecord-sqlserver-adapter 7.1.8 → 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 +11 -5
  4. data/CHANGELOG.md +5 -105
  5. data/Gemfile +4 -4
  6. data/README.md +40 -17
  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 +49 -34
  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 +22 -9
  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 +262 -190
  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 -9
  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 +11 -12
  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: dac0412f21213482d15ff47e53332fe825939a1c4e1d9526884b2a4c91a93d7d
4
- data.tar.gz: c86cf7d138d27def9534f715c421b029370649343985b4e9d5d16e1c9953ae03
3
+ metadata.gz: b6356803690516019929168fed2c356f3250eb5ec8a9894b8117fc35db84b8c1
4
+ data.tar.gz: dbedbedb583e766c526d959459166edd195516700fb6f0b1be2769ea1d947233
5
5
  SHA512:
6
- metadata.gz: b2ef1d7310bea2d0e1bf6feb84a4dd9124898cb80ec83b9f4c30e7f94ce9e4a3220f57285a5f3d71a2dc48706a906edb17a39ad099367b871d52fe5783dc6225
7
- data.tar.gz: f510e15d47aaadd47a5ceeb2b89d0becbc91758ef4b4383caaef940a8ad29a462cd737a0f967186c7cafbc5c57d2277c46b8c0332f32e43c64461957b147cb3e
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,11 +1,17 @@
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:
7
13
  name: Run test suite
8
- runs-on: ubuntu-20.04 # TODO: Change back to 'ubuntu-latest' when https://github.com/microsoft/mssql-docker/issues/899 resolved.
14
+ runs-on: ubuntu-latest
9
15
 
10
16
  env:
11
17
  COMPOSE_FILE: docker-compose.ci.yml
@@ -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,112 +1,12 @@
1
- ## v7.1.8
2
-
3
- #### Fixed
4
-
5
- - [#1232](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1232) Enable identity insert on view's base table
6
-
7
- ## v7.1.7
8
-
9
- #### Fixed
10
-
11
- - [#1210](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1210) Handle blank SQL when parsing table name
12
-
13
- ## v7.1.6
14
-
15
- #### Fixed
16
-
17
- - [#1208](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1208) Exclude "guest" schema in schema dumper
18
-
19
- ## v7.1.5
20
-
21
- #### Added
22
-
23
- - [#1201](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1201) Support non-dbo schemas in schema dumper
24
- - [#1206](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1206) Support table names containing spaces
25
-
26
- ## v7.1.4
27
-
28
- #### Fixed
29
-
30
- - [#1164](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1164) Fix composite primary key with different data type with triggers
31
-
32
- #### Changed
33
-
34
- - [#1199](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1199) Remove ActiveRecord::Relation#calculate patch
35
-
36
- ## v7.1.3
37
-
38
- #### Fixed
39
-
40
- - [#1152](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1152) Fix Composite Key Inserts with Triggers
41
-
42
- ## v7.1.2
43
-
44
- #### Fixed
45
-
46
- - [#1151](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1151) FROM subquery should work if order provided
47
-
48
- ## v7.1.1
49
-
50
- #### Fixed
51
-
52
- - [#1145](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1145) Ensure correct order of COLLATE and NOT NULL in CREATE TABLE statements
53
- - [#1144](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1144) Fix precision handling in time migration
54
- - [#1143](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1143) Fix precision handling for datetimeoffset migration
55
-
56
- ## v7.1.0
57
-
58
- #### Added
59
-
60
- - [#1141](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1141) Added support for check constraints.
61
-
62
- ## v7.1.0.rc2
63
-
64
- #### Added
65
-
66
- - [#1136](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1136) Prevent marking broken connections as verified
67
- - [#1138](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1138) Cache quoted names
68
-
69
- ## v7.1.0.rc1
1
+ ## Unreleased
70
2
 
71
3
  #### Added
72
4
 
73
- * Rails 7.1 Support
74
-
75
- The adapter supports new Rails 7.1 features such as composite primary keys. See the
76
- [Rails 7.1 release notes](https://guides.rubyonrails.org/7_1_release_notes.html) for more information.
5
+ - [#1178](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1178) Support encrypting binary columns
77
6
 
78
7
  #### Changed
79
8
 
80
- * Configure Connection
81
-
82
- If you require additional connection configuration you now need to call `super` within the `configure_connection`
83
- method so that the default configuration is also applied.
84
-
85
- v7.1.x adapter:
86
- ```ruby
87
- module ActiveRecord
88
- module ConnectionAdapters
89
- class SQLServerAdapter < AbstractAdapter
90
- def configure_connection
91
- super
92
- raw_connection_do "SET TEXTSIZE #{64.megabytes}"
93
- end
94
- end
95
- end
96
- end
97
- ```
98
-
99
- v7.0.x adapter:
100
- ```ruby
101
- module ActiveRecord
102
- module ConnectionAdapters
103
- class SQLServerAdapter < AbstractAdapter
104
- def configure_connection
105
- raw_connection_do "SET TEXTSIZE #{64.megabytes}"
106
- end
107
- end
108
- end
109
- end
110
- ```
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
111
11
 
112
- 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,22 +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.
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.
13
16
 
14
- See [Rubygems](https://rubygems.org/gems/activerecord-sqlserver-adapter/versions) for the latest version of the adapter for each Rails release.
15
-
16
- | Adapter Version | Rails Version | Support | Branch |
17
- |-----------------|---------------|---------|--------------------------------------------------------------------------------------------------|
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) |
18
20
  | `7.1.x` | `7.1.x` | Active | [7-1-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/7-1-stable) |
19
- | `7.0.x` | `7.0.x` | Ended | [7-0-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/7-0-stable) |
20
- | `6.1.x` | `6.1.x` | Ended | [6-1-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/6-1-stable) |
21
- | `6.0.x` | `6.0.x` | Ended | [6-0-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/6-0-stable) |
22
- | `5.2.x` | `5.2.x` | Ended | [5-2-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/5-2-stable) |
23
- | `5.1.x` | `5.1.x` | Ended | [5-1-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/5-1-stable) |
24
- | `4.2.x` | `4.2.x` | Ended | [4-2-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/4-2-stable) |
25
- | `4.1.x` | `4.1.x` | Ended | [4-1-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/4-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) |
26
28
 
27
- For older versions, please check their stable branches.
29
+ See [Rubygems](https://rubygems.org/gems/activerecord-sqlserver-adapter/versions) for the latest version of the adapter for each Rails release.
28
30
 
29
31
  #### Native Data Type Support
30
32
 
@@ -169,14 +171,35 @@ ActiveRecord::ConnectionAdapters::SQLServerAdapter.showplan_option = 'SHOWPLAN_X
169
171
 
170
172
  ## New Rails Applications
171
173
 
172
- 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.
176
+
177
+ 1. Create new Rails application, the database defaults to `sqlite`.
173
178
 
179
+ ```bash
180
+ rails new my_app
174
181
  ```
175
- 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'
176
187
  ```
177
188
 
178
- 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.
179
191
 
192
+ Example:
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
+ ```
180
203
 
181
204
  ## Installation
182
205
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 7.1.8
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,23 +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
- # If the table name is a view, we need to get the base table name for enabling identity insert.
49
- id_insert_table_name = view_table_name(id_insert_table_name) if view_exists?(id_insert_table_name)
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
50
51
 
51
- with_identity_insert_enabled(id_insert_table_name, conn) do
52
- result = internal_exec_sql_query(sql, conn)
53
- end
54
- else
55
- result = internal_exec_sql_query(sql, conn)
56
- end
57
52
  verified!
53
+ notification_payload[:row_count] = result.count
54
+ result
58
55
  end
59
56
  end
60
-
61
- result
62
57
  end
63
58
 
64
59
  def internal_exec_sql_query(sql, conn)
@@ -156,10 +151,10 @@ module ActiveRecord
156
151
 
157
152
  if returning = insert.send(:insert_all).returning
158
153
  returning_sql = if returning.is_a?(String)
159
- returning
160
- else
161
- returning.map { |column| "INSERTED.#{quote_column_name(column)}" }.join(", ")
162
- end
154
+ returning
155
+ else
156
+ returning.map { |column| "INSERTED.#{quote_column_name(column)}" }.join(", ")
157
+ end
163
158
  sql << " OUTPUT #{returning_sql}"
164
159
  end
165
160
 
@@ -177,7 +172,7 @@ module ActiveRecord
177
172
  end.join(", ")
178
173
  sql = "EXEC #{proc_name} #{vars}".strip
179
174
 
180
- log(sql, "Execute Procedure") do
175
+ log(sql, "Execute Procedure") do |notification_payload|
181
176
  with_raw_connection do |conn|
182
177
  result = internal_raw_execute(sql, conn)
183
178
  verified!
@@ -188,10 +183,11 @@ module ActiveRecord
188
183
  yield(r) if block_given?
189
184
  end
190
185
 
191
- 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
192
189
  end
193
190
  end
194
-
195
191
  end
196
192
 
197
193
  def with_identity_insert_enabled(table_name, conn)
@@ -332,11 +328,17 @@ module ActiveRecord
332
328
  end
333
329
 
334
330
  def sp_executesql_sql_type(attr)
335
- return "nvarchar(max)".freeze if attr.is_a?(Symbol)
336
- 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)
337
333
 
338
- case value = attr.value_for_database
339
- 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)
340
342
  value > 2_147_483_647 ? "bigint".freeze : "int".freeze
341
343
  else
342
344
  "nvarchar(max)".freeze
@@ -344,17 +346,26 @@ module ActiveRecord
344
346
  end
345
347
 
346
348
  def sp_executesql_sql_param(attr)
347
- return quote(attr) if attr.is_a?(Symbol)
349
+ return quote(attr) if basic_attribute_type?(attr)
348
350
 
349
351
  case value = attr.value_for_database
350
- when Type::Binary::Data,
351
- ActiveRecord::Type::SQLServer::Data
352
+ when Type::Binary::Data, ActiveRecord::Type::SQLServer::Data
352
353
  quote(value)
353
354
  else
354
355
  quote(type_cast(value))
355
356
  end
356
357
  end
357
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
+
358
369
  def sp_executesql_sql(sql, types, params, name)
359
370
  if name == "EXPLAIN"
360
371
  params.each.with_index do |param, index|
@@ -427,7 +438,11 @@ module ActiveRecord
427
438
  qo[:as] = (options[:ar_result] || options[:fetch] == :rows) ? :array : :hash
428
439
  end
429
440
  results = handle.each(query_options)
430
- 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
431
446
 
432
447
  options[:ar_result] ? ActiveRecord::Result.new(columns, results) : results
433
448
  end