mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
BUG#121915: Merge 4.1->5.0
This commit is contained in:
@ -263,3 +263,62 @@ test
|
|||||||
delete from t1 where count(*)=1;
|
delete from t1 where count(*)=1;
|
||||||
ERROR HY000: Invalid use of group function
|
ERROR HY000: Invalid use of group function
|
||||||
drop table t1;
|
drop table t1;
|
||||||
|
create table t1 ( a int, index (a) );
|
||||||
|
insert into t1 values (0),(0),(0),(0),(0),(0),(0),(0);
|
||||||
|
flush status;
|
||||||
|
select a from t1 order by a limit 1;
|
||||||
|
a
|
||||||
|
0
|
||||||
|
show status like 'handler_read%';
|
||||||
|
Variable_name Value
|
||||||
|
Handler_read_first 1
|
||||||
|
Handler_read_key 0
|
||||||
|
Handler_read_next 0
|
||||||
|
Handler_read_prev 0
|
||||||
|
Handler_read_rnd 0
|
||||||
|
Handler_read_rnd_next 0
|
||||||
|
flush status;
|
||||||
|
update t1 set a=unix_timestamp() order by a limit 1;
|
||||||
|
show status like 'handler_read%';
|
||||||
|
Variable_name Value
|
||||||
|
Handler_read_first 1
|
||||||
|
Handler_read_key 0
|
||||||
|
Handler_read_next 0
|
||||||
|
Handler_read_prev 0
|
||||||
|
Handler_read_rnd 1
|
||||||
|
Handler_read_rnd_next 0
|
||||||
|
flush status;
|
||||||
|
delete from t1 order by a limit 1;
|
||||||
|
show status like 'handler_read%';
|
||||||
|
Variable_name Value
|
||||||
|
Handler_read_first 1
|
||||||
|
Handler_read_key 0
|
||||||
|
Handler_read_next 0
|
||||||
|
Handler_read_prev 0
|
||||||
|
Handler_read_rnd 0
|
||||||
|
Handler_read_rnd_next 0
|
||||||
|
flush status;
|
||||||
|
delete from t1 order by a desc limit 1;
|
||||||
|
show status like 'handler_read%';
|
||||||
|
Variable_name Value
|
||||||
|
Handler_read_first 0
|
||||||
|
Handler_read_key 0
|
||||||
|
Handler_read_next 0
|
||||||
|
Handler_read_prev 0
|
||||||
|
Handler_read_rnd 1
|
||||||
|
Handler_read_rnd_next 9
|
||||||
|
alter table t1 disable keys;
|
||||||
|
flush status;
|
||||||
|
delete from t1 order by a limit 1;
|
||||||
|
show status like 'handler_read%';
|
||||||
|
Variable_name Value
|
||||||
|
Handler_read_first 0
|
||||||
|
Handler_read_key 0
|
||||||
|
Handler_read_next 0
|
||||||
|
Handler_read_prev 0
|
||||||
|
Handler_read_rnd 1
|
||||||
|
Handler_read_rnd_next 9
|
||||||
|
select count(*) from t1;
|
||||||
|
count(*)
|
||||||
|
5
|
||||||
|
drop table t1;
|
||||||
|
@ -227,4 +227,33 @@ select DATABASE();
|
|||||||
delete from t1 where count(*)=1;
|
delete from t1 where count(*)=1;
|
||||||
drop table t1;
|
drop table t1;
|
||||||
|
|
||||||
|
# BUG#12915: Optimize "DELETE|UPDATE ... ORDER BY ... LIMIT n" to use an index
|
||||||
|
create table t1 ( a int, index (a) );
|
||||||
|
insert into t1 values (0),(0),(0),(0),(0),(0),(0),(0);
|
||||||
|
|
||||||
|
flush status;
|
||||||
|
select a from t1 order by a limit 1;
|
||||||
|
show status like 'handler_read%';
|
||||||
|
|
||||||
|
flush status;
|
||||||
|
update t1 set a=unix_timestamp() order by a limit 1;
|
||||||
|
show status like 'handler_read%';
|
||||||
|
|
||||||
|
flush status;
|
||||||
|
delete from t1 order by a limit 1;
|
||||||
|
show status like 'handler_read%';
|
||||||
|
|
||||||
|
flush status;
|
||||||
|
delete from t1 order by a desc limit 1;
|
||||||
|
show status like 'handler_read%';
|
||||||
|
|
||||||
|
alter table t1 disable keys;
|
||||||
|
|
||||||
|
flush status;
|
||||||
|
delete from t1 order by a limit 1;
|
||||||
|
show status like 'handler_read%';
|
||||||
|
|
||||||
|
select count(*) from t1;
|
||||||
|
|
||||||
|
drop table t1;
|
||||||
# End of 4.1 tests
|
# End of 4.1 tests
|
||||||
|
@ -1334,6 +1334,8 @@ void change_byte(byte *,uint,char,char);
|
|||||||
void init_read_record(READ_RECORD *info, THD *thd, TABLE *reg_form,
|
void init_read_record(READ_RECORD *info, THD *thd, TABLE *reg_form,
|
||||||
SQL_SELECT *select,
|
SQL_SELECT *select,
|
||||||
int use_record_cache, bool print_errors);
|
int use_record_cache, bool print_errors);
|
||||||
|
void init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table,
|
||||||
|
bool print_error, uint idx);
|
||||||
void end_read_record(READ_RECORD *info);
|
void end_read_record(READ_RECORD *info);
|
||||||
ha_rows filesort(THD *thd, TABLE *form,struct st_sort_field *sortorder,
|
ha_rows filesort(THD *thd, TABLE *form,struct st_sort_field *sortorder,
|
||||||
uint s_length, SQL_SELECT *select,
|
uint s_length, SQL_SELECT *select,
|
||||||
|
@ -3674,7 +3674,6 @@ static void bootstrap(FILE *file)
|
|||||||
|
|
||||||
THD *thd= new THD;
|
THD *thd= new THD;
|
||||||
thd->bootstrap=1;
|
thd->bootstrap=1;
|
||||||
thd->client_capabilities=0;
|
|
||||||
my_net_init(&thd->net,(st_vio*) 0);
|
my_net_init(&thd->net,(st_vio*) 0);
|
||||||
thd->max_client_packet_length= thd->net.max_packet;
|
thd->max_client_packet_length= thd->net.max_packet;
|
||||||
thd->security_ctx->master_access= ~(ulong)0;
|
thd->security_ctx->master_access= ~(ulong)0;
|
||||||
|
@ -1362,6 +1362,95 @@ SEL_ARG *SEL_ARG::clone_tree()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Find the best index to retrieve first N records in given order
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
get_index_for_order()
|
||||||
|
table Table to be accessed
|
||||||
|
order Required ordering
|
||||||
|
limit Number of records that will be retrieved
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
Find the best index that allows to retrieve first #limit records in the
|
||||||
|
given order cheaper then one would retrieve them using full table scan.
|
||||||
|
|
||||||
|
IMPLEMENTATION
|
||||||
|
Run through all table indexes and find the shortest index that allows
|
||||||
|
records to be retrieved in given order. We look for the shortest index
|
||||||
|
as we will have fewer index pages to read with it.
|
||||||
|
|
||||||
|
This function is used only by UPDATE/DELETE, so we take into account how
|
||||||
|
the UPDATE/DELETE code will work:
|
||||||
|
* index can only be scanned in forward direction
|
||||||
|
* HA_EXTRA_KEYREAD will not be used
|
||||||
|
Perhaps these assumptions could be relaxed
|
||||||
|
|
||||||
|
RETURN
|
||||||
|
index number
|
||||||
|
MAX_KEY if no such index was found.
|
||||||
|
*/
|
||||||
|
|
||||||
|
uint get_index_for_order(TABLE *table, ORDER *order, ha_rows limit)
|
||||||
|
{
|
||||||
|
uint idx;
|
||||||
|
uint match_key= MAX_KEY, match_key_len= MAX_KEY_LENGTH + 1;
|
||||||
|
ORDER *ord;
|
||||||
|
|
||||||
|
for (ord= order; ord; ord= ord->next)
|
||||||
|
if (!ord->asc)
|
||||||
|
return MAX_KEY;
|
||||||
|
|
||||||
|
for (idx= 0; idx < table->keys; idx++)
|
||||||
|
{
|
||||||
|
if (!(table->keys_in_use_for_query.is_set(idx)))
|
||||||
|
continue;
|
||||||
|
KEY_PART_INFO *keyinfo= table->key_info[idx].key_part;
|
||||||
|
uint partno= 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
The below check is sufficient considering we now have either BTREE
|
||||||
|
indexes (records are returned in order for any index prefix) or HASH
|
||||||
|
indexes (records are not returned in order for any index prefix).
|
||||||
|
*/
|
||||||
|
if (!(table->file->index_flags(idx, 0, 1) & HA_READ_ORDER))
|
||||||
|
continue;
|
||||||
|
for (ord= order; ord; ord= ord->next, partno++)
|
||||||
|
{
|
||||||
|
Item *item= order->item[0];
|
||||||
|
if (!(item->type() == Item::FIELD_ITEM &&
|
||||||
|
((Item_field*)item)->field->eq(keyinfo[partno].field)))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ord && table->key_info[idx].key_length < match_key_len)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Ok, the ordering is compatible and this key is shorter then
|
||||||
|
previous match (we want shorter keys as we'll have to read fewer
|
||||||
|
index pages for the same number of records)
|
||||||
|
*/
|
||||||
|
match_key= idx;
|
||||||
|
match_key_len= table->key_info[idx].key_length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (match_key != MAX_KEY)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Found an index that allows records to be retrieved in the requested
|
||||||
|
order. Now we'll check if using the index is cheaper then doing a table
|
||||||
|
scan.
|
||||||
|
*/
|
||||||
|
double full_scan_time= table->file->scan_time();
|
||||||
|
double index_scan_time= table->file->read_time(match_key, 1, limit);
|
||||||
|
if (index_scan_time > full_scan_time)
|
||||||
|
match_key= MAX_KEY;
|
||||||
|
}
|
||||||
|
return match_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Table rows retrieval plan. Range optimizer creates QUICK_SELECT_I-derived
|
Table rows retrieval plan. Range optimizer creates QUICK_SELECT_I-derived
|
||||||
objects from table read plans.
|
objects from table read plans.
|
||||||
|
@ -716,4 +716,6 @@ public:
|
|||||||
QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table,
|
QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table,
|
||||||
struct st_table_ref *ref,
|
struct st_table_ref *ref,
|
||||||
ha_rows records);
|
ha_rows records);
|
||||||
|
uint get_index_for_order(TABLE *table, ORDER *order, ha_rows limit);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
108
sql/records.cc
108
sql/records.cc
@ -29,7 +29,59 @@ static int rr_from_cache(READ_RECORD *info);
|
|||||||
static int init_rr_cache(THD *thd, READ_RECORD *info);
|
static int init_rr_cache(THD *thd, READ_RECORD *info);
|
||||||
static int rr_cmp(uchar *a,uchar *b);
|
static int rr_cmp(uchar *a,uchar *b);
|
||||||
|
|
||||||
/* init struct for read with info->read_record */
|
static int rr_index(READ_RECORD *info);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Initialize READ_RECORD structure to perform full index scan
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
init_read_record_idx()
|
||||||
|
info READ_RECORD structure to initialize.
|
||||||
|
thd Thread handle
|
||||||
|
table Table to be accessed
|
||||||
|
print_error If true, call table->file->print_error() if an error
|
||||||
|
occurs (except for end-of-records error)
|
||||||
|
idx index to scan
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
Initialize READ_RECORD structure to perform full index scan (in forward
|
||||||
|
direction) using read_record.read_record() interface.
|
||||||
|
|
||||||
|
This function has been added at late stage and is used only by
|
||||||
|
UPDATE/DELETE. Other statements perform index scans using
|
||||||
|
join_read_first/next functions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table,
|
||||||
|
bool print_error, uint idx)
|
||||||
|
{
|
||||||
|
bzero((char*) info,sizeof(*info));
|
||||||
|
info->thd=thd;
|
||||||
|
info->table=table;
|
||||||
|
info->file= table->file;
|
||||||
|
info->forms= &info->table; /* Only one table */
|
||||||
|
|
||||||
|
info->record= table->record[0];
|
||||||
|
info->ref_length= table->file->ref_length;
|
||||||
|
|
||||||
|
info->select=NULL;
|
||||||
|
info->print_error=print_error;
|
||||||
|
info->ignore_not_found_rows= 0;
|
||||||
|
table->status=0; /* And it's always found */
|
||||||
|
|
||||||
|
if (!table->file->inited)
|
||||||
|
{
|
||||||
|
table->file->ha_index_init(idx);
|
||||||
|
table->file->extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY);
|
||||||
|
}
|
||||||
|
info->read_record= rr_index;
|
||||||
|
info->first= TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* init struct for read with info->read_record */
|
||||||
|
|
||||||
void init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
|
void init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
|
||||||
SQL_SELECT *select,
|
SQL_SELECT *select,
|
||||||
@ -187,6 +239,60 @@ static int rr_quick(READ_RECORD *info)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
A READ_RECORD::read_record implementation that reads index sequentially
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
rr_index()
|
||||||
|
info Scan info
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
Read the next index record (in forward direction) and translate return
|
||||||
|
value.
|
||||||
|
|
||||||
|
RETURN
|
||||||
|
0 Ok
|
||||||
|
-1 End of records
|
||||||
|
1 Error
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int rr_index(READ_RECORD *info)
|
||||||
|
{
|
||||||
|
int tmp;
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
if (info->first)
|
||||||
|
{
|
||||||
|
info->first= FALSE;
|
||||||
|
tmp= info->file->index_first(info->record);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
tmp= info->file->index_next(info->record);
|
||||||
|
|
||||||
|
if (!tmp)
|
||||||
|
break;
|
||||||
|
if (info->thd->killed)
|
||||||
|
{
|
||||||
|
my_error(ER_SERVER_SHUTDOWN,MYF(0));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (tmp != HA_ERR_RECORD_DELETED)
|
||||||
|
{
|
||||||
|
if (tmp == HA_ERR_END_OF_FILE)
|
||||||
|
tmp= -1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (info->print_error)
|
||||||
|
info->table->file->print_error(tmp,MYF(0));
|
||||||
|
if (tmp < 0) // Fix negative BDB errno
|
||||||
|
tmp=1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
static int rr_sequential(READ_RECORD *info)
|
static int rr_sequential(READ_RECORD *info)
|
||||||
{
|
{
|
||||||
int tmp;
|
int tmp;
|
||||||
|
@ -67,7 +67,6 @@ static int init_failsafe_rpl_thread(THD* thd)
|
|||||||
*/
|
*/
|
||||||
thd->system_thread = thd->bootstrap = 1;
|
thd->system_thread = thd->bootstrap = 1;
|
||||||
thd->security_ctx->skip_grants();
|
thd->security_ctx->skip_grants();
|
||||||
thd->client_capabilities = 0;
|
|
||||||
my_net_init(&thd->net, 0);
|
my_net_init(&thd->net, 0);
|
||||||
thd->net.read_timeout = slave_net_timeout;
|
thd->net.read_timeout = slave_net_timeout;
|
||||||
thd->max_client_packet_length=thd->net.max_packet;
|
thd->max_client_packet_length=thd->net.max_packet;
|
||||||
|
@ -2869,7 +2869,6 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type)
|
|||||||
thd->system_thread = (thd_type == SLAVE_THD_SQL) ?
|
thd->system_thread = (thd_type == SLAVE_THD_SQL) ?
|
||||||
SYSTEM_THREAD_SLAVE_SQL : SYSTEM_THREAD_SLAVE_IO;
|
SYSTEM_THREAD_SLAVE_SQL : SYSTEM_THREAD_SLAVE_IO;
|
||||||
thd->security_ctx->skip_grants();
|
thd->security_ctx->skip_grants();
|
||||||
thd->client_capabilities = 0;
|
|
||||||
my_net_init(&thd->net, 0);
|
my_net_init(&thd->net, 0);
|
||||||
thd->net.read_timeout = slave_net_timeout;
|
thd->net.read_timeout = slave_net_timeout;
|
||||||
thd->slave_thread = 1;
|
thd->slave_thread = 1;
|
||||||
|
@ -218,6 +218,7 @@ THD::THD()
|
|||||||
#ifndef EMBEDDED_LIBRARY
|
#ifndef EMBEDDED_LIBRARY
|
||||||
net.vio=0;
|
net.vio=0;
|
||||||
#endif
|
#endif
|
||||||
|
client_capabilities= 0; // minimalistic client
|
||||||
net.last_error[0]=0; // If error on boot
|
net.last_error[0]=0; // If error on boot
|
||||||
net.query_cache_query=0; // If error on boot
|
net.query_cache_query=0; // If error on boot
|
||||||
ull=0;
|
ull=0;
|
||||||
|
@ -37,6 +37,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
|
|||||||
bool using_limit=limit != HA_POS_ERROR;
|
bool using_limit=limit != HA_POS_ERROR;
|
||||||
bool transactional_table, safe_update, const_cond;
|
bool transactional_table, safe_update, const_cond;
|
||||||
ha_rows deleted;
|
ha_rows deleted;
|
||||||
|
uint usable_index= MAX_KEY;
|
||||||
SELECT_LEX *select_lex= &thd->lex->select_lex;
|
SELECT_LEX *select_lex= &thd->lex->select_lex;
|
||||||
DBUG_ENTER("mysql_delete");
|
DBUG_ENTER("mysql_delete");
|
||||||
|
|
||||||
@ -140,27 +141,42 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
|
|||||||
tables.table = table;
|
tables.table = table;
|
||||||
tables.alias = table_list->alias;
|
tables.alias = table_list->alias;
|
||||||
|
|
||||||
table->sort.io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE),
|
|
||||||
MYF(MY_FAE | MY_ZEROFILL));
|
|
||||||
if (select_lex->setup_ref_array(thd, order->elements) ||
|
if (select_lex->setup_ref_array(thd, order->elements) ||
|
||||||
setup_order(thd, select_lex->ref_pointer_array, &tables,
|
setup_order(thd, select_lex->ref_pointer_array, &tables,
|
||||||
fields, all_fields, (ORDER*) order->first) ||
|
fields, all_fields, (ORDER*) order->first))
|
||||||
!(sortorder=make_unireg_sortorder((ORDER*) order->first, &length)) ||
|
{
|
||||||
|
delete select;
|
||||||
|
free_underlaid_joins(thd, &thd->lex->select_lex);
|
||||||
|
DBUG_RETURN(-1); // This will force out message
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!select && limit != HA_POS_ERROR)
|
||||||
|
usable_index= get_index_for_order(table, (ORDER*)(order->first), limit);
|
||||||
|
|
||||||
|
if (usable_index == MAX_KEY)
|
||||||
|
{
|
||||||
|
table->sort.io_cache= (IO_CACHE *) my_malloc(sizeof(IO_CACHE),
|
||||||
|
MYF(MY_FAE | MY_ZEROFILL));
|
||||||
|
|
||||||
|
if ( !(sortorder=make_unireg_sortorder((ORDER*) order->first, &length)) ||
|
||||||
(table->sort.found_records = filesort(thd, table, sortorder, length,
|
(table->sort.found_records = filesort(thd, table, sortorder, length,
|
||||||
select, HA_POS_ERROR,
|
select, HA_POS_ERROR,
|
||||||
&examined_rows))
|
&examined_rows))
|
||||||
== HA_POS_ERROR)
|
== HA_POS_ERROR)
|
||||||
{
|
{
|
||||||
|
delete select;
|
||||||
|
free_underlaid_joins(thd, &thd->lex->select_lex);
|
||||||
|
DBUG_RETURN(-1); // This will force out message
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
Filesort has already found and selected the rows we want to delete,
|
||||||
|
so we don't need the where clause
|
||||||
|
*/
|
||||||
delete select;
|
delete select;
|
||||||
free_underlaid_joins(thd, select_lex);
|
free_underlaid_joins(thd, select_lex);
|
||||||
|
select= 0;
|
||||||
DBUG_RETURN(TRUE);
|
DBUG_RETURN(TRUE);
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
Filesort has already found and selected the rows we want to delete,
|
|
||||||
so we don't need the where clause
|
|
||||||
*/
|
|
||||||
delete select;
|
|
||||||
select= 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If quick select is used, initialize it before retrieving rows. */
|
/* If quick select is used, initialize it before retrieving rows. */
|
||||||
@ -170,7 +186,11 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
|
|||||||
free_underlaid_joins(thd, select_lex);
|
free_underlaid_joins(thd, select_lex);
|
||||||
DBUG_RETURN(TRUE);
|
DBUG_RETURN(TRUE);
|
||||||
}
|
}
|
||||||
init_read_record(&info,thd,table,select,1,1);
|
if (usable_index==MAX_KEY)
|
||||||
|
init_read_record(&info,thd,table,select,1,1);
|
||||||
|
else
|
||||||
|
init_read_record_idx(&info, thd, table, 1, usable_index);
|
||||||
|
|
||||||
deleted=0L;
|
deleted=0L;
|
||||||
init_ftfuncs(thd, select_lex, 1);
|
init_ftfuncs(thd, select_lex, 1);
|
||||||
thd->proc_info="updating";
|
thd->proc_info="updating";
|
||||||
|
@ -122,7 +122,8 @@ int mysql_update(THD *thd,
|
|||||||
bool used_key_is_modified, transactional_table;
|
bool used_key_is_modified, transactional_table;
|
||||||
int res;
|
int res;
|
||||||
int error=0;
|
int error=0;
|
||||||
uint used_index;
|
uint used_index= MAX_KEY;
|
||||||
|
bool need_sort= TRUE;
|
||||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||||
uint want_privilege;
|
uint want_privilege;
|
||||||
#endif
|
#endif
|
||||||
@ -241,6 +242,11 @@ int mysql_update(THD *thd,
|
|||||||
send_ok(thd); // No matching records
|
send_ok(thd); // No matching records
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
if (!select && limit != HA_POS_ERROR)
|
||||||
|
{
|
||||||
|
if (MAX_KEY != (used_index= get_index_for_order(table, order, limit)))
|
||||||
|
need_sort= FALSE;
|
||||||
|
}
|
||||||
/* If running in safe sql mode, don't allow updates without keys */
|
/* If running in safe sql mode, don't allow updates without keys */
|
||||||
if (table->quick_keys.is_clear_all())
|
if (table->quick_keys.is_clear_all())
|
||||||
{
|
{
|
||||||
@ -261,6 +267,10 @@ int mysql_update(THD *thd,
|
|||||||
used_key_is_modified= (!select->quick->unique_key_range() &&
|
used_key_is_modified= (!select->quick->unique_key_range() &&
|
||||||
select->quick->check_if_keys_used(&fields));
|
select->quick->check_if_keys_used(&fields));
|
||||||
}
|
}
|
||||||
|
else if (used_index != MAX_KEY)
|
||||||
|
{
|
||||||
|
used_key_is_modified= check_if_key_used(table, used_index, fields);
|
||||||
|
}
|
||||||
else if ((used_index=table->file->key_used_on_scan) < MAX_KEY)
|
else if ((used_index=table->file->key_used_on_scan) < MAX_KEY)
|
||||||
used_key_is_modified=check_if_key_used(table, used_index, fields);
|
used_key_is_modified=check_if_key_used(table, used_index, fields);
|
||||||
else
|
else
|
||||||
@ -276,10 +286,11 @@ int mysql_update(THD *thd,
|
|||||||
if (used_index < MAX_KEY && old_used_keys.is_set(used_index))
|
if (used_index < MAX_KEY && old_used_keys.is_set(used_index))
|
||||||
{
|
{
|
||||||
table->key_read=1;
|
table->key_read=1;
|
||||||
table->file->extra(HA_EXTRA_KEYREAD);
|
table->file->extra(HA_EXTRA_KEYREAD); //todo: psergey: check
|
||||||
}
|
}
|
||||||
|
|
||||||
if (order)
|
/* note: can actually avoid sorting below.. */
|
||||||
|
if (order && need_sort)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Doing an ORDER BY; Let filesort find and sort the rows we are going
|
Doing an ORDER BY; Let filesort find and sort the rows we are going
|
||||||
@ -323,7 +334,10 @@ int mysql_update(THD *thd,
|
|||||||
/* If quick select is used, initialize it before retrieving rows. */
|
/* If quick select is used, initialize it before retrieving rows. */
|
||||||
if (select && select->quick && select->quick->reset())
|
if (select && select->quick && select->quick->reset())
|
||||||
goto err;
|
goto err;
|
||||||
init_read_record(&info,thd,table,select,0,1);
|
if (used_index == MAX_KEY)
|
||||||
|
init_read_record(&info,thd,table,select,0,1);
|
||||||
|
else
|
||||||
|
init_read_record_idx(&info, thd, table, 1, used_index);
|
||||||
|
|
||||||
thd->proc_info="Searching rows for update";
|
thd->proc_info="Searching rows for update";
|
||||||
uint tmp_limit= limit;
|
uint tmp_limit= limit;
|
||||||
@ -352,6 +366,10 @@ int mysql_update(THD *thd,
|
|||||||
error= 1; // Aborted
|
error= 1; // Aborted
|
||||||
limit= tmp_limit;
|
limit= tmp_limit;
|
||||||
end_read_record(&info);
|
end_read_record(&info);
|
||||||
|
|
||||||
|
/* if we got here we must not use index in the main update loop below */
|
||||||
|
used_index= MAX_KEY;
|
||||||
|
|
||||||
/* Change select to use tempfile */
|
/* Change select to use tempfile */
|
||||||
if (select)
|
if (select)
|
||||||
{
|
{
|
||||||
|
@ -135,6 +135,7 @@ typedef struct st_read_record { /* Parameter to read_record */
|
|||||||
byte *cache,*cache_pos,*cache_end,*read_positions;
|
byte *cache,*cache_pos,*cache_end,*read_positions;
|
||||||
IO_CACHE *io_cache;
|
IO_CACHE *io_cache;
|
||||||
bool print_error, ignore_not_found_rows;
|
bool print_error, ignore_not_found_rows;
|
||||||
|
bool first; /* used only with rr_index_read */
|
||||||
} READ_RECORD;
|
} READ_RECORD;
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user