libsql 0.1.0-x64-mingw-ucrt
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 +7 -0
- data/CONTRIBUTING.md +60 -0
- data/HISTORY.md +6 -0
- data/LICENSE +31 -0
- data/Manifest.txt +96 -0
- data/README.md +59 -0
- data/Rakefile +28 -0
- data/TODO.md +57 -0
- data/examples/a.rb +9 -0
- data/examples/blob.rb +106 -0
- data/examples/define_aggregate.rb +75 -0
- data/examples/define_function.rb +104 -0
- data/examples/fts5.rb +152 -0
- data/examples/gem-db.rb +94 -0
- data/examples/schema-info.rb +34 -0
- data/ext/libsql/c/extconf.rb +86 -0
- data/ext/libsql/c/gen_constants.rb +353 -0
- data/ext/libsql/c/libsql_blob.c +240 -0
- data/ext/libsql/c/libsql_constants.c +1518 -0
- data/ext/libsql/c/libsql_database.c +1188 -0
- data/ext/libsql/c/libsql_ext.c +383 -0
- data/ext/libsql/c/libsql_ext.h +149 -0
- data/ext/libsql/c/libsql_statement.c +649 -0
- data/ext/libsql/c/notes.txt +134 -0
- data/ext/libsql/c/sqlite3.c +247030 -0
- data/ext/libsql/c/sqlite3.h +13436 -0
- data/lib/libsql/3.1/libsql_ext.so +0 -0
- data/lib/libsql/3.2/libsql_ext.so +0 -0
- data/lib/libsql/aggregate.rb +73 -0
- data/lib/libsql/blob.rb +186 -0
- data/lib/libsql/boolean.rb +42 -0
- data/lib/libsql/busy_timeout.rb +47 -0
- data/lib/libsql/column.rb +99 -0
- data/lib/libsql/csv_table_importer.rb +75 -0
- data/lib/libsql/database.rb +933 -0
- data/lib/libsql/function.rb +61 -0
- data/lib/libsql/index.rb +43 -0
- data/lib/libsql/memory_database.rb +15 -0
- data/lib/libsql/paths.rb +80 -0
- data/lib/libsql/profile_tap.rb +131 -0
- data/lib/libsql/progress_handler.rb +21 -0
- data/lib/libsql/schema.rb +225 -0
- data/lib/libsql/sqlite3/constants.rb +95 -0
- data/lib/libsql/sqlite3/database/function.rb +48 -0
- data/lib/libsql/sqlite3/database/status.rb +68 -0
- data/lib/libsql/sqlite3/libsql_version.rb +32 -0
- data/lib/libsql/sqlite3/status.rb +60 -0
- data/lib/libsql/sqlite3/version.rb +55 -0
- data/lib/libsql/sqlite3.rb +7 -0
- data/lib/libsql/statement.rb +421 -0
- data/lib/libsql/table.rb +91 -0
- data/lib/libsql/taps/console.rb +27 -0
- data/lib/libsql/taps/io.rb +74 -0
- data/lib/libsql/taps.rb +2 -0
- data/lib/libsql/trace_tap.rb +35 -0
- data/lib/libsql/type_map.rb +63 -0
- data/lib/libsql/type_maps/default_map.rb +166 -0
- data/lib/libsql/type_maps/storage_map.rb +38 -0
- data/lib/libsql/type_maps/text_map.rb +21 -0
- data/lib/libsql/version.rb +8 -0
- data/lib/libsql/view.rb +26 -0
- data/lib/libsql-ruby.rb +1 -0
- data/lib/libsql.rb +51 -0
- data/spec/aggregate_spec.rb +158 -0
- data/spec/blob_spec.rb +78 -0
- data/spec/boolean_spec.rb +24 -0
- data/spec/busy_handler.rb +157 -0
- data/spec/data/iso-3166-country.txt +242 -0
- data/spec/data/iso-3166-schema.sql +22 -0
- data/spec/data/iso-3166-subcountry.txt +3995 -0
- data/spec/data/make-iso-db.sh +12 -0
- data/spec/database_spec.rb +505 -0
- data/spec/default_map_spec.rb +92 -0
- data/spec/function_spec.rb +78 -0
- data/spec/integeration_spec.rb +97 -0
- data/spec/iso_3166_database.rb +58 -0
- data/spec/json_spec.rb +24 -0
- data/spec/libsql_spec.rb +4 -0
- data/spec/paths_spec.rb +28 -0
- data/spec/progress_handler_spec.rb +91 -0
- data/spec/rtree_spec.rb +66 -0
- data/spec/schema_spec.rb +131 -0
- data/spec/spec_helper.rb +48 -0
- data/spec/sqlite3/constants_spec.rb +108 -0
- data/spec/sqlite3/database_status_spec.rb +36 -0
- data/spec/sqlite3/libsql_version_spec.rb +16 -0
- data/spec/sqlite3/status_spec.rb +22 -0
- data/spec/sqlite3/version_spec.rb +28 -0
- data/spec/sqlite3_spec.rb +53 -0
- data/spec/statement_spec.rb +168 -0
- data/spec/storage_map_spec.rb +38 -0
- data/spec/tap_spec.rb +57 -0
- data/spec/text_map_spec.rb +20 -0
- data/spec/type_map_spec.rb +14 -0
- data/spec/version_spec.rb +8 -0
- data/tasks/custom.rake +134 -0
- data/tasks/default.rake +257 -0
- data/tasks/extension.rake +29 -0
- data/tasks/this.rb +208 -0
- metadata +329 -0
@@ -0,0 +1,353 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'pp'
|
4
|
+
|
5
|
+
# readin in the sqlite3.h file and parse out all the #define lines
|
6
|
+
sqlite3_h_fname = File.expand_path(File.join(File.dirname(__FILE__), "sqlite3.h"))
|
7
|
+
|
8
|
+
# special handling for those that are function result codes
|
9
|
+
result_codes = %w[
|
10
|
+
SQLITE_OK
|
11
|
+
SQLITE_ERROR
|
12
|
+
SQLITE_INTERNAL
|
13
|
+
SQLITE_PERM
|
14
|
+
SQLITE_ABORT
|
15
|
+
SQLITE_BUSY
|
16
|
+
SQLITE_LOCKED
|
17
|
+
SQLITE_NOMEM
|
18
|
+
SQLITE_READONLY
|
19
|
+
SQLITE_INTERRUPT
|
20
|
+
SQLITE_IOERR
|
21
|
+
SQLITE_CORRUPT
|
22
|
+
SQLITE_NOTFOUND
|
23
|
+
SQLITE_FULL
|
24
|
+
SQLITE_CANTOPEN
|
25
|
+
SQLITE_PROTOCOL
|
26
|
+
SQLITE_EMPTY
|
27
|
+
SQLITE_SCHEMA
|
28
|
+
SQLITE_TOOBIG
|
29
|
+
SQLITE_CONSTRAINT
|
30
|
+
SQLITE_MISMATCH
|
31
|
+
SQLITE_MISUSE
|
32
|
+
SQLITE_NOLFS
|
33
|
+
SQLITE_AUTH
|
34
|
+
SQLITE_FORMAT
|
35
|
+
SQLITE_RANGE
|
36
|
+
SQLITE_NOTADB
|
37
|
+
SQLITE_NOTICE
|
38
|
+
SQLITE_WARNING
|
39
|
+
SQLITE_ROW
|
40
|
+
SQLITE_DONE
|
41
|
+
SQLITE_ERROR_MISSING_COLLSEQ
|
42
|
+
SQLITE_ERROR_RETRY
|
43
|
+
SQLITE_ERROR_SNAPSHOT
|
44
|
+
SQLITE_IOERR_READ
|
45
|
+
SQLITE_IOERR_SHORT_READ
|
46
|
+
SQLITE_IOERR_WRITE
|
47
|
+
SQLITE_IOERR_FSYNC
|
48
|
+
SQLITE_IOERR_DIR_FSYNC
|
49
|
+
SQLITE_IOERR_TRUNCATE
|
50
|
+
SQLITE_IOERR_FSTAT
|
51
|
+
SQLITE_IOERR_UNLOCK
|
52
|
+
SQLITE_IOERR_RDLOCK
|
53
|
+
SQLITE_IOERR_DELETE
|
54
|
+
SQLITE_IOERR_BLOCKED
|
55
|
+
SQLITE_IOERR_NOMEM
|
56
|
+
SQLITE_IOERR_ACCESS
|
57
|
+
SQLITE_IOERR_CHECKRESERVEDLOCK
|
58
|
+
SQLITE_IOERR_LOCK
|
59
|
+
SQLITE_IOERR_CLOSE
|
60
|
+
SQLITE_IOERR_DIR_CLOSE
|
61
|
+
SQLITE_IOERR_SHMOPEN
|
62
|
+
SQLITE_IOERR_SHMSIZE
|
63
|
+
SQLITE_IOERR_SHMLOCK
|
64
|
+
SQLITE_IOERR_SHMMAP
|
65
|
+
SQLITE_IOERR_SEEK
|
66
|
+
SQLITE_IOERR_DELETE_NOENT
|
67
|
+
SQLITE_IOERR_MMAP
|
68
|
+
SQLITE_IOERR_GETTEMPPATH
|
69
|
+
SQLITE_IOERR_CONVPATH
|
70
|
+
SQLITE_IOERR_VNODE
|
71
|
+
SQLITE_IOERR_AUTH
|
72
|
+
SQLITE_IOERR_BEGIN_ATOMIC
|
73
|
+
SQLITE_IOERR_COMMIT_ATOMIC
|
74
|
+
SQLITE_IOERR_ROLLBACK_ATOMIC
|
75
|
+
SQLITE_IOERR_DATA
|
76
|
+
SQLITE_IOERR_CORRUPTFS
|
77
|
+
SQLITE_LOCKED_SHAREDCACHE
|
78
|
+
SQLITE_LOCKED_VTAB
|
79
|
+
SQLITE_BUSY_RECOVERY
|
80
|
+
SQLITE_BUSY_SNAPSHOT
|
81
|
+
SQLITE_BUSY_TIMEOUT
|
82
|
+
SQLITE_CANTOPEN_NOTEMPDIR
|
83
|
+
SQLITE_CANTOPEN_ISDIR
|
84
|
+
SQLITE_CANTOPEN_FULLPATH
|
85
|
+
SQLITE_CANTOPEN_CONVPATH
|
86
|
+
SQLITE_CANTOPEN_DIRTYWAL
|
87
|
+
SQLITE_CANTOPEN_SYMLINK
|
88
|
+
SQLITE_CORRUPT_VTAB
|
89
|
+
SQLITE_CORRUPT_SEQUENCE
|
90
|
+
SQLITE_CORRUPT_INDEX
|
91
|
+
SQLITE_READONLY_RECOVERY
|
92
|
+
SQLITE_READONLY_CANTLOCK
|
93
|
+
SQLITE_READONLY_ROLLBACK
|
94
|
+
SQLITE_READONLY_DBMOVED
|
95
|
+
SQLITE_READONLY_CANTINIT
|
96
|
+
SQLITE_READONLY_DIRECTORY
|
97
|
+
SQLITE_ABORT_ROLLBACK
|
98
|
+
SQLITE_CONSTRAINT_CHECK
|
99
|
+
SQLITE_CONSTRAINT_COMMITHOOK
|
100
|
+
SQLITE_CONSTRAINT_FOREIGNKEY
|
101
|
+
SQLITE_CONSTRAINT_FUNCTION
|
102
|
+
SQLITE_CONSTRAINT_NOTNULL
|
103
|
+
SQLITE_CONSTRAINT_PRIMARYKEY
|
104
|
+
SQLITE_CONSTRAINT_TRIGGER
|
105
|
+
SQLITE_CONSTRAINT_UNIQUE
|
106
|
+
SQLITE_CONSTRAINT_VTAB
|
107
|
+
SQLITE_CONSTRAINT_ROWID
|
108
|
+
SQLITE_CONSTRAINT_PINNED
|
109
|
+
SQLITE_NOTICE_RECOVER_WAL
|
110
|
+
SQLITE_NOTICE_RECOVER_ROLLBACK
|
111
|
+
SQLITE_WARNING_AUTOINDEX
|
112
|
+
SQLITE_AUTH_USER
|
113
|
+
SQLITE_OK_LOAD_PERMANENTLY
|
114
|
+
SQLITE_OK_SYMLINK
|
115
|
+
]
|
116
|
+
|
117
|
+
deprecated_codes = %w[ SQLITE_GET_LOCKPROXYFILE SQLITE_SET_LOCKPROXYFILE SQLITE_LAST_ERRNO ]
|
118
|
+
version_codes = %w[ SQLITE_VERSION SQLITE_VERSION_NUMBER SQLITE_SOURCE_ID LIBSQL_VERSION ]
|
119
|
+
rtree_codes = %w[ NOT_WITHIN PARTLY_WITHIN FULLY_WITHIN ]
|
120
|
+
|
121
|
+
authorizer_codes = %w[
|
122
|
+
SQLITE_DENY
|
123
|
+
SQLITE_IGNORE
|
124
|
+
SQLITE_CREATE_INDEX
|
125
|
+
SQLITE_CREATE_TABLE
|
126
|
+
SQLITE_CREATE_TEMP_INDEX
|
127
|
+
SQLITE_CREATE_TEMP_TABLE
|
128
|
+
SQLITE_CREATE_TEMP_TRIGGER
|
129
|
+
SQLITE_CREATE_TEMP_VIEW
|
130
|
+
SQLITE_CREATE_TRIGGER
|
131
|
+
SQLITE_CREATE_VIEW
|
132
|
+
SQLITE_DELETE
|
133
|
+
SQLITE_DROP_INDEX
|
134
|
+
SQLITE_DROP_TABLE
|
135
|
+
SQLITE_DROP_TEMP_INDEX
|
136
|
+
SQLITE_DROP_TEMP_TABLE
|
137
|
+
SQLITE_DROP_TEMP_TRIGGER
|
138
|
+
SQLITE_DROP_TEMP_VIEW
|
139
|
+
SQLITE_DROP_TRIGGER
|
140
|
+
SQLITE_DROP_VIEW
|
141
|
+
SQLITE_INSERT
|
142
|
+
SQLITE_PRAGMA
|
143
|
+
SQLITE_READ
|
144
|
+
SQLITE_SELECT
|
145
|
+
SQLITE_TRANSACTION
|
146
|
+
SQLITE_UPDATE
|
147
|
+
SQLITE_ATTACH
|
148
|
+
SQLITE_DETACH
|
149
|
+
SQLITE_ALTER_TABLE
|
150
|
+
SQLITE_REINDEX
|
151
|
+
SQLITE_ANALYZE
|
152
|
+
SQLITE_CREATE_VTABLE
|
153
|
+
SQLITE_DROP_VTABLE
|
154
|
+
SQLITE_FUNCTION
|
155
|
+
SQLITE_SAVEPOINT
|
156
|
+
SQLITE_COPY
|
157
|
+
SQLITE_RECURSIVE
|
158
|
+
]
|
159
|
+
|
160
|
+
text_encoding_codes = %w[
|
161
|
+
SQLITE_UTF8
|
162
|
+
SQLITE_UTF16LE
|
163
|
+
SQLITE_UTF16BE
|
164
|
+
SQLITE_UTF16
|
165
|
+
SQLITE_ANY
|
166
|
+
SQLITE_UTF16_ALIGNED
|
167
|
+
SQLITE_DETERMINISTIC
|
168
|
+
SQLITE_DIRECTONLY
|
169
|
+
SQLITE_SUBTYPE
|
170
|
+
SQLITE_INNOCUOUS
|
171
|
+
]
|
172
|
+
|
173
|
+
data_type_codes = %w[
|
174
|
+
SQLITE_INTEGER
|
175
|
+
SQLITE_FLOAT
|
176
|
+
SQLITE_BLOB
|
177
|
+
SQLITE_NULL
|
178
|
+
SQLITE3_TEXT
|
179
|
+
]
|
180
|
+
|
181
|
+
fts5_codes = %w[
|
182
|
+
FTS5_TOKENIZE_QUERY
|
183
|
+
FTS5_TOKENIZE_PREFIX
|
184
|
+
FTS5_TOKENIZE_DOCUMENT
|
185
|
+
FTS5_TOKENIZE_AUX
|
186
|
+
FTS5_TOKEN_COLOCATED
|
187
|
+
]
|
188
|
+
|
189
|
+
ignore_codes = [
|
190
|
+
# vtab related
|
191
|
+
"SQLITE_ROLLBACK",
|
192
|
+
"SQLITE_FAIL",
|
193
|
+
"SQLITE_REPLACE",
|
194
|
+
"SQLITE_VTAB_CONSTRAINT_SUPPORT",
|
195
|
+
"SQLITE_VTAB_INNOCUOUS",
|
196
|
+
"SQLITE_VTAB_DIRECTONLY",
|
197
|
+
|
198
|
+
# sqlite destructor callback codes
|
199
|
+
"SQLITE_STATIC",
|
200
|
+
"SQLITE_TRANSIENT",
|
201
|
+
]
|
202
|
+
|
203
|
+
# oddball name
|
204
|
+
module_name_mapping = {
|
205
|
+
|
206
|
+
"DBCONFIG" => "DBConfig",
|
207
|
+
"DBSTATUS" => "DBStatus",
|
208
|
+
"IOCAP" => "IOCap",
|
209
|
+
"SHM" => "SHM",
|
210
|
+
"SCANSTAT" => "ScanStat",
|
211
|
+
"STMTSTATUS" => "StatementStatus",
|
212
|
+
"CHANGESETAPPLY" => "ChangesetApply",
|
213
|
+
"CHANGESETSTART" => "ChangesetStart",
|
214
|
+
"TXN" => "Transaction",
|
215
|
+
}
|
216
|
+
|
217
|
+
defines = []
|
218
|
+
IO.readlines(sqlite3_h_fname).each do |l|
|
219
|
+
result = {
|
220
|
+
"c_define" => nil,
|
221
|
+
"c_value" => nil,
|
222
|
+
"docstring" => nil,
|
223
|
+
|
224
|
+
"is_error_code" => false,
|
225
|
+
|
226
|
+
"r_module" => nil,
|
227
|
+
"r_constant" => nil,
|
228
|
+
}
|
229
|
+
|
230
|
+
if l =~ /beginning-of-error-codes/ .. l =~ /end-of-error-codes/ then
|
231
|
+
result["is_error_code"] = true
|
232
|
+
end
|
233
|
+
|
234
|
+
l.strip!
|
235
|
+
md = l.match(/\A#define\s+(\w+)\s+([^\/]+)\s*(\/\*(.*)\*\/)?\Z/)
|
236
|
+
next unless md
|
237
|
+
|
238
|
+
# Name munging
|
239
|
+
c_define = md[1]
|
240
|
+
|
241
|
+
c_parts = c_define.gsub(/^SQLITE_/,'').split("_")
|
242
|
+
r_module = c_parts.shift
|
243
|
+
r_constant = c_parts.join("_")
|
244
|
+
|
245
|
+
|
246
|
+
# custom module naming so they are human readable
|
247
|
+
r_module = module_name_mapping.fetch(r_module) { |m| r_module.capitalize }
|
248
|
+
|
249
|
+
case c_define
|
250
|
+
when *version_codes
|
251
|
+
next
|
252
|
+
|
253
|
+
when *deprecated_codes
|
254
|
+
next
|
255
|
+
|
256
|
+
when *rtree_codes
|
257
|
+
r_module = "RTree"
|
258
|
+
r_constant = c_define
|
259
|
+
|
260
|
+
when *result_codes
|
261
|
+
r_module = "ResultCode"
|
262
|
+
r_constant = c_define.gsub(/^SQLITE_/,'')
|
263
|
+
|
264
|
+
when *authorizer_codes
|
265
|
+
r_module = "Authorizer"
|
266
|
+
r_constant = c_define.gsub(/^SQLITE_/,'')
|
267
|
+
|
268
|
+
when *text_encoding_codes
|
269
|
+
r_module = "TextEncoding"
|
270
|
+
r_constant = c_define.gsub(/^SQLITE_/,'')
|
271
|
+
|
272
|
+
when *data_type_codes
|
273
|
+
r_module = "DataType"
|
274
|
+
r_constant = c_define.gsub(/^SQLITE(3)?_/,'')
|
275
|
+
|
276
|
+
when *fts5_codes
|
277
|
+
r_module = "FTS5"
|
278
|
+
r_constant = c_define.gsub(/^FTS5_/,'')
|
279
|
+
|
280
|
+
when *ignore_codes
|
281
|
+
next
|
282
|
+
|
283
|
+
when /TESTCTRL/ # sqlite3 codes used in testing
|
284
|
+
next
|
285
|
+
|
286
|
+
when /^__/ # sqlite3 internal items
|
287
|
+
next
|
288
|
+
end
|
289
|
+
|
290
|
+
result["c_define"] = c_define
|
291
|
+
result["c_value"] = md[2].strip
|
292
|
+
if !md[4].nil? && (md[4].strip.length > 0) then
|
293
|
+
result["docstring"] = md[4].strip
|
294
|
+
end
|
295
|
+
result["r_module"] = r_module
|
296
|
+
result["r_constant"] = r_constant
|
297
|
+
|
298
|
+
defines << result
|
299
|
+
end
|
300
|
+
|
301
|
+
#
|
302
|
+
# rework defines into constants
|
303
|
+
#
|
304
|
+
CONSTANTS = defines.group_by{ |d| d["r_module"] }
|
305
|
+
|
306
|
+
fname = File.expand_path(File.join(File.dirname(__FILE__), "libsql_constants.c"))
|
307
|
+
|
308
|
+
|
309
|
+
File.open(fname, "w+") do |f|
|
310
|
+
f.puts "/* Generated by gen_constants.rb -- do not edit */"
|
311
|
+
f.puts
|
312
|
+
f.puts '#include "libsql_ext.h"'
|
313
|
+
f.puts '/**'
|
314
|
+
f.puts ' * Document-class: ::Libsql::SQLite3::Constants'
|
315
|
+
f.puts ' *'
|
316
|
+
f.puts ' * class holding constants in the sqlite extension'
|
317
|
+
f.puts ' */'
|
318
|
+
f.puts "void Init_libsql_ext_constants( )"
|
319
|
+
f.puts "{"
|
320
|
+
f.puts
|
321
|
+
f.puts ' VALUE ma = rb_define_module("Libsql");'
|
322
|
+
f.puts ' VALUE mas = rb_define_module_under(ma, "SQLite3");'
|
323
|
+
f.puts
|
324
|
+
f.puts " /*"
|
325
|
+
f.puts " * module encapsulating all the SQLite C extension constants "
|
326
|
+
f.puts " */"
|
327
|
+
f.puts ' VALUE mC = rb_define_module_under( mas, "Constants");'
|
328
|
+
|
329
|
+
|
330
|
+
CONSTANTS.keys.sort.each do |mod|
|
331
|
+
f.puts " /**"
|
332
|
+
f.puts " * module encapsulating the SQLite3 C extension constants for #{mod}"
|
333
|
+
f.puts " */"
|
334
|
+
f.puts " VALUE mC_#{mod} = rb_define_module_under(mC, \"#{mod}\");"
|
335
|
+
f.puts
|
336
|
+
end
|
337
|
+
|
338
|
+
CONSTANTS.keys.sort.each do |mod|
|
339
|
+
const_set = CONSTANTS[mod]
|
340
|
+
const_set.sort_by { |c| c["c_define"] }.each do |result|
|
341
|
+
sql_const = result["c_define"]
|
342
|
+
const_doc = " /* no meaningful autogenerated documentation -- constant is self explanatory ?*/"
|
343
|
+
if !result["docstring"].nil? then
|
344
|
+
const_doc = " /* #{result['c_value']} -- #{result['docstring']} */"
|
345
|
+
end
|
346
|
+
ruby_constant = result['r_constant']
|
347
|
+
f.puts const_doc
|
348
|
+
f.puts " rb_define_const(mC_#{mod}, \"#{ruby_constant}\", INT2FIX(#{sql_const}));"
|
349
|
+
f.puts
|
350
|
+
end
|
351
|
+
end
|
352
|
+
f.puts "}"
|
353
|
+
end
|
@@ -0,0 +1,240 @@
|
|
1
|
+
#include "libsql_ext.h"
|
2
|
+
/**
|
3
|
+
* Copyright (c) 2023 Jeremy Hinegardner
|
4
|
+
* All rights reserved. See LICENSE and/or COPYING for details.
|
5
|
+
*
|
6
|
+
* vim: shiftwidth=4
|
7
|
+
*/
|
8
|
+
|
9
|
+
/* class Amalgliate::SQLite3::Blob */
|
10
|
+
VALUE cLS_Blob;
|
11
|
+
|
12
|
+
/**
|
13
|
+
* call-seq:
|
14
|
+
* Blob.new( database, table_name, column_name, row_id, flag ) -> Blob
|
15
|
+
*
|
16
|
+
* Create a new Blob object and associate it with the approriate, database,
|
17
|
+
* table, column and row. +flag+ indicates if the Blob is to be opened for
|
18
|
+
* writing "w" or reading "r".
|
19
|
+
*
|
20
|
+
*/
|
21
|
+
VALUE libsql_ext_sqlite3_blob_initialize( VALUE self, VALUE db, VALUE db_name, VALUE table_name, VALUE column_name, VALUE rowid, VALUE flag)
|
22
|
+
{
|
23
|
+
libsql_ext_sqlite3_blob *libsql_ext_blob;
|
24
|
+
int rc;
|
25
|
+
libsql_ext_sqlite3 *libsql_ext_db;
|
26
|
+
char *zDb = StringValuePtr( db_name );
|
27
|
+
char *zTable = StringValuePtr( table_name );
|
28
|
+
char *zColumn = StringValuePtr( column_name );
|
29
|
+
sqlite3_int64 iRow = NUM2SQLINT64( rowid ) ;
|
30
|
+
VALUE flag_str = StringValue( flag );
|
31
|
+
int flags = 0;
|
32
|
+
|
33
|
+
/* extract the blob struct */
|
34
|
+
Data_Get_Struct(self, libsql_ext_sqlite3_blob, libsql_ext_blob);
|
35
|
+
|
36
|
+
/* extract the sqlite3 db struct */
|
37
|
+
Data_Get_Struct(db, libsql_ext_sqlite3, libsql_ext_db);
|
38
|
+
|
39
|
+
/* make sure that the flags are valid, only 'r' or 'w' are allowed */
|
40
|
+
if ( ( RSTRING_LEN( flag_str ) != 1) ||
|
41
|
+
( ( 'r' != RSTRING_PTR( flag_str )[0] ) &&
|
42
|
+
( 'w' != RSTRING_PTR( flag_str )[0] ))) {
|
43
|
+
rb_raise( eLS_Error, "Error opening Blob in db = %s, table = %s, column = %s, rowid = %lu. Invalid flag '%s'. Must be either 'w' or 'r'\n",
|
44
|
+
zDb, zTable, zColumn, (unsigned long)iRow, RSTRING_PTR( flag_str ));
|
45
|
+
}
|
46
|
+
|
47
|
+
/* switch to write mode */
|
48
|
+
if ( 'w' == RSTRING_PTR( flag_str )[0] ) {
|
49
|
+
flags = 1;
|
50
|
+
}
|
51
|
+
|
52
|
+
/* open the blob and associate the db to it */
|
53
|
+
rc = sqlite3_blob_open( libsql_ext_db->db, zDb, zTable, zColumn, iRow, flags, &( libsql_ext_blob->blob ) );
|
54
|
+
if ( SQLITE_OK != rc ) {
|
55
|
+
rb_raise( eLS_Error, "Error opening Blob in db = %s, table = %s, column = %s, rowid = %lu : [SQLITE_ERROR %d] %s\n", zDb, zTable, zColumn, (unsigned long)iRow, rc, sqlite3_errmsg( libsql_ext_db->db) );
|
56
|
+
}
|
57
|
+
libsql_ext_blob->length = sqlite3_blob_bytes( libsql_ext_blob->blob );
|
58
|
+
libsql_ext_blob->db = libsql_ext_db->db;
|
59
|
+
|
60
|
+
/* if a block is given then yield self and close the blob when done */
|
61
|
+
if ( rb_block_given_p() ) {
|
62
|
+
rb_yield( self );
|
63
|
+
libsql_ext_sqlite3_blob_close( self );
|
64
|
+
return Qnil;
|
65
|
+
} else {
|
66
|
+
return self;
|
67
|
+
}
|
68
|
+
}
|
69
|
+
|
70
|
+
/**
|
71
|
+
* call-seq:
|
72
|
+
* blob.close -> nil
|
73
|
+
*
|
74
|
+
* Closes the blob.
|
75
|
+
*/
|
76
|
+
VALUE libsql_ext_sqlite3_blob_close( VALUE self )
|
77
|
+
{
|
78
|
+
libsql_ext_sqlite3_blob *libsql_ext_blob;
|
79
|
+
int rc;
|
80
|
+
|
81
|
+
Data_Get_Struct(self, libsql_ext_sqlite3_blob, libsql_ext_blob);
|
82
|
+
rc = sqlite3_blob_close( libsql_ext_blob->blob );
|
83
|
+
if ( SQLITE_OK != rc ) {
|
84
|
+
rb_raise(eLS_Error, "Error closing blob: [SQLITE_ERROR %d] %s\n",
|
85
|
+
rc, sqlite3_errmsg( libsql_ext_blob->db ));
|
86
|
+
}
|
87
|
+
|
88
|
+
|
89
|
+
return Qnil;
|
90
|
+
}
|
91
|
+
|
92
|
+
|
93
|
+
/**
|
94
|
+
* call-seq:
|
95
|
+
* blob.length -> length in bytes of the blob
|
96
|
+
*
|
97
|
+
* Returns the number of bytes in the blob.
|
98
|
+
*/
|
99
|
+
VALUE libsql_ext_sqlite3_blob_length( VALUE self )
|
100
|
+
{
|
101
|
+
libsql_ext_sqlite3_blob *libsql_ext_blob;
|
102
|
+
|
103
|
+
Data_Get_Struct(self, libsql_ext_sqlite3_blob, libsql_ext_blob);
|
104
|
+
|
105
|
+
return INT2FIX( libsql_ext_blob->length );
|
106
|
+
}
|
107
|
+
|
108
|
+
/**
|
109
|
+
* call-seq:
|
110
|
+
* blob.read( int ) -> String containting int number of bytes or nil if eof.
|
111
|
+
*
|
112
|
+
* returns int number of bytes as a String from the database
|
113
|
+
*/
|
114
|
+
VALUE libsql_ext_sqlite3_blob_read( VALUE self, VALUE length )
|
115
|
+
{
|
116
|
+
libsql_ext_sqlite3_blob *libsql_ext_blob;
|
117
|
+
int rc;
|
118
|
+
int n = NUM2INT( length );
|
119
|
+
void *buf = NULL;
|
120
|
+
VALUE result;
|
121
|
+
|
122
|
+
Data_Get_Struct(self, libsql_ext_sqlite3_blob, libsql_ext_blob);
|
123
|
+
|
124
|
+
/* we have to be exact on the number of bytes to read. n + current_offset
|
125
|
+
* cannot be larger than the blob's length
|
126
|
+
*/
|
127
|
+
if ( (n + libsql_ext_blob->current_offset > libsql_ext_blob->length)) {
|
128
|
+
n = libsql_ext_blob->length - libsql_ext_blob->current_offset;
|
129
|
+
}
|
130
|
+
|
131
|
+
if ( libsql_ext_blob->current_offset == libsql_ext_blob->length ) {
|
132
|
+
return Qnil;
|
133
|
+
}
|
134
|
+
|
135
|
+
buf = (void *)malloc( n );
|
136
|
+
rc = sqlite3_blob_read( libsql_ext_blob->blob, buf, n, libsql_ext_blob->current_offset);
|
137
|
+
|
138
|
+
if ( rc != SQLITE_OK ) {
|
139
|
+
rb_raise(eLS_Error, "Error reading %d bytes blob at offset %d: [SQLITE_ERROR %d] %s\n",
|
140
|
+
n, libsql_ext_blob->current_offset, rc, sqlite3_errmsg( libsql_ext_blob->db ));
|
141
|
+
}
|
142
|
+
|
143
|
+
libsql_ext_blob->current_offset += n;
|
144
|
+
|
145
|
+
result = rb_str_new( (char*)buf, n );
|
146
|
+
free( buf );
|
147
|
+
return result;
|
148
|
+
|
149
|
+
}
|
150
|
+
|
151
|
+
/**
|
152
|
+
* call-seq:
|
153
|
+
* blob.write( buf ) -> int
|
154
|
+
*
|
155
|
+
* writes the contents of the string buffer to the blob and returns the number
|
156
|
+
* of bytes written.
|
157
|
+
*
|
158
|
+
*/
|
159
|
+
VALUE libsql_ext_sqlite3_blob_write( VALUE self, VALUE buf )
|
160
|
+
{
|
161
|
+
libsql_ext_sqlite3_blob *libsql_ext_blob;
|
162
|
+
int rc;
|
163
|
+
VALUE str = StringValue( buf );
|
164
|
+
int n = (int)RSTRING_LEN( str );
|
165
|
+
char *chk_buf = NULL;
|
166
|
+
|
167
|
+
Data_Get_Struct(self, libsql_ext_sqlite3_blob, libsql_ext_blob);
|
168
|
+
|
169
|
+
rc = sqlite3_blob_write( libsql_ext_blob->blob, RSTRING_PTR(str), n, libsql_ext_blob->current_offset);
|
170
|
+
|
171
|
+
if ( rc != SQLITE_OK ) {
|
172
|
+
rb_raise(eLS_Error, "Error writing %d bytes blob at offset %d: [SQLITE_ERROR %d] %s\n",
|
173
|
+
n, libsql_ext_blob->current_offset, rc, sqlite3_errmsg( libsql_ext_blob->db ));
|
174
|
+
}
|
175
|
+
|
176
|
+
chk_buf = (char *) malloc( n + 1);
|
177
|
+
chk_buf[n] = '\0';
|
178
|
+
sqlite3_blob_read( libsql_ext_blob->blob, chk_buf, n, 0);
|
179
|
+
|
180
|
+
libsql_ext_blob->current_offset += n;
|
181
|
+
|
182
|
+
return INT2FIX( n );
|
183
|
+
|
184
|
+
}
|
185
|
+
|
186
|
+
|
187
|
+
/***********************************************************************
|
188
|
+
* Ruby life cycle methods
|
189
|
+
***********************************************************************/
|
190
|
+
|
191
|
+
/*
|
192
|
+
* garbage collector free method for the libsql_ext_sqlite3_blob structure
|
193
|
+
*/
|
194
|
+
void libsql_ext_sqlite3_blob_free(libsql_ext_sqlite3_blob* wrapper)
|
195
|
+
{
|
196
|
+
free(wrapper);
|
197
|
+
return;
|
198
|
+
}
|
199
|
+
|
200
|
+
/*
|
201
|
+
* allocate the libsql_ext_blob structure
|
202
|
+
*/
|
203
|
+
VALUE libsql_ext_sqlite3_blob_alloc(VALUE klass)
|
204
|
+
{
|
205
|
+
libsql_ext_sqlite3_blob *wrapper = ALLOC( libsql_ext_sqlite3_blob );
|
206
|
+
VALUE obj ;
|
207
|
+
|
208
|
+
wrapper->current_offset = 0;
|
209
|
+
wrapper->db = NULL;
|
210
|
+
obj = Data_Wrap_Struct(klass, NULL, libsql_ext_sqlite3_blob_free, wrapper);
|
211
|
+
return obj;
|
212
|
+
}
|
213
|
+
|
214
|
+
|
215
|
+
/**
|
216
|
+
* Document-class: Libsql::SQLite3::Blob
|
217
|
+
*
|
218
|
+
* The Blob class enables incremental IO on blob items. If you do not need
|
219
|
+
* incremental IO on a binary object, then you do not need to use Blob.
|
220
|
+
*/
|
221
|
+
|
222
|
+
void Init_libsql_ext_blob( )
|
223
|
+
{
|
224
|
+
|
225
|
+
VALUE ma = rb_define_module("Libsql");
|
226
|
+
VALUE mas = rb_define_module_under(ma, "SQLite3");
|
227
|
+
|
228
|
+
/*
|
229
|
+
* Encapsulate the SQLite3 Statement handle in a class
|
230
|
+
*/
|
231
|
+
cLS_Blob = rb_define_class_under( mas, "Blob", rb_cObject );
|
232
|
+
rb_define_alloc_func(cLS_Blob, libsql_ext_sqlite3_blob_alloc);
|
233
|
+
rb_define_method(cLS_Blob, "initialize", libsql_ext_sqlite3_blob_initialize, 6);
|
234
|
+
rb_define_method(cLS_Blob, "close", libsql_ext_sqlite3_blob_close, 0);
|
235
|
+
rb_define_method(cLS_Blob, "read", libsql_ext_sqlite3_blob_read, 1);
|
236
|
+
rb_define_method(cLS_Blob, "write", libsql_ext_sqlite3_blob_write, 1);
|
237
|
+
rb_define_method(cLS_Blob, "length", libsql_ext_sqlite3_blob_length, 0);
|
238
|
+
}
|
239
|
+
|
240
|
+
|