Skip to content

Commit

Permalink
Add isExplain and isReadOnly to statements
Browse files Browse the repository at this point in the history
  • Loading branch information
simolus3 committed Feb 13, 2024
1 parent 4cac1e4 commit d0c903a
Show file tree
Hide file tree
Showing 11 changed files with 111 additions and 3 deletions.
3 changes: 2 additions & 1 deletion sqlite3/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## 2.3.1-dev
## 2.4.0

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

Expand Down
2 changes: 2 additions & 0 deletions sqlite3/assets/sqlite3.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ int sqlite3_prepare_v3(sqlite3 *db, const sqlite3_char *zSql, int nByte,
int sqlite3_finalize(sqlite3_stmt *pStmt);
int sqlite3_step(sqlite3_stmt *pStmt);
int sqlite3_reset(sqlite3_stmt *pStmt);
int sqlite3_stmt_isexplain(sqlite3_stmt *pStmt);
int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);

int sqlite3_column_count(sqlite3_stmt *pStmt);
int sqlite3_bind_parameter_count(sqlite3_stmt *pStmt);
Expand Down
10 changes: 10 additions & 0 deletions sqlite3/lib/src/ffi/bindings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,16 @@ final class FfiStatement extends RawSqliteStatement {
return bindings.sqlite3_bind_parameter_count(stmt);
}

@override
int sqlite3_stmt_isexplain() {
return bindings.sqlite3_stmt_isexplain(stmt);
}

@override
int sqlite3_stmt_readonly() {
return bindings.sqlite3_stmt_readonly(stmt);
}

@override
int sqlite3_bind_parameter_index(String name) {
final ptr = Utf8Utils.allocateZeroTerminated(name);
Expand Down
28 changes: 28 additions & 0 deletions sqlite3/lib/src/ffi/sqlite3.g.dart
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,34 @@ class Bindings {
late final _sqlite3_reset =
_sqlite3_resetPtr.asFunction<int Function(ffi.Pointer<sqlite3_stmt>)>();

int sqlite3_stmt_isexplain(
ffi.Pointer<sqlite3_stmt> pStmt,
) {
return _sqlite3_stmt_isexplain(
pStmt,
);
}

late final _sqlite3_stmt_isexplainPtr =
_lookup<ffi.NativeFunction<ffi.Int Function(ffi.Pointer<sqlite3_stmt>)>>(
'sqlite3_stmt_isexplain');
late final _sqlite3_stmt_isexplain = _sqlite3_stmt_isexplainPtr
.asFunction<int Function(ffi.Pointer<sqlite3_stmt>)>();

int sqlite3_stmt_readonly(
ffi.Pointer<sqlite3_stmt> pStmt,
) {
return _sqlite3_stmt_readonly(
pStmt,
);
}

late final _sqlite3_stmt_readonlyPtr =
_lookup<ffi.NativeFunction<ffi.Int Function(ffi.Pointer<sqlite3_stmt>)>>(
'sqlite3_stmt_readonly');
late final _sqlite3_stmt_readonly = _sqlite3_stmt_readonlyPtr
.asFunction<int Function(ffi.Pointer<sqlite3_stmt>)>();

int sqlite3_column_count(
ffi.Pointer<sqlite3_stmt> pStmt,
) {
Expand Down
2 changes: 2 additions & 0 deletions sqlite3/lib/src/implementation/bindings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ abstract base class RawSqliteStatement {
Uint8List sqlite3_column_bytes(int index);

int sqlite3_bind_parameter_count();
int sqlite3_stmt_readonly();
int sqlite3_stmt_isexplain();
}

abstract base class RawSqliteContext {
Expand Down
6 changes: 6 additions & 0 deletions sqlite3/lib/src/implementation/statement.dart
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,12 @@ base class StatementImplementation extends CommonPreparedStatement {
@override
int get parameterCount => statement.sqlite3_bind_parameter_count();

@override
bool get isReadOnly => statement.sqlite3_stmt_readonly() != 0;

@override
bool get isExplain => statement.sqlite3_stmt_isexplain() != 0;

@override
ResultSet selectMap(Map<String, Object?> parameters) {
_ensureNotFinalized();
Expand Down
13 changes: 13 additions & 0 deletions sqlite3/lib/src/statement.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,19 @@ abstract class CommonPreparedStatement {
/// Returns the amount of parameters in this prepared statement.
int get parameterCount;

/// Returns whether this statement makes no direct changes to the contents of
/// the database file.
///
/// See also: https://www.sqlite.org/c3ref/stmt_readonly.html
bool get isReadOnly;

/// Whether this statement is either an `EXPLAIN` or an `EXPLAIN QUERY PLAN`
/// statement.
///
/// This uses `sqlite3_stmt_isexplain`, which is documented here:
/// https://www.sqlite.org/c3ref/stmt_isexplain.html
bool get isExplain;

/// {@template pkg_sqlite3_stmt_execute}
/// Executes this statement, ignoring result rows if there are any.
///
Expand Down
10 changes: 10 additions & 0 deletions sqlite3/lib/src/wasm/bindings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,16 @@ final class WasmStatement extends RawSqliteStatement {
return bindings.sqlite3_bind_parameter_count(stmt);
}

@override
int sqlite3_stmt_isexplain() {
return bindings.sqlite3_stmt_isexplain(stmt);
}

@override
int sqlite3_stmt_readonly() {
return bindings.sqlite3_stmt_readonly(stmt);
}

@override
int sqlite3_bind_parameter_index(String name) {
final namePtr = bindings.allocateZeroTerminated(name);
Expand Down
12 changes: 11 additions & 1 deletion sqlite3/lib/src/wasm/wasm_interop.dart
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,9 @@ class WasmBindings {
_sqlite3_value_text,
_sqlite3_value_blob,
_sqlite3_aggregate_context,
_sqlite3_get_autocommit;
_sqlite3_get_autocommit,
_sqlite3_stmt_readonly,
_sqlite3_stmt_isexplain;

final Function? _sqlite3_db_config;

Expand Down Expand Up @@ -154,6 +156,8 @@ class WasmBindings {
_sqlite3_aggregate_context =
instance.functions['sqlite3_aggregate_context']!,
_sqlite3_get_autocommit = instance.functions['sqlite3_get_autocommit']!,
_sqlite3_stmt_isexplain = instance.functions['sqlite3_stmt_isexplain']!,
_sqlite3_stmt_readonly = instance.functions['sqlite3_stmt_readonly']!,
_sqlite3_db_config = instance.functions['dart_sqlite3_db_config_int'],
_sqlite3_temp_directory = instance.globals['sqlite3_temp_directory']! {
values.bindings = this;
Expand Down Expand Up @@ -404,6 +408,12 @@ class WasmBindings {

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

int sqlite3_stmt_isexplain(Pointer stmt) =>
_sqlite3_stmt_isexplain(stmt) as int;

int sqlite3_stmt_readonly(Pointer stmt) =>
_sqlite3_stmt_readonly(stmt) as int;

int sqlite3_last_insert_rowid(Pointer db) =>
JsBigInt(_sqlite3_last_insert_rowid(db) as Object).asDartInt;

Expand Down
2 changes: 1 addition & 1 deletion sqlite3/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: sqlite3
description: Provides lightweight yet convenient bindings to SQLite by using dart:ffi
version: 2.3.0
version: 2.4.0
homepage: https://github.com/simolus3/sqlite3.dart/tree/main/sqlite3
issue_tracker: https://github.com/simolus3/sqlite3.dart/issues

Expand Down
26 changes: 26 additions & 0 deletions sqlite3/test/common/prepared_statement.dart
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,32 @@ void testPreparedStatements(
expect(stmt.select, throwsStateError);
});

test('parameterCount', () {
final opened = sqlite3.openInMemory();
addTearDown(opened.dispose);

expect(opened.prepare('SELECT 1').parameterCount, 0);
expect(opened.prepare('SELECT 1, ?2 AS r').parameterCount, 2);
});

test('isReadOnly', () {
final opened = sqlite3.openInMemory()
..execute('CREATE TABLE tbl (a TEXT);');
addTearDown(opened.dispose);

expect(opened.prepare('SELECT 1').isReadOnly, isTrue);
expect(opened.prepare('UPDATE tbl SET a = a || ?').isReadOnly, isFalse);
});

test('isExplain', () {
final opened = sqlite3.openInMemory()
..execute('CREATE TABLE tbl (a TEXT);');
addTearDown(opened.dispose);

expect(opened.prepare('SELECT 1').isExplain, isFalse);
expect(opened.prepare('EXPLAIN SELECT 1').isExplain, isTrue);
});

Uint8List? insertBlob(Uint8List? value) {
final opened = sqlite3.openInMemory();
opened.execute('CREATE TABLE tbl (x BLOB);');
Expand Down

0 comments on commit d0c903a

Please sign in to comment.