activerecord-sqlserver-adapter 8.0.11 → 8.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/Gemfile +1 -0
- data/VERSION +1 -1
- data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +34 -26
- data/test/cases/adapter_test_sqlserver.rb +2 -0
- data/test/cases/change_column_null_test_sqlserver.rb +46 -16
- data/test/cases/schema_test_sqlserver.rb +32 -0
- metadata +4 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f29d990915f935a12f18189d83a0cc11916810756fdac53a52059fcf7e1b8b6b
|
|
4
|
+
data.tar.gz: a5cc606fc70a25ef265f5905c39488267f9a879a7453e422a233bf1e1310aa4d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5e23eb5561377a71f81fb04207bd943b9a30e81b8c01bf7b1a9957a0ade81b7877905dacb9134dce4ad0c129dcb582a487cc2334c1b14e075c804d0a3e803bed
|
|
7
|
+
data.tar.gz: 987035b58b5f7f3fd598d6f819e53a0eb653b8a8390199c56f30765b9f58f461f4a0a44833a3dbf4d6ca1e14f82fb39a3e9c30d469cd3702665dea4103566a69
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
## v8.0.12
|
|
2
|
+
|
|
3
|
+
#### Fixed
|
|
4
|
+
|
|
5
|
+
- [#1418](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1418) Fix `change_column_null` to re-declare datetime2 columns correctly.
|
|
6
|
+
|
|
7
|
+
#### Changed
|
|
8
|
+
|
|
9
|
+
- [#1405](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1405) Fix `insert_all`/`upsert_all` for single character, temporary, non-ASCII and three part table names, and stop an aliased target being included in the `MERGE` table name.
|
|
10
|
+
|
|
1
11
|
## v8.0.11
|
|
2
12
|
|
|
3
13
|
#### Changed
|
data/Gemfile
CHANGED
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
8.0.
|
|
1
|
+
8.0.12
|
|
@@ -4,6 +4,9 @@ module ActiveRecord
|
|
|
4
4
|
module ConnectionAdapters
|
|
5
5
|
module SQLServer
|
|
6
6
|
module SchemaStatements
|
|
7
|
+
MERGE_TARGET_IDENTIFIER = /(?:\[[^\]]+\]|[a-z0-9_-]+)/i # :nodoc:
|
|
8
|
+
MERGE_TARGET_TABLE_NAME = /\A\s*MERGE\s+INTO\s+(#{MERGE_TARGET_IDENTIFIER}(?:\s*\.#{MERGE_TARGET_IDENTIFIER}){0,2})\s+(?:AS|WITH|USING)/i # :nodoc:
|
|
9
|
+
|
|
7
10
|
def native_database_types
|
|
8
11
|
@native_database_types ||= initialize_native_database_types.freeze
|
|
9
12
|
end
|
|
@@ -349,12 +352,12 @@ module ActiveRecord
|
|
|
349
352
|
|
|
350
353
|
def columns_for_distinct(columns, orders)
|
|
351
354
|
order_columns = orders.reject(&:blank?).map { |s|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
355
|
+
s = visitor.compile(s) unless s.is_a?(String)
|
|
356
|
+
s.gsub(/\s+(?:ASC|DESC)\b/i, "")
|
|
357
|
+
.gsub(/\s+NULLS\s+(?:FIRST|LAST)\b/i, "")
|
|
358
|
+
}
|
|
359
|
+
.reject(&:blank?)
|
|
360
|
+
.reject { |s| columns.include?(s) }
|
|
358
361
|
|
|
359
362
|
order_columns_aliased = order_columns.map.with_index { |column, i| "#{column} AS alias_#{i}" }
|
|
360
363
|
|
|
@@ -374,7 +377,12 @@ module ActiveRecord
|
|
|
374
377
|
if !null.nil? && null == false && !default.nil?
|
|
375
378
|
execute("UPDATE #{table_id} SET #{column_id}=#{quote(default)} WHERE #{column_id} IS NULL")
|
|
376
379
|
end
|
|
377
|
-
|
|
380
|
+
|
|
381
|
+
# If datetime column has precision then it should be datetime2 column.
|
|
382
|
+
column_type = column.type
|
|
383
|
+
column_type = :datetime2 if column.type.to_s == "datetime" && !column.precision.nil?
|
|
384
|
+
|
|
385
|
+
sql = "ALTER TABLE #{table_id} ALTER COLUMN #{column_id} #{type_to_sql column_type, limit: column.limit, precision: column.precision, scale: column.scale}"
|
|
378
386
|
sql += " NOT NULL" if !null.nil? && null == false
|
|
379
387
|
|
|
380
388
|
execute sql
|
|
@@ -720,7 +728,7 @@ module ActiveRecord
|
|
|
720
728
|
elsif s.match?(/^\s*UPDATE\s+.*/i)
|
|
721
729
|
s.match(/UPDATE\s+([^\(\s]+)\s*/i)[1]
|
|
722
730
|
elsif s.match?(/^\s*MERGE INTO.*/i)
|
|
723
|
-
s.match(
|
|
731
|
+
s.match(MERGE_TARGET_TABLE_NAME)[1]
|
|
724
732
|
else
|
|
725
733
|
s.match(/FROM[\s|\(]+((\[[^\(\]]+\])|[^\(\s]+)\s*/i)[1]
|
|
726
734
|
end.strip
|
|
@@ -745,24 +753,24 @@ module ActiveRecord
|
|
|
745
753
|
@view_information ||= {}
|
|
746
754
|
|
|
747
755
|
@view_information[table_name] ||= begin
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
756
|
+
identifier = SQLServer::Utils.extract_identifiers(table_name)
|
|
757
|
+
information_query_table = identifier.database.present? ? "[#{identifier.database}].[INFORMATION_SCHEMA].[VIEWS]" : "[INFORMATION_SCHEMA].[VIEWS]"
|
|
758
|
+
|
|
759
|
+
view_info = select_one("SELECT * FROM #{information_query_table} WITH (NOLOCK) WHERE TABLE_NAME = #{quote(identifier.object)}", "SCHEMA").to_h
|
|
760
|
+
|
|
761
|
+
if view_info.present?
|
|
762
|
+
if view_info['VIEW_DEFINITION'].blank? || view_info['VIEW_DEFINITION'].length == 4000
|
|
763
|
+
view_info['VIEW_DEFINITION'] = begin
|
|
764
|
+
select_values("EXEC sp_helptext #{identifier.object_quoted}", "SCHEMA").join
|
|
765
|
+
rescue
|
|
766
|
+
warn "No view definition found, possible permissions problem.\nPlease run GRANT VIEW DEFINITION TO your_user;"
|
|
767
|
+
nil
|
|
768
|
+
end
|
|
769
|
+
end
|
|
770
|
+
end
|
|
771
|
+
|
|
772
|
+
view_info
|
|
773
|
+
end
|
|
766
774
|
end
|
|
767
775
|
|
|
768
776
|
def views_real_column_name(table_name, column_name)
|
|
@@ -224,6 +224,7 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
|
224
224
|
@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
225
|
@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
226
|
@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)", "")
|
|
227
228
|
|
|
228
229
|
@identity_insert_sql_non_dbo = "INSERT INTO [test].[aliens] ([id],[name]) VALUES(420,'Mork')"
|
|
229
230
|
@identity_insert_sql_non_dbo_unquoted = "INSERT INTO test.aliens ([id],[name]) VALUES(420,'Mork')"
|
|
@@ -247,6 +248,7 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
|
247
248
|
assert_equal "[ships]", connection.send(:query_requires_identity_insert?, @identity_merge_sql)
|
|
248
249
|
assert_equal "[ships]", connection.send(:query_requires_identity_insert?, @identity_merge_sql_unquoted)
|
|
249
250
|
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)
|
|
250
252
|
|
|
251
253
|
assert_equal "[test].[aliens]", connection.send(:query_requires_identity_insert?, @identity_insert_sql_non_dbo)
|
|
252
254
|
assert_equal "[test].[aliens]", connection.send(:query_requires_identity_insert?, @identity_insert_sql_non_dbo_unquoted)
|
|
@@ -2,29 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
require "cases/helper_sqlserver"
|
|
4
4
|
require "migrations/create_clients_and_change_column_null"
|
|
5
|
+
require "cases/migration/helper"
|
|
5
6
|
|
|
6
7
|
class ChangeColumnNullTestSqlServer < ActiveRecord::TestCase
|
|
7
|
-
|
|
8
|
-
@old_verbose = ActiveRecord::Migration.verbose
|
|
9
|
-
ActiveRecord::Migration.verbose = false
|
|
10
|
-
CreateClientsAndChangeColumnNull.new.up
|
|
11
|
-
end
|
|
8
|
+
include ::ActiveRecord::Migration::TestHelper
|
|
12
9
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
ActiveRecord::Migration.verbose = @old_verbose
|
|
10
|
+
def find_column(table, column_name)
|
|
11
|
+
connection.columns(table).find { |column| column.name == column_name.to_s }
|
|
16
12
|
end
|
|
17
13
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
14
|
+
describe "using migration" do
|
|
15
|
+
before do
|
|
16
|
+
@old_verbose = ActiveRecord::Migration.verbose
|
|
17
|
+
ActiveRecord::Migration.verbose = false
|
|
18
|
+
CreateClientsAndChangeColumnNull.new.up
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
after do
|
|
22
|
+
CreateClientsAndChangeColumnNull.new.down
|
|
23
|
+
ActiveRecord::Migration.verbose = @old_verbose
|
|
24
|
+
end
|
|
21
25
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
let(:value_column) { find_column(clients_table, "value") }
|
|
26
|
+
let(:name_column) { find_column("clients", "name") }
|
|
27
|
+
let(:code_column) { find_column("clients", "code") }
|
|
28
|
+
let(:value_column) { find_column("clients", "value") }
|
|
26
29
|
|
|
27
|
-
describe "#change_column_null" do
|
|
28
30
|
it "does not change the column limit" do
|
|
29
31
|
_(name_column.limit).must_equal 15
|
|
30
32
|
end
|
|
@@ -41,4 +43,32 @@ class ChangeColumnNullTestSqlServer < ActiveRecord::TestCase
|
|
|
41
43
|
_(value_column.scale).must_equal 8
|
|
42
44
|
end
|
|
43
45
|
end
|
|
46
|
+
|
|
47
|
+
it "datetime2 column" do
|
|
48
|
+
add_column :test_models, :expiry_date, :datetime, precision: 6, null: true
|
|
49
|
+
|
|
50
|
+
_(find_column(:test_models, :expiry_date).sql_type).must_equal "datetime2(6)"
|
|
51
|
+
_(find_column(:test_models, :expiry_date).null).must_equal true
|
|
52
|
+
|
|
53
|
+
connection.change_column_null(:test_models, :expiry_date, false)
|
|
54
|
+
|
|
55
|
+
_(find_column(:test_models, :expiry_date).sql_type).must_equal "datetime2(6)"
|
|
56
|
+
_(find_column(:test_models, :expiry_date).null).must_equal false
|
|
57
|
+
ensure
|
|
58
|
+
remove_column("test_models", "expiry_date")
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it "datetime column" do
|
|
62
|
+
add_column :test_models, :expiry_date, :datetime, precision: nil, null: true
|
|
63
|
+
|
|
64
|
+
_(find_column(:test_models, :expiry_date).sql_type).must_equal "datetime"
|
|
65
|
+
_(find_column(:test_models, :expiry_date).null).must_equal true
|
|
66
|
+
|
|
67
|
+
connection.change_column_null(:test_models, :expiry_date, false)
|
|
68
|
+
|
|
69
|
+
_(find_column(:test_models, :expiry_date).sql_type).must_equal "datetime"
|
|
70
|
+
_(find_column(:test_models, :expiry_date).null).must_equal false
|
|
71
|
+
ensure
|
|
72
|
+
remove_column("test_models", "expiry_date")
|
|
73
|
+
end
|
|
44
74
|
end
|
|
@@ -122,6 +122,38 @@ class SchemaTestSQLServer < ActiveRecord::TestCase
|
|
|
122
122
|
it do
|
|
123
123
|
assert_equal "[with_numbers_1234]", connection.send(:get_raw_table_name, "MERGE INTO [with_numbers_1234] AS target")
|
|
124
124
|
end
|
|
125
|
+
|
|
126
|
+
it do
|
|
127
|
+
assert_equal "[dashboards]", connection.send(:get_raw_table_name, "MERGE INTO [dashboards] AS target USING (VALUES (1)) AS source ([id]) ON (target.[id] = source.[id]) WHEN NOT MATCHED THEN INSERT ([id]) VALUES (source.[id]);")
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
it do
|
|
131
|
+
assert_equal "lock_without_defaults", connection.send(:get_raw_table_name, "MERGE INTO lock_without_defaults AS target USING (VALUES (1)) AS source ([id]) ON (target.[id] = source.[id]) WHEN NOT MATCHED THEN INSERT ([id]) VALUES (source.[id]);")
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
it do
|
|
135
|
+
assert_equal "[WITH - SPACES]", connection.send(:get_raw_table_name, "MERGE INTO [WITH - SPACES] AS target USING (VALUES (1)) AS source ([id]) ON (target.[id] = source.[id]) WHEN NOT MATCHED THEN INSERT ([id]) VALUES (source.[id]);")
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
it do
|
|
139
|
+
assert_equal "[with].[select notation]", connection.send(:get_raw_table_name, "MERGE INTO [with].[select notation] AS target USING (VALUES (1)) AS source ([id]) ON (target.[id] = source.[id]) WHEN NOT MATCHED THEN INSERT ([id]) VALUES (source.[id]);")
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
it do
|
|
143
|
+
assert_equal "[x]", connection.send(:get_raw_table_name, "MERGE INTO [x] WITH (UPDLOCK, HOLDLOCK) AS target USING (VALUES (1)) AS source ([id]) ON (target.[id] = source.[id]) WHEN NOT MATCHED THEN INSERT ([id]) VALUES (source.[id]);")
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
it do
|
|
147
|
+
assert_equal "[with].[select notation]", connection.send(:get_raw_table_name, "MERGE INTO [with].[select notation] WITH (UPDLOCK, HOLDLOCK) AS target USING (VALUES (1)) AS source ([id]) ON (target.[id] = source.[id]) WHEN NOT MATCHED THEN INSERT ([id]) VALUES (source.[id]);")
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
it do
|
|
151
|
+
assert_equal "[a].[dbo].[dashboards]", connection.send(:get_raw_table_name, "MERGE INTO [a].[dbo].[dashboards] WITH (UPDLOCK, HOLDLOCK) AS target USING (VALUES (1)) AS source ([id]) ON (target.[id] = source.[id]) WHEN NOT MATCHED THEN INSERT ([id]) VALUES (source.[id]);")
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
it do
|
|
155
|
+
assert_equal "with .dashboards", connection.send(:get_raw_table_name, "MERGE INTO with .dashboards WITH (UPDLOCK, HOLDLOCK) AS target USING (VALUES (1)) AS source ([id]) ON (target.[id] = source.[id]) WHEN NOT MATCHED THEN INSERT ([id]) VALUES (source.[id]);")
|
|
156
|
+
end
|
|
125
157
|
end
|
|
126
158
|
|
|
127
159
|
describe 'CREATE VIEW statements' do
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: activerecord-sqlserver-adapter
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 8.0.
|
|
4
|
+
version: 8.0.12
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ken Collins
|
|
@@ -243,8 +243,8 @@ licenses:
|
|
|
243
243
|
- MIT
|
|
244
244
|
metadata:
|
|
245
245
|
bug_tracker_uri: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/issues
|
|
246
|
-
changelog_uri: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/blob/v8.0.
|
|
247
|
-
source_code_uri: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/v8.0.
|
|
246
|
+
changelog_uri: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/blob/v8.0.12/CHANGELOG.md
|
|
247
|
+
source_code_uri: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/v8.0.12
|
|
248
248
|
rdoc_options: []
|
|
249
249
|
require_paths:
|
|
250
250
|
- lib
|
|
@@ -259,7 +259,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
259
259
|
- !ruby/object:Gem::Version
|
|
260
260
|
version: '0'
|
|
261
261
|
requirements: []
|
|
262
|
-
rubygems_version:
|
|
262
|
+
rubygems_version: 4.0.16
|
|
263
263
|
specification_version: 4
|
|
264
264
|
summary: ActiveRecord SQL Server Adapter.
|
|
265
265
|
test_files:
|