diff --git a/apps/desktop/src/stores/queryStore.ts b/apps/desktop/src/stores/queryStore.ts index 04bf1f250e..e8f9ab7e5e 100644 --- a/apps/desktop/src/stores/queryStore.ts +++ b/apps/desktop/src/stores/queryStore.ts @@ -798,7 +798,7 @@ export const useQueryStore = defineStore("query", () => { } console.info("[DBX][executeTabSql:execute-multi:start]", { traceId, elapsed: elapsed() }); - const clientSessionId = useAgentResultSession ? tab.id : undefined; + const clientSessionId = tab.mode === "query" ? tab.id : undefined; const executionOptions = { ...(typeof pageLimit === "number" ? useAgentResultSession @@ -830,9 +830,11 @@ export const useQueryStore = defineStore("query", () => { const current = tabs.value.find((t) => t.id === id); if (current?.executionId === executionId) { if (results.length > 1) { + const activeResultIndex = results.findIndex((result) => result.columns.length > 0); + const resultIndex = activeResultIndex >= 0 ? activeResultIndex : 0; current.results = results; - current.activeResultIndex = 0; - current.result = results[0]; + current.activeResultIndex = resultIndex; + current.result = results[resultIndex]; } else { current.results = undefined; current.activeResultIndex = undefined; diff --git a/packages/app-tests/queryStore.test.ts b/packages/app-tests/queryStore.test.ts index 9ac84d3840..0bd15e15e4 100644 --- a/packages/app-tests/queryStore.test.ts +++ b/packages/app-tests/queryStore.test.ts @@ -489,7 +489,7 @@ test("query execution finishes without waiting for metadata analysis", async () } }); -test("normal query execution does not create a tab-scoped client session", async () => { +test("query execution is scoped to the tab client session", async () => { const restoreStorage = installMemoryStorage(); setActivePinia(createPinia()); const connectionStore = useConnectionStore(); @@ -527,7 +527,7 @@ test("normal query execution does not create a tab-scoped client session", async try { await store.executeTabSql(tabId, "select 1"); - assert.equal(executeBody.clientSessionId, undefined); + assert.equal(executeBody.clientSessionId, tabId); assert.equal(executeBody.timeoutSecs, 30); } finally { globalThis.fetch = originalFetch; @@ -535,6 +535,55 @@ test("normal query execution does not create a tab-scoped client session", async } }); +test("multi statement execution shows the first result set by default", async () => { + const restoreStorage = installMemoryStorage(); + setActivePinia(createPinia()); + const connectionStore = useConnectionStore(); + const store = useQueryStore(); + const originalFetch = globalThis.fetch; + + connectionStore.addEphemeralConnection(conn("conn-1")); + const tabId = store.createTab("conn-1", "db", "Query"); + + globalThis.fetch = (async (input) => { + const url = String(input); + if (url === "/api/query/prepare-pagination-plan") { + return new Response(JSON.stringify({ sqlToExecute: "set @id = 1; select @id", useAgentResultSession: false }), { + status: 200, + headers: { "Content-Type": "application/json" }, + }); + } + if (url === "/api/query/execute-multi") { + return new Response( + JSON.stringify([ + { columns: [], rows: [], affected_rows: 0, execution_time_ms: 1 }, + { columns: ["@id"], rows: [[1]], affected_rows: 0, execution_time_ms: 1 }, + ]), + { status: 200, headers: { "Content-Type": "application/json" } }, + ); + } + if (url === "/api/query/analyze-editability") { + return new Response(JSON.stringify({ editable: false, reason: "complex-source" }), { + status: 200, + headers: { "Content-Type": "application/json" }, + }); + } + return new Response("unexpected request", { status: 500 }); + }) as typeof fetch; + + try { + await store.executeTabSql(tabId, "set @id = 1; select @id"); + + const tab = store.tabs.find((item) => item.id === tabId); + assert.equal(tab?.activeResultIndex, 1); + assert.deepEqual(tab?.result?.columns, ["@id"]); + assert.deepEqual(tab?.result?.rows, [[1]]); + } finally { + globalThis.fetch = originalFetch; + restoreStorage(); + } +}); + test("tab reuse is scoped by mode and schema instead of title alone", () => { const restoreStorage = installMemoryStorage(); try {