mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-07-01 18:01:25 +08:00
@@ -5429,6 +5429,41 @@ describe('QueryEditor external SQL save', () => {
|
||||
expect(textContent(renderer!.root)).not.toContain('未提交');
|
||||
});
|
||||
|
||||
it('keeps TDengine insert on the regular query path because it has no managed transaction support', async () => {
|
||||
storeState.connections[0].config.type = 'tdengine';
|
||||
backendApp.DBQueryMulti.mockResolvedValueOnce({
|
||||
success: true,
|
||||
data: [
|
||||
{ columns: ['affectedRows'], rows: [{ affectedRows: 1 }], statementIndex: 1 },
|
||||
],
|
||||
});
|
||||
|
||||
let renderer!: ReactTestRenderer;
|
||||
await act(async () => {
|
||||
renderer = create(<QueryEditor tab={createTab({
|
||||
query: 'INSERT INTO meters(ts, current) VALUES (NOW, 10.2)',
|
||||
})} />);
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
await findButton(renderer!, '运行').props.onClick();
|
||||
});
|
||||
await act(async () => {
|
||||
await Promise.resolve();
|
||||
await Promise.resolve();
|
||||
});
|
||||
|
||||
expect(backendApp.DBQueryMulti).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
'main',
|
||||
expect.stringContaining('INSERT INTO meters'),
|
||||
'query-1',
|
||||
);
|
||||
expect(backendApp.DBQueryMultiTransactional).not.toHaveBeenCalled();
|
||||
expect(messageApi.error).not.toHaveBeenCalledWith(expect.stringContaining('SQL 编辑器托管事务'));
|
||||
expect(textContent(renderer!.root)).toContain('影响行数:1');
|
||||
});
|
||||
|
||||
it('reuses the pending managed transaction for follow-up read-only SQL in the same tab', async () => {
|
||||
backendApp.DBQueryMultiTransactional.mockResolvedValueOnce({
|
||||
success: true,
|
||||
|
||||
@@ -47,9 +47,15 @@ describe('sqlEditorTransaction', () => {
|
||||
])).toBe(false);
|
||||
});
|
||||
|
||||
it('keeps Trino DML on the plain multi-statement execution path', () => {
|
||||
expect(shouldUseSqlEditorManagedTransactionForType('trino', [
|
||||
'UPDATE hive.default.orders SET status = \'done\'',
|
||||
it.each([
|
||||
['trino', 'UPDATE hive.default.orders SET status = \'done\''],
|
||||
['tdengine', 'INSERT INTO meters(ts, current) VALUES (NOW, 10.2)'],
|
||||
['clickhouse', 'INSERT INTO events FORMAT JSONEachRow {"id":1}'],
|
||||
['iotdb', 'INSERT INTO root.ln.wf01.wt01(timestamp,status) VALUES(1,true)'],
|
||||
])('keeps %s writes on the plain multi-statement execution path', (dbType, sql) => {
|
||||
expect(shouldUseSqlEditorManagedTransactionForType(dbType, [sql])).toBe(false);
|
||||
expect(canReusePendingSqlEditorTransactionForType(dbType, [
|
||||
'SELECT * FROM users WHERE id = 1',
|
||||
])).toBe(false);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,6 +1,16 @@
|
||||
const SQL_EDITOR_DML_KEYWORDS = new Set(['insert', 'update', 'delete', 'replace', 'merge', 'upsert']);
|
||||
const SQL_EDITOR_READ_KEYWORDS = new Set(['select', 'with', 'show', 'describe', 'desc', 'explain', 'pragma', 'values']);
|
||||
const SQL_EDITOR_TRANSACTION_CONTROL_KEYWORDS = new Set(['begin', 'commit', 'rollback', 'savepoint', 'release']);
|
||||
const SQL_EDITOR_MANAGED_TRANSACTION_UNSUPPORTED_TYPES = new Set([
|
||||
'trino',
|
||||
'tdengine',
|
||||
'clickhouse',
|
||||
'iotdb',
|
||||
'rocketmq',
|
||||
'mqtt',
|
||||
'kafka',
|
||||
'rabbitmq',
|
||||
]);
|
||||
|
||||
type SqlEditorWithAnalysis = {
|
||||
keyword: string;
|
||||
@@ -253,7 +263,7 @@ export const shouldUseSqlEditorManagedTransactionForType = (
|
||||
type: string,
|
||||
statements: string[],
|
||||
): boolean => {
|
||||
if (String(type || '').trim().toLowerCase() === 'trino') {
|
||||
if (SQL_EDITOR_MANAGED_TRANSACTION_UNSUPPORTED_TYPES.has(String(type || '').trim().toLowerCase())) {
|
||||
return false;
|
||||
}
|
||||
let hasManagedWrite = false;
|
||||
@@ -279,7 +289,7 @@ export const canReusePendingSqlEditorTransactionForType = (
|
||||
type: string,
|
||||
statements: string[],
|
||||
): boolean => {
|
||||
if (String(type || '').trim().toLowerCase() === 'trino') {
|
||||
if (SQL_EDITOR_MANAGED_TRANSACTION_UNSUPPORTED_TYPES.has(String(type || '').trim().toLowerCase())) {
|
||||
return false;
|
||||
}
|
||||
let hasReadStatement = false;
|
||||
|
||||
@@ -369,7 +369,7 @@ func executeManagedSQLTransactionStatements(ctx context.Context, session db.Stat
|
||||
}
|
||||
|
||||
func shouldUseManagedSQLTransaction(dbType string, query string) bool {
|
||||
if strings.EqualFold(strings.TrimSpace(dbType), "trino") {
|
||||
if isManagedSQLTransactionUnsupportedType(dbType) {
|
||||
return false
|
||||
}
|
||||
statements := splitSQLStatements(query)
|
||||
@@ -394,6 +394,15 @@ func shouldUseManagedSQLTransaction(dbType string, query string) bool {
|
||||
return hasManagedWrite
|
||||
}
|
||||
|
||||
func isManagedSQLTransactionUnsupportedType(dbType string) bool {
|
||||
switch strings.ToLower(strings.TrimSpace(dbType)) {
|
||||
case "trino", "tdengine", "clickhouse", "iotdb", "rocketmq", "mqtt", "kafka", "rabbitmq":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func sqlEditorImplicitTransactionSQL(dbType string) (commitSQL string, rollbackSQL string, ok bool) {
|
||||
switch strings.ToLower(strings.TrimSpace(dbType)) {
|
||||
case "oracle":
|
||||
|
||||
@@ -2,13 +2,28 @@ package app
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestShouldUseManagedSQLTransaction_TrinoAlwaysUsesPlainExecution(t *testing.T) {
|
||||
func TestShouldUseManagedSQLTransaction_UnsupportedTypesUsePlainExecution(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
if shouldUseManagedSQLTransaction("trino", "UPDATE hive.default.orders SET status = 'done'") {
|
||||
t.Fatal("expected trino DML to skip SQL editor managed transactions")
|
||||
cases := []struct {
|
||||
dbType string
|
||||
query string
|
||||
}{
|
||||
{dbType: "trino", query: "UPDATE hive.default.orders SET status = 'done'"},
|
||||
{dbType: "tdengine", query: "INSERT INTO meters(ts, current) VALUES (NOW, 10.2)"},
|
||||
{dbType: "clickhouse", query: `INSERT INTO events FORMAT JSONEachRow {"id":1}`},
|
||||
{dbType: "iotdb", query: "INSERT INTO root.ln.wf01.wt01(timestamp,status) VALUES(1,true)"},
|
||||
}
|
||||
if shouldUseManagedSQLTransaction("trino", "BEGIN; UPDATE hive.default.orders SET status = 'done'; COMMIT;") {
|
||||
t.Fatal("expected trino explicit transactions to stay unmanaged")
|
||||
for _, tc := range cases {
|
||||
tc := tc
|
||||
t.Run(tc.dbType, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
if shouldUseManagedSQLTransaction(tc.dbType, tc.query) {
|
||||
t.Fatalf("expected %s DML to skip SQL editor managed transactions", tc.dbType)
|
||||
}
|
||||
if shouldUseManagedSQLTransaction(tc.dbType, "BEGIN; "+tc.query+"; COMMIT;") {
|
||||
t.Fatalf("expected %s explicit transactions to stay unmanaged", tc.dbType)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user