fix(gbase): support 8a and 8s profiles
This commit is contained in:
1 parent
213162aad3
commit
cbc7f9b0db
41 files changed
+596
-50
No files matched your search
@@ -129,6 +129,7 @@ const defaultForm = (): ConnectionForm => ({
|
||||
redis_cluster_nodes: "",
|
||||
redis_key_separator: ":",
|
||||
etcd_endpoints: "",
|
||||
gbase_server: "",
|
||||
read_only: false,
|
||||
visible_databases: undefined,
|
||||
});
|
||||
@@ -388,7 +389,8 @@ const driverProfiles: Record<
|
||||
vertica: { type: "vertica", port: 5433, user: "dbadmin", label: "Vertica", icon: "vertica" },
|
||||
firebird: { type: "firebird", port: 3050, user: "SYSDBA", label: "Firebird", icon: "firebird" },
|
||||
exasol: { type: "exasol", port: 8563, user: "sys", label: "Exasol", icon: "exasol" },
|
||||
gbase: { type: "gbase", port: 5258, user: "gbasedbt", label: "GBase", icon: "gbase" },
|
||||
gbase: { type: "gbase", port: 5258, user: "gbasedbt", label: "GBase 8a", icon: "gbase" },
|
||||
gbase8a: { type: "gbase", port: 5258, user: "gbasedbt", label: "GBase 8a", icon: "gbase" },
|
||||
gbase8s: { type: "gbase", port: 9088, user: "gbasedbt", label: "GBase 8s", icon: "gbase" },
|
||||
opengauss: {
|
||||
type: "opengauss",
|
||||
@@ -545,7 +547,7 @@ function switchOceanbaseMode(mode: "mysql" | "oracle") {
|
||||
resetTestState();
|
||||
}
|
||||
|
||||
function switchGbaseProfile(profile: "gbase" | "gbase8s") {
|
||||
function switchGbaseProfile(profile: "gbase8a" | "gbase8s") {
|
||||
applyProfile(profile, false);
|
||||
selectedType.value = "gbase";
|
||||
resetTestState();
|
||||
@@ -603,7 +605,7 @@ watch(
|
||||
if (profile === "oceanbase") {
|
||||
oceanbaseSubMode.value = config.driver_profile === "oceanbase-oracle" ? "oracle" : "mysql";
|
||||
}
|
||||
if (profile === "gbase8s") {
|
||||
if (profile === "gbase8a" || profile === "gbase8s") {
|
||||
selectedType.value = "gbase";
|
||||
}
|
||||
mongoUseUrl.value = !!config.connection_string;
|
||||
@@ -1590,7 +1592,7 @@ function applyConnectionPrefill(draft: ConnectionDeepLinkDraft) {
|
||||
oceanbaseSubMode.value = "oracle";
|
||||
selectedType.value = "oceanbase";
|
||||
}
|
||||
if (draft.driverProfile === "gbase8s") {
|
||||
if (draft.driverProfile === "gbase8a" || draft.driverProfile === "gbase8s") {
|
||||
selectedType.value = "gbase";
|
||||
}
|
||||
customDriverName.value = isCustomCompatibleProfile() ? draft.driverLabel : "";
|
||||
@@ -2184,7 +2186,7 @@ function openExternalUrl(url: string) {
|
||||
<div v-if="selectedType === 'gbase'" class="grid grid-cols-4 items-center gap-4">
|
||||
<Label class="text-right text-xs">{{ t("connection.version") }}</Label>
|
||||
<div class="col-span-3 flex gap-2">
|
||||
<Button size="sm" :variant="form.driver_profile === 'gbase8s' ? 'outline' : 'default'" @click="switchGbaseProfile('gbase')"> GBase </Button>
|
||||
<Button size="sm" :variant="form.driver_profile === 'gbase8s' ? 'outline' : 'default'" @click="switchGbaseProfile('gbase8a')"> GBase 8a </Button>
|
||||
<Button size="sm" :variant="form.driver_profile === 'gbase8s' ? 'default' : 'outline'" @click="switchGbaseProfile('gbase8s')"> GBase 8s </Button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -2595,6 +2597,11 @@ function openExternalUrl(url: string) {
|
||||
<Input v-model.number="form.port" type="number" class="col-span-1" />
|
||||
</div>
|
||||
|
||||
<div v-if="form.driver_profile === 'gbase8s'" class="grid grid-cols-4 items-center gap-4">
|
||||
<Label class="text-right text-xs">{{ t("connection.gbaseServer") }}</Label>
|
||||
<Input v-model="form.gbase_server" class="col-span-3" placeholder="gbase01" />
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-4 items-center gap-4">
|
||||
<Label class="text-right">{{ t("connection.user") }}</Label>
|
||||
<Input v-model="form.username" class="col-span-3" />
|
||||
|
||||
@@ -66,6 +66,7 @@ const assetIcons: Record<string, string> = {
|
||||
firebird: "firebird.webp",
|
||||
exasol: "exasol.webp",
|
||||
gbase: "gbase.webp",
|
||||
gbase8a: "gbase.webp",
|
||||
gbase8s: "gbase.webp",
|
||||
tdsql: "tdsql.webp",
|
||||
polardb: "polardb.webp",
|
||||
|
||||
@@ -643,6 +643,11 @@ defineExpose({ focusSearch, refreshData, handleModRTarget });
|
||||
{{ t(queryExecutionLabelKey(activeTab)) }}
|
||||
<span class="ml-1 tabular-nums text-muted-foreground/80">· {{ queryRunningElapsedSeconds }}s</span>
|
||||
</div>
|
||||
<Button variant="destructive" size="sm" class="h-7 gap-1.5" :disabled="!canCancelQueryExecution(activeTab)" @click="emit('cancel')">
|
||||
<Loader2 v-if="activeTab.isCancelling" class="h-3.5 w-3.5 animate-spin" />
|
||||
<Square v-else class="h-3.5 w-3.5 fill-current" />
|
||||
{{ t("toolbar.stopQuery") }}
|
||||
</Button>
|
||||
</div>
|
||||
<div v-else-if="!activeTab.result" class="flex-1 min-h-0 flex flex-col items-center justify-center gap-1 text-muted-foreground text-sm">
|
||||
<div>{{ t("editor.pressToExecute", { mod: shortcutModifier }) }}</div>
|
||||
|
||||
@@ -47,7 +47,7 @@ import * as api from "@/lib/api";
|
||||
import type { ConnectionConfig, ObjectInfo, ObjectSourceKind } from "@/types/database";
|
||||
import { isSchemaAware } from "@/lib/databaseCapabilities";
|
||||
import { supportsSchemaDiagram, supportsTableImport, supportsTableStructureEditing, supportsTableTruncate } from "@/lib/databaseFeatureSupport";
|
||||
import { connectionUsesDatabaseObjectTreeMode, effectiveDatabaseTypeForConnection } from "@/lib/jdbcDialect";
|
||||
import { connectionUsesDatabaseObjectTreeMode, effectiveDatabaseTypeForConnection, tableStructureDatabaseTypeForConnection } from "@/lib/jdbcDialect";
|
||||
import { buildTableSelectSql } from "@/lib/tableSelectSql";
|
||||
import { buildDropObjectSql, buildDuplicateTableStructureSql, buildEmptyTableSql, buildTruncateTableSql, type TableAdminSqlOptions } from "@/lib/dbAdminSql";
|
||||
import { useToast } from "@/composables/useToast";
|
||||
@@ -106,6 +106,7 @@ const sourceError = ref("");
|
||||
const sourceRow = ref<ObjectBrowserRow | null>(null);
|
||||
const sourceEditing = ref(false);
|
||||
const effectiveDatabaseType = computed(() => effectiveDatabaseTypeForConnection(props.connection) ?? props.connection.db_type);
|
||||
const tableStructureDatabaseType = computed(() => tableStructureDatabaseTypeForConnection(props.connection) ?? props.connection.db_type);
|
||||
const sourceDraft = ref("");
|
||||
const sourceSaving = ref(false);
|
||||
const sourceSaveError = ref("");
|
||||
@@ -144,7 +145,7 @@ const procedureCount = computed(() => rows.value.filter((row) => row.type === "P
|
||||
const functionCount = computed(() => rows.value.filter((row) => row.type === "FUNCTION").length);
|
||||
const sequenceCount = computed(() => rows.value.filter((row) => row.type === "SEQUENCE").length);
|
||||
const packageCount = computed(() => rows.value.filter((row) => row.type === "PACKAGE" || row.type === "PACKAGE_BODY").length);
|
||||
const canOpenStructureEditor = computed(() => supportsTableStructureEditing(effectiveDatabaseType.value));
|
||||
const canOpenStructureEditor = computed(() => supportsTableStructureEditing(tableStructureDatabaseType.value));
|
||||
const canOpenDiagram = computed(() => !!props.database && supportsSchemaDiagram(effectiveDatabaseType.value));
|
||||
const canOpenTableImport = computed(() => !!props.database && supportsTableImport(effectiveDatabaseType.value));
|
||||
const supportsTruncateTable = computed(() => supportsTableTruncate(effectiveDatabaseType.value));
|
||||
|
||||
@@ -326,7 +326,9 @@ async function ensureTreeLoadedForTarget(target: ActiveTabSidebarTarget, opts?:
|
||||
if (!dbNode) return;
|
||||
const targetSchema = "schema" in target ? target.schema : undefined;
|
||||
const databaseChildrenLoaded = !!dbNode.children && dbNode.children.length > 0;
|
||||
const shouldLoadSchemaTables = target.type === "table" && !!targetSchema && usesTreeSchemaMode(config.db_type) && !connectionUsesDatabaseObjectTreeMode(config);
|
||||
const effectiveDbType = effectiveDatabaseTypeForConnection(config);
|
||||
const usesSchemaTree = usesTreeSchemaMode(effectiveDbType) && !connectionUsesDatabaseObjectTreeMode(config);
|
||||
const shouldLoadSchemaTables = target.type === "table" && !!targetSchema && usesSchemaTree;
|
||||
if (!force && databaseChildrenLoaded && !shouldLoadSchemaTables) return;
|
||||
|
||||
// Load database contents
|
||||
@@ -335,7 +337,7 @@ async function ensureTreeLoadedForTarget(target: ActiveTabSidebarTarget, opts?:
|
||||
if (force || !databaseChildrenLoaded) {
|
||||
await store.loadSqlServerDatabaseObjects(connId, target.database, loadOptions);
|
||||
}
|
||||
} else if (usesTreeSchemaMode(config.db_type) && !connectionUsesDatabaseObjectTreeMode(config)) {
|
||||
} else if (usesSchemaTree) {
|
||||
if (force || !databaseChildrenLoaded) {
|
||||
await store.loadSchemas(connId, target.database, loadOptions);
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ import { buildRenameObjectSql, supportsObjectRename, type RenameableObjectType }
|
||||
import { buildRoutineRenameObjectSourceStatements, supportsSourceBackedRoutineRename } from "@/lib/objectSourceEditor";
|
||||
import { buildViewDdl } from "@/lib/viewDdl";
|
||||
import { getTableStructureCapabilities } from "@/lib/tableStructureCapabilities";
|
||||
import { connectionObjectTreeNodeSchema, connectionObjectTreeQuerySchema, connectionUsesDatabaseObjectTreeMode, effectiveDatabaseTypeForConnection } from "@/lib/jdbcDialect";
|
||||
import { connectionObjectTreeNodeSchema, connectionObjectTreeQuerySchema, connectionUsesDatabaseObjectTreeMode, effectiveDatabaseTypeForConnection, tableStructureDatabaseTypeForConnection } from "@/lib/jdbcDialect";
|
||||
import { hexToRgba } from "@/lib/color";
|
||||
import { focusSidebarRenameInput } from "@/lib/sidebarRenameFocus";
|
||||
import { hasTreeNodeDatabaseContext } from "@/lib/treeNodeContext";
|
||||
@@ -164,6 +164,10 @@ function currentDatabaseType(): DatabaseType | undefined {
|
||||
return props.node.connectionId ? effectiveDatabaseTypeForConnection(connectionStore.getConfig(props.node.connectionId)) : undefined;
|
||||
}
|
||||
|
||||
function currentTableStructureDatabaseType(): DatabaseType | undefined {
|
||||
return props.node.connectionId ? tableStructureDatabaseTypeForConnection(connectionStore.getConfig(props.node.connectionId)) : undefined;
|
||||
}
|
||||
|
||||
function rawDatabaseType(): DatabaseType | undefined {
|
||||
return props.node.connectionId ? connectionStore.getConfig(props.node.connectionId)?.db_type : undefined;
|
||||
}
|
||||
@@ -172,6 +176,10 @@ function databaseTypeForNode(node: TreeNode): DatabaseType | undefined {
|
||||
return node.connectionId ? effectiveDatabaseTypeForConnection(connectionStore.getConfig(node.connectionId)) : undefined;
|
||||
}
|
||||
|
||||
function tableStructureDatabaseTypeForNode(node: TreeNode): DatabaseType | undefined {
|
||||
return node.connectionId ? tableStructureDatabaseTypeForConnection(connectionStore.getConfig(node.connectionId)) : undefined;
|
||||
}
|
||||
|
||||
function hasNodeDatabaseContext(node: TreeNode): node is TreeNode & { connectionId: string; database: string } {
|
||||
return !!node.connectionId && hasTreeNodeDatabaseContext(node);
|
||||
}
|
||||
@@ -361,9 +369,10 @@ async function toggle() {
|
||||
queryStore.updateSql(tab, node.label);
|
||||
} else if (node.type === "database" && node.connectionId && hasTreeNodeDatabaseContext(node)) {
|
||||
const config = connectionStore.getConfig(node.connectionId);
|
||||
const effectiveDbType = effectiveDatabaseTypeForConnection(config);
|
||||
if (config?.db_type === "sqlserver") {
|
||||
await connectionStore.loadSqlServerDatabaseObjects(node.connectionId, node.database);
|
||||
} else if (usesTreeSchemaMode(config?.db_type) && !connectionUsesDatabaseObjectTreeMode(config)) {
|
||||
} else if (usesTreeSchemaMode(effectiveDbType) && !connectionUsesDatabaseObjectTreeMode(config)) {
|
||||
await connectionStore.loadSchemas(node.connectionId, node.database);
|
||||
} else {
|
||||
await connectionStore.loadTables(node.connectionId, node.database);
|
||||
@@ -701,6 +710,20 @@ async function openData() {
|
||||
return queryStore.createTab(node.connectionId, node.database, node.label, "data", tableSchema);
|
||||
})();
|
||||
console.info("[DBX][openData:tab-created]", { traceId, tabId, elapsed: elapsed() });
|
||||
|
||||
// Cancel any previous execution on this tab before starting a new one
|
||||
const existingTab = queryStore.tabs.find((t) => t.id === tabId);
|
||||
if (existingTab?.isExecuting && existingTab.executionId) {
|
||||
await queryStore.cancelTabExecution(tabId);
|
||||
}
|
||||
|
||||
const openDataId = uuid();
|
||||
// Clear previous result so DataGrid doesn't show its internal loading overlay (without stop button)
|
||||
const tab = queryStore.tabs.find((t) => t.id === tabId);
|
||||
if (tab) {
|
||||
tab.result = undefined;
|
||||
tab.results = undefined;
|
||||
}
|
||||
queryStore.setTableMeta(tabId, {
|
||||
schema: tableSchema,
|
||||
tableName: node.label,
|
||||
@@ -708,11 +731,15 @@ async function openData() {
|
||||
columns: [],
|
||||
primaryKeys: [],
|
||||
});
|
||||
queryStore.setExecuting(tabId, true);
|
||||
queryStore.setExecutingWithId(tabId, openDataId);
|
||||
|
||||
// Helper to check if this openData call is still active (not superseded by a newer click)
|
||||
const isActive = () => queryStore.tabs.find((t) => t.id === tabId)?.executionId === openDataId;
|
||||
|
||||
try {
|
||||
console.info("[DBX][openData:ensure-connected:start]", { traceId, elapsed: elapsed() });
|
||||
await connectionStore.ensureConnected(node.connectionId);
|
||||
if (!isActive()) return;
|
||||
console.info("[DBX][openData:ensure-connected:done]", { traceId, elapsed: elapsed() });
|
||||
if (!config) throw new Error("Connection config not found");
|
||||
|
||||
@@ -730,6 +757,7 @@ async function openData() {
|
||||
elapsed: elapsed(),
|
||||
});
|
||||
columns = await api.getColumns(node.connectionId, node.database, querySchema, node.label);
|
||||
if (!isActive()) return;
|
||||
primaryKeys = editablePrimaryKeys(effectiveDbType, columns, node.type === "view" ? "VIEW" : "TABLE");
|
||||
console.info("[DBX][openData:get-columns:done]", {
|
||||
traceId,
|
||||
@@ -748,6 +776,9 @@ async function openData() {
|
||||
console.warn("[DBX][openData:get-columns:error]", { traceId, elapsed: elapsed(), error });
|
||||
}
|
||||
|
||||
// Check if superseded by a newer openData call
|
||||
if (!isActive()) return;
|
||||
|
||||
const includeRowId = usesSyntheticRowIdKey(effectiveDbType, primaryKeys);
|
||||
const fallbackOrderColumns = effectiveDbType === "sqlserver" && !primaryKeys.length ? columns.slice(0, 1).map((column) => column.name) : undefined;
|
||||
const sql = await buildTableSelectSql({
|
||||
@@ -773,6 +804,7 @@ async function openData() {
|
||||
await queryStore.executeTabSql(tabId, sql);
|
||||
console.info("[DBX][openData:execute:done]", { traceId, tabId, elapsed: elapsed() });
|
||||
} catch (e: any) {
|
||||
if (!isActive()) return;
|
||||
console.error("[DBX][openData:error]", { traceId, elapsed: elapsed(), error: e });
|
||||
queryStore.setErrorResult(tabId, e);
|
||||
}
|
||||
@@ -980,7 +1012,7 @@ function dropObjectSqlOptions(): DropObjectSqlOptions | null {
|
||||
function dropObjectSqlOptionsForNode(node: TreeNode): DropObjectSqlOptions | null {
|
||||
if (node.type !== "view" && node.type !== "procedure" && node.type !== "function") return null;
|
||||
return {
|
||||
databaseType: databaseTypeForNode(node),
|
||||
databaseType: tableStructureDatabaseTypeForNode(node),
|
||||
objectType: node.type === "view" ? "VIEW" : node.type === "procedure" ? "PROCEDURE" : "FUNCTION",
|
||||
schema: node.schema,
|
||||
name: node.label,
|
||||
@@ -1421,7 +1453,7 @@ const supportsTruncate = computed(() => {
|
||||
|
||||
const canCreateTable = computed(() => {
|
||||
const config = props.node.connectionId ? connectionStore.getConfig(props.node.connectionId) : undefined;
|
||||
return (props.node.type === "database" || props.node.type === "schema" || props.node.type === "group-tables") && !!props.node.database && supportsTableStructureEditing(effectiveDatabaseTypeForConnection(config));
|
||||
return (props.node.type === "database" || props.node.type === "schema" || props.node.type === "group-tables") && !!props.node.database && supportsTableStructureEditing(tableStructureDatabaseTypeForConnection(config));
|
||||
});
|
||||
|
||||
const canCreateDatabase = computed(() => {
|
||||
@@ -1446,12 +1478,12 @@ const canDropDatabase = computed(() => {
|
||||
|
||||
const canCreateSchema = computed(() => {
|
||||
const config = props.node.connectionId ? connectionStore.getConfig(props.node.connectionId) : undefined;
|
||||
return props.node.type === "database" && usesTreeSchemaMode(config?.db_type) && !connectionUsesDatabaseObjectTreeMode(config);
|
||||
return props.node.type === "database" && usesTreeSchemaMode(effectiveDatabaseTypeForConnection(config)) && !connectionUsesDatabaseObjectTreeMode(config);
|
||||
});
|
||||
|
||||
const canDropSchema = computed(() => {
|
||||
const config = props.node.connectionId ? connectionStore.getConfig(props.node.connectionId) : undefined;
|
||||
return props.node.type === "schema" && usesTreeSchemaMode(config?.db_type) && !connectionUsesDatabaseObjectTreeMode(config);
|
||||
return props.node.type === "schema" && usesTreeSchemaMode(effectiveDatabaseTypeForConnection(config)) && !connectionUsesDatabaseObjectTreeMode(config);
|
||||
});
|
||||
|
||||
function tableAdminSqlOptions(): TableAdminSqlOptions {
|
||||
@@ -2325,7 +2357,7 @@ const canOpenTableImport = computed(() => {
|
||||
return props.node.type === "table" && !!props.node.database && supportsTableImport(currentDatabaseType());
|
||||
});
|
||||
const canOpenStructureEditor = computed(() => {
|
||||
return props.node.type === "table" && !!props.node.database && supportsTableStructureEditing(currentDatabaseType());
|
||||
return props.node.type === "table" && !!props.node.database && supportsTableStructureEditing(currentTableStructureDatabaseType());
|
||||
});
|
||||
const canOpenFieldLineage = computed(() => {
|
||||
return props.node.type === "column" && !!props.node.database && !!props.node.tableName && supportsFieldLineage(currentDatabaseType());
|
||||
|
||||
@@ -24,7 +24,7 @@ import { queryTimeoutSecsForConnection } from "@/lib/queryTimeout";
|
||||
import { type EditableStructureColumn, type EditableStructureForeignKey, type EditableStructureIndex, type EditableStructureTrigger } from "@/lib/tableStructureEditorSql";
|
||||
import { getTableMetadataCapabilities } from "@/lib/tableMetadataCapabilities";
|
||||
import { getTableStructureCapabilities } from "@/lib/tableStructureCapabilities";
|
||||
import { connectionObjectTreeQuerySchema, effectiveDatabaseTypeForConnection } from "@/lib/jdbcDialect";
|
||||
import { connectionObjectTreeQuerySchema, tableStructureDatabaseTypeForConnection } from "@/lib/jdbcDialect";
|
||||
import {
|
||||
buildStructureTargetLabel,
|
||||
combineDataTypeForDatabase,
|
||||
@@ -279,7 +279,7 @@ function onIndexColResize(e: MouseEvent, col: number) {
|
||||
}
|
||||
|
||||
const connection = computed(() => (props.connectionId ? store.getConfig(props.connectionId) : undefined));
|
||||
const databaseType = computed(() => effectiveDatabaseTypeForConnection(connection.value));
|
||||
const databaseType = computed(() => tableStructureDatabaseTypeForConnection(connection.value));
|
||||
const structureCapabilities = computed(() => getTableStructureCapabilities(databaseType.value));
|
||||
const tableMetadataCapabilities = computed(() => getTableMetadataCapabilities(databaseType.value));
|
||||
const structureDialect = computed(() => structureCapabilities.value.dialect);
|
||||
|
||||
Reference in new issue
Block a user