activerecord-sqlserver-adapter 2.3.11 → 2.3.12
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 +11 -0
- data/README.rdoc +1 -0
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +24 -48
- data/test/cases/column_test_sqlserver.rb +21 -0
- data/test/cases/execute_procedure_test_sqlserver.rb +12 -20
- data/test/cases/sqlserver_helper.rb +2 -0
- data/test/cases/unicode_test_sqlserver.rb +13 -9
- data/test/cases/validations_test_sqlserver.rb +2 -19
- data/test/schema/sqlserver_specific_schema.rb +1 -0
- metadata +7 -7
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
|
-
|
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.
|
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.
|
302
|
-
|
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
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
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
|
-
|
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[
|
20
|
-
assert_equal 'TABLE', table_info[
|
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
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
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
|
36
|
+
should 'insert and retrieve unicode data' do
|
37
37
|
assert data = SqlServerUnicode.create!(:nvarchar => @unicode_data)
|
38
|
-
|
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
|
-
|
13
|
+
true
|
32
14
|
end
|
33
15
|
|
16
|
+
|
34
17
|
end
|
35
18
|
|
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:
|
4
|
+
hash: 27
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 2
|
8
8
|
- 3
|
9
|
-
-
|
10
|
-
version: 2.3.
|
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-
|
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:
|
33
|
+
hash: 7
|
34
34
|
segments:
|
35
35
|
- 2
|
36
|
-
-
|
37
|
-
version: "2.
|
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.
|