summaryrefslogtreecommitdiff
path: root/sql/handler.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/handler.cc')
-rw-r--r--sql/handler.cc497
1 files changed, 288 insertions, 209 deletions
diff --git a/sql/handler.cc b/sql/handler.cc
index 0b7fbc93cb5..10d2991e67c 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -31,11 +31,10 @@
#include "sql_table.h" // build_table_filename
#include "sql_parse.h" // check_stack_overrun
#include "sql_acl.h" // SUPER_ACL
-#include "sql_base.h" // free_io_cache
+#include "sql_base.h" // TDC_element
#include "discover.h" // extension_based_table_discovery, etc
#include "log_event.h" // *_rows_log_event
#include "create_options.h"
-#include "rpl_filter.h"
#include <myisampack.h>
#include "transaction.h"
#include "myisam.h"
@@ -259,7 +258,7 @@ handler *get_new_handler(TABLE_SHARE *share, MEM_ROOT *alloc,
{
handler *file;
DBUG_ENTER("get_new_handler");
- DBUG_PRINT("enter", ("alloc: 0x%lx", (long) alloc));
+ DBUG_PRINT("enter", ("alloc: %p", alloc));
if (db_type && db_type->state == SHOW_OPTION_YES && db_type->create)
{
@@ -305,7 +304,7 @@ handler *get_ha_partition(partition_info *part_info)
static const char **handler_errmsgs;
C_MODE_START
-static const char **get_handler_errmsgs(void)
+static const char **get_handler_errmsgs(int nr)
{
return handler_errmsgs;
}
@@ -369,7 +368,7 @@ int ha_init_errors(void)
SETMSG(HA_ERR_NO_CONNECTION, "Could not connect to storage engine");
SETMSG(HA_ERR_TABLE_DEF_CHANGED, ER_DEFAULT(ER_TABLE_DEF_CHANGED));
SETMSG(HA_ERR_FOREIGN_DUPLICATE_KEY, "FK constraint would lead to duplicate key");
- SETMSG(HA_ERR_TABLE_NEEDS_UPGRADE, "Table upgrade required. Please do \"REPAIR TABLE %`\" or dump/reload to fix it");
+ SETMSG(HA_ERR_TABLE_NEEDS_UPGRADE, ER_DEFAULT(ER_TABLE_NEEDS_UPGRADE));
SETMSG(HA_ERR_TABLE_READONLY, ER_DEFAULT(ER_OPEN_AS_READONLY));
SETMSG(HA_ERR_AUTOINC_READ_FAILED, ER_DEFAULT(ER_AUTOINC_READ_FAILED));
SETMSG(HA_ERR_AUTOINC_ERANGE, ER_DEFAULT(ER_WARN_DATA_OUT_OF_RANGE));
@@ -380,6 +379,8 @@ int ha_init_errors(void)
SETMSG(HA_ERR_TABLE_IN_FK_CHECK, ER_DEFAULT(ER_TABLE_IN_FK_CHECK));
SETMSG(HA_ERR_DISK_FULL, ER_DEFAULT(ER_DISK_FULL));
SETMSG(HA_ERR_FTS_TOO_MANY_WORDS_IN_PHRASE, "Too many words in a FTS phrase or proximity search");
+ SETMSG(HA_ERR_FK_DEPTH_EXCEEDED, "Foreign key cascade delete/update exceeds");
+ SETMSG(HA_ERR_TABLESPACE_MISSING, ER_DEFAULT(ER_TABLESPACE_MISSING));
/* Register the error messages for use with my_error(). */
return my_error_register(get_handler_errmsgs, HA_ERR_FIRST, HA_ERR_LAST);
@@ -396,12 +397,10 @@ int ha_init_errors(void)
*/
static int ha_finish_errors(void)
{
- const char **errmsgs;
-
/* Allocate a pointer array for the error message strings. */
- if (! (errmsgs= my_error_unregister(HA_ERR_FIRST, HA_ERR_LAST)))
- return 1;
- my_free(errmsgs);
+ my_error_unregister(HA_ERR_FIRST, HA_ERR_LAST);
+ my_free(handler_errmsgs);
+ handler_errmsgs= 0;
return 0;
}
@@ -796,8 +795,8 @@ static my_bool closecon_handlerton(THD *thd, plugin_ref plugin,
void ha_close_connection(THD* thd)
{
plugin_foreach_with_mask(thd, closecon_handlerton,
- MYSQL_STORAGE_ENGINE_PLUGIN,
- PLUGIN_IS_DELETED|PLUGIN_IS_READY, 0);
+ MYSQL_STORAGE_ENGINE_PLUGIN,
+ PLUGIN_IS_DELETED|PLUGIN_IS_READY, 0);
}
static my_bool kill_handlerton(THD *thd, plugin_ref plugin,
@@ -1376,7 +1375,7 @@ int ha_commit_trans(THD *thd, bool all)
uint rw_ha_count= ha_check_and_coalesce_trx_read_only(thd, ha_info, 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());
+ (rw_ha_count > (thd->is_current_stmt_binlog_disabled()?0U:1U));
MDL_request mdl_request;
DBUG_PRINT("info", ("is_real_trans: %d rw_trans: %d rw_ha_count: %d",
is_real_trans, rw_trans, rw_ha_count));
@@ -1676,7 +1675,7 @@ int ha_rollback_trans(THD *thd, bool all)
my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err);
error=1;
#ifdef WITH_WSREP
- WSREP_WARN("handlerton rollback failed, thd %lu %lld conf %d SQL %s",
+ WSREP_WARN("handlerton rollback failed, thd %llu %lld conf %d SQL %s",
thd->thread_id, thd->query_id, thd->wsrep_conflict_state,
thd->query());
#endif /* WITH_WSREP */
@@ -1828,6 +1827,35 @@ static char* xid_to_str(char *buf, XID *xid)
}
#endif
+#ifdef WITH_WSREP
+static my_xid wsrep_order_and_check_continuity(XID *list, int len)
+{
+ wsrep_sort_xid_array(list, len);
+ wsrep_uuid_t uuid;
+ wsrep_seqno_t seqno;
+ if (wsrep_get_SE_checkpoint(uuid, seqno))
+ {
+ WSREP_ERROR("Could not read wsrep SE checkpoint for recovery");
+ return 0;
+ }
+ long long cur_seqno= seqno;
+ for (int i= 0; i < len; ++i)
+ {
+ if (!wsrep_is_wsrep_xid(list + i) ||
+ wsrep_xid_seqno(*(list + i)) != cur_seqno + 1)
+ {
+ WSREP_WARN("Discovered discontinuity in recovered wsrep "
+ "transaction XIDs. Truncating the recovery list to "
+ "%d entries", i);
+ break;
+ }
+ ++cur_seqno;
+ }
+ WSREP_INFO("Last wsrep seqno to be recovered %lld", cur_seqno);
+ return (cur_seqno < 0 ? 0 : cur_seqno);
+}
+#endif /* WITH_WSREP */
+
/**
recover() step of xa.
@@ -1865,6 +1893,19 @@ static my_bool xarecover_handlerton(THD *unused, plugin_ref plugin,
{
sql_print_information("Found %d prepared transaction(s) in %s",
got, hton_name(hton)->str);
+#ifdef WITH_WSREP
+ /* If wsrep_on=ON, XIDs are first ordered and then the range of
+ recovered XIDs is checked for continuity. All the XIDs which
+ are in continuous range can be safely committed if binlog
+ is off since they have already ordered and certified in the
+ cluster. */
+ my_xid wsrep_limit= 0;
+ if (WSREP_ON)
+ {
+ wsrep_limit= wsrep_order_and_check_continuity(info->list, got);
+ }
+#endif /* WITH_WSREP */
+
for (int i=0; i < got; i ++)
{
my_xid x= WSREP_ON && wsrep_is_wsrep_xid(&info->list[i]) ?
@@ -1880,15 +1921,21 @@ static my_bool xarecover_handlerton(THD *unused, plugin_ref plugin,
info->found_foreign_xids++;
continue;
}
- if (info->dry_run)
+ if (IF_WSREP(!(wsrep_emulate_bin_log &&
+ wsrep_is_wsrep_xid(info->list + i) &&
+ x <= wsrep_limit) && info->dry_run,
+ info->dry_run))
{
info->found_my_xids++;
continue;
}
// recovery mode
- if (info->commit_list ?
- my_hash_search(info->commit_list, (uchar *)&x, sizeof(x)) != 0 :
- tc_heuristic_recover == TC_HEURISTIC_RECOVER_COMMIT)
+ if (IF_WSREP((wsrep_emulate_bin_log &&
+ wsrep_is_wsrep_xid(info->list + i) &&
+ x <= wsrep_limit), false) ||
+ (info->commit_list ?
+ my_hash_search(info->commit_list, (uchar *)&x, sizeof(x)) != 0 :
+ tc_heuristic_recover == TC_HEURISTIC_RECOVER_COMMIT))
{
#ifndef DBUG_OFF
int rc=
@@ -2051,44 +2098,6 @@ commit_checkpoint_notify_ha(handlerton *hton, void *cookie)
/**
- @details
- This function should be called when MySQL sends rows of a SELECT result set
- or the EOF mark to the client. It releases a possible adaptive hash index
- S-latch held by thd in InnoDB and also releases a possible InnoDB query
- FIFO ticket to enter InnoDB. To save CPU time, InnoDB allows a thd to
- keep them over several calls of the InnoDB handler interface when a join
- is executed. But when we let the control to pass to the client they have
- to be released because if the application program uses mysql_use_result(),
- it may deadlock on the S-latch if the application on another connection
- performs another SQL query. In MySQL-4.1 this is even more important because
- there a connection can have several SELECT queries open at the same time.
-
- @param thd the thread handle of the current connection
-
- @return
- always 0
-*/
-
-int ha_release_temporary_latches(THD *thd)
-{
- Ha_trx_info *info;
-
- /*
- Note that below we assume that only transactional storage engines
- may need release_temporary_latches(). If this will ever become false,
- we could iterate on thd->open_tables instead (and remove duplicates
- as if (!seen[hton->slot]) { seen[hton->slot]=1; ... }).
- */
- for (info= thd->transaction.stmt.ha_list; info; info= info->next())
- {
- handlerton *hton= info->ht();
- if (hton && hton->release_temporary_latches)
- hton->release_temporary_latches(hton, thd);
- }
- return 0;
-}
-
-/**
Check if all storage engines used in transaction agree that after
rollback to savepoint it is safe to release MDL locks acquired after
savepoint creation.
@@ -2247,7 +2256,8 @@ static my_bool snapshot_handlerton(THD *thd, plugin_ref plugin,
if (hton->state == SHOW_OPTION_YES &&
hton->start_consistent_snapshot)
{
- hton->start_consistent_snapshot(hton, thd);
+ if (hton->start_consistent_snapshot(hton, thd))
+ return TRUE;
*((bool *)arg)= false;
}
return FALSE;
@@ -2255,7 +2265,7 @@ static my_bool snapshot_handlerton(THD *thd, plugin_ref plugin,
int ha_start_consistent_snapshot(THD *thd)
{
- bool warn= true;
+ bool err, warn= true;
/*
Holding the LOCK_commit_ordered mutex ensures that we get the same
@@ -2265,9 +2275,15 @@ int ha_start_consistent_snapshot(THD *thd)
have a consistent binlog position.
*/
mysql_mutex_lock(&LOCK_commit_ordered);
- plugin_foreach(thd, snapshot_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN, &warn);
+ err= plugin_foreach(thd, snapshot_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN, &warn);
mysql_mutex_unlock(&LOCK_commit_ordered);
+ if (err)
+ {
+ ha_rollback_trans(thd, true);
+ return 1;
+ }
+
/*
Same idea as when one wants to CREATE TABLE in one engine which does not
exist:
@@ -2614,6 +2630,8 @@ int handler::ha_rnd_next(uchar *buf)
if (!result)
{
update_rows_read();
+ if (table->vfield && buf == table->record[0])
+ table->update_virtual_fields(this, VCOL_UPDATE_FOR_READ);
increment_statistics(&SSV::ha_read_rnd_next_count);
}
else if (result == HA_ERR_RECORD_DELETED)
@@ -2631,14 +2649,17 @@ int handler::ha_rnd_pos(uchar *buf, uchar *pos)
DBUG_ENTER("handler::ha_rnd_pos");
DBUG_ASSERT(table_share->tmp_table != NO_TMP_TABLE ||
m_lock_type != F_UNLCK);
- /* TODO: Find out how to solve ha_rnd_pos when finding duplicate update. */
- /* DBUG_ASSERT(inited == RND); */
+ DBUG_ASSERT(inited == RND);
TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_FETCH_ROW, MAX_KEY, 0,
{ result= rnd_pos(buf, pos); })
increment_statistics(&SSV::ha_read_rnd_count);
if (!result)
+ {
update_rows_read();
+ if (table->vfield && buf == table->record[0])
+ table->update_virtual_fields(this, VCOL_UPDATE_FOR_READ);
+ }
table->status=result ? STATUS_NOT_FOUND: 0;
DBUG_RETURN(result);
}
@@ -2657,7 +2678,11 @@ int handler::ha_index_read_map(uchar *buf, const uchar *key,
{ result= index_read_map(buf, key, keypart_map, find_flag); })
increment_statistics(&SSV::ha_read_key_count);
if (!result)
+ {
update_index_statistics();
+ if (table->vfield && buf == table->record[0])
+ table->update_virtual_fields(this, VCOL_UPDATE_FOR_READ);
+ }
table->status=result ? STATUS_NOT_FOUND: 0;
DBUG_RETURN(result);
}
@@ -2684,6 +2709,8 @@ int handler::ha_index_read_idx_map(uchar *buf, uint index, const uchar *key,
{
update_rows_read();
index_rows_read[index]++;
+ if (table->vfield && buf == table->record[0])
+ table->update_virtual_fields(this, VCOL_UPDATE_FOR_READ);
}
table->status=result ? STATUS_NOT_FOUND: 0;
return result;
@@ -2701,7 +2728,11 @@ int handler::ha_index_next(uchar * buf)
{ result= index_next(buf); })
increment_statistics(&SSV::ha_read_next_count);
if (!result)
+ {
update_index_statistics();
+ if (table->vfield && buf == table->record[0])
+ table->update_virtual_fields(this, VCOL_UPDATE_FOR_READ);
+ }
table->status=result ? STATUS_NOT_FOUND: 0;
DBUG_RETURN(result);
}
@@ -2718,7 +2749,11 @@ int handler::ha_index_prev(uchar * buf)
{ result= index_prev(buf); })
increment_statistics(&SSV::ha_read_prev_count);
if (!result)
+ {
update_index_statistics();
+ if (table->vfield && buf == table->record[0])
+ table->update_virtual_fields(this, VCOL_UPDATE_FOR_READ);
+ }
table->status=result ? STATUS_NOT_FOUND: 0;
DBUG_RETURN(result);
}
@@ -2734,7 +2769,11 @@ int handler::ha_index_first(uchar * buf)
{ result= index_first(buf); })
increment_statistics(&SSV::ha_read_first_count);
if (!result)
+ {
update_index_statistics();
+ if (table->vfield && buf == table->record[0])
+ table->update_virtual_fields(this, VCOL_UPDATE_FOR_READ);
+ }
table->status=result ? STATUS_NOT_FOUND: 0;
return result;
}
@@ -2750,7 +2789,11 @@ int handler::ha_index_last(uchar * buf)
{ result= index_last(buf); })
increment_statistics(&SSV::ha_read_last_count);
if (!result)
+ {
update_index_statistics();
+ if (table->vfield && buf == table->record[0])
+ table->update_virtual_fields(this, VCOL_UPDATE_FOR_READ);
+ }
table->status=result ? STATUS_NOT_FOUND: 0;
return result;
}
@@ -2766,7 +2809,11 @@ int handler::ha_index_next_same(uchar *buf, const uchar *key, uint keylen)
{ result= index_next_same(buf, key, keylen); })
increment_statistics(&SSV::ha_read_next_count);
if (!result)
+ {
update_index_statistics();
+ if (table->vfield && buf == table->record[0])
+ table->update_virtual_fields(this, VCOL_UPDATE_FOR_READ);
+ }
table->status=result ? STATUS_NOT_FOUND: 0;
return result;
}
@@ -2800,7 +2847,7 @@ int handler::ha_rnd_init_with_error(bool scan)
*/
int handler::read_first_row(uchar * buf, uint primary_key)
{
- register int error;
+ int error;
DBUG_ENTER("handler::read_first_row");
/*
@@ -2879,7 +2926,7 @@ void handler::adjust_next_insert_id_after_explicit_value(ulonglong nr)
{
/*
If we have set THD::next_insert_id previously and plan to insert an
- explicitely-specified value larger than this, we need to increase
+ explicitly-specified value larger than this, we need to increase
THD::next_insert_id to be greater than the explicit value.
*/
if ((next_insert_id > 0) && (nr >= next_insert_id))
@@ -3136,6 +3183,7 @@ int handler::update_auto_increment()
if (unlikely(nr == ULONGLONG_MAX))
DBUG_RETURN(HA_ERR_AUTOINC_ERANGE);
+ DBUG_ASSERT(nr != 0);
DBUG_PRINT("info",("auto_increment: %llu nb_reserved_values: %llu",
nr, append ? nb_reserved_values : 0));
@@ -3228,8 +3276,8 @@ void handler::column_bitmaps_signal()
{
DBUG_ENTER("column_bitmaps_signal");
if (table)
- DBUG_PRINT("info", ("read_set: 0x%lx write_set: 0x%lx",
- (long) table->read_set, (long) table->write_set));
+ DBUG_PRINT("info", ("read_set: %p write_set: %p",
+ table->read_set, table->write_set));
DBUG_VOID_RETURN;
}
@@ -3258,11 +3306,13 @@ void handler::get_auto_increment(ulonglong offset, ulonglong increment,
{
ulonglong nr;
int error;
+ MY_BITMAP *old_read_set;
+ bool rnd_inited= (inited == RND);
- (void) extra(HA_EXTRA_KEYREAD);
- table->mark_columns_used_by_index_no_reset(table->s->next_number_index,
- table->read_set);
- column_bitmaps_signal();
+ if (rnd_inited && ha_rnd_end())
+ return;
+
+ old_read_set= table->prepare_for_keyread(table->s->next_number_index);
if (ha_index_init(table->s->next_number_index, 1))
{
@@ -3270,6 +3320,10 @@ void handler::get_auto_increment(ulonglong offset, ulonglong increment,
DBUG_ASSERT(0);
(void) extra(HA_EXTRA_NO_KEYREAD);
*first_value= ULONGLONG_MAX;
+ if (rnd_inited && ha_rnd_init_with_error(0))
+ {
+ //TODO: it would be nice to return here an error
+ }
return;
}
@@ -3314,8 +3368,12 @@ void handler::get_auto_increment(ulonglong offset, ulonglong increment,
nr= ((ulonglong) table->next_number_field->
val_int_offset(table->s->rec_buff_length)+1);
ha_index_end();
- (void) extra(HA_EXTRA_NO_KEYREAD);
+ table->restore_column_maps_after_keyread(old_read_set);
*first_value= nr;
+ if (rnd_inited && ha_rnd_init_with_error(0))
+ {
+ //TODO: it would be nice to return here an error
+ }
return;
}
@@ -3416,6 +3474,12 @@ void handler::print_error(int error, myf errflag)
DBUG_ENTER("handler::print_error");
DBUG_PRINT("enter",("error: %d",error));
+ if (ha_thd()->transaction_rollback_request)
+ {
+ /* Ensure this becomes a true error */
+ errflag&= ~(ME_JUST_WARNING | ME_JUST_INFO);
+ }
+
int textno= -1; // impossible value
switch (error) {
case EACCES:
@@ -3559,10 +3623,14 @@ void handler::print_error(int error, myf errflag)
textno=ER_LOCK_TABLE_FULL;
break;
case HA_ERR_LOCK_DEADLOCK:
- textno=ER_LOCK_DEADLOCK;
- /* cannot continue. the statement was already aborted in the engine */
- SET_FATAL_ERROR;
- break;
+ {
+ String str, full_err_msg(ER_DEFAULT(ER_LOCK_DEADLOCK), system_charset_info);
+
+ get_error_message(error, &str);
+ full_err_msg.append(str);
+ my_printf_error(ER_LOCK_DEADLOCK, "%s", errflag, full_err_msg.c_ptr_safe());
+ DBUG_VOID_RETURN;
+ }
case HA_ERR_READ_ONLY_TRANSACTION:
textno=ER_READ_ONLY_TRANSACTION;
break;
@@ -3607,9 +3675,10 @@ void handler::print_error(int error, myf errflag)
DBUG_VOID_RETURN;
}
case HA_ERR_TABLE_NEEDS_UPGRADE:
+ textno= ER_TABLE_NEEDS_UPGRADE;
my_error(ER_TABLE_NEEDS_UPGRADE, errflag,
"TABLE", table_share->table_name.str);
- break;
+ DBUG_VOID_RETURN;
case HA_ERR_NO_PARTITION_FOUND:
textno=ER_WRONG_PARTITION_NAME;
break;
@@ -3792,7 +3861,7 @@ int handler::ha_check_for_upgrade(HA_CHECK_OPT *check_opt)
}
}
}
- if (table->s->frm_version != FRM_VER_TRUE_VARCHAR)
+ if (table->s->frm_version < FRM_VER_TRUE_VARCHAR)
return HA_ADMIN_NEEDS_ALTER;
if ((error= check_collation_compatibility()))
@@ -4009,9 +4078,7 @@ int handler::ha_check(THD *thd, HA_CHECK_OPT *check_opt)
if it is started.
*/
-inline
-void
-handler::mark_trx_read_write()
+void handler::mark_trx_read_write_internal()
{
Ha_trx_info *ha_info= &ha_thd()->ha_data[ht->slot].ha_info[0];
/*
@@ -4279,6 +4346,7 @@ handler::check_if_supported_inplace_alter(TABLE *altered_table,
Alter_inplace_info::ALTER_COLUMN_OPTION |
Alter_inplace_info::CHANGE_CREATE_OPTION |
Alter_inplace_info::ALTER_PARTITIONED |
+ Alter_inplace_info::ALTER_VIRTUAL_GCOL_EXPR |
Alter_inplace_info::ALTER_RENAME;
/* Is there at least one operation that requires copy algorithm? */
@@ -4766,7 +4834,7 @@ int ha_create_table(THD *thd, const char *path,
share.table_name.str, share.table_name.length);
}
- (void) closefrm(&table, 0);
+ (void) closefrm(&table);
err:
free_table_share(&share);
@@ -5004,7 +5072,7 @@ public:
bool handle_condition(THD *thd,
uint sql_errno,
const char* sqlstate,
- Sql_condition::enum_warning_level level,
+ Sql_condition::enum_warning_level *level,
const char* msg,
Sql_condition ** cond_hdl)
{
@@ -5017,7 +5085,7 @@ public:
return TRUE;
}
- if (level == Sql_condition::WARN_LEVEL_ERROR)
+ if (*level == Sql_condition::WARN_LEVEL_ERROR)
m_unhandled_errors++;
return FALSE;
}
@@ -5130,7 +5198,9 @@ bool ha_table_exists(THD *thd, const char *db, const char *table_name,
Table_exists_error_handler no_such_table_handler;
thd->push_internal_handler(&no_such_table_handler);
- TABLE_SHARE *share= tdc_acquire_share(thd, db, table_name, flags);
+ table.init_one_table(db, strlen(db), table_name, strlen(table_name),
+ table_name, TL_READ);
+ TABLE_SHARE *share= tdc_acquire_share(thd, &table, flags);
thd->pop_internal_handler();
if (hton && share)
@@ -5464,7 +5534,7 @@ int handler::compare_key(key_range *range)
This is used by index condition pushdown implementation.
*/
-int handler::compare_key2(key_range *range)
+int handler::compare_key2(key_range *range) const
{
int cmp;
if (!range)
@@ -5579,9 +5649,9 @@ TYPELIB *ha_known_exts(void)
}
-static bool stat_print(THD *thd, const char *type, uint type_len,
- const char *file, uint file_len,
- const char *status, uint status_len)
+static bool stat_print(THD *thd, const char *type, size_t type_len,
+ const char *file, size_t file_len,
+ const char *status, size_t status_len)
{
Protocol *protocol= thd->protocol;
protocol->prepare_for_resend();
@@ -5660,30 +5730,38 @@ bool ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat)
correct for the table.
A row in the given table should be replicated if:
+ - It's not called by partition engine
- Row-based replication is enabled in the current thread
- The binlog is enabled
- It is not a temporary table
- The binary log is open
- The database the table resides in shall be binlogged (binlog_*_db rules)
- table is not mysql.event
+
+ RETURN VALUE
+ 0 No binary logging in row format
+ 1 Row needs to be logged
*/
-static bool check_table_binlog_row_based(THD *thd, TABLE *table)
+inline bool handler::check_table_binlog_row_based(bool binlog_row)
{
- if (table->s->cached_row_logging_check == -1)
+ if (unlikely((table->in_use->variables.sql_log_bin_off)))
+ return 0; /* Called by partitioning engine */
+ if (unlikely((!check_table_binlog_row_based_done)))
{
- int const check(table->s->tmp_table == NO_TMP_TABLE &&
- ! table->no_replicate &&
- binlog_filter->db_ok(table->s->db.str));
- table->s->cached_row_logging_check= check;
+ check_table_binlog_row_based_done= 1;
+ check_table_binlog_row_based_result=
+ check_table_binlog_row_based_internal(binlog_row);
}
+ return check_table_binlog_row_based_result;
+}
- DBUG_ASSERT(table->s->cached_row_logging_check == 0 ||
- table->s->cached_row_logging_check == 1);
+bool handler::check_table_binlog_row_based_internal(bool binlog_row)
+{
+ THD *thd= table->in_use;
- return (thd->is_current_stmt_binlog_format_row() &&
- table->s->cached_row_logging_check &&
-#ifdef WITH_WSREP
+ return (table->s->cached_row_logging_check &&
+ thd->is_current_stmt_binlog_format_row() &&
/*
Wsrep partially enables binary logging if it have not been
explicitly turned on. As a result we return 'true' if we are in
@@ -5698,14 +5776,13 @@ static bool check_table_binlog_row_based(THD *thd, TABLE *table)
Otherwise, return 'true' if binary logging is on.
*/
- (thd->variables.sql_log_bin_off != 1) &&
- ((WSREP_EMULATE_BINLOG(thd) && (thd->wsrep_exec_mode != REPL_RECV)) ||
- ((WSREP(thd) || (thd->variables.option_bits & OPTION_BIN_LOG)) &&
- mysql_bin_log.is_open())));
-#else
- (thd->variables.option_bits & OPTION_BIN_LOG) &&
- mysql_bin_log.is_open());
-#endif
+ IF_WSREP(((WSREP_EMULATE_BINLOG(thd) &&
+ (thd->wsrep_exec_mode != REPL_RECV)) ||
+ ((WSREP(thd) ||
+ (thd->variables.option_bits & OPTION_BIN_LOG)) &&
+ mysql_bin_log.is_open())),
+ (thd->variables.option_bits & OPTION_BIN_LOG) &&
+ mysql_bin_log.is_open()));
}
@@ -5733,60 +5810,57 @@ static bool check_table_binlog_row_based(THD *thd, TABLE *table)
static int write_locked_table_maps(THD *thd)
{
DBUG_ENTER("write_locked_table_maps");
- DBUG_PRINT("enter", ("thd: 0x%lx thd->lock: 0x%lx "
- "thd->extra_lock: 0x%lx",
- (long) thd, (long) thd->lock, (long) thd->extra_lock));
+ DBUG_PRINT("enter", ("thd:%p thd->lock:%p "
+ "thd->extra_lock: %p",
+ thd, thd->lock, thd->extra_lock));
DBUG_PRINT("debug", ("get_binlog_table_maps(): %d", thd->get_binlog_table_maps()));
- if (thd->get_binlog_table_maps() == 0)
+ MYSQL_LOCK *locks[2];
+ locks[0]= thd->extra_lock;
+ locks[1]= thd->lock;
+ my_bool with_annotate= thd->variables.binlog_annotate_row_events &&
+ thd->query() && thd->query_length();
+
+ for (uint i= 0 ; i < sizeof(locks)/sizeof(*locks) ; ++i )
{
- MYSQL_LOCK *locks[2];
- locks[0]= thd->extra_lock;
- locks[1]= thd->lock;
- my_bool with_annotate= thd->variables.binlog_annotate_row_events &&
- thd->query() && thd->query_length();
+ MYSQL_LOCK const *const lock= locks[i];
+ if (lock == NULL)
+ continue;
- for (uint i= 0 ; i < sizeof(locks)/sizeof(*locks) ; ++i )
+ TABLE **const end_ptr= lock->table + lock->table_count;
+ for (TABLE **table_ptr= lock->table ;
+ table_ptr != end_ptr ;
+ ++table_ptr)
{
- MYSQL_LOCK const *const lock= locks[i];
- if (lock == NULL)
- continue;
-
- TABLE **const end_ptr= lock->table + lock->table_count;
- for (TABLE **table_ptr= lock->table ;
- table_ptr != end_ptr ;
- ++table_ptr)
+ TABLE *const table= *table_ptr;
+ DBUG_PRINT("info", ("Checking table %s", table->s->table_name.str));
+ if (table->current_lock == F_WRLCK &&
+ table->file->check_table_binlog_row_based(0))
{
- TABLE *const table= *table_ptr;
- DBUG_PRINT("info", ("Checking table %s", table->s->table_name.str));
- if (table->current_lock == F_WRLCK &&
- check_table_binlog_row_based(thd, table))
- {
- /*
- We need to have a transactional behavior for SQLCOM_CREATE_TABLE
- (e.g. CREATE TABLE... SELECT * FROM TABLE) in order to keep a
- compatible behavior with the STMT based replication even when
- the table is not transactional. In other words, if the operation
- fails while executing the insert phase nothing is written to the
- binlog.
-
- Note that at this point, we check the type of a set of tables to
- create the table map events. In the function binlog_log_row(),
- which calls the current function, we check the type of the table
- of the current row.
- */
- bool const has_trans= thd->lex->sql_command == SQLCOM_CREATE_TABLE ||
- table->file->has_transactions();
- int const error= thd->binlog_write_table_map(table, has_trans,
- &with_annotate);
- /*
- If an error occurs, it is the responsibility of the caller to
- roll back the transaction.
- */
- if (unlikely(error))
- DBUG_RETURN(1);
- }
+ /*
+ We need to have a transactional behavior for SQLCOM_CREATE_TABLE
+ (e.g. CREATE TABLE... SELECT * FROM TABLE) in order to keep a
+ compatible behavior with the STMT based replication even when
+ the table is not transactional. In other words, if the operation
+ fails while executing the insert phase nothing is written to the
+ binlog.
+
+ Note that at this point, we check the type of a set of tables to
+ create the table map events. In the function binlog_log_row(),
+ which calls the current function, we check the type of the table
+ of the current row.
+ */
+ bool const has_trans= thd->lex->sql_command == SQLCOM_CREATE_TABLE ||
+ table->file->has_transactions();
+ int const error= thd->binlog_write_table_map(table, has_trans,
+ &with_annotate);
+ /*
+ If an error occurs, it is the responsibility of the caller to
+ roll back the transaction.
+ */
+ if (unlikely(error))
+ DBUG_RETURN(1);
}
}
}
@@ -5796,22 +5870,49 @@ static int write_locked_table_maps(THD *thd)
typedef bool Log_func(THD*, TABLE*, bool, const uchar*, const uchar*);
-static int binlog_log_row(TABLE* table,
- const uchar *before_record,
- const uchar *after_record,
- Log_func *log_func)
+static int binlog_log_row_internal(TABLE* table,
+ const uchar *before_record,
+ const uchar *after_record,
+ Log_func *log_func)
{
bool error= 0;
THD *const thd= table->in_use;
-#ifdef WITH_WSREP
/*
- Only InnoDB tables will be replicated through binlog emulation. Also
- updates in mysql.gtid_slave_state table should not be binlogged.
+ If there are no table maps written to the binary log, this is
+ the first row handled in this statement. In that case, we need
+ to write table maps for all locked tables to the binary log.
*/
+ if (likely(!(error= ((thd->get_binlog_table_maps() == 0 &&
+ write_locked_table_maps(thd))))))
+ {
+ /*
+ We need to have a transactional behavior for SQLCOM_CREATE_TABLE
+ (i.e. CREATE TABLE... SELECT * FROM TABLE) in order to keep a
+ compatible behavior with the STMT based replication even when
+ the table is not transactional. In other words, if the operation
+ fails while executing the insert phase nothing is written to the
+ binlog.
+ */
+ bool const has_trans= thd->lex->sql_command == SQLCOM_CREATE_TABLE ||
+ table->file->has_transactions();
+ error= (*log_func)(thd, table, has_trans, before_record, after_record);
+ }
+ return error ? HA_ERR_RBR_LOGGING_FAILED : 0;
+}
+
+static inline int binlog_log_row(TABLE* table,
+ const uchar *before_record,
+ const uchar *after_record,
+ Log_func *log_func)
+{
+#ifdef WITH_WSREP
+ THD *const thd= table->in_use;
+
+ /* only InnoDB tables will be replicated through binlog emulation */
if ((WSREP_EMULATE_BINLOG(thd) &&
table->file->partition_ht()->db_type != DB_TYPE_INNODB) ||
- (thd->wsrep_ignore_table == true))
+ (thd->wsrep_ignore_table == true))
return 0;
/* enforce wsrep_max_ws_rows */
@@ -5827,33 +5928,14 @@ static int binlog_log_row(TABLE* table,
return ER_ERROR_DURING_COMMIT;
}
}
-#endif /* WITH_WSREP */
+#endif
- if (check_table_binlog_row_based(thd, table))
- {
- /*
- If there are no table maps written to the binary log, this is
- the first row handled in this statement. In that case, we need
- to write table maps for all locked tables to the binary log.
- */
- if (likely(!(error= write_locked_table_maps(thd))))
- {
- /*
- We need to have a transactional behavior for SQLCOM_CREATE_TABLE
- (i.e. CREATE TABLE... SELECT * FROM TABLE) in order to keep a
- compatible behavior with the STMT based replication even when
- the table is not transactional. In other words, if the operation
- fails while executing the insert phase nothing is written to the
- binlog.
- */
- bool const has_trans= thd->lex->sql_command == SQLCOM_CREATE_TABLE ||
- table->file->has_transactions();
- error= (*log_func)(thd, table, has_trans, before_record, after_record);
- }
- }
- return error ? HA_ERR_RBR_LOGGING_FAILED : 0;
+ if (!table->file->check_table_binlog_row_based(1))
+ return 0;
+ return binlog_log_row_internal(table, before_record, after_record, log_func);
}
+
int handler::ha_external_lock(THD *thd, int lock_type)
{
int error;
@@ -5892,8 +5974,6 @@ int handler::ha_external_lock(THD *thd, int lock_type)
}
}
- ha_statistic_increment(&SSV::ha_external_lock_count);
-
/*
We cache the table flags if the locking succeeded. Otherwise, we
keep them as they were when they were fetched in ha_open().
@@ -5943,15 +6023,15 @@ int handler::ha_reset()
table->s->column_bitmap_size ==
(uchar*) table->def_write_set.bitmap);
DBUG_ASSERT(bitmap_is_set_all(&table->s->all_set));
- DBUG_ASSERT(table->key_read == 0);
+ DBUG_ASSERT(!table->file->keyread_enabled());
/* ensure that ha_index_end / ha_rnd_end has been called */
DBUG_ASSERT(inited == NONE);
- /* Free cache used by filesort */
- free_io_cache(table);
/* reset the bitmaps to point to defaults */
table->default_column_bitmaps();
pushed_cond= NULL;
tracker= NULL;
+ mark_trx_read_write_done= check_table_binlog_row_based_done=
+ check_table_binlog_row_based_result= 0;
/* Reset information about pushed engine conditions */
cancel_pushed_idx_cond();
/* Reset information about pushed index conditions */
@@ -5976,14 +6056,13 @@ int handler::ha_write_row(uchar *buf)
{ error= write_row(buf); })
MYSQL_INSERT_ROW_DONE(error);
- if (unlikely(error))
- DBUG_RETURN(error);
- rows_changed++;
- if (unlikely(error= binlog_log_row(table, 0, buf, log_func)))
- DBUG_RETURN(error); /* purecov: inspected */
-
+ if (likely(!error))
+ {
+ rows_changed++;
+ error= binlog_log_row(table, 0, buf, log_func);
+ }
DEBUG_SYNC_C("ha_write_row_end");
- DBUG_RETURN(0);
+ DBUG_RETURN(error);
}
@@ -6009,12 +6088,12 @@ int handler::ha_update_row(const uchar *old_data, uchar *new_data)
{ error= update_row(old_data, new_data);})
MYSQL_UPDATE_ROW_DONE(error);
- if (unlikely(error))
- return error;
- rows_changed++;
- if (unlikely(error= binlog_log_row(table, old_data, new_data, log_func)))
- return error;
- return 0;
+ if (likely(!error))
+ {
+ rows_changed++;
+ error= binlog_log_row(table, old_data, new_data, log_func);
+ }
+ return error;
}
int handler::ha_delete_row(const uchar *buf)
@@ -6036,12 +6115,12 @@ int handler::ha_delete_row(const uchar *buf)
TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_DELETE_ROW, active_index, 0,
{ error= delete_row(buf);})
MYSQL_DELETE_ROW_DONE(error);
- if (unlikely(error))
- return error;
- rows_changed++;
- if (unlikely(error= binlog_log_row(table, buf, 0, log_func)))
- return error;
- return 0;
+ if (likely(!error))
+ {
+ rows_changed++;
+ error= binlog_log_row(table, buf, 0, log_func);
+ }
+ return error;
}