activerecord-sqlserver-adapter 4.2.18 → 5.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|