activerecord-sqlserver-adapter 6.1.2.0 → 7.0.0.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/.github/workflows/ci.yml +4 -1
- data/CHANGELOG.md +16 -41
- data/Gemfile +1 -0
- data/MIT-LICENSE +1 -1
- data/README.md +18 -9
- data/VERSION +1 -1
- data/activerecord-sqlserver-adapter.gemspec +2 -2
- data/appveyor.yml +4 -6
- data/lib/active_record/connection_adapters/sqlserver/core_ext/preloader.rb +7 -15
- data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +15 -6
- data/lib/active_record/connection_adapters/sqlserver/quoting.rb +2 -4
- data/lib/active_record/connection_adapters/sqlserver/schema_creation.rb +11 -9
- data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +27 -8
- data/lib/active_record/connection_adapters/sqlserver/type/data.rb +3 -1
- data/lib/active_record/connection_adapters/sqlserver/type/date.rb +1 -1
- data/lib/active_record/connection_adapters/sqlserver/type/datetime.rb +1 -1
- data/lib/active_record/connection_adapters/sqlserver/type/time.rb +1 -1
- data/lib/active_record/connection_adapters/sqlserver/utils.rb +16 -1
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +84 -74
- data/lib/arel/visitors/sqlserver.rb +2 -0
- data/test/cases/active_schema_test_sqlserver.rb +55 -0
- data/test/cases/coerced_tests.rb +301 -85
- data/test/cases/column_test_sqlserver.rb +58 -58
- data/test/cases/eager_load_too_many_ids_test_sqlserver.rb +18 -0
- data/test/cases/rake_test_sqlserver.rb +2 -1
- data/test/cases/schema_dumper_test_sqlserver.rb +1 -1
- data/test/migrations/transaction_table/1_table_will_never_be_created.rb +1 -1
- data/test/support/coerceable_test_sqlserver.rb +4 -4
- data/test/support/marshal_compatibility_fixtures/SQLServer/rails_6_1_topic.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/SQLServer/rails_6_1_topic_associations.dump +0 -0
- data/test/support/rake_helpers.rb +3 -1
- metadata +15 -11
- data/test/support/marshal_compatibility_fixtures/SQLServer/rails_6_0_topic.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/SQLServer/rails_6_0_topic_associations.dump +0 -0
|
@@ -105,7 +105,7 @@ module ActiveRecord
|
|
|
105
105
|
end
|
|
106
106
|
|
|
107
107
|
def config_appname(config)
|
|
108
|
-
if
|
|
108
|
+
if instance_methods.include?(:configure_application_name)
|
|
109
109
|
ActiveSupport::Deprecation.warn <<~MSG.squish
|
|
110
110
|
Configuring the application name used by TinyTDS by overriding the
|
|
111
111
|
`ActiveRecord::ConnectionAdapters::SQLServerAdapter#configure_application_name`
|
|
@@ -119,9 +119,9 @@ module ActiveRecord
|
|
|
119
119
|
end
|
|
120
120
|
|
|
121
121
|
def rails_application_name
|
|
122
|
-
return nil if Rails.application.nil?
|
|
123
|
-
|
|
124
122
|
Rails.application.class.name.split("::").first
|
|
123
|
+
rescue
|
|
124
|
+
nil # Might not be in a Rails context so we fallback to `nil`.
|
|
125
125
|
end
|
|
126
126
|
|
|
127
127
|
def config_login_timeout(config)
|
|
@@ -377,83 +377,93 @@ module ActiveRecord
|
|
|
377
377
|
version_year
|
|
378
378
|
end
|
|
379
379
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
380
|
+
class << self
|
|
381
|
+
protected
|
|
382
|
+
|
|
383
|
+
def initialize_type_map(m)
|
|
384
|
+
m.register_type %r{.*}, SQLServer::Type::UnicodeString.new
|
|
385
|
+
|
|
386
|
+
# Exact Numerics
|
|
387
|
+
register_class_with_limit m, "bigint(8)", SQLServer::Type::BigInteger
|
|
388
|
+
m.alias_type "bigint", "bigint(8)"
|
|
389
|
+
register_class_with_limit m, "int(4)", SQLServer::Type::Integer
|
|
390
|
+
m.alias_type "integer", "int(4)"
|
|
391
|
+
m.alias_type "int", "int(4)"
|
|
392
|
+
register_class_with_limit m, "smallint(2)", SQLServer::Type::SmallInteger
|
|
393
|
+
m.alias_type "smallint", "smallint(2)"
|
|
394
|
+
register_class_with_limit m, "tinyint(1)", SQLServer::Type::TinyInteger
|
|
395
|
+
m.alias_type "tinyint", "tinyint(1)"
|
|
396
|
+
m.register_type "bit", SQLServer::Type::Boolean.new
|
|
397
|
+
m.register_type %r{\Adecimal}i do |sql_type|
|
|
398
|
+
scale = extract_scale(sql_type)
|
|
399
|
+
precision = extract_precision(sql_type)
|
|
400
|
+
if scale == 0
|
|
401
|
+
SQLServer::Type::DecimalWithoutScale.new(precision: precision)
|
|
402
|
+
else
|
|
403
|
+
SQLServer::Type::Decimal.new(precision: precision, scale: scale)
|
|
404
|
+
end
|
|
405
405
|
end
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
406
|
+
m.alias_type %r{\Anumeric}i, "decimal"
|
|
407
|
+
m.register_type "money", SQLServer::Type::Money.new
|
|
408
|
+
m.register_type "smallmoney", SQLServer::Type::SmallMoney.new
|
|
409
|
+
|
|
410
|
+
# Approximate Numerics
|
|
411
|
+
m.register_type "float", SQLServer::Type::Float.new
|
|
412
|
+
m.register_type "real", SQLServer::Type::Real.new
|
|
413
|
+
|
|
414
|
+
# Date and Time
|
|
415
|
+
m.register_type "date", SQLServer::Type::Date.new
|
|
416
|
+
m.register_type %r{\Adatetime} do |sql_type|
|
|
417
|
+
precision = extract_precision(sql_type)
|
|
418
|
+
if precision
|
|
419
|
+
SQLServer::Type::DateTime2.new precision: precision
|
|
420
|
+
else
|
|
421
|
+
SQLServer::Type::DateTime.new
|
|
422
|
+
end
|
|
423
423
|
end
|
|
424
|
+
m.register_type %r{\Adatetimeoffset}i do |sql_type|
|
|
425
|
+
precision = extract_precision(sql_type)
|
|
426
|
+
SQLServer::Type::DateTimeOffset.new precision: precision
|
|
427
|
+
end
|
|
428
|
+
m.register_type "smalldatetime", SQLServer::Type::SmallDateTime.new
|
|
429
|
+
m.register_type %r{\Atime}i do |sql_type|
|
|
430
|
+
precision = extract_precision(sql_type) || DEFAULT_TIME_PRECISION
|
|
431
|
+
SQLServer::Type::Time.new precision: precision
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
# Character Strings
|
|
435
|
+
register_class_with_limit m, %r{\Achar}i, SQLServer::Type::Char
|
|
436
|
+
register_class_with_limit m, %r{\Avarchar}i, SQLServer::Type::Varchar
|
|
437
|
+
m.register_type "varchar(max)", SQLServer::Type::VarcharMax.new
|
|
438
|
+
m.register_type "text", SQLServer::Type::Text.new
|
|
439
|
+
|
|
440
|
+
# Unicode Character Strings
|
|
441
|
+
register_class_with_limit m, %r{\Anchar}i, SQLServer::Type::UnicodeChar
|
|
442
|
+
register_class_with_limit m, %r{\Anvarchar}i, SQLServer::Type::UnicodeVarchar
|
|
443
|
+
m.alias_type "string", "nvarchar(4000)"
|
|
444
|
+
m.register_type "nvarchar(max)", SQLServer::Type::UnicodeVarcharMax.new
|
|
445
|
+
m.register_type "nvarchar(max)", SQLServer::Type::UnicodeVarcharMax.new
|
|
446
|
+
m.register_type "ntext", SQLServer::Type::UnicodeText.new
|
|
447
|
+
|
|
448
|
+
# Binary Strings
|
|
449
|
+
register_class_with_limit m, %r{\Abinary}i, SQLServer::Type::Binary
|
|
450
|
+
register_class_with_limit m, %r{\Avarbinary}i, SQLServer::Type::Varbinary
|
|
451
|
+
m.register_type "varbinary(max)", SQLServer::Type::VarbinaryMax.new
|
|
452
|
+
|
|
453
|
+
# Other Data Types
|
|
454
|
+
m.register_type "uniqueidentifier", SQLServer::Type::Uuid.new
|
|
455
|
+
m.register_type "timestamp", SQLServer::Type::Timestamp.new
|
|
424
456
|
end
|
|
425
|
-
|
|
426
|
-
precision = extract_precision(sql_type)
|
|
427
|
-
SQLServer::Type::DateTimeOffset.new precision: precision
|
|
428
|
-
end
|
|
429
|
-
m.register_type "smalldatetime", SQLServer::Type::SmallDateTime.new
|
|
430
|
-
m.register_type %r{\Atime}i do |sql_type|
|
|
431
|
-
precision = extract_precision(sql_type) || DEFAULT_TIME_PRECISION
|
|
432
|
-
SQLServer::Type::Time.new precision: precision
|
|
433
|
-
end
|
|
457
|
+
end
|
|
434
458
|
|
|
435
|
-
|
|
436
|
-
register_class_with_limit m, %r{\Achar}i, SQLServer::Type::Char
|
|
437
|
-
register_class_with_limit m, %r{\Avarchar}i, SQLServer::Type::Varchar
|
|
438
|
-
m.register_type "varchar(max)", SQLServer::Type::VarcharMax.new
|
|
439
|
-
m.register_type "text", SQLServer::Type::Text.new
|
|
459
|
+
TYPE_MAP = Type::TypeMap.new.tap { |m| initialize_type_map(m) }
|
|
440
460
|
|
|
441
|
-
|
|
442
|
-
register_class_with_limit m, %r{\Anchar}i, SQLServer::Type::UnicodeChar
|
|
443
|
-
register_class_with_limit m, %r{\Anvarchar}i, SQLServer::Type::UnicodeVarchar
|
|
444
|
-
m.alias_type "string", "nvarchar(4000)"
|
|
445
|
-
m.register_type "nvarchar(max)", SQLServer::Type::UnicodeVarcharMax.new
|
|
446
|
-
m.register_type "nvarchar(max)", SQLServer::Type::UnicodeVarcharMax.new
|
|
447
|
-
m.register_type "ntext", SQLServer::Type::UnicodeText.new
|
|
461
|
+
protected
|
|
448
462
|
|
|
449
|
-
|
|
450
|
-
register_class_with_limit m, %r{\Abinary}i, SQLServer::Type::Binary
|
|
451
|
-
register_class_with_limit m, %r{\Avarbinary}i, SQLServer::Type::Varbinary
|
|
452
|
-
m.register_type "varbinary(max)", SQLServer::Type::VarbinaryMax.new
|
|
463
|
+
# === Abstract Adapter (Misc Support) =========================== #
|
|
453
464
|
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
m.register_type "timestamp", SQLServer::Type::Timestamp.new
|
|
465
|
+
def type_map
|
|
466
|
+
TYPE_MAP
|
|
457
467
|
end
|
|
458
468
|
|
|
459
469
|
def translate_exception(e, message:, sql:, binds:)
|
|
@@ -467,7 +477,7 @@ module ActiveRecord
|
|
|
467
477
|
when /has been chosen as the deadlock victim/i
|
|
468
478
|
DeadlockVictim.new(message, sql: sql, binds: binds)
|
|
469
479
|
when /database .* does not exist/i
|
|
470
|
-
NoDatabaseError.new(message
|
|
480
|
+
NoDatabaseError.new(message)
|
|
471
481
|
when /data would be truncated/
|
|
472
482
|
ValueTooLong.new(message, sql: sql, binds: binds)
|
|
473
483
|
when /connection timed out/
|
|
@@ -83,6 +83,8 @@ module Arel
|
|
|
83
83
|
# Monkey-patch start. Add query attribute bindings rather than just values.
|
|
84
84
|
column_name = o.column_name
|
|
85
85
|
column_type = o.attribute.relation.type_for_attribute(o.column_name)
|
|
86
|
+
# Use cast_type on encrypted attributes. Don't encrypt them again
|
|
87
|
+
column_type = column_type.cast_type if column_type.is_a?(ActiveRecord::Encryption::EncryptedAttributeType)
|
|
86
88
|
attrs = values.map { |value| ActiveRecord::Relation::QueryAttribute.new(column_name, value, column_type) }
|
|
87
89
|
|
|
88
90
|
collector.add_binds(attrs, &bind_block)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "cases/helper_sqlserver"
|
|
4
|
+
|
|
5
|
+
class ActiveSchemaTestSQLServer < ActiveRecord::TestCase
|
|
6
|
+
before do
|
|
7
|
+
connection.create_table :schema_test_table, force: true, id: false do |t|
|
|
8
|
+
t.column :foo, :string, limit: 100
|
|
9
|
+
t.column :state, :string
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
after do
|
|
14
|
+
connection.drop_table :schema_test_table rescue nil
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it 'default index' do
|
|
18
|
+
assert_sql('CREATE INDEX [index_schema_test_table_on_foo] ON [schema_test_table] ([foo])') do
|
|
19
|
+
connection.add_index :schema_test_table, "foo"
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it 'unique index' do
|
|
24
|
+
assert_sql('CREATE UNIQUE INDEX [index_schema_test_table_on_foo] ON [schema_test_table] ([foo])') do
|
|
25
|
+
connection.add_index :schema_test_table, "foo", unique: true
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it 'where condition on index' do
|
|
30
|
+
assert_sql("CREATE INDEX [index_schema_test_table_on_foo] ON [schema_test_table] ([foo]) WHERE state = 'active'") do
|
|
31
|
+
connection.add_index :schema_test_table, "foo", where: "state = 'active'"
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it 'if index does not exist' do
|
|
36
|
+
assert_sql("IF NOT EXISTS (SELECT name FROM sysindexes WHERE name = 'index_schema_test_table_on_foo') " \
|
|
37
|
+
"CREATE INDEX [index_schema_test_table_on_foo] ON [schema_test_table] ([foo])") do
|
|
38
|
+
connection.add_index :schema_test_table, "foo", if_not_exists: true
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
describe "index types" do
|
|
43
|
+
it 'clustered index' do
|
|
44
|
+
assert_sql('CREATE CLUSTERED INDEX [index_schema_test_table_on_foo] ON [schema_test_table] ([foo])') do
|
|
45
|
+
connection.add_index :schema_test_table, "foo", type: :clustered
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it 'nonclustered index' do
|
|
50
|
+
assert_sql('CREATE NONCLUSTERED INDEX [index_schema_test_table_on_foo] ON [schema_test_table] ([foo])') do
|
|
51
|
+
connection.add_index :schema_test_table, "foo", type: :nonclustered
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|