Skip to content

Commit a4dd987

Browse files
Address Copilot review: add integration test and docs
- Add TestExitCommandMultiLineInteractive: exercises the full multi-line EXIT flow with real database connection (unbalanced parens -> read continuation -> execute query -> verify exit code) - Add 'Interactive Mode Commands' section to README with EXIT examples showing both single-line and multi-line usage with continuation prompt
1 parent a2b558f commit a4dd987

2 files changed

Lines changed: 56 additions & 0 deletions

File tree

README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,24 @@ sqlcmd
112112

113113
If no current context exists, `sqlcmd` (with no connection parameters) reverts to the original ODBC `sqlcmd` behavior of creating an interactive session to the default local instance on port 1433 using trusted authentication, otherwise it will create an interactive session to the current context.
114114

115+
### Interactive Mode Commands
116+
117+
In interactive mode, `sqlcmd` supports several special commands. The `EXIT` command can execute a query and use its result as the exit code:
118+
119+
```
120+
1> EXIT(SELECT 100)
121+
```
122+
123+
For complex queries, `EXIT(query)` can span multiple lines. When parentheses are unbalanced, `sqlcmd` prompts for continuation:
124+
125+
```
126+
1> EXIT(SELECT 1
127+
-> + 2
128+
-> + 3)
129+
```
130+
131+
The query result (6 in this example) becomes the process exit code.
132+
115133
## Sqlcmd
116134

117135
The `sqlcmd` project aims to be a complete port of the original ODBC sqlcmd to the `Go` language, utilizing the [go-mssqldb][] driver. For full documentation of the tool and installation instructions, see [go-sqlcmd-utility][].

pkg/sqlcmd/commands_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -632,3 +632,41 @@ func TestExitCommandNonInteractiveUnbalanced(t *testing.T) {
632632
err := exitCommand(s, []string{"(select 1"}, 1)
633633
assert.EqualError(t, err, InvalidCommandError("EXIT", 1).Error(), "unbalanced parens in non-interactive should error")
634634
}
635+
636+
// TestExitCommandMultiLineInteractive is an integration test that exercises the full
637+
// multi-line EXIT flow: starting with unbalanced parentheses, reading continuation lines
638+
// from the console, executing the combined query, and returning the correct exit code.
639+
func TestExitCommandMultiLineInteractive(t *testing.T) {
640+
s, buf := setupSqlCmdWithMemoryOutput(t)
641+
defer buf.Close()
642+
643+
// Set up mock console to provide continuation lines
644+
continuationLines := []string{"+ 2", ")"}
645+
lineIndex := 0
646+
s.lineIo = &testConsole{
647+
OnReadLine: func() (string, error) {
648+
if lineIndex >= len(continuationLines) {
649+
return "", io.EOF
650+
}
651+
line := continuationLines[lineIndex]
652+
lineIndex++
653+
return line, nil
654+
},
655+
OnPasswordPrompt: func(prompt string) ([]byte, error) {
656+
return nil, nil
657+
},
658+
}
659+
660+
// Initialize batch so exitCommand can work with it
661+
s.batch = NewBatch(nil, nil)
662+
663+
// Call exitCommand with unbalanced parentheses - this should:
664+
// 1. Detect unbalanced parens in "(select 1"
665+
// 2. Read continuation lines "+ 2" and ")" from the mock console
666+
// 3. Combine into "(select 1\r\n+ 2\r\n)" and execute
667+
// 4. Return ErrExitRequested with Exitcode set to 3 (1+2)
668+
err := exitCommand(s, []string{"(select 1"}, 1)
669+
670+
assert.Equal(t, ErrExitRequested, err, "exitCommand should return ErrExitRequested")
671+
assert.Equal(t, 3, s.Exitcode, "Exitcode should be 3 (result of 'select 1 + 2')")
672+
}

0 commit comments

Comments
 (0)