Class: Amalgalite::Database
- Inherits:
-
Object
- Object
- Amalgalite::Database
- Includes:
- SQLite3::Constants
- Defined in:
- lib/amalgalite/database.rb
Overview
The encapsulation of a connection to an SQLite3 database.
Example opening and possibly creating a new database
db = Amalgalite::Database.new( "mydb.db" )
db.execute( "SELECT * FROM table" ) do |row|
puts row
end
db.close
Open a database read only:
db = Amalgalite::Database.new( "mydb.db", "r" )
Open an in-memory database:
db = Amalgalite::MemoryDatabase.new
Direct Known Subclasses
Defined Under Namespace
Classes: AggregateError, BusyHandlerError, FunctionError, InvalidModeError, ProgressHandlerError, TransactionBehavior
Constant Summary collapse
- VALID_MODES =
list of valid modes for opening an Amalgalite::Database
{ "r" => Open::READONLY, "r+" => Open::READWRITE, "w+" => Open::READWRITE | Open::CREATE, }
Instance Attribute Summary collapse
-
#aggregates ⇒ Object
readonly
A list of the user defined aggregates.
-
#api ⇒ Object
readonly
the low level Amalgalite::SQLite3::Database.
-
#functions ⇒ Object
readonly
A list of the user defined functions.
-
#profile_tap ⇒ Object
readonly
An object that follows the ProfileTap protocol, or nil.
-
#trace_tap ⇒ Object
An object that follows the TraceTap protocol, or nil.
-
#type_map ⇒ Object
An object that follows the TypeMap protocol, or nil.
Instance Method Summary collapse
-
#autocommit? ⇒ Boolean
Is the database in autocommit mode or not.
-
#clear_taps! ⇒ Object
clear all the current taps.
-
#close ⇒ Object
Close the database.
-
#commit ⇒ Object
Commit a transaction.
-
#define_aggregate(name, klass) ⇒ Object
(also: #aggregate)
call-seq: db.define_aggregate( ‘name’, MyAggregateClass ).
-
#define_busy_handler(callable = nil, &block) ⇒ Object
(also: #busy_handler)
call-seq: db.busy_handler( callable ) db.define_busy_handler do |count| end db.busy_handler( Amalgalite::BusyTimeout.new( 30 ) ).
-
#define_function(name, callable = nil, &block) ⇒ Object
(also: #function)
call-seq: db.define_function( “name”, MyDBFunction.new ) db.define_function( “my_func”, callable ) db.define_function( “my_func” ) do |x,y| .…
-
#define_progress_handler(op_code_count = 25, callable = nil, &block) ⇒ Object
(also: #progress_handler)
call-seq: db.progress_handler( 50, MyProgressHandler.new ) db.progress_handler( 25 , callable ) db.progress_handler do .…
-
#encoding ⇒ Object
return the encoding of the database.
-
#escape(s) ⇒ Object
SQL escape the input string.
-
#exclusive_transaction(&block) ⇒ Object
helper for an exclusive transaction.
-
#execute(sql, *bind_params) ⇒ Object
Execute a single SQL statement.
-
#execute_batch(sql, *bind_params) ⇒ Object
Execute a batch of statements, this will execute all the sql in the given string until no more sql can be found in the string.
-
#first_row_from(sql, *bind_params) ⇒ Object
Execute a sql statment, and only return the first row of results.
-
#first_value_from(sql, *bind_params) ⇒ Object
Execute an sql statement, and return only the first column of the first row.
-
#immediate_transaction(&block) ⇒ Object
helper for an immediate transaction.
-
#import(sql) ⇒ Object
Execute a batch of statements via sqlite3_exec.
-
#import_csv_to_table(csv_path, table_name, options = {}) ⇒ Object
call-seq: db.import_csv_to_table( “/some/location/data.csv”, “my_table” ) db.import_csv_to_table( “countries.csv”, “countries”, :col_sep => “|”, :headers => %w[ name two_letter id ] ).
-
#in_transaction? ⇒ Boolean
return whether or not the database is currently in a transaction or not.
-
#initialize(filename, mode = "w+", opts = {}) ⇒ Database
constructor
Create a new Amalgalite database.
-
#interrupt! ⇒ Object
call-seq: db.interrupt!.
-
#last_insert_rowid ⇒ Object
Return the rowid of the last inserted row.
-
#open? ⇒ Boolean
Is the database open or not.
-
#pragma(cmd, &block) ⇒ Object
Run a pragma command against the database.
-
#prepare(sql) ⇒ Object
Prepare a statement for execution.
-
#quote(s) ⇒ Object
Surround the give string with single-quotes and escape any single-quotes in the string.
-
#release(point_name) ⇒ Object
call-seq: db.release( ‘mypoint’ ).
-
#reload_schema!(dbname = "main") ⇒ Object
:call-seq: db.reload_schema! -> Schema.
-
#remove_aggregate(name, klass_or_arity = nil) ⇒ Object
call-seq: db.remove_aggregate( ‘name’, MyAggregateClass ) db.remove_aggregate( ‘name’ ).
-
#remove_busy_handler ⇒ Object
call-seq: db.remove_busy_handler.
-
#remove_function(name, callable_or_arity = nil) ⇒ Object
call-seq: db.remove_function( ‘name’, MyScalerFunctor.new ) db.remove_function( ‘name’, callable ) db.remove_function( ‘name’, arity ) db.remove_function( ‘name’ ).
-
#remove_progress_handler ⇒ Object
call-seq: db.remove_progress_handler.
-
#replicate_to(location) ⇒ Object
call-seq: db.replicate_to( “:memory:” ) -> new_db db.replicate_to( “/some/location/my.db” ) -> new_db db.replicate_to( Amalgalite::Database.new( “/my/backup.db” ) ) -> new_db.
-
#rollback ⇒ Object
Rollback a transaction.
-
#rollback_to(point_name) ⇒ Object
call-seq: db.rollback_to( point_name ).
-
#row_changes ⇒ Object
return how many rows changed in the last insert, update or delete statement.
-
#savepoint(name) ⇒ Object
call-seq: db.savepoint( ‘mypoint’ ) -> db db.savepoint( ‘mypoint’ ) do |db_in_savepoint| …
-
#schema(dbname = "main") ⇒ Object
:call-seq: db.schema( dbname = “main” ) -> Schema.
-
#total_changes ⇒ Object
return how many rows have changed since this connection to the database was opened.
-
#transaction(mode = TransactionBehavior::DEFERRED, &block) ⇒ Object
(also: #deferred_transaction)
Begin a transaction.
-
#utf16? ⇒ Boolean
Is the database utf16 or not? A database is utf16 if the encoding is not UTF-8.
Constructor Details
#initialize(filename, mode = "w+", opts = {}) ⇒ Database
Create a new Amalgalite database
:call-seq:
Amalgalite::Database.new( filename, "w+", opts = {}) -> Database
The first parameter is the filename of the sqlite database. Specifying “:memory:” as the filename creates an in-memory database.
The second parameter is the standard file modes of how to open a file.
The modes are:
-
r - Read-only
-
r+ - Read/write, an error is thrown if the database does not already exist
-
w+ - Read/write, create a new database if it doesn’t exist
w+
is the default as this is how most databases will want to be utilized.
opts is a hash of available options for the database:
-
:utf16 option to set the database to a utf16 encoding if creating a database.
By default, databases are created with an encoding of utf8. Setting this to true and opening an already existing database has no effect.
NOTE Currently :utf16 is not supported by Amalgalite, it is planned for a later release
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
# File 'lib/amalgalite/database.rb', line 139 def initialize( filename, mode = "w+", opts = {}) @open = false @profile_tap = nil @trace_tap = nil @type_map = ::Amalgalite::TypeMaps::DefaultMap.new @functions = Hash.new @aggregates = Hash.new @utf16 = false unless VALID_MODES.keys.include?( mode ) raise InvalidModeError, "#{mode} is invalid, must be one of #{VALID_MODES.keys.join(', ')}" end if not File.exist?( filename ) and opts[:utf16] then raise NotImplementedError, "Currently Amalgalite has not implemented utf16 support" else @api = Amalgalite::SQLite3::Database.open( filename, VALID_MODES[mode] ) end @open = true end |
Instance Attribute Details
#aggregates ⇒ Object (readonly)
A list of the user defined aggregates
107 108 109 |
# File 'lib/amalgalite/database.rb', line 107 def aggregates @aggregates end |
#api ⇒ Object (readonly)
the low level Amalgalite::SQLite3::Database
91 92 93 |
# File 'lib/amalgalite/database.rb', line 91 def api @api end |
#functions ⇒ Object (readonly)
A list of the user defined functions
104 105 106 |
# File 'lib/amalgalite/database.rb', line 104 def functions @functions end |
#profile_tap ⇒ Object (readonly)
An object that follows the ProfileTap protocol, or nil. By default this is nil
97 98 99 |
# File 'lib/amalgalite/database.rb', line 97 def profile_tap @profile_tap end |
#trace_tap ⇒ Object
An object that follows the TraceTap protocol, or nil. By default this is nil
94 95 96 |
# File 'lib/amalgalite/database.rb', line 94 def trace_tap @trace_tap end |
#type_map ⇒ Object
An object that follows the TypeMap protocol, or nil.
By default this is an instances of TypeMaps::DefaultMap
101 102 103 |
# File 'lib/amalgalite/database.rb', line 101 def type_map @type_map end |
Instance Method Details
#autocommit? ⇒ Boolean
Is the database in autocommit mode or not
180 181 182 |
# File 'lib/amalgalite/database.rb', line 180 def autocommit? @api.autocommit? end |
#clear_taps! ⇒ Object
clear all the current taps
340 341 342 |
# File 'lib/amalgalite/database.rb', line 340 def clear_taps! self.trace_tap = nil end |
#close ⇒ Object
Close the database
170 171 172 173 174 175 |
# File 'lib/amalgalite/database.rb', line 170 def close if open? then @api.close @open = false end end |
#commit ⇒ Object
Commit a transaction
621 622 623 |
# File 'lib/amalgalite/database.rb', line 621 def commit execute( "COMMIT TRANSACTION" ) if in_transaction? end |
#define_aggregate(name, klass) ⇒ Object Also known as: aggregate
call-seq:
db.define_aggregate( 'name', MyAggregateClass )
Define an SQL aggregate function, these are functions like max(), min(), avg(), etc. SQL functions that would be used when a GROUP BY clause is in effect. See also ::Amalgalite::Aggregate.
A new instance of MyAggregateClass is created for each instance that the SQL aggregate is mentioned in SQL.
718 719 720 721 722 723 724 725 726 |
# File 'lib/amalgalite/database.rb', line 718 def define_aggregate( name, klass ) db_aggregate = klass a = klass.new raise AggregateError, "Use only mandatory or arbitrary parameters in an SQL Aggregate, not both" if a.arity < -1 raise AggregateError, "Aggregate implementation name '#{a.name}' does not match defined name '#{name}'" if a.name != name @api.define_aggregate( name, a.arity, klass ) @aggregates[a.signature] = db_aggregate nil end |
#define_busy_handler(callable = nil, &block) ⇒ Object Also known as: busy_handler
call-seq:
db.busy_handler( callable )
db.define_busy_handler do |count|
end
db.busy_handler( Amalgalite::BusyTimeout.new( 30 ) )
Register a busy handler for this database connection, the handler MUST follow the to_proc
protocol indicating that is will respond_to?(:call). This is intrinsic to lambdas and blocks so those will work automatically.
This exposes the sqlite busy handler api to ruby.
The busy handler’s _call(N)_ method may be invoked whenever an attempt is made to open a database table that another thread or process has locked. N
will be the number of times the _call(N)_ method has been invoked during this locking event.
The handler may or maynot be called based upon what SQLite determins.
If the handler returns nil or false then no more busy handler calls will be made in this lock event and you are probably going to see an SQLite::Error in your immediately future in another process or in another piece of code.
If the handler returns non-nil or non-false then another attempt will be made to obtain the lock, lather, rinse, repeat.
If an Exception happens in a busy handler, it will be the same as if the busy handler had returned nil or false. The exception itself will not be propogated further.
804 805 806 807 808 809 |
# File 'lib/amalgalite/database.rb', line 804 def define_busy_handler( callable = nil, &block ) handler = ( callable || block ).to_proc a = handler.arity raise BusyHandlerError, "A busy handler expects 1 and only 1 argument, not #{a}" if a != 1 @api.busy_handler( handler ) end |
#define_function(name, callable = nil, &block) ⇒ Object Also known as: function
call-seq:
db.define_function( "name", MyDBFunction.new )
db.define_function( "my_func", callable )
db.define_function( "my_func" ) do |x,y|
....
return result
end
register a callback to be exposed as an SQL function. There are multiple ways to register this function:
-
db.define_function( “name” ) { |a| … }
-
pass
define_function
a name and a block. -
The SQL function name taking arity parameters will be registered, where arity is the arity of the block.
-
The return value of the block is the return value of the registred SQL function
-
-
db.define_function( “name”, callable )
-
pass
function
a name and something thatresponds_to?( :to_proc )
-
The SQL function name is registered taking arity parameters is registered where arity is the arity of
callable.to_proc.call
-
The return value of the
callable.to_proc.call
is the return value of the SQL function
-
See also ::Amalgalite::Function
659 660 661 662 663 664 665 666 |
# File 'lib/amalgalite/database.rb', line 659 def define_function( name, callable = nil, &block ) p = ( callable || block ).to_proc raise FunctionError, "Use only mandatory or arbitrary parameters in an SQL Function, not both" if p.arity < -1 db_function = ::Amalgalite::SQLite3::Database::Function.new( name, p ) @api.define_function( db_function.name, db_function ) @functions[db_function.signature] = db_function nil end |
#define_progress_handler(op_code_count = 25, callable = nil, &block) ⇒ Object Also known as: progress_handler
call-seq:
db.progress_handler( 50, MyProgressHandler.new )
db.progress_handler( 25 , callable )
db.progress_handler do
....
return result
end
Register a progress handler for this database connection, the handler MUST follow the to_proc
protocol indicating that is will respond_to?(:call). This is intrinsic to lambdas and blocks so those will work automatically.
This exposes the sqlite progress handler api to ruby.
The progress handler’s _call()_ method may be invoked ever N SQLite op codes. If the progress handler returns anything that can evaluate to true
then current running sqlite statement is terminated at the earliest oppportunity.
You can use this to be notified that a thread is still processingn a request.
859 860 861 862 863 864 |
# File 'lib/amalgalite/database.rb', line 859 def define_progress_handler( op_code_count = 25, callable = nil, &block ) handler = ( callable || block ).to_proc a = handler.arity raise ProgressHandlerError, "A progress handler expects 0 arguments, not #{a}" if a != 0 @api.progress_handler( op_code_count, handler ) end |
#encoding ⇒ Object
return the encoding of the database
220 221 222 |
# File 'lib/amalgalite/database.rb', line 220 def encoding @encoding ||= pragma( "encoding" ).first['encoding'] end |
#escape(s) ⇒ Object
SQL escape the input string
194 195 196 |
# File 'lib/amalgalite/database.rb', line 194 def escape( s ) Amalgalite::SQLite3.escape( s ) end |
#exclusive_transaction(&block) ⇒ Object
helper for an exclusive transaction
543 544 545 |
# File 'lib/amalgalite/database.rb', line 543 def exclusive_transaction( &block ) transaction( TransactionBehavior::EXCLUSIVE, &block ) end |
#execute(sql, *bind_params) ⇒ Object
Execute a single SQL statement.
If called with a block and there are result rows, then they are iteratively yielded to the block.
If no block is passed, then all the results are returned as an arrayfields instance. This is an array with field name access.
If no block is passed, and there are no results, then an empty Array is returned.
On an error an exception is thrown
This is just a wrapper around the preparation of an Amalgalite Statement and iterating over the results.
294 295 296 297 298 299 300 301 302 303 304 |
# File 'lib/amalgalite/database.rb', line 294 def execute( sql, *bind_params ) stmt = prepare( sql ) stmt.bind( *bind_params ) if block_given? then stmt.each { |row| yield row } else return stmt.all_rows end ensure stmt.close if stmt end |
#execute_batch(sql, *bind_params) ⇒ Object
Execute a batch of statements, this will execute all the sql in the given string until no more sql can be found in the string. It will bind the same parameters to each statement. All data that would be returned from all of the statements is thrown away.
All statements to be executed in the batch must be terminated with a ‘;’ Returns the number of statements executed
316 317 318 319 320 321 322 323 324 325 326 327 |
# File 'lib/amalgalite/database.rb', line 316 def execute_batch( sql, *bind_params) count = 0 while sql prepare( sql ) do |stmt| stmt.execute( *bind_params ) sql = stmt.remaining_sql sql = nil unless (sql.index(";") and Amalgalite::SQLite3.complete?( sql )) end count += 1 end return count end |
#first_row_from(sql, *bind_params) ⇒ Object
Execute a sql statment, and only return the first row of results. This is a shorthand method when you only want a single row of results from a query. If there is no result, then return an empty array
It is in all other was, exactly like #execute()
351 352 353 354 355 356 357 |
# File 'lib/amalgalite/database.rb', line 351 def first_row_from( sql, *bind_params ) stmt = prepare( sql ) stmt.bind( *bind_params) row = stmt.next_row || [] stmt.close return row end |
#first_value_from(sql, *bind_params) ⇒ Object
Execute an sql statement, and return only the first column of the first row. If there is no result, return nil.
It is in all other ways, exactly like #first_row_from()
365 366 367 |
# File 'lib/amalgalite/database.rb', line 365 def first_value_from( sql, *bind_params ) return first_row_from( sql, *bind_params).first end |
#immediate_transaction(&block) ⇒ Object
helper for an immediate transaction
538 539 540 |
# File 'lib/amalgalite/database.rb', line 538 def immediate_transaction( &block ) transaction( TransactionBehavior::IMMEDIATE, &block ) end |
#import(sql) ⇒ Object
Execute a batch of statements via sqlite3_exec. This does the same as execute_batch, but doesn’t update the statement statistics.
333 334 335 |
# File 'lib/amalgalite/database.rb', line 333 def import(sql) @api.execute_batch(sql) end |
#import_csv_to_table(csv_path, table_name, options = {}) ⇒ Object
call-seq:
db.import_csv_to_table( "/some/location/data.csv", "my_table" )
db.import_csv_to_table( "countries.csv", "countries", :col_sep => "|", :headers => %w[ name two_letter id ] )
import_csv_to_table() takes 2 required arguments, and a hash of options. The first argument is the path to a CSV, the second is the table in which to load the data. The options has is a subset of those used by CSV
-
:col_sep - the string placed between each field. Default is “,”
-
:row_sep - the String appended to the end of each row. Default is :auto
-
:quote_char - The character used to quote fields. Default ‘“’
-
:headers - set to true or :first_row if there are headers in this CSV. Default is false.
This may also be an Array. If that is the case then the array is used as the fields in the CSV and the fields in the table in which to insert. If this is set to an Array, it is assumed that all rows in the csv will be inserted.
927 928 929 930 |
# File 'lib/amalgalite/database.rb', line 927 def import_csv_to_table( csv_path, table_name, = {} ) importer = CSVTableImporter.new( csv_path, self, table_name, ) importer.run end |
#in_transaction? ⇒ Boolean
return whether or not the database is currently in a transaction or not
227 228 229 |
# File 'lib/amalgalite/database.rb', line 227 def in_transaction? not @api.autocommit? end |
#interrupt! ⇒ Object
call-seq:
db.interrupt!
Cause another thread with a handle on this database to be interrupted and return at the earliest opportunity as interrupted. It is not safe to call this method if the database might be closed before interrupt! returns.
829 830 831 |
# File 'lib/amalgalite/database.rb', line 829 def interrupt! @api.interrupt! end |
#last_insert_rowid ⇒ Object
Return the rowid of the last inserted row
187 188 189 |
# File 'lib/amalgalite/database.rb', line 187 def last_insert_rowid @api.last_insert_rowid end |
#open? ⇒ Boolean
Is the database open or not
163 164 165 |
# File 'lib/amalgalite/database.rb', line 163 def open? @open end |
#pragma(cmd, &block) ⇒ Object
Run a pragma command against the database
Returns the result set of the pragma
474 475 476 |
# File 'lib/amalgalite/database.rb', line 474 def pragma( cmd, &block ) execute("PRAGMA #{cmd}", &block) end |
#prepare(sql) ⇒ Object
Prepare a statement for execution
If called with a block, the statement is yielded to the block and the statement is closed when the block is done.
db.prepare( "SELECT * FROM table WHERE c = ?" ) do |stmt|
list_of_c_values.each do |c|
stmt.execute( c ) do |row|
puts "when c = #{c} : #{row.inspect}"
end
end
end
Or without a block:
stmt = db.prepare( "INSERT INTO t1(x, y, z) VALUES ( :
264 265 266 267 268 269 270 271 272 273 274 275 |
# File 'lib/amalgalite/database.rb', line 264 def prepare( sql ) stmt = Amalgalite::Statement.new( self, sql ) if block_given? then begin yield stmt ensure stmt.close stmt = nil end end return stmt end |
#quote(s) ⇒ Object
Surround the give string with single-quotes and escape any single-quotes in the string
201 202 203 |
# File 'lib/amalgalite/database.rb', line 201 def quote( s ) Amalgalite::SQLite3.quote( s ) end |
#release(point_name) ⇒ Object
call-seq:
db.release( 'mypoint' )
Release a savepoint. This is similar to a commit but only for savepoints. All savepoints up the savepoint stack and include the name savepoint being released are ‘committed’ to the transaction. There are several ways of thinking about release and they are all detailed in the sqlite documentation: sqlite.org/lang_savepoint.html
604 605 606 |
# File 'lib/amalgalite/database.rb', line 604 def release( point_name ) execute( "RELEASE SAVEPOINT #{point_name}" ) if in_transaction? end |
#reload_schema!(dbname = "main") ⇒ Object
:call-seq:
db.reload_schema! -> Schema
By default once the schema is obtained, it is cached. This is here to force the schema to be reloaded.
465 466 467 468 |
# File 'lib/amalgalite/database.rb', line 465 def reload_schema!( dbname = "main" ) @schema = nil schema( dbname ) end |
#remove_aggregate(name, klass_or_arity = nil) ⇒ Object
call-seq:
db.remove_aggregate( 'name', MyAggregateClass )
db.remove_aggregate( 'name' )
Remove an aggregate from use in the database. Since the same aggregate may be refistered more than once with different arity, you may specify the arity, or the aggregate class, or nil. If nil is used for the arity then Amalgalite does its best to remove all aggregates of the given name
739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 |
# File 'lib/amalgalite/database.rb', line 739 def remove_aggregate( name, klass_or_arity = nil ) klass = nil case klass_or_arity when Integer arity = klass_or_arity when NilClass arity = nil else klass = klass_or_arity arity = klass.new.arity end to_remove = [] if arity then signature = ::Amalgalite::SQLite3::Database::Function.signature( name, arity ) db_aggregate = @aggregates[ signature ] raise AggregateError, "db aggregate '#{name}' with arity #{arity} does not appear to be defined" unless db_aggregate to_remove << db_aggregate else possibles = @aggregates.values.select { |a| a.new.name == name } raise AggregateError, "no db aggregate '#{name}' appears to be defined" if possibles.empty? to_remove = possibles end to_remove.each do |db_agg| i = db_agg.new @api.remove_aggregate( i.name, i.arity, db_agg) @aggregates.delete( i.signature ) end end |
#remove_busy_handler ⇒ Object
call-seq:
db.remove_busy_handler
Remove the busy handler for this database connection.
817 818 819 |
# File 'lib/amalgalite/database.rb', line 817 def remove_busy_handler @api.busy_handler( nil ) end |
#remove_function(name, callable_or_arity = nil) ⇒ Object
call-seq:
db.remove_function( 'name', MyScalerFunctor.new )
db.remove_function( 'name', callable )
db.remove_function( 'name', arity )
db.remove_function( 'name' )
Remove a function from use in the database. Since the same function may be registered more than once with different arity, you may specify the arity, or the function object, or nil. If nil is used for the arity, then Amalgalite does its best to remove all functions of given name.
681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 |
# File 'lib/amalgalite/database.rb', line 681 def remove_function( name, callable_or_arity = nil ) arity = nil if callable_or_arity.respond_to?( :to_proc ) then arity = callable_or_arity.to_proc.arity elsif callable_or_arity.respond_to?( :to_int ) then arity = callable_or_arity.to_int end to_remove = [] if arity then signature = ::Amalgalite::SQLite3::Database::Function.signature( name, arity ) db_function = @functions[ signature ] raise FunctionError, "db function '#{name}' with arity #{arity} does not appear to be defined" unless db_function to_remove << db_function else possibles = @functions.values.select { |f| f.name == name } raise FunctionError, "no db function '#{name}' appears to be defined" if possibles.empty? to_remove = possibles end to_remove.each do |db_func| @api.remove_function( db_func.name, db_func ) @functions.delete( db_func.signature ) end end |
#remove_progress_handler ⇒ Object
call-seq:
db.remove_progress_handler
Remove the progress handler for this database connection.
872 873 874 |
# File 'lib/amalgalite/database.rb', line 872 def remove_progress_handler @api.progress_handler( nil, nil ) end |
#replicate_to(location) ⇒ Object
call-seq:
db.replicate_to( ":memory:" ) -> new_db
db.replicate_to( "/some/location/my.db" ) -> new_db
db.replicate_to( Amalgalite::Database.new( "/my/backup.db" ) ) -> new_db
replicate_to() takes a single argument, either a String or an Amalgalite::Database. It returns the replicated database object. If given a String, it will truncate that database if it already exists.
Replicate the current database to another location, this can be used for a number of purposes:
-
load an sqlite database from disk into memory
-
snaphost an in memory db and save it to disk
-
backup on sqlite database to another location
893 894 895 896 897 898 899 900 901 902 903 904 905 906 |
# File 'lib/amalgalite/database.rb', line 893 def replicate_to( location ) to_db = nil case location when String to_db = Amalgalite::Database.new( location ) when Amalgalite::Database to_db = location else raise ArgumentError, "replicate_to( #{location} ) must be a String or a Database" end @api.replicate_to( to_db.api ) return to_db end |
#rollback ⇒ Object
Rollback a transaction
628 629 630 |
# File 'lib/amalgalite/database.rb', line 628 def rollback execute( "ROLLBACK TRANSACTION" ) if in_transaction? end |
#rollback_to(point_name) ⇒ Object
call-seq:
db.rollback_to( point_name )
Rollback to a savepoint. The transaction is not cancelled, the transaction is restarted.
614 615 616 |
# File 'lib/amalgalite/database.rb', line 614 def rollback_to( point_name ) execute( "ROLLBACK TO SAVEPOINT #{point_name}" ) end |
#row_changes ⇒ Object
return how many rows changed in the last insert, update or delete statement.
234 235 236 |
# File 'lib/amalgalite/database.rb', line 234 def row_changes @api.row_changes end |
#savepoint(name) ⇒ Object
call-seq:
db.savepoint( 'mypoint' ) -> db
db.savepoint( 'mypoint' ) do |db_in_savepoint|
...
end
Much of the following documentation is para-phrased from sqlite.org/lang_savepoint.html
Savepoints are a method of creating transactions, similar to transaction except that they may be nested.
-
Every savepoint must have a name,
to_s
is called on the method argument -
A savepoint does not need to be initialized inside a transaction. If it is not inside a transaction it behaves exactly as if a DEFERRED transaction had been started.
-
If a block is passed to saveponit then when the block exists, it is guaranteed that either a ‘RELEASE’ or ‘ROLLBACK TO name’ has been executed.
-
If any exception happens during the savepoint transaction, then a ‘ROLLOBACK TO’ is issued when the block closes.
-
If no exception happens during the transaction then a ‘RELEASE name’ is issued upon leaving the block
If no block is passed in then you are on your own.
574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 |
# File 'lib/amalgalite/database.rb', line 574 def savepoint( name ) point_name = name.to_s.strip raise Amalgalite::Error, "Invalid savepoint name '#{name}'" unless point_name and point_name.length > 1 execute( "SAVEPOINT #{point_name};") if block_given? then begin return ( yield self ) ensure if $! then rollback_to( point_name ) raise $! else release( point_name ) end end else return in_transaction? end end |
#schema(dbname = "main") ⇒ Object
:call-seq:
db.schema( dbname = "main" ) -> Schema
Returns a Schema object containing the table and column structure of the database.
450 451 452 453 454 455 456 |
# File 'lib/amalgalite/database.rb', line 450 def schema( dbname = "main" ) @schema ||= ::Amalgalite::Schema.new( self, dbname ) if @schema and @schema.dirty? reload_schema!( dbname ) end return @schema end |
#total_changes ⇒ Object
return how many rows have changed since this connection to the database was opened.
242 243 244 |
# File 'lib/amalgalite/database.rb', line 242 def total_changes @api.total_changes end |
#transaction(mode = TransactionBehavior::DEFERRED, &block) ⇒ Object Also known as: deferred_transaction
Begin a transaction. The valid transaction types are:
- DEFERRED
-
no read or write locks are created until the first statement is executed that requries a read or a write
- IMMEDIATE
-
a readlock is obtained immediately so that no other process can write to the database
- EXCLUSIVE
-
a read+write lock is obtained, no other proces can read or write to the database
As a convenience, these are constants available in the Database::TransactionBehavior class.
Amalgalite Transactions are database level transactions, just as SQLite’s are.
If a block is passed in, then when the block exits, it is guaranteed that either ‘COMMIT’ or ‘ROLLBACK’ has been executed.
If any exception happens during the transaction that is caught by Amalgalite, then a ‘ROLLBACK’ is issued when the block closes.
If no exception happens during the transaction then a ‘COMMIT’ is issued upon leaving the block.
If no block is passed in then you are on your own.
Nesting a transaaction via the transaction method are no-ops. If you call transaction within a transaction, no new transaction is started, the current one is just continued.
True nexted transactions are available through the savepoint method.
511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 |
# File 'lib/amalgalite/database.rb', line 511 def transaction( mode = TransactionBehavior::DEFERRED, &block ) raise Amalgalite::Error, "Invalid transaction behavior mode #{mode}" unless TransactionBehavior.valid?( mode ) # if already in a transaction, no need to start a new one. if not in_transaction? then execute( "BEGIN #{mode} TRANSACTION" ) end if block_given? then begin previous_exception = $! return ( yield self ) ensure if $! and ($! != previous_exception) then rollback raise $! else commit end end else return in_transaction? end end |
#utf16? ⇒ Boolean
Is the database utf16 or not? A database is utf16 if the encoding is not UTF-8. Database can only be UTF-8 or UTF-16, and the default is UTF-8
209 210 211 212 213 214 215 |
# File 'lib/amalgalite/database.rb', line 209 def utf16? return @utf16 #if @utf16.nil? # @utf16 = (encoding != "UTF-8") #end #return @utf16 end |