diff --git a/sqlite3/lib/src/api/functions.dart b/sqlite3/lib/src/api/functions.dart index b41bd910..60802c36 100644 --- a/sqlite3/lib/src/api/functions.dart +++ b/sqlite3/lib/src/api/functions.dart @@ -3,7 +3,7 @@ import 'package:meta/meta.dart'; /// A scalar function exposed to sql. /// /// {@template sqlite3_function_behavior} -/// The function must either return a `bool`, `num`, `String`, `List` or +/// The function must either return a `bool`, `num`, `String`, `Uint8List`, `List` or /// `null`. /// /// If invoking the function throws a Dart exception, the sql function will diff --git a/sqlite3/lib/src/ffi/ffi.dart b/sqlite3/lib/src/ffi/ffi.dart index 38328bec..9181e95e 100644 --- a/sqlite3/lib/src/ffi/ffi.dart +++ b/sqlite3/lib/src/ffi/ffi.dart @@ -69,6 +69,8 @@ extension ValueUtils on Pointer { } } +final utf8Encode = utf8.encoder.convert; + extension ContextUtils on Pointer { Pointer aggregateContext(Bindings bindings, int bytes) { return bindings.sqlite3_aggregate_context(this, bytes); @@ -88,13 +90,13 @@ extension ContextUtils on Pointer { } else if (result is bool) { bindings.sqlite3_result_int64(this, result ? 1 : 0); } else if (result is String) { - final bytes = utf8.encode(result); + Uint8List bytes = utf8Encode(result); final ptr = allocateBytes(bytes); bindings.sqlite3_result_text( this, ptr.cast(), bytes.length, SQLITE_TRANSIENT); ptr.free(); - } else if (result is List) { + } else if (result is Uint8List) { final ptr = allocateBytes(result); bindings.sqlite3_result_blob64( @@ -104,7 +106,7 @@ extension ContextUtils on Pointer { } void setError(Bindings bindings, String description) { - final bytes = utf8.encode(description); + final Uint8List bytes = utf8Encode(description); final ptr = allocateBytes(bytes); bindings.sqlite3_result_error(this, ptr.cast(), bytes.length); @@ -148,7 +150,7 @@ class ValueList extends ListBase { } final result = argArray[index].read(bindings); - if (result is String || result is List) { + if (result is String || result is Uint8List) { // Cache to avoid excessive copying in case the argument is loaded // multiple times _cachedCopies[index] = result; diff --git a/sqlite3/lib/src/ffi/memory.dart b/sqlite3/lib/src/ffi/memory.dart index 147e8f62..97d4617e 100644 --- a/sqlite3/lib/src/ffi/memory.dart +++ b/sqlite3/lib/src/ffi/memory.dart @@ -31,7 +31,7 @@ extension FreePointerExtension on Pointer { void free() => allocate.free(this); } -Pointer allocateBytes(List bytes, {int additionalLength = 0}) { +Pointer allocateBytes(Uint8List bytes, {int additionalLength = 0}) { final ptr = allocate.allocate(bytes.length + additionalLength); final data = Uint8List(bytes.length + additionalLength)..setAll(0, bytes); @@ -40,6 +40,7 @@ Pointer allocateBytes(List bytes, {int additionalLength = 0}) { return ptr; } +final utf8Encode = utf8.encoder.convert; Pointer allocateZeroTerminated(String string) { - return allocateBytes(utf8.encode(string), additionalLength: 1).cast(); + return allocateBytes(utf8Encode(string), additionalLength: 1).cast(); } diff --git a/sqlite3/lib/src/impl/database.dart b/sqlite3/lib/src/impl/database.dart index d8ceca75..7cf9a524 100644 --- a/sqlite3/lib/src/impl/database.dart +++ b/sqlite3/lib/src/impl/database.dart @@ -145,7 +145,7 @@ class DatabaseImpl implements Database { final pzTail = checkNoTail ? allocate>() : nullPtr>(); - final bytes = utf8.encode(sql); + final bytes = utf8Encode(sql); final sqlPtr = allocateBytes(bytes); var prepFlags = 0; @@ -229,7 +229,7 @@ class DatabaseImpl implements Database { } Pointer _functionName(String functionName) { - final functionNameBytes = utf8.encode(functionName); + final functionNameBytes = utf8Encode(functionName); if (functionNameBytes.length > 255) { throw ArgumentError.value(functionName, 'functionName', diff --git a/sqlite3/lib/src/impl/statement.dart b/sqlite3/lib/src/impl/statement.dart index 13182f59..1cb04081 100644 --- a/sqlite3/lib/src/impl/statement.dart +++ b/sqlite3/lib/src/impl/statement.dart @@ -100,7 +100,10 @@ class PreparedStatementImpl implements PreparedStatement { // variables in sqlite are 1-indexed for (var i = 1; i <= params.length; i++) { - final Object? param = params[i - 1]; + Object? param = params[i - 1]; + if (param is List) { + param = Uint8List.fromList(param); + } if (param == null) { _bindings.sqlite3_bind_null(_stmt, i); @@ -109,13 +112,13 @@ class PreparedStatementImpl implements PreparedStatement { } else if (param is double) { _bindings.sqlite3_bind_double(_stmt, i, param.toDouble()); } else if (param is String) { - final bytes = utf8.encode(param); + final bytes = utf8Encode(param); final ptr = allocateBytes(bytes); _allocatedWhileBinding.add(ptr); _bindings.sqlite3_bind_text( _stmt, i, ptr.cast(), bytes.length, nullPtr()); - } else if (param is List) { + } else if (param is Uint8List) { if (param.isEmpty) { // malloc(0) is implementation-defined and might return a null // pointer, which is not what we want: Passing a null-pointer to @@ -133,8 +136,8 @@ class PreparedStatementImpl implements PreparedStatement { throw ArgumentError.value( param, 'params[$i]', - 'Allowed parameters must either be null or an int, num, String or ' - 'List.', + 'Allowed parameters must either be null or an int, num, String, List or ' + 'Uint8List.', ); } }