module DBI
++
Dispatch classes (Handle, DriverHandle, DatabaseHandle and StatementHandle)
$Id: utils.rb,v 1.5 2006/01/29 06:14:19 djberg96 Exp $
Constants
- DEFAULT_TRACE_MODE
Module functions (of DBI)
- DEFAULT_TRACE_OUTPUT
- SQL_BIGINT
- SQL_BINARY
- SQL_BIT
- SQL_BLOB
TODO Find types for these (XOPEN?)
SQL_ARRAY =
- SQL_BOOLEAN
- SQL_CHAR
SQL type constants
- SQL_CLOB
- SQL_DATE
- SQL_DECIMAL
- SQL_DOUBLE
- SQL_FETCH_ABSOLUTE
- SQL_FETCH_FIRST
- SQL_FETCH_LAST
- SQL_FETCH_NEXT
Constants for fetch_scroll
- SQL_FETCH_PRIOR
- SQL_FETCH_RELATIVE
- SQL_FLOAT
- SQL_INTEGER
- SQL_LONGVARBINARY
- SQL_LONGVARCHAR
- SQL_NUMERIC
- SQL_OTHER
SQL_DISTINCT = SQL_OBJECT = SQL_NULL =
- SQL_REAL
- SQL_SMALLINT
- SQL_TIME
- SQL_TIMESTAMP
- SQL_TINYINT
- SQL_TYPE_NAMES
SQL_REF = SQL_STRUCT =
- SQL_VARBINARY
- SQL_VARCHAR
- VERSION
Public Class Methods
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 ::collect_drivers for reasons.
# File lib/dbi.rb, line 203 def available_drivers drivers = [] collect_drivers.each do |key, value| drivers.push("dbi:#{key}:") end return drivers end
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.
# File lib/dbi.rb, line 184 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 end end return drivers end
Establish a database connection.
Format goes as such: “dbi:Driver:database_conn_args”
-
“dbi” is the literal string “dbi”. Case is unimportant.
-
“Driver” is the case-dependent name of your database driver class. The file “dbd/#{Driver}” will be required. If you are using rubygems to control your DBDs and DBI, you must make the gem's file path available via the “gem” command before this will work.
-
database_conn_args can be:
-
The database name.
-
A more complex key/value association (to indicate host, etc). This is driver dependent; you should consult your DBD documentation.
-
# File lib/dbi.rb, line 144 def connect(driver_url, user=nil, auth=nil, params=nil, &p) dr, db_args = _get_full_driver(driver_url) dh = dr[0] # driver-handle dh.convert_types = @@convert_types @@last_connection = dh.connect(db_args, user, auth, params, &p) end
Return the current status of type conversion at this level. This status will be propogated to any new DatabaseHandles created.
# File lib/dbi.rb, line 119 def self.convert_types @@convert_types end
Set the current status of type conversion at this level. This status will be propogated to any new DatabaseHandles created.
# File lib/dbi.rb, line 125 def self.convert_types=(bool) @@convert_types = bool end
Attempt to collect the available data sources to the driver, specified in ::connect format.
The result is heavily dependent on the driver's ability to enumerate these sources, and results will vary.
# File lib/dbi.rb, line 216 def data_sources(driver) db_driver, = parse_url(driver) db_driver = load_driver(db_driver) dh = @@driver_map[db_driver][0] dh.data_sources end
Attempt to disconnect all database handles. If a driver is provided, disconnections will happen under that scope. Otherwise, all loaded drivers (and their handles) will be attempted.
# File lib/dbi.rb, line 228 def disconnect_all( driver = nil ) if driver.nil? @@driver_map.each {|k,v| v[0].disconnect_all} else db_driver, = parse_url(driver) @@driver_map[db_driver][0].disconnect_all end end
Return the last connection attempted.
# File lib/dbi.rb, line 113 def self.last_connection @@last_connection end
Enable tracing mode. Requires that 'dbi/trace' be required before it does anything.
As of 0.4.0, this mode does not do anything either way, so this currently just throws an InterfaceError. This issue is expected to be resolved in the next release.
# File lib/dbi.rb, line 171 def trace(mode=nil, output=nil) # FIXME trace raise InterfaceError, "the trace module has been removed until it actually works." @@trace_mode = mode || @@trace_mode || DBI::DEFAULT_TRACE_MODE @@trace_output = output || @@trace_output || DBI::DEFAULT_TRACE_OUTPUT end
Private Class Methods
Given a driver name, locate and load the associated DBD package, generate a DriverHandle and return it.
# File lib/dbi.rb, line 241 def load_driver(driver_name) @@driver_monitor.synchronize do unless @@driver_map[driver_name] dc = driver_name.downcase # caseless look for drivers already loaded found = @@driver_map.keys.find {|key| key.downcase == dc} return found if found begin require "dbd/#{driver_name}" rescue LoadError => e1 # see if you can find it in the path unless @@caseless_driver_name_map @@caseless_driver_name_map = { } collect_drivers.each do |key, value| @@caseless_driver_name_map[key.downcase] = value end end begin require @@caseless_driver_name_map[dc] if @@caseless_driver_name_map[dc] rescue LoadError => e2 raise e1.class, "Could not find driver #{driver_name} or #{driver_name.downcase} (error: #{e1.message})" end end # On a filesystem that is not case-sensitive (e.g., HFS+ on Mac OS X), # the initial require attempt that loads the driver may succeed even # though the lettercase of driver_name doesn't match the actual # filename. If that happens, const_get will fail and it become # necessary to look though the list of constants and look for a # caseless match. The result of this match provides the constant # with the proper lettercase -- which can be used to generate the # driver handle. dr = nil dr_error = nil begin dr = DBI::DBD.const_get(driver_name.intern) rescue NameError => dr_error # caseless look for constants to find actual constant dc = driver_name.downcase found = DBI::DBD.constants.find { |e| e.downcase == dc } dr = DBI::DBD.const_get(found.intern) unless found.nil? end # If dr is nil at this point, it means the underlying driver # failed to load. This usually means it's not installed, but # can fail for other reasons. if dr.nil? err = "Unable to load driver '#{driver_name}'" if dr_error err += " (underlying error: #{dr_error.message})" else err += " (BUG: could not determine underlying error)" end raise DBI::InterfaceError, err end dbd_dr = dr::Driver.new drh = DBI::DriverHandle.new(dbd_dr, @@convert_types) drh.driver_name = dr.driver_name # FIXME trace # drh.trace(@@trace_mode, @@trace_output) @@driver_map[driver_name] = [drh, dbd_dr] return driver_name else return driver_name end end rescue LoadError, NameError if $SAFE >= 1 raise InterfaceError, "Could not load driver (#{$!.message}). Note that in SAFE mode >= 1, driver URLs have to be case sensitive!" else raise InterfaceError, "Could not load driver (#{$!.message})" end end
Splits a DBI URL into two components - the database driver name and the datasource (along with any options, if any) and returns a two element array, e.g. 'dbi:foo:bar' would return ['foo','bar'].
A regular expression is used instead of a simple split to validate the proper format for the URL. If it isn't correct, an Interface error is raised.
# File lib/dbi.rb, line 329 def parse_url(driver_url) if driver_url =~ /^(DBI|dbi):([^:]+)(:(.*))$/ [$2, $4] else raise InterfaceError, "Invalid Data Source Name" end end