code: func (e *ReplaceExec) removeRow(handle int64, r toBeCheckedRow) (bool, error) {
  	newRow := r.row
  	oldRow, err := e.batchChecker.getOldRow(e.ctx, r.t, handle)
  	if err != nil {
  		logutil.Logger(context.Background()).Error("get old row failed when replace", zap.Int64("handle", handle), zap.String("toBeInsertedRow", types.DatumsToStrNoErr(r.row)))
  		return false, err
  	}
  	rowUnchanged, err := types.EqualDatums(e.ctx.GetSessionVars().StmtCtx, oldRow, newRow)
  	if err != nil {
  		return false, err
  	}
  	if rowUnchanged {
  		e.ctx.GetSessionVars().StmtCtx.AddAffectedRows(1)
  		return true, nil
  	}
  
  	err = r.t.RemoveRecord(e.ctx, handle, oldRow)
  	if err != nil {
  		return false, err
  	}
  	e.ctx.GetSessionVars().StmtCtx.AddAffectedRows(1)
  
  	// Cleanup keys map, because the record was removed.
  	err = e.deleteDupKeys(e.ctx, r.t, [][]types.Datum{oldRow})
  	if err != nil {
  		return false, err
  	}
  	return false, nil
  }
docs: // removeRow removes the duplicate row and cleanup its keys in the key-value map,
  // but if the to-be-removed row equals to the to-be-added row, no remove or add things to do.