Sunday, May 27, 2007

ActiveRecord-JDBC db:schema:dump

AcitveRecord-JDBC JTDS db:schema:dump

I have a MS-Sql Server DB that I would like to test out under JRuby (0.9) and ActiveRecord-JDBC (0.3.1). I'm using JTDS. Two problems I ran into, and the patches that to fix them:

  • The first problem is "no type for date", and the fix has been posted somewhere by can-remember-who: add the bold line to ../ActiveRecord-JDBC-0.3.1/lib/active_record/connection_adapters/jdbc_adapter.rb
:date => [ lambda {|r| Jdbc::Types::DATE == r['data_type'].to_i},
lambda {|r| r['type_name'] =~ /^date$/i},
lambda {|r| r['type_name'] =~ /^datetime$/i}],

  • The next problem occures when I try to do a "rake db:schema:dump". I've search the web but failed to come up with any solution. There is actually a multitude of related problems:
    • method indexes is no defined in ../ActiveRecord-JDBC-0.3.1/lib/jdbc_adapter/jdbc_mssql.rb. So I simply copy it from jdbc_mysql.rb:
#### copy from mysql ###
def indexes(table_name, name = nil)#:nodoc:
r = @connection.indexes(table_name.upcase)
end
    • with the above modification, the tables are dumped in the resulting schema.rb (althought it also dump a bunch of system-tables and numeric(xx,yy) columns are not defined properly with the correct precision and scale, I could live with that for now). But all index tables failed. This look like a peculiarity with the JTDS driver that is not properly handled by jdbc_adapter. Here is the fix to jdbc_adapter.rb:

def indexes(table_name, name = nil)
metadata = @connection.getMetaData
unless String === table_name
table_name = table_name.to_s
else
table_name = table_name.dup
end
table_name.upcase! if metadata.storesUpperCaseIdentifiers
table_name.downcase! if metadata.storesLowerCaseIdentifiers
resultset = metadata.getIndexInfo(nil, nil, table_name, false, false)
primary_keys = primary_keys(table_name)
indexes = []
current_index = nil
while resultset.next
# index_name = resultset.get_string(Jdbc::IndexMetaData::INDEX_NAME).downcase
# The first resultset seems to contain information other than that of a index's column. INDEX_NAME is null.
# And you get a nil.downcase not defined
index_name = resultset.get_string(Jdbc::IndexMetaData::INDEX_NAME)
# just ignore if index_name is null
next if !index_name
index_name.downcase! if index_name
column_name = resultset.get_string(Jdbc::IndexMetaData::COLUMN_NAME).downcase


Note that the above fixes are more of a hack than a real solution.

I'm actually using Dr. Nic Magic Models on the legacy SQL Server database. I may blog about that when I find time for that.