Skip to content

Commit b1a3ced

Browse files
Add hybrid float formatting: use 'f' format with fallback to 'g' for extreme values
Co-authored-by: dlevy-msft-sql <[email protected]>
1 parent bb5d504 commit b1a3ced

2 files changed

Lines changed: 39 additions & 4 deletions

File tree

pkg/sqlcmd/format.go

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -533,12 +533,26 @@ func (f *sqlCmdFormatterType) scanRow(rows *sql.Rows) ([]string, error) {
533533
}
534534
case float64:
535535
// Format float64 to match ODBC sqlcmd behavior
536-
// Use 'f' format with -1 precision to avoid scientific notation
537-
// and to show all significant digits
538-
row[n] = strconv.FormatFloat(x, 'f', -1, 64)
536+
// Use 'f' format with -1 precision to avoid scientific notation for typical values
537+
// Fall back to 'g' format if the result would exceed the column display width
538+
formatted := strconv.FormatFloat(x, 'f', -1, 64)
539+
displayWidth := f.columnDetails[n].displayWidth
540+
if displayWidth > 0 && int64(len(formatted)) > displayWidth {
541+
// Use 'g' format for very large/small values to avoid truncation issues
542+
formatted = strconv.FormatFloat(x, 'g', -1, 64)
543+
}
544+
row[n] = formatted
539545
case float32:
540546
// Format float32 to match ODBC sqlcmd behavior
541-
row[n] = strconv.FormatFloat(float64(x), 'f', -1, 32)
547+
// Use 'f' format with -1 precision to avoid scientific notation for typical values
548+
// Fall back to 'g' format if the result would exceed the column display width
549+
formatted := strconv.FormatFloat(float64(x), 'f', -1, 32)
550+
displayWidth := f.columnDetails[n].displayWidth
551+
if displayWidth > 0 && int64(len(formatted)) > displayWidth {
552+
// Use 'g' format for very large/small values to avoid truncation issues
553+
formatted = strconv.FormatFloat(float64(x), 'g', -1, 32)
554+
}
555+
row[n] = formatted
542556
default:
543557
var err error
544558
if row[n], err = fmt.Sprintf("%v", x), nil; err != nil {

pkg/sqlcmd/format_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,3 +194,24 @@ func TestFormatterFloatFormatting(t *testing.T) {
194194
assert.Contains(t, output, "788569.3655858", "Output should contain decimal representation of Longitude3")
195195
assert.Contains(t, output, "4714608.041809", "Output should contain decimal representation of Latitude3")
196196
}
197+
198+
func TestFormatterFloatFormattingExtremeValues(t *testing.T) {
199+
// Test that extreme float values fall back to scientific notation
200+
// to avoid truncation issues with very large or very small numbers
201+
s, buf := setupSqlCmdWithMemoryOutput(t)
202+
defer buf.Close()
203+
204+
// Test query with extreme float values that would exceed the 24-char display width
205+
query := `SELECT
206+
CAST(1e100 AS FLOAT) as VeryLarge,
207+
CAST(1e-100 AS FLOAT) as VerySmall`
208+
209+
err := runSqlCmd(t, s, []string{query, "GO"})
210+
assert.NoError(t, err, "runSqlCmd returned error")
211+
212+
output := buf.buf.String()
213+
214+
// Verify that extremely large/small values use scientific notation
215+
// (because decimal format would exceed the 24-char column width)
216+
assert.Contains(t, output, "e+", "Output should contain scientific notation for extreme values")
217+
}

0 commit comments

Comments
 (0)