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.
@@ -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
- /* call-seq: SQLite3::Database.new(file, options = {})
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
- rb_scan_args(argc, argv, "12", &file, &opts, &zvfs);
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
- static VALUE sqlite3val2rb(sqlite3_value * val)
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 rb_tainted_str_new2((const char *)sqlite3_value_text(val));
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 and rb_tainted_str_new apparently create string with ASCII-8BIT (BINARY) encoding,
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
- #ifdef HAVE_RUBY_ENCODING_H
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
- static void set_sqlite3_func_result(sqlite3_context * ctx, VALUE result)
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: define_function(name) { |args,...| }
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 define_function(VALUE self, VALUE name)
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
- SQLITE_UTF8,
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
- static int sqlite3_obj_method_arity(VALUE obj, ID id)
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 an aggregate function named +name+ using the object +aggregator+.
480
- * +aggregator+ must respond to +step+ and +finalize+. +step+ will be called
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 define_aggregator(VALUE self, VALUE name, VALUE aggregator)
350
+ static VALUE define_function(VALUE self, VALUE name)
485
351
  {
486
- sqlite3RubyPtr ctx;
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
- rb_define_method(cSqlite3Database, "initialize", initialize, -1);
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, "define_aggregator", define_aggregator, 2);
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
- id_utf16 = rb_intern("utf16");
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
  }
@@ -11,5 +11,7 @@ typedef struct _sqlite3Ruby sqlite3Ruby;
11
11
  typedef sqlite3Ruby * sqlite3RubyPtr;
12
12
 
13
13
  void init_sqlite3_database();
14
+ void set_sqlite3_func_result(sqlite3_context * ctx, VALUE result);
15
+ VALUE sqlite3val2rb(sqlite3_value * val);
14
16
 
15
17
  #endif
@@ -4,7 +4,9 @@ void rb_sqlite3_raise(sqlite3 * db, int status)
4
4
  {
5
5
  VALUE klass = Qnil;
6
6
 
7
- switch(status) {
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
- rb_raise(klass, "%s", sqlite3_errmsg(db));
95
+ klass = rb_exc_new2(klass, sqlite3_errmsg(db));
96
+ rb_iv_set(klass, "@code", INT2FIX(status));
97
+ rb_exc_raise(klass);
94
98
  }
@@ -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
- brew_prefix = `brew --prefix sqlite3`.chomp
15
- ldflags = "#{brew_prefix}/lib"
16
- cppflags = "#{brew_prefix}/include"
17
- pkg_conf = "#{brew_prefix}/lib/pkgconfig"
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
- pkg_config("sqlite3")
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
- dir_config("sqlite3", cppflags, ldflags)
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
- asplode('sqlite3') unless find_library 'sqlite3', 'sqlite3_libversion_number'
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
- have_func('sqlite3_open_v2')
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')
@@ -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));
@@ -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