mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 03:52:35 +01:00
MDEV-15758 Split Item_bool_func::get_mm_leaf() into virtual methods in Field and Type_handler
This commit is contained in:
parent
6bfeace10b
commit
fee4632387
6 changed files with 589 additions and 232 deletions
115
sql/field.h
115
sql/field.h
|
@ -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 @@ public:
|
|||
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 @@ protected:
|
|||
}
|
||||
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 @@ public:
|
|||
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 @@ public:
|
|||
{
|
||||
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 @@ public:
|
|||
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 @@ public:
|
|||
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 @@ public:
|
|||
{
|
||||
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 @@ public:
|
|||
};
|
||||
|
||||
|
||||
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 @@ public:
|
|||
};
|
||||
|
||||
|
||||
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 @@ public:
|
|||
}
|
||||
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);
|
||||
|
|
73
sql/item.cc
73
sql/item.cc
|
@ -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)
|
||||
Type_handler_hybrid_field_type cmp(field->type_handler_for_comparison());
|
||||
if (cmp.aggregate_for_comparison(item->type_handler_for_comparison()))
|
||||
{
|
||||
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)
|
||||
{
|
||||
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 @@ public:
|
|||
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)
|
||||
|
|
505
sql/opt_range.cc
505
sql/opt_range.cc
|
@ -1892,6 +1892,118 @@ SEL_ARG::SEL_ARG(Field *field_,uint8 part_,
|
|||
left=right= &null_element;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
A number of helper classes:
|
||||
SEL_ARG_LE, SEL_ARG_LT, SEL_ARG_GT, SEL_ARG_GE,
|
||||
to share the code between:
|
||||
Field::stored_field_make_mm_leaf()
|
||||
Field::stored_field_make_mm_leaf_exact()
|
||||
*/
|
||||
class SEL_ARG_LE: public SEL_ARG
|
||||
{
|
||||
public:
|
||||
SEL_ARG_LE(const uchar *key, Field *field)
|
||||
:SEL_ARG(field, key, key)
|
||||
{
|
||||
if (!field->real_maybe_null())
|
||||
min_flag= NO_MIN_RANGE; // From start
|
||||
else
|
||||
{
|
||||
min_value= is_null_string;
|
||||
min_flag= NEAR_MIN; // > NULL
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class SEL_ARG_LT: public SEL_ARG_LE
|
||||
{
|
||||
public:
|
||||
/*
|
||||
Use this constructor if value->save_in_field() went precisely,
|
||||
without any data rounding or truncation.
|
||||
*/
|
||||
SEL_ARG_LT(const uchar *key, Field *field)
|
||||
:SEL_ARG_LE(key, field)
|
||||
{ max_flag= NEAR_MAX; }
|
||||
/*
|
||||
Use this constructor if value->save_in_field() returned success,
|
||||
but we don't know if rounding or truncation happened
|
||||
(as some Field::store() do not report minor data changes).
|
||||
*/
|
||||
SEL_ARG_LT(THD *thd, const uchar *key, Field *field, Item *value)
|
||||
:SEL_ARG_LE(key, field)
|
||||
{
|
||||
if (stored_field_cmp_to_item(thd, field, value) == 0)
|
||||
max_flag= NEAR_MAX;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class SEL_ARG_GT: public SEL_ARG
|
||||
{
|
||||
public:
|
||||
/*
|
||||
Use this constructor if value->save_in_field() went precisely,
|
||||
without any data rounding or truncation.
|
||||
*/
|
||||
SEL_ARG_GT(const uchar *key, const KEY_PART *key_part, Field *field)
|
||||
:SEL_ARG(field, key, key)
|
||||
{
|
||||
// Don't use open ranges for partial key_segments
|
||||
if (!(key_part->flag & HA_PART_KEY_SEG))
|
||||
min_flag= NEAR_MIN;
|
||||
max_flag= NO_MAX_RANGE;
|
||||
}
|
||||
/*
|
||||
Use this constructor if value->save_in_field() returned success,
|
||||
but we don't know if rounding or truncation happened
|
||||
(as some Field::store() do not report minor data changes).
|
||||
*/
|
||||
SEL_ARG_GT(THD *thd, const uchar *key,
|
||||
const KEY_PART *key_part, Field *field, Item *value)
|
||||
:SEL_ARG(field, key, key)
|
||||
{
|
||||
// Don't use open ranges for partial key_segments
|
||||
if ((!(key_part->flag & HA_PART_KEY_SEG)) &&
|
||||
(stored_field_cmp_to_item(thd, field, value) <= 0))
|
||||
min_flag= NEAR_MIN;
|
||||
max_flag= NO_MAX_RANGE;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class SEL_ARG_GE: public SEL_ARG
|
||||
{
|
||||
public:
|
||||
/*
|
||||
Use this constructor if value->save_in_field() went precisely,
|
||||
without any data rounding or truncation.
|
||||
*/
|
||||
SEL_ARG_GE(const uchar *key, Field *field)
|
||||
:SEL_ARG(field, key, key)
|
||||
{
|
||||
max_flag= NO_MAX_RANGE;
|
||||
}
|
||||
/*
|
||||
Use this constructor if value->save_in_field() returned success,
|
||||
but we don't know if rounding or truncation happened
|
||||
(as some Field::store() do not report minor data changes).
|
||||
*/
|
||||
SEL_ARG_GE(THD *thd, const uchar *key,
|
||||
const KEY_PART *key_part, Field *field, Item *value)
|
||||
:SEL_ARG(field, key, key)
|
||||
{
|
||||
// Don't use open ranges for partial key_segments
|
||||
if ((!(key_part->flag & HA_PART_KEY_SEG)) &&
|
||||
(stored_field_cmp_to_item(thd, field, value) < 0))
|
||||
min_flag= NEAR_MIN;
|
||||
max_flag= NO_MAX_RANGE;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
SEL_ARG *SEL_ARG::clone(RANGE_OPT_PARAM *param, SEL_ARG *new_parent,
|
||||
SEL_ARG **next_arg)
|
||||
{
|
||||
|
@ -8015,52 +8127,112 @@ Item_func_like::get_mm_leaf(RANGE_OPT_PARAM *param,
|
|||
SEL_ARG *
|
||||
Item_bool_func::get_mm_leaf(RANGE_OPT_PARAM *param,
|
||||
Field *field, KEY_PART *key_part,
|
||||
Item_func::Functype type, Item *value)
|
||||
Item_func::Functype functype, Item *value)
|
||||
{
|
||||
uint maybe_null=(uint) field->real_maybe_null();
|
||||
SEL_ARG *tree= 0;
|
||||
MEM_ROOT *alloc= param->mem_root;
|
||||
uchar *str;
|
||||
int err;
|
||||
DBUG_ENTER("Item_bool_func::get_mm_leaf");
|
||||
|
||||
DBUG_ASSERT(value); // IS NULL and IS NOT NULL are handled separately
|
||||
|
||||
if (key_part->image_type != Field::itRAW)
|
||||
DBUG_RETURN(0); // e.g. SPATIAL index
|
||||
DBUG_RETURN(field->get_mm_leaf(param, key_part, this,
|
||||
functype_to_scalar_comparison_op(functype),
|
||||
value));
|
||||
}
|
||||
|
||||
if (param->using_real_indexes &&
|
||||
!field->optimize_range(param->real_keynr[key_part->key],
|
||||
key_part->part) &&
|
||||
type != EQ_FUNC &&
|
||||
type != EQUAL_FUNC)
|
||||
goto end; // Can't optimize this
|
||||
|
||||
if (!field->can_optimize_range(this, value,
|
||||
type == EQUAL_FUNC || type == EQ_FUNC))
|
||||
goto end;
|
||||
bool Field::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
|
||||
{
|
||||
bool is_eq_func= op == SCALAR_CMP_EQ || op == SCALAR_CMP_EQUAL;
|
||||
if ((param->using_real_indexes &&
|
||||
!optimize_range(param->real_keynr[key_part->key],
|
||||
key_part->part) && !is_eq_func) ||
|
||||
!can_optimize_range(cond, value, is_eq_func))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
err= value->save_in_field_no_warnings(field, 1);
|
||||
|
||||
uchar *Field::make_key_image(MEM_ROOT *mem_root, const KEY_PART *key_part)
|
||||
{
|
||||
DBUG_ENTER("Field::make_key_image");
|
||||
uint maybe_null= (uint) real_maybe_null();
|
||||
uchar *str;
|
||||
if (!(str= (uchar*) alloc_root(mem_root, key_part->store_length + 1)))
|
||||
DBUG_RETURN(0);
|
||||
if (maybe_null)
|
||||
*str= (uchar) is_real_null(); // Set to 1 if null
|
||||
get_key_image(str + maybe_null, key_part->length, key_part->image_type);
|
||||
DBUG_RETURN(str);
|
||||
}
|
||||
|
||||
|
||||
SEL_ARG *Field::stored_field_make_mm_leaf_truncated(RANGE_OPT_PARAM *param,
|
||||
scalar_comparison_op op,
|
||||
Item *value)
|
||||
{
|
||||
DBUG_ENTER("Field::stored_field_make_mm_leaf_truncated");
|
||||
if ((op == SCALAR_CMP_EQ || op == SCALAR_CMP_EQUAL) &&
|
||||
value->result_type() == item_cmp_type(result_type(),
|
||||
value->result_type()))
|
||||
DBUG_RETURN(new (param->mem_root) SEL_ARG_IMPOSSIBLE(this));
|
||||
/*
|
||||
TODO: We should return trees of the type SEL_ARG::IMPOSSIBLE
|
||||
for the cases like int_field > 999999999999999999999999 as well.
|
||||
*/
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
SEL_ARG *Field_num::get_mm_leaf(RANGE_OPT_PARAM *prm, KEY_PART *key_part,
|
||||
const Item_bool_func *cond,
|
||||
scalar_comparison_op op, Item *value)
|
||||
{
|
||||
DBUG_ENTER("Field_num::get_mm_leaf");
|
||||
if (!can_optimize_scalar_range(prm, key_part, cond, op, value))
|
||||
DBUG_RETURN(0);
|
||||
int err= value->save_in_field_no_warnings(this, 1);
|
||||
if ((op != SCALAR_CMP_EQUAL && is_real_null()) || err < 0)
|
||||
DBUG_RETURN(&null_element);
|
||||
if (err > 0 && cmp_type() != value->result_type())
|
||||
DBUG_RETURN(stored_field_make_mm_leaf_truncated(prm, op, value));
|
||||
DBUG_RETURN(stored_field_make_mm_leaf(prm, key_part, op, value));
|
||||
}
|
||||
|
||||
|
||||
SEL_ARG *Field_temporal::get_mm_leaf(RANGE_OPT_PARAM *prm, KEY_PART *key_part,
|
||||
const Item_bool_func *cond,
|
||||
scalar_comparison_op op, Item *value)
|
||||
{
|
||||
DBUG_ENTER("Field_temporal::get_mm_leaf");
|
||||
if (!can_optimize_scalar_range(prm, key_part, cond, op, value))
|
||||
DBUG_RETURN(0);
|
||||
int err= value->save_in_field_no_warnings(this, 1);
|
||||
if ((op != SCALAR_CMP_EQUAL && is_real_null()) || err < 0)
|
||||
DBUG_RETURN(&null_element);
|
||||
if (err > 0)
|
||||
DBUG_RETURN(stored_field_make_mm_leaf_truncated(prm, op, value));
|
||||
DBUG_RETURN(stored_field_make_mm_leaf(prm, key_part, op, value));
|
||||
}
|
||||
|
||||
|
||||
SEL_ARG *Field_date_common::get_mm_leaf(RANGE_OPT_PARAM *prm,
|
||||
KEY_PART *key_part,
|
||||
const Item_bool_func *cond,
|
||||
scalar_comparison_op op,
|
||||
Item *value)
|
||||
{
|
||||
DBUG_ENTER("Field_date_common::get_mm_leaf");
|
||||
if (!can_optimize_scalar_range(prm, key_part, cond, op, value))
|
||||
DBUG_RETURN(0);
|
||||
int err= value->save_in_field_no_warnings(this, 1);
|
||||
if ((op != SCALAR_CMP_EQUAL && is_real_null()) || err < 0)
|
||||
DBUG_RETURN(&null_element);
|
||||
if (err > 0)
|
||||
{
|
||||
if (field->type_handler() == &type_handler_enum ||
|
||||
field->type_handler() == &type_handler_set)
|
||||
{
|
||||
if (type == EQ_FUNC || type == EQUAL_FUNC)
|
||||
tree= new (alloc) SEL_ARG_IMPOSSIBLE(field);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (err == 2 && field->cmp_type() == STRING_RESULT)
|
||||
{
|
||||
if (type == EQ_FUNC || type == EQUAL_FUNC)
|
||||
tree= new (alloc) SEL_ARG_IMPOSSIBLE(field);
|
||||
else
|
||||
tree= NULL; /* Cannot infer anything */
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (err == 3 && field->type() == FIELD_TYPE_DATE)
|
||||
if (err == 3)
|
||||
{
|
||||
/*
|
||||
We were saving DATETIME into a DATE column, the conversion went ok
|
||||
|
@ -8080,81 +8252,86 @@ Item_bool_func::get_mm_leaf(RANGE_OPT_PARAM *param,
|
|||
be done together with other types at the end of this function
|
||||
(grep for stored_field_cmp_to_item)
|
||||
*/
|
||||
if (type == EQ_FUNC || type == EQUAL_FUNC)
|
||||
{
|
||||
tree= new (alloc) SEL_ARG_IMPOSSIBLE(field);
|
||||
goto end;
|
||||
}
|
||||
// Continue with processing non-equality ranges
|
||||
}
|
||||
else if (field->cmp_type() != value->result_type())
|
||||
{
|
||||
if ((type == EQ_FUNC || type == EQUAL_FUNC) &&
|
||||
value->result_type() == item_cmp_type(field->result_type(),
|
||||
value->result_type()))
|
||||
{
|
||||
tree= new (alloc) SEL_ARG_IMPOSSIBLE(field);
|
||||
goto end;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
TODO: We should return trees of the type SEL_ARG::IMPOSSIBLE
|
||||
for the cases like int_field > 999999999999999999999999 as well.
|
||||
*/
|
||||
tree= 0;
|
||||
goto end;
|
||||
}
|
||||
if (op == SCALAR_CMP_EQ || op == SCALAR_CMP_EQUAL)
|
||||
DBUG_RETURN(new (prm->mem_root) SEL_ARG_IMPOSSIBLE(this));
|
||||
DBUG_RETURN(stored_field_make_mm_leaf(prm, key_part, op, value));
|
||||
}
|
||||
DBUG_RETURN(stored_field_make_mm_leaf_truncated(prm, op, value));
|
||||
}
|
||||
DBUG_RETURN(stored_field_make_mm_leaf(prm, key_part, op, value));
|
||||
}
|
||||
|
||||
/*
|
||||
guaranteed at this point: err > 0; field and const of same type
|
||||
If an integer got bounded (e.g. to within 0..255 / -128..127)
|
||||
for < or >, set flags as for <= or >= (no NEAR_MAX / NEAR_MIN)
|
||||
*/
|
||||
else if (err == 1 && field->result_type() == INT_RESULT)
|
||||
{
|
||||
if (type == EQ_FUNC || type == EQUAL_FUNC) // e.g. tinyint = 200
|
||||
{
|
||||
tree= new (alloc) SEL_ARG_IMPOSSIBLE(field);
|
||||
goto end;
|
||||
}
|
||||
if (type == LT_FUNC && (value->val_int() > 0))
|
||||
type= LE_FUNC;
|
||||
else if (type == GT_FUNC &&
|
||||
(field->type() != FIELD_TYPE_BIT) &&
|
||||
!((Field_num*)field)->unsigned_flag &&
|
||||
!value->unsigned_flag &&
|
||||
(value->val_int() < 0))
|
||||
type= GE_FUNC;
|
||||
}
|
||||
}
|
||||
else if (err < 0)
|
||||
{
|
||||
/* This happens when we try to insert a NULL field in a not null column */
|
||||
tree= &null_element; // cmp with NULL is never TRUE
|
||||
goto end;
|
||||
}
|
||||
|
||||
/*
|
||||
Any sargable predicate except "<=>" involving NULL as a constant is always
|
||||
FALSE
|
||||
*/
|
||||
if (type != EQUAL_FUNC && field->is_real_null())
|
||||
SEL_ARG *Field_str::get_mm_leaf(RANGE_OPT_PARAM *prm, KEY_PART *key_part,
|
||||
const Item_bool_func *cond,
|
||||
scalar_comparison_op op, Item *value)
|
||||
{
|
||||
DBUG_ENTER("Field_str::get_mm_leaf");
|
||||
if (!can_optimize_scalar_range(prm, key_part, cond, op, value))
|
||||
DBUG_RETURN(0);
|
||||
int err= value->save_in_field_no_warnings(this, 1);
|
||||
if ((op != SCALAR_CMP_EQUAL && is_real_null()) || err < 0)
|
||||
DBUG_RETURN(&null_element);
|
||||
if (err > 0)
|
||||
{
|
||||
tree= &null_element;
|
||||
goto end;
|
||||
if (op == SCALAR_CMP_EQ || op == SCALAR_CMP_EQUAL)
|
||||
DBUG_RETURN(new (prm->mem_root) SEL_ARG_IMPOSSIBLE(this));
|
||||
DBUG_RETURN(NULL); /* Cannot infer anything */
|
||||
}
|
||||
|
||||
str= (uchar*) alloc_root(alloc, key_part->store_length+1);
|
||||
if (!str)
|
||||
goto end;
|
||||
if (maybe_null)
|
||||
*str= (uchar) field->is_real_null(); // Set to 1 if null
|
||||
field->get_key_image(str+maybe_null, key_part->length,
|
||||
key_part->image_type);
|
||||
if (!(tree= new (alloc) SEL_ARG(field, str, str)))
|
||||
goto end; // out of memory
|
||||
DBUG_RETURN(stored_field_make_mm_leaf(prm, key_part, op, value));
|
||||
}
|
||||
|
||||
|
||||
SEL_ARG *Field::get_mm_leaf_int(RANGE_OPT_PARAM *prm, KEY_PART *key_part,
|
||||
const Item_bool_func *cond,
|
||||
scalar_comparison_op op, Item *value,
|
||||
bool unsigned_field)
|
||||
{
|
||||
DBUG_ENTER("Field::get_mm_leaf_int");
|
||||
if (!can_optimize_scalar_range(prm, key_part, cond, op, value))
|
||||
DBUG_RETURN(0);
|
||||
int err= value->save_in_field_no_warnings(this, 1);
|
||||
if ((op != SCALAR_CMP_EQUAL && is_real_null()) || err < 0)
|
||||
DBUG_RETURN(&null_element);
|
||||
if (err > 0)
|
||||
{
|
||||
if (value->result_type() != INT_RESULT)
|
||||
DBUG_RETURN(stored_field_make_mm_leaf_truncated(prm, op, value));
|
||||
else
|
||||
DBUG_RETURN(stored_field_make_mm_leaf_bounded_int(prm, key_part,
|
||||
op, value,
|
||||
unsigned_field));
|
||||
}
|
||||
if (value->result_type() != INT_RESULT)
|
||||
DBUG_RETURN(stored_field_make_mm_leaf(prm, key_part, op, value));
|
||||
DBUG_RETURN(stored_field_make_mm_leaf_exact(prm, key_part, op, value));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
This method is called when:
|
||||
- value->save_in_field_no_warnings() returned err > 0
|
||||
- and both field and "value" are of integer data types
|
||||
If an integer got bounded (e.g. to within 0..255 / -128..127)
|
||||
for < or >, set flags as for <= or >= (no NEAR_MAX / NEAR_MIN)
|
||||
*/
|
||||
|
||||
SEL_ARG *Field::stored_field_make_mm_leaf_bounded_int(RANGE_OPT_PARAM *param,
|
||||
KEY_PART *key_part,
|
||||
scalar_comparison_op op,
|
||||
Item *value,
|
||||
bool unsigned_field)
|
||||
{
|
||||
DBUG_ENTER("Field::stored_field_make_mm_leaf_bounded_int");
|
||||
if (op == SCALAR_CMP_EQ || op == SCALAR_CMP_EQUAL) // e.g. tinyint = 200
|
||||
DBUG_RETURN(new (param->mem_root) SEL_ARG_IMPOSSIBLE(this));
|
||||
longlong item_val= value->val_int();
|
||||
|
||||
if (op == SCALAR_CMP_LT && item_val > 0)
|
||||
op= SCALAR_CMP_LE; // e.g. rewrite (tinyint < 200) to (tinyint <= 127)
|
||||
else if (op == SCALAR_CMP_GT && !unsigned_field &&
|
||||
!value->unsigned_flag && item_val < 0)
|
||||
op= SCALAR_CMP_GE; // e.g. rewrite (tinyint > -200) to (tinyint >= -128)
|
||||
|
||||
/*
|
||||
Check if we are comparing an UNSIGNED integer with a negative constant.
|
||||
|
@ -8167,66 +8344,74 @@ Item_bool_func::get_mm_leaf(RANGE_OPT_PARAM *param,
|
|||
negative integers (which otherwise fails because at query execution time
|
||||
negative integers are cast to unsigned if compared with unsigned).
|
||||
*/
|
||||
if (field->result_type() == INT_RESULT &&
|
||||
value->result_type() == INT_RESULT &&
|
||||
((field->type() == FIELD_TYPE_BIT ||
|
||||
((Field_num *) field)->unsigned_flag) &&
|
||||
!value->unsigned_flag))
|
||||
if (unsigned_field && !value->unsigned_flag && item_val < 0)
|
||||
{
|
||||
longlong item_val= value->val_int();
|
||||
if (item_val < 0)
|
||||
{
|
||||
if (type == LT_FUNC || type == LE_FUNC)
|
||||
{
|
||||
tree->type= SEL_ARG::IMPOSSIBLE;
|
||||
goto end;
|
||||
}
|
||||
if (type == GT_FUNC || type == GE_FUNC)
|
||||
{
|
||||
tree= 0;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
if (op == SCALAR_CMP_LT || op == SCALAR_CMP_LE) // e.g. uint < -1
|
||||
DBUG_RETURN(new (param->mem_root) SEL_ARG_IMPOSSIBLE(this));
|
||||
if (op == SCALAR_CMP_GT || op == SCALAR_CMP_GE) // e.g. uint > -1
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
DBUG_RETURN(stored_field_make_mm_leaf_exact(param, key_part, op, value));
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case LT_FUNC:
|
||||
if (stored_field_cmp_to_item(param->thd, field, value) == 0)
|
||||
tree->max_flag=NEAR_MAX;
|
||||
/* fall through */
|
||||
case LE_FUNC:
|
||||
if (!maybe_null)
|
||||
tree->min_flag=NO_MIN_RANGE; /* From start */
|
||||
else
|
||||
{ // > NULL
|
||||
tree->min_value=is_null_string;
|
||||
tree->min_flag=NEAR_MIN;
|
||||
}
|
||||
break;
|
||||
case GT_FUNC:
|
||||
/* Don't use open ranges for partial key_segments */
|
||||
if ((!(key_part->flag & HA_PART_KEY_SEG)) &&
|
||||
(stored_field_cmp_to_item(param->thd, field, value) <= 0))
|
||||
tree->min_flag=NEAR_MIN;
|
||||
tree->max_flag= NO_MAX_RANGE;
|
||||
break;
|
||||
case GE_FUNC:
|
||||
/* Don't use open ranges for partial key_segments */
|
||||
if ((!(key_part->flag & HA_PART_KEY_SEG)) &&
|
||||
(stored_field_cmp_to_item(param->thd, field, value) < 0))
|
||||
tree->min_flag= NEAR_MIN;
|
||||
tree->max_flag=NO_MAX_RANGE;
|
||||
break;
|
||||
case EQ_FUNC:
|
||||
case EQUAL_FUNC:
|
||||
break;
|
||||
default:
|
||||
DBUG_ASSERT(0);
|
||||
|
||||
SEL_ARG *Field::stored_field_make_mm_leaf(RANGE_OPT_PARAM *param,
|
||||
KEY_PART *key_part,
|
||||
scalar_comparison_op op,
|
||||
Item *value)
|
||||
{
|
||||
DBUG_ENTER("Field::stored_field_make_mm_leaf");
|
||||
THD *thd= param->thd;
|
||||
MEM_ROOT *mem_root= param->mem_root;
|
||||
uchar *str;
|
||||
if (!(str= make_key_image(param->mem_root, key_part)))
|
||||
DBUG_RETURN(0);
|
||||
|
||||
switch (op) {
|
||||
case SCALAR_CMP_LE:
|
||||
DBUG_RETURN(new (mem_root) SEL_ARG_LE(str, this));
|
||||
case SCALAR_CMP_LT:
|
||||
DBUG_RETURN(new (mem_root) SEL_ARG_LT(thd, str, this, value));
|
||||
case SCALAR_CMP_GT:
|
||||
DBUG_RETURN(new (mem_root) SEL_ARG_GT(thd, str, key_part, this, value));
|
||||
case SCALAR_CMP_GE:
|
||||
DBUG_RETURN(new (mem_root) SEL_ARG_GE(thd, str, key_part, this, value));
|
||||
case SCALAR_CMP_EQ:
|
||||
case SCALAR_CMP_EQUAL:
|
||||
DBUG_RETURN(new (mem_root) SEL_ARG(this, str, str));
|
||||
break;
|
||||
}
|
||||
DBUG_ASSERT(0);
|
||||
DBUG_RETURN(NULL);
|
||||
}
|
||||
|
||||
end:
|
||||
DBUG_RETURN(tree);
|
||||
|
||||
SEL_ARG *Field::stored_field_make_mm_leaf_exact(RANGE_OPT_PARAM *param,
|
||||
KEY_PART *key_part,
|
||||
scalar_comparison_op op,
|
||||
Item *value)
|
||||
{
|
||||
DBUG_ENTER("Field::stored_field_make_mm_leaf_exact");
|
||||
uchar *str;
|
||||
if (!(str= make_key_image(param->mem_root, key_part)))
|
||||
DBUG_RETURN(0);
|
||||
|
||||
switch (op) {
|
||||
case SCALAR_CMP_LE:
|
||||
DBUG_RETURN(new (param->mem_root) SEL_ARG_LE(str, this));
|
||||
case SCALAR_CMP_LT:
|
||||
DBUG_RETURN(new (param->mem_root) SEL_ARG_LT(str, this));
|
||||
case SCALAR_CMP_GT:
|
||||
DBUG_RETURN(new (param->mem_root) SEL_ARG_GT(str, key_part, this));
|
||||
case SCALAR_CMP_GE:
|
||||
DBUG_RETURN(new (param->mem_root) SEL_ARG_GE(str, this));
|
||||
case SCALAR_CMP_EQ:
|
||||
case SCALAR_CMP_EQUAL:
|
||||
DBUG_RETURN(new (param->mem_root) SEL_ARG(this, str, str));
|
||||
break;
|
||||
}
|
||||
DBUG_ASSERT(0);
|
||||
DBUG_RETURN(NULL);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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 @@ public:
|
|||
{
|
||||
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 @@ public:
|
|||
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 @@ public:
|
|||
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 @@ public:
|
|||
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 @@ public:
|
|||
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 @@ public:
|
|||
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 @@ public:
|
|||
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 @@ public:
|
|||
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 @@ public:
|
|||
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
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue