class Sequel::SQLite::Database
Database class for SQLite databases used with Sequel and the ruby-sqlite3 driver.
Constants
- DatasetClass
Attributes
The conversion procs to use for this database
Public Instance Methods
Connect to the database. Since SQLite is a file based database, available options are limited:
- :database
-
database name (filename or ':memory:' or file: URI)
- :readonly
-
open database in read-only mode; useful for reading static data that you do not want to modify
- :timeout
-
how long to wait for the database to be available if it is locked, given in milliseconds (default is 5000)
# File lib/sequel/adapters/sqlite.rb, line 102 def connect(server) opts = server_opts(server) opts[:database] = ':memory:' if blank_object?(opts[:database]) sqlite3_opts = {} sqlite3_opts[:readonly] = typecast_value_boolean(opts[:readonly]) if opts.has_key?(:readonly) db = ::SQLite3::Database.new(opts[:database].to_s, sqlite3_opts) db.busy_timeout(opts.fetch(:timeout, 5000)) connection_pragmas.each{|s| log_yield(s){db.execute_batch(s)}} class << db attr_reader :prepared_statements end db.instance_variable_set(:@prepared_statements, {}) db end
Disconnect given connections from the database.
# File lib/sequel/adapters/sqlite.rb, line 121 def disconnect_connection(c) c.prepared_statements.each_value{|v| v.first.close} c.close end
Run the given SQL with the given arguments and yield each row.
# File lib/sequel/adapters/sqlite.rb, line 127 def execute(sql, opts=OPTS, &block) _execute(:select, sql, opts, &block) end
Drop any prepared statements on the connection when executing DDL. This is because prepared statements lock the table in such a way that you can't drop or alter the table while a prepared statement that references it still exists.
# File lib/sequel/adapters/sqlite.rb, line 139 def execute_ddl(sql, opts=OPTS) synchronize(opts[:server]) do |conn| conn.prepared_statements.values.each{|cps, s| cps.close} conn.prepared_statements.clear super end end
Run the given SQL with the given arguments and return the number of changed rows.
# File lib/sequel/adapters/sqlite.rb, line 132 def execute_dui(sql, opts=OPTS) _execute(:update, sql, opts) end
Run the given SQL with the given arguments and return the last inserted row id.
# File lib/sequel/adapters/sqlite.rb, line 148 def execute_insert(sql, opts=OPTS) _execute(:insert, sql, opts) end
Handle Integer and Float arguments, since SQLite can store timestamps as integers and floats.
# File lib/sequel/adapters/sqlite.rb, line 153 def to_application_timestamp(s) case s when String super when Integer super(Time.at(s).to_s) when Float super(DateTime.jd(s).to_s) else raise Sequel::Error, "unhandled type when converting to : #{s.inspect} (#{s.class.inspect})" end end
Private Instance Methods
Yield an available connection. Rescue any SQLite3::Exceptions and turn them into DatabaseErrors.
# File lib/sequel/adapters/sqlite.rb, line 176 def _execute(type, sql, opts, &block) begin synchronize(opts[:server]) do |conn| return execute_prepared_statement(conn, type, sql, opts, &block) if sql.is_a?(Symbol) log_args = opts[:arguments] args = {} opts.fetch(:arguments, {}).each{|k, v| args[k] = prepared_statement_argument(v)} case type when :select log_yield(sql, log_args){conn.query(sql, args, &block)} when :insert log_yield(sql, log_args){conn.execute(sql, args)} conn.last_insert_row_id when :update log_yield(sql, log_args){conn.execute_batch(sql, args)} conn.changes end end rescue SQLite3::Exception => e raise_error(e) end end
# File lib/sequel/adapters/sqlite.rb, line 168 def adapter_initialize @conversion_procs = SQLITE_TYPES.dup @conversion_procs['datetime'] = @conversion_procs['timestamp'] = method(:to_application_timestamp) set_integer_booleans end
The SQLite adapter does not need the pool to convert exceptions. Also, force the max connections to 1 if a memory database is being used, as otherwise each connection gets a separate database.
# File lib/sequel/adapters/sqlite.rb, line 202 def connection_pool_default_options o = super.dup # Default to only a single connection if a memory database is used, # because otherwise each connection will get a separate database o[:max_connections] = 1 if @opts[:database] == ':memory:' || blank_object?(@opts[:database]) o end
SQLite3 raises ArgumentError in addition to SQLite3::Exception in some cases, such as operations on a closed database.
# File lib/sequel/adapters/sqlite.rb, line 266 def database_error_classes [SQLite3::Exception, ArgumentError] end
Execute a prepared statement on the database using the given name.
# File lib/sequel/adapters/sqlite.rb, line 228 def execute_prepared_statement(conn, type, name, opts, &block) ps = prepared_statement(name) sql = ps.prepared_sql args = opts[:arguments] ps_args = {} args.each{|k, v| ps_args[k] = prepared_statement_argument(v)} if cpsa = conn.prepared_statements[name] cps, cps_sql = cpsa if cps_sql != sql cps.close cps = nil end end unless cps cps = log_yield("PREPARE #{name}: #{sql}"){conn.prepare(sql)} conn.prepared_statements[name] = [cps, sql] end log_sql = "EXECUTE #{name}" if ps.log_sql log_sql << " (" log_sql << sql log_sql << ")" end if block log_yield(log_sql, args){cps.execute(ps_args, &block)} else log_yield(log_sql, args){cps.execute!(ps_args){|r|}} case type when :insert conn.last_insert_row_id when :update conn.changes end end end
# File lib/sequel/adapters/sqlite.rb, line 210 def prepared_statement_argument(arg) case arg when Date, DateTime, Time literal(arg)[1...-1] when SQL::Blob arg.to_blob when true, false if integer_booleans arg ? 1 : 0 else literal(arg)[1...-1] end else arg end end