diff options
Diffstat (limited to 'sql/handler.cc')
-rw-r--r-- | sql/handler.cc | 128 |
1 files changed, 100 insertions, 28 deletions
diff --git a/sql/handler.cc b/sql/handler.cc index ae9345d7673..7471fd8247d 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -642,6 +642,43 @@ void ha_checkpoint_state(bool disable) } +struct st_commit_checkpoint_request { + void *cookie; + void (*pre_hook)(void *); +}; + +static my_bool commit_checkpoint_request_handlerton(THD *unused1, plugin_ref plugin, + void *data) +{ + st_commit_checkpoint_request *st= (st_commit_checkpoint_request *)data; + handlerton *hton= plugin_data(plugin, handlerton *); + if (hton->state == SHOW_OPTION_YES && hton->commit_checkpoint_request) + { + void *cookie= st->cookie; + if (st->pre_hook) + (*st->pre_hook)(cookie); + (*hton->commit_checkpoint_request)(hton, cookie); + } + return FALSE; +} + + +/* + Invoke commit_checkpoint_request() in all storage engines that implement it. + + If pre_hook is non-NULL, the hook will be called prior to each invocation. +*/ +void +ha_commit_checkpoint_request(void *cookie, void (*pre_hook)(void *)) +{ + st_commit_checkpoint_request st; + st.cookie= cookie; + st.pre_hook= pre_hook; + plugin_foreach(NULL, commit_checkpoint_request_handlerton, + MYSQL_STORAGE_ENGINE_PLUGIN, &st); +} + + static my_bool closecon_handlerton(THD *thd, plugin_ref plugin, void *unused) @@ -1287,11 +1324,13 @@ int ha_commit_trans(THD *thd, bool all) goto done; } + DEBUG_SYNC(thd, "ha_commit_trans_before_log_and_order"); cookie= tc_log->log_and_order(thd, xid, all, need_prepare_ordered, need_commit_ordered); if (!cookie) goto err; + 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) ? 2 : 0; @@ -1783,6 +1822,17 @@ bool mysql_xa_recover(THD *thd) DBUG_RETURN(0); } +/* + Called by engine to notify TC that a new commit checkpoint has been reached. + See comments on handlerton method commit_checkpoint_request() for details. +*/ +void +commit_checkpoint_notify_ha(handlerton *hton, void *cookie) +{ + tc_log->commit_checkpoint_notify(cookie); +} + + /** @details This function should be called when MySQL sends rows of a SELECT result set @@ -2698,6 +2748,8 @@ int handler::update_auto_increment() bool append= FALSE; THD *thd= table->in_use; struct system_variables *variables= &thd->variables; + int result=0, tmp; + enum enum_check_fields save_count_cuted_fields; DBUG_ENTER("handler::update_auto_increment"); /* @@ -2715,8 +2767,10 @@ int handler::update_auto_increment() statement (case of INSERT VALUES(null),(3763),(null): the last NULL needs to insert 3764, not the value of the first NULL plus 1). + Ignore negative values. */ - adjust_next_insert_id_after_explicit_value(nr); + if ((longlong) nr > 0 || (table->next_number_field->flags & UNSIGNED_FLAG)) + adjust_next_insert_id_after_explicit_value(nr); insert_id_for_cur_row= 0; // didn't generate anything DBUG_RETURN(0); } @@ -2750,8 +2804,19 @@ int handler::update_auto_increment() reservation means potentially losing unused values). Note that in prelocked mode no estimation is given. */ + if ((auto_inc_intervals_count == 0) && (estimation_rows_to_insert > 0)) nb_desired_values= estimation_rows_to_insert; + else if ((auto_inc_intervals_count == 0) && + (thd->lex->many_values.elements > 0)) + { + /* + For multi-row inserts, if the bulk inserts cannot be started, the + handler::estimation_rows_to_insert will not be set. But we still + want to reserve the autoinc values. + */ + nb_desired_values= thd->lex->many_values.elements; + } else /* go with the increasing defaults */ { /* avoid overflow in formula, with this if() */ @@ -2764,7 +2829,6 @@ int handler::update_auto_increment() else nb_desired_values= AUTO_INC_DEFAULT_NB_MAX; } - /* This call ignores all its parameters but nr, currently */ get_auto_increment(variables->auto_increment_offset, variables->auto_increment_increment, nb_desired_values, &nr, @@ -2801,29 +2865,24 @@ int handler::update_auto_increment() } if (unlikely(nr == ULONGLONG_MAX)) - DBUG_RETURN(HA_ERR_AUTOINC_ERANGE); + DBUG_RETURN(HA_ERR_AUTOINC_ERANGE); - DBUG_PRINT("info",("auto_increment: %lu", (ulong) nr)); + DBUG_PRINT("info",("auto_increment: %llu nb_reserved_values: %llu", + nr, nb_reserved_values)); - if (unlikely(table->next_number_field->store((longlong) nr, TRUE))) - { - /* - first test if the query was aborted due to strict mode constraints - */ - if (killed_mask_hard(thd->killed) == KILL_BAD_DATA) - DBUG_RETURN(HA_ERR_AUTOINC_ERANGE); + /* Store field without warning (Warning will be printed by insert) */ + save_count_cuted_fields= thd->count_cuted_fields; + thd->count_cuted_fields= CHECK_FIELD_IGNORE; + tmp= table->next_number_field->store((longlong) nr, TRUE); + thd->count_cuted_fields= save_count_cuted_fields; + if (unlikely(tmp)) // Out of range value in store + { /* - field refused this value (overflow) and truncated it, use the result of - the truncation (which is going to be inserted); however we try to - decrease it to honour auto_increment_* variables. - That will shift the left bound of the reserved interval, we don't - bother shifting the right bound (anyway any other value from this - interval will cause a duplicate key). + It's better to return an error here than getting a confusing + 'duplicate key error' later. */ - nr= prev_insert_id(table->next_number_field->val_int(), variables); - if (unlikely(table->next_number_field->store((longlong) nr, TRUE))) - nr= table->next_number_field->val_int(); + result= HA_ERR_AUTOINC_ERANGE; } if (append) { @@ -2845,6 +2904,10 @@ int handler::update_auto_increment() already set. */ insert_id_for_cur_row= nr; + + if (result) // overflow + DBUG_RETURN(result); + /* Set next insert id to point to next auto-increment value to be able to handle multi-row statements. @@ -2968,7 +3031,7 @@ void handler::ha_release_auto_increment() } -void handler::print_keydup_error(uint key_nr, const char *msg) +void handler::print_keydup_error(uint key_nr, const char *msg, myf errflag) { /* Write the duplicated key in the error message */ char key[MAX_KEY_LENGTH]; @@ -2978,7 +3041,7 @@ void handler::print_keydup_error(uint key_nr, const char *msg) { /* Key is unknown */ str.copy("", 0, system_charset_info); - my_printf_error(ER_DUP_ENTRY, msg, MYF(0), str.c_ptr(), "*UNKNOWN*"); + my_printf_error(ER_DUP_ENTRY, msg, errflag, str.c_ptr(), "*UNKNOWN*"); } else { @@ -2991,7 +3054,7 @@ void handler::print_keydup_error(uint key_nr, const char *msg) str.append(STRING_WITH_LEN("...")); } my_printf_error(ER_DUP_ENTRY, msg, - MYF(0), str.c_ptr_safe(), table->key_info[key_nr].name); + errflag, str.c_ptr_safe(), table->key_info[key_nr].name); } } @@ -3059,7 +3122,7 @@ void handler::print_error(int error, myf errflag) uint key_nr=get_dup_key(error); if ((int) key_nr >= 0) { - print_keydup_error(key_nr, ER(ER_DUP_ENTRY_WITH_KEY_NAME)); + print_keydup_error(key_nr, ER(ER_DUP_ENTRY_WITH_KEY_NAME), errflag); DBUG_VOID_RETURN; } } @@ -3178,7 +3241,7 @@ void handler::print_error(int error, myf errflag) textno=ER_TABLE_DEF_CHANGED; break; case HA_ERR_NO_SUCH_TABLE: - my_error(ER_NO_SUCH_TABLE, errflag, table_share->db.str, + my_error(ER_NO_SUCH_TABLE_IN_ENGINE, errflag, table_share->db.str, table_share->table_name.str); DBUG_VOID_RETURN; case HA_ERR_RBR_LOGGING_FAILED: @@ -3206,7 +3269,10 @@ void handler::print_error(int error, myf errflag) textno= ER_AUTOINC_READ_FAILED; break; case HA_ERR_AUTOINC_ERANGE: - textno= ER_WARN_DATA_OUT_OF_RANGE; + textno= error; + my_error(textno, errflag, table->next_number_field->field_name, + table->in_use->warning_info->current_row_for_warning()); + DBUG_VOID_RETURN; break; case HA_ERR_TOO_MANY_CONCURRENT_TRXS: textno= ER_TOO_MANY_CONCURRENT_TRXS; @@ -4991,10 +5057,14 @@ bool ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat) db_type->show_status(db_type, thd, stat_print, stat) ? 1 : 0; } - if (!result) + /* + We also check thd->is_error() as Innodb may return 0 even if + there was an error. + */ + if (!result && !thd->is_error()) my_eof(thd); else if (!thd->is_error()) - my_error(ER_GET_ERRNO, MYF(0), 0); + my_error(ER_GET_ERRNO, MYF(0), errno); return result; } @@ -5283,6 +5353,8 @@ int handler::ha_write_row(uchar *buf) rows_changed++; if (unlikely(error= binlog_log_row(table, 0, buf, log_func))) DBUG_RETURN(error); /* purecov: inspected */ + + DEBUG_SYNC_C("ha_write_row_end"); DBUG_RETURN(0); } |