Skip to content

Commit d0c903a

Browse files
committed
Add isExplain and isReadOnly to statements
1 parent 4cac1e4 commit d0c903a

11 files changed

+111
-3
lines changed

sqlite3/CHANGELOG.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
## 2.3.1-dev
1+
## 2.4.0
22

3+
- Add `isReadOnly` and `isExplain` getters to prepared statements.
34
- Set `NativeCallable.keepIsolateAlive` to `false` for callables managed by
45
this package.
56

sqlite3/assets/sqlite3.h

+2
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ int sqlite3_prepare_v3(sqlite3 *db, const sqlite3_char *zSql, int nByte,
4646
int sqlite3_finalize(sqlite3_stmt *pStmt);
4747
int sqlite3_step(sqlite3_stmt *pStmt);
4848
int sqlite3_reset(sqlite3_stmt *pStmt);
49+
int sqlite3_stmt_isexplain(sqlite3_stmt *pStmt);
50+
int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
4951

5052
int sqlite3_column_count(sqlite3_stmt *pStmt);
5153
int sqlite3_bind_parameter_count(sqlite3_stmt *pStmt);

sqlite3/lib/src/ffi/bindings.dart

+10
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,16 @@ final class FfiStatement extends RawSqliteStatement {
420420
return bindings.sqlite3_bind_parameter_count(stmt);
421421
}
422422

423+
@override
424+
int sqlite3_stmt_isexplain() {
425+
return bindings.sqlite3_stmt_isexplain(stmt);
426+
}
427+
428+
@override
429+
int sqlite3_stmt_readonly() {
430+
return bindings.sqlite3_stmt_readonly(stmt);
431+
}
432+
423433
@override
424434
int sqlite3_bind_parameter_index(String name) {
425435
final ptr = Utf8Utils.allocateZeroTerminated(name);

sqlite3/lib/src/ffi/sqlite3.g.dart

+28
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,34 @@ class Bindings {
432432
late final _sqlite3_reset =
433433
_sqlite3_resetPtr.asFunction<int Function(ffi.Pointer<sqlite3_stmt>)>();
434434

435+
int sqlite3_stmt_isexplain(
436+
ffi.Pointer<sqlite3_stmt> pStmt,
437+
) {
438+
return _sqlite3_stmt_isexplain(
439+
pStmt,
440+
);
441+
}
442+
443+
late final _sqlite3_stmt_isexplainPtr =
444+
_lookup<ffi.NativeFunction<ffi.Int Function(ffi.Pointer<sqlite3_stmt>)>>(
445+
'sqlite3_stmt_isexplain');
446+
late final _sqlite3_stmt_isexplain = _sqlite3_stmt_isexplainPtr
447+
.asFunction<int Function(ffi.Pointer<sqlite3_stmt>)>();
448+
449+
int sqlite3_stmt_readonly(
450+
ffi.Pointer<sqlite3_stmt> pStmt,
451+
) {
452+
return _sqlite3_stmt_readonly(
453+
pStmt,
454+
);
455+
}
456+
457+
late final _sqlite3_stmt_readonlyPtr =
458+
_lookup<ffi.NativeFunction<ffi.Int Function(ffi.Pointer<sqlite3_stmt>)>>(
459+
'sqlite3_stmt_readonly');
460+
late final _sqlite3_stmt_readonly = _sqlite3_stmt_readonlyPtr
461+
.asFunction<int Function(ffi.Pointer<sqlite3_stmt>)>();
462+
435463
int sqlite3_column_count(
436464
ffi.Pointer<sqlite3_stmt> pStmt,
437465
) {

sqlite3/lib/src/implementation/bindings.dart

+2
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,8 @@ abstract base class RawSqliteStatement {
164164
Uint8List sqlite3_column_bytes(int index);
165165

166166
int sqlite3_bind_parameter_count();
167+
int sqlite3_stmt_readonly();
168+
int sqlite3_stmt_isexplain();
167169
}
168170

169171
abstract base class RawSqliteContext {

sqlite3/lib/src/implementation/statement.dart

+6
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,12 @@ base class StatementImplementation extends CommonPreparedStatement {
306306
@override
307307
int get parameterCount => statement.sqlite3_bind_parameter_count();
308308

309+
@override
310+
bool get isReadOnly => statement.sqlite3_stmt_readonly() != 0;
311+
312+
@override
313+
bool get isExplain => statement.sqlite3_stmt_isexplain() != 0;
314+
309315
@override
310316
ResultSet selectMap(Map<String, Object?> parameters) {
311317
_ensureNotFinalized();

sqlite3/lib/src/statement.dart

+13
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,19 @@ abstract class CommonPreparedStatement {
1111
/// Returns the amount of parameters in this prepared statement.
1212
int get parameterCount;
1313

14+
/// Returns whether this statement makes no direct changes to the contents of
15+
/// the database file.
16+
///
17+
/// See also: https://www.sqlite.org/c3ref/stmt_readonly.html
18+
bool get isReadOnly;
19+
20+
/// Whether this statement is either an `EXPLAIN` or an `EXPLAIN QUERY PLAN`
21+
/// statement.
22+
///
23+
/// This uses `sqlite3_stmt_isexplain`, which is documented here:
24+
/// https://www.sqlite.org/c3ref/stmt_isexplain.html
25+
bool get isExplain;
26+
1427
/// {@template pkg_sqlite3_stmt_execute}
1528
/// Executes this statement, ignoring result rows if there are any.
1629
///

sqlite3/lib/src/wasm/bindings.dart

+10
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,16 @@ final class WasmStatement extends RawSqliteStatement {
350350
return bindings.sqlite3_bind_parameter_count(stmt);
351351
}
352352

353+
@override
354+
int sqlite3_stmt_isexplain() {
355+
return bindings.sqlite3_stmt_isexplain(stmt);
356+
}
357+
358+
@override
359+
int sqlite3_stmt_readonly() {
360+
return bindings.sqlite3_stmt_readonly(stmt);
361+
}
362+
353363
@override
354364
int sqlite3_bind_parameter_index(String name) {
355365
final namePtr = bindings.allocateZeroTerminated(name);

sqlite3/lib/src/wasm/wasm_interop.dart

+11-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,9 @@ class WasmBindings {
7878
_sqlite3_value_text,
7979
_sqlite3_value_blob,
8080
_sqlite3_aggregate_context,
81-
_sqlite3_get_autocommit;
81+
_sqlite3_get_autocommit,
82+
_sqlite3_stmt_readonly,
83+
_sqlite3_stmt_isexplain;
8284

8385
final Function? _sqlite3_db_config;
8486

@@ -154,6 +156,8 @@ class WasmBindings {
154156
_sqlite3_aggregate_context =
155157
instance.functions['sqlite3_aggregate_context']!,
156158
_sqlite3_get_autocommit = instance.functions['sqlite3_get_autocommit']!,
159+
_sqlite3_stmt_isexplain = instance.functions['sqlite3_stmt_isexplain']!,
160+
_sqlite3_stmt_readonly = instance.functions['sqlite3_stmt_readonly']!,
157161
_sqlite3_db_config = instance.functions['dart_sqlite3_db_config_int'],
158162
_sqlite3_temp_directory = instance.globals['sqlite3_temp_directory']! {
159163
values.bindings = this;
@@ -404,6 +408,12 @@ class WasmBindings {
404408

405409
int sqlite3_changes(Pointer db) => _sqlite3_changes(db) as int;
406410

411+
int sqlite3_stmt_isexplain(Pointer stmt) =>
412+
_sqlite3_stmt_isexplain(stmt) as int;
413+
414+
int sqlite3_stmt_readonly(Pointer stmt) =>
415+
_sqlite3_stmt_readonly(stmt) as int;
416+
407417
int sqlite3_last_insert_rowid(Pointer db) =>
408418
JsBigInt(_sqlite3_last_insert_rowid(db) as Object).asDartInt;
409419

sqlite3/pubspec.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: sqlite3
22
description: Provides lightweight yet convenient bindings to SQLite by using dart:ffi
3-
version: 2.3.0
3+
version: 2.4.0
44
homepage: https://github.com/simolus3/sqlite3.dart/tree/main/sqlite3
55
issue_tracker: https://github.com/simolus3/sqlite3.dart/issues
66

sqlite3/test/common/prepared_statement.dart

+26
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,32 @@ void testPreparedStatements(
7777
expect(stmt.select, throwsStateError);
7878
});
7979

80+
test('parameterCount', () {
81+
final opened = sqlite3.openInMemory();
82+
addTearDown(opened.dispose);
83+
84+
expect(opened.prepare('SELECT 1').parameterCount, 0);
85+
expect(opened.prepare('SELECT 1, ?2 AS r').parameterCount, 2);
86+
});
87+
88+
test('isReadOnly', () {
89+
final opened = sqlite3.openInMemory()
90+
..execute('CREATE TABLE tbl (a TEXT);');
91+
addTearDown(opened.dispose);
92+
93+
expect(opened.prepare('SELECT 1').isReadOnly, isTrue);
94+
expect(opened.prepare('UPDATE tbl SET a = a || ?').isReadOnly, isFalse);
95+
});
96+
97+
test('isExplain', () {
98+
final opened = sqlite3.openInMemory()
99+
..execute('CREATE TABLE tbl (a TEXT);');
100+
addTearDown(opened.dispose);
101+
102+
expect(opened.prepare('SELECT 1').isExplain, isFalse);
103+
expect(opened.prepare('EXPLAIN SELECT 1').isExplain, isTrue);
104+
});
105+
80106
Uint8List? insertBlob(Uint8List? value) {
81107
final opened = sqlite3.openInMemory();
82108
opened.execute('CREATE TABLE tbl (x BLOB);');

0 commit comments

Comments
 (0)