ray_apps_blog

June 26, 2008

ruby-plsql gem now supports JRuby and Oracle JDBC driver

Filed under: jruby, oracle, pl/sql, ruby — Raimonds Simanovskis @ 9:11 pm

Some time ago I created ruby-plsql gem which provides simple Ruby API for Oracle PL/SQL stored procedures.

Initially this gem supported just MRI with ruby-oci8 library which provides connectivity to Oracle database as this was my main development and production environment for Ruby & Oracle applications. But as JRuby is fast growing alternative Ruby deployment platform and as it can be integrated into Oracle Fusion middleware platform (e.g. Oracle Mix is running on JRuby on Oracle Fusion middleware) then I planned to support JRuby as well.

I started to work on JRuby support during RailsConf JRuby hackfest and initially this did not seem very hard task for me. But as I did not know JDBC very well it took me much more time than initially planned. And unfortunately JDBC is also much less powerful compared to ruby-oci8 library for construction of dynamic PL/SQL calls. In addition I needed to strugle with Ruby and JDBC data type mappings which differs from Ruby and ruby-oci8 data type mappings.

But finally I have completed JRuby support and released ruby-plsql gem version 0.2.0. And good news are that from usage perspective ruby-plsql behaves identically on MRI and JRuby - at least my RSpec tests are telling so.

To install this gem on JRuby execute

sudo jruby -S gem install ruby-plsql

or

sudo jgem install ruby-plsql

depending on how you have installed JRuby on your computer.

Source code of ruby-plsql is located on GitHub where you can find usage examples in RSpec tests.

12 Comments »

  1. It seams that you also need to copy ojdbc14.jar to $JRUBY_HOME/lib directory as otherwise jruby cannot load this jar file and ruby-plsql will fail with “No suitable driver” exception.

    Comment by Raimonds Simanovskis — June 26, 2008 @ 9:55 pm

  2. Great job! yep, ojdbc14.jar is actually needed!

    Comment by Jesse Hu — June 27, 2008 @ 3:51 am

  3. Cool stuff, and it’s great to see other gem developers considering JRuby support. Feel free to announce on JRuby user list if you like.

    Comment by Charles Oliver Nutter — June 27, 2008 @ 4:30 am

  4. Ray,

    Thanks for the great work! I cannot seem to find the syntax for setting up a connection with jruby. The docs only cover setting up a new OCI8 based connection. If it is documented, would you mind pointing me in the right direction?

    Comment by Brett — July 31, 2008 @ 3:27 pm

  5. You just need to assign JDBC connection object to plsql.connection.

    So if you would like to use ruby-plsql without Rails / ActiveRecord then you need to establish connection, for example, in the following way:

    import java.sql.Statement
    import java.sql.Connection
    import java.sql.SQLException
    import java.sql.Types
    import java.sql.DriverManager
    DriverManager.registerDriver Java::oracle.jdbc.driver.OracleDriver.new
    jdbc_conn = DriverManager.getConnection(”jdbc:oracle:thin:@server:1521:SID”,”user”,”password”)
    plsql.connection = jdbc_conn

    if you are using it with Rails / ActiveRecord JDBC adapter then you can just put in environment.rb (or some initialization file):

    plsql.connection = ActiveRecord::Base.connection.connection

    Comment by Raimonds Simanovskis — August 3, 2008 @ 7:43 pm

  6. I’m having problems with it.

    That is what I did:

    - Included ojdbc14.jar in $JRUBY_HOME/lib;
    - Added $JRUBY_HOME/lib to PATH windows enviroment variable;

    And when I try to execute, it returns the following error:

    C:\project\trunk>jruby -S script\console
    Loading development environment (Rails 2.1.0)
    >> require “ruby_plsql”
    To use ruby_plsql you must have Oracle JDBC driver installed.
    => ["RubyPlsql"]

    >> plsql.connection = ActiveRecord::Base.connection.raw_connection
    ArgumentError: Unknown raw driver
    from C:/Documents and Settings/murad/Desktop/jruby-1.1.3/lib/ruby/gems/1.8/gems/ruby-plsql-0.2.2/lib/plsql/connection.rb:17:in `create’
    from C:/Documents and Settings/murad/Desktop/jruby-1.1.3/lib/ruby/gems/1.8/gems/ruby-plsql-0.2.2/lib/plsql/schema.rb:28:in `connection=’
    from (irb):3

    If I try this other way

    import java.sql.Statement
    import java.sql.Connection
    import java.sql.SQLException
    import java.sql.Types
    import java.sql.DriverManager
    DriverManager.registerDriver Java::oracle.jdbc.driver.OracleDriver.new
    jdbc_conn = DriverManager.getConnection(”jdbc:oracle:thin:@server:port:simu3″,”login”,”pass”)

    require “ruby_plsql”

    plsql.connection = jdbc_conn

    The connection works OK but when I try

    plsql.bra_customhr_eval_pk.validate_login_p(:p_username => “MMENEZES”, :p_password => “@senhateste2006″, :p_validate => nil)[:p_validate]

    I get the following error

    NoMethodError: undefined method `setStringAtName’ for #
    from C:/Documents and Settings/murad/Desktop/jruby-1.1.3/lib/ruby/gems/1.8/gems/ruby-plsql-0.2.2/lib/plsql/connection.rb:377:in `set_bind_variable’
    from C:/Documents and Settings/murad/Desktop/jruby-1.1.3/lib/ruby/gems/1.8/gems/ruby-plsql-0.2.2/lib/plsql/connection.rb:297:in `bind_param’
    from C:/Documents and Settings/murad/Desktop/jruby-1.1.3/lib/ruby/gems/1.8/gems/ruby-plsql-0.2.2/lib/plsql/procedure.rb:157:in `exec’
    from C:/Documents and Settings/murad/Desktop/jruby-1.1.3/lib/ruby/gems/1.8/gems/ruby-plsql-0.2.2/lib/plsql/procedure.rb:155:in `each’
    from C:/Documents and Settings/murad/Desktop/jruby-1.1.3/lib/ruby/gems/1.8/gems/ruby-plsql-0.2.2/lib/plsql/procedure.rb:155:in `exec’
    from C:/Documents and Settings/murad/Desktop/jruby-1.1.3/lib/ruby/gems/1.8/gems/ruby-plsql-0.2.2/lib/plsql/package.rb:31:in `method_missing’
    from (irb):19

    Any help will be appreciate!

    Thanks,
    Marcelo Murad

    Comment by Marcelo Murad — September 17, 2008 @ 8:44 pm

  7. I found out that the correct way how to assign JDBC connection from Rails JDBC adapter is:

    plsql.connection = ActiveRecord::Base.connection.raw_connection.connection

    And I also understood why you get this “you must have Oracle JDBC driver installed” error. I use the following code to find ojdbc14.jar in PATH:

    ojdbc_jar = “ojdbc14.jar”
    ojdbc_jar_path = ENV["PATH"].split(”:”).find{|d| File.exists?(File.join(d,ojdbc_jar))}

    but on Windows PATH directories are separated by “;” and not by “:” as in Unix. Sorry that I did not think about Windows collegues :)

    But in Rails case probably you can ignore this message as ActiveRecord JDBC adapter will already load all necessary JDBC drivers.

    Comment by Raimonds Simanovskis — September 17, 2008 @ 10:22 pm

  8. Thanks Raimonds,

    I did a fast update the file now connection association works, but I still get the setStringAtName error.

    >> require “ruby_plsql”
    => ["Statement", "Connection", "RubyPlsql", "Types", "DriverManager", "SQLException"]
    >> plsql.connection = ActiveRecord::Base.connection.raw_connection.connection
    => #
    >> plsql.bra_customhr_eval_pk.validate_login_p(:p_username => “MMENEZES”, :p_password => “@senhateste2006″, :p_validate => nil)[:p_validate]

    NoMethodError: undefined method `setStringAtName’ for #
    from C:/Documents and Settings/murad/Desktop/jruby-1.1.3/lib/ruby/gems/1.8/gems/ruby-plsql-0.2.2/lib/plsql/connection.rb:377:in `set
    _bind_variable’
    from C:/Documents and Settings/murad/Desktop/jruby-1.1.3/lib/ruby/gems/1.8/gems/ruby-plsql-0.2.2/lib/plsql/connection.rb:297:in `bin
    d_param’
    from C:/Documents and Settings/murad/Desktop/jruby-1.1.3/lib/ruby/gems/1.8/gems/ruby-plsql-0.2.2/lib/plsql/procedure.rb:157:in `exec

    from C:/Documents and Settings/murad/Desktop/jruby-1.1.3/lib/ruby/gems/1.8/gems/ruby-plsql-0.2.2/lib/plsql/procedure.rb:155:in `each

    from C:/Documents and Settings/murad/Desktop/jruby-1.1.3/lib/ruby/gems/1.8/gems/ruby-plsql-0.2.2/lib/plsql/procedure.rb:155:in `exec

    from C:/Documents and Settings/murad/Desktop/jruby-1.1.3/lib/ruby/gems/1.8/gems/ruby-plsql-0.2.2/lib/plsql/package.rb:34:in `method_
    missing’
    from (irb):4

    Comment by Marcelo Murad — September 17, 2008 @ 10:47 pm

  9. It was a older version of ojdbc14.jar. I uypdate it and it works like a charm!

    Comment by Marcelo Murad — September 17, 2008 @ 11:27 pm

  10. Raimonds,

    Try as I might, I just cannot get this to work. My current gems are:

    actionmailer (2.1.2, 2.0.2)
    actionpack (2.1.2, 2.0.2)
    activerecord (2.1.2, 2.0.2)
    activerecord-jdbc-adapter (0.8.2)
    activeresource (2.1.2, 2.0.2)
    activesupport (2.1.2, 2.0.2)
    composite_primary_keys (1.1.0, 0.8.6)
    jruby-openssl (0.3)
    rails (2.1.2, 2.0.2)
    rake (0.8.3)
    rspec (1.1.11)
    ruby-plsql (0.2.3)
    sources (0.0.1)

    And the code I am using is:

    require “rubygems”
    gem “activerecord”
    gem “ruby-plsql”

    require ‘active_record’
    require ‘ruby_plsql’
    require ‘pp’

    ActiveRecord::Base.establish_connection(:adapter => “jdbc”,
    :driver => “oracle.jdbc.OracleDriver”,
    :url => “removed”,
    :username => “removed”,
    :password => “removed”)

    class Foo < ActiveRecord::Base
    plsql = ActiveRecord::Base.connection.raw_connection
    puts plsql.class.to_s
    PLSQL::Procedure.find(plsql,’bal.test_it’)
    res = plsql.test_it(’foo’)
    pp res
    end

    I keep getting an error of:

    jruby-1.1.5/lib/ruby/gems/1.8/gems/ruby-plsql-0.2.3/lib/plsql/procedure.rb:5:in `find’: undefined method `schema_name’ for # (NoMethodError)

    I have been through a lot of the source code, and cannot seem to track down where these extra methods such as ’schema_name’ are getting added to the JdbcConnection class - have you any ideas as to where I am going wrong?

    Any help is much appreciated!

    Stephen.

    Comment by Stephen — November 13, 2008 @ 5:00 pm

  11. @Stephen

    Instead of

    plsql = ActiveRecord::Base.connection.raw_connection

    you need to write (in JRuby & JDBC case):

    plsql.connection = ActiveRecord::Base.connection.raw_connection.connection

    And better please put this line outside class definition.
    And you should not use PLSQL::Procedure.find :) Just use plsl.package_name.procedure_name

    Comment by Raimonds Simanovskis — November 13, 2008 @ 7:36 pm

  12. Raimonds,

    Works perfectly now for my test code at least. Now to port my OCI8 MRI code to ruby-plsql jruby instead …

    Thanks!

    Comment by Stephen — November 14, 2008 @ 12:27 pm

RSS feed for comments on this post.

Leave a comment

Blog at WordPress.com.