From da132939f4e520a829603848c30d69243fea5dc2 Mon Sep 17 00:00:00 2001 From: Ken Collins Date: Tue, 20 Apr 2010 15:16:06 -0400 Subject: [PATCH] Allow adapter to return multipe results sets, for example from stored procedures. Fixes issue #29. --- CHANGELOG | 2 + .../connection_adapters/sqlserver_adapter.rb | 40 +++++++++++++------ .../cases/execute_procedure_test_sqlserver.rb | 11 +++++ 3 files changed, 41 insertions(+), 12 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 3dd34f64e..da03b5d3f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,8 @@ MASTER +* Allow adapter to return multipe results sets, for example from stored procedures. [Chris Hall] + * 2.3.4 diff --git a/lib/active_record/connection_adapters/sqlserver_adapter.rb b/lib/active_record/connection_adapters/sqlserver_adapter.rb index 29ed00c40..dc5fcfe1b 100644 --- a/lib/active_record/connection_adapters/sqlserver_adapter.rb +++ b/lib/active_record/connection_adapters/sqlserver_adapter.rb @@ -394,7 +394,7 @@ def run_with_isolation_level(isolation_level) end def select_rows(sql, name = nil) - raw_select(sql,name).last + raw_select(sql,name).first.last end def execute(sql, name = nil, &block) @@ -410,7 +410,11 @@ def execute_procedure(proc_name, *variables) vars = variables.map{ |v| quote(v) }.join(', ') sql = "EXEC #{proc_name} #{vars}".strip select(sql,'Execute Procedure',true).inject([]) do |results,row| - results << row.with_indifferent_access + if row.kind_of?(Array) + results << row.inject([]) { |rs,r| rs << r.with_indifferent_access } + else + results << row.with_indifferent_access + end end end @@ -824,7 +828,15 @@ def auto_reconnected? def select(sql, name = nil, ignore_special_columns = false) repair_special_columns(sql) unless ignore_special_columns - fields, rows = raw_select(sql,name) + fields_and_row_sets = raw_select(sql,name) + final_result_set = fields_and_row_sets.inject([]) do |rs,fields_and_rows| + fields, rows = fields_and_rows + rs << zip_fields_and_rows(fields,rows) + end + final_result_set.many? ? final_result_set : final_result_set.first + end + + def zip_fields_and_rows(fields, rows) rows.inject([]) do |results,row| row_hash = {} fields.each_with_index do |f, i| @@ -859,24 +871,28 @@ def do_execute(sql,name=nil) def raw_select(sql, name = nil) handle = raw_execute(sql,name) - fields = handle.columns(true).map{|c|c.name} - results = handle_as_array(handle) - rows = results.inject([]) do |rows,row| - row.each_with_index do |value, i| - if value.is_a? ODBC::TimeStamp - row[i] = value.to_sqlserver_string + fields_and_row_sets = [] + loop do + fields = handle.columns(true).map{|c|c.name} + results = handle_as_array(handle) + rows = results.inject([]) do |rows,row| + row.each_with_index do |value, i| + if value.is_a? ODBC::TimeStamp + row[i] = value.to_sqlserver_string + end end + rows << row end - rows << row + fields_and_row_sets << [fields,rows] + finish_statement_handle(handle) && break unless handle.more_results end - return fields, rows + fields_and_row_sets end def handle_as_array(handle) array = handle.inject([]) do |rows,row| rows << row.inject([]){ |values,value| values << value } end - finish_statement_handle(handle) array end diff --git a/test/cases/execute_procedure_test_sqlserver.rb b/test/cases/execute_procedure_test_sqlserver.rb index 55d68317b..7aeba6ef5 100644 --- a/test/cases/execute_procedure_test_sqlserver.rb +++ b/test/cases/execute_procedure_test_sqlserver.rb @@ -29,5 +29,16 @@ def setup end if sqlserver_2000? end + should 'allow multiple result sets to be returned' do + results1, results2 = @klass.execute_procedure('sp_helpconstraint','accounts') + assert_instance_of Array, results1 + assert_instance_of HashWithIndifferentAccess, results1.first + assert results1.first['Object Name'] + assert_instance_of Array, results2 + assert_instance_of HashWithIndifferentAccess, results2.first + assert results2.first['constraint_name'] + assert results2.first['constraint_type'] + end + end