Skip to content

Commit f58da1a

Browse files
authored
Fix: Use proper reader for long file lines (#441)
1 parent ba1a16d commit f58da1a

File tree

2 files changed

+34
-15
lines changed

2 files changed

+34
-15
lines changed

pkg/sqlcmd/sqlcmd.go

+18-15
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,6 @@ var (
3939
}
4040
)
4141

42-
const maxLineBuffer = 2 * 1024 * 1024 // 2Mb
43-
4442
// Console defines methods used for console input and output
4543
type Console interface {
4644
// Readline returns the next line of input.
@@ -327,24 +325,29 @@ func (s *Sqlcmd) IncludeFile(path string, processAll bool) error {
327325
b := s.batch.batchline
328326
utf16bom := unicode.BOMOverride(unicode.UTF8.NewDecoder())
329327
unicodeReader := transform.NewReader(f, utf16bom)
330-
scanner := bufio.NewScanner(unicodeReader)
331-
buf := make([]byte, maxLineBuffer)
332-
scanner.Buffer(buf, maxLineBuffer)
328+
scanner := bufio.NewReader(unicodeReader)
333329
curLine := s.batch.read
334330
echoFileLines := s.echoFileLines
331+
ln := make([]byte, 0, 2*1024*1024)
335332
s.batch.read = func() (string, error) {
336-
if !scanner.Scan() {
337-
err := scanner.Err()
338-
if err == nil {
339-
return "", io.EOF
340-
}
341-
return "", err
333+
var (
334+
isPrefix bool = true
335+
err error = nil
336+
line []byte
337+
)
338+
339+
for isPrefix && err == nil {
340+
line, isPrefix, err = scanner.ReadLine()
341+
ln = append(ln, line...)
342342
}
343-
t := scanner.Text()
344-
if echoFileLines {
345-
_, _ = s.GetOutput().Write([]byte(s.Prompt() + t + SqlcmdEol))
343+
if err == nil && echoFileLines {
344+
_, _ = s.GetOutput().Write([]byte(s.Prompt()))
345+
_, _ = s.GetOutput().Write(ln)
346+
_, _ = s.GetOutput().Write([]byte(SqlcmdEol))
346347
}
347-
return t, nil
348+
t := string(ln)
349+
ln = ln[:0]
350+
return t, err
348351
}
349352
err = s.Run(false, processAll)
350353
s.batch.read = curLine

pkg/sqlcmd/sqlcmd_test.go

+16
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,22 @@ func TestSqlCmdOutputAndError(t *testing.T) {
549549
}
550550
}
551551

552+
func TestVeryLongLineInFile(t *testing.T) {
553+
s, buf := setupSqlCmdWithMemoryOutput(t)
554+
val := strings.Repeat("a1b", (3*1024*1024)/3)
555+
line := "set nocount on" + SqlcmdEol + "select('" + val + "')"
556+
file, err := os.CreateTemp("", "sqlcmdlongline")
557+
assert.NoError(t, err, "os.CreateTemp")
558+
defer os.Remove(file.Name())
559+
_, err = file.WriteString(line)
560+
assert.NoError(t, err, "Unable to write temp file")
561+
err = s.IncludeFile(file.Name(), true)
562+
if assert.NoError(t, err, "runSqlCmd") {
563+
actual := strings.TrimRight(buf.buf.String(), "\r\n")
564+
assert.Equal(t, val, actual, "Query result")
565+
}
566+
}
567+
552568
// runSqlCmd uses lines as input for sqlcmd instead of relying on file or console input
553569
func runSqlCmd(t testing.TB, s *Sqlcmd, lines []string) error {
554570
t.Helper()

0 commit comments

Comments
 (0)