sqlite3-ffi 0.1.8 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/lib/sqlite3/ffi/c_api.rb +19 -0
- data/lib/sqlite3/ffi/database.rb +48 -0
- data/lib/sqlite3/ffi/functions.rb +1 -1
- data/lib/sqlite3/ffi/sqlite3.rb +1 -1
- data/lib/sqlite3/ffi/statement.rb +15 -2
- data/lib/sqlite3/ffi/utils.rb +5 -1
- data/lib/sqlite3/ffi/version.rb +1 -1
- data/lib/sqlite3/resultset.rb +10 -4
- data/lib/sqlite3/statement.rb +29 -10
- data/lib/sqlite3/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 402ba8b0d0f49fd0f6229dba55575c8c5c22e460a2c2883095782f7f0f370ae6
|
|
4
|
+
data.tar.gz: 22c9aad92904a410a4a697aa8dddcb84519e4669cb8976c57ba6d1f2c04c37d4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9ef8d936ee00247132f2d0c632491bffc4802915b539267ffc8131c13dfcee6cb85eb568d68d439894eed3a511813cb9e7f19baf82cbeff9fd7d896bdc4b8845
|
|
7
|
+
data.tar.gz: 0a454150d3d90edbf20cd59f3eb69c75d0825bb406efb290aded8b4376e32ea14e45e6317252134c691fddbb1e065a00f9ae8981d852861131ad1a4c80e0bf16
|
data/CHANGELOG.md
CHANGED
data/lib/sqlite3/ffi/c_api.rb
CHANGED
|
@@ -90,6 +90,9 @@ module SQLite3
|
|
|
90
90
|
SQLITE_DBCONFIG_ENABLE_COMMENTS = 1022
|
|
91
91
|
SQLITE_DBCONFIG_MAX = 1022
|
|
92
92
|
|
|
93
|
+
SQLITE_DESERIALIZE_FREEONCLOSE = 1
|
|
94
|
+
SQLITE_DESERIALIZE_RESIZEABLE = 2
|
|
95
|
+
|
|
93
96
|
SQLITE_OPEN_READONLY = 0x00000001
|
|
94
97
|
SQLITE_OPEN_READWRITE = 0x00000002
|
|
95
98
|
SQLITE_OPEN_CREATE = 0x00000004
|
|
@@ -182,6 +185,7 @@ module SQLite3
|
|
|
182
185
|
attach_function :sqlite3_last_insert_rowid, [:pointer], :int64
|
|
183
186
|
attach_function :sqlite3_libversion, [], :string
|
|
184
187
|
attach_function :sqlite3_libversion_number, [], :int
|
|
188
|
+
attach_function :sqlite3_malloc64, [:int64], :pointer
|
|
185
189
|
attach_function :sqlite3_mprintf, [:string, :varargs], :pointer
|
|
186
190
|
attach_function :sqlite3_open16, [:pointer, :pointer], :int
|
|
187
191
|
attach_function :sqlite3_open_v2, [:string, :pointer, :int, :string], :int
|
|
@@ -197,6 +201,7 @@ module SQLite3
|
|
|
197
201
|
attach_function :sqlite3_sql, [:pointer], :string
|
|
198
202
|
attach_function :sqlite3_status64, [:int, :pointer, :pointer, :int], :int
|
|
199
203
|
attach_function :sqlite3_step, [:pointer], :int
|
|
204
|
+
attach_function :sqlite3_stmt_busy, [:pointer], :int
|
|
200
205
|
attach_function :sqlite3_stmt_status, [:pointer, :int, :int], :int
|
|
201
206
|
attach_function :sqlite3_threadsafe, [], :int
|
|
202
207
|
attach_function :sqlite3_total_changes, [:pointer], :int
|
|
@@ -216,6 +221,13 @@ module SQLite3
|
|
|
216
221
|
false
|
|
217
222
|
end
|
|
218
223
|
|
|
224
|
+
HAVE_SQLITE3_DESERIALIZE = begin
|
|
225
|
+
attach_function :sqlite3_deserialize, [:pointer, :string, :pointer, :int64, :int64, :uint], :int
|
|
226
|
+
true
|
|
227
|
+
rescue ::FFI::NotFoundError
|
|
228
|
+
false
|
|
229
|
+
end
|
|
230
|
+
|
|
219
231
|
HAVE_SQLITE3_ENABLE_LOAD_EXTENSION = begin
|
|
220
232
|
attach_function :sqlite3_enable_load_extension, [:pointer, :int], :int
|
|
221
233
|
true
|
|
@@ -229,6 +241,13 @@ module SQLite3
|
|
|
229
241
|
rescue ::FFI::NotFoundError
|
|
230
242
|
false
|
|
231
243
|
end
|
|
244
|
+
|
|
245
|
+
HAVE_SQLITE3_SERIALIZE = begin
|
|
246
|
+
attach_function :sqlite3_serialize, [:pointer, :string, :pointer, :uint], :pointer
|
|
247
|
+
true
|
|
248
|
+
rescue ::FFI::NotFoundError
|
|
249
|
+
false
|
|
250
|
+
end
|
|
232
251
|
end
|
|
233
252
|
end
|
|
234
253
|
end
|
data/lib/sqlite3/ffi/database.rb
CHANGED
|
@@ -144,6 +144,8 @@ module SQLite3
|
|
|
144
144
|
def exec_batch(sql, results_as_hash)
|
|
145
145
|
require_open_db
|
|
146
146
|
|
|
147
|
+
@stmt_deadline = nil
|
|
148
|
+
|
|
147
149
|
callback_ary = []
|
|
148
150
|
err_msg = ::FFI::MemoryPointer.new(:pointer)
|
|
149
151
|
callback = results_as_hash == true ? FFI::HASH_CALLBACK : FFI::REGULAR_CALLBACK
|
|
@@ -159,6 +161,52 @@ module SQLite3
|
|
|
159
161
|
fname.null? ? nil : fname.read_string.force_encoding(Encoding::UTF_8)
|
|
160
162
|
end
|
|
161
163
|
|
|
164
|
+
if FFI::CApi::HAVE_SQLITE3_SERIALIZE
|
|
165
|
+
def serialize(db_name = nil)
|
|
166
|
+
require_open_db
|
|
167
|
+
|
|
168
|
+
z_schema = db_name.nil? ? nil : FFI.string_value_cstr(db_name)
|
|
169
|
+
|
|
170
|
+
size = ::FFI::MemoryPointer.new(:int64)
|
|
171
|
+
data = FFI::CApi.sqlite3_serialize(@db, z_schema, size, 0)
|
|
172
|
+
size = size.read_int64
|
|
173
|
+
|
|
174
|
+
if data.null? && size < 0
|
|
175
|
+
raise SQLite3::Exception, "unable to serialize database \"%s\"" % [z_schema || "main"]
|
|
176
|
+
end
|
|
177
|
+
if data.null? && size > 0
|
|
178
|
+
raise NoMemoryError, "failed to allocate %d bytes for serialization" % [size]
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
result = data.read_bytes(size)
|
|
182
|
+
FFI::CApi.sqlite3_free(data)
|
|
183
|
+
result
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
if FFI::CApi::HAVE_SQLITE3_DESERIALIZE && FFI::CApi.sqlite3_libversion_number >= 3054000
|
|
188
|
+
def deserialize(data, db_name = nil)
|
|
189
|
+
require_open_db
|
|
190
|
+
|
|
191
|
+
data = FFI.string_value(data)
|
|
192
|
+
z_schema = db_name.nil? ? nil : FFI.string_value_cstr(db_name)
|
|
193
|
+
sz_db = data.bytesize
|
|
194
|
+
|
|
195
|
+
sz_buf = sz_db + 20
|
|
196
|
+
p_data = FFI::CApi.sqlite3_malloc64(sz_buf)
|
|
197
|
+
if p_data.null?
|
|
198
|
+
raise NoMemoryError, "failed to allocate %d bytes for deserialization" % [sz_buf]
|
|
199
|
+
end
|
|
200
|
+
p_data.put_bytes(0, data)
|
|
201
|
+
p_data.put_bytes(sz_db, "\x00"*(sz_buf - sz_db))
|
|
202
|
+
|
|
203
|
+
status = FFI::CApi.sqlite3_deserialize(@db, z_schema, p_data, sz_db, sz_db, FFI::CApi::SQLITE_DESERIALIZE_FREEONCLOSE | FFI::CApi::SQLITE_DESERIALIZE_RESIZEABLE)
|
|
204
|
+
|
|
205
|
+
FFI.check(@db, status)
|
|
206
|
+
self
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
|
|
162
210
|
private
|
|
163
211
|
|
|
164
212
|
def require_open_db
|
|
@@ -55,7 +55,7 @@ module SQLite3
|
|
|
55
55
|
ctx = unwrap(ctx)
|
|
56
56
|
current_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
57
57
|
if ctx.instance_variable_get(:@stmt_deadline).nil?
|
|
58
|
-
ctx.instance_variable_set(:@stmt_deadline, current_time)
|
|
58
|
+
ctx.instance_variable_set(:@stmt_deadline, current_time + ctx.instance_variable_get(:@stmt_timeout).to_i / 1000.0)
|
|
59
59
|
0
|
|
60
60
|
elsif current_time >= ctx.instance_variable_get(:@stmt_deadline)
|
|
61
61
|
1
|
data/lib/sqlite3/ffi/sqlite3.rb
CHANGED
|
@@ -4,6 +4,7 @@ module SQLite3
|
|
|
4
4
|
sql = FFI.string_value(sql)
|
|
5
5
|
|
|
6
6
|
@db = db # so can check if discarded
|
|
7
|
+
@db.instance_variable_set(:@stmt_deadline, nil)
|
|
7
8
|
db = db.instance_variable_get(:@db)
|
|
8
9
|
stmt = ::FFI::MemoryPointer.new(:pointer)
|
|
9
10
|
tail = ::FFI::MemoryPointer.new(:pointer)
|
|
@@ -11,7 +12,6 @@ module SQLite3
|
|
|
11
12
|
FFI.check_prepare(db, status, sql)
|
|
12
13
|
|
|
13
14
|
@stmt = ::FFI::AutoPointer.new(stmt.read_pointer, FFI::CApi.method(:sqlite3_finalize))
|
|
14
|
-
@db.instance_variable_set(:@stmt_deadline, nil)
|
|
15
15
|
|
|
16
16
|
tail.read_pointer.read_string.force_encoding(Encoding::UTF_8)
|
|
17
17
|
end
|
|
@@ -35,6 +35,10 @@ module SQLite3
|
|
|
35
35
|
|
|
36
36
|
stmt = @stmt
|
|
37
37
|
|
|
38
|
+
if FFI::CApi.sqlite3_stmt_busy(stmt) == 0
|
|
39
|
+
@db.instance_variable_set(:@stmt_deadline, nil)
|
|
40
|
+
end
|
|
41
|
+
|
|
38
42
|
value = FFI::CApi.sqlite3_step(stmt)
|
|
39
43
|
if FFI.rb_errinfo
|
|
40
44
|
exception = FFI.rb_errinfo
|
|
@@ -168,7 +172,16 @@ module SQLite3
|
|
|
168
172
|
require_live_db
|
|
169
173
|
require_open_stmt
|
|
170
174
|
|
|
171
|
-
FFI::CApi.sqlite3_column_decltype(@stmt, index)
|
|
175
|
+
name = FFI::CApi.sqlite3_column_decltype(@stmt, index)
|
|
176
|
+
name ? name.force_encoding(Encoding::UTF_8) : nil
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def column_decltype_downcased(index)
|
|
180
|
+
require_live_db
|
|
181
|
+
require_open_stmt
|
|
182
|
+
|
|
183
|
+
name = FFI::CApi.sqlite3_column_decltype(@stmt, index)
|
|
184
|
+
name ? FFI.interned_downcased_utf8_cstr(name) : nil
|
|
172
185
|
end
|
|
173
186
|
|
|
174
187
|
def bind_parameter_count
|
data/lib/sqlite3/ffi/utils.rb
CHANGED
|
@@ -39,7 +39,11 @@ module SQLite3
|
|
|
39
39
|
end
|
|
40
40
|
|
|
41
41
|
def self.interned_utf8_cstr(str)
|
|
42
|
-
-str
|
|
42
|
+
-str.force_encoding(Encoding::UTF_8)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def self.interned_downcased_utf8_cstr(str)
|
|
46
|
+
-str.force_encoding(Encoding::UTF_8).downcase(:ascii)
|
|
43
47
|
end
|
|
44
48
|
|
|
45
49
|
def self.string_value(obj)
|
data/lib/sqlite3/ffi/version.rb
CHANGED
data/lib/sqlite3/resultset.rb
CHANGED
|
@@ -43,20 +43,26 @@ module SQLite3
|
|
|
43
43
|
@stmt.step
|
|
44
44
|
end
|
|
45
45
|
|
|
46
|
-
#
|
|
47
|
-
#
|
|
46
|
+
# With a block given, iterates over the rows of the result set, passing each
|
|
47
|
+
# to the block. Returns self.
|
|
48
|
+
# With no block given, returns a new Enumerator.
|
|
48
49
|
def each
|
|
50
|
+
return enum_for(__method__) unless block_given?
|
|
49
51
|
while (node = self.next)
|
|
50
52
|
yield node
|
|
51
53
|
end
|
|
54
|
+
self
|
|
52
55
|
end
|
|
53
56
|
|
|
54
|
-
#
|
|
55
|
-
#
|
|
57
|
+
# With a block given, iterates over the rows of the result set, passing each
|
|
58
|
+
# to the block as a hash. Returns self.
|
|
59
|
+
# With no block given, returns a new Enumerator.
|
|
56
60
|
def each_hash
|
|
61
|
+
return enum_for(__method__) unless block_given?
|
|
57
62
|
while (node = next_hash)
|
|
58
63
|
yield node
|
|
59
64
|
end
|
|
65
|
+
self
|
|
60
66
|
end
|
|
61
67
|
|
|
62
68
|
# Closes the statement that spawned this result set.
|
data/lib/sqlite3/statement.rb
CHANGED
|
@@ -42,6 +42,24 @@ module SQLite3
|
|
|
42
42
|
# See Database#execute for a description of the valid placeholder
|
|
43
43
|
# syntaxes.
|
|
44
44
|
#
|
|
45
|
+
# Type mapping from Ruby to SQLite3:
|
|
46
|
+
# - +nil+ → NULL
|
|
47
|
+
# - Integer → INTEGER (or REAL when outside the signed int64 range)
|
|
48
|
+
# - Float → REAL
|
|
49
|
+
# - SQLite3::Blob → BLOB
|
|
50
|
+
# - String with Encoding::ASCII_8BIT
|
|
51
|
+
# (a.k.a. BINARY) → BLOB
|
|
52
|
+
# - String with Encoding::UTF_16LE
|
|
53
|
+
# or Encoding::UTF_16BE → TEXT (bound as UTF-16)
|
|
54
|
+
# - String (all other encodings) → TEXT (re-encoded to UTF-8 if needed)
|
|
55
|
+
# - Any other type → raises RuntimeError
|
|
56
|
+
#
|
|
57
|
+
# Note: a String with Encoding::ASCII_8BIT (BINARY) is always bound as a
|
|
58
|
+
# BLOB, even when its bytes are all valid ASCII. If you want such a string
|
|
59
|
+
# compared or stored as TEXT, re-encode it before binding:
|
|
60
|
+
#
|
|
61
|
+
# stmt.bind_params(my_binary_str.encode(Encoding::UTF_8))
|
|
62
|
+
#
|
|
45
63
|
# Example:
|
|
46
64
|
#
|
|
47
65
|
# stmt = db.prepare( "select * from table where a=? and b=?" )
|
|
@@ -112,9 +130,9 @@ module SQLite3
|
|
|
112
130
|
!done?
|
|
113
131
|
end
|
|
114
132
|
|
|
115
|
-
# Return
|
|
116
|
-
# may execute the statement in order to
|
|
117
|
-
# a (potentially) expensive operation.
|
|
133
|
+
# Return a frozen array of the column names for this statement, as frozen
|
|
134
|
+
# UTF-8 strings. Note that this may execute the statement in order to
|
|
135
|
+
# obtain the metadata; this makes it a (potentially) expensive operation.
|
|
118
136
|
def columns
|
|
119
137
|
get_metadata unless @columns
|
|
120
138
|
@columns
|
|
@@ -128,9 +146,11 @@ module SQLite3
|
|
|
128
146
|
end
|
|
129
147
|
end
|
|
130
148
|
|
|
131
|
-
# Return
|
|
132
|
-
#
|
|
133
|
-
#
|
|
149
|
+
# Return a frozen array of the declared types of the columns in this
|
|
150
|
+
# statement, as frozen UTF-8 strings with ASCII letters downcased. A column
|
|
151
|
+
# with no declared type, such as an expression, has a +nil+ type. Note that
|
|
152
|
+
# this may execute the statement in order to obtain the metadata; this makes
|
|
153
|
+
# it a (potentially) expensive operation.
|
|
134
154
|
def types
|
|
135
155
|
must_be_open!
|
|
136
156
|
get_metadata unless @types
|
|
@@ -180,11 +200,10 @@ module SQLite3
|
|
|
180
200
|
def get_metadata
|
|
181
201
|
@columns = Array.new(column_count) do |column|
|
|
182
202
|
column_name column
|
|
183
|
-
end
|
|
203
|
+
end.freeze
|
|
184
204
|
@types = Array.new(column_count) do |column|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
end
|
|
205
|
+
column_decltype_downcased(column)
|
|
206
|
+
end.freeze
|
|
188
207
|
end
|
|
189
208
|
end
|
|
190
209
|
end
|
data/lib/sqlite3/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: sqlite3-ffi
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jamis Buck
|
|
@@ -70,14 +70,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
70
70
|
requirements:
|
|
71
71
|
- - ">="
|
|
72
72
|
- !ruby/object:Gem::Version
|
|
73
|
-
version: '3.
|
|
73
|
+
version: '3.2'
|
|
74
74
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
75
75
|
requirements:
|
|
76
76
|
- - ">="
|
|
77
77
|
- !ruby/object:Gem::Version
|
|
78
78
|
version: '0'
|
|
79
79
|
requirements: []
|
|
80
|
-
rubygems_version: 4.0.
|
|
80
|
+
rubygems_version: 4.0.20
|
|
81
81
|
specification_version: 4
|
|
82
82
|
summary: A drop-in replacement for the sqlite3 gem for JRuby
|
|
83
83
|
test_files: []
|