AsyncNativeOdbcConnection class

Non-blocking wrapper around ODBC using a long-lived worker isolate.

Architecture: All FFI/ODBC operations run in a dedicated worker isolate. The main thread stays responsive; no blocking FFI calls run on the UI thread.

How it works

  1. initialize spawns a worker isolate and loads the ODBC driver.
  2. Each operation sends a request (via SendPort) to the worker.
  3. The worker runs the FFI call and sends back the result (via ReceivePort).
  4. The main thread never blocks on ODBC.

Performance

  • Worker spawn (one-time): ~50–100 ms.
  • Per-operation overhead: ~1–3 ms.
  • Parallel queries: N queries complete in the time of the longest (not the sum).

Request timeout

Use requestTimeout to avoid UI hangs when the worker does not respond (default 30s). Pass Duration.zero or null to disable.

Example

final async = AsyncNativeOdbcConnection(
  requestTimeout: Duration(seconds: 30),
);
await async.initialize();

final connId = await async.connect(dsn);
final data = await async.executeQueryParams(connId, 'SELECT 1', []);
await async.disconnect(connId);

async.dispose(); // Pending requests complete with error

See also:

Constructors

AsyncNativeOdbcConnection({Duration? requestTimeout, void isolateEntry(SendPort)?, bool autoRecoverOnWorkerCrash = false})

Properties

autoRecoverOnWorkerCrash bool
When true, on worker isolate error/done WorkerCrashRecovery.handleWorkerCrash is invoked after failing pending requests. All previous connection IDs are invalid after recovery; callers must reconnect.
final
hashCode int
The hash code for this object.
no setterinherited
isInitialized bool
Whether the worker isolate and ODBC environment are initialized.
no setter
runtimeType Type
A representation of the runtime type of the object.
no setterinherited
workerIsolateForTesting Isolate?
Worker isolate, exposed for testing (e.g., to simulate crash).
no setter

Methods

asyncCancel(int asyncRequestId) Future<bool>
Best-effort cancellation for async request.
asyncFree(int asyncRequestId) Future<bool>
Frees async request resources.
asyncGetResult(int asyncRequestId, {int? maxBufferBytes}) Future<Uint8List?>
Retrieves binary result for a completed async request.
asyncPoll(int asyncRequestId) Future<int>
Polls async request status.
beginTransaction(int connectionId, int isolationLevel) Future<int>
Starts a transaction in the worker for connectionId with isolationLevel. Returns the transaction ID on success.
bulkInsertArray(int connectionId, String table, List<String> columns, Uint8List dataBuffer, int rowCount) Future<int>
Performs bulk insert on connectionId: table, columns, dataBuffer, rowCount. Returns rows inserted, or negative on error.
bulkInsertParallel(int poolId, String table, List<String> columns, Uint8List dataBuffer, int parallelism) Future<int>
Performs parallel bulk insert on poolId. Returns rows inserted, or negative value on error.
cancelStatement(int stmtId) Future<bool>
Requests cancellation of prepared statement stmtId in the worker.
catalogColumns(int connectionId, String table) Future<Uint8List?>
Returns catalog columns for table on connectionId. Binary result or null on error.
catalogTables(int connectionId, {String catalog = '', String schema = ''}) Future<Uint8List?>
Returns catalog tables for connectionId (optional catalog and schema). Returns binary result or null on error.
catalogTypeInfo(int connectionId) Future<Uint8List?>
Returns type info for connectionId. Binary result or null on error.
clearAllStatements() Future<int>
clearAuditEvents() Future<bool>
Clears in-memory audit events in the worker.
clearMetadataCache() Future<bool>
Clears metadata cache entries in the worker.
clearStatementCache() Future<bool>
Clears the prepared statement cache in the worker.
closeStatement(int stmtId) Future<bool>
Closes the prepared statement stmtId in the worker.
commitTransaction(int txnId) Future<bool>
Commits the transaction identified by txnId in the worker.
connect(String connectionString, {int timeoutMs = 0}) Future<int>
Opens a connection in the worker using connectionString.
createSavepoint(int txnId, String name) Future<bool>
Creates a savepoint name within the transaction txnId in the worker.
detectDriver(String connectionString) Future<String?>
Detects the database driver from a connection string.
disconnect(int connectionId) Future<bool>
Closes the connection identified by connectionId in the worker.
dispose() → void
Shuts down the worker isolate and releases resources.
executeAsync(int connectionId, String sql, {Duration pollInterval = const Duration(milliseconds: 10), Duration? timeout, int? maxBufferBytes}) Future<Uint8List?>
Executes sql in non-blocking mode using native async request lifecycle.
executeAsyncStart(int connectionId, String sql) Future<int>
Starts non-blocking query execution in native layer.
executePrepared(int stmtId, List<ParamValue>? params, int timeoutOverrideMs, int fetchSize, {int? maxBufferBytes}) Future<Uint8List?>
Executes a prepared statement stmtId in the worker with optional params. Returns the binary result, or null on error.
executePreparedNamed(int stmtId, Map<String, Object?> namedParams, int timeoutOverrideMs, int fetchSize, {int? maxBufferBytes}) Future<Uint8List?>
Executes a prepared statement stmtId using named parameters.
executeQueryMulti(int connectionId, String sql, {int? maxBufferBytes}) Future<Uint8List?>
Executes sql on connectionId for multi-result sets in the worker. When maxBufferBytes is set, caps the result buffer size. Returns the binary result, or null on error.
executeQueryNamed(int connectionId, String sql, Map<String, Object?> namedParams, {int? maxBufferBytes}) Future<Uint8List?>
Executes sql on connectionId using named parameters.
executeQueryParams(int connectionId, String sql, List<ParamValue> params, {int? maxBufferBytes}) Future<Uint8List?>
Executes sql on connectionId with params in the worker.
getAuditEventsJson({int limit = 0}) Future<String?>
Returns audit events as JSON payload, or null on failure.
getAuditStatusJson() Future<String?>
Returns audit status as JSON payload, or null on failure.
getCacheMetrics() Future<PreparedStatementMetrics?>
Returns prepared statement cache metrics from the worker.
getDriverCapabilitiesJson(String connectionString) Future<String?>
Returns driver capabilities payload as JSON, or null on failure.
getError() Future<String>
Returns the last error message from the worker (plain text).
getMetadataCacheStatsJson() Future<String?>
Returns metadata cache stats as JSON payload, or null on failure.
getMetrics() Future<OdbcMetrics?>
Returns ODBC metrics from the worker (query count, errors, latency, etc.).
getStructuredError() Future<StructuredError?>
Returns the last structured error (message, SQLSTATE, native code), or null if there is no error.
getVersion() Future<Map<String, String>?>
Returns engine version (api + abi) for compatibility checks.
initialize() Future<bool>
Initializes the worker isolate and ODBC environment.
metadataCacheEnable({required int maxEntries, required int ttlSeconds}) Future<bool>
Enables metadata cache in the worker.
noSuchMethod(Invocation invocation) → dynamic
Invoked when a nonexistent method or property is accessed.
inherited
poolClose(int poolId) Future<bool>
Closes pool poolId in the worker.
poolCreate(String connectionString, int maxSize) Future<int>
Creates a connection pool in the worker. Returns pool ID on success.
poolGetConnection(int poolId) Future<int>
Obtains a connection from pool poolId. Returns connection ID on success.
poolGetState(int poolId) Future<({int idle, int size})?>
Returns the current state (size, idle) of pool poolId, or null on error.
poolGetStateJson(int poolId) Future<String?>
Returns detailed pool state payload as JSON, or null on failure.
poolHealthCheck(int poolId) Future<bool>
Runs a health check on pool poolId.
poolReleaseConnection(int connectionId) Future<bool>
Returns connectionId to its pool.
poolSetSize(int poolId, int newMaxSize) Future<bool>
Resizes pool poolId to newMaxSize in the worker.
prepare(int connectionId, String sql, {int timeoutMs = 0}) Future<int>
Prepares sql on connectionId in the worker.
prepareNamed(int connectionId, String sql, {int timeoutMs = 0}) Future<int>
Prepares sql with named parameters on connectionId in the worker.
recoverWorker() Future<void>
Disposes the current worker and re-initializes a fresh one.
releaseSavepoint(int txnId, String name) Future<bool>
Releases savepoint name in transaction txnId. Transaction stays active.
rollbackToSavepoint(int txnId, String name) Future<bool>
Rolls back to savepoint name in transaction txnId. Transaction stays active.
rollbackTransaction(int txnId) Future<bool>
Rolls back the transaction identified by txnId in the worker.
setAuditEnabled({required bool enabled}) Future<bool>
Enables/disables native audit event collection in the worker.
streamAsync(int connectionId, String sql, {int fetchSize = 1000, int chunkSize = 64 * 1024, Duration pollInterval = const Duration(milliseconds: 10), int? maxBufferBytes}) Stream<ParsedRowBuffer>
Runs sql using native async stream lifecycle: stream_start_async -> stream_poll_async -> stream_fetch -> stream_close.
streamCancel(int streamId) Future<bool>
Cancels an active low-level native stream in the worker.
streamPollAsync(int streamId) Future<int>
Polls low-level async stream status.
streamQuery(int connectionId, String sql, {int chunkSize = 1000, int? maxBufferBytes}) Stream<ParsedRowBuffer>
Runs sql in the worker using native streaming.
streamQueryBatched(int connectionId, String sql, {int fetchSize = 1000, int chunkSize = 64 * 1024, int? maxBufferBytes}) Stream<ParsedRowBuffer>
Runs sql in the worker using native batched streaming.
streamStartAsync(int connectionId, String sql, {int fetchSize = 1000, int chunkSize = 64 * 1024}) Future<int>
Starts low-level async stream lifecycle and returns stream ID.
toString() String
A string representation of this object.
inherited
validateConnectionString(String connectionString) Future<String?>
Validates connection string format without opening a connection.

Operators

operator ==(Object other) bool
The equality operator.
inherited