sqlite3-full 1.3.9.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +7 -0
  2. data/.gemtest +0 -0
  3. data/API_CHANGES.rdoc +50 -0
  4. data/CHANGELOG.rdoc +278 -0
  5. data/ChangeLog.cvs +88 -0
  6. data/Gemfile +15 -0
  7. data/LICENSE +34 -0
  8. data/Manifest.txt +52 -0
  9. data/README.rdoc +90 -0
  10. data/Rakefile +10 -0
  11. data/ext/sqlite3/backup.c +168 -0
  12. data/ext/sqlite3/backup.h +15 -0
  13. data/ext/sqlite3/database.c +825 -0
  14. data/ext/sqlite3/database.h +15 -0
  15. data/ext/sqlite3/exception.c +94 -0
  16. data/ext/sqlite3/exception.h +8 -0
  17. data/ext/sqlite3/extconf.rb +86 -0
  18. data/ext/sqlite3/sqlite3.c +97 -0
  19. data/ext/sqlite3/sqlite3_ruby.h +52 -0
  20. data/ext/sqlite3/sqlite3amalgamation.c +153367 -0
  21. data/ext/sqlite3/statement.c +447 -0
  22. data/ext/sqlite3/statement.h +16 -0
  23. data/faq/faq.rb +145 -0
  24. data/faq/faq.yml +426 -0
  25. data/lib/sqlite3/constants.rb +49 -0
  26. data/lib/sqlite3/database.rb +590 -0
  27. data/lib/sqlite3/errors.rb +44 -0
  28. data/lib/sqlite3/pragmas.rb +280 -0
  29. data/lib/sqlite3/resultset.rb +195 -0
  30. data/lib/sqlite3/statement.rb +144 -0
  31. data/lib/sqlite3/translator.rb +118 -0
  32. data/lib/sqlite3/value.rb +57 -0
  33. data/lib/sqlite3/version.rb +25 -0
  34. data/lib/sqlite3.rb +10 -0
  35. data/setup.rb +1333 -0
  36. data/tasks/faq.rake +9 -0
  37. data/tasks/gem.rake +38 -0
  38. data/tasks/native.rake +52 -0
  39. data/tasks/vendor_sqlite3.rake +91 -0
  40. data/test/helper.rb +18 -0
  41. data/test/test_backup.rb +33 -0
  42. data/test/test_collation.rb +82 -0
  43. data/test/test_database.rb +367 -0
  44. data/test/test_database_readonly.rb +29 -0
  45. data/test/test_deprecated.rb +44 -0
  46. data/test/test_encoding.rb +153 -0
  47. data/test/test_integration.rb +572 -0
  48. data/test/test_integration_open_close.rb +30 -0
  49. data/test/test_integration_pending.rb +115 -0
  50. data/test/test_integration_resultset.rb +159 -0
  51. data/test/test_integration_statement.rb +194 -0
  52. data/test/test_result_set.rb +37 -0
  53. data/test/test_sqlite3.rb +9 -0
  54. data/test/test_statement.rb +260 -0
  55. data/test/test_statement_execute.rb +35 -0
  56. metadata +205 -0
@@ -0,0 +1,825 @@
1
+ #include <sqlite3_ruby.h>
2
+
3
+ #define REQUIRE_OPEN_DB(_ctxt) \
4
+ if(!_ctxt->db) \
5
+ rb_raise(rb_path2class("SQLite3::Exception"), "cannot use a closed database");
6
+
7
+ VALUE cSqlite3Database;
8
+ static VALUE sym_utf16, sym_results_as_hash, sym_type_translation;
9
+
10
+ static void deallocate(void * ctx)
11
+ {
12
+ sqlite3RubyPtr c = (sqlite3RubyPtr)ctx;
13
+ sqlite3 * db = c->db;
14
+
15
+ if(db) sqlite3_close(db);
16
+ xfree(c);
17
+ }
18
+
19
+ static VALUE allocate(VALUE klass)
20
+ {
21
+ sqlite3RubyPtr ctx = xcalloc((size_t)1, sizeof(sqlite3Ruby));
22
+ return Data_Wrap_Struct(klass, NULL, deallocate, ctx);
23
+ }
24
+
25
+ static char *
26
+ utf16_string_value_ptr(VALUE str)
27
+ {
28
+ StringValue(str);
29
+ rb_str_buf_cat(str, "\x00", 1L);
30
+ return RSTRING_PTR(str);
31
+ }
32
+
33
+ /* call-seq: SQLite3::Database.new(file, options = {})
34
+ *
35
+ * Create a new Database object that opens the given file. If utf16
36
+ * is +true+, the filename is interpreted as a UTF-16 encoded string.
37
+ *
38
+ * By default, the new database will return result rows as arrays
39
+ * (#results_as_hash) and has type translation disabled (#type_translation=).
40
+ */
41
+ static VALUE initialize(int argc, VALUE *argv, VALUE self)
42
+ {
43
+ sqlite3RubyPtr ctx;
44
+ VALUE file;
45
+ VALUE opts;
46
+ VALUE zvfs;
47
+ #ifdef HAVE_SQLITE3_OPEN_V2
48
+ int mode = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
49
+ #endif
50
+ int status;
51
+
52
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
53
+
54
+ rb_scan_args(argc, argv, "12", &file, &opts, &zvfs);
55
+ #if defined StringValueCStr
56
+ StringValuePtr(file);
57
+ rb_check_safe_obj(file);
58
+ #else
59
+ Check_SafeStr(file);
60
+ #endif
61
+ if(NIL_P(opts)) opts = rb_hash_new();
62
+ else Check_Type(opts, T_HASH);
63
+
64
+ #ifdef HAVE_RUBY_ENCODING_H
65
+ if(UTF16_LE_P(file) || UTF16_BE_P(file)) {
66
+ status = sqlite3_open16(utf16_string_value_ptr(file), &ctx->db);
67
+ } else {
68
+ #endif
69
+
70
+ if(Qtrue == rb_hash_aref(opts, sym_utf16)) {
71
+ status = sqlite3_open16(utf16_string_value_ptr(file), &ctx->db);
72
+ } else {
73
+
74
+ #ifdef HAVE_RUBY_ENCODING_H
75
+ if(!UTF8_P(file)) {
76
+ file = rb_str_export_to_enc(file, rb_utf8_encoding());
77
+ }
78
+ #endif
79
+
80
+ if (Qtrue == rb_hash_aref(opts, ID2SYM(rb_intern("readonly")))) {
81
+ #ifdef HAVE_SQLITE3_OPEN_V2
82
+ mode = SQLITE_OPEN_READONLY;
83
+ #else
84
+ rb_raise(rb_eNotImpError, "sqlite3-ruby was compiled against a version of sqlite that does not support readonly databases");
85
+ #endif
86
+ }
87
+ #ifdef HAVE_SQLITE3_OPEN_V2
88
+ status = sqlite3_open_v2(
89
+ StringValuePtr(file),
90
+ &ctx->db,
91
+ mode,
92
+ NIL_P(zvfs) ? NULL : StringValuePtr(zvfs)
93
+ );
94
+ #else
95
+ status = sqlite3_open(
96
+ StringValuePtr(file),
97
+ &ctx->db
98
+ );
99
+ #endif
100
+ }
101
+
102
+ #ifdef HAVE_RUBY_ENCODING_H
103
+ }
104
+ #endif
105
+
106
+ CHECK(ctx->db, status)
107
+
108
+ rb_iv_set(self, "@tracefunc", Qnil);
109
+ rb_iv_set(self, "@authorizer", Qnil);
110
+ rb_iv_set(self, "@encoding", Qnil);
111
+ rb_iv_set(self, "@busy_handler", Qnil);
112
+ rb_iv_set(self, "@collations", rb_hash_new());
113
+ rb_iv_set(self, "@functions", rb_hash_new());
114
+ rb_iv_set(self, "@results_as_hash", rb_hash_aref(opts, sym_results_as_hash));
115
+ rb_iv_set(self, "@type_translation", rb_hash_aref(opts, sym_type_translation));
116
+ #ifdef HAVE_SQLITE3_OPEN_V2
117
+ rb_iv_set(self, "@readonly", mode == SQLITE_OPEN_READONLY ? Qtrue : Qfalse);
118
+ #else
119
+ rb_iv_set(self, "@readonly", Qfalse);
120
+ #endif
121
+
122
+ if(rb_block_given_p()) {
123
+ rb_yield(self);
124
+ rb_funcall(self, rb_intern("close"), 0);
125
+ }
126
+
127
+ return self;
128
+ }
129
+
130
+ /* call-seq: db.close
131
+ *
132
+ * Closes this database.
133
+ */
134
+ static VALUE sqlite3_rb_close(VALUE self)
135
+ {
136
+ sqlite3RubyPtr ctx;
137
+ sqlite3 * db;
138
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
139
+
140
+ db = ctx->db;
141
+ CHECK(db, sqlite3_close(ctx->db));
142
+
143
+ ctx->db = NULL;
144
+
145
+ return self;
146
+ }
147
+
148
+ /* call-seq: db.closed?
149
+ *
150
+ * Returns +true+ if this database instance has been closed (see #close).
151
+ */
152
+ static VALUE closed_p(VALUE self)
153
+ {
154
+ sqlite3RubyPtr ctx;
155
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
156
+
157
+ if(!ctx->db) return Qtrue;
158
+
159
+ return Qfalse;
160
+ }
161
+
162
+ /* call-seq: total_changes
163
+ *
164
+ * Returns the total number of changes made to this database instance
165
+ * since it was opened.
166
+ */
167
+ static VALUE total_changes(VALUE self)
168
+ {
169
+ sqlite3RubyPtr ctx;
170
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
171
+ REQUIRE_OPEN_DB(ctx);
172
+
173
+ return INT2NUM((long)sqlite3_total_changes(ctx->db));
174
+ }
175
+
176
+ static void tracefunc(void * data, const char *sql)
177
+ {
178
+ VALUE self = (VALUE)data;
179
+ VALUE thing = rb_iv_get(self, "@tracefunc");
180
+ rb_funcall(thing, rb_intern("call"), 1, rb_str_new2(sql));
181
+ }
182
+
183
+ /* call-seq:
184
+ * trace { |sql| ... }
185
+ * trace(Class.new { def call sql; end }.new)
186
+ *
187
+ * Installs (or removes) a block that will be invoked for every SQL
188
+ * statement executed. The block receives one parameter: the SQL statement
189
+ * executed. If the block is +nil+, any existing tracer will be uninstalled.
190
+ */
191
+ static VALUE trace(int argc, VALUE *argv, VALUE self)
192
+ {
193
+ sqlite3RubyPtr ctx;
194
+ VALUE block;
195
+
196
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
197
+ REQUIRE_OPEN_DB(ctx);
198
+
199
+ rb_scan_args(argc, argv, "01", &block);
200
+
201
+ if(NIL_P(block) && rb_block_given_p()) block = rb_block_proc();
202
+
203
+ rb_iv_set(self, "@tracefunc", block);
204
+
205
+ sqlite3_trace(ctx->db, NIL_P(block) ? NULL : tracefunc, (void *)self);
206
+
207
+ return self;
208
+ }
209
+
210
+ static int rb_sqlite3_busy_handler(void * ctx, int count)
211
+ {
212
+ VALUE self = (VALUE)(ctx);
213
+ VALUE handle = rb_iv_get(self, "@busy_handler");
214
+ VALUE result = rb_funcall(handle, rb_intern("call"), 1, INT2NUM((long)count));
215
+
216
+ if(Qfalse == result) return 0;
217
+
218
+ return 1;
219
+ }
220
+
221
+ /* call-seq:
222
+ * busy_handler { |count| ... }
223
+ * busy_handler(Class.new { def call count; end }.new)
224
+ *
225
+ * Register a busy handler with this database instance. When a requested
226
+ * resource is busy, this handler will be invoked. If the handler returns
227
+ * +false+, the operation will be aborted; otherwise, the resource will
228
+ * be requested again.
229
+ *
230
+ * The handler will be invoked with the name of the resource that was
231
+ * busy, and the number of times it has been retried.
232
+ *
233
+ * See also the mutually exclusive #busy_timeout.
234
+ */
235
+ static VALUE busy_handler(int argc, VALUE *argv, VALUE self)
236
+ {
237
+ sqlite3RubyPtr ctx;
238
+ VALUE block;
239
+ int status;
240
+
241
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
242
+ REQUIRE_OPEN_DB(ctx);
243
+
244
+ rb_scan_args(argc, argv, "01", &block);
245
+
246
+ if(NIL_P(block) && rb_block_given_p()) block = rb_block_proc();
247
+
248
+ rb_iv_set(self, "@busy_handler", block);
249
+
250
+ status = sqlite3_busy_handler(
251
+ ctx->db, NIL_P(block) ? NULL : rb_sqlite3_busy_handler, (void *)self);
252
+
253
+ CHECK(ctx->db, status);
254
+
255
+ return self;
256
+ }
257
+
258
+ /* call-seq: last_insert_row_id
259
+ *
260
+ * Obtains the unique row ID of the last row to be inserted by this Database
261
+ * instance.
262
+ */
263
+ static VALUE last_insert_row_id(VALUE self)
264
+ {
265
+ sqlite3RubyPtr ctx;
266
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
267
+ REQUIRE_OPEN_DB(ctx);
268
+
269
+ return LL2NUM(sqlite3_last_insert_rowid(ctx->db));
270
+ }
271
+
272
+ static VALUE sqlite3val2rb(sqlite3_value * val)
273
+ {
274
+ switch(sqlite3_value_type(val)) {
275
+ case SQLITE_INTEGER:
276
+ return LL2NUM(sqlite3_value_int64(val));
277
+ break;
278
+ case SQLITE_FLOAT:
279
+ return rb_float_new(sqlite3_value_double(val));
280
+ break;
281
+ case SQLITE_TEXT:
282
+ return rb_tainted_str_new2((const char *)sqlite3_value_text(val));
283
+ break;
284
+ case SQLITE_BLOB: {
285
+ /* Sqlite warns calling sqlite3_value_bytes may invalidate pointer from sqlite3_value_blob,
286
+ so we explicitly get the length before getting blob pointer.
287
+ Note that rb_str_new and rb_tainted_str_new apparently create string with ASCII-8BIT (BINARY) encoding,
288
+ which is what we want, as blobs are binary
289
+ */
290
+ int len = sqlite3_value_bytes(val);
291
+ return rb_tainted_str_new((const char *)sqlite3_value_blob(val), len);
292
+ break;
293
+ }
294
+ case SQLITE_NULL:
295
+ return Qnil;
296
+ break;
297
+ default:
298
+ rb_raise(rb_eRuntimeError, "bad type"); /* FIXME */
299
+ }
300
+ }
301
+
302
+ static void set_sqlite3_func_result(sqlite3_context * ctx, VALUE result)
303
+ {
304
+ switch(TYPE(result)) {
305
+ case T_NIL:
306
+ sqlite3_result_null(ctx);
307
+ break;
308
+ case T_FIXNUM:
309
+ sqlite3_result_int64(ctx, (sqlite3_int64)FIX2LONG(result));
310
+ break;
311
+ case T_BIGNUM: {
312
+ #if SIZEOF_LONG < 8
313
+ sqlite3_int64 num64;
314
+
315
+ if (bignum_to_int64(result, &num64)) {
316
+ sqlite3_result_int64(ctx, num64);
317
+ break;
318
+ }
319
+ #endif
320
+ }
321
+ case T_FLOAT:
322
+ sqlite3_result_double(ctx, NUM2DBL(result));
323
+ break;
324
+ case T_STRING:
325
+ sqlite3_result_text(
326
+ ctx,
327
+ (const char *)StringValuePtr(result),
328
+ (int)RSTRING_LEN(result),
329
+ SQLITE_TRANSIENT
330
+ );
331
+ break;
332
+ default:
333
+ rb_raise(rb_eRuntimeError, "can't return %s",
334
+ rb_class2name(CLASS_OF(result)));
335
+ }
336
+ }
337
+
338
+ static void rb_sqlite3_func(sqlite3_context * ctx, int argc, sqlite3_value **argv)
339
+ {
340
+ VALUE callable = (VALUE)sqlite3_user_data(ctx);
341
+ VALUE * params = NULL;
342
+ VALUE result;
343
+ int i;
344
+
345
+ if (argc > 0) {
346
+ params = xcalloc((size_t)argc, sizeof(VALUE *));
347
+
348
+ for(i = 0; i < argc; i++) {
349
+ VALUE param = sqlite3val2rb(argv[i]);
350
+ RB_GC_GUARD(param);
351
+ params[i] = param;
352
+ }
353
+ }
354
+
355
+ result = rb_funcall2(callable, rb_intern("call"), argc, params);
356
+ xfree(params);
357
+
358
+ set_sqlite3_func_result(ctx, result);
359
+ }
360
+
361
+ #ifndef HAVE_RB_PROC_ARITY
362
+ int rb_proc_arity(VALUE self)
363
+ {
364
+ return (int)NUM2INT(rb_funcall(self, rb_intern("arity"), 0));
365
+ }
366
+ #endif
367
+
368
+ /* call-seq: define_function(name) { |args,...| }
369
+ *
370
+ * Define a function named +name+ with +args+. The arity of the block
371
+ * will be used as the arity for the function defined.
372
+ */
373
+ static VALUE define_function(VALUE self, VALUE name)
374
+ {
375
+ sqlite3RubyPtr ctx;
376
+ VALUE block;
377
+ int status;
378
+
379
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
380
+ REQUIRE_OPEN_DB(ctx);
381
+
382
+ block = rb_block_proc();
383
+
384
+ status = sqlite3_create_function(
385
+ ctx->db,
386
+ StringValuePtr(name),
387
+ rb_proc_arity(block),
388
+ SQLITE_UTF8,
389
+ (void *)block,
390
+ rb_sqlite3_func,
391
+ NULL,
392
+ NULL
393
+ );
394
+
395
+ CHECK(ctx->db, status);
396
+
397
+ rb_hash_aset(rb_iv_get(self, "@functions"), name, block);
398
+
399
+ return self;
400
+ }
401
+
402
+ static int sqlite3_obj_method_arity(VALUE obj, ID id)
403
+ {
404
+ VALUE method = rb_funcall(obj, rb_intern("method"), 1, ID2SYM(id));
405
+ VALUE arity = rb_funcall(method, rb_intern("arity"), 0);
406
+
407
+ return (int)NUM2INT(arity);
408
+ }
409
+
410
+ static void rb_sqlite3_step(sqlite3_context * ctx, int argc, sqlite3_value **argv)
411
+ {
412
+ VALUE callable = (VALUE)sqlite3_user_data(ctx);
413
+ VALUE * params = NULL;
414
+ int i;
415
+
416
+ if (argc > 0) {
417
+ params = xcalloc((size_t)argc, sizeof(VALUE *));
418
+ for(i = 0; i < argc; i++) {
419
+ params[i] = sqlite3val2rb(argv[i]);
420
+ }
421
+ }
422
+ rb_funcall2(callable, rb_intern("step"), argc, params);
423
+ xfree(params);
424
+ }
425
+
426
+ static void rb_sqlite3_final(sqlite3_context * ctx)
427
+ {
428
+ VALUE callable = (VALUE)sqlite3_user_data(ctx);
429
+ VALUE result = rb_funcall(callable, rb_intern("finalize"), 0);
430
+ set_sqlite3_func_result(ctx, result);
431
+ }
432
+
433
+ /* call-seq: define_aggregator(name, aggregator)
434
+ *
435
+ * Define an aggregate function named +name+ using the object +aggregator+.
436
+ * +aggregator+ must respond to +step+ and +finalize+. +step+ will be called
437
+ * with row information and +finalize+ must return the return value for the
438
+ * aggregator function.
439
+ */
440
+ static VALUE define_aggregator(VALUE self, VALUE name, VALUE aggregator)
441
+ {
442
+ sqlite3RubyPtr ctx;
443
+ int arity, status;
444
+
445
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
446
+ REQUIRE_OPEN_DB(ctx);
447
+
448
+ arity = sqlite3_obj_method_arity(aggregator, rb_intern("step"));
449
+
450
+ status = sqlite3_create_function(
451
+ ctx->db,
452
+ StringValuePtr(name),
453
+ arity,
454
+ SQLITE_UTF8,
455
+ (void *)aggregator,
456
+ NULL,
457
+ rb_sqlite3_step,
458
+ rb_sqlite3_final
459
+ );
460
+
461
+ rb_iv_set(self, "@agregator", aggregator);
462
+
463
+ CHECK(ctx->db, status);
464
+
465
+ return self;
466
+ }
467
+
468
+ /* call-seq: interrupt
469
+ *
470
+ * Interrupts the currently executing operation, causing it to abort.
471
+ */
472
+ static VALUE interrupt(VALUE self)
473
+ {
474
+ sqlite3RubyPtr ctx;
475
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
476
+ REQUIRE_OPEN_DB(ctx);
477
+
478
+ sqlite3_interrupt(ctx->db);
479
+
480
+ return self;
481
+ }
482
+
483
+ /* call-seq: errmsg
484
+ *
485
+ * Return a string describing the last error to have occurred with this
486
+ * database.
487
+ */
488
+ static VALUE errmsg(VALUE self)
489
+ {
490
+ sqlite3RubyPtr ctx;
491
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
492
+ REQUIRE_OPEN_DB(ctx);
493
+
494
+ return rb_str_new2(sqlite3_errmsg(ctx->db));
495
+ }
496
+
497
+ /* call-seq: errcode
498
+ *
499
+ * Return an integer representing the last error to have occurred with this
500
+ * database.
501
+ */
502
+ static VALUE errcode_(VALUE self)
503
+ {
504
+ sqlite3RubyPtr ctx;
505
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
506
+ REQUIRE_OPEN_DB(ctx);
507
+
508
+ return INT2NUM((long)sqlite3_errcode(ctx->db));
509
+ }
510
+
511
+ /* call-seq: complete?(sql)
512
+ *
513
+ * Return +true+ if the string is a valid (ie, parsable) SQL statement, and
514
+ * +false+ otherwise.
515
+ */
516
+ static VALUE complete_p(VALUE UNUSED(self), VALUE sql)
517
+ {
518
+ if(sqlite3_complete(StringValuePtr(sql)))
519
+ return Qtrue;
520
+
521
+ return Qfalse;
522
+ }
523
+
524
+ /* call-seq: changes
525
+ *
526
+ * Returns the number of changes made to this database instance by the last
527
+ * operation performed. Note that a "delete from table" without a where
528
+ * clause will not affect this value.
529
+ */
530
+ static VALUE changes(VALUE self)
531
+ {
532
+ sqlite3RubyPtr ctx;
533
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
534
+ REQUIRE_OPEN_DB(ctx);
535
+
536
+ return INT2NUM(sqlite3_changes(ctx->db));
537
+ }
538
+
539
+ static int rb_sqlite3_auth(
540
+ void *ctx,
541
+ int _action,
542
+ const char * _a,
543
+ const char * _b,
544
+ const char * _c,
545
+ const char * _d)
546
+ {
547
+ VALUE self = (VALUE)ctx;
548
+ VALUE action = INT2NUM(_action);
549
+ VALUE a = _a ? rb_str_new2(_a) : Qnil;
550
+ VALUE b = _b ? rb_str_new2(_b) : Qnil;
551
+ VALUE c = _c ? rb_str_new2(_c) : Qnil;
552
+ VALUE d = _d ? rb_str_new2(_d) : Qnil;
553
+ VALUE callback = rb_iv_get(self, "@authorizer");
554
+ VALUE result = rb_funcall(callback, rb_intern("call"), 5, action, a, b, c, d);
555
+
556
+ if(T_FIXNUM == TYPE(result)) return (int)NUM2INT(result);
557
+ if(Qtrue == result) return SQLITE_OK;
558
+ if(Qfalse == result) return SQLITE_DENY;
559
+
560
+ return SQLITE_IGNORE;
561
+ }
562
+
563
+ /* call-seq: set_authorizer = auth
564
+ *
565
+ * Set the authorizer for this database. +auth+ must respond to +call+, and
566
+ * +call+ must take 5 arguments.
567
+ *
568
+ * Installs (or removes) a block that will be invoked for every access
569
+ * to the database. If the block returns 0 (or +true+), the statement
570
+ * is allowed to proceed. Returning 1 or false causes an authorization error to
571
+ * occur, and returning 2 or nil causes the access to be silently denied.
572
+ */
573
+ static VALUE set_authorizer(VALUE self, VALUE authorizer)
574
+ {
575
+ sqlite3RubyPtr ctx;
576
+ int status;
577
+
578
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
579
+ REQUIRE_OPEN_DB(ctx);
580
+
581
+ status = sqlite3_set_authorizer(
582
+ ctx->db, NIL_P(authorizer) ? NULL : rb_sqlite3_auth, (void *)self
583
+ );
584
+
585
+ CHECK(ctx->db, status);
586
+
587
+ rb_iv_set(self, "@authorizer", authorizer);
588
+
589
+ return self;
590
+ }
591
+
592
+ /* call-seq: db.busy_timeout = ms
593
+ *
594
+ * Indicates that if a request for a resource terminates because that
595
+ * resource is busy, SQLite should sleep and retry for up to the indicated
596
+ * number of milliseconds. By default, SQLite does not retry
597
+ * busy resources. To restore the default behavior, send 0 as the
598
+ * +ms+ parameter.
599
+ *
600
+ * See also the mutually exclusive #busy_handler.
601
+ */
602
+ static VALUE set_busy_timeout(VALUE self, VALUE timeout)
603
+ {
604
+ sqlite3RubyPtr ctx;
605
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
606
+ REQUIRE_OPEN_DB(ctx);
607
+
608
+ CHECK(ctx->db, sqlite3_busy_timeout(ctx->db, (int)NUM2INT(timeout)));
609
+
610
+ return self;
611
+ }
612
+
613
+ int rb_comparator_func(void * ctx, int a_len, const void * a, int b_len, const void * b)
614
+ {
615
+ VALUE comparator;
616
+ VALUE a_str;
617
+ VALUE b_str;
618
+ VALUE comparison;
619
+ #ifdef HAVE_RUBY_ENCODING_H
620
+ rb_encoding * internal_encoding;
621
+
622
+ internal_encoding = rb_default_internal_encoding();
623
+ #endif
624
+
625
+ comparator = (VALUE)ctx;
626
+ a_str = rb_str_new((const char *)a, a_len);
627
+ b_str = rb_str_new((const char *)b, b_len);
628
+
629
+ #ifdef HAVE_RUBY_ENCODING_H
630
+ rb_enc_associate_index(a_str, rb_utf8_encindex());
631
+ rb_enc_associate_index(b_str, rb_utf8_encindex());
632
+
633
+ if(internal_encoding) {
634
+ a_str = rb_str_export_to_enc(a_str, internal_encoding);
635
+ b_str = rb_str_export_to_enc(b_str, internal_encoding);
636
+ }
637
+ #endif
638
+
639
+ comparison = rb_funcall(comparator, rb_intern("compare"), 2, a_str, b_str);
640
+
641
+ return NUM2INT(comparison);
642
+ }
643
+
644
+ /* call-seq: db.collation(name, comparator)
645
+ *
646
+ * Add a collation with name +name+, and a +comparator+ object. The
647
+ * +comparator+ object should implement a method called "compare" that takes
648
+ * two parameters and returns an integer less than, equal to, or greater than
649
+ * 0.
650
+ */
651
+ static VALUE collation(VALUE self, VALUE name, VALUE comparator)
652
+ {
653
+ sqlite3RubyPtr ctx;
654
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
655
+ REQUIRE_OPEN_DB(ctx);
656
+
657
+ CHECK(ctx->db, sqlite3_create_collation(
658
+ ctx->db,
659
+ StringValuePtr(name),
660
+ SQLITE_UTF8,
661
+ (void *)comparator,
662
+ NIL_P(comparator) ? NULL : rb_comparator_func));
663
+
664
+ /* Make sure our comparator doesn't get garbage collected. */
665
+ rb_hash_aset(rb_iv_get(self, "@collations"), name, comparator);
666
+
667
+ return self;
668
+ }
669
+
670
+ #ifdef HAVE_SQLITE3_LOAD_EXTENSION
671
+ /* call-seq: db.load_extension(file)
672
+ *
673
+ * Loads an SQLite extension library from the named file. Extension
674
+ * loading must be enabled using db.enable_load_extension(true) prior
675
+ * to calling this API.
676
+ */
677
+ static VALUE load_extension(VALUE self, VALUE file)
678
+ {
679
+ sqlite3RubyPtr ctx;
680
+ int status;
681
+ char *errMsg;
682
+ VALUE errexp;
683
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
684
+ REQUIRE_OPEN_DB(ctx);
685
+
686
+ status = sqlite3_load_extension(ctx->db, RSTRING_PTR(file), 0, &errMsg);
687
+ if (status != SQLITE_OK)
688
+ {
689
+ errexp = rb_exc_new2(rb_eRuntimeError, errMsg);
690
+ sqlite3_free(errMsg);
691
+ rb_exc_raise(errexp);
692
+ }
693
+
694
+ return self;
695
+ }
696
+ #endif
697
+
698
+ #ifdef HAVE_SQLITE3_ENABLE_LOAD_EXTENSION
699
+ /* call-seq: db.enable_load_extension(onoff)
700
+ *
701
+ * Enable or disable extension loading.
702
+ */
703
+ static VALUE enable_load_extension(VALUE self, VALUE onoff)
704
+ {
705
+ sqlite3RubyPtr ctx;
706
+ int onoffparam;
707
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
708
+ REQUIRE_OPEN_DB(ctx);
709
+
710
+ if (Qtrue == onoff) {
711
+ onoffparam = 1;
712
+ } else if (Qfalse == onoff) {
713
+ onoffparam = 0;
714
+ } else {
715
+ onoffparam = (int)NUM2INT(onoff);
716
+ }
717
+
718
+ CHECK(ctx->db, sqlite3_enable_load_extension(ctx->db, onoffparam));
719
+
720
+ return self;
721
+ }
722
+ #endif
723
+
724
+ #ifdef HAVE_RUBY_ENCODING_H
725
+ static int enc_cb(void * _self, int UNUSED(columns), char **data, char **UNUSED(names))
726
+ {
727
+ VALUE self = (VALUE)_self;
728
+
729
+ int index = rb_enc_find_index(data[0]);
730
+ rb_encoding * e = rb_enc_from_index(index);
731
+ rb_iv_set(self, "@encoding", rb_enc_from_encoding(e));
732
+
733
+ return 0;
734
+ }
735
+ #else
736
+ static int enc_cb(void * _self, int UNUSED(columns), char **data, char **UNUSED(names))
737
+ {
738
+ VALUE self = (VALUE)_self;
739
+
740
+ rb_iv_set(self, "@encoding", rb_str_new2(data[0]));
741
+
742
+ return 0;
743
+ }
744
+ #endif
745
+
746
+ /* call-seq: db.encoding
747
+ *
748
+ * Fetch the encoding set on this database
749
+ */
750
+ static VALUE db_encoding(VALUE self)
751
+ {
752
+ sqlite3RubyPtr ctx;
753
+ VALUE enc;
754
+
755
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
756
+ REQUIRE_OPEN_DB(ctx);
757
+
758
+ enc = rb_iv_get(self, "@encoding");
759
+
760
+ if(NIL_P(enc)) {
761
+ sqlite3_exec(ctx->db, "PRAGMA encoding", enc_cb, (void *)self, NULL);
762
+ }
763
+
764
+ return rb_iv_get(self, "@encoding");
765
+ }
766
+
767
+ /* call-seq: db.transaction_active?
768
+ *
769
+ * Returns +true+ if there is a transaction active, and +false+ otherwise.
770
+ *
771
+ */
772
+ static VALUE transaction_active_p(VALUE self)
773
+ {
774
+ sqlite3RubyPtr ctx;
775
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
776
+ REQUIRE_OPEN_DB(ctx);
777
+
778
+ return sqlite3_get_autocommit(ctx->db) ? Qfalse : Qtrue;
779
+ }
780
+
781
+ void init_sqlite3_database()
782
+ {
783
+ ID id_utf16, id_results_as_hash, id_type_translation;
784
+ #if 0
785
+ VALUE mSqlite3 = rb_define_module("SQLite3");
786
+ #endif
787
+ cSqlite3Database = rb_define_class_under(mSqlite3, "Database", rb_cObject);
788
+
789
+ rb_define_alloc_func(cSqlite3Database, allocate);
790
+ rb_define_method(cSqlite3Database, "initialize", initialize, -1);
791
+ rb_define_method(cSqlite3Database, "collation", collation, 2);
792
+ rb_define_method(cSqlite3Database, "close", sqlite3_rb_close, 0);
793
+ rb_define_method(cSqlite3Database, "closed?", closed_p, 0);
794
+ rb_define_method(cSqlite3Database, "total_changes", total_changes, 0);
795
+ rb_define_method(cSqlite3Database, "trace", trace, -1);
796
+ rb_define_method(cSqlite3Database, "last_insert_row_id", last_insert_row_id, 0);
797
+ rb_define_method(cSqlite3Database, "define_function", define_function, 1);
798
+ rb_define_method(cSqlite3Database, "define_aggregator", define_aggregator, 2);
799
+ rb_define_method(cSqlite3Database, "interrupt", interrupt, 0);
800
+ rb_define_method(cSqlite3Database, "errmsg", errmsg, 0);
801
+ rb_define_method(cSqlite3Database, "errcode", errcode_, 0);
802
+ rb_define_method(cSqlite3Database, "complete?", complete_p, 1);
803
+ rb_define_method(cSqlite3Database, "changes", changes, 0);
804
+ rb_define_method(cSqlite3Database, "authorizer=", set_authorizer, 1);
805
+ rb_define_method(cSqlite3Database, "busy_handler", busy_handler, -1);
806
+ rb_define_method(cSqlite3Database, "busy_timeout=", set_busy_timeout, 1);
807
+ rb_define_method(cSqlite3Database, "transaction_active?", transaction_active_p, 0);
808
+
809
+ #ifdef HAVE_SQLITE3_LOAD_EXTENSION
810
+ rb_define_method(cSqlite3Database, "load_extension", load_extension, 1);
811
+ #endif
812
+
813
+ #ifdef HAVE_SQLITE3_ENABLE_LOAD_EXTENSION
814
+ rb_define_method(cSqlite3Database, "enable_load_extension", enable_load_extension, 1);
815
+ #endif
816
+
817
+ rb_define_method(cSqlite3Database, "encoding", db_encoding, 0);
818
+
819
+ id_utf16 = rb_intern("utf16");
820
+ sym_utf16 = ID2SYM(id_utf16);
821
+ id_results_as_hash = rb_intern("results_as_hash");
822
+ sym_results_as_hash = ID2SYM(id_results_as_hash);
823
+ id_type_translation = rb_intern("type_translation");
824
+ sym_type_translation = ID2SYM(id_type_translation);
825
+ }