fix(oracle): Oracle 11g compatibility and sidebar improvements

- Rewrite FETCH FIRST to ROWNUM for Oracle 11g (no 12c+ syntax)
- Filter APEX_*, FLOWS_*, $-prefixed system schemas from sidebar
- Set schema prefix on table nodes for schema-aware databases
- Use all_objects instead of all_tables+all_views (4x faster)
- Disable statement cache to avoid stale cursor issues
- Update rust-oracle with streaming TTC, drain fixes
This commit is contained in:
t8y2 2026-05-08 18:53:50 +08:00
parent 8a249a2194
commit 85be58822e
3 changed files with 26 additions and 26 deletions

26
Cargo.lock generated
View File

@ -1857,7 +1857,7 @@ dependencies = [
"libc",
"option-ext",
"redox_users",
"windows-sys 0.61.2",
"windows-sys 0.59.0",
]
[[package]]
@ -2191,7 +2191,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [
"libc",
"windows-sys 0.61.2",
"windows-sys 0.59.0",
]
[[package]]
@ -3189,7 +3189,7 @@ dependencies = [
"js-sys",
"log",
"wasm-bindgen",
"windows-core 0.62.2",
"windows-core 0.61.2",
]
[[package]]
@ -4147,7 +4147,7 @@ dependencies = [
"png 0.18.1",
"serde",
"thiserror 2.0.18",
"windows-sys 0.61.2",
"windows-sys 0.60.2",
]
[[package]]
@ -4238,7 +4238,7 @@ version = "0.50.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
dependencies = [
"windows-sys 0.61.2",
"windows-sys 0.59.0",
]
[[package]]
@ -4869,7 +4869,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d8fae84b431384b68627d0f9b3b1245fcf9f46f6c0e3dc902e9dce64edd1967"
dependencies = [
"libc",
"windows-sys 0.61.2",
"windows-sys 0.45.0",
]
[[package]]
@ -6178,7 +6178,7 @@ dependencies = [
[[package]]
name = "rust-oracle"
version = "0.1.6"
source = "git+https://github.com/t8y2/rust-oracle?branch=main#75d32d09a021e3544cd013a8e2cbf21a929df507"
source = "git+https://github.com/t8y2/rust-oracle?branch=main#6d16519f51791e04511b02ee7b3cbf5fc5524b4e"
dependencies = [
"aes 0.8.4",
"async-trait",
@ -6293,7 +6293,7 @@ dependencies = [
"errno",
"libc",
"linux-raw-sys 0.12.1",
"windows-sys 0.61.2",
"windows-sys 0.59.0",
]
[[package]]
@ -6394,7 +6394,7 @@ dependencies = [
"security-framework 3.7.0",
"security-framework-sys",
"webpki-root-certs",
"windows-sys 0.61.2",
"windows-sys 0.59.0",
]
[[package]]
@ -7046,7 +7046,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e"
dependencies = [
"libc",
"windows-sys 0.61.2",
"windows-sys 0.60.2",
]
[[package]]
@ -7986,7 +7986,7 @@ dependencies = [
"getrandom 0.4.2",
"once_cell",
"rustix 1.1.4",
"windows-sys 0.61.2",
"windows-sys 0.59.0",
]
[[package]]
@ -8485,7 +8485,7 @@ dependencies = [
"png 0.18.1",
"serde",
"thiserror 2.0.18",
"windows-sys 0.61.2",
"windows-sys 0.60.2",
]
[[package]]
@ -9097,7 +9097,7 @@ version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
dependencies = [
"windows-sys 0.61.2",
"windows-sys 0.48.0",
]
[[package]]

View File

@ -15,8 +15,7 @@ pub async fn connect(
pass: &str,
sysdba: bool,
) -> Result<OracleClient, String> {
let mut config = Config::new(host, port, service, user, pass);
config.sysdba = sysdba;
let config = Config::new(host, port, service, user, pass).with_statement_cache_size(0).sysdba_flag(sysdba);
let conn = tokio::time::timeout(connection_timeout(), Connection::connect_with_config(config))
.await
.map_err(|_| format!("Oracle connection timed out ({CONNECTION_TIMEOUT_SECS}s)"))?
@ -40,9 +39,6 @@ fn value_to_json(val: &rust_oracle::Value) -> serde_json::Value {
}
pub async fn list_databases(conn: &OracleClient) -> Result<Vec<DatabaseInfo>, String> {
// Use a single query that works on ALL Oracle versions (11g through 23ai).
// Oracle 12c+ has oracle_maintained column; 11g does not.
// COALESCE with a subquery detects whether the column exists at runtime.
let result = conn
.query(
"SELECT username FROM all_users \
@ -54,7 +50,11 @@ pub async fn list_databases(conn: &OracleClient) -> Result<Vec<DatabaseInfo>, St
'ORACLE_OCM','SI_INFORMTN_SCHEMA','WMSYS','XS$NULL','DBSFWUSER',\
'REMOTE_SCHEDULER_AGENT','PDBADMIN','DGPDB_INT','OPS$ORACLE',\
'GGSYS','FLOWS_FILES','APEX_PUBLIC_USER'\
) ORDER BY username",
) \
AND username NOT LIKE 'APEX_%' \
AND username NOT LIKE 'FLOWS_%' \
AND username NOT LIKE '%$%' \
ORDER BY username",
&[],
)
.await
@ -73,10 +73,10 @@ pub async fn list_schemas(conn: &OracleClient) -> Result<Vec<String>, String> {
pub async fn list_tables(conn: &OracleClient, schema: &str) -> Result<Vec<TableInfo>, String> {
let sql = format!(
"SELECT table_name, 'TABLE' AS table_type FROM all_tables WHERE owner = '{s}' \
UNION ALL \
SELECT view_name, 'VIEW' FROM all_views WHERE owner = '{s}' \
ORDER BY 1",
"SELECT object_name, \
CASE object_type WHEN 'VIEW' THEN 'VIEW' ELSE 'TABLE' END AS table_type \
FROM all_objects WHERE owner = '{s}' AND object_type IN ('TABLE','VIEW') \
ORDER BY object_name",
s = schema.replace('\'', "''")
);
log::debug!("[oracle] list_tables: schema={schema}, sql={sql}");
@ -266,7 +266,6 @@ pub async fn execute_query(conn: &OracleClient, sql: &str) -> Result<QueryResult
let sql = sql.as_ref();
let trimmed = sql.to_uppercase();
log::debug!("[oracle] execute_query: sql={}", &sql[..sql.len().min(200)]);
if trimmed.starts_with("SELECT")
|| trimmed.starts_with("WITH")
@ -274,7 +273,6 @@ pub async fn execute_query(conn: &OracleClient, sql: &str) -> Result<QueryResult
|| trimmed.starts_with("DESCRIBE")
|| trimmed.starts_with("EXPLAIN")
{
log::info!("[oracle] execute_query: final sql={}", &sql[..sql.len().min(200)]);
let result = conn.query(sql, &[]).await.map_err(|e| {
log::error!("[oracle] execute_query SELECT failed: {e}");
e.to_string()

View File

@ -493,6 +493,8 @@ export const useConnectionStore = defineStore("connection", () => {
try {
const querySchema = schema || database;
const tables = await api.listTables(connectionId, database, querySchema);
const config = getConfig(connectionId);
const effectiveSchema = schema || (config?.db_type && isSchemaAware(config.db_type) ? database : undefined);
setChildren(
node,
tables.map((t) => ({
@ -501,7 +503,7 @@ export const useConnectionStore = defineStore("connection", () => {
type: (t.table_type === "VIEW" ? "view" : "table") as "view" | "table",
connectionId,
database,
schema,
schema: effectiveSchema,
isExpanded: false,
children: [],
})),