activerecord-sqlserver-adapter 6.0.0.rc2 → 6.1.0.0
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/CHANGELOG.md +20 -41
- data/README.md +32 -3
- data/RUNNING_UNIT_TESTS.md +1 -1
- data/VERSION +1 -1
- data/activerecord-sqlserver-adapter.gemspec +1 -1
- data/lib/active_record/connection_adapters/sqlserver/core_ext/calculations.rb +0 -9
- data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +7 -2
- data/lib/active_record/connection_adapters/sqlserver/database_limits.rb +0 -4
- data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +28 -16
- data/lib/active_record/connection_adapters/sqlserver/quoting.rb +7 -7
- data/lib/active_record/connection_adapters/sqlserver/schema_creation.rb +22 -1
- data/lib/active_record/connection_adapters/sqlserver/schema_dumper.rb +9 -3
- data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +31 -8
- data/lib/active_record/connection_adapters/sqlserver/sql_type_metadata.rb +27 -7
- data/lib/active_record/connection_adapters/sqlserver/table_definition.rb +0 -1
- data/lib/active_record/connection_adapters/sqlserver/transaction.rb +2 -2
- data/lib/active_record/connection_adapters/sqlserver/type.rb +1 -0
- data/lib/active_record/connection_adapters/sqlserver/type/decimal_without_scale.rb +22 -0
- data/lib/active_record/connection_adapters/sqlserver/utils.rb +1 -1
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +100 -68
- data/lib/active_record/connection_adapters/sqlserver_column.rb +17 -0
- data/lib/active_record/sqlserver_base.rb +9 -15
- data/lib/active_record/tasks/sqlserver_database_tasks.rb +17 -14
- data/lib/arel/visitors/sqlserver.rb +111 -39
- data/test/cases/adapter_test_sqlserver.rb +48 -14
- data/test/cases/change_column_collation_test_sqlserver.rb +33 -0
- data/test/cases/coerced_tests.rb +598 -78
- data/test/cases/column_test_sqlserver.rb +5 -2
- data/test/cases/disconnected_test_sqlserver.rb +39 -0
- data/test/cases/execute_procedure_test_sqlserver.rb +9 -0
- data/test/cases/in_clause_test_sqlserver.rb +27 -0
- data/test/cases/lateral_test_sqlserver.rb +35 -0
- data/test/cases/migration_test_sqlserver.rb +51 -0
- data/test/cases/optimizer_hints_test_sqlserver.rb +72 -0
- data/test/cases/order_test_sqlserver.rb +7 -0
- data/test/cases/primary_keys_test_sqlserver.rb +103 -0
- data/test/cases/rake_test_sqlserver.rb +3 -2
- data/test/cases/schema_dumper_test_sqlserver.rb +20 -3
- data/test/migrations/create_clients_and_change_column_collation.rb +19 -0
- data/test/models/sqlserver/sst_string_collation.rb +3 -0
- data/test/schema/sqlserver_specific_schema.rb +17 -0
- data/test/support/marshal_compatibility_fixtures/SQLServer/rails_6_0_topic.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/SQLServer/rails_6_0_topic_associations.dump +0 -0
- data/test/support/sql_counter_sqlserver.rb +14 -12
- metadata +32 -13
- data/.travis.yml +0 -23
@@ -157,13 +157,16 @@ class ColumnTestSQLServer < ActiveRecord::TestCase
|
|
157
157
|
_(col.default).must_equal BigDecimal("191")
|
158
158
|
_(obj.numeric_18_0).must_equal BigDecimal("191")
|
159
159
|
_(col.default_function).must_be_nil
|
160
|
+
|
160
161
|
type = connection.lookup_cast_type_from_column(col)
|
161
|
-
_(type).must_be_instance_of Type::
|
162
|
+
_(type).must_be_instance_of Type::DecimalWithoutScale
|
162
163
|
_(type.limit).must_be_nil
|
163
164
|
_(type.precision).must_equal 18
|
164
|
-
_(type.scale).
|
165
|
+
_(type.scale).must_be_nil
|
166
|
+
|
165
167
|
obj.numeric_18_0 = "192.1"
|
166
168
|
_(obj.numeric_18_0).must_equal BigDecimal("192")
|
169
|
+
|
167
170
|
obj.save!
|
168
171
|
_(obj.reload.numeric_18_0).must_equal BigDecimal("192")
|
169
172
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "cases/helper_sqlserver"
|
4
|
+
|
5
|
+
class TestDisconnectedAdapter < ActiveRecord::TestCase
|
6
|
+
self.use_transactional_tests = false
|
7
|
+
|
8
|
+
def setup
|
9
|
+
@connection = ActiveRecord::Base.connection
|
10
|
+
end
|
11
|
+
|
12
|
+
teardown do
|
13
|
+
return if in_memory_db?
|
14
|
+
db_config = ActiveRecord::Base.connection_db_config
|
15
|
+
ActiveRecord::Base.establish_connection(db_config)
|
16
|
+
end
|
17
|
+
|
18
|
+
test "can't execute procedures while disconnected" do
|
19
|
+
@connection.execute_procedure :sp_tables, "sst_datatypes"
|
20
|
+
@connection.disconnect!
|
21
|
+
assert_raises(ActiveRecord::ConnectionNotEstablished, 'SQL Server client is not connected') do
|
22
|
+
@connection.execute_procedure :sp_tables, "sst_datatypes"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
test "can't execute query while disconnected" do
|
27
|
+
sql = "SELECT count(*) from products WHERE id IN(@0, @1)"
|
28
|
+
binds = [
|
29
|
+
ActiveRecord::Relation::QueryAttribute.new("id", 2, ActiveRecord::Type::BigInteger.new),
|
30
|
+
ActiveRecord::Relation::QueryAttribute.new("id", 2, ActiveRecord::Type::BigInteger.new)
|
31
|
+
]
|
32
|
+
|
33
|
+
@connection.exec_query sql, "TEST", binds
|
34
|
+
@connection.disconnect!
|
35
|
+
assert_raises(ActiveRecord::ConnectionNotEstablished, 'SQL Server client is not connected') do
|
36
|
+
@connection.exec_query sql, "TEST", binds
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -41,4 +41,13 @@ class ExecuteProcedureTestSQLServer < ActiveRecord::TestCase
|
|
41
41
|
date_base = connection.select_value("select GETUTCDATE()")
|
42
42
|
assert_equal date_base.change(usec: 0), date_proc.change(usec: 0)
|
43
43
|
end
|
44
|
+
|
45
|
+
it 'test deprecation with transaction return when executing procedure' do
|
46
|
+
assert_deprecated do
|
47
|
+
ActiveRecord::Base.transaction do
|
48
|
+
connection.execute_procedure("my_getutcdate")
|
49
|
+
return
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
44
53
|
end
|
@@ -33,4 +33,31 @@ class InClauseTestSQLServer < ActiveRecord::TestCase
|
|
33
33
|
assert_includes posts.to_sql, "ORDER BY [authors].[name]"
|
34
34
|
assert_equal 8, posts.length
|
35
35
|
end
|
36
|
+
|
37
|
+
it "removes ordering from 'not' subqueries" do
|
38
|
+
authors_subquery = Author.where.not(name: ["Mary", "Bob"]).order(:name)
|
39
|
+
posts = Post.where(author: authors_subquery)
|
40
|
+
|
41
|
+
assert_includes authors_subquery.to_sql, "ORDER BY [authors].[name]"
|
42
|
+
assert_not_includes posts.to_sql, "ORDER BY [authors].[name]"
|
43
|
+
assert_equal 5, posts.length
|
44
|
+
end
|
45
|
+
|
46
|
+
it "does not remove ordering from 'not' subquery that includes a limit" do
|
47
|
+
authors_subquery = Author.where.not(name: ["Ronan", "Mary", "Bob"]).order(:name).limit(2)
|
48
|
+
posts = Post.where(author: authors_subquery)
|
49
|
+
|
50
|
+
assert_includes authors_subquery.to_sql, "ORDER BY [authors].[name]"
|
51
|
+
assert_includes posts.to_sql, "ORDER BY [authors].[name]"
|
52
|
+
assert_equal 5, posts.length
|
53
|
+
end
|
54
|
+
|
55
|
+
it "does not remove ordering from 'not' subquery that includes an offset" do
|
56
|
+
authors_subquery = Author.where.not(name: ["David", "Ronan", "Cian"]).order(:name).offset(1)
|
57
|
+
posts = Post.where(author: authors_subquery)
|
58
|
+
|
59
|
+
assert_includes authors_subquery.to_sql, "ORDER BY [authors].[name]"
|
60
|
+
assert_includes posts.to_sql, "ORDER BY [authors].[name]"
|
61
|
+
assert_equal 3, posts.length
|
62
|
+
end
|
36
63
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "cases/helper_sqlserver"
|
4
|
+
require "models/post"
|
5
|
+
require "models/author"
|
6
|
+
|
7
|
+
class LateralTestSQLServer < ActiveRecord::TestCase
|
8
|
+
fixtures :posts, :authors
|
9
|
+
|
10
|
+
it 'uses OUTER APPLY for OUTER JOIN LATERAL' do
|
11
|
+
post = Arel::Table.new(:posts)
|
12
|
+
author = Arel::Table.new(:authors)
|
13
|
+
subselect = post.project(Arel.star).take(1).where(post[:author_id].eq(author[:id])).where(post[:id].eq(42))
|
14
|
+
|
15
|
+
one = Arel::Nodes::Quoted.new(1)
|
16
|
+
eq = Arel::Nodes::Equality.new(one, one)
|
17
|
+
|
18
|
+
sql = author.project(Arel.star).where(author[:name].matches("David")).outer_join(subselect.lateral.as("bar")).on(eq).to_sql
|
19
|
+
results = ActiveRecord::Base.connection.exec_query sql
|
20
|
+
assert_equal sql, "SELECT * FROM [authors] OUTER APPLY (SELECT * FROM [posts] WHERE [posts].[author_id] = [authors].[id] AND [posts].[id] = 42 ORDER BY [posts].[id] ASC OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY) AS bar WHERE [authors].[name] LIKE N'David'"
|
21
|
+
assert_equal results.length, 1
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'uses CROSS APPLY for INNER JOIN LATERAL' do
|
25
|
+
post = Arel::Table.new(:posts)
|
26
|
+
author = Arel::Table.new(:authors)
|
27
|
+
subselect = post.project(Arel.star).take(1).where(post[:author_id].eq(author[:id])).where(post[:id].eq(42))
|
28
|
+
|
29
|
+
sql = author.project(Arel.star).where(author[:name].matches("David")).join(subselect.lateral.as("bar")).to_sql
|
30
|
+
results = ActiveRecord::Base.connection.exec_query sql
|
31
|
+
|
32
|
+
assert_equal sql, "SELECT * FROM [authors] CROSS APPLY (SELECT * FROM [posts] WHERE [posts].[author_id] = [authors].[id] AND [posts].[id] = 42 ORDER BY [posts].[id] ASC OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY) AS bar WHERE [authors].[name] LIKE N'David'"
|
33
|
+
assert_equal results.length, 0
|
34
|
+
end
|
35
|
+
end
|
@@ -63,5 +63,56 @@ class MigrationTestSQLServer < ActiveRecord::TestCase
|
|
63
63
|
it "change null and default" do
|
64
64
|
assert_nothing_raised { connection.change_column :people, :first_name, :text, null: true, default: nil }
|
65
65
|
end
|
66
|
+
|
67
|
+
it "change collation" do
|
68
|
+
assert_nothing_raised { connection.change_column :sst_string_collation, :string_with_collation, :varchar, collation: :SQL_Latin1_General_CP437_BIN }
|
69
|
+
|
70
|
+
SstStringCollation.reset_column_information
|
71
|
+
assert_equal "SQL_Latin1_General_CP437_BIN", SstStringCollation.columns_hash['string_with_collation'].collation
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe "#create_schema" do
|
76
|
+
it "creates a new schema" do
|
77
|
+
connection.create_schema("some schema")
|
78
|
+
|
79
|
+
schemas = connection.exec_query("select name from sys.schemas").to_a
|
80
|
+
|
81
|
+
assert_includes schemas, { "name" => "some schema" }
|
82
|
+
end
|
83
|
+
|
84
|
+
it "creates a new schema with an owner" do
|
85
|
+
connection.create_schema("some schema", :guest)
|
86
|
+
|
87
|
+
schemas = connection.exec_query("select name, principal_id from sys.schemas").to_a
|
88
|
+
|
89
|
+
assert_includes schemas, { "name" => "some schema", "principal_id" => 2 }
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe "#change_table_schema" do
|
94
|
+
before { connection.create_schema("foo") }
|
95
|
+
|
96
|
+
it "transfer the given table to the given schema" do
|
97
|
+
connection.change_table_schema("foo", "orders")
|
98
|
+
|
99
|
+
assert connection.data_source_exists?("foo.orders")
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
describe "#drop_schema" do
|
104
|
+
before { connection.create_schema("some schema") }
|
105
|
+
|
106
|
+
it "drops a schema" do
|
107
|
+
schemas = connection.exec_query("select name from sys.schemas").to_a
|
108
|
+
|
109
|
+
assert_includes schemas, { "name" => "some schema" }
|
110
|
+
|
111
|
+
connection.drop_schema("some schema")
|
112
|
+
|
113
|
+
schemas = connection.exec_query("select name from sys.schemas").to_a
|
114
|
+
|
115
|
+
refute_includes schemas, { "name" => "some schema" }
|
116
|
+
end
|
66
117
|
end
|
67
118
|
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "cases/helper_sqlserver"
|
4
|
+
require "models/company"
|
5
|
+
|
6
|
+
class OptimizerHitsTestSQLServer < ActiveRecord::TestCase
|
7
|
+
fixtures :companies
|
8
|
+
|
9
|
+
it "apply optimizations" do
|
10
|
+
assert_sql(%r{\ASELECT .+ FROM .+ OPTION \(HASH GROUP\)\z}) do
|
11
|
+
companies = Company.optimizer_hints("HASH GROUP")
|
12
|
+
companies = companies.distinct.select("firm_id")
|
13
|
+
assert_includes companies.explain, "| Hash Match | Aggregate |"
|
14
|
+
end
|
15
|
+
|
16
|
+
assert_sql(%r{\ASELECT .+ FROM .+ OPTION \(ORDER GROUP\)\z}) do
|
17
|
+
companies = Company.optimizer_hints("ORDER GROUP")
|
18
|
+
companies = companies.distinct.select("firm_id")
|
19
|
+
assert_includes companies.explain, "| Stream Aggregate | Aggregate |"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
it "apply multiple optimizations" do
|
24
|
+
assert_sql(%r{\ASELECT .+ FROM .+ OPTION \(HASH GROUP, FAST 1\)\z}) do
|
25
|
+
companies = Company.optimizer_hints("HASH GROUP", "FAST 1")
|
26
|
+
companies = companies.distinct.select("firm_id")
|
27
|
+
assert_includes companies.explain, "| Hash Match | Flow Distinct |"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
it "support subqueries" do
|
32
|
+
assert_sql(%r{.*'SELECT COUNT\(count_column\) FROM \(SELECT .*\) subquery_for_count OPTION \(MAXDOP 2\)'.*}) do
|
33
|
+
companies = Company.optimizer_hints("MAXDOP 2")
|
34
|
+
companies = companies.select(:id).where(firm_id: [0, 1]).limit(3)
|
35
|
+
assert_equal 3, companies.count
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
it "sanitize values" do
|
40
|
+
assert_sql(%r{\ASELECT .+ FROM .+ OPTION \(HASH GROUP\)\z}) do
|
41
|
+
companies = Company.optimizer_hints("OPTION (HASH GROUP)")
|
42
|
+
companies = companies.distinct.select("firm_id")
|
43
|
+
companies.to_a
|
44
|
+
end
|
45
|
+
|
46
|
+
assert_sql(%r{\ASELECT .+ FROM .+ OPTION \(HASH GROUP\)\z}) do
|
47
|
+
companies = Company.optimizer_hints("OPTION(HASH GROUP)")
|
48
|
+
companies = companies.distinct.select("firm_id")
|
49
|
+
companies.to_a
|
50
|
+
end
|
51
|
+
|
52
|
+
assert_sql(%r{\ASELECT .+ FROM .+ OPTION \(TABLE HINT \(\[companies\], INDEX\(1\)\)\)\z}) do
|
53
|
+
companies = Company.optimizer_hints("OPTION(TABLE HINT ([companies], INDEX(1)))")
|
54
|
+
companies = companies.distinct.select("firm_id")
|
55
|
+
companies.to_a
|
56
|
+
end
|
57
|
+
|
58
|
+
assert_sql(%r{\ASELECT .+ FROM .+ OPTION \(HASH GROUP\)\z}) do
|
59
|
+
companies = Company.optimizer_hints("Option(HASH GROUP)")
|
60
|
+
companies = companies.distinct.select("firm_id")
|
61
|
+
companies.to_a
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
it "skip optimization after unscope" do
|
66
|
+
assert_sql("SELECT DISTINCT [companies].[firm_id] FROM [companies]") do
|
67
|
+
companies = Company.optimizer_hints("HASH GROUP")
|
68
|
+
companies = companies.distinct.select("firm_id")
|
69
|
+
companies.unscope(:optimizer_hints).load
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -143,4 +143,11 @@ class OrderTestSQLServer < ActiveRecord::TestCase
|
|
143
143
|
assert_equal post1, Post.order(Arel.sql(order)).first
|
144
144
|
assert_equal post2, Post.order(Arel.sql(order)).second
|
145
145
|
end
|
146
|
+
|
147
|
+
# Executing this kind of queries will raise "A column has been specified more than once in the order by list"
|
148
|
+
# This test shows that we don't do anything to prevent this
|
149
|
+
it "doesn't deduplicate semantically equal orders" do
|
150
|
+
sql = Post.order(:id).order("posts.id ASC").to_sql
|
151
|
+
assert_equal "SELECT [posts].* FROM [posts] ORDER BY [posts].[id] ASC, posts.id ASC", sql
|
152
|
+
end
|
146
153
|
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "cases/helper_sqlserver"
|
4
|
+
require "support/schema_dumping_helper"
|
5
|
+
|
6
|
+
class PrimaryKeyUuidTypeTest < ActiveRecord::TestCase
|
7
|
+
include SchemaDumpingHelper
|
8
|
+
|
9
|
+
self.use_transactional_tests = false
|
10
|
+
|
11
|
+
class Barcode < ActiveRecord::Base
|
12
|
+
end
|
13
|
+
|
14
|
+
setup do
|
15
|
+
@connection = ActiveRecord::Base.connection
|
16
|
+
@connection.create_table(:barcodes, primary_key: "code", id: :uuid, force: true)
|
17
|
+
end
|
18
|
+
|
19
|
+
teardown do
|
20
|
+
@connection.drop_table(:barcodes, if_exists: true)
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_any_type_primary_key
|
24
|
+
assert_equal "code", Barcode.primary_key
|
25
|
+
|
26
|
+
column = Barcode.column_for_attribute(Barcode.primary_key)
|
27
|
+
assert_not column.null
|
28
|
+
assert_equal :uuid, column.type
|
29
|
+
assert_not_predicate column, :is_identity?
|
30
|
+
assert_predicate column, :is_primary?
|
31
|
+
ensure
|
32
|
+
Barcode.reset_column_information
|
33
|
+
end
|
34
|
+
|
35
|
+
test "schema dump primary key includes default" do
|
36
|
+
schema = dump_table_schema "barcodes"
|
37
|
+
assert_match %r/create_table "barcodes", primary_key: "code", id: :uuid, default: -> { "newid\(\)" }/, schema
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class PrimaryKeyIntegerTest < ActiveRecord::TestCase
|
42
|
+
include SchemaDumpingHelper
|
43
|
+
|
44
|
+
self.use_transactional_tests = false
|
45
|
+
|
46
|
+
class Barcode < ActiveRecord::Base
|
47
|
+
end
|
48
|
+
|
49
|
+
class Widget < ActiveRecord::Base
|
50
|
+
end
|
51
|
+
|
52
|
+
setup do
|
53
|
+
@connection = ActiveRecord::Base.connection
|
54
|
+
end
|
55
|
+
|
56
|
+
teardown do
|
57
|
+
@connection.drop_table :barcodes, if_exists: true
|
58
|
+
@connection.drop_table :widgets, if_exists: true
|
59
|
+
end
|
60
|
+
|
61
|
+
test "integer primary key without default" do
|
62
|
+
@connection.create_table(:widgets, id: :integer, force: true)
|
63
|
+
column = @connection.columns(:widgets).find { |c| c.name == "id" }
|
64
|
+
assert_predicate column, :is_primary?
|
65
|
+
assert_predicate column, :is_identity?
|
66
|
+
assert_equal :integer, column.type
|
67
|
+
assert_not_predicate column, :bigint?
|
68
|
+
|
69
|
+
schema = dump_table_schema "widgets"
|
70
|
+
assert_match %r/create_table "widgets", id: :integer, force: :cascade do/, schema
|
71
|
+
end
|
72
|
+
|
73
|
+
test "bigint primary key without default" do
|
74
|
+
@connection.create_table(:widgets, id: :bigint, force: true)
|
75
|
+
column = @connection.columns(:widgets).find { |c| c.name == "id" }
|
76
|
+
assert_predicate column, :is_primary?
|
77
|
+
assert_predicate column, :is_identity?
|
78
|
+
assert_equal :integer, column.type
|
79
|
+
assert_predicate column, :bigint?
|
80
|
+
|
81
|
+
schema = dump_table_schema "widgets"
|
82
|
+
assert_match %r/create_table "widgets", force: :cascade do/, schema
|
83
|
+
end
|
84
|
+
|
85
|
+
test "don't set identity to integer and bigint when there is a default" do
|
86
|
+
@connection.create_table(:barcodes, id: :integer, default: nil, force: true)
|
87
|
+
@connection.create_table(:widgets, id: :bigint, default: nil, force: true)
|
88
|
+
|
89
|
+
column = @connection.columns(:widgets).find { |c| c.name == "id" }
|
90
|
+
assert_predicate column, :is_primary?
|
91
|
+
assert_not_predicate column, :is_identity?
|
92
|
+
|
93
|
+
schema = dump_table_schema "widgets"
|
94
|
+
assert_match %r/create_table "widgets", id: :bigint, default: nil, force: :cascade do/, schema
|
95
|
+
|
96
|
+
column = @connection.columns(:barcodes).find { |c| c.name == "id" }
|
97
|
+
assert_predicate column, :is_primary?
|
98
|
+
assert_not_predicate column, :is_identity?
|
99
|
+
|
100
|
+
schema = dump_table_schema "barcodes"
|
101
|
+
assert_match %r/create_table "barcodes", id: :integer, default: nil, force: :cascade do/, schema
|
102
|
+
end
|
103
|
+
end
|
@@ -10,8 +10,9 @@ class SQLServerRakeTest < ActiveRecord::TestCase
|
|
10
10
|
|
11
11
|
let(:db_tasks) { ActiveRecord::Tasks::DatabaseTasks }
|
12
12
|
let(:new_database) { "activerecord_unittest_tasks" }
|
13
|
-
let(:default_configuration) { ARTest.
|
13
|
+
let(:default_configuration) { ARTest.test_configuration_hashes["arunit"] }
|
14
14
|
let(:configuration) { default_configuration.merge("database" => new_database) }
|
15
|
+
let(:db_config) { ActiveRecord::Base.configurations.resolve(configuration) }
|
15
16
|
|
16
17
|
before { skip "on azure" if azure_skip }
|
17
18
|
before { disconnect! unless azure_skip }
|
@@ -151,7 +152,7 @@ class SQLServerRakeStructureDumpLoadTest < SQLServerRakeTest
|
|
151
152
|
_(filedata).must_match %r{CREATE TABLE dbo\.users}
|
152
153
|
db_tasks.purge(configuration)
|
153
154
|
_(connection.tables).wont_include "users"
|
154
|
-
db_tasks.load_schema
|
155
|
+
db_tasks.load_schema db_config, :sql, filename
|
155
156
|
_(connection.tables).must_include "users"
|
156
157
|
end
|
157
158
|
end
|
@@ -16,7 +16,7 @@ class SchemaDumperTestSQLServer < ActiveRecord::TestCase
|
|
16
16
|
assert_line :tinyint, type: "integer", limit: 1, precision: nil, scale: nil, default: 42
|
17
17
|
assert_line :bit, type: "boolean", limit: nil, precision: nil, scale: nil, default: true
|
18
18
|
assert_line :decimal_9_2, type: "decimal", limit: nil, precision: 9, scale: 2, default: 12345.01
|
19
|
-
assert_line :numeric_18_0, type: "decimal", limit: nil, precision: 18, scale:
|
19
|
+
assert_line :numeric_18_0, type: "decimal", limit: nil, precision: 18, scale: nil, default: 191
|
20
20
|
assert_line :numeric_36_2, type: "decimal", limit: nil, precision: 36, scale: 2, default: 12345678901234567890.01
|
21
21
|
assert_line :money, type: "money", limit: nil, precision: 19, scale: 4, default: 4.2
|
22
22
|
assert_line :smallmoney, type: "smallmoney", limit: nil, precision: 10, scale: 4, default: 4.2
|
@@ -75,7 +75,7 @@ class SchemaDumperTestSQLServer < ActiveRecord::TestCase
|
|
75
75
|
assert_line :integer_col, type: "integer", limit: nil, precision: nil, scale: nil, default: nil
|
76
76
|
assert_line :bigint_col, type: "bigint", limit: nil, precision: nil, scale: nil, default: nil
|
77
77
|
assert_line :boolean_col, type: "boolean", limit: nil, precision: nil, scale: nil, default: nil
|
78
|
-
assert_line :decimal_col, type: "decimal", limit: nil, precision: 18, scale:
|
78
|
+
assert_line :decimal_col, type: "decimal", limit: nil, precision: 18, scale: nil, default: nil
|
79
79
|
assert_line :float_col, type: "float", limit: nil, precision: nil, scale: nil, default: nil
|
80
80
|
assert_line :string_col, type: "string", limit: nil, precision: nil, scale: nil, default: nil
|
81
81
|
assert_line :text_col, type: "text", limit: nil, precision: nil, scale: nil, default: nil
|
@@ -119,6 +119,15 @@ class SchemaDumperTestSQLServer < ActiveRecord::TestCase
|
|
119
119
|
assert_line :json_col, type: "text", limit: nil, precision: nil, scale: nil, default: nil
|
120
120
|
end
|
121
121
|
|
122
|
+
it "dump column collation" do
|
123
|
+
generate_schema_for_table('sst_string_collation')
|
124
|
+
|
125
|
+
assert_line :string_without_collation, type: "string", limit: nil, default: nil, collation: nil
|
126
|
+
assert_line :string_default_collation, type: "varchar", limit: nil, default: nil, collation: nil
|
127
|
+
assert_line :string_with_collation, type: "varchar", limit: nil, default: nil, collation: "SQL_Latin1_General_CP1_CS_AS"
|
128
|
+
assert_line :varchar_with_collation, type: "varchar", limit: nil, default: nil, collation: "SQL_Latin1_General_CP1_CS_AS"
|
129
|
+
end
|
130
|
+
|
122
131
|
# Special Cases
|
123
132
|
|
124
133
|
it "honor nonstandard primary keys" do
|
@@ -135,6 +144,12 @@ class SchemaDumperTestSQLServer < ActiveRecord::TestCase
|
|
135
144
|
assert_line :name, type: "string", limit: nil, default: nil, collation: nil
|
136
145
|
end
|
137
146
|
|
147
|
+
it "dumps field with unique key constraints only once" do
|
148
|
+
output = generate_schema_for_table "unique_key_dumped_table"
|
149
|
+
|
150
|
+
_(output.scan('t.integer "unique_field"').length).must_equal(1)
|
151
|
+
end
|
152
|
+
|
138
153
|
private
|
139
154
|
|
140
155
|
def generate_schema_for_table(*table_names)
|
@@ -160,13 +175,15 @@ class SchemaDumperTestSQLServer < ActiveRecord::TestCase
|
|
160
175
|
|
161
176
|
def assert_line(column_name, options = {})
|
162
177
|
line = line(column_name)
|
163
|
-
assert line, "
|
178
|
+
assert line, "Could not find line with column name: #{column_name.inspect} in schema:\n#{schema}"
|
179
|
+
|
164
180
|
[:type, :limit, :precision, :scale, :collation, :default].each do |key|
|
165
181
|
next unless options.key?(key)
|
166
182
|
|
167
183
|
actual = key == :type ? line.send(:type_method) : line.send(key)
|
168
184
|
expected = options[key]
|
169
185
|
message = "#{key.to_s.titleize} of #{expected.inspect} not found in:\n#{line}"
|
186
|
+
|
170
187
|
if expected.nil?
|
171
188
|
_(actual).must_be_nil message
|
172
189
|
elsif expected.is_a?(Array)
|