extralite 1.27 → 2.1
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/CHANGELOG.md +14 -0
- data/Gemfile.lock +1 -1
- data/LICENSE +1 -1
- data/README.md +40 -14
- data/TODO.md +21 -0
- data/ext/extralite/common.c +80 -58
- data/ext/extralite/database.c +138 -78
- data/ext/extralite/extconf.rb +16 -16
- data/ext/extralite/extralite.h +63 -17
- data/ext/extralite/extralite_ext.c +4 -2
- data/ext/extralite/iterator.c +208 -0
- data/ext/extralite/query.c +534 -0
- data/lib/extralite/sqlite3_constants.rb +1 -1
- data/lib/extralite/version.rb +1 -1
- data/lib/extralite.rb +0 -2
- data/lib/sequel/adapters/extralite.rb +104 -106
- data/test/perf_prepared.rb +2 -2
- data/test/test_database.rb +35 -9
- data/test/test_extralite.rb +1 -1
- data/test/test_iterator.rb +104 -0
- data/test/test_query.rb +519 -0
- data/test/test_sequel.rb +23 -4
- metadata +6 -4
- data/ext/extralite/prepared_statement.c +0 -333
- data/test/test_prepared_statement.rb +0 -225
data/ext/extralite/extralite.h
CHANGED
@@ -20,7 +20,8 @@
|
|
20
20
|
#define SAFE(f) (VALUE (*)(VALUE))(f)
|
21
21
|
|
22
22
|
extern VALUE cDatabase;
|
23
|
-
extern VALUE
|
23
|
+
extern VALUE cQuery;
|
24
|
+
extern VALUE cIterator;
|
24
25
|
|
25
26
|
extern VALUE cError;
|
26
27
|
extern VALUE cSQLError;
|
@@ -33,48 +34,93 @@ extern ID ID_new;
|
|
33
34
|
extern ID ID_strip;
|
34
35
|
extern ID ID_to_s;
|
35
36
|
|
37
|
+
extern VALUE SYM_hash;
|
38
|
+
extern VALUE SYM_ary;
|
39
|
+
extern VALUE SYM_single_column;
|
40
|
+
|
36
41
|
typedef struct {
|
37
42
|
sqlite3 *sqlite3_db;
|
38
|
-
VALUE
|
43
|
+
VALUE trace_block;
|
39
44
|
} Database_t;
|
40
45
|
|
41
46
|
typedef struct {
|
42
|
-
VALUE
|
43
|
-
VALUE
|
44
|
-
Database_t
|
45
|
-
sqlite3
|
46
|
-
sqlite3_stmt
|
47
|
-
|
47
|
+
VALUE db;
|
48
|
+
VALUE sql;
|
49
|
+
Database_t *db_struct;
|
50
|
+
sqlite3 *sqlite3_db;
|
51
|
+
sqlite3_stmt *stmt;
|
52
|
+
int eof;
|
53
|
+
int closed;
|
54
|
+
} Query_t;
|
55
|
+
|
56
|
+
enum iterator_mode {
|
57
|
+
ITERATOR_HASH,
|
58
|
+
ITERATOR_ARY,
|
59
|
+
ITERATOR_SINGLE_COLUMN
|
60
|
+
};
|
48
61
|
|
49
62
|
typedef struct {
|
50
|
-
VALUE
|
51
|
-
|
52
|
-
|
53
|
-
|
63
|
+
VALUE query;
|
64
|
+
enum iterator_mode mode;
|
65
|
+
} Iterator_t;
|
66
|
+
|
67
|
+
enum query_mode {
|
68
|
+
QUERY_YIELD,
|
69
|
+
QUERY_MULTI_ROW,
|
70
|
+
QUERY_SINGLE_ROW
|
71
|
+
};
|
72
|
+
|
73
|
+
typedef struct {
|
74
|
+
VALUE self;
|
75
|
+
sqlite3 *sqlite3_db;
|
76
|
+
sqlite3_stmt *stmt;
|
77
|
+
VALUE params;
|
78
|
+
enum query_mode mode;
|
79
|
+
int max_rows;
|
80
|
+
int eof;
|
54
81
|
} query_ctx;
|
55
82
|
|
56
83
|
typedef struct {
|
57
|
-
VALUE
|
58
|
-
VALUE
|
59
|
-
sqlite3_backup
|
84
|
+
VALUE dst;
|
85
|
+
VALUE src;
|
86
|
+
sqlite3_backup *p;
|
60
87
|
} backup_t;
|
61
88
|
|
89
|
+
#define TUPLE_MAX_EMBEDDED_VALUES 20
|
90
|
+
#define ALL_ROWS -1
|
91
|
+
#define SINGLE_ROW -2
|
92
|
+
#define QUERY_MODE(default) (rb_block_given_p() ? QUERY_YIELD : default)
|
93
|
+
#define MULTI_ROW_P(mode) (mode == QUERY_MULTI_ROW)
|
94
|
+
|
62
95
|
VALUE safe_execute_multi(query_ctx *ctx);
|
63
96
|
VALUE safe_query_ary(query_ctx *ctx);
|
97
|
+
VALUE safe_query_changes(query_ctx *ctx);
|
64
98
|
VALUE safe_query_columns(query_ctx *ctx);
|
65
99
|
VALUE safe_query_hash(query_ctx *ctx);
|
66
100
|
VALUE safe_query_single_column(query_ctx *ctx);
|
67
101
|
VALUE safe_query_single_row(query_ctx *ctx);
|
68
102
|
VALUE safe_query_single_value(query_ctx *ctx);
|
69
103
|
|
104
|
+
VALUE Query_each_hash(VALUE self);
|
105
|
+
VALUE Query_each_ary(VALUE self);
|
106
|
+
VALUE Query_each_single_column(VALUE self);
|
107
|
+
|
108
|
+
VALUE Query_next_hash(int argc, VALUE *argv, VALUE self);
|
109
|
+
VALUE Query_next_ary(int argc, VALUE *argv, VALUE self);
|
110
|
+
VALUE Query_next_single_column(int argc, VALUE *argv, VALUE self);
|
111
|
+
|
112
|
+
VALUE Query_to_a_hash(VALUE self);
|
113
|
+
VALUE Query_to_a_ary(VALUE self);
|
114
|
+
VALUE Query_to_a_single_column(VALUE self);
|
115
|
+
|
70
116
|
void prepare_single_stmt(sqlite3 *db, sqlite3_stmt **stmt, VALUE sql);
|
71
117
|
void prepare_multi_stmt(sqlite3 *db, sqlite3_stmt **stmt, VALUE sql);
|
72
118
|
void bind_all_parameters(sqlite3_stmt *stmt, int argc, VALUE *argv);
|
73
119
|
void bind_all_parameters_from_object(sqlite3_stmt *stmt, VALUE obj);
|
74
|
-
int stmt_iterate(
|
120
|
+
int stmt_iterate(query_ctx *ctx);
|
75
121
|
VALUE cleanup_stmt(query_ctx *ctx);
|
76
122
|
|
77
123
|
sqlite3 *Database_sqlite3_db(VALUE self);
|
78
|
-
Database_t *
|
124
|
+
Database_t *self_to_database(VALUE self);
|
79
125
|
|
80
126
|
#endif /* EXTRALITE_H */
|
@@ -1,7 +1,9 @@
|
|
1
1
|
void Init_ExtraliteDatabase();
|
2
|
-
void
|
2
|
+
void Init_ExtraliteQuery();
|
3
|
+
void Init_ExtraliteIterator();
|
3
4
|
|
4
5
|
void Init_extralite_ext(void) {
|
5
6
|
Init_ExtraliteDatabase();
|
6
|
-
|
7
|
+
Init_ExtraliteQuery();
|
8
|
+
Init_ExtraliteIterator();
|
7
9
|
}
|
@@ -0,0 +1,208 @@
|
|
1
|
+
#include <stdio.h>
|
2
|
+
#include "extralite.h"
|
3
|
+
|
4
|
+
/*
|
5
|
+
* Document-class: Extralite::Iterator
|
6
|
+
*
|
7
|
+
* This class implements an iterator used to iterate through query results.
|
8
|
+
*/
|
9
|
+
|
10
|
+
VALUE cIterator;
|
11
|
+
|
12
|
+
VALUE SYM_hash;
|
13
|
+
VALUE SYM_ary;
|
14
|
+
VALUE SYM_single_column;
|
15
|
+
|
16
|
+
static size_t Iterator_size(const void *ptr) {
|
17
|
+
return sizeof(Iterator_t);
|
18
|
+
}
|
19
|
+
|
20
|
+
static void Iterator_mark(void *ptr) {
|
21
|
+
Iterator_t *iterator = ptr;
|
22
|
+
rb_gc_mark(iterator->query);
|
23
|
+
}
|
24
|
+
|
25
|
+
static const rb_data_type_t Iterator_type = {
|
26
|
+
"Iterator",
|
27
|
+
{Iterator_mark, free, Iterator_size,},
|
28
|
+
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
|
29
|
+
};
|
30
|
+
|
31
|
+
static VALUE Iterator_allocate(VALUE klass) {
|
32
|
+
Iterator_t *iterator = ALLOC(Iterator_t);
|
33
|
+
iterator->query = Qnil;
|
34
|
+
return TypedData_Wrap_Struct(klass, &Iterator_type, iterator);
|
35
|
+
}
|
36
|
+
|
37
|
+
static inline Iterator_t *self_to_iterator(VALUE obj) {
|
38
|
+
Iterator_t *iterator;
|
39
|
+
TypedData_Get_Struct((obj), Iterator_t, &Iterator_type, (iterator));
|
40
|
+
return iterator;
|
41
|
+
}
|
42
|
+
|
43
|
+
static inline enum iterator_mode symbol_to_mode(VALUE sym) {
|
44
|
+
if (sym == SYM_hash) return ITERATOR_HASH;
|
45
|
+
if (sym == SYM_ary) return ITERATOR_ARY;
|
46
|
+
if (sym == SYM_single_column) return ITERATOR_SINGLE_COLUMN;
|
47
|
+
|
48
|
+
rb_raise(cError, "Invalid iterator mode");
|
49
|
+
}
|
50
|
+
|
51
|
+
/* Initializes an iterator using the given query object and iteration mode. The
|
52
|
+
* iteration mode is one of: `:hash`, `:ary`, or `:single_column`. An iterator
|
53
|
+
* is normally returned from one of the methods `Query#each`/`Query#each_hash`,
|
54
|
+
* `Query#each_ary` or `Query#each_single_column` when called without a block:
|
55
|
+
*
|
56
|
+
* iterator = query.each
|
57
|
+
* ...
|
58
|
+
*
|
59
|
+
* @param query [Extralite::Query] associated query
|
60
|
+
* @param mode [Symbol] iteration mode
|
61
|
+
* @return [void]
|
62
|
+
*/
|
63
|
+
VALUE Iterator_initialize(VALUE self, VALUE query, VALUE mode) {
|
64
|
+
Iterator_t *iterator = self_to_iterator(self);
|
65
|
+
|
66
|
+
iterator->query = query;
|
67
|
+
iterator->mode = symbol_to_mode(mode);
|
68
|
+
|
69
|
+
return Qnil;
|
70
|
+
}
|
71
|
+
|
72
|
+
typedef VALUE (*each_method)(VALUE);
|
73
|
+
|
74
|
+
inline each_method mode_to_each_method(enum iterator_mode mode) {
|
75
|
+
switch (mode) {
|
76
|
+
case ITERATOR_ARY:
|
77
|
+
return Query_each_ary;
|
78
|
+
case ITERATOR_SINGLE_COLUMN:
|
79
|
+
return Query_each_single_column;
|
80
|
+
default:
|
81
|
+
return Query_each_hash;
|
82
|
+
}
|
83
|
+
}
|
84
|
+
|
85
|
+
/* Iterates through the associated query's result set using the iteration mode
|
86
|
+
* set when initialized. Each row would be passed to the given block according
|
87
|
+
* to the iteration mode, i.e. as a hash, an array, or a single value. In
|
88
|
+
* `:single column` mode an error will be raised if the result sets contains
|
89
|
+
* more than one columns.
|
90
|
+
*
|
91
|
+
* @return [Extralite::Iterator] self
|
92
|
+
*/
|
93
|
+
VALUE Iterator_each(VALUE self) {
|
94
|
+
if (rb_block_given_p()) {
|
95
|
+
Iterator_t *iterator = self_to_iterator(self);
|
96
|
+
each_method method = mode_to_each_method(iterator->mode);
|
97
|
+
method(iterator->query);
|
98
|
+
}
|
99
|
+
|
100
|
+
return self;
|
101
|
+
}
|
102
|
+
|
103
|
+
typedef VALUE (*next_method)(int, VALUE *, VALUE);
|
104
|
+
|
105
|
+
inline next_method mode_to_next_method(enum iterator_mode mode) {
|
106
|
+
switch (mode) {
|
107
|
+
case ITERATOR_ARY:
|
108
|
+
return Query_next_ary;
|
109
|
+
case ITERATOR_SINGLE_COLUMN:
|
110
|
+
return Query_next_single_column;
|
111
|
+
default:
|
112
|
+
return Query_next_hash;
|
113
|
+
}
|
114
|
+
}
|
115
|
+
|
116
|
+
/* Returns the next 1 or more rows from the associated query's result set
|
117
|
+
* according to the iteration mode, i.e. as a hash, an array or a single value.
|
118
|
+
*
|
119
|
+
* If no row count is given, a single row is returned. If a row count is given,
|
120
|
+
* an array containing up to the `row_count` rows is returned. If `row_count` is
|
121
|
+
* -1, all rows are returned. If the end of the result set has been reached,
|
122
|
+
* `nil` is returned.
|
123
|
+
*
|
124
|
+
* If a block is given, rows are passed to the block and self is returned.
|
125
|
+
*
|
126
|
+
* @overload next()
|
127
|
+
* @return [Hash, Array, Object, Extralite::Iterator] next row or self if block is given
|
128
|
+
* @overload next(row_count)
|
129
|
+
* @param row_count [Integer] maximum row count or -1 for all rows
|
130
|
+
* @return [Array, Extralite::Iterator] next rows or self if block is given
|
131
|
+
*/
|
132
|
+
VALUE Iterator_next(int argc, VALUE *argv, VALUE self) {
|
133
|
+
Iterator_t *iterator = self_to_iterator(self);
|
134
|
+
next_method method = mode_to_next_method(iterator->mode);
|
135
|
+
VALUE result = method(argc, argv, iterator->query);
|
136
|
+
|
137
|
+
return rb_block_given_p() ? self : result;
|
138
|
+
}
|
139
|
+
|
140
|
+
typedef VALUE (*to_a_method)(VALUE);
|
141
|
+
|
142
|
+
inline to_a_method mode_to_to_a_method(enum iterator_mode mode) {
|
143
|
+
switch (mode) {
|
144
|
+
case ITERATOR_ARY:
|
145
|
+
return Query_to_a_ary;
|
146
|
+
case ITERATOR_SINGLE_COLUMN:
|
147
|
+
return Query_to_a_single_column;
|
148
|
+
default:
|
149
|
+
return Query_to_a_hash;
|
150
|
+
}
|
151
|
+
}
|
152
|
+
|
153
|
+
/* Returns all rows from the associated query's result set according to the
|
154
|
+
* iteration mode, i.e. as a hash, an array or a single value.
|
155
|
+
*
|
156
|
+
* @return [Array] array of query result set rows
|
157
|
+
*/
|
158
|
+
VALUE Iterator_to_a(VALUE self) {
|
159
|
+
Iterator_t *iterator = self_to_iterator(self);
|
160
|
+
to_a_method method = mode_to_to_a_method(iterator->mode);
|
161
|
+
return method(iterator->query);
|
162
|
+
}
|
163
|
+
|
164
|
+
inline VALUE mode_to_symbol(Iterator_t *iterator) {
|
165
|
+
switch (iterator->mode) {
|
166
|
+
case ITERATOR_ARY:
|
167
|
+
return SYM_ary;
|
168
|
+
case ITERATOR_SINGLE_COLUMN:
|
169
|
+
return SYM_single_column;
|
170
|
+
default:
|
171
|
+
return SYM_hash;
|
172
|
+
}
|
173
|
+
}
|
174
|
+
|
175
|
+
/* Returns a short string representation of the iterator instance, including the
|
176
|
+
* SQL string.
|
177
|
+
*
|
178
|
+
* @return [String] string representation
|
179
|
+
*/
|
180
|
+
VALUE Iterator_inspect(VALUE self) {
|
181
|
+
VALUE cname = rb_class_name(CLASS_OF(self));
|
182
|
+
VALUE sym = mode_to_symbol(self_to_iterator(self));
|
183
|
+
|
184
|
+
return rb_sprintf("#<%"PRIsVALUE":%p %"PRIsVALUE">", cname, (void*)self, sym);
|
185
|
+
}
|
186
|
+
|
187
|
+
void Init_ExtraliteIterator(void) {
|
188
|
+
VALUE mExtralite = rb_define_module("Extralite");
|
189
|
+
|
190
|
+
cIterator = rb_define_class_under(mExtralite, "Iterator", rb_cObject);
|
191
|
+
rb_define_alloc_func(cIterator, Iterator_allocate);
|
192
|
+
|
193
|
+
rb_include_module(cIterator, rb_mEnumerable);
|
194
|
+
|
195
|
+
rb_define_method(cIterator, "initialize", Iterator_initialize, 2);
|
196
|
+
rb_define_method(cIterator, "each", Iterator_each, 0);
|
197
|
+
rb_define_method(cIterator, "inspect", Iterator_inspect, 0);
|
198
|
+
rb_define_method(cIterator, "next", Iterator_next, -1);
|
199
|
+
rb_define_method(cIterator, "to_a", Iterator_to_a, 0);
|
200
|
+
|
201
|
+
SYM_hash = ID2SYM(rb_intern("hash"));
|
202
|
+
SYM_ary = ID2SYM(rb_intern("ary"));
|
203
|
+
SYM_single_column = ID2SYM(rb_intern("single_column"));
|
204
|
+
|
205
|
+
rb_gc_register_mark_object(SYM_hash);
|
206
|
+
rb_gc_register_mark_object(SYM_ary);
|
207
|
+
rb_gc_register_mark_object(SYM_single_column);
|
208
|
+
}
|