Sunday, January 25, 2009

Ruby DBI does find DBD drivers on Mac when using Gem

I found a very nice problem when trying to use DBI on a mac, with the sqlite3 driver
I've been a avid your of dbi, which is a direct database API in Ruby, that allow
low level access to databases.

I've used it on Linux, and Windows against Oracle extensively, and several other databases.

So expected it to work the same. Seems like I hit a small problem in that oh.

My script was telling me no driver. When I ran the dbi command, it showed there was no drivers.
If I used irb, and did a DBI.drivers_available, it told me none.

First, a quick review of the installed gems:

sh-3.2# gem list

*** LOCAL GEMS ***

actionmailer (2.2.2)
actionpack (2.2.2)
activerecord (2.2.2)
activeresource (2.2.2)
activesupport (2.2.2)
dbd-sqlite3 (1.2.4)
dbi (0.4.1)
deprecated (2.0.1)
gem_plugin (0.2.3)
hpricot (0.6.164)
mechanize (0.9.0)
nokogiri (1.1.1)
rails (2.2.2)
rake (0.8.3)
scrubyt (0.4.06)
sqlite3-ruby (1.2.4)
wxruby (1.9.9)

Yep, Its there, everything looks ok.

Now lets track down the source to find out what is going on.
# Returns a list (of String) of the currently available drivers on your system in
# 'dbi:driver:' format.
# This currently does not work for rubygems installations, please see
# DBI.collect_drivers for reasons.
def available_drivers
drivers = []
collect_drivers.each do |key, value|
return drivers
That looks ok.

Lets go and see what collect_drivers()
# Return a list (of String) of the available drivers.
# NOTE:: This is non-functional for gem installations, due to the
# nature of how it currently works. A better solution for
# this will be provided in DBI 0.6.0.
def collect_drivers
drivers = { }
# FIXME rewrite this to leverage require and be more intelligent
path = File.join(File.dirname(__FILE__), "dbd", "*.rb")
Dir[path].each do |f|
if File.file?(f)
driver = File.basename(f, ".rb")
drivers[driver] = f

Ok, the FIXME gives us the clue.
Looks like it does not bother to search thru rubygems.
You must manually copy the dbd drivers into dbi.

The Solution:
Copy the drivers into the dbi gem.
cd /opt/local/lib/ruby/gems/1.8/gems/dbi-0.4.1/lib
cp -r ../../dbd-sqlite3-1.2.4/lib/dbd dbd


Anonymous said...

You saved me from pulling out my hair- i am using DBI 0.4.1 with OCI8. The OCI page says it does not work with DBI 0.4.1 - i followed instructions to your solution for OCI8 and it works!

Kevin said...

Many thx. Solved my exact problem undoubtedly saving me many hours!