activerecord-sqlserver-adapter 2.3.11 → 2.3.12

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,4 +1,15 @@
1
1
 
2
+ * 2.3.12 *
3
+
4
+ * Add multiple results set support with #execute_procedure for :dblib mode. [Ken Collins]
5
+
6
+ * Allow unicode conditions strings to be quoted correctly. Like 3.0 branch. [Ken Collins]
7
+
8
+ * Simplify encoding support. [Ken Collins]
9
+
10
+ * Add binary timestamp datatype handling. [Erik Bryn]
11
+
12
+
2
13
  * 2.3.11
3
14
 
4
15
  * Add TinyTds/dblib connection mode. [Ken Collins]
data/README.rdoc CHANGED
@@ -6,6 +6,7 @@ The SQL Server adapter for rails is back for ActiveRecord 2.2 and up! We are cur
6
6
 
7
7
  == What's New
8
8
 
9
+ * New dblib connection mode using TinyTds!
9
10
  * Integration with rails :db namespaced rake tasks.
10
11
  * IronRuby support using ADONET connection mode.
11
12
  * Direct ODBC mode. No DBI anymore, means around 20% faster!
@@ -54,38 +54,16 @@ module ActiveRecord
54
54
 
55
55
  class << self
56
56
 
57
- def string_to_utf8_encoding(value)
58
- value.force_encoding('UTF-8') rescue value
59
- end
60
-
61
57
  def string_to_binary(value)
62
- value = value.dup.force_encoding(Encoding::BINARY) if value.respond_to?(:force_encoding)
63
58
  "0x#{value.unpack("H*")[0]}"
64
59
  end
65
60
 
66
61
  def binary_to_string(value)
67
- value = value.dup.force_encoding(Encoding::BINARY) if value.respond_to?(:force_encoding)
68
62
  value =~ /[^[:xdigit:]]/ ? value : [value].pack('H*')
69
63
  end
70
64
 
71
65
  end
72
66
 
73
- def type_cast(value)
74
- if value && type == :string && is_utf8?
75
- self.class.string_to_utf8_encoding(value)
76
- else
77
- super
78
- end
79
- end
80
-
81
- def type_cast_code(var_name)
82
- if type == :string && is_utf8?
83
- "#{self.class.name}.string_to_utf8_encoding(#{var_name})"
84
- else
85
- super
86
- end
87
- end
88
-
89
67
  def is_identity?
90
68
  @sqlserver_options[:is_identity]
91
69
  end
@@ -146,6 +124,7 @@ module ActiveRecord
146
124
  when /uniqueidentifier/i then :string
147
125
  when /datetime/i then simplified_datetime
148
126
  when /varchar\(max\)/ then :text
127
+ when /timestamp/ then :binary
149
128
  else super
150
129
  end
151
130
  end
@@ -164,19 +143,11 @@ module ActiveRecord
164
143
 
165
144
  end #SQLServerColumn
166
145
 
167
- # In ODBC mode, the adapter requires Ruby ODBC and requires that you specify
168
- # a :dsn option. Ruby ODBC is available at http://www.ch-werner.de/rubyodbc/
169
- #
170
- # Options:
171
- #
172
- # * <tt>:username</tt> -- Defaults to sa.
173
- # * <tt>:password</tt> -- Defaults to blank string.
174
- # * <tt>:dsn</tt> -- An ODBC DSN. (required)
175
- #
146
+
176
147
  class SQLServerAdapter < AbstractAdapter
177
148
 
178
149
  ADAPTER_NAME = 'SQLServer'.freeze
179
- VERSION = '2.3.11'.freeze
150
+ VERSION = '2.3.12'.freeze
180
151
  DATABASE_VERSION_REGEXP = /Microsoft SQL Server\s+(\d{4})/
181
152
  SUPPORTED_VERSIONS = [2000,2005,2008].freeze
182
153
  LIMITABLE_TYPES = ['string','integer','float','char','nchar','varchar','nvarchar'].to_set.freeze
@@ -298,8 +269,9 @@ module ActiveRecord
298
269
  when String, ActiveSupport::Multibyte::Chars
299
270
  if column && column.type == :binary
300
271
  column.class.string_to_binary(value)
301
- elsif column && column.respond_to?(:is_utf8?) && column.is_utf8?
302
- quoted_utf8_value(value)
272
+ # elsif column && column.type == :string
273
+ elsif value.is_utf8? || (column && column.type == :string)
274
+ "N'#{quote_string(value)}'"
303
275
  else
304
276
  super
305
277
  end
@@ -337,10 +309,6 @@ module ActiveRecord
337
309
  end
338
310
  end
339
311
 
340
- def quoted_utf8_value(value)
341
- "N'#{quote_string(value)}'"
342
- end
343
-
344
312
  # REFERENTIAL INTEGRITY ====================================#
345
313
 
346
314
  def disable_referential_integrity
@@ -441,12 +409,17 @@ module ActiveRecord
441
409
  vars = variables.map{ |v| quote(v) }.join(', ')
442
410
  sql = "EXEC #{proc_name} #{vars}".strip
443
411
  name = 'Execute Procedure'
444
- results = []
445
- case @connection_options[:mode]
446
- when :dblib
447
- results << select(sql, name).map { |r| r.with_indifferent_access }
448
- when :odbc
449
- log(sql, name) do
412
+ log(sql, name) do
413
+ case @connection_options[:mode]
414
+ when :dblib
415
+ result = @connection.execute(sql)
416
+ result.each(:as => :hash, :cache_rows => true) do |row|
417
+ r = row.with_indifferent_access
418
+ yield(r) if block_given?
419
+ end
420
+ result.each
421
+ when :odbc
422
+ results = []
450
423
  raw_connection_run(sql) do |handle|
451
424
  get_rows = lambda {
452
425
  rows = handle_to_names_and_values handle, :fetch => :all
@@ -458,11 +431,13 @@ module ActiveRecord
458
431
  get_rows.call
459
432
  end
460
433
  end
434
+ results.many? ? results : results.first
435
+ when :adonet
436
+ results = []
437
+ results << select(sql, name).map { |r| r.with_indifferent_access }
438
+ results.many? ? results : results.first
461
439
  end
462
- when :adonet
463
- results << select(sql, name).map { |r| r.with_indifferent_access }
464
440
  end
465
- results.many? ? results : results.first
466
441
  end
467
442
 
468
443
  def use_database(database=nil)
@@ -1311,7 +1286,8 @@ module ActiveRecord
1311
1286
  :nchar => { :name => "nchar" },
1312
1287
  :nvarchar => { :name => "nvarchar", :limit => 255 },
1313
1288
  :nvarchar_max => { :name => "nvarchar(max)" },
1314
- :ntext => { :name => "ntext" }
1289
+ :ntext => { :name => "ntext" },
1290
+ :ss_timestamp => { :name => 'timestamp'}
1315
1291
  })
1316
1292
  end
1317
1293
 
@@ -161,6 +161,8 @@ class ColumnTestSqlserver < ActiveRecord::TestCase
161
161
  @time = SqlServerChronic.columns_hash['time']
162
162
  @datetime = SqlServerChronic.columns_hash['datetime']
163
163
  @smalldatetime = SqlServerChronic.columns_hash['smalldatetime']
164
+ @timestamp = SqlServerChronic.columns_hash['timestamp']
165
+ @ss_timestamp = SqlServerChronic.columns_hash['ss_timestamp']
164
166
  end
165
167
 
166
168
  should 'have correct simplified type for uncast datetime' do
@@ -184,6 +186,25 @@ class ColumnTestSqlserver < ActiveRecord::TestCase
184
186
  assert_equal nil, @datetime.limit
185
187
  end
186
188
 
189
+ context 'with timestamps' do
190
+
191
+ should 'use datetime sql type when using :timestamp in schema statements' do
192
+ assert_equal :datetime, @timestamp.type
193
+ assert_equal 'datetime', @timestamp.sql_type
194
+ end
195
+
196
+ should 'be able to use real sql server timestamp if you really want to' do
197
+ assert_equal :binary, @ss_timestamp.type
198
+ assert_equal 'timestamp', @ss_timestamp.sql_type
199
+ end
200
+
201
+ should 'return :timestamp as a binaryish string' do
202
+ chronic = SqlServerChronic.create!.reload
203
+ assert_match %r|\000|, chronic.ss_timestamp
204
+ end
205
+
206
+ end
207
+
187
208
  context 'For smalldatetime types' do
188
209
 
189
210
  should 'have created that type using rails migrations' do
@@ -9,34 +9,26 @@ class ExecuteProcedureTestSqlserver < ActiveRecord::TestCase
9
9
  should 'execute a simple procedure' do
10
10
  tables = @klass.execute_procedure :sp_tables
11
11
  assert_instance_of Array, tables
12
- assert_instance_of HashWithIndifferentAccess, tables.first
12
+ assert tables.first.respond_to?(:keys)
13
13
  end
14
14
 
15
15
  should 'take parameter arguments' do
16
16
  tables = @klass.execute_procedure :sp_tables, 'sql_server_chronics'
17
17
  table_info = tables.first
18
18
  assert_equal 1, tables.size
19
- assert_equal (ENV['ARUNIT_DB_NAME'] || 'activerecord_unittest'), table_info[:TABLE_QUALIFIER], "Table Info: #{table_info.inspect}"
20
- assert_equal 'TABLE', table_info[:TABLE_TYPE], "Table Info: #{table_info.inspect}"
19
+ assert_equal (ENV['ARUNIT_DB_NAME'] || 'activerecord_unittest'), table_info['TABLE_QUALIFIER'], "Table Info: #{table_info.inspect}"
20
+ assert_equal 'TABLE', table_info['TABLE_TYPE'], "Table Info: #{table_info.inspect}"
21
21
  end
22
22
 
23
- if connection_mode_odbc?
24
-
25
- should 'allow multiple result sets to be returned' do
26
- results1, results2 = @klass.execute_procedure('sp_helpconstraint','accounts')
27
- assert_instance_of Array, results1
28
- assert_instance_of HashWithIndifferentAccess, results1.first
29
- assert results1.first['Object Name']
30
- assert_instance_of Array, results2
31
- assert_instance_of HashWithIndifferentAccess, results2.first
32
- assert results2.first['constraint_name']
33
- assert results2.first['constraint_type']
34
- end
35
-
36
- else
37
-
38
- should 'allow multiple result sets to be returned'
39
-
23
+ should 'allow multiple result sets to be returned' do
24
+ results1, results2 = @klass.execute_procedure('sp_helpconstraint','accounts')
25
+ assert_instance_of Array, results1
26
+ assert results1.first.respond_to?(:keys)
27
+ assert results1.first['Object Name']
28
+ assert_instance_of Array, results2
29
+ assert results2.first.respond_to?(:keys)
30
+ assert results2.first['constraint_name']
31
+ assert results2.first['constraint_type']
40
32
  end
41
33
 
42
34
 
@@ -106,6 +106,7 @@ module ActiveRecord
106
106
  class << self
107
107
  def connection_mode_dblib? ; ActiveRecord::Base.connection.instance_variable_get(:@connection_options)[:mode] == :dblib ; end
108
108
  def connection_mode_odbc? ; ActiveRecord::Base.connection.instance_variable_get(:@connection_options)[:mode] == :odbc ; end
109
+ def connection_mode_adonet? ; ActiveRecord::Base.connection.instance_variable_get(:@connection_options)[:mode] == :adonet ; end
109
110
  def sqlserver_2000? ; ActiveRecord::Base.connection.sqlserver_2000? ; end
110
111
  def sqlserver_2005? ; ActiveRecord::Base.connection.sqlserver_2005? ; end
111
112
  def sqlserver_2008? ; ActiveRecord::Base.connection.sqlserver_2008? ; end
@@ -125,6 +126,7 @@ module ActiveRecord
125
126
  end
126
127
  def connection_mode_dblib? ; self.class.connection_mode_dblib? ; end
127
128
  def connection_mode_odbc? ; self.class.connection_mode_odbc? ; end
129
+ def connection_mode_adonet? ; self.class.connection_mode_adonet? ; end
128
130
  def sqlserver_2000? ; self.class.sqlserver_2000? ; end
129
131
  def sqlserver_2005? ; self.class.sqlserver_2005? ; end
130
132
  def sqlserver_2008? ; self.class.sqlserver_2008? ; end
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  require 'cases/sqlserver_helper'
2
3
 
3
4
  class UnicodeTestSqlserver < ActiveRecord::TestCase
@@ -29,19 +30,22 @@ class UnicodeTestSqlserver < ActiveRecord::TestCase
29
30
  context 'Testing unicode data' do
30
31
 
31
32
  setup do
32
- @unicode_data = "\344\270\200\344\272\21434\344\272\224\345\205\255"
33
- @encoded_unicode_data = "\344\270\200\344\272\21434\344\272\224\345\205\255".force_encoding('UTF-8') if ruby_19?
33
+ @unicode_data = "\344\270\200\344\272\21434\344\272\224\345\205\255" # "一二34五六"
34
34
  end
35
35
 
36
- should 'insert into nvarchar field' do
36
+ should 'insert and retrieve unicode data' do
37
37
  assert data = SqlServerUnicode.create!(:nvarchar => @unicode_data)
38
- assert_equal @unicode_data, data.reload.nvarchar
38
+ if connection_mode_dblib?
39
+ assert_equal "一二34五六", data.reload.nvarchar
40
+ elsif connection_mode_odbc?
41
+ assert_equal "一二34五六", data.reload.nvarchar, 'perhaps you are not using the utf8 odbc that does this legwork'
42
+ elsif connection_mode_adonet?
43
+ assert_equal "一二34五六", data.reload.nvarchar
44
+ else
45
+ raise 'need to add a case for this'
46
+ end
47
+ assert_equal Encoding.find('UTF-8'), data.nvarchar.encoding if ruby_19?
39
48
  end
40
-
41
- should 're-encode data on DB reads' do
42
- assert data = SqlServerUnicode.create!(:nvarchar => @unicode_data)
43
- assert_equal @encoded_unicode_data, data.reload.nvarchar
44
- end if ruby_19?
45
49
 
46
50
  end
47
51
 
@@ -9,27 +9,10 @@ class ValidationsTest < ActiveRecord::TestCase
9
9
 
10
10
  include SqlserverCoercedTest
11
11
 
12
- # This test is tricky to pass. The validation SQL would generate something like this:
13
- #
14
- # SELECT TOP 1 [events].id FROM [events] WHERE ([events].[title] COLLATE Latin1_General_CS_AS = '一二三四五')
15
- #
16
- # The problem is that we can not change the adapters quote method from this:
17
- #
18
- # elsif column && column.respond_to?(:is_utf8?) && column.is_utf8?
19
- # quoted_utf8_value(value)
20
- #
21
- # To something like this for all quoting like blind bind vars:
22
- #
23
- # elsif value.is_utf8?
24
- # quoted_utf8_value(value)
25
- #
26
- # As it would cause way more errors, sure this piggybacks on ActiveSupport's 1.8/1.9 abstract
27
- # code to infer if the passed in string is indeed a national/unicde type. Perhaps in rails 3
28
- # and using AREL this might get better, but I do not see a solution right now.
29
- #
30
12
  def test_coerced_test_validate_uniqueness_with_limit_and_utf8
31
- assert true
13
+ true
32
14
  end
33
15
 
16
+
34
17
  end
35
18
 
@@ -25,6 +25,7 @@ ActiveRecord::Schema.define do
25
25
  t.column :time, :time
26
26
  t.column :datetime, :datetime
27
27
  t.column :timestamp, :timestamp
28
+ t.column :ss_timestamp, :ss_timestamp
28
29
  t.column :smalldatetime, :smalldatetime
29
30
  end
30
31
 
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: 21
4
+ hash: 27
5
5
  prerelease: false
6
6
  segments:
7
7
  - 2
8
8
  - 3
9
- - 11
10
- version: 2.3.11
9
+ - 12
10
+ version: 2.3.12
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-10-17 00:00:00 -04:00
22
+ date: 2010-10-26 00:00:00 -04:00
23
23
  default_executable:
24
24
  dependencies:
25
25
  - !ruby/object:Gem::Dependency
@@ -30,11 +30,11 @@ dependencies:
30
30
  requirements:
31
31
  - - ~>
32
32
  - !ruby/object:Gem::Version
33
- hash: 5
33
+ hash: 7
34
34
  segments:
35
35
  - 2
36
- - 3
37
- version: "2.3"
36
+ - 2
37
+ version: "2.2"
38
38
  type: :runtime
39
39
  version_requirements: *id001
40
40
  description: SQL Server 2000, 2005 and 2008 Adapter For Rails.