sqlite3 2.9.5-x86-linux-musl → 2.9.6-x86-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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 60c73758921b3789af9e4472d571c1503d462134ddef04e4bf19c7b738b58533
4
- data.tar.gz: 066eb4e15badd291f1987f7bb2aa2734afe6774aa5b68ab479d7d3e60a7fab80
3
+ metadata.gz: 9bcf80141ecc52e119a73a8347cc530cc4380e4f1f8a6539193bbaf4323242fb
4
+ data.tar.gz: cc00013fdbe1e8ed8ef0d51ab1ab3e5daa43d6d4e9fa416b5f810dacb3719699
5
5
  SHA512:
6
- metadata.gz: e84ab86acfcb4e99d500f1c5087525fe7ea9ca7276669ec27c8e6a38f544d9868c89320293ca855e8b205d15d316d467ed4da858b152e22afec161af53e7c03a
7
- data.tar.gz: 469b4a8469ecef8cdc5fc6765a41908994f917f6f11f855d075657a262d9e01045d1fd3fc91f913f4148fdd1a79d82437308d3d3dd1e56d3e39a8df54047aa2d
6
+ metadata.gz: 1399b84338d67bc92adaeff075dd4cae8e62d961980f6b026476ff89ab8f000e086914db96ca1fee7b76d214a8ed2cf809ef5dd3fb7c3c6077737654fa989f6d
7
+ data.tar.gz: 74ae4d6d1e66c8ca85775532e50fff31589a22379d3abb6e63ae4fce6acd34206a01e12a925b6cf649da7717b514a2207032a0976dd473164ba482d96b30f785
data/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # sqlite3-ruby Changelog
2
2
 
3
+ ## 2.9.6 / 2026-08-11
4
+
5
+ ### Security / Stability
6
+
7
+ - Fix a garbage collection bug where the argument array passed to a custom aggregate function's `step` was not visible to the GC, so arguments could be collected mid-conversion when the aggregate takes two or more arguments, corrupting the values passed to `step` or crashing the process. See [GHSA-mwm8-39rw-8826](https://github.com/sparklemotion/sqlite3-ruby/security/advisories/GHSA-mwm8-39rw-8826) for more information. #733 @jeremy
8
+
9
+ ### Fixed
10
+
11
+ - Fix a leak where custom aggregate handler instances were never released, so a connection accumulated one instance per `GROUP BY` group per query for its lifetime. #722 @djmb
12
+ - Fix GC compaction issues with custom functions, aggregates, collations, `#trace` and `#authorizer=`. These callbacks were registered with sqlite by passing a raw Ruby object pointer as user data; keeping the object reachable prevented collection but not relocation, after which sqlite held a stale address and the next call could raise `NoMethodError`, return a wrong result, or segfault. Affects applications that call `GC.compact` or run with `GC.auto_compact = true`. The equivalent issue in `#busy_handler` was fixed in #466. #723 @djmb
13
+ - Fix the private methods `Database#open_v2` and `#open16` silently replacing a live connection and leaking the previous connection handle when invoked via `send` on an open database. They now raise `SQLite3::Exception`. #729 @flavorjones
14
+ - Fix TEXT values containing an embedded NUL byte being truncated at the first NUL when passed as arguments to functions created with `Database#define_function`. #730 @flavorjones
15
+ - Fix an exception raised inside a `Database#define_function` block leaving the connection's sqlite mutex held, which deadlocked any other thread that later used the connection. The exception now propagates to the caller and the connection remains usable. #731 @flavorjones
16
+ - `Database.new` now raises `ArgumentError` when the filename or VFS name contains an embedded NUL byte (or an embedded 0x0000 code unit in a UTF-16 filename), instead of silently opening a path truncated at the NUL. #732 @flavorjones
17
+
18
+
19
+ ### Improved
20
+
21
+ - When `Database.new` fails to open the database file, the underlying sqlite3 connection handle is now closed immediately instead of waiting for the garbage collector to clean it up. #719 @katafrakt
22
+
23
+
3
24
  ## 2.9.5 / 2026-06-07
4
25
 
5
26
  ### Dependencies
data/CONTRIBUTING.md CHANGED
@@ -27,6 +27,71 @@ explicitly closed, it will be closed when it is GCed.
27
27
  will be closed/finalized when it is GCed.
28
28
 
29
29
 
30
+ ## Debugging memory issues
31
+
32
+ Please install `valgrind` and `gdb` before you use the tools in this section.
33
+
34
+ Run the test suite under valgrind and [`ruby_memcheck`](https://github.com/Shopify/ruby_memcheck) to
35
+ look for memory leaks and other memory errors:
36
+
37
+ ``` sh
38
+ bundle exec rake compile test:valgrind
39
+ ```
40
+
41
+ If you can't install valgrind on your system, use the `sqlite3-dev` docker image, which contains
42
+ valgrind:
43
+
44
+ ``` sh
45
+ # build the image
46
+ bundle exec rake docker:dev:build
47
+
48
+ # run the test suite in a container
49
+ bundle exec rake docker:dev:test
50
+
51
+ # run the test suite under valgrind in a container
52
+ bundle exec rake docker:dev:test:valgrind
53
+ ```
54
+
55
+ Each `docker:dev:test` task builds the image first, then mounts your working copy at `/sqlite3` in
56
+ the container. Note that the container compiles into the mounted working copy, so please re-run
57
+ `rake compile` on your machine afterwards.
58
+
59
+ Run the test suite in the debugger:
60
+
61
+ ``` sh
62
+ bundle exec rake compile test:gdb
63
+ ```
64
+
65
+ You can also run the test suite with a variety of GC behaviors, which is useful to localize some
66
+ classes of memory bugs. Set the `SQLITE3_TEST_GC_LEVEL` environment variable (see `test/helper.rb`
67
+ for more info). A more stressful level finds more bugs, but makes the suite slower:
68
+
69
+ ``` sh
70
+ # ordinary GC behavior (the default)
71
+ SQLITE3_TEST_GC_LEVEL=normal bundle exec rake compile test
72
+
73
+ # minor GC after each test
74
+ SQLITE3_TEST_GC_LEVEL=minor bundle exec rake compile test
75
+
76
+ # major GC after each test
77
+ SQLITE3_TEST_GC_LEVEL=major bundle exec rake compile test
78
+
79
+ # major GC after each test, and GC compaction after every 20 tests
80
+ SQLITE3_TEST_GC_LEVEL=compact bundle exec rake compile test
81
+
82
+ # verify references after compaction, after every 20 tests
83
+ # (see https://alanwu.space/post/check-compaction/)
84
+ SQLITE3_TEST_GC_LEVEL=verify bundle exec rake compile test
85
+
86
+ # run each test with GC "stress mode" on
87
+ SQLITE3_TEST_GC_LEVEL=stress bundle exec rake compile test
88
+ ```
89
+
90
+ The `compact` and `verify` levels fall back to `normal` on a platform that does not support GC
91
+ compaction. The `stress` level makes the suite about 150 times slower, and it makes
92
+ timing-sensitive tests unreliable.
93
+
94
+
30
95
  ## Building gems
31
96
 
32
97
  As a prerequisite please make sure you have `docker` correctly installed, so that you're able to cross-compile the native gems.
@@ -97,7 +97,7 @@ rb_sqlite3_aggregate_instance_destroy(sqlite3_context *ctx)
97
97
  VALUE *inst_ptr = sqlite3_aggregate_context(ctx, 0);
98
98
  VALUE inst;
99
99
 
100
- if (!inst_ptr || (inst = *inst_ptr)) {
100
+ if (!inst_ptr || !(inst = *inst_ptr)) {
101
101
  return;
102
102
  }
103
103
 
@@ -119,6 +119,7 @@ rb_sqlite3_aggregator_step(sqlite3_context *ctx, int argc, sqlite3_value **argv)
119
119
  VALUE inst = rb_sqlite3_aggregate_instance(ctx);
120
120
  VALUE handler_instance = rb_iv_get(inst, "-handler_instance");
121
121
  VALUE *params = NULL;
122
+ VALUE params_handle = 0;
122
123
  VALUE one_param;
123
124
  int exc_status = NUM2INT(rb_iv_get(inst, "-exc_status"));
124
125
  int i;
@@ -132,7 +133,9 @@ rb_sqlite3_aggregator_step(sqlite3_context *ctx, int argc, sqlite3_value **argv)
132
133
  params = &one_param;
133
134
  }
134
135
  if (argc > 1) {
135
- params = xcalloc((size_t)argc, sizeof(VALUE));
136
+ /* ALLOCV memory is conservatively marked, so stored VALUEs survive a
137
+ * GC raised by a later sqlite3val2rb call. */
138
+ params = ALLOCV_N(VALUE, params_handle, argc);
136
139
  for (i = 0; i < argc; i++) {
137
140
  params[i] = sqlite3val2rb(argv[i]);
138
141
  }
@@ -140,7 +143,7 @@ rb_sqlite3_aggregator_step(sqlite3_context *ctx, int argc, sqlite3_value **argv)
140
143
  rb_sqlite3_protected_funcall(
141
144
  handler_instance, rb_intern("step"), argc, params, &exc_status);
142
145
  if (argc > 1) {
143
- xfree(params);
146
+ ALLOCV_END(params_handle);
144
147
  }
145
148
 
146
149
  rb_iv_set(inst, "-exc_status", INT2NUM(exc_status));
@@ -254,10 +257,17 @@ rb_sqlite3_define_aggregator2(VALUE self, VALUE aggregator, VALUE ruby_name)
254
257
  CHECK(ctx->db, status);
255
258
 
256
259
  rb_ary_push(aggregators, aw);
260
+ RB_OBJ_WRITE(self, &ctx->aggregators, aggregators);
257
261
 
258
262
  return self;
259
263
  }
260
264
 
265
+ void
266
+ rb_sqlite3_aggregator_pin_instances(VALUE aw)
267
+ {
268
+ rb_sqlite3_pin_array_and_contents(rb_iv_get(aw, "-instances"));
269
+ }
270
+
261
271
  void
262
272
  rb_sqlite3_aggregator_init(void)
263
273
  {
@@ -7,4 +7,8 @@ VALUE rb_sqlite3_define_aggregator2(VALUE self, VALUE aggregator, VALUE ruby_nam
7
7
 
8
8
  void rb_sqlite3_aggregator_init(void);
9
9
 
10
+ /* sqlite stores each live instance's VALUE in its aggregate context, so those
11
+ * must not move either. */
12
+ void rb_sqlite3_aggregator_pin_instances(VALUE aw);
13
+
10
14
  #endif
@@ -10,6 +10,10 @@
10
10
  if(!_ctxt->db) \
11
11
  rb_raise(rb_path2class("SQLite3::Exception"), "cannot use a closed database");
12
12
 
13
+ #define REQUIRE_CLOSED_DB(_ctxt) \
14
+ if(_ctxt->db) \
15
+ rb_raise(rb_path2class("SQLite3::Exception"), "cannot open a database that is already open");
16
+
13
17
  VALUE cSqlite3Database;
14
18
 
15
19
  /* See adr/2024-09-fork-safety.md */
@@ -70,11 +74,64 @@ close_or_discard_db(sqlite3RubyPtr ctx)
70
74
  }
71
75
 
72
76
 
77
+ void
78
+ rb_sqlite3_pin_array_and_contents(VALUE ary)
79
+ {
80
+ long i;
81
+
82
+ if (NIL_P(ary) || !ary) { return; }
83
+
84
+ rb_gc_mark(ary);
85
+ for (i = 0; i < RARRAY_LEN(ary); i++) {
86
+ rb_gc_mark(RARRAY_AREF(ary, i));
87
+ }
88
+ }
89
+
90
+ static int
91
+ pin_hash_value(VALUE UNUSED(key), VALUE value, VALUE UNUSED(arg))
92
+ {
93
+ rb_gc_mark(value);
94
+ return ST_CONTINUE;
95
+ }
96
+
97
+ static void
98
+ pin_hash_and_contents(VALUE hash)
99
+ {
100
+ if (NIL_P(hash) || !hash) { return; }
101
+
102
+ rb_gc_mark(hash);
103
+ rb_hash_foreach(hash, pin_hash_value, 0);
104
+ }
105
+
106
+ /* Each wrapper also owns live aggregate instances, whose VALUEs sqlite keeps in
107
+ * its own aggregate contexts. */
108
+ static void
109
+ pin_aggregators(VALUE aggregators)
110
+ {
111
+ long i;
112
+
113
+ rb_sqlite3_pin_array_and_contents(aggregators);
114
+
115
+ if (NIL_P(aggregators) || !aggregators) { return; }
116
+
117
+ for (i = 0; i < RARRAY_LEN(aggregators); i++) {
118
+ rb_sqlite3_aggregator_pin_instances(RARRAY_AREF(aggregators, i));
119
+ }
120
+ }
121
+
73
122
  static void
74
123
  database_mark(void *ctx)
75
124
  {
76
125
  sqlite3RubyPtr c = (sqlite3RubyPtr)ctx;
126
+
127
+ /* sqlite holds raw pointers to these, so they must not move. */
77
128
  rb_gc_mark(c->busy_handler);
129
+ rb_gc_mark(c->trace_handler);
130
+ rb_gc_mark(c->authorizer);
131
+
132
+ rb_sqlite3_pin_array_and_contents(c->functions);
133
+ pin_hash_and_contents(c->collations);
134
+ pin_aggregators(c->aggregators);
78
135
  }
79
136
 
80
137
  static void
@@ -114,7 +171,21 @@ allocate(VALUE klass)
114
171
  static char *
115
172
  utf16_string_value_ptr(VALUE str)
116
173
  {
174
+ VALUE utf16str, codepoints;
175
+
117
176
  StringValue(str);
177
+
178
+ utf16str = rb_str_dup(str);
179
+ if (!UTF16_LE_P(utf16str) && !UTF16_BE_P(utf16str)) {
180
+ /* an untagged string (the utf16 option) holds native-byte-order UTF-16 */
181
+ const union { uint16_t u16; uint8_t u8[2]; } native = { 1 };
182
+ rb_enc_associate_index(utf16str, rb_enc_find_index(native.u8[0] ? "UTF-16LE" : "UTF-16BE"));
183
+ }
184
+ codepoints = rb_funcall(utf16str, rb_intern("codepoints"), 0);
185
+ if (RTEST(rb_funcall(codepoints, rb_intern("include?"), 1, INT2FIX(0)))) {
186
+ rb_raise(rb_eArgError, "string contains null char");
187
+ }
188
+
118
189
  rb_str_buf_cat(str, "\x00\x00", 2L);
119
190
  return RSTRING_PTR(str);
120
191
  }
@@ -135,6 +206,7 @@ rb_sqlite3_open_v2(VALUE self, VALUE file, VALUE mode, VALUE zvfs)
135
206
  int flags;
136
207
 
137
208
  TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
209
+ REQUIRE_CLOSED_DB(ctx);
138
210
 
139
211
  #if defined TAINTING_SUPPORT
140
212
  # if defined StringValueCStr
@@ -147,13 +219,19 @@ rb_sqlite3_open_v2(VALUE self, VALUE file, VALUE mode, VALUE zvfs)
147
219
 
148
220
  flags = NUM2INT(mode);
149
221
  status = sqlite3_open_v2(
150
- StringValuePtr(file),
222
+ StringValueCStr(file),
151
223
  &ctx->db,
152
224
  flags,
153
- NIL_P(zvfs) ? NULL : StringValuePtr(zvfs)
225
+ NIL_P(zvfs) ? NULL : StringValueCStr(zvfs)
154
226
  );
155
227
 
156
- CHECK(ctx->db, status);
228
+ if (status != SQLITE_OK) {
229
+ char *msg = sqlite3_mprintf("%s", sqlite3_errmsg(ctx->db));
230
+ sqlite3_close_v2(ctx->db);
231
+ ctx->db = NULL;
232
+ CHECK_MSG(ctx->db, status, msg);
233
+ }
234
+
157
235
  if (flags & SQLITE_OPEN_READONLY) {
158
236
  ctx->flags |= SQLITE3_RB_DATABASE_READONLY;
159
237
  }
@@ -246,9 +324,8 @@ total_changes(VALUE self)
246
324
  static void
247
325
  tracefunc(void *data, const char *sql)
248
326
  {
249
- VALUE self = (VALUE)data;
250
- VALUE thing = rb_iv_get(self, "@tracefunc");
251
- rb_funcall(thing, rb_intern("call"), 1, rb_str_new2(sql));
327
+ sqlite3RubyPtr ctx = (sqlite3RubyPtr)data;
328
+ rb_funcall(ctx->trace_handler, rb_intern("call"), 1, rb_str_new2(sql));
252
329
  }
253
330
 
254
331
  /* call-seq:
@@ -272,9 +349,9 @@ trace(int argc, VALUE *argv, VALUE self)
272
349
 
273
350
  if (NIL_P(block) && rb_block_given_p()) { block = rb_block_proc(); }
274
351
 
275
- rb_iv_set(self, "@tracefunc", block);
352
+ RB_OBJ_WRITE(self, &ctx->trace_handler, block);
276
353
 
277
- sqlite3_trace(ctx->db, NIL_P(block) ? NULL : tracefunc, (void *)self);
354
+ sqlite3_trace(ctx->db, NIL_P(block) ? NULL : tracefunc, (void *)ctx);
278
355
 
279
356
  return self;
280
357
  }
@@ -398,7 +475,9 @@ sqlite3val2rb(sqlite3_value *val)
398
475
  rb_val = rb_float_new(sqlite3_value_double(val));
399
476
  break;
400
477
  case SQLITE_TEXT: {
401
- rb_val = rb_utf8_str_new_cstr((const char *)sqlite3_value_text(val));
478
+ const char *text = (const char *)sqlite3_value_text(val);
479
+ int len = sqlite3_value_bytes(val);
480
+ rb_val = rb_utf8_str_new(text, len);
402
481
  rb_obj_freeze(rb_val);
403
482
  break;
404
483
  }
@@ -466,24 +545,46 @@ set_sqlite3_func_result(sqlite3_context *ctx, VALUE result)
466
545
  }
467
546
  }
468
547
 
469
- static void
470
- rb_sqlite3_func(sqlite3_context *ctx, int argc, sqlite3_value **argv)
548
+ typedef struct {
549
+ sqlite3_context *ctx;
550
+ int argc;
551
+ sqlite3_value **argv;
552
+ } rb_sqlite3_func_args_t;
553
+
554
+ static VALUE
555
+ rb_sqlite3_func_protected(VALUE func_args_value)
471
556
  {
472
- VALUE callable = (VALUE)sqlite3_user_data(ctx);
473
- VALUE params = rb_ary_new2(argc);
557
+ rb_sqlite3_func_args_t *args = (rb_sqlite3_func_args_t *)func_args_value;
558
+ VALUE callable = (VALUE)sqlite3_user_data(args->ctx);
559
+ VALUE params = rb_ary_new2(args->argc);
474
560
  VALUE result;
475
561
  int i;
476
562
 
477
- if (argc > 0) {
478
- for (i = 0; i < argc; i++) {
479
- VALUE param = sqlite3val2rb(argv[i]);
480
- rb_ary_push(params, param);
481
- }
563
+ for (i = 0; i < args->argc; i++) {
564
+ VALUE param = sqlite3val2rb(args->argv[i]);
565
+ rb_ary_push(params, param);
482
566
  }
483
567
 
484
568
  result = rb_apply(callable, rb_intern("call"), params);
485
569
 
486
- set_sqlite3_func_result(ctx, result);
570
+ set_sqlite3_func_result(args->ctx, result);
571
+
572
+ return Qnil;
573
+ }
574
+
575
+ static void
576
+ rb_sqlite3_func(sqlite3_context *ctx, int argc, sqlite3_value **argv)
577
+ {
578
+ rb_sqlite3_func_args_t args = { .ctx = ctx, .argc = argc, .argv = argv };
579
+ int exc_status;
580
+
581
+ rb_protect(rb_sqlite3_func_protected, (VALUE)&args, &exc_status);
582
+
583
+ if (exc_status) {
584
+ /* the user should never see this message, because Statement#step will
585
+ * re-raise the exception still in rb_errinfo */
586
+ sqlite3_result_error(ctx, "Ruby Exception occurred", -1);
587
+ }
487
588
  }
488
589
 
489
590
  #ifndef HAVE_RB_PROC_ARITY
@@ -503,7 +604,7 @@ static VALUE
503
604
  define_function_with_flags(VALUE self, VALUE name, VALUE flags)
504
605
  {
505
606
  sqlite3RubyPtr ctx;
506
- VALUE block;
607
+ VALUE block, functions;
507
608
  int status;
508
609
 
509
610
  TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
@@ -524,7 +625,9 @@ define_function_with_flags(VALUE self, VALUE name, VALUE flags)
524
625
 
525
626
  CHECK(ctx->db, status);
526
627
 
527
- rb_ary_push(rb_iv_get(self, "@functions"), block);
628
+ functions = rb_iv_get(self, "@functions");
629
+ rb_ary_push(functions, block);
630
+ RB_OBJ_WRITE(self, &ctx->functions, functions);
528
631
 
529
632
  return self;
530
633
  }
@@ -626,14 +729,13 @@ rb_sqlite3_auth(
626
729
  const char *_c,
627
730
  const char *_d)
628
731
  {
629
- VALUE self = (VALUE)ctx;
732
+ sqlite3RubyPtr db_ctx = (sqlite3RubyPtr)ctx;
630
733
  VALUE action = INT2NUM(_action);
631
734
  VALUE a = _a ? rb_str_new2(_a) : Qnil;
632
735
  VALUE b = _b ? rb_str_new2(_b) : Qnil;
633
736
  VALUE c = _c ? rb_str_new2(_c) : Qnil;
634
737
  VALUE d = _d ? rb_str_new2(_d) : Qnil;
635
- VALUE callback = rb_iv_get(self, "@authorizer");
636
- VALUE result = rb_funcall(callback, rb_intern("call"), 5, action, a, b, c, d);
738
+ VALUE result = rb_funcall(db_ctx->authorizer, rb_intern("call"), 5, action, a, b, c, d);
637
739
 
638
740
  if (T_FIXNUM == TYPE(result)) { return (int)NUM2INT(result); }
639
741
  if (Qtrue == result) { return SQLITE_OK; }
@@ -662,12 +764,12 @@ set_authorizer(VALUE self, VALUE authorizer)
662
764
  REQUIRE_OPEN_DB(ctx);
663
765
 
664
766
  status = sqlite3_set_authorizer(
665
- ctx->db, NIL_P(authorizer) ? NULL : rb_sqlite3_auth, (void *)self
767
+ ctx->db, NIL_P(authorizer) ? NULL : rb_sqlite3_auth, (void *)ctx
666
768
  );
667
769
 
668
770
  CHECK(ctx->db, status);
669
771
 
670
- rb_iv_set(self, "@authorizer", authorizer);
772
+ RB_OBJ_WRITE(self, &ctx->authorizer, authorizer);
671
773
 
672
774
  return self;
673
775
  }
@@ -750,6 +852,7 @@ static VALUE
750
852
  collation(VALUE self, VALUE name, VALUE comparator)
751
853
  {
752
854
  sqlite3RubyPtr ctx;
855
+ VALUE collations;
753
856
  TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
754
857
  REQUIRE_OPEN_DB(ctx);
755
858
 
@@ -760,8 +863,10 @@ collation(VALUE self, VALUE name, VALUE comparator)
760
863
  (void *)comparator,
761
864
  NIL_P(comparator) ? NULL : rb_comparator_func));
762
865
 
763
- /* Make sure our comparator doesn't get garbage collected. */
764
- rb_hash_aset(rb_iv_get(self, "@collations"), name, comparator);
866
+ /* sqlite holds a raw pointer to the comparator, so keep it alive and unmoved. */
867
+ collations = rb_iv_get(self, "@collations");
868
+ rb_hash_aset(collations, name, comparator);
869
+ RB_OBJ_WRITE(self, &ctx->collations, collations);
765
870
 
766
871
  return self;
767
872
  }
@@ -926,6 +1031,7 @@ rb_sqlite3_open16(VALUE self, VALUE file)
926
1031
  sqlite3RubyPtr ctx;
927
1032
 
928
1033
  TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
1034
+ REQUIRE_CLOSED_DB(ctx);
929
1035
 
930
1036
  #if defined TAINTING_SUPPORT
931
1037
  #if defined StringValueCStr
@@ -941,7 +1047,12 @@ rb_sqlite3_open16(VALUE self, VALUE file)
941
1047
  // so we do not ever set SQLITE3_RB_DATABASE_READONLY in ctx->flags
942
1048
  status = sqlite3_open16(utf16_string_value_ptr(file), &ctx->db);
943
1049
 
944
- CHECK(ctx->db, status)
1050
+ if (status != SQLITE_OK) {
1051
+ char *msg = sqlite3_mprintf("%s", sqlite3_errmsg(ctx->db));
1052
+ sqlite3_close_v2(ctx->db);
1053
+ ctx->db = NULL;
1054
+ CHECK_MSG(ctx->db, status, msg);
1055
+ }
945
1056
 
946
1057
  return INT2NUM(status);
947
1058
  }
@@ -10,6 +10,11 @@
10
10
  struct _sqlite3Ruby {
11
11
  sqlite3 *db;
12
12
  VALUE busy_handler;
13
+ VALUE functions;
14
+ VALUE collations;
15
+ VALUE aggregators;
16
+ VALUE trace_handler;
17
+ VALUE authorizer;
13
18
  int stmt_timeout;
14
19
  struct timespec stmt_deadline;
15
20
  rb_pid_t owner;
@@ -19,6 +24,9 @@ struct _sqlite3Ruby {
19
24
  typedef struct _sqlite3Ruby sqlite3Ruby;
20
25
  typedef sqlite3Ruby *sqlite3RubyPtr;
21
26
 
27
+ /* Pinning a collection doesn't pin what's in it, hence both. */
28
+ void rb_sqlite3_pin_array_and_contents(VALUE ary);
29
+
22
30
  void init_sqlite3_database();
23
31
  void set_sqlite3_func_result(sqlite3_context *ctx, VALUE result);
24
32
 
@@ -66,7 +66,7 @@ module Sqlite3
66
66
  "-DSQLITE_ENABLE_DBSTAT_VTAB=1"
67
67
  ]
68
68
  env["CFLAGS"] = [user_cflags, env["CFLAGS"], more_cflags].flatten.join(" ")
69
- recipe.configure_options += env.select { |k, v| ENV_ALLOWLIST.include?(k) }
69
+ recipe.configure_options += env.slice(*ENV_ALLOWLIST)
70
70
  .map { |key, value| "#{key}=#{value.strip}" }
71
71
  end
72
72
 
Binary file
Binary file
Binary file
Binary file
@@ -171,8 +171,6 @@ module SQLite3
171
171
  end
172
172
  end
173
173
 
174
- @tracefunc = nil
175
- @authorizer = nil
176
174
  @progress_handler = nil
177
175
  @collations = {}
178
176
  @functions = []
@@ -458,9 +456,7 @@ module SQLite3
458
456
  #
459
457
  # See also #create_aggregate_handler for a more object-oriented approach to
460
458
  # aggregate functions.
461
- def create_aggregate(name, arity, step = nil, finalize = nil,
462
- text_rep = Constants::TextRep::ANY, &block)
463
-
459
+ def create_aggregate(name, arity, step = nil, finalize = nil, text_rep = Constants::TextRep::ANY, &block)
464
460
  proxy = Class.new do
465
461
  def self.step(&block)
466
462
  define_method(:step_with_ctx, &block)
@@ -1,4 +1,4 @@
1
1
  module SQLite3
2
2
  # (String) the version of the sqlite3 gem, e.g. "2.1.1"
3
- VERSION = "2.9.5"
3
+ VERSION = "2.9.6"
4
4
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sqlite3
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.9.5
4
+ version: 2.9.6
5
5
  platform: x86-linux-musl
6
6
  authors:
7
7
  - Jamis Buck