activerecord-sqlserver-adapter 3.1.3 → 3.1.4
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +31 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/database_statements.rb +97 -0
- data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +69 -12
- data/lib/active_record/connection_adapters/sqlserver/errors.rb +3 -0
- data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +9 -4
- data/lib/active_record/connection_adapters/sqlserver/version.rb +1 -1
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +28 -6
- data/lib/arel/visitors/sqlserver.rb +19 -3
- metadata +6 -7
data/CHANGELOG
CHANGED
@@ -1,4 +1,35 @@
|
|
1
1
|
|
2
|
+
* 3.1.4 *
|
3
|
+
|
4
|
+
* Use INFORMATION_SCHEMA.KEY_COLUMN_USAGE for schema reflection speed.
|
5
|
+
Fixes #125. [Wüthrich Hannes @hwuethrich]
|
6
|
+
|
7
|
+
* New deadlock victim retry using the #retry_deadlock_victim config. [Joe Rafaniello]
|
8
|
+
|
9
|
+
* Renamed #with_auto_reconnect to #with_sqlserver_error_handling now that it handles both dropped
|
10
|
+
connections and deadlock victim errors. Fixes #150 [Joe Rafaniello]
|
11
|
+
|
12
|
+
* Add activity_stats method that mimics the SQL Server Activity Monitor. Fixes #146 [Joe Rafaniello]
|
13
|
+
|
14
|
+
* Add methods for sqlserver's #product_version, #product_level, #edition and include them in inspect.
|
15
|
+
Fixes #145 [Joe Rafaniello]
|
16
|
+
|
17
|
+
* Handle statements that cannot be retried on a new database connection by not reconnecting.
|
18
|
+
Fixes #147 [Joe Rafaniello]
|
19
|
+
|
20
|
+
* Added connection#spid for debugging. Fixes #144 [Joe Rafaniello]
|
21
|
+
|
22
|
+
* Add ENV['TEST_FILES'] to Rakefile for easy single case tests. [Joe Rafaniello]
|
23
|
+
|
24
|
+
* Pass ActiveRecord tests. Made windowed distinct pass all orders to groups.
|
25
|
+
- test_limited_eager_with_multiple_order_columns
|
26
|
+
- test_limited_eager_with_order
|
27
|
+
|
28
|
+
* Pass AR tests by moving DISTINCT to GROUP BY in windowed SQL.
|
29
|
+
- test_count_eager_with_has_many_and_limit_and_high_offset
|
30
|
+
- test_eager_with_has_many_and_limit_and_high_offset
|
31
|
+
|
32
|
+
|
2
33
|
* 3.1.3 *
|
3
34
|
|
4
35
|
* Distinguish between identity and primary key key columns during schema reflection. Allows us
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
module Sqlserver
|
4
|
+
module CoreExt
|
5
|
+
module DatabaseStatements
|
6
|
+
|
7
|
+
# This is a copy of the current (3.1.3) ActiveRecord's transaction method. We should propose
|
8
|
+
# a patch to the default transaction method to make it more callback for adapters that want to
|
9
|
+
# do deadlock retry logic. Because this is a copy, we really need to keep an eye out on this when
|
10
|
+
# upgradding the adapter.
|
11
|
+
def transaction_with_retry_deadlock_victim(options = {})
|
12
|
+
options.assert_valid_keys :requires_new, :joinable
|
13
|
+
|
14
|
+
last_transaction_joinable = defined?(@transaction_joinable) ? @transaction_joinable : nil
|
15
|
+
if options.has_key?(:joinable)
|
16
|
+
@transaction_joinable = options[:joinable]
|
17
|
+
else
|
18
|
+
@transaction_joinable = true
|
19
|
+
end
|
20
|
+
requires_new = options[:requires_new] || !last_transaction_joinable
|
21
|
+
|
22
|
+
transaction_open = false
|
23
|
+
@_current_transaction_records ||= []
|
24
|
+
|
25
|
+
begin
|
26
|
+
if block_given?
|
27
|
+
if requires_new || open_transactions == 0
|
28
|
+
if open_transactions == 0
|
29
|
+
begin_db_transaction
|
30
|
+
elsif requires_new
|
31
|
+
create_savepoint
|
32
|
+
end
|
33
|
+
increment_open_transactions
|
34
|
+
transaction_open = true
|
35
|
+
@_current_transaction_records.push([])
|
36
|
+
end
|
37
|
+
yield
|
38
|
+
end
|
39
|
+
rescue Exception => database_transaction_rollback
|
40
|
+
if transaction_open && !outside_transaction?
|
41
|
+
transaction_open = false
|
42
|
+
decrement_open_transactions
|
43
|
+
# handle deadlock victim retries at the outermost transaction
|
44
|
+
if open_transactions == 0
|
45
|
+
if database_transaction_rollback.is_a?(::ActiveRecord::DeadlockVictim)
|
46
|
+
# SQL Server has already rolled back, so rollback activerecord's history
|
47
|
+
rollback_transaction_records(true)
|
48
|
+
retry
|
49
|
+
else
|
50
|
+
rollback_db_transaction
|
51
|
+
rollback_transaction_records(true)
|
52
|
+
end
|
53
|
+
else
|
54
|
+
rollback_to_savepoint
|
55
|
+
rollback_transaction_records(false)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
raise unless database_transaction_rollback.is_a?(::ActiveRecord::Rollback)
|
59
|
+
end
|
60
|
+
ensure
|
61
|
+
@transaction_joinable = last_transaction_joinable
|
62
|
+
|
63
|
+
if outside_transaction?
|
64
|
+
@open_transactions = 0
|
65
|
+
elsif transaction_open
|
66
|
+
decrement_open_transactions
|
67
|
+
begin
|
68
|
+
if open_transactions == 0
|
69
|
+
commit_db_transaction
|
70
|
+
commit_transaction_records
|
71
|
+
else
|
72
|
+
release_savepoint
|
73
|
+
save_point_records = @_current_transaction_records.pop
|
74
|
+
unless save_point_records.blank?
|
75
|
+
@_current_transaction_records.push([]) if @_current_transaction_records.empty?
|
76
|
+
@_current_transaction_records.last.concat(save_point_records)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
rescue Exception => database_transaction_rollback
|
80
|
+
if open_transactions == 0
|
81
|
+
rollback_db_transaction
|
82
|
+
rollback_transaction_records(true)
|
83
|
+
else
|
84
|
+
rollback_to_savepoint
|
85
|
+
rollback_transaction_records(false)
|
86
|
+
end
|
87
|
+
raise
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
@@ -3,6 +3,8 @@ module ActiveRecord
|
|
3
3
|
module Sqlserver
|
4
4
|
module DatabaseStatements
|
5
5
|
|
6
|
+
include CoreExt::DatabaseStatements
|
7
|
+
|
6
8
|
def select_rows(sql, name = nil)
|
7
9
|
raw_select sql, name, [], :fetch => :rows
|
8
10
|
end
|
@@ -45,12 +47,20 @@ module ActiveRecord
|
|
45
47
|
true
|
46
48
|
end
|
47
49
|
|
50
|
+
def transaction(options = {})
|
51
|
+
if retry_deadlock_victim?
|
52
|
+
block_given? ? transaction_with_retry_deadlock_victim(options) { yield } : transaction_with_retry_deadlock_victim(options)
|
53
|
+
else
|
54
|
+
block_given? ? super(options) { yield } : super(options)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
48
58
|
def begin_db_transaction
|
49
59
|
do_execute "BEGIN TRANSACTION"
|
50
60
|
end
|
51
61
|
|
52
62
|
def commit_db_transaction
|
53
|
-
do_execute "COMMIT TRANSACTION"
|
63
|
+
disable_auto_reconnect { do_execute "COMMIT TRANSACTION" }
|
54
64
|
end
|
55
65
|
|
56
66
|
def rollback_db_transaction
|
@@ -58,14 +68,14 @@ module ActiveRecord
|
|
58
68
|
end
|
59
69
|
|
60
70
|
def create_savepoint
|
61
|
-
do_execute "SAVE TRANSACTION #{current_savepoint_name}"
|
71
|
+
disable_auto_reconnect { do_execute "SAVE TRANSACTION #{current_savepoint_name}" }
|
62
72
|
end
|
63
73
|
|
64
74
|
def release_savepoint
|
65
75
|
end
|
66
76
|
|
67
77
|
def rollback_to_savepoint
|
68
|
-
do_execute "ROLLBACK TRANSACTION #{current_savepoint_name}"
|
78
|
+
disable_auto_reconnect { do_execute "ROLLBACK TRANSACTION #{current_savepoint_name}" }
|
69
79
|
end
|
70
80
|
|
71
81
|
def add_limit_offset!(sql, options)
|
@@ -185,6 +195,51 @@ module ActiveRecord
|
|
185
195
|
select_value "SELECT NEWSEQUENTIALID()"
|
186
196
|
end
|
187
197
|
|
198
|
+
def activity_stats
|
199
|
+
select_all %|
|
200
|
+
SELECT
|
201
|
+
[session_id] = s.session_id,
|
202
|
+
[user_process] = CONVERT(CHAR(1), s.is_user_process),
|
203
|
+
[login] = s.login_name,
|
204
|
+
[database] = ISNULL(db_name(r.database_id), N''),
|
205
|
+
[task_state] = ISNULL(t.task_state, N''),
|
206
|
+
[command] = ISNULL(r.command, N''),
|
207
|
+
[application] = ISNULL(s.program_name, N''),
|
208
|
+
[wait_time_ms] = ISNULL(w.wait_duration_ms, 0),
|
209
|
+
[wait_type] = ISNULL(w.wait_type, N''),
|
210
|
+
[wait_resource] = ISNULL(w.resource_description, N''),
|
211
|
+
[blocked_by] = ISNULL(CONVERT (varchar, w.blocking_session_id), ''),
|
212
|
+
[head_blocker] =
|
213
|
+
CASE
|
214
|
+
-- session has an active request, is blocked, but is blocking others
|
215
|
+
WHEN r2.session_id IS NOT NULL AND r.blocking_session_id = 0 THEN '1'
|
216
|
+
-- session is idle but has an open tran and is blocking others
|
217
|
+
WHEN r.session_id IS NULL THEN '1'
|
218
|
+
ELSE ''
|
219
|
+
END,
|
220
|
+
[total_cpu_ms] = s.cpu_time,
|
221
|
+
[total_physical_io_mb] = (s.reads + s.writes) * 8 / 1024,
|
222
|
+
[memory_use_kb] = s.memory_usage * 8192 / 1024,
|
223
|
+
[open_transactions] = ISNULL(r.open_transaction_count,0),
|
224
|
+
[login_time] = s.login_time,
|
225
|
+
[last_request_start_time] = s.last_request_start_time,
|
226
|
+
[host_name] = ISNULL(s.host_name, N''),
|
227
|
+
[net_address] = ISNULL(c.client_net_address, N''),
|
228
|
+
[execution_context_id] = ISNULL(t.exec_context_id, 0),
|
229
|
+
[request_id] = ISNULL(r.request_id, 0),
|
230
|
+
[workload_group] = N''
|
231
|
+
FROM sys.dm_exec_sessions s LEFT OUTER JOIN sys.dm_exec_connections c ON (s.session_id = c.session_id)
|
232
|
+
LEFT OUTER JOIN sys.dm_exec_requests r ON (s.session_id = r.session_id)
|
233
|
+
LEFT OUTER JOIN sys.dm_os_tasks t ON (r.session_id = t.session_id AND r.request_id = t.request_id)
|
234
|
+
LEFT OUTER JOIN
|
235
|
+
(SELECT *, ROW_NUMBER() OVER (PARTITION BY waiting_task_address ORDER BY wait_duration_ms DESC) AS row_num
|
236
|
+
FROM sys.dm_os_waiting_tasks
|
237
|
+
) w ON (t.task_address = w.waiting_task_address) AND w.row_num = 1
|
238
|
+
LEFT OUTER JOIN sys.dm_exec_requests r2 ON (r.session_id = r2.blocking_session_id)
|
239
|
+
WHERE db_name(r.database_id) = '#{current_database}'
|
240
|
+
ORDER BY s.session_id|
|
241
|
+
end
|
242
|
+
|
188
243
|
# === SQLServer Specific (Rake/Test Helpers) ==================== #
|
189
244
|
|
190
245
|
def recreate_database
|
@@ -262,7 +317,7 @@ module ActiveRecord
|
|
262
317
|
def do_execute(sql, name = nil)
|
263
318
|
name ||= 'EXECUTE'
|
264
319
|
log(sql, name) do
|
265
|
-
|
320
|
+
with_sqlserver_error_handling { raw_connection_do(sql) }
|
266
321
|
end
|
267
322
|
end
|
268
323
|
|
@@ -307,18 +362,20 @@ module ActiveRecord
|
|
307
362
|
# === SQLServer Specific (Selecting) ============================ #
|
308
363
|
|
309
364
|
def raw_select(sql, name=nil, binds=[], options={})
|
310
|
-
log(sql,name,binds)
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
365
|
+
log(sql,name,binds) { _raw_select(sql, options) }
|
366
|
+
end
|
367
|
+
|
368
|
+
def _raw_select(sql, options={})
|
369
|
+
begin
|
370
|
+
handle = raw_connection_run(sql)
|
371
|
+
handle_to_names_and_values(handle, options)
|
372
|
+
ensure
|
373
|
+
finish_statement_handle(handle)
|
317
374
|
end
|
318
375
|
end
|
319
376
|
|
320
377
|
def raw_connection_run(sql)
|
321
|
-
|
378
|
+
with_sqlserver_error_handling do
|
322
379
|
case @connection_options[:mode]
|
323
380
|
when :dblib
|
324
381
|
@connection.execute(sql)
|
@@ -193,7 +193,7 @@ module ActiveRecord
|
|
193
193
|
ELSE NULL
|
194
194
|
END AS [is_nullable],
|
195
195
|
CASE
|
196
|
-
WHEN
|
196
|
+
WHEN KCU.COLUMN_NAME IS NOT NULL AND TC.CONSTRAINT_TYPE = N'PRIMARY KEY' THEN 1
|
197
197
|
ELSE NULL
|
198
198
|
END AS [is_primary],
|
199
199
|
CASE
|
@@ -201,12 +201,17 @@ module ActiveRecord
|
|
201
201
|
ELSE NULL
|
202
202
|
END AS [is_identity]
|
203
203
|
FROM #{db_name_with_period}INFORMATION_SCHEMA.COLUMNS columns
|
204
|
-
LEFT OUTER JOIN #{db_name_with_period}INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS TC
|
205
|
-
|
204
|
+
LEFT OUTER JOIN #{db_name_with_period}INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS TC
|
205
|
+
ON TC.TABLE_NAME = columns.TABLE_NAME
|
206
|
+
AND TC.CONSTRAINT_TYPE = N'PRIMARY KEY'
|
207
|
+
LEFT OUTER JOIN #{db_name_with_period}INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS KCU
|
208
|
+
ON KCU.COLUMN_NAME = columns.COLUMN_NAME
|
209
|
+
AND KCU.CONSTRAINT_NAME = TC.CONSTRAINT_NAME
|
210
|
+
AND KCU.CONSTRAINT_CATALOG = TC.CONSTRAINT_CATALOG
|
211
|
+
AND KCU.CONSTRAINT_SCHEMA = TC.CONSTRAINT_SCHEMA
|
206
212
|
WHERE columns.TABLE_NAME = @0
|
207
213
|
AND columns.TABLE_SCHEMA = #{table_schema.blank? ? "schema_name()" : "@1"}
|
208
214
|
ORDER BY columns.ordinal_position
|
209
|
-
|
210
215
|
}.gsub(/[ \t\r\n]+/,' ')
|
211
216
|
binds = [['table_name', table_name]]
|
212
217
|
binds << ['table_schema',table_schema] unless table_schema.blank?
|
@@ -2,6 +2,7 @@ require 'arel/visitors/sqlserver'
|
|
2
2
|
require 'active_record'
|
3
3
|
require 'active_record/connection_adapters/abstract_adapter'
|
4
4
|
require 'active_record/connection_adapters/sqlserver/core_ext/active_record'
|
5
|
+
require 'active_record/connection_adapters/sqlserver/core_ext/database_statements'
|
5
6
|
require 'active_record/connection_adapters/sqlserver/database_limits'
|
6
7
|
require 'active_record/connection_adapters/sqlserver/database_statements'
|
7
8
|
require 'active_record/connection_adapters/sqlserver/errors'
|
@@ -176,10 +177,10 @@ module ActiveRecord
|
|
176
177
|
DATABASE_VERSION_REGEXP = /Microsoft SQL Server\s+"?(\d{4}|\w+)"?/
|
177
178
|
SUPPORTED_VERSIONS = [2005,2008,2010,2011].freeze
|
178
179
|
|
179
|
-
attr_reader :database_version, :database_year
|
180
|
+
attr_reader :database_version, :database_year, :spid, :product_level, :product_version, :edition
|
180
181
|
|
181
182
|
cattr_accessor :native_text_database_type, :native_binary_database_type, :native_string_database_type,
|
182
|
-
:log_info_schema_queries, :enable_default_unicode_types, :auto_connect,
|
183
|
+
:log_info_schema_queries, :enable_default_unicode_types, :auto_connect, :retry_deadlock_victim,
|
183
184
|
:cs_equality_operator, :lowercase_schema_reflection, :auto_connect_duration
|
184
185
|
|
185
186
|
self.enable_default_unicode_types = true
|
@@ -208,6 +209,9 @@ module ActiveRecord
|
|
208
209
|
rescue
|
209
210
|
0
|
210
211
|
end
|
212
|
+
@product_level = info_schema_query { select_value("SELECT CAST(SERVERPROPERTY('productlevel') AS VARCHAR(128))") }
|
213
|
+
@product_version = info_schema_query { select_value("SELECT CAST(SERVERPROPERTY('productversion') AS VARCHAR(128))") }
|
214
|
+
@edition = info_schema_query { select_value("SELECT CAST(SERVERPROPERTY('edition') AS VARCHAR(128))") }
|
211
215
|
initialize_dateformatter
|
212
216
|
initialize_sqlserver_caches
|
213
217
|
use_database
|
@@ -269,6 +273,7 @@ module ActiveRecord
|
|
269
273
|
end
|
270
274
|
|
271
275
|
def disconnect!
|
276
|
+
@spid = nil
|
272
277
|
case @connection_options[:mode]
|
273
278
|
when :dblib
|
274
279
|
@connection.close rescue nil
|
@@ -323,7 +328,7 @@ module ActiveRecord
|
|
323
328
|
end
|
324
329
|
|
325
330
|
def inspect
|
326
|
-
"#<#{self.class} version: #{version}, year: #{@database_year}, connection_options: #{@connection_options.inspect}>"
|
331
|
+
"#<#{self.class} version: #{version}, year: #{@database_year}, product_level: #{@product_level.inspect}, product_version: #{@product_version.inspect}, edition: #{@edition.inspect}, connection_options: #{@connection_options.inspect}>"
|
327
332
|
end
|
328
333
|
|
329
334
|
def auto_connect
|
@@ -334,6 +339,11 @@ module ActiveRecord
|
|
334
339
|
@@auto_connect_duration ||= 10
|
335
340
|
end
|
336
341
|
|
342
|
+
def retry_deadlock_victim
|
343
|
+
@@retry_deadlock_victim.is_a?(FalseClass) ? false : true
|
344
|
+
end
|
345
|
+
alias :retry_deadlock_victim? :retry_deadlock_victim
|
346
|
+
|
337
347
|
def native_string_database_type
|
338
348
|
@@native_string_database_type || (enable_default_unicode_types ? 'nvarchar' : 'varchar')
|
339
349
|
end
|
@@ -358,7 +368,6 @@ module ActiveRecord
|
|
358
368
|
@@cs_equality_operator || 'COLLATE Latin1_General_CS_AS_WS'
|
359
369
|
end
|
360
370
|
|
361
|
-
|
362
371
|
protected
|
363
372
|
|
364
373
|
# === Abstract Adapter (Misc Support) =========================== #
|
@@ -369,6 +378,8 @@ module ActiveRecord
|
|
369
378
|
RecordNotUnique.new(message,e)
|
370
379
|
when /conflicted with the foreign key constraint/i
|
371
380
|
InvalidForeignKey.new(message,e)
|
381
|
+
when /has been chosen as the deadlock victim/i
|
382
|
+
DeadlockVictim.new(message,e)
|
372
383
|
when *lost_connection_messages
|
373
384
|
LostConnection.new(message,e)
|
374
385
|
else
|
@@ -431,6 +442,7 @@ module ActiveRecord
|
|
431
442
|
end
|
432
443
|
end
|
433
444
|
end
|
445
|
+
@spid = _raw_select("SELECT @@SPID", :fetch => :rows).first.first
|
434
446
|
configure_connection
|
435
447
|
rescue
|
436
448
|
raise unless @auto_connecting
|
@@ -468,15 +480,25 @@ module ActiveRecord
|
|
468
480
|
end if block_given?
|
469
481
|
end
|
470
482
|
|
471
|
-
def
|
483
|
+
def with_sqlserver_error_handling
|
472
484
|
begin
|
473
485
|
yield
|
474
486
|
rescue Exception => e
|
475
|
-
|
487
|
+
case translate_exception(e,e.message)
|
488
|
+
when LostConnection; retry if auto_reconnected?
|
489
|
+
when DeadlockVictim; retry if retry_deadlock_victim? && open_transactions == 0
|
490
|
+
end
|
476
491
|
raise
|
477
492
|
end
|
478
493
|
end
|
479
494
|
|
495
|
+
def disable_auto_reconnect
|
496
|
+
old_auto_connect, self.class.auto_connect = self.class.auto_connect, false
|
497
|
+
yield
|
498
|
+
ensure
|
499
|
+
self.class.auto_connect = old_auto_connect
|
500
|
+
end
|
501
|
+
|
480
502
|
def auto_reconnected?
|
481
503
|
return false unless auto_connect
|
482
504
|
@auto_connecting = true
|
@@ -138,9 +138,11 @@ module Arel
|
|
138
138
|
orders = o.orders.uniq
|
139
139
|
if windowed
|
140
140
|
projections = function_select_statement?(o) ? projections : projections.map { |x| projection_without_expression(x) }
|
141
|
+
groups = projections.map { |x| projection_without_expression(x) } if windowed_single_distinct_select_statement?(o) && groups.empty?
|
142
|
+
groups += orders.map { |x| Arel.sql(x.expr) } if windowed_single_distinct_select_statement?(o)
|
141
143
|
elsif eager_limiting_select_statement?(o)
|
142
|
-
groups = projections.map { |x| projection_without_expression(x) }
|
143
144
|
projections = projections.map { |x| projection_without_expression(x) }
|
145
|
+
groups = projections.map { |x| projection_without_expression(x) }
|
144
146
|
orders = orders.map do |x|
|
145
147
|
expr = Arel.sql projection_without_expression(x.expr)
|
146
148
|
x.descending? ? Arel::Nodes::Max.new([expr]) : Arel::Nodes::Min.new([expr])
|
@@ -162,7 +164,7 @@ module Arel
|
|
162
164
|
def visit_Arel_Nodes_SelectStatementWithOffset(o)
|
163
165
|
orders = rowtable_orders(o)
|
164
166
|
[ "SELECT",
|
165
|
-
(visit(o.limit) if o.limit && !
|
167
|
+
(visit(o.limit) if o.limit && !windowed_single_distinct_select_statement?(o)),
|
166
168
|
(rowtable_projections(o).map{ |x| visit(x) }.join(', ')),
|
167
169
|
"FROM (",
|
168
170
|
"SELECT ROW_NUMBER() OVER (ORDER BY #{orders.map{ |x| visit(x) }.join(', ')}) AS [__rn],",
|
@@ -238,6 +240,10 @@ module Arel
|
|
238
240
|
p1.respond_to?(:include?) && p1.include?('DISTINCT'))
|
239
241
|
end
|
240
242
|
|
243
|
+
def windowed_single_distinct_select_statement?(o)
|
244
|
+
o.limit && o.offset && single_distinct_select_statement?(o)
|
245
|
+
end
|
246
|
+
|
241
247
|
def single_distinct_select_everything_statement?(o)
|
242
248
|
single_distinct_select_statement?(o) && visit(o.cores.first.projections.first).ends_with?(".*")
|
243
249
|
end
|
@@ -316,7 +322,17 @@ module Arel
|
|
316
322
|
|
317
323
|
def rowtable_projections(o)
|
318
324
|
core = o.cores.first
|
319
|
-
if
|
325
|
+
if windowed_single_distinct_select_statement?(o) && core.groups.blank?
|
326
|
+
tn = table_from_select_statement(o).name
|
327
|
+
core.projections.map do |x|
|
328
|
+
x.dup.tap do |p|
|
329
|
+
p.sub! 'DISTINCT', ''
|
330
|
+
p.insert 0, visit(o.limit) if o.limit
|
331
|
+
p.gsub! /\[?#{tn}\]?\./, '[__rnt].'
|
332
|
+
p.strip!
|
333
|
+
end
|
334
|
+
end
|
335
|
+
elsif single_distinct_select_statement?(o)
|
320
336
|
tn = table_from_select_statement(o).name
|
321
337
|
core.projections.map do |x|
|
322
338
|
x.dup.tap do |p|
|
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: 11
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 3
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 3.1.
|
9
|
+
- 4
|
10
|
+
version: 3.1.4
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Ken Collins
|
@@ -19,8 +19,7 @@ autorequire:
|
|
19
19
|
bindir: bin
|
20
20
|
cert_chain: []
|
21
21
|
|
22
|
-
date: 2011-
|
23
|
-
default_executable:
|
22
|
+
date: 2011-11-30 00:00:00 Z
|
24
23
|
dependencies:
|
25
24
|
- !ruby/object:Gem::Dependency
|
26
25
|
name: activerecord
|
@@ -50,6 +49,7 @@ files:
|
|
50
49
|
- CHANGELOG
|
51
50
|
- MIT-LICENSE
|
52
51
|
- lib/active_record/connection_adapters/sqlserver/core_ext/active_record.rb
|
52
|
+
- lib/active_record/connection_adapters/sqlserver/core_ext/database_statements.rb
|
53
53
|
- lib/active_record/connection_adapters/sqlserver/core_ext/odbc.rb
|
54
54
|
- lib/active_record/connection_adapters/sqlserver/database_limits.rb
|
55
55
|
- lib/active_record/connection_adapters/sqlserver/database_statements.rb
|
@@ -60,7 +60,6 @@ files:
|
|
60
60
|
- lib/active_record/connection_adapters/sqlserver_adapter.rb
|
61
61
|
- lib/activerecord-sqlserver-adapter.rb
|
62
62
|
- lib/arel/visitors/sqlserver.rb
|
63
|
-
has_rdoc: true
|
64
63
|
homepage: http://github.com/rails-sqlserver/activerecord-sqlserver-adapter
|
65
64
|
licenses: []
|
66
65
|
|
@@ -90,7 +89,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
90
89
|
requirements: []
|
91
90
|
|
92
91
|
rubyforge_project: activerecord-sqlserver-adapter
|
93
|
-
rubygems_version: 1.
|
92
|
+
rubygems_version: 1.8.8
|
94
93
|
signing_key:
|
95
94
|
specification_version: 3
|
96
95
|
summary: SQL Server 2005 and 2008 Adapter For ActiveRecord.
|