Почему хранимые процедуры все еще не поддерживаются в Rails (3+)?

Я знаком с давними отношениями между любовью и ненавистью между Ruby on Rails, DB (MS) -drivers и хранимыми процедурами, и я разрабатываю приложения Rails с версии 2.3.2.

Однако время от времени возникает ситуация, когда SP - просто лучший выбор, чем объединение данных на (гораздо медленнее) уровне приложения. В частности, запуск отчетов, который объединяет данные из нескольких таблиц, обычно лучше подходит для SP.

Почему хранящиеся процедуры все еще настолько плохо интегрированы в Rails или Gem. В настоящее время я работаю над проектом с Rails 3.0.10 и MySQL2 gem 0.2.13, но, насколько я вижу, даже самые последние Edge Rails и MySQL gem 0.3+ все еще бросают истерики при использовании SP.

Проблема, которая была и остается в том, что соединение с базой данных теряется после вызова SP.

>> ActiveRecord::Base.connection.execute("CALL stored_proc")
=> #<Mysql::Result:0x103429c90>
>> ActiveRecord::Base.connection.execute("CALL stored_proc")
ActiveRecord::StatementInvalid: Mysql::Error: Commands out of sync; 
[...]
>> ActiveRecord::Base.connection.active?
=> false
>> ActiveRecord::Base.connection.reconnect!
=> nil
>> ActiveRecord::Base.connection.execute("CALL proc01")
=> #<Mysql::Result:0x1034102e0>
>> ActiveRecord::Base.connection.active?
=> false

Это действительно сложная проблема для решения, технически, или это выбор дизайна Rails?

Ответ 1

Сохраненные процедуры поддерживаются в рельсах. Исключительная ошибка, которую вы получаете, заключается в том, что флаг MULTI_STATEMENTS для MySQL не включен по умолчанию в Rails. Этот флаг позволяет процедурам возвращать более 1 набора результатов.

См. здесь пример кода о том, как его включить: https://gist.github.com/wok/1367987

Сохраненные процедуры работают из коробки с MS SQL Server.

Я использую хранимые процедуры почти во всех моих проектах на основе mySQL и SQL Server без каких-либо выпусков.

Ответ 2

Это для postgres для выполнения хранимой процедуры, которая возвращает экземпляры MyClass.

sql=<<-SQL
select * from my_cool_sp_with_3_parameters(?, ?, ?) as 
foo(
  column_1 <type1>,
  column_2 <type2>
)
SQL

MyClass.find_by_sql([sql, param1, param2, param3]);

Замените список столбцов внутри foo() на столбцы из вашей модели и результаты хранимой процедуры. Я уверен, что это можно сделать общим, проверив столбцы класса.

Ответ 3

Те, кто получает ошибки синхронизации, могут иметь процедуры, которые генерируют несколько результатов. Вам нужно будет сделать что-то вроде этого, чтобы справиться с ними:

raise 'You updated Rails. Check this duck punch is still valid' unless Rails.version == "3.2.15"
module ActiveRecord
  module ConnectionAdapters
    class Mysql2Adapter
      def call_stored_procedure(sql)
        results = []
        results << select_all(sql)
        while @connection.more_results?
          results << @connection.next_result
        end
        results
      end
    end
  end
end

Вызов:

ActiveRecord::Base.connection.call_stored_procedure("CALL your_procedure('foo')")