summaryrefslogtreecommitdiff
path: root/sql/handler.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/handler.cc')
-rw-r--r--sql/handler.cc485
1 files changed, 249 insertions, 236 deletions
diff --git a/sql/handler.cc b/sql/handler.cc
index 9e4ac52656d..bcf051deb62 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -79,6 +79,8 @@ TYPELIB tx_isolation_typelib= {array_elements(tx_isolation_names)-1,"",
static TYPELIB known_extensions= {0,"known_exts", NULL, NULL};
uint known_extensions_id= 0;
+static int commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans,
+ bool is_real_trans);
static plugin_ref ha_default_plugin(THD *thd)
@@ -343,6 +345,7 @@ int ha_init_errors(void)
SETMSG(HA_ERR_AUTOINC_READ_FAILED, ER(ER_AUTOINC_READ_FAILED));
SETMSG(HA_ERR_AUTOINC_ERANGE, ER(ER_WARN_DATA_OUT_OF_RANGE));
SETMSG(HA_ERR_TOO_MANY_CONCURRENT_TRXS, ER(ER_TOO_MANY_CONCURRENT_TRXS));
+ SETMSG(HA_ERR_DISK_FULL, ER(ER_DISK_FULL));
SETMSG(HA_ERR_TABLE_IN_FK_CHECK, "Table being used in foreign key check");
/* Register the error messages for use with my_error(). */
@@ -597,6 +600,23 @@ void ha_drop_database(char* path)
}
+static my_bool checkpoint_state_handlerton(THD *unused1, plugin_ref plugin,
+ void *disable)
+{
+ handlerton *hton= plugin_data(plugin, handlerton *);
+ if (hton->state == SHOW_OPTION_YES && hton->checkpoint_state)
+ hton->checkpoint_state(hton, (int) *(bool*) disable);
+ return FALSE;
+}
+
+
+void ha_checkpoint_state(bool disable)
+{
+ plugin_foreach(NULL, checkpoint_state_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN, &disable);
+}
+
+
+
static my_bool closecon_handlerton(THD *thd, plugin_ref plugin,
void *unused)
{
@@ -1078,7 +1098,7 @@ ha_check_and_coalesce_trx_read_only(THD *thd, Ha_trx_info *ha_list,
*/
int ha_commit_trans(THD *thd, bool all)
{
- int error= 0, cookie= 0;
+ int error= 0, cookie;
/*
'all' means that this is either an explicit commit issued by
user, or an implicit commit issued by a DDL.
@@ -1093,7 +1113,8 @@ int ha_commit_trans(THD *thd, bool all)
*/
bool is_real_trans= all || thd->transaction.all.ha_list == 0;
Ha_trx_info *ha_info= trans->ha_list;
- my_xid xid= thd->transaction.xid_state.xid.get_my_xid();
+ bool need_prepare_ordered, need_commit_ordered;
+ my_xid xid;
DBUG_ENTER("ha_commit_trans");
/* Just a random warning to test warnings pushed during autocommit. */
@@ -1132,89 +1153,114 @@ int ha_commit_trans(THD *thd, bool all)
DBUG_RETURN(2);
}
#ifdef USING_TRANSACTIONS
- if (ha_info)
+ if (!ha_info)
{
- uint rw_ha_count;
- bool rw_trans;
+ /* Free resources and perform other cleanup even for 'empty' transactions. */
+ if (is_real_trans)
+ thd->transaction.cleanup();
+ DBUG_RETURN(0);
+ }
- DBUG_EXECUTE_IF("crash_commit_before", DBUG_SUICIDE(););
+ DBUG_EXECUTE_IF("crash_commit_before", DBUG_SUICIDE(););
- /* Close all cursors that can not survive COMMIT */
- if (is_real_trans) /* not a statement commit */
- thd->stmt_map.close_transient_cursors();
+ /* Close all cursors that can not survive COMMIT */
+ if (is_real_trans) /* not a statement commit */
+ thd->stmt_map.close_transient_cursors();
- 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 */
- rw_trans= is_real_trans && (rw_ha_count > 0);
+ 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 > 0);
- if (rw_trans &&
- wait_if_global_read_lock(thd, 0, 0))
- {
- ha_rollback_trans(thd, all);
- DBUG_RETURN(1);
- }
+ if (rw_trans &&
+ wait_if_global_read_lock(thd, 0, 0))
+ {
+ ha_rollback_trans(thd, all);
+ DBUG_RETURN(1);
+ }
- if (rw_trans &&
- opt_readonly &&
- !(thd->security_ctx->master_access & SUPER_ACL) &&
- !thd->slave_thread)
- {
- my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
- ha_rollback_trans(thd, all);
- error= 1;
- goto end;
- }
+ if (rw_trans &&
+ opt_readonly &&
+ !(thd->security_ctx->master_access & SUPER_ACL) &&
+ !thd->slave_thread)
+ {
+ my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
+ goto err;
+ }
- if (!trans->no_2pc && (rw_ha_count > 1))
- {
- for (; ha_info && !error; ha_info= ha_info->next())
- {
- int err;
- handlerton *ht= ha_info->ht();
- /*
- Do not call two-phase commit if this particular
- transaction is read-only. This allows for simpler
- implementation in engines that are always read-only.
- */
- if (! ha_info->is_trx_read_write())
- continue;
- /*
- Sic: we know that prepare() is not NULL since otherwise
- trans->no_2pc would have been set.
- */
- if ((err= ht->prepare(ht, thd, all)))
- {
- my_error(ER_ERROR_DURING_COMMIT, MYF(0), err);
- error= 1;
- }
- status_var_increment(thd->status_var.ha_prepare_count);
- }
- DBUG_EXECUTE_IF("crash_commit_after_prepare", DBUG_SUICIDE(););
- if (error || (is_real_trans && xid &&
- (error= !(cookie= tc_log->log_xid(thd, xid)))))
- {
- ha_rollback_trans(thd, all);
- error= 1;
- goto end;
- }
- DBUG_EXECUTE_IF("crash_commit_after_log", DBUG_SUICIDE(););
- }
- error=ha_commit_one_phase(thd, all) ? (cookie ? 2 : 1) : 0;
- DBUG_EXECUTE_IF("crash_commit_before_unlog", DBUG_SUICIDE(););
- if (cookie)
- if(tc_log->unlog(cookie, xid))
- {
- error= 2;
- goto end;
- }
+ if (trans->no_2pc || (rw_ha_count <= 1))
+ {
+ error= ha_commit_one_phase(thd, all);
DBUG_EXECUTE_IF("crash_commit_after", DBUG_SUICIDE(););
-end:
- if (rw_trans)
- start_waiting_global_read_lock(thd);
+ goto end;
}
- /* Free resources and perform other cleanup even for 'empty' transactions. */
- else if (is_real_trans)
- thd->transaction.cleanup();
+
+ need_prepare_ordered= FALSE;
+ need_commit_ordered= FALSE;
+ xid= thd->transaction.xid_state.xid.get_my_xid();
+
+ for (Ha_trx_info *hi= ha_info; hi; hi= hi->next())
+ {
+ int err;
+ handlerton *ht= hi->ht();
+ /*
+ Do not call two-phase commit if this particular
+ transaction is read-only. This allows for simpler
+ implementation in engines that are always read-only.
+ */
+ if (! hi->is_trx_read_write())
+ continue;
+ /*
+ Sic: we know that prepare() is not NULL since otherwise
+ trans->no_2pc would have been set.
+ */
+ err= ht->prepare(ht, thd, all);
+ status_var_increment(thd->status_var.ha_prepare_count);
+ if (err)
+ my_error(ER_ERROR_DURING_COMMIT, MYF(0), err);
+
+ if (err)
+ goto err;
+
+ need_prepare_ordered|= (ht->prepare_ordered != NULL);
+ need_commit_ordered|= (ht->commit_ordered != NULL);
+ }
+ DBUG_EXECUTE_IF("crash_commit_after_prepare", DBUG_SUICIDE(););
+
+ if (!is_real_trans)
+ {
+ error= commit_one_phase_2(thd, all, trans, is_real_trans);
+ DBUG_EXECUTE_IF("crash_commit_after", DBUG_SUICIDE(););
+ goto end;
+ }
+
+ cookie= tc_log->log_and_order(thd, xid, all, need_prepare_ordered,
+ need_commit_ordered);
+ if (!cookie)
+ goto err;
+
+ DBUG_EXECUTE_IF("crash_commit_after_log", DBUG_SUICIDE(););
+
+ error= commit_one_phase_2(thd, all, trans, is_real_trans) ? 2 : 0;
+ DBUG_EXECUTE_IF("crash_commit_after", DBUG_SUICIDE(););
+
+ DBUG_EXECUTE_IF("crash_commit_before_unlog", DBUG_SUICIDE(););
+ if (tc_log->unlog(cookie, xid))
+ {
+ error= 2; /* Error during commit */
+ goto end;
+ }
+
+ DBUG_EXECUTE_IF("crash_commit_after", DBUG_SUICIDE(););
+ goto end;
+
+ /* Come here if error and we need to rollback. */
+err:
+ error= 1; /* Transaction was rolled back */
+ ha_rollback_trans(thd, all);
+
+end:
+ if (rw_trans)
+ start_waiting_global_read_lock(thd);
#endif /* USING_TRANSACTIONS */
DBUG_RETURN(error);
}
@@ -1225,7 +1271,6 @@ end:
*/
int ha_commit_one_phase(THD *thd, bool all)
{
- int error=0;
THD_TRANS *trans=all ? &thd->transaction.all : &thd->transaction.stmt;
/*
"real" is a nick name for a transaction for which a commit will
@@ -1235,8 +1280,16 @@ int ha_commit_one_phase(THD *thd, bool all)
enclosing 'all' transaction is rolled back.
*/
bool is_real_trans=all || thd->transaction.all.ha_list == 0;
- Ha_trx_info *ha_info= trans->ha_list, *ha_info_next;
DBUG_ENTER("ha_commit_one_phase");
+ DBUG_RETURN(commit_one_phase_2(thd, all, trans, is_real_trans));
+}
+
+static int
+commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans, bool is_real_trans)
+{
+ int error= 0;
+ Ha_trx_info *ha_info= trans->ha_list, *ha_info_next;
+ DBUG_ENTER("commit_one_phase_2");
#ifdef USING_TRANSACTIONS
if (ha_info)
{
@@ -1260,7 +1313,7 @@ int ha_commit_one_phase(THD *thd, bool all)
{
#ifdef HAVE_QUERY_CACHE
if (thd->transaction.changed_tables)
- query_cache.invalidate(thd->transaction.changed_tables);
+ query_cache.invalidate(thd, thd->transaction.changed_tables);
#endif
thd->variables.tx_isolation=thd->session_tx_isolation;
}
@@ -1352,13 +1405,12 @@ int ha_rollback_trans(THD *thd, bool all)
the error log; but we don't want users to wonder why they have this
message in the error log, so we don't send it.
- We don't have to test for thd->killed == THD::KILL_SYSTEM_THREAD as
+ We don't have to test for thd->killed == KILL_SYSTEM_THREAD as
it doesn't matter if a warning is pushed to a system thread or not:
No one will see it...
*/
if (is_real_trans && thd->transaction.all.modified_non_trans_table &&
- !thd->slave_thread && thd->killed != THD::KILL_CONNECTION &&
- thd->killed != THD::KILL_SERVER)
+ !thd->slave_thread && thd->killed < KILL_CONNECTION)
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARNING_NOT_COMPLETE_ROLLBACK,
ER(ER_WARNING_NOT_COMPLETE_ROLLBACK));
@@ -1859,7 +1911,16 @@ int ha_start_consistent_snapshot(THD *thd)
{
bool warn= true;
+ /*
+ Holding the LOCK_commit_ordered mutex ensures that we get the same
+ snapshot for all engines (including the binary log). This allows us
+ among other things to do backups with
+ START TRANSACTION WITH CONSISTENT SNAPSHOT and
+ have a consistent binlog position.
+ */
+ pthread_mutex_lock(&LOCK_commit_ordered);
plugin_foreach(thd, snapshot_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN, &warn);
+ pthread_mutex_unlock(&LOCK_commit_ordered);
/*
Same idea as when one wants to CREATE TABLE in one engine which does not
@@ -2113,7 +2174,7 @@ THD *handler::ha_thd(void) const
Don't wait for locks if not HA_OPEN_WAIT_IF_LOCKED is set
*/
int handler::ha_open(TABLE *table_arg, const char *name, int mode,
- int test_if_locked)
+ uint test_if_locked)
{
int error;
DBUG_ENTER("handler::ha_open");
@@ -2157,11 +2218,22 @@ int handler::ha_open(TABLE *table_arg, const char *name, int mode,
dup_ref=ref+ALIGN_SIZE(ref_length);
cached_table_flags= table_flags();
}
- rows_read= rows_changed= 0;
- memset(index_rows_read, 0, sizeof(index_rows_read));
+ reset_statistics();
+ internal_tmp_table= test(test_if_locked & HA_OPEN_INTERNAL_TABLE);
DBUG_RETURN(error);
}
+int handler::ha_close()
+{
+ DBUG_ENTER("ha_close");
+ /*
+ Increment global statistics for temporary tables.
+ In_use is 0 for tables that was closed from the table cache.
+ */
+ if (table->in_use)
+ status_var_add(table->in_use->status_var.rows_tmp_read, rows_tmp_read);
+ DBUG_RETURN(close());
+}
/* Initialize handler for random reading, with error handling */
@@ -2504,7 +2576,7 @@ int handler::update_auto_increment()
/*
first test if the query was aborted due to strict mode constraints
*/
- if (thd->killed == THD::KILL_BAD_DATA)
+ if (killed_mask_hard(thd->killed) == KILL_BAD_DATA)
DBUG_RETURN(HA_ERR_AUTOINC_ERANGE);
/*
@@ -2565,8 +2637,9 @@ int handler::update_auto_increment()
void handler::column_bitmaps_signal()
{
DBUG_ENTER("column_bitmaps_signal");
- DBUG_PRINT("info", ("read_set: 0x%lx write_set: 0x%lx", (long) table->read_set,
- (long) table->write_set));
+ if (table)
+ DBUG_PRINT("info", ("read_set: 0x%lx write_set: 0x%lx",
+ (long) table->read_set, (long) table->write_set));
DBUG_VOID_RETURN;
}
@@ -2643,6 +2716,7 @@ void handler::get_auto_increment(ulonglong offset, ulonglong increment,
void handler::ha_release_auto_increment()
{
+ DBUG_ENTER("ha_release_auto_increment");
release_auto_increment();
insert_id_for_cur_row= 0;
auto_inc_interval_for_cur_row.replace(0, 0, 0);
@@ -2656,6 +2730,7 @@ void handler::ha_release_auto_increment()
*/
table->in_use->auto_inc_intervals_forced.empty();
}
+ DBUG_VOID_RETURN;
}
@@ -2716,6 +2791,11 @@ void handler::print_error(int error, myf errflag)
case ENOENT:
textno=ER_FILE_NOT_FOUND;
break;
+ case ENOSPC:
+ case HA_ERR_DISK_FULL:
+ textno= ER_DISK_FULL;
+ SET_FATAL_ERROR; // Ensure error is logged
+ break;
case HA_ERR_KEY_NOT_FOUND:
case HA_ERR_NO_ACTIVE_RECORD:
case HA_ERR_END_OF_FILE:
@@ -2728,6 +2808,12 @@ void handler::print_error(int error, myf errflag)
SET_FATAL_ERROR;
textno=ER_KEY_NOT_FOUND;
break;
+ case HA_ERR_ABORTED_BY_USER:
+ {
+ DBUG_ASSERT(table->in_use->killed);
+ table->in_use->send_kill_message();
+ DBUG_VOID_RETURN;
+ }
case HA_ERR_WRONG_MRG_TABLE_DEF:
textno=ER_WRONG_MRG_TABLE;
break;
@@ -2779,15 +2865,15 @@ void handler::print_error(int error, myf errflag)
str.length(max_length-4);
str.append(STRING_WITH_LEN("..."));
}
- my_error(ER_FOREIGN_DUPLICATE_KEY, MYF(0), table_share->table_name.str,
- str.c_ptr_safe(), key_nr+1);
+ my_error(ER_FOREIGN_DUPLICATE_KEY, errflag, table_share->table_name.str,
+ str.c_ptr_safe(), key_nr+1);
DBUG_VOID_RETURN;
}
textno= ER_DUP_KEY;
break;
}
case HA_ERR_NULL_IN_SPATIAL:
- my_error(ER_CANT_CREATE_GEOMETRY_OBJECT, MYF(0));
+ my_error(ER_CANT_CREATE_GEOMETRY_OBJECT, errflag);
DBUG_VOID_RETURN;
case HA_ERR_FOUND_DUPP_UNIQUE:
textno=ER_DUP_UNIQUE;
@@ -2857,21 +2943,21 @@ void handler::print_error(int error, myf errflag)
{
String str;
get_error_message(error, &str);
- my_error(ER_ROW_IS_REFERENCED_2, MYF(0), str.c_ptr_safe());
+ my_error(ER_ROW_IS_REFERENCED_2, errflag, str.c_ptr_safe());
DBUG_VOID_RETURN;
}
case HA_ERR_NO_REFERENCED_ROW:
{
String str;
get_error_message(error, &str);
- my_error(ER_NO_REFERENCED_ROW_2, MYF(0), str.c_ptr_safe());
+ my_error(ER_NO_REFERENCED_ROW_2, errflag, str.c_ptr_safe());
DBUG_VOID_RETURN;
}
case HA_ERR_TABLE_DEF_CHANGED:
textno=ER_TABLE_DEF_CHANGED;
break;
case HA_ERR_NO_SUCH_TABLE:
- my_error(ER_NO_SUCH_TABLE, MYF(0), table_share->db.str,
+ my_error(ER_NO_SUCH_TABLE, errflag, table_share->db.str,
table_share->table_name.str);
DBUG_VOID_RETURN;
case HA_ERR_RBR_LOGGING_FAILED:
@@ -2883,7 +2969,7 @@ void handler::print_error(int error, myf errflag)
uint key_nr= get_dup_key(error);
if ((int) key_nr >= 0)
ptr= table->key_info[key_nr].name;
- my_error(ER_DROP_INDEX_FK, MYF(0), ptr);
+ my_error(ER_DROP_INDEX_FK, errflag, ptr);
DBUG_VOID_RETURN;
}
case HA_ERR_TABLE_NEEDS_UPGRADE:
@@ -2913,12 +2999,12 @@ void handler::print_error(int error, myf errflag)
{
const char* engine= table_type();
if (temporary)
- my_error(ER_GET_TEMPORARY_ERRMSG, MYF(0), error, str.c_ptr(),
+ my_error(ER_GET_TEMPORARY_ERRMSG, errflag, error, str.c_ptr(),
engine);
else
{
SET_FATAL_ERROR;
- my_error(ER_GET_ERRMSG, MYF(0), error, str.c_ptr(), engine);
+ my_error(ER_GET_ERRMSG, errflag, error, str.c_ptr(), engine);
}
}
else
@@ -2926,15 +3012,19 @@ void handler::print_error(int error, myf errflag)
DBUG_VOID_RETURN;
}
}
- if (fatal_error && (debug_assert_if_crashed_table ||
- global_system_variables.log_warnings > 1))
+ if (fatal_error)
{
- /*
- Log error to log before we crash or if extended warnings are requested
- */
- errflag|= ME_NOREFRESH;
- }
-
+ /* Ensure this becomes a true error */
+ errflag&= ~(ME_JUST_WARNING | ME_JUST_INFO);
+ if ((debug_assert_if_crashed_table ||
+ global_system_variables.log_warnings > 1))
+ {
+ /*
+ Log error to log before we crash or if extended warnings are requested
+ */
+ errflag|= ME_NOREFRESH;
+ }
+ }
my_error(textno, errflag, table_share->table_name.str, error);
DBUG_ASSERT(!fatal_error || !debug_assert_if_crashed_table);
DBUG_VOID_RETURN;
@@ -3197,7 +3287,7 @@ int handler::rename_table(const char * from, const char * to)
void handler::drop_table(const char *name)
{
- close();
+ ha_close();
delete_table(name);
}
@@ -3506,6 +3596,9 @@ handler::ha_delete_table(const char *name)
Drop table in the engine: public interface.
@sa handler::drop_table()
+
+ The difference between this and delete_table() is that the table is open in
+ drop_table().
*/
void
@@ -3710,6 +3803,7 @@ void handler::update_global_table_stats()
TABLE_STATS * table_stats;
status_var_add(table->in_use->status_var.rows_read, rows_read);
+ DBUG_ASSERT(rows_tmp_read == 0);
if (!table->in_use->userstat_running)
{
@@ -4342,133 +4436,6 @@ void ha_binlog_log_query(THD *thd, handlerton *hton,
}
#endif
-/**
- Read the first row of a multi-range set.
-
- @param found_range_p Returns a pointer to the element in 'ranges' that
- corresponds to the returned row.
- @param ranges An array of KEY_MULTI_RANGE range descriptions.
- @param range_count Number of ranges in 'ranges'.
- @param sorted If result should be sorted per key.
- @param buffer A HANDLER_BUFFER for internal handler usage.
-
- @note
- - Record is read into table->record[0].
- - *found_range_p returns a valid value only if read_multi_range_first()
- returns 0.
- - Sorting is done within each range. If you want an overall sort, enter
- 'ranges' with sorted ranges.
-
- @retval
- 0 OK, found a row
- @retval
- HA_ERR_END_OF_FILE No rows in range
- @retval
- \# Error code
-*/
-int handler::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
- KEY_MULTI_RANGE *ranges, uint range_count,
- bool sorted, HANDLER_BUFFER *buffer)
-{
- int result= HA_ERR_END_OF_FILE;
- DBUG_ENTER("handler::read_multi_range_first");
- multi_range_sorted= sorted;
- multi_range_buffer= buffer;
-
- table->mark_columns_used_by_index_no_reset(active_index, table->read_set);
- table->column_bitmaps_set(table->read_set, table->write_set);
-
- for (multi_range_curr= ranges, multi_range_end= ranges + range_count;
- multi_range_curr < multi_range_end;
- multi_range_curr++)
- {
- result= read_range_first(multi_range_curr->start_key.keypart_map ?
- &multi_range_curr->start_key : 0,
- multi_range_curr->end_key.keypart_map ?
- &multi_range_curr->end_key : 0,
- test(multi_range_curr->range_flag & EQ_RANGE),
- multi_range_sorted);
- if (result != HA_ERR_END_OF_FILE)
- break;
- }
-
- *found_range_p= multi_range_curr;
- DBUG_PRINT("exit",("result %d", result));
- DBUG_RETURN(result);
-}
-
-
-/**
- Read the next row of a multi-range set.
-
- @param found_range_p Returns a pointer to the element in 'ranges' that
- corresponds to the returned row.
-
- @note
- - Record is read into table->record[0].
- - *found_range_p returns a valid value only if read_multi_range_next()
- returns 0.
-
- @retval
- 0 OK, found a row
- @retval
- HA_ERR_END_OF_FILE No (more) rows in range
- @retval
- \# Error code
-*/
-int handler::read_multi_range_next(KEY_MULTI_RANGE **found_range_p)
-{
- int result= 0;
- DBUG_ENTER("handler::read_multi_range_next");
-
- /* We should not be called after the last call returned EOF. */
- DBUG_ASSERT(multi_range_curr < multi_range_end);
-
- do
- {
- /* Save a call if there can be only one row in range. */
- if (multi_range_curr->range_flag != (UNIQUE_RANGE | EQ_RANGE))
- {
- result= read_range_next();
-
- /* On success or non-EOF errors jump to the end. */
- if (result != HA_ERR_END_OF_FILE)
- break;
- }
- else
- {
- if (was_semi_consistent_read())
- goto scan_it_again;
- /*
- We need to set this for the last range only, but checking this
- condition is more expensive than just setting the result code.
- */
- result= HA_ERR_END_OF_FILE;
- }
-
- multi_range_curr++;
-scan_it_again:
- /* Try the next range(s) until one matches a record. */
- for (; multi_range_curr < multi_range_end; multi_range_curr++)
- {
- result= read_range_first(multi_range_curr->start_key.keypart_map ?
- &multi_range_curr->start_key : 0,
- multi_range_curr->end_key.keypart_map ?
- &multi_range_curr->end_key : 0,
- test(multi_range_curr->range_flag & EQ_RANGE),
- multi_range_sorted);
- if (result != HA_ERR_END_OF_FILE)
- break;
- }
- }
- while ((result == HA_ERR_END_OF_FILE) &&
- (multi_range_curr < multi_range_end));
-
- *found_range_p= multi_range_curr;
- DBUG_PRINT("exit",("handler::read_multi_range_next: result %d", result));
- DBUG_RETURN(result);
-}
-
/**
Read first row between two ranges.
@@ -4598,7 +4565,7 @@ int handler::read_range_next()
int handler::compare_key(key_range *range)
{
int cmp;
- if (!range)
+ if (!range || in_range_check_pushed_down)
return 0; // No max range
cmp= key_cmp(range_key_part, range->key, range->length);
if (!cmp)
@@ -4607,6 +4574,44 @@ int handler::compare_key(key_range *range)
}
+/*
+ Same as compare_key() but doesn't check have in_range_check_pushed_down.
+ This is used by index condition pushdown implementation.
+*/
+
+int handler::compare_key2(key_range *range)
+{
+ int cmp;
+ if (!range)
+ return 0; // no max range
+ cmp= key_cmp(range_key_part, range->key, range->length);
+ if (!cmp)
+ cmp= key_compare_result_on_equal;
+ return cmp;
+}
+
+
+/**
+ ICP callback - to be called by an engine to check the pushed condition
+*/
+extern "C" enum icp_result handler_index_cond_check(void* h_arg)
+{
+ handler *h= (handler*)h_arg;
+ THD *thd= h->table->in_use;
+ enum icp_result res;
+
+ if (thd_killed(thd))
+ return ICP_ABORTED_BY_USER;
+
+ if (h->end_range && h->compare_key2(h->end_range) > 0)
+ return ICP_OUT_OF_RANGE;
+ h->increment_statistics(&SSV::ha_icp_attempts);
+ if ((res= h->pushed_idx_cond->val_int()? ICP_MATCH : ICP_NO_MATCH) ==
+ ICP_MATCH)
+ h->increment_statistics(&SSV::ha_icp_match);
+ return res;
+}
+
int handler::index_read_idx_map(uchar * buf, uint index, const uchar * key,
key_part_map keypart_map,
enum ha_rkey_function find_flag)
@@ -4793,7 +4798,8 @@ static bool check_table_binlog_row_based(THD *thd, TABLE *table)
/** @brief
Write table maps for all (manually or automatically) locked tables
- to the binary log.
+ to the binary log. Also, if binlog_annotate_row_events is ON,
+ write Annotate_rows event before the first table map.
SYNOPSIS
write_locked_table_maps()
@@ -4830,6 +4836,9 @@ static int write_locked_table_maps(THD *thd)
locks[0]= thd->extra_lock;
locks[1]= thd->lock;
locks[2]= thd->locked_tables;
+ 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 const *const lock= locks[i];
@@ -4847,7 +4856,8 @@ static int write_locked_table_maps(THD *thd)
check_table_binlog_row_based(thd, table))
{
int const has_trans= table->file->has_transactions();
- int const error= thd->binlog_write_table_map(table, has_trans);
+ 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.
@@ -4946,6 +4956,9 @@ int handler::ha_reset()
/* reset the bitmaps to point to defaults */
table->default_column_bitmaps();
pushed_cond= NULL;
+ /* Reset information about pushed engine conditions */
+ cancel_pushed_idx_cond();
+ /* Reset information about pushed index conditions */
DBUG_RETURN(reset());
}