MySqlX (C connector) with Dart's ffi brings error "NoSuchMethodError: The method 'FfiTrampoline' was called on null."
MySqlX (C connector) with Dart's ffi brings error "NoSuchMethodError: The method 'FfiTrampoline' was called on null."
我正在尝试使用 Dart 的 ffi 包和 MYSQL 的原生 C-Connector 直接连接到 MYSQL。
我的 Dart 代码是:
import 'dart:ffi';
import 'package:ffi/ffi.dart';
typedef CFun = Pointer Function(Pointer<Utf8>, Int32, Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Pointer<Pointer>?);
typedef DartFun = Pointer Function(Pointer<Utf8>, int, Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Pointer<Pointer>?);
void main() {
final lib = DynamicLibrary.open('/usr/lib64/libmysqlcppconn8.so.2');
final fc = lib.lookup<NativeFunction<CFun>>('mysqlx_get_session');
print('We have C: $fc');
final DartFun fd = fc.asFunction();
print('We have Dart: $fd');
Pointer<Pointer>? error;
Pointer? session;
session = fd('localhost'.toNativeUtf8(), 33060, '*user*'.toNativeUtf8(), '*password*'.toNativeUtf8(), ''.toNativeUtf8(), error);
}
当 运行 时,我得到这个输出:
We have Pointer<NativeFunction<(Pointer<Utf8>, Int32, Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Pointer<Pointer<NativeType>>?) => Pointer<NativeType>>>: address=0x7f5b9c78f770
We have Closure: (Pointer<Utf8>, int, Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Pointer<Pointer<NativeType>>?) => Pointer<NativeType>
Unhandled exception:
NoSuchMethodError: The method 'FfiTrampoline' was called on null.
Receiver: null
Tried calling: FfiTrampoline()
#0 FfiTrampoline (dart:ffi)
#1 main (package:greudb/src/connection.dart:37:14)
#2 _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:283:19)
#3 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)
在 C 中尝试相同的方法,它完美地工作:
#include <mysql-cppconn/mysqlx/xapi.h>
#include <stdio.h>
int main()
{
mysqlx_session_t *session = 0;
mysqlx_error_t *error = 0;
session = mysqlx_get_session("localhost", 33060, "*user*", "*password*", "", &error);
if(error != 0) {
printf("%s/n", mysqlx_error_message(error));
}
return 0;
}
我猜我的 Dart 函数签名不正确,但无论我怎么尝试都无济于事。
MySQL 的 C 文档在这里:https://dev.mysql.com/doc/dev/connector-cpp/8.0/group__xapi__sess.html
我正在使用 Linux Fedora 33,MySQL 社区服务器 8,MySQL 连接器 C/C++ 8,Dart 202.8488。
环顾四周后, 您可以使用以下方法为 error
创建合适的类型:
final error = calloc<Pointer>();
在后台使用适当的 byteCount
调用 calloc.allocate<Pointer>(...)
。由于这是非托管内存,您需要记住通过调用释放它:
calloc.free(error);
完成后。
幸运的是,mysqlx
API 似乎将所有结构都视为不透明的,因此您可以通过执行以下操作来确定实际错误是什么:
final message = errorMessage(error.value);
print(message.toDartString());
关于释放内存的话题,调用toNativeUtf8()
创建的Pointer<Utf8>
个值也需要释放。
将所有这些放在一起:
import 'dart:ffi';
import 'package:ffi/ffi.dart';
typedef _GetSession = Pointer Function(Pointer<Utf8>, Int32, Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Pointer<Pointer>);
typedef GetSession = Pointer Function(Pointer<Utf8>, int, Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Pointer<Pointer>);
typedef _CloseSession = Void Function(Pointer);
typedef CloseSession = void Function(Pointer);
typedef _ErrorMessage = Pointer<Utf8> Function(Pointer);
typedef ErrorMessage = Pointer<Utf8> Function(Pointer);
void main() {
final lib = DynamicLibrary.open('/usr/lib64/libmysqlcppconn8.so.2');
final GetSession getSession = lib.lookup<NativeFunction<_GetSession>>('mysqlx_get_session').asFunction();
final CloseSession closeSession = lib.lookup<NativeFunction<_CloseSession>>('mysqlx_session_close').asFunction();
final ErrorMessage errorMessage = lib.lookup<NativeFunction<_ErrorMessage>>('mysqlx_error_message').asFunction();
final host = 'localhost'.toNativeUtf8();
final user = 'user'.toNativeUtf8();
final password = 'password'.toNativeUtf8();
final database = ''.toNativeUtf8();
final error = calloc<Pointer>();
final session = getSession(host, 33060, user, password, database, error);
calloc.free(host);
calloc.free(user);
calloc.free(password);
calloc.free(database);
if (error.value != nullptr) {
final message = errorMessage(error.value);
print(message.toDartString());
calloc.free(error);
return;
}
// Do something with session
closeSession(session);
}
我正在尝试使用 Dart 的 ffi 包和 MYSQL 的原生 C-Connector 直接连接到 MYSQL。
我的 Dart 代码是:
import 'dart:ffi';
import 'package:ffi/ffi.dart';
typedef CFun = Pointer Function(Pointer<Utf8>, Int32, Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Pointer<Pointer>?);
typedef DartFun = Pointer Function(Pointer<Utf8>, int, Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Pointer<Pointer>?);
void main() {
final lib = DynamicLibrary.open('/usr/lib64/libmysqlcppconn8.so.2');
final fc = lib.lookup<NativeFunction<CFun>>('mysqlx_get_session');
print('We have C: $fc');
final DartFun fd = fc.asFunction();
print('We have Dart: $fd');
Pointer<Pointer>? error;
Pointer? session;
session = fd('localhost'.toNativeUtf8(), 33060, '*user*'.toNativeUtf8(), '*password*'.toNativeUtf8(), ''.toNativeUtf8(), error);
}
当 运行 时,我得到这个输出:
We have Pointer<NativeFunction<(Pointer<Utf8>, Int32, Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Pointer<Pointer<NativeType>>?) => Pointer<NativeType>>>: address=0x7f5b9c78f770
We have Closure: (Pointer<Utf8>, int, Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Pointer<Pointer<NativeType>>?) => Pointer<NativeType>
Unhandled exception:
NoSuchMethodError: The method 'FfiTrampoline' was called on null.
Receiver: null
Tried calling: FfiTrampoline()
#0 FfiTrampoline (dart:ffi)
#1 main (package:greudb/src/connection.dart:37:14)
#2 _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:283:19)
#3 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)
在 C 中尝试相同的方法,它完美地工作:
#include <mysql-cppconn/mysqlx/xapi.h>
#include <stdio.h>
int main()
{
mysqlx_session_t *session = 0;
mysqlx_error_t *error = 0;
session = mysqlx_get_session("localhost", 33060, "*user*", "*password*", "", &error);
if(error != 0) {
printf("%s/n", mysqlx_error_message(error));
}
return 0;
}
我猜我的 Dart 函数签名不正确,但无论我怎么尝试都无济于事。 MySQL 的 C 文档在这里:https://dev.mysql.com/doc/dev/connector-cpp/8.0/group__xapi__sess.html
我正在使用 Linux Fedora 33,MySQL 社区服务器 8,MySQL 连接器 C/C++ 8,Dart 202.8488。
环顾四周后,error
创建合适的类型:
final error = calloc<Pointer>();
在后台使用适当的 byteCount
调用 calloc.allocate<Pointer>(...)
。由于这是非托管内存,您需要记住通过调用释放它:
calloc.free(error);
完成后。
幸运的是,mysqlx
API 似乎将所有结构都视为不透明的,因此您可以通过执行以下操作来确定实际错误是什么:
final message = errorMessage(error.value);
print(message.toDartString());
关于释放内存的话题,调用toNativeUtf8()
创建的Pointer<Utf8>
个值也需要释放。
将所有这些放在一起:
import 'dart:ffi';
import 'package:ffi/ffi.dart';
typedef _GetSession = Pointer Function(Pointer<Utf8>, Int32, Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Pointer<Pointer>);
typedef GetSession = Pointer Function(Pointer<Utf8>, int, Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Pointer<Pointer>);
typedef _CloseSession = Void Function(Pointer);
typedef CloseSession = void Function(Pointer);
typedef _ErrorMessage = Pointer<Utf8> Function(Pointer);
typedef ErrorMessage = Pointer<Utf8> Function(Pointer);
void main() {
final lib = DynamicLibrary.open('/usr/lib64/libmysqlcppconn8.so.2');
final GetSession getSession = lib.lookup<NativeFunction<_GetSession>>('mysqlx_get_session').asFunction();
final CloseSession closeSession = lib.lookup<NativeFunction<_CloseSession>>('mysqlx_session_close').asFunction();
final ErrorMessage errorMessage = lib.lookup<NativeFunction<_ErrorMessage>>('mysqlx_error_message').asFunction();
final host = 'localhost'.toNativeUtf8();
final user = 'user'.toNativeUtf8();
final password = 'password'.toNativeUtf8();
final database = ''.toNativeUtf8();
final error = calloc<Pointer>();
final session = getSession(host, 33060, user, password, database, error);
calloc.free(host);
calloc.free(user);
calloc.free(password);
calloc.free(database);
if (error.value != nullptr) {
final message = errorMessage(error.value);
print(message.toDartString());
calloc.free(error);
return;
}
// Do something with session
closeSession(session);
}