如何使用ActiveRecord调用带有OUT参数的DB2存储过程?

时间:2015-11-12 21:02:24

标签: ruby stored-procedures activerecord db2 jruby

我需要使用ActiveRecord调用一些旧的存储过程。

当没有参数或只有IN参数时,我可以使用ActiveRecords调用程序。

e.g。

ActiveRecord::Base.connection.execute('call legacy_proc')

ActiveRecord::Base.connection.execute("call legacy_proc('param1', 'param2')")

以上工作完美无缺。现在,当我需要使用OUT参数调用一个过程时出现问题。我尝试了不同的方式来调用SP,但我无法让它工作。

 ActiveRecord::Base.connection.execute("call legacy_proc_with_out_params('param1', 'param2', ?, ?)")

 ActiveRecord::Base.connection.execute("call legacy_proc_with_out_params('param1', 'param2', null, null)")

 ActiveRecord::Base.connection.execute("call legacy_proc_with_out_params('param1', 'param2', '', '')")

以上工作都没有(最后两个参数是OUT参数)。作为最后一个选项,我甚至可以跳过读取OUT参数,如果这真的不可能,只要我至少可以执行该程序。

编辑:添加错误详细信息以澄清“不工作”。

 ActiveRecord::StatementInvalid: ActiveRecord::JDBCError: com.ibm.db2.jcc.am.SqlException: DB2 SQL Error: SQLCODE=-313, SQLSTATE=07004, SQLERRMC=null, DRIVER=4.15.113: call legacy_proc_with_out_params('param1', 'param2', ?, ?)
    from arjdbc/jdbc/RubyJdbcConnection.java:547:in `execute'
    from /home/devusr.gem/gems/activerecord-jdbc-adapter-1.3.16/lib/arjdbc/jdbc/adapter.rb:581:in `_execute'
    from /home/devusr.gem/gems/activerecord-jdbc-adapter-1.3.16/lib/arjdbc/jdbc/adapter.rb:557:in `execute'
    from /home/devusr.gem/gems/activerecord-4.1.8/lib/active_record/connection_adapters/abstract_adapter.rb:373:in `log'
    from /home/devusr.gem/gems/activesupport-4.1.8/lib/active_support/notifications/instrumenter.rb:20:in `instrument'
    from /home/devusr.gem/gems/activerecord-4.1.8/lib/active_record/connection_adapters/abstract_adapter.rb:367:in `log'
    from /home/devusr.gem/gems/activerecord-jdbc-adapter-1.3.16/lib/arjdbc/jdbc/adapter.rb:557:in `execute'
    from (irb):30:in `evaluate'
    from org/jruby/RubyKernel.java:1119:in `eval'
    from org/jruby/RubyKernel.java:1519:in `loop'
    from org/jruby/RubyKernel.java:1282:in `catch'
    from org/jruby/RubyKernel.java:1282:in `catch'
    from /home/devusr.gem/gems/railties-4.1.8/lib/rails/commands/console.rb:90:in `start'
    from /home/devusr.gem/gems/railties-4.1.8/lib/rails/commands/console.rb:9:in `start'
    from /home/devusr.gem/gems/railties-4.1.8/lib/rails/commands/commands_tasks.rb:69:in `console'
    from /home/devusr.gem/gems/railties-4.1.8/lib/rails/commands/commands_tasks.rb:40:in `run_command!'
    from /home/devusr.gem/gems/railties-4.1.8/lib/rails/commands.rb:17:in `(root)'
    from org/jruby/RubyKernel.java:1083:in `require'

编辑2:尝试了@ mustaccio的建议(即通过prepare使用raw_connection方法,但DB2适配器没有实现该方法。如果有替代路径来实现类似方法DB2,这肯定会解决问题。

我也忘了提到我正在使用jRuby。因此,我正在使用DB2的jdbc适配器。

 irb(main):049:0> ActiveRecord::ConnectionAdapters.constants.grep /DB2/
 => [:DB2Column, :DB2JdbcConnection]

 irb(main):050:0> ActiveRecord::Base.connection.raw_connection.methods.sort.grep /prep/
 => []

 irb(main):051:0>  ActiveRecord::Base.connection.raw_connection.prepare
 NoMethodError: undefined method `prepare' for #<ActiveRecord::ConnectionAdapters::DB2JdbcConnection:0xe6bc1cd0>
    from (irb):51:in `evaluate'
    from org/jruby/RubyKernel.java:1119:in `eval'
    from org/jruby/RubyKernel.java:1519:in `loop'
    from org/jruby/RubyKernel.java:1282:in `catch'
    from org/jruby/RubyKernel.java:1282:in `catch'
    from /home/srpec/.gem/gems/railties-4.1.8/lib/rails/commands/console.rb:90:in `start'
    from /home/srpec/.gem/gems/railties-4.1.8/lib/rails/commands/console.rb:9:in `start'
    from /home/srpec/.gem/gems/railties-4.1.8/lib/rails/commands/commands_tasks.rb:69:in `console'
    from /home/srpec/.gem/gems/railties-4.1.8/lib/rails/commands/commands_tasks.rb:40:in `run_command!'
    from /home/srpec/.gem/gems/railties-4.1.8/lib/rails/commands.rb:17:in `(root)'
    from org/jruby/RubyKernel.java:1083:in `require'
    from bin/rails:4:in `(root)'

1 个答案:

答案 0 :(得分:0)

我找到的解决方案是使用BEGIN-END块并声明虚拟变量以绑定到OUT参数。

给出这个例子:

ActiveRecord::Base.connection.execute("call legacy_proc_with_out_params('param1', 'param2', ?, ?)")

如果第一个OUT参数是INTEGER而第二个是SMALLINT,则完整调用如下所示:

 beginend_stmt = "BEGIN
                      DECLARE out_Param1 INTEGER;
                      DECLARE out_Param2 SMALLINT;

                      call legacy_proc_with_out_params('param1', 'param2', out_Param1, out_Param2);
                  END"

  ActiveRecord::Base.connection.execute beginend_stmt