activerecord-sqlserver-adapter_new 4.2.15
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 +7 -0
- data/.gitignore +15 -0
- data/CHANGELOG.md +212 -0
- data/CODE_OF_CONDUCT.md +31 -0
- data/Gemfile +61 -0
- data/Guardfile +29 -0
- data/MIT-LICENSE +20 -0
- data/README.md +201 -0
- data/RUNNING_UNIT_TESTS.md +121 -0
- data/Rakefile +48 -0
- data/VERSION +1 -0
- data/activerecord-sqlserver-adapter_new.gemspec +20 -0
- data/appveyor.yml +39 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/active_record.rb +27 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/attribute_methods.rb +25 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +40 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/explain_subscriber.rb +4 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/odbc.rb +34 -0
- data/lib/active_record/connection_adapters/sqlserver/database_limits.rb +49 -0
- data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +386 -0
- data/lib/active_record/connection_adapters/sqlserver/database_tasks.rb +68 -0
- data/lib/active_record/connection_adapters/sqlserver/errors.rb +7 -0
- data/lib/active_record/connection_adapters/sqlserver/quoting.rb +69 -0
- data/lib/active_record/connection_adapters/sqlserver/schema_cache.rb +114 -0
- data/lib/active_record/connection_adapters/sqlserver/schema_creation.rb +52 -0
- data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +473 -0
- data/lib/active_record/connection_adapters/sqlserver/showplan.rb +66 -0
- data/lib/active_record/connection_adapters/sqlserver/showplan/printer_table.rb +66 -0
- data/lib/active_record/connection_adapters/sqlserver/showplan/printer_xml.rb +22 -0
- data/lib/active_record/connection_adapters/sqlserver/table_definition.rb +76 -0
- data/lib/active_record/connection_adapters/sqlserver/transaction.rb +57 -0
- data/lib/active_record/connection_adapters/sqlserver/type.rb +46 -0
- data/lib/active_record/connection_adapters/sqlserver/type/big_integer.rb +15 -0
- data/lib/active_record/connection_adapters/sqlserver/type/binary.rb +15 -0
- data/lib/active_record/connection_adapters/sqlserver/type/boolean.rb +12 -0
- data/lib/active_record/connection_adapters/sqlserver/type/char.rb +38 -0
- data/lib/active_record/connection_adapters/sqlserver/type/date.rb +21 -0
- data/lib/active_record/connection_adapters/sqlserver/type/datetime.rb +41 -0
- data/lib/active_record/connection_adapters/sqlserver/type/datetime2.rb +17 -0
- data/lib/active_record/connection_adapters/sqlserver/type/datetimeoffset.rb +31 -0
- data/lib/active_record/connection_adapters/sqlserver/type/decimal.rb +12 -0
- data/lib/active_record/connection_adapters/sqlserver/type/float.rb +15 -0
- data/lib/active_record/connection_adapters/sqlserver/type/integer.rb +12 -0
- data/lib/active_record/connection_adapters/sqlserver/type/money.rb +21 -0
- data/lib/active_record/connection_adapters/sqlserver/type/real.rb +15 -0
- data/lib/active_record/connection_adapters/sqlserver/type/small_integer.rb +13 -0
- data/lib/active_record/connection_adapters/sqlserver/type/small_money.rb +21 -0
- data/lib/active_record/connection_adapters/sqlserver/type/smalldatetime.rb +22 -0
- data/lib/active_record/connection_adapters/sqlserver/type/string.rb +12 -0
- data/lib/active_record/connection_adapters/sqlserver/type/text.rb +15 -0
- data/lib/active_record/connection_adapters/sqlserver/type/time.rb +40 -0
- data/lib/active_record/connection_adapters/sqlserver/type/time_value_fractional.rb +76 -0
- data/lib/active_record/connection_adapters/sqlserver/type/timestamp.rb +15 -0
- data/lib/active_record/connection_adapters/sqlserver/type/tiny_integer.rb +22 -0
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_char.rb +15 -0
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_string.rb +12 -0
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_text.rb +15 -0
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar.rb +20 -0
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar_max.rb +20 -0
- data/lib/active_record/connection_adapters/sqlserver/type/uuid.rb +23 -0
- data/lib/active_record/connection_adapters/sqlserver/type/varbinary.rb +20 -0
- data/lib/active_record/connection_adapters/sqlserver/type/varbinary_max.rb +20 -0
- data/lib/active_record/connection_adapters/sqlserver/type/varchar.rb +20 -0
- data/lib/active_record/connection_adapters/sqlserver/type/varchar_max.rb +20 -0
- data/lib/active_record/connection_adapters/sqlserver/utils.rb +136 -0
- data/lib/active_record/connection_adapters/sqlserver/version.rb +11 -0
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +405 -0
- data/lib/active_record/connection_adapters/sqlserver_column.rb +53 -0
- data/lib/active_record/sqlserver_base.rb +20 -0
- data/lib/active_record/tasks/sqlserver_database_tasks.rb +131 -0
- data/lib/activerecord-sqlserver-adapter.rb +1 -0
- data/lib/arel/visitors/sqlserver.rb +214 -0
- data/lib/arel_sqlserver.rb +3 -0
- data/test/appveyor/dbsetup.ps1 +27 -0
- data/test/appveyor/dbsetup.sql +11 -0
- data/test/cases/adapter_test_sqlserver.rb +444 -0
- data/test/cases/coerced_tests.rb +713 -0
- data/test/cases/column_test_sqlserver.rb +780 -0
- data/test/cases/connection_test_sqlserver.rb +142 -0
- data/test/cases/execute_procedure_test_sqlserver.rb +44 -0
- data/test/cases/fetch_test_sqlserver.rb +57 -0
- data/test/cases/fully_qualified_identifier_test_sqlserver.rb +76 -0
- data/test/cases/helper_sqlserver.rb +54 -0
- data/test/cases/migration_test_sqlserver.rb +61 -0
- data/test/cases/order_test_sqlserver.rb +147 -0
- data/test/cases/pessimistic_locking_test_sqlserver.rb +90 -0
- data/test/cases/rake_test_sqlserver.rb +163 -0
- data/test/cases/schema_dumper_test_sqlserver.rb +198 -0
- data/test/cases/schema_test_sqlserver.rb +54 -0
- data/test/cases/scratchpad_test_sqlserver.rb +9 -0
- data/test/cases/showplan_test_sqlserver.rb +65 -0
- data/test/cases/specific_schema_test_sqlserver.rb +167 -0
- data/test/cases/transaction_test_sqlserver.rb +66 -0
- data/test/cases/utils_test_sqlserver.rb +129 -0
- data/test/cases/uuid_test_sqlserver.rb +48 -0
- data/test/config.yml +41 -0
- data/test/debug.rb +14 -0
- data/test/fixtures/1px.gif +0 -0
- data/test/migrations/transaction_table/1_table_will_never_be_created.rb +11 -0
- data/test/models/sqlserver/booking.rb +3 -0
- data/test/models/sqlserver/customers_view.rb +3 -0
- data/test/models/sqlserver/datatype.rb +3 -0
- data/test/models/sqlserver/datatype_migration.rb +3 -0
- data/test/models/sqlserver/dollar_table_name.rb +3 -0
- data/test/models/sqlserver/dot_table_name.rb +3 -0
- data/test/models/sqlserver/edge_schema.rb +13 -0
- data/test/models/sqlserver/fk_has_fk.rb +3 -0
- data/test/models/sqlserver/fk_has_pk.rb +3 -0
- data/test/models/sqlserver/natural_pk_data.rb +4 -0
- data/test/models/sqlserver/natural_pk_int_data.rb +3 -0
- data/test/models/sqlserver/no_pk_data.rb +3 -0
- data/test/models/sqlserver/object_default.rb +3 -0
- data/test/models/sqlserver/quoted_table.rb +7 -0
- data/test/models/sqlserver/quoted_view_1.rb +3 -0
- data/test/models/sqlserver/quoted_view_2.rb +3 -0
- data/test/models/sqlserver/string_default.rb +3 -0
- data/test/models/sqlserver/string_defaults_big_view.rb +3 -0
- data/test/models/sqlserver/string_defaults_view.rb +3 -0
- data/test/models/sqlserver/tinyint_pk.rb +3 -0
- data/test/models/sqlserver/upper.rb +3 -0
- data/test/models/sqlserver/uppered.rb +3 -0
- data/test/models/sqlserver/uuid.rb +3 -0
- data/test/schema/datatypes/2012.sql +55 -0
- data/test/schema/sqlserver_specific_schema.rb +207 -0
- data/test/support/coerceable_test_sqlserver.rb +45 -0
- data/test/support/connection_reflection.rb +37 -0
- data/test/support/load_schema_sqlserver.rb +29 -0
- data/test/support/minitest_sqlserver.rb +1 -0
- data/test/support/paths_sqlserver.rb +50 -0
- data/test/support/rake_helpers.rb +41 -0
- data/test/support/sql_counter_sqlserver.rb +32 -0
- metadata +253 -0
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
require 'cases/helper_sqlserver'
|
|
2
|
+
require 'models/reply'
|
|
3
|
+
require 'models/topic'
|
|
4
|
+
|
|
5
|
+
class ConnectionTestSQLServer < ActiveRecord::TestCase
|
|
6
|
+
|
|
7
|
+
self.use_transactional_fixtures = false
|
|
8
|
+
|
|
9
|
+
fixtures :topics, :accounts
|
|
10
|
+
|
|
11
|
+
before { assert connection.active? }
|
|
12
|
+
after { connection.reconnect! }
|
|
13
|
+
|
|
14
|
+
it 'affect rows' do
|
|
15
|
+
topic_data = { 1 => { "content" => "1 updated" }, 2 => { "content" => "2 updated" } }
|
|
16
|
+
updated = Topic.update(topic_data.keys, topic_data.values)
|
|
17
|
+
assert_equal 2, updated.size
|
|
18
|
+
assert_equal "1 updated", Topic.find(1).content
|
|
19
|
+
assert_equal "2 updated", Topic.find(2).content
|
|
20
|
+
assert_equal 2, Topic.delete([1, 2])
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it 'allow usage of :database connection option to remove setting from dsn' do
|
|
24
|
+
assert_equal 'activerecord_unittest', connection.current_database
|
|
25
|
+
begin
|
|
26
|
+
connection.use_database('activerecord_unittest2')
|
|
27
|
+
assert_equal 'activerecord_unittest2', connection.current_database
|
|
28
|
+
ensure
|
|
29
|
+
connection.use_database
|
|
30
|
+
assert_equal 'activerecord_unittest', connection.current_database, 'Would default back to connection options'
|
|
31
|
+
end
|
|
32
|
+
end unless connection_sqlserver_azure?
|
|
33
|
+
|
|
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
|
+
describe 'Connection management' do
|
|
90
|
+
|
|
91
|
+
it 'set spid on connect' do
|
|
92
|
+
assert_instance_of Fixnum, connection.spid
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
it 'reset spid on disconnect!' do
|
|
96
|
+
connection.disconnect!
|
|
97
|
+
assert connection.spid.nil?
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
it 'reset the connection' do
|
|
101
|
+
connection.disconnect!
|
|
102
|
+
connection.raw_connection.must_be_nil
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
it 'be able to disconnect and reconnect at will' do
|
|
106
|
+
disconnect_raw_connection!
|
|
107
|
+
assert !connection.active?
|
|
108
|
+
connection.reconnect!
|
|
109
|
+
assert connection.active?
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
private
|
|
116
|
+
|
|
117
|
+
def disconnect_raw_connection!
|
|
118
|
+
case connection_options[:mode]
|
|
119
|
+
when :dblib
|
|
120
|
+
connection.raw_connection.close rescue nil
|
|
121
|
+
when :odbc
|
|
122
|
+
connection.raw_connection.disconnect rescue nil
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
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
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
require 'cases/helper_sqlserver'
|
|
2
|
+
|
|
3
|
+
class ExecuteProcedureTestSQLServer < ActiveRecord::TestCase
|
|
4
|
+
|
|
5
|
+
it 'execute a simple procedure' do
|
|
6
|
+
tables = ActiveRecord::Base.execute_procedure :sp_tables
|
|
7
|
+
assert_instance_of Array, tables
|
|
8
|
+
assert tables.first.respond_to?(:keys)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it 'take parameter arguments' do
|
|
12
|
+
tables = ActiveRecord::Base.execute_procedure :sp_tables, 'sst_datatypes'
|
|
13
|
+
table_info = tables.first
|
|
14
|
+
assert_equal 1, tables.size
|
|
15
|
+
assert_equal (ENV['ARUNIT_DB_NAME'] || 'activerecord_unittest'), table_info['TABLE_QUALIFIER'], "Table Info: #{table_info.inspect}"
|
|
16
|
+
assert_equal 'TABLE', table_info['TABLE_TYPE'], "Table Info: #{table_info.inspect}"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it 'allow multiple result sets to be returned' do
|
|
20
|
+
results1, results2 = ActiveRecord::Base.execute_procedure('sp_helpconstraint','accounts')
|
|
21
|
+
assert_instance_of Array, results1
|
|
22
|
+
assert results1.first.respond_to?(:keys)
|
|
23
|
+
assert results1.first['Object Name']
|
|
24
|
+
assert_instance_of Array, results2
|
|
25
|
+
assert results2.first.respond_to?(:keys)
|
|
26
|
+
assert results2.first['constraint_name']
|
|
27
|
+
assert results2.first['constraint_type']
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it 'take named parameter arguments' do
|
|
31
|
+
tables = ActiveRecord::Base.execute_procedure :sp_tables, table_name: 'tables', table_owner: 'sys'
|
|
32
|
+
table_info = tables.first
|
|
33
|
+
assert_equal 1, tables.size
|
|
34
|
+
assert_equal (ENV['ARUNIT_DB_NAME'] || 'activerecord_unittest'), table_info['TABLE_QUALIFIER'], "Table Info: #{table_info.inspect}"
|
|
35
|
+
assert_equal 'VIEW', table_info['TABLE_TYPE'], "Table Info: #{table_info.inspect}"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it 'uses the proper timezone' do
|
|
39
|
+
date_proc = connection.execute_procedure('my_getutcdate').first['utcdate']
|
|
40
|
+
date_base = connection.select_value('select GETUTCDATE()')
|
|
41
|
+
assert_equal date_base.change(usec: 0), date_proc.change(usec: 0)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
require 'cases/helper_sqlserver'
|
|
2
|
+
require 'models/book'
|
|
3
|
+
|
|
4
|
+
class FetchTestSqlserver < ActiveRecord::TestCase
|
|
5
|
+
|
|
6
|
+
let(:books) { @books }
|
|
7
|
+
|
|
8
|
+
before { create_10_books }
|
|
9
|
+
|
|
10
|
+
it 'work with fully qualified table and columns in select' do
|
|
11
|
+
books = Book.select('books.id, books.name').limit(3).offset(5)
|
|
12
|
+
assert_equal Book.all[5,3].map(&:id), books.map(&:id)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
describe 'count' do
|
|
16
|
+
|
|
17
|
+
it 'gauntlet' do
|
|
18
|
+
books[0].destroy
|
|
19
|
+
books[1].destroy
|
|
20
|
+
books[2].destroy
|
|
21
|
+
assert_equal 7, Book.count
|
|
22
|
+
assert_equal 1, Book.limit(1).offset(1).count
|
|
23
|
+
assert_equal 1, Book.limit(1).offset(5).count
|
|
24
|
+
assert_equal 1, Book.limit(1).offset(6).count
|
|
25
|
+
assert_equal 0, Book.limit(1).offset(7).count
|
|
26
|
+
assert_equal 3, Book.limit(3).offset(4).count
|
|
27
|
+
assert_equal 2, Book.limit(3).offset(5).count
|
|
28
|
+
assert_equal 1, Book.limit(3).offset(6).count
|
|
29
|
+
assert_equal 0, Book.limit(3).offset(7).count
|
|
30
|
+
assert_equal 0, Book.limit(3).offset(8).count
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
describe 'order' do
|
|
36
|
+
|
|
37
|
+
it 'gauntlet' do
|
|
38
|
+
Book.where(name:'Name-10').delete_all
|
|
39
|
+
Book.order(:name).limit(1).offset(1).map(&:name).must_equal ['Name-2']
|
|
40
|
+
Book.order(:name).limit(2).offset(2).map(&:name).must_equal ['Name-3', 'Name-4']
|
|
41
|
+
Book.order(:name).limit(2).offset(7).map(&:name).must_equal ['Name-8', 'Name-9']
|
|
42
|
+
Book.order(:name).limit(3).offset(7).map(&:name).must_equal ['Name-8', 'Name-9']
|
|
43
|
+
Book.order(:name).limit(3).offset(9).map(&:name).must_equal []
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
protected
|
|
50
|
+
|
|
51
|
+
def create_10_books
|
|
52
|
+
Book.delete_all
|
|
53
|
+
@books = (1..10).map { |i| Book.create! name: "Name-#{i}" }
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
end
|
|
57
|
+
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
require 'cases/helper_sqlserver'
|
|
2
|
+
|
|
3
|
+
class FullyQualifiedIdentifierTestSQLServer < ActiveRecord::TestCase
|
|
4
|
+
|
|
5
|
+
describe 'local server' do
|
|
6
|
+
|
|
7
|
+
it 'should use table name in select projections' do
|
|
8
|
+
table = Arel::Table.new(:table)
|
|
9
|
+
expected_sql = "SELECT [table].[name] FROM [table]"
|
|
10
|
+
assert_equal expected_sql, table.project(table[:name]).to_sql
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
describe 'remote server' do
|
|
16
|
+
|
|
17
|
+
before do
|
|
18
|
+
connection_options[:database_prefix] = "[my.server].db.schema."
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
after do
|
|
22
|
+
connection_options.delete :database_prefix
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it 'should use fully qualified table name in select from clause' do
|
|
26
|
+
table = Arel::Table.new(:table)
|
|
27
|
+
expected_sql = "SELECT * FROM [my.server].[db].[schema].[table]"
|
|
28
|
+
assert_equal expected_sql, table.project(Arel.star).to_sql
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it 'should not use fully qualified table name in select projections' do
|
|
32
|
+
table = Arel::Table.new(:table)
|
|
33
|
+
expected_sql = "SELECT [table].[name] FROM [my.server].[db].[schema].[table]"
|
|
34
|
+
assert_equal expected_sql, table.project(table[:name]).to_sql
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it 'should not use fully qualified table name in where clause' do
|
|
38
|
+
table = Arel::Table.new(:table)
|
|
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
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it 'should not use fully qualified table name in order clause' do
|
|
44
|
+
table = Arel::Table.new(:table)
|
|
45
|
+
expected_sql = "SELECT * FROM [my.server].[db].[schema].[table] ORDER BY [table].[name]"
|
|
46
|
+
assert_equal expected_sql, table.project(Arel.star).order(table[:name]).to_sql
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it 'should use fully qualified table name in insert statement' do
|
|
50
|
+
manager = Arel::InsertManager.new(Arel::Table.engine)
|
|
51
|
+
manager.into Arel::Table.new(:table)
|
|
52
|
+
manager.values = manager.create_values [Arel.sql('*')], %w{ a }
|
|
53
|
+
expected_sql = "INSERT INTO [my.server].[db].[schema].[table] VALUES (*)"
|
|
54
|
+
assert_equal expected_sql, manager.to_sql
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it 'should use fully qualified table name in update statement' do
|
|
58
|
+
table = Arel::Table.new(:table)
|
|
59
|
+
manager = Arel::UpdateManager.new(Arel::Table.engine)
|
|
60
|
+
manager.table(table).where(table[:id].eq(42))
|
|
61
|
+
manager.set([[table[:name], "Bob"]])
|
|
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
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
it 'should use fully qualified table name in delete statement' do
|
|
67
|
+
table = Arel::Table.new(:table)
|
|
68
|
+
manager = Arel::DeleteManager.new(Arel::Table.engine)
|
|
69
|
+
manager.from(table).where(table[:id].eq(42))
|
|
70
|
+
expected_sql = "DELETE FROM [my.server].[db].[schema].[table] WHERE [table].[id] = 42"
|
|
71
|
+
assert_equal expected_sql, manager.to_sql
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
require 'support/paths_sqlserver'
|
|
2
|
+
require 'bundler/setup'
|
|
3
|
+
Bundler.require :default, :development
|
|
4
|
+
require 'support/minitest_sqlserver'
|
|
5
|
+
require 'cases/helper'
|
|
6
|
+
require 'support/load_schema_sqlserver'
|
|
7
|
+
require 'support/coerceable_test_sqlserver'
|
|
8
|
+
require 'support/sql_counter_sqlserver'
|
|
9
|
+
require 'support/connection_reflection'
|
|
10
|
+
require 'mocha/mini_test'
|
|
11
|
+
|
|
12
|
+
module ActiveRecord
|
|
13
|
+
class TestCase < ActiveSupport::TestCase
|
|
14
|
+
|
|
15
|
+
SQLServer = ActiveRecord::ConnectionAdapters::SQLServer
|
|
16
|
+
|
|
17
|
+
include ARTest::SQLServer::CoerceableTest,
|
|
18
|
+
ARTest::SQLServer::ConnectionReflection
|
|
19
|
+
|
|
20
|
+
let(:logger) { ActiveRecord::Base.logger }
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def host_windows?
|
|
26
|
+
RbConfig::CONFIG['host_os'] =~ /mswin|mingw/
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def with_use_output_inserted_disabled
|
|
30
|
+
klass = ActiveRecord::ConnectionAdapters::SQLServerAdapter
|
|
31
|
+
klass.use_output_inserted = false
|
|
32
|
+
yield
|
|
33
|
+
ensure
|
|
34
|
+
klass.use_output_inserted = true
|
|
35
|
+
end
|
|
36
|
+
|
|
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
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
Dir["#{ARTest::SQLServer.test_root_sqlserver}/models/**/*.rb"].each { |f| require f }
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
require 'cases/helper_sqlserver'
|
|
2
|
+
require 'models/person'
|
|
3
|
+
|
|
4
|
+
class MigrationTestSQLServer < ActiveRecord::TestCase
|
|
5
|
+
|
|
6
|
+
describe 'For transactions' do
|
|
7
|
+
|
|
8
|
+
before do
|
|
9
|
+
@trans_test_table1 = 'sqlserver_trans_table1'
|
|
10
|
+
@trans_test_table2 = 'sqlserver_trans_table2'
|
|
11
|
+
@trans_tables = [@trans_test_table1,@trans_test_table2]
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
after do
|
|
15
|
+
@trans_tables.each do |table_name|
|
|
16
|
+
ActiveRecord::Migration.drop_table(table_name) if connection.tables.include?(table_name)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it 'not create a tables if error in migrations' do
|
|
21
|
+
begin
|
|
22
|
+
migrations_dir = File.join ARTest::SQLServer.migrations_root, 'transaction_table'
|
|
23
|
+
quietly { ActiveRecord::Migrator.up(migrations_dir) }
|
|
24
|
+
rescue Exception => e
|
|
25
|
+
assert_match %r|this and all later migrations canceled|, e.message
|
|
26
|
+
end
|
|
27
|
+
connection.tables.wont_include @trans_test_table1
|
|
28
|
+
connection.tables.wont_include @trans_test_table2
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
describe 'For changing column' do
|
|
34
|
+
|
|
35
|
+
it 'not raise exception when column contains default constraint' do
|
|
36
|
+
lock_version_column = Person.columns_hash['lock_version']
|
|
37
|
+
assert_equal :integer, lock_version_column.type
|
|
38
|
+
assert lock_version_column.default.present?
|
|
39
|
+
assert_nothing_raised { connection.change_column 'people', 'lock_version', :string }
|
|
40
|
+
Person.reset_column_information
|
|
41
|
+
lock_version_column = Person.columns_hash['lock_version']
|
|
42
|
+
assert_equal :string, lock_version_column.type
|
|
43
|
+
assert lock_version_column.default.nil?
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it 'not drop the default contraint if just renaming' do
|
|
47
|
+
find_default = lambda do
|
|
48
|
+
connection.execute_procedure(:sp_helpconstraint, 'sst_string_defaults', 'nomsg').select do |row|
|
|
49
|
+
row['constraint_type'] == "DEFAULT on column string_with_pretend_paren_three"
|
|
50
|
+
end.last
|
|
51
|
+
end
|
|
52
|
+
default_before = find_default.call
|
|
53
|
+
connection.change_column :sst_string_defaults, :string_with_pretend_paren_three, :string, limit: 255
|
|
54
|
+
default_after = find_default.call
|
|
55
|
+
assert default_after
|
|
56
|
+
assert_equal default_before['constraint_keys'], default_after['constraint_keys']
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
end
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
require 'cases/helper_sqlserver'
|
|
2
|
+
require 'models/post'
|
|
3
|
+
|
|
4
|
+
class OrderTestSQLServer < ActiveRecord::TestCase
|
|
5
|
+
|
|
6
|
+
fixtures :posts
|
|
7
|
+
|
|
8
|
+
it 'not mangel complex order clauses' do
|
|
9
|
+
xyz_order = "CASE WHEN [title] LIKE N'XYZ%' THEN 0 ELSE 1 END"
|
|
10
|
+
xyz_post = Post.create title: 'XYZ Post', body: 'Test cased orders.'
|
|
11
|
+
assert_equal xyz_post, Post.order(Arel.sql(xyz_order)).first
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it 'support column' do
|
|
15
|
+
order = "title"
|
|
16
|
+
post1 = Post.create title: 'AAA Post', body: 'Test cased orders.'
|
|
17
|
+
assert_equal post1, Post.order(order).first
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it 'support column ASC' do
|
|
21
|
+
order = "title ASC"
|
|
22
|
+
post1 = Post.create title: 'AAA Post', body: 'Test cased orders.'
|
|
23
|
+
assert_equal post1, Post.order(order).first
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it 'support column DESC' do
|
|
27
|
+
order = "title DESC"
|
|
28
|
+
post1 = Post.create title: 'ZZZ Post', body: 'Test cased orders.'
|
|
29
|
+
assert_equal post1, Post.order(order).first
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it 'support column as symbol' do
|
|
33
|
+
order = :title
|
|
34
|
+
post1 = Post.create title: 'AAA Post', body: 'Test cased orders.'
|
|
35
|
+
assert_equal post1, Post.order(order).first
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it 'support table and column' do
|
|
39
|
+
order = "posts.title"
|
|
40
|
+
post1 = Post.create title: 'AAA Post', body: 'Test cased orders.'
|
|
41
|
+
assert_equal post1, Post.order(order).first
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it 'support quoted column' do
|
|
45
|
+
order = "[title]"
|
|
46
|
+
post1 = Post.create title: 'AAA Post', body: 'Test cased orders.'
|
|
47
|
+
assert_equal post1, Post.order(order).first
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it 'support quoted table and column' do
|
|
51
|
+
order = "[posts].[title]"
|
|
52
|
+
post1 = Post.create title: 'AAA Post', body: 'Test cased orders.'
|
|
53
|
+
assert_equal post1, Post.order(order).first
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it 'support primary: column, secondary: column' do
|
|
57
|
+
order = "title DESC, body"
|
|
58
|
+
post1 = Post.create title: 'ZZZ Post', body: 'Test cased orders.'
|
|
59
|
+
post2 = Post.create title: 'ZZZ Post', body: 'ZZZ Test cased orders.'
|
|
60
|
+
assert_equal post1, Post.order(order).first
|
|
61
|
+
assert_equal post2, Post.order(order).second
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it 'support primary: table and column, secondary: column' do
|
|
65
|
+
order = "posts.title DESC, body"
|
|
66
|
+
post1 = Post.create title: 'ZZZ Post', body: 'Test cased orders.'
|
|
67
|
+
post2 = Post.create title: 'ZZZ Post', body: 'ZZZ Test cased orders.'
|
|
68
|
+
assert_equal post1, Post.order(order).first
|
|
69
|
+
assert_equal post2, Post.order(order).second
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it 'support primary: case expression, secondary: column' do
|
|
73
|
+
order = "(CASE WHEN [title] LIKE N'ZZZ%' THEN title ELSE '' END) DESC, body"
|
|
74
|
+
post1 = Post.create title: 'ZZZ Post', body: 'Test cased orders.'
|
|
75
|
+
post2 = Post.create title: 'ZZZ Post', body: 'ZZZ Test cased orders.'
|
|
76
|
+
assert_equal post1, Post.order(order).first
|
|
77
|
+
assert_equal post2, Post.order(order).second
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it 'support primary: quoted table and column, secondary: case expresion' do
|
|
81
|
+
order = "[posts].[body] DESC, (CASE WHEN [title] LIKE N'ZZZ%' THEN title ELSE '' END) DESC"
|
|
82
|
+
post1 = Post.create title: 'ZZZ Post', body: 'ZZZ Test cased orders.'
|
|
83
|
+
post2 = Post.create title: 'ZZY Post', body: 'ZZZ Test cased orders.'
|
|
84
|
+
assert_equal post1, Post.order(order).first
|
|
85
|
+
assert_equal post2, Post.order(order).second
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
it 'support inline function' do
|
|
89
|
+
order = "LEN(title)"
|
|
90
|
+
post1 = Post.create title: 'A', body: 'AAA Test cased orders.'
|
|
91
|
+
assert_equal post1, Post.order(order).first
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
it 'support inline function with parameters' do
|
|
95
|
+
order = "SUBSTRING(title, 1, 3)"
|
|
96
|
+
post1 = Post.create title: 'AAA Post', body: 'Test cased orders.'
|
|
97
|
+
assert_equal post1, Post.order(order).first
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
it 'support inline function with parameters DESC' do
|
|
101
|
+
order = "SUBSTRING(title, 1, 3) DESC"
|
|
102
|
+
post1 = Post.create title: 'ZZZ Post', body: 'Test cased orders.'
|
|
103
|
+
assert_equal post1, Post.order(order).first
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
it 'support primary: inline function, secondary: column' do
|
|
107
|
+
order = "LEN(title), body"
|
|
108
|
+
post1 = Post.create title: 'A', body: 'AAA Test cased orders.'
|
|
109
|
+
post2 = Post.create title: 'A', body: 'Test cased orders.'
|
|
110
|
+
assert_equal post1, Post.order(order).first
|
|
111
|
+
assert_equal post2, Post.order(order).second
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
it 'support primary: inline function, secondary: column with direction' do
|
|
115
|
+
order = "LEN(title) ASC, body DESC"
|
|
116
|
+
post1 = Post.create title: 'A', body: 'ZZZ Test cased orders.'
|
|
117
|
+
post2 = Post.create title: 'A', body: 'Test cased orders.'
|
|
118
|
+
assert_equal post1, Post.order(order).first
|
|
119
|
+
assert_equal post2, Post.order(order).second
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
it 'support primary: column, secondary: inline function' do
|
|
123
|
+
order = "body DESC, LEN(title)"
|
|
124
|
+
post1 = Post.create title: 'Post', body: 'ZZZ Test cased orders.'
|
|
125
|
+
post2 = Post.create title: 'Longer Post', body: 'ZZZ Test cased orders.'
|
|
126
|
+
assert_equal post1, Post.order(order).first
|
|
127
|
+
assert_equal post2, Post.order(order).second
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
it 'support primary: case expression, secondary: inline function' do
|
|
131
|
+
order = "CASE WHEN [title] LIKE N'ZZZ%' THEN title ELSE '' END DESC, LEN(body) ASC"
|
|
132
|
+
post1 = Post.create title: 'ZZZ Post', body: 'Z'
|
|
133
|
+
post2 = Post.create title: 'ZZZ Post', body: 'Test cased orders.'
|
|
134
|
+
assert_equal post1, Post.order(order).first
|
|
135
|
+
assert_equal post2, Post.order(order).second
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
it 'support primary: inline function, secondary: case expression' do
|
|
139
|
+
order = "LEN(body), CASE WHEN [title] LIKE N'ZZZ%' THEN title ELSE '' END DESC"
|
|
140
|
+
post1 = Post.create title: 'ZZZ Post', body: 'Z'
|
|
141
|
+
post2 = Post.create title: 'Post', body: 'Z'
|
|
142
|
+
assert_equal post1, Post.order(order).first
|
|
143
|
+
assert_equal post2, Post.order(order).second
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
end
|