activerecord-sqlserver-adapter 5.2.1 → 6.0.2
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/.editorconfig +9 -0
- data/.github/issue_template.md +23 -0
- data/.github/workflows/ci.yml +26 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +29 -0
- data/CHANGELOG.md +58 -20
- data/{Dockerfile → Dockerfile.ci} +1 -1
- data/Gemfile +48 -41
- data/Guardfile +9 -8
- data/README.md +28 -31
- data/RUNNING_UNIT_TESTS.md +3 -0
- data/Rakefile +14 -16
- data/VERSION +1 -1
- data/activerecord-sqlserver-adapter.gemspec +25 -14
- data/appveyor.yml +24 -17
- data/docker-compose.ci.yml +7 -5
- data/guides/RELEASING.md +11 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/active_record.rb +2 -4
- data/lib/active_record/connection_adapters/sqlserver/core_ext/attribute_methods.rb +3 -4
- data/lib/active_record/connection_adapters/sqlserver/core_ext/calculations.rb +5 -4
- data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +3 -3
- 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 +8 -7
- data/lib/active_record/connection_adapters/sqlserver/core_ext/preloader.rb +36 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/query_methods.rb +6 -4
- data/lib/active_record/connection_adapters/sqlserver/database_limits.rb +9 -0
- data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +88 -44
- data/lib/active_record/connection_adapters/sqlserver/database_tasks.rb +9 -12
- data/lib/active_record/connection_adapters/sqlserver/errors.rb +2 -3
- data/lib/active_record/connection_adapters/sqlserver/quoting.rb +46 -8
- data/lib/active_record/connection_adapters/sqlserver/schema_creation.rb +16 -5
- data/lib/active_record/connection_adapters/sqlserver/schema_dumper.rb +9 -7
- data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +210 -163
- data/lib/active_record/connection_adapters/sqlserver/showplan.rb +8 -8
- data/lib/active_record/connection_adapters/sqlserver/showplan/printer_table.rb +4 -2
- data/lib/active_record/connection_adapters/sqlserver/showplan/printer_xml.rb +3 -1
- data/lib/active_record/connection_adapters/sqlserver/sql_type_metadata.rb +2 -2
- data/lib/active_record/connection_adapters/sqlserver/table_definition.rb +43 -44
- data/lib/active_record/connection_adapters/sqlserver/transaction.rb +7 -9
- data/lib/active_record/connection_adapters/sqlserver/type.rb +38 -35
- data/lib/active_record/connection_adapters/sqlserver/type/big_integer.rb +3 -3
- data/lib/active_record/connection_adapters/sqlserver/type/binary.rb +5 -4
- data/lib/active_record/connection_adapters/sqlserver/type/boolean.rb +3 -3
- data/lib/active_record/connection_adapters/sqlserver/type/char.rb +7 -4
- data/lib/active_record/connection_adapters/sqlserver/type/data.rb +2 -2
- data/lib/active_record/connection_adapters/sqlserver/type/date.rb +4 -3
- data/lib/active_record/connection_adapters/sqlserver/type/datetime.rb +8 -8
- data/lib/active_record/connection_adapters/sqlserver/type/datetime2.rb +2 -2
- data/lib/active_record/connection_adapters/sqlserver/type/datetimeoffset.rb +2 -2
- data/lib/active_record/connection_adapters/sqlserver/type/decimal.rb +5 -4
- data/lib/active_record/connection_adapters/sqlserver/type/decimal_without_scale.rb +22 -0
- data/lib/active_record/connection_adapters/sqlserver/type/float.rb +3 -3
- data/lib/active_record/connection_adapters/sqlserver/type/integer.rb +3 -3
- data/lib/active_record/connection_adapters/sqlserver/type/json.rb +2 -1
- data/lib/active_record/connection_adapters/sqlserver/type/money.rb +4 -4
- data/lib/active_record/connection_adapters/sqlserver/type/real.rb +3 -3
- data/lib/active_record/connection_adapters/sqlserver/type/small_integer.rb +3 -3
- data/lib/active_record/connection_adapters/sqlserver/type/small_money.rb +4 -4
- data/lib/active_record/connection_adapters/sqlserver/type/smalldatetime.rb +3 -3
- data/lib/active_record/connection_adapters/sqlserver/type/string.rb +2 -2
- data/lib/active_record/connection_adapters/sqlserver/type/text.rb +3 -3
- data/lib/active_record/connection_adapters/sqlserver/type/time.rb +6 -6
- data/lib/active_record/connection_adapters/sqlserver/type/time_value_fractional.rb +8 -9
- data/lib/active_record/connection_adapters/sqlserver/type/timestamp.rb +3 -3
- data/lib/active_record/connection_adapters/sqlserver/type/tiny_integer.rb +3 -3
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_char.rb +5 -4
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_string.rb +2 -2
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_text.rb +3 -3
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar.rb +6 -5
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar_max.rb +4 -4
- data/lib/active_record/connection_adapters/sqlserver/type/uuid.rb +4 -3
- data/lib/active_record/connection_adapters/sqlserver/type/varbinary.rb +6 -5
- data/lib/active_record/connection_adapters/sqlserver/type/varbinary_max.rb +4 -4
- data/lib/active_record/connection_adapters/sqlserver/type/varchar.rb +6 -5
- data/lib/active_record/connection_adapters/sqlserver/type/varchar_max.rb +4 -4
- data/lib/active_record/connection_adapters/sqlserver/utils.rb +10 -11
- data/lib/active_record/connection_adapters/sqlserver/version.rb +2 -2
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +145 -94
- data/lib/active_record/connection_adapters/sqlserver_column.rb +9 -5
- data/lib/active_record/sqlserver_base.rb +9 -1
- data/lib/active_record/tasks/sqlserver_database_tasks.rb +28 -32
- data/lib/activerecord-sqlserver-adapter.rb +3 -1
- data/lib/arel/visitors/sqlserver.rb +108 -34
- data/lib/arel_sqlserver.rb +4 -2
- data/test/appveyor/dbsetup.ps1 +4 -4
- data/test/cases/adapter_test_sqlserver.rb +246 -171
- data/test/cases/change_column_null_test_sqlserver.rb +14 -12
- data/test/cases/coerced_tests.rb +722 -381
- data/test/cases/column_test_sqlserver.rb +287 -285
- data/test/cases/connection_test_sqlserver.rb +17 -20
- data/test/cases/execute_procedure_test_sqlserver.rb +20 -20
- data/test/cases/fetch_test_sqlserver.rb +16 -22
- data/test/cases/fully_qualified_identifier_test_sqlserver.rb +15 -19
- data/test/cases/helper_sqlserver.rb +15 -15
- data/test/cases/in_clause_test_sqlserver.rb +36 -0
- data/test/cases/index_test_sqlserver.rb +15 -15
- data/test/cases/json_test_sqlserver.rb +25 -25
- data/test/cases/lateral_test_sqlserver.rb +35 -0
- data/test/cases/migration_test_sqlserver.rb +67 -27
- data/test/cases/optimizer_hints_test_sqlserver.rb +72 -0
- data/test/cases/order_test_sqlserver.rb +53 -54
- data/test/cases/pessimistic_locking_test_sqlserver.rb +27 -33
- data/test/cases/rake_test_sqlserver.rb +33 -45
- data/test/cases/schema_dumper_test_sqlserver.rb +115 -109
- data/test/cases/schema_test_sqlserver.rb +20 -26
- data/test/cases/scratchpad_test_sqlserver.rb +4 -4
- data/test/cases/showplan_test_sqlserver.rb +28 -35
- data/test/cases/specific_schema_test_sqlserver.rb +68 -65
- data/test/cases/transaction_test_sqlserver.rb +18 -20
- data/test/cases/trigger_test_sqlserver.rb +14 -13
- data/test/cases/utils_test_sqlserver.rb +70 -70
- data/test/cases/uuid_test_sqlserver.rb +13 -14
- data/test/debug.rb +8 -6
- data/test/migrations/create_clients_and_change_column_null.rb +3 -1
- data/test/migrations/transaction_table/1_table_will_never_be_created.rb +4 -4
- data/test/models/sqlserver/booking.rb +3 -1
- data/test/models/sqlserver/customers_view.rb +3 -1
- data/test/models/sqlserver/datatype.rb +2 -0
- data/test/models/sqlserver/datatype_migration.rb +2 -0
- data/test/models/sqlserver/dollar_table_name.rb +3 -1
- data/test/models/sqlserver/edge_schema.rb +3 -3
- data/test/models/sqlserver/fk_has_fk.rb +3 -1
- data/test/models/sqlserver/fk_has_pk.rb +3 -1
- data/test/models/sqlserver/natural_pk_data.rb +4 -2
- data/test/models/sqlserver/natural_pk_int_data.rb +3 -1
- data/test/models/sqlserver/no_pk_data.rb +3 -1
- data/test/models/sqlserver/object_default.rb +3 -1
- data/test/models/sqlserver/quoted_table.rb +4 -2
- data/test/models/sqlserver/quoted_view_1.rb +3 -1
- data/test/models/sqlserver/quoted_view_2.rb +3 -1
- data/test/models/sqlserver/sst_memory.rb +3 -1
- data/test/models/sqlserver/string_default.rb +3 -1
- data/test/models/sqlserver/string_defaults_big_view.rb +3 -1
- data/test/models/sqlserver/string_defaults_view.rb +3 -1
- data/test/models/sqlserver/tinyint_pk.rb +3 -1
- data/test/models/sqlserver/trigger.rb +4 -2
- data/test/models/sqlserver/trigger_history.rb +3 -1
- data/test/models/sqlserver/upper.rb +3 -1
- data/test/models/sqlserver/uppered.rb +3 -1
- data/test/models/sqlserver/uuid.rb +3 -1
- data/test/schema/sqlserver_specific_schema.rb +31 -21
- data/test/support/coerceable_test_sqlserver.rb +15 -9
- data/test/support/connection_reflection.rb +3 -2
- data/test/support/core_ext/query_cache.rb +4 -1
- data/test/support/load_schema_sqlserver.rb +5 -5
- data/test/support/minitest_sqlserver.rb +3 -1
- data/test/support/paths_sqlserver.rb +11 -11
- data/test/support/rake_helpers.rb +13 -10
- data/test/support/sql_counter_sqlserver.rb +3 -4
- data/test/support/test_in_memory_oltp.rb +9 -7
- metadata +27 -12
- data/.travis.yml +0 -25
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "cases/helper_sqlserver"
|
|
4
|
+
require "migrations/create_clients_and_change_column_null"
|
|
3
5
|
|
|
4
6
|
class ChangeColumnNullTestSqlServer < ActiveRecord::TestCase
|
|
5
7
|
before do
|
|
@@ -17,25 +19,25 @@ class ChangeColumnNullTestSqlServer < ActiveRecord::TestCase
|
|
|
17
19
|
table.find { |column| column.name == name }
|
|
18
20
|
end
|
|
19
21
|
|
|
20
|
-
let(:clients_table) { connection.columns(
|
|
21
|
-
let(:name_column) { find_column(clients_table,
|
|
22
|
-
let(:code_column) { find_column(clients_table,
|
|
23
|
-
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") }
|
|
24
26
|
|
|
25
|
-
describe
|
|
26
|
-
it
|
|
27
|
+
describe "#change_column_null" do
|
|
28
|
+
it "does not change the column limit" do
|
|
27
29
|
_(name_column.limit).must_equal 15
|
|
28
30
|
end
|
|
29
31
|
|
|
30
|
-
it
|
|
31
|
-
_(code_column.default).must_equal
|
|
32
|
+
it "does not change the column default" do
|
|
33
|
+
_(code_column.default).must_equal "n/a"
|
|
32
34
|
end
|
|
33
35
|
|
|
34
|
-
it
|
|
36
|
+
it "does not change the column precision" do
|
|
35
37
|
_(value_column.precision).must_equal 32
|
|
36
38
|
end
|
|
37
39
|
|
|
38
|
-
it
|
|
40
|
+
it "does not change the column scale" do
|
|
39
41
|
_(value_column.scale).must_equal 8
|
|
40
42
|
end
|
|
41
43
|
end
|
data/test/cases/coerced_tests.rb
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "cases/helper_sqlserver"
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
require 'models/event'
|
|
5
|
+
require "models/event"
|
|
6
6
|
class UniquenessValidationTest < ActiveRecord::TestCase
|
|
7
|
-
# So sp_executesql swallows this exception. Run without
|
|
7
|
+
# So sp_executesql swallows this exception. Run without prepared to see it.
|
|
8
8
|
coerce_tests! :test_validate_uniqueness_with_limit
|
|
9
9
|
def test_validate_uniqueness_with_limit_coerced
|
|
10
10
|
connection.unprepared_statement do
|
|
@@ -14,7 +14,7 @@ class UniquenessValidationTest < ActiveRecord::TestCase
|
|
|
14
14
|
end
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
-
# So sp_executesql swallows this exception. Run without
|
|
17
|
+
# So sp_executesql swallows this exception. Run without prepared to see it.
|
|
18
18
|
coerce_tests! :test_validate_uniqueness_with_limit_and_utf8
|
|
19
19
|
def test_validate_uniqueness_with_limit_and_utf8_coerced
|
|
20
20
|
connection.unprepared_statement do
|
|
@@ -23,66 +23,125 @@ class UniquenessValidationTest < ActiveRecord::TestCase
|
|
|
23
23
|
end
|
|
24
24
|
end
|
|
25
25
|
end
|
|
26
|
-
end
|
|
27
|
-
|
|
28
26
|
|
|
27
|
+
# Skip the test if database is case-insensitive.
|
|
28
|
+
coerce_tests! :test_validate_case_sensitive_uniqueness_by_default
|
|
29
|
+
def test_validate_case_sensitive_uniqueness_by_default_coerced
|
|
30
|
+
database_collation = connection.select_one("SELECT collation_name FROM sys.databases WHERE name = 'activerecord_unittest'").values.first
|
|
31
|
+
skip if database_collation.include?("_CI_")
|
|
29
32
|
|
|
33
|
+
original_test_validate_case_sensitive_uniqueness_by_default_coerced
|
|
34
|
+
end
|
|
35
|
+
end
|
|
30
36
|
|
|
31
|
-
require
|
|
37
|
+
require "models/event"
|
|
32
38
|
module ActiveRecord
|
|
33
39
|
class AdapterTest < ActiveRecord::TestCase
|
|
34
|
-
# I really
|
|
40
|
+
# I really don`t think we can support legacy binds.
|
|
35
41
|
coerce_tests! :test_select_all_with_legacy_binds
|
|
36
42
|
coerce_tests! :test_insert_update_delete_with_legacy_binds
|
|
37
43
|
|
|
38
44
|
# As far as I can tell, SQL Server does not support null bytes in strings.
|
|
39
45
|
coerce_tests! :test_update_prepared_statement
|
|
40
46
|
|
|
41
|
-
# So sp_executesql swallows this exception. Run without
|
|
47
|
+
# So sp_executesql swallows this exception. Run without prepared to see it.
|
|
42
48
|
coerce_tests! :test_value_limit_violations_are_translated_to_specific_exception
|
|
43
49
|
def test_value_limit_violations_are_translated_to_specific_exception_coerced
|
|
44
50
|
connection.unprepared_statement do
|
|
45
51
|
error = assert_raises(ActiveRecord::ValueTooLong) do
|
|
46
|
-
Event.create(title:
|
|
52
|
+
Event.create(title: "abcdefgh")
|
|
47
53
|
end
|
|
48
54
|
assert_not_nil error.cause
|
|
49
55
|
end
|
|
50
56
|
end
|
|
57
|
+
|
|
58
|
+
# Fix randomly failing test. The loading of the model's schema was affecting the test.
|
|
59
|
+
coerce_tests! :test_errors_when_an_insert_query_is_called_while_preventing_writes
|
|
60
|
+
def test_errors_when_an_insert_query_is_called_while_preventing_writes_coerced
|
|
61
|
+
Subscriber.send(:load_schema!)
|
|
62
|
+
original_test_errors_when_an_insert_query_is_called_while_preventing_writes
|
|
63
|
+
end
|
|
51
64
|
end
|
|
52
65
|
end
|
|
53
66
|
|
|
67
|
+
module ActiveRecord
|
|
68
|
+
class AdapterTestWithoutTransaction < ActiveRecord::TestCase
|
|
69
|
+
# SQL Server does not allow truncation of tables that are referenced by foreign key
|
|
70
|
+
# constraints. So manually remove/add foreign keys in test.
|
|
71
|
+
coerce_tests! :test_truncate_tables
|
|
72
|
+
def test_truncate_tables_coerced
|
|
73
|
+
# Remove foreign key constraint to allow truncation.
|
|
74
|
+
@connection.remove_foreign_key :authors, :author_addresses
|
|
75
|
+
|
|
76
|
+
assert_operator Post.count, :>, 0
|
|
77
|
+
assert_operator Author.count, :>, 0
|
|
78
|
+
assert_operator AuthorAddress.count, :>, 0
|
|
79
|
+
|
|
80
|
+
@connection.truncate_tables("author_addresses", "authors", "posts")
|
|
81
|
+
|
|
82
|
+
assert_equal 0, Post.count
|
|
83
|
+
assert_equal 0, Author.count
|
|
84
|
+
assert_equal 0, AuthorAddress.count
|
|
85
|
+
ensure
|
|
86
|
+
reset_fixtures("posts", "authors", "author_addresses")
|
|
87
|
+
|
|
88
|
+
# Restore foreign key constraint.
|
|
89
|
+
@connection.add_foreign_key :authors, :author_addresses
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# SQL Server does not allow truncation of tables that are referenced by foreign key
|
|
93
|
+
# constraints. So manually remove/add foreign keys in test.
|
|
94
|
+
coerce_tests! :test_truncate_tables_with_query_cache
|
|
95
|
+
def test_truncate_tables_with_query_cache
|
|
96
|
+
# Remove foreign key constraint to allow truncation.
|
|
97
|
+
@connection.remove_foreign_key :authors, :author_addresses
|
|
54
98
|
|
|
99
|
+
@connection.enable_query_cache!
|
|
55
100
|
|
|
101
|
+
assert_operator Post.count, :>, 0
|
|
102
|
+
assert_operator Author.count, :>, 0
|
|
103
|
+
assert_operator AuthorAddress.count, :>, 0
|
|
56
104
|
|
|
57
|
-
|
|
105
|
+
@connection.truncate_tables("author_addresses", "authors", "posts")
|
|
106
|
+
|
|
107
|
+
assert_equal 0, Post.count
|
|
108
|
+
assert_equal 0, Author.count
|
|
109
|
+
assert_equal 0, AuthorAddress.count
|
|
110
|
+
ensure
|
|
111
|
+
reset_fixtures("posts", "authors", "author_addresses")
|
|
112
|
+
@connection.disable_query_cache!
|
|
113
|
+
|
|
114
|
+
# Restore foreign key constraint.
|
|
115
|
+
@connection.add_foreign_key :authors, :author_addresses
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
require "models/topic"
|
|
58
121
|
class AttributeMethodsTest < ActiveRecord::TestCase
|
|
122
|
+
# Use IFF for boolean statement in SELECT
|
|
59
123
|
coerce_tests! %r{typecast attribute from select to false}
|
|
60
124
|
def test_typecast_attribute_from_select_to_false_coerced
|
|
61
|
-
Topic.create(:title =>
|
|
125
|
+
Topic.create(:title => "Budget")
|
|
62
126
|
topic = Topic.all.merge!(:select => "topics.*, IIF (1 = 2, 1, 0) as is_test").first
|
|
63
|
-
|
|
127
|
+
assert_not_predicate topic, :is_test?
|
|
64
128
|
end
|
|
65
129
|
|
|
130
|
+
# Use IFF for boolean statement in SELECT
|
|
66
131
|
coerce_tests! %r{typecast attribute from select to true}
|
|
67
132
|
def test_typecast_attribute_from_select_to_true_coerced
|
|
68
|
-
Topic.create(:title =>
|
|
133
|
+
Topic.create(:title => "Budget")
|
|
69
134
|
topic = Topic.all.merge!(:select => "topics.*, IIF (1 = 1, 1, 0) as is_test").first
|
|
70
|
-
|
|
135
|
+
assert_predicate topic, :is_test?
|
|
71
136
|
end
|
|
72
137
|
end
|
|
73
138
|
|
|
74
|
-
|
|
75
|
-
class NumericDataTest < ActiveRecord::TestCase
|
|
76
|
-
# We do not have do the DecimalWithoutScale type.
|
|
77
|
-
coerce_tests! :test_numeric_fields
|
|
78
|
-
coerce_tests! :test_numeric_fields_with_scale
|
|
79
|
-
end
|
|
80
|
-
|
|
81
139
|
class BasicsTest < ActiveRecord::TestCase
|
|
140
|
+
# Use square brackets as SQL Server escaped character
|
|
82
141
|
coerce_tests! :test_column_names_are_escaped
|
|
83
142
|
def test_column_names_are_escaped_coerced
|
|
84
143
|
conn = ActiveRecord::Base.connection
|
|
85
|
-
assert_equal
|
|
144
|
+
assert_equal "[t]]]", conn.quote_column_name("t]")
|
|
86
145
|
end
|
|
87
146
|
|
|
88
147
|
# Just like PostgreSQLAdapter does.
|
|
@@ -96,52 +155,60 @@ class BasicsTest < ActiveRecord::TestCase
|
|
|
96
155
|
Time.use_zone("Eastern Time (US & Canada)") do
|
|
97
156
|
topic = Topic.find(1)
|
|
98
157
|
time = Time.zone.parse("2017-07-17 10:56")
|
|
99
|
-
topic.
|
|
158
|
+
topic.update!(written_on: time)
|
|
100
159
|
assert_equal(time, topic.written_on)
|
|
101
160
|
end
|
|
102
161
|
end
|
|
103
162
|
|
|
104
163
|
def test_update_date_time_attributes_with_default_timezone_local
|
|
105
|
-
with_env_tz
|
|
164
|
+
with_env_tz "America/New_York" do
|
|
106
165
|
with_timezone_config default: :local do
|
|
107
166
|
Time.use_zone("Eastern Time (US & Canada)") do
|
|
108
167
|
topic = Topic.find(1)
|
|
109
168
|
time = Time.zone.parse("2017-07-17 10:56")
|
|
110
|
-
topic.
|
|
169
|
+
topic.update!(written_on: time)
|
|
111
170
|
assert_equal(time, topic.written_on)
|
|
112
171
|
end
|
|
113
172
|
end
|
|
114
173
|
end
|
|
115
174
|
end
|
|
116
175
|
|
|
117
|
-
#
|
|
118
|
-
coerce_tests! %r{
|
|
119
|
-
test "
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
176
|
+
# SQL Server does not have query for release_savepoint
|
|
177
|
+
coerce_tests! %r{an empty transaction does not raise if preventing writes}
|
|
178
|
+
test "an empty transaction does not raise if preventing writes coerced" do
|
|
179
|
+
ActiveRecord::Base.connection_handler.while_preventing_writes do
|
|
180
|
+
assert_queries(1, ignore_none: true) do
|
|
181
|
+
Bird.transaction do
|
|
182
|
+
ActiveRecord::Base.connection.materialize_transactions
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
end
|
|
125
186
|
end
|
|
126
187
|
end
|
|
127
188
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
189
|
class BelongsToAssociationsTest < ActiveRecord::TestCase
|
|
132
190
|
# Since @client.firm is a single first/top, and we use FETCH the order clause is used.
|
|
133
191
|
coerce_tests! :test_belongs_to_does_not_use_order_by
|
|
134
192
|
|
|
193
|
+
# Square brackets around column name
|
|
135
194
|
coerce_tests! :test_belongs_to_with_primary_key_joins_on_correct_column
|
|
136
195
|
def test_belongs_to_with_primary_key_joins_on_correct_column_coerced
|
|
137
196
|
sql = Client.joins(:firm_with_primary_key).to_sql
|
|
138
197
|
assert_no_match(/\[firm_with_primary_keys_companies\]\.\[id\]/, sql)
|
|
139
198
|
assert_match(/\[firm_with_primary_keys_companies\]\.\[name\]/, sql)
|
|
140
199
|
end
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
|
|
144
200
|
|
|
201
|
+
# Asserted SQL to get one row different from original test.
|
|
202
|
+
coerce_tests! :test_belongs_to
|
|
203
|
+
def test_belongs_to_coerced
|
|
204
|
+
client = Client.find(3)
|
|
205
|
+
first_firm = companies(:first_firm)
|
|
206
|
+
assert_sql(/FETCH NEXT @(\d) ROWS ONLY(.)*@\1 = 1/) do
|
|
207
|
+
assert_equal first_firm, client.firm
|
|
208
|
+
assert_equal first_firm.name, client.firm.name
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
end
|
|
145
212
|
|
|
146
213
|
module ActiveRecord
|
|
147
214
|
class BindParameterTest < ActiveRecord::TestCase
|
|
@@ -163,62 +230,53 @@ module ActiveRecord
|
|
|
163
230
|
# SQL Server adapter does not use a statement cache as query plans are already reused using `EXEC sp_executesql`.
|
|
164
231
|
coerce_tests! :test_statement_cache
|
|
165
232
|
coerce_tests! :test_statement_cache_with_query_cache
|
|
233
|
+
coerce_tests! :test_statement_cache_with_find
|
|
166
234
|
coerce_tests! :test_statement_cache_with_find_by
|
|
167
235
|
coerce_tests! :test_statement_cache_with_in_clause
|
|
168
236
|
coerce_tests! :test_statement_cache_with_sql_string_literal
|
|
169
237
|
end
|
|
170
238
|
end
|
|
171
239
|
|
|
172
|
-
|
|
173
240
|
module ActiveRecord
|
|
174
241
|
class InstrumentationTest < ActiveRecord::TestCase
|
|
175
|
-
#
|
|
242
|
+
# Fix randomly failing test. The loading of the model's schema was affecting the test.
|
|
176
243
|
coerce_tests! :test_payload_name_on_load
|
|
177
244
|
def test_payload_name_on_load_coerced
|
|
178
|
-
Book.
|
|
179
|
-
|
|
180
|
-
subscriber = ActiveSupport::Notifications.subscribe("sql.active_record") do |*args|
|
|
181
|
-
event = ActiveSupport::Notifications::Event.new(*args)
|
|
182
|
-
if event.payload[:sql].match "SELECT"
|
|
183
|
-
assert_equal "Book Load", event.payload[:name]
|
|
184
|
-
end
|
|
185
|
-
end
|
|
186
|
-
Book.first
|
|
187
|
-
ensure
|
|
188
|
-
ActiveSupport::Notifications.unsubscribe(subscriber) if subscriber
|
|
245
|
+
Book.send(:load_schema!)
|
|
246
|
+
original_test_payload_name_on_load
|
|
189
247
|
end
|
|
190
248
|
end
|
|
191
249
|
end
|
|
192
250
|
|
|
193
251
|
class CalculationsTest < ActiveRecord::TestCase
|
|
194
|
-
#
|
|
252
|
+
# Fix randomly failing test. The loading of the model's schema was affecting the test.
|
|
195
253
|
coerce_tests! :test_offset_is_kept
|
|
196
254
|
def test_offset_is_kept_coerced
|
|
197
|
-
Account.
|
|
198
|
-
|
|
199
|
-
assert_equal 1, queries.length
|
|
200
|
-
assert_match(/OFFSET/, queries.first)
|
|
255
|
+
Account.send(:load_schema!)
|
|
256
|
+
original_test_offset_is_kept
|
|
201
257
|
end
|
|
202
258
|
|
|
203
259
|
# Are decimal, not integer.
|
|
204
260
|
coerce_tests! :test_should_return_decimal_average_of_integer_field
|
|
205
261
|
def test_should_return_decimal_average_of_integer_field_coerced
|
|
206
262
|
value = Account.average(:id)
|
|
207
|
-
assert_equal BigDecimal(
|
|
263
|
+
assert_equal BigDecimal("3.0").to_s, BigDecimal(value).to_s
|
|
208
264
|
end
|
|
209
265
|
|
|
266
|
+
# Match SQL Server limit implementation
|
|
210
267
|
coerce_tests! :test_limit_is_kept
|
|
211
268
|
def test_limit_is_kept_coerced
|
|
212
269
|
queries = capture_sql_ss { Account.limit(1).count }
|
|
213
270
|
assert_equal 1, queries.length
|
|
214
|
-
|
|
271
|
+
assert_match(/ORDER BY \[accounts\]\.\[id\] ASC OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY.*@0 = 1/, queries.first)
|
|
215
272
|
end
|
|
216
273
|
|
|
274
|
+
# Match SQL Server limit implementation
|
|
217
275
|
coerce_tests! :test_limit_with_offset_is_kept
|
|
218
276
|
def test_limit_with_offset_is_kept_coerced
|
|
219
277
|
queries = capture_sql_ss { Account.limit(1).offset(1).count }
|
|
220
278
|
assert_equal 1, queries.length
|
|
221
|
-
|
|
279
|
+
assert_match(/ORDER BY \[accounts\]\.\[id\] ASC OFFSET @0 ROWS FETCH NEXT @1 ROWS ONLY.*@0 = 1, @1 = 1/, queries.first)
|
|
222
280
|
end
|
|
223
281
|
|
|
224
282
|
# SQL Server needs an alias for the calculated column
|
|
@@ -233,49 +291,57 @@ class CalculationsTest < ActiveRecord::TestCase
|
|
|
233
291
|
coerce_tests! :test_having_with_strong_parameters
|
|
234
292
|
end
|
|
235
293
|
|
|
236
|
-
|
|
237
|
-
|
|
238
294
|
module ActiveRecord
|
|
239
295
|
class Migration
|
|
240
296
|
class ChangeSchemaTest < ActiveRecord::TestCase
|
|
241
|
-
|
|
242
|
-
coerce_tests! :
|
|
243
|
-
|
|
244
|
-
|
|
297
|
+
# Integer.default is a number and not a string
|
|
298
|
+
coerce_tests! :test_create_table_with_defaults
|
|
299
|
+
def test_create_table_with_defaults_coerce
|
|
300
|
+
connection.create_table :testings do |t|
|
|
301
|
+
t.column :one, :string, default: "hello"
|
|
302
|
+
t.column :two, :boolean, default: true
|
|
303
|
+
t.column :three, :boolean, default: false
|
|
304
|
+
t.column :four, :integer, default: 1
|
|
305
|
+
t.column :five, :text, default: "hello"
|
|
306
|
+
end
|
|
245
307
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
308
|
+
columns = connection.columns(:testings)
|
|
309
|
+
one = columns.detect { |c| c.name == "one" }
|
|
310
|
+
two = columns.detect { |c| c.name == "two" }
|
|
311
|
+
three = columns.detect { |c| c.name == "three" }
|
|
312
|
+
four = columns.detect { |c| c.name == "four" }
|
|
313
|
+
five = columns.detect { |c| c.name == "five" }
|
|
314
|
+
|
|
315
|
+
assert_equal "hello", one.default
|
|
316
|
+
assert_equal true, connection.lookup_cast_type_from_column(two).deserialize(two.default)
|
|
317
|
+
assert_equal false, connection.lookup_cast_type_from_column(three).deserialize(three.default)
|
|
318
|
+
assert_equal 1, four.default
|
|
319
|
+
assert_equal "hello", five.default
|
|
320
|
+
end
|
|
249
321
|
end
|
|
250
322
|
end
|
|
251
323
|
end
|
|
252
324
|
|
|
253
|
-
|
|
254
|
-
|
|
255
325
|
module ActiveRecord
|
|
256
326
|
module ConnectionAdapters
|
|
257
327
|
class QuoteARBaseTest < ActiveRecord::TestCase
|
|
258
|
-
|
|
259
328
|
# Use our date format.
|
|
260
329
|
coerce_tests! :test_quote_ar_object
|
|
261
330
|
def test_quote_ar_object_coerced
|
|
262
331
|
value = DatetimePrimaryKey.new(id: @time)
|
|
263
|
-
assert_equal "'02-14-2017 12:34:56.79'",
|
|
332
|
+
assert_equal "'02-14-2017 12:34:56.79'", @connection.quote(value)
|
|
264
333
|
end
|
|
265
334
|
|
|
266
335
|
# Use our date format.
|
|
267
336
|
coerce_tests! :test_type_cast_ar_object
|
|
268
337
|
def test_type_cast_ar_object_coerced
|
|
269
338
|
value = DatetimePrimaryKey.new(id: @time)
|
|
270
|
-
assert_equal "02-14-2017 12:34:56.79",
|
|
339
|
+
assert_equal "02-14-2017 12:34:56.79", @connection.type_cast(value)
|
|
271
340
|
end
|
|
272
|
-
|
|
273
341
|
end
|
|
274
342
|
end
|
|
275
343
|
end
|
|
276
344
|
|
|
277
|
-
|
|
278
|
-
|
|
279
345
|
module ActiveRecord
|
|
280
346
|
class Migration
|
|
281
347
|
class ColumnAttributesTest < ActiveRecord::TestCase
|
|
@@ -290,16 +356,13 @@ module ActiveRecord
|
|
|
290
356
|
end
|
|
291
357
|
end
|
|
292
358
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
359
|
module ActiveRecord
|
|
297
360
|
class Migration
|
|
298
|
-
class ColumnsTest
|
|
361
|
+
class ColumnsTest < ActiveRecord::TestCase
|
|
299
362
|
# Our defaults are real 70000 integers vs '70000' strings.
|
|
300
363
|
coerce_tests! :test_rename_column_preserves_default_value_not_null
|
|
301
364
|
def test_rename_column_preserves_default_value_not_null_coerced
|
|
302
|
-
add_column
|
|
365
|
+
add_column "test_models", "salary", :integer, :default => 70000
|
|
303
366
|
default_before = connection.columns("test_models").find { |c| c.name == "salary" }.default
|
|
304
367
|
assert_equal 70000, default_before
|
|
305
368
|
rename_column "test_models", "salary", "annual_salary"
|
|
@@ -315,9 +378,9 @@ module ActiveRecord
|
|
|
315
378
|
add_column "test_models", :hat_size, :integer
|
|
316
379
|
add_column "test_models", :hat_style, :string, :limit => 100
|
|
317
380
|
add_index "test_models", ["hat_style", "hat_size"], :unique => true
|
|
318
|
-
assert_equal 1, connection.indexes(
|
|
381
|
+
assert_equal 1, connection.indexes("test_models").size
|
|
319
382
|
remove_column("test_models", "hat_size")
|
|
320
|
-
assert_equal [], connection.indexes(
|
|
383
|
+
assert_equal [], connection.indexes("test_models").map(&:name)
|
|
321
384
|
end
|
|
322
385
|
|
|
323
386
|
# Choose `StatementInvalid` vs `ActiveRecordError`.
|
|
@@ -332,61 +395,19 @@ module ActiveRecord
|
|
|
332
395
|
end
|
|
333
396
|
end
|
|
334
397
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
398
|
class MigrationTest < ActiveRecord::TestCase
|
|
339
|
-
# We do not have do the DecimalWithoutScale type.
|
|
340
|
-
coerce_tests! :test_add_table_with_decimals
|
|
341
|
-
def test_add_table_with_decimals_coerced
|
|
342
|
-
Person.connection.drop_table :big_numbers rescue nil
|
|
343
|
-
assert !BigNumber.table_exists?
|
|
344
|
-
GiveMeBigNumbers.up
|
|
345
|
-
BigNumber.reset_column_information
|
|
346
|
-
assert BigNumber.create(
|
|
347
|
-
:bank_balance => 1586.43,
|
|
348
|
-
:big_bank_balance => BigDecimal("1000234000567.95"),
|
|
349
|
-
:world_population => 6000000000,
|
|
350
|
-
:my_house_population => 3,
|
|
351
|
-
:value_of_e => BigDecimal("2.7182818284590452353602875")
|
|
352
|
-
)
|
|
353
|
-
b = BigNumber.first
|
|
354
|
-
assert_not_nil b
|
|
355
|
-
assert_not_nil b.bank_balance
|
|
356
|
-
assert_not_nil b.big_bank_balance
|
|
357
|
-
assert_not_nil b.world_population
|
|
358
|
-
assert_not_nil b.my_house_population
|
|
359
|
-
assert_not_nil b.value_of_e
|
|
360
|
-
assert_kind_of BigDecimal, b.world_population
|
|
361
|
-
assert_equal '6000000000.0', b.world_population.to_s
|
|
362
|
-
assert_kind_of Integer, b.my_house_population
|
|
363
|
-
assert_equal 3, b.my_house_population
|
|
364
|
-
assert_kind_of BigDecimal, b.bank_balance
|
|
365
|
-
assert_equal BigDecimal("1586.43"), b.bank_balance
|
|
366
|
-
assert_kind_of BigDecimal, b.big_bank_balance
|
|
367
|
-
assert_equal BigDecimal("1000234000567.95"), b.big_bank_balance
|
|
368
|
-
GiveMeBigNumbers.down
|
|
369
|
-
assert_raise(ActiveRecord::StatementInvalid) { BigNumber.first }
|
|
370
|
-
end
|
|
371
|
-
|
|
372
399
|
# For some reason our tests set Rails.@_env which breaks test env switching.
|
|
373
400
|
coerce_tests! :test_internal_metadata_stores_environment_when_other_data_exists
|
|
374
401
|
coerce_tests! :test_internal_metadata_stores_environment
|
|
375
402
|
end
|
|
376
403
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
404
|
class CoreTest < ActiveRecord::TestCase
|
|
381
|
-
# I think fixtures are
|
|
405
|
+
# I think fixtures are using the wrong time zone and the `:first`
|
|
382
406
|
# `topics`.`bonus_time` attribute of 2005-01-30t15:28:00.00+01:00 is
|
|
383
407
|
# getting local EST time for me and set to "09:28:00.0000000".
|
|
384
408
|
coerce_tests! :test_pretty_print_persisted
|
|
385
409
|
end
|
|
386
410
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
411
|
module ActiveRecord
|
|
391
412
|
module ConnectionAdapters
|
|
392
413
|
# Just like PostgreSQLAdapter does.
|
|
@@ -400,27 +421,152 @@ module ActiveRecord
|
|
|
400
421
|
end
|
|
401
422
|
end
|
|
402
423
|
|
|
424
|
+
module ActiveRecord
|
|
425
|
+
# The original module is hardcoded for PostgreSQL/SQLite/MySQL tests.
|
|
426
|
+
module DatabaseTasksSetupper
|
|
427
|
+
def setup
|
|
428
|
+
@sqlserver_tasks =
|
|
429
|
+
Class.new do
|
|
430
|
+
def create; end
|
|
403
431
|
|
|
432
|
+
def drop; end
|
|
404
433
|
|
|
434
|
+
def purge; end
|
|
435
|
+
|
|
436
|
+
def charset; end
|
|
437
|
+
|
|
438
|
+
def collation; end
|
|
439
|
+
|
|
440
|
+
def structure_dump(*); end
|
|
441
|
+
|
|
442
|
+
def structure_load(*); end
|
|
443
|
+
end.new
|
|
444
|
+
|
|
445
|
+
$stdout, @original_stdout = StringIO.new, $stdout
|
|
446
|
+
$stderr, @original_stderr = StringIO.new, $stderr
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
def with_stubbed_new
|
|
450
|
+
ActiveRecord::Tasks::SQLServerDatabaseTasks.stub(:new, @sqlserver_tasks) do
|
|
451
|
+
yield
|
|
452
|
+
end
|
|
453
|
+
end
|
|
454
|
+
end
|
|
455
|
+
|
|
456
|
+
class DatabaseTasksCreateTest < ActiveRecord::TestCase
|
|
457
|
+
# Coerce PostgreSQL/SQLite/MySQL tests.
|
|
458
|
+
coerce_all_tests!
|
|
459
|
+
|
|
460
|
+
def test_sqlserver_create
|
|
461
|
+
with_stubbed_new do
|
|
462
|
+
assert_called(eval("@sqlserver_tasks"), :create) do
|
|
463
|
+
ActiveRecord::Tasks::DatabaseTasks.create "adapter" => :sqlserver
|
|
464
|
+
end
|
|
465
|
+
end
|
|
466
|
+
end
|
|
467
|
+
end
|
|
468
|
+
|
|
469
|
+
class DatabaseTasksDropTest < ActiveRecord::TestCase
|
|
470
|
+
# Coerce PostgreSQL/SQLite/MySQL tests.
|
|
471
|
+
coerce_all_tests!
|
|
472
|
+
|
|
473
|
+
def test_sqlserver_drop
|
|
474
|
+
with_stubbed_new do
|
|
475
|
+
assert_called(eval("@sqlserver_tasks"), :drop) do
|
|
476
|
+
ActiveRecord::Tasks::DatabaseTasks.drop "adapter" => :sqlserver
|
|
477
|
+
end
|
|
478
|
+
end
|
|
479
|
+
end
|
|
480
|
+
end
|
|
481
|
+
|
|
482
|
+
class DatabaseTasksPurgeTest < ActiveRecord::TestCase
|
|
483
|
+
# Coerce PostgreSQL/SQLite/MySQL tests.
|
|
484
|
+
coerce_all_tests!
|
|
485
|
+
|
|
486
|
+
def test_sqlserver_purge
|
|
487
|
+
with_stubbed_new do
|
|
488
|
+
assert_called(eval("@sqlserver_tasks"), :purge) do
|
|
489
|
+
ActiveRecord::Tasks::DatabaseTasks.purge "adapter" => :sqlserver
|
|
490
|
+
end
|
|
491
|
+
end
|
|
492
|
+
end
|
|
493
|
+
end
|
|
494
|
+
|
|
495
|
+
class DatabaseTasksCharsetTest < ActiveRecord::TestCase
|
|
496
|
+
# Coerce PostgreSQL/SQLite/MySQL tests.
|
|
497
|
+
coerce_all_tests!
|
|
498
|
+
|
|
499
|
+
def test_sqlserver_charset
|
|
500
|
+
with_stubbed_new do
|
|
501
|
+
assert_called(eval("@sqlserver_tasks"), :charset) do
|
|
502
|
+
ActiveRecord::Tasks::DatabaseTasks.charset "adapter" => :sqlserver
|
|
503
|
+
end
|
|
504
|
+
end
|
|
505
|
+
end
|
|
506
|
+
end
|
|
507
|
+
|
|
508
|
+
class DatabaseTasksCollationTest < ActiveRecord::TestCase
|
|
509
|
+
# Coerce PostgreSQL/SQLite/MySQL tests.
|
|
510
|
+
coerce_all_tests!
|
|
511
|
+
|
|
512
|
+
def test_sqlserver_collation
|
|
513
|
+
with_stubbed_new do
|
|
514
|
+
assert_called(eval("@sqlserver_tasks"), :collation) do
|
|
515
|
+
ActiveRecord::Tasks::DatabaseTasks.collation "adapter" => :sqlserver
|
|
516
|
+
end
|
|
517
|
+
end
|
|
518
|
+
end
|
|
519
|
+
end
|
|
520
|
+
|
|
521
|
+
class DatabaseTasksStructureDumpTest < ActiveRecord::TestCase
|
|
522
|
+
# Coerce PostgreSQL/SQLite/MySQL tests.
|
|
523
|
+
coerce_all_tests!
|
|
524
|
+
|
|
525
|
+
def test_sqlserver_structure_dump
|
|
526
|
+
with_stubbed_new do
|
|
527
|
+
assert_called_with(
|
|
528
|
+
eval("@sqlserver_tasks"), :structure_dump,
|
|
529
|
+
["awesome-file.sql", nil]
|
|
530
|
+
) do
|
|
531
|
+
ActiveRecord::Tasks::DatabaseTasks.structure_dump({ "adapter" => :sqlserver }, "awesome-file.sql")
|
|
532
|
+
end
|
|
533
|
+
end
|
|
534
|
+
end
|
|
535
|
+
end
|
|
536
|
+
|
|
537
|
+
class DatabaseTasksStructureLoadTest < ActiveRecord::TestCase
|
|
538
|
+
# Coerce PostgreSQL/SQLite/MySQL tests.
|
|
539
|
+
coerce_all_tests!
|
|
540
|
+
|
|
541
|
+
def test_sqlserver_structure_load
|
|
542
|
+
with_stubbed_new do
|
|
543
|
+
assert_called_with(
|
|
544
|
+
eval("@sqlserver_tasks"),
|
|
545
|
+
:structure_load,
|
|
546
|
+
["awesome-file.sql", nil]
|
|
547
|
+
) do
|
|
548
|
+
ActiveRecord::Tasks::DatabaseTasks.structure_load({ "adapter" => :sqlserver }, "awesome-file.sql")
|
|
549
|
+
end
|
|
550
|
+
end
|
|
551
|
+
end
|
|
552
|
+
end
|
|
405
553
|
|
|
406
|
-
module ActiveRecord
|
|
407
554
|
class DatabaseTasksDumpSchemaCacheTest < ActiveRecord::TestCase
|
|
408
555
|
# Skip this test with /tmp/my_schema_cache.yml path on Windows.
|
|
409
|
-
coerce_tests! :test_dump_schema_cache if RbConfig::CONFIG[
|
|
556
|
+
coerce_tests! :test_dump_schema_cache if RbConfig::CONFIG["host_os"] =~ /mswin|mingw/
|
|
410
557
|
end
|
|
558
|
+
|
|
411
559
|
class DatabaseTasksCreateAllTest < ActiveRecord::TestCase
|
|
412
560
|
# We extend `local_database?` so that common VM IPs can be used.
|
|
413
561
|
coerce_tests! :test_ignores_remote_databases, :test_warning_for_remote_databases
|
|
414
562
|
end
|
|
563
|
+
|
|
415
564
|
class DatabaseTasksDropAllTest < ActiveRecord::TestCase
|
|
416
565
|
# We extend `local_database?` so that common VM IPs can be used.
|
|
417
566
|
coerce_tests! :test_ignores_remote_databases, :test_warning_for_remote_databases
|
|
418
567
|
end
|
|
419
568
|
end
|
|
420
569
|
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
570
|
class DefaultScopingTest < ActiveRecord::TestCase
|
|
425
571
|
# We are not doing order duplicate removal anymore.
|
|
426
572
|
coerce_tests! :test_order_in_default_scope_should_not_prevail
|
|
@@ -434,16 +580,13 @@ class DefaultScopingTest < ActiveRecord::TestCase
|
|
|
434
580
|
end
|
|
435
581
|
end
|
|
436
582
|
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
require 'models/post'
|
|
441
|
-
require 'models/subscriber'
|
|
583
|
+
require "models/post"
|
|
584
|
+
require "models/subscriber"
|
|
442
585
|
class EachTest < ActiveRecord::TestCase
|
|
443
586
|
# Quoting in tests does not cope with bracket quoting.
|
|
444
587
|
coerce_tests! :test_find_in_batches_should_quote_batch_order
|
|
445
588
|
def test_find_in_batches_should_quote_batch_order_coerced
|
|
446
|
-
|
|
589
|
+
Post.connection
|
|
447
590
|
assert_sql(/ORDER BY \[posts\]\.\[id\]/) do
|
|
448
591
|
Post.find_in_batches(:batch_size => 1) do |batch|
|
|
449
592
|
assert_kind_of Array, batch
|
|
@@ -455,7 +598,7 @@ class EachTest < ActiveRecord::TestCase
|
|
|
455
598
|
# Quoting in tests does not cope with bracket quoting.
|
|
456
599
|
coerce_tests! :test_in_batches_should_quote_batch_order
|
|
457
600
|
def test_in_batches_should_quote_batch_order_coerced
|
|
458
|
-
|
|
601
|
+
Post.connection
|
|
459
602
|
assert_sql(/ORDER BY \[posts\]\.\[id\]/) do
|
|
460
603
|
Post.in_batches(of: 1) do |relation|
|
|
461
604
|
assert_kind_of ActiveRecord::Relation, relation
|
|
@@ -465,9 +608,6 @@ class EachTest < ActiveRecord::TestCase
|
|
|
465
608
|
end
|
|
466
609
|
end
|
|
467
610
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
611
|
class EagerAssociationTest < ActiveRecord::TestCase
|
|
472
612
|
# Use LEN() vs length() function.
|
|
473
613
|
coerce_tests! :test_count_with_include
|
|
@@ -479,14 +619,13 @@ class EagerAssociationTest < ActiveRecord::TestCase
|
|
|
479
619
|
coerce_tests! %r{including association based on sql condition and no database column}
|
|
480
620
|
end
|
|
481
621
|
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
require 'models/topic'
|
|
622
|
+
require "models/topic"
|
|
486
623
|
class FinderTest < ActiveRecord::TestCase
|
|
624
|
+
# We have implicit ordering, via FETCH.
|
|
487
625
|
coerce_tests! %r{doesn't have implicit ordering},
|
|
488
|
-
:test_find_doesnt_have_implicit_ordering
|
|
626
|
+
:test_find_doesnt_have_implicit_ordering
|
|
489
627
|
|
|
628
|
+
# Square brackets around column name
|
|
490
629
|
coerce_tests! :test_exists_does_not_select_columns_without_alias
|
|
491
630
|
def test_exists_does_not_select_columns_without_alias_coerced
|
|
492
631
|
assert_sql(/SELECT\s+1 AS one FROM \[topics\].*OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY.*@0 = 1/i) do
|
|
@@ -494,6 +633,7 @@ class FinderTest < ActiveRecord::TestCase
|
|
|
494
633
|
end
|
|
495
634
|
end
|
|
496
635
|
|
|
636
|
+
# Assert SQL Server limit implementation
|
|
497
637
|
coerce_tests! :test_take_and_first_and_last_with_integer_should_use_sql_limit
|
|
498
638
|
def test_take_and_first_and_last_with_integer_should_use_sql_limit_coerced
|
|
499
639
|
assert_sql(/OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY.* @0 = 3/) { Topic.take(3).entries }
|
|
@@ -507,7 +647,7 @@ class FinderTest < ActiveRecord::TestCase
|
|
|
507
647
|
# Can not use array condition due to not finding right type and hence fractional second quoting.
|
|
508
648
|
coerce_tests! :test_condition_utc_time_interpolation_with_default_timezone_local
|
|
509
649
|
def test_condition_utc_time_interpolation_with_default_timezone_local_coerced
|
|
510
|
-
with_env_tz
|
|
650
|
+
with_env_tz "America/New_York" do
|
|
511
651
|
with_timezone_config default: :local do
|
|
512
652
|
topic = Topic.first
|
|
513
653
|
assert_equal topic, Topic.where(written_on: topic.written_on.getutc).first
|
|
@@ -518,7 +658,7 @@ class FinderTest < ActiveRecord::TestCase
|
|
|
518
658
|
# Can not use array condition due to not finding right type and hence fractional second quoting.
|
|
519
659
|
coerce_tests! :test_condition_local_time_interpolation_with_default_timezone_utc
|
|
520
660
|
def test_condition_local_time_interpolation_with_default_timezone_utc_coerced
|
|
521
|
-
with_env_tz
|
|
661
|
+
with_env_tz "America/New_York" do
|
|
522
662
|
with_timezone_config default: :utc do
|
|
523
663
|
topic = Topic.first
|
|
524
664
|
assert_equal topic, Topic.where(written_on: topic.written_on.getlocal).first
|
|
@@ -527,9 +667,6 @@ class FinderTest < ActiveRecord::TestCase
|
|
|
527
667
|
end
|
|
528
668
|
end
|
|
529
669
|
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
670
|
module ActiveRecord
|
|
534
671
|
class Migration
|
|
535
672
|
class ForeignKeyTest < ActiveRecord::TestCase
|
|
@@ -547,90 +684,103 @@ module ActiveRecord
|
|
|
547
684
|
end
|
|
548
685
|
end
|
|
549
686
|
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
687
|
class HasOneAssociationsTest < ActiveRecord::TestCase
|
|
554
688
|
# We use OFFSET/FETCH vs TOP. So we always have an order.
|
|
555
689
|
coerce_tests! :test_has_one_does_not_use_order_by
|
|
556
|
-
end
|
|
557
|
-
|
|
558
690
|
|
|
691
|
+
# Asserted SQL to get one row different from original test.
|
|
692
|
+
coerce_tests! :test_has_one
|
|
693
|
+
def test_has_one_coerced
|
|
694
|
+
firm = companies(:first_firm)
|
|
695
|
+
first_account = Account.find(1)
|
|
696
|
+
assert_sql(/FETCH NEXT @(\d) ROWS ONLY(.)*@\1 = 1/) do
|
|
697
|
+
assert_equal first_account, firm.account
|
|
698
|
+
assert_equal first_account.credit_limit, firm.account.credit_limit
|
|
699
|
+
end
|
|
700
|
+
end
|
|
701
|
+
end
|
|
559
702
|
|
|
703
|
+
class HasOneThroughAssociationsTest < ActiveRecord::TestCase
|
|
704
|
+
# Asserted SQL to get one row different from original test.
|
|
705
|
+
coerce_tests! :test_has_one_through_executes_limited_query
|
|
706
|
+
def test_has_one_through_executes_limited_query_coerced
|
|
707
|
+
boring_club = clubs(:boring_club)
|
|
708
|
+
assert_sql(/FETCH NEXT @(\d) ROWS ONLY(.)*@\1 = 1/) do
|
|
709
|
+
assert_equal boring_club, @member.general_club
|
|
710
|
+
end
|
|
711
|
+
end
|
|
712
|
+
end
|
|
560
713
|
|
|
561
|
-
require
|
|
714
|
+
require "models/company"
|
|
562
715
|
class InheritanceTest < ActiveRecord::TestCase
|
|
716
|
+
# Rails test required inserting to a identity column.
|
|
563
717
|
coerce_tests! :test_a_bad_type_column
|
|
564
718
|
def test_a_bad_type_column_coerced
|
|
565
|
-
Company.connection.with_identity_insert_enabled(
|
|
719
|
+
Company.connection.with_identity_insert_enabled("companies") do
|
|
566
720
|
Company.connection.insert "INSERT INTO companies (id, #{QUOTED_TYPE}, name) VALUES(100, 'bad_class!', 'Not happening')"
|
|
567
721
|
end
|
|
568
722
|
assert_raise(ActiveRecord::SubclassNotFound) { Company.find(100) }
|
|
569
723
|
end
|
|
570
724
|
|
|
725
|
+
# Use Square brackets around column name
|
|
571
726
|
coerce_tests! :test_eager_load_belongs_to_primary_key_quoting
|
|
572
727
|
def test_eager_load_belongs_to_primary_key_quoting_coerced
|
|
573
|
-
|
|
728
|
+
Account.connection
|
|
574
729
|
assert_sql(/\[companies\]\.\[id\] = @0.* @0 = 1/) do
|
|
575
730
|
Account.all.merge!(:includes => :firm).find(1)
|
|
576
731
|
end
|
|
577
732
|
end
|
|
578
733
|
end
|
|
579
734
|
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
735
|
class LeftOuterJoinAssociationTest < ActiveRecord::TestCase
|
|
584
736
|
# Uses || operator in SQL. Just trust core gets value out of this test.
|
|
585
737
|
coerce_tests! :test_does_not_override_select
|
|
586
738
|
end
|
|
587
739
|
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
class NamedScopingTest < ActiveRecord::TestCase
|
|
592
|
-
# This works now because we add an `order(:id)` sort to break the order tie for deterministic results.
|
|
593
|
-
coerce_tests! :test_scopes_honor_current_scopes_from_when_defined
|
|
594
|
-
def test_scopes_honor_current_scopes_from_when_defined_coerced
|
|
595
|
-
assert !Post.ranked_by_comments.order(:id).limit_by(5).empty?
|
|
596
|
-
assert !authors(:david).posts.ranked_by_comments.order(:id).limit_by(5).empty?
|
|
597
|
-
assert_not_equal Post.ranked_by_comments.order(:id).limit_by(5), authors(:david).posts.ranked_by_comments.order(:id).limit_by(5)
|
|
598
|
-
assert_not_equal Post.order(:id).top(5), authors(:david).posts.order(:id).top(5)
|
|
599
|
-
# Oracle sometimes sorts differently if WHERE condition is changed
|
|
600
|
-
assert_equal authors(:david).posts.ranked_by_comments.limit_by(5).to_a.sort_by(&:id), authors(:david).posts.top(5).to_a.sort_by(&:id)
|
|
601
|
-
assert_equal Post.ranked_by_comments.limit_by(5), Post.top(5)
|
|
602
|
-
end
|
|
603
|
-
end
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
require 'models/developer'
|
|
609
|
-
require 'models/computer'
|
|
740
|
+
require "models/developer"
|
|
741
|
+
require "models/computer"
|
|
610
742
|
class NestedRelationScopingTest < ActiveRecord::TestCase
|
|
743
|
+
# Assert SQL Server limit implementation
|
|
611
744
|
coerce_tests! :test_merge_options
|
|
612
745
|
def test_merge_options_coerced
|
|
613
|
-
Developer.where(
|
|
746
|
+
Developer.where("salary = 80000").scoping do
|
|
614
747
|
Developer.limit(10).scoping do
|
|
615
748
|
devs = Developer.all
|
|
616
749
|
sql = devs.to_sql
|
|
617
|
-
assert_match
|
|
618
|
-
assert_match
|
|
750
|
+
assert_match "(salary = 80000)", sql
|
|
751
|
+
assert_match "FETCH NEXT 10 ROWS ONLY", sql
|
|
619
752
|
end
|
|
620
753
|
end
|
|
621
754
|
end
|
|
622
755
|
end
|
|
623
756
|
|
|
757
|
+
require "models/topic"
|
|
758
|
+
class PersistenceTest < ActiveRecord::TestCase
|
|
759
|
+
# Rails test required updating a identity column.
|
|
760
|
+
coerce_tests! :test_update_columns_changing_id
|
|
624
761
|
|
|
762
|
+
# Rails test required updating a identity column.
|
|
763
|
+
coerce_tests! :test_update
|
|
764
|
+
def test_update_coerced
|
|
765
|
+
topic = Topic.find(1)
|
|
766
|
+
assert_not_predicate topic, :approved?
|
|
767
|
+
assert_equal "The First Topic", topic.title
|
|
625
768
|
|
|
769
|
+
topic.update("approved" => true, "title" => "The First Topic Updated")
|
|
770
|
+
topic.reload
|
|
771
|
+
assert_predicate topic, :approved?
|
|
772
|
+
assert_equal "The First Topic Updated", topic.title
|
|
626
773
|
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
774
|
+
topic.update(approved: false, title: "The First Topic")
|
|
775
|
+
topic.reload
|
|
776
|
+
assert_not_predicate topic, :approved?
|
|
777
|
+
assert_equal "The First Topic", topic.title
|
|
778
|
+
end
|
|
779
|
+
end
|
|
632
780
|
|
|
633
|
-
|
|
781
|
+
require "models/author"
|
|
782
|
+
class UpdateAllTest < ActiveRecord::TestCase
|
|
783
|
+
# Rails test required updating a identity column.
|
|
634
784
|
coerce_tests! :test_update_all_doesnt_ignore_order
|
|
635
785
|
def test_update_all_doesnt_ignore_order_coerced
|
|
636
786
|
david, mary = authors(:david), authors(:mary)
|
|
@@ -638,81 +788,80 @@ class PersistenceTest < ActiveRecord::TestCase
|
|
|
638
788
|
_(mary.id).must_equal 2
|
|
639
789
|
_(david.name).wont_equal mary.name
|
|
640
790
|
assert_sql(/UPDATE.*\(SELECT \[authors\].\[id\] FROM \[authors\].*ORDER BY \[authors\].\[id\]/i) do
|
|
641
|
-
Author.where(
|
|
791
|
+
Author.where("[id] > 1").order(:id).update_all(name: "Test")
|
|
642
792
|
end
|
|
643
|
-
_(david.reload.name).must_equal
|
|
644
|
-
_(mary.reload.name).must_equal
|
|
645
|
-
end
|
|
646
|
-
|
|
647
|
-
# We can not UPDATE identity columns.
|
|
648
|
-
coerce_tests! :test_update_attributes
|
|
649
|
-
def test_update_attributes_coerced
|
|
650
|
-
topic = Topic.find(1)
|
|
651
|
-
assert !topic.approved?
|
|
652
|
-
assert_equal "The First Topic", topic.title
|
|
653
|
-
topic.update_attributes("approved" => true, "title" => "The First Topic Updated")
|
|
654
|
-
topic.reload
|
|
655
|
-
assert topic.approved?
|
|
656
|
-
assert_equal "The First Topic Updated", topic.title
|
|
657
|
-
topic.update_attributes(approved: false, title: "The First Topic")
|
|
658
|
-
topic.reload
|
|
659
|
-
assert !topic.approved?
|
|
660
|
-
assert_equal "The First Topic", topic.title
|
|
661
|
-
# SQLServer: Here is where it breaks down. No exceptions.
|
|
662
|
-
# assert_raise(ActiveRecord::RecordNotUnique, ActiveRecord::StatementInvalid) do
|
|
663
|
-
# topic.update_attributes(id: 3, title: "Hm is it possible?")
|
|
664
|
-
# end
|
|
665
|
-
# assert_not_equal "Hm is it possible?", Topic.find(3).title
|
|
666
|
-
# topic.update_attributes(id: 1234)
|
|
667
|
-
# assert_nothing_raised { topic.reload }
|
|
668
|
-
# assert_equal topic.title, Topic.find(1234).title
|
|
793
|
+
_(david.reload.name).must_equal "David"
|
|
794
|
+
_(mary.reload.name).must_equal "Test"
|
|
669
795
|
end
|
|
670
796
|
end
|
|
671
797
|
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
require 'models/topic'
|
|
798
|
+
require "models/topic"
|
|
676
799
|
module ActiveRecord
|
|
677
800
|
class PredicateBuilderTest < ActiveRecord::TestCase
|
|
801
|
+
# Same as original test except string has `N` prefix to indicate unicode string.
|
|
678
802
|
coerce_tests! :test_registering_new_handlers
|
|
679
803
|
def test_registering_new_handlers_coerced
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
804
|
+
assert_match %r{#{Regexp.escape(topic_title)} ~ N'rails'}i, Topic.where(title: /rails/).to_sql
|
|
805
|
+
end
|
|
806
|
+
|
|
807
|
+
# Same as original test except string has `N` prefix to indicate unicode string.
|
|
808
|
+
coerce_tests! :test_registering_new_handlers_for_association
|
|
809
|
+
def test_registering_new_handlers_for_association_coerced
|
|
810
|
+
assert_match %r{#{Regexp.escape(topic_title)} ~ N'rails'}i, Reply.joins(:topic).where(topics: { title: /rails/ }).to_sql
|
|
686
811
|
end
|
|
687
812
|
end
|
|
688
813
|
end
|
|
689
814
|
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
815
|
class PrimaryKeysTest < ActiveRecord::TestCase
|
|
694
|
-
#
|
|
695
|
-
# but as far as I can tell, this is only one for us anyway.
|
|
816
|
+
# SQL Server does not have query for release_savepoint
|
|
696
817
|
coerce_tests! :test_create_without_primary_key_no_extra_query
|
|
818
|
+
def test_create_without_primary_key_no_extra_query_coerced
|
|
819
|
+
klass = Class.new(ActiveRecord::Base) do
|
|
820
|
+
self.table_name = "dashboards"
|
|
821
|
+
end
|
|
822
|
+
klass.create! # warmup schema cache
|
|
823
|
+
assert_queries(2, ignore_none: true) { klass.create! }
|
|
824
|
+
end
|
|
697
825
|
end
|
|
698
826
|
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
require 'models/task'
|
|
827
|
+
require "models/task"
|
|
703
828
|
class QueryCacheTest < ActiveRecord::TestCase
|
|
829
|
+
# SQL Server adapter not in list of supported adapters in original test.
|
|
704
830
|
coerce_tests! :test_cache_does_not_wrap_results_in_arrays
|
|
705
831
|
def test_cache_does_not_wrap_results_in_arrays_coerced
|
|
706
832
|
Task.cache do
|
|
707
|
-
|
|
833
|
+
assert_equal 2, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks")
|
|
708
834
|
end
|
|
709
835
|
end
|
|
710
|
-
end
|
|
711
836
|
|
|
837
|
+
# Same as original test except that we expect one query to be performed to retrieve the table's primary key.
|
|
838
|
+
# When we generate the SQL for the `find` it includes ordering on the primary key. If we reset the column
|
|
839
|
+
# information then the primary key needs to be retrieved from the database again to generate the SQL causing the
|
|
840
|
+
# original test's `assert_no_queries` assertion to fail. Assert that the query was to get the primary key.
|
|
841
|
+
coerce_tests! :test_query_cached_even_when_types_are_reset
|
|
842
|
+
def test_query_cached_even_when_types_are_reset_coerced
|
|
843
|
+
Task.cache do
|
|
844
|
+
# Warm the cache
|
|
845
|
+
Task.find(1)
|
|
846
|
+
|
|
847
|
+
# Preload the type cache again (so we don't have those queries issued during our assertions)
|
|
848
|
+
Task.connection.send(:reload_type_map)
|
|
849
|
+
|
|
850
|
+
# Clear places where type information is cached
|
|
851
|
+
Task.reset_column_information
|
|
852
|
+
Task.initialize_find_by_cache
|
|
853
|
+
Task.define_attribute_methods
|
|
712
854
|
|
|
855
|
+
assert_queries(1, ignore_none: true) do
|
|
856
|
+
Task.find(1)
|
|
857
|
+
end
|
|
713
858
|
|
|
859
|
+
assert_includes ActiveRecord::SQLCounter.log_all.first, "TC.CONSTRAINT_TYPE = N''PRIMARY KEY''"
|
|
860
|
+
end
|
|
861
|
+
end
|
|
862
|
+
end
|
|
714
863
|
|
|
715
|
-
require
|
|
864
|
+
require "models/post"
|
|
716
865
|
class RelationTest < ActiveRecord::TestCase
|
|
717
866
|
# Use LEN vs LENGTH function.
|
|
718
867
|
coerce_tests! :test_reverse_order_with_function
|
|
@@ -733,6 +882,26 @@ class RelationTest < ActiveRecord::TestCase
|
|
|
733
882
|
# We have implicit ordering, via FETCH.
|
|
734
883
|
coerce_tests! %r{doesn't have implicit ordering}
|
|
735
884
|
|
|
885
|
+
# We have implicit ordering, via FETCH.
|
|
886
|
+
coerce_tests! :test_reorder_with_take
|
|
887
|
+
def test_reorder_with_take_coerced
|
|
888
|
+
sql_log = capture_sql do
|
|
889
|
+
assert Post.order(:title).reorder(nil).take
|
|
890
|
+
end
|
|
891
|
+
assert sql_log.none? { |sql| /order by [posts].[title]/i.match?(sql) }, "ORDER BY title was used in the query: #{sql_log}"
|
|
892
|
+
assert sql_log.all? { |sql| /order by \[posts\]\.\[id\]/i.match?(sql) }, "default ORDER BY ID was not used in the query: #{sql_log}"
|
|
893
|
+
end
|
|
894
|
+
|
|
895
|
+
# We have implicit ordering, via FETCH.
|
|
896
|
+
coerce_tests! :test_reorder_with_first
|
|
897
|
+
def test_reorder_with_first_coerced
|
|
898
|
+
sql_log = capture_sql do
|
|
899
|
+
assert Post.order(:title).reorder(nil).first
|
|
900
|
+
end
|
|
901
|
+
assert sql_log.none? { |sql| /order by [posts].[title]/i.match?(sql) }, "ORDER BY title was used in the query: #{sql_log}"
|
|
902
|
+
assert sql_log.all? { |sql| /order by \[posts\]\.\[id\]/i.match?(sql) }, "default ORDER BY ID was not used in the query: #{sql_log}"
|
|
903
|
+
end
|
|
904
|
+
|
|
736
905
|
# We are not doing order duplicate removal anymore.
|
|
737
906
|
coerce_tests! :test_order_using_scoping
|
|
738
907
|
|
|
@@ -756,17 +925,17 @@ class RelationTest < ActiveRecord::TestCase
|
|
|
756
925
|
# so we are skipping all together.
|
|
757
926
|
coerce_tests! :test_empty_complex_chained_relations
|
|
758
927
|
|
|
759
|
-
# Can't apply offset
|
|
928
|
+
# Can't apply offset without ORDER
|
|
760
929
|
coerce_tests! %r{using a custom table affects the wheres}
|
|
761
|
-
test
|
|
930
|
+
test "using a custom table affects the wheres coerced" do
|
|
762
931
|
post = posts(:welcome)
|
|
763
932
|
|
|
764
933
|
assert_equal post, custom_post_relation.where!(title: post.title).order(:id).take
|
|
765
934
|
end
|
|
766
935
|
|
|
767
|
-
# Can't apply offset
|
|
936
|
+
# Can't apply offset without ORDER
|
|
768
937
|
coerce_tests! %r{using a custom table with joins affects the joins}
|
|
769
|
-
test
|
|
938
|
+
test "using a custom table with joins affects the joins coerced" do
|
|
770
939
|
post = posts(:welcome)
|
|
771
940
|
|
|
772
941
|
assert_equal post, custom_post_relation.joins(:author).where!(title: post.title).order(:id).take
|
|
@@ -780,45 +949,46 @@ class RelationTest < ActiveRecord::TestCase
|
|
|
780
949
|
end
|
|
781
950
|
end
|
|
782
951
|
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
%r[INNER\s+JOIN\s+#{Regexp.escape(Author.quoted_table_name)}\s+\Wauthors_categorizations\W]i.match?(sql)
|
|
952
|
+
module ActiveRecord
|
|
953
|
+
class RelationTest < ActiveRecord::TestCase
|
|
954
|
+
# Skipping this test. SQL Server doesn't support optimizer hint as comments
|
|
955
|
+
coerce_tests! :test_relation_with_optimizer_hints_filters_sql_comment_delimiters
|
|
956
|
+
|
|
957
|
+
coerce_tests! :test_does_not_duplicate_optimizer_hints_on_merge
|
|
958
|
+
def test_does_not_duplicate_optimizer_hints_on_merge_coerced
|
|
959
|
+
escaped_table = Post.connection.quote_table_name("posts")
|
|
960
|
+
expected = "SELECT #{escaped_table}.* FROM #{escaped_table} OPTION (OMGHINT)"
|
|
961
|
+
query = Post.optimizer_hints("OMGHINT").merge(Post.optimizer_hints("OMGHINT")).to_sql
|
|
962
|
+
assert_equal expected, query
|
|
795
963
|
end
|
|
796
|
-
|
|
797
|
-
assert query_matches, "Should be aliasing the child INNER JOINs in query"
|
|
798
964
|
end
|
|
799
965
|
end
|
|
800
966
|
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
require 'models/post'
|
|
967
|
+
require "models/post"
|
|
805
968
|
class SanitizeTest < ActiveRecord::TestCase
|
|
969
|
+
# Use nvarchar string (N'') in assert
|
|
806
970
|
coerce_tests! :test_sanitize_sql_like_example_use_case
|
|
807
971
|
def test_sanitize_sql_like_example_use_case_coerced
|
|
808
972
|
searchable_post = Class.new(Post) do
|
|
809
|
-
def self.
|
|
810
|
-
where("title LIKE ?", sanitize_sql_like(term,
|
|
973
|
+
def self.search_as_method(term)
|
|
974
|
+
where("title LIKE ?", sanitize_sql_like(term, "!"))
|
|
811
975
|
end
|
|
976
|
+
|
|
977
|
+
scope :search_as_scope, ->(term) {
|
|
978
|
+
where("title LIKE ?", sanitize_sql_like(term, "!"))
|
|
979
|
+
}
|
|
980
|
+
end
|
|
981
|
+
|
|
982
|
+
assert_sql(/LIKE N'20!% !_reduction!_!!'/) do
|
|
983
|
+
searchable_post.search_as_method("20% _reduction_!").to_a
|
|
812
984
|
end
|
|
813
|
-
|
|
814
|
-
|
|
985
|
+
|
|
986
|
+
assert_sql(/LIKE N'20!% !_reduction!_!!'/) do
|
|
987
|
+
searchable_post.search_as_scope("20% _reduction_!").to_a
|
|
815
988
|
end
|
|
816
989
|
end
|
|
817
990
|
end
|
|
818
991
|
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
992
|
class SchemaDumperTest < ActiveRecord::TestCase
|
|
823
993
|
# We have precision to 38.
|
|
824
994
|
coerce_tests! :test_schema_dump_keeps_large_precision_integer_columns_as_decimal
|
|
@@ -850,19 +1020,14 @@ class SchemaDumperDefaultsTest < ActiveRecord::TestCase
|
|
|
850
1020
|
coerce_tests! :test_schema_dump_defaults_with_universally_supported_types
|
|
851
1021
|
end
|
|
852
1022
|
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
1023
|
class TestAdapterWithInvalidConnection < ActiveRecord::TestCase
|
|
857
1024
|
# We trust Rails on this since we do not want to install mysql.
|
|
858
1025
|
coerce_tests! %r{inspect on Model class does not raise}
|
|
859
1026
|
end
|
|
860
1027
|
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
require 'models/topic'
|
|
1028
|
+
require "models/topic"
|
|
865
1029
|
class TransactionTest < ActiveRecord::TestCase
|
|
1030
|
+
# SQL Server does not have query for release_savepoint
|
|
866
1031
|
coerce_tests! :test_releasing_named_savepoints
|
|
867
1032
|
def test_releasing_named_savepoints_coerced
|
|
868
1033
|
Topic.transaction do
|
|
@@ -874,10 +1039,7 @@ class TransactionTest < ActiveRecord::TestCase
|
|
|
874
1039
|
end
|
|
875
1040
|
end
|
|
876
1041
|
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
require 'models/tag'
|
|
1042
|
+
require "models/tag"
|
|
881
1043
|
class TransactionIsolationTest < ActiveRecord::TestCase
|
|
882
1044
|
# SQL Server will lock the table for counts even when both
|
|
883
1045
|
# connections are `READ COMMITTED`. So we bypass with `READPAST`.
|
|
@@ -887,7 +1049,7 @@ class TransactionIsolationTest < ActiveRecord::TestCase
|
|
|
887
1049
|
assert_equal 0, Tag.count
|
|
888
1050
|
Tag2.transaction do
|
|
889
1051
|
Tag2.create
|
|
890
|
-
assert_equal 0, Tag.lock(
|
|
1052
|
+
assert_equal 0, Tag.lock("WITH(READPAST)").count
|
|
891
1053
|
end
|
|
892
1054
|
end
|
|
893
1055
|
assert_equal 1, Tag.count
|
|
@@ -897,10 +1059,7 @@ class TransactionIsolationTest < ActiveRecord::TestCase
|
|
|
897
1059
|
coerce_tests! %r{repeatable read}
|
|
898
1060
|
end
|
|
899
1061
|
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
require 'models/book'
|
|
1062
|
+
require "models/book"
|
|
904
1063
|
class ViewWithPrimaryKeyTest < ActiveRecord::TestCase
|
|
905
1064
|
# We have a few view tables. use includes vs equality.
|
|
906
1065
|
coerce_tests! :test_views
|
|
@@ -912,9 +1071,10 @@ class ViewWithPrimaryKeyTest < ActiveRecord::TestCase
|
|
|
912
1071
|
coerce_tests! :test_does_not_assume_id_column_as_primary_key
|
|
913
1072
|
def test_does_not_assume_id_column_as_primary_key_coerced
|
|
914
1073
|
model = Class.new(ActiveRecord::Base) { self.table_name = "ebooks" }
|
|
915
|
-
assert_equal
|
|
1074
|
+
assert_equal "id", model.primary_key
|
|
916
1075
|
end
|
|
917
1076
|
end
|
|
1077
|
+
|
|
918
1078
|
class ViewWithoutPrimaryKeyTest < ActiveRecord::TestCase
|
|
919
1079
|
# We have a few view tables. use includes vs equality.
|
|
920
1080
|
coerce_tests! :test_views
|
|
@@ -923,23 +1083,17 @@ class ViewWithoutPrimaryKeyTest < ActiveRecord::TestCase
|
|
|
923
1083
|
end
|
|
924
1084
|
end
|
|
925
1085
|
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
require 'models/author'
|
|
1086
|
+
require "models/author"
|
|
930
1087
|
class YamlSerializationTest < ActiveRecord::TestCase
|
|
931
1088
|
coerce_tests! :test_types_of_virtual_columns_are_not_changed_on_round_trip
|
|
932
1089
|
def test_types_of_virtual_columns_are_not_changed_on_round_trip_coerced
|
|
933
|
-
author = Author.select(
|
|
1090
|
+
author = Author.select("authors.*, 5 as posts_count").first
|
|
934
1091
|
dumped = YAML.load(YAML.dump(author))
|
|
935
1092
|
assert_equal 5, author.posts_count
|
|
936
1093
|
assert_equal 5, dumped.posts_count
|
|
937
1094
|
end
|
|
938
1095
|
end
|
|
939
1096
|
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
1097
|
class DateTimePrecisionTest < ActiveRecord::TestCase
|
|
944
1098
|
# Original test had `7` which we support vs `8` which we use.
|
|
945
1099
|
coerce_tests! :test_invalid_datetime_precision_raises_error
|
|
@@ -955,7 +1109,7 @@ class DateTimePrecisionTest < ActiveRecord::TestCase
|
|
|
955
1109
|
coerce_tests! :test_datetime_precision_is_truncated_on_assignment
|
|
956
1110
|
def test_datetime_precision_is_truncated_on_assignment_coerced
|
|
957
1111
|
@connection.create_table(:foos, force: true)
|
|
958
|
-
@connection.add_column :foos, :created_at,
|
|
1112
|
+
@connection.add_column :foos, :created_at, :datetime, precision: 0
|
|
959
1113
|
@connection.add_column :foos, :updated_at, :datetime, precision: 6
|
|
960
1114
|
|
|
961
1115
|
time = ::Time.now.change(nsec: 123456789)
|
|
@@ -972,8 +1126,6 @@ class DateTimePrecisionTest < ActiveRecord::TestCase
|
|
|
972
1126
|
end
|
|
973
1127
|
end
|
|
974
1128
|
|
|
975
|
-
|
|
976
|
-
|
|
977
1129
|
class TimePrecisionTest < ActiveRecord::TestCase
|
|
978
1130
|
# datetime is rounded to increments of .000, .003, or .007 seconds
|
|
979
1131
|
coerce_tests! :test_time_precision_is_truncated_on_assignment
|
|
@@ -994,9 +1146,10 @@ class TimePrecisionTest < ActiveRecord::TestCase
|
|
|
994
1146
|
assert_equal 0, foo.start.nsec
|
|
995
1147
|
assert_equal 123457000, foo.finish.nsec
|
|
996
1148
|
end
|
|
997
|
-
end
|
|
998
|
-
|
|
999
1149
|
|
|
1150
|
+
# SQL Server uses default precision for time.
|
|
1151
|
+
coerce_tests! :test_no_time_precision_isnt_truncated_on_assignment
|
|
1152
|
+
end
|
|
1000
1153
|
|
|
1001
1154
|
class DefaultNumbersTest < ActiveRecord::TestCase
|
|
1002
1155
|
# We do better with native types and do not return strings for everything.
|
|
@@ -1006,16 +1159,23 @@ class DefaultNumbersTest < ActiveRecord::TestCase
|
|
|
1006
1159
|
assert_equal 7, record.positive_integer
|
|
1007
1160
|
assert_equal 7, record.positive_integer_before_type_cast
|
|
1008
1161
|
end
|
|
1162
|
+
|
|
1163
|
+
# We do better with native types and do not return strings for everything.
|
|
1009
1164
|
coerce_tests! :test_default_negative_integer
|
|
1010
1165
|
def test_default_negative_integer_coerced
|
|
1011
1166
|
record = DefaultNumber.new
|
|
1012
1167
|
assert_equal -5, record.negative_integer
|
|
1013
1168
|
assert_equal -5, record.negative_integer_before_type_cast
|
|
1014
1169
|
end
|
|
1015
|
-
end
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
1170
|
|
|
1171
|
+
# We do better with native types and do not return strings for everything.
|
|
1172
|
+
coerce_tests! :test_default_decimal_number
|
|
1173
|
+
def test_default_decimal_number_coerced
|
|
1174
|
+
record = DefaultNumber.new
|
|
1175
|
+
assert_equal BigDecimal("2.78"), record.decimal_number
|
|
1176
|
+
assert_equal 2.78, record.decimal_number_before_type_cast
|
|
1177
|
+
end
|
|
1178
|
+
end
|
|
1019
1179
|
|
|
1020
1180
|
module ActiveRecord
|
|
1021
1181
|
class CollectionCacheKeyTest < ActiveRecord::TestCase
|
|
@@ -1024,40 +1184,63 @@ module ActiveRecord
|
|
|
1024
1184
|
end
|
|
1025
1185
|
end
|
|
1026
1186
|
|
|
1187
|
+
module ActiveRecord
|
|
1188
|
+
class CacheKeyTest < ActiveRecord::TestCase
|
|
1189
|
+
# Like Mysql2 and PostgreSQL, SQL Server doesn't return a string value for updated_at. In the Rails tests
|
|
1190
|
+
# the tests are skipped if adapter is Mysql2 or PostgreSQL.
|
|
1191
|
+
coerce_tests! %r{cache_version is the same when it comes from the DB or from the user}
|
|
1192
|
+
coerce_tests! %r{cache_version does NOT call updated_at when value is from the database}
|
|
1193
|
+
coerce_tests! %r{cache_version does not truncate zeros when timestamp ends in zeros}
|
|
1194
|
+
end
|
|
1195
|
+
end
|
|
1027
1196
|
|
|
1028
|
-
|
|
1029
|
-
|
|
1197
|
+
require "models/book"
|
|
1030
1198
|
module ActiveRecord
|
|
1031
1199
|
class StatementCacheTest < ActiveRecord::TestCase
|
|
1032
1200
|
# Getting random failures.
|
|
1033
1201
|
coerce_tests! :test_find_does_not_use_statement_cache_if_table_name_is_changed
|
|
1034
|
-
end
|
|
1035
|
-
end
|
|
1036
|
-
|
|
1037
1202
|
|
|
1203
|
+
# Need to remove index as SQL Server considers NULLs on a unique-index to be equal unlike PostgreSQL/MySQL/SQLite.
|
|
1204
|
+
coerce_tests! :test_statement_cache_values_differ
|
|
1205
|
+
def test_statement_cache_values_differ_coerced
|
|
1206
|
+
Book.connection.remove_index(:books, column: [:author_id, :name])
|
|
1038
1207
|
|
|
1208
|
+
original_test_statement_cache_values_differ
|
|
1209
|
+
ensure
|
|
1210
|
+
Book.connection.add_index(:books, [:author_id, :name], unique: true)
|
|
1211
|
+
end
|
|
1212
|
+
end
|
|
1213
|
+
end
|
|
1039
1214
|
|
|
1040
1215
|
module ActiveRecord
|
|
1041
1216
|
module ConnectionAdapters
|
|
1042
1217
|
class SchemaCacheTest < ActiveRecord::TestCase
|
|
1043
1218
|
private
|
|
1219
|
+
|
|
1044
1220
|
# We need to give the full path for this to work.
|
|
1045
1221
|
def schema_dump_path
|
|
1046
|
-
File.join ARTest::SQLServer.root_activerecord,
|
|
1222
|
+
File.join ARTest::SQLServer.root_activerecord, "test/assets/schema_dump_5_1.yml"
|
|
1047
1223
|
end
|
|
1048
1224
|
end
|
|
1049
1225
|
end
|
|
1050
1226
|
end
|
|
1051
1227
|
|
|
1228
|
+
require "models/post"
|
|
1229
|
+
require "models/comment"
|
|
1052
1230
|
class UnsafeRawSqlTest < ActiveRecord::TestCase
|
|
1053
|
-
|
|
1054
|
-
|
|
1231
|
+
fixtures :posts
|
|
1232
|
+
|
|
1233
|
+
# Use LEN() vs length() function.
|
|
1234
|
+
coerce_tests! %r{order: always allows Arel}
|
|
1235
|
+
test "order: always allows Arel" do
|
|
1055
1236
|
ids_depr = with_unsafe_raw_sql_deprecated { Post.order(Arel.sql("len(title)")).pluck(:title) }
|
|
1056
1237
|
ids_disabled = with_unsafe_raw_sql_disabled { Post.order(Arel.sql("len(title)")).pluck(:title) }
|
|
1057
1238
|
|
|
1058
1239
|
assert_equal ids_depr, ids_disabled
|
|
1059
1240
|
end
|
|
1060
1241
|
|
|
1242
|
+
# Use LEN() vs length() function.
|
|
1243
|
+
coerce_tests! %r{pluck: always allows Arel}
|
|
1061
1244
|
test "pluck: always allows Arel" do
|
|
1062
1245
|
values_depr = with_unsafe_raw_sql_deprecated { Post.includes(:comments).pluck(:title, Arel.sql("len(title)")) }
|
|
1063
1246
|
values_disabled = with_unsafe_raw_sql_disabled { Post.includes(:comments).pluck(:title, Arel.sql("len(title)")) }
|
|
@@ -1065,73 +1248,98 @@ class UnsafeRawSqlTest < ActiveRecord::TestCase
|
|
|
1065
1248
|
assert_equal values_depr, values_disabled
|
|
1066
1249
|
end
|
|
1067
1250
|
|
|
1068
|
-
|
|
1069
|
-
coerce_tests! %r{order: disallows invalid Array arguments}
|
|
1070
|
-
test "order: disallows invalid Array arguments" do
|
|
1071
|
-
with_unsafe_raw_sql_disabled do
|
|
1072
|
-
assert_raises(ActiveRecord::UnknownAttributeReference) do
|
|
1073
|
-
Post.order(["author_id", "len(title)"]).pluck(:id)
|
|
1074
|
-
end
|
|
1075
|
-
end
|
|
1076
|
-
end
|
|
1077
|
-
|
|
1251
|
+
# Use LEN() vs length() function.
|
|
1078
1252
|
coerce_tests! %r{order: allows valid Array arguments}
|
|
1079
1253
|
test "order: allows valid Array arguments" do
|
|
1080
1254
|
ids_expected = Post.order(Arel.sql("author_id, len(title)")).pluck(:id)
|
|
1081
1255
|
|
|
1082
|
-
ids_depr = with_unsafe_raw_sql_deprecated { Post.order(["author_id",
|
|
1083
|
-
ids_disabled = with_unsafe_raw_sql_disabled { Post.order(["author_id",
|
|
1256
|
+
ids_depr = with_unsafe_raw_sql_deprecated { Post.order(["author_id", "len(title)"]).pluck(:id) }
|
|
1257
|
+
ids_disabled = with_unsafe_raw_sql_disabled { Post.order(["author_id", "len(title)"]).pluck(:id) }
|
|
1084
1258
|
|
|
1085
1259
|
assert_equal ids_expected, ids_depr
|
|
1086
1260
|
assert_equal ids_expected, ids_disabled
|
|
1087
1261
|
end
|
|
1088
1262
|
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1263
|
+
test "order: allows string column names that are quoted" do
|
|
1264
|
+
ids_expected = Post.order(Arel.sql("id")).pluck(:id)
|
|
1265
|
+
|
|
1266
|
+
ids_depr = with_unsafe_raw_sql_deprecated { Post.order("[id]").pluck(:id) }
|
|
1267
|
+
ids_disabled = with_unsafe_raw_sql_disabled { Post.order("[id]").pluck(:id) }
|
|
1268
|
+
|
|
1269
|
+
assert_equal ids_expected, ids_depr
|
|
1270
|
+
assert_equal ids_expected, ids_disabled
|
|
1096
1271
|
end
|
|
1097
1272
|
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1273
|
+
test "order: allows string column names that are quoted with table" do
|
|
1274
|
+
ids_expected = Post.order(Arel.sql("id")).pluck(:id)
|
|
1275
|
+
|
|
1276
|
+
ids_depr = with_unsafe_raw_sql_deprecated { Post.order("[posts].[id]").pluck(:id) }
|
|
1277
|
+
ids_disabled = with_unsafe_raw_sql_disabled { Post.order("[posts].[id]").pluck(:id) }
|
|
1278
|
+
|
|
1279
|
+
assert_equal ids_expected, ids_depr
|
|
1280
|
+
assert_equal ids_expected, ids_disabled
|
|
1281
|
+
end
|
|
1282
|
+
|
|
1283
|
+
test "order: allows string column names that are quoted with table and user" do
|
|
1284
|
+
ids_expected = Post.order(Arel.sql("id")).pluck(:id)
|
|
1285
|
+
|
|
1286
|
+
ids_depr = with_unsafe_raw_sql_deprecated { Post.order("[dbo].[posts].[id]").pluck(:id) }
|
|
1287
|
+
ids_disabled = with_unsafe_raw_sql_disabled { Post.order("[dbo].[posts].[id]").pluck(:id) }
|
|
1288
|
+
|
|
1289
|
+
assert_equal ids_expected, ids_depr
|
|
1290
|
+
assert_equal ids_expected, ids_disabled
|
|
1291
|
+
end
|
|
1292
|
+
|
|
1293
|
+
test "order: allows string column names that are quoted with table, user and database" do
|
|
1294
|
+
ids_expected = Post.order(Arel.sql("id")).pluck(:id)
|
|
1295
|
+
|
|
1296
|
+
ids_depr = with_unsafe_raw_sql_deprecated { Post.order("[activerecord_unittest].[dbo].[posts].[id]").pluck(:id) }
|
|
1297
|
+
ids_disabled = with_unsafe_raw_sql_disabled { Post.order("[activerecord_unittest].[dbo].[posts].[id]").pluck(:id) }
|
|
1298
|
+
|
|
1299
|
+
assert_equal ids_expected, ids_depr
|
|
1300
|
+
assert_equal ids_expected, ids_disabled
|
|
1301
|
+
end
|
|
1302
|
+
|
|
1303
|
+
test "pluck: allows string column name that are quoted" do
|
|
1304
|
+
titles_expected = Post.pluck(Arel.sql("title"))
|
|
1305
|
+
|
|
1306
|
+
titles_depr = with_unsafe_raw_sql_deprecated { Post.pluck("[title]") }
|
|
1307
|
+
titles_disabled = with_unsafe_raw_sql_disabled { Post.pluck("[title]") }
|
|
1308
|
+
|
|
1309
|
+
assert_equal titles_expected, titles_depr
|
|
1310
|
+
assert_equal titles_expected, titles_disabled
|
|
1311
|
+
end
|
|
1312
|
+
|
|
1313
|
+
test "pluck: allows string column name that are quoted with table" do
|
|
1314
|
+
titles_expected = Post.pluck(Arel.sql("title"))
|
|
1134
1315
|
|
|
1316
|
+
titles_depr = with_unsafe_raw_sql_deprecated { Post.pluck("[posts].[title]") }
|
|
1317
|
+
titles_disabled = with_unsafe_raw_sql_disabled { Post.pluck("[posts].[title]") }
|
|
1318
|
+
|
|
1319
|
+
assert_equal titles_expected, titles_depr
|
|
1320
|
+
assert_equal titles_expected, titles_disabled
|
|
1321
|
+
end
|
|
1322
|
+
|
|
1323
|
+
test "pluck: allows string column name that are quoted with table and user" do
|
|
1324
|
+
titles_expected = Post.pluck(Arel.sql("title"))
|
|
1325
|
+
|
|
1326
|
+
titles_depr = with_unsafe_raw_sql_deprecated { Post.pluck("[dbo].[posts].[title]") }
|
|
1327
|
+
titles_disabled = with_unsafe_raw_sql_disabled { Post.pluck("[dbo].[posts].[title]") }
|
|
1328
|
+
|
|
1329
|
+
assert_equal titles_expected, titles_depr
|
|
1330
|
+
assert_equal titles_expected, titles_disabled
|
|
1331
|
+
end
|
|
1332
|
+
|
|
1333
|
+
test "pluck: allows string column name that are quoted with table, user and database" do
|
|
1334
|
+
titles_expected = Post.pluck(Arel.sql("title"))
|
|
1335
|
+
|
|
1336
|
+
titles_depr = with_unsafe_raw_sql_deprecated { Post.pluck("[activerecord_unittest].[dbo].[posts].[title]") }
|
|
1337
|
+
titles_disabled = with_unsafe_raw_sql_disabled { Post.pluck("[activerecord_unittest].[dbo].[posts].[title]") }
|
|
1338
|
+
|
|
1339
|
+
assert_equal titles_expected, titles_depr
|
|
1340
|
+
assert_equal titles_expected, titles_disabled
|
|
1341
|
+
end
|
|
1342
|
+
end
|
|
1135
1343
|
|
|
1136
1344
|
class ReservedWordTest < ActiveRecord::TestCase
|
|
1137
1345
|
coerce_tests! :test_change_columns
|
|
@@ -1143,32 +1351,29 @@ class ReservedWordTest < ActiveRecord::TestCase
|
|
|
1143
1351
|
end
|
|
1144
1352
|
end
|
|
1145
1353
|
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
1354
|
class OptimisticLockingTest < ActiveRecord::TestCase
|
|
1149
1355
|
# We do not allow updating identities, but we can test using a non-identity key
|
|
1150
1356
|
coerce_tests! :test_update_with_dirty_primary_key
|
|
1151
1357
|
def test_update_with_dirty_primary_key_coerced
|
|
1152
1358
|
assert_raises(ActiveRecord::RecordNotUnique) do
|
|
1153
|
-
record = StringKeyObject.find(
|
|
1154
|
-
record.id =
|
|
1359
|
+
record = StringKeyObject.find("record1")
|
|
1360
|
+
record.id = "record2"
|
|
1155
1361
|
record.save!
|
|
1156
1362
|
end
|
|
1157
1363
|
|
|
1158
|
-
record = StringKeyObject.find(
|
|
1159
|
-
record.id =
|
|
1364
|
+
record = StringKeyObject.find("record1")
|
|
1365
|
+
record.id = "record42"
|
|
1160
1366
|
record.save!
|
|
1161
1367
|
|
|
1162
|
-
assert StringKeyObject.find(
|
|
1368
|
+
assert StringKeyObject.find("record42")
|
|
1163
1369
|
assert_raises(ActiveRecord::RecordNotFound) do
|
|
1164
|
-
StringKeyObject.find(
|
|
1370
|
+
StringKeyObject.find("record1")
|
|
1165
1371
|
end
|
|
1166
1372
|
end
|
|
1167
1373
|
end
|
|
1168
1374
|
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
1375
|
class RelationMergingTest < ActiveRecord::TestCase
|
|
1376
|
+
# Use nvarchar string (N'') in assert
|
|
1172
1377
|
coerce_tests! :test_merging_with_order_with_binds
|
|
1173
1378
|
def test_merging_with_order_with_binds_coerced
|
|
1174
1379
|
relation = Post.all.merge(Post.order([Arel.sql("title LIKE ?"), "%suffix"]))
|
|
@@ -1176,8 +1381,144 @@ class RelationMergingTest < ActiveRecord::TestCase
|
|
|
1176
1381
|
end
|
|
1177
1382
|
end
|
|
1178
1383
|
|
|
1384
|
+
module ActiveRecord
|
|
1385
|
+
class DatabaseTasksTruncateAllTest < ActiveRecord::TestCase
|
|
1386
|
+
# SQL Server does not allow truncation of tables that are referenced by foreign key
|
|
1387
|
+
# constraints. As this test truncates all tables we would need to remove all foreign
|
|
1388
|
+
# key constraints and then restore them afterwards to get this test to pass.
|
|
1389
|
+
coerce_tests! :test_truncate_tables
|
|
1390
|
+
end
|
|
1391
|
+
end
|
|
1392
|
+
|
|
1393
|
+
require "models/book"
|
|
1394
|
+
class EnumTest < ActiveRecord::TestCase
|
|
1395
|
+
# Need to remove index as SQL Server considers NULLs on a unique-index to be equal unlike PostgreSQL/MySQL/SQLite.
|
|
1396
|
+
coerce_tests! %r{enums are distinct per class}
|
|
1397
|
+
test "enums are distinct per class coerced" do
|
|
1398
|
+
Book.connection.remove_index(:books, column: [:author_id, :name])
|
|
1399
|
+
|
|
1400
|
+
send(:'original_enums are distinct per class')
|
|
1401
|
+
ensure
|
|
1402
|
+
Book.connection.add_index(:books, [:author_id, :name], unique: true)
|
|
1403
|
+
end
|
|
1404
|
+
|
|
1405
|
+
# Need to remove index as SQL Server considers NULLs on a unique-index to be equal unlike PostgreSQL/MySQL/SQLite.
|
|
1406
|
+
coerce_tests! %r{creating new objects with enum scopes}
|
|
1407
|
+
test "creating new objects with enum scopes coerced" do
|
|
1408
|
+
Book.connection.remove_index(:books, column: [:author_id, :name])
|
|
1409
|
+
|
|
1410
|
+
send(:'original_creating new objects with enum scopes')
|
|
1411
|
+
ensure
|
|
1412
|
+
Book.connection.add_index(:books, [:author_id, :name], unique: true)
|
|
1413
|
+
end
|
|
1414
|
+
|
|
1415
|
+
# Need to remove index as SQL Server considers NULLs on a unique-index to be equal unlike PostgreSQL/MySQL/SQLite.
|
|
1416
|
+
coerce_tests! %r{enums are inheritable}
|
|
1417
|
+
test "enums are inheritable coerced" do
|
|
1418
|
+
Book.connection.remove_index(:books, column: [:author_id, :name])
|
|
1419
|
+
|
|
1420
|
+
send(:'original_enums are inheritable')
|
|
1421
|
+
ensure
|
|
1422
|
+
Book.connection.add_index(:books, [:author_id, :name], unique: true)
|
|
1423
|
+
end
|
|
1424
|
+
|
|
1425
|
+
# Need to remove index as SQL Server considers NULLs on a unique-index to be equal unlike PostgreSQL/MySQL/SQLite.
|
|
1426
|
+
coerce_tests! %r{declare multiple enums at a time}
|
|
1427
|
+
test "declare multiple enums at a time coerced" do
|
|
1428
|
+
Book.connection.remove_index(:books, column: [:author_id, :name])
|
|
1429
|
+
|
|
1430
|
+
send(:'original_declare multiple enums at a time')
|
|
1431
|
+
ensure
|
|
1432
|
+
Book.connection.add_index(:books, [:author_id, :name], unique: true)
|
|
1433
|
+
end
|
|
1434
|
+
end
|
|
1435
|
+
|
|
1436
|
+
require "models/task"
|
|
1437
|
+
class QueryCacheExpiryTest < ActiveRecord::TestCase
|
|
1438
|
+
# SQL Server does not support skipping or upserting duplicates.
|
|
1439
|
+
coerce_tests! :test_insert_all
|
|
1440
|
+
def test_insert_all_coerced
|
|
1441
|
+
assert_raises(ArgumentError, /does not support skipping duplicates/) do
|
|
1442
|
+
Task.cache { Task.insert({ starting: Time.now }) }
|
|
1443
|
+
end
|
|
1444
|
+
|
|
1445
|
+
assert_called(ActiveRecord::Base.connection, :clear_query_cache, times: 2) do
|
|
1446
|
+
Task.cache { Task.insert_all!([{ starting: Time.now }]) }
|
|
1447
|
+
end
|
|
1448
|
+
|
|
1449
|
+
assert_called(ActiveRecord::Base.connection, :clear_query_cache, times: 2) do
|
|
1450
|
+
Task.cache { Task.insert!({ starting: Time.now }) }
|
|
1451
|
+
end
|
|
1452
|
+
|
|
1453
|
+
assert_called(ActiveRecord::Base.connection, :clear_query_cache, times: 2) do
|
|
1454
|
+
Task.cache { Task.insert_all!([{ starting: Time.now }]) }
|
|
1455
|
+
end
|
|
1456
|
+
|
|
1457
|
+
assert_raises(ArgumentError, /does not support upsert/) do
|
|
1458
|
+
Task.cache { Task.upsert({ starting: Time.now }) }
|
|
1459
|
+
end
|
|
1460
|
+
|
|
1461
|
+
assert_raises(ArgumentError, /does not support upsert/) do
|
|
1462
|
+
Task.cache { Task.upsert_all([{ starting: Time.now }]) }
|
|
1463
|
+
end
|
|
1464
|
+
end
|
|
1465
|
+
end
|
|
1179
1466
|
|
|
1467
|
+
require "models/citation"
|
|
1180
1468
|
class EagerLoadingTooManyIdsTest < ActiveRecord::TestCase
|
|
1181
|
-
#
|
|
1469
|
+
# Original Rails test fails with SQL Server error message "The query processor ran out of internal resources and
|
|
1470
|
+
# could not produce a query plan". This error goes away if you change database compatibility level to 110 (SQL 2012)
|
|
1471
|
+
# (see https://www.mssqltips.com/sqlservertip/5279/sql-server-error-query-processor-ran-out-of-internal-resources-and-could-not-produce-a-query-plan/).
|
|
1472
|
+
# However, you cannot change the compatibility level during a test. The purpose of the test is to ensure that an
|
|
1473
|
+
# unprepared statement is used if the number of values exceeds the adapter's `bind_params_length`. The coerced test
|
|
1474
|
+
# still does this as there will be 32,768 remaining citation records in the database and the `bind_params_length` of
|
|
1475
|
+
# adapter is 2,098.
|
|
1182
1476
|
coerce_tests! :test_eager_loading_too_may_ids
|
|
1477
|
+
def test_eager_loading_too_may_ids_coerced
|
|
1478
|
+
# Remove excess records.
|
|
1479
|
+
Citation.limit(32768).order(id: :desc).delete_all
|
|
1480
|
+
|
|
1481
|
+
# Perform test
|
|
1482
|
+
citation_count = Citation.count
|
|
1483
|
+
assert_sql(/WHERE \(\[citations\]\.\[id\] IN \(0, 1/) do
|
|
1484
|
+
assert_equal citation_count, Citation.eager_load(:citations).offset(0).size
|
|
1485
|
+
end
|
|
1486
|
+
end
|
|
1487
|
+
end
|
|
1488
|
+
|
|
1489
|
+
class LogSubscriberTest < ActiveRecord::TestCase
|
|
1490
|
+
# Call original test from coerced test. Fixes issue on CI with Rails installed as a gem.
|
|
1491
|
+
coerce_tests! :test_vebose_query_logs
|
|
1492
|
+
def test_vebose_query_logs_coerced
|
|
1493
|
+
original_test_vebose_query_logs
|
|
1494
|
+
end
|
|
1495
|
+
end
|
|
1496
|
+
|
|
1497
|
+
class ActiveRecordSchemaTest < ActiveRecord::TestCase
|
|
1498
|
+
# Workaround for randomly failing test.
|
|
1499
|
+
coerce_tests! :test_has_primary_key
|
|
1500
|
+
def test_has_primary_key_coerced
|
|
1501
|
+
@schema_migration.reset_column_information
|
|
1502
|
+
original_test_has_primary_key
|
|
1503
|
+
end
|
|
1504
|
+
end
|
|
1505
|
+
|
|
1506
|
+
module ActiveRecord
|
|
1507
|
+
module ConnectionAdapters
|
|
1508
|
+
class ReaperTest < ActiveRecord::TestCase
|
|
1509
|
+
# Coerce can be removed if Rails version > 6.0.3
|
|
1510
|
+
coerce_tests! :test_connection_pool_starts_reaper_in_fork unless Process.respond_to?(:fork)
|
|
1511
|
+
end
|
|
1512
|
+
end
|
|
1513
|
+
end
|
|
1514
|
+
|
|
1515
|
+
class FixturesTest < ActiveRecord::TestCase
|
|
1516
|
+
# Skip test on Windows. Skip can be removed when Rails PR https://github.com/rails/rails/pull/39234 has been merged.
|
|
1517
|
+
coerce_tests! :test_binary_in_fixtures if RbConfig::CONFIG["host_os"] =~ /mswin|mingw/
|
|
1518
|
+
end
|
|
1519
|
+
|
|
1520
|
+
class ReloadModelsTest < ActiveRecord::TestCase
|
|
1521
|
+
# Skip test on Windows. The number of arguements passed to `IO.popen` in
|
|
1522
|
+
# `activesupport/lib/active_support/testing/isolation.rb` exceeds what Windows can handle.
|
|
1523
|
+
coerce_tests! :test_has_one_with_reload if RbConfig::CONFIG["host_os"] =~ /mswin|mingw/
|
|
1183
1524
|
end
|