sqlite3 2.1.0.rc1-x86_64-linux-gnu → 2.1.0.rc2-x86_64-linux-gnu

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 354e3943741a819d8bc285bd26573e6df25154ace5a39e6edf2220e24f7ce5e0
4
- data.tar.gz: dc33f1e99524a65d3ab5c387bb20fbf550723937f307ee4352aa49411d669be9
3
+ metadata.gz: 1c6dd8dd1847a3ab86b2e7626e64e9adc66967906d7b594f9540f1239358c675
4
+ data.tar.gz: e409c99762cea60186c288f958af877d3d466e64b9a85fbe19323996633c14b7
5
5
  SHA512:
6
- metadata.gz: 4092492e92fc72e59474081e2e11749f364329b84833acad749ee7ad9e17797419a0377f31f68e15aa5c3d7a298ae33fc0e648f821b8bc46957ef9ebb1246cfd
7
- data.tar.gz: 8e0434d82a80b566826d939c106536226017eb30bb339199b6ac797a6d7596220cad557e3dc086e206780edd394a53614322927558aa29986089aebf23aa408f
6
+ metadata.gz: 4e8a1510d3c62f9d6440b541a91944920a1d728a7e9dbac1b0a9d8287725e89f1c6c387fc67718e82ce387fa4e9150b35e4ee0ac3efa8f702d320893198b61ab
7
+ data.tar.gz: 2d9cda1218ac175908fc466344c0b1c76b1f6cd0a02d412c73170ce1310071ac9a7a61841bfb141c7341c1670498781a2e22efb19de4757017036bbcbd29a86d
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # sqlite3-ruby Changelog
2
2
 
3
+ ## prerelease 2.1.0.rc2 / 2024-09-18
4
+
5
+ ### Improved
6
+
7
+ - Address a performance regression in 2.1.0.rc1.
8
+
9
+
3
10
  ## prerelease 2.1.0.rc1 / 2024-09-18
4
11
 
5
12
  ### Ruby
data/CONTRIBUTING.md CHANGED
@@ -16,20 +16,15 @@ please look there for additional information.
16
16
 
17
17
  All statements keep pointers back to their respective database connections.
18
18
  The `@connection` instance variable on the `Statement` handle keeps the database
19
- connection alive. Memory allocated for a statement handler will be freed in
20
- two cases:
19
+ connection alive.
21
20
 
22
- 1. `#close` is called on the statement
23
- 2. The `SQLite3::Database` object gets garbage collected
24
-
25
- We can't free the memory for the statement in the garbage collection function
26
- for the statement handler. The reason is because there exists a race
27
- condition. We cannot guarantee the order in which objects will be garbage
28
- collected. So, it is possible that a connection and a statement are up for
29
- garbage collection. If the database connection were to be free'd before the
30
- statement, then boom. Instead we'll be conservative and free unclosed
31
- statements when the connection is terminated.
21
+ We use `sqlite3_close_v2` in `Database#close` since v2.1.0 which defers _actually_ closing the
22
+ connection and freeing the underlying memory until all open statments are closed; though the
23
+ `Database` object will immediately behave as though it's been fully closed. If a Database is not
24
+ explicitly closed, it will be closed when it is GCed.
32
25
 
26
+ `Statement#close` finalizes the underlying statement. If a Statement is not explicitly closed, it
27
+ will be closed/finalized when it is GCed.
33
28
 
34
29
 
35
30
  ## Building gems
@@ -49,15 +49,16 @@ discard_db(sqlite3RubyPtr ctx)
49
49
  }
50
50
 
51
51
  ctx->db = NULL;
52
+ ctx->flags |= SQLITE3_RB_DATABASE_DISCARDED;
52
53
  }
53
54
 
54
55
  static void
55
56
  close_or_discard_db(sqlite3RubyPtr ctx)
56
57
  {
57
58
  if (ctx->db) {
58
- int isReadonly = (ctx->flags & SQLITE_OPEN_READONLY);
59
+ int is_readonly = (ctx->flags & SQLITE3_RB_DATABASE_READONLY);
59
60
 
60
- if (isReadonly || ctx->owner == getpid()) {
61
+ if (is_readonly || ctx->owner == getpid()) {
61
62
  // Ordinary close.
62
63
  sqlite3_close_v2(ctx->db);
63
64
  ctx->db = NULL;
@@ -153,7 +154,9 @@ rb_sqlite3_open_v2(VALUE self, VALUE file, VALUE mode, VALUE zvfs)
153
154
  );
154
155
 
155
156
  CHECK(ctx->db, status);
156
- ctx->flags = flags;
157
+ if (flags & SQLITE_OPEN_READONLY) {
158
+ ctx->flags |= SQLITE3_RB_DATABASE_READONLY;
159
+ }
157
160
 
158
161
  return self;
159
162
  }
@@ -943,11 +946,10 @@ rb_sqlite3_open16(VALUE self, VALUE file)
943
946
  #endif
944
947
  #endif
945
948
 
946
- status = sqlite3_open16(utf16_string_value_ptr(file), &ctx->db);
947
-
948
- // these are the perm flags used implicitly by sqlite3_open16,
949
+ // sqlite3_open16 implicitly uses flags (SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE)
949
950
  // see https://www.sqlite.org/capi3ref.html#sqlite3_open
950
- ctx->flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
951
+ // so we do not ever set SQLITE3_RB_DATABASE_READONLY in ctx->flags
952
+ status = sqlite3_open16(utf16_string_value_ptr(file), &ctx->db);
951
953
 
952
954
  CHECK(ctx->db, status)
953
955
 
@@ -3,6 +3,10 @@
3
3
 
4
4
  #include <sqlite3_ruby.h>
5
5
 
6
+ /* bits in the `flags` field */
7
+ #define SQLITE3_RB_DATABASE_READONLY 0x01
8
+ #define SQLITE3_RB_DATABASE_DISCARDED 0x02
9
+
6
10
  struct _sqlite3Ruby {
7
11
  sqlite3 *db;
8
12
  VALUE busy_handler;
@@ -1,22 +1,12 @@
1
1
  #include <sqlite3_ruby.h>
2
2
 
3
3
  #define REQUIRE_OPEN_STMT(_ctxt) \
4
- if(!_ctxt->st) \
4
+ if (!_ctxt->st) \
5
5
  rb_raise(rb_path2class("SQLite3::Exception"), "cannot use a closed statement");
6
6
 
7
- static void
8
- require_open_db(VALUE stmt_rb)
9
- {
10
- VALUE closed_p = rb_funcall(
11
- rb_iv_get(stmt_rb, "@connection"),
12
- rb_intern("closed?"), 0);
13
-
14
- if (RTEST(closed_p)) {
15
- rb_raise(rb_path2class("SQLite3::Exception"),
16
- "cannot use a statement associated with a closed database");
17
- }
18
- }
19
-
7
+ #define REQUIRE_LIVE_DB(_ctxt) \
8
+ if (_ctxt->db->flags & SQLITE3_RB_DATABASE_DISCARDED) \
9
+ rb_raise(rb_path2class("SQLite3::Exception"), "cannot use a statement associated with a discarded database");
20
10
 
21
11
  VALUE cSqlite3Statement;
22
12
 
@@ -71,6 +61,11 @@ prepare(VALUE self, VALUE db, VALUE sql)
71
61
 
72
62
  TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
73
63
 
64
+ /* Dereferencing a pointer to the database struct will be faster than accessing it through the
65
+ * instance variable @connection. The struct pointer is guaranteed to be live because instance
66
+ * variable will keep it from being GCed. */
67
+ ctx->db = db_ctx;
68
+
74
69
  #ifdef HAVE_SQLITE3_PREPARE_V2
75
70
  status = sqlite3_prepare_v2(
76
71
  #else
@@ -135,7 +130,7 @@ step(VALUE self)
135
130
 
136
131
  TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
137
132
 
138
- require_open_db(self);
133
+ REQUIRE_LIVE_DB(ctx);
139
134
  REQUIRE_OPEN_STMT(ctx);
140
135
 
141
136
  if (ctx->done_p) { return Qnil; }
@@ -232,7 +227,7 @@ bind_param(VALUE self, VALUE key, VALUE value)
232
227
 
233
228
  TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
234
229
 
235
- require_open_db(self);
230
+ REQUIRE_LIVE_DB(ctx);
236
231
  REQUIRE_OPEN_STMT(ctx);
237
232
 
238
233
  switch (TYPE(key)) {
@@ -326,7 +321,7 @@ reset_bang(VALUE self)
326
321
 
327
322
  TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
328
323
 
329
- require_open_db(self);
324
+ REQUIRE_LIVE_DB(ctx);
330
325
  REQUIRE_OPEN_STMT(ctx);
331
326
 
332
327
  sqlite3_reset(ctx->st);
@@ -348,7 +343,7 @@ clear_bindings_bang(VALUE self)
348
343
 
349
344
  TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
350
345
 
351
- require_open_db(self);
346
+ REQUIRE_LIVE_DB(ctx);
352
347
  REQUIRE_OPEN_STMT(ctx);
353
348
 
354
349
  sqlite3_clear_bindings(ctx->st);
@@ -382,7 +377,7 @@ column_count(VALUE self)
382
377
  sqlite3StmtRubyPtr ctx;
383
378
  TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
384
379
 
385
- require_open_db(self);
380
+ REQUIRE_LIVE_DB(ctx);
386
381
  REQUIRE_OPEN_STMT(ctx);
387
382
 
388
383
  return INT2NUM(sqlite3_column_count(ctx->st));
@@ -415,7 +410,7 @@ column_name(VALUE self, VALUE index)
415
410
 
416
411
  TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
417
412
 
418
- require_open_db(self);
413
+ REQUIRE_LIVE_DB(ctx);
419
414
  REQUIRE_OPEN_STMT(ctx);
420
415
 
421
416
  name = sqlite3_column_name(ctx->st, (int)NUM2INT(index));
@@ -440,7 +435,7 @@ column_decltype(VALUE self, VALUE index)
440
435
 
441
436
  TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
442
437
 
443
- require_open_db(self);
438
+ REQUIRE_LIVE_DB(ctx);
444
439
  REQUIRE_OPEN_STMT(ctx);
445
440
 
446
441
  name = sqlite3_column_decltype(ctx->st, (int)NUM2INT(index));
@@ -459,7 +454,7 @@ bind_parameter_count(VALUE self)
459
454
  sqlite3StmtRubyPtr ctx;
460
455
  TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
461
456
 
462
- require_open_db(self);
457
+ REQUIRE_LIVE_DB(ctx);
463
458
  REQUIRE_OPEN_STMT(ctx);
464
459
 
465
460
  return INT2NUM(sqlite3_bind_parameter_count(ctx->st));
@@ -568,7 +563,7 @@ stats_as_hash(VALUE self)
568
563
  sqlite3StmtRubyPtr ctx;
569
564
  TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
570
565
 
571
- require_open_db(self);
566
+ REQUIRE_LIVE_DB(ctx);
572
567
  REQUIRE_OPEN_STMT(ctx);
573
568
 
574
569
  VALUE arg = rb_hash_new();
@@ -587,7 +582,7 @@ stat_for(VALUE self, VALUE key)
587
582
  sqlite3StmtRubyPtr ctx;
588
583
  TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
589
584
 
590
- require_open_db(self);
585
+ REQUIRE_LIVE_DB(ctx);
591
586
  REQUIRE_OPEN_STMT(ctx);
592
587
 
593
588
  if (SYMBOL_P(key)) {
@@ -609,7 +604,7 @@ memused(VALUE self)
609
604
  sqlite3StmtRubyPtr ctx;
610
605
  TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
611
606
 
612
- require_open_db(self);
607
+ REQUIRE_LIVE_DB(ctx);
613
608
  REQUIRE_OPEN_STMT(ctx);
614
609
 
615
610
  return INT2NUM(sqlite3_stmt_status(ctx->st, SQLITE_STMTSTATUS_MEMUSED, 0));
@@ -628,7 +623,7 @@ database_name(VALUE self, VALUE index)
628
623
  sqlite3StmtRubyPtr ctx;
629
624
  TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
630
625
 
631
- require_open_db(self);
626
+ REQUIRE_LIVE_DB(ctx);
632
627
  REQUIRE_OPEN_STMT(ctx);
633
628
 
634
629
  return SQLITE3_UTF8_STR_NEW2(
@@ -647,7 +642,7 @@ get_sql(VALUE self)
647
642
  sqlite3StmtRubyPtr ctx;
648
643
  TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
649
644
 
650
- require_open_db(self);
645
+ REQUIRE_LIVE_DB(ctx);
651
646
  REQUIRE_OPEN_STMT(ctx);
652
647
 
653
648
  return rb_obj_freeze(SQLITE3_UTF8_STR_NEW2(sqlite3_sql(ctx->st)));
@@ -667,7 +662,7 @@ get_expanded_sql(VALUE self)
667
662
 
668
663
  TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
669
664
 
670
- require_open_db(self);
665
+ REQUIRE_LIVE_DB(ctx);
671
666
  REQUIRE_OPEN_STMT(ctx);
672
667
 
673
668
  expanded_sql = sqlite3_expanded_sql(ctx->st);
@@ -5,6 +5,7 @@
5
5
 
6
6
  struct _sqlite3StmtRuby {
7
7
  sqlite3_stmt *st;
8
+ sqlite3Ruby *db;
8
9
  int done_p;
9
10
  };
10
11
 
Binary file
Binary file
Binary file
@@ -1,3 +1,3 @@
1
1
  module SQLite3
2
- VERSION = "2.1.0.rc1"
2
+ VERSION = "2.1.0.rc2"
3
3
  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.1.0.rc1
4
+ version: 2.1.0.rc2
5
5
  platform: x86_64-linux-gnu
6
6
  authors:
7
7
  - Jamis Buck
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2024-09-18 00:00:00.000000000 Z
14
+ date: 2024-09-19 00:00:00.000000000 Z
15
15
  dependencies: []
16
16
  description: |
17
17
  Ruby library to interface with the SQLite3 database engine (http://www.sqlite.org). Precompiled