MDEV-21540 Initialization of already inited long unique index on reorganize partition

Handler for existing partition was already index-inited at the
beginning of copy_partitions().

In the case of REORGANIZE PARTITION we fill new partition by calling
its ha_write_row() (handler is storage engine of new partition). From
that we go through the below conditions:

    if (this->inited == RND)
      table->clone_handler_for_update();
    handler *h= table->update_handler ? table->update_handler : table->file;

First, the above misses the meaning of this->inited check. Now it is
new partition and this handler is not inited. So, we assign
table->file which is ha_partition and is really not known to be inited
or not. It is supposed (this == table->file), otherwise we are
out of the logic for using update_handler. This patch adds DBUG_ASSERT
for that.

Second, we call check_duplicate_long_entries() for table->file and
that calls ha_partition::index_init() which calls index_init() for
each partition's handler. But the existing parititions' handlers was
already inited in copy_partitions() and we fail on assertion.

The fix implies that we don't need check_duplicate_long_entries()
per-partition as we've already done check_duplicate_long_entries() for
ha_partition. For REORGANIZE PARTITION that means existing row was
already checked at previous INSERT/UPDATE commands, so no need to
check it again (see NOTE in handler::ha_write_row()).

The fix also optimizes ha_update_row() so
check_duplicate_long_entries_update() is not called per-partition
considering it was already called for ha_partition. Besides,
per-partition duplicate check is not really usable.
This commit is contained in:
Aleksey Midenkov 2022-08-01 11:13:50 +03:00
commit 231feabd2b
3 changed files with 69 additions and 3 deletions

View file

@ -6782,7 +6782,18 @@ int handler::ha_write_row(const uchar *buf)
mark_trx_read_write();
increment_statistics(&SSV::ha_write_count);
if (table->s->long_unique_table)
/*
NOTE: this != table->file is true in 3 cases:
1. under copy_partitions() (REORGANIZE PARTITION): that does not
require long unique check as it does not introduce new rows or new index.
2. under partition's ha_write_row() (INSERT): check_duplicate_long_entries()
was already done by ha_partition::ha_write_row(), no need to check it
again for each single partition.
3. under ha_mroonga::wrapper_write_row()
*/
if (table->s->long_unique_table && this == table->file)
{
if (this->inited == RND)
table->clone_handler_for_update();
@ -6830,8 +6841,17 @@ int handler::ha_update_row(const uchar *old_data, const uchar *new_data)
MYSQL_UPDATE_ROW_START(table_share->db.str, table_share->table_name.str);
mark_trx_read_write();
increment_statistics(&SSV::ha_update_count);
if (table->s->long_unique_table &&
(error= check_duplicate_long_entries_update(table, table->file, (uchar *)new_data)))
/*
NOTE: this != table->file is true under partition's ha_update_row():
check_duplicate_long_entries_update() was already done by
ha_partition::ha_update_row(), no need to check it again for each single
partition. Same applies to ha_mroonga wrapper.
*/
if (table->s->long_unique_table && this == table->file &&
(error= check_duplicate_long_entries_update(table, table->file,
(uchar *)new_data)))
{
return error;
}