@@ -30,6 +30,7 @@ import (
30
30
"github.com/pingcap/tidb/parser/model"
31
31
"github.com/pingcap/tidb/parser/mysql"
32
32
"github.com/pingcap/tidb/parser/terror"
33
+ "github.com/pingcap/tidb/sessionctx"
33
34
"github.com/pingcap/tidb/table"
34
35
"github.com/pingcap/tidb/table/tables"
35
36
"github.com/pingcap/tidb/tablecodec"
@@ -196,7 +197,15 @@ func (e *InsertValues) prefetchDataCache(ctx context.Context, txn kv.Transaction
196
197
}
197
198
198
199
// updateDupRow updates a duplicate row to a new row.
199
- func (e * InsertExec ) updateDupRow (ctx context.Context , idxInBatch int , txn kv.Transaction , row toBeCheckedRow , handle kv.Handle , onDuplicate []* expression.Assignment , autoColIdx int ) error {
200
+ func (e * InsertExec ) updateDupRow (
201
+ ctx context.Context ,
202
+ idxInBatch int ,
203
+ txn kv.Transaction ,
204
+ row toBeCheckedRow ,
205
+ handle kv.Handle ,
206
+ _ []* expression.Assignment ,
207
+ autoColIdx int ,
208
+ ) error {
200
209
oldRow , err := getOldRow (ctx , e .ctx , txn , row .t , handle , e .GenExprs )
201
210
if err != nil {
202
211
return err
@@ -394,8 +403,14 @@ func (e *InsertExec) initEvalBuffer4Dup() {
394
403
}
395
404
396
405
// doDupRowUpdate updates the duplicate row.
397
- func (e * InsertExec ) doDupRowUpdate (ctx context.Context , handle kv.Handle , oldRow []types.Datum , newRow []types.Datum ,
398
- extraCols []types.Datum , cols []* expression.Assignment , idxInBatch int , autoColIdx int ) error {
406
+ func (e * InsertExec ) doDupRowUpdate (
407
+ ctx context.Context ,
408
+ handle kv.Handle ,
409
+ oldRow , newRow , extraCols []types.Datum ,
410
+ assigns []* expression.Assignment ,
411
+ idxInBatch int ,
412
+ autoColIdx int ,
413
+ ) error {
399
414
assignFlag := make ([]bool , len (e .Table .WritableCols ()))
400
415
// See http://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html#function_values
401
416
e .curInsertVals .SetDatums (newRow ... )
@@ -409,40 +424,71 @@ func (e *InsertExec) doDupRowUpdate(ctx context.Context, handle kv.Handle, oldRo
409
424
e .row4Update = append (e .row4Update , extraCols ... )
410
425
e .row4Update = append (e .row4Update , newRow ... )
411
426
412
- // Update old row when the key is duplicated.
413
- e .evalBuffer4Dup .SetDatums (e .row4Update ... )
414
- sc := e .ctx .GetSessionVars ().StmtCtx
415
- warnCnt := int (sc .WarningCount ())
416
- for _ , col := range cols {
417
- if col .LazyErr != nil {
418
- return col .LazyErr
419
- }
420
- val , err1 := col .Expr .Eval (e .evalBuffer4Dup .ToRow ())
421
- if err1 != nil {
422
- return err1
423
- }
424
- c := col .Col .ToInfo ()
425
- c .Name = col .ColName
426
- e .row4Update [col .Col .Index ], err1 = table .CastValue (e .ctx , val , c , false , false )
427
- if err1 != nil {
428
- return err1
427
+ // Only evaluate non-generated columns here,
428
+ // other fields will be evaluated in updateRecord.
429
+ var generated , nonGenerated []* expression.Assignment
430
+ cols := e .Table .Cols ()
431
+ for _ , assign := range assigns {
432
+ if cols [assign .Col .Index ].IsGenerated () {
433
+ generated = append (generated , assign )
434
+ } else {
435
+ nonGenerated = append (nonGenerated , assign )
429
436
}
437
+ }
438
+
439
+ warnCnt := int (e .ctx .GetSessionVars ().StmtCtx .WarningCount ())
440
+ errorHandler := func (sctx sessionctx.Context , assign * expression.Assignment , val * types.Datum , err error ) error {
441
+ c := assign .Col .ToInfo ()
442
+ c .Name = assign .ColName
443
+ sc := sctx .GetSessionVars ().StmtCtx
444
+
430
445
if newWarnings := sc .TruncateWarnings (warnCnt ); len (newWarnings ) > 0 {
431
446
for k := range newWarnings {
432
447
// Use `idxInBatch` here for simplicity, since the offset of the batch is unknown under the current context.
433
- newWarnings [k ].Err = completeInsertErr (c , & val , idxInBatch , newWarnings [k ].Err )
448
+ newWarnings [k ].Err = completeInsertErr (c , val , idxInBatch , newWarnings [k ].Err )
434
449
}
435
450
sc .AppendWarnings (newWarnings )
436
451
warnCnt += len (newWarnings )
437
452
}
438
- e .evalBuffer4Dup .SetDatum (col .Col .Index , e .row4Update [col .Col .Index ])
439
- assignFlag [col .Col .Index ] = true
453
+ return err
454
+ }
455
+
456
+ // Update old row when the key is duplicated.
457
+ e .evalBuffer4Dup .SetDatums (e .row4Update ... )
458
+ for _ , assign := range nonGenerated {
459
+ var val types.Datum
460
+ if assign .LazyErr != nil {
461
+ return assign .LazyErr
462
+ }
463
+ val , err := assign .Expr .Eval (e .evalBuffer4Dup .ToRow ())
464
+ if err != nil {
465
+ return err
466
+ }
467
+
468
+ c := assign .Col .ToInfo ()
469
+ idx := assign .Col .Index
470
+ c .Name = assign .ColName
471
+ val , err = table .CastValue (e .ctx , val , c , false , false )
472
+ if err != nil {
473
+ return err
474
+ }
475
+
476
+ _ = errorHandler (e .ctx , assign , & val , nil )
477
+ e .evalBuffer4Dup .SetDatum (idx , val )
478
+ e .row4Update [assign .Col .Index ] = val
479
+ assignFlag [assign .Col .Index ] = true
440
480
}
441
481
442
482
newData := e .row4Update [:len (oldRow )]
443
- _ , err := updateRecord (ctx , e .ctx , handle , oldRow , newData , assignFlag , e .Table , true , e .memTracker , e .fkChecks , e .fkCascades )
483
+ _ , err := updateRecord (
484
+ ctx , e .ctx ,
485
+ handle , oldRow , newData ,
486
+ 0 , generated , e .evalBuffer4Dup , errorHandler ,
487
+ assignFlag , e .Table ,
488
+ true , e .memTracker , e .fkChecks , e .fkCascades )
489
+
444
490
if err != nil {
445
- return err
491
+ return errors . Trace ( err )
446
492
}
447
493
448
494
if autoColIdx >= 0 {
0 commit comments