Patch set 4:Commit-Queue +1
2 comments:
Patchset:
Hi Michael,
I noticed our ffi sqlite sample wasn't working anymore.
Kind regards,
Daco
File samples/ffi/sqlite/lib/src/database.dart:
Patch Set #1, Line 286: query.reachabilityFence();
We can avoid this if we extend NativeResource to also stay alive till after methods in which it is a […]
Done
To view, visit change 143804. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Michael Thomsen.
Daco Harkes would like Michael Thomsen to review this change.
[samples/ffi] Update sqlite sample
The sample wasn't working for the longest time.
Fixes:
- Null safety, and late fields.
- `dart pub` instead of `pub`.
- Use the new `NativeFinalizer` and `Finalizable` features.
Change-Id: I0a397abae511ab3f6762d1b2c4047226d15e36d6
---
M samples/ffi/sqlite/README.md
M samples/ffi/sqlite/lib/src/bindings/bindings.dart
M samples/ffi/sqlite/lib/src/database.dart
M samples/ffi/sqlite/pubspec.yaml
4 files changed, 160 insertions(+), 49 deletions(-)
diff --git a/samples/ffi/sqlite/README.md b/samples/ffi/sqlite/README.md
index fbd5cb9..a7c65ad 100644
--- a/samples/ffi/sqlite/README.md
+++ b/samples/ffi/sqlite/README.md
@@ -23,7 +23,7 @@
Running `pub get` and `pub run example/main` should produce the following output.
```sh
-$ pub get
+$ dart pub get
Resolving dependencies... (6.8s)
+ analyzer 0.35.4
...
@@ -38,7 +38,7 @@
```
```
-$ pub run example/main
+$ dart pub run example/main
1 Chocolade chip cookie Chocolade cookie foo
2 Ginger cookie null 42
3 Cinnamon roll null null
diff --git a/samples/ffi/sqlite/lib/src/bindings/bindings.dart b/samples/ffi/sqlite/lib/src/bindings/bindings.dart
index a3d73bd..c262829 100644
--- a/samples/ffi/sqlite/lib/src/bindings/bindings.dart
+++ b/samples/ffi/sqlite/lib/src/bindings/bindings.dart
@@ -34,6 +34,10 @@
Pointer<Utf8> vfs) sqlite3_open_v2;
late int Function(Pointer<Database> database) sqlite3_close_v2;
+ late Pointer<NativeFunction<sqlite3_close_v2_native_t>>
+ sqlite3_close_v2_native;
+ late Pointer<NativeFunction<Void Function(Pointer<Database> database)>>
+ sqlite3_close_v2_native_return_void;
/// Compiling An SQL Statement
///
@@ -214,6 +218,10 @@
/// statement after it has been finalized can result in undefined and
/// undesirable behavior such as segfaults and heap corruption.
late int Function(Pointer<Statement> statement) sqlite3_finalize;
+ late Pointer<NativeFunction<sqlite3_finalize_native_t>>
+ sqlite3_finalize_native;
+ late Pointer<NativeFunction<Void Function(Pointer<Statement> statement)>>
+ sqlite3_finalize_native_return_void;
/// Number Of Columns In A Result Set
///
@@ -336,9 +344,10 @@
sqlite3_open_v2 = sqlite
.lookup<NativeFunction<sqlite3_open_v2_native_t>>("sqlite3_open_v2")
.asFunction();
- sqlite3_close_v2 = sqlite
- .lookup<NativeFunction<sqlite3_close_v2_native_t>>("sqlite3_close_v2")
- .asFunction();
+ sqlite3_close_v2_native = sqlite
+ .lookup<NativeFunction<sqlite3_close_v2_native_t>>("sqlite3_close_v2");
+ sqlite3_close_v2_native_return_void = sqlite3_close_v2_native.cast();
+ sqlite3_close_v2 = sqlite3_close_v2_native.asFunction();
sqlite3_prepare_v2 = sqlite
.lookup<NativeFunction<sqlite3_prepare_v2_native_t>>(
"sqlite3_prepare_v2")
@@ -349,9 +358,10 @@
sqlite3_reset = sqlite
.lookup<NativeFunction<sqlite3_reset_native_t>>("sqlite3_reset")
.asFunction();
- sqlite3_finalize = sqlite
- .lookup<NativeFunction<sqlite3_finalize_native_t>>("sqlite3_finalize")
- .asFunction();
+ sqlite3_finalize_native = sqlite
+ .lookup<NativeFunction<sqlite3_finalize_native_t>>("sqlite3_finalize");
+ sqlite3_finalize_native_return_void = sqlite3_finalize_native.cast();
+ sqlite3_finalize = sqlite3_finalize_native.asFunction();
sqlite3_errstr = sqlite
.lookup<NativeFunction<sqlite3_errstr_native_t>>("sqlite3_errstr")
.asFunction();
diff --git a/samples/ffi/sqlite/lib/src/database.dart b/samples/ffi/sqlite/lib/src/database.dart
index 9b0570c..fa6a8d5 100644
--- a/samples/ffi/sqlite/lib/src/database.dart
+++ b/samples/ffi/sqlite/lib/src/database.dart
@@ -21,19 +21,19 @@
///
/// This database interacts with SQLite synchonously.
class Database {
- late Pointer<types.Database> _database;
+ late DatabaseResource _database;
bool _open = false;
/// Open a database located at the file [path].
Database(String path,
[int flags = Flags.SQLITE_OPEN_READWRITE | Flags.SQLITE_OPEN_CREATE]) {
Pointer<Pointer<types.Database>> dbOut = calloc();
- final pathC = path.toNativeUtf8();
+ final pathC = Utf8Resource(path.toNativeUtf8());
final int resultCode =
- bindings.sqlite3_open_v2(pathC, dbOut, flags, nullptr);
- _database = dbOut.value;
+ bindings.sqlite3_open_v2(pathC.unsafe(), dbOut, flags, nullptr);
+ _database = DatabaseResource(dbOut.value);
calloc.free(dbOut);
- calloc.free(pathC);
+ pathC.free();
if (resultCode == Errors.SQLITE_OK) {
_open = true;
@@ -53,7 +53,7 @@
/// avoid resource leaks.
void close() {
assert(_open);
- final int resultCode = bindings.sqlite3_close_v2(_database);
+ final int resultCode = _database.close();
if (resultCode == Errors.SQLITE_OK) {
_open = false;
} else {
@@ -63,18 +63,17 @@
/// Execute a query, discarding any returned rows.
void execute(String query) {
- Pointer<Pointer<Statement>> statementOut = calloc();
- Pointer<Utf8> queryC = query.toNativeUtf8();
- int resultCode = bindings.sqlite3_prepare_v2(
- _database, queryC, -1, statementOut, nullptr);
- Pointer<Statement> statement = statementOut.value;
+ Pointer<Pointer<Statement>> statementOut = malloc();
+ final queryC = Utf8Resource(query.toNativeUtf8());
+ int resultCode = _database.prepare(queryC, -1, statementOut, nullptr);
+ final statement = StatementResource(statementOut.value);
calloc.free(statementOut);
- calloc.free(queryC);
+ queryC.free();
while (resultCode == Errors.SQLITE_ROW || resultCode == Errors.SQLITE_OK) {
- resultCode = bindings.sqlite3_step(statement);
+ resultCode = statement.step();
}
- bindings.sqlite3_finalize(statement);
+ statement.finalize();
if (resultCode != Errors.SQLITE_DONE) {
throw _loadError(resultCode);
}
@@ -82,32 +81,33 @@
/// Evaluate a query and return the resulting rows as an iterable.
Result query(String query) {
- Pointer<Pointer<Statement>> statementOut = calloc();
- Pointer<Utf8> queryC = query.toNativeUtf8();
- int resultCode = bindings.sqlite3_prepare_v2(
- _database, queryC, -1, statementOut, nullptr);
- Pointer<Statement> statement = statementOut.value;
+ Pointer<Pointer<Statement>> statementOut = malloc();
+ final queryC = Utf8Resource(query.toNativeUtf8());
+ int resultCode = _database.prepare(queryC, -1, statementOut, nullptr);
+ final statement = StatementResource(statementOut.value);
calloc.free(statementOut);
- calloc.free(queryC);
+ queryC.free();
if (resultCode != Errors.SQLITE_OK) {
- bindings.sqlite3_finalize(statement);
+ statement.finalize();
throw _loadError(resultCode);
}
Map<String, int> columnIndices = {};
- int columnCount = bindings.sqlite3_column_count(statement);
+ int columnCount = statement.columnCount;
for (int i = 0; i < columnCount; i++) {
- String columnName =
- bindings.sqlite3_column_name(statement, i).toDartString();
+ String columnName = statement.columnName(i);
columnIndices[columnName] = i;
}
return Result._(this, statement, columnIndices);
}
- SQLiteException _loadError(int errorCode) {
- String errorMessage = bindings.sqlite3_errmsg(_database).toDartString();
+ SQLiteException _loadError([int? errorCode]) {
+ String errorMessage = _database.errmsg().toDartString();
+ if (errorCode == null) {
+ return SQLiteException(errorMessage);
+ }
String errorCodeExplanation =
bindings.sqlite3_errstr(errorCode).toDartString();
return SQLiteException(
@@ -125,7 +125,7 @@
Result._(
Database database,
- Pointer<Statement> statement,
+ StatementResource statement,
Map<String, int> columnIndices,
) : _iterator = _ResultIterator(statement, columnIndices) {}
@@ -135,7 +135,7 @@
}
class _ResultIterator implements ClosableIterator<Row> {
- final Pointer<Statement> _statement;
+ final StatementResource _statement;
final Map<String, int> _columnIndices;
Row? _currentRow;
@@ -148,7 +148,7 @@
throw SQLiteException("The result has already been closed.");
}
_currentRow?._setNotCurrent();
- int stepResult = bindings.sqlite3_step(_statement);
+ int stepResult = _statement.step();
if (stepResult == Errors.SQLITE_ROW) {
_currentRow = Row._(_statement, _columnIndices);
return true;
@@ -168,12 +168,12 @@
void close() {
_currentRow?._setNotCurrent();
_closed = true;
- bindings.sqlite3_finalize(_statement);
+ _statement.finalize();
}
}
class Row {
- final Pointer<Statement> _statement;
+ final StatementResource _statement;
final Map<String, int> _columnIndices;
bool _isCurrentRow = true;
@@ -201,12 +201,10 @@
Type dynamicType;
if (convert == Convert.DynamicType) {
- dynamicType =
- _typeFromCode(bindings.sqlite3_column_type(_statement, columnIndex));
+ dynamicType = _typeFromCode(_statement.columnType(columnIndex));
} else {
- dynamicType = _typeFromText(bindings
- .sqlite3_column_decltype(_statement, columnIndex)
- .toDartString());
+ dynamicType =
+ _typeFromText(_statement.columnDecltype(columnIndex).toDartString());
}
switch (dynamicType) {
@@ -230,7 +228,7 @@
/// integer.
int readColumnByIndexAsInt(int columnIndex) {
_checkIsCurrentRow();
- return bindings.sqlite3_column_int(_statement, columnIndex);
+ return _statement.columnInt(columnIndex);
}
/// Reads column [columnName] and converts to [Type.Text] if not text.
@@ -241,7 +239,7 @@
/// Reads column [columnIndex] and converts to [Type.Text] if not text.
String readColumnByIndexAsText(int columnIndex) {
_checkIsCurrentRow();
- return bindings.sqlite3_column_text(_statement, columnIndex).toDartString();
+ return _statement.columnText(columnIndex).toDartString();
}
void _checkIsCurrentRow() {
@@ -257,6 +255,93 @@
}
}
+class DatabaseResource implements Finalizable {
+ static final NativeFinalizer _finalizer =
+ NativeFinalizer(bindings.sqlite3_close_v2_native_return_void.cast());
+
+ /// [_statement] must never escape [StatementResource], otherwise the
+ /// [_finalizer] will run prematurely.
+ Pointer<types.Database> _database;
+
+ DatabaseResource(this._database) {
+ _finalizer.attach(this, _database.cast(), detach: this);
+ }
+
+ int close() {
+ _finalizer.detach(this);
+ return bindings.sqlite3_close_v2(_database);
+ }
+
+ int prepare(Utf8Resource query, int nbytes,
+ Pointer<Pointer<Statement>> statementOut, Pointer<Pointer<Utf8>> tail) {
+ int result = bindings.sqlite3_prepare_v2(
+ _database, query.unsafe(), nbytes, statementOut, tail);
+ return result;
+ }
+
+ Pointer<Utf8> errmsg() => bindings.sqlite3_errmsg(_database);
+}
+
+class StatementResource implements Finalizable {
+ static final NativeFinalizer _finalizer =
+ NativeFinalizer(bindings.sqlite3_finalize_native_return_void.cast());
+
+ /// [_statement] must never escape [StatementResource], otherwise the
+ /// [_finalizer] will run prematurely.
+ final Pointer<Statement> _statement;
+
+ StatementResource(this._statement) {
+ _finalizer.attach(this, _statement.cast(), detach: this);
+ }
+
+ int finalize() {
+ _finalizer.detach(this);
+ return bindings.sqlite3_finalize(_statement);
+ }
+
+ int get columnCount => bindings.sqlite3_column_count(_statement);
+
+ String columnName(int index) =>
+ bindings.sqlite3_column_name(_statement, index).toDartString();
+
+ int step() => bindings.sqlite3_step(_statement);
+
+ int columnType(int columnIndex) =>
+ bindings.sqlite3_column_type(_statement, columnIndex);
+
+ Pointer<Utf8> columnDecltype(int columnIndex) =>
+ bindings.sqlite3_column_decltype(_statement, columnIndex);
+
+ int columnInt(int columnIndex) =>
+ bindings.sqlite3_column_int(_statement, columnIndex);
+
+ Pointer<Utf8> columnText(int columnIndex) =>
+ bindings.sqlite3_column_text(_statement, columnIndex);
+}
+
+class Utf8Resource implements Finalizable {
+ static final NativeFinalizer _finalizer = NativeFinalizer(posixFree);
+
+ /// [_cString] must never escape [Utf8Resource], otherwise the
+ /// [_finalizer] will run prematurely.
+ final Pointer<Utf8> _cString;
+
+ Utf8Resource(this._cString) {
+ _finalizer.attach(this, _cString.cast(), detach: this);
+ }
+
+ void free() {
+ _finalizer.detach(this);
+ calloc.free(_cString);
+ }
+
+ /// Ensure this [Utf8Resource] stays in scope longer than the inner resource.
+ Pointer<Utf8> unsafe() => _cString;
+}
+
+final DynamicLibrary stdlib = DynamicLibrary.process();
+final posixFree = stdlib.lookup<NativeFunction<Void Function(Pointer)>>("free");
+
Type _typeFromCode(int code) {
switch (code) {
case Types.SQLITE_INTEGER:
diff --git a/samples/ffi/sqlite/pubspec.yaml b/samples/ffi/sqlite/pubspec.yaml
index 90e67f4..6ad5097 100644
--- a/samples/ffi/sqlite/pubspec.yaml
+++ b/samples/ffi/sqlite/pubspec.yaml
@@ -2,10 +2,9 @@
version: 0.0.1
description: >-
Sqlite3 wrapper. Demo for dart:ffi.
-author: Daco Harkes <dacoh...@google.com>, Samir Jindel <sji...@google.com>
environment:
- sdk: '>=2.12.0-0 <3.0.0'
+ sdk: '>=2.17.0-0 <3.0.0'
dependencies:
ffi: ^1.1.2
dev_dependencies:
- test: ^1.16.0-nullsafety.12
+ test: ^1.21.1
To view, visit change 143804. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Michael Thomsen.
1 comment:
Patchset:
Hi Michael,
I noticed our ffi sqlite sample wasn't working anymore.
Kind regards,
Daco
To view, visit change 143804. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Daco Harkes, Michael Thomsen.
go/dart-cbuild result: SUCCESS
Details: https://goto.google.com/dart-cbuild/find/f869c62d6f8f807f809963317e2a6fe0a6cf40e6
Attention is currently required from: Daco Harkes.
1 comment:
Patchset:
Is this ready to submit?
To view, visit change 143804. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Michael Thomsen.
1 comment:
Patchset:
Is this ready to submit?
Yes, it's marked for review and awaiting your review.
To view, visit change 143804. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Daco Harkes.
4 comments:
Patchset:
Looks great, a few smaller comments
File samples/ffi/sqlite/README.md:
Patch Set #4, Line 23: Running `pub get` and `pub run example/main` should produce the following output.
just `dart run`
Patch Set #4, Line 41: $ dart pub run example/main
This is just `dart run example/main` now
File samples/ffi/sqlite/pubspec.yaml:
Patch Set #4, Line 6: sdk: '>=2.17.0-0 <3.0.0'
We can make this just `>=2.17.0 <3.0.0` as 2.17 stable is out.
To view, visit change 143804. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Michael Thomsen.
Patch set 6:Commit-Queue +2
4 comments:
Patchset:
Thanks Michael!
File samples/ffi/sqlite/README.md:
Patch Set #4, Line 23: Running `pub get` and `pub run example/main` should produce the following output.
just `dart run`
Done
Patch Set #4, Line 41: $ dart pub run example/main
This is just `dart run example/main` now
Done
File samples/ffi/sqlite/pubspec.yaml:
Patch Set #4, Line 6: sdk: '>=2.17.0-0 <3.0.0'
We can make this just `>=2.17.0 <3.0.0` as 2.17 stable is out.
Done
To view, visit change 143804. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Daco Harkes, Michael Thomsen.
go/dart-cbuild result: FAILURE (NO REGRESSIONS DETECTED)
Details: https://goto.google.com/dart-cbuild/find/95b59b06d6f8551ff547a03914c83a3c764c3985
Attention is currently required from: Daco Harkes.
Patch set 6:Code-Review +1
Patch set 6:Commit-Queue +2
1 comment:
Patchset:
Thanks Michael!
To view, visit change 143804. To unsubscribe, or for help writing mail filters, visit settings.
Commit Bot submitted this change.
[samples/ffi] Update sqlite sample
The sample wasn't working for the longest time.
Fixes:
- Null safety, and late fields.
- `dart pub` instead of `pub`.
- Use the new `NativeFinalizer` and `Finalizable` features.
Change-Id: I0a397abae511ab3f6762d1b2c4047226d15e36d6
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/143804
Commit-Queue: Daco Harkes <dacoh...@google.com>
Reviewed-by: Michael Thomsen <m...@google.com>
---
M samples/ffi/sqlite/README.md
M samples/ffi/sqlite/lib/src/bindings/bindings.dart
M samples/ffi/sqlite/lib/src/database.dart
M samples/ffi/sqlite/pubspec.yaml
M samples_2/ffi/sqlite/README.md
M samples_2/ffi/sqlite/lib/src/bindings/bindings.dart
M samples_2/ffi/sqlite/lib/src/database.dart
M samples_2/ffi/sqlite/lib/src/ffi/dylib_utils.dart
M samples_2/ffi/sqlite/pubspec.yaml
M samples_2/ffi/sqlite/test/sqlite_test.dart
10 files changed, 315 insertions(+), 150 deletions(-)
diff --git a/samples/ffi/sqlite/README.md b/samples/ffi/sqlite/README.md
index fbd5cb9..c4656df 100644
--- a/samples/ffi/sqlite/README.md
+++ b/samples/ffi/sqlite/README.md
@@ -20,25 +20,10 @@
## Building and Running this Sample
Building and running this sample is done through pub.
-Running `pub get` and `pub run example/main` should produce the following output.
+Running `dart run example/main` should produce the following output.
```sh
-$ pub get
-Resolving dependencies... (6.8s)
-+ analyzer 0.35.4
-...
-+ yaml 2.1.15
-Downloading analyzer 0.35.4...
-Downloading kernel 0.3.14...
-Downloading front_end 0.1.14...
-Changed 47 dependencies!
-Precompiling executables... (18.0s)
-Precompiled test:test.
-
-```
-
-```
-$ pub run example/main
+$ dart run example/main
index 90e67f4..ab886aa 100644
--- a/samples/ffi/sqlite/pubspec.yaml
+++ b/samples/ffi/sqlite/pubspec.yaml
@@ -2,10 +2,9 @@
version: 0.0.1
description: >-
Sqlite3 wrapper. Demo for dart:ffi.
-author: Daco Harkes <dacoh...@google.com>, Samir Jindel <sji...@google.com>
environment:
- sdk: '>=2.12.0-0 <3.0.0'
+ sdk: '>=2.17.0 <3.0.0'
dependencies:
- ffi: ^1.1.2
+ ffi: ^2.0.0
dev_dependencies:
- test: ^1.16.0-nullsafety.12
+ test: ^1.21.1
diff --git a/samples_2/ffi/sqlite/README.md b/samples_2/ffi/sqlite/README.md
index fbd5cb9..c4656df 100644
--- a/samples_2/ffi/sqlite/README.md
+++ b/samples_2/ffi/sqlite/README.md
@@ -20,25 +20,10 @@
## Building and Running this Sample
Building and running this sample is done through pub.
-Running `pub get` and `pub run example/main` should produce the following output.
+Running `dart run example/main` should produce the following output.
```sh
-$ pub get
-Resolving dependencies... (6.8s)
-+ analyzer 0.35.4
-...
-+ yaml 2.1.15
-Downloading analyzer 0.35.4...
-Downloading kernel 0.3.14...
-Downloading front_end 0.1.14...
-Changed 47 dependencies!
-Precompiling executables... (18.0s)
-Precompiled test:test.
-
-```
-
-```
-$ pub run example/main
+$ dart run example/main
1 Chocolade chip cookie Chocolade cookie foo
2 Ginger cookie null 42
3 Cinnamon roll null null
diff --git a/samples_2/ffi/sqlite/lib/src/bindings/bindings.dart b/samples_2/ffi/sqlite/lib/src/bindings/bindings.dart
index a1cdba7..2491813 100644
--- a/samples_2/ffi/sqlite/lib/src/bindings/bindings.dart
+++ b/samples_2/ffi/sqlite/lib/src/bindings/bindings.dart
@@ -33,6 +33,9 @@
int flags, Pointer<Utf8> vfs) sqlite3_open_v2;
int Function(Pointer<Database> database) sqlite3_close_v2;
+ Pointer<NativeFunction<sqlite3_close_v2_native_t>> sqlite3_close_v2_native;
+ Pointer<NativeFunction<Void Function(Pointer<Database> database)>>
+ sqlite3_close_v2_native_return_void;
/// Compiling An SQL Statement
///
@@ -213,6 +216,9 @@
/// statement after it has been finalized can result in undefined and
/// undesirable behavior such as segfaults and heap corruption.
int Function(Pointer<Statement> statement) sqlite3_finalize;
+ Pointer<NativeFunction<sqlite3_finalize_native_t>> sqlite3_finalize_native;
+ Pointer<NativeFunction<Void Function(Pointer<Statement> statement)>>
+ sqlite3_finalize_native_return_void;
/// Number Of Columns In A Result Set
///
@@ -335,9 +341,10 @@
sqlite3_open_v2 = sqlite
.lookup<NativeFunction<sqlite3_open_v2_native_t>>("sqlite3_open_v2")
.asFunction();
- sqlite3_close_v2 = sqlite
- .lookup<NativeFunction<sqlite3_close_v2_native_t>>("sqlite3_close_v2")
- .asFunction();
+ sqlite3_close_v2_native = sqlite
+ .lookup<NativeFunction<sqlite3_close_v2_native_t>>("sqlite3_close_v2");
+ sqlite3_close_v2_native_return_void = sqlite3_close_v2_native.cast();
+ sqlite3_close_v2 = sqlite3_close_v2_native.asFunction();
sqlite3_prepare_v2 = sqlite
.lookup<NativeFunction<sqlite3_prepare_v2_native_t>>(
"sqlite3_prepare_v2")
@@ -348,9 +355,10 @@
sqlite3_reset = sqlite
.lookup<NativeFunction<sqlite3_reset_native_t>>("sqlite3_reset")
.asFunction();
- sqlite3_finalize = sqlite
- .lookup<NativeFunction<sqlite3_finalize_native_t>>("sqlite3_finalize")
- .asFunction();
+ sqlite3_finalize_native = sqlite
+ .lookup<NativeFunction<sqlite3_finalize_native_t>>("sqlite3_finalize");
+ sqlite3_finalize_native_return_void = sqlite3_finalize_native.cast();
+ sqlite3_finalize = sqlite3_finalize_native.asFunction();
sqlite3_errstr = sqlite
.lookup<NativeFunction<sqlite3_errstr_native_t>>("sqlite3_errstr")
.asFunction();
diff --git a/samples_2/ffi/sqlite/lib/src/database.dart b/samples_2/ffi/sqlite/lib/src/database.dart
index d65724f..5bfc770 100644
--- a/samples_2/ffi/sqlite/lib/src/database.dart
+++ b/samples_2/ffi/sqlite/lib/src/database.dart
@@ -23,19 +23,19 @@
///
/// This database interacts with SQLite synchonously.
class Database {
- Pointer<types.Database> _database;
+ DatabaseResource _database;
bool _open = false;
/// Open a database located at the file [path].
Database(String path,
[int flags = Flags.SQLITE_OPEN_READWRITE | Flags.SQLITE_OPEN_CREATE]) {
Pointer<Pointer<types.Database>> dbOut = calloc();
- final pathC = path.toNativeUtf8();
+ final pathC = Utf8Resource(path.toNativeUtf8());
final int resultCode =
- bindings.sqlite3_open_v2(pathC, dbOut, flags, nullptr);
- _database = dbOut.value;
+ bindings.sqlite3_open_v2(pathC.unsafe(), dbOut, flags, nullptr);
+ _database = DatabaseResource(dbOut.value);
calloc.free(dbOut);
- calloc.free(pathC);
+ pathC.free();
if (resultCode == Errors.SQLITE_OK) {
_open = true;
@@ -55,7 +55,7 @@
/// avoid resource leaks.
void close() {
assert(_open);
- final int resultCode = bindings.sqlite3_close_v2(_database);
+ final int resultCode = _database.close();
if (resultCode == Errors.SQLITE_OK) {
_open = false;
} else {
@@ -65,18 +65,17 @@
/// Execute a query, discarding any returned rows.
void execute(String query) {
- Pointer<Pointer<Statement>> statementOut = calloc();
- Pointer<Utf8> queryC = query.toNativeUtf8();
- int resultCode = bindings.sqlite3_prepare_v2(
- _database, queryC, -1, statementOut, nullptr);
- Pointer<Statement> statement = statementOut.value;
+ Pointer<Pointer<Statement>> statementOut = malloc();
+ final queryC = Utf8Resource(query.toNativeUtf8());
+ int resultCode = _database.prepare(queryC, -1, statementOut, nullptr);
+ final statement = StatementResource(statementOut.value);
calloc.free(statementOut);
- calloc.free(queryC);
+ queryC.free();
while (resultCode == Errors.SQLITE_ROW || resultCode == Errors.SQLITE_OK) {
- resultCode = bindings.sqlite3_step(statement);
+ resultCode = statement.step();
}
- bindings.sqlite3_finalize(statement);
+ statement.finalize();
if (resultCode != Errors.SQLITE_DONE) {
throw _loadError(resultCode);
}
@@ -84,24 +83,22 @@
@@ -109,7 +106,7 @@
}
SQLiteException _loadError([int errorCode]) {
- String errorMessage = bindings.sqlite3_errmsg(_database).toDartString();
+ String errorMessage = _database.errmsg().toDartString();
if (errorCode == null) {
return SQLiteException(errorMessage);
}
@@ -126,18 +123,13 @@
/// Please note that this iterator should be [close]d manually if not all [Row]s
/// are consumed.
class Result extends IterableBase<Row> implements ClosableIterable<Row> {
- final Database _database;
final ClosableIterator<Row> _iterator;
- final Pointer<Statement> _statement;
- final Map<String, int> _columnIndices;
-
- Row _currentRow = null;
Result._(
- this._database,
- this._statement,
- this._columnIndices,
- ) : _iterator = _ResultIterator(_statement, _columnIndices) {}
+ Database database,
+ StatementResource statement,
+ Map<String, int> columnIndices,
+ ) : _iterator = _ResultIterator(statement, columnIndices) {}
void close() => _iterator.close();
@@ -145,10 +137,10 @@
}
class _ResultIterator implements ClosableIterator<Row> {
- final Pointer<Statement> _statement;
+ final StatementResource _statement;
final Map<String, int> _columnIndices;
- Row _currentRow = null;
+ Row _currentRow;
bool _closed = false;
_ResultIterator(this._statement, this._columnIndices) {}
@@ -157,8 +149,10 @@
if (_closed) {
throw SQLiteException("The result has already been closed.");
}
- _currentRow?._setNotCurrent();
- int stepResult = bindings.sqlite3_step(_statement);
+ if (_currentRow != null) {
+ _currentRow._setNotCurrent();
+ }
+ int stepResult = _statement.step();
if (stepResult == Errors.SQLITE_ROW) {
_currentRow = Row._(_statement, _columnIndices);
return true;
@@ -176,14 +170,14 @@
}
void close() {
- _currentRow?._setNotCurrent();
+ _currentRow._setNotCurrent();
_closed = true;
- bindings.sqlite3_finalize(_statement);
+ _statement.finalize();
}
}
class Row {
- final Pointer<Statement> _statement;
+ final StatementResource _statement;
final Map<String, int> _columnIndices;
bool _isCurrentRow = true;
@@ -211,12 +205,10 @@
Type dynamicType;
if (convert == Convert.DynamicType) {
- dynamicType =
- _typeFromCode(bindings.sqlite3_column_type(_statement, columnIndex));
+ dynamicType = _typeFromCode(_statement.columnType(columnIndex));
} else {
- dynamicType = _typeFromText(bindings
- .sqlite3_column_decltype(_statement, columnIndex)
- .toDartString());
+ dynamicType =
+ _typeFromText(_statement.columnDecltype(columnIndex).toDartString());
}
switch (dynamicType) {
@@ -226,7 +218,6 @@
return readColumnByIndexAsText(columnIndex);
case Type.Null:
return null;
- break;
default:
}
}
@@ -241,7 +232,7 @@
/// integer.
int readColumnByIndexAsInt(int columnIndex) {
_checkIsCurrentRow();
- return bindings.sqlite3_column_int(_statement, columnIndex);
+ return _statement.columnInt(columnIndex);
}
/// Reads column [columnName] and converts to [Type.Text] if not text.
@@ -252,7 +243,7 @@
/// Reads column [columnIndex] and converts to [Type.Text] if not text.
String readColumnByIndexAsText(int columnIndex) {
_checkIsCurrentRow();
- return bindings.sqlite3_column_text(_statement, columnIndex).toDartString();
+ return _statement.columnText(columnIndex).toDartString();
}
void _checkIsCurrentRow() {
@@ -268,6 +259,93 @@
@@ -297,7 +375,6 @@
case "null":
return Type.Null;
}
- if (textRepresentation == null) return Type.Null;
throw Exception("Unknown type [$textRepresentation]");
}
diff --git a/samples_2/ffi/sqlite/lib/src/ffi/dylib_utils.dart b/samples_2/ffi/sqlite/lib/src/ffi/dylib_utils.dart
index b783ad8..fccdca3 100644
--- a/samples_2/ffi/sqlite/lib/src/ffi/dylib_utils.dart
+++ b/samples_2/ffi/sqlite/lib/src/ffi/dylib_utils.dart
@@ -7,8 +7,7 @@
import 'dart:ffi';
import 'dart:io' show Platform;
-String _platformPath(String name, {String path}) {
- if (path == null) path = "";
+String _platformPath(String name, String path) {
if (Platform.isLinux || Platform.isAndroid || Platform.isFuchsia)
return path + "lib" + name + ".so";
if (Platform.isMacOS) return path + "lib" + name + ".dylib";
@@ -16,7 +15,7 @@
throw Exception("Platform not implemented");
}
-DynamicLibrary dlopenPlatformSpecific(String name, {String path}) {
- String fullPath = _platformPath(name, path: path);
+DynamicLibrary dlopenPlatformSpecific(String name, {String path = ""}) {
+ String fullPath = _platformPath(name, path);
return DynamicLibrary.open(fullPath);
}
diff --git a/samples_2/ffi/sqlite/pubspec.yaml b/samples_2/ffi/sqlite/pubspec.yaml
index 762107f..ab886aa 100644
--- a/samples_2/ffi/sqlite/pubspec.yaml
+++ b/samples_2/ffi/sqlite/pubspec.yaml
@@ -2,10 +2,9 @@
version: 0.0.1
description: >-
Sqlite3 wrapper. Demo for dart:ffi.
-author: Daco Harkes <dacoh...@google.com>, Samir Jindel <sji...@google.com>
environment:
- sdk: '>=2.1.0 <3.0.0'
+ sdk: '>=2.17.0 <3.0.0'
dependencies:
- ffi: ^1.1.2
+ ffi: ^2.0.0
dev_dependencies:
- test: ^1.5.3
+ test: ^1.21.1
diff --git a/samples_2/ffi/sqlite/test/sqlite_test.dart b/samples_2/ffi/sqlite/test/sqlite_test.dart
index 91efe13..8640438 100644
--- a/samples_2/ffi/sqlite/test/sqlite_test.dart
+++ b/samples_2/ffi/sqlite/test/sqlite_test.dart
@@ -49,8 +49,7 @@
expect(true, 1 <= id && id <= 3);
String name = r.readColumnByIndex(1);
expect(true, name is String);
- String alternativeName = r.readColumn("alternative_name");
- expect(true, alternativeName is String || alternativeName == null);
+ final alternativeName = r.readColumn("alternative_name") as String;
dynamic multiTypedValue = r.readColumn("multi_typed_column");
expect(
true,
@@ -76,8 +75,7 @@
expect(true, 1 <= id && id <= 3);
String name = r.readColumnByIndex(1);
expect(true, name is String);
- String alternativeName = r.readColumn("alternative_name");
- expect(true, alternativeName is String || alternativeName == null);
+ final alternativeName = r.readColumn("alternative_name") as String;
dynamic multiTypedValue = r.readColumn("multi_typed_column");
expect(
true,
To view, visit change 143804. To unsubscribe, or for help writing mail filters, visit settings.
go/dart-cbuild result: FAILURE (NO REGRESSIONS DETECTED)
Details: https://goto.google.com/dart-cbuild/find/81584f5d031fc12049f954b8510de7c36f1e56ea