Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions sqlite3/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
- Add `RawPreparedStatement.columnBytes` and `RawPreparedStatement.columnBlobInto`, which copies a
column into an existing buffer instead of allocating a new list for each value.
- Hooks: `defines` accepts a map with per-OS entries and a `default`, like `source` and `name`.
- Add `CommonDatabase.status()` (`sqlite3_db_status64`, requires SQLite 3.51.0 or newer) on all
platforms, and `Database.releaseMemory()` (`sqlite3_db_release_memory`) on native platforms.

## 3.6.0

Expand Down
3 changes: 3 additions & 0 deletions sqlite3/assets/sqlite3.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ void* sqlite3_update_hook(sqlite3*,
void* sqlite3_commit_hook(sqlite3*, int (*)(void*), void*);
void* sqlite3_rollback_hook(sqlite3*, void (*)(void*), void*);
int sqlite3_get_autocommit(sqlite3* db);
int sqlite3_db_release_memory(sqlite3* db);
int sqlite3_db_status64(sqlite3* db, int op, int64_t* pCur, int64_t* pHiwtr,
int resetFlg);

// Statements
int sqlite3_prepare_v2(sqlite3* db, const sqlite3_char* zSql, int nByte,
Expand Down
71 changes: 71 additions & 0 deletions sqlite3/lib/src/database.dart
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,22 @@ abstract class CommonDatabase {
/// For details, see https://www.sqlite.org/c3ref/get_autocommit.html
bool get autocommit;

/// Returns runtime status information about this connection, such as the
/// amount of memory used by its page cache ([DatabaseStatus.cacheUsed]).
///
/// Not every [option] reports a meaningful `highwater` value, see the
/// documentation of the options for details. When [reset] is set, the
/// highest value is reset after reading it.
///
/// This requires SQLite 3.51.0 or newer, as it uses `sqlite3_db_status64`.
/// With older SQLite libraries or `sqlite3.wasm` bundles, this throws.
///
/// See https://sqlite.org/c3ref/db_status.html
({int current, int highwater}) status(
DatabaseStatus option, {
bool reset = false,
});

/// Closes this database and releases associated resources.
@Deprecated('Call close() instead')
void dispose();
Expand All @@ -302,6 +318,61 @@ abstract class CommonDatabase {
void close();
}

/// Status parameters that can be queried with [CommonDatabase.status].
///
/// See https://sqlite.org/c3ref/c_dbstatus_options.html for a description of
/// each option.
///
/// {@category common}
enum DatabaseStatus {
/// `SQLITE_DBSTATUS_LOOKASIDE_USED`
lookasideUsed(0),

/// `SQLITE_DBSTATUS_CACHE_USED`
cacheUsed(1),

/// `SQLITE_DBSTATUS_SCHEMA_USED`
schemaUsed(2),

/// `SQLITE_DBSTATUS_STMT_USED`
statementUsed(3),

/// `SQLITE_DBSTATUS_LOOKASIDE_HIT`
lookasideHit(4),

/// `SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE`
lookasideMissSize(5),

/// `SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL`
lookasideMissFull(6),

/// `SQLITE_DBSTATUS_CACHE_HIT`
cacheHit(7),

/// `SQLITE_DBSTATUS_CACHE_MISS`
cacheMiss(8),

/// `SQLITE_DBSTATUS_CACHE_WRITE`
cacheWrite(9),

/// `SQLITE_DBSTATUS_DEFERRED_FKS`
deferredForeignKeys(10),

/// `SQLITE_DBSTATUS_CACHE_USED_SHARED`
cacheUsedShared(11),

/// `SQLITE_DBSTATUS_CACHE_SPILL`
cacheSpill(12),

/// `SQLITE_DBSTATUS_TEMPBUF_SPILL`
tempBufferSpill(13);

/// The numeric `SQLITE_DBSTATUS_*` value passed to SQLite.
final int code;

const DatabaseStatus(this.code);
}

/// The kind of an [SqliteUpdate] received through a [CommonDatabase.updates]
/// stream.
///
Expand Down
6 changes: 6 additions & 0 deletions sqlite3/lib/src/ffi/api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,12 @@ abstract class Database extends CommonDatabase {
///
/// See https://www.sqlite.org/c3ref/backup_finish.html
Stream<double> backup(Database toDatabase, {int nPage = 5});

/// Frees as much heap memory as possible from this connection, mostly by
/// releasing unused pages from its page cache.
///
/// See https://sqlite.org/c3ref/db_release_memory.html
void releaseMemory();
}

/// A prepared statement.
Expand Down
18 changes: 18 additions & 0 deletions sqlite3/lib/src/ffi/bindings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1092,6 +1092,24 @@ final class FfiDatabase implements RawSqliteDatabase, Finalizable {
return libsqlite3.sqlite3_get_autocommit(db);
}

@override
({int resultCode, int current, int highwater}) sqlite3_db_status64(
int op,
int resetFlg,
) {
final values = allocate<Int64>(2);
final rc = libsqlite3.sqlite3_db_status64(
db,
op,
values,
values + 1,
resetFlg,
);
final result = (resultCode: rc, current: values[0], highwater: values[1]);
values.free();
return result;
}

@override
int sqlite3_busy_handler(int Function(int)? callback) {
if (callback == null) {
Expand Down
8 changes: 8 additions & 0 deletions sqlite3/lib/src/ffi/implementation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,14 @@ final class FfiDatabaseImplementation extends DatabaseImplementation
}
}

@override
void releaseMemory() {
final rc = libsqlite3.sqlite3_db_release_memory(ffiDatabase.db);
if (rc != SqlError.SQLITE_OK) {
throwException(this, rc, operation: 'releasing memory');
}
}

@override
Pointer<void> get handle => ffiDatabase.db;

Expand Down
35 changes: 35 additions & 0 deletions sqlite3/lib/src/ffi/libsqlite3.g.dart
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,26 @@ external ffi.Pointer<sqlite3_char> sqlite3_db_filename(
ffi.Pointer<sqlite3_char> zDbName,
);

@ffi.Native<ffi.Int Function(ffi.Pointer<sqlite3>)>()
external int sqlite3_db_release_memory(ffi.Pointer<sqlite3> db);

@ffi.Native<
ffi.Int Function(
ffi.Pointer<sqlite3>,
ffi.Int,
ffi.Pointer<ffi.Int64>,
ffi.Pointer<ffi.Int64>,
ffi.Int,
)
>()
external int sqlite3_db_status64(
ffi.Pointer<sqlite3> db,
int op,
ffi.Pointer<ffi.Int64> pCur,
ffi.Pointer<ffi.Int64> pHiwtr,
int resetFlg,
);

@ffi.Native<ffi.Pointer<sqlite3_char> Function(ffi.Pointer<sqlite3>)>()
external ffi.Pointer<sqlite3_char> sqlite3_errmsg(ffi.Pointer<sqlite3> db);

Expand Down Expand Up @@ -1171,6 +1191,21 @@ class _SymbolAddresses {
>
>
get sqlite3_db_filename => ffi.Native.addressOf(self.sqlite3_db_filename);
ffi.Pointer<ffi.NativeFunction<ffi.Int Function(ffi.Pointer<sqlite3>)>>
get sqlite3_db_release_memory =>
ffi.Native.addressOf(self.sqlite3_db_release_memory);
ffi.Pointer<
ffi.NativeFunction<
ffi.Int Function(
ffi.Pointer<sqlite3>,
ffi.Int,
ffi.Pointer<ffi.Int64>,
ffi.Pointer<ffi.Int64>,
ffi.Int,
)
>
>
get sqlite3_db_status64 => ffi.Native.addressOf(self.sqlite3_db_status64);
ffi.Pointer<
ffi.NativeFunction<ffi.Pointer<sqlite3_char> Function(ffi.Pointer<sqlite3>)>
>
Expand Down
2 changes: 2 additions & 0 deletions sqlite3/lib/src/hook/compile/used_symbols.dart
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ const usedSqliteSymbols = {
'sqlite3_create_window_function',
'sqlite3_db_config',
'sqlite3_db_filename',
'sqlite3_db_release_memory',
'sqlite3_db_status64',
'sqlite3_errmsg',
'sqlite3_error_offset',
'sqlite3_errstr',
Expand Down
5 changes: 5 additions & 0 deletions sqlite3/lib/src/implementation/bindings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,11 @@ abstract interface class RawSqliteDatabase {

int sqlite3_db_config(int op, int value);
int sqlite3_get_autocommit();

({int resultCode, int current, int highwater}) sqlite3_db_status64(
int op,
int resetFlg,
);
}

/// A stateful wrapper around multiple `sqlite3_prepare` invocations.
Expand Down
17 changes: 17 additions & 0 deletions sqlite3/lib/src/implementation/database.dart
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,23 @@ base class DatabaseImplementation implements CommonDatabase {
return database.sqlite3_get_autocommit() != 0;
}

@override
({int current, int highwater}) status(
DatabaseStatus option, {
bool reset = false,
}) {
final result = database.sqlite3_db_status64(option.code, reset ? 1 : 0);
if (result.resultCode != SqlError.SQLITE_OK) {
// sqlite3_db_status64 doesn't set an error message on the connection.
throw createExceptionOutsideOfDatabase(
bindings,
result.resultCode,
operation: 'sqlite3_db_status64',
);
}
return (current: result.current, highwater: result.highwater);
}

@override
set busyHandler(bool Function(int count)? handler) {
final result = database.sqlite3_busy_handler(switch (handler) {
Expand Down
22 changes: 22 additions & 0 deletions sqlite3/lib/src/wasm/bindings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,28 @@ final class WasmDatabase implements RawSqliteDatabase {
return bindings.sqlite3_get_autocommit(db);
}

@override
({int resultCode, int current, int highwater}) sqlite3_db_status64(
int op,
int resetFlg,
) {
final values = bindings.malloc(16);
final rc = bindings.sqlite3_db_status64(
db,
op,
values,
values + 8,
resetFlg,
);
final result = (
resultCode: rc,
current: bindings.memory.int64ValueOfPointer(values).asDartInt,
highwater: bindings.memory.int64ValueOfPointer(values + 8).asDartInt,
);
bindings.free(values);
return result;
}

@override
int sqlite3_db_config(int op, int value) {
return bindings.sqlite3_db_config(db, op, value);
Expand Down
10 changes: 10 additions & 0 deletions sqlite3/lib/src/wasm/js_interop/typed_data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@ extension NativeUint8List on Uint8List {
}

extension NativeDataView on ByteData {
JsBigInt getBigInt64(int offset, bool littleEndian) {
return JsBigInt(
toJS.callMethod<JSBigInt>(
'getBigInt64'.toJS,
offset.toJS,
littleEndian.toJS,
),
);
}

void setBigInt64(int offset, JsBigInt value, bool littleEndian) {
toJS.callMethod(
'setBigInt64'.toJS,
Expand Down
1 change: 1 addition & 0 deletions sqlite3/lib/src/wasm/sqlite3_wasm.g.dart
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ extension type SqliteExports(JSObject raw) implements JSObject {
int iCol,
);
external int sqlite3_db_config(Pointer /*<struct sqlite3 *>*/ db, int op);
external JSFunction? get sqlite3_db_status64;
external Pointer /*<struct sqlite3_char *>*/ sqlite3_errmsg(
Pointer /*<struct sqlite3 *>*/ db,
);
Expand Down
30 changes: 30 additions & 0 deletions sqlite3/lib/src/wasm/wasm_interop.dart
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,31 @@ class WasmBindings {

int sqlite3_get_autocommit(Pointer db) => sqlite3.sqlite3_get_autocommit(db);

int sqlite3_db_status64(
Pointer db,
int op,
Pointer pCur,
Pointer pHiwtr,
int resetFlg,
) {
final function = sqlite3.sqlite3_db_status64;
if (function == null) {
throw UnsupportedError(
'sqlite3_db_status64 is not supported by this sqlite3.wasm, try '
'upgrading to a more recent version.',
);
}

return function.callMethodVarArgs<JSNumber>('call'.toJS, [
null,
db.toJS,
op.toJS,
pCur.toJS,
pHiwtr.toJS,
resetFlg.toJS,
]).toDartInt;
}

int sqlite3_db_config(Pointer db, int op, int value) {
return sqlite3.dart_sqlite3_db_config_int(db, op, value);
}
Expand Down Expand Up @@ -464,6 +489,11 @@ extension WrappedMemory on Memory {
dartBuffer.asInt32List()[pointer >> 2] = value;
}

JsBigInt int64ValueOfPointer(Pointer pointer) {
assert(pointer != 0, 'Null pointer dereference');
return dartBuffer.asByteData().getBigInt64(pointer, true);
}

void setInt64Value(Pointer pointer, JsBigInt value) {
assert(pointer != 0, 'Null pointer dereference');
dartBuffer.asByteData().setBigInt64(pointer, value, true);
Expand Down
Loading
Loading