sqlite3 2.0.0-aarch64-linux-musl

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