activerecord-sqlserver-adapter 7.0.2.0 → 7.0.4.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +23 -0
- data/MIT-LICENSE +1 -1
- data/README.md +9 -4
- data/VERSION +1 -1
- data/activerecord-sqlserver-adapter.gemspec +1 -1
- data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +5 -5
- data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +27 -8
- data/lib/active_record/connection_adapters/sqlserver/table_definition.rb +7 -2
- data/lib/active_record/connection_adapters/sqlserver/type/data.rb +6 -0
- data/lib/active_record/connection_adapters/sqlserver/utils.rb +1 -1
- data/test/cases/adapter_test_sqlserver.rb +44 -8
- data/test/cases/coerced_tests.rb +58 -9
- data/test/cases/enum_test_sqlserver.rb +49 -0
- data/test/cases/migration_test_sqlserver.rb +18 -0
- data/test/cases/schema_dumper_test_sqlserver.rb +121 -101
- data/test/cases/schema_test_sqlserver.rb +0 -4
- data/test/cases/utils_test_sqlserver.rb +2 -2
- data/test/schema/sqlserver_specific_schema.rb +4 -2
- metadata +8 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 41b4642838dbc7178a170c4b002937e5481bf0c7154446d43cff2dae7800a938
|
4
|
+
data.tar.gz: fa20040c55e79a8417ec58c414b5ad6617acaa2fe808c5b48fc44c6e3187c5d7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b7786aeaaf3f90af8a69208e76901c1263e20ef1c4f410948319108531e128ff2d5247838efb10cbcda0fe6b035d1b130576647824e027a668b0fc3df1988305
|
7
|
+
data.tar.gz: 3d9db5b28f4b8b8468b71049b14b7000e25c7aa7afcac55f6fec0ec234f0e4cdf76c4158069328da464ad0a718f45ee9b45b2b6f19f00fc058b7d4ab87071308
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,26 @@
|
|
1
|
+
## v7.0.4.0
|
2
|
+
|
3
|
+
#### Changed
|
4
|
+
|
5
|
+
- [#1073](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1073) Improve performance of view default function lookup
|
6
|
+
|
7
|
+
#### Fixed
|
8
|
+
|
9
|
+
- [#1088](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1088) Fix creation of stored procedures that contain insert statements
|
10
|
+
- [#1089](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1089) When changing columns set date-time columns to datetime(6) by default
|
11
|
+
|
12
|
+
## v7.0.3.0
|
13
|
+
|
14
|
+
#### Fixed
|
15
|
+
|
16
|
+
- [#1052](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1052) Ignore casing of VALUES clause when inserting records using SQL
|
17
|
+
- [#1053](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1053) Fix insertion of records to non-default schema table using raw SQL
|
18
|
+
- [#1059](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1059) Fix enums defined on string columns
|
19
|
+
|
20
|
+
#### Changed
|
21
|
+
|
22
|
+
- [#1057](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1057) Set precision 6 by default for timestamps.
|
23
|
+
|
1
24
|
## v7.0.2.0
|
2
25
|
|
3
26
|
[Full changelog](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/compare/v7.0.1.0...v7.0.2.0)
|
data/MIT-LICENSE
CHANGED
data/README.md
CHANGED
@@ -13,9 +13,9 @@ Interested in older versions? We follow a rational versioning policy that tracks
|
|
13
13
|
|
14
14
|
| Adapter Version | Rails Version | Support |
|
15
15
|
|-----------------| ------------- | ------------------------------------------------------------------------------------------- |
|
16
|
-
| `7.0.
|
16
|
+
| `7.0.4.0` | `7.0.x` | [active](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/main) |
|
17
17
|
| `6.1.2.1` | `6.1.x` | [active](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/6-1-stable) |
|
18
|
-
| `6.0.
|
18
|
+
| `6.0.3` | `6.0.x` | [active](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/6-0-stable) |
|
19
19
|
| `5.2.1` | `5.2.x` | [ended](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/5-2-stable) |
|
20
20
|
| `5.1.6` | `5.1.x` | [ended](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/5-1-stable) |
|
21
21
|
| `4.2.18` | `4.2.x` | [ended](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/4-2-stable) |
|
@@ -29,7 +29,11 @@ We support every data type supported by FreeTDS. All simplified Rails types in m
|
|
29
29
|
|
30
30
|
The following types (`date`, `datetime2`, `datetimeoffset`, `time`) all require TDS version `7.3` with TinyTDS. We recommend using FreeTDS 1.0 or higher which default to using `TDSVER` to `7.3`. The adapter also sets TinyTDS's `tds_version` to this as well if non is specified.
|
31
31
|
|
32
|
-
The
|
32
|
+
The adapter supports ActiveRecord's `datetime_with_precision` setting. This means that passing `:precision` to a datetime column is supported.
|
33
|
+
|
34
|
+
By default, precision 6 is used for `:datetime` types if precision is not specified. Any non-nil precision will tell
|
35
|
+
the adapter to use the `datetime2` column type. To create a `datetime` column using a migration a precision of `nil`
|
36
|
+
should be specified, otherwise the precision will default to 6 and a `datetime2` column will be created.
|
33
37
|
|
34
38
|
|
35
39
|
#### Identity Inserts with Triggers
|
@@ -186,6 +190,7 @@ Many many people have contributed. If you do not see your name here and it shoul
|
|
186
190
|
|
187
191
|
You can see an up-to-date list of contributors here: http://github.com/rails-sqlserver/activerecord-sqlserver-adapter/contributors
|
188
192
|
|
193
|
+
|
189
194
|
## License
|
190
195
|
|
191
|
-
|
196
|
+
ActiveRecord SQL Server Adapter is released under the [MIT License](https://opensource.org/licenses/MIT).
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
7.0.
|
1
|
+
7.0.4.0
|
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
|
|
10
10
|
spec.required_ruby_version = ">= 2.7.0"
|
11
11
|
|
12
12
|
spec.license = "MIT"
|
13
|
-
spec.authors = ["Ken Collins", "Anna Carey", "Will Bond", "Murray Steele", "Shawn Balestracci", "Joe Rafaniello", "Tom Ward"]
|
13
|
+
spec.authors = ["Ken Collins", "Anna Carey", "Will Bond", "Murray Steele", "Shawn Balestracci", "Joe Rafaniello", "Tom Ward", "Aidan Haran"]
|
14
14
|
spec.email = ["ken@metaskills.net", "will@wbond.net"]
|
15
15
|
spec.homepage = "http://github.com/rails-sqlserver/activerecord-sqlserver-adapter"
|
16
16
|
spec.summary = "ActiveRecord SQL Server Adapter."
|
@@ -278,11 +278,11 @@ module ActiveRecord
|
|
278
278
|
id_sql_type = exclude_output_inserted.is_a?(TrueClass) ? "bigint" : exclude_output_inserted
|
279
279
|
<<~SQL.squish
|
280
280
|
DECLARE @ssaIdInsertTable table (#{quoted_pk} #{id_sql_type});
|
281
|
-
#{sql.dup.insert sql.index(/ (DEFAULT )?VALUES/), " OUTPUT INSERTED.#{quoted_pk} INTO @ssaIdInsertTable"}
|
281
|
+
#{sql.dup.insert sql.index(/ (DEFAULT )?VALUES/i), " OUTPUT INSERTED.#{quoted_pk} INTO @ssaIdInsertTable"}
|
282
282
|
SELECT CAST(#{quoted_pk} AS #{id_sql_type}) FROM @ssaIdInsertTable
|
283
283
|
SQL
|
284
284
|
else
|
285
|
-
sql.dup.insert sql.index(/ (DEFAULT )?VALUES/), " OUTPUT INSERTED.#{quoted_pk}"
|
285
|
+
sql.dup.insert sql.index(/ (DEFAULT )?VALUES/i), " OUTPUT INSERTED.#{quoted_pk}"
|
286
286
|
end
|
287
287
|
else
|
288
288
|
"#{sql}; SELECT CAST(SCOPE_IDENTITY() AS bigint) AS Ident"
|
@@ -392,7 +392,7 @@ module ActiveRecord
|
|
392
392
|
self.class.exclude_output_inserted_table_names[table_name]
|
393
393
|
end
|
394
394
|
|
395
|
-
def exec_insert_requires_identity?(sql,
|
395
|
+
def exec_insert_requires_identity?(sql, _pk, _binds)
|
396
396
|
query_requires_identity_insert?(sql)
|
397
397
|
end
|
398
398
|
|
@@ -402,11 +402,11 @@ module ActiveRecord
|
|
402
402
|
raw_table_name = get_raw_table_name(sql)
|
403
403
|
id_column = identity_columns(raw_table_name).first
|
404
404
|
|
405
|
-
id_column && sql =~ /^\s*(INSERT|EXEC sp_executesql N'INSERT)[^(]+\([^)]*\b(#{id_column.name})\b,?[^)]*\)/i ? SQLServer::Utils.extract_identifiers(raw_table_name).
|
405
|
+
id_column && sql =~ /^\s*(INSERT|EXEC sp_executesql N'INSERT)[^(]+\([^)]*\b(#{id_column.name})\b,?[^)]*\)/i ? SQLServer::Utils.extract_identifiers(raw_table_name).quoted : false
|
406
406
|
end
|
407
407
|
|
408
408
|
def insert_sql?(sql)
|
409
|
-
!(sql =~
|
409
|
+
!(sql =~ /\A\s*(INSERT|EXEC sp_executesql N'INSERT)/i).nil?
|
410
410
|
end
|
411
411
|
|
412
412
|
def identity_columns(table_name)
|
@@ -143,6 +143,15 @@ module ActiveRecord
|
|
143
143
|
def change_column(table_name, column_name, type, options = {})
|
144
144
|
sql_commands = []
|
145
145
|
indexes = []
|
146
|
+
|
147
|
+
if type == :datetime
|
148
|
+
# If no precision then default it to 6.
|
149
|
+
options[:precision] = 6 unless options.key?(:precision)
|
150
|
+
|
151
|
+
# If there is precision then column must be of type 'datetime2'.
|
152
|
+
type = :datetime2 unless options[:precision].nil?
|
153
|
+
end
|
154
|
+
|
146
155
|
column_object = schema_cache.columns(table_name).find { |c| c.name.to_s == column_name.to_s }
|
147
156
|
without_constraints = options.key?(:default) || options.key?(:limit)
|
148
157
|
default = if !options.key?(:default) && column_object
|
@@ -150,24 +159,29 @@ module ActiveRecord
|
|
150
159
|
else
|
151
160
|
options[:default]
|
152
161
|
end
|
162
|
+
|
153
163
|
if without_constraints || (column_object && column_object.type != type.to_sym)
|
154
164
|
remove_default_constraint(table_name, column_name)
|
155
165
|
indexes = indexes(table_name).select { |index| index.columns.include?(column_name.to_s) }
|
156
166
|
remove_indexes(table_name, column_name)
|
157
167
|
end
|
168
|
+
|
158
169
|
sql_commands << "UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote_default_expression(options[:default], column_object)} WHERE #{quote_column_name(column_name)} IS NULL" if !options[:null].nil? && options[:null] == false && !options[:default].nil?
|
159
170
|
alter_command = "ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN #{quote_column_name(column_name)} #{type_to_sql(type, limit: options[:limit], precision: options[:precision], scale: options[:scale])}"
|
160
171
|
alter_command += " COLLATE #{options[:collation]}" if options[:collation].present?
|
161
172
|
alter_command += " NOT NULL" if !options[:null].nil? && options[:null] == false
|
162
173
|
sql_commands << alter_command
|
174
|
+
|
163
175
|
if without_constraints
|
164
176
|
default = quote_default_expression(default, column_object || column_for(table_name, column_name))
|
165
177
|
sql_commands << "ALTER TABLE #{quote_table_name(table_name)} ADD CONSTRAINT #{default_constraint_name(table_name, column_name)} DEFAULT #{default} FOR #{quote_column_name(column_name)}"
|
166
178
|
end
|
179
|
+
|
167
180
|
# Add any removed indexes back
|
168
181
|
indexes.each do |index|
|
169
182
|
sql_commands << "CREATE INDEX #{quote_table_name(index.name)} ON #{quote_table_name(table_name)} (#{index.columns.map { |c| quote_column_name(c) }.join(', ')})"
|
170
183
|
end
|
184
|
+
|
171
185
|
sql_commands.each { |c| do_execute(c) }
|
172
186
|
clear_cache!
|
173
187
|
end
|
@@ -229,6 +243,7 @@ module ActiveRecord
|
|
229
243
|
def type_to_sql(type, limit: nil, precision: nil, scale: nil, **)
|
230
244
|
type_limitable = %w(string integer float char nchar varchar nvarchar).include?(type.to_s)
|
231
245
|
limit = nil unless type_limitable
|
246
|
+
|
232
247
|
case type.to_s
|
233
248
|
when "integer"
|
234
249
|
case limit
|
@@ -346,7 +361,7 @@ module ActiveRecord
|
|
346
361
|
datetime2: { name: "datetime2" },
|
347
362
|
datetimeoffset: { name: "datetimeoffset" },
|
348
363
|
smalldatetime: { name: "smalldatetime" },
|
349
|
-
timestamp: { name: "
|
364
|
+
timestamp: { name: "datetime2(6)" },
|
350
365
|
time: { name: "time" },
|
351
366
|
char: { name: "char" },
|
352
367
|
varchar: { name: "varchar", limit: 8000 },
|
@@ -371,6 +386,15 @@ module ActiveRecord
|
|
371
386
|
view_exists = view_exists?(table_name)
|
372
387
|
view_tblnm = view_table_name(table_name) if view_exists
|
373
388
|
|
389
|
+
if view_exists
|
390
|
+
results = sp_executesql %{
|
391
|
+
SELECT c.COLUMN_NAME AS [name], c.COLUMN_DEFAULT AS [default]
|
392
|
+
FROM #{database}.INFORMATION_SCHEMA.COLUMNS c
|
393
|
+
WHERE c.TABLE_NAME = #{quote(view_tblnm)}
|
394
|
+
}.squish, "SCHEMA", []
|
395
|
+
default_functions = results.each.with_object({}) {|row, out| out[row["name"]] = row["default"] }.compact
|
396
|
+
end
|
397
|
+
|
374
398
|
sql = column_definitions_sql(database, identifier)
|
375
399
|
|
376
400
|
binds = []
|
@@ -402,13 +426,8 @@ module ActiveRecord
|
|
402
426
|
ci[:default_function] = begin
|
403
427
|
default = ci[:default_value]
|
404
428
|
if default.nil? && view_exists
|
405
|
-
|
406
|
-
|
407
|
-
FROM #{database}.INFORMATION_SCHEMA.COLUMNS c
|
408
|
-
WHERE
|
409
|
-
c.TABLE_NAME = '#{view_tblnm}'
|
410
|
-
AND c.COLUMN_NAME = '#{views_real_column_name(table_name, ci[:name])}'
|
411
|
-
}.squish, "SCHEMA"
|
429
|
+
view_column = views_real_column_name(table_name, ci[:name])
|
430
|
+
default = default_functions[view_column] if view_column.present?
|
412
431
|
end
|
413
432
|
case default
|
414
433
|
when nil
|
@@ -101,11 +101,16 @@ module ActiveRecord
|
|
101
101
|
|
102
102
|
def new_column_definition(name, type, **options)
|
103
103
|
case type
|
104
|
-
when :datetime
|
105
|
-
|
104
|
+
when :datetime, :timestamp
|
105
|
+
# If no precision then default it to 6.
|
106
|
+
options[:precision] = 6 unless options.key?(:precision)
|
107
|
+
|
108
|
+
# If there is precision then column must be of type 'datetime2'.
|
109
|
+
type = :datetime2 unless options[:precision].nil?
|
106
110
|
when :primary_key
|
107
111
|
options[:is_identity] = true
|
108
112
|
end
|
113
|
+
|
109
114
|
super
|
110
115
|
end
|
111
116
|
end
|
@@ -27,6 +27,12 @@ module ActiveRecord
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def eql?(other)
|
30
|
+
# Support comparing `Type::Char`, `Type::Varchar` and `VarcharMax` with strings.
|
31
|
+
# This happens when we use enum with string columns.
|
32
|
+
if other.is_a?(::String)
|
33
|
+
return type.is_a?(ActiveRecord::ConnectionAdapters::SQLServer::Type::String) && value == other
|
34
|
+
end
|
35
|
+
|
30
36
|
self.class == other.class && value == other.value
|
31
37
|
end
|
32
38
|
alias :== :eql?
|
@@ -9,7 +9,7 @@ module ActiveRecord
|
|
9
9
|
QUOTED_STRING_PREFIX = "N"
|
10
10
|
|
11
11
|
# Value object to return identifiers from SQL Server names http://bit.ly/1CZ3EiL
|
12
|
-
#
|
12
|
+
# Inspired from Rails PostgreSQL::Name adapter object in their own Utils.
|
13
13
|
#
|
14
14
|
class Name
|
15
15
|
SEPARATOR = "."
|
@@ -193,17 +193,31 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
193
193
|
@identity_insert_sql_unquoted = "INSERT INTO funny_jokes (id, name) VALUES(420, 'Knock knock')"
|
194
194
|
@identity_insert_sql_unordered = "INSERT INTO [funny_jokes] ([name],[id]) VALUES('Knock knock',420)"
|
195
195
|
@identity_insert_sql_sp = "EXEC sp_executesql N'INSERT INTO [funny_jokes] ([id],[name]) VALUES (@0, @1)', N'@0 int, @1 nvarchar(255)', @0 = 420, @1 = N'Knock knock'"
|
196
|
-
@identity_insert_sql_unquoted_sp = "EXEC sp_executesql N'INSERT INTO
|
196
|
+
@identity_insert_sql_unquoted_sp = "EXEC sp_executesql N'INSERT INTO funny_jokes (id, name) VALUES (@0, @1)', N'@0 int, @1 nvarchar(255)', @0 = 420, @1 = N'Knock knock'"
|
197
197
|
@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"
|
198
|
+
|
199
|
+
@identity_insert_sql_non_dbo = "INSERT INTO [test].[aliens] ([id],[name]) VALUES(420,'Mork')"
|
200
|
+
@identity_insert_sql_non_dbo_unquoted = "INSERT INTO test.aliens ([id],[name]) VALUES(420,'Mork')"
|
201
|
+
@identity_insert_sql_non_dbo_unordered = "INSERT INTO [test].[aliens] ([name],[id]) VALUES('Mork',420)"
|
202
|
+
@identity_insert_sql_non_dbo_sp = "EXEC sp_executesql N'INSERT INTO [test].[aliens] ([id],[name]) VALUES (@0, @1)', N'@0 int, @1 nvarchar(255)', @0 = 420, @1 = N'Mork'"
|
203
|
+
@identity_insert_sql_non_dbo_unquoted_sp = "EXEC sp_executesql N'INSERT INTO test.aliens (id, name) VALUES (@0, @1)', N'@0 int, @1 nvarchar(255)', @0 = 420, @1 = N'Mork'"
|
204
|
+
@identity_insert_sql_non_dbo_unordered_sp = "EXEC sp_executesql N'INSERT INTO [test].[aliens] ([name],[id]) VALUES (@0, @1)', N'@0 nvarchar(255), @1 int', @0 = N'Mork', @1 = 420"
|
198
205
|
end
|
199
206
|
|
200
|
-
it "return
|
201
|
-
assert_equal "funny_jokes",
|
202
|
-
assert_equal "funny_jokes",
|
203
|
-
assert_equal "funny_jokes",
|
204
|
-
assert_equal "funny_jokes",
|
205
|
-
assert_equal "funny_jokes",
|
206
|
-
assert_equal "funny_jokes",
|
207
|
+
it "return quoted table_name to #query_requires_identity_insert? when INSERT sql contains id column" do
|
208
|
+
assert_equal "[funny_jokes]", connection.send(:query_requires_identity_insert?, @identity_insert_sql)
|
209
|
+
assert_equal "[funny_jokes]", connection.send(:query_requires_identity_insert?, @identity_insert_sql_unquoted)
|
210
|
+
assert_equal "[funny_jokes]", connection.send(:query_requires_identity_insert?, @identity_insert_sql_unordered)
|
211
|
+
assert_equal "[funny_jokes]", connection.send(:query_requires_identity_insert?, @identity_insert_sql_sp)
|
212
|
+
assert_equal "[funny_jokes]", connection.send(:query_requires_identity_insert?, @identity_insert_sql_unquoted_sp)
|
213
|
+
assert_equal "[funny_jokes]", connection.send(:query_requires_identity_insert?, @identity_insert_sql_unordered_sp)
|
214
|
+
|
215
|
+
assert_equal "[test].[aliens]", connection.send(:query_requires_identity_insert?, @identity_insert_sql_non_dbo)
|
216
|
+
assert_equal "[test].[aliens]", connection.send(:query_requires_identity_insert?, @identity_insert_sql_non_dbo_unquoted)
|
217
|
+
assert_equal "[test].[aliens]", connection.send(:query_requires_identity_insert?, @identity_insert_sql_non_dbo_unordered)
|
218
|
+
assert_equal "[test].[aliens]", connection.send(:query_requires_identity_insert?, @identity_insert_sql_non_dbo_sp)
|
219
|
+
assert_equal "[test].[aliens]", connection.send(:query_requires_identity_insert?, @identity_insert_sql_non_dbo_unquoted_sp)
|
220
|
+
assert_equal "[test].[aliens]", connection.send(:query_requires_identity_insert?, @identity_insert_sql_non_dbo_unordered_sp)
|
207
221
|
end
|
208
222
|
|
209
223
|
it "return false to #query_requires_identity_insert? for normal SQL" do
|
@@ -532,4 +546,26 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
532
546
|
end
|
533
547
|
end
|
534
548
|
end
|
549
|
+
|
550
|
+
describe 'table is in non-dbo schema' do
|
551
|
+
it "records can be created successfully" do
|
552
|
+
Alien.create!(name: 'Trisolarans')
|
553
|
+
end
|
554
|
+
|
555
|
+
it 'records can be inserted using SQL' do
|
556
|
+
Alien.connection.exec_insert("insert into [test].[aliens] (id, name) VALUES(1, 'Trisolarans'), (2, 'Xenomorph')")
|
557
|
+
end
|
558
|
+
end
|
559
|
+
|
560
|
+
describe "exec_insert" do
|
561
|
+
it 'values clause should be case-insensitive' do
|
562
|
+
assert_difference("Post.count", 4) do
|
563
|
+
first_insert = connection.exec_insert("INSERT INTO [posts] ([id],[title],[body]) VALUES(100, 'Title', 'Body'), (102, 'Title', 'Body')")
|
564
|
+
second_insert = connection.exec_insert("INSERT INTO [posts] ([id],[title],[body]) values(113, 'Body', 'Body'), (114, 'Body', 'Body')")
|
565
|
+
|
566
|
+
assert_equal first_insert.rows.map(&:first), [100, 102]
|
567
|
+
assert_equal second_insert.rows.map(&:first), [113, 114]
|
568
|
+
end
|
569
|
+
end
|
570
|
+
end
|
535
571
|
end
|
data/test/cases/coerced_tests.rb
CHANGED
@@ -450,7 +450,7 @@ class CalculationsTest < ActiveRecord::TestCase
|
|
450
450
|
FROM companies
|
451
451
|
INNER JOIN accounts ON companies.id = accounts.firm_id
|
452
452
|
WHERE companies.id = ?
|
453
|
-
GROUP BY companies.id, companies.type, companies.firm_id, companies.firm_name, companies.name, companies.client_of, companies.rating, companies.account_id, companies.description
|
453
|
+
GROUP BY companies.id, companies.type, companies.firm_id, companies.firm_name, companies.name, companies.client_of, companies.rating, companies.account_id, companies.description, companies.status
|
454
454
|
ORDER BY companies.id
|
455
455
|
OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY
|
456
456
|
SQL
|
@@ -476,7 +476,7 @@ class CalculationsTest < ActiveRecord::TestCase
|
|
476
476
|
.select("companies.*", "AVG(CAST(accounts.credit_limit AS DECIMAL)) AS avg_credit_limit")
|
477
477
|
.where(id: rails_core)
|
478
478
|
.joins(:account)
|
479
|
-
.group(:id, :type, :firm_id, :firm_name, :name, :client_of, :rating, :account_id, :description)
|
479
|
+
.group(:id, :type, :firm_id, :firm_name, :name, :client_of, :rating, :account_id, :description, :status)
|
480
480
|
.take!
|
481
481
|
|
482
482
|
# all the DependentFirm attributes should be present
|
@@ -543,7 +543,7 @@ module ActiveRecord
|
|
543
543
|
assert_equal "hello", five.default
|
544
544
|
end
|
545
545
|
|
546
|
-
#
|
546
|
+
# Use precision 6 by default for datetime/timestamp columns. SQL Server uses `datetime2` for date-times with precision.
|
547
547
|
coerce_tests! :test_add_column_with_postgresql_datetime_type
|
548
548
|
def test_add_column_with_postgresql_datetime_type_coerced
|
549
549
|
connection.create_table :testings do |t|
|
@@ -556,7 +556,7 @@ module ActiveRecord
|
|
556
556
|
assert_equal "datetime2(6)", column.sql_type
|
557
557
|
end
|
558
558
|
|
559
|
-
#
|
559
|
+
# Use precision 6 by default for datetime/timestamp columns. SQL Server uses `datetime2` for date-times with precision.
|
560
560
|
coerce_tests! :test_change_column_with_timestamp_type
|
561
561
|
def test_change_column_with_timestamp_type_coerced
|
562
562
|
connection.create_table :testings do |t|
|
@@ -568,7 +568,20 @@ module ActiveRecord
|
|
568
568
|
column = connection.columns(:testings).find { |c| c.name == "foo" }
|
569
569
|
|
570
570
|
assert_equal :datetime, column.type
|
571
|
-
assert_equal "
|
571
|
+
assert_equal "datetime2(6)", column.sql_type
|
572
|
+
end
|
573
|
+
|
574
|
+
# Use precision 6 by default for datetime/timestamp columns. SQL Server uses `datetime2` for date-times with precision.
|
575
|
+
coerce_tests! :test_add_column_with_timestamp_type
|
576
|
+
def test_add_column_with_timestamp_type_coerced
|
577
|
+
connection.create_table :testings do |t|
|
578
|
+
t.column :foo, :timestamp
|
579
|
+
end
|
580
|
+
|
581
|
+
column = connection.columns(:testings).find { |c| c.name == "foo" }
|
582
|
+
|
583
|
+
assert_equal :datetime, column.type
|
584
|
+
assert_equal "datetime2(6)", column.sql_type
|
572
585
|
end
|
573
586
|
end
|
574
587
|
end
|
@@ -1297,9 +1310,26 @@ class RelationTest < ActiveRecord::TestCase
|
|
1297
1310
|
# We are not doing order duplicate removal anymore.
|
1298
1311
|
coerce_tests! :test_default_scope_order_with_scope_order
|
1299
1312
|
|
1300
|
-
#
|
1313
|
+
# Order column must be in the GROUP clause.
|
1301
1314
|
coerce_tests! :test_multiple_where_and_having_clauses
|
1315
|
+
def test_multiple_where_and_having_clauses_coerced
|
1316
|
+
post = Post.first
|
1317
|
+
having_then_where = Post.having(id: post.id).where(title: post.title)
|
1318
|
+
.having(id: post.id).where(title: post.title).group(:id).select(:id)
|
1319
|
+
|
1320
|
+
assert_equal [post], having_then_where
|
1321
|
+
end
|
1322
|
+
|
1323
|
+
# Order column must be in the GROUP clause.
|
1302
1324
|
coerce_tests! :test_having_with_binds_for_both_where_and_having
|
1325
|
+
def test_having_with_binds_for_both_where_and_having
|
1326
|
+
post = Post.first
|
1327
|
+
having_then_where = Post.having(id: post.id).where(title: post.title).group(:id).select(:id)
|
1328
|
+
where_then_having = Post.where(title: post.title).having(id: post.id).group(:id).select(:id)
|
1329
|
+
|
1330
|
+
assert_equal [post], having_then_where
|
1331
|
+
assert_equal [post], where_then_having
|
1332
|
+
end
|
1303
1333
|
|
1304
1334
|
# Find any limit via our expression.
|
1305
1335
|
coerce_tests! %r{relations don't load all records in #inspect}
|
@@ -1309,10 +1339,18 @@ class RelationTest < ActiveRecord::TestCase
|
|
1309
1339
|
end
|
1310
1340
|
end
|
1311
1341
|
|
1312
|
-
#
|
1313
|
-
# However, this pull request on Rails core drops order on exists relation. https://github.com/rails/rails/pull/28699
|
1314
|
-
# so we are skipping all together.
|
1342
|
+
# Order column must be in the GROUP clause.
|
1315
1343
|
coerce_tests! :test_empty_complex_chained_relations
|
1344
|
+
def test_empty_complex_chained_relations_coerced
|
1345
|
+
posts = Post.select("comments_count").where("id is not null").group("author_id", "id").where("legacy_comments_count > 0")
|
1346
|
+
|
1347
|
+
assert_queries(1) { assert_equal false, posts.empty? }
|
1348
|
+
assert_not_predicate posts, :loaded?
|
1349
|
+
|
1350
|
+
no_posts = posts.where(title: "")
|
1351
|
+
assert_queries(1) { assert_equal true, no_posts.empty? }
|
1352
|
+
assert_not_predicate no_posts, :loaded?
|
1353
|
+
end
|
1316
1354
|
|
1317
1355
|
# Can't apply offset without ORDER
|
1318
1356
|
coerce_tests! %r{using a custom table affects the wheres}
|
@@ -2107,6 +2145,17 @@ class FieldOrderedValuesTest < ActiveRecord::TestCase
|
|
2107
2145
|
Book.where(author_id: nil, name: nil).delete_all
|
2108
2146
|
Book.connection.add_index(:books, [:author_id, :name], unique: true)
|
2109
2147
|
end
|
2148
|
+
|
2149
|
+
# Need to remove index as SQL Server considers NULLs on a unique-index to be equal unlike PostgreSQL/MySQL/SQLite.
|
2150
|
+
coerce_tests! :test_in_order_of_with_nil
|
2151
|
+
def test_in_order_of_with_nil_coerced
|
2152
|
+
Book.connection.remove_index(:books, column: [:author_id, :name])
|
2153
|
+
|
2154
|
+
original_test_in_order_of_with_nil
|
2155
|
+
ensure
|
2156
|
+
Book.where(author_id: nil, name: nil).delete_all
|
2157
|
+
Book.connection.add_index(:books, [:author_id, :name], unique: true)
|
2158
|
+
end
|
2110
2159
|
end
|
2111
2160
|
|
2112
2161
|
require "models/dashboard"
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "cases/helper_sqlserver"
|
4
|
+
|
5
|
+
class EnumTestSQLServer < ActiveRecord::TestCase
|
6
|
+
|
7
|
+
# Check that enums are supported for all string types.
|
8
|
+
# For each type we check: cast, serialize, and update by declaration.
|
9
|
+
# We create a custom class for each type to test.
|
10
|
+
%w[char_10 varchar_50 varchar_max text nchar_10 nvarchar_50 nvarchar_max ntext].each do |col_name|
|
11
|
+
describe "support #{col_name} enums" do
|
12
|
+
let(:klass) do
|
13
|
+
Class.new(ActiveRecord::Base) do
|
14
|
+
self.table_name = 'sst_datatypes'
|
15
|
+
|
16
|
+
enum col_name => { alpha: "A", beta: "B" }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
it "type.cast" do
|
21
|
+
type = klass.type_for_attribute(col_name)
|
22
|
+
|
23
|
+
assert_equal "alpha", type.cast('A')
|
24
|
+
assert_equal "beta", type.cast('B')
|
25
|
+
end
|
26
|
+
|
27
|
+
it "type.serialize" do
|
28
|
+
type = klass.type_for_attribute(col_name)
|
29
|
+
|
30
|
+
assert_equal 'A', type.serialize('A')
|
31
|
+
assert_equal 'B', type.serialize('B')
|
32
|
+
|
33
|
+
assert_equal 'A', type.serialize(:alpha)
|
34
|
+
assert_equal 'B', type.serialize(:beta)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "update by declaration" do
|
38
|
+
r = klass.new
|
39
|
+
|
40
|
+
r.alpha!
|
41
|
+
assert_predicate r, :alpha?
|
42
|
+
|
43
|
+
r.beta!
|
44
|
+
assert_not_predicate r, :alpha?
|
45
|
+
assert_predicate r, :beta?
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -115,4 +115,22 @@ class MigrationTestSQLServer < ActiveRecord::TestCase
|
|
115
115
|
refute_includes schemas, { "name" => "some schema" }
|
116
116
|
end
|
117
117
|
end
|
118
|
+
|
119
|
+
describe 'creating stored procedure' do
|
120
|
+
it 'stored procedure contains inserts are created successfully' do
|
121
|
+
sql = <<-SQL
|
122
|
+
CREATE OR ALTER PROCEDURE do_some_task
|
123
|
+
AS
|
124
|
+
IF NOT EXISTS(SELECT * FROM sys.objects WHERE type = 'U' AND name = 'SomeTableName')
|
125
|
+
BEGIN
|
126
|
+
CREATE TABLE SomeTableName (SomeNum int PRIMARY KEY CLUSTERED);
|
127
|
+
INSERT INTO SomeTableName(SomeNum) VALUES(1);
|
128
|
+
END
|
129
|
+
SQL
|
130
|
+
|
131
|
+
assert_nothing_raised { connection.execute(sql) }
|
132
|
+
ensure
|
133
|
+
connection.execute("DROP PROCEDURE IF EXISTS dbo.do_some_task;")
|
134
|
+
end
|
135
|
+
end
|
118
136
|
end
|
@@ -10,122 +10,130 @@ class SchemaDumperTestSQLServer < ActiveRecord::TestCase
|
|
10
10
|
|
11
11
|
it "sst_datatypes" do
|
12
12
|
generate_schema_for_table "sst_datatypes"
|
13
|
-
|
14
|
-
assert_line :
|
15
|
-
assert_line :
|
16
|
-
assert_line :
|
17
|
-
assert_line :
|
18
|
-
assert_line :
|
19
|
-
assert_line :
|
20
|
-
assert_line :
|
21
|
-
assert_line :
|
22
|
-
assert_line :
|
13
|
+
|
14
|
+
assert_line :bigint, type: "bigint", default: 42
|
15
|
+
assert_line :int, type: "integer", default: 42
|
16
|
+
assert_line :smallint, type: "integer", limit: 2, default: 42
|
17
|
+
assert_line :tinyint, type: "integer", limit: 1, default: 42
|
18
|
+
assert_line :bit, type: "boolean", default: true
|
19
|
+
assert_line :decimal_9_2, type: "decimal", precision: 9, scale: 2, default: 12345.01
|
20
|
+
assert_line :numeric_18_0, type: "decimal", precision: 18, default: 191
|
21
|
+
assert_line :numeric_36_2, type: "decimal", precision: 36, scale: 2, default: 12345678901234567890.01
|
22
|
+
assert_line :money, type: "money", precision: 19, scale: 4, default: 4.2
|
23
|
+
assert_line :smallmoney, type: "smallmoney", precision: 10, scale: 4, default: 4.2
|
23
24
|
# Approximate Numerics
|
24
|
-
assert_line :float, type: "float",
|
25
|
-
assert_line :real, type: "real",
|
25
|
+
assert_line :float, type: "float", default: 123.00000001
|
26
|
+
assert_line :real, type: "real", default: 123.45
|
26
27
|
# Date and Time
|
27
|
-
assert_line :date, type: "date",
|
28
|
-
assert_line :datetime, type: "datetime",
|
28
|
+
assert_line :date, type: "date", default: "01-01-0001"
|
29
|
+
assert_line :datetime, type: "datetime", precision: nil, default: "01-01-1753 00:00:00.123"
|
29
30
|
if connection_dblib_73?
|
30
|
-
assert_line :datetime2_7,
|
31
|
-
assert_line :datetime2_3,
|
32
|
-
assert_line :datetime2_1,
|
31
|
+
assert_line :datetime2_7, type: "datetime", precision: 7, default: "12-31-9999 23:59:59.9999999"
|
32
|
+
assert_line :datetime2_3, type: "datetime", precision: 3
|
33
|
+
assert_line :datetime2_1, type: "datetime", precision: 1
|
33
34
|
end
|
34
|
-
assert_line :smalldatetime,
|
35
|
+
assert_line :smalldatetime, type: "smalldatetime", default: "01-01-1901 15:45:00.0"
|
35
36
|
if connection_dblib_73?
|
36
|
-
assert_line :time_7,
|
37
|
-
assert_line :time_2,
|
38
|
-
assert_line :time_default,
|
37
|
+
assert_line :time_7, type: "time", precision: 7, default: "04:20:00.2883215"
|
38
|
+
assert_line :time_2, type: "time", precision: 2
|
39
|
+
assert_line :time_default, type: "time", precision: 7, default: "15:03:42.0621978"
|
39
40
|
end
|
40
41
|
# Character Strings
|
41
|
-
assert_line :char_10, type: "char",
|
42
|
-
assert_line :varchar_50, type: "varchar",
|
43
|
-
assert_line :varchar_max, type: "varchar_max",
|
44
|
-
assert_line :text, type: "text_basic",
|
42
|
+
assert_line :char_10, type: "char", limit: 10, default: "1234567890"
|
43
|
+
assert_line :varchar_50, type: "varchar", limit: 50, default: "test varchar_50"
|
44
|
+
assert_line :varchar_max, type: "varchar_max", default: "test varchar_max"
|
45
|
+
assert_line :text, type: "text_basic", default: "test text"
|
45
46
|
# Unicode Character Strings
|
46
|
-
assert_line :nchar_10, type: "nchar",
|
47
|
-
assert_line :nvarchar_50, type: "string",
|
48
|
-
assert_line :nvarchar_max, type: "text",
|
49
|
-
assert_line :ntext, type: "ntext",
|
47
|
+
assert_line :nchar_10, type: "nchar", limit: 10, default: "12345678åå"
|
48
|
+
assert_line :nvarchar_50, type: "string", limit: 50, default: "test nvarchar_50 åå"
|
49
|
+
assert_line :nvarchar_max, type: "text", default: "test nvarchar_max åå"
|
50
|
+
assert_line :ntext, type: "ntext", default: "test ntext åå"
|
50
51
|
# Binary Strings
|
51
|
-
assert_line :binary_49, type: "binary_basic",
|
52
|
-
assert_line :varbinary_49, type: "varbinary",
|
53
|
-
assert_line :varbinary_max, type: "binary"
|
52
|
+
assert_line :binary_49, type: "binary_basic", limit: 49
|
53
|
+
assert_line :varbinary_49, type: "varbinary", limit: 49
|
54
|
+
assert_line :varbinary_max, type: "binary"
|
54
55
|
# Other Data Types
|
55
|
-
assert_line :uniqueidentifier, type: "uuid",
|
56
|
-
assert_line :timestamp, type: "ss_timestamp"
|
56
|
+
assert_line :uniqueidentifier, type: "uuid", default: -> { "newid()" }
|
57
|
+
assert_line :timestamp, type: "ss_timestamp"
|
57
58
|
end
|
58
59
|
|
59
60
|
it "sst_datatypes_migration" do
|
60
61
|
columns = SSTestDatatypeMigration.columns_hash
|
61
62
|
generate_schema_for_table "sst_datatypes_migration"
|
63
|
+
|
62
64
|
# Simple Rails conventions
|
63
|
-
_(columns["integer_col"].sql_type).must_equal
|
64
|
-
_(columns["bigint_col"].sql_type).must_equal
|
65
|
-
_(columns["boolean_col"].sql_type).must_equal
|
66
|
-
_(columns["decimal_col"].sql_type).must_equal
|
67
|
-
_(columns["float_col"].sql_type).must_equal
|
68
|
-
_(columns["string_col"].sql_type).must_equal
|
69
|
-
_(columns["text_col"].sql_type).must_equal
|
70
|
-
_(columns["
|
71
|
-
_(columns["
|
72
|
-
_(columns["
|
73
|
-
_(columns["
|
74
|
-
_(columns["
|
75
|
-
|
76
|
-
|
77
|
-
assert_line :
|
78
|
-
assert_line :
|
79
|
-
assert_line :
|
80
|
-
assert_line :
|
81
|
-
assert_line :
|
82
|
-
assert_line :
|
83
|
-
assert_line :
|
84
|
-
assert_line :
|
85
|
-
assert_line :
|
86
|
-
assert_line :
|
65
|
+
_(columns["integer_col"].sql_type).must_equal "int(4)"
|
66
|
+
_(columns["bigint_col"].sql_type).must_equal "bigint(8)"
|
67
|
+
_(columns["boolean_col"].sql_type).must_equal "bit"
|
68
|
+
_(columns["decimal_col"].sql_type).must_equal "decimal(18,0)"
|
69
|
+
_(columns["float_col"].sql_type).must_equal "float"
|
70
|
+
_(columns["string_col"].sql_type).must_equal "nvarchar(4000)"
|
71
|
+
_(columns["text_col"].sql_type).must_equal "nvarchar(max)"
|
72
|
+
_(columns["datetime_nil_precision_col"].sql_type).must_equal "datetime"
|
73
|
+
_(columns["datetime_col"].sql_type).must_equal "datetime2(6)"
|
74
|
+
_(columns["timestamp_col"].sql_type).must_equal "datetime2(6)"
|
75
|
+
_(columns["time_col"].sql_type).must_equal "time(7)"
|
76
|
+
_(columns["date_col"].sql_type).must_equal "date"
|
77
|
+
_(columns["binary_col"].sql_type).must_equal "varbinary(max)"
|
78
|
+
|
79
|
+
assert_line :integer_col, type: "integer"
|
80
|
+
assert_line :bigint_col, type: "bigint"
|
81
|
+
assert_line :boolean_col, type: "boolean"
|
82
|
+
assert_line :decimal_col, type: "decimal", precision: 18
|
83
|
+
assert_line :float_col, type: "float"
|
84
|
+
assert_line :string_col, type: "string"
|
85
|
+
assert_line :text_col, type: "text"
|
86
|
+
assert_line :datetime_nil_precision_col, type: "datetime", precision: nil
|
87
|
+
assert_line :datetime_col, type: "datetime"
|
88
|
+
assert_line :datetime_col, type: "datetime"
|
89
|
+
assert_line :timestamp_col, type: "datetime"
|
90
|
+
assert_line :time_col, type: "time", precision: 7
|
91
|
+
assert_line :date_col, type: "date"
|
92
|
+
assert_line :binary_col, type: "binary"
|
93
|
+
|
87
94
|
# Our type methods.
|
88
|
-
_(columns["real_col"].sql_type).must_equal
|
89
|
-
_(columns["money_col"].sql_type).must_equal
|
95
|
+
_(columns["real_col"].sql_type).must_equal "real"
|
96
|
+
_(columns["money_col"].sql_type).must_equal "money"
|
90
97
|
_(columns["smalldatetime_col"].sql_type).must_equal "smalldatetime"
|
91
|
-
_(columns["datetime2_col"].sql_type).must_equal
|
92
|
-
_(columns["datetimeoffset"].sql_type).must_equal
|
93
|
-
_(columns["smallmoney_col"].sql_type).must_equal
|
94
|
-
_(columns["char_col"].sql_type).must_equal
|
95
|
-
_(columns["varchar_col"].sql_type).must_equal
|
96
|
-
_(columns["text_basic_col"].sql_type).must_equal
|
97
|
-
_(columns["nchar_col"].sql_type).must_equal
|
98
|
-
_(columns["ntext_col"].sql_type).must_equal
|
99
|
-
_(columns["binary_basic_col"].sql_type).must_equal
|
100
|
-
_(columns["varbinary_col"].sql_type).must_equal
|
101
|
-
_(columns["uuid_col"].sql_type).must_equal
|
102
|
-
_(columns["sstimestamp_col"].sql_type).must_equal
|
103
|
-
_(columns["json_col"].sql_type).must_equal
|
104
|
-
|
105
|
-
assert_line :
|
106
|
-
assert_line :
|
107
|
-
assert_line :
|
108
|
-
assert_line :
|
109
|
-
assert_line :
|
110
|
-
assert_line :
|
111
|
-
assert_line :
|
112
|
-
assert_line :
|
113
|
-
assert_line :
|
114
|
-
assert_line :
|
115
|
-
assert_line :
|
116
|
-
assert_line :
|
117
|
-
assert_line :
|
118
|
-
assert_line :
|
119
|
-
assert_line :
|
98
|
+
_(columns["datetime2_col"].sql_type).must_equal "datetime2(7)"
|
99
|
+
_(columns["datetimeoffset"].sql_type).must_equal "datetimeoffset(7)"
|
100
|
+
_(columns["smallmoney_col"].sql_type).must_equal "smallmoney"
|
101
|
+
_(columns["char_col"].sql_type).must_equal "char(1)"
|
102
|
+
_(columns["varchar_col"].sql_type).must_equal "varchar(8000)"
|
103
|
+
_(columns["text_basic_col"].sql_type).must_equal "text"
|
104
|
+
_(columns["nchar_col"].sql_type).must_equal "nchar(1)"
|
105
|
+
_(columns["ntext_col"].sql_type).must_equal "ntext"
|
106
|
+
_(columns["binary_basic_col"].sql_type).must_equal "binary(1)"
|
107
|
+
_(columns["varbinary_col"].sql_type).must_equal "varbinary(8000)"
|
108
|
+
_(columns["uuid_col"].sql_type).must_equal "uniqueidentifier"
|
109
|
+
_(columns["sstimestamp_col"].sql_type).must_equal "timestamp"
|
110
|
+
_(columns["json_col"].sql_type).must_equal "nvarchar(max)"
|
111
|
+
|
112
|
+
assert_line :real_col, type: "real"
|
113
|
+
assert_line :money_col, type: "money", precision: 19, scale: 4
|
114
|
+
assert_line :smalldatetime_col, type: "smalldatetime"
|
115
|
+
assert_line :datetime2_col, type: "datetime", precision: 7
|
116
|
+
assert_line :datetimeoffset, type: "datetimeoffset", precision: 7
|
117
|
+
assert_line :smallmoney_col, type: "smallmoney", precision: 10, scale: 4
|
118
|
+
assert_line :char_col, type: "char", limit: 1
|
119
|
+
assert_line :varchar_col, type: "varchar"
|
120
|
+
assert_line :text_basic_col, type: "text_basic"
|
121
|
+
assert_line :nchar_col, type: "nchar", limit: 1
|
122
|
+
assert_line :ntext_col, type: "ntext"
|
123
|
+
assert_line :binary_basic_col, type: "binary_basic", limit: 1
|
124
|
+
assert_line :varbinary_col, type: "varbinary"
|
125
|
+
assert_line :uuid_col, type: "uuid"
|
126
|
+
assert_line :sstimestamp_col, type: "ss_timestamp", null: false
|
127
|
+
assert_line :json_col, type: "text"
|
120
128
|
end
|
121
129
|
|
122
130
|
it "dump column collation" do
|
123
131
|
generate_schema_for_table('sst_string_collation')
|
124
132
|
|
125
|
-
assert_line :string_without_collation, type: "string"
|
126
|
-
assert_line :string_default_collation, type: "varchar"
|
127
|
-
assert_line :string_with_collation,
|
128
|
-
assert_line :varchar_with_collation,
|
133
|
+
assert_line :string_without_collation, type: "string"
|
134
|
+
assert_line :string_default_collation, type: "varchar"
|
135
|
+
assert_line :string_with_collation, type: "varchar", collation: "SQL_Latin1_General_CP1_CS_AS"
|
136
|
+
assert_line :varchar_with_collation, type: "varchar", collation: "SQL_Latin1_General_CP1_CS_AS"
|
129
137
|
end
|
130
138
|
|
131
139
|
# Special Cases
|
@@ -140,8 +148,9 @@ class SchemaDumperTestSQLServer < ActiveRecord::TestCase
|
|
140
148
|
|
141
149
|
it "no id with model driven primary key" do
|
142
150
|
output = generate_schema_for_table "sst_no_pk_data"
|
151
|
+
|
143
152
|
_(output).must_match %r{create_table "sst_no_pk_data".*id:\sfalse.*do}
|
144
|
-
assert_line :name, type: "string"
|
153
|
+
assert_line :name, type: "string"
|
145
154
|
end
|
146
155
|
|
147
156
|
it "dumps field with unique key constraints only once" do
|
@@ -154,6 +163,7 @@ class SchemaDumperTestSQLServer < ActiveRecord::TestCase
|
|
154
163
|
|
155
164
|
def generate_schema_for_table(*table_names)
|
156
165
|
require "stringio"
|
166
|
+
|
157
167
|
stream = StringIO.new
|
158
168
|
ActiveRecord::SchemaDumper.ignore_tables = all_tables - table_names
|
159
169
|
ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
|
@@ -173,15 +183,19 @@ class SchemaDumperTestSQLServer < ActiveRecord::TestCase
|
|
173
183
|
@schema_lines[column_name.to_s]
|
174
184
|
end
|
175
185
|
|
176
|
-
def assert_line(column_name,
|
186
|
+
def assert_line(column_name, expected_options = {})
|
177
187
|
line = line(column_name)
|
178
188
|
assert line, "Could not find line with column name: #{column_name.inspect} in schema:\n#{schema}"
|
179
189
|
|
180
|
-
|
181
|
-
|
190
|
+
# Check that the expected and actual option keys.
|
191
|
+
expected_options_keys = expected_options.keys
|
192
|
+
expected_options_keys.delete(:type)
|
193
|
+
_(expected_options_keys.sort).must_equal (line.options.keys.sort), "For column '#{column_name}' expected schema options and actual schema options do not match."
|
182
194
|
|
195
|
+
# Check the expected and actual option values.
|
196
|
+
expected_options.each do |key, expected|
|
183
197
|
actual = key == :type ? line.send(:type_method) : line.send(key)
|
184
|
-
|
198
|
+
|
185
199
|
message = "#{key.to_s.titleize} of #{expected.inspect} not found in:\n#{line}"
|
186
200
|
|
187
201
|
if expected.nil?
|
@@ -207,7 +221,13 @@ class SchemaDumperTestSQLServer < ActiveRecord::TestCase
|
|
207
221
|
:options
|
208
222
|
|
209
223
|
def self.option(method_name)
|
210
|
-
define_method(method_name)
|
224
|
+
define_method(method_name) do
|
225
|
+
if options.key?(method_name.to_sym)
|
226
|
+
options[method_name.to_sym]
|
227
|
+
else
|
228
|
+
throw "Schema line does include the '#{method_name}' option!"
|
229
|
+
end
|
230
|
+
end
|
211
231
|
end
|
212
232
|
|
213
233
|
def initialize(line)
|
@@ -220,6 +240,7 @@ class SchemaDumperTestSQLServer < ActiveRecord::TestCase
|
|
220
240
|
option :scale
|
221
241
|
option :default
|
222
242
|
option :collation
|
243
|
+
option :null
|
223
244
|
|
224
245
|
def to_s
|
225
246
|
line.squish
|
@@ -234,6 +255,7 @@ class SchemaDumperTestSQLServer < ActiveRecord::TestCase
|
|
234
255
|
def parse_line
|
235
256
|
_all, type_method, col_name, options = @line.match(LINE_PARSER).to_a
|
236
257
|
options = parse_options(options)
|
258
|
+
|
237
259
|
[type_method, col_name, options]
|
238
260
|
end
|
239
261
|
|
@@ -243,8 +265,6 @@ class SchemaDumperTestSQLServer < ActiveRecord::TestCase
|
|
243
265
|
else
|
244
266
|
{}
|
245
267
|
end
|
246
|
-
rescue SyntaxError
|
247
|
-
{}
|
248
268
|
end
|
249
269
|
end
|
250
270
|
end
|
@@ -47,9 +47,5 @@ class SchemaTestSQLServer < ActiveRecord::TestCase
|
|
47
47
|
assert_equal 255, columns.find { |c| c.name == "n_name" }.limit
|
48
48
|
assert_equal 1000, columns.find { |c| c.name == "n_description" }.limit
|
49
49
|
end
|
50
|
-
|
51
|
-
it "creates new record" do
|
52
|
-
Alien.create!(name: 'Trisolarans')
|
53
|
-
end
|
54
50
|
end
|
55
51
|
end
|
@@ -77,7 +77,7 @@ class UtilsTestSQLServer < ActiveRecord::TestCase
|
|
77
77
|
_(extract_identifiers(" ").object).must_be_nil
|
78
78
|
end
|
79
79
|
|
80
|
-
it "has a #quoted that returns a fully quoted name with all identifiers as
|
80
|
+
it "has a #quoted that returns a fully quoted name with all identifiers as originally passed in" do
|
81
81
|
_(extract_identifiers("object").quoted).must_equal "[object]"
|
82
82
|
_(extract_identifiers("server.database..object").quoted).must_equal "[server].[database]..[object]"
|
83
83
|
_(extract_identifiers("[server]...[object]").quoted).must_equal "[server]...[object]"
|
@@ -92,7 +92,7 @@ class UtilsTestSQLServer < ActiveRecord::TestCase
|
|
92
92
|
_(extract_identifiers("[obj.name].[foo]").quoted).must_equal "[obj.name].[foo]"
|
93
93
|
end
|
94
94
|
|
95
|
-
it "should indicate if a name is fully
|
95
|
+
it "should indicate if a name is fully qualified" do
|
96
96
|
_(extract_identifiers("object").fully_qualified?).must_equal false
|
97
97
|
_(extract_identifiers("schema.object").fully_qualified?).must_equal false
|
98
98
|
_(extract_identifiers("database.schema.object").fully_qualified?).must_equal false
|
@@ -14,8 +14,9 @@ ActiveRecord::Schema.define do
|
|
14
14
|
t.float :float_col
|
15
15
|
t.string :string_col
|
16
16
|
t.text :text_col
|
17
|
-
t.datetime :
|
18
|
-
t.
|
17
|
+
t.datetime :datetime_nil_precision_col, precision: nil
|
18
|
+
t.datetime :datetime_col # Precision defaults to 6
|
19
|
+
t.timestamp :timestamp_col # Precision defaults to 6
|
19
20
|
t.time :time_col
|
20
21
|
t.date :date_col
|
21
22
|
t.binary :binary_col
|
@@ -316,6 +317,7 @@ ActiveRecord::Schema.define do
|
|
316
317
|
execute "IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'aliens' and TABLE_SCHEMA = 'test') DROP TABLE test.aliens"
|
317
318
|
execute <<-TABLE_IN_OTHER_SCHEMA_USED_BY_MODEL
|
318
319
|
CREATE TABLE test.aliens(
|
320
|
+
id int IDENTITY NOT NULL primary key,
|
319
321
|
name varchar(255)
|
320
322
|
)
|
321
323
|
TABLE_IN_OTHER_SCHEMA_USED_BY_MODEL
|
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: 7.0.
|
4
|
+
version: 7.0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ken Collins
|
@@ -11,10 +11,11 @@ authors:
|
|
11
11
|
- Shawn Balestracci
|
12
12
|
- Joe Rafaniello
|
13
13
|
- Tom Ward
|
14
|
+
- Aidan Haran
|
14
15
|
autorequire:
|
15
16
|
bindir: bin
|
16
17
|
cert_chain: []
|
17
|
-
date: 2023-
|
18
|
+
date: 2023-09-19 00:00:00.000000000 Z
|
18
19
|
dependencies:
|
19
20
|
- !ruby/object:Gem::Dependency
|
20
21
|
name: activerecord
|
@@ -152,6 +153,7 @@ files:
|
|
152
153
|
- test/cases/dbconsole.rb
|
153
154
|
- test/cases/disconnected_test_sqlserver.rb
|
154
155
|
- test/cases/eager_load_too_many_ids_test_sqlserver.rb
|
156
|
+
- test/cases/enum_test_sqlserver.rb
|
155
157
|
- test/cases/execute_procedure_test_sqlserver.rb
|
156
158
|
- test/cases/fetch_test_sqlserver.rb
|
157
159
|
- test/cases/fully_qualified_identifier_test_sqlserver.rb
|
@@ -228,8 +230,8 @@ licenses:
|
|
228
230
|
- MIT
|
229
231
|
metadata:
|
230
232
|
bug_tracker_uri: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/issues
|
231
|
-
changelog_uri: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/blob/v7.0.
|
232
|
-
source_code_uri: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/v7.0.
|
233
|
+
changelog_uri: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/blob/v7.0.4.0/CHANGELOG.md
|
234
|
+
source_code_uri: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/v7.0.4.0
|
233
235
|
post_install_message:
|
234
236
|
rdoc_options: []
|
235
237
|
require_paths:
|
@@ -245,7 +247,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
245
247
|
- !ruby/object:Gem::Version
|
246
248
|
version: '0'
|
247
249
|
requirements: []
|
248
|
-
rubygems_version: 3.
|
250
|
+
rubygems_version: 3.4.10
|
249
251
|
signing_key:
|
250
252
|
specification_version: 4
|
251
253
|
summary: ActiveRecord SQL Server Adapter.
|
@@ -265,6 +267,7 @@ test_files:
|
|
265
267
|
- test/cases/dbconsole.rb
|
266
268
|
- test/cases/disconnected_test_sqlserver.rb
|
267
269
|
- test/cases/eager_load_too_many_ids_test_sqlserver.rb
|
270
|
+
- test/cases/enum_test_sqlserver.rb
|
268
271
|
- test/cases/execute_procedure_test_sqlserver.rb
|
269
272
|
- test/cases/fetch_test_sqlserver.rb
|
270
273
|
- test/cases/fully_qualified_identifier_test_sqlserver.rb
|