sqlite3 1.3.13 → 1.4.0

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