diff options
Diffstat (limited to 'sql/sql_base.cc')
-rw-r--r-- | sql/sql_base.cc | 157 |
1 files changed, 141 insertions, 16 deletions
diff --git a/sql/sql_base.cc b/sql/sql_base.cc index e5191feba14..69b867da0cb 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -3528,7 +3528,7 @@ open_and_process_table(THD *thd, LEX *lex, TABLE_LIST *tables, */ if (thd->locked_tables_mode <= LTM_LOCK_TABLES && ! has_prelocking_list && - tables->lock_type >= TL_WRITE_ALLOW_WRITE) + (tables->lock_type >= TL_WRITE_ALLOW_WRITE || thd->lex->default_used)) { bool need_prelocking= FALSE; TABLE_LIST **save_query_tables_last= lex->query_tables_last; @@ -4234,7 +4234,7 @@ static bool table_already_fk_prelocked(TABLE_LIST *tl, LEX_CSTRING *db, for (; tl; tl= tl->next_global ) { if (tl->lock_type >= lock_type && - tl->prelocking_placeholder == TABLE_LIST::FK && + tl->prelocking_placeholder == TABLE_LIST::PRELOCK_FK && strcmp(tl->db, db->str) == 0 && strcmp(tl->table_name, table->str) == 0) return true; @@ -4243,6 +4243,55 @@ static bool table_already_fk_prelocked(TABLE_LIST *tl, LEX_CSTRING *db, } +static bool internal_table_exists(TABLE_LIST *global_list, + const char *table_name) +{ + do + { + if (global_list->table_name == table_name) + return 1; + } while ((global_list= global_list->next_global)); + return 0; +} + + +static bool +add_internal_tables(THD *thd, Query_tables_list *prelocking_ctx, + TABLE_LIST *tables) +{ + TABLE_LIST *global_table_list= prelocking_ctx->query_tables; + + do + { + /* + Skip table if already in the list. Can happen with prepared statements + */ + if (tables->next_local && + internal_table_exists(global_table_list, tables->table_name)) + continue; + + TABLE_LIST *tl= (TABLE_LIST *) thd->alloc(sizeof(TABLE_LIST)); + if (!tl) + return TRUE; + tl->init_one_table_for_prelocking(tables->db, + strlen(tables->db), + tables->table_name, + strlen(tables->table_name), + NULL, tables->lock_type, + TABLE_LIST::PRELOCK_NONE, + 0, 0, + &prelocking_ctx->query_tables_last); + /* + Store link to the new table_list that will be used by open so that + Item_func_nextval() can find it + */ + tables->next_local= tl; + } while ((tables= tables->next_global)); + return FALSE; +} + + + /** Defines how prelocking algorithm for DML statements should handle table list elements: @@ -4269,21 +4318,23 @@ bool DML_prelocking_strategy:: handle_table(THD *thd, Query_tables_list *prelocking_ctx, TABLE_LIST *table_list, bool *need_prelocking) { + TABLE *table= table_list->table; /* We rely on a caller to check that table is going to be changed. */ - DBUG_ASSERT(table_list->lock_type >= TL_WRITE_ALLOW_WRITE); + DBUG_ASSERT(table_list->lock_type >= TL_WRITE_ALLOW_WRITE || + thd->lex->default_used); if (table_list->trg_event_map) { - if (table_list->table->triggers) + if (table->triggers) { *need_prelocking= TRUE; - if (table_list->table->triggers-> + if (table->triggers-> add_tables_and_routines_for_triggers(thd, prelocking_ctx, table_list)) return TRUE; } - if (table_list->table->file->referenced_by_foreign_key()) + if (table->file->referenced_by_foreign_key()) { List <FOREIGN_KEY_INFO> fk_list; List_iterator<FOREIGN_KEY_INFO> fk_list_it(fk_list); @@ -4292,7 +4343,7 @@ handle_table(THD *thd, Query_tables_list *prelocking_ctx, arena= thd->activate_stmt_arena_if_needed(&backup); - table_list->table->file->get_parent_foreign_key_list(thd, &fk_list); + table->file->get_parent_foreign_key_list(thd, &fk_list); if (thd->is_error()) { if (arena) @@ -4321,21 +4372,96 @@ handle_table(THD *thd, Query_tables_list *prelocking_ctx, 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); + 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, + TABLE_LIST::PRELOCK_FK, + table_list->belong_to_view, op, + &prelocking_ctx->query_tables_last); } if (arena) thd->restore_active_arena(arena, &backup); } } + /* Open any tables used by DEFAULT (like sequence tables) */ + if (table->internal_tables && + ((sql_command_flags[thd->lex->sql_command] & CF_INSERTS_DATA) || + thd->lex->default_used)) + { + Query_arena *arena, backup; + bool error; + arena= thd->activate_stmt_arena_if_needed(&backup); + error= add_internal_tables(thd, prelocking_ctx, + table->internal_tables); + if (arena) + thd->restore_active_arena(arena, &backup); + if (error) + { + *need_prelocking= TRUE; + return TRUE; + } + } return FALSE; } /** + Open all tables used by DEFAULT functions. + + This is different from normal open_and_lock_tables() as we may + already have other tables opened and locked and we have to merge the + new table with the old ones. +*/ + +bool open_and_lock_internal_tables(TABLE *table, bool lock_table) +{ + THD *thd= table->in_use; + TABLE_LIST *tl; + MYSQL_LOCK *save_lock,*new_lock; + DBUG_ENTER("open_internal_tables"); + + /* remove pointer to old select_lex which is already destroyed */ + for (tl= table->internal_tables ; tl ; tl= tl->next_global) + tl->select_lex= 0; + + uint counter; + MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint(); + TABLE_LIST *tmp= table->internal_tables; + DML_prelocking_strategy prelocking_strategy; + + if (open_tables(thd, thd->lex->create_info, &tmp, &counter, 0, + &prelocking_strategy)) + goto err; + + if (lock_table) + { + save_lock= thd->lock; + thd->lock= 0; + if (lock_tables(thd, table->internal_tables, counter, + MYSQL_LOCK_USE_MALLOC)) + goto err; + + if (!(new_lock= mysql_lock_merge(save_lock, thd->lock))) + { + thd->lock= save_lock; + mysql_unlock_tables(thd, save_lock, 1); + /* We don't have to close tables as caller will do that */ + goto err; + } + thd->lock= new_lock; + } + DBUG_RETURN(0); + +err: + thd->mdl_context.rollback_to_savepoint(mdl_savepoint); + DBUG_RETURN(1); +} + + +/** Defines how prelocking algorithm for DML statements should handle view - all view routines should be added to the prelocking set. @@ -4486,7 +4612,7 @@ static bool check_lock_and_start_stmt(THD *thd, Prelocking placeholder is not set for TABLE_LIST that are directly used by TOP level statement. */ - DBUG_ASSERT(table_list->prelocking_placeholder == false); + DBUG_ASSERT(table_list->prelocking_placeholder == TABLE_LIST::PRELOCK_NONE); /* TL_WRITE_DEFAULT and TL_READ_DEFAULT are supposed to be parser only @@ -4499,7 +4625,6 @@ static bool check_lock_and_start_stmt(THD *thd, Last argument routine_modifies_data for read_lock_type_for_table() is ignored, as prelocking placeholder will never be set here. */ - DBUG_ASSERT(table_list->prelocking_placeholder == false); if (table_list->lock_type == TL_WRITE_DEFAULT) lock_type= thd->update_lock_default; else if (table_list->lock_type == TL_READ_DEFAULT) @@ -4507,8 +4632,8 @@ static bool check_lock_and_start_stmt(THD *thd, else lock_type= table_list->lock_type; - if ((int) lock_type > (int) TL_WRITE_ALLOW_WRITE && - (int) table_list->table->reginfo.lock_type <= (int) TL_WRITE_ALLOW_WRITE) + if ((int) lock_type >= (int) TL_WRITE_ALLOW_WRITE && + (int) table_list->table->reginfo.lock_type < (int) TL_WRITE_ALLOW_WRITE) { my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0), table_list->table->alias.c_ptr()); @@ -5532,7 +5657,7 @@ find_field_in_table(THD *thd, TABLE *table, const char *name, uint length, DBUG_EVALUATE_IF("test_completely_invisible", 0, 1)) DBUG_RETURN((Field*)0); - *cached_field_index_ptr= field_ptr - table->field; + *cached_field_index_ptr= (uint)(field_ptr - table->field); field= *field_ptr; } else |