Skip to content

Commit 4197693

Browse files
Implement :serverlist command
- Add serverlist command to list SQL Server instances via SQL Browser service - Move server listing logic from cmd/sqlcmd to pkg/sqlcmd for reuse - Both -L flag and :serverlist command now use shared ListLocalServers function - Add comprehensive tests for serverlist functionality
1 parent 758fca9 commit 4197693

4 files changed

Lines changed: 839 additions & 722 deletions

File tree

cmd/sqlcmd/sqlcmd.go

Lines changed: 1 addition & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,16 @@
55
package sqlcmd
66

77
import (
8-
"context"
98
"errors"
109
"fmt"
11-
"net"
1210
"os"
1311
"regexp"
1412
"runtime/trace"
1513
"strconv"
1614
"strings"
17-
"time"
1815

1916
mssql "github.com/microsoft/go-mssqldb"
2017
"github.com/microsoft/go-mssqldb/azuread"
21-
"github.com/microsoft/go-mssqldb/msdsn"
2218
"github.com/microsoft/go-sqlcmd/internal/localizer"
2319
"github.com/microsoft/go-sqlcmd/pkg/console"
2420
"github.com/microsoft/go-sqlcmd/pkg/sqlcmd"
@@ -236,7 +232,7 @@ func Execute(version string) {
236232
fmt.Println()
237233
fmt.Println(localizer.Sprintf("Servers:"))
238234
}
239-
listLocalServers()
235+
sqlcmd.ListLocalServers(os.Stdout)
240236
os.Exit(0)
241237
}
242238
if len(argss) > 0 {
@@ -911,76 +907,3 @@ func run(vars *sqlcmd.Variables, args *SQLCmdArguments) (int, error) {
911907
s.SetError(nil)
912908
return s.Exitcode, err
913909
}
914-
915-
func listLocalServers() {
916-
bmsg := []byte{byte(msdsn.BrowserAllInstances)}
917-
resp := make([]byte, 16*1024-1)
918-
dialer := &net.Dialer{}
919-
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
920-
defer cancel()
921-
conn, err := dialer.DialContext(ctx, "udp", ":1434")
922-
// silently ignore failures to connect, same as ODBC
923-
if err != nil {
924-
return
925-
}
926-
defer conn.Close()
927-
dl, _ := ctx.Deadline()
928-
_ = conn.SetDeadline(dl)
929-
_, err = conn.Write(bmsg)
930-
if err != nil {
931-
if !errors.Is(err, os.ErrDeadlineExceeded) {
932-
fmt.Println(err)
933-
}
934-
return
935-
}
936-
read, err := conn.Read(resp)
937-
if err != nil {
938-
if !errors.Is(err, os.ErrDeadlineExceeded) {
939-
fmt.Println(err)
940-
}
941-
return
942-
}
943-
944-
data := parseInstances(resp[:read])
945-
instances := make([]string, 0, len(data))
946-
for s := range data {
947-
if s == "MSSQLSERVER" {
948-
949-
instances = append(instances, "(local)", data[s]["ServerName"])
950-
} else {
951-
instances = append(instances, fmt.Sprintf(`%s\%s`, data[s]["ServerName"], s))
952-
}
953-
}
954-
for _, s := range instances {
955-
fmt.Println(" ", s)
956-
}
957-
}
958-
959-
func parseInstances(msg []byte) msdsn.BrowserData {
960-
results := msdsn.BrowserData{}
961-
if len(msg) > 3 && msg[0] == 5 {
962-
out_s := string(msg[3:])
963-
tokens := strings.Split(out_s, ";")
964-
instdict := map[string]string{}
965-
got_name := false
966-
var name string
967-
for _, token := range tokens {
968-
if got_name {
969-
instdict[name] = token
970-
got_name = false
971-
} else {
972-
name = token
973-
if len(name) == 0 {
974-
if len(instdict) == 0 {
975-
break
976-
}
977-
results[strings.ToUpper(instdict["InstanceName"])] = instdict
978-
instdict = map[string]string{}
979-
continue
980-
}
981-
got_name = true
982-
}
983-
}
984-
}
985-
return results
986-
}

0 commit comments

Comments
 (0)