fix(mysql): strip CLI \G suffix before executing queries

This commit is contained in:
zipg authored and GitHub committed 2026-09-17 02:15:13 +08:00
1 parent b85062cd74
commit 4644015201
5 files changed
+82 -8

No files matched your search

@@ -106,6 +106,14 @@ describe("queryStore MySQL grouped-result editing", () => {
expect(listIndexes).not.toHaveBeenCalled();
});
it("strips the MySQL CLI vertical-output suffix only from the submitted SQL", async () => {
const sourceSql = "SHOW CREATE FUNCTION fun_grade \\G;";
const tab = await executeGrouped(sourceSql, ["Create Function"]);
expect(executeMulti.mock.calls[0]?.[2]).toBe("SHOW CREATE FUNCTION fun_grade;");
expect(tab.lastExecutedSql).toBe(sourceSql);
});
it("identifies the FROM root independently of metadata completion order", async () => {
getColumns.mockImplementation(async (_connectionId: string, _database: string, _schema: string, table: string) => {
if (table === "users") await new Promise((resolve) => setTimeout(resolve, 10));
@@ -132,4 +132,29 @@ describe("queryStore query result export", () => {
expect(request?.useAgentCursor).toBe(true);
});
it("strips the MySQL CLI vertical-output suffix from export re-execution SQL", async () => {
mocks.getConfig.mockReturnValue({ id: "mysql-1", name: "MySQL", db_type: "mysql", database: "app", query_timeout_secs: 30 });
const { useQueryStore } = await import("@/stores/queryStore");
const store = useQueryStore();
const tabId = store.createTab("mysql-1", "app", "Query");
const tab = store.tabs.find((item) => item.id === tabId)!;
tab.sql = "SHOW CREATE FUNCTION fun_grade \\G";
tab.lastExecutedSql = tab.sql;
tab.result = {
columns: ["Create Function"],
rows: [["definition"]],
affected_rows: 0,
execution_time_ms: 1,
};
const request = await store.buildQueryResultExportRequest(tabId, {
exportId: "export-g",
filePath: "fun.csv",
format: "csv",
});
expect(request?.sql).toBe("SHOW CREATE FUNCTION fun_grade");
expect(request?.queryBaseSql).toBe("SHOW CREATE FUNCTION fun_grade");
});
});
+13 -7
View File
@@ -59,7 +59,7 @@ import { appendLargeValueCells, canUseTableDataLargeValuePreview, remapLargeValu
import { simpleDataGridOrderByReferencesMissingColumn, sortDataGridRowIndexes, type DataGridSortDirection } from "@/lib/dataGrid/dataGridSort";
import { normalizeResultPageSize } from "@/lib/dataGrid/paginationPageSize";
import { agentProtocolQueryResultMaxRows, capQueryResultTotal, effectiveQueryResultMaxRows, limitQueryPagination, queryResultLimitReached } from "@/lib/dataGrid/queryResultRowLimit";
import { elasticsearchRestRequestRanges, executableStatementRanges, splitSqlStatementRanges, sqlStatementParameterOptionsForCompatibility } from "@/lib/sql/sqlStatementRanges";
import { elasticsearchRestRequestRanges, executableStatementRanges, splitSqlStatementRanges, sqlStatementParameterOptionsForCompatibility, stripMysqlClientDisplayCommand } from "@/lib/sql/sqlStatementRanges";
import type { SqlParameterOptions } from "@/lib/sql/sqlParameters";
import { replaceSqlServerLeadingUseQuery, sqlServerLeadingUseScript, sqlServerUseDatabaseFromStatement } from "@/lib/sql/sqlCompletionLookupTarget";
import { classifySqlRisk } from "@/lib/sql/sqlRisk";
@@ -6241,6 +6241,9 @@ export const useQueryStore = defineStore("query", () => {
mongoCommands = splitMongoCommandRanges(sql);
}
const effectiveDbType = effectiveDatabaseTypeForConnection(conn);
if (effectiveDbType === "mysql") {
sqlToExecute = stripMysqlClientDisplayCommand(sqlToExecute);
}
if (tab.autoCommit === false && !supportsTransaction(conn?.db_type)) {
tab.autoCommit = true;
}
@@ -8291,12 +8294,13 @@ export const useQueryStore = defineStore("query", () => {
await connStore.ensureConnected(location.connectionId);
const conn = connStore.getConfig(location.connectionId);
const effectiveDbType = effectiveDatabaseTypeForConnection(conn);
const executableSql = effectiveDbType === "mysql" ? stripMysqlClientDisplayCommand(sql) : sql;
const executionDatabase = dataTabExecutionDatabase(conn, location.database, location.catalog);
// main 引入全局查询超时:queryTimeoutSecsForConnection 现需传入全局默认值;
// settingsStore 取 defineStore 顶层声明的实例(本函数无局部覆盖)。
const queryTimeoutSecs = queryTimeoutSecsForConnection(conn, settingsStore.editorSettings.globalQueryTimeoutSecs);
const useAgentCursor = usesAgentCursorForQuery(conn?.db_type, conn?.driver_profile);
const queryBaseSql = queryResultBaseSql(tab);
const queryBaseSql = effectiveDbType === "mysql" ? stripMysqlClientDisplayCommand(queryResultBaseSql(tab)) : queryResultBaseSql(tab);
const exportSettings = useSettingsStore().editorSettings;
const exportRowLimit = exportSettings.exportRowLimitEnabled ? exportSettings.exportRowLimit : Number.POSITIVE_INFINITY;
@@ -8375,7 +8379,7 @@ export const useQueryStore = defineStore("query", () => {
const remaining = exportRowLimit - rows.length;
const effectivePageLimit = Math.min(pageLimit, remaining);
const plan = await api.prepareQueryPaginationExecutionPlan({
sql,
sql: executableSql,
queryBaseSql,
databaseType: effectiveDbType,
pagination: { limit: effectivePageLimit, offset, sessionId },
@@ -8437,7 +8441,8 @@ export const useQueryStore = defineStore("query", () => {
if (!effectiveDbType) return undefined;
if (effectiveDbType === "mongodb") return undefined;
const useAgentCursor = usesAgentCursorForQuery(conn?.db_type, conn?.driver_profile);
const queryBaseSql = queryResultBaseSql(tab);
const executableSql = effectiveDbType === "mysql" ? stripMysqlClientDisplayCommand(sql) : sql;
const queryBaseSql = effectiveDbType === "mysql" ? stripMysqlClientDisplayCommand(queryResultBaseSql(tab)) : queryResultBaseSql(tab);
const resultStatementIndex = tab.result.statement_index;
const batchSql = tab.resultBaseSql ?? tab.lastExecutedSql ?? tab.sql;
const batchStatements = effectiveDbType === "postgres" && tab.result.truncated === true && Number.isInteger(resultStatementIndex) && resultStatementIndex! > 0 ? splitSqlStatementRanges(batchSql, effectiveDbType) : [];
@@ -8452,7 +8457,7 @@ export const useQueryStore = defineStore("query", () => {
database: dataTabExecutionDatabase(conn, location.database, location.catalog),
schema: location.schema,
catalog: location.catalog,
sql,
sql: executableSql,
queryBaseSql,
setupSql,
databaseType: effectiveDbType,
@@ -8488,13 +8493,14 @@ export const useQueryStore = defineStore("query", () => {
if (!effectiveDbType) return;
const exportId = uuid();
const executableSql = effectiveDbType === "mysql" ? stripMysqlClientDisplayCommand(sql) : sql;
const request: api.QueryResultExportRequest = {
exportId,
connectionId: tab.connectionId,
database: tab.database,
schema: tab.schema,
sql,
queryBaseSql: sql,
sql: executableSql,
queryBaseSql: executableSql,
databaseType: effectiveDbType,
useAgentCursor: usesAgentCursorForQuery(conn?.db_type, conn?.driver_profile),
filePath,