MDEV-16451 Split Item_equal::add_const() into a virtual method in type_handler()

MDEV-16452 Split TIME and DATETIME handling in Item_func_between, in_temporal, cmp_item_internal
This commit is contained in:
Alexander Barkov 2018-06-09 13:38:22 +04:00
parent 9043dd7a2d
commit d60fdb5814
7 changed files with 265 additions and 112 deletions

View file

@ -486,3 +486,44 @@ DROP TABLE t1;
#
# End of 10.2 tests
#
#
# Start of 10.4 tests
#
#
# MDEV-16451 Split Item_equal::add_const() into a virtual method in type_handler()
#
CREATE TABLE t1 (a YEAR(4));
INSERT INTO t1 VALUES (93),(94);
SELECT * FROM t1;
a
1993
1994
SELECT * FROM t1 WHERE a=1993 and a=93;
a
1993
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=1993 and a=93;
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` = 1993
DROP TABLE t1;
CREATE TABLE t1 (a YEAR(2));
Warnings:
Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead
INSERT INTO t1 VALUES (93),(94);
SELECT * FROM t1;
a
93
94
SELECT * FROM t1 WHERE a=1993 and a=93;
a
93
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=1993 and a=93;
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` = 93
DROP TABLE t1;
#
# End of 10.4 tests
#

View file

@ -254,3 +254,30 @@ DROP TABLE t1;
--echo #
--echo # End of 10.2 tests
--echo #
--echo #
--echo # Start of 10.4 tests
--echo #
--echo #
--echo # MDEV-16451 Split Item_equal::add_const() into a virtual method in type_handler()
--echo #
CREATE TABLE t1 (a YEAR(4));
INSERT INTO t1 VALUES (93),(94);
SELECT * FROM t1;
SELECT * FROM t1 WHERE a=1993 and a=93;
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=1993 and a=93;
DROP TABLE t1;
CREATE TABLE t1 (a YEAR(2));
INSERT INTO t1 VALUES (93),(94);
SELECT * FROM t1;
SELECT * FROM t1 WHERE a=1993 and a=93;
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=1993 and a=93;
DROP TABLE t1;
--echo #
--echo # End of 10.4 tests
--echo #

View file

@ -1676,12 +1676,6 @@ public:
return get_date_result(&ltime, fuzzydate) ? 0 : pack_time(&ltime);
}
// Get a temporal value in packed DATE/DATETIME or TIME format
longlong val_temporal_packed(enum_field_types f_type)
{
return f_type == MYSQL_TYPE_TIME ? val_time_packed() :
val_datetime_packed();
}
bool get_seconds(ulonglong *sec, ulong *sec_part);
virtual bool get_date_result(MYSQL_TIME *ltime, ulonglong fuzzydate)
{ return get_date(ltime,fuzzydate); }

View file

@ -2117,23 +2117,25 @@ bool Item_func_between::fix_length_and_dec_temporal(THD *thd)
}
longlong Item_func_between::val_int_cmp_temporal()
longlong Item_func_between::val_int_cmp_datetime()
{
enum_field_types f_type= m_comparator.type_handler()->field_type();
longlong value= args[0]->val_temporal_packed(f_type), a, b;
longlong value= args[0]->val_datetime_packed(), a, b;
if ((null_value= args[0]->null_value))
return 0;
a= args[1]->val_temporal_packed(f_type);
b= args[2]->val_temporal_packed(f_type);
if (!args[1]->null_value && !args[2]->null_value)
return (longlong) ((value >= a && value <= b) != negated);
if (args[1]->null_value && args[2]->null_value)
null_value= true;
else if (args[1]->null_value)
null_value= value <= b; // not null if false range.
else
null_value= value >= a;
return (longlong) (!null_value && negated);
a= args[1]->val_datetime_packed();
b= args[2]->val_datetime_packed();
return val_int_cmp_int_finalize(value, a, b);
}
longlong Item_func_between::val_int_cmp_time()
{
longlong value= args[0]->val_time_packed(), a, b;
if ((null_value= args[0]->null_value))
return 0;
a= args[1]->val_time_packed();
b= args[2]->val_time_packed();
return val_int_cmp_int_finalize(value, a, b);
}
@ -2172,18 +2174,22 @@ longlong Item_func_between::val_int_cmp_int()
return 0; /* purecov: inspected */
a= args[1]->val_int();
b= args[2]->val_int();
return val_int_cmp_int_finalize(value, a, b);
}
bool Item_func_between::val_int_cmp_int_finalize(longlong value,
longlong a,
longlong b)
{
if (!args[1]->null_value && !args[2]->null_value)
return (longlong) ((value >= a && value <= b) != negated);
if (args[1]->null_value && args[2]->null_value)
null_value= true;
else if (args[1]->null_value)
{
null_value= value <= b; // not null if false range.
}
else
{
null_value= value >= a;
}
return (longlong) (!null_value && negated);
}
@ -3653,9 +3659,18 @@ void in_time::set(uint pos,Item *item)
buff->unsigned_flag= 1L;
}
uchar *in_temporal::get_value_internal(Item *item, enum_field_types f_type)
uchar *in_datetime::get_value(Item *item)
{
tmp.val= item->val_temporal_packed(f_type);
tmp.val= item->val_datetime_packed();
if (item->null_value)
return 0;
tmp.unsigned_flag= 1L;
return (uchar*) &tmp;
}
uchar *in_time::get_value(Item *item)
{
tmp.val= item->val_time_packed();
if (item->null_value)
return 0;
tmp.unsigned_flag= 1L;
@ -4011,14 +4026,6 @@ cmp_item* cmp_item_decimal::make_same()
}
void cmp_item_temporal::store_value_internal(Item *item,
enum_field_types f_type)
{
value= item->val_temporal_packed(f_type);
m_null_value= item->null_value;
}
int cmp_item_datetime::cmp_not_null(const Value *val)
{
DBUG_ASSERT(!val->is_null());
@ -6262,76 +6269,53 @@ void Item_equal::add_const(THD *thd, Item *c)
equal_items.push_front(c, thd->mem_root);
return;
}
Item *const_item= get_const();
switch (Item_equal::compare_type_handler()->cmp_type()) {
case TIME_RESULT:
{
enum_field_types f_type= context_field->field_type();
longlong value0= c->val_temporal_packed(f_type);
longlong value1= const_item->val_temporal_packed(f_type);
cond_false= c->null_value || const_item->null_value || value0 != value1;
break;
}
case STRING_RESULT:
{
String *str1, *str2;
/*
Suppose we have an expression (with a string type field) like this:
WHERE field=const1 AND field=const2 ...
For all pairs field=constXXX we know that:
/*
Suppose we have an expression (with a string type field) like this:
WHERE field=const1 AND field=const2 ...
- Item_func_eq::fix_length_and_dec() performed collation and character
set aggregation and added character set converters when needed.
Note, the case like:
WHERE field=const1 COLLATE latin1_bin AND field=const2
is not handled here, because the field would be replaced to
Item_func_set_collation, which cannot get into Item_equal.
So all constXXX that are handled by Item_equal
already have compatible character sets with "field".
For all pairs field=constXXX we know that:
- Also, Field_str::test_if_equality_guarantees_uniqueness() guarantees
that the comparison collation of all equalities handled by Item_equal
match the the collation of the field.
- Item_func_eq::fix_length_and_dec() performed collation and character
set aggregation and added character set converters when needed.
Note, the case like:
WHERE field=const1 COLLATE latin1_bin AND field=const2
is not handled here, because the field would be replaced to
Item_func_set_collation, which cannot get into Item_equal.
So all constXXX that are handled by Item_equal
already have compatible character sets with "field".
Therefore, at Item_equal::add_const() time all constants constXXX
should be directly comparable to each other without an additional
character set conversion.
It's safe to do val_str() for "const_item" and "c" and compare
them according to the collation of the *field*.
- Also, Field_str::test_if_equality_guarantees_uniqueness() guarantees
that the comparison collation of all equalities handled by Item_equal
match the the collation of the field.
So in a script like this:
CREATE TABLE t1 (a VARCHAR(10) COLLATE xxx);
INSERT INTO t1 VALUES ('a'),('A');
SELECT * FROM t1 WHERE a='a' AND a='A';
Item_equal::add_const() effectively rewrites the condition to:
SELECT * FROM t1 WHERE a='a' AND 'a' COLLATE xxx='A';
and then to:
SELECT * FROM t1 WHERE a='a'; // if the two constants were equal
// e.g. in case of latin1_swedish_ci
or to:
SELECT * FROM t1 WHERE FALSE; // if the two constants were not equal
// e.g. in case of latin1_bin
Therefore, at Item_equal::add_const() time all constants constXXX
should be directly comparable to each other without an additional
character set conversion.
It's safe to do val_str() for "const_item" and "c" and compare
them according to the collation of the *field*.
Note, both "const_item" and "c" can return NULL, e.g.:
SELECT * FROM t1 WHERE a=NULL AND a='const';
SELECT * FROM t1 WHERE a='const' AND a=NULL;
SELECT * FROM t1 WHERE a='const' AND a=(SELECT MAX(a) FROM t2)
*/
cond_false= !(str1= const_item->val_str(&cmp_value1)) ||
!(str2= c->val_str(&cmp_value2)) ||
!str1->eq(str2, compare_collation());
break;
}
default:
{
Item_func_eq *func= new (thd->mem_root) Item_func_eq(thd, c, const_item);
if (func->set_cmp_func())
return;
func->quick_fix_field();
cond_false= !func->val_int();
}
}
So in a script like this:
CREATE TABLE t1 (a VARCHAR(10) COLLATE xxx);
INSERT INTO t1 VALUES ('a'),('A');
SELECT * FROM t1 WHERE a='a' AND a='A';
Item_equal::add_const() effectively rewrites the condition to:
SELECT * FROM t1 WHERE a='a' AND 'a' COLLATE xxx='A';
and then to:
SELECT * FROM t1 WHERE a='a'; // if the two constants were equal
// e.g. in case of latin1_swedish_ci
or to:
SELECT * FROM t1 WHERE FALSE; // if the two constants were not equal
// e.g. in case of latin1_bin
Note, both "const_item" and "c" can return NULL, e.g.:
SELECT * FROM t1 WHERE a=NULL AND a='const';
SELECT * FROM t1 WHERE a='const' AND a=NULL;
SELECT * FROM t1 WHERE a='const' AND a=(SELECT MAX(a) FROM t2)
*/
cond_false= !Item_equal::compare_type_handler()->Item_eq_value(thd, this, c,
get_const());
if (with_const && equal_items.elements == 1)
cond_true= TRUE;
if (cond_false || cond_true)

View file

@ -152,7 +152,8 @@ public:
class SEL_ARG;
struct KEY_PART;
class Item_bool_func :public Item_int_func
class Item_bool_func :public Item_int_func,
public Type_cmp_attributes
{
protected:
/*
@ -217,7 +218,7 @@ public:
Item_bool_func(THD *thd, Item_bool_func *item) :Item_int_func(thd, item) {}
const Type_handler *type_handler() const { return &type_handler_bool; }
const Type_handler *fixed_type_handler() const { return &type_handler_bool; }
virtual CHARSET_INFO *compare_collation() const { return NULL; }
CHARSET_INFO *compare_collation() const { return NULL; }
void fix_length_and_dec() { decimals=0; max_length=1; }
uint decimal_precision() const { return 1; }
bool need_parentheses_in_default() { return true; }
@ -891,6 +892,7 @@ class Item_func_between :public Item_func_opt_neg
protected:
SEL_TREE *get_func_mm_tree(RANGE_OPT_PARAM *param,
Field *field, Item *value);
bool val_int_cmp_int_finalize(longlong value, longlong a, longlong b);
public:
String value0,value1,value2;
Item_func_between(THD *thd, Item *a, Item *b, Item *c):
@ -931,7 +933,8 @@ public:
{ return get_item_copy<Item_func_between>(thd, this); }
longlong val_int_cmp_string();
longlong val_int_cmp_temporal();
longlong val_int_cmp_datetime();
longlong val_int_cmp_time();
longlong val_int_cmp_int();
longlong val_int_cmp_real();
longlong val_int_cmp_decimal();
@ -1404,8 +1407,6 @@ public:
*/
class in_temporal :public in_longlong
{
protected:
uchar *get_value_internal(Item *item, enum_field_types f_type);
public:
/* Cache for the left item. */
@ -1418,8 +1419,6 @@ public:
Item_datetime *dt= static_cast<Item_datetime*>(item);
dt->set(val->val, type_handler()->mysql_timestamp_type());
}
uchar *get_value(Item *item)
{ return get_value_internal(item, type_handler()->field_type()); }
friend int cmp_longlong(void *cmp_arg, packed_longlong *a,packed_longlong *b);
};
@ -1431,6 +1430,7 @@ public:
:in_temporal(thd, elements)
{}
void set(uint pos,Item *item);
uchar *get_value(Item *item);
const Type_handler *type_handler() const { return &type_handler_datetime2; }
};
@ -1442,6 +1442,7 @@ public:
:in_temporal(thd, elements)
{}
void set(uint pos,Item *item);
uchar *get_value(Item *item);
const Type_handler *type_handler() const { return &type_handler_time2; }
};
@ -1616,7 +1617,6 @@ class cmp_item_temporal: public cmp_item_scalar
{
protected:
longlong value;
void store_value_internal(Item *item, enum_field_types type);
public:
cmp_item_temporal() {}
int compare(cmp_item *ci);
@ -1631,7 +1631,8 @@ public:
{ }
void store_value(Item *item)
{
store_value_internal(item, MYSQL_TYPE_DATETIME);
value= item->val_datetime_packed();
m_null_value= item->null_value;
}
int cmp_not_null(const Value *val);
int cmp(Item *arg);
@ -1647,7 +1648,8 @@ public:
{ }
void store_value(Item *item)
{
store_value_internal(item, MYSQL_TYPE_TIME);
value= item->val_time_packed();
m_null_value= item->null_value;
}
int cmp_not_null(const Value *val);
int cmp(Item *arg);
@ -3081,7 +3083,6 @@ class Item_equal: public Item_bool_func
const Type_handler *m_compare_handler;
CHARSET_INFO *m_compare_collation;
String cmp_value1, cmp_value2;
public:
COND_EQUAL *upper_levels; /* multiple equalities of upper and levels */

View file

@ -3739,10 +3739,16 @@ longlong Type_handler_string_result::
return func->val_int_cmp_string();
}
longlong Type_handler_temporal_result::
longlong Type_handler_temporal_with_date::
Item_func_between_val_int(Item_func_between *func) const
{
return func->val_int_cmp_temporal();
return func->val_int_cmp_datetime();
}
longlong Type_handler_time_common::
Item_func_between_val_int(Item_func_between *func) const
{
return func->val_int_cmp_time();
}
longlong Type_handler_int_result::
@ -6450,4 +6456,79 @@ Type_handler_hex_hybrid::type_handler_for_system_time() const
}
/***************************************************************************/
bool Type_handler_row::Item_eq_value(THD *thd, const Type_cmp_attributes *attr,
Item *a, Item *b) const
{
DBUG_ASSERT(0);
return false;
}
bool Type_handler_int_result::Item_eq_value(THD *thd,
const Type_cmp_attributes *attr,
Item *a, Item *b) const
{
longlong value0= a->val_int();
longlong value1= b->val_int();
return !a->null_value && !b->null_value && value0 == value1 &&
(value0 >= 0 || a->unsigned_flag == b->unsigned_flag);
}
bool Type_handler_real_result::Item_eq_value(THD *thd,
const Type_cmp_attributes *attr,
Item *a, Item *b) const
{
double value0= a->val_real();
double value1= b->val_real();
return !a->null_value && !b->null_value && value0 == value1;
}
bool Type_handler_time_common::Item_eq_value(THD *thd,
const Type_cmp_attributes *attr,
Item *a, Item *b) const
{
longlong value0= a->val_time_packed();
longlong value1= b->val_time_packed();
return !a->null_value && !b->null_value && value0 == value1;
}
bool Type_handler_temporal_with_date::Item_eq_value(THD *thd,
const Type_cmp_attributes *attr,
Item *a, Item *b) const
{
longlong value0= a->val_datetime_packed();
longlong value1= b->val_datetime_packed();
return !a->null_value && !b->null_value && value0 == value1;
}
bool Type_handler_string_result::Item_eq_value(THD *thd,
const Type_cmp_attributes *attr,
Item *a, Item *b) const
{
String *va, *vb;
StringBuffer<128> cmp_value1, cmp_value2;
return (va= a->val_str(&cmp_value1)) &&
(vb= b->val_str(&cmp_value2)) &&
va->eq(vb, attr->compare_collation());
}
bool Type_handler_decimal_result::Item_eq_value(THD *thd,
const Type_cmp_attributes *attr,
Item *a, Item *b) const
{
my_decimal *va, *vb;
my_decimal cmp_value1, cmp_value2;
return (va= a->val_decimal(&cmp_value1)) &&
(vb= b->val_decimal(&cmp_value2)) &&
!my_decimal_cmp(va, vb);
}
/***************************************************************************/

View file

@ -836,6 +836,14 @@ public:
};
class Type_cmp_attributes
{
public:
virtual ~Type_cmp_attributes() { }
virtual CHARSET_INFO *compare_collation() const= 0;
};
class Type_cast_attributes
{
CHARSET_INFO *m_charset;
@ -1400,6 +1408,8 @@ public:
{
return false;
}
virtual bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr,
Item *a, Item *b) const= 0;
virtual bool Item_hybrid_func_fix_attributes(THD *thd,
const char *name,
Type_handler_hybrid_field_type *,
@ -1623,6 +1633,8 @@ public:
DBUG_ASSERT(0);
return 0;
}
bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr,
Item *a, Item *b) const;
uint Item_decimal_precision(const Item *item) const
{
DBUG_ASSERT(0);
@ -1878,6 +1890,8 @@ public:
SORT_FIELD_ATTR *attr) const;
bool Item_const_eq(const Item_const *a, const Item_const *b,
bool binary_cmp) const;
bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr,
Item *a, Item *b) const;
uint Item_decimal_precision(const Item *item) const;
bool Item_save_in_value(Item *item, st_value *value) const;
bool Item_param_set_from_value(THD *thd,
@ -1957,6 +1971,8 @@ public:
const Type_cast_attributes &attr) const;
bool Item_const_eq(const Item_const *a, const Item_const *b,
bool binary_cmp) const;
bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr,
Item *a, Item *b) const;
uint Item_decimal_precision(const Item *item) const;
bool Item_save_in_value(Item *item, st_value *value) const;
void Item_param_set_param_func(Item_param *param,
@ -2161,6 +2177,8 @@ public:
SORT_FIELD_ATTR *attr) const;
bool Item_const_eq(const Item_const *a, const Item_const *b,
bool binary_cmp) const;
bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr,
Item *a, Item *b) const;
uint Item_decimal_precision(const Item *item) const;
bool Item_save_in_value(Item *item, st_value *value) const;
bool Item_param_set_from_value(THD *thd,
@ -2282,7 +2300,6 @@ public:
bool Item_func_min_max_get_date(Item_func_min_max*,
MYSQL_TIME *, ulonglong fuzzydate) const;
bool Item_func_between_fix_length_and_dec(Item_func_between *func) const;
longlong Item_func_between_val_int(Item_func_between *func) const;
bool Item_func_in_fix_comparator_compatible_types(THD *thd,
Item_func_in *) const;
bool Item_func_round_fix_length_and_dec(Item_func_round *) const;
@ -2328,6 +2345,8 @@ public:
uint32 max_display_length(const Item *item) const;
bool Item_const_eq(const Item_const *a, const Item_const *b,
bool binary_cmp) const;
bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr,
Item *a, Item *b) const;
uint Item_time_precision(Item *item) const
{
return Item_temporal_precision(item, true);
@ -2847,6 +2866,8 @@ public:
}
Item *create_typecast_item(THD *thd, Item *item,
const Type_cast_attributes &attr) const;
bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr,
Item *a, Item *b) const;
uint Item_decimal_scale(const Item *item) const
{
return Item_decimal_scale_with_seconds(item);
@ -2885,6 +2906,7 @@ public:
ulonglong fuzzydate) const;
bool Item_func_min_max_get_date(Item_func_min_max*,
MYSQL_TIME *, ulonglong fuzzydate) const;
longlong Item_func_between_val_int(Item_func_between *func) const;
Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const;
bool set_comparator_func(Arg_comparator *cmp) const;
cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const;
@ -2952,6 +2974,8 @@ class Type_handler_temporal_with_date: public Type_handler_temporal_result
{
public:
virtual ~Type_handler_temporal_with_date() {}
bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr,
Item *a, Item *b) const;
bool Item_save_in_value(Item *item, st_value *value) const;
bool Item_send(Item *item, Protocol *protocol, st_value *buf) const
{
@ -2962,6 +2986,7 @@ public:
bool set_comparator_func(Arg_comparator *cmp) const;
cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const;
in_vector *make_in_vector(THD *, const Item_func_in *, uint nargs) const;
longlong Item_func_between_val_int(Item_func_between *func) const;
};