sqlite3 1.3.13-x64-mingw32 → 1.5.0-x64-mingw32
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of sqlite3 might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/.gemtest +0 -0
- data/{API_CHANGES.rdoc → API_CHANGES.md} +3 -4
- data/CHANGELOG.md +425 -0
- data/CONTRIBUTING.md +24 -0
- data/Gemfile +2 -14
- data/LICENSE-DEPENDENCIES +20 -0
- data/README.md +233 -0
- data/ext/sqlite3/aggregator.c +274 -0
- data/ext/sqlite3/aggregator.h +12 -0
- data/ext/sqlite3/database.c +171 -206
- data/ext/sqlite3/database.h +2 -0
- data/ext/sqlite3/exception.c +6 -2
- data/ext/sqlite3/extconf.rb +236 -55
- data/ext/sqlite3/sqlite3.c +12 -1
- data/ext/sqlite3/sqlite3_ruby.h +3 -7
- data/ext/sqlite3/statement.c +15 -20
- data/faq/faq.md +431 -0
- data/faq/faq.yml +1 -1
- data/lib/sqlite3/2.6/sqlite3_native.so +0 -0
- data/lib/sqlite3/2.7/sqlite3_native.so +0 -0
- data/lib/sqlite3/3.0/sqlite3_native.so +0 -0
- data/lib/sqlite3/constants.rb +2 -1
- data/lib/sqlite3/database.rb +202 -52
- data/lib/sqlite3/errors.rb +1 -10
- data/lib/sqlite3/pragmas.rb +17 -10
- data/lib/sqlite3/resultset.rb +2 -10
- data/lib/sqlite3/statement.rb +2 -1
- data/lib/sqlite3/translator.rb +1 -1
- data/lib/sqlite3/version.rb +3 -5
- data/test/helper.rb +9 -0
- data/test/test_database.rb +126 -11
- 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_sqlite3.rb +9 -0
- data/test/test_statement.rb +11 -8
- metadata +54 -85
- data/CHANGELOG.rdoc +0 -292
- data/Manifest.txt +0 -52
- data/README.rdoc +0 -118
- data/Rakefile +0 -10
- data/lib/sqlite3/2.0/sqlite3_native.so +0 -0
- data/lib/sqlite3/2.1/sqlite3_native.so +0 -0
- data/lib/sqlite3/2.2/sqlite3_native.so +0 -0
- data/lib/sqlite3/2.3/sqlite3_native.so +0 -0
- data/lib/sqlite3/2.4/sqlite3_native.so +0 -0
- data/setup.rb +0 -1333
- data/tasks/faq.rake +0 -9
- data/tasks/gem.rake +0 -38
- data/tasks/native.rake +0 -52
- data/tasks/vendor_sqlite3.rake +0 -97
data/ext/sqlite3/database.c
CHANGED
@@ -1,11 +1,16 @@
|
|
1
1
|
#include <sqlite3_ruby.h>
|
2
|
+
#include <aggregator.h>
|
3
|
+
|
4
|
+
#ifdef _MSC_VER
|
5
|
+
#pragma warning( push )
|
6
|
+
#pragma warning( disable : 4028 )
|
7
|
+
#endif
|
2
8
|
|
3
9
|
#define REQUIRE_OPEN_DB(_ctxt) \
|
4
10
|
if(!_ctxt->db) \
|
5
11
|
rb_raise(rb_path2class("SQLite3::Exception"), "cannot use a closed database");
|
6
12
|
|
7
13
|
VALUE cSqlite3Database;
|
8
|
-
static VALUE sym_utf16, sym_results_as_hash, sym_type_translation;
|
9
14
|
|
10
15
|
static void deallocate(void * ctx)
|
11
16
|
{
|
@@ -26,133 +31,55 @@ static char *
|
|
26
31
|
utf16_string_value_ptr(VALUE str)
|
27
32
|
{
|
28
33
|
StringValue(str);
|
29
|
-
rb_str_buf_cat(str, "\x00",
|
34
|
+
rb_str_buf_cat(str, "\x00\x00", 2L);
|
30
35
|
return RSTRING_PTR(str);
|
31
36
|
}
|
32
37
|
|
33
38
|
static VALUE sqlite3_rb_close(VALUE self);
|
34
39
|
|
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)
|
40
|
+
static VALUE rb_sqlite3_open_v2(VALUE self, VALUE file, VALUE mode, VALUE zvfs)
|
44
41
|
{
|
45
42
|
sqlite3RubyPtr ctx;
|
46
|
-
VALUE file;
|
47
|
-
VALUE opts;
|
48
|
-
VALUE zvfs;
|
49
|
-
VALUE flags;
|
50
|
-
#ifdef HAVE_SQLITE3_OPEN_V2
|
51
|
-
int mode = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
|
52
|
-
#endif
|
53
43
|
int status;
|
54
44
|
|
55
45
|
Data_Get_Struct(self, sqlite3Ruby, ctx);
|
56
46
|
|
57
|
-
|
58
|
-
#if defined StringValueCStr
|
47
|
+
#if defined TAINTING_SUPPORT
|
48
|
+
# if defined StringValueCStr
|
59
49
|
StringValuePtr(file);
|
60
50
|
rb_check_safe_obj(file);
|
61
|
-
#else
|
51
|
+
# else
|
62
52
|
Check_SafeStr(file);
|
63
|
-
#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 {
|
53
|
+
# endif
|
71
54
|
#endif
|
72
55
|
|
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
|
-
#endif
|
82
|
-
|
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
56
|
status = sqlite3_open_v2(
|
118
57
|
StringValuePtr(file),
|
119
58
|
&ctx->db,
|
120
|
-
mode,
|
59
|
+
NUM2INT(mode),
|
121
60
|
NIL_P(zvfs) ? NULL : StringValuePtr(zvfs)
|
122
61
|
);
|
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
62
|
|
135
63
|
CHECK(ctx->db, status)
|
136
64
|
|
137
|
-
|
138
|
-
|
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
|
65
|
+
return self;
|
66
|
+
}
|
150
67
|
|
151
|
-
|
152
|
-
|
153
|
-
|
68
|
+
static VALUE rb_sqlite3_disable_quirk_mode(VALUE self)
|
69
|
+
{
|
70
|
+
#if defined SQLITE_DBCONFIG_DQS_DDL
|
71
|
+
sqlite3RubyPtr ctx;
|
72
|
+
Data_Get_Struct(self, sqlite3Ruby, ctx);
|
154
73
|
|
155
|
-
return
|
74
|
+
if(!ctx->db) return Qfalse;
|
75
|
+
|
76
|
+
sqlite3_db_config(ctx->db, SQLITE_DBCONFIG_DQS_DDL, 0, (void*)0);
|
77
|
+
sqlite3_db_config(ctx->db, SQLITE_DBCONFIG_DQS_DML, 0, (void*)0);
|
78
|
+
|
79
|
+
return Qtrue;
|
80
|
+
#else
|
81
|
+
return Qfalse;
|
82
|
+
#endif
|
156
83
|
}
|
157
84
|
|
158
85
|
/* call-seq: db.close
|
@@ -170,6 +97,8 @@ static VALUE sqlite3_rb_close(VALUE self)
|
|
170
97
|
|
171
98
|
ctx->db = NULL;
|
172
99
|
|
100
|
+
rb_iv_set(self, "-aggregators", Qnil);
|
101
|
+
|
173
102
|
return self;
|
174
103
|
}
|
175
104
|
|
@@ -297,7 +226,7 @@ static VALUE last_insert_row_id(VALUE self)
|
|
297
226
|
return LL2NUM(sqlite3_last_insert_rowid(ctx->db));
|
298
227
|
}
|
299
228
|
|
300
|
-
|
229
|
+
VALUE sqlite3val2rb(sqlite3_value * val)
|
301
230
|
{
|
302
231
|
switch(sqlite3_value_type(val)) {
|
303
232
|
case SQLITE_INTEGER:
|
@@ -307,23 +236,16 @@ static VALUE sqlite3val2rb(sqlite3_value * val)
|
|
307
236
|
return rb_float_new(sqlite3_value_double(val));
|
308
237
|
break;
|
309
238
|
case SQLITE_TEXT:
|
310
|
-
return
|
239
|
+
return rb_str_new2((const char *)sqlite3_value_text(val));
|
311
240
|
break;
|
312
241
|
case SQLITE_BLOB: {
|
313
242
|
/* Sqlite warns calling sqlite3_value_bytes may invalidate pointer from sqlite3_value_blob,
|
314
243
|
so we explicitly get the length before getting blob pointer.
|
315
|
-
Note that rb_str_new
|
244
|
+
Note that rb_str_new apparently create string with ASCII-8BIT (BINARY) encoding,
|
316
245
|
which is what we want, as blobs are binary
|
317
246
|
*/
|
318
247
|
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
|
248
|
+
return rb_str_new((const char *)sqlite3_value_blob(val), len);
|
327
249
|
break;
|
328
250
|
}
|
329
251
|
case SQLITE_NULL:
|
@@ -334,7 +256,7 @@ static VALUE sqlite3val2rb(sqlite3_value * val)
|
|
334
256
|
}
|
335
257
|
}
|
336
258
|
|
337
|
-
|
259
|
+
void set_sqlite3_func_result(sqlite3_context * ctx, VALUE result)
|
338
260
|
{
|
339
261
|
switch(TYPE(result)) {
|
340
262
|
case T_NIL:
|
@@ -358,9 +280,7 @@ static void set_sqlite3_func_result(sqlite3_context * ctx, VALUE result)
|
|
358
280
|
break;
|
359
281
|
case T_STRING:
|
360
282
|
if(CLASS_OF(result) == cSqlite3Blob
|
361
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
362
283
|
|| rb_enc_get_index(result) == rb_ascii8bit_encindex()
|
363
|
-
#endif
|
364
284
|
) {
|
365
285
|
sqlite3_result_blob(
|
366
286
|
ctx,
|
@@ -409,12 +329,12 @@ int rb_proc_arity(VALUE self)
|
|
409
329
|
}
|
410
330
|
#endif
|
411
331
|
|
412
|
-
/* call-seq:
|
332
|
+
/* call-seq: define_function_with_flags(name, flags) { |args,...| }
|
413
333
|
*
|
414
|
-
* Define a function named +name+ with +args+. The arity of the block
|
334
|
+
* Define a function named +name+ with +args+ using TextRep bitflags +flags+. The arity of the block
|
415
335
|
* will be used as the arity for the function defined.
|
416
336
|
*/
|
417
|
-
static VALUE
|
337
|
+
static VALUE define_function_with_flags(VALUE self, VALUE name, VALUE flags)
|
418
338
|
{
|
419
339
|
sqlite3RubyPtr ctx;
|
420
340
|
VALUE block;
|
@@ -429,7 +349,7 @@ static VALUE define_function(VALUE self, VALUE name)
|
|
429
349
|
ctx->db,
|
430
350
|
StringValuePtr(name),
|
431
351
|
rb_proc_arity(block),
|
432
|
-
|
352
|
+
NUM2INT(flags),
|
433
353
|
(void *)block,
|
434
354
|
rb_sqlite3_func,
|
435
355
|
NULL,
|
@@ -443,70 +363,14 @@ static VALUE define_function(VALUE self, VALUE name)
|
|
443
363
|
return self;
|
444
364
|
}
|
445
365
|
|
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)
|
366
|
+
/* call-seq: define_function(name) { |args,...| }
|
478
367
|
*
|
479
|
-
* Define
|
480
|
-
*
|
481
|
-
* with row information and +finalize+ must return the return value for the
|
482
|
-
* aggregator function.
|
368
|
+
* Define a function named +name+ with +args+. The arity of the block
|
369
|
+
* will be used as the arity for the function defined.
|
483
370
|
*/
|
484
|
-
static VALUE
|
371
|
+
static VALUE define_function(VALUE self, VALUE name)
|
485
372
|
{
|
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;
|
373
|
+
return define_function_with_flags(self, name, INT2FIX(SQLITE_UTF8));
|
510
374
|
}
|
511
375
|
|
512
376
|
/* call-seq: interrupt
|
@@ -654,23 +518,36 @@ static VALUE set_busy_timeout(VALUE self, VALUE timeout)
|
|
654
518
|
return self;
|
655
519
|
}
|
656
520
|
|
521
|
+
/* call-seq: db.extended_result_codes = true
|
522
|
+
*
|
523
|
+
* Enable extended result codes in SQLite. These result codes allow for more
|
524
|
+
* detailed exception reporting, such a which type of constraint is violated.
|
525
|
+
*/
|
526
|
+
static VALUE set_extended_result_codes(VALUE self, VALUE enable)
|
527
|
+
{
|
528
|
+
sqlite3RubyPtr ctx;
|
529
|
+
Data_Get_Struct(self, sqlite3Ruby, ctx);
|
530
|
+
REQUIRE_OPEN_DB(ctx);
|
531
|
+
|
532
|
+
CHECK(ctx->db, sqlite3_extended_result_codes(ctx->db, RTEST(enable) ? 1 : 0));
|
533
|
+
|
534
|
+
return self;
|
535
|
+
}
|
536
|
+
|
657
537
|
int rb_comparator_func(void * ctx, int a_len, const void * a, int b_len, const void * b)
|
658
538
|
{
|
659
539
|
VALUE comparator;
|
660
540
|
VALUE a_str;
|
661
541
|
VALUE b_str;
|
662
542
|
VALUE comparison;
|
663
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
664
543
|
rb_encoding * internal_encoding;
|
665
544
|
|
666
545
|
internal_encoding = rb_default_internal_encoding();
|
667
|
-
#endif
|
668
546
|
|
669
547
|
comparator = (VALUE)ctx;
|
670
548
|
a_str = rb_str_new((const char *)a, a_len);
|
671
549
|
b_str = rb_str_new((const char *)b, b_len);
|
672
550
|
|
673
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
674
551
|
rb_enc_associate_index(a_str, rb_utf8_encindex());
|
675
552
|
rb_enc_associate_index(b_str, rb_utf8_encindex());
|
676
553
|
|
@@ -678,7 +555,6 @@ int rb_comparator_func(void * ctx, int a_len, const void * a, int b_len, const v
|
|
678
555
|
a_str = rb_str_export_to_enc(a_str, internal_encoding);
|
679
556
|
b_str = rb_str_export_to_enc(b_str, internal_encoding);
|
680
557
|
}
|
681
|
-
#endif
|
682
558
|
|
683
559
|
comparison = rb_funcall(comparator, rb_intern("compare"), 2, a_str, b_str);
|
684
560
|
|
@@ -727,7 +603,7 @@ static VALUE load_extension(VALUE self, VALUE file)
|
|
727
603
|
Data_Get_Struct(self, sqlite3Ruby, ctx);
|
728
604
|
REQUIRE_OPEN_DB(ctx);
|
729
605
|
|
730
|
-
status = sqlite3_load_extension(ctx->db,
|
606
|
+
status = sqlite3_load_extension(ctx->db, StringValuePtr(file), 0, &errMsg);
|
731
607
|
if (status != SQLITE_OK)
|
732
608
|
{
|
733
609
|
errexp = rb_exc_new2(rb_eRuntimeError, errMsg);
|
@@ -765,7 +641,6 @@ static VALUE enable_load_extension(VALUE self, VALUE onoff)
|
|
765
641
|
}
|
766
642
|
#endif
|
767
643
|
|
768
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
769
644
|
static int enc_cb(void * _self, int UNUSED(columns), char **data, char **UNUSED(names))
|
770
645
|
{
|
771
646
|
VALUE self = (VALUE)_self;
|
@@ -776,16 +651,6 @@ static int enc_cb(void * _self, int UNUSED(columns), char **data, char **UNUSED(
|
|
776
651
|
|
777
652
|
return 0;
|
778
653
|
}
|
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
654
|
|
790
655
|
/* call-seq: db.encoding
|
791
656
|
*
|
@@ -822,6 +687,78 @@ static VALUE transaction_active_p(VALUE self)
|
|
822
687
|
return sqlite3_get_autocommit(ctx->db) ? Qfalse : Qtrue;
|
823
688
|
}
|
824
689
|
|
690
|
+
static int hash_callback_function(VALUE callback_ary, int count, char **data, char **columns)
|
691
|
+
{
|
692
|
+
VALUE new_hash = rb_hash_new();
|
693
|
+
int i;
|
694
|
+
|
695
|
+
for (i = 0; i < count; i++) {
|
696
|
+
if (data[i] == NULL) {
|
697
|
+
rb_hash_aset(new_hash, rb_str_new_cstr(columns[i]), Qnil);
|
698
|
+
} else {
|
699
|
+
rb_hash_aset(new_hash, rb_str_new_cstr(columns[i]), rb_str_new_cstr(data[i]));
|
700
|
+
}
|
701
|
+
}
|
702
|
+
|
703
|
+
rb_ary_push(callback_ary, new_hash);
|
704
|
+
|
705
|
+
return 0;
|
706
|
+
}
|
707
|
+
|
708
|
+
static int regular_callback_function(VALUE callback_ary, int count, char **data, char **columns)
|
709
|
+
{
|
710
|
+
VALUE new_ary = rb_ary_new();
|
711
|
+
int i;
|
712
|
+
|
713
|
+
for (i = 0; i < count; i++) {
|
714
|
+
if (data[i] == NULL) {
|
715
|
+
rb_ary_push(new_ary, Qnil);
|
716
|
+
} else {
|
717
|
+
rb_ary_push(new_ary, rb_str_new_cstr(data[i]));
|
718
|
+
}
|
719
|
+
}
|
720
|
+
|
721
|
+
rb_ary_push(callback_ary, new_ary);
|
722
|
+
|
723
|
+
return 0;
|
724
|
+
}
|
725
|
+
|
726
|
+
|
727
|
+
/* Is invoked by calling db.execute_batch2(sql, &block)
|
728
|
+
*
|
729
|
+
* Executes all statements in a given string separated by semicolons.
|
730
|
+
* If a query is made, all values returned are strings
|
731
|
+
* (except for 'NULL' values which return nil),
|
732
|
+
* so the user may parse values with a block.
|
733
|
+
* If no query is made, an empty array will be returned.
|
734
|
+
*/
|
735
|
+
static VALUE exec_batch(VALUE self, VALUE sql, VALUE results_as_hash)
|
736
|
+
{
|
737
|
+
sqlite3RubyPtr ctx;
|
738
|
+
int status;
|
739
|
+
VALUE callback_ary = rb_ary_new();
|
740
|
+
char *errMsg;
|
741
|
+
VALUE errexp;
|
742
|
+
|
743
|
+
Data_Get_Struct(self, sqlite3Ruby, ctx);
|
744
|
+
REQUIRE_OPEN_DB(ctx);
|
745
|
+
|
746
|
+
if(results_as_hash == Qtrue) {
|
747
|
+
status = sqlite3_exec(ctx->db, StringValuePtr(sql), (sqlite3_callback)hash_callback_function, (void*)callback_ary, &errMsg);
|
748
|
+
} else {
|
749
|
+
status = sqlite3_exec(ctx->db, StringValuePtr(sql), (sqlite3_callback)regular_callback_function, (void*)callback_ary, &errMsg);
|
750
|
+
}
|
751
|
+
|
752
|
+
if (status != SQLITE_OK)
|
753
|
+
{
|
754
|
+
errexp = rb_exc_new2(rb_eRuntimeError, errMsg);
|
755
|
+
sqlite3_free(errMsg);
|
756
|
+
rb_exc_raise(errexp);
|
757
|
+
}
|
758
|
+
|
759
|
+
return callback_ary;
|
760
|
+
}
|
761
|
+
|
825
762
|
/* call-seq: db.db_filename(database_name)
|
826
763
|
*
|
827
764
|
* Returns the file associated with +database_name+. Can return nil or an
|
@@ -840,16 +777,39 @@ static VALUE db_filename(VALUE self, VALUE db_name)
|
|
840
777
|
return Qnil;
|
841
778
|
}
|
842
779
|
|
780
|
+
static VALUE rb_sqlite3_open16(VALUE self, VALUE file)
|
781
|
+
{
|
782
|
+
int status;
|
783
|
+
sqlite3RubyPtr ctx;
|
784
|
+
|
785
|
+
Data_Get_Struct(self, sqlite3Ruby, ctx);
|
786
|
+
|
787
|
+
#if defined TAINTING_SUPPORT
|
788
|
+
#if defined StringValueCStr
|
789
|
+
StringValuePtr(file);
|
790
|
+
rb_check_safe_obj(file);
|
791
|
+
#else
|
792
|
+
Check_SafeStr(file);
|
793
|
+
#endif
|
794
|
+
#endif
|
795
|
+
|
796
|
+
status = sqlite3_open16(utf16_string_value_ptr(file), &ctx->db);
|
797
|
+
|
798
|
+
CHECK(ctx->db, status)
|
799
|
+
|
800
|
+
return INT2NUM(status);
|
801
|
+
}
|
802
|
+
|
843
803
|
void init_sqlite3_database()
|
844
804
|
{
|
845
|
-
ID id_utf16, id_results_as_hash, id_type_translation;
|
846
805
|
#if 0
|
847
806
|
VALUE mSqlite3 = rb_define_module("SQLite3");
|
848
807
|
#endif
|
849
808
|
cSqlite3Database = rb_define_class_under(mSqlite3, "Database", rb_cObject);
|
850
809
|
|
851
810
|
rb_define_alloc_func(cSqlite3Database, allocate);
|
852
|
-
|
811
|
+
rb_define_private_method(cSqlite3Database, "open_v2", rb_sqlite3_open_v2, 3);
|
812
|
+
rb_define_private_method(cSqlite3Database, "open16", rb_sqlite3_open16, 1);
|
853
813
|
rb_define_method(cSqlite3Database, "collation", collation, 2);
|
854
814
|
rb_define_method(cSqlite3Database, "close", sqlite3_rb_close, 0);
|
855
815
|
rb_define_method(cSqlite3Database, "closed?", closed_p, 0);
|
@@ -857,7 +817,11 @@ void init_sqlite3_database()
|
|
857
817
|
rb_define_method(cSqlite3Database, "trace", trace, -1);
|
858
818
|
rb_define_method(cSqlite3Database, "last_insert_row_id", last_insert_row_id, 0);
|
859
819
|
rb_define_method(cSqlite3Database, "define_function", define_function, 1);
|
860
|
-
rb_define_method(cSqlite3Database, "
|
820
|
+
rb_define_method(cSqlite3Database, "define_function_with_flags", define_function_with_flags, 2);
|
821
|
+
/* public "define_aggregator" is now a shim around define_aggregator2
|
822
|
+
* implemented in Ruby */
|
823
|
+
rb_define_private_method(cSqlite3Database, "define_aggregator2", rb_sqlite3_define_aggregator2, 2);
|
824
|
+
rb_define_private_method(cSqlite3Database, "disable_quirk_mode", rb_sqlite3_disable_quirk_mode, 0);
|
861
825
|
rb_define_method(cSqlite3Database, "interrupt", interrupt, 0);
|
862
826
|
rb_define_method(cSqlite3Database, "errmsg", errmsg, 0);
|
863
827
|
rb_define_method(cSqlite3Database, "errcode", errcode_, 0);
|
@@ -866,7 +830,9 @@ void init_sqlite3_database()
|
|
866
830
|
rb_define_method(cSqlite3Database, "authorizer=", set_authorizer, 1);
|
867
831
|
rb_define_method(cSqlite3Database, "busy_handler", busy_handler, -1);
|
868
832
|
rb_define_method(cSqlite3Database, "busy_timeout=", set_busy_timeout, 1);
|
833
|
+
rb_define_method(cSqlite3Database, "extended_result_codes=", set_extended_result_codes, 1);
|
869
834
|
rb_define_method(cSqlite3Database, "transaction_active?", transaction_active_p, 0);
|
835
|
+
rb_define_private_method(cSqlite3Database, "exec_batch", exec_batch, 2);
|
870
836
|
rb_define_private_method(cSqlite3Database, "db_filename", db_filename, 1);
|
871
837
|
|
872
838
|
#ifdef HAVE_SQLITE3_LOAD_EXTENSION
|
@@ -879,10 +845,9 @@ void init_sqlite3_database()
|
|
879
845
|
|
880
846
|
rb_define_method(cSqlite3Database, "encoding", db_encoding, 0);
|
881
847
|
|
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);
|
848
|
+
rb_sqlite3_aggregator_init();
|
888
849
|
}
|
850
|
+
|
851
|
+
#ifdef _MSC_VER
|
852
|
+
#pragma warning( pop )
|
853
|
+
#endif
|
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
|
}
|