Commit ac6b3c44 authored by Sergei Golubchik's avatar Sergei Golubchik

few small MySQL bugs/issues that impact the engines, as discussed in the SE summit

* remove handler::index_read_last()
* create handler::keyread_read_time() (was get_index_only_read_time() in opt_range.cc)
* ha_show_status() allows engine's show_status() to fail
* remove HTON_FLUSH_AFTER_RENAME
* fix key_cmp_if_same() to work for floats and doubles
* set table->status in the server, don't force engines to do it
* increment status vars in the server, don't force engines to do it

mysql-test/r/status_user.result:
  correct test results - innodb was wrongly counting internal
  index searches as handler_read_* calls.
sql/ha_partition.cc:
  compensate for handler incrementing status counters -
  we want to count only calls to underlying engines
sql/handler.h:
  inline methods moved to sql_class.h
sql/key.cc:
  simplify the check
sql/opt_range.cc:
  move get_index_only_read_time to the handler class
sql/sp.cc:
  don't use a key that's stored in the record buffer -
  the engine can overwrite the buffer with anything, destroying the key
sql/sql_class.h:
  inline handler methods that need to see THD and TABLE definitions
sql/sql_select.cc:
  no ha_index_read_last_map anymore
sql/sql_table.cc:
  remove HTON_FLUSH_AFTER_RENAME
sql/table.cc:
  set HA_CAN_MEMCMP as appropriate
sql/tztime.cc:
  don't use a key that's stored in the record buffer -
  the engine can overwrite the buffer with anything, destroying the key
storage/myisam/ha_myisam.cc:
  engines don't need to update table->status or use ha_statistic_increment anymore
storage/myisam/ha_myisam.h:
  index_read_last_map is no more
parent 59eb4f6a
No related merge requests found
......@@ -300,6 +300,7 @@ enum ha_base_keytype {
*/
#define HA_END_SPACE_ARE_EQUAL 512
#define HA_BIT_PART 1024
#define HA_CAN_MEMCMP 2048 /* internal, never stored in frm */
/* optionbits for database */
#define HA_OPTION_PACK_RECORD 1
......
......@@ -100,8 +100,8 @@ Handler_commit 19
Handler_delete 1
Handler_discover 0
Handler_prepare 18
Handler_read_first 1
Handler_read_key 8
Handler_read_first 0
Handler_read_key 3
Handler_read_next 0
Handler_read_prev 0
Handler_read_rnd 0
......@@ -113,7 +113,7 @@ Handler_update 5
Handler_write 7
select variable_value - @global_read_key as "handler_read_key" from information_schema.global_status where variable_name="handler_read_key";
handler_read_key
8
3
set @@global.userstat=0;
select * from information_schema.index_statistics;
TABLE_SCHEMA TABLE_NAME INDEX_NAME ROWS_READ
......
......@@ -3636,6 +3636,7 @@ int ha_partition::rnd_next(uchar *buf)
int result= HA_ERR_END_OF_FILE;
uint part_id= m_part_spec.start_part;
DBUG_ENTER("ha_partition::rnd_next");
decrement_statistics(&SSV::ha_read_rnd_next_count);
if (NO_CURRENT_PART_ID == part_id)
{
......@@ -3779,6 +3780,7 @@ int ha_partition::rnd_pos(uchar * buf, uchar *pos)
uint part_id;
handler *file;
DBUG_ENTER("ha_partition::rnd_pos");
decrement_statistics(&SSV::ha_read_rnd_count);
part_id= uint2korr((const uchar *) pos);
DBUG_ASSERT(part_id < m_tot_parts);
......@@ -3991,6 +3993,7 @@ int ha_partition::index_read_map(uchar *buf, const uchar *key,
enum ha_rkey_function find_flag)
{
DBUG_ENTER("ha_partition::index_read_map");
decrement_statistics(&SSV::ha_read_key_count);
end_range= 0;
m_index_scan_type= partition_index_read;
m_start_key.key= key;
......@@ -4119,6 +4122,7 @@ int ha_partition::common_index_read(uchar *buf, bool have_start_key)
int ha_partition::index_first(uchar * buf)
{
DBUG_ENTER("ha_partition::index_first");
decrement_statistics(&SSV::ha_read_first_count);
end_range= 0;
m_index_scan_type= partition_index_first;
......@@ -4150,6 +4154,7 @@ int ha_partition::index_first(uchar * buf)
int ha_partition::index_last(uchar * buf)
{
DBUG_ENTER("ha_partition::index_last");
decrement_statistics(&SSV::ha_read_last_count);
m_index_scan_type= partition_index_last;
DBUG_RETURN(common_first_last(buf));
......@@ -4177,39 +4182,6 @@ int ha_partition::common_first_last(uchar *buf)
}
/*
Read last using key
SYNOPSIS
index_read_last_map()
buf Read row in MySQL Row Format
key Key
keypart_map Which part of key is used
RETURN VALUE
>0 Error code
0 Success
DESCRIPTION
This is used in join_read_last_key to optimise away an ORDER BY.
Can only be used on indexes supporting HA_READ_ORDER
*/
int ha_partition::index_read_last_map(uchar *buf, const uchar *key,
key_part_map keypart_map)
{
DBUG_ENTER("ha_partition::index_read_last");
m_ordered= TRUE; // Safety measure
end_range= 0;
m_index_scan_type= partition_index_read_last;
m_start_key.key= key;
m_start_key.keypart_map= keypart_map;
m_start_key.flag= HA_READ_PREFIX_LAST;
DBUG_RETURN(common_index_read(buf, TRUE));
}
/*
Read next record in a forward index scan
......@@ -4228,6 +4200,7 @@ int ha_partition::index_read_last_map(uchar *buf, const uchar *key,
int ha_partition::index_next(uchar * buf)
{
DBUG_ENTER("ha_partition::index_next");
decrement_statistics(&SSV::ha_read_next_count);
/*
TODO(low priority):
......@@ -4264,6 +4237,7 @@ int ha_partition::index_next(uchar * buf)
int ha_partition::index_next_same(uchar *buf, const uchar *key, uint keylen)
{
DBUG_ENTER("ha_partition::index_next_same");
decrement_statistics(&SSV::ha_read_next_count);
DBUG_ASSERT(keylen == m_start_key.length);
DBUG_ASSERT(m_index_scan_type != partition_index_last);
......@@ -4291,6 +4265,7 @@ int ha_partition::index_next_same(uchar *buf, const uchar *key, uint keylen)
int ha_partition::index_prev(uchar * buf)
{
DBUG_ENTER("ha_partition::index_prev");
decrement_statistics(&SSV::ha_read_prev_count);
/* TODO: read comment in index_next */
DBUG_ASSERT(m_index_scan_type != partition_index_first);
......@@ -4704,12 +4679,6 @@ int ha_partition::handle_ordered_index_scan(uchar *buf, bool reverse_order)
error= file->ha_index_last(rec_buf_ptr);
reverse_order= TRUE;
break;
case partition_index_read_last:
error= file->ha_index_read_last_map(rec_buf_ptr,
m_start_key.key,
m_start_key.keypart_map);
reverse_order= TRUE;
break;
case partition_read_range:
{
/*
......
......@@ -64,9 +64,8 @@ private:
partition_index_first= 1,
partition_index_first_unordered= 2,
partition_index_last= 3,
partition_index_read_last= 4,
partition_read_range = 5,
partition_no_index_scan= 6
partition_read_range = 4,
partition_no_index_scan= 5
};
/* Data for the partition handler */
int m_mode; // Open mode
......@@ -458,8 +457,6 @@ public:
virtual int index_first(uchar * buf);
virtual int index_last(uchar * buf);
virtual int index_next_same(uchar * buf, const uchar * key, uint keylen);
virtual int index_read_last_map(uchar * buf, const uchar * key,
key_part_map keypart_map);
/*
read_first_row is virtual method but is only implemented by
......
......@@ -2044,12 +2044,6 @@ handler *handler::clone(MEM_ROOT *mem_root)
}
void handler::ha_statistic_increment(ulong SSV::*offset) const
{
status_var_increment(table->in_use->status_var.*offset);
}
void **handler::ha_data(THD *thd) const
{
return thd_ha_data(thd, ht);
......@@ -2131,8 +2125,6 @@ int handler::read_first_row(uchar * buf, uint primary_key)
register int error;
DBUG_ENTER("handler::read_first_row");
ha_statistic_increment(&SSV::ha_read_first_count);
/*
If there is very few deleted rows in the table, find the first row by
scanning the table.
......@@ -2142,14 +2134,14 @@ int handler::read_first_row(uchar * buf, uint primary_key)
!(index_flags(primary_key, 0, 0) & HA_READ_ORDER))
{
(void) ha_rnd_init(1);
while ((error= rnd_next(buf)) == HA_ERR_RECORD_DELETED) ;
while ((error= ha_rnd_next(buf)) == HA_ERR_RECORD_DELETED) ;
(void) ha_rnd_end();
}
else
{
/* Find the first row through the primary key */
if (!(error = ha_index_init(primary_key, 0)))
error= index_first(buf);
error= ha_index_first(buf);
(void) ha_index_end();
}
DBUG_RETURN(error);
......@@ -2520,10 +2512,10 @@ void handler::get_auto_increment(ulonglong offset, ulonglong increment,
table->mark_columns_used_by_index_no_reset(table->s->next_number_index,
table->read_set);
column_bitmaps_signal();
index_init(table->s->next_number_index, 1);
ha_index_init(table->s->next_number_index, 1);
if (table->s->next_number_keypart == 0)
{ // Autoincrement at key-start
error=index_last(table->record[1]);
error=ha_index_last(table->record[1]);
/*
MySQL implicitely assumes such method does locking (as MySQL decides to
use nr+increment without checking again with the handler, in
......@@ -2555,7 +2547,7 @@ void handler::get_auto_increment(ulonglong offset, ulonglong increment,
else
nr= ((ulonglong) table->next_number_field->
val_int_offset(table->s->rec_buff_length)+1);
index_end();
ha_index_end();
(void) extra(HA_EXTRA_NO_KEYREAD);
*first_value= nr;
}
......@@ -3110,6 +3102,33 @@ int handler::ha_check(THD *thd, HA_CHECK_OPT *check_opt)
return update_frm_version(table);
}
/*
Calculate cost of 'index only' scan for given index and number of records.
SYNOPSIS
handler->keyread_read_time()
index key to read
ranges number of ranges
rows #of records to read
NOTES
It is assumed that we will read trough all key ranges and that all
key blocks are half full (normally things are much better). It is also
assumed that each time we read the next key from the index, the handler
performs a random seek, thus the cost is proportional to the number of
blocks read.
*/
double handler::keyread_read_time(uint index, uint ranges, ha_rows rows)
{
double read_time;
uint keys_per_block= (stats.block_size/2/
(table->key_info[index].key_length + ref_length) + 1);
read_time=((double) (rows+keys_per_block-1)/ (double) keys_per_block);
return read_time;
}
/**
A helper function to mark a transaction read-write,
if it is started.
......@@ -3503,7 +3522,7 @@ int ha_enable_transaction(THD *thd, bool on)
int handler::index_next_same(uchar *buf, const uchar *key, uint keylen)
{
int error;
DBUG_ENTER("index_next_same");
DBUG_ENTER("handler::index_next_same");
if (!(error=index_next(buf)))
{
my_ptrdiff_t ptrdiff= buf - table->record[0];
......@@ -3548,6 +3567,7 @@ int handler::index_next_same(uchar *buf, const uchar *key, uint keylen)
key_part->field->move_field_offset(-ptrdiff);
}
}
DBUG_PRINT("return",("%i", error));
DBUG_RETURN(error);
}
......@@ -4598,6 +4618,8 @@ bool ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat)
if (!result)
my_eof(thd);
else if (!thd->is_error())
my_error(ER_GET_ERRNO, MYF(0), 0);
return result;
}
......@@ -4798,6 +4820,7 @@ int handler::ha_write_row(uchar *buf)
DBUG_ENTER("handler::ha_write_row");
mark_trx_read_write();
increment_statistics(&SSV::ha_write_count);
if (unlikely(error= write_row(buf)))
DBUG_RETURN(error);
......@@ -4820,6 +4843,7 @@ int handler::ha_update_row(const uchar *old_data, uchar *new_data)
DBUG_ASSERT(new_data == table->record[0]);
mark_trx_read_write();
increment_statistics(&SSV::ha_update_count);
if (unlikely(error= update_row(old_data, new_data)))
return error;
......@@ -4835,6 +4859,7 @@ int handler::ha_delete_row(const uchar *buf)
Log_func *log_func= Delete_rows_log_event::binlog_row_logging_function;
mark_trx_read_write();
increment_statistics(&SSV::ha_delete_count);
if (unlikely(error= delete_row(buf)))
return error;
......
......@@ -843,7 +843,6 @@ inline LEX_STRING *hton_name(const handlerton *hton)
#define HTON_ALTER_NOT_SUPPORTED (1 << 1) //Engine does not support alter
#define HTON_CAN_RECREATE (1 << 2) //Delete all is used fro truncate
#define HTON_HIDDEN (1 << 3) //Engine does not appear in lists
#define HTON_FLUSH_AFTER_RENAME (1 << 4)
#define HTON_NOT_USER_SELECTABLE (1 << 5)
#define HTON_TEMPORARY_NOT_SUPPORTED (1 << 6) //Having temporary tables not supported
#define HTON_SUPPORT_LOG_TABLES (1 << 7) //Engine supports log tables
......@@ -1439,6 +1438,7 @@ public:
{ return ulonglong2double(stats.data_file_length) / IO_SIZE + 2; }
virtual double read_time(uint index, uint ranges, ha_rows rows)
{ return rows2double(ranges+rows); }
virtual double keyread_read_time(uint index, uint ranges, ha_rows rows);
virtual const key_map *keys_to_use_for_scanning() { return &key_map_empty; }
bool has_transactions()
{ return (ha_table_flags() & HA_NO_TRANSACTIONS) == 0; }
......@@ -1572,17 +1572,6 @@ protected:
virtual int index_last(uchar * buf)
{ return HA_ERR_WRONG_COMMAND; }
virtual int index_next_same(uchar *buf, const uchar *key, uint keylen);
/**
@brief
The following functions works like index_read, but it find the last
row with the current key value or prefix.
*/
virtual int index_read_last_map(uchar * buf, const uchar * key,
key_part_map keypart_map)
{
uint key_len= calculate_key_len(table, active_index, key, keypart_map);
return index_read_last(buf, key, key_len);
}
inline void update_index_statistics()
{
index_rows_read[active_index]++;
......@@ -1593,68 +1582,15 @@ public:
/* Similar functions like the above, but does statistics counting */
inline int ha_index_read_map(uchar * buf, const uchar * key,
key_part_map keypart_map,
enum ha_rkey_function find_flag)
{
int error= index_read_map(buf, key, keypart_map, find_flag);
if (!error)
update_index_statistics();
return error;
}
enum ha_rkey_function find_flag);
inline int ha_index_read_idx_map(uchar * buf, uint index, const uchar * key,
key_part_map keypart_map,
enum ha_rkey_function find_flag)
{
int error= index_read_idx_map(buf, index, key, keypart_map, find_flag);
if (!error)
{
rows_read++;
index_rows_read[index]++;
}
return error;
}
inline int ha_index_next(uchar * buf)
{
int error= index_next(buf);
if (!error)
update_index_statistics();
return error;
}
inline int ha_index_prev(uchar * buf)
{
int error= index_prev(buf);
if (!error)
update_index_statistics();
return error;
}
inline int ha_index_first(uchar * buf)
{
int error= index_first(buf);
if (!error)
update_index_statistics();
return error;
}
inline int ha_index_last(uchar * buf)
{
int error= index_last(buf);
if (!error)
update_index_statistics();
return error;
}
inline int ha_index_next_same(uchar *buf, const uchar *key, uint keylen)
{
int error= index_next_same(buf, key, keylen);
if (!error)
update_index_statistics();
return error;
}
inline int ha_index_read_last_map(uchar * buf, const uchar * key,
key_part_map keypart_map)
{
int error= index_read_last_map(buf, key, keypart_map);
if (!error)
update_index_statistics();
return error;
}
enum ha_rkey_function find_flag);
inline int ha_index_next(uchar * buf);
inline int ha_index_prev(uchar * buf);
inline int ha_index_first(uchar * buf);
inline int ha_index_last(uchar * buf);
inline int ha_index_next_same(uchar *buf, const uchar *key, uint keylen);
virtual int read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
KEY_MULTI_RANGE *ranges, uint range_count,
......@@ -1688,41 +1624,11 @@ private:
public:
/* Same as above, but with statistics */
inline int ha_ft_read(uchar *buf)
{
int error= ft_read(buf);
if (!error)
rows_read++;
return error;
}
inline int ha_rnd_next(uchar *buf)
{
int error= rnd_next(buf);
if (!error)
rows_read++;
return error;
}
inline int ha_rnd_pos(uchar *buf, uchar *pos)
{
int error= rnd_pos(buf, pos);
if (!error)
rows_read++;
return error;
}
inline int ha_rnd_pos_by_record(uchar *buf)
{
int error= rnd_pos_by_record(buf);
if (!error)
rows_read++;
return error;
}
inline int ha_read_first_row(uchar *buf, uint primary_key)
{
int error= read_first_row(buf, primary_key);
if (!error)
rows_read++;
return error;
}
inline int ha_ft_read(uchar *buf);
inline int ha_rnd_next(uchar *buf);
inline int ha_rnd_pos(uchar *buf, uchar *pos);
inline int ha_rnd_pos_by_record(uchar *buf);
inline int ha_read_first_row(uchar *buf, uint primary_key);
/**
The following 3 function is only needed for tables that may be
......@@ -2041,8 +1947,10 @@ public:
virtual bool check_if_supported_virtual_columns(void) { return FALSE;}
protected:
/* deprecated, don't use in new engines */
inline void ha_statistic_increment(ulong SSV::*offset) const { }
/* Service methods for use by storage engines. */
void ha_statistic_increment(ulong SSV::*offset) const;
void **ha_data(THD *) const;
THD *ha_thd(void) const;
......@@ -2068,6 +1976,8 @@ private:
if (!mark_trx_done)
mark_trx_read_write_part2();
}
inline void increment_statistics(ulong SSV::*offset) const;
inline void decrement_statistics(ulong SSV::*offset) const;
/*
Low-level primitives for storage engines. These should be
......@@ -2155,8 +2065,6 @@ private:
virtual int index_read(uchar * buf, const uchar * key, uint key_len,
enum ha_rkey_function find_flag)
{ return HA_ERR_WRONG_COMMAND; }
virtual int index_read_last(uchar * buf, const uchar * key, uint key_len)
{ return (my_errno= HA_ERR_WRONG_COMMAND); }
/**
This method is similar to update_row, however the handler doesn't need
to execute the updates at this point in time. The handler can be certain
......
......@@ -278,8 +278,7 @@ bool key_cmp_if_same(TABLE *table,const uchar *key,uint idx,uint key_length)
key++;
store_length--;
}
if (key_part->key_part_flag & (HA_BLOB_PART | HA_VAR_LENGTH_PART |
HA_BIT_PART))
if (!(key_part->key_part_flag & HA_CAN_MEMCMP))
{
if (key_part->field->key_cmp(key, key_part->length))
return 1;
......
......@@ -707,10 +707,7 @@ TRP_ROR_INTERSECT *get_best_covering_ror_intersect(PARAM *param,
static
TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge,
double read_time);
static
TRP_GROUP_MIN_MAX *get_best_group_min_max(PARAM *param, SEL_TREE *tree);
static double get_index_only_read_time(const PARAM* param, ha_rows records,
int keynr);
static TRP_GROUP_MIN_MAX *get_best_group_min_max(PARAM *param, SEL_TREE *tree);
#ifndef DBUG_OFF
static void print_sel_tree(PARAM *param, SEL_TREE *tree, key_map *tree_map,
......@@ -2314,9 +2311,9 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
if (!head->covering_keys.is_clear_all())
{
int key_for_use= find_shortest_key(head, &head->covering_keys);
double key_read_time= (get_index_only_read_time(&param, records,
key_for_use) +
(double) records / TIME_FOR_COMPARE);
double key_read_time= param.table->file->keyread_read_time(key_for_use,
1, records) +
(double) records / TIME_FOR_COMPARE;
DBUG_PRINT("info", ("'all'+'using index' scan will be using key %d, "
"read time %g", key_for_use, key_read_time));
if (key_read_time < read_time)
......@@ -3938,42 +3935,6 @@ skip_to_ror_scan:
}
/*
Calculate cost of 'index only' scan for given index and number of records.
SYNOPSIS
get_index_only_read_time()
param parameters structure
records #of records to read
keynr key to read
NOTES
It is assumed that we will read trough the whole key range and that all
key blocks are half full (normally things are much better). It is also
assumed that each time we read the next key from the index, the handler
performs a random seek, thus the cost is proportional to the number of
blocks read.
TODO:
Move this to handler->read_time() by adding a flag 'index-only-read' to
this call. The reason for doing this is that the current function doesn't
handle the case when the row is stored in the b-tree (like in innodb
clustered index)
*/
static double get_index_only_read_time(const PARAM* param, ha_rows records,
int keynr)
{
double read_time;
uint keys_per_block= (param->table->file->stats.block_size/2/
(param->table->key_info[keynr].key_length+
param->table->file->ref_length) + 1);
read_time=((double) (records+keys_per_block-1)/
(double) keys_per_block);
return read_time;
}
typedef struct st_ror_scan_info
{
uint idx; /* # of used key in param->keys */
......@@ -4050,8 +4011,8 @@ ROR_SCAN_INFO *make_ror_scan(const PARAM *param, int idx, SEL_ARG *sel_arg)
bitmap_set_bit(&ror_scan->covered_fields, key_part->fieldnr-1);
}
ror_scan->index_read_cost=
get_index_only_read_time(param, param->table->quick_rows[ror_scan->keynr],
ror_scan->keynr);
param->table->file->keyread_read_time(ror_scan->keynr, 1,
param->table->quick_rows[ror_scan->keynr]);
DBUG_RETURN(ror_scan);
}
......@@ -4886,7 +4847,8 @@ static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree,
We can resolve this by only reading through this key.
0.01 is added to avoid races between range and 'index' scan.
*/
found_read_time= get_index_only_read_time(param,found_records,keynr) +
found_read_time= param->table->file->keyread_read_time(keynr,1,
found_records) +
cpu_cost + 0.01;
}
else
......
......@@ -1276,6 +1276,7 @@ sp_drop_db_routines(THD *thd, char *db)
TABLE *table;
int ret;
uint key_len;
uchar keybuf[MAX_KEY_LENGTH];
DBUG_ENTER("sp_drop_db_routines");
DBUG_PRINT("enter", ("db: %s", db));
......@@ -1285,12 +1286,14 @@ sp_drop_db_routines(THD *thd, char *db)
table->field[MYSQL_PROC_FIELD_DB]->store(db, strlen(db), system_charset_info);
key_len= table->key_info->key_part[0].store_length;
table->field[MYSQL_PROC_FIELD_DB]->get_key_image(keybuf, key_len, Field::itRAW);
ret= SP_OK;
table->file->ha_index_init(0, 1);
if (!table->file->ha_index_read_map(table->record[0],
(uchar *) table->field[MYSQL_PROC_FIELD_DB]->ptr,
(key_part_map)1, HA_READ_KEY_EXACT))
if (!table->file->ha_index_read_map(table->record[0], keybuf, (key_part_map)1,
HA_READ_KEY_EXACT))
{
int nxtres;
bool deleted= FALSE;
......@@ -1305,11 +1308,8 @@ sp_drop_db_routines(THD *thd, char *db)
nxtres= 0;
break;
}
} while (!(nxtres= table->file->
ha_index_next_same(table->record[0],
(uchar *)table->field[MYSQL_PROC_FIELD_DB]->
ptr,
key_len)));
} while (!(nxtres= table->file->ha_index_next_same(table->record[0],
keybuf, key_len)));
if (nxtres != HA_ERR_END_OF_FILE)
ret= SP_KEY_NOT_FOUND;
if (deleted)
......
......@@ -3133,4 +3133,150 @@ void add_diff_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var,
STATUS_VAR *dec_var);
void mark_transaction_to_rollback(THD *thd, bool all);
/*
inline handler methods that need to know TABLE and THD structures
*/
inline void handler::increment_statistics(ulong SSV::*offset) const
{
status_var_increment(table->in_use->status_var.*offset);
}
inline void handler::decrement_statistics(ulong SSV::*offset) const
{
status_var_decrement(table->in_use->status_var.*offset);
}
inline int handler::ha_index_read_map(uchar * buf, const uchar * key,
key_part_map keypart_map,
enum ha_rkey_function find_flag)
{
DBUG_ASSERT(inited==INDEX);
increment_statistics(&SSV::ha_read_key_count);
int error= index_read_map(buf, key, keypart_map, find_flag);
if (!error)
update_index_statistics();
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
}
inline int handler::ha_index_read_idx_map(uchar * buf, uint index,
const uchar * key,
key_part_map keypart_map,
enum ha_rkey_function find_flag)
{
increment_statistics(&SSV::ha_read_key_count);
int error= index_read_idx_map(buf, index, key, keypart_map, find_flag);
if (!error)
{
rows_read++;
index_rows_read[index]++;
}
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
}
inline int handler::ha_index_next(uchar * buf)
{
DBUG_ASSERT(inited==INDEX);
increment_statistics(&SSV::ha_read_next_count);
int error= index_next(buf);
if (!error)
update_index_statistics();
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
}
inline int handler::ha_index_prev(uchar * buf)
{
DBUG_ASSERT(inited==INDEX);
increment_statistics(&SSV::ha_read_prev_count);
int error= index_prev(buf);
if (!error)
update_index_statistics();
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
}
inline int handler::ha_index_first(uchar * buf)
{
DBUG_ASSERT(inited==INDEX);
increment_statistics(&SSV::ha_read_first_count);
int error= index_first(buf);
if (!error)
update_index_statistics();
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
}
inline int handler::ha_index_last(uchar * buf)
{
DBUG_ASSERT(inited==INDEX);
increment_statistics(&SSV::ha_read_last_count);
int error= index_last(buf);
if (!error)
update_index_statistics();
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
}
inline int handler::ha_index_next_same(uchar *buf, const uchar *key,
uint keylen)
{
DBUG_ASSERT(inited==INDEX);
increment_statistics(&SSV::ha_read_next_count);
int error= index_next_same(buf, key, keylen);
if (!error)
update_index_statistics();
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
}
inline int handler::ha_ft_read(uchar *buf)
{
int error= ft_read(buf);
if (!error)
rows_read++;
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
}
inline int handler::ha_rnd_next(uchar *buf)
{
increment_statistics(&SSV::ha_read_rnd_next_count);
int error= rnd_next(buf);
if (!error)
rows_read++;
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
}
inline int handler::ha_rnd_pos(uchar *buf, uchar *pos)
{
increment_statistics(&SSV::ha_read_rnd_count);
int error= rnd_pos(buf, pos);
if (!error)
rows_read++;
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
}
inline int handler::ha_rnd_pos_by_record(uchar *buf)
{
int error= rnd_pos_by_record(buf);
if (!error)
rows_read++;
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
}
inline int handler::ha_read_first_row(uchar *buf, uint primary_key)
{
int error= read_first_row(buf, primary_key);
if (!error)
rows_read++;
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
}
#endif /* MYSQL_SERVER */
......@@ -12249,9 +12249,10 @@ join_read_last_key(JOIN_TAB *tab)
}
if (cp_buffer_from_ref(tab->join->thd, table, &tab->ref))
return -1;
if ((error= table->file->ha_index_read_last_map(table->record[0],
tab->ref.key_buff,
make_prev_keypart_map(tab->ref.key_parts))))
if ((error= table->file->ha_index_read_map(table->record[0],
tab->ref.key_buff,
make_prev_keypart_map(tab->ref.key_parts),
HA_READ_PREFIX_LAST)))
{
if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
return report_error(table, error);
......
......@@ -7668,27 +7668,6 @@ view_err:
if (write_bin_log(thd, TRUE, thd->query(), thd->query_length()))
DBUG_RETURN(TRUE);
if (ha_check_storage_engine_flag(old_db_type, HTON_FLUSH_AFTER_RENAME))
{
/*
For the alter table to be properly flushed to the logs, we
have to open the new table. If not, we get a problem on server
shutdown. But we do not need to attach MERGE children.
*/
char path[FN_REFLEN];
TABLE *t_table;
build_table_filename(path + 1, sizeof(path) - 1, new_db, table_name, "", 0);
t_table= open_temporary_table(thd, path, new_db, tmp_name, 0);
if (t_table)
{
intern_close_table(t_table);
my_free(t_table, MYF(0));
}
else
sql_print_warning("Could not open table %s.%s after rename\n",
new_db,table_name);
ha_flush_logs(old_db_type);
}
table_list->table=0; // For query cache
query_cache_invalidate3(thd, table_list, 0);
......
......@@ -1594,6 +1594,15 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
*/
if (field->real_maybe_null())
key_part->key_part_flag|= HA_NULL_PART;
/*
Sometimes we can compare key parts for equality with memcmp.
But not always.
*/
if (!(key_part->key_part_flag & (HA_BLOB_PART | HA_VAR_LENGTH_PART |
HA_BIT_PART)) &&
key_part->type != HA_KEYTYPE_FLOAT &&
key_part->type == HA_KEYTYPE_DOUBLE)
key_part->key_part_flag|= HA_CAN_MEMCMP;
}
keyinfo->usable_key_parts= usable_parts; // Filesort
......
......@@ -1813,6 +1813,7 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
uint tzid, ttid;
my_time_t ttime;
char buff[MAX_FIELD_WIDTH];
uchar keybuff[32];
String abbr(buff, sizeof(buff), &my_charset_latin1);
char *alloc_buff, *tz_name_buff;
/*
......@@ -1891,9 +1892,10 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
table= tz_tables->table;
tz_tables= tz_tables->next_local;
table->field[0]->store((longlong) tzid, TRUE);
table->field[0]->get_key_image(keybuff, sizeof(keybuff), Field::itRAW);
(void)table->file->ha_index_init(0, 1);
if (table->file->ha_index_read_map(table->record[0], table->field[0]->ptr,
if (table->file->ha_index_read_map(table->record[0], keybuff,
HA_WHOLE_KEY, HA_READ_KEY_EXACT))
{
sql_print_error("Can't find description of time zone '%u'", tzid);
......@@ -1918,9 +1920,10 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
table= tz_tables->table;
tz_tables= tz_tables->next_local;
table->field[0]->store((longlong) tzid, TRUE);
table->field[0]->get_key_image(keybuff, sizeof(keybuff), Field::itRAW);
(void)table->file->ha_index_init(0, 1);
res= table->file->ha_index_read_map(table->record[0], table->field[0]->ptr,
res= table->file->ha_index_read_map(table->record[0], keybuff,
(key_part_map)1, HA_READ_KEY_EXACT);
while (!res)
{
......@@ -1968,8 +1971,7 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
tmp_tz_info.typecnt= ttid + 1;
res= table->file->ha_index_next_same(table->record[0],
table->field[0]->ptr, 4);
res= table->file->ha_index_next_same(table->record[0], keybuff, 4);
}
if (res != HA_ERR_END_OF_FILE)
......@@ -1991,7 +1993,7 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
table->field[0]->store((longlong) tzid, TRUE);
(void)table->file->ha_index_init(0, 1);
res= table->file->ha_index_read_map(table->record[0], table->field[0]->ptr,
res= table->file->ha_index_read_map(table->record[0], keybuff,
(key_part_map)1, HA_READ_KEY_EXACT);
while (!res)
{
......@@ -2021,8 +2023,7 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
("time_zone_transition table: tz_id: %u tt_time: %lu tt_id: %u",
tzid, (ulong) ttime, ttid));
res= table->file->ha_index_next_same(table->record[0],
table->field[0]->ptr, 4);
res= table->file->ha_index_next_same(table->record[0], keybuff, 4);
}
/*
......
......@@ -776,8 +776,6 @@ int ha_myisam::close(void)
int ha_myisam::write_row(uchar *buf)
{
ha_statistic_increment(&SSV::ha_write_count);
/* If we have a timestamp column, update it to the current time */
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
table->timestamp_field->set_time();
......@@ -1663,7 +1661,6 @@ bool ha_myisam::is_crashed() const
int ha_myisam::update_row(const uchar *old_data, uchar *new_data)
{
ha_statistic_increment(&SSV::ha_update_count);
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
table->timestamp_field->set_time();
return mi_update(file,old_data,new_data);
......@@ -1671,7 +1668,6 @@ int ha_myisam::update_row(const uchar *old_data, uchar *new_data)
int ha_myisam::delete_row(const uchar *buf)
{
ha_statistic_increment(&SSV::ha_delete_count);
return mi_delete(file,buf);
}
......@@ -1679,84 +1675,48 @@ int ha_myisam::index_read_map(uchar *buf, const uchar *key,
key_part_map keypart_map,
enum ha_rkey_function find_flag)
{
DBUG_ASSERT(inited==INDEX);
ha_statistic_increment(&SSV::ha_read_key_count);
int error=mi_rkey(file, buf, active_index, key, keypart_map, find_flag);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
return mi_rkey(file, buf, active_index, key, keypart_map, find_flag);
}
int ha_myisam::index_read_idx_map(uchar *buf, uint index, const uchar *key,
key_part_map keypart_map,
enum ha_rkey_function find_flag)
{
ha_statistic_increment(&SSV::ha_read_key_count);
int error=mi_rkey(file, buf, index, key, keypart_map, find_flag);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
}
int ha_myisam::index_read_last_map(uchar *buf, const uchar *key,
key_part_map keypart_map)
{
DBUG_ENTER("ha_myisam::index_read_last");
DBUG_ASSERT(inited==INDEX);
ha_statistic_increment(&SSV::ha_read_key_count);
int error=mi_rkey(file, buf, active_index, key, keypart_map,
HA_READ_PREFIX_LAST);
table->status=error ? STATUS_NOT_FOUND: 0;
DBUG_RETURN(error);
return mi_rkey(file, buf, index, key, keypart_map, find_flag);
}
int ha_myisam::index_next(uchar *buf)
{
DBUG_ASSERT(inited==INDEX);
ha_statistic_increment(&SSV::ha_read_next_count);
int error=mi_rnext(file,buf,active_index);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
return mi_rnext(file,buf,active_index);
}
int ha_myisam::index_prev(uchar *buf)
{
DBUG_ASSERT(inited==INDEX);
ha_statistic_increment(&SSV::ha_read_prev_count);
int error=mi_rprev(file,buf, active_index);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
return mi_rprev(file,buf, active_index);
}
int ha_myisam::index_first(uchar *buf)
{
DBUG_ASSERT(inited==INDEX);
ha_statistic_increment(&SSV::ha_read_first_count);
int error=mi_rfirst(file, buf, active_index);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
return mi_rfirst(file, buf, active_index);
}
int ha_myisam::index_last(uchar *buf)
{
DBUG_ASSERT(inited==INDEX);
ha_statistic_increment(&SSV::ha_read_last_count);
int error=mi_rlast(file, buf, active_index);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
return mi_rlast(file, buf, active_index);
}
int ha_myisam::index_next_same(uchar *buf,
const uchar *key __attribute__((unused)),
uint length __attribute__((unused)))
{
DBUG_ENTER("ha_myisam::index_next_same");
int error;
DBUG_ASSERT(inited==INDEX);
ha_statistic_increment(&SSV::ha_read_next_count);
do
{
error= mi_rnext_same(file,buf);
} while (error == HA_ERR_RECORD_DELETED);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
DBUG_PRINT("return",("%i", error));
DBUG_RETURN(error);
}
......@@ -1769,10 +1729,7 @@ int ha_myisam::rnd_init(bool scan)
int ha_myisam::rnd_next(uchar *buf)
{
ha_statistic_increment(&SSV::ha_read_rnd_next_count);
int error=mi_scan(file, buf);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
return mi_scan(file, buf);
}
int ha_myisam::remember_rnd_pos()
......@@ -1788,10 +1745,7 @@ int ha_myisam::restart_rnd_next(uchar *buf)
int ha_myisam::rnd_pos(uchar *buf, uchar *pos)
{
ha_statistic_increment(&SSV::ha_read_rnd_count);
int error=mi_rrnd(file, buf, my_get_ptr(pos,ref_length));
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
return mi_rrnd(file, buf, my_get_ptr(pos,ref_length));
}
void ha_myisam::position(const uchar *record)
......@@ -2092,8 +2046,6 @@ int ha_myisam::ft_read(uchar *buf)
&LOCK_status); // why ?
error=ft_handler->please->read_next(ft_handler,(char*) buf);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
}
......
......@@ -71,7 +71,6 @@ class ha_myisam: public handler
int index_read_idx_map(uchar *buf, uint index, const uchar *key,
key_part_map keypart_map,
enum ha_rkey_function find_flag);
int index_read_last_map(uchar *buf, const uchar *key, key_part_map keypart_map);
int index_next(uchar * buf);
int index_prev(uchar * buf);
int index_first(uchar * buf);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment