Skip to content

Commit 3ba1c37

Browse files
authored
Add errors for mutually exclusive parameters (#388)
1 parent 208a6b2 commit 3ba1c37

File tree

15 files changed

+1497
-1078
lines changed

15 files changed

+1497
-1078
lines changed

build/build.cmd

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@ for /f %%i in ('"git describe --tags --abbrev=0"') do set sqlcmdVersion=%%i
1111

1212
setlocal
1313
SET RED=%ESC%[1;31m
14-
echo %RED%
14+
@echo %RED%
1515
REM run the custom sqlcmd linter for code style enforcement
1616
REM using for/do instead of running it directly so the status code isn't checked by the shell.
1717
REM Once we are prepared to block the build with the linter we will move this step into a pipeline
18-
for /F "usebackq" %%l in (`go run cmd\sqlcmd-linter\main.go -test %~dp0../...`) DO echo %%l
19-
echo %ESC%[0m
18+
@for /F "usebackq" %%l in (`go run cmd\sqlcmd-linter\main.go -test %~dp0../...`) DO echo %%l
19+
@echo %ESC%[0m
2020

2121
if not exist %gopath%\bin\go-winres.exe (
2222
go install github.com/tc-hib/go-winres@latest
@@ -30,13 +30,17 @@ del %~dp0..\cmd\modern\*.syso
3030

3131
REM generates translations file and resources
3232
go generate %~dp0../... 2> %~dp0generate.txt
33+
if NOT ERRORLEVEL 0 (
34+
type %~dp0generate.txt
35+
goto :end
36+
) else (
3337
echo Fix any conflicting localizable strings:
34-
echo %RED%
35-
findstr conflicting "%~dp0generate.txt"
36-
echo %ESC%[0m
38+
@echo %RED%
39+
@findstr conflicting "%~dp0generate.txt"
40+
@echo %ESC%[0m
41+
)
3742
endlocal
3843

39-
if not %errorlevel% == 0 goto :end
4044
REM Generates sqlcmd.exe in the root dir of the repo
4145
go build -o %~dp0..\sqlcmd.exe -ldflags="-X main.version=%sqlcmdVersion%" %~dp0..\cmd\modern
4246

cmd/sqlcmd/sqlcmd.go

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ type SQLCmdArguments struct {
6767
MultiSubnetFailover bool
6868
Password string
6969
DedicatedAdminConnection bool
70+
ListServers bool
7071
// Keep Help at the end of the list
7172
Help bool
7273
}
@@ -84,18 +85,33 @@ const (
8485

8586
// Validate arguments for settings not describe
8687
func (a *SQLCmdArguments) Validate(c *cobra.Command) (err error) {
87-
switch {
88-
case a.PacketSize != 0 && (a.PacketSize < 512 || a.PacketSize > 32767):
89-
err = localizer.Errorf(`'-a %d': Packet size has to be a number between 512 and 32767.`, a.PacketSize)
90-
// Ignore 0 even though it's technically an invalid input
91-
case a.Headers < -1:
92-
err = localizer.Errorf(`'-h %d': header value must be either -1 or a value between 1 and 2147483647`, a.Headers)
93-
case a.ScreenWidth != nil && (*a.ScreenWidth < 9 || *a.ScreenWidth > 65535):
94-
err = rangeParameterError("-w", fmt.Sprint(*a.ScreenWidth), 8, 65536, false)
95-
case a.FixedTypeWidth != nil && (*a.FixedTypeWidth < 0 || *a.FixedTypeWidth > 8000):
96-
err = rangeParameterError("-Y", fmt.Sprint(*a.FixedTypeWidth), 0, 8000, true)
97-
case a.VariableTypeWidth != nil && (*a.VariableTypeWidth < 0 || *a.VariableTypeWidth > 8000):
98-
err = rangeParameterError("-y", fmt.Sprint(*a.VariableTypeWidth), 0, 8000, true)
88+
if a.ListServers {
89+
c.Flags().Visit(func(f *pflag.Flag) {
90+
if f.Shorthand != "L" {
91+
err = localizer.Errorf("The -L parameter can not be used in combination with other parameters.")
92+
}
93+
})
94+
}
95+
if err == nil {
96+
switch {
97+
case len(a.InputFile) > 0 && (len(a.Query) > 0 || len(a.InitialQuery) > 0):
98+
err = mutuallyExclusiveError("i", `-Q/-q`)
99+
case a.UseTrustedConnection && (len(a.UserName) > 0 || len(a.Password) > 0):
100+
err = mutuallyExclusiveError("-E", `-U/-P`)
101+
case a.UseAad && len(a.AuthenticationMethod) > 0:
102+
err = mutuallyExclusiveError("-G", "--authentication-method")
103+
case a.PacketSize != 0 && (a.PacketSize < 512 || a.PacketSize > 32767):
104+
err = localizer.Errorf(`'-a %#v': Packet size has to be a number between 512 and 32767.`, a.PacketSize)
105+
// Ignore 0 even though it's technically an invalid input
106+
case a.Headers < -1:
107+
err = localizer.Errorf(`'-h %#v': header value must be either -1 or a value between 1 and 2147483647`, a.Headers)
108+
case a.ScreenWidth != nil && (*a.ScreenWidth < 9 || *a.ScreenWidth > 65535):
109+
err = rangeParameterError("-w", fmt.Sprint(*a.ScreenWidth), 8, 65536, false)
110+
case a.FixedTypeWidth != nil && (*a.FixedTypeWidth < 0 || *a.FixedTypeWidth > 8000):
111+
err = rangeParameterError("-Y", fmt.Sprint(*a.FixedTypeWidth), 0, 8000, true)
112+
case a.VariableTypeWidth != nil && (*a.VariableTypeWidth < 0 || *a.VariableTypeWidth > 8000):
113+
err = rangeParameterError("-y", fmt.Sprint(*a.VariableTypeWidth), 0, 8000, true)
114+
}
99115
}
100116
if err != nil {
101117
c.PrintErrln(sqlcmdErrorPrefix + err.Error())
@@ -154,6 +170,13 @@ func Execute(version string) {
154170
return nil
155171
},
156172
Run: func(cmd *cobra.Command, argss []string) {
173+
// emulate -L returning no servers
174+
if args.ListServers {
175+
fmt.Println()
176+
fmt.Println(localizer.Sprintf("Servers:"))
177+
fmt.Println(" ;UID:Login ID=?;PWD:Password=?;Trusted_Connection:Use Integrated Security=?;*APP:AppName=?;*WSID:WorkStation ID=?;")
178+
os.Exit(0)
179+
}
157180
if len(argss) > 0 {
158181
fmt.Printf("%s'%s': Unknown command. Enter '--help' for command help.", sqlcmdErrorPrefix, argss[0])
159182
os.Exit(1)
@@ -294,6 +317,7 @@ func setFlags(rootCmd *cobra.Command, args *SQLCmdArguments) {
294317
_ = rootCmd.Flags().IntP(screenWidth, "w", 0, localizer.Sprintf("Specifies the screen width for output"))
295318
_ = rootCmd.Flags().IntP(variableTypeWidth, "y", 256, setScriptVariable("SQLCMDMAXVARTYPEWIDTH"))
296319
_ = rootCmd.Flags().IntP(fixedTypeWidth, "Y", 0, setScriptVariable("SQLCMDMAXFIXEDTYPEWIDTH"))
320+
rootCmd.Flags().BoolVarP(&args.ListServers, "list-servers", "L", false, "List servers")
297321
rootCmd.Flags().BoolVarP(&args.DedicatedAdminConnection, "dedicated-admin-connection", "A", false, localizer.Sprintf("Dedicated administrator connection"))
298322
}
299323

@@ -372,6 +396,10 @@ func invalidParameterError(flag string, value string, allowedValues ...string) e
372396
return localizer.Errorf("'%s %s': Unexpected argument. Argument value has to be one of %v.", flag, value, allowedValues)
373397
}
374398

399+
func mutuallyExclusiveError(flag1 string, flag2 string) error {
400+
return localizer.Errorf("The %s and the %s options are mutually exclusive.", flag1, flag2)
401+
}
402+
375403
func flagErrorHandler(c *cobra.Command, err error) (e error) {
376404
c.SilenceUsage = true
377405
c.SilenceErrors = true

cmd/sqlcmd/sqlcmd_test.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,9 @@ func TestInvalidCommandLine(t *testing.T) {
124124
}
125125

126126
commands := []cmdLineTest{
127-
// Issue:341 https://github.com/microsoft/go-sqlcmd/issues/341
128-
//{[]string{"-E", "-U", "someuser"}, "--use-trusted-connection and --user-name can't be used together"},
127+
{[]string{"-E", "-U", "someuser"}, "The -E and the -U/-P options are mutually exclusive."},
128+
{[]string{"-L", "-q", `"select 1"`}, "The -L parameter can not be used in combination with other parameters."},
129+
{[]string{"-i", "foo.sql", "-q", `"select 1"`}, "The i and the -Q/-q options are mutually exclusive."},
129130
{[]string{"-F", "what"}, "'-F what': Unexpected argument. Argument value has to be one of [horiz horizontal vert vertical]."},
130131
{[]string{"-r", "5"}, `'-r 5': Unexpected argument. Argument value has to be one of [0 1].`},
131132
{[]string{"-w", "x"}, "'-w x': value must be greater than 8 and less than 65536."},
@@ -158,9 +159,10 @@ func TestInvalidCommandLine(t *testing.T) {
158159
setFlags(cmd, arguments)
159160
cmd.SetArgs(test.commandLine)
160161
err := cmd.Execute()
161-
assert.EqualError(t, err, test.errorMessage, "Command line:", test.commandLine)
162-
errBytes := buf.buf.String()
163-
assert.Equalf(t, sqlcmdErrorPrefix, string(errBytes)[:len(sqlcmdErrorPrefix)], "Output error should start with '%s' - %s", sqlcmdErrorPrefix, test.commandLine)
162+
if assert.EqualErrorf(t, err, test.errorMessage, "Command line: %s", test.commandLine) {
163+
errBytes := buf.buf.String()
164+
assert.Equalf(t, sqlcmdErrorPrefix, string(errBytes)[:len(sqlcmdErrorPrefix)], "Output error should start with '%s' but got '%s' - %s", sqlcmdErrorPrefix, string(errBytes), test.commandLine)
165+
}
164166
}
165167
}
166168

0 commit comments

Comments
 (0)