Commit 93bc7283 authored by Alexander Barkov's avatar Alexander Barkov

MDEV-11503 Introduce Type_handler::make_in_vector() and...

MDEV-11503 Introduce Type_handler::make_in_vector() and Item_func_in_fix_comparator_compatible_types()

This patch implements the task according to the description:

1. The old code from Item_func_in::fix_length_and_dec() was decomposed
into smaller methods:
- all_items_are_consts()
- compatible_types_scalar_bisection_possible()
- compatible_types_row_bisection_possible()
- fix_in_vector()
- fix_for_scalar_comparison_using_bisection()
- fix_for_scalar_comparison_using_cmp_items()
- fix_for_row_comparison_using_bisection()
- fix_for_row_comparison_using_cmp_items()

The data type dependend pieces where moved as methods to Type_handler.

2. Splits in_datetime into separate:
   - in_datetime, for DATETIME and DATE,
   - in_time, for TIME
   to make the code more symmetric across data types.

Additionally:
- Adds a test func_debug.test to see which calculation strategy
  (bisect or no bisect) is chosen to handle IN with various arguments.
- Adds a new helper method (to avoid duplicate code):
  cmp_item_rows::prepare_comparators()
- Changes the propotype for cmp_item_row::alloc_comparators(),
  to avoid duplicate code, and to use less current_thd.
- Changes "friend" sections in cmp_item_row and in_row from
  an exact Item_func_in method to the entire class Item_func_in,
  as their internals are now needed in multiple Item_func_in methods.
- Added more comments (e.g. on bisection, on the problem reported in MDEV-11511)
parent 8b930b8f
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -1264,20 +1264,18 @@ class in_longlong :public in_vector
If the left item is a constant one then its value is cached in the
lval_cache variable.
*/
class in_datetime :public in_longlong
class in_temporal :public in_longlong
{
protected:
uchar *get_value_internal(Item *item, enum_field_types f_type);
public:
THD *thd;
/* An item used to issue warnings. */
Item *warn_item;
/* Cache for the left item. */
Item *lval_cache;
in_datetime(THD *thd, Item *warn_item_arg, uint elements)
:in_longlong(thd, elements), thd(current_thd), warn_item(warn_item_arg),
in_temporal(THD *thd, uint elements)
:in_longlong(thd, elements), thd(current_thd),
lval_cache(0) {};
void set(uint pos,Item *item);
uchar *get_value(Item *item);
Item *create_item(THD *thd);
void value_to_item(uint pos, Item *item)
{
......@@ -1289,6 +1287,30 @@ class in_datetime :public in_longlong
};
class in_datetime :public in_temporal
{
public:
in_datetime(THD *thd, uint elements)
:in_temporal(thd, elements)
{}
void set(uint pos,Item *item);
uchar *get_value(Item *item)
{ return get_value_internal(item, MYSQL_TYPE_DATETIME); }
};
class in_time :public in_temporal
{
public:
in_time(THD *thd, uint elements)
:in_temporal(thd, elements)
{}
void set(uint pos,Item *item);
uchar *get_value(Item *item)
{ return get_value_internal(item, MYSQL_TYPE_TIME); }
};
class in_double :public in_vector
{
double tmp;
......@@ -1602,12 +1624,24 @@ class Item_func_case :public Item_func_hybrid_field_type
The current implementation distinguishes 2 cases:
1) all items in <in value list> are constants and have the same
result type. This case is handled by in_vector class.
result type. This case is handled by in_vector class,
implementing fast bisection search.
2) otherwise Item_func_in employs several cmp_item objects to perform
comparisons of in_expr and an item from <in value list>. One cmp_item
object for each result type. Different result types are collected in the
fix_length_and_dec() member function by means of collect_cmp_types()
function.
Bisection is possible when:
1. All types are similar
2. All expressions in <in value list> are const
In the presence of NULLs, the correct result of evaluating this item
must be UNKNOWN or FALSE. To achieve that:
- If type is scalar, we can use bisection and the "have_null" boolean.
- If type is ROW, we will need to scan all of <in value list> when
searching, so bisection is impossible. Unless:
3. UNKNOWN and FALSE are equivalent results
4. Neither left expression nor <in value list> contain any NULL value
*/
class Item_func_in :public Item_func_opt_neg
{
......@@ -1617,6 +1651,15 @@ class Item_func_in :public Item_func_opt_neg
IN ( (-5, (12,NULL)), ... ).
*/
bool list_contains_null();
bool all_items_are_consts(Item **items, uint nitems) const
{
for (uint i= 0; i < nitems; i++)
{
if (!items[i]->const_item())
return false;
}
return true;
}
protected:
SEL_TREE *get_func_mm_tree(RANGE_OPT_PARAM *param,
Field *field, Item *value);
......@@ -1648,6 +1691,38 @@ class Item_func_in :public Item_func_opt_neg
longlong val_int();
bool fix_fields(THD *, Item **);
void fix_length_and_dec();
bool compatible_types_scalar_bisection_possible()
{
DBUG_ASSERT(m_comparator.cmp_type() != ROW_RESULT);
return all_items_are_consts(args + 1, arg_count - 1); // Bisection #2
}
bool compatible_types_row_bisection_possible()
{
DBUG_ASSERT(m_comparator.cmp_type() == ROW_RESULT);
return all_items_are_consts(args + 1, arg_count - 1) && // Bisection #2
((is_top_level_item() && !negated) || // Bisection #3
(!list_contains_null() && !args[0]->maybe_null)); // Bisection #4
}
bool agg_all_arg_charsets_for_comparison()
{
return agg_arg_charsets_for_comparison(cmp_collation, args, arg_count);
}
void fix_in_vector();
bool value_list_convert_const_to_int(THD *thd);
bool fix_for_scalar_comparison_using_bisection(THD *thd)
{
array= m_comparator.type_handler()->make_in_vector(thd, this, arg_count - 1);
if (!array) // OOM
return true;
fix_in_vector();
return false;
}
bool fix_for_scalar_comparison_using_cmp_items(uint found_types);
bool fix_for_row_comparison_using_cmp_items(THD *thd);
bool fix_for_row_comparison_using_bisection(THD *thd);
void cleanup()
{
uint i;
......@@ -1711,12 +1786,13 @@ class cmp_item_row :public cmp_item
cmp_item_row(): comparators(0), n(0) {}
~cmp_item_row();
void store_value(Item *item);
inline void alloc_comparators();
bool alloc_comparators(THD *thd, uint n);
bool prepare_comparators(THD *, Item **args, uint arg_count);
int cmp(Item *arg);
int compare(cmp_item *arg);
cmp_item *make_same();
void store_value_by_template(THD *thd, cmp_item *tmpl, Item *);
friend void Item_func_in::fix_length_and_dec();
friend class Item_func_in;
};
......@@ -1728,7 +1804,7 @@ class in_row :public in_vector
~in_row();
void set(uint pos,Item *item);
uchar *get_value(Item *item);
friend void Item_func_in::fix_length_and_dec();
friend class Item_func_in;
Item_result result_type() { return ROW_RESULT; }
};
......
......@@ -32,7 +32,6 @@ static Type_handler_time type_handler_time;
static Type_handler_time2 type_handler_time2;
static Type_handler_date type_handler_date;
static Type_handler_newdate type_handler_newdate;
static Type_handler_datetime type_handler_datetime;
static Type_handler_datetime2 type_handler_datetime2;
static Type_handler_timestamp type_handler_timestamp;
static Type_handler_timestamp2 type_handler_timestamp2;
......@@ -54,6 +53,7 @@ Type_handler_row type_handler_row;
Type_handler_varchar type_handler_varchar;
Type_handler_longlong type_handler_longlong;
Type_handler_newdecimal type_handler_newdecimal;
Type_handler_datetime type_handler_datetime;
/**
......@@ -1231,3 +1231,143 @@ longlong Type_handler_decimal_result::
}
/***************************************************************************/
static int srtcmp_in(CHARSET_INFO *cs, const String *x,const String *y)
{
return cs->coll->strnncollsp(cs,
(uchar *) x->ptr(),x->length(),
(uchar *) y->ptr(),y->length());
}
in_vector *Type_handler_string_result::make_in_vector(THD *thd,
const Item_func_in *func,
uint nargs) const
{
return new (thd->mem_root) in_string(thd, nargs, (qsort2_cmp) srtcmp_in,
func->compare_collation());
}
in_vector *Type_handler_int_result::make_in_vector(THD *thd,
const Item_func_in *func,
uint nargs) const
{
return new (thd->mem_root) in_longlong(thd, nargs);
}
in_vector *Type_handler_real_result::make_in_vector(THD *thd,
const Item_func_in *func,
uint nargs) const
{
return new (thd->mem_root) in_double(thd, nargs);
}
in_vector *Type_handler_decimal_result::make_in_vector(THD *thd,
const Item_func_in *func,
uint nargs) const
{
return new (thd->mem_root) in_decimal(thd, nargs);
}
in_vector *Type_handler_time_common::make_in_vector(THD *thd,
const Item_func_in *func,
uint nargs) const
{
return new (thd->mem_root) in_time(thd, nargs);
}
in_vector *
Type_handler_temporal_with_date::make_in_vector(THD *thd,
const Item_func_in *func,
uint nargs) const
{
return new (thd->mem_root) in_datetime(thd, nargs);
}
in_vector *Type_handler_row::make_in_vector(THD *thd,
const Item_func_in *func,
uint nargs) const
{
return new (thd->mem_root) in_row(thd, nargs, 0);
}
/***************************************************************************/
bool Type_handler_string_result::
Item_func_in_fix_comparator_compatible_types(THD *thd,
Item_func_in *func) const
{
if (func->agg_all_arg_charsets_for_comparison())
return true;
if (func->compatible_types_scalar_bisection_possible())
{
return func->value_list_convert_const_to_int(thd) ||
func->fix_for_scalar_comparison_using_bisection(thd);
}
return
func->fix_for_scalar_comparison_using_cmp_items(1U << (uint) STRING_RESULT);
}
bool Type_handler_int_result::
Item_func_in_fix_comparator_compatible_types(THD *thd,
Item_func_in *func) const
{
/*
Does not need to call value_list_convert_const_to_int()
as already handled by int handler.
*/
return func->compatible_types_scalar_bisection_possible() ?
func->fix_for_scalar_comparison_using_bisection(thd) :
func->fix_for_scalar_comparison_using_cmp_items(1U << (uint) INT_RESULT);
}
bool Type_handler_real_result::
Item_func_in_fix_comparator_compatible_types(THD *thd,
Item_func_in *func) const
{
return func->compatible_types_scalar_bisection_possible() ?
(func->value_list_convert_const_to_int(thd) ||
func->fix_for_scalar_comparison_using_bisection(thd)) :
func->fix_for_scalar_comparison_using_cmp_items(1U << (uint) REAL_RESULT);
}
bool Type_handler_decimal_result::
Item_func_in_fix_comparator_compatible_types(THD *thd,
Item_func_in *func) const
{
return func->compatible_types_scalar_bisection_possible() ?
(func->value_list_convert_const_to_int(thd) ||
func->fix_for_scalar_comparison_using_bisection(thd)) :
func->fix_for_scalar_comparison_using_cmp_items(1U << (uint) DECIMAL_RESULT);
}
bool Type_handler_temporal_result::
Item_func_in_fix_comparator_compatible_types(THD *thd,
Item_func_in *func) const
{
return func->compatible_types_scalar_bisection_possible() ?
(func->value_list_convert_const_to_int(thd) ||
func->fix_for_scalar_comparison_using_bisection(thd)) :
func->fix_for_scalar_comparison_using_cmp_items(1U << (uint) TIME_RESULT);
}
bool Type_handler_row::Item_func_in_fix_comparator_compatible_types(THD *thd,
Item_func_in *func) const
{
return func->compatible_types_row_bisection_possible() ?
func->fix_for_row_comparison_using_bisection(thd) :
func->fix_for_row_comparison_using_cmp_items(thd);
}
/***************************************************************************/
......@@ -30,6 +30,8 @@ class Item_sum_hybrid;
class Item_func_hex;
class Item_func_hybrid_field_type;
class Item_func_between;
class Item_func_in;
class in_vector;
class Type_std_attributes;
class Sort_param;
class Arg_comparator;
......@@ -317,6 +319,13 @@ class Type_handler
virtual longlong
Item_func_between_val_int(Item_func_between *func) const= 0;
virtual in_vector *
make_in_vector(THD *thd, const Item_func_in *func, uint nargs) const= 0;
virtual bool
Item_func_in_fix_comparator_compatible_types(THD *thd, Item_func_in *)
const= 0;
};
......@@ -414,6 +423,9 @@ class Type_handler_row: public Type_handler
}
longlong Item_func_between_val_int(Item_func_between *func) const;
in_vector *make_in_vector(THD *thd, const Item_func_in *f, uint nargs) const;
bool Item_func_in_fix_comparator_compatible_types(THD *thd,
Item_func_in *) const;
};
......@@ -462,6 +474,10 @@ class Type_handler_real_result: public Type_handler_numeric
MYSQL_TIME *,
ulonglong fuzzydate) const;
longlong Item_func_between_val_int(Item_func_between *func) const;
in_vector *make_in_vector(THD *, const Item_func_in *, uint nargs) const;
bool Item_func_in_fix_comparator_compatible_types(THD *thd,
Item_func_in *) const;
};
......@@ -495,6 +511,9 @@ class Type_handler_decimal_result: public Type_handler_numeric
MYSQL_TIME *,
ulonglong fuzzydate) const;
longlong Item_func_between_val_int(Item_func_between *func) const;
in_vector *make_in_vector(THD *, const Item_func_in *, uint nargs) const;
bool Item_func_in_fix_comparator_compatible_types(THD *thd,
Item_func_in *) const;
};
......@@ -528,6 +547,9 @@ class Type_handler_int_result: public Type_handler_numeric
MYSQL_TIME *,
ulonglong fuzzydate) const;
longlong Item_func_between_val_int(Item_func_between *func) const;
in_vector *make_in_vector(THD *, const Item_func_in *, uint nargs) const;
bool Item_func_in_fix_comparator_compatible_types(THD *thd,
Item_func_in *) const;
};
......@@ -559,6 +581,8 @@ class Type_handler_temporal_result: public Type_handler
MYSQL_TIME *,
ulonglong fuzzydate) 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;
};
......@@ -594,6 +618,9 @@ class Type_handler_string_result: public Type_handler
MYSQL_TIME *,
ulonglong fuzzydate) const;
longlong Item_func_between_val_int(Item_func_between *func) const;
in_vector *make_in_vector(THD *, const Item_func_in *, uint nargs) const;
bool Item_func_in_fix_comparator_compatible_types(THD *thd,
Item_func_in *) const;
};
......@@ -714,6 +741,7 @@ class Type_handler_time_common: public Type_handler_temporal_result
virtual ~Type_handler_time_common() { }
enum_field_types field_type() const { return MYSQL_TYPE_TIME; }
int Item_save_in_field(Item *item, Field *field, bool no_conversions) const;
in_vector *make_in_vector(THD *, const Item_func_in *, uint nargs) const;
};
......@@ -741,6 +769,7 @@ class Type_handler_temporal_with_date: public Type_handler_temporal_result
public:
virtual ~Type_handler_temporal_with_date() {}
int Item_save_in_field(Item *item, Field *field, bool no_conversions) const;
in_vector *make_in_vector(THD *, const Item_func_in *, uint nargs) const;
};
......@@ -1014,5 +1043,6 @@ extern Type_handler_null type_handler_null;
extern Type_handler_varchar type_handler_varchar;
extern Type_handler_longlong type_handler_longlong;
extern Type_handler_newdecimal type_handler_newdecimal;
extern Type_handler_datetime type_handler_datetime;
#endif /* SQL_TYPE_H_INCLUDED */
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