fix: support mysql install scripts without selected database (#2356)

This commit is contained in:
onenewcode authored and GitHub committed 2026-07-02 13:18:49 +08:00
1 parent 730f839e74
commit 71e618dd46
12 files changed
+975 -90

No files matched your search

@@ -39,8 +39,20 @@ describe("requiresDatabaseSelection", () => {
expect(requiresDatabaseSelection(queryTab(), connection("mysql"), "CREATE SCHEMA `app-db` DEFAULT CHARACTER SET utf8mb4")).toBe(false);
});
it("requires a database when a MySQL batch includes non-creation statements", () => {
expect(requiresDatabaseSelection(queryTab(), connection("mysql"), "CREATE DATABASE app_db; SELECT * FROM users")).toBe(true);
it("allows MySQL install batches that switch databases before table DDL", () => {
expect(requiresDatabaseSelection(queryTab(), connection("mysql"), "CREATE DATABASE app_db; USE app_db; CREATE TABLE users(id INT PRIMARY KEY)")).toBe(false);
});
it("allows MySQL install batches with session setup before switching databases", () => {
expect(requiresDatabaseSelection(queryTab(), connection("mysql"), "SET NAMES utf8mb4; DROP DATABASE IF EXISTS app_db; CREATE DATABASE app_db; USE app_db; INSERT INTO users VALUES (1)")).toBe(false);
});
it("requires a database when MySQL batch statements never establish database context", () => {
expect(requiresDatabaseSelection(queryTab(), connection("mysql"), "CREATE DATABASE app_db; CREATE TABLE users(id INT)")).toBe(true);
});
it("requires a database when a USE statement is not a standalone database switch", () => {
expect(requiresDatabaseSelection(queryTab(), connection("mysql"), "CREATE DATABASE app_db; USE app_db SELECT 1; CREATE TABLE users(id INT)")).toBe(true);
});
it("still requires a database for ordinary MySQL queries", () => {
@@ -6,6 +6,7 @@ import { useConnectionStore } from "@/stores/connectionStore";
import { useSettingsStore } from "@/stores/settingsStore";
import { useToast } from "@/composables/useToast";
import { isSingleDatabase } from "@/lib/databaseCapabilities";
import { canExecuteWithoutSelectedDatabase } from "@/lib/connectionLevelDatabaseBootstrap";
import { classifySqlActivityKind } from "@/lib/historyActivityKind";
import { sqlMetadataRefreshTarget } from "@/lib/sqlMetadataRefresh";
import { classifyRedisCommandSafety, firstRedisCommandToken } from "@/lib/redisCommandSafety";
@@ -14,7 +15,6 @@ import { extractSqlParameters } from "@/lib/sqlParameters";
import type { ConnectionConfig, QueryTab } from "@/types/database";
const DANGER_RE = /^\s*(DROP|DELETE|TRUNCATE|ALTER|UPDATE|MERGE|REPLACE)\b/i;
const CONNECTION_LEVEL_CREATE_DATABASE_RE = /^\s*CREATE\s+(?:DATABASE|SCHEMA)\s+(?:IF\s+NOT\s+EXISTS\s+)?[`"[\]\w$.-]+/i;
export function stripSqlComments(sql: string): string {
return sql
@@ -227,17 +227,6 @@ function supportsSqlTemplateParameters(connection: ConnectionConfig | undefined)
return connection.db_type !== "redis" && connection.db_type !== "mongodb";
}
function canExecuteWithoutSelectedDatabase(connection: ConnectionConfig, sql: string): boolean {
if (connection.db_type !== "mysql") return false;
const statements = stripSqlComments(sql)
.split(";")
.map((stmt) => stmt.trim())
.filter(Boolean);
// Only connection-level database creation may bypass the selected-database guard.
if (statements.length !== 1) return false;
return CONNECTION_LEVEL_CREATE_DATABASE_RE.test(statements[0]);
}
export function requiresDatabaseSelection(tab: QueryTab, connection: ConnectionConfig | undefined, sql = ""): boolean {
if (tab.mode !== "query") return false;
if (!connection || tab.database) return false;