extralite-bundle 2.3 → 2.4
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/.editorconfig +6 -0
- data/.github/workflows/test.yml +15 -1
- data/.gitignore +3 -0
- data/CHANGELOG.md +12 -0
- data/Gemfile-bundle +5 -0
- data/Gemfile.lock +3 -3
- data/README.md +69 -10
- data/bin/update_sqlite_source +10 -3
- data/ext/extralite/common.c +67 -23
- data/ext/extralite/database.c +74 -26
- data/ext/extralite/extralite.h +15 -8
- data/ext/extralite/iterator.c +5 -5
- data/ext/extralite/query.c +37 -29
- data/ext/sqlite3/sqlite3.c +196 -90
- data/ext/sqlite3/sqlite3.h +55 -12
- data/lib/extralite/version.rb +1 -1
- data/lib/extralite.rb +27 -0
- data/test/fixtures/image.png +0 -0
- data/test/helper.rb +2 -0
- data/test/issue-38.rb +80 -0
- data/test/perf_ary.rb +6 -3
- data/test/perf_hash.rb +7 -4
- data/test/test_database.rb +256 -4
- data/test/test_iterator.rb +2 -1
- data/test/test_query.rb +40 -4
- metadata +6 -2
data/ext/extralite/database.c
CHANGED
@@ -1,11 +1,14 @@
|
|
1
1
|
#include <stdio.h>
|
2
|
+
#include <stdlib.h>
|
2
3
|
#include "extralite.h"
|
3
4
|
|
4
5
|
VALUE cDatabase;
|
6
|
+
VALUE cBlob;
|
5
7
|
VALUE cError;
|
6
8
|
VALUE cSQLError;
|
7
9
|
VALUE cBusyError;
|
8
10
|
VALUE cInterruptError;
|
11
|
+
VALUE cParameterError;
|
9
12
|
VALUE eArgumentError;
|
10
13
|
|
11
14
|
ID ID_bind;
|
@@ -13,7 +16,6 @@ ID ID_call;
|
|
13
16
|
ID ID_keys;
|
14
17
|
ID ID_new;
|
15
18
|
ID ID_strip;
|
16
|
-
ID ID_to_s;
|
17
19
|
|
18
20
|
VALUE SYM_read_only;
|
19
21
|
|
@@ -21,6 +23,11 @@ static size_t Database_size(const void *ptr) {
|
|
21
23
|
return sizeof(Database_t);
|
22
24
|
}
|
23
25
|
|
26
|
+
static void Database_mark(void *ptr) {
|
27
|
+
Database_t *db = ptr;
|
28
|
+
rb_gc_mark(db->trace_block);
|
29
|
+
}
|
30
|
+
|
24
31
|
static void Database_free(void *ptr) {
|
25
32
|
Database_t *db = ptr;
|
26
33
|
if (db->sqlite3_db) sqlite3_close_v2(db->sqlite3_db);
|
@@ -29,8 +36,8 @@ static void Database_free(void *ptr) {
|
|
29
36
|
|
30
37
|
static const rb_data_type_t Database_type = {
|
31
38
|
"Database",
|
32
|
-
{
|
33
|
-
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
|
39
|
+
{Database_mark, Database_free, Database_size,},
|
40
|
+
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
|
34
41
|
};
|
35
42
|
|
36
43
|
static VALUE Database_allocate(VALUE klass) {
|
@@ -48,7 +55,7 @@ inline Database_t *self_to_database(VALUE self) {
|
|
48
55
|
inline Database_t *self_to_open_database(VALUE self) {
|
49
56
|
Database_t *db = self_to_database(self);
|
50
57
|
if (!(db)->sqlite3_db) rb_raise(cError, "Database is closed");
|
51
|
-
|
58
|
+
|
52
59
|
return db;
|
53
60
|
}
|
54
61
|
|
@@ -118,6 +125,7 @@ VALUE Database_initialize(int argc, VALUE *argv, VALUE self) {
|
|
118
125
|
#endif
|
119
126
|
|
120
127
|
db->trace_block = Qnil;
|
128
|
+
db->gvl_release_threshold = DEFAULT_GVL_RELEASE_THRESHOLD;
|
121
129
|
|
122
130
|
return Qnil;
|
123
131
|
}
|
@@ -178,8 +186,8 @@ static inline VALUE Database_perform_query(int argc, VALUE *argv, VALUE self, VA
|
|
178
186
|
RB_GC_GUARD(sql);
|
179
187
|
|
180
188
|
bind_all_parameters(stmt, argc - 1, argv + 1);
|
181
|
-
query_ctx ctx =
|
182
|
-
|
189
|
+
query_ctx ctx = QUERY_CTX(self, db, stmt, Qnil, QUERY_MODE(QUERY_MULTI_ROW), ALL_ROWS);
|
190
|
+
|
183
191
|
return rb_ensure(SAFE(call), (VALUE)&ctx, SAFE(cleanup_stmt), (VALUE)&ctx);
|
184
192
|
}
|
185
193
|
|
@@ -190,18 +198,18 @@ static inline VALUE Database_perform_query(int argc, VALUE *argv, VALUE self, VA
|
|
190
198
|
* Runs a query returning rows as hashes (with symbol keys). If a block is
|
191
199
|
* given, it will be called for each row. Otherwise, an array containing all
|
192
200
|
* rows is returned.
|
193
|
-
*
|
201
|
+
*
|
194
202
|
* Query parameters to be bound to placeholders in the query can be specified as
|
195
203
|
* a list of values or as a hash mapping parameter names to values. When
|
196
204
|
* parameters are given as an array, the query should specify parameters using
|
197
205
|
* `?`:
|
198
|
-
*
|
206
|
+
*
|
199
207
|
* db.query('select * from foo where x = ?', 42)
|
200
208
|
*
|
201
209
|
* Named placeholders are specified using `:`. The placeholder values are
|
202
210
|
* specified using a hash, where keys are either strings are symbols. String
|
203
211
|
* keys can include or omit the `:` prefix. The following are equivalent:
|
204
|
-
*
|
212
|
+
*
|
205
213
|
* db.query('select * from foo where x = :bar', bar: 42)
|
206
214
|
* db.query('select * from foo where x = :bar', 'bar' => 42)
|
207
215
|
* db.query('select * from foo where x = :bar', ':bar' => 42)
|
@@ -355,7 +363,7 @@ VALUE Database_execute_multi(VALUE self, VALUE sql, VALUE params_array) {
|
|
355
363
|
|
356
364
|
// prepare query ctx
|
357
365
|
prepare_single_stmt(db->sqlite3_db, &stmt, sql);
|
358
|
-
query_ctx ctx =
|
366
|
+
query_ctx ctx = QUERY_CTX(self, db, stmt, params_array, QUERY_MULTI_ROW, ALL_ROWS);
|
359
367
|
|
360
368
|
return rb_ensure(SAFE(safe_execute_multi), (VALUE)&ctx, SAFE(cleanup_stmt), (VALUE)&ctx);
|
361
369
|
}
|
@@ -391,10 +399,10 @@ VALUE Database_changes(VALUE self) {
|
|
391
399
|
return INT2FIX(sqlite3_changes(db->sqlite3_db));
|
392
400
|
}
|
393
401
|
|
394
|
-
/* call-seq:
|
395
|
-
* db.filename -> string
|
402
|
+
/* call-seq: db.filename -> string db.filename(db_name) -> string
|
396
403
|
*
|
397
|
-
* Returns the database filename.
|
404
|
+
* Returns the database filename. If db_name is given, returns the filename for
|
405
|
+
* the respective attached database.
|
398
406
|
*/
|
399
407
|
VALUE Database_filename(int argc, VALUE *argv, VALUE self) {
|
400
408
|
const char *db_name;
|
@@ -480,13 +488,13 @@ typedef struct {
|
|
480
488
|
#define BACKUP_STEP_MAX_PAGES 16
|
481
489
|
#define BACKUP_SLEEP_MS 100
|
482
490
|
|
483
|
-
void *
|
491
|
+
void *backup_step_impl(void *ptr) {
|
484
492
|
backup_ctx *ctx = (backup_ctx *)ptr;
|
485
493
|
ctx->rc = sqlite3_backup_step(ctx->backup, BACKUP_STEP_MAX_PAGES);
|
486
494
|
return NULL;
|
487
495
|
}
|
488
496
|
|
489
|
-
void *
|
497
|
+
void *backup_sleep_impl(void *unused) {
|
490
498
|
sqlite3_sleep(BACKUP_SLEEP_MS);
|
491
499
|
return NULL;
|
492
500
|
}
|
@@ -496,7 +504,7 @@ VALUE backup_safe_iterate(VALUE ptr) {
|
|
496
504
|
int done = 0;
|
497
505
|
|
498
506
|
while (!done) {
|
499
|
-
|
507
|
+
gvl_call(GVL_RELEASE, backup_step_impl, (void *)ctx);
|
500
508
|
switch(ctx->rc) {
|
501
509
|
case SQLITE_DONE:
|
502
510
|
if (ctx->block_given) {
|
@@ -514,7 +522,7 @@ VALUE backup_safe_iterate(VALUE ptr) {
|
|
514
522
|
continue;
|
515
523
|
case SQLITE_BUSY:
|
516
524
|
case SQLITE_LOCKED:
|
517
|
-
|
525
|
+
gvl_call(GVL_RELEASE, backup_sleep_impl, NULL);
|
518
526
|
continue;
|
519
527
|
default:
|
520
528
|
rb_raise(cError, "%s", sqlite3_errstr(ctx->rc));
|
@@ -689,7 +697,7 @@ VALUE Database_total_changes(VALUE self) {
|
|
689
697
|
VALUE Database_trace(VALUE self) {
|
690
698
|
Database_t *db = self_to_open_database(self);
|
691
699
|
|
692
|
-
db->trace_block
|
700
|
+
RB_OBJ_WRITE(self, &db->trace_block, rb_block_given_p() ? rb_block_proc() : Qnil);
|
693
701
|
return self;
|
694
702
|
}
|
695
703
|
|
@@ -734,11 +742,51 @@ VALUE Database_error_offset(VALUE self) {
|
|
734
742
|
* @return [String] string representation
|
735
743
|
*/
|
736
744
|
VALUE Database_inspect(VALUE self) {
|
745
|
+
Database_t *db = self_to_database(self);
|
737
746
|
VALUE cname = rb_class_name(CLASS_OF(self));
|
738
|
-
VALUE filename = Database_filename(0, NULL, self);
|
739
|
-
if (RSTRING_LEN(filename) == 0) filename = rb_str_new_literal(":memory:");
|
740
747
|
|
741
|
-
|
748
|
+
if (!(db)->sqlite3_db)
|
749
|
+
return rb_sprintf("#<%"PRIsVALUE":%p (closed)>", cname, (void*)self);
|
750
|
+
else {
|
751
|
+
VALUE filename = Database_filename(0, NULL, self);
|
752
|
+
if (RSTRING_LEN(filename) == 0) filename = rb_str_new_literal(":memory:");
|
753
|
+
return rb_sprintf("#<%"PRIsVALUE":%p %"PRIsVALUE">", cname, (void*)self, filename);
|
754
|
+
}
|
755
|
+
}
|
756
|
+
|
757
|
+
/* Returns the database's GVL release threshold.
|
758
|
+
*
|
759
|
+
* @return [Integer] GVL release threshold
|
760
|
+
*/
|
761
|
+
VALUE Database_gvl_release_threshold_get(VALUE self) {
|
762
|
+
Database_t *db = self_to_open_database(self);
|
763
|
+
return INT2NUM(db->gvl_release_threshold);
|
764
|
+
}
|
765
|
+
|
766
|
+
/* Sets the database's GVL release threshold. To always hold the GVL while
|
767
|
+
* running a query, set the threshold to 0. To release the GVL on each record,
|
768
|
+
* set the threshold to 1. Larger values mean the GVL will be released less
|
769
|
+
* often, e.g. a value of 10 means the GVL will be released every 10 records
|
770
|
+
* iterated. A value of nil sets the threshold to the default value, which is
|
771
|
+
* currently 1000.
|
772
|
+
*
|
773
|
+
* @return [Integer, nil] New GVL release threshold
|
774
|
+
*/
|
775
|
+
VALUE Database_gvl_release_threshold_set(VALUE self, VALUE value) {
|
776
|
+
Database_t *db = self_to_open_database(self);
|
777
|
+
|
778
|
+
switch (TYPE(value)) {
|
779
|
+
case T_FIXNUM:
|
780
|
+
db->gvl_release_threshold = NUM2INT(value);
|
781
|
+
break;
|
782
|
+
case T_NIL:
|
783
|
+
db->gvl_release_threshold = DEFAULT_GVL_RELEASE_THRESHOLD;
|
784
|
+
break;
|
785
|
+
default:
|
786
|
+
rb_raise(eArgumentError, "Invalid GVL release threshold value (expect integer or nil)");
|
787
|
+
}
|
788
|
+
|
789
|
+
return INT2NUM(db->gvl_release_threshold);
|
742
790
|
}
|
743
791
|
|
744
792
|
void Init_ExtraliteDatabase(void) {
|
@@ -765,6 +813,8 @@ void Init_ExtraliteDatabase(void) {
|
|
765
813
|
rb_define_method(cDatabase, "execute", Database_execute, -1);
|
766
814
|
rb_define_method(cDatabase, "execute_multi", Database_execute_multi, 2);
|
767
815
|
rb_define_method(cDatabase, "filename", Database_filename, -1);
|
816
|
+
rb_define_method(cDatabase, "gvl_release_threshold", Database_gvl_release_threshold_get, 0);
|
817
|
+
rb_define_method(cDatabase, "gvl_release_threshold=", Database_gvl_release_threshold_set, 1);
|
768
818
|
rb_define_method(cDatabase, "initialize", Database_initialize, -1);
|
769
819
|
rb_define_method(cDatabase, "inspect", Database_inspect, 0);
|
770
820
|
rb_define_method(cDatabase, "interrupt", Database_interrupt, 0);
|
@@ -787,14 +837,13 @@ void Init_ExtraliteDatabase(void) {
|
|
787
837
|
rb_define_method(cDatabase, "load_extension", Database_load_extension, 1);
|
788
838
|
#endif
|
789
839
|
|
840
|
+
cBlob = rb_define_class_under(mExtralite, "Blob", rb_cString);
|
841
|
+
|
790
842
|
cError = rb_define_class_under(mExtralite, "Error", rb_eStandardError);
|
791
843
|
cSQLError = rb_define_class_under(mExtralite, "SQLError", cError);
|
792
844
|
cBusyError = rb_define_class_under(mExtralite, "BusyError", cError);
|
793
845
|
cInterruptError = rb_define_class_under(mExtralite, "InterruptError", cError);
|
794
|
-
|
795
|
-
rb_gc_register_mark_object(cSQLError);
|
796
|
-
rb_gc_register_mark_object(cBusyError);
|
797
|
-
rb_gc_register_mark_object(cInterruptError);
|
846
|
+
cParameterError = rb_define_class_under(mExtralite, "ParameterError", cError);
|
798
847
|
|
799
848
|
eArgumentError = rb_const_get(rb_cObject, rb_intern("ArgumentError"));
|
800
849
|
|
@@ -803,7 +852,6 @@ void Init_ExtraliteDatabase(void) {
|
|
803
852
|
ID_keys = rb_intern("keys");
|
804
853
|
ID_new = rb_intern("new");
|
805
854
|
ID_strip = rb_intern("strip");
|
806
|
-
ID_to_s = rb_intern("to_s");
|
807
855
|
|
808
856
|
SYM_read_only = ID2SYM(rb_intern("read_only"));
|
809
857
|
rb_gc_register_mark_object(SYM_read_only);
|
data/ext/extralite/extralite.h
CHANGED
@@ -23,17 +23,18 @@
|
|
23
23
|
extern VALUE cDatabase;
|
24
24
|
extern VALUE cQuery;
|
25
25
|
extern VALUE cIterator;
|
26
|
+
extern VALUE cBlob;
|
26
27
|
|
27
28
|
extern VALUE cError;
|
28
29
|
extern VALUE cSQLError;
|
29
30
|
extern VALUE cBusyError;
|
30
31
|
extern VALUE cInterruptError;
|
32
|
+
extern VALUE cParameterError;
|
31
33
|
|
32
34
|
extern ID ID_call;
|
33
35
|
extern ID ID_keys;
|
34
36
|
extern ID ID_new;
|
35
37
|
extern ID ID_strip;
|
36
|
-
extern ID ID_to_s;
|
37
38
|
|
38
39
|
extern VALUE SYM_hash;
|
39
40
|
extern VALUE SYM_ary;
|
@@ -42,6 +43,7 @@ extern VALUE SYM_single_column;
|
|
42
43
|
typedef struct {
|
43
44
|
sqlite3 *sqlite3_db;
|
44
45
|
VALUE trace_block;
|
46
|
+
int gvl_release_threshold;
|
45
47
|
} Database_t;
|
46
48
|
|
47
49
|
typedef struct {
|
@@ -79,19 +81,22 @@ typedef struct {
|
|
79
81
|
enum query_mode mode;
|
80
82
|
int max_rows;
|
81
83
|
int eof;
|
84
|
+
int gvl_release_threshold;
|
85
|
+
int step_count;
|
82
86
|
} query_ctx;
|
83
87
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
} backup_t;
|
88
|
+
enum gvl_mode {
|
89
|
+
GVL_RELEASE,
|
90
|
+
GVL_HOLD
|
91
|
+
};
|
89
92
|
|
90
|
-
#define TUPLE_MAX_EMBEDDED_VALUES 20
|
91
93
|
#define ALL_ROWS -1
|
92
94
|
#define SINGLE_ROW -2
|
93
95
|
#define QUERY_MODE(default) (rb_block_given_p() ? QUERY_YIELD : default)
|
94
96
|
#define MULTI_ROW_P(mode) (mode == QUERY_MULTI_ROW)
|
97
|
+
#define QUERY_CTX(self, db, stmt, params, mode, max_rows) \
|
98
|
+
{ self, db->sqlite3_db, stmt, params, mode, max_rows, 0, db->gvl_release_threshold, 0 }
|
99
|
+
#define DEFAULT_GVL_RELEASE_THRESHOLD 1000
|
95
100
|
|
96
101
|
extern rb_encoding *UTF8_ENCODING;
|
97
102
|
|
@@ -126,4 +131,6 @@ VALUE cleanup_stmt(query_ctx *ctx);
|
|
126
131
|
sqlite3 *Database_sqlite3_db(VALUE self);
|
127
132
|
Database_t *self_to_database(VALUE self);
|
128
133
|
|
129
|
-
|
134
|
+
void *gvl_call(enum gvl_mode mode, void *(*fn)(void *), void *data);
|
135
|
+
|
136
|
+
#endif /* EXTRALITE_H */
|
data/ext/extralite/iterator.c
CHANGED
@@ -52,7 +52,7 @@ static inline enum iterator_mode symbol_to_mode(VALUE sym) {
|
|
52
52
|
* iteration mode is one of: `:hash`, `:ary`, or `:single_column`. An iterator
|
53
53
|
* is normally returned from one of the methods `Query#each`/`Query#each_hash`,
|
54
54
|
* `Query#each_ary` or `Query#each_single_column` when called without a block:
|
55
|
-
*
|
55
|
+
*
|
56
56
|
* iterator = query.each
|
57
57
|
* ...
|
58
58
|
*
|
@@ -115,12 +115,12 @@ inline next_method mode_to_next_method(enum iterator_mode mode) {
|
|
115
115
|
|
116
116
|
/* Returns the next 1 or more rows from the associated query's result set
|
117
117
|
* according to the iteration mode, i.e. as a hash, an array or a single value.
|
118
|
-
*
|
118
|
+
*
|
119
119
|
* If no row count is given, a single row is returned. If a row count is given,
|
120
120
|
* an array containing up to the `row_count` rows is returned. If `row_count` is
|
121
121
|
* -1, all rows are returned. If the end of the result set has been reached,
|
122
122
|
* `nil` is returned.
|
123
|
-
*
|
123
|
+
*
|
124
124
|
* If a block is given, rows are passed to the block and self is returned.
|
125
125
|
*
|
126
126
|
* @overload next()
|
@@ -152,7 +152,7 @@ inline to_a_method mode_to_to_a_method(enum iterator_mode mode) {
|
|
152
152
|
|
153
153
|
/* Returns all rows from the associated query's result set according to the
|
154
154
|
* iteration mode, i.e. as a hash, an array or a single value.
|
155
|
-
*
|
155
|
+
*
|
156
156
|
* @return [Array] array of query result set rows
|
157
157
|
*/
|
158
158
|
VALUE Iterator_to_a(VALUE self) {
|
@@ -180,7 +180,7 @@ inline VALUE mode_to_symbol(Iterator_t *iterator) {
|
|
180
180
|
VALUE Iterator_inspect(VALUE self) {
|
181
181
|
VALUE cname = rb_class_name(CLASS_OF(self));
|
182
182
|
VALUE sym = mode_to_symbol(self_to_iterator(self));
|
183
|
-
|
183
|
+
|
184
184
|
return rb_sprintf("#<%"PRIsVALUE":%p %"PRIsVALUE">", cname, (void*)self, sym);
|
185
185
|
}
|
186
186
|
|
data/ext/extralite/query.c
CHANGED
@@ -33,7 +33,7 @@ static void Query_free(void *ptr) {
|
|
33
33
|
static const rb_data_type_t Query_type = {
|
34
34
|
"Query",
|
35
35
|
{Query_mark, Query_free, Query_size,},
|
36
|
-
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
|
36
|
+
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
|
37
37
|
};
|
38
38
|
|
39
39
|
static VALUE Query_allocate(VALUE klass) {
|
@@ -67,10 +67,12 @@ VALUE Query_initialize(VALUE self, VALUE db, VALUE sql) {
|
|
67
67
|
if (!RSTRING_LEN(sql))
|
68
68
|
rb_raise(cError, "Cannot prepare an empty SQL query");
|
69
69
|
|
70
|
+
RB_OBJ_WRITE(self, &query->db, db);
|
71
|
+
RB_OBJ_WRITE(self, &query->sql, sql);
|
72
|
+
|
70
73
|
query->db = db;
|
71
74
|
query->db_struct = self_to_database(db);
|
72
75
|
query->sqlite3_db = Database_sqlite3_db(db);
|
73
|
-
query->sql = sql;
|
74
76
|
query->stmt = NULL;
|
75
77
|
query->closed = 0;
|
76
78
|
query->eof = 0;
|
@@ -134,14 +136,14 @@ VALUE Query_reset(VALUE self) {
|
|
134
136
|
* Bound parameters can be specified as a list of values or as a hash mapping
|
135
137
|
* parameter names to values. When parameters are given as a splatted array, the
|
136
138
|
* query should specify parameters using `?`:
|
137
|
-
*
|
139
|
+
*
|
138
140
|
* query = db.prepare('select * from foo where x = ?')
|
139
141
|
* query.bind(42)
|
140
142
|
*
|
141
143
|
* Named placeholders are specified using `:`. The placeholder values are
|
142
144
|
* specified using a hash, where keys are either strings are symbols. String
|
143
145
|
* keys can include or omit the `:` prefix. The following are equivalent:
|
144
|
-
*
|
146
|
+
*
|
145
147
|
* query = db.prepare('select * from foo where x = :bar')
|
146
148
|
* query.bind(bar: 42)
|
147
149
|
*
|
@@ -171,19 +173,18 @@ VALUE Query_eof_p(VALUE self) {
|
|
171
173
|
static inline VALUE Query_perform_next(VALUE self, int max_rows, VALUE (*call)(query_ctx *)) {
|
172
174
|
Query_t *query = self_to_query(self);
|
173
175
|
if (query->closed) rb_raise(cError, "Query is closed");
|
174
|
-
|
176
|
+
|
175
177
|
if (!query->stmt) query_reset(query);
|
176
178
|
if (query->eof) return rb_block_given_p() ? self : Qnil;
|
177
179
|
|
178
|
-
query_ctx ctx =
|
180
|
+
query_ctx ctx = QUERY_CTX(
|
179
181
|
self,
|
180
|
-
query->
|
182
|
+
query->db_struct,
|
181
183
|
query->stmt,
|
182
184
|
Qnil,
|
183
185
|
QUERY_MODE(max_rows == SINGLE_ROW ? QUERY_SINGLE_ROW : QUERY_MULTI_ROW),
|
184
|
-
MAX_ROWS(max_rows)
|
185
|
-
|
186
|
-
};
|
186
|
+
MAX_ROWS(max_rows)
|
187
|
+
);
|
187
188
|
VALUE result = call(&ctx);
|
188
189
|
query->eof = ctx.eof;
|
189
190
|
return (ctx.mode == QUERY_YIELD) ? self : result;
|
@@ -193,12 +194,12 @@ static inline VALUE Query_perform_next(VALUE self, int max_rows, VALUE (*call)(q
|
|
193
194
|
|
194
195
|
/* Returns the next 1 or more rows from the associated query's result set as a
|
195
196
|
* hash.
|
196
|
-
*
|
197
|
+
*
|
197
198
|
* If no row count is given, a single row is returned. If a row count is given,
|
198
199
|
* an array containing up to the `row_count` rows is returned. If `row_count` is
|
199
200
|
* -1, all rows are returned. If the end of the result set has been reached,
|
200
201
|
* `nil` is returned.
|
201
|
-
*
|
202
|
+
*
|
202
203
|
* If a block is given, rows are passed to the block and self is returned.
|
203
204
|
*
|
204
205
|
* @overload next()
|
@@ -219,12 +220,12 @@ VALUE Query_next_hash(int argc, VALUE *argv, VALUE self) {
|
|
219
220
|
|
220
221
|
/* Returns the next 1 or more rows from the associated query's result set as an
|
221
222
|
* array.
|
222
|
-
*
|
223
|
+
*
|
223
224
|
* If no row count is given, a single row is returned. If a row count is given,
|
224
225
|
* an array containing up to the `row_count` rows is returned. If `row_count` is
|
225
226
|
* -1, all rows are returned. If the end of the result set has been reached,
|
226
227
|
* `nil` is returned.
|
227
|
-
*
|
228
|
+
*
|
228
229
|
* If a block is given, rows are passed to the block and self is returned.
|
229
230
|
*
|
230
231
|
* @overload next_ary()
|
@@ -241,12 +242,12 @@ VALUE Query_next_ary(int argc, VALUE *argv, VALUE self) {
|
|
241
242
|
/* Returns the next 1 or more rows from the associated query's result set as an
|
242
243
|
* single values. If the result set contains more than one column an error is
|
243
244
|
* raised.
|
244
|
-
*
|
245
|
+
*
|
245
246
|
* If no row count is given, a single row is returned. If a row count is given,
|
246
247
|
* an array containing up to the `row_count` rows is returned. If `row_count` is
|
247
248
|
* -1, all rows are returned. If the end of the result set has been reached,
|
248
249
|
* `nil` is returned.
|
249
|
-
*
|
250
|
+
*
|
250
251
|
* If a block is given, rows are passed to the block and self is returned.
|
251
252
|
*
|
252
253
|
* @overload next_ary()
|
@@ -261,7 +262,7 @@ VALUE Query_next_single_column(int argc, VALUE *argv, VALUE self) {
|
|
261
262
|
}
|
262
263
|
|
263
264
|
/* Returns all rows in the associated query's result set as hashes.
|
264
|
-
*
|
265
|
+
*
|
265
266
|
* @overload to_a()
|
266
267
|
* @return [Array<Hash>] all rows
|
267
268
|
* @overload to_a_hash
|
@@ -274,7 +275,7 @@ VALUE Query_to_a_hash(VALUE self) {
|
|
274
275
|
}
|
275
276
|
|
276
277
|
/* Returns all rows in the associated query's result set as arrays.
|
277
|
-
*
|
278
|
+
*
|
278
279
|
* @return [Array<Array>] all rows
|
279
280
|
*/
|
280
281
|
VALUE Query_to_a_ary(VALUE self) {
|
@@ -285,7 +286,7 @@ VALUE Query_to_a_ary(VALUE self) {
|
|
285
286
|
|
286
287
|
/* Returns all rows in the associated query's result set as single values. If
|
287
288
|
* the result set contains more than one column an error is raised.
|
288
|
-
*
|
289
|
+
*
|
289
290
|
* @return [Array<Object>] all rows
|
290
291
|
*/
|
291
292
|
VALUE Query_to_a_single_column(VALUE self) {
|
@@ -297,7 +298,7 @@ VALUE Query_to_a_single_column(VALUE self) {
|
|
297
298
|
/* Iterates through the result set, passing each row to the given block as a
|
298
299
|
* hash. If no block is given, returns a `Extralite::Iterator` instance in hash
|
299
300
|
* mode.
|
300
|
-
*
|
301
|
+
*
|
301
302
|
* @return [Extralite::Query, Extralite::Iterator] self or an iterator if no block is given
|
302
303
|
*/
|
303
304
|
VALUE Query_each_hash(VALUE self) {
|
@@ -311,7 +312,7 @@ VALUE Query_each_hash(VALUE self) {
|
|
311
312
|
/* Iterates through the result set, passing each row to the given block as an
|
312
313
|
* array. If no block is given, returns a `Extralite::Iterator` instance in
|
313
314
|
* array mode.
|
314
|
-
*
|
315
|
+
*
|
315
316
|
* @return [Extralite::Query, Extralite::Iterator] self or an iterator if no block is given
|
316
317
|
*/
|
317
318
|
VALUE Query_each_ary(VALUE self) {
|
@@ -326,7 +327,7 @@ VALUE Query_each_ary(VALUE self) {
|
|
326
327
|
* single value. If the result set contains more than one column an error is
|
327
328
|
* raised. If no block is given, returns a `Extralite::Iterator` instance in
|
328
329
|
* single column mode.
|
329
|
-
*
|
330
|
+
*
|
330
331
|
* @return [Extralite::Query, Extralite::Iterator] self or an iterator if no block is given
|
331
332
|
*/
|
332
333
|
VALUE Query_each_single_column(VALUE self) {
|
@@ -388,7 +389,14 @@ VALUE Query_execute_multi(VALUE self, VALUE parameters) {
|
|
388
389
|
if (!query->stmt)
|
389
390
|
prepare_single_stmt(query->sqlite3_db, &query->stmt, query->sql);
|
390
391
|
|
391
|
-
query_ctx ctx =
|
392
|
+
query_ctx ctx = QUERY_CTX(
|
393
|
+
self,
|
394
|
+
query->db_struct,
|
395
|
+
query->stmt,
|
396
|
+
parameters,
|
397
|
+
QUERY_MODE(QUERY_MULTI_ROW),
|
398
|
+
ALL_ROWS
|
399
|
+
);
|
392
400
|
return safe_execute_multi(&ctx);
|
393
401
|
}
|
394
402
|
|
@@ -405,7 +413,7 @@ VALUE Query_database(VALUE self) {
|
|
405
413
|
}
|
406
414
|
|
407
415
|
/* Returns the SQL string for the query.
|
408
|
-
*
|
416
|
+
*
|
409
417
|
* @return [String] SQL string
|
410
418
|
*/
|
411
419
|
VALUE Query_sql(VALUE self) {
|
@@ -414,7 +422,7 @@ VALUE Query_sql(VALUE self) {
|
|
414
422
|
}
|
415
423
|
|
416
424
|
/* Returns the column names for the query without running it.
|
417
|
-
*
|
425
|
+
*
|
418
426
|
* @return [Array<Symbol>] column names
|
419
427
|
*/
|
420
428
|
VALUE Query_columns(VALUE self) {
|
@@ -424,7 +432,7 @@ VALUE Query_columns(VALUE self) {
|
|
424
432
|
}
|
425
433
|
|
426
434
|
/* Closes the query. Attempting to run a closed query will raise an error.
|
427
|
-
*
|
435
|
+
*
|
428
436
|
* @return [Extralite::Query] self
|
429
437
|
*/
|
430
438
|
VALUE Query_close(VALUE self) {
|
@@ -438,7 +446,7 @@ VALUE Query_close(VALUE self) {
|
|
438
446
|
}
|
439
447
|
|
440
448
|
/* Returns true if the query is closed.
|
441
|
-
*
|
449
|
+
*
|
442
450
|
* @return [boolean] true if query is closed
|
443
451
|
*/
|
444
452
|
VALUE Query_closed_p(VALUE self) {
|
@@ -449,7 +457,7 @@ VALUE Query_closed_p(VALUE self) {
|
|
449
457
|
/* Returns the current [status
|
450
458
|
* value](https://sqlite.org/c3ref/c_stmtstatus_counter.html) for the given op.
|
451
459
|
* To reset the value, pass true as reset.
|
452
|
-
*
|
460
|
+
*
|
453
461
|
* @overload status(op)
|
454
462
|
* @param op [Integer] status op
|
455
463
|
* @return [Integer] current status value for the given op
|
@@ -486,7 +494,7 @@ VALUE Query_inspect(VALUE self) {
|
|
486
494
|
rb_str_cat2(sql, "...");
|
487
495
|
}
|
488
496
|
sql = rb_funcall(sql, ID_inspect, 0);
|
489
|
-
|
497
|
+
|
490
498
|
RB_GC_GUARD(sql);
|
491
499
|
return rb_sprintf("#<%"PRIsVALUE":%p %"PRIsVALUE">", cname, (void*)self, sql);
|
492
500
|
}
|