mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-07-02 13:01:45 +08:00
🐛 fix(query-results): 修复多结果集回退空结果页
This commit is contained in:
@@ -1105,6 +1105,50 @@ describe('QueryEditor external SQL save', () => {
|
||||
expect(textContent(renderer!.toJSON())).not.toContain('影响行数:0');
|
||||
});
|
||||
|
||||
it('shows the data result tab in V2 when the SQL log tab is already visible', async () => {
|
||||
storeState.appearance.uiVersion = 'v2';
|
||||
storeState.sqlLogs = [{
|
||||
id: 'log-existing',
|
||||
timestamp: Date.now(),
|
||||
sql: 'SELECT * FROM ldf_server.mes_work_order',
|
||||
status: 'success',
|
||||
duration: 120,
|
||||
}];
|
||||
storeState.connections[0].config.type = 'kingbase';
|
||||
storeState.connections[0].config.database = 'ldf_server_dbs_dev';
|
||||
backendApp.DBQueryMulti.mockResolvedValueOnce({
|
||||
success: true,
|
||||
data: [{
|
||||
statementIndex: 1,
|
||||
columns: ['work_order'],
|
||||
rows: [{ work_order: 'MO-20260629' }],
|
||||
}],
|
||||
});
|
||||
|
||||
let renderer!: ReactTestRenderer;
|
||||
await act(async () => {
|
||||
renderer = create(<QueryEditor tab={createTab({
|
||||
dbName: 'ldf_server_dbs_dev',
|
||||
query: 'SELECT * FROM ldf_server.mes_work_order;',
|
||||
resultPanelVisible: true,
|
||||
})} />);
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
await findButton(renderer!, '运行').props.onClick();
|
||||
});
|
||||
await act(async () => {
|
||||
await Promise.resolve();
|
||||
await Promise.resolve();
|
||||
});
|
||||
|
||||
const rendered = textContent(renderer!.toJSON());
|
||||
expect(rendered).toContain('日志');
|
||||
expect(rendered).toContain('结果 1');
|
||||
expect(dataGridState.latestProps?.columnNames).toEqual(['work_order']);
|
||||
expect(dataGridState.latestProps?.data?.[0]).toMatchObject({ work_order: 'MO-20260629' });
|
||||
});
|
||||
|
||||
it('prefers sqlserver print output messages over affected-row status results', async () => {
|
||||
storeState.connections[0].config.type = 'sqlserver';
|
||||
storeState.connections[0].config.database = 'hydee';
|
||||
|
||||
@@ -1232,6 +1232,22 @@ func (a *App) DBQueryMulti(config connection.ConnectionConfig, dbName string, qu
|
||||
statementResults []connection.ResultSetData
|
||||
usedMultiResult bool
|
||||
)
|
||||
runStatementQuery := func() error {
|
||||
if sessionQueryMessageTarget != nil {
|
||||
data, columns, messages, err = sessionQueryMessageTarget.QueryContextWithMessages(ctx, stmt)
|
||||
} else if sessionQueryTarget != nil {
|
||||
data, columns, err = sessionQueryTarget.QueryContext(ctx, stmt)
|
||||
} else if q, ok := dbInst.(db.QueryMessageExecer); ok {
|
||||
data, columns, messages, err = q.QueryContextWithMessages(ctx, stmt)
|
||||
} else if q, ok := dbInst.(interface {
|
||||
QueryContext(context.Context, string) ([]map[string]interface{}, []string, error)
|
||||
}); ok {
|
||||
data, columns, err = q.QueryContext(ctx, stmt)
|
||||
} else {
|
||||
data, columns, err = dbInst.Query(stmt)
|
||||
}
|
||||
return err
|
||||
}
|
||||
if sessionMultiQueryMessageTarget != nil {
|
||||
statementResults, messages, err = sessionMultiQueryMessageTarget.QueryMultiContextWithMessages(ctx, stmt)
|
||||
usedMultiResult = true
|
||||
@@ -1247,18 +1263,17 @@ func (a *App) DBQueryMulti(config connection.ConnectionConfig, dbName string, qu
|
||||
} else if q, ok := dbInst.(db.MultiResultQuerier); ok {
|
||||
statementResults, err = q.QueryMulti(stmt)
|
||||
usedMultiResult = true
|
||||
} else if sessionQueryMessageTarget != nil {
|
||||
data, columns, messages, err = sessionQueryMessageTarget.QueryContextWithMessages(ctx, stmt)
|
||||
} else if sessionQueryTarget != nil {
|
||||
data, columns, err = sessionQueryTarget.QueryContext(ctx, stmt)
|
||||
} else if q, ok := dbInst.(db.QueryMessageExecer); ok {
|
||||
data, columns, messages, err = q.QueryContextWithMessages(ctx, stmt)
|
||||
} else if q, ok := dbInst.(interface {
|
||||
QueryContext(context.Context, string) ([]map[string]interface{}, []string, error)
|
||||
}); ok {
|
||||
data, columns, err = q.QueryContext(ctx, stmt)
|
||||
} else {
|
||||
data, columns, err = dbInst.Query(stmt)
|
||||
err = runStatementQuery()
|
||||
}
|
||||
if err == nil && usedMultiResult && nativeReadOnlyResultsMissingTabularPayload(isReadStmt, statementResults) {
|
||||
logger.Warnf("DBQueryMulti 逐条多结果集返回空结果,将回退普通查询(第 %d/%d 条):%s SQL片段=%q", idx+1, len(statements), formatConnSummary(runConfig), sqlSnippet(stmt))
|
||||
usedMultiResult = false
|
||||
statementResults = nil
|
||||
data = nil
|
||||
columns = nil
|
||||
messages = nil
|
||||
err = runStatementQuery()
|
||||
}
|
||||
if err == nil {
|
||||
if usedMultiResult {
|
||||
|
||||
@@ -1756,6 +1756,67 @@ func TestDBQueryMultiFallsBackWhenNativeReadOnlyBatchReturnsBlankResultSet(t *te
|
||||
}
|
||||
}
|
||||
|
||||
func TestDBQueryMultiFallsBackToPlainQueryWhenSequentialMultiStillReturnsBlankResultSet(t *testing.T) {
|
||||
originalNewDatabaseFunc := newDatabaseFunc
|
||||
t.Cleanup(func() {
|
||||
newDatabaseFunc = originalNewDatabaseFunc
|
||||
})
|
||||
|
||||
query := "SELECT * FROM ldf_server.mes_work_order"
|
||||
blankNativeResult := []connection.ResultSetData{{
|
||||
Rows: []map[string]interface{}{},
|
||||
Columns: []string{},
|
||||
}}
|
||||
baseDB := &fakeBatchWriteDB{
|
||||
queryMap: map[string][]map[string]interface{}{
|
||||
query: {
|
||||
{"work_order": "MO-20260629"},
|
||||
},
|
||||
},
|
||||
fieldMap: map[string][]string{
|
||||
query: {"work_order"},
|
||||
},
|
||||
multiResult: map[string][]connection.ResultSetData{
|
||||
query: blankNativeResult,
|
||||
},
|
||||
queryErr: map[string]error{},
|
||||
}
|
||||
fakeDB := &fakeNativeMultiResultDB{fakeBatchWriteDB: baseDB}
|
||||
newDatabaseFunc = func(dbType string) (db.Database, error) {
|
||||
return fakeDB, nil
|
||||
}
|
||||
|
||||
app := NewAppWithSecretStore(secretstore.NewUnavailableStore("test"))
|
||||
config := connection.ConnectionConfig{Type: "kingbase", Host: "127.0.0.1", Port: 54321, User: "system"}
|
||||
|
||||
result := app.DBQueryMulti(config, "ldf_server_dbs_dev", query, "sequential-blank-native-read-fallback-test")
|
||||
if !result.Success {
|
||||
t.Fatalf("expected DBQueryMulti success, got failure: %s", result.Message)
|
||||
}
|
||||
if fakeDB.multiCalls != 1 {
|
||||
t.Fatalf("expected one top-level native multi-result attempt, got %d", fakeDB.multiCalls)
|
||||
}
|
||||
if baseDB.session == nil {
|
||||
t.Fatal("expected DBQueryMulti to open a pinned session for sequential fallback")
|
||||
}
|
||||
if baseDB.session.queryCalls != 2 {
|
||||
t.Fatalf("expected sequential multi-result attempt plus plain query fallback, got %d calls", baseDB.session.queryCalls)
|
||||
}
|
||||
resultSets, ok := result.Data.([]connection.ResultSetData)
|
||||
if !ok {
|
||||
t.Fatalf("expected []connection.ResultSetData, got %T", result.Data)
|
||||
}
|
||||
if len(resultSets) != 1 {
|
||||
t.Fatalf("expected one plain query fallback result set, got %#v", resultSets)
|
||||
}
|
||||
if !reflect.DeepEqual(resultSets[0].Columns, []string{"work_order"}) {
|
||||
t.Fatalf("expected fallback columns, got %#v", resultSets[0].Columns)
|
||||
}
|
||||
if got := resultSets[0].Rows[0]["work_order"]; got != "MO-20260629" {
|
||||
t.Fatalf("expected fallback SELECT result work_order=MO-20260629, got %#v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDBQueryMultiUsesPinnedSessionForSequentialFallback(t *testing.T) {
|
||||
originalNewDatabaseFunc := newDatabaseFunc
|
||||
t.Cleanup(func() {
|
||||
|
||||
Reference in New Issue
Block a user