extralite-bundle 1.14 → 1.16
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.yml +2 -2
- data/CHANGELOG.md +9 -0
- data/Gemfile.lock +1 -1
- data/README.md +12 -2
- data/Rakefile +1 -1
- data/ext/extralite/common.c +5 -1
- data/ext/extralite/database.c +12 -2
- data/ext/extralite/extralite.h +1 -0
- data/ext/extralite/prepared_statement.c +45 -0
- data/lib/extralite/version.rb +1 -1
- data/lib/extralite.rb +25 -1
- data/lib/sequel/adapters/extralite.rb +13 -13
- data/test/test_database.rb +30 -0
- data/test/test_prepared_statement.rb +19 -0
- metadata +7 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b476307d5717c18c6c94107a9f34458f3aa6b5b8060313220f320e7ec223dd3e
|
4
|
+
data.tar.gz: 7198ba58a8bd3daf29f01a63191f6d5dfbf5aada9b32aa293d70fb191792c6a9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0a35a6895ed144c529e2b3c7c911177028268c5da1fc945dbc2ee645a95d350b7445935667be23a537d85bde5b943216c2f988d02c2cf819cbce2e501c286964
|
7
|
+
data.tar.gz: '091a1b6a0e7430228dc9b2e2ebdc0bf6e0d47aded534acfe547326fc0d85987d079852bfe30e7d2e365d72bfef5bf6592f0564a9b1bb82e818396d45ffc76f89'
|
data/.github/workflows/test.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
## 1.16 2022-10-04
|
2
|
+
|
3
|
+
- Fix `Database#pragma` to always return array of records
|
4
|
+
|
5
|
+
## 1.15 2022-10-01
|
6
|
+
|
7
|
+
- Add `Database#pragma` method
|
8
|
+
- Add `Database#tables` method
|
9
|
+
|
1
10
|
## 1.14 2022-02-28
|
2
11
|
|
3
12
|
- Introduce `extralite-bundle` gem for bundling SQLite, use system lib by
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -38,6 +38,8 @@ latest features and enhancements.
|
|
38
38
|
- A variety of methods for different data access patterns: rows as hashes, rows
|
39
39
|
as arrays, single row, single column, single value.
|
40
40
|
- Prepared statements.
|
41
|
+
- Use system-installed sqlite3, or the [bundled latest version of
|
42
|
+
SQLite3](#installing-the-extralite-sqlite3-bundle).
|
41
43
|
- Super fast - [up to 12.5x faster](#performance) than the
|
42
44
|
[sqlite3](https://github.com/sparklemotion/sqlite3-ruby) gem (see also
|
43
45
|
[comparison](#why-not-just-use-the-sqlite3-gem).)
|
@@ -63,7 +65,7 @@ gem 'extralite'
|
|
63
65
|
|
64
66
|
You can also run `gem install extralite` if you just want to check it out.
|
65
67
|
|
66
|
-
|
68
|
+
### Installing the Extralite-SQLite3 bundle
|
67
69
|
|
68
70
|
If you don't have sqlite3 installed on your system, do not want to use the
|
69
71
|
system-installed version of SQLite3, or would like to use the latest version of
|
@@ -136,6 +138,14 @@ number_of_rows_affected = db.changes
|
|
136
138
|
# get db filename
|
137
139
|
db.filename #=> "/tmp/my.db"
|
138
140
|
|
141
|
+
# get list of tables
|
142
|
+
db.tables #=> ['foo', 'bar']
|
143
|
+
|
144
|
+
# get and set pragmas
|
145
|
+
db.pragma(:journal_mode) #=> 'delete'
|
146
|
+
db.pragma(journal_mode: 'wal')
|
147
|
+
db.pragma(:journal_mode) #=> 'wal'
|
148
|
+
|
139
149
|
# load an extension
|
140
150
|
db.load_extension('/path/to/extension.so')
|
141
151
|
|
@@ -175,7 +185,7 @@ Here's a table summarizing the differences between the two gems:
|
|
175
185
|
|
176
186
|
| |sqlite3-ruby|Extralite|
|
177
187
|
|-|-|-|
|
178
|
-
|SQLite3 dependency|depends on OS-installed libsqlite3|
|
188
|
+
|SQLite3 dependency|depends on OS-installed libsqlite3|Use either system sqlite3 or [bundled latest version of SQLite3](#installing-the-extralite-sqlite3-bundle)|
|
179
189
|
|API design|multiple classes|single class|
|
180
190
|
|Query results|row as hash, row as array, single row, single value|row as hash, row as array, __single column__, single row, single value|
|
181
191
|
|Execute multiple statements|separate API (#execute_batch)|integrated|
|
data/Rakefile
CHANGED
@@ -36,7 +36,7 @@ task :release do
|
|
36
36
|
`gem build extralite-bundle.gemspec`
|
37
37
|
|
38
38
|
puts "Pushing extralite #{version}..."
|
39
|
-
|
39
|
+
`gem push extralite-#{version}.gem`
|
40
40
|
|
41
41
|
puts "Pushing extralite-bundle #{version}..."
|
42
42
|
`gem push extralite-bundle-#{version}.gem`
|
data/ext/extralite/common.c
CHANGED
@@ -31,7 +31,7 @@ void bind_hash_parameter_values(sqlite3_stmt *stmt, VALUE hash) {
|
|
31
31
|
|
32
32
|
switch (TYPE(k)) {
|
33
33
|
case T_FIXNUM:
|
34
|
-
bind_parameter_value(stmt,
|
34
|
+
bind_parameter_value(stmt, FIX2INT(k), v);
|
35
35
|
break;
|
36
36
|
case T_SYMBOL:
|
37
37
|
k = rb_funcall(k, ID_TO_S, 0);
|
@@ -345,3 +345,7 @@ VALUE safe_query_single_value(query_ctx *ctx) {
|
|
345
345
|
RB_GC_GUARD(value);
|
346
346
|
return value;
|
347
347
|
}
|
348
|
+
|
349
|
+
VALUE safe_query_columns(query_ctx *ctx) {
|
350
|
+
return get_column_names(ctx->stmt, sqlite3_column_count(ctx->stmt));
|
351
|
+
}
|
data/ext/extralite/database.c
CHANGED
@@ -263,6 +263,15 @@ VALUE Database_query_single_value(int argc, VALUE *argv, VALUE self) {
|
|
263
263
|
return Database_perform_query(argc, argv, self, safe_query_single_value);
|
264
264
|
}
|
265
265
|
|
266
|
+
/* call-seq:
|
267
|
+
* db.columns(sql) -> columns
|
268
|
+
*
|
269
|
+
* Returns the column names for the given query, without running it.
|
270
|
+
*/
|
271
|
+
VALUE Database_columns(VALUE self, VALUE sql) {
|
272
|
+
return Database_perform_query(1, &sql, self, safe_query_columns);
|
273
|
+
}
|
274
|
+
|
266
275
|
/* call-seq:
|
267
276
|
* db.last_insert_rowid -> int
|
268
277
|
*
|
@@ -272,7 +281,7 @@ VALUE Database_last_insert_rowid(VALUE self) {
|
|
272
281
|
Database_t *db;
|
273
282
|
GetOpenDatabase(self, db);
|
274
283
|
|
275
|
-
return
|
284
|
+
return INT2FIX(sqlite3_last_insert_rowid(db->sqlite3_db));
|
276
285
|
}
|
277
286
|
|
278
287
|
/* call-seq:
|
@@ -284,7 +293,7 @@ VALUE Database_changes(VALUE self) {
|
|
284
293
|
Database_t *db;
|
285
294
|
GetOpenDatabase(self, db);
|
286
295
|
|
287
|
-
return
|
296
|
+
return INT2FIX(sqlite3_changes(db->sqlite3_db));
|
288
297
|
}
|
289
298
|
|
290
299
|
/* call-seq:
|
@@ -362,6 +371,7 @@ void Init_ExtraliteDatabase() {
|
|
362
371
|
rb_define_method(cDatabase, "query_single_row", Database_query_single_row, -1);
|
363
372
|
rb_define_method(cDatabase, "query_single_column", Database_query_single_column, -1);
|
364
373
|
rb_define_method(cDatabase, "query_single_value", Database_query_single_value, -1);
|
374
|
+
rb_define_method(cDatabase, "columns", Database_columns, 1);
|
365
375
|
|
366
376
|
rb_define_method(cDatabase, "last_insert_rowid", Database_last_insert_rowid, 0);
|
367
377
|
rb_define_method(cDatabase, "changes", Database_changes, 0);
|
data/ext/extralite/extralite.h
CHANGED
@@ -53,6 +53,7 @@ VALUE safe_query_hash(query_ctx *ctx);
|
|
53
53
|
VALUE safe_query_single_column(query_ctx *ctx);
|
54
54
|
VALUE safe_query_single_row(query_ctx *ctx);
|
55
55
|
VALUE safe_query_single_value(query_ctx *ctx);
|
56
|
+
VALUE safe_query_columns(query_ctx *ctx);
|
56
57
|
|
57
58
|
void prepare_single_stmt(sqlite3 *db, sqlite3_stmt **stmt, VALUE sql);
|
58
59
|
void prepare_multi_stmt(sqlite3 *db, sqlite3_stmt **stmt, VALUE sql);
|
@@ -63,6 +63,9 @@ static inline VALUE PreparedStatement_perform_query(int argc, VALUE *argv, VALUE
|
|
63
63
|
PreparedStatement_t *stmt;
|
64
64
|
GetPreparedStatement(self, stmt);
|
65
65
|
|
66
|
+
if (!stmt->stmt)
|
67
|
+
rb_raise(cError, "Prepared statement is closed");
|
68
|
+
|
66
69
|
sqlite3_reset(stmt->stmt);
|
67
70
|
sqlite3_clear_bindings(stmt->stmt);
|
68
71
|
bind_all_parameters(stmt->stmt, argc, argv);
|
@@ -218,6 +221,43 @@ VALUE PreparedStatement_sql(VALUE self) {
|
|
218
221
|
return stmt->sql;
|
219
222
|
}
|
220
223
|
|
224
|
+
/* call-seq:
|
225
|
+
* stmt.columns -> columns
|
226
|
+
*
|
227
|
+
* Returns the column names for the prepared statement without running it.
|
228
|
+
*/
|
229
|
+
VALUE PreparedStatement_columns(VALUE self) {
|
230
|
+
return PreparedStatement_perform_query(0, NULL, self, safe_query_columns);
|
231
|
+
}
|
232
|
+
|
233
|
+
/* call-seq:
|
234
|
+
* stmt.close -> stmt
|
235
|
+
*
|
236
|
+
* Closes the prepared statement. Running a closed prepared statement will raise
|
237
|
+
* an error.
|
238
|
+
*/
|
239
|
+
VALUE PreparedStatement_close(VALUE self) {
|
240
|
+
PreparedStatement_t *stmt;
|
241
|
+
GetPreparedStatement(self, stmt);
|
242
|
+
if (stmt->stmt) {
|
243
|
+
sqlite3_finalize(stmt->stmt);
|
244
|
+
stmt->stmt = NULL;
|
245
|
+
}
|
246
|
+
return self;
|
247
|
+
}
|
248
|
+
|
249
|
+
/* call-seq:
|
250
|
+
* stmt.closed? -> closed
|
251
|
+
*
|
252
|
+
* Returns true if the prepared statement is closed.
|
253
|
+
*/
|
254
|
+
VALUE PreparedStatement_closed_p(VALUE self) {
|
255
|
+
PreparedStatement_t *stmt;
|
256
|
+
GetPreparedStatement(self, stmt);
|
257
|
+
|
258
|
+
return stmt->stmt ? Qfalse : Qtrue;
|
259
|
+
}
|
260
|
+
|
221
261
|
void Init_ExtralitePreparedStatement() {
|
222
262
|
VALUE mExtralite = rb_define_module("Extralite");
|
223
263
|
|
@@ -235,4 +275,9 @@ void Init_ExtralitePreparedStatement() {
|
|
235
275
|
rb_define_method(cPreparedStatement, "query_single_row", PreparedStatement_query_single_row, -1);
|
236
276
|
rb_define_method(cPreparedStatement, "query_single_column", PreparedStatement_query_single_column, -1);
|
237
277
|
rb_define_method(cPreparedStatement, "query_single_value", PreparedStatement_query_single_value, -1);
|
278
|
+
|
279
|
+
rb_define_method(cPreparedStatement, "columns", PreparedStatement_columns, 0);
|
280
|
+
|
281
|
+
rb_define_method(cPreparedStatement, "close", PreparedStatement_close, 0);
|
282
|
+
rb_define_method(cPreparedStatement, "closed?", PreparedStatement_closed_p, 0);
|
238
283
|
}
|
data/lib/extralite/version.rb
CHANGED
data/lib/extralite.rb
CHANGED
@@ -17,5 +17,29 @@ module Extralite
|
|
17
17
|
|
18
18
|
# An SQLite database
|
19
19
|
class Database
|
20
|
+
alias_method :execute, :query
|
21
|
+
|
22
|
+
TABLES_SQL = <<~SQL
|
23
|
+
SELECT name FROM sqlite_schema
|
24
|
+
WHERE type ='table'
|
25
|
+
AND name NOT LIKE 'sqlite_%';
|
26
|
+
SQL
|
27
|
+
|
28
|
+
def tables
|
29
|
+
query_single_column(TABLES_SQL)
|
30
|
+
end
|
31
|
+
|
32
|
+
def pragma(value)
|
33
|
+
value.is_a?(Hash) ? pragma_set(value) : pragma_get(value)
|
34
|
+
end
|
35
|
+
|
36
|
+
def pragma_set(values)
|
37
|
+
sql = values.inject(+'') { |s, (k, v)| s += "pragma #{k}=#{v}; " }
|
38
|
+
query(sql)
|
39
|
+
end
|
40
|
+
|
41
|
+
def pragma_get(key)
|
42
|
+
query("pragma #{key}")
|
43
|
+
end
|
20
44
|
end
|
21
|
-
end
|
45
|
+
end
|
@@ -122,17 +122,17 @@ module Sequel
|
|
122
122
|
|
123
123
|
connection_pragmas.each{|s| log_connection_yield(s, db){db.query(s)}}
|
124
124
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
125
|
+
class << db
|
126
|
+
attr_reader :prepared_statements
|
127
|
+
end
|
128
|
+
db.instance_variable_set(:@prepared_statements, {})
|
129
129
|
|
130
130
|
db
|
131
131
|
end
|
132
132
|
|
133
133
|
# Disconnect given connections from the database.
|
134
134
|
def disconnect_connection(c)
|
135
|
-
|
135
|
+
c.prepared_statements.each_value{|v| v.first.close }
|
136
136
|
c.close
|
137
137
|
end
|
138
138
|
|
@@ -149,13 +149,13 @@ module Sequel
|
|
149
149
|
# Drop any prepared statements on the connection when executing DDL. This is because
|
150
150
|
# prepared statements lock the table in such a way that you can't drop or alter the
|
151
151
|
# table while a prepared statement that references it still exists.
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
152
|
+
def execute_ddl(sql, opts=OPTS)
|
153
|
+
synchronize(opts[:server]) do |conn|
|
154
|
+
conn.prepared_statements.values.each{|cps, s| cps.close}
|
155
|
+
conn.prepared_statements.clear
|
156
|
+
super
|
157
|
+
end
|
158
|
+
end
|
159
159
|
|
160
160
|
def execute_insert(sql, opts=OPTS)
|
161
161
|
_execute(:insert, sql, opts)
|
@@ -193,7 +193,7 @@ module Sequel
|
|
193
193
|
def _execute(type, sql, opts, &block)
|
194
194
|
begin
|
195
195
|
synchronize(opts[:server]) do |conn|
|
196
|
-
|
196
|
+
return execute_prepared_statement(conn, type, sql, opts, &block) if sql.is_a?(Symbol)
|
197
197
|
log_args = opts[:arguments]
|
198
198
|
args = {}
|
199
199
|
opts.fetch(:arguments, OPTS).each{|k, v| args[k] = prepared_statement_argument(v) }
|
data/test/test_database.rb
CHANGED
@@ -68,6 +68,11 @@ end
|
|
68
68
|
assert_nil r
|
69
69
|
end
|
70
70
|
|
71
|
+
def test_columns
|
72
|
+
r = @db.columns('select x, z from t')
|
73
|
+
assert_equal [:x, :z], r
|
74
|
+
end
|
75
|
+
|
71
76
|
def test_transaction_active?
|
72
77
|
assert_equal false, @db.transaction_active?
|
73
78
|
@db.query('begin')
|
@@ -177,6 +182,31 @@ end
|
|
177
182
|
r = @db.query_single_value("select reverse('abcd')")
|
178
183
|
assert_equal 'dcba', r
|
179
184
|
end
|
185
|
+
|
186
|
+
def test_tables
|
187
|
+
assert_equal ['t'], @db.tables
|
188
|
+
|
189
|
+
@db.query('create table foo (bar text)')
|
190
|
+
assert_equal ['t', 'foo'], @db.tables
|
191
|
+
|
192
|
+
@db.query('drop table t')
|
193
|
+
assert_equal ['foo'], @db.tables
|
194
|
+
|
195
|
+
@db.query('drop table foo')
|
196
|
+
assert_equal [], @db.tables
|
197
|
+
end
|
198
|
+
|
199
|
+
def test_pragma
|
200
|
+
assert_equal [{journal_mode: 'memory'}], @db.pragma('journal_mode')
|
201
|
+
assert_equal [{synchronous: 2}], @db.pragma('synchronous')
|
202
|
+
|
203
|
+
assert_equal [{schema_version: 1}], @db.pragma(:schema_version)
|
204
|
+
assert_equal [{recursive_triggers: 0}], @db.pragma(:recursive_triggers)
|
205
|
+
|
206
|
+
assert_equal [], @db.pragma(schema_version: 33, recursive_triggers: 1)
|
207
|
+
assert_equal [{schema_version: 33}], @db.pragma(:schema_version)
|
208
|
+
assert_equal [{recursive_triggers: 1}], @db.pragma(:recursive_triggers)
|
209
|
+
end
|
180
210
|
end
|
181
211
|
|
182
212
|
class ScenarioTest < MiniTest::Test
|
@@ -162,4 +162,23 @@ end
|
|
162
162
|
r = @db.prepare('select null').query_single_value
|
163
163
|
assert_nil r
|
164
164
|
end
|
165
|
+
|
166
|
+
def test_prepared_statement_columns
|
167
|
+
r = @db.prepare("select 'abc' as a, 'def' as b").columns
|
168
|
+
assert_equal [:a, :b], r
|
169
|
+
end
|
170
|
+
|
171
|
+
def test_prepared_statement_close
|
172
|
+
p = @db.prepare("select 'abc'")
|
173
|
+
|
174
|
+
assert_equal false, p.closed?
|
175
|
+
|
176
|
+
p.close
|
177
|
+
assert_equal true, p.closed?
|
178
|
+
|
179
|
+
p.close
|
180
|
+
assert_equal true, p.closed?
|
181
|
+
|
182
|
+
assert_raises { p.query_single_value }
|
183
|
+
end
|
165
184
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: extralite-bundle
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '1.
|
4
|
+
version: '1.16'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sharon Rosner
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-10-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake-compiler
|
@@ -80,7 +80,7 @@ dependencies:
|
|
80
80
|
- - '='
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: 5.51.0
|
83
|
-
description:
|
83
|
+
description:
|
84
84
|
email: sharon@noteflakes.com
|
85
85
|
executables: []
|
86
86
|
extensions:
|
@@ -134,7 +134,7 @@ metadata:
|
|
134
134
|
documentation_uri: https://www.rubydoc.info/gems/extralite
|
135
135
|
homepage_uri: https://github.com/digital-fabric/extralite
|
136
136
|
changelog_uri: https://github.com/digital-fabric/extralite/blob/master/CHANGELOG.md
|
137
|
-
post_install_message:
|
137
|
+
post_install_message:
|
138
138
|
rdoc_options:
|
139
139
|
- "--title"
|
140
140
|
- extralite
|
@@ -153,8 +153,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
153
153
|
- !ruby/object:Gem::Version
|
154
154
|
version: '0'
|
155
155
|
requirements: []
|
156
|
-
rubygems_version: 3.3.
|
157
|
-
signing_key:
|
156
|
+
rubygems_version: 3.3.7
|
157
|
+
signing_key:
|
158
158
|
specification_version: 4
|
159
159
|
summary: Extra-lightweight SQLite3 wrapper for Ruby with bundled SQLite3
|
160
160
|
test_files: []
|