diff options
Diffstat (limited to 'sql/sql_insert.cc')
-rw-r--r-- | sql/sql_insert.cc | 126 |
1 files changed, 83 insertions, 43 deletions
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 567c7ff2b30..37cc20a07e7 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -88,6 +88,7 @@ static bool check_view_insertability(THD *thd, TABLE_LIST *view); SYNOPSIS check_view_single_update() fields The insert/update fields to be checked. + values Values to use for update view The view for insert. map [in/out] The insert table map. @@ -107,8 +108,8 @@ static bool check_view_insertability(THD *thd, TABLE_LIST *view); 1 Error */ -bool check_view_single_update(List<Item> &fields, TABLE_LIST *view, - table_map *map) +bool check_view_single_update(List<Item> &fields, List<Item> *values, + TABLE_LIST *view, table_map *map) { /* it is join view => we need to find the table for update */ List_iterator_fast<Item> it(fields); @@ -119,6 +120,15 @@ bool check_view_single_update(List<Item> &fields, TABLE_LIST *view, while ((item= it++)) tables|= item->used_tables(); + if (values) + { + it.init(*values); + while ((item= it++)) + tables|= item->used_tables(); + } + + /* Convert to real table bits */ + tables&= ~PSEUDO_TABLE_BITS; /* Check found map against provided map */ if (*map) { @@ -152,6 +162,10 @@ error: fields The insert fields. values The insert values. check_unique If duplicate values should be rejected. + fields_and_values_from_different_maps + Set to 1 if fields and values are using + different table maps, like on select ... insert + map Store here table map for used fields NOTE Clears TIMESTAMP_AUTO_SET_ON_INSERT from table->timestamp_field_type @@ -165,7 +179,9 @@ error: static int check_insert_fields(THD *thd, TABLE_LIST *table_list, List<Item> &fields, List<Item> &values, - bool check_unique, table_map *map) + bool check_unique, + bool fields_and_values_from_different_maps, + table_map *map) { TABLE *table= table_list->table; @@ -238,7 +254,10 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, if (table_list->effective_algorithm == VIEW_ALGORITHM_MERGE) { - if (check_view_single_update(fields, table_list, map)) + if (check_view_single_update(fields, + fields_and_values_from_different_maps ? + (List<Item>*) 0 : &values, + table_list, map)) return -1; table= table_list->table; } @@ -298,10 +317,12 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, */ static int check_update_fields(THD *thd, TABLE_LIST *insert_table_list, - List<Item> &update_fields, table_map *map) + List<Item> &update_fields, + List<Item> &update_values, table_map *map) { TABLE *table= insert_table_list->table; - my_bool timestamp_mark= 0; + my_bool timestamp_mark; + LINT_INIT(timestamp_mark); if (table->timestamp_field) { @@ -318,7 +339,8 @@ static int check_update_fields(THD *thd, TABLE_LIST *insert_table_list, return -1; if (insert_table_list->effective_algorithm == VIEW_ALGORITHM_MERGE && - check_view_single_update(update_fields, insert_table_list, map)) + check_view_single_update(update_fields, &update_values, + insert_table_list, map)) return -1; if (table->timestamp_field) @@ -385,10 +407,9 @@ void prepare_triggers_for_insert_stmt(TABLE *table) downgrade the lock in handler::store_lock() method. */ -static -void upgrade_lock_type(THD *thd, thr_lock_type *lock_type, - enum_duplicates duplic, - bool is_multi_insert) +void upgrade_lock_type_for_insert(THD *thd, thr_lock_type *lock_type, + enum_duplicates duplic, + bool is_multi_insert) { if (duplic == DUP_UPDATE || (duplic == DUP_REPLACE && *lock_type == TL_WRITE_CONCURRENT_INSERT)) @@ -573,6 +594,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, bool transactional_table, joins_freed= FALSE; bool changed; bool was_insert_delayed= (table_list->lock_type == TL_WRITE_DELAYED); + bool using_bulk_insert= 0; uint value_count; ulong counter = 1; ulonglong id; @@ -600,8 +622,8 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, Upgrade lock type if the requested lock is incompatible with the current connection mode or table operation. */ - upgrade_lock_type(thd, &table_list->lock_type, duplic, - values_list.elements > 1); + upgrade_lock_type_for_insert(thd, &table_list->lock_type, duplic, + values_list.elements > 1); /* We can't write-delayed into a table locked with LOCK TABLES: @@ -738,8 +760,11 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, { if (duplic != DUP_ERROR || ignore) table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); - if (!thd->prelocked_mode) + if (!thd->prelocked_mode && values_list.elements > 1) + { + using_bulk_insert= 1; table->file->ha_start_bulk_insert(values_list.elements); + } } thd->abort_on_warning= (!ignore && (thd->variables.sql_mode & @@ -862,7 +887,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, auto_inc values from the delayed_insert thread as they share TABLE. */ table->file->ha_release_auto_increment(); - if (!thd->prelocked_mode && table->file->ha_end_bulk_insert() && !error) + if (using_bulk_insert && table->file->ha_end_bulk_insert() && !error) { table->file->print_error(my_errno,MYF(0)); error=1; @@ -883,7 +908,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, } if ((changed && error <= 0) || thd->transaction.stmt.modified_non_trans_table || - was_insert_delayed) + was_insert_delayed) { if (mysql_bin_log.is_open()) { @@ -1212,7 +1237,7 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, bool res= 0; table_map map= 0; DBUG_ENTER("mysql_prepare_insert"); - DBUG_PRINT("enter", ("table_list 0x%lx, table 0x%lx, view %d", + DBUG_PRINT("enter", ("table_list: 0x%lx table: 0x%lx view: %d", (ulong)table_list, (ulong)table, (int)insert_into_view)); /* INSERT should have a SELECT or VALUES clause */ @@ -1265,9 +1290,9 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, table_list->next_local= 0; context->resolve_in_table_list_only(table_list); - res= check_insert_fields(thd, context->table_list, fields, *values, - !insert_into_view, &map) || - setup_fields(thd, 0, *values, MARK_COLUMNS_READ, 0, 0); + res= (setup_fields(thd, 0, *values, MARK_COLUMNS_READ, 0, 0) || + check_insert_fields(thd, context->table_list, fields, *values, + !insert_into_view, 0, &map)); if (!res && check_fields) { @@ -1280,18 +1305,19 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, thd->abort_on_warning= saved_abort_on_warning; } + if (!res) + res= setup_fields(thd, 0, update_values, MARK_COLUMNS_READ, 0, 0); + if (!res && duplic == DUP_UPDATE) { select_lex->no_wrap_view_item= TRUE; - res= check_update_fields(thd, context->table_list, update_fields, &map); + res= check_update_fields(thd, context->table_list, update_fields, + update_values, &map); select_lex->no_wrap_view_item= FALSE; } /* Restore the current context. */ ctx_state.restore_state(context, table_list); - - if (!res) - res= setup_fields(thd, 0, update_values, MARK_COLUMNS_READ, 0, 0); } if (res) @@ -1483,7 +1509,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) table->file->adjust_next_insert_id_after_explicit_value( table->next_number_field->val_int()); info->touched++; - if ((table->file->ha_table_flags() & HA_PARTIAL_COLUMN_READ && + if (((table->file->ha_table_flags() & HA_PARTIAL_COLUMN_READ) && !bitmap_is_subset(table->write_set, table->read_set)) || compare_record(table)) { @@ -1767,7 +1793,8 @@ public: thd.system_thread= SYSTEM_THREAD_DELAYED_INSERT; thd.security_ctx->host_or_ip= ""; bzero((char*) &info,sizeof(info)); - pthread_mutex_init(&mutex,MY_MUTEX_INIT_FAST); + my_pthread_mutex_init(&mutex, MY_MUTEX_INIT_FAST, "Delayed_insert::mutex", + 0); pthread_cond_init(&cond,NULL); pthread_cond_init(&cond_client,NULL); VOID(pthread_mutex_lock(&LOCK_thread_count)); @@ -2277,6 +2304,7 @@ void kill_delayed_threads(void) while ((di= it++)) { di->thd.killed= THD::KILL_CONNECTION; + pthread_mutex_lock(&di->thd.LOCK_thd_data); if (di->thd.mysys_var) { pthread_mutex_lock(&di->thd.mysys_var->mutex); @@ -2287,13 +2315,15 @@ void kill_delayed_threads(void) in handle_delayed_insert() */ if (&di->mutex != di->thd.mysys_var->current_mutex) - pthread_mutex_lock(di->thd.mysys_var->current_mutex); + my_pthread_mutex_lock(di->thd.mysys_var->current_mutex, + MYF_NO_DEADLOCK_DETECTION); pthread_cond_broadcast(di->thd.mysys_var->current_cond); if (&di->mutex != di->thd.mysys_var->current_mutex) pthread_mutex_unlock(di->thd.mysys_var->current_mutex); } pthread_mutex_unlock(&di->thd.mysys_var->mutex); } + pthread_mutex_unlock(&di->thd.LOCK_thd_data); } VOID(pthread_mutex_unlock(&LOCK_delayed_insert)); // For unlink from list } @@ -2541,13 +2571,14 @@ end: clients */ - close_thread_tables(thd); // Free the table di->table=0; di->dead= 1; // If error thd->killed= THD::KILL_CONNECTION; // If error - pthread_cond_broadcast(&di->cond_client); // Safety pthread_mutex_unlock(&di->mutex); + close_thread_tables(thd); // Free the table + pthread_cond_broadcast(&di->cond_client); // Safety + pthread_mutex_lock(&LOCK_delayed_create); // Because of delayed_get_table pthread_mutex_lock(&LOCK_delayed_insert); delete di; @@ -2612,7 +2643,7 @@ bool Delayed_insert::handle_inserts(void) or if another thread is removing the current table definition from the table cache. */ - my_error(ER_DELAYED_CANT_CHANGE_LOCK,MYF(ME_FATALERROR), + my_error(ER_DELAYED_CANT_CHANGE_LOCK, MYF(ME_FATALERROR | ME_NOREFRESH), table->s->table_name.str); goto err; } @@ -2786,10 +2817,11 @@ bool Delayed_insert::handle_inserts(void) query_cache_invalidate3(&thd, table, 1); if (thr_reschedule_write_lock(*thd.lock->locks)) { - /* This is not known to happen. */ - my_error(ER_DELAYED_CANT_CHANGE_LOCK,MYF(ME_FATALERROR), - table->s->table_name.str); - goto err; + /* This is not known to happen. */ + my_error(ER_DELAYED_CANT_CHANGE_LOCK, + MYF(ME_FATALERROR | ME_NOREFRESH), + table->s->table_name.str); + goto err; } if (!using_bin_log) table->file->extra(HA_EXTRA_WRITE_CACHE); @@ -2964,10 +2996,9 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u) /* Errors during check_insert_fields() should not be ignored. */ lex->current_select->no_error= FALSE; - res= check_insert_fields(thd, table_list, *fields, values, - !insert_into_view, &map) || - setup_fields(thd, 0, values, MARK_COLUMNS_READ, 0, 0); - + res= (setup_fields(thd, 0, values, MARK_COLUMNS_READ, 0, 0) || + check_insert_fields(thd, table_list, *fields, values, + !insert_into_view, 1, &map)); if (!res && fields->elements) { bool saved_abort_on_warning= thd->abort_on_warning; @@ -2993,7 +3024,8 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u) lex->select_lex.no_wrap_view_item= TRUE; res= res || check_update_fields(thd, context->table_list, - *info.update_fields, &map); + *info.update_fields, *info.update_values, + &map); lex->select_lex.no_wrap_view_item= FALSE; /* When we are not using GROUP BY and there are no ungrouped aggregate functions @@ -3248,12 +3280,11 @@ bool select_insert::send_eof() DBUG_PRINT("enter", ("trans_table=%d, table_type='%s'", trans_table, table->file->table_type())); - error= (!thd->prelocked_mode) ? table->file->ha_end_bulk_insert():0; + error= (!thd->prelocked_mode) ? table->file->ha_end_bulk_insert() : 0; table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE); - changed= (info.copied || info.deleted || info.updated); - if (changed) + if ((changed= (info.copied || info.deleted || info.updated))) { /* We must invalidate the table in the query cache before binlog writing @@ -3549,10 +3580,12 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, Create_field *cr_field; Field *field, *def_field; if (item->type() == Item::FUNC_ITEM) + { if (item->result_type() != STRING_RESULT) field= item->tmp_table_field(&tmp_table); else field= item->tmp_table_field_from_field_type(&tmp_table, 0); + } else field= create_tmp_field(thd, &tmp_table, item, item->type(), (Item ***) 0, &tmp_field, &def_field, 0, 0, 0, 0, @@ -3647,6 +3680,12 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, MYSQL_LOCK_IGNORE_FLUSH, ¬_used)) || hooks->postlock(&table, 1)) { + /* purecov: begin tested */ + /* + This can happen in innodb when you get a deadlock when using same table + in insert and select + */ + my_error(ER_CANT_LOCK, MYF(0), my_errno); if (*lock) { mysql_unlock_tables(thd, *lock); @@ -3656,6 +3695,7 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, if (!create_info->table_existed) drop_open_table(thd, table, create_table->db, create_table->table_name); DBUG_RETURN(0); + /* purecov: end */ } DBUG_RETURN(table); } @@ -3786,7 +3826,7 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u) DBUG_RETURN(-1); } - /* First field to copy */ + /* First field to copy */ field= table->field+table->s->fields - values.elements; /* Mark all fields that are given values */ |