activerecord-sqlserver-adapter 4.1.8 → 4.2.0.pre

Sign up to get free protection for your applications and to get access to all the features.
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