extralite 2.5 → 2.7
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
}
|