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.
Files changed (122) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +15 -0
  3. data/CHANGELOG.md +60 -0
  4. data/Gemfile +45 -0
  5. data/Guardfile +29 -0
  6. data/MIT-LICENSE +5 -5
  7. data/README.md +193 -0
  8. data/RUNNING_UNIT_TESTS.md +95 -0
  9. data/Rakefile +48 -0
  10. data/activerecord-sqlserver-adapter.gemspec +28 -0
  11. data/lib/active_record/connection_adapters/sqlserver/core_ext/active_record.rb +5 -15
  12. data/lib/active_record/connection_adapters/sqlserver/core_ext/attribute_methods.rb +25 -0
  13. data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +6 -4
  14. data/lib/active_record/connection_adapters/sqlserver/core_ext/odbc.rb +9 -3
  15. data/lib/active_record/connection_adapters/sqlserver/database_limits.rb +3 -1
  16. data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +130 -151
  17. data/lib/active_record/connection_adapters/sqlserver/errors.rb +0 -25
  18. data/lib/active_record/connection_adapters/sqlserver/quoting.rb +39 -78
  19. data/lib/active_record/connection_adapters/sqlserver/schema_cache.rb +71 -47
  20. data/lib/active_record/connection_adapters/sqlserver/schema_creation.rb +14 -30
  21. data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +112 -108
  22. data/lib/active_record/connection_adapters/sqlserver/showplan.rb +4 -2
  23. data/lib/active_record/connection_adapters/sqlserver/showplan/printer_table.rb +1 -1
  24. data/lib/active_record/connection_adapters/sqlserver/showplan/printer_xml.rb +1 -1
  25. data/lib/active_record/connection_adapters/sqlserver/table_definition.rb +52 -7
  26. data/lib/active_record/connection_adapters/sqlserver/transaction.rb +52 -0
  27. data/lib/active_record/connection_adapters/sqlserver/type.rb +46 -0
  28. data/lib/active_record/connection_adapters/sqlserver/type/big_integer.rb +15 -0
  29. data/lib/active_record/connection_adapters/sqlserver/type/binary.rb +15 -0
  30. data/lib/active_record/connection_adapters/sqlserver/type/boolean.rb +13 -0
  31. data/lib/active_record/connection_adapters/sqlserver/type/castable.rb +15 -0
  32. data/lib/active_record/connection_adapters/sqlserver/type/char.rb +15 -0
  33. data/lib/active_record/connection_adapters/sqlserver/type/core_ext/value.rb +39 -0
  34. data/lib/active_record/connection_adapters/sqlserver/type/date.rb +14 -0
  35. data/lib/active_record/connection_adapters/sqlserver/type/datetime.rb +37 -0
  36. data/lib/active_record/connection_adapters/sqlserver/type/decimal.rb +13 -0
  37. data/lib/active_record/connection_adapters/sqlserver/type/float.rb +17 -0
  38. data/lib/active_record/connection_adapters/sqlserver/type/integer.rb +13 -0
  39. data/lib/active_record/connection_adapters/sqlserver/type/money.rb +21 -0
  40. data/lib/active_record/connection_adapters/sqlserver/type/quoter.rb +32 -0
  41. data/lib/active_record/connection_adapters/sqlserver/type/real.rb +17 -0
  42. data/lib/active_record/connection_adapters/sqlserver/type/small_integer.rb +13 -0
  43. data/lib/active_record/connection_adapters/sqlserver/type/small_money.rb +21 -0
  44. data/lib/active_record/connection_adapters/sqlserver/type/smalldatetime.rb +24 -0
  45. data/lib/active_record/connection_adapters/sqlserver/type/string.rb +12 -0
  46. data/lib/active_record/connection_adapters/sqlserver/type/text.rb +15 -0
  47. data/lib/active_record/connection_adapters/sqlserver/type/time.rb +59 -0
  48. data/lib/active_record/connection_adapters/sqlserver/type/timestamp.rb +15 -0
  49. data/lib/active_record/connection_adapters/sqlserver/type/tiny_integer.rb +22 -0
  50. data/lib/active_record/connection_adapters/sqlserver/type/unicode_char.rb +15 -0
  51. data/lib/active_record/connection_adapters/sqlserver/type/unicode_string.rb +12 -0
  52. data/lib/active_record/connection_adapters/sqlserver/type/unicode_text.rb +15 -0
  53. data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar.rb +20 -0
  54. data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar_max.rb +20 -0
  55. data/lib/active_record/connection_adapters/sqlserver/type/uuid.rb +23 -0
  56. data/lib/active_record/connection_adapters/sqlserver/type/varbinary.rb +20 -0
  57. data/lib/active_record/connection_adapters/sqlserver/type/varbinary_max.rb +20 -0
  58. data/lib/active_record/connection_adapters/sqlserver/type/varchar.rb +20 -0
  59. data/lib/active_record/connection_adapters/sqlserver/type/varchar_max.rb +20 -0
  60. data/lib/active_record/connection_adapters/sqlserver/utils.rb +118 -12
  61. data/lib/active_record/connection_adapters/sqlserver/version.rb +11 -0
  62. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +133 -198
  63. data/lib/active_record/connection_adapters/sqlserver_column.rb +15 -86
  64. data/lib/active_record/sqlserver_base.rb +2 -0
  65. data/lib/arel/visitors/sqlserver.rb +120 -393
  66. data/lib/{arel/arel_sqlserver.rb → arel_sqlserver.rb} +1 -3
  67. data/test/cases/adapter_test_sqlserver.rb +420 -0
  68. data/test/cases/coerced_tests.rb +642 -0
  69. data/test/cases/column_test_sqlserver.rb +703 -0
  70. data/test/cases/connection_test_sqlserver.rb +216 -0
  71. data/test/cases/database_statements_test_sqlserver.rb +57 -0
  72. data/test/cases/execute_procedure_test_sqlserver.rb +38 -0
  73. data/test/cases/helper_sqlserver.rb +36 -0
  74. data/test/cases/migration_test_sqlserver.rb +66 -0
  75. data/test/cases/order_test_sqlserver.rb +147 -0
  76. data/test/cases/pessimistic_locking_test_sqlserver.rb +90 -0
  77. data/test/cases/schema_dumper_test_sqlserver.rb +175 -0
  78. data/test/cases/schema_test_sqlserver.rb +54 -0
  79. data/test/cases/scratchpad_test_sqlserver.rb +9 -0
  80. data/test/cases/showplan_test_sqlserver.rb +65 -0
  81. data/test/cases/specific_schema_test_sqlserver.rb +118 -0
  82. data/test/cases/transaction_test_sqlserver.rb +61 -0
  83. data/test/cases/utils_test_sqlserver.rb +91 -0
  84. data/test/cases/uuid_test_sqlserver.rb +41 -0
  85. data/test/config.yml +35 -0
  86. data/test/fixtures/1px.gif +0 -0
  87. data/test/migrations/transaction_table/1_table_will_never_be_created.rb +11 -0
  88. data/test/models/sqlserver/customers_view.rb +3 -0
  89. data/test/models/sqlserver/datatype.rb +3 -0
  90. data/test/models/sqlserver/datatype_migration.rb +3 -0
  91. data/test/models/sqlserver/dollar_table_name.rb +3 -0
  92. data/test/models/sqlserver/edge_schema.rb +13 -0
  93. data/test/models/sqlserver/fk_has_fk.rb +3 -0
  94. data/test/models/sqlserver/fk_has_pk.rb +3 -0
  95. data/test/models/sqlserver/natural_pk_data.rb +4 -0
  96. data/test/models/sqlserver/natural_pk_int_data.rb +3 -0
  97. data/test/models/sqlserver/no_pk_data.rb +3 -0
  98. data/test/models/sqlserver/quoted_table.rb +7 -0
  99. data/test/models/sqlserver/quoted_view_1.rb +3 -0
  100. data/test/models/sqlserver/quoted_view_2.rb +3 -0
  101. data/test/models/sqlserver/string_default.rb +3 -0
  102. data/test/models/sqlserver/string_defaults_big_view.rb +3 -0
  103. data/test/models/sqlserver/string_defaults_view.rb +3 -0
  104. data/test/models/sqlserver/tinyint_pk.rb +3 -0
  105. data/test/models/sqlserver/upper.rb +3 -0
  106. data/test/models/sqlserver/uppered.rb +3 -0
  107. data/test/models/sqlserver/uuid.rb +3 -0
  108. data/test/schema/datatypes/2012.sql +64 -0
  109. data/test/schema/sqlserver_specific_schema.rb +181 -0
  110. data/test/support/coerceable_test_sqlserver.rb +45 -0
  111. data/test/support/load_schema_sqlserver.rb +29 -0
  112. data/test/support/minitest_sqlserver.rb +1 -0
  113. data/test/support/paths_sqlserver.rb +48 -0
  114. data/test/support/rake_helpers.rb +41 -0
  115. data/test/support/sql_counter_sqlserver.rb +32 -0
  116. metadata +271 -21
  117. data/CHANGELOG +0 -39
  118. data/VERSION +0 -1
  119. data/lib/active_record/connection_adapters/sqlserver/core_ext/relation.rb +0 -17
  120. data/lib/active_record/sqlserver_test_case.rb +0 -17
  121. data/lib/arel/nodes_sqlserver.rb +0 -14
  122. 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 Sqlserver
4
- class Utils
5
- class << self
6
- def unquote_string(string)
7
- string.to_s.gsub(/\'\'/, "'")
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 unqualify_table_name(table_name)
11
- table_name.to_s.split('.').last.tr('[]', '')
34
+ def database_quoted
35
+ database ? quote(database) : database
12
36
  end
13
37
 
14
- def unqualify_table_schema(table_name)
15
- table_name.to_s.split('.')[-2].gsub(/[\[\]]/, '') rescue nil
38
+ def server_quoted
39
+ server ? quote(server) : server
16
40
  end
17
41
 
18
- def unqualify_db_name(table_name)
19
- table_names = table_name.to_s.split('.')
20
- table_names.length == 3 ? table_names.first.tr('[]', '') : nil
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
@@ -0,0 +1,11 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module SQLServer
4
+ module Version
5
+
6
+ VERSION = '4.2.0.pre'
7
+
8
+ end
9
+ end
10
+ end
11
+ 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 'active_record/base'
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/relation'
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
- VERSION = File.read(File.expand_path('../../../../VERSION', __FILE__)).strip
38
- ADAPTER_NAME = 'SQLServer'.freeze
39
- DATABASE_VERSION_REGEXP = /Microsoft SQL Server\s+"?(\d{4}|\w+)"?/
40
- SUPPORTED_VERSIONS = [2005, 2008, 2010, 2011, 2012, 2014, 2016, 2017]
29
+ include SQLServer::Version,
30
+ SQLServer::Quoting,
31
+ SQLServer::DatabaseStatements,
32
+ SQLServer::Showplan,
33
+ SQLServer::SchemaStatements,
34
+ SQLServer::DatabaseLimits
41
35
 
42
- attr_reader :database_version, :database_year, :spid, :product_level, :product_version, :edition
36
+ ADAPTER_NAME = 'SQLServer'.freeze
43
37
 
44
- cattr_accessor :native_text_database_type, :native_binary_database_type, :native_string_database_type,
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
- self.enable_default_unicode_types = true
40
+ cattr_accessor :cs_equality_operator, instance_accessor: false
41
+ cattr_accessor :lowercase_schema_reflection, :showplan_option
49
42
 
50
- class BindSubstitution < Arel::Visitors::SQLServer # :nodoc:
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 = Sqlserver::SchemaCache.new self
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
- @database_version = select_value 'SELECT @@version', 'SCHEMA'
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
- @database_year >= 2008
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
- case @connection_options[:mode]
141
- when :dblib
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 *lost_connection_exceptions
127
+ rescue TinyTds::Error, ODBC::Error
147
128
  false
148
129
  end
149
130
 
150
131
  def reconnect!
151
- reset_transaction
132
+ super
152
133
  disconnect!
153
134
  connect
154
- active?
155
135
  end
156
136
 
157
137
  def disconnect!
158
- reset_transaction
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
- remove_database_connections_and_rollback {}
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}, year: #{@database_year}, product_level: #{@product_level.inspect}, product_version: #{@product_version.inspect}, edition: #{@edition.inspect}, connection_options: #{@connection_options.inspect}>"
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
- dataserver: config[:dataserver],
295
- host: config[:host],
296
- port: config[:port],
297
- username: config[:username],
298
- password: config[:password],
299
- database: config[:database],
300
- tds_version: config[:tds_version],
301
- appname: appname(config),
302
- login_timeout: login_timeout(config),
303
- timeout: timeout(config),
304
- encoding: encoding(config),
305
- azure: config[:azure]
306
- ).tap do |client|
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
- # Override this method so every connection can be configured to your needs.
361
- # For example:
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
- # Override this method so every connection can have a unique name. Max 30 characters. Used by TinyTDS only.
368
- # For example:
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 ||= current_database
384
- do_execute "ALTER DATABASE #{quote_database_name(database)} SET SINGLE_USER WITH ROLLBACK IMMEDIATE"
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 #{quote_database_name(database)} SET MULTI_USER"
355
+ do_execute "ALTER DATABASE #{name} SET MULTI_USER"
389
356
  end if block_given?
390
357
  end
391
358
 
392
- def with_sqlserver_error_handling
393
- yield
394
- rescue Exception => e
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