diff --git a/frontend/src/components/DataGrid.ddl.test.tsx b/frontend/src/components/DataGrid.ddl.test.tsx
index 7625aff..5f8ea08 100644
--- a/frontend/src/components/DataGrid.ddl.test.tsx
+++ b/frontend/src/components/DataGrid.ddl.test.tsx
@@ -1246,10 +1246,48 @@ describe('DataGrid DDL interactions', () => {
expect(editors).toHaveLength(1);
expect(editors[0].props['data-language']).toBe('sql');
expect(editors[0].props['data-read-only']).toBe('true');
- expect(textContent(editors[0])).toContain('CREATE TABLE users');
+ expect(textContent(editors[0])).toContain('CREATE TABLE');
+ expect(textContent(editors[0])).toContain('users');
expect(renderer!.root.findAll((node) => node.type === 'pre' && textContent(node).includes('CREATE TABLE users'))).toHaveLength(0);
});
+ it('formats DuckDB DDL into readable multiline SQL in the v2 view', async () => {
+ storeState.appearance.uiVersion = 'v2';
+ storeState.connections[0].config.type = 'duckdb';
+ backendApp.DBShowCreateTable.mockResolvedValueOnce({
+ success: true,
+ data: 'CREATE TABLE customers(customer_id BIGINT, customer_code VARCHAR, city VARCHAR, tier VARCHAR, signup_date DATE, lifetime_value DECIMAL(12,2), PRIMARY KEY(customer_id));',
+ });
+
+ let renderer: ReactTestRenderer;
+ await act(async () => {
+ renderer = create(
+ ,
+ );
+ });
+ await waitForEffects();
+
+ await act(async () => {
+ findButton(renderer!, '查看 DDL').props.onClick();
+ });
+ await waitForEffects();
+
+ const editors = renderer!.root.findAll((node) => node.props['data-monaco-editor'] === 'true');
+ expect(editors).toHaveLength(1);
+ const ddlText = textContent(editors[0]);
+ expect(ddlText).toContain('CREATE TABLE customers (');
+ expect(ddlText).toContain('customer_id BIGINT,');
+ expect(ddlText).toContain('PRIMARY KEY (customer_id)');
+ expect(ddlText).toContain('\n');
+ });
+
it('opens the v2 DDL view as a right sidebar while keeping the table visible', async () => {
storeState.appearance.uiVersion = 'v2';
backendApp.DBShowCreateTable.mockResolvedValueOnce({
diff --git a/frontend/src/components/DataGrid.tsx b/frontend/src/components/DataGrid.tsx
index b860102..21debb6 100644
--- a/frontend/src/components/DataGrid.tsx
+++ b/frontend/src/components/DataGrid.tsx
@@ -3214,6 +3214,7 @@ const DataGrid: React.FC = ({
canViewDdl,
currentConnConfig,
dbName,
+ dbType,
tableName,
isV2Ui,
cellEditMode,
diff --git a/frontend/src/components/useDataGridDdlView.ts b/frontend/src/components/useDataGridDdlView.ts
index da1bbab..5ab694c 100644
--- a/frontend/src/components/useDataGridDdlView.ts
+++ b/frontend/src/components/useDataGridDdlView.ts
@@ -1,6 +1,7 @@
import React from 'react';
import { DBShowCreateTable } from '../../wailsjs/go/app/App';
import { buildRpcConnectionConfig } from '../utils/connectionRpcConfig';
+import { formatDdlForDisplay } from '../utils/ddlFormat';
type GridViewMode = 'table' | 'json' | 'text' | 'fields' | 'ddl' | 'er';
type DdlViewLayoutMode = 'bottom' | 'side';
@@ -20,6 +21,7 @@ interface UseDataGridDdlViewParams {
messageApi: {
error: (content: string) => void;
};
+ dbType?: string;
}
export interface UseDataGridDdlViewResult {
@@ -54,6 +56,7 @@ export const useDataGridDdlView = ({
closeCellEditModeRef,
setTextRecordIndex,
messageApi,
+ dbType,
}: UseDataGridDdlViewParams): UseDataGridDdlViewResult => {
const [viewMode, setViewMode] = React.useState('table');
const [ddlModalOpen, setDdlModalOpen] = React.useState(false);
@@ -92,7 +95,7 @@ export const useDataGridDdlView = ({
const res = await DBShowCreateTable(buildRpcConnectionConfig(currentConnConfig as any) as any, dbName || '', tableName);
if (requestSeq !== ddlRequestSeqRef.current) return;
if (res.success) {
- setDdlText(String(res.data ?? ''));
+ setDdlText(formatDdlForDisplay(res.data, dbType || String((currentConnConfig as any)?.type || '')));
return;
}
messageApi.error(res.message || '获取 DDL 失败');
@@ -104,7 +107,7 @@ export const useDataGridDdlView = ({
setDdlLoading(false);
}
}
- }, [canViewDdl, currentConnConfig, dbName, isV2Ui, messageApi, tableName]);
+ }, [canViewDdl, currentConnConfig, dbName, dbType, isV2Ui, messageApi, tableName]);
React.useEffect(() => {
if (isV2Ui || (viewMode !== 'fields' && viewMode !== 'ddl' && viewMode !== 'er')) return;
diff --git a/frontend/src/utils/ddlFormat.test.ts b/frontend/src/utils/ddlFormat.test.ts
new file mode 100644
index 0000000..cbbaea5
--- /dev/null
+++ b/frontend/src/utils/ddlFormat.test.ts
@@ -0,0 +1,22 @@
+import { describe, expect, it } from 'vitest';
+
+import { formatDdlForDisplay } from './ddlFormat';
+
+describe('formatDdlForDisplay', () => {
+ it('formats DuckDB create table SQL into multiline output', () => {
+ const raw = 'CREATE TABLE customers(customer_id BIGINT, customer_code VARCHAR, city VARCHAR, tier VARCHAR, signup_date DATE, lifetime_value DECIMAL(12,2), PRIMARY KEY(customer_id));';
+
+ const formatted = formatDdlForDisplay(raw, 'duckdb');
+
+ expect(formatted).toContain('CREATE TABLE customers (');
+ expect(formatted).toContain('customer_id BIGINT,');
+ expect(formatted).toContain('PRIMARY KEY (customer_id)');
+ expect(formatted).toContain('\n');
+ });
+
+ it('returns original text when formatter cannot parse the statement', () => {
+ const raw = 'not valid ddl(';
+
+ expect(formatDdlForDisplay(raw, 'duckdb')).toBe(raw);
+ });
+});
diff --git a/frontend/src/utils/ddlFormat.ts b/frontend/src/utils/ddlFormat.ts
new file mode 100644
index 0000000..a3e5c0c
--- /dev/null
+++ b/frontend/src/utils/ddlFormat.ts
@@ -0,0 +1,53 @@
+import { format } from 'sql-formatter';
+
+const resolveDdlFormatterLanguage = (dbType: string): string | null => {
+ const normalized = String(dbType || '').trim().toLowerCase();
+ switch (normalized) {
+ case 'duckdb':
+ return 'duckdb';
+ case 'sqlite':
+ return 'sqlite';
+ case 'postgres':
+ case 'postgresql':
+ case 'kingbase':
+ case 'highgo':
+ case 'opengauss':
+ case 'vastbase':
+ return 'postgresql';
+ case 'mariadb':
+ return 'mariadb';
+ case 'mysql':
+ case 'sphinx':
+ return 'mysql';
+ case 'sqlserver':
+ return 'transactsql';
+ case 'oracle':
+ case 'dameng':
+ case 'oceanbase':
+ return 'plsql';
+ case 'clickhouse':
+ return 'clickhouse';
+ default:
+ return 'sql';
+ }
+};
+
+export const formatDdlForDisplay = (ddlText: unknown, dbType: string): string => {
+ const raw = String(ddlText ?? '').trim();
+ if (!raw) {
+ return '';
+ }
+ const language = resolveDdlFormatterLanguage(dbType);
+ if (!language) {
+ return raw;
+ }
+ try {
+ return format(raw, {
+ language,
+ keywordCase: 'upper',
+ linesBetweenQueries: 1,
+ });
+ } catch {
+ return raw;
+ }
+};