feat: 18 引擎驱动全家桶 + 驱动管理/离线包 + 设置中心 + 工作台交互打磨
驱动接入(全部本机真实例验收): - Elasticsearch 原生 SQL API、InfluxDB 原生 HTTP+Flux(官方 JDBC 付费许可,实测弃用) - ZooKeeper/MongoDB JVM agent(连接时自动下载官方驱动 jar,sha256 钉版本到 ~/.opsxdb/drivers/) - 达梦 JDBC agent 桥就绪(待厂商 jar+实例);TiDB 真实例验收 - 协议族代码审查放行 PolarDB/TDSQL/OceanBase/Kingbase/GaussDB/Oracle - 驱动能力模型:按驱动开关对象树分组/右键菜单/行编辑,NoSQL 树拍平(对象直挂库节点) 驱动管理: - 驱动管理弹框(状态/预装/离线包导入/JDK 检测)+ /api/drivers/* 三接口 - opsxdb-driver 驱动商店仓库(清单/fetch.sh/pack.sh 离线包/import.sh) - 连接时懒加载:DMG 零 Java 产物,首连自动下载(实测 ZK 九件套 1.35s),离线包自动回退 UI/交互: - 设置中心(⚙):常规/执行/结果/驱动/快捷键/关于,左导航+右面板(对标 opsxshell) - 实例级展开箭头(行首 SVG chevron,替代字体回退失真的 Unicode 三角) - 树内嵌套渲染修复:对象树挂在激活连接下;工具栏窄窗口不断行(按钮 nowrap+整颗换行) - 侧栏连接行精简(图标+连接名)、SQLite SSH 守卫、Oracle 死参数清理 质量: - Go 协议层/离线回退单测、E2E 门控测试(ES/ZK/Influx/Mongo/TiDB/JDBC 桥) - 驱动注册表单一事实来源 connection-types.json,README/BACKLOG/AGENTS 同步
This commit is contained in:
1 parent
26f459d1b8
commit
a9510235bb
156 files changed
+17200
-2520
No files matched your search
@@ -0,0 +1,121 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// GetDDL 返回表/视图的建表语句。mysql 族走 SHOW CREATE TABLE,sqlite 读 sqlite_master,
|
||||
// pg/mssql/oracle 用 ListColumns 元数据在 Go 侧拼装 CREATE TABLE。
|
||||
func GetDDL(ctx context.Context, c ConnReq) (string, error) {
|
||||
ctx = reqCtx(ctx)
|
||||
if c.Table == "" {
|
||||
return "", fmt.Errorf("缺少表名")
|
||||
}
|
||||
if isRedis(c.Driver) {
|
||||
return "", fmt.Errorf("该驱动不支持 DDL 查看")
|
||||
}
|
||||
// pg/mssql/oracle:复用列元数据拼装,避免再查一次库
|
||||
switch {
|
||||
case isPostgresFamily(c.Driver), isMSSQL(c.Driver), driverKey(c.Driver) == "oracle":
|
||||
cols, err := ListColumns(ctx, c)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return buildDDLFromColumns(c.Driver, c.Table, cols)
|
||||
}
|
||||
var out string
|
||||
err := withDB(c, func(db *sql.DB) error {
|
||||
var err error
|
||||
switch {
|
||||
case isMySQLFamily(c.Driver):
|
||||
out, err = getDDLMySQL(ctx, db, c)
|
||||
case driverKey(c.Driver) == "sqlite":
|
||||
out, err = getDDLSQLite(ctx, db, c.Table)
|
||||
default:
|
||||
err = unsupportedDriverErr(c)
|
||||
}
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// getDDLMySQL SHOW CREATE TABLE 第二列即 DDL(列名随对象类型变化:Create Table/Create View)。
|
||||
func getDDLMySQL(ctx context.Context, dbh *sql.DB, c ConnReq) (string, error) {
|
||||
ident := quoteMySQLIdent(c.Table)
|
||||
if c.Database != "" {
|
||||
ident = quoteMySQLIdent(c.Database) + "." + ident
|
||||
}
|
||||
rows, err := dbh.QueryContext(ctx, "SHOW CREATE TABLE "+ident)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer rows.Close()
|
||||
if rows.Next() {
|
||||
var name string
|
||||
var ddl sql.NullString
|
||||
if err := rows.Scan(&name, &ddl); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if !ddl.Valid {
|
||||
return "", fmt.Errorf("无法读取 %s 的 DDL", c.Table)
|
||||
}
|
||||
return ddl.String, nil
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return "", fmt.Errorf("表 %s 不存在", c.Table)
|
||||
}
|
||||
|
||||
// getDDLSQLite sqlite_master 的 sql 列即建表语句。
|
||||
func getDDLSQLite(ctx context.Context, dbh *sql.DB, table string) (string, error) {
|
||||
var ddl sql.NullString
|
||||
err := dbh.QueryRowContext(ctx, `SELECT sql FROM sqlite_master WHERE name = ?`, table).Scan(&ddl)
|
||||
if err == sql.ErrNoRows {
|
||||
return "", fmt.Errorf("表 %s 不存在", table)
|
||||
}
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if !ddl.Valid {
|
||||
return "", fmt.Errorf("表 %s 无 DDL 记录", table)
|
||||
}
|
||||
return ddl.String, nil
|
||||
}
|
||||
|
||||
// buildDDLFromColumns 用列元数据拼装 CREATE TABLE(类型直接用 ColumnInfo.Type)。
|
||||
func buildDDLFromColumns(driver, table string, cols []ColumnInfo) (string, error) {
|
||||
if len(cols) == 0 {
|
||||
return "", fmt.Errorf("表 %s 不存在或无列", table)
|
||||
}
|
||||
var pks []string
|
||||
for _, col := range cols {
|
||||
if col.Key == "PRI" {
|
||||
pks = append(pks, quoteIdentFor(driver, col.Name))
|
||||
}
|
||||
}
|
||||
var b strings.Builder
|
||||
fmt.Fprintf(&b, "CREATE TABLE %s (\n", quoteTableNameFor(driver, table))
|
||||
for i, col := range cols {
|
||||
line := " " + quoteIdentFor(driver, col.Name) + " " + col.Type
|
||||
if !col.Nullable {
|
||||
line += " NOT NULL"
|
||||
}
|
||||
// 非最后一列、或后面还有 PRIMARY KEY 子句时需要逗号
|
||||
if i < len(cols)-1 || len(pks) > 0 {
|
||||
line += ","
|
||||
}
|
||||
b.WriteString(line + "\n")
|
||||
}
|
||||
if len(pks) > 0 {
|
||||
b.WriteString(" PRIMARY KEY (" + strings.Join(pks, ", ") + ")\n")
|
||||
}
|
||||
b.WriteString(");\n")
|
||||
return b.String(), nil
|
||||
}
|
||||
Reference in new issue
Block a user