Added more tests for new UPDATE ... ORDER BY ... LIMIT optimization
heap/_check.c: Change arguments to ha_key_cmp heap/hp_create.c: Change arguments to ha_key_cmp include/my_base.h: Remove SEARCH_RETURN_B_POS and instead always send an array to ha_key_cmp() as last argument myisam/mi_check.c: Change arguments to ha_key_cmp myisam/mi_rnext_same.c: Change arguments to ha_key_cmp myisam/mi_search.c: Change arguments to ha_key_cmp myisam/mi_write.c: Change arguments to ha_key_cmp myisammrg/myrg_queue.c: Change arguments to ha_key_cmp mysys/my_handler.c: Remove SEARCH_RETURN_B_POS and instead always send an array to ha_key_cmp() as last argument (This removes an if in a loop at the expensive of an int on the stack) sql/records.cc: Simplify new rr_index() code Create common error handling function for rr_() functions. Remove loop from rr_index() as handler::index_next() can never return HA_ERR_RECORD_DELETED sql/sql_load.cc: Simplify sql/sql_update.cc: Simplify code Fixed bug when one is updating an index column that could be used with ORDER BY sql/structs.h: Removed not needed structure element
This commit is contained in:
parent
3c02a0534d
commit
8d6634c9e0
@ -167,7 +167,7 @@ static int check_one_rb_key(HP_INFO *info, uint keynr, ulong records,
|
|||||||
ulong found= 0;
|
ulong found= 0;
|
||||||
byte *key, *recpos;
|
byte *key, *recpos;
|
||||||
uint key_length;
|
uint key_length;
|
||||||
uint not_used;
|
uint not_used[2];
|
||||||
|
|
||||||
if ((key= tree_search_edge(&keydef->rb_tree, info->parents,
|
if ((key= tree_search_edge(&keydef->rb_tree, info->parents,
|
||||||
&info->last_pos, offsetof(TREE_ELEMENT, left))))
|
&info->last_pos, offsetof(TREE_ELEMENT, left))))
|
||||||
@ -177,7 +177,7 @@ static int check_one_rb_key(HP_INFO *info, uint keynr, ulong records,
|
|||||||
memcpy(&recpos, key + (*keydef->get_key_length)(keydef,key), sizeof(byte*));
|
memcpy(&recpos, key + (*keydef->get_key_length)(keydef,key), sizeof(byte*));
|
||||||
key_length= hp_rb_make_key(keydef, info->recbuf, recpos, 0);
|
key_length= hp_rb_make_key(keydef, info->recbuf, recpos, 0);
|
||||||
if (ha_key_cmp(keydef->seg, (uchar*) info->recbuf, (uchar*) key,
|
if (ha_key_cmp(keydef->seg, (uchar*) info->recbuf, (uchar*) key,
|
||||||
key_length, SEARCH_FIND | SEARCH_SAME, ¬_used))
|
key_length, SEARCH_FIND | SEARCH_SAME, not_used))
|
||||||
{
|
{
|
||||||
error= 1;
|
error= 1;
|
||||||
DBUG_PRINT("error",("Record in wrong link: key: %d Record: %lx\n",
|
DBUG_PRINT("error",("Record in wrong link: key: %d Record: %lx\n",
|
||||||
|
@ -170,9 +170,9 @@ int heap_create(const char *name, uint keys, HP_KEYDEF *keydef,
|
|||||||
|
|
||||||
static int keys_compare(heap_rb_param *param, uchar *key1, uchar *key2)
|
static int keys_compare(heap_rb_param *param, uchar *key1, uchar *key2)
|
||||||
{
|
{
|
||||||
uint not_used;
|
uint not_used[2];
|
||||||
return ha_key_cmp(param->keyseg, key1, key2, param->key_length,
|
return ha_key_cmp(param->keyseg, key1, key2, param->key_length,
|
||||||
param->search_flag, ¬_used);
|
param->search_flag, not_used);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_block(HP_BLOCK *block, uint reclength, ulong min_records,
|
static void init_block(HP_BLOCK *block, uint reclength, ulong min_records,
|
||||||
|
@ -319,8 +319,6 @@ enum ha_base_keytype {
|
|||||||
#define SEARCH_NULL_ARE_EQUAL 32768 /* NULL in keys are equal */
|
#define SEARCH_NULL_ARE_EQUAL 32768 /* NULL in keys are equal */
|
||||||
#define SEARCH_NULL_ARE_NOT_EQUAL 65536 /* NULL in keys are not equal */
|
#define SEARCH_NULL_ARE_NOT_EQUAL 65536 /* NULL in keys are not equal */
|
||||||
|
|
||||||
#define SEARCH_RETURN_B_POS (65536*2) /* see ha_key_cmp for description */
|
|
||||||
|
|
||||||
/* bits in opt_flag */
|
/* bits in opt_flag */
|
||||||
#define QUICK_USED 1
|
#define QUICK_USED 1
|
||||||
#define READ_CACHE_USED 2
|
#define READ_CACHE_USED 2
|
||||||
|
@ -619,6 +619,7 @@ int mi_collect_stats_nonulls_next(HA_KEYSEG *keyseg, ulonglong *notnull,
|
|||||||
{
|
{
|
||||||
uint diffs[2];
|
uint diffs[2];
|
||||||
uint first_null_seg, kp;
|
uint first_null_seg, kp;
|
||||||
|
HA_KEYSEG *seg;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Find the first keypart where values are different or either of them is
|
Find the first keypart where values are different or either of them is
|
||||||
@ -629,9 +630,8 @@ int mi_collect_stats_nonulls_next(HA_KEYSEG *keyseg, ulonglong *notnull,
|
|||||||
value in prev_key.
|
value in prev_key.
|
||||||
*/
|
*/
|
||||||
ha_key_cmp(keyseg, prev_key, last_key, USE_WHOLE_KEY,
|
ha_key_cmp(keyseg, prev_key, last_key, USE_WHOLE_KEY,
|
||||||
SEARCH_FIND | SEARCH_NULL_ARE_NOT_EQUAL | SEARCH_RETURN_B_POS,
|
SEARCH_FIND | SEARCH_NULL_ARE_NOT_EQUAL, diffs);
|
||||||
diffs);
|
seg= keyseg + diffs[0] - 1;
|
||||||
HA_KEYSEG *seg= keyseg + diffs[0] - 1;
|
|
||||||
|
|
||||||
/* Find first NULL in last_key */
|
/* Find first NULL in last_key */
|
||||||
first_null_seg= ha_find_null(seg, last_key + diffs[1]) - keyseg;
|
first_null_seg= ha_find_null(seg, last_key + diffs[1]) - keyseg;
|
||||||
@ -658,7 +658,7 @@ static int chk_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo,
|
|||||||
uchar key[MI_MAX_POSSIBLE_KEY_BUFF],*temp_buff,*keypos,*old_keypos,*endpos;
|
uchar key[MI_MAX_POSSIBLE_KEY_BUFF],*temp_buff,*keypos,*old_keypos,*endpos;
|
||||||
my_off_t next_page,record;
|
my_off_t next_page,record;
|
||||||
char llbuff[22];
|
char llbuff[22];
|
||||||
uint diff_pos;
|
uint diff_pos[2];
|
||||||
DBUG_ENTER("chk_index");
|
DBUG_ENTER("chk_index");
|
||||||
DBUG_DUMP("buff",(byte*) buff,mi_getint(buff));
|
DBUG_DUMP("buff",(byte*) buff,mi_getint(buff));
|
||||||
|
|
||||||
@ -716,7 +716,7 @@ static int chk_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo,
|
|||||||
}
|
}
|
||||||
if ((*keys)++ &&
|
if ((*keys)++ &&
|
||||||
(flag=ha_key_cmp(keyinfo->seg,info->lastkey,key,key_length,
|
(flag=ha_key_cmp(keyinfo->seg,info->lastkey,key,key_length,
|
||||||
comp_flag, &diff_pos)) >=0)
|
comp_flag, diff_pos)) >=0)
|
||||||
{
|
{
|
||||||
DBUG_DUMP("old",(byte*) info->lastkey, info->lastkey_length);
|
DBUG_DUMP("old",(byte*) info->lastkey, info->lastkey_length);
|
||||||
DBUG_DUMP("new",(byte*) key, key_length);
|
DBUG_DUMP("new",(byte*) key, key_length);
|
||||||
@ -735,14 +735,14 @@ static int chk_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo,
|
|||||||
if (param->stats_method == MI_STATS_METHOD_NULLS_NOT_EQUAL)
|
if (param->stats_method == MI_STATS_METHOD_NULLS_NOT_EQUAL)
|
||||||
ha_key_cmp(keyinfo->seg,info->lastkey,key,USE_WHOLE_KEY,
|
ha_key_cmp(keyinfo->seg,info->lastkey,key,USE_WHOLE_KEY,
|
||||||
SEARCH_FIND | SEARCH_NULL_ARE_NOT_EQUAL,
|
SEARCH_FIND | SEARCH_NULL_ARE_NOT_EQUAL,
|
||||||
&diff_pos);
|
diff_pos);
|
||||||
else if (param->stats_method == MI_STATS_METHOD_IGNORE_NULLS)
|
else if (param->stats_method == MI_STATS_METHOD_IGNORE_NULLS)
|
||||||
{
|
{
|
||||||
diff_pos= mi_collect_stats_nonulls_next(keyinfo->seg,
|
diff_pos[0]= mi_collect_stats_nonulls_next(keyinfo->seg,
|
||||||
param->notnull_count,
|
param->notnull_count,
|
||||||
info->lastkey, key);
|
info->lastkey, key);
|
||||||
}
|
}
|
||||||
param->unique_count[diff_pos-1]++;
|
param->unique_count[diff_pos[0]-1]++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -3340,15 +3340,15 @@ int sort_write_record(MI_SORT_PARAM *sort_param)
|
|||||||
static int sort_key_cmp(MI_SORT_PARAM *sort_param, const void *a,
|
static int sort_key_cmp(MI_SORT_PARAM *sort_param, const void *a,
|
||||||
const void *b)
|
const void *b)
|
||||||
{
|
{
|
||||||
uint not_used;
|
uint not_used[2];
|
||||||
return (ha_key_cmp(sort_param->seg, *((uchar**) a), *((uchar**) b),
|
return (ha_key_cmp(sort_param->seg, *((uchar**) a), *((uchar**) b),
|
||||||
USE_WHOLE_KEY, SEARCH_SAME,¬_used));
|
USE_WHOLE_KEY, SEARCH_SAME, not_used));
|
||||||
} /* sort_key_cmp */
|
} /* sort_key_cmp */
|
||||||
|
|
||||||
|
|
||||||
static int sort_key_write(MI_SORT_PARAM *sort_param, const void *a)
|
static int sort_key_write(MI_SORT_PARAM *sort_param, const void *a)
|
||||||
{
|
{
|
||||||
uint diff_pos;
|
uint diff_pos[2];
|
||||||
char llbuff[22],llbuff2[22];
|
char llbuff[22],llbuff2[22];
|
||||||
SORT_INFO *sort_info=sort_param->sort_info;
|
SORT_INFO *sort_info=sort_param->sort_info;
|
||||||
MI_CHECK *param= sort_info->param;
|
MI_CHECK *param= sort_info->param;
|
||||||
@ -3358,19 +3358,19 @@ static int sort_key_write(MI_SORT_PARAM *sort_param, const void *a)
|
|||||||
{
|
{
|
||||||
cmp=ha_key_cmp(sort_param->seg,sort_info->key_block->lastkey,
|
cmp=ha_key_cmp(sort_param->seg,sort_info->key_block->lastkey,
|
||||||
(uchar*) a, USE_WHOLE_KEY,SEARCH_FIND | SEARCH_UPDATE,
|
(uchar*) a, USE_WHOLE_KEY,SEARCH_FIND | SEARCH_UPDATE,
|
||||||
&diff_pos);
|
diff_pos);
|
||||||
if (param->stats_method == MI_STATS_METHOD_NULLS_NOT_EQUAL)
|
if (param->stats_method == MI_STATS_METHOD_NULLS_NOT_EQUAL)
|
||||||
ha_key_cmp(sort_param->seg,sort_info->key_block->lastkey,
|
ha_key_cmp(sort_param->seg,sort_info->key_block->lastkey,
|
||||||
(uchar*) a, USE_WHOLE_KEY,
|
(uchar*) a, USE_WHOLE_KEY,
|
||||||
SEARCH_FIND | SEARCH_NULL_ARE_NOT_EQUAL, &diff_pos);
|
SEARCH_FIND | SEARCH_NULL_ARE_NOT_EQUAL, diff_pos);
|
||||||
else if (param->stats_method == MI_STATS_METHOD_IGNORE_NULLS)
|
else if (param->stats_method == MI_STATS_METHOD_IGNORE_NULLS)
|
||||||
{
|
{
|
||||||
diff_pos= mi_collect_stats_nonulls_next(sort_param->seg,
|
diff_pos[0]= mi_collect_stats_nonulls_next(sort_param->seg,
|
||||||
sort_param->notnull,
|
sort_param->notnull,
|
||||||
sort_info->key_block->lastkey,
|
sort_info->key_block->lastkey,
|
||||||
(uchar*)a);
|
(uchar*)a);
|
||||||
}
|
}
|
||||||
sort_param->unique[diff_pos-1]++;
|
sort_param->unique[diff_pos[0]-1]++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
int mi_rnext_same(MI_INFO *info, byte *buf)
|
int mi_rnext_same(MI_INFO *info, byte *buf)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
uint inx,not_used;
|
uint inx,not_used[2];
|
||||||
MI_KEYDEF *keyinfo;
|
MI_KEYDEF *keyinfo;
|
||||||
DBUG_ENTER("mi_rnext_same");
|
DBUG_ENTER("mi_rnext_same");
|
||||||
|
|
||||||
@ -69,7 +69,7 @@ int mi_rnext_same(MI_INFO *info, byte *buf)
|
|||||||
info->s->state.key_root[inx])))
|
info->s->state.key_root[inx])))
|
||||||
break;
|
break;
|
||||||
if (ha_key_cmp(keyinfo->seg, info->lastkey, info->lastkey2,
|
if (ha_key_cmp(keyinfo->seg, info->lastkey, info->lastkey2,
|
||||||
info->last_rkey_length, SEARCH_FIND, ¬_used))
|
info->last_rkey_length, SEARCH_FIND, not_used))
|
||||||
{
|
{
|
||||||
error=1;
|
error=1;
|
||||||
my_errno=HA_ERR_END_OF_FILE;
|
my_errno=HA_ERR_END_OF_FILE;
|
||||||
|
@ -128,13 +128,13 @@ int _mi_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
|
|||||||
|
|
||||||
if ((nextflag & (SEARCH_SMALLER | SEARCH_LAST)) && flag != 0)
|
if ((nextflag & (SEARCH_SMALLER | SEARCH_LAST)) && flag != 0)
|
||||||
{
|
{
|
||||||
uint not_used;
|
uint not_used[2];
|
||||||
if (_mi_get_prev_key(info,keyinfo, buff, info->lastkey, keypos,
|
if (_mi_get_prev_key(info,keyinfo, buff, info->lastkey, keypos,
|
||||||
&info->lastkey_length))
|
&info->lastkey_length))
|
||||||
goto err;
|
goto err;
|
||||||
if (!(nextflag & SEARCH_SMALLER) &&
|
if (!(nextflag & SEARCH_SMALLER) &&
|
||||||
ha_key_cmp(keyinfo->seg, info->lastkey, key, key_len, SEARCH_FIND,
|
ha_key_cmp(keyinfo->seg, info->lastkey, key, key_len, SEARCH_FIND,
|
||||||
¬_used))
|
not_used))
|
||||||
{
|
{
|
||||||
my_errno=HA_ERR_KEY_NOT_FOUND; /* Didn't find key */
|
my_errno=HA_ERR_KEY_NOT_FOUND; /* Didn't find key */
|
||||||
goto err;
|
goto err;
|
||||||
@ -178,7 +178,7 @@ int _mi_bin_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
|
|||||||
{
|
{
|
||||||
reg4 int start,mid,end,save_end;
|
reg4 int start,mid,end,save_end;
|
||||||
int flag;
|
int flag;
|
||||||
uint totlength,nod_flag,not_used;
|
uint totlength,nod_flag,not_used[2];
|
||||||
DBUG_ENTER("_mi_bin_search");
|
DBUG_ENTER("_mi_bin_search");
|
||||||
|
|
||||||
LINT_INIT(flag);
|
LINT_INIT(flag);
|
||||||
@ -192,7 +192,7 @@ int _mi_bin_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
|
|||||||
{
|
{
|
||||||
mid= (start+end)/2;
|
mid= (start+end)/2;
|
||||||
if ((flag=ha_key_cmp(keyinfo->seg,page+(uint) mid*totlength,key,key_len,
|
if ((flag=ha_key_cmp(keyinfo->seg,page+(uint) mid*totlength,key,key_len,
|
||||||
comp_flag,¬_used))
|
comp_flag, not_used))
|
||||||
>= 0)
|
>= 0)
|
||||||
end=mid;
|
end=mid;
|
||||||
else
|
else
|
||||||
@ -200,7 +200,7 @@ int _mi_bin_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
|
|||||||
}
|
}
|
||||||
if (mid != start)
|
if (mid != start)
|
||||||
flag=ha_key_cmp(keyinfo->seg,page+(uint) start*totlength,key,key_len,
|
flag=ha_key_cmp(keyinfo->seg,page+(uint) start*totlength,key,key_len,
|
||||||
comp_flag,¬_used);
|
comp_flag, not_used);
|
||||||
if (flag < 0)
|
if (flag < 0)
|
||||||
start++; /* point at next, bigger key */
|
start++; /* point at next, bigger key */
|
||||||
*ret_pos=page+(uint) start*totlength;
|
*ret_pos=page+(uint) start*totlength;
|
||||||
@ -241,7 +241,7 @@ int _mi_seq_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
|
|||||||
uchar *buff, my_bool *last_key)
|
uchar *buff, my_bool *last_key)
|
||||||
{
|
{
|
||||||
int flag;
|
int flag;
|
||||||
uint nod_flag,length,not_used;
|
uint nod_flag,length,not_used[2];
|
||||||
uchar t_buff[MI_MAX_KEY_BUFF],*end;
|
uchar t_buff[MI_MAX_KEY_BUFF],*end;
|
||||||
DBUG_ENTER("_mi_seq_search");
|
DBUG_ENTER("_mi_seq_search");
|
||||||
|
|
||||||
@ -262,7 +262,7 @@ int _mi_seq_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
|
|||||||
DBUG_RETURN(MI_FOUND_WRONG_KEY);
|
DBUG_RETURN(MI_FOUND_WRONG_KEY);
|
||||||
}
|
}
|
||||||
if ((flag=ha_key_cmp(keyinfo->seg,t_buff,key,key_len,comp_flag,
|
if ((flag=ha_key_cmp(keyinfo->seg,t_buff,key,key_len,comp_flag,
|
||||||
¬_used)) >= 0)
|
not_used)) >= 0)
|
||||||
break;
|
break;
|
||||||
#ifdef EXTRA_DEBUG
|
#ifdef EXTRA_DEBUG
|
||||||
DBUG_PRINT("loop",("page: %lx key: '%s' flag: %d", (long) page, t_buff,
|
DBUG_PRINT("loop",("page: %lx key: '%s' flag: %d", (long) page, t_buff,
|
||||||
@ -503,9 +503,9 @@ int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
|
|||||||
cmp_rest:
|
cmp_rest:
|
||||||
if (key_len_left>0)
|
if (key_len_left>0)
|
||||||
{
|
{
|
||||||
uint not_used;
|
uint not_used[2];
|
||||||
if ((flag = ha_key_cmp(keyinfo->seg+1,vseg,
|
if ((flag = ha_key_cmp(keyinfo->seg+1,vseg,
|
||||||
k,key_len_left,nextflag,¬_used)) >= 0)
|
k, key_len_left, nextflag, not_used)) >= 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -885,10 +885,10 @@ int _mi_ck_write_tree(register MI_INFO *info, uint keynr, uchar *key,
|
|||||||
|
|
||||||
static int keys_compare(bulk_insert_param *param, uchar *key1, uchar *key2)
|
static int keys_compare(bulk_insert_param *param, uchar *key1, uchar *key2)
|
||||||
{
|
{
|
||||||
uint not_used;
|
uint not_used[2];
|
||||||
return ha_key_cmp(param->info->s->keyinfo[param->keynr].seg,
|
return ha_key_cmp(param->info->s->keyinfo[param->keynr].seg,
|
||||||
key1, key2, USE_WHOLE_KEY, SEARCH_SAME,
|
key1, key2, USE_WHOLE_KEY, SEARCH_SAME,
|
||||||
¬_used);
|
not_used);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -20,9 +20,9 @@ static int queue_key_cmp(void *keyseg, byte *a, byte *b)
|
|||||||
{
|
{
|
||||||
MI_INFO *aa=((MYRG_TABLE *)a)->table;
|
MI_INFO *aa=((MYRG_TABLE *)a)->table;
|
||||||
MI_INFO *bb=((MYRG_TABLE *)b)->table;
|
MI_INFO *bb=((MYRG_TABLE *)b)->table;
|
||||||
uint not_used;
|
uint not_used[2];
|
||||||
int ret= ha_key_cmp((HA_KEYSEG *)keyseg, aa->lastkey, bb->lastkey,
|
int ret= ha_key_cmp((HA_KEYSEG *)keyseg, aa->lastkey, bb->lastkey,
|
||||||
USE_WHOLE_KEY, SEARCH_FIND, ¬_used);
|
USE_WHOLE_KEY, SEARCH_FIND, not_used);
|
||||||
return ret < 0 ? -1 : ret > 0 ? 1 : 0;
|
return ret < 0 ? -1 : ret > 0 ? 1 : 0;
|
||||||
} /* queue_key_cmp */
|
} /* queue_key_cmp */
|
||||||
|
|
||||||
|
@ -263,8 +263,8 @@ 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) );
|
create table t1 ( a int, b int default 0, index (a) );
|
||||||
insert into t1 values (0),(0),(0),(0),(0),(0),(0),(0);
|
insert into t1 (a) values (0),(0),(0),(0),(0),(0),(0),(0);
|
||||||
flush status;
|
flush status;
|
||||||
select a from t1 order by a limit 1;
|
select a from t1 order by a limit 1;
|
||||||
a
|
a
|
||||||
@ -278,15 +278,16 @@ Handler_read_prev 0
|
|||||||
Handler_read_rnd 0
|
Handler_read_rnd 0
|
||||||
Handler_read_rnd_next 0
|
Handler_read_rnd_next 0
|
||||||
flush status;
|
flush status;
|
||||||
update t1 set a=unix_timestamp() order by a limit 1;
|
update t1 set a=9999 order by a limit 1;
|
||||||
|
update t1 set b=9999 order by a limit 1;
|
||||||
show status like 'handler_read%';
|
show status like 'handler_read%';
|
||||||
Variable_name Value
|
Variable_name Value
|
||||||
Handler_read_first 1
|
Handler_read_first 1
|
||||||
Handler_read_key 0
|
Handler_read_key 0
|
||||||
Handler_read_next 0
|
Handler_read_next 0
|
||||||
Handler_read_prev 0
|
Handler_read_prev 0
|
||||||
Handler_read_rnd 1
|
Handler_read_rnd 2
|
||||||
Handler_read_rnd_next 0
|
Handler_read_rnd_next 9
|
||||||
flush status;
|
flush status;
|
||||||
delete from t1 order by a limit 1;
|
delete from t1 order by a limit 1;
|
||||||
show status like 'handler_read%';
|
show status like 'handler_read%';
|
||||||
@ -318,7 +319,21 @@ Handler_read_next 0
|
|||||||
Handler_read_prev 0
|
Handler_read_prev 0
|
||||||
Handler_read_rnd 1
|
Handler_read_rnd 1
|
||||||
Handler_read_rnd_next 9
|
Handler_read_rnd_next 9
|
||||||
select count(*) from t1;
|
select * from t1;
|
||||||
count(*)
|
a b
|
||||||
5
|
0 0
|
||||||
|
0 0
|
||||||
|
0 0
|
||||||
|
0 0
|
||||||
|
0 0
|
||||||
|
update t1 set a=a+10,b=1 order by a limit 3;
|
||||||
|
update t1 set a=a+11,b=2 order by a limit 3;
|
||||||
|
update t1 set a=a+12,b=3 order by a limit 3;
|
||||||
|
select * from t1 order by a;
|
||||||
|
a b
|
||||||
|
11 2
|
||||||
|
21 2
|
||||||
|
22 3
|
||||||
|
22 3
|
||||||
|
23 3
|
||||||
drop table t1;
|
drop table t1;
|
||||||
|
@ -228,15 +228,16 @@ 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
|
# BUG#12915: Optimize "DELETE|UPDATE ... ORDER BY ... LIMIT n" to use an index
|
||||||
create table t1 ( a int, index (a) );
|
create table t1 ( a int, b int default 0, index (a) );
|
||||||
insert into t1 values (0),(0),(0),(0),(0),(0),(0),(0);
|
insert into t1 (a) values (0),(0),(0),(0),(0),(0),(0),(0);
|
||||||
|
|
||||||
flush status;
|
flush status;
|
||||||
select a from t1 order by a limit 1;
|
select a from t1 order by a limit 1;
|
||||||
show status like 'handler_read%';
|
show status like 'handler_read%';
|
||||||
|
|
||||||
flush status;
|
flush status;
|
||||||
update t1 set a=unix_timestamp() order by a limit 1;
|
update t1 set a=9999 order by a limit 1;
|
||||||
|
update t1 set b=9999 order by a limit 1;
|
||||||
show status like 'handler_read%';
|
show status like 'handler_read%';
|
||||||
|
|
||||||
flush status;
|
flush status;
|
||||||
@ -253,7 +254,11 @@ flush status;
|
|||||||
delete from t1 order by a limit 1;
|
delete from t1 order by a limit 1;
|
||||||
show status like 'handler_read%';
|
show status like 'handler_read%';
|
||||||
|
|
||||||
select count(*) from t1;
|
select * from t1;
|
||||||
|
update t1 set a=a+10,b=1 order by a limit 3;
|
||||||
|
update t1 set a=a+11,b=2 order by a limit 3;
|
||||||
|
update t1 set a=a+12,b=3 order by a limit 3;
|
||||||
|
select * from t1 order by a;
|
||||||
|
|
||||||
drop table t1;
|
drop table t1;
|
||||||
# End of 4.1 tests
|
# End of 4.1 tests
|
||||||
|
@ -86,15 +86,9 @@ static int compare_bin(uchar *a, uint a_length, uchar *b, uint b_length,
|
|||||||
position and this should also be compared
|
position and this should also be compared
|
||||||
diff_pos OUT Number of first keypart where values differ, counting
|
diff_pos OUT Number of first keypart where values differ, counting
|
||||||
from one.
|
from one.
|
||||||
|
diff_pos[1] OUT (b + diff_pos[1]) points to first value in tuple b
|
||||||
DESCRIPTION
|
|
||||||
If SEARCH_RETURN_B_POS flag is set, diff_pos must point to array of 2
|
|
||||||
values, first value has the meaning as described in parameter
|
|
||||||
description above, the second value is:
|
|
||||||
|
|
||||||
diff_pos[1] OUT (b + diff_pos[1]) points to first value in tuple b
|
|
||||||
that is different from corresponding value in tuple a.
|
that is different from corresponding value in tuple a.
|
||||||
|
|
||||||
EXAMPLES
|
EXAMPLES
|
||||||
Example1: if the function is called for tuples
|
Example1: if the function is called for tuples
|
||||||
('aaa','bbb') and ('eee','fff'), then
|
('aaa','bbb') and ('eee','fff'), then
|
||||||
@ -137,9 +131,7 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
|
|||||||
uchar *end;
|
uchar *end;
|
||||||
uint piks=! (keyseg->flag & HA_NO_SORT);
|
uint piks=! (keyseg->flag & HA_NO_SORT);
|
||||||
(*diff_pos)++;
|
(*diff_pos)++;
|
||||||
|
diff_pos[1]= (uint)(b - orig_b);
|
||||||
if (nextflag & SEARCH_RETURN_B_POS)
|
|
||||||
diff_pos[1]= (uint)(b - orig_b);
|
|
||||||
|
|
||||||
/* Handle NULL part */
|
/* Handle NULL part */
|
||||||
if (keyseg->null_bit)
|
if (keyseg->null_bit)
|
||||||
|
182
sql/records.cc
182
sql/records.cc
@ -28,11 +28,10 @@ static int rr_from_pointers(READ_RECORD *info);
|
|||||||
static int rr_from_cache(READ_RECORD *info);
|
static int rr_from_cache(READ_RECORD *info);
|
||||||
static int init_rr_cache(READ_RECORD *info);
|
static int init_rr_cache(READ_RECORD *info);
|
||||||
static int rr_cmp(uchar *a,uchar *b);
|
static int rr_cmp(uchar *a,uchar *b);
|
||||||
|
static int rr_index_first(READ_RECORD *info);
|
||||||
static int rr_index(READ_RECORD *info);
|
static int rr_index(READ_RECORD *info);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Initialize READ_RECORD structure to perform full index scan
|
Initialize READ_RECORD structure to perform full index scan
|
||||||
|
|
||||||
@ -58,26 +57,19 @@ void init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table,
|
|||||||
bool print_error, uint idx)
|
bool print_error, uint idx)
|
||||||
{
|
{
|
||||||
bzero((char*) info,sizeof(*info));
|
bzero((char*) info,sizeof(*info));
|
||||||
info->thd=thd;
|
info->table= table;
|
||||||
info->table=table;
|
info->file= table->file;
|
||||||
info->file= table->file;
|
|
||||||
info->forms= &info->table; /* Only one table */
|
|
||||||
|
|
||||||
info->record= table->record[0];
|
info->record= table->record[0];
|
||||||
info->ref_length= table->file->ref_length;
|
info->print_error= print_error;
|
||||||
|
|
||||||
info->select=NULL;
|
|
||||||
info->print_error=print_error;
|
|
||||||
info->ignore_not_found_rows= 0;
|
|
||||||
table->status=0; /* And it's always found */
|
table->status=0; /* And it's always found */
|
||||||
|
|
||||||
if (!table->file->inited)
|
if (!table->file->inited)
|
||||||
{
|
{
|
||||||
table->file->ha_index_init(idx);
|
table->file->ha_index_init(idx);
|
||||||
table->file->extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY);
|
table->file->extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY);
|
||||||
}
|
}
|
||||||
info->read_record= rr_index;
|
/* read_record will be changed to rr_index in rr_index_first */
|
||||||
info->first= TRUE;
|
info->read_record= rr_index_first;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -204,6 +196,21 @@ void end_read_record(READ_RECORD *info)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int rr_handle_error(READ_RECORD *info, int error)
|
||||||
|
{
|
||||||
|
if (error == HA_ERR_END_OF_FILE)
|
||||||
|
error= -1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (info->print_error)
|
||||||
|
info->table->file->print_error(error, MYF(0));
|
||||||
|
if (error < 0) // Fix negative BDB errno
|
||||||
|
error= 1;
|
||||||
|
}
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Read a record from head-database */
|
/* Read a record from head-database */
|
||||||
|
|
||||||
static int rr_quick(READ_RECORD *info)
|
static int rr_quick(READ_RECORD *info)
|
||||||
@ -218,15 +225,7 @@ static int rr_quick(READ_RECORD *info)
|
|||||||
}
|
}
|
||||||
if (tmp != HA_ERR_RECORD_DELETED)
|
if (tmp != HA_ERR_RECORD_DELETED)
|
||||||
{
|
{
|
||||||
if (tmp == HA_ERR_END_OF_FILE)
|
tmp= rr_handle_error(info, tmp);
|
||||||
tmp= -1;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (info->print_error)
|
|
||||||
info->file->print_error(tmp,MYF(0));
|
|
||||||
if (tmp < 0) // Fix negative BDB errno
|
|
||||||
tmp=1;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -235,7 +234,31 @@ static int rr_quick(READ_RECORD *info)
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
A READ_RECORD::read_record implementation that reads index sequentially
|
Reads first row in an index scan
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
rr_index_first()
|
||||||
|
info Scan info
|
||||||
|
|
||||||
|
RETURN
|
||||||
|
0 Ok
|
||||||
|
-1 End of records
|
||||||
|
1 Error
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
static int rr_index_first(READ_RECORD *info)
|
||||||
|
{
|
||||||
|
int tmp= info->file->index_first(info->record);
|
||||||
|
info->read_record= rr_index;
|
||||||
|
if (tmp)
|
||||||
|
tmp= rr_handle_error(info, tmp);
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Reads index sequentially after first row
|
||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
rr_index()
|
rr_index()
|
||||||
@ -251,43 +274,16 @@ static int rr_quick(READ_RECORD *info)
|
|||||||
1 Error
|
1 Error
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
static int rr_index(READ_RECORD *info)
|
static int rr_index(READ_RECORD *info)
|
||||||
{
|
{
|
||||||
int tmp;
|
int tmp= info->file->index_next(info->record);
|
||||||
while (1)
|
if (tmp)
|
||||||
{
|
tmp= rr_handle_error(info, tmp);
|
||||||
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;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int rr_sequential(READ_RECORD *info)
|
static int rr_sequential(READ_RECORD *info)
|
||||||
{
|
{
|
||||||
int tmp;
|
int tmp;
|
||||||
@ -298,17 +294,13 @@ static int rr_sequential(READ_RECORD *info)
|
|||||||
my_error(ER_SERVER_SHUTDOWN,MYF(0));
|
my_error(ER_SERVER_SHUTDOWN,MYF(0));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
rnd_next can return RECORD_DELETED for MyISAM when one thread is
|
||||||
|
reading and another deleting without locks.
|
||||||
|
*/
|
||||||
if (tmp != HA_ERR_RECORD_DELETED)
|
if (tmp != HA_ERR_RECORD_DELETED)
|
||||||
{
|
{
|
||||||
if (tmp == HA_ERR_END_OF_FILE)
|
tmp= rr_handle_error(info, tmp);
|
||||||
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -319,23 +311,18 @@ static int rr_sequential(READ_RECORD *info)
|
|||||||
static int rr_from_tempfile(READ_RECORD *info)
|
static int rr_from_tempfile(READ_RECORD *info)
|
||||||
{
|
{
|
||||||
int tmp;
|
int tmp;
|
||||||
tryNext:
|
for (;;)
|
||||||
if (my_b_read(info->io_cache,info->ref_pos,info->ref_length))
|
|
||||||
return -1; /* End of file */
|
|
||||||
if ((tmp=info->file->rnd_pos(info->record,info->ref_pos)))
|
|
||||||
{
|
{
|
||||||
if (tmp == HA_ERR_END_OF_FILE)
|
if (my_b_read(info->io_cache,info->ref_pos,info->ref_length))
|
||||||
tmp= -1;
|
return -1; /* End of file */
|
||||||
else if (tmp == HA_ERR_RECORD_DELETED ||
|
if (!(tmp=info->file->rnd_pos(info->record,info->ref_pos)))
|
||||||
(tmp == HA_ERR_KEY_NOT_FOUND && info->ignore_not_found_rows))
|
break;
|
||||||
goto tryNext;
|
/* The following is extremely unlikely to happen */
|
||||||
else
|
if (tmp == HA_ERR_RECORD_DELETED ||
|
||||||
{
|
(tmp == HA_ERR_KEY_NOT_FOUND && info->ignore_not_found_rows))
|
||||||
if (info->print_error)
|
continue;
|
||||||
info->file->print_error(tmp,MYF(0));
|
tmp= rr_handle_error(info, tmp);
|
||||||
if (tmp < 0) // Fix negative BDB errno
|
break;
|
||||||
tmp=1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return tmp;
|
return tmp;
|
||||||
} /* rr_from_tempfile */
|
} /* rr_from_tempfile */
|
||||||
@ -373,26 +360,23 @@ static int rr_from_pointers(READ_RECORD *info)
|
|||||||
{
|
{
|
||||||
int tmp;
|
int tmp;
|
||||||
byte *cache_pos;
|
byte *cache_pos;
|
||||||
tryNext:
|
|
||||||
if (info->cache_pos == info->cache_end)
|
|
||||||
return -1; /* End of file */
|
|
||||||
cache_pos=info->cache_pos;
|
|
||||||
info->cache_pos+=info->ref_length;
|
|
||||||
|
|
||||||
if ((tmp=info->file->rnd_pos(info->record,cache_pos)))
|
for (;;)
|
||||||
{
|
{
|
||||||
if (tmp == HA_ERR_END_OF_FILE)
|
if (info->cache_pos == info->cache_end)
|
||||||
tmp= -1;
|
return -1; /* End of file */
|
||||||
else if (tmp == HA_ERR_RECORD_DELETED ||
|
cache_pos= info->cache_pos;
|
||||||
(tmp == HA_ERR_KEY_NOT_FOUND && info->ignore_not_found_rows))
|
info->cache_pos+= info->ref_length;
|
||||||
goto tryNext;
|
|
||||||
else
|
if (!(tmp=info->file->rnd_pos(info->record,cache_pos)))
|
||||||
{
|
break;
|
||||||
if (info->print_error)
|
|
||||||
info->file->print_error(tmp,MYF(0));
|
/* The following is extremely unlikely to happen */
|
||||||
if (tmp < 0) // Fix negative BDB errno
|
if (tmp == HA_ERR_RECORD_DELETED ||
|
||||||
tmp=1;
|
(tmp == HA_ERR_KEY_NOT_FOUND && info->ignore_not_found_rows))
|
||||||
}
|
continue;
|
||||||
|
tmp= rr_handle_error(info, tmp);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
@ -818,11 +818,8 @@ int READ_INFO::read_field()
|
|||||||
*to++ = (byte) unescape((char) chr);
|
*to++ = (byte) unescape((char) chr);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else
|
PUSH(chr);
|
||||||
{
|
chr= escape_char;
|
||||||
PUSH(chr);
|
|
||||||
chr= escape_char;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#ifdef ALLOW_LINESEPARATOR_IN_STRINGS
|
#ifdef ALLOW_LINESEPARATOR_IN_STRINGS
|
||||||
if (chr == line_term_char)
|
if (chr == line_term_char)
|
||||||
|
@ -148,7 +148,7 @@ int mysql_update(THD *thd,
|
|||||||
}
|
}
|
||||||
if (!select && limit != HA_POS_ERROR)
|
if (!select && limit != HA_POS_ERROR)
|
||||||
{
|
{
|
||||||
if (MAX_KEY != (used_index= get_index_for_order(table, order, limit)))
|
if ((used_index= get_index_for_order(table, order, limit)) != MAX_KEY)
|
||||||
need_sort= FALSE;
|
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 */
|
||||||
@ -171,14 +171,14 @@ int mysql_update(THD *thd,
|
|||||||
used_key_is_modified= (!select->quick->unique_key_range() &&
|
used_key_is_modified= (!select->quick->unique_key_range() &&
|
||||||
check_if_key_used(table, used_index, fields));
|
check_if_key_used(table, used_index, 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)
|
|
||||||
used_key_is_modified=check_if_key_used(table, used_index, fields);
|
|
||||||
else
|
else
|
||||||
used_key_is_modified=0;
|
{
|
||||||
|
used_key_is_modified= 0;
|
||||||
|
if (used_index == MAX_KEY) // no index for sort order
|
||||||
|
used_index= table->file->key_used_on_scan;
|
||||||
|
if (used_index != MAX_KEY)
|
||||||
|
used_key_is_modified= check_if_key_used(table, used_index, fields);
|
||||||
|
}
|
||||||
|
|
||||||
if (used_key_is_modified || order)
|
if (used_key_is_modified || order)
|
||||||
{
|
{
|
||||||
@ -190,11 +190,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); //todo: psergey: check
|
table->file->extra(HA_EXTRA_KEYREAD);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* note: can actually avoid sorting below.. */
|
/* note: can actually avoid sorting below.. */
|
||||||
if (order && need_sort)
|
if (order && (need_sort || used_key_is_modified))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
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
|
||||||
@ -204,6 +204,7 @@ int mysql_update(THD *thd,
|
|||||||
SORT_FIELD *sortorder;
|
SORT_FIELD *sortorder;
|
||||||
ha_rows examined_rows;
|
ha_rows examined_rows;
|
||||||
|
|
||||||
|
used_index= MAX_KEY; // For call to init_read_record()
|
||||||
table->sort.io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE),
|
table->sort.io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE),
|
||||||
MYF(MY_FAE | MY_ZEROFILL));
|
MYF(MY_FAE | MY_ZEROFILL));
|
||||||
if (!(sortorder=make_unireg_sortorder(order, &length)) ||
|
if (!(sortorder=make_unireg_sortorder(order, &length)) ||
|
||||||
@ -265,10 +266,7 @@ 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)
|
||||||
{
|
{
|
||||||
|
@ -132,7 +132,6 @@ 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;
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user