Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
mariadb
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
mariadb
Commits
ee0a516c
Commit
ee0a516c
authored
Jun 14, 2004
by
sergefp@mysql.com
Browse files
Options
Browse Files
Download
Plain Diff
Manual merge
parents
078f7178
2e93dfaf
Changes
30
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
30 changed files
with
4548 additions
and
677 deletions
+4548
-677
include/my_base.h
include/my_base.h
+7
-1
include/my_bitmap.h
include/my_bitmap.h
+2
-0
include/my_sys.h
include/my_sys.h
+1
-0
innobase/include/row0mysql.h
innobase/include/row0mysql.h
+4
-0
innobase/row/row0sel.c
innobase/row/row0sel.c
+28
-3
mysql-test/r/index_merge.result
mysql-test/r/index_merge.result
+31
-31
mysql-test/r/index_merge_innodb.result
mysql-test/r/index_merge_innodb.result
+4
-4
mysql-test/r/index_merge_ror.result
mysql-test/r/index_merge_ror.result
+196
-0
mysql-test/r/index_merge_ror_cpk.result
mysql-test/r/index_merge_ror_cpk.result
+99
-0
mysql-test/r/rowid_order_bdb.result
mysql-test/r/rowid_order_bdb.result
+186
-0
mysql-test/r/rowid_order_innodb.result
mysql-test/r/rowid_order_innodb.result
+186
-0
mysql-test/t/index_merge_ror.test
mysql-test/t/index_merge_ror.test
+249
-0
mysql-test/t/index_merge_ror_cpk.test
mysql-test/t/index_merge_ror_cpk.test
+84
-0
mysql-test/t/rowid_order_bdb.test
mysql-test/t/rowid_order_bdb.test
+108
-0
mysql-test/t/rowid_order_innodb.test
mysql-test/t/rowid_order_innodb.test
+108
-0
mysys/my_bit.c
mysys/my_bit.c
+5
-0
mysys/my_bitmap.c
mysys/my_bitmap.c
+66
-0
sql/ha_berkeley.cc
sql/ha_berkeley.cc
+25
-0
sql/ha_berkeley.h
sql/ha_berkeley.h
+1
-0
sql/ha_heap.h
sql/ha_heap.h
+6
-1
sql/ha_innodb.cc
sql/ha_innodb.cc
+57
-0
sql/ha_innodb.h
sql/ha_innodb.h
+1
-0
sql/handler.h
sql/handler.h
+5
-0
sql/opt_range.cc
sql/opt_range.cc
+2762
-481
sql/opt_range.h
sql/opt_range.h
+249
-21
sql/sql_delete.cc
sql/sql_delete.cc
+5
-5
sql/sql_select.cc
sql/sql_select.cc
+60
-66
sql/sql_select.h
sql/sql_select.h
+1
-1
sql/sql_test.cc
sql/sql_test.cc
+2
-31
sql/sql_update.cc
sql/sql_update.cc
+10
-32
No files found.
include/my_base.h
View file @
ee0a516c
...
@@ -146,7 +146,13 @@ enum ha_extra_function {
...
@@ -146,7 +146,13 @@ enum ha_extra_function {
On-the-fly switching between unique and non-unique key inserting.
On-the-fly switching between unique and non-unique key inserting.
*/
*/
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() */
...
...
include/my_bitmap.h
View file @
ee0a516c
...
@@ -46,6 +46,8 @@ extern my_bool bitmap_is_set(const MY_BITMAP *map, uint bitmap_bit);
...
@@ -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
);
...
...
include/my_sys.h
View file @
ee0a516c
...
@@ -748,6 +748,7 @@ extern byte *my_compress_alloc(const byte *packet, ulong *len, ulong *complen);
...
@@ -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
);
...
...
innobase/include/row0mysql.h
View file @
ee0a516c
...
@@ -573,6 +573,10 @@ struct row_prebuilt_struct {
...
@@ -573,6 +573,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
...
...
innobase/row/row0sel.c
View file @
ee0a516c
...
@@ -2571,10 +2571,35 @@ row_sel_pop_cached_row_for_mysql(
...
@@ -2571,10 +2571,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
);
if
(
prebuilt
->
keep_other_fields_on_keyread
)
{
/* 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
);
ut_memcpy
(
buf
,
prebuilt
->
fetch_cache
[
prebuilt
->
fetch_cache_first
],
if
(
templ
->
mysql_null_bit_mask
)
prebuilt
->
mysql_row_len
);
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
++
;
...
...
mysql-test/r/index_merge.result
View file @
ee0a516c
This diff is collapsed.
Click to expand it.
mysql-test/r/index_merge_innodb.result
View file @
ee0a516c
...
@@ -8,7 +8,7 @@ INDEX i2(key2)
...
@@ -8,7 +8,7 @@ INDEX i2(key2)
) engine=innodb;
) engine=innodb;
explain select * from t1 where key1 < 5 or key2 > 197;
explain select * from t1 where key1 < 5 or key2 > 197;
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index_merge i1,i2 i1,i2 4,4 NULL 8 Using where
1 SIMPLE t1 index_merge i1,i2 i1,i2 4,4 NULL 8 Using
sort_union(i1,i2); Using
where
select * from t1 where key1 < 5 or key2 > 197;
select * from t1 where key1 < 5 or key2 > 197;
key1 key2
key1 key2
0 200
0 200
...
@@ -18,7 +18,7 @@ key1 key2
...
@@ -18,7 +18,7 @@ key1 key2
4 196
4 196
explain select * from t1 where key1 < 3 or key2 > 195;
explain select * from t1 where key1 < 3 or key2 > 195;
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index_merge i1,i2 i1,i2 4,4 NULL 8 Using where
1 SIMPLE t1 index_merge i1,i2 i1,i2 4,4 NULL 8 Using
sort_union(i1,i2); Using
where
select * from t1 where key1 < 3 or key2 > 195;
select * from t1 where key1 < 3 or key2 > 195;
key1 key2
key1 key2
0 200
0 200
...
@@ -34,7 +34,7 @@ update t1 set str1='aaa', str2='bbb', str3=concat(key2, '-', key1 div 2, '_' ,if
...
@@ -34,7 +34,7 @@ update t1 set str1='aaa', str2='bbb', str3=concat(key2, '-', key1 div 2, '_' ,if
alter table t1 add primary key (str1, zeroval, str2, str3);
alter table t1 add primary key (str1, zeroval, str2, str3);
explain select * from t1 where key1 < 5 or key2 > 197;
explain select * from t1 where key1 < 5 or key2 > 197;
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index_merge i1,i2 i1,i2 4,4 NULL 8 Using where
1 SIMPLE t1 index_merge i1,i2 i1,i2 4,4 NULL 8 Using
sort_union(i1,i2); Using
where
select * from t1 where key1 < 5 or key2 > 197;
select * from t1 where key1 < 5 or key2 > 197;
key1 key2 str1 zeroval str2 str3
key1 key2 str1 zeroval str2 str3
4 196 aaa 0 bbb 196-2_a
4 196 aaa 0 bbb 196-2_a
...
@@ -44,7 +44,7 @@ key1 key2 str1 zeroval str2 str3
...
@@ -44,7 +44,7 @@ key1 key2 str1 zeroval str2 str3
0 200 aaa 0 bbb 200-0_a
0 200 aaa 0 bbb 200-0_a
explain select * from t1 where key1 < 3 or key2 > 195;
explain select * from t1 where key1 < 3 or key2 > 195;
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index_merge i1,i2 i1,i2 4,4 NULL 8 Using where
1 SIMPLE t1 index_merge i1,i2 i1,i2 4,4 NULL 8 Using
sort_union(i1,i2); Using
where
select * from t1 where key1 < 3 or key2 > 195;
select * from t1 where key1 < 3 or key2 > 195;
key1 key2 str1 zeroval str2 str3
key1 key2 str1 zeroval str2 str3
4 196 aaa 0 bbb 196-2_a
4 196 aaa 0 bbb 196-2_a
...
...
mysql-test/r/index_merge_ror.result
0 → 100644
View file @
ee0a516c
This diff is collapsed.
Click to expand it.
mysql-test/r/index_merge_ror_cpk.result
0 → 100644
View file @
ee0a516c
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 key1,key2 4,4 NULL 1 Using intersect(key1,key2); 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 key1,PRIMARY 4,4 NULL 38 Using intersect(key1,PRIMARY); 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 key1,pktail1ok 4,4 NULL 1 Using intersect(key1,pktail1ok); 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 key1,pktail2ok 4,4 NULL 1 Using intersect(key1,pktail2ok); Using where
select ' The following is actually a deficiency, it uses sort_union currently:' as 'note:';
note:
The following is actually a deficiency, it uses sort_union currently:
explain select * from t1 where (pktail2ok=1 and pk1< 50000) or key1=10;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index_merge PRIMARY,key1,pktail2ok pktail2ok,key1 8,4 NULL 199 Using sort_union(pktail2ok,key1); 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 key1,key2 4,4 NULL 1 Using intersect(key1,key2); 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;
mysql-test/r/rowid_order_bdb.result
0 → 100644
View file @
ee0a516c
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 sort_union(key1,key2); 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;
mysql-test/r/rowid_order_innodb.result
0 → 100644
View file @
ee0a516c
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 6 Using sort_union(key1,key2); 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;
mysql-test/t/index_merge_ror.test
0 → 100644
View file @
ee0a516c
#
# ROR-index_merge tests.
#
--
disable_warnings
drop
table
if
exists
t0
,
t1
,
t2
;
--
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
;
# 'Partially' covered fields test
create
table
t2
(
a
char
(
10
),
b
char
(
10
),
filler1
char
(
255
),
filler2
char
(
255
),
key
(
a
(
5
)),
key
(
b
(
5
))
);
--
disable_query_log
let
$
1
=
8
;
while
(
$
1
)
{
eval
insert
into
t2
values
(
repeat
(
char
(
$
1
+
64
),
8
),
repeat
(
char
(
$
1
+
64
),
8
),
'filler1'
,
'filler2'
);
dec
$
1
;
}
insert
into
t2
select
*
from
t2
;
insert
into
t2
select
*
from
t2
;
--
enable_query_log
# The table row buffer is reused. Fill it with rows that don't match.
select
count
(
a
)
from
t2
where
a
=
'BBBBBBBB'
;
select
count
(
a
)
from
t2
where
b
=
'BBBBBBBB'
;
# BUG#1:
explain
select
count
(
a
)
from
t2
where
a
=
'AAAAAAAA'
and
b
=
'AAAAAAAA'
;
select
count
(
a
)
from
t2
where
a
=
'AAAAAAAA'
and
b
=
'AAAAAAAA'
;
select
count
(
a
)
from
t2
ignore
index
(
a
,
b
)
where
a
=
'AAAAAAAA'
and
b
=
'AAAAAAAA'
;
insert
into
t2
values
(
'ab'
,
'ab'
,
'uh'
,
'oh'
);
explain
select
a
from
t2
where
a
=
'ab'
;
drop
table
t2
;
mysql-test/t/index_merge_ror_cpk.test
0 → 100644
View file @
ee0a516c
#
# 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
;
select
' The following is actually a deficiency, it uses sort_union currently:'
as
'note:'
;
explain
select
*
from
t1
where
(
pktail2ok
=
1
and
pk1
<
50000
)
or
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
;
mysql-test/t/rowid_order_bdb.test
0 → 100644
View file @
ee0a516c
#
# 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
;
mysql-test/t/rowid_order_innodb.test
0 → 100644
View file @
ee0a516c
#
# 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
;
mysys/my_bit.c
View file @
ee0a516c
...
@@ -71,3 +71,8 @@ uint my_count_bits(ulonglong v)
...
@@ -71,3 +71,8 @@ uint my_count_bits(ulonglong v)
#endif
#endif
}
}
uint
my_count_bits_ushort
(
ushort
v
)
{
return
nbits
[
v
];
}
mysys/my_bitmap.c
View file @
ee0a516c
...
@@ -28,6 +28,9 @@
...
@@ -28,6 +28,9 @@
* when both arguments are bitmaps, they must be of the same size
* when both arguments are bitmaps, they must be of the same size
* bitmap_intersect() is an exception :)
* bitmap_intersect() is an exception :)
(for for Bitmap::intersect(ulonglong map2buff))
(for for Bitmap::intersect(ulonglong map2buff))
If THREAD is defined all bitmap operations except bitmap_init/bitmap_free
are thread-safe.
TODO:
TODO:
Make assembler THREAD safe versions of these using test-and-set instructions
Make assembler THREAD safe versions of these using test-and-set instructions
...
@@ -330,3 +333,66 @@ void bitmap_union(MY_BITMAP *map, const MY_BITMAP *map2)
...
@@ -330,3 +333,66 @@ void bitmap_union(MY_BITMAP *map, const MY_BITMAP *map2)
bitmap_unlock
(
map
);
bitmap_unlock
(
map
);
}
}
/*
SYNOPSIS
bitmap_bits_set()
map
RETURN
Number of set bits in the bitmap.
*/
uint
bitmap_bits_set
(
const
MY_BITMAP
*
map
)
{
uchar
*
m
=
map
->
bitmap
;
uchar
*
end
=
m
+
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
;
}
/*
SYNOPSIS
bitmap_get_first()
map
RETURN
Number of first unset bit in the bitmap 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
;
}
sql/ha_berkeley.cc
View file @
ee0a516c
...
@@ -2499,4 +2499,29 @@ ha_rows ha_berkeley::estimate_number_of_rows()
...
@@ -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 */
sql/ha_berkeley.h
View file @
ee0a516c
...
@@ -163,6 +163,7 @@ class ha_berkeley: public handler
...
@@ -163,6 +163,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
;
...
...
sql/ha_heap.h
View file @
ee0a516c
...
@@ -94,5 +94,10 @@ class ha_heap: public handler
...
@@ -94,5 +94,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
);
}
};
};
sql/ha_innodb.cc
View file @
ee0a516c
...
@@ -749,6 +749,8 @@ ha_innobase::init_table_handle_for_HANDLER(void)
...
@@ -749,6 +749,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
;
}
}
/*************************************************************************
/*************************************************************************
...
@@ -4579,9 +4581,11 @@ ha_innobase::extra(
...
@@ -4579,9 +4581,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
:
...
@@ -4600,6 +4604,9 @@ ha_innobase::extra(
...
@@ -4600,6 +4604,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 */
;
;
}
}
...
@@ -4648,6 +4655,7 @@ ha_innobase::start_stmt(
...
@@ -4648,6 +4655,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
...
@@ -4725,6 +4733,7 @@ ha_innobase::external_lock(
...
@@ -4725,6 +4733,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
)
{
...
@@ -5161,4 +5170,52 @@ ha_innobase::get_auto_increment()
...
@@ -5161,4 +5170,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 */
sql/ha_innodb.h
View file @
ee0a516c
...
@@ -184,6 +184,7 @@ class ha_innobase: public handler
...
@@ -184,6 +184,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
;
...
...
sql/handler.h
View file @
ee0a516c
...
@@ -446,6 +446,11 @@ public:
...
@@ -446,6 +446,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 */
...
...
sql/opt_range.cc
View file @
ee0a516c
This diff is collapsed.
Click to expand it.
sql/opt_range.h
View file @
ee0a516c
This diff is collapsed.
Click to expand it.
sql/sql_delete.cc
View file @
ee0a516c
...
@@ -291,10 +291,10 @@ int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds)
...
@@ -291,10 +291,10 @@ int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds)
#define MEM_STRIP_BUF_SIZE current_thd->variables.sortbuff_size
#define MEM_STRIP_BUF_SIZE current_thd->variables.sortbuff_size
extern
"C"
int
refpos
cmp2
(
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
,
...
@@ -358,8 +358,8 @@ multi_delete::initialize_tables(JOIN *join)
...
@@ -358,8 +358,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
(
refpos
cmp2
,
*
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
);
}
}
...
...
sql/sql_select.cc
View file @
ee0a516c
...
@@ -8061,8 +8061,16 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
...
@@ -8061,8 +8061,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
;
...
@@ -8123,9 +8131,11 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
...
@@ -8123,9 +8131,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
...
@@ -10105,6 +10115,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
...
@@ -10105,6 +10115,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
=
system_charset_info
;
CHARSET_INFO
*
cs
=
system_charset_info
;
int
quick_type
;
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
,
...
@@ -10196,17 +10207,20 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
...
@@ -10196,17 +10207,20 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
{
{
JOIN_TAB
*
tab
=
join
->
join_tab
+
i
;
JOIN_TAB
*
tab
=
join
->
join_tab
+
i
;
TABLE
*
table
=
tab
->
table
;
TABLE
*
table
=
tab
->
table
;
char
buff
[
512
]
,
*
buff_ptr
=
buff
;
char
buff
[
512
]
;
char
buff1
[
512
],
buff2
[
512
],
buff3
[
512
];
char
buff1
[
512
],
buff2
[
512
],
buff3
[
512
];
char
keylen_str_buf
[
64
];
char
keylen_str_buf
[
64
];
String
extra
(
buff
,
sizeof
(
buff
),
cs
);
char
table_name_buffer
[
NAME_LEN
];
char
table_name_buffer
[
NAME_LEN
];
String
tmp1
(
buff1
,
sizeof
(
buff1
),
cs
);
String
tmp1
(
buff1
,
sizeof
(
buff1
),
cs
);
String
tmp2
(
buff2
,
sizeof
(
buff2
),
cs
);
String
tmp2
(
buff2
,
sizeof
(
buff2
),
cs
);
String
tmp3
(
buff3
,
sizeof
(
buff3
),
cs
);
String
tmp3
(
buff3
,
sizeof
(
buff3
),
cs
);
extra
.
length
(
0
);
tmp1
.
length
(
0
);
tmp1
.
length
(
0
);
tmp2
.
length
(
0
);
tmp2
.
length
(
0
);
tmp3
.
length
(
0
);
tmp3
.
length
(
0
);
quick_type
=
-
1
;
item_list
.
empty
();
item_list
.
empty
();
/* id */
/* id */
item_list
.
push_back
(
new
Item_uint
((
uint32
)
item_list
.
push_back
(
new
Item_uint
((
uint32
)
...
@@ -10217,8 +10231,10 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
...
@@ -10217,8 +10231,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
;
...
@@ -10241,7 +10257,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
...
@@ -10241,7 +10257,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
;
/*
possible_keys
*/
/*
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
++
)
...
@@ -10260,7 +10276,8 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
...
@@ -10260,7 +10276,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
);
/* key key_len ref */
/* 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
;
...
@@ -10296,48 +10313,9 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
...
@@ -10296,48 +10313,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
->
add_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
...
@@ -10346,52 +10324,68 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
...
@@ -10346,52 +10324,68 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
item_list
.
push_back
(
item_null
);
item_list
.
push_back
(
item_null
);
item_list
.
push_back
(
item_null
);
item_list
.
push_back
(
item_null
);
}
}
/*
rows
*/
/*
Add "rows" field to item_list.
*/
item_list
.
push_back
(
new
Item_int
((
longlong
)
(
ulonglong
)
item_list
.
push_back
(
new
Item_int
((
longlong
)
(
ulonglong
)
join
->
best_positions
[
i
].
records_read
,
join
->
best_positions
[
i
].
records_read
,
21
));
21
));
/*
extra
*/
/*
Build "Extra" field and add it to item_list.
*/
my_bool
key_read
=
table
->
key_read
;
my_bool
key_read
=
table
->
key_read
;
if
((
tab
->
type
==
JT_NEXT
||
tab
->
type
==
JT_CONST
)
&&
if
((
tab
->
type
==
JT_NEXT
||
tab
->
type
==
JT_CONST
)
&&
table
->
used_keys
.
is_set
(
tab
->
index
))
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
));
else
else
{
{
if
(
quick_type
==
QUICK_SELECT_I
::
QS_TYPE_ROR_UNION
||
quick_type
==
QUICK_SELECT_I
::
QS_TYPE_ROR_INTERSECT
||
quick_type
==
QUICK_SELECT_I
::
QS_TYPE_INDEX_MERGE
)
{
extra
.
append
(
"; Using "
);
tab
->
select
->
quick
->
add_info_string
(
&
extra
);
}
if
(
tab
->
select
)
if
(
tab
->
select
)
{
{
if
(
tab
->
use_quick
==
2
)
if
(
tab
->
use_quick
==
2
)
{
{
char
buf
[
MAX_KEY
/
8
+
1
];
char
buf
[
MAX_KEY
/
8
+
1
];
sprintf
(
buff_ptr
,
"; Range checked for each record (index map: 0x%s)"
,
extra
.
append
(
"; Range checked for each record (index map: 0x"
);
tab
->
keys
.
print
(
buf
));
extra
.
append
(
tab
->
keys
.
print
(
buf
));
buff_ptr
=
strend
(
buff_ptr
);
extra
.
append
(
')'
);
}
}
else
else
buff_ptr
=
strmov
(
buff_ptr
,
"; Using where"
);
extra
.
append
(
"; Using where"
);
}
}
if
(
key_read
)
if
(
key_read
)
buff_ptr
=
strmov
(
buff_ptr
,
"; Using index"
);
extra
.
append
(
"; Using index"
);
if
(
table
->
reginfo
.
not_exists_optimize
)
if
(
table
->
reginfo
.
not_exists_optimize
)
buff_ptr
=
strmov
(
buff_ptr
,
"; Not exists"
);
extra
.
append
(
"; Not exists"
);
if
(
need_tmp_table
)
if
(
need_tmp_table
)
{
{
need_tmp_table
=
0
;
need_tmp_table
=
0
;
buff_ptr
=
strmov
(
buff_ptr
,
"; Using temporary"
);
extra
.
append
(
"; Using temporary"
);
}
}
if
(
need_order
)
if
(
need_order
)
{
{
need_order
=
0
;
need_order
=
0
;
buff_ptr
=
strmov
(
buff_ptr
,
"; Using filesort"
);
extra
.
append
(
"; Using filesort"
);
}
}
if
(
distinct
&
test_all_bits
(
used_tables
,
thd
->
used_tables
))
if
(
distinct
&
test_all_bits
(
used_tables
,
thd
->
used_tables
))
buff_ptr
=
strmov
(
buff_ptr
,
"; Distinct"
);
extra
.
append
(
"; Distinct"
);
if
(
buff_ptr
==
buff
)
buff_ptr
+=
2
;
// Skip inital "; "
/* Skip initial "; "*/
item_list
.
push_back
(
new
Item_string
(
buff
+
2
,(
uint
)
(
buff_ptr
-
buff
)
-
2
,
const
char
*
str
=
extra
.
ptr
();
cs
));
uint32
len
=
extra
.
length
();
if
(
len
)
{
str
+=
2
;
len
-=
2
;
}
item_list
.
push_back
(
new
Item_string
(
str
,
len
,
cs
));
}
}
// For next iteration
// For next iteration
used_tables
|=
table
->
map
;
used_tables
|=
table
->
map
;
...
...
sql/sql_select.h
View file @
ee0a516c
...
@@ -340,7 +340,7 @@ uint find_shortest_key(TABLE *table, const key_map *usable_keys);
...
@@ -340,7 +340,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
refpos
cmp2
(
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 */
...
...
sql/sql_test.cc
View file @
ee0a516c
...
@@ -182,37 +182,8 @@ TEST_join(JOIN *join)
...
@@ -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
));
...
...
sql/sql_update.cc
View file @
ee0a516c
...
@@ -156,18 +156,12 @@ int mysql_update(THD *thd,
...
@@ -156,18 +156,12 @@ 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_index
=
select
->
quick
->
index
;
{
used_key_is_modified
=
(
!
select
->
quick
->
unique_key_range
()
&&
used_index
=
select
->
quick
->
index
;
select
->
quick
->
check_if_keys_used
(
&
fields
));
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
);
...
@@ -180,7 +174,7 @@ int mysql_update(THD *thd,
...
@@ -180,7 +174,7 @@ int mysql_update(THD *thd,
matching rows before updating the table!
matching rows before updating the table!
*/
*/
table
->
file
->
extra
(
HA_EXTRA_RETRIEVE_ALL_COLS
);
table
->
file
->
extra
(
HA_EXTRA_RETRIEVE_ALL_COLS
);
if
(
old_used_keys
.
is_set
(
used_index
))
if
(
(
used_index
!=
MAX_KEY
)
&&
old_used_keys
.
is_set
(
used_index
))
{
{
table
->
key_read
=
1
;
table
->
key_read
=
1
;
table
->
file
->
extra
(
HA_EXTRA_KEYREAD
);
table
->
file
->
extra
(
HA_EXTRA_KEYREAD
);
...
@@ -226,7 +220,7 @@ int mysql_update(THD *thd,
...
@@ -226,7 +220,7 @@ int mysql_update(THD *thd,
if
(
open_cached_file
(
&
tempfile
,
mysql_tmpdir
,
TEMP_PREFIX
,
if
(
open_cached_file
(
&
tempfile
,
mysql_tmpdir
,
TEMP_PREFIX
,
DISK_BUFFER_SIZE
,
MYF
(
MY_WME
)))
DISK_BUFFER_SIZE
,
MYF
(
MY_WME
)))
goto
err
;
goto
err
;
/* If quick select is used, initialize it before retrieving rows. */
/* If quick select is used, initialize it before retrieving rows. */
if
(
select
&&
select
->
quick
&&
select
->
quick
->
reset
())
if
(
select
&&
select
->
quick
&&
select
->
quick
->
reset
())
goto
err
;
goto
err
;
...
@@ -286,6 +280,9 @@ int mysql_update(THD *thd,
...
@@ -286,6 +280,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
;
...
@@ -833,26 +830,7 @@ static bool safe_update_on_fly(JOIN_TAB *join_tab, List<Item> *fields)
...
@@ -833,26 +830,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
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment