Class: RDBI::Database
- Inherits:
-
Object
- Object
- RDBI::Database
- Extended by:
- MethLab
- Defined in:
- lib/rdbi/database.rb
Overview
RDBI::Database is the base class for database handles. This is the primary method in which most users will access their database system.
To execute statements, look at prepare
and execute
.
To retrieve schema information, look at schema
and table_schema
.
To deal with transactions, transaction
, commit
, and rollback
.
Instance Attribute Summary collapse
-
#connect_args ⇒ Object
readonly
the arguments used to create the connection.
-
#database_name ⇒ Object
the name of the database we’re connected to, if any.
-
#driver ⇒ Object
the driver class that is responsible for creating this database handle.
-
#mutex ⇒ Object
readonly
the mutex for this database handle.
Instance Method Summary collapse
-
#commit ⇒ Object
:method: commit ends the outstanding transaction and commits the result.
-
#connected ⇒ Object
:attr_accessor: connected? are we connected to the database?.
-
#disconnect ⇒ Object
disconnects from the database: will close (and complain, loudly) any statement handles left open.
-
#execute(query, *binds) ⇒ Object
Prepares and executes a statement.
-
#in_transaction ⇒ Object
:attr: in_transaction? are we currently in a transaction?.
-
#initialize(*args) ⇒ Database
constructor
Create a new database handle.
-
#last_query ⇒ Object
:attr: last_query the last query sent, as a string.
-
#last_statement ⇒ Object
:attr_reader: last_statement.
-
#open_statements ⇒ Object
:attr: open_statements all the open statement handles.
-
#ping ⇒ Object
:method: ping ping the database.
-
#prepare(query) ⇒ Object
Prepares a statement for execution.
-
#preprocess_query(query, *binds) ⇒ Object
Process the query as your driver would normally, and return the result.
-
#reconnect ⇒ Object
reconnect to the database.
-
#rollback ⇒ Object
:method: rollback ends the outstanding transaction and rolls the affected rows back.
-
#schema ⇒ Object
:method: schema query the schema for the entire database.
-
#table_schema ⇒ Object
:method: table_schema query the schema for a specific table.
-
#transaction(&block) ⇒ Object
Open a new transaction for processing.
Constructor Details
#initialize(*args) ⇒ Database
Create a new database handle. This is typically done by a driver and likely shouldn’t be done directly.
args is the connection arguments the user initially supplied to RDBI.connect.
90 91 92 93 94 95 96 |
# File 'lib/rdbi/database.rb', line 90 def initialize(*args) @connect_args = RDBI::Util.key_hash_as_symbols(args[0]) @connected = true @mutex = Mutex.new @in_transaction = 0 self.open_statements = [] end |
Instance Attribute Details
#connect_args ⇒ Object (readonly)
the arguments used to create the connection.
20 21 22 |
# File 'lib/rdbi/database.rb', line 20 def connect_args @connect_args end |
#database_name ⇒ Object
the name of the database we’re connected to, if any.
17 18 19 |
# File 'lib/rdbi/database.rb', line 17 def database_name @database_name end |
#driver ⇒ Object
the driver class that is responsible for creating this database handle.
14 15 16 |
# File 'lib/rdbi/database.rb', line 14 def driver @driver end |
#mutex ⇒ Object (readonly)
the mutex for this database handle.
48 49 50 |
# File 'lib/rdbi/database.rb', line 48 def mutex @mutex end |
Instance Method Details
#commit ⇒ Object
:method: commit ends the outstanding transaction and commits the result.
82 |
# File 'lib/rdbi/database.rb', line 82 inline(:commit) { @in_transaction -= 1 unless @in_transaction == 0 } |
#connected ⇒ Object
:attr_accessor: connected? are we connected to the database?
57 |
# File 'lib/rdbi/database.rb', line 57 inline(:connected, :connected?) { @connected } |
#disconnect ⇒ Object
disconnects from the database: will close (and complain, loudly) any statement handles left open.
108 109 110 111 112 113 114 115 |
# File 'lib/rdbi/database.rb', line 108 def disconnect unless self.open_statements.empty? warn "[RDBI] Open statements during disconnection -- automatically finishing. You should fix this." self.open_statements.each(&:finish) end self.open_statements = [] @connected = false end |
#execute(query, *binds) ⇒ Object
Prepares and executes a statement. Takes a string query and an optional number of variable type binds.
ex:
res = dbh.execute("select * from foo where item = ?", "an item")
ary = res.to_a
You can also use a block form which will finish the statement and yield the result handle:
dbh.execute("select * from foo where item = ?", "an item") do |res|
res.as(:Struct).fetch(:all).each do |struct|
p struct.item
end
end
Which will be considerably more performant under some database drivers.
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 |
# File 'lib/rdbi/database.rb', line 203 def execute(query, *binds) res = nil mutex.synchronize do self.last_query = query self.last_statement = sth = new_statement(query) res = sth.execute(*binds) if block_given? yield res else res.coerce_to_array end sth.finish end return res end |
#in_transaction ⇒ Object
:attr: in_transaction? are we currently in a transaction?
45 |
# File 'lib/rdbi/database.rb', line 45 inline(:in_transaction, :in_transaction?) { @in_transaction > 0 } |
#last_query ⇒ Object
:attr: last_query the last query sent, as a string.
31 |
# File 'lib/rdbi/database.rb', line 31 attr_threaded_accessor :last_query |
#last_statement ⇒ Object
:attr_reader: last_statement
the last statement handle allocated. affected by prepare
and execute
.
26 |
# File 'lib/rdbi/database.rb', line 26 attr_threaded_accessor :last_statement |
#open_statements ⇒ Object
:attr: open_statements all the open statement handles.
36 |
# File 'lib/rdbi/database.rb', line 36 attr_threaded_accessor :open_statements |
#ping ⇒ Object
:method: ping ping the database. yield an integer result on success.
62 |
# File 'lib/rdbi/database.rb', line 62 inline(:ping) { raise NoMethodError, "this method is not implemented in this driver" } |
#prepare(query) ⇒ Object
Prepares a statement for execution. Takes a query as its only argument, returns a RDBI::Statement.
ex:
sth = dbh.prepare("select * from foo where item = ?")
res = sth.execute("an item")
ary = res.to_a
sth.finish
You can also use a block form which will auto-finish:
dbh.prepare("select * from foo where item = ?") do |sth|
sth.execute("an item")
end
173 174 175 176 177 178 179 180 181 182 183 |
# File 'lib/rdbi/database.rb', line 173 def prepare(query) sth = nil mutex.synchronize do self.last_query = query sth = new_statement(query) yield sth if block_given? sth.finish if block_given? end return self.last_statement = sth end |
#preprocess_query(query, *binds) ⇒ Object
Process the query as your driver would normally, and return the result. Depending on the driver implementation and potentially connection settings, this may include interpolated data or client binding placeholders.
Driver Authors: if the instance variable @preprocess_quoter is set to a proc that accepts an index/key, a map of named binds and an array of indexed binds, it will be called instead of the default quoter and there is no need to override this method. For example:
def initialize(...)
@preprocess_quoter = proc do |x, named, indexed|
@some_handle.quote((named[x] || indexed[x]).to_s)
end
end
This will use RDBI’s code to manage the binds before quoting, but use your quoter during bind processing.
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 |
# File 'lib/rdbi/database.rb', line 243 def preprocess_query(query, *binds) mutex.synchronize do self.last_query = query end ep = Epoxy.new(query) hashes = binds.select { |x| x.kind_of?(Hash) } binds.collect! { |x| x.kind_of?(Hash) ? nil : x } total_hash = hashes.inject({}) { |x, y| x.merge(y) } if @preprocess_quoter.respond_to?(:call) ep.quote(total_hash) { |x| @preprocess_quoter.call(x, total_hash, binds) } else ep.quote(total_hash) { |x| %Q{'#{(total_hash[x] || binds[x]).to_s.gsub(/'/, "''")}'} } end end |
#reconnect ⇒ Object
reconnect to the database. Any outstanding connection will be terminated.
99 100 101 102 |
# File 'lib/rdbi/database.rb', line 99 def reconnect disconnect rescue nil @connected = true end |
#rollback ⇒ Object
:method: rollback ends the outstanding transaction and rolls the affected rows back.
77 |
# File 'lib/rdbi/database.rb', line 77 inline(:rollback) { @in_transaction -= 1 unless @in_transaction == 0 } |
#schema ⇒ Object
:method: schema query the schema for the entire database. Returns an array of RDBI::Schema objects.
72 |
# File 'lib/rdbi/database.rb', line 72 inline(:schema) { |*args| raise NoMethodError, "this method is not implemented in this driver" } |
#table_schema ⇒ Object
:method: table_schema query the schema for a specific table. Returns a RDBI::Schema object.
67 |
# File 'lib/rdbi/database.rb', line 67 inline(:table_schema) { |*args| raise NoMethodError, "this method is not implemented in this driver" } |
#transaction(&block) ⇒ Object
Open a new transaction for processing. Accepts a block which will execute the portions during the transaction.
Example:
dbh.transaction do |dbh|
dbh.execute("some query")
dbh.execute("some other query")
raise "oh crap!" # would rollback
dbh.commit # commits
dbh.rollback # rolls back
end
# at this point, if no raise or commit/rollback was triggered, it would
# commit.
Any exception that isn’t caught within this block will trigger a rollback. Additionally, you may use commit
and rollback
directly within the block to terminate the transaction early – at which point *the transaction is over with and you may be in autocommit*. The RDBI::Database accessor in_transaction
exists to tell you if RDBI thinks its in a transaction or not.
If you do not commit
or rollback
within the block and no exception is raised, RDBI presumes you wish this transaction to succeed and commits for you.
145 146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/rdbi/database.rb', line 145 def transaction(&block) @in_transaction += 1 begin yield self self.commit if @in_transaction > 0 rescue => e self.rollback raise e ensure @in_transaction -= 1 unless @in_transaction == 0 end end |