activerecord-sqlserver-adapter 6.0.1 → 6.1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +26 -0
  3. data/CHANGELOG.md +29 -46
  4. data/README.md +32 -3
  5. data/RUNNING_UNIT_TESTS.md +1 -1
  6. data/VERSION +1 -1
  7. data/activerecord-sqlserver-adapter.gemspec +1 -1
  8. data/lib/active_record/connection_adapters/sqlserver/core_ext/attribute_methods.rb +2 -0
  9. data/lib/active_record/connection_adapters/sqlserver/core_ext/calculations.rb +5 -10
  10. data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +9 -2
  11. data/lib/active_record/connection_adapters/sqlserver/core_ext/finder_methods.rb +2 -0
  12. data/lib/active_record/connection_adapters/sqlserver/core_ext/preloader.rb +2 -0
  13. data/lib/active_record/connection_adapters/sqlserver/database_limits.rb +0 -4
  14. data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +28 -16
  15. data/lib/active_record/connection_adapters/sqlserver/quoting.rb +8 -7
  16. data/lib/active_record/connection_adapters/sqlserver/schema_creation.rb +22 -1
  17. data/lib/active_record/connection_adapters/sqlserver/schema_dumper.rb +9 -3
  18. data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +31 -9
  19. data/lib/active_record/connection_adapters/sqlserver/sql_type_metadata.rb +36 -7
  20. data/lib/active_record/connection_adapters/sqlserver/table_definition.rb +0 -1
  21. data/lib/active_record/connection_adapters/sqlserver/transaction.rb +2 -2
  22. data/lib/active_record/connection_adapters/sqlserver/type.rb +1 -0
  23. data/lib/active_record/connection_adapters/sqlserver/type/date.rb +2 -1
  24. data/lib/active_record/connection_adapters/sqlserver/type/decimal_without_scale.rb +22 -0
  25. data/lib/active_record/connection_adapters/sqlserver/utils.rb +1 -1
  26. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +100 -69
  27. data/lib/active_record/connection_adapters/sqlserver_column.rb +75 -19
  28. data/lib/active_record/sqlserver_base.rb +9 -15
  29. data/lib/active_record/tasks/sqlserver_database_tasks.rb +17 -14
  30. data/lib/arel/visitors/sqlserver.rb +125 -40
  31. data/test/cases/adapter_test_sqlserver.rb +50 -16
  32. data/test/cases/change_column_collation_test_sqlserver.rb +33 -0
  33. data/test/cases/coerced_tests.rb +611 -78
  34. data/test/cases/column_test_sqlserver.rb +9 -2
  35. data/test/cases/disconnected_test_sqlserver.rb +39 -0
  36. data/test/cases/execute_procedure_test_sqlserver.rb +9 -0
  37. data/test/cases/fetch_test_sqlserver.rb +18 -0
  38. data/test/cases/in_clause_test_sqlserver.rb +27 -0
  39. data/test/cases/lateral_test_sqlserver.rb +35 -0
  40. data/test/cases/migration_test_sqlserver.rb +51 -0
  41. data/test/cases/optimizer_hints_test_sqlserver.rb +72 -0
  42. data/test/cases/order_test_sqlserver.rb +7 -0
  43. data/test/cases/primary_keys_test_sqlserver.rb +103 -0
  44. data/test/cases/rake_test_sqlserver.rb +38 -2
  45. data/test/cases/schema_dumper_test_sqlserver.rb +14 -3
  46. data/test/migrations/create_clients_and_change_column_collation.rb +19 -0
  47. data/test/models/sqlserver/composite_pk.rb +9 -0
  48. data/test/models/sqlserver/sst_string_collation.rb +3 -0
  49. data/test/schema/sqlserver_specific_schema.rb +25 -0
  50. data/test/support/marshal_compatibility_fixtures/SQLServer/rails_6_0_topic.dump +0 -0
  51. data/test/support/marshal_compatibility_fixtures/SQLServer/rails_6_0_topic_associations.dump +0 -0
  52. data/test/support/sql_counter_sqlserver.rb +14 -12
  53. metadata +29 -9
  54. data/.travis.yml +0 -23
  55. data/lib/active_record/connection_adapters/sqlserver/core_ext/query_methods.rb +0 -28
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0a7160737c2d7b0946054cdf6e9fd7c26144cef8f1bc66be90d0b51b7e9ba91f
4
- data.tar.gz: 67ef07c9e35bd3f4735bed2303f3c63f58d09e1bacb7203339b365457c03d296
3
+ metadata.gz: f481c462cbdd16314d87172f78c7a63f63f4c4f7f81df1ca84f110adcb3b6da8
4
+ data.tar.gz: cc79ad659b39244a0df7c37774922f22a537adf736adc9ba6344cdac6643c686
5
5
  SHA512:
6
- metadata.gz: 599f09313bdd68db576bd7282174f04ac9c7e848b2d84b73857e5da9ca5a76427bd22a63bc717e90cd7293747701bdcbcbbc4159e7309bd5328a8be8baa5a245
7
- data.tar.gz: dd54538736ba65dd12ee1ce87aae3da4e324888ca3a9b7a793cae34817451f66ec5b19e0e67882335057e7136f55f1871dad89553f8dfca0824ecdd6c4f34540
6
+ metadata.gz: f0b3f273dfa36cc20e15d52384d8ba8d145f23c5816e7592b5c96324314a5204ea7d76879f6e27bd028cccf1be0411e0f7cbc60009f22b34831ff9383776b252
7
+ data.tar.gz: 6f34b2de7d27af451a8376501a46c65780ab960710632dceb939a4dbb39ac3a7754f48cf84da58e4f15064570d07792f8b779dde036720df74d483c462a7a5ed
@@ -0,0 +1,26 @@
1
+ name: CI
2
+
3
+ on: [push, pull_request]
4
+
5
+ jobs:
6
+ test:
7
+ name: Run test suite
8
+ runs-on: ubuntu-latest
9
+
10
+ env:
11
+ COMPOSE_FILE: docker-compose.ci.yml
12
+
13
+ strategy:
14
+ fail-fast: false
15
+ matrix:
16
+ ruby: [2.5.9, 2.6.7, 2.7.3, 3.0.1]
17
+
18
+ steps:
19
+ - name: Checkout code
20
+ uses: actions/checkout@v2
21
+
22
+ - name: Build docker images
23
+ run: docker-compose build --build-arg TARGET_VERSION=${{ matrix.ruby }}
24
+
25
+ - name: Run tests
26
+ run: docker-compose run ci
data/CHANGELOG.md CHANGED
@@ -1,60 +1,43 @@
1
- ## v6.0.1
1
+ ## v6.1.1.0
2
2
 
3
- #### Fixed
4
-
5
- - [#851](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/851) Updated 'column_definitions_sql' to ensure that only primary key key constraints are queried for
6
-
7
- ## v6.0.0
8
-
9
- **No Changes**
10
-
11
- ## v6.0.0.rc2
3
+ [Full changelog](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/compare/v6.1.0.0...v6.1.1.0)
12
4
 
13
5
  #### Fixed
14
6
 
15
- - [#639](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/639) Primary key should be lowercase if schema forced to lowercase
16
- - [#720](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/720) quoted_date doesn't work for Type::DateTime
7
+ - [#933](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/933) Conditionally apply SQL Server monkey patches to ActiveRecord so that it is safe to use this gem alongside other database adapters (e.g. PostgreSQL) in a multi-database Rails app
8
+ - [#935](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/935) Fix schema cache generation
9
+ (**breaking change**)
10
+ - [#936](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/936) Fix deteministic fetch when table has a composite primary key
11
+ - [#938](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/938) Fix date columns serialization for range values
17
12
 
18
- #### Changed
13
+ ## v6.1.0.0
14
+
15
+ - No changes
19
16
 
20
- - [#826](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/826) Rubocop: Enable Style/StringLiterals cop
21
- - [#827](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/827) Rubocop: Enable Layout/EmptyLinesAroundClassBody cop
22
- - [#828](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/828) Rubocop: Enable Layout/EmptyLines cop
23
- - [#829](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/829) Rubocop: Enable Layout/Layout/EmptyLinesAround* cops
24
- - [#830](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/830) Rubocop: Enable Layout/IndentationWidth and Layout/TrailingWhitespace cops
25
- - [#831](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/831) Rubocop: Enable Spacing cops
26
- - [#832](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/832) Rubocop: Enable Bundler cops
27
- - [#833](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/833) Rubocop: Enable Layout/* cops
28
- - [#834](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/834) Rubocop: Enable Lint/UselessAssignment cop
29
- - [#835](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/835) Rubocop: Configure Naming cops
17
+ ## v6.1.0.0.rc1
30
18
 
31
- ## v6.0.0.rc1
19
+ [Full changelog](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/compare/6-0-stable...v6.1.0.0.rc1)
32
20
 
33
21
  #### Fixed
34
22
 
35
- - [#690](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/690) Rails 6 support
36
- - [#805](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/805) Rails 6: Fix database tasks tests for SQL Server
37
- - [#807](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/807) Rails 6: Skip binary fixtures test on Windows
38
- - [#809](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/809) Rails 6: Coerce reaper test using fork
39
- - [#810](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/810) Rails 6: Fix randomly failing tests due to schema load
40
- - [#812](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/812) Rails 6: Coerce ReloadModelsTest test on Windows
41
- - [#818](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/818) Handle false return by TinyTDS if connection fails and fixed CI
42
- - [#819](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/819) Fix Ruby 2.7 kwargs warnings
43
- - [#825](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/825) Adjust error message when connection is dead
23
+ - [#872](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/872) Use native String#start_with
24
+ - [#876](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/876) Use native String#end_with
25
+ - [#873](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/873) Various fixes to get the tests running for Rails 6.1
26
+ - [#874](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/874) Deduplicate schema cache structures
27
+ - [#875](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/875) Handle default boolean column values when deduplicating
28
+ - [#879](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/879) Added visit method for HomogeneousIn
29
+ - [#880](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/880) Handle any default column class when deduplicating
30
+ - [#861](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/861) Fix Rails 6.1 database config
31
+ - [#890](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/890) Fix removal of invalid ordering from select statements
32
+ - [#881](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/881) Dump column collation to schema.rb and allow collation changes using column_change
33
+ - [#891](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/891) Add support for if_not_exists to indexes
34
+ - [#892](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/892) Add support for if_exists on remove_column
35
+ - [#883](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/885) Fix quoting of ActiveRecord::Relation::QueryAttribute and ActiveModel::Attributes
36
+ - [#893](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/893) Add Active Record Marshal forward compatibility tests
37
+ - [#903](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/903) Raise ActiveRecord::ConnectionNotEstablished on calls to execute with a disconnected connection
44
38
 
45
39
  #### Changed
46
40
 
47
- - [#716](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/716) Translate the connection timed out error
48
- - [#763](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/763) Refactor columns introspection query to make it faster
49
- - [#783](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/783) Update test matrix
50
- - [#820](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/820) Enable frozen strings for tests
51
- - [#821](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/821) Enable frozen strings - part 1
52
- - [#822](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/822) Enable frozen strings - part 2
53
- - [#823](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/823) Enable frozen strings - final
54
- - [#824](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/824) Tidy up Gemfile
55
-
56
- #### Added
57
-
58
- - [#726](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/726) How to Develop ActiveRecord SQL Server Adapter with Pre-Installed MS SQL
41
+ - [#917](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/917) Refactored to use new_client connection pattern
59
42
 
60
- Please check [5-2-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/blob/5-2-stable/CHANGELOG.md) for previous changes.
43
+ Please check [6-0-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/blob/6-0-stable/CHANGELOG.md) for previous changes.
data/README.md CHANGED
@@ -1,15 +1,26 @@
1
1
  # ActiveRecord SQL Server Adapter. For SQL Server 2012 And Higher.
2
2
 
3
- * [![TravisCI](https://travis-ci.org/rails-sqlserver/activerecord-sqlserver-adapter.svg?branch=master)](https://travis-ci.org/rails-sqlserver/activerecord-sqlserver-adapter) - TravisCI
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
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
5
  * [![Gem Version](http://img.shields.io/gem/v/activerecord-sqlserver-adapter.svg)](https://rubygems.org/gems/activerecord-sqlserver-adapter) - Gem Version
6
6
  * [![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
7
 
8
8
  ## About The Adapter
9
9
 
10
- The SQL Server adapter for ActiveRecord v6.0 using SQL Server 2012 or higher.
10
+ The SQL Server adapter for ActiveRecord using SQL Server 2012 or higher.
11
11
 
12
- Interested in older versions? We follow a rational versioning policy that tracks Rails. That means that our 5.2.x version of the adapter is only for the latest 5.2 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.
12
+ Interested in older versions? We follow a rational versioning policy that tracks Rails. That means that our 6.x version of the adapter is only for the latest 6.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 |
15
+ | --------------- | ------------- | ------------------------------------------------------------------------------------------- |
16
+ | `6.1.1.0` | `6.1.x` | [active](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/main) |
17
+ | `6.0.2` | `6.0.x` | [active](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/6-0-stable) |
18
+ | `5.2.1` | `5.2.x` | [active](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/5-2-stable) |
19
+ | `5.1.6` | `5.1.x` | [ended](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/5-1-stable) |
20
+ | `4.2.18` | `4.2.x` | [ended](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/4-2-stable) |
21
+ | `4.1.8` | `4.1.x` | [ended](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/4-1-stable) |
22
+
23
+ For older versions, please check their stable branches.
13
24
 
14
25
  #### Native Data Type Support
15
26
 
@@ -52,6 +63,24 @@ Depending on your user and schema setup, it may be needed to use a table name pr
52
63
  ActiveRecord::Base.table_name_prefix = 'dbo.'
53
64
  ```
54
65
 
66
+ It's also possible to create/change/drop a schema in the migration file as in the example below:
67
+
68
+ ```ruby
69
+ class CreateFooSchema < ActiveRecord::Migration[6.0]
70
+ def up
71
+ create_schema('foo')
72
+
73
+ # Or you could move a table to a different schema
74
+
75
+ change_table_schema('foo', 'dbo.admin')
76
+ end
77
+
78
+ def down
79
+ drop_schema('foo')
80
+ end
81
+ end
82
+ ```
83
+
55
84
 
56
85
  #### Configure Connection & App Name
57
86
 
@@ -5,7 +5,7 @@ This process is much easier than it has been before!
5
5
 
6
6
  ## MS SQL SERVER
7
7
 
8
- If you don't have easy access to MS SQL Server, you can set up a Vagrant/VirtualBox virtual machine with MS SQL Server. [Here's how](/https://github.com/rails-sqlserver/activerecord-sqlserver-adapter-dev-box).
8
+ If you don't have easy access to MS SQL Server, you can set up a Vagrant/VirtualBox virtual machine with MS SQL Server. [Here's how](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter-dev-box).
9
9
 
10
10
  ## TL;DR
11
11
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 6.0.1
1
+ 6.1.1.0
@@ -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", "~> 6.0.0"
30
+ spec.add_dependency "activerecord", "~> 6.1.0"
31
31
  spec.add_dependency "tiny_tds"
32
32
  end
@@ -10,6 +10,8 @@ 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"
14
+
13
15
  super.reject do |name|
14
16
  column = self.class.columns_hash[name]
15
17
  column && column.respond_to?(:is_identity?) && column.is_identity?
@@ -10,6 +10,8 @@ module ActiveRecord
10
10
  module Calculations
11
11
  # Same as original except we don't perform PostgreSQL hack that removes ordering.
12
12
  def calculate(operation, column_name)
13
+ return super unless klass.connection.adapter_name == "SQLServer"
14
+
13
15
  if has_include?(column_name)
14
16
  relation = apply_join_dependency
15
17
 
@@ -29,16 +31,9 @@ module ActiveRecord
29
31
  private
30
32
 
31
33
  def build_count_subquery(relation, column_name, distinct)
32
- super(relation.unscope(:order), column_name, distinct)
33
- end
34
+ return super unless klass.connection.adapter_name == "SQLServer"
34
35
 
35
- def type_cast_calculated_value(value, type, operation = nil)
36
- case operation
37
- when "count" then value.to_i
38
- when "sum" then type.deserialize(value || 0)
39
- when "average" then value&.respond_to?(:to_d) ? value.to_d : value
40
- else type.deserialize(value)
41
- end
36
+ super(relation.unscope(:order), column_name, distinct)
42
37
  end
43
38
  end
44
39
  end
@@ -48,5 +43,5 @@ end
48
43
 
49
44
  ActiveSupport.on_load(:active_record) do
50
45
  mod = ActiveRecord::ConnectionAdapters::SQLServer::CoreExt::Calculations
51
- ActiveRecord::Relation.prepend(mod)
46
+ ActiveRecord::Relation.include(mod)
52
47
  end
@@ -9,6 +9,8 @@ module ActiveRecord
9
9
  SQLSERVER_STATEMENT_REGEXP = /N'(.+)', N'(.+)', (.+)/
10
10
 
11
11
  def exec_explain(queries)
12
+ return super unless connection.adapter_name == "SQLServer"
13
+
12
14
  unprepared_queries = queries.map do |(sql, binds)|
13
15
  [unprepare_sqlserver_statement(sql, binds), binds]
14
16
  end
@@ -21,13 +23,18 @@ module ActiveRecord
21
23
  # which uses sp_executesql to just the first argument, then unquote it. Likewise our
22
24
  # `sp_executesql` method should substitude the @n args with the quoted values.
23
25
  def unprepare_sqlserver_statement(sql, binds)
24
- return sql unless sql.starts_with?(SQLSERVER_STATEMENT_PREFIX)
26
+ return sql unless sql.start_with?(SQLSERVER_STATEMENT_PREFIX)
25
27
 
26
28
  executesql = sql.from(SQLSERVER_STATEMENT_PREFIX.length)
27
29
  executesql = executesql.match(SQLSERVER_STATEMENT_REGEXP).to_a[1]
28
30
 
29
31
  binds.each_with_index do |bind, index|
30
- value = connection.quote(bind)
32
+
33
+ value = if bind.is_a?(::ActiveModel::Attribute) then
34
+ connection.quote(bind.value_for_database)
35
+ else
36
+ connection.quote(bind)
37
+ end
31
38
  executesql = executesql.sub("@#{index}", value)
32
39
  end
33
40
 
@@ -12,6 +12,8 @@ module ActiveRecord
12
12
 
13
13
  # Same as original except we order by values in distinct select if present.
14
14
  def construct_relation_for_exists(conditions)
15
+ return super unless klass.connection.adapter_name == "SQLServer"
16
+
15
17
  conditions = sanitize_forbidden_attributes(conditions)
16
18
 
17
19
  if distinct_value && offset_value
@@ -10,6 +10,8 @@ module ActiveRecord
10
10
  private
11
11
 
12
12
  def records_for(ids)
13
+ return super unless klass.connection.adapter_name == "SQLServer"
14
+
13
15
  ids.each_slice(in_clause_length).flat_map do |slice|
14
16
  scope.where(association_key_name => slice).load do |record|
15
17
  # Processing only the first owner
@@ -37,10 +37,6 @@ module ActiveRecord
37
37
  end
38
38
  deprecate :columns_per_multicolumn_index
39
39
 
40
- def in_clause_length
41
- 10_000
42
- end
43
-
44
40
  def sql_query_length
45
41
  65_536 * 4_096
46
42
  end
@@ -4,7 +4,7 @@ module ActiveRecord
4
4
  module ConnectionAdapters
5
5
  module SQLServer
6
6
  module DatabaseStatements
7
- READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(:begin, :commit, :dbcc, :explain, :save, :select, :set, :rollback) # :nodoc:
7
+ READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(:begin, :commit, :dbcc, :explain, :save, :select, :set, :rollback, :waitfor) # :nodoc:
8
8
  private_constant :READ_QUERY
9
9
 
10
10
  def write_query?(sql) # :nodoc:
@@ -17,6 +17,7 @@ module ActiveRecord
17
17
  end
18
18
 
19
19
  materialize_transactions
20
+ mark_transaction_written_if_write(sql)
20
21
 
21
22
  if id_insert_table_name = query_requires_identity_insert?(sql)
22
23
  with_identity_insert_enabled(id_insert_table_name) { do_execute(sql, name) }
@@ -31,6 +32,7 @@ module ActiveRecord
31
32
  end
32
33
 
33
34
  materialize_transactions
35
+ mark_transaction_written_if_write(sql)
34
36
 
35
37
  sp_executesql(sql, name, binds, prepare: prepare)
36
38
  end
@@ -54,7 +56,7 @@ module ActiveRecord
54
56
  end
55
57
 
56
58
  def begin_db_transaction
57
- do_execute "BEGIN TRANSACTION"
59
+ do_execute "BEGIN TRANSACTION", "TRANSACTION"
58
60
  end
59
61
 
60
62
  def transaction_isolation_levels
@@ -67,25 +69,25 @@ module ActiveRecord
67
69
  end
68
70
 
69
71
  def set_transaction_isolation_level(isolation_level)
70
- do_execute "SET TRANSACTION ISOLATION LEVEL #{isolation_level}"
72
+ do_execute "SET TRANSACTION ISOLATION LEVEL #{isolation_level}", "TRANSACTION"
71
73
  end
72
74
 
73
75
  def commit_db_transaction
74
- do_execute "COMMIT TRANSACTION"
76
+ do_execute "COMMIT TRANSACTION", "TRANSACTION"
75
77
  end
76
78
 
77
79
  def exec_rollback_db_transaction
78
- do_execute "IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION"
80
+ do_execute "IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION", "TRANSACTION"
79
81
  end
80
82
 
81
83
  include Savepoints
82
84
 
83
85
  def create_savepoint(name = current_savepoint_name)
84
- do_execute "SAVE TRANSACTION #{name}"
86
+ do_execute "SAVE TRANSACTION #{name}", "TRANSACTION"
85
87
  end
86
88
 
87
89
  def exec_rollback_to_savepoint(name = current_savepoint_name)
88
- do_execute "ROLLBACK TRANSACTION #{name}"
90
+ do_execute "ROLLBACK TRANSACTION #{name}", "TRANSACTION"
89
91
  end
90
92
 
91
93
  def release_savepoint(name = current_savepoint_name)
@@ -165,7 +167,7 @@ module ActiveRecord
165
167
  log(sql, name) do
166
168
  case @connection_options[:mode]
167
169
  when :dblib
168
- result = @connection.execute(sql)
170
+ result = ensure_established_connection! { dblib_execute(sql) }
169
171
  options = { as: :hash, cache_rows: true, timezone: ActiveRecord::Base.default_timezone || :utc }
170
172
  result.each(options) do |row|
171
173
  r = row.with_indifferent_access
@@ -291,6 +293,7 @@ module ActiveRecord
291
293
 
292
294
  def do_execute(sql, name = "SQL")
293
295
  materialize_transactions
296
+ mark_transaction_written_if_write(sql)
294
297
 
295
298
  log(sql, name) { raw_connection_do(sql) }
296
299
  end
@@ -354,13 +357,7 @@ module ActiveRecord
354
357
  def raw_connection_do(sql)
355
358
  case @connection_options[:mode]
356
359
  when :dblib
357
- result = @connection.execute(sql)
358
-
359
- # TinyTDS returns false instead of raising an exception if connection fails.
360
- # Getting around this by raising an exception ourselves while this PR
361
- # https://github.com/rails-sqlserver/tiny_tds/pull/469 is not released.
362
- raise TinyTds::Error, "failed to execute statement" if result.is_a?(FalseClass)
363
-
360
+ result = ensure_established_connection! { dblib_execute(sql) }
364
361
  result.do
365
362
  end
366
363
  ensure
@@ -425,7 +422,7 @@ module ActiveRecord
425
422
  def raw_connection_run(sql)
426
423
  case @connection_options[:mode]
427
424
  when :dblib
428
- @connection.execute(sql)
425
+ ensure_established_connection! { dblib_execute(sql) }
429
426
  end
430
427
  end
431
428
 
@@ -459,6 +456,21 @@ module ActiveRecord
459
456
  end
460
457
  handle
461
458
  end
459
+
460
+ def dblib_execute(sql)
461
+ @connection.execute(sql).tap do |result|
462
+ # TinyTDS returns false instead of raising an exception if connection fails.
463
+ # Getting around this by raising an exception ourselves while this PR
464
+ # https://github.com/rails-sqlserver/tiny_tds/pull/469 is not released.
465
+ raise TinyTds::Error, "failed to execute statement" if result.is_a?(FalseClass)
466
+ end
467
+ end
468
+
469
+ def ensure_established_connection!
470
+ raise TinyTds::Error, 'SQL Server client is not connected' unless @connection
471
+
472
+ yield
473
+ end
462
474
  end
463
475
  end
464
476
  end
@@ -10,14 +10,15 @@ module ActiveRecord
10
10
 
11
11
  def fetch_type_metadata(sql_type, sqlserver_options = {})
12
12
  cast_type = lookup_cast_type(sql_type)
13
- SQLServer::SqlTypeMetadata.new(
13
+ simple_type = SqlTypeMetadata.new(
14
14
  sql_type: sql_type,
15
15
  type: cast_type.type,
16
16
  limit: cast_type.limit,
17
17
  precision: cast_type.precision,
18
- scale: cast_type.scale,
19
- sqlserver_options: sqlserver_options
18
+ scale: cast_type.scale
20
19
  )
20
+
21
+ SQLServer::TypeMetadata.new(simple_type, **sqlserver_options)
21
22
  end
22
23
 
23
24
  def quote_string(s)
@@ -83,8 +84,8 @@ module ActiveRecord
83
84
  \A
84
85
  (
85
86
  (?:
86
- # [table_name].[column_name] | function(one or no argument)
87
- ((?:\w+\.|\[\w+\]\.)?(?:\w+|\[\w+\])) | \w+\((?:|\g<2>)\)
87
+ # [database_name].[database_owner].[table_name].[column_name] | function(one or no argument)
88
+ ((?:\w+\.|\[\w+\]\.)?(?:\w+\.|\[\w+\]\.)?(?:\w+\.|\[\w+\]\.)?(?:\w+|\[\w+\])) | \w+\((?:|\g<2>)\)
88
89
  )
89
90
  (?:\s+AS\s+(?:\w+|\[\w+\]))?
90
91
  )
@@ -96,8 +97,8 @@ module ActiveRecord
96
97
  \A
97
98
  (
98
99
  (?:
99
- # [table_name].[column_name] | function(one or no argument)
100
- ((?:\w+\.|\[\w+\]\.)?(?:\w+|\[\w+\])) | \w+\((?:|\g<2>)\)
100
+ # [database_name].[database_owner].[table_name].[column_name] | function(one or no argument)
101
+ ((?:\w+\.|\[\w+\]\.)?(?:\w+\.|\[\w+\]\.)?(?:\w+\.|\[\w+\]\.)?(?:\w+|\[\w+\])) | \w+\((?:|\g<2>)\)
101
102
  )
102
103
  (?:\s+ASC|\s+DESC)?
103
104
  (?:\s+NULLS\s+(?:FIRST|LAST))?