14 files changed
+160
-1
No files matched your search
@@ -900,6 +900,7 @@ export async function executeQuery(
|
||||
catalog?: string;
|
||||
fetchSize?: number;
|
||||
pageSize?: number;
|
||||
rowOffset?: number;
|
||||
resultSessionId?: string;
|
||||
clientSessionId?: string;
|
||||
timeoutSecs?: number;
|
||||
@@ -927,6 +928,7 @@ export async function executeMulti(
|
||||
catalog?: string;
|
||||
fetchSize?: number;
|
||||
pageSize?: number;
|
||||
rowOffset?: number;
|
||||
maxResultBytes?: number;
|
||||
resultKeyColumns?: string[];
|
||||
tableDataPreview?: boolean;
|
||||
@@ -970,6 +972,7 @@ export async function executeMultiWithProgress(
|
||||
catalog?: string;
|
||||
fetchSize?: number;
|
||||
pageSize?: number;
|
||||
rowOffset?: number;
|
||||
maxResultBytes?: number;
|
||||
resultKeyColumns?: string[];
|
||||
tableDataPreview?: boolean;
|
||||
|
||||
@@ -1115,6 +1115,7 @@ export async function executeQuery(
|
||||
catalog?: string;
|
||||
fetchSize?: number;
|
||||
pageSize?: number;
|
||||
rowOffset?: number;
|
||||
resultSessionId?: string;
|
||||
clientSessionId?: string;
|
||||
timeoutSecs?: number;
|
||||
@@ -1146,6 +1147,7 @@ export async function executeMulti(
|
||||
catalog?: string;
|
||||
fetchSize?: number;
|
||||
pageSize?: number;
|
||||
rowOffset?: number;
|
||||
maxResultBytes?: number;
|
||||
resultKeyColumns?: string[];
|
||||
tableDataPreview?: boolean;
|
||||
@@ -1193,6 +1195,7 @@ export async function executeMultiWithProgress(
|
||||
catalog?: string;
|
||||
fetchSize?: number;
|
||||
pageSize?: number;
|
||||
rowOffset?: number;
|
||||
maxResultBytes?: number;
|
||||
resultKeyColumns?: string[];
|
||||
tableDataPreview?: boolean;
|
||||
|
||||
@@ -19,6 +19,7 @@ export interface BuildTableSelectSqlOptions {
|
||||
orderBy?: string;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
useDriverRowOffset?: boolean;
|
||||
whereInput?: string;
|
||||
includeRowId?: boolean;
|
||||
catalog?: string;
|
||||
|
||||
@@ -128,6 +128,44 @@ describe("queryStore table data refresh", () => {
|
||||
expect(store.tabs.find((tab) => tab.id === archiveTabId)?.result).toBeUndefined();
|
||||
});
|
||||
|
||||
it("uses JDBC ResultSet offset pagination for Caché data tabs", async () => {
|
||||
mocks.getConnectionConfig.mockReturnValue({
|
||||
id: "cache-1",
|
||||
name: "Caché 2016",
|
||||
db_type: "jdbc",
|
||||
database: "USER",
|
||||
connection_string: "jdbc:Cache://localhost:1972/USER",
|
||||
query_timeout_secs: 30,
|
||||
});
|
||||
mocks.buildTableSelectSql.mockResolvedValue('SELECT * FROM "SS"."SS_User" ORDER BY "ID" ASC');
|
||||
const { useQueryStore } = await import("@/stores/queryStore");
|
||||
const store = useQueryStore();
|
||||
const tabId = store.createTab("cache-1", "USER", "SS_User", "data", "SS");
|
||||
store.setTableMeta(tabId, {
|
||||
schema: "SS",
|
||||
tableName: "SS_User",
|
||||
tableType: "TABLE",
|
||||
columns: [{ name: "ID", data_type: "%Library.Integer", is_nullable: false, column_default: null, is_primary_key: true, extra: null }],
|
||||
primaryKeys: ["ID"],
|
||||
});
|
||||
const tab = store.tabs.find((candidate) => candidate.id === tabId)!;
|
||||
tab.orderByInput = '"ID" ASC';
|
||||
tab.resultPageLimit = 100;
|
||||
tab.resultPageOffset = 100;
|
||||
|
||||
await store.refreshDataTab(tabId);
|
||||
|
||||
expect(mocks.buildTableSelectSql).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
databaseType: "iris",
|
||||
limit: 100,
|
||||
offset: 100,
|
||||
useDriverRowOffset: true,
|
||||
}),
|
||||
);
|
||||
expect(mocks.executeMulti).toHaveBeenCalledWith("cache-1", "USER", 'SELECT * FROM "SS"."SS_User" ORDER BY "ID" ASC', undefined, expect.any(String), expect.objectContaining({ maxRows: 100, fetchSize: 100, rowOffset: 100 }));
|
||||
});
|
||||
|
||||
it("refreshes one targeted tab while preserving its query context", async () => {
|
||||
const { useQueryStore } = await import("@/stores/queryStore");
|
||||
const store = useQueryStore();
|
||||
|
||||
@@ -2766,6 +2766,7 @@ export const useQueryStore = defineStore("query", () => {
|
||||
const orderBy = tab.orderByInput?.trim() || sortOrder;
|
||||
const limit = tab.resultPageLimit ?? tableOpenPageLimit(settingsStore.editorSettings.tableOpenPageSize);
|
||||
const offset = tab.resultPageOffset ?? 0;
|
||||
const useDriverRowOffset = conn?.db_type === "jdbc" && effectiveDbType === "iris";
|
||||
const refreshPreparationId = uuid();
|
||||
|
||||
// Reserve the tab synchronously before SQL construction yields so repeated
|
||||
@@ -2789,6 +2790,7 @@ export const useQueryStore = defineStore("query", () => {
|
||||
orderBy,
|
||||
limit,
|
||||
offset,
|
||||
...(useDriverRowOffset ? { useDriverRowOffset: true } : {}),
|
||||
});
|
||||
if (!sql.trim()) throw new Error("Failed to build table refresh SQL");
|
||||
const current = tabs.value.find((candidate) => candidate.id === id);
|
||||
@@ -4577,6 +4579,7 @@ export const useQueryStore = defineStore("query", () => {
|
||||
// connection-local state and avoid MySQL pool resets on every refresh.
|
||||
const dataTabMeta = tab.mode === "data" ? tableMetaForDataTab(tab) : undefined;
|
||||
const useTableDataPreview = canUseTableDataLargeValuePreview(effectiveDbType, dataTabMeta?.columns ?? [], dataTabMeta?.primaryKeys ?? []);
|
||||
const useJdbcDriverRowOffset = tab.mode === "data" && conn?.db_type === "jdbc" && effectiveDbType === "iris";
|
||||
const executionOptions = {
|
||||
...(typeof pageLimit === "number"
|
||||
? useAgentResultSession
|
||||
@@ -4589,6 +4592,7 @@ export const useQueryStore = defineStore("query", () => {
|
||||
}
|
||||
: { maxRows: pageLimit, fetchSize: pageLimit }
|
||||
: { maxRows: agentProtocolQueryResultMaxRows(queryResultMaxRows) }),
|
||||
...(useJdbcDriverRowOffset && typeof pageOffset === "number" && pageOffset > 0 ? { rowOffset: pageOffset } : {}),
|
||||
...(executionClientSessionId ? { clientSessionId: executionClientSessionId } : {}),
|
||||
...(tab.mode === "data" && (effectiveDbType === "mysql" || effectiveDbType === "postgres")
|
||||
? {
|
||||
|
||||
Reference in new issue
Block a user