From f5b5d2c53ac9edd8d28e8caecf1bb44d04ad9d7d Mon Sep 17 00:00:00 2001 From: Oliver Tan Date: Fri, 9 Dec 2022 18:15:29 -0500 Subject: [PATCH] clisqlshell: correctly handle sending zero input for COPY Release note (bug fix): Previously, empty COPY commands would not escape after an EOF character or error if encountering a `\.` with no input. This is now resolved. --- pkg/cli/clisqlclient/copy.go | 11 +++++++---- pkg/cli/clisqlshell/sql.go | 6 ++++-- pkg/cli/interactive_tests/test_copy.tcl | 16 ++++++++++++++++ 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/pkg/cli/clisqlclient/copy.go b/pkg/cli/clisqlclient/copy.go index 733aaaefeba6..7e2b57d72fee 100644 --- a/pkg/cli/clisqlclient/copy.go +++ b/pkg/cli/clisqlclient/copy.go @@ -96,10 +96,13 @@ func (c *CopyFromState) Commit(ctx context.Context, cleanupFunc func(), lines st return func(ctx context.Context, conn Conn) (Rows, bool, error) { defer cleanupFunc() rows, isMulti, err := func() (Rows, bool, error) { - for _, l := range strings.Split(lines, "\n") { - _, err := c.copyFromer.CopyData(ctx, l) - if err != nil { - return nil, false, err + // Do not send anything if it is just an empty string. + if lines != "" { + for _, l := range strings.Split(lines, "\n") { + _, err := c.copyFromer.CopyData(ctx, l) + if err != nil { + return nil, false, err + } } } r, err := c.copyFromer.Exec(nil) diff --git a/pkg/cli/clisqlshell/sql.go b/pkg/cli/clisqlshell/sql.go index a31814774380..756fb8666a85 100644 --- a/pkg/cli/clisqlshell/sql.go +++ b/pkg/cli/clisqlshell/sql.go @@ -974,6 +974,7 @@ func (c *cliState) doStartLine(nextState cliStateEnum) cliStateEnum { c.atEOF = false c.partialLines = c.partialLines[:0] c.partialStmtsLen = 0 + c.concatLines = "" c.useContinuePrompt = false @@ -1243,7 +1244,8 @@ func (c *cliState) doHandleCliCmd(loopState, nextState cliStateEnum) cliStateEnu case `\.`: if c.inCopy() { - c.concatLines += "\n" + `\.` + c.partialLines = append(c.partialLines, `\.`) + c.partialStmtsLen++ return cliRunStatement } return c.invalidSyntax(errState) @@ -1602,7 +1604,7 @@ func (c *cliState) doPrepareStatementLine( (c.inCopy() && (strings.HasSuffix(c.concatLines, "\n"+`\.`) || c.atEOF)) || // We're always at the end of a statement if EOF is reached in the // single statement mode. - c.singleStatement && c.atEOF + (c.singleStatement && c.atEOF) if c.atEOF { // Definitely no more input expected. if !endOfStmt { diff --git a/pkg/cli/interactive_tests/test_copy.tcl b/pkg/cli/interactive_tests/test_copy.tcl index de3362ba7d60..1a0713bd2aa4 100644 --- a/pkg/cli/interactive_tests/test_copy.tcl +++ b/pkg/cli/interactive_tests/test_copy.tcl @@ -28,6 +28,22 @@ eexpect "could not parse" end_test +start_test "check EMPTY copy" + +send "COPY t FROM STDIN;\r" +eexpect ">>" +send_eof +eexpect "COPY 0" +eexpect root@ + +send "COPY t FROM STDIN;\r" +eexpect ">>" +send "\\.\r" +eexpect "COPY 0" +eexpect root@ + +end_test + start_test "multi statement with COPY" send "SELECT 1; COPY t FROM STDIN CSV;\r" eexpect "COPY together with other statements in a query string is not supported"