Commit 30b28bab authored by Sergey Petrunya's avatar Sergey Petrunya

Merge 5.3->5.5

parents b2d71434 a8341dfd
This diff is collapsed.
......@@ -109,3 +109,12 @@
select * from t1, t2 where t1.a=t2.a and t2.b + t1.b > 100;
a b c filler a b
set optimizer_switch='index_condition_pushdown=on';
@@ -170,7 +170,7 @@
select * from t2 straight_join t1 force index(kp1) where t1.kp1=t2.a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 10
-1 SIMPLE t1 ref kp1 kp1 32 test.t2.a 1 Using join buffer (flat, BKAH join); Key-ordered Rowid-ordered scan
+1 SIMPLE t1 ref kp1 kp1 32 test.t2.a 1
select * from t2 straight_join t1 force index(kp1) where t1.kp1=t2.a;
a pk kp1 col1
kp1-1000 pk-1000 kp1-1000 val-1000
......@@ -145,11 +145,47 @@ select * from t1, t2 where t1.a=t2.a and t2.b + t1.b > 100;
a b c filler a b
set optimizer_switch='index_condition_pushdown=on';
drop table t1,t2;
set @@join_cache_level= @save_join_cache_level;
set storage_engine=@save_storage_engine;
set optimizer_switch=@innodb_mrr_cpk_tmp;
drop table t0;
#
# MDEV-6878: Use of uninitialized saved_primary_key in Mrr_ordered_index_reader::resume_read()
#
create table t0(a int);
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table t1 (
pk varchar(32) character set utf8 primary key,
kp1 char(32) not null,
col1 varchar(32),
key (kp1)
) engine=innodb;
insert into t1
select
concat('pk-', 1000 +A.a),
concat('kp1-', 1000 +A.a),
concat('val-', 1000 +A.a)
from test.t0 A ;
create table t2 as select kp1 as a from t1;
set join_cache_level=8;
set optimizer_switch='mrr=on,mrr_sort_keys=on';
explain
select * from t2 straight_join t1 force index(kp1) where t1.kp1=t2.a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 10
1 SIMPLE t1 ref kp1 kp1 32 test.t2.a 1 Using join buffer (flat, BKAH join); Key-ordered Rowid-ordered scan
select * from t2 straight_join t1 force index(kp1) where t1.kp1=t2.a;
a pk kp1 col1
kp1-1000 pk-1000 kp1-1000 val-1000
kp1-1001 pk-1001 kp1-1001 val-1001
kp1-1002 pk-1002 kp1-1002 val-1002
kp1-1003 pk-1003 kp1-1003 val-1003
kp1-1004 pk-1004 kp1-1004 val-1004
kp1-1005 pk-1005 kp1-1005 val-1005
kp1-1006 pk-1006 kp1-1006 val-1006
kp1-1007 pk-1007 kp1-1007 val-1007
kp1-1008 pk-1008 kp1-1008 val-1008
kp1-1009 pk-1009 kp1-1009 val-1009
drop table t0,t1,t2;
#
#
# MDEV-3817: Wrong result with index_merge+index_merge_intersection, InnoDB table, join, AND and OR conditions
#
set @tmp_mdev3817=@@optimizer_switch;
......@@ -194,3 +230,9 @@ id select_type table type possible_keys key key_len ref rows Extra
2 DERIVED t2 ALL NULL NULL NULL NULL #
set join_cache_level= @tmp_mdev5037;
drop table t0,t1,t2;
#
# This must be at the end:
#
set @@join_cache_level= @save_join_cache_level;
set storage_engine=@save_storage_engine;
set optimizer_switch=@innodb_mrr_cpk_tmp;
......@@ -498,8 +498,8 @@ CountryLanguage.Percentage > 50 AND
LENGTH(Language) < LENGTH(City.Name) - 2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE Country ALL NULL NULL NULL NULL 239 Using where
1 SIMPLE City ALL NULL NULL NULL NULL 4079 Using where; Using join buffer (flat, BNL join)
1 SIMPLE CountryLanguage ALL NULL NULL NULL NULL 984 Using where; Using join buffer (flat, BNL join)
1 SIMPLE City ALL NULL NULL NULL NULL 4079 Using where; Using join buffer (flat, BNL join)
SELECT City.Name, Country.Name, CountryLanguage.Language
FROM City,Country,CountryLanguage
WHERE City.Country=Country.Code AND
......@@ -576,8 +576,8 @@ CountryLanguage.Percentage > 50 AND
LENGTH(Language) < LENGTH(City.Name) - 2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE Country ALL NULL NULL NULL NULL 239 Using where
1 SIMPLE City ALL NULL NULL NULL NULL 4079 Using where; Using join buffer (flat, BNL join)
1 SIMPLE CountryLanguage ALL NULL NULL NULL NULL 984 Using where; Using join buffer (incremental, BNL join)
1 SIMPLE CountryLanguage ALL NULL NULL NULL NULL 984 Using where; Using join buffer (flat, BNL join)
1 SIMPLE City ALL NULL NULL NULL NULL 4079 Using where; Using join buffer (incremental, BNL join)
SELECT City.Name, Country.Name, CountryLanguage.Language
FROM City,Country,CountryLanguage
WHERE City.Country=Country.Code AND
......@@ -654,8 +654,8 @@ CountryLanguage.Percentage > 50 AND
LENGTH(Language) < LENGTH(City.Name) - 2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE Country ALL NULL NULL NULL NULL 239 Using where
1 SIMPLE City hash_ALL NULL #hash#$hj 3 world.Country.Code 4079 Using where; Using join buffer (flat, BNLH join)
1 SIMPLE CountryLanguage hash_ALL NULL #hash#$hj 3 world.Country.Code 984 Using where; Using join buffer (flat, BNLH join)
1 SIMPLE City hash_ALL NULL #hash#$hj 3 world.Country.Code 4079 Using where; Using join buffer (flat, BNLH join)
SELECT City.Name, Country.Name, CountryLanguage.Language
FROM City,Country,CountryLanguage
WHERE City.Country=Country.Code AND
......@@ -732,8 +732,8 @@ CountryLanguage.Percentage > 50 AND
LENGTH(Language) < LENGTH(City.Name) - 2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE Country ALL NULL NULL NULL NULL 239 Using where
1 SIMPLE City hash_ALL NULL #hash#$hj 3 world.Country.Code 4079 Using where; Using join buffer (flat, BNLH join)
1 SIMPLE CountryLanguage hash_ALL NULL #hash#$hj 3 world.Country.Code 984 Using where; Using join buffer (incremental, BNLH join)
1 SIMPLE CountryLanguage hash_ALL NULL #hash#$hj 3 world.Country.Code 984 Using where; Using join buffer (flat, BNLH join)
1 SIMPLE City hash_ALL NULL #hash#$hj 3 world.Country.Code 4079 Using where; Using join buffer (incremental, BNLH join)
SELECT City.Name, Country.Name, CountryLanguage.Language
FROM City,Country,CountryLanguage
WHERE City.Country=Country.Code AND
......
......@@ -2222,4 +2222,27 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
Warnings:
Note 1003 select `test`.`t1`.`i1` AS `i1`,`test`.`t2`.`i2` AS `i2`,`test`.`t3`.`i3` AS `i3`,`test`.`t3`.`d3` AS `d3` from `test`.`t1` left join (`test`.`t2` join `test`.`t3`) on(((`test`.`t2`.`i2` = `test`.`t1`.`i1`) and (`test`.`t3`.`i3` = `test`.`t1`.`i1`))) where ((`test`.`t3`.`d3` = 0) or isnull(`test`.`t3`.`d3`))
DROP TABLE t1,t2,t3;
#
# Bug mdev-6705: wrong on expression after constant row substitution
# that triggers a simplification of WHERE condition
#
CREATE TABLE t1 (a int, b int) ENGINE=MyISAM;
INSERT INTO t1 VALUES (10,8);
CREATE TABLE t2 (c int) ENGINE=MyISAM;
INSERT INTO t2 VALUES (8),(9);
CREATE TABLE t3 (d int) ENGINE=MyISAM;
INSERT INTO t3 VALUES (3),(8);
EXPLAIN EXTENDED
SELECT * FROM t1 INNER JOIN t2 ON c = b LEFT JOIN t3 ON d = a
WHERE b IN (1,2,3) OR b = d;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 system NULL NULL NULL NULL 1 100.00
1 SIMPLE t2 ALL NULL NULL NULL NULL 2 100.00 Using where
1 SIMPLE t3 ALL NULL NULL NULL NULL 2 100.00 Using where
Warnings:
Note 1003 select 10 AS `a`,8 AS `b`,`test`.`t2`.`c` AS `c`,`test`.`t3`.`d` AS `d` from `test`.`t2` left join `test`.`t3` on((`test`.`t3`.`d` = 10)) where ((`test`.`t2`.`c` = 8) and (`test`.`t3`.`d` = 8))
SELECT * FROM t1 INNER JOIN t2 ON c = b LEFT JOIN t3 ON d = a
WHERE b IN (1,2,3) OR b = d;
a b c d
DROP TABLE t1,t2,t3;
SET optimizer_switch=@save_optimizer_switch;
......@@ -2233,6 +2233,29 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
Warnings:
Note 1003 select `test`.`t1`.`i1` AS `i1`,`test`.`t2`.`i2` AS `i2`,`test`.`t3`.`i3` AS `i3`,`test`.`t3`.`d3` AS `d3` from `test`.`t1` left join (`test`.`t2` join `test`.`t3`) on(((`test`.`t2`.`i2` = `test`.`t1`.`i1`) and (`test`.`t3`.`i3` = `test`.`t1`.`i1`))) where ((`test`.`t3`.`d3` = 0) or isnull(`test`.`t3`.`d3`))
DROP TABLE t1,t2,t3;
#
# Bug mdev-6705: wrong on expression after constant row substitution
# that triggers a simplification of WHERE condition
#
CREATE TABLE t1 (a int, b int) ENGINE=MyISAM;
INSERT INTO t1 VALUES (10,8);
CREATE TABLE t2 (c int) ENGINE=MyISAM;
INSERT INTO t2 VALUES (8),(9);
CREATE TABLE t3 (d int) ENGINE=MyISAM;
INSERT INTO t3 VALUES (3),(8);
EXPLAIN EXTENDED
SELECT * FROM t1 INNER JOIN t2 ON c = b LEFT JOIN t3 ON d = a
WHERE b IN (1,2,3) OR b = d;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 system NULL NULL NULL NULL 1 100.00
1 SIMPLE t2 ALL NULL NULL NULL NULL 2 100.00 Using where
1 SIMPLE t3 ALL NULL NULL NULL NULL 2 100.00 Using where; Using join buffer (flat, BNL join)
Warnings:
Note 1003 select 10 AS `a`,8 AS `b`,`test`.`t2`.`c` AS `c`,`test`.`t3`.`d` AS `d` from `test`.`t1` join `test`.`t2` left join `test`.`t3` on((`test`.`t3`.`d` = 10)) where ((`test`.`t2`.`c` = 8) and (`test`.`t3`.`d` = 8))
SELECT * FROM t1 INNER JOIN t2 ON c = b LEFT JOIN t3 ON d = a
WHERE b IN (1,2,3) OR b = d;
a b c d
DROP TABLE t1,t2,t3;
SET optimizer_switch=@save_optimizer_switch;
set join_cache_level=default;
show variables like 'join_cache_level';
......
# Initialize
--disable_warnings
drop table if exists t1,t2,t3;
drop table if exists t0,t1,t2,t3;
drop database if exists test1;
--enable_warnings
set @exit_optimizer_switch=@@optimizer_switch;
......@@ -272,5 +273,95 @@ limit 10;
drop table t1, t2, t3, t4;
--echo #
--echo # MDEV-6888: Query spends a long time in best_extension_by_limited_search with mrr enabled
--echo #
create database test1;
use test1;
set @tmp_jcl= @@join_cache_level;
set @tmp_os= @@optimizer_switch;
set join_cache_level=8;
set optimizer_switch='mrr=on,mrr_sort_keys=on';
CREATE TABLE t0 (
f1 bigint(20) DEFAULT NULL,
f2 char(50) DEFAULT NULL
) ENGINE=MEMORY DEFAULT CHARSET=latin1;
INSERT INTO t0 VALUES (NULL,'numeric column is NULL'),(0,NULL),(5,'five'),(1,'one'),(2,'two');
CREATE TABLE t1 (
f1 decimal(64,30) DEFAULT NULL,
f2 varchar(50) DEFAULT NULL
) ENGINE=MEMORY DEFAULT CHARSET=latin1;
INSERT INTO t1 VALUES
(NULL,'numeric column is NULL'),
(0.000000000000000000000000000000,NULL),
(5.000000000000000000000000000000,'five'),
(1.000000000000000000000000000000,'one'),
(3.000000000000000000000000000000,'three');
CREATE TABLE t2 (
f1 double DEFAULT NULL,
f2 varbinary(50) DEFAULT NULL
) ENGINE=MEMORY DEFAULT CHARSET=latin1;
INSERT INTO t2 VALUES (NULL,'numeric column is NULL'),(0,NULL),(5,'five'),(2,'two'),(3,'three');
create VIEW v0 AS select f1,f2 from t1 ;
let $cnt= 27;
while ($cnt)
{
# i runs from 1 to 27
let $i= `select 28 - $cnt`;
let $prev=`select $i - 1`;
# rem = i mod 3
let $rem= `select MOD($i, 3)`;
# view uses $i, $prev and $rem:
eval create VIEW v$i AS select tab1_v$i.f1,tab1_v$i.f2 from t$rem tab1_v$i join v$prev tab2 on tab1_v$i.f1 = tab2.f1 and tab1_v$i.f2 = tab2.f2;
dec $cnt;
}
EXPLAIN SELECT CAST(f1 AS SIGNED INTEGER) AS f1, CAST(f2 AS CHAR) AS f2 FROM v27;
--echo # This used to hang forever:
EXPLAIN SELECT CAST(f1 AS SIGNED INTEGER) AS f1, CAST(f2 AS CHAR) AS f2 FROM v27;
use test;
drop database test1;
set join_cache_level=@tmp_jcl;
set optimizer_switch=@tmp_os;
--echo #
--echo # MDEV-6879: Dereference of NULL primary_file->table in DsMrr_impl::get_disk_sweep_mrr_cost()
--echo #
create table t1(a int);
insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table t2 (a int, b int, c text);
insert into t2
select
A.a + B.a* 10,
A.a + B.a* 10,
'blob-data'
from t1 A, t1 B;
set @tmp_jcl= @@join_cache_level;
set @tmp_os= @@optimizer_switch;
set join_cache_level=6;
set @@optimizer_switch='derived_merge=on,derived_with_keys=on,mrr=on';
explain
select * from
t1 join
(select * from t2 order by a limit 1000) as D1
where
D1.a= t1.a;
set join_cache_level=@tmp_jcl;
set optimizer_switch=@tmp_os;
drop table t1, t2;
# The following command must be the last one the file
set optimizer_switch=@exit_optimizer_switch;
......@@ -134,11 +134,39 @@ set optimizer_switch='index_condition_pushdown=on';
drop table t1,t2;
set @@join_cache_level= @save_join_cache_level;
set storage_engine=@save_storage_engine;
set optimizer_switch=@innodb_mrr_cpk_tmp;
drop table t0;
--echo #
--echo # MDEV-6878: Use of uninitialized saved_primary_key in Mrr_ordered_index_reader::resume_read()
--echo #
create table t0(a int);
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table t1 (
pk varchar(32) character set utf8 primary key,
kp1 char(32) not null,
col1 varchar(32),
key (kp1)
) engine=innodb;
insert into t1
select
concat('pk-', 1000 +A.a),
concat('kp1-', 1000 +A.a),
concat('val-', 1000 +A.a)
from test.t0 A ;
create table t2 as select kp1 as a from t1;
set join_cache_level=8;
set optimizer_switch='mrr=on,mrr_sort_keys=on';
explain
select * from t2 straight_join t1 force index(kp1) where t1.kp1=t2.a;
select * from t2 straight_join t1 force index(kp1) where t1.kp1=t2.a;
drop table t0,t1,t2;
--echo #
--echo #
--echo # MDEV-3817: Wrong result with index_merge+index_merge_intersection, InnoDB table, join, AND and OR conditions
--echo #
......@@ -190,5 +218,13 @@ set join_cache_level=3;
explain SELECT 1 FROM (SELECT url, id FROM t2 LIMIT 1 OFFSET 20) derived RIGHT JOIN t1 ON t1.id = derived.id;
set join_cache_level= @tmp_mdev5037;
drop table t0,t1,t2;
--echo #
--echo # This must be at the end:
--echo #
set @@join_cache_level= @save_join_cache_level;
set storage_engine=@save_storage_engine;
set optimizer_switch=@innodb_mrr_cpk_tmp;
......@@ -1777,4 +1777,28 @@ SELECT * FROM t1 LEFT JOIN t2 LEFT JOIN t3 ON i2 = i3 ON i1 = i3
DROP TABLE t1,t2,t3;
--echo #
--echo # Bug mdev-6705: wrong on expression after constant row substitution
--echo # that triggers a simplification of WHERE condition
--echo #
CREATE TABLE t1 (a int, b int) ENGINE=MyISAM;
INSERT INTO t1 VALUES (10,8);
CREATE TABLE t2 (c int) ENGINE=MyISAM;
INSERT INTO t2 VALUES (8),(9);
CREATE TABLE t3 (d int) ENGINE=MyISAM;
INSERT INTO t3 VALUES (3),(8);
EXPLAIN EXTENDED
SELECT * FROM t1 INNER JOIN t2 ON c = b LEFT JOIN t3 ON d = a
WHERE b IN (1,2,3) OR b = d;
SELECT * FROM t1 INNER JOIN t2 ON c = b LEFT JOIN t3 ON d = a
WHERE b IN (1,2,3) OR b = d;
DROP TABLE t1,t2,t3;
SET optimizer_switch=@save_optimizer_switch;
......@@ -426,6 +426,7 @@ bool Mrr_ordered_index_reader::set_interruption_temp_buffer(uint rowid_length,
*space_start += key_len;
have_saved_rowid= FALSE;
read_was_interrupted= FALSE;
return FALSE;
}
......@@ -434,6 +435,7 @@ void Mrr_ordered_index_reader::set_no_interruption_temp_buffer()
support_scan_interruptions= FALSE;
saved_key_tuple= saved_rowid= saved_primary_key= NULL; /* safety */
have_saved_rowid= FALSE;
read_was_interrupted= FALSE;
}
void Mrr_ordered_index_reader::interrupt_read()
......@@ -451,6 +453,7 @@ void Mrr_ordered_index_reader::interrupt_read()
&table->key_info[table->s->primary_key],
table->key_info[table->s->primary_key].key_length);
}
read_was_interrupted= TRUE;
/* Save the last rowid */
memcpy(saved_rowid, file->ref, file->ref_length);
......@@ -468,6 +471,10 @@ void Mrr_ordered_index_reader::position()
void Mrr_ordered_index_reader::resume_read()
{
TABLE *table= file->get_table();
if (!read_was_interrupted)
return;
KEY *used_index= &table->key_info[file->active_index];
key_restore(table->record[0], saved_key_tuple,
used_index, used_index->key_length);
......@@ -557,8 +564,7 @@ int Mrr_ordered_index_reader::init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
is_mrr_assoc= !test(mode & HA_MRR_NO_ASSOCIATION);
mrr_funcs= *seq_funcs;
source_exhausted= FALSE;
if (support_scan_interruptions)
bzero(saved_key_tuple, key_info->key_length);
read_was_interrupted= false;
have_saved_rowid= FALSE;
return 0;
}
......
......@@ -340,6 +340,12 @@ private:
uchar *saved_key_tuple; /* Saved current key tuple */
uchar *saved_primary_key; /* Saved current primary key tuple */
/*
TRUE<=> saved_key_tuple (and saved_primary_key when applicable) have
valid values.
*/
bool read_was_interrupted;
static int compare_keys(void* arg, uchar* key1, uchar* key2);
static int compare_keys_reverse(void* arg, uchar* key1, uchar* key2);
......
......@@ -3618,6 +3618,7 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
join->impossible_where= false;
if (conds && const_count)
{
COND_EQUAL *orig_cond_equal = join->cond_equal;
conds->update_used_tables();
conds= remove_eq_conds(join->thd, conds, &join->cond_value);
if (conds && conds->type() == Item::COND_ITEM &&
......@@ -3645,6 +3646,20 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
join->cond_equal->current_level.push_back((Item_equal*) conds);
}
}
if (orig_cond_equal != join->cond_equal)
{
/*
If join->cond_equal has changed all references to it from COND_EQUAL
objects associated with ON expressions must be updated.
*/
for (JOIN_TAB **pos=stat_vector+const_count ; (s= *pos) ; pos++)
{
if (*s->on_expr_ref && s->cond_equal &&
s->cond_equal->upper_levels == orig_cond_equal)
s->cond_equal->upper_levels= join->cond_equal;
}
}
}
/* Calc how many (possible) matched records in each table */
......@@ -9871,6 +9886,19 @@ uint check_join_cache_usage(JOIN_TAB *tab,
cache_level--;
}
/*
Don't use BKA for materialized tables. We could actually have a
meaningful use of BKA when linked join buffers are used.
The problem is, the temp.table is not filled (actually not even opened
properly) yet, and this doesn't let us call
handler->multi_range_read_info(). It is possible to come up with
estimates, etc. without acessing the table, but it seems not to worth the
effort now.
*/
if (tab->table->pos_in_table_list->is_materialized_derived())
no_bka_cache= true;
/*
Don't use join buffering if we're dictated not to by no_jbuf_after
(This is not meaningfully used currently)
......@@ -9937,7 +9965,7 @@ uint check_join_cache_usage(JOIN_TAB *tab,
if (tab->ref.is_access_triggered())
goto no_join_cache;
if (!tab->is_ref_for_hash_join())
if (!tab->is_ref_for_hash_join() && !no_bka_cache)
{
flags= HA_MRR_NO_NULL_ENDPOINTS | HA_MRR_SINGLE_POINT;
if (tab->table->covering_keys.is_set(tab->ref.key))
......@@ -12399,9 +12427,17 @@ Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels,
if (upper)
{
TABLE_LIST *native_sjm= embedding_sjm(item_equal->context_field);
if (item_const && upper->get_const())
Item *upper_const= upper->get_const();
if (item_const && upper_const)
{
/* Upper item also has "field_item=const". Don't produce equality here */
/*
Upper item also has "field_item=const".
Don't produce equality if const is equal to item_const.
*/
Item_func_eq *func= new Item_func_eq(item_const, upper_const);
func->set_cmp_func();
func->quick_fix_field();
if (func->val_int())
item= 0;
}
else
......
......@@ -5950,7 +5950,6 @@ void TABLE::create_key_part_by_field(KEY *keyinfo,
KEY_PART_INFO *key_part_info,
Field *field, uint fieldnr)
{
field->flags|= PART_KEY_FLAG;
key_part_info->null_bit= field->null_bit;
key_part_info->null_offset= (uint) (field->null_ptr -
(uchar*) record[0]);
......@@ -6104,6 +6103,7 @@ bool TABLE::add_tmp_key(uint key, uint key_parts,
(*reg_field)->key_start.set_bit(key);
(*reg_field)->part_of_key.set_bit(key);
create_key_part_by_field(keyinfo, key_part_info, *reg_field, fld_idx+1);
(*reg_field)->flags|= PART_KEY_FLAG;
key_start= FALSE;
key_part_info++;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment