Class: RDBI::Database
- Inherits:
-
Object
- Object
- RDBI::Database
- Defined in:
- lib/rdbi/database.rb
Overview
RDBI::Database is the base class for database handles. Most users will access their database system through this class.
To execute statements, look at prepare
and execute
.
To retrieve schema information, look at schema
and table_schema
.
To deal with transactions, refer to transaction
, commit
, and rollback
.
Instance Attribute Summary collapse
-
#connect_args ⇒ Object
readonly
the arguments used to create the connection.
-
#connected ⇒ Object
(also: #connected?)
readonly
are we connected to the database?.
-
#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.
-
#last_query ⇒ Object
the last query sent, as a string.
-
#last_statement ⇒ Object
the last statement handle allocated.
-
#open_statements ⇒ Object
all the open statement handles.
-
#rewindable_result ⇒ Object
see RDBI::Statement#rewindable_result.
Instance Method Summary collapse
-
#commit ⇒ Object
ends the outstanding transaction and commits the result.
-
#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.
-
#execute_modification(query, *binds) ⇒ Object
Prepare, execute and finish a statement, returning the number of rows affected (number of rows INSERTed, DELETEd, etc.).
-
#in_transaction ⇒ Object
(also: #in_transaction?)
are we currently in a transaction?.
-
#initialize(*args) ⇒ Database
constructor
Create a new database handle.
-
#ping ⇒ Object
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.
-
#quote(item) ⇒ Object
Quote a single item using a consistent quoting method.
-
#reconnect ⇒ Object
reconnect to the database.
-
#rollback ⇒ Object
ends the outstanding transaction and rolls the affected rows back.
-
#schema ⇒ Object
query the schema for the entire database.
-
#table_schema(table_name) ⇒ Object
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.
75 76 77 78 79 80 81 82 |
# File 'lib/rdbi/database.rb', line 75 def initialize(*args) @connect_args = RDBI::Util.key_hash_as_symbols(args[0]) @connected = true @in_transaction = 0 @rewindable_result = false @preprocess_quoter = nil self.open_statements = { } end |
Instance Attribute Details
#connect_args ⇒ Object (readonly)
the arguments used to create the connection.
21 22 23 |
# File 'lib/rdbi/database.rb', line 21 def connect_args @connect_args end |
#connected ⇒ Object (readonly) Also known as: connected?
are we connected to the database?
41 42 43 |
# File 'lib/rdbi/database.rb', line 41 def connected @connected end |
#database_name ⇒ Object
the name of the database we’re connected to, if any.
15 16 17 |
# File 'lib/rdbi/database.rb', line 15 def database_name @database_name end |
#driver ⇒ Object
the driver class that is responsible for creating this database handle.
12 13 14 |
# File 'lib/rdbi/database.rb', line 12 def driver @driver end |
#last_query ⇒ Object
the last query sent, as a string.
27 28 29 |
# File 'lib/rdbi/database.rb', line 27 def last_query @last_query end |
#last_statement ⇒ Object
the last statement handle allocated. affected by prepare
and execute
.
24 25 26 |
# File 'lib/rdbi/database.rb', line 24 def last_statement @last_statement end |
#open_statements ⇒ Object
all the open statement handles.
30 31 32 |
# File 'lib/rdbi/database.rb', line 30 def open_statements @open_statements end |
#rewindable_result ⇒ Object
see RDBI::Statement#rewindable_result
18 19 20 |
# File 'lib/rdbi/database.rb', line 18 def rewindable_result @rewindable_result end |
Instance Method Details
#commit ⇒ Object
ends the outstanding transaction and commits the result.
65 66 67 |
# File 'lib/rdbi/database.rb', line 65 def commit @in_transaction -= 1 unless @in_transaction == 0 end |
#disconnect ⇒ Object
disconnects from the database: will close (and complain, loudly) any statement handles left open.
94 95 96 97 98 99 |
# File 'lib/rdbi/database.rb', line 94 def disconnect @connected = false # FIXME - this is not serving a useful purpose nor public API self.open_statements.values.each { |x| x.finish if x } self.open_statements = { } 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
If invoked with a block, the result handle will be yielded and the handle and statement will be finished at the end of the block. Use this form when the result handle is not needed outside the block:
dbh.execute("select * from foo where item = ?", "an item") do |res|
res.as(:Struct).fetch(:all).each do |struct|
p struct.item
end
end
Block invocation may be considerably more efficient under some database drivers.
For DDL and other statements which return no rows, see #execute_modification.
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 |
# File 'lib/rdbi/database.rb', line 196 def execute(query, *binds) res = nil sth = prepare(query) begin res = sth.execute(*binds) rescue Exception => e sth.finish rescue nil raise e end unless block_given? RDBI::Util.upon_finalize!(res, sth, :finish) return res end begin yield res ensure res.finish rescue nil sth.finish rescue nil end end |
#execute_modification(query, *binds) ⇒ Object
Prepare, execute and finish a statement, returning the number of rows affected (number of rows INSERTed, DELETEd, etc.).
Effectively equivalent to
dbh.execute(sql_stmt) do |res|
res.affected_count
end
but likely more efficient. See also RDBI::Statement#execute_modification
232 233 234 235 236 237 |
# File 'lib/rdbi/database.rb', line 232 def execute_modification(query, *binds) sth = prepare(query) sth.execute_modification(*binds) ensure sth.finish rescue nil end |
#in_transaction ⇒ Object Also known as: in_transaction?
are we currently in a transaction?
33 34 35 |
# File 'lib/rdbi/database.rb', line 33 def in_transaction @in_transaction > 0 end |
#ping ⇒ Object
ping the database. yield an integer result on success.
45 46 47 |
# File 'lib/rdbi/database.rb', line 45 def ping raise NoMethodError, "this method is not implemented in this driver" end |
#prepare(query) ⇒ Object
Prepares a statement for execution. Takes a query as its only argument, returns an 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
157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/rdbi/database.rb', line 157 def prepare(query) sth = new_statement(query) self.last_query = query self.open_statements[sth.object_id] = self.last_statement = ::WeakRef.new(sth) return sth unless block_given? begin yield sth ensure sth.finish rescue nil end 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.
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 |
# File 'lib/rdbi/database.rb', line 259 def preprocess_query(query, *binds) self.last_query = query 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 |
#quote(item) ⇒ Object
Quote a single item using a consistent quoting method.
278 279 280 |
# File 'lib/rdbi/database.rb', line 278 def quote(item) "\'#{item.to_s}\'" end |
#reconnect ⇒ Object
reconnect to the database. Any outstanding connection will be terminated.
85 86 87 88 |
# File 'lib/rdbi/database.rb', line 85 def reconnect disconnect rescue nil @connected = true end |
#rollback ⇒ Object
ends the outstanding transaction and rolls the affected rows back.
60 61 62 |
# File 'lib/rdbi/database.rb', line 60 def rollback @in_transaction -= 1 unless @in_transaction == 0 end |
#schema ⇒ Object
query the schema for the entire database. Returns an array of RDBI::Schema objects.
55 56 57 |
# File 'lib/rdbi/database.rb', line 55 def schema raise NoMethodError, "this method is not implemented in this driver" end |
#table_schema(table_name) ⇒ Object
query the schema for a specific table. Returns an RDBI::Schema object.
50 51 52 |
# File 'lib/rdbi/database.rb', line 50 def table_schema(table_name) raise NoMethodError, "this method is not implemented in this driver" end |
#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.
129 130 131 132 133 134 135 136 137 138 139 140 |
# File 'lib/rdbi/database.rb', line 129 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 |