1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
|
begin
require 'fastthread'
rescue LoadError
end
module DataObjects
# An abstract connection to a DataObjects resource. The physical connection may be broken and re-established from time to time.
class Connection
include Logging
# Make a connection to the database using the DataObjects::URI given.
# Note that the physical connection may be delayed until the first command is issued, so success here doesn't necessarily mean you can connect.
def self.new(uri_s)
uri = DataObjects::URI::parse(uri_s)
case uri.scheme.to_sym
when :java
warn 'JNDI URLs (connection strings) are only for use with JRuby' unless RUBY_PLATFORM =~ /java/
driver = uri.query.delete('scheme')
driver = uri.query.delete('driver')
conn_uri = uri.to_s.gsub(/\?$/, '')
when :jdbc
warn 'JDBC URLs (connection strings) are only for use with JRuby' unless RUBY_PLATFORM =~ /java/
path = uri.subscheme
driver = if path.split(':').first == 'sqlite'
'sqlite3'
elsif path.split(':').first == 'postgresql'
'postgres'
else
path.split(':').first
end
conn_uri = uri_s # NOTE: for now, do not reformat this JDBC connection
# string -- or, in other words, do not let
# DataObjects::URI#to_s be called -- as it is not
# correctly handling JDBC URLs, and in doing so, causing
# java.sql.DriverManager.getConnection to throw a
# 'No suitable driver found for...' exception.
else
driver = uri.scheme
conn_uri = uri
end
# Exceptions to how a driver class is determined for a given URI
driver_class = if driver == 'sqlserver'
'SqlServer'
else
driver.capitalize
end
clazz = DataObjects.const_get(driver_class)::Connection
unless clazz.method_defined? :close
if (uri.scheme.to_sym == :java)
clazz.class_eval do
alias close dispose
end
else
clazz.class_eval do
include Pooling
alias close release
end
end
end
clazz.new(conn_uri)
end
# Ensure that all Connection subclasses handle pooling and logging uniformly.
# See also DataObjects::Pooling and DataObjects::Logger
def self.inherited(target)
target.class_eval do
# Allocate a Connection object from the pool, creating one if necessary. This method is active in Connection subclasses only.
def self.new(*args)
instance = allocate
instance.send(:initialize, *args)
instance
end
include Quoting
end
if driver_module_name = target.name.split('::')[-2]
driver_module = DataObjects::const_get(driver_module_name)
driver_module.class_eval <<-EOS, __FILE__, __LINE__
def self.logger
@logger
end
def self.logger=(logger)
@logger = logger
end
EOS
driver_module.logger = DataObjects::Logger.new(nil, :off)
end
end
#####################################################
# Standard API Definition
#####################################################
# Show the URI for this connection, without
# the password the connection was setup with
def to_s
@uri.to_s
end
def initialize(uri) #:nodoc:
raise NotImplementedError.new
end
def dispose #:nodoc:
raise NotImplementedError.new
end
# Create a Command object of the right subclass using the given text
def create_command(text)
concrete_command.new(self, text)
end
def extension
driver_namespace.const_get('Extension').new(self)
end
private
def driver_namespace
DataObjects::const_get(self.class.name.split('::')[-2])
end
def concrete_command
@concrete_command || begin
class << self
private
def concrete_command
@concrete_command
end
end
@concrete_command = DataObjects::const_get(self.class.name.split('::')[-2]).const_get('Command')
end
end
end
end
|