sqlite3 1.3.13 → 1.4.0

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.
@@ -0,0 +1,12 @@
1
+ #ifndef SQLITE3_AGGREGATOR_RUBY
2
+ #define SQLITE3_AGGREGATOR_RUBY
3
+
4
+ #include <sqlite3_ruby.h>
5
+
6
+ VALUE
7
+ rb_sqlite3_define_aggregator2(VALUE self, VALUE aggregator, VALUE ruby_name);
8
+
9
+ void
10
+ rb_sqlite3_aggregator_init(void);
11
+
12
+ #endif
@@ -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,30 @@ 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);
58
43
  #if defined StringValueCStr
59
44
  StringValuePtr(file);
60
45
  rb_check_safe_obj(file);
61
46
  #else
62
47
  Check_SafeStr(file);
63
48
  #endif
64
- if(NIL_P(opts)) opts = rb_hash_new();
65
- else Check_Type(opts, T_HASH);
66
49
 
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
- #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
50
  status = sqlite3_open_v2(
118
51
  StringValuePtr(file),
119
52
  &ctx->db,
120
- mode,
53
+ NUM2INT(mode),
121
54
  NIL_P(zvfs) ? NULL : StringValuePtr(zvfs)
122
55
  );
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
56
 
135
57
  CHECK(ctx->db, status)
136
58
 
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
59
  return self;
156
60
  }
157
61
 
@@ -170,6 +74,8 @@ static VALUE sqlite3_rb_close(VALUE self)
170
74
 
171
75
  ctx->db = NULL;
172
76
 
77
+ rb_iv_set(self, "-aggregators", Qnil);
78
+
173
79
  return self;
174
80
  }
175
81
 
@@ -297,7 +203,7 @@ static VALUE last_insert_row_id(VALUE self)
297
203
  return LL2NUM(sqlite3_last_insert_rowid(ctx->db));
298
204
  }
299
205
 
300
- static VALUE sqlite3val2rb(sqlite3_value * val)
206
+ VALUE sqlite3val2rb(sqlite3_value * val)
301
207
  {
302
208
  switch(sqlite3_value_type(val)) {
303
209
  case SQLITE_INTEGER:
@@ -316,14 +222,7 @@ static VALUE sqlite3val2rb(sqlite3_value * val)
316
222
  which is what we want, as blobs are binary
317
223
  */
318
224
  int len = sqlite3_value_bytes(val);
319
- #ifdef HAVE_RUBY_ENCODING_H
320
225
  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
327
226
  break;
328
227
  }
329
228
  case SQLITE_NULL:
@@ -334,7 +233,7 @@ static VALUE sqlite3val2rb(sqlite3_value * val)
334
233
  }
335
234
  }
336
235
 
337
- static void set_sqlite3_func_result(sqlite3_context * ctx, VALUE result)
236
+ void set_sqlite3_func_result(sqlite3_context * ctx, VALUE result)
338
237
  {
339
238
  switch(TYPE(result)) {
340
239
  case T_NIL:
@@ -358,9 +257,7 @@ static void set_sqlite3_func_result(sqlite3_context * ctx, VALUE result)
358
257
  break;
359
258
  case T_STRING:
360
259
  if(CLASS_OF(result) == cSqlite3Blob
361
- #ifdef HAVE_RUBY_ENCODING_H
362
260
  || rb_enc_get_index(result) == rb_ascii8bit_encindex()
363
- #endif
364
261
  ) {
365
262
  sqlite3_result_blob(
366
263
  ctx,
@@ -409,12 +306,12 @@ int rb_proc_arity(VALUE self)
409
306
  }
410
307
  #endif
411
308
 
412
- /* call-seq: define_function(name) { |args,...| }
309
+ /* call-seq: define_function_with_flags(name, flags) { |args,...| }
413
310
  *
414
- * Define a function named +name+ with +args+. The arity of the block
311
+ * Define a function named +name+ with +args+ using TextRep bitflags +flags+. The arity of the block
415
312
  * will be used as the arity for the function defined.
416
313
  */
417
- static VALUE define_function(VALUE self, VALUE name)
314
+ static VALUE define_function_with_flags(VALUE self, VALUE name, VALUE flags)
418
315
  {
419
316
  sqlite3RubyPtr ctx;
420
317
  VALUE block;
@@ -429,7 +326,7 @@ static VALUE define_function(VALUE self, VALUE name)
429
326
  ctx->db,
430
327
  StringValuePtr(name),
431
328
  rb_proc_arity(block),
432
- SQLITE_UTF8,
329
+ NUM2INT(flags),
433
330
  (void *)block,
434
331
  rb_sqlite3_func,
435
332
  NULL,
@@ -443,70 +340,14 @@ static VALUE define_function(VALUE self, VALUE name)
443
340
  return self;
444
341
  }
445
342
 
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)
343
+ /* call-seq: define_function(name) { |args,...| }
478
344
  *
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.
345
+ * Define a function named +name+ with +args+. The arity of the block
346
+ * will be used as the arity for the function defined.
483
347
  */
484
- static VALUE define_aggregator(VALUE self, VALUE name, VALUE aggregator)
348
+ static VALUE define_function(VALUE self, VALUE name)
485
349
  {
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;
350
+ return define_function_with_flags(self, name, INT2FIX(SQLITE_UTF8));
510
351
  }
511
352
 
512
353
  /* call-seq: interrupt
@@ -654,23 +495,36 @@ static VALUE set_busy_timeout(VALUE self, VALUE timeout)
654
495
  return self;
655
496
  }
656
497
 
498
+ /* call-seq: db.extended_result_codes = true
499
+ *
500
+ * Enable extended result codes in SQLite. These result codes allow for more
501
+ * detailed exception reporting, such a which type of constraint is violated.
502
+ */
503
+ static VALUE set_extended_result_codes(VALUE self, VALUE enable)
504
+ {
505
+ sqlite3RubyPtr ctx;
506
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
507
+ REQUIRE_OPEN_DB(ctx);
508
+
509
+ CHECK(ctx->db, sqlite3_extended_result_codes(ctx->db, RTEST(enable) ? 1 : 0));
510
+
511
+ return self;
512
+ }
513
+
657
514
  int rb_comparator_func(void * ctx, int a_len, const void * a, int b_len, const void * b)
658
515
  {
659
516
  VALUE comparator;
660
517
  VALUE a_str;
661
518
  VALUE b_str;
662
519
  VALUE comparison;
663
- #ifdef HAVE_RUBY_ENCODING_H
664
520
  rb_encoding * internal_encoding;
665
521
 
666
522
  internal_encoding = rb_default_internal_encoding();
667
- #endif
668
523
 
669
524
  comparator = (VALUE)ctx;
670
525
  a_str = rb_str_new((const char *)a, a_len);
671
526
  b_str = rb_str_new((const char *)b, b_len);
672
527
 
673
- #ifdef HAVE_RUBY_ENCODING_H
674
528
  rb_enc_associate_index(a_str, rb_utf8_encindex());
675
529
  rb_enc_associate_index(b_str, rb_utf8_encindex());
676
530
 
@@ -678,7 +532,6 @@ int rb_comparator_func(void * ctx, int a_len, const void * a, int b_len, const v
678
532
  a_str = rb_str_export_to_enc(a_str, internal_encoding);
679
533
  b_str = rb_str_export_to_enc(b_str, internal_encoding);
680
534
  }
681
- #endif
682
535
 
683
536
  comparison = rb_funcall(comparator, rb_intern("compare"), 2, a_str, b_str);
684
537
 
@@ -765,7 +618,6 @@ static VALUE enable_load_extension(VALUE self, VALUE onoff)
765
618
  }
766
619
  #endif
767
620
 
768
- #ifdef HAVE_RUBY_ENCODING_H
769
621
  static int enc_cb(void * _self, int UNUSED(columns), char **data, char **UNUSED(names))
770
622
  {
771
623
  VALUE self = (VALUE)_self;
@@ -776,16 +628,6 @@ static int enc_cb(void * _self, int UNUSED(columns), char **data, char **UNUSED(
776
628
 
777
629
  return 0;
778
630
  }
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
631
 
790
632
  /* call-seq: db.encoding
791
633
  *
@@ -822,6 +664,78 @@ static VALUE transaction_active_p(VALUE self)
822
664
  return sqlite3_get_autocommit(ctx->db) ? Qfalse : Qtrue;
823
665
  }
824
666
 
667
+ static int hash_callback_function(VALUE callback_ary, int count, char **data, char **columns)
668
+ {
669
+ VALUE new_hash = rb_hash_new();
670
+ int i;
671
+
672
+ for (i = 0; i < count; i++) {
673
+ if (data[i] == NULL) {
674
+ rb_hash_aset(new_hash, rb_str_new_cstr(columns[i]), Qnil);
675
+ } else {
676
+ rb_hash_aset(new_hash, rb_str_new_cstr(columns[i]), rb_str_new_cstr(data[i]));
677
+ }
678
+ }
679
+
680
+ rb_ary_push(callback_ary, new_hash);
681
+
682
+ return 0;
683
+ }
684
+
685
+ static int regular_callback_function(VALUE callback_ary, int count, char **data, char **columns)
686
+ {
687
+ VALUE new_ary = rb_ary_new();
688
+ int i;
689
+
690
+ for (i = 0; i < count; i++) {
691
+ if (data[i] == NULL) {
692
+ rb_ary_push(new_ary, Qnil);
693
+ } else {
694
+ rb_ary_push(new_ary, rb_str_new_cstr(data[i]));
695
+ }
696
+ }
697
+
698
+ rb_ary_push(callback_ary, new_ary);
699
+
700
+ return 0;
701
+ }
702
+
703
+
704
+ /* Is invoked by calling db.execute_batch2(sql, &block)
705
+ *
706
+ * Executes all statments in a given string separated by semicolons.
707
+ * If a query is made, all values returned are strings
708
+ * (except for 'NULL' values which return nil),
709
+ * so the user may parse values with a block.
710
+ * If no query is made, an empty array will be returned.
711
+ */
712
+ static VALUE exec_batch(VALUE self, VALUE sql, VALUE results_as_hash)
713
+ {
714
+ sqlite3RubyPtr ctx;
715
+ int status;
716
+ VALUE callback_ary = rb_ary_new();
717
+ char *errMsg;
718
+ VALUE errexp;
719
+
720
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
721
+ REQUIRE_OPEN_DB(ctx);
722
+
723
+ if(results_as_hash == Qtrue) {
724
+ status = sqlite3_exec(ctx->db, StringValuePtr(sql), hash_callback_function, callback_ary, &errMsg);
725
+ } else {
726
+ status = sqlite3_exec(ctx->db, StringValuePtr(sql), regular_callback_function, callback_ary, &errMsg);
727
+ }
728
+
729
+ if (status != SQLITE_OK)
730
+ {
731
+ errexp = rb_exc_new2(rb_eRuntimeError, errMsg);
732
+ sqlite3_free(errMsg);
733
+ rb_exc_raise(errexp);
734
+ }
735
+
736
+ return callback_ary;
737
+ }
738
+
825
739
  /* call-seq: db.db_filename(database_name)
826
740
  *
827
741
  * Returns the file associated with +database_name+. Can return nil or an
@@ -840,16 +754,37 @@ static VALUE db_filename(VALUE self, VALUE db_name)
840
754
  return Qnil;
841
755
  }
842
756
 
757
+ static VALUE rb_sqlite3_open16(VALUE self, VALUE file)
758
+ {
759
+ int status;
760
+ sqlite3RubyPtr ctx;
761
+
762
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
763
+
764
+ #if defined StringValueCStr
765
+ StringValuePtr(file);
766
+ rb_check_safe_obj(file);
767
+ #else
768
+ Check_SafeStr(file);
769
+ #endif
770
+
771
+ status = sqlite3_open16(utf16_string_value_ptr(file), &ctx->db);
772
+
773
+ CHECK(ctx->db, status)
774
+
775
+ return INT2NUM(status);
776
+ }
777
+
843
778
  void init_sqlite3_database()
844
779
  {
845
- ID id_utf16, id_results_as_hash, id_type_translation;
846
780
  #if 0
847
781
  VALUE mSqlite3 = rb_define_module("SQLite3");
848
782
  #endif
849
783
  cSqlite3Database = rb_define_class_under(mSqlite3, "Database", rb_cObject);
850
784
 
851
785
  rb_define_alloc_func(cSqlite3Database, allocate);
852
- rb_define_method(cSqlite3Database, "initialize", initialize, -1);
786
+ rb_define_private_method(cSqlite3Database, "open_v2", rb_sqlite3_open_v2, 3);
787
+ rb_define_private_method(cSqlite3Database, "open16", rb_sqlite3_open16, 1);
853
788
  rb_define_method(cSqlite3Database, "collation", collation, 2);
854
789
  rb_define_method(cSqlite3Database, "close", sqlite3_rb_close, 0);
855
790
  rb_define_method(cSqlite3Database, "closed?", closed_p, 0);
@@ -857,7 +792,10 @@ void init_sqlite3_database()
857
792
  rb_define_method(cSqlite3Database, "trace", trace, -1);
858
793
  rb_define_method(cSqlite3Database, "last_insert_row_id", last_insert_row_id, 0);
859
794
  rb_define_method(cSqlite3Database, "define_function", define_function, 1);
860
- rb_define_method(cSqlite3Database, "define_aggregator", define_aggregator, 2);
795
+ rb_define_method(cSqlite3Database, "define_function_with_flags", define_function_with_flags, 2);
796
+ /* public "define_aggregator" is now a shim around define_aggregator2
797
+ * implemented in Ruby */
798
+ rb_define_private_method(cSqlite3Database, "define_aggregator2", rb_sqlite3_define_aggregator2, 2);
861
799
  rb_define_method(cSqlite3Database, "interrupt", interrupt, 0);
862
800
  rb_define_method(cSqlite3Database, "errmsg", errmsg, 0);
863
801
  rb_define_method(cSqlite3Database, "errcode", errcode_, 0);
@@ -866,7 +804,9 @@ void init_sqlite3_database()
866
804
  rb_define_method(cSqlite3Database, "authorizer=", set_authorizer, 1);
867
805
  rb_define_method(cSqlite3Database, "busy_handler", busy_handler, -1);
868
806
  rb_define_method(cSqlite3Database, "busy_timeout=", set_busy_timeout, 1);
807
+ rb_define_method(cSqlite3Database, "extended_result_codes=", set_extended_result_codes, 1);
869
808
  rb_define_method(cSqlite3Database, "transaction_active?", transaction_active_p, 0);
809
+ rb_define_private_method(cSqlite3Database, "exec_batch", exec_batch, 2);
870
810
  rb_define_private_method(cSqlite3Database, "db_filename", db_filename, 1);
871
811
 
872
812
  #ifdef HAVE_SQLITE3_LOAD_EXTENSION
@@ -879,10 +819,5 @@ void init_sqlite3_database()
879
819
 
880
820
  rb_define_method(cSqlite3Database, "encoding", db_encoding, 0);
881
821
 
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);
822
+ rb_sqlite3_aggregator_init();
888
823
  }