extralite 2.15 → 3.0.0
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/.github/workflows/test-bundle.yml +1 -1
- data/.github/workflows/test.yml +1 -1
- data/CHANGELOG.md +10 -0
- data/README.md +106 -42
- data/TODO.md +2 -16
- data/examples/transform.rb +61 -0
- data/ext/extralite/changeset.c +11 -11
- data/ext/extralite/common.c +234 -22
- data/ext/extralite/database.c +157 -100
- data/ext/extralite/extralite.h +52 -6
- data/ext/extralite/extralite_ext.c +2 -0
- data/ext/extralite/query.c +67 -41
- data/ext/extralite/transform.c +420 -0
- data/gemspec.rb +1 -1
- data/lib/extralite/version.rb +1 -1
- data/lib/extralite.rb +102 -1
- data/test/perf_array.rb +1 -1
- data/test/perf_hash.rb +1 -1
- data/test/perf_hash_prepared.rb +2 -2
- data/test/perf_splat.rb +1 -1
- data/test/perf_transform.rb +58 -0
- data/test/test_database.rb +37 -10
- data/test/test_query.rb +11 -15
- data/test/test_transform.rb +817 -0
- metadata +6 -2
data/ext/extralite/database.c
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
#include <stdlib.h>
|
|
3
3
|
#include "extralite.h"
|
|
4
4
|
|
|
5
|
+
/*
|
|
6
|
+
* Document-class: Extralite::Database
|
|
7
|
+
*
|
|
8
|
+
* This class represents an SQLite database connection, and provides various
|
|
9
|
+
* methods for interacting with the database.
|
|
10
|
+
*/
|
|
11
|
+
|
|
5
12
|
VALUE cDatabase;
|
|
6
13
|
VALUE cBlob;
|
|
7
14
|
VALUE cError;
|
|
@@ -16,7 +23,7 @@ ID ID_call;
|
|
|
16
23
|
ID ID_each;
|
|
17
24
|
ID ID_keys;
|
|
18
25
|
ID ID_new;
|
|
19
|
-
ID
|
|
26
|
+
ID ID_parse;
|
|
20
27
|
ID ID_strip;
|
|
21
28
|
ID ID_to_s;
|
|
22
29
|
ID ID_track;
|
|
@@ -24,11 +31,11 @@ ID ID_track;
|
|
|
24
31
|
VALUE SYM_at_least_once;
|
|
25
32
|
VALUE SYM_full;
|
|
26
33
|
VALUE SYM_gvl_release_threshold;
|
|
34
|
+
VALUE SYM_legacy;
|
|
27
35
|
VALUE SYM_once;
|
|
28
36
|
VALUE SYM_none;
|
|
29
37
|
VALUE SYM_normal;
|
|
30
38
|
VALUE SYM_passive;
|
|
31
|
-
VALUE SYM_pragma;
|
|
32
39
|
VALUE SYM_read_only;
|
|
33
40
|
VALUE SYM_restart;
|
|
34
41
|
VALUE SYM_truncate;
|
|
@@ -120,26 +127,26 @@ default_flags:
|
|
|
120
127
|
}
|
|
121
128
|
|
|
122
129
|
void Database_apply_opts(VALUE self, Database_t *db, VALUE opts) {
|
|
123
|
-
|
|
130
|
+
if (NIL_P(opts)) goto modern_pragmas;
|
|
124
131
|
|
|
125
132
|
// :gvl_release_threshold
|
|
126
|
-
value = rb_hash_aref(opts, SYM_gvl_release_threshold);
|
|
133
|
+
VALUE value = rb_hash_aref(opts, SYM_gvl_release_threshold);
|
|
127
134
|
if (!NIL_P(value)) db->gvl_release_threshold = NUM2INT(value);
|
|
128
135
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
// :
|
|
134
|
-
|
|
135
|
-
if (
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
136
|
+
value = rb_hash_aref(opts, SYM_legacy);
|
|
137
|
+
if (RTEST(value)) return;
|
|
138
|
+
|
|
139
|
+
modern_pragmas:
|
|
140
|
+
// :modern pragmas
|
|
141
|
+
int rc = sqlite3_exec(db->sqlite3_db, "PRAGMA journal_mode=wal", NULL, NULL, NULL);
|
|
142
|
+
if (rc != SQLITE_OK)
|
|
143
|
+
rb_raise(cError, "Failed to set WAL journaling mode: %s", sqlite3_errstr(rc));
|
|
144
|
+
rc = sqlite3_exec(db->sqlite3_db, "PRAGMA synchronous=1", NULL, NULL, NULL);
|
|
145
|
+
if (rc != SQLITE_OK)
|
|
146
|
+
rb_raise(cError, "Failed to set synchronous mode: %s", sqlite3_errstr(rc));
|
|
147
|
+
rc = sqlite3_exec(db->sqlite3_db, "PRAGMA foreign_keys=1", NULL, NULL, NULL);
|
|
148
|
+
if (rc != SQLITE_OK)
|
|
149
|
+
rb_raise(cError, "Failed to set foreign keys mode: %s", sqlite3_errstr(rc));
|
|
143
150
|
}
|
|
144
151
|
|
|
145
152
|
int Database_progress_handler(void *ptr) {
|
|
@@ -166,16 +173,16 @@ int Database_busy_handler(void *ptr, int v) {
|
|
|
166
173
|
*
|
|
167
174
|
* - `:gvl_release_threshold` (`Integer`): sets the GVL release threshold (see
|
|
168
175
|
* `#gvl_release_threshold=`).
|
|
169
|
-
* - `:pragma` (`Hash`): one or more pragmas to set upon opening the database.
|
|
170
176
|
* - `:read_only` (`true`/`false`): opens the database in read-only mode if true.
|
|
171
|
-
* - `:
|
|
172
|
-
*
|
|
173
|
-
*
|
|
177
|
+
* - `:legacy` (`true`/`false`): By default the database is set up for
|
|
178
|
+
* concurrent access with [WAL journaling
|
|
179
|
+
* mode](https://www.sqlite.org/wal.html). To prevent Extralite from setting up
|
|
180
|
+
* WAL journaling, set this option to true.
|
|
174
181
|
*
|
|
175
182
|
* @overload initialize(path)
|
|
176
183
|
* @param path [String] file path (or ':memory:' for memory database)
|
|
177
184
|
* @return [void]
|
|
178
|
-
* @overload initialize(path, gvl_release_threshold: , on_progress: , read_only: ,
|
|
185
|
+
* @overload initialize(path, gvl_release_threshold: , on_progress: , read_only: , legacy: )
|
|
179
186
|
* @param path [String] file path (or ':memory:' for memory database)
|
|
180
187
|
* @param options [Hash] options for opening the database
|
|
181
188
|
* @return [void]
|
|
@@ -203,11 +210,9 @@ VALUE Database_initialize(int argc, VALUE *argv, VALUE self) {
|
|
|
203
210
|
}
|
|
204
211
|
|
|
205
212
|
#ifdef HAVE_SQLITE3_ENABLE_LOAD_EXTENSION
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
rb_raise(cError, "%s", sqlite3_errmsg(db->sqlite3_db));
|
|
210
|
-
}
|
|
213
|
+
// Allow loading extensions only using the C interface, i.e. Database#load_extension
|
|
214
|
+
// see: https://www.sqlite.org/c3ref/c_dbconfig_defensive.html#sqlitedbconfigenableloadextension
|
|
215
|
+
sqlite3_db_config(db->sqlite3_db ,SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, 1, NULL);
|
|
211
216
|
#endif
|
|
212
217
|
|
|
213
218
|
db->trace_proc = Qnil;
|
|
@@ -223,7 +228,7 @@ VALUE Database_initialize(int argc, VALUE *argv, VALUE self) {
|
|
|
223
228
|
sqlite3_busy_handler(db->sqlite3_db, &Database_busy_handler, db);
|
|
224
229
|
}
|
|
225
230
|
|
|
226
|
-
|
|
231
|
+
Database_apply_opts(self, db, opts);
|
|
227
232
|
return Qnil;
|
|
228
233
|
}
|
|
229
234
|
|
|
@@ -238,7 +243,7 @@ VALUE Database_read_only_p(VALUE self) {
|
|
|
238
243
|
}
|
|
239
244
|
|
|
240
245
|
/* Closes the database.
|
|
241
|
-
*
|
|
246
|
+
*
|
|
242
247
|
* @return [Extralite::Database] database
|
|
243
248
|
*/
|
|
244
249
|
VALUE Database_close(VALUE self) {
|
|
@@ -276,9 +281,9 @@ static inline VALUE Database_perform_query(int argc, VALUE *argv, VALUE self, VA
|
|
|
276
281
|
VALUE sql = Qnil;
|
|
277
282
|
VALUE transform = Qnil;
|
|
278
283
|
// transform mode is set and the first parameter is not a string, so we expect
|
|
279
|
-
// a transform
|
|
284
|
+
// a transform.,
|
|
280
285
|
int got_transform = (TYPE(argv[0]) != T_STRING);
|
|
281
|
-
|
|
286
|
+
|
|
282
287
|
// extract query from args
|
|
283
288
|
rb_check_arity(argc, got_transform ? 2 : 1, UNLIMITED_ARGUMENTS);
|
|
284
289
|
|
|
@@ -329,7 +334,7 @@ static inline VALUE Database_perform_query(int argc, VALUE *argv, VALUE self, VA
|
|
|
329
334
|
* specified using keyword arguments:
|
|
330
335
|
*
|
|
331
336
|
* db.query('select * from foo where x = :bar', bar: 42)
|
|
332
|
-
*
|
|
337
|
+
*
|
|
333
338
|
* @overload query(sql, ...)
|
|
334
339
|
* @param sql [String] SQL statement
|
|
335
340
|
* @return [Array<Hash>, Integer] rows or total changes
|
|
@@ -339,7 +344,11 @@ static inline VALUE Database_perform_query(int argc, VALUE *argv, VALUE self, VA
|
|
|
339
344
|
* @return [Array<Hash>, Integer] rows or total changes
|
|
340
345
|
*/
|
|
341
346
|
VALUE Database_query(int argc, VALUE *argv, VALUE self) {
|
|
342
|
-
|
|
347
|
+
int got_transform = (argc > 1) && (TYPE(argv[0]) != T_STRING);
|
|
348
|
+
if (got_transform && rb_obj_is_instance_of(argv[0], cTransform))
|
|
349
|
+
return Database_perform_query(argc, argv, self, safe_query_transform, QUERY_HASH);
|
|
350
|
+
else
|
|
351
|
+
return Database_perform_query(argc, argv, self, safe_query_hash, QUERY_HASH);
|
|
343
352
|
}
|
|
344
353
|
|
|
345
354
|
/* Runs a query and transforms rows through the given transform poc. Each row is
|
|
@@ -382,7 +391,7 @@ VALUE Database_query_splat(int argc, VALUE *argv, VALUE self) {
|
|
|
382
391
|
* db.query_array('select * from foo where x = :bar', bar: 42)
|
|
383
392
|
* db.query_array('select * from foo where x = :bar', 'bar' => 42)
|
|
384
393
|
* db.query_array('select * from foo where x = :bar', ':bar' => 42)
|
|
385
|
-
*
|
|
394
|
+
*
|
|
386
395
|
* @overload query_array(sql, ...)
|
|
387
396
|
* @param sql [String] SQL statement
|
|
388
397
|
* @return [Array<Array>, Integer] rows or total changes
|
|
@@ -418,7 +427,11 @@ VALUE Database_query_array(int argc, VALUE *argv, VALUE self) {
|
|
|
418
427
|
* @return [Array, any] row
|
|
419
428
|
*/
|
|
420
429
|
VALUE Database_query_single(int argc, VALUE *argv, VALUE self) {
|
|
421
|
-
|
|
430
|
+
int got_transform = (argc > 1) && (TYPE(argv[0]) != T_STRING);
|
|
431
|
+
if (got_transform && rb_obj_is_instance_of(argv[0], cTransform))
|
|
432
|
+
return Database_perform_query(argc, argv, self, safe_query_single_row_transform, QUERY_HASH);
|
|
433
|
+
else
|
|
434
|
+
return Database_perform_query(argc, argv, self, safe_query_single_row_hash, QUERY_HASH);
|
|
422
435
|
}
|
|
423
436
|
|
|
424
437
|
/* Runs a query returning a single row as an array or a single value.
|
|
@@ -434,7 +447,7 @@ VALUE Database_query_single(int argc, VALUE *argv, VALUE self) {
|
|
|
434
447
|
* specified using keyword arguments:
|
|
435
448
|
*
|
|
436
449
|
* db.query_single_splat('select * from foo where x = :bar', bar: 42)
|
|
437
|
-
*
|
|
450
|
+
*
|
|
438
451
|
* @overload query_single_splat(sql, ...) -> row
|
|
439
452
|
* @param sql [String] SQL statement
|
|
440
453
|
* @return [Array, any] row
|
|
@@ -460,7 +473,7 @@ VALUE Database_query_single_splat(int argc, VALUE *argv, VALUE self) {
|
|
|
460
473
|
* specified using keyword arguments:
|
|
461
474
|
*
|
|
462
475
|
* db.query_single_array('select * from foo where x = :bar', bar: 42)
|
|
463
|
-
*
|
|
476
|
+
*
|
|
464
477
|
* @overload query_single_array(sql, ...) -> row
|
|
465
478
|
* @param sql [String] SQL statement
|
|
466
479
|
* @return [Array, any] row
|
|
@@ -647,7 +660,7 @@ VALUE Database_batch_query_splat(VALUE self, VALUE sql, VALUE parameters) {
|
|
|
647
660
|
}
|
|
648
661
|
|
|
649
662
|
/* Returns the column names for the given query, without running it.
|
|
650
|
-
*
|
|
663
|
+
*
|
|
651
664
|
* @return [Array<String>] column names
|
|
652
665
|
*/
|
|
653
666
|
VALUE Database_columns(VALUE self, VALUE sql) {
|
|
@@ -655,7 +668,7 @@ VALUE Database_columns(VALUE self, VALUE sql) {
|
|
|
655
668
|
}
|
|
656
669
|
|
|
657
670
|
/* Returns the rowid of the last inserted row.
|
|
658
|
-
*
|
|
671
|
+
*
|
|
659
672
|
* @return [Integer] last rowid
|
|
660
673
|
*/
|
|
661
674
|
VALUE Database_last_insert_rowid(VALUE self) {
|
|
@@ -665,7 +678,7 @@ VALUE Database_last_insert_rowid(VALUE self) {
|
|
|
665
678
|
}
|
|
666
679
|
|
|
667
680
|
/* Returns the number of changes made to the database by the last operation.
|
|
668
|
-
*
|
|
681
|
+
*
|
|
669
682
|
* @return [Integer] number of changes
|
|
670
683
|
*/
|
|
671
684
|
VALUE Database_changes(VALUE self) {
|
|
@@ -676,7 +689,7 @@ VALUE Database_changes(VALUE self) {
|
|
|
676
689
|
|
|
677
690
|
/* Returns the database filename. If db_name is given, returns the filename for
|
|
678
691
|
* the respective attached database.
|
|
679
|
-
*
|
|
692
|
+
*
|
|
680
693
|
* @overload filename()
|
|
681
694
|
* @return [String] database filename
|
|
682
695
|
* @overload filename(db_name)
|
|
@@ -695,7 +708,7 @@ VALUE Database_filename(int argc, VALUE *argv, VALUE self) {
|
|
|
695
708
|
}
|
|
696
709
|
|
|
697
710
|
/* Returns true if a transaction is currently in progress.
|
|
698
|
-
*
|
|
711
|
+
*
|
|
699
712
|
* @return [bool] is transaction in progress
|
|
700
713
|
*/
|
|
701
714
|
VALUE Database_transaction_active_p(VALUE self) {
|
|
@@ -706,7 +719,7 @@ VALUE Database_transaction_active_p(VALUE self) {
|
|
|
706
719
|
|
|
707
720
|
#ifdef HAVE_SQLITE3_LOAD_EXTENSION
|
|
708
721
|
/* Loads an extension with the given path.
|
|
709
|
-
*
|
|
722
|
+
*
|
|
710
723
|
* @param path [String] extension file path
|
|
711
724
|
* @return [Extralite::Database] database
|
|
712
725
|
*/
|
|
@@ -728,8 +741,17 @@ VALUE Database_load_extension(VALUE self, VALUE path) {
|
|
|
728
741
|
static inline VALUE Database_prepare(int argc, VALUE *argv, VALUE self, VALUE mode) {
|
|
729
742
|
rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
|
|
730
743
|
|
|
744
|
+
VALUE transform = Qnil;
|
|
745
|
+
if (argc > 1 && rb_obj_is_instance_of(argv[0], cTransform)) {
|
|
746
|
+
transform = argv[0];
|
|
747
|
+
argv++;
|
|
748
|
+
argc--;
|
|
749
|
+
}
|
|
750
|
+
|
|
731
751
|
VALUE args[] = { self, argv[0], mode};
|
|
732
752
|
VALUE query = rb_funcall_passing_block(cQuery, ID_new, 3, args);
|
|
753
|
+
if (!NIL_P(transform))
|
|
754
|
+
Query_transform_set(query, transform);
|
|
733
755
|
if (argc > 1) rb_funcallv(query, ID_bind, argc - 1, argv + 1);
|
|
734
756
|
RB_GC_GUARD(query);
|
|
735
757
|
return query;
|
|
@@ -739,11 +761,14 @@ static inline VALUE Database_prepare(int argc, VALUE *argv, VALUE self, VALUE mo
|
|
|
739
761
|
* db.prepare(sql) -> query
|
|
740
762
|
* db.prepare(sql, *params) -> query
|
|
741
763
|
* db.prepare(sql, *params) { ... } -> query
|
|
764
|
+
* db.prepare(transform, sql) -> query
|
|
765
|
+
* db.prepare(transform, sql, *params) -> query
|
|
742
766
|
*
|
|
743
767
|
* Creates a prepared query with the given SQL query in hash mode. If query
|
|
744
768
|
* parameters are given, they are bound to the query. If a block is given, it is
|
|
745
769
|
* used as a transform proc.
|
|
746
|
-
*
|
|
770
|
+
*
|
|
771
|
+
* @param transform [Extralite::Transform] transform
|
|
747
772
|
* @param sql [String] SQL statement
|
|
748
773
|
* @param *params [Array<any>] parameters to bind
|
|
749
774
|
* @return [Extralite::Query] prepared query
|
|
@@ -760,7 +785,7 @@ VALUE Database_prepare_hash(int argc, VALUE *argv, VALUE self) {
|
|
|
760
785
|
* Creates a prepared query with the given SQL query in argv mode. If query
|
|
761
786
|
* parameters are given, they are bound to the query. If a block is given, it is
|
|
762
787
|
* used as a transform proc.
|
|
763
|
-
*
|
|
788
|
+
*
|
|
764
789
|
* @param sql [String] SQL statement
|
|
765
790
|
* @param *params [Array<any>] parameters to bind
|
|
766
791
|
* @return [Extralite::Query] prepared query
|
|
@@ -777,7 +802,7 @@ VALUE Database_prepare_splat(int argc, VALUE *argv, VALUE self) {
|
|
|
777
802
|
* Creates a prepared query with the given SQL query in array mode. If query
|
|
778
803
|
* parameters are given, they are bound to the query. If a block is given, it is
|
|
779
804
|
* used as a transform proc.
|
|
780
|
-
*
|
|
805
|
+
*
|
|
781
806
|
* @param sql [String] SQL statement
|
|
782
807
|
* @param *params [Array<any>] parameters to bind
|
|
783
808
|
* @return [Extralite::Query] prepared query
|
|
@@ -793,7 +818,7 @@ VALUE Database_prepare_array(int argc, VALUE *argv, VALUE self) {
|
|
|
793
818
|
* It is not safe to call `#interrupt` on a database that is about to be closed.
|
|
794
819
|
* For more information, consult the [sqlite3 API
|
|
795
820
|
* docs](https://sqlite.org/c3ref/interrupt.html).
|
|
796
|
-
*
|
|
821
|
+
*
|
|
797
822
|
* @return [Extralite::Database] database
|
|
798
823
|
*/
|
|
799
824
|
VALUE Database_interrupt(VALUE self) {
|
|
@@ -874,11 +899,11 @@ VALUE backup_cleanup(VALUE ptr) {
|
|
|
874
899
|
* method with two arguments: the remaining page count, and the total page
|
|
875
900
|
* count, which can be used to display the progress to the user or to collect
|
|
876
901
|
* statistics.
|
|
877
|
-
*
|
|
902
|
+
*
|
|
878
903
|
* db_src.backup(db_dest) do |remaining, total|
|
|
879
904
|
* puts "Backing up #{remaining}/#{total}"
|
|
880
905
|
* end
|
|
881
|
-
*
|
|
906
|
+
*
|
|
882
907
|
* @param dest [String, Extralite::Database] backup destination
|
|
883
908
|
* @param src_db_name [String] source database name (default: "main")
|
|
884
909
|
* @param dst_db_name [String] Destination database name (default: "main")
|
|
@@ -933,12 +958,12 @@ VALUE Database_backup(int argc, VALUE *argv, VALUE self) {
|
|
|
933
958
|
/* Returns runtime status values for the given op as an array containing the
|
|
934
959
|
* current value and the high water mark value. To reset the high water mark,
|
|
935
960
|
* pass true as reset.
|
|
936
|
-
*
|
|
961
|
+
*
|
|
937
962
|
* You can use the various `Extralite::SQLITE_STATUS_xxx` constants with this
|
|
938
963
|
* method:
|
|
939
|
-
*
|
|
964
|
+
*
|
|
940
965
|
* Extralite.runtime_status(Extralite::SQLITE_STATUS_MEMORY_USED)
|
|
941
|
-
*
|
|
966
|
+
*
|
|
942
967
|
* For more information see the SQLite docs: https://sqlite.org/c3ref/c_status_malloc_count.html
|
|
943
968
|
*
|
|
944
969
|
* @overload runtime_status(op)
|
|
@@ -964,7 +989,7 @@ VALUE Extralite_runtime_status(int argc, VALUE* argv, VALUE self) {
|
|
|
964
989
|
/* Returns database status values for the given op as an array containing the
|
|
965
990
|
* current value and the high water mark value. To reset the high water mark,
|
|
966
991
|
* pass true as reset.
|
|
967
|
-
*
|
|
992
|
+
*
|
|
968
993
|
* @overload status(op)
|
|
969
994
|
* @param op [Integer] op
|
|
970
995
|
* @return [Array<Integer>] array containing the value and high water mark
|
|
@@ -989,7 +1014,7 @@ VALUE Database_status(int argc, VALUE *argv, VALUE self) {
|
|
|
989
1014
|
|
|
990
1015
|
/* Returns the current limit for the given category. If a new value is given,
|
|
991
1016
|
* sets the limit to the new value and returns the previous value.
|
|
992
|
-
*
|
|
1017
|
+
*
|
|
993
1018
|
* @overload limit(category)
|
|
994
1019
|
* @param category [Integer] category
|
|
995
1020
|
* @return [Integer] limit value
|
|
@@ -1018,7 +1043,7 @@ VALUE Database_limit(int argc, VALUE *argv, VALUE self) {
|
|
|
1018
1043
|
* cause the program to wait for the database to become available. If the
|
|
1019
1044
|
* database is still locked when the timeout period has elapsed, the query will
|
|
1020
1045
|
* fail with a `Extralite::BusyError` exception.
|
|
1021
|
-
*
|
|
1046
|
+
*
|
|
1022
1047
|
* Setting the busy timeout allows other threads to run while waiting for the
|
|
1023
1048
|
* database to become available. See also `#on_progress`.
|
|
1024
1049
|
*
|
|
@@ -1036,7 +1061,7 @@ VALUE Database_busy_timeout_set(VALUE self, VALUE sec) {
|
|
|
1036
1061
|
}
|
|
1037
1062
|
|
|
1038
1063
|
/* Returns the total number of changes made to the database since opening it.
|
|
1039
|
-
*
|
|
1064
|
+
*
|
|
1040
1065
|
* @return [Integer] total changes
|
|
1041
1066
|
*/
|
|
1042
1067
|
VALUE Database_total_changes(VALUE self) {
|
|
@@ -1048,7 +1073,7 @@ VALUE Database_total_changes(VALUE self) {
|
|
|
1048
1073
|
|
|
1049
1074
|
/* Installs or removes a block that will be invoked for every SQL statement
|
|
1050
1075
|
* executed. To stop tracing, call `#trace` without a block.
|
|
1051
|
-
*
|
|
1076
|
+
*
|
|
1052
1077
|
* @return [Extralite::Database] database
|
|
1053
1078
|
*/
|
|
1054
1079
|
VALUE Database_trace(VALUE self) {
|
|
@@ -1066,13 +1091,13 @@ VALUE Database_trace(VALUE self) {
|
|
|
1066
1091
|
* then be used to store the changes to a file, apply them to another database,
|
|
1067
1092
|
* or undo the changes. The given table names specify which tables should be
|
|
1068
1093
|
* tracked for changes. Passing a value of nil causes all tables to be tracked.
|
|
1069
|
-
*
|
|
1094
|
+
*
|
|
1070
1095
|
* changeset = db.track_changes(:foo, :bar) do
|
|
1071
1096
|
* perform_a_bunch_of_queries
|
|
1072
1097
|
* end
|
|
1073
|
-
*
|
|
1098
|
+
*
|
|
1074
1099
|
* File.open('my.changes', 'w+') { |f| f << changeset.to_blob }
|
|
1075
|
-
*
|
|
1100
|
+
*
|
|
1076
1101
|
* @param *tables [Array<String, Symbol>] table(s) to track
|
|
1077
1102
|
* @return [Extralite::Changeset] changeset
|
|
1078
1103
|
*/
|
|
@@ -1195,10 +1220,10 @@ struct progress_handler parse_progress_handler_opts(VALUE opts) {
|
|
|
1195
1220
|
* work correctly also when running simple queries that don't include many
|
|
1196
1221
|
* VM instructions. If the `tick` value is greater than the period value it is
|
|
1197
1222
|
* automatically capped to the period value.
|
|
1198
|
-
*
|
|
1223
|
+
*
|
|
1199
1224
|
* The `mode` parameter controls the progress handler mode, which is one of the
|
|
1200
1225
|
* following:
|
|
1201
|
-
*
|
|
1226
|
+
*
|
|
1202
1227
|
* - `:normal` (default): the progress handler proc is invoked on query
|
|
1203
1228
|
* progress.
|
|
1204
1229
|
* - `:once`: the progress handler proc is invoked only once, when preparing the
|
|
@@ -1286,12 +1311,12 @@ VALUE Database_on_progress(int argc, VALUE *argv, VALUE self) {
|
|
|
1286
1311
|
|
|
1287
1312
|
/* call-seq:
|
|
1288
1313
|
* Extralite.on_progress(**opts) { ... }
|
|
1289
|
-
*
|
|
1314
|
+
*
|
|
1290
1315
|
* Installs or removes a global progress handler that will be executed
|
|
1291
1316
|
* periodically while a query is running. This method can be used to support
|
|
1292
1317
|
* switching between fibers and threads or implementing timeouts for running
|
|
1293
1318
|
* queries.
|
|
1294
|
-
*
|
|
1319
|
+
*
|
|
1295
1320
|
* This method sets the progress handler settings and behaviour for all
|
|
1296
1321
|
* subsequently created `Database` instances. Calling this method will have no
|
|
1297
1322
|
* effect on already existing `Database` instances
|
|
@@ -1309,10 +1334,10 @@ VALUE Database_on_progress(int argc, VALUE *argv, VALUE self) {
|
|
|
1309
1334
|
* work correctly also when running simple queries that don't include many
|
|
1310
1335
|
* VM instructions. If the `tick` value is greater than the period value it is
|
|
1311
1336
|
* automatically capped to the period value.
|
|
1312
|
-
*
|
|
1337
|
+
*
|
|
1313
1338
|
* The `mode` parameter controls the progress handler mode, which is one of the
|
|
1314
1339
|
* following:
|
|
1315
|
-
*
|
|
1340
|
+
*
|
|
1316
1341
|
* - `:normal` (default): the progress handler proc is invoked on query
|
|
1317
1342
|
* progress.
|
|
1318
1343
|
* - `:once`: the progress handler proc is invoked only once, when preparing the
|
|
@@ -1353,7 +1378,7 @@ VALUE Extralite_on_progress(int argc, VALUE *argv, VALUE self) {
|
|
|
1353
1378
|
}
|
|
1354
1379
|
|
|
1355
1380
|
/* Returns the last error code for the database.
|
|
1356
|
-
*
|
|
1381
|
+
*
|
|
1357
1382
|
* @return [Integer] last error code
|
|
1358
1383
|
*/
|
|
1359
1384
|
VALUE Database_errcode(VALUE self) {
|
|
@@ -1363,7 +1388,7 @@ VALUE Database_errcode(VALUE self) {
|
|
|
1363
1388
|
}
|
|
1364
1389
|
|
|
1365
1390
|
/* Returns the last error message for the database.
|
|
1366
|
-
*
|
|
1391
|
+
*
|
|
1367
1392
|
* @return [String] last error message
|
|
1368
1393
|
*/
|
|
1369
1394
|
VALUE Database_errmsg(VALUE self) {
|
|
@@ -1375,7 +1400,7 @@ VALUE Database_errmsg(VALUE self) {
|
|
|
1375
1400
|
#ifdef HAVE_SQLITE3_ERROR_OFFSET
|
|
1376
1401
|
/* Returns the offset for the last error. This is useful for indicating where in
|
|
1377
1402
|
* the SQL string an error was encountered.
|
|
1378
|
-
*
|
|
1403
|
+
*
|
|
1379
1404
|
* @return [Integer] offset in the last submitted SQL string
|
|
1380
1405
|
*/
|
|
1381
1406
|
VALUE Database_error_offset(VALUE self) {
|
|
@@ -1414,7 +1439,7 @@ VALUE Database_gvl_release_threshold_get(VALUE self) {
|
|
|
1414
1439
|
|
|
1415
1440
|
/* Sets the database's GVL release threshold. The release policy changes
|
|
1416
1441
|
* according to the given value:
|
|
1417
|
-
*
|
|
1442
|
+
*
|
|
1418
1443
|
* - Less than 0: the GVL is never released while running queries. This is the
|
|
1419
1444
|
* policy used when a progress handler is set. For more information see
|
|
1420
1445
|
* `#on_progress`.
|
|
@@ -1499,10 +1524,40 @@ VALUE Database_wal_checkpoint(int argc, VALUE *argv, VALUE self) {
|
|
|
1499
1524
|
);
|
|
1500
1525
|
if (rc != SQLITE_OK)
|
|
1501
1526
|
rb_raise(cError, "Failed to perform WAL checkpoint: %s", sqlite3_errstr(rc));
|
|
1502
|
-
|
|
1527
|
+
|
|
1503
1528
|
return rb_ary_new3(2, INT2NUM(total_frames), INT2NUM(checkpointed_frames));
|
|
1504
1529
|
}
|
|
1505
1530
|
|
|
1531
|
+
/* Flushes dirty pages in the pager-cache to the disk. For more information see:
|
|
1532
|
+
* https://sqlite.org/c3ref/db_cacheflush.html
|
|
1533
|
+
*
|
|
1534
|
+
* @return [Extralite::Database] Database
|
|
1535
|
+
*/
|
|
1536
|
+
VALUE Database_cache_flush(VALUE self) {
|
|
1537
|
+
Database_t *db = self_to_open_database(self);
|
|
1538
|
+
|
|
1539
|
+
int rc = sqlite3_db_cacheflush(db->sqlite3_db);
|
|
1540
|
+
if (rc != SQLITE_OK)
|
|
1541
|
+
rb_raise(cError, "Failed to flush the database cache: %s", sqlite3_errstr(rc));
|
|
1542
|
+
|
|
1543
|
+
return self;
|
|
1544
|
+
}
|
|
1545
|
+
|
|
1546
|
+
/* Attempts to free up as much memory as possible. For more information see:
|
|
1547
|
+
* https://sqlite.org/c3ref/db_release_memory.html
|
|
1548
|
+
*
|
|
1549
|
+
* @return [Extralite::Database] Database
|
|
1550
|
+
*/
|
|
1551
|
+
VALUE Database_release_memory(VALUE self) {
|
|
1552
|
+
Database_t *db = self_to_open_database(self);
|
|
1553
|
+
|
|
1554
|
+
int rc = sqlite3_db_release_memory(db->sqlite3_db);
|
|
1555
|
+
if (rc != SQLITE_OK)
|
|
1556
|
+
rb_raise(cError, "Failed to release memory: %s", sqlite3_errstr(rc));
|
|
1557
|
+
|
|
1558
|
+
return self;
|
|
1559
|
+
}
|
|
1560
|
+
|
|
1506
1561
|
void Init_ExtraliteDatabase(void) {
|
|
1507
1562
|
VALUE mExtralite = rb_define_module("Extralite");
|
|
1508
1563
|
rb_define_singleton_method(mExtralite, "runtime_status", Extralite_runtime_status, -1);
|
|
@@ -1515,10 +1570,11 @@ void Init_ExtraliteDatabase(void) {
|
|
|
1515
1570
|
rb_define_method(cDatabase, "backup", Database_backup, -1);
|
|
1516
1571
|
rb_define_method(cDatabase, "batch_execute", Database_batch_execute, 2);
|
|
1517
1572
|
rb_define_method(cDatabase, "batch_query", Database_batch_query, 2);
|
|
1518
|
-
rb_define_method(cDatabase, "batch_query_array",
|
|
1519
|
-
rb_define_method(cDatabase, "batch_query_splat",
|
|
1573
|
+
rb_define_method(cDatabase, "batch_query_array", Database_batch_query_array, 2);
|
|
1574
|
+
rb_define_method(cDatabase, "batch_query_splat", Database_batch_query_splat, 2);
|
|
1520
1575
|
rb_define_method(cDatabase, "batch_query_hash", Database_batch_query, 2);
|
|
1521
1576
|
rb_define_method(cDatabase, "busy_timeout=", Database_busy_timeout_set, 1);
|
|
1577
|
+
rb_define_method(cDatabase, "cache_flush", Database_cache_flush, 0);
|
|
1522
1578
|
rb_define_method(cDatabase, "changes", Database_changes, 0);
|
|
1523
1579
|
rb_define_method(cDatabase, "close", Database_close, 0);
|
|
1524
1580
|
rb_define_method(cDatabase, "closed?", Database_closed_p, 0);
|
|
@@ -1558,6 +1614,7 @@ void Init_ExtraliteDatabase(void) {
|
|
|
1558
1614
|
rb_define_method(cDatabase, "query_single_splat", Database_query_single_splat, -1);
|
|
1559
1615
|
rb_define_method(cDatabase, "query_single_hash", Database_query_single, -1);
|
|
1560
1616
|
rb_define_method(cDatabase, "read_only?", Database_read_only_p, 0);
|
|
1617
|
+
rb_define_method(cDatabase, "release_memory", Database_release_memory, 0);
|
|
1561
1618
|
rb_define_method(cDatabase, "status", Database_status, -1);
|
|
1562
1619
|
rb_define_method(cDatabase, "total_changes", Database_total_changes, 0);
|
|
1563
1620
|
rb_define_method(cDatabase, "trace", Database_trace, 0);
|
|
@@ -1566,7 +1623,7 @@ void Init_ExtraliteDatabase(void) {
|
|
|
1566
1623
|
#ifdef EXTRALITE_ENABLE_CHANGESET
|
|
1567
1624
|
rb_define_method(cDatabase, "track_changes", Database_track_changes, -1);
|
|
1568
1625
|
#endif
|
|
1569
|
-
|
|
1626
|
+
|
|
1570
1627
|
rb_define_method(cDatabase, "transaction_active?", Database_transaction_active_p, 0);
|
|
1571
1628
|
|
|
1572
1629
|
cBlob = rb_define_class_under(mExtralite, "Blob", rb_cString);
|
|
@@ -1575,39 +1632,39 @@ void Init_ExtraliteDatabase(void) {
|
|
|
1575
1632
|
cBusyError = rb_define_class_under(mExtralite, "BusyError", cError);
|
|
1576
1633
|
cInterruptError = rb_define_class_under(mExtralite, "InterruptError", cError);
|
|
1577
1634
|
cParameterError = rb_define_class_under(mExtralite, "ParameterError", cError);
|
|
1578
|
-
eArgumentError = rb_const_get(rb_cObject,
|
|
1579
|
-
|
|
1580
|
-
ID_bind =
|
|
1581
|
-
ID_call =
|
|
1582
|
-
ID_each =
|
|
1583
|
-
ID_keys =
|
|
1584
|
-
ID_new =
|
|
1585
|
-
|
|
1586
|
-
ID_strip =
|
|
1587
|
-
ID_to_s =
|
|
1588
|
-
ID_track =
|
|
1589
|
-
|
|
1590
|
-
SYM_at_least_once = ID2SYM(
|
|
1591
|
-
SYM_full = ID2SYM(
|
|
1592
|
-
SYM_gvl_release_threshold = ID2SYM(
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
SYM_read_only = ID2SYM(
|
|
1599
|
-
SYM_restart = ID2SYM(
|
|
1600
|
-
SYM_truncate = ID2SYM(
|
|
1601
|
-
SYM_wal = ID2SYM(
|
|
1635
|
+
eArgumentError = rb_const_get(rb_cObject, rb_intern_const("ArgumentError"));
|
|
1636
|
+
|
|
1637
|
+
ID_bind = rb_intern_const("bind");
|
|
1638
|
+
ID_call = rb_intern_const("call");
|
|
1639
|
+
ID_each = rb_intern_const("each");
|
|
1640
|
+
ID_keys = rb_intern_const("keys");
|
|
1641
|
+
ID_new = rb_intern_const("new");
|
|
1642
|
+
ID_parse = rb_intern_const("parse");
|
|
1643
|
+
ID_strip = rb_intern_const("strip");
|
|
1644
|
+
ID_to_s = rb_intern_const("to_s");
|
|
1645
|
+
ID_track = rb_intern_const("track");
|
|
1646
|
+
|
|
1647
|
+
SYM_at_least_once = ID2SYM(rb_intern_const("at_least_once"));
|
|
1648
|
+
SYM_full = ID2SYM(rb_intern_const("full"));
|
|
1649
|
+
SYM_gvl_release_threshold = ID2SYM(rb_intern_const("gvl_release_threshold"));
|
|
1650
|
+
SYM_legacy = ID2SYM(rb_intern_const("legacy"));
|
|
1651
|
+
SYM_once = ID2SYM(rb_intern_const("once"));
|
|
1652
|
+
SYM_none = ID2SYM(rb_intern_const("none"));
|
|
1653
|
+
SYM_normal = ID2SYM(rb_intern_const("normal"));
|
|
1654
|
+
SYM_passive = ID2SYM(rb_intern_const("passive"));
|
|
1655
|
+
SYM_read_only = ID2SYM(rb_intern_const("read_only"));
|
|
1656
|
+
SYM_restart = ID2SYM(rb_intern_const("restart"));
|
|
1657
|
+
SYM_truncate = ID2SYM(rb_intern_const("truncate"));
|
|
1658
|
+
SYM_wal = ID2SYM(rb_intern_const("wal"));
|
|
1602
1659
|
|
|
1603
1660
|
rb_gc_register_mark_object(SYM_at_least_once);
|
|
1604
1661
|
rb_gc_register_mark_object(SYM_full);
|
|
1605
1662
|
rb_gc_register_mark_object(SYM_gvl_release_threshold);
|
|
1663
|
+
rb_gc_register_mark_object(SYM_legacy);
|
|
1606
1664
|
rb_gc_register_mark_object(SYM_once);
|
|
1607
1665
|
rb_gc_register_mark_object(SYM_none);
|
|
1608
1666
|
rb_gc_register_mark_object(SYM_normal);
|
|
1609
1667
|
rb_gc_register_mark_object(SYM_passive);
|
|
1610
|
-
rb_gc_register_mark_object(SYM_pragma);
|
|
1611
1668
|
rb_gc_register_mark_object(SYM_read_only);
|
|
1612
1669
|
rb_gc_register_mark_object(SYM_restart);
|
|
1613
1670
|
rb_gc_register_mark_object(SYM_truncate);
|