/usr/lib/ruby/vendor_ruby/sequel/adapters/amalgalite.rb is in ruby-sequel 4.1.1-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 | require 'amalgalite'
Sequel.require 'adapters/shared/sqlite'
module Sequel
# Top level module for holding all Amalgalite-related modules and classes
# for Sequel.
module Amalgalite
# Type conversion map class for Sequel's use of Amalgamite
class SequelTypeMap < ::Amalgalite::TypeMaps::DefaultMap
methods_handling_sql_types.delete('string')
methods_handling_sql_types.merge!(
'datetime' => %w'datetime timestamp',
'time' => %w'time',
'float' => ['float', 'double', 'real', 'double precision'],
'decimal' => %w'numeric decimal money'
)
# Store the related database object, in order to be able to correctly
# handle the database timezone.
def initialize(db)
@db = db
end
# Return blobs as instances of Sequel::SQL::Blob instead of
# Amalgamite::Blob
def blob(s)
SQL::Blob.new(s)
end
# Return numeric/decimal types as instances of BigDecimal
# instead of Float
def decimal(s)
BigDecimal.new(s)
end
# Return datetime types as instances of Sequel.datetime_class
def datetime(s)
@db.to_application_timestamp(s)
end
def time(s)
Sequel.string_to_time(s)
end
# Don't raise an error if the value is a string and the declared
# type doesn't match a known type, just return the value.
def result_value_of(declared_type, value)
if value.is_a?(::Amalgalite::Blob)
SQL::Blob.new(value.to_s)
elsif value.is_a?(String) && declared_type
(meth = self.class.sql_to_method(declared_type.downcase)) ? send(meth, value) : value
else
super
end
end
end
# Database class for SQLite databases used with Sequel and the
# amalgalite driver.
class Database < Sequel::Database
include ::Sequel::SQLite::DatabaseMethods
set_adapter_scheme :amalgalite
# Mimic the file:// uri, by having 2 preceding slashes specify a relative
# path, and 3 preceding slashes specify an absolute path.
def self.uri_to_options(uri) # :nodoc:
{ :database => (uri.host.nil? && uri.path == '/') ? nil : "#{uri.host}#{uri.path}" }
end
private_class_method :uri_to_options
# Connect to the database. Since SQLite is a file based database,
# the only options available are :database (to specify the database
# name), and :timeout, to specify how long to wait for the database to
# be available if it is locked, given in milliseconds (default is 5000).
def connect(server)
opts = server_opts(server)
opts[:database] = ':memory:' if blank_object?(opts[:database])
db = ::Amalgalite::Database.new(opts[:database])
db.busy_handler(::Amalgalite::BusyTimeout.new(opts.fetch(:timeout, 5000)/50, 50))
db.type_map = SequelTypeMap.new(self)
connection_pragmas.each{|s| log_yield(s){db.execute_batch(s)}}
db
end
# Amalgalite is just the SQLite database without a separate SQLite installation.
def database_type
:sqlite
end
# Run the given SQL with the given arguments. Returns nil.
def execute_ddl(sql, opts=OPTS)
_execute(sql, opts){|conn| log_yield(sql){conn.execute_batch(sql)}}
nil
end
# Run the given SQL with the given arguments and return the number of changed rows.
def execute_dui(sql, opts=OPTS)
_execute(sql, opts){|conn| log_yield(sql){conn.execute_batch(sql)}; conn.row_changes}
end
# Run the given SQL with the given arguments and return the last inserted row id.
def execute_insert(sql, opts=OPTS)
_execute(sql, opts){|conn| log_yield(sql){conn.execute_batch(sql)}; conn.last_insert_rowid}
end
# Run the given SQL with the given arguments and yield each row.
def execute(sql, opts=OPTS)
_execute(sql, opts) do |conn|
begin
yield(stmt = log_yield(sql){conn.prepare(sql)})
ensure
stmt.close if stmt
end
end
end
# Run the given SQL with the given arguments and return the first value of the first row.
def single_value(sql, opts=OPTS)
_execute(sql, opts){|conn| log_yield(sql){conn.first_value_from(sql)}}
end
private
# Yield an available connection. Rescue
# any Amalgalite::Errors and turn them into DatabaseErrors.
def _execute(sql, opts)
begin
synchronize(opts[:server]){|conn| yield conn}
rescue ::Amalgalite::Error, ::Amalgalite::SQLite3::Error => e
raise_error(e)
end
end
# The Amagalite 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.
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
# Both main error classes that Amalgalite raises
def database_error_classes
[::Amalgalite::Error, ::Amalgalite::SQLite3::Error]
end
end
# Dataset class for SQLite datasets that use the amalgalite driver.
class Dataset < Sequel::Dataset
include ::Sequel::SQLite::DatasetMethods
Database::DatasetClass = self
# Yield a hash for each row in the dataset.
def fetch_rows(sql)
execute(sql) do |stmt|
@columns = cols = stmt.result_fields.map{|c| output_identifier(c)}
col_count = cols.size
stmt.each do |result|
row = {}
col_count.times{|i| row[cols[i]] = result[i]}
yield row
end
end
end
private
# Quote the string using the adapter instance method.
def literal_string_append(sql, v)
db.synchronize(@opts[:server]){|c| sql << c.quote(v)}
end
end
end
end
|