activerecord-sqlserver-adapter 7.1.7 → 7.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.devcontainer/Dockerfile +3 -3
  3. data/.github/workflows/ci.yml +4 -4
  4. data/CHANGELOG.md +7 -94
  5. data/Dockerfile.ci +1 -1
  6. data/Gemfile +4 -4
  7. data/README.md +43 -19
  8. data/VERSION +1 -1
  9. data/activerecord-sqlserver-adapter.gemspec +2 -2
  10. data/docker-compose.ci.yml +1 -0
  11. data/lib/active_record/connection_adapters/sqlserver/core_ext/attribute_methods.rb +6 -4
  12. data/lib/active_record/connection_adapters/sqlserver/core_ext/calculations.rb +6 -5
  13. data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +7 -4
  14. data/lib/active_record/connection_adapters/sqlserver/core_ext/finder_methods.rb +6 -4
  15. data/lib/active_record/connection_adapters/sqlserver/core_ext/preloader.rb +14 -12
  16. data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +53 -32
  17. data/lib/active_record/connection_adapters/sqlserver/quoting.rb +44 -46
  18. data/lib/active_record/connection_adapters/sqlserver/savepoints.rb +2 -0
  19. data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +1 -1
  20. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +2 -5
  21. data/lib/active_record/tasks/sqlserver_database_tasks.rb +38 -32
  22. data/lib/arel/visitors/sqlserver.rb +57 -12
  23. data/test/cases/active_schema_test_sqlserver.rb +6 -6
  24. data/test/cases/adapter_test_sqlserver.rb +17 -18
  25. data/test/cases/coerced_tests.rb +279 -167
  26. data/test/cases/disconnected_test_sqlserver.rb +9 -3
  27. data/test/cases/eager_load_too_many_ids_test_sqlserver.rb +1 -1
  28. data/test/cases/enum_test_sqlserver.rb +1 -1
  29. data/test/cases/execute_procedure_test_sqlserver.rb +9 -5
  30. data/test/cases/helper_sqlserver.rb +11 -5
  31. data/test/cases/index_test_sqlserver.rb +8 -6
  32. data/test/cases/json_test_sqlserver.rb +1 -1
  33. data/test/cases/lateral_test_sqlserver.rb +2 -2
  34. data/test/cases/migration_test_sqlserver.rb +1 -1
  35. data/test/cases/optimizer_hints_test_sqlserver.rb +12 -12
  36. data/test/cases/pessimistic_locking_test_sqlserver.rb +8 -7
  37. data/test/cases/primary_keys_test_sqlserver.rb +2 -2
  38. data/test/cases/rake_test_sqlserver.rb +8 -4
  39. data/test/cases/schema_dumper_test_sqlserver.rb +4 -5
  40. data/test/cases/showplan_test_sqlserver.rb +7 -7
  41. data/test/cases/specific_schema_test_sqlserver.rb +17 -13
  42. data/test/cases/view_test_sqlserver.rb +9 -1
  43. data/test/schema/sqlserver_specific_schema.rb +4 -4
  44. data/test/support/connection_reflection.rb +1 -1
  45. data/test/support/core_ext/query_cache.rb +2 -2
  46. data/test/support/query_assertions.rb +49 -0
  47. data/test/support/table_definition_sqlserver.rb +24 -0
  48. data/test/support/test_in_memory_oltp.rb +2 -2
  49. metadata +12 -13
  50. data/lib/active_record/sqlserver_base.rb +0 -13
  51. data/test/cases/scratchpad_test_sqlserver.rb +0 -8
  52. 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: 73bbb76f7c1a620edbaf0aa6e69c5a8fcb9ba2f7c7c14716bb2663f776b8cb0d
4
+ data.tar.gz: a6d9ac56dbcddd486bd0111da5db2e2d0cc6c2bbc3519041a73fffa5cfc3fddb
5
5
  SHA512:
6
- metadata.gz: 6bfc66070966a026f6f1b42bf1c87e48ad9e0d044ce01755eeddbcbc71f2b5cabd8cd395dc9ebfa0aa1e92c5b8f4c524ead92d1abf017b907de774f224c0c02a
7
- data.tar.gz: 9ebcf4c64077e0fdfac80b7f5ca6fc5b6218251f378dd6f61c3fcbfd48e4196a93fc09a5de87048834f1e96f3b839ddd2e0ec61457da081bf3f20fd5d5fed08c
6
+ metadata.gz: 921bd35d9de85b363190dee9b001373fbae60b0c1e99755ff4b172c9f51510d7353b49fb39d636b4acc015755067846bfed6ca4f984eb75d91def007679154da
7
+ data.tar.gz: 384e76d966178e7c8bdc4f84cc03e3739bcfec1291fd42e57d8eb4804b7df37e4311f94ee659efa4d6b76a82ae833f8cd741f66bb667abf7a1e0c2f182107be9
@@ -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
@@ -5,7 +5,7 @@ on: [push, pull_request]
5
5
  jobs:
6
6
  test:
7
7
  name: Run test suite
8
- runs-on: ubuntu-latest
8
+ runs-on: ubuntu-20.04 # TODO: Change back to 'ubuntu-latest' when https://github.com/microsoft/mssql-docker/issues/899 resolved.
9
9
 
10
10
  env:
11
11
  COMPOSE_FILE: docker-compose.ci.yml
@@ -14,9 +14,9 @@ jobs:
14
14
  fail-fast: false
15
15
  matrix:
16
16
  ruby:
17
- - 3.0.6
18
- - 3.1.4
19
- - 3.2.2
17
+ - 3.1.6
18
+ - 3.2.4
19
+ - 3.3.2
20
20
 
21
21
  steps:
22
22
  - name: Checkout code
data/CHANGELOG.md CHANGED
@@ -1,106 +1,19 @@
1
- ## v7.1.7
1
+ ## v7.2.1
2
2
 
3
3
  #### Fixed
4
4
 
5
- - [#1210](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1210) Handle blank SQL when parsing table name
5
+ - [#1231](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1231) Enable identity insert on view's base table
6
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
14
-
15
- #### Added
16
-
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
25
-
26
- #### Changed
27
-
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
7
+ ## v7.2.0
51
8
 
52
9
  #### Added
53
10
 
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.
11
+ - [#1178](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1178) Support encrypting binary columns
71
12
 
72
13
  #### Changed
73
14
 
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
- ```
15
+ - [#1153](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1153) Only support Ruby v3.1+
16
+ - [#1196](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1196) Use default inspect for database adapter
92
17
 
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
- ```
105
18
 
106
- Please check [7-0-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/blob/7-0-stable/CHANGELOG.md) for previous changes.
19
+ Please check [7-1-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/blob/7-1-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 bundle install --jobs `expr $(cat /proc/cpuinfo | grep -c "cpu cores") - 1` --retry 3
12
+ RUN RAILS_BRANCH=7-2-stable bundle install --jobs `expr $(cat /proc/cpuinfo | grep -c "cpu cores") - 1` --retry 3
13
13
 
14
14
  CMD ["sh"]
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` | Ended | [7-0-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/7-0-stable) |
22
+ | `6.1.x` | `6.1.x` | Ended | [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.1
@@ -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
@@ -5,6 +5,7 @@ services:
5
5
  ci:
6
6
  environment:
7
7
  - ACTIVERECORD_UNITTEST_HOST=sqlserver
8
+ - RAILS_BRANCH=7-2-stable
8
9
  build:
9
10
  context: .
10
11
  dockerfile: Dockerfile.ci
@@ -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,24 @@ 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
+ # 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
+
54
55
  verified!
56
+ notification_payload[:row_count] = result.count
57
+ result
55
58
  end
56
59
  end
57
-
58
- result
59
60
  end
60
61
 
61
62
  def internal_exec_sql_query(sql, conn)
@@ -153,10 +154,10 @@ module ActiveRecord
153
154
 
154
155
  if returning = insert.send(:insert_all).returning
155
156
  returning_sql = if returning.is_a?(String)
156
- returning
157
- else
158
- returning.map { |column| "INSERTED.#{quote_column_name(column)}" }.join(", ")
159
- end
157
+ returning
158
+ else
159
+ returning.map { |column| "INSERTED.#{quote_column_name(column)}" }.join(", ")
160
+ end
160
161
  sql << " OUTPUT #{returning_sql}"
161
162
  end
162
163
 
@@ -174,7 +175,7 @@ module ActiveRecord
174
175
  end.join(", ")
175
176
  sql = "EXEC #{proc_name} #{vars}".strip
176
177
 
177
- log(sql, "Execute Procedure") do
178
+ log(sql, "Execute Procedure") do |notification_payload|
178
179
  with_raw_connection do |conn|
179
180
  result = internal_raw_execute(sql, conn)
180
181
  verified!
@@ -185,10 +186,11 @@ module ActiveRecord
185
186
  yield(r) if block_given?
186
187
  end
187
188
 
188
- result.each.map { |row| row.is_a?(Hash) ? row.with_indifferent_access : row }
189
+ result = result.each.map { |row| row.is_a?(Hash) ? row.with_indifferent_access : row }
190
+ notification_payload[:row_count] = result.count
191
+ result
189
192
  end
190
193
  end
191
-
192
194
  end
193
195
 
194
196
  def with_identity_insert_enabled(table_name, conn)
@@ -329,11 +331,17 @@ module ActiveRecord
329
331
  end
330
332
 
331
333
  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)
334
+ if attr.respond_to?(:type)
335
+ return attr.type.sqlserver_type if attr.type.respond_to?(:sqlserver_type)
334
336
 
335
- case value = attr.value_for_database
336
- when Numeric
337
+ if attr.type.is_a?(ActiveRecord::Encryption::EncryptedAttributeType) && attr.type.instance_variable_get(:@cast_type).respond_to?(:sqlserver_type)
338
+ return attr.type.instance_variable_get(:@cast_type).sqlserver_type
339
+ end
340
+ end
341
+
342
+ value = basic_attribute_type?(attr) ? attr : attr.value_for_database
343
+
344
+ if value.is_a?(Numeric)
337
345
  value > 2_147_483_647 ? "bigint".freeze : "int".freeze
338
346
  else
339
347
  "nvarchar(max)".freeze
@@ -341,17 +349,26 @@ module ActiveRecord
341
349
  end
342
350
 
343
351
  def sp_executesql_sql_param(attr)
344
- return quote(attr) if attr.is_a?(Symbol)
352
+ return quote(attr) if basic_attribute_type?(attr)
345
353
 
346
354
  case value = attr.value_for_database
347
- when Type::Binary::Data,
348
- ActiveRecord::Type::SQLServer::Data
355
+ when Type::Binary::Data, ActiveRecord::Type::SQLServer::Data
349
356
  quote(value)
350
357
  else
351
358
  quote(type_cast(value))
352
359
  end
353
360
  end
354
361
 
362
+ def basic_attribute_type?(type)
363
+ type.is_a?(Symbol) ||
364
+ type.is_a?(String) ||
365
+ type.is_a?(Numeric) ||
366
+ type.is_a?(Time) ||
367
+ type.is_a?(TrueClass) ||
368
+ type.is_a?(FalseClass) ||
369
+ type.is_a?(NilClass)
370
+ end
371
+
355
372
  def sp_executesql_sql(sql, types, params, name)
356
373
  if name == "EXPLAIN"
357
374
  params.each.with_index do |param, index|
@@ -424,7 +441,11 @@ module ActiveRecord
424
441
  qo[:as] = (options[:ar_result] || options[:fetch] == :rows) ? :array : :hash
425
442
  end
426
443
  results = handle.each(query_options)
427
- columns = lowercase_schema_reflection ? handle.fields.map { |c| c.downcase } : handle.fields
444
+
445
+ columns = handle.fields
446
+ # If query returns multiple result sets, only return the columns of the last one.
447
+ columns = columns.last if columns.any? && columns.all? { |e| e.is_a?(Array) }
448
+ columns = columns.map(&:downcase) if lowercase_schema_reflection
428
449
 
429
450
  options[:ar_result] ? ActiveRecord::Result.new(columns, results) : results
430
451
  end