MDEV-23547 InnoDB: Failing assertion: *len in row_upd_ext_fetch

This bug was originally repeated on 10.4 after defining a UNIQUE KEY
on a TEXT column, which is implemented by MDEV-371 by creating the
index on a hidden virtual column.

While row_vers_vc_matches_cluster() is executing in a purge thread
to find out if an index entry may be removed in a secondary index
that comprises a virtual column, another purge thread may process
the undo log record that this check is interested in, and write
a null BLOB pointer in that record. This would trip the assertion.

To prevent this from occurring, we must propagate the 'missing BLOB'
error up the call stack.

row_upd_ext_fetch(): Return NULL when the error occurs.

row_upd_index_replace_new_col_val(): Return whether the previous
version was built successfully.

row_upd_index_replace_new_col_vals_index_pos(): Check the error
result. Yes, we would intentionally crash on this error if it
occurs outside the purge thread.

row_upd_index_replace_new_col_vals(): Check for the error condition,
and simplify the logic.

trx_undo_prev_version_build(): Check for the error condition.
This commit is contained in:
Marko Mäkelä 2020-08-25 15:32:15 +03:00
commit 8cf8ad86d4
3 changed files with 78 additions and 85 deletions

View file

@ -257,24 +257,18 @@ row_upd_index_replace_new_col_vals_index_pos(
mem_heap_t* heap) /*!< in: memory heap for allocating and
copying the new values */
MY_ATTRIBUTE((nonnull));
/***********************************************************//**
Replaces the new column values stored in the update vector to the index entry
given. */
void
row_upd_index_replace_new_col_vals(
/*===============================*/
dtuple_t* entry, /*!< in/out: index entry where replaced;
the clustered index record must be
covered by a lock or a page latch to
prevent deletion (rollback or purge) */
dict_index_t* index, /*!< in: index; NOTE that this may also be a
non-clustered index */
const upd_t* update, /*!< in: an update vector built for the
CLUSTERED index so that the field number in
an upd_field is the clustered index position */
mem_heap_t* heap) /*!< in: memory heap for allocating and
copying the new values */
MY_ATTRIBUTE((nonnull));
/** Replace the new column values stored in the update vector,
during trx_undo_prev_version_build().
@param entry clustered index tuple where the values are replaced
(the clustered index leaf page latch must be held)
@param index clustered index
@param update update vector for the clustered index
@param heap memory heap for allocating and copying values
@return whether the previous version was built successfully */
bool
row_upd_index_replace_new_col_vals(dtuple_t *entry, const dict_index_t &index,
const upd_t *update, mem_heap_t *heap)
MY_ATTRIBUTE((nonnull, warn_unused_result));
/***********************************************************//**
Replaces the new column values stored in the update vector. */
void