Commit b75c0033 authored by Alexander Barkov's avatar Alexander Barkov

MDEV-8816 Equal field propagation is not applied for WHERE...

MDEV-8816 Equal field propagation is not applied for WHERE varbinary_column>=_utf8'a' COLLATE utf8_general_ci AND varbinary_column='A';
1. Removing the legacy code that disabled equal field propagation in cases
   when comparison is done as VARBINARY. This is now correctly handled by
   the new propagation code in Item_xxx::propagate_equal_fields() and
   Field_str::can_be_substituted_to_equal_item (the bug fix).
2. Also, removing legacy (pre-MySQL-4.1) Arg_comparator methods
   compare_binary_string() and compare_e_binary_string(), as VARBINARY
   comparison is correcty handled in compare_string() and compare_e_string() by
   the corresponding VARBINARY collation handler implemented in my_charset_bin.
   (not really a part of the bug fix)
parent da3ec3d4
...@@ -10198,5 +10198,20 @@ Warnings: ...@@ -10198,5 +10198,20 @@ Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where ((`test`.`t1`.`a` = '1ë1') and (`test`.`t1`.`a` in (1,2,'x'))) Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where ((`test`.`t1`.`a` = '1ë1') and (`test`.`t1`.`a` in (1,2,'x')))
DROP TABLE IF EXISTS t1; DROP TABLE IF EXISTS t1;
# #
# MDEV-8816 Equal field propagation is not applied for WHERE varbinary_column>=_utf8'a' COLLATE utf8_swedish_ci AND varbinary_column='A';
#
CREATE TABLE t1 (c VARBINARY(10));
INSERT INTO t1 VALUES ('a'),('A');
SELECT * FROM t1 WHERE c>=_utf8'a' COLLATE utf8_general_ci AND c='A';
c
A
EXPLAIN EXTENDED
SELECT * FROM t1 WHERE c>=_utf8'a' COLLATE utf8_general_ci AND c='A';
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`.`c` AS `c` from `test`.`t1` where (`test`.`t1`.`c` = 'A')
DROP TABLE t1;
#
# End of 10.1 tests # End of 10.1 tests
# #
...@@ -1833,6 +1833,17 @@ EXPLAIN EXTENDED SELECT * FROM t1 WHERE a IN (1,2,'x') AND a='1ë1'; ...@@ -1833,6 +1833,17 @@ EXPLAIN EXTENDED SELECT * FROM t1 WHERE a IN (1,2,'x') AND a='1ë1';
DROP TABLE IF EXISTS t1; DROP TABLE IF EXISTS t1;
--echo #
--echo # MDEV-8816 Equal field propagation is not applied for WHERE varbinary_column>=_utf8'a' COLLATE utf8_swedish_ci AND varbinary_column='A';
--echo #
CREATE TABLE t1 (c VARBINARY(10));
INSERT INTO t1 VALUES ('a'),('A');
SELECT * FROM t1 WHERE c>=_utf8'a' COLLATE utf8_general_ci AND c='A';
EXPLAIN EXTENDED
SELECT * FROM t1 WHERE c>=_utf8'a' COLLATE utf8_general_ci AND c='A';
DROP TABLE t1;
--echo # --echo #
--echo # End of 10.1 tests --echo # End of 10.1 tests
--echo # --echo #
...@@ -2140,8 +2140,6 @@ bool agg_item_set_converter(DTCollation &coll, const char *fname, ...@@ -2140,8 +2140,6 @@ bool agg_item_set_converter(DTCollation &coll, const char *fname,
res= TRUE; res= TRUE;
break; // we cannot return here, we need to restore "arena". break; // we cannot return here, we need to restore "arena".
} }
if ((*arg)->type() == Item::FIELD_ITEM)
((Item_field *)(*arg))->no_const_subst= 1;
/* /*
If in statement prepare, then we create a converter for two If in statement prepare, then we create a converter for two
constant items, do it once and then reuse it. constant items, do it once and then reuse it.
...@@ -2226,7 +2224,7 @@ void Item_ident_for_show::make_field(Send_field *tmp_field) ...@@ -2226,7 +2224,7 @@ void Item_ident_for_show::make_field(Send_field *tmp_field)
Item_field::Item_field(THD *thd, Field *f) Item_field::Item_field(THD *thd, Field *f)
:Item_ident(thd, 0, NullS, *f->table_name, f->field_name), :Item_ident(thd, 0, NullS, *f->table_name, f->field_name),
item_equal(0), no_const_subst(0), item_equal(0),
have_privileges(0), any_privileges(0) have_privileges(0), any_privileges(0)
{ {
set_field(f); set_field(f);
...@@ -2249,7 +2247,7 @@ Item_field::Item_field(THD *thd, Field *f) ...@@ -2249,7 +2247,7 @@ Item_field::Item_field(THD *thd, Field *f)
Item_field::Item_field(THD *thd, Name_resolution_context *context_arg, Item_field::Item_field(THD *thd, Name_resolution_context *context_arg,
Field *f) Field *f)
:Item_ident(thd, context_arg, f->table->s->db.str, *f->table_name, f->field_name), :Item_ident(thd, context_arg, f->table->s->db.str, *f->table_name, f->field_name),
item_equal(0), no_const_subst(0), item_equal(0),
have_privileges(0), any_privileges(0) have_privileges(0), any_privileges(0)
{ {
/* /*
...@@ -2292,7 +2290,7 @@ Item_field::Item_field(THD *thd, Name_resolution_context *context_arg, ...@@ -2292,7 +2290,7 @@ Item_field::Item_field(THD *thd, Name_resolution_context *context_arg,
const char *db_arg,const char *table_name_arg, const char *db_arg,const char *table_name_arg,
const char *field_name_arg) const char *field_name_arg)
:Item_ident(thd, context_arg, db_arg, table_name_arg, field_name_arg), :Item_ident(thd, context_arg, db_arg, table_name_arg, field_name_arg),
field(0), item_equal(0), no_const_subst(0), field(0), item_equal(0),
have_privileges(0), any_privileges(0) have_privileges(0), any_privileges(0)
{ {
SELECT_LEX *select= thd->lex->current_select; SELECT_LEX *select= thd->lex->current_select;
...@@ -2310,7 +2308,6 @@ Item_field::Item_field(THD *thd, Item_field *item) ...@@ -2310,7 +2308,6 @@ Item_field::Item_field(THD *thd, Item_field *item)
:Item_ident(thd, item), :Item_ident(thd, item),
field(item->field), field(item->field),
item_equal(item->item_equal), item_equal(item->item_equal),
no_const_subst(item->no_const_subst),
have_privileges(item->have_privileges), have_privileges(item->have_privileges),
any_privileges(item->any_privileges) any_privileges(item->any_privileges)
{ {
...@@ -5335,7 +5332,7 @@ Item *Item_field::propagate_equal_fields(THD *thd, ...@@ -5335,7 +5332,7 @@ Item *Item_field::propagate_equal_fields(THD *thd,
const Context &ctx, const Context &ctx,
COND_EQUAL *arg) COND_EQUAL *arg)
{ {
if (no_const_subst || !(item_equal= find_item_equal(arg))) if (!(item_equal= find_item_equal(arg)))
return this; return this;
if (!field->can_be_substituted_to_equal_item(ctx, item_equal)) if (!field->can_be_substituted_to_equal_item(ctx, item_equal))
{ {
...@@ -5372,20 +5369,6 @@ Item *Item_field::propagate_equal_fields(THD *thd, ...@@ -5372,20 +5369,6 @@ Item *Item_field::propagate_equal_fields(THD *thd,
} }
/**
Mark the item to not be part of substitution if it's not a binary item.
See comments in Arg_comparator::set_compare_func() for details.
*/
bool Item_field::set_no_const_sub(uchar *arg)
{
if (field->charset() != &my_charset_bin)
no_const_subst=1;
return FALSE;
}
/** /**
Replace an Item_field for an equal Item_field that evaluated earlier Replace an Item_field for an equal Item_field that evaluated earlier
(if any). (if any).
......
...@@ -1520,7 +1520,6 @@ class Item: public Value_source, public Type_std_attributes ...@@ -1520,7 +1520,6 @@ class Item: public Value_source, public Type_std_attributes
return trace_unsupported_by_check_vcol_func_processor(full_name()); return trace_unsupported_by_check_vcol_func_processor(full_name());
} }
virtual bool set_no_const_sub(uchar *arg) { return FALSE; }
/* arg points to REPLACE_EQUAL_FIELD_ARG object */ /* arg points to REPLACE_EQUAL_FIELD_ARG object */
virtual Item *replace_equal_field(THD *thd, uchar *arg) { return this; } virtual Item *replace_equal_field(THD *thd, uchar *arg) { return this; }
/* /*
...@@ -2333,7 +2332,6 @@ class Item_field :public Item_ident ...@@ -2333,7 +2332,6 @@ class Item_field :public Item_ident
public: public:
Field *field; Field *field;
Item_equal *item_equal; Item_equal *item_equal;
bool no_const_subst;
/* /*
if any_privileges set to TRUE then here real effective privileges will if any_privileges set to TRUE then here real effective privileges will
be stored be stored
...@@ -2465,7 +2463,6 @@ class Item_field :public Item_ident ...@@ -2465,7 +2463,6 @@ class Item_field :public Item_ident
void set_item_equal(Item_equal *item_eq) { item_equal= item_eq; } void set_item_equal(Item_equal *item_eq) { item_equal= item_eq; }
Item_equal *find_item_equal(COND_EQUAL *cond_equal); Item_equal *find_item_equal(COND_EQUAL *cond_equal);
Item* propagate_equal_fields(THD *, const Context &, COND_EQUAL *); Item* propagate_equal_fields(THD *, const Context &, COND_EQUAL *);
bool set_no_const_sub(uchar *arg);
Item *replace_equal_field(THD *thd, uchar *arg); Item *replace_equal_field(THD *thd, uchar *arg);
inline uint32 max_disp_length() { return field->max_display_length(); } inline uint32 max_disp_length() { return field->max_display_length(); }
Item_field *field_for_view_update() { return this; } Item_field *field_for_view_update() { return this; }
......
...@@ -554,32 +554,6 @@ int Arg_comparator::set_compare_func(Item_func_or_sum *item, Item_result type) ...@@ -554,32 +554,6 @@ int Arg_comparator::set_compare_func(Item_func_or_sum *item, Item_result type)
} }
break; break;
} }
case STRING_RESULT:
{
if (cmp_collation.collation == &my_charset_bin)
{
/*
We are using BLOB/BINARY/VARBINARY, change to compare byte by byte,
without removing end space
*/
if (func == &Arg_comparator::compare_string)
func= &Arg_comparator::compare_binary_string;
else if (func == &Arg_comparator::compare_e_string)
func= &Arg_comparator::compare_e_binary_string;
/*
As this is binary compassion, mark all fields that they can't be
transformed. Otherwise we would get into trouble with comparisons
like:
WHERE col= 'j' AND col LIKE BINARY 'j'
which would be transformed to:
WHERE col= 'j'
*/
(*a)->walk(&Item::set_no_const_sub, FALSE, (uchar*) 0);
(*b)->walk(&Item::set_no_const_sub, FALSE, (uchar*) 0);
}
break;
}
case INT_RESULT: case INT_RESULT:
{ {
if (func == &Arg_comparator::compare_int_signed) if (func == &Arg_comparator::compare_int_signed)
...@@ -598,6 +572,7 @@ int Arg_comparator::set_compare_func(Item_func_or_sum *item, Item_result type) ...@@ -598,6 +572,7 @@ int Arg_comparator::set_compare_func(Item_func_or_sum *item, Item_result type)
} }
break; break;
} }
case STRING_RESULT:
case DECIMAL_RESULT: case DECIMAL_RESULT:
break; break;
case REAL_RESULT: case REAL_RESULT:
...@@ -943,38 +918,6 @@ int Arg_comparator::compare_string() ...@@ -943,38 +918,6 @@ int Arg_comparator::compare_string()
} }
/**
Compare strings byte by byte. End spaces are also compared.
@retval
<0 *a < *b
@retval
0 *b == *b
@retval
>0 *a > *b
*/
int Arg_comparator::compare_binary_string()
{
String *res1,*res2;
if ((res1= (*a)->val_str(&value1)))
{
if ((res2= (*b)->val_str(&value2)))
{
if (set_null)
owner->null_value= 0;
uint res1_length= res1->length();
uint res2_length= res2->length();
int cmp= memcmp(res1->ptr(), res2->ptr(), MY_MIN(res1_length,res2_length));
return cmp ? cmp : (int) (res1_length - res2_length);
}
}
if (set_null)
owner->null_value= 1;
return -1;
}
/** /**
Compare strings, but take into account that NULL == NULL. Compare strings, but take into account that NULL == NULL.
*/ */
...@@ -991,17 +934,6 @@ int Arg_comparator::compare_e_string() ...@@ -991,17 +934,6 @@ int Arg_comparator::compare_e_string()
} }
int Arg_comparator::compare_e_binary_string()
{
String *res1,*res2;
res1= (*a)->val_str(&value1);
res2= (*b)->val_str(&value2);
if (!res1 || !res2)
return MY_TEST(res1 == res2);
return MY_TEST(stringcmp(res1, res2) == 0);
}
int Arg_comparator::compare_real() int Arg_comparator::compare_real()
{ {
/* /*
......
...@@ -86,7 +86,6 @@ class Arg_comparator: public Sql_alloc ...@@ -86,7 +86,6 @@ class Arg_comparator: public Sql_alloc
inline int compare() { return (this->*func)(); } inline int compare() { return (this->*func)(); }
int compare_string(); // compare args[0] & args[1] int compare_string(); // compare args[0] & args[1]
int compare_binary_string(); // compare args[0] & args[1]
int compare_real(); // compare args[0] & args[1] int compare_real(); // compare args[0] & args[1]
int compare_decimal(); // compare args[0] & args[1] int compare_decimal(); // compare args[0] & args[1]
int compare_int_signed(); // compare args[0] & args[1] int compare_int_signed(); // compare args[0] & args[1]
...@@ -95,7 +94,6 @@ class Arg_comparator: public Sql_alloc ...@@ -95,7 +94,6 @@ class Arg_comparator: public Sql_alloc
int compare_int_unsigned(); int compare_int_unsigned();
int compare_row(); // compare args[0] & args[1] int compare_row(); // compare args[0] & args[1]
int compare_e_string(); // compare args[0] & args[1] int compare_e_string(); // compare args[0] & args[1]
int compare_e_binary_string(); // compare args[0] & args[1]
int compare_e_real(); // compare args[0] & args[1] int compare_e_real(); // compare args[0] & args[1]
int compare_e_decimal(); // compare args[0] & args[1] int compare_e_decimal(); // compare args[0] & args[1]
int compare_e_int(); // compare args[0] & args[1] int compare_e_int(); // compare args[0] & args[1]
......
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