mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-07-08 11:31:57 +08:00
🐛 fix(tdengine): 修复低版本驱动连接与表元数据兼容问题
- 修复 TDengine 历史驱动源码构建未按所选版本切换依赖的问题 - 为 DESCRIBE 与 SHOW CREATE 增加旧版本语法降级,避免表详情加载报错 - 为表概览补充 TDengine 专用查询分支,避免误查 information_schema - 补充 TDengine 兼容性与驱动构建回归测试 Refs #531
This commit is contained in:
@@ -16,6 +16,7 @@ import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
stdRuntime "runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
@@ -3656,6 +3657,15 @@ func buildOptionalDriverAgentFromSource(definition driverDefinition, executableP
|
||||
if rootErr != nil {
|
||||
return "", rootErr
|
||||
}
|
||||
buildArgs := []string{"build", "-tags", tagName, "-trimpath", "-ldflags", "-s -w"}
|
||||
cleanupModOverride := func() {}
|
||||
if modOverride, modErr := prepareOptionalDriverBuildModOverride(projectRoot, driverType, selectedVersion); modErr != nil {
|
||||
return "", modErr
|
||||
} else if modOverride != nil {
|
||||
buildArgs = append(buildArgs, "-modfile", modOverride.modFile)
|
||||
cleanupModOverride = modOverride.cleanup
|
||||
}
|
||||
defer cleanupModOverride()
|
||||
env := append([]string{}, os.Environ()...)
|
||||
env = withEnvValue(env, "GOTOOLCHAIN", "auto")
|
||||
var duckDBLibDir string
|
||||
@@ -3679,7 +3689,8 @@ func buildOptionalDriverAgentFromSource(definition driverDefinition, executableP
|
||||
env = withEnvValue(env, "CGO_LDFLAGS", fmt.Sprintf("-L\"%s\" -lduckdb", filepath.ToSlash(duckDBLibDir)))
|
||||
env = prependPathEnv(env, duckDBLibDir)
|
||||
}
|
||||
cmd := exec.Command(goPath, "build", "-tags", tagName, "-trimpath", "-ldflags", "-s -w", "-o", executablePath, "./cmd/optional-driver-agent")
|
||||
buildArgs = append(buildArgs, "-o", executablePath, "./cmd/optional-driver-agent")
|
||||
cmd := exec.Command(goPath, buildArgs...)
|
||||
cmd.Dir = projectRoot
|
||||
cmd.Env = env
|
||||
output, buildErr := cmd.CombinedOutput()
|
||||
@@ -3701,6 +3712,94 @@ func buildOptionalDriverAgentFromSource(definition driverDefinition, executableP
|
||||
return hash, nil
|
||||
}
|
||||
|
||||
type optionalDriverBuildModOverride struct {
|
||||
modFile string
|
||||
cleanup func()
|
||||
}
|
||||
|
||||
func prepareOptionalDriverBuildModOverride(projectRoot string, driverType string, selectedVersion string) (*optionalDriverBuildModOverride, error) {
|
||||
modulePath := strings.TrimSpace(driverGoModulePathMap[normalizeDriverType(driverType)])
|
||||
versionText := normalizeVersion(strings.TrimSpace(selectedVersion))
|
||||
if strings.EqualFold(normalizeDriverType(driverType), "tdengine") && modulePath != "" && versionText != "" {
|
||||
return buildVersionedDriverModOverride(projectRoot, modulePath, versionText)
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func buildVersionedDriverModOverride(projectRoot string, modulePath string, version string) (*optionalDriverBuildModOverride, error) {
|
||||
goModPath := filepath.Join(projectRoot, "go.mod")
|
||||
goSumPath := filepath.Join(projectRoot, "go.sum")
|
||||
modBytes, err := os.ReadFile(goModPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("读取 go.mod 失败:%w", err)
|
||||
}
|
||||
|
||||
replaced, changed, err := rewriteRequiredModuleVersion(modBytes, modulePath, version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !changed {
|
||||
return nil, fmt.Errorf("未在 go.mod 中找到驱动依赖:%s", modulePath)
|
||||
}
|
||||
|
||||
workDir, err := os.MkdirTemp("", "gonavi-driver-mod-*")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("创建驱动构建临时目录失败:%w", err)
|
||||
}
|
||||
cleanup := func() {
|
||||
_ = os.RemoveAll(workDir)
|
||||
}
|
||||
|
||||
modFile := filepath.Join(workDir, "go.mod")
|
||||
sumFile := filepath.Join(workDir, "go.sum")
|
||||
if err := os.WriteFile(modFile, replaced, 0o644); err != nil {
|
||||
cleanup()
|
||||
return nil, fmt.Errorf("写入临时 go.mod 失败:%w", err)
|
||||
}
|
||||
if sumBytes, readErr := os.ReadFile(goSumPath); readErr == nil {
|
||||
if writeErr := os.WriteFile(sumFile, sumBytes, 0o644); writeErr != nil {
|
||||
cleanup()
|
||||
return nil, fmt.Errorf("写入临时 go.sum 失败:%w", writeErr)
|
||||
}
|
||||
}
|
||||
|
||||
return &optionalDriverBuildModOverride{
|
||||
modFile: modFile,
|
||||
cleanup: cleanup,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func rewriteRequiredModuleVersion(goMod []byte, modulePath string, version string) ([]byte, bool, error) {
|
||||
trimmedModule := strings.TrimSpace(modulePath)
|
||||
trimmedVersion := normalizeVersion(strings.TrimSpace(version))
|
||||
if trimmedModule == "" || trimmedVersion == "" {
|
||||
return nil, false, fmt.Errorf("驱动模块或版本为空")
|
||||
}
|
||||
|
||||
pattern := fmt.Sprintf(`(?m)^(?P<prefix>\s*%s\s+)v[^\s]+(?P<suffix>\s*(//.*)?)$`, regexp.QuoteMeta(trimmedModule))
|
||||
re := regexp.MustCompile(pattern)
|
||||
changed := false
|
||||
replaced := re.ReplaceAllFunc(goMod, func(line []byte) []byte {
|
||||
match := re.FindSubmatch(line)
|
||||
if len(match) == 0 {
|
||||
return line
|
||||
}
|
||||
changed = true
|
||||
text := string(line)
|
||||
submatches := re.FindStringSubmatch(text)
|
||||
if len(submatches) == 0 {
|
||||
return line
|
||||
}
|
||||
prefix := submatches[1]
|
||||
suffix := ""
|
||||
if len(submatches) > 2 {
|
||||
suffix = submatches[2]
|
||||
}
|
||||
return []byte(prefix + "v" + trimmedVersion + suffix)
|
||||
})
|
||||
return replaced, changed, nil
|
||||
}
|
||||
|
||||
func resolveMongoDriverMajorFromVersion(version string) int {
|
||||
trimmed := strings.TrimSpace(version)
|
||||
trimmed = strings.TrimPrefix(trimmed, "v")
|
||||
|
||||
75
internal/app/methods_driver_tdengine_build_test.go
Normal file
75
internal/app/methods_driver_tdengine_build_test.go
Normal file
@@ -0,0 +1,75 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRewriteRequiredModuleVersionUpdatesTDengineDriver(t *testing.T) {
|
||||
input := []byte(`module example
|
||||
|
||||
go 1.24.3
|
||||
|
||||
require (
|
||||
github.com/taosdata/driver-go/v3 v3.7.8
|
||||
github.com/go-sql-driver/mysql v1.9.3
|
||||
)
|
||||
`)
|
||||
|
||||
got, changed, err := rewriteRequiredModuleVersion(input, "github.com/taosdata/driver-go/v3", "3.3.1")
|
||||
if err != nil {
|
||||
t.Fatalf("rewriteRequiredModuleVersion returned error: %v", err)
|
||||
}
|
||||
if !changed {
|
||||
t.Fatal("expected TDengine module version to be rewritten")
|
||||
}
|
||||
text := string(got)
|
||||
if !strings.Contains(text, "github.com/taosdata/driver-go/v3 v3.3.1") {
|
||||
t.Fatalf("expected rewritten go.mod to contain TDengine 3.3.1, got:\n%s", text)
|
||||
}
|
||||
if !strings.Contains(text, "github.com/go-sql-driver/mysql v1.9.3") {
|
||||
t.Fatalf("expected unrelated dependencies to remain unchanged, got:\n%s", text)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrepareOptionalDriverBuildModOverrideCreatesVersionedModFileForTDengine(t *testing.T) {
|
||||
projectRoot := t.TempDir()
|
||||
goMod := `module example
|
||||
|
||||
go 1.24.3
|
||||
|
||||
require (
|
||||
github.com/taosdata/driver-go/v3 v3.7.8
|
||||
)
|
||||
`
|
||||
if err := os.WriteFile(filepath.Join(projectRoot, "go.mod"), []byte(goMod), 0o644); err != nil {
|
||||
t.Fatalf("write go.mod: %v", err)
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(projectRoot, "go.sum"), []byte("placeholder"), 0o644); err != nil {
|
||||
t.Fatalf("write go.sum: %v", err)
|
||||
}
|
||||
|
||||
override, err := prepareOptionalDriverBuildModOverride(projectRoot, "tdengine", "3.3.1")
|
||||
if err != nil {
|
||||
t.Fatalf("prepareOptionalDriverBuildModOverride returned error: %v", err)
|
||||
}
|
||||
if override == nil {
|
||||
t.Fatal("expected TDengine versioned build to create a mod override")
|
||||
}
|
||||
|
||||
modBytes, err := os.ReadFile(override.modFile)
|
||||
if err != nil {
|
||||
t.Fatalf("read override mod file: %v", err)
|
||||
}
|
||||
if !strings.Contains(string(modBytes), "github.com/taosdata/driver-go/v3 v3.3.1") {
|
||||
t.Fatalf("override mod file did not pin TDengine 3.3.1:\n%s", string(modBytes))
|
||||
}
|
||||
|
||||
overrideDir := filepath.Dir(override.modFile)
|
||||
override.cleanup()
|
||||
if _, statErr := os.Stat(overrideDir); !os.IsNotExist(statErr) {
|
||||
t.Fatalf("expected cleanup to remove override dir, statErr=%v", statErr)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user