• Aleksey Midenkov's avatar
    MDEV-25644 UPDATE not working properly on transaction precise system versioned table · 14cc7e7d
    Aleksey Midenkov authored
    First UPDATE under START TRANSACTION does nothing (nstate= nstate),
    but anyway generates history. Since update vector is empty we get into
    (!uvect->n_fields) branch which only adds history row, but does not do
    update. After that we get current row with wrong (old) row_start value
    and because of that second UPDATE tries to insert history row again
    because it sees trx->id != row_start which is the guard to avoid
    inserting multiple trx_id-based history rows under same transaction
    (because we have same trx_id and we get duplicate error and this bug
    demostrates that). But this try anyway fails because PK is based on
    row_end which is constant under same transaction, so PK didn't change.
    
    The fix moves vers_make_update() to an earlier stage of
    calc_row_difference(). Therefore it prepares update vector before
    (!uvect->n_fields) check and never gets into that branch, hence no
    need to handle versioning inside that condition anymore.
    
    Now trx->id and row_start are equal after first UPDATE and we don't
    try to insert second history row.
    
    == Cleanups and improvements ==
    
    ha_innobase::update_row():
    
    vers_set_fields and vers_ins_row are cleaned up into direct condition
    check. SQLCOM_ALTER_TABLE check now is not used as this is dead code,
    assertion is done instead.
    
    upd_node->is_delete is set in calc_row_difference() just to keep
    versioning code as much in one place as possible. vers_make_delete()
    is still located in row_update_for_mysql() as this is required for
    ha_innodbase::delete_row() as well.
    
    row_ins_duplicate_error_in_clust():
    
    Restrict DB_FOREIGN_DUPLICATE_KEY to the better conditions.
    VERSIONED_DELETE is used specifically to help lower stack to
    understand what caused current insert. Related to MDEV-29813.
    14cc7e7d
ha_innodb.cc 624 KB