extralite 2.6 → 2.7.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/.gitignore +1 -0
- data/.yardopts +1 -1
- data/CHANGELOG.md +32 -17
- data/Gemfile +4 -0
- data/Gemfile-bundle +1 -1
- data/README.md +262 -75
- data/Rakefile +18 -0
- data/TODO.md +0 -9
- 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 +3 -3
- data/ext/extralite/common.c +173 -87
- data/ext/extralite/database.c +650 -315
- data/ext/extralite/extconf.rb +7 -11
- data/ext/extralite/extralite.h +89 -48
- data/ext/extralite/iterator.c +6 -84
- data/ext/extralite/query.c +165 -256
- 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 +27 -17
- data/lib/sequel/adapters/extralite.rb +1 -1
- data/test/helper.rb +2 -1
- data/test/perf_argv_transform.rb +74 -0
- data/test/perf_hash_transform.rb +66 -0
- data/test/perf_polyphony.rb +74 -0
- data/test/test_changeset.rb +2 -2
- data/test/test_database.rb +531 -115
- data/test/test_extralite.rb +2 -2
- data/test/test_iterator.rb +28 -13
- data/test/test_query.rb +348 -111
- data/test/test_sequel.rb +4 -4
- metadata +20 -14
- data/Gemfile.lock +0 -37
data/ext/extralite/extconf.rb
CHANGED
@@ -35,28 +35,27 @@ else
|
|
35
35
|
end
|
36
36
|
|
37
37
|
if with_config('sqlcipher')
|
38
|
-
pkg_config(
|
38
|
+
pkg_config('sqlcipher')
|
39
39
|
else
|
40
|
-
pkg_config(
|
40
|
+
pkg_config('sqlite3')
|
41
41
|
end
|
42
42
|
|
43
43
|
# --with-sqlite3-{dir,include,lib}
|
44
44
|
if with_config('sqlcipher')
|
45
45
|
$CFLAGS << ' -DUSING_SQLCIPHER'
|
46
|
-
dir_config(
|
46
|
+
dir_config('sqlcipher', cppflags, ldflags)
|
47
47
|
else
|
48
|
-
dir_config(
|
48
|
+
dir_config('sqlite3', cppflags, ldflags)
|
49
49
|
end
|
50
50
|
|
51
|
-
if RbConfig::CONFIG[
|
51
|
+
if RbConfig::CONFIG['host_os'] =~ /mswin/
|
52
52
|
$CFLAGS << ' -W3'
|
53
53
|
end
|
54
54
|
|
55
55
|
# @!visibility private
|
56
56
|
def asplode missing
|
57
57
|
if RUBY_PLATFORM =~ /mingw|mswin/
|
58
|
-
abort "#{missing} is missing. Install SQLite3 from "
|
59
|
-
"http://www.sqlite.org/ first."
|
58
|
+
abort "#{missing} is missing. Install SQLite3 from http://www.sqlite.org/ first."
|
60
59
|
else
|
61
60
|
abort <<~error
|
62
61
|
#{missing} is missing. Try 'brew install sqlite3',
|
@@ -87,11 +86,8 @@ else
|
|
87
86
|
if have_type('sqlite3_session', 'sqlite.h')
|
88
87
|
$defs << '-DEXTRALITE_ENABLE_CHANGESET'
|
89
88
|
end
|
90
|
-
# have_macro('__SQLITESESSION_H_')
|
91
|
-
# have_macro('SQLITE3_H')
|
92
89
|
|
93
|
-
|
94
|
-
$defs << "-DEXTRALITE_NO_BUNDLE"
|
90
|
+
$defs << '-DEXTRALITE_NO_BUNDLE'
|
95
91
|
|
96
92
|
dir_config('extralite_ext')
|
97
93
|
create_makefile('extralite_ext')
|
data/ext/extralite/extralite.h
CHANGED
@@ -17,6 +17,8 @@
|
|
17
17
|
VALUE s = rb_funcall(obj, rb_intern("inspect"), 0); \
|
18
18
|
printf(": %s\n", StringValueCStr(s)); \
|
19
19
|
}
|
20
|
+
#define CALLER() rb_funcall(rb_mKernel, rb_intern("caller"), 0)
|
21
|
+
#define TRACE_CALLER() INSPECT("caller: ", CALLER())
|
20
22
|
|
21
23
|
#define SAFE(f) (VALUE (*)(VALUE))(f)
|
22
24
|
|
@@ -40,36 +42,60 @@ extern ID ID_strip;
|
|
40
42
|
extern ID ID_to_s;
|
41
43
|
extern ID ID_track;
|
42
44
|
|
45
|
+
extern VALUE SYM_argv;
|
43
46
|
extern VALUE SYM_ary;
|
44
47
|
extern VALUE SYM_hash;
|
45
|
-
|
48
|
+
|
49
|
+
enum progress_handler_mode {
|
50
|
+
PROGRESS_NONE,
|
51
|
+
PROGRESS_NORMAL,
|
52
|
+
PROGRESS_ONCE,
|
53
|
+
PROGRESS_AT_LEAST_ONCE,
|
54
|
+
};
|
55
|
+
|
56
|
+
struct progress_handler {
|
57
|
+
enum progress_handler_mode mode;
|
58
|
+
VALUE proc;
|
59
|
+
int period;
|
60
|
+
int tick;
|
61
|
+
int tick_count;
|
62
|
+
int call_count;
|
63
|
+
};
|
46
64
|
|
47
65
|
typedef struct {
|
48
|
-
sqlite3
|
49
|
-
VALUE
|
50
|
-
|
51
|
-
|
66
|
+
sqlite3 *sqlite3_db;
|
67
|
+
VALUE trace_proc;
|
68
|
+
int gvl_release_threshold;
|
69
|
+
struct progress_handler progress_handler;
|
52
70
|
} Database_t;
|
53
71
|
|
72
|
+
enum query_mode {
|
73
|
+
QUERY_HASH,
|
74
|
+
QUERY_ARGV,
|
75
|
+
QUERY_ARY
|
76
|
+
};
|
77
|
+
|
54
78
|
typedef struct {
|
55
|
-
VALUE
|
56
|
-
VALUE
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
int
|
79
|
+
VALUE db;
|
80
|
+
VALUE sql;
|
81
|
+
VALUE transform_proc;
|
82
|
+
Database_t *db_struct;
|
83
|
+
sqlite3 *sqlite3_db;
|
84
|
+
sqlite3_stmt *stmt;
|
85
|
+
int eof;
|
86
|
+
int closed;
|
87
|
+
enum query_mode query_mode;
|
62
88
|
} Query_t;
|
63
89
|
|
64
90
|
enum iterator_mode {
|
65
91
|
ITERATOR_HASH,
|
92
|
+
ITERATOR_ARGV,
|
66
93
|
ITERATOR_ARY,
|
67
94
|
ITERATOR_SINGLE_COLUMN
|
68
95
|
};
|
69
96
|
|
70
97
|
typedef struct {
|
71
98
|
VALUE query;
|
72
|
-
enum iterator_mode mode;
|
73
99
|
} Iterator_t;
|
74
100
|
|
75
101
|
#ifdef EXTRALITE_ENABLE_CHANGESET
|
@@ -79,22 +105,29 @@ typedef struct {
|
|
79
105
|
} Changeset_t;
|
80
106
|
#endif
|
81
107
|
|
82
|
-
enum
|
83
|
-
|
84
|
-
|
85
|
-
|
108
|
+
enum row_mode {
|
109
|
+
ROW_YIELD,
|
110
|
+
ROW_MULTI,
|
111
|
+
ROW_SINGLE
|
86
112
|
};
|
87
113
|
|
88
114
|
typedef struct {
|
89
|
-
VALUE
|
90
|
-
|
91
|
-
|
92
|
-
VALUE
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
115
|
+
VALUE self;
|
116
|
+
VALUE sql;
|
117
|
+
VALUE params;
|
118
|
+
VALUE transform_proc;
|
119
|
+
|
120
|
+
Database_t *db;
|
121
|
+
sqlite3 *sqlite3_db;
|
122
|
+
sqlite3_stmt *stmt;
|
123
|
+
|
124
|
+
int gvl_release_threshold;
|
125
|
+
enum query_mode query_mode;
|
126
|
+
enum row_mode row_mode;
|
127
|
+
int max_rows;
|
128
|
+
|
129
|
+
int eof;
|
130
|
+
int step_count;
|
98
131
|
} query_ctx;
|
99
132
|
|
100
133
|
enum gvl_mode {
|
@@ -104,41 +137,48 @@ enum gvl_mode {
|
|
104
137
|
|
105
138
|
#define ALL_ROWS -1
|
106
139
|
#define SINGLE_ROW -2
|
107
|
-
#define
|
108
|
-
#define
|
109
|
-
#define QUERY_CTX(self, db, stmt, params,
|
110
|
-
|
111
|
-
|
112
|
-
|
140
|
+
#define ROW_YIELD_OR_MODE(default) (rb_block_given_p() ? ROW_YIELD : default)
|
141
|
+
#define ROW_MULTI_P(mode) (mode == ROW_MULTI)
|
142
|
+
#define QUERY_CTX(self, sql, db, stmt, params, transform_proc, query_mode, row_mode, max_rows) { \
|
143
|
+
self, \
|
144
|
+
sql, \
|
145
|
+
params, \
|
146
|
+
transform_proc, \
|
147
|
+
db, \
|
148
|
+
db->sqlite3_db, \
|
149
|
+
stmt, \
|
150
|
+
db->gvl_release_threshold, \
|
151
|
+
query_mode, \
|
152
|
+
row_mode, \
|
153
|
+
max_rows, \
|
154
|
+
0, \
|
155
|
+
0 \
|
156
|
+
}
|
113
157
|
|
114
158
|
#define DEFAULT_GVL_RELEASE_THRESHOLD 1000
|
115
|
-
|
159
|
+
#define DEFAULT_PROGRESS_HANDLER_PERIOD 1000
|
160
|
+
#define DEFAULT_PROGRESS_HANDLER_TICK 10
|
116
161
|
|
117
162
|
extern rb_encoding *UTF8_ENCODING;
|
118
163
|
|
164
|
+
typedef VALUE (*safe_query_impl)(query_ctx *);
|
165
|
+
|
119
166
|
VALUE safe_batch_execute(query_ctx *ctx);
|
120
167
|
VALUE safe_batch_query(query_ctx *ctx);
|
168
|
+
VALUE safe_batch_query_argv(query_ctx *ctx);
|
121
169
|
VALUE safe_batch_query_ary(query_ctx *ctx);
|
122
|
-
VALUE
|
170
|
+
VALUE safe_query_argv(query_ctx *ctx);
|
123
171
|
VALUE safe_query_ary(query_ctx *ctx);
|
124
172
|
VALUE safe_query_changes(query_ctx *ctx);
|
125
173
|
VALUE safe_query_columns(query_ctx *ctx);
|
126
174
|
VALUE safe_query_hash(query_ctx *ctx);
|
127
|
-
VALUE
|
128
|
-
VALUE
|
129
|
-
VALUE
|
130
|
-
|
131
|
-
VALUE Query_each_hash(VALUE self);
|
132
|
-
VALUE Query_each_ary(VALUE self);
|
133
|
-
VALUE Query_each_single_column(VALUE self);
|
134
|
-
|
135
|
-
VALUE Query_next_hash(int argc, VALUE *argv, VALUE self);
|
136
|
-
VALUE Query_next_ary(int argc, VALUE *argv, VALUE self);
|
137
|
-
VALUE Query_next_single_column(int argc, VALUE *argv, VALUE self);
|
175
|
+
VALUE safe_query_single_row_hash(query_ctx *ctx);
|
176
|
+
VALUE safe_query_single_row_argv(query_ctx *ctx);
|
177
|
+
VALUE safe_query_single_row_ary(query_ctx *ctx);
|
138
178
|
|
139
|
-
VALUE
|
140
|
-
VALUE
|
141
|
-
VALUE
|
179
|
+
VALUE Query_each(VALUE self);
|
180
|
+
VALUE Query_next(int argc, VALUE *argv, VALUE self);
|
181
|
+
VALUE Query_to_a(VALUE self);
|
142
182
|
|
143
183
|
void prepare_single_stmt(enum gvl_mode mode, sqlite3 *db, sqlite3_stmt **stmt, VALUE sql);
|
144
184
|
void prepare_multi_stmt(enum gvl_mode mode, sqlite3 *db, sqlite3_stmt **stmt, VALUE sql);
|
@@ -147,6 +187,7 @@ void bind_all_parameters_from_object(sqlite3_stmt *stmt, VALUE obj);
|
|
147
187
|
int stmt_iterate(query_ctx *ctx);
|
148
188
|
VALUE cleanup_stmt(query_ctx *ctx);
|
149
189
|
|
190
|
+
void Database_issue_query(Database_t *db, VALUE sql);
|
150
191
|
sqlite3 *Database_sqlite3_db(VALUE self);
|
151
192
|
enum gvl_mode Database_prepare_gvl_mode(Database_t *db);
|
152
193
|
Database_t *self_to_database(VALUE self);
|
data/ext/extralite/iterator.c
CHANGED
@@ -9,10 +9,6 @@
|
|
9
9
|
|
10
10
|
VALUE cIterator;
|
11
11
|
|
12
|
-
VALUE SYM_hash;
|
13
|
-
VALUE SYM_ary;
|
14
|
-
VALUE SYM_single_column;
|
15
|
-
|
16
12
|
static size_t Iterator_size(const void *ptr) {
|
17
13
|
return sizeof(Iterator_t);
|
18
14
|
}
|
@@ -45,14 +41,6 @@ static inline Iterator_t *self_to_iterator(VALUE obj) {
|
|
45
41
|
return iterator;
|
46
42
|
}
|
47
43
|
|
48
|
-
static inline enum iterator_mode symbol_to_mode(VALUE sym) {
|
49
|
-
if (sym == SYM_hash) return ITERATOR_HASH;
|
50
|
-
if (sym == SYM_ary) return ITERATOR_ARY;
|
51
|
-
if (sym == SYM_single_column) return ITERATOR_SINGLE_COLUMN;
|
52
|
-
|
53
|
-
rb_raise(cError, "Invalid iterator mode");
|
54
|
-
}
|
55
|
-
|
56
44
|
/* Initializes an iterator using the given query object and iteration mode. The
|
57
45
|
* iteration mode is one of: `:hash`, `:ary`, or `:single_column`. An iterator
|
58
46
|
* is normally returned from one of the methods `Query#each`/`Query#each_hash`,
|
@@ -62,31 +50,14 @@ static inline enum iterator_mode symbol_to_mode(VALUE sym) {
|
|
62
50
|
* ...
|
63
51
|
*
|
64
52
|
* @param query [Extralite::Query] associated query
|
65
|
-
* @param mode [Symbol] iteration mode
|
66
53
|
* @return [void]
|
67
54
|
*/
|
68
|
-
VALUE Iterator_initialize(VALUE self, VALUE query
|
55
|
+
VALUE Iterator_initialize(VALUE self, VALUE query) {
|
69
56
|
Iterator_t *iterator = self_to_iterator(self);
|
70
|
-
|
71
57
|
iterator->query = query;
|
72
|
-
iterator->mode = symbol_to_mode(mode);
|
73
|
-
|
74
58
|
return Qnil;
|
75
59
|
}
|
76
60
|
|
77
|
-
typedef VALUE (*each_method)(VALUE);
|
78
|
-
|
79
|
-
inline each_method mode_to_each_method(enum iterator_mode mode) {
|
80
|
-
switch (mode) {
|
81
|
-
case ITERATOR_ARY:
|
82
|
-
return Query_each_ary;
|
83
|
-
case ITERATOR_SINGLE_COLUMN:
|
84
|
-
return Query_each_single_column;
|
85
|
-
default:
|
86
|
-
return Query_each_hash;
|
87
|
-
}
|
88
|
-
}
|
89
|
-
|
90
61
|
/* Iterates through the associated query's result set using the iteration mode
|
91
62
|
* set when initialized. Each row would be passed to the given block according
|
92
63
|
* to the iteration mode, i.e. as a hash, an array, or a single value. In
|
@@ -98,26 +69,12 @@ inline each_method mode_to_each_method(enum iterator_mode mode) {
|
|
98
69
|
VALUE Iterator_each(VALUE self) {
|
99
70
|
if (rb_block_given_p()) {
|
100
71
|
Iterator_t *iterator = self_to_iterator(self);
|
101
|
-
|
102
|
-
method(iterator->query);
|
72
|
+
Query_each(iterator->query);
|
103
73
|
}
|
104
74
|
|
105
75
|
return self;
|
106
76
|
}
|
107
77
|
|
108
|
-
typedef VALUE (*next_method)(int, VALUE *, VALUE);
|
109
|
-
|
110
|
-
inline next_method mode_to_next_method(enum iterator_mode mode) {
|
111
|
-
switch (mode) {
|
112
|
-
case ITERATOR_ARY:
|
113
|
-
return Query_next_ary;
|
114
|
-
case ITERATOR_SINGLE_COLUMN:
|
115
|
-
return Query_next_single_column;
|
116
|
-
default:
|
117
|
-
return Query_next_hash;
|
118
|
-
}
|
119
|
-
}
|
120
|
-
|
121
78
|
/* Returns the next 1 or more rows from the associated query's result set
|
122
79
|
* according to the iteration mode, i.e. as a hash, an array or a single value.
|
123
80
|
*
|
@@ -136,25 +93,11 @@ inline next_method mode_to_next_method(enum iterator_mode mode) {
|
|
136
93
|
*/
|
137
94
|
VALUE Iterator_next(int argc, VALUE *argv, VALUE self) {
|
138
95
|
Iterator_t *iterator = self_to_iterator(self);
|
139
|
-
|
140
|
-
VALUE result = method(argc, argv, iterator->query);
|
96
|
+
VALUE result = Query_next(argc, argv, iterator->query);
|
141
97
|
|
142
98
|
return rb_block_given_p() ? self : result;
|
143
99
|
}
|
144
100
|
|
145
|
-
typedef VALUE (*to_a_method)(VALUE);
|
146
|
-
|
147
|
-
inline to_a_method mode_to_to_a_method(enum iterator_mode mode) {
|
148
|
-
switch (mode) {
|
149
|
-
case ITERATOR_ARY:
|
150
|
-
return Query_to_a_ary;
|
151
|
-
case ITERATOR_SINGLE_COLUMN:
|
152
|
-
return Query_to_a_single_column;
|
153
|
-
default:
|
154
|
-
return Query_to_a_hash;
|
155
|
-
}
|
156
|
-
}
|
157
|
-
|
158
101
|
/* Returns all rows from the associated query's result set according to the
|
159
102
|
* iteration mode, i.e. as a hash, an array or a single value.
|
160
103
|
*
|
@@ -162,19 +105,7 @@ inline to_a_method mode_to_to_a_method(enum iterator_mode mode) {
|
|
162
105
|
*/
|
163
106
|
VALUE Iterator_to_a(VALUE self) {
|
164
107
|
Iterator_t *iterator = self_to_iterator(self);
|
165
|
-
|
166
|
-
return method(iterator->query);
|
167
|
-
}
|
168
|
-
|
169
|
-
inline VALUE mode_to_symbol(Iterator_t *iterator) {
|
170
|
-
switch (iterator->mode) {
|
171
|
-
case ITERATOR_ARY:
|
172
|
-
return SYM_ary;
|
173
|
-
case ITERATOR_SINGLE_COLUMN:
|
174
|
-
return SYM_single_column;
|
175
|
-
default:
|
176
|
-
return SYM_hash;
|
177
|
-
}
|
108
|
+
return Query_to_a(iterator->query);
|
178
109
|
}
|
179
110
|
|
180
111
|
/* Returns a short string representation of the iterator instance, including the
|
@@ -184,9 +115,8 @@ inline VALUE mode_to_symbol(Iterator_t *iterator) {
|
|
184
115
|
*/
|
185
116
|
VALUE Iterator_inspect(VALUE self) {
|
186
117
|
VALUE cname = rb_class_name(CLASS_OF(self));
|
187
|
-
VALUE sym = mode_to_symbol(self_to_iterator(self));
|
188
118
|
|
189
|
-
return rb_sprintf("#<%"PRIsVALUE":%p
|
119
|
+
return rb_sprintf("#<%"PRIsVALUE":%p>", cname, (void*)self);
|
190
120
|
}
|
191
121
|
|
192
122
|
void Init_ExtraliteIterator(void) {
|
@@ -197,17 +127,9 @@ void Init_ExtraliteIterator(void) {
|
|
197
127
|
|
198
128
|
rb_include_module(cIterator, rb_mEnumerable);
|
199
129
|
|
200
|
-
rb_define_method(cIterator, "initialize", Iterator_initialize,
|
130
|
+
rb_define_method(cIterator, "initialize", Iterator_initialize, 1);
|
201
131
|
rb_define_method(cIterator, "each", Iterator_each, 0);
|
202
132
|
rb_define_method(cIterator, "inspect", Iterator_inspect, 0);
|
203
133
|
rb_define_method(cIterator, "next", Iterator_next, -1);
|
204
134
|
rb_define_method(cIterator, "to_a", Iterator_to_a, 0);
|
205
|
-
|
206
|
-
SYM_hash = ID2SYM(rb_intern("hash"));
|
207
|
-
SYM_ary = ID2SYM(rb_intern("ary"));
|
208
|
-
SYM_single_column = ID2SYM(rb_intern("single_column"));
|
209
|
-
|
210
|
-
rb_gc_register_mark_object(SYM_hash);
|
211
|
-
rb_gc_register_mark_object(SYM_ary);
|
212
|
-
rb_gc_register_mark_object(SYM_single_column);
|
213
135
|
}
|