Files
MyGoNavi/internal/db/sphinx_impl.go
Syngnat 26a7aacfec feat(drivers): 支持按需启动数据源并通过外置驱动代理减少发行包体积
- MySQL/Redis/Oracle/PostgreSQL 内置可用,其余数据源改为“安装启用”后可用
- 新建连接对未安装驱动做弹窗内拦截提示,并支持一键跳转驱动管理安装
- 驱动管理展示安装包真实大小(从 Release 资产元数据读取)并优化加载性能
- Release 工作流发布各平台驱动代理资产,主程序构建启用 -s -w 精简
2026-02-13 17:23:38 +08:00

200 lines
5.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//go:build gonavi_full_drivers || gonavi_sphinx_driver
package db
import (
"fmt"
"strings"
"GoNavi-Wails/internal/connection"
"GoNavi-Wails/internal/logger"
)
const sphinxDefaultDatabaseName = "default"
// SphinxDB 复用 MySQL 协议实现,并在数据库列表不可用时提供兜底。
type SphinxDB struct {
MySQLDB
fallbackDatabase string
}
func isSphinxUnsupportedFeatureError(err error) bool {
if err == nil {
return false
}
text := strings.ToLower(strings.TrimSpace(err.Error()))
if text == "" {
return false
}
keywords := []string{
"not supported",
"unsupported",
"syntax error",
"unknown table",
"unknown column",
"doesn't exist",
}
for _, keyword := range keywords {
if strings.Contains(text, keyword) {
return true
}
}
return false
}
func (s *SphinxDB) Connect(config connection.ConnectionConfig) error {
runConfig := applyMySQLURI(config)
s.fallbackDatabase = strings.TrimSpace(runConfig.Database)
return s.MySQLDB.Connect(config)
}
func (s *SphinxDB) resolveDatabaseName(dbName string) string {
name := strings.TrimSpace(dbName)
if name == "" {
return s.fallbackDatabase
}
if strings.EqualFold(name, sphinxDefaultDatabaseName) && s.fallbackDatabase == "" {
return ""
}
return name
}
func (s *SphinxDB) GetDatabases() ([]string, error) {
dbs, err := s.MySQLDB.GetDatabases()
if err == nil && len(dbs) > 0 {
return dbs, nil
}
if s.fallbackDatabase != "" {
return []string{s.fallbackDatabase}, nil
}
return []string{sphinxDefaultDatabaseName}, nil
}
func (s *SphinxDB) GetTables(dbName string) ([]string, error) {
tables, err := s.MySQLDB.GetTables(s.resolveDatabaseName(dbName))
if err == nil {
return tables, nil
}
if !isSphinxUnsupportedFeatureError(err) {
return nil, err
}
// Sphinx/Manticore 常见返回列名为 `Index`,并且不支持 `SHOW TABLES FROM <db>` 语法。
data, fields, fallbackErr := s.MySQLDB.Query("SHOW TABLES")
if fallbackErr != nil {
return nil, fallbackErr
}
fallbackTables := make([]string, 0, len(data))
for _, row := range data {
if val, ok := row["Index"]; ok {
fallbackTables = append(fallbackTables, fmt.Sprintf("%v", val))
continue
}
if val, ok := row["index"]; ok {
fallbackTables = append(fallbackTables, fmt.Sprintf("%v", val))
continue
}
for _, field := range fields {
if val, ok := row[field]; ok {
fallbackTables = append(fallbackTables, fmt.Sprintf("%v", val))
break
}
}
}
return fallbackTables, nil
}
func (s *SphinxDB) GetCreateStatement(dbName, tableName string) (string, error) {
return s.MySQLDB.GetCreateStatement(s.resolveDatabaseName(dbName), tableName)
}
func (s *SphinxDB) GetColumns(dbName, tableName string) ([]connection.ColumnDefinition, error) {
// Sphinx 使用 DESCRIBE 语法获取索引结构
query := fmt.Sprintf("DESCRIBE %s", tableName)
data, _, err := s.MySQLDB.Query(query)
if err != nil {
// 如果 DESCRIBE 失败,尝试使用 MySQL 的方式作为降级
return s.MySQLDB.GetColumns(s.resolveDatabaseName(dbName), tableName)
}
var columns []connection.ColumnDefinition
for _, row := range data {
// Sphinx DESCRIBE 返回的字段Field, Type, Properties
fieldName := ""
if val, ok := row["Field"]; ok {
fieldName = fmt.Sprintf("%v", val)
} else if val, ok := row["field"]; ok {
fieldName = fmt.Sprintf("%v", val)
}
fieldType := ""
if val, ok := row["Type"]; ok {
fieldType = fmt.Sprintf("%v", val)
} else if val, ok := row["type"]; ok {
fieldType = fmt.Sprintf("%v", val)
}
properties := ""
if val, ok := row["Properties"]; ok {
properties = fmt.Sprintf("%v", val)
} else if val, ok := row["properties"]; ok {
properties = fmt.Sprintf("%v", val)
}
if fieldName == "" {
continue
}
col := connection.ColumnDefinition{
Name: fieldName,
Type: fieldType,
Nullable: "YES", // Sphinx 默认字段可为空
Key: "", // Sphinx 没有主键概念
Default: nil, // Sphinx DESCRIBE 不返回默认值
Extra: properties,
Comment: "",
}
// 根据 properties 判断是否为索引字段
if strings.Contains(strings.ToLower(properties), "indexed") {
col.Key = "MUL"
}
columns = append(columns, col)
}
// 如果没有获取到任何列,尝试使用 MySQL 方式
if len(columns) == 0 {
logger.Warnf("Sphinx DESCRIBE 未返回任何列,尝试使用 MySQL 方式获取:表=%s", tableName)
return s.MySQLDB.GetColumns(s.resolveDatabaseName(dbName), tableName)
}
return columns, nil
}
func (s *SphinxDB) GetAllColumns(dbName string) ([]connection.ColumnDefinitionWithTable, error) {
return s.MySQLDB.GetAllColumns(s.resolveDatabaseName(dbName))
}
func (s *SphinxDB) GetIndexes(dbName, tableName string) ([]connection.IndexDefinition, error) {
return s.MySQLDB.GetIndexes(s.resolveDatabaseName(dbName), tableName)
}
func (s *SphinxDB) GetForeignKeys(dbName, tableName string) ([]connection.ForeignKeyDefinition, error) {
fks, err := s.MySQLDB.GetForeignKeys(s.resolveDatabaseName(dbName), tableName)
if err != nil && isSphinxUnsupportedFeatureError(err) {
return []connection.ForeignKeyDefinition{}, nil
}
return fks, err
}
func (s *SphinxDB) GetTriggers(dbName, tableName string) ([]connection.TriggerDefinition, error) {
triggers, err := s.MySQLDB.GetTriggers(s.resolveDatabaseName(dbName), tableName)
if err != nil && isSphinxUnsupportedFeatureError(err) {
return []connection.TriggerDefinition{}, nil
}
return triggers, err
}