sqlite3 1.3.13 → 1.4.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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