activerecord-sqlserver-adapter 4.2.18 → 5.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/CHANGELOG.md +8 -223
- data/Gemfile +18 -17
- data/RAILS5-TODO.md +36 -0
- data/README.md +27 -8
- data/RUNNING_UNIT_TESTS.md +0 -17
- data/Rakefile +2 -7
- data/VERSION +1 -1
- data/activerecord-sqlserver-adapter.gemspec +1 -1
- data/appveyor.yml +0 -2
- data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +15 -8
- data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +45 -97
- data/lib/active_record/connection_adapters/sqlserver/database_tasks.rb +1 -2
- data/lib/active_record/connection_adapters/sqlserver/quoting.rb +31 -10
- data/lib/active_record/connection_adapters/sqlserver/schema_creation.rb +0 -18
- data/lib/active_record/connection_adapters/sqlserver/schema_dumper.rb +16 -0
- data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +101 -58
- data/lib/active_record/connection_adapters/sqlserver/showplan.rb +7 -7
- data/lib/active_record/connection_adapters/sqlserver/sql_type_metadata.rb +20 -0
- data/lib/active_record/connection_adapters/sqlserver/table_definition.rb +56 -32
- data/lib/active_record/connection_adapters/sqlserver/transaction.rb +1 -1
- data/lib/active_record/connection_adapters/sqlserver/type.rb +34 -32
- data/lib/active_record/connection_adapters/sqlserver/type/big_integer.rb +4 -0
- data/lib/active_record/connection_adapters/sqlserver/type/binary.rb +6 -0
- data/lib/active_record/connection_adapters/sqlserver/type/boolean.rb +3 -0
- data/lib/active_record/connection_adapters/sqlserver/type/char.rb +9 -20
- data/lib/active_record/connection_adapters/sqlserver/type/data.rb +30 -0
- data/lib/active_record/connection_adapters/sqlserver/type/date.rb +28 -4
- data/lib/active_record/connection_adapters/sqlserver/type/datetime.rb +28 -14
- data/lib/active_record/connection_adapters/sqlserver/type/datetime2.rb +2 -2
- data/lib/active_record/connection_adapters/sqlserver/type/datetimeoffset.rb +4 -16
- data/lib/active_record/connection_adapters/sqlserver/type/decimal.rb +9 -0
- data/lib/active_record/connection_adapters/sqlserver/type/float.rb +4 -0
- data/lib/active_record/connection_adapters/sqlserver/type/integer.rb +3 -0
- data/lib/active_record/connection_adapters/sqlserver/type/money.rb +5 -1
- data/lib/active_record/connection_adapters/sqlserver/type/real.rb +4 -0
- data/lib/active_record/connection_adapters/sqlserver/type/small_integer.rb +3 -1
- data/lib/active_record/connection_adapters/sqlserver/type/small_money.rb +5 -1
- data/lib/active_record/connection_adapters/sqlserver/type/smalldatetime.rb +8 -1
- data/lib/active_record/connection_adapters/sqlserver/type/text.rb +4 -0
- data/lib/active_record/connection_adapters/sqlserver/type/time.rb +20 -8
- data/lib/active_record/connection_adapters/sqlserver/type/time_value_fractional.rb +25 -10
- data/lib/active_record/connection_adapters/sqlserver/type/timestamp.rb +4 -0
- data/lib/active_record/connection_adapters/sqlserver/type/tiny_integer.rb +3 -0
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_char.rb +6 -0
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_text.rb +4 -0
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar.rb +7 -1
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar_max.rb +5 -1
- data/lib/active_record/connection_adapters/sqlserver/type/uuid.rb +15 -2
- data/lib/active_record/connection_adapters/sqlserver/type/varbinary.rb +7 -1
- data/lib/active_record/connection_adapters/sqlserver/type/varbinary_max.rb +5 -1
- data/lib/active_record/connection_adapters/sqlserver/type/varchar.rb +7 -1
- data/lib/active_record/connection_adapters/sqlserver/type/varchar_max.rb +5 -1
- data/lib/active_record/connection_adapters/sqlserver/utils.rb +10 -0
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +71 -57
- data/lib/active_record/connection_adapters/sqlserver_column.rb +5 -30
- data/lib/active_record/sqlserver_base.rb +1 -5
- data/lib/arel/visitors/sqlserver.rb +11 -20
- data/test/bin/setup.sh +4 -6
- data/test/cases/adapter_test_sqlserver.rb +11 -20
- data/test/cases/coerced_tests.rb +233 -138
- data/test/cases/column_test_sqlserver.rb +244 -227
- data/test/cases/connection_test_sqlserver.rb +5 -76
- data/test/cases/fully_qualified_identifier_test_sqlserver.rb +7 -7
- data/test/cases/helper_sqlserver.rb +4 -15
- data/test/cases/pessimistic_locking_test_sqlserver.rb +1 -1
- data/test/cases/rake_test_sqlserver.rb +20 -14
- data/test/cases/schema_dumper_test_sqlserver.rb +94 -63
- data/test/cases/schema_test_sqlserver.rb +2 -2
- data/test/cases/showplan_test_sqlserver.rb +1 -1
- data/test/cases/specific_schema_test_sqlserver.rb +7 -14
- data/test/cases/transaction_test_sqlserver.rb +1 -1
- data/test/cases/uuid_test_sqlserver.rb +0 -1
- data/test/config.yml +0 -10
- data/test/migrations/transaction_table/1_table_will_never_be_created.rb +1 -1
- data/test/schema/sqlserver_specific_schema.rb +0 -16
- data/test/support/coerceable_test_sqlserver.rb +6 -2
- data/test/support/connection_reflection.rb +0 -4
- data/test/support/sql_counter_sqlserver.rb +17 -21
- metadata +9 -7
- data/lib/active_record/connection_adapters/sqlserver/core_ext/odbc.rb +0 -34
- data/lib/active_record/connection_adapters/sqlserver/schema_cache.rb +0 -114
@@ -4,12 +4,14 @@ require 'models/topic'
|
|
4
4
|
|
5
5
|
class ConnectionTestSQLServer < ActiveRecord::TestCase
|
6
6
|
|
7
|
-
self.
|
7
|
+
self.use_transactional_tests = false
|
8
8
|
|
9
9
|
fixtures :topics, :accounts
|
10
10
|
|
11
|
-
before
|
12
|
-
|
11
|
+
before do
|
12
|
+
connection.reconnect!
|
13
|
+
assert connection.active?
|
14
|
+
end
|
13
15
|
|
14
16
|
it 'affect rows' do
|
15
17
|
topic_data = { 1 => { "content" => "1 updated" }, 2 => { "content" => "2 updated" } }
|
@@ -31,61 +33,6 @@ class ConnectionTestSQLServer < ActiveRecord::TestCase
|
|
31
33
|
end
|
32
34
|
end unless connection_sqlserver_azure?
|
33
35
|
|
34
|
-
describe 'ODBC connection management' do
|
35
|
-
|
36
|
-
it 'return finished ODBC statement handle from #execute without block' do
|
37
|
-
assert_all_odbc_statements_used_are_closed do
|
38
|
-
connection.execute('SELECT * FROM [topics]')
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
it 'finish ODBC statement handle from #execute with block' do
|
43
|
-
assert_all_odbc_statements_used_are_closed do
|
44
|
-
connection.execute('SELECT * FROM [topics]') { }
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
it 'finish connection from #raw_select' do
|
49
|
-
assert_all_odbc_statements_used_are_closed do
|
50
|
-
connection.send(:raw_select,'SELECT * FROM [topics]')
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
it 'execute without block closes statement' do
|
55
|
-
assert_all_odbc_statements_used_are_closed do
|
56
|
-
connection.execute("SELECT 1")
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
it 'execute with block closes statement' do
|
61
|
-
assert_all_odbc_statements_used_are_closed do
|
62
|
-
connection.execute("SELECT 1") do |sth|
|
63
|
-
assert !sth.finished?, "Statement should still be alive within block"
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
it 'insert with identity closes statement' do
|
69
|
-
assert_all_odbc_statements_used_are_closed do
|
70
|
-
connection.exec_insert "INSERT INTO accounts ([id],[firm_id],[credit_limit]) VALUES (999, 1, 50)", "SQL", []
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
it 'insert without identity closes statement' do
|
75
|
-
assert_all_odbc_statements_used_are_closed do
|
76
|
-
connection.exec_insert "INSERT INTO accounts ([firm_id],[credit_limit]) VALUES (1, 50)", "SQL", []
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
it 'active closes statement' do
|
81
|
-
assert_all_odbc_statements_used_are_closed do
|
82
|
-
connection.active?
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
end if connection_odbc?
|
87
|
-
|
88
|
-
|
89
36
|
describe 'Connection management' do
|
90
37
|
|
91
38
|
it 'set spid on connect' do
|
@@ -118,25 +65,7 @@ class ConnectionTestSQLServer < ActiveRecord::TestCase
|
|
118
65
|
case connection_options[:mode]
|
119
66
|
when :dblib
|
120
67
|
connection.raw_connection.close rescue nil
|
121
|
-
when :odbc
|
122
|
-
connection.raw_connection.disconnect rescue nil
|
123
68
|
end
|
124
69
|
end
|
125
70
|
|
126
|
-
def assert_all_odbc_statements_used_are_closed(&block)
|
127
|
-
odbc = connection.raw_connection.class.parent
|
128
|
-
existing_handles = []
|
129
|
-
ObjectSpace.each_object(odbc::Statement) { |h| existing_handles << h }
|
130
|
-
existing_handle_ids = existing_handles.map(&:object_id)
|
131
|
-
assert existing_handles.all?(&:finished?), "Somewhere before the block some statements were not closed"
|
132
|
-
GC.disable
|
133
|
-
yield
|
134
|
-
used_handles = []
|
135
|
-
ObjectSpace.each_object(odbc::Statement) { |h| used_handles << h unless existing_handle_ids.include?(h.object_id) }
|
136
|
-
assert used_handles.size > 0, "No statements were used within given block"
|
137
|
-
assert used_handles.all?(&:finished?), "Statement should have been closed within given block"
|
138
|
-
ensure
|
139
|
-
GC.enable
|
140
|
-
end
|
141
|
-
|
142
71
|
end
|
@@ -37,7 +37,7 @@ class FullyQualifiedIdentifierTestSQLServer < ActiveRecord::TestCase
|
|
37
37
|
it 'should not use fully qualified table name in where clause' do
|
38
38
|
table = Arel::Table.new(:table)
|
39
39
|
expected_sql = "SELECT * FROM [my.server].[db].[schema].[table] WHERE [table].[id] = 42"
|
40
|
-
assert_equal expected_sql, table.project(Arel.star).where(table[:id].eq(42)).to_sql
|
40
|
+
quietly { assert_equal expected_sql, table.project(Arel.star).where(table[:id].eq(42)).to_sql }
|
41
41
|
end
|
42
42
|
|
43
43
|
it 'should not use fully qualified table name in order clause' do
|
@@ -47,28 +47,28 @@ class FullyQualifiedIdentifierTestSQLServer < ActiveRecord::TestCase
|
|
47
47
|
end
|
48
48
|
|
49
49
|
it 'should use fully qualified table name in insert statement' do
|
50
|
-
manager = Arel::InsertManager.new
|
50
|
+
manager = Arel::InsertManager.new
|
51
51
|
manager.into Arel::Table.new(:table)
|
52
52
|
manager.values = manager.create_values [Arel.sql('*')], %w{ a }
|
53
53
|
expected_sql = "INSERT INTO [my.server].[db].[schema].[table] VALUES (*)"
|
54
|
-
assert_equal expected_sql, manager.to_sql
|
54
|
+
quietly { assert_equal expected_sql, manager.to_sql }
|
55
55
|
end
|
56
56
|
|
57
57
|
it 'should use fully qualified table name in update statement' do
|
58
58
|
table = Arel::Table.new(:table)
|
59
|
-
manager = Arel::UpdateManager.new
|
59
|
+
manager = Arel::UpdateManager.new
|
60
60
|
manager.table(table).where(table[:id].eq(42))
|
61
61
|
manager.set([[table[:name], "Bob"]])
|
62
62
|
expected_sql = "UPDATE [my.server].[db].[schema].[table] SET [name] = N'Bob' WHERE [table].[id] = 42"
|
63
|
-
assert_equal expected_sql, manager.to_sql
|
63
|
+
quietly { assert_equal expected_sql, manager.to_sql }
|
64
64
|
end
|
65
65
|
|
66
66
|
it 'should use fully qualified table name in delete statement' do
|
67
67
|
table = Arel::Table.new(:table)
|
68
|
-
manager = Arel::DeleteManager.new
|
68
|
+
manager = Arel::DeleteManager.new
|
69
69
|
manager.from(table).where(table[:id].eq(42))
|
70
70
|
expected_sql = "DELETE FROM [my.server].[db].[schema].[table] WHERE [table].[id] = 42"
|
71
|
-
assert_equal expected_sql, manager.to_sql
|
71
|
+
quietly { assert_equal expected_sql, manager.to_sql }
|
72
72
|
end
|
73
73
|
|
74
74
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'support/paths_sqlserver'
|
2
2
|
require 'bundler/setup'
|
3
3
|
Bundler.require :default, :development
|
4
|
+
require 'pry'
|
4
5
|
require 'support/minitest_sqlserver'
|
5
6
|
require 'cases/helper'
|
6
7
|
require 'support/load_schema_sqlserver'
|
@@ -15,7 +16,9 @@ module ActiveRecord
|
|
15
16
|
SQLServer = ActiveRecord::ConnectionAdapters::SQLServer
|
16
17
|
|
17
18
|
include ARTest::SQLServer::CoerceableTest,
|
18
|
-
ARTest::SQLServer::ConnectionReflection
|
19
|
+
ARTest::SQLServer::ConnectionReflection,
|
20
|
+
ARTest::SQLServer::SqlCounterSqlserver,
|
21
|
+
ActiveSupport::Testing::Stream
|
19
22
|
|
20
23
|
let(:logger) { ActiveRecord::Base.logger }
|
21
24
|
|
@@ -34,20 +37,6 @@ module ActiveRecord
|
|
34
37
|
klass.use_output_inserted = true
|
35
38
|
end
|
36
39
|
|
37
|
-
def silence_stream(stream)
|
38
|
-
old_stream = stream.dup
|
39
|
-
stream.reopen(RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ ? 'NUL:' : '/dev/null')
|
40
|
-
stream.sync = true
|
41
|
-
yield
|
42
|
-
ensure
|
43
|
-
stream.reopen(old_stream)
|
44
|
-
old_stream.close
|
45
|
-
end
|
46
|
-
|
47
|
-
def quietly
|
48
|
-
silence_stream(STDOUT) { silence_stream(STDERR) { yield } }
|
49
|
-
end
|
50
|
-
|
51
40
|
end
|
52
41
|
end
|
53
42
|
|
@@ -73,7 +73,7 @@ class PessimisticLockingTestSQLServer < ActiveRecord::TestCase
|
|
73
73
|
end
|
74
74
|
|
75
75
|
it 'copes with eager loading un-locked paginated' do
|
76
|
-
eager_ids_sql = /SELECT\s+DISTINCT \[people\].\[id\] FROM \[people\] WITH\(UPDLOCK\) LEFT OUTER JOIN \[readers\] WITH\(UPDLOCK\)\s+ON \[readers\].\[person_id\] = \[people\].\[id\]\s+ORDER BY \[people\].\[id\] ASC OFFSET
|
76
|
+
eager_ids_sql = /SELECT\s+DISTINCT \[people\].\[id\] FROM \[people\] WITH\(UPDLOCK\) LEFT OUTER JOIN \[readers\] WITH\(UPDLOCK\)\s+ON \[readers\].\[person_id\] = \[people\].\[id\]\s+ORDER BY \[people\].\[id\] ASC OFFSET @0 ROWS FETCH NEXT @1 ROWS ONLY/
|
77
77
|
loader_sql = /SELECT.*FROM \[people\] WITH\(UPDLOCK\).*WHERE \[people\]\.\[id\] IN/
|
78
78
|
assert_sql(eager_ids_sql, loader_sql) do
|
79
79
|
people = Person.lock(true).limit(5).offset(10).includes(:readers).references(:readers).to_a
|
@@ -2,7 +2,7 @@ require 'cases/helper_sqlserver'
|
|
2
2
|
|
3
3
|
class SQLServerRakeTest < ActiveRecord::TestCase
|
4
4
|
|
5
|
-
self.
|
5
|
+
self.use_transactional_tests = false
|
6
6
|
|
7
7
|
cattr_accessor :azure_skip
|
8
8
|
self.azure_skip = connection_sqlserver_azure?
|
@@ -42,24 +42,24 @@ class SQLServerRakeCreateTest < SQLServerRakeTest
|
|
42
42
|
self.azure_skip = false
|
43
43
|
|
44
44
|
it 'establishes connection to database after create ' do
|
45
|
-
db_tasks.create configuration
|
45
|
+
quietly { db_tasks.create configuration }
|
46
46
|
connection.current_database.must_equal(new_database)
|
47
47
|
end
|
48
48
|
|
49
49
|
it 'creates database with default collation' do
|
50
|
-
db_tasks.create configuration
|
50
|
+
quietly { db_tasks.create configuration }
|
51
51
|
connection.collation.must_equal 'SQL_Latin1_General_CP1_CI_AS'
|
52
52
|
end
|
53
53
|
|
54
54
|
it 'creates database with given collation' do
|
55
|
-
db_tasks.create configuration.merge('collation' => 'Latin1_General_CI_AS')
|
55
|
+
quietly { db_tasks.create configuration.merge('collation' => 'Latin1_General_CI_AS') }
|
56
56
|
connection.collation.must_equal 'Latin1_General_CI_AS'
|
57
57
|
end
|
58
58
|
|
59
59
|
it 'prints error message when database exists' do
|
60
|
-
db_tasks.create configuration
|
60
|
+
quietly { db_tasks.create configuration }
|
61
61
|
message = capture(:stderr) { db_tasks.create configuration }
|
62
|
-
message.must_match %r{activerecord_unittest_tasks
|
62
|
+
message.must_match %r{activerecord_unittest_tasks.*already exists}
|
63
63
|
end
|
64
64
|
|
65
65
|
end
|
@@ -69,8 +69,10 @@ class SQLServerRakeDropTest < SQLServerRakeTest
|
|
69
69
|
self.azure_skip = false
|
70
70
|
|
71
71
|
it 'drops database and uses master' do
|
72
|
-
|
73
|
-
|
72
|
+
quietly do
|
73
|
+
db_tasks.create configuration
|
74
|
+
db_tasks.drop configuration
|
75
|
+
end
|
74
76
|
connection.current_database.must_equal 'master'
|
75
77
|
end
|
76
78
|
|
@@ -84,7 +86,7 @@ end
|
|
84
86
|
class SQLServerRakePurgeTest < SQLServerRakeTest
|
85
87
|
|
86
88
|
before do
|
87
|
-
db_tasks.create(configuration)
|
89
|
+
quietly { db_tasks.create(configuration) }
|
88
90
|
connection.create_table :users, force: true do |t|
|
89
91
|
t.string :name, :email
|
90
92
|
t.timestamps null: false
|
@@ -94,7 +96,7 @@ class SQLServerRakePurgeTest < SQLServerRakeTest
|
|
94
96
|
it 'clears active connections, drops database, and recreates with established connection' do
|
95
97
|
connection.current_database.must_equal(new_database)
|
96
98
|
connection.tables.must_include 'users'
|
97
|
-
db_tasks.purge(configuration)
|
99
|
+
quietly { db_tasks.purge(configuration) }
|
98
100
|
connection.current_database.must_equal(new_database)
|
99
101
|
connection.tables.wont_include 'users'
|
100
102
|
end
|
@@ -103,7 +105,9 @@ end
|
|
103
105
|
|
104
106
|
class SQLServerRakeCharsetTest < SQLServerRakeTest
|
105
107
|
|
106
|
-
before
|
108
|
+
before do
|
109
|
+
quietly { db_tasks.create(configuration) }
|
110
|
+
end
|
107
111
|
|
108
112
|
it 'retrieves charset' do
|
109
113
|
db_tasks.charset(configuration).must_equal 'iso_1'
|
@@ -113,7 +117,9 @@ end
|
|
113
117
|
|
114
118
|
class SQLServerRakeCollationTest < SQLServerRakeTest
|
115
119
|
|
116
|
-
before
|
120
|
+
before do
|
121
|
+
quietly { db_tasks.create(configuration) }
|
122
|
+
end
|
117
123
|
|
118
124
|
it 'retrieves collation' do
|
119
125
|
db_tasks.collation(configuration).must_equal 'SQL_Latin1_General_CP1_CI_AS'
|
@@ -127,7 +133,7 @@ class SQLServerRakeStructureDumpLoadTest < SQLServerRakeTest
|
|
127
133
|
let(:filedata) { File.read(filename) }
|
128
134
|
|
129
135
|
before do
|
130
|
-
db_tasks.create(configuration)
|
136
|
+
quietly { db_tasks.create(configuration) }
|
131
137
|
connection.create_table :users, force: true do |t|
|
132
138
|
t.string :name, :email
|
133
139
|
t.text :background1
|
@@ -156,7 +162,7 @@ class SQLServerRakeStructureDumpLoadTest < SQLServerRakeTest
|
|
156
162
|
filedata.must_match %r{CREATE TABLE dbo\.users}
|
157
163
|
db_tasks.purge(configuration)
|
158
164
|
connection.tables.wont_include 'users'
|
159
|
-
db_tasks.
|
165
|
+
db_tasks.load_schema configuration, :sql, filename
|
160
166
|
connection.tables.must_include 'users'
|
161
167
|
end
|
162
168
|
|
@@ -9,49 +9,48 @@ class SchemaDumperTestSQLServer < ActiveRecord::TestCase
|
|
9
9
|
|
10
10
|
it 'sst_datatypes' do
|
11
11
|
generate_schema_for_table 'sst_datatypes'
|
12
|
-
|
13
|
-
assert_line :
|
14
|
-
assert_line :
|
15
|
-
assert_line :
|
16
|
-
assert_line :
|
17
|
-
assert_line :
|
18
|
-
assert_line :
|
19
|
-
assert_line :
|
20
|
-
assert_line :
|
21
|
-
assert_line :
|
22
|
-
assert_line :smallmoney, type: 'smallmoney', limit: nil, precision: '10', scale: '4', default: '4.2'
|
12
|
+
assert_line :bigint, type: 'bigint', limit: nil, precision: nil, scale: nil, default: 42
|
13
|
+
assert_line :int, type: 'integer', limit: nil, precision: nil, scale: nil, default: 42
|
14
|
+
assert_line :smallint, type: 'integer', limit: 2, precision: nil, scale: nil, default: 42
|
15
|
+
assert_line :tinyint, type: 'integer', limit: 1, precision: nil, scale: nil, default: 42
|
16
|
+
assert_line :bit, type: 'boolean', limit: nil, precision: nil, scale: nil, default: true
|
17
|
+
assert_line :decimal_9_2, type: 'decimal', limit: nil, precision: 9, scale: 2, default: 12345.01
|
18
|
+
assert_line :numeric_18_0, type: 'decimal', limit: nil, precision: 18, scale: 0, default: 191.0
|
19
|
+
assert_line :numeric_36_2, type: 'decimal', limit: nil, precision: 36, scale: 2, default: 12345678901234567890.01
|
20
|
+
assert_line :money, type: 'money', limit: nil, precision: 19, scale: 4, default: 4.2
|
21
|
+
assert_line :smallmoney, type: 'smallmoney', limit: nil, precision: 10, scale: 4, default: 4.2
|
23
22
|
# Approximate Numerics
|
24
|
-
assert_line :float, type: 'float', limit: nil,
|
25
|
-
assert_line :real, type: 'real', limit: nil,
|
23
|
+
assert_line :float, type: 'float', limit: nil, precision: nil, scale: nil, default: 123.00000001
|
24
|
+
assert_line :real, type: 'real', limit: nil, precision: nil, scale: nil, default: 123.45
|
26
25
|
# Date and Time
|
27
|
-
assert_line :date, type: 'date', limit: nil, precision: nil, scale: nil, default: "
|
28
|
-
assert_line :datetime, type: 'datetime', limit: nil, precision: nil, scale: nil, default: "
|
26
|
+
assert_line :date, type: 'date', limit: nil, precision: nil, scale: nil, default: "01-01-0001"
|
27
|
+
assert_line :datetime, type: 'datetime', limit: nil, precision: nil, scale: nil, default: "01-01-1753 00:00:00.123"
|
29
28
|
if connection_dblib_73?
|
30
|
-
assert_line :datetime2_7, type: '
|
31
|
-
assert_line :datetime2_3, type: '
|
32
|
-
assert_line :datetime2_1, type: '
|
29
|
+
assert_line :datetime2_7, type: 'datetime', limit: nil, precision: 7, scale: nil, default: "12-31-9999 23:59:59.9999999"
|
30
|
+
assert_line :datetime2_3, type: 'datetime', limit: nil, precision: 3, scale: nil, default: nil
|
31
|
+
assert_line :datetime2_1, type: 'datetime', limit: nil, precision: 1, scale: nil, default: nil
|
33
32
|
end
|
34
|
-
assert_line :smalldatetime, type: 'smalldatetime',limit: nil, precision: nil, scale: nil, default: "
|
33
|
+
assert_line :smalldatetime, type: 'smalldatetime',limit: nil, precision: nil, scale: nil, default: "01-01-1901 15:45:00.0"
|
35
34
|
if connection_dblib_73?
|
36
|
-
assert_line :time_7, type: 'time', limit: nil, precision:
|
37
|
-
assert_line :time_2, type: 'time', limit: nil, precision:
|
35
|
+
assert_line :time_7, type: 'time', limit: nil, precision: 7, scale: nil, default: "04:20:00.2883215"
|
36
|
+
assert_line :time_2, type: 'time', limit: nil, precision: 2, scale: nil, default: nil
|
38
37
|
end
|
39
38
|
# Character Strings
|
40
|
-
assert_line :char_10, type: 'char', limit:
|
41
|
-
assert_line :varchar_50, type: 'varchar', limit:
|
42
|
-
assert_line :varchar_max, type: 'varchar_max', limit:
|
43
|
-
assert_line :text, type: 'text_basic', limit:
|
39
|
+
assert_line :char_10, type: 'char', limit: 10, precision: nil, scale: nil, default: "1234567890", collation: nil
|
40
|
+
assert_line :varchar_50, type: 'varchar', limit: 50, precision: nil, scale: nil, default: "test varchar_50", collation: nil
|
41
|
+
assert_line :varchar_max, type: 'varchar_max', limit: 2147483647, precision: nil, scale: nil, default: "test varchar_max", collation: nil
|
42
|
+
assert_line :text, type: 'text_basic', limit: 2147483647, precision: nil, scale: nil, default: "test text", collation: nil
|
44
43
|
# Unicode Character Strings
|
45
|
-
assert_line :nchar_10, type: 'nchar', limit:
|
46
|
-
assert_line :nvarchar_50, type: 'string', limit:
|
47
|
-
assert_line :nvarchar_max, type: 'text', limit:
|
48
|
-
assert_line :ntext, type: 'ntext', limit:
|
44
|
+
assert_line :nchar_10, type: 'nchar', limit: 10, precision: nil, scale: nil, default: "12345678åå", collation: nil
|
45
|
+
assert_line :nvarchar_50, type: 'string', limit: 50, precision: nil, scale: nil, default: "test nvarchar_50 åå", collation: nil
|
46
|
+
assert_line :nvarchar_max, type: 'text', limit: 2147483647, precision: nil, scale: nil, default: "test nvarchar_max åå", collation: nil
|
47
|
+
assert_line :ntext, type: 'ntext', limit: 2147483647, precision: nil, scale: nil, default: "test ntext åå", collation: nil
|
49
48
|
# Binary Strings
|
50
|
-
assert_line :binary_49, type: 'binary_basic', limit:
|
51
|
-
assert_line :varbinary_49, type: 'varbinary', limit:
|
52
|
-
assert_line :varbinary_max, type: 'binary', limit:
|
49
|
+
assert_line :binary_49, type: 'binary_basic', limit: 49, precision: nil, scale: nil, default: nil
|
50
|
+
assert_line :varbinary_49, type: 'varbinary', limit: 49, precision: nil, scale: nil, default: nil
|
51
|
+
assert_line :varbinary_max, type: 'binary', limit: 2147483647, precision: nil, scale: nil, default: nil
|
53
52
|
# Other Data Types
|
54
|
-
assert_line :uniqueidentifier, type: 'uuid', limit: nil, precision: nil, scale: nil, default:
|
53
|
+
assert_line :uniqueidentifier, type: 'uuid', limit: nil, precision: nil, scale: nil, default: -> { "newid()" }
|
55
54
|
assert_line :timestamp, type: 'ss_timestamp', limit: nil, precision: nil, scale: nil, default: nil
|
56
55
|
end
|
57
56
|
|
@@ -71,18 +70,18 @@ class SchemaDumperTestSQLServer < ActiveRecord::TestCase
|
|
71
70
|
columns['time_col'].sql_type.must_equal 'time(7)'
|
72
71
|
columns['date_col'].sql_type.must_equal 'date'
|
73
72
|
columns['binary_col'].sql_type.must_equal 'varbinary(max)'
|
74
|
-
assert_line :integer_col, type: 'integer', limit:
|
75
|
-
assert_line :bigint_col, type: 'bigint', limit:
|
73
|
+
assert_line :integer_col, type: 'integer', limit: nil, precision: nil, scale: nil, default: nil
|
74
|
+
assert_line :bigint_col, type: 'bigint', limit: nil, precision: nil, scale: nil, default: nil
|
76
75
|
assert_line :boolean_col, type: 'boolean', limit: nil, precision: nil, scale: nil, default: nil
|
77
|
-
assert_line :decimal_col, type: 'decimal', limit: nil, precision:
|
76
|
+
assert_line :decimal_col, type: 'decimal', limit: nil, precision: 18, scale: 0, default: nil
|
78
77
|
assert_line :float_col, type: 'float', limit: nil, precision: nil, scale: nil, default: nil
|
79
|
-
assert_line :string_col, type: 'string', limit:
|
80
|
-
assert_line :text_col, type: 'text', limit:
|
78
|
+
assert_line :string_col, type: 'string', limit: nil, precision: nil, scale: nil, default: nil
|
79
|
+
assert_line :text_col, type: 'text', limit: 2147483647, precision: nil, scale: nil, default: nil
|
81
80
|
assert_line :datetime_col, type: 'datetime', limit: nil, precision: nil, scale: nil, default: nil
|
82
81
|
assert_line :timestamp_col, type: 'datetime', limit: nil, precision: nil, scale: nil, default: nil
|
83
|
-
assert_line :time_col, type: 'time', limit: nil, precision:
|
82
|
+
assert_line :time_col, type: 'time', limit: nil, precision: 7, scale: nil, default: nil
|
84
83
|
assert_line :date_col, type: 'date', limit: nil, precision: nil, scale: nil, default: nil
|
85
|
-
assert_line :binary_col, type: 'binary', limit:
|
84
|
+
assert_line :binary_col, type: 'binary', limit: 2147483647, precision: nil, scale: nil, default: nil
|
86
85
|
# Our type methods.
|
87
86
|
columns['real_col'].sql_type.must_equal 'real'
|
88
87
|
columns['money_col'].sql_type.must_equal 'money'
|
@@ -99,16 +98,16 @@ class SchemaDumperTestSQLServer < ActiveRecord::TestCase
|
|
99
98
|
columns['uuid_col'].sql_type.must_equal 'uniqueidentifier'
|
100
99
|
columns['sstimestamp_col'].sql_type.must_equal 'timestamp'
|
101
100
|
assert_line :real_col, type: 'real', limit: nil, precision: nil, scale: nil, default: nil
|
102
|
-
assert_line :money_col, type: 'money', limit: nil, precision:
|
103
|
-
assert_line :datetime2_col, type: '
|
104
|
-
assert_line :smallmoney_col, type: 'smallmoney', limit: nil, precision:
|
105
|
-
assert_line :char_col, type: 'char', limit:
|
106
|
-
assert_line :varchar_col, type: 'varchar', limit:
|
107
|
-
assert_line :text_basic_col, type: 'text_basic', limit:
|
108
|
-
assert_line :nchar_col, type: 'nchar', limit:
|
109
|
-
assert_line :ntext_col, type: 'ntext', limit:
|
110
|
-
assert_line :binary_basic_col, type: 'binary_basic', limit:
|
111
|
-
assert_line :varbinary_col, type: 'varbinary', limit:
|
101
|
+
assert_line :money_col, type: 'money', limit: nil, precision: 19, scale: 4, default: nil
|
102
|
+
assert_line :datetime2_col, type: 'datetime', limit: nil, precision: 7, scale: nil, default: nil
|
103
|
+
assert_line :smallmoney_col, type: 'smallmoney', limit: nil, precision: 10, scale: 4, default: nil
|
104
|
+
assert_line :char_col, type: 'char', limit: 1, precision: nil, scale: nil, default: nil
|
105
|
+
assert_line :varchar_col, type: 'varchar', limit: nil, precision: nil, scale: nil, default: nil
|
106
|
+
assert_line :text_basic_col, type: 'text_basic', limit: 2147483647, precision: nil, scale: nil, default: nil
|
107
|
+
assert_line :nchar_col, type: 'nchar', limit: 1, precision: nil, scale: nil, default: nil
|
108
|
+
assert_line :ntext_col, type: 'ntext', limit: 2147483647, precision: nil, scale: nil, default: nil
|
109
|
+
assert_line :binary_basic_col, type: 'binary_basic', limit: 1, precision: nil, scale: nil, default: nil
|
110
|
+
assert_line :varbinary_col, type: 'varbinary', limit: nil, precision: nil, scale: nil, default: nil
|
112
111
|
assert_line :uuid_col, type: 'uuid', limit: nil, precision: nil, scale: nil, default: nil
|
113
112
|
assert_line :sstimestamp_col, type: 'ss_timestamp', limit: nil, precision: nil, scale: nil, default: nil
|
114
113
|
end
|
@@ -126,7 +125,7 @@ class SchemaDumperTestSQLServer < ActiveRecord::TestCase
|
|
126
125
|
it 'no id with model driven primary key' do
|
127
126
|
output = generate_schema_for_table 'sst_no_pk_data'
|
128
127
|
output.must_match %r{create_table "sst_no_pk_data".*id:\sfalse.*do}
|
129
|
-
assert_line :name, type: 'string', limit:
|
128
|
+
assert_line :name, type: 'string', limit: nil, default: nil, collation: nil
|
130
129
|
end
|
131
130
|
|
132
131
|
|
@@ -155,15 +154,19 @@ class SchemaDumperTestSQLServer < ActiveRecord::TestCase
|
|
155
154
|
def assert_line(column_name, options={})
|
156
155
|
line = line(column_name)
|
157
156
|
assert line, "Count not find line with column name: #{column_name.inspect} in schema:\n#{schema}"
|
158
|
-
[:type, :limit, :precision, :scale, :default].each do |key|
|
157
|
+
[:type, :limit, :precision, :scale, :collation, :default].each do |key|
|
159
158
|
next unless options.key?(key)
|
160
159
|
actual = key == :type ? line.send(:type_method) : line.send(key)
|
161
160
|
expected = options[key]
|
162
161
|
message = "#{key.to_s.titleize} of #{expected.inspect} not found in:\n#{line}"
|
163
162
|
if expected.nil?
|
164
163
|
actual.must_be_nil message
|
165
|
-
elsif expected.is_a?(
|
166
|
-
actual.
|
164
|
+
elsif expected.is_a?(Array)
|
165
|
+
actual.must_include expected, message
|
166
|
+
elsif expected.is_a?(Float)
|
167
|
+
actual.must_be_close_to expected, 0.001
|
168
|
+
elsif expected.is_a?(Proc)
|
169
|
+
actual.call.must_equal(expected.call)
|
167
170
|
else
|
168
171
|
actual.must_equal expected, message
|
169
172
|
end
|
@@ -172,24 +175,52 @@ class SchemaDumperTestSQLServer < ActiveRecord::TestCase
|
|
172
175
|
|
173
176
|
class SchemaLine
|
174
177
|
|
175
|
-
|
178
|
+
LINE_PARSER = %r{t\.(\w+)\s+"(.*?)"[,\s+](.*)}
|
176
179
|
|
177
|
-
|
178
|
-
|
180
|
+
attr_reader :line,
|
181
|
+
:type_method,
|
182
|
+
:col_name,
|
183
|
+
:options
|
184
|
+
|
185
|
+
def self.option(method_name)
|
186
|
+
define_method(method_name) { options.present? ? options[method_name.to_sym] : nil }
|
179
187
|
end
|
180
188
|
|
181
189
|
def initialize(line)
|
182
190
|
@line = line
|
191
|
+
@type_method, @col_name, @options = parse_line
|
183
192
|
end
|
184
193
|
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
194
|
+
option :limit
|
195
|
+
option :precision
|
196
|
+
option :scale
|
197
|
+
option :default
|
198
|
+
option :collation
|
190
199
|
|
191
200
|
def to_s
|
192
|
-
line
|
201
|
+
line.squish
|
202
|
+
end
|
203
|
+
|
204
|
+
def inspect
|
205
|
+
"#<SchemaLine col_name=#{col_name.inspect}, options=#{options.inspect}>"
|
206
|
+
end
|
207
|
+
|
208
|
+
private
|
209
|
+
|
210
|
+
def parse_line
|
211
|
+
_all, type_method, col_name, options = @line.match(LINE_PARSER).to_a
|
212
|
+
options = parse_options(options)
|
213
|
+
[type_method, col_name, options]
|
214
|
+
end
|
215
|
+
|
216
|
+
def parse_options(opts)
|
217
|
+
if opts.present?
|
218
|
+
eval "{#{opts}}"
|
219
|
+
else
|
220
|
+
{}
|
221
|
+
end
|
222
|
+
rescue SyntaxError
|
223
|
+
{}
|
193
224
|
end
|
194
225
|
|
195
226
|
end
|