activerecord-sqlserver-adapter 7.0.5.1 → 7.1.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +3 -3
  3. data/.gitignore +3 -1
  4. data/CHANGELOG.md +38 -83
  5. data/Gemfile +3 -0
  6. data/README.md +16 -11
  7. data/RUNNING_UNIT_TESTS.md +24 -10
  8. data/Rakefile +2 -6
  9. data/VERSION +1 -1
  10. data/activerecord-sqlserver-adapter.gemspec +1 -1
  11. data/lib/active_record/connection_adapters/sqlserver/core_ext/abstract_adapter.rb +20 -0
  12. data/lib/active_record/connection_adapters/sqlserver/core_ext/calculations.rb +29 -6
  13. data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +4 -4
  14. data/lib/active_record/connection_adapters/sqlserver/core_ext/finder_methods.rb +10 -2
  15. data/lib/active_record/connection_adapters/sqlserver/core_ext/preloader.rb +15 -3
  16. data/lib/active_record/connection_adapters/sqlserver/database_limits.rb +0 -31
  17. data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +86 -133
  18. data/lib/active_record/connection_adapters/sqlserver/database_tasks.rb +5 -5
  19. data/lib/active_record/connection_adapters/sqlserver/quoting.rb +3 -2
  20. data/lib/active_record/connection_adapters/sqlserver/savepoints.rb +24 -0
  21. data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +68 -29
  22. data/lib/active_record/connection_adapters/sqlserver/showplan.rb +3 -3
  23. data/lib/active_record/connection_adapters/sqlserver/table_definition.rb +6 -0
  24. data/lib/active_record/connection_adapters/sqlserver/transaction.rb +4 -6
  25. data/lib/active_record/connection_adapters/sqlserver/type/data.rb +10 -0
  26. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +81 -114
  27. data/lib/active_record/connection_adapters/sqlserver_column.rb +1 -0
  28. data/lib/active_record/sqlserver_base.rb +1 -10
  29. data/lib/active_record/tasks/sqlserver_database_tasks.rb +5 -2
  30. data/lib/arel/visitors/sqlserver.rb +0 -33
  31. data/test/cases/adapter_test_sqlserver.rb +8 -7
  32. data/test/cases/coerced_tests.rb +526 -235
  33. data/test/cases/column_test_sqlserver.rb +6 -6
  34. data/test/cases/connection_test_sqlserver.rb +3 -6
  35. data/test/cases/disconnected_test_sqlserver.rb +5 -8
  36. data/test/cases/execute_procedure_test_sqlserver.rb +1 -1
  37. data/test/cases/rake_test_sqlserver.rb +1 -1
  38. data/test/cases/schema_dumper_test_sqlserver.rb +2 -2
  39. data/test/cases/transaction_test_sqlserver.rb +13 -8
  40. data/test/config.yml +1 -2
  41. data/test/support/connection_reflection.rb +2 -8
  42. data/test/support/core_ext/query_cache.rb +7 -1
  43. data/test/support/marshal_compatibility_fixtures/SQLServer/rails_6_1_topic_associations.dump +0 -0
  44. data/test/support/marshal_compatibility_fixtures/SQLServer/rails_7_1_topic.dump +0 -0
  45. data/test/support/marshal_compatibility_fixtures/SQLServer/rails_7_1_topic_associations.dump +0 -0
  46. data/test/support/sql_counter_sqlserver.rb +0 -15
  47. metadata +14 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 02401b4f2142fc0cdebfd2308b94647ab6dc927c77542d4125dae6b6184e7e1c
4
- data.tar.gz: c4d0d77af6f8344846387c14b1b84977b5af321bc7b2e9cf208bdab59179363d
3
+ metadata.gz: 42ca12c2b62c162e798e40d6ca3ec7861e736835d8d91f132eef16240dcfeb02
4
+ data.tar.gz: ddf249b287e32a11a03ea4b2a9bfe85dbbded619d83165559f108892d90da658
5
5
  SHA512:
6
- metadata.gz: e37d3daf2d7a509ef38eb45218fc3db5d4c60938ac2b8687a7f53a5e516df6fa3fa29dea71914d469336ebb8a7020921f5b479917afe78654d05048b51dd3911
7
- data.tar.gz: 91a4c0bb6729b16736885cc7b2a89e7a80abbb11580bc02b31bb83dc4c3e2b72eb2e10815ae85af7e5a28f9990a8e7bea102345d146fa8323593605a32ec2bda
6
+ metadata.gz: dde118ab5b86cd3b154739ce66933e8d4f3380503e6626796941c93cd08775571ad1f6b1630d7a5882b8dc97e0cd5475a7043fd8ac792af723e7c85720ff2271
7
+ data.tar.gz: 80efec8b5e389f05c57a1a2bab01cae17addbda59ec772a602f9aa1e4212508301a954b32d795d0ec6898c161226d36664a169f834c3f34e3ce1fd1c34a56d0e
@@ -14,9 +14,9 @@ jobs:
14
14
  fail-fast: false
15
15
  matrix:
16
16
  ruby:
17
- - 2.7.7
18
- - 3.1.3
19
- - 3.2.1
17
+ - 3.0.6
18
+ - 3.1.4
19
+ - 3.2.2
20
20
 
21
21
  steps:
22
22
  - name: Checkout code
data/.gitignore CHANGED
@@ -1,5 +1,5 @@
1
1
  nbproject/
2
- debug.log
2
+ debug.log*
3
3
  .DS_Store
4
4
  pkg/
5
5
  doc/
@@ -16,3 +16,5 @@ coverage/*
16
16
  .flooignore
17
17
  .floo
18
18
  .byebug_history
19
+ tmp/*
20
+ test/storage/test.sqlite3*
data/CHANGELOG.md CHANGED
@@ -1,89 +1,44 @@
1
- ## v7.0.5.1
1
+ ## v7.1.0.rc1
2
2
 
3
- #### Fixed
4
-
5
- - [#1133](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1133) Fix matching view's real column name
6
-
7
- ## v7.0.5.0
8
-
9
- #### Fixed
10
-
11
- - [#1113](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1113) Fix issue with default view value not being found because of case sensitivity
12
- - [#1126](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1113) Fix view issue with default column value not found
13
-
14
- ## v7.0.4.0
15
-
16
- #### Changed
17
-
18
- - [#1073](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1073) Improve performance of view default function lookup
19
-
20
- #### Fixed
21
-
22
- - [#1088](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1088) Fix creation of stored procedures that contain insert statements
23
- - [#1089](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1089) When changing columns set date-time columns to datetime(6) by default
24
-
25
- ## v7.0.3.0
26
-
27
- #### Fixed
28
-
29
- - [#1052](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1052) Ignore casing of VALUES clause when inserting records using SQL
30
- - [#1053](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1053) Fix insertion of records to non-default schema table using raw SQL
31
- - [#1059](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1059) Fix enums defined on string columns
32
-
33
- #### Changed
34
-
35
- - [#1057](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1057) Set precision 6 by default for timestamps.
36
-
37
- ## v7.0.2.0
38
-
39
- [Full changelog](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/compare/v7.0.1.0...v7.0.2.0)
40
-
41
- #### Fixed
42
-
43
- - [#1049](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1049) Fix for inserting records into non-dbo schema table.
44
-
45
- ## v7.0.1.0
46
-
47
- [Full changelog](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/compare/v7.0.0.0...v7.0.1.0)
48
-
49
- #### Fixed
50
-
51
- - [#1029](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1029) Handle views defined in other databases.
52
- - [#1033](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1033) Support proc default values in ruby 3.2.
53
- - [#1020](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1020) Support using adapter as a stand-alone gem.
54
- - [#1039](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1039) Fix hook method that allows custom connection configuration.
55
-
56
- #### Changed
57
-
58
- - [#1021](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1021) Freeze the SQL sent to instrumentation.
59
-
60
- ## v7.0.0.0
61
-
62
- [Full changelog](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/compare/v7.0.0.0.rc1...v7.0.0.0)
63
-
64
- #### Fixed
65
-
66
- - [#1002](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1002) Fix support for index types
67
-
68
- #### Changed
69
-
70
- - [#1004](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1004) Dump the precision for datetime columns following the new defaults.
3
+ #### Added
71
4
 
72
- ## v7.0.0.0.rc1
5
+ * Rails 7.1 Support
73
6
 
74
- [Full changelog](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/compare/6-1-stable...v7.0.0.0.rc1)
7
+ The adapter supports new Rails 7.1 features such as composite primary keys. See the
8
+ [Rails 7.1 release notes](https://guides.rubyonrails.org/7_1_release_notes.html) for more information.
75
9
 
76
10
  #### Changed
77
11
 
78
- - [#968](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/968) Define adapter type maps statically
79
- - [#983](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/983) Optimize remove_columns to use a single SQL statement
80
- - [#984](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/984) Better handle SQL queries with invalid encoding
81
- - [#988](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/988) Raise `ActiveRecord::StatementInvalid` when `columns` is called with a non-existing table (***breaking change***)
82
-
83
- #### Added
84
-
85
- - [#972](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/972) Support `ActiveRecord::QueryLogs`
86
- - [#981](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/981) Support `find_by` an encrypted attribute
87
- - [#985](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/985) Support string returning clause for `ActiveRecord#insert_all`
88
-
89
- Please check [6-1-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/blob/6-1-stable/CHANGELOG.md) for previous changes.
12
+ * Configure Connection
13
+
14
+ If you require additional connection configuration you now need to call `super` within the `configure_connection`
15
+ method so that the default configuration is also applied.
16
+
17
+ v7.1.x adapter:
18
+ ```ruby
19
+ module ActiveRecord
20
+ module ConnectionAdapters
21
+ class SQLServerAdapter < AbstractAdapter
22
+ def configure_connection
23
+ super
24
+ raw_connection_do "SET TEXTSIZE #{64.megabytes}"
25
+ end
26
+ end
27
+ end
28
+ end
29
+ ```
30
+
31
+ v7.0.x adapter:
32
+ ```ruby
33
+ module ActiveRecord
34
+ module ConnectionAdapters
35
+ class SQLServerAdapter < AbstractAdapter
36
+ def configure_connection
37
+ raw_connection_do "SET TEXTSIZE #{64.megabytes}"
38
+ end
39
+ end
40
+ end
41
+ end
42
+ ```
43
+
44
+ Please check [7-0-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/blob/7-0-stable/CHANGELOG.md) for previous changes.
data/Gemfile CHANGED
@@ -12,9 +12,12 @@ gem "sqlite3", "~> 1.4"
12
12
  gem "tzinfo-data", platforms: [:mingw, :mswin, :x64_mingw, :jruby]
13
13
  gem "benchmark-ips"
14
14
  gem "minitest", ">= 5.15.0", "< 5.16"
15
+ gem "msgpack", ">= 1.7.0"
15
16
 
16
17
  if ENV["RAILS_SOURCE"]
17
18
  gemspec path: ENV["RAILS_SOURCE"]
19
+ elsif ENV["RAILS_MAIN"]
20
+ gem "rails", github: "rails/rails", branch: 'main'
18
21
  else
19
22
  # Need to get rails source because the gem doesn't include tests
20
23
  version = ENV["RAILS_VERSION"] || begin
data/README.md CHANGED
@@ -11,15 +11,16 @@ The SQL Server adapter for ActiveRecord using SQL Server 2012 or higher.
11
11
 
12
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
13
 
14
- | Adapter Version | Rails Version | Support |
15
- |-----------------| ------------- | ------------------------------------------------------------------------------------------- |
16
- | `7.0.5.1` | `7.0.x` | [active](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/main) |
17
- | `6.1.2.1` | `6.1.x` | [active](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/6-1-stable) |
18
- | `6.0.3` | `6.0.x` | [active](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/6-0-stable) |
19
- | `5.2.1` | `5.2.x` | [ended](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/5-2-stable) |
20
- | `5.1.6` | `5.1.x` | [ended](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/5-1-stable) |
21
- | `4.2.18` | `4.2.x` | [ended](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/4-2-stable) |
22
- | `4.1.8` | `4.1.x` | [ended](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/4-1-stable) |
14
+ | Adapter Version | Rails Version | Support | Branch |
15
+ |-----------------|---------------|----------------|-------------------------------------------------------------------------------------------------|
16
+ | `7.1.0.rc1` | `7.1.x` | In development | [main](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/main) |
17
+ | `7.0.5.1` | `7.0.x` | Active | [7-0-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/7-0-stable) |
18
+ | `6.1.3.0` | `6.1.x` | Active | [6-1-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/6-1-stable) |
19
+ | `6.0.3` | `6.0.x` | Ended | [6-0-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/6-0-stable) |
20
+ | `5.2.1` | `5.2.x` | Ended | [5-2-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/5-2-stable) |
21
+ | `5.1.6` | `5.1.x` | Ended | [5-1-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/5-1-stable) |
22
+ | `4.2.18` | `4.2.x` | Ended | [4-2-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/4-2-stable) |
23
+ | `4.1.8` | `4.1.x` | Ended | [4-1-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/4-1-stable) |
23
24
 
24
25
  For older versions, please check their stable branches.
25
26
 
@@ -89,13 +90,16 @@ end
89
90
 
90
91
  #### Configure Connection
91
92
 
92
- We currently conform to an unpublished and non-standard AbstractAdapter interface to configure connections made to the database. To do so, just implement the `configure_connection` method in an initializer like so. In this case below we are setting the `TEXTSIZE` to 64 megabytes.
93
+ The adapter conforms to the AbstractAdapter interface to configure connections. If you require additional connection
94
+ configuration then implement the `configure_connection` method in an initializer like so. In the following
95
+ example we are setting the `TEXTSIZE` to 64 megabytes.
93
96
 
94
97
  ```ruby
95
98
  module ActiveRecord
96
99
  module ConnectionAdapters
97
100
  class SQLServerAdapter < AbstractAdapter
98
101
  def configure_connection
102
+ super
99
103
  raw_connection_do "SET TEXTSIZE #{64.megabytes}"
100
104
  end
101
105
  end
@@ -170,7 +174,8 @@ To then connect the application to your SQL Server instance edit the `config/dat
170
174
 
171
175
  ## Installation
172
176
 
173
- The adapter has no strict gem dependencies outside of `ActiveRecord`. You will have to pick a connection mode, the default is dblib which uses the `TinyTDS` gem. Just bundle the gem and the adapter will use it.
177
+ The adapter has no strict gem dependencies outside of `ActiveRecord` and
178
+ [TinyTDS](https://github.com/rails-sqlserver/tiny_tds).
174
179
 
175
180
  ```ruby
176
181
  gem 'activerecord-sqlserver-adapter'
@@ -13,12 +13,12 @@ Default testing uses DBLIB with TinyTDS.
13
13
 
14
14
  * Setup two databases in SQL Server, [activerecord_unittest] and [activerecord_unittest2]
15
15
  * Create a [rails] user with an empty password and give it a [db_owner] role to both DBs. Some tests require a server role of [sysadmin] too. More details below with DDL SQL examples.
16
- * $ bundle install
17
- * $ bundle exec rake test ACTIVERECORD_UNITTEST_HOST='my.db.net'
16
+ * `bundle install`
17
+ * `bundle exec rake test ACTIVERECORD_UNITTEST_HOST='my.db.net'`
18
18
 
19
19
  Focusing tests. Use the `ONLY_` env vars to run either ours or the ActiveRecord cases. Use the `TEST_FILES` env variants to focus on specific test(s), use commas for multiple cases. Note, you have to use different env vars to focus only on ours or a core ActiveRecord case. There may be failures when focusing on an ActiveRecord case since our coereced test files is not loaded in this scenerio.
20
20
 
21
- ```
21
+ ```console
22
22
  $ bundle exec rake test ONLY_SQLSERVER=1
23
23
  $ bundle exec rake test ONLY_ACTIVERECORD=1
24
24
 
@@ -49,13 +49,13 @@ GO
49
49
 
50
50
  The tests of this adapter depend on the existence of the Rails which are automatically cloned for you with bundler. However you can clone Rails from git://github.com/rails/rails.git and set the `RAILS_SOURCE` environment variable so bundler will use another local path instead.
51
51
 
52
- ```
52
+ ```console
53
53
  $ git clone git://github.com/rails-sqlserver/activerecord-sqlserver-adapter.git
54
54
  ```
55
55
 
56
56
  Suggest just letting bundler do all the work and assuming there is a git tag for the Rails version, you can set `RAILS_VERSION` before bundling.
57
57
 
58
- ```
58
+ ```console
59
59
  $ export RAILS_VERSION='4.2.0'
60
60
  $ bundle install
61
61
  ```
@@ -65,20 +65,20 @@ $ bundle install
65
65
 
66
66
  Please consult the `test/config.yml` file which is used to parse the configuration options for the DB connections when running tests. This file has overrides for any connection mode that you can set using simple environment variables. Assuming you are using FreeTDS 0.91 and above
67
67
 
68
- ```
68
+ ```console
69
69
  $ export ACTIVERECORD_UNITTEST_HOST='my.db.net' # Defaults to localhost
70
70
  $ export ACTIVERECORD_UNITTEST_PORT='1533' # Defaults to 1433
71
71
  ```
72
72
 
73
73
  If you have FreeTDS installed and/or want to use a named dataserver in your freetds.conf file
74
74
 
75
- ```
75
+ ```console
76
76
  $ export ACTIVERECORD_UNITTEST_DATASERVER='mydbname'
77
77
  ```
78
78
 
79
79
  These can be passed down to rake too.
80
80
 
81
- ```
81
+ ```console
82
82
  $ bundle exec rake test ACTIVERECORD_UNITTEST_HOST='my.db.net'
83
83
  ```
84
84
 
@@ -87,16 +87,30 @@ $ bundle exec rake test ACTIVERECORD_UNITTEST_HOST='my.db.net'
87
87
 
88
88
  Now with that out of the way you can run "bundle install" to hook everything up. Our tests use bundler to setup the load paths correctly. The default mode is DBLIB using TinyTDS. It is important to use bundle exec so we can wire up the ActiveRecord test libs correctly.
89
89
 
90
- ```
90
+ ```console
91
91
  $ bundle exec rake test
92
92
  ```
93
93
 
94
94
 
95
95
  ## Testing Options
96
96
 
97
-
98
97
  By default, Bundler will download the Rails git repo and use the git tag that matches the dependency version in our gemspec. If you want to test another version of Rails, you can either temporarily change the :tag for Rails in the Gemfile. Likewise, you can clone the Rails repo your self to another directory and use the `RAILS_SOURCE` environment variable.
99
98
 
99
+ ```console
100
+ $ RAILS_SOURCE='/vagrant/rails' bundle exec rake test
101
+ ```
102
+
103
+ If you want to use a specific seed for the tests use the `TESTOPTS` env variable like:
104
+
105
+ ```console
106
+ $ bundle exec rake test TESTOPTS="--seed=45250"
107
+ ```
108
+
109
+ And to make the tests fail-fast use:
110
+
111
+ ```console
112
+ $ bundle exec rake test TESTOPTS="-f"
113
+ ```
100
114
 
101
115
  ## Troubleshooting
102
116
 
data/Rakefile CHANGED
@@ -9,6 +9,8 @@ task test: ["test:dblib"]
9
9
  task default: [:test]
10
10
 
11
11
  namespace :test do
12
+ ENV["ARCONN"] = "sqlserver"
13
+
12
14
  %w(dblib).each do |mode|
13
15
  Rake::TestTask.new(mode) do |t|
14
16
  t.libs = ARTest::SQLServer.test_load_paths
@@ -17,14 +19,8 @@ namespace :test do
17
19
  t.verbose = false
18
20
  end
19
21
  end
20
-
21
- task "dblib:env" do
22
- ENV["ARCONN"] = "dblib"
23
- end
24
22
  end
25
23
 
26
- task "test:dblib" => "test:dblib:env"
27
-
28
24
  namespace :profile do
29
25
  ["dblib"].each do |mode|
30
26
  namespace mode.to_sym do
data/VERSION CHANGED
@@ -1 +1 @@
1
- 7.0.5.1
1
+ 7.1.0.rc1
@@ -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.0.0"
30
+ spec.add_dependency "activerecord", "~> 7.1.1"
31
31
  spec.add_dependency "tiny_tds"
32
32
  end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module ConnectionAdapters
5
+ module SQLServer
6
+ module CoreExt
7
+ module AbstractAdapter
8
+ def sqlserver?
9
+ false
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+
17
+ ActiveSupport.on_load(:active_record) do
18
+ mod = ActiveRecord::ConnectionAdapters::SQLServer::CoreExt::AbstractAdapter
19
+ ActiveRecord::ConnectionAdapters::AbstractAdapter.prepend(mod)
20
+ end
@@ -8,18 +8,43 @@ module ActiveRecord
8
8
  module SQLServer
9
9
  module CoreExt
10
10
  module Calculations
11
- # Same as original except we don't perform PostgreSQL hack that removes ordering.
12
11
  def calculate(operation, column_name)
13
- return super unless klass.connection.adapter_name == "SQLServer"
12
+ if klass.connection.sqlserver?
13
+ _calculate(operation, column_name)
14
+ else
15
+ super
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ # Same as original `calculate` method except we don't perform PostgreSQL hack that removes ordering.
22
+ def _calculate(operation, column_name)
23
+ operation = operation.to_s.downcase
24
+
25
+ if @none
26
+ case operation
27
+ when "count", "sum"
28
+ result = group_values.any? ? Hash.new : 0
29
+ return @async ? Promise::Complete.new(result) : result
30
+ when "average", "minimum", "maximum"
31
+ result = group_values.any? ? Hash.new : nil
32
+ return @async ? Promise::Complete.new(result) : result
33
+ end
34
+ end
14
35
 
15
36
  if has_include?(column_name)
16
37
  relation = apply_join_dependency
17
38
 
18
- if operation.to_s.downcase == "count"
39
+ if operation == "count"
19
40
  unless distinct_value || distinct_select?(column_name || select_for_count)
20
41
  relation.distinct!
21
- relation.select_values = [klass.primary_key || table[Arel.star]]
42
+ relation.select_values = [ klass.primary_key || table[Arel.star] ]
22
43
  end
44
+ # PostgreSQL: ORDER BY expressions must appear in SELECT list when using DISTINCT
45
+ # Start of monkey-patch
46
+ # relation.order_values = [] if group_values.empty?
47
+ # End of monkey-patch
23
48
  end
24
49
 
25
50
  relation.calculate(operation, column_name)
@@ -28,8 +53,6 @@ module ActiveRecord
28
53
  end
29
54
  end
30
55
 
31
- private
32
-
33
56
  def build_count_subquery(relation, column_name, distinct)
34
57
  return super unless klass.connection.adapter_name == "SQLServer"
35
58
 
@@ -8,20 +8,20 @@ module ActiveRecord
8
8
  SQLSERVER_STATEMENT_PREFIX = "EXEC sp_executesql "
9
9
  SQLSERVER_STATEMENT_REGEXP = /N'(.+)', N'(.+)', (.+)/
10
10
 
11
- def exec_explain(queries)
11
+ def exec_explain(queries, options = [])
12
12
  return super unless connection.adapter_name == "SQLServer"
13
13
 
14
14
  unprepared_queries = queries.map do |(sql, binds)|
15
15
  [unprepare_sqlserver_statement(sql, binds), binds]
16
16
  end
17
- super(unprepared_queries)
17
+ super(unprepared_queries, options)
18
18
  end
19
19
 
20
20
  private
21
21
 
22
- # This is somewhat hacky, but it should reliably reformat our prepared sql statment
22
+ # This is somewhat hacky, but it should reliably reformat our prepared sql statement
23
23
  # which uses sp_executesql to just the first argument, then unquote it. Likewise our
24
- # `sp_executesql` method should substitude the @n args with the quoted values.
24
+ # `sp_executesql` method should substitute the @n args with the quoted values.
25
25
  def unprepare_sqlserver_statement(sql, binds)
26
26
  return sql unless sql.start_with?(SQLSERVER_STATEMENT_PREFIX)
27
27
 
@@ -10,18 +10,26 @@ module ActiveRecord
10
10
  module FinderMethods
11
11
  private
12
12
 
13
- # Same as original except we order by values in distinct select if present.
14
13
  def construct_relation_for_exists(conditions)
15
- return super unless klass.connection.adapter_name == "SQLServer"
14
+ if klass.connection.sqlserver?
15
+ _construct_relation_for_exists(conditions)
16
+ else
17
+ super
18
+ end
19
+ end
16
20
 
21
+ # Same as original except we order by values in distinct select if present.
22
+ def _construct_relation_for_exists(conditions)
17
23
  conditions = sanitize_forbidden_attributes(conditions)
18
24
 
19
25
  if distinct_value && offset_value
26
+ # Start of monkey-patch
20
27
  if select_values.present?
21
28
  relation = order(*select_values).limit!(1)
22
29
  else
23
30
  relation = except(:order).limit!(1)
24
31
  end
32
+ # End of monkey-patch
25
33
  else
26
34
  relation = except(:select, :distinct, :order)._select!(::ActiveRecord::FinderMethods::ONE_AS_ONE).limit!(1)
27
35
  end
@@ -8,10 +8,22 @@ 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.adapter_name == "SQLServer"
11
+ return super unless scope.connection.sqlserver?
12
12
 
13
- keys.each_slice(in_clause_length).flat_map do |slice|
14
- scope.where(association_key_name => slice).load(&block).records
13
+ if association_key_name.is_a?(Array)
14
+ query_constraints = Hash.new { |hsh, key| hsh[key] = Set.new }
15
+
16
+ keys.each_with_object(query_constraints) do |values_set, constraints|
17
+ association_key_name.zip(values_set).each do |key_name, value|
18
+ constraints[key_name] << value
19
+ end
20
+ end
21
+
22
+ scope.where(query_constraints).load(&block)
23
+ else
24
+ keys.each_slice(in_clause_length).flat_map do |slice|
25
+ scope.where(association_key_name => slice).load(&block).records
26
+ end
15
27
  end
16
28
  end
17
29
 
@@ -8,45 +8,14 @@ module ActiveRecord
8
8
  128
9
9
  end
10
10
 
11
- def column_name_length
12
- 128
13
- end
14
- deprecate :column_name_length
15
-
16
11
  def table_name_length
17
12
  128
18
13
  end
19
- deprecate :table_name_length
20
14
 
21
15
  def index_name_length
22
16
  128
23
17
  end
24
18
 
25
- def columns_per_table
26
- 1024
27
- end
28
- deprecate :columns_per_table
29
-
30
- def indexes_per_table
31
- 999
32
- end
33
- deprecate :indexes_per_table
34
-
35
- def columns_per_multicolumn_index
36
- 16
37
- end
38
- deprecate :columns_per_multicolumn_index
39
-
40
- def sql_query_length
41
- 65_536 * 4_096
42
- end
43
- deprecate :sql_query_length
44
-
45
- def joins_per_query
46
- 256
47
- end
48
- deprecate :joins_per_query
49
-
50
19
  private
51
20
 
52
21
  # The max number of binds is 2100, but because sp_executesql takes