sqlite3 2.0.0-aarch64-linux-musl
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 +7 -0
- data/.gemtest +0 -0
- data/CHANGELOG.md +800 -0
- data/CONTRIBUTING.md +56 -0
- data/FAQ.md +388 -0
- data/INSTALLATION.md +267 -0
- data/LICENSE +23 -0
- data/README.md +181 -0
- data/dependencies.yml +13 -0
- data/ext/sqlite3/aggregator.c +270 -0
- data/ext/sqlite3/aggregator.h +10 -0
- data/ext/sqlite3/backup.c +190 -0
- data/ext/sqlite3/backup.h +15 -0
- data/ext/sqlite3/database.c +931 -0
- data/ext/sqlite3/database.h +22 -0
- data/ext/sqlite3/exception.c +117 -0
- data/ext/sqlite3/exception.h +10 -0
- data/ext/sqlite3/extconf.rb +284 -0
- data/ext/sqlite3/sqlite3.c +208 -0
- data/ext/sqlite3/sqlite3_ruby.h +48 -0
- data/ext/sqlite3/statement.c +667 -0
- data/ext/sqlite3/statement.h +16 -0
- data/ext/sqlite3/timespec.h +20 -0
- data/lib/sqlite3/3.0/sqlite3_native.so +0 -0
- data/lib/sqlite3/3.1/sqlite3_native.so +0 -0
- data/lib/sqlite3/3.2/sqlite3_native.so +0 -0
- data/lib/sqlite3/3.3/sqlite3_native.so +0 -0
- data/lib/sqlite3/constants.rb +174 -0
- data/lib/sqlite3/database.rb +701 -0
- data/lib/sqlite3/errors.rb +60 -0
- data/lib/sqlite3/pragmas.rb +585 -0
- data/lib/sqlite3/resultset.rb +96 -0
- data/lib/sqlite3/statement.rb +190 -0
- data/lib/sqlite3/value.rb +54 -0
- data/lib/sqlite3/version.rb +3 -0
- data/lib/sqlite3.rb +17 -0
- metadata +101 -0
@@ -0,0 +1,667 @@
|
|
1
|
+
#include <sqlite3_ruby.h>
|
2
|
+
|
3
|
+
#define REQUIRE_OPEN_STMT(_ctxt) \
|
4
|
+
if(!_ctxt->st) \
|
5
|
+
rb_raise(rb_path2class("SQLite3::Exception"), "cannot use a closed statement");
|
6
|
+
|
7
|
+
VALUE cSqlite3Statement;
|
8
|
+
|
9
|
+
static void
|
10
|
+
statement_deallocate(void *data)
|
11
|
+
{
|
12
|
+
sqlite3StmtRubyPtr s = (sqlite3StmtRubyPtr)data;
|
13
|
+
|
14
|
+
if (s->st) {
|
15
|
+
sqlite3_finalize(s->st);
|
16
|
+
}
|
17
|
+
|
18
|
+
xfree(data);
|
19
|
+
}
|
20
|
+
|
21
|
+
static size_t
|
22
|
+
statement_memsize(const void *data)
|
23
|
+
{
|
24
|
+
const sqlite3StmtRubyPtr s = (const sqlite3StmtRubyPtr)data;
|
25
|
+
// NB: can't account for s->st because the type is incomplete.
|
26
|
+
return sizeof(*s);
|
27
|
+
}
|
28
|
+
|
29
|
+
static const rb_data_type_t statement_type = {
|
30
|
+
"SQLite3::Backup",
|
31
|
+
{
|
32
|
+
NULL,
|
33
|
+
statement_deallocate,
|
34
|
+
statement_memsize,
|
35
|
+
},
|
36
|
+
0,
|
37
|
+
0,
|
38
|
+
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
|
39
|
+
};
|
40
|
+
|
41
|
+
static VALUE
|
42
|
+
allocate(VALUE klass)
|
43
|
+
{
|
44
|
+
sqlite3StmtRubyPtr ctx;
|
45
|
+
return TypedData_Make_Struct(klass, sqlite3StmtRuby, &statement_type, ctx);
|
46
|
+
}
|
47
|
+
|
48
|
+
static VALUE
|
49
|
+
prepare(VALUE self, VALUE db, VALUE sql)
|
50
|
+
{
|
51
|
+
sqlite3RubyPtr db_ctx = sqlite3_database_unwrap(db);
|
52
|
+
sqlite3StmtRubyPtr ctx;
|
53
|
+
const char *tail = NULL;
|
54
|
+
int status;
|
55
|
+
|
56
|
+
StringValue(sql);
|
57
|
+
|
58
|
+
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
|
59
|
+
|
60
|
+
#ifdef HAVE_SQLITE3_PREPARE_V2
|
61
|
+
status = sqlite3_prepare_v2(
|
62
|
+
#else
|
63
|
+
status = sqlite3_prepare(
|
64
|
+
#endif
|
65
|
+
db_ctx->db,
|
66
|
+
(const char *)StringValuePtr(sql),
|
67
|
+
(int)RSTRING_LEN(sql),
|
68
|
+
&ctx->st,
|
69
|
+
&tail
|
70
|
+
);
|
71
|
+
|
72
|
+
CHECK(db_ctx->db, status);
|
73
|
+
timespecclear(&db_ctx->stmt_deadline);
|
74
|
+
|
75
|
+
return rb_str_new2(tail);
|
76
|
+
}
|
77
|
+
|
78
|
+
/* call-seq: stmt.close
|
79
|
+
*
|
80
|
+
* Closes the statement by finalizing the underlying statement
|
81
|
+
* handle. The statement must not be used after being closed.
|
82
|
+
*/
|
83
|
+
static VALUE
|
84
|
+
sqlite3_rb_close(VALUE self)
|
85
|
+
{
|
86
|
+
sqlite3StmtRubyPtr ctx;
|
87
|
+
|
88
|
+
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
|
89
|
+
|
90
|
+
REQUIRE_OPEN_STMT(ctx);
|
91
|
+
|
92
|
+
sqlite3_finalize(ctx->st);
|
93
|
+
ctx->st = NULL;
|
94
|
+
|
95
|
+
return self;
|
96
|
+
}
|
97
|
+
|
98
|
+
/* call-seq: stmt.closed?
|
99
|
+
*
|
100
|
+
* Returns true if the statement has been closed.
|
101
|
+
*/
|
102
|
+
static VALUE
|
103
|
+
closed_p(VALUE self)
|
104
|
+
{
|
105
|
+
sqlite3StmtRubyPtr ctx;
|
106
|
+
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
|
107
|
+
|
108
|
+
if (!ctx->st) { return Qtrue; }
|
109
|
+
|
110
|
+
return Qfalse;
|
111
|
+
}
|
112
|
+
|
113
|
+
static VALUE
|
114
|
+
step(VALUE self)
|
115
|
+
{
|
116
|
+
sqlite3StmtRubyPtr ctx;
|
117
|
+
sqlite3_stmt *stmt;
|
118
|
+
int value, length;
|
119
|
+
VALUE list;
|
120
|
+
rb_encoding *internal_encoding;
|
121
|
+
|
122
|
+
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
|
123
|
+
|
124
|
+
REQUIRE_OPEN_STMT(ctx);
|
125
|
+
|
126
|
+
if (ctx->done_p) { return Qnil; }
|
127
|
+
|
128
|
+
internal_encoding = rb_default_internal_encoding();
|
129
|
+
|
130
|
+
stmt = ctx->st;
|
131
|
+
|
132
|
+
value = sqlite3_step(stmt);
|
133
|
+
if (rb_errinfo() != Qnil) {
|
134
|
+
/* some user defined function was invoked as a callback during step and
|
135
|
+
* it raised an exception that has been suppressed until step returns.
|
136
|
+
* Now re-raise it. */
|
137
|
+
VALUE exception = rb_errinfo();
|
138
|
+
rb_set_errinfo(Qnil);
|
139
|
+
rb_exc_raise(exception);
|
140
|
+
}
|
141
|
+
|
142
|
+
length = sqlite3_column_count(stmt);
|
143
|
+
list = rb_ary_new2((long)length);
|
144
|
+
|
145
|
+
switch (value) {
|
146
|
+
case SQLITE_ROW: {
|
147
|
+
int i;
|
148
|
+
for (i = 0; i < length; i++) {
|
149
|
+
VALUE val;
|
150
|
+
|
151
|
+
switch (sqlite3_column_type(stmt, i)) {
|
152
|
+
case SQLITE_INTEGER:
|
153
|
+
val = LL2NUM(sqlite3_column_int64(stmt, i));
|
154
|
+
break;
|
155
|
+
case SQLITE_FLOAT:
|
156
|
+
val = rb_float_new(sqlite3_column_double(stmt, i));
|
157
|
+
break;
|
158
|
+
case SQLITE_TEXT: {
|
159
|
+
val = rb_utf8_str_new(
|
160
|
+
(const char *)sqlite3_column_text(stmt, i),
|
161
|
+
(long)sqlite3_column_bytes(stmt, i)
|
162
|
+
);
|
163
|
+
if (internal_encoding) {
|
164
|
+
val = rb_str_export_to_enc(val, internal_encoding);
|
165
|
+
}
|
166
|
+
rb_obj_freeze(val);
|
167
|
+
}
|
168
|
+
break;
|
169
|
+
case SQLITE_BLOB: {
|
170
|
+
val = rb_str_new(
|
171
|
+
(const char *)sqlite3_column_blob(stmt, i),
|
172
|
+
(long)sqlite3_column_bytes(stmt, i)
|
173
|
+
);
|
174
|
+
rb_obj_freeze(val);
|
175
|
+
}
|
176
|
+
break;
|
177
|
+
case SQLITE_NULL:
|
178
|
+
val = Qnil;
|
179
|
+
break;
|
180
|
+
default:
|
181
|
+
rb_raise(rb_eRuntimeError, "bad type");
|
182
|
+
}
|
183
|
+
|
184
|
+
rb_ary_store(list, (long)i, val);
|
185
|
+
}
|
186
|
+
}
|
187
|
+
break;
|
188
|
+
case SQLITE_DONE:
|
189
|
+
ctx->done_p = 1;
|
190
|
+
return Qnil;
|
191
|
+
break;
|
192
|
+
default:
|
193
|
+
sqlite3_reset(stmt);
|
194
|
+
ctx->done_p = 0;
|
195
|
+
CHECK(sqlite3_db_handle(ctx->st), value);
|
196
|
+
}
|
197
|
+
|
198
|
+
rb_obj_freeze(list);
|
199
|
+
|
200
|
+
return list;
|
201
|
+
}
|
202
|
+
|
203
|
+
/* call-seq: stmt.bind_param(key, value)
|
204
|
+
*
|
205
|
+
* Binds value to the named (or positional) placeholder. If +param+ is a
|
206
|
+
* Fixnum, it is treated as an index for a positional placeholder.
|
207
|
+
* Otherwise it is used as the name of the placeholder to bind to.
|
208
|
+
*
|
209
|
+
* See also #bind_params.
|
210
|
+
*/
|
211
|
+
static VALUE
|
212
|
+
bind_param(VALUE self, VALUE key, VALUE value)
|
213
|
+
{
|
214
|
+
sqlite3StmtRubyPtr ctx;
|
215
|
+
int status;
|
216
|
+
int index;
|
217
|
+
|
218
|
+
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
|
219
|
+
REQUIRE_OPEN_STMT(ctx);
|
220
|
+
|
221
|
+
switch (TYPE(key)) {
|
222
|
+
case T_SYMBOL:
|
223
|
+
key = rb_funcall(key, rb_intern("to_s"), 0);
|
224
|
+
case T_STRING:
|
225
|
+
if (RSTRING_PTR(key)[0] != ':') { key = rb_str_plus(rb_str_new2(":"), key); }
|
226
|
+
index = sqlite3_bind_parameter_index(ctx->st, StringValuePtr(key));
|
227
|
+
break;
|
228
|
+
default:
|
229
|
+
index = (int)NUM2INT(key);
|
230
|
+
}
|
231
|
+
|
232
|
+
if (index == 0) {
|
233
|
+
rb_raise(rb_path2class("SQLite3::Exception"), "no such bind parameter");
|
234
|
+
}
|
235
|
+
|
236
|
+
switch (TYPE(value)) {
|
237
|
+
case T_STRING:
|
238
|
+
if (CLASS_OF(value) == cSqlite3Blob
|
239
|
+
|| rb_enc_get_index(value) == rb_ascii8bit_encindex()
|
240
|
+
) {
|
241
|
+
status = sqlite3_bind_blob(
|
242
|
+
ctx->st,
|
243
|
+
index,
|
244
|
+
(const char *)StringValuePtr(value),
|
245
|
+
(int)RSTRING_LEN(value),
|
246
|
+
SQLITE_TRANSIENT
|
247
|
+
);
|
248
|
+
} else {
|
249
|
+
|
250
|
+
|
251
|
+
if (UTF16_LE_P(value) || UTF16_BE_P(value)) {
|
252
|
+
status = sqlite3_bind_text16(
|
253
|
+
ctx->st,
|
254
|
+
index,
|
255
|
+
(const char *)StringValuePtr(value),
|
256
|
+
(int)RSTRING_LEN(value),
|
257
|
+
SQLITE_TRANSIENT
|
258
|
+
);
|
259
|
+
} else {
|
260
|
+
if (!UTF8_P(value) || !USASCII_P(value)) {
|
261
|
+
value = rb_str_encode(value, rb_enc_from_encoding(rb_utf8_encoding()), 0, Qnil);
|
262
|
+
}
|
263
|
+
status = sqlite3_bind_text(
|
264
|
+
ctx->st,
|
265
|
+
index,
|
266
|
+
(const char *)StringValuePtr(value),
|
267
|
+
(int)RSTRING_LEN(value),
|
268
|
+
SQLITE_TRANSIENT
|
269
|
+
);
|
270
|
+
}
|
271
|
+
}
|
272
|
+
break;
|
273
|
+
case T_BIGNUM: {
|
274
|
+
sqlite3_int64 num64;
|
275
|
+
if (bignum_to_int64(value, &num64)) {
|
276
|
+
status = sqlite3_bind_int64(ctx->st, index, num64);
|
277
|
+
break;
|
278
|
+
}
|
279
|
+
}
|
280
|
+
case T_FLOAT:
|
281
|
+
status = sqlite3_bind_double(ctx->st, index, NUM2DBL(value));
|
282
|
+
break;
|
283
|
+
case T_FIXNUM:
|
284
|
+
status = sqlite3_bind_int64(ctx->st, index, (sqlite3_int64)FIX2LONG(value));
|
285
|
+
break;
|
286
|
+
case T_NIL:
|
287
|
+
status = sqlite3_bind_null(ctx->st, index);
|
288
|
+
break;
|
289
|
+
default:
|
290
|
+
rb_raise(rb_eRuntimeError, "can't prepare %s",
|
291
|
+
rb_class2name(CLASS_OF(value)));
|
292
|
+
break;
|
293
|
+
}
|
294
|
+
|
295
|
+
CHECK(sqlite3_db_handle(ctx->st), status);
|
296
|
+
|
297
|
+
return self;
|
298
|
+
}
|
299
|
+
|
300
|
+
/* call-seq: stmt.reset!
|
301
|
+
*
|
302
|
+
* Resets the statement. This is typically done internally, though it might
|
303
|
+
* occasionally be necessary to manually reset the statement.
|
304
|
+
*/
|
305
|
+
static VALUE
|
306
|
+
reset_bang(VALUE self)
|
307
|
+
{
|
308
|
+
sqlite3StmtRubyPtr ctx;
|
309
|
+
|
310
|
+
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
|
311
|
+
REQUIRE_OPEN_STMT(ctx);
|
312
|
+
|
313
|
+
sqlite3_reset(ctx->st);
|
314
|
+
|
315
|
+
ctx->done_p = 0;
|
316
|
+
|
317
|
+
return self;
|
318
|
+
}
|
319
|
+
|
320
|
+
/* call-seq: stmt.clear_bindings!
|
321
|
+
*
|
322
|
+
* Resets the statement. This is typically done internally, though it might
|
323
|
+
* occasionally be necessary to manually reset the statement.
|
324
|
+
*/
|
325
|
+
static VALUE
|
326
|
+
clear_bindings_bang(VALUE self)
|
327
|
+
{
|
328
|
+
sqlite3StmtRubyPtr ctx;
|
329
|
+
|
330
|
+
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
|
331
|
+
REQUIRE_OPEN_STMT(ctx);
|
332
|
+
|
333
|
+
sqlite3_clear_bindings(ctx->st);
|
334
|
+
|
335
|
+
ctx->done_p = 0;
|
336
|
+
|
337
|
+
return self;
|
338
|
+
}
|
339
|
+
|
340
|
+
/* call-seq: stmt.done?
|
341
|
+
*
|
342
|
+
* returns true if all rows have been returned.
|
343
|
+
*/
|
344
|
+
static VALUE
|
345
|
+
done_p(VALUE self)
|
346
|
+
{
|
347
|
+
sqlite3StmtRubyPtr ctx;
|
348
|
+
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
|
349
|
+
|
350
|
+
if (ctx->done_p) { return Qtrue; }
|
351
|
+
return Qfalse;
|
352
|
+
}
|
353
|
+
|
354
|
+
/* call-seq: stmt.column_count
|
355
|
+
*
|
356
|
+
* Returns the number of columns to be returned for this statement
|
357
|
+
*/
|
358
|
+
static VALUE
|
359
|
+
column_count(VALUE self)
|
360
|
+
{
|
361
|
+
sqlite3StmtRubyPtr ctx;
|
362
|
+
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
|
363
|
+
REQUIRE_OPEN_STMT(ctx);
|
364
|
+
|
365
|
+
return INT2NUM(sqlite3_column_count(ctx->st));
|
366
|
+
}
|
367
|
+
|
368
|
+
#if HAVE_RB_ENC_INTERNED_STR_CSTR
|
369
|
+
static VALUE
|
370
|
+
interned_utf8_cstr(const char *str)
|
371
|
+
{
|
372
|
+
return rb_enc_interned_str_cstr(str, rb_utf8_encoding());
|
373
|
+
}
|
374
|
+
#else
|
375
|
+
static VALUE
|
376
|
+
interned_utf8_cstr(const char *str)
|
377
|
+
{
|
378
|
+
VALUE rb_str = rb_utf8_str_new_cstr(str);
|
379
|
+
return rb_funcall(rb_str, rb_intern("-@"), 0);
|
380
|
+
}
|
381
|
+
#endif
|
382
|
+
|
383
|
+
/* call-seq: stmt.column_name(index)
|
384
|
+
*
|
385
|
+
* Get the column name at +index+. 0 based.
|
386
|
+
*/
|
387
|
+
static VALUE
|
388
|
+
column_name(VALUE self, VALUE index)
|
389
|
+
{
|
390
|
+
sqlite3StmtRubyPtr ctx;
|
391
|
+
const char *name;
|
392
|
+
|
393
|
+
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
|
394
|
+
REQUIRE_OPEN_STMT(ctx);
|
395
|
+
|
396
|
+
name = sqlite3_column_name(ctx->st, (int)NUM2INT(index));
|
397
|
+
|
398
|
+
VALUE ret = Qnil;
|
399
|
+
|
400
|
+
if (name) {
|
401
|
+
ret = interned_utf8_cstr(name);
|
402
|
+
}
|
403
|
+
return ret;
|
404
|
+
}
|
405
|
+
|
406
|
+
/* call-seq: stmt.column_decltype(index)
|
407
|
+
*
|
408
|
+
* Get the column type at +index+. 0 based.
|
409
|
+
*/
|
410
|
+
static VALUE
|
411
|
+
column_decltype(VALUE self, VALUE index)
|
412
|
+
{
|
413
|
+
sqlite3StmtRubyPtr ctx;
|
414
|
+
const char *name;
|
415
|
+
|
416
|
+
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
|
417
|
+
REQUIRE_OPEN_STMT(ctx);
|
418
|
+
|
419
|
+
name = sqlite3_column_decltype(ctx->st, (int)NUM2INT(index));
|
420
|
+
|
421
|
+
if (name) { return rb_str_new2(name); }
|
422
|
+
return Qnil;
|
423
|
+
}
|
424
|
+
|
425
|
+
/* call-seq: stmt.bind_parameter_count
|
426
|
+
*
|
427
|
+
* Return the number of bind parameters
|
428
|
+
*/
|
429
|
+
static VALUE
|
430
|
+
bind_parameter_count(VALUE self)
|
431
|
+
{
|
432
|
+
sqlite3StmtRubyPtr ctx;
|
433
|
+
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
|
434
|
+
REQUIRE_OPEN_STMT(ctx);
|
435
|
+
|
436
|
+
return INT2NUM(sqlite3_bind_parameter_count(ctx->st));
|
437
|
+
}
|
438
|
+
|
439
|
+
enum stmt_stat_sym {
|
440
|
+
stmt_stat_sym_fullscan_steps,
|
441
|
+
stmt_stat_sym_sorts,
|
442
|
+
stmt_stat_sym_autoindexes,
|
443
|
+
stmt_stat_sym_vm_steps,
|
444
|
+
#ifdef SQLITE_STMTSTATUS_REPREPARE
|
445
|
+
stmt_stat_sym_reprepares,
|
446
|
+
#endif
|
447
|
+
#ifdef SQLITE_STMTSTATUS_RUN
|
448
|
+
stmt_stat_sym_runs,
|
449
|
+
#endif
|
450
|
+
#ifdef SQLITE_STMTSTATUS_FILTER_MISS
|
451
|
+
stmt_stat_sym_filter_misses,
|
452
|
+
#endif
|
453
|
+
#ifdef SQLITE_STMTSTATUS_FILTER_HIT
|
454
|
+
stmt_stat_sym_filter_hits,
|
455
|
+
#endif
|
456
|
+
stmt_stat_sym_last
|
457
|
+
};
|
458
|
+
|
459
|
+
static VALUE stmt_stat_symbols[stmt_stat_sym_last];
|
460
|
+
|
461
|
+
static void
|
462
|
+
setup_stmt_stat_symbols(void)
|
463
|
+
{
|
464
|
+
if (stmt_stat_symbols[0] == 0) {
|
465
|
+
#define S(s) stmt_stat_symbols[stmt_stat_sym_##s] = ID2SYM(rb_intern_const(#s))
|
466
|
+
S(fullscan_steps);
|
467
|
+
S(sorts);
|
468
|
+
S(autoindexes);
|
469
|
+
S(vm_steps);
|
470
|
+
#ifdef SQLITE_STMTSTATUS_REPREPARE
|
471
|
+
S(reprepares);
|
472
|
+
#endif
|
473
|
+
#ifdef SQLITE_STMTSTATUS_RUN
|
474
|
+
S(runs);
|
475
|
+
#endif
|
476
|
+
#ifdef SQLITE_STMTSTATUS_FILTER_MISS
|
477
|
+
S(filter_misses);
|
478
|
+
#endif
|
479
|
+
#ifdef SQLITE_STMTSTATUS_FILTER_HIT
|
480
|
+
S(filter_hits);
|
481
|
+
#endif
|
482
|
+
#undef S
|
483
|
+
}
|
484
|
+
}
|
485
|
+
|
486
|
+
static size_t
|
487
|
+
stmt_stat_internal(VALUE hash_or_sym, sqlite3_stmt *stmt)
|
488
|
+
{
|
489
|
+
VALUE hash = Qnil, key = Qnil;
|
490
|
+
|
491
|
+
setup_stmt_stat_symbols();
|
492
|
+
|
493
|
+
if (RB_TYPE_P(hash_or_sym, T_HASH)) {
|
494
|
+
hash = hash_or_sym;
|
495
|
+
} else if (SYMBOL_P(hash_or_sym)) {
|
496
|
+
key = hash_or_sym;
|
497
|
+
} else {
|
498
|
+
rb_raise(rb_eTypeError, "non-hash or symbol argument");
|
499
|
+
}
|
500
|
+
|
501
|
+
#define SET(name, stat_type) \
|
502
|
+
if (key == stmt_stat_symbols[stmt_stat_sym_##name]) \
|
503
|
+
return sqlite3_stmt_status(stmt, stat_type, 0); \
|
504
|
+
else if (hash != Qnil) \
|
505
|
+
rb_hash_aset(hash, stmt_stat_symbols[stmt_stat_sym_##name], SIZET2NUM(sqlite3_stmt_status(stmt, stat_type, 0)));
|
506
|
+
|
507
|
+
SET(fullscan_steps, SQLITE_STMTSTATUS_FULLSCAN_STEP);
|
508
|
+
SET(sorts, SQLITE_STMTSTATUS_SORT);
|
509
|
+
SET(autoindexes, SQLITE_STMTSTATUS_AUTOINDEX);
|
510
|
+
SET(vm_steps, SQLITE_STMTSTATUS_VM_STEP);
|
511
|
+
#ifdef SQLITE_STMTSTATUS_REPREPARE
|
512
|
+
SET(reprepares, SQLITE_STMTSTATUS_REPREPARE);
|
513
|
+
#endif
|
514
|
+
#ifdef SQLITE_STMTSTATUS_RUN
|
515
|
+
SET(runs, SQLITE_STMTSTATUS_RUN);
|
516
|
+
#endif
|
517
|
+
#ifdef SQLITE_STMTSTATUS_FILTER_MISS
|
518
|
+
SET(filter_misses, SQLITE_STMTSTATUS_FILTER_MISS);
|
519
|
+
#endif
|
520
|
+
#ifdef SQLITE_STMTSTATUS_FILTER_HIT
|
521
|
+
SET(filter_hits, SQLITE_STMTSTATUS_FILTER_HIT);
|
522
|
+
#endif
|
523
|
+
#undef SET
|
524
|
+
|
525
|
+
if (!NIL_P(key)) { /* matched key should return above */
|
526
|
+
rb_raise(rb_eArgError, "unknown key: %"PRIsVALUE, rb_sym2str(key));
|
527
|
+
}
|
528
|
+
|
529
|
+
return 0;
|
530
|
+
}
|
531
|
+
|
532
|
+
/* call-seq: stmt.stats_as_hash(hash)
|
533
|
+
*
|
534
|
+
* Returns a Hash containing information about the statement.
|
535
|
+
*/
|
536
|
+
static VALUE
|
537
|
+
stats_as_hash(VALUE self)
|
538
|
+
{
|
539
|
+
sqlite3StmtRubyPtr ctx;
|
540
|
+
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
|
541
|
+
REQUIRE_OPEN_STMT(ctx);
|
542
|
+
VALUE arg = rb_hash_new();
|
543
|
+
|
544
|
+
stmt_stat_internal(arg, ctx->st);
|
545
|
+
return arg;
|
546
|
+
}
|
547
|
+
|
548
|
+
/* call-seq: stmt.stmt_stat(hash_or_key)
|
549
|
+
*
|
550
|
+
* Returns a Hash containing information about the statement.
|
551
|
+
*/
|
552
|
+
static VALUE
|
553
|
+
stat_for(VALUE self, VALUE key)
|
554
|
+
{
|
555
|
+
sqlite3StmtRubyPtr ctx;
|
556
|
+
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
|
557
|
+
REQUIRE_OPEN_STMT(ctx);
|
558
|
+
|
559
|
+
if (SYMBOL_P(key)) {
|
560
|
+
size_t value = stmt_stat_internal(key, ctx->st);
|
561
|
+
return SIZET2NUM(value);
|
562
|
+
} else {
|
563
|
+
rb_raise(rb_eTypeError, "non-symbol given");
|
564
|
+
}
|
565
|
+
}
|
566
|
+
|
567
|
+
#ifdef SQLITE_STMTSTATUS_MEMUSED
|
568
|
+
/* call-seq: stmt.memory_used
|
569
|
+
*
|
570
|
+
* Return the approximate number of bytes of heap memory used to store the prepared statement
|
571
|
+
*/
|
572
|
+
static VALUE
|
573
|
+
memused(VALUE self)
|
574
|
+
{
|
575
|
+
sqlite3StmtRubyPtr ctx;
|
576
|
+
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
|
577
|
+
REQUIRE_OPEN_STMT(ctx);
|
578
|
+
|
579
|
+
return INT2NUM(sqlite3_stmt_status(ctx->st, SQLITE_STMTSTATUS_MEMUSED, 0));
|
580
|
+
}
|
581
|
+
#endif
|
582
|
+
|
583
|
+
#ifdef HAVE_SQLITE3_COLUMN_DATABASE_NAME
|
584
|
+
|
585
|
+
/* call-seq: stmt.database_name(column_index)
|
586
|
+
*
|
587
|
+
* Return the database name for the column at +column_index+
|
588
|
+
*/
|
589
|
+
static VALUE
|
590
|
+
database_name(VALUE self, VALUE index)
|
591
|
+
{
|
592
|
+
sqlite3StmtRubyPtr ctx;
|
593
|
+
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
|
594
|
+
REQUIRE_OPEN_STMT(ctx);
|
595
|
+
|
596
|
+
return SQLITE3_UTF8_STR_NEW2(
|
597
|
+
sqlite3_column_database_name(ctx->st, NUM2INT(index)));
|
598
|
+
}
|
599
|
+
|
600
|
+
#endif
|
601
|
+
|
602
|
+
/* call-seq: stmt.sql
|
603
|
+
*
|
604
|
+
* Returns the SQL statement used to create this prepared statement
|
605
|
+
*/
|
606
|
+
static VALUE
|
607
|
+
get_sql(VALUE self)
|
608
|
+
{
|
609
|
+
sqlite3StmtRubyPtr ctx;
|
610
|
+
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
|
611
|
+
REQUIRE_OPEN_STMT(ctx);
|
612
|
+
|
613
|
+
return rb_obj_freeze(SQLITE3_UTF8_STR_NEW2(sqlite3_sql(ctx->st)));
|
614
|
+
}
|
615
|
+
|
616
|
+
/* call-seq: stmt.expanded_sql
|
617
|
+
*
|
618
|
+
* Returns the SQL statement used to create this prepared statement, but
|
619
|
+
* with bind parameters substituted in to the statement.
|
620
|
+
*/
|
621
|
+
static VALUE
|
622
|
+
get_expanded_sql(VALUE self)
|
623
|
+
{
|
624
|
+
sqlite3StmtRubyPtr ctx;
|
625
|
+
char *expanded_sql;
|
626
|
+
VALUE rb_expanded_sql;
|
627
|
+
|
628
|
+
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
|
629
|
+
REQUIRE_OPEN_STMT(ctx);
|
630
|
+
|
631
|
+
expanded_sql = sqlite3_expanded_sql(ctx->st);
|
632
|
+
rb_expanded_sql = rb_obj_freeze(SQLITE3_UTF8_STR_NEW2(expanded_sql));
|
633
|
+
sqlite3_free(expanded_sql);
|
634
|
+
|
635
|
+
return rb_expanded_sql;
|
636
|
+
}
|
637
|
+
|
638
|
+
void
|
639
|
+
init_sqlite3_statement(void)
|
640
|
+
{
|
641
|
+
cSqlite3Statement = rb_define_class_under(mSqlite3, "Statement", rb_cObject);
|
642
|
+
|
643
|
+
rb_define_alloc_func(cSqlite3Statement, allocate);
|
644
|
+
rb_define_method(cSqlite3Statement, "close", sqlite3_rb_close, 0);
|
645
|
+
rb_define_method(cSqlite3Statement, "closed?", closed_p, 0);
|
646
|
+
rb_define_method(cSqlite3Statement, "bind_param", bind_param, 2);
|
647
|
+
rb_define_method(cSqlite3Statement, "reset!", reset_bang, 0);
|
648
|
+
rb_define_method(cSqlite3Statement, "clear_bindings!", clear_bindings_bang, 0);
|
649
|
+
rb_define_method(cSqlite3Statement, "step", step, 0);
|
650
|
+
rb_define_method(cSqlite3Statement, "done?", done_p, 0);
|
651
|
+
rb_define_method(cSqlite3Statement, "column_count", column_count, 0);
|
652
|
+
rb_define_method(cSqlite3Statement, "column_name", column_name, 1);
|
653
|
+
rb_define_method(cSqlite3Statement, "column_decltype", column_decltype, 1);
|
654
|
+
rb_define_method(cSqlite3Statement, "bind_parameter_count", bind_parameter_count, 0);
|
655
|
+
rb_define_method(cSqlite3Statement, "sql", get_sql, 0);
|
656
|
+
rb_define_method(cSqlite3Statement, "expanded_sql", get_expanded_sql, 0);
|
657
|
+
#ifdef HAVE_SQLITE3_COLUMN_DATABASE_NAME
|
658
|
+
rb_define_method(cSqlite3Statement, "database_name", database_name, 1);
|
659
|
+
#endif
|
660
|
+
#ifdef SQLITE_STMTSTATUS_MEMUSED
|
661
|
+
rb_define_method(cSqlite3Statement, "memused", memused, 0);
|
662
|
+
#endif
|
663
|
+
|
664
|
+
rb_define_private_method(cSqlite3Statement, "prepare", prepare, 2);
|
665
|
+
rb_define_private_method(cSqlite3Statement, "stats_as_hash", stats_as_hash, 0);
|
666
|
+
rb_define_private_method(cSqlite3Statement, "stat_for", stat_for, 1);
|
667
|
+
}
|
@@ -0,0 +1,16 @@
|
|
1
|
+
#ifndef SQLITE3_STATEMENT_RUBY
|
2
|
+
#define SQLITE3_STATEMENT_RUBY
|
3
|
+
|
4
|
+
#include <sqlite3_ruby.h>
|
5
|
+
|
6
|
+
struct _sqlite3StmtRuby {
|
7
|
+
sqlite3_stmt *st;
|
8
|
+
int done_p;
|
9
|
+
};
|
10
|
+
|
11
|
+
typedef struct _sqlite3StmtRuby sqlite3StmtRuby;
|
12
|
+
typedef sqlite3StmtRuby *sqlite3StmtRubyPtr;
|
13
|
+
|
14
|
+
void init_sqlite3_statement();
|
15
|
+
|
16
|
+
#endif
|
@@ -0,0 +1,20 @@
|
|
1
|
+
#define timespecclear(tsp) (tsp)->tv_sec = (tsp)->tv_nsec = 0
|
2
|
+
#define timespecisset(tsp) ((tsp)->tv_sec || (tsp)->tv_nsec)
|
3
|
+
#define timespecisvalid(tsp) \
|
4
|
+
((tsp)->tv_nsec >= 0 && (tsp)->tv_nsec < 1000000000L)
|
5
|
+
#define timespeccmp(tsp, usp, cmp) \
|
6
|
+
(((tsp)->tv_sec == (usp)->tv_sec) ? \
|
7
|
+
((tsp)->tv_nsec cmp (usp)->tv_nsec) : \
|
8
|
+
((tsp)->tv_sec cmp (usp)->tv_sec))
|
9
|
+
#define timespecsub(tsp, usp, vsp) \
|
10
|
+
do { \
|
11
|
+
(vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec; \
|
12
|
+
(vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec; \
|
13
|
+
if ((vsp)->tv_nsec < 0) { \
|
14
|
+
(vsp)->tv_sec--; \
|
15
|
+
(vsp)->tv_nsec += 1000000000L; \
|
16
|
+
} \
|
17
|
+
} while (0)
|
18
|
+
#define timespecafter(tsp, usp) \
|
19
|
+
(((tsp)->tv_sec > (usp)->tv_sec) || \
|
20
|
+
((tsp)->tv_sec == (usp)->tv_sec && (tsp)->tv_nsec > (usp)->tv_nsec))
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|