Commit 3e653fb9 authored by monty@mysql.com's avatar monty@mysql.com

Added more tests for new UPDATE ... ORDER BY ... LIMIT optimization

parent ea3ea9ed
...@@ -167,7 +167,7 @@ static int check_one_rb_key(HP_INFO *info, uint keynr, ulong records, ...@@ -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, ...@@ -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, &not_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, ...@@ -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, &not_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 { ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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,&not_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) ...@@ -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 @@ ...@@ -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) ...@@ -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, &not_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, ...@@ -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,
&not_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, ...@@ -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, ...@@ -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,&not_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, ...@@ -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,&not_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, ...@@ -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, ...@@ -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,
&not_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, ...@@ -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,&not_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, ...@@ -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,
&not_used); not_used);
} }
......
...@@ -20,9 +20,9 @@ static int queue_key_cmp(void *keyseg, byte *a, byte *b) ...@@ -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, &not_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 ...@@ -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 ...@@ -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 ...@@ -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; ...@@ -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; ...@@ -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, ...@@ -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, ...@@ -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)
......
...@@ -28,11 +28,10 @@ static int rr_from_pointers(READ_RECORD *info); ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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() ...@@ -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, ...@@ -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, ...@@ -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) else
{ {
used_key_is_modified= check_if_key_used(table, used_index, fields); 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);
} }
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
used_key_is_modified=0;
if (used_key_is_modified || order) if (used_key_is_modified || order)
{ {
...@@ -190,11 +190,11 @@ int mysql_update(THD *thd, ...@@ -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, ...@@ -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, ...@@ -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 */ ...@@ -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;
......
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