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