sqlite3 1.5.0-arm64-darwin

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of sqlite3 might be problematic. Click here for more details.

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