Module: SQLite3::FFI
- Defined in:
- lib/sqlite3/ffi/c_api.rb,
lib/sqlite3/ffi/utils.rb,
lib/sqlite3/ffi/version.rb,
lib/sqlite3/ffi/core_ext.rb,
lib/sqlite3/ffi/exception.rb,
lib/sqlite3/ffi/functions.rb,
lib/sqlite3/ffi/aggregator.rb
Defined Under Namespace
Modules: CApi, CoreExt Classes: AggregatorInstance, AggregatorWrapper
Constant Summary collapse
- RB_ERRINFO =
:sqlite3_ffi_rb_errinfo- OBJECT_REGISTRY =
ObjectSpace::WeakMap.new
- VERSION =
"0.1.4"- COMPARATOR =
::FFI::Function.new(:int, [:pointer, :int, :pointer, :int, :pointer]) do |ctx, a_len, a, b_len, b| comparator = unwrap(ctx) a_str = a.read_bytes(a_len).force_encoding(Encoding::UTF_8) b_str = b.read_bytes(b_len).force_encoding(Encoding::UTF_8) if Encoding.default_internal a_str = a_str.encode(Encoding.default_internal) b_str = b_str.encode(Encoding.default_internal) end comparator.compare(a_str, b_str) end
- TRACE =
::FFI::Function.new(:int, [:uint, :pointer, :pointer, :pointer]) do |_, ctx, _, x| unwrap(ctx).call(x.read_string) 0 end
- AUTH =
::FFI::Function.new(:int, [:pointer, :int, :string, :string, :string, :string]) do |ctx, op_id, s1, s2, s3, s4| result = unwrap(ctx).call(op_id, s1, s2, s3, s4) if result.is_a?(Integer) result elsif result == true CApi::SQLITE_OK elsif result == false CApi::SQLITE_DENY else CApi::SQLITE_IGNORE end end
- HASH_CALLBACK =
::FFI::Function.new(:int, [:pointer, :int, :pointer, :pointer]) do |ctx, count, data, columns| callback_ary = unwrap(ctx) new_hash = {} data.read_array_of_pointer(count).zip(columns.read_array_of_pointer(count)) do |value, column| new_hash[column.read_string] = value.null? ? nil : value.read_string end callback_ary << new_hash 0 end
- REGULAR_CALLBACK =
::FFI::Function.new(:int, [:pointer, :int, :pointer, :pointer]) do |ctx, count, data, columns| callback_ary = unwrap(ctx) new_ary = [] data.read_array_of_pointer(count).each do |value| new_ary << (value.null? ? nil : value.read_string) end callback_ary << new_ary 0 end
- STATEMENT_TIMEOUT =
::FFI::Function.new(:int, [:pointer]) do |ctx| ctx = unwrap(ctx) current_time = Process.clock_gettime(Process::CLOCK_MONOTONIC) if ctx.instance_variable_get(:@stmt_deadline).nil? ctx.instance_variable_set(:@stmt_deadline, current_time) 0 elsif current_time >= ctx.instance_variable_get(:@stmt_deadline) 1 else 0 end end
- BUSY_HANDLER =
::FFI::Function.new(:int, [:pointer, :int]) do |ctx, count| handler = unwrap(ctx).instance_variable_get(:@busy_handler) result = handler.(count) result == false ? 0 : 1 end
- FUNC =
::FFI::Function.new(:void, [:pointer, :int, :pointer]) do |ctx, argc, argv| callable = unwrap(CApi.sqlite3_user_data(ctx)) params = argv.read_array_of_pointer(argc).map { |v| FFI.sqlite3val2rb(v) } result = callable.(*params) FFI.set_sqlite3_func_result(ctx, result) end
- AGGREGATOR_STEP =
::FFI::Function.new(:void, [:pointer, :int, :pointer]) do |ctx, argc, argv| begin inst = aggregate_instance(ctx) handler_instance = inst.handler_instance params = argv.read_array_of_pointer(argc).map { |v| FFI.sqlite3val2rb(v) } handler_instance.step(*params) rescue => e FFI.rb_errinfo = e end end
- AGGREGATOR_FINAL =
::FFI::Function.new(:void, [:pointer]) do |ctx| begin inst = aggregate_instance(ctx) handler_instance = inst.handler_instance result = handler_instance.finalize FFI.set_sqlite3_func_result(ctx, result) aggregate_instance_destroy(ctx) rescue => e FFI.rb_errinfo = e end end
Class Method Summary collapse
- .aggregate_instance(ctx) ⇒ Object
- .aggregate_instance_destroy(ctx) ⇒ Object
- .check(db, status) ⇒ Object
- .check_msg(db, status, msg) ⇒ Object
- .check_prepare(db, status, sql) ⇒ Object
- .interned_utf8_cstr(str) ⇒ Object
- .raise_(db, status) ⇒ Object
- .raise_msg(db, status, msg) ⇒ Object
- .raise_with_sql(db, status, sql) ⇒ Object
- .rb_errinfo ⇒ Object
- .rb_errinfo=(e) ⇒ Object
- .set_sqlite3_func_result(ctx, result) ⇒ Object
- .sqlite3val2rb(val) ⇒ Object
- .status2klass(status) ⇒ Object
- .string_value(obj) ⇒ Object
- .unwrap(ptr) ⇒ Object
- .wrap(obj) ⇒ Object
Class Method Details
.aggregate_instance(ctx) ⇒ Object
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 |
# File 'lib/sqlite3/ffi/aggregator.rb', line 16 def self.aggregate_instance(ctx) aw = FFI.unwrap(CApi.sqlite3_user_data(ctx)) handler_klass = aw.handler_klass inst_ptr = CApi.sqlite3_aggregate_context(ctx, 8) if inst_ptr.null? fatal "SQLite is out-of-merory" end if inst_ptr.read_pointer.null? instances = aw.instances inst = AggregatorInstance.new inst.handler_instance = handler_klass.new instances << inst inst_ptr.write_pointer(FFI.wrap(inst)) else inst = FFI.unwrap(inst_ptr.read_pointer) end if inst.nil? fatal "SQLite called us back on an already destroyed aggregate instance" end inst end |
.aggregate_instance_destroy(ctx) ⇒ Object
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/sqlite3/ffi/aggregator.rb', line 43 def self.aggregate_instance_destroy(ctx) aw = FFI.unwrap(CApi.sqlite3_user_data(ctx)) instances = aw.instances inst_ptr = CApi.sqlite3_aggregate_context(ctx, 0) if inst_ptr.null? || inst_ptr.read_pointer.null? return end inst = FFI.unwrap(inst_ptr.read_pointer) if inst.nil? fatal "attempt to destroy aggregate instance twice" end inst.handler_instance = nil if instances.delete(inst).nil? fatal "must be in instances at that point" end inst_ptr.write_pointer(::FFI::Pointer.new(0)) end |
.check(db, status) ⇒ Object
3 4 5 |
# File 'lib/sqlite3/ffi/exception.rb', line 3 def self.check(db, status) raise_(db, status) end |
.check_msg(db, status, msg) ⇒ Object
7 8 9 |
# File 'lib/sqlite3/ffi/exception.rb', line 7 def self.check_msg(db, status, msg) raise_msg(db, status, msg) end |
.check_prepare(db, status, sql) ⇒ Object
11 12 13 |
# File 'lib/sqlite3/ffi/exception.rb', line 11 def self.check_prepare(db, status, sql) raise_with_sql(db, status, sql) end |
.interned_utf8_cstr(str) ⇒ Object
41 42 43 |
# File 'lib/sqlite3/ffi/utils.rb', line 41 def self.interned_utf8_cstr(str) -str end |
.raise_(db, status) ⇒ Object
76 77 78 79 80 81 82 83 84 |
# File 'lib/sqlite3/ffi/exception.rb', line 76 def self.raise_(db, status) klass = status2klass(status) return if klass.nil? exception = klass.new(CApi.sqlite3_errmsg(db)) exception.instance_variable_set(:@code, status) raise exception end |
.raise_msg(db, status, msg) ⇒ Object
86 87 88 89 90 91 92 93 94 95 |
# File 'lib/sqlite3/ffi/exception.rb', line 86 def self.raise_msg(db, status, msg) klass = status2klass(status) return if klass.nil? exception = klass.new(msg.read_pointer.read_string) exception.instance_variable_set(:@code, status) CApi.sqlite3_free(msg.read_pointer) raise exception end |
.raise_with_sql(db, status, sql) ⇒ Object
97 98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/sqlite3/ffi/exception.rb', line 97 def self.raise_with_sql(db, status, sql) klass = status2klass(status) return if klass.nil? exception = klass.new(CApi.sqlite3_errmsg(db)) exception.instance_variable_set(:@code, status) if sql exception.instance_variable_set(:@sql, sql) exception.instance_variable_set(:@sql_offset, CApi.sqlite3_error_offset(db)) end raise exception end |
.rb_errinfo ⇒ Object
63 64 65 |
# File 'lib/sqlite3/ffi/utils.rb', line 63 def self.rb_errinfo Thread.current[RB_ERRINFO] end |
.rb_errinfo=(e) ⇒ Object
67 68 69 |
# File 'lib/sqlite3/ffi/utils.rb', line 67 def self.rb_errinfo=(e) Thread.current[RB_ERRINFO] = e end |
.set_sqlite3_func_result(ctx, result) ⇒ Object
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
# File 'lib/sqlite3/ffi/utils.rb', line 22 def self.set_sqlite3_func_result(ctx, result) case result when NilClass CApi.sqlite3_result_null(ctx) when Integer CApi.sqlite3_result_int64(ctx, result) when Float CApi.sqlite3_result_double(ctx, result) when String if result.is_a?(Blob) || result.encoding == Encoding::BINARY CApi.sqlite3_result_blob(ctx, result, result.bytesize, CApi::SQLITE_TRANSIENT) else CApi.sqlite3_result_text(ctx, result, result.bytesize, CApi::SQLITE_TRANSIENT) end else raise RuntimeError, "can't return #{result.class.name}" end end |
.sqlite3val2rb(val) ⇒ Object
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
# File 'lib/sqlite3/ffi/utils.rb', line 3 def self.sqlite3val2rb(val) case CApi.sqlite3_value_type(val) when CApi::SQLITE_INTEGER CApi.sqlite3_value_int64(val) when CApi::SQLITE_FLOAT CApi.sqlite3_value_double(val) when CApi::SQLITE_TEXT len = CApi.sqlite3_value_bytes(val) CApi.sqlite3_value_text(val).read_bytes(len).force_encoding(Encoding::UTF_8).freeze when CApi::SQLITE_BLOB len = CApi.sqlite3_value_bytes(val) CApi.sqlite3_value_text(val).read_bytes(len).freeze when CApi::SQLITE_NULL nil else raise RuntimeError, "bad type" end end |
.status2klass(status) ⇒ Object
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 |
# File 'lib/sqlite3/ffi/exception.rb', line 15 def self.status2klass(status) case status & 0xff when 0 nil when CApi::SQLITE_ERROR SQLite3::SQLException when CApi::SQLITE_INTERNAL SQLite3::InternalException when CApi::SQLITE_PERM SQLite3::PermissionException when CApi::SQLITE_ABORT SQLite3::AbortException when CApi::SQLITE_BUSY SQLite3::BusyException when CApi::SQLITE_LOCKED SQLite3::LockedException when CApi::SQLITE_NOMEM SQLite3::MemoryException when CApi::SQLITE_READONLY SQLite3::ReadOnlyException when CApi::SQLITE_INTERRUPT SQLite3::InterruptException when CApi::SQLITE_IOERR SQLite3::IOException when CApi::SQLITE_CORRUPT SQLite3::CorruptException when CApi::SQLITE_NOTFOUND SQLite3::NotFoundException when CApi::SQLITE_FULL SQLite3::FullException when CApi::SQLITE_CANTOPEN SQLite3::CantOpenException when CApi::SQLITE_PROTOCOL SQLite3::ProtocolException when CApi::SQLITE_EMPTY SQLite3::EmptyException when CApi::SQLITE_SCHEMA SQLite3::SchemaChangedException when CApi::SQLITE_TOOBIG SQLite3::TooBigException when CApi::SQLITE_CONSTRAINT SQLite3::ConstraintException when CApi::SQLITE_MISMATCH SQLite3::MismatchException when CApi::SQLITE_MISUSE SQLite3::MisuseException when CApi::SQLITE_NOLFS SQLite3::UnsupportedException when CApi::SQLITE_AUTH SQLite3::AuthorizationException when CApi::SQLITE_FORMAT SQLite3::FormatException when CApi::SQLITE_RANGE SQLite3::RangeException when CApi::SQLITE_NOTADB SQLite3::NotADatabaseException else SQLite3::Exception end end |
.string_value(obj) ⇒ Object
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/sqlite3/ffi/utils.rb', line 45 def self.string_value(obj) unless obj.respond_to?(:to_str) val = case obj when nil "nil" when true, false obj.to_s else obj.class.name end raise TypeError, "no implicit conversion of #{val} into String" end obj.to_str end |
.unwrap(ptr) ⇒ Object
78 79 80 |
# File 'lib/sqlite3/ffi/utils.rb', line 78 def self.unwrap(ptr) OBJECT_REGISTRY[ptr.to_i] || (raise "object not found") end |
.wrap(obj) ⇒ Object
73 74 75 76 |
# File 'lib/sqlite3/ffi/utils.rb', line 73 def self.wrap(obj) OBJECT_REGISTRY[obj.object_id] = obj ::FFI::Pointer.new(obj.object_id) end |