class Sequel::SQLite::Database
Attributes
The conversion procs to use for this database
Public Class Methods
Sequel::Database::new
# File lib/sequel/adapters/sqlite.rb 101 def initialize(opts = OPTS) 102 super 103 @allow_regexp = typecast_value_boolean(opts[:setup_regexp_function]) 104 end
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)
- :setup_regexp_function
-
enable use of Regexp objects with
SQL
'REGEXP' operator. If the value is :cached or "cached", caches the generated regexps, which can result in a memory leak if dynamic regexps are used. If the value is a Proc, it will be called with a string for the regexp and a string for the value to compare, and should return whether the regexp matches.
- :regexp_function_cache
-
If setting
setup_regexp_function
tocached
, this
determines the cache to use. It should either be a proc or a class, and it defaults to +Hash+. You can use +ObjectSpace::WeakKeyMap+ on Ruby 3.3+ to have the VM automatically remove regexps from the cache after they are no longer used.
# File lib/sequel/adapters/sqlite.rb 126 def connect(server) 127 opts = server_opts(server) 128 opts[:database] = ':memory:' if blank_object?(opts[:database]) 129 sqlite3_opts = {} 130 sqlite3_opts[:readonly] = typecast_value_boolean(opts[:readonly]) if opts.has_key?(:readonly) 131 db = ::SQLite3::Database.new(opts[:database].to_s, sqlite3_opts) 132 db.busy_timeout(typecast_value_integer(opts.fetch(:timeout, 5000))) 133 134 if USE_EXTENDED_RESULT_CODES 135 db.extended_result_codes = true 136 end 137 138 connection_pragmas.each{|s| log_connection_yield(s, db){db.execute_batch(s)}} 139 140 if typecast_value_boolean(opts[:setup_regexp_function]) 141 setup_regexp_function(db, opts[:setup_regexp_function]) 142 end 143 144 class << db 145 attr_reader :prepared_statements 146 end 147 db.instance_variable_set(:@prepared_statements, {}) 148 149 db 150 end
Disconnect given connections from the database.
# File lib/sequel/adapters/sqlite.rb 159 def disconnect_connection(c) 160 c.prepared_statements.each_value{|v| v.first.close} 161 c.close 162 end
Run the given SQL
with the given arguments and yield each row.
# File lib/sequel/adapters/sqlite.rb 165 def execute(sql, opts=OPTS, &block) 166 _execute(:select, sql, opts, &block) 167 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.
Sequel::Database#execute_ddl
# File lib/sequel/adapters/sqlite.rb 177 def execute_ddl(sql, opts=OPTS) 178 synchronize(opts[:server]) do |conn| 179 conn.prepared_statements.values.each{|cps, s| cps.close} 180 conn.prepared_statements.clear 181 super 182 end 183 end
Run the given SQL
with the given arguments and return the number of changed rows.
# File lib/sequel/adapters/sqlite.rb 170 def execute_dui(sql, opts=OPTS) 171 _execute(:update, sql, opts) 172 end
# File lib/sequel/adapters/sqlite.rb 185 def execute_insert(sql, opts=OPTS) 186 _execute(:insert, sql, opts) 187 end
Sequel::SQLite::DatabaseMethods#freeze
# File lib/sequel/adapters/sqlite.rb 189 def freeze 190 @conversion_procs.freeze 191 super 192 end
Handle Integer and Float arguments, since SQLite
can store timestamps as integers and floats.
Sequel::Database#to_application_timestamp
# File lib/sequel/adapters/sqlite.rb 195 def to_application_timestamp(s) 196 case s 197 when String 198 super 199 when Integer 200 super(Time.at(s).to_s) 201 when Float 202 super(DateTime.jd(s).to_s) 203 else 204 raise Sequel::Error, "unhandled type when converting to : #{s.inspect} (#{s.class.inspect})" 205 end 206 end
Private Instance Methods
Yield an available connection. Rescue any SQLite3::Exceptions and turn them into DatabaseErrors.
# File lib/sequel/adapters/sqlite.rb 247 def _execute(type, sql, opts, &block) 248 synchronize(opts[:server]) do |conn| 249 return execute_prepared_statement(conn, type, sql, opts, &block) if sql.is_a?(Symbol) 250 log_args = opts[:arguments] 251 args = {} 252 opts.fetch(:arguments, OPTS).each{|k, v| args[k] = prepared_statement_argument(v)} 253 case type 254 when :select 255 log_connection_yield(sql, conn, log_args){conn.query(sql, args, &block)} 256 when :insert 257 log_connection_yield(sql, conn, log_args){conn.execute(sql, args)} 258 conn.last_insert_row_id 259 when :update 260 log_connection_yield(sql, conn, log_args){conn.execute_batch(sql, args)} 261 conn.changes 262 end 263 end 264 rescue SQLite3::Exception => e 265 raise_error(e) 266 end
# File lib/sequel/adapters/sqlite.rb 210 def adapter_initialize 211 @conversion_procs = SQLITE_TYPES.dup 212 @conversion_procs['datetime'] = @conversion_procs['timestamp'] = method(:to_application_timestamp) 213 set_integer_booleans 214 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.
Sequel::Database#connection_pool_default_options
# File lib/sequel/adapters/sqlite.rb 271 def connection_pool_default_options 272 o = super.dup 273 # Default to only a single connection if a memory database is used, 274 # because otherwise each connection will get a separate database 275 o[:max_connections] = 1 if @opts[:database] == ':memory:' || blank_object?(@opts[:database]) 276 o 277 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 336 def database_error_classes 337 [SQLite3::Exception, ArgumentError] 338 end
# File lib/sequel/adapters/sqlite.rb 340 def dataset_class_default 341 Dataset 342 end
Execute a prepared statement on the database using the given name.
# File lib/sequel/adapters/sqlite.rb 297 def execute_prepared_statement(conn, type, name, opts, &block) 298 ps = prepared_statement(name) 299 sql = ps.prepared_sql 300 args = opts[:arguments] 301 ps_args = {} 302 args.each{|k, v| ps_args[k] = prepared_statement_argument(v)} 303 if cpsa = conn.prepared_statements[name] 304 cps, cps_sql = cpsa 305 if cps_sql != sql 306 cps.close 307 cps = nil 308 end 309 end 310 unless cps 311 cps = log_connection_yield("PREPARE #{name}: #{sql}", conn){conn.prepare(sql)} 312 conn.prepared_statements[name] = [cps, sql] 313 end 314 log_sql = String.new 315 log_sql << "EXECUTE #{name}" 316 if ps.log_sql 317 log_sql << " (" 318 log_sql << sql 319 log_sql << ")" 320 end 321 if block 322 log_connection_yield(log_sql, conn, args){cps.execute(ps_args, &block)} 323 else 324 log_connection_yield(log_sql, conn, args){cps.execute!(ps_args){|r|}} 325 case type 326 when :insert 327 conn.last_insert_row_id 328 when :update 329 conn.changes 330 end 331 end 332 end
# File lib/sequel/adapters/sqlite.rb 279 def prepared_statement_argument(arg) 280 case arg 281 when Date, DateTime, Time 282 literal(arg)[1...-1] 283 when SQL::Blob 284 arg.to_blob 285 when true, false 286 if integer_booleans 287 arg ? 1 : 0 288 else 289 literal(arg)[1...-1] 290 end 291 else 292 arg 293 end 294 end
# File lib/sequel/adapters/sqlite.rb 216 def setup_regexp_function(db, how) 217 case how 218 when Proc 219 # nothing 220 when :cached, "cached" 221 cache = @opts[:regexp_function_cache] || Hash 222 cache = cache.is_a?(Proc) ? cache.call : cache.new 223 how = if RUBY_VERSION >= '2.4' 224 lambda do |regexp_str, str| 225 (cache[regexp_str] ||= Regexp.new(regexp_str)).match?(str) 226 end 227 else 228 lambda do |regexp_str, str| 229 (cache[regexp_str] ||= Regexp.new(regexp_str)).match(str) 230 end 231 end 232 else 233 how = if RUBY_VERSION >= '2.4' 234 lambda{|regexp_str, str| Regexp.new(regexp_str).match?(str)} 235 else 236 lambda{|regexp_str, str| Regexp.new(regexp_str).match(str)} 237 end 238 end 239 240 db.create_function("regexp", 2) do |func, regexp_str, str| 241 func.result = how.call(regexp_str, str) ? 1 : 0 242 end 243 end
Support SQLite
exception codes if ruby-sqlite3 supports them.
# File lib/sequel/adapters/sqlite.rb 346 def sqlite_error_code(exception) 347 exception.code if exception.respond_to?(:code) 348 end