activerecord-sqlserver-adapter 5.2.1 → 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/.editorconfig +9 -0
- data/.github/issue_template.md +23 -0
- data/.github/workflows/ci.yml +29 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +29 -0
- data/CHANGELOG.md +17 -27
- data/{Dockerfile → Dockerfile.ci} +1 -1
- data/Gemfile +49 -41
- data/Guardfile +9 -8
- data/MIT-LICENSE +1 -1
- data/README.md +65 -42
- data/RUNNING_UNIT_TESTS.md +3 -0
- data/Rakefile +14 -16
- data/VERSION +1 -1
- data/activerecord-sqlserver-adapter.gemspec +25 -14
- data/appveyor.yml +22 -17
- data/docker-compose.ci.yml +7 -5
- data/guides/RELEASING.md +11 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/active_record.rb +2 -4
- data/lib/active_record/connection_adapters/sqlserver/core_ext/attribute_methods.rb +5 -4
- data/lib/active_record/connection_adapters/sqlserver/core_ext/calculations.rb +10 -14
- data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +12 -5
- data/lib/active_record/connection_adapters/sqlserver/core_ext/explain_subscriber.rb +2 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/finder_methods.rb +10 -7
- data/lib/active_record/connection_adapters/sqlserver/core_ext/preloader.rb +30 -0
- data/lib/active_record/connection_adapters/sqlserver/database_limits.rb +9 -4
- data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +117 -52
- data/lib/active_record/connection_adapters/sqlserver/database_tasks.rb +9 -12
- data/lib/active_record/connection_adapters/sqlserver/errors.rb +2 -3
- data/lib/active_record/connection_adapters/sqlserver/quoting.rb +51 -14
- data/lib/active_record/connection_adapters/sqlserver/schema_creation.rb +40 -6
- data/lib/active_record/connection_adapters/sqlserver/schema_dumper.rb +18 -10
- data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +235 -167
- data/lib/active_record/connection_adapters/sqlserver/showplan/printer_table.rb +4 -2
- data/lib/active_record/connection_adapters/sqlserver/showplan/printer_xml.rb +3 -1
- data/lib/active_record/connection_adapters/sqlserver/showplan.rb +8 -8
- data/lib/active_record/connection_adapters/sqlserver/sql_type_metadata.rb +36 -7
- data/lib/active_record/connection_adapters/sqlserver/table_definition.rb +43 -45
- data/lib/active_record/connection_adapters/sqlserver/transaction.rb +8 -10
- data/lib/active_record/connection_adapters/sqlserver/type/big_integer.rb +3 -3
- data/lib/active_record/connection_adapters/sqlserver/type/binary.rb +5 -4
- data/lib/active_record/connection_adapters/sqlserver/type/boolean.rb +3 -3
- data/lib/active_record/connection_adapters/sqlserver/type/char.rb +7 -4
- data/lib/active_record/connection_adapters/sqlserver/type/data.rb +5 -3
- data/lib/active_record/connection_adapters/sqlserver/type/date.rb +7 -5
- data/lib/active_record/connection_adapters/sqlserver/type/datetime.rb +8 -8
- data/lib/active_record/connection_adapters/sqlserver/type/datetime2.rb +2 -2
- data/lib/active_record/connection_adapters/sqlserver/type/datetimeoffset.rb +2 -2
- data/lib/active_record/connection_adapters/sqlserver/type/decimal.rb +5 -4
- data/lib/active_record/connection_adapters/sqlserver/type/decimal_without_scale.rb +22 -0
- data/lib/active_record/connection_adapters/sqlserver/type/float.rb +3 -3
- data/lib/active_record/connection_adapters/sqlserver/type/integer.rb +3 -3
- data/lib/active_record/connection_adapters/sqlserver/type/json.rb +2 -1
- data/lib/active_record/connection_adapters/sqlserver/type/money.rb +4 -4
- data/lib/active_record/connection_adapters/sqlserver/type/real.rb +3 -3
- data/lib/active_record/connection_adapters/sqlserver/type/small_integer.rb +3 -3
- data/lib/active_record/connection_adapters/sqlserver/type/small_money.rb +4 -4
- data/lib/active_record/connection_adapters/sqlserver/type/smalldatetime.rb +3 -3
- data/lib/active_record/connection_adapters/sqlserver/type/string.rb +2 -2
- data/lib/active_record/connection_adapters/sqlserver/type/text.rb +3 -3
- data/lib/active_record/connection_adapters/sqlserver/type/time.rb +6 -6
- data/lib/active_record/connection_adapters/sqlserver/type/time_value_fractional.rb +8 -9
- data/lib/active_record/connection_adapters/sqlserver/type/timestamp.rb +3 -3
- data/lib/active_record/connection_adapters/sqlserver/type/tiny_integer.rb +3 -3
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_char.rb +5 -4
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_string.rb +2 -2
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_text.rb +3 -3
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar.rb +6 -5
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar_max.rb +4 -4
- data/lib/active_record/connection_adapters/sqlserver/type/uuid.rb +4 -3
- data/lib/active_record/connection_adapters/sqlserver/type/varbinary.rb +6 -5
- data/lib/active_record/connection_adapters/sqlserver/type/varbinary_max.rb +4 -4
- data/lib/active_record/connection_adapters/sqlserver/type/varchar.rb +6 -5
- data/lib/active_record/connection_adapters/sqlserver/type/varchar_max.rb +4 -4
- data/lib/active_record/connection_adapters/sqlserver/type.rb +38 -35
- data/lib/active_record/connection_adapters/sqlserver/utils.rb +26 -12
- data/lib/active_record/connection_adapters/sqlserver/version.rb +2 -2
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +271 -180
- data/lib/active_record/connection_adapters/sqlserver_column.rb +76 -16
- data/lib/active_record/sqlserver_base.rb +11 -9
- data/lib/active_record/tasks/sqlserver_database_tasks.rb +38 -39
- data/lib/activerecord-sqlserver-adapter.rb +3 -1
- data/lib/arel/visitors/sqlserver.rb +177 -56
- data/lib/arel_sqlserver.rb +4 -2
- data/test/appveyor/dbsetup.ps1 +4 -4
- data/test/cases/active_schema_test_sqlserver.rb +55 -0
- data/test/cases/adapter_test_sqlserver.rb +258 -173
- data/test/cases/change_column_collation_test_sqlserver.rb +33 -0
- data/test/cases/change_column_null_test_sqlserver.rb +14 -12
- data/test/cases/coerced_tests.rb +1421 -397
- data/test/cases/column_test_sqlserver.rb +321 -315
- data/test/cases/connection_test_sqlserver.rb +17 -20
- data/test/cases/disconnected_test_sqlserver.rb +39 -0
- data/test/cases/eager_load_too_many_ids_test_sqlserver.rb +18 -0
- data/test/cases/execute_procedure_test_sqlserver.rb +28 -19
- data/test/cases/fetch_test_sqlserver.rb +33 -21
- data/test/cases/fully_qualified_identifier_test_sqlserver.rb +15 -19
- data/test/cases/helper_sqlserver.rb +15 -15
- data/test/cases/in_clause_test_sqlserver.rb +63 -0
- data/test/cases/index_test_sqlserver.rb +15 -15
- data/test/cases/json_test_sqlserver.rb +25 -25
- data/test/cases/lateral_test_sqlserver.rb +35 -0
- data/test/cases/migration_test_sqlserver.rb +74 -27
- data/test/cases/optimizer_hints_test_sqlserver.rb +72 -0
- data/test/cases/order_test_sqlserver.rb +59 -53
- data/test/cases/pessimistic_locking_test_sqlserver.rb +27 -33
- data/test/cases/primary_keys_test_sqlserver.rb +103 -0
- data/test/cases/rake_test_sqlserver.rb +70 -45
- data/test/cases/schema_dumper_test_sqlserver.rb +124 -109
- data/test/cases/schema_test_sqlserver.rb +20 -26
- data/test/cases/scratchpad_test_sqlserver.rb +4 -4
- data/test/cases/showplan_test_sqlserver.rb +28 -35
- data/test/cases/specific_schema_test_sqlserver.rb +68 -65
- data/test/cases/transaction_test_sqlserver.rb +18 -20
- data/test/cases/trigger_test_sqlserver.rb +14 -13
- data/test/cases/utils_test_sqlserver.rb +70 -70
- data/test/cases/uuid_test_sqlserver.rb +13 -14
- data/test/debug.rb +8 -6
- data/test/migrations/create_clients_and_change_column_collation.rb +19 -0
- data/test/migrations/create_clients_and_change_column_null.rb +3 -1
- data/test/migrations/transaction_table/1_table_will_never_be_created.rb +4 -4
- data/test/models/sqlserver/booking.rb +3 -1
- data/test/models/sqlserver/composite_pk.rb +9 -0
- data/test/models/sqlserver/customers_view.rb +3 -1
- data/test/models/sqlserver/datatype.rb +2 -0
- data/test/models/sqlserver/datatype_migration.rb +2 -0
- data/test/models/sqlserver/dollar_table_name.rb +3 -1
- data/test/models/sqlserver/edge_schema.rb +3 -3
- data/test/models/sqlserver/fk_has_fk.rb +3 -1
- data/test/models/sqlserver/fk_has_pk.rb +3 -1
- data/test/models/sqlserver/natural_pk_data.rb +4 -2
- data/test/models/sqlserver/natural_pk_int_data.rb +3 -1
- data/test/models/sqlserver/no_pk_data.rb +3 -1
- data/test/models/sqlserver/object_default.rb +3 -1
- data/test/models/sqlserver/quoted_table.rb +4 -2
- data/test/models/sqlserver/quoted_view_1.rb +3 -1
- data/test/models/sqlserver/quoted_view_2.rb +3 -1
- data/test/models/sqlserver/sst_memory.rb +3 -1
- data/test/models/sqlserver/sst_string_collation.rb +3 -0
- data/test/models/sqlserver/string_default.rb +3 -1
- data/test/models/sqlserver/string_defaults_big_view.rb +3 -1
- data/test/models/sqlserver/string_defaults_view.rb +3 -1
- data/test/models/sqlserver/tinyint_pk.rb +3 -1
- data/test/models/sqlserver/trigger.rb +4 -2
- data/test/models/sqlserver/trigger_history.rb +3 -1
- data/test/models/sqlserver/upper.rb +3 -1
- data/test/models/sqlserver/uppered.rb +3 -1
- data/test/models/sqlserver/uuid.rb +3 -1
- data/test/schema/sqlserver_specific_schema.rb +56 -21
- data/test/support/coerceable_test_sqlserver.rb +19 -13
- data/test/support/connection_reflection.rb +3 -2
- data/test/support/core_ext/query_cache.rb +4 -1
- data/test/support/load_schema_sqlserver.rb +5 -5
- 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/minitest_sqlserver.rb +3 -1
- data/test/support/paths_sqlserver.rb +11 -11
- data/test/support/rake_helpers.rb +15 -10
- data/test/support/sql_counter_sqlserver.rb +16 -15
- data/test/support/test_in_memory_oltp.rb +9 -7
- metadata +47 -13
- data/.travis.yml +0 -25
- data/lib/active_record/connection_adapters/sqlserver/core_ext/query_methods.rb +0 -26
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module ActiveRecord
|
|
2
4
|
module ConnectionAdapters
|
|
3
5
|
module SQLServer
|
|
@@ -41,7 +43,7 @@ module ActiveRecord
|
|
|
41
43
|
end
|
|
42
44
|
|
|
43
45
|
def build_separator
|
|
44
|
-
|
|
46
|
+
"+" + @widths.map { |w| "-" * (w + (cell_padding * 2)) }.join("+") + "+"
|
|
45
47
|
end
|
|
46
48
|
|
|
47
49
|
def build_cells(items)
|
|
@@ -54,7 +56,7 @@ module ActiveRecord
|
|
|
54
56
|
|
|
55
57
|
def cast_item(item)
|
|
56
58
|
case item
|
|
57
|
-
when NilClass then
|
|
59
|
+
when NilClass then "NULL"
|
|
58
60
|
when Float then item.to_s.to(9)
|
|
59
61
|
else item.to_s.truncate(max_column_width)
|
|
60
62
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module ActiveRecord
|
|
2
4
|
module ConnectionAdapters
|
|
3
5
|
module SQLServer
|
|
@@ -10,7 +12,7 @@ module ActiveRecord
|
|
|
10
12
|
def pp
|
|
11
13
|
xml = @result.rows.first.first
|
|
12
14
|
if defined?(Nokogiri)
|
|
13
|
-
Nokogiri::XML(xml).to_xml indent: 2, encoding:
|
|
15
|
+
Nokogiri::XML(xml).to_xml indent: 2, encoding: "UTF-8"
|
|
14
16
|
else
|
|
15
17
|
xml
|
|
16
18
|
end
|
|
@@ -1,19 +1,20 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_record/connection_adapters/sqlserver/showplan/printer_table"
|
|
4
|
+
require "active_record/connection_adapters/sqlserver/showplan/printer_xml"
|
|
3
5
|
|
|
4
6
|
module ActiveRecord
|
|
5
7
|
module ConnectionAdapters
|
|
6
8
|
module SQLServer
|
|
7
9
|
module Showplan
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
OPTION_XML = 'SHOWPLAN_XML'
|
|
10
|
+
OPTION_ALL = "SHOWPLAN_ALL"
|
|
11
|
+
OPTION_TEXT = "SHOWPLAN_TEXT"
|
|
12
|
+
OPTION_XML = "SHOWPLAN_XML"
|
|
12
13
|
OPTIONS = [OPTION_ALL, OPTION_TEXT, OPTION_XML]
|
|
13
14
|
|
|
14
15
|
def explain(arel, binds = [])
|
|
15
16
|
sql = to_sql(arel)
|
|
16
|
-
result = with_showplan_on { sp_executesql(sql,
|
|
17
|
+
result = with_showplan_on { sp_executesql(sql, "EXPLAIN", binds) }
|
|
17
18
|
printer = showplan_printer.new(result)
|
|
18
19
|
printer.pp
|
|
19
20
|
end
|
|
@@ -59,7 +60,6 @@ module ActiveRecord
|
|
|
59
60
|
else PrinterTable
|
|
60
61
|
end
|
|
61
62
|
end
|
|
62
|
-
|
|
63
63
|
end
|
|
64
64
|
end
|
|
65
65
|
end
|
|
@@ -1,19 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module ActiveRecord
|
|
2
4
|
module ConnectionAdapters
|
|
3
5
|
module SQLServer
|
|
4
|
-
class
|
|
6
|
+
class TypeMetadata < DelegateClass(SqlTypeMetadata)
|
|
7
|
+
undef to_yaml if method_defined?(:to_yaml)
|
|
8
|
+
|
|
9
|
+
include Deduplicable
|
|
10
|
+
|
|
11
|
+
attr_reader :is_identity, :is_primary, :table_name, :ordinal_position
|
|
5
12
|
|
|
6
|
-
def initialize(
|
|
7
|
-
|
|
8
|
-
|
|
13
|
+
def initialize(type_metadata, is_identity: nil, is_primary: nil, table_name: nil, ordinal_position: nil)
|
|
14
|
+
super(type_metadata)
|
|
15
|
+
@is_identity = is_identity
|
|
16
|
+
@is_primary = is_primary
|
|
17
|
+
@table_name = table_name
|
|
18
|
+
@ordinal_position = ordinal_position
|
|
9
19
|
end
|
|
10
20
|
|
|
11
|
-
|
|
21
|
+
def ==(other)
|
|
22
|
+
other.is_a?(TypeMetadata) &&
|
|
23
|
+
__getobj__ == other.__getobj__ &&
|
|
24
|
+
is_identity == other.is_identity &&
|
|
25
|
+
is_primary == other.is_primary &&
|
|
26
|
+
table_name == other.table_name &&
|
|
27
|
+
ordinal_position == other.ordinal_position
|
|
28
|
+
end
|
|
29
|
+
alias eql? ==
|
|
12
30
|
|
|
13
|
-
def
|
|
14
|
-
|
|
31
|
+
def hash
|
|
32
|
+
TypeMetadata.hash ^
|
|
33
|
+
__getobj__.hash ^
|
|
34
|
+
is_identity.hash ^
|
|
35
|
+
is_primary.hash ^
|
|
36
|
+
table_name.hash ^
|
|
37
|
+
ordinal_position.hash
|
|
15
38
|
end
|
|
16
39
|
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
def deduplicated
|
|
43
|
+
__setobj__(__getobj__.deduplicate)
|
|
44
|
+
super
|
|
45
|
+
end
|
|
17
46
|
end
|
|
18
47
|
end
|
|
19
48
|
end
|
|
@@ -1,101 +1,99 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module ActiveRecord
|
|
2
4
|
module ConnectionAdapters
|
|
3
5
|
module SQLServer
|
|
4
|
-
|
|
5
6
|
module ColumnMethods
|
|
6
|
-
|
|
7
7
|
def primary_key(name, type = :primary_key, **options)
|
|
8
8
|
if [:integer, :bigint].include?(type)
|
|
9
9
|
options[:is_identity] = true unless options.key?(:default)
|
|
10
10
|
elsif type == :uuid
|
|
11
|
-
options[:default] = options.fetch(:default,
|
|
12
|
-
options[:primary_key] = true
|
|
11
|
+
options[:default] = options.fetch(:default, "NEWID()")
|
|
13
12
|
end
|
|
14
13
|
super
|
|
15
14
|
end
|
|
16
15
|
|
|
17
|
-
def primary_key_nonclustered(*
|
|
18
|
-
|
|
16
|
+
def primary_key_nonclustered(*names, **options)
|
|
17
|
+
names.each { |name| column(name, :primary_key_nonclustered, **options) }
|
|
19
18
|
end
|
|
20
19
|
|
|
21
|
-
def real(*
|
|
22
|
-
|
|
20
|
+
def real(*names, **options)
|
|
21
|
+
names.each { |name| column(name, :real, **options) }
|
|
23
22
|
end
|
|
24
23
|
|
|
25
|
-
def money(*
|
|
26
|
-
|
|
24
|
+
def money(*names, **options)
|
|
25
|
+
names.each { |name| column(name, :money, **options) }
|
|
27
26
|
end
|
|
28
27
|
|
|
29
|
-
def smalldatetime(*
|
|
30
|
-
|
|
28
|
+
def smalldatetime(*names, **options)
|
|
29
|
+
names.each { |name| column(name, :smalldatetime, **options) }
|
|
31
30
|
end
|
|
32
31
|
|
|
33
|
-
def datetime(*
|
|
34
|
-
|
|
32
|
+
def datetime(*names, **options)
|
|
33
|
+
names.each do |name|
|
|
35
34
|
if options[:precision]
|
|
36
|
-
datetime2(name, options)
|
|
35
|
+
datetime2(name, **options)
|
|
37
36
|
else
|
|
38
|
-
column(name, :datetime, options)
|
|
37
|
+
column(name, :datetime, **options)
|
|
39
38
|
end
|
|
40
39
|
end
|
|
41
40
|
end
|
|
42
41
|
|
|
43
|
-
def datetime2(*
|
|
44
|
-
|
|
42
|
+
def datetime2(*names, **options)
|
|
43
|
+
names.each { |name| column(name, :datetime2, **options) }
|
|
45
44
|
end
|
|
46
45
|
|
|
47
|
-
def datetimeoffset(*
|
|
48
|
-
|
|
46
|
+
def datetimeoffset(*names, **options)
|
|
47
|
+
names.each { |name| column(name, :datetimeoffset, **options) }
|
|
49
48
|
end
|
|
50
49
|
|
|
51
|
-
def smallmoney(*
|
|
52
|
-
|
|
50
|
+
def smallmoney(*names, **options)
|
|
51
|
+
names.each { |name| column(name, :smallmoney, **options) }
|
|
53
52
|
end
|
|
54
53
|
|
|
55
|
-
def char(*
|
|
56
|
-
|
|
54
|
+
def char(*names, **options)
|
|
55
|
+
names.each { |name| column(name, :char, **options) }
|
|
57
56
|
end
|
|
58
57
|
|
|
59
|
-
def varchar(*
|
|
60
|
-
|
|
58
|
+
def varchar(*names, **options)
|
|
59
|
+
names.each { |name| column(name, :varchar, **options) }
|
|
61
60
|
end
|
|
62
61
|
|
|
63
|
-
def varchar_max(*
|
|
64
|
-
|
|
62
|
+
def varchar_max(*names, **options)
|
|
63
|
+
names.each { |name| column(name, :varchar_max, **options) }
|
|
65
64
|
end
|
|
66
65
|
|
|
67
|
-
def text_basic(*
|
|
68
|
-
|
|
66
|
+
def text_basic(*names, **options)
|
|
67
|
+
names.each { |name| column(name, :text_basic, **options) }
|
|
69
68
|
end
|
|
70
69
|
|
|
71
|
-
def nchar(*
|
|
72
|
-
|
|
70
|
+
def nchar(*names, **options)
|
|
71
|
+
names.each { |name| column(name, :nchar, **options) }
|
|
73
72
|
end
|
|
74
73
|
|
|
75
|
-
def ntext(*
|
|
76
|
-
|
|
74
|
+
def ntext(*names, **options)
|
|
75
|
+
names.each { |name| column(name, :ntext, **options) }
|
|
77
76
|
end
|
|
78
77
|
|
|
79
|
-
def binary_basic(*
|
|
80
|
-
|
|
78
|
+
def binary_basic(*names, **options)
|
|
79
|
+
names.each { |name| column(name, :binary_basic, **options) }
|
|
81
80
|
end
|
|
82
81
|
|
|
83
|
-
def varbinary(*
|
|
84
|
-
|
|
82
|
+
def varbinary(*names, **options)
|
|
83
|
+
names.each { |name| column(name, :varbinary, **options) }
|
|
85
84
|
end
|
|
86
85
|
|
|
87
|
-
def uuid(*
|
|
88
|
-
|
|
86
|
+
def uuid(*names, **options)
|
|
87
|
+
names.each { |name| column(name, :uniqueidentifier, **options) }
|
|
89
88
|
end
|
|
90
89
|
|
|
91
|
-
def ss_timestamp(*
|
|
92
|
-
|
|
90
|
+
def ss_timestamp(*names, **options)
|
|
91
|
+
names.each { |name| column(name, :ss_timestamp, **options) }
|
|
93
92
|
end
|
|
94
93
|
|
|
95
|
-
def json(*
|
|
96
|
-
|
|
94
|
+
def json(*names, **options)
|
|
95
|
+
names.each { |name| column(name, :text, **options) }
|
|
97
96
|
end
|
|
98
|
-
|
|
99
97
|
end
|
|
100
98
|
|
|
101
99
|
class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_record/connection_adapters/abstract/transaction"
|
|
2
4
|
|
|
3
5
|
module ActiveRecord
|
|
4
6
|
module ConnectionAdapters
|
|
5
|
-
|
|
6
7
|
module SQLServerTransaction
|
|
7
|
-
|
|
8
8
|
private
|
|
9
9
|
|
|
10
10
|
def sqlserver?
|
|
@@ -13,28 +13,27 @@ module ActiveRecord
|
|
|
13
13
|
|
|
14
14
|
def current_isolation_level
|
|
15
15
|
return unless sqlserver?
|
|
16
|
+
|
|
16
17
|
level = connection.user_options_isolation_level
|
|
17
18
|
# When READ_COMMITTED_SNAPSHOT is set to ON,
|
|
18
19
|
# user_options_isolation_level will be equal to 'read committed
|
|
19
20
|
# snapshot' which is not a valid isolation level
|
|
20
|
-
if level.blank? || level ==
|
|
21
|
-
|
|
21
|
+
if level.blank? || level == "read committed snapshot"
|
|
22
|
+
"READ COMMITTED"
|
|
22
23
|
else
|
|
23
24
|
level.upcase
|
|
24
25
|
end
|
|
25
26
|
end
|
|
26
|
-
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
Transaction.send :prepend, SQLServerTransaction
|
|
30
30
|
|
|
31
31
|
module SQLServerRealTransaction
|
|
32
|
-
|
|
33
32
|
attr_reader :starting_isolation_level
|
|
34
33
|
|
|
35
|
-
def initialize(connection,
|
|
34
|
+
def initialize(connection, isolation: nil, joinable: true, run_commit_callbacks: false)
|
|
36
35
|
@connection = connection
|
|
37
|
-
@starting_isolation_level = current_isolation_level if
|
|
36
|
+
@starting_isolation_level = current_isolation_level if isolation
|
|
38
37
|
super
|
|
39
38
|
end
|
|
40
39
|
|
|
@@ -55,7 +54,6 @@ module ActiveRecord
|
|
|
55
54
|
connection.set_transaction_isolation_level(starting_isolation_level)
|
|
56
55
|
end
|
|
57
56
|
end
|
|
58
|
-
|
|
59
57
|
end
|
|
60
58
|
|
|
61
59
|
RealTransaction.send :prepend, SQLServerRealTransaction
|
|
@@ -1,19 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module ActiveRecord
|
|
2
4
|
module ConnectionAdapters
|
|
3
5
|
module SQLServer
|
|
4
6
|
module Type
|
|
5
7
|
class Binary < ActiveRecord::Type::Binary
|
|
6
|
-
|
|
7
8
|
def type
|
|
8
9
|
:binary_basic
|
|
9
10
|
end
|
|
10
11
|
|
|
11
12
|
def sqlserver_type
|
|
12
|
-
|
|
13
|
-
type
|
|
13
|
+
"binary".yield_self do |type|
|
|
14
|
+
type += "(#{limit})" if limit
|
|
15
|
+
type
|
|
14
16
|
end
|
|
15
17
|
end
|
|
16
|
-
|
|
17
18
|
end
|
|
18
19
|
end
|
|
19
20
|
end
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module ActiveRecord
|
|
2
4
|
module ConnectionAdapters
|
|
3
5
|
module SQLServer
|
|
4
6
|
module Type
|
|
5
7
|
class Char < String
|
|
6
|
-
|
|
7
8
|
def type
|
|
8
9
|
:char
|
|
9
10
|
end
|
|
@@ -11,20 +12,22 @@ module ActiveRecord
|
|
|
11
12
|
def serialize(value)
|
|
12
13
|
return if value.nil?
|
|
13
14
|
return value if value.is_a?(Data)
|
|
15
|
+
|
|
14
16
|
Data.new super, self
|
|
15
17
|
end
|
|
16
18
|
|
|
17
19
|
def sqlserver_type
|
|
18
|
-
|
|
19
|
-
type
|
|
20
|
+
"char".yield_self do |type|
|
|
21
|
+
type += "(#{limit})" if limit
|
|
22
|
+
type
|
|
20
23
|
end
|
|
21
24
|
end
|
|
22
25
|
|
|
23
26
|
def quoted(value)
|
|
24
27
|
return value.quoted_id if value.respond_to?(:quoted_id)
|
|
28
|
+
|
|
25
29
|
Utils.quote_string_single(value)
|
|
26
30
|
end
|
|
27
|
-
|
|
28
31
|
end
|
|
29
32
|
end
|
|
30
33
|
end
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module ActiveRecord
|
|
2
4
|
module ConnectionAdapters
|
|
3
5
|
module SQLServer
|
|
4
6
|
module Type
|
|
5
7
|
class Data
|
|
6
|
-
|
|
7
8
|
attr_reader :value, :type
|
|
8
9
|
|
|
10
|
+
delegate :sub, to: :value
|
|
11
|
+
|
|
9
12
|
def initialize(value, type)
|
|
10
13
|
@value, @type = value, type
|
|
11
14
|
end
|
|
@@ -24,10 +27,9 @@ module ActiveRecord
|
|
|
24
27
|
end
|
|
25
28
|
|
|
26
29
|
def eql?(other)
|
|
27
|
-
self.class == other.class &&
|
|
30
|
+
self.class == other.class && value == other.value
|
|
28
31
|
end
|
|
29
32
|
alias :== :eql?
|
|
30
|
-
|
|
31
33
|
end
|
|
32
34
|
end
|
|
33
35
|
end
|
|
@@ -1,16 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module ActiveRecord
|
|
2
4
|
module ConnectionAdapters
|
|
3
5
|
module SQLServer
|
|
4
6
|
module Type
|
|
5
7
|
class Date < ActiveRecord::Type::Date
|
|
6
|
-
|
|
7
8
|
def sqlserver_type
|
|
8
|
-
|
|
9
|
+
"date"
|
|
9
10
|
end
|
|
10
11
|
|
|
11
12
|
def serialize(value)
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
value = super
|
|
14
|
+
return value unless value.acts_like?(:date)
|
|
15
|
+
|
|
16
|
+
date = super(value).to_formatted_s(:_sqlserver_dateformat)
|
|
14
17
|
Data.new date, self
|
|
15
18
|
end
|
|
16
19
|
|
|
@@ -37,7 +40,6 @@ module ActiveRecord
|
|
|
37
40
|
def fast_string_to_date_format
|
|
38
41
|
::Date::DATE_FORMATS[:_sqlserver_dateformat]
|
|
39
42
|
end
|
|
40
|
-
|
|
41
43
|
end
|
|
42
44
|
end
|
|
43
45
|
end
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module ActiveRecord
|
|
2
4
|
module ConnectionAdapters
|
|
3
5
|
module SQLServer
|
|
4
6
|
module Type
|
|
5
7
|
class DateTime < ActiveRecord::Type::DateTime
|
|
6
|
-
|
|
7
8
|
include TimeValueFractional
|
|
8
9
|
|
|
9
10
|
def sqlserver_type
|
|
10
|
-
|
|
11
|
+
"datetime"
|
|
11
12
|
end
|
|
12
13
|
|
|
13
14
|
def serialize(value)
|
|
14
15
|
value = super
|
|
15
16
|
return value unless value.acts_like?(:time)
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
end
|
|
17
|
+
|
|
18
|
+
datetime = "#{value.to_formatted_s(:_sqlserver_datetime)}.#{quote_fractional(value)}"
|
|
19
|
+
|
|
20
20
|
Data.new datetime, self
|
|
21
21
|
end
|
|
22
22
|
|
|
@@ -35,7 +35,7 @@ module ActiveRecord
|
|
|
35
35
|
private
|
|
36
36
|
|
|
37
37
|
def fast_string_to_time(string)
|
|
38
|
-
time = ActiveSupport::TimeZone[
|
|
38
|
+
time = ActiveSupport::TimeZone["UTC"].strptime(string, fast_string_to_time_format)
|
|
39
39
|
new_time(time.year, time.month, time.day, time.hour,
|
|
40
40
|
time.min, time.sec, Rational(time.nsec, 1_000))
|
|
41
41
|
rescue ArgumentError
|
|
@@ -43,7 +43,7 @@ module ActiveRecord
|
|
|
43
43
|
end
|
|
44
44
|
|
|
45
45
|
def fast_string_to_time_format
|
|
46
|
-
"#{::Time::DATE_FORMATS[:_sqlserver_datetime]}.%N"
|
|
46
|
+
"#{::Time::DATE_FORMATS[:_sqlserver_datetime]}.%N"
|
|
47
47
|
end
|
|
48
48
|
end
|
|
49
49
|
end
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module ActiveRecord
|
|
2
4
|
module ConnectionAdapters
|
|
3
5
|
module SQLServer
|
|
4
6
|
module Type
|
|
5
7
|
class DateTime2 < DateTime
|
|
6
|
-
|
|
7
8
|
include TimeValueFractional2
|
|
8
9
|
|
|
9
10
|
def sqlserver_type
|
|
10
11
|
"datetime2(#{precision.to_i})"
|
|
11
12
|
end
|
|
12
|
-
|
|
13
13
|
end
|
|
14
14
|
end
|
|
15
15
|
end
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module ActiveRecord
|
|
2
4
|
module ConnectionAdapters
|
|
3
5
|
module SQLServer
|
|
4
6
|
module Type
|
|
5
7
|
class DateTimeOffset < DateTime2
|
|
6
|
-
|
|
7
8
|
def type
|
|
8
9
|
:datetimeoffset
|
|
9
10
|
end
|
|
@@ -15,7 +16,6 @@ module ActiveRecord
|
|
|
15
16
|
def quoted(value)
|
|
16
17
|
Utils.quote_string_single(value)
|
|
17
18
|
end
|
|
18
|
-
|
|
19
19
|
end
|
|
20
20
|
end
|
|
21
21
|
end
|
|
@@ -1,19 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module ActiveRecord
|
|
2
4
|
module ConnectionAdapters
|
|
3
5
|
module SQLServer
|
|
4
6
|
module Type
|
|
5
7
|
class Decimal < ActiveRecord::Type::Decimal
|
|
6
|
-
|
|
7
8
|
def sqlserver_type
|
|
8
|
-
|
|
9
|
-
type
|
|
9
|
+
"decimal".yield_self do |type|
|
|
10
|
+
type += "(#{precision.to_i},#{scale.to_i})" if precision || scale
|
|
11
|
+
type
|
|
10
12
|
end
|
|
11
13
|
end
|
|
12
14
|
|
|
13
15
|
def type_cast_for_schema(value)
|
|
14
16
|
value.is_a?(BigDecimal) ? value.to_s : value.inspect
|
|
15
17
|
end
|
|
16
|
-
|
|
17
18
|
end
|
|
18
19
|
end
|
|
19
20
|
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
module ConnectionAdapters
|
|
5
|
+
module SQLServer
|
|
6
|
+
module Type
|
|
7
|
+
class DecimalWithoutScale < ActiveRecord::Type::DecimalWithoutScale
|
|
8
|
+
def sqlserver_type
|
|
9
|
+
"decimal".yield_self do |type|
|
|
10
|
+
type += "(#{precision.to_i},0)" if precision
|
|
11
|
+
type
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def type_cast_for_schema(value)
|
|
16
|
+
value.is_a?(BigDecimal) ? value.to_s : value.inspect
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module ActiveRecord
|
|
2
4
|
module ConnectionAdapters
|
|
3
5
|
module SQLServer
|
|
4
6
|
module Type
|
|
5
7
|
class Float < ActiveRecord::Type::Float
|
|
6
|
-
|
|
7
8
|
def type
|
|
8
9
|
:float
|
|
9
10
|
end
|
|
10
11
|
|
|
11
12
|
def sqlserver_type
|
|
12
|
-
|
|
13
|
+
"float"
|
|
13
14
|
end
|
|
14
|
-
|
|
15
15
|
end
|
|
16
16
|
end
|
|
17
17
|
end
|