diff options
Diffstat (limited to 'sql/handler.cc')
-rw-r--r-- | sql/handler.cc | 497 |
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; } |