Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

executor,expression: avoid to append nil to warnings #36304

Merged
merged 11 commits into from
Aug 5, 2022
18 changes: 15 additions & 3 deletions executor/insert.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ func (e *InsertExec) updateDupRow(ctx context.Context, idxInBatch int, txn kv.Tr
extraCols = e.ctx.GetSessionVars().CurrInsertBatchExtraCols[idxInBatch]
}

err = e.doDupRowUpdate(ctx, handle, oldRow, row.row, extraCols, e.OnDuplicate)
err = e.doDupRowUpdate(ctx, handle, oldRow, row.row, extraCols, e.OnDuplicate, idxInBatch)
if e.ctx.GetSessionVars().StmtCtx.DupKeyAsWarning && kv.ErrKeyExists.Equal(err) {
e.ctx.GetSessionVars().StmtCtx.AppendWarning(err)
return nil
Expand Down Expand Up @@ -374,7 +374,7 @@ func (e *InsertExec) initEvalBuffer4Dup() {

// doDupRowUpdate updates the duplicate row.
func (e *InsertExec) doDupRowUpdate(ctx context.Context, handle kv.Handle, oldRow []types.Datum, newRow []types.Datum,
extraCols []types.Datum, cols []*expression.Assignment) error {
extraCols []types.Datum, cols []*expression.Assignment, idxInBatch int) error {
assignFlag := make([]bool, len(e.Table.WritableCols()))
// See http://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html#function_values
e.curInsertVals.SetDatums(newRow...)
Expand All @@ -390,6 +390,8 @@ func (e *InsertExec) doDupRowUpdate(ctx context.Context, handle kv.Handle, oldRo

// Update old row when the key is duplicated.
e.evalBuffer4Dup.SetDatums(e.row4Update...)
sc := e.ctx.GetSessionVars().StmtCtx
warnCnt := int(sc.WarningCount())
for _, col := range cols {
if col.LazyErr != nil {
return col.LazyErr
Expand All @@ -398,10 +400,20 @@ func (e *InsertExec) doDupRowUpdate(ctx context.Context, handle kv.Handle, oldRo
if err1 != nil {
return err1
}
e.row4Update[col.Col.Index], err1 = table.CastValue(e.ctx, val, col.Col.ToInfo(), false, false)
c := col.Col.ToInfo()
c.Name = col.ColName
e.row4Update[col.Col.Index], err1 = table.CastValue(e.ctx, val, c, false, false)
if err1 != nil {
return err1
}
if newWarnings := sc.TruncateWarnings(warnCnt); len(newWarnings) > 0 {
for k := range newWarnings {
// Use `idxInBatch` here for simplicity, since the offset of the batch is unknown under the current context.
newWarnings[k].Err = completeInsertErr(c, &val, idxInBatch, newWarnings[k].Err)
}
sc.AppendWarnings(newWarnings)
warnCnt += len(newWarnings)
}
e.evalBuffer4Dup.SetDatum(col.Col.Index, e.row4Update[col.Col.Index])
assignFlag[col.Col.Index] = true
}
Expand Down
39 changes: 33 additions & 6 deletions executor/insert_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -287,12 +287,7 @@ func insertRows(ctx context.Context, base insertCommon) (err error) {
return nil
}

func (e *InsertValues) handleErr(col *table.Column, val *types.Datum, rowIdx int, err error) error {
if err == nil {
return nil
}

// Convert the error with full messages.
func completeInsertErr(col *model.ColumnInfo, val *types.Datum, rowIdx int, err error) error {
var (
colTp byte
colName string
Expand Down Expand Up @@ -323,6 +318,20 @@ func (e *InsertValues) handleErr(col *table.Column, val *types.Datum, rowIdx int
} else if types.ErrWarnDataOutOfRange.Equal(err) {
err = types.ErrWarnDataOutOfRange.GenWithStackByArgs(colName, rowIdx+1)
}
return err
}

func (e *InsertValues) handleErr(col *table.Column, val *types.Datum, rowIdx int, err error) error {
if err == nil {
return nil
}

// Convert the error with full messages.
var c *model.ColumnInfo
if col != nil {
c = col.ColumnInfo
}
err = completeInsertErr(c, val, rowIdx, err)

if !e.ctx.GetSessionVars().StmtCtx.DupKeyAsWarning {
return err
Expand Down Expand Up @@ -350,6 +359,8 @@ func (e *InsertValues) evalRow(ctx context.Context, list []expression.Expression
}

e.evalBuffer.SetDatums(row...)
sc := e.ctx.GetSessionVars().StmtCtx
warnCnt := int(sc.WarningCount())
for i, expr := range list {
val, err := expr.Eval(e.evalBuffer.ToRow())
if err != nil {
Expand All @@ -359,6 +370,13 @@ func (e *InsertValues) evalRow(ctx context.Context, list []expression.Expression
if err = e.handleErr(e.insertColumns[i], &val, rowIdx, err); err != nil {
return nil, err
}
if newWarnings := sc.TruncateWarnings(warnCnt); len(newWarnings) > 0 {
for k := range newWarnings {
newWarnings[k].Err = completeInsertErr(e.insertColumns[i].ColumnInfo, &val, rowIdx, newWarnings[k].Err)
}
sc.AppendWarnings(newWarnings)
warnCnt += len(newWarnings)
}

offset := e.insertColumns[i].Offset
val1.Copy(&row[offset])
Expand All @@ -378,6 +396,8 @@ func (e *InsertValues) fastEvalRow(ctx context.Context, list []expression.Expres
}
row := make([]types.Datum, rowLen)
hasValue := make([]bool, rowLen)
sc := e.ctx.GetSessionVars().StmtCtx
warnCnt := int(sc.WarningCount())
for i, expr := range list {
con := expr.(*expression.Constant)
val, err := con.Eval(emptyRow)
Expand All @@ -388,6 +408,13 @@ func (e *InsertValues) fastEvalRow(ctx context.Context, list []expression.Expres
if err = e.handleErr(e.insertColumns[i], &val, rowIdx, err); err != nil {
return nil, err
}
if newWarnings := sc.TruncateWarnings(warnCnt); len(newWarnings) > 0 {
for k := range newWarnings {
newWarnings[k].Err = completeInsertErr(e.insertColumns[i].ColumnInfo, &val, rowIdx, newWarnings[k].Err)
}
sc.AppendWarnings(newWarnings)
warnCnt += len(newWarnings)
}
offset := e.insertColumns[i].Offset
row[offset], hasValue[offset] = val1, true
}
Expand Down
22 changes: 22 additions & 0 deletions expression/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7469,6 +7469,28 @@ func TestIssue31600(t *testing.T) {
tk.MustExec("drop table t")
}

func TestIssue31569(t *testing.T) {
store, clean := testkit.CreateMockStore(t)
defer clean()

tk := testkit.NewTestKit(t, store)

tk.MustExec("use test")
tk.MustExec("drop table if exists t")
tk.MustExec("create table t (c int primary key, c2 enum('a', 'b'))")
tk.MustExec("set session sql_mode = ''")
tk.MustExec("insert into t values(4, 'a')")
tk.MustExec("insert into t values(4, 0) on duplicate key update c=values(c), c2=values(c2)")
// tidb produces two warnings here (when eval (4, 0) & values(c2)), which is slightly incompatible with mysql
tk.MustQuery("show warnings").Check([][]interface{}{
{"Warning", "1265", "Data truncated for column 'c2' at row 1"},
{"Warning", "1265", "Data truncated for column 'c2' at row 1"},
})
tk.MustExec("insert into t values(4, 'a') on duplicate key update c=values(c), c2=values(c2)")
tk.MustQuery("show warnings").Check([][]interface{}{})
tk.MustExec("drop table t")
}

func TestDateAddForNonExistingTimestamp(t *testing.T) {
store, clean := testkit.CreateMockStore(t)
defer clean()
Expand Down
5 changes: 1 addition & 4 deletions expression/scalar_function.go
Original file line number Diff line number Diff line change
Expand Up @@ -375,10 +375,7 @@ func (sf *ScalarFunction) Eval(row chunk.Row) (d types.Datum, err error) {
res, err = types.ParseEnum(tp.GetElems(), str, tp.GetCollate())
if ctx := sf.GetCtx(); ctx != nil {
if sc := ctx.GetSessionVars().StmtCtx; sc != nil {
if sc.TruncateAsWarning {
ctx.GetSessionVars().StmtCtx.AppendWarning(err)
err = nil
}
err = sc.HandleTruncate(err)
}
}
} else {
Expand Down