extralite-bundle 3.1.0 → 3.1.1
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 +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +11 -1
- data/ext/extralite/common.c +6 -7
- data/ext/extralite/database.c +22 -2
- data/lib/extralite/version.rb +1 -1
- data/test/helper.rb +10 -0
- data/test/test_database.rb +35 -0
- data/test/test_sequel.rb +1 -0
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7fffde36ad772833bc816f85c26c6472d1c9e6c8e4ba91092734efeb24e2541a
|
|
4
|
+
data.tar.gz: c4200d06ffece67d1241297567b37b3ddb6bc882d72dd6b4ba402a2611f4a1a1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 97fa8bbe57df8c8f679703764a7b6a185c235cf53c40738bf46f06bea82385fe1a7deed5d2990cb9837a1e1aaf858a5a4a88e5baccbb6117526dce8c3591fd32
|
|
7
|
+
data.tar.gz: 07716c4ba47c25b2ee796ce287e7a87e051176cdbd79badb906ea86fe45fd7526b3cd0180f077cfae3ff6311a7e182b351c36d8696c10feb8ac50714f8dd1dd0
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
|
@@ -49,7 +49,7 @@ latest features and enhancements.
|
|
|
49
49
|
allowing iterating through single records or batches of records.
|
|
50
50
|
- [Prepared queries](#prepared-queries).
|
|
51
51
|
- [Parameter binding](#parameter-binding).
|
|
52
|
-
- [Automatic query caching] for queries
|
|
52
|
+
- [Automatic query caching](#automatic-query-caching) for parametric queries.
|
|
53
53
|
- [Batch execution](#batch-execution-of-queries) of queries.
|
|
54
54
|
- [transactions and savepoints](#transactions-and-savepoints).
|
|
55
55
|
- Advanced features: load [SQLite extensions](#loading-extensions), create
|
|
@@ -363,6 +363,16 @@ To use the transform, pass it along with the SQL string to `Database#query`:
|
|
|
363
363
|
db.qurey(transform, sql) #=> [...]
|
|
364
364
|
```
|
|
365
365
|
|
|
366
|
+
Structured transforms support the following column types:
|
|
367
|
+
|
|
368
|
+
- `integer`
|
|
369
|
+
- `float`
|
|
370
|
+
- `text`
|
|
371
|
+
- `bool` - represented as an integer value of 0/1.
|
|
372
|
+
- `json` - represented as a string (text).
|
|
373
|
+
- A custom proc/lambda - e.g. `->(v) { v.split(',') }`.
|
|
374
|
+
- `auto` - uses the native database data type.
|
|
375
|
+
|
|
366
376
|
Transforms can also be used with [prepared
|
|
367
377
|
queries](#transforms-in-prepared-queries).
|
|
368
378
|
|
data/ext/extralite/common.c
CHANGED
|
@@ -318,6 +318,7 @@ void *exec_multi_stmt_impl(void *ptr) {
|
|
|
318
318
|
int res = sqlite3_prepare_v2(ctx->db, rest, end-rest, &next_stmt, NULL);
|
|
319
319
|
if (next_stmt) res = SQLITE_MISUSE;
|
|
320
320
|
if (res != SQLITE_OK) {
|
|
321
|
+
ctx->flags &= ~STMT_CTX_F_USE_CACHE;
|
|
321
322
|
ctx->rc = res;
|
|
322
323
|
goto done;
|
|
323
324
|
}
|
|
@@ -367,6 +368,7 @@ int exec_multi_stmt(stmt_ctx *ctx) {
|
|
|
367
368
|
if (ctx->rc == SQLITE_OK) return ctx->total_changes;
|
|
368
369
|
|
|
369
370
|
if (*(ctx->stmtptr)) sqlite3_finalize(*(ctx->stmtptr));
|
|
371
|
+
|
|
370
372
|
return raise_error(ctx);
|
|
371
373
|
}
|
|
372
374
|
|
|
@@ -403,6 +405,7 @@ void prep_single_stmt(stmt_ctx *ctx) {
|
|
|
403
405
|
if (ctx->rc == SQLITE_OK) return;
|
|
404
406
|
|
|
405
407
|
if (*(ctx->stmtptr)) sqlite3_finalize(*(ctx->stmtptr));
|
|
408
|
+
|
|
406
409
|
raise_error(ctx);
|
|
407
410
|
}
|
|
408
411
|
|
|
@@ -453,12 +456,10 @@ inline int stmt_iterate(query_ctx *ctx) {
|
|
|
453
456
|
VALUE cleanup_stmt(query_ctx *ctx) {
|
|
454
457
|
if (!ctx->stmt) goto done;
|
|
455
458
|
|
|
456
|
-
if (ctx->flags & STMT_CTX_F_USE_CACHE)
|
|
457
|
-
if (!(ctx->flags & STMT_CTX_F_CACHE_HIT))
|
|
458
|
-
rb_hash_aset(ctx->db->stmt_cache, ctx->sql, ULONG2NUM((uint64_t)(ctx->stmt)));
|
|
459
|
-
}
|
|
460
|
-
else
|
|
459
|
+
if (!(ctx->flags & STMT_CTX_F_USE_CACHE))
|
|
461
460
|
sqlite3_finalize(ctx->stmt);
|
|
461
|
+
else if (!(ctx->flags & STMT_CTX_F_CACHE_HIT))
|
|
462
|
+
rb_hash_aset(ctx->db->stmt_cache, ctx->sql, ULONG2NUM((uint64_t)(ctx->stmt)));
|
|
462
463
|
done:
|
|
463
464
|
return Qnil;
|
|
464
465
|
}
|
|
@@ -600,8 +601,6 @@ VALUE run_transform_no_identity(
|
|
|
600
601
|
static inline VALUE run_transform(
|
|
601
602
|
VALUE identity_storage, struct transform_node *node, sqlite3_stmt *stmt
|
|
602
603
|
) {
|
|
603
|
-
// fprintf(stdout, "transform_container: %p flags: %02x identity_idx: %d\n", node, node->flags, node->identity_idx);
|
|
604
|
-
// if (node->flags & TRANSFORM_F_NAME) INSPECT(" name", node->name);
|
|
605
604
|
if (node->identity_node) {
|
|
606
605
|
return run_transform_with_identity(identity_storage, node, stmt);
|
|
607
606
|
}
|
data/ext/extralite/database.c
CHANGED
|
@@ -72,9 +72,27 @@ static void Database_compact(void *ptr) {
|
|
|
72
72
|
db->progress_handler.proc = rb_gc_location(db->progress_handler.proc);
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
static int stmt_cache_iter(VALUE key, VALUE value, VALUE _param) {
|
|
76
|
+
sqlite3_stmt *stmt = (sqlite3_stmt *)NUM2ULONG(value);
|
|
77
|
+
sqlite3_finalize(stmt);
|
|
78
|
+
return ST_CONTINUE;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
static void stmt_cache_clear(sqlite3 *db, VALUE stmt_cache) {
|
|
82
|
+
if (stmt_cache == Qnil) return;
|
|
83
|
+
if (rb_hash_size_num(stmt_cache) == 0) return;
|
|
84
|
+
|
|
85
|
+
rb_hash_foreach(stmt_cache, stmt_cache_iter, Qnil);
|
|
86
|
+
rb_hash_clear(stmt_cache);
|
|
87
|
+
RB_GC_GUARD(stmt_cache);
|
|
88
|
+
}
|
|
89
|
+
|
|
75
90
|
static void Database_free(void *ptr) {
|
|
76
91
|
Database_t *db = ptr;
|
|
77
|
-
if (db->sqlite3_db)
|
|
92
|
+
if (db->sqlite3_db) {
|
|
93
|
+
stmt_cache_clear(db->sqlite3_db, db->stmt_cache);
|
|
94
|
+
sqlite3_close_v2(db->sqlite3_db);
|
|
95
|
+
}
|
|
78
96
|
free(ptr);
|
|
79
97
|
}
|
|
80
98
|
|
|
@@ -261,6 +279,7 @@ VALUE Database_close(VALUE self) {
|
|
|
261
279
|
int rc;
|
|
262
280
|
Database_t *db = self_to_database(self);
|
|
263
281
|
|
|
282
|
+
stmt_cache_clear(db->sqlite3_db, db->stmt_cache);
|
|
264
283
|
rc = sqlite3_close_v2(db->sqlite3_db);
|
|
265
284
|
if (rc) {
|
|
266
285
|
rb_raise(cError, "%s", sqlite3_errmsg(db->sqlite3_db));
|
|
@@ -573,13 +592,14 @@ VALUE Database_batch_execute(VALUE self, VALUE sql, VALUE parameters) {
|
|
|
573
592
|
if (RSTRING_LEN(sql) == 0) return Qnil;
|
|
574
593
|
|
|
575
594
|
stmt_ctx stmt_ctx;
|
|
576
|
-
make_stmt_ctx(&stmt_ctx, db, &stmt, sql,
|
|
595
|
+
make_stmt_ctx(&stmt_ctx, db, &stmt, sql, 1, NULL);
|
|
577
596
|
prep_single_stmt(&stmt_ctx);
|
|
578
597
|
// prepare_xsingle_stmt(DB_GVL_MODE(db), db->stmt_cache, db->sqlite3_db, &stmt, sql, 0, NULL);
|
|
579
598
|
query_ctx ctx = QUERY_CTX(
|
|
580
599
|
self, sql, db, stmt, parameters,
|
|
581
600
|
Qnil, QUERY_HASH, ROW_MULTI, ALL_ROWS
|
|
582
601
|
);
|
|
602
|
+
ctx.flags = stmt_ctx.flags;
|
|
583
603
|
|
|
584
604
|
return rb_ensure(SAFE(safe_batch_execute), (VALUE)&ctx, SAFE(cleanup_stmt), (VALUE)&ctx);
|
|
585
605
|
}
|
data/lib/extralite/version.rb
CHANGED
data/test/helper.rb
CHANGED
data/test/test_database.rb
CHANGED
|
@@ -2225,4 +2225,39 @@ class StmtCacheText < Minitest::Test
|
|
|
2225
2225
|
assert_equal [{ x: 42 }], rows
|
|
2226
2226
|
assert_equal({}, @db.stmt_cache)
|
|
2227
2227
|
end
|
|
2228
|
+
|
|
2229
|
+
def test_stmt_cache_close
|
|
2230
|
+
fn = Tempfile.new('extralite_test_stmt_cache_close').path
|
|
2231
|
+
|
|
2232
|
+
db = Extralite::Database.new(fn)
|
|
2233
|
+
db.query('create table t (x)')
|
|
2234
|
+
|
|
2235
|
+
db.execute <<~SQL
|
|
2236
|
+
insert into t values (42)
|
|
2237
|
+
SQL
|
|
2238
|
+
assert File.file?("#{fn}-wal"), "WAL file should exist"
|
|
2239
|
+
|
|
2240
|
+
assert_equal [{x: 42}], db.query('select * from t where x = ?', 42)
|
|
2241
|
+
|
|
2242
|
+
db.close
|
|
2243
|
+
refute File.file?("#{fn}-wal"), "WAL file should not exist after close"
|
|
2244
|
+
end
|
|
2245
|
+
|
|
2246
|
+
def test_stmt_cache_gc
|
|
2247
|
+
fn = Tempfile.new('extralite_test_stmt_cache_close').path
|
|
2248
|
+
|
|
2249
|
+
db = Extralite::Database.new(fn)
|
|
2250
|
+
db.query('create table t (x)')
|
|
2251
|
+
|
|
2252
|
+
db.execute <<~SQL
|
|
2253
|
+
insert into t values (42)
|
|
2254
|
+
SQL
|
|
2255
|
+
assert File.file?("#{fn}-wal"), "WAL file should exist"
|
|
2256
|
+
|
|
2257
|
+
assert_equal [{x: 42}], db.query('select * from t where x = ?', 42)
|
|
2258
|
+
|
|
2259
|
+
db = nil
|
|
2260
|
+
GC.start
|
|
2261
|
+
refute File.file?("#{fn}-wal"), "WAL file should not exist after GC"
|
|
2262
|
+
end
|
|
2228
2263
|
end
|
data/test/test_sequel.rb
CHANGED