Skip to content

Commit 568ebd1

Browse files
committed
feat:尝试支持人大进仓
1 parent f78cd23 commit 568ebd1

File tree

11 files changed

+471
-18
lines changed

11 files changed

+471
-18
lines changed

database_schema/factory.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
PostgreSQLInspector,
66
OracleInspector,
77
GaussDBInspector,
8+
KingbaseESInspector,
89
DMInspector
910
)
1011

@@ -19,6 +20,7 @@ def create_inspector(db_type: str, **kwargs) -> object:
1920
'postgresql': PostgreSQLInspector,
2021
'oracle': OracleInspector,
2122
'gaussdb': GaussDBInspector,
23+
'kingbase': KingbaseESInspector,
2224
'dm': DMInspector
2325
}
2426

database_schema/inspectors/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from .postgresql import PostgreSQLInspector
55
from .oracle import OracleInspector
66
from .gaussdb import GaussDBInspector
7+
from .kingbase import KingbaseESInspector
78
from .dm import DMInspector
89

910
__all__ = [
@@ -12,5 +13,6 @@
1213
'PostgreSQLInspector',
1314
'OracleInspector',
1415
'GaussDBInspector',
16+
'KingbaseESInspector',
1517
'DMInspector'
1618
]

database_schema/inspectors/dm.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,22 @@
44
from .base import BaseInspector
55
from urllib.parse import quote_plus
66

7+
# 导入达梦数据库自定义方言以注册到 SQLAlchemy
8+
try:
9+
from utils.dm_dialect import DMDialect
10+
except ImportError:
11+
pass # 如果导入失败,使用标准方言
12+
713
class DMInspector(BaseInspector):
814
"""达梦数据库(DM Database)元数据获取实现
915
1016
达梦数据库特点:
1117
1. 国产数据库,部分兼容 Oracle 语法
12-
2. 使用 dmPython 驱动
18+
2. 使用 dmPython 驱动(专用驱动)
1319
3. 默认端口:5236
1420
4. 支持 Schema 概念,类似 Oracle
1521
5. 表名和列名默认大写
22+
6. 需要使用 dm+dmPython 方言连接
1623
"""
1724

1825
def __init__(self, host: str, port: int, database: str,
@@ -26,15 +33,15 @@ def build_conn_str(self, host: str, port: int, database: str,
2633
username: str, password: str) -> str:
2734
"""构建达梦数据库连接字符串
2835
29-
dmPython 不支持 SQLAlchemy 方言,改用 Oracle 兼容模式
30-
达梦数据库在协议层面兼容 Oracle,可以使用 oracledb 驱动
36+
达梦数据库使用专用的 dmPython 驱动和 dm 方言
37+
连接字符串格式: dm+dmPython://user:password@host:port/schema
3138
"""
3239
encoded_username = quote_plus(username)
3340
encoded_password = quote_plus(password)
3441

35-
# 使用 Oracle 驱动连接达梦数据库(达梦兼容 Oracle 协议)
36-
# 格式:oracle+oracledb://user:pass@host:port/?service_name=SYSDBA
37-
return f"oracle+oracledb://{encoded_username}:{encoded_password}@{host}:{port}/?service_name=SYSDBA"
42+
# 使用达梦专用方言和 dmPython 驱动
43+
# database 参数在达梦中表示 schema
44+
return f"dm+dmPython://{encoded_username}:{encoded_password}@{host}:{port}/{database}"
3845

3946
def get_table_names(self, inspector: reflection.Inspector) -> list[str]:
4047
"""获取指定 schema 下的所有表名"""
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
# database_schema/inspectors/kingbase.py
2+
from sqlalchemy.sql import text
3+
from sqlalchemy.engine import reflection
4+
from .base import BaseInspector
5+
from urllib.parse import quote_plus
6+
7+
# 导入 KingbaseES 自定义方言以注册到 SQLAlchemy
8+
try:
9+
from utils.kingbase_dialect import KingbaseESDialect
10+
except ImportError:
11+
pass # 如果导入失败,使用标准 PostgreSQL 方言
12+
13+
class KingbaseESInspector(BaseInspector):
14+
"""人大金仓数据库(KingbaseES) 元数据获取实现
15+
16+
KingbaseES 兼容 PostgreSQL 协议,是国产数据库的代表之一
17+
主要特点:
18+
1. 完全兼容 PostgreSQL 9.6+ 的语法和协议
19+
2. 使用 SCRAM-SHA-256 或 MD5 认证
20+
3. 默认端口为 54321 (不同于 PostgreSQL 的 5432)
21+
4. 系统表结构与 PostgreSQL 相同
22+
5. 支持 schema 概念,默认 schema 为 public
23+
"""
24+
25+
def __init__(self, host: str, port: int, database: str,
26+
username: str, password: str, schema_name: str = None, **kwargs):
27+
super().__init__(host, port, database, username, password, schema_name)
28+
self.schema_name = schema_name or "public"
29+
30+
def build_conn_str(self, host: str, port: int, database: str,
31+
username: str, password: str) -> str:
32+
"""构建人大金仓数据库连接字符串
33+
34+
关键参数说明:
35+
- 使用自定义的 kingbase 方言处理版本解析问题
36+
- 默认端口: 54321
37+
- 驱动: psycopg2 (兼容 PostgreSQL)
38+
"""
39+
encoded_password = quote_plus(password)
40+
encoded_username = quote_plus(username)
41+
42+
# 构建基础连接字符串,使用自定义的 kingbase 方言
43+
base_uri = f"kingbase+psycopg2://{encoded_username}:{encoded_password}@{host}:{port}/{database}"
44+
45+
return base_uri
46+
47+
def get_table_names(self, inspector: reflection.Inspector) -> list[str]:
48+
"""获取指定 schema 下的所有表名"""
49+
return inspector.get_table_names(schema=self.schema_name)
50+
51+
def get_table_comment(self, inspector: reflection.Inspector,
52+
table_name: str) -> str:
53+
"""获取表注释
54+
55+
KingbaseES 使用与 PostgreSQL 相同的系统目录结构
56+
"""
57+
with self.engine.connect() as conn:
58+
sql = text("""
59+
SELECT obj_description(c.oid, 'pg_class')
60+
FROM pg_catalog.pg_class c
61+
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
62+
WHERE n.nspname = :schema AND c.relname = :table
63+
""")
64+
result = conn.execute(sql, {
65+
"schema": self.schema_name,
66+
"table": table_name
67+
}).scalar()
68+
return result or ""
69+
70+
def get_column_comment(self, inspector: reflection.Inspector,
71+
table_name: str, column_name: str) -> str:
72+
"""获取列注释"""
73+
with self.engine.connect() as conn:
74+
sql = text("""
75+
SELECT pg_catalog.col_description(c.oid, a.attnum)
76+
FROM pg_catalog.pg_class c
77+
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
78+
JOIN pg_catalog.pg_attribute a ON a.attrelid = c.oid
79+
WHERE n.nspname = :schema
80+
AND c.relname = :table
81+
AND a.attname = :column
82+
AND a.attnum > 0
83+
AND NOT a.attisdropped
84+
""")
85+
result = conn.execute(sql, {
86+
"schema": self.schema_name,
87+
"table": table_name,
88+
"column": column_name
89+
}).scalar()
90+
return result or ""
91+
92+
def normalize_type(self, raw_type: str) -> str:
93+
"""标准化字段类型
94+
95+
KingbaseES 支持 PostgreSQL 类型 + 部分 Oracle 兼容类型
96+
"""
97+
type_map = {
98+
# PostgreSQL 标准类型
99+
'jsonb': 'JSON',
100+
'bytea': 'BLOB',
101+
'serial': 'INTEGER',
102+
'bigserial': 'BIGINT',
103+
'uuid': 'UUID',
104+
'int4': 'INTEGER',
105+
'int8': 'BIGINT',
106+
'int2': 'SMALLINT',
107+
'float4': 'FLOAT',
108+
'float8': 'DOUBLE',
109+
'bool': 'BOOLEAN',
110+
'timestamptz': 'TIMESTAMP WITH TIME ZONE',
111+
'timestamp': 'TIMESTAMP',
112+
113+
# KingbaseES 扩展类型 (Oracle 兼容)
114+
'clob': 'TEXT',
115+
'blob': 'BLOB',
116+
'number': 'NUMERIC',
117+
'raw': 'BYTEA',
118+
'nvarchar2': 'NVARCHAR',
119+
'varchar2': 'VARCHAR',
120+
'long': 'TEXT',
121+
'binary_double': 'DOUBLE',
122+
'binary_float': 'FLOAT'
123+
}
124+
125+
# 提取基础类型(去除长度限制)
126+
base_type = raw_type.split('(')[0].lower().strip()
127+
return type_map.get(base_type, raw_type.upper())

requirements.txt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@ sqlalchemy>=2.0.0
55
# 数据库驱动
66
pyodbc>=4.0.39 # SQL Server新驱动
77
pymysql>=1.1.1 # MySQL驱动
8-
psycopg2-binary>=2.9.10 # PostgreSQL驱动 (也用于GaussDB,2.9+ 支持 SCRAM-SHA-256)
8+
psycopg2-binary>=2.9.10 # PostgreSQL驱动 (也用于GaussDB和KingbaseES,2.9+ 支持 SCRAM-SHA-256)
99
psycopg[binary]>=3.2.0 # 为 GaussDB 使用 psycopg3 驱动
10-
oracledb>=2.0.0 # Oracle驱动 (也用于达梦数据库,达梦兼容 Oracle 协议)
11-
# dmPython>=2.3.0 # 达梦原生驱动(不支持 SQLAlchemy,已改用 oracledb)
10+
oracledb>=2.0.0 # Oracle驱动
11+
# dmPython>=2.3.0 # 达梦数据库专用驱动(需要从达梦官方下载安装,源码编译)
12+
# 安装方法: 从达梦数据库安装目录的 drivers/python 目录获取源码,执行 python setup.py install
1213

1314
# 安全相关
1415
cryptography>=41.0.0,<43.0.0 # 使用范围版本以提高平台兼容性

rookie_text2data.difypkg

4.43 KB
Binary file not shown.

tools/rookie_excute_sql.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ parameters:
4242
en_US: GaussDB
4343
zh_Hans: 华为高斯数据库
4444
value: gaussdb
45+
- label:
46+
en_US: KingbaseES
47+
zh_Hans: 人大金仓数据库
48+
value: kingbase
4549
- label:
4650
en_US: DM Database
4751
zh_Hans: 达梦数据库

tools/rookie_text2data.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ parameters:
4646
en_US: GaussDB
4747
zh_Hans: 华为高斯数据库
4848
value: gaussdb
49+
- label:
50+
en_US: KingbaseES
51+
zh_Hans: 人大金仓数据库
52+
value: kingbase
4953
- label:
5054
en_US: DM Database
5155
zh_Hans: 达梦数据库

utils/alchemy_db_client.py

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@
66
import logging
77
import time
88

9-
# 导入 GaussDB 自定义方言以注册到 SQLAlchemy
9+
# 导入自定义方言以注册到 SQLAlchemy
1010
try:
1111
from .gaussdb_dialect import GaussDBDialect
12+
from .kingbase_dialect import KingbaseESDialect
13+
from .dm_dialect import DMDialect
1214
except ImportError:
13-
pass # 如果导入失败,使用标准 PostgreSQL 方言
15+
pass # 如果导入失败,使用标准方言
1416

1517
# 配置日志
1618
logging.basicConfig(
@@ -103,8 +105,8 @@ def get_or_create_engine(
103105
encoded_password = quote_plus(password)
104106
connect_args = {}
105107

106-
# PostgreSQL 和 GaussDB schema 特殊处理
107-
if db_type.lower() in ('postgresql', 'gaussdb') and schema:
108+
# PostgreSQL、GaussDBKingbaseES schema 特殊处理
109+
if db_type.lower() in ('postgresql', 'gaussdb', 'kingbase') and schema:
108110
connect_args['options'] = f"-c search_path={schema}"
109111

110112
# 构建连接字符串
@@ -231,7 +233,7 @@ def execute_sql(
231233

232234
with engine.begin() as conn:
233235
# 显式设置schema(部分数据库需要)
234-
if db_type.lower() in ('postgresql', 'gaussdb') and schema:
236+
if db_type.lower() in ('postgresql', 'gaussdb', 'kingbase') and schema:
235237
conn.execute(text(f"SET search_path TO {schema}"))
236238
elif db_type.lower() in ('oracle', 'dm') and schema:
237239
# Oracle 和达梦数据库使用 ALTER SESSION 设置当前 schema
@@ -263,7 +265,8 @@ def _get_driver(db_type: str) -> str:
263265
'sqlserver': 'pymssql',
264266
'postgresql': 'psycopg2',
265267
'gaussdb': 'psycopg', # 仅 GaussDB 使用 psycopg3,避免版本解析问题
266-
'dm': 'oracledb' # 达梦数据库使用 oracledb 驱动(兼容 Oracle 协议)
268+
'kingbase': 'psycopg2', # 人大金仓使用 psycopg2 驱动(兼容 PostgreSQL)
269+
'dm': 'dmPython' # 达梦数据库使用专用的 dmPython 驱动
267270
}
268271
return drivers.get(db_type.lower(), '')
269272

@@ -285,10 +288,15 @@ def _build_connection_uri(
285288
# GaussDB 使用自定义方言来处理版本解析问题
286289
# 只禁用 SSL,保留 SCRAM-SHA-256 等认证方式的支持
287290
return f"gaussdb+{driver}://{username}:{password}@{host}:{port}/{database}?sslmode=disable"
291+
elif db_type == 'kingbase':
292+
# KingbaseES 使用自定义方言来处理版本解析问题
293+
# 人大金仓数据库兼容 PostgreSQL 协议
294+
return f"kingbase+{driver}://{username}:{password}@{host}:{port}/{database}"
288295
elif db_type == 'dm':
289-
# 达梦数据库使用 Oracle 驱动(兼容 Oracle 协议)
290-
# 格式:oracle+oracledb://user:pass@host:port/?service_name=SYSDBA
291-
return f"oracle+{driver}://{username}:{password}@{host}:{port}/?service_name=SYSDBA"
296+
# 达梦数据库使用专用的 dmPython 驱动和 dm 方言
297+
# 格式:dm+dmPython://user:pass@host:port/schema
298+
# database 参数在达梦中表示 schema
299+
return f"dm+{driver}://{username}:{password}@{host}:{port}/{database}"
292300

293301
return f"{db_type}+{driver}://{username}:{password}@{host}:{port}/{database}"
294302

0 commit comments

Comments
 (0)