Commit 3fcd84c2 authored by Alexander Barkov's avatar Alexander Barkov

MDEV-8741 Equal field propagation leaves some remainders after simplifying WH...

MDEV-8741 Equal field propagation leaves some remainders after simplifying WH ERE zerofill_column=2010 AND zerofill_column>=2010
parent 4cb6edba
...@@ -1369,7 +1369,7 @@ EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=2010 AND NULLIF(10.1,a) IS NULL; ...@@ -1369,7 +1369,7 @@ EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=2010 AND NULLIF(10.1,a) IS NULL;
id select_type table type possible_keys key key_len ref rows filtered Extra id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where
Warnings: Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where ((`test`.`t1`.`a` = 2010) and 1) Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` = 2010)
SELECT * FROM t1 WHERE a=2010 AND CASE WHEN 10.1=a THEN NULL ELSE 10.1 END IS NULL; SELECT * FROM t1 WHERE a=2010 AND CASE WHEN 10.1=a THEN NULL ELSE 10.1 END IS NULL;
a a
2010 2010
...@@ -1377,7 +1377,7 @@ EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=2010 AND CASE WHEN 10.1=a THEN NULL EL ...@@ -1377,7 +1377,7 @@ EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=2010 AND CASE WHEN 10.1=a THEN NULL EL
id select_type table type possible_keys key key_len ref rows filtered Extra id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where
Warnings: Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where ((`test`.`t1`.`a` = 2010) and 1) Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` = 2010)
DROP TABLE t1; DROP TABLE t1;
# Two warnings expected # Two warnings expected
CREATE TABLE t1 AS SELECT CREATE TABLE t1 AS SELECT
......
...@@ -625,5 +625,16 @@ Warnings: ...@@ -625,5 +625,16 @@ Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where ((`test`.`t1`.`a` = 1.10e0) and (<cache>(length(1.100)) <> rand())) Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where ((`test`.`t1`.`a` = 1.10e0) and (<cache>(length(1.100)) <> rand()))
DROP TABLE t1; DROP TABLE t1;
# #
# MDEV-8741 Equal field propagation leaves some remainders after simplifying WHERE zerofill_column=2010 AND zerofill_column>=2010
#
CREATE TABLE t1 (a DOUBLE ZEROFILL);
INSERT INTO t1 VALUES (2010),(2020);
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=2010e0 AND a>=2010e0;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` = 2010e0)
DROP TABLE t1;
#
# End of 10.1 tests # End of 10.1 tests
# #
#
# Start of 10.1 tests
#
#
# MDEV-8741 Equal field propagation leaves some remainders after simplifying WHERE zerofill_column=2010 AND zerofill_column>=2010
#
CREATE TABLE t1 (a INT ZEROFILL);
INSERT INTO t1 VALUES (2010),(2020);
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=2010 AND a>=2010;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` = 2010)
DROP TABLE t1;
#
# End of 10.1 tests
#
...@@ -2145,5 +2145,16 @@ Warnings: ...@@ -2145,5 +2145,16 @@ Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where ((`test`.`t1`.`a` = 1.10) and (<cache>(length(1.100)) <> rand())) Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where ((`test`.`t1`.`a` = 1.10) and (<cache>(length(1.100)) <> rand()))
DROP TABLE t1; DROP TABLE t1;
# #
# MDEV-8741 Equal field propagation leaves some remainders after simplifying WHERE zerofill_column=2010 AND zerofill_column>=2010
#
CREATE TABLE t1 (a DECIMAL(10,1) ZEROFILL);
INSERT INTO t1 VALUES (2010),(2020);
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=2010.0 AND a>=2010.0;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` = 2010.0)
DROP TABLE t1;
#
# End of 10.1 tests # End of 10.1 tests
# #
...@@ -394,3 +394,47 @@ select a from t1 where a=b; ...@@ -394,3 +394,47 @@ select a from t1 where a=b;
a a
drop table t1; drop table t1;
drop function y2k; drop function y2k;
#
# Start of 10.1 tests
#
#
# MDEV-8741 Equal field propagation leaves some remainders after simplifying WHERE zerofill_column=2010 AND zerofill_column>=2010
#
CREATE TABLE t1 (a YEAR);
INSERT INTO t1 VALUES (2010),(2020);
SELECT * FROM t1 WHERE a=2010 AND a>=2010;
a
2010
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=2010 AND a>=2010;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` = 2010)
SELECT * FROM t1 WHERE a=2010 AND a>=10;
a
2010
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=2010 AND a>=10;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` = 2010)
SELECT * FROM t1 WHERE a=10 AND a>=2010;
a
2010
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=10 AND a>=2010;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` = 2010)
SELECT * FROM t1 WHERE a=10 AND a>=10;
a
2010
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=10 AND a>=10;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` = 2010)
DROP TABLE t1;
#
# End of 10.1 tests
#
...@@ -446,6 +446,15 @@ SELECT * FROM t1 WHERE LENGTH(a)!=RAND() AND a=1.10e0; ...@@ -446,6 +446,15 @@ SELECT * FROM t1 WHERE LENGTH(a)!=RAND() AND a=1.10e0;
DROP TABLE t1; DROP TABLE t1;
--echo #
--echo # MDEV-8741 Equal field propagation leaves some remainders after simplifying WHERE zerofill_column=2010 AND zerofill_column>=2010
--echo #
CREATE TABLE t1 (a DOUBLE ZEROFILL);
INSERT INTO t1 VALUES (2010),(2020);
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=2010e0 AND a>=2010e0;
DROP TABLE t1;
--echo # --echo #
--echo # End of 10.1 tests --echo # End of 10.1 tests
--echo # --echo #
--echo #
--echo # Start of 10.1 tests
--echo #
--echo #
--echo # MDEV-8741 Equal field propagation leaves some remainders after simplifying WHERE zerofill_column=2010 AND zerofill_column>=2010
--echo #
CREATE TABLE t1 (a INT ZEROFILL);
INSERT INTO t1 VALUES (2010),(2020);
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=2010 AND a>=2010;
DROP TABLE t1;
--echo #
--echo # End of 10.1 tests
--echo #
...@@ -1667,6 +1667,13 @@ EXPLAIN EXTENDED ...@@ -1667,6 +1667,13 @@ EXPLAIN EXTENDED
SELECT * FROM t1 WHERE LENGTH(a)!=rand() AND a=1.10; SELECT * FROM t1 WHERE LENGTH(a)!=rand() AND a=1.10;
DROP TABLE t1; DROP TABLE t1;
--echo #
--echo # MDEV-8741 Equal field propagation leaves some remainders after simplifying WHERE zerofill_column=2010 AND zerofill_column>=2010
--echo #
CREATE TABLE t1 (a DECIMAL(10,1) ZEROFILL);
INSERT INTO t1 VALUES (2010),(2020);
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=2010.0 AND a>=2010.0;
DROP TABLE t1;
--echo # --echo #
--echo # End of 10.1 tests --echo # End of 10.1 tests
......
...@@ -188,3 +188,25 @@ drop table t1; ...@@ -188,3 +188,25 @@ drop table t1;
drop function y2k; drop function y2k;
--echo #
--echo # Start of 10.1 tests
--echo #
--echo #
--echo # MDEV-8741 Equal field propagation leaves some remainders after simplifying WHERE zerofill_column=2010 AND zerofill_column>=2010
--echo #
CREATE TABLE t1 (a YEAR);
INSERT INTO t1 VALUES (2010),(2020);
SELECT * FROM t1 WHERE a=2010 AND a>=2010;
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=2010 AND a>=2010;
SELECT * FROM t1 WHERE a=2010 AND a>=10;
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=2010 AND a>=10;
SELECT * FROM t1 WHERE a=10 AND a>=2010;
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=10 AND a>=2010;
SELECT * FROM t1 WHERE a=10 AND a>=10;
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=10 AND a>=10;
DROP TABLE t1;
--echo #
--echo # End of 10.1 tests
--echo #
...@@ -1403,7 +1403,6 @@ Item *Field_num::convert_zerofill_number_to_string(THD *thd, Item *item) const ...@@ -1403,7 +1403,6 @@ Item *Field_num::convert_zerofill_number_to_string(THD *thd, Item *item) const
Item *Field_num::get_equal_zerofill_const_item(THD *thd, const Context &ctx, Item *Field_num::get_equal_zerofill_const_item(THD *thd, const Context &ctx,
Item_field *field_item,
Item *const_item) Item *const_item)
{ {
switch (ctx.subst_constraint()) { switch (ctx.subst_constraint()) {
...@@ -1414,7 +1413,7 @@ Item *Field_num::get_equal_zerofill_const_item(THD *thd, const Context &ctx, ...@@ -1414,7 +1413,7 @@ Item *Field_num::get_equal_zerofill_const_item(THD *thd, const Context &ctx,
} }
DBUG_ASSERT(const_item->const_item()); DBUG_ASSERT(const_item->const_item());
DBUG_ASSERT(ctx.compare_type() != STRING_RESULT); DBUG_ASSERT(ctx.compare_type() != STRING_RESULT);
return field_item; return const_item;
} }
...@@ -3292,12 +3291,10 @@ Field_new_decimal::unpack(uchar* to, const uchar *from, const uchar *from_end, ...@@ -3292,12 +3291,10 @@ Field_new_decimal::unpack(uchar* to, const uchar *from, const uchar *from_end,
Item *Field_new_decimal::get_equal_const_item(THD *thd, const Context &ctx, Item *Field_new_decimal::get_equal_const_item(THD *thd, const Context &ctx,
Item_field *field_item,
Item *const_item) Item *const_item)
{ {
if (flags & ZEROFILL_FLAG) if (flags & ZEROFILL_FLAG)
return Field_num::get_equal_zerofill_const_item(thd, ctx, return Field_num::get_equal_zerofill_const_item(thd, ctx, const_item);
field_item, const_item);
switch (ctx.subst_constraint()) { switch (ctx.subst_constraint()) {
case IDENTITY_SUBST: case IDENTITY_SUBST:
if (const_item->field_type() != MYSQL_TYPE_NEWDECIMAL || if (const_item->field_type() != MYSQL_TYPE_NEWDECIMAL ||
...@@ -4644,12 +4641,10 @@ bool Field_real::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate) ...@@ -4644,12 +4641,10 @@ bool Field_real::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate)
Item *Field_real::get_equal_const_item(THD *thd, const Context &ctx, Item *Field_real::get_equal_const_item(THD *thd, const Context &ctx,
Item_field *field_item,
Item *const_item) Item *const_item)
{ {
if (flags & ZEROFILL_FLAG) if (flags & ZEROFILL_FLAG)
return Field_num::get_equal_zerofill_const_item(thd, ctx, return Field_num::get_equal_zerofill_const_item(thd, ctx, const_item);
field_item, const_item);
switch (ctx.subst_constraint()) { switch (ctx.subst_constraint()) {
case IDENTITY_SUBST: case IDENTITY_SUBST:
if (const_item->decimal_scale() != Field_real::decimals()) if (const_item->decimal_scale() != Field_real::decimals())
...@@ -5519,8 +5514,8 @@ bool Field_temporal::can_optimize_group_min_max(const Item_bool_func *cond, ...@@ -5519,8 +5514,8 @@ bool Field_temporal::can_optimize_group_min_max(const Item_bool_func *cond,
} }
Item *Field_temporal::get_equal_const_item_datetime(THD *thd, const Context &ctx, Item *Field_temporal::get_equal_const_item_datetime(THD *thd,
Item_field *field_item, const Context &ctx,
Item *const_item) Item *const_item)
{ {
switch (ctx.subst_constraint()) { switch (ctx.subst_constraint()) {
...@@ -5843,7 +5838,6 @@ int Field_time::store_decimal(const my_decimal *d) ...@@ -5843,7 +5838,6 @@ int Field_time::store_decimal(const my_decimal *d)
Item *Field_time::get_equal_const_item(THD *thd, const Context &ctx, Item *Field_time::get_equal_const_item(THD *thd, const Context &ctx,
Item_field *field_item,
Item *const_item) Item *const_item)
{ {
switch (ctx.subst_constraint()) { switch (ctx.subst_constraint()) {
...@@ -6311,7 +6305,6 @@ void Field_newdate::sql_type(String &res) const ...@@ -6311,7 +6305,6 @@ void Field_newdate::sql_type(String &res) const
Item *Field_newdate::get_equal_const_item(THD *thd, const Context &ctx, Item *Field_newdate::get_equal_const_item(THD *thd, const Context &ctx,
Item_field *field_item,
Item *const_item) Item *const_item)
{ {
switch (ctx.subst_constraint()) { switch (ctx.subst_constraint()) {
......
...@@ -1103,7 +1103,7 @@ class Field: public Value_source ...@@ -1103,7 +1103,7 @@ class Field: public Value_source
virtual bool can_be_substituted_to_equal_item(const Context &ctx, virtual bool can_be_substituted_to_equal_item(const Context &ctx,
const Item_equal *item); const Item_equal *item);
virtual Item *get_equal_const_item(THD *thd, const Context &ctx, virtual Item *get_equal_const_item(THD *thd, const Context &ctx,
Item_field *field_item, Item *const_item) Item *const_item)
{ {
return const_item; return const_item;
} }
...@@ -1209,7 +1209,6 @@ class Field_num :public Field { ...@@ -1209,7 +1209,6 @@ class Field_num :public Field {
protected: protected:
Item *convert_zerofill_number_to_string(THD *thd, Item *item) const; Item *convert_zerofill_number_to_string(THD *thd, Item *item) const;
Item *get_equal_zerofill_const_item(THD *thd, const Context &ctx, Item *get_equal_zerofill_const_item(THD *thd, const Context &ctx,
Item_field *field_item,
Item *const_item); Item *const_item);
public: public:
const uint8 dec; const uint8 dec;
...@@ -1223,11 +1222,10 @@ class Field_num :public Field { ...@@ -1223,11 +1222,10 @@ class Field_num :public Field {
uint repertoire(void) const { return MY_REPERTOIRE_NUMERIC; } uint repertoire(void) const { return MY_REPERTOIRE_NUMERIC; }
CHARSET_INFO *charset(void) const { return &my_charset_numeric; } CHARSET_INFO *charset(void) const { return &my_charset_numeric; }
void prepend_zeros(String *value) const; void prepend_zeros(String *value) const;
Item *get_equal_const_item(THD *thd, const Context &ctx, Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item)
Item_field *field_item, Item *const_item)
{ {
return (flags & ZEROFILL_FLAG) ? return (flags & ZEROFILL_FLAG) ?
get_equal_zerofill_const_item(thd, ctx, field_item, const_item) : get_equal_zerofill_const_item(thd, ctx, const_item) :
const_item; const_item;
} }
void add_zerofill_and_unsigned(String &res) const; void add_zerofill_and_unsigned(String &res) const;
...@@ -1363,8 +1361,7 @@ class Field_real :public Field_num { ...@@ -1363,8 +1361,7 @@ class Field_real :public Field_num {
my_decimal *val_decimal(my_decimal *); my_decimal *val_decimal(my_decimal *);
uint32 max_display_length() { return field_length; } uint32 max_display_length() { return field_length; }
uint size_of() const { return sizeof(*this); } uint size_of() const { return sizeof(*this); }
Item *get_equal_const_item(THD *thd, const Context &ctx, Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item);
Item_field *field_item, Item *const_item);
}; };
...@@ -1450,8 +1447,7 @@ class Field_new_decimal :public Field_num { ...@@ -1450,8 +1447,7 @@ class Field_new_decimal :public Field_num {
uint is_equal(Create_field *new_field); uint is_equal(Create_field *new_field);
virtual const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, uint param_data); virtual const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, uint param_data);
static Field *create_from_item(MEM_ROOT *root, Item *); static Field *create_from_item(MEM_ROOT *root, Item *);
Item *get_equal_const_item(THD *thd, const Context &ctx, Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item);
Item_field *field_item, Item *const_item);
}; };
...@@ -1790,7 +1786,6 @@ class Field_null :public Field_str { ...@@ -1790,7 +1786,6 @@ class Field_null :public Field_str {
class Field_temporal: public Field { class Field_temporal: public Field {
protected: protected:
Item *get_equal_const_item_datetime(THD *thd, const Context &ctx, Item *get_equal_const_item_datetime(THD *thd, const Context &ctx,
Item_field *field_item,
Item *const_item); Item *const_item);
public: public:
Field_temporal(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg, Field_temporal(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
...@@ -1937,10 +1932,9 @@ class Field_timestamp :public Field_temporal { ...@@ -1937,10 +1932,9 @@ class Field_timestamp :public Field_temporal {
return unpack_int32(to, from, from_end); return unpack_int32(to, from, from_end);
} }
bool validate_value_in_record(THD *thd, const uchar *record) const; bool validate_value_in_record(THD *thd, const uchar *record) const;
Item *get_equal_const_item(THD *thd, const Context &ctx, Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item)
Item_field *field_item, Item *const_item)
{ {
return get_equal_const_item_datetime(thd, ctx, field_item, const_item); return get_equal_const_item_datetime(thd, ctx, const_item);
} }
uint size_of() const { return sizeof(*this); } uint size_of() const { return sizeof(*this); }
}; };
...@@ -2130,8 +2124,7 @@ class Field_newdate :public Field_temporal_with_date { ...@@ -2130,8 +2124,7 @@ class Field_newdate :public Field_temporal_with_date {
bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
{ return Field_newdate::get_TIME(ltime, ptr, fuzzydate); } { return Field_newdate::get_TIME(ltime, ptr, fuzzydate); }
uint size_of() const { return sizeof(*this); } uint size_of() const { return sizeof(*this); }
Item *get_equal_const_item(THD *thd, const Context &ctx, Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item);
Item_field *field_item, Item *const_item);
}; };
...@@ -2175,8 +2168,7 @@ class Field_time :public Field_temporal { ...@@ -2175,8 +2168,7 @@ class Field_time :public Field_temporal {
Field *new_key_field(MEM_ROOT *root, TABLE *new_table, Field *new_key_field(MEM_ROOT *root, TABLE *new_table,
uchar *new_ptr, uint32 length, uchar *new_ptr, uint32 length,
uchar *new_null_ptr, uint new_null_bit); uchar *new_null_ptr, uint new_null_bit);
Item *get_equal_const_item(THD *thd, const Context &ctx, Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item);
Item_field *field_item, Item *const_item);
}; };
...@@ -2335,10 +2327,9 @@ class Field_datetime :public Field_temporal_with_date { ...@@ -2335,10 +2327,9 @@ class Field_datetime :public Field_temporal_with_date {
{ {
return unpack_int64(to, from, from_end); return unpack_int64(to, from, from_end);
} }
Item *get_equal_const_item(THD *thd, const Context &ctx, Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item)
Item_field *field_item, Item *const_item)
{ {
return get_equal_const_item_datetime(thd, ctx, field_item, const_item); return get_equal_const_item_datetime(thd, ctx, const_item);
} }
uint size_of() const { return sizeof(*this); } uint size_of() const { return sizeof(*this); }
}; };
......
...@@ -5416,7 +5416,7 @@ Item *Item_field::propagate_equal_fields(THD *thd, ...@@ -5416,7 +5416,7 @@ Item *Item_field::propagate_equal_fields(THD *thd,
*/ */
return this; return this;
} }
if (!(item= field->get_equal_const_item(thd, ctx, this, item))) if (!(item= field->get_equal_const_item(thd, ctx, item)))
{ {
/* /*
Could not do safe conversion from the original constant item Could not do safe conversion from the original constant item
......
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