Skip to content

Conversation

@dlevy-msft-sql
Copy link
Contributor

@dlevy-msft-sql dlevy-msft-sql commented Jan 25, 2026

Summary

Implements the -R flag to enable locale-aware formatting for output, matching ODBC sqlcmd behavior.

Changes

  • Add RegionalSettings struct with locale-aware formatting methods
  • Detect user locale from Windows LCID or Unix environment variables (LC_ALL, LC_MESSAGES, LANG)
  • Apply regional formatting to:
    • DECIMAL/NUMERIC: Numbers with locale-specific thousand separators
    • MONEY/SMALLMONEY: Currency with locale-specific thousand separators
    • DATE: Locale-specific date format (e.g., MM/DD/YYYY for en-US, DD/MM/YYYY for en-GB)
    • TIME/DATETIME/DATETIME2/DATETIMEOFFSET: Locale-specific time format (12/24 hour)
  • Add comprehensive tests for regional formatting
  • Update README to document the -R flag behavior

Usage

# Enable regional formatting based on system locale
sqlcmd -S server -R -Q "SELECT GETDATE(), 1234.56"

Motivation

Customers migrating from ODBC sqlcmd expect the -R flag to produce locale-aware output. Previously this was a no-op stub.

Testing

  • Added unit tests for all formatting functions
  • All existing tests pass

- Add -f/--code-page flag with ODBC-compatible format parsing

- Support 50+ codepages: Unicode, Windows, OEM/DOS, ISO-8859, CJK, EBCDIC, Macintosh

- Apply input codepage in IncludeFile() for :r command

- Apply output codepage in outCommand() for :OUT file writes

- Add --list-codepages flag to display all supported codepages

- Add comprehensive unit tests for parsing and encoding lookup
- Add RegionalSettings struct with locale-aware formatting for numbers,
  currency, dates, and times
- Detect user locale from Windows LCID or Unix environment variables
- Apply regional formatting to DECIMAL, NUMERIC, MONEY, SMALLMONEY,
  DATE, TIME, DATETIME, DATETIME2, DATETIMEOFFSET types
- Add comprehensive tests for regional formatting
- Update README to document the -R flag behavior

This enables customers migrating from ODBC sqlcmd to see the same
locale-aware output formatting when using the -R flag.
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements locale-aware formatting for query results when -R is specified and introduces configurable code page handling for input/output, plus associated CLI flags and documentation updates.

Changes:

  • Add RegionalSettings with platform-specific locale detection (detectUserLocale) and integrate it into the default formatter so that -R controls locale-aware numeric and date/time formatting.
  • Introduce code page parsing and encoding support (ParseCodePage, GetEncoding, SupportedCodePages) and wire it into file input (:R), output (:OUT, :ERROR), and new CLI flags -f/--code-page and --list-codepages.
  • Extend tests to cover regional formatting helpers, formatter construction, code page parsing/encoding, CLI argument parsing/validation, and document new -R and -f behaviors in README.md.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
pkg/sqlcmd/sqlcmd.go Adds CodePage *CodePageSettings to Sqlcmd and updates IncludeFile to honor configured input code pages or BOM-based UTF-16 auto-detection when reading :R files.
pkg/sqlcmd/regional.go Implements RegionalSettings (locale detection via detectUserLocale), number/money/date/time formatting, and locale-specific separators and date/time layouts.
pkg/sqlcmd/regional_windows.go Windows-only locale detection using GetUserDefaultLCID and a mapping from LCID values to BCP 47 language tags.
pkg/sqlcmd/regional_linux.go Linux-only locale detection from LC_ALL, LC_MESSAGES, and LANG, plus Unix locale string parsing to BCP 47 tags.
pkg/sqlcmd/regional_darwin.go macOS-only locale detection using environment variables or defaults read -g AppleLocale, with Unix locale parsing similar to Linux.
pkg/sqlcmd/regional_test.go Unit tests for RegionalSettings enable/disable behavior, NULL/empty handling, separators, date/time format selection, helper functions, and basic formatter construction with/without regional settings.
pkg/sqlcmd/format.go Extends sqlCmdFormatterType with a regional *RegionalSettings field, adds NewSQLCmdDefaultFormatterWithRegional, and applies regional formatting to numeric and date/time columns in scanRow when -R is enabled.
pkg/sqlcmd/commands.go Updates :OUT and :ERROR commands to write using either UTF-16 (for -u) or a configured output code page via GetEncoding, falling back to raw UTF-8 when appropriate.
pkg/sqlcmd/codepage.go Adds CodePageSettings, ParseCodePage for -f syntax, GetEncoding for many Windows and related code pages, and SupportedCodePages metadata for listing.
pkg/sqlcmd/codepage_test.go Tests ParseCodePage (including error cases and specific code pages) and GetEncoding for successful encodings and error handling for unsupported code pages.
cmd/sqlcmd/sqlcmd.go Extends SQLCmdArguments with CodePage, ListCodePages, and UseRegionalSettings, validates -f, adds --code-page, --list-codepages, and -R flag wiring, lists supported code pages when requested, parses code page settings before running, and uses NewSQLCmdDefaultFormatterWithRegional to honor -R.
cmd/sqlcmd/sqlcmd_test.go Adds CLI argument parsing tests for -f variations and --list-codepages, plus invalid -f cases that exercise Validate; reuses existing test harness for command-line normalization and error formatting.
README.md Updates the description of -R to reflect new locale-aware formatting behavior and documents the new -f code page option and --list-codepages helper, including examples of supported code pages.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

- Fix nil encoder panic in errorCommand when using UTF-8 codepage
- Improve error handling with proper file close on encoding error
- Remove dead code (unused 'err' variable) in format.go
- Add missing -R flag test in TestValidCommandLineToArgsConversion
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated 2 comments.

Removes float64 parsing to preserve precision for DECIMAL(38,s) values.
FormatNumber now uses pure string manipulation with addThousandSeparators
and getDecimalSeparator, avoiding any potential precision loss.
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated 1 comment.

- Fix FormatMoney to use string manipulation instead of float64
  to preserve precision for large MONEY/SMALLMONEY values
- Improve test naming in TestGetEncoding to use cp_<number> format
  for better readability when tests fail
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated no new comments.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated 3 comments.

Comment on lines 24 to 32
// NewRegionalSettings creates a new RegionalSettings instance
// If enabled is false, all format methods return values unchanged
func NewRegionalSettings(enabled bool) *RegionalSettings {
r := &RegionalSettings{enabled: enabled}
if enabled {
r.tag = detectUserLocale()
r.printer = message.NewPrinter(r.tag)
r.dateFmt, r.timeFmt = getLocaleDateTimeFormats(r.tag)
}
Copy link

Copilot AI Jan 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NewRegionalSettings calls detectUserLocale, but this function is only implemented in regional_windows.go, regional_linux.go, and regional_darwin.go using GOOS-specific build tags. On other platforms (for example freebsd or openbsd), this package will fail to compile because detectUserLocale has no definition. Consider adding a fallback implementation in a regional_other.go file with a complementary build tag (e.g. //go:build !windows && !linux && !darwin) that returns a sensible default like language.English so cross-compilation and tests on non-main platforms continue to work.

Copilot uses AI. Check for mistakes.
@dlevy-msft-sql dlevy-msft-sql self-assigned this Jan 25, 2026
@dlevy-msft-sql dlevy-msft-sql added sqlcmd switch switch in existing sqlcmd Size: S Small issue (less than one week effort) labels Jan 25, 2026
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated no new comments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Size: S Small issue (less than one week effort) sqlcmd switch switch in existing sqlcmd

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant