Skip to content

Commit b7c3c88

Browse files
authored
initial support for UTF16 input files (#83)
1 parent 7bd70e5 commit b7c3c88

File tree

7 files changed

+70
-1
lines changed

7 files changed

+70
-1
lines changed

cmd/sqlcmd/main_test.go

+49
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,55 @@ func TestUnicodeOutput(t *testing.T) {
179179
}
180180
}
181181

182+
func TestUnicodeInput(t *testing.T) {
183+
testfiles := []string{
184+
`testdata/selectutf8.txt`,
185+
`testdata/selectutf8_bom.txt`,
186+
`testdata/selectunicode_BE.txt`,
187+
`testdata/selectunicode_LE.txt`,
188+
}
189+
190+
for _, test := range testfiles {
191+
for _, unicodeOutput := range []bool{true, false} {
192+
var outfile string
193+
if unicodeOutput {
194+
outfile = `testdata/unicodeout_linux.txt`
195+
if runtime.GOOS == "windows" {
196+
outfile = `testdata/unicodeout.txt`
197+
}
198+
} else {
199+
outfile = `testdata/utf8out_linux.txt`
200+
if runtime.GOOS == "windows" {
201+
outfile = `testdata/utf8out.txt`
202+
}
203+
}
204+
o, err := os.CreateTemp("", "sqlcmdmain")
205+
assert.NoError(t, err, "os.CreateTemp")
206+
defer os.Remove(o.Name())
207+
defer o.Close()
208+
args = newArguments()
209+
args.InputFile = []string{test}
210+
args.OutputFile = o.Name()
211+
args.UnicodeOutputFile = unicodeOutput
212+
if canTestAzureAuth() {
213+
args.UseAad = true
214+
}
215+
vars := sqlcmd.InitializeVariables(!args.DisableCmdAndWarn)
216+
setVars(vars, &args)
217+
exitCode, err := run(vars, &args)
218+
assert.NoError(t, err, "run")
219+
assert.Equal(t, 0, exitCode, "exitCode")
220+
bytes, err := os.ReadFile(o.Name())
221+
if assert.NoError(t, err, "os.ReadFile") {
222+
expectedBytes, err := os.ReadFile(outfile)
223+
if assert.NoErrorf(t, err, "Unable to open %s", outfile) {
224+
assert.Equalf(t, expectedBytes, bytes, "input file: <%s> output bytes should match <%s>", test, outfile)
225+
}
226+
}
227+
}
228+
}
229+
}
230+
182231
func TestQueryAndExit(t *testing.T) {
183232
o, err := os.CreateTemp("", "sqlcmdmain")
184233
assert.NoError(t, err, "os.CreateTemp")
88 Bytes
Binary file not shown.
88 Bytes
Binary file not shown.
+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
select N'挨挨唉哀皑癌蔼矮' as SimplifiedChinese
2+

cmd/sqlcmd/testdata/utf8out.txt

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
SimplifiedChinese
2+
-----------------
3+
挨挨唉哀皑癌蔼矮
4+
5+
(1 row affected)

cmd/sqlcmd/testdata/utf8out_linux.txt

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
SimplifiedChinese
2+
-----------------
3+
挨挨唉哀皑癌蔼矮
4+
5+
(1 row affected)

pkg/sqlcmd/sqlcmd.go

+9-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ import (
2121
mssql "github.com/denisenkom/go-mssqldb"
2222
"github.com/denisenkom/go-mssqldb/msdsn"
2323
"github.com/golang-sql/sqlexp"
24+
"golang.org/x/text/encoding/unicode"
25+
"golang.org/x/text/transform"
2426
)
2527

2628
var (
@@ -32,6 +34,8 @@ var (
3234
ErrCtrlC = errors.New(WarningPrefix + "The last operation was terminated because the user pressed CTRL+C")
3335
)
3436

37+
const maxLineBuffer = 2 * 1024 * 1024 // 2Mb
38+
3539
// Console defines methods used for console input and output
3640
type Console interface {
3741
// Readline returns the next line of input.
@@ -284,7 +288,11 @@ func (s *Sqlcmd) IncludeFile(path string, processAll bool) error {
284288
}
285289
defer f.Close()
286290
b := s.batch.batchline
287-
scanner := bufio.NewScanner(f)
291+
utf16bom := unicode.BOMOverride(unicode.UTF8.NewDecoder())
292+
unicodeReader := transform.NewReader(f, utf16bom)
293+
scanner := bufio.NewScanner(unicodeReader)
294+
buf := make([]byte, maxLineBuffer)
295+
scanner.Buffer(buf, maxLineBuffer)
288296
curLine := s.batch.read
289297
s.batch.read = func() (string, error) {
290298
if !scanner.Scan() {

0 commit comments

Comments
 (0)