Skip to content

Commit 2c454b5

Browse files
Copilotshueybubbles
andcommitted
Add detection of redirected stdin for proper interactive mode detection
Co-authored-by: shueybubbles <[email protected]>
1 parent adff5ef commit 2c454b5

2 files changed

Lines changed: 85 additions & 1 deletion

File tree

cmd/sqlcmd/sqlcmd.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -717,8 +717,24 @@ func setConnect(connect *sqlcmd.ConnectSettings, args *SQLCmdArguments, vars *sq
717717
}
718718

719719
func isConsoleInitializationRequired(connect *sqlcmd.ConnectSettings, args *SQLCmdArguments) bool {
720+
// Password input always requires console initialization
721+
if connect.RequiresPassword() {
722+
return true
723+
}
724+
725+
// Check if stdin is from a terminal or a redirection
726+
file, err := os.Stdin.Stat()
727+
if err == nil {
728+
// If stdin is not a character device, it's coming from a pipe or redirect
729+
if (file.Mode() & os.ModeCharDevice) == 0 {
730+
// Non-interactive: stdin is redirected
731+
return false
732+
}
733+
}
734+
735+
// If we get here, stdin is from a terminal or we couldn't determine
720736
iactive := args.InputFile == nil && args.Query == "" && len(args.ChangePasswordAndExit) == 0
721-
return iactive || connect.RequiresPassword()
737+
return iactive
722738
}
723739

724740
func run(vars *sqlcmd.Variables, args *SQLCmdArguments) (int, error) {

cmd/sqlcmd/stdin_console_test.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT license.
3+
4+
package sqlcmd
5+
6+
import (
7+
"os"
8+
"testing"
9+
10+
"github.com/microsoft/go-sqlcmd/pkg/sqlcmd"
11+
"github.com/stretchr/testify/assert"
12+
)
13+
14+
func TestIsConsoleInitializationRequiredWithRedirectedStdin(t *testing.T) {
15+
// Create a temp file to simulate redirected stdin
16+
tempFile, err := os.CreateTemp("", "stdin-test-*.txt")
17+
if err != nil {
18+
t.Fatalf("Failed to create temp file: %v", err)
19+
}
20+
defer os.Remove(tempFile.Name())
21+
defer tempFile.Close()
22+
23+
// Write some data to it
24+
_, err = tempFile.WriteString("SELECT 1;\nGO\n")
25+
if err != nil {
26+
t.Fatalf("Failed to write to temp file: %v", err)
27+
}
28+
29+
// Remember the original stdin
30+
originalStdin := os.Stdin
31+
defer func() { os.Stdin = originalStdin }()
32+
33+
// Test with a file redirection
34+
stdinFile, err := os.Open(tempFile.Name())
35+
if err != nil {
36+
t.Fatalf("Failed to open temp file: %v", err)
37+
}
38+
defer stdinFile.Close()
39+
40+
// Replace stdin with our redirected file
41+
os.Stdin = stdinFile
42+
43+
// Set up a connect settings instance for SQL authentication
44+
connectConfig := sqlcmd.ConnectSettings{
45+
UserName: "testuser", // This will trigger SQL authentication, requiring a password
46+
}
47+
48+
// Test regular args
49+
args := &SQLCmdArguments{}
50+
51+
// Print file stat mode for debugging
52+
fileStat, _ := os.Stdin.Stat()
53+
t.Logf("File mode: %v", fileStat.Mode())
54+
t.Logf("Is character device: %v", (fileStat.Mode()&os.ModeCharDevice) != 0)
55+
t.Logf("Connection config: %+v", connectConfig)
56+
t.Logf("RequiresPassword() returns: %v", connectConfig.RequiresPassword())
57+
58+
// Test with SQL authentication that requires a password
59+
res := isConsoleInitializationRequired(&connectConfig, args)
60+
// Should be true since password is required, even with redirected stdin
61+
assert.True(t, res, "Console initialization should be required when SQL authentication is used")
62+
63+
// Now test with no authentication (no password required)
64+
connectConfig = sqlcmd.ConnectSettings{}
65+
res = isConsoleInitializationRequired(&connectConfig, args)
66+
// Should be false since stdin is redirected and no password is required
67+
assert.False(t, res, "Console initialization should not be required with redirected stdin and no password")
68+
}

0 commit comments

Comments
 (0)