activerecord-sqlserver-adapter 5.2.1 → 6.0.2

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 (153) hide show
  1. checksums.yaml +4 -4
  2. data/.editorconfig +9 -0
  3. data/.github/issue_template.md +23 -0
  4. data/.github/workflows/ci.yml +26 -0
  5. data/.gitignore +1 -0
  6. data/.rubocop.yml +29 -0
  7. data/CHANGELOG.md +58 -20
  8. data/{Dockerfile → Dockerfile.ci} +1 -1
  9. data/Gemfile +48 -41
  10. data/Guardfile +9 -8
  11. data/README.md +28 -31
  12. data/RUNNING_UNIT_TESTS.md +3 -0
  13. data/Rakefile +14 -16
  14. data/VERSION +1 -1
  15. data/activerecord-sqlserver-adapter.gemspec +25 -14
  16. data/appveyor.yml +24 -17
  17. data/docker-compose.ci.yml +7 -5
  18. data/guides/RELEASING.md +11 -0
  19. data/lib/active_record/connection_adapters/sqlserver/core_ext/active_record.rb +2 -4
  20. data/lib/active_record/connection_adapters/sqlserver/core_ext/attribute_methods.rb +3 -4
  21. data/lib/active_record/connection_adapters/sqlserver/core_ext/calculations.rb +5 -4
  22. data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +3 -3
  23. data/lib/active_record/connection_adapters/sqlserver/core_ext/explain_subscriber.rb +2 -0
  24. data/lib/active_record/connection_adapters/sqlserver/core_ext/finder_methods.rb +8 -7
  25. data/lib/active_record/connection_adapters/sqlserver/core_ext/preloader.rb +36 -0
  26. data/lib/active_record/connection_adapters/sqlserver/core_ext/query_methods.rb +6 -4
  27. data/lib/active_record/connection_adapters/sqlserver/database_limits.rb +9 -0
  28. data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +88 -44
  29. data/lib/active_record/connection_adapters/sqlserver/database_tasks.rb +9 -12
  30. data/lib/active_record/connection_adapters/sqlserver/errors.rb +2 -3
  31. data/lib/active_record/connection_adapters/sqlserver/quoting.rb +46 -8
  32. data/lib/active_record/connection_adapters/sqlserver/schema_creation.rb +16 -5
  33. data/lib/active_record/connection_adapters/sqlserver/schema_dumper.rb +9 -7
  34. data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +210 -163
  35. data/lib/active_record/connection_adapters/sqlserver/showplan.rb +8 -8
  36. data/lib/active_record/connection_adapters/sqlserver/showplan/printer_table.rb +4 -2
  37. data/lib/active_record/connection_adapters/sqlserver/showplan/printer_xml.rb +3 -1
  38. data/lib/active_record/connection_adapters/sqlserver/sql_type_metadata.rb +2 -2
  39. data/lib/active_record/connection_adapters/sqlserver/table_definition.rb +43 -44
  40. data/lib/active_record/connection_adapters/sqlserver/transaction.rb +7 -9
  41. data/lib/active_record/connection_adapters/sqlserver/type.rb +38 -35
  42. data/lib/active_record/connection_adapters/sqlserver/type/big_integer.rb +3 -3
  43. data/lib/active_record/connection_adapters/sqlserver/type/binary.rb +5 -4
  44. data/lib/active_record/connection_adapters/sqlserver/type/boolean.rb +3 -3
  45. data/lib/active_record/connection_adapters/sqlserver/type/char.rb +7 -4
  46. data/lib/active_record/connection_adapters/sqlserver/type/data.rb +2 -2
  47. data/lib/active_record/connection_adapters/sqlserver/type/date.rb +4 -3
  48. data/lib/active_record/connection_adapters/sqlserver/type/datetime.rb +8 -8
  49. data/lib/active_record/connection_adapters/sqlserver/type/datetime2.rb +2 -2
  50. data/lib/active_record/connection_adapters/sqlserver/type/datetimeoffset.rb +2 -2
  51. data/lib/active_record/connection_adapters/sqlserver/type/decimal.rb +5 -4
  52. data/lib/active_record/connection_adapters/sqlserver/type/decimal_without_scale.rb +22 -0
  53. data/lib/active_record/connection_adapters/sqlserver/type/float.rb +3 -3
  54. data/lib/active_record/connection_adapters/sqlserver/type/integer.rb +3 -3
  55. data/lib/active_record/connection_adapters/sqlserver/type/json.rb +2 -1
  56. data/lib/active_record/connection_adapters/sqlserver/type/money.rb +4 -4
  57. data/lib/active_record/connection_adapters/sqlserver/type/real.rb +3 -3
  58. data/lib/active_record/connection_adapters/sqlserver/type/small_integer.rb +3 -3
  59. data/lib/active_record/connection_adapters/sqlserver/type/small_money.rb +4 -4
  60. data/lib/active_record/connection_adapters/sqlserver/type/smalldatetime.rb +3 -3
  61. data/lib/active_record/connection_adapters/sqlserver/type/string.rb +2 -2
  62. data/lib/active_record/connection_adapters/sqlserver/type/text.rb +3 -3
  63. data/lib/active_record/connection_adapters/sqlserver/type/time.rb +6 -6
  64. data/lib/active_record/connection_adapters/sqlserver/type/time_value_fractional.rb +8 -9
  65. data/lib/active_record/connection_adapters/sqlserver/type/timestamp.rb +3 -3
  66. data/lib/active_record/connection_adapters/sqlserver/type/tiny_integer.rb +3 -3
  67. data/lib/active_record/connection_adapters/sqlserver/type/unicode_char.rb +5 -4
  68. data/lib/active_record/connection_adapters/sqlserver/type/unicode_string.rb +2 -2
  69. data/lib/active_record/connection_adapters/sqlserver/type/unicode_text.rb +3 -3
  70. data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar.rb +6 -5
  71. data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar_max.rb +4 -4
  72. data/lib/active_record/connection_adapters/sqlserver/type/uuid.rb +4 -3
  73. data/lib/active_record/connection_adapters/sqlserver/type/varbinary.rb +6 -5
  74. data/lib/active_record/connection_adapters/sqlserver/type/varbinary_max.rb +4 -4
  75. data/lib/active_record/connection_adapters/sqlserver/type/varchar.rb +6 -5
  76. data/lib/active_record/connection_adapters/sqlserver/type/varchar_max.rb +4 -4
  77. data/lib/active_record/connection_adapters/sqlserver/utils.rb +10 -11
  78. data/lib/active_record/connection_adapters/sqlserver/version.rb +2 -2
  79. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +145 -94
  80. data/lib/active_record/connection_adapters/sqlserver_column.rb +9 -5
  81. data/lib/active_record/sqlserver_base.rb +9 -1
  82. data/lib/active_record/tasks/sqlserver_database_tasks.rb +28 -32
  83. data/lib/activerecord-sqlserver-adapter.rb +3 -1
  84. data/lib/arel/visitors/sqlserver.rb +108 -34
  85. data/lib/arel_sqlserver.rb +4 -2
  86. data/test/appveyor/dbsetup.ps1 +4 -4
  87. data/test/cases/adapter_test_sqlserver.rb +246 -171
  88. data/test/cases/change_column_null_test_sqlserver.rb +14 -12
  89. data/test/cases/coerced_tests.rb +722 -381
  90. data/test/cases/column_test_sqlserver.rb +287 -285
  91. data/test/cases/connection_test_sqlserver.rb +17 -20
  92. data/test/cases/execute_procedure_test_sqlserver.rb +20 -20
  93. data/test/cases/fetch_test_sqlserver.rb +16 -22
  94. data/test/cases/fully_qualified_identifier_test_sqlserver.rb +15 -19
  95. data/test/cases/helper_sqlserver.rb +15 -15
  96. data/test/cases/in_clause_test_sqlserver.rb +36 -0
  97. data/test/cases/index_test_sqlserver.rb +15 -15
  98. data/test/cases/json_test_sqlserver.rb +25 -25
  99. data/test/cases/lateral_test_sqlserver.rb +35 -0
  100. data/test/cases/migration_test_sqlserver.rb +67 -27
  101. data/test/cases/optimizer_hints_test_sqlserver.rb +72 -0
  102. data/test/cases/order_test_sqlserver.rb +53 -54
  103. data/test/cases/pessimistic_locking_test_sqlserver.rb +27 -33
  104. data/test/cases/rake_test_sqlserver.rb +33 -45
  105. data/test/cases/schema_dumper_test_sqlserver.rb +115 -109
  106. data/test/cases/schema_test_sqlserver.rb +20 -26
  107. data/test/cases/scratchpad_test_sqlserver.rb +4 -4
  108. data/test/cases/showplan_test_sqlserver.rb +28 -35
  109. data/test/cases/specific_schema_test_sqlserver.rb +68 -65
  110. data/test/cases/transaction_test_sqlserver.rb +18 -20
  111. data/test/cases/trigger_test_sqlserver.rb +14 -13
  112. data/test/cases/utils_test_sqlserver.rb +70 -70
  113. data/test/cases/uuid_test_sqlserver.rb +13 -14
  114. data/test/debug.rb +8 -6
  115. data/test/migrations/create_clients_and_change_column_null.rb +3 -1
  116. data/test/migrations/transaction_table/1_table_will_never_be_created.rb +4 -4
  117. data/test/models/sqlserver/booking.rb +3 -1
  118. data/test/models/sqlserver/customers_view.rb +3 -1
  119. data/test/models/sqlserver/datatype.rb +2 -0
  120. data/test/models/sqlserver/datatype_migration.rb +2 -0
  121. data/test/models/sqlserver/dollar_table_name.rb +3 -1
  122. data/test/models/sqlserver/edge_schema.rb +3 -3
  123. data/test/models/sqlserver/fk_has_fk.rb +3 -1
  124. data/test/models/sqlserver/fk_has_pk.rb +3 -1
  125. data/test/models/sqlserver/natural_pk_data.rb +4 -2
  126. data/test/models/sqlserver/natural_pk_int_data.rb +3 -1
  127. data/test/models/sqlserver/no_pk_data.rb +3 -1
  128. data/test/models/sqlserver/object_default.rb +3 -1
  129. data/test/models/sqlserver/quoted_table.rb +4 -2
  130. data/test/models/sqlserver/quoted_view_1.rb +3 -1
  131. data/test/models/sqlserver/quoted_view_2.rb +3 -1
  132. data/test/models/sqlserver/sst_memory.rb +3 -1
  133. data/test/models/sqlserver/string_default.rb +3 -1
  134. data/test/models/sqlserver/string_defaults_big_view.rb +3 -1
  135. data/test/models/sqlserver/string_defaults_view.rb +3 -1
  136. data/test/models/sqlserver/tinyint_pk.rb +3 -1
  137. data/test/models/sqlserver/trigger.rb +4 -2
  138. data/test/models/sqlserver/trigger_history.rb +3 -1
  139. data/test/models/sqlserver/upper.rb +3 -1
  140. data/test/models/sqlserver/uppered.rb +3 -1
  141. data/test/models/sqlserver/uuid.rb +3 -1
  142. data/test/schema/sqlserver_specific_schema.rb +31 -21
  143. data/test/support/coerceable_test_sqlserver.rb +15 -9
  144. data/test/support/connection_reflection.rb +3 -2
  145. data/test/support/core_ext/query_cache.rb +4 -1
  146. data/test/support/load_schema_sqlserver.rb +5 -5
  147. data/test/support/minitest_sqlserver.rb +3 -1
  148. data/test/support/paths_sqlserver.rb +11 -11
  149. data/test/support/rake_helpers.rb +13 -10
  150. data/test/support/sql_counter_sqlserver.rb +3 -4
  151. data/test/support/test_in_memory_oltp.rb +9 -7
  152. metadata +27 -12
  153. data/.travis.yml +0 -25
@@ -1,2 +1,4 @@
1
- require 'arel'
2
- require 'arel/visitors/sqlserver'
1
+ # frozen_string_literal: true
2
+
3
+ require "arel"
4
+ require "arel/visitors/sqlserver"
@@ -5,15 +5,15 @@ Write-Output "Setting up..."
5
5
 
6
6
  Write-Output "Setting variables..."
7
7
  $serverName = $env:COMPUTERNAME
8
- $instances = @('SQL2012SP1', 'SQL2014')
8
+ $instanceNames = @('SQL2014')
9
9
  $smo = 'Microsoft.SqlServer.Management.Smo.'
10
10
  $wmi = new-object ($smo + 'Wmi.ManagedComputer')
11
11
 
12
12
  Write-Output "Configure Instances..."
13
- foreach ($instance in $instances) {
14
- Write-Output "Instance $instance ..."
13
+ foreach ($instanceName in $instanceNames) {
14
+ Write-Output "Instance $instanceName ..."
15
15
  Write-Output "Enable TCP/IP and port 1433..."
16
- $uri = "ManagedComputer[@Name='$serverName']/ServerInstance[@Name='$instance']/ServerProtocol[@Name='Tcp']"
16
+ $uri = "ManagedComputer[@Name='$serverName']/ServerInstance[@Name='$instanceName']/ServerProtocol[@Name='Tcp']"
17
17
  $tcp = $wmi.GetSmoObject($uri)
18
18
  $tcp.IsEnabled = $true
19
19
  foreach ($ipAddress in $Tcp.IPAddresses) {
@@ -1,19 +1,21 @@
1
- require 'cases/helper_sqlserver'
2
- require 'models/topic'
3
- require 'models/task'
4
- require 'models/post'
5
- require 'models/subscriber'
6
- require 'models/minimalistic'
1
+ # frozen_string_literal: true
7
2
 
8
- class AdapterTestSQLServer < ActiveRecord::TestCase
3
+ require "cases/helper_sqlserver"
4
+ require "models/topic"
5
+ require "models/task"
6
+ require "models/post"
7
+ require "models/subscriber"
8
+ require "models/minimalistic"
9
+ require "models/college"
9
10
 
11
+ class AdapterTestSQLServer < ActiveRecord::TestCase
10
12
  fixtures :tasks
11
13
 
12
14
  let(:basic_insert_sql) { "INSERT INTO [funny_jokes] ([name]) VALUES('Knock knock')" }
13
15
  let(:basic_update_sql) { "UPDATE [customers] SET [address_street] = NULL WHERE [id] = 2" }
14
16
  let(:basic_select_sql) { "SELECT * FROM [customers] WHERE ([customers].[id] = 1)" }
15
17
 
16
- it 'has basic and non-senstive information in the adpaters inspect method' do
18
+ it "has basic and non-sensitive information in the adapters inspect method" do
17
19
  string = connection.inspect
18
20
  _(string).must_match %r{ActiveRecord::ConnectionAdapters::SQLServerAdapter}
19
21
  _(string).must_match %r{version\: \d.\d}
@@ -25,48 +27,97 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
25
27
  _(string).wont_match %r{port}
26
28
  end
27
29
 
28
- it 'has a 128 max #table_alias_length' do
30
+ it "has a 128 max #table_alias_length" do
29
31
  assert connection.table_alias_length <= 128
30
32
  end
31
33
 
32
- it 'raises invalid statement error for bad SQL' do
34
+ it "raises invalid statement error for bad SQL" do
33
35
  assert_raise(ActiveRecord::StatementInvalid) { Topic.connection.update("UPDATE XXX") }
34
36
  end
35
37
 
36
- it 'is has our adapter_name' do
37
- assert_equal 'SQLServer', connection.adapter_name
38
+ it "is has our adapter_name" do
39
+ assert_equal "SQLServer", connection.adapter_name
38
40
  end
39
41
 
40
- it 'support DDL in transactions' do
42
+ it "support DDL in transactions" do
41
43
  assert connection.supports_ddl_transactions?
42
44
  end
43
45
 
44
- it 'allow owner table name prefixs like dbo to still allow table exists to return true' do
46
+ it "table exists works if table name prefixed by schema and owner" do
45
47
  begin
46
- assert_equal 'topics', Topic.table_name
48
+ assert_equal "topics", Topic.table_name
47
49
  assert Topic.table_exists?
48
- Topic.table_name = 'dbo.topics'
49
- assert Topic.table_exists?, 'Tasks table name of dbo.topics should return true for exists.'
50
+
51
+ # Test when owner included in table name.
52
+ Topic.table_name = "dbo.topics"
53
+ assert Topic.table_exists?, "Topics table name of 'dbo.topics' should return true for exists."
54
+
55
+ # Test when database and owner included in table name.
56
+ Topic.table_name = "#{ActiveRecord::Base.configurations["arunit"]['database']}.dbo.topics"
57
+ assert Topic.table_exists?, "Topics table name of '[DATABASE].dbo.topics' should return true for exists."
50
58
  ensure
51
- Topic.table_name = 'topics'
59
+ Topic.table_name = "topics"
52
60
  end
53
61
  end
54
62
 
55
- it 'return true to insert sql query for inserts only' do
56
- assert connection.send(:insert_sql?,'INSERT...')
63
+ it "test table existence across database schemas" do
64
+ arunit_connection = Topic.connection
65
+ arunit2_connection = College.connection
66
+
67
+ arunit_database = arunit_connection.pool.spec.config[:database]
68
+ arunit2_database = arunit2_connection.pool.spec.config[:database]
69
+
70
+ # Assert that connections use different default databases schemas.
71
+ assert_not_equal arunit_database, arunit2_database
72
+
73
+ # Assert that the Topics table exists when using the Topics connection.
74
+ assert arunit_connection.table_exists?('topics'), 'Topics table exists using table name'
75
+ assert arunit_connection.table_exists?('dbo.topics'), 'Topics table exists using owner and table name'
76
+ assert arunit_connection.table_exists?("#{arunit_database}.dbo.topics"), 'Topics table exists using database, owner and table name'
77
+
78
+ # Assert that the Colleges table exists when using the Colleges connection.
79
+ assert arunit2_connection.table_exists?('colleges'), 'College table exists using table name'
80
+ assert arunit2_connection.table_exists?('dbo.colleges'), 'College table exists using owner and table name'
81
+ assert arunit2_connection.table_exists?("#{arunit2_database}.dbo.colleges"), 'College table exists using database, owner and table name'
82
+
83
+ # Assert that the tables exist when using each others connection.
84
+ assert arunit_connection.table_exists?("#{arunit2_database}.dbo.colleges"), 'Colleges table exists using Topics connection'
85
+ assert arunit2_connection.table_exists?("#{arunit_database}.dbo.topics"), 'Topics table exists using Colleges connection'
86
+ end
87
+
88
+ it "return true to insert sql query for inserts only" do
89
+ assert connection.send(:insert_sql?, "INSERT...")
57
90
  assert connection.send(:insert_sql?, "EXEC sp_executesql N'INSERT INTO [fk_test_has_fks] ([fk_id]) VALUES (@0); SELECT CAST(SCOPE_IDENTITY() AS bigint) AS Ident', N'@0 int', @0 = 0")
58
- assert !connection.send(:insert_sql?,'UPDATE...')
59
- assert !connection.send(:insert_sql?,'SELECT...')
91
+ assert !connection.send(:insert_sql?, "UPDATE...")
92
+ assert !connection.send(:insert_sql?, "SELECT...")
93
+ end
94
+
95
+ it "return unquoted table name object from basic INSERT UPDATE and SELECT statements" do
96
+ assert_equal "funny_jokes", connection.send(:get_table_name, basic_insert_sql)
97
+ assert_equal "customers", connection.send(:get_table_name, basic_update_sql)
98
+ assert_equal "customers", connection.send(:get_table_name, basic_select_sql)
60
99
  end
61
100
 
62
- it 'return unquoted table name object from basic INSERT UPDATE and SELECT statements' do
63
- assert_equal 'funny_jokes', connection.send(:get_table_name, basic_insert_sql)
64
- assert_equal 'customers', connection.send(:get_table_name, basic_update_sql)
65
- assert_equal 'customers', connection.send(:get_table_name, basic_select_sql)
101
+ it "test bad connection" do
102
+ assert_raise ActiveRecord::NoDatabaseError do
103
+ config = ActiveRecord::Base.configurations["arunit"].merge(database: "inexistent_activerecord_unittest")
104
+ ActiveRecord::Base.sqlserver_connection config
105
+ end
106
+ end
107
+
108
+ it "test database exists returns false if database does not exist" do
109
+ config = ActiveRecord::Base.configurations["arunit"].merge(database: "inexistent_activerecord_unittest")
110
+ assert_not ActiveRecord::ConnectionAdapters::SQLServerAdapter.database_exists?(config),
111
+ "expected database to not exist"
66
112
  end
67
113
 
68
- describe 'with different language' do
114
+ it "test database exists returns true when the database exists" do
115
+ config = ActiveRecord::Base.configurations["arunit"]
116
+ assert ActiveRecord::ConnectionAdapters::SQLServerAdapter.database_exists?(config),
117
+ "expected database #{config[:database]} to exist"
118
+ end
69
119
 
120
+ describe "with different language" do
70
121
  before do
71
122
  @default_language = connection.user_options_language
72
123
  end
@@ -76,18 +127,18 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
76
127
  connection.send :initialize_dateformatter
77
128
  end
78
129
 
79
- it 'memos users dateformat' do
130
+ it "memos users dateformat" do
80
131
  connection.execute("SET LANGUAGE us_english") rescue nil
81
132
  dateformat = connection.instance_variable_get(:@database_dateformat)
82
- assert_equal 'mdy', dateformat
133
+ assert_equal "mdy", dateformat
83
134
  end
84
135
 
85
- it 'has a dateformatter' do
136
+ it "has a dateformatter" do
86
137
  assert Date::DATE_FORMATS[:_sqlserver_dateformat]
87
138
  assert Time::DATE_FORMATS[:_sqlserver_dateformat]
88
139
  end
89
140
 
90
- it 'does a datetime insertion when language is german' do
141
+ it "does a datetime insertion when language is german" do
91
142
  connection.execute("SET LANGUAGE deutsch")
92
143
  connection.send :initialize_dateformatter
93
144
  assert_nothing_raised do
@@ -96,40 +147,36 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
96
147
  Task.create! starting: starting, ending: ending
97
148
  end
98
149
  end
99
-
100
150
  end
101
151
 
102
- describe 'testing #lowercase_schema_reflection' do
103
-
152
+ describe "testing #lowercase_schema_reflection" do
104
153
  before do
105
154
  SSTestUpper.delete_all
106
- SSTestUpper.create COLUMN1: 'Got a minute?', COLUMN2: 419
107
- SSTestUpper.create COLUMN1: 'Favorite number?', COLUMN2: 69
155
+ SSTestUpper.create COLUMN1: "Got a minute?", COLUMN2: 419
156
+ SSTestUpper.create COLUMN1: "Favorite number?", COLUMN2: 69
108
157
  end
109
158
 
110
159
  after do
111
160
  connection.lowercase_schema_reflection = false
112
161
  end
113
162
 
114
- it 'not lowercase schema reflection by default' do
115
- assert SSTestUpper.columns_hash['COLUMN1']
116
- assert_equal 'Got a minute?', SSTestUpper.first.COLUMN1
117
- assert_equal 'Favorite number?', SSTestUpper.last.COLUMN1
118
- assert SSTestUpper.columns_hash['COLUMN2']
163
+ it "not lowercase schema reflection by default" do
164
+ assert SSTestUpper.columns_hash["COLUMN1"]
165
+ assert_equal "Got a minute?", SSTestUpper.first.COLUMN1
166
+ assert_equal "Favorite number?", SSTestUpper.last.COLUMN1
167
+ assert SSTestUpper.columns_hash["COLUMN2"]
119
168
  end
120
169
 
121
- it 'lowercase schema reflection when set' do
170
+ it "lowercase schema reflection when set" do
122
171
  connection.lowercase_schema_reflection = true
123
- assert SSTestUppered.columns_hash['column1']
124
- assert_equal 'Got a minute?', SSTestUppered.first.column1
125
- assert_equal 'Favorite number?', SSTestUppered.last.column1
126
- assert SSTestUppered.columns_hash['column2']
172
+ assert SSTestUppered.columns_hash["column1"]
173
+ assert_equal "Got a minute?", SSTestUppered.first.column1
174
+ assert_equal "Favorite number?", SSTestUppered.last.column1
175
+ assert SSTestUppered.columns_hash["column2"]
127
176
  end
128
-
129
177
  end
130
178
 
131
- describe 'identity inserts' do
132
-
179
+ describe "identity inserts" do
133
180
  before do
134
181
  @identity_insert_sql = "INSERT INTO [funny_jokes] ([id],[name]) VALUES(420,'Knock knock')"
135
182
  @identity_insert_sql_unquoted = "INSERT INTO funny_jokes (id, name) VALUES(420, 'Knock knock')"
@@ -139,62 +186,60 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
139
186
  @identity_insert_sql_unordered_sp = "EXEC sp_executesql N'INSERT INTO [funny_jokes] ([name],[id]) VALUES (@0, @1)', N'@0 nvarchar(255), @1 int', @0 = N'Knock knock', @1 = 420"
140
187
  end
141
188
 
142
- it 'return quoted table_name to #query_requires_identity_insert? when INSERT sql contains id column' do
143
- assert_equal 'funny_jokes', connection.send(:query_requires_identity_insert?,@identity_insert_sql)
144
- assert_equal 'funny_jokes', connection.send(:query_requires_identity_insert?,@identity_insert_sql_unquoted)
145
- assert_equal 'funny_jokes', connection.send(:query_requires_identity_insert?,@identity_insert_sql_unordered)
146
- assert_equal 'funny_jokes', connection.send(:query_requires_identity_insert?,@identity_insert_sql_sp)
147
- assert_equal 'funny_jokes', connection.send(:query_requires_identity_insert?,@identity_insert_sql_unquoted_sp)
148
- assert_equal 'funny_jokes', connection.send(:query_requires_identity_insert?,@identity_insert_sql_unordered_sp)
189
+ it "return quoted table_name to #query_requires_identity_insert? when INSERT sql contains id column" do
190
+ assert_equal "funny_jokes", connection.send(:query_requires_identity_insert?, @identity_insert_sql)
191
+ assert_equal "funny_jokes", connection.send(:query_requires_identity_insert?, @identity_insert_sql_unquoted)
192
+ assert_equal "funny_jokes", connection.send(:query_requires_identity_insert?, @identity_insert_sql_unordered)
193
+ assert_equal "funny_jokes", connection.send(:query_requires_identity_insert?, @identity_insert_sql_sp)
194
+ assert_equal "funny_jokes", connection.send(:query_requires_identity_insert?, @identity_insert_sql_unquoted_sp)
195
+ assert_equal "funny_jokes", connection.send(:query_requires_identity_insert?, @identity_insert_sql_unordered_sp)
149
196
  end
150
197
 
151
- it 'return false to #query_requires_identity_insert? for normal SQL' do
198
+ it "return false to #query_requires_identity_insert? for normal SQL" do
152
199
  [basic_insert_sql, basic_update_sql, basic_select_sql].each do |sql|
153
- assert !connection.send(:query_requires_identity_insert?,sql), "SQL was #{sql}"
200
+ assert !connection.send(:query_requires_identity_insert?, sql), "SQL was #{sql}"
154
201
  end
155
202
  end
156
203
 
157
- it 'find identity column using #identity_columns' do
158
- task_id_column = Task.columns_hash['id']
204
+ it "find identity column using #identity_columns" do
205
+ task_id_column = Task.columns_hash["id"]
159
206
  assert_equal task_id_column.name, connection.send(:identity_columns, Task.table_name).first.name
160
207
  assert_equal task_id_column.sql_type, connection.send(:identity_columns, Task.table_name).first.sql_type
161
208
  end
162
209
 
163
- it 'return an empty array when calling #identity_columns for a table_name with no identity' do
210
+ it "return an empty array when calling #identity_columns for a table_name with no identity" do
164
211
  _(connection.send(:identity_columns, Subscriber.table_name)).must_equal []
165
212
  end
166
-
167
213
  end
168
214
 
169
- describe 'quoting' do
170
-
171
- it 'return 1 for #quoted_true' do
172
- assert_equal '1', connection.quoted_true
215
+ describe "quoting" do
216
+ it "return 1 for #quoted_true" do
217
+ assert_equal "1", connection.quoted_true
173
218
  end
174
219
 
175
- it 'return 0 for #quoted_false' do
176
- assert_equal '0', connection.quoted_false
220
+ it "return 0 for #quoted_false" do
221
+ assert_equal "0", connection.quoted_false
177
222
  end
178
223
 
179
- it 'not escape backslash characters like abstract adapter' do
224
+ it "not escape backslash characters like abstract adapter" do
180
225
  string_with_backslashs = "\\n"
181
226
  assert_equal string_with_backslashs, connection.quote_string(string_with_backslashs)
182
227
  end
183
228
 
184
- it 'quote column names with brackets' do
185
- assert_equal '[foo]', connection.quote_column_name(:foo)
186
- assert_equal '[foo]', connection.quote_column_name('foo')
187
- assert_equal '[foo].[bar]', connection.quote_column_name('foo.bar')
229
+ it "quote column names with brackets" do
230
+ assert_equal "[foo]", connection.quote_column_name(:foo)
231
+ assert_equal "[foo]", connection.quote_column_name("foo")
232
+ assert_equal "[foo].[bar]", connection.quote_column_name("foo.bar")
188
233
  end
189
234
 
190
- it 'not quote already quoted column names with brackets' do
191
- assert_equal '[foo]', connection.quote_column_name('[foo]')
192
- assert_equal '[foo].[bar]', connection.quote_column_name('[foo].[bar]')
235
+ it "not quote already quoted column names with brackets" do
236
+ assert_equal "[foo]", connection.quote_column_name("[foo]")
237
+ assert_equal "[foo].[bar]", connection.quote_column_name("[foo].[bar]")
193
238
  end
194
239
 
195
- it 'quote table names like columns' do
196
- assert_equal '[foo].[bar]', connection.quote_column_name('foo.bar')
197
- assert_equal '[foo].[bar].[baz]', connection.quote_column_name('foo.bar.baz')
240
+ it "quote table names like columns" do
241
+ assert_equal "[foo].[bar]", connection.quote_column_name("foo.bar")
242
+ assert_equal "[foo].[bar].[baz]", connection.quote_column_name("foo.bar.baz")
198
243
  end
199
244
 
200
245
  it "surround string with national prefix" do
@@ -204,44 +249,40 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
204
249
  it "escape all single quotes by repeating them" do
205
250
  assert_equal "N'''quotation''s'''", connection.quote("'quotation's'")
206
251
  end
207
-
208
252
  end
209
253
 
210
- describe 'disabling referential integrity' do
211
-
254
+ describe "disabling referential integrity" do
212
255
  before do
213
256
  connection.disable_referential_integrity { SSTestHasPk.delete_all; SSTestHasFk.delete_all }
214
257
  @parent = SSTestHasPk.create!
215
258
  @member = SSTestHasFk.create!(fk_id: @parent.id)
216
259
  end
217
260
 
218
- it 'NOT ALLOW by default the deletion of a referenced parent' do
219
- SSTestHasPk.connection.disable_referential_integrity { }
261
+ it "NOT ALLOW by default the deletion of a referenced parent" do
262
+ SSTestHasPk.connection.disable_referential_integrity {}
220
263
  assert_raise(ActiveRecord::StatementInvalid) { @parent.destroy }
221
264
  end
222
265
 
223
- it 'ALLOW deletion of referenced parent using #disable_referential_integrity block' do
266
+ it "ALLOW deletion of referenced parent using #disable_referential_integrity block" do
224
267
  SSTestHasPk.connection.disable_referential_integrity { @parent.destroy }
225
268
  end
226
269
 
227
- it 'again NOT ALLOW deletion of referenced parent after #disable_referential_integrity block' do
270
+ it "again NOT ALLOW deletion of referenced parent after #disable_referential_integrity block" do
228
271
  assert_raise(ActiveRecord::StatementInvalid) do
229
- SSTestHasPk.connection.disable_referential_integrity { }
272
+ SSTestHasPk.connection.disable_referential_integrity {}
230
273
  @parent.destroy
231
274
  end
232
275
  end
233
276
 
234
- it 'not disable referential integrity for the same table twice' do
277
+ it "not disable referential integrity for the same table twice" do
235
278
  tables = SSTestHasPk.connection.tables_with_referential_integrity
236
279
  assert_equal tables.size, tables.uniq.size
237
280
  end
238
-
239
281
  end
240
282
 
241
- describe 'database statements' do
242
-
283
+ describe "database statements" do
243
284
  it "run the database consistency checker useroptions command" do
244
- skip 'on azure' if connection_sqlserver_azure?
285
+ skip "on azure" if connection_sqlserver_azure?
245
286
  keys = [:textsize, :language, :isolation_level, :dateformat]
246
287
  user_options = connection.user_options
247
288
  keys.each do |key|
@@ -251,183 +292,217 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
251
292
  end
252
293
 
253
294
  it "return a underscored key hash with indifferent access of the results" do
254
- skip 'on azure' if connection_sqlserver_azure?
295
+ skip "on azure" if connection_sqlserver_azure?
255
296
  user_options = connection.user_options
256
- assert_equal 'read committed', user_options['isolation_level']
257
- assert_equal 'read committed', user_options[:isolation_level]
297
+ assert_equal "read committed", user_options["isolation_level"]
298
+ assert_equal "read committed", user_options[:isolation_level]
258
299
  end
259
-
260
300
  end
261
301
 
262
- describe 'schema statements' do
263
-
264
- it 'create integers when no limit supplied' do
265
- assert_equal 'integer', connection.type_to_sql(:integer)
302
+ describe "schema statements" do
303
+ it "create integers when no limit supplied" do
304
+ assert_equal "integer", connection.type_to_sql(:integer)
266
305
  end
267
306
 
268
- it 'create integers when limit is 4' do
269
- assert_equal 'integer', connection.type_to_sql(:integer, limit: 4)
307
+ it "create integers when limit is 4" do
308
+ assert_equal "integer", connection.type_to_sql(:integer, limit: 4)
270
309
  end
271
310
 
272
- it 'create integers when limit is 3' do
273
- assert_equal 'integer', connection.type_to_sql(:integer, limit: 3)
311
+ it "create integers when limit is 3" do
312
+ assert_equal "integer", connection.type_to_sql(:integer, limit: 3)
274
313
  end
275
314
 
276
- it 'create smallints when limit is 2' do
277
- assert_equal 'smallint', connection.type_to_sql(:integer, limit: 2)
315
+ it "create smallints when limit is 2" do
316
+ assert_equal "smallint", connection.type_to_sql(:integer, limit: 2)
278
317
  end
279
318
 
280
- it 'create tinyints when limit is 1' do
281
- assert_equal 'tinyint', connection.type_to_sql(:integer, limit: 1)
319
+ it "create tinyints when limit is 1" do
320
+ assert_equal "tinyint", connection.type_to_sql(:integer, limit: 1)
282
321
  end
283
322
 
284
- it 'create bigints when limit is greateer than 4' do
285
- assert_equal 'bigint', connection.type_to_sql(:integer, limit: 5)
286
- assert_equal 'bigint', connection.type_to_sql(:integer, limit: 6)
287
- assert_equal 'bigint', connection.type_to_sql(:integer, limit: 7)
288
- assert_equal 'bigint', connection.type_to_sql(:integer, limit: 8)
323
+ it "create bigints when limit is greateer than 4" do
324
+ assert_equal "bigint", connection.type_to_sql(:integer, limit: 5)
325
+ assert_equal "bigint", connection.type_to_sql(:integer, limit: 6)
326
+ assert_equal "bigint", connection.type_to_sql(:integer, limit: 7)
327
+ assert_equal "bigint", connection.type_to_sql(:integer, limit: 8)
289
328
  end
290
329
 
291
- it 'create floats when no limit supplied' do
292
- assert_equal 'float', connection.type_to_sql(:float)
330
+ it "create floats when no limit supplied" do
331
+ assert_equal "float", connection.type_to_sql(:float)
293
332
  end
294
-
295
333
  end
296
334
 
297
- describe 'views' do
298
-
335
+ describe "views" do
299
336
  # Using connection.views
300
337
 
301
- it 'return an array' do
338
+ it "return an array" do
302
339
  assert_instance_of Array, connection.views
303
340
  end
304
341
 
305
- it 'find SSTestCustomersView table name' do
306
- _(connection.views).must_include 'sst_customers_view'
342
+ it "find SSTestCustomersView table name" do
343
+ _(connection.views).must_include "sst_customers_view"
307
344
  end
308
345
 
309
- it 'work with dynamic finders' do
310
- name = 'MetaSkills'
346
+ it "work with dynamic finders" do
347
+ name = "MetaSkills"
311
348
  customer = SSTestCustomersView.create! name: name
312
349
  assert_equal customer, SSTestCustomersView.find_by_name(name)
313
350
  end
314
351
 
315
- it 'not contain system views' do
316
- systables = ['sysconstraints','syssegments']
352
+ it "not contain system views" do
353
+ systables = ["sysconstraints", "syssegments"]
317
354
  systables.each do |systable|
318
355
  assert !connection.views.include?(systable), "This systable #{systable} should not be in the views array."
319
356
  end
320
357
  end
321
358
 
322
- it 'allow the connection#view_information method to return meta data on the view' do
323
- view_info = connection.send(:view_information,'sst_customers_view')
324
- assert_equal('sst_customers_view', view_info['TABLE_NAME'])
325
- assert_match(/CREATE VIEW sst_customers_view/, view_info['VIEW_DEFINITION'])
359
+ it "allow the connection#view_information method to return meta data on the view" do
360
+ view_info = connection.send(:view_information, "sst_customers_view")
361
+ assert_equal("sst_customers_view", view_info["TABLE_NAME"])
362
+ assert_match(/CREATE VIEW sst_customers_view/, view_info["VIEW_DEFINITION"])
326
363
  end
327
364
 
328
- it 'allow the connection#view_table_name method to return true table_name for the view' do
329
- assert_equal 'customers', connection.send(:view_table_name,'sst_customers_view')
330
- assert_equal 'topics', connection.send(:view_table_name,'topics'), 'No view here, the same table name should come back.'
365
+ it "allow the connection#view_table_name method to return true table_name for the view" do
366
+ assert_equal "customers", connection.send(:view_table_name, "sst_customers_view")
367
+ assert_equal "topics", connection.send(:view_table_name, "topics"), "No view here, the same table name should come back."
331
368
  end
332
369
 
333
370
  # With same column names
334
371
 
335
- it 'have matching column objects' do
336
- columns = ['id','name','balance']
372
+ it "have matching column objects" do
373
+ columns = ["id", "name", "balance"]
337
374
  assert !SSTestCustomersView.columns.blank?
338
375
  assert_equal columns.size, SSTestCustomersView.columns.size
339
376
  columns.each do |colname|
340
377
  assert_instance_of ActiveRecord::ConnectionAdapters::SQLServerColumn,
341
- SSTestCustomersView.columns_hash[colname],
342
- "Column name #{colname.inspect} was not found in these columns #{SSTestCustomersView.columns.map(&:name).inspect}"
378
+ SSTestCustomersView.columns_hash[colname],
379
+ "Column name #{colname.inspect} was not found in these columns #{SSTestCustomersView.columns.map(&:name).inspect}"
343
380
  end
344
381
  end
345
382
 
346
- it 'find identity column' do
347
- _(SSTestCustomersView.primary_key).must_equal 'id'
348
- _(connection.primary_key(SSTestCustomersView.table_name)).must_equal 'id'
349
- _(SSTestCustomersView.columns_hash['id']).must_be :is_identity?
383
+ it "find identity column" do
384
+ _(SSTestCustomersView.primary_key).must_equal "id"
385
+ _(connection.primary_key(SSTestCustomersView.table_name)).must_equal "id"
386
+ _(SSTestCustomersView.columns_hash["id"]).must_be :is_identity?
350
387
  end
351
388
 
352
- it 'find default values' do
389
+ it "find default values" do
353
390
  assert_equal 0, SSTestCustomersView.new.balance
354
391
  end
355
392
 
356
- it 'respond true to data_source_exists?' do
393
+ it "respond true to data_source_exists?" do
357
394
  assert SSTestCustomersView.connection.data_source_exists?(SSTestCustomersView.table_name)
358
395
  end
359
396
 
360
397
  # With aliased column names
361
398
 
362
- it 'have matching column objects' do
363
- columns = ['id','pretend_null']
399
+ it "have matching column objects" do
400
+ columns = ["id", "pretend_null"]
364
401
  assert !SSTestStringDefaultsView.columns.blank?
365
402
  assert_equal columns.size, SSTestStringDefaultsView.columns.size
366
403
  columns.each do |colname|
367
404
  assert_instance_of ActiveRecord::ConnectionAdapters::SQLServerColumn,
368
- SSTestStringDefaultsView.columns_hash[colname],
369
- "Column name #{colname.inspect} was not found in these columns #{SSTestStringDefaultsView.columns.map(&:name).inspect}"
405
+ SSTestStringDefaultsView.columns_hash[colname],
406
+ "Column name #{colname.inspect} was not found in these columns #{SSTestStringDefaultsView.columns.map(&:name).inspect}"
370
407
  end
371
408
  end
372
409
 
373
- it 'find identity column' do
374
- _(SSTestStringDefaultsView.primary_key).must_equal 'id'
375
- _(connection.primary_key(SSTestStringDefaultsView.table_name)).must_equal 'id'
376
- _(SSTestStringDefaultsView.columns_hash['id']).must_be :is_identity?
410
+ it "find identity column" do
411
+ _(SSTestStringDefaultsView.primary_key).must_equal "id"
412
+ _(connection.primary_key(SSTestStringDefaultsView.table_name)).must_equal "id"
413
+ _(SSTestStringDefaultsView.columns_hash["id"]).must_be :is_identity?
377
414
  end
378
415
 
379
- it 'find default values' do
380
- assert_equal 'null', SSTestStringDefaultsView.new.pretend_null,
381
- SSTestStringDefaultsView.columns_hash['pretend_null'].inspect
416
+ it "find default values" do
417
+ assert_equal "null", SSTestStringDefaultsView.new.pretend_null,
418
+ SSTestStringDefaultsView.columns_hash["pretend_null"].inspect
382
419
  end
383
420
 
384
- it 'respond true to data_source_exists?' do
421
+ it "respond true to data_source_exists?" do
385
422
  assert SSTestStringDefaultsView.connection.data_source_exists?(SSTestStringDefaultsView.table_name)
386
423
  end
387
424
 
388
425
  # That have more than 4000 chars for their defintion
389
426
 
390
- it 'cope with null returned for the defintion' do
427
+ it "cope with null returned for the defintion" do
391
428
  assert_nothing_raised() { SSTestStringDefaultsBigView.columns }
392
429
  end
393
430
 
394
- it 'using alternate view defintion still be able to find real default' do
395
- assert_equal 'null', SSTestStringDefaultsBigView.new.pretend_null,
396
- SSTestStringDefaultsBigView.columns_hash['pretend_null'].inspect
431
+ it "using alternate view defintion still be able to find real default" do
432
+ assert_equal "null", SSTestStringDefaultsBigView.new.pretend_null,
433
+ SSTestStringDefaultsBigView.columns_hash["pretend_null"].inspect
397
434
  end
398
-
399
435
  end
400
436
 
401
- describe 'database_prefix_remote_server?' do
402
-
437
+ describe "database_prefix_remote_server?" do
403
438
  after do
404
439
  connection_options.delete(:database_prefix)
405
440
  end
406
441
 
407
- it 'returns false if database_prefix is not configured' do
442
+ it "returns false if database_prefix is not configured" do
408
443
  assert_equal false, connection.database_prefix_remote_server?
409
444
  end
410
445
 
411
- it 'returns true if database_prefix has been set' do
446
+ it "returns true if database_prefix has been set" do
412
447
  connection_options[:database_prefix] = "server.database.schema."
413
448
  assert_equal true, connection.database_prefix_remote_server?
414
449
  end
415
450
 
416
- it 'returns false if database_prefix has been set incorrectly' do
451
+ it "returns false if database_prefix has been set incorrectly" do
417
452
  connection_options[:database_prefix] = "server.database.schema"
418
453
  assert_equal false, connection.database_prefix_remote_server?
419
454
  end
420
-
421
455
  end
422
456
 
423
- it 'in_memory_oltp' do
424
- if ENV['IN_MEMORY_OLTP'] && connection.supports_in_memory_oltp?
425
- _(SSTMemory.primary_key).must_equal 'id'
426
- _(SSTMemory.columns_hash['id']).must_be :is_identity?
457
+ it "in_memory_oltp" do
458
+ if ENV["IN_MEMORY_OLTP"] && connection.supports_in_memory_oltp?
459
+ _(SSTMemory.primary_key).must_equal "id"
460
+ _(SSTMemory.columns_hash["id"]).must_be :is_identity?
427
461
  else
428
- skip 'supports_in_memory_oltp? => false'
462
+ skip "supports_in_memory_oltp? => false"
429
463
  end
430
464
  end
431
465
 
432
- end
466
+ describe "block writes to a database" do
467
+ def setup
468
+ @conn = ActiveRecord::Base.connection
469
+ @connection_handler = ActiveRecord::Base.connection_handler
470
+ end
471
+
472
+ def test_errors_when_an_insert_query_is_called_while_preventing_writes
473
+ assert_raises(ActiveRecord::ReadOnlyError) do
474
+ @connection_handler.while_preventing_writes do
475
+ @conn.insert("INSERT INTO [subscribers] ([nick]) VALUES ('aido')")
476
+ end
477
+ end
478
+ end
433
479
 
480
+ def test_errors_when_an_update_query_is_called_while_preventing_writes
481
+ @conn.insert("INSERT INTO [subscribers] ([nick]) VALUES ('aido')")
482
+
483
+ assert_raises(ActiveRecord::ReadOnlyError) do
484
+ @connection_handler.while_preventing_writes do
485
+ @conn.update("UPDATE [subscribers] SET [subscribers].[name] = 'Aidan' WHERE [subscribers].[nick] = 'aido'")
486
+ end
487
+ end
488
+ end
489
+
490
+ def test_errors_when_a_delete_query_is_called_while_preventing_writes
491
+ @conn.execute("INSERT INTO [subscribers] ([nick]) VALUES ('aido')")
492
+
493
+ assert_raises(ActiveRecord::ReadOnlyError) do
494
+ @connection_handler.while_preventing_writes do
495
+ @conn.execute("DELETE FROM [subscribers] WHERE [subscribers].[nick] = 'aido'")
496
+ end
497
+ end
498
+ end
499
+
500
+ def test_doesnt_error_when_a_select_query_is_called_while_preventing_writes
501
+ @conn.execute("INSERT INTO [subscribers] ([nick]) VALUES ('aido')")
502
+
503
+ @connection_handler.while_preventing_writes do
504
+ assert_equal 1, @conn.execute("SELECT * FROM [subscribers] WHERE [subscribers].[nick] = 'aido'")
505
+ end
506
+ end
507
+ end
508
+ end