diff options
Diffstat (limited to 'sql/handler.cc')
-rw-r--r-- | sql/handler.cc | 157 |
1 files changed, 92 insertions, 65 deletions
diff --git a/sql/handler.cc b/sql/handler.cc index 64d13d1601f..01825c13da6 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -188,7 +188,7 @@ private: static int commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans, - bool is_real_trans, bool rw_trans); + bool is_real_trans); static plugin_ref ha_default_plugin(THD *thd) @@ -1621,9 +1621,37 @@ int ha_commit_trans(THD *thd, bool all) /* rw_trans is TRUE when we in a transaction changing data */ bool rw_trans= is_real_trans && (rw_ha_count > (thd->is_current_stmt_binlog_disabled()?0U:1U)); + MDL_request mdl_backup; DBUG_PRINT("info", ("is_real_trans: %d rw_trans: %d rw_ha_count: %d", is_real_trans, rw_trans, rw_ha_count)); + if (rw_trans) + { + /* + Acquire a metadata lock which will ensure that COMMIT is blocked + by an active FLUSH TABLES WITH READ LOCK (and vice versa: + COMMIT in progress blocks FTWRL). + + We allow the owner of FTWRL to COMMIT; we assume that it knows + what it does. + */ + MDL_REQUEST_INIT(&mdl_backup, MDL_key::BACKUP, "", "", MDL_BACKUP_COMMIT, + MDL_EXPLICIT); + + if (!WSREP(thd)) + { + if (thd->mdl_context.acquire_lock(&mdl_backup, + thd->variables.lock_wait_timeout)) + { + my_error(ER_ERROR_DURING_COMMIT, MYF(0), 1); + ha_rollback_trans(thd, all); + DBUG_RETURN(1); + } + thd->backup_commit_lock= &mdl_backup; + } + DEBUG_SYNC(thd, "ha_commit_trans_after_acquire_commit_lock"); + } + if (rw_trans && opt_readonly && !(thd->security_ctx->master_access & PRIV_IGNORE_READ_ONLY) && @@ -1663,7 +1691,7 @@ int ha_commit_trans(THD *thd, bool all) // Here, the call will not commit inside InnoDB. It is only working // around closing thd->transaction.stmt open by TR_table::open(). if (all) - commit_one_phase_2(thd, false, &thd->transaction->stmt, false, false); + commit_one_phase_2(thd, false, &thd->transaction->stmt, false); } } #endif @@ -1683,7 +1711,7 @@ int ha_commit_trans(THD *thd, bool all) goto wsrep_err; } #endif /* WITH_WSREP */ - error= ha_commit_one_phase(thd, all, rw_trans); + error= ha_commit_one_phase(thd, all); #ifdef WITH_WSREP // Here in case of error we must return 2 for inconsistency if (run_wsrep_hooks && !error) @@ -1720,7 +1748,7 @@ int ha_commit_trans(THD *thd, bool all) if (!is_real_trans) { - error= commit_one_phase_2(thd, all, trans, is_real_trans, rw_trans); + error= commit_one_phase_2(thd, all, trans, is_real_trans); goto done; } @@ -1754,7 +1782,7 @@ int ha_commit_trans(THD *thd, bool all) DEBUG_SYNC(thd, "ha_commit_trans_after_log_and_order"); DBUG_EXECUTE_IF("crash_commit_after_log", DBUG_SUICIDE();); - error= commit_one_phase_2(thd, all, trans, is_real_trans, rw_trans) ? 2 : 0; + error= commit_one_phase_2(thd, all, trans, is_real_trans) ? 2 : 0; #ifdef WITH_WSREP if (run_wsrep_hooks && (error || (error = wsrep_after_commit(thd, all)))) @@ -1828,6 +1856,17 @@ err: thd->rgi_slave->is_parallel_exec); } end: + if (mdl_backup.ticket) + { + /* + We do not always immediately release transactional locks + after ha_commit_trans() (see uses of ha_enable_transaction()), + thus we release the commit blocker lock as soon as it's + not needed. + */ + thd->mdl_context.release_lock(mdl_backup.ticket); + } + thd->backup_commit_lock= 0; #ifdef WITH_WSREP if (wsrep_is_active(thd) && is_real_trans && !error && (rw_ha_count == 0 || all) && @@ -1842,8 +1881,8 @@ end: /** @note - This function does not care about global read lock. A caller should. - However backup locks are handled in commit_one_phase_2. + This function does not care about global read lock or backup locks, + the caller should. @param[in] all Is set in case of explicit commit (COMMIT statement), or implicit commit @@ -1852,7 +1891,7 @@ end: autocommit=1. */ -int ha_commit_one_phase(THD *thd, bool all, bool rw_trans) +int ha_commit_one_phase(THD *thd, bool all) { THD_TRANS *trans=all ? &thd->transaction->all : &thd->transaction->stmt; /* @@ -1878,48 +1917,21 @@ int ha_commit_one_phase(THD *thd, bool all, bool rw_trans) if ((res= thd->wait_for_prior_commit())) DBUG_RETURN(res); } - res= commit_one_phase_2(thd, all, trans, is_real_trans, rw_trans); + res= commit_one_phase_2(thd, all, trans, is_real_trans); DBUG_RETURN(res); } static int -commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans, bool is_real_trans, - bool rw_trans) +commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans, bool is_real_trans) { int error= 0; uint count= 0; Ha_trx_info *ha_info= trans->ha_list, *ha_info_next; - MDL_request mdl_request; - mdl_request.ticket= 0; DBUG_ENTER("commit_one_phase_2"); if (is_real_trans) DEBUG_SYNC(thd, "commit_one_phase_2"); - if (rw_trans) - { - /* - Acquire a metadata lock which will ensure that COMMIT is blocked - by an active FLUSH TABLES WITH READ LOCK (and vice versa: - COMMIT in progress blocks FTWRL). - - We allow the owner of FTWRL to COMMIT; we assume that it knows - what it does. - */ - MDL_REQUEST_INIT(&mdl_request, MDL_key::BACKUP, "", "", MDL_BACKUP_COMMIT, - MDL_EXPLICIT); - - if (!WSREP(thd) && - thd->mdl_context.acquire_lock(&mdl_request, - thd->variables.lock_wait_timeout)) - { - my_error(ER_ERROR_DURING_COMMIT, MYF(0), 1); - ha_rollback_trans(thd, all); - DBUG_RETURN(1); - } - DEBUG_SYNC(thd, "ha_commit_trans_after_acquire_commit_lock"); - } - if (ha_info) { for (; ha_info; ha_info= ha_info_next) @@ -1948,16 +1960,6 @@ commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans, bool is_real_trans, #endif } } - if (mdl_request.ticket) - { - /* - We do not always immediately release transactional locks - after ha_commit_trans() (see uses of ha_enable_transaction()), - thus we release the commit blocker lock as soon as it's - not needed. - */ - thd->mdl_context.release_lock(mdl_request.ticket); - } /* Free resources and perform other cleanup even for 'empty' transactions. */ if (is_real_trans) @@ -2314,7 +2316,7 @@ static my_bool xarecover_handlerton(THD *unused, plugin_ref plugin, for (int i=0; i < got; i ++) { - my_xid x= IF_WSREP(WSREP_ON && wsrep_is_wsrep_xid(&info->list[i]) ? + my_xid x= IF_WSREP(wsrep_is_wsrep_xid(&info->list[i]) ? wsrep_xid_seqno(&info->list[i]) : info->list[i].get_my_xid(), info->list[i].get_my_xid()); @@ -2762,6 +2764,9 @@ int ha_delete_table(THD *thd, handlerton *hton, const char *path, if (hton == NULL || hton == view_pseudo_hton) DBUG_RETURN(0); + if (ha_check_if_updates_are_ignored(thd, hton, "DROP")) + DBUG_RETURN(0); + error= hton->drop_table(hton, path); if (error > 0) { @@ -2799,7 +2804,8 @@ int ha_delete_table(THD *thd, handlerton *hton, const char *path, error= -1; } } - + if (error) + DBUG_PRINT("exit", ("error: %d", error)); DBUG_RETURN(error); } @@ -5006,7 +5012,8 @@ static my_bool delete_table_force(THD *thd, plugin_ref plugin, void *arg) handlerton *hton = plugin_hton(plugin); st_force_drop_table_params *param = (st_force_drop_table_params *)arg; - if (param->discovering == (hton->discover_table != NULL)) + if (param->discovering == (hton->discover_table != NULL) && + !(thd->slave_thread && (hton->flags & HTON_IGNORE_UPDATES))) { int error; error= ha_delete_table(thd, hton, param->path, param->db, param->alias, 0); @@ -6316,6 +6323,7 @@ extern "C" check_result_t handler_index_cond_check(void* h_arg) THD *thd= h->table->in_use; check_result_t res; + DEBUG_SYNC(thd, "handler_index_cond_check"); enum thd_kill_levels abort_at= h->has_rollback() ? THD_ABORT_SOFTLY : THD_ABORT_ASAP; if (thd_kill_level(thd) > abort_at) @@ -6349,6 +6357,7 @@ check_result_t handler_rowid_filter_check(void *h_arg) if (!h->pushed_idx_cond) { THD *thd= h->table->in_use; + DEBUG_SYNC(thd, "handler_rowid_filter_check"); enum thd_kill_levels abort_at= h->has_transactions() ? THD_ABORT_SOFTLY : THD_ABORT_ASAP; if (thd_kill_level(thd) > abort_at) @@ -6938,7 +6947,7 @@ int handler::ha_check_overlaps(const uchar *old_data, const uchar* new_data) uchar *record_buffer= lookup_buffer + table_share->max_unique_length + table_share->null_fields; - // Needs to compare record refs later is old_row_found() + // Needed to compare record refs later if (is_update) position(old_data); @@ -6994,12 +7003,8 @@ int handler::ha_check_overlaps(const uchar *old_data, const uchar* new_data) /* In case of update it could happen that the nearest neighbour is a record we are updating. It means, that there are no overlaps from this side. - - An assumption is made that during update we always have the last - fetched row in old_data. Therefore, comparing ref's is enough */ DBUG_ASSERT(lookup_handler != this); - DBUG_ASSERT(inited != NONE); DBUG_ASSERT(ref_length == lookup_handler->ref_length); lookup_handler->position(record_buffer); @@ -7124,16 +7129,17 @@ int handler::ha_write_row(const uchar *buf) if ((error= ha_check_overlaps(NULL, buf))) DBUG_RETURN(error); - MYSQL_INSERT_ROW_START(table_share->db.str, table_share->table_name.str); - mark_trx_read_write(); - increment_statistics(&SSV::ha_write_count); - if (table->s->long_unique_table && this == table->file) { DBUG_ASSERT(inited == NONE || lookup_handler != this); if ((error= check_duplicate_long_entries(buf))) DBUG_RETURN(error); } + + MYSQL_INSERT_ROW_START(table_share->db.str, table_share->table_name.str); + mark_trx_read_write(); + increment_statistics(&SSV::ha_write_count); + TABLE_IO_WAIT(tracker, PSI_TABLE_WRITE_ROW, MAX_KEY, error, { error= write_row(buf); }) @@ -7173,17 +7179,19 @@ int handler::ha_update_row(const uchar *old_data, const uchar *new_data) DBUG_ASSERT(new_data == table->record[0]); DBUG_ASSERT(old_data == table->record[1]); - if ((error= ha_check_overlaps(old_data, new_data))) + uint saved_status= table->status; + error= ha_check_overlaps(old_data, new_data); + + if (!error && table->s->long_unique_table && this == table->file) + error= check_duplicate_long_entries_update(new_data); + table->status= saved_status; + + if (error) return error; 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 && this == table->file && - (error= check_duplicate_long_entries_update(new_data))) - { - return error; - } TABLE_IO_WAIT(tracker, PSI_TABLE_UPDATE_ROW, active_index, 0, { error= update_row(old_data, new_data);}) @@ -8075,6 +8083,8 @@ Vers_parse_info::fix_create_like(Alter_info &alter_info, HA_CREATE_INFO &create_ TABLE_LIST &src_table, TABLE_LIST &table) { List_iterator<Create_field> it(alter_info.create_list); + List_iterator<Key> key_it(alter_info.key_list); + List_iterator<Key_part_spec> kp_it; Create_field *f, *f_start=NULL, *f_end= NULL; DBUG_ASSERT(alter_info.create_list.elements > 2); @@ -8089,6 +8099,23 @@ Vers_parse_info::fix_create_like(Alter_info &alter_info, HA_CREATE_INFO &create_ it.remove(); remove--; } + key_it.rewind(); + while (Key *key= key_it++) + { + kp_it.init(key->columns); + while (Key_part_spec *kp= kp_it++) + { + if (0 == lex_string_cmp(system_charset_info, &kp->field_name, + &f->field_name)) + { + kp_it.remove(); + } + } + if (0 == key->columns.elements) + { + key_it.remove(); + } + } } DBUG_ASSERT(remove == 0); push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN, |