sqlite3 1.5.0.rc1-arm64-darwin

Sign up to get free protection for your applications and to get access to all the features.
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 +419 -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 +273 -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 +159 -0
  20. data/ext/sqlite3/sqlite3.c +163 -0
  21. data/ext/sqlite3/sqlite3_ruby.h +45 -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 +25 -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 +538 -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 +25 -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", 1L);
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, RSTRING_PTR(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