Repository: pingcap/tidb
File: pkg/executor/insert_common.go (Go)

Code before:
			err = errors.NotFoundf("can not be duplicated row, due to old row not found. handle %s", handle)
		}
		return false, err
	}
	return e.removeOldRow(txn, handle, oldRow, r, inReplace)
}

// 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 and return (true, nil).
func (e *InsertValues) removeOldRow(
	txn kv.Transaction,
	handle kv.Handle,
	oldRow []types.Datum,
	r toBeCheckedRow,
	inReplace bool,
) (bool, error) {
	newRow := r.row
	identical, err := e.equalDatumsAsBinary(oldRow, newRow)
	if err != nil {
		return false, err
	}

	// isRemoveSoftDeleteRow indicates whether we are removing an old soft-deleted row.
	// This condition may affect whether we should add affected rows count or not to make sure the soft-delete
	// should behaviors the same as normal delete in terms of affected rows count.
	// If `SoftDeleteRewrite` is false, we should also recognize the old row as an exist-row because in this mode,
	// the soft=delete row should be regarded as a normal one.
	isRemoveSoftDeleteRow := e.isRowSoftDeleted(oldRow) && e.Ctx().GetSessionVars().SoftDeleteRewrite
	if identical {
		if inReplace && !isRemoveSoftDeleteRow {
			e.Ctx().GetSessionVars().StmtCtx.AddAffectedRows(1)
		}
		keySet := lockRowKey
		if e.Ctx().GetSessionVars().LockUnchangedKeys {
			keySet |= lockUniqueKeys
		}
		if _, err := addUnchangedKeysForLockByRow(e.Ctx(), r.t, handle, oldRow, keySet); err != nil {
			return false, err
		}
		return true, nil
	}

	if ph, ok := handle.(kv.PartitionHandle); ok {
		err = e.Table.(table.PartitionedTable).GetPartition(ph.PartitionID).RemoveRecord(e.Ctx().GetTableCtx(), txn, ph.Handle, oldRow)
	} else {
		err = r.t.RemoveRecord(e.Ctx().GetTableCtx(), txn, handle, oldRow)
	}
	if err != nil {
		return false, err
	}

Review comment (suggestion):
Typo in comment: "should behaviors" should be "should behave".
```suggestion
	// should behave the same as normal delete in terms of affected rows count.
```

Code after:
			err = errors.NotFoundf("can not be duplicated row, due to old row not found. handle %s", handle)
		}
		return false, err
	}
	return e.removeOldRow(txn, handle, oldRow, r, inReplace)
}

// 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 and return (true, nil).
func (e *InsertValues) removeOldRow(
	txn kv.Transaction,
	handle kv.Handle,
	oldRow []types.Datum,
	r toBeCheckedRow,
	inReplace bool,
) (bool, error) {
	newRow := r.row
	identical, err := e.equalDatumsAsBinary(oldRow, newRow)
	if err != nil {
		return false, err
	}

	// isRemoveSoftDeleteRow indicates whether we are removing an old soft-deleted row.
	// This condition may affect whether we should add affected rows count or not to make sure the soft-delete
	// should behave the same as normal delete in terms of affected rows count.
	// If `SoftDeleteRewrite` is false, we should also recognize the old row as an exist-row because in this mode,
	// the soft-delete row should be regarded as a normal one.
	isRemoveSoftDeleteRow := e.isRowSoftDeleted(oldRow) && e.Ctx().GetSessionVars().SoftDeleteRewrite
	if identical {
		if inReplace && !isRemoveSoftDeleteRow {
			e.Ctx().GetSessionVars().StmtCtx.AddAffectedRows(1)
		}
		keySet := lockRowKey
		if e.Ctx().GetSessionVars().LockUnchangedKeys {
			keySet |= lockUniqueKeys
		}
		if _, err := addUnchangedKeysForLockByRow(e.Ctx(), r.t, handle, oldRow, keySet); err != nil {
			return false, err
		}
		return true, nil
	}

	if ph, ok := handle.(kv.PartitionHandle); ok {
		err = e.Table.(table.PartitionedTable).GetPartition(ph.PartitionID).RemoveRecord(e.Ctx().GetTableCtx(), txn, ph.Handle, oldRow)
	} else {
		err = r.t.RemoveRecord(e.Ctx().GetTableCtx(), txn, handle, oldRow)
	}
	if err != nil {
		return false, err
	}