activerecord-sqlserver-adapter 2.2.20 → 2.2.21
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 +10 -0
- data/Manifest +3 -3
- data/Rakefile +2 -2
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +3 -3
- data/lib/active_record/connection_adapters/sqlserver_adapter/core_ext/active_record.rb +150 -0
- data/lib/active_record/connection_adapters/sqlserver_adapter/core_ext/dbi.rb +96 -0
- metadata +7 -7
- data/lib/core_ext/active_record.rb +0 -151
- data/lib/core_ext/dbi.rb +0 -85
data/CHANGELOG
CHANGED
@@ -4,6 +4,16 @@ MASTER
|
|
4
4
|
*
|
5
5
|
|
6
6
|
|
7
|
+
* 2.2.21 * (September 10th, 2009)
|
8
|
+
|
9
|
+
* Changes for gem best practices per http://weblog.rubyonrails.org/2009/9/1/gem-packaging-best-practices
|
10
|
+
Details of such are as follows: [Ken Collins]
|
11
|
+
- Removed rails-sqlserver-2000-2005-adapter.rb load file for old github usage.
|
12
|
+
- Move the core_ext directory to active_record/connection_adapters/sqlserver_adapter/core_ext
|
13
|
+
- Renamespace SQLServerDBI to ActiveRecord::ConnectionAdapters::SQLServerCoreExtensions::DBI
|
14
|
+
- Renamespace ActiveRecord::ConnectionAdapters::SQLServerActiveRecordExtensions to ActiveRecord::ConnectionAdapters::SQLServerCoreExtensions::ActiveRecord
|
15
|
+
|
16
|
+
|
7
17
|
* 2.2.20 * (September 10th, 2009)
|
8
18
|
|
9
19
|
* Implement a new remove_default_constraint method that uses sp_helpconstraint [Ken Collins]
|
data/Manifest
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
CHANGELOG
|
2
|
-
lib/active_record/connection_adapters/sqlserver_adapter.rb
|
3
2
|
lib/activerecord-sqlserver-adapter.rb
|
4
|
-
lib/
|
5
|
-
lib/core_ext/
|
3
|
+
lib/active_record/connection_adapters/sqlserver_adapter.rb
|
4
|
+
lib/active_record/connection_adapters/sqlserver_adapter/core_ext/active_record.rb
|
5
|
+
lib/active_record/connection_adapters/sqlserver_adapter/core_ext/dbi.rb
|
6
6
|
Manifest
|
7
7
|
MIT-LICENSE
|
8
8
|
Rakefile
|
data/Rakefile
CHANGED
@@ -3,7 +3,7 @@ require 'rake'
|
|
3
3
|
require 'rake/testtask'
|
4
4
|
require 'echoe'
|
5
5
|
|
6
|
-
Echoe.new('activerecord-sqlserver-adapter','2.2.
|
6
|
+
Echoe.new('activerecord-sqlserver-adapter','2.2.21') do |p|
|
7
7
|
p.summary = "SQL Server 2000, 2005 and 2008 Adapter For Rails."
|
8
8
|
p.description = "SQL Server 2000, 2005 and 2008 Adapter For Rails."
|
9
9
|
p.author = ["Ken Collins","Murray Steele","Shawn Balestracci","Joe Rafaniello","Tom Ward"]
|
@@ -11,7 +11,7 @@ Echoe.new('activerecord-sqlserver-adapter','2.2.20') do |p|
|
|
11
11
|
p.url = "http://github.com/rails-sqlserver"
|
12
12
|
p.runtime_dependencies = ["dbi =0.4.1","dbd-odbc =0.2.4"]
|
13
13
|
p.include_gemspec = false
|
14
|
-
p.ignore_pattern = ["autotest/*","*.gemspec"
|
14
|
+
p.ignore_pattern = ["autotest/*","*.gemspec"]
|
15
15
|
p.project = 'arsqlserver'
|
16
16
|
end
|
17
17
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'active_record/connection_adapters/abstract_adapter'
|
2
2
|
require_library_or_gem 'dbi' unless defined?(DBI)
|
3
|
-
require 'core_ext/dbi'
|
4
|
-
require 'core_ext/active_record'
|
3
|
+
require 'active_record/connection_adapters/sqlserver_adapter/core_ext/dbi'
|
4
|
+
require 'active_record/connection_adapters/sqlserver_adapter/core_ext/active_record'
|
5
5
|
require 'base64'
|
6
6
|
|
7
7
|
module ActiveRecord
|
@@ -183,7 +183,7 @@ module ActiveRecord
|
|
183
183
|
class SQLServerAdapter < AbstractAdapter
|
184
184
|
|
185
185
|
ADAPTER_NAME = 'SQLServer'.freeze
|
186
|
-
VERSION = '2.2.
|
186
|
+
VERSION = '2.2.21'.freeze
|
187
187
|
DATABASE_VERSION_REGEXP = /Microsoft SQL Server\s+(\d{4})/
|
188
188
|
SUPPORTED_VERSIONS = [2000,2005,2008].freeze
|
189
189
|
LIMITABLE_TYPES = ['string','integer','float','char','nchar','varchar','nvarchar'].freeze
|
@@ -0,0 +1,150 @@
|
|
1
|
+
require 'active_record/version'
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module ConnectionAdapters
|
5
|
+
module SQLServerCoreExtensions
|
6
|
+
|
7
|
+
|
8
|
+
module ActiveRecord
|
9
|
+
|
10
|
+
def self.included(klass)
|
11
|
+
klass.extend ClassMethods
|
12
|
+
class << klass
|
13
|
+
alias_method_chain :reset_column_information, :sqlserver_cache_support
|
14
|
+
alias_method_chain :add_order!, :sqlserver_unique_checking
|
15
|
+
alias_method_chain :add_limit!, :sqlserver_order_checking
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
module ClassMethods
|
20
|
+
|
21
|
+
def execute_procedure(proc_name, *variables)
|
22
|
+
if connection.respond_to?(:execute_procedure)
|
23
|
+
connection.execute_procedure(proc_name,*variables)
|
24
|
+
else
|
25
|
+
[]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def coerce_sqlserver_date(*attributes)
|
30
|
+
write_inheritable_attribute :coerced_sqlserver_date_columns, Set.new(attributes.map(&:to_s))
|
31
|
+
end
|
32
|
+
|
33
|
+
def coerce_sqlserver_time(*attributes)
|
34
|
+
write_inheritable_attribute :coerced_sqlserver_time_columns, Set.new(attributes.map(&:to_s))
|
35
|
+
end
|
36
|
+
|
37
|
+
def coerced_sqlserver_date_columns
|
38
|
+
read_inheritable_attribute(:coerced_sqlserver_date_columns) || []
|
39
|
+
end
|
40
|
+
|
41
|
+
def coerced_sqlserver_time_columns
|
42
|
+
read_inheritable_attribute(:coerced_sqlserver_time_columns) || []
|
43
|
+
end
|
44
|
+
|
45
|
+
def reset_column_information_with_sqlserver_cache_support
|
46
|
+
connection.send(:initialize_sqlserver_caches) if connection.respond_to?(:sqlserver?)
|
47
|
+
reset_column_information_without_sqlserver_cache_support
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def add_limit_with_sqlserver_order_checking!(sql, options, scope = :auto)
|
53
|
+
if connection.respond_to?(:sqlserver?)
|
54
|
+
scope = scope(:find) if :auto == scope
|
55
|
+
if scope
|
56
|
+
options = options.dup
|
57
|
+
scoped_order = scope[:order]
|
58
|
+
order = options[:order]
|
59
|
+
if order && scoped_order
|
60
|
+
options[:order] = add_order_with_sqlserver_unique_checking!('', order, scope).gsub(/^ ORDER BY /,'')
|
61
|
+
elsif scoped_order
|
62
|
+
options[:order] = scoped_order
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
add_limit_without_sqlserver_order_checking!(sql, options, scope)
|
67
|
+
end
|
68
|
+
|
69
|
+
def add_order_with_sqlserver_unique_checking!(sql, order, scope = :auto)
|
70
|
+
if connection.respond_to?(:sqlserver?)
|
71
|
+
order_sql = ''
|
72
|
+
add_order_without_sqlserver_unique_checking!(order_sql, order, scope)
|
73
|
+
unless order_sql.blank?
|
74
|
+
unique_order_hash = {}
|
75
|
+
select_table_name = connection.send(:get_table_name,sql)
|
76
|
+
select_table_name.tr!('[]','') if select_table_name
|
77
|
+
orders_and_dirs_set = connection.send(:orders_and_dirs_set,order_sql)
|
78
|
+
unique_order_sql = orders_and_dirs_set.inject([]) do |array,order_dir|
|
79
|
+
ord, dir = order_dir
|
80
|
+
ord_tn_and_cn = ord.to_s.split('.').map{|o|o.tr('[]','')}
|
81
|
+
ord_table_name, ord_column_name = if ord_tn_and_cn.size > 1
|
82
|
+
ord_tn_and_cn
|
83
|
+
else
|
84
|
+
[nil, ord_tn_and_cn.first]
|
85
|
+
end
|
86
|
+
if (ord_table_name && ord_table_name == select_table_name && unique_order_hash[ord_column_name]) || unique_order_hash[ord_column_name]
|
87
|
+
array
|
88
|
+
else
|
89
|
+
unique_order_hash[ord_column_name] = true
|
90
|
+
array << "#{ord} #{dir}".strip
|
91
|
+
end
|
92
|
+
end.join(', ')
|
93
|
+
sql << " ORDER BY #{unique_order_sql}"
|
94
|
+
end
|
95
|
+
else
|
96
|
+
add_order_without_sqlserver_unique_checking!(sql, order, scope)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
module JoinAssociationChanges
|
103
|
+
|
104
|
+
def self.included(klass)
|
105
|
+
klass.class_eval do
|
106
|
+
include InstanceMethods
|
107
|
+
alias_method_chain :aliased_table_name_for, :sqlserver_support
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
module InstanceMethods
|
112
|
+
|
113
|
+
protected
|
114
|
+
|
115
|
+
# An exact copy, except this method has a Regexp escape on the quoted table name.
|
116
|
+
def aliased_table_name_for_with_sqlserver_support(name,suffix=nil)
|
117
|
+
if !parent.table_joins.blank? && parent.table_joins.to_s.downcase =~ %r{join(\s+\w+)?\s+#{Regexp.escape(active_record.connection.quote_table_name(name.downcase))}\son}i
|
118
|
+
@join_dependency.table_aliases[name] += 1
|
119
|
+
end
|
120
|
+
unless @join_dependency.table_aliases[name].zero?
|
121
|
+
# if the table name has been used, then use an alias
|
122
|
+
name = active_record.connection.table_alias_for "#{pluralize(reflection.name)}_#{parent_table_name}#{suffix}"
|
123
|
+
table_index = @join_dependency.table_aliases[name]
|
124
|
+
@join_dependency.table_aliases[name] += 1
|
125
|
+
name = name[0..active_record.connection.table_alias_length-3] + "_#{table_index+1}" if table_index > 0
|
126
|
+
else
|
127
|
+
@join_dependency.table_aliases[name] += 1
|
128
|
+
end
|
129
|
+
name
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
137
|
+
|
138
|
+
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
|
144
|
+
ActiveRecord::Base.send :include, ActiveRecord::ConnectionAdapters::SQLServerCoreExtensions::ActiveRecord
|
145
|
+
|
146
|
+
if ActiveRecord::VERSION::MAJOR == 2 && ActiveRecord::VERSION::MINOR >= 3
|
147
|
+
require 'active_record/associations'
|
148
|
+
ActiveRecord::Associations::ClassMethods::JoinDependency::JoinAssociation.send :include, ActiveRecord::ConnectionAdapters::SQLServerCoreExtensions::ActiveRecord::JoinAssociationChanges
|
149
|
+
end
|
150
|
+
|
@@ -0,0 +1,96 @@
|
|
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
|
+
end
|
51
|
+
|
52
|
+
module TypeUtil
|
53
|
+
|
54
|
+
def self.included(klass)
|
55
|
+
klass.extend ClassMethods
|
56
|
+
class << klass
|
57
|
+
alias_method_chain :type_name_to_module, :sqlserver_types
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
module ClassMethods
|
62
|
+
|
63
|
+
# Capture all types classes that we need to handle directly for SQL Server
|
64
|
+
# and allow normal processing for those that we do not.
|
65
|
+
def type_name_to_module_with_sqlserver_types(type_name)
|
66
|
+
case type_name
|
67
|
+
when /^timestamp$/i
|
68
|
+
DBI::Type::SqlserverTimestamp
|
69
|
+
when /^float|decimal|money$/i
|
70
|
+
DBI::Type::SqlserverForcedString
|
71
|
+
else
|
72
|
+
type_name_to_module_without_sqlserver_types(type_name)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
|
88
|
+
|
89
|
+
|
90
|
+
if defined?(DBI::TypeUtil)
|
91
|
+
DBI::Type.send :include, ActiveRecord::ConnectionAdapters::SQLServerCoreExtensions::DBI::Type
|
92
|
+
DBI::TypeUtil.send :include, ActiveRecord::ConnectionAdapters::SQLServerCoreExtensions::DBI::TypeUtil
|
93
|
+
elsif defined?(DBI::Timestamp) # DEPRECATED in DBI 0.4.0 and above. Remove when 0.2.2 and lower is no longer supported.
|
94
|
+
DBI::Timestamp.send :include, ActiveRecord::ConnectionAdapters::SQLServerCoreExtensions::DBI::Timestamp
|
95
|
+
end
|
96
|
+
|
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.2.
|
4
|
+
version: 2.2.21
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ken Collins, Murray Steele, Shawn Balestracci, Joe Rafaniello, Tom Ward
|
@@ -40,18 +40,18 @@ extensions: []
|
|
40
40
|
|
41
41
|
extra_rdoc_files:
|
42
42
|
- CHANGELOG
|
43
|
-
- lib/active_record/connection_adapters/sqlserver_adapter.rb
|
44
43
|
- lib/activerecord-sqlserver-adapter.rb
|
45
|
-
- lib/
|
46
|
-
- lib/core_ext/
|
44
|
+
- lib/active_record/connection_adapters/sqlserver_adapter.rb
|
45
|
+
- lib/active_record/connection_adapters/sqlserver_adapter/core_ext/active_record.rb
|
46
|
+
- lib/active_record/connection_adapters/sqlserver_adapter/core_ext/dbi.rb
|
47
47
|
- README.rdoc
|
48
48
|
- tasks/sqlserver.rake
|
49
49
|
files:
|
50
50
|
- CHANGELOG
|
51
|
-
- lib/active_record/connection_adapters/sqlserver_adapter.rb
|
52
51
|
- lib/activerecord-sqlserver-adapter.rb
|
53
|
-
- lib/
|
54
|
-
- lib/core_ext/
|
52
|
+
- lib/active_record/connection_adapters/sqlserver_adapter.rb
|
53
|
+
- lib/active_record/connection_adapters/sqlserver_adapter/core_ext/active_record.rb
|
54
|
+
- lib/active_record/connection_adapters/sqlserver_adapter/core_ext/dbi.rb
|
55
55
|
- Manifest
|
56
56
|
- MIT-LICENSE
|
57
57
|
- Rakefile
|
@@ -1,151 +0,0 @@
|
|
1
|
-
require 'active_record/version'
|
2
|
-
|
3
|
-
module ActiveRecord
|
4
|
-
module ConnectionAdapters
|
5
|
-
module SQLServerActiveRecordExtensions
|
6
|
-
|
7
|
-
def self.included(klass)
|
8
|
-
klass.extend ClassMethods
|
9
|
-
class << klass
|
10
|
-
alias_method_chain :reset_column_information, :sqlserver_cache_support
|
11
|
-
alias_method_chain :add_order!, :sqlserver_unique_checking
|
12
|
-
alias_method_chain :add_limit!, :sqlserver_order_checking
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
module ClassMethods
|
17
|
-
|
18
|
-
def execute_procedure(proc_name, *variables)
|
19
|
-
if connection.respond_to?(:execute_procedure)
|
20
|
-
connection.execute_procedure(proc_name,*variables)
|
21
|
-
else
|
22
|
-
[]
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def coerce_sqlserver_date(*attributes)
|
27
|
-
write_inheritable_attribute :coerced_sqlserver_date_columns, Set.new(attributes.map(&:to_s))
|
28
|
-
end
|
29
|
-
|
30
|
-
def coerce_sqlserver_time(*attributes)
|
31
|
-
write_inheritable_attribute :coerced_sqlserver_time_columns, Set.new(attributes.map(&:to_s))
|
32
|
-
end
|
33
|
-
|
34
|
-
def coerced_sqlserver_date_columns
|
35
|
-
read_inheritable_attribute(:coerced_sqlserver_date_columns) || []
|
36
|
-
end
|
37
|
-
|
38
|
-
def coerced_sqlserver_time_columns
|
39
|
-
read_inheritable_attribute(:coerced_sqlserver_time_columns) || []
|
40
|
-
end
|
41
|
-
|
42
|
-
def reset_column_information_with_sqlserver_cache_support
|
43
|
-
connection.send(:initialize_sqlserver_caches) if connection.respond_to?(:sqlserver?)
|
44
|
-
reset_column_information_without_sqlserver_cache_support
|
45
|
-
end
|
46
|
-
|
47
|
-
private
|
48
|
-
|
49
|
-
def add_limit_with_sqlserver_order_checking!(sql, options, scope = :auto)
|
50
|
-
if connection.respond_to?(:sqlserver?)
|
51
|
-
scope = scope(:find) if :auto == scope
|
52
|
-
if scope
|
53
|
-
options = options.dup
|
54
|
-
scoped_order = scope[:order]
|
55
|
-
order = options[:order]
|
56
|
-
if order && scoped_order
|
57
|
-
options[:order] = add_order_with_sqlserver_unique_checking!('', order, scope).gsub(/^ ORDER BY /,'')
|
58
|
-
elsif scoped_order
|
59
|
-
options[:order] = scoped_order
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
add_limit_without_sqlserver_order_checking!(sql, options, scope)
|
64
|
-
end
|
65
|
-
|
66
|
-
def add_order_with_sqlserver_unique_checking!(sql, order, scope = :auto)
|
67
|
-
if connection.respond_to?(:sqlserver?)
|
68
|
-
order_sql = ''
|
69
|
-
add_order_without_sqlserver_unique_checking!(order_sql, order, scope)
|
70
|
-
unless order_sql.blank?
|
71
|
-
unique_order_hash = {}
|
72
|
-
select_table_name = connection.send(:get_table_name,sql)
|
73
|
-
select_table_name.tr!('[]','') if select_table_name
|
74
|
-
orders_and_dirs_set = connection.send(:orders_and_dirs_set,order_sql)
|
75
|
-
unique_order_sql = orders_and_dirs_set.inject([]) do |array,order_dir|
|
76
|
-
ord, dir = order_dir
|
77
|
-
ord_tn_and_cn = ord.to_s.split('.').map{|o|o.tr('[]','')}
|
78
|
-
ord_table_name, ord_column_name = if ord_tn_and_cn.size > 1
|
79
|
-
ord_tn_and_cn
|
80
|
-
else
|
81
|
-
[nil, ord_tn_and_cn.first]
|
82
|
-
end
|
83
|
-
if (ord_table_name && ord_table_name == select_table_name && unique_order_hash[ord_column_name]) || unique_order_hash[ord_column_name]
|
84
|
-
array
|
85
|
-
else
|
86
|
-
unique_order_hash[ord_column_name] = true
|
87
|
-
array << "#{ord} #{dir}".strip
|
88
|
-
end
|
89
|
-
end.join(', ')
|
90
|
-
sql << " ORDER BY #{unique_order_sql}"
|
91
|
-
end
|
92
|
-
else
|
93
|
-
add_order_without_sqlserver_unique_checking!(sql, order, scope)
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
end
|
98
|
-
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
ActiveRecord::Base.send :include, ActiveRecord::ConnectionAdapters::SQLServerActiveRecordExtensions
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
if ActiveRecord::VERSION::MAJOR == 2 && ActiveRecord::VERSION::MINOR >= 3
|
109
|
-
|
110
|
-
require 'active_record/associations'
|
111
|
-
module ActiveRecord
|
112
|
-
module ConnectionAdapters
|
113
|
-
module SQLServerJoinAssociationChanges
|
114
|
-
|
115
|
-
def self.included(klass)
|
116
|
-
klass.class_eval do
|
117
|
-
include InstanceMethods
|
118
|
-
alias_method_chain :aliased_table_name_for, :sqlserver_support
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
module InstanceMethods
|
123
|
-
|
124
|
-
protected
|
125
|
-
|
126
|
-
# An exact copy, except this method has a Regexp escape on the quoted table name.
|
127
|
-
def aliased_table_name_for_with_sqlserver_support(name,suffix=nil)
|
128
|
-
if !parent.table_joins.blank? && parent.table_joins.to_s.downcase =~ %r{join(\s+\w+)?\s+#{Regexp.escape(active_record.connection.quote_table_name(name.downcase))}\son}i
|
129
|
-
@join_dependency.table_aliases[name] += 1
|
130
|
-
end
|
131
|
-
unless @join_dependency.table_aliases[name].zero?
|
132
|
-
# if the table name has been used, then use an alias
|
133
|
-
name = active_record.connection.table_alias_for "#{pluralize(reflection.name)}_#{parent_table_name}#{suffix}"
|
134
|
-
table_index = @join_dependency.table_aliases[name]
|
135
|
-
@join_dependency.table_aliases[name] += 1
|
136
|
-
name = name[0..active_record.connection.table_alias_length-3] + "_#{table_index+1}" if table_index > 0
|
137
|
-
else
|
138
|
-
@join_dependency.table_aliases[name] += 1
|
139
|
-
end
|
140
|
-
name
|
141
|
-
end
|
142
|
-
|
143
|
-
end
|
144
|
-
|
145
|
-
end
|
146
|
-
end
|
147
|
-
end
|
148
|
-
ActiveRecord::Associations::ClassMethods::JoinDependency::JoinAssociation.send :include, ActiveRecord::ConnectionAdapters::SQLServerJoinAssociationChanges
|
149
|
-
|
150
|
-
end
|
151
|
-
|
data/lib/core_ext/dbi.rb
DELETED
@@ -1,85 +0,0 @@
|
|
1
|
-
|
2
|
-
module SQLServerDBI
|
3
|
-
|
4
|
-
module Timestamp
|
5
|
-
# Deprecated DBI. See documentation for Type::SqlserverTimestamp which
|
6
|
-
# this method tries to mimic as ODBC is still going to convert SQL Server
|
7
|
-
# milliconds to whole number representation of nanoseconds.
|
8
|
-
def to_sqlserver_string
|
9
|
-
datetime, nanoseconds = to_s.split('.')
|
10
|
-
"#{datetime}.#{sprintf("%03d",nanoseconds.to_i/1000000)}"
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
module Type
|
15
|
-
|
16
|
-
# Make sure we get DBI::Type::Timestamp returning a string NOT a time object
|
17
|
-
# that represents what is in the DB before type casting while letting core
|
18
|
-
# ActiveRecord do the reset. It is assumed that DBI is using ODBC connections
|
19
|
-
# and that ODBC::Timestamp is taking the native milliseconds that SQL Server
|
20
|
-
# stores and returning them incorrect using ODBC::Timestamp#fraction which is
|
21
|
-
# nanoseconds. Below shows the incorrect ODBC::Timestamp represented by DBI
|
22
|
-
# and the conversion we expect to have in the DB before type casting.
|
23
|
-
#
|
24
|
-
# "1985-04-15 00:00:00 0" # => "1985-04-15 00:00:00.000"
|
25
|
-
# "2008-11-08 10:24:36 30000000" # => "2008-11-08 10:24:36.003"
|
26
|
-
# "2008-11-08 10:24:36 123000000" # => "2008-11-08 10:24:36.123"
|
27
|
-
class SqlserverTimestamp
|
28
|
-
def self.parse(obj)
|
29
|
-
return nil if ::DBI::Type::Null.parse(obj).nil?
|
30
|
-
date, time, nanoseconds = obj.split(' ')
|
31
|
-
"#{date} #{time}.#{sprintf("%03d",nanoseconds.to_i/1000000)}"
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
# The adapter and rails will parse our floats, decimals, and money field correctly
|
36
|
-
# from a string. Do not let the DBI::Type classes create Float/BigDecimal objects
|
37
|
-
# for us. Trust rails .type_cast to do what it is built to do.
|
38
|
-
class SqlserverForcedString
|
39
|
-
def self.parse(obj)
|
40
|
-
return nil if ::DBI::Type::Null.parse(obj).nil?
|
41
|
-
obj.to_s
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
end
|
46
|
-
|
47
|
-
module TypeUtil
|
48
|
-
|
49
|
-
def self.included(klass)
|
50
|
-
klass.extend ClassMethods
|
51
|
-
class << klass
|
52
|
-
alias_method_chain :type_name_to_module, :sqlserver_types
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
module ClassMethods
|
57
|
-
|
58
|
-
# Capture all types classes that we need to handle directly for SQL Server
|
59
|
-
# and allow normal processing for those that we do not.
|
60
|
-
def type_name_to_module_with_sqlserver_types(type_name)
|
61
|
-
case type_name
|
62
|
-
when /^timestamp$/i
|
63
|
-
DBI::Type::SqlserverTimestamp
|
64
|
-
when /^float|decimal|money$/i
|
65
|
-
DBI::Type::SqlserverForcedString
|
66
|
-
else
|
67
|
-
type_name_to_module_without_sqlserver_types(type_name)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
end
|
72
|
-
|
73
|
-
end
|
74
|
-
|
75
|
-
|
76
|
-
end
|
77
|
-
|
78
|
-
|
79
|
-
if defined?(DBI::TypeUtil)
|
80
|
-
DBI::Type.send :include, SQLServerDBI::Type
|
81
|
-
DBI::TypeUtil.send :include, SQLServerDBI::TypeUtil
|
82
|
-
elsif defined?(DBI::Timestamp) # DEPRECATED in DBI 0.4.0 and above. Remove when 0.2.2 and lower is no longer supported.
|
83
|
-
DBI::Timestamp.send :include, SQLServerDBI::Timestamp
|
84
|
-
end
|
85
|
-
|