extralite-bundle 2.7 → 2.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +1 -1
- data/.yardopts +1 -1
- data/CHANGELOG.md +15 -4
- data/README.md +83 -46
- data/examples/kv_store.rb +1 -1
- data/examples/pubsub_store_polyphony.rb +2 -2
- data/examples/pubsub_store_threads.rb +3 -3
- data/ext/extralite/changeset.c +1 -1
- data/ext/extralite/common.c +27 -27
- data/ext/extralite/database.c +182 -102
- data/ext/extralite/extralite.h +10 -17
- data/ext/extralite/iterator.c +0 -1
- data/ext/extralite/query.c +45 -44
- data/gemspec.rb +1 -1
- data/lib/extralite/version.rb +1 -1
- data/lib/extralite.rb +158 -4
- data/test/{perf_ary.rb → perf_array.rb} +1 -1
- data/test/perf_splat.rb +63 -0
- data/test/{perf_argv_transform.rb → perf_splat_transform.rb} +7 -7
- data/test/test_database.rb +148 -117
- data/test/test_iterator.rb +12 -12
- data/test/test_query.rb +92 -92
- metadata +7 -7
- data/lib/extralite/sqlite3_constants.rb +0 -157
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6757a6d12ebfc72fade7fc2f75aada49e7dc670779552cef55f830b0a729b7ef
|
4
|
+
data.tar.gz: '058484f92cc779df7603b13ce4759e32a41761734ab9b64d21f21e48b3914641'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8fd0e04aa351b14543103dc983392de02f6310aee0aed4e913b304b1feded5cc80074a0ff4ca33214a160b412d1435e08cbdb298f15bb55ef97eadb6dae45b0b
|
7
|
+
data.tar.gz: '081327e8a2363422fb9ce898ec46b6d15ad8297be7d84d819c494bfa39c761f59a3f0d6774805217da83808697206637d76cb1fd4ee4acb65c716ac44f445088'
|
data/.github/workflows/test.yml
CHANGED
data/.yardopts
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,12 +1,23 @@
|
|
1
|
+
# 2.8 2024-03-10
|
2
|
+
|
3
|
+
- Improve documentation.
|
4
|
+
- Implement `Database#wal_checkpoint`.
|
5
|
+
- Rename query modes: `hash` (the default mode), `array`, `splat`, simplify querying APIs.
|
6
|
+
[#69](https://github.com/digital-fabric/extralite/pull/69)
|
7
|
+
|
8
|
+
# 2.7.1 2024-02-11
|
9
|
+
|
10
|
+
- Fix API docs.
|
11
|
+
|
1
12
|
# 2.7 2024-02-09
|
2
13
|
|
3
14
|
- Improve progress handler API, add mode, period, tick options, global progress
|
4
15
|
handler. [#68](https://github.com/digital-fabric/extralite/pull/68)
|
5
|
-
- Rework `Database#initialize` options
|
6
|
-
- Add argv row mode (for passing column values as argv)
|
7
|
-
- Streamline and improve query methods
|
16
|
+
- Rework `Database#initialize` options.
|
17
|
+
- Add argv row mode (for passing column values as argv).
|
18
|
+
- Streamline and improve query methods.
|
8
19
|
[#67](https://github.com/digital-fabric/extralite/pull/67)
|
9
|
-
- Implement row transforms
|
20
|
+
- Implement row transforms.
|
10
21
|
|
11
22
|
# 2.6 2024-01-23
|
12
23
|
|
data/README.md
CHANGED
@@ -141,10 +141,10 @@ single values, if you're just reading one column.
|
|
141
141
|
For that purpose, Extralite offers three different ways, or modes, of retrieving
|
142
142
|
records:
|
143
143
|
|
144
|
-
- `:hash`:
|
145
|
-
- `:
|
146
|
-
- `:
|
147
|
-
|
144
|
+
- `:hash`: retrieve each row as a hash (this is the default mode).
|
145
|
+
- `:array`: retrieve each row as an array.
|
146
|
+
- `:splat`: retrieve each row as one or more splatted values, without wrapping
|
147
|
+
them in a container (see [below](#the-splat-query-mode)).
|
148
148
|
|
149
149
|
Extralite provides separate methods for the different modes:
|
150
150
|
|
@@ -152,9 +152,9 @@ Extralite provides separate methods for the different modes:
|
|
152
152
|
# alias #query_hash
|
153
153
|
db.query('select 1') #=> [{ "1" => 1 }]
|
154
154
|
|
155
|
-
db.
|
155
|
+
db.query_array('select 1') #=> [[1]]
|
156
156
|
|
157
|
-
db.
|
157
|
+
db.query_splat('select 1') #=> [1]
|
158
158
|
```
|
159
159
|
|
160
160
|
Notice how all the return values above are arrays. This is because the different
|
@@ -163,19 +163,56 @@ get back a single row, use one of the `query_single_xxx` methods:
|
|
163
163
|
|
164
164
|
```ruby
|
165
165
|
# alias #query_single_hash
|
166
|
-
db.
|
166
|
+
db.query_single('select 1') #=> { "1" => 1 }
|
167
167
|
|
168
|
-
db.
|
168
|
+
db.query_single_array('select 1') #=> [1]
|
169
169
|
|
170
|
-
db.
|
170
|
+
db.query_single_splat('select 1') #=> 1
|
171
171
|
```
|
172
172
|
|
173
|
-
|
173
|
+
### Iterating Over Query Results with a Block
|
174
174
|
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
175
|
+
In addition to getting query results as an array of rows, you can also directly
|
176
|
+
iterate over the query results by providing a block to the different
|
177
|
+
`#query_xxx` methods:
|
178
|
+
|
179
|
+
```ruby
|
180
|
+
db.query('select * from foo') { |row| handle_row(row) }
|
181
|
+
```
|
182
|
+
|
183
|
+
### The Splat Query Mode
|
184
|
+
|
185
|
+
The splat query mode allows you to retrieve column values for each row without
|
186
|
+
wrapping them in a container. This is useful especially when performing queries
|
187
|
+
that return a single column:
|
188
|
+
|
189
|
+
```ruby
|
190
|
+
# When using the array mode we need to take unwrap the values
|
191
|
+
ids = db.query_array('select id from tasks where active = 1').map { |r| r.first }
|
192
|
+
|
193
|
+
# In splat mode we don't need to do that
|
194
|
+
ids = db.query_splat('select id from tasks where active = 1')
|
195
|
+
```
|
196
|
+
|
197
|
+
The splat mode is also useful when iterating over records with a block. The
|
198
|
+
column values are provided as splatted arguments to the given block:
|
199
|
+
|
200
|
+
```ruby
|
201
|
+
db.query_splat('select a, b, c from foo') do |a, b, c|
|
202
|
+
do_this_with(a, b)
|
203
|
+
do_that_with(c)
|
204
|
+
end
|
205
|
+
```
|
206
|
+
|
207
|
+
When iterating over records in this manner, the splat mode is slightly faster
|
208
|
+
than the array mode, and also reduces pressure on the Ruby GC since you avoid
|
209
|
+
allocating arrays or hashes to hold the column values.
|
210
|
+
|
211
|
+
## Parameter Binding
|
212
|
+
|
213
|
+
The `#execute` and `#query_xxx` methods accept parameters that can be bound to
|
214
|
+
the query, which means that their values will be used for each corresponding
|
215
|
+
place-holder (expressed using `?`) in the SQL statement:
|
179
216
|
|
180
217
|
```ruby
|
181
218
|
db.query('select x from my_table where y = ? and z = ?', 'foo', 'bar')
|
@@ -224,14 +261,14 @@ values:
|
|
224
261
|
- `String` (see below)
|
225
262
|
- nil
|
226
263
|
|
227
|
-
### Boolean
|
264
|
+
### Boolean Values
|
228
265
|
|
229
266
|
SQLite does not have a boolean data type. Extralite will automatically translate
|
230
267
|
bound parameter values of `true` or `false` to the integer values `1` and `0`,
|
231
268
|
respectively. Note that boolean values stored in the database will be fetched as
|
232
269
|
integers.
|
233
270
|
|
234
|
-
### String
|
271
|
+
### String Values
|
235
272
|
|
236
273
|
String parameter values are translated by Extralite to either `TEXT` or `BLOB`
|
237
274
|
values according to the string encoding used. Strings with an `ASCII-8BIT` are
|
@@ -269,12 +306,12 @@ db.query(transform, 'select * from foo')
|
|
269
306
|
#=> rows as instances of MyModel
|
270
307
|
```
|
271
308
|
|
272
|
-
When using the `
|
309
|
+
When using the `splat` mode, the different column values are passed as splatted
|
273
310
|
values to the transform proc:
|
274
311
|
|
275
312
|
```ruby
|
276
313
|
transform = ->(a, b, c) { { a:a, b: b, c: JSON.parse(c) } }
|
277
|
-
db.
|
314
|
+
db.query_splat(transform, 'select a, b, c from foo')
|
278
315
|
#=> transformed rows
|
279
316
|
```
|
280
317
|
|
@@ -325,16 +362,16 @@ three different modes: as a hash, an array or as individual column values. To
|
|
325
362
|
set the mode, you can use one of the `#prepare_xxx` methods:
|
326
363
|
|
327
364
|
```ruby
|
328
|
-
# hash mode
|
365
|
+
# hash mode (alias #prepare_hash)
|
329
366
|
db.prepare('select * from foo').to_a
|
330
367
|
#=> [{ x: 1, y: 2, z: 3}]
|
331
368
|
|
332
|
-
#
|
333
|
-
db.
|
369
|
+
# splat mode
|
370
|
+
db.prepare_splat('select x from foo').to_a
|
334
371
|
#=> [1]
|
335
372
|
|
336
|
-
#
|
337
|
-
db.
|
373
|
+
# array mode
|
374
|
+
db.prepare_array('select * from foo').to_a
|
338
375
|
#=> [[1, 2, 3]]
|
339
376
|
```
|
340
377
|
|
@@ -345,7 +382,7 @@ q = db.prepare('select * from foo')
|
|
345
382
|
q.to_a #=> [{ x: 1, y: 2, z: 3}]
|
346
383
|
|
347
384
|
q.mode #=> :hash
|
348
|
-
q.mode = :
|
385
|
+
q.mode = :array
|
349
386
|
q.to_a "=> [[1, 2, 3]]
|
350
387
|
```
|
351
388
|
|
@@ -368,12 +405,12 @@ query.next(10)
|
|
368
405
|
#=> [{ x: 1, y: 2, z: 3 }, { x: 4, y: 5, z: 6 }]
|
369
406
|
|
370
407
|
# Fetch the next row as an array
|
371
|
-
query = db.
|
408
|
+
query = db.prepare_array('select * from foo')
|
372
409
|
query.next
|
373
410
|
#=> [1, 2, 3]
|
374
411
|
|
375
412
|
# Fetch the next row as a single column
|
376
|
-
db.
|
413
|
+
db.prepare_splat('select z from foo').next
|
377
414
|
#=> 3
|
378
415
|
```
|
379
416
|
|
@@ -400,11 +437,11 @@ query = db.prepare('select * from foo')
|
|
400
437
|
query.each { |r| ... }
|
401
438
|
|
402
439
|
# iterate over records as arrays
|
403
|
-
query = db.
|
440
|
+
query = db.prepare_array('select * from foo')
|
404
441
|
query.each { |r| ... }
|
405
442
|
|
406
443
|
# iterate over records as single values
|
407
|
-
query = db.
|
444
|
+
query = db.prepare_splat('select a, b, c from foo')
|
408
445
|
query.each { |a, b, c| ... }
|
409
446
|
```
|
410
447
|
|
@@ -429,7 +466,7 @@ instantiate an iterator explicitly:
|
|
429
466
|
|
430
467
|
```ruby
|
431
468
|
# You need to pass the query to iterate over:
|
432
|
-
iterator = Extralite::Iterator(query)
|
469
|
+
iterator = Extralite::Iterator.new(query)
|
433
470
|
iterator.each { |r| ... }
|
434
471
|
```
|
435
472
|
|
@@ -437,7 +474,7 @@ iterator.each { |r| ... }
|
|
437
474
|
|
438
475
|
Prepared queries can automatically transform their result sets by setting a
|
439
476
|
transform block. The transform block receives values according to the query mode
|
440
|
-
(hash, array or
|
477
|
+
(hash, array or splat). To set a transform you can pass a block to one of the
|
441
478
|
`Database#prepare_xxx` methods, or use `Query#transform`:
|
442
479
|
|
443
480
|
```ruby
|
@@ -449,12 +486,12 @@ q = db.prepare('select * from items where id = ?')
|
|
449
486
|
q.transform { |h| Item.new(h) }
|
450
487
|
```
|
451
488
|
|
452
|
-
The same can be done for queries in `
|
489
|
+
The same can be done for queries in `splat` or `array` mode:
|
453
490
|
|
454
491
|
```ruby
|
455
|
-
db.
|
492
|
+
db.prepare_splat('select * from foo') { |a, b, c| a + b + c }
|
456
493
|
|
457
|
-
db.
|
494
|
+
db.prepare_array('select * from foo') { |a| a.map(&:to_s).join }
|
458
495
|
```
|
459
496
|
|
460
497
|
## Batch Execution of Queries
|
@@ -640,7 +677,7 @@ end
|
|
640
677
|
|
641
678
|
## Database Information
|
642
679
|
|
643
|
-
### Getting the
|
680
|
+
### Getting the List of Tables
|
644
681
|
|
645
682
|
To get the list of tables in a database, use the `#tables` method:
|
646
683
|
|
@@ -657,7 +694,7 @@ db.tables('foo')
|
|
657
694
|
#=> [...]
|
658
695
|
```
|
659
696
|
|
660
|
-
### Getting the
|
697
|
+
### Getting the Last Insert Row Id
|
661
698
|
|
662
699
|
```ruby
|
663
700
|
db.execute 'insert into foo values (?)', 42
|
@@ -665,7 +702,7 @@ db.last_insert_rowid
|
|
665
702
|
#=> 1
|
666
703
|
```
|
667
704
|
|
668
|
-
### Getting the
|
705
|
+
### Getting the Column Names for a Given Query
|
669
706
|
|
670
707
|
```ruby
|
671
708
|
db.columns('select a, b, c from foo')
|
@@ -891,7 +928,7 @@ above, calling `#interrupt` causes the query to raise a
|
|
891
928
|
`Extralite::InterruptError` exception:
|
892
929
|
|
893
930
|
```ruby
|
894
|
-
db.on_progress { db.interrupt }
|
931
|
+
db.on_progress(period: 1) { db.interrupt }
|
895
932
|
db.query('select 1')
|
896
933
|
#=> Extralite::InterruptError!
|
897
934
|
```
|
@@ -900,7 +937,7 @@ You can also interrupt queries in progress by raising an exception. The query
|
|
900
937
|
will be stopped, and the exception will propagate to the call site:
|
901
938
|
|
902
939
|
```ruby
|
903
|
-
db.on_progress do
|
940
|
+
db.on_progress(period: 1) do
|
904
941
|
raise 'BOOM!'
|
905
942
|
end
|
906
943
|
|
@@ -1003,7 +1040,7 @@ handler. This will work for switching between fibers using either Polyphony or
|
|
1003
1040
|
any fiber scheduler gem, such as Async et al:
|
1004
1041
|
|
1005
1042
|
```ruby
|
1006
|
-
db.on_progress
|
1043
|
+
db.on_progress { sleep(0) }
|
1007
1044
|
```
|
1008
1045
|
|
1009
1046
|
For Polyphony-based apps, you can also call `snooze` to allow other fibers to
|
@@ -1011,7 +1048,7 @@ run while a query is progressing. If your Polyphony app is multi-threaded,
|
|
1011
1048
|
you'll also need to call `Thread.pass` in order to allow other threads to run:
|
1012
1049
|
|
1013
1050
|
```ruby
|
1014
|
-
db.on_progress
|
1051
|
+
db.on_progress do
|
1015
1052
|
snooze
|
1016
1053
|
Thread.pass
|
1017
1054
|
end
|
@@ -1022,7 +1059,7 @@ use the regular `#move_on_after` and `#cancel_after` methods to implement
|
|
1022
1059
|
timeouts for queries:
|
1023
1060
|
|
1024
1061
|
```ruby
|
1025
|
-
db.on_progress
|
1062
|
+
db.on_progress { snooze }
|
1026
1063
|
|
1027
1064
|
cancel_after(3) do
|
1028
1065
|
db.query(long_running_query)
|
@@ -1220,13 +1257,13 @@ code](https://github.com/digital-fabric/extralite/blob/main/test/perf_hash.rb)
|
|
1220
1257
|
### Rows as Arrays
|
1221
1258
|
|
1222
1259
|
[Benchmark source
|
1223
|
-
code](https://github.com/digital-fabric/extralite/blob/main/test/
|
1260
|
+
code](https://github.com/digital-fabric/extralite/blob/main/test/perf_array.rb)
|
1224
1261
|
|
1225
1262
|
|Row count|sqlite3 1.7.0|Extralite 2.5|Advantage|
|
1226
1263
|
|-:|-:|-:|-:|
|
1227
|
-
|10|
|
1228
|
-
|1K|
|
1229
|
-
|100K|
|
1264
|
+
|10|278.0K rows/s|493.6K rows/s|__1.78x__|
|
1265
|
+
|1K|608.6K rows/s|2692.2K rows/s|__4.42x__|
|
1266
|
+
|100K|502.9K rows/s|2564.0K rows/s|__5.10x__|
|
1230
1267
|
|
1231
1268
|
### Prepared Queries (Prepared Statements)
|
1232
1269
|
|
@@ -1239,7 +1276,7 @@ code](https://github.com/digital-fabric/extralite/blob/main/test/perf_hash_prepa
|
|
1239
1276
|
|1K|296.5K rows/s|2396.2K rows/s|__8.08x__|
|
1240
1277
|
|100K|145.9K rows/s|2107.3K rows/s|__14.45x__|
|
1241
1278
|
|
1242
|
-
As those benchmarks show, Extralite is capabale of reading up to 2.
|
1279
|
+
As those benchmarks show, Extralite is capabale of reading up to 2.7M rows per
|
1243
1280
|
second, and can be more than 14 times faster than the `sqlite3` gem.
|
1244
1281
|
|
1245
1282
|
Note that the benchmarks above were performed on synthetic data, in a
|
data/examples/kv_store.rb
CHANGED
@@ -24,7 +24,7 @@ class KVStore
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def setup_queries
|
27
|
-
@q_get = @db.
|
27
|
+
@q_get = @db.prepare_splat('select value from kv where key = ?')
|
28
28
|
@q_set = @db.prepare('insert into kv (key, value) values($1, $2) on conflict (key) do update set value = $2')
|
29
29
|
end
|
30
30
|
|
@@ -42,7 +42,7 @@ class PubSub
|
|
42
42
|
|
43
43
|
def get_messages(&block)
|
44
44
|
# @db.execute('update subscribers set stamp = ? where id = ?', Time.now.to_i, @id)
|
45
|
-
@db.
|
45
|
+
@db.query_splat('delete from messages where subscriber_id = ? returning topic, message', @id, &block)
|
46
46
|
end
|
47
47
|
|
48
48
|
SCHEMA = <<~SQL
|
@@ -174,7 +174,7 @@ while true
|
|
174
174
|
elapsed = now - last_t
|
175
175
|
d_publish = publish_count - last_publish_count
|
176
176
|
d_receive = receive_count - last_receive_count
|
177
|
-
pending = db4.
|
177
|
+
pending = db4.query_single_splat('select count(*) from messages')
|
178
178
|
puts "#{Time.now} publish: #{d_publish/elapsed}/s receive: #{d_receive/elapsed}/s pending: #{pending}"
|
179
179
|
last_t = now
|
180
180
|
last_publish_count = publish_count
|
@@ -35,14 +35,14 @@ class PubSub
|
|
35
35
|
|
36
36
|
def get_messages(&block)
|
37
37
|
@db.transaction(:deferred) do
|
38
|
-
results = @db.
|
38
|
+
results = @db.query_array('select topic, message from messages where subscriber_id = ?', @id)
|
39
39
|
return [] if results.empty?
|
40
40
|
|
41
41
|
@db.execute('delete from messages where subscriber_id = ?', @id)
|
42
42
|
results
|
43
43
|
end
|
44
44
|
|
45
|
-
# messages = @db.
|
45
|
+
# messages = @db.query_array('delete from messages where subscriber_id = ? returning topic, message', @id)
|
46
46
|
# if block
|
47
47
|
# messages.each(&block)
|
48
48
|
# nil
|
@@ -196,7 +196,7 @@ while true
|
|
196
196
|
d_publish = publish_count - last_publish_count
|
197
197
|
d_receive = receive_count - last_receive_count
|
198
198
|
|
199
|
-
count = db4.
|
199
|
+
count = db4.query_single_splat('select count(*) from messages')
|
200
200
|
puts "#{Time.now} publish: #{d_publish/elapsed}/s receive: #{d_receive/elapsed}/s pending: #{count}"
|
201
201
|
last_t = now
|
202
202
|
last_publish_count = publish_count
|
data/ext/extralite/changeset.c
CHANGED
@@ -339,7 +339,7 @@ VALUE Changeset_to_a(VALUE self) {
|
|
339
339
|
|
340
340
|
// copied from: https://sqlite.org/sessionintro.html
|
341
341
|
static int xConflict(void *pCtx, int eConflict, sqlite3_changeset_iter *pIter){
|
342
|
-
|
342
|
+
long ret = (long)pCtx;
|
343
343
|
return ret;
|
344
344
|
}
|
345
345
|
|
data/ext/extralite/common.c
CHANGED
@@ -153,7 +153,7 @@ static inline VALUE row_to_hash(sqlite3_stmt *stmt, int column_count, VALUE colu
|
|
153
153
|
return row;
|
154
154
|
}
|
155
155
|
|
156
|
-
static inline VALUE
|
156
|
+
static inline VALUE row_to_array(sqlite3_stmt *stmt, int column_count) {
|
157
157
|
VALUE row = rb_ary_new2(column_count);
|
158
158
|
for (int i = 0; i < column_count; i++) {
|
159
159
|
VALUE value = get_column_value(stmt, i, sqlite3_column_type(stmt, i));
|
@@ -162,7 +162,7 @@ static inline VALUE row_to_ary(sqlite3_stmt *stmt, int column_count) {
|
|
162
162
|
return row;
|
163
163
|
}
|
164
164
|
|
165
|
-
static inline void
|
165
|
+
static inline void row_to_splat_values(sqlite3_stmt *stmt, int column_count, VALUE *values) {
|
166
166
|
for (int i = 0; i < column_count; i++) {
|
167
167
|
values[i] = get_column_value(stmt, i, sqlite3_column_type(stmt, i));
|
168
168
|
}
|
@@ -321,7 +321,7 @@ VALUE cleanup_stmt(query_ctx *ctx) {
|
|
321
321
|
return Qnil;
|
322
322
|
}
|
323
323
|
|
324
|
-
VALUE
|
324
|
+
VALUE safe_query_splat(query_ctx *ctx);
|
325
325
|
|
326
326
|
VALUE safe_query_hash(query_ctx *ctx) {
|
327
327
|
VALUE array = ROW_MULTI_P(ctx->row_mode) ? rb_ary_new() : Qnil;
|
@@ -369,13 +369,13 @@ VALUE safe_query_hash(query_ctx *ctx) {
|
|
369
369
|
RB_GC_GUARD(values[7])
|
370
370
|
|
371
371
|
#define ARGV_GET_ROW(ctx, column_count, argv_values, row, do_transform, return_rows) \
|
372
|
-
|
372
|
+
row_to_splat_values(ctx->stmt, column_count, argv_values); \
|
373
373
|
if (do_transform) \
|
374
374
|
row = rb_funcall2(ctx->transform_proc, ID_call, column_count, argv_values); \
|
375
375
|
else if (return_rows) \
|
376
376
|
row = column_count == 1 ? argv_values[0] : rb_ary_new_from_values(column_count, argv_values);
|
377
377
|
|
378
|
-
VALUE
|
378
|
+
VALUE safe_query_splat(query_ctx *ctx) {
|
379
379
|
VALUE array = ROW_MULTI_P(ctx->row_mode) ? rb_ary_new() : Qnil;
|
380
380
|
VALUE argv_values[MAX_ARGV_COLUMNS] = NIL_ARGV_VALUES;
|
381
381
|
VALUE row = Qnil;
|
@@ -413,7 +413,7 @@ VALUE safe_query_argv(query_ctx *ctx) {
|
|
413
413
|
return ROW_MULTI_P(ctx->row_mode) ? array : Qnil;
|
414
414
|
}
|
415
415
|
|
416
|
-
VALUE
|
416
|
+
VALUE safe_query_array(query_ctx *ctx) {
|
417
417
|
VALUE array = ROW_MULTI_P(ctx->row_mode) ? rb_ary_new() : Qnil;
|
418
418
|
VALUE row = Qnil;
|
419
419
|
int column_count = sqlite3_column_count(ctx->stmt);
|
@@ -421,7 +421,7 @@ VALUE safe_query_ary(query_ctx *ctx) {
|
|
421
421
|
int do_transform = !NIL_P(ctx->transform_proc);
|
422
422
|
|
423
423
|
while (stmt_iterate(ctx)) {
|
424
|
-
row =
|
424
|
+
row = row_to_array(ctx->stmt, column_count);
|
425
425
|
if (do_transform)
|
426
426
|
row = rb_funcall(ctx->transform_proc, ID_call, 1, row);
|
427
427
|
row_count++;
|
@@ -463,7 +463,7 @@ VALUE safe_query_single_row_hash(query_ctx *ctx) {
|
|
463
463
|
return row;
|
464
464
|
}
|
465
465
|
|
466
|
-
VALUE
|
466
|
+
VALUE safe_query_single_row_splat(query_ctx *ctx) {
|
467
467
|
VALUE argv_values[MAX_ARGV_COLUMNS] = NIL_ARGV_VALUES;
|
468
468
|
VALUE row = Qnil;
|
469
469
|
int column_count = sqlite3_column_count(ctx->stmt);
|
@@ -480,13 +480,13 @@ VALUE safe_query_single_row_argv(query_ctx *ctx) {
|
|
480
480
|
return row;
|
481
481
|
}
|
482
482
|
|
483
|
-
VALUE
|
483
|
+
VALUE safe_query_single_row_array(query_ctx *ctx) {
|
484
484
|
int column_count = sqlite3_column_count(ctx->stmt);
|
485
485
|
VALUE row = Qnil;
|
486
486
|
int do_transform = !NIL_P(ctx->transform_proc);
|
487
487
|
|
488
488
|
if (stmt_iterate(ctx)) {
|
489
|
-
row =
|
489
|
+
row = row_to_array(ctx->stmt, column_count);
|
490
490
|
if (do_transform)
|
491
491
|
row = rb_funcall(ctx->transform_proc, ID_call, 1, row);
|
492
492
|
}
|
@@ -498,8 +498,8 @@ VALUE safe_query_single_row_ary(query_ctx *ctx) {
|
|
498
498
|
enum batch_mode {
|
499
499
|
BATCH_EXECUTE,
|
500
500
|
BATCH_QUERY_HASH,
|
501
|
-
|
502
|
-
|
501
|
+
BATCH_QUERY_SPLAT,
|
502
|
+
BATCH_QUERY_ARRAY,
|
503
503
|
};
|
504
504
|
|
505
505
|
static inline VALUE batch_iterate_hash(query_ctx *ctx) {
|
@@ -522,14 +522,14 @@ static inline VALUE batch_iterate_hash(query_ctx *ctx) {
|
|
522
522
|
return rows;
|
523
523
|
}
|
524
524
|
|
525
|
-
static inline VALUE
|
525
|
+
static inline VALUE batch_iterate_array(query_ctx *ctx) {
|
526
526
|
VALUE rows = rb_ary_new();
|
527
527
|
VALUE row = Qnil;
|
528
528
|
int column_count = sqlite3_column_count(ctx->stmt);
|
529
529
|
int do_transform = !NIL_P(ctx->transform_proc);
|
530
530
|
|
531
531
|
while (stmt_iterate(ctx)) {
|
532
|
-
row =
|
532
|
+
row = row_to_array(ctx->stmt, column_count);
|
533
533
|
if (do_transform)
|
534
534
|
row = rb_funcall(ctx->transform_proc, ID_call, 1, row);
|
535
535
|
rb_ary_push(rows, row);
|
@@ -540,7 +540,7 @@ static inline VALUE batch_iterate_ary(query_ctx *ctx) {
|
|
540
540
|
return rows;
|
541
541
|
}
|
542
542
|
|
543
|
-
static inline VALUE
|
543
|
+
static inline VALUE batch_iterate_splat(query_ctx *ctx) {
|
544
544
|
VALUE rows = rb_ary_new();
|
545
545
|
VALUE argv_values[MAX_ARGV_COLUMNS] = NIL_ARGV_VALUES;
|
546
546
|
VALUE row = Qnil;
|
@@ -568,11 +568,11 @@ static inline void batch_iterate(query_ctx *ctx, enum batch_mode mode, VALUE *ro
|
|
568
568
|
case BATCH_QUERY_HASH:
|
569
569
|
*rows = batch_iterate_hash(ctx);
|
570
570
|
break;
|
571
|
-
case
|
572
|
-
*rows =
|
571
|
+
case BATCH_QUERY_SPLAT:
|
572
|
+
*rows = batch_iterate_splat(ctx);
|
573
573
|
break;
|
574
|
-
case
|
575
|
-
*rows =
|
574
|
+
case BATCH_QUERY_ARRAY:
|
575
|
+
*rows = batch_iterate_array(ctx);
|
576
576
|
break;
|
577
577
|
}
|
578
578
|
}
|
@@ -715,21 +715,21 @@ VALUE safe_batch_query(query_ctx *ctx) {
|
|
715
715
|
switch (ctx->query_mode) {
|
716
716
|
case QUERY_HASH:
|
717
717
|
return batch_run(ctx, BATCH_QUERY_HASH);
|
718
|
-
case
|
719
|
-
return batch_run(ctx,
|
720
|
-
case
|
721
|
-
return batch_run(ctx,
|
718
|
+
case QUERY_SPLAT:
|
719
|
+
return batch_run(ctx, BATCH_QUERY_SPLAT);
|
720
|
+
case QUERY_ARRAY:
|
721
|
+
return batch_run(ctx, BATCH_QUERY_ARRAY);
|
722
722
|
default:
|
723
723
|
rb_raise(cError, "Invalid query mode (safe_batch_query)");
|
724
724
|
}
|
725
725
|
}
|
726
726
|
|
727
|
-
VALUE
|
728
|
-
return batch_run(ctx,
|
727
|
+
VALUE safe_batch_query_array(query_ctx *ctx) {
|
728
|
+
return batch_run(ctx, BATCH_QUERY_ARRAY);
|
729
729
|
}
|
730
730
|
|
731
|
-
VALUE
|
732
|
-
return batch_run(ctx,
|
731
|
+
VALUE safe_batch_query_splat(query_ctx *ctx) {
|
732
|
+
return batch_run(ctx, BATCH_QUERY_SPLAT);
|
733
733
|
}
|
734
734
|
|
735
735
|
VALUE safe_query_columns(query_ctx *ctx) {
|