activerecord-sqlserver-adapter 4.1.8 → 4.2.0.pre
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/.gitignore +15 -0
- data/CHANGELOG.md +60 -0
- data/Gemfile +45 -0
- data/Guardfile +29 -0
- data/MIT-LICENSE +5 -5
- data/README.md +193 -0
- data/RUNNING_UNIT_TESTS.md +95 -0
- data/Rakefile +48 -0
- data/activerecord-sqlserver-adapter.gemspec +28 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/active_record.rb +5 -15
- data/lib/active_record/connection_adapters/sqlserver/core_ext/attribute_methods.rb +25 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +6 -4
- data/lib/active_record/connection_adapters/sqlserver/core_ext/odbc.rb +9 -3
- data/lib/active_record/connection_adapters/sqlserver/database_limits.rb +3 -1
- data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +130 -151
- data/lib/active_record/connection_adapters/sqlserver/errors.rb +0 -25
- data/lib/active_record/connection_adapters/sqlserver/quoting.rb +39 -78
- data/lib/active_record/connection_adapters/sqlserver/schema_cache.rb +71 -47
- data/lib/active_record/connection_adapters/sqlserver/schema_creation.rb +14 -30
- data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +112 -108
- data/lib/active_record/connection_adapters/sqlserver/showplan.rb +4 -2
- data/lib/active_record/connection_adapters/sqlserver/showplan/printer_table.rb +1 -1
- data/lib/active_record/connection_adapters/sqlserver/showplan/printer_xml.rb +1 -1
- data/lib/active_record/connection_adapters/sqlserver/table_definition.rb +52 -7
- data/lib/active_record/connection_adapters/sqlserver/transaction.rb +52 -0
- data/lib/active_record/connection_adapters/sqlserver/type.rb +46 -0
- data/lib/active_record/connection_adapters/sqlserver/type/big_integer.rb +15 -0
- data/lib/active_record/connection_adapters/sqlserver/type/binary.rb +15 -0
- data/lib/active_record/connection_adapters/sqlserver/type/boolean.rb +13 -0
- data/lib/active_record/connection_adapters/sqlserver/type/castable.rb +15 -0
- data/lib/active_record/connection_adapters/sqlserver/type/char.rb +15 -0
- data/lib/active_record/connection_adapters/sqlserver/type/core_ext/value.rb +39 -0
- data/lib/active_record/connection_adapters/sqlserver/type/date.rb +14 -0
- data/lib/active_record/connection_adapters/sqlserver/type/datetime.rb +37 -0
- data/lib/active_record/connection_adapters/sqlserver/type/decimal.rb +13 -0
- data/lib/active_record/connection_adapters/sqlserver/type/float.rb +17 -0
- data/lib/active_record/connection_adapters/sqlserver/type/integer.rb +13 -0
- data/lib/active_record/connection_adapters/sqlserver/type/money.rb +21 -0
- data/lib/active_record/connection_adapters/sqlserver/type/quoter.rb +32 -0
- data/lib/active_record/connection_adapters/sqlserver/type/real.rb +17 -0
- data/lib/active_record/connection_adapters/sqlserver/type/small_integer.rb +13 -0
- data/lib/active_record/connection_adapters/sqlserver/type/small_money.rb +21 -0
- data/lib/active_record/connection_adapters/sqlserver/type/smalldatetime.rb +24 -0
- data/lib/active_record/connection_adapters/sqlserver/type/string.rb +12 -0
- data/lib/active_record/connection_adapters/sqlserver/type/text.rb +15 -0
- data/lib/active_record/connection_adapters/sqlserver/type/time.rb +59 -0
- data/lib/active_record/connection_adapters/sqlserver/type/timestamp.rb +15 -0
- data/lib/active_record/connection_adapters/sqlserver/type/tiny_integer.rb +22 -0
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_char.rb +15 -0
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_string.rb +12 -0
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_text.rb +15 -0
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar.rb +20 -0
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar_max.rb +20 -0
- data/lib/active_record/connection_adapters/sqlserver/type/uuid.rb +23 -0
- data/lib/active_record/connection_adapters/sqlserver/type/varbinary.rb +20 -0
- data/lib/active_record/connection_adapters/sqlserver/type/varbinary_max.rb +20 -0
- data/lib/active_record/connection_adapters/sqlserver/type/varchar.rb +20 -0
- data/lib/active_record/connection_adapters/sqlserver/type/varchar_max.rb +20 -0
- data/lib/active_record/connection_adapters/sqlserver/utils.rb +118 -12
- data/lib/active_record/connection_adapters/sqlserver/version.rb +11 -0
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +133 -198
- data/lib/active_record/connection_adapters/sqlserver_column.rb +15 -86
- data/lib/active_record/sqlserver_base.rb +2 -0
- data/lib/arel/visitors/sqlserver.rb +120 -393
- data/lib/{arel/arel_sqlserver.rb → arel_sqlserver.rb} +1 -3
- data/test/cases/adapter_test_sqlserver.rb +420 -0
- data/test/cases/coerced_tests.rb +642 -0
- data/test/cases/column_test_sqlserver.rb +703 -0
- data/test/cases/connection_test_sqlserver.rb +216 -0
- data/test/cases/database_statements_test_sqlserver.rb +57 -0
- data/test/cases/execute_procedure_test_sqlserver.rb +38 -0
- data/test/cases/helper_sqlserver.rb +36 -0
- data/test/cases/migration_test_sqlserver.rb +66 -0
- data/test/cases/order_test_sqlserver.rb +147 -0
- data/test/cases/pessimistic_locking_test_sqlserver.rb +90 -0
- data/test/cases/schema_dumper_test_sqlserver.rb +175 -0
- data/test/cases/schema_test_sqlserver.rb +54 -0
- data/test/cases/scratchpad_test_sqlserver.rb +9 -0
- data/test/cases/showplan_test_sqlserver.rb +65 -0
- data/test/cases/specific_schema_test_sqlserver.rb +118 -0
- data/test/cases/transaction_test_sqlserver.rb +61 -0
- data/test/cases/utils_test_sqlserver.rb +91 -0
- data/test/cases/uuid_test_sqlserver.rb +41 -0
- data/test/config.yml +35 -0
- data/test/fixtures/1px.gif +0 -0
- data/test/migrations/transaction_table/1_table_will_never_be_created.rb +11 -0
- data/test/models/sqlserver/customers_view.rb +3 -0
- data/test/models/sqlserver/datatype.rb +3 -0
- data/test/models/sqlserver/datatype_migration.rb +3 -0
- data/test/models/sqlserver/dollar_table_name.rb +3 -0
- data/test/models/sqlserver/edge_schema.rb +13 -0
- data/test/models/sqlserver/fk_has_fk.rb +3 -0
- data/test/models/sqlserver/fk_has_pk.rb +3 -0
- data/test/models/sqlserver/natural_pk_data.rb +4 -0
- data/test/models/sqlserver/natural_pk_int_data.rb +3 -0
- data/test/models/sqlserver/no_pk_data.rb +3 -0
- data/test/models/sqlserver/quoted_table.rb +7 -0
- data/test/models/sqlserver/quoted_view_1.rb +3 -0
- data/test/models/sqlserver/quoted_view_2.rb +3 -0
- data/test/models/sqlserver/string_default.rb +3 -0
- data/test/models/sqlserver/string_defaults_big_view.rb +3 -0
- data/test/models/sqlserver/string_defaults_view.rb +3 -0
- data/test/models/sqlserver/tinyint_pk.rb +3 -0
- data/test/models/sqlserver/upper.rb +3 -0
- data/test/models/sqlserver/uppered.rb +3 -0
- data/test/models/sqlserver/uuid.rb +3 -0
- data/test/schema/datatypes/2012.sql +64 -0
- data/test/schema/sqlserver_specific_schema.rb +181 -0
- data/test/support/coerceable_test_sqlserver.rb +45 -0
- data/test/support/load_schema_sqlserver.rb +29 -0
- data/test/support/minitest_sqlserver.rb +1 -0
- data/test/support/paths_sqlserver.rb +48 -0
- data/test/support/rake_helpers.rb +41 -0
- data/test/support/sql_counter_sqlserver.rb +32 -0
- metadata +271 -21
- data/CHANGELOG +0 -39
- data/VERSION +0 -1
- data/lib/active_record/connection_adapters/sqlserver/core_ext/relation.rb +0 -17
- data/lib/active_record/sqlserver_test_case.rb +0 -17
- data/lib/arel/nodes_sqlserver.rb +0 -14
- data/lib/arel/select_manager_sqlserver.rb +0 -62
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module ActiveRecord
|
|
2
|
+
module ConnectionAdapters
|
|
3
|
+
module SQLServer
|
|
4
|
+
module Type
|
|
5
|
+
class VarcharMax < Varchar
|
|
6
|
+
|
|
7
|
+
def initialize(options = {})
|
|
8
|
+
super
|
|
9
|
+
@limit = 2_147_483_647
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def type
|
|
13
|
+
:varchar_max
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -1,25 +1,131 @@
|
|
|
1
|
+
require 'strscan'
|
|
2
|
+
|
|
1
3
|
module ActiveRecord
|
|
2
4
|
module ConnectionAdapters
|
|
3
|
-
module
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
module SQLServer
|
|
6
|
+
module Utils
|
|
7
|
+
|
|
8
|
+
# Value object to return identifiers from SQL Server names http://bit.ly/1CZ3EiL
|
|
9
|
+
# Inspiried from Rails PostgreSQL::Name adapter object in their own Utils.
|
|
10
|
+
#
|
|
11
|
+
class Name
|
|
12
|
+
|
|
13
|
+
SEPARATOR = "."
|
|
14
|
+
UNQUOTED_SCANNER = /\]?\./
|
|
15
|
+
QUOTED_SCANNER = /\A\[.*?\]\./
|
|
16
|
+
QUOTED_CHECKER = /\A\[/
|
|
17
|
+
|
|
18
|
+
attr_reader :server, :database, :schema, :object
|
|
19
|
+
attr_reader :raw_name
|
|
20
|
+
|
|
21
|
+
def initialize(name)
|
|
22
|
+
@raw_name = name.to_s
|
|
23
|
+
parse_raw_name
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def object_quoted
|
|
27
|
+
quote object
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def schema_quoted
|
|
31
|
+
schema ? quote(schema) : schema
|
|
8
32
|
end
|
|
9
33
|
|
|
10
|
-
def
|
|
11
|
-
|
|
34
|
+
def database_quoted
|
|
35
|
+
database ? quote(database) : database
|
|
12
36
|
end
|
|
13
37
|
|
|
14
|
-
def
|
|
15
|
-
|
|
38
|
+
def server_quoted
|
|
39
|
+
server ? quote(server) : server
|
|
16
40
|
end
|
|
17
41
|
|
|
18
|
-
def
|
|
19
|
-
|
|
20
|
-
|
|
42
|
+
def to_s
|
|
43
|
+
quoted
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def quoted
|
|
47
|
+
parts.map{ |p| quote(p) if p }.join SEPARATOR
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def ==(o)
|
|
51
|
+
o.class == self.class && o.parts == parts
|
|
52
|
+
end
|
|
53
|
+
alias_method :eql?, :==
|
|
54
|
+
|
|
55
|
+
def hash
|
|
56
|
+
parts.hash
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
protected
|
|
60
|
+
|
|
61
|
+
def parse_raw_name
|
|
62
|
+
@parts = []
|
|
63
|
+
return if raw_name.blank?
|
|
64
|
+
scanner = StringScanner.new(raw_name)
|
|
65
|
+
matched = scanner.exist?(QUOTED_CHECKER) ? scanner.scan_until(QUOTED_SCANNER) : scanner.scan_until(UNQUOTED_SCANNER)
|
|
66
|
+
while matched
|
|
67
|
+
part = matched[0..-2]
|
|
68
|
+
@parts << (part.blank? ? nil : unquote(part))
|
|
69
|
+
matched = scanner.exist?(QUOTED_CHECKER) ? scanner.scan_until(QUOTED_SCANNER) : scanner.scan_until(UNQUOTED_SCANNER)
|
|
70
|
+
end
|
|
71
|
+
case @parts.length
|
|
72
|
+
when 3
|
|
73
|
+
@server, @database, @schema = @parts
|
|
74
|
+
when 2
|
|
75
|
+
@database, @schema = @parts
|
|
76
|
+
when 1
|
|
77
|
+
@schema = @parts.first
|
|
78
|
+
end
|
|
79
|
+
rest = scanner.rest
|
|
80
|
+
rest = rest.starts_with?('.') ? rest[1..-1] : rest[0..-1]
|
|
81
|
+
@object = unquote(rest)
|
|
82
|
+
@parts << @object
|
|
21
83
|
end
|
|
84
|
+
|
|
85
|
+
def quote(part)
|
|
86
|
+
part =~ /\A\[.*\]\z/ ? part : "[#{part.to_s.gsub(']', ']]')}]"
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def unquote(part)
|
|
90
|
+
if part && part.start_with?('[')
|
|
91
|
+
part[1..-2]
|
|
92
|
+
else
|
|
93
|
+
part
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def parts
|
|
98
|
+
@parts
|
|
99
|
+
end
|
|
100
|
+
|
|
22
101
|
end
|
|
102
|
+
|
|
103
|
+
extend self
|
|
104
|
+
|
|
105
|
+
def quote_string(s)
|
|
106
|
+
s.to_s.gsub /\'/, "''"
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def unquote_string(s)
|
|
110
|
+
s.to_s.gsub(/\'\'/, "'")
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def extract_identifiers(name)
|
|
114
|
+
SQLServer::Utils::Name.new(name)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def with_sqlserver_db_date_formats
|
|
118
|
+
old_db_format_date = Date::DATE_FORMATS[:db]
|
|
119
|
+
old_db_format_time = Time::DATE_FORMATS[:db]
|
|
120
|
+
date_format = Date::DATE_FORMATS[:_sqlserver_dateformat]
|
|
121
|
+
Date::DATE_FORMATS[:db] = "#{date_format}"
|
|
122
|
+
Time::DATE_FORMATS[:db] = "#{date_format} %H:%M:%S"
|
|
123
|
+
yield
|
|
124
|
+
ensure
|
|
125
|
+
Date::DATE_FORMATS[:db] = old_db_format_date
|
|
126
|
+
Time::DATE_FORMATS[:db] = old_db_format_time
|
|
127
|
+
end
|
|
128
|
+
|
|
23
129
|
end
|
|
24
130
|
end
|
|
25
131
|
end
|
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
require 'base64'
|
|
2
|
-
require 'arel/arel_sqlserver'
|
|
3
|
-
require 'arel/visitors/bind_visitor'
|
|
4
2
|
require 'active_record'
|
|
5
|
-
require '
|
|
6
|
-
require 'active_support/concern'
|
|
7
|
-
require 'active_support/core_ext/string'
|
|
3
|
+
require 'arel_sqlserver'
|
|
8
4
|
require 'active_record/connection_adapters/abstract_adapter'
|
|
9
5
|
require 'active_record/connection_adapters/sqlserver/core_ext/active_record'
|
|
10
6
|
require 'active_record/connection_adapters/sqlserver/core_ext/explain'
|
|
11
7
|
require 'active_record/connection_adapters/sqlserver/core_ext/explain_subscriber'
|
|
12
|
-
require 'active_record/connection_adapters/sqlserver/core_ext/
|
|
8
|
+
require 'active_record/connection_adapters/sqlserver/core_ext/attribute_methods'
|
|
9
|
+
require 'active_record/connection_adapters/sqlserver/version'
|
|
10
|
+
require 'active_record/connection_adapters/sqlserver/type'
|
|
13
11
|
require 'active_record/connection_adapters/sqlserver/database_limits'
|
|
14
12
|
require 'active_record/connection_adapters/sqlserver/database_statements'
|
|
13
|
+
require 'active_record/connection_adapters/sqlserver/transaction'
|
|
15
14
|
require 'active_record/connection_adapters/sqlserver/errors'
|
|
16
15
|
require 'active_record/connection_adapters/sqlserver/schema_cache'
|
|
17
16
|
require 'active_record/connection_adapters/sqlserver/schema_creation'
|
|
@@ -20,73 +19,54 @@ require 'active_record/connection_adapters/sqlserver/showplan'
|
|
|
20
19
|
require 'active_record/connection_adapters/sqlserver/table_definition'
|
|
21
20
|
require 'active_record/connection_adapters/sqlserver/quoting'
|
|
22
21
|
require 'active_record/connection_adapters/sqlserver/utils'
|
|
23
|
-
|
|
24
22
|
require 'active_record/sqlserver_base'
|
|
25
23
|
require 'active_record/connection_adapters/sqlserver_column'
|
|
26
24
|
|
|
27
25
|
module ActiveRecord
|
|
28
26
|
module ConnectionAdapters
|
|
29
27
|
class SQLServerAdapter < AbstractAdapter
|
|
30
|
-
include Sqlserver::Quoting
|
|
31
|
-
include Sqlserver::DatabaseStatements
|
|
32
|
-
include Sqlserver::Showplan
|
|
33
|
-
include Sqlserver::SchemaStatements
|
|
34
|
-
include Sqlserver::DatabaseLimits
|
|
35
|
-
include Sqlserver::Errors
|
|
36
28
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
29
|
+
include SQLServer::Version,
|
|
30
|
+
SQLServer::Quoting,
|
|
31
|
+
SQLServer::DatabaseStatements,
|
|
32
|
+
SQLServer::Showplan,
|
|
33
|
+
SQLServer::SchemaStatements,
|
|
34
|
+
SQLServer::DatabaseLimits
|
|
41
35
|
|
|
42
|
-
|
|
36
|
+
ADAPTER_NAME = 'SQLServer'.freeze
|
|
43
37
|
|
|
44
|
-
|
|
45
|
-
:enable_default_unicode_types, :auto_connect, :cs_equality_operator,
|
|
46
|
-
:lowercase_schema_reflection, :auto_connect_duration, :showplan_option
|
|
38
|
+
attr_reader :spid
|
|
47
39
|
|
|
48
|
-
|
|
40
|
+
cattr_accessor :cs_equality_operator, instance_accessor: false
|
|
41
|
+
cattr_accessor :lowercase_schema_reflection, :showplan_option
|
|
49
42
|
|
|
50
|
-
|
|
51
|
-
include Arel::Visitors::BindVisitor
|
|
52
|
-
end
|
|
43
|
+
self.cs_equality_operator = 'COLLATE Latin1_General_CS_AS_WS'
|
|
53
44
|
|
|
54
45
|
def initialize(connection, logger, pool, config)
|
|
55
46
|
super(connection, logger, pool)
|
|
56
47
|
# AbstractAdapter Responsibility
|
|
57
|
-
@schema_cache =
|
|
48
|
+
@schema_cache = SQLServer::SchemaCache.new self
|
|
58
49
|
@visitor = Arel::Visitors::SQLServer.new self
|
|
50
|
+
@prepared_statements = true
|
|
59
51
|
# Our Responsibility
|
|
60
52
|
@config = config
|
|
61
53
|
@connection_options = config
|
|
62
54
|
connect
|
|
63
|
-
@
|
|
64
|
-
@database_year = begin
|
|
65
|
-
if @database_version =~ /Azure/i
|
|
66
|
-
@sqlserver_azure = true
|
|
67
|
-
@database_version.match(/\s-\s([0-9.]+)/)[1]
|
|
68
|
-
year = 2016
|
|
69
|
-
elsif @database_version =~ /vNext/i
|
|
70
|
-
year = 2016
|
|
71
|
-
else
|
|
72
|
-
year = DATABASE_VERSION_REGEXP.match(@database_version)[1]
|
|
73
|
-
year == 'Denali' ? 2011 : year.to_i
|
|
74
|
-
end
|
|
75
|
-
rescue
|
|
76
|
-
0
|
|
77
|
-
end
|
|
78
|
-
@product_level = select_value "SELECT CAST(SERVERPROPERTY('productlevel') AS VARCHAR(128))", 'SCHEMA'
|
|
79
|
-
@product_version = select_value "SELECT CAST(SERVERPROPERTY('productversion') AS VARCHAR(128))", 'SCHEMA'
|
|
80
|
-
@edition = select_value "SELECT CAST(SERVERPROPERTY('edition') AS VARCHAR(128))", 'SCHEMA'
|
|
55
|
+
@sqlserver_azure = !!(select_value('SELECT @@version', 'SCHEMA') =~ /Azure/i)
|
|
81
56
|
initialize_dateformatter
|
|
82
57
|
use_database
|
|
83
|
-
unless @sqlserver_azure == true || SUPPORTED_VERSIONS.include?(@database_year)
|
|
84
|
-
raise NotImplementedError, "Currently, only #{SUPPORTED_VERSIONS.to_sentence} are supported. We got back #{@database_version}."
|
|
85
|
-
end
|
|
86
58
|
end
|
|
87
59
|
|
|
88
60
|
# === Abstract Adapter ========================================== #
|
|
89
61
|
|
|
62
|
+
def valid_type?(type)
|
|
63
|
+
!native_database_types[type].nil?
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def schema_creation
|
|
67
|
+
SQLServer::SchemaCreation.new self
|
|
68
|
+
end
|
|
69
|
+
|
|
90
70
|
def adapter_name
|
|
91
71
|
ADAPTER_NAME
|
|
92
72
|
end
|
|
@@ -108,10 +88,6 @@ module ActiveRecord
|
|
|
108
88
|
end
|
|
109
89
|
|
|
110
90
|
def supports_bulk_alter?
|
|
111
|
-
false
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
def supports_savepoints?
|
|
115
91
|
true
|
|
116
92
|
end
|
|
117
93
|
|
|
@@ -120,13 +96,21 @@ module ActiveRecord
|
|
|
120
96
|
end
|
|
121
97
|
|
|
122
98
|
def supports_partial_index?
|
|
123
|
-
|
|
99
|
+
true
|
|
124
100
|
end
|
|
125
101
|
|
|
126
102
|
def supports_explain?
|
|
127
103
|
true
|
|
128
104
|
end
|
|
129
105
|
|
|
106
|
+
def supports_transaction_isolation?
|
|
107
|
+
true
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def supports_views?
|
|
111
|
+
true
|
|
112
|
+
end
|
|
113
|
+
|
|
130
114
|
def disable_referential_integrity
|
|
131
115
|
do_execute "EXEC sp_MSforeachtable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL'"
|
|
132
116
|
yield
|
|
@@ -137,25 +121,21 @@ module ActiveRecord
|
|
|
137
121
|
# === Abstract Adapter (Connection Management) ================== #
|
|
138
122
|
|
|
139
123
|
def active?
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
return @connection.active?
|
|
143
|
-
end
|
|
144
|
-
raw_connection_do('SELECT 1')
|
|
124
|
+
return false unless @connection
|
|
125
|
+
raw_connection_do 'SELECT 1'
|
|
145
126
|
true
|
|
146
|
-
rescue
|
|
127
|
+
rescue TinyTds::Error, ODBC::Error
|
|
147
128
|
false
|
|
148
129
|
end
|
|
149
130
|
|
|
150
131
|
def reconnect!
|
|
151
|
-
|
|
132
|
+
super
|
|
152
133
|
disconnect!
|
|
153
134
|
connect
|
|
154
|
-
active?
|
|
155
135
|
end
|
|
156
136
|
|
|
157
137
|
def disconnect!
|
|
158
|
-
|
|
138
|
+
super
|
|
159
139
|
@spid = nil
|
|
160
140
|
case @connection_options[:mode]
|
|
161
141
|
when :dblib
|
|
@@ -163,10 +143,12 @@ module ActiveRecord
|
|
|
163
143
|
when :odbc
|
|
164
144
|
@connection.disconnect rescue nil
|
|
165
145
|
end
|
|
146
|
+
@connection = nil
|
|
166
147
|
end
|
|
167
148
|
|
|
168
149
|
def reset!
|
|
169
|
-
|
|
150
|
+
reset_transaction
|
|
151
|
+
do_execute 'IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION'
|
|
170
152
|
end
|
|
171
153
|
|
|
172
154
|
# === Abstract Adapter (Misc Support) =========================== #
|
|
@@ -180,36 +162,12 @@ module ActiveRecord
|
|
|
180
162
|
identity_column(table_name).try(:name) || schema_cache.columns(table_name).find(&:is_primary?).try(:name)
|
|
181
163
|
end
|
|
182
164
|
|
|
183
|
-
def schema_creation
|
|
184
|
-
Sqlserver::SchemaCreation.new self
|
|
185
|
-
end
|
|
186
|
-
|
|
187
165
|
# === SQLServer Specific (DB Reflection) ======================== #
|
|
188
166
|
|
|
189
167
|
def sqlserver?
|
|
190
168
|
true
|
|
191
169
|
end
|
|
192
170
|
|
|
193
|
-
def sqlserver_2005?
|
|
194
|
-
@database_year == 2005
|
|
195
|
-
end
|
|
196
|
-
|
|
197
|
-
def sqlserver_2008?
|
|
198
|
-
@database_year == 2008
|
|
199
|
-
end
|
|
200
|
-
|
|
201
|
-
def sqlserver_2011?
|
|
202
|
-
@database_year == 2011
|
|
203
|
-
end
|
|
204
|
-
|
|
205
|
-
def sqlserver_2012?
|
|
206
|
-
@database_year == 2012
|
|
207
|
-
end
|
|
208
|
-
|
|
209
|
-
def sqlserver_2014?
|
|
210
|
-
@database_year == 2014
|
|
211
|
-
end
|
|
212
|
-
|
|
213
171
|
def sqlserver_azure?
|
|
214
172
|
@sqlserver_azure
|
|
215
173
|
end
|
|
@@ -219,45 +177,67 @@ module ActiveRecord
|
|
|
219
177
|
end
|
|
220
178
|
|
|
221
179
|
def inspect
|
|
222
|
-
"#<#{self.class} version: #{version},
|
|
223
|
-
end
|
|
224
|
-
|
|
225
|
-
def auto_connect
|
|
226
|
-
@@auto_connect.is_a?(FalseClass) ? false : true
|
|
227
|
-
end
|
|
228
|
-
|
|
229
|
-
def auto_connect_duration
|
|
230
|
-
@@auto_connect_duration ||= 10
|
|
231
|
-
end
|
|
232
|
-
|
|
233
|
-
def native_string_database_type
|
|
234
|
-
@@native_string_database_type || (enable_default_unicode_types ? 'nvarchar' : 'varchar')
|
|
235
|
-
end
|
|
236
|
-
|
|
237
|
-
def native_text_database_type
|
|
238
|
-
@@native_text_database_type || (enable_default_unicode_types ? 'nvarchar(max)' : 'varchar(max)')
|
|
239
|
-
end
|
|
240
|
-
|
|
241
|
-
def native_time_database_type
|
|
242
|
-
sqlserver_2005? ? 'datetime' : 'time'
|
|
180
|
+
"#<#{self.class} version: #{version}, mode: #{@connection_options[:mode]}, azure: #{sqlserver_azure?.inspect}>"
|
|
243
181
|
end
|
|
244
182
|
|
|
245
|
-
def native_date_database_type
|
|
246
|
-
sqlserver_2005? ? 'datetime' : 'date'
|
|
247
|
-
end
|
|
248
|
-
|
|
249
|
-
def native_binary_database_type
|
|
250
|
-
@@native_binary_database_type || 'varbinary(max)'
|
|
251
|
-
end
|
|
252
|
-
|
|
253
|
-
def cs_equality_operator
|
|
254
|
-
@@cs_equality_operator || 'COLLATE Latin1_General_CS_AS_WS'
|
|
255
|
-
end
|
|
256
183
|
|
|
257
184
|
protected
|
|
258
185
|
|
|
259
186
|
# === Abstract Adapter (Misc Support) =========================== #
|
|
260
187
|
|
|
188
|
+
def initialize_type_map(m)
|
|
189
|
+
m.register_type %r{.*}, SQLServer::Type::UnicodeString.new
|
|
190
|
+
# Exact Numerics
|
|
191
|
+
register_class_with_limit m, 'bigint(8)', SQLServer::Type::BigInteger
|
|
192
|
+
m.alias_type 'bigint', 'bigint(8)'
|
|
193
|
+
register_class_with_limit m, 'int(4)', SQLServer::Type::Integer
|
|
194
|
+
m.alias_type 'integer', 'int(4)'
|
|
195
|
+
m.alias_type 'int', 'int(4)'
|
|
196
|
+
register_class_with_limit m, 'smallint(2)', SQLServer::Type::SmallInteger
|
|
197
|
+
m.alias_type 'smallint', 'smallint(2)'
|
|
198
|
+
register_class_with_limit m, 'tinyint(1)', SQLServer::Type::TinyInteger
|
|
199
|
+
m.alias_type 'tinyint', 'tinyint(1)'
|
|
200
|
+
m.register_type 'bit', SQLServer::Type::Boolean.new
|
|
201
|
+
m.register_type %r{\Adecimal}i do |sql_type|
|
|
202
|
+
scale = extract_scale(sql_type)
|
|
203
|
+
precision = extract_precision(sql_type)
|
|
204
|
+
SQLServer::Type::Decimal.new precision: precision, scale: scale
|
|
205
|
+
end
|
|
206
|
+
m.alias_type %r{\Anumeric}i, 'decimal'
|
|
207
|
+
m.register_type 'money', SQLServer::Type::Money.new
|
|
208
|
+
m.register_type 'smallmoney', SQLServer::Type::SmallMoney.new
|
|
209
|
+
# Approximate Numerics
|
|
210
|
+
m.register_type 'float', SQLServer::Type::Float.new
|
|
211
|
+
m.register_type 'real', SQLServer::Type::Real.new
|
|
212
|
+
# Date and Time
|
|
213
|
+
m.register_type 'date', SQLServer::Type::Date.new
|
|
214
|
+
m.register_type 'datetime', SQLServer::Type::DateTime.new
|
|
215
|
+
m.register_type 'smalldatetime', SQLServer::Type::SmallDateTime.new
|
|
216
|
+
m.register_type %r{\Atime}i do |sql_type|
|
|
217
|
+
scale = extract_scale(sql_type)
|
|
218
|
+
precision = extract_precision(sql_type)
|
|
219
|
+
SQLServer::Type::Time.new precision: precision
|
|
220
|
+
end
|
|
221
|
+
# Character Strings
|
|
222
|
+
register_class_with_limit m, %r{\Achar}i, SQLServer::Type::Char
|
|
223
|
+
register_class_with_limit m, %r{\Avarchar}i, SQLServer::Type::Varchar
|
|
224
|
+
m.register_type 'varchar(max)', SQLServer::Type::VarcharMax.new
|
|
225
|
+
m.register_type 'text', SQLServer::Type::Text.new
|
|
226
|
+
# Unicode Character Strings
|
|
227
|
+
register_class_with_limit m, %r{\Anchar}i, SQLServer::Type::UnicodeChar
|
|
228
|
+
register_class_with_limit m, %r{\Anvarchar}i, SQLServer::Type::UnicodeVarchar
|
|
229
|
+
m.alias_type 'string', 'nvarchar(4000)'
|
|
230
|
+
m.register_type 'nvarchar(max)', SQLServer::Type::UnicodeVarcharMax.new
|
|
231
|
+
m.register_type 'ntext', SQLServer::Type::UnicodeText.new
|
|
232
|
+
# Binary Strings
|
|
233
|
+
register_class_with_limit m, %r{\Abinary}i, SQLServer::Type::Binary
|
|
234
|
+
register_class_with_limit m, %r{\Avarbinary}i, SQLServer::Type::Varbinary
|
|
235
|
+
m.register_type 'varbinary(max)', SQLServer::Type::VarbinaryMax.new
|
|
236
|
+
# Other Data Types
|
|
237
|
+
m.register_type 'uniqueidentifier', SQLServer::Type::Uuid.new
|
|
238
|
+
m.register_type 'timestamp', SQLServer::Type::Timestamp.new
|
|
239
|
+
end
|
|
240
|
+
|
|
261
241
|
def translate_exception(e, message)
|
|
262
242
|
case message
|
|
263
243
|
when /(cannot insert duplicate key .* with unique index) | (violation of unique key constraint)/i
|
|
@@ -266,8 +246,6 @@ module ActiveRecord
|
|
|
266
246
|
InvalidForeignKey.new(message, e)
|
|
267
247
|
when /has been chosen as the deadlock victim/i
|
|
268
248
|
DeadlockVictim.new(message, e)
|
|
269
|
-
when *lost_connection_messages
|
|
270
|
-
LostConnection.new(message, e)
|
|
271
249
|
else
|
|
272
250
|
super
|
|
273
251
|
end
|
|
@@ -285,25 +263,23 @@ module ActiveRecord
|
|
|
285
263
|
end
|
|
286
264
|
@spid = _raw_select('SELECT @@SPID', fetch: :rows).first.first
|
|
287
265
|
configure_connection
|
|
288
|
-
rescue
|
|
289
|
-
raise unless @auto_connecting
|
|
290
266
|
end
|
|
291
267
|
|
|
292
268
|
def dblib_connect(config)
|
|
293
269
|
TinyTds::Client.new(
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
270
|
+
dataserver: config[:dataserver],
|
|
271
|
+
host: config[:host],
|
|
272
|
+
port: config[:port],
|
|
273
|
+
username: config[:username],
|
|
274
|
+
password: config[:password],
|
|
275
|
+
database: config[:database],
|
|
276
|
+
tds_version: config[:tds_version],
|
|
277
|
+
appname: config_appname(config),
|
|
278
|
+
login_timeout: config_login_timeout(config),
|
|
279
|
+
timeout: config_timeout(config),
|
|
280
|
+
encoding: config_encoding(config),
|
|
281
|
+
azure: config[:azure]
|
|
282
|
+
).tap do |client|
|
|
307
283
|
if config[:azure]
|
|
308
284
|
client.execute('SET ANSI_NULLS ON').do
|
|
309
285
|
client.execute('SET CURSOR_CLOSE_ON_COMMIT OFF').do
|
|
@@ -322,22 +298,6 @@ module ActiveRecord
|
|
|
322
298
|
end
|
|
323
299
|
end
|
|
324
300
|
|
|
325
|
-
def appname(config)
|
|
326
|
-
config[:appname] || configure_application_name || Rails.application.class.name.split('::').first rescue nil
|
|
327
|
-
end
|
|
328
|
-
|
|
329
|
-
def login_timeout(config)
|
|
330
|
-
config[:login_timeout].present? ? config[:login_timeout].to_i : nil
|
|
331
|
-
end
|
|
332
|
-
|
|
333
|
-
def timeout(config)
|
|
334
|
-
config[:timeout].present? ? config[:timeout].to_i / 1000 : nil
|
|
335
|
-
end
|
|
336
|
-
|
|
337
|
-
def encoding(config)
|
|
338
|
-
config[:encoding].present? ? config[:encoding] : nil
|
|
339
|
-
end
|
|
340
|
-
|
|
341
301
|
def odbc_connect(config)
|
|
342
302
|
if config[:dsn].include?(';')
|
|
343
303
|
driver = ODBC::Driver.new.tap do |d|
|
|
@@ -357,19 +317,26 @@ module ActiveRecord
|
|
|
357
317
|
end
|
|
358
318
|
end
|
|
359
319
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
# raw_connection_do "SET TEXTSIZE #{64.megabytes}"
|
|
363
|
-
# raw_connection_do "SET CONCAT_NULL_YIELDS_NULL ON"
|
|
364
|
-
def configure_connection
|
|
320
|
+
def config_appname(config)
|
|
321
|
+
config[:appname] || configure_application_name || Rails.application.class.name.split('::').first rescue nil
|
|
365
322
|
end
|
|
366
323
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
# "myapp_#{$$}_#{Thread.current.object_id}".to(29)
|
|
370
|
-
def configure_application_name
|
|
324
|
+
def config_login_timeout(config)
|
|
325
|
+
config[:login_timeout].present? ? config[:login_timeout].to_i : nil
|
|
371
326
|
end
|
|
372
327
|
|
|
328
|
+
def config_timeout(config)
|
|
329
|
+
config[:timeout].present? ? config[:timeout].to_i / 1000 : nil
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
def config_encoding(config)
|
|
333
|
+
config[:encoding].present? ? config[:encoding] : nil
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
def configure_connection ; end
|
|
337
|
+
|
|
338
|
+
def configure_application_name ; end
|
|
339
|
+
|
|
373
340
|
def initialize_dateformatter
|
|
374
341
|
@database_dateformat = user_options_dateformat
|
|
375
342
|
a, b, c = @database_dateformat.each_char.to_a
|
|
@@ -380,47 +347,15 @@ module ActiveRecord
|
|
|
380
347
|
end
|
|
381
348
|
|
|
382
349
|
def remove_database_connections_and_rollback(database = nil)
|
|
383
|
-
database
|
|
384
|
-
do_execute "ALTER DATABASE #{
|
|
350
|
+
name = SQLServer::Utils.extract_identifiers(database || current_database)
|
|
351
|
+
do_execute "ALTER DATABASE #{name} SET SINGLE_USER WITH ROLLBACK IMMEDIATE"
|
|
385
352
|
begin
|
|
386
353
|
yield
|
|
387
354
|
ensure
|
|
388
|
-
do_execute "ALTER DATABASE #{
|
|
355
|
+
do_execute "ALTER DATABASE #{name} SET MULTI_USER"
|
|
389
356
|
end if block_given?
|
|
390
357
|
end
|
|
391
358
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
case translate_exception(e, e.message)
|
|
396
|
-
when LostConnection then retry if auto_reconnected?
|
|
397
|
-
end
|
|
398
|
-
raise
|
|
399
|
-
end
|
|
400
|
-
|
|
401
|
-
def disable_auto_reconnect
|
|
402
|
-
old_auto_connect, self.class.auto_connect = self.class.auto_connect, false
|
|
403
|
-
yield
|
|
404
|
-
ensure
|
|
405
|
-
self.class.auto_connect = old_auto_connect
|
|
406
|
-
end
|
|
407
|
-
|
|
408
|
-
def auto_reconnected?
|
|
409
|
-
return false unless auto_connect
|
|
410
|
-
@auto_connecting = true
|
|
411
|
-
count = 0
|
|
412
|
-
while count <= (auto_connect_duration / 2)
|
|
413
|
-
result = reconnect!
|
|
414
|
-
ActiveRecord::Base.did_retry_sqlserver_connection(self, count)
|
|
415
|
-
return true if result
|
|
416
|
-
sleep 2**count
|
|
417
|
-
count += 1
|
|
418
|
-
end
|
|
419
|
-
ActiveRecord::Base.did_lose_sqlserver_connection(self)
|
|
420
|
-
false
|
|
421
|
-
ensure
|
|
422
|
-
@auto_connecting = false
|
|
423
|
-
end
|
|
424
|
-
end # class SQLServerAdapter < AbstractAdapter
|
|
425
|
-
end # module ConnectionAdapters
|
|
426
|
-
end # module ActiveRecord
|
|
359
|
+
end
|
|
360
|
+
end
|
|
361
|
+
end
|