From 5a4c1e4c4eeb63a6af584cbd8e6ce94ffd3997c1 Mon Sep 17 00:00:00 2001
From: AutumnNazi <104422820+AutumnNazi@users.noreply.github.com>
Date: Wed, 29 Jul 2026 17:22:36 +0800
Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20fix(dameng):=20=E4=BF=AE?=
=?UTF-8?q?=E5=A4=8D=E7=B3=BB=E7=BB=9F=E8=A7=86=E5=9B=BE=E6=9F=A5=E8=AF=A2?=
=?UTF-8?q?=E8=A2=AB=E6=B3=A8=E5=85=A5=20ROWID?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 达梦系统视图字段元数据为空时按只读结果处理\n- 避免 DBA_TAB_PRIVS 和 USER_COL_COMMENTS 查询追加 ROWID\n- 增加两个达梦系统视图查询回归测试
---
.../QueryEditor.external-sql-save.test.tsx | 81 +++++++++++++++++++
.../queryEditor/QueryEditorHelpers.ts | 4 +
2 files changed, 85 insertions(+)
diff --git a/frontend/src/components/QueryEditor.external-sql-save.test.tsx b/frontend/src/components/QueryEditor.external-sql-save.test.tsx
index 23f8a43a..67d747b8 100644
--- a/frontend/src/components/QueryEditor.external-sql-save.test.tsx
+++ b/frontend/src/components/QueryEditor.external-sql-save.test.tsx
@@ -9509,6 +9509,87 @@ describe('QueryEditor external SQL save', () => {
expect(messageApi.warning).not.toHaveBeenCalled();
});
+ it('keeps Dameng USER_COL_COMMENTS queries read-only without injecting ROWID', async () => {
+ storeState.connections[0].config.type = 'dameng';
+ storeState.connections[0].config.database = 'APP';
+ const sql = `SELECT T.TABLE_NAME, T.COLUMN_NAME, T.COMMENTS
+FROM USER_COL_COMMENTS T
+WHERE T.TABLE_NAME = 'MEITUAN_COMMENT_INFO';`;
+ backendApp.DBGetColumns.mockResolvedValueOnce({ success: true, data: [] });
+ backendApp.DBGetIndexes.mockResolvedValueOnce({ success: true, data: [] });
+ backendApp.DBQueryMulti.mockResolvedValueOnce({
+ success: true,
+ data: [{
+ columns: ['TABLE_NAME', 'COLUMN_NAME', 'COMMENTS'],
+ rows: [{
+ TABLE_NAME: 'MEITUAN_COMMENT_INFO',
+ COLUMN_NAME: 'CONTENT',
+ COMMENTS: '评论内容',
+ }],
+ }],
+ });
+
+ let renderer: ReactTestRenderer;
+ await act(async () => {
+ renderer = create();
+ });
+
+ await act(async () => {
+ await findButton(renderer!, '运行').props.onClick();
+ });
+ await act(async () => {
+ await Promise.resolve();
+ await Promise.resolve();
+ });
+
+ const executedSql = String(backendApp.DBQueryMulti.mock.calls[0][2]);
+ expect(executedSql).toContain('FROM USER_COL_COMMENTS T');
+ expect(executedSql).not.toMatch(/\bROWID\b/i);
+ expect(dataGridState.latestProps?.editLocator).toMatchObject({ readOnly: true });
+ expect(dataGridState.latestProps?.readOnly).toBe(true);
+ });
+
+ it('keeps Dameng DBA_TAB_PRIVS queries read-only without injecting ROWID', async () => {
+ storeState.connections[0].config.type = 'dameng';
+ storeState.connections[0].config.database = 'APP';
+ const sql = `SELECT *
+FROM DBA_TAB_PRIVS
+WHERE GRANTEE = 'APPUSER';`;
+ backendApp.DBGetColumns.mockResolvedValueOnce({ success: true, data: [] });
+ backendApp.DBGetIndexes.mockResolvedValueOnce({ success: true, data: [] });
+ backendApp.DBQueryMulti.mockResolvedValueOnce({
+ success: true,
+ data: [{
+ columns: ['GRANTEE', 'OWNER', 'TABLE_NAME', 'PRIVILEGE'],
+ rows: [{
+ GRANTEE: 'APPUSER',
+ OWNER: 'APPUSER',
+ TABLE_NAME: 'MEITUAN_COMMENT_INFO',
+ PRIVILEGE: 'SELECT',
+ }],
+ }],
+ });
+
+ let renderer: ReactTestRenderer;
+ await act(async () => {
+ renderer = create();
+ });
+
+ await act(async () => {
+ await findButton(renderer!, '运行').props.onClick();
+ });
+ await act(async () => {
+ await Promise.resolve();
+ await Promise.resolve();
+ });
+
+ const executedSql = String(backendApp.DBQueryMulti.mock.calls[0][2]);
+ expect(executedSql).toContain('FROM DBA_TAB_PRIVS');
+ expect(executedSql).not.toMatch(/\bROWID\b/i);
+ expect(dataGridState.latestProps?.editLocator).toMatchObject({ readOnly: true });
+ expect(dataGridState.latestProps?.readOnly).toBe(true);
+ });
+
it('uses Oracle login user as default schema for unqualified query result metadata', async () => {
storeState.connections[0].config.type = 'oracle';
storeState.connections[0].config.user = 'dev';
diff --git a/frontend/src/components/queryEditor/QueryEditorHelpers.ts b/frontend/src/components/queryEditor/QueryEditorHelpers.ts
index 4935019f..d4a834b5 100644
--- a/frontend/src/components/queryEditor/QueryEditorHelpers.ts
+++ b/frontend/src/components/queryEditor/QueryEditorHelpers.ts
@@ -2771,6 +2771,10 @@ export const resolveQueryLocatorPlan = async ({
const tableColumns = resCols.data as ColumnDefinition[];
const tableColumnNames = tableColumns.map(getColumnDefinitionName).filter(Boolean);
+ if (tableColumnNames.length === 0) {
+ plan.editLocator = buildQueryReadOnlyLocator(translate('query_editor.message.read_only_system_metadata'));
+ return plan;
+ }
let executableStatement = statement;
if (isOracleLikeDialect(dbType) && selectInfo.selectsAll) {
const rewritten = rewriteOracleDuplicateSelectColumns(executableStatement, tableColumnNames);