Commit fd098416 authored by Data Governance Dev's avatar Data Governance Dev

feat(backend): Oracle 端到端打通(thick + health + 11g 兼容 + schema 名修正)

Oracle 11g (11.2.0.4) 数据库连接抽数据字典端到端跑通,解决 4 个独立问题:

1. connect_timeout → tcp_connect_timeout
   oracledb 1.4.2+ 移除了 connect_timeout kwarg(之前误以为兼容),
   改成 tcp_connect_timeout;报错日志加 inspect 自动定位兼容 kwarg。

2. thick 模式加载 + DPI-1047 深度诊断
   - _ensure_oracle_client() 解析 oci.dll 的 PE 导入表,自动列出
     实际依赖的运行时 DLL(如 MSVCR120.dll → VC++ 2013 Redist)
   - DPY-3010(thin 不支持老 Oracle)日志加针对性安装指引
   - 11.2.0.4 必须 thick 模式(thin 不支持 11.2)

3. 健康检查 SQL 分方言
   新建 check_connection.oracle.sql 写 SELECT 1 FROM dual;
   Oracle 严格执行 SQL 标准,不像 MySQL/达梦 兼容裸 SELECT 1。
   sql_loader 按 <name>.<dialect>.sql 优先 + .sql 回退 自动分流。

4. ALL_TABLES 11g 列兼容性
   修 list_tables.oracle.sql:
   - data_length 用 t.BLOCKS * 8192 估算(11g 没 BYTES 列,12c+ 才有)
   - create_time / update_time 取 NULL(11g 没 CREATED/LAST_DDL_TIME,12c+ 才有)
   - 注释贴了 11.2.0.4 ALL_TABLES 完整可用列清单(用户 DESC 确认)

5. schema 名传递修正
   data_dict.py 之前对所有数据库都传 cfg.database 给 list_tables/list_columns,
   但 Oracle 体系里 ALL_TABLES.OWNER 是用户名(=cfg.user),不是 service_name。
   加 cfg.db_type == 'oracle' 分支:schema_name = cfg.user

6. /api/db-defaults 加 oracle_client_dir
   路径从 web/configs/db_defaults.yaml 预填,前端可隐藏输入框。

验证日志:
  [DB] Oracle Instant Client 已加载(thick 模式)lib_dir=...
  [DB] 连接已建立(耗时 ~100ms)
  [DB] 测试连接成功
  [Cache] 写入数据字典: (表 N 张, 字段 M 个)

踩坑详见 docs/WORKLOG.md(2026-08-13 Oracle 端到端打通条目)。
parent e7fb2a8c
...@@ -64,9 +64,10 @@ async def db_defaults(): ...@@ -64,9 +64,10 @@ async def db_defaults():
return {} return {}
defaults = raw.get("db_defaults", {}) defaults = raw.get("db_defaults", {})
# 仅返回前端表单关心的字段,避免泄露无关配置 # 仅返回前端表单关心的字段,避免泄露无关配置
# 2026-08-13:oracle_client_dir 加入预填(仅 Oracle 有效,留空走 thin 模式)
return { return {
k: defaults[k] k: defaults[k]
for k in ("host", "user", "password", "database") for k in ("host", "user", "password", "database", "oracle_client_dir")
if k in defaults if k in defaults
} }
......
...@@ -37,12 +37,16 @@ def extract_data_dictionary(cfg: DBConfig, log: Optional[Callable] = None) -> di ...@@ -37,12 +37,16 @@ def extract_data_dictionary(cfg: DBConfig, log: Optional[Callable] = None) -> di
with open_db(cfg) as db: with open_db(cfg) as db:
if log: if log:
log("INFO", "已建立连接,开始读取 information_schema.COLUMNS ...") log("INFO", "已建立连接,开始读取 information_schema.COLUMNS ...")
columns = db.list_columns(cfg.database) # 2026-08-13:Oracle 体系里 ALL_TAB_COLUMNS.OWNER / ALL_TABLES.OWNER 是「用户名」,
# 不是 service_name(service_name 在 cfg.database,用于连接);MySQL/达梦 的
# database 既是连接用也是 schema 名,所以单独分支。
schema_name = cfg.user if cfg.db_type == "oracle" else cfg.database
columns = db.list_columns(schema_name)
if log: if log:
log("INFO", f" · COLUMNS: {len(columns)} 行") log("INFO", f" · COLUMNS: {len(columns)} 行")
if log: if log:
log("INFO", "读取 information_schema.TABLES ...") log("INFO", "读取 information_schema.TABLES ...")
tables = db.list_tables(cfg.database) tables = db.list_tables(schema_name)
if log: if log:
log("INFO", f" · TABLES: {len(tables)} 行") log("INFO", f" · TABLES: {len(tables)} 行")
......
This diff is collapsed.
-- ============================================================================
-- 健康检查:确认连接可用,返回固定值 1
-- 调用方:web/core/db_adapter.py → test_connection()
-- 方言:Oracle
--
-- Oracle 严格遵循 SQL 标准 —— SELECT 必须有 FROM 子句,
-- 因此不能像 MySQL 那样写 SELECT 1,必须 FROM dual。
-- dual 是 Oracle 内置的单行单列表,恒定返回 1 行。
-- ============================================================================
SELECT 1 FROM dual
\ No newline at end of file
...@@ -6,16 +6,27 @@ ...@@ -6,16 +6,27 @@
-- - Oracle 没有 INFORMATION_SCHEMA,使用 ALL_TABLES(结构与达梦高度一致) -- - Oracle 没有 INFORMATION_SCHEMA,使用 ALL_TABLES(结构与达梦高度一致)
-- - Oracle ALL_TABLES 没有 COMMENTS 列,表注释在 ALL_TAB_COMMENTS 里, -- - Oracle ALL_TABLES 没有 COMMENTS 列,表注释在 ALL_TAB_COMMENTS 里,
-- LEFT JOIN 出来(与达梦同源——同一类问题同一个修法) -- LEFT JOIN 出来(与达梦同源——同一类问题同一个修法)
-- - 2026-08-13:实测 11g (11.2.0.4) ALL_TABLES 实际可用列清单(用户跑 DESC ALL_TABLES 确认):
-- OWNER / TABLE_NAME / TABLESPACE_NAME / CLUSTER_NAME / IOT_NAME / STATUS /
-- PCT_FREE / PCT_USED / INI_TRANS / MAX_TRANS /
-- INITIAL_EXTENT / NEXT_EXTENT / MIN_EXTENTS / MAX_EXTENTS / PCT_INCREASE /
-- FREELISTS / FREELIST_GROUPS / LOGGING / BACKED_UP /
-- NUM_ROWS / BLOCKS / EMPTY_BLOCKS / AVG_SPACE / CHAIN_CNT / AVG_ROW_LEN /
-- AVG_SPACE_FREELIST_BLOCKS / NUM_FREELIST_BLOCKS
-- - 11g ALL_TABLES **没有** BYTES / CREATED / LAST_DDL_TIME 列(这三个都是 12c+ 加的),
-- 所以 data_length 用 BLOCKS * 8192 估算(Oracle 默认 block size 8KB;空表为 0,未分配 segment),
-- create_time / update_time 取 NULL。若以后接 12c+,新增 list_tables.oracle.12c.sql
-- 即可(sql_loader 自动优先选方言版本,不影响 11g)。
-- ============================================================================ -- ============================================================================
SELECT t.TABLE_NAME AS table_name, SELECT t.TABLE_NAME AS table_name,
'BASE TABLE' AS table_type, 'BASE TABLE' AS table_type,
NULL AS engine, NULL AS engine,
t.NUM_ROWS AS table_rows, t.NUM_ROWS AS table_rows,
t.BYTES AS data_length, t.BLOCKS * 8192 AS data_length, -- 11g 没 BYTES,用 BLOCKS×8K 估算
0 AS index_length, 0 AS index_length,
tc.COMMENTS AS table_comment, tc.COMMENTS AS table_comment,
t.CREATED AS create_time, NULL AS create_time, -- 11g ALL_TABLES 没有 CREATED(12c+)
t.LAST_DDL_TIME AS update_time NULL AS update_time -- 11g ALL_TABLES 没有 LAST_DDL_TIME(12c+)
FROM ALL_TABLES t FROM ALL_TABLES t
LEFT JOIN ALL_TAB_COMMENTS tc LEFT JOIN ALL_TAB_COMMENTS tc
ON tc.OWNER = t.OWNER ON tc.OWNER = t.OWNER
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment