activerecord-sqlserver-adapter 7.1.7 → 7.2.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/.devcontainer/Dockerfile +3 -3
- data/.github/workflows/ci.yml +10 -4
- data/CHANGELOG.md +5 -99
- data/Gemfile +4 -4
- data/README.md +43 -19
- data/VERSION +1 -1
- data/activerecord-sqlserver-adapter.gemspec +2 -2
- data/lib/active_record/connection_adapters/sqlserver/core_ext/attribute_methods.rb +6 -4
- data/lib/active_record/connection_adapters/sqlserver/core_ext/calculations.rb +6 -5
- data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +7 -4
- data/lib/active_record/connection_adapters/sqlserver/core_ext/finder_methods.rb +6 -4
- data/lib/active_record/connection_adapters/sqlserver/core_ext/preloader.rb +14 -12
- data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +50 -32
- data/lib/active_record/connection_adapters/sqlserver/quoting.rb +44 -46
- data/lib/active_record/connection_adapters/sqlserver/savepoints.rb +2 -0
- data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +1 -1
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +2 -5
- data/lib/active_record/tasks/sqlserver_database_tasks.rb +38 -32
- data/lib/arel/visitors/sqlserver.rb +57 -12
- data/test/cases/active_schema_test_sqlserver.rb +6 -6
- data/test/cases/adapter_test_sqlserver.rb +17 -18
- data/test/cases/coerced_tests.rb +279 -167
- data/test/cases/disconnected_test_sqlserver.rb +9 -3
- data/test/cases/eager_load_too_many_ids_test_sqlserver.rb +1 -1
- data/test/cases/enum_test_sqlserver.rb +1 -1
- data/test/cases/execute_procedure_test_sqlserver.rb +9 -5
- data/test/cases/helper_sqlserver.rb +11 -5
- data/test/cases/index_test_sqlserver.rb +8 -6
- data/test/cases/json_test_sqlserver.rb +1 -1
- data/test/cases/lateral_test_sqlserver.rb +2 -2
- data/test/cases/migration_test_sqlserver.rb +1 -1
- data/test/cases/optimizer_hints_test_sqlserver.rb +12 -12
- data/test/cases/pessimistic_locking_test_sqlserver.rb +8 -7
- data/test/cases/primary_keys_test_sqlserver.rb +2 -2
- data/test/cases/rake_test_sqlserver.rb +8 -4
- data/test/cases/schema_dumper_test_sqlserver.rb +4 -5
- data/test/cases/showplan_test_sqlserver.rb +7 -7
- data/test/cases/specific_schema_test_sqlserver.rb +17 -13
- data/test/cases/view_test_sqlserver.rb +1 -1
- data/test/schema/sqlserver_specific_schema.rb +4 -4
- data/test/support/connection_reflection.rb +1 -1
- data/test/support/core_ext/query_cache.rb +2 -2
- data/test/support/query_assertions.rb +49 -0
- data/test/support/table_definition_sqlserver.rb +24 -0
- data/test/support/test_in_memory_oltp.rb +2 -2
- metadata +12 -13
- data/lib/active_record/sqlserver_base.rb +0 -13
- data/test/cases/scratchpad_test_sqlserver.rb +0 -8
- data/test/support/sql_counter_sqlserver.rb +0 -14
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: b6356803690516019929168fed2c356f3250eb5ec8a9894b8117fc35db84b8c1
         | 
| 4 | 
            +
              data.tar.gz: dbedbedb583e766c526d959459166edd195516700fb6f0b1be2769ea1d947233
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 5079fd8e88a8e67b91f11de2f9ec158d686afe121461f2b2050ebdd1072f1ac0fc86356dd81da507e99b72b8f9266aa5a59031d886dcb8d119715cab4cbef1c8
         | 
| 7 | 
            +
              data.tar.gz: d1a8f37563ba09c443242e83f75098b2cc74bd269c9b11b9c6834a5e2fa23c7791f93083c7884ec1d22acdeca3bdf75f752153bde565fa0d92c3988a6653565c
         | 
    
        data/.devcontainer/Dockerfile
    CHANGED
    
    | @@ -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. | 
| 10 | 
            -
                && tar -xzf freetds-1. | 
| 11 | 
            -
                && cd freetds-1. | 
| 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
         | 
    
        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 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. | 
| 18 | 
            -
                      - 3. | 
| 19 | 
            -
                      - 3. | 
| 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 | 
            -
            ##  | 
| 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 | 
            -
            - [# | 
| 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 | 
            -
            - [# | 
| 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- | 
| 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", " | 
| 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" | 
| 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[" | 
| 20 | 
            -
              gem "rails", github: "rails/rails", branch:  | 
| 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 | 
             
            * [](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/actions/workflows/ci.yml) - CI
         | 
| 4 | 
            -
            * [](https://ci.appveyor.com/project/rails-sqlserver/activerecord-sqlserver-adapter/branch/master) - Appveyor
         | 
| 5 4 | 
             
            * [](https://rubygems.org/gems/activerecord-sqlserver-adapter) - Gem Version
         | 
| 6 5 | 
             
            * [](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 | 
| 13 | 
            -
             | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 18 | 
            -
            |  | 
| 19 | 
            -
             | 
| 20 | 
            -
            | ` | 
| 21 | 
            -
            | ` | 
| 22 | 
            -
            | ` | 
| 23 | 
            -
            | ` | 
| 24 | 
            -
            | ` | 
| 25 | 
            -
             | 
| 26 | 
            -
             | 
| 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  | 
| 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 | 
            -
             | 
| 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 | 
            -
             | 
| 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.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 = ">=  | 
| 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. | 
| 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 | 
            -
                         | 
| 13 | 
            +
                        self.class.with_connection do |connection|
         | 
| 14 | 
            +
                          return super(attribute_names) unless connection.sqlserver?
         | 
| 14 15 |  | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 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 | 
            -
                         | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 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 | 
            -
                         | 
| 12 | 
            +
                        with_connection do |connection|
         | 
| 13 | 
            +
                          return super(queries, options) unless connection.sqlserver?
         | 
| 13 14 |  | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 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 | 
            -
                         | 
| 15 | 
            -
                           | 
| 16 | 
            -
             | 
| 17 | 
            -
                           | 
| 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 | 
            -
                         | 
| 11 | 
            +
                        scope.with_connection do |connection|
         | 
| 12 | 
            +
                          return super unless connection.sqlserver?
         | 
| 12 13 |  | 
| 13 | 
            -
             | 
| 14 | 
            +
                          return [] if keys.empty?
         | 
| 14 15 |  | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 16 | 
            +
                          if association_key_name.is_a?(Array)
         | 
| 17 | 
            +
                            query_constraints = Hash.new { |hsh, key| hsh[key] = Set.new }
         | 
| 17 18 |  | 
| 18 | 
            -
             | 
| 19 | 
            -
             | 
| 20 | 
            -
             | 
| 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 | 
            -
             | 
| 25 | 
            -
             | 
| 26 | 
            -
             | 
| 27 | 
            -
             | 
| 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 | 
            -
                       | 
| 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 | 
            -
             | 
| 49 | 
            -
             | 
| 50 | 
            -
             | 
| 51 | 
            -
             | 
| 52 | 
            -
             | 
| 53 | 
            -
             | 
| 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 | 
            -
             | 
| 157 | 
            -
             | 
| 158 | 
            -
             | 
| 159 | 
            -
             | 
| 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 | 
            -
                       | 
| 333 | 
            -
             | 
| 331 | 
            +
                      if attr.respond_to?(:type)
         | 
| 332 | 
            +
                        return attr.type.sqlserver_type if attr.type.respond_to?(:sqlserver_type)
         | 
| 334 333 |  | 
| 335 | 
            -
             | 
| 336 | 
            -
             | 
| 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  | 
| 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 | 
            -
             | 
| 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
         |