extralite-bundle 2.5 → 2.7
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/.gitignore +1 -0
- data/CHANGELOG.md +34 -13
- data/Gemfile +4 -0
- data/Gemfile-bundle +1 -1
- data/LICENSE +1 -1
- data/README.md +1059 -247
- data/Rakefile +18 -0
- data/TODO.md +0 -7
- data/examples/kv_store.rb +49 -0
- data/examples/multi_fiber.rb +16 -0
- data/examples/on_progress.rb +9 -0
- data/examples/pubsub_store_polyphony.rb +194 -0
- data/examples/pubsub_store_threads.rb +204 -0
- data/ext/extralite/changeset.c +463 -0
- data/ext/extralite/common.c +177 -91
- data/ext/extralite/database.c +745 -276
- data/ext/extralite/extconf-bundle.rb +10 -4
- data/ext/extralite/extconf.rb +34 -34
- data/ext/extralite/extralite.h +104 -47
- data/ext/extralite/extralite_ext.c +6 -0
- data/ext/extralite/iterator.c +14 -86
- data/ext/extralite/query.c +171 -264
- data/extralite-bundle.gemspec +1 -1
- data/extralite.gemspec +1 -1
- data/gemspec.rb +10 -11
- data/lib/extralite/version.rb +1 -1
- data/lib/extralite.rb +69 -10
- data/lib/sequel/adapters/extralite.rb +1 -1
- data/test/helper.rb +9 -1
- data/test/perf_argv_transform.rb +74 -0
- data/test/perf_ary.rb +14 -12
- data/test/perf_hash.rb +17 -15
- data/test/perf_hash_prepared.rb +58 -0
- data/test/perf_hash_transform.rb +66 -0
- data/test/perf_polyphony.rb +74 -0
- data/test/test_changeset.rb +161 -0
- data/test/test_database.rb +720 -104
- data/test/test_extralite.rb +2 -2
- data/test/test_iterator.rb +28 -13
- data/test/test_query.rb +352 -110
- data/test/test_sequel.rb +4 -4
- metadata +24 -16
- data/Gemfile.lock +0 -37
- data/test/perf_prepared.rb +0 -64
data/ext/extralite/database.c
CHANGED
@@ -16,12 +16,30 @@ ID ID_call;
|
|
16
16
|
ID ID_each;
|
17
17
|
ID ID_keys;
|
18
18
|
ID ID_new;
|
19
|
+
ID ID_pragma;
|
19
20
|
ID ID_strip;
|
21
|
+
ID ID_to_s;
|
22
|
+
ID ID_track;
|
20
23
|
|
24
|
+
VALUE SYM_at_least_once;
|
21
25
|
VALUE SYM_gvl_release_threshold;
|
26
|
+
VALUE SYM_once;
|
27
|
+
VALUE SYM_none;
|
28
|
+
VALUE SYM_normal;
|
29
|
+
VALUE SYM_pragma;
|
22
30
|
VALUE SYM_read_only;
|
23
|
-
VALUE
|
24
|
-
|
31
|
+
VALUE SYM_wal;
|
32
|
+
|
33
|
+
struct progress_handler global_progress_handler = {
|
34
|
+
.mode = PROGRESS_NONE,
|
35
|
+
.proc = Qnil,
|
36
|
+
.period = DEFAULT_PROGRESS_HANDLER_PERIOD,
|
37
|
+
.tick = DEFAULT_PROGRESS_HANDLER_TICK,
|
38
|
+
.tick_count = 0,
|
39
|
+
.call_count = 0
|
40
|
+
};
|
41
|
+
|
42
|
+
#define DB_GVL_MODE(db) Database_prepare_gvl_mode(db)
|
25
43
|
|
26
44
|
static size_t Database_size(const void *ptr) {
|
27
45
|
return sizeof(Database_t);
|
@@ -29,12 +47,14 @@ static size_t Database_size(const void *ptr) {
|
|
29
47
|
|
30
48
|
static void Database_mark(void *ptr) {
|
31
49
|
Database_t *db = ptr;
|
32
|
-
rb_gc_mark_movable(db->
|
50
|
+
rb_gc_mark_movable(db->trace_proc);
|
51
|
+
rb_gc_mark_movable(db->progress_handler.proc);
|
33
52
|
}
|
34
53
|
|
35
54
|
static void Database_compact(void *ptr) {
|
36
55
|
Database_t *db = ptr;
|
37
|
-
db->
|
56
|
+
db->trace_proc = rb_gc_location(db->trace_proc);
|
57
|
+
db->progress_handler.proc = rb_gc_location(db->progress_handler.proc);
|
38
58
|
}
|
39
59
|
|
40
60
|
static void Database_free(void *ptr) {
|
@@ -51,7 +71,10 @@ static const rb_data_type_t Database_type = {
|
|
51
71
|
|
52
72
|
static VALUE Database_allocate(VALUE klass) {
|
53
73
|
Database_t *db = ALLOC(Database_t);
|
54
|
-
db->sqlite3_db =
|
74
|
+
db->sqlite3_db = NULL;
|
75
|
+
db->trace_proc = Qnil;
|
76
|
+
db->progress_handler.proc = Qnil;
|
77
|
+
db->progress_handler.mode = PROGRESS_NONE;
|
55
78
|
return TypedData_Wrap_Struct(klass, &Database_type, db);
|
56
79
|
}
|
57
80
|
|
@@ -72,12 +95,10 @@ inline sqlite3 *Database_sqlite3_db(VALUE self) {
|
|
72
95
|
return self_to_database(self)->sqlite3_db;
|
73
96
|
}
|
74
97
|
|
75
|
-
/*
|
76
|
-
* Extralite.sqlite3_version -> version
|
98
|
+
/* Returns the sqlite3 library version used by Extralite.
|
77
99
|
*
|
78
|
-
*
|
100
|
+
* @return [String] SQLite version
|
79
101
|
*/
|
80
|
-
|
81
102
|
VALUE Extralite_sqlite3_version(VALUE self) {
|
82
103
|
return rb_str_new_cstr(sqlite3_version);
|
83
104
|
}
|
@@ -94,40 +115,64 @@ default_flags:
|
|
94
115
|
return SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
|
95
116
|
}
|
96
117
|
|
97
|
-
VALUE Database_execute(int argc, VALUE *argv, VALUE self);
|
98
|
-
|
99
118
|
void Database_apply_opts(VALUE self, Database_t *db, VALUE opts) {
|
100
119
|
VALUE value = Qnil;
|
101
120
|
|
121
|
+
// :gvl_release_threshold
|
102
122
|
value = rb_hash_aref(opts, SYM_gvl_release_threshold);
|
103
123
|
if (!NIL_P(value)) db->gvl_release_threshold = NUM2INT(value);
|
104
124
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
Database_execute(1, &value, self);
|
109
|
-
}
|
125
|
+
// :pragma
|
126
|
+
value = rb_hash_aref(opts, SYM_pragma);
|
127
|
+
if (!NIL_P(value)) rb_funcall(self, ID_pragma, 1, value);
|
110
128
|
|
111
|
-
|
129
|
+
// :wal
|
130
|
+
value = rb_hash_aref(opts, SYM_wal);
|
112
131
|
if (RTEST(value)) {
|
113
|
-
|
114
|
-
|
132
|
+
int rc = sqlite3_exec(db->sqlite3_db, "PRAGMA journal_mode=wal", NULL, NULL, NULL);
|
133
|
+
if (rc != SQLITE_OK)
|
134
|
+
rb_raise(cError, "Failed to set WAL journaling mode: %s", sqlite3_errstr(rc));
|
135
|
+
rc = sqlite3_exec(db->sqlite3_db, "PRAGMA synchronous=1", NULL, NULL, NULL);
|
136
|
+
if (rc != SQLITE_OK)
|
137
|
+
rb_raise(cError, "Failed to set synchronous mode: %s", sqlite3_errstr(rc));
|
115
138
|
}
|
139
|
+
}
|
140
|
+
|
141
|
+
int Database_progress_handler(void *ptr) {
|
142
|
+
Database_t *db = (Database_t *)ptr;
|
143
|
+
db->progress_handler.tick_count += db->progress_handler.tick;
|
144
|
+
if (db->progress_handler.tick_count < db->progress_handler.period)
|
145
|
+
goto done;
|
146
|
+
|
147
|
+
db->progress_handler.tick_count -= db->progress_handler.period;
|
148
|
+
db->progress_handler.call_count += 1;
|
149
|
+
rb_funcall(db->progress_handler.proc, ID_call, 0);
|
150
|
+
done:
|
151
|
+
return 0;
|
152
|
+
}
|
116
153
|
|
117
|
-
|
154
|
+
int Database_busy_handler(void *ptr, int v) {
|
155
|
+
Database_t *db = (Database_t *)ptr;
|
156
|
+
rb_funcall(db->progress_handler.proc, ID_call, 1, Qtrue);
|
157
|
+
return 1;
|
118
158
|
}
|
119
159
|
|
120
|
-
/* Initializes a new SQLite database with the given path and options
|
160
|
+
/* Initializes a new SQLite database with the given path and options:
|
161
|
+
*
|
162
|
+
* - `:gvl_release_threshold` (`Integer`): sets the GVL release threshold (see
|
163
|
+
* `#gvl_release_threshold=`).
|
164
|
+
* - `:pragma` (`Hash`): one or more pragmas to set upon opening the database.
|
165
|
+
* - `:read_only` (`true`/`false`): opens the database in read-only mode if true.
|
166
|
+
* - `:wal` (`true`/`false`): sets up the database for [WAL journaling
|
167
|
+
* mode](https://www.sqlite.org/wal.html) by setting `PRAGMA journal_mode=wal`
|
168
|
+
* and `PRAGMA synchronous=1`.
|
121
169
|
*
|
122
170
|
* @overload initialize(path)
|
123
171
|
* @param path [String] file path (or ':memory:' for memory database)
|
124
172
|
* @return [void]
|
125
|
-
* @overload initialize(path, gvl_release_threshold: ,
|
173
|
+
* @overload initialize(path, gvl_release_threshold: , on_progress: , read_only: , wal: )
|
126
174
|
* @param path [String] file path (or ':memory:' for memory database)
|
127
|
-
* @param
|
128
|
-
* @param read_only [boolean] true for opening the database for reading only
|
129
|
-
* @param synchronous [boolean] true to set PRAGMA synchronous=1
|
130
|
-
* @param wal_journal_mode [boolean] true to set PRAGMA journal_mode=wal
|
175
|
+
* @param options [Hash] options for opening the database
|
131
176
|
* @return [void]
|
132
177
|
*/
|
133
178
|
VALUE Database_initialize(int argc, VALUE *argv, VALUE self) {
|
@@ -141,6 +186,7 @@ VALUE Database_initialize(int argc, VALUE *argv, VALUE self) {
|
|
141
186
|
int rc = sqlite3_open_v2(StringValueCStr(path), &db->sqlite3_db, flags, NULL);
|
142
187
|
if (rc) {
|
143
188
|
sqlite3_close_v2(db->sqlite3_db);
|
189
|
+
db->sqlite3_db = NULL;
|
144
190
|
rb_raise(cError, "%s", sqlite3_errstr(rc));
|
145
191
|
}
|
146
192
|
|
@@ -159,11 +205,20 @@ VALUE Database_initialize(int argc, VALUE *argv, VALUE self) {
|
|
159
205
|
}
|
160
206
|
#endif
|
161
207
|
|
162
|
-
db->
|
208
|
+
db->trace_proc = Qnil;
|
163
209
|
db->gvl_release_threshold = DEFAULT_GVL_RELEASE_THRESHOLD;
|
164
210
|
|
165
|
-
|
211
|
+
db->progress_handler = global_progress_handler;
|
212
|
+
db->progress_handler.tick_count = 0;
|
213
|
+
db->progress_handler.call_count = 0;
|
214
|
+
if (db->progress_handler.mode != PROGRESS_NONE) {
|
215
|
+
db->gvl_release_threshold = -1;
|
216
|
+
if (db->progress_handler.mode != PROGRESS_ONCE)
|
217
|
+
sqlite3_progress_handler(db->sqlite3_db, db->progress_handler.tick, &Database_progress_handler, db);
|
218
|
+
sqlite3_busy_handler(db->sqlite3_db, &Database_busy_handler, db);
|
219
|
+
}
|
166
220
|
|
221
|
+
if (!NIL_P(opts)) Database_apply_opts(self, db, opts);
|
167
222
|
return Qnil;
|
168
223
|
}
|
169
224
|
|
@@ -177,10 +232,9 @@ VALUE Database_read_only_p(VALUE self) {
|
|
177
232
|
return (open == 1) ? Qtrue : Qfalse;
|
178
233
|
}
|
179
234
|
|
180
|
-
/*
|
181
|
-
*
|
182
|
-
*
|
183
|
-
* Closes the database.
|
235
|
+
/* Closes the database.
|
236
|
+
*
|
237
|
+
* @return [Extralite::Database] database
|
184
238
|
*/
|
185
239
|
VALUE Database_close(VALUE self) {
|
186
240
|
int rc;
|
@@ -191,7 +245,7 @@ VALUE Database_close(VALUE self) {
|
|
191
245
|
rb_raise(cError, "%s", sqlite3_errmsg(db->sqlite3_db));
|
192
246
|
}
|
193
247
|
|
194
|
-
db->sqlite3_db =
|
248
|
+
db->sqlite3_db = NULL;
|
195
249
|
return self;
|
196
250
|
}
|
197
251
|
|
@@ -207,24 +261,44 @@ VALUE Database_closed_p(VALUE self) {
|
|
207
261
|
return db->sqlite3_db ? Qfalse : Qtrue;
|
208
262
|
}
|
209
263
|
|
210
|
-
|
264
|
+
inline enum gvl_mode Database_prepare_gvl_mode(Database_t *db) {
|
265
|
+
return db->gvl_release_threshold < 0 ? GVL_HOLD : GVL_RELEASE;
|
266
|
+
}
|
267
|
+
|
268
|
+
static inline VALUE Database_perform_query(int argc, VALUE *argv, VALUE self, VALUE (*call)(query_ctx *), enum query_mode query_mode) {
|
211
269
|
Database_t *db = self_to_open_database(self);
|
212
270
|
sqlite3_stmt *stmt;
|
213
|
-
VALUE sql;
|
214
|
-
|
271
|
+
VALUE sql = Qnil;
|
272
|
+
VALUE transform = Qnil;
|
273
|
+
// transform mode is set and the first parameter is not a string, so we expect
|
274
|
+
// a transform.
|
275
|
+
int got_transform = (TYPE(argv[0]) != T_STRING);
|
276
|
+
|
215
277
|
// extract query from args
|
216
|
-
rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
|
278
|
+
rb_check_arity(argc, got_transform ? 2 : 1, UNLIMITED_ARGUMENTS);
|
279
|
+
|
280
|
+
if (got_transform) {
|
281
|
+
transform = argv[0];
|
282
|
+
argc--;
|
283
|
+
argv++;
|
284
|
+
}
|
285
|
+
|
217
286
|
sql = rb_funcall(argv[0], ID_strip, 0);
|
218
287
|
if (RSTRING_LEN(sql) == 0) return Qnil;
|
219
288
|
|
220
|
-
|
221
|
-
prepare_multi_stmt(db->sqlite3_db, &stmt, sql);
|
289
|
+
Database_issue_query(db, sql);
|
290
|
+
prepare_multi_stmt(DB_GVL_MODE(db), db->sqlite3_db, &stmt, sql);
|
222
291
|
RB_GC_GUARD(sql);
|
223
292
|
|
224
293
|
bind_all_parameters(stmt, argc - 1, argv + 1);
|
225
|
-
query_ctx ctx = QUERY_CTX(
|
226
|
-
|
227
|
-
|
294
|
+
query_ctx ctx = QUERY_CTX(
|
295
|
+
self, sql, db, stmt, Qnil, transform,
|
296
|
+
query_mode, ROW_YIELD_OR_MODE(ROW_MULTI), ALL_ROWS
|
297
|
+
);
|
298
|
+
|
299
|
+
VALUE result = rb_ensure(SAFE(call), (VALUE)&ctx, SAFE(cleanup_stmt), (VALUE)&ctx);
|
300
|
+
RB_GC_GUARD(result);
|
301
|
+
return result;
|
228
302
|
}
|
229
303
|
|
230
304
|
/* call-seq:
|
@@ -243,21 +317,46 @@ static inline VALUE Database_perform_query(int argc, VALUE *argv, VALUE self, VA
|
|
243
317
|
* db.query('select * from foo where x = ?', 42)
|
244
318
|
*
|
245
319
|
* Named placeholders are specified using `:`. The placeholder values are
|
246
|
-
* specified using
|
247
|
-
* keys can include or omit the `:` prefix. The following are equivalent:
|
320
|
+
* specified using keyword arguments:
|
248
321
|
*
|
249
322
|
* db.query('select * from foo where x = :bar', bar: 42)
|
250
|
-
*
|
251
|
-
*
|
323
|
+
*
|
324
|
+
* @overload query(sql, ...)
|
325
|
+
* @param sql [String] SQL statement
|
326
|
+
* @return [Array<Hash>, Integer] rows or total changes
|
327
|
+
* @overload query(transform, sql, ...)
|
328
|
+
* @param transform [Proc] transform proc
|
329
|
+
* @param sql [String] SQL statement
|
330
|
+
* @return [Array<Hash>, Integer] rows or total changes
|
252
331
|
*/
|
253
|
-
VALUE
|
254
|
-
return Database_perform_query(argc, argv, self, safe_query_hash);
|
332
|
+
VALUE Database_query(int argc, VALUE *argv, VALUE self) {
|
333
|
+
return Database_perform_query(argc, argv, self, safe_query_hash, QUERY_HASH);
|
255
334
|
}
|
256
335
|
|
257
|
-
/*
|
258
|
-
*
|
336
|
+
/* Runs a query and transforms rows through the given transform poc. Each row is
|
337
|
+
* provided to the transform proc as a list of values. If a block is given, it
|
338
|
+
* will be called for each row. Otherwise, an array containing all rows is
|
339
|
+
* returned.
|
259
340
|
*
|
260
|
-
*
|
341
|
+
* If a transform block is given, it is called for each row, with the row values
|
342
|
+
* splatted:
|
343
|
+
*
|
344
|
+
* transform = ->(a, b, c) { a * 100 + b * 10 + c }
|
345
|
+
* db.query_argv(transform, 'select a, b, c from foo where c = ?', 42)
|
346
|
+
*
|
347
|
+
* @overload query_argv(sql, ...)
|
348
|
+
* @param sql [String] SQL statement
|
349
|
+
* @return [Array<Array, any>, Integer] rows or total changes
|
350
|
+
* @overload query_argv(transform, sql, ...)
|
351
|
+
* @param transform [Proc] transform proc
|
352
|
+
* @param sql [String] SQL statement
|
353
|
+
* @return [Array<Array, any>, Integer] rows or total changes
|
354
|
+
*/
|
355
|
+
VALUE Database_query_argv(int argc, VALUE *argv, VALUE self) {
|
356
|
+
return Database_perform_query(argc, argv, self, safe_query_argv, QUERY_ARGV);
|
357
|
+
}
|
358
|
+
|
359
|
+
/* Runs a query returning rows as arrays. If a block is given, it will be called
|
261
360
|
* for each row. Otherwise, an array containing all rows is returned.
|
262
361
|
*
|
263
362
|
* Query parameters to be bound to placeholders in the query can be specified as
|
@@ -274,82 +373,95 @@ VALUE Database_query_hash(int argc, VALUE *argv, VALUE self) {
|
|
274
373
|
* db.query_ary('select * from foo where x = :bar', bar: 42)
|
275
374
|
* db.query_ary('select * from foo where x = :bar', 'bar' => 42)
|
276
375
|
* db.query_ary('select * from foo where x = :bar', ':bar' => 42)
|
376
|
+
*
|
377
|
+
* @overload query_ary(sql, ...)
|
378
|
+
* @param sql [String] SQL statement
|
379
|
+
* @return [Array<Array>, Integer] rows or total changes
|
380
|
+
* @overload query_ary(transform, sql, ...)
|
381
|
+
* @param transform [Proc] transform proc
|
382
|
+
* @param sql [String] SQL statement
|
383
|
+
* @return [Array<Array>, Integer] rows or total changes
|
277
384
|
*/
|
278
385
|
VALUE Database_query_ary(int argc, VALUE *argv, VALUE self) {
|
279
|
-
return Database_perform_query(argc, argv, self, safe_query_ary);
|
386
|
+
return Database_perform_query(argc, argv, self, safe_query_ary, QUERY_ARY);
|
280
387
|
}
|
281
388
|
|
282
|
-
/*
|
283
|
-
* db.query_single_row(sql, *parameters) -> {...}
|
284
|
-
*
|
285
|
-
* Runs a query returning a single row as a hash.
|
389
|
+
/* Runs a query returning a single row as a hash.
|
286
390
|
*
|
287
391
|
* Query parameters to be bound to placeholders in the query can be specified as
|
288
392
|
* a list of values or as a hash mapping parameter names to values. When
|
289
393
|
* parameters are given as an array, the query should specify parameters using
|
290
394
|
* `?`:
|
291
395
|
*
|
292
|
-
* db.
|
396
|
+
* db.query_single('select * from foo where x = ?', 42)
|
293
397
|
*
|
294
398
|
* Named placeholders are specified using `:`. The placeholder values are
|
295
|
-
* specified using
|
296
|
-
* keys can include or omit the `:` prefix. The following are equivalent:
|
399
|
+
* specified using keyword arguments:
|
297
400
|
*
|
298
|
-
* db.
|
299
|
-
*
|
300
|
-
*
|
401
|
+
* db.query_single('select * from foo where x = :bar', bar: 42)
|
402
|
+
*
|
403
|
+
* @overload query_single(sql, ...) -> row
|
404
|
+
* @param sql [String] SQL statement
|
405
|
+
* @return [Array, any] row
|
406
|
+
* @overload query_single(transform, sql, ...) -> row
|
407
|
+
* @param transform [Proc] transform proc
|
408
|
+
* @param sql [String] SQL statement
|
409
|
+
* @return [Array, any] row
|
301
410
|
*/
|
302
|
-
VALUE
|
303
|
-
return Database_perform_query(argc, argv, self,
|
411
|
+
VALUE Database_query_single(int argc, VALUE *argv, VALUE self) {
|
412
|
+
return Database_perform_query(argc, argv, self, safe_query_single_row_hash, QUERY_HASH);
|
304
413
|
}
|
305
414
|
|
306
|
-
/*
|
307
|
-
* db.query_single_column(sql, *parameters, &block) -> [...]
|
308
|
-
*
|
309
|
-
* Runs a query returning single column values. If a block is given, it will be called
|
310
|
-
* for each value. Otherwise, an array containing all values is returned.
|
415
|
+
/* Runs a query returning a single row as an array or a single value.
|
311
416
|
*
|
312
417
|
* Query parameters to be bound to placeholders in the query can be specified as
|
313
418
|
* a list of values or as a hash mapping parameter names to values. When
|
314
419
|
* parameters are given as an array, the query should specify parameters using
|
315
420
|
* `?`:
|
316
421
|
*
|
317
|
-
* db.
|
422
|
+
* db.query_single_argv('select * from foo where x = ?', 42)
|
318
423
|
*
|
319
424
|
* Named placeholders are specified using `:`. The placeholder values are
|
320
|
-
* specified using
|
321
|
-
*
|
322
|
-
*
|
323
|
-
*
|
324
|
-
*
|
325
|
-
*
|
425
|
+
* specified using keyword arguments:
|
426
|
+
*
|
427
|
+
* db.query_single_argv('select * from foo where x = :bar', bar: 42)
|
428
|
+
*
|
429
|
+
* @overload query_single_argv(sql, ...) -> row
|
430
|
+
* @param sql [String] SQL statement
|
431
|
+
* @return [Array, any] row
|
432
|
+
* @overload query_single_argv(transform, sql, ...) -> row
|
433
|
+
* @param transform [Proc] transform proc
|
434
|
+
* @param sql [String] SQL statement
|
435
|
+
* @return [Array, any] row
|
326
436
|
*/
|
327
|
-
VALUE
|
328
|
-
return Database_perform_query(argc, argv, self,
|
437
|
+
VALUE Database_query_single_argv(int argc, VALUE *argv, VALUE self) {
|
438
|
+
return Database_perform_query(argc, argv, self, safe_query_single_row_argv, QUERY_ARGV);
|
329
439
|
}
|
330
440
|
|
331
|
-
/*
|
332
|
-
* db.query_single_value(sql, *parameters) -> value
|
333
|
-
*
|
334
|
-
* Runs a query returning a single value from the first row.
|
441
|
+
/* Runs a query returning a single row as an array.
|
335
442
|
*
|
336
443
|
* Query parameters to be bound to placeholders in the query can be specified as
|
337
444
|
* a list of values or as a hash mapping parameter names to values. When
|
338
445
|
* parameters are given as an array, the query should specify parameters using
|
339
446
|
* `?`:
|
340
447
|
*
|
341
|
-
* db.
|
448
|
+
* db.query_single_ary('select * from foo where x = ?', 42)
|
342
449
|
*
|
343
450
|
* Named placeholders are specified using `:`. The placeholder values are
|
344
|
-
* specified using
|
345
|
-
*
|
346
|
-
*
|
347
|
-
*
|
348
|
-
*
|
349
|
-
*
|
451
|
+
* specified using keyword arguments:
|
452
|
+
*
|
453
|
+
* db.query_single_ary('select * from foo where x = :bar', bar: 42)
|
454
|
+
*
|
455
|
+
* @overload query_single_ary(sql, ...) -> row
|
456
|
+
* @param sql [String] SQL statement
|
457
|
+
* @return [Array, any] row
|
458
|
+
* @overload query_single_ary(transform, sql, ...) -> row
|
459
|
+
* @param transform [Proc] transform proc
|
460
|
+
* @param sql [String] SQL statement
|
461
|
+
* @return [Array, any] row
|
350
462
|
*/
|
351
|
-
VALUE
|
352
|
-
return Database_perform_query(argc, argv, self,
|
463
|
+
VALUE Database_query_single_ary(int argc, VALUE *argv, VALUE self) {
|
464
|
+
return Database_perform_query(argc, argv, self, safe_query_single_row_ary, QUERY_ARY);
|
353
465
|
}
|
354
466
|
|
355
467
|
/* call-seq:
|
@@ -366,21 +478,16 @@ VALUE Database_query_single_value(int argc, VALUE *argv, VALUE self) {
|
|
366
478
|
* db.execute('update foo set x = ? where y = ?', 42, 43)
|
367
479
|
*
|
368
480
|
* Named placeholders are specified using `:`. The placeholder values are
|
369
|
-
* specified using
|
370
|
-
* keys can include or omit the `:` prefix. The following are equivalent:
|
481
|
+
* specified using keyword arguments:
|
371
482
|
*
|
372
483
|
* db.execute('update foo set x = :bar', bar: 42)
|
373
|
-
* db.execute('update foo set x = :bar', 'bar' => 42)
|
374
|
-
* db.execute('update foo set x = :bar', ':bar' => 42)
|
375
484
|
*/
|
376
485
|
VALUE Database_execute(int argc, VALUE *argv, VALUE self) {
|
377
|
-
return Database_perform_query(argc, argv, self, safe_query_changes);
|
486
|
+
return Database_perform_query(argc, argv, self, safe_query_changes, QUERY_HASH);
|
378
487
|
}
|
379
488
|
|
380
489
|
/* call-seq:
|
381
|
-
* db.batch_execute(sql,
|
382
|
-
* db.batch_execute(sql, enumerable) -> changes
|
383
|
-
* db.batch_execute(sql, callable) -> changes
|
490
|
+
* db.batch_execute(sql, params_source) -> changes
|
384
491
|
*
|
385
492
|
* Executes the given query for each list of parameters in the paramter source.
|
386
493
|
* If an enumerable is given, it is iterated and each of its values is used as
|
@@ -413,19 +520,18 @@ VALUE Database_batch_execute(VALUE self, VALUE sql, VALUE parameters) {
|
|
413
520
|
|
414
521
|
if (RSTRING_LEN(sql) == 0) return Qnil;
|
415
522
|
|
416
|
-
prepare_single_stmt(db->sqlite3_db, &stmt, sql);
|
417
|
-
query_ctx ctx = QUERY_CTX(
|
523
|
+
prepare_single_stmt(DB_GVL_MODE(db), db->sqlite3_db, &stmt, sql);
|
524
|
+
query_ctx ctx = QUERY_CTX(
|
525
|
+
self, sql, db, stmt, parameters,
|
526
|
+
Qnil, QUERY_HASH, ROW_MULTI, ALL_ROWS
|
527
|
+
);
|
418
528
|
|
419
529
|
return rb_ensure(SAFE(safe_batch_execute), (VALUE)&ctx, SAFE(cleanup_stmt), (VALUE)&ctx);
|
420
530
|
}
|
421
531
|
|
422
532
|
/* call-seq:
|
423
|
-
* db.batch_query(sql,
|
424
|
-
* db.batch_query(sql,
|
425
|
-
* db.batch_query(sql, callable) -> rows
|
426
|
-
* db.batch_query(sql, params_array) { |rows| ... } -> changes
|
427
|
-
* db.batch_query(sql, enumerable) { |rows| ... } -> changes
|
428
|
-
* db.batch_query(sql, callable) { |rows| ... } -> changes
|
533
|
+
* db.batch_query(sql, params_source) -> rows
|
534
|
+
* db.batch_query(sql, params_source) { |rows| ... } -> changes
|
429
535
|
*
|
430
536
|
* Executes the given query for each list of parameters in the given paramter
|
431
537
|
* source. If a block is given, it is called with the resulting rows for each
|
@@ -448,19 +554,18 @@ VALUE Database_batch_query(VALUE self, VALUE sql, VALUE parameters) {
|
|
448
554
|
Database_t *db = self_to_open_database(self);
|
449
555
|
sqlite3_stmt *stmt;
|
450
556
|
|
451
|
-
prepare_single_stmt(db->sqlite3_db, &stmt, sql);
|
452
|
-
query_ctx ctx = QUERY_CTX(
|
557
|
+
prepare_single_stmt(DB_GVL_MODE(db), db->sqlite3_db, &stmt, sql);
|
558
|
+
query_ctx ctx = QUERY_CTX(
|
559
|
+
self, sql, db, stmt, parameters,
|
560
|
+
Qnil, QUERY_HASH, ROW_MULTI, ALL_ROWS
|
561
|
+
);
|
453
562
|
|
454
563
|
return rb_ensure(SAFE(safe_batch_query), (VALUE)&ctx, SAFE(cleanup_stmt), (VALUE)&ctx);
|
455
564
|
}
|
456
565
|
|
457
566
|
/* call-seq:
|
458
|
-
* db.batch_query_ary(sql,
|
459
|
-
* db.batch_query_ary(sql,
|
460
|
-
* db.batch_query_ary(sql, callable) -> rows
|
461
|
-
* db.batch_query_ary(sql, params_array) { |rows| ... } -> changes
|
462
|
-
* db.batch_query_ary(sql, enumerable) { |rows| ... } -> changes
|
463
|
-
* db.batch_query_ary(sql, callable) { |rows| ... } -> changes
|
567
|
+
* db.batch_query_ary(sql, params_source) -> rows
|
568
|
+
* db.batch_query_ary(sql, params_source) { |rows| ... } -> changes
|
464
569
|
*
|
465
570
|
* Executes the given query for each list of parameters in the given paramter
|
466
571
|
* source. If a block is given, it is called with the resulting rows for each
|
@@ -483,19 +588,18 @@ VALUE Database_batch_query_ary(VALUE self, VALUE sql, VALUE parameters) {
|
|
483
588
|
Database_t *db = self_to_open_database(self);
|
484
589
|
sqlite3_stmt *stmt;
|
485
590
|
|
486
|
-
prepare_single_stmt(db->sqlite3_db, &stmt, sql);
|
487
|
-
query_ctx ctx = QUERY_CTX(
|
591
|
+
prepare_single_stmt(DB_GVL_MODE(db), db->sqlite3_db, &stmt, sql);
|
592
|
+
query_ctx ctx = QUERY_CTX(
|
593
|
+
self, sql, db, stmt, parameters,
|
594
|
+
Qnil, QUERY_ARY, ROW_MULTI, ALL_ROWS
|
595
|
+
);
|
488
596
|
|
489
597
|
return rb_ensure(SAFE(safe_batch_query_ary), (VALUE)&ctx, SAFE(cleanup_stmt), (VALUE)&ctx);
|
490
598
|
}
|
491
599
|
|
492
600
|
/* call-seq:
|
493
|
-
* db.
|
494
|
-
* db.
|
495
|
-
* db.batch_query_single_column(sql, callable) -> rows
|
496
|
-
* db.batch_query_single_column(sql, params_array) { |rows| ... } -> changes
|
497
|
-
* db.batch_query_single_column(sql, enumerable) { |rows| ... } -> changes
|
498
|
-
* db.batch_query_single_column(sql, callable) { |rows| ... } -> changes
|
601
|
+
* db.batch_query_argv(sql, params_source) -> rows
|
602
|
+
* db.batch_query_argv(sql, params_source) { |rows| ... } -> changes
|
499
603
|
*
|
500
604
|
* Executes the given query for each list of parameters in the given paramter
|
501
605
|
* source. If a block is given, it is called with the resulting rows for each
|
@@ -507,36 +611,37 @@ VALUE Database_batch_query_ary(VALUE self, VALUE sql, VALUE parameters) {
|
|
507
611
|
* [1, 2],
|
508
612
|
* [3, 4]
|
509
613
|
* ]
|
510
|
-
* db.
|
614
|
+
* db.batch_query_argv('insert into foo values (?, ?) returning baz', records)
|
511
615
|
* #=> [2, 4]
|
512
616
|
* *
|
513
617
|
* @param sql [String] query SQL
|
514
618
|
* @param parameters [Array<Array, Hash>, Enumerable, Enumerator, Callable] parameters to run query with
|
515
619
|
* @return [Array<any>, Integer] Total number of changes effected
|
516
620
|
*/
|
517
|
-
VALUE
|
621
|
+
VALUE Database_batch_query_argv(VALUE self, VALUE sql, VALUE parameters) {
|
518
622
|
Database_t *db = self_to_open_database(self);
|
519
623
|
sqlite3_stmt *stmt;
|
520
624
|
|
521
|
-
prepare_single_stmt(db->sqlite3_db, &stmt, sql);
|
522
|
-
query_ctx ctx = QUERY_CTX(
|
625
|
+
prepare_single_stmt(DB_GVL_MODE(db), db->sqlite3_db, &stmt, sql);
|
626
|
+
query_ctx ctx = QUERY_CTX(
|
627
|
+
self, sql, db, stmt, parameters,
|
628
|
+
Qnil, QUERY_ARGV, ROW_MULTI, ALL_ROWS
|
629
|
+
);
|
523
630
|
|
524
|
-
return rb_ensure(SAFE(
|
631
|
+
return rb_ensure(SAFE(safe_batch_query_argv), (VALUE)&ctx, SAFE(cleanup_stmt), (VALUE)&ctx);
|
525
632
|
}
|
526
633
|
|
527
|
-
/*
|
528
|
-
*
|
529
|
-
*
|
530
|
-
* Returns the column names for the given query, without running it.
|
634
|
+
/* Returns the column names for the given query, without running it.
|
635
|
+
*
|
636
|
+
* @return [Array<String>] column names
|
531
637
|
*/
|
532
638
|
VALUE Database_columns(VALUE self, VALUE sql) {
|
533
|
-
return Database_perform_query(1, &sql, self, safe_query_columns);
|
639
|
+
return Database_perform_query(1, &sql, self, safe_query_columns, QUERY_HASH);
|
534
640
|
}
|
535
641
|
|
536
|
-
/*
|
537
|
-
*
|
538
|
-
*
|
539
|
-
* Returns the rowid of the last inserted row.
|
642
|
+
/* Returns the rowid of the last inserted row.
|
643
|
+
*
|
644
|
+
* @return [Integer] last rowid
|
540
645
|
*/
|
541
646
|
VALUE Database_last_insert_rowid(VALUE self) {
|
542
647
|
Database_t *db = self_to_open_database(self);
|
@@ -544,10 +649,9 @@ VALUE Database_last_insert_rowid(VALUE self) {
|
|
544
649
|
return INT2FIX(sqlite3_last_insert_rowid(db->sqlite3_db));
|
545
650
|
}
|
546
651
|
|
547
|
-
/*
|
548
|
-
*
|
549
|
-
*
|
550
|
-
* Returns the number of changes made to the database by the last operation.
|
652
|
+
/* Returns the number of changes made to the database by the last operation.
|
653
|
+
*
|
654
|
+
* @return [Integer] number of changes
|
551
655
|
*/
|
552
656
|
VALUE Database_changes(VALUE self) {
|
553
657
|
Database_t *db = self_to_open_database(self);
|
@@ -555,10 +659,14 @@ VALUE Database_changes(VALUE self) {
|
|
555
659
|
return INT2FIX(sqlite3_changes(db->sqlite3_db));
|
556
660
|
}
|
557
661
|
|
558
|
-
/*
|
559
|
-
*
|
560
|
-
* Returns the database filename. If db_name is given, returns the filename for
|
662
|
+
/* Returns the database filename. If db_name is given, returns the filename for
|
561
663
|
* the respective attached database.
|
664
|
+
*
|
665
|
+
* @overload filename()
|
666
|
+
* @return [String] database filename
|
667
|
+
* @overload filename(db_name)
|
668
|
+
* @param db_name [String] attached database name
|
669
|
+
* @return [String] database filename
|
562
670
|
*/
|
563
671
|
VALUE Database_filename(int argc, VALUE *argv, VALUE self) {
|
564
672
|
const char *db_name;
|
@@ -571,10 +679,9 @@ VALUE Database_filename(int argc, VALUE *argv, VALUE self) {
|
|
571
679
|
return filename ? rb_str_new_cstr(filename) : Qnil;
|
572
680
|
}
|
573
681
|
|
574
|
-
/*
|
575
|
-
*
|
576
|
-
*
|
577
|
-
* Returns true if a transaction is currently in progress.
|
682
|
+
/* Returns true if a transaction is currently in progress.
|
683
|
+
*
|
684
|
+
* @return [bool] is transaction in progress
|
578
685
|
*/
|
579
686
|
VALUE Database_transaction_active_p(VALUE self) {
|
580
687
|
Database_t *db = self_to_open_database(self);
|
@@ -583,10 +690,10 @@ VALUE Database_transaction_active_p(VALUE self) {
|
|
583
690
|
}
|
584
691
|
|
585
692
|
#ifdef HAVE_SQLITE3_LOAD_EXTENSION
|
586
|
-
/*
|
587
|
-
*
|
588
|
-
*
|
589
|
-
*
|
693
|
+
/* Loads an extension with the given path.
|
694
|
+
*
|
695
|
+
* @param path [String] extension file path
|
696
|
+
* @return [Extralite::Database] database
|
590
697
|
*/
|
591
698
|
VALUE Database_load_extension(VALUE self, VALUE path) {
|
592
699
|
Database_t *db = self_to_open_database(self);
|
@@ -603,30 +710,73 @@ VALUE Database_load_extension(VALUE self, VALUE path) {
|
|
603
710
|
}
|
604
711
|
#endif
|
605
712
|
|
606
|
-
|
607
|
-
* db.prepare(sql) -> Extralite::Query
|
608
|
-
* db.prepare(sql, ...) -> Extralite::Query
|
609
|
-
*
|
610
|
-
* Creates a prepared statement with the given SQL query. If query parameters
|
611
|
-
* are given, they are bound to the query.
|
612
|
-
*/
|
613
|
-
VALUE Database_prepare(int argc, VALUE *argv, VALUE self) {
|
713
|
+
static inline VALUE Database_prepare(int argc, VALUE *argv, VALUE self, VALUE mode) {
|
614
714
|
rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
|
615
|
-
|
715
|
+
|
716
|
+
VALUE args[] = { self, argv[0], mode};
|
717
|
+
VALUE query = rb_funcall_passing_block(cQuery, ID_new, 3, args);
|
616
718
|
if (argc > 1) rb_funcallv(query, ID_bind, argc - 1, argv + 1);
|
617
719
|
RB_GC_GUARD(query);
|
618
720
|
return query;
|
619
721
|
}
|
620
722
|
|
621
723
|
/* call-seq:
|
622
|
-
* db.
|
623
|
-
*
|
624
|
-
*
|
724
|
+
* db.prepare(sql) -> Extralite::Query
|
725
|
+
* db.prepare(sql, ...) -> Extralite::Query
|
726
|
+
* db.prepare(sql, ...) { ... } -> Extralite::Query
|
727
|
+
*
|
728
|
+
* Creates a prepared query with the given SQL query in hash mode. If query
|
729
|
+
* parameters are given, they are bound to the query. If a block is given, it is
|
730
|
+
* used as a transform proc.
|
731
|
+
*
|
732
|
+
* @param sql [String] SQL statement
|
733
|
+
* @return [Extralite::Query] prepared query
|
734
|
+
*/
|
735
|
+
VALUE Database_prepare_hash(int argc, VALUE *argv, VALUE self) {
|
736
|
+
return Database_prepare(argc, argv, self, SYM_hash);
|
737
|
+
}
|
738
|
+
|
739
|
+
/* call-seq:
|
740
|
+
* db.prepare_argv(sql) -> Extralite::Query
|
741
|
+
* db.prepare_argv(sql, ...) -> Extralite::Query
|
742
|
+
* db.prepare_argv(sql, ...) { ... } -> Extralite::Query
|
743
|
+
*
|
744
|
+
* Creates a prepared query with the given SQL query in argv mode. If query
|
745
|
+
* parameters are given, they are bound to the query. If a block is given, it is
|
746
|
+
* used as a transform proc.
|
747
|
+
*
|
748
|
+
* @param sql [String] SQL statement
|
749
|
+
* @return [Extralite::Query] prepared query
|
750
|
+
*/
|
751
|
+
VALUE Database_prepare_argv(int argc, VALUE *argv, VALUE self) {
|
752
|
+
return Database_prepare(argc, argv, self, SYM_argv);
|
753
|
+
}
|
754
|
+
|
755
|
+
/* call-seq:
|
756
|
+
* db.prepare_ary(sql) -> Extralite::Query
|
757
|
+
* db.prepare_ary(sql, ...) -> Extralite::Query
|
758
|
+
* db.prepare_ary(sql, ...) { ... } -> Extralite::Query
|
759
|
+
*
|
760
|
+
* Creates a prepared query with the given SQL query in ary mode. If query
|
761
|
+
* parameters are given, they are bound to the query. If a block is given, it is
|
762
|
+
* used as a transform proc.
|
763
|
+
*
|
764
|
+
* @param sql [String] SQL statement
|
765
|
+
* @return [Extralite::Query] prepared query
|
766
|
+
*/
|
767
|
+
VALUE Database_prepare_ary(int argc, VALUE *argv, VALUE self) {
|
768
|
+
return Database_prepare(argc, argv, self, SYM_ary);
|
769
|
+
}
|
770
|
+
|
771
|
+
/* Interrupts a long running query. This method is to be called from a different
|
625
772
|
* thread than the one running the query. Upon calling `#interrupt` the running
|
626
773
|
* query will stop and raise an `Extralite::InterruptError` exception.
|
627
774
|
*
|
628
775
|
* It is not safe to call `#interrupt` on a database that is about to be closed.
|
629
|
-
* For more information, consult the [sqlite3 API
|
776
|
+
* For more information, consult the [sqlite3 API
|
777
|
+
* docs](https://sqlite.org/c3ref/interrupt.html).
|
778
|
+
*
|
779
|
+
* @return [Extralite::Database] database
|
630
780
|
*/
|
631
781
|
VALUE Database_interrupt(VALUE self) {
|
632
782
|
Database_t *db = self_to_open_database(self);
|
@@ -700,16 +850,19 @@ VALUE backup_cleanup(VALUE ptr) {
|
|
700
850
|
return Qnil;
|
701
851
|
}
|
702
852
|
|
703
|
-
/*
|
704
|
-
* db.backup(dest) -> db
|
705
|
-
* db.backup(dest) { |remaining, total| } -> db
|
706
|
-
*
|
707
|
-
* Creates a backup of the database to the given destination, which can be
|
853
|
+
/* Creates a backup of the database to the given destination, which can be
|
708
854
|
* either a filename or a database instance. In order to monitor the backup
|
709
855
|
* progress you can pass a block that will be called periodically by the backup
|
710
856
|
* method with two arguments: the remaining page count, and the total page
|
711
857
|
* count, which can be used to display the progress to the user or to collect
|
712
858
|
* statistics.
|
859
|
+
*
|
860
|
+
* db_src.backup(db_dest) do |remaining, total|
|
861
|
+
* puts "Backing up #{remaining}/#{total}"
|
862
|
+
* end
|
863
|
+
*
|
864
|
+
* @param dest [String, Extralite::Database] backup destination
|
865
|
+
* @return [Extralite::Database] source database
|
713
866
|
*/
|
714
867
|
VALUE Database_backup(int argc, VALUE *argv, VALUE self) {
|
715
868
|
VALUE dst;
|
@@ -755,12 +908,17 @@ VALUE Database_backup(int argc, VALUE *argv, VALUE self) {
|
|
755
908
|
return self;
|
756
909
|
}
|
757
910
|
|
758
|
-
/*
|
759
|
-
* Extralite.runtime_status(op[, reset]) -> [value, highwatermark]
|
760
|
-
*
|
761
|
-
* Returns runtime status values for the given op as an array containing the
|
911
|
+
/* Returns runtime status values for the given op as an array containing the
|
762
912
|
* current value and the high water mark value. To reset the high water mark,
|
763
913
|
* pass true as reset.
|
914
|
+
*
|
915
|
+
* @overload runtime_status(op)
|
916
|
+
* @param op [Integer] op
|
917
|
+
* @return [Array<Integer>] array containing the value and high water mark
|
918
|
+
* @overload runtime_status(op, reset)
|
919
|
+
* @param op [Integer] op
|
920
|
+
* @param reset [Integer, bool] reset flag
|
921
|
+
* @return [Array<Integer>] array containing the value and high water mark
|
764
922
|
*/
|
765
923
|
VALUE Extralite_runtime_status(int argc, VALUE* argv, VALUE self) {
|
766
924
|
VALUE op, reset;
|
@@ -774,12 +932,17 @@ VALUE Extralite_runtime_status(int argc, VALUE* argv, VALUE self) {
|
|
774
932
|
return rb_ary_new3(2, LONG2FIX(cur), LONG2FIX(hwm));
|
775
933
|
}
|
776
934
|
|
777
|
-
/*
|
778
|
-
* db.status(op[, reset]) -> [value, highwatermark]
|
779
|
-
*
|
780
|
-
* Returns database status values for the given op as an array containing the
|
935
|
+
/* Returns database status values for the given op as an array containing the
|
781
936
|
* current value and the high water mark value. To reset the high water mark,
|
782
937
|
* pass true as reset.
|
938
|
+
*
|
939
|
+
* @overload status(op)
|
940
|
+
* @param op [Integer] op
|
941
|
+
* @return [Array<Integer>] array containing the value and high water mark
|
942
|
+
* @overload status(op, reset)
|
943
|
+
* @param op [Integer] op
|
944
|
+
* @param reset [Integer, bool] reset flag
|
945
|
+
* @return [Array<Integer>] array containing the value and high water mark
|
783
946
|
*/
|
784
947
|
VALUE Database_status(int argc, VALUE *argv, VALUE self) {
|
785
948
|
VALUE op, reset;
|
@@ -795,12 +958,16 @@ VALUE Database_status(int argc, VALUE *argv, VALUE self) {
|
|
795
958
|
return rb_ary_new3(2, INT2NUM(cur), INT2NUM(hwm));
|
796
959
|
}
|
797
960
|
|
798
|
-
/*
|
799
|
-
* db.limit(category) -> value
|
800
|
-
* db.limit(category, new_value) -> prev_value
|
801
|
-
*
|
802
|
-
* Returns the current limit for the given category. If a new value is given,
|
961
|
+
/* Returns the current limit for the given category. If a new value is given,
|
803
962
|
* sets the limit to the new value and returns the previous value.
|
963
|
+
*
|
964
|
+
* @overload limit(category)
|
965
|
+
* @param category [Integer] category
|
966
|
+
* @return [Integer] limit value
|
967
|
+
* @overload limit(category, new_value)
|
968
|
+
* @param category [Integer] category
|
969
|
+
* @param new_value [Integer] new value
|
970
|
+
* @return [Integer] old value
|
804
971
|
*/
|
805
972
|
VALUE Database_limit(int argc, VALUE *argv, VALUE self) {
|
806
973
|
VALUE category, new_value;
|
@@ -816,12 +983,18 @@ VALUE Database_limit(int argc, VALUE *argv, VALUE self) {
|
|
816
983
|
return INT2NUM(value);
|
817
984
|
}
|
818
985
|
|
819
|
-
/*
|
820
|
-
*
|
821
|
-
*
|
822
|
-
*
|
823
|
-
*
|
824
|
-
*
|
986
|
+
/* Sets the busy timeout for the database, in seconds or fractions thereof. To
|
987
|
+
* disable the busy timeout, set it to 0 or nil. When the busy timeout is set to
|
988
|
+
* a value larger than zero, running a query when the database is locked will
|
989
|
+
* cause the program to wait for the database to become available. If the
|
990
|
+
* database is still locked when the timeout period has elapsed, the query will
|
991
|
+
* fail with a `Extralite::BusyError` exception.
|
992
|
+
*
|
993
|
+
* Setting the busy timeout allows other threads to run while waiting for the
|
994
|
+
* database to become available. See also `#on_progress`.
|
995
|
+
*
|
996
|
+
* @param sec [Number, nil] timeout value
|
997
|
+
* @return [Extralite::Database] database
|
825
998
|
*/
|
826
999
|
VALUE Database_busy_timeout_set(VALUE self, VALUE sec) {
|
827
1000
|
Database_t *db = self_to_open_database(self);
|
@@ -833,10 +1006,9 @@ VALUE Database_busy_timeout_set(VALUE self, VALUE sec) {
|
|
833
1006
|
return self;
|
834
1007
|
}
|
835
1008
|
|
836
|
-
/*
|
837
|
-
*
|
838
|
-
*
|
839
|
-
* Returns the total number of changes made to the database since opening it.
|
1009
|
+
/* Returns the total number of changes made to the database since opening it.
|
1010
|
+
*
|
1011
|
+
* @return [Integer] total changes
|
840
1012
|
*/
|
841
1013
|
VALUE Database_total_changes(VALUE self) {
|
842
1014
|
Database_t *db = self_to_open_database(self);
|
@@ -845,24 +1017,277 @@ VALUE Database_total_changes(VALUE self) {
|
|
845
1017
|
return INT2NUM(value);
|
846
1018
|
}
|
847
1019
|
|
848
|
-
/*
|
849
|
-
*
|
850
|
-
*
|
851
|
-
*
|
852
|
-
* Installs or removes a block that will be invoked for every SQL statement
|
853
|
-
* executed.
|
1020
|
+
/* Installs or removes a block that will be invoked for every SQL statement
|
1021
|
+
* executed. To stop tracing, call `#trace` without a block.
|
1022
|
+
*
|
1023
|
+
* @return [Extralite::Database] database
|
854
1024
|
*/
|
855
1025
|
VALUE Database_trace(VALUE self) {
|
856
1026
|
Database_t *db = self_to_open_database(self);
|
857
1027
|
|
858
|
-
RB_OBJ_WRITE(self, &db->
|
1028
|
+
RB_OBJ_WRITE(self, &db->trace_proc, rb_block_given_p() ? rb_block_proc() : Qnil);
|
859
1029
|
return self;
|
860
1030
|
}
|
861
1031
|
|
862
|
-
|
863
|
-
|
864
|
-
*
|
865
|
-
*
|
1032
|
+
#ifdef EXTRALITE_ENABLE_CHANGESET
|
1033
|
+
/* Tracks changes to the database and returns a changeset. The changeset can
|
1034
|
+
* then be used to store the changes to a file, apply them to another database,
|
1035
|
+
* or undo the changes. The given table names specify which tables should be
|
1036
|
+
* tracked for changes. Passing a value of nil causes all tables to be tracked.
|
1037
|
+
*
|
1038
|
+
* changeset = db.track_changes(:foo, :bar) do
|
1039
|
+
* perform_a_bunch_of_queries
|
1040
|
+
* end
|
1041
|
+
*
|
1042
|
+
* File.open('my.changes', 'w+') { |f| f << changeset.to_blob }
|
1043
|
+
*
|
1044
|
+
* @param table [String, Symbol] table to track
|
1045
|
+
* @return [Extralite::Changeset] changeset
|
1046
|
+
*/
|
1047
|
+
VALUE Database_track_changes(int argc, VALUE *argv, VALUE self) {
|
1048
|
+
self_to_open_database(self);
|
1049
|
+
|
1050
|
+
VALUE changeset = rb_funcall(cChangeset, ID_new, 0);
|
1051
|
+
VALUE tables = rb_ary_new_from_values(argc, argv);
|
1052
|
+
|
1053
|
+
rb_funcall(changeset, ID_track, 2, self, tables);
|
1054
|
+
|
1055
|
+
RB_GC_GUARD(changeset);
|
1056
|
+
RB_GC_GUARD(tables);
|
1057
|
+
return changeset;
|
1058
|
+
}
|
1059
|
+
#endif
|
1060
|
+
|
1061
|
+
void Database_reset_progress_handler(VALUE self, Database_t *db) {
|
1062
|
+
db->progress_handler.mode = PROGRESS_NONE;
|
1063
|
+
RB_OBJ_WRITE(self, &db->progress_handler.proc, Qnil);
|
1064
|
+
sqlite3_progress_handler(db->sqlite3_db, 0, NULL, NULL);
|
1065
|
+
sqlite3_busy_handler(db->sqlite3_db, NULL, NULL);
|
1066
|
+
}
|
1067
|
+
|
1068
|
+
static inline enum progress_handler_mode symbol_to_progress_mode(VALUE mode) {
|
1069
|
+
if (mode == SYM_at_least_once) return PROGRESS_AT_LEAST_ONCE;
|
1070
|
+
if (mode == SYM_once) return PROGRESS_ONCE;
|
1071
|
+
if (mode == SYM_normal) return PROGRESS_NORMAL;
|
1072
|
+
if (mode == SYM_none) return PROGRESS_NONE;
|
1073
|
+
rb_raise(eArgumentError, "Invalid progress handler mode");
|
1074
|
+
}
|
1075
|
+
|
1076
|
+
inline void Database_issue_query(Database_t *db, VALUE sql) {
|
1077
|
+
if (db->trace_proc != Qnil) rb_funcall(db->trace_proc, ID_call, 1, sql);
|
1078
|
+
switch (db->progress_handler.mode) {
|
1079
|
+
case PROGRESS_AT_LEAST_ONCE:
|
1080
|
+
case PROGRESS_ONCE:
|
1081
|
+
rb_funcall(db->progress_handler.proc, ID_call, 0);
|
1082
|
+
default:
|
1083
|
+
; // do nothing
|
1084
|
+
|
1085
|
+
}
|
1086
|
+
}
|
1087
|
+
|
1088
|
+
struct progress_handler parse_progress_handler_opts(VALUE opts) {
|
1089
|
+
static ID kw_ids[3];
|
1090
|
+
VALUE kw_args[3];
|
1091
|
+
struct progress_handler prog = {
|
1092
|
+
.mode = rb_block_given_p() ? PROGRESS_NORMAL : PROGRESS_NONE,
|
1093
|
+
.proc = rb_block_given_p() ? rb_block_proc() : Qnil,
|
1094
|
+
.period = DEFAULT_PROGRESS_HANDLER_PERIOD,
|
1095
|
+
.tick = DEFAULT_PROGRESS_HANDLER_TICK
|
1096
|
+
};
|
1097
|
+
|
1098
|
+
if (!NIL_P(opts)) {
|
1099
|
+
if (!kw_ids[0]) {
|
1100
|
+
CONST_ID(kw_ids[0], "period");
|
1101
|
+
CONST_ID(kw_ids[1], "tick");
|
1102
|
+
CONST_ID(kw_ids[2], "mode");
|
1103
|
+
}
|
1104
|
+
|
1105
|
+
rb_get_kwargs(opts, kw_ids, 0, 3, kw_args);
|
1106
|
+
if (kw_args[0] != Qundef) { prog.period = NUM2INT(kw_args[0]); }
|
1107
|
+
if (kw_args[1] != Qundef) { prog.tick = NUM2INT(kw_args[1]); }
|
1108
|
+
if (kw_args[2] != Qundef) { prog.mode = symbol_to_progress_mode(kw_args[2]); }
|
1109
|
+
if (prog.tick > prog.period) prog.tick = prog.period;
|
1110
|
+
}
|
1111
|
+
if (NIL_P(prog.proc) || (prog.period <= 0)) prog.mode = PROGRESS_NONE;
|
1112
|
+
if (prog.mode == PROGRESS_NONE) prog.proc = Qnil;
|
1113
|
+
|
1114
|
+
return prog;
|
1115
|
+
}
|
1116
|
+
|
1117
|
+
/* Installs or removes a progress handler that will be executed periodically
|
1118
|
+
* while a query is running. This method can be used to support switching
|
1119
|
+
* between fibers and threads or implementing timeouts for running queries.
|
1120
|
+
*
|
1121
|
+
* The `period` parameter specifies the approximate number of SQLite
|
1122
|
+
* virtual machine instructions that are evaluated between successive
|
1123
|
+
* invocations of the progress handler. A period of less than 1 removes the
|
1124
|
+
* progress handler. The default period value is 1000.
|
1125
|
+
*
|
1126
|
+
* The optional `tick` parameter specifies the granularity of how often the
|
1127
|
+
* progress handler is called. The default tick value is 10, which means that
|
1128
|
+
* Extralite's underlying progress callback will be called every 10 SQLite VM
|
1129
|
+
* instructions. The given progress proc, however, will be only called every
|
1130
|
+
* `period` (cumulative) VM instructions. This allows the progress handler to
|
1131
|
+
* work correctly also when running simple queries that don't include many
|
1132
|
+
* VM instructions. If the `tick` value is greater than the period value it is
|
1133
|
+
* automatically capped to the period value.
|
1134
|
+
*
|
1135
|
+
* The `mode` parameter controls the progress handler mode, which is one of the
|
1136
|
+
* following:
|
1137
|
+
*
|
1138
|
+
* - `:normal` (default): the progress handler proc is invoked on query
|
1139
|
+
* progress.
|
1140
|
+
* - `:once`: the progress handler proc is invoked only once, when preparing the
|
1141
|
+
* query.
|
1142
|
+
* - `:at_least_once`: the progress handler proc is invoked when prearing the
|
1143
|
+
* query, and on query progress.
|
1144
|
+
*
|
1145
|
+
* The progress handler is called also when the database is busy. This lets the
|
1146
|
+
* application perform work while waiting for the database to become unlocked,
|
1147
|
+
* or implement a timeout. Note that setting the database's busy_timeout _after_
|
1148
|
+
* setting a progress handler may lead to undefined behaviour in a concurrent
|
1149
|
+
* application. When busy, the progress handler proc is passed `true` as the
|
1150
|
+
* first argument.
|
1151
|
+
*
|
1152
|
+
* When the progress handler is set, the gvl release threshold value is set to
|
1153
|
+
* -1, which means that the GVL will not be released at all when preparing or
|
1154
|
+
* running queries. It is the application's responsibility to let other threads
|
1155
|
+
* or fibers run by calling e.g. Thread.pass:
|
1156
|
+
*
|
1157
|
+
* db.on_progress do
|
1158
|
+
* do_something_interesting
|
1159
|
+
* Thread.pass # let other threads run
|
1160
|
+
* end
|
1161
|
+
*
|
1162
|
+
* Note that the progress handler is set globally for the database and that
|
1163
|
+
* Extralite does provide any hooks for telling which queries are currently
|
1164
|
+
* running or at what time they were started. This means that you'll need to
|
1165
|
+
* wrap the stock #query_xxx and #execute methods with your own code that
|
1166
|
+
* calculates timeouts, for example:
|
1167
|
+
*
|
1168
|
+
* def setup_progress_handler
|
1169
|
+
* @db.on_progress do
|
1170
|
+
* raise TimeoutError if Time.now - @t0 >= @timeout
|
1171
|
+
* Thread.pass
|
1172
|
+
* end
|
1173
|
+
* end
|
1174
|
+
*
|
1175
|
+
* def query(sql, *)
|
1176
|
+
* @t0 = Time.now
|
1177
|
+
* @db.query(sql, *)
|
1178
|
+
* end
|
1179
|
+
*
|
1180
|
+
* If the gvl release threshold is set to a value equal to or larger than 0
|
1181
|
+
* after setting the progress handler, the progress handler will be reset.
|
1182
|
+
*
|
1183
|
+
* @param period [Integer] progress handler period
|
1184
|
+
* @param [Hash] opts progress options
|
1185
|
+
* @option opts [Integer] :period period value (`1000` by default)
|
1186
|
+
* @option opts [Integer] :tick tick value (`10` by default)
|
1187
|
+
* @option opts [Symbol] :mode progress handler mode (`:normal` by default)
|
1188
|
+
* @returns [Extralite::Database] database
|
1189
|
+
*/
|
1190
|
+
VALUE Database_on_progress(int argc, VALUE *argv, VALUE self) {
|
1191
|
+
Database_t *db = self_to_open_database(self);
|
1192
|
+
VALUE opts;
|
1193
|
+
struct progress_handler prog;
|
1194
|
+
|
1195
|
+
rb_scan_args(argc, argv, "00:", &opts);
|
1196
|
+
prog = parse_progress_handler_opts(opts);
|
1197
|
+
|
1198
|
+
if (prog.mode == PROGRESS_NONE) {
|
1199
|
+
Database_reset_progress_handler(self, db);
|
1200
|
+
db->gvl_release_threshold = DEFAULT_GVL_RELEASE_THRESHOLD;
|
1201
|
+
return self;
|
1202
|
+
}
|
1203
|
+
|
1204
|
+
db->gvl_release_threshold = -1;
|
1205
|
+
db->progress_handler.mode = prog.mode;
|
1206
|
+
RB_OBJ_WRITE(self, &db->progress_handler.proc, prog.proc);
|
1207
|
+
db->progress_handler.period = prog.period;
|
1208
|
+
db->progress_handler.tick = prog.tick;
|
1209
|
+
db->progress_handler.tick_count = 0;
|
1210
|
+
db->progress_handler.call_count = 0;
|
1211
|
+
|
1212
|
+
// The PROGRESS_ONCE mode works by invoking the progress handler proc exactly
|
1213
|
+
// once, before iterating over the result set, so in that mode we don't
|
1214
|
+
// actually need to set the progress handler at the sqlite level.
|
1215
|
+
if (prog.mode != PROGRESS_ONCE)
|
1216
|
+
sqlite3_progress_handler(db->sqlite3_db, prog.tick, &Database_progress_handler, db);
|
1217
|
+
if (prog.mode != PROGRESS_NONE)
|
1218
|
+
sqlite3_busy_handler(db->sqlite3_db, &Database_busy_handler, db);
|
1219
|
+
|
1220
|
+
return self;
|
1221
|
+
}
|
1222
|
+
|
1223
|
+
/* Installs or removes a global progress handler that will be executed
|
1224
|
+
* periodically while a query is running. This method can be used to support
|
1225
|
+
* switching between fibers and threads or implementing timeouts for running
|
1226
|
+
* queries.
|
1227
|
+
*
|
1228
|
+
* This method sets the progress handler settings and behaviour for all
|
1229
|
+
* subsequently created `Database` instances. Calling this method will have no
|
1230
|
+
* effect on already existing `Database` instances
|
1231
|
+
*
|
1232
|
+
* The `period` parameter specifies the approximate number of SQLite
|
1233
|
+
* virtual machine instructions that are evaluated between successive
|
1234
|
+
* invocations of the progress handler. A period of less than 1 removes the
|
1235
|
+
* progress handler. The default period value is 1000.
|
1236
|
+
*
|
1237
|
+
* The optional `tick` parameter specifies the granularity of how often the
|
1238
|
+
* progress handler is called. The default tick value is 10, which means that
|
1239
|
+
* Extralite's underlying progress callback will be called every 10 SQLite VM
|
1240
|
+
* instructions. The given progress proc, however, will be only called every
|
1241
|
+
* `period` (cumulative) VM instructions. This allows the progress handler to
|
1242
|
+
* work correctly also when running simple queries that don't include many
|
1243
|
+
* VM instructions. If the `tick` value is greater than the period value it is
|
1244
|
+
* automatically capped to the period value.
|
1245
|
+
*
|
1246
|
+
* The `mode` parameter controls the progress handler mode, which is one of the
|
1247
|
+
* following:
|
1248
|
+
*
|
1249
|
+
* - `:normal` (default): the progress handler proc is invoked on query
|
1250
|
+
* progress.
|
1251
|
+
* - `:once`: the progress handler proc is invoked only once, when preparing the
|
1252
|
+
* query.
|
1253
|
+
* - `:at_least_once`: the progress handler proc is invoked when prearing the
|
1254
|
+
* query, and on query progress.
|
1255
|
+
*
|
1256
|
+
* The progress handler is called also when the database is busy. This lets the
|
1257
|
+
* application perform work while waiting for the database to become unlocked,
|
1258
|
+
* or implement a timeout. Note that setting the database's busy_timeout _after_
|
1259
|
+
* setting a progress handler may lead to undefined behaviour in a concurrent
|
1260
|
+
* application. When busy, the progress handler proc is passed `true` as the
|
1261
|
+
* first argument.
|
1262
|
+
*
|
1263
|
+
* When the progress handler is set, the gvl release threshold value is set to
|
1264
|
+
* -1, which means that the GVL will not be released at all when preparing or
|
1265
|
+
* running queries. It is the application's responsibility to let other threads
|
1266
|
+
* or fibers run by calling e.g. Thread.pass:
|
1267
|
+
*
|
1268
|
+
* Extralite.on_progress do
|
1269
|
+
* do_something_interesting
|
1270
|
+
* Thread.pass # let other threads run
|
1271
|
+
* end
|
1272
|
+
*
|
1273
|
+
* @param period [Integer] progress handler period
|
1274
|
+
* @param [Hash] opts progress options
|
1275
|
+
* @option opts [Integer] :period period value (`1000` by default)
|
1276
|
+
* @option opts [Integer] :tick tick value (`10` by default)
|
1277
|
+
* @option opts [Symbol] :mode progress handler mode (`:normal` by default)
|
1278
|
+
* @returns [Extralite::Database] database
|
1279
|
+
*/
|
1280
|
+
VALUE Extralite_on_progress(int argc, VALUE *argv, VALUE self) {
|
1281
|
+
VALUE opts;
|
1282
|
+
|
1283
|
+
rb_scan_args(argc, argv, "00:", &opts);
|
1284
|
+
global_progress_handler = parse_progress_handler_opts(opts);
|
1285
|
+
return self;
|
1286
|
+
}
|
1287
|
+
|
1288
|
+
/* Returns the last error code for the database.
|
1289
|
+
*
|
1290
|
+
* @return [Integer] last error code
|
866
1291
|
*/
|
867
1292
|
VALUE Database_errcode(VALUE self) {
|
868
1293
|
Database_t *db = self_to_open_database(self);
|
@@ -870,10 +1295,9 @@ VALUE Database_errcode(VALUE self) {
|
|
870
1295
|
return INT2NUM(sqlite3_errcode(db->sqlite3_db));
|
871
1296
|
}
|
872
1297
|
|
873
|
-
/*
|
874
|
-
*
|
875
|
-
*
|
876
|
-
* Returns the last error message for the database.
|
1298
|
+
/* Returns the last error message for the database.
|
1299
|
+
*
|
1300
|
+
* @return [String] last error message
|
877
1301
|
*/
|
878
1302
|
VALUE Database_errmsg(VALUE self) {
|
879
1303
|
Database_t *db = self_to_open_database(self);
|
@@ -882,10 +1306,10 @@ VALUE Database_errmsg(VALUE self) {
|
|
882
1306
|
}
|
883
1307
|
|
884
1308
|
#ifdef HAVE_SQLITE3_ERROR_OFFSET
|
885
|
-
/*
|
886
|
-
*
|
887
|
-
*
|
888
|
-
*
|
1309
|
+
/* Returns the offset for the last error. This is useful for indicating where in
|
1310
|
+
* the SQL string an error was encountered.
|
1311
|
+
*
|
1312
|
+
* @return [Integer] offset in the last submitted SQL string
|
889
1313
|
*/
|
890
1314
|
VALUE Database_error_offset(VALUE self) {
|
891
1315
|
Database_t *db = self_to_open_database(self);
|
@@ -921,22 +1345,40 @@ VALUE Database_gvl_release_threshold_get(VALUE self) {
|
|
921
1345
|
return INT2NUM(db->gvl_release_threshold);
|
922
1346
|
}
|
923
1347
|
|
924
|
-
/* Sets the database's GVL release threshold.
|
925
|
-
*
|
926
|
-
*
|
927
|
-
*
|
928
|
-
*
|
1348
|
+
/* Sets the database's GVL release threshold. The release policy changes
|
1349
|
+
* according to the given value:
|
1350
|
+
*
|
1351
|
+
* - Less than 0: the GVL is never released while running queries. This is the
|
1352
|
+
* policy used when a progress handler is set. For more information see
|
1353
|
+
* `#on_progress`.
|
1354
|
+
* - 0: The GVL is released while preparing queries, but held when iterating
|
1355
|
+
* through records.
|
1356
|
+
* - Greater than 0: the GVL is released while preparing queries, and released
|
1357
|
+
* periodically while iterating through records, according to the given
|
1358
|
+
* period. A value of 1 will release the GVL on every iterated record. A value
|
1359
|
+
* of 100 will release the GVL once for every 100 records.
|
1360
|
+
*
|
1361
|
+
* A value of nil sets the threshold to the default value, which is
|
929
1362
|
* currently 1000.
|
930
1363
|
*
|
931
|
-
* @
|
1364
|
+
* @param [Integer, nil] GVL release threshold
|
1365
|
+
* @return [Integer] GVL release threshold
|
932
1366
|
*/
|
933
1367
|
VALUE Database_gvl_release_threshold_set(VALUE self, VALUE value) {
|
934
1368
|
Database_t *db = self_to_open_database(self);
|
935
1369
|
|
936
1370
|
switch (TYPE(value)) {
|
937
1371
|
case T_FIXNUM:
|
938
|
-
|
939
|
-
|
1372
|
+
{
|
1373
|
+
int value_int = NUM2INT(value);
|
1374
|
+
if (value_int < -1)
|
1375
|
+
rb_raise(eArgumentError, "Invalid GVL release threshold value (expect integer >= -1)");
|
1376
|
+
|
1377
|
+
if (value_int > -1 && db->progress_handler.mode != PROGRESS_NONE)
|
1378
|
+
Database_reset_progress_handler(self, db);
|
1379
|
+
db->gvl_release_threshold = value_int;
|
1380
|
+
break;
|
1381
|
+
}
|
940
1382
|
case T_NIL:
|
941
1383
|
db->gvl_release_threshold = DEFAULT_GVL_RELEASE_THRESHOLD;
|
942
1384
|
break;
|
@@ -951,79 +1393,106 @@ void Init_ExtraliteDatabase(void) {
|
|
951
1393
|
VALUE mExtralite = rb_define_module("Extralite");
|
952
1394
|
rb_define_singleton_method(mExtralite, "runtime_status", Extralite_runtime_status, -1);
|
953
1395
|
rb_define_singleton_method(mExtralite, "sqlite3_version", Extralite_sqlite3_version, 0);
|
1396
|
+
rb_define_singleton_method(mExtralite, "on_progress", Extralite_on_progress, -1);
|
954
1397
|
|
955
1398
|
cDatabase = rb_define_class_under(mExtralite, "Database", rb_cObject);
|
956
1399
|
rb_define_alloc_func(cDatabase, Database_allocate);
|
957
1400
|
|
958
|
-
rb_define_method(cDatabase,
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
|
1401
|
+
#define DEF(s, f, a) rb_define_method(cDatabase, s, f, a)
|
1402
|
+
|
1403
|
+
DEF("backup", Database_backup, -1);
|
1404
|
+
DEF("batch_execute", Database_batch_execute, 2);
|
1405
|
+
DEF("batch_query", Database_batch_query, 2);
|
1406
|
+
DEF("batch_query_ary", Database_batch_query_ary, 2);
|
1407
|
+
DEF("batch_query_argv", Database_batch_query_argv, 2);
|
1408
|
+
DEF("batch_query_hash", Database_batch_query, 2);
|
1409
|
+
DEF("busy_timeout=", Database_busy_timeout_set, 1);
|
1410
|
+
DEF("changes", Database_changes, 0);
|
1411
|
+
DEF("close", Database_close, 0);
|
1412
|
+
DEF("closed?", Database_closed_p, 0);
|
1413
|
+
DEF("columns", Database_columns, 1);
|
1414
|
+
DEF("errcode", Database_errcode, 0);
|
1415
|
+
DEF("errmsg", Database_errmsg, 0);
|
966
1416
|
|
967
1417
|
#ifdef HAVE_SQLITE3_ERROR_OFFSET
|
968
|
-
|
1418
|
+
DEF("error_offset", Database_error_offset, 0);
|
969
1419
|
#endif
|
970
1420
|
|
971
|
-
|
972
|
-
|
973
|
-
|
974
|
-
|
975
|
-
|
976
|
-
|
977
|
-
|
978
|
-
|
979
|
-
|
980
|
-
|
981
|
-
|
982
|
-
|
983
|
-
|
984
|
-
rb_define_method(cDatabase, "prepare", Database_prepare, -1);
|
985
|
-
rb_define_method(cDatabase, "query", Database_query_hash, -1);
|
986
|
-
rb_define_method(cDatabase, "query_ary", Database_query_ary, -1);
|
987
|
-
rb_define_method(cDatabase, "query_hash", Database_query_hash, -1);
|
988
|
-
rb_define_method(cDatabase, "query_single_column", Database_query_single_column, -1);
|
989
|
-
rb_define_method(cDatabase, "query_single_row", Database_query_single_row, -1);
|
990
|
-
rb_define_method(cDatabase, "query_single_value", Database_query_single_value, -1);
|
991
|
-
rb_define_method(cDatabase, "read_only?", Database_read_only_p, 0);
|
992
|
-
rb_define_method(cDatabase, "status", Database_status, -1);
|
993
|
-
rb_define_method(cDatabase, "total_changes", Database_total_changes, 0);
|
994
|
-
rb_define_method(cDatabase, "trace", Database_trace, 0);
|
995
|
-
rb_define_method(cDatabase, "transaction_active?", Database_transaction_active_p, 0);
|
996
|
-
|
997
|
-
#ifdef HAVE_SQLITE3_LOAD_EXTENSION
|
998
|
-
rb_define_method(cDatabase, "load_extension", Database_load_extension, 1);
|
999
|
-
#endif
|
1421
|
+
DEF("execute", Database_execute, -1);
|
1422
|
+
DEF("filename", Database_filename, -1);
|
1423
|
+
DEF("gvl_release_threshold", Database_gvl_release_threshold_get, 0);
|
1424
|
+
DEF("gvl_release_threshold=", Database_gvl_release_threshold_set, 1);
|
1425
|
+
DEF("initialize", Database_initialize, -1);
|
1426
|
+
DEF("inspect", Database_inspect, 0);
|
1427
|
+
DEF("interrupt", Database_interrupt, 0);
|
1428
|
+
DEF("last_insert_rowid", Database_last_insert_rowid, 0);
|
1429
|
+
DEF("limit", Database_limit, -1);
|
1430
|
+
|
1431
|
+
#ifdef HAVE_SQLITE3_LOAD_EXTENSION
|
1432
|
+
DEF("load_extension", Database_load_extension, 1);
|
1433
|
+
#endif
|
1000
1434
|
|
1001
|
-
|
1435
|
+
DEF("on_progress", Database_on_progress, -1);
|
1436
|
+
DEF("prepare", Database_prepare_hash, -1);
|
1437
|
+
DEF("prepare_argv", Database_prepare_argv, -1);
|
1438
|
+
DEF("prepare_ary", Database_prepare_ary, -1);
|
1439
|
+
DEF("prepare_hash", Database_prepare_hash, -1);
|
1440
|
+
DEF("query", Database_query, -1);
|
1441
|
+
DEF("query_argv", Database_query_argv, -1);
|
1442
|
+
DEF("query_ary", Database_query_ary, -1);
|
1443
|
+
DEF("query_hash", Database_query, -1);
|
1444
|
+
DEF("query_single", Database_query_single, -1);
|
1445
|
+
DEF("query_single_ary", Database_query_single_ary, -1);
|
1446
|
+
DEF("query_single_argv", Database_query_single_argv, -1);
|
1447
|
+
DEF("query_single_hash", Database_query_single, -1);
|
1448
|
+
DEF("read_only?", Database_read_only_p, 0);
|
1449
|
+
DEF("status", Database_status, -1);
|
1450
|
+
DEF("total_changes", Database_total_changes, 0);
|
1451
|
+
DEF("trace", Database_trace, 0);
|
1452
|
+
|
1453
|
+
#ifdef EXTRALITE_ENABLE_CHANGESET
|
1454
|
+
DEF("track_changes", Database_track_changes, -1);
|
1455
|
+
#endif
|
1456
|
+
|
1457
|
+
DEF("transaction_active?", Database_transaction_active_p, 0);
|
1002
1458
|
|
1003
|
-
|
1004
|
-
|
1005
|
-
|
1459
|
+
cBlob = rb_define_class_under(mExtralite, "Blob", rb_cString);
|
1460
|
+
cError = rb_define_class_under(mExtralite, "Error", rb_eStandardError);
|
1461
|
+
cSQLError = rb_define_class_under(mExtralite, "SQLError", cError);
|
1462
|
+
cBusyError = rb_define_class_under(mExtralite, "BusyError", cError);
|
1006
1463
|
cInterruptError = rb_define_class_under(mExtralite, "InterruptError", cError);
|
1007
1464
|
cParameterError = rb_define_class_under(mExtralite, "ParameterError", cError);
|
1008
|
-
|
1009
|
-
|
1010
|
-
|
1011
|
-
|
1012
|
-
|
1013
|
-
|
1014
|
-
|
1015
|
-
|
1016
|
-
ID_strip
|
1017
|
-
|
1465
|
+
eArgumentError = rb_const_get(rb_cObject, rb_intern("ArgumentError"));
|
1466
|
+
|
1467
|
+
ID_bind = rb_intern("bind");
|
1468
|
+
ID_call = rb_intern("call");
|
1469
|
+
ID_each = rb_intern("each");
|
1470
|
+
ID_keys = rb_intern("keys");
|
1471
|
+
ID_new = rb_intern("new");
|
1472
|
+
ID_pragma = rb_intern("pragma");
|
1473
|
+
ID_strip = rb_intern("strip");
|
1474
|
+
ID_to_s = rb_intern("to_s");
|
1475
|
+
ID_track = rb_intern("track");
|
1476
|
+
|
1477
|
+
SYM_at_least_once = ID2SYM(rb_intern("at_least_once"));
|
1018
1478
|
SYM_gvl_release_threshold = ID2SYM(rb_intern("gvl_release_threshold"));
|
1479
|
+
SYM_once = ID2SYM(rb_intern("once"));
|
1480
|
+
SYM_none = ID2SYM(rb_intern("none"));
|
1481
|
+
SYM_normal = ID2SYM(rb_intern("normal"));
|
1482
|
+
SYM_pragma = ID2SYM(rb_intern("pragma"));
|
1019
1483
|
SYM_read_only = ID2SYM(rb_intern("read_only"));
|
1020
|
-
|
1021
|
-
SYM_wal_journal_mode = ID2SYM(rb_intern("wal_journal_mode"));
|
1484
|
+
SYM_wal = ID2SYM(rb_intern("wal"));
|
1022
1485
|
|
1486
|
+
rb_gc_register_mark_object(SYM_at_least_once);
|
1023
1487
|
rb_gc_register_mark_object(SYM_gvl_release_threshold);
|
1488
|
+
rb_gc_register_mark_object(SYM_once);
|
1489
|
+
rb_gc_register_mark_object(SYM_none);
|
1490
|
+
rb_gc_register_mark_object(SYM_normal);
|
1491
|
+
rb_gc_register_mark_object(SYM_pragma);
|
1024
1492
|
rb_gc_register_mark_object(SYM_read_only);
|
1025
|
-
rb_gc_register_mark_object(
|
1026
|
-
|
1493
|
+
rb_gc_register_mark_object(SYM_wal);
|
1494
|
+
|
1495
|
+
rb_gc_register_mark_object(global_progress_handler.proc);
|
1027
1496
|
|
1028
1497
|
UTF8_ENCODING = rb_utf8_encoding();
|
1029
1498
|
}
|