views:

2365

answers:

3

When I try to call a stored procedure from Rails, I get this exception:

ActiveRecord::StatementInvalid: Mysql::Error: PROCEDURE pipeline-ws_development.match_save_all can't return a result set in the given context: call match_save_all()
    from /Users/otto/Projects/Futures/src/pipeline-ws/vendor/rails/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb:150:in `log'
    from /Users/otto/Projects/Futures/src/pipeline-ws/vendor/rails/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb:281:in `execute'
    from (irb):3

There is a page in the Rails Wiki that discusses a patch for the MySQL adapter that resolves this issue, but it's out-of-date and doesn't seem to work anymore.

The configuration code enables stored procedures correctly, but it still has the issue with the connection getting out of sync after a stored procedure call and the new call_sp method doesn't work anymore.

Any suggestions for how to get this working?

This is the code I'm using:

ActiveRecord::Base.connection("call storedproc()")

It throws the same exception whether storedproc() returns any results or not.

+1  A: 

Would it work to wrap the procedure in a function? If Ruby's barfing due to no rows returned (...can't return a result set in the given context...), this may fix it:

DELIMITER $

CREATE PROCEDURE tProc()
BEGIN
    SET @a = 'test';
END;
$

CREATE FUNCTION tFunc()
RETURNS INT
BEGIN
    CALL tProc();
    RETURN 1;
END;
$

DELIMITER ;

SELECT tFunc() FROM DUAL;
>> 1

SELECT @a FROM DUAL;
>> 'test'

Although, realistically, this isn't a very extensible solution.

Followup: I'm pretty n00by at Ruby/ActiveRecord, but this example definitely works

ActiveRecord::Base.establish_connection(authopts)

class TestClass < ActiveRecord::Base
end

test_class = TestClass.new
puts %{#{test_class.connection.select_one('SELECT tFunc() AS tf FROM DUAL')}}
>> tf1

Using CALL tProc() resulted in an error similar to yours.

kyle
Your example works, but with our stored proc I get "ERROR 1415 (0A000): Not allowed to return a result set from a function". I'm going to talk to the guy who wrote them and see if we can't rewrite them to return things like your example.
Otto
This moves us forward, but we still have a couple procs that need to return a lot of data that won't work in variables.
Otto
I went ahead and accepted, as this seems to be the best current solution. There's still the issue of returning lots of data, but it's been a few days and no one has come up with something better. I don't think it exists without fixing the MySQL adapter.
Otto
I'm a little unclear -- can procs return data? I'm fairly sure procs in MySQL return nothing. Can you elaborate?
kyle
+1  A: 

Are you using ActiveRecord::Base.connection.execute? This method should allow you to execute some arbitrary SQL statement that isn't naively supported in the Active Record wrapper.

PJ Davis
That is what I'm using, and I get that exception.
Otto
A: 

I've submitted a patch to Rails 2.3.4 which gives a configuration option to fix this problem. Please stop by my ticket and show your support for it!

https://rails.lighthouseapp.com/projects/8994/tickets/3151-mysql-adapter-update-to-enable-use-of-stored-procedures

Justin Bailey