mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-06-14 10:29:52 +08:00
- 分离 Oracle/OceanBase Oracle 同步连接 Service Name 与选中 schema - 兼容旧同步请求中 database 被 schema 覆盖的情况 - 规范 MySQL/MariaDB SHOW CREATE TABLE 标识符引用 Refs #549 Refs #518
217 lines
5.5 KiB
Go
217 lines
5.5 KiB
Go
package sync
|
||
|
||
import (
|
||
"strings"
|
||
|
||
"GoNavi-Wails/internal/connection"
|
||
"GoNavi-Wails/internal/db"
|
||
)
|
||
|
||
func selectedSyncDatabase(selected string, fallback string) string {
|
||
if value := strings.TrimSpace(selected); value != "" {
|
||
return value
|
||
}
|
||
return strings.TrimSpace(fallback)
|
||
}
|
||
|
||
func selectedSyncSourceDatabase(config SyncConfig) string {
|
||
return selectedSyncDatabase(config.SourceDatabase, config.SourceConfig.Database)
|
||
}
|
||
|
||
func selectedSyncTargetDatabase(config SyncConfig) string {
|
||
return selectedSyncDatabase(config.TargetDatabase, config.TargetConfig.Database)
|
||
}
|
||
|
||
func normalizeSyncConnectionDatabases(config SyncConfig) SyncConfig {
|
||
config.SourceConfig = normalizeSyncConnectionDatabase(config.SourceConfig, config.SourceDatabase)
|
||
config.TargetConfig = normalizeSyncConnectionDatabase(config.TargetConfig, config.TargetDatabase)
|
||
return config
|
||
}
|
||
|
||
func normalizeSyncConnectionDatabase(config connection.ConnectionConfig, selectedDatabase string) connection.ConnectionConfig {
|
||
selected := strings.TrimSpace(selectedDatabase)
|
||
if selected == "" {
|
||
return config
|
||
}
|
||
switch resolveMigrationDBType(config) {
|
||
case "oracle":
|
||
// Oracle 的 ConnectionConfig.Database 是 Service Name,数据同步选择的是 schema/owner。
|
||
return config
|
||
case "oceanbase":
|
||
if isOceanBaseOracleSyncConnection(config) {
|
||
return config
|
||
}
|
||
default:
|
||
config.Database = selected
|
||
return config
|
||
}
|
||
config.Database = selected
|
||
return config
|
||
}
|
||
|
||
func isOceanBaseOracleSyncConnection(config connection.ConnectionConfig) bool {
|
||
if !strings.EqualFold(strings.TrimSpace(config.Type), "oceanbase") {
|
||
return false
|
||
}
|
||
if strings.EqualFold(strings.TrimSpace(config.OceanBaseProtocol), "oracle") {
|
||
return true
|
||
}
|
||
for _, part := range strings.FieldsFunc(config.ConnectionParams, func(r rune) bool { return r == '&' || r == ';' }) {
|
||
key, value, ok := strings.Cut(part, "=")
|
||
if !ok {
|
||
continue
|
||
}
|
||
normalizedKey := strings.ToLower(strings.TrimSpace(key))
|
||
normalizedValue := strings.ToLower(strings.TrimSpace(value))
|
||
if (normalizedKey == "protocol" || normalizedKey == "tenantmode") && normalizedValue == "oracle" {
|
||
return true
|
||
}
|
||
}
|
||
return false
|
||
}
|
||
|
||
func normalizeSyncMode(mode string) string {
|
||
m := strings.ToLower(strings.TrimSpace(mode))
|
||
switch m {
|
||
case "", "insert_update":
|
||
return "insert_update"
|
||
case "insert_only":
|
||
return "insert_only"
|
||
case "full_overwrite":
|
||
return "full_overwrite"
|
||
default:
|
||
return "insert_update"
|
||
}
|
||
}
|
||
|
||
func quoteIdentByType(dbType string, ident string) string {
|
||
if ident == "" {
|
||
return ident
|
||
}
|
||
|
||
switch normalizeMigrationDBType(dbType) {
|
||
case "mysql", "mariadb", "oceanbase", "diros", "starrocks", "sphinx", "clickhouse", "tdengine":
|
||
return "`" + strings.ReplaceAll(ident, "`", "``") + "`"
|
||
case "kingbase":
|
||
return db.QuoteKingbaseIdentifier(ident)
|
||
case "sqlserver":
|
||
escaped := strings.ReplaceAll(ident, "]", "]]")
|
||
return "[" + escaped + "]"
|
||
default:
|
||
return `"` + strings.ReplaceAll(ident, `"`, `""`) + `"`
|
||
}
|
||
}
|
||
|
||
func quoteQualifiedIdentByType(dbType string, ident string) string {
|
||
raw := strings.TrimSpace(ident)
|
||
if raw == "" {
|
||
return raw
|
||
}
|
||
|
||
normalizedType := normalizeMigrationDBType(dbType)
|
||
if normalizedType == "kingbase" {
|
||
schema, table := db.SplitKingbaseQualifiedName(raw)
|
||
if table == "" {
|
||
return quoteIdentByType(normalizedType, raw)
|
||
}
|
||
if schema == "" {
|
||
return quoteIdentByType(normalizedType, table)
|
||
}
|
||
return quoteIdentByType(normalizedType, schema) + "." + quoteIdentByType(normalizedType, table)
|
||
}
|
||
|
||
parts := strings.Split(raw, ".")
|
||
if len(parts) <= 1 {
|
||
return quoteIdentByType(normalizedType, raw)
|
||
}
|
||
|
||
quotedParts := make([]string, 0, len(parts))
|
||
for _, part := range parts {
|
||
part = strings.TrimSpace(part)
|
||
if part == "" {
|
||
continue
|
||
}
|
||
quotedParts = append(quotedParts, quoteIdentByType(normalizedType, part))
|
||
}
|
||
|
||
if len(quotedParts) == 0 {
|
||
return quoteIdentByType(normalizedType, raw)
|
||
}
|
||
return strings.Join(quotedParts, ".")
|
||
}
|
||
|
||
func normalizeSchemaAndTable(dbType string, dbName string, tableName string) (string, string) {
|
||
rawTable := strings.TrimSpace(tableName)
|
||
rawDB := strings.TrimSpace(dbName)
|
||
if rawTable == "" {
|
||
return rawDB, rawTable
|
||
}
|
||
|
||
normalizedType := normalizeMigrationDBType(dbType)
|
||
if normalizedType == "kingbase" {
|
||
schema, table := db.SplitKingbaseQualifiedName(rawTable)
|
||
if schema != "" && table != "" {
|
||
return schema, table
|
||
}
|
||
if table != "" {
|
||
return "public", table
|
||
}
|
||
}
|
||
|
||
if parts := strings.SplitN(rawTable, ".", 2); len(parts) == 2 {
|
||
schema := strings.TrimSpace(parts[0])
|
||
table := strings.TrimSpace(parts[1])
|
||
if schema != "" && table != "" {
|
||
return schema, table
|
||
}
|
||
}
|
||
|
||
switch normalizedType {
|
||
case "postgres", "kingbase", "highgo", "vastbase", "opengauss":
|
||
return "public", rawTable
|
||
case "duckdb":
|
||
return "main", rawTable
|
||
default:
|
||
return rawDB, rawTable
|
||
}
|
||
}
|
||
|
||
func qualifiedNameForQuery(dbType string, schema string, table string, original string) string {
|
||
raw := strings.TrimSpace(original)
|
||
if raw == "" {
|
||
return raw
|
||
}
|
||
if strings.Contains(raw, ".") {
|
||
return raw
|
||
}
|
||
|
||
switch normalizeMigrationDBType(dbType) {
|
||
case "postgres", "kingbase", "highgo", "vastbase", "opengauss":
|
||
s := strings.TrimSpace(schema)
|
||
if s == "" {
|
||
s = "public"
|
||
}
|
||
if table == "" {
|
||
return raw
|
||
}
|
||
return s + "." + table
|
||
case "duckdb":
|
||
s := strings.TrimSpace(schema)
|
||
if s == "" {
|
||
s = "main"
|
||
}
|
||
if table == "" {
|
||
return raw
|
||
}
|
||
return s + "." + table
|
||
case "mysql", "mariadb", "oceanbase", "diros", "starrocks", "sphinx", "clickhouse", "tdengine":
|
||
s := strings.TrimSpace(schema)
|
||
if s == "" || table == "" {
|
||
return table
|
||
}
|
||
return s + "." + table
|
||
default:
|
||
return table
|
||
}
|
||
}
|