diff options
author | Ramil Kalimullin <ramil@mysql.com> | 2008-10-31 14:02:06 +0400 |
---|---|---|
committer | Ramil Kalimullin <ramil@mysql.com> | 2008-10-31 14:02:06 +0400 |
commit | 84356ab0adeb6a603ed8b5633750e8e95bb5b371 (patch) | |
tree | b649244c8f1642eb762b42d5a8242dc0efef09de /sql | |
parent | bba814d0b9dd248a14c25c703542f26fe0d65d4a (diff) | |
parent | e030732861d6b4250ef15528b93f5d0ea27a0c81 (diff) | |
download | mariadb-git-84356ab0adeb6a603ed8b5633750e8e95bb5b371.tar.gz |
Merge
Diffstat (limited to 'sql')
-rw-r--r-- | sql/field.cc | 35 | ||||
-rw-r--r-- | sql/field.h | 2 | ||||
-rw-r--r-- | sql/handler.cc | 7 | ||||
-rw-r--r-- | sql/log.cc | 2 | ||||
-rw-r--r-- | sql/log_event.cc | 38 | ||||
-rw-r--r-- | sql/log_event_old.cc | 47 | ||||
-rw-r--r-- | sql/share/errmsg.txt | 6 | ||||
-rw-r--r-- | sql/sql_class.cc | 2 | ||||
-rw-r--r-- | sql/sql_class.h | 4 | ||||
-rw-r--r-- | sql/sql_parse.cc | 78 |
10 files changed, 183 insertions, 38 deletions
diff --git a/sql/field.cc b/sql/field.cc index 16bf0fdb070..a03beb4e8af 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -8783,28 +8783,43 @@ bool Field::eq_def(Field *field) return 1; } + /** @return returns 1 if the fields are equally defined */ + bool Field_enum::eq_def(Field *field) { if (!Field::eq_def(field)) return 0; - TYPELIB *from_lib=((Field_enum*) field)->typelib; + return compare_enum_values(((Field_enum*) field)->typelib); +} - if (typelib->count < from_lib->count) - return 0; - for (uint i=0 ; i < from_lib->count ; i++) + +bool Field_enum::compare_enum_values(TYPELIB *values) +{ + if (typelib->count != values->count) + return FALSE; + for (uint i= 0; i < typelib->count; i++) if (my_strnncoll(field_charset, - (const uchar*)typelib->type_names[i], - strlen(typelib->type_names[i]), - (const uchar*)from_lib->type_names[i], - strlen(from_lib->type_names[i]))) - return 0; - return 1; + (const uchar*) typelib->type_names[i], + typelib->type_lengths[i], + (const uchar*) values->type_names[i], + values->type_lengths[i])) + return FALSE; + return TRUE; +} + + +uint Field_enum::is_equal(Create_field *new_field) +{ + if (!Field_str::is_equal(new_field)) + return 0; + return compare_enum_values(new_field->interval); } + /** @return returns 1 if the fields are equally defined diff --git a/sql/field.h b/sql/field.h index aa69fea6bdd..81905cc64ae 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1853,6 +1853,8 @@ public: CHARSET_INFO *sort_charset(void) const { return &my_charset_bin; } private: int do_save_field_metadata(uchar *first_byte); + bool compare_enum_values(TYPELIB *values); + uint is_equal(Create_field *new_field); }; diff --git a/sql/handler.cc b/sql/handler.cc index d82b2dd967e..9c70bd1a801 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1278,7 +1278,12 @@ int ha_rollback_trans(THD *thd, bool all) trans->ha_list= 0; trans->no_2pc=0; if (is_real_trans) - thd->transaction.xid_state.xid.null(); + { + if (thd->transaction_rollback_request) + thd->transaction.xid_state.rm_error= thd->main_da.sql_errno(); + else + thd->transaction.xid_state.xid.null(); + } if (all) { thd->variables.tx_isolation=thd->session_tx_isolation; diff --git a/sql/log.cc b/sql/log.cc index 8ab2e892b27..fb8669a5731 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -3779,7 +3779,7 @@ THD::binlog_set_pending_rows_event(Rows_log_event* ev) int MYSQL_BIN_LOG::remove_pending_rows_event(THD *thd) { - DBUG_ENTER(__FUNCTION__); + DBUG_ENTER("MYSQL_BIN_LOG::remove_pending_rows_event"); binlog_trx_data *const trx_data= (binlog_trx_data*) thd_get_ha_data(thd, binlog_hton); diff --git a/sql/log_event.cc b/sql/log_event.cc index f91ebf3823f..0d03593946d 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -7203,6 +7203,9 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) error= do_exec_row(rli); + DBUG_PRINT("info", ("error: %s", HA_ERR(error))); + DBUG_ASSERT(error != HA_ERR_RECORD_DELETED); + table->in_use = old_thd; switch (error) { @@ -7218,11 +7221,13 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) case HA_ERR_TABLE_DEF_CHANGED: case HA_ERR_CANNOT_ADD_FOREIGN: - + which are not included into to the list. + + Note that HA_ERR_RECORD_DELETED is not in the list since + do_exec_row() should not return that error code. */ case HA_ERR_RECORD_CHANGED: - case HA_ERR_RECORD_DELETED: case HA_ERR_KEY_NOT_FOUND: case HA_ERR_END_OF_FILE: case HA_ERR_FOUND_DUPP_KEY: @@ -7231,7 +7236,6 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) case HA_ERR_NO_REFERENCED_ROW: case HA_ERR_ROW_IS_REFERENCED: - DBUG_PRINT("info", ("error: %s", HA_ERR(error))); if (bit_is_set(slave_exec_mode, SLAVE_EXEC_MODE_IDEMPOTENT) == 1) { if (global_system_variables.log_warnings) @@ -7254,7 +7258,6 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) m_curr_row_end. */ - DBUG_PRINT("info", ("error: %d", error)); DBUG_PRINT("info", ("curr_row: 0x%lu; curr_row_end: 0x%lu; rows_end: 0x%lu", (ulong) m_curr_row, (ulong) m_curr_row_end, (ulong) m_rows_end)); @@ -8269,6 +8272,8 @@ Rows_log_event::write_row(const Relay_log_info *const rli, if (error) { DBUG_PRINT("info",("rnd_pos() returns error %d",error)); + if (error == HA_ERR_RECORD_DELETED) + error= HA_ERR_KEY_NOT_FOUND; table->file->print_error(error, MYF(0)); DBUG_RETURN(error); } @@ -8301,7 +8306,9 @@ Rows_log_event::write_row(const Relay_log_info *const rli, HA_READ_KEY_EXACT); if (error) { - DBUG_PRINT("info",("index_read_idx() returns error %d",error)); + DBUG_PRINT("info",("index_read_idx() returns %s", HA_ERR(error))); + if (error == HA_ERR_RECORD_DELETED) + error= HA_ERR_KEY_NOT_FOUND; table->file->print_error(error, MYF(0)); DBUG_RETURN(error); } @@ -8574,6 +8581,8 @@ int Rows_log_event::find_row(const Relay_log_info *rli) if (error) { DBUG_PRINT("info",("rnd_pos returns error %d",error)); + if (error == HA_ERR_RECORD_DELETED) + error= HA_ERR_KEY_NOT_FOUND; table->file->print_error(error, MYF(0)); } DBUG_RETURN(error); @@ -8633,6 +8642,8 @@ int Rows_log_event::find_row(const Relay_log_info *rli) HA_READ_KEY_EXACT))) { DBUG_PRINT("info",("no record matching the key found in the table")); + if (error == HA_ERR_RECORD_DELETED) + error= HA_ERR_KEY_NOT_FOUND; table->file->print_error(error, MYF(0)); table->file->ha_index_end(); goto err; @@ -8690,8 +8701,11 @@ int Rows_log_event::find_row(const Relay_log_info *rli) 256U - (1U << table->s->last_null_bit_pos); } - if ((error= table->file->index_next(table->record[0]))) + while ((error= table->file->index_next(table->record[0]))) { + /* We just skip records that has already been deleted */ + if (error == HA_ERR_RECORD_DELETED) + continue; DBUG_PRINT("info",("no record matching the given row found")); table->file->print_error(error, MYF(0)); table->file->ha_index_end(); @@ -8722,14 +8736,22 @@ int Rows_log_event::find_row(const Relay_log_info *rli) /* Continue until we find the right record or have made a full loop */ do { + restart_rnd_next: error= table->file->rnd_next(table->record[0]); + DBUG_PRINT("info", ("error: %s", HA_ERR(error))); switch (error) { case 0: - case HA_ERR_RECORD_DELETED: break; + /* + If the record was deleted, we pick the next one without doing + any comparisons. + */ + case HA_ERR_RECORD_DELETED: + goto restart_rnd_next; + case HA_ERR_END_OF_FILE: if (++restart_count < 2) table->file->ha_rnd_init(1); @@ -8759,7 +8781,7 @@ int Rows_log_event::find_row(const Relay_log_info *rli) DBUG_DUMP("record found", table->record[0], table->s->reclength); table->file->ha_rnd_end(); - DBUG_ASSERT(error == HA_ERR_END_OF_FILE || error == HA_ERR_RECORD_DELETED || error == 0); + DBUG_ASSERT(error == HA_ERR_END_OF_FILE || error == 0); goto err; } ok: diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc index c6b99b1bd69..75aa8722aa9 100644 --- a/sql/log_event_old.cc +++ b/sql/log_event_old.cc @@ -556,6 +556,9 @@ replace_record(THD *thd, TABLE *table, error= table->file->rnd_pos(table->record[1], table->file->dup_ref); if (error) { + DBUG_PRINT("info",("rnd_pos() returns error %d",error)); + if (error == HA_ERR_RECORD_DELETED) + error= HA_ERR_KEY_NOT_FOUND; table->file->print_error(error, MYF(0)); DBUG_RETURN(error); } @@ -582,6 +585,9 @@ replace_record(THD *thd, TABLE *table, HA_READ_KEY_EXACT); if (error) { + DBUG_PRINT("info", ("index_read_idx() returns error %d", error)); + if (error == HA_ERR_RECORD_DELETED) + error= HA_ERR_KEY_NOT_FOUND; table->file->print_error(error, MYF(0)); DBUG_RETURN(error); } @@ -787,11 +793,14 @@ static int find_and_fetch_row(TABLE *table, uchar *key) 256U - (1U << table->s->last_null_bit_pos); } - if ((error= table->file->index_next(table->record[1]))) + while ((error= table->file->index_next(table->record[1]))) { - table->file->print_error(error, MYF(0)); + /* We just skip records that has already been deleted */ + if (error == HA_ERR_RECORD_DELETED) + continue; + table->file->print_error(error, MYF(0)); table->file->ha_index_end(); - DBUG_RETURN(error); + DBUG_RETURN(error); } } @@ -812,6 +821,7 @@ static int find_and_fetch_row(TABLE *table, uchar *key) /* Continue until we find the right record or have made a full loop */ do { + restart_rnd_next: error= table->file->rnd_next(table->record[1]); DBUG_DUMP("record[0]", table->record[0], table->s->reclength); @@ -819,8 +829,14 @@ static int find_and_fetch_row(TABLE *table, uchar *key) switch (error) { case 0: + break; + + /* + If the record was deleted, we pick the next one without doing + any comparisons. + */ case HA_ERR_RECORD_DELETED: - break; + goto restart_rnd_next; case HA_ERR_END_OF_FILE: if (++restart_count < 2) @@ -1680,6 +1696,9 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli) error= do_exec_row(rli); + DBUG_PRINT("info", ("error: %d", error)); + DBUG_ASSERT(error != HA_ERR_RECORD_DELETED); + table->in_use = old_thd; switch (error) { @@ -2100,6 +2119,8 @@ Old_rows_log_event::write_row(const Relay_log_info *const rli, if (error) { DBUG_PRINT("info",("rnd_pos() returns error %d",error)); + if (error == HA_ERR_RECORD_DELETED) + error= HA_ERR_KEY_NOT_FOUND; table->file->print_error(error, MYF(0)); DBUG_RETURN(error); } @@ -2132,7 +2153,9 @@ Old_rows_log_event::write_row(const Relay_log_info *const rli, HA_READ_KEY_EXACT); if (error) { - DBUG_PRINT("info",("index_read_idx() returns error %d",error)); + DBUG_PRINT("info",("index_read_idx() returns error %d", error)); + if (error == HA_ERR_RECORD_DELETED) + error= HA_ERR_KEY_NOT_FOUND; table->file->print_error(error, MYF(0)); DBUG_RETURN(error); } @@ -2288,6 +2311,8 @@ int Old_rows_log_event::find_row(const Relay_log_info *rli) if (error) { DBUG_PRINT("info",("rnd_pos returns error %d",error)); + if (error == HA_ERR_RECORD_DELETED) + error= HA_ERR_KEY_NOT_FOUND; table->file->print_error(error, MYF(0)); } DBUG_RETURN(error); @@ -2347,6 +2372,8 @@ int Old_rows_log_event::find_row(const Relay_log_info *rli) HA_READ_KEY_EXACT))) { DBUG_PRINT("info",("no record matching the key found in the table")); + if (error == HA_ERR_RECORD_DELETED) + error= HA_ERR_KEY_NOT_FOUND; table->file->print_error(error, MYF(0)); table->file->ha_index_end(); DBUG_RETURN(error); @@ -2404,8 +2431,11 @@ int Old_rows_log_event::find_row(const Relay_log_info *rli) 256U - (1U << table->s->last_null_bit_pos); } - if ((error= table->file->index_next(table->record[0]))) + while ((error= table->file->index_next(table->record[0]))) { + /* We just skip records that has already been deleted */ + if (error == HA_ERR_RECORD_DELETED) + continue; DBUG_PRINT("info",("no record matching the given row found")); table->file->print_error(error, MYF(0)); table->file->ha_index_end(); @@ -2436,14 +2466,17 @@ int Old_rows_log_event::find_row(const Relay_log_info *rli) /* Continue until we find the right record or have made a full loop */ do { + restart_rnd_next: error= table->file->rnd_next(table->record[0]); switch (error) { case 0: - case HA_ERR_RECORD_DELETED: break; + case HA_ERR_RECORD_DELETED: + goto restart_rnd_next; + case HA_ERR_END_OF_FILE: if (++restart_count < 2) table->file->ha_rnd_init(1); diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 84eb5f5ba64..c6fa5366f46 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -6128,6 +6128,12 @@ ER_LOAD_DATA_INVALID_COLUMN ER_LOG_PURGE_NO_FILE eng "Being purged log %s was not found" +ER_XA_RBTIMEOUT XA106 + eng "XA_RBTIMEOUT: Transaction branch was rolled back: took too long" + +ER_XA_RBDEADLOCK XA102 + eng "XA_RBDEADLOCK: Transaction branch was rolled back: deadlock was detected" + ER_NEED_REPREPARE eng "Prepared statement needs to be re-prepared" diff --git a/sql/sql_class.cc b/sql/sql_class.cc index abbb2de0a82..e63eed2d23c 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -3513,7 +3513,7 @@ int THD::binlog_delete_row(TABLE* table, bool is_trans, int THD::binlog_remove_pending_rows_event(bool clear_maps) { - DBUG_ENTER(__FUNCTION__); + DBUG_ENTER("THD::binlog_remove_pending_rows_event"); if (!mysql_bin_log.is_open()) DBUG_RETURN(0); diff --git a/sql/sql_class.h b/sql/sql_class.h index 7696882bbcc..f5cf31d1030 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -739,7 +739,7 @@ struct st_savepoint { Ha_trx_info *ha_list; }; -enum xa_states {XA_NOTR=0, XA_ACTIVE, XA_IDLE, XA_PREPARED}; +enum xa_states {XA_NOTR=0, XA_ACTIVE, XA_IDLE, XA_PREPARED, XA_ROLLBACK_ONLY}; extern const char *xa_state_names[]; typedef struct st_xid_state { @@ -747,6 +747,8 @@ typedef struct st_xid_state { XID xid; // transaction identifier enum xa_states xa_state; // used by external XA only bool in_thd; + /* Error reported by the Resource Manager (RM) to the Transaction Manager. */ + uint rm_error; } XID_STATE; extern pthread_mutex_t LOCK_xid_cache; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index b083d93a801..704c16cfdec 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -83,9 +83,57 @@ const LEX_STRING command_name[]={ }; const char *xa_state_names[]={ - "NON-EXISTING", "ACTIVE", "IDLE", "PREPARED" + "NON-EXISTING", "ACTIVE", "IDLE", "PREPARED", "ROLLBACK ONLY" }; +/** + Mark a XA transaction as rollback-only if the RM unilaterally + rolled back the transaction branch. + + @note If a rollback was requested by the RM, this function sets + the appropriate rollback error code and transits the state + to XA_ROLLBACK_ONLY. + + @return TRUE if transaction was rolled back or if the transaction + state is XA_ROLLBACK_ONLY. FALSE otherwise. +*/ +static bool xa_trans_rolled_back(XID_STATE *xid_state) +{ + if (xid_state->rm_error) + { + switch (xid_state->rm_error) { + case ER_LOCK_WAIT_TIMEOUT: + my_error(ER_XA_RBTIMEOUT, MYF(0)); + break; + case ER_LOCK_DEADLOCK: + my_error(ER_XA_RBDEADLOCK, MYF(0)); + break; + default: + my_error(ER_XA_RBROLLBACK, MYF(0)); + } + xid_state->xa_state= XA_ROLLBACK_ONLY; + } + + return (xid_state->xa_state == XA_ROLLBACK_ONLY); +} + +/** + Rollback work done on behalf of at ransaction branch. +*/ +static bool xa_trans_rollback(THD *thd) +{ + bool status= test(ha_rollback(thd)); + + thd->options&= ~(ulong) OPTION_BEGIN; + thd->transaction.all.modified_non_trans_table= FALSE; + thd->server_status&= ~SERVER_STATUS_IN_TRANS; + xid_cache_delete(&thd->transaction.xid_state); + thd->transaction.xid_state.xa_state= XA_NOTR; + thd->transaction.xid_state.rm_error= 0; + + return status; +} + static void unlock_locked_tables(THD *thd) { if (thd->locked_tables) @@ -4505,6 +4553,7 @@ create_sp_error: } DBUG_ASSERT(thd->transaction.xid_state.xid.is_null()); thd->transaction.xid_state.xa_state=XA_ACTIVE; + thd->transaction.xid_state.rm_error= 0; thd->transaction.xid_state.xid.set(thd->lex->xid); xid_cache_insert(&thd->transaction.xid_state); thd->transaction.all.modified_non_trans_table= FALSE; @@ -4530,6 +4579,8 @@ create_sp_error: my_error(ER_XAER_NOTA, MYF(0)); break; } + if (xa_trans_rolled_back(&thd->transaction.xid_state)) + break; thd->transaction.xid_state.xa_state=XA_IDLE; my_ok(thd); break; @@ -4561,6 +4612,12 @@ create_sp_error: XID_STATE *xs=xid_cache_search(thd->lex->xid); if (!xs || xs->in_thd) my_error(ER_XAER_NOTA, MYF(0)); + else if (xa_trans_rolled_back(xs)) + { + ha_commit_or_rollback_by_xid(thd->lex->xid, 0); + xid_cache_delete(xs); + break; + } else { ha_commit_or_rollback_by_xid(thd->lex->xid, 1); @@ -4569,6 +4626,11 @@ create_sp_error: } break; } + if (xa_trans_rolled_back(&thd->transaction.xid_state)) + { + xa_trans_rollback(thd); + break; + } if (thd->transaction.xid_state.xa_state == XA_IDLE && thd->lex->xa_opt == XA_ONE_PHASE) { @@ -4615,28 +4677,26 @@ create_sp_error: my_error(ER_XAER_NOTA, MYF(0)); else { + bool ok= !xa_trans_rolled_back(xs); ha_commit_or_rollback_by_xid(thd->lex->xid, 0); xid_cache_delete(xs); - my_ok(thd); + if (ok) + my_ok(thd); } break; } if (thd->transaction.xid_state.xa_state != XA_IDLE && - thd->transaction.xid_state.xa_state != XA_PREPARED) + thd->transaction.xid_state.xa_state != XA_PREPARED && + thd->transaction.xid_state.xa_state != XA_ROLLBACK_ONLY) { my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[thd->transaction.xid_state.xa_state]); break; } - if (ha_rollback(thd)) + if (xa_trans_rollback(thd)) my_error(ER_XAER_RMERR, MYF(0)); else my_ok(thd); - thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG); - thd->transaction.all.modified_non_trans_table= FALSE; - thd->server_status&= ~SERVER_STATUS_IN_TRANS; - xid_cache_delete(&thd->transaction.xid_state); - thd->transaction.xid_state.xa_state=XA_NOTR; break; case SQLCOM_XA_RECOVER: res= mysql_xa_recover(thd); |