activerecord-sqlserver-adapter 5.2.0 → 6.0.1
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/.gitignore +1 -0
- data/.rubocop.yml +29 -0
- data/.travis.yml +6 -8
- data/CHANGELOG.md +46 -11
- data/{Dockerfile → Dockerfile.ci} +2 -2
- data/Gemfile +48 -41
- data/Guardfile +9 -8
- data/README.md +9 -37
- 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 +24 -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 +3 -4
- data/lib/active_record/connection_adapters/sqlserver/core_ext/calculations.rb +22 -2
- data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +3 -3
- 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 +44 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/preloader.rb +36 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/query_methods.rb +28 -0
- data/lib/active_record/connection_adapters/sqlserver/database_limits.rb +9 -0
- data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +88 -44
- data/lib/active_record/connection_adapters/sqlserver/database_tasks.rb +10 -12
- data/lib/active_record/connection_adapters/sqlserver/errors.rb +2 -3
- data/lib/active_record/connection_adapters/sqlserver/quoting.rb +46 -8
- data/lib/active_record/connection_adapters/sqlserver/schema_creation.rb +16 -5
- data/lib/active_record/connection_adapters/sqlserver/schema_dumper.rb +9 -7
- data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +197 -165
- data/lib/active_record/connection_adapters/sqlserver/showplan.rb +8 -8
- 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/sql_type_metadata.rb +2 -2
- data/lib/active_record/connection_adapters/sqlserver/table_definition.rb +43 -44
- data/lib/active_record/connection_adapters/sqlserver/transaction.rb +7 -9
- data/lib/active_record/connection_adapters/sqlserver/type.rb +37 -35
- 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 +2 -2
- data/lib/active_record/connection_adapters/sqlserver/type/date.rb +4 -3
- 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/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/utils.rb +10 -11
- data/lib/active_record/connection_adapters/sqlserver/version.rb +2 -2
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +132 -92
- data/lib/active_record/connection_adapters/sqlserver_column.rb +9 -5
- data/lib/active_record/sqlserver_base.rb +9 -1
- data/lib/active_record/tasks/sqlserver_database_tasks.rb +28 -32
- data/lib/activerecord-sqlserver-adapter.rb +3 -1
- data/lib/arel/visitors/sqlserver.rb +58 -24
- data/lib/arel_sqlserver.rb +4 -2
- data/test/appveyor/dbsetup.ps1 +4 -4
- data/test/cases/adapter_test_sqlserver.rb +223 -180
- data/test/cases/change_column_null_test_sqlserver.rb +17 -15
- data/test/cases/coerced_tests.rb +654 -360
- data/test/cases/column_test_sqlserver.rb +635 -604
- data/test/cases/connection_test_sqlserver.rb +18 -21
- data/test/cases/execute_procedure_test_sqlserver.rb +20 -20
- data/test/cases/fetch_test_sqlserver.rb +17 -23
- data/test/cases/fully_qualified_identifier_test_sqlserver.rb +15 -19
- data/test/cases/helper_sqlserver.rb +20 -15
- data/test/cases/in_clause_test_sqlserver.rb +36 -0
- data/test/cases/index_test_sqlserver.rb +15 -15
- data/test/cases/json_test_sqlserver.rb +25 -25
- data/test/cases/migration_test_sqlserver.rb +30 -26
- data/test/cases/order_test_sqlserver.rb +53 -54
- data/test/cases/pessimistic_locking_test_sqlserver.rb +31 -37
- data/test/cases/rake_test_sqlserver.rb +44 -56
- data/test/cases/schema_dumper_test_sqlserver.rb +117 -112
- 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 +32 -39
- data/test/cases/specific_schema_test_sqlserver.rb +75 -72
- data/test/cases/transaction_test_sqlserver.rb +27 -29
- data/test/cases/trigger_test_sqlserver.rb +18 -17
- data/test/cases/utils_test_sqlserver.rb +78 -78
- data/test/cases/uuid_test_sqlserver.rb +19 -20
- data/test/debug.rb +8 -6
- 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/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/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/datatypes/2012.sql +1 -0
- data/test/schema/sqlserver_specific_schema.rb +31 -21
- data/test/support/coerceable_test_sqlserver.rb +15 -9
- 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/minitest_sqlserver.rb +3 -1
- data/test/support/paths_sqlserver.rb +11 -11
- data/test/support/rake_helpers.rb +13 -10
- data/test/support/sql_counter_sqlserver.rb +3 -4
- data/test/support/test_in_memory_oltp.rb +9 -7
- metadata +23 -13
- data/BACKERS.md +0 -32
- data/circle.yml +0 -38
|
@@ -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 Timestamp < Binary
|
|
6
|
-
|
|
7
8
|
def type
|
|
8
9
|
:ss_timestamp
|
|
9
10
|
end
|
|
10
11
|
|
|
11
12
|
def sqlserver_type
|
|
12
|
-
|
|
13
|
+
"timestamp"
|
|
13
14
|
end
|
|
14
|
-
|
|
15
15
|
end
|
|
16
16
|
end
|
|
17
17
|
end
|
|
@@ -1,11 +1,12 @@
|
|
|
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 TinyInteger < Integer
|
|
6
|
-
|
|
7
8
|
def sqlserver_type
|
|
8
|
-
|
|
9
|
+
"tinyint"
|
|
9
10
|
end
|
|
10
11
|
|
|
11
12
|
private
|
|
@@ -17,7 +18,6 @@ module ActiveRecord
|
|
|
17
18
|
def min_value
|
|
18
19
|
0
|
|
19
20
|
end
|
|
20
|
-
|
|
21
21
|
end
|
|
22
22
|
end
|
|
23
23
|
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 UnicodeChar < UnicodeString
|
|
6
|
-
|
|
7
8
|
def type
|
|
8
9
|
:nchar
|
|
9
10
|
end
|
|
10
11
|
|
|
11
12
|
def sqlserver_type
|
|
12
|
-
|
|
13
|
-
type
|
|
13
|
+
"nchar".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,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 UnicodeText < UnicodeVarcharMax
|
|
6
|
-
|
|
7
8
|
def type
|
|
8
9
|
:ntext
|
|
9
10
|
end
|
|
10
11
|
|
|
11
12
|
def sqlserver_type
|
|
12
|
-
|
|
13
|
+
"ntext"
|
|
13
14
|
end
|
|
14
|
-
|
|
15
15
|
end
|
|
16
16
|
end
|
|
17
17
|
end
|
|
@@ -1,10 +1,11 @@
|
|
|
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 UnicodeVarchar < UnicodeChar
|
|
6
|
-
|
|
7
|
-
def initialize(*args)
|
|
8
|
+
def initialize(**args)
|
|
8
9
|
super
|
|
9
10
|
@limit = 4000 if @limit.to_i == 0
|
|
10
11
|
end
|
|
@@ -14,11 +15,11 @@ module ActiveRecord
|
|
|
14
15
|
end
|
|
15
16
|
|
|
16
17
|
def sqlserver_type
|
|
17
|
-
|
|
18
|
-
type
|
|
18
|
+
"nvarchar".yield_self do |type|
|
|
19
|
+
type += "(#{limit})" if limit
|
|
20
|
+
type
|
|
19
21
|
end
|
|
20
22
|
end
|
|
21
|
-
|
|
22
23
|
end
|
|
23
24
|
end
|
|
24
25
|
end
|
|
@@ -1,10 +1,11 @@
|
|
|
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 UnicodeVarcharMax < UnicodeVarchar
|
|
6
|
-
|
|
7
|
-
def initialize(*args)
|
|
8
|
+
def initialize(**args)
|
|
8
9
|
super
|
|
9
10
|
@limit = 2_147_483_647
|
|
10
11
|
end
|
|
@@ -14,9 +15,8 @@ module ActiveRecord
|
|
|
14
15
|
end
|
|
15
16
|
|
|
16
17
|
def sqlserver_type
|
|
17
|
-
|
|
18
|
+
"nvarchar(max)"
|
|
18
19
|
end
|
|
19
|
-
|
|
20
20
|
end
|
|
21
21
|
end
|
|
22
22
|
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 Uuid < String
|
|
6
|
-
|
|
7
8
|
ACCEPTABLE_UUID = %r{\A\{?([a-fA-F0-9]{4}-?){8}\}?\z}x
|
|
8
9
|
|
|
9
10
|
alias_method :serialize, :deserialize
|
|
@@ -13,11 +14,12 @@ module ActiveRecord
|
|
|
13
14
|
end
|
|
14
15
|
|
|
15
16
|
def sqlserver_type
|
|
16
|
-
|
|
17
|
+
"uniqueidentifier"
|
|
17
18
|
end
|
|
18
19
|
|
|
19
20
|
def serialize(value)
|
|
20
21
|
return unless value
|
|
22
|
+
|
|
21
23
|
Data.new super, self
|
|
22
24
|
end
|
|
23
25
|
|
|
@@ -28,7 +30,6 @@ module ActiveRecord
|
|
|
28
30
|
def quoted(value)
|
|
29
31
|
Utils.quote_string_single(value) if value
|
|
30
32
|
end
|
|
31
|
-
|
|
32
33
|
end
|
|
33
34
|
end
|
|
34
35
|
end
|
|
@@ -1,10 +1,11 @@
|
|
|
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 Varbinary < Binary
|
|
6
|
-
|
|
7
|
-
def initialize(*args)
|
|
8
|
+
def initialize(**args)
|
|
8
9
|
super
|
|
9
10
|
@limit = 8000 if @limit.to_i == 0
|
|
10
11
|
end
|
|
@@ -14,11 +15,11 @@ module ActiveRecord
|
|
|
14
15
|
end
|
|
15
16
|
|
|
16
17
|
def sqlserver_type
|
|
17
|
-
|
|
18
|
-
type
|
|
18
|
+
"varbinary".yield_self do |type|
|
|
19
|
+
type += "(#{limit})" if limit
|
|
20
|
+
type
|
|
19
21
|
end
|
|
20
22
|
end
|
|
21
|
-
|
|
22
23
|
end
|
|
23
24
|
end
|
|
24
25
|
end
|
|
@@ -1,10 +1,11 @@
|
|
|
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 VarbinaryMax < Varbinary
|
|
6
|
-
|
|
7
|
-
def initialize(*args)
|
|
8
|
+
def initialize(**args)
|
|
8
9
|
super
|
|
9
10
|
@limit = 2_147_483_647
|
|
10
11
|
end
|
|
@@ -14,9 +15,8 @@ module ActiveRecord
|
|
|
14
15
|
end
|
|
15
16
|
|
|
16
17
|
def sqlserver_type
|
|
17
|
-
|
|
18
|
+
"varbinary(max)"
|
|
18
19
|
end
|
|
19
|
-
|
|
20
20
|
end
|
|
21
21
|
end
|
|
22
22
|
end
|
|
@@ -1,10 +1,11 @@
|
|
|
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 Varchar < Char
|
|
6
|
-
|
|
7
|
-
def initialize(*args)
|
|
8
|
+
def initialize(**args)
|
|
8
9
|
super
|
|
9
10
|
@limit = 8000 if @limit.to_i == 0
|
|
10
11
|
end
|
|
@@ -14,11 +15,11 @@ module ActiveRecord
|
|
|
14
15
|
end
|
|
15
16
|
|
|
16
17
|
def sqlserver_type
|
|
17
|
-
|
|
18
|
-
type
|
|
18
|
+
"varchar".yield_self do |type|
|
|
19
|
+
type += "(#{limit})" if limit
|
|
20
|
+
type
|
|
19
21
|
end
|
|
20
22
|
end
|
|
21
|
-
|
|
22
23
|
end
|
|
23
24
|
end
|
|
24
25
|
end
|
|
@@ -1,10 +1,11 @@
|
|
|
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 VarcharMax < Varchar
|
|
6
|
-
|
|
7
|
-
def initialize(*args)
|
|
8
|
+
def initialize(**args)
|
|
8
9
|
super
|
|
9
10
|
@limit = 2_147_483_647
|
|
10
11
|
end
|
|
@@ -14,9 +15,8 @@ module ActiveRecord
|
|
|
14
15
|
end
|
|
15
16
|
|
|
16
17
|
def sqlserver_type
|
|
17
|
-
|
|
18
|
+
"varchar(max)"
|
|
18
19
|
end
|
|
19
|
-
|
|
20
20
|
end
|
|
21
21
|
end
|
|
22
22
|
end
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "strscan"
|
|
2
4
|
|
|
3
5
|
module ActiveRecord
|
|
4
6
|
module ConnectionAdapters
|
|
5
7
|
module SQLServer
|
|
6
8
|
module Utils
|
|
7
|
-
|
|
8
|
-
QUOTED_STRING_PREFIX = 'N'
|
|
9
|
+
QUOTED_STRING_PREFIX = "N"
|
|
9
10
|
|
|
10
11
|
# Value object to return identifiers from SQL Server names http://bit.ly/1CZ3EiL
|
|
11
12
|
# Inspiried from Rails PostgreSQL::Name adapter object in their own Utils.
|
|
12
13
|
#
|
|
13
14
|
class Name
|
|
14
|
-
|
|
15
15
|
SEPARATOR = "."
|
|
16
16
|
UNQUOTED_SCANNER = /\]?\./
|
|
17
17
|
QUOTED_SCANNER = /\A\[.*?\]\./
|
|
@@ -54,15 +54,15 @@ module ActiveRecord
|
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
def quoted
|
|
57
|
-
parts.map{ |p| quote(p) if p }.join SEPARATOR
|
|
57
|
+
parts.map { |p| quote(p) if p }.join SEPARATOR
|
|
58
58
|
end
|
|
59
59
|
|
|
60
60
|
def quoted_raw
|
|
61
61
|
quote @raw_name
|
|
62
62
|
end
|
|
63
63
|
|
|
64
|
-
def ==(
|
|
65
|
-
|
|
64
|
+
def ==(other)
|
|
65
|
+
other.class == self.class && other.parts == parts
|
|
66
66
|
end
|
|
67
67
|
alias_method :eql?, :==
|
|
68
68
|
|
|
@@ -75,6 +75,7 @@ module ActiveRecord
|
|
|
75
75
|
def parse_raw_name
|
|
76
76
|
@parts = []
|
|
77
77
|
return if raw_name.blank?
|
|
78
|
+
|
|
78
79
|
scanner = StringScanner.new(raw_name)
|
|
79
80
|
matched = scanner.exist?(QUOTED_CHECKER) ? scanner.scan_until(QUOTED_SCANNER) : scanner.scan_until(UNQUOTED_SCANNER)
|
|
80
81
|
while matched
|
|
@@ -91,7 +92,7 @@ module ActiveRecord
|
|
|
91
92
|
@schema = @parts.first
|
|
92
93
|
end
|
|
93
94
|
rest = scanner.rest
|
|
94
|
-
rest = rest.starts_with?(
|
|
95
|
+
rest = rest.starts_with?(".") ? rest[1..-1] : rest[0..-1]
|
|
95
96
|
@object = unquote(rest)
|
|
96
97
|
@parts << @object
|
|
97
98
|
end
|
|
@@ -101,7 +102,7 @@ module ActiveRecord
|
|
|
101
102
|
end
|
|
102
103
|
|
|
103
104
|
def unquote(part)
|
|
104
|
-
if part && part.start_with?(
|
|
105
|
+
if part && part.start_with?("[")
|
|
105
106
|
part[1..-2]
|
|
106
107
|
else
|
|
107
108
|
part
|
|
@@ -111,7 +112,6 @@ module ActiveRecord
|
|
|
111
112
|
def parts
|
|
112
113
|
@parts
|
|
113
114
|
end
|
|
114
|
-
|
|
115
115
|
end
|
|
116
116
|
|
|
117
117
|
extend self
|
|
@@ -139,7 +139,6 @@ module ActiveRecord
|
|
|
139
139
|
def extract_identifiers(name)
|
|
140
140
|
SQLServer::Utils::Name.new(name)
|
|
141
141
|
end
|
|
142
|
-
|
|
143
142
|
end
|
|
144
143
|
end
|
|
145
144
|
end
|
|
@@ -1,35 +1,39 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
require
|
|
4
|
-
require
|
|
5
|
-
require
|
|
6
|
-
require
|
|
7
|
-
require
|
|
8
|
-
require
|
|
9
|
-
require
|
|
10
|
-
require
|
|
11
|
-
require
|
|
12
|
-
require
|
|
13
|
-
require
|
|
14
|
-
require
|
|
15
|
-
require
|
|
16
|
-
require
|
|
17
|
-
require
|
|
18
|
-
require
|
|
19
|
-
require
|
|
20
|
-
require
|
|
21
|
-
require
|
|
22
|
-
require
|
|
23
|
-
require
|
|
24
|
-
require
|
|
25
|
-
require
|
|
26
|
-
require
|
|
27
|
-
require
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "base64"
|
|
4
|
+
require "active_record"
|
|
5
|
+
require "arel_sqlserver"
|
|
6
|
+
require "active_record/connection_adapters/abstract_adapter"
|
|
7
|
+
require "active_record/connection_adapters/sqlserver/core_ext/active_record"
|
|
8
|
+
require "active_record/connection_adapters/sqlserver/core_ext/calculations"
|
|
9
|
+
require "active_record/connection_adapters/sqlserver/core_ext/explain"
|
|
10
|
+
require "active_record/connection_adapters/sqlserver/core_ext/explain_subscriber"
|
|
11
|
+
require "active_record/connection_adapters/sqlserver/core_ext/attribute_methods"
|
|
12
|
+
require "active_record/connection_adapters/sqlserver/core_ext/finder_methods"
|
|
13
|
+
require "active_record/connection_adapters/sqlserver/core_ext/query_methods"
|
|
14
|
+
require "active_record/connection_adapters/sqlserver/core_ext/preloader"
|
|
15
|
+
require "active_record/connection_adapters/sqlserver/version"
|
|
16
|
+
require "active_record/connection_adapters/sqlserver/type"
|
|
17
|
+
require "active_record/connection_adapters/sqlserver/database_limits"
|
|
18
|
+
require "active_record/connection_adapters/sqlserver/database_statements"
|
|
19
|
+
require "active_record/connection_adapters/sqlserver/database_tasks"
|
|
20
|
+
require "active_record/connection_adapters/sqlserver/transaction"
|
|
21
|
+
require "active_record/connection_adapters/sqlserver/errors"
|
|
22
|
+
require "active_record/connection_adapters/sqlserver/schema_creation"
|
|
23
|
+
require "active_record/connection_adapters/sqlserver/schema_dumper"
|
|
24
|
+
require "active_record/connection_adapters/sqlserver/schema_statements"
|
|
25
|
+
require "active_record/connection_adapters/sqlserver/sql_type_metadata"
|
|
26
|
+
require "active_record/connection_adapters/sqlserver/showplan"
|
|
27
|
+
require "active_record/connection_adapters/sqlserver/table_definition"
|
|
28
|
+
require "active_record/connection_adapters/sqlserver/quoting"
|
|
29
|
+
require "active_record/connection_adapters/sqlserver/utils"
|
|
30
|
+
require "active_record/sqlserver_base"
|
|
31
|
+
require "active_record/connection_adapters/sqlserver_column"
|
|
32
|
+
require "active_record/tasks/sqlserver_database_tasks"
|
|
28
33
|
|
|
29
34
|
module ActiveRecord
|
|
30
35
|
module ConnectionAdapters
|
|
31
36
|
class SQLServerAdapter < AbstractAdapter
|
|
32
|
-
|
|
33
37
|
include SQLServer::Version,
|
|
34
38
|
SQLServer::Quoting,
|
|
35
39
|
SQLServer::DatabaseStatements,
|
|
@@ -38,7 +42,10 @@ module ActiveRecord
|
|
|
38
42
|
SQLServer::DatabaseLimits,
|
|
39
43
|
SQLServer::DatabaseTasks
|
|
40
44
|
|
|
41
|
-
ADAPTER_NAME =
|
|
45
|
+
ADAPTER_NAME = "SQLServer".freeze
|
|
46
|
+
|
|
47
|
+
# Default precision for 'time' (See https://docs.microsoft.com/en-us/sql/t-sql/data-types/time-transact-sql)
|
|
48
|
+
DEFAULT_TIME_PRECISION = 7
|
|
42
49
|
|
|
43
50
|
attr_reader :spid
|
|
44
51
|
|
|
@@ -48,7 +55,7 @@ module ActiveRecord
|
|
|
48
55
|
cattr_accessor :showplan_option, instance_accessor: false
|
|
49
56
|
cattr_accessor :lowercase_schema_reflection
|
|
50
57
|
|
|
51
|
-
self.cs_equality_operator =
|
|
58
|
+
self.cs_equality_operator = "COLLATE Latin1_General_CS_AS_WS"
|
|
52
59
|
self.use_output_inserted = true
|
|
53
60
|
self.exclude_output_inserted_table_names = Concurrent::Map.new { false }
|
|
54
61
|
|
|
@@ -75,6 +82,12 @@ module ActiveRecord
|
|
|
75
82
|
SQLServer::SchemaCreation.new self
|
|
76
83
|
end
|
|
77
84
|
|
|
85
|
+
def self.database_exists?(config)
|
|
86
|
+
!!ActiveRecord::Base.sqlserver_connection(config)
|
|
87
|
+
rescue ActiveRecord::NoDatabaseError
|
|
88
|
+
false
|
|
89
|
+
end
|
|
90
|
+
|
|
78
91
|
def supports_ddl_transactions?
|
|
79
92
|
true
|
|
80
93
|
end
|
|
@@ -139,10 +152,30 @@ module ActiveRecord
|
|
|
139
152
|
true
|
|
140
153
|
end
|
|
141
154
|
|
|
155
|
+
def supports_lazy_transactions?
|
|
156
|
+
true
|
|
157
|
+
end
|
|
158
|
+
|
|
142
159
|
def supports_in_memory_oltp?
|
|
143
160
|
@version_year >= 2014
|
|
144
161
|
end
|
|
145
162
|
|
|
163
|
+
def supports_insert_returning?
|
|
164
|
+
true
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def supports_insert_on_duplicate_skip?
|
|
168
|
+
false
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def supports_insert_on_duplicate_update?
|
|
172
|
+
false
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def supports_insert_conflict_target?
|
|
176
|
+
false
|
|
177
|
+
end
|
|
178
|
+
|
|
146
179
|
def disable_referential_integrity
|
|
147
180
|
tables = tables_with_referential_integrity
|
|
148
181
|
tables.each { |t| do_execute "ALTER TABLE #{quote_table_name(t)} NOCHECK CONSTRAINT ALL" }
|
|
@@ -155,7 +188,8 @@ module ActiveRecord
|
|
|
155
188
|
|
|
156
189
|
def active?
|
|
157
190
|
return false unless @connection
|
|
158
|
-
|
|
191
|
+
|
|
192
|
+
raw_connection_do "SELECT 1"
|
|
159
193
|
true
|
|
160
194
|
rescue *connection_errors
|
|
161
195
|
false
|
|
@@ -185,13 +219,13 @@ module ActiveRecord
|
|
|
185
219
|
|
|
186
220
|
def reset!
|
|
187
221
|
reset_transaction
|
|
188
|
-
do_execute
|
|
222
|
+
do_execute "IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION"
|
|
189
223
|
end
|
|
190
224
|
|
|
191
225
|
# === Abstract Adapter (Misc Support) =========================== #
|
|
192
226
|
|
|
193
227
|
def tables_with_referential_integrity
|
|
194
|
-
schemas_and_tables = select_rows
|
|
228
|
+
schemas_and_tables = select_rows <<~SQL.squish
|
|
195
229
|
SELECT DISTINCT s.name, o.name
|
|
196
230
|
FROM sys.foreign_keys i
|
|
197
231
|
INNER JOIN sys.objects o ON i.parent_object_id = o.OBJECT_ID
|
|
@@ -220,6 +254,7 @@ module ActiveRecord
|
|
|
220
254
|
|
|
221
255
|
def database_prefix_remote_server?
|
|
222
256
|
return false if database_prefix.blank?
|
|
257
|
+
|
|
223
258
|
name = SQLServer::Utils.extract_identifiers(database_prefix)
|
|
224
259
|
name.fully_qualified? && name.object.blank?
|
|
225
260
|
end
|
|
@@ -251,37 +286,40 @@ module ActiveRecord
|
|
|
251
286
|
result
|
|
252
287
|
end
|
|
253
288
|
|
|
289
|
+
def get_database_version # :nodoc:
|
|
290
|
+
version_year
|
|
291
|
+
end
|
|
254
292
|
|
|
255
293
|
protected
|
|
256
294
|
|
|
257
295
|
# === Abstract Adapter (Misc Support) =========================== #
|
|
258
296
|
|
|
259
297
|
def initialize_type_map(m = type_map)
|
|
260
|
-
m.register_type %r{.*},
|
|
298
|
+
m.register_type %r{.*}, SQLServer::Type::UnicodeString.new
|
|
261
299
|
# Exact Numerics
|
|
262
|
-
register_class_with_limit m,
|
|
263
|
-
m.alias_type
|
|
264
|
-
register_class_with_limit m,
|
|
265
|
-
m.alias_type
|
|
266
|
-
m.alias_type
|
|
267
|
-
register_class_with_limit m,
|
|
268
|
-
m.alias_type
|
|
269
|
-
register_class_with_limit m,
|
|
270
|
-
m.alias_type
|
|
271
|
-
m.register_type
|
|
300
|
+
register_class_with_limit m, "bigint(8)", SQLServer::Type::BigInteger
|
|
301
|
+
m.alias_type "bigint", "bigint(8)"
|
|
302
|
+
register_class_with_limit m, "int(4)", SQLServer::Type::Integer
|
|
303
|
+
m.alias_type "integer", "int(4)"
|
|
304
|
+
m.alias_type "int", "int(4)"
|
|
305
|
+
register_class_with_limit m, "smallint(2)", SQLServer::Type::SmallInteger
|
|
306
|
+
m.alias_type "smallint", "smallint(2)"
|
|
307
|
+
register_class_with_limit m, "tinyint(1)", SQLServer::Type::TinyInteger
|
|
308
|
+
m.alias_type "tinyint", "tinyint(1)"
|
|
309
|
+
m.register_type "bit", SQLServer::Type::Boolean.new
|
|
272
310
|
m.register_type %r{\Adecimal}i do |sql_type|
|
|
273
311
|
scale = extract_scale(sql_type)
|
|
274
312
|
precision = extract_precision(sql_type)
|
|
275
313
|
SQLServer::Type::Decimal.new precision: precision, scale: scale
|
|
276
314
|
end
|
|
277
|
-
m.alias_type %r{\Anumeric}i,
|
|
278
|
-
m.register_type
|
|
279
|
-
m.register_type
|
|
315
|
+
m.alias_type %r{\Anumeric}i, "decimal"
|
|
316
|
+
m.register_type "money", SQLServer::Type::Money.new
|
|
317
|
+
m.register_type "smallmoney", SQLServer::Type::SmallMoney.new
|
|
280
318
|
# Approximate Numerics
|
|
281
|
-
m.register_type
|
|
282
|
-
m.register_type
|
|
319
|
+
m.register_type "float", SQLServer::Type::Float.new
|
|
320
|
+
m.register_type "real", SQLServer::Type::Real.new
|
|
283
321
|
# Date and Time
|
|
284
|
-
m.register_type
|
|
322
|
+
m.register_type "date", SQLServer::Type::Date.new
|
|
285
323
|
m.register_type %r{\Adatetime} do |sql_type|
|
|
286
324
|
precision = extract_precision(sql_type)
|
|
287
325
|
if precision
|
|
@@ -290,49 +328,50 @@ module ActiveRecord
|
|
|
290
328
|
SQLServer::Type::DateTime.new
|
|
291
329
|
end
|
|
292
330
|
end
|
|
293
|
-
m.register_type
|
|
331
|
+
m.register_type %r{\Adatetimeoffset}i do |sql_type|
|
|
294
332
|
precision = extract_precision(sql_type)
|
|
295
333
|
SQLServer::Type::DateTimeOffset.new precision: precision
|
|
296
334
|
end
|
|
297
|
-
m.register_type
|
|
335
|
+
m.register_type "smalldatetime", SQLServer::Type::SmallDateTime.new
|
|
298
336
|
m.register_type %r{\Atime}i do |sql_type|
|
|
299
|
-
|
|
300
|
-
precision = extract_precision(sql_type)
|
|
337
|
+
precision = extract_precision(sql_type) || DEFAULT_TIME_PRECISION
|
|
301
338
|
SQLServer::Type::Time.new precision: precision
|
|
302
339
|
end
|
|
303
340
|
# Character Strings
|
|
304
341
|
register_class_with_limit m, %r{\Achar}i, SQLServer::Type::Char
|
|
305
342
|
register_class_with_limit m, %r{\Avarchar}i, SQLServer::Type::Varchar
|
|
306
|
-
m.register_type
|
|
307
|
-
m.register_type
|
|
343
|
+
m.register_type "varchar(max)", SQLServer::Type::VarcharMax.new
|
|
344
|
+
m.register_type "text", SQLServer::Type::Text.new
|
|
308
345
|
# Unicode Character Strings
|
|
309
346
|
register_class_with_limit m, %r{\Anchar}i, SQLServer::Type::UnicodeChar
|
|
310
347
|
register_class_with_limit m, %r{\Anvarchar}i, SQLServer::Type::UnicodeVarchar
|
|
311
|
-
m.alias_type
|
|
312
|
-
m.register_type
|
|
313
|
-
m.register_type
|
|
314
|
-
m.register_type
|
|
348
|
+
m.alias_type "string", "nvarchar(4000)"
|
|
349
|
+
m.register_type "nvarchar(max)", SQLServer::Type::UnicodeVarcharMax.new
|
|
350
|
+
m.register_type "nvarchar(max)", SQLServer::Type::UnicodeVarcharMax.new
|
|
351
|
+
m.register_type "ntext", SQLServer::Type::UnicodeText.new
|
|
315
352
|
# Binary Strings
|
|
316
353
|
register_class_with_limit m, %r{\Abinary}i, SQLServer::Type::Binary
|
|
317
354
|
register_class_with_limit m, %r{\Avarbinary}i, SQLServer::Type::Varbinary
|
|
318
|
-
m.register_type
|
|
355
|
+
m.register_type "varbinary(max)", SQLServer::Type::VarbinaryMax.new
|
|
319
356
|
# Other Data Types
|
|
320
|
-
m.register_type
|
|
321
|
-
m.register_type
|
|
357
|
+
m.register_type "uniqueidentifier", SQLServer::Type::Uuid.new
|
|
358
|
+
m.register_type "timestamp", SQLServer::Type::Timestamp.new
|
|
322
359
|
end
|
|
323
360
|
|
|
324
|
-
def translate_exception(e, message)
|
|
361
|
+
def translate_exception(e, message:, sql:, binds:)
|
|
325
362
|
case message
|
|
326
363
|
when /(cannot insert duplicate key .* with unique index) | (violation of unique key constraint)/i
|
|
327
|
-
RecordNotUnique.new(message)
|
|
328
|
-
when /conflicted with the foreign key constraint/i
|
|
329
|
-
InvalidForeignKey.new(message)
|
|
364
|
+
RecordNotUnique.new(message, sql: sql, binds: binds)
|
|
365
|
+
when /(conflicted with the foreign key constraint) | (The DELETE statement conflicted with the REFERENCE constraint)/i
|
|
366
|
+
InvalidForeignKey.new(message, sql: sql, binds: binds)
|
|
330
367
|
when /has been chosen as the deadlock victim/i
|
|
331
|
-
DeadlockVictim.new(message)
|
|
368
|
+
DeadlockVictim.new(message, sql: sql, binds: binds)
|
|
332
369
|
when /database .* does not exist/i
|
|
333
|
-
NoDatabaseError.new(message)
|
|
370
|
+
NoDatabaseError.new(message, sql: sql, binds: binds)
|
|
334
371
|
when /data would be truncated/
|
|
335
|
-
ValueTooLong.new(message)
|
|
372
|
+
ValueTooLong.new(message, sql: sql, binds: binds)
|
|
373
|
+
when /connection timed out/
|
|
374
|
+
StatementTimeout.new(message, sql: sql, binds: binds)
|
|
336
375
|
when /Column '(.*)' is not the same data type as referencing column '(.*)' in foreign key/
|
|
337
376
|
pk_id, fk_id = SQLServer::Utils.extract_identifiers($1), SQLServer::Utils.extract_identifiers($2)
|
|
338
377
|
MismatchedForeignKey.new(
|
|
@@ -344,9 +383,9 @@ module ActiveRecord
|
|
|
344
383
|
primary_key: pk_id.object
|
|
345
384
|
)
|
|
346
385
|
when /Cannot insert the value NULL into column.*does not allow nulls/
|
|
347
|
-
NotNullViolation.new(message)
|
|
386
|
+
NotNullViolation.new(message, sql: sql, binds: binds)
|
|
348
387
|
when /Arithmetic overflow error/
|
|
349
|
-
RangeError.new(message)
|
|
388
|
+
RangeError.new(message, sql: sql, binds: binds)
|
|
350
389
|
else
|
|
351
390
|
super
|
|
352
391
|
end
|
|
@@ -360,7 +399,7 @@ module ActiveRecord
|
|
|
360
399
|
when :dblib
|
|
361
400
|
dblib_connect(config)
|
|
362
401
|
end
|
|
363
|
-
@spid = _raw_select(
|
|
402
|
+
@spid = _raw_select("SELECT @@SPID", fetch: :rows).first.first
|
|
364
403
|
@version_year = version_year
|
|
365
404
|
configure_connection
|
|
366
405
|
end
|
|
@@ -379,32 +418,32 @@ module ActiveRecord
|
|
|
379
418
|
username: config[:username],
|
|
380
419
|
password: config[:password],
|
|
381
420
|
database: config[:database],
|
|
382
|
-
tds_version: config[:tds_version] ||
|
|
421
|
+
tds_version: config[:tds_version] || "7.3",
|
|
383
422
|
appname: config_appname(config),
|
|
384
423
|
login_timeout: config_login_timeout(config),
|
|
385
424
|
timeout: config_timeout(config),
|
|
386
|
-
encoding:
|
|
425
|
+
encoding: config_encoding(config),
|
|
387
426
|
azure: config[:azure],
|
|
388
427
|
contained: config[:contained]
|
|
389
428
|
).tap do |client|
|
|
390
429
|
if config[:azure]
|
|
391
|
-
client.execute(
|
|
392
|
-
client.execute(
|
|
393
|
-
client.execute(
|
|
394
|
-
client.execute(
|
|
430
|
+
client.execute("SET ANSI_NULLS ON").do
|
|
431
|
+
client.execute("SET ANSI_NULL_DFLT_ON ON").do
|
|
432
|
+
client.execute("SET ANSI_PADDING ON").do
|
|
433
|
+
client.execute("SET ANSI_WARNINGS ON").do
|
|
395
434
|
else
|
|
396
|
-
client.execute(
|
|
435
|
+
client.execute("SET ANSI_DEFAULTS ON").do
|
|
397
436
|
end
|
|
398
|
-
client.execute(
|
|
399
|
-
client.execute(
|
|
400
|
-
client.execute(
|
|
401
|
-
client.execute(
|
|
402
|
-
client.execute(
|
|
437
|
+
client.execute("SET QUOTED_IDENTIFIER ON").do
|
|
438
|
+
client.execute("SET CURSOR_CLOSE_ON_COMMIT OFF").do
|
|
439
|
+
client.execute("SET IMPLICIT_TRANSACTIONS OFF").do
|
|
440
|
+
client.execute("SET TEXTSIZE 2147483647").do
|
|
441
|
+
client.execute("SET CONCAT_NULL_YIELDS_NULL ON").do
|
|
403
442
|
end
|
|
404
443
|
end
|
|
405
444
|
|
|
406
445
|
def config_appname(config)
|
|
407
|
-
config[:appname] || configure_application_name || Rails.application.class.name.split(
|
|
446
|
+
config[:appname] || configure_application_name || Rails.application.class.name.split("::").first rescue nil
|
|
408
447
|
end
|
|
409
448
|
|
|
410
449
|
def config_login_timeout(config)
|
|
@@ -419,18 +458,18 @@ module ActiveRecord
|
|
|
419
458
|
config[:encoding].present? ? config[:encoding] : nil
|
|
420
459
|
end
|
|
421
460
|
|
|
422
|
-
def configure_connection
|
|
461
|
+
def configure_connection; end
|
|
423
462
|
|
|
424
|
-
def configure_application_name
|
|
463
|
+
def configure_application_name; end
|
|
425
464
|
|
|
426
465
|
def initialize_dateformatter
|
|
427
466
|
@database_dateformat = user_options_dateformat
|
|
428
467
|
a, b, c = @database_dateformat.each_char.to_a
|
|
429
|
-
[a, b, c].each { |f| f.upcase! if f ==
|
|
468
|
+
[a, b, c].each { |f| f.upcase! if f == "y" }
|
|
430
469
|
dateformat = "%#{a}-%#{b}-%#{c}"
|
|
431
470
|
::Date::DATE_FORMATS[:_sqlserver_dateformat] = dateformat
|
|
432
471
|
::Time::DATE_FORMATS[:_sqlserver_dateformat] = dateformat
|
|
433
|
-
::Time::DATE_FORMATS[:_sqlserver_time] =
|
|
472
|
+
::Time::DATE_FORMATS[:_sqlserver_time] = "%H:%M:%S"
|
|
434
473
|
::Time::DATE_FORMATS[:_sqlserver_datetime] = "#{dateformat} %H:%M:%S"
|
|
435
474
|
::Time::DATE_FORMATS[:_sqlserver_datetimeoffset] = lambda { |time|
|
|
436
475
|
time.strftime "#{dateformat} %H:%M:%S.%9N #{time.formatted_offset}"
|
|
@@ -439,13 +478,14 @@ module ActiveRecord
|
|
|
439
478
|
|
|
440
479
|
def version_year
|
|
441
480
|
return 2016 if sqlserver_version =~ /vNext/
|
|
481
|
+
|
|
442
482
|
/SQL Server (\d+)/.match(sqlserver_version).to_a.last.to_s.to_i
|
|
443
|
-
rescue StandardError
|
|
483
|
+
rescue StandardError
|
|
444
484
|
2016
|
|
445
485
|
end
|
|
446
486
|
|
|
447
487
|
def sqlserver_version
|
|
448
|
-
@sqlserver_version ||= _raw_select(
|
|
488
|
+
@sqlserver_version ||= _raw_select("SELECT @@version", fetch: :rows).first.first.to_s
|
|
449
489
|
end
|
|
450
490
|
end
|
|
451
491
|
end
|