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