sqlite3 1.3.13 → 1.4.2
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 +5 -5
- data/.gemtest +0 -0
- data/.travis.yml +33 -0
- data/CHANGELOG.rdoc +27 -1
- data/Gemfile +6 -4
- data/Manifest.txt +12 -4
- data/README.rdoc +1 -1
- data/Rakefile +0 -2
- data/appveyor.yml +36 -0
- data/ext/sqlite3/aggregator.c +273 -0
- data/ext/sqlite3/aggregator.h +12 -0
- data/ext/sqlite3/database.c +140 -201
- data/ext/sqlite3/database.h +2 -0
- data/ext/sqlite3/exception.c +6 -2
- data/ext/sqlite3/extconf.rb +39 -10
- data/ext/sqlite3/sqlite3.c +10 -1
- data/ext/sqlite3/sqlite3_ruby.h +0 -7
- data/ext/sqlite3/statement.c +13 -18
- data/lib/sqlite3/constants.rb +1 -0
- data/lib/sqlite3/database.rb +196 -51
- data/lib/sqlite3/errors.rb +1 -10
- data/lib/sqlite3/pragmas.rb +7 -7
- data/lib/sqlite3/resultset.rb +2 -10
- data/lib/sqlite3/version.rb +3 -3
- data/{tasks → rakelib}/faq.rake +0 -0
- data/{tasks → rakelib}/gem.rake +6 -4
- data/{tasks → rakelib}/native.rake +4 -0
- data/{tasks → rakelib}/vendor_sqlite3.rake +0 -0
- data/test/test_database.rb +79 -6
- data/test/test_database_flags.rb +95 -0
- data/test/test_database_readwrite.rb +41 -0
- data/test/test_integration.rb +12 -81
- data/test/test_integration_aggregate.rb +336 -0
- data/test/test_integration_resultset.rb +0 -17
- data/test/test_statement.rb +11 -8
- metadata +56 -27
data/ext/sqlite3/database.c
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
#include <sqlite3_ruby.h>
|
2
|
+
#include <aggregator.h>
|
2
3
|
|
3
4
|
#define REQUIRE_OPEN_DB(_ctxt) \
|
4
5
|
if(!_ctxt->db) \
|
5
6
|
rb_raise(rb_path2class("SQLite3::Exception"), "cannot use a closed database");
|
6
7
|
|
7
8
|
VALUE cSqlite3Database;
|
8
|
-
static VALUE sym_utf16, sym_results_as_hash, sym_type_translation;
|
9
9
|
|
10
10
|
static void deallocate(void * ctx)
|
11
11
|
{
|
@@ -32,126 +32,32 @@ utf16_string_value_ptr(VALUE str)
|
|
32
32
|
|
33
33
|
static VALUE sqlite3_rb_close(VALUE self);
|
34
34
|
|
35
|
-
|
36
|
-
*
|
37
|
-
* Create a new Database object that opens the given file. If utf16
|
38
|
-
* is +true+, the filename is interpreted as a UTF-16 encoded string.
|
39
|
-
*
|
40
|
-
* By default, the new database will return result rows as arrays
|
41
|
-
* (#results_as_hash) and has type translation disabled (#type_translation=).
|
42
|
-
*/
|
43
|
-
static VALUE initialize(int argc, VALUE *argv, VALUE self)
|
35
|
+
static VALUE rb_sqlite3_open_v2(VALUE self, VALUE file, VALUE mode, VALUE zvfs)
|
44
36
|
{
|
45
37
|
sqlite3RubyPtr ctx;
|
46
|
-
VALUE file;
|
47
|
-
VALUE opts;
|
48
|
-
VALUE zvfs;
|
49
38
|
VALUE flags;
|
50
|
-
#ifdef HAVE_SQLITE3_OPEN_V2
|
51
|
-
int mode = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
|
52
|
-
#endif
|
53
39
|
int status;
|
54
40
|
|
55
41
|
Data_Get_Struct(self, sqlite3Ruby, ctx);
|
56
42
|
|
57
|
-
|
43
|
+
#if defined TAINTING_SUPPORT
|
58
44
|
#if defined StringValueCStr
|
59
45
|
StringValuePtr(file);
|
60
46
|
rb_check_safe_obj(file);
|
61
47
|
#else
|
62
48
|
Check_SafeStr(file);
|
63
49
|
#endif
|
64
|
-
if(NIL_P(opts)) opts = rb_hash_new();
|
65
|
-
else Check_Type(opts, T_HASH);
|
66
|
-
|
67
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
68
|
-
if(UTF16_LE_P(file) || UTF16_BE_P(file)) {
|
69
|
-
status = sqlite3_open16(utf16_string_value_ptr(file), &ctx->db);
|
70
|
-
} else {
|
71
|
-
#endif
|
72
|
-
|
73
|
-
if(Qtrue == rb_hash_aref(opts, sym_utf16)) {
|
74
|
-
status = sqlite3_open16(utf16_string_value_ptr(file), &ctx->db);
|
75
|
-
} else {
|
76
|
-
|
77
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
78
|
-
if(!UTF8_P(file)) {
|
79
|
-
file = rb_str_export_to_enc(file, rb_utf8_encoding());
|
80
|
-
}
|
81
50
|
#endif
|
82
51
|
|
83
|
-
/* The three primary flag values for sqlite3_open_v2 are:
|
84
|
-
* SQLITE_OPEN_READONLY
|
85
|
-
* SQLITE_OPEN_READWRITE
|
86
|
-
* SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE -- always used for sqlite3_open and sqlite3_open16
|
87
|
-
*/
|
88
|
-
if (Qtrue == rb_hash_aref(opts, ID2SYM(rb_intern("readonly")))) {
|
89
|
-
#ifdef HAVE_SQLITE3_OPEN_V2
|
90
|
-
mode = SQLITE_OPEN_READONLY;
|
91
|
-
#else
|
92
|
-
rb_raise(rb_eNotImpError, "sqlite3-ruby was compiled against a version of sqlite that does not support readonly databases");
|
93
|
-
#endif
|
94
|
-
}
|
95
|
-
if (Qtrue == rb_hash_aref(opts, ID2SYM(rb_intern("readwrite")))) {
|
96
|
-
#ifdef HAVE_SQLITE3_OPEN_V2
|
97
|
-
if (mode == SQLITE_OPEN_READONLY) {
|
98
|
-
rb_raise(rb_eRuntimeError, "conflicting options: readonly and readwrite");
|
99
|
-
}
|
100
|
-
mode = SQLITE_OPEN_READWRITE;
|
101
|
-
#else
|
102
|
-
rb_raise(rb_eNotImpError, "sqlite3-ruby was compiled against a version of sqlite that does not support readwrite without create");
|
103
|
-
#endif
|
104
|
-
}
|
105
|
-
flags = rb_hash_aref(opts, ID2SYM(rb_intern("flags")));
|
106
|
-
if (flags != Qnil) {
|
107
|
-
#ifdef HAVE_SQLITE3_OPEN_V2
|
108
|
-
if ((mode & SQLITE_OPEN_CREATE) == 0) {
|
109
|
-
rb_raise(rb_eRuntimeError, "conflicting options: flags with readonly and/or readwrite");
|
110
|
-
}
|
111
|
-
mode = (int)NUM2INT(flags);
|
112
|
-
#else
|
113
|
-
rb_raise(rb_eNotImpError, "sqlite3-ruby was compiled against a version of sqlite that does not support flags on open");
|
114
|
-
#endif
|
115
|
-
}
|
116
|
-
#ifdef HAVE_SQLITE3_OPEN_V2
|
117
52
|
status = sqlite3_open_v2(
|
118
53
|
StringValuePtr(file),
|
119
54
|
&ctx->db,
|
120
|
-
mode,
|
55
|
+
NUM2INT(mode),
|
121
56
|
NIL_P(zvfs) ? NULL : StringValuePtr(zvfs)
|
122
57
|
);
|
123
|
-
#else
|
124
|
-
status = sqlite3_open(
|
125
|
-
StringValuePtr(file),
|
126
|
-
&ctx->db
|
127
|
-
);
|
128
|
-
#endif
|
129
|
-
}
|
130
|
-
|
131
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
132
|
-
}
|
133
|
-
#endif
|
134
58
|
|
135
59
|
CHECK(ctx->db, status)
|
136
60
|
|
137
|
-
rb_iv_set(self, "@tracefunc", Qnil);
|
138
|
-
rb_iv_set(self, "@authorizer", Qnil);
|
139
|
-
rb_iv_set(self, "@encoding", Qnil);
|
140
|
-
rb_iv_set(self, "@busy_handler", Qnil);
|
141
|
-
rb_iv_set(self, "@collations", rb_hash_new());
|
142
|
-
rb_iv_set(self, "@functions", rb_hash_new());
|
143
|
-
rb_iv_set(self, "@results_as_hash", rb_hash_aref(opts, sym_results_as_hash));
|
144
|
-
rb_iv_set(self, "@type_translation", rb_hash_aref(opts, sym_type_translation));
|
145
|
-
#ifdef HAVE_SQLITE3_OPEN_V2
|
146
|
-
rb_iv_set(self, "@readonly", (mode & SQLITE_OPEN_READONLY) ? Qtrue : Qfalse);
|
147
|
-
#else
|
148
|
-
rb_iv_set(self, "@readonly", Qfalse);
|
149
|
-
#endif
|
150
|
-
|
151
|
-
if(rb_block_given_p()) {
|
152
|
-
rb_ensure(rb_yield, self, sqlite3_rb_close, self);
|
153
|
-
}
|
154
|
-
|
155
61
|
return self;
|
156
62
|
}
|
157
63
|
|
@@ -170,6 +76,8 @@ static VALUE sqlite3_rb_close(VALUE self)
|
|
170
76
|
|
171
77
|
ctx->db = NULL;
|
172
78
|
|
79
|
+
rb_iv_set(self, "-aggregators", Qnil);
|
80
|
+
|
173
81
|
return self;
|
174
82
|
}
|
175
83
|
|
@@ -297,7 +205,7 @@ static VALUE last_insert_row_id(VALUE self)
|
|
297
205
|
return LL2NUM(sqlite3_last_insert_rowid(ctx->db));
|
298
206
|
}
|
299
207
|
|
300
|
-
|
208
|
+
VALUE sqlite3val2rb(sqlite3_value * val)
|
301
209
|
{
|
302
210
|
switch(sqlite3_value_type(val)) {
|
303
211
|
case SQLITE_INTEGER:
|
@@ -307,23 +215,16 @@ static VALUE sqlite3val2rb(sqlite3_value * val)
|
|
307
215
|
return rb_float_new(sqlite3_value_double(val));
|
308
216
|
break;
|
309
217
|
case SQLITE_TEXT:
|
310
|
-
return
|
218
|
+
return rb_str_new2((const char *)sqlite3_value_text(val));
|
311
219
|
break;
|
312
220
|
case SQLITE_BLOB: {
|
313
221
|
/* Sqlite warns calling sqlite3_value_bytes may invalidate pointer from sqlite3_value_blob,
|
314
222
|
so we explicitly get the length before getting blob pointer.
|
315
|
-
Note that rb_str_new
|
223
|
+
Note that rb_str_new apparently create string with ASCII-8BIT (BINARY) encoding,
|
316
224
|
which is what we want, as blobs are binary
|
317
225
|
*/
|
318
226
|
int len = sqlite3_value_bytes(val);
|
319
|
-
|
320
|
-
return rb_tainted_str_new((const char *)sqlite3_value_blob(val), len);
|
321
|
-
#else
|
322
|
-
/* When encoding is not available, make it class SQLite3::Blob. */
|
323
|
-
VALUE strargv[1];
|
324
|
-
strargv[0] = rb_tainted_str_new((const char *)sqlite3_value_blob(val), len);
|
325
|
-
return rb_class_new_instance(1, strargv, cSqlite3Blob);
|
326
|
-
#endif
|
227
|
+
return rb_str_new((const char *)sqlite3_value_blob(val), len);
|
327
228
|
break;
|
328
229
|
}
|
329
230
|
case SQLITE_NULL:
|
@@ -334,7 +235,7 @@ static VALUE sqlite3val2rb(sqlite3_value * val)
|
|
334
235
|
}
|
335
236
|
}
|
336
237
|
|
337
|
-
|
238
|
+
void set_sqlite3_func_result(sqlite3_context * ctx, VALUE result)
|
338
239
|
{
|
339
240
|
switch(TYPE(result)) {
|
340
241
|
case T_NIL:
|
@@ -358,9 +259,7 @@ static void set_sqlite3_func_result(sqlite3_context * ctx, VALUE result)
|
|
358
259
|
break;
|
359
260
|
case T_STRING:
|
360
261
|
if(CLASS_OF(result) == cSqlite3Blob
|
361
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
362
262
|
|| rb_enc_get_index(result) == rb_ascii8bit_encindex()
|
363
|
-
#endif
|
364
263
|
) {
|
365
264
|
sqlite3_result_blob(
|
366
265
|
ctx,
|
@@ -409,12 +308,12 @@ int rb_proc_arity(VALUE self)
|
|
409
308
|
}
|
410
309
|
#endif
|
411
310
|
|
412
|
-
/* call-seq:
|
311
|
+
/* call-seq: define_function_with_flags(name, flags) { |args,...| }
|
413
312
|
*
|
414
|
-
* Define a function named +name+ with +args+. The arity of the block
|
313
|
+
* Define a function named +name+ with +args+ using TextRep bitflags +flags+. The arity of the block
|
415
314
|
* will be used as the arity for the function defined.
|
416
315
|
*/
|
417
|
-
static VALUE
|
316
|
+
static VALUE define_function_with_flags(VALUE self, VALUE name, VALUE flags)
|
418
317
|
{
|
419
318
|
sqlite3RubyPtr ctx;
|
420
319
|
VALUE block;
|
@@ -429,7 +328,7 @@ static VALUE define_function(VALUE self, VALUE name)
|
|
429
328
|
ctx->db,
|
430
329
|
StringValuePtr(name),
|
431
330
|
rb_proc_arity(block),
|
432
|
-
|
331
|
+
NUM2INT(flags),
|
433
332
|
(void *)block,
|
434
333
|
rb_sqlite3_func,
|
435
334
|
NULL,
|
@@ -443,70 +342,14 @@ static VALUE define_function(VALUE self, VALUE name)
|
|
443
342
|
return self;
|
444
343
|
}
|
445
344
|
|
446
|
-
|
447
|
-
{
|
448
|
-
VALUE method = rb_funcall(obj, rb_intern("method"), 1, ID2SYM(id));
|
449
|
-
VALUE arity = rb_funcall(method, rb_intern("arity"), 0);
|
450
|
-
|
451
|
-
return (int)NUM2INT(arity);
|
452
|
-
}
|
453
|
-
|
454
|
-
static void rb_sqlite3_step(sqlite3_context * ctx, int argc, sqlite3_value **argv)
|
455
|
-
{
|
456
|
-
VALUE callable = (VALUE)sqlite3_user_data(ctx);
|
457
|
-
VALUE * params = NULL;
|
458
|
-
int i;
|
459
|
-
|
460
|
-
if (argc > 0) {
|
461
|
-
params = xcalloc((size_t)argc, sizeof(VALUE *));
|
462
|
-
for(i = 0; i < argc; i++) {
|
463
|
-
params[i] = sqlite3val2rb(argv[i]);
|
464
|
-
}
|
465
|
-
}
|
466
|
-
rb_funcall2(callable, rb_intern("step"), argc, params);
|
467
|
-
xfree(params);
|
468
|
-
}
|
469
|
-
|
470
|
-
static void rb_sqlite3_final(sqlite3_context * ctx)
|
471
|
-
{
|
472
|
-
VALUE callable = (VALUE)sqlite3_user_data(ctx);
|
473
|
-
VALUE result = rb_funcall(callable, rb_intern("finalize"), 0);
|
474
|
-
set_sqlite3_func_result(ctx, result);
|
475
|
-
}
|
476
|
-
|
477
|
-
/* call-seq: define_aggregator(name, aggregator)
|
345
|
+
/* call-seq: define_function(name) { |args,...| }
|
478
346
|
*
|
479
|
-
* Define
|
480
|
-
*
|
481
|
-
* with row information and +finalize+ must return the return value for the
|
482
|
-
* aggregator function.
|
347
|
+
* Define a function named +name+ with +args+. The arity of the block
|
348
|
+
* will be used as the arity for the function defined.
|
483
349
|
*/
|
484
|
-
static VALUE
|
350
|
+
static VALUE define_function(VALUE self, VALUE name)
|
485
351
|
{
|
486
|
-
|
487
|
-
int arity, status;
|
488
|
-
|
489
|
-
Data_Get_Struct(self, sqlite3Ruby, ctx);
|
490
|
-
REQUIRE_OPEN_DB(ctx);
|
491
|
-
|
492
|
-
arity = sqlite3_obj_method_arity(aggregator, rb_intern("step"));
|
493
|
-
|
494
|
-
status = sqlite3_create_function(
|
495
|
-
ctx->db,
|
496
|
-
StringValuePtr(name),
|
497
|
-
arity,
|
498
|
-
SQLITE_UTF8,
|
499
|
-
(void *)aggregator,
|
500
|
-
NULL,
|
501
|
-
rb_sqlite3_step,
|
502
|
-
rb_sqlite3_final
|
503
|
-
);
|
504
|
-
|
505
|
-
rb_iv_set(self, "@agregator", aggregator);
|
506
|
-
|
507
|
-
CHECK(ctx->db, status);
|
508
|
-
|
509
|
-
return self;
|
352
|
+
return define_function_with_flags(self, name, INT2FIX(SQLITE_UTF8));
|
510
353
|
}
|
511
354
|
|
512
355
|
/* call-seq: interrupt
|
@@ -654,23 +497,36 @@ static VALUE set_busy_timeout(VALUE self, VALUE timeout)
|
|
654
497
|
return self;
|
655
498
|
}
|
656
499
|
|
500
|
+
/* call-seq: db.extended_result_codes = true
|
501
|
+
*
|
502
|
+
* Enable extended result codes in SQLite. These result codes allow for more
|
503
|
+
* detailed exception reporting, such a which type of constraint is violated.
|
504
|
+
*/
|
505
|
+
static VALUE set_extended_result_codes(VALUE self, VALUE enable)
|
506
|
+
{
|
507
|
+
sqlite3RubyPtr ctx;
|
508
|
+
Data_Get_Struct(self, sqlite3Ruby, ctx);
|
509
|
+
REQUIRE_OPEN_DB(ctx);
|
510
|
+
|
511
|
+
CHECK(ctx->db, sqlite3_extended_result_codes(ctx->db, RTEST(enable) ? 1 : 0));
|
512
|
+
|
513
|
+
return self;
|
514
|
+
}
|
515
|
+
|
657
516
|
int rb_comparator_func(void * ctx, int a_len, const void * a, int b_len, const void * b)
|
658
517
|
{
|
659
518
|
VALUE comparator;
|
660
519
|
VALUE a_str;
|
661
520
|
VALUE b_str;
|
662
521
|
VALUE comparison;
|
663
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
664
522
|
rb_encoding * internal_encoding;
|
665
523
|
|
666
524
|
internal_encoding = rb_default_internal_encoding();
|
667
|
-
#endif
|
668
525
|
|
669
526
|
comparator = (VALUE)ctx;
|
670
527
|
a_str = rb_str_new((const char *)a, a_len);
|
671
528
|
b_str = rb_str_new((const char *)b, b_len);
|
672
529
|
|
673
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
674
530
|
rb_enc_associate_index(a_str, rb_utf8_encindex());
|
675
531
|
rb_enc_associate_index(b_str, rb_utf8_encindex());
|
676
532
|
|
@@ -678,7 +534,6 @@ int rb_comparator_func(void * ctx, int a_len, const void * a, int b_len, const v
|
|
678
534
|
a_str = rb_str_export_to_enc(a_str, internal_encoding);
|
679
535
|
b_str = rb_str_export_to_enc(b_str, internal_encoding);
|
680
536
|
}
|
681
|
-
#endif
|
682
537
|
|
683
538
|
comparison = rb_funcall(comparator, rb_intern("compare"), 2, a_str, b_str);
|
684
539
|
|
@@ -765,7 +620,6 @@ static VALUE enable_load_extension(VALUE self, VALUE onoff)
|
|
765
620
|
}
|
766
621
|
#endif
|
767
622
|
|
768
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
769
623
|
static int enc_cb(void * _self, int UNUSED(columns), char **data, char **UNUSED(names))
|
770
624
|
{
|
771
625
|
VALUE self = (VALUE)_self;
|
@@ -776,16 +630,6 @@ static int enc_cb(void * _self, int UNUSED(columns), char **data, char **UNUSED(
|
|
776
630
|
|
777
631
|
return 0;
|
778
632
|
}
|
779
|
-
#else
|
780
|
-
static int enc_cb(void * _self, int UNUSED(columns), char **data, char **UNUSED(names))
|
781
|
-
{
|
782
|
-
VALUE self = (VALUE)_self;
|
783
|
-
|
784
|
-
rb_iv_set(self, "@encoding", rb_str_new2(data[0]));
|
785
|
-
|
786
|
-
return 0;
|
787
|
-
}
|
788
|
-
#endif
|
789
633
|
|
790
634
|
/* call-seq: db.encoding
|
791
635
|
*
|
@@ -822,6 +666,78 @@ static VALUE transaction_active_p(VALUE self)
|
|
822
666
|
return sqlite3_get_autocommit(ctx->db) ? Qfalse : Qtrue;
|
823
667
|
}
|
824
668
|
|
669
|
+
static int hash_callback_function(VALUE callback_ary, int count, char **data, char **columns)
|
670
|
+
{
|
671
|
+
VALUE new_hash = rb_hash_new();
|
672
|
+
int i;
|
673
|
+
|
674
|
+
for (i = 0; i < count; i++) {
|
675
|
+
if (data[i] == NULL) {
|
676
|
+
rb_hash_aset(new_hash, rb_str_new_cstr(columns[i]), Qnil);
|
677
|
+
} else {
|
678
|
+
rb_hash_aset(new_hash, rb_str_new_cstr(columns[i]), rb_str_new_cstr(data[i]));
|
679
|
+
}
|
680
|
+
}
|
681
|
+
|
682
|
+
rb_ary_push(callback_ary, new_hash);
|
683
|
+
|
684
|
+
return 0;
|
685
|
+
}
|
686
|
+
|
687
|
+
static int regular_callback_function(VALUE callback_ary, int count, char **data, char **columns)
|
688
|
+
{
|
689
|
+
VALUE new_ary = rb_ary_new();
|
690
|
+
int i;
|
691
|
+
|
692
|
+
for (i = 0; i < count; i++) {
|
693
|
+
if (data[i] == NULL) {
|
694
|
+
rb_ary_push(new_ary, Qnil);
|
695
|
+
} else {
|
696
|
+
rb_ary_push(new_ary, rb_str_new_cstr(data[i]));
|
697
|
+
}
|
698
|
+
}
|
699
|
+
|
700
|
+
rb_ary_push(callback_ary, new_ary);
|
701
|
+
|
702
|
+
return 0;
|
703
|
+
}
|
704
|
+
|
705
|
+
|
706
|
+
/* Is invoked by calling db.execute_batch2(sql, &block)
|
707
|
+
*
|
708
|
+
* Executes all statments in a given string separated by semicolons.
|
709
|
+
* If a query is made, all values returned are strings
|
710
|
+
* (except for 'NULL' values which return nil),
|
711
|
+
* so the user may parse values with a block.
|
712
|
+
* If no query is made, an empty array will be returned.
|
713
|
+
*/
|
714
|
+
static VALUE exec_batch(VALUE self, VALUE sql, VALUE results_as_hash)
|
715
|
+
{
|
716
|
+
sqlite3RubyPtr ctx;
|
717
|
+
int status;
|
718
|
+
VALUE callback_ary = rb_ary_new();
|
719
|
+
char *errMsg;
|
720
|
+
VALUE errexp;
|
721
|
+
|
722
|
+
Data_Get_Struct(self, sqlite3Ruby, ctx);
|
723
|
+
REQUIRE_OPEN_DB(ctx);
|
724
|
+
|
725
|
+
if(results_as_hash == Qtrue) {
|
726
|
+
status = sqlite3_exec(ctx->db, StringValuePtr(sql), hash_callback_function, callback_ary, &errMsg);
|
727
|
+
} else {
|
728
|
+
status = sqlite3_exec(ctx->db, StringValuePtr(sql), regular_callback_function, callback_ary, &errMsg);
|
729
|
+
}
|
730
|
+
|
731
|
+
if (status != SQLITE_OK)
|
732
|
+
{
|
733
|
+
errexp = rb_exc_new2(rb_eRuntimeError, errMsg);
|
734
|
+
sqlite3_free(errMsg);
|
735
|
+
rb_exc_raise(errexp);
|
736
|
+
}
|
737
|
+
|
738
|
+
return callback_ary;
|
739
|
+
}
|
740
|
+
|
825
741
|
/* call-seq: db.db_filename(database_name)
|
826
742
|
*
|
827
743
|
* Returns the file associated with +database_name+. Can return nil or an
|
@@ -840,16 +756,39 @@ static VALUE db_filename(VALUE self, VALUE db_name)
|
|
840
756
|
return Qnil;
|
841
757
|
}
|
842
758
|
|
759
|
+
static VALUE rb_sqlite3_open16(VALUE self, VALUE file)
|
760
|
+
{
|
761
|
+
int status;
|
762
|
+
sqlite3RubyPtr ctx;
|
763
|
+
|
764
|
+
Data_Get_Struct(self, sqlite3Ruby, ctx);
|
765
|
+
|
766
|
+
#if defined TAINTING_SUPPORT
|
767
|
+
#if defined StringValueCStr
|
768
|
+
StringValuePtr(file);
|
769
|
+
rb_check_safe_obj(file);
|
770
|
+
#else
|
771
|
+
Check_SafeStr(file);
|
772
|
+
#endif
|
773
|
+
#endif
|
774
|
+
|
775
|
+
status = sqlite3_open16(utf16_string_value_ptr(file), &ctx->db);
|
776
|
+
|
777
|
+
CHECK(ctx->db, status)
|
778
|
+
|
779
|
+
return INT2NUM(status);
|
780
|
+
}
|
781
|
+
|
843
782
|
void init_sqlite3_database()
|
844
783
|
{
|
845
|
-
ID id_utf16, id_results_as_hash, id_type_translation;
|
846
784
|
#if 0
|
847
785
|
VALUE mSqlite3 = rb_define_module("SQLite3");
|
848
786
|
#endif
|
849
787
|
cSqlite3Database = rb_define_class_under(mSqlite3, "Database", rb_cObject);
|
850
788
|
|
851
789
|
rb_define_alloc_func(cSqlite3Database, allocate);
|
852
|
-
|
790
|
+
rb_define_private_method(cSqlite3Database, "open_v2", rb_sqlite3_open_v2, 3);
|
791
|
+
rb_define_private_method(cSqlite3Database, "open16", rb_sqlite3_open16, 1);
|
853
792
|
rb_define_method(cSqlite3Database, "collation", collation, 2);
|
854
793
|
rb_define_method(cSqlite3Database, "close", sqlite3_rb_close, 0);
|
855
794
|
rb_define_method(cSqlite3Database, "closed?", closed_p, 0);
|
@@ -857,7 +796,10 @@ void init_sqlite3_database()
|
|
857
796
|
rb_define_method(cSqlite3Database, "trace", trace, -1);
|
858
797
|
rb_define_method(cSqlite3Database, "last_insert_row_id", last_insert_row_id, 0);
|
859
798
|
rb_define_method(cSqlite3Database, "define_function", define_function, 1);
|
860
|
-
rb_define_method(cSqlite3Database, "
|
799
|
+
rb_define_method(cSqlite3Database, "define_function_with_flags", define_function_with_flags, 2);
|
800
|
+
/* public "define_aggregator" is now a shim around define_aggregator2
|
801
|
+
* implemented in Ruby */
|
802
|
+
rb_define_private_method(cSqlite3Database, "define_aggregator2", rb_sqlite3_define_aggregator2, 2);
|
861
803
|
rb_define_method(cSqlite3Database, "interrupt", interrupt, 0);
|
862
804
|
rb_define_method(cSqlite3Database, "errmsg", errmsg, 0);
|
863
805
|
rb_define_method(cSqlite3Database, "errcode", errcode_, 0);
|
@@ -866,7 +808,9 @@ void init_sqlite3_database()
|
|
866
808
|
rb_define_method(cSqlite3Database, "authorizer=", set_authorizer, 1);
|
867
809
|
rb_define_method(cSqlite3Database, "busy_handler", busy_handler, -1);
|
868
810
|
rb_define_method(cSqlite3Database, "busy_timeout=", set_busy_timeout, 1);
|
811
|
+
rb_define_method(cSqlite3Database, "extended_result_codes=", set_extended_result_codes, 1);
|
869
812
|
rb_define_method(cSqlite3Database, "transaction_active?", transaction_active_p, 0);
|
813
|
+
rb_define_private_method(cSqlite3Database, "exec_batch", exec_batch, 2);
|
870
814
|
rb_define_private_method(cSqlite3Database, "db_filename", db_filename, 1);
|
871
815
|
|
872
816
|
#ifdef HAVE_SQLITE3_LOAD_EXTENSION
|
@@ -879,10 +823,5 @@ void init_sqlite3_database()
|
|
879
823
|
|
880
824
|
rb_define_method(cSqlite3Database, "encoding", db_encoding, 0);
|
881
825
|
|
882
|
-
|
883
|
-
sym_utf16 = ID2SYM(id_utf16);
|
884
|
-
id_results_as_hash = rb_intern("results_as_hash");
|
885
|
-
sym_results_as_hash = ID2SYM(id_results_as_hash);
|
886
|
-
id_type_translation = rb_intern("type_translation");
|
887
|
-
sym_type_translation = ID2SYM(id_type_translation);
|
826
|
+
rb_sqlite3_aggregator_init();
|
888
827
|
}
|
data/ext/sqlite3/database.h
CHANGED
data/ext/sqlite3/exception.c
CHANGED
@@ -4,7 +4,9 @@ void rb_sqlite3_raise(sqlite3 * db, int status)
|
|
4
4
|
{
|
5
5
|
VALUE klass = Qnil;
|
6
6
|
|
7
|
-
|
7
|
+
/* Consider only lower 8 bits, to work correctly when
|
8
|
+
extended result codes are enabled. */
|
9
|
+
switch(status & 0xff) {
|
8
10
|
case SQLITE_OK:
|
9
11
|
return;
|
10
12
|
break;
|
@@ -90,5 +92,7 @@ void rb_sqlite3_raise(sqlite3 * db, int status)
|
|
90
92
|
klass = rb_eRuntimeError;
|
91
93
|
}
|
92
94
|
|
93
|
-
|
95
|
+
klass = rb_exc_new2(klass, sqlite3_errmsg(db));
|
96
|
+
rb_iv_set(klass, "@code", INT2FIX(status));
|
97
|
+
rb_exc_raise(klass);
|
94
98
|
}
|
data/ext/sqlite3/extconf.rb
CHANGED
@@ -6,15 +6,20 @@ require 'mkmf'
|
|
6
6
|
|
7
7
|
RbConfig::MAKEFILE_CONFIG['CC'] = ENV['CC'] if ENV['CC']
|
8
8
|
|
9
|
-
|
10
|
-
|
11
9
|
ldflags = cppflags = nil
|
12
10
|
if RbConfig::CONFIG["host_os"] =~ /darwin/
|
13
11
|
begin
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
12
|
+
if with_config('sqlcipher')
|
13
|
+
brew_prefix = `brew --prefix sqlcipher`.chomp
|
14
|
+
ldflags = "#{brew_prefix}/lib"
|
15
|
+
cppflags = "#{brew_prefix}/include/sqlcipher"
|
16
|
+
pkg_conf = "#{brew_prefix}/lib/pkgconfig"
|
17
|
+
else
|
18
|
+
brew_prefix = `brew --prefix sqlite3`.chomp
|
19
|
+
ldflags = "#{brew_prefix}/lib"
|
20
|
+
cppflags = "#{brew_prefix}/include"
|
21
|
+
pkg_conf = "#{brew_prefix}/lib/pkgconfig"
|
22
|
+
end
|
18
23
|
|
19
24
|
# pkg_config should be less error prone than parsing compiler
|
20
25
|
# commandline options, but we need to set default ldflags and cpp flags
|
@@ -24,15 +29,28 @@ if RbConfig::CONFIG["host_os"] =~ /darwin/
|
|
24
29
|
end
|
25
30
|
end
|
26
31
|
|
27
|
-
|
32
|
+
if with_config('sqlcipher')
|
33
|
+
pkg_config("sqlcipher")
|
34
|
+
else
|
35
|
+
pkg_config("sqlite3")
|
36
|
+
end
|
28
37
|
|
29
38
|
# --with-sqlite3-{dir,include,lib}
|
30
|
-
|
39
|
+
if with_config('sqlcipher')
|
40
|
+
$CFLAGS << ' -DUSING_SQLCIPHER'
|
41
|
+
dir_config("sqlcipher", cppflags, ldflags)
|
42
|
+
else
|
43
|
+
dir_config("sqlite3", cppflags, ldflags)
|
44
|
+
end
|
31
45
|
|
32
46
|
if RbConfig::CONFIG["host_os"] =~ /mswin/
|
33
47
|
$CFLAGS << ' -W3'
|
34
48
|
end
|
35
49
|
|
50
|
+
if RUBY_VERSION < '2.7'
|
51
|
+
$CFLAGS << ' -DTAINTING_SUPPORT'
|
52
|
+
end
|
53
|
+
|
36
54
|
def asplode missing
|
37
55
|
if RUBY_PLATFORM =~ /mingw|mswin/
|
38
56
|
abort "#{missing} is missing. Install SQLite3 from " +
|
@@ -49,7 +67,14 @@ end
|
|
49
67
|
|
50
68
|
asplode('sqlite3.h') unless find_header 'sqlite3.h'
|
51
69
|
find_library 'pthread', 'pthread_create' # 1.8 support. *shrug*
|
52
|
-
|
70
|
+
|
71
|
+
have_library 'dl' # for static builds
|
72
|
+
|
73
|
+
if with_config('sqlcipher')
|
74
|
+
asplode('sqlcipher') unless find_library 'sqlcipher', 'sqlite3_libversion_number'
|
75
|
+
else
|
76
|
+
asplode('sqlite3') unless find_library 'sqlite3', 'sqlite3_libversion_number'
|
77
|
+
end
|
53
78
|
|
54
79
|
# Functions defined in 1.9 but not 1.8
|
55
80
|
have_func('rb_proc_arity')
|
@@ -63,7 +88,11 @@ have_func('sqlite3_backup_init')
|
|
63
88
|
have_func('sqlite3_column_database_name')
|
64
89
|
have_func('sqlite3_enable_load_extension')
|
65
90
|
have_func('sqlite3_load_extension')
|
66
|
-
|
91
|
+
|
92
|
+
unless have_func('sqlite3_open_v2')
|
93
|
+
abort "Please use a newer version of SQLite3"
|
94
|
+
end
|
95
|
+
|
67
96
|
have_func('sqlite3_prepare_v2')
|
68
97
|
have_type('sqlite3_int64', 'sqlite3.h')
|
69
98
|
have_type('sqlite3_uint64', 'sqlite3.h')
|
data/ext/sqlite3/sqlite3.c
CHANGED
@@ -65,6 +65,15 @@ static VALUE libversion(VALUE UNUSED(klass))
|
|
65
65
|
return INT2NUM(sqlite3_libversion_number());
|
66
66
|
}
|
67
67
|
|
68
|
+
static VALUE using_sqlcipher(VALUE UNUSED(klass))
|
69
|
+
{
|
70
|
+
#ifdef USING_SQLCIPHER
|
71
|
+
return Qtrue;
|
72
|
+
#else
|
73
|
+
return Qfalse;
|
74
|
+
#endif
|
75
|
+
}
|
76
|
+
|
68
77
|
/* Returns the compile time setting of the SQLITE_THREADSAFE flag.
|
69
78
|
* See: https://www.sqlite.org/c3ref/threadsafe.html
|
70
79
|
*/
|
@@ -144,7 +153,7 @@ void Init_sqlite3_native()
|
|
144
153
|
#ifdef HAVE_SQLITE3_BACKUP_INIT
|
145
154
|
init_sqlite3_backup();
|
146
155
|
#endif
|
147
|
-
|
156
|
+
rb_define_singleton_method(mSqlite3, "sqlcipher?", using_sqlcipher, 0);
|
148
157
|
rb_define_singleton_method(mSqlite3, "libversion", libversion, 0);
|
149
158
|
rb_define_singleton_method(mSqlite3, "threadsafe", threadsafe_p, 0);
|
150
159
|
rb_define_const(mSqlite3, "SQLITE_VERSION", rb_str_new2(SQLITE_VERSION));
|
data/ext/sqlite3/sqlite3_ruby.h
CHANGED
@@ -12,7 +12,6 @@
|
|
12
12
|
# define UNUSED(x) x
|
13
13
|
#endif
|
14
14
|
|
15
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
16
15
|
#include <ruby/encoding.h>
|
17
16
|
|
18
17
|
#define USASCII_P(_obj) (rb_enc_get_index(_obj) == rb_usascii_encindex())
|
@@ -22,12 +21,6 @@
|
|
22
21
|
#define SQLITE3_UTF8_STR_NEW2(_obj) \
|
23
22
|
(rb_enc_associate_index(rb_str_new2(_obj), rb_utf8_encindex()))
|
24
23
|
|
25
|
-
#else
|
26
|
-
|
27
|
-
#define SQLITE3_UTF8_STR_NEW2(_obj) (rb_str_new2(_obj))
|
28
|
-
|
29
|
-
#endif
|
30
|
-
|
31
24
|
|
32
25
|
#include <sqlite3.h>
|
33
26
|
|