activerecord-sqlserver-adapter 6.0.0.rc1 → 6.1.0.0.rc1
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/.github/workflows/ci.yml +26 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +29 -0
- data/CHANGELOG.md +18 -23
- data/Gemfile +11 -5
- data/Guardfile +9 -8
- data/README.md +32 -3
- data/RUNNING_UNIT_TESTS.md +1 -1
- data/Rakefile +12 -16
- data/VERSION +1 -1
- data/activerecord-sqlserver-adapter.gemspec +4 -4
- data/lib/active_record/connection_adapters/sqlserver/core_ext/active_record.rb +0 -4
- data/lib/active_record/connection_adapters/sqlserver/core_ext/attribute_methods.rb +1 -4
- data/lib/active_record/connection_adapters/sqlserver/core_ext/calculations.rb +3 -13
- data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +8 -5
- data/lib/active_record/connection_adapters/sqlserver/core_ext/finder_methods.rb +2 -3
- data/lib/active_record/connection_adapters/sqlserver/core_ext/query_methods.rb +2 -3
- data/lib/active_record/connection_adapters/sqlserver/database_limits.rb +0 -4
- data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +58 -43
- data/lib/active_record/connection_adapters/sqlserver/database_tasks.rb +7 -12
- data/lib/active_record/connection_adapters/sqlserver/errors.rb +0 -3
- data/lib/active_record/connection_adapters/sqlserver/quoting.rb +15 -15
- data/lib/active_record/connection_adapters/sqlserver/schema_creation.rb +22 -3
- data/lib/active_record/connection_adapters/sqlserver/schema_dumper.rb +16 -10
- data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +131 -105
- data/lib/active_record/connection_adapters/sqlserver/showplan.rb +6 -8
- data/lib/active_record/connection_adapters/sqlserver/showplan/printer_table.rb +2 -2
- data/lib/active_record/connection_adapters/sqlserver/showplan/printer_xml.rb +1 -1
- data/lib/active_record/connection_adapters/sqlserver/sql_type_metadata.rb +25 -7
- data/lib/active_record/connection_adapters/sqlserver/table_definition.rb +1 -5
- data/lib/active_record/connection_adapters/sqlserver/transaction.rb +6 -10
- data/lib/active_record/connection_adapters/sqlserver/type.rb +36 -35
- data/lib/active_record/connection_adapters/sqlserver/type/big_integer.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/type/binary.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/type/boolean.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/type/char.rb +2 -2
- data/lib/active_record/connection_adapters/sqlserver/type/data.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/type/date.rb +2 -3
- data/lib/active_record/connection_adapters/sqlserver/type/datetime.rb +2 -3
- data/lib/active_record/connection_adapters/sqlserver/type/datetime2.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/type/datetimeoffset.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/type/decimal.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/type/decimal_without_scale.rb +22 -0
- data/lib/active_record/connection_adapters/sqlserver/type/float.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/type/integer.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/type/json.rb +0 -1
- data/lib/active_record/connection_adapters/sqlserver/type/money.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/type/real.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/type/small_integer.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/type/small_money.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/type/smalldatetime.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/type/string.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/type/text.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/type/time.rb +2 -3
- data/lib/active_record/connection_adapters/sqlserver/type/time_value_fractional.rb +6 -9
- data/lib/active_record/connection_adapters/sqlserver/type/timestamp.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/type/tiny_integer.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_char.rb +1 -3
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_string.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_text.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar_max.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/type/uuid.rb +1 -2
- data/lib/active_record/connection_adapters/sqlserver/type/varbinary.rb +1 -3
- data/lib/active_record/connection_adapters/sqlserver/type/varbinary_max.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/type/varchar.rb +1 -3
- data/lib/active_record/connection_adapters/sqlserver/type/varchar_max.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/utils.rb +8 -11
- data/lib/active_record/connection_adapters/sqlserver/version.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +170 -136
- data/lib/active_record/connection_adapters/sqlserver_column.rb +16 -1
- data/lib/active_record/sqlserver_base.rb +9 -15
- data/lib/active_record/tasks/sqlserver_database_tasks.rb +36 -39
- data/lib/activerecord-sqlserver-adapter.rb +1 -1
- data/lib/arel/visitors/sqlserver.rb +126 -50
- data/lib/arel_sqlserver.rb +2 -2
- data/test/cases/adapter_test_sqlserver.rb +203 -190
- data/test/cases/change_column_collation_test_sqlserver.rb +33 -0
- data/test/cases/change_column_null_test_sqlserver.rb +12 -12
- data/test/cases/coerced_tests.rb +656 -318
- data/test/cases/column_test_sqlserver.rb +285 -284
- data/test/cases/connection_test_sqlserver.rb +15 -20
- data/test/cases/disconnected_test_sqlserver.rb +39 -0
- data/test/cases/execute_procedure_test_sqlserver.rb +26 -19
- data/test/cases/fetch_test_sqlserver.rb +14 -22
- data/test/cases/fully_qualified_identifier_test_sqlserver.rb +12 -18
- data/test/cases/helper_sqlserver.rb +13 -15
- data/test/cases/in_clause_test_sqlserver.rb +36 -9
- data/test/cases/index_test_sqlserver.rb +13 -15
- data/test/cases/json_test_sqlserver.rb +23 -25
- data/test/cases/lateral_test_sqlserver.rb +35 -0
- data/test/cases/migration_test_sqlserver.rb +71 -26
- data/test/cases/optimizer_hints_test_sqlserver.rb +72 -0
- data/test/cases/order_test_sqlserver.rb +57 -53
- data/test/cases/pessimistic_locking_test_sqlserver.rb +25 -33
- data/test/cases/primary_keys_test_sqlserver.rb +103 -0
- data/test/cases/rake_test_sqlserver.rb +33 -46
- data/test/cases/schema_dumper_test_sqlserver.rb +121 -108
- data/test/cases/schema_test_sqlserver.rb +18 -26
- data/test/cases/scratchpad_test_sqlserver.rb +2 -4
- data/test/cases/showplan_test_sqlserver.rb +24 -33
- data/test/cases/specific_schema_test_sqlserver.rb +66 -65
- data/test/cases/transaction_test_sqlserver.rb +16 -19
- data/test/cases/trigger_test_sqlserver.rb +12 -12
- data/test/cases/utils_test_sqlserver.rb +68 -70
- data/test/cases/uuid_test_sqlserver.rb +11 -13
- data/test/debug.rb +6 -6
- data/test/migrations/create_clients_and_change_column_collation.rb +19 -0
- data/test/migrations/create_clients_and_change_column_null.rb +1 -1
- data/test/migrations/transaction_table/1_table_will_never_be_created.rb +2 -4
- data/test/models/sqlserver/booking.rb +1 -1
- data/test/models/sqlserver/customers_view.rb +1 -1
- data/test/models/sqlserver/dollar_table_name.rb +1 -1
- data/test/models/sqlserver/edge_schema.rb +1 -3
- data/test/models/sqlserver/fk_has_fk.rb +1 -1
- data/test/models/sqlserver/fk_has_pk.rb +1 -1
- data/test/models/sqlserver/natural_pk_data.rb +2 -2
- data/test/models/sqlserver/natural_pk_int_data.rb +1 -1
- data/test/models/sqlserver/no_pk_data.rb +1 -1
- data/test/models/sqlserver/object_default.rb +1 -1
- data/test/models/sqlserver/quoted_table.rb +2 -2
- data/test/models/sqlserver/quoted_view_1.rb +1 -1
- data/test/models/sqlserver/quoted_view_2.rb +1 -1
- data/test/models/sqlserver/sst_memory.rb +1 -1
- data/test/models/sqlserver/sst_string_collation.rb +3 -0
- data/test/models/sqlserver/string_default.rb +1 -1
- data/test/models/sqlserver/string_defaults_big_view.rb +1 -1
- data/test/models/sqlserver/string_defaults_view.rb +1 -1
- data/test/models/sqlserver/tinyint_pk.rb +1 -1
- data/test/models/sqlserver/trigger.rb +2 -2
- data/test/models/sqlserver/trigger_history.rb +1 -1
- data/test/models/sqlserver/upper.rb +1 -1
- data/test/models/sqlserver/uppered.rb +1 -1
- data/test/models/sqlserver/uuid.rb +1 -1
- data/test/schema/sqlserver_specific_schema.rb +36 -21
- data/test/support/coerceable_test_sqlserver.rb +1 -4
- data/test/support/connection_reflection.rb +1 -2
- data/test/support/core_ext/query_cache.rb +1 -1
- data/test/support/load_schema_sqlserver.rb +3 -5
- 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/minitest_sqlserver.rb +1 -1
- data/test/support/paths_sqlserver.rb +9 -11
- data/test/support/rake_helpers.rb +12 -10
- data/test/support/sql_counter_sqlserver.rb +14 -16
- data/test/support/test_in_memory_oltp.rb +7 -7
- metadata +31 -11
- data/.travis.yml +0 -23
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "cases/helper_sqlserver"
|
|
4
|
+
require "migrations/create_clients_and_change_column_collation"
|
|
5
|
+
|
|
6
|
+
class ChangeColumnCollationTestSqlServer < ActiveRecord::TestCase
|
|
7
|
+
before do
|
|
8
|
+
@old_verbose = ActiveRecord::Migration.verbose
|
|
9
|
+
ActiveRecord::Migration.verbose = false
|
|
10
|
+
CreateClientsAndChangeColumnCollation.new.up
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
after do
|
|
14
|
+
CreateClientsAndChangeColumnCollation.new.down
|
|
15
|
+
ActiveRecord::Migration.verbose = @old_verbose
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def find_column(table, name)
|
|
19
|
+
table.find { |column| column.name == name }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
let(:clients_table) { connection.columns("clients") }
|
|
23
|
+
let(:name_column) { find_column(clients_table, "name") }
|
|
24
|
+
let(:code_column) { find_column(clients_table, "code") }
|
|
25
|
+
|
|
26
|
+
it "change column collation to other than default" do
|
|
27
|
+
_(name_column.collation).must_equal "SQL_Latin1_General_CP1_CS_AS"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "change column collation to default" do
|
|
31
|
+
_(code_column.collation).must_equal "SQL_Latin1_General_CP1_CI_AS"
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require
|
|
3
|
+
require "cases/helper_sqlserver"
|
|
4
|
+
require "migrations/create_clients_and_change_column_null"
|
|
5
5
|
|
|
6
6
|
class ChangeColumnNullTestSqlServer < ActiveRecord::TestCase
|
|
7
7
|
before do
|
|
@@ -19,25 +19,25 @@ class ChangeColumnNullTestSqlServer < ActiveRecord::TestCase
|
|
|
19
19
|
table.find { |column| column.name == name }
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
-
let(:clients_table) { connection.columns(
|
|
23
|
-
let(:name_column) { find_column(clients_table,
|
|
24
|
-
let(:code_column) { find_column(clients_table,
|
|
25
|
-
let(:value_column) { find_column(clients_table,
|
|
22
|
+
let(:clients_table) { connection.columns("clients") }
|
|
23
|
+
let(:name_column) { find_column(clients_table, "name") }
|
|
24
|
+
let(:code_column) { find_column(clients_table, "code") }
|
|
25
|
+
let(:value_column) { find_column(clients_table, "value") }
|
|
26
26
|
|
|
27
|
-
describe
|
|
28
|
-
it
|
|
27
|
+
describe "#change_column_null" do
|
|
28
|
+
it "does not change the column limit" do
|
|
29
29
|
_(name_column.limit).must_equal 15
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
-
it
|
|
33
|
-
_(code_column.default).must_equal
|
|
32
|
+
it "does not change the column default" do
|
|
33
|
+
_(code_column.default).must_equal "n/a"
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
-
it
|
|
36
|
+
it "does not change the column precision" do
|
|
37
37
|
_(value_column.precision).must_equal 32
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
-
it
|
|
40
|
+
it "does not change the column scale" do
|
|
41
41
|
_(value_column.scale).must_equal 8
|
|
42
42
|
end
|
|
43
43
|
end
|
data/test/cases/coerced_tests.rb
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
3
|
+
require "cases/helper_sqlserver"
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
require 'models/event'
|
|
5
|
+
require "models/event"
|
|
8
6
|
class UniquenessValidationTest < ActiveRecord::TestCase
|
|
9
7
|
# So sp_executesql swallows this exception. Run without prepared to see it.
|
|
10
8
|
coerce_tests! :test_validate_uniqueness_with_limit
|
|
@@ -26,25 +24,35 @@ class UniquenessValidationTest < ActiveRecord::TestCase
|
|
|
26
24
|
end
|
|
27
25
|
end
|
|
28
26
|
|
|
29
|
-
#
|
|
30
|
-
coerce_tests! :
|
|
31
|
-
def
|
|
32
|
-
|
|
33
|
-
skip if database_collation.include?('_CI_')
|
|
27
|
+
# Same as original coerced test except that it handles default SQL Server case-insensitive collation.
|
|
28
|
+
coerce_tests! :test_validate_uniqueness_by_default_database_collation
|
|
29
|
+
def test_validate_uniqueness_by_default_database_collation_coerced
|
|
30
|
+
Topic.validates_uniqueness_of(:author_email_address)
|
|
34
31
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
32
|
+
topic1 = Topic.new(author_email_address: "david@loudthinking.com")
|
|
33
|
+
topic2 = Topic.new(author_email_address: "David@loudthinking.com")
|
|
34
|
+
|
|
35
|
+
assert_equal 1, Topic.where(author_email_address: "david@loudthinking.com").count
|
|
38
36
|
|
|
37
|
+
assert_not topic1.valid?
|
|
38
|
+
assert_not topic1.save
|
|
39
39
|
|
|
40
|
+
# Case insensitive collation (SQL_Latin1_General_CP1_CI_AS) by default.
|
|
41
|
+
# Should not allow "David" if "david" exists.
|
|
42
|
+
assert_not topic2.valid?
|
|
43
|
+
assert_not topic2.save
|
|
40
44
|
|
|
45
|
+
assert_equal 1, Topic.where(author_email_address: "david@loudthinking.com").count
|
|
46
|
+
assert_equal 1, Topic.where(author_email_address: "David@loudthinking.com").count
|
|
47
|
+
end
|
|
48
|
+
end
|
|
41
49
|
|
|
42
|
-
require
|
|
50
|
+
require "models/event"
|
|
43
51
|
module ActiveRecord
|
|
44
52
|
class AdapterTest < ActiveRecord::TestCase
|
|
45
|
-
#
|
|
46
|
-
coerce_tests! :
|
|
47
|
-
coerce_tests! :
|
|
53
|
+
# Legacy binds are not supported.
|
|
54
|
+
coerce_tests! :test_select_all_insert_update_delete_with_casted_binds
|
|
55
|
+
coerce_tests! :test_select_all_insert_update_delete_with_legacy_binds
|
|
48
56
|
|
|
49
57
|
# As far as I can tell, SQL Server does not support null bytes in strings.
|
|
50
58
|
coerce_tests! :test_update_prepared_statement
|
|
@@ -54,23 +62,70 @@ module ActiveRecord
|
|
|
54
62
|
def test_value_limit_violations_are_translated_to_specific_exception_coerced
|
|
55
63
|
connection.unprepared_statement do
|
|
56
64
|
error = assert_raises(ActiveRecord::ValueTooLong) do
|
|
57
|
-
Event.create(title:
|
|
65
|
+
Event.create(title: "abcdefgh")
|
|
58
66
|
end
|
|
59
67
|
assert_not_nil error.cause
|
|
60
68
|
end
|
|
61
69
|
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
62
72
|
|
|
73
|
+
module ActiveRecord
|
|
74
|
+
class AdapterPreventWritesTest < ActiveRecord::TestCase
|
|
63
75
|
# Fix randomly failing test. The loading of the model's schema was affecting the test.
|
|
64
76
|
coerce_tests! :test_errors_when_an_insert_query_is_called_while_preventing_writes
|
|
65
77
|
def test_errors_when_an_insert_query_is_called_while_preventing_writes_coerced
|
|
66
78
|
Subscriber.send(:load_schema!)
|
|
67
79
|
original_test_errors_when_an_insert_query_is_called_while_preventing_writes
|
|
68
80
|
end
|
|
81
|
+
|
|
82
|
+
# Fix randomly failing test. The loading of the model's schema was affecting the test.
|
|
83
|
+
coerce_tests! :test_errors_when_an_insert_query_prefixed_by_a_double_dash_comment_containing_read_command_is_called_while_preventing_writes
|
|
84
|
+
def test_errors_when_an_insert_query_prefixed_by_a_double_dash_comment_containing_read_command_is_called_while_preventing_writes_coerced
|
|
85
|
+
Subscriber.send(:load_schema!)
|
|
86
|
+
original_test_errors_when_an_insert_query_prefixed_by_a_double_dash_comment_containing_read_command_is_called_while_preventing_writes
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Fix randomly failing test. The loading of the model's schema was affecting the test.
|
|
90
|
+
coerce_tests! :test_errors_when_an_insert_query_prefixed_by_a_double_dash_comment_is_called_while_preventing_writes
|
|
91
|
+
def test_errors_when_an_insert_query_prefixed_by_a_double_dash_comment_is_called_while_preventing_writes_coerced
|
|
92
|
+
Subscriber.send(:load_schema!)
|
|
93
|
+
original_test_errors_when_an_insert_query_prefixed_by_a_double_dash_comment_is_called_while_preventing_writes
|
|
94
|
+
end
|
|
69
95
|
end
|
|
70
96
|
end
|
|
71
97
|
|
|
98
|
+
module ActiveRecord
|
|
99
|
+
class AdapterPreventWritesLegacyTest < ActiveRecord::TestCase
|
|
100
|
+
# Fix randomly failing test. The loading of the model's schema was affecting the test.
|
|
101
|
+
coerce_tests! :test_errors_when_an_insert_query_is_called_while_preventing_writes
|
|
102
|
+
def test_errors_when_an_insert_query_is_called_while_preventing_writes_coerced
|
|
103
|
+
Subscriber.send(:load_schema!)
|
|
104
|
+
original_test_errors_when_an_insert_query_is_called_while_preventing_writes
|
|
105
|
+
end
|
|
72
106
|
|
|
107
|
+
# Fix randomly failing test. The loading of the model's schema was affecting the test.
|
|
108
|
+
coerce_tests! :test_errors_when_an_insert_query_prefixed_by_a_slash_star_comment_is_called_while_preventing_writes
|
|
109
|
+
def test_errors_when_an_insert_query_prefixed_by_a_slash_star_comment_is_called_while_preventing_writes_coerced
|
|
110
|
+
Subscriber.send(:load_schema!)
|
|
111
|
+
original_test_errors_when_an_insert_query_prefixed_by_a_slash_star_comment_is_called_while_preventing_writes
|
|
112
|
+
end
|
|
73
113
|
|
|
114
|
+
# Fix randomly failing test. The loading of the model's schema was affecting the test.
|
|
115
|
+
coerce_tests! :test_errors_when_an_insert_query_prefixed_by_a_double_dash_comment_is_called_while_preventing_writes
|
|
116
|
+
def test_errors_when_an_insert_query_prefixed_by_a_double_dash_comment_is_called_while_preventing_writes_coerced
|
|
117
|
+
Subscriber.send(:load_schema!)
|
|
118
|
+
original_test_errors_when_an_insert_query_prefixed_by_a_double_dash_comment_is_called_while_preventing_writes
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Fix randomly failing test. The loading of the model's schema was affecting the test.
|
|
122
|
+
coerce_tests! :test_errors_when_an_insert_query_prefixed_by_a_double_dash_comment_containing_read_command_is_called_while_preventing_writes
|
|
123
|
+
def test_errors_when_an_insert_query_prefixed_by_a_double_dash_comment_containing_read_command_is_called_while_preventing_writes_coerced
|
|
124
|
+
Subscriber.send(:load_schema!)
|
|
125
|
+
original_test_errors_when_an_insert_query_prefixed_by_a_double_dash_comment_containing_read_command_is_called_while_preventing_writes
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
74
129
|
|
|
75
130
|
module ActiveRecord
|
|
76
131
|
class AdapterTestWithoutTransaction < ActiveRecord::TestCase
|
|
@@ -125,15 +180,12 @@ module ActiveRecord
|
|
|
125
180
|
end
|
|
126
181
|
end
|
|
127
182
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
require 'models/topic'
|
|
183
|
+
require "models/topic"
|
|
132
184
|
class AttributeMethodsTest < ActiveRecord::TestCase
|
|
133
185
|
# Use IFF for boolean statement in SELECT
|
|
134
186
|
coerce_tests! %r{typecast attribute from select to false}
|
|
135
187
|
def test_typecast_attribute_from_select_to_false_coerced
|
|
136
|
-
Topic.create(:title =>
|
|
188
|
+
Topic.create(:title => "Budget")
|
|
137
189
|
topic = Topic.all.merge!(:select => "topics.*, IIF (1 = 2, 1, 0) as is_test").first
|
|
138
190
|
assert_not_predicate topic, :is_test?
|
|
139
191
|
end
|
|
@@ -141,21 +193,18 @@ class AttributeMethodsTest < ActiveRecord::TestCase
|
|
|
141
193
|
# Use IFF for boolean statement in SELECT
|
|
142
194
|
coerce_tests! %r{typecast attribute from select to true}
|
|
143
195
|
def test_typecast_attribute_from_select_to_true_coerced
|
|
144
|
-
Topic.create(:title =>
|
|
196
|
+
Topic.create(:title => "Budget")
|
|
145
197
|
topic = Topic.all.merge!(:select => "topics.*, IIF (1 = 1, 1, 0) as is_test").first
|
|
146
198
|
assert_predicate topic, :is_test?
|
|
147
199
|
end
|
|
148
200
|
end
|
|
149
201
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
202
|
class BasicsTest < ActiveRecord::TestCase
|
|
154
203
|
# Use square brackets as SQL Server escaped character
|
|
155
204
|
coerce_tests! :test_column_names_are_escaped
|
|
156
205
|
def test_column_names_are_escaped_coerced
|
|
157
206
|
conn = ActiveRecord::Base.connection
|
|
158
|
-
assert_equal
|
|
207
|
+
assert_equal "[t]]]", conn.quote_column_name("t]")
|
|
159
208
|
end
|
|
160
209
|
|
|
161
210
|
# Just like PostgreSQLAdapter does.
|
|
@@ -175,7 +224,7 @@ class BasicsTest < ActiveRecord::TestCase
|
|
|
175
224
|
end
|
|
176
225
|
|
|
177
226
|
def test_update_date_time_attributes_with_default_timezone_local
|
|
178
|
-
with_env_tz
|
|
227
|
+
with_env_tz "America/New_York" do
|
|
179
228
|
with_timezone_config default: :local do
|
|
180
229
|
Time.use_zone("Eastern Time (US & Canada)") do
|
|
181
230
|
topic = Topic.find(1)
|
|
@@ -190,7 +239,7 @@ class BasicsTest < ActiveRecord::TestCase
|
|
|
190
239
|
# SQL Server does not have query for release_savepoint
|
|
191
240
|
coerce_tests! %r{an empty transaction does not raise if preventing writes}
|
|
192
241
|
test "an empty transaction does not raise if preventing writes coerced" do
|
|
193
|
-
ActiveRecord::Base.
|
|
242
|
+
ActiveRecord::Base.while_preventing_writes do
|
|
194
243
|
assert_queries(1, ignore_none: true) do
|
|
195
244
|
Bird.transaction do
|
|
196
245
|
ActiveRecord::Base.connection.materialize_transactions
|
|
@@ -200,9 +249,6 @@ class BasicsTest < ActiveRecord::TestCase
|
|
|
200
249
|
end
|
|
201
250
|
end
|
|
202
251
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
252
|
class BelongsToAssociationsTest < ActiveRecord::TestCase
|
|
207
253
|
# Since @client.firm is a single first/top, and we use FETCH the order clause is used.
|
|
208
254
|
coerce_tests! :test_belongs_to_does_not_use_order_by
|
|
@@ -227,9 +273,6 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
|
|
|
227
273
|
end
|
|
228
274
|
end
|
|
229
275
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
276
|
module ActiveRecord
|
|
234
277
|
class BindParameterTest < ActiveRecord::TestCase
|
|
235
278
|
# Same as original coerced test except log is found using `EXEC sp_executesql` wrapper.
|
|
@@ -254,11 +297,57 @@ module ActiveRecord
|
|
|
254
297
|
coerce_tests! :test_statement_cache_with_find_by
|
|
255
298
|
coerce_tests! :test_statement_cache_with_in_clause
|
|
256
299
|
coerce_tests! :test_statement_cache_with_sql_string_literal
|
|
257
|
-
end
|
|
258
|
-
end
|
|
259
300
|
|
|
301
|
+
# Same as original coerced test except prepared statements include `EXEC sp_executesql` wrapper.
|
|
302
|
+
coerce_tests! :test_bind_params_to_sql_with_prepared_statements, :test_bind_params_to_sql_with_unprepared_statements
|
|
303
|
+
def test_bind_params_to_sql_with_prepared_statements_coerced
|
|
304
|
+
assert_bind_params_to_sql_coerced(prepared: true)
|
|
305
|
+
end
|
|
260
306
|
|
|
307
|
+
def test_bind_params_to_sql_with_unprepared_statements_coerced
|
|
308
|
+
@connection.unprepared_statement do
|
|
309
|
+
assert_bind_params_to_sql_coerced(prepared: false)
|
|
310
|
+
end
|
|
311
|
+
end
|
|
261
312
|
|
|
313
|
+
private
|
|
314
|
+
|
|
315
|
+
def assert_bind_params_to_sql_coerced(prepared:)
|
|
316
|
+
table = Author.quoted_table_name
|
|
317
|
+
pk = "#{table}.#{Author.quoted_primary_key}"
|
|
318
|
+
|
|
319
|
+
# prepared_statements: true
|
|
320
|
+
#
|
|
321
|
+
# EXEC sp_executesql N'SELECT [authors].* FROM [authors] WHERE [authors].[id] IN (@0, @1, @2) OR [authors].[id] IS NULL)', N'@0 bigint, @1 bigint, @2 bigint', @0 = 1, @1 = 2, @2 = 3
|
|
322
|
+
#
|
|
323
|
+
# prepared_statements: false
|
|
324
|
+
#
|
|
325
|
+
# SELECT [authors].* FROM [authors] WHERE ([authors].[id] IN (1, 2, 3) OR [authors].[id] IS NULL)
|
|
326
|
+
#
|
|
327
|
+
sql_unprepared = "SELECT #{table}.* FROM #{table} WHERE (#{pk} IN (#{bind_params(1..3)}) OR #{pk} IS NULL)"
|
|
328
|
+
sql_prepared = "EXEC sp_executesql N'SELECT #{table}.* FROM #{table} WHERE (#{pk} IN (#{bind_params(1..3)}) OR #{pk} IS NULL)', N'@0 bigint, @1 bigint, @2 bigint', @0 = 1, @1 = 2, @2 = 3"
|
|
329
|
+
|
|
330
|
+
authors = Author.where(id: [1, 2, 3, nil])
|
|
331
|
+
assert_equal sql_unprepared, @connection.to_sql(authors.arel)
|
|
332
|
+
assert_sql(prepared ? sql_prepared : sql_unprepared) { assert_equal 3, authors.length }
|
|
333
|
+
|
|
334
|
+
# prepared_statements: true
|
|
335
|
+
#
|
|
336
|
+
# EXEC sp_executesql N'SELECT [authors].* FROM [authors] WHERE [authors].[id] IN (@0, @1, @2)', N'@0 bigint, @1 bigint, @2 bigint', @0 = 1, @1 = 2, @2 = 3
|
|
337
|
+
#
|
|
338
|
+
# prepared_statements: false
|
|
339
|
+
#
|
|
340
|
+
# SELECT [authors].* FROM [authors] WHERE [authors].[id] IN (1, 2, 3)
|
|
341
|
+
#
|
|
342
|
+
sql_unprepared = "SELECT #{table}.* FROM #{table} WHERE #{pk} IN (#{bind_params(1..3)})"
|
|
343
|
+
sql_prepared = "EXEC sp_executesql N'SELECT #{table}.* FROM #{table} WHERE #{pk} IN (#{bind_params(1..3)})', N'@0 bigint, @1 bigint, @2 bigint', @0 = 1, @1 = 2, @2 = 3"
|
|
344
|
+
|
|
345
|
+
authors = Author.where(id: [1, 2, 3, 9223372036854775808])
|
|
346
|
+
assert_equal sql_unprepared, @connection.to_sql(authors.arel)
|
|
347
|
+
assert_sql(prepared ? sql_prepared : sql_unprepared) { assert_equal 3, authors.length }
|
|
348
|
+
end
|
|
349
|
+
end
|
|
350
|
+
end
|
|
262
351
|
|
|
263
352
|
module ActiveRecord
|
|
264
353
|
class InstrumentationTest < ActiveRecord::TestCase
|
|
@@ -271,9 +360,6 @@ module ActiveRecord
|
|
|
271
360
|
end
|
|
272
361
|
end
|
|
273
362
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
363
|
class CalculationsTest < ActiveRecord::TestCase
|
|
278
364
|
# Fix randomly failing test. The loading of the model's schema was affecting the test.
|
|
279
365
|
coerce_tests! :test_offset_is_kept
|
|
@@ -282,11 +368,112 @@ class CalculationsTest < ActiveRecord::TestCase
|
|
|
282
368
|
original_test_offset_is_kept
|
|
283
369
|
end
|
|
284
370
|
|
|
285
|
-
#
|
|
371
|
+
# The SQL Server `AVG()` function for a list of integers returns an integer (not a decimal).
|
|
286
372
|
coerce_tests! :test_should_return_decimal_average_of_integer_field
|
|
287
373
|
def test_should_return_decimal_average_of_integer_field_coerced
|
|
288
374
|
value = Account.average(:id)
|
|
289
|
-
assert_equal
|
|
375
|
+
assert_equal 3, value
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
# In SQL Server the `AVG()` function for a list of integers returns an integer so need to cast values as decimals before averaging.
|
|
379
|
+
# Match SQL Server limit implementation.
|
|
380
|
+
coerce_tests! :test_select_avg_with_group_by_as_virtual_attribute_with_sql
|
|
381
|
+
def test_select_avg_with_group_by_as_virtual_attribute_with_sql_coerced
|
|
382
|
+
rails_core = companies(:rails_core)
|
|
383
|
+
|
|
384
|
+
sql = <<~SQL
|
|
385
|
+
SELECT firm_id, AVG(CAST(credit_limit AS DECIMAL)) AS avg_credit_limit
|
|
386
|
+
FROM accounts
|
|
387
|
+
WHERE firm_id = ?
|
|
388
|
+
GROUP BY firm_id
|
|
389
|
+
ORDER BY firm_id
|
|
390
|
+
OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY
|
|
391
|
+
SQL
|
|
392
|
+
|
|
393
|
+
account = Account.find_by_sql([sql, rails_core]).first
|
|
394
|
+
|
|
395
|
+
# id was not selected, so it should be nil
|
|
396
|
+
# (cannot select id because it wasn't used in the GROUP BY clause)
|
|
397
|
+
assert_nil account.id
|
|
398
|
+
|
|
399
|
+
# firm_id was explicitly selected, so it should be present
|
|
400
|
+
assert_equal(rails_core, account.firm)
|
|
401
|
+
|
|
402
|
+
# avg_credit_limit should be present as a virtual attribute
|
|
403
|
+
assert_equal(52.5, account.avg_credit_limit)
|
|
404
|
+
end
|
|
405
|
+
|
|
406
|
+
# In SQL Server the `AVG()` function for a list of integers returns an integer so need to cast values as decimals before averaging.
|
|
407
|
+
# Order column must be in the GROUP clause.
|
|
408
|
+
coerce_tests! :test_select_avg_with_group_by_as_virtual_attribute_with_ar
|
|
409
|
+
def test_select_avg_with_group_by_as_virtual_attribute_with_ar_coerced
|
|
410
|
+
rails_core = companies(:rails_core)
|
|
411
|
+
|
|
412
|
+
account = Account
|
|
413
|
+
.select(:firm_id, "AVG(CAST(credit_limit AS DECIMAL)) AS avg_credit_limit")
|
|
414
|
+
.where(firm: rails_core)
|
|
415
|
+
.group(:firm_id)
|
|
416
|
+
.order(:firm_id)
|
|
417
|
+
.take!
|
|
418
|
+
|
|
419
|
+
# id was not selected, so it should be nil
|
|
420
|
+
# (cannot select id because it wasn't used in the GROUP BY clause)
|
|
421
|
+
assert_nil account.id
|
|
422
|
+
|
|
423
|
+
# firm_id was explicitly selected, so it should be present
|
|
424
|
+
assert_equal(rails_core, account.firm)
|
|
425
|
+
|
|
426
|
+
# avg_credit_limit should be present as a virtual attribute
|
|
427
|
+
assert_equal(52.5, account.avg_credit_limit)
|
|
428
|
+
end
|
|
429
|
+
|
|
430
|
+
# In SQL Server the `AVG()` function for a list of integers returns an integer so need to cast values as decimals before averaging.
|
|
431
|
+
# SELECT columns must be in the GROUP clause.
|
|
432
|
+
# Match SQL Server limit implementation.
|
|
433
|
+
coerce_tests! :test_select_avg_with_joins_and_group_by_as_virtual_attribute_with_sql
|
|
434
|
+
def test_select_avg_with_joins_and_group_by_as_virtual_attribute_with_sql_coerced
|
|
435
|
+
rails_core = companies(:rails_core)
|
|
436
|
+
|
|
437
|
+
sql = <<~SQL
|
|
438
|
+
SELECT companies.*, AVG(CAST(accounts.credit_limit AS DECIMAL)) AS avg_credit_limit
|
|
439
|
+
FROM companies
|
|
440
|
+
INNER JOIN accounts ON companies.id = accounts.firm_id
|
|
441
|
+
WHERE companies.id = ?
|
|
442
|
+
GROUP BY companies.id, companies.type, companies.firm_id, companies.firm_name, companies.name, companies.client_of, companies.rating, companies.account_id, companies.description
|
|
443
|
+
ORDER BY companies.id
|
|
444
|
+
OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY
|
|
445
|
+
SQL
|
|
446
|
+
|
|
447
|
+
firm = DependentFirm.find_by_sql([sql, rails_core]).first
|
|
448
|
+
|
|
449
|
+
# all the DependentFirm attributes should be present
|
|
450
|
+
assert_equal rails_core, firm
|
|
451
|
+
assert_equal rails_core.name, firm.name
|
|
452
|
+
|
|
453
|
+
# avg_credit_limit should be present as a virtual attribute
|
|
454
|
+
assert_equal(52.5, firm.avg_credit_limit)
|
|
455
|
+
end
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
# In SQL Server the `AVG()` function for a list of integers returns an integer so need to cast values as decimals before averaging.
|
|
459
|
+
# SELECT columns must be in the GROUP clause.
|
|
460
|
+
coerce_tests! :test_select_avg_with_joins_and_group_by_as_virtual_attribute_with_ar
|
|
461
|
+
def test_select_avg_with_joins_and_group_by_as_virtual_attribute_with_ar_coerced
|
|
462
|
+
rails_core = companies(:rails_core)
|
|
463
|
+
|
|
464
|
+
firm = DependentFirm
|
|
465
|
+
.select("companies.*", "AVG(CAST(accounts.credit_limit AS DECIMAL)) AS avg_credit_limit")
|
|
466
|
+
.where(id: rails_core)
|
|
467
|
+
.joins(:account)
|
|
468
|
+
.group(:id, :type, :firm_id, :firm_name, :name, :client_of, :rating, :account_id, :description)
|
|
469
|
+
.take!
|
|
470
|
+
|
|
471
|
+
# all the DependentFirm attributes should be present
|
|
472
|
+
assert_equal rails_core, firm
|
|
473
|
+
assert_equal rails_core.name, firm.name
|
|
474
|
+
|
|
475
|
+
# avg_credit_limit should be present as a virtual attribute
|
|
476
|
+
assert_equal(52.5, firm.avg_credit_limit)
|
|
290
477
|
end
|
|
291
478
|
|
|
292
479
|
# Match SQL Server limit implementation
|
|
@@ -317,9 +504,6 @@ class CalculationsTest < ActiveRecord::TestCase
|
|
|
317
504
|
coerce_tests! :test_having_with_strong_parameters
|
|
318
505
|
end
|
|
319
506
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
507
|
module ActiveRecord
|
|
324
508
|
class Migration
|
|
325
509
|
class ChangeSchemaTest < ActiveRecord::TestCase
|
|
@@ -351,9 +535,6 @@ module ActiveRecord
|
|
|
351
535
|
end
|
|
352
536
|
end
|
|
353
537
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
538
|
module ActiveRecord
|
|
358
539
|
module ConnectionAdapters
|
|
359
540
|
class QuoteARBaseTest < ActiveRecord::TestCase
|
|
@@ -361,22 +542,23 @@ module ActiveRecord
|
|
|
361
542
|
coerce_tests! :test_quote_ar_object
|
|
362
543
|
def test_quote_ar_object_coerced
|
|
363
544
|
value = DatetimePrimaryKey.new(id: @time)
|
|
364
|
-
|
|
545
|
+
assert_deprecated do
|
|
546
|
+
assert_equal "'02-14-2017 12:34:56.79'", @connection.quote(value)
|
|
547
|
+
end
|
|
365
548
|
end
|
|
366
549
|
|
|
367
550
|
# Use our date format.
|
|
368
551
|
coerce_tests! :test_type_cast_ar_object
|
|
369
552
|
def test_type_cast_ar_object_coerced
|
|
370
553
|
value = DatetimePrimaryKey.new(id: @time)
|
|
371
|
-
|
|
554
|
+
assert_deprecated do
|
|
555
|
+
assert_equal "02-14-2017 12:34:56.79", @connection.type_cast(value)
|
|
556
|
+
end
|
|
372
557
|
end
|
|
373
558
|
end
|
|
374
559
|
end
|
|
375
560
|
end
|
|
376
561
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
562
|
module ActiveRecord
|
|
381
563
|
class Migration
|
|
382
564
|
class ColumnAttributesTest < ActiveRecord::TestCase
|
|
@@ -391,16 +573,13 @@ module ActiveRecord
|
|
|
391
573
|
end
|
|
392
574
|
end
|
|
393
575
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
576
|
module ActiveRecord
|
|
398
577
|
class Migration
|
|
399
578
|
class ColumnsTest < ActiveRecord::TestCase
|
|
400
579
|
# Our defaults are real 70000 integers vs '70000' strings.
|
|
401
580
|
coerce_tests! :test_rename_column_preserves_default_value_not_null
|
|
402
581
|
def test_rename_column_preserves_default_value_not_null_coerced
|
|
403
|
-
add_column
|
|
582
|
+
add_column "test_models", "salary", :integer, :default => 70000
|
|
404
583
|
default_before = connection.columns("test_models").find { |c| c.name == "salary" }.default
|
|
405
584
|
assert_equal 70000, default_before
|
|
406
585
|
rename_column "test_models", "salary", "annual_salary"
|
|
@@ -416,9 +595,9 @@ module ActiveRecord
|
|
|
416
595
|
add_column "test_models", :hat_size, :integer
|
|
417
596
|
add_column "test_models", :hat_style, :string, :limit => 100
|
|
418
597
|
add_index "test_models", ["hat_style", "hat_size"], :unique => true
|
|
419
|
-
assert_equal 1, connection.indexes(
|
|
598
|
+
assert_equal 1, connection.indexes("test_models").size
|
|
420
599
|
remove_column("test_models", "hat_size")
|
|
421
|
-
assert_equal [], connection.indexes(
|
|
600
|
+
assert_equal [], connection.indexes("test_models").map(&:name)
|
|
422
601
|
end
|
|
423
602
|
|
|
424
603
|
# Choose `StatementInvalid` vs `ActiveRecordError`.
|
|
@@ -433,51 +612,12 @@ module ActiveRecord
|
|
|
433
612
|
end
|
|
434
613
|
end
|
|
435
614
|
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
615
|
class MigrationTest < ActiveRecord::TestCase
|
|
440
|
-
# We do not have do the DecimalWithoutScale type.
|
|
441
|
-
coerce_tests! :test_add_table_with_decimals
|
|
442
|
-
def test_add_table_with_decimals_coerced
|
|
443
|
-
Person.connection.drop_table :big_numbers rescue nil
|
|
444
|
-
assert !BigNumber.table_exists?
|
|
445
|
-
GiveMeBigNumbers.up
|
|
446
|
-
BigNumber.reset_column_information
|
|
447
|
-
assert BigNumber.create(
|
|
448
|
-
:bank_balance => 1586.43,
|
|
449
|
-
:big_bank_balance => BigDecimal("1000234000567.95"),
|
|
450
|
-
:world_population => 6000000000,
|
|
451
|
-
:my_house_population => 3,
|
|
452
|
-
:value_of_e => BigDecimal("2.7182818284590452353602875")
|
|
453
|
-
)
|
|
454
|
-
b = BigNumber.first
|
|
455
|
-
assert_not_nil b
|
|
456
|
-
assert_not_nil b.bank_balance
|
|
457
|
-
assert_not_nil b.big_bank_balance
|
|
458
|
-
assert_not_nil b.world_population
|
|
459
|
-
assert_not_nil b.my_house_population
|
|
460
|
-
assert_not_nil b.value_of_e
|
|
461
|
-
assert_kind_of BigDecimal, b.world_population
|
|
462
|
-
assert_equal '6000000000.0', b.world_population.to_s
|
|
463
|
-
assert_kind_of Integer, b.my_house_population
|
|
464
|
-
assert_equal 3, b.my_house_population
|
|
465
|
-
assert_kind_of BigDecimal, b.bank_balance
|
|
466
|
-
assert_equal BigDecimal("1586.43"), b.bank_balance
|
|
467
|
-
assert_kind_of BigDecimal, b.big_bank_balance
|
|
468
|
-
assert_equal BigDecimal("1000234000567.95"), b.big_bank_balance
|
|
469
|
-
GiveMeBigNumbers.down
|
|
470
|
-
assert_raise(ActiveRecord::StatementInvalid) { BigNumber.first }
|
|
471
|
-
end
|
|
472
|
-
|
|
473
616
|
# For some reason our tests set Rails.@_env which breaks test env switching.
|
|
474
617
|
coerce_tests! :test_internal_metadata_stores_environment_when_other_data_exists
|
|
475
618
|
coerce_tests! :test_internal_metadata_stores_environment
|
|
476
619
|
end
|
|
477
620
|
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
621
|
class CoreTest < ActiveRecord::TestCase
|
|
482
622
|
# I think fixtures are using the wrong time zone and the `:first`
|
|
483
623
|
# `topics`.`bonus_time` attribute of 2005-01-30t15:28:00.00+01:00 is
|
|
@@ -485,9 +625,6 @@ class CoreTest < ActiveRecord::TestCase
|
|
|
485
625
|
coerce_tests! :test_pretty_print_persisted
|
|
486
626
|
end
|
|
487
627
|
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
628
|
module ActiveRecord
|
|
492
629
|
module ConnectionAdapters
|
|
493
630
|
# Just like PostgreSQLAdapter does.
|
|
@@ -501,23 +638,26 @@ module ActiveRecord
|
|
|
501
638
|
end
|
|
502
639
|
end
|
|
503
640
|
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
641
|
module ActiveRecord
|
|
508
642
|
# The original module is hardcoded for PostgreSQL/SQLite/MySQL tests.
|
|
509
643
|
module DatabaseTasksSetupper
|
|
510
644
|
def setup
|
|
511
645
|
@sqlserver_tasks =
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
646
|
+
Class.new do
|
|
647
|
+
def create; end
|
|
648
|
+
|
|
649
|
+
def drop; end
|
|
650
|
+
|
|
651
|
+
def purge; end
|
|
652
|
+
|
|
653
|
+
def charset; end
|
|
654
|
+
|
|
655
|
+
def collation; end
|
|
656
|
+
|
|
657
|
+
def structure_dump(*); end
|
|
658
|
+
|
|
659
|
+
def structure_load(*); end
|
|
660
|
+
end.new
|
|
521
661
|
|
|
522
662
|
$stdout, @original_stdout = StringIO.new, $stdout
|
|
523
663
|
$stderr, @original_stderr = StringIO.new, $stderr
|
|
@@ -580,7 +720,6 @@ module ActiveRecord
|
|
|
580
720
|
end
|
|
581
721
|
end
|
|
582
722
|
end
|
|
583
|
-
|
|
584
723
|
end
|
|
585
724
|
|
|
586
725
|
class DatabaseTasksCollationTest < ActiveRecord::TestCase
|
|
@@ -603,8 +742,8 @@ module ActiveRecord
|
|
|
603
742
|
def test_sqlserver_structure_dump
|
|
604
743
|
with_stubbed_new do
|
|
605
744
|
assert_called_with(
|
|
606
|
-
|
|
607
|
-
|
|
745
|
+
eval("@sqlserver_tasks"), :structure_dump,
|
|
746
|
+
["awesome-file.sql", nil]
|
|
608
747
|
) do
|
|
609
748
|
ActiveRecord::Tasks::DatabaseTasks.structure_dump({ "adapter" => :sqlserver }, "awesome-file.sql")
|
|
610
749
|
end
|
|
@@ -619,9 +758,9 @@ module ActiveRecord
|
|
|
619
758
|
def test_sqlserver_structure_load
|
|
620
759
|
with_stubbed_new do
|
|
621
760
|
assert_called_with(
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
761
|
+
eval("@sqlserver_tasks"),
|
|
762
|
+
:structure_load,
|
|
763
|
+
["awesome-file.sql", nil]
|
|
625
764
|
) do
|
|
626
765
|
ActiveRecord::Tasks::DatabaseTasks.structure_load({ "adapter" => :sqlserver }, "awesome-file.sql")
|
|
627
766
|
end
|
|
@@ -629,11 +768,6 @@ module ActiveRecord
|
|
|
629
768
|
end
|
|
630
769
|
end
|
|
631
770
|
|
|
632
|
-
class DatabaseTasksDumpSchemaCacheTest < ActiveRecord::TestCase
|
|
633
|
-
# Skip this test with /tmp/my_schema_cache.yml path on Windows.
|
|
634
|
-
coerce_tests! :test_dump_schema_cache if RbConfig::CONFIG['host_os'] =~ /mswin|mingw/
|
|
635
|
-
end
|
|
636
|
-
|
|
637
771
|
class DatabaseTasksCreateAllTest < ActiveRecord::TestCase
|
|
638
772
|
# We extend `local_database?` so that common VM IPs can be used.
|
|
639
773
|
coerce_tests! :test_ignores_remote_databases, :test_warning_for_remote_databases
|
|
@@ -645,9 +779,6 @@ module ActiveRecord
|
|
|
645
779
|
end
|
|
646
780
|
end
|
|
647
781
|
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
782
|
class DefaultScopingTest < ActiveRecord::TestCase
|
|
652
783
|
# We are not doing order duplicate removal anymore.
|
|
653
784
|
coerce_tests! :test_order_in_default_scope_should_not_prevail
|
|
@@ -661,16 +792,13 @@ class DefaultScopingTest < ActiveRecord::TestCase
|
|
|
661
792
|
end
|
|
662
793
|
end
|
|
663
794
|
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
require 'models/post'
|
|
668
|
-
require 'models/subscriber'
|
|
795
|
+
require "models/post"
|
|
796
|
+
require "models/subscriber"
|
|
669
797
|
class EachTest < ActiveRecord::TestCase
|
|
670
798
|
# Quoting in tests does not cope with bracket quoting.
|
|
671
799
|
coerce_tests! :test_find_in_batches_should_quote_batch_order
|
|
672
800
|
def test_find_in_batches_should_quote_batch_order_coerced
|
|
673
|
-
|
|
801
|
+
Post.connection
|
|
674
802
|
assert_sql(/ORDER BY \[posts\]\.\[id\]/) do
|
|
675
803
|
Post.find_in_batches(:batch_size => 1) do |batch|
|
|
676
804
|
assert_kind_of Array, batch
|
|
@@ -682,7 +810,7 @@ class EachTest < ActiveRecord::TestCase
|
|
|
682
810
|
# Quoting in tests does not cope with bracket quoting.
|
|
683
811
|
coerce_tests! :test_in_batches_should_quote_batch_order
|
|
684
812
|
def test_in_batches_should_quote_batch_order_coerced
|
|
685
|
-
|
|
813
|
+
Post.connection
|
|
686
814
|
assert_sql(/ORDER BY \[posts\]\.\[id\]/) do
|
|
687
815
|
Post.in_batches(of: 1) do |relation|
|
|
688
816
|
assert_kind_of ActiveRecord::Relation, relation
|
|
@@ -692,9 +820,6 @@ class EachTest < ActiveRecord::TestCase
|
|
|
692
820
|
end
|
|
693
821
|
end
|
|
694
822
|
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
823
|
class EagerAssociationTest < ActiveRecord::TestCase
|
|
699
824
|
# Use LEN() vs length() function.
|
|
700
825
|
coerce_tests! :test_count_with_include
|
|
@@ -706,11 +831,12 @@ class EagerAssociationTest < ActiveRecord::TestCase
|
|
|
706
831
|
coerce_tests! %r{including association based on sql condition and no database column}
|
|
707
832
|
end
|
|
708
833
|
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
require 'models/topic'
|
|
834
|
+
require "models/topic"
|
|
835
|
+
require "models/customer"
|
|
836
|
+
require "models/non_primary_key"
|
|
713
837
|
class FinderTest < ActiveRecord::TestCase
|
|
838
|
+
fixtures :customers, :topics, :authors
|
|
839
|
+
|
|
714
840
|
# We have implicit ordering, via FETCH.
|
|
715
841
|
coerce_tests! %r{doesn't have implicit ordering},
|
|
716
842
|
:test_find_doesnt_have_implicit_ordering
|
|
@@ -737,7 +863,7 @@ class FinderTest < ActiveRecord::TestCase
|
|
|
737
863
|
# Can not use array condition due to not finding right type and hence fractional second quoting.
|
|
738
864
|
coerce_tests! :test_condition_utc_time_interpolation_with_default_timezone_local
|
|
739
865
|
def test_condition_utc_time_interpolation_with_default_timezone_local_coerced
|
|
740
|
-
with_env_tz
|
|
866
|
+
with_env_tz "America/New_York" do
|
|
741
867
|
with_timezone_config default: :local do
|
|
742
868
|
topic = Topic.first
|
|
743
869
|
assert_equal topic, Topic.where(written_on: topic.written_on.getutc).first
|
|
@@ -748,17 +874,95 @@ class FinderTest < ActiveRecord::TestCase
|
|
|
748
874
|
# Can not use array condition due to not finding right type and hence fractional second quoting.
|
|
749
875
|
coerce_tests! :test_condition_local_time_interpolation_with_default_timezone_utc
|
|
750
876
|
def test_condition_local_time_interpolation_with_default_timezone_utc_coerced
|
|
751
|
-
with_env_tz
|
|
877
|
+
with_env_tz "America/New_York" do
|
|
752
878
|
with_timezone_config default: :utc do
|
|
753
879
|
topic = Topic.first
|
|
754
880
|
assert_equal topic, Topic.where(written_on: topic.written_on.getlocal).first
|
|
755
881
|
end
|
|
756
882
|
end
|
|
757
883
|
end
|
|
758
|
-
end
|
|
759
884
|
|
|
885
|
+
# Check for `FETCH NEXT x ROWS` rather then `LIMIT`.
|
|
886
|
+
coerce_tests! :test_include_on_unloaded_relation_with_match
|
|
887
|
+
def test_include_on_unloaded_relation_with_match_coerced
|
|
888
|
+
assert_sql(/1 AS one.*FETCH NEXT @2 ROWS ONLY.*@2 = 1/) do
|
|
889
|
+
assert_equal true, Customer.where(name: "David").include?(customers(:david))
|
|
890
|
+
end
|
|
891
|
+
end
|
|
892
|
+
|
|
893
|
+
# Check for `FETCH NEXT x ROWS` rather then `LIMIT`.
|
|
894
|
+
coerce_tests! :test_include_on_unloaded_relation_without_match
|
|
895
|
+
def test_include_on_unloaded_relation_without_match_coerced
|
|
896
|
+
assert_sql(/1 AS one.*FETCH NEXT @2 ROWS ONLY.*@2 = 1/) do
|
|
897
|
+
assert_equal false, Customer.where(name: "David").include?(customers(:mary))
|
|
898
|
+
end
|
|
899
|
+
end
|
|
900
|
+
|
|
901
|
+
# Check for `FETCH NEXT x ROWS` rather then `LIMIT`.
|
|
902
|
+
coerce_tests! :test_member_on_unloaded_relation_with_match
|
|
903
|
+
def test_member_on_unloaded_relation_with_match_coerced
|
|
904
|
+
assert_sql(/1 AS one.*FETCH NEXT @2 ROWS ONLY.*@2 = 1/) do
|
|
905
|
+
assert_equal true, Customer.where(name: "David").member?(customers(:david))
|
|
906
|
+
end
|
|
907
|
+
end
|
|
908
|
+
|
|
909
|
+
# Check for `FETCH NEXT x ROWS` rather then `LIMIT`.
|
|
910
|
+
coerce_tests! :test_member_on_unloaded_relation_without_match
|
|
911
|
+
def test_member_on_unloaded_relation_without_match_coerced
|
|
912
|
+
assert_sql(/1 AS one.*FETCH NEXT @2 ROWS ONLY.*@2 = 1/) do
|
|
913
|
+
assert_equal false, Customer.where(name: "David").member?(customers(:mary))
|
|
914
|
+
end
|
|
915
|
+
end
|
|
916
|
+
|
|
917
|
+
# Check for `FETCH NEXT x ROWS` rather then `LIMIT`.
|
|
918
|
+
coerce_tests! :test_implicit_order_column_is_configurable
|
|
919
|
+
def test_implicit_order_column_is_configurable_coerced
|
|
920
|
+
old_implicit_order_column = Topic.implicit_order_column
|
|
921
|
+
Topic.implicit_order_column = "title"
|
|
760
922
|
|
|
923
|
+
assert_equal topics(:fifth), Topic.first
|
|
924
|
+
assert_equal topics(:third), Topic.last
|
|
761
925
|
|
|
926
|
+
c = Topic.connection
|
|
927
|
+
assert_sql(/ORDER BY #{Regexp.escape(c.quote_table_name("topics.title"))} DESC, #{Regexp.escape(c.quote_table_name("topics.id"))} DESC OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY.*@0 = 1/i) {
|
|
928
|
+
Topic.last
|
|
929
|
+
}
|
|
930
|
+
ensure
|
|
931
|
+
Topic.implicit_order_column = old_implicit_order_column
|
|
932
|
+
end
|
|
933
|
+
|
|
934
|
+
# Check for `FETCH NEXT x ROWS` rather then `LIMIT`.
|
|
935
|
+
coerce_tests! :test_implicit_order_set_to_primary_key
|
|
936
|
+
def test_implicit_order_set_to_primary_key_coerced
|
|
937
|
+
old_implicit_order_column = Topic.implicit_order_column
|
|
938
|
+
Topic.implicit_order_column = "id"
|
|
939
|
+
|
|
940
|
+
c = Topic.connection
|
|
941
|
+
assert_sql(/ORDER BY #{Regexp.escape(c.quote_table_name("topics.id"))} DESC OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY.*@0 = 1/i) {
|
|
942
|
+
Topic.last
|
|
943
|
+
}
|
|
944
|
+
ensure
|
|
945
|
+
Topic.implicit_order_column = old_implicit_order_column
|
|
946
|
+
end
|
|
947
|
+
|
|
948
|
+
# Check for `FETCH NEXT x ROWS` rather then `LIMIT`.
|
|
949
|
+
coerce_tests! :test_implicit_order_for_model_without_primary_key
|
|
950
|
+
def test_implicit_order_for_model_without_primary_key_coerced
|
|
951
|
+
old_implicit_order_column = NonPrimaryKey.implicit_order_column
|
|
952
|
+
NonPrimaryKey.implicit_order_column = "created_at"
|
|
953
|
+
|
|
954
|
+
c = NonPrimaryKey.connection
|
|
955
|
+
|
|
956
|
+
assert_sql(/ORDER BY #{Regexp.escape(c.quote_table_name("non_primary_keys.created_at"))} DESC OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY.*@0 = 1/i) {
|
|
957
|
+
NonPrimaryKey.last
|
|
958
|
+
}
|
|
959
|
+
ensure
|
|
960
|
+
NonPrimaryKey.implicit_order_column = old_implicit_order_column
|
|
961
|
+
end
|
|
962
|
+
|
|
963
|
+
# SQL Server is unable to use aliased SELECT in the HAVING clause.
|
|
964
|
+
coerce_tests! :test_include_on_unloaded_relation_with_having_referencing_aliased_select
|
|
965
|
+
end
|
|
762
966
|
|
|
763
967
|
module ActiveRecord
|
|
764
968
|
class Migration
|
|
@@ -777,9 +981,6 @@ module ActiveRecord
|
|
|
777
981
|
end
|
|
778
982
|
end
|
|
779
983
|
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
984
|
class HasOneAssociationsTest < ActiveRecord::TestCase
|
|
784
985
|
# We use OFFSET/FETCH vs TOP. So we always have an order.
|
|
785
986
|
coerce_tests! :test_has_one_does_not_use_order_by
|
|
@@ -796,9 +997,6 @@ class HasOneAssociationsTest < ActiveRecord::TestCase
|
|
|
796
997
|
end
|
|
797
998
|
end
|
|
798
999
|
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
1000
|
class HasOneThroughAssociationsTest < ActiveRecord::TestCase
|
|
803
1001
|
# Asserted SQL to get one row different from original test.
|
|
804
1002
|
coerce_tests! :test_has_one_through_executes_limited_query
|
|
@@ -810,16 +1008,12 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase
|
|
|
810
1008
|
end
|
|
811
1009
|
end
|
|
812
1010
|
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
require 'models/company'
|
|
1011
|
+
require "models/company"
|
|
818
1012
|
class InheritanceTest < ActiveRecord::TestCase
|
|
819
1013
|
# Rails test required inserting to a identity column.
|
|
820
1014
|
coerce_tests! :test_a_bad_type_column
|
|
821
1015
|
def test_a_bad_type_column_coerced
|
|
822
|
-
Company.connection.with_identity_insert_enabled(
|
|
1016
|
+
Company.connection.with_identity_insert_enabled("companies") do
|
|
823
1017
|
Company.connection.insert "INSERT INTO companies (id, #{QUOTED_TYPE}, name) VALUES(100, 'bad_class!', 'Not happening')"
|
|
824
1018
|
end
|
|
825
1019
|
assert_raise(ActiveRecord::SubclassNotFound) { Company.find(100) }
|
|
@@ -828,45 +1022,36 @@ class InheritanceTest < ActiveRecord::TestCase
|
|
|
828
1022
|
# Use Square brackets around column name
|
|
829
1023
|
coerce_tests! :test_eager_load_belongs_to_primary_key_quoting
|
|
830
1024
|
def test_eager_load_belongs_to_primary_key_quoting_coerced
|
|
831
|
-
|
|
1025
|
+
Account.connection
|
|
832
1026
|
assert_sql(/\[companies\]\.\[id\] = @0.* @0 = 1/) do
|
|
833
1027
|
Account.all.merge!(:includes => :firm).find(1)
|
|
834
1028
|
end
|
|
835
1029
|
end
|
|
836
1030
|
end
|
|
837
1031
|
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
1032
|
class LeftOuterJoinAssociationTest < ActiveRecord::TestCase
|
|
842
1033
|
# Uses || operator in SQL. Just trust core gets value out of this test.
|
|
843
1034
|
coerce_tests! :test_does_not_override_select
|
|
844
1035
|
end
|
|
845
1036
|
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
require 'models/developer'
|
|
850
|
-
require 'models/computer'
|
|
1037
|
+
require "models/developer"
|
|
1038
|
+
require "models/computer"
|
|
851
1039
|
class NestedRelationScopingTest < ActiveRecord::TestCase
|
|
852
1040
|
# Assert SQL Server limit implementation
|
|
853
1041
|
coerce_tests! :test_merge_options
|
|
854
1042
|
def test_merge_options_coerced
|
|
855
|
-
Developer.where(
|
|
1043
|
+
Developer.where("salary = 80000").scoping do
|
|
856
1044
|
Developer.limit(10).scoping do
|
|
857
1045
|
devs = Developer.all
|
|
858
1046
|
sql = devs.to_sql
|
|
859
|
-
assert_match
|
|
860
|
-
assert_match
|
|
1047
|
+
assert_match "(salary = 80000)", sql
|
|
1048
|
+
assert_match "FETCH NEXT 10 ROWS ONLY", sql
|
|
861
1049
|
end
|
|
862
1050
|
end
|
|
863
1051
|
end
|
|
864
1052
|
end
|
|
865
1053
|
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
require 'models/topic'
|
|
1054
|
+
require "models/topic"
|
|
870
1055
|
class PersistenceTest < ActiveRecord::TestCase
|
|
871
1056
|
# Rails test required updating a identity column.
|
|
872
1057
|
coerce_tests! :test_update_columns_changing_id
|
|
@@ -890,10 +1075,7 @@ class PersistenceTest < ActiveRecord::TestCase
|
|
|
890
1075
|
end
|
|
891
1076
|
end
|
|
892
1077
|
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
require 'models/author'
|
|
1078
|
+
require "models/author"
|
|
897
1079
|
class UpdateAllTest < ActiveRecord::TestCase
|
|
898
1080
|
# Rails test required updating a identity column.
|
|
899
1081
|
coerce_tests! :test_update_all_doesnt_ignore_order
|
|
@@ -903,17 +1085,14 @@ class UpdateAllTest < ActiveRecord::TestCase
|
|
|
903
1085
|
_(mary.id).must_equal 2
|
|
904
1086
|
_(david.name).wont_equal mary.name
|
|
905
1087
|
assert_sql(/UPDATE.*\(SELECT \[authors\].\[id\] FROM \[authors\].*ORDER BY \[authors\].\[id\]/i) do
|
|
906
|
-
Author.where(
|
|
1088
|
+
Author.where("[id] > 1").order(:id).update_all(name: "Test")
|
|
907
1089
|
end
|
|
908
|
-
_(david.reload.name).must_equal
|
|
909
|
-
_(mary.reload.name).must_equal
|
|
1090
|
+
_(david.reload.name).must_equal "David"
|
|
1091
|
+
_(mary.reload.name).must_equal "Test"
|
|
910
1092
|
end
|
|
911
1093
|
end
|
|
912
1094
|
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
require 'models/topic'
|
|
1095
|
+
require "models/topic"
|
|
917
1096
|
module ActiveRecord
|
|
918
1097
|
class PredicateBuilderTest < ActiveRecord::TestCase
|
|
919
1098
|
# Same as original test except string has `N` prefix to indicate unicode string.
|
|
@@ -930,9 +1109,6 @@ module ActiveRecord
|
|
|
930
1109
|
end
|
|
931
1110
|
end
|
|
932
1111
|
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
1112
|
class PrimaryKeysTest < ActiveRecord::TestCase
|
|
937
1113
|
# SQL Server does not have query for release_savepoint
|
|
938
1114
|
coerce_tests! :test_create_without_primary_key_no_extra_query
|
|
@@ -945,10 +1121,7 @@ class PrimaryKeysTest < ActiveRecord::TestCase
|
|
|
945
1121
|
end
|
|
946
1122
|
end
|
|
947
1123
|
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
require 'models/task'
|
|
1124
|
+
require "models/task"
|
|
952
1125
|
class QueryCacheTest < ActiveRecord::TestCase
|
|
953
1126
|
# SQL Server adapter not in list of supported adapters in original test.
|
|
954
1127
|
coerce_tests! :test_cache_does_not_wrap_results_in_arrays
|
|
@@ -980,15 +1153,12 @@ class QueryCacheTest < ActiveRecord::TestCase
|
|
|
980
1153
|
Task.find(1)
|
|
981
1154
|
end
|
|
982
1155
|
|
|
983
|
-
assert_includes ActiveRecord::SQLCounter.log_all.first
|
|
1156
|
+
assert_includes ActiveRecord::SQLCounter.log_all.first, "TC.CONSTRAINT_TYPE = N''PRIMARY KEY''"
|
|
984
1157
|
end
|
|
985
1158
|
end
|
|
986
1159
|
end
|
|
987
1160
|
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
require 'models/post'
|
|
1161
|
+
require "models/post"
|
|
992
1162
|
class RelationTest < ActiveRecord::TestCase
|
|
993
1163
|
# Use LEN vs LENGTH function.
|
|
994
1164
|
coerce_tests! :test_reverse_order_with_function
|
|
@@ -1023,13 +1193,19 @@ class RelationTest < ActiveRecord::TestCase
|
|
|
1023
1193
|
coerce_tests! :test_reorder_with_first
|
|
1024
1194
|
def test_reorder_with_first_coerced
|
|
1025
1195
|
sql_log = capture_sql do
|
|
1026
|
-
|
|
1196
|
+
message = <<~MSG.squish
|
|
1197
|
+
`.reorder(nil)` with `.first` / `.first!` no longer
|
|
1198
|
+
takes non-deterministic result in Rails 6.2.
|
|
1199
|
+
To continue taking non-deterministic result, use `.take` / `.take!` instead.
|
|
1200
|
+
MSG
|
|
1201
|
+
assert_deprecated(message) do
|
|
1202
|
+
assert Post.order(:title).reorder(nil).first
|
|
1203
|
+
end
|
|
1027
1204
|
end
|
|
1028
1205
|
assert sql_log.none? { |sql| /order by [posts].[title]/i.match?(sql) }, "ORDER BY title was used in the query: #{sql_log}"
|
|
1029
1206
|
assert sql_log.all? { |sql| /order by \[posts\]\.\[id\]/i.match?(sql) }, "default ORDER BY ID was not used in the query: #{sql_log}"
|
|
1030
1207
|
end
|
|
1031
1208
|
|
|
1032
|
-
|
|
1033
1209
|
# We are not doing order duplicate removal anymore.
|
|
1034
1210
|
coerce_tests! :test_order_using_scoping
|
|
1035
1211
|
|
|
@@ -1055,7 +1231,7 @@ class RelationTest < ActiveRecord::TestCase
|
|
|
1055
1231
|
|
|
1056
1232
|
# Can't apply offset without ORDER
|
|
1057
1233
|
coerce_tests! %r{using a custom table affects the wheres}
|
|
1058
|
-
test
|
|
1234
|
+
test "using a custom table affects the wheres coerced" do
|
|
1059
1235
|
post = posts(:welcome)
|
|
1060
1236
|
|
|
1061
1237
|
assert_equal post, custom_post_relation.where!(title: post.title).order(:id).take
|
|
@@ -1063,7 +1239,7 @@ class RelationTest < ActiveRecord::TestCase
|
|
|
1063
1239
|
|
|
1064
1240
|
# Can't apply offset without ORDER
|
|
1065
1241
|
coerce_tests! %r{using a custom table with joins affects the joins}
|
|
1066
|
-
test
|
|
1242
|
+
test "using a custom table with joins affects the joins coerced" do
|
|
1067
1243
|
post = posts(:welcome)
|
|
1068
1244
|
|
|
1069
1245
|
assert_equal post, custom_post_relation.joins(:author).where!(title: post.title).order(:id).take
|
|
@@ -1077,10 +1253,32 @@ class RelationTest < ActiveRecord::TestCase
|
|
|
1077
1253
|
end
|
|
1078
1254
|
end
|
|
1079
1255
|
|
|
1256
|
+
module ActiveRecord
|
|
1257
|
+
class RelationTest < ActiveRecord::TestCase
|
|
1258
|
+
# Skipping this test. SQL Server doesn't support optimizer hint as comments
|
|
1259
|
+
coerce_tests! :test_relation_with_optimizer_hints_filters_sql_comment_delimiters
|
|
1260
|
+
|
|
1261
|
+
coerce_tests! :test_does_not_duplicate_optimizer_hints_on_merge
|
|
1262
|
+
def test_does_not_duplicate_optimizer_hints_on_merge_coerced
|
|
1263
|
+
escaped_table = Post.connection.quote_table_name("posts")
|
|
1264
|
+
expected = "SELECT #{escaped_table}.* FROM #{escaped_table} OPTION (OMGHINT)"
|
|
1265
|
+
query = Post.optimizer_hints("OMGHINT").merge(Post.optimizer_hints("OMGHINT")).to_sql
|
|
1266
|
+
assert_equal expected, query
|
|
1267
|
+
end
|
|
1080
1268
|
|
|
1269
|
+
# Original Rails test fails on Windows CI because the dump file was not being binary read.
|
|
1270
|
+
coerce_tests! :test_marshal_load_legacy_relation
|
|
1271
|
+
def test_marshal_load_legacy_relation_coerced
|
|
1272
|
+
path = File.expand_path(
|
|
1273
|
+
"support/marshal_compatibility_fixtures/legacy_relation.dump",
|
|
1274
|
+
ARTest::SQLServer.root_activerecord_test
|
|
1275
|
+
)
|
|
1276
|
+
assert_equal 11, Marshal.load(File.binread(path)).size
|
|
1277
|
+
end
|
|
1278
|
+
end
|
|
1279
|
+
end
|
|
1081
1280
|
|
|
1082
|
-
|
|
1083
|
-
require 'models/post'
|
|
1281
|
+
require "models/post"
|
|
1084
1282
|
class SanitizeTest < ActiveRecord::TestCase
|
|
1085
1283
|
# Use nvarchar string (N'') in assert
|
|
1086
1284
|
coerce_tests! :test_sanitize_sql_like_example_use_case
|
|
@@ -1090,7 +1288,7 @@ class SanitizeTest < ActiveRecord::TestCase
|
|
|
1090
1288
|
where("title LIKE ?", sanitize_sql_like(term, "!"))
|
|
1091
1289
|
end
|
|
1092
1290
|
|
|
1093
|
-
scope :search_as_scope, ->
|
|
1291
|
+
scope :search_as_scope, ->(term) {
|
|
1094
1292
|
where("title LIKE ?", sanitize_sql_like(term, "!"))
|
|
1095
1293
|
}
|
|
1096
1294
|
end
|
|
@@ -1105,9 +1303,6 @@ class SanitizeTest < ActiveRecord::TestCase
|
|
|
1105
1303
|
end
|
|
1106
1304
|
end
|
|
1107
1305
|
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
1306
|
class SchemaDumperTest < ActiveRecord::TestCase
|
|
1112
1307
|
# We have precision to 38.
|
|
1113
1308
|
coerce_tests! :test_schema_dump_keeps_large_precision_integer_columns_as_decimal
|
|
@@ -1134,26 +1329,17 @@ class SchemaDumperTest < ActiveRecord::TestCase
|
|
|
1134
1329
|
end
|
|
1135
1330
|
end
|
|
1136
1331
|
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
1332
|
class SchemaDumperDefaultsTest < ActiveRecord::TestCase
|
|
1141
1333
|
# These date formats do not match ours. We got these covered in our dumper tests.
|
|
1142
1334
|
coerce_tests! :test_schema_dump_defaults_with_universally_supported_types
|
|
1143
1335
|
end
|
|
1144
1336
|
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
1337
|
class TestAdapterWithInvalidConnection < ActiveRecord::TestCase
|
|
1149
1338
|
# We trust Rails on this since we do not want to install mysql.
|
|
1150
1339
|
coerce_tests! %r{inspect on Model class does not raise}
|
|
1151
1340
|
end
|
|
1152
1341
|
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
require 'models/topic'
|
|
1342
|
+
require "models/topic"
|
|
1157
1343
|
class TransactionTest < ActiveRecord::TestCase
|
|
1158
1344
|
# SQL Server does not have query for release_savepoint
|
|
1159
1345
|
coerce_tests! :test_releasing_named_savepoints
|
|
@@ -1167,10 +1353,7 @@ class TransactionTest < ActiveRecord::TestCase
|
|
|
1167
1353
|
end
|
|
1168
1354
|
end
|
|
1169
1355
|
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
require 'models/tag'
|
|
1356
|
+
require "models/tag"
|
|
1174
1357
|
class TransactionIsolationTest < ActiveRecord::TestCase
|
|
1175
1358
|
# SQL Server will lock the table for counts even when both
|
|
1176
1359
|
# connections are `READ COMMITTED`. So we bypass with `READPAST`.
|
|
@@ -1180,7 +1363,7 @@ class TransactionIsolationTest < ActiveRecord::TestCase
|
|
|
1180
1363
|
assert_equal 0, Tag.count
|
|
1181
1364
|
Tag2.transaction do
|
|
1182
1365
|
Tag2.create
|
|
1183
|
-
assert_equal 0, Tag.lock(
|
|
1366
|
+
assert_equal 0, Tag.lock("WITH(READPAST)").count
|
|
1184
1367
|
end
|
|
1185
1368
|
end
|
|
1186
1369
|
assert_equal 1, Tag.count
|
|
@@ -1190,10 +1373,7 @@ class TransactionIsolationTest < ActiveRecord::TestCase
|
|
|
1190
1373
|
coerce_tests! %r{repeatable read}
|
|
1191
1374
|
end
|
|
1192
1375
|
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
require 'models/book'
|
|
1376
|
+
require "models/book"
|
|
1197
1377
|
class ViewWithPrimaryKeyTest < ActiveRecord::TestCase
|
|
1198
1378
|
# We have a few view tables. use includes vs equality.
|
|
1199
1379
|
coerce_tests! :test_views
|
|
@@ -1205,13 +1385,10 @@ class ViewWithPrimaryKeyTest < ActiveRecord::TestCase
|
|
|
1205
1385
|
coerce_tests! :test_does_not_assume_id_column_as_primary_key
|
|
1206
1386
|
def test_does_not_assume_id_column_as_primary_key_coerced
|
|
1207
1387
|
model = Class.new(ActiveRecord::Base) { self.table_name = "ebooks" }
|
|
1208
|
-
assert_equal
|
|
1388
|
+
assert_equal "id", model.primary_key
|
|
1209
1389
|
end
|
|
1210
1390
|
end
|
|
1211
1391
|
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
1392
|
class ViewWithoutPrimaryKeyTest < ActiveRecord::TestCase
|
|
1216
1393
|
# We have a few view tables. use includes vs equality.
|
|
1217
1394
|
coerce_tests! :test_views
|
|
@@ -1220,23 +1397,17 @@ class ViewWithoutPrimaryKeyTest < ActiveRecord::TestCase
|
|
|
1220
1397
|
end
|
|
1221
1398
|
end
|
|
1222
1399
|
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
require 'models/author'
|
|
1400
|
+
require "models/author"
|
|
1227
1401
|
class YamlSerializationTest < ActiveRecord::TestCase
|
|
1228
1402
|
coerce_tests! :test_types_of_virtual_columns_are_not_changed_on_round_trip
|
|
1229
1403
|
def test_types_of_virtual_columns_are_not_changed_on_round_trip_coerced
|
|
1230
|
-
author = Author.select(
|
|
1404
|
+
author = Author.select("authors.*, 5 as posts_count").first
|
|
1231
1405
|
dumped = YAML.load(YAML.dump(author))
|
|
1232
1406
|
assert_equal 5, author.posts_count
|
|
1233
1407
|
assert_equal 5, dumped.posts_count
|
|
1234
1408
|
end
|
|
1235
1409
|
end
|
|
1236
1410
|
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
1411
|
class DateTimePrecisionTest < ActiveRecord::TestCase
|
|
1241
1412
|
# Original test had `7` which we support vs `8` which we use.
|
|
1242
1413
|
coerce_tests! :test_invalid_datetime_precision_raises_error
|
|
@@ -1252,7 +1423,7 @@ class DateTimePrecisionTest < ActiveRecord::TestCase
|
|
|
1252
1423
|
coerce_tests! :test_datetime_precision_is_truncated_on_assignment
|
|
1253
1424
|
def test_datetime_precision_is_truncated_on_assignment_coerced
|
|
1254
1425
|
@connection.create_table(:foos, force: true)
|
|
1255
|
-
@connection.add_column :foos, :created_at,
|
|
1426
|
+
@connection.add_column :foos, :created_at, :datetime, precision: 0
|
|
1256
1427
|
@connection.add_column :foos, :updated_at, :datetime, precision: 6
|
|
1257
1428
|
|
|
1258
1429
|
time = ::Time.now.change(nsec: 123456789)
|
|
@@ -1269,9 +1440,6 @@ class DateTimePrecisionTest < ActiveRecord::TestCase
|
|
|
1269
1440
|
end
|
|
1270
1441
|
end
|
|
1271
1442
|
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
1443
|
class TimePrecisionTest < ActiveRecord::TestCase
|
|
1276
1444
|
# datetime is rounded to increments of .000, .003, or .007 seconds
|
|
1277
1445
|
coerce_tests! :test_time_precision_is_truncated_on_assignment
|
|
@@ -1297,9 +1465,6 @@ class TimePrecisionTest < ActiveRecord::TestCase
|
|
|
1297
1465
|
coerce_tests! :test_no_time_precision_isnt_truncated_on_assignment
|
|
1298
1466
|
end
|
|
1299
1467
|
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
1468
|
class DefaultNumbersTest < ActiveRecord::TestCase
|
|
1304
1469
|
# We do better with native types and do not return strings for everything.
|
|
1305
1470
|
coerce_tests! :test_default_positive_integer
|
|
@@ -1326,9 +1491,6 @@ class DefaultNumbersTest < ActiveRecord::TestCase
|
|
|
1326
1491
|
end
|
|
1327
1492
|
end
|
|
1328
1493
|
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
1494
|
module ActiveRecord
|
|
1333
1495
|
class CollectionCacheKeyTest < ActiveRecord::TestCase
|
|
1334
1496
|
# Will trust rails has this sorted since you cant offset without a limit.
|
|
@@ -1336,9 +1498,6 @@ module ActiveRecord
|
|
|
1336
1498
|
end
|
|
1337
1499
|
end
|
|
1338
1500
|
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
1501
|
module ActiveRecord
|
|
1343
1502
|
class CacheKeyTest < ActiveRecord::TestCase
|
|
1344
1503
|
# Like Mysql2 and PostgreSQL, SQL Server doesn't return a string value for updated_at. In the Rails tests
|
|
@@ -1349,9 +1508,6 @@ module ActiveRecord
|
|
|
1349
1508
|
end
|
|
1350
1509
|
end
|
|
1351
1510
|
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
1511
|
require "models/book"
|
|
1356
1512
|
module ActiveRecord
|
|
1357
1513
|
class StatementCacheTest < ActiveRecord::TestCase
|
|
@@ -1370,41 +1526,74 @@ module ActiveRecord
|
|
|
1370
1526
|
end
|
|
1371
1527
|
end
|
|
1372
1528
|
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
1529
|
module ActiveRecord
|
|
1377
1530
|
module ConnectionAdapters
|
|
1378
1531
|
class SchemaCacheTest < ActiveRecord::TestCase
|
|
1532
|
+
# Tests fail on Windows AppVeyor CI with 'Permission denied' error when renaming file during `File.atomic_write` call.
|
|
1533
|
+
coerce_tests! :test_yaml_dump_and_load, :test_yaml_dump_and_load_with_gzip if RbConfig::CONFIG["host_os"] =~ /mswin|mingw/
|
|
1534
|
+
|
|
1535
|
+
# Ruby 2.5 and 2.6 have issues to marshal Time before 1900. 2012.sql has one column with default value 1753
|
|
1536
|
+
coerce_tests! :test_marshal_dump_and_load_with_gzip, :test_marshal_dump_and_load_via_disk
|
|
1537
|
+
|
|
1538
|
+
# Tests fail on Windows AppVeyor CI with 'Permission denied' error when renaming file during `File.atomic_write` call.
|
|
1539
|
+
unless RbConfig::CONFIG["host_os"] =~ /mswin|mingw/
|
|
1540
|
+
def test_marshal_dump_and_load_with_gzip_coerced
|
|
1541
|
+
with_marshable_time_defaults { original_test_marshal_dump_and_load_with_gzip }
|
|
1542
|
+
end
|
|
1543
|
+
def test_marshal_dump_and_load_via_disk_coerced
|
|
1544
|
+
with_marshable_time_defaults { original_test_marshal_dump_and_load_via_disk }
|
|
1545
|
+
end
|
|
1546
|
+
end
|
|
1547
|
+
|
|
1379
1548
|
private
|
|
1549
|
+
|
|
1550
|
+
def with_marshable_time_defaults
|
|
1551
|
+
# Detect problems
|
|
1552
|
+
if Gem::Version.new(RUBY_VERSION) < Gem::Version.new("2.7")
|
|
1553
|
+
column = @connection.columns(:sst_datatypes).find { |c| c.name == "datetime" }
|
|
1554
|
+
current_default = column.default if column.default.is_a?(Time) && column.default.year < 1900
|
|
1555
|
+
end
|
|
1556
|
+
|
|
1557
|
+
# Correct problems
|
|
1558
|
+
if current_default.present?
|
|
1559
|
+
@connection.change_column_default(:sst_datatypes, :datetime, current_default.dup.change(year: 1900))
|
|
1560
|
+
end
|
|
1561
|
+
|
|
1562
|
+
# Run original test
|
|
1563
|
+
yield
|
|
1564
|
+
ensure
|
|
1565
|
+
# Revert changes
|
|
1566
|
+
@connection.change_column_default(:sst_datatypes, :datetime, current_default) if current_default.present?
|
|
1567
|
+
end
|
|
1568
|
+
|
|
1380
1569
|
# We need to give the full path for this to work.
|
|
1381
1570
|
def schema_dump_path
|
|
1382
|
-
File.join ARTest::SQLServer.root_activerecord,
|
|
1571
|
+
File.join ARTest::SQLServer.root_activerecord, "test/assets/schema_dump_5_1.yml"
|
|
1383
1572
|
end
|
|
1384
1573
|
end
|
|
1385
1574
|
end
|
|
1386
1575
|
end
|
|
1387
1576
|
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1577
|
+
require "models/post"
|
|
1578
|
+
require "models/comment"
|
|
1391
1579
|
class UnsafeRawSqlTest < ActiveRecord::TestCase
|
|
1392
|
-
|
|
1580
|
+
fixtures :posts
|
|
1581
|
+
|
|
1582
|
+
# Use LEN() vs length() function.
|
|
1393
1583
|
coerce_tests! %r{order: always allows Arel}
|
|
1394
|
-
test
|
|
1395
|
-
|
|
1396
|
-
ids_disabled = with_unsafe_raw_sql_disabled { Post.order(Arel.sql("len(title)")).pluck(:title) }
|
|
1584
|
+
test "order: always allows Arel" do
|
|
1585
|
+
titles = Post.order(Arel.sql("len(title)")).pluck(:title)
|
|
1397
1586
|
|
|
1398
|
-
|
|
1587
|
+
assert_not_empty titles
|
|
1399
1588
|
end
|
|
1400
1589
|
|
|
1401
1590
|
# Use LEN() vs length() function.
|
|
1402
1591
|
coerce_tests! %r{pluck: always allows Arel}
|
|
1403
1592
|
test "pluck: always allows Arel" do
|
|
1404
|
-
|
|
1405
|
-
|
|
1593
|
+
excepted_values = Post.includes(:comments).pluck(:title).map { |title| [title, title.size] }
|
|
1594
|
+
values = Post.includes(:comments).pluck(:title, Arel.sql("len(title)"))
|
|
1406
1595
|
|
|
1407
|
-
assert_equal
|
|
1596
|
+
assert_equal excepted_values, values
|
|
1408
1597
|
end
|
|
1409
1598
|
|
|
1410
1599
|
# Use LEN() vs length() function.
|
|
@@ -1412,16 +1601,75 @@ class UnsafeRawSqlTest < ActiveRecord::TestCase
|
|
|
1412
1601
|
test "order: allows valid Array arguments" do
|
|
1413
1602
|
ids_expected = Post.order(Arel.sql("author_id, len(title)")).pluck(:id)
|
|
1414
1603
|
|
|
1415
|
-
|
|
1416
|
-
ids_disabled = with_unsafe_raw_sql_disabled { Post.order(["author_id", "len(title)"]).pluck(:id) }
|
|
1604
|
+
ids = Post.order(["author_id", "len(title)"]).pluck(:id)
|
|
1417
1605
|
|
|
1418
|
-
assert_equal ids_expected,
|
|
1419
|
-
assert_equal ids_expected, ids_disabled
|
|
1606
|
+
assert_equal ids_expected, ids
|
|
1420
1607
|
end
|
|
1421
|
-
end
|
|
1422
1608
|
|
|
1609
|
+
test "order: allows string column names that are quoted" do
|
|
1610
|
+
ids_expected = Post.order(Arel.sql("id")).pluck(:id)
|
|
1611
|
+
|
|
1612
|
+
ids = Post.order("[id]").pluck(:id)
|
|
1613
|
+
|
|
1614
|
+
assert_equal ids_expected, ids
|
|
1615
|
+
end
|
|
1616
|
+
|
|
1617
|
+
test "order: allows string column names that are quoted with table" do
|
|
1618
|
+
ids_expected = Post.order(Arel.sql("id")).pluck(:id)
|
|
1619
|
+
|
|
1620
|
+
ids = Post.order("[posts].[id]").pluck(:id)
|
|
1621
|
+
|
|
1622
|
+
assert_equal ids_expected, ids
|
|
1623
|
+
end
|
|
1624
|
+
|
|
1625
|
+
test "order: allows string column names that are quoted with table and user" do
|
|
1626
|
+
ids_expected = Post.order(Arel.sql("id")).pluck(:id)
|
|
1627
|
+
|
|
1628
|
+
ids = Post.order("[dbo].[posts].[id]").pluck(:id)
|
|
1629
|
+
|
|
1630
|
+
assert_equal ids_expected, ids
|
|
1631
|
+
end
|
|
1632
|
+
|
|
1633
|
+
test "order: allows string column names that are quoted with table, user and database" do
|
|
1634
|
+
ids_expected = Post.order(Arel.sql("id")).pluck(:id)
|
|
1635
|
+
|
|
1636
|
+
ids = Post.order("[activerecord_unittest].[dbo].[posts].[id]").pluck(:id)
|
|
1637
|
+
|
|
1638
|
+
assert_equal ids_expected, ids
|
|
1639
|
+
end
|
|
1640
|
+
|
|
1641
|
+
test "pluck: allows string column name that are quoted" do
|
|
1642
|
+
titles_expected = Post.pluck(Arel.sql("title"))
|
|
1643
|
+
|
|
1644
|
+
titles = Post.pluck("[title]")
|
|
1645
|
+
|
|
1646
|
+
assert_equal titles_expected, titles
|
|
1647
|
+
end
|
|
1423
1648
|
|
|
1649
|
+
test "pluck: allows string column name that are quoted with table" do
|
|
1650
|
+
titles_expected = Post.pluck(Arel.sql("title"))
|
|
1424
1651
|
|
|
1652
|
+
titles = Post.pluck("[posts].[title]")
|
|
1653
|
+
|
|
1654
|
+
assert_equal titles_expected, titles
|
|
1655
|
+
end
|
|
1656
|
+
|
|
1657
|
+
test "pluck: allows string column name that are quoted with table and user" do
|
|
1658
|
+
titles_expected = Post.pluck(Arel.sql("title"))
|
|
1659
|
+
|
|
1660
|
+
titles = Post.pluck("[dbo].[posts].[title]")
|
|
1661
|
+
|
|
1662
|
+
assert_equal titles_expected, titles
|
|
1663
|
+
end
|
|
1664
|
+
|
|
1665
|
+
test "pluck: allows string column name that are quoted with table, user and database" do
|
|
1666
|
+
titles_expected = Post.pluck(Arel.sql("title"))
|
|
1667
|
+
|
|
1668
|
+
titles = Post.pluck("[activerecord_unittest].[dbo].[posts].[title]")
|
|
1669
|
+
|
|
1670
|
+
assert_equal titles_expected, titles
|
|
1671
|
+
end
|
|
1672
|
+
end
|
|
1425
1673
|
|
|
1426
1674
|
class ReservedWordTest < ActiveRecord::TestCase
|
|
1427
1675
|
coerce_tests! :test_change_columns
|
|
@@ -1433,33 +1681,27 @@ class ReservedWordTest < ActiveRecord::TestCase
|
|
|
1433
1681
|
end
|
|
1434
1682
|
end
|
|
1435
1683
|
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
1684
|
class OptimisticLockingTest < ActiveRecord::TestCase
|
|
1440
1685
|
# We do not allow updating identities, but we can test using a non-identity key
|
|
1441
1686
|
coerce_tests! :test_update_with_dirty_primary_key
|
|
1442
1687
|
def test_update_with_dirty_primary_key_coerced
|
|
1443
1688
|
assert_raises(ActiveRecord::RecordNotUnique) do
|
|
1444
|
-
record = StringKeyObject.find(
|
|
1445
|
-
record.id =
|
|
1689
|
+
record = StringKeyObject.find("record1")
|
|
1690
|
+
record.id = "record2"
|
|
1446
1691
|
record.save!
|
|
1447
1692
|
end
|
|
1448
1693
|
|
|
1449
|
-
record = StringKeyObject.find(
|
|
1450
|
-
record.id =
|
|
1694
|
+
record = StringKeyObject.find("record1")
|
|
1695
|
+
record.id = "record42"
|
|
1451
1696
|
record.save!
|
|
1452
1697
|
|
|
1453
|
-
assert StringKeyObject.find(
|
|
1698
|
+
assert StringKeyObject.find("record42")
|
|
1454
1699
|
assert_raises(ActiveRecord::RecordNotFound) do
|
|
1455
|
-
StringKeyObject.find(
|
|
1700
|
+
StringKeyObject.find("record1")
|
|
1456
1701
|
end
|
|
1457
1702
|
end
|
|
1458
1703
|
end
|
|
1459
1704
|
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
1705
|
class RelationMergingTest < ActiveRecord::TestCase
|
|
1464
1706
|
# Use nvarchar string (N'') in assert
|
|
1465
1707
|
coerce_tests! :test_merging_with_order_with_binds
|
|
@@ -1467,10 +1709,26 @@ class RelationMergingTest < ActiveRecord::TestCase
|
|
|
1467
1709
|
relation = Post.all.merge(Post.order([Arel.sql("title LIKE ?"), "%suffix"]))
|
|
1468
1710
|
assert_equal ["title LIKE N'%suffix'"], relation.order_values
|
|
1469
1711
|
end
|
|
1470
|
-
end
|
|
1471
1712
|
|
|
1713
|
+
# Same as original but change first regexp to match sp_executesql binding syntax
|
|
1714
|
+
coerce_tests! :test_merge_doesnt_duplicate_same_clauses
|
|
1715
|
+
def test_merge_doesnt_duplicate_same_clauses_coerced
|
|
1716
|
+
david, mary, bob = authors(:david, :mary, :bob)
|
|
1717
|
+
|
|
1718
|
+
non_mary_and_bob = Author.where.not(id: [mary, bob])
|
|
1472
1719
|
|
|
1720
|
+
author_id = Author.connection.quote_table_name("authors.id")
|
|
1721
|
+
assert_sql(/WHERE #{Regexp.escape(author_id)} NOT IN \((@\d), \g<1>\)'/) do
|
|
1722
|
+
assert_equal [david], non_mary_and_bob.merge(non_mary_and_bob)
|
|
1723
|
+
end
|
|
1473
1724
|
|
|
1725
|
+
only_david = Author.where("#{author_id} IN (?)", david)
|
|
1726
|
+
|
|
1727
|
+
assert_sql(/WHERE \(#{Regexp.escape(author_id)} IN \(1\)\)\z/) do
|
|
1728
|
+
assert_equal [david], only_david.merge(only_david)
|
|
1729
|
+
end
|
|
1730
|
+
end
|
|
1731
|
+
end
|
|
1474
1732
|
|
|
1475
1733
|
module ActiveRecord
|
|
1476
1734
|
class DatabaseTasksTruncateAllTest < ActiveRecord::TestCase
|
|
@@ -1481,9 +1739,6 @@ module ActiveRecord
|
|
|
1481
1739
|
end
|
|
1482
1740
|
end
|
|
1483
1741
|
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
1742
|
require "models/book"
|
|
1488
1743
|
class EnumTest < ActiveRecord::TestCase
|
|
1489
1744
|
# Need to remove index as SQL Server considers NULLs on a unique-index to be equal unlike PostgreSQL/MySQL/SQLite.
|
|
@@ -1527,13 +1782,8 @@ class EnumTest < ActiveRecord::TestCase
|
|
|
1527
1782
|
end
|
|
1528
1783
|
end
|
|
1529
1784
|
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
require 'models/task'
|
|
1785
|
+
require "models/task"
|
|
1535
1786
|
class QueryCacheExpiryTest < ActiveRecord::TestCase
|
|
1536
|
-
|
|
1537
1787
|
# SQL Server does not support skipping or upserting duplicates.
|
|
1538
1788
|
coerce_tests! :test_insert_all
|
|
1539
1789
|
def test_insert_all_coerced
|
|
@@ -1563,10 +1813,10 @@ class QueryCacheExpiryTest < ActiveRecord::TestCase
|
|
|
1563
1813
|
end
|
|
1564
1814
|
end
|
|
1565
1815
|
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
require 'models/citation'
|
|
1816
|
+
require "models/citation"
|
|
1569
1817
|
class EagerLoadingTooManyIdsTest < ActiveRecord::TestCase
|
|
1818
|
+
fixtures :citations
|
|
1819
|
+
|
|
1570
1820
|
# Original Rails test fails with SQL Server error message "The query processor ran out of internal resources and
|
|
1571
1821
|
# could not produce a query plan". This error goes away if you change database compatibility level to 110 (SQL 2012)
|
|
1572
1822
|
# (see https://www.mssqltips.com/sqlservertip/5279/sql-server-error-query-processor-ran-out-of-internal-resources-and-could-not-produce-a-query-plan/).
|
|
@@ -1574,22 +1824,19 @@ class EagerLoadingTooManyIdsTest < ActiveRecord::TestCase
|
|
|
1574
1824
|
# unprepared statement is used if the number of values exceeds the adapter's `bind_params_length`. The coerced test
|
|
1575
1825
|
# still does this as there will be 32,768 remaining citation records in the database and the `bind_params_length` of
|
|
1576
1826
|
# adapter is 2,098.
|
|
1577
|
-
coerce_tests! :
|
|
1578
|
-
def
|
|
1827
|
+
coerce_tests! :test_eager_loading_too_many_ids
|
|
1828
|
+
def test_eager_loading_too_many_ids_coerced
|
|
1579
1829
|
# Remove excess records.
|
|
1580
1830
|
Citation.limit(32768).order(id: :desc).delete_all
|
|
1581
1831
|
|
|
1582
1832
|
# Perform test
|
|
1583
1833
|
citation_count = Citation.count
|
|
1584
|
-
assert_sql(/WHERE \
|
|
1834
|
+
assert_sql(/WHERE \[citations\]\.\[id\] IN \(0, 1/) do
|
|
1585
1835
|
assert_equal citation_count, Citation.eager_load(:citations).offset(0).size
|
|
1586
1836
|
end
|
|
1587
1837
|
end
|
|
1588
1838
|
end
|
|
1589
1839
|
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
1840
|
class LogSubscriberTest < ActiveRecord::TestCase
|
|
1594
1841
|
# Call original test from coerced test. Fixes issue on CI with Rails installed as a gem.
|
|
1595
1842
|
coerce_tests! :test_vebose_query_logs
|
|
@@ -1598,9 +1845,6 @@ class LogSubscriberTest < ActiveRecord::TestCase
|
|
|
1598
1845
|
end
|
|
1599
1846
|
end
|
|
1600
1847
|
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
1848
|
class ActiveRecordSchemaTest < ActiveRecord::TestCase
|
|
1605
1849
|
# Workaround for randomly failing test.
|
|
1606
1850
|
coerce_tests! :test_has_primary_key
|
|
@@ -1610,31 +1854,125 @@ class ActiveRecordSchemaTest < ActiveRecord::TestCase
|
|
|
1610
1854
|
end
|
|
1611
1855
|
end
|
|
1612
1856
|
|
|
1857
|
+
class ReloadModelsTest < ActiveRecord::TestCase
|
|
1858
|
+
# Skip test on Windows. The number of arguments passed to `IO.popen` in
|
|
1859
|
+
# `activesupport/lib/active_support/testing/isolation.rb` exceeds what Windows can handle.
|
|
1860
|
+
coerce_tests! :test_has_one_with_reload if RbConfig::CONFIG["host_os"] =~ /mswin|mingw/
|
|
1861
|
+
end
|
|
1613
1862
|
|
|
1863
|
+
require "models/post"
|
|
1864
|
+
class AnnotateTest < ActiveRecord::TestCase
|
|
1865
|
+
# Same as original coerced test except our SQL starts with `EXEC sp_executesql`.
|
|
1866
|
+
# TODO: Remove coerce after Rails 7 (see https://github.com/rails/rails/pull/42027)
|
|
1867
|
+
coerce_tests! :test_annotate_wraps_content_in_an_inline_comment
|
|
1868
|
+
def test_annotate_wraps_content_in_an_inline_comment_coerced
|
|
1869
|
+
quoted_posts_id, quoted_posts = regexp_escape_table_name("posts.id"), regexp_escape_table_name("posts")
|
|
1870
|
+
|
|
1871
|
+
assert_sql(%r{SELECT #{quoted_posts_id} FROM #{quoted_posts} /\* foo \*/}i) do
|
|
1872
|
+
posts = Post.select(:id).annotate("foo")
|
|
1873
|
+
assert posts.first
|
|
1874
|
+
end
|
|
1875
|
+
end
|
|
1614
1876
|
|
|
1877
|
+
# Same as original coerced test except our SQL starts with `EXEC sp_executesql`.
|
|
1878
|
+
# TODO: Remove coerce after Rails 7 (see https://github.com/rails/rails/pull/42027)
|
|
1879
|
+
coerce_tests! :test_annotate_is_sanitized
|
|
1880
|
+
def test_annotate_is_sanitized_coerced
|
|
1881
|
+
quoted_posts_id, quoted_posts = regexp_escape_table_name("posts.id"), regexp_escape_table_name("posts")
|
|
1615
1882
|
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1883
|
+
assert_sql(%r{SELECT #{quoted_posts_id} FROM #{quoted_posts} /\* foo \*/}i) do
|
|
1884
|
+
posts = Post.select(:id).annotate("*/foo/*")
|
|
1885
|
+
assert posts.first
|
|
1886
|
+
end
|
|
1887
|
+
|
|
1888
|
+
assert_sql(%r{SELECT #{quoted_posts_id} FROM #{quoted_posts} /\* foo \*/}i) do
|
|
1889
|
+
posts = Post.select(:id).annotate("**//foo//**")
|
|
1890
|
+
assert posts.first
|
|
1891
|
+
end
|
|
1892
|
+
|
|
1893
|
+
assert_sql(%r{SELECT #{quoted_posts_id} FROM #{quoted_posts} /\* foo \*/ /\* bar \*/}i) do
|
|
1894
|
+
posts = Post.select(:id).annotate("*/foo/*").annotate("*/bar")
|
|
1895
|
+
assert posts.first
|
|
1896
|
+
end
|
|
1897
|
+
|
|
1898
|
+
assert_sql(%r{SELECT #{quoted_posts_id} FROM #{quoted_posts} /\* \+ MAX_EXECUTION_TIME\(1\) \*/}i) do
|
|
1899
|
+
posts = Post.select(:id).annotate("+ MAX_EXECUTION_TIME(1)")
|
|
1900
|
+
assert posts.first
|
|
1621
1901
|
end
|
|
1622
1902
|
end
|
|
1623
1903
|
end
|
|
1624
1904
|
|
|
1905
|
+
class MarshalSerializationTest < ActiveRecord::TestCase
|
|
1906
|
+
private
|
|
1907
|
+
|
|
1908
|
+
def marshal_fixture_path(file_name)
|
|
1909
|
+
File.expand_path(
|
|
1910
|
+
"support/marshal_compatibility_fixtures/#{ActiveRecord::Base.connection.adapter_name}/#{file_name}.dump",
|
|
1911
|
+
ARTest::SQLServer.test_root_sqlserver
|
|
1912
|
+
)
|
|
1913
|
+
end
|
|
1914
|
+
end
|
|
1625
1915
|
|
|
1916
|
+
class NestedThroughAssociationsTest < ActiveRecord::TestCase
|
|
1917
|
+
# Same as original but replace order with "order(:id)" to ensure that assert_includes_and_joins_equal doesn't raise
|
|
1918
|
+
# "A column has been specified more than once in the order by list"
|
|
1919
|
+
# Example: original test generate queries like "ORDER BY authors.id, [authors].[id]". We don't support duplicate columns in the order list
|
|
1920
|
+
coerce_tests! :test_has_many_through_has_many_with_has_many_through_habtm_source_reflection_preload_via_joins, :test_has_many_through_has_and_belongs_to_many_with_has_many_source_reflection_preload_via_joins
|
|
1921
|
+
def test_has_many_through_has_many_with_has_many_through_habtm_source_reflection_preload_via_joins_coerced
|
|
1922
|
+
# preload table schemas
|
|
1923
|
+
Author.joins(:category_post_comments).first
|
|
1924
|
+
|
|
1925
|
+
assert_includes_and_joins_equal(
|
|
1926
|
+
Author.where("comments.id" => comments(:does_it_hurt).id).order(:id),
|
|
1927
|
+
[authors(:david), authors(:mary)], :category_post_comments
|
|
1928
|
+
)
|
|
1929
|
+
end
|
|
1626
1930
|
|
|
1931
|
+
def test_has_many_through_has_and_belongs_to_many_with_has_many_source_reflection_preload_via_joins_coerced
|
|
1932
|
+
# preload table schemas
|
|
1933
|
+
Category.joins(:post_comments).first
|
|
1627
1934
|
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1935
|
+
assert_includes_and_joins_equal(
|
|
1936
|
+
Category.where("comments.id" => comments(:more_greetings).id).order(:id),
|
|
1937
|
+
[categories(:general), categories(:technology)], :post_comments
|
|
1938
|
+
)
|
|
1939
|
+
end
|
|
1631
1940
|
end
|
|
1632
1941
|
|
|
1942
|
+
class BasePreventWritesTest < ActiveRecord::TestCase
|
|
1943
|
+
# SQL Server does not have query for release_savepoint
|
|
1944
|
+
coerce_tests! %r{an empty transaction does not raise if preventing writes}
|
|
1945
|
+
test "an empty transaction does not raise if preventing writes coerced" do
|
|
1946
|
+
ActiveRecord::Base.while_preventing_writes do
|
|
1947
|
+
assert_queries(1, ignore_none: true) do
|
|
1948
|
+
Bird.transaction do
|
|
1949
|
+
ActiveRecord::Base.connection.materialize_transactions
|
|
1950
|
+
end
|
|
1951
|
+
end
|
|
1952
|
+
end
|
|
1953
|
+
end
|
|
1633
1954
|
|
|
1955
|
+
class BasePreventWritesLegacyTest < ActiveRecord::TestCase
|
|
1956
|
+
# SQL Server does not have query for release_savepoint
|
|
1957
|
+
coerce_tests! %r{an empty transaction does not raise if preventing writes}
|
|
1958
|
+
test "an empty transaction does not raise if preventing writes coerced" do
|
|
1959
|
+
ActiveRecord::Base.connection_handler.while_preventing_writes do
|
|
1960
|
+
assert_queries(1, ignore_none: true) do
|
|
1961
|
+
Bird.transaction do
|
|
1962
|
+
ActiveRecord::Base.connection.materialize_transactions
|
|
1963
|
+
end
|
|
1964
|
+
end
|
|
1965
|
+
end
|
|
1966
|
+
end
|
|
1967
|
+
end
|
|
1968
|
+
end
|
|
1634
1969
|
|
|
1970
|
+
class MigratorTest < ActiveRecord::TestCase
|
|
1971
|
+
# Test fails on Windows AppVeyor CI for unknown reason.
|
|
1972
|
+
coerce_tests! :test_migrator_db_has_no_schema_migrations_table if RbConfig::CONFIG["host_os"] =~ /mswin|mingw/
|
|
1973
|
+
end
|
|
1635
1974
|
|
|
1636
|
-
class
|
|
1637
|
-
#
|
|
1638
|
-
|
|
1639
|
-
coerce_tests! :test_has_one_with_reload if RbConfig::CONFIG['host_os'] =~ /mswin|mingw/
|
|
1975
|
+
class MultiDbMigratorTest < ActiveRecord::TestCase
|
|
1976
|
+
# Test fails on Windows AppVeyor CI for unknown reason.
|
|
1977
|
+
coerce_tests! :test_migrator_db_has_no_schema_migrations_table if RbConfig::CONFIG["host_os"] =~ /mswin|mingw/
|
|
1640
1978
|
end
|