Skip to content

Commit bebde18

Browse files
committed
Changelog all of Joe's work.
1 parent b580534 commit bebde18

File tree

5 files changed

+79
-66
lines changed

5 files changed

+79
-66
lines changed

CHANGELOG

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,18 @@
11

22
* master *
33

4+
* Add activity_stats method that mimics the SQL Server Activity Monitor. Fixes #146 [Joe Rafaniello]
5+
6+
* Add methods for sqlserver's #product_version, #product_level, #edition and include them in inspect.
7+
Fixes #145 [Joe Rafaniello]
8+
9+
* Handle statements that cannot be retried on a new database connection by not reconnecting.
10+
Fixes #147 [Joe Rafaniello]
11+
12+
* Added connection#spid for debugging. Fixes #144 [Joe Rafaniello]
13+
14+
* Add ENV['TEST_FILES'] to Rakefile for easy single case tests. [Joe Rafaniello]
15+
416
* Pass ActiveRecord tests. Made windowed distinct pass all orders to groups.
517
- test_limited_eager_with_multiple_order_columns
618
- test_limited_eager_with_order

Rakefile

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ end
1212

1313
def test_files
1414
return Dir.glob(ENV['TEST_FILES']).sort if ENV['TEST_FILES']
15-
1615
files = Dir.glob("test/cases/**/*_test_sqlserver.rb").sort
1716
ar_path = Gem.loaded_specs['activerecord'].full_gem_path
1817
ar_cases = Dir.glob("#{ar_path}/test/cases/**/*_test.rb")

lib/active_record/connection_adapters/sqlserver/database_statements.rb

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,51 @@ def newsequentialid_function
185185
select_value "SELECT NEWSEQUENTIALID()"
186186
end
187187

188+
def activity_stats
189+
select_all %|
190+
SELECT
191+
[session_id] = s.session_id,
192+
[user_process] = CONVERT(CHAR(1), s.is_user_process),
193+
[login] = s.login_name,
194+
[database] = ISNULL(db_name(r.database_id), N''),
195+
[task_state] = ISNULL(t.task_state, N''),
196+
[command] = ISNULL(r.command, N''),
197+
[application] = ISNULL(s.program_name, N''),
198+
[wait_time_ms] = ISNULL(w.wait_duration_ms, 0),
199+
[wait_type] = ISNULL(w.wait_type, N''),
200+
[wait_resource] = ISNULL(w.resource_description, N''),
201+
[blocked_by] = ISNULL(CONVERT (varchar, w.blocking_session_id), ''),
202+
[head_blocker] =
203+
CASE
204+
-- session has an active request, is blocked, but is blocking others
205+
WHEN r2.session_id IS NOT NULL AND r.blocking_session_id = 0 THEN '1'
206+
-- session is idle but has an open tran and is blocking others
207+
WHEN r.session_id IS NULL THEN '1'
208+
ELSE ''
209+
END,
210+
[total_cpu_ms] = s.cpu_time,
211+
[total_physical_io_mb] = (s.reads + s.writes) * 8 / 1024,
212+
[memory_use_kb] = s.memory_usage * 8192 / 1024,
213+
[open_transactions] = ISNULL(r.open_transaction_count,0),
214+
[login_time] = s.login_time,
215+
[last_request_start_time] = s.last_request_start_time,
216+
[host_name] = ISNULL(s.host_name, N''),
217+
[net_address] = ISNULL(c.client_net_address, N''),
218+
[execution_context_id] = ISNULL(t.exec_context_id, 0),
219+
[request_id] = ISNULL(r.request_id, 0),
220+
[workload_group] = N''
221+
FROM sys.dm_exec_sessions s LEFT OUTER JOIN sys.dm_exec_connections c ON (s.session_id = c.session_id)
222+
LEFT OUTER JOIN sys.dm_exec_requests r ON (s.session_id = r.session_id)
223+
LEFT OUTER JOIN sys.dm_os_tasks t ON (r.session_id = t.session_id AND r.request_id = t.request_id)
224+
LEFT OUTER JOIN
225+
(SELECT *, ROW_NUMBER() OVER (PARTITION BY waiting_task_address ORDER BY wait_duration_ms DESC) AS row_num
226+
FROM sys.dm_os_waiting_tasks
227+
) w ON (t.task_address = w.waiting_task_address) AND w.row_num = 1
228+
LEFT OUTER JOIN sys.dm_exec_requests r2 ON (r.session_id = r2.blocking_session_id)
229+
WHERE db_name(r.database_id) = '#{current_database}'
230+
ORDER BY s.session_id|
231+
end
232+
188233
# === SQLServer Specific (Rake/Test Helpers) ==================== #
189234

190235
def recreate_database
@@ -307,13 +352,15 @@ def raw_connection_do(sql)
307352
# === SQLServer Specific (Selecting) ============================ #
308353

309354
def raw_select(sql, name=nil, binds=[], options={})
310-
log(sql,name,binds) do
311-
begin
312-
handle = raw_connection_run(sql)
313-
handle_to_names_and_values(handle, options)
314-
ensure
315-
finish_statement_handle(handle)
316-
end
355+
log(sql,name,binds) { _raw_select(sql, options) }
356+
end
357+
358+
def _raw_select(sql, options={})
359+
begin
360+
handle = raw_connection_run(sql)
361+
handle_to_names_and_values(handle, options)
362+
ensure
363+
finish_statement_handle(handle)
317364
end
318365
end
319366

lib/active_record/connection_adapters/sqlserver_adapter.rb

Lines changed: 1 addition & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -371,52 +371,6 @@ def cs_equality_operator
371371
@@cs_equality_operator || 'COLLATE Latin1_General_CS_AS_WS'
372372
end
373373

374-
def activity_stats
375-
self.select(<<-EOSQL)
376-
SELECT
377-
[session_id] = s.session_id,
378-
[user_process] = CONVERT(CHAR(1), s.is_user_process),
379-
[login] = s.login_name,
380-
[database] = ISNULL(db_name(r.database_id), N''),
381-
[task_state] = ISNULL(t.task_state, N''),
382-
[command] = ISNULL(r.command, N''),
383-
[application] = ISNULL(s.program_name, N''),
384-
[wait_time_ms] = ISNULL(w.wait_duration_ms, 0),
385-
[wait_type] = ISNULL(w.wait_type, N''),
386-
[wait_resource] = ISNULL(w.resource_description, N''),
387-
[blocked_by] = ISNULL(CONVERT (varchar, w.blocking_session_id), ''),
388-
[head_blocker] =
389-
CASE
390-
-- session has an active request, is blocked, but is blocking others
391-
WHEN r2.session_id IS NOT NULL AND r.blocking_session_id = 0 THEN '1'
392-
-- session is idle but has an open tran and is blocking others
393-
WHEN r.session_id IS NULL THEN '1'
394-
ELSE ''
395-
END,
396-
[total_cpu_ms] = s.cpu_time,
397-
[total_physical_io_mb] = (s.reads + s.writes) * 8 / 1024,
398-
[memory_use_kb] = s.memory_usage * 8192 / 1024,
399-
[open_transactions] = ISNULL(r.open_transaction_count,0),
400-
[login_time] = s.login_time,
401-
[last_request_start_time] = s.last_request_start_time,
402-
[host_name] = ISNULL(s.host_name, N''),
403-
[net_address] = ISNULL(c.client_net_address, N''),
404-
[execution_context_id] = ISNULL(t.exec_context_id, 0),
405-
[request_id] = ISNULL(r.request_id, 0),
406-
[workload_group] = N''
407-
FROM sys.dm_exec_sessions s LEFT OUTER JOIN sys.dm_exec_connections c ON (s.session_id = c.session_id)
408-
LEFT OUTER JOIN sys.dm_exec_requests r ON (s.session_id = r.session_id)
409-
LEFT OUTER JOIN sys.dm_os_tasks t ON (r.session_id = t.session_id AND r.request_id = t.request_id)
410-
LEFT OUTER JOIN
411-
(SELECT *, ROW_NUMBER() OVER (PARTITION BY waiting_task_address ORDER BY wait_duration_ms DESC) AS row_num
412-
FROM sys.dm_os_waiting_tasks
413-
) w ON (t.task_address = w.waiting_task_address) AND w.row_num = 1
414-
LEFT OUTER JOIN sys.dm_exec_requests r2 ON (r.session_id = r2.blocking_session_id)
415-
WHERE db_name(r.database_id) = '#{current_database}'
416-
ORDER BY s.session_id
417-
EOSQL
418-
end
419-
420374
protected
421375

422376
# === Abstract Adapter (Misc Support) =========================== #
@@ -457,7 +411,6 @@ def connect
457411
:encoding => encoding,
458412
:azure => config[:azure]
459413
}).tap do |client|
460-
@spid = client.execute("SELECT @@spid").first.values.first
461414
if config[:azure]
462415
client.execute("SET ANSI_NULLS ON").do
463416
client.execute("SET CURSOR_CLOSE_ON_COMMIT OFF").do
@@ -490,6 +443,7 @@ def connect
490443
end
491444
end
492445
end
446+
@spid = _raw_select("SELECT @@SPID", :fetch => :rows).first.first
493447
configure_connection
494448
rescue
495449
raise unless @auto_connecting

test/cases/connection_test_sqlserver.rb

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -92,15 +92,13 @@ def setup
9292
assert @connection.active?
9393
end
9494

95-
if connection_mode_dblib?
96-
should 'set spid on connect' do
97-
assert @connection.spid.kind_of?(Fixnum)
98-
end
99-
100-
should 'reset spid on disconnect!' do
101-
@connection.disconnect!
102-
assert @connection.spid.nil?
103-
end
95+
should 'set spid on connect' do
96+
assert_instance_of Fixnum, @connection.spid
97+
end
98+
99+
should 'reset spid on disconnect!' do
100+
@connection.disconnect!
101+
assert @connection.spid.nil?
104102
end
105103

106104
should 'be able to disconnect and reconnect at will' do
@@ -126,6 +124,7 @@ def setup
126124
end
127125

128126
context 'testing #disable_auto_reconnect' do
127+
129128
should 'when auto reconnect setting is on' do
130129
with_auto_connect(true) do
131130
@connection.send(:disable_auto_reconnect) do
@@ -143,6 +142,7 @@ def setup
143142
assert !@connection.class.auto_connect
144143
end
145144
end
145+
146146
end
147147

148148
should 'not auto reconnect on commit transaction' do
@@ -167,13 +167,14 @@ def setup
167167
end
168168

169169
context 'Diagnostics' do
170+
170171
should 'testing #activity_stats' do
171172
stats = @connection.activity_stats
172-
assert stats.length > 0
173-
173+
assert stats.length > 0
174174
assert stats.all? { |s| s.has_key?("session_id") }
175175
assert stats.all? { |s| s["database"] == @connection.current_database }
176176
end
177+
177178
end
178179

179180

0 commit comments

Comments
 (0)