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.
Files changed (132) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/CHANGELOG.md +212 -0
  4. data/CODE_OF_CONDUCT.md +31 -0
  5. data/Gemfile +61 -0
  6. data/Guardfile +29 -0
  7. data/MIT-LICENSE +20 -0
  8. data/README.md +201 -0
  9. data/RUNNING_UNIT_TESTS.md +121 -0
  10. data/Rakefile +48 -0
  11. data/VERSION +1 -0
  12. data/activerecord-sqlserver-adapter_new.gemspec +20 -0
  13. data/appveyor.yml +39 -0
  14. data/lib/active_record/connection_adapters/sqlserver/core_ext/active_record.rb +27 -0
  15. data/lib/active_record/connection_adapters/sqlserver/core_ext/attribute_methods.rb +25 -0
  16. data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +40 -0
  17. data/lib/active_record/connection_adapters/sqlserver/core_ext/explain_subscriber.rb +4 -0
  18. data/lib/active_record/connection_adapters/sqlserver/core_ext/odbc.rb +34 -0
  19. data/lib/active_record/connection_adapters/sqlserver/database_limits.rb +49 -0
  20. data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +386 -0
  21. data/lib/active_record/connection_adapters/sqlserver/database_tasks.rb +68 -0
  22. data/lib/active_record/connection_adapters/sqlserver/errors.rb +7 -0
  23. data/lib/active_record/connection_adapters/sqlserver/quoting.rb +69 -0
  24. data/lib/active_record/connection_adapters/sqlserver/schema_cache.rb +114 -0
  25. data/lib/active_record/connection_adapters/sqlserver/schema_creation.rb +52 -0
  26. data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +473 -0
  27. data/lib/active_record/connection_adapters/sqlserver/showplan.rb +66 -0
  28. data/lib/active_record/connection_adapters/sqlserver/showplan/printer_table.rb +66 -0
  29. data/lib/active_record/connection_adapters/sqlserver/showplan/printer_xml.rb +22 -0
  30. data/lib/active_record/connection_adapters/sqlserver/table_definition.rb +76 -0
  31. data/lib/active_record/connection_adapters/sqlserver/transaction.rb +57 -0
  32. data/lib/active_record/connection_adapters/sqlserver/type.rb +46 -0
  33. data/lib/active_record/connection_adapters/sqlserver/type/big_integer.rb +15 -0
  34. data/lib/active_record/connection_adapters/sqlserver/type/binary.rb +15 -0
  35. data/lib/active_record/connection_adapters/sqlserver/type/boolean.rb +12 -0
  36. data/lib/active_record/connection_adapters/sqlserver/type/char.rb +38 -0
  37. data/lib/active_record/connection_adapters/sqlserver/type/date.rb +21 -0
  38. data/lib/active_record/connection_adapters/sqlserver/type/datetime.rb +41 -0
  39. data/lib/active_record/connection_adapters/sqlserver/type/datetime2.rb +17 -0
  40. data/lib/active_record/connection_adapters/sqlserver/type/datetimeoffset.rb +31 -0
  41. data/lib/active_record/connection_adapters/sqlserver/type/decimal.rb +12 -0
  42. data/lib/active_record/connection_adapters/sqlserver/type/float.rb +15 -0
  43. data/lib/active_record/connection_adapters/sqlserver/type/integer.rb +12 -0
  44. data/lib/active_record/connection_adapters/sqlserver/type/money.rb +21 -0
  45. data/lib/active_record/connection_adapters/sqlserver/type/real.rb +15 -0
  46. data/lib/active_record/connection_adapters/sqlserver/type/small_integer.rb +13 -0
  47. data/lib/active_record/connection_adapters/sqlserver/type/small_money.rb +21 -0
  48. data/lib/active_record/connection_adapters/sqlserver/type/smalldatetime.rb +22 -0
  49. data/lib/active_record/connection_adapters/sqlserver/type/string.rb +12 -0
  50. data/lib/active_record/connection_adapters/sqlserver/type/text.rb +15 -0
  51. data/lib/active_record/connection_adapters/sqlserver/type/time.rb +40 -0
  52. data/lib/active_record/connection_adapters/sqlserver/type/time_value_fractional.rb +76 -0
  53. data/lib/active_record/connection_adapters/sqlserver/type/timestamp.rb +15 -0
  54. data/lib/active_record/connection_adapters/sqlserver/type/tiny_integer.rb +22 -0
  55. data/lib/active_record/connection_adapters/sqlserver/type/unicode_char.rb +15 -0
  56. data/lib/active_record/connection_adapters/sqlserver/type/unicode_string.rb +12 -0
  57. data/lib/active_record/connection_adapters/sqlserver/type/unicode_text.rb +15 -0
  58. data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar.rb +20 -0
  59. data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar_max.rb +20 -0
  60. data/lib/active_record/connection_adapters/sqlserver/type/uuid.rb +23 -0
  61. data/lib/active_record/connection_adapters/sqlserver/type/varbinary.rb +20 -0
  62. data/lib/active_record/connection_adapters/sqlserver/type/varbinary_max.rb +20 -0
  63. data/lib/active_record/connection_adapters/sqlserver/type/varchar.rb +20 -0
  64. data/lib/active_record/connection_adapters/sqlserver/type/varchar_max.rb +20 -0
  65. data/lib/active_record/connection_adapters/sqlserver/utils.rb +136 -0
  66. data/lib/active_record/connection_adapters/sqlserver/version.rb +11 -0
  67. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +405 -0
  68. data/lib/active_record/connection_adapters/sqlserver_column.rb +53 -0
  69. data/lib/active_record/sqlserver_base.rb +20 -0
  70. data/lib/active_record/tasks/sqlserver_database_tasks.rb +131 -0
  71. data/lib/activerecord-sqlserver-adapter.rb +1 -0
  72. data/lib/arel/visitors/sqlserver.rb +214 -0
  73. data/lib/arel_sqlserver.rb +3 -0
  74. data/test/appveyor/dbsetup.ps1 +27 -0
  75. data/test/appveyor/dbsetup.sql +11 -0
  76. data/test/cases/adapter_test_sqlserver.rb +444 -0
  77. data/test/cases/coerced_tests.rb +713 -0
  78. data/test/cases/column_test_sqlserver.rb +780 -0
  79. data/test/cases/connection_test_sqlserver.rb +142 -0
  80. data/test/cases/execute_procedure_test_sqlserver.rb +44 -0
  81. data/test/cases/fetch_test_sqlserver.rb +57 -0
  82. data/test/cases/fully_qualified_identifier_test_sqlserver.rb +76 -0
  83. data/test/cases/helper_sqlserver.rb +54 -0
  84. data/test/cases/migration_test_sqlserver.rb +61 -0
  85. data/test/cases/order_test_sqlserver.rb +147 -0
  86. data/test/cases/pessimistic_locking_test_sqlserver.rb +90 -0
  87. data/test/cases/rake_test_sqlserver.rb +163 -0
  88. data/test/cases/schema_dumper_test_sqlserver.rb +198 -0
  89. data/test/cases/schema_test_sqlserver.rb +54 -0
  90. data/test/cases/scratchpad_test_sqlserver.rb +9 -0
  91. data/test/cases/showplan_test_sqlserver.rb +65 -0
  92. data/test/cases/specific_schema_test_sqlserver.rb +167 -0
  93. data/test/cases/transaction_test_sqlserver.rb +66 -0
  94. data/test/cases/utils_test_sqlserver.rb +129 -0
  95. data/test/cases/uuid_test_sqlserver.rb +48 -0
  96. data/test/config.yml +41 -0
  97. data/test/debug.rb +14 -0
  98. data/test/fixtures/1px.gif +0 -0
  99. data/test/migrations/transaction_table/1_table_will_never_be_created.rb +11 -0
  100. data/test/models/sqlserver/booking.rb +3 -0
  101. data/test/models/sqlserver/customers_view.rb +3 -0
  102. data/test/models/sqlserver/datatype.rb +3 -0
  103. data/test/models/sqlserver/datatype_migration.rb +3 -0
  104. data/test/models/sqlserver/dollar_table_name.rb +3 -0
  105. data/test/models/sqlserver/dot_table_name.rb +3 -0
  106. data/test/models/sqlserver/edge_schema.rb +13 -0
  107. data/test/models/sqlserver/fk_has_fk.rb +3 -0
  108. data/test/models/sqlserver/fk_has_pk.rb +3 -0
  109. data/test/models/sqlserver/natural_pk_data.rb +4 -0
  110. data/test/models/sqlserver/natural_pk_int_data.rb +3 -0
  111. data/test/models/sqlserver/no_pk_data.rb +3 -0
  112. data/test/models/sqlserver/object_default.rb +3 -0
  113. data/test/models/sqlserver/quoted_table.rb +7 -0
  114. data/test/models/sqlserver/quoted_view_1.rb +3 -0
  115. data/test/models/sqlserver/quoted_view_2.rb +3 -0
  116. data/test/models/sqlserver/string_default.rb +3 -0
  117. data/test/models/sqlserver/string_defaults_big_view.rb +3 -0
  118. data/test/models/sqlserver/string_defaults_view.rb +3 -0
  119. data/test/models/sqlserver/tinyint_pk.rb +3 -0
  120. data/test/models/sqlserver/upper.rb +3 -0
  121. data/test/models/sqlserver/uppered.rb +3 -0
  122. data/test/models/sqlserver/uuid.rb +3 -0
  123. data/test/schema/datatypes/2012.sql +55 -0
  124. data/test/schema/sqlserver_specific_schema.rb +207 -0
  125. data/test/support/coerceable_test_sqlserver.rb +45 -0
  126. data/test/support/connection_reflection.rb +37 -0
  127. data/test/support/load_schema_sqlserver.rb +29 -0
  128. data/test/support/minitest_sqlserver.rb +1 -0
  129. data/test/support/paths_sqlserver.rb +50 -0
  130. data/test/support/rake_helpers.rb +41 -0
  131. data/test/support/sql_counter_sqlserver.rb +32 -0
  132. 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