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
27 changes: 17 additions & 10 deletions lib/sea/SeaSessionBackend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,24 +183,31 @@ export default class SeaSessionBackend implements ISessionBackend {
options.queryTimeout !== undefined ? numberToInt64(options.queryTimeout).toNumber() : undefined;

if (!runAsync) {
// Sync path: forward `queryTimeoutSecs` to the napi options — the kernel
// `execute()` honours it (server statement timeout).
// DEFAULT — directResults (the Thrift / JDBC / Python use_sea model). The
// kernel sends ExecuteStatement with the server inline wait (~10s default
// + on_wait_timeout=CONTINUE) and returns WITHOUT polling past it, as a
// single `AsyncStatement` handle:
// - a fast query comes back seeded with the inline result, so the first
// fetch/status is served with zero extra round-trips (and is
// 404-proof — a terminal handle never polls a released statement);
// - a slow query comes back as a poll/cancel handle.
// Either way the handle is tied to a server-owned statement, so a long
// query stays cancellable (`asyncStatement.cancel()`) and `close()` is a
// clean release — no eager-handle / close-drives workaround. Fire-and-
// forget DDL/DML commits because the server runs it inline during the POST.
const execOptions = this.buildExecuteOptions(options, queryTimeoutSecs);
let cancellableExecution;
let asyncStatement;
try {
cancellableExecution =
asyncStatement =
execOptions === undefined
? await this.connection.executeStatementCancellable(statement)
: await this.connection.executeStatementCancellable(statement, execOptions);
? await this.connection.executeStatement(statement)
: await this.connection.executeStatement(statement, execOptions);
} catch (err) {
throw this.logAndMapError('executeStatement', err);
}
return new SeaOperationBackend({
cancellableExecution: cancellableExecution!,
asyncStatement,
context: this.context,
// The kernel honours `queryTimeoutSecs` on the sync `execute` path, so
// it is forwarded via the napi options (see `buildExecuteOptions`); the
// backend also keeps it as a deadline guard for parity with async.
queryTimeoutSecs,
});
}
Expand Down
40 changes: 22 additions & 18 deletions native/sea/index.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 14 additions & 10 deletions tests/unit/sea/execution.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,28 +210,32 @@ class FakeNativeConnection implements SeaConnection {
// sync `runAsync: false` query path — the DEFAULT).
public lastCancellableExecution?: FakeCancellableExecution;

// The bare blocking executeStatement path: the SEA backend's sync default
// routes through executeStatementCancellable (below), but the binding still
// exposes this for completeness.
public async executeStatement(sql: string, options?: unknown): Promise<SeaStatement> {
// Sync (`runAsync: false`) cancellable query path (retained for the
// executeStatementCancellable binding; the default execute path is the
// directResults `executeStatement` below).
public async executeStatementCancellable(sql: string, options?: unknown): Promise<any> {
if (this.throwOnExecute) {
throw this.throwOnExecute;
}
this.lastSql = sql;
this.lastOptions = options;
return this.statementToReturn;
this.lastCancellableExecution = new FakeCancellableExecution();
return this.lastCancellableExecution;
}

// Sync (`runAsync: false`, the DEFAULT) query path: records sql + options and
// returns a pending CancellableExecution whose result() drives the execute.
public async executeStatementCancellable(sql: string, options?: unknown): Promise<any> {
// directResults (`runAsync: false`, the DEFAULT) query path: records sql +
// options and returns a single `AsyncStatement` handle — the kernel `execute()`
// sends the inline-wait POST and returns one handle (seeded with the inline
// result on the fast path, a poll/cancel handle otherwise). `submitStatusValue`
// configures the state it reports.
public async executeStatement(sql: string, options?: unknown): Promise<any> {
if (this.throwOnExecute) {
throw this.throwOnExecute;
}
this.lastSql = sql;
this.lastOptions = options;
this.lastCancellableExecution = new FakeCancellableExecution();
return this.lastCancellableExecution;
this.lastAsyncStatement = new FakeAsyncStatement(this.submitStatusValue);
return this.lastAsyncStatement;
}

// Async-submit path: records sql + per-statement options (for forwarding
Expand Down
Loading