diff --git a/enginetest/queries/load_queries.go b/enginetest/queries/load_queries.go index a3faedab3e..00f6cef701 100644 --- a/enginetest/queries/load_queries.go +++ b/enginetest/queries/load_queries.go @@ -22,6 +22,20 @@ import ( ) var LoadDataScripts = []ScriptTest{ + { + Name: "LOAD DATA applies column defaults when \\N provided", + SetUpScript: []string{ + "create table t (pk int primary key, c1 int default 1, c2 int)", + // Explicitly use Windows-style line endings to be robust on Windows CI + "LOAD DATA INFILE './testdata/load_defaults_null.csv' INTO TABLE t FIELDS TERMINATED BY ',' LINES TERMINATED BY '\r\n'", + }, + Assertions: []ScriptTestAssertion{ + { + Query: "select * from t", + Expected: []sql.Row{{1, 1, 1}}, + }, + }, + }, { Name: "Basic load data with enclosed values.", SetUpScript: []string{ diff --git a/enginetest/testdata/load_defaults_null.csv b/enginetest/testdata/load_defaults_null.csv new file mode 100644 index 0000000000..3fa94d7434 --- /dev/null +++ b/enginetest/testdata/load_defaults_null.csv @@ -0,0 +1 @@ +1,\N,1 diff --git a/sql/rowexec/ddl_iters.go b/sql/rowexec/ddl_iters.go index ebf32fca20..becf91167e 100644 --- a/sql/rowexec/ddl_iters.go +++ b/sql/rowexec/ddl_iters.go @@ -207,7 +207,19 @@ func (l *loadDataIter) parseFields(ctx *sql.Context, line string) ([]sql.Express } } case "NULL": - exprs[exprIdx] = expression.NewLiteral(nil, types.Null) + // For MySQL LOAD DATA semantics, \N (mapped to NULL here) should use the column default + // if one exists; otherwise insert NULL. + destIdx := l.fieldToColMap[fieldIdx] + if destIdx >= 0 { + destCol := l.destSch[destIdx] + if destCol.Default != nil { + exprs[exprIdx] = destCol.Default + } else { + exprs[exprIdx] = expression.NewLiteral(nil, types.Null) + } + } else { + exprs[exprIdx] = expression.NewLiteral(nil, types.Null) + } default: exprs[exprIdx] = expression.NewLiteral(field, types.LongText) }