activerecord-sqlserver-adapter 8.0.12 → 8.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/.devcontainer/Dockerfile +1 -1
  3. data/.github/workflows/ci.yml +34 -3
  4. data/CHANGELOG.md +13 -84
  5. data/Dockerfile.ci +1 -1
  6. data/Gemfile +9 -12
  7. data/Guardfile +2 -2
  8. data/README.md +33 -13
  9. data/Rakefile +1 -1
  10. data/VERSION +1 -1
  11. data/activerecord-sqlserver-adapter.gemspec +15 -16
  12. data/compose.ci.yaml +8 -1
  13. data/lib/active_record/connection_adapters/sqlserver/core_ext/attribute_methods.rb +1 -1
  14. data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +1 -2
  15. data/lib/active_record/connection_adapters/sqlserver/core_ext/explain_subscriber.rb +1 -1
  16. data/lib/active_record/connection_adapters/sqlserver/core_ext/finder_methods.rb +4 -4
  17. data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +118 -83
  18. data/lib/active_record/connection_adapters/sqlserver/database_tasks.rb +3 -4
  19. data/lib/active_record/connection_adapters/sqlserver/quoting.rb +7 -7
  20. data/lib/active_record/connection_adapters/sqlserver/schema_creation.rb +24 -12
  21. data/lib/active_record/connection_adapters/sqlserver/schema_dumper.rb +17 -8
  22. data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +170 -172
  23. data/lib/active_record/connection_adapters/sqlserver/showplan/printer_table.rb +2 -2
  24. data/lib/active_record/connection_adapters/sqlserver/showplan.rb +5 -5
  25. data/lib/active_record/connection_adapters/sqlserver/sql_type_metadata.rb +2 -7
  26. data/lib/active_record/connection_adapters/sqlserver/table_definition.rb +3 -1
  27. data/lib/active_record/connection_adapters/sqlserver/type/data.rb +3 -3
  28. data/lib/active_record/connection_adapters/sqlserver/type/date.rb +3 -3
  29. data/lib/active_record/connection_adapters/sqlserver/type/datetime.rb +3 -4
  30. data/lib/active_record/connection_adapters/sqlserver/type/smalldatetime.rb +1 -1
  31. data/lib/active_record/connection_adapters/sqlserver/type/time.rb +4 -6
  32. data/lib/active_record/connection_adapters/sqlserver/type/time_value_fractional.rb +1 -1
  33. data/lib/active_record/connection_adapters/sqlserver/type/uuid.rb +0 -2
  34. data/lib/active_record/connection_adapters/sqlserver/utils.rb +10 -12
  35. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +119 -67
  36. data/lib/active_record/connection_adapters/sqlserver_column.rb +17 -9
  37. data/lib/active_record/tasks/sqlserver_database_tasks.rb +5 -5
  38. data/lib/arel/visitors/sqlserver.rb +55 -26
  39. data/test/cases/active_schema_test_sqlserver.rb +45 -23
  40. data/test/cases/adapter_test_sqlserver.rb +72 -61
  41. data/test/cases/change_column_null_test_sqlserver.rb +16 -46
  42. data/test/cases/coerced_tests.rb +365 -161
  43. data/test/cases/column_test_sqlserver.rb +328 -316
  44. data/test/cases/connection_test_sqlserver.rb +15 -11
  45. data/test/cases/enum_test_sqlserver.rb +8 -9
  46. data/test/cases/execute_procedure_test_sqlserver.rb +1 -1
  47. data/test/cases/fetch_test_sqlserver.rb +1 -1
  48. data/test/cases/helper_sqlserver.rb +8 -3
  49. data/test/cases/index_test_sqlserver.rb +8 -6
  50. data/test/cases/insert_all_test_sqlserver.rb +3 -28
  51. data/test/cases/json_test_sqlserver.rb +8 -8
  52. data/test/cases/lateral_test_sqlserver.rb +2 -2
  53. data/test/cases/migration_test_sqlserver.rb +12 -12
  54. data/test/cases/pessimistic_locking_test_sqlserver.rb +6 -6
  55. data/test/cases/primary_keys_test_sqlserver.rb +4 -4
  56. data/test/cases/rake_test_sqlserver.rb +15 -7
  57. data/test/cases/schema_dumper_test_sqlserver.rb +109 -113
  58. data/test/cases/schema_test_sqlserver.rb +7 -39
  59. data/test/cases/transaction_test_sqlserver.rb +6 -8
  60. data/test/cases/trigger_test_sqlserver.rb +1 -1
  61. data/test/cases/utils_test_sqlserver.rb +3 -3
  62. data/test/cases/view_test_sqlserver.rb +12 -8
  63. data/test/cases/virtual_column_test_sqlserver.rb +113 -0
  64. data/test/migrations/create_clients_and_change_column_collation.rb +2 -2
  65. data/test/models/sqlserver/edge_schema.rb +2 -2
  66. data/test/schema/sqlserver_specific_schema.rb +49 -37
  67. data/test/support/coerceable_test_sqlserver.rb +10 -10
  68. data/test/support/connection_reflection.rb +0 -5
  69. data/test/support/core_ext/backtrace_cleaner.rb +36 -0
  70. data/test/support/query_assertions.rb +6 -6
  71. data/test/support/rake_helpers.rb +6 -10
  72. metadata +13 -108
@@ -16,7 +16,9 @@ module Arel
16
16
  BIND_BLOCK = proc { |i| "@#{i - 1}" }
17
17
  private_constant :BIND_BLOCK
18
18
 
19
- def bind_block; BIND_BLOCK; end
19
+ def bind_block
20
+ BIND_BLOCK
21
+ end
20
22
 
21
23
  def visit_Arel_Nodes_Bin(o, collector)
22
24
  visit o.expr, collector
@@ -29,10 +31,49 @@ module Arel
29
31
  visit o.right, collector
30
32
  end
31
33
 
34
+ # Same as SQLite and PostgreSQL.
32
35
  def visit_Arel_Nodes_UpdateStatement(o, collector)
33
- if has_join_and_composite_primary_key?(o)
34
- update_statement_using_join(o, collector)
36
+ collector.retryable = false
37
+ o = prepare_update_statement(o)
38
+
39
+ collector << "UPDATE "
40
+
41
+ # UPDATE with JOIN is in the form of:
42
+ #
43
+ # UPDATE t1
44
+ # SET ..
45
+ # FROM t1 JOIN t2 ON t2.join_id = t1.join_id ..
46
+ # WHERE ..
47
+ if has_join_sources?(o)
48
+ collector = visit o.relation.left, collector
49
+ collect_nodes_for o.values, collector, " SET "
50
+ collector << " FROM "
51
+ collector = inject_join o.relation.right, collector, " "
52
+ else
53
+ collector = visit o.relation, collector
54
+ collect_nodes_for o.values, collector, " SET "
55
+ end
56
+
57
+ collect_nodes_for o.wheres, collector, " WHERE ", " AND "
58
+ collect_nodes_for o.orders, collector, " ORDER BY "
59
+ maybe_visit o.limit, collector
60
+ maybe_visit o.comment, collector
61
+ end
62
+
63
+ # Similar to PostgreSQL and SQLite.
64
+ def prepare_update_statement(o)
65
+ if o.key && has_join_sources?(o) && !has_group_by_and_having?(o) && !has_limit_or_offset_or_orders?(o)
66
+ # Join clauses cannot reference the target table, so alias the
67
+ # updated table, place the entire relation in the FROM clause, and
68
+ # add a self-join (which requires the primary key)
69
+ stmt = o.clone
70
+
71
+ stmt.relation, stmt.wheres = o.relation.clone, o.wheres.clone
72
+ stmt.relation.right = [stmt.relation.left, *stmt.relation.right]
73
+ # Don't need to use alias
74
+ stmt
35
75
  else
76
+ # If using subquery, we need to add limit
36
77
  o.limit = Nodes::Limit.new(9_223_372_036_854_775_807) if o.orders.any? && o.limit.nil?
37
78
 
38
79
  super
@@ -61,19 +102,8 @@ module Arel
61
102
  collect_nodes_for o.wheres, collector, " WHERE ", " AND "
62
103
  end
63
104
 
64
- def update_statement_using_join(o, collector)
65
- collector.retryable = false
66
-
67
- collector << "UPDATE "
68
- visit o.relation.left, collector
69
- collect_nodes_for o.values, collector, " SET "
70
- collector << " FROM "
71
- visit o.relation, collector
72
- collect_nodes_for o.wheres, collector, " WHERE ", " AND "
73
- end
74
-
75
105
  def visit_Arel_Nodes_Lock(o, collector)
76
- o.expr = Arel.sql("WITH(UPDLOCK)") if o.expr.to_s =~ /FOR UPDATE/
106
+ o.expr = Arel.sql("WITH(UPDLOCK)") if /FOR UPDATE/.match?(o.expr.to_s)
77
107
  collector << " "
78
108
  visit o.expr, collector
79
109
  end
@@ -87,12 +117,11 @@ module Arel
87
117
  def visit_Arel_Nodes_Limit(o, collector)
88
118
  if node_value(o) == 0
89
119
  collector << FETCH0
90
- collector << ROWS_ONLY
91
120
  else
92
121
  collector << FETCH
93
122
  visit o.expr, collector
94
- collector << ROWS_ONLY
95
123
  end
124
+ collector << ROWS_ONLY
96
125
  end
97
126
 
98
127
  def visit_Arel_Nodes_Grouping(o, collector)
@@ -105,10 +134,10 @@ module Arel
105
134
 
106
135
  visit o.left, collector
107
136
 
108
- if o.type == :in
109
- collector << " IN ("
137
+ collector << if o.type == :in
138
+ " IN ("
110
139
  else
111
- collector << " NOT IN ("
140
+ " NOT IN ("
112
141
  end
113
142
 
114
143
  values = o.casted_values
@@ -170,14 +199,14 @@ module Arel
170
199
  quote_table_name(o.name)
171
200
  end
172
201
  end
173
- rescue Exception
202
+ rescue
174
203
  quote_table_name(o.name)
175
204
  end
176
205
 
177
- if o.table_alias
178
- collector << "#{table_name} #{quote_table_name o.table_alias}"
206
+ collector << if o.table_alias
207
+ "#{table_name} #{quote_table_name o.table_alias}"
179
208
  else
180
- collector << table_name
209
+ table_name
181
210
  end
182
211
  end
183
212
 
@@ -297,7 +326,7 @@ module Arel
297
326
  end
298
327
 
299
328
  def select_statement_lock?
300
- @select_statement && @select_statement.lock
329
+ @select_statement&.lock
301
330
  end
302
331
 
303
332
  def make_Fetch_Possible_And_Deterministic(o)
@@ -330,7 +359,7 @@ module Arel
330
359
  elsif Arel::Nodes::SqlLiteral === core.from
331
360
  Arel::Table.new(core.from)
332
361
  elsif Arel::Nodes::JoinSource === core.source
333
- Arel::Nodes::SqlLiteral === core.source.left ? Arel::Table.new(core.source.left, @engine) : core.source.left.left
362
+ (Arel::Nodes::SqlLiteral === core.source.left) ? Arel::Table.new(core.source.left, @engine) : core.source.left.left
334
363
  end
335
364
  end
336
365
 
@@ -12,48 +12,50 @@ class ActiveSchemaTestSQLServer < ActiveRecord::TestCase
12
12
  end
13
13
 
14
14
  after do
15
- connection.drop_table :schema_test_table rescue nil
15
+ connection.drop_table :schema_test_table
16
+ rescue
17
+ nil
16
18
  end
17
19
 
18
- it 'default index' do
19
- assert_queries_match('CREATE INDEX [index_schema_test_table_on_foo] ON [schema_test_table] ([foo])') do
20
+ it "default index" do
21
+ assert_queries_match("CREATE INDEX [index_schema_test_table_on_foo] ON [schema_test_table] ([foo])") do
20
22
  connection.add_index :schema_test_table, "foo"
21
23
  end
22
24
  end
23
25
 
24
- it 'unique index' do
25
- assert_queries_match('CREATE UNIQUE INDEX [index_schema_test_table_on_foo] ON [schema_test_table] ([foo])') do
26
+ it "unique index" do
27
+ assert_queries_match("CREATE UNIQUE INDEX [index_schema_test_table_on_foo] ON [schema_test_table] ([foo])") do
26
28
  connection.add_index :schema_test_table, "foo", unique: true
27
29
  end
28
30
  end
29
31
 
30
- it 'where condition on index' do
32
+ it "where condition on index" do
31
33
  assert_queries_match("CREATE INDEX [index_schema_test_table_on_foo] ON [schema_test_table] ([foo]) WHERE state = 'active'") do
32
34
  connection.add_index :schema_test_table, "foo", where: "state = 'active'"
33
35
  end
34
36
  end
35
37
 
36
- it 'if index does not exist' do
38
+ it "if index does not exist" do
37
39
  assert_queries_match("IF NOT EXISTS (SELECT name FROM sysindexes WHERE name = 'index_schema_test_table_on_foo') " \
38
40
  "CREATE INDEX [index_schema_test_table_on_foo] ON [schema_test_table] ([foo])") do
39
41
  connection.add_index :schema_test_table, "foo", if_not_exists: true
40
42
  end
41
43
  end
42
44
 
43
- it 'clustered index' do
44
- assert_queries_match('CREATE CLUSTERED INDEX [index_schema_test_table_on_foo] ON [schema_test_table] ([foo])') do
45
+ it "clustered index" do
46
+ assert_queries_match("CREATE CLUSTERED INDEX [index_schema_test_table_on_foo] ON [schema_test_table] ([foo])") do
45
47
  connection.add_index :schema_test_table, "foo", type: :clustered
46
48
  end
47
49
  end
48
50
 
49
- it 'nonclustered index' do
50
- assert_queries_match('CREATE NONCLUSTERED INDEX [index_schema_test_table_on_foo] ON [schema_test_table] ([foo])') do
51
+ it "nonclustered index" do
52
+ assert_queries_match("CREATE NONCLUSTERED INDEX [index_schema_test_table_on_foo] ON [schema_test_table] ([foo])") do
51
53
  connection.add_index :schema_test_table, "foo", type: :nonclustered
52
54
  end
53
55
  end
54
56
  end
55
57
 
56
- describe 'collation' do
58
+ describe "collation" do
57
59
  it "create column with NOT NULL and COLLATE" do
58
60
  assert_nothing_raised do
59
61
  connection.create_table :not_null_with_collation_table, force: true, id: false do |t|
@@ -61,12 +63,16 @@ class ActiveSchemaTestSQLServer < ActiveRecord::TestCase
61
63
  end
62
64
  end
63
65
  ensure
64
- connection.drop_table :not_null_with_collation_table rescue nil
66
+ begin
67
+ connection.drop_table :not_null_with_collation_table
68
+ rescue
69
+ nil
70
+ end
65
71
  end
66
72
  end
67
73
 
68
- describe 'datetimeoffset precision' do
69
- it 'valid precisions are correct' do
74
+ describe "datetimeoffset precision" do
75
+ it "valid precisions are correct" do
70
76
  assert_nothing_raised do
71
77
  connection.create_table :datetimeoffset_precisions do |t|
72
78
  t.datetimeoffset :precision_default
@@ -81,22 +87,30 @@ class ActiveSchemaTestSQLServer < ActiveRecord::TestCase
81
87
  assert_equal columns.find { |column| column.name == "precision_5" }.precision, 5
82
88
  assert_equal columns.find { |column| column.name == "precision_7" }.precision, 7
83
89
  ensure
84
- connection.drop_table :datetimeoffset_precisions rescue nil
90
+ begin
91
+ connection.drop_table :datetimeoffset_precisions
92
+ rescue
93
+ nil
94
+ end
85
95
  end
86
96
 
87
- it 'invalid precision raises exception' do
97
+ it "invalid precision raises exception" do
88
98
  assert_raise(ActiveRecord::ActiveRecordError) do
89
99
  connection.create_table :datetimeoffset_precisions do |t|
90
100
  t.datetimeoffset :precision_8, precision: 8
91
101
  end
92
102
  end
93
103
  ensure
94
- connection.drop_table :datetimeoffset_precisions rescue nil
104
+ begin
105
+ connection.drop_table :datetimeoffset_precisions
106
+ rescue
107
+ nil
108
+ end
95
109
  end
96
110
  end
97
111
 
98
- describe 'time precision' do
99
- it 'valid precisions are correct' do
112
+ describe "time precision" do
113
+ it "valid precisions are correct" do
100
114
  assert_nothing_raised do
101
115
  connection.create_table :time_precisions do |t|
102
116
  t.time :precision_default
@@ -111,17 +125,25 @@ class ActiveSchemaTestSQLServer < ActiveRecord::TestCase
111
125
  assert_equal columns.find { |column| column.name == "precision_5" }.precision, 5
112
126
  assert_equal columns.find { |column| column.name == "precision_7" }.precision, 7
113
127
  ensure
114
- connection.drop_table :time_precisions rescue nil
128
+ begin
129
+ connection.drop_table :time_precisions
130
+ rescue
131
+ nil
132
+ end
115
133
  end
116
134
 
117
- it 'invalid precision raises exception' do
135
+ it "invalid precision raises exception" do
118
136
  assert_raise(ActiveRecord::ActiveRecordError) do
119
137
  connection.create_table :time_precisions do |t|
120
138
  t.time :precision_8, precision: 8
121
139
  end
122
140
  end
123
141
  ensure
124
- connection.drop_table :time_precisions rescue nil
142
+ begin
143
+ connection.drop_table :time_precisions
144
+ rescue
145
+ nil
146
+ end
125
147
  end
126
148
  end
127
149
  end
@@ -14,10 +14,10 @@ require "models/discount"
14
14
  class AdapterTestSQLServer < ActiveRecord::TestCase
15
15
  fixtures :tasks
16
16
 
17
- let(:arunit_connection) { Topic.lease_connection }
17
+ let(:arunit_connection) { Topic.lease_connection }
18
18
  let(:arunit2_connection) { College.lease_connection }
19
- let(:arunit_database) { arunit_connection.pool.db_config.database }
20
- let(:arunit2_database) { arunit2_connection.pool.db_config.database }
19
+ let(:arunit_database) { arunit_connection.pool.db_config.database }
20
+ let(:arunit2_database) { arunit2_connection.pool.db_config.database }
21
21
 
22
22
  let(:basic_insert_sql) { "INSERT INTO [funny_jokes] ([name]) VALUES('Knock knock')" }
23
23
  let(:basic_merge_sql) { "MERGE INTO [ships] WITH (UPDLOCK, HOLDLOCK) AS target USING ( SELECT * FROM ( SELECT [id], [name], ROW_NUMBER() OVER ( PARTITION BY [id] ORDER BY [id] DESC ) AS rn_0 FROM ( VALUES (101, N'RSS Sir David Attenborough') ) AS t1 ([id], [name]) ) AS ranked_source WHERE rn_0 = 1 ) AS source ON (target.[id] = source.[id]) WHEN MATCHED THEN UPDATE SET target.[name] = source.[name]" }
@@ -50,20 +50,18 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
50
50
  end
51
51
 
52
52
  it "table exists works if table name prefixed by schema and owner" do
53
- begin
54
- assert_equal "topics", Topic.table_name
55
- assert Topic.table_exists?
56
-
57
- # Test when owner included in table name.
58
- Topic.table_name = "dbo.topics"
59
- assert Topic.table_exists?, "Topics table name of 'dbo.topics' should return true for exists."
60
-
61
- # Test when database and owner included in table name.
62
- Topic.table_name = "#{arunit_database}.dbo.topics"
63
- assert Topic.table_exists?, "Topics table name of '[DATABASE].dbo.topics' should return true for exists."
64
- ensure
65
- Topic.table_name = "topics"
66
- end
53
+ assert_equal "topics", Topic.table_name
54
+ assert Topic.table_exists?
55
+
56
+ # Test when owner included in table name.
57
+ Topic.table_name = "dbo.topics"
58
+ assert Topic.table_exists?, "Topics table name of 'dbo.topics' should return true for exists."
59
+
60
+ # Test when database and owner included in table name.
61
+ Topic.table_name = "#{arunit_database}.dbo.topics"
62
+ assert Topic.table_exists?, "Topics table name of '[DATABASE].dbo.topics' should return true for exists."
63
+ ensure
64
+ Topic.table_name = "topics"
67
65
  end
68
66
 
69
67
  it "test table existence across database schemas" do
@@ -77,18 +75,18 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
77
75
  assert_not_equal arunit_database, arunit2_database
78
76
 
79
77
  # Assert that the Topics table exists when using the Topics connection.
80
- assert arunit_connection.table_exists?('topics'), 'Topics table exists using table name'
81
- assert arunit_connection.table_exists?('dbo.topics'), 'Topics table exists using owner and table name'
82
- assert arunit_connection.table_exists?("#{arunit_database}.dbo.topics"), 'Topics table exists using database, owner and table name'
78
+ assert arunit_connection.table_exists?("topics"), "Topics table exists using table name"
79
+ assert arunit_connection.table_exists?("dbo.topics"), "Topics table exists using owner and table name"
80
+ assert arunit_connection.table_exists?("#{arunit_database}.dbo.topics"), "Topics table exists using database, owner and table name"
83
81
 
84
82
  # Assert that the Colleges table exists when using the Colleges connection.
85
- assert arunit2_connection.table_exists?('colleges'), 'College table exists using table name'
86
- assert arunit2_connection.table_exists?('dbo.colleges'), 'College table exists using owner and table name'
87
- assert arunit2_connection.table_exists?("#{arunit2_database}.dbo.colleges"), 'College table exists using database, owner and table name'
83
+ assert arunit2_connection.table_exists?("colleges"), "College table exists using table name"
84
+ assert arunit2_connection.table_exists?("dbo.colleges"), "College table exists using owner and table name"
85
+ assert arunit2_connection.table_exists?("#{arunit2_database}.dbo.colleges"), "College table exists using database, owner and table name"
88
86
 
89
87
  # Assert that the tables exist when using each others connection.
90
- assert arunit_connection.table_exists?("#{arunit2_database}.dbo.colleges"), 'Colleges table exists using Topics connection'
91
- assert arunit2_connection.table_exists?("#{arunit_database}.dbo.topics"), 'Topics table exists using Colleges connection'
88
+ assert arunit_connection.table_exists?("#{arunit2_database}.dbo.colleges"), "Colleges table exists using Topics connection"
89
+ assert arunit2_connection.table_exists?("#{arunit_database}.dbo.topics"), "Topics table exists using Colleges connection"
92
90
  end
93
91
 
94
92
  it "return true to insert sql query for inserts only" do
@@ -118,20 +116,20 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
118
116
  db_config = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", name: "primary")
119
117
  configuration = db_config.configuration_hash.merge(database: "nonexistent_activerecord_unittest")
120
118
  assert_not ActiveRecord::ConnectionAdapters::SQLServerAdapter.database_exists?(configuration),
121
- "expected database #{configuration[:database]} to not exist"
119
+ "expected database #{configuration[:database]} to not exist"
122
120
  end
123
121
 
124
122
  it "test database exists returns true when the database exists" do
125
123
  db_config = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", name: "primary")
126
124
  assert ActiveRecord::ConnectionAdapters::SQLServerAdapter.database_exists?(db_config.configuration_hash),
127
- "expected database #{db_config.database} to exist"
125
+ "expected database #{db_config.database} to exist"
128
126
  end
129
127
 
130
128
  it "test primary key violation" do
131
- Post.create!(id: 0, title: 'Setup', body: 'Create post with primary key of zero')
129
+ Post.create!(id: 0, title: "Setup", body: "Create post with primary key of zero")
132
130
 
133
131
  assert_raise ActiveRecord::RecordNotUnique do
134
- Post.create!(id: 0, title: 'Test', body: 'Try to create another post with primary key of zero')
132
+ Post.create!(id: 0, title: "Test", body: "Try to create another post with primary key of zero")
135
133
  end
136
134
  end
137
135
 
@@ -141,12 +139,20 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
141
139
  end
142
140
 
143
141
  after do
144
- connection.execute("SET LANGUAGE #{@default_language}") rescue nil
142
+ begin
143
+ connection.execute("SET LANGUAGE #{@default_language}")
144
+ rescue
145
+ nil
146
+ end
145
147
  connection.send :initialize_dateformatter
146
148
  end
147
149
 
148
150
  it "memos users dateformat" do
149
- connection.execute("SET LANGUAGE us_english") rescue nil
151
+ begin
152
+ connection.execute("SET LANGUAGE us_english")
153
+ rescue
154
+ nil
155
+ end
150
156
  dateformat = connection.instance_variable_get(:@database_dateformat)
151
157
  assert_equal "mdy", dateformat
152
158
  end
@@ -206,7 +212,7 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
206
212
  connection.lowercase_schema_reflection = true
207
213
 
208
214
  assert_nothing_raised do
209
- post = Post.create!(title: 'Setup', body: 'Record to be deleted')
215
+ post = Post.create!(title: "Setup", body: "Record to be deleted")
210
216
  post.destroy!
211
217
  end
212
218
  end
@@ -224,7 +230,6 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
224
230
  @identity_merge_sql = "MERGE INTO [ships] WITH (UPDLOCK, HOLDLOCK) AS target USING ( SELECT * FROM ( SELECT [id], [name], ROW_NUMBER() OVER ( PARTITION BY [id] ORDER BY [id] DESC ) AS rn_0 FROM ( VALUES (101, N'RSS Sir David Attenborough') ) AS t1 ([id], [name]) ) AS ranked_source WHERE rn_0 = 1 ) AS source ON (target.[id] = source.[id]) WHEN MATCHED THEN UPDATE SET target.[name] = source.[name] WHEN NOT MATCHED BY TARGET THEN INSERT ([id], [name]) VALUES (source.[id], source.[name]) OUTPUT INSERTED.[id]"
225
231
  @identity_merge_sql_unquoted = "MERGE INTO ships WITH (UPDLOCK, HOLDLOCK) AS target USING ( SELECT * FROM ( SELECT id, name, ROW_NUMBER() OVER ( PARTITION BY id ORDER BY id DESC ) AS rn_0 FROM ( VALUES (101, N'RSS Sir David Attenborough') ) AS t1 (id, name) ) AS ranked_source WHERE rn_0 = 1 ) AS source ON (target.id = source.id) WHEN MATCHED THEN UPDATE SET target.name = source.name WHEN NOT MATCHED BY TARGET THEN INSERT (id, name) VALUES (source.id, source.name) OUTPUT INSERTED.id"
226
232
  @identity_merge_sql_unordered = "MERGE INTO [ships] WITH (UPDLOCK, HOLDLOCK) AS target USING ( SELECT * FROM ( SELECT [name], [id], ROW_NUMBER() OVER ( PARTITION BY [id] ORDER BY [id] DESC ) AS rn_0 FROM ( VALUES (101, N'RSS Sir David Attenborough') ) AS t1 ([name], [id]) ) AS ranked_source WHERE rn_0 = 1 ) AS source ON (target.[id] = source.[id]) WHEN MATCHED THEN UPDATE SET target.[name] = source.[name] WHEN NOT MATCHED BY TARGET THEN INSERT ([name], [id]) VALUES (source.[name], source.[id]) OUTPUT INSERTED.[id]"
227
- @identity_merge_sql_aliased_target = @identity_merge_sql.sub(" WITH (UPDLOCK, HOLDLOCK)", "")
228
233
 
229
234
  @identity_insert_sql_non_dbo = "INSERT INTO [test].[aliens] ([id],[name]) VALUES(420,'Mork')"
230
235
  @identity_insert_sql_non_dbo_unquoted = "INSERT INTO test.aliens ([id],[name]) VALUES(420,'Mork')"
@@ -238,17 +243,16 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
238
243
  end
239
244
 
240
245
  it "return quoted table_name to #query_requires_identity_insert? when INSERT sql contains id column" do
241
- assert_equal "[funny_jokes]", connection.send(:query_requires_identity_insert?, @identity_insert_sql)
242
- assert_equal "[funny_jokes]", connection.send(:query_requires_identity_insert?, @identity_insert_sql_unquoted)
243
- assert_equal "[funny_jokes]", connection.send(:query_requires_identity_insert?, @identity_insert_sql_unordered)
244
- assert_equal "[funny_jokes]", connection.send(:query_requires_identity_insert?, @identity_insert_sql_sp)
245
- assert_equal "[funny_jokes]", connection.send(:query_requires_identity_insert?, @identity_insert_sql_unquoted_sp)
246
- assert_equal "[funny_jokes]", connection.send(:query_requires_identity_insert?, @identity_insert_sql_unordered_sp)
246
+ assert_equal "[funny_jokes]", connection.send(:query_requires_identity_insert?, @identity_insert_sql)
247
+ assert_equal "[funny_jokes]", connection.send(:query_requires_identity_insert?, @identity_insert_sql_unquoted)
248
+ assert_equal "[funny_jokes]", connection.send(:query_requires_identity_insert?, @identity_insert_sql_unordered)
249
+ assert_equal "[funny_jokes]", connection.send(:query_requires_identity_insert?, @identity_insert_sql_sp)
250
+ assert_equal "[funny_jokes]", connection.send(:query_requires_identity_insert?, @identity_insert_sql_unquoted_sp)
251
+ assert_equal "[funny_jokes]", connection.send(:query_requires_identity_insert?, @identity_insert_sql_unordered_sp)
247
252
 
248
253
  assert_equal "[ships]", connection.send(:query_requires_identity_insert?, @identity_merge_sql)
249
254
  assert_equal "[ships]", connection.send(:query_requires_identity_insert?, @identity_merge_sql_unquoted)
250
255
  assert_equal "[ships]", connection.send(:query_requires_identity_insert?, @identity_merge_sql_unordered)
251
- assert_equal "[ships]", connection.send(:query_requires_identity_insert?, @identity_merge_sql_aliased_target)
252
256
 
253
257
  assert_equal "[test].[aliens]", connection.send(:query_requires_identity_insert?, @identity_insert_sql_non_dbo)
254
258
  assert_equal "[test].[aliens]", connection.send(:query_requires_identity_insert?, @identity_insert_sql_non_dbo_unquoted)
@@ -328,7 +332,10 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
328
332
 
329
333
  describe "disabling referential integrity" do
330
334
  before do
331
- connection.disable_referential_integrity { SSTestHasPk.delete_all; SSTestHasFk.delete_all }
335
+ connection.disable_referential_integrity {
336
+ SSTestHasPk.delete_all
337
+ SSTestHasFk.delete_all
338
+ }
332
339
  @parent = SSTestHasPk.create!
333
340
  @member = SSTestHasFk.create!(fk_id: @parent.id)
334
341
  end
@@ -469,8 +476,8 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
469
476
  assert_equal columns.size, SSTestCustomersView.columns.size
470
477
  columns.each do |colname|
471
478
  assert_instance_of ActiveRecord::ConnectionAdapters::SQLServer::Column,
472
- SSTestCustomersView.columns_hash[colname],
473
- "Column name #{colname.inspect} was not found in these columns #{SSTestCustomersView.columns.map(&:name).inspect}"
479
+ SSTestCustomersView.columns_hash[colname],
480
+ "Column name #{colname.inspect} was not found in these columns #{SSTestCustomersView.columns.map(&:name).inspect}"
474
481
  end
475
482
  end
476
483
 
@@ -496,8 +503,8 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
496
503
  assert_equal columns.size, SSTestStringDefaultsView.columns.size
497
504
  columns.each do |colname|
498
505
  assert_instance_of ActiveRecord::ConnectionAdapters::SQLServer::Column,
499
- SSTestStringDefaultsView.columns_hash[colname],
500
- "Column name #{colname.inspect} was not found in these columns #{SSTestStringDefaultsView.columns.map(&:name).inspect}"
506
+ SSTestStringDefaultsView.columns_hash[colname],
507
+ "Column name #{colname.inspect} was not found in these columns #{SSTestStringDefaultsView.columns.map(&:name).inspect}"
501
508
  end
502
509
  end
503
510
 
@@ -509,7 +516,7 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
509
516
 
510
517
  it "find default values" do
511
518
  assert_equal "null", SSTestStringDefaultsView.new.pretend_null,
512
- SSTestStringDefaultsView.columns_hash["pretend_null"].inspect
519
+ SSTestStringDefaultsView.columns_hash["pretend_null"].inspect
513
520
  end
514
521
 
515
522
  it "respond true to data_source_exists?" do
@@ -519,12 +526,12 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
519
526
  # That have more than 4000 chars for their definition
520
527
 
521
528
  it "cope with null returned for the definition" do
522
- assert_nothing_raised() { SSTestStringDefaultsBigView.columns }
529
+ assert_nothing_raised { SSTestStringDefaultsBigView.columns }
523
530
  end
524
531
 
525
532
  it "using alternate view definition still be able to find real default" do
526
533
  assert_equal "null", SSTestStringDefaultsBigView.new.pretend_null,
527
- SSTestStringDefaultsBigView.columns_hash["pretend_null"].inspect
534
+ SSTestStringDefaultsBigView.columns_hash["pretend_null"].inspect
528
535
  end
529
536
  end
530
537
 
@@ -599,30 +606,30 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
599
606
  end
600
607
  end
601
608
 
602
- describe 'table is in non-dbo schema' do
609
+ describe "table is in non-dbo schema" do
603
610
  it "records can be created successfully" do
604
611
  assert_difference("Alien.count", 1) do
605
- Alien.create!(name: 'Trisolarans')
612
+ Alien.create!(name: "Trisolarans")
606
613
  end
607
614
  end
608
615
 
609
- it 'records can be inserted using SQL' do
616
+ it "records can be inserted using SQL" do
610
617
  assert_difference("Alien.count", 2) do
611
618
  Alien.lease_connection.exec_insert("insert into [test].[aliens] (id, name) VALUES(1, 'Trisolarans'), (2, 'Xenomorph')")
612
619
  end
613
620
  end
614
621
  end
615
622
 
616
- describe 'table names contains spaces' do
617
- it 'records can be created successfully' do
623
+ describe "table names contains spaces" do
624
+ it "records can be created successfully" do
618
625
  assert_difference("TableWithSpaces.count", 1) do
619
- TableWithSpaces.create!(name: 'Bob')
626
+ TableWithSpaces.create!(name: "Bob")
620
627
  end
621
628
  end
622
629
  end
623
630
 
624
631
  describe "exec_insert" do
625
- it 'values clause should be case-insensitive' do
632
+ it "values clause should be case-insensitive" do
626
633
  assert_difference("Post.count", 4) do
627
634
  first_insert = connection.exec_insert("INSERT INTO [posts] ([id],[title],[body]) VALUES(100, 'Title', 'Body'), (102, 'Title', 'Body')")
628
635
  second_insert = connection.exec_insert("INSERT INTO [posts] ([id],[title],[body]) values(113, 'Body', 'Body'), (114, 'Body', 'Body')")
@@ -638,33 +645,37 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
638
645
  @conn = ActiveRecord::Base.lease_connection
639
646
  end
640
647
 
641
- it 'raises an error when the foreign key is mismatched' do
648
+ it "raises an error when the foreign key is mismatched" do
642
649
  error = assert_raises(ActiveRecord::MismatchedForeignKey) do
643
650
  @conn.add_reference :engines, :old_car
644
651
  @conn.add_foreign_key :engines, :old_cars
645
652
  end
646
653
 
647
654
  assert_match(
648
- %r/Column 'old_cars\.id' is not the same data type as referencing column 'engines\.old_car_id' in foreign key '.*'/,
655
+ %r{Column 'old_cars\.id' is not the same data type as referencing column 'engines\.old_car_id' in foreign key '.*'},
649
656
  error.message
650
657
  )
651
658
  assert_not_nil error.cause
652
659
  assert_equal @conn.pool, error.connection_pool
653
660
  ensure
654
- @conn.execute("ALTER TABLE engines DROP COLUMN old_car_id") rescue nil
661
+ begin
662
+ @conn.execute("ALTER TABLE engines DROP COLUMN old_car_id")
663
+ rescue
664
+ nil
665
+ end
655
666
  end
656
667
  end
657
668
 
658
669
  describe "placeholder conditions" do
659
- it 'using time placeholder' do
670
+ it "using time placeholder" do
660
671
  assert_equal Task.where("starting < ?", Time.now).count, 1
661
672
  end
662
673
 
663
- it 'using date placeholder' do
674
+ it "using date placeholder" do
664
675
  assert_equal Task.where("starting < ?", Date.today).count, 1
665
676
  end
666
677
 
667
- it 'using date-time placeholder' do
678
+ it "using date-time placeholder" do
668
679
  assert_equal Task.where("starting < ?", DateTime.current).count, 1
669
680
  end
670
681
  end