activerecord-sqlserver-adapter 2.3.1 → 2.3.2
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +12 -0
- data/README.rdoc +3 -10
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +84 -88
- data/lib/active_record/connection_adapters/sqlserver_adapter/core_ext/active_record.rb +3 -2
- data/lib/active_record/connection_adapters/sqlserver_adapter/core_ext/odbc.rb +41 -0
- data/test/cases/adapter_test_sqlserver.rb +4 -0
- data/test/cases/connection_test_sqlserver.rb +8 -9
- metadata +3 -3
- data/lib/active_record/connection_adapters/sqlserver_adapter/core_ext/dbi.rb +0 -106
data/CHANGELOG
CHANGED
@@ -1,6 +1,18 @@
|
|
1
1
|
|
2
2
|
MASTER
|
3
3
|
|
4
|
+
2.3.2
|
5
|
+
|
6
|
+
* Insert queries that include the word "insert" as a partial column name with the word
|
7
|
+
"id" as a value were falsely being matched as identity inserts. [Sean Caffery/bfabry]
|
8
|
+
|
9
|
+
* Delegate all low level #raw_connection calls to #raw_connection_run and #raw_connection_do
|
10
|
+
which abstract out the low level modes in the connection options at that point. [Ken Collins]
|
11
|
+
|
12
|
+
* Remove DBI dependency and go straight ODBC for speed improvement [Erik Bryn]
|
13
|
+
|
14
|
+
* Leave order by alone when same column crosses two tables [Ransom Briggs]
|
15
|
+
|
4
16
|
|
5
17
|
* 2.3 * (December 1st, 2009)
|
6
18
|
|
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
|
+
* Strict ODBC required! No DBI means around 20% faster!
|
9
10
|
* Now supports SQL Server 2008 too!
|
10
11
|
* Fully tested under 1.9!!! Correctly encodes/decodes UTF-8 types in ruby 1.9 too.
|
11
12
|
* Now supports both rails 2.2 & 2.3!!!
|
@@ -128,24 +129,16 @@ It is our goal to match the adapter version with each version of rails. However
|
|
128
129
|
|
129
130
|
== Installation
|
130
131
|
|
131
|
-
|
132
|
+
You will need Ruby ODBC. If you are using the adapter under 1.9, then you need at least ruby-odbc version 0.9996. Currently ADO modes are not supported since we dropped the unnecessary DBI dependency and transport layer. This was done so we could incorporate other transports such as ADO.NET (w IronRuby) mode in the future or possibly a straight FreeTDS layer. The sky is the limit now and we have a code that can be accept these optional transports. If you are interested in helping, open a ticket and submit a patch. Or start a conversation on the Google Group.
|
132
133
|
|
133
|
-
It should be noted that this version of the adapter was developed using both the ancient 0.0.23 version of DBI up to the current stable release of 0.4.1. Note that DBI 0.4.1 is the minimal for ruby 1.9 compatibility. Because later versions of DBI will be changing many things, IT IS HIGHLY NECESSARY that you max your install to version 0.4.1 which the examples below show. For the time being we are not supporting DBI versions higher than 0.4.1 this they settle down on new internal implementations.
|
134
|
-
|
135
|
-
$ gem install dbi --version 0.4.1
|
136
|
-
$ gem install dbd-odbc --version 0.2.4
|
137
134
|
$ gem install activerecord-sqlserver-adapter
|
138
135
|
|
139
136
|
Optionally configure your gem dependencies in your rails environment.rb file.
|
140
137
|
|
141
|
-
config.gem '
|
142
|
-
config.gem 'dbd-odbc', :version => '0.2.4', :lib => 'dbd/ODBC'
|
143
|
-
config.gem 'activerecord-sqlserver-adapter', :version => 'x.x.xx',
|
144
|
-
:lib => 'active_record/connection_adapters/sqlserver_adapter'
|
138
|
+
config.gem 'activerecord-sqlserver-adapter', :version => 'x.x.xx'
|
145
139
|
|
146
140
|
Here are some external links for libraries and/or tutorials on how to install any other additional components to use this adapter. If you know of a good one that we can include here, just let us know.
|
147
141
|
|
148
|
-
* http://ruby-dbi.sourceforge.net/
|
149
142
|
* http://www.ch-werner.de/rubyodbc/
|
150
143
|
|
151
144
|
|
@@ -1,6 +1,5 @@
|
|
1
|
+
require 'active_record'
|
1
2
|
require 'active_record/connection_adapters/abstract_adapter'
|
2
|
-
require_library_or_gem 'dbi' unless defined?(DBI)
|
3
|
-
require 'active_record/connection_adapters/sqlserver_adapter/core_ext/dbi'
|
4
3
|
require 'active_record/connection_adapters/sqlserver_adapter/core_ext/active_record'
|
5
4
|
require 'base64'
|
6
5
|
|
@@ -9,21 +8,22 @@ module ActiveRecord
|
|
9
8
|
class Base
|
10
9
|
|
11
10
|
def self.sqlserver_connection(config) #:nodoc:
|
12
|
-
config.symbolize_keys!
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
11
|
+
config = config.dup.symbolize_keys!
|
12
|
+
config.reverse_merge! :mode => :odbc, :host => 'localhost', :username => 'sa', :password => ''
|
13
|
+
mode = config[:mode].to_s.downcase.underscore.to_sym
|
14
|
+
case mode
|
15
|
+
when :odbc
|
16
|
+
require_library_or_gem 'odbc' unless defined?(ODBC)
|
17
|
+
require 'active_record/connection_adapters/sqlserver_adapter/core_ext/odbc'
|
18
|
+
raise ArgumentError, 'Missing :dsn configuration.' unless config.has_key?(:dsn)
|
19
|
+
config = config.slice :dsn, :username, :password
|
20
|
+
when :ado
|
21
|
+
raise NotImplementedError, 'Please use version 2.3.1 of the adapter for ADO connections. Future versions may support ADO.NET.'
|
22
|
+
raise ArgumentError, 'Missing :database configuration.' unless config.has_key?(:database)
|
20
23
|
else
|
21
|
-
raise ArgumentError, "
|
22
|
-
database = config[:database]
|
23
|
-
host = config[:host] ? config[:host].to_s : 'localhost'
|
24
|
-
driver_url = "DBI:ADO:Provider=SQLOLEDB;Data Source=#{host};Initial Catalog=#{database};User ID=#{username};Password=#{password};"
|
24
|
+
raise ArgumentError, "Unknown connection mode in #{config.inspect}."
|
25
25
|
end
|
26
|
-
ConnectionAdapters::SQLServerAdapter.new(logger,
|
26
|
+
ConnectionAdapters::SQLServerAdapter.new(logger,config.merge(:mode=>mode))
|
27
27
|
end
|
28
28
|
|
29
29
|
protected
|
@@ -147,53 +147,30 @@ module ActiveRecord
|
|
147
147
|
|
148
148
|
end #SQLServerColumn
|
149
149
|
|
150
|
-
# In
|
151
|
-
#
|
152
|
-
#
|
153
|
-
# This mode also relies on the ADO support in the DBI module. If you are using the
|
154
|
-
# one-click installer of Ruby, then you already have DBI installed, but the ADO module
|
155
|
-
# is *NOT* installed. You will need to get the latest source distribution of Ruby-DBI
|
156
|
-
# from http://ruby-dbi.sourceforge.net/ unzip it, and copy the file from
|
157
|
-
# <tt>src/lib/dbd_ado/ADO.rb</tt> to <tt>X:/Ruby/lib/ruby/site_ruby/1.8/DBD/ADO/ADO.rb</tt>
|
158
|
-
#
|
159
|
-
# You will more than likely need to create the ADO directory. Once you've installed
|
160
|
-
# that file, you are ready to go.
|
161
|
-
#
|
162
|
-
# In ODBC mode, the adapter requires the ODBC support in the DBI module which requires
|
163
|
-
# the Ruby ODBC module. Ruby ODBC 0.996 was used in development and testing,
|
164
|
-
# and it is available at http://www.ch-werner.de/rubyodbc/
|
150
|
+
# In ODBC mode, the adapter requires Ruby ODBC and requires that you specify
|
151
|
+
# a :dsn option. Ruby ODBC is available at http://www.ch-werner.de/rubyodbc/
|
165
152
|
#
|
166
153
|
# Options:
|
167
154
|
#
|
168
|
-
# * <tt>:mode</tt> -- ADO or ODBC. Defaults to ADO.
|
169
155
|
# * <tt>:username</tt> -- Defaults to sa.
|
170
|
-
# * <tt>:password</tt> -- Defaults to
|
171
|
-
# * <tt>:
|
172
|
-
#
|
173
|
-
# ADO specific options:
|
174
|
-
#
|
175
|
-
# * <tt>:host</tt> -- Defaults to localhost.
|
176
|
-
# * <tt>:database</tt> -- The name of the database. No default, must be provided.
|
177
|
-
# * <tt>:windows_auth</tt> -- Use windows authentication instead of username/password.
|
178
|
-
#
|
179
|
-
# ODBC specific options:
|
180
|
-
#
|
181
|
-
# * <tt>:dsn</tt> -- Defaults to nothing.
|
156
|
+
# * <tt>:password</tt> -- Defaults to blank string.
|
157
|
+
# * <tt>:dsn</tt> -- An ODBC DSN. (required)
|
182
158
|
#
|
183
159
|
class SQLServerAdapter < AbstractAdapter
|
184
160
|
|
185
|
-
ADAPTER_NAME
|
186
|
-
VERSION
|
187
|
-
DATABASE_VERSION_REGEXP
|
188
|
-
SUPPORTED_VERSIONS
|
189
|
-
LIMITABLE_TYPES
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
161
|
+
ADAPTER_NAME = 'SQLServer'.freeze
|
162
|
+
VERSION = '2.3.2'.freeze
|
163
|
+
DATABASE_VERSION_REGEXP = /Microsoft SQL Server\s+(\d{4})/
|
164
|
+
SUPPORTED_VERSIONS = [2000,2005,2008].freeze
|
165
|
+
LIMITABLE_TYPES = ['string','integer','float','char','nchar','varchar','nvarchar'].freeze
|
166
|
+
LOST_CONNECTION_EXCEPTIONS = {
|
167
|
+
:odbc => ['ODBC::Error'],
|
168
|
+
:ado => []
|
169
|
+
}
|
170
|
+
LOST_CONNECTION_MESSAGES = {
|
171
|
+
:odbc => [/link failure/, /server failed/, /connection was already closed/, /invalid handle/i],
|
172
|
+
:ado => []
|
173
|
+
}
|
197
174
|
|
198
175
|
cattr_accessor :native_text_database_type, :native_binary_database_type, :native_string_database_type,
|
199
176
|
:log_info_schema_queries, :enable_default_unicode_types, :auto_connect
|
@@ -206,8 +183,8 @@ module ActiveRecord
|
|
206
183
|
|
207
184
|
end
|
208
185
|
|
209
|
-
def initialize(logger,
|
210
|
-
@connection_options =
|
186
|
+
def initialize(logger,config)
|
187
|
+
@connection_options = config
|
211
188
|
connect
|
212
189
|
super(raw_connection, logger)
|
213
190
|
initialize_sqlserver_caches
|
@@ -349,9 +326,9 @@ module ActiveRecord
|
|
349
326
|
# CONNECTION MANAGEMENT ====================================#
|
350
327
|
|
351
328
|
def active?
|
352
|
-
|
329
|
+
raw_connection_do("SELECT 1")
|
353
330
|
true
|
354
|
-
rescue *
|
331
|
+
rescue *lost_connection_exceptions
|
355
332
|
false
|
356
333
|
end
|
357
334
|
|
@@ -365,8 +342,28 @@ module ActiveRecord
|
|
365
342
|
raw_connection.disconnect rescue nil
|
366
343
|
end
|
367
344
|
|
345
|
+
def raw_connection_run(sql)
|
346
|
+
with_auto_reconnect do
|
347
|
+
case connection_mode
|
348
|
+
when :odbc
|
349
|
+
block_given? ? raw_connection.run_block(sql) { |handle| yield(handle) } : raw_connection.run(sql)
|
350
|
+
else :ado
|
351
|
+
|
352
|
+
end
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
def raw_connection_do(sql)
|
357
|
+
case connection_mode
|
358
|
+
when :odbc
|
359
|
+
raw_connection.do(sql)
|
360
|
+
else :ado
|
361
|
+
|
362
|
+
end
|
363
|
+
end
|
364
|
+
|
368
365
|
def finish_statement_handle(handle)
|
369
|
-
handle.
|
366
|
+
handle.drop if handle && handle.respond_to?(:drop) && !handle.finished?
|
370
367
|
handle
|
371
368
|
end
|
372
369
|
|
@@ -771,22 +768,35 @@ module ActiveRecord
|
|
771
768
|
# CONNECTION MANAGEMENT ====================================#
|
772
769
|
|
773
770
|
def connect
|
774
|
-
|
775
|
-
@connection =
|
776
|
-
|
771
|
+
config = @connection_options
|
772
|
+
@connection = case connection_mode
|
773
|
+
when :odbc
|
774
|
+
ODBC.connect config[:dsn], config[:username], config[:password]
|
775
|
+
when :ado
|
776
|
+
|
777
|
+
end
|
777
778
|
rescue
|
778
779
|
raise unless @auto_connecting
|
779
780
|
end
|
780
781
|
|
781
|
-
def
|
782
|
-
|
782
|
+
def connection_mode
|
783
|
+
@connection_options[:mode]
|
784
|
+
end
|
785
|
+
|
786
|
+
def lost_connection_exceptions
|
787
|
+
exceptions = LOST_CONNECTION_EXCEPTIONS[connection_mode]
|
788
|
+
@lost_connection_exceptions ||= exceptions ? exceptions.map(&:constantize) : []
|
789
|
+
end
|
790
|
+
|
791
|
+
def lost_connection_messages
|
792
|
+
LOST_CONNECTION_MESSAGES[connection_mode]
|
783
793
|
end
|
784
794
|
|
785
795
|
def with_auto_reconnect
|
786
796
|
begin
|
787
797
|
yield
|
788
|
-
rescue *
|
789
|
-
if
|
798
|
+
rescue *lost_connection_exceptions => e
|
799
|
+
if lost_connection_messages.any? { |lcm| e.message =~ lcm }
|
790
800
|
retry if auto_reconnected?
|
791
801
|
end
|
792
802
|
raise
|
@@ -837,36 +847,22 @@ module ActiveRecord
|
|
837
847
|
end
|
838
848
|
|
839
849
|
def raw_execute(sql, name = nil, &block)
|
840
|
-
log(sql,
|
841
|
-
if block_given?
|
842
|
-
with_auto_reconnect { raw_connection.execute(sql) { |handle| yield(handle) } }
|
843
|
-
else
|
844
|
-
with_auto_reconnect { raw_connection.execute(sql) }
|
845
|
-
end
|
846
|
-
end
|
847
|
-
end
|
848
|
-
|
849
|
-
def without_type_conversion
|
850
|
-
raw_connection.convert_types = false if raw_connection.respond_to?(:convert_types=)
|
851
|
-
yield
|
852
|
-
ensure
|
853
|
-
raw_connection.convert_types = true if raw_connection.respond_to?(:convert_types=)
|
850
|
+
log(sql,name) { raw_connection_run(sql) }
|
854
851
|
end
|
855
852
|
|
856
853
|
def do_execute(sql,name=nil)
|
857
854
|
log(sql, name || 'EXECUTE') do
|
858
|
-
with_auto_reconnect {
|
855
|
+
with_auto_reconnect { raw_connection_do(sql) }
|
859
856
|
end
|
860
857
|
end
|
861
858
|
|
862
859
|
def raw_select(sql, name = nil)
|
863
860
|
handle = raw_execute(sql,name)
|
864
|
-
fields = handle.
|
861
|
+
fields = handle.columns(true).map{|c|c.name}
|
865
862
|
results = handle_as_array(handle)
|
866
863
|
rows = results.inject([]) do |rows,row|
|
867
864
|
row.each_with_index do |value, i|
|
868
|
-
|
869
|
-
if value.is_a? DBI::Timestamp
|
865
|
+
if value.is_a? ODBC::TimeStamp
|
870
866
|
row[i] = value.to_sqlserver_string
|
871
867
|
end
|
872
868
|
end
|
@@ -946,7 +942,7 @@ module ActiveRecord
|
|
946
942
|
if insert_sql?(sql)
|
947
943
|
table_name = get_table_name(sql)
|
948
944
|
id_column = identity_column(table_name)
|
949
|
-
id_column && sql =~
|
945
|
+
id_column && sql =~ /^\s*INSERT[^(]+\([^)]*\b(#{id_column.name})\b,?[^)]*\)/i ? quote_table_name(table_name) : false
|
950
946
|
else
|
951
947
|
false
|
952
948
|
end
|
@@ -1053,7 +1049,7 @@ module ActiveRecord
|
|
1053
1049
|
WHERE columns.TABLE_NAME = '#{table_name}'
|
1054
1050
|
ORDER BY columns.ordinal_position
|
1055
1051
|
}.gsub(/[ \t\r\n]+/,' ')
|
1056
|
-
results = info_schema_query {
|
1052
|
+
results = info_schema_query { select(sql,nil,true) }
|
1057
1053
|
results.collect do |ci|
|
1058
1054
|
ci.symbolize_keys!
|
1059
1055
|
ci[:type] = case ci[:type]
|
@@ -1070,7 +1066,7 @@ module ActiveRecord
|
|
1070
1066
|
real_table_name = table_name_or_views_table_name(table_name)
|
1071
1067
|
real_column_name = views_real_column_name(table_name,ci[:name])
|
1072
1068
|
col_default_sql = "SELECT c.COLUMN_DEFAULT FROM INFORMATION_SCHEMA.COLUMNS c WHERE c.TABLE_NAME = '#{real_table_name}' AND c.COLUMN_NAME = '#{real_column_name}'"
|
1073
|
-
ci[:default_value] = info_schema_query {
|
1069
|
+
ci[:default_value] = info_schema_query { select_value(col_default_sql) }
|
1074
1070
|
end
|
1075
1071
|
ci[:default_value] = case ci[:default_value]
|
1076
1072
|
when nil, '(null)', '(NULL)'
|
@@ -83,10 +83,11 @@ module ActiveRecord
|
|
83
83
|
else
|
84
84
|
[nil, ord_tn_and_cn.first]
|
85
85
|
end
|
86
|
-
|
86
|
+
unique_key = [(ord_table_name || select_table_name), ord_column_name]
|
87
|
+
if unique_order_hash[unique_key]
|
87
88
|
array
|
88
89
|
else
|
89
|
-
unique_order_hash[
|
90
|
+
unique_order_hash[unique_key] = true
|
90
91
|
array << "#{ord} #{dir}".strip
|
91
92
|
end
|
92
93
|
end.join(', ')
|
@@ -0,0 +1,41 @@
|
|
1
|
+
|
2
|
+
module ActiveRecord
|
3
|
+
module ConnectionAdapters
|
4
|
+
module SQLServerCoreExtensions
|
5
|
+
module ODBC
|
6
|
+
|
7
|
+
module TimeStamp
|
8
|
+
def to_sqlserver_string
|
9
|
+
date, time, nanoseconds = to_s.split(' ')
|
10
|
+
"#{date} #{time}.#{sprintf("%03d",nanoseconds.to_i/1000000)}"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module Statement
|
15
|
+
def finished?
|
16
|
+
begin
|
17
|
+
connected?
|
18
|
+
false
|
19
|
+
rescue ::ODBC::Error => e
|
20
|
+
true
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
module Database
|
27
|
+
def run_block(*args)
|
28
|
+
yield sth = run(*args)
|
29
|
+
sth.drop
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
ODBC::TimeStamp.send :include, ActiveRecord::ConnectionAdapters::SQLServerCoreExtensions::ODBC::TimeStamp if defined?(ODBC::TimeStamp)
|
39
|
+
ODBC::Statement.send :include, ActiveRecord::ConnectionAdapters::SQLServerCoreExtensions::ODBC::Statement if defined?(ODBC::Statement)
|
40
|
+
ODBC::Database.send :include, ActiveRecord::ConnectionAdapters::SQLServerCoreExtensions::ODBC::Database if defined?(ODBC::Database)
|
41
|
+
|
@@ -218,6 +218,10 @@ class AdapterTestSqlserver < ActiveRecord::TestCase
|
|
218
218
|
assert_equal 'MIN(comments.id) DESC, MIN(comments.post_id) ASC', order_to_min_set(@two_orders_with_desc_and_asc)
|
219
219
|
end
|
220
220
|
|
221
|
+
should 'leave order by alone when same column crosses two tables' do
|
222
|
+
assert_equal ' ORDER BY developers.name, projects.name', add_order!('developers.name, projects.name')
|
223
|
+
end
|
224
|
+
|
221
225
|
end
|
222
226
|
|
223
227
|
context 'with different language' do
|
@@ -12,21 +12,21 @@ class ConnectionTestSqlserver < ActiveRecord::TestCase
|
|
12
12
|
end
|
13
13
|
|
14
14
|
|
15
|
-
should 'return finished
|
15
|
+
should 'return finished ODBC statment handle from #execute without block' do
|
16
16
|
handle = @connection.execute('SELECT * FROM [topics]')
|
17
|
-
assert_instance_of
|
17
|
+
assert_instance_of ODBC::Statement, handle
|
18
18
|
assert handle.finished?
|
19
19
|
end
|
20
20
|
|
21
|
-
should 'finish
|
21
|
+
should 'finish ODBC statment handle from #execute with block' do
|
22
22
|
assert_all_statements_used_are_closed do
|
23
23
|
@connection.execute('SELECT * FROM [topics]') { }
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
-
should 'return an unfinished
|
27
|
+
should 'return an unfinished ODBC statement handler from #raw_execute' do
|
28
28
|
handle = @connection.send(:raw_execute,'SELECT * FROM [topics]')
|
29
|
-
assert_instance_of
|
29
|
+
assert_instance_of ODBC::Statement, handle
|
30
30
|
assert !handle.finished?
|
31
31
|
end
|
32
32
|
|
@@ -37,7 +37,6 @@ class ConnectionTestSqlserver < ActiveRecord::TestCase
|
|
37
37
|
end
|
38
38
|
|
39
39
|
should 'affect rows' do
|
40
|
-
assert Topic.connection.instance_variable_get("@connection")["AutoCommit"]
|
41
40
|
topic_data = { 1 => { "content" => "1 updated" }, 2 => { "content" => "2 updated" } }
|
42
41
|
updated = Topic.update(topic_data.keys, topic_data.values)
|
43
42
|
assert_equal 2, updated.size
|
@@ -114,15 +113,15 @@ class ConnectionTestSqlserver < ActiveRecord::TestCase
|
|
114
113
|
|
115
114
|
def assert_all_statements_used_are_closed(&block)
|
116
115
|
existing_handles = []
|
117
|
-
ObjectSpace.each_object(
|
116
|
+
ObjectSpace.each_object(ODBC::Statement) {|handle| existing_handles << handle}
|
118
117
|
GC.disable
|
119
118
|
yield
|
120
119
|
used_handles = []
|
121
|
-
ObjectSpace.each_object(
|
120
|
+
ObjectSpace.each_object(ODBC::Statement) {|handle| used_handles << handle unless existing_handles.include? handle}
|
122
121
|
assert_block "No statements were used within given block" do
|
123
122
|
used_handles.size > 0
|
124
123
|
end
|
125
|
-
ObjectSpace.each_object(
|
124
|
+
ObjectSpace.each_object(ODBC::Statement) do |handle|
|
126
125
|
assert_block "Statement should have been closed within given block" do
|
127
126
|
handle.finished?
|
128
127
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord-sqlserver-adapter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.3.
|
4
|
+
version: 2.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ken Collins
|
@@ -13,7 +13,7 @@ autorequire:
|
|
13
13
|
bindir: bin
|
14
14
|
cert_chain: []
|
15
15
|
|
16
|
-
date:
|
16
|
+
date: 2010-02-15 00:00:00 -05:00
|
17
17
|
default_executable:
|
18
18
|
dependencies: []
|
19
19
|
|
@@ -37,7 +37,7 @@ files:
|
|
37
37
|
- lib/activerecord-sqlserver-adapter.rb
|
38
38
|
- lib/active_record/connection_adapters/sqlserver_adapter.rb
|
39
39
|
- lib/active_record/connection_adapters/sqlserver_adapter/core_ext/active_record.rb
|
40
|
-
- lib/active_record/connection_adapters/sqlserver_adapter/core_ext/
|
40
|
+
- lib/active_record/connection_adapters/sqlserver_adapter/core_ext/odbc.rb
|
41
41
|
has_rdoc: true
|
42
42
|
homepage: http://github.com/rails-sqlserver
|
43
43
|
licenses: []
|
@@ -1,106 +0,0 @@
|
|
1
|
-
|
2
|
-
module ActiveRecord
|
3
|
-
module ConnectionAdapters
|
4
|
-
module SQLServerCoreExtensions
|
5
|
-
|
6
|
-
|
7
|
-
module DBI
|
8
|
-
|
9
|
-
module Timestamp
|
10
|
-
# Deprecated DBI. See documentation for Type::SqlserverTimestamp which
|
11
|
-
# this method tries to mimic as ODBC is still going to convert SQL Server
|
12
|
-
# milliconds to whole number representation of nanoseconds.
|
13
|
-
def to_sqlserver_string
|
14
|
-
datetime, nanoseconds = to_s.split('.')
|
15
|
-
"#{datetime}.#{sprintf("%03d",nanoseconds.to_i/1000000)}"
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
module Type
|
20
|
-
|
21
|
-
# Make sure we get DBI::Type::Timestamp returning a string NOT a time object
|
22
|
-
# that represents what is in the DB before type casting while letting core
|
23
|
-
# ActiveRecord do the reset. It is assumed that DBI is using ODBC connections
|
24
|
-
# and that ODBC::Timestamp is taking the native milliseconds that SQL Server
|
25
|
-
# stores and returning them incorrect using ODBC::Timestamp#fraction which is
|
26
|
-
# nanoseconds. Below shows the incorrect ODBC::Timestamp represented by DBI
|
27
|
-
# and the conversion we expect to have in the DB before type casting.
|
28
|
-
#
|
29
|
-
# "1985-04-15 00:00:00 0" # => "1985-04-15 00:00:00.000"
|
30
|
-
# "2008-11-08 10:24:36 30000000" # => "2008-11-08 10:24:36.003"
|
31
|
-
# "2008-11-08 10:24:36 123000000" # => "2008-11-08 10:24:36.123"
|
32
|
-
class SqlserverTimestamp
|
33
|
-
def self.parse(obj)
|
34
|
-
return nil if ::DBI::Type::Null.parse(obj).nil?
|
35
|
-
date, time, nanoseconds = obj.split(' ')
|
36
|
-
"#{date} #{time}.#{sprintf("%03d",nanoseconds.to_i/1000000)}"
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
# The adapter and rails will parse our floats, decimals, and money field correctly
|
41
|
-
# from a string. Do not let the DBI::Type classes create Float/BigDecimal objects
|
42
|
-
# for us. Trust rails .type_cast to do what it is built to do.
|
43
|
-
class SqlserverForcedString
|
44
|
-
def self.parse(obj)
|
45
|
-
return nil if ::DBI::Type::Null.parse(obj).nil?
|
46
|
-
obj.to_s
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
# We want our true 1 to 255 tinyint range.
|
51
|
-
class SqlserverForcedTinyint
|
52
|
-
def self.parse(obj)
|
53
|
-
return nil if ::DBI::Type::Null.parse(obj).nil?
|
54
|
-
obj.to_i
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
end
|
59
|
-
|
60
|
-
module TypeUtil
|
61
|
-
|
62
|
-
def self.included(klass)
|
63
|
-
klass.extend ClassMethods
|
64
|
-
class << klass
|
65
|
-
alias_method_chain :type_name_to_module, :sqlserver_types
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
module ClassMethods
|
70
|
-
|
71
|
-
# Capture all types classes that we need to handle directly for SQL Server
|
72
|
-
# and allow normal processing for those that we do not.
|
73
|
-
def type_name_to_module_with_sqlserver_types(type_name)
|
74
|
-
case type_name
|
75
|
-
when /^timestamp$/i
|
76
|
-
DBI::Type::SqlserverTimestamp
|
77
|
-
when /^float|decimal|money$/i
|
78
|
-
DBI::Type::SqlserverForcedString
|
79
|
-
when /^tinyint$/i
|
80
|
-
DBI::Type::SqlserverForcedTinyint
|
81
|
-
else
|
82
|
-
type_name_to_module_without_sqlserver_types(type_name)
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
end
|
87
|
-
|
88
|
-
end
|
89
|
-
|
90
|
-
end
|
91
|
-
|
92
|
-
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
if defined?(DBI::TypeUtil)
|
101
|
-
DBI::Type.send :include, ActiveRecord::ConnectionAdapters::SQLServerCoreExtensions::DBI::Type
|
102
|
-
DBI::TypeUtil.send :include, ActiveRecord::ConnectionAdapters::SQLServerCoreExtensions::DBI::TypeUtil
|
103
|
-
elsif defined?(DBI::Timestamp) # DEPRECATED in DBI 0.4.0 and above. Remove when 0.2.2 and lower is no longer supported.
|
104
|
-
DBI::Timestamp.send :include, ActiveRecord::ConnectionAdapters::SQLServerCoreExtensions::DBI::Timestamp
|
105
|
-
end
|
106
|
-
|