From c036dd19e45f51ca549b3118381dbb62d8e10d74 Mon Sep 17 00:00:00 2001 From: t8y2 <1156263951@qq.com> Date: Fri, 8 May 2026 17:19:31 +0800 Subject: [PATCH] feat: support middle-click to close tabs (#162) --- crates/dbx-core/src/db/oracle_driver.rs | 35 ++++++++++++++++++++----- src/components/layout/AppTabBar.vue | 1 + 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/crates/dbx-core/src/db/oracle_driver.rs b/crates/dbx-core/src/db/oracle_driver.rs index f4e64020f..0ec7ce12e 100644 --- a/crates/dbx-core/src/db/oracle_driver.rs +++ b/crates/dbx-core/src/db/oracle_driver.rs @@ -274,6 +274,7 @@ pub async fn execute_query(conn: &OracleClient, sql: &str) -> Result Result std::borrow::Cow<'_, str> { let upper = sql.to_uppercase(); - if let Some(pos) = upper.find("FETCH FIRST") { - if let Some(end) = upper[pos..].find("ROWS ONLY") { - let between = sql[pos + 11..pos + end].trim(); - if let Ok(n) = between.parse::() { - let base = sql[..pos].trim_end(); - return std::borrow::Cow::Owned(format!("SELECT * FROM ({base}) WHERE ROWNUM <= {n}")); + // Match: ... [OFFSET M ROWS] FETCH FIRST|NEXT N ROWS ONLY + let fetch_pos = upper.find("FETCH FIRST").or_else(|| upper.find("FETCH NEXT")); + let Some(fpos) = fetch_pos else { return std::borrow::Cow::Borrowed(sql) }; + let after_fetch = &upper[fpos..]; + let Some(end) = after_fetch.find("ROWS ONLY") else { return std::borrow::Cow::Borrowed(sql) }; + let keyword_len = if after_fetch.starts_with("FETCH FIRST") { 11 } else { 10 }; + let between = sql[fpos + keyword_len..fpos + end].trim(); + let Ok(n) = between.parse::() else { return std::borrow::Cow::Borrowed(sql) }; + + // Check for OFFSET M ROWS before FETCH + let mut base = &sql[..fpos]; + let base_upper = base.to_uppercase(); + if let Some(opos) = base_upper.rfind("OFFSET ") { + let after_offset = base_upper[opos + 7..].trim(); + if let Some(rpos) = after_offset.find(" ROWS") { + let offset_str = after_offset[..rpos].trim(); + if let Ok(offset) = offset_str.parse::() { + let inner = sql[..opos].trim_end(); + return std::borrow::Cow::Owned(format!( + "SELECT * FROM (SELECT a.*, ROWNUM rn__ FROM ({inner}) a WHERE ROWNUM <= {}) WHERE rn__ > {offset}", + offset + n + )); } } + base = sql[..opos].trim_end(); + } else { + base = base.trim_end(); } - std::borrow::Cow::Borrowed(sql) + + std::borrow::Cow::Owned(format!("SELECT * FROM ({base}) WHERE ROWNUM <= {n}")) } diff --git a/src/components/layout/AppTabBar.vue b/src/components/layout/AppTabBar.vue index 64f64bcd4..36ea4f85a 100644 --- a/src/components/layout/AppTabBar.vue +++ b/src/components/layout/AppTabBar.vue @@ -75,6 +75,7 @@ watch( " :data-active-tab="tab.id === queryStore.activeTabId" @click="queryStore.activeTabId = tab.id" + @mousedown.middle.prevent="queryStore.closeTab(tab.id)" >