extralite 1.7 → 1.10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/FUNDING.yml +1 -0
- data/CHANGELOG.md +12 -0
- data/Gemfile.lock +10 -33
- data/README.md +29 -19
- data/Rakefile +16 -7
- data/ext/extralite/extralite.c +137 -4
- data/extralite.gemspec +5 -5
- data/lib/extralite/version.rb +1 -1
- data/lib/extralite.rb +20 -0
- data/lib/sequel/adapters/extralite.rb +4 -0
- data/test/perf_ary.rb +51 -0
- data/test/{perf.rb → perf_hash.rb} +0 -0
- data/test/test_database.rb +25 -0
- metadata +13 -25
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e1dbf79f19c8e1a1b31da57db9e1b20eb32efed2a510dfd1a19df048ecdf6532
|
4
|
+
data.tar.gz: 633afbfd7042dedb38a5275d525bf9876a8cd194e6b6f95db183d78019c53816
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9987a2e1b14e9213a289d04d79a0914e6d3a843c5af94e4d57d6839f193b8294b57b280141dd4784419d9f920d8b1ee32f9a21efee56a85ff524128bc4262aed
|
7
|
+
data.tar.gz: 2b53f9dd796f37e7c901f88b5bfe2b28463c0465ff5aaf0ade160b1ecf95f0beb7b0cd56496e3c76bd4f754ef7649bf8a704ff7eb94053a7b7f1b1099cf31a5b
|
data/.github/FUNDING.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
github: ciconia
|
data/CHANGELOG.md
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,60 +1,37 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
extralite (1.
|
4
|
+
extralite (1.10)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
|
-
ast (2.4.2)
|
10
|
-
coderay (1.1.3)
|
11
9
|
docile (1.4.0)
|
12
10
|
json (2.5.1)
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
parser (3.0.1.1)
|
17
|
-
ast (~> 2.4.1)
|
18
|
-
pry (0.13.1)
|
19
|
-
coderay (~> 1.1)
|
20
|
-
method_source (~> 1.0)
|
21
|
-
rainbow (3.0.0)
|
22
|
-
rake (13.0.3)
|
23
|
-
rake-compiler (1.1.1)
|
11
|
+
minitest (5.15.0)
|
12
|
+
rake (13.0.6)
|
13
|
+
rake-compiler (1.1.6)
|
24
14
|
rake
|
25
|
-
regexp_parser (2.1.1)
|
26
|
-
rexml (3.2.5)
|
27
|
-
rubocop (0.85.1)
|
28
|
-
parallel (~> 1.10)
|
29
|
-
parser (>= 2.7.0.1)
|
30
|
-
rainbow (>= 2.2.2, < 4.0)
|
31
|
-
regexp_parser (>= 1.7)
|
32
|
-
rexml
|
33
|
-
rubocop-ast (>= 0.0.3)
|
34
|
-
ruby-progressbar (~> 1.7)
|
35
|
-
unicode-display_width (>= 1.4.0, < 2.0)
|
36
|
-
rubocop-ast (1.5.0)
|
37
|
-
parser (>= 3.0.1.1)
|
38
|
-
ruby-progressbar (1.11.0)
|
39
15
|
sequel (5.51.0)
|
40
16
|
simplecov (0.17.1)
|
41
17
|
docile (~> 1.1)
|
42
18
|
json (>= 1.8, < 3)
|
43
19
|
simplecov-html (~> 0.10.0)
|
44
20
|
simplecov-html (0.10.2)
|
45
|
-
|
21
|
+
webrick (1.7.0)
|
22
|
+
yard (0.9.27)
|
23
|
+
webrick (~> 1.7.0)
|
46
24
|
|
47
25
|
PLATFORMS
|
48
26
|
ruby
|
49
27
|
|
50
28
|
DEPENDENCIES
|
51
29
|
extralite!
|
52
|
-
minitest (= 5.
|
53
|
-
|
54
|
-
rake-compiler (= 1.1.1)
|
55
|
-
rubocop (= 0.85.1)
|
30
|
+
minitest (= 5.15.0)
|
31
|
+
rake-compiler (= 1.1.6)
|
56
32
|
sequel (= 5.51.0)
|
57
33
|
simplecov (= 0.17.1)
|
34
|
+
yard (= 0.9.27)
|
58
35
|
|
59
36
|
BUNDLED WITH
|
60
37
|
2.1.4
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Extralite - a Ruby gem for working with SQLite3 databases
|
1
|
+
# Extralite - a fast Ruby gem for working with SQLite3 databases
|
2
2
|
|
3
3
|
[![Gem Version](https://badge.fury.io/rb/extralite.svg)](http://rubygems.org/gems/extralite)
|
4
4
|
[![Modulation Test](https://github.com/digital-fabric/extralite/workflows/Tests/badge.svg)](https://github.com/digital-fabric/extralite/actions?query=workflow%3ATests)
|
@@ -6,9 +6,9 @@
|
|
6
6
|
|
7
7
|
## What is Extralite?
|
8
8
|
|
9
|
-
Extralite is
|
10
|
-
wrapper for Ruby. It provides a single class with a minimal set of methods
|
11
|
-
|
9
|
+
Extralite is a fast, extra-lightweight (less than 460 lines of C-code) SQLite3
|
10
|
+
wrapper for Ruby. It provides a single class with a minimal set of methods for
|
11
|
+
interacting with an SQLite3 database.
|
12
12
|
|
13
13
|
## Features
|
14
14
|
|
@@ -73,7 +73,7 @@ db.query('select * from foo where bar = :bar', 'bar' => 42)
|
|
73
73
|
db.query('select * from foo where bar = :bar', ':bar' => 42)
|
74
74
|
|
75
75
|
# get last insert rowid
|
76
|
-
rowid = db.
|
76
|
+
rowid = db.last_insert_rowid
|
77
77
|
|
78
78
|
# get number of rows changed in last query
|
79
79
|
number_of_rows_affected = db.changes
|
@@ -127,7 +127,7 @@ Here's a table summarizing the differences between the two gems:
|
|
127
127
|
|custom collations|yes|no|
|
128
128
|
|custom aggregate functions|yes|no|
|
129
129
|
|Multithread friendly|no|[yes](#what-about-concurrency)|
|
130
|
-
|Code size|~2650LoC|~
|
130
|
+
|Code size|~2650LoC|~530LoC|
|
131
131
|
|Performance|1x|1.5x to 12.5x (see [below](#performance))|
|
132
132
|
|
133
133
|
## What about concurrency?
|
@@ -140,23 +140,33 @@ performance:
|
|
140
140
|
|
141
141
|
## Performance
|
142
142
|
|
143
|
-
A benchmark script is
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
times faster than `sqlite3` when fetching a large number of rows. Here are the
|
148
|
-
results (using the `sqlite3` gem performance as baseline):
|
143
|
+
A benchmark script is included, creating a table of various row counts, then
|
144
|
+
fetching the entire table using either `sqlite3` or `extralite`. This benchmark
|
145
|
+
shows Extralite to be up to 12.5 times faster than `sqlite3` when fetching a
|
146
|
+
large number of rows. Here are the [results for fetching rows as hashes](https://github.com/digital-fabric/extralite/blob/main/test/perf_hash.rb):
|
149
147
|
|
150
|
-
|Row count|sqlite3-ruby
|
151
|
-
|
152
|
-
|10|
|
153
|
-
|1K|
|
154
|
-
|100K|
|
148
|
+
|Row count|sqlite3-ruby|Extralite|Advantage|
|
149
|
+
|-:|-:|-:|-:|
|
150
|
+
|10|57620 rows/s|95340 rows/s|__1.65x__|
|
151
|
+
|1K|286.8K rows/s|2106.4 rows/s|__7.35x__|
|
152
|
+
|100K|181K rows/s|2275.3K rows/s|__12.53x__|
|
153
|
+
|
154
|
+
When [fetching rows as arrays](https://github.com/digital-fabric/extralite/blob/main/test/perf_ary.rb) Extralite also significantly outperforms sqlite3-ruby:
|
155
|
+
|
156
|
+
|Row count|sqlite3-ruby|Extralite|Advantage|
|
157
|
+
|-:|-:|-:|-:|
|
158
|
+
|10|64365 rows/s|94031 rows/s|__1.46x__|
|
159
|
+
|1K|498.9K rows/s|2478.2K rows/s|__4.97x__|
|
160
|
+
|100K|441.1K rows/s|3023.4K rows/s|__6.85x__|
|
155
161
|
|
156
162
|
(If you're interested in checking this yourself, just run the script and let me
|
157
|
-
know if your results are
|
163
|
+
know if your results are better/worse.)
|
164
|
+
|
165
|
+
As those benchmarks show, Extralite is capabale of reading more than 3M
|
166
|
+
rows/second (when fetching rows as arrays), and more than 2.2M rows/second (when
|
167
|
+
fetching rows as hashes.)
|
158
168
|
|
159
169
|
## Contributing
|
160
170
|
|
161
171
|
Contributions in the form of issues, PRs or comments will be greatly
|
162
|
-
appreciated!
|
172
|
+
appreciated!
|
data/Rakefile
CHANGED
@@ -1,18 +1,27 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
require 'rake/clean'
|
5
5
|
|
6
|
-
require
|
7
|
-
Rake::ExtensionTask.new(
|
8
|
-
ext.ext_dir =
|
6
|
+
require 'rake/extensiontask'
|
7
|
+
Rake::ExtensionTask.new('extralite_ext') do |ext|
|
8
|
+
ext.ext_dir = 'ext/extralite'
|
9
9
|
end
|
10
10
|
|
11
11
|
task :recompile => [:clean, :compile]
|
12
12
|
|
13
|
-
task :default => [:compile, :test]
|
13
|
+
task :default => [:compile, :doc, :test]
|
14
|
+
task :doc => :yard
|
14
15
|
task :test do
|
15
16
|
exec 'ruby test/run.rb'
|
16
17
|
end
|
17
18
|
|
18
|
-
CLEAN.include
|
19
|
+
CLEAN.include '**/*.o', '**/*.so', '**/*.so.*', '**/*.a', '**/*.bundle', '**/*.jar', 'pkg', 'tmp'
|
20
|
+
|
21
|
+
require 'yard'
|
22
|
+
YARD_FILES = FileList['ext/extralite/extralite.c', 'lib/extralite.rb', 'lib/sequel/adapters/extralite.rb']
|
23
|
+
|
24
|
+
YARD::Rake::YardocTask.new do |t|
|
25
|
+
t.files = YARD_FILES
|
26
|
+
t.options = %w(-o doc --readme README.md)
|
27
|
+
end
|
data/ext/extralite/extralite.c
CHANGED
@@ -51,6 +51,10 @@ static VALUE Database_allocate(VALUE klass) {
|
|
51
51
|
} \
|
52
52
|
}
|
53
53
|
|
54
|
+
/* call-seq: initialize(path)
|
55
|
+
*
|
56
|
+
* Initializes a new SQLite database with the given path.
|
57
|
+
*/
|
54
58
|
|
55
59
|
VALUE Database_initialize(VALUE self, VALUE path) {
|
56
60
|
int rc;
|
@@ -72,6 +76,10 @@ VALUE Database_initialize(VALUE self, VALUE path) {
|
|
72
76
|
return Qnil;
|
73
77
|
}
|
74
78
|
|
79
|
+
/* call-seq: close
|
80
|
+
*
|
81
|
+
* Closes the database.
|
82
|
+
*/
|
75
83
|
VALUE Database_close(VALUE self) {
|
76
84
|
int rc;
|
77
85
|
Database_t *db;
|
@@ -86,6 +94,10 @@ VALUE Database_close(VALUE self) {
|
|
86
94
|
return self;
|
87
95
|
}
|
88
96
|
|
97
|
+
/* call-seq: closed?
|
98
|
+
*
|
99
|
+
* Returns true if the database is closed.
|
100
|
+
*/
|
89
101
|
VALUE Database_closed_p(VALUE self) {
|
90
102
|
Database_t *db;
|
91
103
|
GetDatabase(self, db);
|
@@ -104,7 +116,7 @@ inline VALUE get_column_value(sqlite3_stmt *stmt, int col, int type) {
|
|
104
116
|
case SQLITE_TEXT:
|
105
117
|
return rb_str_new_cstr((char *)sqlite3_column_text(stmt, col));
|
106
118
|
case SQLITE_BLOB:
|
107
|
-
|
119
|
+
return rb_str_new((const char *)sqlite3_column_blob(stmt, col), (long)sqlite3_column_bytes(stmt, col));
|
108
120
|
default:
|
109
121
|
rb_raise(cError, "Unknown column type: %d", type);
|
110
122
|
}
|
@@ -124,16 +136,16 @@ static inline void bind_hash_parameter_values(sqlite3_stmt *stmt, VALUE hash) {
|
|
124
136
|
switch (TYPE(k)) {
|
125
137
|
case T_FIXNUM:
|
126
138
|
bind_parameter_value(stmt, NUM2INT(k), v);
|
127
|
-
|
139
|
+
break;
|
128
140
|
case T_SYMBOL:
|
129
141
|
k = rb_funcall(k, ID_TO_S, 0);
|
130
142
|
case T_STRING:
|
131
143
|
if(RSTRING_PTR(k)[0] != ':') k = rb_str_plus(rb_str_new2(":"), k);
|
132
144
|
int pos = sqlite3_bind_parameter_index(stmt, StringValuePtr(k));
|
133
145
|
bind_parameter_value(stmt, pos, v);
|
134
|
-
|
146
|
+
break;
|
135
147
|
default:
|
136
|
-
|
148
|
+
rb_raise(cError, "Cannot bind hash key value idx %d", i);
|
137
149
|
}
|
138
150
|
}
|
139
151
|
RB_GC_GUARD(keys);
|
@@ -342,6 +354,29 @@ VALUE safe_query_hash(VALUE arg) {
|
|
342
354
|
return result;
|
343
355
|
}
|
344
356
|
|
357
|
+
/* call-seq:
|
358
|
+
* query(sql, *parameters, &block)
|
359
|
+
* query_hash(sql, *parameters, &block)
|
360
|
+
*
|
361
|
+
* Runs a query returning rows as hashes (with symbol keys). If a block is
|
362
|
+
* given, it will be called for each row. Otherwise, an array containing all
|
363
|
+
* rows is returned.
|
364
|
+
*
|
365
|
+
* Query parameters to be bound to placeholders in the query can be specified as
|
366
|
+
* a list of values or as a hash mapping parameter names to values. When
|
367
|
+
* parameters are given as a least, the query should specify parameters using
|
368
|
+
* `?`:
|
369
|
+
*
|
370
|
+
* db.query('select * from foo where x = ?', 42)
|
371
|
+
*
|
372
|
+
* Named placeholders are specified using `:`. The placeholder values are
|
373
|
+
* specified using a hash, where keys are either strings are symbols. String
|
374
|
+
* keys can include or omit the `:` prefix. The following are equivalent:
|
375
|
+
*
|
376
|
+
* db.query('select * from foo where x = :bar', bar: 42)
|
377
|
+
* db.query('select * from foo where x = :bar', 'bar' => 42)
|
378
|
+
* db.query('select * from foo where x = :bar', ':bar' => 42)
|
379
|
+
*/
|
345
380
|
VALUE Database_query_hash(int argc, VALUE *argv, VALUE self) {
|
346
381
|
query_ctx ctx = { self, argc, argv, 0 };
|
347
382
|
return rb_ensure(safe_query_hash, (VALUE)&ctx, cleanup_stmt, (VALUE)&ctx);
|
@@ -376,6 +411,26 @@ VALUE safe_query_ary(VALUE arg) {
|
|
376
411
|
return result;
|
377
412
|
}
|
378
413
|
|
414
|
+
/* call-seq: query_ary(sql, *parameters, &block)
|
415
|
+
*
|
416
|
+
* Runs a query returning rows as arrays. If a block is given, it will be called
|
417
|
+
* for each row. Otherwise, an array containing all rows is returned.
|
418
|
+
*
|
419
|
+
* Query parameters to be bound to placeholders in the query can be specified as
|
420
|
+
* a list of values or as a hash mapping parameter names to values. When
|
421
|
+
* parameters are given as a least, the query should specify parameters using
|
422
|
+
* `?`:
|
423
|
+
*
|
424
|
+
* db.query_ary('select * from foo where x = ?', 42)
|
425
|
+
*
|
426
|
+
* Named placeholders are specified using `:`. The placeholder values are
|
427
|
+
* specified using a hash, where keys are either strings are symbols. String
|
428
|
+
* keys can include or omit the `:` prefix. The following are equivalent:
|
429
|
+
*
|
430
|
+
* db.query_ary('select * from foo where x = :bar', bar: 42)
|
431
|
+
* db.query_ary('select * from foo where x = :bar', 'bar' => 42)
|
432
|
+
* db.query_ary('select * from foo where x = :bar', ':bar' => 42)
|
433
|
+
*/
|
379
434
|
VALUE Database_query_ary(int argc, VALUE *argv, VALUE self) {
|
380
435
|
query_ctx ctx = { self, argc, argv, 0 };
|
381
436
|
return rb_ensure(safe_query_ary, (VALUE)&ctx, cleanup_stmt, (VALUE)&ctx);
|
@@ -405,6 +460,25 @@ VALUE safe_query_single_row(VALUE arg) {
|
|
405
460
|
return row;
|
406
461
|
}
|
407
462
|
|
463
|
+
/* call-seq: query_single_row(sql, *parameters)
|
464
|
+
*
|
465
|
+
* Runs a query returning a single row as a hash.
|
466
|
+
*
|
467
|
+
* Query parameters to be bound to placeholders in the query can be specified as
|
468
|
+
* a list of values or as a hash mapping parameter names to values. When
|
469
|
+
* parameters are given as a least, the query should specify parameters using
|
470
|
+
* `?`:
|
471
|
+
*
|
472
|
+
* db.query_single_row('select * from foo where x = ?', 42)
|
473
|
+
*
|
474
|
+
* Named placeholders are specified using `:`. The placeholder values are
|
475
|
+
* specified using a hash, where keys are either strings are symbols. String
|
476
|
+
* keys can include or omit the `:` prefix. The following are equivalent:
|
477
|
+
*
|
478
|
+
* db.query_single_row('select * from foo where x = :bar', bar: 42)
|
479
|
+
* db.query_single_row('select * from foo where x = :bar', 'bar' => 42)
|
480
|
+
* db.query_single_row('select * from foo where x = :bar', ':bar' => 42)
|
481
|
+
*/
|
408
482
|
VALUE Database_query_single_row(int argc, VALUE *argv, VALUE self) {
|
409
483
|
query_ctx ctx = { self, argc, argv, 0 };
|
410
484
|
return rb_ensure(safe_query_single_row, (VALUE)&ctx, cleanup_stmt, (VALUE)&ctx);
|
@@ -442,6 +516,26 @@ VALUE safe_query_single_column(VALUE arg) {
|
|
442
516
|
return result;
|
443
517
|
}
|
444
518
|
|
519
|
+
/* call-seq: query_single_column(sql, *parameters, &block)
|
520
|
+
*
|
521
|
+
* Runs a query returning single column values. If a block is given, it will be called
|
522
|
+
* for each value. Otherwise, an array containing all values is returned.
|
523
|
+
*
|
524
|
+
* Query parameters to be bound to placeholders in the query can be specified as
|
525
|
+
* a list of values or as a hash mapping parameter names to values. When
|
526
|
+
* parameters are given as a least, the query should specify parameters using
|
527
|
+
* `?`:
|
528
|
+
*
|
529
|
+
* db.query_single_column('select x from foo where x = ?', 42)
|
530
|
+
*
|
531
|
+
* Named placeholders are specified using `:`. The placeholder values are
|
532
|
+
* specified using a hash, where keys are either strings are symbols. String
|
533
|
+
* keys can include or omit the `:` prefix. The following are equivalent:
|
534
|
+
*
|
535
|
+
* db.query_single_column('select x from foo where x = :bar', bar: 42)
|
536
|
+
* db.query_single_column('select x from foo where x = :bar', 'bar' => 42)
|
537
|
+
* db.query_single_column('select x from foo where x = :bar', ':bar' => 42)
|
538
|
+
*/
|
445
539
|
VALUE Database_query_single_column(int argc, VALUE *argv, VALUE self) {
|
446
540
|
query_ctx ctx = { self, argc, argv, 0 };
|
447
541
|
return rb_ensure(safe_query_single_column, (VALUE)&ctx, cleanup_stmt, (VALUE)&ctx);
|
@@ -470,11 +564,34 @@ VALUE safe_query_single_value(VALUE arg) {
|
|
470
564
|
return value;
|
471
565
|
}
|
472
566
|
|
567
|
+
/* call-seq: query_single_value(sql, *parameters)
|
568
|
+
*
|
569
|
+
* Runs a query returning a single value from the first row.
|
570
|
+
*
|
571
|
+
* Query parameters to be bound to placeholders in the query can be specified as
|
572
|
+
* a list of values or as a hash mapping parameter names to values. When
|
573
|
+
* parameters are given as a least, the query should specify parameters using
|
574
|
+
* `?`:
|
575
|
+
*
|
576
|
+
* db.query_single_value('select x from foo where x = ?', 42)
|
577
|
+
*
|
578
|
+
* Named placeholders are specified using `:`. The placeholder values are
|
579
|
+
* specified using a hash, where keys are either strings are symbols. String
|
580
|
+
* keys can include or omit the `:` prefix. The following are equivalent:
|
581
|
+
*
|
582
|
+
* db.query_single_value('select x from foo where x = :bar', bar: 42)
|
583
|
+
* db.query_single_value('select x from foo where x = :bar', 'bar' => 42)
|
584
|
+
* db.query_single_value('select x from foo where x = :bar', ':bar' => 42)
|
585
|
+
*/
|
473
586
|
VALUE Database_query_single_value(int argc, VALUE *argv, VALUE self) {
|
474
587
|
query_ctx ctx = { self, argc, argv, 0 };
|
475
588
|
return rb_ensure(safe_query_single_value, (VALUE)&ctx, cleanup_stmt, (VALUE)&ctx);
|
476
589
|
}
|
477
590
|
|
591
|
+
/* call-seq: last_insert_rowid
|
592
|
+
*
|
593
|
+
* Returns the rowid of the last inserted row.
|
594
|
+
*/
|
478
595
|
VALUE Database_last_insert_rowid(VALUE self) {
|
479
596
|
Database_t *db;
|
480
597
|
GetOpenDatabase(self, db);
|
@@ -482,6 +599,10 @@ VALUE Database_last_insert_rowid(VALUE self) {
|
|
482
599
|
return INT2NUM(sqlite3_last_insert_rowid(db->sqlite3_db));
|
483
600
|
}
|
484
601
|
|
602
|
+
/* call-seq: changes
|
603
|
+
*
|
604
|
+
* Returns the number of changes made to the database by the last operation.
|
605
|
+
*/
|
485
606
|
VALUE Database_changes(VALUE self) {
|
486
607
|
Database_t *db;
|
487
608
|
GetOpenDatabase(self, db);
|
@@ -489,6 +610,10 @@ VALUE Database_changes(VALUE self) {
|
|
489
610
|
return INT2NUM(sqlite3_changes(db->sqlite3_db));
|
490
611
|
}
|
491
612
|
|
613
|
+
/* call-seq: filename
|
614
|
+
*
|
615
|
+
* Returns the database filename.
|
616
|
+
*/
|
492
617
|
VALUE Database_filename(int argc, VALUE *argv, VALUE self) {
|
493
618
|
const char *db_name;
|
494
619
|
const char *filename;
|
@@ -501,6 +626,10 @@ VALUE Database_filename(int argc, VALUE *argv, VALUE self) {
|
|
501
626
|
return filename ? rb_str_new_cstr(filename) : Qnil;
|
502
627
|
}
|
503
628
|
|
629
|
+
/* call-seq: transaction_active?
|
630
|
+
*
|
631
|
+
* Returns true if a transaction is currently in progress.
|
632
|
+
*/
|
504
633
|
VALUE Database_transaction_active_p(VALUE self) {
|
505
634
|
Database_t *db;
|
506
635
|
GetOpenDatabase(self, db);
|
@@ -508,6 +637,10 @@ VALUE Database_transaction_active_p(VALUE self) {
|
|
508
637
|
return sqlite3_get_autocommit(db->sqlite3_db) ? Qfalse : Qtrue;
|
509
638
|
}
|
510
639
|
|
640
|
+
/* call-seq: load_extension(path)
|
641
|
+
*
|
642
|
+
* Loads an extension with the given path.
|
643
|
+
*/
|
511
644
|
VALUE Database_load_extension(VALUE self, VALUE path) {
|
512
645
|
Database_t *db;
|
513
646
|
GetOpenDatabase(self, db);
|
data/extralite.gemspec
CHANGED
@@ -11,7 +11,7 @@ Gem::Specification.new do |s|
|
|
11
11
|
s.homepage = 'https://github.com/digital-fabric/extralite'
|
12
12
|
s.metadata = {
|
13
13
|
"source_code_uri" => "https://github.com/digital-fabric/extralite",
|
14
|
-
"documentation_uri" => "https://
|
14
|
+
"documentation_uri" => "https://www.rubydoc.info/gems/extralite",
|
15
15
|
"homepage_uri" => "https://github.com/digital-fabric/extralite",
|
16
16
|
"changelog_uri" => "https://github.com/digital-fabric/extralite/blob/master/CHANGELOG.md"
|
17
17
|
}
|
@@ -21,10 +21,10 @@ Gem::Specification.new do |s|
|
|
21
21
|
s.require_paths = ["lib"]
|
22
22
|
s.required_ruby_version = '>= 2.6'
|
23
23
|
|
24
|
-
s.add_development_dependency 'rake-compiler', '1.1.
|
25
|
-
s.add_development_dependency 'minitest', '5.
|
24
|
+
s.add_development_dependency 'rake-compiler', '1.1.6'
|
25
|
+
s.add_development_dependency 'minitest', '5.15.0'
|
26
26
|
s.add_development_dependency 'simplecov', '0.17.1'
|
27
|
-
s.add_development_dependency '
|
28
|
-
|
27
|
+
s.add_development_dependency 'yard', '0.9.27'
|
28
|
+
|
29
29
|
s.add_development_dependency 'sequel', '5.51.0'
|
30
30
|
end
|
data/lib/extralite/version.rb
CHANGED
data/lib/extralite.rb
CHANGED
@@ -1 +1,21 @@
|
|
1
1
|
require_relative './extralite_ext'
|
2
|
+
|
3
|
+
# Extralite is a Ruby gem for working with SQLite databases
|
4
|
+
module Extralite
|
5
|
+
# A base class for Extralite exceptions
|
6
|
+
class Error < RuntimeError
|
7
|
+
end
|
8
|
+
|
9
|
+
# An exception representing an SQL error emitted by SQLite
|
10
|
+
class SQLError < Error
|
11
|
+
end
|
12
|
+
|
13
|
+
# An exception raised when an SQLite database is busy (locked by another
|
14
|
+
# thread or process)
|
15
|
+
class BusyError < Error
|
16
|
+
end
|
17
|
+
|
18
|
+
# An SQLite database
|
19
|
+
class Database
|
20
|
+
end
|
21
|
+
end
|
data/test/perf_ary.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/inline'
|
4
|
+
|
5
|
+
gemfile do
|
6
|
+
source 'https://rubygems.org'
|
7
|
+
gem 'sqlite3'
|
8
|
+
gem 'extralite', path: '..'
|
9
|
+
gem 'benchmark-ips'
|
10
|
+
end
|
11
|
+
|
12
|
+
require 'benchmark/ips'
|
13
|
+
require 'fileutils'
|
14
|
+
|
15
|
+
DB_PATH = '/tmp/extralite_sqlite3_perf.db'
|
16
|
+
|
17
|
+
def prepare_database(count)
|
18
|
+
FileUtils.rm(DB_PATH) rescue nil
|
19
|
+
db = Extralite::Database.new(DB_PATH)
|
20
|
+
db.query('create table foo ( a integer primary key, b text )')
|
21
|
+
db.query('begin')
|
22
|
+
count.times { db.query('insert into foo (b) values (?)', "hello#{rand(1000)}" )}
|
23
|
+
db.query('commit')
|
24
|
+
end
|
25
|
+
|
26
|
+
def sqlite3_run(count)
|
27
|
+
db = SQLite3::Database.new(DB_PATH)
|
28
|
+
results = db.execute('select * from foo')
|
29
|
+
raise unless results.size == count
|
30
|
+
end
|
31
|
+
|
32
|
+
def extralite_run(count)
|
33
|
+
db = Extralite::Database.new(DB_PATH)
|
34
|
+
results = db.query_ary('select * from foo')
|
35
|
+
raise unless results.size == count
|
36
|
+
end
|
37
|
+
|
38
|
+
[10, 1000, 100000].each do |c|
|
39
|
+
puts; puts; puts "Record count: #{c}"
|
40
|
+
|
41
|
+
prepare_database(c)
|
42
|
+
|
43
|
+
Benchmark.ips do |x|
|
44
|
+
x.config(:time => 3, :warmup => 1)
|
45
|
+
|
46
|
+
x.report("sqlite3") { sqlite3_run(c) }
|
47
|
+
x.report("extralite") { extralite_run(c) }
|
48
|
+
|
49
|
+
x.compare!
|
50
|
+
end
|
51
|
+
end
|
File without changes
|
data/test/test_database.rb
CHANGED
@@ -138,6 +138,31 @@ end
|
|
138
138
|
r = @db.query('select x, y, z from t where z = :bazzz', ':bazzz' => 6)
|
139
139
|
assert_equal [{ x: 4, y: 5, z: 6 }], r
|
140
140
|
end
|
141
|
+
|
142
|
+
def test_parameter_binding_with_index_key
|
143
|
+
r = @db.query('select x, y, z from t where z = ?', 1 => 3)
|
144
|
+
assert_equal [{ x: 1, y: 2, z: 3 }], r
|
145
|
+
|
146
|
+
r = @db.query('select x, y, z from t where x = ?2', 1 => 42, 2 => 4)
|
147
|
+
assert_equal [{ x: 4, y: 5, z: 6 }], r
|
148
|
+
end
|
149
|
+
|
150
|
+
def test_value_casting
|
151
|
+
r = @db.query_single_value("select 'abc'")
|
152
|
+
assert_equal 'abc', r
|
153
|
+
|
154
|
+
r = @db.query_single_value('select 123')
|
155
|
+
assert_equal 123, r
|
156
|
+
|
157
|
+
r = @db.query_single_value('select 12.34')
|
158
|
+
assert_equal 12.34, r
|
159
|
+
|
160
|
+
r = @db.query_single_value('select zeroblob(4)')
|
161
|
+
assert_equal "\x00\x00\x00\x00", r
|
162
|
+
|
163
|
+
r = @db.query_single_value('select null')
|
164
|
+
assert_nil r
|
165
|
+
end
|
141
166
|
end
|
142
167
|
|
143
168
|
class ScenarioTest < MiniTest::Test
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: extralite
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '1.
|
4
|
+
version: '1.10'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sharon Rosner
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-12-
|
11
|
+
date: 2021-12-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake-compiler
|
@@ -16,28 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 1.1.
|
19
|
+
version: 1.1.6
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 1.1.
|
26
|
+
version: 1.1.6
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: minitest
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - '='
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 5.
|
33
|
+
version: 5.15.0
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - '='
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 5.
|
40
|
+
version: 5.15.0
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: simplecov
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -53,33 +53,19 @@ dependencies:
|
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: 0.17.1
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: yard
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - '='
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: 0.
|
61
|
+
version: 0.9.27
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - '='
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: 0.
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: pry
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - '='
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: 0.13.1
|
76
|
-
type: :development
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - '='
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: 0.13.1
|
68
|
+
version: 0.9.27
|
83
69
|
- !ruby/object:Gem::Dependency
|
84
70
|
name: sequel
|
85
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -102,6 +88,7 @@ extensions:
|
|
102
88
|
extra_rdoc_files:
|
103
89
|
- README.md
|
104
90
|
files:
|
91
|
+
- ".github/FUNDING.yml"
|
105
92
|
- ".github/workflows/test.yml"
|
106
93
|
- ".gitignore"
|
107
94
|
- CHANGELOG.md
|
@@ -119,7 +106,8 @@ files:
|
|
119
106
|
- lib/extralite/version.rb
|
120
107
|
- lib/sequel/adapters/extralite.rb
|
121
108
|
- test/helper.rb
|
122
|
-
- test/
|
109
|
+
- test/perf_ary.rb
|
110
|
+
- test/perf_hash.rb
|
123
111
|
- test/run.rb
|
124
112
|
- test/test_database.rb
|
125
113
|
- test/test_sequel.rb
|
@@ -128,7 +116,7 @@ licenses:
|
|
128
116
|
- MIT
|
129
117
|
metadata:
|
130
118
|
source_code_uri: https://github.com/digital-fabric/extralite
|
131
|
-
documentation_uri: https://
|
119
|
+
documentation_uri: https://www.rubydoc.info/gems/extralite
|
132
120
|
homepage_uri: https://github.com/digital-fabric/extralite
|
133
121
|
changelog_uri: https://github.com/digital-fabric/extralite/blob/master/CHANGELOG.md
|
134
122
|
post_install_message:
|