Commit fee46323 authored by Alexander Barkov's avatar Alexander Barkov

MDEV-15758 Split Item_bool_func::get_mm_leaf() into virtual methods in Field and Type_handler

parent 6bfeace1
......@@ -48,6 +48,9 @@ class Item_equal;
class Virtual_tmp_table;
class Qualified_column_ident;
class Table_ident;
class SEL_ARG;
class RANGE_OPT_PARAM;
struct KEY_PART;
enum enum_check_fields
{
......@@ -847,6 +850,10 @@ class Field: public Value_source
to be quoted when used in constructing an SQL query.
*/
virtual bool str_needs_quotes() { return FALSE; }
const Type_handler *type_handler_for_comparison() const
{
return type_handler()->type_handler_for_comparison();
}
Item_result result_type () const
{
return type_handler()->result_type();
......@@ -1375,6 +1382,59 @@ class Field: public Value_source
}
int warn_if_overflow(int op_result);
Copy_func *get_identical_copy_func() const;
bool can_optimize_scalar_range(const RANGE_OPT_PARAM *param,
const KEY_PART *key_part,
const Item_bool_func *cond,
scalar_comparison_op op,
const Item *value) const;
uchar *make_key_image(MEM_ROOT *mem_root, const KEY_PART *key_part);
SEL_ARG *get_mm_leaf_int(RANGE_OPT_PARAM *param, KEY_PART *key_part,
const Item_bool_func *cond,
scalar_comparison_op op, Item *value,
bool unsigned_field);
/*
Make a leaf tree for the cases when the value was stored
to the field exactly, without any truncation, rounding or adjustments.
For example, if we stored an INT value into an INT column,
and value->save_in_field_no_warnings() returned 0,
we know that the value was stored exactly.
*/
SEL_ARG *stored_field_make_mm_leaf_exact(RANGE_OPT_PARAM *param,
KEY_PART *key_part,
scalar_comparison_op op,
Item *value);
/*
Make a leaf tree for the cases when we don't know if
the value was stored to the field without any data loss,
or was modified to a smaller or a greater value.
Used for the data types whose methods Field::store*()
silently adjust the value. This is the most typical case.
*/
SEL_ARG *stored_field_make_mm_leaf(RANGE_OPT_PARAM *param,
KEY_PART *key_part,
scalar_comparison_op op, Item *value);
/*
Make a leaf tree when an INT value was stored into a field of INT type,
and some truncation happened. Tries to adjust the range search condition
when possible, e.g. "tinytint < 300" -> "tinyint <= 127".
Can also return SEL_ARG_IMPOSSIBLE(), and NULL (not sargable).
*/
SEL_ARG *stored_field_make_mm_leaf_bounded_int(RANGE_OPT_PARAM *param,
KEY_PART *key_part,
scalar_comparison_op op,
Item *value,
bool unsigned_field);
/*
Make a leaf tree when some truncation happened during
value->save_in_field_no_warning(this), and we cannot yet adjust the range
search condition for the current combination of the field and the value
data types.
Returns SEL_ARG_IMPOSSIBLE() for "=" and "<=>".
Returns NULL (not sargable) for other comparison operations.
*/
SEL_ARG *stored_field_make_mm_leaf_truncated(RANGE_OPT_PARAM *prm,
scalar_comparison_op,
Item *value);
public:
void set_table_name(String *alias)
{
......@@ -1547,6 +1607,10 @@ class Field: public Value_source
const Item *item,
bool is_eq_func) const;
virtual SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param, KEY_PART *key_part,
const Item_bool_func *cond,
scalar_comparison_op op, Item *value)= 0;
bool can_optimize_outer_join_table_elimination(const Item_bool_func *cond,
const Item *item) const
{
......@@ -1708,6 +1772,9 @@ class Field_num :public Field {
{
return pos_in_interval_val_real(min, max);
}
SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param, KEY_PART *key_part,
const Item_bool_func *cond,
scalar_comparison_op op, Item *value);
};
......@@ -1764,6 +1831,9 @@ class Field_str :public Field {
return pos_in_interval_val_str(min, max, length_size());
}
bool test_if_equality_guarantees_uniqueness(const Item *const_item) const;
SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param, KEY_PART *key_part,
const Item_bool_func *cond,
scalar_comparison_op op, Item *value);
};
/* base class for Field_string, Field_varstring and Field_blob */
......@@ -2061,6 +2131,12 @@ class Field_int :public Field_num
uint32 prec= type_limits_int()->precision();
return Information_schema_numeric_attributes(prec, 0);
}
SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param, KEY_PART *key_part,
const Item_bool_func *cond,
scalar_comparison_op op, Item *value)
{
return get_mm_leaf_int(param, key_part, cond, op, value, unsigned_flag);
}
};
......@@ -2543,6 +2619,9 @@ class Field_temporal: public Field {
{
return true;
}
SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param, KEY_PART *key_part,
const Item_bool_func *cond,
scalar_comparison_op op, Item *value);
};
......@@ -2823,14 +2902,31 @@ class Field_year :public Field_tiny {
};
class Field_date :public Field_temporal_with_date {
class Field_date_common: public Field_temporal_with_date
{
public:
Field_date_common(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
enum utype unireg_check_arg,
const LEX_CSTRING *field_name_arg)
:Field_temporal_with_date(ptr_arg, MAX_DATE_WIDTH,
null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg)
{}
SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param, KEY_PART *key_part,
const Item_bool_func *cond,
scalar_comparison_op op, Item *value);
};
class Field_date :public Field_date_common
{
void store_TIME(MYSQL_TIME *ltime);
bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, ulonglong fuzzydate) const;
public:
Field_date(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg)
:Field_temporal_with_date(ptr_arg, MAX_DATE_WIDTH, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg) {}
:Field_date_common(ptr_arg, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg) {}
const Type_handler *type_handler() const { return &type_handler_date; }
enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; }
int reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=0; return 0; }
......@@ -2858,14 +2954,15 @@ class Field_date :public Field_temporal_with_date {
};
class Field_newdate :public Field_temporal_with_date {
class Field_newdate :public Field_date_common
{
void store_TIME(MYSQL_TIME *ltime);
bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, ulonglong fuzzydate) const;
public:
Field_newdate(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg)
:Field_temporal_with_date(ptr_arg, MAX_DATE_WIDTH, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg)
:Field_date_common(ptr_arg, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg)
{}
const Type_handler *type_handler() const { return &type_handler_newdate; }
enum ha_base_keytype key_type() const { return HA_KEYTYPE_UINT24; }
......@@ -4180,6 +4277,12 @@ class Field_bit :public Field {
}
void hash(ulong *nr, ulong *nr2);
SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param, KEY_PART *key_part,
const Item_bool_func *cond,
scalar_comparison_op op, Item *value)
{
return get_mm_leaf_int(param, key_part, cond, op, value, true);
}
private:
virtual size_t do_last_null_byte() const;
int save_field_metadata(uchar *first_byte);
......
......@@ -6507,7 +6507,7 @@ Item *Item_field::replace_equal_field(THD *thd, uchar *arg)
comparison context, and it's safe to replace it to the constant from
item_equal.
*/
DBUG_ASSERT(type_handler()->type_handler_for_comparison()->cmp_type() ==
DBUG_ASSERT(type_handler_for_comparison()->cmp_type() ==
item_equal->compare_type_handler()->cmp_type());
return const_item2;
}
......@@ -9941,73 +9941,14 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item)
int stored_field_cmp_to_item(THD *thd, Field *field, Item *item)
{
Item_result res_type=item_cmp_type(field->result_type(),
item->result_type());
/*
We have to check field->cmp_type() instead of res_type,
as result_type() - and thus res_type - can never be TIME_RESULT (yet).
*/
if (field->cmp_type() == TIME_RESULT)
{
MYSQL_TIME field_time, item_time, item_time2, *item_time_cmp= &item_time;
if (field->type() == MYSQL_TYPE_TIME)
{
field->get_time(&field_time);
item->get_time(&item_time);
}
else
{
field->get_date(&field_time, TIME_INVALID_DATES);
item->get_date(&item_time, TIME_INVALID_DATES);
if (item_time.time_type == MYSQL_TIMESTAMP_TIME)
if (time_to_datetime(thd, &item_time, item_time_cmp= &item_time2))
return 1;
}
return my_time_compare(&field_time, item_time_cmp);
}
if (res_type == STRING_RESULT)
Type_handler_hybrid_field_type cmp(field->type_handler_for_comparison());
if (cmp.aggregate_for_comparison(item->type_handler_for_comparison()))
{
char item_buff[MAX_FIELD_WIDTH];
char field_buff[MAX_FIELD_WIDTH];
String item_tmp(item_buff,sizeof(item_buff),&my_charset_bin);
String field_tmp(field_buff,sizeof(field_buff),&my_charset_bin);
String *item_result= item->val_str(&item_tmp);
/*
Some implementations of Item::val_str(String*) actually modify
the field Item::null_value, hence we can't check it earlier.
*/
if (item->null_value)
return 0;
String *field_result= field->val_str(&field_tmp);
return sortcmp(field_result, item_result, field->charset());
}
if (res_type == INT_RESULT)
return 0; // Both are of type int
if (res_type == DECIMAL_RESULT)
{
my_decimal item_buf, *item_val,
field_buf, *field_val;
item_val= item->val_decimal(&item_buf);
if (item->null_value)
return 0;
field_val= field->val_decimal(&field_buf);
return my_decimal_cmp(field_val, item_val);
}
/*
The patch for Bug#13463415 started using this function for comparing
BIGINTs. That uncovered a bug in Visual Studio 32bit optimized mode.
Prefixing the auto variables with volatile fixes the problem....
*/
volatile double result= item->val_real();
if (item->null_value)
// At fix_fields() time we checked that "field" and "item" are comparable
DBUG_ASSERT(0);
return 0;
volatile double field_result= field->val_real();
if (field_result < result)
return -1;
else if (field_result > result)
return 1;
return 0;
}
return cmp.type_handler()->stored_field_cmp_to_item(thd, field, item);
}
......
......@@ -78,6 +78,20 @@ class Item_func :public Item_func_or_sum,
EXTRACT_FUNC, CHAR_TYPECAST_FUNC, FUNC_SP, UDF_FUNC,
NEG_FUNC, GSYSVAR_FUNC, IN_OPTIMIZER_FUNC, DYNCOL_FUNC,
JSON_EXTRACT_FUNC };
static scalar_comparison_op functype_to_scalar_comparison_op(Functype type)
{
switch (type) {
case EQ_FUNC: return SCALAR_CMP_EQ;
case EQUAL_FUNC: return SCALAR_CMP_EQUAL;
case LT_FUNC: return SCALAR_CMP_LT;
case LE_FUNC: return SCALAR_CMP_LE;
case GE_FUNC: return SCALAR_CMP_GE;
case GT_FUNC: return SCALAR_CMP_GT;
default: break;
}
DBUG_ASSERT(0);
return SCALAR_CMP_EQ;
}
enum Type type() const { return FUNC_ITEM; }
virtual enum Functype functype() const { return UNKNOWN_FUNC; }
Item_func(THD *thd): Item_func_or_sum(thd)
......
This diff is collapsed.
......@@ -6574,3 +6574,92 @@ void Type_handler_timestamp_common::
else
c->set_handler(&type_handler_timestamp);
}
/***************************************************************************/
int Type_handler_temporal_with_date::stored_field_cmp_to_item(THD *thd,
Field *field,
Item *item) const
{
MYSQL_TIME field_time, item_time, item_time2, *item_time_cmp= &item_time;
field->get_date(&field_time, TIME_INVALID_DATES);
item->get_date(&item_time, TIME_INVALID_DATES);
if (item_time.time_type == MYSQL_TIMESTAMP_TIME &&
time_to_datetime(thd, &item_time, item_time_cmp= &item_time2))
return 1;
return my_time_compare(&field_time, item_time_cmp);
}
int Type_handler_time_common::stored_field_cmp_to_item(THD *thd,
Field *field,
Item *item) const
{
MYSQL_TIME field_time, item_time;
field->get_time(&field_time);
item->get_time(&item_time);
return my_time_compare(&field_time, &item_time);
}
int Type_handler_string_result::stored_field_cmp_to_item(THD *thd,
Field *field,
Item *item) const
{
StringBuffer<MAX_FIELD_WIDTH> item_tmp;
StringBuffer<MAX_FIELD_WIDTH> field_tmp;
String *item_result= item->val_str(&item_tmp);
/*
Some implementations of Item::val_str(String*) actually modify
the field Item::null_value, hence we can't check it earlier.
*/
if (item->null_value)
return 0;
String *field_result= field->val_str(&field_tmp);
return sortcmp(field_result, item_result, field->charset());
}
int Type_handler_int_result::stored_field_cmp_to_item(THD *thd,
Field *field,
Item *item) const
{
DBUG_ASSERT(0); // Not used yet
return 0;
}
int Type_handler_decimal_result::stored_field_cmp_to_item(THD *thd,
Field *field,
Item *item) const
{
my_decimal item_buf, *item_val, field_buf, *field_val;
item_val= item->val_decimal(&item_buf);
if (item->null_value)
return 0;
field_val= field->val_decimal(&field_buf);
return my_decimal_cmp(field_val, item_val);
}
int Type_handler_real_result::stored_field_cmp_to_item(THD *thd,
Field *field,
Item *item) const
{
/*
The patch for Bug#13463415 started using this function for comparing
BIGINTs. That uncovered a bug in Visual Studio 32bit optimized mode.
Prefixing the auto variables with volatile fixes the problem....
*/
volatile double result= item->val_real();
if (item->null_value)
return 0;
volatile double field_result= field->val_real();
if (field_result < result)
return -1;
else if (field_result > result)
return 1;
return 0;
}
......@@ -77,6 +77,17 @@ struct SORT_FIELD_ATTR;
class Vers_history_point;
enum scalar_comparison_op
{
SCALAR_CMP_EQ,
SCALAR_CMP_EQUAL,
SCALAR_CMP_LT,
SCALAR_CMP_LE,
SCALAR_CMP_GE,
SCALAR_CMP_GT
};
/**
Class Time is designed to store valid TIME values.
......@@ -1184,6 +1195,8 @@ class Type_handler
{
return this;
}
virtual int
stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const= 0;
virtual CHARSET_INFO *charset_for_protocol(const Item *item) const;
virtual const Type_handler*
type_handler_adjusted_to_max_octet_length(uint max_octet_length,
......@@ -1562,6 +1575,11 @@ class Type_handler_row: public Type_handler
return ROW_RESULT;
}
const Type_handler *type_handler_for_comparison() const;
int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const
{
DBUG_ASSERT(0);
return 0;
}
bool subquery_type_allows_materialization(const Item *inner,
const Item *outer) const
{
......@@ -1888,6 +1906,7 @@ class Type_handler_real_result: public Type_handler_numeric
Item_result cmp_type() const { return REAL_RESULT; }
virtual ~Type_handler_real_result() {}
const Type_handler *type_handler_for_comparison() const;
int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const;
bool subquery_type_allows_materialization(const Item *inner,
const Item *outer) const;
void make_sort_key(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field,
......@@ -1965,6 +1984,7 @@ class Type_handler_decimal_result: public Type_handler_numeric
Item_result cmp_type() const { return DECIMAL_RESULT; }
virtual ~Type_handler_decimal_result() {};
const Type_handler *type_handler_for_comparison() const;
int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const;
bool subquery_type_allows_materialization(const Item *inner,
const Item *outer) const;
Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const;
......@@ -2174,6 +2194,7 @@ class Type_handler_int_result: public Type_handler_numeric
bool is_limit_clause_valid_type() const { return true; }
virtual ~Type_handler_int_result() {}
const Type_handler *type_handler_for_comparison() const;
int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const;
bool subquery_type_allows_materialization(const Item *inner,
const Item *outer) const;
Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const;
......@@ -2237,6 +2258,7 @@ class Type_handler_int_result: public Type_handler_numeric
bool Item_func_mul_fix_length_and_dec(Item_func_mul *) const;
bool Item_func_div_fix_length_and_dec(Item_func_div *) const;
bool Item_func_mod_fix_length_and_dec(Item_func_mod *) const;
};
......@@ -2331,6 +2353,7 @@ class Type_handler_string_result: public Type_handler
CHARSET_INFO *charset_for_protocol(const Item *item) const;
virtual ~Type_handler_string_result() {}
const Type_handler *type_handler_for_comparison() const;
int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const;
const Type_handler *
type_handler_adjusted_to_max_octet_length(uint max_octet_length,
CHARSET_INFO *cs) const;
......@@ -2885,6 +2908,7 @@ class Type_handler_time_common: public Type_handler_temporal_result
return Item_divisor_precision_increment_with_seconds(item);
}
const Type_handler *type_handler_for_comparison() const;
int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const;
void Column_definition_implicit_upgrade(Column_definition *c) const;
bool Column_definition_fix_attributes(Column_definition *c) const;
bool Item_save_in_value(Item *item, st_value *value) const;
......@@ -2986,6 +3010,7 @@ class Type_handler_temporal_with_date: public Type_handler_temporal_result
virtual ~Type_handler_temporal_with_date() {}
bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr,
Item *a, Item *b) const;
int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const;
bool Item_save_in_value(Item *item, st_value *value) const;
bool Item_send(Item *item, Protocol *protocol, st_value *buf) const
{
......
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