1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-29 05:21:33 +03:00

extend prelocking to FK-accessed tables

Backport of f136291098
This commit is contained in:
Sergei Golubchik
2018-07-17 16:56:40 +02:00
parent 3b365fa829
commit 64a23c1c8a
6 changed files with 157 additions and 4 deletions

View File

@ -4802,6 +4802,25 @@ handle_routine(THD *thd, Query_tables_list *prelocking_ctx,
}
/*
@note this can be changed to use a hash, instead of scanning the linked
list, if the performance of this function will ever become an issue
*/
static bool table_already_fk_prelocked(TABLE_LIST *tl, LEX_STRING *db,
LEX_STRING *table, thr_lock_type lock_type)
{
for (; tl; tl= tl->next_global )
{
if (tl->lock_type >= lock_type &&
tl->prelocking_placeholder == TABLE_LIST::FK &&
strcmp(tl->db, db->str) == 0 &&
strcmp(tl->table_name, table->str) == 0)
return true;
}
return false;
}
/**
Defines how prelocking algorithm for DML statements should handle table list
elements:
@ -4841,6 +4860,52 @@ handle_table(THD *thd, Query_tables_list *prelocking_ctx,
add_tables_and_routines_for_triggers(thd, prelocking_ctx, table_list))
return TRUE;
}
if (table_list->table->file->referenced_by_foreign_key())
{
List <FOREIGN_KEY_INFO> fk_list;
List_iterator<FOREIGN_KEY_INFO> fk_list_it(fk_list);
FOREIGN_KEY_INFO *fk;
Query_arena *arena, backup;
arena= thd->activate_stmt_arena_if_needed(&backup);
table_list->table->file->get_parent_foreign_key_list(thd, &fk_list);
if (thd->is_error())
{
if (arena)
thd->restore_active_arena(arena, &backup);
return TRUE;
}
*need_prelocking= TRUE;
while ((fk= fk_list_it++))
{
// FK_OPTION_RESTRICT and FK_OPTION_NO_ACTION only need read access
static bool can_write[]= { true, false, true, true, false, true };
uint8 op= table_list->trg_event_map;
thr_lock_type lock_type;
if ((op & (1 << TRG_EVENT_DELETE) && can_write[fk->delete_method])
|| (op & (1 << TRG_EVENT_UPDATE) && can_write[fk->update_method]))
lock_type= TL_WRITE_ALLOW_WRITE;
else
lock_type= TL_READ;
if (table_already_fk_prelocked(table_list, fk->foreign_db,
fk->foreign_table, lock_type))
continue;
TABLE_LIST *tl= (TABLE_LIST *) thd->alloc(sizeof(TABLE_LIST));
tl->init_one_table_for_prelocking(fk->foreign_db->str, fk->foreign_db->length,
fk->foreign_table->str, fk->foreign_table->length,
NULL, lock_type, false, table_list->belong_to_view,
op, &prelocking_ctx->query_tables_last);
}
if (arena)
thd->restore_active_arena(arena, &backup);
}
}
return FALSE;