summaryrefslogtreecommitdiff
path: root/sql/handler.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/handler.cc')
-rw-r--r--sql/handler.cc157
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,