Skip to content
Closed
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ linux-s390x/sqlcmd
# Build artifacts in root
/sqlcmd
/sqlcmd_binary
/modern

# certificates used for local testing
*.der
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,14 @@ The Homebrew package manager may be used on Linux and Windows Subsystem for Linu

Use `sqlcmd` to create SQL Server and Azure SQL Edge instances using a local container runtime (e.g. [Docker][] or [Podman][])

### Create SQL Server instance using local container runtime and connect using Azure Data Studio
### Create SQL Server instance using local container runtime and connect using Visual Studio Code

To create a local SQL Server instance with the AdventureWorksLT database restored, query it, and connect to it using Azure Data Studio, run:
To create a local SQL Server instance with the AdventureWorksLT database restored, query it, and connect to it using Visual Studio Code with the MSSQL extension, run:

```
sqlcmd create mssql --accept-eula --using https://aka.ms/AdventureWorksLT.bak
sqlcmd query "SELECT DB_NAME()"
sqlcmd open ads
sqlcmd open vscode
```

Use `sqlcmd --help` to view all the available sub-commands. Use `sqlcmd -?` to view the original ODBC `sqlcmd` flags.
Expand Down
6 changes: 4 additions & 2 deletions cmd/modern/root/open.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,21 @@ type Open struct {
func (c *Open) DefineCommand(...cmdparser.CommandOptions) {
options := cmdparser.CommandOptions{
Use: "open",
Short: localizer.Sprintf("Open tools (e.g Azure Data Studio) for current context"),
Short: localizer.Sprintf("Open tools (e.g Visual Studio Code, SSMS) for current context"),
SubCommands: c.SubCommands(),
}

c.Cmd.DefineCommand(options)
}

// SubCommands sets up the sub-commands for `sqlcmd open` such as
// `sqlcmd open ads`
// `sqlcmd open ads`, `sqlcmd open vscode`, and `sqlcmd open ssms`
func (c *Open) SubCommands() []cmdparser.Command {
dependencies := c.Dependencies()

return []cmdparser.Command{
cmdparser.New[*open.Ads](dependencies),
cmdparser.New[*open.VSCode](dependencies),
cmdparser.New[*open.Ssms](dependencies),
}
}
95 changes: 95 additions & 0 deletions cmd/modern/root/open/ssms.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

package open

import (
"fmt"
"runtime"
"strings"

"github.com/microsoft/go-sqlcmd/cmd/modern/sqlconfig"
"github.com/microsoft/go-sqlcmd/internal/cmdparser"
"github.com/microsoft/go-sqlcmd/internal/config"
"github.com/microsoft/go-sqlcmd/internal/container"
"github.com/microsoft/go-sqlcmd/internal/localizer"
"github.com/microsoft/go-sqlcmd/internal/tools"
)

// Ssms implements the `sqlcmd open ssms` command. It opens
// SQL Server Management Studio and connects to the current context using the
// credentials specified in the context.
func (c *Ssms) DefineCommand(...cmdparser.CommandOptions) {
options := cmdparser.CommandOptions{
Use: "ssms",
Short: localizer.Sprintf("Open SQL Server Management Studio and connect to current context"),
Examples: []cmdparser.ExampleOptions{{
Description: localizer.Sprintf("Open SSMS and connect using the current context"),
Steps: []string{"sqlcmd open ssms"}}},
Run: c.run,
}

c.Cmd.DefineCommand(options)
}

// Launch SSMS and connect to the current context
func (c *Ssms) run() {
endpoint, user := config.CurrentContext()

// If the context has a local container, ensure it is running, otherwise bail out
if endpoint.ContainerDetails != nil {
c.ensureContainerIsRunning(endpoint)
}

// Launch SSMS with connection parameters
c.launchSsms(endpoint.Address, endpoint.Port, user)
}

func (c *Ssms) ensureContainerIsRunning(endpoint sqlconfig.Endpoint) {
output := c.Output()
controller := container.NewController()
if !controller.ContainerRunning(endpoint.Id) {
output.FatalWithHintExamples([][]string{
{localizer.Sprintf("To start the container"), localizer.Sprintf("sqlcmd start")},
}, localizer.Sprintf("Container is not running"))
}
}

// launchSsms launches SQL Server Management Studio using the specified server and user credentials.
func (c *Ssms) launchSsms(host string, port int, user *sqlconfig.User) {
output := c.Output()

// Build server connection string
serverArg := fmt.Sprintf("%s,%d", host, port)

args := []string{
"-S", serverArg,
"-nosplash",
}

// Add authentication parameters
if user != nil && user.AuthenticationType == "basic" {
// SQL Server authentication
// Escape double quotes in username (SQL Server allows " in login names)
username := strings.ReplaceAll(user.BasicAuth.Username, `"`, `\"`)
args = append(args, "-U", username)
// Note: -P parameter was removed in SSMS 18+ for security reasons
// User will need to enter password in the login dialog
output.Info(localizer.Sprintf("Note: You will need to enter the password in the SSMS login dialog"))
} else {
// Windows integrated authentication
if runtime.GOOS == "windows" {
args = append(args, "-E")
}
}

tool := tools.NewTool("ssms")
if !tool.IsInstalled() {
output.Fatal(tool.HowToInstall())
}

c.displayPreLaunchInfo()

_, err := tool.Run(args)
c.CheckErr(err)
}
22 changes: 22 additions & 0 deletions cmd/modern/root/open/ssms_darwin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

package open

import (
"github.com/microsoft/go-sqlcmd/internal/cmdparser"
"github.com/microsoft/go-sqlcmd/internal/localizer"
)

// Type Ssms is used to implement the "open ssms" which launches SQL Server
// Management Studio and establishes a connection to the SQL Server for the current
// context
type Ssms struct {
cmdparser.Cmd
}

func (c *Ssms) displayPreLaunchInfo() {
output := c.Output()
output.Info(localizer.Sprintf("SSMS is only available on Windows"))
output.Info(localizer.Sprintf("Please use 'sqlcmd open vscode' or 'sqlcmd open ads' instead"))
}
22 changes: 22 additions & 0 deletions cmd/modern/root/open/ssms_linux.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

package open

import (
"github.com/microsoft/go-sqlcmd/internal/cmdparser"
"github.com/microsoft/go-sqlcmd/internal/localizer"
)

// Type Ssms is used to implement the "open ssms" which launches SQL Server
// Management Studio and establishes a connection to the SQL Server for the current
// context
type Ssms struct {
cmdparser.Cmd
}

func (c *Ssms) displayPreLaunchInfo() {
output := c.Output()
output.Info(localizer.Sprintf("SSMS is only available on Windows"))
output.Info(localizer.Sprintf("Please use 'sqlcmd open vscode' or 'sqlcmd open ads' instead"))
}
36 changes: 36 additions & 0 deletions cmd/modern/root/open/ssms_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

package open

import (
"github.com/microsoft/go-sqlcmd/cmd/modern/sqlconfig"
"github.com/microsoft/go-sqlcmd/internal/cmdparser"
"github.com/microsoft/go-sqlcmd/internal/config"
"runtime"
"testing"
)

// TestSsms runs a sanity test of `sqlcmd open ssms`
func TestSsms(t *testing.T) {
if runtime.GOOS != "windows" {
t.Skip("SSMS is only available on Windows")
}

cmdparser.TestSetup(t)
config.AddEndpoint(sqlconfig.Endpoint{
AssetDetails: nil,
EndpointDetails: sqlconfig.EndpointDetails{},
Name: "endpoint",
})
config.AddContext(sqlconfig.Context{
ContextDetails: sqlconfig.ContextDetails{
Endpoint: "endpoint",
User: nil,
},
Name: "context",
})
config.SetCurrentContextName("context")

cmdparser.TestCmd[*Ssms]()
}
22 changes: 22 additions & 0 deletions cmd/modern/root/open/ssms_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

package open

import (
"github.com/microsoft/go-sqlcmd/internal/cmdparser"
"github.com/microsoft/go-sqlcmd/internal/localizer"
)

// Type Ssms is used to implement the "open ssms" which launches SQL Server
// Management Studio and establishes a connection to the SQL Server for the current
// context
type Ssms struct {
cmdparser.Cmd
}

// On Windows, display info before launching
func (c *Ssms) displayPreLaunchInfo() {
output := c.Output()
output.Info(localizer.Sprintf("Launching SQL Server Management Studio..."))
}
Loading
Loading