activerecord-sqlserver-adapter 6.1.2.1 → 7.2.4
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 +30 -0
- data/.devcontainer/boot.sh +22 -0
- data/.devcontainer/devcontainer.json +38 -0
- data/.devcontainer/docker-compose.yml +42 -0
- data/.github/workflows/ci.yml +7 -4
- data/.gitignore +3 -1
- data/CHANGELOG.md +19 -42
- data/Dockerfile.ci +3 -3
- data/Gemfile +6 -1
- data/MIT-LICENSE +1 -1
- data/README.md +113 -27
- data/RUNNING_UNIT_TESTS.md +27 -14
- data/Rakefile +2 -6
- data/VERSION +1 -1
- data/activerecord-sqlserver-adapter.gemspec +3 -3
- data/appveyor.yml +4 -6
- data/docker-compose.ci.yml +2 -1
- data/lib/active_record/connection_adapters/sqlserver/core_ext/abstract_adapter.rb +20 -0
- 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 +5 -23
- data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +10 -7
- data/lib/active_record/connection_adapters/sqlserver/core_ext/explain_subscriber.rb +2 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/finder_methods.rb +12 -2
- data/lib/active_record/connection_adapters/sqlserver/core_ext/preloader.rb +24 -16
- data/lib/active_record/connection_adapters/sqlserver/database_limits.rb +0 -31
- data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +143 -155
- data/lib/active_record/connection_adapters/sqlserver/database_tasks.rb +5 -5
- data/lib/active_record/connection_adapters/sqlserver/quoting.rb +57 -56
- data/lib/active_record/connection_adapters/sqlserver/savepoints.rb +26 -0
- data/lib/active_record/connection_adapters/sqlserver/schema_creation.rb +14 -12
- data/lib/active_record/connection_adapters/sqlserver/schema_dumper.rb +11 -0
- data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +213 -57
- data/lib/active_record/connection_adapters/sqlserver/showplan.rb +3 -3
- data/lib/active_record/connection_adapters/sqlserver/table_definition.rb +13 -2
- data/lib/active_record/connection_adapters/sqlserver/transaction.rb +4 -6
- data/lib/active_record/connection_adapters/sqlserver/type/data.rb +19 -1
- data/lib/active_record/connection_adapters/sqlserver/type/date.rb +1 -1
- data/lib/active_record/connection_adapters/sqlserver/type/datetime.rb +1 -1
- data/lib/active_record/connection_adapters/sqlserver/type/time.rb +1 -1
- data/lib/active_record/connection_adapters/sqlserver/utils.rb +21 -10
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +187 -187
- data/lib/active_record/connection_adapters/sqlserver_column.rb +1 -0
- data/lib/active_record/tasks/sqlserver_database_tasks.rb +42 -33
- data/lib/arel/visitors/sqlserver.rb +77 -34
- data/test/cases/active_schema_test_sqlserver.rb +127 -0
- data/test/cases/adapter_test_sqlserver.rb +114 -26
- data/test/cases/coerced_tests.rb +1121 -340
- data/test/cases/column_test_sqlserver.rb +67 -64
- data/test/cases/connection_test_sqlserver.rb +3 -6
- data/test/cases/dbconsole.rb +19 -0
- data/test/cases/disconnected_test_sqlserver.rb +8 -5
- data/test/cases/eager_load_too_many_ids_test_sqlserver.rb +18 -0
- data/test/cases/enum_test_sqlserver.rb +49 -0
- data/test/cases/execute_procedure_test_sqlserver.rb +9 -5
- data/test/cases/fetch_test_sqlserver.rb +19 -0
- 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 +19 -1
- data/test/cases/optimizer_hints_test_sqlserver.rb +21 -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 +10 -5
- data/test/cases/schema_dumper_test_sqlserver.rb +155 -109
- data/test/cases/schema_test_sqlserver.rb +64 -1
- data/test/cases/showplan_test_sqlserver.rb +7 -7
- data/test/cases/specific_schema_test_sqlserver.rb +17 -13
- data/test/cases/transaction_test_sqlserver.rb +13 -8
- data/test/cases/trigger_test_sqlserver.rb +20 -0
- data/test/cases/utils_test_sqlserver.rb +2 -2
- data/test/cases/uuid_test_sqlserver.rb +8 -0
- data/test/cases/view_test_sqlserver.rb +58 -0
- data/test/config.yml +1 -2
- data/test/migrations/transaction_table/1_table_will_never_be_created.rb +1 -1
- data/test/models/sqlserver/alien.rb +5 -0
- data/test/models/sqlserver/table_with_spaces.rb +5 -0
- data/test/models/sqlserver/trigger.rb +8 -0
- data/test/schema/sqlserver_specific_schema.rb +54 -6
- data/test/support/coerceable_test_sqlserver.rb +4 -4
- data/test/support/connection_reflection.rb +3 -9
- data/test/support/core_ext/query_cache.rb +7 -1
- data/test/support/marshal_compatibility_fixtures/SQLServer/rails_6_1_topic.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/SQLServer/rails_6_1_topic_associations.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/SQLServer/rails_7_1_topic.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/SQLServer/rails_7_1_topic_associations.dump +0 -0
- data/test/support/query_assertions.rb +49 -0
- data/test/support/rake_helpers.rb +3 -1
- data/test/support/table_definition_sqlserver.rb +24 -0
- data/test/support/test_in_memory_oltp.rb +2 -2
- metadata +41 -17
- data/lib/active_record/sqlserver_base.rb +0 -18
- data/test/cases/scratchpad_test_sqlserver.rb +0 -8
- data/test/support/marshal_compatibility_fixtures/SQLServer/rails_6_0_topic.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/SQLServer/rails_6_0_topic_associations.dump +0 -0
- data/test/support/sql_counter_sqlserver.rb +0 -29
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
|
-
|
1
|
+
7.2.4
|
@@ -7,10 +7,10 @@ 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
|
-
spec.authors = ["Ken Collins", "Anna Carey", "Will Bond", "Murray Steele", "Shawn Balestracci", "Joe Rafaniello", "Tom Ward"]
|
13
|
+
spec.authors = ["Ken Collins", "Anna Carey", "Will Bond", "Murray Steele", "Shawn Balestracci", "Joe Rafaniello", "Tom Ward", "Aidan Haran"]
|
14
14
|
spec.email = ["ken@metaskills.net", "will@wbond.net"]
|
15
15
|
spec.homepage = "http://github.com/rails-sqlserver/activerecord-sqlserver-adapter"
|
16
16
|
spec.summary = "ActiveRecord SQL Server Adapter."
|
@@ -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", "~>
|
30
|
+
spec.add_dependency "activerecord", "~> 7.2.0"
|
31
31
|
spec.add_dependency "tiny_tds"
|
32
32
|
end
|
data/appveyor.yml
CHANGED
@@ -5,10 +5,10 @@ build: off
|
|
5
5
|
matrix:
|
6
6
|
fast_finish: true
|
7
7
|
allow_failures:
|
8
|
-
- ruby_version: "25"
|
9
|
-
- ruby_version: "26"
|
10
8
|
- ruby_version: "27"
|
11
9
|
- ruby_version: "27-x64"
|
10
|
+
- ruby_version: "30"
|
11
|
+
- ruby_version: "30-x64"
|
12
12
|
services:
|
13
13
|
- mssql2014
|
14
14
|
|
@@ -38,9 +38,7 @@ environment:
|
|
38
38
|
CI_AZURE_PASS:
|
39
39
|
secure: cSQp8sk4urJYvq0utpsK+r7J+snJ2wpcdp8RdXJfB+w=
|
40
40
|
matrix:
|
41
|
-
- ruby_version: "25-x64"
|
42
|
-
- ruby_version: "25"
|
43
|
-
- ruby_version: "26-x64"
|
44
|
-
- ruby_version: "26"
|
45
41
|
- ruby_version: "27-x64"
|
46
42
|
- ruby_version: "27"
|
43
|
+
- ruby_version: "30-x64"
|
44
|
+
- ruby_version: "30"
|
data/docker-compose.ci.yml
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
version: "2.2"
|
2
2
|
services:
|
3
3
|
sqlserver:
|
4
|
-
image:
|
4
|
+
image: ghcr.io/rails-sqlserver/mssql-server-linux-rails
|
5
5
|
ci:
|
6
6
|
environment:
|
7
7
|
- ACTIVERECORD_UNITTEST_HOST=sqlserver
|
8
|
+
- RAILS_BRANCH=7-2-stable
|
8
9
|
build:
|
9
10
|
context: .
|
10
11
|
dockerfile: Dockerfile.ci
|
@@ -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
|
@@ -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,32 +8,14 @@ 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
|
-
def calculate(operation, column_name)
|
13
|
-
return super unless klass.connection.adapter_name == "SQLServer"
|
14
|
-
|
15
|
-
if has_include?(column_name)
|
16
|
-
relation = apply_join_dependency
|
17
|
-
|
18
|
-
if operation.to_s.downcase == "count"
|
19
|
-
unless distinct_value || distinct_select?(column_name || select_for_count)
|
20
|
-
relation.distinct!
|
21
|
-
relation.select_values = [klass.primary_key || table[Arel.star]]
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
relation.calculate(operation, column_name)
|
26
|
-
else
|
27
|
-
perform_calculation(operation, column_name)
|
28
|
-
end
|
29
|
-
end
|
30
11
|
|
31
12
|
private
|
32
|
-
|
13
|
+
|
33
14
|
def build_count_subquery(relation, column_name, distinct)
|
34
|
-
|
35
|
-
|
36
|
-
|
15
|
+
klass.with_connection do |connection|
|
16
|
+
relation = relation.unscope(:order) if connection.sqlserver?
|
17
|
+
super(relation, column_name, distinct)
|
18
|
+
end
|
37
19
|
end
|
38
20
|
end
|
39
21
|
end
|
@@ -8,20 +8,23 @@ module ActiveRecord
|
|
8
8
|
SQLSERVER_STATEMENT_PREFIX = "EXEC sp_executesql "
|
9
9
|
SQLSERVER_STATEMENT_REGEXP = /N'(.+)', N'(.+)', (.+)/
|
10
10
|
|
11
|
-
def exec_explain(queries)
|
12
|
-
|
11
|
+
def exec_explain(queries, options = [])
|
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)
|
18
21
|
end
|
19
22
|
|
20
23
|
private
|
21
24
|
|
22
|
-
# This is somewhat hacky, but it should reliably reformat our prepared sql
|
25
|
+
# This is somewhat hacky, but it should reliably reformat our prepared sql statement
|
23
26
|
# which uses sp_executesql to just the first argument, then unquote it. Likewise our
|
24
|
-
# `sp_executesql` method should
|
27
|
+
# `sp_executesql` method should substitute the @n args with the quoted values.
|
25
28
|
def unprepare_sqlserver_statement(sql, binds)
|
26
29
|
return sql unless sql.start_with?(SQLSERVER_STATEMENT_PREFIX)
|
27
30
|
|
@@ -10,18 +10,28 @@ 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
|
-
|
14
|
+
klass.with_connection do |connection|
|
15
|
+
if connection.sqlserver?
|
16
|
+
_construct_relation_for_exists(conditions)
|
17
|
+
else
|
18
|
+
super
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
16
22
|
|
23
|
+
# Same as original except we order by values in distinct select if present.
|
24
|
+
def _construct_relation_for_exists(conditions)
|
17
25
|
conditions = sanitize_forbidden_attributes(conditions)
|
18
26
|
|
19
27
|
if distinct_value && offset_value
|
28
|
+
# Start of monkey-patch
|
20
29
|
if select_values.present?
|
21
30
|
relation = order(*select_values).limit!(1)
|
22
31
|
else
|
23
32
|
relation = except(:order).limit!(1)
|
24
33
|
end
|
34
|
+
# End of monkey-patch
|
25
35
|
else
|
26
36
|
relation = except(:select, :distinct, :order)._select!(::ActiveRecord::FinderMethods::ONE_AS_ONE).limit!(1)
|
27
37
|
end
|
@@ -6,20 +6,28 @@ module ActiveRecord
|
|
6
6
|
module ConnectionAdapters
|
7
7
|
module SQLServer
|
8
8
|
module CoreExt
|
9
|
-
module
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
9
|
+
module LoaderQuery
|
10
|
+
def load_records_for_keys(keys, &block)
|
11
|
+
scope.with_connection do |connection|
|
12
|
+
return super unless connection.sqlserver?
|
13
|
+
|
14
|
+
return [] if keys.empty?
|
15
|
+
|
16
|
+
if association_key_name.is_a?(Array)
|
17
|
+
query_constraints = Hash.new { |hsh, key| hsh[key] = Set.new }
|
18
|
+
|
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
|
23
|
+
end
|
24
|
+
|
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
|
30
|
+
end
|
23
31
|
end
|
24
32
|
end
|
25
33
|
|
@@ -33,6 +41,6 @@ module ActiveRecord
|
|
33
41
|
end
|
34
42
|
|
35
43
|
ActiveSupport.on_load(:active_record) do
|
36
|
-
mod = ActiveRecord::ConnectionAdapters::SQLServer::CoreExt::
|
37
|
-
ActiveRecord::Associations::Preloader::Association.prepend(mod)
|
44
|
+
mod = ActiveRecord::ConnectionAdapters::SQLServer::CoreExt::LoaderQuery
|
45
|
+
ActiveRecord::Associations::Preloader::Association::LoaderQuery.prepend(mod)
|
38
46
|
end
|
@@ -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
|