sic-activerecord-sqlserver-adapter 4.0.0
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.
- checksums.yaml +7 -0
- data/CHANGELOG +603 -0
- data/MIT-LICENSE +20 -0
- data/VERSION +1 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/active_record.rb +42 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +41 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/explain_subscriber.rb +4 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/odbc.rb +38 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/relation.rb +19 -0
- data/lib/active_record/connection_adapters/sqlserver/database_limits.rb +49 -0
- data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +458 -0
- data/lib/active_record/connection_adapters/sqlserver/errors.rb +36 -0
- data/lib/active_record/connection_adapters/sqlserver/quoting.rb +109 -0
- data/lib/active_record/connection_adapters/sqlserver/schema_cache.rb +85 -0
- data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +395 -0
- data/lib/active_record/connection_adapters/sqlserver/showplan.rb +67 -0
- data/lib/active_record/connection_adapters/sqlserver/showplan/printer_table.rb +69 -0
- data/lib/active_record/connection_adapters/sqlserver/showplan/printer_xml.rb +25 -0
- data/lib/active_record/connection_adapters/sqlserver/utils.rb +32 -0
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +545 -0
- data/lib/active_record/sqlserver_test_case.rb +17 -0
- data/lib/activerecord-sqlserver-adapter.rb +1 -0
- data/lib/arel/select_manager_sqlserver.rb +64 -0
- data/lib/arel/visitors/sqlserver.rb +326 -0
- metadata +98 -0
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'active_record/test_case.rb'
|
2
|
+
|
3
|
+
# TODO: I'm struggling to figure out how to unsubscribe from only one 'sql.active_record'
|
4
|
+
# This is a temporary hack until we can just get the sqlserver_ignored regex in rails
|
5
|
+
ActiveSupport::Notifications.notifier.listeners_for('sql.active_record').each do |listener|
|
6
|
+
if listener.inspect =~ /ActiveRecord::SQLCounter/
|
7
|
+
ActiveSupport::Notifications.unsubscribe(listener)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
module ActiveRecord
|
12
|
+
class SQLCounter
|
13
|
+
sqlserver_ignored = [%r|SELECT SCOPE_IDENTITY|, %r{INFORMATION_SCHEMA\.(TABLES|VIEWS|COLUMNS)},%r|SELECT @@version|, %r|SELECT @@TRANCOUNT|, %r{(BEGIN|COMMIT|ROLLBACK|SAVE) TRANSACTION}]
|
14
|
+
ignored_sql.concat sqlserver_ignored
|
15
|
+
end
|
16
|
+
ActiveSupport::Notifications.subscribe('sql.active_record', SQLCounter.new)
|
17
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'active_record/connection_adapters/sqlserver_adapter'
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Arel
|
2
|
+
class SelectManager < Arel::TreeManager
|
3
|
+
|
4
|
+
AR_CA_SQLSA_NAME = 'ActiveRecord::ConnectionAdapters::SQLServerAdapter'.freeze
|
5
|
+
|
6
|
+
# Getting real Ordering objects is very important for us. We need to be able to call #uniq on
|
7
|
+
# a colleciton of them reliably as well as using their true object attributes to mutate them
|
8
|
+
# to grouping objects for the inner sql during a select statment with an offset/rownumber. So this
|
9
|
+
# is here till ActiveRecord & ARel does this for us instead of using SqlLiteral objects.
|
10
|
+
alias :order_without_sqlserver :order
|
11
|
+
def order(*expr)
|
12
|
+
return order_without_sqlserver(*expr) unless engine_activerecord_sqlserver_adapter?
|
13
|
+
@ast.orders.concat(expr.map{ |x|
|
14
|
+
case x
|
15
|
+
when Arel::Attributes::Attribute
|
16
|
+
table = Arel::Table.new(x.relation.table_alias || x.relation.name)
|
17
|
+
e = table[x.name]
|
18
|
+
Arel::Nodes::Ascending.new e
|
19
|
+
when Arel::Nodes::Ordering
|
20
|
+
x
|
21
|
+
when String
|
22
|
+
x.split(',').map do |s|
|
23
|
+
s = x if x.strip =~ /\A\b\w+\b\(.*,.*\)(\s+(ASC|DESC))?\Z/i # Allow functions with comma(s) to pass thru.
|
24
|
+
s.strip!
|
25
|
+
d = s =~ /(ASC|DESC)\Z/i ? $1.upcase : nil
|
26
|
+
e = d.nil? ? s : s.mb_chars[0...-d.length].strip
|
27
|
+
e = Arel.sql(e)
|
28
|
+
d && d == "DESC" ? Arel::Nodes::Descending.new(e) : Arel::Nodes::Ascending.new(e)
|
29
|
+
end
|
30
|
+
else
|
31
|
+
e = Arel.sql(x.to_s)
|
32
|
+
Arel::Nodes::Ascending.new e
|
33
|
+
end
|
34
|
+
}.flatten)
|
35
|
+
self
|
36
|
+
end
|
37
|
+
|
38
|
+
# A friendly over ride that allows us to put a special lock object that can have a default or pass
|
39
|
+
# custom string hints down. See the visit_Arel_Nodes_LockWithSQLServer delegation method.
|
40
|
+
alias :lock_without_sqlserver :lock
|
41
|
+
def lock(locking=true)
|
42
|
+
if engine_activerecord_sqlserver_adapter?
|
43
|
+
case locking
|
44
|
+
when true
|
45
|
+
locking = Arel.sql('WITH(HOLDLOCK, ROWLOCK)')
|
46
|
+
when Arel::Nodes::SqlLiteral
|
47
|
+
when String
|
48
|
+
locking = Arel.sql locking
|
49
|
+
end
|
50
|
+
@ast.lock = Arel::Nodes::Lock.new(locking)
|
51
|
+
self
|
52
|
+
else
|
53
|
+
lock_without_sqlserver(locking)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def engine_activerecord_sqlserver_adapter?
|
60
|
+
@engine.connection && @engine.connection.class.name == AR_CA_SQLSA_NAME
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,326 @@
|
|
1
|
+
require 'arel'
|
2
|
+
require 'arel/select_manager_sqlserver'
|
3
|
+
module Arel
|
4
|
+
|
5
|
+
module Nodes
|
6
|
+
|
7
|
+
# Extending the Ordering class to be comparison friendly which allows us to call #uniq on a
|
8
|
+
# collection of them. See SelectManager#order for more details.
|
9
|
+
class Ordering < Arel::Nodes::Unary
|
10
|
+
def hash
|
11
|
+
expr.hash
|
12
|
+
end
|
13
|
+
def ==(other)
|
14
|
+
other.is_a?(Arel::Nodes::Ordering) && self.expr == other.expr
|
15
|
+
end
|
16
|
+
def eql?(other)
|
17
|
+
self == other
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
module Visitors
|
24
|
+
class SQLServer < Arel::Visitors::ToSql
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
# SQLServer ToSql/Visitor (Overides)
|
29
|
+
|
30
|
+
def visit_Arel_Nodes_SelectStatement(o, a)
|
31
|
+
if complex_count_sql?(o)
|
32
|
+
visit_Arel_Nodes_SelectStatementForComplexCount(o, a)
|
33
|
+
elsif o.offset
|
34
|
+
visit_Arel_Nodes_SelectStatementWithOffset(o, a)
|
35
|
+
else
|
36
|
+
visit_Arel_Nodes_SelectStatementWithOutOffset(o, a)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def visit_Arel_Nodes_UpdateStatement(o, a)
|
41
|
+
if o.orders.any? && o.limit.nil?
|
42
|
+
o.limit = Nodes::Limit.new(9223372036854775807)
|
43
|
+
end
|
44
|
+
super
|
45
|
+
end
|
46
|
+
|
47
|
+
def visit_Arel_Nodes_Offset(o, a)
|
48
|
+
"WHERE [__rnt].[__rn] > (#{visit o.expr})"
|
49
|
+
end
|
50
|
+
|
51
|
+
def visit_Arel_Nodes_Limit(o, a)
|
52
|
+
"TOP (#{visit o.expr})"
|
53
|
+
end
|
54
|
+
|
55
|
+
def visit_Arel_Nodes_Lock(o, a)
|
56
|
+
visit o.expr
|
57
|
+
end
|
58
|
+
|
59
|
+
def visit_Arel_Nodes_Ordering(o, a)
|
60
|
+
if o.respond_to?(:direction)
|
61
|
+
"#{visit o.expr} #{o.ascending? ? 'ASC' : 'DESC'}"
|
62
|
+
else
|
63
|
+
visit o.expr
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def visit_Arel_Nodes_Bin(o, a)
|
68
|
+
"#{visit o.expr} #{@connection.cs_equality_operator}"
|
69
|
+
end
|
70
|
+
|
71
|
+
# SQLServer ToSql/Visitor (Additions)
|
72
|
+
|
73
|
+
def visit_Arel_Nodes_SelectStatementWithOutOffset(o, a, windowed = false)
|
74
|
+
find_and_fix_uncorrelated_joins_in_select_statement(o)
|
75
|
+
core = o.cores.first
|
76
|
+
projections = core.projections
|
77
|
+
groups = core.groups
|
78
|
+
orders = o.orders.uniq
|
79
|
+
if windowed
|
80
|
+
projections = function_select_statement?(o) ? projections : projections.map { |x| projection_without_expression(x) }
|
81
|
+
groups = projections.map { |x| projection_without_expression(x) } if windowed_single_distinct_select_statement?(o) && groups.empty?
|
82
|
+
groups += orders.map { |x| Arel.sql(x.expr) } if windowed_single_distinct_select_statement?(o)
|
83
|
+
elsif eager_limiting_select_statement?(o)
|
84
|
+
projections = projections.map { |x| projection_without_expression(x) }
|
85
|
+
groups = projections.map { |x| projection_without_expression(x) }
|
86
|
+
orders = orders.map do |x|
|
87
|
+
expr = Arel.sql projection_without_expression(x.expr)
|
88
|
+
x.descending? ? Arel::Nodes::Max.new([expr]) : Arel::Nodes::Min.new([expr])
|
89
|
+
end
|
90
|
+
elsif top_one_everything_for_through_join?(o)
|
91
|
+
projections = projections.map { |x| projection_without_expression(x) }
|
92
|
+
end
|
93
|
+
[ ("SELECT" if !windowed),
|
94
|
+
(visit(core.set_quantifier) if core.set_quantifier && !windowed),
|
95
|
+
(visit(o.limit) if o.limit && !windowed),
|
96
|
+
(projections.map{ |x| v = visit(x); v == "1" ? "1 AS [__wrp]" : v }.join(', ')),
|
97
|
+
(source_with_lock_for_select_statement(o)),
|
98
|
+
("WHERE #{core.wheres.map{ |x| visit(x) }.join ' AND ' }" unless core.wheres.empty?),
|
99
|
+
("GROUP BY #{groups.map { |x| visit(x) }.join ', ' }" unless groups.empty?),
|
100
|
+
(visit(core.having) if core.having),
|
101
|
+
("ORDER BY #{orders.map{ |x| visit(x) }.join(', ')}" if !orders.empty? && !windowed)
|
102
|
+
].compact.join ' '
|
103
|
+
end
|
104
|
+
|
105
|
+
def visit_Arel_Nodes_SelectStatementWithOffset(o, a)
|
106
|
+
core = o.cores.first
|
107
|
+
o.limit ||= Arel::Nodes::Limit.new(9223372036854775807)
|
108
|
+
orders = rowtable_orders(o)
|
109
|
+
[ "SELECT",
|
110
|
+
(visit(o.limit) if o.limit && !windowed_single_distinct_select_statement?(o)),
|
111
|
+
(rowtable_projections(o).map{ |x| visit(x) }.join(', ')),
|
112
|
+
"FROM (",
|
113
|
+
"SELECT #{core.set_quantifier ? 'DISTINCT DENSE_RANK()' : 'ROW_NUMBER()'} OVER (ORDER BY #{orders.map{ |x| visit(x) }.join(', ')}) AS [__rn],",
|
114
|
+
visit_Arel_Nodes_SelectStatementWithOutOffset(o, a, true),
|
115
|
+
") AS [__rnt]",
|
116
|
+
(visit(o.offset) if o.offset),
|
117
|
+
"ORDER BY [__rnt].[__rn] ASC"
|
118
|
+
].compact.join ' '
|
119
|
+
end
|
120
|
+
|
121
|
+
def visit_Arel_Nodes_SelectStatementForComplexCount(o, a)
|
122
|
+
core = o.cores.first
|
123
|
+
o.limit.expr = Arel.sql("#{o.limit.expr} + #{o.offset ? o.offset.expr : 0}") if o.limit
|
124
|
+
orders = rowtable_orders(o)
|
125
|
+
[ "SELECT COUNT([count]) AS [count_id]",
|
126
|
+
"FROM (",
|
127
|
+
"SELECT",
|
128
|
+
(visit(o.limit) if o.limit),
|
129
|
+
"ROW_NUMBER() OVER (ORDER BY #{orders.map{ |x| visit(x) }.join(', ')}) AS [__rn],",
|
130
|
+
"1 AS [count]",
|
131
|
+
(source_with_lock_for_select_statement(o)),
|
132
|
+
("WHERE #{core.wheres.map{ |x| visit(x) }.join ' AND ' }" unless core.wheres.empty?),
|
133
|
+
("GROUP BY #{core.groups.map { |x| visit x }.join ', ' }" unless core.groups.empty?),
|
134
|
+
(visit(core.having) if core.having),
|
135
|
+
("ORDER BY #{o.orders.map{ |x| visit(x) }.join(', ')}" if !o.orders.empty?),
|
136
|
+
") AS [__rnt]",
|
137
|
+
(visit(o.offset) if o.offset)
|
138
|
+
].compact.join ' '
|
139
|
+
end
|
140
|
+
|
141
|
+
|
142
|
+
# SQLServer Helpers
|
143
|
+
|
144
|
+
def source_with_lock_for_select_statement(o)
|
145
|
+
core = o.cores.first
|
146
|
+
source = "FROM #{visit(core.source).strip}" if core.source
|
147
|
+
if source && o.lock
|
148
|
+
lock = visit o.lock
|
149
|
+
index = source.match(/FROM [\w\[\]\.]+/)[0].mb_chars.length
|
150
|
+
source.insert index, " #{lock}"
|
151
|
+
else
|
152
|
+
source
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def table_from_select_statement(o)
|
157
|
+
core = o.cores.first
|
158
|
+
# TODO: [ARel 2.2] Use #from/#source vs. #froms
|
159
|
+
# if Arel::Table === core.from
|
160
|
+
# core.from
|
161
|
+
# elsif Arel::Nodes::SqlLiteral === core.from
|
162
|
+
# Arel::Table.new(core.from, @engine)
|
163
|
+
# elsif Arel::Nodes::JoinSource === core.source
|
164
|
+
# Arel::Nodes::SqlLiteral === core.source.left ? Arel::Table.new(core.source.left, @engine) : core.source.left
|
165
|
+
# end
|
166
|
+
table_finder = lambda { |x|
|
167
|
+
case x
|
168
|
+
when Arel::Table
|
169
|
+
x
|
170
|
+
when Arel::Nodes::SqlLiteral
|
171
|
+
Arel::Table.new(x, @engine)
|
172
|
+
when Arel::Nodes::Join
|
173
|
+
table_finder.call(x.left)
|
174
|
+
end
|
175
|
+
}
|
176
|
+
table_finder.call(core.froms)
|
177
|
+
end
|
178
|
+
|
179
|
+
def single_distinct_select_statement?(o)
|
180
|
+
projections = o.cores.first.projections
|
181
|
+
p1 = projections.first
|
182
|
+
projections.size == 1 &&
|
183
|
+
((p1.respond_to?(:distinct) && p1.distinct) ||
|
184
|
+
p1.respond_to?(:include?) && p1.include?('DISTINCT'))
|
185
|
+
end
|
186
|
+
|
187
|
+
def windowed_single_distinct_select_statement?(o)
|
188
|
+
o.limit && o.offset && single_distinct_select_statement?(o)
|
189
|
+
end
|
190
|
+
|
191
|
+
def single_distinct_select_everything_statement?(o)
|
192
|
+
single_distinct_select_statement?(o) && visit(o.cores.first.projections.first).ends_with?(".*")
|
193
|
+
end
|
194
|
+
|
195
|
+
def top_one_everything_for_through_join?(o)
|
196
|
+
single_distinct_select_everything_statement?(o) &&
|
197
|
+
(o.limit && !o.offset) &&
|
198
|
+
join_in_select_statement?(o)
|
199
|
+
end
|
200
|
+
|
201
|
+
def all_projections_aliased_in_select_statement?(o)
|
202
|
+
projections = o.cores.first.projections
|
203
|
+
projections.all? do |x|
|
204
|
+
visit(x).split(',').all? { |y| y.include?(' AS ') }
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
def function_select_statement?(o)
|
209
|
+
core = o.cores.first
|
210
|
+
core.projections.any? { |x| Arel::Nodes::Function === x }
|
211
|
+
end
|
212
|
+
|
213
|
+
def eager_limiting_select_statement?(o)
|
214
|
+
core = o.cores.first
|
215
|
+
single_distinct_select_statement?(o) &&
|
216
|
+
(o.limit && !o.offset) &&
|
217
|
+
core.groups.empty? &&
|
218
|
+
!single_distinct_select_everything_statement?(o)
|
219
|
+
end
|
220
|
+
|
221
|
+
def join_in_select_statement?(o)
|
222
|
+
core = o.cores.first
|
223
|
+
core.source.right.any? { |x| Arel::Nodes::Join === x }
|
224
|
+
end
|
225
|
+
|
226
|
+
def complex_count_sql?(o)
|
227
|
+
core = o.cores.first
|
228
|
+
core.projections.size == 1 &&
|
229
|
+
Arel::Nodes::Count === core.projections.first &&
|
230
|
+
o.limit &&
|
231
|
+
!join_in_select_statement?(o)
|
232
|
+
end
|
233
|
+
|
234
|
+
def select_primary_key_sql?(o)
|
235
|
+
core = o.cores.first
|
236
|
+
return false if core.projections.size != 1
|
237
|
+
p = core.projections.first
|
238
|
+
t = table_from_select_statement(o)
|
239
|
+
Arel::Attributes::Attribute === p && t.primary_key && t.primary_key.name == p.name
|
240
|
+
end
|
241
|
+
|
242
|
+
def find_and_fix_uncorrelated_joins_in_select_statement(o)
|
243
|
+
core = o.cores.first
|
244
|
+
# TODO: [ARel 2.2] Use #from/#source vs. #froms
|
245
|
+
# return if !join_in_select_statement?(o) || core.source.right.size != 2
|
246
|
+
# j1 = core.source.right.first
|
247
|
+
# j2 = core.source.right.second
|
248
|
+
# return unless Arel::Nodes::OuterJoin === j1 && Arel::Nodes::StringJoin === j2
|
249
|
+
# j1_tn = j1.left.name
|
250
|
+
# j2_tn = j2.left.match(/JOIN \[(.*)\].*ON/).try(:[],1)
|
251
|
+
# return unless j1_tn == j2_tn
|
252
|
+
# crltd_tn = "#{j1_tn}_crltd"
|
253
|
+
# j1.left.table_alias = crltd_tn
|
254
|
+
# j1.right.expr.left.relation.table_alias = crltd_tn
|
255
|
+
return if !join_in_select_statement?(o) || !(Arel::Nodes::StringJoin === core.froms)
|
256
|
+
j1 = core.froms.left
|
257
|
+
j2 = core.froms.right
|
258
|
+
return unless Arel::Nodes::OuterJoin === j1 && Arel::Nodes::SqlLiteral === j2 && j2.include?('JOIN ')
|
259
|
+
j1_tn = j1.right.name
|
260
|
+
j2_tn = j2.match(/JOIN \[(.*)\].*ON/).try(:[],1)
|
261
|
+
return unless j1_tn == j2_tn
|
262
|
+
on_index = j2.index(' ON ')
|
263
|
+
j2.insert on_index, " AS [#{j2_tn}_crltd]"
|
264
|
+
j2.sub! "[#{j2_tn}].", "[#{j2_tn}_crltd]."
|
265
|
+
end
|
266
|
+
|
267
|
+
def rowtable_projections(o)
|
268
|
+
core = o.cores.first
|
269
|
+
if windowed_single_distinct_select_statement?(o) && core.groups.blank?
|
270
|
+
tn = table_from_select_statement(o).name
|
271
|
+
core.projections.map do |x|
|
272
|
+
x.dup.tap do |p|
|
273
|
+
p.sub! 'DISTINCT', ''
|
274
|
+
p.insert 0, visit(o.limit) if o.limit
|
275
|
+
p.gsub! /\[?#{tn}\]?\./, '[__rnt].'
|
276
|
+
p.strip!
|
277
|
+
end
|
278
|
+
end
|
279
|
+
elsif single_distinct_select_statement?(o)
|
280
|
+
tn = table_from_select_statement(o).name
|
281
|
+
core.projections.map do |x|
|
282
|
+
x.dup.tap do |p|
|
283
|
+
p.sub! 'DISTINCT', "DISTINCT #{visit(o.limit)}".strip if o.limit
|
284
|
+
p.gsub! /\[?#{tn}\]?\./, '[__rnt].'
|
285
|
+
p.strip!
|
286
|
+
end
|
287
|
+
end
|
288
|
+
elsif join_in_select_statement?(o) && all_projections_aliased_in_select_statement?(o)
|
289
|
+
core.projections.map do |x|
|
290
|
+
Arel.sql visit(x).split(',').map{ |y| y.split(' AS ').last.strip }.join(', ')
|
291
|
+
end
|
292
|
+
elsif select_primary_key_sql?(o)
|
293
|
+
[Arel.sql("[__rnt].#{quote_column_name(core.projections.first.name)}")]
|
294
|
+
else
|
295
|
+
[Arel.sql('[__rnt].*')]
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
def rowtable_orders(o)
|
300
|
+
core = o.cores.first
|
301
|
+
if !o.orders.empty?
|
302
|
+
o.orders
|
303
|
+
else
|
304
|
+
t = table_from_select_statement(o)
|
305
|
+
c = t.primary_key || t.columns.first
|
306
|
+
[c.asc]
|
307
|
+
end.uniq
|
308
|
+
end
|
309
|
+
|
310
|
+
# TODO: We use this for grouping too, maybe make Grouping objects vs SqlLiteral.
|
311
|
+
def projection_without_expression(projection)
|
312
|
+
Arel.sql(visit(projection).split(',').map do |x|
|
313
|
+
x.strip!
|
314
|
+
x.sub!(/^(COUNT|SUM|MAX|MIN|AVG)\s*(\((.*)\))?/,'\3')
|
315
|
+
x.sub!(/^DISTINCT\s*/,'')
|
316
|
+
x.sub!(/TOP\s*\(\d+\)\s*/i,'')
|
317
|
+
x.strip
|
318
|
+
end.join(', '))
|
319
|
+
end
|
320
|
+
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
end
|
325
|
+
|
326
|
+
Arel::Visitors::VISITORS['sqlserver'] = Arel::Visitors::SQLServer
|
metadata
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sic-activerecord-sqlserver-adapter
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 4.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ken Collins
|
8
|
+
- Murray Steele
|
9
|
+
- Shawn Balestracci
|
10
|
+
- Joe Rafaniello
|
11
|
+
- Tom Ward
|
12
|
+
autorequire:
|
13
|
+
bindir: bin
|
14
|
+
cert_chain: []
|
15
|
+
date: 2014-03-20 00:00:00.000000000 Z
|
16
|
+
dependencies:
|
17
|
+
- !ruby/object:Gem::Dependency
|
18
|
+
name: activerecord
|
19
|
+
requirement: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - "~>"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 4.0.0
|
24
|
+
type: :runtime
|
25
|
+
prerelease: false
|
26
|
+
version_requirements: !ruby/object:Gem::Requirement
|
27
|
+
requirements:
|
28
|
+
- - "~>"
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: 4.0.0
|
31
|
+
- !ruby/object:Gem::Dependency
|
32
|
+
name: arel
|
33
|
+
requirement: !ruby/object:Gem::Requirement
|
34
|
+
requirements:
|
35
|
+
- - "~>"
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 4.0.1
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
requirements:
|
42
|
+
- - "~>"
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: 4.0.1
|
45
|
+
description: ActiveRecord SQL Server Adapter. For SQL Server 2005 And Higher.
|
46
|
+
email: ken@metaskills.net
|
47
|
+
executables: []
|
48
|
+
extensions: []
|
49
|
+
extra_rdoc_files: []
|
50
|
+
files:
|
51
|
+
- CHANGELOG
|
52
|
+
- MIT-LICENSE
|
53
|
+
- VERSION
|
54
|
+
- lib/active_record/connection_adapters/sqlserver/core_ext/active_record.rb
|
55
|
+
- lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb
|
56
|
+
- lib/active_record/connection_adapters/sqlserver/core_ext/explain_subscriber.rb
|
57
|
+
- lib/active_record/connection_adapters/sqlserver/core_ext/odbc.rb
|
58
|
+
- lib/active_record/connection_adapters/sqlserver/core_ext/relation.rb
|
59
|
+
- lib/active_record/connection_adapters/sqlserver/database_limits.rb
|
60
|
+
- lib/active_record/connection_adapters/sqlserver/database_statements.rb
|
61
|
+
- lib/active_record/connection_adapters/sqlserver/errors.rb
|
62
|
+
- lib/active_record/connection_adapters/sqlserver/quoting.rb
|
63
|
+
- lib/active_record/connection_adapters/sqlserver/schema_cache.rb
|
64
|
+
- lib/active_record/connection_adapters/sqlserver/schema_statements.rb
|
65
|
+
- lib/active_record/connection_adapters/sqlserver/showplan.rb
|
66
|
+
- lib/active_record/connection_adapters/sqlserver/showplan/printer_table.rb
|
67
|
+
- lib/active_record/connection_adapters/sqlserver/showplan/printer_xml.rb
|
68
|
+
- lib/active_record/connection_adapters/sqlserver/utils.rb
|
69
|
+
- lib/active_record/connection_adapters/sqlserver_adapter.rb
|
70
|
+
- lib/active_record/sqlserver_test_case.rb
|
71
|
+
- lib/activerecord-sqlserver-adapter.rb
|
72
|
+
- lib/arel/select_manager_sqlserver.rb
|
73
|
+
- lib/arel/visitors/sqlserver.rb
|
74
|
+
homepage: http://github.com/rails-sqlserver/activerecord-sqlserver-adapter
|
75
|
+
licenses: []
|
76
|
+
metadata: {}
|
77
|
+
post_install_message:
|
78
|
+
rdoc_options: []
|
79
|
+
require_paths:
|
80
|
+
- lib
|
81
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
requirements: []
|
92
|
+
rubyforge_project: activerecord-sqlserver-adapter
|
93
|
+
rubygems_version: 2.2.2
|
94
|
+
signing_key:
|
95
|
+
specification_version: 4
|
96
|
+
summary: ActiveRecord SQL Server Adapter. For SQL Server 2005 And Higher.
|
97
|
+
test_files: []
|
98
|
+
has_rdoc:
|