sqlite3 2.0.0-aarch64-linux-musl

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