Skip to content
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
de9d0c2
Initial plan
Copilot Jan 31, 2026
8ef7a8f
Add float64/float32 formatting to match ODBC sqlcmd behavior
Copilot Jan 31, 2026
5a4abc5
Remove binary from repo and update .gitignore
Copilot Jan 31, 2026
bb5d504
Fix trailing whitespace in test file
Copilot Jan 31, 2026
b1a3ced
Add hybrid float formatting: use 'f' format with fallback to 'g' for …
Copilot Feb 1, 2026
9a407bb
Enhance extreme values test to verify both e+ and e- notation
Copilot Feb 1, 2026
99f5b8d
Fix extreme values test and add REAL formatting test
Copilot Feb 1, 2026
ef8579c
Improve REAL formatting test assertions
Copilot Feb 1, 2026
c53be10
Fix test configuration issues
Copilot Feb 1, 2026
a3b7a26
Clean up code formatting in tests
Copilot Feb 1, 2026
6a8b162
Fix errcheck linting errors in test functions
Copilot Feb 2, 2026
635cb07
Fix float formatting to use DatabaseTypeName for bitSize and add conn…
Copilot Feb 2, 2026
38ac3ee
Improve float formatting to also handle SMALLMONEY as 32-bit
Copilot Feb 2, 2026
5a574a5
Fix fallback logic for displayWidth=0 and remove trailing whitespace
Copilot Feb 2, 2026
5194b35
Centralize float type default width constants
Copilot Feb 2, 2026
85c8c8b
Fix golangci-lint errcheck violations in commands.go
Copilot Feb 2, 2026
9f87576
Fix file handle cleanup and add displayWidth=0 test
Copilot Feb 2, 2026
9611e7b
Remove commented-out dead code in connectCommand
Copilot Feb 2, 2026
db681ab
Merge branch 'main' into copilot/fix-float-formatting-issue
dlevy-msft-sql Feb 5, 2026
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
9 changes: 9 additions & 0 deletions pkg/sqlcmd/format.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"errors"
"fmt"
"io"
"strconv"
"strings"
"time"

Expand Down Expand Up @@ -530,6 +531,14 @@ func (f *sqlCmdFormatterType) scanRow(rows *sql.Rows) ([]string, error) {
} else {
row[n] = "0"
}
case float64:
// Format float64 to match ODBC sqlcmd behavior
// Use 'f' format with -1 precision to avoid scientific notation
// and to show all significant digits
row[n] = strconv.FormatFloat(x, 'f', -1, 64)
case float32:
// Format float32 to match ODBC sqlcmd behavior
row[n] = strconv.FormatFloat(float64(x), 'f', -1, 32)
Comment thread
dlevy-msft-sql marked this conversation as resolved.
Outdated
default:
var err error
if row[n], err = fmt.Sprintf("%v", x), nil; err != nil {
Expand Down
36 changes: 36 additions & 0 deletions pkg/sqlcmd/format_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,3 +158,39 @@ func TestFormatterXmlMode(t *testing.T) {
assert.NoError(t, err, "runSqlCmd returned error")
assert.Equal(t, `<sys.databases name="master"/>`+SqlcmdEol, buf.buf.String())
}

func TestFormatterFloatFormatting(t *testing.T) {
// Test that float formatting matches ODBC sqlcmd behavior
// This addresses the issue where go-sqlcmd was using scientific notation
// while ODBC sqlcmd uses decimal notation
s, buf := setupSqlCmdWithMemoryOutput(t)
defer buf.Close()

// Test query with float values from the issue
query := `SELECT
CAST(788991.19988463481 AS FLOAT) as Longitude1,
CAST(4713347.3103808956 AS FLOAT) as Latitude1,
CAST(789288.40771771886 AS FLOAT) as Longitude2,
CAST(4712632.075629076 AS FLOAT) as Latitude2,
CAST(788569.36558582436 AS FLOAT) as Longitude3,
CAST(4714608.0418091472 AS FLOAT) as Latitude3`
Comment thread
dlevy-msft-sql marked this conversation as resolved.

err := runSqlCmd(t, s, []string{query, "GO"})
assert.NoError(t, err, "runSqlCmd returned error")

output := buf.buf.String()

// Verify that the output contains decimal notation, not scientific notation
// Scientific notation would look like "4.713347310380896e+06"
// Decimal notation should look like "4713347.3103808956"
assert.NotContains(t, output, "e+", "Output should not contain scientific notation (e+)")
assert.NotContains(t, output, "E+", "Output should not contain scientific notation (E+)")

// Verify that specific expected values are present (allowing for precision differences)
assert.Contains(t, output, "788991.1998846", "Output should contain decimal representation of Longitude1")
assert.Contains(t, output, "4713347.310380", "Output should contain decimal representation of Latitude1")
assert.Contains(t, output, "789288.4077177", "Output should contain decimal representation of Longitude2")
assert.Contains(t, output, "4712632.075629", "Output should contain decimal representation of Latitude2")
assert.Contains(t, output, "788569.3655858", "Output should contain decimal representation of Longitude3")
assert.Contains(t, output, "4714608.041809", "Output should contain decimal representation of Latitude3")
}
Loading