sqlite3 2.9.6 → 2.10.2

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.
@@ -74,51 +74,6 @@ close_or_discard_db(sqlite3RubyPtr ctx)
74
74
  }
75
75
 
76
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
-
122
77
  static void
123
78
  database_mark(void *ctx)
124
79
  {
@@ -130,8 +85,8 @@ database_mark(void *ctx)
130
85
  rb_gc_mark(c->authorizer);
131
86
 
132
87
  rb_sqlite3_pin_array_and_contents(c->functions);
133
- pin_hash_and_contents(c->collations);
134
- pin_aggregators(c->aggregators);
88
+ rb_sqlite3_pin_array_and_contents(c->collations);
89
+ rb_sqlite3_aggregator_pin(c->aggregators);
135
90
  }
136
91
 
137
92
  static void
@@ -150,7 +105,7 @@ database_memsize(const void *ctx)
150
105
  }
151
106
 
152
107
  static const rb_data_type_t database_type = {
153
- .wrap_struct_name = "SQLite3::Backup",
108
+ .wrap_struct_name = "SQLite3::Database",
154
109
  .function = {
155
110
  .dmark = database_mark,
156
111
  .dfree = deallocate,
@@ -321,11 +276,21 @@ total_changes(VALUE self)
321
276
  return INT2NUM(sqlite3_total_changes(ctx->db));
322
277
  }
323
278
 
279
+ static VALUE
280
+ tracefunc_protected(VALUE args_value)
281
+ {
282
+ VALUE *args = (VALUE *)args_value;
283
+ return rb_funcall(args[0], rb_intern("call"), 1, rb_str_new2((const char *)args[1]));
284
+ }
285
+
324
286
  static void
325
287
  tracefunc(void *data, const char *sql)
326
288
  {
327
289
  sqlite3RubyPtr ctx = (sqlite3RubyPtr)data;
328
- rb_funcall(ctx->trace_handler, rb_intern("call"), 1, rb_str_new2(sql));
290
+ VALUE args[] = { ctx->trace_handler, (VALUE)sql };
291
+ int failed;
292
+
293
+ rb_sqlite3_protect_callback(tracefunc_protected, (VALUE)args, &failed);
329
294
  }
330
295
 
331
296
  /* call-seq:
@@ -356,15 +321,24 @@ trace(int argc, VALUE *argv, VALUE self)
356
321
  return self;
357
322
  }
358
323
 
324
+ static VALUE
325
+ rb_sqlite3_busy_handler_protected(VALUE args_value)
326
+ {
327
+ VALUE *args = (VALUE *)args_value;
328
+ return rb_funcall(args[0], rb_intern("call"), 1, INT2NUM((int)args[1]));
329
+ }
330
+
359
331
  static int
360
332
  rb_sqlite3_busy_handler(void *context, int count)
361
333
  {
362
334
  sqlite3RubyPtr ctx = (sqlite3RubyPtr)context;
335
+ VALUE args[] = { ctx->busy_handler, (VALUE)count };
336
+ VALUE result;
337
+ int failed;
363
338
 
364
- VALUE handle = ctx->busy_handler;
365
- VALUE result = rb_funcall(handle, rb_intern("call"), 1, INT2NUM(count));
339
+ result = rb_sqlite3_protect_callback(rb_sqlite3_busy_handler_protected, (VALUE)args, &failed);
366
340
 
367
- if (Qfalse == result) { return 0; }
341
+ if (failed || Qfalse == result) { return 0; }
368
342
 
369
343
  return 1;
370
344
  }
@@ -417,8 +391,10 @@ rb_sqlite3_statement_timeout(void *context)
417
391
  clock_gettime(CLOCK_MONOTONIC, &currentTime);
418
392
 
419
393
  if (!timespecisset(&ctx->stmt_deadline)) {
420
- // Set stmt_deadline if not already set
421
- ctx->stmt_deadline = currentTime;
394
+ struct timespec timeout;
395
+ timeout.tv_sec = ctx->stmt_timeout / 1000;
396
+ timeout.tv_nsec = (ctx->stmt_timeout % 1000) * 1000000L;
397
+ timespecadd(&currentTime, &timeout, &ctx->stmt_deadline);
422
398
  } else if (timespecafter(&currentTime, &ctx->stmt_deadline)) {
423
399
  return 1;
424
400
  }
@@ -527,14 +503,14 @@ set_sqlite3_func_result(sqlite3_context *ctx, VALUE result)
527
503
  sqlite3_result_blob(
528
504
  ctx,
529
505
  (const void *)StringValuePtr(result),
530
- (int)RSTRING_LEN(result),
506
+ RSTRING_LENINT(result),
531
507
  SQLITE_TRANSIENT
532
508
  );
533
509
  } else {
534
510
  sqlite3_result_text(
535
511
  ctx,
536
512
  (const char *)StringValuePtr(result),
537
- (int)RSTRING_LEN(result),
513
+ RSTRING_LENINT(result),
538
514
  SQLITE_TRANSIENT
539
515
  );
540
516
  }
@@ -576,13 +552,13 @@ static void
576
552
  rb_sqlite3_func(sqlite3_context *ctx, int argc, sqlite3_value **argv)
577
553
  {
578
554
  rb_sqlite3_func_args_t args = { .ctx = ctx, .argc = argc, .argv = argv };
579
- int exc_status;
555
+ int failed;
580
556
 
581
- rb_protect(rb_sqlite3_func_protected, (VALUE)&args, &exc_status);
557
+ rb_sqlite3_protect_callback(rb_sqlite3_func_protected, (VALUE)&args, &failed);
582
558
 
583
- if (exc_status) {
559
+ if (failed) {
584
560
  /* the user should never see this message, because Statement#step will
585
- * re-raise the exception still in rb_errinfo */
561
+ * resume the Ruby exception instead */
586
562
  sqlite3_result_error(ctx, "Ruby Exception occurred", -1);
587
563
  }
588
564
  }
@@ -720,6 +696,33 @@ changes(VALUE self)
720
696
  return INT2NUM(sqlite3_changes(ctx->db));
721
697
  }
722
698
 
699
+ typedef struct {
700
+ VALUE authorizer;
701
+ int action;
702
+ const char *a;
703
+ const char *b;
704
+ const char *c;
705
+ const char *d;
706
+ } rb_sqlite3_auth_args_t;
707
+
708
+ static VALUE
709
+ rb_sqlite3_auth_protected(VALUE auth_args_value)
710
+ {
711
+ rb_sqlite3_auth_args_t *args = (rb_sqlite3_auth_args_t *)auth_args_value;
712
+ VALUE action = INT2NUM(args->action);
713
+ VALUE a = args->a ? rb_str_new2(args->a) : Qnil;
714
+ VALUE b = args->b ? rb_str_new2(args->b) : Qnil;
715
+ VALUE c = args->c ? rb_str_new2(args->c) : Qnil;
716
+ VALUE d = args->d ? rb_str_new2(args->d) : Qnil;
717
+ VALUE result = rb_funcall(args->authorizer, rb_intern("call"), 5, action, a, b, c, d);
718
+
719
+ if (T_FIXNUM == TYPE(result)) { return INT2FIX(NUM2INT(result)); }
720
+ if (Qtrue == result) { return INT2FIX(SQLITE_OK); }
721
+ if (Qfalse == result) { return INT2FIX(SQLITE_DENY); }
722
+
723
+ return INT2FIX(SQLITE_IGNORE);
724
+ }
725
+
723
726
  static int
724
727
  rb_sqlite3_auth(
725
728
  void *ctx,
@@ -730,18 +733,17 @@ rb_sqlite3_auth(
730
733
  const char *_d)
731
734
  {
732
735
  sqlite3RubyPtr db_ctx = (sqlite3RubyPtr)ctx;
733
- VALUE action = INT2NUM(_action);
734
- VALUE a = _a ? rb_str_new2(_a) : Qnil;
735
- VALUE b = _b ? rb_str_new2(_b) : Qnil;
736
- VALUE c = _c ? rb_str_new2(_c) : Qnil;
737
- VALUE d = _d ? rb_str_new2(_d) : Qnil;
738
- VALUE result = rb_funcall(db_ctx->authorizer, rb_intern("call"), 5, action, a, b, c, d);
739
-
740
- if (T_FIXNUM == TYPE(result)) { return (int)NUM2INT(result); }
741
- if (Qtrue == result) { return SQLITE_OK; }
742
- if (Qfalse == result) { return SQLITE_DENY; }
743
-
744
- return SQLITE_IGNORE;
736
+ rb_sqlite3_auth_args_t args = {
737
+ .authorizer = db_ctx->authorizer, .action = _action, .a = _a, .b = _b, .c = _c, .d = _d
738
+ };
739
+ VALUE result;
740
+ int failed;
741
+
742
+ result = rb_sqlite3_protect_callback(rb_sqlite3_auth_protected, (VALUE)&args, &failed);
743
+
744
+ if (failed) { return SQLITE_DENY; }
745
+
746
+ return FIX2INT(result);
745
747
  }
746
748
 
747
749
  /* call-seq: set_authorizer = auth
@@ -813,10 +815,19 @@ set_extended_result_codes(VALUE self, VALUE enable)
813
815
  return self;
814
816
  }
815
817
 
816
- int
817
- rb_comparator_func(void *ctx, int a_len, const void *a, int b_len, const void *b)
818
- {
818
+ typedef struct {
819
819
  VALUE comparator;
820
+ int a_len;
821
+ const void *a;
822
+ int b_len;
823
+ const void *b;
824
+ int comparison;
825
+ } rb_comparator_args_t;
826
+
827
+ static VALUE
828
+ rb_comparator_protected(VALUE comparator_args_value)
829
+ {
830
+ rb_comparator_args_t *args = (rb_comparator_args_t *)comparator_args_value;
820
831
  VALUE a_str;
821
832
  VALUE b_str;
822
833
  VALUE comparison;
@@ -824,9 +835,8 @@ rb_comparator_func(void *ctx, int a_len, const void *a, int b_len, const void *b
824
835
 
825
836
  internal_encoding = rb_default_internal_encoding();
826
837
 
827
- comparator = (VALUE)ctx;
828
- a_str = rb_str_new((const char *)a, a_len);
829
- b_str = rb_str_new((const char *)b, b_len);
838
+ a_str = rb_str_new((const char *)args->a, args->a_len);
839
+ b_str = rb_str_new((const char *)args->b, args->b_len);
830
840
 
831
841
  rb_enc_associate_index(a_str, rb_utf8_encindex());
832
842
  rb_enc_associate_index(b_str, rb_utf8_encindex());
@@ -836,9 +846,30 @@ rb_comparator_func(void *ctx, int a_len, const void *a, int b_len, const void *b
836
846
  b_str = rb_str_export_to_enc(b_str, internal_encoding);
837
847
  }
838
848
 
839
- comparison = rb_funcall(comparator, rb_intern("compare"), 2, a_str, b_str);
849
+ comparison = rb_funcall(args->comparator, rb_intern("compare"), 2, a_str, b_str);
850
+
851
+ args->comparison = NUM2INT(comparison);
840
852
 
841
- return NUM2INT(comparison);
853
+ return Qnil;
854
+ }
855
+
856
+ int
857
+ rb_comparator_func(void *ctx, int a_len, const void *a, int b_len, const void *b)
858
+ {
859
+ rb_comparator_args_t args = { .comparator = (VALUE)ctx, .a_len = a_len, .a = a, .b_len = b_len, .b = b };
860
+ int failed;
861
+
862
+ rb_sqlite3_protect_callback(rb_comparator_protected, (VALUE)&args, &failed);
863
+
864
+ /* sqlite has no way to report a comparator error */
865
+ return failed ? 0 : args.comparison;
866
+ }
867
+
868
+ static int
869
+ push_hash_value(VALUE UNUSED(key), VALUE value, VALUE ary)
870
+ {
871
+ rb_ary_push(ary, value);
872
+ return ST_CONTINUE;
842
873
  }
843
874
 
844
875
  /* call-seq: db.collation(name, comparator)
@@ -852,21 +883,42 @@ static VALUE
852
883
  collation(VALUE self, VALUE name, VALUE comparator)
853
884
  {
854
885
  sqlite3RubyPtr ctx;
855
- VALUE collations;
886
+ VALUE registry, key, comparators;
887
+ char *key_ptr;
888
+ long i;
856
889
  TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
857
890
  REQUIRE_OPEN_DB(ctx);
858
891
 
892
+ /* sqlite holds a raw pointer to the comparator, so keep it alive and
893
+ * unmoved. The registry is private because callers can mutate the public
894
+ * @collations hash, and the snapshot is an array so database_mark can pin
895
+ * it without iterating a hash. sqlite matches collation names without
896
+ * regard to ASCII case, so the registry does too. The key and registry
897
+ * are prepared before sqlite takes the pointer, and the snapshot is
898
+ * published before the public hash, whose write can raise. */
899
+ key = rb_str_new_cstr(StringValuePtr(name));
900
+ key_ptr = RSTRING_PTR(key);
901
+ for (i = 0; i < RSTRING_LEN(key); i++) {
902
+ if (key_ptr[i] >= 'A' && key_ptr[i] <= 'Z') { key_ptr[i] += 'a' - 'A'; }
903
+ }
904
+ if (!rb_ivar_defined(self, rb_intern("-collations"))) {
905
+ rb_iv_set(self, "-collations", rb_hash_new());
906
+ }
907
+ registry = rb_iv_get(self, "-collations");
908
+
859
909
  CHECK(ctx->db, sqlite3_create_collation(
860
910
  ctx->db,
861
- StringValuePtr(name),
911
+ RSTRING_PTR(name),
862
912
  SQLITE_UTF8,
863
913
  (void *)comparator,
864
914
  NIL_P(comparator) ? NULL : rb_comparator_func));
865
915
 
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);
916
+ rb_hash_aset(registry, key, comparator);
917
+ comparators = rb_ary_new();
918
+ rb_hash_foreach(registry, push_hash_value, comparators);
919
+ RB_OBJ_WRITE(self, &ctx->collations, comparators);
920
+
921
+ rb_hash_aset(rb_iv_get(self, "@collations"), name, comparator);
870
922
 
871
923
  return self;
872
924
  }
@@ -932,42 +984,68 @@ transaction_active_p(VALUE self)
932
984
  return sqlite3_get_autocommit(ctx->db) ? Qfalse : Qtrue;
933
985
  }
934
986
 
935
- static int
936
- hash_callback_function(VALUE callback_ary, int count, char **data, char **columns)
987
+ typedef struct {
988
+ VALUE callback_ary;
989
+ VALUE (*build_row)(VALUE);
990
+ } rb_sqlite3_exec_batch_t;
991
+
992
+ typedef struct {
993
+ VALUE callback_ary;
994
+ int count;
995
+ char **data;
996
+ char **columns;
997
+ } rb_sqlite3_exec_row_t;
998
+
999
+ static VALUE
1000
+ hash_callback_protected(VALUE row_value)
937
1001
  {
1002
+ rb_sqlite3_exec_row_t *row = (rb_sqlite3_exec_row_t *)row_value;
938
1003
  VALUE new_hash = rb_hash_new();
939
1004
  int i;
940
1005
 
941
- for (i = 0; i < count; i++) {
942
- if (data[i] == NULL) {
943
- rb_hash_aset(new_hash, rb_str_new_cstr(columns[i]), Qnil);
1006
+ for (i = 0; i < row->count; i++) {
1007
+ if (row->data[i] == NULL) {
1008
+ rb_hash_aset(new_hash, rb_str_new_cstr(row->columns[i]), Qnil);
944
1009
  } else {
945
- rb_hash_aset(new_hash, rb_str_new_cstr(columns[i]), rb_str_new_cstr(data[i]));
1010
+ rb_hash_aset(new_hash, rb_str_new_cstr(row->columns[i]), rb_str_new_cstr(row->data[i]));
946
1011
  }
947
1012
  }
948
1013
 
949
- rb_ary_push(callback_ary, new_hash);
1014
+ rb_ary_push(row->callback_ary, new_hash);
950
1015
 
951
- return 0;
1016
+ return Qnil;
952
1017
  }
953
1018
 
954
- static int
955
- regular_callback_function(VALUE callback_ary, int count, char **data, char **columns)
1019
+ static VALUE
1020
+ regular_callback_protected(VALUE row_value)
956
1021
  {
1022
+ rb_sqlite3_exec_row_t *row = (rb_sqlite3_exec_row_t *)row_value;
957
1023
  VALUE new_ary = rb_ary_new();
958
1024
  int i;
959
1025
 
960
- for (i = 0; i < count; i++) {
961
- if (data[i] == NULL) {
1026
+ for (i = 0; i < row->count; i++) {
1027
+ if (row->data[i] == NULL) {
962
1028
  rb_ary_push(new_ary, Qnil);
963
1029
  } else {
964
- rb_ary_push(new_ary, rb_str_new_cstr(data[i]));
1030
+ rb_ary_push(new_ary, rb_str_new_cstr(row->data[i]));
965
1031
  }
966
1032
  }
967
1033
 
968
- rb_ary_push(callback_ary, new_ary);
1034
+ rb_ary_push(row->callback_ary, new_ary);
969
1035
 
970
- return 0;
1036
+ return Qnil;
1037
+ }
1038
+
1039
+ static int
1040
+ exec_batch_callback_function(void *batch_ptr, int count, char **data, char **columns)
1041
+ {
1042
+ rb_sqlite3_exec_batch_t *batch = (rb_sqlite3_exec_batch_t *)batch_ptr;
1043
+ rb_sqlite3_exec_row_t row = { .callback_ary = batch->callback_ary, .count = count, .data = data, .columns = columns };
1044
+ int failed;
1045
+
1046
+ rb_sqlite3_protect_callback(batch->build_row, (VALUE)&row, &failed);
1047
+
1048
+ return failed;
971
1049
  }
972
1050
 
973
1051
 
@@ -985,19 +1063,27 @@ exec_batch(VALUE self, VALUE sql, VALUE results_as_hash)
985
1063
  sqlite3RubyPtr ctx;
986
1064
  int status;
987
1065
  VALUE callback_ary = rb_ary_new();
1066
+ rb_sqlite3_exec_batch_t batch = {
1067
+ .callback_ary = callback_ary,
1068
+ .build_row = results_as_hash == Qtrue ? hash_callback_protected : regular_callback_protected
1069
+ };
1070
+ rb_sqlite3_callback_frame_t frame;
1071
+ int callback_state;
1072
+ const char *sql_cstr;
988
1073
  char *errMsg;
989
1074
 
990
1075
  TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
991
1076
  REQUIRE_OPEN_DB(ctx);
992
1077
 
993
- if (results_as_hash == Qtrue) {
994
- status = sqlite3_exec(ctx->db, StringValuePtr(sql), (sqlite3_callback)hash_callback_function,
995
- (void *)callback_ary,
996
- &errMsg);
997
- } else {
998
- status = sqlite3_exec(ctx->db, StringValuePtr(sql), (sqlite3_callback)regular_callback_function,
999
- (void *)callback_ary,
1000
- &errMsg);
1078
+ sql_cstr = StringValuePtr(sql);
1079
+ timespecclear(&ctx->stmt_deadline);
1080
+
1081
+ rb_sqlite3_push_callback_frame(&frame);
1082
+ status = sqlite3_exec(ctx->db, sql_cstr, exec_batch_callback_function, (void *)&batch, &errMsg);
1083
+
1084
+ if ((callback_state = rb_sqlite3_pop_callback_frame(&frame))) {
1085
+ sqlite3_free(errMsg);
1086
+ rb_jump_tag(callback_state);
1001
1087
  }
1002
1088
 
1003
1089
  CHECK_MSG(ctx->db, status, errMsg);
@@ -1024,6 +1110,137 @@ db_filename(VALUE self, VALUE db_name)
1024
1110
  return Qnil;
1025
1111
  }
1026
1112
 
1113
+ #ifdef HAVE_SQLITE3_SERIALIZE
1114
+ /* call-seq: db.serialize(database_name = "main")
1115
+ *
1116
+ * Serialize the database into a binary string.
1117
+ *
1118
+ * [database_name] The name of the database to serialize. The default value
1119
+ * is +main+ which is the main database file. For ATTACHed
1120
+ * databases, use the name given in the ATTACH statement.
1121
+ *
1122
+ * Returns the contents of the database as a binary string. For an ordinary
1123
+ * on-disk database file, this is just a copy of the disk file. For an
1124
+ * in-memory database or a "TEMP" database, this is the same sequence of bytes
1125
+ * which would be written to disk if that database were backed up to disk.
1126
+ *
1127
+ * Note: This method will only be defined if SQLite was compiled without
1128
+ * +SQLITE_OMIT_DESERIALIZE+.
1129
+ *
1130
+ * See also: https://www.sqlite.org/c3ref/serialize.html
1131
+ */
1132
+ static VALUE
1133
+ serialize(int argc, VALUE *argv, VALUE self)
1134
+ {
1135
+ sqlite3RubyPtr ctx;
1136
+ VALUE db_name;
1137
+ const char *zSchema;
1138
+ sqlite3_int64 size;
1139
+ unsigned char *data;
1140
+ VALUE result;
1141
+
1142
+ TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
1143
+ REQUIRE_OPEN_DB(ctx);
1144
+
1145
+ rb_scan_args(argc, argv, "01", &db_name);
1146
+
1147
+ zSchema = NIL_P(db_name) ? NULL : StringValueCStr(db_name);
1148
+
1149
+ data = sqlite3_serialize(ctx->db, zSchema, &size, 0);
1150
+
1151
+ if (data == NULL && size < 0) {
1152
+ rb_raise(rb_path2class("SQLite3::Exception"), "unable to serialize database \"%s\"",
1153
+ zSchema ? zSchema : "main");
1154
+ }
1155
+ if (data == NULL && size > 0) {
1156
+ rb_raise(rb_eNoMemError, "failed to allocate %lld bytes for serialization", (long long)size);
1157
+ }
1158
+
1159
+ result = rb_str_new((const char *)data, (long)size);
1160
+ sqlite3_free(data);
1161
+
1162
+ return result;
1163
+ }
1164
+ #endif
1165
+
1166
+ #ifdef HAVE_SQLITE3_DESERIALIZE
1167
+ /* call-seq: db.deserialize(data, database_name = "main")
1168
+ *
1169
+ * Deserialize a binary string into the database. The database is replaced with
1170
+ * the contents of the serialized data.
1171
+ *
1172
+ * [data] A binary string containing the serialized database content.
1173
+ * This is typically obtained from a prior call to #serialize.
1174
+ *
1175
+ * [database_name] The name of the database to replace. The default value is
1176
+ * +main+ which is the main database file. For ATTACHed
1177
+ * databases, use the name given in the ATTACH statement.
1178
+ *
1179
+ * Raises SQLite3::BusyException if the database has an open read or write
1180
+ * transaction, including one held by an unfinished statement, or is involved in
1181
+ * a backup.
1182
+ *
1183
+ * Deserializing into a database backed by a file detaches the connection from
1184
+ * that file. The file is left unchanged, and #filename(database_name) returns an
1185
+ * empty string afterwards.
1186
+ *
1187
+ * ⚠ An image of a database in WAL mode deserializes without error, but later
1188
+ * statements, even <tt>SELECT 1</tt>, raise SQLite3::CantOpenException. Rails
1189
+ * enables WAL mode by default.
1190
+ *
1191
+ * ⚠ Deserializing untrusted data carries the same risks as opening an untrusted
1192
+ * database file. See https://www.sqlite.org/security.html
1193
+ *
1194
+ * Note: This method will only be defined if the loaded SQLite is version 3.54.0
1195
+ * or later and was compiled without +SQLITE_OMIT_DESERIALIZE+. Older versions do
1196
+ * not raise SQLite3::BusyException; they free memory that an unfinished statement
1197
+ * still uses.
1198
+ *
1199
+ * See also: https://www.sqlite.org/c3ref/deserialize.html
1200
+ */
1201
+ static VALUE
1202
+ deserialize(int argc, VALUE *argv, VALUE self)
1203
+ {
1204
+ sqlite3RubyPtr ctx;
1205
+ VALUE data, db_name;
1206
+ const char *zSchema;
1207
+ unsigned char *pData;
1208
+ sqlite3_int64 szDb, szBuf;
1209
+ int status;
1210
+
1211
+ TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
1212
+ REQUIRE_OPEN_DB(ctx);
1213
+
1214
+ rb_scan_args(argc, argv, "11", &data, &db_name);
1215
+
1216
+ StringValue(data);
1217
+ zSchema = NIL_P(db_name) ? NULL : StringValueCStr(db_name);
1218
+ szDb = RSTRING_LEN(data);
1219
+
1220
+ /* SQLite's docs advise padding the buffer with about 20 extra bytes, because a maliciously
1221
+ * malformed image may make SQLite read past its end. See https://www.sqlite.org/c3ref/deserialize.html
1222
+ *
1223
+ * With SQLITE_DESERIALIZE_RESIZEABLE set, SQLite copies pages out of the buffer with bounds
1224
+ * checks instead of reading it in place, so the padding is defensive. It also keeps the
1225
+ * allocation nonzero for an empty string, for which sqlite3_malloc64(0) returns NULL.
1226
+ */
1227
+ szBuf = szDb + 20;
1228
+ pData = sqlite3_malloc64(szBuf);
1229
+ if (pData == NULL) {
1230
+ rb_raise(rb_eNoMemError, "failed to allocate %lld bytes for deserialization", (long long)szBuf);
1231
+ }
1232
+ memcpy(pData, RSTRING_PTR(data), (size_t)szDb);
1233
+ memset(pData + szDb, 0, (size_t)(szBuf - szDb));
1234
+
1235
+ status = sqlite3_deserialize(ctx->db, zSchema, pData, szDb, szDb,
1236
+ SQLITE_DESERIALIZE_FREEONCLOSE | SQLITE_DESERIALIZE_RESIZEABLE);
1237
+
1238
+ CHECK(ctx->db, status);
1239
+
1240
+ return self;
1241
+ }
1242
+ #endif
1243
+
1027
1244
  static VALUE
1028
1245
  rb_sqlite3_open16(VALUE self, VALUE file)
1029
1246
  {
@@ -1104,6 +1321,16 @@ init_sqlite3_database(void)
1104
1321
  #endif
1105
1322
  #endif
1106
1323
 
1324
+ #ifdef HAVE_SQLITE3_SERIALIZE
1325
+ rb_define_method(cSqlite3Database, "serialize", serialize, -1);
1326
+ #endif
1327
+
1328
+ #ifdef HAVE_SQLITE3_DESERIALIZE
1329
+ /* Before 3.54.0, sqlite3_deserialize frees memory that an unfinished statement still uses. */
1330
+ if (sqlite3_libversion_number() >= 3054000) {
1331
+ rb_define_method(cSqlite3Database, "deserialize", deserialize, -1);
1332
+ }
1333
+ #endif
1107
1334
 
1108
1335
  rb_sqlite3_aggregator_init();
1109
1336
  }
@@ -10,6 +10,12 @@
10
10
  struct _sqlite3Ruby {
11
11
  sqlite3 *db;
12
12
  VALUE busy_handler;
13
+ /* sqlite holds raw pointers to everything in these arrays. functions and
14
+ * aggregators are append-only, so redefining a name keeps the old object
15
+ * for the life of the connection: sqlite keys them by name and arity, and
16
+ * releasing on name alone was GHSA-28hh-pr2h-2w89. collations is rebuilt
17
+ * from a private hash keyed by name without regard to ASCII case, as
18
+ * sqlite keys them, so it releases a replaced comparator. */
13
19
  VALUE functions;
14
20
  VALUE collations;
15
21
  VALUE aggregators;
@@ -24,9 +30,6 @@ struct _sqlite3Ruby {
24
30
  typedef struct _sqlite3Ruby sqlite3Ruby;
25
31
  typedef sqlite3Ruby *sqlite3RubyPtr;
26
32
 
27
- /* Pinning a collection doesn't pin what's in it, hence both. */
28
- void rb_sqlite3_pin_array_and_contents(VALUE ary);
29
-
30
33
  void init_sqlite3_database();
31
34
  void set_sqlite3_func_result(sqlite3_context *ctx, VALUE result);
32
35