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 +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.
|