Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ enginetest/testdata/test6.csv binary
enginetest/testdata/test7.txt binary
enginetest/testdata/test8.txt binary
enginetest/testdata/test9.txt binary
enginetest/testdata/test10.txt binary
enginetest/testdata/test10.txt binary
enginetest/testdata/simple_json.txt binary
17 changes: 17 additions & 0 deletions enginetest/queries/load_queries.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import (
"fmt"
"time"

"github.com/dolthub/go-mysql-server/sql/types"

"github.com/dolthub/go-mysql-server/sql"
)

Expand Down Expand Up @@ -126,6 +128,21 @@ var LoadDataScripts = []ScriptTest{
},
},
},
{
Name: "Load JSON data. EnclosedBy and EscapedBy are the same.",
SetUpScript: []string{
"create table loadtable(pk int primary key, j json)",
"LOAD DATA INFILE './testdata/simple_json.txt' INTO TABLE loadtable FIELDS TERMINATED BY ',' ENCLOSED BY '\"' ESCAPED BY '\"';",
},
Assertions: []ScriptTestAssertion{
{
Query: "select * from loadtable",
Expected: []sql.Row{
{1, types.MustJSON(`{"foo": "bar"}`)},
},
},
},
},
{
Name: "LOAD DATA handles Windows line-endings and a subset of columns that are not in order",
SetUpScript: []string{
Expand Down
1 change: 1 addition & 0 deletions enginetest/testdata/simple_json.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"1","{""foo"":""bar""}"
19 changes: 17 additions & 2 deletions sql/rowexec/ddl_iters.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ func (l *loadDataIter) parseFields(ctx *sql.Context, line string) ([]sql.Express
// TODO: Support the OPTIONALLY parameter.
if l.fieldsEnclosedBy != "" {
for i, field := range fields {
if string(field[0]) == l.fieldsEnclosedBy && string(field[len(field)-1]) == l.fieldsEnclosedBy {
if field[0] == l.fieldsEnclosedBy[0] && field[len(field)-1] == l.fieldsEnclosedBy[0] {
fields[i] = field[1 : len(field)-1]
} else {
return nil, fmt.Errorf("error: field not properly enclosed")
Expand All @@ -162,7 +162,22 @@ func (l *loadDataIter) parseFields(ctx *sql.Context, line string) ([]sql.Express
} else if field == "\\0" {
fields[i] = fmt.Sprintf("%c", 0) // ASCII 0
} else {
fields[i] = strings.ReplaceAll(field, l.fieldsEscapedBy, "")
// The character immediately following the escaped character remains untouched, even if it is the same
// as the escape character
newField := make([]byte, 0, len(field))
for cIdx := 0; cIdx < len(field); cIdx++ {
c := field[cIdx]
// skip over escaped character, but always add the following character
if c == l.fieldsEscapedBy[0] {
cIdx += 1
if cIdx < len(field) {
newField = append(newField, c)
}
continue
}
newField = append(newField, c)
}
fields[i] = string(newField)
}
}
}
Expand Down
Loading