feat: implement -j raw-errors flag for ODBC sqlcmd compatibility#759
feat: implement -j raw-errors flag for ODBC sqlcmd compatibility#759dlevy-msft-sql wants to merge 10 commits into
Conversation
Adds the -j / --raw-errors flag to the legacy sqlcmd CLI, mirroring the ODBC sqlcmd's m_PrintRawErrorMessages behavior (Sql/utils/sqlcmd/console/src/Formatter.cpp). When set, the driver-supplied 'mssql: ' prefix is preserved in error output; the Msg/Level/State/Server header and screen-width wrapping are unaffected, matching ODBC sqlcmd which also only gates the prefix strip. Closes the -j gap tracked in discussion microsoft#292.
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Adds ODBC-compatible -j/--raw-errors support so go-sqlcmd can optionally preserve the go-mssqldb "mssql: " error prefix, improving parity with ODBC sqlcmd behavior.
Changes:
- Extend the default formatter with a functional-options pattern and a
WithRawErrorsoption. - Gate stripping of the
"mssql: "prefix inAddErrorbased on the new option. - Wire
-j/--raw-errorsthrough CLI args and add targeted test coverage.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| pkg/sqlcmd/format.go | Adds rawErrors option plumbing and gates mssql: prefix trimming in AddError. |
| pkg/sqlcmd/format_test.go | Adds coverage validating prefix stripping behavior in default vs raw modes. |
| cmd/sqlcmd/sqlcmd.go | Introduces RawErrors CLI flag and passes formatter option through. |
| cmd/sqlcmd/sqlcmd_test.go | Adds CLI parsing test for -j. |
Comments suppressed due to low confidence (1)
pkg/sqlcmd/format.go:1
- The docstring is internally inconsistent: it describes the prefix as "driver-supplied" while also stating it is prepended by
go-mssqldb. Consider rewording to clarify that-jpreserves thego-mssqldb-added prefix (or more generally, preserves the error string exactly as returned by the Go driver) to avoid confusing API consumers.
// Copyright (c) Microsoft Corporation.
|
Took the docstring feedback as well — reworded both the |
| rootCmd.Flags().IntVar(&args.DriverLoggingLevel, "driver-logging-level", 0, localizer.Sprintf("Level of mssql driver messages to print")) | ||
| rootCmd.Flags().BoolVarP(&args.ExitOnError, "exit-on-error", "b", false, localizer.Sprintf("Specifies that sqlcmd exits and returns a %s value when an error occurs", localizer.DosErrorLevel)) | ||
| rootCmd.Flags().IntVarP(&args.ErrorLevel, "error-level", "m", 0, localizer.Sprintf("Controls which error messages are sent to %s. Messages that have severity level greater than or equal to this level are sent", localizer.StdoutName)) | ||
| rootCmd.Flags().BoolVarP(&args.RawErrors, "raw-errors", "j", false, localizer.Sprintf("Do not strip the \"mssql: \" prefix from error messages")) |
There was a problem hiding this comment.
Going to push back on this one, similar to the test-coupling thread above.
The whole point of CLI flag help is to let a user predict the concrete diff they'll see in their output. With -j set, every error line will literally contain mssql: where it wouldn't otherwise; that's user-observable text, not implementation. Replacing the concrete string with abstract phrasing like "preserve raw driver error text" makes the help less actionable — a user reading it can't tell what -j will actually change in their terminal.
format.go hardcodes strings.TrimPrefix(msg, "mssql: ") against that exact literal. If go-mssqldb ever changes its prefix format, the gate, the help text, and the tests all need to update together — that coupling is intentional and consistent with how the rest of the flag help in this file describes concrete behavior (see -b, -h, etc.).
Problem
go-sqlcmddid not implement the-jswitch from the ODBC-basedsqlcmd, which is required to preserve raw driver-supplied error text. This was tracked in discussion #292 as a gap blocking ODBCsqlcmdretirement.Root Cause
The default formatter (
pkg/sqlcmd/format.go) unconditionally stripped the"mssql: "prefix thatgo-mssqldbprepends to everymssql.Error.Error()string. There was no way for a caller to opt out, and no CLI flag exposed the behavior.Solution
Implement
-j/--raw-errorswith semantics that match the ODBC reference (Sql/utils/sqlcmd/console/src/Formatter.cpp, gated onm_PrintRawErrorMessages):-jis set, the driver-supplied prefix is preserved verbatim.Msg N, Level N, State N, Server S, Line Nheader is always emitted (matches ODBC).fitToScreenis always applied (matches ODBC).The formatter is extended via a non-breaking variadic functional-options pattern, so existing callers (including
internal/sql/mssql.go) compile unchanged.Changes
pkg/sqlcmd/format.gorawErrorsfield,FormatterOptiontype,WithRawErrors; gatestrings.TrimPrefix(msg, "mssql: ")inAddError.pkg/sqlcmd/format_test.goTestAddErrorStripsMssqlPrefixByDefaultandTestAddErrorWithRawErrorsKeepsMssqlPrefix— two parallel tests, each readable end-to-end, covering both gate states.cmd/sqlcmd/sqlcmd.goRawErrorstoSQLCmdArguments; register-j/--raw-errors; passWithRawErrorsinto the formatter.cmd/sqlcmd/sqlcmd_test.go-jcase toTestValidCommandLineToArgsConversion.Testing
go build ./...clean.go vet ./...clean (only pre-existing credman warnings onwindows/v0.21.0).go test ./pkg/sqlcmd/ ./cmd/sqlcmd/ -count=1against a live SQL Server: PASS.TestAddError…tests assert the header and message body appear in both modes and that the"mssql: "prefix is stripped exactly when-jis unset (would fail in either direction if the gate logic regressed).Related Issues
Closes the
-jgap in discussion #292.