extralite 2.6 → 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 +28 -17
- data/Gemfile +4 -0
- data/Gemfile-bundle +1 -1
- data/README.md +259 -72
- 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 +638 -316
- data/ext/extralite/extconf.rb +7 -11
- data/ext/extralite/extralite.h +89 -48
- data/ext/extralite/iterator.c +6 -83
- data/ext/extralite/query.c +164 -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 +28 -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`,
|
@@ -65,28 +53,12 @@ static inline enum iterator_mode symbol_to_mode(VALUE sym) {
|
|
65
53
|
* @param mode [Symbol] iteration mode
|
66
54
|
* @return [void]
|
67
55
|
*/
|
68
|
-
VALUE Iterator_initialize(VALUE self, VALUE query
|
56
|
+
VALUE Iterator_initialize(VALUE self, VALUE query) {
|
69
57
|
Iterator_t *iterator = self_to_iterator(self);
|
70
|
-
|
71
58
|
iterator->query = query;
|
72
|
-
iterator->mode = symbol_to_mode(mode);
|
73
|
-
|
74
59
|
return Qnil;
|
75
60
|
}
|
76
61
|
|
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
62
|
/* Iterates through the associated query's result set using the iteration mode
|
91
63
|
* set when initialized. Each row would be passed to the given block according
|
92
64
|
* to the iteration mode, i.e. as a hash, an array, or a single value. In
|
@@ -98,26 +70,12 @@ inline each_method mode_to_each_method(enum iterator_mode mode) {
|
|
98
70
|
VALUE Iterator_each(VALUE self) {
|
99
71
|
if (rb_block_given_p()) {
|
100
72
|
Iterator_t *iterator = self_to_iterator(self);
|
101
|
-
|
102
|
-
method(iterator->query);
|
73
|
+
Query_each(iterator->query);
|
103
74
|
}
|
104
75
|
|
105
76
|
return self;
|
106
77
|
}
|
107
78
|
|
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
79
|
/* Returns the next 1 or more rows from the associated query's result set
|
122
80
|
* according to the iteration mode, i.e. as a hash, an array or a single value.
|
123
81
|
*
|
@@ -136,25 +94,11 @@ inline next_method mode_to_next_method(enum iterator_mode mode) {
|
|
136
94
|
*/
|
137
95
|
VALUE Iterator_next(int argc, VALUE *argv, VALUE self) {
|
138
96
|
Iterator_t *iterator = self_to_iterator(self);
|
139
|
-
|
140
|
-
VALUE result = method(argc, argv, iterator->query);
|
97
|
+
VALUE result = Query_next(argc, argv, iterator->query);
|
141
98
|
|
142
99
|
return rb_block_given_p() ? self : result;
|
143
100
|
}
|
144
101
|
|
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
102
|
/* Returns all rows from the associated query's result set according to the
|
159
103
|
* iteration mode, i.e. as a hash, an array or a single value.
|
160
104
|
*
|
@@ -162,19 +106,7 @@ inline to_a_method mode_to_to_a_method(enum iterator_mode mode) {
|
|
162
106
|
*/
|
163
107
|
VALUE Iterator_to_a(VALUE self) {
|
164
108
|
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
|
-
}
|
109
|
+
return Query_to_a(iterator->query);
|
178
110
|
}
|
179
111
|
|
180
112
|
/* Returns a short string representation of the iterator instance, including the
|
@@ -184,9 +116,8 @@ inline VALUE mode_to_symbol(Iterator_t *iterator) {
|
|
184
116
|
*/
|
185
117
|
VALUE Iterator_inspect(VALUE self) {
|
186
118
|
VALUE cname = rb_class_name(CLASS_OF(self));
|
187
|
-
VALUE sym = mode_to_symbol(self_to_iterator(self));
|
188
119
|
|
189
|
-
return rb_sprintf("#<%"PRIsVALUE":%p
|
120
|
+
return rb_sprintf("#<%"PRIsVALUE":%p>", cname, (void*)self);
|
190
121
|
}
|
191
122
|
|
192
123
|
void Init_ExtraliteIterator(void) {
|
@@ -197,17 +128,9 @@ void Init_ExtraliteIterator(void) {
|
|
197
128
|
|
198
129
|
rb_include_module(cIterator, rb_mEnumerable);
|
199
130
|
|
200
|
-
rb_define_method(cIterator, "initialize", Iterator_initialize,
|
131
|
+
rb_define_method(cIterator, "initialize", Iterator_initialize, 1);
|
201
132
|
rb_define_method(cIterator, "each", Iterator_each, 0);
|
202
133
|
rb_define_method(cIterator, "inspect", Iterator_inspect, 0);
|
203
134
|
rb_define_method(cIterator, "next", Iterator_next, -1);
|
204
135
|
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
136
|
}
|