From f55683279f199790b853c6addf18372fa0b020d8 Mon Sep 17 00:00:00 2001 From: GreatRiver Date: Sat, 4 Jul 2026 23:30:37 +0800 Subject: [PATCH 1/2] fix(load): adjust non-strict load data values --- pkg/sql/colexec/external/external.go | 107 +++++++++++++++++++++- pkg/sql/colexec/external/external_test.go | 105 +++++++++++++++++++++ 2 files changed, 207 insertions(+), 5 deletions(-) diff --git a/pkg/sql/colexec/external/external.go b/pkg/sql/colexec/external/external.go index c87df71be0b00..fd2e37b692214 100644 --- a/pkg/sql/colexec/external/external.go +++ b/pkg/sql/colexec/external/external.go @@ -891,9 +891,19 @@ func getNullFlag(nullMap map[string][]string, attr, field string) bool { func shouldLoadEmptyNumericAsZero(param *ExternalParam, id types.T) bool { if param == nil || param.Extern == nil || param.Extern.ExternType != int32(plan.ExternType_LOAD) || - (!param.ParallelLoad && !param.LoadEmptyNumericAsZero) { + (!param.ParallelLoad && !param.LoadEmptyNumericAsZero && !shouldApplyLoadDataNonStrictAdjustments(param)) { return false } + return isLoadNumericZeroFillType(id) +} + +func shouldApplyLoadDataNonStrictAdjustments(param *ExternalParam) bool { + return param != nil && param.Extern != nil && + param.Extern.ExternType == int32(plan.ExternType_LOAD) && + !checkLineStrict(param) +} + +func isLoadNumericZeroFillType(id types.T) bool { switch id { case types.T_bool, types.T_int8, types.T_int16, types.T_int32, types.T_int64, @@ -906,6 +916,69 @@ func shouldLoadEmptyNumericAsZero(param *ExternalParam, id types.T) bool { } } +func isLoadNumericAdjustedValueType(id types.T) bool { + switch id { + case types.T_int8, types.T_int16, types.T_int32, types.T_int64, + types.T_uint8, types.T_uint16, types.T_uint32, types.T_uint64, + types.T_float32, types.T_float64, + types.T_decimal64, types.T_decimal128: + return true + default: + return false + } +} + +func loadDataNonStrictNumericPrefix(val string) string { + val = strings.TrimSpace(val) + if val == "" { + return "0" + } + + i := 0 + if val[i] == '+' || val[i] == '-' { + i++ + } + digitsStart := i + for i < len(val) && val[i] >= '0' && val[i] <= '9' { + i++ + } + digits := i > digitsStart + if i < len(val) && val[i] == '.' { + i++ + fracStart := i + for i < len(val) && val[i] >= '0' && val[i] <= '9' { + i++ + } + digits = digits || i > fracStart + } + if !digits { + return "0" + } + + end := i + if i < len(val) && (val[i] == 'e' || val[i] == 'E') { + exp := i + 1 + if exp < len(val) && (val[exp] == '+' || val[exp] == '-') { + exp++ + } + expDigits := exp + for exp < len(val) && val[exp] >= '0' && val[exp] <= '9' { + exp++ + } + if exp > expDigits { + end = exp + } + } + return val[:end] +} + +func truncateLoadDataStringValue(val string, width int32) string { + if width <= 0 || utf8.RuneCountInString(val) <= int(width) { + return val + } + return string([]rune(val)[:width]) +} + func appendLoadEmptyNumericZero(vec *vector.Vector, id types.T, asBytes bool, mp *mpool.MPool) error { if asBytes { return vector.AppendBytes(vec, loadZeroBytes, false, mp) @@ -995,6 +1068,7 @@ func getColData(bat *batch.Batch, line []csvparser.Field, rowIdx int, param *Ext field := getFieldFromLine(line, colName, param, fieldIdx) id := types.T(col.Typ.Id) + loadDataNonStrictAdjustments := shouldApplyLoadDataNonStrictAdjustments(param) trimSpace := false // T_bit carries raw bytes (parsed byte-by-byte, not as text), so whitespace // bytes are data and must not be trimmed (a whitespace-only bit value would @@ -1019,6 +1093,23 @@ func getColData(bat *batch.Batch, line []csvparser.Field, rowIdx int, param *Ext return nil } + zeroDateAdjusted := false + if loadDataNonStrictAdjustments { + switch { + case isLoadNumericAdjustedValueType(id): + field.Val = loadDataNonStrictNumericPrefix(field.Val) + case id == types.T_date: + if _, err := types.ParseDateCast(field.Val); err != nil { + zeroDateAdjusted = true + if param.ParallelLoad { + field.Val = "0000-00-00" + } + } + case id == types.T_char || id == types.T_varchar: + field.Val = truncateLoadDataStringValue(field.Val, col.Typ.Width) + } + } + // In strict SQL mode (non-LOCAL load), an over-width CHAR/VARCHAR value is // rejected instead of silently truncated, matching strict assignment casts // (cast_strict) and MySQL's "Data too long" behavior. Uses rune count, like @@ -1326,10 +1417,16 @@ func getColData(bat *batch.Batch, line []csvparser.Field, rowIdx int, param *Ext return err } case types.T_date: - d, err := types.ParseDateCast(field.Val) - if err != nil { - logutil.Errorf("parse field[%v] err:%v", field.Val, err) - return moerr.NewInternalErrorf(param.Ctx, "the input value '%v' is not Date type for column %d", field.Val, colIdx) + var d types.Date + if zeroDateAdjusted { + d = types.Date(0) + } else { + var err error + d, err = types.ParseDateCast(field.Val) + if err != nil { + logutil.Errorf("parse field[%v] err:%v", field.Val, err) + return moerr.NewInternalErrorf(param.Ctx, "the input value '%v' is not Date type for column %d", field.Val, colIdx) + } } if err := vector.AppendFixed(vec, d, false, mp); err != nil { diff --git a/pkg/sql/colexec/external/external_test.go b/pkg/sql/colexec/external/external_test.go index 64802e08d7c5a..e85ac092bb8c3 100644 --- a/pkg/sql/colexec/external/external_test.go +++ b/pkg/sql/colexec/external/external_test.go @@ -473,6 +473,111 @@ func TestGetColDataLoadDataYear(t *testing.T) { require.Contains(t, err.Error(), "not Year type") } +func TestGetOneRowDataLoadDataNonStrictAdjustedValues(t *testing.T) { + proc := testutil.NewProcess(t) + defer proc.Free() + + decType := types.New(types.T_decimal64, 5, 2) + varcharType := types.New(types.T_varchar, 4, 0) + cols := []*plan.ColDef{ + {Name: "id", Typ: plan.Type{Id: int32(types.T_int32)}}, + {Name: "i", Typ: plan.Type{Id: int32(types.T_int32)}}, + {Name: "d", Typ: plan.Type{Id: int32(types.T_decimal64), Width: 5, Scale: 2}}, + {Name: "dt", Typ: plan.Type{Id: int32(types.T_date)}}, + {Name: "vc", Typ: plan.Type{Id: int32(types.T_varchar), Width: 4}}, + } + attrs := make([]plan.ExternAttr, len(cols)) + for idx, col := range cols { + attrs[idx] = plan.ExternAttr{ColName: col.Name, ColIndex: int32(idx), ColFieldIndex: int32(idx)} + } + + bat := batch.NewWithSize(len(cols)) + bat.Vecs[0] = vector.NewVec(types.T_int32.ToType()) + bat.Vecs[1] = vector.NewVec(types.T_int32.ToType()) + bat.Vecs[2] = vector.NewVec(decType) + bat.Vecs[3] = vector.NewVec(types.T_date.ToType()) + bat.Vecs[4] = vector.NewVec(varcharType) + defer bat.Clean(proc.Mp()) + + param := &ExternalParam{ + ExParamConst: ExParamConst{ + Ctx: context.Background(), + ColumnListLen: int32(len(cols)), + StrictSqlMode: false, + Attrs: attrs, + Cols: cols, + Extern: &tree.ExternParam{ + ExParamConst: tree.ExParamConst{Format: tree.CSV}, + ExParam: tree.ExParam{ExternType: int32(plan.ExternType_LOAD), Local: true}, + }, + }, + ExParam: ExParam{Fileparam: &ExFileparam{}}, + } + + lines := [][]csvparser.Field{ + {{Val: "1"}, {Val: "12"}, {Val: "12.345"}, {Val: "20240102"}, {Val: "abcd"}}, + {{Val: "2"}, {Val: "abc"}, {Val: "10.00x"}, {Val: "2024-02-31"}, {Val: "abcdef"}}, + {{Val: "3"}, {Val: ""}, {Val: "bad"}, {Val: "0000-00-00"}, {Val: "xy"}}, + } + for idx, line := range lines { + require.NoError(t, getOneRowData(proc, bat, line, idx, param)) + } + + require.Equal(t, []int32{1, 2, 3}, vector.MustFixedColWithTypeCheck[int32](bat.Vecs[0])) + require.Equal(t, []int32{12, 0, 0}, vector.MustFixedColWithTypeCheck[int32](bat.Vecs[1])) + + d0, err := types.ParseDecimal64("12.35", 5, 2) + require.NoError(t, err) + d1, err := types.ParseDecimal64("10.00", 5, 2) + require.NoError(t, err) + require.Equal(t, []types.Decimal64{d0, d1, 0}, vector.MustFixedColWithTypeCheck[types.Decimal64](bat.Vecs[2])) + + date0, err := types.ParseDateCast("20240102") + require.NoError(t, err) + require.Equal(t, []types.Date{date0, types.Date(0), types.Date(0)}, vector.MustFixedColWithTypeCheck[types.Date](bat.Vecs[3])) + + require.Equal(t, "abcd", string(bat.Vecs[4].GetBytesAt(0))) + require.Equal(t, "abcd", string(bat.Vecs[4].GetBytesAt(1))) + require.Equal(t, "xy", string(bat.Vecs[4].GetBytesAt(2))) +} + +func TestGetColDataLoadDataStrictRejectsInvalidInteger(t *testing.T) { + proc := testutil.NewProcess(t) + defer proc.Free() + + bat := batch.NewWithSize(1) + bat.Vecs[0] = vector.NewVec(types.T_int32.ToType()) + defer bat.Clean(proc.Mp()) + + param := &ExternalParam{ + ExParamConst: ExParamConst{ + Ctx: context.Background(), + StrictSqlMode: true, + Cols: []*plan.ColDef{{ + Name: "i", + Typ: plan.Type{Id: int32(types.T_int32)}, + }}, + Extern: &tree.ExternParam{ + ExParamConst: tree.ExParamConst{Format: tree.CSV}, + ExParam: tree.ExParam{ExternType: int32(plan.ExternType_LOAD), Local: false}, + }, + }, + ExParam: ExParam{Fileparam: &ExFileparam{}}, + } + + err := getColData( + bat, + []csvparser.Field{{Val: "abc"}}, + 0, + param, + proc.Mp(), + plan.ExternAttr{ColName: "i", ColIndex: 0, ColFieldIndex: 0}, + proc, + ) + require.Error(t, err) + require.Contains(t, err.Error(), "not int32 type") +} + func TestIsLegalLineLoadDataYear(t *testing.T) { param := &tree.ExternParam{ExParamConst: tree.ExParamConst{Format: tree.CSV}} cols := []*plan.ColDef{{ From f568cb42fcf22e15d8b9c0349525dbddc0cedc84 Mon Sep 17 00:00:00 2001 From: GreatRiver Date: Sun, 5 Jul 2026 11:28:22 +0800 Subject: [PATCH 2/2] fix(load): narrow adjusted load data compatibility --- pkg/sql/colexec/external/external.go | 11 +- pkg/sql/colexec/external/external_test.go | 172 ++++++++++++++++++ .../cases/load_data/issue_25366.result | 77 ++++++++ .../cases/load_data/issue_25366.sql | 65 +++++++ .../issue_25366_load_data_local_adjusted.csv | 3 + .../issue_25366_quoted_invalid_decimal.csv | 1 + .../issue_25366_quoted_invalid_int.csv | 1 + 7 files changed, 328 insertions(+), 2 deletions(-) create mode 100644 test/distributed/cases/load_data/issue_25366.result create mode 100644 test/distributed/cases/load_data/issue_25366.sql create mode 100644 test/distributed/resources/load_data/issue_25366_load_data_local_adjusted.csv create mode 100644 test/distributed/resources/load_data/issue_25366_quoted_invalid_decimal.csv create mode 100644 test/distributed/resources/load_data/issue_25366_quoted_invalid_int.csv diff --git a/pkg/sql/colexec/external/external.go b/pkg/sql/colexec/external/external.go index fd2e37b692214..3c77afbdf0e8e 100644 --- a/pkg/sql/colexec/external/external.go +++ b/pkg/sql/colexec/external/external.go @@ -894,13 +894,18 @@ func shouldLoadEmptyNumericAsZero(param *ExternalParam, id types.T) bool { (!param.ParallelLoad && !param.LoadEmptyNumericAsZero && !shouldApplyLoadDataNonStrictAdjustments(param)) { return false } + if !param.ParallelLoad && !param.LoadEmptyNumericAsZero { + return isLoadNumericAdjustedValueType(id) + } return isLoadNumericZeroFillType(id) } func shouldApplyLoadDataNonStrictAdjustments(param *ExternalParam) bool { return param != nil && param.Extern != nil && param.Extern.ExternType == int32(plan.ExternType_LOAD) && - !checkLineStrict(param) + param.Extern.Local && + param.Extern.Format == tree.CSV && + !param.StrictSqlMode } func isLoadNumericZeroFillType(id types.T) bool { @@ -1097,7 +1102,9 @@ func getColData(bat *batch.Batch, line []csvparser.Field, rowIdx int, param *Ext if loadDataNonStrictAdjustments { switch { case isLoadNumericAdjustedValueType(id): - field.Val = loadDataNonStrictNumericPrefix(field.Val) + if !field.HasStringQuote { + field.Val = loadDataNonStrictNumericPrefix(field.Val) + } case id == types.T_date: if _, err := types.ParseDateCast(field.Val); err != nil { zeroDateAdjusted = true diff --git a/pkg/sql/colexec/external/external_test.go b/pkg/sql/colexec/external/external_test.go index e85ac092bb8c3..f1dfe0cac198f 100644 --- a/pkg/sql/colexec/external/external_test.go +++ b/pkg/sql/colexec/external/external_test.go @@ -578,6 +578,178 @@ func TestGetColDataLoadDataStrictRejectsInvalidInteger(t *testing.T) { require.Contains(t, err.Error(), "not int32 type") } +func TestGetColDataLoadDataAdjustmentsOnlyLocalCSVNonStrict(t *testing.T) { + cases := []struct { + name string + local bool + strictSQLMode bool + format string + wantErr bool + }{ + {name: "local csv non-strict adjusts", local: true, strictSQLMode: false, format: tree.CSV}, + {name: "local csv strict rejects", local: true, strictSQLMode: true, format: tree.CSV, wantErr: true}, + {name: "non-local csv non-strict rejects", local: false, strictSQLMode: false, format: tree.CSV, wantErr: true}, + {name: "local jsonline non-strict rejects", local: true, strictSQLMode: false, format: tree.JSONLINE, wantErr: true}, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + proc := testutil.NewProcess(t) + defer proc.Free() + + bat := batch.NewWithSize(1) + bat.Vecs[0] = vector.NewVec(types.T_int32.ToType()) + defer bat.Clean(proc.Mp()) + + param := &ExternalParam{ + ExParamConst: ExParamConst{ + Ctx: context.Background(), + StrictSqlMode: tc.strictSQLMode, + Cols: []*plan.ColDef{{ + Name: "i", + Typ: plan.Type{Id: int32(types.T_int32)}, + }}, + Extern: &tree.ExternParam{ + ExParamConst: tree.ExParamConst{Format: tc.format}, + ExParam: tree.ExParam{ + ExternType: int32(plan.ExternType_LOAD), + Local: tc.local, + }, + }, + }, + ExParam: ExParam{Fileparam: &ExFileparam{}}, + } + + err := getColData( + bat, + []csvparser.Field{{Val: "abc"}}, + 0, + param, + proc.Mp(), + plan.ExternAttr{ColName: "i", ColIndex: 0, ColFieldIndex: 0}, + proc, + ) + if tc.wantErr { + require.Error(t, err) + require.Contains(t, err.Error(), "not int32 type") + return + } + require.NoError(t, err) + require.Equal(t, []int32{0}, vector.MustFixedColWithTypeCheck[int32](bat.Vecs[0])) + }) + } +} + +func TestGetColDataLoadDataNonStrictAdjustmentRejectsQuotedInvalidNumeric(t *testing.T) { + cases := []struct { + name string + colName string + vecType types.Type + colType plan.Type + fieldVal string + wantErrText string + }{ + { + name: "quoted invalid int is not adjusted", + colName: "i", + vecType: types.T_int32.ToType(), + colType: plan.Type{Id: int32(types.T_int32)}, + fieldVal: "abc", + wantErrText: "not int32 type", + }, + { + name: "quoted invalid decimal is not adjusted", + colName: "d", + vecType: types.New(types.T_decimal64, 5, 2), + colType: plan.Type{Id: int32(types.T_decimal64), Width: 5, Scale: 2}, + fieldVal: "10x", + wantErrText: "invalid Decimal64 type", + }, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + proc := testutil.NewProcess(t) + defer proc.Free() + + bat := batch.NewWithSize(1) + bat.Vecs[0] = vector.NewVec(tc.vecType) + defer bat.Clean(proc.Mp()) + + param := &ExternalParam{ + ExParamConst: ExParamConst{ + Ctx: context.Background(), + StrictSqlMode: false, + Cols: []*plan.ColDef{{ + Name: tc.colName, + Typ: tc.colType, + }}, + Extern: &tree.ExternParam{ + ExParamConst: tree.ExParamConst{Format: tree.CSV}, + ExParam: tree.ExParam{ + ExternType: int32(plan.ExternType_LOAD), + Local: true, + }, + }, + }, + ExParam: ExParam{Fileparam: &ExFileparam{}}, + } + + err := getColData( + bat, + []csvparser.Field{{Val: tc.fieldVal, HasStringQuote: true}}, + 0, + param, + proc.Mp(), + plan.ExternAttr{ColName: tc.colName, ColIndex: 0, ColFieldIndex: 0}, + proc, + ) + require.Error(t, err) + require.Contains(t, err.Error(), tc.wantErrText) + }) + } +} + +func TestGetColDataLoadDataNonStrictAdjustmentLeavesEmptyBoolNull(t *testing.T) { + proc := testutil.NewProcess(t) + defer proc.Free() + + bat := batch.NewWithSize(1) + bat.Vecs[0] = vector.NewVec(types.T_bool.ToType()) + defer bat.Clean(proc.Mp()) + + param := &ExternalParam{ + ExParamConst: ExParamConst{ + Ctx: context.Background(), + StrictSqlMode: false, + Cols: []*plan.ColDef{{ + Name: "b", + Typ: plan.Type{Id: int32(types.T_bool)}, + }}, + Extern: &tree.ExternParam{ + ExParamConst: tree.ExParamConst{Format: tree.CSV}, + ExParam: tree.ExParam{ + ExternType: int32(plan.ExternType_LOAD), + Local: true, + }, + }, + }, + ExParam: ExParam{Fileparam: &ExFileparam{}}, + } + + err := getColData( + bat, + []csvparser.Field{{Val: ""}}, + 0, + param, + proc.Mp(), + plan.ExternAttr{ColName: "b", ColIndex: 0, ColFieldIndex: 0}, + proc, + ) + require.NoError(t, err) + require.True(t, bat.Vecs[0].GetNulls().Contains(0)) +} + func TestIsLegalLineLoadDataYear(t *testing.T) { param := &tree.ExternParam{ExParamConst: tree.ExParamConst{Format: tree.CSV}} cols := []*plan.ColDef{{ diff --git a/test/distributed/cases/load_data/issue_25366.result b/test/distributed/cases/load_data/issue_25366.result new file mode 100644 index 0000000000000..3334508fd8c3b --- /dev/null +++ b/test/distributed/cases/load_data/issue_25366.result @@ -0,0 +1,77 @@ +drop database if exists issue_25366_load_data_local_adjusted; +create database issue_25366_load_data_local_adjusted; +use issue_25366_load_data_local_adjusted; +set sql_mode = ''; +create table t_load( +id int primary key, +i int, +d decimal(5,2), +dt date, +vc varchar(4), +nullable_i int +); +load data local infile '$resources/load_data/issue_25366_load_data_local_adjusted.csv' +into table t_load +fields terminated by ',' lines terminated by '\n'; +select id, i, d, dt, vc, hex(vc), nullable_i from t_load order by id; +id i d dt vc hex(vc) nullable_i +1 12 12.35 2024-01-02 abcd 61626364 null +2 0 10.00 0001-01-01 abcd 61626364 0 +3 0 0.00 0001-01-01 xy 7879 7 +set sql_mode = 'STRICT_TRANS_TABLES'; +truncate table t_load; +load data local infile '$resources/load_data/issue_25366_load_data_local_adjusted.csv' +into table t_load +fields terminated by ',' lines terminated by '\n'; +internal error: the input value 'abc' is not int32 type for column 1 +select count(*) from t_load; +count(*) +0 +set sql_mode = ''; +truncate table t_load; +load data infile '$resources/load_data/issue_25366_load_data_local_adjusted.csv' +into table t_load +fields terminated by ',' lines terminated by '\n'; +internal error: the input value 'abc' is not int32 type for column 1 +select count(*) from t_load; +count(*) +0 +create table t_quoted_int(id int primary key, i int); +load data local infile '$resources/load_data/issue_25366_quoted_invalid_int.csv' +into table t_quoted_int +fields terminated by ',' enclosed by '"' lines terminated by '\n'; +internal error: the input value 'abc' is not int32 type for column 1 +select count(*) from t_quoted_int; +count(*) +0 +set sql_mode = 'STRICT_TRANS_TABLES'; +truncate table t_quoted_int; +load data local infile '$resources/load_data/issue_25366_quoted_invalid_int.csv' +into table t_quoted_int +fields terminated by ',' enclosed by '"' lines terminated by '\n'; +internal error: the input value 'abc' is not int32 type for column 1 +select count(*) from t_quoted_int; +count(*) +0 +set sql_mode = ''; +truncate table t_quoted_int; +load data infile '$resources/load_data/issue_25366_quoted_invalid_int.csv' +into table t_quoted_int +fields terminated by ',' enclosed by '"' lines terminated by '\n'; +internal error: the input value 'abc' is not int32 type for column 1 +select count(*) from t_quoted_int; +count(*) +0 +create table t_quoted_decimal(id int primary key, d decimal(5,2)); +load data local infile '$resources/load_data/issue_25366_quoted_invalid_decimal.csv' +into table t_quoted_decimal +fields terminated by ',' enclosed by '"' lines terminated by '\n'; +internal error: the input value '10x' is invalid Decimal64 type for column 1 +select count(*) from t_quoted_decimal; +count(*) +0 +set sql_mode = default; +drop table t_quoted_decimal; +drop table t_quoted_int; +drop table t_load; +drop database issue_25366_load_data_local_adjusted; diff --git a/test/distributed/cases/load_data/issue_25366.sql b/test/distributed/cases/load_data/issue_25366.sql new file mode 100644 index 0000000000000..9fbc3112a0be4 --- /dev/null +++ b/test/distributed/cases/load_data/issue_25366.sql @@ -0,0 +1,65 @@ +drop database if exists issue_25366_load_data_local_adjusted; +create database issue_25366_load_data_local_adjusted; +use issue_25366_load_data_local_adjusted; + +set sql_mode = ''; +create table t_load( + id int primary key, + i int, + d decimal(5,2), + dt date, + vc varchar(4), + nullable_i int +); + +load data local infile '$resources/load_data/issue_25366_load_data_local_adjusted.csv' +into table t_load +fields terminated by ',' lines terminated by '\n'; + +select id, i, d, dt, vc, hex(vc), nullable_i from t_load order by id; + +set sql_mode = 'STRICT_TRANS_TABLES'; +truncate table t_load; +load data local infile '$resources/load_data/issue_25366_load_data_local_adjusted.csv' +into table t_load +fields terminated by ',' lines terminated by '\n'; +select count(*) from t_load; + +set sql_mode = ''; +truncate table t_load; +load data infile '$resources/load_data/issue_25366_load_data_local_adjusted.csv' +into table t_load +fields terminated by ',' lines terminated by '\n'; +select count(*) from t_load; + +create table t_quoted_int(id int primary key, i int); +load data local infile '$resources/load_data/issue_25366_quoted_invalid_int.csv' +into table t_quoted_int +fields terminated by ',' enclosed by '"' lines terminated by '\n'; +select count(*) from t_quoted_int; + +set sql_mode = 'STRICT_TRANS_TABLES'; +truncate table t_quoted_int; +load data local infile '$resources/load_data/issue_25366_quoted_invalid_int.csv' +into table t_quoted_int +fields terminated by ',' enclosed by '"' lines terminated by '\n'; +select count(*) from t_quoted_int; + +set sql_mode = ''; +truncate table t_quoted_int; +load data infile '$resources/load_data/issue_25366_quoted_invalid_int.csv' +into table t_quoted_int +fields terminated by ',' enclosed by '"' lines terminated by '\n'; +select count(*) from t_quoted_int; + +create table t_quoted_decimal(id int primary key, d decimal(5,2)); +load data local infile '$resources/load_data/issue_25366_quoted_invalid_decimal.csv' +into table t_quoted_decimal +fields terminated by ',' enclosed by '"' lines terminated by '\n'; +select count(*) from t_quoted_decimal; + +set sql_mode = default; +drop table t_quoted_decimal; +drop table t_quoted_int; +drop table t_load; +drop database issue_25366_load_data_local_adjusted; diff --git a/test/distributed/resources/load_data/issue_25366_load_data_local_adjusted.csv b/test/distributed/resources/load_data/issue_25366_load_data_local_adjusted.csv new file mode 100644 index 0000000000000..410af6f3ed651 --- /dev/null +++ b/test/distributed/resources/load_data/issue_25366_load_data_local_adjusted.csv @@ -0,0 +1,3 @@ +1,12,12.345,20240102,abcd,\N +2,abc,10.00x,2024-02-31,abcdef, +3,,bad,0000-00-00,xy,7 diff --git a/test/distributed/resources/load_data/issue_25366_quoted_invalid_decimal.csv b/test/distributed/resources/load_data/issue_25366_quoted_invalid_decimal.csv new file mode 100644 index 0000000000000..51e50db739603 --- /dev/null +++ b/test/distributed/resources/load_data/issue_25366_quoted_invalid_decimal.csv @@ -0,0 +1 @@ +1,"10x" diff --git a/test/distributed/resources/load_data/issue_25366_quoted_invalid_int.csv b/test/distributed/resources/load_data/issue_25366_quoted_invalid_int.csv new file mode 100644 index 0000000000000..e10fff626b565 --- /dev/null +++ b/test/distributed/resources/load_data/issue_25366_quoted_invalid_int.csv @@ -0,0 +1 @@ +1,"abc"