activerecord-sqlserver-adapter 3.0.0 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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