Tuesday, April 19, 2011

ActiveRecord JDBC adapter multiple database bug

My rails application need to two database simultaneously, one is db2 and the other is SQL server. Unfortunately I got an error called "undefined method `identity=' for". After googling, there is a bug reported here https://github.com/nicksieger/activerecord-jdbc-adapter/issues/25.

After tracing JDBC adapter source, I found the reason for my case: the class method column_types in arjdbc/jdbc/column.rb

@column_types ||= ::ArJdbc.constants.map{|c|
::ArJdbc.const_get c }.select{ |c|
c.respond_to? :column_selector }.map{|c|
c.column_selector }.inject({}) { |h,val|
h[val[0]] = val[1]; h }

Both MsSQL and DB2 are lazy loaded. When you have multiple databases, once @column_types is instantiated for db2, it will never be changed. But it is possible that MsSQL module is not loaded yet and so its column_selector is never called.

def self.column_selector
[/sqlserver|tds|Microsoft SQL/i, lambda {|cfg,col| col.extend(::ArJdbc::MsSQL::Column)}]
end

column_selector extends JdbcColumn with MsSQL version Column, and it defines :identity. If it is not called, "undefined method 'identity='" will be thrown.

The simple way I found to fix this issue: put the following in config/application.rb

# overcome activerecord-jdbc-adapter bug "undefined method 'identity='"
# for multiple databases by preloading the driver
if defined?(ArJdbc::Version::VERSION)
require 'arjdbc/db2'
require 'arjdbc/mssql'
end

No comments:

Post a Comment