package db import ( "database/sql" "fmt" "net/url" "strings" _ "github.com/microsoft/go-mssqldb" ) func openMSSQL(c ConnReq) (*sql.DB, error) { host := c.Host if host == "" { host = "127.0.0.1" } port := c.Port if port == 0 { port = 1433 } user := c.User if user == "" { user = "sa" } dbName := c.Database if dbName == "" { dbName = "master" } mode := EffectiveSSLMode(c) q := url.Values{} q.Set("database", dbName) q.Set("connection timeout", "5") switch mode { case "disable": q.Set("encrypt", "disable") case "skip-verify": q.Set("encrypt", "true") q.Set("TrustServerCertificate", "true") if ca := strings.TrimSpace(c.SSLCA); ca != "" { q.Set("certificate", ca) } case "require", "verify-ca": q.Set("encrypt", "true") q.Set("TrustServerCertificate", "false") ca := strings.TrimSpace(c.SSLCA) if mode == "verify-ca" && ca == "" { return nil, fmt.Errorf("verify-ca 模式需要填写 CA 证书路径") } if ca != "" { // go-mssqldb msdsn certificate= builds RootCAs from PEM/DER q.Set("certificate", ca) } if host != "" { q.Set("hostnameincertificate", host) } default: return nil, fmt.Errorf("未知 SSL 模式: %s", mode) } dsn := fmt.Sprintf("sqlserver://%s:%s@%s:%d?%s", url.QueryEscape(user), url.QueryEscape(c.Password), host, port, q.Encode()) return sql.Open("sqlserver", dsn) } func listDatabasesMSSQL(db *sql.DB) ([]string, error) { rows, err := db.Query(`SELECT name FROM sys.databases WHERE name NOT IN ('master','tempdb','model','msdb') ORDER BY name`) if err != nil { return nil, err } defer rows.Close() var out []string for rows.Next() { var name string if err := rows.Scan(&name); err != nil { return nil, err } out = append(out, name) } return out, rows.Err() } func listTablesMSSQL(db *sql.DB, database string) ([]string, error) { _ = database rows, err := db.Query(` SELECT TABLE_SCHEMA + '.' + TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' ORDER BY 1`) if err != nil { return nil, err } defer rows.Close() var out []string for rows.Next() { var name string if err := rows.Scan(&name); err != nil { return nil, err } out = append(out, name) } return out, rows.Err() } func listColumnsMSSQL(dbh *sql.DB, _, table string) ([]ColumnInfo, error) { schema, t := splitSchemaTable(table) if schema == "" { schema = "dbo" } rows, err := dbh.Query(` SELECT COLUMN_NAME, DATA_TYPE, ISNULL(CAST(CHARACTER_MAXIMUM_LENGTH AS varchar), ''), IS_NULLABLE, COLUMN_DEFAULT FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = @p1 AND TABLE_NAME = @p2 ORDER BY ORDINAL_POSITION`, schema, t) if err != nil { return nil, err } defer rows.Close() var out []ColumnInfo for rows.Next() { var name, typ, extra, nullable string var def sql.NullString if err := rows.Scan(&name, &typ, &extra, &nullable, &def); err != nil { return nil, err } if extra != "" && extra != "-1" { typ = typ + "(" + extra + ")" } col := ColumnInfo{Name: name, Type: typ, Nullable: nullable == "YES"} if def.Valid { col.Default = def.String } out = append(out, col) } if out == nil { out = []ColumnInfo{} } return out, rows.Err() }