feat(gbase8s): read create-database locale options from the instance

This commit is contained in:
弈秋 authored and GitHub committed 2026-09-17 11:40:58 +08:00
1 parent 48d0ebc90e
commit 8c6acaad3d
3 files changed
+50 -4

No files matched your search

@@ -202,7 +202,7 @@ import { savedSqlClipboardFileIds, savedSqlPasteTargetForNode } from "@/lib/save
import { exportSavedSqlFileContent } from "@/lib/savedSql/savedSqlExport";
import { isSqlServerLinkedNode } from "@/lib/database/sqlServerLinkedServers";
import { flattenTree } from "@/composables/useFlatTree";
import { createDatabaseCollationOptionsForCharset, DEFAULT_GBASE8S_DATABASE_LOCALE, GBASE8S_DATABASE_LOCALES, nextCreateDatabaseCollation, normalizeCreateDatabaseCharset, parseCreateDatabaseCharsetMetadata } from "@/lib/database/createDatabaseCharsetOptions";
import { createDatabaseCollationOptionsForCharset, DEFAULT_GBASE8S_DATABASE_LOCALE, defaultGbase8sDatabaseLocale, GBASE8S_DATABASE_LOCALES, nextCreateDatabaseCollation, normalizeCreateDatabaseCharset, parseCreateDatabaseCharsetMetadata } from "@/lib/database/createDatabaseCharsetOptions";
import { executeWithProductionContextGuard, executeWithProductionSqlGuard } from "@/lib/database/productionExecutionGuard";
import { connectionIsEffectivelyReadOnly } from "@/lib/database/readOnlyWriteAccess";
import { buildXuguCompileSql } from "@/lib/database/xuguCompileSql";
@@ -3828,12 +3828,13 @@ function openCreateDatabaseDialog() {
showCreateDatabaseDialog.value = true;
if (canSetCreateDatabaseLocale.value) {
// GBase 8s / Informix: the "charset" control selects the new database's DB_LOCALE, which the
// agent applies by opening the CREATE DATABASE session with it. Default to UTF-8 so new
// databases can store Chinese; no server charset catalog query is needed.
// agent applies by opening the CREATE DATABASE session with it. Seed a UTF-8 default, then
// repopulate the options with the collations already present on the connected instance.
createDatabaseCharsetOptions.value = [...GBASE8S_DATABASE_LOCALES];
createDatabaseCollationsByCharset.value = {};
createDatabaseCharset.value = DEFAULT_GBASE8S_DATABASE_LOCALE;
createDatabaseCollation.value = "";
void loadGbase8sDatabaseLocales();
} else if (canSetCreateDatabaseCharset.value) {
void loadCreateDatabaseCharsetMetadata();
}
@@ -3958,6 +3959,33 @@ async function loadCreateDatabaseCharsetMetadata(target: "create" | "edit" = "cr
}
}
async function loadGbase8sDatabaseLocales() {
const node = activeNode.value;
if (!node.connectionId) return;
createDatabaseCharsetLoading.value = true;
try {
await connectionStore.ensureConnected(node.connectionId);
const result = await api.executeQuery(node.connectionId, "", "SELECT DISTINCT dbs_collate FROM sysmaster:sysdbslocale ORDER BY 1", undefined, undefined, { maxRows: 500 });
if (!showCreateDatabaseDialog.value) return;
const idx = result.columns.findIndex((column) => column.trim().toLowerCase() === "dbs_collate");
const locales = [...new Set(result.rows.map((row) => String(row[idx >= 0 ? idx : 0] ?? "").trim()).filter(Boolean))];
if (!locales.length) throw new Error("no collations");
createDatabaseCharsetOptions.value = locales;
createDatabaseCollationsByCharset.value = {};
if (!locales.includes(createDatabaseCharset.value)) {
updateCreateDatabaseCharset(defaultGbase8sDatabaseLocale(locales));
}
} catch {
createDatabaseCharsetOptions.value = [...GBASE8S_DATABASE_LOCALES];
createDatabaseCollationsByCharset.value = {};
if (!createDatabaseCharsetOptions.value.includes(createDatabaseCharset.value)) {
updateCreateDatabaseCharset(DEFAULT_GBASE8S_DATABASE_LOCALE);
}
} finally {
createDatabaseCharsetLoading.value = false;
}
}
function ensureDuckDbFileExtension(path: string): string {
return /\.(duckdb|db)$/i.test(path) ? path : `${path}.duckdb`;
}
@@ -1,6 +1,6 @@
import { describe, expect, it } from "vitest";
import { supportsCreateDatabaseCharset, supportsCreateDatabaseLocale } from "@/lib/database/createDatabaseSql";
import { DEFAULT_GBASE8S_DATABASE_LOCALE, GBASE8S_DATABASE_LOCALES } from "@/lib/database/createDatabaseCharsetOptions";
import { DEFAULT_GBASE8S_DATABASE_LOCALE, defaultGbase8sDatabaseLocale, GBASE8S_DATABASE_LOCALES } from "@/lib/database/createDatabaseCharsetOptions";
describe("GBase 8s / Informix create-database locale support", () => {
it("offers a locale picker only for the gbase8s profile", () => {
@@ -22,4 +22,16 @@ describe("GBase 8s / Informix create-database locale support", () => {
expect(GBASE8S_DATABASE_LOCALES).toContain("zh_CN.utf8");
expect(DEFAULT_GBASE8S_DATABASE_LOCALE).toBe("zh_CN.utf8");
});
it("seeds the default from instance locales reporting the numeric UTF-8 code set", () => {
// Real GBase 8s instances report dbs_collate like zh_CN.57372 (57372 = UTF-8) alongside
// en_US.819 (ISO-8859-1); after ORDER BY 1 the plain first entry cannot hold CJK.
expect(defaultGbase8sDatabaseLocale(["en_US.819", "zh_CN.57372"])).toBe("zh_CN.57372");
expect(defaultGbase8sDatabaseLocale(["en_US.819", "zh_CN.utf8"])).toBe("zh_CN.utf8");
});
it("falls back to the first locale or the static default when no UTF-8 option exists", () => {
expect(defaultGbase8sDatabaseLocale(["en_US.819"])).toBe("en_US.819");
expect(defaultGbase8sDatabaseLocale([])).toBe(DEFAULT_GBASE8S_DATABASE_LOCALE);
});
});
@@ -16,6 +16,12 @@ export const CREATE_DATABASE_CHARSET_OPTIONS = ["utf8mb4", "utf8", "gbk", "latin
export const GBASE8S_DATABASE_LOCALES = ["zh_CN.utf8", "en_US.utf8", "ja_JP.utf8", "ko_KR.utf8", "zh_CN.gbk", "zh_CN.gb18030", "en_US.819"] as const;
export const DEFAULT_GBASE8S_DATABASE_LOCALE = "zh_CN.utf8";
// Informix-family instances report dbs_collate with the numeric code set (57372 = UTF-8,
// 819 = ISO-8859-1) instead of the "utf8" mnemonic, so both spellings must seed the default.
export function defaultGbase8sDatabaseLocale(locales: string[]): string {
return locales.find((locale) => /(?:utf8|57372)/i.test(locale)) ?? locales[0] ?? DEFAULT_GBASE8S_DATABASE_LOCALE;
}
const FALLBACK_COLLATION_OPTIONS: Record<string, string[]> = {
ascii: ["ascii_general_ci", "ascii_bin"],
big5: ["big5_chinese_ci", "big5_bin"],