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/query.c
CHANGED
@@ -14,6 +14,12 @@ VALUE cQuery;
|
|
14
14
|
ID ID_inspect;
|
15
15
|
ID ID_slice;
|
16
16
|
|
17
|
+
VALUE SYM_hash;
|
18
|
+
VALUE SYM_argv;
|
19
|
+
VALUE SYM_ary;
|
20
|
+
|
21
|
+
#define DB_GVL_MODE(query) Database_prepare_gvl_mode(query->db_struct)
|
22
|
+
|
17
23
|
static size_t Query_size(const void *ptr) {
|
18
24
|
return sizeof(Query_t);
|
19
25
|
}
|
@@ -22,12 +28,14 @@ static void Query_mark(void *ptr) {
|
|
22
28
|
Query_t *query = ptr;
|
23
29
|
rb_gc_mark_movable(query->db);
|
24
30
|
rb_gc_mark_movable(query->sql);
|
31
|
+
rb_gc_mark_movable(query->transform_proc);
|
25
32
|
}
|
26
33
|
|
27
34
|
static void Query_compact(void *ptr) {
|
28
35
|
Query_t *query = ptr;
|
29
36
|
query->db = rb_gc_location(query->db);
|
30
37
|
query->sql = rb_gc_location(query->sql);
|
38
|
+
query->transform_proc = rb_gc_location(query->transform_proc);
|
31
39
|
}
|
32
40
|
|
33
41
|
static void Query_free(void *ptr) {
|
@@ -46,6 +54,7 @@ static VALUE Query_allocate(VALUE klass) {
|
|
46
54
|
Query_t *query = ALLOC(Query_t);
|
47
55
|
query->db = Qnil;
|
48
56
|
query->sql = Qnil;
|
57
|
+
query->transform_proc = Qnil;
|
49
58
|
query->sqlite3_db = NULL;
|
50
59
|
query->stmt = NULL;
|
51
60
|
return TypedData_Wrap_Struct(klass, &Query_type, query);
|
@@ -57,6 +66,27 @@ static inline Query_t *self_to_query(VALUE obj) {
|
|
57
66
|
return query;
|
58
67
|
}
|
59
68
|
|
69
|
+
static inline enum query_mode symbol_to_query_mode(VALUE sym) {
|
70
|
+
if (sym == SYM_hash) return QUERY_HASH;
|
71
|
+
if (sym == SYM_argv) return QUERY_ARGV;
|
72
|
+
if (sym == SYM_ary) return QUERY_ARY;
|
73
|
+
|
74
|
+
rb_raise(cError, "Invalid query mode");
|
75
|
+
}
|
76
|
+
|
77
|
+
static inline VALUE query_mode_to_symbol(enum query_mode query_mode) {
|
78
|
+
switch (query_mode) {
|
79
|
+
case QUERY_HASH:
|
80
|
+
return SYM_hash;
|
81
|
+
case QUERY_ARGV:
|
82
|
+
return SYM_argv;
|
83
|
+
case QUERY_ARY:
|
84
|
+
return SYM_ary;
|
85
|
+
default:
|
86
|
+
rb_raise(cError, "Invalid mode");
|
87
|
+
}
|
88
|
+
}
|
89
|
+
|
60
90
|
/* Initializes a new prepared query with the given database and SQL string. A
|
61
91
|
* `Query` is normally instantiated by calling `Database#prepare`:
|
62
92
|
*
|
@@ -64,9 +94,10 @@ static inline Query_t *self_to_query(VALUE obj) {
|
|
64
94
|
*
|
65
95
|
* @param db [Extralite::Database] associated database
|
66
96
|
* @param sql [String] SQL string
|
97
|
+
* @param mode [Symbol] query mode
|
67
98
|
* @return [void]
|
68
99
|
*/
|
69
|
-
VALUE Query_initialize(VALUE self, VALUE db, VALUE sql) {
|
100
|
+
VALUE Query_initialize(VALUE self, VALUE db, VALUE sql, VALUE mode) {
|
70
101
|
Query_t *query = self_to_query(self);
|
71
102
|
|
72
103
|
sql = rb_funcall(sql, ID_strip, 0);
|
@@ -75,6 +106,8 @@ VALUE Query_initialize(VALUE self, VALUE db, VALUE sql) {
|
|
75
106
|
|
76
107
|
RB_OBJ_WRITE(self, &query->db, db);
|
77
108
|
RB_OBJ_WRITE(self, &query->sql, sql);
|
109
|
+
if (rb_block_given_p())
|
110
|
+
RB_OBJ_WRITE(self, &query->transform_proc, rb_block_proc());
|
78
111
|
|
79
112
|
query->db = db;
|
80
113
|
query->db_struct = self_to_database(db);
|
@@ -82,26 +115,23 @@ VALUE Query_initialize(VALUE self, VALUE db, VALUE sql) {
|
|
82
115
|
query->stmt = NULL;
|
83
116
|
query->closed = 0;
|
84
117
|
query->eof = 0;
|
118
|
+
query->query_mode = symbol_to_query_mode(mode);
|
85
119
|
|
86
120
|
return Qnil;
|
87
121
|
}
|
88
122
|
|
89
123
|
static inline void query_reset(Query_t *query) {
|
90
124
|
if (!query->stmt)
|
91
|
-
prepare_single_stmt(query->sqlite3_db, &query->stmt, query->sql);
|
92
|
-
|
93
|
-
rb_funcall(query->db_struct->trace_block, ID_call, 1, query->sql);
|
125
|
+
prepare_single_stmt(DB_GVL_MODE(query), query->sqlite3_db, &query->stmt, query->sql);
|
126
|
+
Database_issue_query(query->db_struct, query->sql);
|
94
127
|
sqlite3_reset(query->stmt);
|
95
128
|
query->eof = 0;
|
96
129
|
}
|
97
130
|
|
98
131
|
static inline void query_reset_and_bind(Query_t *query, int argc, VALUE * argv) {
|
99
132
|
if (!query->stmt)
|
100
|
-
prepare_single_stmt(query->sqlite3_db, &query->stmt, query->sql);
|
101
|
-
|
102
|
-
if (query->db_struct->trace_block != Qnil)
|
103
|
-
rb_funcall(query->db_struct->trace_block, ID_call, 1, query->sql);
|
104
|
-
|
133
|
+
prepare_single_stmt(DB_GVL_MODE(query), query->sqlite3_db, &query->stmt, query->sql);
|
134
|
+
Database_issue_query(query->db_struct, query->sql);
|
105
135
|
sqlite3_reset(query->stmt);
|
106
136
|
query->eof = 0;
|
107
137
|
if (argc > 0) {
|
@@ -128,9 +158,6 @@ VALUE Query_reset(VALUE self) {
|
|
128
158
|
if (query->closed) rb_raise(cError, "Query is closed");
|
129
159
|
|
130
160
|
query_reset(query);
|
131
|
-
if (query->db_struct->trace_block != Qnil)
|
132
|
-
rb_funcall(query->db_struct->trace_block, ID_call, 1, query->sql);
|
133
|
-
|
134
161
|
return self;
|
135
162
|
}
|
136
163
|
|
@@ -176,7 +203,7 @@ VALUE Query_eof_p(VALUE self) {
|
|
176
203
|
|
177
204
|
#define MAX_ROWS(max_rows) (max_rows == SINGLE_ROW ? 1 : max_rows)
|
178
205
|
|
179
|
-
static inline VALUE Query_perform_next(VALUE self, int max_rows,
|
206
|
+
static inline VALUE Query_perform_next(VALUE self, int max_rows, safe_query_impl call) {
|
180
207
|
Query_t *query = self_to_query(self);
|
181
208
|
if (query->closed) rb_raise(cError, "Query is closed");
|
182
209
|
|
@@ -185,69 +212,37 @@ static inline VALUE Query_perform_next(VALUE self, int max_rows, VALUE (*call)(q
|
|
185
212
|
|
186
213
|
query_ctx ctx = QUERY_CTX(
|
187
214
|
self,
|
215
|
+
query->sql,
|
188
216
|
query->db_struct,
|
189
217
|
query->stmt,
|
190
218
|
Qnil,
|
191
|
-
|
219
|
+
query->transform_proc,
|
220
|
+
query->query_mode,
|
221
|
+
ROW_YIELD_OR_MODE(max_rows == SINGLE_ROW ? ROW_SINGLE : ROW_MULTI),
|
192
222
|
MAX_ROWS(max_rows)
|
193
223
|
);
|
194
224
|
VALUE result = call(&ctx);
|
195
225
|
query->eof = ctx.eof;
|
196
|
-
return (ctx.
|
226
|
+
return (ctx.row_mode == ROW_YIELD) ? self : result;
|
197
227
|
}
|
198
228
|
|
199
229
|
#define MAX_ROWS_FROM_ARGV(argc, argv) (argc == 1 ? FIX2INT(argv[0]) : SINGLE_ROW)
|
200
230
|
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
* @return [Hash, Extralite::Query] next row or self if block is given
|
213
|
-
* @overload next_hash()
|
214
|
-
* @return [Hash, Extralite::Query] next row or self if block is given
|
215
|
-
* @overload next(row_count)
|
216
|
-
* @param row_count [Integer] maximum row count or -1 for all rows
|
217
|
-
* @return [Array<Hash>, Extralite::Query] next rows or self if block is given
|
218
|
-
* @overload next_hash(row_count)
|
219
|
-
* @param row_count [Integer] maximum row count or -1 for all rows
|
220
|
-
* @return [Array<Hash>, Extralite::Query] next rows or self if block is given
|
221
|
-
*/
|
222
|
-
VALUE Query_next_hash(int argc, VALUE *argv, VALUE self) {
|
223
|
-
rb_check_arity(argc, 0, 1);
|
224
|
-
return Query_perform_next(self, MAX_ROWS_FROM_ARGV(argc, argv), safe_query_hash);
|
225
|
-
}
|
226
|
-
|
227
|
-
/* Returns the next 1 or more rows from the associated query's result set as an
|
228
|
-
* array.
|
229
|
-
*
|
230
|
-
* If no row count is given, a single row is returned. If a row count is given,
|
231
|
-
* an array containing up to the `row_count` rows is returned. If `row_count` is
|
232
|
-
* -1, all rows are returned. If the end of the result set has been reached,
|
233
|
-
* `nil` is returned.
|
234
|
-
*
|
235
|
-
* If a block is given, rows are passed to the block and self is returned.
|
236
|
-
*
|
237
|
-
* @overload next_ary()
|
238
|
-
* @return [Array, Extralite::Query] next row or self if block is given
|
239
|
-
* @overload next_ary(row_count)
|
240
|
-
* @param row_count [Integer] maximum row count or -1 for all rows
|
241
|
-
* @return [Array<Array>, Extralite::Query] next rows or self if block is given
|
242
|
-
*/
|
243
|
-
VALUE Query_next_ary(int argc, VALUE *argv, VALUE self) {
|
244
|
-
rb_check_arity(argc, 0, 1);
|
245
|
-
return Query_perform_next(self, MAX_ROWS_FROM_ARGV(argc, argv), safe_query_ary);
|
231
|
+
inline safe_query_impl query_impl(enum query_mode query_mode) {
|
232
|
+
switch (query_mode) {
|
233
|
+
case QUERY_HASH:
|
234
|
+
return safe_query_hash;
|
235
|
+
case QUERY_ARGV:
|
236
|
+
return safe_query_argv;
|
237
|
+
case QUERY_ARY:
|
238
|
+
return safe_query_ary;
|
239
|
+
default:
|
240
|
+
rb_raise(cError, "Invalid query mode (query_impl)");
|
241
|
+
}
|
246
242
|
}
|
247
243
|
|
248
|
-
/* Returns the next 1 or more rows from the associated query's result set
|
249
|
-
*
|
250
|
-
* raised.
|
244
|
+
/* Returns the next 1 or more rows from the associated query's result set. The
|
245
|
+
* row value is returned according to the query mode and the query transform.
|
251
246
|
*
|
252
247
|
* If no row count is given, a single row is returned. If a row count is given,
|
253
248
|
* an array containing up to the `row_count` rows is returned. If `row_count` is
|
@@ -256,92 +251,41 @@ VALUE Query_next_ary(int argc, VALUE *argv, VALUE self) {
|
|
256
251
|
*
|
257
252
|
* If a block is given, rows are passed to the block and self is returned.
|
258
253
|
*
|
259
|
-
* @overload
|
260
|
-
* @return [
|
261
|
-
* @overload
|
254
|
+
* @overload next()
|
255
|
+
* @return [any, Extralite::Query] next row or self if block is given
|
256
|
+
* @overload next(row_count)
|
262
257
|
* @param row_count [Integer] maximum row count or -1 for all rows
|
263
|
-
* @return [Array<
|
264
|
-
*/
|
265
|
-
VALUE Query_next_single_column(int argc, VALUE *argv, VALUE self) {
|
266
|
-
rb_check_arity(argc, 0, 1);
|
267
|
-
return Query_perform_next(self, MAX_ROWS_FROM_ARGV(argc, argv), safe_query_single_column);
|
268
|
-
}
|
269
|
-
|
270
|
-
/* Returns all rows in the associated query's result set as hashes.
|
271
|
-
*
|
272
|
-
* @overload to_a()
|
273
|
-
* @return [Array<Hash>] all rows
|
274
|
-
* @overload to_a_hash
|
275
|
-
* @return [Array<Hash>] all rows
|
276
|
-
*/
|
277
|
-
VALUE Query_to_a_hash(VALUE self) {
|
278
|
-
Query_t *query = self_to_query(self);
|
279
|
-
query_reset(query);
|
280
|
-
return Query_perform_next(self, ALL_ROWS, safe_query_hash);
|
281
|
-
}
|
282
|
-
|
283
|
-
/* Returns all rows in the associated query's result set as arrays.
|
284
|
-
*
|
285
|
-
* @return [Array<Array>] all rows
|
286
|
-
*/
|
287
|
-
VALUE Query_to_a_ary(VALUE self) {
|
288
|
-
Query_t *query = self_to_query(self);
|
289
|
-
query_reset(query);
|
290
|
-
return Query_perform_next(self, ALL_ROWS, safe_query_ary);
|
291
|
-
}
|
292
|
-
|
293
|
-
/* Returns all rows in the associated query's result set as single values. If
|
294
|
-
* the result set contains more than one column an error is raised.
|
295
|
-
*
|
296
|
-
* @return [Array<Object>] all rows
|
258
|
+
* @return [Array<any>, Extralite::Query] next rows or self if block is given
|
297
259
|
*/
|
298
|
-
VALUE
|
260
|
+
VALUE Query_next(int argc, VALUE *argv, VALUE self) {
|
299
261
|
Query_t *query = self_to_query(self);
|
300
|
-
|
301
|
-
return Query_perform_next(self,
|
262
|
+
rb_check_arity(argc, 0, 1);
|
263
|
+
return Query_perform_next(self, MAX_ROWS_FROM_ARGV(argc, argv), query_impl(query->query_mode));
|
302
264
|
}
|
303
265
|
|
304
|
-
/*
|
305
|
-
*
|
306
|
-
* mode.
|
266
|
+
/* Returns all rows in the associated query's result set. Rows are returned
|
267
|
+
* according to the query mode and the query transform.
|
307
268
|
*
|
308
|
-
* @return [
|
269
|
+
* @return [Array<any>] all rows
|
309
270
|
*/
|
310
|
-
VALUE
|
311
|
-
if (!rb_block_given_p()) return rb_funcall(cIterator, ID_new, 2, self, SYM_hash);
|
312
|
-
|
271
|
+
VALUE Query_to_a(VALUE self) {
|
313
272
|
Query_t *query = self_to_query(self);
|
314
273
|
query_reset(query);
|
315
|
-
return Query_perform_next(self, ALL_ROWS,
|
274
|
+
return Query_perform_next(self, ALL_ROWS, query_impl(query->query_mode));
|
316
275
|
}
|
317
276
|
|
318
|
-
/* Iterates through the result set, passing each row to the given block
|
319
|
-
*
|
320
|
-
*
|
277
|
+
/* Iterates through the result set, passing each row to the given block. If no
|
278
|
+
* block is given, returns a `Extralite::Iterator` instance. Rows are given to
|
279
|
+
* the block according to the query mode and the query transform.
|
321
280
|
*
|
322
281
|
* @return [Extralite::Query, Extralite::Iterator] self or an iterator if no block is given
|
323
282
|
*/
|
324
|
-
VALUE
|
325
|
-
if (!rb_block_given_p()) return rb_funcall(cIterator, ID_new,
|
283
|
+
VALUE Query_each(VALUE self) {
|
284
|
+
if (!rb_block_given_p()) return rb_funcall(cIterator, ID_new, 1, self);
|
326
285
|
|
327
286
|
Query_t *query = self_to_query(self);
|
328
287
|
query_reset(query);
|
329
|
-
return Query_perform_next(self, ALL_ROWS,
|
330
|
-
}
|
331
|
-
|
332
|
-
/* Iterates through the result set, passing each row to the given block as a
|
333
|
-
* single value. If the result set contains more than one column an error is
|
334
|
-
* raised. If no block is given, returns a `Extralite::Iterator` instance in
|
335
|
-
* single column mode.
|
336
|
-
*
|
337
|
-
* @return [Extralite::Query, Extralite::Iterator] self or an iterator if no block is given
|
338
|
-
*/
|
339
|
-
VALUE Query_each_single_column(VALUE self) {
|
340
|
-
if (!rb_block_given_p()) return rb_funcall(cIterator, ID_new, 2, self, SYM_single_column);
|
341
|
-
|
342
|
-
Query_t *query = self_to_query(self);
|
343
|
-
query_reset(query);
|
344
|
-
return Query_perform_next(self, ALL_ROWS, safe_query_single_column);
|
288
|
+
return Query_perform_next(self, ALL_ROWS, query_impl(query->query_mode));
|
345
289
|
}
|
346
290
|
|
347
291
|
/* call-seq:
|
@@ -437,14 +381,17 @@ VALUE Query_batch_execute(VALUE self, VALUE parameters) {
|
|
437
381
|
if (query->closed) rb_raise(cError, "Query is closed");
|
438
382
|
|
439
383
|
if (!query->stmt)
|
440
|
-
prepare_single_stmt(query->sqlite3_db, &query->stmt, query->sql);
|
384
|
+
prepare_single_stmt(DB_GVL_MODE(query), query->sqlite3_db, &query->stmt, query->sql);
|
441
385
|
|
442
386
|
query_ctx ctx = QUERY_CTX(
|
443
387
|
self,
|
388
|
+
query->sql,
|
444
389
|
query->db_struct,
|
445
390
|
query->stmt,
|
446
391
|
parameters,
|
447
|
-
|
392
|
+
Qnil,
|
393
|
+
QUERY_HASH,
|
394
|
+
ROW_YIELD_OR_MODE(ROW_MULTI),
|
448
395
|
ALL_ROWS
|
449
396
|
);
|
450
397
|
return safe_batch_execute(&ctx);
|
@@ -463,6 +410,8 @@ VALUE Query_batch_execute(VALUE self, VALUE parameters) {
|
|
463
410
|
* invocation of the query, and the total number of changes is returned.
|
464
411
|
* Otherwise, an array containing the resulting rows for each invocation is
|
465
412
|
* returned.
|
413
|
+
*
|
414
|
+
* Rows are returned according to the query mode and transform.
|
466
415
|
*
|
467
416
|
* q = db.prepare('insert into foo values (?, ?) returning bar, baz')
|
468
417
|
* records = [
|
@@ -474,114 +423,29 @@ VALUE Query_batch_execute(VALUE self, VALUE parameters) {
|
|
474
423
|
* *
|
475
424
|
* @param sql [String] query SQL
|
476
425
|
* @param parameters [Array<Array, Hash>, Enumerable, Enumerator, Callable] parameters to run query with
|
477
|
-
* @return [Array<
|
426
|
+
* @return [Array<Array>, Integer] Returned rows or total number of changes effected
|
478
427
|
*/
|
479
428
|
VALUE Query_batch_query(VALUE self, VALUE parameters) {
|
480
429
|
Query_t *query = self_to_query(self);
|
481
430
|
if (query->closed) rb_raise(cError, "Query is closed");
|
482
431
|
|
483
432
|
if (!query->stmt)
|
484
|
-
prepare_single_stmt(query->sqlite3_db, &query->stmt, query->sql);
|
433
|
+
prepare_single_stmt(DB_GVL_MODE(query), query->sqlite3_db, &query->stmt, query->sql);
|
485
434
|
|
486
435
|
query_ctx ctx = QUERY_CTX(
|
487
436
|
self,
|
437
|
+
query->sql,
|
488
438
|
query->db_struct,
|
489
439
|
query->stmt,
|
490
440
|
parameters,
|
491
|
-
|
441
|
+
query->transform_proc,
|
442
|
+
query->query_mode,
|
443
|
+
ROW_YIELD_OR_MODE(ROW_MULTI),
|
492
444
|
ALL_ROWS
|
493
445
|
);
|
494
446
|
return safe_batch_query(&ctx);
|
495
447
|
}
|
496
448
|
|
497
|
-
/* call-seq:
|
498
|
-
* query.batch_query_ary(sql, params_array) -> rows
|
499
|
-
* query.batch_query_ary(sql, enumerable) -> rows
|
500
|
-
* query.batch_query_ary(sql, callable) -> rows
|
501
|
-
* query.batch_query_ary(sql, params_array) { |rows| ... } -> changes
|
502
|
-
* query.batch_query_ary(sql, enumerable) { |rows| ... } -> changes
|
503
|
-
* query.batch_query_ary(sql, callable) { |rows| ... } -> changes
|
504
|
-
*
|
505
|
-
* Executes the prepared query for each list of parameters in the given paramter
|
506
|
-
* source. If a block is given, it is called with the resulting rows for each
|
507
|
-
* invocation of the query, and the total number of changes is returned.
|
508
|
-
* Otherwise, an array containing the resulting rows for each invocation is
|
509
|
-
* returned. Rows are represented as arrays.
|
510
|
-
*
|
511
|
-
* q = db.prepare('insert into foo values (?, ?) returning bar, baz')
|
512
|
-
* records = [
|
513
|
-
* [1, 2],
|
514
|
-
* [3, 4]
|
515
|
-
* ]
|
516
|
-
* q.batch_query_ary(records)
|
517
|
-
* #=> [{ bar: 1, baz: 2 }, { bar: 3, baz: 4}]
|
518
|
-
* *
|
519
|
-
* @param sql [String] query SQL
|
520
|
-
* @param parameters [Array<Array, Hash>, Enumerable, Enumerator, Callable] parameters to run query with
|
521
|
-
* @return [Array<Hash>, Integer] Total number of changes effected
|
522
|
-
*/
|
523
|
-
VALUE Query_batch_query_ary(VALUE self, VALUE parameters) {
|
524
|
-
Query_t *query = self_to_query(self);
|
525
|
-
if (query->closed) rb_raise(cError, "Query is closed");
|
526
|
-
|
527
|
-
if (!query->stmt)
|
528
|
-
prepare_single_stmt(query->sqlite3_db, &query->stmt, query->sql);
|
529
|
-
|
530
|
-
query_ctx ctx = QUERY_CTX(
|
531
|
-
self,
|
532
|
-
query->db_struct,
|
533
|
-
query->stmt,
|
534
|
-
parameters,
|
535
|
-
QUERY_MODE(QUERY_MULTI_ROW),
|
536
|
-
ALL_ROWS
|
537
|
-
);
|
538
|
-
return safe_batch_query_ary(&ctx);
|
539
|
-
}
|
540
|
-
|
541
|
-
/* call-seq:
|
542
|
-
* query.batch_query_single_column(sql, params_array) -> rows
|
543
|
-
* query.batch_query_single_column(sql, enumerable) -> rows
|
544
|
-
* query.batch_query_single_column(sql, callable) -> rows
|
545
|
-
* query.batch_query_single_column(sql, params_array) { |rows| ... } -> changes
|
546
|
-
* query.batch_query_single_column(sql, enumerable) { |rows| ... } -> changes
|
547
|
-
* query.batch_query_single_column(sql, callable) { |rows| ... } -> changes
|
548
|
-
*
|
549
|
-
* Executes the prepared query for each list of parameters in the given paramter
|
550
|
-
* source. If a block is given, it is called with the resulting rows for each
|
551
|
-
* invocation of the query, and the total number of changes is returned.
|
552
|
-
* Otherwise, an array containing the resulting rows for each invocation is
|
553
|
-
* returned. Rows are represented as single values.
|
554
|
-
*
|
555
|
-
* q = db.prepare('insert into foo values (?, ?) returning bar, baz')
|
556
|
-
* records = [
|
557
|
-
* [1, 2],
|
558
|
-
* [3, 4]
|
559
|
-
* ]
|
560
|
-
* q.batch_query_single_column(records)
|
561
|
-
* #=> [{ bar: 1, baz: 2 }, { bar: 3, baz: 4}]
|
562
|
-
* *
|
563
|
-
* @param sql [String] query SQL
|
564
|
-
* @param parameters [Array<Array, Hash>, Enumerable, Enumerator, Callable] parameters to run query with
|
565
|
-
* @return [Array<Hash>, Integer] Total number of changes effected
|
566
|
-
*/
|
567
|
-
VALUE Query_batch_query_single_column(VALUE self, VALUE parameters) {
|
568
|
-
Query_t *query = self_to_query(self);
|
569
|
-
if (query->closed) rb_raise(cError, "Query is closed");
|
570
|
-
|
571
|
-
if (!query->stmt)
|
572
|
-
prepare_single_stmt(query->sqlite3_db, &query->stmt, query->sql);
|
573
|
-
|
574
|
-
query_ctx ctx = QUERY_CTX(
|
575
|
-
self,
|
576
|
-
query->db_struct,
|
577
|
-
query->stmt,
|
578
|
-
parameters,
|
579
|
-
QUERY_MODE(QUERY_MULTI_ROW),
|
580
|
-
ALL_ROWS
|
581
|
-
);
|
582
|
-
return safe_batch_query_single_column(&ctx);
|
583
|
-
}
|
584
|
-
|
585
449
|
/* Returns the database associated with the query.
|
586
450
|
*
|
587
451
|
* @overload database()
|
@@ -623,7 +487,12 @@ VALUE Query_columns(VALUE self) {
|
|
623
487
|
*/
|
624
488
|
VALUE Query_clone(VALUE self) {
|
625
489
|
Query_t *query = self_to_query(self);
|
626
|
-
|
490
|
+
VALUE args[] = {
|
491
|
+
query->db,
|
492
|
+
query->sql,
|
493
|
+
query_mode_to_symbol(query->query_mode)
|
494
|
+
};
|
495
|
+
return rb_funcall_with_block(cQuery, ID_new, 3, args, query->transform_proc);
|
627
496
|
}
|
628
497
|
|
629
498
|
/* Closes the query. Attempting to run a closed query will raise an error.
|
@@ -670,12 +539,33 @@ VALUE Query_status(int argc, VALUE* argv, VALUE self) {
|
|
670
539
|
if (query->closed) rb_raise(cError, "Query is closed");
|
671
540
|
|
672
541
|
if (!query->stmt)
|
673
|
-
prepare_single_stmt(query->sqlite3_db, &query->stmt, query->sql);
|
542
|
+
prepare_single_stmt(DB_GVL_MODE(query), query->sqlite3_db, &query->stmt, query->sql);
|
674
543
|
|
675
544
|
int value = sqlite3_stmt_status(query->stmt, NUM2INT(op), RTEST(reset) ? 1 : 0);
|
676
545
|
return INT2NUM(value);
|
677
546
|
}
|
678
547
|
|
548
|
+
/* Sets the transform block to the given block. If a transform block is set,
|
549
|
+
* calls to #to_a, #next, #each and #batch_query will transform values fetched
|
550
|
+
* from the database using the transform block before passing them to the
|
551
|
+
* application code. To remove the transform block, call `#transform`
|
552
|
+
* without a block. The transform for each row is done by passing the row hash
|
553
|
+
* to the block.
|
554
|
+
*
|
555
|
+
* # fetch column c as an ORM object
|
556
|
+
* q = db.prepare('select * from foo order by a').transform do |h|
|
557
|
+
* MyModel.new(h)
|
558
|
+
* end
|
559
|
+
*
|
560
|
+
* @return [Extralite::Query] query
|
561
|
+
*/
|
562
|
+
VALUE Query_transform(VALUE self) {
|
563
|
+
Query_t *query = self_to_query(self);
|
564
|
+
|
565
|
+
RB_OBJ_WRITE(self, &query->transform_proc, rb_block_given_p() ? rb_block_proc() : Qnil);
|
566
|
+
return self;
|
567
|
+
}
|
568
|
+
|
679
569
|
/* Returns a short string representation of the query instance, including the
|
680
570
|
* SQL string.
|
681
571
|
*
|
@@ -694,50 +584,67 @@ VALUE Query_inspect(VALUE self) {
|
|
694
584
|
return rb_sprintf("#<%"PRIsVALUE":%p %"PRIsVALUE">", cname, (void*)self, sql);
|
695
585
|
}
|
696
586
|
|
587
|
+
/* Returns the query mode.
|
588
|
+
*
|
589
|
+
* @return [Symbol] query mode
|
590
|
+
*/
|
591
|
+
VALUE Query_mode_get(VALUE self) {
|
592
|
+
Query_t *query = self_to_query(self);
|
593
|
+
return query_mode_to_symbol(query->query_mode);
|
594
|
+
}
|
595
|
+
|
596
|
+
/* Sets the query mode. This can be one of `:hash`, `:argv`, `:ary`.
|
597
|
+
*
|
598
|
+
* @param [Symbol] query mode
|
599
|
+
* @return [Symbol] query mode
|
600
|
+
*/
|
601
|
+
VALUE Query_mode_set(VALUE self, VALUE mode) {
|
602
|
+
Query_t *query = self_to_query(self);
|
603
|
+
query->query_mode = symbol_to_query_mode(mode);
|
604
|
+
return mode;
|
605
|
+
}
|
606
|
+
|
697
607
|
void Init_ExtraliteQuery(void) {
|
698
608
|
VALUE mExtralite = rb_define_module("Extralite");
|
699
609
|
|
700
610
|
cQuery = rb_define_class_under(mExtralite, "Query", rb_cObject);
|
701
611
|
rb_define_alloc_func(cQuery, Query_allocate);
|
702
612
|
|
703
|
-
rb_define_method(cQuery,
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
rb_define_method(cQuery, "next_hash", Query_next_hash, -1);
|
730
|
-
rb_define_method(cQuery, "next_single_column", Query_next_single_column, -1);
|
731
|
-
|
732
|
-
rb_define_method(cQuery, "reset", Query_reset, 0);
|
733
|
-
rb_define_method(cQuery, "sql", Query_sql, 0);
|
734
|
-
rb_define_method(cQuery, "status", Query_status, -1);
|
735
|
-
|
736
|
-
rb_define_method(cQuery, "to_a", Query_to_a_hash, 0);
|
737
|
-
rb_define_method(cQuery, "to_a_ary", Query_to_a_ary, 0);
|
738
|
-
rb_define_method(cQuery, "to_a_hash", Query_to_a_hash, 0);
|
739
|
-
rb_define_method(cQuery, "to_a_single_column", Query_to_a_single_column, 0);
|
613
|
+
#define DEF(s, f, a) rb_define_method(cQuery, s, f, a)
|
614
|
+
|
615
|
+
DEF("bind", Query_bind, -1);
|
616
|
+
DEF("close", Query_close, 0);
|
617
|
+
DEF("closed?", Query_closed_p, 0);
|
618
|
+
DEF("columns", Query_columns, 0);
|
619
|
+
DEF("clone", Query_clone, 0);
|
620
|
+
DEF("database", Query_database, 0);
|
621
|
+
DEF("db", Query_database, 0);
|
622
|
+
DEF("dup", Query_clone, 0);
|
623
|
+
DEF("each", Query_each, 0);
|
624
|
+
DEF("eof?", Query_eof_p, 0);
|
625
|
+
DEF("execute", Query_execute, -1);
|
626
|
+
DEF("<<", Query_execute_chevrons, 1);
|
627
|
+
DEF("batch_execute", Query_batch_execute, 1);
|
628
|
+
DEF("batch_query", Query_batch_query, 1);
|
629
|
+
DEF("initialize", Query_initialize, 3);
|
630
|
+
DEF("inspect", Query_inspect, 0);
|
631
|
+
DEF("mode", Query_mode_get, 0);
|
632
|
+
DEF("mode=", Query_mode_set, 1);
|
633
|
+
DEF("next", Query_next, -1);
|
634
|
+
DEF("reset", Query_reset, 0);
|
635
|
+
DEF("sql", Query_sql, 0);
|
636
|
+
DEF("status", Query_status, -1);
|
637
|
+
DEF("to_a", Query_to_a, 0);
|
638
|
+
DEF("transform", Query_transform, 0);
|
740
639
|
|
741
640
|
ID_inspect = rb_intern("inspect");
|
742
641
|
ID_slice = rb_intern("slice");
|
642
|
+
|
643
|
+
SYM_hash = ID2SYM(rb_intern("hash"));
|
644
|
+
SYM_argv = ID2SYM(rb_intern("argv"));
|
645
|
+
SYM_ary = ID2SYM(rb_intern("ary"));
|
646
|
+
|
647
|
+
rb_gc_register_mark_object(SYM_hash);
|
648
|
+
rb_gc_register_mark_object(SYM_argv);
|
649
|
+
rb_gc_register_mark_object(SYM_ary);
|
743
650
|
}
|
data/extralite-bundle.gemspec
CHANGED
data/extralite.gemspec
CHANGED