activerecord-sqlserver-adapter 3.0.0 → 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,5 +1,10 @@
1
1
 
2
- MASTER
2
+ * 3.0.1
3
+
4
+ * Support DSN'less connections. Resolves ticket 38.
5
+
6
+ * Support upcoming ruby odbc 0.99992
7
+
3
8
 
4
9
  * 3.0.0
5
10
 
@@ -203,11 +203,11 @@ module ActiveRecord
203
203
  end
204
204
 
205
205
  def raw_connection_do(sql)
206
- case connection_mode
206
+ case @connection_options[:mode]
207
207
  when :odbc
208
- raw_connection.do(sql)
208
+ @connection.do(sql)
209
209
  else :adonet
210
- raw_connection.create_command.tap{ |cmd| cmd.command_text = sql }.execute_non_query
210
+ @connection.create_command.tap{ |cmd| cmd.command_text = sql }.execute_non_query
211
211
  end
212
212
  end
213
213
 
@@ -226,17 +226,17 @@ module ActiveRecord
226
226
 
227
227
  def raw_connection_run(sql)
228
228
  with_auto_reconnect do
229
- case connection_mode
229
+ case @connection_options[:mode]
230
230
  when :odbc
231
- block_given? ? raw_connection.run_block(sql) { |handle| yield(handle) } : raw_connection.run(sql)
231
+ block_given? ? @connection.run_block(sql) { |handle| yield(handle) } : @connection.run(sql)
232
232
  else :adonet
233
- raw_connection.create_command.tap{ |cmd| cmd.command_text = sql }.execute_reader
233
+ @connection.create_command.tap{ |cmd| cmd.command_text = sql }.execute_reader
234
234
  end
235
235
  end
236
236
  end
237
237
 
238
238
  def handle_more_results?(handle)
239
- case connection_mode
239
+ case @connection_options[:mode]
240
240
  when :odbc
241
241
  handle.more_results
242
242
  when :adonet
@@ -245,7 +245,7 @@ module ActiveRecord
245
245
  end
246
246
 
247
247
  def handle_to_names_and_values(handle, options={})
248
- case connection_mode
248
+ case @connection_options[:mode]
249
249
  when :odbc
250
250
  handle_to_names_and_values_odbc(handle, options)
251
251
  when :adonet
@@ -254,29 +254,40 @@ module ActiveRecord
254
254
  end
255
255
 
256
256
  def handle_to_names_and_values_odbc(handle, options={})
257
+ @connection.use_utc = ActiveRecord::Base.default_timezone == :utc if @connection_supports_native_types
257
258
  case options[:fetch]
258
259
  when :all, :one
259
- rows = if options[:fetch] == :all
260
- handle.fetch_all || []
261
- else
262
- row = handle.fetch
263
- row ? [row] : [[]]
264
- end
265
- names = handle.columns(true).map{ |c| c.name }
266
- names_and_values = []
267
- rows.each do |row|
268
- h = {}
269
- i = 0
270
- while i < row.size
271
- v = row[i]
272
- h[names[i]] = v.respond_to?(:to_sqlserver_string) ? v.to_sqlserver_string : v
273
- i += 1
260
+ if @connection_supports_native_types
261
+ if options[:fetch] == :all
262
+ handle.each_hash || []
263
+ else
264
+ row = handle.fetch_hash
265
+ rows = row ? [row] : [[]]
274
266
  end
275
- names_and_values << h
267
+ else
268
+ rows = if options[:fetch] == :all
269
+ handle.fetch_all || []
270
+ else
271
+ row = handle.fetch
272
+ row ? [row] : [[]]
273
+ end
274
+ names = handle.columns(true).map{ |c| c.name }
275
+ names_and_values = []
276
+ rows.each do |row|
277
+ h = {}
278
+ i = 0
279
+ while i < row.size
280
+ v = row[i]
281
+ h[names[i]] = v.respond_to?(:to_sqlserver_string) ? v.to_sqlserver_string : v
282
+ i += 1
283
+ end
284
+ names_and_values << h
285
+ end
286
+ names_and_values
276
287
  end
277
- names_and_values
278
288
  when :rows
279
289
  rows = handle.fetch_all || []
290
+ return rows if @connection_supports_native_types
280
291
  rows.each do |row|
281
292
  i = 0
282
293
  while i < row.size
@@ -291,36 +302,55 @@ module ActiveRecord
291
302
 
292
303
  def handle_to_names_and_values_adonet(handle, options={})
293
304
  if handle.has_rows
294
- fields = []
305
+ names = []
295
306
  rows = []
296
- fields_named = false
307
+ fields_named = options[:fetch] == :rows
308
+ one_row_only = options[:fetch] == :one
297
309
  while handle.read
298
310
  row = []
299
311
  handle.visible_field_count.times do |row_index|
300
312
  value = handle.get_value(row_index)
301
- value = if value.is_a? System::String
313
+ value = case value
314
+ when System::String
302
315
  value.to_s
303
- elsif value.is_a? System::DBNull
316
+ when System::DBNull
304
317
  nil
305
- elsif value.is_a? System::DateTime
306
- value.to_string("yyyy-MM-dd HH:MM:ss.fff").to_s
318
+ when System::DateTime
319
+ value.to_string("yyyy-MM-dd HH:mm:ss.fff").to_s
320
+ when @@array_of_bytes ||= System::Array[System::Byte]
321
+ String.new(value)
307
322
  else
308
323
  value
309
324
  end
310
325
  row << value
311
- fields << handle.get_name(row_index).to_s unless fields_named
326
+ names << handle.get_name(row_index).to_s unless fields_named
327
+ break if one_row_only
312
328
  end
313
329
  rows << row
314
330
  fields_named = true
315
331
  end
316
332
  else
317
- fields, rows = [], []
333
+ rows = []
334
+ end
335
+ if options[:fetch] != :rows
336
+ names_and_values = []
337
+ rows.each do |row|
338
+ h = {}
339
+ i = 0
340
+ while i < row.size
341
+ h[names[i]] = row[i]
342
+ i += 1
343
+ end
344
+ names_and_values << h
345
+ end
346
+ names_and_values
347
+ else
348
+ rows
318
349
  end
319
- [fields,rows]
320
350
  end
321
351
 
322
352
  def finish_statement_handle(handle)
323
- case connection_mode
353
+ case @connection_options[:mode]
324
354
  when :odbc
325
355
  handle.drop if handle && handle.respond_to?(:drop) && !handle.finished?
326
356
  when :adonet
@@ -19,12 +19,12 @@ module ActiveRecord
19
19
 
20
20
 
21
21
  def lost_connection_exceptions
22
- exceptions = LOST_CONNECTION_EXCEPTIONS[connection_mode]
22
+ exceptions = LOST_CONNECTION_EXCEPTIONS[@connection_options[:mode]]
23
23
  @lost_connection_exceptions ||= exceptions ? exceptions.map{ |e| e.constantize rescue nil }.compact : []
24
24
  end
25
25
 
26
26
  def lost_connection_messages
27
- LOST_CONNECTION_MESSAGES[connection_mode]
27
+ LOST_CONNECTION_MESSAGES[@connection_options[:mode]]
28
28
  end
29
29
 
30
30
  end
@@ -3,6 +3,8 @@ module ActiveRecord
3
3
  module Sqlserver
4
4
  module Quoting
5
5
 
6
+ QUOTED_TRUE, QUOTED_FALSE = '1', '0'
7
+
6
8
  def quote(value, column = nil)
7
9
  case value
8
10
  when String, ActiveSupport::Multibyte::Chars
@@ -22,21 +24,21 @@ module ActiveRecord
22
24
  string.to_s.gsub(/\'/, "''")
23
25
  end
24
26
 
25
- def quote_column_name(column_name)
26
- column_name.to_s.split('.').map{ |name| name =~ /^\[.*\]$/ ? name : "[#{name}]" }.join('.')
27
+ def quote_column_name(name)
28
+ @sqlserver_quoted_column_and_table_names[name] ||=
29
+ name.to_s.split('.').map{ |n| n =~ /^\[.*\]$/ ? n : "[#{n}]" }.join('.')
27
30
  end
28
31
 
29
- def quote_table_name(table_name)
30
- return table_name if table_name =~ /^\[.*\]$/
31
- quote_column_name(table_name)
32
+ def quote_table_name(name)
33
+ quote_column_name(name)
32
34
  end
33
35
 
34
36
  def quoted_true
35
- '1'
37
+ QUOTED_TRUE
36
38
  end
37
39
 
38
40
  def quoted_false
39
- '0'
41
+ QUOTED_FALSE
40
42
  end
41
43
 
42
44
  def quoted_date(value)
@@ -4,27 +4,7 @@ module ActiveRecord
4
4
  module SchemaStatements
5
5
 
6
6
  def native_database_types
7
- {
8
- :primary_key => "int NOT NULL IDENTITY(1,1) PRIMARY KEY",
9
- :string => { :name => native_string_database_type, :limit => 255 },
10
- :text => { :name => native_text_database_type },
11
- :integer => { :name => "int", :limit => 4 },
12
- :float => { :name => "float", :limit => 8 },
13
- :decimal => { :name => "decimal" },
14
- :datetime => { :name => "datetime" },
15
- :timestamp => { :name => "datetime" },
16
- :time => { :name => native_time_database_type },
17
- :date => { :name => native_date_database_type },
18
- :binary => { :name => native_binary_database_type },
19
- :boolean => { :name => "bit"},
20
- # These are custom types that may move somewhere else for good schema_dumper.rb hacking to output them.
21
- :char => { :name => 'char' },
22
- :varchar_max => { :name => 'varchar(max)' },
23
- :nchar => { :name => "nchar" },
24
- :nvarchar => { :name => "nvarchar", :limit => 255 },
25
- :nvarchar_max => { :name => "nvarchar(max)" },
26
- :ntext => { :name => "ntext" }
27
- }
7
+ ActiveRecord::ConnectionAdapters::SQLServerAdapter::NATIVE_DATABASE_TYPES
28
8
  end
29
9
 
30
10
  def tables(name = nil)
@@ -167,6 +147,31 @@ module ActiveRecord
167
147
 
168
148
  # === SQLServer Specific ======================================== #
169
149
 
150
+ def initialize_native_database_types
151
+ return if defined?(ActiveRecord::ConnectionAdapters::SQLServerAdapter::NATIVE_DATABASE_TYPES)
152
+ ActiveRecord::ConnectionAdapters::SQLServerAdapter.const_set(:NATIVE_DATABASE_TYPES,{
153
+ :primary_key => "int NOT NULL IDENTITY(1,1) PRIMARY KEY",
154
+ :string => { :name => native_string_database_type, :limit => 255 },
155
+ :text => { :name => native_text_database_type },
156
+ :integer => { :name => "int", :limit => 4 },
157
+ :float => { :name => "float", :limit => 8 },
158
+ :decimal => { :name => "decimal" },
159
+ :datetime => { :name => "datetime" },
160
+ :timestamp => { :name => "datetime" },
161
+ :time => { :name => native_time_database_type },
162
+ :date => { :name => native_date_database_type },
163
+ :binary => { :name => native_binary_database_type },
164
+ :boolean => { :name => "bit"},
165
+ # These are custom types that may move somewhere else for good schema_dumper.rb hacking to output them.
166
+ :char => { :name => 'char' },
167
+ :varchar_max => { :name => 'varchar(max)' },
168
+ :nchar => { :name => "nchar" },
169
+ :nvarchar => { :name => "nvarchar", :limit => 255 },
170
+ :nvarchar_max => { :name => "nvarchar(max)" },
171
+ :ntext => { :name => "ntext" }
172
+ })
173
+ end
174
+
170
175
  def column_definitions(table_name)
171
176
  db_name = unqualify_db_name(table_name)
172
177
  db_name_with_period = "#{db_name}." if db_name
@@ -330,6 +335,7 @@ module ActiveRecord
330
335
  @sqlserver_columns_cache = {} if reset_columns
331
336
  @sqlserver_views_cache = nil
332
337
  @sqlserver_view_information_cache = {}
338
+ @sqlserver_quoted_column_and_table_names = {}
333
339
  end
334
340
 
335
341
  # === SQLServer Specific (Identity Inserts) ===================== #
@@ -102,7 +102,7 @@ module ActiveRecord
102
102
  end
103
103
 
104
104
  def is_utf8?
105
- sql_type =~ /nvarchar|ntext|nchar/i
105
+ @sql_type =~ /nvarchar|ntext|nchar/i
106
106
  end
107
107
 
108
108
  def default_function
@@ -181,10 +181,13 @@ module ActiveRecord
181
181
  include Sqlserver::Errors
182
182
 
183
183
  ADAPTER_NAME = 'SQLServer'.freeze
184
- VERSION = '3.0.0'.freeze
184
+ VERSION = '3.0.1'.freeze
185
185
  DATABASE_VERSION_REGEXP = /Microsoft SQL Server\s+(\d{4})/
186
186
  SUPPORTED_VERSIONS = [2005,2008].freeze
187
187
 
188
+ attr_reader :database_version, :database_year,
189
+ :connection_supports_native_types
190
+
188
191
  cattr_accessor :native_text_database_type, :native_binary_database_type, :native_string_database_type,
189
192
  :log_info_schema_queries, :enable_default_unicode_types, :auto_connect,
190
193
  :cs_equality_operator
@@ -192,10 +195,13 @@ module ActiveRecord
192
195
  def initialize(logger,config)
193
196
  @connection_options = config
194
197
  connect
195
- super(raw_connection, logger)
198
+ super(@connection, logger)
199
+ @database_version = info_schema_query { select_value('SELECT @@version') }
200
+ @database_year = DATABASE_VERSION_REGEXP.match(@database_version)[1].to_i rescue 0
201
+ initialize_native_database_types
196
202
  initialize_sqlserver_caches
197
203
  use_database
198
- unless SUPPORTED_VERSIONS.include?(database_year)
204
+ unless SUPPORTED_VERSIONS.include?(@database_year)
199
205
  raise NotImplementedError, "Currently, only #{SUPPORTED_VERSIONS.to_sentence} are supported."
200
206
  end
201
207
  end
@@ -249,11 +255,11 @@ module ActiveRecord
249
255
  end
250
256
 
251
257
  def disconnect!
252
- case connection_mode
258
+ case @connection_options[:mode]
253
259
  when :odbc
254
- raw_connection.disconnect rescue nil
260
+ @connection.disconnect rescue nil
255
261
  else :adonet
256
- raw_connection.close rescue nil
262
+ @connection.close rescue nil
257
263
  end
258
264
  end
259
265
 
@@ -274,24 +280,16 @@ module ActiveRecord
274
280
 
275
281
  # === SQLServer Specific (DB Reflection) ======================== #
276
282
 
277
- def database_version
278
- @database_version ||= info_schema_query { select_value('SELECT @@version') }
279
- end
280
-
281
- def database_year
282
- DATABASE_VERSION_REGEXP.match(database_version)[1].to_i
283
- end
284
-
285
283
  def sqlserver?
286
284
  true
287
285
  end
288
286
 
289
287
  def sqlserver_2005?
290
- database_year == 2005
288
+ @database_year == 2005
291
289
  end
292
290
 
293
291
  def sqlserver_2008?
294
- database_year == 2008
292
+ @database_year == 2008
295
293
  end
296
294
 
297
295
  def version
@@ -299,7 +297,7 @@ module ActiveRecord
299
297
  end
300
298
 
301
299
  def inspect
302
- "#<#{self.class} version: #{version}, year: #{database_year}, connection_options: #{@connection_options.inspect}>"
300
+ "#<#{self.class} version: #{version}, year: #{@database_year}, connection_options: #{@connection_options.inspect}>"
303
301
  end
304
302
 
305
303
  def auto_connect
@@ -352,10 +350,24 @@ module ActiveRecord
352
350
 
353
351
  def connect
354
352
  config = @connection_options
355
- @connection = case connection_mode
353
+ @connection = case @connection_options[:mode]
356
354
  when :odbc
357
355
  odbc = ['::ODBC','::ODBC_UTF8','::ODBC_NONE'].detect{ |odbc_ns| odbc_ns.constantize rescue nil }.constantize
358
- odbc.connect config[:dsn], config[:username], config[:password]
356
+ if config[:dsn].include?(';')
357
+ driver = odbc::Driver.new.tap do |d|
358
+ d.name = config[:dsn_name] || 'Driver1'
359
+ driver.attrs = dsn.split(';').map{ |atr| atr.split('=') }.reject{ |kv| kv.size != 2 }.inject({}){ |h,kv| k,v = kv ; h[k] = v ; h }
360
+ end
361
+ odbc::Database.new.drvconnect(driver)
362
+ else
363
+ odbc.connect config[:dsn], config[:username], config[:password]
364
+ end.tap do |c|
365
+ if c.respond_to?(:use_time)
366
+ c.use_time = true
367
+ c.use_utc = ActiveRecord::Base.default_timezone == :utc
368
+ @connection_supports_native_types = true
369
+ end
370
+ end
359
371
  when :adonet
360
372
  System::Data::SqlClient::SqlConnection.new.tap do |connection|
361
373
  connection.connection_string = System::Data::SqlClient::SqlConnectionStringBuilder.new.tap do |cs|
@@ -411,10 +423,6 @@ module ActiveRecord
411
423
  ensure
412
424
  @auto_connecting = false
413
425
  end
414
-
415
- def connection_mode
416
- @connection_options[:mode]
417
- end
418
426
 
419
427
  end #class SQLServerAdapter < AbstractAdapter
420
428
 
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord-sqlserver-adapter
3
3
  version: !ruby/object:Gem::Version
4
- hash: 7
4
+ hash: 5
5
5
  prerelease: false
6
6
  segments:
7
7
  - 3
8
8
  - 0
9
- - 0
10
- version: 3.0.0
9
+ - 1
10
+ version: 3.0.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - Ken Collins
@@ -19,7 +19,7 @@ autorequire:
19
19
  bindir: bin
20
20
  cert_chain: []
21
21
 
22
- date: 2010-08-29 00:00:00 -04:00
22
+ date: 2010-09-15 00:00:00 -04:00
23
23
  default_executable:
24
24
  dependencies:
25
25
  - !ruby/object:Gem::Dependency