activerecord-sqlserver-adapter 3.0.2 → 3.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,4 +1,9 @@
1
1
 
2
+ * 3.0.3
3
+
4
+ * Add TinyTDS/dblib connection mode. [Ken Collins]
5
+
6
+
2
7
  * 3.0.2
3
8
 
4
9
  * Fix DSN'less code. [Erik Bryn]
@@ -150,14 +150,24 @@ If you’d like to contribute a feature or bugfix, thanks! To make sure your fix
150
150
 
151
151
  Many many people have contributed. If you do not see your name here and it should be let us know. Also, many thanks go out to those that have pledged financial contributions.
152
152
 
153
- * Ken Collins
154
- * Erik Bryn
155
- * Murray Steele
156
- * Shawn Balestracci
157
- * Joe Rafaniello
158
- * Tom Ward
159
-
160
-
153
+ === Contributers
154
+ Up-to-date list of contributors: http://github.com/rails-sqlserver/activerecord-sqlserver-adapter/contributors
155
+
156
+ * metaskills (Ken Collins)
157
+ * h-lame (Murray Steele)
158
+ * vegantech
159
+ * cjheath (Clifford Heath)
160
+ * jrafanie (Joe Rafaniello)
161
+ * nerdrew (Andrew Ryan)
162
+ * snowblink (Jonathan Lim)
163
+ * koppen (Jakob Skjerning)
164
+ * ebryn (Erik Bryn)
165
+ * adzap (Adam Meehan)
166
+ * neomindryan (Ryan Findley)
167
+ * jeremydurham (Jeremy Durham)
168
+
169
+ === Donators
170
+ http://pledgie.com/campaigns/11630
161
171
 
162
172
  == License
163
173
 
@@ -13,8 +13,8 @@ module ActiveRecord
13
13
  end
14
14
 
15
15
  def execute(sql, name = nil, skip_logging = false)
16
- if table_name = query_requires_identity_insert?(sql)
17
- with_identity_insert_enabled(table_name) { do_execute(sql,name) }
16
+ if id_insert_table_name = query_requires_identity_insert?(sql)
17
+ with_identity_insert_enabled(id_insert_table_name) { do_execute(sql,name) }
18
18
  else
19
19
  do_execute(sql,name)
20
20
  end
@@ -71,19 +71,27 @@ module ActiveRecord
71
71
  def execute_procedure(proc_name, *variables)
72
72
  vars = variables.map{ |v| quote(v) }.join(', ')
73
73
  sql = "EXEC #{proc_name} #{vars}".strip
74
+ name = 'Execute Procedure'
74
75
  results = []
75
- log(sql,'Execute Procedure') do
76
- raw_connection_run(sql) do |handle|
77
- get_rows = lambda {
78
- rows = handle_to_names_and_values handle, :fetch => :all
79
- rows.each_with_index { |r,i| rows[i] = r.with_indifferent_access }
80
- results << rows
81
- }
82
- get_rows.call
83
- while handle_more_results?(handle)
76
+ case @connection_options[:mode]
77
+ when :dblib
78
+ results << select(sql, name).map { |r| r.with_indifferent_access }
79
+ when :odbc
80
+ log(sql, name) do
81
+ raw_connection_run(sql) do |handle|
82
+ get_rows = lambda {
83
+ rows = handle_to_names_and_values handle, :fetch => :all
84
+ rows.each_with_index { |r,i| rows[i] = r.with_indifferent_access }
85
+ results << rows
86
+ }
84
87
  get_rows.call
88
+ while handle_more_results?(handle)
89
+ get_rows.call
90
+ end
85
91
  end
86
92
  end
93
+ when :adonet
94
+ results << select(sql, name).map { |r| r.with_indifferent_access }
87
95
  end
88
96
  results.many? ? results : results.first
89
97
  end
@@ -179,12 +187,24 @@ module ActiveRecord
179
187
  end
180
188
 
181
189
  def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
182
- super || select_value("SELECT SCOPE_IDENTITY() AS Ident")
190
+ @insert_sql = true
191
+ case @connection_options[:mode]
192
+ when :dblib
193
+ execute(sql, name) || id_value
194
+ else
195
+ super || select_value("SELECT CAST(SCOPE_IDENTITY() AS bigint) AS Ident")
196
+ end
183
197
  end
184
198
 
185
199
  def update_sql(sql, name = nil)
186
- execute(sql, name)
187
- select_value('SELECT @@ROWCOUNT AS AffectedRows')
200
+ @update_sql = true
201
+ case @connection_options[:mode]
202
+ when :dblib
203
+ execute(sql, name)
204
+ else
205
+ execute(sql, name)
206
+ select_value('SELECT @@ROWCOUNT AS AffectedRows')
207
+ end
188
208
  end
189
209
 
190
210
  # === SQLServer Specific ======================================== #
@@ -204,11 +224,16 @@ module ActiveRecord
204
224
 
205
225
  def raw_connection_do(sql)
206
226
  case @connection_options[:mode]
227
+ when :dblib
228
+ @insert_sql ? @connection.execute(sql).insert : @connection.execute(sql).do
207
229
  when :odbc
208
230
  @connection.do(sql)
209
231
  else :adonet
210
232
  @connection.create_command.tap{ |cmd| cmd.command_text = sql }.execute_non_query
211
233
  end
234
+ ensure
235
+ @insert_sql = false
236
+ @update_sql = false
212
237
  end
213
238
 
214
239
  # === SQLServer Specific (Selecting) ============================ #
@@ -227,6 +252,8 @@ module ActiveRecord
227
252
  def raw_connection_run(sql)
228
253
  with_auto_reconnect do
229
254
  case @connection_options[:mode]
255
+ when :dblib
256
+ @connection.execute(sql)
230
257
  when :odbc
231
258
  block_given? ? @connection.run_block(sql) { |handle| yield(handle) } : @connection.run(sql)
232
259
  else :adonet
@@ -237,6 +264,7 @@ module ActiveRecord
237
264
 
238
265
  def handle_more_results?(handle)
239
266
  case @connection_options[:mode]
267
+ when :dblib
240
268
  when :odbc
241
269
  handle.more_results
242
270
  when :adonet
@@ -246,13 +274,24 @@ module ActiveRecord
246
274
 
247
275
  def handle_to_names_and_values(handle, options={})
248
276
  case @connection_options[:mode]
277
+ when :dblib
278
+ handle_to_names_and_values_dblib(handle, options)
249
279
  when :odbc
250
280
  handle_to_names_and_values_odbc(handle, options)
251
281
  when :adonet
252
282
  handle_to_names_and_values_adonet(handle, options)
253
283
  end
254
284
  end
255
-
285
+
286
+ def handle_to_names_and_values_dblib(handle, options={})
287
+ query_options = {}.tap do |qo|
288
+ qo[:timezone] = ActiveRecord::Base.default_timezone || :utc
289
+ qo[:first] = true if options[:fetch] == :one
290
+ qo[:as] = options[:fetch] == :rows ? :array : :hash
291
+ end
292
+ handle.each(query_options)
293
+ end
294
+
256
295
  def handle_to_names_and_values_odbc(handle, options={})
257
296
  @connection.use_utc = ActiveRecord::Base.default_timezone == :utc if @connection_supports_native_types
258
297
  case options[:fetch]
@@ -351,6 +390,7 @@ module ActiveRecord
351
390
 
352
391
  def finish_statement_handle(handle)
353
392
  case @connection_options[:mode]
393
+ when :dblib
354
394
  when :odbc
355
395
  handle.drop if handle && handle.respond_to?(:drop) && !handle.finished?
356
396
  when :adonet
@@ -8,11 +8,13 @@ module ActiveRecord
8
8
  module Errors
9
9
 
10
10
  LOST_CONNECTION_EXCEPTIONS = {
11
+ :dblib => ['TinyTds::Error'],
11
12
  :odbc => ['ODBC::Error','ODBC_UTF8::Error','ODBC_NONE::Error'],
12
13
  :adonet => ['TypeError','System::Data::SqlClient::SqlException']
13
14
  }.freeze
14
15
 
15
16
  LOST_CONNECTION_MESSAGES = {
17
+ :dblib => [/closed connection/],
16
18
  :odbc => [/link failure/, /server failed/, /connection was already closed/, /invalid handle/i],
17
19
  :adonet => [/current state is closed/, /network-related/]
18
20
  }.freeze
@@ -20,6 +20,9 @@ module ActiveRecord
20
20
  config.reverse_merge! :mode => :odbc, :host => 'localhost', :username => 'sa', :password => ''
21
21
  mode = config[:mode].to_s.downcase.underscore.to_sym
22
22
  case mode
23
+ when :dblib
24
+ raise ArgumentError, 'Missing :dataserver configuration.' unless config.has_key?(:dataserver)
25
+ require_library_or_gem 'tiny_tds'
23
26
  when :odbc
24
27
  raise ArgumentError, 'Missing :dsn configuration.' unless config.has_key?(:dsn)
25
28
  if RUBY_VERSION < '1.9'
@@ -181,7 +184,7 @@ module ActiveRecord
181
184
  include Sqlserver::Errors
182
185
 
183
186
  ADAPTER_NAME = 'SQLServer'.freeze
184
- VERSION = '3.0.2'.freeze
187
+ VERSION = '3.0.3'.freeze
185
188
  DATABASE_VERSION_REGEXP = /Microsoft SQL Server\s+(\d{4})/
186
189
  SUPPORTED_VERSIONS = [2005,2008].freeze
187
190
 
@@ -242,6 +245,15 @@ module ActiveRecord
242
245
  # === Abstract Adapter (Connection Management) ================== #
243
246
 
244
247
  def active?
248
+ connected = case @connection_options[:mode]
249
+ when :dblib
250
+ !@connection.closed?
251
+ when :odbc
252
+ true
253
+ else :adonet
254
+ true
255
+ end
256
+ return false if !connected
245
257
  raw_connection_do("SELECT 1")
246
258
  true
247
259
  rescue *lost_connection_exceptions
@@ -256,6 +268,8 @@ module ActiveRecord
256
268
 
257
269
  def disconnect!
258
270
  case @connection_options[:mode]
271
+ when :dblib
272
+ @connection.close rescue nil
259
273
  when :odbc
260
274
  @connection.disconnect rescue nil
261
275
  else :adonet
@@ -351,6 +365,23 @@ module ActiveRecord
351
365
  def connect
352
366
  config = @connection_options
353
367
  @connection = case @connection_options[:mode]
368
+ when :dblib
369
+ appname = config[:appname] || Rails.application.class.name.split('::').first rescue nil
370
+ encoding = config[:encoding].present? ? config[:encoding] : nil
371
+ TinyTds::Client.new({
372
+ :dataserver => config[:dataserver],
373
+ :username => config[:username],
374
+ :password => config[:password],
375
+ :database => config[:database],
376
+ :appname => appname,
377
+ :login_timeout => config[:dblib_login_timeout],
378
+ :timeout => config[:dblib_timeout],
379
+ :encoding => encoding
380
+ }).tap do |client|
381
+ client.execute("SET ANSI_DEFAULTS ON").do
382
+ client.execute("SET IMPLICIT_TRANSACTIONS OFF").do
383
+ client.execute("SET CURSOR_CLOSE_ON_COMMIT OFF").do
384
+ end
354
385
  when :odbc
355
386
  odbc = ['::ODBC','::ODBC_UTF8','::ODBC_NONE'].detect{ |odbc_ns| odbc_ns.constantize rescue nil }.constantize
356
387
  if config[:dsn].include?(';')
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: 3
4
+ hash: 1
5
5
  prerelease: false
6
6
  segments:
7
7
  - 3
8
8
  - 0
9
- - 2
10
- version: 3.0.2
9
+ - 3
10
+ version: 3.0.3
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-09-21 00:00:00 -04:00
22
+ date: 2010-10-17 00:00:00 -04:00
23
23
  default_executable:
24
24
  dependencies:
25
25
  - !ruby/object:Gem::Dependency