Commit 37a8497d authored by unknown's avatar unknown

LP BUG#823169 fix.

For ANY subqueries NULLs should be ignored (if there is other values) when finding max min.
For ALL subqueries NULLs should be saved if they found.

Optimisation for ALL suqbueries if NULL is possible in the SELECT list with max/min aggregate function switched off.

Some test changed where NULL is not used but optimization with max/min aggregate function important so NOT NULL added.

mysql-test/r/explain.result:
  Forced old optimization.
mysql-test/r/subselect.result:
  Forced old optimization.
  
  New test suite.
mysql-test/t/explain.test:
  Forced old optimization.
mysql-test/t/subselect.test:
  Forced old optimization.
  
  New test suite.
sql/item_subselect.cc:
  Store converted subquery type.
  
  Switch off aggregate function optimisation for ALL and nulls.
sql/sql_class.cc:
  Fixed NULL comparison.
sql/sql_class.h:
  Store converted subquery type.
parent 31c8c95b
......@@ -171,7 +171,7 @@ DROP TABLE t1;
# Bug#48295:
# explain extended crash with subquery and ONLY_FULL_GROUP_BY sql_mode
#
CREATE TABLE t1 (f1 INT);
CREATE TABLE t1 (f1 INT not null);
SELECT @@session.sql_mode INTO @old_sql_mode;
SET SESSION sql_mode='ONLY_FULL_GROUP_BY';
EXPLAIN EXTENDED SELECT 1 FROM t1
......
......@@ -908,6 +908,131 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a`,<in_optimizer>(`test`.`t1`.`a`,<exists>(select 1 from `test`.`t2` join `test`.`t3` where ((`test`.`t3`.`a` = `test`.`t2`.`a`) and ((<cache>(`test`.`t1`.`a`) = `test`.`t2`.`a`) or isnull(`test`.`t2`.`a`))) having <is_not_null_test>(`test`.`t2`.`a`))) AS `t1.a in (select t2.a from t2,t3 where t3.a=t2.a)` from `test`.`t1`
drop table t1,t2,t3;
# check correct NULL Processing for normal IN/ALL/ANY
# and 2 ways of max/min optimization
create table t1 (a int);
insert into t1 values (1), (100), (NULL), (1000);
create table t2 (a int not null);
# subselect returns empty set (for NULL and non-NULL left part)
select a, a in (select * from t2) from t1;
a a in (select * from t2)
1 0
100 0
NULL 0
1000 0
select a, a > any (select * from t2) from t1;
a a > any (select * from t2)
1 0
100 0
NULL 0
1000 0
select a, a > all (select * from t2) from t1;
a a > all (select * from t2)
1 1
100 1
NULL 1
1000 1
select a from t1 where a in (select * from t2);
a
select a from t1 where a > any (select * from t2);
a
select a from t1 where a > all (select * from t2);
a
1
100
NULL
1000
select a from t1 where a in (select * from t2 group by a);
a
select a from t1 where a > any (select * from t2 group by a);
a
select a from t1 where a > all (select * from t2 group by a);
a
1
100
NULL
1000
insert into t2 values (1),(200);
# sebselect returns non-empty set without NULLs
select a, a in (select * from t2) from t1;
a a in (select * from t2)
1 1
100 0
NULL NULL
1000 0
select a, a > any (select * from t2) from t1;
a a > any (select * from t2)
1 0
100 1
NULL NULL
1000 1
select a, a > all (select * from t2) from t1;
a a > all (select * from t2)
1 0
100 0
NULL NULL
1000 1
select a from t1 where a in (select * from t2);
a
1
select a from t1 where a > any (select * from t2);
a
100
1000
select a from t1 where a > all (select * from t2);
a
1000
select a from t1 where a in (select * from t2 group by a);
a
1
select a from t1 where a > any (select * from t2 group by a);
a
100
1000
select a from t1 where a > all (select * from t2 group by a);
a
1000
drop table t2;
create table t2 (a int);
insert into t2 values (1),(NULL),(200);
# sebselect returns non-empty set with NULLs
select a, a in (select * from t2) from t1;
a a in (select * from t2)
1 1
100 NULL
NULL NULL
1000 NULL
select a, a > any (select * from t2) from t1;
a a > any (select * from t2)
1 NULL
100 1
NULL NULL
1000 1
select a, a > all (select * from t2) from t1;
a a > all (select * from t2)
1 0
100 0
NULL NULL
1000 NULL
select a from t1 where a in (select * from t2);
a
1
select a from t1 where a > any (select * from t2);
a
100
1000
select a from t1 where a > all (select * from t2);
a
select a from t1 where a in (select * from t2 group by a);
a
1
select a from t1 where a > any (select * from t2 group by a);
a
100
1000
select a from t1 where a > all (select * from t2 group by a);
a
drop table t1, t2;
create table t1 (a float);
select 10.5 IN (SELECT * from t1 LIMIT 1);
ERROR 42000: This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery'
......@@ -1483,7 +1608,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
Warnings:
Note 1003 select `test`.`t1`.`s1` AS `s1`,(not(<in_optimizer>(`test`.`t1`.`s1`,<exists>(<index_lookup>(<cache>(`test`.`t1`.`s1`) in t2 on s1 checking NULL where (`test`.`t2`.`s1` < 'a2') having trigcond(<is_not_null_test>(`test`.`t2`.`s1`))))))) AS `s1 NOT IN (SELECT s1 FROM t2 WHERE s1 < 'a2')` from `test`.`t1`
drop table t1,t2;
create table t2 (a int, b int);
create table t2 (a int, b int not null);
create table t3 (a int);
insert into t3 values (6),(7),(3);
select * from t3 where a >= all (select b from t2);
......@@ -4779,3 +4904,145 @@ SELECT 1 as foo FROM t1 WHERE a < SOME
);
foo
DROP TABLE t1;
CREATE TABLE t1 (a int(11), b varchar(1));
INSERT INTO t1 VALUES (2,NULL),(5,'d'),(7,'g');
SELECT a FROM t1 WHERE b < ANY ( SELECT b FROM t1 GROUP BY b );
a
5
SELECT a FROM t1 WHERE b < ANY ( SELECT b FROM t1 );
a
5
SELECT a FROM t1 WHERE b > ANY ( SELECT b FROM t1 GROUP BY b );
a
7
SELECT a FROM t1 WHERE b > ANY ( SELECT b FROM t1 );
a
7
SELECT a FROM t1 WHERE b <= ANY ( SELECT b FROM t1 GROUP BY b );
a
5
7
SELECT a FROM t1 WHERE b <= ANY ( SELECT b FROM t1 );
a
5
7
SELECT a FROM t1 WHERE b >= ANY ( SELECT b FROM t1 GROUP BY b );
a
5
7
SELECT a FROM t1 WHERE b >= ANY ( SELECT b FROM t1 );
a
5
7
SELECT a FROM t1 WHERE b = ANY ( SELECT b FROM t1 );
a
5
7
SELECT a FROM t1 WHERE b = ANY ( SELECT b FROM t1 GROUP BY b );
a
5
7
SELECT a FROM t1 WHERE b <> ANY ( SELECT b FROM t1 );
a
5
7
SELECT a FROM t1 WHERE b <> ANY ( SELECT b FROM t1 GROUP BY b );
a
5
7
SELECT a FROM t1 WHERE b < ALL ( SELECT b FROM t1 GROUP BY b );
a
SELECT a FROM t1 WHERE b < ALL ( SELECT b FROM t1 );
a
SELECT a FROM t1 WHERE b > ALL ( SELECT b FROM t1 GROUP BY b );
a
SELECT a FROM t1 WHERE b > ALL ( SELECT b FROM t1 );
a
SELECT a FROM t1 WHERE b <= ALL ( SELECT b FROM t1 GROUP BY b );
a
SELECT a FROM t1 WHERE b <= ALL ( SELECT b FROM t1 );
a
SELECT a FROM t1 WHERE b >= ALL ( SELECT b FROM t1 GROUP BY b );
a
SELECT a FROM t1 WHERE b >= ALL ( SELECT b FROM t1 );
a
SELECT a FROM t1 WHERE b = ALL ( SELECT b FROM t1 );
a
SELECT a FROM t1 WHERE b = ALL ( SELECT b FROM t1 GROUP BY b );
a
SELECT a FROM t1 WHERE b <> ALL ( SELECT b FROM t1 );
a
SELECT a FROM t1 WHERE b <> ALL ( SELECT b FROM t1 GROUP BY b );
a
delete from t1;
INSERT INTO t1 VALUES (2,NULL),(5,'d'),(7,'g');
SELECT a FROM t1 WHERE b < ANY ( SELECT b FROM t1 GROUP BY b );
a
5
SELECT a FROM t1 WHERE b < ANY ( SELECT b FROM t1 );
a
5
SELECT a FROM t1 WHERE b > ANY ( SELECT b FROM t1 GROUP BY b );
a
7
SELECT a FROM t1 WHERE b > ANY ( SELECT b FROM t1 );
a
7
SELECT a FROM t1 WHERE b <= ANY ( SELECT b FROM t1 GROUP BY b );
a
5
7
SELECT a FROM t1 WHERE b <= ANY ( SELECT b FROM t1 );
a
5
7
SELECT a FROM t1 WHERE b >= ANY ( SELECT b FROM t1 GROUP BY b );
a
5
7
SELECT a FROM t1 WHERE b >= ANY ( SELECT b FROM t1 );
a
5
7
SELECT a FROM t1 WHERE b = ANY ( SELECT b FROM t1 );
a
5
7
SELECT a FROM t1 WHERE b = ANY ( SELECT b FROM t1 GROUP BY b );
a
5
7
SELECT a FROM t1 WHERE b <> ANY ( SELECT b FROM t1 );
a
5
7
SELECT a FROM t1 WHERE b <> ANY ( SELECT b FROM t1 GROUP BY b );
a
5
7
SELECT a FROM t1 WHERE b < ALL ( SELECT b FROM t1 GROUP BY b );
a
SELECT a FROM t1 WHERE b < ALL ( SELECT b FROM t1 );
a
SELECT a FROM t1 WHERE b > ALL ( SELECT b FROM t1 GROUP BY b );
a
SELECT a FROM t1 WHERE b > ALL ( SELECT b FROM t1 );
a
SELECT a FROM t1 WHERE b <= ALL ( SELECT b FROM t1 GROUP BY b );
a
SELECT a FROM t1 WHERE b <= ALL ( SELECT b FROM t1 );
a
SELECT a FROM t1 WHERE b >= ALL ( SELECT b FROM t1 GROUP BY b );
a
SELECT a FROM t1 WHERE b >= ALL ( SELECT b FROM t1 );
a
SELECT a FROM t1 WHERE b = ALL ( SELECT b FROM t1 );
a
SELECT a FROM t1 WHERE b = ALL ( SELECT b FROM t1 GROUP BY b );
a
SELECT a FROM t1 WHERE b <> ALL ( SELECT b FROM t1 );
a
SELECT a FROM t1 WHERE b <> ALL ( SELECT b FROM t1 GROUP BY b );
a
drop table t1;
End of 5.2 tests
......@@ -152,7 +152,7 @@ DROP TABLE t1;
--echo # explain extended crash with subquery and ONLY_FULL_GROUP_BY sql_mode
--echo #
CREATE TABLE t1 (f1 INT);
CREATE TABLE t1 (f1 INT not null);
SELECT @@session.sql_mode INTO @old_sql_mode;
SET SESSION sql_mode='ONLY_FULL_GROUP_BY';
......
......@@ -488,6 +488,54 @@ SELECT t1.a, t1.a in (select t2.a from t2,t3 where t3.a=t2.a) FROM t1;
explain extended SELECT t1.a, t1.a in (select t2.a from t2,t3 where t3.a=t2.a) FROM t1;
drop table t1,t2,t3;
--echo # check correct NULL Processing for normal IN/ALL/ANY
--echo # and 2 ways of max/min optimization
create table t1 (a int);
insert into t1 values (1), (100), (NULL), (1000);
create table t2 (a int not null);
--echo # subselect returns empty set (for NULL and non-NULL left part)
select a, a in (select * from t2) from t1;
select a, a > any (select * from t2) from t1;
select a, a > all (select * from t2) from t1;
select a from t1 where a in (select * from t2);
select a from t1 where a > any (select * from t2);
select a from t1 where a > all (select * from t2);
select a from t1 where a in (select * from t2 group by a);
select a from t1 where a > any (select * from t2 group by a);
select a from t1 where a > all (select * from t2 group by a);
insert into t2 values (1),(200);
--echo # sebselect returns non-empty set without NULLs
select a, a in (select * from t2) from t1;
select a, a > any (select * from t2) from t1;
select a, a > all (select * from t2) from t1;
select a from t1 where a in (select * from t2);
select a from t1 where a > any (select * from t2);
select a from t1 where a > all (select * from t2);
select a from t1 where a in (select * from t2 group by a);
select a from t1 where a > any (select * from t2 group by a);
select a from t1 where a > all (select * from t2 group by a);
drop table t2;
create table t2 (a int);
insert into t2 values (1),(NULL),(200);
--echo # sebselect returns non-empty set with NULLs
select a, a in (select * from t2) from t1;
select a, a > any (select * from t2) from t1;
select a, a > all (select * from t2) from t1;
select a from t1 where a in (select * from t2);
select a from t1 where a > any (select * from t2);
select a from t1 where a > all (select * from t2);
select a from t1 where a in (select * from t2 group by a);
select a from t1 where a > any (select * from t2 group by a);
select a from t1 where a > all (select * from t2 group by a);
drop table t1, t2;
#LIMIT is not supported now
create table t1 (a float);
-- error ER_NOT_SUPPORTED_YET
......@@ -924,7 +972,7 @@ drop table t1,t2;
#
# correct ALL optimisation
#
create table t2 (a int, b int);
create table t2 (a int, b int not null);
create table t3 (a int);
insert into t3 values (6),(7),(3);
select * from t3 where a >= all (select b from t2);
......@@ -3797,3 +3845,68 @@ SELECT 1 as foo FROM t1 WHERE a < SOME
);
DROP TABLE t1;
#
# LP BUG#823169 NULLs with ALL/ANY and maxmin optimization
#
CREATE TABLE t1 (a int(11), b varchar(1));
INSERT INTO t1 VALUES (2,NULL),(5,'d'),(7,'g');
SELECT a FROM t1 WHERE b < ANY ( SELECT b FROM t1 GROUP BY b );
SELECT a FROM t1 WHERE b < ANY ( SELECT b FROM t1 );
SELECT a FROM t1 WHERE b > ANY ( SELECT b FROM t1 GROUP BY b );
SELECT a FROM t1 WHERE b > ANY ( SELECT b FROM t1 );
SELECT a FROM t1 WHERE b <= ANY ( SELECT b FROM t1 GROUP BY b );
SELECT a FROM t1 WHERE b <= ANY ( SELECT b FROM t1 );
SELECT a FROM t1 WHERE b >= ANY ( SELECT b FROM t1 GROUP BY b );
SELECT a FROM t1 WHERE b >= ANY ( SELECT b FROM t1 );
SELECT a FROM t1 WHERE b = ANY ( SELECT b FROM t1 );
SELECT a FROM t1 WHERE b = ANY ( SELECT b FROM t1 GROUP BY b );
SELECT a FROM t1 WHERE b <> ANY ( SELECT b FROM t1 );
SELECT a FROM t1 WHERE b <> ANY ( SELECT b FROM t1 GROUP BY b );
SELECT a FROM t1 WHERE b < ALL ( SELECT b FROM t1 GROUP BY b );
SELECT a FROM t1 WHERE b < ALL ( SELECT b FROM t1 );
SELECT a FROM t1 WHERE b > ALL ( SELECT b FROM t1 GROUP BY b );
SELECT a FROM t1 WHERE b > ALL ( SELECT b FROM t1 );
SELECT a FROM t1 WHERE b <= ALL ( SELECT b FROM t1 GROUP BY b );
SELECT a FROM t1 WHERE b <= ALL ( SELECT b FROM t1 );
SELECT a FROM t1 WHERE b >= ALL ( SELECT b FROM t1 GROUP BY b );
SELECT a FROM t1 WHERE b >= ALL ( SELECT b FROM t1 );
SELECT a FROM t1 WHERE b = ALL ( SELECT b FROM t1 );
SELECT a FROM t1 WHERE b = ALL ( SELECT b FROM t1 GROUP BY b );
SELECT a FROM t1 WHERE b <> ALL ( SELECT b FROM t1 );
SELECT a FROM t1 WHERE b <> ALL ( SELECT b FROM t1 GROUP BY b );
delete from t1;
INSERT INTO t1 VALUES (2,NULL),(5,'d'),(7,'g');
SELECT a FROM t1 WHERE b < ANY ( SELECT b FROM t1 GROUP BY b );
SELECT a FROM t1 WHERE b < ANY ( SELECT b FROM t1 );
SELECT a FROM t1 WHERE b > ANY ( SELECT b FROM t1 GROUP BY b );
SELECT a FROM t1 WHERE b > ANY ( SELECT b FROM t1 );
SELECT a FROM t1 WHERE b <= ANY ( SELECT b FROM t1 GROUP BY b );
SELECT a FROM t1 WHERE b <= ANY ( SELECT b FROM t1 );
SELECT a FROM t1 WHERE b >= ANY ( SELECT b FROM t1 GROUP BY b );
SELECT a FROM t1 WHERE b >= ANY ( SELECT b FROM t1 );
SELECT a FROM t1 WHERE b = ANY ( SELECT b FROM t1 );
SELECT a FROM t1 WHERE b = ANY ( SELECT b FROM t1 GROUP BY b );
SELECT a FROM t1 WHERE b <> ANY ( SELECT b FROM t1 );
SELECT a FROM t1 WHERE b <> ANY ( SELECT b FROM t1 GROUP BY b );
SELECT a FROM t1 WHERE b < ALL ( SELECT b FROM t1 GROUP BY b );
SELECT a FROM t1 WHERE b < ALL ( SELECT b FROM t1 );
SELECT a FROM t1 WHERE b > ALL ( SELECT b FROM t1 GROUP BY b );
SELECT a FROM t1 WHERE b > ALL ( SELECT b FROM t1 );
SELECT a FROM t1 WHERE b <= ALL ( SELECT b FROM t1 GROUP BY b );
SELECT a FROM t1 WHERE b <= ALL ( SELECT b FROM t1 );
SELECT a FROM t1 WHERE b >= ALL ( SELECT b FROM t1 GROUP BY b );
SELECT a FROM t1 WHERE b >= ALL ( SELECT b FROM t1 );
SELECT a FROM t1 WHERE b = ALL ( SELECT b FROM t1 );
SELECT a FROM t1 WHERE b = ALL ( SELECT b FROM t1 GROUP BY b );
SELECT a FROM t1 WHERE b <> ALL ( SELECT b FROM t1 );
SELECT a FROM t1 WHERE b <> ALL ( SELECT b FROM t1 GROUP BY b );
drop table t1;
--echo End of 5.2 tests
......@@ -390,7 +390,10 @@ Item_maxmin_subselect::Item_maxmin_subselect(THD *thd_param,
{
DBUG_ENTER("Item_maxmin_subselect::Item_maxmin_subselect");
max= max_arg;
init(select_lex, new select_max_min_finder_subselect(this, max_arg));
init(select_lex,
new select_max_min_finder_subselect(this, max_arg,
parent->substype() ==
Item_subselect::ALL_SUBS));
max_columns= 1;
maybe_null= 1;
max_columns= 1;
......@@ -1008,11 +1011,20 @@ Item_in_subselect::single_value_transformer(JOIN *join,
}
Item *subs;
if (!select_lex->group_list.elements &&
!select_lex->having &&
!select_lex->with_sum_func &&
!(select_lex->next_select()) &&
select_lex->table_list.elements)
/*
Check if optimization with aggregate min/max possible
1 There is no aggregate in the subquery
2 It is not UNION
3 There is tables
4 It is not ALL subquery with possible NULLs in the SELECT list
*/
if (!select_lex->group_list.elements && /*1*/
!select_lex->having && /*1*/
!select_lex->with_sum_func && /*1*/
!(select_lex->next_select()) && /*2*/
select_lex->table_list.elements && /*3*/
(!select_lex->ref_pointer_array[0]->maybe_null || /*4*/
substype() != Item_subselect::ALL_SUBS)) /*4*/
{
Item_sum_hybrid *item;
nesting_map save_allow_sum_func;
......
......@@ -2580,26 +2580,32 @@ bool select_max_min_finder_subselect::cmp_real()
{
Item *maxmin= ((Item_singlerow_subselect *)item)->element_index(0);
double val1= cache->val_real(), val2= maxmin->val_real();
/* Ignore NULLs for ANY and keep them for ALL subqueries */
if (cache->null_value)
return (is_all && !maxmin->null_value) || (!is_all && maxmin->null_value);
if (maxmin->null_value)
return !is_all;
if (fmax)
return (cache->null_value && !maxmin->null_value) ||
(!cache->null_value && !maxmin->null_value &&
val1 > val2);
return (maxmin->null_value && !cache->null_value) ||
(!cache->null_value && !maxmin->null_value &&
val1 < val2);
return(val1 > val2);
return (val1 < val2);
}
bool select_max_min_finder_subselect::cmp_int()
{
Item *maxmin= ((Item_singlerow_subselect *)item)->element_index(0);
longlong val1= cache->val_int(), val2= maxmin->val_int();
/* Ignore NULLs for ANY and keep them for ALL subqueries */
if (cache->null_value)
return (is_all && !maxmin->null_value) || (!is_all && maxmin->null_value);
if (maxmin->null_value)
return !is_all;
if (fmax)
return (cache->null_value && !maxmin->null_value) ||
(!cache->null_value && !maxmin->null_value &&
val1 > val2);
return (maxmin->null_value && !cache->null_value) ||
(!cache->null_value && !maxmin->null_value &&
val1 < val2);
return(val1 > val2);
return (val1 < val2);
}
bool select_max_min_finder_subselect::cmp_decimal()
......@@ -2607,13 +2613,16 @@ bool select_max_min_finder_subselect::cmp_decimal()
Item *maxmin= ((Item_singlerow_subselect *)item)->element_index(0);
my_decimal cval, *cvalue= cache->val_decimal(&cval);
my_decimal mval, *mvalue= maxmin->val_decimal(&mval);
/* Ignore NULLs for ANY and keep them for ALL subqueries */
if (cache->null_value)
return (is_all && !maxmin->null_value) || (!is_all && maxmin->null_value);
if (maxmin->null_value)
return !is_all;
if (fmax)
return (cache->null_value && !maxmin->null_value) ||
(!cache->null_value && !maxmin->null_value &&
my_decimal_cmp(cvalue, mvalue) > 0) ;
return (maxmin->null_value && !cache->null_value) ||
(!cache->null_value && !maxmin->null_value &&
my_decimal_cmp(cvalue,mvalue) < 0);
return (my_decimal_cmp(cvalue, mvalue) > 0) ;
return (my_decimal_cmp(cvalue,mvalue) < 0);
}
bool select_max_min_finder_subselect::cmp_str()
......@@ -2626,13 +2635,16 @@ bool select_max_min_finder_subselect::cmp_str()
*/
val1= cache->val_str(&buf1);
val2= maxmin->val_str(&buf1);
/* Ignore NULLs for ANY and keep them for ALL subqueries */
if (cache->null_value)
return (is_all && !maxmin->null_value) || (!is_all && maxmin->null_value);
if (maxmin->null_value)
return !is_all;
if (fmax)
return (cache->null_value && !maxmin->null_value) ||
(!cache->null_value && !maxmin->null_value &&
sortcmp(val1, val2, cache->collation.collation) > 0) ;
return (maxmin->null_value && !cache->null_value) ||
(!cache->null_value && !maxmin->null_value &&
sortcmp(val1, val2, cache->collation.collation) < 0);
return (sortcmp(val1, val2, cache->collation.collation) > 0) ;
return (sortcmp(val1, val2, cache->collation.collation) < 0);
}
int select_exists_subselect::send_data(List<Item> &items)
......
......@@ -2931,9 +2931,11 @@ class select_max_min_finder_subselect :public select_subselect
Item_cache *cache;
bool (select_max_min_finder_subselect::*op)();
bool fmax;
bool is_all;
public:
select_max_min_finder_subselect(Item_subselect *item_arg, bool mx)
:select_subselect(item_arg), cache(0), fmax(mx)
select_max_min_finder_subselect(Item_subselect *item_arg, bool mx,
bool all)
:select_subselect(item_arg), cache(0), fmax(mx), is_all(all)
{}
void cleanup();
int send_data(List<Item> &items);
......
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