Manual merge
include/my_sys.h: Auto merged innobase/include/row0mysql.h: Auto merged innobase/row/row0sel.c: Auto merged sql/ha_berkeley.cc: Auto merged sql/ha_berkeley.h: Auto merged sql/ha_heap.h: Auto merged sql/ha_innodb.cc: Auto merged sql/ha_innodb.h: Auto merged sql/handler.h: Auto merged sql/sql_select.cc: Auto merged sql/sql_select.h: Auto merged sql/sql_test.cc: Auto merged include/my_base.h: Manually merged sql/opt_range.cc: Manually merged sql/opt_range.h: Manually merged sql/sql_delete.cc: Manually merged sql/sql_update.cc: Manually merged
This commit is contained in:
commit
fee57535b7
@ -147,6 +147,12 @@ enum ha_extra_function {
|
|||||||
*/
|
*/
|
||||||
HA_EXTRA_CHANGE_KEY_TO_UNIQUE,
|
HA_EXTRA_CHANGE_KEY_TO_UNIQUE,
|
||||||
HA_EXTRA_CHANGE_KEY_TO_DUP
|
HA_EXTRA_CHANGE_KEY_TO_DUP
|
||||||
|
/*
|
||||||
|
When using HA_EXTRA_KEYREAD, overwrite only key member fields and keep
|
||||||
|
other fields intact. When this is off (by default) InnoDB will use memcpy
|
||||||
|
to overwrite entire row.
|
||||||
|
*/
|
||||||
|
HA_EXTRA_KEYREAD_PRESERVE_FIELDS
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The following is parameter to ha_panic() */
|
/* The following is parameter to ha_panic() */
|
||||||
|
@ -46,6 +46,8 @@ extern my_bool bitmap_is_set(const MY_BITMAP *map, uint bitmap_bit);
|
|||||||
extern my_bool bitmap_is_set_all(const MY_BITMAP *map);
|
extern my_bool bitmap_is_set_all(const MY_BITMAP *map);
|
||||||
extern my_bool bitmap_is_subset(const MY_BITMAP *map1, const MY_BITMAP *map2);
|
extern my_bool bitmap_is_subset(const MY_BITMAP *map1, const MY_BITMAP *map2);
|
||||||
extern uint bitmap_set_next(MY_BITMAP *map);
|
extern uint bitmap_set_next(MY_BITMAP *map);
|
||||||
|
extern uint bitmap_get_first(const MY_BITMAP *map);
|
||||||
|
extern uint bitmap_bits_set(const MY_BITMAP *map);
|
||||||
extern void bitmap_clear_all(MY_BITMAP *map);
|
extern void bitmap_clear_all(MY_BITMAP *map);
|
||||||
extern void bitmap_clear_bit(MY_BITMAP *map, uint bitmap_bit);
|
extern void bitmap_clear_bit(MY_BITMAP *map, uint bitmap_bit);
|
||||||
extern void bitmap_free(MY_BITMAP *map);
|
extern void bitmap_free(MY_BITMAP *map);
|
||||||
|
@ -748,6 +748,7 @@ extern byte *my_compress_alloc(const byte *packet, ulong *len, ulong *complen);
|
|||||||
extern ha_checksum my_checksum(ha_checksum crc, const byte *mem, uint count);
|
extern ha_checksum my_checksum(ha_checksum crc, const byte *mem, uint count);
|
||||||
extern uint my_bit_log2(ulong value);
|
extern uint my_bit_log2(ulong value);
|
||||||
extern uint my_count_bits(ulonglong v);
|
extern uint my_count_bits(ulonglong v);
|
||||||
|
extern uint my_count_bits_ushort(ushort v);
|
||||||
extern void my_sleep(ulong m_seconds);
|
extern void my_sleep(ulong m_seconds);
|
||||||
extern ulong crc32(ulong crc, const uchar *buf, uint len);
|
extern ulong crc32(ulong crc, const uchar *buf, uint len);
|
||||||
extern uint my_set_max_open_files(uint files);
|
extern uint my_set_max_open_files(uint files);
|
||||||
|
@ -554,6 +554,10 @@ struct row_prebuilt_struct {
|
|||||||
allocated mem buf start, because
|
allocated mem buf start, because
|
||||||
there is a 4 byte magic number at the
|
there is a 4 byte magic number at the
|
||||||
start and at the end */
|
start and at the end */
|
||||||
|
ibool keep_other_fields_on_keyread; /* when using fetch
|
||||||
|
cache with HA_EXTRA_KEYREAD, don't
|
||||||
|
overwrite other fields in mysql row
|
||||||
|
row buffer.*/
|
||||||
ulint fetch_cache_first;/* position of the first not yet
|
ulint fetch_cache_first;/* position of the first not yet
|
||||||
fetched row in fetch_cache */
|
fetched row in fetch_cache */
|
||||||
ulint n_fetch_cached; /* number of not yet fetched rows
|
ulint n_fetch_cached; /* number of not yet fetched rows
|
||||||
|
@ -2579,10 +2579,35 @@ row_sel_pop_cached_row_for_mysql(
|
|||||||
row */
|
row */
|
||||||
row_prebuilt_t* prebuilt) /* in: prebuilt struct */
|
row_prebuilt_t* prebuilt) /* in: prebuilt struct */
|
||||||
{
|
{
|
||||||
ut_ad(prebuilt->n_fetch_cached > 0);
|
ulint i;
|
||||||
|
mysql_row_templ_t* templ;
|
||||||
|
byte* cached_rec;
|
||||||
|
ut_ad(prebuilt->n_fetch_cached > 0);
|
||||||
|
|
||||||
ut_memcpy(buf, prebuilt->fetch_cache[prebuilt->fetch_cache_first],
|
if (prebuilt->keep_other_fields_on_keyread)
|
||||||
prebuilt->mysql_row_len);
|
{
|
||||||
|
/* Copy cache record field by field, don't touch fields that
|
||||||
|
are not covered by current key */
|
||||||
|
cached_rec =
|
||||||
|
prebuilt->fetch_cache[prebuilt->fetch_cache_first];
|
||||||
|
|
||||||
|
for (i = 0; i < prebuilt->n_template; i++) {
|
||||||
|
templ = prebuilt->mysql_template + i;
|
||||||
|
ut_memcpy(
|
||||||
|
buf + templ->mysql_col_offset,
|
||||||
|
cached_rec + templ->mysql_col_offset,
|
||||||
|
templ->mysql_col_len);
|
||||||
|
|
||||||
|
if (templ->mysql_null_bit_mask)
|
||||||
|
buf[templ->mysql_null_byte_offset] &=
|
||||||
|
cached_rec[templ->mysql_null_byte_offset];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ut_memcpy(buf, prebuilt->fetch_cache[prebuilt->fetch_cache_first],
|
||||||
|
prebuilt->mysql_row_len);
|
||||||
|
}
|
||||||
prebuilt->n_fetch_cached--;
|
prebuilt->n_fetch_cached--;
|
||||||
prebuilt->fetch_cache_first++;
|
prebuilt->fetch_cache_first++;
|
||||||
|
|
||||||
|
168
mysql-test/r/index_merge_ror.result
Normal file
168
mysql-test/r/index_merge_ror.result
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
drop table if exists t1,t0;
|
||||||
|
select count(*) from t1;
|
||||||
|
count(*)
|
||||||
|
64801
|
||||||
|
explain select key1,key2 from t1 where key1=100 and key2=100;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 index_merge key1,key2 key1,key2 5,5 NULL 3 Using where; Using index
|
||||||
|
select key1,key2 from t1 where key1=100 and key2=100;
|
||||||
|
key1 key2
|
||||||
|
100 100
|
||||||
|
explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 index_merge key1,key2,key3,key4 key1,key2,key3,key4 5,5,5,5 NULL 8 Using where
|
||||||
|
select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100;
|
||||||
|
key1 key2 key3 key4 filler1
|
||||||
|
100 100 100 100 key1-key2-key3-key4
|
||||||
|
insert into t1 (key1, key2, key3, key4, filler1) values (100, 100, -1, -1, 'key1-key2');
|
||||||
|
insert into t1 (key1, key2, key3, key4, filler1) values (-1, -1, 100, 100, 'key4-key3');
|
||||||
|
explain select key1,key2,filler1 from t1 where key1=100 and key2=100;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 index_merge key1,key2 key1,key2 5,5 NULL 3 Using where
|
||||||
|
select key1,key2,filler1 from t1 where key1=100 and key2=100;
|
||||||
|
key1 key2 filler1
|
||||||
|
100 100 key1-key2-key3-key4
|
||||||
|
100 100 key1-key2
|
||||||
|
explain select key1,key2 from t1 where key1=100 and key2=100;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 index_merge key1,key2 key1,key2 5,5 NULL 3 Using where; Using index
|
||||||
|
select key1,key2 from t1 where key1=100 and key2=100;
|
||||||
|
key1 key2
|
||||||
|
100 100
|
||||||
|
100 100
|
||||||
|
explain select key1,key2,key3,key4 from t1 where key1=100 and key2=100 or key3=100 and key4=100;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 index_merge key1,key2,key3,key4 key1,key2,key3,key4 5,5,5,5 NULL 8 Using where
|
||||||
|
select key1,key2,key3,key4 from t1 where key1=100 and key2=100 or key3=100 and key4=100;
|
||||||
|
key1 key2 key3 key4
|
||||||
|
100 100 100 100
|
||||||
|
100 100 -1 -1
|
||||||
|
-1 -1 100 100
|
||||||
|
explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 index_merge key1,key2,key3,key4 key1,key2,key3,key4 5,5,5,5 NULL 8 Using where
|
||||||
|
select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100;
|
||||||
|
key1 key2 key3 key4 filler1
|
||||||
|
100 100 100 100 key1-key2-key3-key4
|
||||||
|
100 100 -1 -1 key1-key2
|
||||||
|
-1 -1 100 100 key4-key3
|
||||||
|
explain select key1,key2,key3 from t1 where key1=100 and key2=100 and key3=100;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 index_merge key1,key2,key3 key1,key2,key3 5,5,5 NULL 1 Using where; Using index
|
||||||
|
select key1,key2,key3 from t1 where key1=100 and key2=100 and key3=100;
|
||||||
|
key1 key2 key3
|
||||||
|
100 100 100
|
||||||
|
insert into t1 (key1,key2,key3,key4,filler1) values (101,101,101,101, 'key1234-101');
|
||||||
|
explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=101;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 index_merge key1,key2,key3 key1,key2,key3 5,5,5 NULL 5 Using where
|
||||||
|
select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=101;
|
||||||
|
key1 key2 key3 key4 filler1
|
||||||
|
100 100 100 100 key1-key2-key3-key4
|
||||||
|
100 100 -1 -1 key1-key2
|
||||||
|
101 101 101 101 key1234-101
|
||||||
|
select key1,key2, filler1 from t1 where key1=100 and key2=100;
|
||||||
|
key1 key2 filler1
|
||||||
|
100 100 key1-key2-key3-key4
|
||||||
|
100 100 key1-key2
|
||||||
|
update t1 set filler1='to be deleted' where key1=100 and key2=100;
|
||||||
|
update t1 set key1=200,key2=200 where key1=100 and key2=100;
|
||||||
|
delete from t1 where key1=200 and key2=200;
|
||||||
|
select key1,key2,filler1 from t1 where key2=100 and key2=200;
|
||||||
|
key1 key2 filler1
|
||||||
|
explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 index_merge key1,key2,key3,key4 key1,key2,key3,key4 5,5,5,5 NULL 8 Using where
|
||||||
|
select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100;
|
||||||
|
key1 key2 key3 key4 filler1
|
||||||
|
-1 -1 100 100 key4-key3
|
||||||
|
delete from t1 where key3=100 and key4=100;
|
||||||
|
explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 index_merge key1,key2,key3,key4 key1,key2,key3,key4 5,5,5,5 NULL 8 Using where
|
||||||
|
select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100;
|
||||||
|
key1 key2 key3 key4 filler1
|
||||||
|
explain select key1,key2 from t1 where key1=100 and key2=100;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 index_merge key1,key2 key1,key2 5,5 NULL 3 Using where; Using index
|
||||||
|
select key1,key2 from t1 where key1=100 and key2=100;
|
||||||
|
key1 key2
|
||||||
|
insert into t1 (key1, key2, key3, key4, filler1) values (100, 100, 200, 200,'key1-key2-key3-key4-1');
|
||||||
|
insert into t1 (key1, key2, key3, key4, filler1) values (100, 100, 200, 200,'key1-key2-key3-key4-2');
|
||||||
|
insert into t1 (key1, key2, key3, key4, filler1) values (100, 100, 200, 200,'key1-key2-key3-key4-3');
|
||||||
|
explain select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 index_merge key1,key2,key3,key4 key3,key1,key2,key4 5,5,5,5 NULL 16 Using where
|
||||||
|
select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200;
|
||||||
|
key1 key2 key3 key4 filler1
|
||||||
|
100 100 200 200 key1-key2-key3-key4-3
|
||||||
|
100 100 200 200 key1-key2-key3-key4-2
|
||||||
|
100 100 200 200 key1-key2-key3-key4-1
|
||||||
|
insert into t1 (key1, key2, key3, key4, filler1) values (-1, -1, -1, 200,'key4');
|
||||||
|
explain select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 index_merge key1,key2,key3,key4 key3,key1,key2,key4 5,5,5,5 NULL 18 Using where
|
||||||
|
select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200;
|
||||||
|
key1 key2 key3 key4 filler1
|
||||||
|
100 100 200 200 key1-key2-key3-key4-3
|
||||||
|
100 100 200 200 key1-key2-key3-key4-2
|
||||||
|
100 100 200 200 key1-key2-key3-key4-1
|
||||||
|
-1 -1 -1 200 key4
|
||||||
|
insert into t1 (key1, key2, key3, key4, filler1) values (-1, -1, 200, -1,'key3');
|
||||||
|
explain select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 index_merge key1,key2,key3,key4 key3,key1,key2,key4 5,5,5,5 NULL 20 Using where
|
||||||
|
select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200;
|
||||||
|
key1 key2 key3 key4 filler1
|
||||||
|
100 100 200 200 key1-key2-key3-key4-3
|
||||||
|
100 100 200 200 key1-key2-key3-key4-2
|
||||||
|
100 100 200 200 key1-key2-key3-key4-1
|
||||||
|
-1 -1 -1 200 key4
|
||||||
|
-1 -1 200 -1 key3
|
||||||
|
explain select * from t1 where st_a=1 and st_b=1;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 index_merge sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a,stb_swt1a_2b,stb_swt1b,st_b st_a,st_b 4,4 NULL 2508 Using where
|
||||||
|
explain select st_a,st_b from t1 where st_a=1 and st_b=1;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 index_merge sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a,stb_swt1a_2b,stb_swt1b,st_b st_a,st_b 4,4 NULL 2508 Using where; Using index
|
||||||
|
explain select st_a from t1 ignore index (st_a) where st_a=1 and st_b=1;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 ref sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,stb_swt1a_2b,stb_swt1b,st_b st_b 4 const 14720 Using where
|
||||||
|
explain select * from t1 where st_a=1 and swt1a=1 and swt2a=1;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 ref sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a sta_swt12a 12 const,const,const 958 Using where
|
||||||
|
explain select * from t1 where st_b=1 and swt1b=1 and swt2b=1;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 ref stb_swt1a_2b,stb_swt1b,st_b stb_swt1b 8 const,const 3757 Using where
|
||||||
|
explain select * from t1 where st_a=1 and swt1a=1 and swt2a=1 and st_b=1 and swt1b=1 and swt2b=1;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 index_merge sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a,stb_swt1a_2b,stb_swt1b,st_b sta_swt12a,stb_swt1a_2b 12,12 NULL 42 Using where
|
||||||
|
explain select * from t1 ignore index (sta_swt21a, stb_swt1a_2b)
|
||||||
|
where st_a=1 and swt1a=1 and swt2a=1 and st_b=1 and swt1b=1 and swt2b=1;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 index_merge sta_swt12a,sta_swt1a,sta_swt2a,st_a,stb_swt1b,st_b sta_swt12a,stb_swt1b 12,8 NULL 42 Using where
|
||||||
|
explain select * from t1 ignore index (sta_swt21a, sta_swt12a, stb_swt1a_2b)
|
||||||
|
where st_a=1 and swt1a=1 and swt2a=1 and st_b=1 and swt1b=1 and swt2b=1;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 index_merge sta_swt1a,sta_swt2a,st_a,stb_swt1b,st_b sta_swt1a,stb_swt1b 8,8 NULL 163 Using where
|
||||||
|
explain select * from t1 ignore index (sta_swt21a, sta_swt12a, stb_swt1a_2b, stb_swt1b)
|
||||||
|
where st_a=1 and swt1a=1 and swt2a=1 and st_b=1 and swt1b=1 and swt2b=1;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 index_merge sta_swt1a,sta_swt2a,st_a,st_b sta_swt1a,st_b 8,4 NULL 640 Using where
|
||||||
|
explain select * from t1
|
||||||
|
where st_a=1 and swt1a=1 and swt2a=1 and st_b=1 and swt1b=1;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 index_merge sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a,stb_swt1a_2b,stb_swt1b,st_b sta_swt12a,stb_swt1a_2b 12,12 NULL 42 Using where
|
||||||
|
explain select * from t1
|
||||||
|
where st_a=1 and swt1a=1 and st_b=1 and swt1b=1 and swt1b=1;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 index_merge sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a,stb_swt1a_2b,stb_swt1b,st_b sta_swt1a,stb_swt1b 8,8 NULL 163 Using where
|
||||||
|
explain select st_a from t1
|
||||||
|
where st_a=1 and swt1a=1 and st_b=1 and swt1b=1 and swt1b=1;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 index_merge sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a,stb_swt1a_2b,stb_swt1b,st_b sta_swt1a,stb_swt1b 8,8 NULL 163 Using where; Using index
|
||||||
|
explain select st_a from t1
|
||||||
|
where st_a=1 and swt1a=1 and st_b=1 and swt1b=1 and swt1b=1;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 index_merge sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a,stb_swt1a_2b,stb_swt1b,st_b sta_swt1a,stb_swt1b 8,8 NULL 163 Using where; Using index
|
||||||
|
drop table t0,t1;
|
93
mysql-test/r/index_merge_ror_cpk.result
Normal file
93
mysql-test/r/index_merge_ror_cpk.result
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
drop table if exists t1;
|
||||||
|
create table t1
|
||||||
|
(
|
||||||
|
pk1 int not null,
|
||||||
|
pk2 int not null,
|
||||||
|
key1 int not null,
|
||||||
|
key2 int not null,
|
||||||
|
pktail1ok int not null,
|
||||||
|
pktail2ok int not null,
|
||||||
|
pktail3bad int not null,
|
||||||
|
pktail4bad int not null,
|
||||||
|
pktail5bad int not null,
|
||||||
|
pk2copy int not null,
|
||||||
|
badkey int not null,
|
||||||
|
filler1 char (200),
|
||||||
|
filler2 char (200),
|
||||||
|
key (key1),
|
||||||
|
key (key2),
|
||||||
|
/* keys with tails from CPK members */
|
||||||
|
key (pktail1ok, pk1),
|
||||||
|
key (pktail2ok, pk1, pk2),
|
||||||
|
key (pktail3bad, pk2, pk1),
|
||||||
|
key (pktail4bad, pk1, pk2copy),
|
||||||
|
key (pktail5bad, pk1, pk2, pk2copy),
|
||||||
|
primary key (pk1, pk2)
|
||||||
|
) engine=innodb;
|
||||||
|
explain select * from t1 where pk1 = 1 and pk2 < 80 and key1=0;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 ref PRIMARY,key1 PRIMARY 4 const 1 Using where
|
||||||
|
select * from t1 where pk1 = 1 and pk2 < 80 and key1=0;
|
||||||
|
pk1 pk2 key1 key2 pktail1ok pktail2ok pktail3bad pktail4bad pktail5bad pk2copy badkey filler1 filler2
|
||||||
|
1 10 0 0 0 0 0 0 0 10 0 filler-data-10 filler2
|
||||||
|
1 11 0 0 0 0 0 0 0 11 0 filler-data-11 filler2
|
||||||
|
1 12 0 0 0 0 0 0 0 12 0 filler-data-12 filler2
|
||||||
|
1 13 0 0 0 0 0 0 0 13 0 filler-data-13 filler2
|
||||||
|
1 14 0 0 0 0 0 0 0 14 0 filler-data-14 filler2
|
||||||
|
1 15 0 0 0 0 0 0 0 15 0 filler-data-15 filler2
|
||||||
|
1 16 0 0 0 0 0 0 0 16 0 filler-data-16 filler2
|
||||||
|
1 17 0 0 0 0 0 0 0 17 0 filler-data-17 filler2
|
||||||
|
1 18 0 0 0 0 0 0 0 18 0 filler-data-18 filler2
|
||||||
|
1 19 0 0 0 0 0 0 0 19 0 filler-data-19 filler2
|
||||||
|
explain select pk1,pk2 from t1 where key1 = 10 and key2=10 and 2*pk1+1 < 2*96+1;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 index_merge key1,key2 intr(key1,key2) 4,4 NULL 1 Using where; Using index
|
||||||
|
select pk1,pk2 from t1 where key1 = 10 and key2=10 and 2*pk1+1 < 2*96+1;
|
||||||
|
pk1 pk2
|
||||||
|
95 50
|
||||||
|
95 51
|
||||||
|
95 52
|
||||||
|
95 53
|
||||||
|
95 54
|
||||||
|
95 55
|
||||||
|
95 56
|
||||||
|
95 57
|
||||||
|
95 58
|
||||||
|
95 59
|
||||||
|
explain select * from t1 where badkey=1 and key1=10;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 ref key1 key1 4 const 101 Using where
|
||||||
|
explain select * from t1 where pk1 < 7500 and key1 = 10;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 index_merge PRIMARY,key1 intr(key1:PRIMARY) 4:4 NULL 38 Using where
|
||||||
|
explain select * from t1 where pktail1ok=1 and key1=10;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 index_merge key1,pktail1ok intr(key1,pktail1ok) 4,4 NULL 1 Using where
|
||||||
|
explain select * from t1 where pktail2ok=1 and key1=10;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 index_merge key1,pktail2ok intr(key1,pktail2ok) 4,4 NULL 1 Using where
|
||||||
|
explain select * from t1 where pktail3bad=1 and key1=10;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 ref key1,pktail3bad pktail3bad 4 const 98 Using where
|
||||||
|
explain select * from t1 where pktail4bad=1 and key1=10;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 ref key1,pktail4bad pktail4bad 4 const 99 Using where
|
||||||
|
explain select * from t1 where pktail5bad=1 and key1=10;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 ref key1,pktail5bad pktail5bad 4 const 99 Using where
|
||||||
|
explain select pk1,pk2,key1,key2 from t1 where key1 = 10 and key2=10 limit 10;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 index_merge key1,key2 intr(key1,key2) 4,4 NULL 1 Using where; Using index
|
||||||
|
select pk1,pk2,key1,key2 from t1 where key1 = 10 and key2=10 limit 10;
|
||||||
|
pk1 pk2 key1 key2
|
||||||
|
95 50 10 10
|
||||||
|
95 51 10 10
|
||||||
|
95 52 10 10
|
||||||
|
95 53 10 10
|
||||||
|
95 54 10 10
|
||||||
|
95 55 10 10
|
||||||
|
95 56 10 10
|
||||||
|
95 57 10 10
|
||||||
|
95 58 10 10
|
||||||
|
95 59 10 10
|
||||||
|
drop table t1;
|
186
mysql-test/r/rowid_order_bdb.result
Normal file
186
mysql-test/r/rowid_order_bdb.result
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
drop table if exists t1, t2, t3,t4;
|
||||||
|
create table t1 (
|
||||||
|
pk1 int not NULL,
|
||||||
|
key1 int(11),
|
||||||
|
key2 int(11),
|
||||||
|
PRIMARY KEY (pk1),
|
||||||
|
KEY key1 (key1),
|
||||||
|
KEY key2 (key2)
|
||||||
|
) engine=bdb;
|
||||||
|
insert into t1 values (-5, 1, 1),
|
||||||
|
(-100, 1, 1),
|
||||||
|
(3, 1, 1),
|
||||||
|
(0, 1, 1),
|
||||||
|
(10, 1, 1);
|
||||||
|
explain select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 index_merge key1,key2 key1,key2 5,5 NULL 5 Using where
|
||||||
|
select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
|
||||||
|
pk1 key1 key2
|
||||||
|
-100 1 1
|
||||||
|
-5 1 1
|
||||||
|
0 1 1
|
||||||
|
3 1 1
|
||||||
|
10 1 1
|
||||||
|
drop table t1;
|
||||||
|
create table t1 (
|
||||||
|
pk1 int unsigned not NULL,
|
||||||
|
key1 int(11),
|
||||||
|
key2 int(11),
|
||||||
|
PRIMARY KEY (pk1),
|
||||||
|
KEY key1 (key1),
|
||||||
|
KEY key2 (key2)
|
||||||
|
) engine=bdb;
|
||||||
|
insert into t1 values (0, 1, 1),
|
||||||
|
(0xFFFFFFFF, 1, 1),
|
||||||
|
(0xFFFFFFFE, 1, 1),
|
||||||
|
(1, 1, 1),
|
||||||
|
(2, 1, 1);
|
||||||
|
select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
|
||||||
|
pk1 key1 key2
|
||||||
|
0 1 1
|
||||||
|
1 1 1
|
||||||
|
2 1 1
|
||||||
|
4294967294 1 1
|
||||||
|
4294967295 1 1
|
||||||
|
drop table t1;
|
||||||
|
create table t1 (
|
||||||
|
pk1 char(4) not NULL,
|
||||||
|
key1 int(11),
|
||||||
|
key2 int(11),
|
||||||
|
PRIMARY KEY (pk1),
|
||||||
|
KEY key1 (key1),
|
||||||
|
KEY key2 (key2)
|
||||||
|
) engine=bdb collate latin2_general_ci;
|
||||||
|
insert into t1 values ('a1', 1, 1),
|
||||||
|
('b2', 1, 1),
|
||||||
|
('A3', 1, 1),
|
||||||
|
('B4', 1, 1);
|
||||||
|
select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
|
||||||
|
pk1 key1 key2
|
||||||
|
a1 1 1
|
||||||
|
A3 1 1
|
||||||
|
b2 1 1
|
||||||
|
B4 1 1
|
||||||
|
drop table t1;
|
||||||
|
create table t1 (
|
||||||
|
pk1 int not NULL,
|
||||||
|
pk2 char(4) not NULL collate latin1_german1_ci,
|
||||||
|
pk3 char(4) not NULL collate latin1_bin,
|
||||||
|
key1 int(11),
|
||||||
|
key2 int(11),
|
||||||
|
PRIMARY KEY (pk1,pk2,pk3),
|
||||||
|
KEY key1 (key1),
|
||||||
|
KEY key2 (key2)
|
||||||
|
) engine=bdb;
|
||||||
|
insert into t1 values
|
||||||
|
(1, 'u', 'u', 1, 1),
|
||||||
|
(1, 'u', char(0xEC), 1, 1),
|
||||||
|
(1, 'u', 'x', 1, 1);
|
||||||
|
insert ignore into t1 select pk1, char(0xEC), pk3, key1, key2 from t1;
|
||||||
|
insert ignore into t1 select pk1, 'x', pk3, key1, key2 from t1 where pk2='u';
|
||||||
|
insert ignore into t1 select 2, pk2, pk3, key1, key2 from t1;
|
||||||
|
select * from t1;
|
||||||
|
pk1 pk2 pk3 key1 key2
|
||||||
|
1 ì u 1 1
|
||||||
|
1 ì x 1 1
|
||||||
|
1 ì ì 1 1
|
||||||
|
1 u u 1 1
|
||||||
|
1 u x 1 1
|
||||||
|
1 u ì 1 1
|
||||||
|
1 x u 1 1
|
||||||
|
1 x x 1 1
|
||||||
|
1 x ì 1 1
|
||||||
|
2 ì u 1 1
|
||||||
|
2 ì x 1 1
|
||||||
|
2 ì ì 1 1
|
||||||
|
2 u u 1 1
|
||||||
|
2 u x 1 1
|
||||||
|
2 u ì 1 1
|
||||||
|
2 x u 1 1
|
||||||
|
2 x x 1 1
|
||||||
|
2 x ì 1 1
|
||||||
|
select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
|
||||||
|
pk1 pk2 pk3 key1 key2
|
||||||
|
1 ì u 1 1
|
||||||
|
1 ì x 1 1
|
||||||
|
1 ì ì 1 1
|
||||||
|
1 u u 1 1
|
||||||
|
1 u x 1 1
|
||||||
|
1 u ì 1 1
|
||||||
|
1 x u 1 1
|
||||||
|
1 x x 1 1
|
||||||
|
1 x ì 1 1
|
||||||
|
2 ì u 1 1
|
||||||
|
2 ì x 1 1
|
||||||
|
2 ì ì 1 1
|
||||||
|
2 u u 1 1
|
||||||
|
2 u x 1 1
|
||||||
|
2 u ì 1 1
|
||||||
|
2 x u 1 1
|
||||||
|
2 x x 1 1
|
||||||
|
2 x ì 1 1
|
||||||
|
alter table t1 drop primary key;
|
||||||
|
select * from t1;
|
||||||
|
pk1 pk2 pk3 key1 key2
|
||||||
|
1 ì u 1 1
|
||||||
|
1 ì x 1 1
|
||||||
|
1 ì ì 1 1
|
||||||
|
1 u u 1 1
|
||||||
|
1 u x 1 1
|
||||||
|
1 u ì 1 1
|
||||||
|
1 x u 1 1
|
||||||
|
1 x x 1 1
|
||||||
|
1 x ì 1 1
|
||||||
|
2 ì u 1 1
|
||||||
|
2 ì x 1 1
|
||||||
|
2 ì ì 1 1
|
||||||
|
2 u u 1 1
|
||||||
|
2 u x 1 1
|
||||||
|
2 u ì 1 1
|
||||||
|
2 x u 1 1
|
||||||
|
2 x x 1 1
|
||||||
|
2 x ì 1 1
|
||||||
|
select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
|
||||||
|
pk1 pk2 pk3 key1 key2
|
||||||
|
1 ì u 1 1
|
||||||
|
1 ì x 1 1
|
||||||
|
1 ì ì 1 1
|
||||||
|
1 u u 1 1
|
||||||
|
1 u x 1 1
|
||||||
|
1 u ì 1 1
|
||||||
|
1 x u 1 1
|
||||||
|
1 x x 1 1
|
||||||
|
1 x ì 1 1
|
||||||
|
2 ì u 1 1
|
||||||
|
2 ì x 1 1
|
||||||
|
2 ì ì 1 1
|
||||||
|
2 u u 1 1
|
||||||
|
2 u x 1 1
|
||||||
|
2 u ì 1 1
|
||||||
|
2 x u 1 1
|
||||||
|
2 x x 1 1
|
||||||
|
2 x ì 1 1
|
||||||
|
drop table t1;
|
||||||
|
create table t1 (
|
||||||
|
pk1 varchar(8) NOT NULL default '',
|
||||||
|
pk2 varchar(4) NOT NULL default '',
|
||||||
|
key1 int(11),
|
||||||
|
key2 int(11),
|
||||||
|
primary key(pk1, pk2),
|
||||||
|
KEY key1 (key1),
|
||||||
|
KEY key2 (key2)
|
||||||
|
) engine=bdb;
|
||||||
|
insert into t1 values ('','empt',2,2),
|
||||||
|
('a','a--a',2,2),
|
||||||
|
('bb','b--b',2,2),
|
||||||
|
('ccc','c--c',2,2),
|
||||||
|
('dddd','d--d',2,2);
|
||||||
|
select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
|
||||||
|
pk1 pk2 key1 key2
|
||||||
|
empt 2 2
|
||||||
|
a a--a 2 2
|
||||||
|
bb b--b 2 2
|
||||||
|
ccc c--c 2 2
|
||||||
|
dddd d--d 2 2
|
||||||
|
drop table t1;
|
186
mysql-test/r/rowid_order_innodb.result
Normal file
186
mysql-test/r/rowid_order_innodb.result
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
drop table if exists t1, t2, t3,t4;
|
||||||
|
create table t1 (
|
||||||
|
pk1 int not NULL,
|
||||||
|
key1 int(11),
|
||||||
|
key2 int(11),
|
||||||
|
PRIMARY KEY (pk1),
|
||||||
|
KEY key1 (key1),
|
||||||
|
KEY key2 (key2)
|
||||||
|
) engine=innodb;
|
||||||
|
insert into t1 values (-5, 1, 1),
|
||||||
|
(-100, 1, 1),
|
||||||
|
(3, 1, 1),
|
||||||
|
(0, 1, 1),
|
||||||
|
(10, 1, 1);
|
||||||
|
explain select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 index_merge key1,key2 key1,key2 5,5 NULL 4 Using where
|
||||||
|
select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
|
||||||
|
pk1 key1 key2
|
||||||
|
-100 1 1
|
||||||
|
-5 1 1
|
||||||
|
0 1 1
|
||||||
|
3 1 1
|
||||||
|
10 1 1
|
||||||
|
drop table t1;
|
||||||
|
create table t1 (
|
||||||
|
pk1 int unsigned not NULL,
|
||||||
|
key1 int(11),
|
||||||
|
key2 int(11),
|
||||||
|
PRIMARY KEY (pk1),
|
||||||
|
KEY key1 (key1),
|
||||||
|
KEY key2 (key2)
|
||||||
|
) engine=innodb;
|
||||||
|
insert into t1 values (0, 1, 1),
|
||||||
|
(0xFFFFFFFF, 1, 1),
|
||||||
|
(0xFFFFFFFE, 1, 1),
|
||||||
|
(1, 1, 1),
|
||||||
|
(2, 1, 1);
|
||||||
|
select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
|
||||||
|
pk1 key1 key2
|
||||||
|
0 1 1
|
||||||
|
1 1 1
|
||||||
|
2 1 1
|
||||||
|
4294967294 1 1
|
||||||
|
4294967295 1 1
|
||||||
|
drop table t1;
|
||||||
|
create table t1 (
|
||||||
|
pk1 char(4) not NULL,
|
||||||
|
key1 int(11),
|
||||||
|
key2 int(11),
|
||||||
|
PRIMARY KEY (pk1),
|
||||||
|
KEY key1 (key1),
|
||||||
|
KEY key2 (key2)
|
||||||
|
) engine=innodb collate latin2_general_ci;
|
||||||
|
insert into t1 values ('a1', 1, 1),
|
||||||
|
('b2', 1, 1),
|
||||||
|
('A3', 1, 1),
|
||||||
|
('B4', 1, 1);
|
||||||
|
select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
|
||||||
|
pk1 key1 key2
|
||||||
|
a1 1 1
|
||||||
|
A3 1 1
|
||||||
|
b2 1 1
|
||||||
|
B4 1 1
|
||||||
|
drop table t1;
|
||||||
|
create table t1 (
|
||||||
|
pk1 int not NULL,
|
||||||
|
pk2 char(4) not NULL collate latin1_german1_ci,
|
||||||
|
pk3 char(4) not NULL collate latin1_bin,
|
||||||
|
key1 int(11),
|
||||||
|
key2 int(11),
|
||||||
|
PRIMARY KEY (pk1,pk2,pk3),
|
||||||
|
KEY key1 (key1),
|
||||||
|
KEY key2 (key2)
|
||||||
|
) engine=innodb;
|
||||||
|
insert into t1 values
|
||||||
|
(1, 'u', 'u', 1, 1),
|
||||||
|
(1, 'u', char(0xEC), 1, 1),
|
||||||
|
(1, 'u', 'x', 1, 1);
|
||||||
|
insert ignore into t1 select pk1, char(0xEC), pk3, key1, key2 from t1;
|
||||||
|
insert ignore into t1 select pk1, 'x', pk3, key1, key2 from t1 where pk2='u';
|
||||||
|
insert ignore into t1 select 2, pk2, pk3, key1, key2 from t1;
|
||||||
|
select * from t1;
|
||||||
|
pk1 pk2 pk3 key1 key2
|
||||||
|
1 ì u 1 1
|
||||||
|
1 ì x 1 1
|
||||||
|
1 ì ì 1 1
|
||||||
|
1 u u 1 1
|
||||||
|
1 u x 1 1
|
||||||
|
1 u ì 1 1
|
||||||
|
1 x u 1 1
|
||||||
|
1 x x 1 1
|
||||||
|
1 x ì 1 1
|
||||||
|
2 ì u 1 1
|
||||||
|
2 ì x 1 1
|
||||||
|
2 ì ì 1 1
|
||||||
|
2 u u 1 1
|
||||||
|
2 u x 1 1
|
||||||
|
2 u ì 1 1
|
||||||
|
2 x u 1 1
|
||||||
|
2 x x 1 1
|
||||||
|
2 x ì 1 1
|
||||||
|
select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
|
||||||
|
pk1 pk2 pk3 key1 key2
|
||||||
|
1 ì u 1 1
|
||||||
|
1 ì x 1 1
|
||||||
|
1 ì ì 1 1
|
||||||
|
1 u u 1 1
|
||||||
|
1 u x 1 1
|
||||||
|
1 u ì 1 1
|
||||||
|
1 x u 1 1
|
||||||
|
1 x x 1 1
|
||||||
|
1 x ì 1 1
|
||||||
|
2 ì u 1 1
|
||||||
|
2 ì x 1 1
|
||||||
|
2 ì ì 1 1
|
||||||
|
2 u u 1 1
|
||||||
|
2 u x 1 1
|
||||||
|
2 u ì 1 1
|
||||||
|
2 x u 1 1
|
||||||
|
2 x x 1 1
|
||||||
|
2 x ì 1 1
|
||||||
|
alter table t1 drop primary key;
|
||||||
|
select * from t1;
|
||||||
|
pk1 pk2 pk3 key1 key2
|
||||||
|
1 ì u 1 1
|
||||||
|
1 ì x 1 1
|
||||||
|
1 ì ì 1 1
|
||||||
|
1 u u 1 1
|
||||||
|
1 u x 1 1
|
||||||
|
1 u ì 1 1
|
||||||
|
1 x u 1 1
|
||||||
|
1 x x 1 1
|
||||||
|
1 x ì 1 1
|
||||||
|
2 ì u 1 1
|
||||||
|
2 ì x 1 1
|
||||||
|
2 ì ì 1 1
|
||||||
|
2 u u 1 1
|
||||||
|
2 u x 1 1
|
||||||
|
2 u ì 1 1
|
||||||
|
2 x u 1 1
|
||||||
|
2 x x 1 1
|
||||||
|
2 x ì 1 1
|
||||||
|
select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
|
||||||
|
pk1 pk2 pk3 key1 key2
|
||||||
|
1 ì u 1 1
|
||||||
|
1 ì x 1 1
|
||||||
|
1 ì ì 1 1
|
||||||
|
1 u u 1 1
|
||||||
|
1 u x 1 1
|
||||||
|
1 u ì 1 1
|
||||||
|
1 x u 1 1
|
||||||
|
1 x x 1 1
|
||||||
|
1 x ì 1 1
|
||||||
|
2 ì u 1 1
|
||||||
|
2 ì x 1 1
|
||||||
|
2 ì ì 1 1
|
||||||
|
2 u u 1 1
|
||||||
|
2 u x 1 1
|
||||||
|
2 u ì 1 1
|
||||||
|
2 x u 1 1
|
||||||
|
2 x x 1 1
|
||||||
|
2 x ì 1 1
|
||||||
|
drop table t1;
|
||||||
|
create table t1 (
|
||||||
|
pk1 varchar(8) NOT NULL default '',
|
||||||
|
pk2 varchar(4) NOT NULL default '',
|
||||||
|
key1 int(11),
|
||||||
|
key2 int(11),
|
||||||
|
primary key(pk1, pk2),
|
||||||
|
KEY key1 (key1),
|
||||||
|
KEY key2 (key2)
|
||||||
|
) engine=innodb;
|
||||||
|
insert into t1 values ('','empt',2,2),
|
||||||
|
('a','a--a',2,2),
|
||||||
|
('bb','b--b',2,2),
|
||||||
|
('ccc','c--c',2,2),
|
||||||
|
('dddd','d--d',2,2);
|
||||||
|
select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
|
||||||
|
pk1 pk2 key1 key2
|
||||||
|
empt 2 2
|
||||||
|
a a--a 2 2
|
||||||
|
bb b--b 2 2
|
||||||
|
ccc c--c 2 2
|
||||||
|
dddd d--d 2 2
|
||||||
|
drop table t1;
|
215
mysql-test/t/index_merge_ror.test
Normal file
215
mysql-test/t/index_merge_ror.test
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
#
|
||||||
|
# ROR-index_merge tests.
|
||||||
|
#
|
||||||
|
--disable_warnings
|
||||||
|
drop table if exists t1,t0;
|
||||||
|
--enable_warnings
|
||||||
|
--disable_query_log
|
||||||
|
create table t1
|
||||||
|
(
|
||||||
|
/* Field names reflect value(rowid) distribution, st=STairs, swt= SaWTooth */
|
||||||
|
st_a int not null,
|
||||||
|
swt1a int not null,
|
||||||
|
swt2a int not null,
|
||||||
|
|
||||||
|
st_b int not null,
|
||||||
|
swt1b int not null,
|
||||||
|
swt2b int not null,
|
||||||
|
|
||||||
|
/* fields/keys for row retrieval tests */
|
||||||
|
key1 int,
|
||||||
|
key2 int,
|
||||||
|
key3 int,
|
||||||
|
key4 int,
|
||||||
|
|
||||||
|
/* make rows much bigger then keys */
|
||||||
|
filler1 char (200),
|
||||||
|
filler2 char (200),
|
||||||
|
filler3 char (200),
|
||||||
|
filler4 char (200),
|
||||||
|
filler5 char (200),
|
||||||
|
filler6 char (200),
|
||||||
|
|
||||||
|
/* order of keys is important */
|
||||||
|
key sta_swt12a(st_a,swt1a,swt2a),
|
||||||
|
key sta_swt1a(st_a,swt1a),
|
||||||
|
key sta_swt2a(st_a,swt2a),
|
||||||
|
key sta_swt21a(st_a,swt2a,swt1a),
|
||||||
|
|
||||||
|
key st_a(st_a),
|
||||||
|
key stb_swt1a_2b(st_b,swt1b,swt2a),
|
||||||
|
key stb_swt1b(st_b,swt1b),
|
||||||
|
key st_b(st_b),
|
||||||
|
|
||||||
|
key(key1),
|
||||||
|
key(key2),
|
||||||
|
key(key3),
|
||||||
|
key(key4)
|
||||||
|
) ;
|
||||||
|
|
||||||
|
# Fill table
|
||||||
|
create table t0 as select * from t1;
|
||||||
|
let $cnt=1000;
|
||||||
|
while ($cnt)
|
||||||
|
{
|
||||||
|
eval insert into t0 values (1, 2, 3, 1, 2, 3, 0, 0, 0, 0, 'data1', 'data2', 'data3', 'data4', 'data5', 'data6');
|
||||||
|
dec $cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
alter table t1 disable keys;
|
||||||
|
let $1=4;
|
||||||
|
while ($1)
|
||||||
|
{
|
||||||
|
let $2=4;
|
||||||
|
while ($2)
|
||||||
|
{
|
||||||
|
let $3=4;
|
||||||
|
while ($3)
|
||||||
|
{
|
||||||
|
eval insert into t1 select $1, $2, $3, $1 ,$2, $3, key1, key2, key3, key4, filler1, filler2, filler3, filler4, filler5, filler6 from t0;
|
||||||
|
dec $3;
|
||||||
|
}
|
||||||
|
dec $2;
|
||||||
|
}
|
||||||
|
dec $1;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Row retrieval tests
|
||||||
|
# -1 is used for values 'out of any range we are using'
|
||||||
|
# insert enough rows for index intersection to be used for (key1,key2)
|
||||||
|
insert into t1 (key1, key2, key3, key4, filler1) values (100, 100, 100, 100,'key1-key2-key3-key4');
|
||||||
|
let $cnt=400;
|
||||||
|
while ($cnt)
|
||||||
|
{
|
||||||
|
eval insert into t1 (key1, key2, key3, key4, filler1) values (100, -1, 100, -1,'key1-key3');
|
||||||
|
dec $cnt;
|
||||||
|
}
|
||||||
|
let $cnt=400;
|
||||||
|
while ($cnt)
|
||||||
|
{
|
||||||
|
eval insert into t1 (key1, key2, key3, key4, filler1) values (-1, 100, -1, 100,'key2-key4');
|
||||||
|
dec $cnt;
|
||||||
|
}
|
||||||
|
alter table t1 enable keys;
|
||||||
|
--enable_query_log
|
||||||
|
select count(*) from t1;
|
||||||
|
|
||||||
|
# One row results tests for cases where a single row matches all conditions
|
||||||
|
explain select key1,key2 from t1 where key1=100 and key2=100;
|
||||||
|
select key1,key2 from t1 where key1=100 and key2=100;
|
||||||
|
|
||||||
|
explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100;
|
||||||
|
select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100;
|
||||||
|
|
||||||
|
# Several-rows results
|
||||||
|
insert into t1 (key1, key2, key3, key4, filler1) values (100, 100, -1, -1, 'key1-key2');
|
||||||
|
insert into t1 (key1, key2, key3, key4, filler1) values (-1, -1, 100, 100, 'key4-key3');
|
||||||
|
|
||||||
|
# ROR-intersection, not covering
|
||||||
|
explain select key1,key2,filler1 from t1 where key1=100 and key2=100;
|
||||||
|
select key1,key2,filler1 from t1 where key1=100 and key2=100;
|
||||||
|
|
||||||
|
# ROR-intersection, covering
|
||||||
|
explain select key1,key2 from t1 where key1=100 and key2=100;
|
||||||
|
select key1,key2 from t1 where key1=100 and key2=100;
|
||||||
|
|
||||||
|
# ROR-union of ROR-intersections
|
||||||
|
explain select key1,key2,key3,key4 from t1 where key1=100 and key2=100 or key3=100 and key4=100;
|
||||||
|
select key1,key2,key3,key4 from t1 where key1=100 and key2=100 or key3=100 and key4=100;
|
||||||
|
explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100;
|
||||||
|
select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100;
|
||||||
|
|
||||||
|
# 3-way ROR-intersection
|
||||||
|
explain select key1,key2,key3 from t1 where key1=100 and key2=100 and key3=100;
|
||||||
|
select key1,key2,key3 from t1 where key1=100 and key2=100 and key3=100;
|
||||||
|
|
||||||
|
# ROR-union(ROR-intersection, ROR-range)
|
||||||
|
insert into t1 (key1,key2,key3,key4,filler1) values (101,101,101,101, 'key1234-101');
|
||||||
|
explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=101;
|
||||||
|
select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=101;
|
||||||
|
|
||||||
|
# Run some ROR updates/deletes
|
||||||
|
select key1,key2, filler1 from t1 where key1=100 and key2=100;
|
||||||
|
update t1 set filler1='to be deleted' where key1=100 and key2=100;
|
||||||
|
update t1 set key1=200,key2=200 where key1=100 and key2=100;
|
||||||
|
delete from t1 where key1=200 and key2=200;
|
||||||
|
select key1,key2,filler1 from t1 where key2=100 and key2=200;
|
||||||
|
|
||||||
|
# ROR-union(ROR-intersection) with one of ROR-intersection giving empty
|
||||||
|
# results
|
||||||
|
explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100;
|
||||||
|
select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100;
|
||||||
|
|
||||||
|
delete from t1 where key3=100 and key4=100;
|
||||||
|
|
||||||
|
# ROR-union with all ROR-intersections giving empty results
|
||||||
|
explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100;
|
||||||
|
select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100;
|
||||||
|
|
||||||
|
# ROR-intersection with empty result
|
||||||
|
explain select key1,key2 from t1 where key1=100 and key2=100;
|
||||||
|
select key1,key2 from t1 where key1=100 and key2=100;
|
||||||
|
|
||||||
|
# ROR-union tests with various cases.
|
||||||
|
# All scans returning duplicate rows:
|
||||||
|
insert into t1 (key1, key2, key3, key4, filler1) values (100, 100, 200, 200,'key1-key2-key3-key4-1');
|
||||||
|
insert into t1 (key1, key2, key3, key4, filler1) values (100, 100, 200, 200,'key1-key2-key3-key4-2');
|
||||||
|
insert into t1 (key1, key2, key3, key4, filler1) values (100, 100, 200, 200,'key1-key2-key3-key4-3');
|
||||||
|
|
||||||
|
explain select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200;
|
||||||
|
select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200;
|
||||||
|
|
||||||
|
insert into t1 (key1, key2, key3, key4, filler1) values (-1, -1, -1, 200,'key4');
|
||||||
|
|
||||||
|
explain select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200;
|
||||||
|
select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200;
|
||||||
|
|
||||||
|
insert into t1 (key1, key2, key3, key4, filler1) values (-1, -1, 200, -1,'key3');
|
||||||
|
|
||||||
|
explain select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200;
|
||||||
|
select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200;
|
||||||
|
|
||||||
|
##
|
||||||
|
## Optimizer tests
|
||||||
|
##
|
||||||
|
|
||||||
|
# Check that the shortest key is used for ROR-intersection, covering and non-covering.
|
||||||
|
explain select * from t1 where st_a=1 and st_b=1;
|
||||||
|
explain select st_a,st_b from t1 where st_a=1 and st_b=1;
|
||||||
|
|
||||||
|
# Check if "ingore index" syntax works
|
||||||
|
explain select st_a from t1 ignore index (st_a) where st_a=1 and st_b=1;
|
||||||
|
|
||||||
|
# Do many tests
|
||||||
|
# Check that keys that don't improve selectivity are skipped.
|
||||||
|
#
|
||||||
|
|
||||||
|
explain select * from t1 where st_a=1 and swt1a=1 and swt2a=1;
|
||||||
|
|
||||||
|
explain select * from t1 where st_b=1 and swt1b=1 and swt2b=1;
|
||||||
|
|
||||||
|
explain select * from t1 where st_a=1 and swt1a=1 and swt2a=1 and st_b=1 and swt1b=1 and swt2b=1;
|
||||||
|
|
||||||
|
explain select * from t1 ignore index (sta_swt21a, stb_swt1a_2b)
|
||||||
|
where st_a=1 and swt1a=1 and swt2a=1 and st_b=1 and swt1b=1 and swt2b=1;
|
||||||
|
|
||||||
|
explain select * from t1 ignore index (sta_swt21a, sta_swt12a, stb_swt1a_2b)
|
||||||
|
where st_a=1 and swt1a=1 and swt2a=1 and st_b=1 and swt1b=1 and swt2b=1;
|
||||||
|
|
||||||
|
explain select * from t1 ignore index (sta_swt21a, sta_swt12a, stb_swt1a_2b, stb_swt1b)
|
||||||
|
where st_a=1 and swt1a=1 and swt2a=1 and st_b=1 and swt1b=1 and swt2b=1;
|
||||||
|
|
||||||
|
explain select * from t1
|
||||||
|
where st_a=1 and swt1a=1 and swt2a=1 and st_b=1 and swt1b=1;
|
||||||
|
|
||||||
|
explain select * from t1
|
||||||
|
where st_a=1 and swt1a=1 and st_b=1 and swt1b=1 and swt1b=1;
|
||||||
|
|
||||||
|
explain select st_a from t1
|
||||||
|
where st_a=1 and swt1a=1 and st_b=1 and swt1b=1 and swt1b=1;
|
||||||
|
|
||||||
|
explain select st_a from t1
|
||||||
|
where st_a=1 and swt1a=1 and st_b=1 and swt1b=1 and swt1b=1;
|
||||||
|
|
||||||
|
drop table t0,t1;
|
||||||
|
|
81
mysql-test/t/index_merge_ror_cpk.test
Normal file
81
mysql-test/t/index_merge_ror_cpk.test
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
#
|
||||||
|
# Clustered PK ROR-index_merge tests
|
||||||
|
#
|
||||||
|
-- source include/have_innodb.inc
|
||||||
|
|
||||||
|
--disable_warnings
|
||||||
|
drop table if exists t1;
|
||||||
|
--enable_warnings
|
||||||
|
|
||||||
|
create table t1
|
||||||
|
(
|
||||||
|
pk1 int not null,
|
||||||
|
pk2 int not null,
|
||||||
|
|
||||||
|
key1 int not null,
|
||||||
|
key2 int not null,
|
||||||
|
|
||||||
|
pktail1ok int not null,
|
||||||
|
pktail2ok int not null,
|
||||||
|
pktail3bad int not null,
|
||||||
|
pktail4bad int not null,
|
||||||
|
pktail5bad int not null,
|
||||||
|
|
||||||
|
pk2copy int not null,
|
||||||
|
badkey int not null,
|
||||||
|
|
||||||
|
filler1 char (200),
|
||||||
|
filler2 char (200),
|
||||||
|
key (key1),
|
||||||
|
key (key2),
|
||||||
|
|
||||||
|
/* keys with tails from CPK members */
|
||||||
|
key (pktail1ok, pk1),
|
||||||
|
key (pktail2ok, pk1, pk2),
|
||||||
|
key (pktail3bad, pk2, pk1),
|
||||||
|
key (pktail4bad, pk1, pk2copy),
|
||||||
|
key (pktail5bad, pk1, pk2, pk2copy),
|
||||||
|
|
||||||
|
primary key (pk1, pk2)
|
||||||
|
) engine=innodb;
|
||||||
|
|
||||||
|
--disable_query_log
|
||||||
|
set autocommit=0;
|
||||||
|
let $1=10000;
|
||||||
|
while ($1)
|
||||||
|
{
|
||||||
|
eval insert into t1 values ($1 div 10,$1 mod 100, $1/100,$1/100, $1/100,$1/100,$1/100,$1/100,$1/100, $1 mod 100, $1/1000,'filler-data-$1','filler2');
|
||||||
|
dec $1;
|
||||||
|
}
|
||||||
|
set autocommit=1;
|
||||||
|
--enable_query_log
|
||||||
|
|
||||||
|
# Verify that range scan on CPK is ROR
|
||||||
|
# (use index_intersection because it is impossible to check that for index union)
|
||||||
|
explain select * from t1 where pk1 = 1 and pk2 < 80 and key1=0;
|
||||||
|
# CPK scan + 1 ROR range scan is a special case
|
||||||
|
select * from t1 where pk1 = 1 and pk2 < 80 and key1=0;
|
||||||
|
|
||||||
|
# Verify that CPK fields are considered to be covered by index scans
|
||||||
|
explain select pk1,pk2 from t1 where key1 = 10 and key2=10 and 2*pk1+1 < 2*96+1;
|
||||||
|
select pk1,pk2 from t1 where key1 = 10 and key2=10 and 2*pk1+1 < 2*96+1;
|
||||||
|
|
||||||
|
# Verify that CPK is always used for index intersection scans
|
||||||
|
# (this is because it is used as a filter, not for retrieval)
|
||||||
|
explain select * from t1 where badkey=1 and key1=10;
|
||||||
|
explain select * from t1 where pk1 < 7500 and key1 = 10;
|
||||||
|
|
||||||
|
# Verify that keys with 'tails' of PK members are ok.
|
||||||
|
explain select * from t1 where pktail1ok=1 and key1=10;
|
||||||
|
explain select * from t1 where pktail2ok=1 and key1=10;
|
||||||
|
|
||||||
|
explain select * from t1 where pktail3bad=1 and key1=10;
|
||||||
|
explain select * from t1 where pktail4bad=1 and key1=10;
|
||||||
|
explain select * from t1 where pktail5bad=1 and key1=10;
|
||||||
|
|
||||||
|
# Test for problem with innodb key values prefetch buffer:
|
||||||
|
explain select pk1,pk2,key1,key2 from t1 where key1 = 10 and key2=10 limit 10;
|
||||||
|
select pk1,pk2,key1,key2 from t1 where key1 = 10 and key2=10 limit 10;
|
||||||
|
|
||||||
|
drop table t1;
|
||||||
|
|
108
mysql-test/t/rowid_order_bdb.test
Normal file
108
mysql-test/t/rowid_order_bdb.test
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
#
|
||||||
|
# Test for rowid ordering (and comparison) functions.
|
||||||
|
# do index_merge select for tables with PK of various types.
|
||||||
|
#
|
||||||
|
--disable_warnings
|
||||||
|
drop table if exists t1, t2, t3,t4;
|
||||||
|
--enable_warnings
|
||||||
|
|
||||||
|
-- source include/have_bdb.inc
|
||||||
|
|
||||||
|
# Signed number as rowid
|
||||||
|
create table t1 (
|
||||||
|
pk1 int not NULL,
|
||||||
|
key1 int(11),
|
||||||
|
key2 int(11),
|
||||||
|
PRIMARY KEY (pk1),
|
||||||
|
KEY key1 (key1),
|
||||||
|
KEY key2 (key2)
|
||||||
|
) engine=bdb;
|
||||||
|
insert into t1 values (-5, 1, 1),
|
||||||
|
(-100, 1, 1),
|
||||||
|
(3, 1, 1),
|
||||||
|
(0, 1, 1),
|
||||||
|
(10, 1, 1);
|
||||||
|
explain select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
|
||||||
|
select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
|
||||||
|
drop table t1;
|
||||||
|
|
||||||
|
# Unsigned numbers as rowids
|
||||||
|
create table t1 (
|
||||||
|
pk1 int unsigned not NULL,
|
||||||
|
key1 int(11),
|
||||||
|
key2 int(11),
|
||||||
|
PRIMARY KEY (pk1),
|
||||||
|
KEY key1 (key1),
|
||||||
|
KEY key2 (key2)
|
||||||
|
) engine=bdb;
|
||||||
|
insert into t1 values (0, 1, 1),
|
||||||
|
(0xFFFFFFFF, 1, 1),
|
||||||
|
(0xFFFFFFFE, 1, 1),
|
||||||
|
(1, 1, 1),
|
||||||
|
(2, 1, 1);
|
||||||
|
select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
|
||||||
|
drop table t1;
|
||||||
|
|
||||||
|
# Case-insensitive char(N)
|
||||||
|
create table t1 (
|
||||||
|
pk1 char(4) not NULL,
|
||||||
|
key1 int(11),
|
||||||
|
key2 int(11),
|
||||||
|
PRIMARY KEY (pk1),
|
||||||
|
KEY key1 (key1),
|
||||||
|
KEY key2 (key2)
|
||||||
|
) engine=bdb collate latin2_general_ci;
|
||||||
|
insert into t1 values ('a1', 1, 1),
|
||||||
|
('b2', 1, 1),
|
||||||
|
('A3', 1, 1),
|
||||||
|
('B4', 1, 1);
|
||||||
|
select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
|
||||||
|
drop table t1;
|
||||||
|
|
||||||
|
# Multi-part PK
|
||||||
|
create table t1 (
|
||||||
|
pk1 int not NULL,
|
||||||
|
pk2 char(4) not NULL collate latin1_german1_ci,
|
||||||
|
pk3 char(4) not NULL collate latin1_bin,
|
||||||
|
key1 int(11),
|
||||||
|
key2 int(11),
|
||||||
|
PRIMARY KEY (pk1,pk2,pk3),
|
||||||
|
KEY key1 (key1),
|
||||||
|
KEY key2 (key2)
|
||||||
|
) engine=bdb;
|
||||||
|
insert into t1 values
|
||||||
|
(1, 'u', 'u', 1, 1),
|
||||||
|
(1, 'u', char(0xEC), 1, 1),
|
||||||
|
(1, 'u', 'x', 1, 1);
|
||||||
|
insert ignore into t1 select pk1, char(0xEC), pk3, key1, key2 from t1;
|
||||||
|
insert ignore into t1 select pk1, 'x', pk3, key1, key2 from t1 where pk2='u';
|
||||||
|
insert ignore into t1 select 2, pk2, pk3, key1, key2 from t1;
|
||||||
|
select * from t1;
|
||||||
|
select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
|
||||||
|
|
||||||
|
# Hidden PK
|
||||||
|
alter table t1 drop primary key;
|
||||||
|
select * from t1;
|
||||||
|
select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
|
||||||
|
drop table t1;
|
||||||
|
|
||||||
|
# Variable-length PK
|
||||||
|
# this is also test for Bug#2688
|
||||||
|
create table t1 (
|
||||||
|
pk1 varchar(8) NOT NULL default '',
|
||||||
|
pk2 varchar(4) NOT NULL default '',
|
||||||
|
key1 int(11),
|
||||||
|
key2 int(11),
|
||||||
|
primary key(pk1, pk2),
|
||||||
|
KEY key1 (key1),
|
||||||
|
KEY key2 (key2)
|
||||||
|
) engine=bdb;
|
||||||
|
insert into t1 values ('','empt',2,2),
|
||||||
|
('a','a--a',2,2),
|
||||||
|
('bb','b--b',2,2),
|
||||||
|
('ccc','c--c',2,2),
|
||||||
|
('dddd','d--d',2,2);
|
||||||
|
select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
|
||||||
|
|
||||||
|
drop table t1;
|
||||||
|
|
108
mysql-test/t/rowid_order_innodb.test
Normal file
108
mysql-test/t/rowid_order_innodb.test
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
#
|
||||||
|
# Test for rowid ordering (and comparison) functions.
|
||||||
|
# do index_merge select for tables with PK of various types.
|
||||||
|
#
|
||||||
|
--disable_warnings
|
||||||
|
drop table if exists t1, t2, t3,t4;
|
||||||
|
--enable_warnings
|
||||||
|
|
||||||
|
-- source include/have_innodb.inc
|
||||||
|
|
||||||
|
# Signed number as rowid
|
||||||
|
create table t1 (
|
||||||
|
pk1 int not NULL,
|
||||||
|
key1 int(11),
|
||||||
|
key2 int(11),
|
||||||
|
PRIMARY KEY (pk1),
|
||||||
|
KEY key1 (key1),
|
||||||
|
KEY key2 (key2)
|
||||||
|
) engine=innodb;
|
||||||
|
insert into t1 values (-5, 1, 1),
|
||||||
|
(-100, 1, 1),
|
||||||
|
(3, 1, 1),
|
||||||
|
(0, 1, 1),
|
||||||
|
(10, 1, 1);
|
||||||
|
explain select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
|
||||||
|
select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
|
||||||
|
drop table t1;
|
||||||
|
|
||||||
|
# Unsigned numbers as rowids
|
||||||
|
create table t1 (
|
||||||
|
pk1 int unsigned not NULL,
|
||||||
|
key1 int(11),
|
||||||
|
key2 int(11),
|
||||||
|
PRIMARY KEY (pk1),
|
||||||
|
KEY key1 (key1),
|
||||||
|
KEY key2 (key2)
|
||||||
|
) engine=innodb;
|
||||||
|
insert into t1 values (0, 1, 1),
|
||||||
|
(0xFFFFFFFF, 1, 1),
|
||||||
|
(0xFFFFFFFE, 1, 1),
|
||||||
|
(1, 1, 1),
|
||||||
|
(2, 1, 1);
|
||||||
|
select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
|
||||||
|
drop table t1;
|
||||||
|
|
||||||
|
# Case-insensitive char(N)
|
||||||
|
create table t1 (
|
||||||
|
pk1 char(4) not NULL,
|
||||||
|
key1 int(11),
|
||||||
|
key2 int(11),
|
||||||
|
PRIMARY KEY (pk1),
|
||||||
|
KEY key1 (key1),
|
||||||
|
KEY key2 (key2)
|
||||||
|
) engine=innodb collate latin2_general_ci;
|
||||||
|
insert into t1 values ('a1', 1, 1),
|
||||||
|
('b2', 1, 1),
|
||||||
|
('A3', 1, 1),
|
||||||
|
('B4', 1, 1);
|
||||||
|
select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
|
||||||
|
drop table t1;
|
||||||
|
|
||||||
|
# Multi-part PK
|
||||||
|
create table t1 (
|
||||||
|
pk1 int not NULL,
|
||||||
|
pk2 char(4) not NULL collate latin1_german1_ci,
|
||||||
|
pk3 char(4) not NULL collate latin1_bin,
|
||||||
|
key1 int(11),
|
||||||
|
key2 int(11),
|
||||||
|
PRIMARY KEY (pk1,pk2,pk3),
|
||||||
|
KEY key1 (key1),
|
||||||
|
KEY key2 (key2)
|
||||||
|
) engine=innodb;
|
||||||
|
insert into t1 values
|
||||||
|
(1, 'u', 'u', 1, 1),
|
||||||
|
(1, 'u', char(0xEC), 1, 1),
|
||||||
|
(1, 'u', 'x', 1, 1);
|
||||||
|
insert ignore into t1 select pk1, char(0xEC), pk3, key1, key2 from t1;
|
||||||
|
insert ignore into t1 select pk1, 'x', pk3, key1, key2 from t1 where pk2='u';
|
||||||
|
insert ignore into t1 select 2, pk2, pk3, key1, key2 from t1;
|
||||||
|
select * from t1;
|
||||||
|
select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
|
||||||
|
|
||||||
|
# Hidden PK
|
||||||
|
alter table t1 drop primary key;
|
||||||
|
select * from t1;
|
||||||
|
select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
|
||||||
|
drop table t1;
|
||||||
|
|
||||||
|
# Variable-length PK
|
||||||
|
# this is also test for Bug#2688
|
||||||
|
create table t1 (
|
||||||
|
pk1 varchar(8) NOT NULL default '',
|
||||||
|
pk2 varchar(4) NOT NULL default '',
|
||||||
|
key1 int(11),
|
||||||
|
key2 int(11),
|
||||||
|
primary key(pk1, pk2),
|
||||||
|
KEY key1 (key1),
|
||||||
|
KEY key2 (key2)
|
||||||
|
) engine=innodb;
|
||||||
|
insert into t1 values ('','empt',2,2),
|
||||||
|
('a','a--a',2,2),
|
||||||
|
('bb','b--b',2,2),
|
||||||
|
('ccc','c--c',2,2),
|
||||||
|
('dddd','d--d',2,2);
|
||||||
|
select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
|
||||||
|
|
||||||
|
drop table t1;
|
||||||
|
|
@ -71,3 +71,8 @@ uint my_count_bits(ulonglong v)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint my_count_bits_ushort(ushort v)
|
||||||
|
{
|
||||||
|
return nbits[v];
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -330,3 +330,59 @@ void bitmap_union(MY_BITMAP *map, const MY_BITMAP *map2)
|
|||||||
bitmap_unlock(map);
|
bitmap_unlock(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Get number of set bits in the bitmap
|
||||||
|
*/
|
||||||
|
uint bitmap_bits_set(const MY_BITMAP *map)
|
||||||
|
{
|
||||||
|
uchar *m= map->bitmap,
|
||||||
|
*end= map->bitmap+map->bitmap_size;
|
||||||
|
uint res= 0;
|
||||||
|
|
||||||
|
DBUG_ASSERT(map->bitmap);
|
||||||
|
|
||||||
|
bitmap_lock((MY_BITMAP *)map);
|
||||||
|
while (m < end)
|
||||||
|
{
|
||||||
|
res+= my_count_bits_ushort(*m++);
|
||||||
|
}
|
||||||
|
|
||||||
|
bitmap_unlock((MY_BITMAP *)map);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Return number of first zero bit or MY_BIT_NONE if all bits are set.
|
||||||
|
*/
|
||||||
|
|
||||||
|
uint bitmap_get_first(const MY_BITMAP *map)
|
||||||
|
{
|
||||||
|
uchar *bitmap=map->bitmap;
|
||||||
|
uint bit_found = MY_BIT_NONE;
|
||||||
|
uint bitmap_size=map->bitmap_size*8;
|
||||||
|
uint i;
|
||||||
|
|
||||||
|
DBUG_ASSERT(map->bitmap);
|
||||||
|
bitmap_lock((MY_BITMAP *)map);
|
||||||
|
for (i=0; i < bitmap_size ; i++, bitmap++)
|
||||||
|
{
|
||||||
|
if (*bitmap != 0xff)
|
||||||
|
{ /* Found slot with free bit */
|
||||||
|
uint b;
|
||||||
|
for (b=0; ; b++)
|
||||||
|
{
|
||||||
|
if (!(*bitmap & (1 << b)))
|
||||||
|
{
|
||||||
|
bit_found = (i*8)+b;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break; /* Found bit */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bitmap_unlock((MY_BITMAP *)map);
|
||||||
|
return bit_found;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -2499,4 +2499,29 @@ ha_rows ha_berkeley::estimate_number_of_rows()
|
|||||||
return share->rows + HA_BERKELEY_EXTRA_ROWS;
|
return share->rows + HA_BERKELEY_EXTRA_ROWS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ha_berkeley::cmp_ref(const byte *ref1, const byte *ref2)
|
||||||
|
{
|
||||||
|
if (hidden_primary_key)
|
||||||
|
return memcmp(ref1, ref2, BDB_HIDDEN_PRIMARY_KEY_LENGTH);
|
||||||
|
|
||||||
|
int result;
|
||||||
|
Field *field;
|
||||||
|
KEY *key_info=table->key_info+table->primary_key;
|
||||||
|
KEY_PART_INFO *key_part=key_info->key_part;
|
||||||
|
KEY_PART_INFO *end=key_part+key_info->key_parts;
|
||||||
|
|
||||||
|
for (; key_part != end; key_part++)
|
||||||
|
{
|
||||||
|
field= key_part->field;
|
||||||
|
result= field->pack_cmp((const char*)ref1, (const char*)ref2,
|
||||||
|
key_part->length);
|
||||||
|
if (result)
|
||||||
|
return result;
|
||||||
|
ref1 += field->packed_col_length((const char*)ref1, key_part->length);
|
||||||
|
ref2 += field->packed_col_length((const char*)ref2, key_part->length);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* HAVE_BERKELEY_DB */
|
#endif /* HAVE_BERKELEY_DB */
|
||||||
|
@ -169,6 +169,7 @@ class ha_berkeley: public handler
|
|||||||
void print_error(int error, myf errflag);
|
void print_error(int error, myf errflag);
|
||||||
uint8 table_cache_type() { return HA_CACHE_TBL_TRANSACT; }
|
uint8 table_cache_type() { return HA_CACHE_TBL_TRANSACT; }
|
||||||
bool primary_key_is_clustered() { return true; }
|
bool primary_key_is_clustered() { return true; }
|
||||||
|
int cmp_ref(const byte *ref1, const byte *ref2);
|
||||||
};
|
};
|
||||||
|
|
||||||
extern bool berkeley_shared_data;
|
extern bool berkeley_shared_data;
|
||||||
|
@ -95,5 +95,10 @@ class ha_heap: public handler
|
|||||||
|
|
||||||
THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
|
THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
|
||||||
enum thr_lock_type lock_type);
|
enum thr_lock_type lock_type);
|
||||||
|
int cmp_ref(const byte *ref1, const byte *ref2)
|
||||||
|
{
|
||||||
|
HEAP_PTR ptr1=*(HEAP_PTR*)ref1;
|
||||||
|
HEAP_PTR ptr2=*(HEAP_PTR*)ref2;
|
||||||
|
return ptr1 < ptr2? -1 : (ptr1 > ptr2? 1 : 0);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
@ -709,6 +709,8 @@ ha_innobase::init_table_handle_for_HANDLER(void)
|
|||||||
prebuilt->read_just_key = FALSE;
|
prebuilt->read_just_key = FALSE;
|
||||||
|
|
||||||
prebuilt->used_in_HANDLER = TRUE;
|
prebuilt->used_in_HANDLER = TRUE;
|
||||||
|
|
||||||
|
prebuilt->keep_other_fields_on_keyread = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
@ -4515,9 +4517,11 @@ ha_innobase::extra(
|
|||||||
if (prebuilt->blob_heap) {
|
if (prebuilt->blob_heap) {
|
||||||
row_mysql_prebuilt_free_blob_heap(prebuilt);
|
row_mysql_prebuilt_free_blob_heap(prebuilt);
|
||||||
}
|
}
|
||||||
|
prebuilt->keep_other_fields_on_keyread = 0;
|
||||||
prebuilt->read_just_key = 0;
|
prebuilt->read_just_key = 0;
|
||||||
break;
|
break;
|
||||||
case HA_EXTRA_RESET_STATE:
|
case HA_EXTRA_RESET_STATE:
|
||||||
|
prebuilt->keep_other_fields_on_keyread = 0;
|
||||||
prebuilt->read_just_key = 0;
|
prebuilt->read_just_key = 0;
|
||||||
break;
|
break;
|
||||||
case HA_EXTRA_NO_KEYREAD:
|
case HA_EXTRA_NO_KEYREAD:
|
||||||
@ -4536,6 +4540,9 @@ ha_innobase::extra(
|
|||||||
case HA_EXTRA_KEYREAD:
|
case HA_EXTRA_KEYREAD:
|
||||||
prebuilt->read_just_key = 1;
|
prebuilt->read_just_key = 1;
|
||||||
break;
|
break;
|
||||||
|
case HA_EXTRA_KEYREAD_PRESERVE_FIELDS:
|
||||||
|
prebuilt->keep_other_fields_on_keyread = 1;
|
||||||
|
break;
|
||||||
default:/* Do nothing */
|
default:/* Do nothing */
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
@ -4594,6 +4601,7 @@ ha_innobase::start_stmt(
|
|||||||
prebuilt->sql_stat_start = TRUE;
|
prebuilt->sql_stat_start = TRUE;
|
||||||
prebuilt->hint_need_to_fetch_extra_cols = 0;
|
prebuilt->hint_need_to_fetch_extra_cols = 0;
|
||||||
prebuilt->read_just_key = 0;
|
prebuilt->read_just_key = 0;
|
||||||
|
prebuilt->keep_other_fields_on_keyread = FALSE;
|
||||||
|
|
||||||
if (!prebuilt->mysql_has_locked) {
|
if (!prebuilt->mysql_has_locked) {
|
||||||
/* This handle is for a temporary table created inside
|
/* This handle is for a temporary table created inside
|
||||||
@ -4672,6 +4680,7 @@ ha_innobase::external_lock(
|
|||||||
prebuilt->hint_need_to_fetch_extra_cols = 0;
|
prebuilt->hint_need_to_fetch_extra_cols = 0;
|
||||||
|
|
||||||
prebuilt->read_just_key = 0;
|
prebuilt->read_just_key = 0;
|
||||||
|
prebuilt->keep_other_fields_on_keyread = FALSE;
|
||||||
|
|
||||||
if (lock_type == F_WRLCK) {
|
if (lock_type == F_WRLCK) {
|
||||||
|
|
||||||
@ -5074,4 +5083,52 @@ ha_innobase::get_auto_increment()
|
|||||||
return(nr);
|
return(nr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ha_innobase::cmp_ref(
|
||||||
|
const mysql_byte *ref1,
|
||||||
|
const mysql_byte *ref2)
|
||||||
|
{
|
||||||
|
row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
|
||||||
|
enum_field_types mysql_type;
|
||||||
|
Field* field;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
if (prebuilt->clust_index_was_generated)
|
||||||
|
return memcmp(ref1, ref2, DATA_ROW_ID_LEN);
|
||||||
|
|
||||||
|
/* Do type-aware comparison of Primary Key members. PK members
|
||||||
|
are always NOT NULL, so no checks for NULL are performed */
|
||||||
|
KEY_PART_INFO *key_part= table->key_info[table->primary_key].key_part;
|
||||||
|
KEY_PART_INFO *key_part_end=
|
||||||
|
key_part + table->key_info[table->primary_key].key_parts;
|
||||||
|
for (; key_part != key_part_end; ++key_part) {
|
||||||
|
field = key_part->field;
|
||||||
|
mysql_type = field->type();
|
||||||
|
if (mysql_type == FIELD_TYPE_TINY_BLOB
|
||||||
|
|| mysql_type == FIELD_TYPE_MEDIUM_BLOB
|
||||||
|
|| mysql_type == FIELD_TYPE_BLOB
|
||||||
|
|| mysql_type == FIELD_TYPE_LONG_BLOB) {
|
||||||
|
|
||||||
|
ut_a(!ref1[1]);
|
||||||
|
ut_a(!ref2[1]);
|
||||||
|
byte len1= *ref1;
|
||||||
|
byte len2= *ref2;
|
||||||
|
ref1 += 2;
|
||||||
|
ref2 += 2;
|
||||||
|
result =
|
||||||
|
((Field_blob*)field)->cmp((const char*)ref1, len1,
|
||||||
|
(const char*)ref2, len2);
|
||||||
|
} else {
|
||||||
|
result =
|
||||||
|
field->cmp((const char*)ref1, (const char*)ref2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result)
|
||||||
|
return result;
|
||||||
|
ref1 += key_part->length;
|
||||||
|
ref2 += key_part->length;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* HAVE_INNOBASE_DB */
|
#endif /* HAVE_INNOBASE_DB */
|
||||||
|
@ -188,6 +188,7 @@ class ha_innobase: public handler
|
|||||||
longlong get_auto_increment();
|
longlong get_auto_increment();
|
||||||
uint8 table_cache_type() { return HA_CACHE_TBL_ASKTRANSACT; }
|
uint8 table_cache_type() { return HA_CACHE_TBL_ASKTRANSACT; }
|
||||||
bool primary_key_is_clustered() { return true; }
|
bool primary_key_is_clustered() { return true; }
|
||||||
|
int cmp_ref(const byte *ref1, const byte *ref2);
|
||||||
};
|
};
|
||||||
|
|
||||||
extern uint innobase_init_flags, innobase_lock_type;
|
extern uint innobase_init_flags, innobase_lock_type;
|
||||||
|
@ -389,6 +389,11 @@ public:
|
|||||||
false otherwise
|
false otherwise
|
||||||
*/
|
*/
|
||||||
virtual bool primary_key_is_clustered() { return false; }
|
virtual bool primary_key_is_clustered() { return false; }
|
||||||
|
|
||||||
|
virtual int cmp_ref(const byte *ref1, const byte *ref2)
|
||||||
|
{
|
||||||
|
return memcmp(ref1, ref2, ref_length);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Some extern variables used with handlers */
|
/* Some extern variables used with handlers */
|
||||||
|
2509
sql/opt_range.cc
2509
sql/opt_range.cc
File diff suppressed because it is too large
Load Diff
157
sql/opt_range.h
157
sql/opt_range.h
@ -79,10 +79,12 @@ public:
|
|||||||
TABLE *head;
|
TABLE *head;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
the only index this quick select uses, or MAX_KEY for
|
index this quick select uses, or MAX_KEY for quick selects
|
||||||
QUICK_INDEX_MERGE_SELECT
|
that use several indexes
|
||||||
*/
|
*/
|
||||||
uint index;
|
uint index;
|
||||||
|
|
||||||
|
/* applicable iff index!= MAX_KEY */
|
||||||
uint max_used_key_length, used_key_parts;
|
uint max_used_key_length, used_key_parts;
|
||||||
|
|
||||||
QUICK_SELECT_I();
|
QUICK_SELECT_I();
|
||||||
@ -106,13 +108,50 @@ public:
|
|||||||
QS_TYPE_RANGE = 0,
|
QS_TYPE_RANGE = 0,
|
||||||
QS_TYPE_INDEX_MERGE = 1,
|
QS_TYPE_INDEX_MERGE = 1,
|
||||||
QS_TYPE_RANGE_DESC = 2,
|
QS_TYPE_RANGE_DESC = 2,
|
||||||
QS_TYPE_FULLTEXT = 3
|
QS_TYPE_FULLTEXT = 3,
|
||||||
|
QS_TYPE_ROR_INTERSECT = 4,
|
||||||
|
QS_TYPE_ROR_UNION = 5,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Get type of this quick select - one of the QS_* values */
|
/* Get type of this quick select - one of the QS_TYPE_* values */
|
||||||
virtual int get_type() = 0;
|
virtual int get_type() = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Initialize this quick select as a child of a index union or intersection
|
||||||
|
scan. This call replaces init() call.
|
||||||
|
*/
|
||||||
|
virtual int init_ror_child_scan(bool reuse_handler)
|
||||||
|
{ DBUG_ASSERT(0); return 1; }
|
||||||
|
|
||||||
|
virtual void cleanup_ror_child_scan() { DBUG_ASSERT(0); }
|
||||||
|
virtual void save_last_pos(){};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Fill key_names with list of keys this quick select used;
|
||||||
|
fill used_lenghth with correponding used lengths.
|
||||||
|
This is used by select_describe.
|
||||||
|
*/
|
||||||
|
virtual void fill_keys_and_lengths(String *key_names,
|
||||||
|
String *used_lengths)=0;
|
||||||
|
|
||||||
|
virtual bool check_if_keys_used(List<Item> *fields);
|
||||||
|
|
||||||
|
/*
|
||||||
|
rowid of last row retrieved by this quick select. This is used only
|
||||||
|
when doing ROR-index_merge selects
|
||||||
|
*/
|
||||||
|
byte *last_rowid;
|
||||||
|
byte *record;
|
||||||
|
#ifndef DBUG_OFF
|
||||||
|
/*
|
||||||
|
Print quick select information to DBUG_FILE. Caller is responsible
|
||||||
|
for locking DBUG_FILE before this call and unlocking it afterwards.
|
||||||
|
*/
|
||||||
|
virtual void dbug_dump(int indent, bool verbose)= 0;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct st_qsel_param;
|
struct st_qsel_param;
|
||||||
class SEL_ARG;
|
class SEL_ARG;
|
||||||
|
|
||||||
@ -122,11 +161,11 @@ protected:
|
|||||||
bool next,dont_free;
|
bool next,dont_free;
|
||||||
public:
|
public:
|
||||||
int error;
|
int error;
|
||||||
handler *file;
|
|
||||||
byte *record;
|
|
||||||
protected:
|
protected:
|
||||||
friend void print_quick_sel_range(QUICK_RANGE_SELECT *quick,
|
handler *file;
|
||||||
const key_map* needed_reg);
|
bool free_file; /* if true, this quick select "owns" file and will free it */
|
||||||
|
|
||||||
|
protected:
|
||||||
friend
|
friend
|
||||||
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);
|
||||||
@ -140,17 +179,19 @@ protected:
|
|||||||
MEM_ROOT *alloc);
|
MEM_ROOT *alloc);
|
||||||
friend class QUICK_SELECT_DESC;
|
friend class QUICK_SELECT_DESC;
|
||||||
friend class QUICK_INDEX_MERGE_SELECT;
|
friend class QUICK_INDEX_MERGE_SELECT;
|
||||||
|
friend class QUICK_ROR_INTERSECT_SELECT;
|
||||||
|
|
||||||
DYNAMIC_ARRAY ranges; /* ordered array of range ptrs */
|
DYNAMIC_ARRAY ranges; /* ordered array of range ptrs */
|
||||||
QUICK_RANGE **cur_range; /* current element in ranges */
|
QUICK_RANGE **cur_range; /* current element in ranges */
|
||||||
|
|
||||||
QUICK_RANGE *range;
|
QUICK_RANGE *range;
|
||||||
MEM_ROOT alloc;
|
|
||||||
KEY_PART *key_parts;
|
KEY_PART *key_parts;
|
||||||
int cmp_next(QUICK_RANGE *range);
|
int cmp_next(QUICK_RANGE *range);
|
||||||
int cmp_prev(QUICK_RANGE *range);
|
int cmp_prev(QUICK_RANGE *range);
|
||||||
bool row_in_ranges();
|
bool row_in_ranges();
|
||||||
public:
|
public:
|
||||||
|
MEM_ROOT alloc;
|
||||||
|
|
||||||
QUICK_RANGE_SELECT(THD *thd, TABLE *table,uint index_arg,bool no_alloc=0,
|
QUICK_RANGE_SELECT(THD *thd, TABLE *table,uint index_arg,bool no_alloc=0,
|
||||||
MEM_ROOT *parent_alloc=NULL);
|
MEM_ROOT *parent_alloc=NULL);
|
||||||
~QUICK_RANGE_SELECT();
|
~QUICK_RANGE_SELECT();
|
||||||
@ -166,7 +207,16 @@ public:
|
|||||||
int get_next();
|
int get_next();
|
||||||
bool reverse_sorted() { return 0; }
|
bool reverse_sorted() { return 0; }
|
||||||
bool unique_key_range();
|
bool unique_key_range();
|
||||||
|
int init_ror_child_scan(bool reuse_handler);
|
||||||
|
void save_last_pos()
|
||||||
|
{
|
||||||
|
file->position(record);
|
||||||
|
};
|
||||||
int get_type() { return QS_TYPE_RANGE; }
|
int get_type() { return QS_TYPE_RANGE; }
|
||||||
|
void fill_keys_and_lengths(String *key_names, String *used_lengths);
|
||||||
|
#ifndef DBUG_OFF
|
||||||
|
virtual void dbug_dump(int indent, bool verbose);
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -241,6 +291,11 @@ public:
|
|||||||
bool reverse_sorted() { return false; }
|
bool reverse_sorted() { return false; }
|
||||||
bool unique_key_range() { return false; }
|
bool unique_key_range() { return false; }
|
||||||
int get_type() { return QS_TYPE_INDEX_MERGE; }
|
int get_type() { return QS_TYPE_INDEX_MERGE; }
|
||||||
|
void fill_keys_and_lengths(String *key_names, String *used_lengths);
|
||||||
|
bool check_if_keys_used(List<Item> *fields);
|
||||||
|
#ifndef DBUG_OFF
|
||||||
|
virtual void dbug_dump(int indent, bool verbose);
|
||||||
|
#endif
|
||||||
|
|
||||||
bool push_quick_back(QUICK_RANGE_SELECT *quick_sel_range);
|
bool push_quick_back(QUICK_RANGE_SELECT *quick_sel_range);
|
||||||
|
|
||||||
@ -251,9 +306,6 @@ public:
|
|||||||
List_iterator_fast<QUICK_RANGE_SELECT> cur_quick_it;
|
List_iterator_fast<QUICK_RANGE_SELECT> cur_quick_it;
|
||||||
QUICK_RANGE_SELECT* cur_quick_select;
|
QUICK_RANGE_SELECT* cur_quick_select;
|
||||||
|
|
||||||
/* last element in quick_selects list */
|
|
||||||
QUICK_RANGE_SELECT* last_quick_select;
|
|
||||||
|
|
||||||
/* quick select that uses clustered primary key (NULL if none) */
|
/* quick select that uses clustered primary key (NULL if none) */
|
||||||
QUICK_RANGE_SELECT* pk_quick_select;
|
QUICK_RANGE_SELECT* pk_quick_select;
|
||||||
|
|
||||||
@ -271,6 +323,87 @@ public:
|
|||||||
READ_RECORD read_record;
|
READ_RECORD read_record;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Rowid-Ordered Retrieval (ROR) index intersection quick select.
|
||||||
|
This quick select produces an intersection of records returned by several
|
||||||
|
QUICK_RANGE_SELECTs that return data ordered by rowid.
|
||||||
|
*/
|
||||||
|
class QUICK_ROR_INTERSECT_SELECT : public QUICK_SELECT_I
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QUICK_ROR_INTERSECT_SELECT(THD *thd, TABLE *table,
|
||||||
|
bool retrieve_full_rows,
|
||||||
|
MEM_ROOT *parent_alloc);
|
||||||
|
~QUICK_ROR_INTERSECT_SELECT();
|
||||||
|
|
||||||
|
int init();
|
||||||
|
int reset(void);
|
||||||
|
int get_next();
|
||||||
|
bool reverse_sorted() { return false; }
|
||||||
|
bool unique_key_range() { return false; }
|
||||||
|
int get_type() { return QS_TYPE_ROR_INTERSECT; }
|
||||||
|
void fill_keys_and_lengths(String *key_names, String *used_lengths);
|
||||||
|
bool check_if_keys_used(List<Item> *fields);
|
||||||
|
#ifndef DBUG_OFF
|
||||||
|
virtual void dbug_dump(int indent, bool verbose);
|
||||||
|
#endif
|
||||||
|
int init_ror_child_scan(bool reuse_handler);
|
||||||
|
bool push_quick_back(QUICK_RANGE_SELECT *quick_sel_range);
|
||||||
|
|
||||||
|
/* range quick selects this intersection consists of */
|
||||||
|
List<QUICK_RANGE_SELECT> quick_selects;
|
||||||
|
|
||||||
|
QUICK_RANGE_SELECT *cpk_quick;
|
||||||
|
MEM_ROOT alloc;
|
||||||
|
THD *thd;
|
||||||
|
bool reset_called;
|
||||||
|
bool need_to_fetch_row;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Rowid-Ordered Retrieval index union select.
|
||||||
|
|
||||||
|
*/
|
||||||
|
class QUICK_ROR_UNION_SELECT : public QUICK_SELECT_I
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QUICK_ROR_UNION_SELECT(THD *thd, TABLE *table);
|
||||||
|
~QUICK_ROR_UNION_SELECT();
|
||||||
|
|
||||||
|
int init();
|
||||||
|
int reset(void);
|
||||||
|
int get_next();
|
||||||
|
bool reverse_sorted() { return false; }
|
||||||
|
bool unique_key_range() { return false; }
|
||||||
|
int get_type() { return QS_TYPE_ROR_UNION; }
|
||||||
|
void fill_keys_and_lengths(String *key_names, String *used_lengths);
|
||||||
|
bool check_if_keys_used(List<Item> *fields);
|
||||||
|
#ifndef DBUG_OFF
|
||||||
|
virtual void dbug_dump(int indent, bool verbose);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool push_quick_back(QUICK_SELECT_I *quick_sel_range);
|
||||||
|
|
||||||
|
/* range quick selects this index_merge read consists of */
|
||||||
|
List<QUICK_SELECT_I> quick_selects;
|
||||||
|
|
||||||
|
QUEUE queue;
|
||||||
|
MEM_ROOT alloc;
|
||||||
|
|
||||||
|
THD *thd;
|
||||||
|
byte *cur_rowid;
|
||||||
|
byte *prev_rowid;
|
||||||
|
uint rowid_length;
|
||||||
|
bool reset_called;
|
||||||
|
bool have_prev_rowid;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static int queue_cmp(void *arg, byte *val1, byte *val2);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class QUICK_SELECT_DESC: public QUICK_RANGE_SELECT
|
class QUICK_SELECT_DESC: public QUICK_RANGE_SELECT
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -260,10 +260,10 @@ cleanup:
|
|||||||
|
|
||||||
#define MEM_STRIP_BUF_SIZE current_thd->variables.sortbuff_size
|
#define MEM_STRIP_BUF_SIZE current_thd->variables.sortbuff_size
|
||||||
|
|
||||||
extern "C" int refposcmp2(void* arg, const void *a,const void *b)
|
extern "C" int refpos_order_cmp(void* arg, const void *a,const void *b)
|
||||||
{
|
{
|
||||||
/* arg is a pointer to file->ref_length */
|
handler *file= (handler*)arg;
|
||||||
return memcmp(a,b, *(int*) arg);
|
return file->cmp_ref((const byte*)a, (const byte*)b);
|
||||||
}
|
}
|
||||||
|
|
||||||
multi_delete::multi_delete(THD *thd_arg, TABLE_LIST *dt,
|
multi_delete::multi_delete(THD *thd_arg, TABLE_LIST *dt,
|
||||||
@ -327,8 +327,8 @@ multi_delete::initialize_tables(JOIN *join)
|
|||||||
for (walk=walk->next ; walk ; walk=walk->next)
|
for (walk=walk->next ; walk ; walk=walk->next)
|
||||||
{
|
{
|
||||||
TABLE *table=walk->table;
|
TABLE *table=walk->table;
|
||||||
*tempfiles_ptr++= new Unique (refposcmp2,
|
*tempfiles_ptr++= new Unique (refpos_order_cmp,
|
||||||
(void *) &table->file->ref_length,
|
(void *) table->file,
|
||||||
table->file->ref_length,
|
table->file->ref_length,
|
||||||
MEM_STRIP_BUF_SIZE);
|
MEM_STRIP_BUF_SIZE);
|
||||||
}
|
}
|
||||||
|
@ -8025,8 +8025,16 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
|
|||||||
}
|
}
|
||||||
else if (select && select->quick) // Range found by opt_range
|
else if (select && select->quick) // Range found by opt_range
|
||||||
{
|
{
|
||||||
/* assume results are not ordered when index merge is used */
|
int quick_type= select->quick->get_type();
|
||||||
if (select->quick->get_type() == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE)
|
/*
|
||||||
|
assume results are not ordered when index merge is used
|
||||||
|
TODO: sergeyp: Results of all index merge selects actually are ordered
|
||||||
|
by clustered PK values.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE ||
|
||||||
|
quick_type == QUICK_SELECT_I::QS_TYPE_ROR_UNION ||
|
||||||
|
quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT)
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
ref_key= select->quick->index;
|
ref_key= select->quick->index;
|
||||||
ref_key_parts= select->quick->used_key_parts;
|
ref_key_parts= select->quick->used_key_parts;
|
||||||
@ -8087,9 +8095,11 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
|
|||||||
*/
|
*/
|
||||||
if (!select->quick->reverse_sorted())
|
if (!select->quick->reverse_sorted())
|
||||||
{
|
{
|
||||||
|
int quick_type= select->quick->get_type();
|
||||||
if (table->file->index_flags(ref_key) & HA_NOT_READ_PREFIX_LAST ||
|
if (table->file->index_flags(ref_key) & HA_NOT_READ_PREFIX_LAST ||
|
||||||
(select->quick->get_type() ==
|
quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE ||
|
||||||
QUICK_SELECT_I::QS_TYPE_INDEX_MERGE))
|
quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT ||
|
||||||
|
quick_type == QUICK_SELECT_I::QS_TYPE_ROR_UNION)
|
||||||
DBUG_RETURN(0); // Use filesort
|
DBUG_RETURN(0); // Use filesort
|
||||||
|
|
||||||
// ORDER BY range_key DESC
|
// ORDER BY range_key DESC
|
||||||
@ -10067,6 +10077,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
|
|||||||
select_result *result=join->result;
|
select_result *result=join->result;
|
||||||
Item *item_null= new Item_null();
|
Item *item_null= new Item_null();
|
||||||
CHARSET_INFO *cs= &my_charset_latin1;
|
CHARSET_INFO *cs= &my_charset_latin1;
|
||||||
|
int quick_type= -1;
|
||||||
DBUG_ENTER("select_describe");
|
DBUG_ENTER("select_describe");
|
||||||
DBUG_PRINT("info", ("Select 0x%lx, type %s, message %s",
|
DBUG_PRINT("info", ("Select 0x%lx, type %s, message %s",
|
||||||
(ulong)join->select_lex, join->select_lex->type,
|
(ulong)join->select_lex, join->select_lex->type,
|
||||||
@ -10112,8 +10123,10 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
|
|||||||
cs));
|
cs));
|
||||||
if (tab->type == JT_ALL && tab->select && tab->select->quick)
|
if (tab->type == JT_ALL && tab->select && tab->select->quick)
|
||||||
{
|
{
|
||||||
if (tab->select->quick->get_type() ==
|
quick_type= tab->select->quick->get_type();
|
||||||
QUICK_SELECT_I::QS_TYPE_INDEX_MERGE)
|
if ((quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE) ||
|
||||||
|
(quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT) ||
|
||||||
|
(quick_type == QUICK_SELECT_I::QS_TYPE_ROR_UNION))
|
||||||
tab->type = JT_INDEX_MERGE;
|
tab->type = JT_INDEX_MERGE;
|
||||||
else
|
else
|
||||||
tab->type = JT_RANGE;
|
tab->type = JT_RANGE;
|
||||||
@ -10134,6 +10147,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
|
|||||||
strlen(join_type_str[tab->type]),
|
strlen(join_type_str[tab->type]),
|
||||||
cs));
|
cs));
|
||||||
uint j;
|
uint j;
|
||||||
|
/* Build "possible_keys" value and add it to item_list */
|
||||||
if (!tab->keys.is_clear_all())
|
if (!tab->keys.is_clear_all())
|
||||||
{
|
{
|
||||||
for (j=0 ; j < table->keys ; j++)
|
for (j=0 ; j < table->keys ; j++)
|
||||||
@ -10150,6 +10164,8 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
|
|||||||
item_list.push_back(new Item_string(tmp1.ptr(),tmp1.length(),cs));
|
item_list.push_back(new Item_string(tmp1.ptr(),tmp1.length(),cs));
|
||||||
else
|
else
|
||||||
item_list.push_back(item_null);
|
item_list.push_back(item_null);
|
||||||
|
|
||||||
|
/* Build key,key_len, and ref values and add them to item_list */
|
||||||
if (tab->ref.key_parts)
|
if (tab->ref.key_parts)
|
||||||
{
|
{
|
||||||
KEY *key_info=table->key_info+ tab->ref.key;
|
KEY *key_info=table->key_info+ tab->ref.key;
|
||||||
@ -10184,48 +10200,9 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
|
|||||||
}
|
}
|
||||||
else if (tab->select && tab->select->quick)
|
else if (tab->select && tab->select->quick)
|
||||||
{
|
{
|
||||||
if (tab->select->quick->get_type() ==
|
tab->select->quick->fill_keys_and_lengths(&tmp2, &tmp3);
|
||||||
QUICK_SELECT_I::QS_TYPE_INDEX_MERGE)
|
|
||||||
{
|
|
||||||
QUICK_INDEX_MERGE_SELECT *quick_imerge=
|
|
||||||
(QUICK_INDEX_MERGE_SELECT*)tab->select->quick;
|
|
||||||
QUICK_RANGE_SELECT *quick;
|
|
||||||
|
|
||||||
List_iterator_fast<QUICK_RANGE_SELECT> it(quick_imerge->
|
|
||||||
quick_selects);
|
|
||||||
while ((quick= it++))
|
|
||||||
{
|
|
||||||
KEY *key_info= table->key_info + quick->index;
|
|
||||||
register uint length;
|
|
||||||
if (tmp3.length())
|
|
||||||
tmp3.append(',');
|
|
||||||
|
|
||||||
tmp3.append(key_info->name);
|
|
||||||
|
|
||||||
if (tmp2.length())
|
|
||||||
tmp2.append(',');
|
|
||||||
|
|
||||||
length= longlong2str(quick->max_used_key_length, keylen_str_buf,
|
|
||||||
10) -
|
|
||||||
keylen_str_buf;
|
|
||||||
|
|
||||||
tmp2.append(keylen_str_buf, length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
KEY *key_info= table->key_info + tab->select->quick->index;
|
|
||||||
register uint length;
|
|
||||||
tmp3.append(key_info->name);
|
|
||||||
|
|
||||||
length= longlong2str(tab->select->quick->max_used_key_length,
|
|
||||||
keylen_str_buf, 10) -
|
|
||||||
keylen_str_buf;
|
|
||||||
tmp2.append(keylen_str_buf, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
item_list.push_back(new Item_string(tmp3.ptr(),tmp3.length(),cs));
|
|
||||||
item_list.push_back(new Item_string(tmp2.ptr(),tmp2.length(),cs));
|
item_list.push_back(new Item_string(tmp2.ptr(),tmp2.length(),cs));
|
||||||
|
item_list.push_back(new Item_string(tmp3.ptr(),tmp3.length(),cs));
|
||||||
item_list.push_back(item_null);
|
item_list.push_back(item_null);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -10240,6 +10217,9 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
|
|||||||
my_bool key_read=table->key_read;
|
my_bool key_read=table->key_read;
|
||||||
if (tab->type == JT_NEXT && table->used_keys.is_set(tab->index))
|
if (tab->type == JT_NEXT && table->used_keys.is_set(tab->index))
|
||||||
key_read=1;
|
key_read=1;
|
||||||
|
if (quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT &&
|
||||||
|
!((QUICK_ROR_INTERSECT_SELECT*)tab->select->quick)->need_to_fetch_row)
|
||||||
|
key_read=1;
|
||||||
|
|
||||||
if (tab->info)
|
if (tab->info)
|
||||||
item_list.push_back(new Item_string(tab->info,strlen(tab->info),cs));
|
item_list.push_back(new Item_string(tab->info,strlen(tab->info),cs));
|
||||||
|
@ -334,7 +334,7 @@ uint find_shortest_key(TABLE *table, const key_map *usable_keys);
|
|||||||
int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds);
|
int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds);
|
||||||
|
|
||||||
/* from sql_delete.cc, used by opt_range.cc */
|
/* from sql_delete.cc, used by opt_range.cc */
|
||||||
extern "C" int refposcmp2(void* arg, const void *a,const void *b);
|
extern "C" int refpos_order_cmp(void* arg, const void *a,const void *b);
|
||||||
|
|
||||||
/* class to copying an field/item to a key struct */
|
/* class to copying an field/item to a key struct */
|
||||||
|
|
||||||
|
@ -182,37 +182,8 @@ TEST_join(JOIN *join)
|
|||||||
tab->select->quick_keys.print(buf));
|
tab->select->quick_keys.print(buf));
|
||||||
else if (tab->select->quick)
|
else if (tab->select->quick)
|
||||||
{
|
{
|
||||||
int quick_type= tab->select->quick->get_type();
|
fprintf(DBUG_FILE, " quick select used:\n");
|
||||||
if ((quick_type == QUICK_SELECT_I::QS_TYPE_RANGE) ||
|
tab->select->quick->dbug_dump(18, false);
|
||||||
(quick_type == QUICK_SELECT_I::QS_TYPE_RANGE_DESC))
|
|
||||||
{
|
|
||||||
fprintf(DBUG_FILE,
|
|
||||||
" quick select used on key %s, length: %d\n",
|
|
||||||
form->key_info[tab->select->quick->index].name,
|
|
||||||
tab->select->quick->max_used_key_length);
|
|
||||||
}
|
|
||||||
else if (quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE)
|
|
||||||
{
|
|
||||||
QUICK_INDEX_MERGE_SELECT *quick_imerge=
|
|
||||||
(QUICK_INDEX_MERGE_SELECT*)tab->select->quick;
|
|
||||||
QUICK_RANGE_SELECT *quick;
|
|
||||||
fprintf(DBUG_FILE,
|
|
||||||
" index_merge quick select used\n");
|
|
||||||
|
|
||||||
List_iterator_fast<QUICK_RANGE_SELECT> it(quick_imerge->quick_selects);
|
|
||||||
while ((quick = it++))
|
|
||||||
{
|
|
||||||
fprintf(DBUG_FILE,
|
|
||||||
" range quick select: key %s, length: %d\n",
|
|
||||||
form->key_info[quick->index].name,
|
|
||||||
quick->max_used_key_length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fprintf(DBUG_FILE,
|
|
||||||
" quick select of unknown nature used\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
VOID(fputs(" select used\n",DBUG_FILE));
|
VOID(fputs(" select used\n",DBUG_FILE));
|
||||||
|
@ -175,18 +175,11 @@ int mysql_update(THD *thd,
|
|||||||
}
|
}
|
||||||
init_ftfuncs(thd, &thd->lex->select_lex, 1);
|
init_ftfuncs(thd, &thd->lex->select_lex, 1);
|
||||||
/* Check if we are modifying a key that we are used to search with */
|
/* Check if we are modifying a key that we are used to search with */
|
||||||
|
|
||||||
if (select && select->quick)
|
if (select && select->quick)
|
||||||
{
|
{
|
||||||
if (select->quick->get_type() != QUICK_SELECT_I::QS_TYPE_INDEX_MERGE)
|
used_key_is_modified= (!select->quick->unique_key_range() &&
|
||||||
{
|
select->quick->check_if_keys_used(&fields));
|
||||||
used_index= select->quick->index;
|
|
||||||
used_key_is_modified= (!select->quick->unique_key_range() &&
|
|
||||||
check_if_key_used(table,used_index,fields));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
used_key_is_modified= true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
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);
|
||||||
@ -305,6 +298,9 @@ int mysql_update(THD *thd,
|
|||||||
|
|
||||||
if (handle_duplicates == DUP_IGNORE)
|
if (handle_duplicates == DUP_IGNORE)
|
||||||
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
|
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
|
||||||
|
|
||||||
|
if (select && select->quick && select->quick->reset())
|
||||||
|
goto err;
|
||||||
init_read_record(&info,thd,table,select,0,1);
|
init_read_record(&info,thd,table,select,0,1);
|
||||||
|
|
||||||
updated= found= 0;
|
updated= found= 0;
|
||||||
@ -792,26 +788,7 @@ static bool safe_update_on_fly(JOIN_TAB *join_tab, List<Item> *fields)
|
|||||||
case JT_ALL:
|
case JT_ALL:
|
||||||
/* If range search on index */
|
/* If range search on index */
|
||||||
if (join_tab->quick)
|
if (join_tab->quick)
|
||||||
{
|
return !join_tab->quick->check_if_keys_used(fields);
|
||||||
if (join_tab->quick->get_type() != QUICK_SELECT_I::QS_TYPE_INDEX_MERGE)
|
|
||||||
{
|
|
||||||
return !check_if_key_used(table,join_tab->quick->index,*fields);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
QUICK_INDEX_MERGE_SELECT *qsel_imerge=
|
|
||||||
(QUICK_INDEX_MERGE_SELECT*)(join_tab->quick);
|
|
||||||
List_iterator_fast<QUICK_RANGE_SELECT> it(qsel_imerge->quick_selects);
|
|
||||||
QUICK_RANGE_SELECT *quick;
|
|
||||||
while ((quick= it++))
|
|
||||||
{
|
|
||||||
if (check_if_key_used(table, quick->index, *fields))
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If scanning in clustered key */
|
/* If scanning in clustered key */
|
||||||
if ((table->file->table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX) &&
|
if ((table->file->table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX) &&
|
||||||
table->primary_key < MAX_KEY)
|
table->primary_key < MAX_KEY)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user